]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/mtd/maps/physmap_of.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux...
[net-next-2.6.git] / drivers / mtd / maps / physmap_of.c
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/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>
28
29 struct of_flash_list {
30         struct mtd_info *mtd;
31         struct map_info map;
32         struct resource *res;
33 };
34
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];
42 };
43
44 #ifdef CONFIG_MTD_PARTITIONS
45 #define OF_FLASH_PARTS(info)    ((info)->parts)
46
47 static int parse_obsolete_partitions(struct platform_device *dev,
48                                      struct of_flash *info,
49                                      struct device_node *dp)
50 {
51         int i, plen, nr_parts;
52         const struct {
53                 __be32 offset, len;
54         } *part;
55         const char *names;
56
57         part = of_get_property(dp, "partitions", &plen);
58         if (!part)
59                 return 0; /* No partitions found */
60
61         dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
62
63         nr_parts = plen / sizeof(part[0]);
64
65         info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
66         if (!info->parts)
67                 return -ENOMEM;
68
69         names = of_get_property(dp, "partition-names", &plen);
70
71         for (i = 0; i < nr_parts; i++) {
72                 info->parts[i].offset = be32_to_cpu(part->offset);
73                 info->parts[i].size   = be32_to_cpu(part->len) & ~1;
74                 if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */
75                         info->parts[i].mask_flags = MTD_WRITEABLE;
76
77                 if (names && (plen > 0)) {
78                         int len = strlen(names) + 1;
79
80                         info->parts[i].name = (char *)names;
81                         plen -= len;
82                         names += len;
83                 } else {
84                         info->parts[i].name = "unnamed";
85                 }
86
87                 part++;
88         }
89
90         return nr_parts;
91 }
92 #else /* MTD_PARTITIONS */
93 #define OF_FLASH_PARTS(info)            (0)
94 #define parse_partitions(info, dev)     (0)
95 #endif /* MTD_PARTITIONS */
96
97 static int of_flash_remove(struct platform_device *dev)
98 {
99         struct of_flash *info;
100         int i;
101
102         info = dev_get_drvdata(&dev->dev);
103         if (!info)
104                 return 0;
105         dev_set_drvdata(&dev->dev, NULL);
106
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);
111         }
112 #endif
113
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);
120                 }
121         }
122
123         for (i = 0; i < info->list_size; i++) {
124                 if (info->list[i].mtd)
125                         map_destroy(info->list[i].mtd);
126
127                 if (info->list[i].map.virt)
128                         iounmap(info->list[i].map.virt);
129
130                 if (info->list[i].res) {
131                         release_resource(info->list[i].res);
132                         kfree(info->list[i].res);
133                 }
134         }
135
136         kfree(info);
137
138         return 0;
139 }
140
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)
146 {
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;
153
154         dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
155                  "flash binding\n");
156
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;
163                 }
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);
174         }
175 }
176
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)
184 {
185         const char *cp;
186         int cplen;
187         unsigned int l;
188         unsigned int count;
189         const char **res;
190
191         cp = of_get_property(dp, "linux,part-probe", &cplen);
192         if (cp == NULL)
193                 return part_probe_types_def;
194
195         count = 0;
196         for (l = 0; l != cplen; l++)
197                 if (cp[l] == 0)
198                         count++;
199
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++;
208         }
209         return res;
210 }
211
212 static void __devinit of_free_probes(const char **probes)
213 {
214         if (probes != part_probe_types_def)
215                 kfree(probes);
216 }
217 #endif
218
219 static int __devinit of_flash_probe(struct platform_device *dev,
220                                     const struct of_device_id *match)
221 {
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 __be32 *width;
230         int err;
231         int i;
232         int count;
233         const __be32 *p;
234         int reg_tuple_size;
235         struct mtd_info **mtd_list = NULL;
236         resource_size_t res_size;
237
238         reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
239
240         /*
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.
245          */
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;
252         }
253         count /= reg_tuple_size;
254
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;
260
261         dev_set_drvdata(&dev->dev, info);
262
263         mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
264         if (!mtd_list)
265                 goto err_flash_remove;
266
267         for (i = 0; i < count; i++) {
268                 err = -ENXIO;
269                 if (of_address_to_resource(dp, i, &res)) {
270                         /*
271                          * Continue with next register tuple if this
272                          * one is not mappable
273                          */
274                         continue;
275                 }
276
277                 dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
278                         (unsigned long long)res.start,
279                         (unsigned long long)res.end);
280
281                 err = -EBUSY;
282                 res_size = resource_size(&res);
283                 info->list[i].res = request_mem_region(res.start, res_size,
284                                                        dev_name(&dev->dev));
285                 if (!info->list[i].res)
286                         goto err_out;
287
288                 err = -ENXIO;
289                 width = of_get_property(dp, "bank-width", NULL);
290                 if (!width) {
291                         dev_err(&dev->dev, "Can't get bank width from device"
292                                 " tree\n");
293                         goto err_out;
294                 }
295
296                 info->list[i].map.name = dev_name(&dev->dev);
297                 info->list[i].map.phys = res.start;
298                 info->list[i].map.size = res_size;
299                 info->list[i].map.bankwidth = be32_to_cpup(width);
300
301                 err = -ENOMEM;
302                 info->list[i].map.virt = ioremap(info->list[i].map.phys,
303                                                  info->list[i].map.size);
304                 if (!info->list[i].map.virt) {
305                         dev_err(&dev->dev, "Failed to ioremap() flash"
306                                 " region\n");
307                         goto err_out;
308                 }
309
310                 simple_map_init(&info->list[i].map);
311
312                 if (probe_type) {
313                         info->list[i].mtd = do_map_probe(probe_type,
314                                                          &info->list[i].map);
315                 } else {
316                         info->list[i].mtd = obsolete_probe(dev,
317                                                            &info->list[i].map);
318                 }
319                 mtd_list[i] = info->list[i].mtd;
320
321                 err = -ENXIO;
322                 if (!info->list[i].mtd) {
323                         dev_err(&dev->dev, "do_map_probe() failed\n");
324                         goto err_out;
325                 } else {
326                         info->list_size++;
327                 }
328                 info->list[i].mtd->owner = THIS_MODULE;
329                 info->list[i].mtd->dev.parent = &dev->dev;
330         }
331
332         err = 0;
333         if (info->list_size == 1) {
334                 info->cmtd = info->list[0].mtd;
335         } else if (info->list_size > 1) {
336                 /*
337                  * We detected multiple devices. Concatenate them together.
338                  */
339 #ifdef CONFIG_MTD_CONCAT
340                 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
341                                                dev_name(&dev->dev));
342                 if (info->cmtd == NULL)
343                         err = -ENXIO;
344 #else
345                 printk(KERN_ERR "physmap_of: multiple devices "
346                        "found but MTD concat support disabled.\n");
347                 err = -ENXIO;
348 #endif
349         }
350         if (err)
351                 goto err_out;
352
353 #ifdef CONFIG_MTD_PARTITIONS
354         part_probe_types = of_get_probes(dp);
355         err = parse_mtd_partitions(info->cmtd, part_probe_types,
356                                    &info->parts, 0);
357         if (err < 0) {
358                 of_free_probes(part_probe_types);
359                 goto err_out;
360         }
361         of_free_probes(part_probe_types);
362
363 #ifdef CONFIG_MTD_OF_PARTS
364         if (err == 0) {
365                 err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
366                 if (err < 0)
367                         goto err_out;
368         }
369 #endif
370
371         if (err == 0) {
372                 err = parse_obsolete_partitions(dev, info, dp);
373                 if (err < 0)
374                         goto err_out;
375         }
376
377         if (err > 0)
378                 add_mtd_partitions(info->cmtd, info->parts, err);
379         else
380 #endif
381                 add_mtd_device(info->cmtd);
382
383         kfree(mtd_list);
384
385         return 0;
386
387 err_out:
388         kfree(mtd_list);
389 err_flash_remove:
390         of_flash_remove(dev);
391
392         return err;
393 }
394
395 static struct of_device_id of_flash_match[] = {
396         {
397                 .compatible     = "cfi-flash",
398                 .data           = (void *)"cfi_probe",
399         },
400         {
401                 /* FIXME: JEDEC chips can't be safely and reliably
402                  * probed, although the mtd code gets it right in
403                  * practice most of the time.  We should use the
404                  * vendor and device ids specified by the binding to
405                  * bypass the heuristic probe code, but the mtd layer
406                  * provides, at present, no interface for doing so
407                  * :(. */
408                 .compatible     = "jedec-flash",
409                 .data           = (void *)"jedec_probe",
410         },
411         {
412                 .compatible     = "mtd-ram",
413                 .data           = (void *)"map_ram",
414         },
415         {
416                 .type           = "rom",
417                 .compatible     = "direct-mapped"
418         },
419         { },
420 };
421 MODULE_DEVICE_TABLE(of, of_flash_match);
422
423 static struct of_platform_driver of_flash_driver = {
424         .driver = {
425                 .name = "of-flash",
426                 .owner = THIS_MODULE,
427                 .of_match_table = of_flash_match,
428         },
429         .probe          = of_flash_probe,
430         .remove         = of_flash_remove,
431 };
432
433 static int __init of_flash_init(void)
434 {
435         return of_register_platform_driver(&of_flash_driver);
436 }
437
438 static void __exit of_flash_exit(void)
439 {
440         of_unregister_platform_driver(&of_flash_driver);
441 }
442
443 module_init(of_flash_init);
444 module_exit(of_flash_exit);
445
446 MODULE_LICENSE("GPL");
447 MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
448 MODULE_DESCRIPTION("Device tree based MTD map driver");