xref: /openbmc/linux/drivers/mtd/maps/sa1100-flash.c (revision 64c70b1c)
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/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>
15 #include <linux/platform_device.h>
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 
23 #include <asm/hardware.h>
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  */
33 static 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: */
69 static 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 
98 static 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 
111 static 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 
128 struct sa_subdev_info {
129 	char name[16];
130 	struct map_info map;
131 	struct mtd_info *mtd;
132 	struct flash_platform_data *plat;
133 };
134 
135 struct sa_info {
136 	struct mtd_partition	*parts;
137 	struct mtd_info		*mtd;
138 	int			num_subdev;
139 	unsigned int		nr_parts;
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->plat->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->plat->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->plat->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, struct flash_platform_data *plat)
227 {
228 	int i;
229 
230 	if (info->mtd) {
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
237 #ifdef CONFIG_MTD_CONCAT
238 		if (info->mtd != info->subdev[0].mtd)
239 			mtd_concat_destroy(info->mtd);
240 #endif
241 	}
242 
243 	kfree(info->parts);
244 
245 	for (i = info->num_subdev - 1; i >= 0; i--)
246 		sa1100_destroy_subdev(&info->subdev[i]);
247 	kfree(info);
248 
249 	if (plat->exit)
250 		plat->exit();
251 }
252 
253 static struct sa_info *__init
254 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
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 	 */
276 	info = kzalloc(size, GFP_KERNEL);
277 	if (!info) {
278 		ret = -ENOMEM;
279 		goto out;
280 	}
281 
282 	if (plat->init) {
283 		ret = plat->init();
284 		if (ret)
285 			goto err;
286 	}
287 
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;
300 		sprintf(subdev->name, "%s-%d", plat->name, i);
301 		subdev->plat = plat;
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) {
322 		strcpy(info->subdev[0].name, plat->name);
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,
335 					      plat->name);
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:
349 	sa1100_destroy(info, plat);
350  out:
351 	return ERR_PTR(ret);
352 }
353 
354 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
355 
356 static int __init sa1100_mtd_probe(struct platform_device *pdev)
357 {
358 	struct flash_platform_data *plat = pdev->dev.platform_data;
359 	struct mtd_partition *parts;
360 	const char *part_type = NULL;
361 	struct sa_info *info;
362 	int err, nr_parts = 0;
363 
364 	if (!plat)
365 		return -ENODEV;
366 
367 	info = sa1100_setup_mtd(pdev, plat);
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 	{
384 		parts = plat->parts;
385 		nr_parts = plat->nr_parts;
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 
399 	info->nr_parts = nr_parts;
400 
401 	platform_set_drvdata(pdev, info);
402 	err = 0;
403 
404  out:
405 	return err;
406 }
407 
408 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
409 {
410 	struct sa_info *info = platform_get_drvdata(pdev);
411 	struct flash_platform_data *plat = pdev->dev.platform_data;
412 
413 	platform_set_drvdata(pdev, NULL);
414 	sa1100_destroy(info, plat);
415 
416 	return 0;
417 }
418 
419 #ifdef CONFIG_PM
420 static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
421 {
422 	struct sa_info *info = platform_get_drvdata(dev);
423 	int ret = 0;
424 
425 	if (info)
426 		ret = info->mtd->suspend(info->mtd);
427 
428 	return ret;
429 }
430 
431 static int sa1100_mtd_resume(struct platform_device *dev)
432 {
433 	struct sa_info *info = platform_get_drvdata(dev);
434 	if (info)
435 		info->mtd->resume(info->mtd);
436 	return 0;
437 }
438 
439 static void sa1100_mtd_shutdown(struct platform_device *dev)
440 {
441 	struct sa_info *info = platform_get_drvdata(dev);
442 	if (info && info->mtd->suspend(info->mtd) == 0)
443 		info->mtd->resume(info->mtd);
444 }
445 #else
446 #define sa1100_mtd_suspend NULL
447 #define sa1100_mtd_resume  NULL
448 #define sa1100_mtd_shutdown NULL
449 #endif
450 
451 static struct platform_driver sa1100_mtd_driver = {
452 	.probe		= sa1100_mtd_probe,
453 	.remove		= __exit_p(sa1100_mtd_remove),
454 	.suspend	= sa1100_mtd_suspend,
455 	.resume		= sa1100_mtd_resume,
456 	.shutdown	= sa1100_mtd_shutdown,
457 	.driver		= {
458 		.name	= "flash",
459 	},
460 };
461 
462 static int __init sa1100_mtd_init(void)
463 {
464 	return platform_driver_register(&sa1100_mtd_driver);
465 }
466 
467 static void __exit sa1100_mtd_exit(void)
468 {
469 	platform_driver_unregister(&sa1100_mtd_driver);
470 }
471 
472 module_init(sa1100_mtd_init);
473 module_exit(sa1100_mtd_exit);
474 
475 MODULE_AUTHOR("Nicolas Pitre");
476 MODULE_DESCRIPTION("SA1100 CFI map driver");
477 MODULE_LICENSE("GPL");
478