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 $
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/ioport.h>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/errno.h>
14 #include <linux/slab.h>
15 #include <linux/platform_device.h>
16 #include <linux/err.h>
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/map.h>
20 #include <linux/mtd/partitions.h>
21 #include <linux/mtd/concat.h>
23 #include <asm/hardware.h>
25 #include <asm/sizes.h>
26 #include <asm/mach/flash.h>
30 * This is here for documentation purposes only - until these people
31 * submit their machine types. It will be gone January 2005.
33 static struct mtd_partition consus_partitions[] = {
35 .name = "Consus boot firmware",
38 .mask_flags = MTD_WRITABLE, /* force read-only */
40 .name = "Consus kernel",
45 .name = "Consus disk",
47 /* The rest (up to 16M) for jffs. We could put 0 and
48 make it find the size automatically, but right now
49 i have 32 megs. jffs will use all 32 megs if given
50 the chance, and this leads to horrible problems
51 when you try to re-flash the image because blob
52 won't erase the whole partition. */
53 .size = 0x01000000 - 0x00140000,
56 /* this disk is a secondary disk, which can be used as
57 needed, for simplicity, make it the size of the other
58 consus partition, although realistically it could be
59 the remainder of the disk (depending on the file
61 .name = "Consus disk2",
63 .size = 0x01000000 - 0x00140000,
68 /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
69 static struct mtd_partition frodo_partitions[] =
75 .mask_flags = MTD_WRITEABLE
77 .name = "bootloader params",
79 .offset = MTDPART_OFS_APPEND,
80 .mask_flags = MTD_WRITEABLE
84 .offset = MTDPART_OFS_APPEND,
85 .mask_flags = MTD_WRITEABLE
89 .offset = MTDPART_OFS_APPEND,
90 .mask_flags = MTD_WRITEABLE
92 .name = "file system",
93 .size = MTDPART_SIZ_FULL,
94 .offset = MTDPART_OFS_APPEND
98 static struct mtd_partition jornada56x_partitions[] = {
103 .mask_flags = MTD_WRITEABLE,
106 .size = MTDPART_SIZ_FULL,
107 .offset = MTDPART_OFS_APPEND,
111 static void jornada56x_set_vpp(int vpp)
121 * Machine Phys Size set_vpp
122 * Consus : SA1100_CS0_PHYS SZ_32M
123 * Frodo : SA1100_CS0_PHYS SZ_32M
124 * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
128 struct sa_subdev_info {
131 struct mtd_info *mtd;
132 struct flash_platform_data *plat;
136 struct mtd_partition *parts;
137 struct mtd_info *mtd;
139 unsigned int nr_parts;
140 struct sa_subdev_info subdev[0];
143 static void sa1100_set_vpp(struct map_info *map, int on)
145 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
146 subdev->plat->set_vpp(on);
149 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
152 map_destroy(subdev->mtd);
153 if (subdev->map.virt)
154 iounmap(subdev->map.virt);
155 release_mem_region(subdev->map.phys, subdev->map.size);
158 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
165 size = res->end - phys + 1;
168 * Retrieve the bankwidth from the MSC registers.
169 * We currently only implement CS0 and CS1 here.
173 printk(KERN_WARNING "SA1100 flash: unknown base address "
174 "0x%08lx, assuming CS0\n", phys);
176 case SA1100_CS0_PHYS:
177 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
180 case SA1100_CS1_PHYS:
181 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
185 if (!request_mem_region(phys, size, subdev->name)) {
190 if (subdev->plat->set_vpp)
191 subdev->map.set_vpp = sa1100_set_vpp;
193 subdev->map.phys = phys;
194 subdev->map.size = size;
195 subdev->map.virt = ioremap(phys, size);
196 if (!subdev->map.virt) {
201 simple_map_init(&subdev->map);
204 * Now let's probe for the actual flash. Do it here since
205 * specific machine settings might have been set above.
207 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
208 if (subdev->mtd == NULL) {
212 subdev->mtd->owner = THIS_MODULE;
214 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
215 "%d-bit\n", phys, subdev->mtd->size >> 20,
216 subdev->map.bankwidth * 8);
221 sa1100_destroy_subdev(subdev);
226 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
231 if (info->nr_parts == 0)
232 del_mtd_device(info->mtd);
233 #ifdef CONFIG_MTD_PARTITIONS
235 del_mtd_partitions(info->mtd);
237 #ifdef CONFIG_MTD_CONCAT
238 if (info->mtd != info->subdev[0].mtd)
239 mtd_concat_destroy(info->mtd);
245 for (i = info->num_subdev - 1; i >= 0; i--)
246 sa1100_destroy_subdev(&info->subdev[i]);
253 static struct sa_info *__init
254 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
256 struct sa_info *info;
257 int nr, size, i, ret = 0;
260 * Count number of devices.
263 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
271 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
274 * Allocate the map_info structs in one go.
276 info = kmalloc(size, GFP_KERNEL);
282 memset(info, 0, size);
291 * Claim and then map the memory regions.
293 for (i = 0; i < nr; i++) {
294 struct sa_subdev_info *subdev = &info->subdev[i];
295 struct resource *res;
297 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
301 subdev->map.name = subdev->name;
302 sprintf(subdev->name, "%s-%d", plat->name, i);
305 ret = sa1100_probe_subdev(subdev, res);
310 info->num_subdev = i;
313 * ENXIO is special. It means we didn't find a chip when we probed.
315 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
319 * If we found one device, don't bother with concat support. If
320 * we found multiple devices, use concat if we have it available,
321 * otherwise fail. Either way, it'll be called "sa1100".
323 if (info->num_subdev == 1) {
324 strcpy(info->subdev[0].name, plat->name);
325 info->mtd = info->subdev[0].mtd;
327 } else if (info->num_subdev > 1) {
328 #ifdef CONFIG_MTD_CONCAT
329 struct mtd_info *cdev[nr];
331 * We detected multiple devices. Concatenate them together.
333 for (i = 0; i < info->num_subdev; i++)
334 cdev[i] = info->subdev[i].mtd;
336 info->mtd = mtd_concat_create(cdev, info->num_subdev,
338 if (info->mtd == NULL)
341 printk(KERN_ERR "SA1100 flash: multiple devices "
342 "found but MTD concat support disabled.\n");
351 sa1100_destroy(info, plat);
356 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
358 static int __init sa1100_mtd_probe(struct platform_device *pdev)
360 struct flash_platform_data *plat = pdev->dev.platform_data;
361 struct mtd_partition *parts;
362 const char *part_type = NULL;
363 struct sa_info *info;
364 int err, nr_parts = 0;
369 info = sa1100_setup_mtd(pdev, plat);
376 * Partition selection stuff.
378 #ifdef CONFIG_MTD_PARTITIONS
379 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
382 part_type = "dynamic";
387 nr_parts = plat->nr_parts;
388 part_type = "static";
392 printk(KERN_NOTICE "SA1100 flash: no partition info "
393 "available, registering whole flash\n");
394 add_mtd_device(info->mtd);
396 printk(KERN_NOTICE "SA1100 flash: using %s partition "
397 "definition\n", part_type);
398 add_mtd_partitions(info->mtd, parts, nr_parts);
401 info->nr_parts = nr_parts;
403 platform_set_drvdata(pdev, info);
410 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
412 struct sa_info *info = platform_get_drvdata(pdev);
413 struct flash_platform_data *plat = pdev->dev.platform_data;
415 platform_set_drvdata(pdev, NULL);
416 sa1100_destroy(info, plat);
422 static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
424 struct sa_info *info = platform_get_drvdata(dev);
428 ret = info->mtd->suspend(info->mtd);
433 static int sa1100_mtd_resume(struct platform_device *dev)
435 struct sa_info *info = platform_get_drvdata(dev);
437 info->mtd->resume(info->mtd);
441 static void sa1100_mtd_shutdown(struct platform_device *dev)
443 struct sa_info *info = platform_get_drvdata(dev);
444 if (info && info->mtd->suspend(info->mtd) == 0)
445 info->mtd->resume(info->mtd);
448 #define sa1100_mtd_suspend NULL
449 #define sa1100_mtd_resume NULL
450 #define sa1100_mtd_shutdown NULL
453 static struct platform_driver sa1100_mtd_driver = {
454 .probe = sa1100_mtd_probe,
455 .remove = __exit_p(sa1100_mtd_remove),
456 .suspend = sa1100_mtd_suspend,
457 .resume = sa1100_mtd_resume,
458 .shutdown = sa1100_mtd_shutdown,
464 static int __init sa1100_mtd_init(void)
466 return platform_driver_register(&sa1100_mtd_driver);
469 static void __exit sa1100_mtd_exit(void)
471 platform_driver_unregister(&sa1100_mtd_driver);
474 module_init(sa1100_mtd_init);
475 module_exit(sa1100_mtd_exit);
477 MODULE_AUTHOR("Nicolas Pitre");
478 MODULE_DESCRIPTION("SA1100 CFI map driver");
479 MODULE_LICENSE("GPL");