xref: /openbmc/linux/drivers/mtd/maps/sa1100-flash.c (revision 87c2ce3b)
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.51 2005/11/07 11:14:28 gleixner 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/platform_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/hardware.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 *plat;
134 };
135 
136 struct sa_info {
137 	struct mtd_partition	*parts;
138 	struct mtd_info		*mtd;
139 	int			num_subdev;
140 	unsigned int		nr_parts;
141 	struct sa_subdev_info	subdev[0];
142 };
143 
144 static void sa1100_set_vpp(struct map_info *map, int on)
145 {
146 	struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
147 	subdev->plat->set_vpp(on);
148 }
149 
150 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
151 {
152 	if (subdev->mtd)
153 		map_destroy(subdev->mtd);
154 	if (subdev->map.virt)
155 		iounmap(subdev->map.virt);
156 	release_mem_region(subdev->map.phys, subdev->map.size);
157 }
158 
159 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
160 {
161 	unsigned long phys;
162 	unsigned int size;
163 	int ret;
164 
165 	phys = res->start;
166 	size = res->end - phys + 1;
167 
168 	/*
169 	 * Retrieve the bankwidth from the MSC registers.
170 	 * We currently only implement CS0 and CS1 here.
171 	 */
172 	switch (phys) {
173 	default:
174 		printk(KERN_WARNING "SA1100 flash: unknown base address "
175 		       "0x%08lx, assuming CS0\n", phys);
176 
177 	case SA1100_CS0_PHYS:
178 		subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
179 		break;
180 
181 	case SA1100_CS1_PHYS:
182 		subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
183 		break;
184 	}
185 
186 	if (!request_mem_region(phys, size, subdev->name)) {
187 		ret = -EBUSY;
188 		goto out;
189 	}
190 
191 	if (subdev->plat->set_vpp)
192 		subdev->map.set_vpp = sa1100_set_vpp;
193 
194 	subdev->map.phys = phys;
195 	subdev->map.size = size;
196 	subdev->map.virt = ioremap(phys, size);
197 	if (!subdev->map.virt) {
198 		ret = -ENOMEM;
199 		goto err;
200 	}
201 
202 	simple_map_init(&subdev->map);
203 
204 	/*
205 	 * Now let's probe for the actual flash.  Do it here since
206 	 * specific machine settings might have been set above.
207 	 */
208 	subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
209 	if (subdev->mtd == NULL) {
210 		ret = -ENXIO;
211 		goto err;
212 	}
213 	subdev->mtd->owner = THIS_MODULE;
214 
215 	printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
216 		"%d-bit\n", phys, subdev->mtd->size >> 20,
217 		subdev->map.bankwidth * 8);
218 
219 	return 0;
220 
221  err:
222 	sa1100_destroy_subdev(subdev);
223  out:
224 	return ret;
225 }
226 
227 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
228 {
229 	int i;
230 
231 	if (info->mtd) {
232 		if (info->nr_parts == 0)
233 			del_mtd_device(info->mtd);
234 #ifdef CONFIG_MTD_PARTITIONS
235 		else
236 			del_mtd_partitions(info->mtd);
237 #endif
238 #ifdef CONFIG_MTD_CONCAT
239 		if (info->mtd != info->subdev[0].mtd)
240 			mtd_concat_destroy(info->mtd);
241 #endif
242 	}
243 
244 	kfree(info->parts);
245 
246 	for (i = info->num_subdev - 1; i >= 0; i--)
247 		sa1100_destroy_subdev(&info->subdev[i]);
248 	kfree(info);
249 
250 	if (plat->exit)
251 		plat->exit();
252 }
253 
254 static struct sa_info *__init
255 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
256 {
257 	struct sa_info *info;
258 	int nr, size, i, ret = 0;
259 
260 	/*
261 	 * Count number of devices.
262 	 */
263 	for (nr = 0; ; nr++)
264 		if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
265 			break;
266 
267 	if (nr == 0) {
268 		ret = -ENODEV;
269 		goto out;
270 	}
271 
272 	size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
273 
274 	/*
275 	 * Allocate the map_info structs in one go.
276 	 */
277 	info = kmalloc(size, GFP_KERNEL);
278 	if (!info) {
279 		ret = -ENOMEM;
280 		goto out;
281 	}
282 
283 	memset(info, 0, size);
284 
285 	if (plat->init) {
286 		ret = plat->init();
287 		if (ret)
288 			goto err;
289 	}
290 
291 	/*
292 	 * Claim and then map the memory regions.
293 	 */
294 	for (i = 0; i < nr; i++) {
295 		struct sa_subdev_info *subdev = &info->subdev[i];
296 		struct resource *res;
297 
298 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
299 		if (!res)
300 			break;
301 
302 		subdev->map.name = subdev->name;
303 		sprintf(subdev->name, "%s-%d", plat->name, i);
304 		subdev->plat = plat;
305 
306 		ret = sa1100_probe_subdev(subdev, res);
307 		if (ret)
308 			break;
309 	}
310 
311 	info->num_subdev = i;
312 
313 	/*
314 	 * ENXIO is special.  It means we didn't find a chip when we probed.
315 	 */
316 	if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
317 		goto err;
318 
319 	/*
320 	 * If we found one device, don't bother with concat support.  If
321 	 * we found multiple devices, use concat if we have it available,
322 	 * otherwise fail.  Either way, it'll be called "sa1100".
323 	 */
324 	if (info->num_subdev == 1) {
325 		strcpy(info->subdev[0].name, plat->name);
326 		info->mtd = info->subdev[0].mtd;
327 		ret = 0;
328 	} else if (info->num_subdev > 1) {
329 #ifdef CONFIG_MTD_CONCAT
330 		struct mtd_info *cdev[nr];
331 		/*
332 		 * We detected multiple devices.  Concatenate them together.
333 		 */
334 		for (i = 0; i < info->num_subdev; i++)
335 			cdev[i] = info->subdev[i].mtd;
336 
337 		info->mtd = mtd_concat_create(cdev, info->num_subdev,
338 					      plat->name);
339 		if (info->mtd == NULL)
340 			ret = -ENXIO;
341 #else
342 		printk(KERN_ERR "SA1100 flash: multiple devices "
343 		       "found but MTD concat support disabled.\n");
344 		ret = -ENXIO;
345 #endif
346 	}
347 
348 	if (ret == 0)
349 		return info;
350 
351  err:
352 	sa1100_destroy(info, plat);
353  out:
354 	return ERR_PTR(ret);
355 }
356 
357 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
358 
359 static int __init sa1100_mtd_probe(struct platform_device *pdev)
360 {
361 	struct flash_platform_data *plat = pdev->dev.platform_data;
362 	struct mtd_partition *parts;
363 	const char *part_type = NULL;
364 	struct sa_info *info;
365 	int err, nr_parts = 0;
366 
367 	if (!plat)
368 		return -ENODEV;
369 
370 	info = sa1100_setup_mtd(pdev, plat);
371 	if (IS_ERR(info)) {
372 		err = PTR_ERR(info);
373 		goto out;
374 	}
375 
376 	/*
377 	 * Partition selection stuff.
378 	 */
379 #ifdef CONFIG_MTD_PARTITIONS
380 	nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
381 	if (nr_parts > 0) {
382 		info->parts = parts;
383 		part_type = "dynamic";
384 	} else
385 #endif
386 	{
387 		parts = plat->parts;
388 		nr_parts = plat->nr_parts;
389 		part_type = "static";
390 	}
391 
392 	if (nr_parts == 0) {
393 		printk(KERN_NOTICE "SA1100 flash: no partition info "
394 			"available, registering whole flash\n");
395 		add_mtd_device(info->mtd);
396 	} else {
397 		printk(KERN_NOTICE "SA1100 flash: using %s partition "
398 			"definition\n", part_type);
399 		add_mtd_partitions(info->mtd, parts, nr_parts);
400 	}
401 
402 	info->nr_parts = nr_parts;
403 
404 	platform_set_drvdata(pdev, info);
405 	err = 0;
406 
407  out:
408 	return err;
409 }
410 
411 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
412 {
413 	struct sa_info *info = platform_get_drvdata(pdev);
414 	struct flash_platform_data *plat = pdev->dev.platform_data;
415 
416 	platform_set_drvdata(pdev, NULL);
417 	sa1100_destroy(info, plat);
418 
419 	return 0;
420 }
421 
422 #ifdef CONFIG_PM
423 static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
424 {
425 	struct sa_info *info = platform_get_drvdata(dev);
426 	int ret = 0;
427 
428 	if (info)
429 		ret = info->mtd->suspend(info->mtd);
430 
431 	return ret;
432 }
433 
434 static int sa1100_mtd_resume(struct platform_device *dev)
435 {
436 	struct sa_info *info = platform_get_drvdata(dev);
437 	if (info)
438 		info->mtd->resume(info->mtd);
439 	return 0;
440 }
441 
442 static void sa1100_mtd_shutdown(struct platform_device *dev)
443 {
444 	struct sa_info *info = platform_get_drvdata(dev);
445 	if (info && info->mtd->suspend(info->mtd) == 0)
446 		info->mtd->resume(info->mtd);
447 }
448 #else
449 #define sa1100_mtd_suspend NULL
450 #define sa1100_mtd_resume  NULL
451 #define sa1100_mtd_shutdown NULL
452 #endif
453 
454 static struct platform_driver sa1100_mtd_driver = {
455 	.probe		= sa1100_mtd_probe,
456 	.remove		= __exit_p(sa1100_mtd_remove),
457 	.suspend	= sa1100_mtd_suspend,
458 	.resume		= sa1100_mtd_resume,
459 	.shutdown	= sa1100_mtd_shutdown,
460 	.driver		= {
461 		.name	= "flash",
462 	},
463 };
464 
465 static int __init sa1100_mtd_init(void)
466 {
467 	return platform_driver_register(&sa1100_mtd_driver);
468 }
469 
470 static void __exit sa1100_mtd_exit(void)
471 {
472 	platform_driver_unregister(&sa1100_mtd_driver);
473 }
474 
475 module_init(sa1100_mtd_init);
476 module_exit(sa1100_mtd_exit);
477 
478 MODULE_AUTHOR("Nicolas Pitre");
479 MODULE_DESCRIPTION("SA1100 CFI map driver");
480 MODULE_LICENSE("GPL");
481