Pull hp-machvec into release branch
[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.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/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 *data;
133 };
134
135 struct 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
142 static 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
148 static 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
157 static 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
225 static 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
246 static struct sa_info *__init
247 sa1100_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
343 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
344
345 static 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
396 static 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
405 static int sa1100_mtd_suspend(struct device *dev, pm_message_t state, u32 level)
406 {
407         struct sa_info *info = dev_get_drvdata(dev);
408         int ret = 0;
409
410         if (info && level == SUSPEND_SAVE_STATE)
411                 ret = info->mtd->suspend(info->mtd);
412
413         return ret;
414 }
415
416 static int sa1100_mtd_resume(struct device *dev, u32 level)
417 {
418         struct sa_info *info = dev_get_drvdata(dev);
419         if (info && level == RESUME_RESTORE_STATE)
420                 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
428 static 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
437 static int __init sa1100_mtd_init(void)
438 {
439         return driver_register(&sa1100_mtd_driver);
440 }
441
442 static void __exit sa1100_mtd_exit(void)
443 {
444         driver_unregister(&sa1100_mtd_driver);
445 }
446
447 module_init(sa1100_mtd_init);
448 module_exit(sa1100_mtd_exit);
449
450 MODULE_AUTHOR("Nicolas Pitre");
451 MODULE_DESCRIPTION("SA1100 CFI map driver");
452 MODULE_LICENSE("GPL");