Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[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/module.h>
9 #include <linux/types.h>
10 #include <linux/ioport.h>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/errno.h>
14 #include <linux/slab.h>
15 #include <linux/platform_device.h>
16 #include <linux/err.h>
17
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/map.h>
20 #include <linux/mtd/partitions.h>
21 #include <linux/mtd/concat.h>
22
23 #include <asm/hardware.h>
24 #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  */
33 static 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: */
69 static 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
98 static 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
111 static 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
128 struct sa_subdev_info {
129         char name[16];
130         struct map_info map;
131         struct mtd_info *mtd;
132         struct flash_platform_data *plat;
133 };
134
135 struct sa_info {
136         struct mtd_partition    *parts;
137         struct mtd_info         *mtd;
138         int                     num_subdev;
139         unsigned int            nr_parts;
140         struct sa_subdev_info   subdev[0];
141 };
142
143 static void sa1100_set_vpp(struct map_info *map, int on)
144 {
145         struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
146         subdev->plat->set_vpp(on);
147 }
148
149 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
150 {
151         if (subdev->mtd)
152                 map_destroy(subdev->mtd);
153         if (subdev->map.virt)
154                 iounmap(subdev->map.virt);
155         release_mem_region(subdev->map.phys, subdev->map.size);
156 }
157
158 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
159 {
160         unsigned long phys;
161         unsigned int size;
162         int ret;
163
164         phys = res->start;
165         size = res->end - phys + 1;
166
167         /*
168          * Retrieve the bankwidth from the MSC registers.
169          * We currently only implement CS0 and CS1 here.
170          */
171         switch (phys) {
172         default:
173                 printk(KERN_WARNING "SA1100 flash: unknown base address "
174                        "0x%08lx, assuming CS0\n", phys);
175
176         case SA1100_CS0_PHYS:
177                 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
178                 break;
179
180         case SA1100_CS1_PHYS:
181                 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
182                 break;
183         }
184
185         if (!request_mem_region(phys, size, subdev->name)) {
186                 ret = -EBUSY;
187                 goto out;
188         }
189
190         if (subdev->plat->set_vpp)
191                 subdev->map.set_vpp = sa1100_set_vpp;
192
193         subdev->map.phys = phys;
194         subdev->map.size = size;
195         subdev->map.virt = ioremap(phys, size);
196         if (!subdev->map.virt) {
197                 ret = -ENOMEM;
198                 goto err;
199         }
200
201         simple_map_init(&subdev->map);
202
203         /*
204          * Now let's probe for the actual flash.  Do it here since
205          * specific machine settings might have been set above.
206          */
207         subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
208         if (subdev->mtd == NULL) {
209                 ret = -ENXIO;
210                 goto err;
211         }
212         subdev->mtd->owner = THIS_MODULE;
213
214         printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
215                 "%d-bit\n", phys, subdev->mtd->size >> 20,
216                 subdev->map.bankwidth * 8);
217
218         return 0;
219
220  err:
221         sa1100_destroy_subdev(subdev);
222  out:
223         return ret;
224 }
225
226 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
227 {
228         int i;
229
230         if (info->mtd) {
231                 if (info->nr_parts == 0)
232                         del_mtd_device(info->mtd);
233 #ifdef CONFIG_MTD_PARTITIONS
234                 else
235                         del_mtd_partitions(info->mtd);
236 #endif
237 #ifdef CONFIG_MTD_CONCAT
238                 if (info->mtd != info->subdev[0].mtd)
239                         mtd_concat_destroy(info->mtd);
240 #endif
241         }
242
243         kfree(info->parts);
244
245         for (i = info->num_subdev - 1; i >= 0; i--)
246                 sa1100_destroy_subdev(&info->subdev[i]);
247         kfree(info);
248
249         if (plat->exit)
250                 plat->exit();
251 }
252
253 static struct sa_info *__init
254 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
255 {
256         struct sa_info *info;
257         int nr, size, i, ret = 0;
258
259         /*
260          * Count number of devices.
261          */
262         for (nr = 0; ; nr++)
263                 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
264                         break;
265
266         if (nr == 0) {
267                 ret = -ENODEV;
268                 goto out;
269         }
270
271         size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
272
273         /*
274          * Allocate the map_info structs in one go.
275          */
276         info = kmalloc(size, GFP_KERNEL);
277         if (!info) {
278                 ret = -ENOMEM;
279                 goto out;
280         }
281
282         memset(info, 0, size);
283
284         if (plat->init) {
285                 ret = plat->init();
286                 if (ret)
287                         goto err;
288         }
289
290         /*
291          * Claim and then map the memory regions.
292          */
293         for (i = 0; i < nr; i++) {
294                 struct sa_subdev_info *subdev = &info->subdev[i];
295                 struct resource *res;
296
297                 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
298                 if (!res)
299                         break;
300
301                 subdev->map.name = subdev->name;
302                 sprintf(subdev->name, "%s-%d", plat->name, i);
303                 subdev->plat = plat;
304
305                 ret = sa1100_probe_subdev(subdev, res);
306                 if (ret)
307                         break;
308         }
309
310         info->num_subdev = i;
311
312         /*
313          * ENXIO is special.  It means we didn't find a chip when we probed.
314          */
315         if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
316                 goto err;
317
318         /*
319          * If we found one device, don't bother with concat support.  If
320          * we found multiple devices, use concat if we have it available,
321          * otherwise fail.  Either way, it'll be called "sa1100".
322          */
323         if (info->num_subdev == 1) {
324                 strcpy(info->subdev[0].name, plat->name);
325                 info->mtd = info->subdev[0].mtd;
326                 ret = 0;
327         } else if (info->num_subdev > 1) {
328 #ifdef CONFIG_MTD_CONCAT
329                 struct mtd_info *cdev[nr];
330                 /*
331                  * We detected multiple devices.  Concatenate them together.
332                  */
333                 for (i = 0; i < info->num_subdev; i++)
334                         cdev[i] = info->subdev[i].mtd;
335
336                 info->mtd = mtd_concat_create(cdev, info->num_subdev,
337                                               plat->name);
338                 if (info->mtd == NULL)
339                         ret = -ENXIO;
340 #else
341                 printk(KERN_ERR "SA1100 flash: multiple devices "
342                        "found but MTD concat support disabled.\n");
343                 ret = -ENXIO;
344 #endif
345         }
346
347         if (ret == 0)
348                 return info;
349
350  err:
351         sa1100_destroy(info, plat);
352  out:
353         return ERR_PTR(ret);
354 }
355
356 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
357
358 static int __init sa1100_mtd_probe(struct platform_device *pdev)
359 {
360         struct flash_platform_data *plat = pdev->dev.platform_data;
361         struct mtd_partition *parts;
362         const char *part_type = NULL;
363         struct sa_info *info;
364         int err, nr_parts = 0;
365
366         if (!plat)
367                 return -ENODEV;
368
369         info = sa1100_setup_mtd(pdev, plat);
370         if (IS_ERR(info)) {
371                 err = PTR_ERR(info);
372                 goto out;
373         }
374
375         /*
376          * Partition selection stuff.
377          */
378 #ifdef CONFIG_MTD_PARTITIONS
379         nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
380         if (nr_parts > 0) {
381                 info->parts = parts;
382                 part_type = "dynamic";
383         } else
384 #endif
385         {
386                 parts = plat->parts;
387                 nr_parts = plat->nr_parts;
388                 part_type = "static";
389         }
390
391         if (nr_parts == 0) {
392                 printk(KERN_NOTICE "SA1100 flash: no partition info "
393                         "available, registering whole flash\n");
394                 add_mtd_device(info->mtd);
395         } else {
396                 printk(KERN_NOTICE "SA1100 flash: using %s partition "
397                         "definition\n", part_type);
398                 add_mtd_partitions(info->mtd, parts, nr_parts);
399         }
400
401         info->nr_parts = nr_parts;
402
403         platform_set_drvdata(pdev, info);
404         err = 0;
405
406  out:
407         return err;
408 }
409
410 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
411 {
412         struct sa_info *info = platform_get_drvdata(pdev);
413         struct flash_platform_data *plat = pdev->dev.platform_data;
414
415         platform_set_drvdata(pdev, NULL);
416         sa1100_destroy(info, plat);
417
418         return 0;
419 }
420
421 #ifdef CONFIG_PM
422 static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
423 {
424         struct sa_info *info = platform_get_drvdata(dev);
425         int ret = 0;
426
427         if (info)
428                 ret = info->mtd->suspend(info->mtd);
429
430         return ret;
431 }
432
433 static int sa1100_mtd_resume(struct platform_device *dev)
434 {
435         struct sa_info *info = platform_get_drvdata(dev);
436         if (info)
437                 info->mtd->resume(info->mtd);
438         return 0;
439 }
440
441 static void sa1100_mtd_shutdown(struct platform_device *dev)
442 {
443         struct sa_info *info = platform_get_drvdata(dev);
444         if (info && info->mtd->suspend(info->mtd) == 0)
445                 info->mtd->resume(info->mtd);
446 }
447 #else
448 #define sa1100_mtd_suspend NULL
449 #define sa1100_mtd_resume  NULL
450 #define sa1100_mtd_shutdown NULL
451 #endif
452
453 static struct platform_driver sa1100_mtd_driver = {
454         .probe          = sa1100_mtd_probe,
455         .remove         = __exit_p(sa1100_mtd_remove),
456         .suspend        = sa1100_mtd_suspend,
457         .resume         = sa1100_mtd_resume,
458         .shutdown       = sa1100_mtd_shutdown,
459         .driver         = {
460                 .name   = "flash",
461         },
462 };
463
464 static int __init sa1100_mtd_init(void)
465 {
466         return platform_driver_register(&sa1100_mtd_driver);
467 }
468
469 static void __exit sa1100_mtd_exit(void)
470 {
471         platform_driver_unregister(&sa1100_mtd_driver);
472 }
473
474 module_init(sa1100_mtd_init);
475 module_exit(sa1100_mtd_exit);
476
477 MODULE_AUTHOR("Nicolas Pitre");
478 MODULE_DESCRIPTION("SA1100 CFI map driver");
479 MODULE_LICENSE("GPL");