2 * Flash memory access on SA11x0 based devices
4 * (C) 2000 Nicolas Pitre <nico@cam.org>
6 * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $
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/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>
26 #include <asm/sizes.h>
27 #include <asm/mach/flash.h>
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",
39 .mask_flags = MTD_WRITABLE, /* force read-only */
41 .name = "Consus kernel",
46 .name = "Consus disk",
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,
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
62 .name = "Consus disk2",
64 .size = 0x01000000 - 0x00140000,
69 /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
70 static struct mtd_partition frodo_partitions[] =
76 .mask_flags = MTD_WRITEABLE
78 .name = "bootloader params",
80 .offset = MTDPART_OFS_APPEND,
81 .mask_flags = MTD_WRITEABLE
85 .offset = MTDPART_OFS_APPEND,
86 .mask_flags = MTD_WRITEABLE
90 .offset = MTDPART_OFS_APPEND,
91 .mask_flags = MTD_WRITEABLE
93 .name = "file system",
94 .size = MTDPART_SIZ_FULL,
95 .offset = MTDPART_OFS_APPEND
99 static struct mtd_partition jornada56x_partitions[] = {
104 .mask_flags = MTD_WRITEABLE,
107 .size = MTDPART_SIZ_FULL,
108 .offset = MTDPART_OFS_APPEND,
112 static void jornada56x_set_vpp(int vpp)
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
129 struct sa_subdev_info {
132 struct mtd_info *mtd;
133 struct flash_platform_data *plat;
137 struct mtd_partition *parts;
138 struct mtd_info *mtd;
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 del_mtd_partitions(info->mtd);
233 #ifdef CONFIG_MTD_CONCAT
234 if (info->mtd != info->subdev[0].mtd)
235 mtd_concat_destroy(info->mtd);
242 for (i = info->num_subdev - 1; i >= 0; i--)
243 sa1100_destroy_subdev(&info->subdev[i]);
250 static struct sa_info *__init
251 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
253 struct sa_info *info;
254 int nr, size, i, ret = 0;
257 * Count number of devices.
260 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
268 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
271 * Allocate the map_info structs in one go.
273 info = kmalloc(size, GFP_KERNEL);
279 memset(info, 0, size);
288 * Claim and then map the memory regions.
290 for (i = 0; i < nr; i++) {
291 struct sa_subdev_info *subdev = &info->subdev[i];
292 struct resource *res;
294 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
298 subdev->map.name = subdev->name;
299 sprintf(subdev->name, "sa1100-%d", i);
302 ret = sa1100_probe_subdev(subdev, res);
307 info->num_subdev = i;
310 * ENXIO is special. It means we didn't find a chip when we probed.
312 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
316 * If we found one device, don't bother with concat support. If
317 * we found multiple devices, use concat if we have it available,
318 * otherwise fail. Either way, it'll be called "sa1100".
320 if (info->num_subdev == 1) {
321 strcpy(info->subdev[0].name, "sa1100");
322 info->mtd = info->subdev[0].mtd;
324 } else if (info->num_subdev > 1) {
325 #ifdef CONFIG_MTD_CONCAT
326 struct mtd_info *cdev[nr];
328 * We detected multiple devices. Concatenate them together.
330 for (i = 0; i < info->num_subdev; i++)
331 cdev[i] = info->subdev[i].mtd;
333 info->mtd = mtd_concat_create(cdev, info->num_subdev,
335 if (info->mtd == NULL)
338 printk(KERN_ERR "SA1100 flash: multiple devices "
339 "found but MTD concat support disabled.\n");
348 sa1100_destroy(info, plat);
353 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
355 static int __init sa1100_mtd_probe(struct device *dev)
357 struct platform_device *pdev = to_platform_device(dev);
358 struct flash_platform_data *plat = pdev->dev.platform_data;
359 struct mtd_partition *parts;
360 const char *part_type = NULL;
361 struct sa_info *info;
362 int err, nr_parts = 0;
367 info = sa1100_setup_mtd(pdev, plat);
374 * Partition selection stuff.
376 #ifdef CONFIG_MTD_PARTITIONS
377 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
380 part_type = "dynamic";
385 nr_parts = plat->nr_parts;
386 part_type = "static";
390 printk(KERN_NOTICE "SA1100 flash: no partition info "
391 "available, registering whole flash\n");
392 add_mtd_device(info->mtd);
394 printk(KERN_NOTICE "SA1100 flash: using %s partition "
395 "definition\n", part_type);
396 add_mtd_partitions(info->mtd, parts, nr_parts);
399 dev_set_drvdata(dev, info);
406 static int __exit sa1100_mtd_remove(struct device *dev)
408 struct sa_info *info = dev_get_drvdata(dev);
409 struct flash_platform_data *plat = dev->platform_data;
411 dev_set_drvdata(dev, NULL);
412 sa1100_destroy(info, plat);
418 static int sa1100_mtd_suspend(struct device *dev, pm_message_t state)
420 struct sa_info *info = dev_get_drvdata(dev);
424 ret = info->mtd->suspend(info->mtd);
429 static int sa1100_mtd_resume(struct device *dev)
431 struct sa_info *info = dev_get_drvdata(dev);
433 info->mtd->resume(info->mtd);
437 #define sa1100_mtd_suspend NULL
438 #define sa1100_mtd_resume NULL
441 static struct device_driver sa1100_mtd_driver = {
443 .bus = &platform_bus_type,
444 .probe = sa1100_mtd_probe,
445 .remove = __exit_p(sa1100_mtd_remove),
446 .suspend = sa1100_mtd_suspend,
447 .resume = sa1100_mtd_resume,
450 static int __init sa1100_mtd_init(void)
452 return driver_register(&sa1100_mtd_driver);
455 static void __exit sa1100_mtd_exit(void)
457 driver_unregister(&sa1100_mtd_driver);
460 module_init(sa1100_mtd_init);
461 module_exit(sa1100_mtd_exit);
463 MODULE_AUTHOR("Nicolas Pitre");
464 MODULE_DESCRIPTION("SA1100 CFI map driver");
465 MODULE_LICENSE("GPL");