aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-10-13 09:58:23 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-10-13 09:58:23 -0400
commitebf8889bd1fe3615991ff4494635d237280652a2 (patch)
tree10fb735717122bbb86474339eac07f26e7ccdf40 /drivers/mtd
parentb160292cc216a50fd0cd386b0bda2cd48352c73b (diff)
parent752097cec53eea111d087c545179b421e2bde98a (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/maps/Kconfig2
-rw-r--r--drivers/mtd/maps/physmap_of.c345
2 files changed, 218 insertions, 129 deletions
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index c2624b2655ac..2a2a125b0c76 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -354,7 +354,7 @@ config MTD_WALNUT
354 354
355config MTD_EBONY 355config MTD_EBONY
356 tristate "Flash devices mapped on IBM 440GP Ebony" 356 tristate "Flash devices mapped on IBM 440GP Ebony"
357 depends on MTD_JEDECPROBE && EBONY 357 depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE
358 help 358 help
359 This enables access routines for the flash chips on the IBM 440GP 359 This enables access routines for the flash chips on the IBM 440GP
360 Ebony board. If you have one of these boards and would like to 360 Ebony board. If you have one of these boards and would like to
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index fbd613968717..aeed9ea79714 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -1,9 +1,12 @@
1/* 1/*
2 * Normal mappings of chips in physical memory for OF devices 2 * Flash mappings described by the OF (or flattened) device tree
3 * 3 *
4 * Copyright (C) 2006 MontaVista Software Inc. 4 * Copyright (C) 2006 MontaVista Software Inc.
5 * Author: Vitaly Wool <vwool@ru.mvista.com> 5 * Author: Vitaly Wool <vwool@ru.mvista.com>
6 * 6 *
7 * Revised to handle newer style flash binding by:
8 * Copyright (C) 2007 David Gibson, IBM Corporation.
9 *
7 * This program is free software; you can redistribute it and/or modify it 10 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the 11 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your 12 * Free Software Foundation; either version 2 of the License, or (at your
@@ -12,102 +15,157 @@
12 15
13#include <linux/module.h> 16#include <linux/module.h>
14#include <linux/types.h> 17#include <linux/types.h>
15#include <linux/kernel.h>
16#include <linux/init.h> 18#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/device.h> 19#include <linux/device.h>
19#include <linux/mtd/mtd.h> 20#include <linux/mtd/mtd.h>
20#include <linux/mtd/map.h> 21#include <linux/mtd/map.h>
21#include <linux/mtd/partitions.h> 22#include <linux/mtd/partitions.h>
22#include <linux/mtd/physmap.h> 23#include <linux/of.h>
23#include <asm/io.h> 24#include <linux/of_platform.h>
24#include <asm/prom.h>
25#include <asm/of_device.h>
26#include <asm/of_platform.h>
27 25
28struct physmap_flash_info { 26struct of_flash {
29 struct mtd_info *mtd; 27 struct mtd_info *mtd;
30 struct map_info map; 28 struct map_info map;
31 struct resource *res; 29 struct resource *res;
32#ifdef CONFIG_MTD_PARTITIONS 30#ifdef CONFIG_MTD_PARTITIONS
33 int nr_parts;
34 struct mtd_partition *parts; 31 struct mtd_partition *parts;
35#endif 32#endif
36}; 33};
37 34
38static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
39#ifdef CONFIG_MTD_PARTITIONS 35#ifdef CONFIG_MTD_PARTITIONS
40static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; 36#define OF_FLASH_PARTS(info) ((info)->parts)
41#endif
42 37
43#ifdef CONFIG_MTD_PARTITIONS 38static int parse_obsolete_partitions(struct of_device *dev,
44static int parse_flash_partitions(struct device_node *node, 39 struct of_flash *info,
45 struct mtd_partition **parts) 40 struct device_node *dp)
46{ 41{
47 int i, plen, retval = -ENOMEM; 42 int i, plen, nr_parts;
48 const u32 *part; 43 const struct {
49 const char *name; 44 u32 offset, len;
50 45 } *part;
51 part = of_get_property(node, "partitions", &plen); 46 const char *names;
52 if (part == NULL) 47
53 goto err; 48 part = of_get_property(dp, "partitions", &plen);
54 49 if (!part)
55 retval = plen / (2 * sizeof(u32)); 50 return 0; /* No partitions found */
56 *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL); 51
57 if (*parts == NULL) { 52 dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
58 printk(KERN_ERR "Can't allocate the flash partition data!\n"); 53
59 goto err; 54 nr_parts = plen / sizeof(part[0]);
60 } 55
56 info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
57 if (!info->parts)
58 return -ENOMEM;
61 59
62 name = of_get_property(node, "partition-names", &plen); 60 names = of_get_property(dp, "partition-names", &plen);
63 61
64 for (i = 0; i < retval; i++) { 62 for (i = 0; i < nr_parts; i++) {
65 (*parts)[i].offset = *part++; 63 info->parts[i].offset = part->offset;
66 (*parts)[i].size = *part & ~1; 64 info->parts[i].size = part->len & ~1;
67 if (*part++ & 1) /* bit 0 set signifies read only partition */ 65 if (part->len & 1) /* bit 0 set signifies read only partition */
68 (*parts)[i].mask_flags = MTD_WRITEABLE; 66 info->parts[i].mask_flags = MTD_WRITEABLE;
69 67
70 if (name != NULL && plen > 0) { 68 if (names && (plen > 0)) {
71 int len = strlen(name) + 1; 69 int len = strlen(names) + 1;
72 70
73 (*parts)[i].name = (char *)name; 71 info->parts[i].name = (char *)names;
74 plen -= len; 72 plen -= len;
75 name += len; 73 names += len;
76 } else 74 } else {
77 (*parts)[i].name = "unnamed"; 75 info->parts[i].name = "unnamed";
76 }
77
78 part++;
78 } 79 }
79err: 80
80 return retval; 81 return nr_parts;
81} 82}
82#endif
83 83
84static int of_physmap_remove(struct of_device *dev) 84static int __devinit parse_partitions(struct of_flash *info,
85 struct of_device *dev)
86{
87 const char *partname;
88 static const char *part_probe_types[]
89 = { "cmdlinepart", "RedBoot", NULL };
90 struct device_node *dp = dev->node, *pp;
91 int nr_parts, i;
92
93 /* First look for RedBoot table or partitions on the command
94 * line, these take precedence over device tree information */
95 nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
96 &info->parts, 0);
97 if (nr_parts > 0) {
98 add_mtd_partitions(info->mtd, info->parts, nr_parts);
99 return 0;
100 }
101
102 /* First count the subnodes */
103 nr_parts = 0;
104 for (pp = dp->child; pp; pp = pp->sibling)
105 nr_parts++;
106
107 if (nr_parts == 0)
108 return parse_obsolete_partitions(dev, info, dp);
109
110 info->parts = kzalloc(nr_parts * sizeof(*info->parts),
111 GFP_KERNEL);
112 if (!info->parts)
113 return -ENOMEM;
114
115 for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
116 const u32 *reg;
117 int len;
118
119 reg = of_get_property(pp, "reg", &len);
120 if (!reg || (len != 2*sizeof(u32))) {
121 dev_err(&dev->dev, "Invalid 'reg' on %s\n",
122 dp->full_name);
123 kfree(info->parts);
124 info->parts = NULL;
125 return -EINVAL;
126 }
127 info->parts[i].offset = reg[0];
128 info->parts[i].size = reg[1];
129
130 partname = of_get_property(pp, "label", &len);
131 if (!partname)
132 partname = of_get_property(pp, "name", &len);
133 info->parts[i].name = (char *)partname;
134
135 if (of_get_property(pp, "read-only", &len))
136 info->parts[i].mask_flags = MTD_WRITEABLE;
137 }
138
139 return nr_parts;
140}
141#else /* MTD_PARTITIONS */
142#define OF_FLASH_PARTS(info) (0)
143#define parse_partitions(info, dev) (0)
144#endif /* MTD_PARTITIONS */
145
146static int of_flash_remove(struct of_device *dev)
85{ 147{
86 struct physmap_flash_info *info; 148 struct of_flash *info;
87 149
88 info = dev_get_drvdata(&dev->dev); 150 info = dev_get_drvdata(&dev->dev);
89 if (info == NULL) 151 if (!info)
90 return 0; 152 return 0;
91 dev_set_drvdata(&dev->dev, NULL); 153 dev_set_drvdata(&dev->dev, NULL);
92 154
93 if (info->mtd != NULL) { 155 if (info->mtd) {
94#ifdef CONFIG_MTD_PARTITIONS 156 if (OF_FLASH_PARTS(info)) {
95 if (info->nr_parts) {
96 del_mtd_partitions(info->mtd); 157 del_mtd_partitions(info->mtd);
97 kfree(info->parts); 158 kfree(OF_FLASH_PARTS(info));
98 } else { 159 } else {
99 del_mtd_device(info->mtd); 160 del_mtd_device(info->mtd);
100 } 161 }
101#else
102 del_mtd_device(info->mtd);
103#endif
104 map_destroy(info->mtd); 162 map_destroy(info->mtd);
105 } 163 }
106 164
107 if (info->map.virt != NULL) 165 if (info->map.virt)
108 iounmap(info->map.virt); 166 iounmap(info->map.virt);
109 167
110 if (info->res != NULL) { 168 if (info->res) {
111 release_resource(info->res); 169 release_resource(info->res);
112 kfree(info->res); 170 kfree(info->res);
113 } 171 }
@@ -115,47 +173,78 @@ static int of_physmap_remove(struct of_device *dev)
115 return 0; 173 return 0;
116} 174}
117 175
118static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) 176/* Helper function to handle probing of the obsolete "direct-mapped"
177 * compatible binding, which has an extra "probe-type" property
178 * describing the type of flash probe necessary. */
179static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
180 struct map_info *map)
119{ 181{
120 struct device_node *dp = dev->node; 182 struct device_node *dp = dev->node;
121 struct resource res;
122 struct physmap_flash_info *info;
123 const char **probe_type;
124 const char *of_probe; 183 const char *of_probe;
184 struct mtd_info *mtd;
185 static const char *rom_probe_types[]
186 = { "cfi_probe", "jedec_probe", "map_rom"};
187 int i;
188
189 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
190 "flash binding\n");
191
192 of_probe = of_get_property(dp, "probe-type", NULL);
193 if (!of_probe) {
194 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
195 mtd = do_map_probe(rom_probe_types[i], map);
196 if (mtd)
197 return mtd;
198 }
199 return NULL;
200 } else if (strcmp(of_probe, "CFI") == 0) {
201 return do_map_probe("cfi_probe", map);
202 } else if (strcmp(of_probe, "JEDEC") == 0) {
203 return do_map_probe("jedec_probe", map);
204 } else {
205 if (strcmp(of_probe, "ROM") != 0)
206 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
207 "type '%s', mapping as rom\n", of_probe);
208 return do_map_probe("mtd_rom", map);
209 }
210}
211
212static int __devinit of_flash_probe(struct of_device *dev,
213 const struct of_device_id *match)
214{
215 struct device_node *dp = dev->node;
216 struct resource res;
217 struct of_flash *info;
218 const char *probe_type = match->data;
125 const u32 *width; 219 const u32 *width;
126 int err; 220 int err;
127 221
128 222 err = -ENXIO;
129 if (of_address_to_resource(dp, 0, &res)) { 223 if (of_address_to_resource(dp, 0, &res)) {
130 dev_err(&dev->dev, "Can't get the flash mapping!\n"); 224 dev_err(&dev->dev, "Can't get IO address from device tree\n");
131 err = -EINVAL;
132 goto err_out; 225 goto err_out;
133 } 226 }
134 227
135 dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n", 228 dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
136 (unsigned long long)res.end - res.start + 1, 229 (unsigned long long)res.start, (unsigned long long)res.end);
137 (unsigned long long)res.start);
138 230
139 info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); 231 err = -ENOMEM;
140 if (info == NULL) { 232 info = kzalloc(sizeof(*info), GFP_KERNEL);
141 err = -ENOMEM; 233 if (!info)
142 goto err_out; 234 goto err_out;
143 }
144 235
145 dev_set_drvdata(&dev->dev, info); 236 dev_set_drvdata(&dev->dev, info);
146 237
238 err = -EBUSY;
147 info->res = request_mem_region(res.start, res.end - res.start + 1, 239 info->res = request_mem_region(res.start, res.end - res.start + 1,
148 dev->dev.bus_id); 240 dev->dev.bus_id);
149 if (info->res == NULL) { 241 if (!info->res)
150 dev_err(&dev->dev, "Could not reserve memory region\n");
151 err = -ENOMEM;
152 goto err_out; 242 goto err_out;
153 }
154 243
244 err = -ENXIO;
155 width = of_get_property(dp, "bank-width", NULL); 245 width = of_get_property(dp, "bank-width", NULL);
156 if (width == NULL) { 246 if (!width) {
157 dev_err(&dev->dev, "Can't get the flash bank width!\n"); 247 dev_err(&dev->dev, "Can't get bank width from device tree\n");
158 err = -EINVAL;
159 goto err_out; 248 goto err_out;
160 } 249 }
161 250
@@ -164,87 +253,87 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
164 info->map.size = res.end - res.start + 1; 253 info->map.size = res.end - res.start + 1;
165 info->map.bankwidth = *width; 254 info->map.bankwidth = *width;
166 255
256 err = -ENOMEM;
167 info->map.virt = ioremap(info->map.phys, info->map.size); 257 info->map.virt = ioremap(info->map.phys, info->map.size);
168 if (info->map.virt == NULL) { 258 if (!info->map.virt) {
169 dev_err(&dev->dev, "Failed to ioremap flash region\n"); 259 dev_err(&dev->dev, "Failed to ioremap() flash region\n");
170 err = EIO;
171 goto err_out; 260 goto err_out;
172 } 261 }
173 262
174 simple_map_init(&info->map); 263 simple_map_init(&info->map);
175 264
176 of_probe = of_get_property(dp, "probe-type", NULL); 265 if (probe_type)
177 if (of_probe == NULL) { 266 info->mtd = do_map_probe(probe_type, &info->map);
178 probe_type = rom_probe_types; 267 else
179 for (; info->mtd == NULL && *probe_type != NULL; probe_type++) 268 info->mtd = obsolete_probe(dev, &info->map);
180 info->mtd = do_map_probe(*probe_type, &info->map); 269
181 } else if (!strcmp(of_probe, "CFI")) 270 err = -ENXIO;
182 info->mtd = do_map_probe("cfi_probe", &info->map); 271 if (!info->mtd) {
183 else if (!strcmp(of_probe, "JEDEC")) 272 dev_err(&dev->dev, "do_map_probe() failed\n");
184 info->mtd = do_map_probe("jedec_probe", &info->map);
185 else {
186 if (strcmp(of_probe, "ROM"))
187 dev_dbg(&dev->dev, "map_probe: don't know probe type "
188 "'%s', mapping as rom\n", of_probe);
189 info->mtd = do_map_probe("mtd_rom", &info->map);
190 }
191 if (info->mtd == NULL) {
192 dev_err(&dev->dev, "map_probe failed\n");
193 err = -ENXIO;
194 goto err_out; 273 goto err_out;
195 } 274 }
196 info->mtd->owner = THIS_MODULE; 275 info->mtd->owner = THIS_MODULE;
197 276
198#ifdef CONFIG_MTD_PARTITIONS 277 err = parse_partitions(info, dev);
199 err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); 278 if (err < 0)
200 if (err > 0) { 279 goto err_out;
201 add_mtd_partitions(info->mtd, info->parts, err); 280
202 } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) { 281 if (err > 0)
203 dev_info(&dev->dev, "Using OF partition information\n"); 282 add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
204 add_mtd_partitions(info->mtd, info->parts, err); 283 else
205 info->nr_parts = err; 284 add_mtd_device(info->mtd);
206 } else
207#endif
208 285
209 add_mtd_device(info->mtd);
210 return 0; 286 return 0;
211 287
212err_out: 288err_out:
213 of_physmap_remove(dev); 289 of_flash_remove(dev);
214 return err; 290 return err;
215} 291}
216 292
217static struct of_device_id of_physmap_match[] = { 293static struct of_device_id of_flash_match[] = {
294 {
295 .compatible = "cfi-flash",
296 .data = (void *)"cfi_probe",
297 },
298 {
299 /* FIXME: JEDEC chips can't be safely and reliably
300 * probed, although the mtd code gets it right in
301 * practice most of the time. We should use the
302 * vendor and device ids specified by the binding to
303 * bypass the heuristic probe code, but the mtd layer
304 * provides, at present, no interface for doing so
305 * :(. */
306 .compatible = "jedec-flash",
307 .data = (void *)"jedec_probe",
308 },
218 { 309 {
219 .type = "rom", 310 .type = "rom",
220 .compatible = "direct-mapped" 311 .compatible = "direct-mapped"
221 }, 312 },
222 { }, 313 { },
223}; 314};
315MODULE_DEVICE_TABLE(of, of_flash_match);
224 316
225MODULE_DEVICE_TABLE(of, of_physmap_match); 317static struct of_platform_driver of_flash_driver = {
226 318 .name = "of-flash",
227 319 .match_table = of_flash_match,
228static struct of_platform_driver of_physmap_flash_driver = { 320 .probe = of_flash_probe,
229 .name = "physmap-flash", 321 .remove = of_flash_remove,
230 .match_table = of_physmap_match,
231 .probe = of_physmap_probe,
232 .remove = of_physmap_remove,
233}; 322};
234 323
235static int __init of_physmap_init(void) 324static int __init of_flash_init(void)
236{ 325{
237 return of_register_platform_driver(&of_physmap_flash_driver); 326 return of_register_platform_driver(&of_flash_driver);
238} 327}
239 328
240static void __exit of_physmap_exit(void) 329static void __exit of_flash_exit(void)
241{ 330{
242 of_unregister_platform_driver(&of_physmap_flash_driver); 331 of_unregister_platform_driver(&of_flash_driver);
243} 332}
244 333
245module_init(of_physmap_init); 334module_init(of_flash_init);
246module_exit(of_physmap_exit); 335module_exit(of_flash_exit);
247 336
248MODULE_LICENSE("GPL"); 337MODULE_LICENSE("GPL");
249MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>"); 338MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
250MODULE_DESCRIPTION("Configurable MTD map driver for OF"); 339MODULE_DESCRIPTION("Device tree based MTD map driver");