kernel: update 3.18 to 3.18.16
[15.05/openwrt.git] / target / linux / brcm63xx / patches-3.18 / 425-bcm63xxpart_parse_paritions_from_dt.patch
1 --- a/drivers/mtd/bcm63xxpart.c
2 +++ b/drivers/mtd/bcm63xxpart.c
3 @@ -32,6 +32,7 @@
4  #include <linux/vmalloc.h>
5  #include <linux/mtd/mtd.h>
6  #include <linux/mtd/partitions.h>
7 +#include <linux/of.h>
8  
9  #include <asm/mach-bcm63xx/bcm63xx_nvram.h>
10  #include <asm/mach-bcm63xx/bcm963xx_tag.h>
11 @@ -43,66 +44,35 @@
12  
13  #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
14  
15 -static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
16 -                                       struct mtd_partition **pparts,
17 -                                       struct mtd_part_parser_data *data)
18 +static bool node_has_compatible(struct device_node *pp)
19 +{
20 +       return of_get_property(pp, "compatible", NULL);
21 +}
22 +
23 +static int parse_bcmtag(struct mtd_info *master, struct mtd_partition *pparts,
24 +                       int next_part, size_t offset, size_t size)
25  {
26 -       /* CFE, NVRAM and global Linux are always present */
27 -       int nrparts = 3, curpart = 0;
28         struct bcm_tag *buf;
29 -       struct mtd_partition *parts;
30 +       u32 computed_crc;
31         int ret;
32         size_t retlen;
33 -       unsigned int rootfsaddr, kerneladdr, spareaddr, nvramaddr;
34 -       unsigned int rootfslen, kernellen, sparelen, totallen;
35 -       unsigned int cfelen, nvramlen;
36 -       unsigned int cfe_erasesize;
37 -       unsigned int caldatalen1 = 0, caldataaddr1 = 0;
38 -       unsigned int caldatalen2 = 0, caldataaddr2 = 0;
39 -       int i;
40 -       u32 computed_crc;
41 +       unsigned int rootfsaddr, kerneladdr;
42 +       unsigned int rootfslen, kernellen, totallen;
43         bool rootfs_first = false;
44 -
45 -       if (!bcm63xx_is_cfe_present())
46 -               return -EINVAL;
47 -
48 -       cfe_erasesize = max_t(uint32_t, master->erasesize,
49 -                             BCM63XX_CFE_BLOCK_SIZE);
50 -
51 -       cfelen = cfe_erasesize;
52 -       nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
53 -       nvramlen = roundup(nvramlen, cfe_erasesize);
54 -       nvramaddr = master->size - nvramlen;
55 -
56 -       if (data) {
57 -               if (data->caldata[0]) {
58 -                       caldatalen1 = cfe_erasesize;
59 -                       caldataaddr1 = rounddown(data->caldata[0],
60 -                                                cfe_erasesize);
61 -               }
62 -               if (data->caldata[1]) {
63 -                       caldatalen2 = cfe_erasesize;
64 -                       caldataaddr2 = rounddown(data->caldata[1],
65 -                                                cfe_erasesize);
66 -               }
67 -               if (caldataaddr1 == caldataaddr2) {
68 -                       caldataaddr2 = 0;
69 -                       caldatalen2 = 0;
70 -               }
71 -       }
72 +       int curr_part = next_part;
73  
74         /* Allocate memory for buffer */
75 -       buf = vmalloc(sizeof(struct bcm_tag));
76 +       buf = vmalloc(sizeof(*buf));
77         if (!buf)
78                 return -ENOMEM;
79  
80         /* Get the tag */
81 -       ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen,
82 +       ret = mtd_read(master, offset, sizeof(*buf), &retlen,
83                        (void *)buf);
84  
85 -       if (retlen != sizeof(struct bcm_tag)) {
86 +       if (retlen != sizeof(*buf)) {
87                 vfree(buf);
88 -               return -EIO;
89 +               return 0;
90         }
91  
92         computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
93 @@ -121,7 +91,6 @@ static int bcm63xx_parse_cfe_partitions(
94  
95                 kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
96                 rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
97 -               spareaddr = roundup(totallen, master->erasesize) + cfelen;
98  
99                 if (rootfsaddr < kerneladdr) {
100                         /* default Broadcom layout */
101 @@ -130,8 +99,8 @@ static int bcm63xx_parse_cfe_partitions(
102                 } else {
103                         /* OpenWrt layout */
104                         rootfsaddr = kerneladdr + kernellen;
105 -                       rootfslen = buf->real_rootfs_length;
106 -                       spareaddr = rootfsaddr + rootfslen;
107 +                       rootfslen = size - kernellen -
108 +                                   sizeof(*buf);
109                 }
110         } else {
111                 pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n",
112 @@ -139,16 +108,153 @@ static int bcm63xx_parse_cfe_partitions(
113                 kernellen = 0;
114                 rootfslen = 0;
115                 rootfsaddr = 0;
116 -               spareaddr = cfelen;
117         }
118 -       sparelen = min_not_zero(nvramaddr, caldataaddr1) - spareaddr;
119  
120 -       /* Determine number of partitions */
121 -       if (rootfslen > 0)
122 -               nrparts++;
123 +       if (kernellen > 0) {
124 +               int kernelpart = curr_part;
125  
126 -       if (kernellen > 0)
127 -               nrparts++;
128 +               if (rootfslen > 0 && rootfs_first)
129 +                       kernelpart++;
130 +               pparts[kernelpart].name = "kernel";
131 +               pparts[kernelpart].offset = kerneladdr;
132 +               pparts[kernelpart].size = kernellen;
133 +               curr_part++;
134 +       }
135 +
136 +       if (rootfslen > 0) {
137 +               int rootfspart = curr_part;
138 +
139 +               if (kernellen > 0 && rootfs_first)
140 +                       rootfspart--;
141 +               pparts[rootfspart].name = "rootfs";
142 +               pparts[rootfspart].offset = rootfsaddr;
143 +               pparts[rootfspart].size = rootfslen;
144 +
145 +               curr_part++;
146 +       }
147 +
148 +       vfree(buf);
149 +
150 +       return curr_part - next_part;
151 +}
152 +
153 +
154 +static int bcm63xx_parse_cfe_partitions_of(struct mtd_info *master,
155 +                                          struct mtd_partition **pparts,
156 +                                          struct mtd_part_parser_data *data)
157 +{
158 +       struct device_node *dp = data->of_node;
159 +       struct device_node *pp;
160 +       int i, nr_parts = 0;
161 +       const char *partname;
162 +       int len;
163 +
164 +       for_each_child_of_node(dp, pp) {
165 +               if (node_has_compatible(pp))
166 +                       continue;
167 +
168 +               if (!of_get_property(pp, "reg", &len))
169 +                       continue;
170 +
171 +               partname = of_get_property(pp, "label", &len);
172 +               if (!partname)
173 +                       partname = of_get_property(pp, "name", &len);
174 +
175 +               if (!strcmp(partname, "linux"))
176 +                       nr_parts += 2;
177 +
178 +               nr_parts++;
179 +       }
180 +
181 +       *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
182 +       if (!*pparts)
183 +               return -ENOMEM;
184 +
185 +       i = 0;
186 +       for_each_child_of_node(dp, pp) {
187 +               const __be32 *reg;
188 +               int a_cells, s_cells;
189 +               size_t size, offset;
190 +
191 +               if (node_has_compatible(pp))
192 +                       continue;
193 +
194 +               reg = of_get_property(pp, "reg", &len);
195 +               if (!reg)
196 +                       continue;
197 +
198 +               a_cells = of_n_addr_cells(pp);
199 +               s_cells = of_n_size_cells(pp);
200 +               offset = of_read_number(reg, a_cells);
201 +               size = of_read_number(reg + a_cells, s_cells);
202 +               partname = of_get_property(pp, "label", &len);
203 +               if (!partname)
204 +                       partname = of_get_property(pp, "name", &len);
205 +
206 +               if (!strcmp(partname, "linux"))
207 +                       i += parse_bcmtag(master, *pparts, i, offset, size);
208 +
209 +               if (of_get_property(pp, "read-only", &len))
210 +                       (*pparts)[i].mask_flags |= MTD_WRITEABLE;
211 +
212 +               if (of_get_property(pp, "lock", &len))
213 +                       (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
214 +
215 +               (*pparts)[i].offset = offset;
216 +               (*pparts)[i].size = size;
217 +               (*pparts)[i].name = partname;
218 +
219 +               i++;
220 +       }
221 +
222 +       return i;
223 +}
224 +
225 +static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
226 +                                       struct mtd_partition **pparts,
227 +                                       struct mtd_part_parser_data *data)
228 +{
229 +       /* CFE, NVRAM and global Linux are always present */
230 +       int nrparts = 5, curpart = 0;
231 +       struct mtd_partition *parts;
232 +       unsigned int nvramaddr;
233 +       unsigned int cfelen, nvramlen;
234 +       unsigned int cfe_erasesize;
235 +       unsigned int caldatalen1 = 0, caldataaddr1 = 0;
236 +       unsigned int caldatalen2 = 0, caldataaddr2 = 0;
237 +       unsigned int imageaddr, imagelen;
238 +       int i;
239 +
240 +       if (!bcm63xx_is_cfe_present())
241 +               return -EINVAL;
242 +
243 +       cfe_erasesize = max_t(uint32_t, master->erasesize,
244 +                             BCM63XX_CFE_BLOCK_SIZE);
245 +
246 +       cfelen = cfe_erasesize;
247 +       nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
248 +       nvramlen = roundup(nvramlen, cfe_erasesize);
249 +       nvramaddr = master->size - nvramlen;
250 +
251 +       if (data) {
252 +               if (data->caldata[0]) {
253 +                       caldatalen1 = cfe_erasesize;
254 +                       caldataaddr1 = rounddown(data->caldata[0],
255 +                                                cfe_erasesize);
256 +               }
257 +               if (data->caldata[1]) {
258 +                       caldatalen2 = cfe_erasesize;
259 +                       caldataaddr2 = rounddown(data->caldata[1],
260 +                                                cfe_erasesize);
261 +               }
262 +               if (caldataaddr1 == caldataaddr2) {
263 +                       caldataaddr2 = 0;
264 +                       caldatalen2 = 0;
265 +               }
266 +       }
267 +
268 +       imageaddr = cfelen;
269 +       imagelen = min_not_zero(nvramaddr, caldataaddr1) - imageaddr;
270  
271         if (caldatalen1 > 0)
272                 nrparts++;
273 @@ -158,10 +264,8 @@ static int bcm63xx_parse_cfe_partitions(
274  
275         /* Ask kernel for more memory */
276         parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
277 -       if (!parts) {
278 -               vfree(buf);
279 +       if (!parts)
280                 return -ENOMEM;
281 -       }
282  
283         /* Start building partition list */
284         parts[curpart].name = "CFE";
285 @@ -169,29 +273,7 @@ static int bcm63xx_parse_cfe_partitions(
286         parts[curpart].size = cfelen;
287         curpart++;
288  
289 -       if (kernellen > 0) {
290 -               int kernelpart = curpart;
291 -
292 -               if (rootfslen > 0 && rootfs_first)
293 -                       kernelpart++;
294 -               parts[kernelpart].name = "kernel";
295 -               parts[kernelpart].offset = kerneladdr;
296 -               parts[kernelpart].size = kernellen;
297 -               curpart++;
298 -       }
299 -
300 -       if (rootfslen > 0) {
301 -               int rootfspart = curpart;
302 -
303 -               if (kernellen > 0 && rootfs_first)
304 -                       rootfspart--;
305 -               parts[rootfspart].name = "rootfs";
306 -               parts[rootfspart].offset = rootfsaddr;
307 -               parts[rootfspart].size = rootfslen;
308 -               if (sparelen > 0  && !rootfs_first)
309 -                       parts[rootfspart].size += sparelen;
310 -               curpart++;
311 -       }
312 +       curpart += parse_bcmtag(master, parts, curpart, imageaddr, imagelen);
313  
314         if (caldatalen1 > 0) {
315                 if (caldatalen2 > 0)
316 @@ -217,25 +299,33 @@ static int bcm63xx_parse_cfe_partitions(
317  
318         /* Global partition "linux" to make easy firmware upgrade */
319         parts[curpart].name = "linux";
320 -       parts[curpart].offset = cfelen;
321 -       parts[curpart].size = min_not_zero(nvramaddr, caldataaddr1) - cfelen;
322 +       parts[curpart].offset = imageaddr;
323 +       parts[curpart].size = imagelen;
324 +       curpart++;
325  
326 -       for (i = 0; i < nrparts; i++)
327 +       for (i = 0; i < curpart; i++)
328                 pr_info("Partition %d is %s offset %llx and length %llx\n", i,
329                         parts[i].name, parts[i].offset, parts[i].size);
330  
331 -       pr_info("Spare partition is offset %x and length %x\n", spareaddr,
332 -               sparelen);
333 -
334         *pparts = parts;
335 -       vfree(buf);
336  
337         return nrparts;
338  };
339  
340 +
341 +static int bcm63xx_parse_partitions(struct mtd_info *master,
342 +                                   struct mtd_partition **pparts,
343 +                                   struct mtd_part_parser_data *data)
344 +{
345 +       if (data && data->of_node)
346 +               return bcm63xx_parse_cfe_partitions_of(master, pparts, data);
347 +       else
348 +               return bcm63xx_parse_cfe_partitions(master, pparts, data);
349 +}
350 +
351  static struct mtd_part_parser bcm63xx_cfe_parser = {
352         .owner = THIS_MODULE,
353 -       .parse_fn = bcm63xx_parse_cfe_partitions,
354 +       .parse_fn = bcm63xx_parse_partitions,
355         .name = "bcm63xxpart",
356  };
357