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