2
* Flash memory access on SA11x0 based devices
4
* (C) 2000 Nicolas Pitre <nico@fluxnic.net>
6
#include <linux/module.h>
7
#include <linux/types.h>
8
#include <linux/ioport.h>
9
#include <linux/kernel.h>
10
#include <linux/init.h>
11
#include <linux/errno.h>
12
#include <linux/slab.h>
13
#include <linux/platform_device.h>
14
#include <linux/err.h>
17
#include <linux/mtd/mtd.h>
18
#include <linux/mtd/map.h>
19
#include <linux/mtd/partitions.h>
20
#include <linux/mtd/concat.h>
22
#include <mach/hardware.h>
23
#include <asm/sizes.h>
24
#include <asm/mach/flash.h>
28
* This is here for documentation purposes only - until these people
29
* submit their machine types. It will be gone January 2005.
31
static struct mtd_partition consus_partitions[] = {
33
.name = "Consus boot firmware",
36
.mask_flags = MTD_WRITABLE, /* force read-only */
38
.name = "Consus kernel",
43
.name = "Consus disk",
45
/* The rest (up to 16M) for jffs. We could put 0 and
46
make it find the size automatically, but right now
47
i have 32 megs. jffs will use all 32 megs if given
48
the chance, and this leads to horrible problems
49
when you try to re-flash the image because blob
50
won't erase the whole partition. */
51
.size = 0x01000000 - 0x00140000,
54
/* this disk is a secondary disk, which can be used as
55
needed, for simplicity, make it the size of the other
56
consus partition, although realistically it could be
57
the remainder of the disk (depending on the file
59
.name = "Consus disk2",
61
.size = 0x01000000 - 0x00140000,
66
/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
67
static struct mtd_partition frodo_partitions[] =
73
.mask_flags = MTD_WRITEABLE
75
.name = "bootloader params",
77
.offset = MTDPART_OFS_APPEND,
78
.mask_flags = MTD_WRITEABLE
82
.offset = MTDPART_OFS_APPEND,
83
.mask_flags = MTD_WRITEABLE
87
.offset = MTDPART_OFS_APPEND,
88
.mask_flags = MTD_WRITEABLE
90
.name = "file system",
91
.size = MTDPART_SIZ_FULL,
92
.offset = MTDPART_OFS_APPEND
96
static struct mtd_partition jornada56x_partitions[] = {
101
.mask_flags = MTD_WRITEABLE,
104
.size = MTDPART_SIZ_FULL,
105
.offset = MTDPART_OFS_APPEND,
109
static void jornada56x_set_vpp(int vpp)
119
* Machine Phys Size set_vpp
120
* Consus : SA1100_CS0_PHYS SZ_32M
121
* Frodo : SA1100_CS0_PHYS SZ_32M
122
* Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
126
struct sa_subdev_info {
129
struct mtd_info *mtd;
130
struct flash_platform_data *plat;
134
struct mtd_partition *parts;
135
struct mtd_info *mtd;
137
unsigned int nr_parts;
138
struct sa_subdev_info subdev[0];
141
static void sa1100_set_vpp(struct map_info *map, int on)
143
struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
144
subdev->plat->set_vpp(on);
147
static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
150
map_destroy(subdev->mtd);
151
if (subdev->map.virt)
152
iounmap(subdev->map.virt);
153
release_mem_region(subdev->map.phys, subdev->map.size);
156
static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
163
size = res->end - phys + 1;
166
* Retrieve the bankwidth from the MSC registers.
167
* We currently only implement CS0 and CS1 here.
171
printk(KERN_WARNING "SA1100 flash: unknown base address "
172
"0x%08lx, assuming CS0\n", phys);
174
case SA1100_CS0_PHYS:
175
subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
178
case SA1100_CS1_PHYS:
179
subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
183
if (!request_mem_region(phys, size, subdev->name)) {
188
if (subdev->plat->set_vpp)
189
subdev->map.set_vpp = sa1100_set_vpp;
191
subdev->map.phys = phys;
192
subdev->map.size = size;
193
subdev->map.virt = ioremap(phys, size);
194
if (!subdev->map.virt) {
199
simple_map_init(&subdev->map);
202
* Now let's probe for the actual flash. Do it here since
203
* specific machine settings might have been set above.
205
subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
206
if (subdev->mtd == NULL) {
210
subdev->mtd->owner = THIS_MODULE;
212
printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %uMiB, %d-bit\n",
213
phys, (unsigned)(subdev->mtd->size >> 20),
214
subdev->map.bankwidth * 8);
219
sa1100_destroy_subdev(subdev);
224
static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
229
if (info->nr_parts == 0)
230
del_mtd_device(info->mtd);
231
#ifdef CONFIG_MTD_PARTITIONS
233
del_mtd_partitions(info->mtd);
235
#ifdef CONFIG_MTD_CONCAT
236
if (info->mtd != info->subdev[0].mtd)
237
mtd_concat_destroy(info->mtd);
243
for (i = info->num_subdev - 1; i >= 0; i--)
244
sa1100_destroy_subdev(&info->subdev[i]);
251
static struct sa_info *__devinit
252
sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
254
struct sa_info *info;
255
int nr, size, i, ret = 0;
258
* Count number of devices.
261
if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
269
size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
272
* Allocate the map_info structs in one go.
274
info = kzalloc(size, GFP_KERNEL);
287
* Claim and then map the memory regions.
289
for (i = 0; i < nr; i++) {
290
struct sa_subdev_info *subdev = &info->subdev[i];
291
struct resource *res;
293
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
297
subdev->map.name = subdev->name;
298
sprintf(subdev->name, "%s-%d", plat->name, i);
301
ret = sa1100_probe_subdev(subdev, res);
306
info->num_subdev = i;
309
* ENXIO is special. It means we didn't find a chip when we probed.
311
if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
315
* If we found one device, don't bother with concat support. If
316
* we found multiple devices, use concat if we have it available,
317
* otherwise fail. Either way, it'll be called "sa1100".
319
if (info->num_subdev == 1) {
320
strcpy(info->subdev[0].name, plat->name);
321
info->mtd = info->subdev[0].mtd;
323
} else if (info->num_subdev > 1) {
324
#ifdef CONFIG_MTD_CONCAT
325
struct mtd_info *cdev[nr];
327
* We detected multiple devices. Concatenate them together.
329
for (i = 0; i < info->num_subdev; i++)
330
cdev[i] = info->subdev[i].mtd;
332
info->mtd = mtd_concat_create(cdev, info->num_subdev,
334
if (info->mtd == NULL)
337
printk(KERN_ERR "SA1100 flash: multiple devices "
338
"found but MTD concat support disabled.\n");
347
sa1100_destroy(info, plat);
352
static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
354
static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
356
struct flash_platform_data *plat = pdev->dev.platform_data;
357
struct mtd_partition *parts;
358
const char *part_type = NULL;
359
struct sa_info *info;
360
int err, nr_parts = 0;
365
info = sa1100_setup_mtd(pdev, plat);
372
* Partition selection stuff.
374
#ifdef CONFIG_MTD_PARTITIONS
375
nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
378
part_type = "dynamic";
383
nr_parts = plat->nr_parts;
384
part_type = "static";
388
printk(KERN_NOTICE "SA1100 flash: no partition info "
389
"available, registering whole flash\n");
390
add_mtd_device(info->mtd);
392
printk(KERN_NOTICE "SA1100 flash: using %s partition "
393
"definition\n", part_type);
394
add_mtd_partitions(info->mtd, parts, nr_parts);
397
info->nr_parts = nr_parts;
399
platform_set_drvdata(pdev, info);
406
static int __exit sa1100_mtd_remove(struct platform_device *pdev)
408
struct sa_info *info = platform_get_drvdata(pdev);
409
struct flash_platform_data *plat = pdev->dev.platform_data;
411
platform_set_drvdata(pdev, NULL);
412
sa1100_destroy(info, plat);
418
static void sa1100_mtd_shutdown(struct platform_device *dev)
420
struct sa_info *info = platform_get_drvdata(dev);
421
if (info && info->mtd->suspend(info->mtd) == 0)
422
info->mtd->resume(info->mtd);
425
#define sa1100_mtd_shutdown NULL
428
static struct platform_driver sa1100_mtd_driver = {
429
.probe = sa1100_mtd_probe,
430
.remove = __exit_p(sa1100_mtd_remove),
431
.shutdown = sa1100_mtd_shutdown,
433
.name = "sa1100-mtd",
434
.owner = THIS_MODULE,
438
static int __init sa1100_mtd_init(void)
440
return platform_driver_register(&sa1100_mtd_driver);
443
static void __exit sa1100_mtd_exit(void)
445
platform_driver_unregister(&sa1100_mtd_driver);
448
module_init(sa1100_mtd_init);
449
module_exit(sa1100_mtd_exit);
451
MODULE_AUTHOR("Nicolas Pitre");
452
MODULE_DESCRIPTION("SA1100 CFI map driver");
453
MODULE_LICENSE("GPL");
454
MODULE_ALIAS("platform:sa1100-mtd");