aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/maps/physmap_of.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/maps/physmap_of.c')
-rw-r--r--drivers/mtd/maps/physmap_of.c224
1 files changed, 99 insertions, 125 deletions
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 096dd47b5d5d..cf75a566442e 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -1,5 +1,5 @@
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>
@@ -15,20 +15,15 @@
15 15
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/types.h> 17#include <linux/types.h>
18#include <linux/kernel.h>
19#include <linux/init.h> 18#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/device.h> 19#include <linux/device.h>
22#include <linux/mtd/mtd.h> 20#include <linux/mtd/mtd.h>
23#include <linux/mtd/map.h> 21#include <linux/mtd/map.h>
24#include <linux/mtd/partitions.h> 22#include <linux/mtd/partitions.h>
25#include <linux/mtd/physmap.h> 23#include <linux/of.h>
26#include <asm/io.h> 24#include <linux/of_platform.h>
27#include <asm/prom.h>
28#include <asm/of_device.h>
29#include <asm/of_platform.h>
30 25
31struct physmap_flash_info { 26struct of_flash {
32 struct mtd_info *mtd; 27 struct mtd_info *mtd;
33 struct map_info map; 28 struct map_info map;
34 struct resource *res; 29 struct resource *res;
@@ -38,8 +33,10 @@ struct physmap_flash_info {
38}; 33};
39 34
40#ifdef CONFIG_MTD_PARTITIONS 35#ifdef CONFIG_MTD_PARTITIONS
36#define OF_FLASH_PARTS(info) ((info)->parts)
37
41static int parse_obsolete_partitions(struct of_device *dev, 38static int parse_obsolete_partitions(struct of_device *dev,
42 struct physmap_flash_info *info, 39 struct of_flash *info,
43 struct device_node *dp) 40 struct device_node *dp)
44{ 41{
45 int i, plen, nr_parts; 42 int i, plen, nr_parts;
@@ -50,17 +47,15 @@ static int parse_obsolete_partitions(struct of_device *dev,
50 47
51 part = of_get_property(dp, "partitions", &plen); 48 part = of_get_property(dp, "partitions", &plen);
52 if (!part) 49 if (!part)
53 return -ENOENT; 50 return 0; /* No partitions found */
54 51
55 dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); 52 dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
56 53
57 nr_parts = plen / sizeof(part[0]); 54 nr_parts = plen / sizeof(part[0]);
58 55
59 info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL); 56 info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
60 if (!info->parts) { 57 if (!info->parts)
61 printk(KERN_ERR "Can't allocate the flash partition data!\n");
62 return -ENOMEM; 58 return -ENOMEM;
63 }
64 59
65 names = of_get_property(dp, "partition-names", &plen); 60 names = of_get_property(dp, "partition-names", &plen);
66 61
@@ -86,8 +81,8 @@ static int parse_obsolete_partitions(struct of_device *dev,
86 return nr_parts; 81 return nr_parts;
87} 82}
88 83
89static int __devinit process_partitions(struct physmap_flash_info *info, 84static int __devinit parse_partitions(struct of_flash *info,
90 struct of_device *dev) 85 struct of_device *dev)
91{ 86{
92 const char *partname; 87 const char *partname;
93 static const char *part_probe_types[] 88 static const char *part_probe_types[]
@@ -109,89 +104,68 @@ static int __devinit process_partitions(struct physmap_flash_info *info,
109 for (pp = dp->child; pp; pp = pp->sibling) 104 for (pp = dp->child; pp; pp = pp->sibling)
110 nr_parts++; 105 nr_parts++;
111 106
112 if (nr_parts) { 107 if (nr_parts == 0)
113 info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), 108 return parse_obsolete_partitions(dev, info, dp);
114 GFP_KERNEL); 109
115 if (!info->parts) { 110 info->parts = kzalloc(nr_parts * sizeof(*info->parts),
116 printk(KERN_ERR "Can't allocate the flash partition data!\n"); 111 GFP_KERNEL);
117 return -ENOMEM; 112 if (!info->parts)
118 } 113 return -ENOMEM;
119 114
120 for (pp = dp->child, i = 0 ; pp; pp = pp->sibling, i++) { 115 for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
121 const u32 *reg; 116 const u32 *reg;
122 int len; 117 int len;
123 118
124 reg = of_get_property(pp, "reg", &len); 119 reg = of_get_property(pp, "reg", &len);
125 if (!reg || (len != 2*sizeof(u32))) { 120 if (!reg || (len != 2*sizeof(u32))) {
126 dev_err(&dev->dev, "Invalid 'reg' on %s\n", 121 dev_err(&dev->dev, "Invalid 'reg' on %s\n",
127 dp->full_name); 122 dp->full_name);
128 kfree(info->parts); 123 kfree(info->parts);
129 info->parts = NULL; 124 info->parts = NULL;
130 return -EINVAL; 125 return -EINVAL;
131 }
132 info->parts[i].offset = reg[0];
133 info->parts[i].size = reg[1];
134
135 partname = of_get_property(pp, "label", &len);
136 if (!partname)
137 partname = of_get_property(pp, "name", &len);
138 info->parts[i].name = (char *)partname;
139
140 if (of_get_property(pp, "read-only", &len))
141 info->parts[i].mask_flags = MTD_WRITEABLE;
142 } 126 }
143 } else { 127 info->parts[i].offset = reg[0];
144 nr_parts = parse_obsolete_partitions(dev, info, dp); 128 info->parts[i].size = reg[1];
145 if (nr_parts == -ENOENT)
146 nr_parts = 0;
147 }
148 129
149 if (nr_parts < 0) 130 partname = of_get_property(pp, "label", &len);
150 return nr_parts; 131 if (!partname)
132 partname = of_get_property(pp, "name", &len);
133 info->parts[i].name = (char *)partname;
151 134
152 if (nr_parts > 0) 135 if (of_get_property(pp, "read-only", &len))
153 add_mtd_partitions(info->mtd, info->parts, nr_parts); 136 info->parts[i].mask_flags = MTD_WRITEABLE;
154 else 137 }
155 add_mtd_device(info->mtd);
156 138
157 return 0; 139 return nr_parts;
158} 140}
159#else /* MTD_PARTITIONS */ 141#else /* MTD_PARTITIONS */
160static int __devinit process_partitions(struct physmap_flash_info *info, 142#define OF_FLASH_PARTS(info) (0)
161 struct device_node *dev) 143#define parse_partitions(info, dev) (0)
162{
163 add_mtd_device(info->mtd);
164 return 0;
165}
166#endif /* MTD_PARTITIONS */ 144#endif /* MTD_PARTITIONS */
167 145
168static int of_physmap_remove(struct of_device *dev) 146static int of_flash_remove(struct of_device *dev)
169{ 147{
170 struct physmap_flash_info *info; 148 struct of_flash *info;
171 149
172 info = dev_get_drvdata(&dev->dev); 150 info = dev_get_drvdata(&dev->dev);
173 if (info == NULL) 151 if (!info)
174 return 0; 152 return 0;
175 dev_set_drvdata(&dev->dev, NULL); 153 dev_set_drvdata(&dev->dev, NULL);
176 154
177 if (info->mtd != NULL) { 155 if (info->mtd) {
178#ifdef CONFIG_MTD_PARTITIONS 156 if (OF_FLASH_PARTS(info)) {
179 if (info->parts) {
180 del_mtd_partitions(info->mtd); 157 del_mtd_partitions(info->mtd);
181 kfree(info->parts); 158 kfree(OF_FLASH_PARTS(info));
182 } else { 159 } else {
183 del_mtd_device(info->mtd); 160 del_mtd_device(info->mtd);
184 } 161 }
185#else
186 del_mtd_device(info->mtd);
187#endif
188 map_destroy(info->mtd); 162 map_destroy(info->mtd);
189 } 163 }
190 164
191 if (info->map.virt != NULL) 165 if (info->map.virt)
192 iounmap(info->map.virt); 166 iounmap(info->map.virt);
193 167
194 if (info->res != NULL) { 168 if (info->res) {
195 release_resource(info->res); 169 release_resource(info->res);
196 kfree(info->res); 170 kfree(info->res);
197 } 171 }
@@ -229,52 +203,49 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
229 return do_map_probe("jedec_probe", map); 203 return do_map_probe("jedec_probe", map);
230 } else { 204 } else {
231 if (strcmp(of_probe, "ROM") != 0) 205 if (strcmp(of_probe, "ROM") != 0)
232 dev_dbg(&dev->dev, "obsolete_probe: don't know probe type " 206 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
233 "'%s', mapping as rom\n", of_probe); 207 "type '%s', mapping as rom\n", of_probe);
234 return do_map_probe("mtd_rom", map); 208 return do_map_probe("mtd_rom", map);
235 } 209 }
236} 210}
237 211
238static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) 212static int __devinit of_flash_probe(struct of_device *dev,
213 const struct of_device_id *match)
239{ 214{
240 struct device_node *dp = dev->node; 215 struct device_node *dp = dev->node;
241 struct resource res; 216 struct resource res;
242 struct physmap_flash_info *info; 217 struct of_flash *info;
243 const char *probe_type = (const char *)match->data; 218 const char *probe_type = match->data;
244 const u32 *width; 219 const u32 *width;
245 int err; 220 int err;
246 221
222 err = -ENXIO;
247 if (of_address_to_resource(dp, 0, &res)) { 223 if (of_address_to_resource(dp, 0, &res)) {
248 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");
249 err = -EINVAL;
250 goto err_out; 225 goto err_out;
251 } 226 }
252 227
253 dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n", 228 dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
254 (unsigned long long)res.end - res.start + 1, 229 (unsigned long long)res.start, (unsigned long long)res.end);
255 (unsigned long long)res.start);
256 230
257 info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); 231 err = -ENOMEM;
258 if (info == NULL) { 232 info = kzalloc(sizeof(*info), GFP_KERNEL);
259 err = -ENOMEM; 233 if (!info)
260 goto err_out; 234 goto err_out;
261 }
262 memset(info, 0, sizeof(*info)); 235 memset(info, 0, sizeof(*info));
263 236
264 dev_set_drvdata(&dev->dev, info); 237 dev_set_drvdata(&dev->dev, info);
265 238
239 err = -EBUSY;
266 info->res = request_mem_region(res.start, res.end - res.start + 1, 240 info->res = request_mem_region(res.start, res.end - res.start + 1,
267 dev->dev.bus_id); 241 dev->dev.bus_id);
268 if (info->res == NULL) { 242 if (!info->res)
269 dev_err(&dev->dev, "Could not reserve memory region\n");
270 err = -ENOMEM;
271 goto err_out; 243 goto err_out;
272 }
273 244
245 err = -ENXIO;
274 width = of_get_property(dp, "bank-width", NULL); 246 width = of_get_property(dp, "bank-width", NULL);
275 if (width == NULL) { 247 if (!width) {
276 dev_err(&dev->dev, "Can't get the flash bank width!\n"); 248 dev_err(&dev->dev, "Can't get bank width from device tree\n");
277 err = -EINVAL;
278 goto err_out; 249 goto err_out;
279 } 250 }
280 251
@@ -283,10 +254,10 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
283 info->map.size = res.end - res.start + 1; 254 info->map.size = res.end - res.start + 1;
284 info->map.bankwidth = *width; 255 info->map.bankwidth = *width;
285 256
257 err = -ENOMEM;
286 info->map.virt = ioremap(info->map.phys, info->map.size); 258 info->map.virt = ioremap(info->map.phys, info->map.size);
287 if (info->map.virt == NULL) { 259 if (!info->map.virt) {
288 dev_err(&dev->dev, "Failed to ioremap flash region\n"); 260 dev_err(&dev->dev, "Failed to ioremap() flash region\n");
289 err = EIO;
290 goto err_out; 261 goto err_out;
291 } 262 }
292 263
@@ -297,25 +268,30 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
297 else 268 else
298 info->mtd = obsolete_probe(dev, &info->map); 269 info->mtd = obsolete_probe(dev, &info->map);
299 270
300 if (info->mtd == NULL) { 271 err = -ENXIO;
301 dev_err(&dev->dev, "map_probe failed\n"); 272 if (!info->mtd) {
302 err = -ENXIO; 273 dev_err(&dev->dev, "do_map_probe() failed\n");
303 goto err_out; 274 goto err_out;
304 } 275 }
305 info->mtd->owner = THIS_MODULE; 276 info->mtd->owner = THIS_MODULE;
306 277
307 return process_partitions(info, dev); 278 err = parse_partitions(info, dev);
279 if (err < 0)
280 goto err_out;
308 281
309err_out: 282 if (err > 0)
310 of_physmap_remove(dev); 283 add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
311 return err; 284 else
285 add_mtd_device(info->mtd);
312 286
313 return 0; 287 return 0;
314 288
315 289err_out:
290 of_flash_remove(dev);
291 return err;
316} 292}
317 293
318static struct of_device_id of_physmap_match[] = { 294static struct of_device_id of_flash_match[] = {
319 { 295 {
320 .compatible = "cfi-flash", 296 .compatible = "cfi-flash",
321 .data = (void *)"cfi_probe", 297 .data = (void *)"cfi_probe",
@@ -337,30 +313,28 @@ static struct of_device_id of_physmap_match[] = {
337 }, 313 },
338 { }, 314 { },
339}; 315};
316MODULE_DEVICE_TABLE(of, of_flash_match);
340 317
341MODULE_DEVICE_TABLE(of, of_physmap_match); 318static struct of_platform_driver of_flash_driver = {
342 319 .name = "of-flash",
343 320 .match_table = of_flash_match,
344static struct of_platform_driver of_physmap_flash_driver = { 321 .probe = of_flash_probe,
345 .name = "physmap-flash", 322 .remove = of_flash_remove,
346 .match_table = of_physmap_match,
347 .probe = of_physmap_probe,
348 .remove = of_physmap_remove,
349}; 323};
350 324
351static int __init of_physmap_init(void) 325static int __init of_flash_init(void)
352{ 326{
353 return of_register_platform_driver(&of_physmap_flash_driver); 327 return of_register_platform_driver(&of_flash_driver);
354} 328}
355 329
356static void __exit of_physmap_exit(void) 330static void __exit of_flash_exit(void)
357{ 331{
358 of_unregister_platform_driver(&of_physmap_flash_driver); 332 of_unregister_platform_driver(&of_flash_driver);
359} 333}
360 334
361module_init(of_physmap_init); 335module_init(of_flash_init);
362module_exit(of_physmap_exit); 336module_exit(of_flash_exit);
363 337
364MODULE_LICENSE("GPL"); 338MODULE_LICENSE("GPL");
365MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>"); 339MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
366MODULE_DESCRIPTION("Configurable MTD map driver for OF"); 340MODULE_DESCRIPTION("Device tree based MTD map driver");