Merge branch 'master'
[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 platform_device *pdev)
360 {
361         struct flash_platform_data *plat = pdev->dev.platform_data;
362         struct mtd_partition *parts;
363         const char *part_type = NULL;
364         struct sa_info *info;
365         int err, nr_parts = 0;
366
367         if (!plat)
368                 return -ENODEV;
369
370         info = sa1100_setup_mtd(pdev, plat);
371         if (IS_ERR(info)) {
372                 err = PTR_ERR(info);
373                 goto out;
374         }
375
376         /*
377          * Partition selection stuff.
378          */
379 #ifdef CONFIG_MTD_PARTITIONS
380         nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
381         if (nr_parts > 0) {
382                 info->parts = parts;
383                 part_type = "dynamic";
384         } else
385 #endif
386         {
387                 parts = plat->parts;
388                 nr_parts = plat->nr_parts;
389                 part_type = "static";
390         }
391
392         if (nr_parts == 0) {
393                 printk(KERN_NOTICE "SA1100 flash: no partition info "
394                         "available, registering whole flash\n");
395                 add_mtd_device(info->mtd);
396         } else {
397                 printk(KERN_NOTICE "SA1100 flash: using %s partition "
398                         "definition\n", part_type);
399                 add_mtd_partitions(info->mtd, parts, nr_parts);
400         }
401
402         info->nr_parts = nr_parts;
403
404         platform_set_drvdata(pdev, info);
405         err = 0;
406
407  out:
408         return err;
409 }
410
411 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
412 {
413         struct sa_info *info = platform_get_drvdata(pdev);
414         struct flash_platform_data *plat = pdev->dev.platform_data;
415
416         platform_set_drvdata(pdev, NULL);
417         sa1100_destroy(info, plat);
418
419         return 0;
420 }
421
422 #ifdef CONFIG_PM
423 static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
424 {
425         struct sa_info *info = platform_get_drvdata(dev);
426         int ret = 0;
427
428         if (info)
429                 ret = info->mtd->suspend(info->mtd);
430
431         return ret;
432 }
433
434 static int sa1100_mtd_resume(struct platform_device *dev)
435 {
436         struct sa_info *info = platform_get_drvdata(dev);
437         if (info)
438                 info->mtd->resume(info->mtd);
439         return 0;
440 }
441
442 static void sa1100_mtd_shutdown(struct platform_device *dev)
443 {
444         struct sa_info *info = platform_get_drvdata(dev);
445         if (info && info->mtd->suspend(info->mtd) == 0)
446                 info->mtd->resume(info->mtd);
447 }
448 #else
449 #define sa1100_mtd_suspend NULL
450 #define sa1100_mtd_resume  NULL
451 #define sa1100_mtd_shutdown NULL
452 #endif
453
454 static struct platform_driver sa1100_mtd_driver = {
455         .probe          = sa1100_mtd_probe,
456         .remove         = __exit_p(sa1100_mtd_remove),
457         .suspend        = sa1100_mtd_suspend,
458         .resume         = sa1100_mtd_resume,
459         .shutdown       = sa1100_mtd_shutdown,
460         .driver         = {
461                 .name   = "flash",
462         },
463 };
464
465 static int __init sa1100_mtd_init(void)
466 {
467         return platform_driver_register(&sa1100_mtd_driver);
468 }
469
470 static void __exit sa1100_mtd_exit(void)
471 {
472         platform_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");