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
*__init
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");