xref: /linux/drivers/mtd/maps/sa1100-flash.c (revision f850548ef88e5ff9e40bae9e1a7140bef0653e6b)
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, %uMiB, %d-bit\n",
213 		phys, (unsigned)(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 		if (info->mtd != info->subdev[0].mtd)
236 			mtd_concat_destroy(info->mtd);
237 	}
238 
239 	kfree(info->parts);
240 
241 	for (i = info->num_subdev - 1; i >= 0; i--)
242 		sa1100_destroy_subdev(&info->subdev[i]);
243 	kfree(info);
244 
245 	if (plat->exit)
246 		plat->exit();
247 }
248 
249 static struct sa_info *__devinit
250 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
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 	 */
272 	info = kzalloc(size, GFP_KERNEL);
273 	if (!info) {
274 		ret = -ENOMEM;
275 		goto out;
276 	}
277 
278 	if (plat->init) {
279 		ret = plat->init();
280 		if (ret)
281 			goto err;
282 	}
283 
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;
296 		sprintf(subdev->name, "%s-%d", plat->name, i);
297 		subdev->plat = plat;
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) {
318 		strcpy(info->subdev[0].name, plat->name);
319 		info->mtd = info->subdev[0].mtd;
320 		ret = 0;
321 	} else if (info->num_subdev > 1) {
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,
330 					      plat->name);
331 		if (info->mtd == NULL)
332 			ret = -ENXIO;
333 	}
334 
335 	if (ret == 0)
336 		return info;
337 
338  err:
339 	sa1100_destroy(info, plat);
340  out:
341 	return ERR_PTR(ret);
342 }
343 
344 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
345 
346 static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
347 {
348 	struct flash_platform_data *plat = pdev->dev.platform_data;
349 	struct mtd_partition *parts;
350 	const char *part_type = NULL;
351 	struct sa_info *info;
352 	int err, nr_parts = 0;
353 
354 	if (!plat)
355 		return -ENODEV;
356 
357 	info = sa1100_setup_mtd(pdev, plat);
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 	{
374 		parts = plat->parts;
375 		nr_parts = plat->nr_parts;
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 
389 	info->nr_parts = nr_parts;
390 
391 	platform_set_drvdata(pdev, info);
392 	err = 0;
393 
394  out:
395 	return err;
396 }
397 
398 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
399 {
400 	struct sa_info *info = platform_get_drvdata(pdev);
401 	struct flash_platform_data *plat = pdev->dev.platform_data;
402 
403 	platform_set_drvdata(pdev, NULL);
404 	sa1100_destroy(info, plat);
405 
406 	return 0;
407 }
408 
409 #ifdef CONFIG_PM
410 static void sa1100_mtd_shutdown(struct platform_device *dev)
411 {
412 	struct sa_info *info = platform_get_drvdata(dev);
413 	if (info && info->mtd->suspend(info->mtd) == 0)
414 		info->mtd->resume(info->mtd);
415 }
416 #else
417 #define sa1100_mtd_shutdown NULL
418 #endif
419 
420 static struct platform_driver sa1100_mtd_driver = {
421 	.probe		= sa1100_mtd_probe,
422 	.remove		= __exit_p(sa1100_mtd_remove),
423 	.shutdown	= sa1100_mtd_shutdown,
424 	.driver		= {
425 		.name	= "sa1100-mtd",
426 		.owner	= THIS_MODULE,
427 	},
428 };
429 
430 static int __init sa1100_mtd_init(void)
431 {
432 	return platform_driver_register(&sa1100_mtd_driver);
433 }
434 
435 static void __exit sa1100_mtd_exit(void)
436 {
437 	platform_driver_unregister(&sa1100_mtd_driver);
438 }
439 
440 module_init(sa1100_mtd_init);
441 module_exit(sa1100_mtd_exit);
442 
443 MODULE_AUTHOR("Nicolas Pitre");
444 MODULE_DESCRIPTION("SA1100 CFI map driver");
445 MODULE_LICENSE("GPL");
446 MODULE_ALIAS("platform:sa1100-mtd");
447