brcm63xx: move buttons and leds to dts files
[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,145 @@ 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 +               nr_parts++;
169 +       }
170 +
171 +       *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
172 +       if (!*pparts)
173 +               return -ENOMEM;
174 +
175 +       i = 0;
176 +       for_each_child_of_node(dp, pp) {
177 +               const __be32 *reg;
178 +               int a_cells, s_cells;
179 +               size_t size, offset;
180 +
181 +               if (node_has_compatible(pp))
182 +                       continue;
183 +
184 +               reg = of_get_property(pp, "reg", &len);
185 +               if (!reg) {
186 +                       nr_parts--;
187 +                       continue;
188 +               }
189 +
190 +               a_cells = of_n_addr_cells(pp);
191 +               s_cells = of_n_size_cells(pp);
192 +               offset = of_read_number(reg, a_cells);
193 +               size = of_read_number(reg + a_cells, s_cells);
194 +               partname = of_get_property(pp, "label", &len);
195 +               if (!partname)
196 +                       partname = of_get_property(pp, "name", &len);
197 +
198 +               if (!strcmp(partname, "linux"))
199 +                       i += parse_bcmtag(master, *pparts, i, offset, size);
200 +
201 +               if (of_get_property(pp, "read-only", &len))
202 +                       (*pparts)[i].mask_flags |= MTD_WRITEABLE;
203 +
204 +               if (of_get_property(pp, "lock", &len))
205 +                       (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
206 +
207 +               (*pparts)[i].offset = offset;
208 +               (*pparts)[i].size = size;
209 +               (*pparts)[i].name = partname;
210 +
211 +               i++;
212 +       }
213 +
214 +       return i;
215 +}
216 +
217 +static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
218 +                                       struct mtd_partition **pparts,
219 +                                       struct mtd_part_parser_data *data)
220 +{
221 +       /* CFE, NVRAM and global Linux are always present */
222 +       int nrparts = 5, curpart = 0;
223 +       struct mtd_partition *parts;
224 +       unsigned int nvramaddr;
225 +       unsigned int cfelen, nvramlen;
226 +       unsigned int cfe_erasesize;
227 +       unsigned int caldatalen1 = 0, caldataaddr1 = 0;
228 +       unsigned int caldatalen2 = 0, caldataaddr2 = 0;
229 +       unsigned int imageaddr, imagelen;
230 +       int i;
231 +
232 +       if (!bcm63xx_is_cfe_present())
233 +               return -EINVAL;
234 +
235 +       cfe_erasesize = max_t(uint32_t, master->erasesize,
236 +                             BCM63XX_CFE_BLOCK_SIZE);
237 +
238 +       cfelen = cfe_erasesize;
239 +       nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
240 +       nvramlen = roundup(nvramlen, cfe_erasesize);
241 +       nvramaddr = master->size - nvramlen;
242 +
243 +       if (data) {
244 +               if (data->caldata[0]) {
245 +                       caldatalen1 = cfe_erasesize;
246 +                       caldataaddr1 = rounddown(data->caldata[0],
247 +                                                cfe_erasesize);
248 +               }
249 +               if (data->caldata[1]) {
250 +                       caldatalen2 = cfe_erasesize;
251 +                       caldataaddr2 = rounddown(data->caldata[1],
252 +                                                cfe_erasesize);
253 +               }
254 +               if (caldataaddr1 == caldataaddr2) {
255 +                       caldataaddr2 = 0;
256 +                       caldatalen2 = 0;
257 +               }
258 +       }
259 +
260 +       imageaddr = cfelen;
261 +       imagelen = min_not_zero(nvramaddr, caldataaddr1) - imageaddr;
262  
263         if (caldatalen1 > 0)
264                 nrparts++;
265 @@ -158,10 +256,8 @@ static int bcm63xx_parse_cfe_partitions(
266  
267         /* Ask kernel for more memory */
268         parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
269 -       if (!parts) {
270 -               vfree(buf);
271 +       if (!parts)
272                 return -ENOMEM;
273 -       }
274  
275         /* Start building partition list */
276         parts[curpart].name = "CFE";
277 @@ -169,29 +265,7 @@ static int bcm63xx_parse_cfe_partitions(
278         parts[curpart].size = cfelen;
279         curpart++;
280  
281 -       if (kernellen > 0) {
282 -               int kernelpart = curpart;
283 -
284 -               if (rootfslen > 0 && rootfs_first)
285 -                       kernelpart++;
286 -               parts[kernelpart].name = "kernel";
287 -               parts[kernelpart].offset = kerneladdr;
288 -               parts[kernelpart].size = kernellen;
289 -               curpart++;
290 -       }
291 -
292 -       if (rootfslen > 0) {
293 -               int rootfspart = curpart;
294 -
295 -               if (kernellen > 0 && rootfs_first)
296 -                       rootfspart--;
297 -               parts[rootfspart].name = "rootfs";
298 -               parts[rootfspart].offset = rootfsaddr;
299 -               parts[rootfspart].size = rootfslen;
300 -               if (sparelen > 0  && !rootfs_first)
301 -                       parts[rootfspart].size += sparelen;
302 -               curpart++;
303 -       }
304 +       curpart += parse_bcmtag(master, parts, curpart, imageaddr, imagelen);
305  
306         if (caldatalen1 > 0) {
307                 if (caldatalen2 > 0)
308 @@ -217,25 +291,33 @@ static int bcm63xx_parse_cfe_partitions(
309  
310         /* Global partition "linux" to make easy firmware upgrade */
311         parts[curpart].name = "linux";
312 -       parts[curpart].offset = cfelen;
313 -       parts[curpart].size = min_not_zero(nvramaddr, caldataaddr1) - cfelen;
314 +       parts[curpart].offset = imageaddr;
315 +       parts[curpart].size = imagelen;
316 +       curpart++;
317  
318 -       for (i = 0; i < nrparts; i++)
319 +       for (i = 0; i < curpart; i++)
320                 pr_info("Partition %d is %s offset %llx and length %llx\n", i,
321                         parts[i].name, parts[i].offset, parts[i].size);
322  
323 -       pr_info("Spare partition is offset %x and length %x\n", spareaddr,
324 -               sparelen);
325 -
326         *pparts = parts;
327 -       vfree(buf);
328  
329         return nrparts;
330  };
331  
332 +
333 +static int bcm63xx_parse_partitions(struct mtd_info *master,
334 +                                   struct mtd_partition **pparts,
335 +                                   struct mtd_part_parser_data *data)
336 +{
337 +       if (data && data->of_node)
338 +               return bcm63xx_parse_cfe_partitions_of(master, pparts, data);
339 +       else
340 +               return bcm63xx_parse_cfe_partitions(master, pparts, data);
341 +}
342 +
343  static struct mtd_part_parser bcm63xx_cfe_parser = {
344         .owner = THIS_MODULE,
345 -       .parse_fn = bcm63xx_parse_cfe_partitions,
346 +       .parse_fn = bcm63xx_parse_partitions,
347         .name = "bcm63xxpart",
348  };
349