]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/mtd/maps/sa1100-flash.c
mtd: rbtx4939-flash: convert to mtd_device_register()
[mirror_ubuntu-jammy-kernel.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) {
822e5e72
RK
229 if (info->nr_parts == 0)
230 del_mtd_device(info->mtd);
231#ifdef CONFIG_MTD_PARTITIONS
232 else
233 del_mtd_partitions(info->mtd);
234#endif
1da177e4
LT
235 if (info->mtd != info->subdev[0].mtd)
236 mtd_concat_destroy(info->mtd);
1da177e4
LT
237 }
238
fa671646 239 kfree(info->parts);
1da177e4
LT
240
241 for (i = info->num_subdev - 1; i >= 0; i--)
242 sa1100_destroy_subdev(&info->subdev[i]);
243 kfree(info);
0d2ef7d7
RK
244
245 if (plat->exit)
246 plat->exit();
1da177e4
LT
247}
248
5a134239 249static struct sa_info *__devinit
57725f0a 250sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
1da177e4
LT
251{
252 struct sa_info *info;
253 int nr, size, i, ret = 0;
254
255 /*
256 * Count number of devices.
257 */
258 for (nr = 0; ; nr++)
259 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
260 break;
261
262 if (nr == 0) {
263 ret = -ENODEV;
264 goto out;
265 }
266
267 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
268
269 /*
270 * Allocate the map_info structs in one go.
271 */
95b93a0c 272 info = kzalloc(size, GFP_KERNEL);
1da177e4
LT
273 if (!info) {
274 ret = -ENOMEM;
275 goto out;
276 }
277
0d2ef7d7
RK
278 if (plat->init) {
279 ret = plat->init();
280 if (ret)
281 goto err;
282 }
283
1da177e4
LT
284 /*
285 * Claim and then map the memory regions.
286 */
287 for (i = 0; i < nr; i++) {
288 struct sa_subdev_info *subdev = &info->subdev[i];
289 struct resource *res;
290
291 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
292 if (!res)
293 break;
294
295 subdev->map.name = subdev->name;
14e66f76 296 sprintf(subdev->name, "%s-%d", plat->name, i);
57725f0a 297 subdev->plat = plat;
1da177e4
LT
298
299 ret = sa1100_probe_subdev(subdev, res);
300 if (ret)
301 break;
302 }
303
304 info->num_subdev = i;
305
306 /*
307 * ENXIO is special. It means we didn't find a chip when we probed.
308 */
309 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
310 goto err;
311
312 /*
313 * If we found one device, don't bother with concat support. If
314 * we found multiple devices, use concat if we have it available,
315 * otherwise fail. Either way, it'll be called "sa1100".
316 */
317 if (info->num_subdev == 1) {
14e66f76 318 strcpy(info->subdev[0].name, plat->name);
1da177e4
LT
319 info->mtd = info->subdev[0].mtd;
320 ret = 0;
321 } else if (info->num_subdev > 1) {
1da177e4
LT
322 struct mtd_info *cdev[nr];
323 /*
324 * We detected multiple devices. Concatenate them together.
325 */
326 for (i = 0; i < info->num_subdev; i++)
327 cdev[i] = info->subdev[i].mtd;
328
329 info->mtd = mtd_concat_create(cdev, info->num_subdev,
14e66f76 330 plat->name);
1da177e4
LT
331 if (info->mtd == NULL)
332 ret = -ENXIO;
1da177e4
LT
333 }
334
335 if (ret == 0)
336 return info;
337
338 err:
0d2ef7d7 339 sa1100_destroy(info, plat);
1da177e4
LT
340 out:
341 return ERR_PTR(ret);
342}
343
344static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
345
f0b1e589 346static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
1da177e4 347{
57725f0a 348 struct flash_platform_data *plat = pdev->dev.platform_data;
1da177e4
LT
349 struct mtd_partition *parts;
350 const char *part_type = NULL;
351 struct sa_info *info;
352 int err, nr_parts = 0;
353
57725f0a 354 if (!plat)
1da177e4
LT
355 return -ENODEV;
356
57725f0a 357 info = sa1100_setup_mtd(pdev, plat);
1da177e4
LT
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 {
57725f0a
RK
374 parts = plat->parts;
375 nr_parts = plat->nr_parts;
1da177e4
LT
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
822e5e72
RK
389 info->nr_parts = nr_parts;
390
3ae5eaec 391 platform_set_drvdata(pdev, info);
1da177e4
LT
392 err = 0;
393
394 out:
395 return err;
396}
397
3ae5eaec 398static int __exit sa1100_mtd_remove(struct platform_device *pdev)
1da177e4 399{
3ae5eaec
RK
400 struct sa_info *info = platform_get_drvdata(pdev);
401 struct flash_platform_data *plat = pdev->dev.platform_data;
0d2ef7d7 402
3ae5eaec 403 platform_set_drvdata(pdev, NULL);
0d2ef7d7
RK
404 sa1100_destroy(info, plat);
405
1da177e4
LT
406 return 0;
407}
408
409#ifdef CONFIG_PM
3ae5eaec 410static void sa1100_mtd_shutdown(struct platform_device *dev)
13bfb34c 411{
3ae5eaec 412 struct sa_info *info = platform_get_drvdata(dev);
13bfb34c
RK
413 if (info && info->mtd->suspend(info->mtd) == 0)
414 info->mtd->resume(info->mtd);
415}
1da177e4 416#else
13bfb34c 417#define sa1100_mtd_shutdown NULL
1da177e4
LT
418#endif
419
3ae5eaec 420static struct platform_driver sa1100_mtd_driver = {
1da177e4
LT
421 .probe = sa1100_mtd_probe,
422 .remove = __exit_p(sa1100_mtd_remove),
13bfb34c 423 .shutdown = sa1100_mtd_shutdown,
3ae5eaec 424 .driver = {
bcc8f3e0 425 .name = "sa1100-mtd",
41d867c9 426 .owner = THIS_MODULE,
3ae5eaec 427 },
1da177e4
LT
428};
429
430static int __init sa1100_mtd_init(void)
431{
3ae5eaec 432 return platform_driver_register(&sa1100_mtd_driver);
1da177e4
LT
433}
434
435static void __exit sa1100_mtd_exit(void)
436{
3ae5eaec 437 platform_driver_unregister(&sa1100_mtd_driver);
1da177e4
LT
438}
439
440module_init(sa1100_mtd_init);
441module_exit(sa1100_mtd_exit);
442
443MODULE_AUTHOR("Nicolas Pitre");
444MODULE_DESCRIPTION("SA1100 CFI map driver");
445MODULE_LICENSE("GPL");
bcc8f3e0 446MODULE_ALIAS("platform:sa1100-mtd");