]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/mtd/maps/sa1100-flash.c
Merge iSeries include file move
[karo-tx-linux.git] / 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.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
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         if (info->parts)
245                 kfree(info->parts);
246
247         for (i = info->num_subdev - 1; i >= 0; i--)
248                 sa1100_destroy_subdev(&info->subdev[i]);
249         kfree(info);
250
251         if (plat->exit)
252                 plat->exit();
253 }
254
255 static struct sa_info *__init
256 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
257 {
258         struct sa_info *info;
259         int nr, size, i, ret = 0;
260
261         /*
262          * Count number of devices.
263          */
264         for (nr = 0; ; nr++)
265                 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
266                         break;
267
268         if (nr == 0) {
269                 ret = -ENODEV;
270                 goto out;
271         }
272
273         size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
274
275         /*
276          * Allocate the map_info structs in one go.
277          */
278         info = kmalloc(size, GFP_KERNEL);
279         if (!info) {
280                 ret = -ENOMEM;
281                 goto out;
282         }
283
284         memset(info, 0, size);
285
286         if (plat->init) {
287                 ret = plat->init();
288                 if (ret)
289                         goto err;
290         }
291
292         /*
293          * Claim and then map the memory regions.
294          */
295         for (i = 0; i < nr; i++) {
296                 struct sa_subdev_info *subdev = &info->subdev[i];
297                 struct resource *res;
298
299                 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
300                 if (!res)
301                         break;
302
303                 subdev->map.name = subdev->name;
304                 sprintf(subdev->name, "%s-%d", plat->name, i);
305                 subdev->plat = plat;
306
307                 ret = sa1100_probe_subdev(subdev, res);
308                 if (ret)
309                         break;
310         }
311
312         info->num_subdev = i;
313
314         /*
315          * ENXIO is special.  It means we didn't find a chip when we probed.
316          */
317         if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
318                 goto err;
319
320         /*
321          * If we found one device, don't bother with concat support.  If
322          * we found multiple devices, use concat if we have it available,
323          * otherwise fail.  Either way, it'll be called "sa1100".
324          */
325         if (info->num_subdev == 1) {
326                 strcpy(info->subdev[0].name, plat->name);
327                 info->mtd = info->subdev[0].mtd;
328                 ret = 0;
329         } else if (info->num_subdev > 1) {
330 #ifdef CONFIG_MTD_CONCAT
331                 struct mtd_info *cdev[nr];
332                 /*
333                  * We detected multiple devices.  Concatenate them together.
334                  */
335                 for (i = 0; i < info->num_subdev; i++)
336                         cdev[i] = info->subdev[i].mtd;
337
338                 info->mtd = mtd_concat_create(cdev, info->num_subdev,
339                                               plat->name);
340                 if (info->mtd == NULL)
341                         ret = -ENXIO;
342 #else
343                 printk(KERN_ERR "SA1100 flash: multiple devices "
344                        "found but MTD concat support disabled.\n");
345                 ret = -ENXIO;
346 #endif
347         }
348
349         if (ret == 0)
350                 return info;
351
352  err:
353         sa1100_destroy(info, plat);
354  out:
355         return ERR_PTR(ret);
356 }
357
358 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
359
360 static int __init sa1100_mtd_probe(struct device *dev)
361 {
362         struct platform_device *pdev = to_platform_device(dev);
363         struct flash_platform_data *plat = pdev->dev.platform_data;
364         struct mtd_partition *parts;
365         const char *part_type = NULL;
366         struct sa_info *info;
367         int err, nr_parts = 0;
368
369         if (!plat)
370                 return -ENODEV;
371
372         info = sa1100_setup_mtd(pdev, plat);
373         if (IS_ERR(info)) {
374                 err = PTR_ERR(info);
375                 goto out;
376         }
377
378         /*
379          * Partition selection stuff.
380          */
381 #ifdef CONFIG_MTD_PARTITIONS
382         nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
383         if (nr_parts > 0) {
384                 info->parts = parts;
385                 part_type = "dynamic";
386         } else
387 #endif
388         {
389                 parts = plat->parts;
390                 nr_parts = plat->nr_parts;
391                 part_type = "static";
392         }
393
394         if (nr_parts == 0) {
395                 printk(KERN_NOTICE "SA1100 flash: no partition info "
396                         "available, registering whole flash\n");
397                 add_mtd_device(info->mtd);
398         } else {
399                 printk(KERN_NOTICE "SA1100 flash: using %s partition "
400                         "definition\n", part_type);
401                 add_mtd_partitions(info->mtd, parts, nr_parts);
402         }
403
404         info->nr_parts = nr_parts;
405
406         dev_set_drvdata(dev, info);
407         err = 0;
408
409  out:
410         return err;
411 }
412
413 static int __exit sa1100_mtd_remove(struct device *dev)
414 {
415         struct sa_info *info = dev_get_drvdata(dev);
416         struct flash_platform_data *plat = dev->platform_data;
417
418         dev_set_drvdata(dev, NULL);
419         sa1100_destroy(info, plat);
420
421         return 0;
422 }
423
424 #ifdef CONFIG_PM
425 static int sa1100_mtd_suspend(struct device *dev, pm_message_t state)
426 {
427         struct sa_info *info = dev_get_drvdata(dev);
428         int ret = 0;
429
430         if (info)
431                 ret = info->mtd->suspend(info->mtd);
432
433         return ret;
434 }
435
436 static int sa1100_mtd_resume(struct device *dev)
437 {
438         struct sa_info *info = dev_get_drvdata(dev);
439         if (info)
440                 info->mtd->resume(info->mtd);
441         return 0;
442 }
443
444 static void sa1100_mtd_shutdown(struct device *dev)
445 {
446         struct sa_info *info = dev_get_drvdata(dev);
447         if (info && info->mtd->suspend(info->mtd) == 0)
448                 info->mtd->resume(info->mtd);
449 }
450 #else
451 #define sa1100_mtd_suspend NULL
452 #define sa1100_mtd_resume  NULL
453 #define sa1100_mtd_shutdown NULL
454 #endif
455
456 static struct device_driver sa1100_mtd_driver = {
457         .name           = "flash",
458         .bus            = &platform_bus_type,
459         .probe          = sa1100_mtd_probe,
460         .remove         = __exit_p(sa1100_mtd_remove),
461         .suspend        = sa1100_mtd_suspend,
462         .resume         = sa1100_mtd_resume,
463         .shutdown       = sa1100_mtd_shutdown,
464 };
465
466 static int __init sa1100_mtd_init(void)
467 {
468         return driver_register(&sa1100_mtd_driver);
469 }
470
471 static void __exit sa1100_mtd_exit(void)
472 {
473         driver_unregister(&sa1100_mtd_driver);
474 }
475
476 module_init(sa1100_mtd_init);
477 module_exit(sa1100_mtd_exit);
478
479 MODULE_AUTHOR("Nicolas Pitre");
480 MODULE_DESCRIPTION("SA1100 CFI map driver");
481 MODULE_LICENSE("GPL");