brcm63xx: backport mtd of node changes from upstream
[openwrt/openwrt.git] / target / linux / brcm63xx / patches-4.4 / 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 = mtd_get_of_node(master);
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 (mtd_get_of_node(master))
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