[ARM] Support register switch in nommu mode
[linux-2.6/verdex.git] / drivers / mtd / maps / sa1100-flash.c
blob5cefb015633ce896e2a08dc75269c93169496573
1 /*
2 * Flash memory access on SA11x0 based devices
4 * (C) 2000 Nicolas Pitre <nico@cam.org>
6 * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $
7 */
8 #include <linux/config.h>
9 #include <linux/module.h>
10 #include <linux/types.h>
11 #include <linux/ioport.h>
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/errno.h>
15 #include <linux/slab.h>
16 #include <linux/platform_device.h>
17 #include <linux/err.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>
24 #include <asm/hardware.h>
25 #include <asm/io.h>
26 #include <asm/sizes.h>
27 #include <asm/mach/flash.h>
29 #if 0
31 * This is here for documentation purposes only - until these people
32 * submit their machine types. It will be gone January 2005.
34 static struct mtd_partition consus_partitions[] = {
36 .name = "Consus boot firmware",
37 .offset = 0,
38 .size = 0x00040000,
39 .mask_flags = MTD_WRITABLE, /* force read-only */
40 }, {
41 .name = "Consus kernel",
42 .offset = 0x00040000,
43 .size = 0x00100000,
44 .mask_flags = 0,
45 }, {
46 .name = "Consus disk",
47 .offset = 0x00140000,
48 /* The rest (up to 16M) for jffs. We could put 0 and
49 make it find the size automatically, but right now
50 i have 32 megs. jffs will use all 32 megs if given
51 the chance, and this leads to horrible problems
52 when you try to re-flash the image because blob
53 won't erase the whole partition. */
54 .size = 0x01000000 - 0x00140000,
55 .mask_flags = 0,
56 }, {
57 /* this disk is a secondary disk, which can be used as
58 needed, for simplicity, make it the size of the other
59 consus partition, although realistically it could be
60 the remainder of the disk (depending on the file
61 system used) */
62 .name = "Consus disk2",
63 .offset = 0x01000000,
64 .size = 0x01000000 - 0x00140000,
65 .mask_flags = 0,
69 /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
70 static struct mtd_partition frodo_partitions[] =
73 .name = "bootloader",
74 .size = 0x00040000,
75 .offset = 0x00000000,
76 .mask_flags = MTD_WRITEABLE
77 }, {
78 .name = "bootloader params",
79 .size = 0x00040000,
80 .offset = MTDPART_OFS_APPEND,
81 .mask_flags = MTD_WRITEABLE
82 }, {
83 .name = "kernel",
84 .size = 0x00100000,
85 .offset = MTDPART_OFS_APPEND,
86 .mask_flags = MTD_WRITEABLE
87 }, {
88 .name = "ramdisk",
89 .size = 0x00400000,
90 .offset = MTDPART_OFS_APPEND,
91 .mask_flags = MTD_WRITEABLE
92 }, {
93 .name = "file system",
94 .size = MTDPART_SIZ_FULL,
95 .offset = MTDPART_OFS_APPEND
99 static struct mtd_partition jornada56x_partitions[] = {
101 .name = "bootldr",
102 .size = 0x00040000,
103 .offset = 0,
104 .mask_flags = MTD_WRITEABLE,
105 }, {
106 .name = "rootfs",
107 .size = MTDPART_SIZ_FULL,
108 .offset = MTDPART_OFS_APPEND,
112 static void jornada56x_set_vpp(int vpp)
114 if (vpp)
115 GPSR = GPIO_GPIO26;
116 else
117 GPCR = GPIO_GPIO26;
118 GPDR |= GPIO_GPIO26;
122 * Machine Phys Size set_vpp
123 * Consus : SA1100_CS0_PHYS SZ_32M
124 * Frodo : SA1100_CS0_PHYS SZ_32M
125 * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
127 #endif
129 struct sa_subdev_info {
130 char name[16];
131 struct map_info map;
132 struct mtd_info *mtd;
133 struct flash_platform_data *plat;
136 struct sa_info {
137 struct mtd_partition *parts;
138 struct mtd_info *mtd;
139 int num_subdev;
140 unsigned int nr_parts;
141 struct sa_subdev_info subdev[0];
144 static void sa1100_set_vpp(struct map_info *map, int on)
146 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
147 subdev->plat->set_vpp(on);
150 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
152 if (subdev->mtd)
153 map_destroy(subdev->mtd);
154 if (subdev->map.virt)
155 iounmap(subdev->map.virt);
156 release_mem_region(subdev->map.phys, subdev->map.size);
159 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
161 unsigned long phys;
162 unsigned int size;
163 int ret;
165 phys = res->start;
166 size = res->end - phys + 1;
169 * Retrieve the bankwidth from the MSC registers.
170 * We currently only implement CS0 and CS1 here.
172 switch (phys) {
173 default:
174 printk(KERN_WARNING "SA1100 flash: unknown base address "
175 "0x%08lx, assuming CS0\n", phys);
177 case SA1100_CS0_PHYS:
178 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
179 break;
181 case SA1100_CS1_PHYS:
182 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
183 break;
186 if (!request_mem_region(phys, size, subdev->name)) {
187 ret = -EBUSY;
188 goto out;
191 if (subdev->plat->set_vpp)
192 subdev->map.set_vpp = sa1100_set_vpp;
194 subdev->map.phys = phys;
195 subdev->map.size = size;
196 subdev->map.virt = ioremap(phys, size);
197 if (!subdev->map.virt) {
198 ret = -ENOMEM;
199 goto err;
202 simple_map_init(&subdev->map);
205 * Now let's probe for the actual flash. Do it here since
206 * specific machine settings might have been set above.
208 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
209 if (subdev->mtd == NULL) {
210 ret = -ENXIO;
211 goto err;
213 subdev->mtd->owner = THIS_MODULE;
215 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
216 "%d-bit\n", phys, subdev->mtd->size >> 20,
217 subdev->map.bankwidth * 8);
219 return 0;
221 err:
222 sa1100_destroy_subdev(subdev);
223 out:
224 return ret;
227 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
229 int i;
231 if (info->mtd) {
232 if (info->nr_parts == 0)
233 del_mtd_device(info->mtd);
234 #ifdef CONFIG_MTD_PARTITIONS
235 else
236 del_mtd_partitions(info->mtd);
237 #endif
238 #ifdef CONFIG_MTD_CONCAT
239 if (info->mtd != info->subdev[0].mtd)
240 mtd_concat_destroy(info->mtd);
241 #endif
244 kfree(info->parts);
246 for (i = info->num_subdev - 1; i >= 0; i--)
247 sa1100_destroy_subdev(&info->subdev[i]);
248 kfree(info);
250 if (plat->exit)
251 plat->exit();
254 static struct sa_info *__init
255 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
257 struct sa_info *info;
258 int nr, size, i, ret = 0;
261 * Count number of devices.
263 for (nr = 0; ; nr++)
264 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
265 break;
267 if (nr == 0) {
268 ret = -ENODEV;
269 goto out;
272 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
275 * Allocate the map_info structs in one go.
277 info = kmalloc(size, GFP_KERNEL);
278 if (!info) {
279 ret = -ENOMEM;
280 goto out;
283 memset(info, 0, size);
285 if (plat->init) {
286 ret = plat->init();
287 if (ret)
288 goto err;
292 * Claim and then map the memory regions.
294 for (i = 0; i < nr; i++) {
295 struct sa_subdev_info *subdev = &info->subdev[i];
296 struct resource *res;
298 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
299 if (!res)
300 break;
302 subdev->map.name = subdev->name;
303 sprintf(subdev->name, "%s-%d", plat->name, i);
304 subdev->plat = plat;
306 ret = sa1100_probe_subdev(subdev, res);
307 if (ret)
308 break;
311 info->num_subdev = i;
314 * ENXIO is special. It means we didn't find a chip when we probed.
316 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
317 goto err;
320 * If we found one device, don't bother with concat support. If
321 * we found multiple devices, use concat if we have it available,
322 * otherwise fail. Either way, it'll be called "sa1100".
324 if (info->num_subdev == 1) {
325 strcpy(info->subdev[0].name, plat->name);
326 info->mtd = info->subdev[0].mtd;
327 ret = 0;
328 } else if (info->num_subdev > 1) {
329 #ifdef CONFIG_MTD_CONCAT
330 struct mtd_info *cdev[nr];
332 * We detected multiple devices. Concatenate them together.
334 for (i = 0; i < info->num_subdev; i++)
335 cdev[i] = info->subdev[i].mtd;
337 info->mtd = mtd_concat_create(cdev, info->num_subdev,
338 plat->name);
339 if (info->mtd == NULL)
340 ret = -ENXIO;
341 #else
342 printk(KERN_ERR "SA1100 flash: multiple devices "
343 "found but MTD concat support disabled.\n");
344 ret = -ENXIO;
345 #endif
348 if (ret == 0)
349 return info;
351 err:
352 sa1100_destroy(info, plat);
353 out:
354 return ERR_PTR(ret);
357 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
359 static int __init sa1100_mtd_probe(struct platform_device *pdev)
361 struct flash_platform_data *plat = pdev->dev.platform_data;
362 struct mtd_partition *parts;
363 const char *part_type = NULL;
364 struct sa_info *info;
365 int err, nr_parts = 0;
367 if (!plat)
368 return -ENODEV;
370 info = sa1100_setup_mtd(pdev, plat);
371 if (IS_ERR(info)) {
372 err = PTR_ERR(info);
373 goto out;
377 * Partition selection stuff.
379 #ifdef CONFIG_MTD_PARTITIONS
380 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
381 if (nr_parts > 0) {
382 info->parts = parts;
383 part_type = "dynamic";
384 } else
385 #endif
387 parts = plat->parts;
388 nr_parts = plat->nr_parts;
389 part_type = "static";
392 if (nr_parts == 0) {
393 printk(KERN_NOTICE "SA1100 flash: no partition info "
394 "available, registering whole flash\n");
395 add_mtd_device(info->mtd);
396 } else {
397 printk(KERN_NOTICE "SA1100 flash: using %s partition "
398 "definition\n", part_type);
399 add_mtd_partitions(info->mtd, parts, nr_parts);
402 info->nr_parts = nr_parts;
404 platform_set_drvdata(pdev, info);
405 err = 0;
407 out:
408 return err;
411 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
413 struct sa_info *info = platform_get_drvdata(pdev);
414 struct flash_platform_data *plat = pdev->dev.platform_data;
416 platform_set_drvdata(pdev, NULL);
417 sa1100_destroy(info, plat);
419 return 0;
422 #ifdef CONFIG_PM
423 static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
425 struct sa_info *info = platform_get_drvdata(dev);
426 int ret = 0;
428 if (info)
429 ret = info->mtd->suspend(info->mtd);
431 return ret;
434 static int sa1100_mtd_resume(struct platform_device *dev)
436 struct sa_info *info = platform_get_drvdata(dev);
437 if (info)
438 info->mtd->resume(info->mtd);
439 return 0;
442 static void sa1100_mtd_shutdown(struct platform_device *dev)
444 struct sa_info *info = platform_get_drvdata(dev);
445 if (info && info->mtd->suspend(info->mtd) == 0)
446 info->mtd->resume(info->mtd);
448 #else
449 #define sa1100_mtd_suspend NULL
450 #define sa1100_mtd_resume NULL
451 #define sa1100_mtd_shutdown NULL
452 #endif
454 static struct platform_driver sa1100_mtd_driver = {
455 .probe = sa1100_mtd_probe,
456 .remove = __exit_p(sa1100_mtd_remove),
457 .suspend = sa1100_mtd_suspend,
458 .resume = sa1100_mtd_resume,
459 .shutdown = sa1100_mtd_shutdown,
460 .driver = {
461 .name = "flash",
465 static int __init sa1100_mtd_init(void)
467 return platform_driver_register(&sa1100_mtd_driver);
470 static void __exit sa1100_mtd_exit(void)
472 platform_driver_unregister(&sa1100_mtd_driver);
475 module_init(sa1100_mtd_init);
476 module_exit(sa1100_mtd_exit);
478 MODULE_AUTHOR("Nicolas Pitre");
479 MODULE_DESCRIPTION("SA1100 CFI map driver");
480 MODULE_LICENSE("GPL");