ofpart_core.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Flash partitions described by the OF (or flattened) device tree
  4. *
  5. * Copyright © 2006 MontaVista Software Inc.
  6. * Author: Vitaly Wool <vwool@ru.mvista.com>
  7. *
  8. * Revised to handle newer style flash binding by:
  9. * Copyright © 2007 David Gibson, IBM Corporation.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <linux/of.h>
  14. #include <linux/mtd/mtd.h>
  15. #include <linux/slab.h>
  16. #include <linux/mtd/partitions.h>
  17. #include "ofpart_bcm4908.h"
  18. #include "ofpart_linksys_ns.h"
  19. struct fixed_partitions_quirks {
  20. int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
  21. };
  22. static struct fixed_partitions_quirks bcm4908_partitions_quirks = {
  23. .post_parse = bcm4908_partitions_post_parse,
  24. };
  25. static struct fixed_partitions_quirks linksys_ns_partitions_quirks = {
  26. .post_parse = linksys_ns_partitions_post_parse,
  27. };
  28. static const struct of_device_id parse_ofpart_match_table[];
  29. static bool node_has_compatible(struct device_node *pp)
  30. {
  31. return of_get_property(pp, "compatible", NULL);
  32. }
  33. static int parse_fixed_partitions(struct mtd_info *master,
  34. const struct mtd_partition **pparts,
  35. struct mtd_part_parser_data *data)
  36. {
  37. const struct fixed_partitions_quirks *quirks;
  38. const struct of_device_id *of_id;
  39. struct mtd_partition *parts;
  40. struct device_node *mtd_node;
  41. struct device_node *ofpart_node;
  42. const char *partname;
  43. struct device_node *pp;
  44. int nr_parts, i, ret = 0;
  45. bool dedicated = true;
  46. /* Pull of_node from the master device node */
  47. mtd_node = mtd_get_of_node(master);
  48. if (!mtd_node)
  49. return 0;
  50. if (!master->parent) { /* Master */
  51. ofpart_node = of_get_child_by_name(mtd_node, "partitions");
  52. if (!ofpart_node) {
  53. /*
  54. * We might get here even when ofpart isn't used at all (e.g.,
  55. * when using another parser), so don't be louder than
  56. * KERN_DEBUG
  57. */
  58. pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
  59. master->name, mtd_node);
  60. ofpart_node = mtd_node;
  61. dedicated = false;
  62. }
  63. } else { /* Partition */
  64. ofpart_node = mtd_node;
  65. }
  66. of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
  67. if (dedicated && !of_id) {
  68. /* The 'partitions' subnode might be used by another parser */
  69. return 0;
  70. }
  71. quirks = of_id ? of_id->data : NULL;
  72. /* First count the subnodes */
  73. nr_parts = 0;
  74. for_each_child_of_node(ofpart_node, pp) {
  75. if (!dedicated && node_has_compatible(pp))
  76. continue;
  77. nr_parts++;
  78. }
  79. if (nr_parts == 0)
  80. return 0;
  81. parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  82. if (!parts)
  83. return -ENOMEM;
  84. i = 0;
  85. for_each_child_of_node(ofpart_node, pp) {
  86. const __be32 *reg;
  87. int len;
  88. int a_cells, s_cells;
  89. if (!dedicated && node_has_compatible(pp))
  90. continue;
  91. reg = of_get_property(pp, "reg", &len);
  92. if (!reg) {
  93. if (dedicated) {
  94. pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
  95. master->name, pp,
  96. mtd_node);
  97. goto ofpart_fail;
  98. } else {
  99. nr_parts--;
  100. continue;
  101. }
  102. }
  103. a_cells = of_n_addr_cells(pp);
  104. s_cells = of_n_size_cells(pp);
  105. if (!dedicated && s_cells == 0) {
  106. /*
  107. * This is a ugly workaround to not create
  108. * regression on devices that are still creating
  109. * partitions as direct children of the nand controller.
  110. * This can happen in case the nand controller node has
  111. * #size-cells equal to 0 and the firmware (e.g.
  112. * U-Boot) just add the partitions there assuming
  113. * 32-bit addressing.
  114. *
  115. * If you get this warning your firmware and/or DTS
  116. * should be really fixed.
  117. *
  118. * This is working only for devices smaller than 4GiB.
  119. */
  120. pr_warn("%s: ofpart partition %pOF (%pOF) #size-cells is wrongly set to <0>, assuming <1> for parsing partitions.\n",
  121. master->name, pp, mtd_node);
  122. s_cells = 1;
  123. }
  124. if (len / 4 != a_cells + s_cells) {
  125. pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
  126. master->name, pp,
  127. mtd_node);
  128. goto ofpart_fail;
  129. }
  130. parts[i].offset = of_read_number(reg, a_cells);
  131. parts[i].size = of_read_number(reg + a_cells, s_cells);
  132. parts[i].of_node = pp;
  133. partname = of_get_property(pp, "label", &len);
  134. if (!partname)
  135. partname = of_get_property(pp, "name", &len);
  136. parts[i].name = partname;
  137. if (of_property_read_bool(pp, "read-only"))
  138. parts[i].mask_flags |= MTD_WRITEABLE;
  139. if (of_property_read_bool(pp, "lock"))
  140. parts[i].mask_flags |= MTD_POWERUP_LOCK;
  141. if (of_property_read_bool(pp, "slc-mode"))
  142. parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION;
  143. i++;
  144. }
  145. if (!nr_parts)
  146. goto ofpart_none;
  147. if (quirks && quirks->post_parse)
  148. quirks->post_parse(master, parts, nr_parts);
  149. *pparts = parts;
  150. return nr_parts;
  151. ofpart_fail:
  152. pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
  153. master->name, pp, mtd_node);
  154. ret = -EINVAL;
  155. ofpart_none:
  156. of_node_put(pp);
  157. kfree(parts);
  158. return ret;
  159. }
  160. static const struct of_device_id parse_ofpart_match_table[] = {
  161. /* Generic */
  162. { .compatible = "fixed-partitions" },
  163. /* Customized */
  164. { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
  165. { .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, },
  166. {},
  167. };
  168. MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
  169. static struct mtd_part_parser ofpart_parser = {
  170. .parse_fn = parse_fixed_partitions,
  171. .name = "fixed-partitions",
  172. .of_match_table = parse_ofpart_match_table,
  173. };
  174. static int parse_ofoldpart_partitions(struct mtd_info *master,
  175. const struct mtd_partition **pparts,
  176. struct mtd_part_parser_data *data)
  177. {
  178. struct mtd_partition *parts;
  179. struct device_node *dp;
  180. int i, plen, nr_parts;
  181. const struct {
  182. __be32 offset, len;
  183. } *part;
  184. const char *names;
  185. /* Pull of_node from the master device node */
  186. dp = mtd_get_of_node(master);
  187. if (!dp)
  188. return 0;
  189. part = of_get_property(dp, "partitions", &plen);
  190. if (!part)
  191. return 0; /* No partitions found */
  192. pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
  193. nr_parts = plen / sizeof(part[0]);
  194. parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  195. if (!parts)
  196. return -ENOMEM;
  197. names = of_get_property(dp, "partition-names", &plen);
  198. for (i = 0; i < nr_parts; i++) {
  199. parts[i].offset = be32_to_cpu(part->offset);
  200. parts[i].size = be32_to_cpu(part->len) & ~1;
  201. /* bit 0 set signifies read only partition */
  202. if (be32_to_cpu(part->len) & 1)
  203. parts[i].mask_flags = MTD_WRITEABLE;
  204. if (names && (plen > 0)) {
  205. int len = strlen(names) + 1;
  206. parts[i].name = names;
  207. plen -= len;
  208. names += len;
  209. } else {
  210. parts[i].name = "unnamed";
  211. }
  212. part++;
  213. }
  214. *pparts = parts;
  215. return nr_parts;
  216. }
  217. static struct mtd_part_parser ofoldpart_parser = {
  218. .parse_fn = parse_ofoldpart_partitions,
  219. .name = "ofoldpart",
  220. };
  221. static int __init ofpart_parser_init(void)
  222. {
  223. register_mtd_parser(&ofpart_parser);
  224. register_mtd_parser(&ofoldpart_parser);
  225. return 0;
  226. }
  227. static void __exit ofpart_parser_exit(void)
  228. {
  229. deregister_mtd_parser(&ofpart_parser);
  230. deregister_mtd_parser(&ofoldpart_parser);
  231. }
  232. module_init(ofpart_parser_init);
  233. module_exit(ofpart_parser_exit);
  234. MODULE_LICENSE("GPL");
  235. MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
  236. MODULE_AUTHOR("Vitaly Wool, David Gibson");
  237. /*
  238. * When MTD core cannot find the requested parser, it tries to load the module
  239. * with the same name. Since we provide the ofoldpart parser, we should have
  240. * the corresponding alias.
  241. */
  242. MODULE_ALIAS("fixed-partitions");
  243. MODULE_ALIAS("ofoldpart");