RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / mtd / maps / physmap_of.c
blob4b133ff9104941bedb6c0f03b5572581279a12c6
1 /*
2 * Flash mappings described by the OF (or flattened) device tree
4 * Copyright (C) 2006 MontaVista Software Inc.
5 * Author: Vitaly Wool <vwool@ru.mvista.com>
7 * Revised to handle newer style flash binding by:
8 * Copyright (C) 2007 David Gibson, IBM Corporation.
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.
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/init.h>
19 #include <linux/device.h>
20 #include <linux/mtd/mtd.h>
21 #include <linux/mtd/map.h>
22 #include <linux/mtd/partitions.h>
23 #include <linux/mtd/concat.h>
24 #include <linux/of.h>
25 #include <linux/of_address.h>
26 #include <linux/of_platform.h>
27 #include <linux/slab.h>
29 struct of_flash_list {
30 struct mtd_info *mtd;
31 struct map_info map;
32 struct resource *res;
35 struct of_flash {
36 struct mtd_info *cmtd;
37 #ifdef CONFIG_MTD_PARTITIONS
38 struct mtd_partition *parts;
39 #endif
40 int list_size; /* number of elements in of_flash_list */
41 struct of_flash_list list[0];
44 #ifdef CONFIG_MTD_PARTITIONS
45 #define OF_FLASH_PARTS(info) ((info)->parts)
47 static int parse_obsolete_partitions(struct platform_device *dev,
48 struct of_flash *info,
49 struct device_node *dp)
51 int i, plen, nr_parts;
52 const struct {
53 u32 offset, len;
54 } *part;
55 const char *names;
57 part = of_get_property(dp, "partitions", &plen);
58 if (!part)
59 return 0; /* No partitions found */
61 dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
63 nr_parts = plen / sizeof(part[0]);
65 info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
66 if (!info->parts)
67 return -ENOMEM;
69 names = of_get_property(dp, "partition-names", &plen);
71 for (i = 0; i < nr_parts; i++) {
72 info->parts[i].offset = part->offset;
73 info->parts[i].size = part->len & ~1;
74 if (part->len & 1) /* bit 0 set signifies read only partition */
75 info->parts[i].mask_flags = MTD_WRITEABLE;
77 if (names && (plen > 0)) {
78 int len = strlen(names) + 1;
80 info->parts[i].name = (char *)names;
81 plen -= len;
82 names += len;
83 } else {
84 info->parts[i].name = "unnamed";
87 part++;
90 return nr_parts;
92 #else /* MTD_PARTITIONS */
93 #define OF_FLASH_PARTS(info) (0)
94 #define parse_partitions(info, dev) (0)
95 #endif /* MTD_PARTITIONS */
97 static int of_flash_remove(struct platform_device *dev)
99 struct of_flash *info;
100 int i;
102 info = dev_get_drvdata(&dev->dev);
103 if (!info)
104 return 0;
105 dev_set_drvdata(&dev->dev, NULL);
107 #ifdef CONFIG_MTD_CONCAT
108 if (info->cmtd != info->list[0].mtd) {
109 del_mtd_device(info->cmtd);
110 mtd_concat_destroy(info->cmtd);
112 #endif
114 if (info->cmtd) {
115 if (OF_FLASH_PARTS(info)) {
116 del_mtd_partitions(info->cmtd);
117 kfree(OF_FLASH_PARTS(info));
118 } else {
119 del_mtd_device(info->cmtd);
123 for (i = 0; i < info->list_size; i++) {
124 if (info->list[i].mtd)
125 map_destroy(info->list[i].mtd);
127 if (info->list[i].map.virt)
128 iounmap(info->list[i].map.virt);
130 if (info->list[i].res) {
131 release_resource(info->list[i].res);
132 kfree(info->list[i].res);
136 kfree(info);
138 return 0;
141 /* Helper function to handle probing of the obsolete "direct-mapped"
142 * compatible binding, which has an extra "probe-type" property
143 * describing the type of flash probe necessary. */
144 static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
145 struct map_info *map)
147 struct device_node *dp = dev->dev.of_node;
148 const char *of_probe;
149 struct mtd_info *mtd;
150 static const char *rom_probe_types[]
151 = { "cfi_probe", "jedec_probe", "map_rom"};
152 int i;
154 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
155 "flash binding\n");
157 of_probe = of_get_property(dp, "probe-type", NULL);
158 if (!of_probe) {
159 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
160 mtd = do_map_probe(rom_probe_types[i], map);
161 if (mtd)
162 return mtd;
164 return NULL;
165 } else if (strcmp(of_probe, "CFI") == 0) {
166 return do_map_probe("cfi_probe", map);
167 } else if (strcmp(of_probe, "JEDEC") == 0) {
168 return do_map_probe("jedec_probe", map);
169 } else {
170 if (strcmp(of_probe, "ROM") != 0)
171 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
172 "type '%s', mapping as rom\n", of_probe);
173 return do_map_probe("mtd_rom", map);
177 #ifdef CONFIG_MTD_PARTITIONS
178 /* When partitions are set we look for a linux,part-probe property which
179 specifies the list of partition probers to use. If none is given then the
180 default is use. These take precedence over other device tree
181 information. */
182 static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL };
183 static const char ** __devinit of_get_probes(struct device_node *dp)
185 const char *cp;
186 int cplen;
187 unsigned int l;
188 unsigned int count;
189 const char **res;
191 cp = of_get_property(dp, "linux,part-probe", &cplen);
192 if (cp == NULL)
193 return part_probe_types_def;
195 count = 0;
196 for (l = 0; l != cplen; l++)
197 if (cp[l] == 0)
198 count++;
200 res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
201 count = 0;
202 while (cplen > 0) {
203 res[count] = cp;
204 l = strlen(cp) + 1;
205 cp += l;
206 cplen -= l;
207 count++;
209 return res;
212 static void __devinit of_free_probes(const char **probes)
214 if (probes != part_probe_types_def)
215 kfree(probes);
217 #endif
219 static int __devinit of_flash_probe(struct platform_device *dev,
220 const struct of_device_id *match)
222 #ifdef CONFIG_MTD_PARTITIONS
223 const char **part_probe_types;
224 #endif
225 struct device_node *dp = dev->dev.of_node;
226 struct resource res;
227 struct of_flash *info;
228 const char *probe_type = match->data;
229 const u32 *width;
230 int err;
231 int i;
232 int count;
233 const u32 *p;
234 int reg_tuple_size;
235 struct mtd_info **mtd_list = NULL;
236 resource_size_t res_size;
238 reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
241 * Get number of "reg" tuples. Scan for MTD devices on area's
242 * described by each "reg" region. This makes it possible (including
243 * the concat support) to support the Intel P30 48F4400 chips which
244 * consists internally of 2 non-identical NOR chips on one die.
246 p = of_get_property(dp, "reg", &count);
247 if (count % reg_tuple_size != 0) {
248 dev_err(&dev->dev, "Malformed reg property on %s\n",
249 dev->dev.of_node->full_name);
250 err = -EINVAL;
251 goto err_flash_remove;
253 count /= reg_tuple_size;
255 err = -ENOMEM;
256 info = kzalloc(sizeof(struct of_flash) +
257 sizeof(struct of_flash_list) * count, GFP_KERNEL);
258 if (!info)
259 goto err_flash_remove;
261 dev_set_drvdata(&dev->dev, info);
263 mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
264 if (!mtd_list)
265 goto err_flash_remove;
267 for (i = 0; i < count; i++) {
268 err = -ENXIO;
269 if (of_address_to_resource(dp, i, &res)) {
270 dev_err(&dev->dev, "Can't get IO address from device"
271 " tree\n");
272 goto err_out;
275 dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
276 (unsigned long long)res.start,
277 (unsigned long long)res.end);
279 err = -EBUSY;
280 res_size = resource_size(&res);
281 info->list[i].res = request_mem_region(res.start, res_size,
282 dev_name(&dev->dev));
283 if (!info->list[i].res)
284 goto err_out;
286 err = -ENXIO;
287 width = of_get_property(dp, "bank-width", NULL);
288 if (!width) {
289 dev_err(&dev->dev, "Can't get bank width from device"
290 " tree\n");
291 goto err_out;
294 info->list[i].map.name = dev_name(&dev->dev);
295 info->list[i].map.phys = res.start;
296 info->list[i].map.size = res_size;
297 info->list[i].map.bankwidth = *width;
299 err = -ENOMEM;
300 info->list[i].map.virt = ioremap(info->list[i].map.phys,
301 info->list[i].map.size);
302 if (!info->list[i].map.virt) {
303 dev_err(&dev->dev, "Failed to ioremap() flash"
304 " region\n");
305 goto err_out;
308 simple_map_init(&info->list[i].map);
310 if (probe_type) {
311 info->list[i].mtd = do_map_probe(probe_type,
312 &info->list[i].map);
313 } else {
314 info->list[i].mtd = obsolete_probe(dev,
315 &info->list[i].map);
317 mtd_list[i] = info->list[i].mtd;
319 err = -ENXIO;
320 if (!info->list[i].mtd) {
321 dev_err(&dev->dev, "do_map_probe() failed\n");
322 goto err_out;
323 } else {
324 info->list_size++;
326 info->list[i].mtd->owner = THIS_MODULE;
327 info->list[i].mtd->dev.parent = &dev->dev;
330 err = 0;
331 if (info->list_size == 1) {
332 info->cmtd = info->list[0].mtd;
333 } else if (info->list_size > 1) {
335 * We detected multiple devices. Concatenate them together.
337 #ifdef CONFIG_MTD_CONCAT
338 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
339 dev_name(&dev->dev));
340 if (info->cmtd == NULL)
341 err = -ENXIO;
342 #else
343 printk(KERN_ERR "physmap_of: multiple devices "
344 "found but MTD concat support disabled.\n");
345 err = -ENXIO;
346 #endif
348 if (err)
349 goto err_out;
351 #ifdef CONFIG_MTD_PARTITIONS
352 part_probe_types = of_get_probes(dp);
353 err = parse_mtd_partitions(info->cmtd, part_probe_types,
354 &info->parts, 0);
355 if (err < 0) {
356 of_free_probes(part_probe_types);
357 goto err_out;
359 of_free_probes(part_probe_types);
361 #ifdef CONFIG_MTD_OF_PARTS
362 if (err == 0) {
363 err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
364 if (err < 0)
365 goto err_out;
367 #endif
369 if (err == 0) {
370 err = parse_obsolete_partitions(dev, info, dp);
371 if (err < 0)
372 goto err_out;
375 if (err > 0)
376 add_mtd_partitions(info->cmtd, info->parts, err);
377 else
378 #endif
379 add_mtd_device(info->cmtd);
381 kfree(mtd_list);
383 return 0;
385 err_out:
386 kfree(mtd_list);
387 err_flash_remove:
388 of_flash_remove(dev);
390 return err;
393 static struct of_device_id of_flash_match[] = {
395 .compatible = "cfi-flash",
396 .data = (void *)"cfi_probe",
399 .compatible = "jedec-flash",
400 .data = (void *)"jedec_probe",
403 .compatible = "mtd-ram",
404 .data = (void *)"map_ram",
407 .type = "rom",
408 .compatible = "direct-mapped"
410 { },
412 MODULE_DEVICE_TABLE(of, of_flash_match);
414 static struct of_platform_driver of_flash_driver = {
415 .driver = {
416 .name = "of-flash",
417 .owner = THIS_MODULE,
418 .of_match_table = of_flash_match,
420 .probe = of_flash_probe,
421 .remove = of_flash_remove,
424 static int __init of_flash_init(void)
426 return of_register_platform_driver(&of_flash_driver);
429 static void __exit of_flash_exit(void)
431 of_unregister_platform_driver(&of_flash_driver);
434 module_init(of_flash_init);
435 module_exit(of_flash_exit);
437 MODULE_LICENSE("GPL");
438 MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
439 MODULE_DESCRIPTION("Device tree based MTD map driver");