1 /*
2 * Flash mappings described by the OF (or flattened) device tree
3 *
4 * Copyright (C) 2006 MontaVista Software Inc.
5 * Author: Vitaly Wool <vwool@ru.mvista.com>
6 *
7 * Revised to handle newer style flash binding by:
8 * Copyright (C) 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/types.h>
18 #include <linux/device.h>
19 #include <linux/mtd/mtd.h>
20 #include <linux/mtd/map.h>
21 #include <linux/mtd/partitions.h>
22 #include <linux/mtd/concat.h>
23 #include <linux/mtd/cfi_endian.h>
24 #include <linux/of.h>
25 #include <linux/of_address.h>
26 #include <linux/of_platform.h>
27 #include <linux/slab.h>
28 #include "physmap_of_gemini.h"
29 #include "physmap_of_versatile.h"
30
31 struct of_flash_list {
32 struct mtd_info *mtd;
33 struct map_info map;
34 };
35
36 struct of_flash {
37 struct mtd_info *cmtd;
38 int list_size; /* number of elements in of_flash_list */
39 struct of_flash_list list[0];
40 };
41
of_flash_remove(struct platform_device * dev)42 static int of_flash_remove(struct platform_device *dev)
43 {
44 struct of_flash *info;
45 int i;
46
47 info = dev_get_drvdata(&dev->dev);
48 if (!info)
49 return 0;
50 dev_set_drvdata(&dev->dev, NULL);
51
52 if (info->cmtd) {
53 mtd_device_unregister(info->cmtd);
54 if (info->cmtd != info->list[0].mtd)
55 mtd_concat_destroy(info->cmtd);
56 }
57
58 for (i = 0; i < info->list_size; i++)
59 if (info->list[i].mtd)
60 map_destroy(info->list[i].mtd);
61
62 return 0;
63 }
64
65 static const char * const rom_probe_types[] = {
66 "cfi_probe", "jedec_probe", "map_rom" };
67
68 /* Helper function to handle probing of the obsolete "direct-mapped"
69 * compatible binding, which has an extra "probe-type" property
70 * describing the type of flash probe necessary. */
obsolete_probe(struct platform_device * dev,struct map_info * map)71 static struct mtd_info *obsolete_probe(struct platform_device *dev,
72 struct map_info *map)
73 {
74 struct device_node *dp = dev->dev.of_node;
75 const char *of_probe;
76 struct mtd_info *mtd;
77 int i;
78
79 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
80 "flash binding\n");
81
82 of_probe = of_get_property(dp, "probe-type", NULL);
83 if (!of_probe) {
84 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
85 mtd = do_map_probe(rom_probe_types[i], map);
86 if (mtd)
87 return mtd;
88 }
89 return NULL;
90 } else if (strcmp(of_probe, "CFI") == 0) {
91 return do_map_probe("cfi_probe", map);
92 } else if (strcmp(of_probe, "JEDEC") == 0) {
93 return do_map_probe("jedec_probe", map);
94 } else {
95 if (strcmp(of_probe, "ROM") != 0)
96 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
97 "type '%s', mapping as rom\n", of_probe);
98 return do_map_probe("map_rom", map);
99 }
100 }
101
102 /* When partitions are set we look for a linux,part-probe property which
103 specifies the list of partition probers to use. If none is given then the
104 default is use. These take precedence over other device tree
105 information. */
106 static const char * const part_probe_types_def[] = {
107 "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
108
of_get_probes(struct device_node * dp)109 static const char * const *of_get_probes(struct device_node *dp)
110 {
111 const char **res;
112 int count;
113
114 count = of_property_count_strings(dp, "linux,part-probe");
115 if (count < 0)
116 return part_probe_types_def;
117
118 res = kcalloc(count + 1, sizeof(*res), GFP_KERNEL);
119 if (!res)
120 return NULL;
121
122 count = of_property_read_string_array(dp, "linux,part-probe", res,
123 count);
124 if (count < 0)
125 return NULL;
126
127 return res;
128 }
129
of_free_probes(const char * const * probes)130 static void of_free_probes(const char * const *probes)
131 {
132 if (probes != part_probe_types_def)
133 kfree(probes);
134 }
135
136 static const struct of_device_id of_flash_match[];
of_flash_probe(struct platform_device * dev)137 static int of_flash_probe(struct platform_device *dev)
138 {
139 const char * const *part_probe_types;
140 const struct of_device_id *match;
141 struct device_node *dp = dev->dev.of_node;
142 struct resource res;
143 struct of_flash *info;
144 const char *probe_type;
145 const __be32 *width;
146 int err;
147 int i;
148 int count;
149 const __be32 *p;
150 int reg_tuple_size;
151 struct mtd_info **mtd_list = NULL;
152 resource_size_t res_size;
153 bool map_indirect;
154 const char *mtd_name = NULL;
155
156 match = of_match_device(of_flash_match, &dev->dev);
157 if (!match)
158 return -EINVAL;
159 probe_type = match->data;
160
161 reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
162
163 of_property_read_string(dp, "linux,mtd-name", &mtd_name);
164
165 /*
166 * Get number of "reg" tuples. Scan for MTD devices on area's
167 * described by each "reg" region. This makes it possible (including
168 * the concat support) to support the Intel P30 48F4400 chips which
169 * consists internally of 2 non-identical NOR chips on one die.
170 */
171 p = of_get_property(dp, "reg", &count);
172 if (!p || count % reg_tuple_size != 0) {
173 dev_err(&dev->dev, "Malformed reg property on %pOF\n",
174 dev->dev.of_node);
175 err = -EINVAL;
176 goto err_flash_remove;
177 }
178 count /= reg_tuple_size;
179
180 map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
181
182 err = -ENOMEM;
183 info = devm_kzalloc(&dev->dev,
184 sizeof(struct of_flash) +
185 sizeof(struct of_flash_list) * count, GFP_KERNEL);
186 if (!info)
187 goto err_flash_remove;
188
189 dev_set_drvdata(&dev->dev, info);
190
191 mtd_list = kcalloc(count, sizeof(*mtd_list), GFP_KERNEL);
192 if (!mtd_list)
193 goto err_flash_remove;
194
195 for (i = 0; i < count; i++) {
196 err = -ENXIO;
197 if (of_address_to_resource(dp, i, &res)) {
198 /*
199 * Continue with next register tuple if this
200 * one is not mappable
201 */
202 continue;
203 }
204
205 dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
206
207 err = -EBUSY;
208 res_size = resource_size(&res);
209 info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res);
210 if (IS_ERR(info->list[i].map.virt)) {
211 err = PTR_ERR(info->list[i].map.virt);
212 goto err_out;
213 }
214
215 err = -ENXIO;
216 width = of_get_property(dp, "bank-width", NULL);
217 if (!width) {
218 dev_err(&dev->dev, "Can't get bank width from device"
219 " tree\n");
220 goto err_out;
221 }
222
223 info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
224 info->list[i].map.phys = res.start;
225 info->list[i].map.size = res_size;
226 info->list[i].map.bankwidth = be32_to_cpup(width);
227 info->list[i].map.device_node = dp;
228
229 if (of_property_read_bool(dp, "big-endian"))
230 info->list[i].map.swap = CFI_BIG_ENDIAN;
231 else if (of_property_read_bool(dp, "little-endian"))
232 info->list[i].map.swap = CFI_LITTLE_ENDIAN;
233
234 err = of_flash_probe_gemini(dev, dp, &info->list[i].map);
235 if (err)
236 goto err_out;
237 err = of_flash_probe_versatile(dev, dp, &info->list[i].map);
238 if (err)
239 goto err_out;
240
241 simple_map_init(&info->list[i].map);
242
243 /*
244 * On some platforms (e.g. MPC5200) a direct 1:1 mapping
245 * may cause problems with JFFS2 usage, as the local bus (LPB)
246 * doesn't support unaligned accesses as implemented in the
247 * JFFS2 code via memcpy(). By setting NO_XIP, the
248 * flash will not be exposed directly to the MTD users
249 * (e.g. JFFS2) any more.
250 */
251 if (map_indirect)
252 info->list[i].map.phys = NO_XIP;
253
254 if (probe_type) {
255 info->list[i].mtd = do_map_probe(probe_type,
256 &info->list[i].map);
257 } else {
258 info->list[i].mtd = obsolete_probe(dev,
259 &info->list[i].map);
260 }
261
262 /* Fall back to mapping region as ROM */
263 if (!info->list[i].mtd) {
264 dev_warn(&dev->dev,
265 "do_map_probe() failed for type %s\n",
266 probe_type);
267
268 info->list[i].mtd = do_map_probe("map_rom",
269 &info->list[i].map);
270 }
271 mtd_list[i] = info->list[i].mtd;
272
273 err = -ENXIO;
274 if (!info->list[i].mtd) {
275 dev_err(&dev->dev, "do_map_probe() failed\n");
276 goto err_out;
277 } else {
278 info->list_size++;
279 }
280 info->list[i].mtd->dev.parent = &dev->dev;
281 }
282
283 err = 0;
284 info->cmtd = NULL;
285 if (info->list_size == 1) {
286 info->cmtd = info->list[0].mtd;
287 } else if (info->list_size > 1) {
288 /*
289 * We detected multiple devices. Concatenate them together.
290 */
291 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
292 dev_name(&dev->dev));
293 }
294 if (info->cmtd == NULL)
295 err = -ENXIO;
296
297 if (err)
298 goto err_out;
299
300 info->cmtd->dev.parent = &dev->dev;
301 mtd_set_of_node(info->cmtd, dp);
302 part_probe_types = of_get_probes(dp);
303 if (!part_probe_types) {
304 err = -ENOMEM;
305 goto err_out;
306 }
307 mtd_device_parse_register(info->cmtd, part_probe_types, NULL,
308 NULL, 0);
309 of_free_probes(part_probe_types);
310
311 kfree(mtd_list);
312
313 return 0;
314
315 err_out:
316 kfree(mtd_list);
317 err_flash_remove:
318 of_flash_remove(dev);
319
320 return err;
321 }
322
323 static const struct of_device_id of_flash_match[] = {
324 {
325 .compatible = "cfi-flash",
326 .data = (void *)"cfi_probe",
327 },
328 {
329 /* FIXME: JEDEC chips can't be safely and reliably
330 * probed, although the mtd code gets it right in
331 * practice most of the time. We should use the
332 * vendor and device ids specified by the binding to
333 * bypass the heuristic probe code, but the mtd layer
334 * provides, at present, no interface for doing so
335 * :(. */
336 .compatible = "jedec-flash",
337 .data = (void *)"jedec_probe",
338 },
339 {
340 .compatible = "mtd-ram",
341 .data = (void *)"map_ram",
342 },
343 {
344 .compatible = "mtd-rom",
345 .data = (void *)"map_rom",
346 },
347 {
348 .type = "rom",
349 .compatible = "direct-mapped"
350 },
351 { },
352 };
353 MODULE_DEVICE_TABLE(of, of_flash_match);
354
355 static struct platform_driver of_flash_driver = {
356 .driver = {
357 .name = "of-flash",
358 .of_match_table = of_flash_match,
359 },
360 .probe = of_flash_probe,
361 .remove = of_flash_remove,
362 };
363
364 module_platform_driver(of_flash_driver);
365
366 MODULE_LICENSE("GPL");
367 MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
368 MODULE_DESCRIPTION("Device tree based MTD map driver");
369