xref: /linux/drivers/mtd/maps/sa1100-flash.c (revision 2f82af08fcc7dc01a7e98a49a5995a77e32a2925)
1 /*
2  * Flash memory access on SA11x0 based devices
3  *
4  * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
5  */
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>
13 #include <linux/platform_device.h>
14 #include <linux/err.h>
15 #include <linux/io.h>
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 
22 #include <mach/hardware.h>
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  */
31 static 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: */
67 static 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 
96 static 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 
109 static 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 
126 struct sa_subdev_info {
127 	char name[16];
128 	struct map_info map;
129 	struct mtd_info *mtd;
130 	struct flash_platform_data *plat;
131 };
132 
133 struct sa_info {
134 	struct mtd_partition	*parts;
135 	struct mtd_info		*mtd;
136 	int			num_subdev;
137 	unsigned int		nr_parts;
138 	struct sa_subdev_info	subdev[0];
139 };
140 
141 static 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);
144 	subdev->plat->set_vpp(on);
145 }
146 
147 static 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 
156 static 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 
188 	if (subdev->plat->set_vpp)
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 	 */
205 	subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
206 	if (subdev->mtd == NULL) {
207 		ret = -ENXIO;
208 		goto err;
209 	}
210 	subdev->mtd->owner = THIS_MODULE;
211 
212 	printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
213 		"%d-bit\n", phys, subdev->mtd->size >> 20,
214 		subdev->map.bankwidth * 8);
215 
216 	return 0;
217 
218  err:
219 	sa1100_destroy_subdev(subdev);
220  out:
221 	return ret;
222 }
223 
224 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
225 {
226 	int i;
227 
228 	if (info->mtd) {
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
235 #ifdef CONFIG_MTD_CONCAT
236 		if (info->mtd != info->subdev[0].mtd)
237 			mtd_concat_destroy(info->mtd);
238 #endif
239 	}
240 
241 	kfree(info->parts);
242 
243 	for (i = info->num_subdev - 1; i >= 0; i--)
244 		sa1100_destroy_subdev(&info->subdev[i]);
245 	kfree(info);
246 
247 	if (plat->exit)
248 		plat->exit();
249 }
250 
251 static struct sa_info *__init
252 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
253 {
254 	struct sa_info *info;
255 	int nr, size, i, ret = 0;
256 
257 	/*
258 	 * Count number of devices.
259 	 */
260 	for (nr = 0; ; nr++)
261 		if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
262 			break;
263 
264 	if (nr == 0) {
265 		ret = -ENODEV;
266 		goto out;
267 	}
268 
269 	size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
270 
271 	/*
272 	 * Allocate the map_info structs in one go.
273 	 */
274 	info = kzalloc(size, GFP_KERNEL);
275 	if (!info) {
276 		ret = -ENOMEM;
277 		goto out;
278 	}
279 
280 	if (plat->init) {
281 		ret = plat->init();
282 		if (ret)
283 			goto err;
284 	}
285 
286 	/*
287 	 * Claim and then map the memory regions.
288 	 */
289 	for (i = 0; i < nr; i++) {
290 		struct sa_subdev_info *subdev = &info->subdev[i];
291 		struct resource *res;
292 
293 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
294 		if (!res)
295 			break;
296 
297 		subdev->map.name = subdev->name;
298 		sprintf(subdev->name, "%s-%d", plat->name, i);
299 		subdev->plat = plat;
300 
301 		ret = sa1100_probe_subdev(subdev, res);
302 		if (ret)
303 			break;
304 	}
305 
306 	info->num_subdev = i;
307 
308 	/*
309 	 * ENXIO is special.  It means we didn't find a chip when we probed.
310 	 */
311 	if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
312 		goto err;
313 
314 	/*
315 	 * If we found one device, don't bother with concat support.  If
316 	 * we found multiple devices, use concat if we have it available,
317 	 * otherwise fail.  Either way, it'll be called "sa1100".
318 	 */
319 	if (info->num_subdev == 1) {
320 		strcpy(info->subdev[0].name, plat->name);
321 		info->mtd = info->subdev[0].mtd;
322 		ret = 0;
323 	} else if (info->num_subdev > 1) {
324 #ifdef CONFIG_MTD_CONCAT
325 		struct mtd_info *cdev[nr];
326 		/*
327 		 * We detected multiple devices.  Concatenate them together.
328 		 */
329 		for (i = 0; i < info->num_subdev; i++)
330 			cdev[i] = info->subdev[i].mtd;
331 
332 		info->mtd = mtd_concat_create(cdev, info->num_subdev,
333 					      plat->name);
334 		if (info->mtd == NULL)
335 			ret = -ENXIO;
336 #else
337 		printk(KERN_ERR "SA1100 flash: multiple devices "
338 		       "found but MTD concat support disabled.\n");
339 		ret = -ENXIO;
340 #endif
341 	}
342 
343 	if (ret == 0)
344 		return info;
345 
346  err:
347 	sa1100_destroy(info, plat);
348  out:
349 	return ERR_PTR(ret);
350 }
351 
352 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
353 
354 static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
355 {
356 	struct flash_platform_data *plat = pdev->dev.platform_data;
357 	struct mtd_partition *parts;
358 	const char *part_type = NULL;
359 	struct sa_info *info;
360 	int err, nr_parts = 0;
361 
362 	if (!plat)
363 		return -ENODEV;
364 
365 	info = sa1100_setup_mtd(pdev, plat);
366 	if (IS_ERR(info)) {
367 		err = PTR_ERR(info);
368 		goto out;
369 	}
370 
371 	/*
372 	 * Partition selection stuff.
373 	 */
374 #ifdef CONFIG_MTD_PARTITIONS
375 	nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
376 	if (nr_parts > 0) {
377 		info->parts = parts;
378 		part_type = "dynamic";
379 	} else
380 #endif
381 	{
382 		parts = plat->parts;
383 		nr_parts = plat->nr_parts;
384 		part_type = "static";
385 	}
386 
387 	if (nr_parts == 0) {
388 		printk(KERN_NOTICE "SA1100 flash: no partition info "
389 			"available, registering whole flash\n");
390 		add_mtd_device(info->mtd);
391 	} else {
392 		printk(KERN_NOTICE "SA1100 flash: using %s partition "
393 			"definition\n", part_type);
394 		add_mtd_partitions(info->mtd, parts, nr_parts);
395 	}
396 
397 	info->nr_parts = nr_parts;
398 
399 	platform_set_drvdata(pdev, info);
400 	err = 0;
401 
402  out:
403 	return err;
404 }
405 
406 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
407 {
408 	struct sa_info *info = platform_get_drvdata(pdev);
409 	struct flash_platform_data *plat = pdev->dev.platform_data;
410 
411 	platform_set_drvdata(pdev, NULL);
412 	sa1100_destroy(info, plat);
413 
414 	return 0;
415 }
416 
417 #ifdef CONFIG_PM
418 static void sa1100_mtd_shutdown(struct platform_device *dev)
419 {
420 	struct sa_info *info = platform_get_drvdata(dev);
421 	if (info && info->mtd->suspend(info->mtd) == 0)
422 		info->mtd->resume(info->mtd);
423 }
424 #else
425 #define sa1100_mtd_shutdown NULL
426 #endif
427 
428 static struct platform_driver sa1100_mtd_driver = {
429 	.probe		= sa1100_mtd_probe,
430 	.remove		= __exit_p(sa1100_mtd_remove),
431 	.shutdown	= sa1100_mtd_shutdown,
432 	.driver		= {
433 		.name	= "sa1100-mtd",
434 		.owner	= THIS_MODULE,
435 	},
436 };
437 
438 static int __init sa1100_mtd_init(void)
439 {
440 	return platform_driver_register(&sa1100_mtd_driver);
441 }
442 
443 static void __exit sa1100_mtd_exit(void)
444 {
445 	platform_driver_unregister(&sa1100_mtd_driver);
446 }
447 
448 module_init(sa1100_mtd_init);
449 module_exit(sa1100_mtd_exit);
450 
451 MODULE_AUTHOR("Nicolas Pitre");
452 MODULE_DESCRIPTION("SA1100 CFI map driver");
453 MODULE_LICENSE("GPL");
454 MODULE_ALIAS("platform:sa1100-mtd");
455