sharpsl.c revision 26615249daaaa9fc194b5154261b9569112ea9fd
1/*
2 * drivers/mtd/nand/sharpsl.c
3 *
4 *  Copyright (C) 2004 Richard Purdie
5 *
6 *  Based on Sharp's NAND driver sharp_sl.c
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/genhd.h>
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/delay.h>
18#include <linux/mtd/mtd.h>
19#include <linux/mtd/nand.h>
20#include <linux/mtd/nand_ecc.h>
21#include <linux/mtd/partitions.h>
22#include <linux/interrupt.h>
23#include <linux/platform_device.h>
24
25#include <asm/io.h>
26#include <mach/hardware.h>
27#include <asm/mach-types.h>
28
29static void __iomem *sharpsl_io_base;
30
31/* register offset */
32#define ECCLPLB	 	sharpsl_io_base+0x00	/* line parity 7 - 0 bit */
33#define ECCLPUB	 	sharpsl_io_base+0x04	/* line parity 15 - 8 bit */
34#define ECCCP	   	sharpsl_io_base+0x08	/* column parity 5 - 0 bit */
35#define ECCCNTR	 	sharpsl_io_base+0x0C	/* ECC byte counter */
36#define ECCCLRR	 	sharpsl_io_base+0x10	/* cleare ECC */
37#define FLASHIO	 	sharpsl_io_base+0x14	/* Flash I/O */
38#define FLASHCTL	sharpsl_io_base+0x18	/* Flash Control */
39
40/* Flash control bit */
41#define FLRYBY		(1 << 5)
42#define FLCE1		(1 << 4)
43#define FLWP		(1 << 3)
44#define FLALE		(1 << 2)
45#define FLCLE		(1 << 1)
46#define FLCE0		(1 << 0)
47
48/*
49 * MTD structure for SharpSL
50 */
51static struct mtd_info *sharpsl_mtd = NULL;
52
53/*
54 * Define partitions for flash device
55 */
56#define DEFAULT_NUM_PARTITIONS 3
57
58static int nr_partitions;
59static struct mtd_partition sharpsl_nand_default_partition_info[] = {
60	{
61	 .name = "System Area",
62	 .offset = 0,
63	 .size = 7 * 1024 * 1024,
64	 },
65	{
66	 .name = "Root Filesystem",
67	 .offset = 7 * 1024 * 1024,
68	 .size = 30 * 1024 * 1024,
69	 },
70	{
71	 .name = "Home Filesystem",
72	 .offset = MTDPART_OFS_APPEND,
73	 .size = MTDPART_SIZ_FULL,
74	 },
75};
76
77/*
78 *	hardware specific access to control-lines
79 *	ctrl:
80 *	NAND_CNE: bit 0 -> ! bit 0 & 4
81 *	NAND_CLE: bit 1 -> bit 1
82 *	NAND_ALE: bit 2 -> bit 2
83 *
84 */
85static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
86				   unsigned int ctrl)
87{
88	struct nand_chip *chip = mtd->priv;
89
90	if (ctrl & NAND_CTRL_CHANGE) {
91		unsigned char bits = ctrl & 0x07;
92
93		bits |= (ctrl & 0x01) << 4;
94
95		bits ^= 0x11;
96
97		writeb((readb(FLASHCTL) & ~0x17) | bits, FLASHCTL);
98	}
99
100	if (cmd != NAND_CMD_NONE)
101		writeb(cmd, chip->IO_ADDR_W);
102}
103
104static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
105
106static struct nand_bbt_descr sharpsl_bbt = {
107	.options = 0,
108	.offs = 4,
109	.len = 2,
110	.pattern = scan_ff_pattern
111};
112
113static struct nand_bbt_descr sharpsl_akita_bbt = {
114	.options = 0,
115	.offs = 4,
116	.len = 1,
117	.pattern = scan_ff_pattern
118};
119
120static struct nand_ecclayout akita_oobinfo = {
121	.eccbytes = 24,
122	.eccpos = {
123		   0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
124		   0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
125		   0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
126	.oobfree = {{0x08, 0x09}}
127};
128
129static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
130{
131	return !((readb(FLASHCTL) & FLRYBY) == 0);
132}
133
134static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
135{
136	writeb(0, ECCCLRR);
137}
138
139static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
140{
141	ecc_code[0] = ~readb(ECCLPUB);
142	ecc_code[1] = ~readb(ECCLPLB);
143	ecc_code[2] = (~readb(ECCCP) << 2) | 0x03;
144	return readb(ECCCNTR) != 0;
145}
146
147#ifdef CONFIG_MTD_PARTITIONS
148const char *part_probes[] = { "cmdlinepart", NULL };
149#endif
150
151/*
152 * Main initialization routine
153 */
154static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
155{
156	struct nand_chip *this;
157	struct mtd_partition *sharpsl_partition_info;
158	struct resource *r;
159	int err = 0;
160
161	/* Allocate memory for MTD device structure and private data */
162	sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
163	if (!sharpsl_mtd) {
164		printk("Unable to allocate SharpSL NAND MTD device structure.\n");
165		return -ENOMEM;
166	}
167
168	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
169	if (!r) {
170		dev_err(&pdev->dev, "no io memory resource defined!\n");
171		err = -ENODEV;
172		goto err_get_res;
173	}
174
175	/* map physical address */
176	sharpsl_io_base = ioremap(r->start, resource_size(r));
177	if (!sharpsl_io_base) {
178		printk("ioremap to access Sharp SL NAND chip failed\n");
179		kfree(sharpsl_mtd);
180		return -EIO;
181	}
182
183	/* Get pointer to private data */
184	this = (struct nand_chip *)(&sharpsl_mtd[1]);
185
186	/* Initialize structures */
187	memset(sharpsl_mtd, 0, sizeof(struct mtd_info));
188	memset(this, 0, sizeof(struct nand_chip));
189
190	/* Link the private data with the MTD structure */
191	sharpsl_mtd->priv = this;
192	sharpsl_mtd->owner = THIS_MODULE;
193
194	/*
195	 * PXA initialize
196	 */
197	writeb(readb(FLASHCTL) | FLWP, FLASHCTL);
198
199	/* Set address of NAND IO lines */
200	this->IO_ADDR_R = FLASHIO;
201	this->IO_ADDR_W = FLASHIO;
202	/* Set address of hardware control function */
203	this->cmd_ctrl = sharpsl_nand_hwcontrol;
204	this->dev_ready = sharpsl_nand_dev_ready;
205	/* 15 us command delay time */
206	this->chip_delay = 15;
207	/* set eccmode using hardware ECC */
208	this->ecc.mode = NAND_ECC_HW;
209	this->ecc.size = 256;
210	this->ecc.bytes = 3;
211	this->badblock_pattern = &sharpsl_bbt;
212	if (machine_is_akita() || machine_is_borzoi()) {
213		this->badblock_pattern = &sharpsl_akita_bbt;
214		this->ecc.layout = &akita_oobinfo;
215	}
216	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
217	this->ecc.calculate = sharpsl_nand_calculate_ecc;
218	this->ecc.correct = nand_correct_data;
219
220	/* Scan to find existence of the device */
221	err = nand_scan(sharpsl_mtd, 1);
222	if (err) {
223		iounmap(sharpsl_io_base);
224		kfree(sharpsl_mtd);
225		return err;
226	}
227
228	/* Register the partitions */
229	sharpsl_mtd->name = "sharpsl-nand";
230	nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0);
231
232	if (nr_partitions <= 0) {
233		nr_partitions = DEFAULT_NUM_PARTITIONS;
234		sharpsl_partition_info = sharpsl_nand_default_partition_info;
235		if (machine_is_poodle()) {
236			sharpsl_partition_info[1].size = 22 * 1024 * 1024;
237		} else if (machine_is_corgi() || machine_is_shepherd()) {
238			sharpsl_partition_info[1].size = 25 * 1024 * 1024;
239		} else if (machine_is_husky()) {
240			sharpsl_partition_info[1].size = 53 * 1024 * 1024;
241		} else if (machine_is_spitz()) {
242			sharpsl_partition_info[1].size = 5 * 1024 * 1024;
243		} else if (machine_is_akita()) {
244			sharpsl_partition_info[1].size = 58 * 1024 * 1024;
245		} else if (machine_is_borzoi()) {
246			sharpsl_partition_info[1].size = 32 * 1024 * 1024;
247		}
248	}
249
250	add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions);
251
252	/* Return happy */
253	return 0;
254
255err_get_res:
256	kfree(sharpsl_mtd);
257	return err;
258}
259
260/*
261 * Clean up routine
262 */
263static int __devexit sharpsl_nand_remove(struct platform_device *pdev)
264{
265	/* Release resources, unregister device */
266	nand_release(sharpsl_mtd);
267
268	iounmap(sharpsl_io_base);
269
270	/* Free the MTD device structure */
271	kfree(sharpsl_mtd);
272
273	return 0;
274}
275
276static struct platform_driver sharpsl_nand_driver = {
277	.driver = {
278		.name	= "sharpsl-nand",
279		.owner	= THIS_MODULE,
280	},
281	.probe		= sharpsl_nand_probe,
282	.remove		= __devexit_p(sharpsl_nand_remove),
283};
284
285static struct resource sharpsl_nand_resources[] = {
286	{
287		.start	= 0x0C000000,
288		.end	= 0x0C000FFF,
289		.flags	= IORESOURCE_MEM,
290	},
291};
292
293static struct platform_device sharpsl_nand_device = {
294	.name		= "sharpsl-nand",
295	.id		= -1,
296	.resource	= sharpsl_nand_resources,
297	.num_resources	= ARRAY_SIZE(sharpsl_nand_resources),
298};
299
300static int __init sharpsl_nand_init(void)
301{
302	platform_device_register(&sharpsl_nand_device);
303	return platform_driver_register(&sharpsl_nand_driver);
304}
305module_init(sharpsl_nand_init);
306
307static void __exit sharpsl_nand_exit(void)
308{
309	platform_driver_unregister(&sharpsl_nand_driver);
310	platform_device_unregister(&sharpsl_nand_device);
311}
312module_exit(sharpsl_nand_exit);
313
314MODULE_LICENSE("GPL");
315MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
316MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
317