[MTD] replace kmalloc+memset with kzalloc
[deliverable/linux.git] / drivers / mtd / maps / sa1100-flash.c
CommitLineData
1da177e4
LT
1/*
2 * Flash memory access on SA11x0 based devices
69f34c98 3 *
1da177e4 4 * (C) 2000 Nicolas Pitre <nico@cam.org>
69f34c98
TG
5 *
6 * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $
1da177e4 7 */
1da177e4
LT
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>
d052d1be 15#include <linux/platform_device.h>
1da177e4
LT
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
674c0453 23#include <asm/hardware.h>
1da177e4
LT
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 */
33static 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: */
69static 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
98static 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
111static 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
128struct sa_subdev_info {
129 char name[16];
130 struct map_info map;
131 struct mtd_info *mtd;
57725f0a 132 struct flash_platform_data *plat;
1da177e4
LT
133};
134
135struct sa_info {
136 struct mtd_partition *parts;
137 struct mtd_info *mtd;
138 int num_subdev;
822e5e72 139 unsigned int nr_parts;
1da177e4
LT
140 struct sa_subdev_info subdev[0];
141};
142
143static 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);
57725f0a 146 subdev->plat->set_vpp(on);
1da177e4
LT
147}
148
149static 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
158static 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
57725f0a 190 if (subdev->plat->set_vpp)
1da177e4
LT
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 */
57725f0a 207 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
1da177e4
LT
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
0d2ef7d7 226static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
1da177e4
LT
227{
228 int i;
229
230 if (info->mtd) {
822e5e72
RK
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
1da177e4
LT
237#ifdef CONFIG_MTD_CONCAT
238 if (info->mtd != info->subdev[0].mtd)
239 mtd_concat_destroy(info->mtd);
240#endif
241 }
242
fa671646 243 kfree(info->parts);
1da177e4
LT
244
245 for (i = info->num_subdev - 1; i >= 0; i--)
246 sa1100_destroy_subdev(&info->subdev[i]);
247 kfree(info);
0d2ef7d7
RK
248
249 if (plat->exit)
250 plat->exit();
1da177e4
LT
251}
252
253static struct sa_info *__init
57725f0a 254sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
1da177e4
LT
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 */
95b93a0c 276 info = kzalloc(size, GFP_KERNEL);
1da177e4
LT
277 if (!info) {
278 ret = -ENOMEM;
279 goto out;
280 }
281
0d2ef7d7
RK
282 if (plat->init) {
283 ret = plat->init();
284 if (ret)
285 goto err;
286 }
287
1da177e4
LT
288 /*
289 * Claim and then map the memory regions.
290 */
291 for (i = 0; i < nr; i++) {
292 struct sa_subdev_info *subdev = &info->subdev[i];
293 struct resource *res;
294
295 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
296 if (!res)
297 break;
298
299 subdev->map.name = subdev->name;
14e66f76 300 sprintf(subdev->name, "%s-%d", plat->name, i);
57725f0a 301 subdev->plat = plat;
1da177e4
LT
302
303 ret = sa1100_probe_subdev(subdev, res);
304 if (ret)
305 break;
306 }
307
308 info->num_subdev = i;
309
310 /*
311 * ENXIO is special. It means we didn't find a chip when we probed.
312 */
313 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
314 goto err;
315
316 /*
317 * If we found one device, don't bother with concat support. If
318 * we found multiple devices, use concat if we have it available,
319 * otherwise fail. Either way, it'll be called "sa1100".
320 */
321 if (info->num_subdev == 1) {
14e66f76 322 strcpy(info->subdev[0].name, plat->name);
1da177e4
LT
323 info->mtd = info->subdev[0].mtd;
324 ret = 0;
325 } else if (info->num_subdev > 1) {
326#ifdef CONFIG_MTD_CONCAT
327 struct mtd_info *cdev[nr];
328 /*
329 * We detected multiple devices. Concatenate them together.
330 */
331 for (i = 0; i < info->num_subdev; i++)
332 cdev[i] = info->subdev[i].mtd;
333
334 info->mtd = mtd_concat_create(cdev, info->num_subdev,
14e66f76 335 plat->name);
1da177e4
LT
336 if (info->mtd == NULL)
337 ret = -ENXIO;
338#else
339 printk(KERN_ERR "SA1100 flash: multiple devices "
340 "found but MTD concat support disabled.\n");
341 ret = -ENXIO;
342#endif
343 }
344
345 if (ret == 0)
346 return info;
347
348 err:
0d2ef7d7 349 sa1100_destroy(info, plat);
1da177e4
LT
350 out:
351 return ERR_PTR(ret);
352}
353
354static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
355
3ae5eaec 356static int __init sa1100_mtd_probe(struct platform_device *pdev)
1da177e4 357{
57725f0a 358 struct flash_platform_data *plat = pdev->dev.platform_data;
1da177e4
LT
359 struct mtd_partition *parts;
360 const char *part_type = NULL;
361 struct sa_info *info;
362 int err, nr_parts = 0;
363
57725f0a 364 if (!plat)
1da177e4
LT
365 return -ENODEV;
366
57725f0a 367 info = sa1100_setup_mtd(pdev, plat);
1da177e4
LT
368 if (IS_ERR(info)) {
369 err = PTR_ERR(info);
370 goto out;
371 }
372
373 /*
374 * Partition selection stuff.
375 */
376#ifdef CONFIG_MTD_PARTITIONS
377 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
378 if (nr_parts > 0) {
379 info->parts = parts;
380 part_type = "dynamic";
381 } else
382#endif
383 {
57725f0a
RK
384 parts = plat->parts;
385 nr_parts = plat->nr_parts;
1da177e4
LT
386 part_type = "static";
387 }
388
389 if (nr_parts == 0) {
390 printk(KERN_NOTICE "SA1100 flash: no partition info "
391 "available, registering whole flash\n");
392 add_mtd_device(info->mtd);
393 } else {
394 printk(KERN_NOTICE "SA1100 flash: using %s partition "
395 "definition\n", part_type);
396 add_mtd_partitions(info->mtd, parts, nr_parts);
397 }
398
822e5e72
RK
399 info->nr_parts = nr_parts;
400
3ae5eaec 401 platform_set_drvdata(pdev, info);
1da177e4
LT
402 err = 0;
403
404 out:
405 return err;
406}
407
3ae5eaec 408static int __exit sa1100_mtd_remove(struct platform_device *pdev)
1da177e4 409{
3ae5eaec
RK
410 struct sa_info *info = platform_get_drvdata(pdev);
411 struct flash_platform_data *plat = pdev->dev.platform_data;
0d2ef7d7 412
3ae5eaec 413 platform_set_drvdata(pdev, NULL);
0d2ef7d7
RK
414 sa1100_destroy(info, plat);
415
1da177e4
LT
416 return 0;
417}
418
419#ifdef CONFIG_PM
3ae5eaec 420static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
1da177e4 421{
3ae5eaec 422 struct sa_info *info = platform_get_drvdata(dev);
1da177e4
LT
423 int ret = 0;
424
9480e307 425 if (info)
1da177e4
LT
426 ret = info->mtd->suspend(info->mtd);
427
428 return ret;
429}
430
3ae5eaec 431static int sa1100_mtd_resume(struct platform_device *dev)
1da177e4 432{
3ae5eaec 433 struct sa_info *info = platform_get_drvdata(dev);
9480e307 434 if (info)
1da177e4
LT
435 info->mtd->resume(info->mtd);
436 return 0;
437}
13bfb34c 438
3ae5eaec 439static void sa1100_mtd_shutdown(struct platform_device *dev)
13bfb34c 440{
3ae5eaec 441 struct sa_info *info = platform_get_drvdata(dev);
13bfb34c
RK
442 if (info && info->mtd->suspend(info->mtd) == 0)
443 info->mtd->resume(info->mtd);
444}
1da177e4
LT
445#else
446#define sa1100_mtd_suspend NULL
447#define sa1100_mtd_resume NULL
13bfb34c 448#define sa1100_mtd_shutdown NULL
1da177e4
LT
449#endif
450
3ae5eaec 451static struct platform_driver sa1100_mtd_driver = {
1da177e4
LT
452 .probe = sa1100_mtd_probe,
453 .remove = __exit_p(sa1100_mtd_remove),
454 .suspend = sa1100_mtd_suspend,
455 .resume = sa1100_mtd_resume,
13bfb34c 456 .shutdown = sa1100_mtd_shutdown,
3ae5eaec
RK
457 .driver = {
458 .name = "flash",
459 },
1da177e4
LT
460};
461
462static int __init sa1100_mtd_init(void)
463{
3ae5eaec 464 return platform_driver_register(&sa1100_mtd_driver);
1da177e4
LT
465}
466
467static void __exit sa1100_mtd_exit(void)
468{
3ae5eaec 469 platform_driver_unregister(&sa1100_mtd_driver);
1da177e4
LT
470}
471
472module_init(sa1100_mtd_init);
473module_exit(sa1100_mtd_exit);
474
475MODULE_AUTHOR("Nicolas Pitre");
476MODULE_DESCRIPTION("SA1100 CFI map driver");
477MODULE_LICENSE("GPL");
This page took 0.273872 seconds and 5 git commands to generate.