Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us