mtd: rbtx4939-flash.c: use mtd_device_parse_register
[deliverable/linux.git] / drivers / mtd / maps / sa1100-flash.c
CommitLineData
1da177e4
LT
1/*
2 * Flash memory access on SA11x0 based devices
69f34c98 3 *
2f82af08 4 * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
1da177e4 5 */
1da177e4
LT
6#include <linux/module.h>
7#include <linux/types.h>
8#include <linux/ioport.h>
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/errno.h>
12#include <linux/slab.h>
d052d1be 13#include <linux/platform_device.h>
1da177e4 14#include <linux/err.h>
99730225 15#include <linux/io.h>
1da177e4
LT
16
17#include <linux/mtd/mtd.h>
18#include <linux/mtd/map.h>
19#include <linux/mtd/partitions.h>
20#include <linux/mtd/concat.h>
21
a09e64fb 22#include <mach/hardware.h>
1da177e4
LT
23#include <asm/sizes.h>
24#include <asm/mach/flash.h>
25
26#if 0
27/*
28 * This is here for documentation purposes only - until these people
29 * submit their machine types. It will be gone January 2005.
30 */
31static struct mtd_partition consus_partitions[] = {
32 {
33 .name = "Consus boot firmware",
34 .offset = 0,
35 .size = 0x00040000,
36 .mask_flags = MTD_WRITABLE, /* force read-only */
37 }, {
38 .name = "Consus kernel",
39 .offset = 0x00040000,
40 .size = 0x00100000,
41 .mask_flags = 0,
42 }, {
43 .name = "Consus disk",
44 .offset = 0x00140000,
45 /* The rest (up to 16M) for jffs. We could put 0 and
46 make it find the size automatically, but right now
47 i have 32 megs. jffs will use all 32 megs if given
48 the chance, and this leads to horrible problems
49 when you try to re-flash the image because blob
50 won't erase the whole partition. */
51 .size = 0x01000000 - 0x00140000,
52 .mask_flags = 0,
53 }, {
54 /* this disk is a secondary disk, which can be used as
55 needed, for simplicity, make it the size of the other
56 consus partition, although realistically it could be
57 the remainder of the disk (depending on the file
58 system used) */
59 .name = "Consus disk2",
60 .offset = 0x01000000,
61 .size = 0x01000000 - 0x00140000,
62 .mask_flags = 0,
63 }
64};
65
66/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
67static struct mtd_partition frodo_partitions[] =
68{
69 {
70 .name = "bootloader",
71 .size = 0x00040000,
72 .offset = 0x00000000,
73 .mask_flags = MTD_WRITEABLE
74 }, {
75 .name = "bootloader params",
76 .size = 0x00040000,
77 .offset = MTDPART_OFS_APPEND,
78 .mask_flags = MTD_WRITEABLE
79 }, {
80 .name = "kernel",
81 .size = 0x00100000,
82 .offset = MTDPART_OFS_APPEND,
83 .mask_flags = MTD_WRITEABLE
84 }, {
85 .name = "ramdisk",
86 .size = 0x00400000,
87 .offset = MTDPART_OFS_APPEND,
88 .mask_flags = MTD_WRITEABLE
89 }, {
90 .name = "file system",
91 .size = MTDPART_SIZ_FULL,
92 .offset = MTDPART_OFS_APPEND
93 }
94};
95
96static struct mtd_partition jornada56x_partitions[] = {
97 {
98 .name = "bootldr",
99 .size = 0x00040000,
100 .offset = 0,
101 .mask_flags = MTD_WRITEABLE,
102 }, {
103 .name = "rootfs",
104 .size = MTDPART_SIZ_FULL,
105 .offset = MTDPART_OFS_APPEND,
106 }
107};
108
109static void jornada56x_set_vpp(int vpp)
110{
111 if (vpp)
112 GPSR = GPIO_GPIO26;
113 else
114 GPCR = GPIO_GPIO26;
115 GPDR |= GPIO_GPIO26;
116}
117
118/*
119 * Machine Phys Size set_vpp
120 * Consus : SA1100_CS0_PHYS SZ_32M
121 * Frodo : SA1100_CS0_PHYS SZ_32M
122 * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
123 */
124#endif
125
126struct sa_subdev_info {
127 char name[16];
128 struct map_info map;
129 struct mtd_info *mtd;
57725f0a 130 struct flash_platform_data *plat;
1da177e4
LT
131};
132
133struct sa_info {
134 struct mtd_partition *parts;
135 struct mtd_info *mtd;
136 int num_subdev;
822e5e72 137 unsigned int nr_parts;
1da177e4
LT
138 struct sa_subdev_info subdev[0];
139};
140
141static void sa1100_set_vpp(struct map_info *map, int on)
142{
143 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
57725f0a 144 subdev->plat->set_vpp(on);
1da177e4
LT
145}
146
147static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
148{
149 if (subdev->mtd)
150 map_destroy(subdev->mtd);
151 if (subdev->map.virt)
152 iounmap(subdev->map.virt);
153 release_mem_region(subdev->map.phys, subdev->map.size);
154}
155
156static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
157{
158 unsigned long phys;
159 unsigned int size;
160 int ret;
161
162 phys = res->start;
163 size = res->end - phys + 1;
164
165 /*
166 * Retrieve the bankwidth from the MSC registers.
167 * We currently only implement CS0 and CS1 here.
168 */
169 switch (phys) {
170 default:
171 printk(KERN_WARNING "SA1100 flash: unknown base address "
172 "0x%08lx, assuming CS0\n", phys);
173
174 case SA1100_CS0_PHYS:
175 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
176 break;
177
178 case SA1100_CS1_PHYS:
179 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
180 break;
181 }
182
183 if (!request_mem_region(phys, size, subdev->name)) {
184 ret = -EBUSY;
185 goto out;
186 }
187
57725f0a 188 if (subdev->plat->set_vpp)
1da177e4
LT
189 subdev->map.set_vpp = sa1100_set_vpp;
190
191 subdev->map.phys = phys;
192 subdev->map.size = size;
193 subdev->map.virt = ioremap(phys, size);
194 if (!subdev->map.virt) {
195 ret = -ENOMEM;
196 goto err;
197 }
198
199 simple_map_init(&subdev->map);
200
201 /*
202 * Now let's probe for the actual flash. Do it here since
203 * specific machine settings might have been set above.
204 */
57725f0a 205 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
1da177e4
LT
206 if (subdev->mtd == NULL) {
207 ret = -ENXIO;
208 goto err;
209 }
210 subdev->mtd->owner = THIS_MODULE;
211
794d579a
RK
212 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %uMiB, %d-bit\n",
213 phys, (unsigned)(subdev->mtd->size >> 20),
1da177e4
LT
214 subdev->map.bankwidth * 8);
215
216 return 0;
217
218 err:
219 sa1100_destroy_subdev(subdev);
220 out:
221 return ret;
222}
223
0d2ef7d7 224static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
1da177e4
LT
225{
226 int i;
227
228 if (info->mtd) {
2fe2e24e 229 mtd_device_unregister(info->mtd);
1da177e4
LT
230 if (info->mtd != info->subdev[0].mtd)
231 mtd_concat_destroy(info->mtd);
1da177e4
LT
232 }
233
fa671646 234 kfree(info->parts);
1da177e4
LT
235
236 for (i = info->num_subdev - 1; i >= 0; i--)
237 sa1100_destroy_subdev(&info->subdev[i]);
238 kfree(info);
0d2ef7d7
RK
239
240 if (plat->exit)
241 plat->exit();
1da177e4
LT
242}
243
5a134239 244static struct sa_info *__devinit
57725f0a 245sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
1da177e4
LT
246{
247 struct sa_info *info;
248 int nr, size, i, ret = 0;
249
250 /*
251 * Count number of devices.
252 */
253 for (nr = 0; ; nr++)
254 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
255 break;
256
257 if (nr == 0) {
258 ret = -ENODEV;
259 goto out;
260 }
261
262 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
263
264 /*
265 * Allocate the map_info structs in one go.
266 */
95b93a0c 267 info = kzalloc(size, GFP_KERNEL);
1da177e4
LT
268 if (!info) {
269 ret = -ENOMEM;
270 goto out;
271 }
272
0d2ef7d7
RK
273 if (plat->init) {
274 ret = plat->init();
275 if (ret)
276 goto err;
277 }
278
1da177e4
LT
279 /*
280 * Claim and then map the memory regions.
281 */
282 for (i = 0; i < nr; i++) {
283 struct sa_subdev_info *subdev = &info->subdev[i];
284 struct resource *res;
285
286 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
287 if (!res)
288 break;
289
290 subdev->map.name = subdev->name;
14e66f76 291 sprintf(subdev->name, "%s-%d", plat->name, i);
57725f0a 292 subdev->plat = plat;
1da177e4
LT
293
294 ret = sa1100_probe_subdev(subdev, res);
295 if (ret)
296 break;
297 }
298
299 info->num_subdev = i;
300
301 /*
302 * ENXIO is special. It means we didn't find a chip when we probed.
303 */
304 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
305 goto err;
306
307 /*
308 * If we found one device, don't bother with concat support. If
309 * we found multiple devices, use concat if we have it available,
310 * otherwise fail. Either way, it'll be called "sa1100".
311 */
312 if (info->num_subdev == 1) {
14e66f76 313 strcpy(info->subdev[0].name, plat->name);
1da177e4
LT
314 info->mtd = info->subdev[0].mtd;
315 ret = 0;
316 } else if (info->num_subdev > 1) {
1da177e4
LT
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,
14e66f76 325 plat->name);
1da177e4
LT
326 if (info->mtd == NULL)
327 ret = -ENXIO;
1da177e4
LT
328 }
329
330 if (ret == 0)
331 return info;
332
333 err:
0d2ef7d7 334 sa1100_destroy(info, plat);
1da177e4
LT
335 out:
336 return ERR_PTR(ret);
337}
338
339static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
340
f0b1e589 341static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
1da177e4 342{
57725f0a 343 struct flash_platform_data *plat = pdev->dev.platform_data;
1da177e4
LT
344 struct mtd_partition *parts;
345 const char *part_type = NULL;
346 struct sa_info *info;
347 int err, nr_parts = 0;
348
57725f0a 349 if (!plat)
1da177e4
LT
350 return -ENODEV;
351
57725f0a 352 info = sa1100_setup_mtd(pdev, plat);
1da177e4
LT
353 if (IS_ERR(info)) {
354 err = PTR_ERR(info);
355 goto out;
356 }
357
358 /*
359 * Partition selection stuff.
360 */
1da177e4
LT
361 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
362 if (nr_parts > 0) {
363 info->parts = parts;
364 part_type = "dynamic";
2fe2e24e 365 } else {
57725f0a
RK
366 parts = plat->parts;
367 nr_parts = plat->nr_parts;
1da177e4
LT
368 part_type = "static";
369 }
370
2fe2e24e 371 if (nr_parts == 0)
1da177e4
LT
372 printk(KERN_NOTICE "SA1100 flash: no partition info "
373 "available, registering whole flash\n");
2fe2e24e 374 else
1da177e4
LT
375 printk(KERN_NOTICE "SA1100 flash: using %s partition "
376 "definition\n", part_type);
2fe2e24e
JI
377
378 mtd_device_register(info->mtd, parts, nr_parts);
1da177e4 379
822e5e72
RK
380 info->nr_parts = nr_parts;
381
3ae5eaec 382 platform_set_drvdata(pdev, info);
1da177e4
LT
383 err = 0;
384
385 out:
386 return err;
387}
388
3ae5eaec 389static int __exit sa1100_mtd_remove(struct platform_device *pdev)
1da177e4 390{
3ae5eaec
RK
391 struct sa_info *info = platform_get_drvdata(pdev);
392 struct flash_platform_data *plat = pdev->dev.platform_data;
0d2ef7d7 393
3ae5eaec 394 platform_set_drvdata(pdev, NULL);
0d2ef7d7
RK
395 sa1100_destroy(info, plat);
396
1da177e4
LT
397 return 0;
398}
399
400#ifdef CONFIG_PM
3ae5eaec 401static void sa1100_mtd_shutdown(struct platform_device *dev)
13bfb34c 402{
3ae5eaec 403 struct sa_info *info = platform_get_drvdata(dev);
13bfb34c
RK
404 if (info && info->mtd->suspend(info->mtd) == 0)
405 info->mtd->resume(info->mtd);
406}
1da177e4 407#else
13bfb34c 408#define sa1100_mtd_shutdown NULL
1da177e4
LT
409#endif
410
3ae5eaec 411static struct platform_driver sa1100_mtd_driver = {
1da177e4
LT
412 .probe = sa1100_mtd_probe,
413 .remove = __exit_p(sa1100_mtd_remove),
13bfb34c 414 .shutdown = sa1100_mtd_shutdown,
3ae5eaec 415 .driver = {
bcc8f3e0 416 .name = "sa1100-mtd",
41d867c9 417 .owner = THIS_MODULE,
3ae5eaec 418 },
1da177e4
LT
419};
420
421static int __init sa1100_mtd_init(void)
422{
3ae5eaec 423 return platform_driver_register(&sa1100_mtd_driver);
1da177e4
LT
424}
425
426static void __exit sa1100_mtd_exit(void)
427{
3ae5eaec 428 platform_driver_unregister(&sa1100_mtd_driver);
1da177e4
LT
429}
430
431module_init(sa1100_mtd_init);
432module_exit(sa1100_mtd_exit);
433
434MODULE_AUTHOR("Nicolas Pitre");
435MODULE_DESCRIPTION("SA1100 CFI map driver");
436MODULE_LICENSE("GPL");
bcc8f3e0 437MODULE_ALIAS("platform:sa1100-mtd");
This page took 0.495762 seconds and 5 git commands to generate.