Branch data Line data Source code
1 : : /*
2 : : * Flash partitions described by the OF (or flattened) device tree
3 : : *
4 : : * Copyright © 2006 MontaVista Software Inc.
5 : : * Author: Vitaly Wool <vwool@ru.mvista.com>
6 : : *
7 : : * Revised to handle newer style flash binding by:
8 : : * Copyright © 2007 David Gibson, IBM Corporation.
9 : : *
10 : : * This program is free software; you can redistribute it and/or modify it
11 : : * under the terms of the GNU General Public License as published by the
12 : : * Free Software Foundation; either version 2 of the License, or (at your
13 : : * option) any later version.
14 : : */
15 : :
16 : : #include <linux/module.h>
17 : : #include <linux/init.h>
18 : : #include <linux/of.h>
19 : : #include <linux/mtd/mtd.h>
20 : : #include <linux/slab.h>
21 : : #include <linux/mtd/partitions.h>
22 : :
23 : : static bool node_has_compatible(struct device_node *pp)
24 : : {
25 : 0 : return of_get_property(pp, "compatible", NULL);
26 : : }
27 : :
28 : 0 : static int parse_ofpart_partitions(struct mtd_info *master,
29 : : struct mtd_partition **pparts,
30 : : struct mtd_part_parser_data *data)
31 : : {
32 : : struct device_node *node;
33 : : const char *partname;
34 : : struct device_node *pp;
35 : : int nr_parts, i;
36 : :
37 : :
38 [ # # ]: 0 : if (!data)
39 : : return 0;
40 : :
41 : 0 : node = data->of_node;
42 [ # # ]: 0 : if (!node)
43 : : return 0;
44 : :
45 : : /* First count the subnodes */
46 : : nr_parts = 0;
47 [ # # ]: 0 : for_each_child_of_node(node, pp) {
48 [ # # ]: 0 : if (node_has_compatible(pp))
49 : 0 : continue;
50 : :
51 : 0 : nr_parts++;
52 : : }
53 : :
54 [ # # ]: 0 : if (nr_parts == 0)
55 : : return 0;
56 : :
57 : 0 : *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
58 [ # # ]: 0 : if (!*pparts)
59 : : return -ENOMEM;
60 : :
61 : : i = 0;
62 [ # # ]: 0 : for_each_child_of_node(node, pp) {
63 : : const __be32 *reg;
64 : : int len;
65 : : int a_cells, s_cells;
66 : :
67 [ # # ]: 0 : if (node_has_compatible(pp))
68 : 0 : continue;
69 : :
70 : 0 : reg = of_get_property(pp, "reg", &len);
71 [ # # ]: 0 : if (!reg) {
72 : 0 : nr_parts--;
73 : 0 : continue;
74 : : }
75 : :
76 : 0 : a_cells = of_n_addr_cells(pp);
77 : 0 : s_cells = of_n_size_cells(pp);
78 : 0 : (*pparts)[i].offset = of_read_number(reg, a_cells);
79 : 0 : (*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
80 : :
81 : 0 : partname = of_get_property(pp, "label", &len);
82 [ # # ]: 0 : if (!partname)
83 : 0 : partname = of_get_property(pp, "name", &len);
84 : 0 : (*pparts)[i].name = (char *)partname;
85 : :
86 [ # # ]: 0 : if (of_get_property(pp, "read-only", &len))
87 : 0 : (*pparts)[i].mask_flags |= MTD_WRITEABLE;
88 : :
89 [ # # ]: 0 : if (of_get_property(pp, "lock", &len))
90 : 0 : (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
91 : :
92 : 0 : i++;
93 : : }
94 : :
95 [ # # ]: 0 : if (!i) {
96 : : of_node_put(pp);
97 : 0 : pr_err("No valid partition found on %s\n", node->full_name);
98 : 0 : kfree(*pparts);
99 : 0 : *pparts = NULL;
100 : 0 : return -EINVAL;
101 : : }
102 : :
103 : : return nr_parts;
104 : : }
105 : :
106 : : static struct mtd_part_parser ofpart_parser = {
107 : : .owner = THIS_MODULE,
108 : : .parse_fn = parse_ofpart_partitions,
109 : : .name = "ofpart",
110 : : };
111 : :
112 : 0 : static int parse_ofoldpart_partitions(struct mtd_info *master,
113 : : struct mtd_partition **pparts,
114 : : struct mtd_part_parser_data *data)
115 : : {
116 : : struct device_node *dp;
117 : : int i, plen, nr_parts;
118 : : const struct {
119 : : __be32 offset, len;
120 : : } *part;
121 : : const char *names;
122 : :
123 [ # # ]: 0 : if (!data)
124 : : return 0;
125 : :
126 : 0 : dp = data->of_node;
127 [ # # ]: 0 : if (!dp)
128 : : return 0;
129 : :
130 : 0 : part = of_get_property(dp, "partitions", &plen);
131 [ # # ]: 0 : if (!part)
132 : : return 0; /* No partitions found */
133 : :
134 : 0 : pr_warning("Device tree uses obsolete partition map binding: %s\n",
135 : : dp->full_name);
136 : :
137 : 0 : nr_parts = plen / sizeof(part[0]);
138 : :
139 : 0 : *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL);
140 [ # # ]: 0 : if (!*pparts)
141 : : return -ENOMEM;
142 : :
143 : 0 : names = of_get_property(dp, "partition-names", &plen);
144 : :
145 [ # # ]: 0 : for (i = 0; i < nr_parts; i++) {
146 [ # # ]: 0 : (*pparts)[i].offset = be32_to_cpu(part->offset);
147 [ # # ]: 0 : (*pparts)[i].size = be32_to_cpu(part->len) & ~1;
148 : : /* bit 0 set signifies read only partition */
149 [ # # ][ # # ]: 0 : if (be32_to_cpu(part->len) & 1)
150 : 0 : (*pparts)[i].mask_flags = MTD_WRITEABLE;
151 : :
152 [ # # ][ # # ]: 0 : if (names && (plen > 0)) {
153 : 0 : int len = strlen(names) + 1;
154 : :
155 : 0 : (*pparts)[i].name = (char *)names;
156 : 0 : plen -= len;
157 : 0 : names += len;
158 : : } else {
159 : 0 : (*pparts)[i].name = "unnamed";
160 : : }
161 : :
162 : 0 : part++;
163 : : }
164 : :
165 : : return nr_parts;
166 : : }
167 : :
168 : : static struct mtd_part_parser ofoldpart_parser = {
169 : : .owner = THIS_MODULE,
170 : : .parse_fn = parse_ofoldpart_partitions,
171 : : .name = "ofoldpart",
172 : : };
173 : :
174 : 0 : static int __init ofpart_parser_init(void)
175 : : {
176 : : int rc;
177 : 0 : rc = register_mtd_parser(&ofpart_parser);
178 [ # # ]: 0 : if (rc)
179 : : goto out;
180 : :
181 : 0 : rc = register_mtd_parser(&ofoldpart_parser);
182 [ # # ]: 0 : if (!rc)
183 : : return 0;
184 : :
185 : 0 : deregister_mtd_parser(&ofoldpart_parser);
186 : : out:
187 : 0 : return rc;
188 : : }
189 : :
190 : 0 : static void __exit ofpart_parser_exit(void)
191 : : {
192 : 0 : deregister_mtd_parser(&ofpart_parser);
193 : 0 : deregister_mtd_parser(&ofoldpart_parser);
194 : 0 : }
195 : :
196 : : module_init(ofpart_parser_init);
197 : : module_exit(ofpart_parser_exit);
198 : :
199 : : MODULE_LICENSE("GPL");
200 : : MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
201 : : MODULE_AUTHOR("Vitaly Wool, David Gibson");
202 : : /*
203 : : * When MTD core cannot find the requested parser, it tries to load the module
204 : : * with the same name. Since we provide the ofoldpart parser, we should have
205 : : * the corresponding alias.
206 : : */
207 : : MODULE_ALIAS("ofoldpart");
|