Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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