403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. From afbef8efb591792579c633a7c545f914c6165f82 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <[email protected]>
  3. Date: Thu, 11 Feb 2021 23:04:27 +0100
  4. Subject: [PATCH] mtd: parsers: ofpart: support BCM4908 fixed partitions
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. Some devices use fixed partitioning with some partitions requiring some
  9. extra logic. E.g. BCM4908 may have multiple firmware partitions but
  10. detecting currently used one requires checking bootloader parameters.
  11. To support such cases without duplicating a lot of code (without copying
  12. most of the ofpart.c code) support for post-parsing callback was added.
  13. BCM4908 support in ofpart can be enabled using config option and results
  14. in compiling & executing a specific callback. It simply reads offset of
  15. currently used firmware partition from the DT. Bootloader specifies it
  16. using the "brcm_blparms" property.
  17. Signed-off-by: Rafał Miłecki <[email protected]>
  18. ---
  19. drivers/mtd/parsers/Kconfig | 9 +++
  20. drivers/mtd/parsers/Makefile | 2 +
  21. drivers/mtd/parsers/ofpart_bcm4908.c | 64 +++++++++++++++++++
  22. drivers/mtd/parsers/ofpart_bcm4908.h | 15 +++++
  23. .../mtd/parsers/{ofpart.c => ofpart_core.c} | 28 +++++++-
  24. 5 files changed, 116 insertions(+), 2 deletions(-)
  25. create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.c
  26. create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.h
  27. rename drivers/mtd/parsers/{ofpart.c => ofpart_core.c} (88%)
  28. --- a/drivers/mtd/parsers/Kconfig
  29. +++ b/drivers/mtd/parsers/Kconfig
  30. @@ -67,6 +67,15 @@ config MTD_OF_PARTS
  31. flash memory node, as described in
  32. Documentation/devicetree/bindings/mtd/partition.txt.
  33. +config MTD_OF_PARTS_BCM4908
  34. + bool "BCM4908 partitioning support"
  35. + depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST)
  36. + default ARCH_BCM4908
  37. + help
  38. + This provides partitions parser for BCM4908 family devices
  39. + that can have multiple "firmware" partitions. It takes care of
  40. + finding currently used one and backup ones.
  41. +
  42. config MTD_PARSER_IMAGETAG
  43. tristate "Parser for BCM963XX Image Tag format partitions"
  44. depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
  45. --- a/drivers/mtd/parsers/Makefile
  46. +++ b/drivers/mtd/parsers/Makefile
  47. @@ -4,6 +4,8 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm4
  48. obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
  49. obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
  50. obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
  51. +ofpart-y += ofpart_core.o
  52. +ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
  53. obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
  54. obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
  55. obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
  56. --- /dev/null
  57. +++ b/drivers/mtd/parsers/ofpart_bcm4908.c
  58. @@ -0,0 +1,64 @@
  59. +// SPDX-License-Identifier: GPL-2.0
  60. +/*
  61. + * Copyright (C) 2021 Rafał Miłecki <[email protected]>
  62. + */
  63. +
  64. +#include <linux/module.h>
  65. +#include <linux/init.h>
  66. +#include <linux/of.h>
  67. +#include <linux/mtd/mtd.h>
  68. +#include <linux/slab.h>
  69. +#include <linux/mtd/partitions.h>
  70. +
  71. +#include "ofpart_bcm4908.h"
  72. +
  73. +#define BLPARAMS_FW_OFFSET "NAND_RFS_OFS"
  74. +
  75. +static long long bcm4908_partitions_fw_offset(void)
  76. +{
  77. + struct device_node *root;
  78. + struct property *prop;
  79. + const char *s;
  80. +
  81. + root = of_find_node_by_path("/");
  82. + if (!root)
  83. + return -ENOENT;
  84. +
  85. + of_property_for_each_string(root, "brcm_blparms", prop, s) {
  86. + size_t len = strlen(BLPARAMS_FW_OFFSET);
  87. + unsigned long offset;
  88. + int err;
  89. +
  90. + if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=')
  91. + continue;
  92. +
  93. + err = kstrtoul(s + len + 1, 0, &offset);
  94. + if (err) {
  95. + pr_err("failed to parse %s\n", s + len + 1);
  96. + return err;
  97. + }
  98. +
  99. + return offset << 10;
  100. + }
  101. +
  102. + return -ENOENT;
  103. +}
  104. +
  105. +int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts)
  106. +{
  107. + long long fw_offset;
  108. + int i;
  109. +
  110. + fw_offset = bcm4908_partitions_fw_offset();
  111. +
  112. + for (i = 0; i < nr_parts; i++) {
  113. + if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) {
  114. + if (fw_offset < 0 || parts[i].offset == fw_offset)
  115. + parts[i].name = "firmware";
  116. + else
  117. + parts[i].name = "backup";
  118. + }
  119. + }
  120. +
  121. + return 0;
  122. +}
  123. --- /dev/null
  124. +++ b/drivers/mtd/parsers/ofpart_bcm4908.h
  125. @@ -0,0 +1,15 @@
  126. +/* SPDX-License-Identifier: GPL-2.0 */
  127. +#ifndef __BCM4908_PARTITIONS_H
  128. +#define __BCM4908_PARTITIONS_H
  129. +
  130. +#ifdef CONFIG_MTD_OF_PARTS_BCM4908
  131. +int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
  132. +#else
  133. +static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts,
  134. + int nr_parts)
  135. +{
  136. + return -EOPNOTSUPP;
  137. +}
  138. +#endif
  139. +
  140. +#endif
  141. --- a/drivers/mtd/parsers/ofpart.c
  142. +++ /dev/null
  143. @@ -1,239 +0,0 @@
  144. -// SPDX-License-Identifier: GPL-2.0-or-later
  145. -/*
  146. - * Flash partitions described by the OF (or flattened) device tree
  147. - *
  148. - * Copyright © 2006 MontaVista Software Inc.
  149. - * Author: Vitaly Wool <[email protected]>
  150. - *
  151. - * Revised to handle newer style flash binding by:
  152. - * Copyright © 2007 David Gibson, IBM Corporation.
  153. - */
  154. -
  155. -#include <linux/module.h>
  156. -#include <linux/init.h>
  157. -#include <linux/of.h>
  158. -#include <linux/mtd/mtd.h>
  159. -#include <linux/slab.h>
  160. -#include <linux/mtd/partitions.h>
  161. -
  162. -static bool node_has_compatible(struct device_node *pp)
  163. -{
  164. - return of_get_property(pp, "compatible", NULL);
  165. -}
  166. -
  167. -static int parse_fixed_partitions(struct mtd_info *master,
  168. - const struct mtd_partition **pparts,
  169. - struct mtd_part_parser_data *data)
  170. -{
  171. - struct mtd_partition *parts;
  172. - struct device_node *mtd_node;
  173. - struct device_node *ofpart_node;
  174. - const char *partname;
  175. - struct device_node *pp;
  176. - int nr_parts, i, ret = 0;
  177. - bool dedicated = true;
  178. -
  179. -
  180. - /* Pull of_node from the master device node */
  181. - mtd_node = mtd_get_of_node(master);
  182. - if (!mtd_node)
  183. - return 0;
  184. -
  185. - ofpart_node = of_get_child_by_name(mtd_node, "partitions");
  186. - if (!ofpart_node) {
  187. - /*
  188. - * We might get here even when ofpart isn't used at all (e.g.,
  189. - * when using another parser), so don't be louder than
  190. - * KERN_DEBUG
  191. - */
  192. - pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
  193. - master->name, mtd_node);
  194. - ofpart_node = mtd_node;
  195. - dedicated = false;
  196. - } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
  197. - /* The 'partitions' subnode might be used by another parser */
  198. - return 0;
  199. - }
  200. -
  201. - /* First count the subnodes */
  202. - nr_parts = 0;
  203. - for_each_child_of_node(ofpart_node, pp) {
  204. - if (!dedicated && node_has_compatible(pp))
  205. - continue;
  206. -
  207. - nr_parts++;
  208. - }
  209. -
  210. - if (nr_parts == 0)
  211. - return 0;
  212. -
  213. - parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  214. - if (!parts)
  215. - return -ENOMEM;
  216. -
  217. - i = 0;
  218. - for_each_child_of_node(ofpart_node, pp) {
  219. - const __be32 *reg;
  220. - int len;
  221. - int a_cells, s_cells;
  222. -
  223. - if (!dedicated && node_has_compatible(pp))
  224. - continue;
  225. -
  226. - reg = of_get_property(pp, "reg", &len);
  227. - if (!reg) {
  228. - if (dedicated) {
  229. - pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
  230. - master->name, pp,
  231. - mtd_node);
  232. - goto ofpart_fail;
  233. - } else {
  234. - nr_parts--;
  235. - continue;
  236. - }
  237. - }
  238. -
  239. - a_cells = of_n_addr_cells(pp);
  240. - s_cells = of_n_size_cells(pp);
  241. - if (len / 4 != a_cells + s_cells) {
  242. - pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
  243. - master->name, pp,
  244. - mtd_node);
  245. - goto ofpart_fail;
  246. - }
  247. -
  248. - parts[i].offset = of_read_number(reg, a_cells);
  249. - parts[i].size = of_read_number(reg + a_cells, s_cells);
  250. - parts[i].of_node = pp;
  251. -
  252. - partname = of_get_property(pp, "label", &len);
  253. - if (!partname)
  254. - partname = of_get_property(pp, "name", &len);
  255. - parts[i].name = partname;
  256. -
  257. - if (of_get_property(pp, "read-only", &len))
  258. - parts[i].mask_flags |= MTD_WRITEABLE;
  259. -
  260. - if (of_get_property(pp, "lock", &len))
  261. - parts[i].mask_flags |= MTD_POWERUP_LOCK;
  262. -
  263. - if (of_property_read_bool(pp, "slc-mode"))
  264. - parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION;
  265. -
  266. - i++;
  267. - }
  268. -
  269. - if (!nr_parts)
  270. - goto ofpart_none;
  271. -
  272. - *pparts = parts;
  273. - return nr_parts;
  274. -
  275. -ofpart_fail:
  276. - pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
  277. - master->name, pp, mtd_node);
  278. - ret = -EINVAL;
  279. -ofpart_none:
  280. - of_node_put(pp);
  281. - kfree(parts);
  282. - return ret;
  283. -}
  284. -
  285. -static const struct of_device_id parse_ofpart_match_table[] = {
  286. - { .compatible = "fixed-partitions" },
  287. - {},
  288. -};
  289. -MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
  290. -
  291. -static struct mtd_part_parser ofpart_parser = {
  292. - .parse_fn = parse_fixed_partitions,
  293. - .name = "fixed-partitions",
  294. - .of_match_table = parse_ofpart_match_table,
  295. -};
  296. -
  297. -static int parse_ofoldpart_partitions(struct mtd_info *master,
  298. - const struct mtd_partition **pparts,
  299. - struct mtd_part_parser_data *data)
  300. -{
  301. - struct mtd_partition *parts;
  302. - struct device_node *dp;
  303. - int i, plen, nr_parts;
  304. - const struct {
  305. - __be32 offset, len;
  306. - } *part;
  307. - const char *names;
  308. -
  309. - /* Pull of_node from the master device node */
  310. - dp = mtd_get_of_node(master);
  311. - if (!dp)
  312. - return 0;
  313. -
  314. - part = of_get_property(dp, "partitions", &plen);
  315. - if (!part)
  316. - return 0; /* No partitions found */
  317. -
  318. - pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
  319. -
  320. - nr_parts = plen / sizeof(part[0]);
  321. -
  322. - parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  323. - if (!parts)
  324. - return -ENOMEM;
  325. -
  326. - names = of_get_property(dp, "partition-names", &plen);
  327. -
  328. - for (i = 0; i < nr_parts; i++) {
  329. - parts[i].offset = be32_to_cpu(part->offset);
  330. - parts[i].size = be32_to_cpu(part->len) & ~1;
  331. - /* bit 0 set signifies read only partition */
  332. - if (be32_to_cpu(part->len) & 1)
  333. - parts[i].mask_flags = MTD_WRITEABLE;
  334. -
  335. - if (names && (plen > 0)) {
  336. - int len = strlen(names) + 1;
  337. -
  338. - parts[i].name = names;
  339. - plen -= len;
  340. - names += len;
  341. - } else {
  342. - parts[i].name = "unnamed";
  343. - }
  344. -
  345. - part++;
  346. - }
  347. -
  348. - *pparts = parts;
  349. - return nr_parts;
  350. -}
  351. -
  352. -static struct mtd_part_parser ofoldpart_parser = {
  353. - .parse_fn = parse_ofoldpart_partitions,
  354. - .name = "ofoldpart",
  355. -};
  356. -
  357. -static int __init ofpart_parser_init(void)
  358. -{
  359. - register_mtd_parser(&ofpart_parser);
  360. - register_mtd_parser(&ofoldpart_parser);
  361. - return 0;
  362. -}
  363. -
  364. -static void __exit ofpart_parser_exit(void)
  365. -{
  366. - deregister_mtd_parser(&ofpart_parser);
  367. - deregister_mtd_parser(&ofoldpart_parser);
  368. -}
  369. -
  370. -module_init(ofpart_parser_init);
  371. -module_exit(ofpart_parser_exit);
  372. -
  373. -MODULE_LICENSE("GPL");
  374. -MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
  375. -MODULE_AUTHOR("Vitaly Wool, David Gibson");
  376. -/*
  377. - * When MTD core cannot find the requested parser, it tries to load the module
  378. - * with the same name. Since we provide the ofoldpart parser, we should have
  379. - * the corresponding alias.
  380. - */
  381. -MODULE_ALIAS("fixed-partitions");
  382. -MODULE_ALIAS("ofoldpart");
  383. --- /dev/null
  384. +++ b/drivers/mtd/parsers/ofpart_core.c
  385. @@ -0,0 +1,263 @@
  386. +// SPDX-License-Identifier: GPL-2.0-or-later
  387. +/*
  388. + * Flash partitions described by the OF (or flattened) device tree
  389. + *
  390. + * Copyright © 2006 MontaVista Software Inc.
  391. + * Author: Vitaly Wool <[email protected]>
  392. + *
  393. + * Revised to handle newer style flash binding by:
  394. + * Copyright © 2007 David Gibson, IBM Corporation.
  395. + */
  396. +
  397. +#include <linux/module.h>
  398. +#include <linux/init.h>
  399. +#include <linux/of.h>
  400. +#include <linux/mtd/mtd.h>
  401. +#include <linux/slab.h>
  402. +#include <linux/mtd/partitions.h>
  403. +
  404. +#include "ofpart_bcm4908.h"
  405. +
  406. +struct fixed_partitions_quirks {
  407. + int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
  408. +};
  409. +
  410. +struct fixed_partitions_quirks bcm4908_partitions_quirks = {
  411. + .post_parse = bcm4908_partitions_post_parse,
  412. +};
  413. +
  414. +static const struct of_device_id parse_ofpart_match_table[];
  415. +
  416. +static bool node_has_compatible(struct device_node *pp)
  417. +{
  418. + return of_get_property(pp, "compatible", NULL);
  419. +}
  420. +
  421. +static int parse_fixed_partitions(struct mtd_info *master,
  422. + const struct mtd_partition **pparts,
  423. + struct mtd_part_parser_data *data)
  424. +{
  425. + const struct fixed_partitions_quirks *quirks;
  426. + const struct of_device_id *of_id;
  427. + struct mtd_partition *parts;
  428. + struct device_node *mtd_node;
  429. + struct device_node *ofpart_node;
  430. + const char *partname;
  431. + struct device_node *pp;
  432. + int nr_parts, i, ret = 0;
  433. + bool dedicated = true;
  434. +
  435. + /* Pull of_node from the master device node */
  436. + mtd_node = mtd_get_of_node(master);
  437. + if (!mtd_node)
  438. + return 0;
  439. +
  440. + ofpart_node = of_get_child_by_name(mtd_node, "partitions");
  441. + if (!ofpart_node) {
  442. + /*
  443. + * We might get here even when ofpart isn't used at all (e.g.,
  444. + * when using another parser), so don't be louder than
  445. + * KERN_DEBUG
  446. + */
  447. + pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
  448. + master->name, mtd_node);
  449. + ofpart_node = mtd_node;
  450. + dedicated = false;
  451. + }
  452. +
  453. + of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
  454. + if (dedicated && !of_id) {
  455. + /* The 'partitions' subnode might be used by another parser */
  456. + return 0;
  457. + }
  458. +
  459. + quirks = of_id ? of_id->data : NULL;
  460. +
  461. + /* First count the subnodes */
  462. + nr_parts = 0;
  463. + for_each_child_of_node(ofpart_node, pp) {
  464. + if (!dedicated && node_has_compatible(pp))
  465. + continue;
  466. +
  467. + nr_parts++;
  468. + }
  469. +
  470. + if (nr_parts == 0)
  471. + return 0;
  472. +
  473. + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  474. + if (!parts)
  475. + return -ENOMEM;
  476. +
  477. + i = 0;
  478. + for_each_child_of_node(ofpart_node, pp) {
  479. + const __be32 *reg;
  480. + int len;
  481. + int a_cells, s_cells;
  482. +
  483. + if (!dedicated && node_has_compatible(pp))
  484. + continue;
  485. +
  486. + reg = of_get_property(pp, "reg", &len);
  487. + if (!reg) {
  488. + if (dedicated) {
  489. + pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
  490. + master->name, pp,
  491. + mtd_node);
  492. + goto ofpart_fail;
  493. + } else {
  494. + nr_parts--;
  495. + continue;
  496. + }
  497. + }
  498. +
  499. + a_cells = of_n_addr_cells(pp);
  500. + s_cells = of_n_size_cells(pp);
  501. + if (len / 4 != a_cells + s_cells) {
  502. + pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
  503. + master->name, pp,
  504. + mtd_node);
  505. + goto ofpart_fail;
  506. + }
  507. +
  508. + parts[i].offset = of_read_number(reg, a_cells);
  509. + parts[i].size = of_read_number(reg + a_cells, s_cells);
  510. + parts[i].of_node = pp;
  511. +
  512. + partname = of_get_property(pp, "label", &len);
  513. + if (!partname)
  514. + partname = of_get_property(pp, "name", &len);
  515. + parts[i].name = partname;
  516. +
  517. + if (of_get_property(pp, "read-only", &len))
  518. + parts[i].mask_flags |= MTD_WRITEABLE;
  519. +
  520. + if (of_get_property(pp, "lock", &len))
  521. + parts[i].mask_flags |= MTD_POWERUP_LOCK;
  522. +
  523. + if (of_property_read_bool(pp, "slc-mode"))
  524. + parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION;
  525. +
  526. + i++;
  527. + }
  528. +
  529. + if (!nr_parts)
  530. + goto ofpart_none;
  531. +
  532. + if (quirks && quirks->post_parse)
  533. + quirks->post_parse(master, parts, nr_parts);
  534. +
  535. + *pparts = parts;
  536. + return nr_parts;
  537. +
  538. +ofpart_fail:
  539. + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
  540. + master->name, pp, mtd_node);
  541. + ret = -EINVAL;
  542. +ofpart_none:
  543. + of_node_put(pp);
  544. + kfree(parts);
  545. + return ret;
  546. +}
  547. +
  548. +static const struct of_device_id parse_ofpart_match_table[] = {
  549. + /* Generic */
  550. + { .compatible = "fixed-partitions" },
  551. + /* Customized */
  552. + { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
  553. + {},
  554. +};
  555. +MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
  556. +
  557. +static struct mtd_part_parser ofpart_parser = {
  558. + .parse_fn = parse_fixed_partitions,
  559. + .name = "fixed-partitions",
  560. + .of_match_table = parse_ofpart_match_table,
  561. +};
  562. +
  563. +static int parse_ofoldpart_partitions(struct mtd_info *master,
  564. + const struct mtd_partition **pparts,
  565. + struct mtd_part_parser_data *data)
  566. +{
  567. + struct mtd_partition *parts;
  568. + struct device_node *dp;
  569. + int i, plen, nr_parts;
  570. + const struct {
  571. + __be32 offset, len;
  572. + } *part;
  573. + const char *names;
  574. +
  575. + /* Pull of_node from the master device node */
  576. + dp = mtd_get_of_node(master);
  577. + if (!dp)
  578. + return 0;
  579. +
  580. + part = of_get_property(dp, "partitions", &plen);
  581. + if (!part)
  582. + return 0; /* No partitions found */
  583. +
  584. + pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
  585. +
  586. + nr_parts = plen / sizeof(part[0]);
  587. +
  588. + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  589. + if (!parts)
  590. + return -ENOMEM;
  591. +
  592. + names = of_get_property(dp, "partition-names", &plen);
  593. +
  594. + for (i = 0; i < nr_parts; i++) {
  595. + parts[i].offset = be32_to_cpu(part->offset);
  596. + parts[i].size = be32_to_cpu(part->len) & ~1;
  597. + /* bit 0 set signifies read only partition */
  598. + if (be32_to_cpu(part->len) & 1)
  599. + parts[i].mask_flags = MTD_WRITEABLE;
  600. +
  601. + if (names && (plen > 0)) {
  602. + int len = strlen(names) + 1;
  603. +
  604. + parts[i].name = names;
  605. + plen -= len;
  606. + names += len;
  607. + } else {
  608. + parts[i].name = "unnamed";
  609. + }
  610. +
  611. + part++;
  612. + }
  613. +
  614. + *pparts = parts;
  615. + return nr_parts;
  616. +}
  617. +
  618. +static struct mtd_part_parser ofoldpart_parser = {
  619. + .parse_fn = parse_ofoldpart_partitions,
  620. + .name = "ofoldpart",
  621. +};
  622. +
  623. +static int __init ofpart_parser_init(void)
  624. +{
  625. + register_mtd_parser(&ofpart_parser);
  626. + register_mtd_parser(&ofoldpart_parser);
  627. + return 0;
  628. +}
  629. +
  630. +static void __exit ofpart_parser_exit(void)
  631. +{
  632. + deregister_mtd_parser(&ofpart_parser);
  633. + deregister_mtd_parser(&ofoldpart_parser);
  634. +}
  635. +
  636. +module_init(ofpart_parser_init);
  637. +module_exit(ofpart_parser_exit);
  638. +
  639. +MODULE_LICENSE("GPL");
  640. +MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
  641. +MODULE_AUTHOR("Vitaly Wool, David Gibson");
  642. +/*
  643. + * When MTD core cannot find the requested parser, it tries to load the module
  644. + * with the same name. Since we provide the ofoldpart parser, we should have
  645. + * the corresponding alias.
  646. + */
  647. +MODULE_ALIAS("fixed-partitions");
  648. +MODULE_ALIAS("ofoldpart");