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>
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 *data;
136 struct mtd_partition *parts;
137 struct mtd_info *mtd;
139 struct sa_subdev_info subdev[0];
142 static void sa1100_set_vpp(struct map_info *map, int on)
144 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
145 subdev->data->set_vpp(on);
148 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
151 map_destroy(subdev->mtd);
152 if (subdev->map.virt)
153 iounmap(subdev->map.virt);
154 release_mem_region(subdev->map.phys, subdev->map.size);
157 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
164 size = res->end - phys + 1;
167 * Retrieve the bankwidth from the MSC registers.
168 * We currently only implement CS0 and CS1 here.
172 printk(KERN_WARNING "SA1100 flash: unknown base address "
173 "0x%08lx, assuming CS0\n", phys);
175 case SA1100_CS0_PHYS:
176 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
179 case SA1100_CS1_PHYS:
180 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
184 if (!request_mem_region(phys, size, subdev->name)) {
189 if (subdev->data->set_vpp)
190 subdev->map.set_vpp = sa1100_set_vpp;
192 subdev->map.phys = phys;
193 subdev->map.size = size;
194 subdev->map.virt = ioremap(phys, size);
195 if (!subdev->map.virt) {
200 simple_map_init(&subdev->map);
203 * Now let's probe for the actual flash. Do it here since
204 * specific machine settings might have been set above.
206 subdev->mtd = do_map_probe(subdev->data->map_name, &subdev->map);
207 if (subdev->mtd == NULL) {
211 subdev->mtd->owner = THIS_MODULE;
213 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
214 "%d-bit\n", phys, subdev->mtd->size >> 20,
215 subdev->map.bankwidth * 8);
220 sa1100_destroy_subdev(subdev);
225 static void sa1100_destroy(struct sa_info *info)
230 del_mtd_partitions(info->mtd);
232 #ifdef CONFIG_MTD_CONCAT
233 if (info->mtd != info->subdev[0].mtd)
234 mtd_concat_destroy(info->mtd);
241 for (i = info->num_subdev - 1; i >= 0; i--)
242 sa1100_destroy_subdev(&info->subdev[i]);
246 static struct sa_info *__init
247 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash)
249 struct sa_info *info;
250 int nr, size, i, ret = 0;
253 * Count number of devices.
256 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
264 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
267 * Allocate the map_info structs in one go.
269 info = kmalloc(size, GFP_KERNEL);
275 memset(info, 0, size);
278 * Claim and then map the memory regions.
280 for (i = 0; i < nr; i++) {
281 struct sa_subdev_info *subdev = &info->subdev[i];
282 struct resource *res;
284 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
288 subdev->map.name = subdev->name;
289 sprintf(subdev->name, "sa1100-%d", i);
290 subdev->data = flash;
292 ret = sa1100_probe_subdev(subdev, res);
297 info->num_subdev = i;
300 * ENXIO is special. It means we didn't find a chip when we probed.
302 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
306 * If we found one device, don't bother with concat support. If
307 * we found multiple devices, use concat if we have it available,
308 * otherwise fail. Either way, it'll be called "sa1100".
310 if (info->num_subdev == 1) {
311 strcpy(info->subdev[0].name, "sa1100");
312 info->mtd = info->subdev[0].mtd;
314 } else if (info->num_subdev > 1) {
315 #ifdef CONFIG_MTD_CONCAT
316 struct mtd_info *cdev[nr];
318 * We detected multiple devices. Concatenate them together.
320 for (i = 0; i < info->num_subdev; i++)
321 cdev[i] = info->subdev[i].mtd;
323 info->mtd = mtd_concat_create(cdev, info->num_subdev,
325 if (info->mtd == NULL)
328 printk(KERN_ERR "SA1100 flash: multiple devices "
329 "found but MTD concat support disabled.\n");
338 sa1100_destroy(info);
343 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
345 static int __init sa1100_mtd_probe(struct device *dev)
347 struct platform_device *pdev = to_platform_device(dev);
348 struct flash_platform_data *flash = pdev->dev.platform_data;
349 struct mtd_partition *parts;
350 const char *part_type = NULL;
351 struct sa_info *info;
352 int err, nr_parts = 0;
357 info = sa1100_setup_mtd(pdev, flash);
364 * Partition selection stuff.
366 #ifdef CONFIG_MTD_PARTITIONS
367 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
370 part_type = "dynamic";
374 parts = flash->parts;
375 nr_parts = flash->nr_parts;
376 part_type = "static";
380 printk(KERN_NOTICE "SA1100 flash: no partition info "
381 "available, registering whole flash\n");
382 add_mtd_device(info->mtd);
384 printk(KERN_NOTICE "SA1100 flash: using %s partition "
385 "definition\n", part_type);
386 add_mtd_partitions(info->mtd, parts, nr_parts);
389 dev_set_drvdata(dev, info);
396 static int __exit sa1100_mtd_remove(struct device *dev)
398 struct sa_info *info = dev_get_drvdata(dev);
399 dev_set_drvdata(dev, NULL);
400 sa1100_destroy(info);
405 static int sa1100_mtd_suspend(struct device *dev, pm_message_t state, u32 level)
407 struct sa_info *info = dev_get_drvdata(dev);
410 if (info && level == SUSPEND_SAVE_STATE)
411 ret = info->mtd->suspend(info->mtd);
416 static int sa1100_mtd_resume(struct device *dev, u32 level)
418 struct sa_info *info = dev_get_drvdata(dev);
419 if (info && level == RESUME_RESTORE_STATE)
420 info->mtd->resume(info->mtd);
424 #define sa1100_mtd_suspend NULL
425 #define sa1100_mtd_resume NULL
428 static struct device_driver sa1100_mtd_driver = {
430 .bus = &platform_bus_type,
431 .probe = sa1100_mtd_probe,
432 .remove = __exit_p(sa1100_mtd_remove),
433 .suspend = sa1100_mtd_suspend,
434 .resume = sa1100_mtd_resume,
437 static int __init sa1100_mtd_init(void)
439 return driver_register(&sa1100_mtd_driver);
442 static void __exit sa1100_mtd_exit(void)
444 driver_unregister(&sa1100_mtd_driver);
447 module_init(sa1100_mtd_init);
448 module_exit(sa1100_mtd_exit);
450 MODULE_AUTHOR("Nicolas Pitre");
451 MODULE_DESCRIPTION("SA1100 CFI map driver");
452 MODULE_LICENSE("GPL");