blob: 55f21ddec3df16847cdd9e2136e86474b82c1b74 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Flash memory access on SA11x0 based devices
3 *
4 * (C) 2000 Nicolas Pitre <nico@cam.org>
5 *
6 * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $
7 */
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>
18
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/map.h>
21#include <linux/mtd/partitions.h>
22#include <linux/mtd/concat.h>
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/io.h>
25#include <asm/sizes.h>
26#include <asm/mach/flash.h>
27
28#if 0
29/*
30 * This is here for documentation purposes only - until these people
31 * submit their machine types. It will be gone January 2005.
32 */
33static struct mtd_partition consus_partitions[] = {
34 {
35 .name = "Consus boot firmware",
36 .offset = 0,
37 .size = 0x00040000,
38 .mask_flags = MTD_WRITABLE, /* force read-only */
39 }, {
40 .name = "Consus kernel",
41 .offset = 0x00040000,
42 .size = 0x00100000,
43 .mask_flags = 0,
44 }, {
45 .name = "Consus disk",
46 .offset = 0x00140000,
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,
54 .mask_flags = 0,
55 }, {
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
60 system used) */
61 .name = "Consus disk2",
62 .offset = 0x01000000,
63 .size = 0x01000000 - 0x00140000,
64 .mask_flags = 0,
65 }
66};
67
68/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
69static struct mtd_partition frodo_partitions[] =
70{
71 {
72 .name = "bootloader",
73 .size = 0x00040000,
74 .offset = 0x00000000,
75 .mask_flags = MTD_WRITEABLE
76 }, {
77 .name = "bootloader params",
78 .size = 0x00040000,
79 .offset = MTDPART_OFS_APPEND,
80 .mask_flags = MTD_WRITEABLE
81 }, {
82 .name = "kernel",
83 .size = 0x00100000,
84 .offset = MTDPART_OFS_APPEND,
85 .mask_flags = MTD_WRITEABLE
86 }, {
87 .name = "ramdisk",
88 .size = 0x00400000,
89 .offset = MTDPART_OFS_APPEND,
90 .mask_flags = MTD_WRITEABLE
91 }, {
92 .name = "file system",
93 .size = MTDPART_SIZ_FULL,
94 .offset = MTDPART_OFS_APPEND
95 }
96};
97
98static struct mtd_partition jornada56x_partitions[] = {
99 {
100 .name = "bootldr",
101 .size = 0x00040000,
102 .offset = 0,
103 .mask_flags = MTD_WRITEABLE,
104 }, {
105 .name = "rootfs",
106 .size = MTDPART_SIZ_FULL,
107 .offset = MTDPART_OFS_APPEND,
108 }
109};
110
111static void jornada56x_set_vpp(int vpp)
112{
113 if (vpp)
114 GPSR = GPIO_GPIO26;
115 else
116 GPCR = GPIO_GPIO26;
117 GPDR |= GPIO_GPIO26;
118}
119
120/*
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
125 */
126#endif
127
128struct sa_subdev_info {
129 char name[16];
130 struct map_info map;
131 struct mtd_info *mtd;
132 struct flash_platform_data *data;
133};
134
135struct sa_info {
136 struct mtd_partition *parts;
137 struct mtd_info *mtd;
138 int num_subdev;
139 struct sa_subdev_info subdev[0];
140};
141
142static void sa1100_set_vpp(struct map_info *map, int on)
143{
144 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
145 subdev->data->set_vpp(on);
146}
147
148static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
149{
150 if (subdev->mtd)
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);
155}
156
157static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
158{
159 unsigned long phys;
160 unsigned int size;
161 int ret;
162
163 phys = res->start;
164 size = res->end - phys + 1;
165
166 /*
167 * Retrieve the bankwidth from the MSC registers.
168 * We currently only implement CS0 and CS1 here.
169 */
170 switch (phys) {
171 default:
172 printk(KERN_WARNING "SA1100 flash: unknown base address "
173 "0x%08lx, assuming CS0\n", phys);
174
175 case SA1100_CS0_PHYS:
176 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
177 break;
178
179 case SA1100_CS1_PHYS:
180 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
181 break;
182 }
183
184 if (!request_mem_region(phys, size, subdev->name)) {
185 ret = -EBUSY;
186 goto out;
187 }
188
189 if (subdev->data->set_vpp)
190 subdev->map.set_vpp = sa1100_set_vpp;
191
192 subdev->map.phys = phys;
193 subdev->map.size = size;
194 subdev->map.virt = ioremap(phys, size);
195 if (!subdev->map.virt) {
196 ret = -ENOMEM;
197 goto err;
198 }
199
200 simple_map_init(&subdev->map);
201
202 /*
203 * Now let's probe for the actual flash. Do it here since
204 * specific machine settings might have been set above.
205 */
206 subdev->mtd = do_map_probe(subdev->data->map_name, &subdev->map);
207 if (subdev->mtd == NULL) {
208 ret = -ENXIO;
209 goto err;
210 }
211 subdev->mtd->owner = THIS_MODULE;
212
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);
216
217 return 0;
218
219 err:
220 sa1100_destroy_subdev(subdev);
221 out:
222 return ret;
223}
224
225static void sa1100_destroy(struct sa_info *info)
226{
227 int i;
228
229 if (info->mtd) {
230 del_mtd_partitions(info->mtd);
231
232#ifdef CONFIG_MTD_CONCAT
233 if (info->mtd != info->subdev[0].mtd)
234 mtd_concat_destroy(info->mtd);
235#endif
236 }
237
238 if (info->parts)
239 kfree(info->parts);
240
241 for (i = info->num_subdev - 1; i >= 0; i--)
242 sa1100_destroy_subdev(&info->subdev[i]);
243 kfree(info);
244}
245
246static struct sa_info *__init
247sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash)
248{
249 struct sa_info *info;
250 int nr, size, i, ret = 0;
251
252 /*
253 * Count number of devices.
254 */
255 for (nr = 0; ; nr++)
256 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
257 break;
258
259 if (nr == 0) {
260 ret = -ENODEV;
261 goto out;
262 }
263
264 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
265
266 /*
267 * Allocate the map_info structs in one go.
268 */
269 info = kmalloc(size, GFP_KERNEL);
270 if (!info) {
271 ret = -ENOMEM;
272 goto out;
273 }
274
275 memset(info, 0, size);
276
277 /*
278 * Claim and then map the memory regions.
279 */
280 for (i = 0; i < nr; i++) {
281 struct sa_subdev_info *subdev = &info->subdev[i];
282 struct resource *res;
283
284 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
285 if (!res)
286 break;
287
288 subdev->map.name = subdev->name;
289 sprintf(subdev->name, "sa1100-%d", i);
290 subdev->data = flash;
291
292 ret = sa1100_probe_subdev(subdev, res);
293 if (ret)
294 break;
295 }
296
297 info->num_subdev = i;
298
299 /*
300 * ENXIO is special. It means we didn't find a chip when we probed.
301 */
302 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
303 goto err;
304
305 /*
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".
309 */
310 if (info->num_subdev == 1) {
311 strcpy(info->subdev[0].name, "sa1100");
312 info->mtd = info->subdev[0].mtd;
313 ret = 0;
314 } else if (info->num_subdev > 1) {
315#ifdef CONFIG_MTD_CONCAT
316 struct mtd_info *cdev[nr];
317 /*
318 * We detected multiple devices. Concatenate them together.
319 */
320 for (i = 0; i < info->num_subdev; i++)
321 cdev[i] = info->subdev[i].mtd;
322
323 info->mtd = mtd_concat_create(cdev, info->num_subdev,
324 "sa1100");
325 if (info->mtd == NULL)
326 ret = -ENXIO;
327#else
328 printk(KERN_ERR "SA1100 flash: multiple devices "
329 "found but MTD concat support disabled.\n");
330 ret = -ENXIO;
331#endif
332 }
333
334 if (ret == 0)
335 return info;
336
337 err:
338 sa1100_destroy(info);
339 out:
340 return ERR_PTR(ret);
341}
342
343static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
344
345static int __init sa1100_mtd_probe(struct device *dev)
346{
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;
353
354 if (!flash)
355 return -ENODEV;
356
357 info = sa1100_setup_mtd(pdev, flash);
358 if (IS_ERR(info)) {
359 err = PTR_ERR(info);
360 goto out;
361 }
362
363 /*
364 * Partition selection stuff.
365 */
366#ifdef CONFIG_MTD_PARTITIONS
367 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
368 if (nr_parts > 0) {
369 info->parts = parts;
370 part_type = "dynamic";
371 } else
372#endif
373 {
374 parts = flash->parts;
375 nr_parts = flash->nr_parts;
376 part_type = "static";
377 }
378
379 if (nr_parts == 0) {
380 printk(KERN_NOTICE "SA1100 flash: no partition info "
381 "available, registering whole flash\n");
382 add_mtd_device(info->mtd);
383 } else {
384 printk(KERN_NOTICE "SA1100 flash: using %s partition "
385 "definition\n", part_type);
386 add_mtd_partitions(info->mtd, parts, nr_parts);
387 }
388
389 dev_set_drvdata(dev, info);
390 err = 0;
391
392 out:
393 return err;
394}
395
396static int __exit sa1100_mtd_remove(struct device *dev)
397{
398 struct sa_info *info = dev_get_drvdata(dev);
399 dev_set_drvdata(dev, NULL);
400 sa1100_destroy(info);
401 return 0;
402}
403
404#ifdef CONFIG_PM
Russell King9480e302005-10-28 09:52:56 -0700405static int sa1100_mtd_suspend(struct device *dev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
407 struct sa_info *info = dev_get_drvdata(dev);
408 int ret = 0;
409
Russell King9480e302005-10-28 09:52:56 -0700410 if (info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 ret = info->mtd->suspend(info->mtd);
412
413 return ret;
414}
415
Russell King9480e302005-10-28 09:52:56 -0700416static int sa1100_mtd_resume(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 struct sa_info *info = dev_get_drvdata(dev);
Russell King9480e302005-10-28 09:52:56 -0700419 if (info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 info->mtd->resume(info->mtd);
421 return 0;
422}
423#else
424#define sa1100_mtd_suspend NULL
425#define sa1100_mtd_resume NULL
426#endif
427
428static struct device_driver sa1100_mtd_driver = {
429 .name = "flash",
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,
435};
436
437static int __init sa1100_mtd_init(void)
438{
439 return driver_register(&sa1100_mtd_driver);
440}
441
442static void __exit sa1100_mtd_exit(void)
443{
444 driver_unregister(&sa1100_mtd_driver);
445}
446
447module_init(sa1100_mtd_init);
448module_exit(sa1100_mtd_exit);
449
450MODULE_AUTHOR("Nicolas Pitre");
451MODULE_DESCRIPTION("SA1100 CFI map driver");
452MODULE_LICENSE("GPL");