aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/maps/physmap_of.c
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/maps/physmap_of.c
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/maps/physmap_of.c')
-rw-r--r--drivers/mtd/maps/physmap_of.c345
1 files changed, 217 insertions, 128 deletions
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");