aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/au1550nd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/au1550nd.c')
-rw-r--r--drivers/mtd/nand/au1550nd.c477
1 files changed, 477 insertions, 0 deletions
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
new file mode 100644
index 000000000000..4c7719ce3f48
--- /dev/null
+++ b/drivers/mtd/nand/au1550nd.c
@@ -0,0 +1,477 @@
1/*
2 * drivers/mtd/nand/au1550nd.c
3 *
4 * Copyright (C) 2004 Embedded Edge, LLC
5 *
6 * $Id: au1550nd.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $
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/slab.h>
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/mtd/mtd.h>
18#include <linux/mtd/nand.h>
19#include <linux/mtd/partitions.h>
20#include <asm/io.h>
21
22/* fixme: this is ugly */
23#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
24#include <asm/mach-au1x00/au1000.h>
25#ifdef CONFIG_MIPS_PB1550
26#include <asm/mach-pb1x00/pb1550.h>
27#endif
28#ifdef CONFIG_MIPS_DB1550
29#include <asm/mach-db1x00/db1x00.h>
30#endif
31#else
32#include <asm/au1000.h>
33#ifdef CONFIG_MIPS_PB1550
34#include <asm/pb1550.h>
35#endif
36#ifdef CONFIG_MIPS_DB1550
37#include <asm/db1x00.h>
38#endif
39#endif
40
41/*
42 * MTD structure for NAND controller
43 */
44static struct mtd_info *au1550_mtd = NULL;
45static void __iomem *p_nand;
46static int nand_width = 1; /* default x8*/
47
48#define NAND_CS 1
49
50/*
51 * Define partitions for flash device
52 */
53const static struct mtd_partition partition_info[] = {
54#ifdef CONFIG_MIPS_PB1550
55#define NUM_PARTITIONS 2
56 {
57 .name = "Pb1550 NAND FS 0",
58 .offset = 0,
59 .size = 8*1024*1024
60 },
61 {
62 .name = "Pb1550 NAND FS 1",
63 .offset = MTDPART_OFS_APPEND,
64 .size = MTDPART_SIZ_FULL
65 }
66#endif
67#ifdef CONFIG_MIPS_DB1550
68#define NUM_PARTITIONS 2
69 {
70 .name = "Db1550 NAND FS 0",
71 .offset = 0,
72 .size = 8*1024*1024
73 },
74 {
75 .name = "Db1550 NAND FS 1",
76 .offset = MTDPART_OFS_APPEND,
77 .size = MTDPART_SIZ_FULL
78 }
79#endif
80};
81
82
83/**
84 * au_read_byte - read one byte from the chip
85 * @mtd: MTD device structure
86 *
87 * read function for 8bit buswith
88 */
89static u_char au_read_byte(struct mtd_info *mtd)
90{
91 struct nand_chip *this = mtd->priv;
92 u_char ret = readb(this->IO_ADDR_R);
93 au_sync();
94 return ret;
95}
96
97/**
98 * au_write_byte - write one byte to the chip
99 * @mtd: MTD device structure
100 * @byte: pointer to data byte to write
101 *
102 * write function for 8it buswith
103 */
104static void au_write_byte(struct mtd_info *mtd, u_char byte)
105{
106 struct nand_chip *this = mtd->priv;
107 writeb(byte, this->IO_ADDR_W);
108 au_sync();
109}
110
111/**
112 * au_read_byte16 - read one byte endianess aware from the chip
113 * @mtd: MTD device structure
114 *
115 * read function for 16bit buswith with
116 * endianess conversion
117 */
118static u_char au_read_byte16(struct mtd_info *mtd)
119{
120 struct nand_chip *this = mtd->priv;
121 u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
122 au_sync();
123 return ret;
124}
125
126/**
127 * au_write_byte16 - write one byte endianess aware to the chip
128 * @mtd: MTD device structure
129 * @byte: pointer to data byte to write
130 *
131 * write function for 16bit buswith with
132 * endianess conversion
133 */
134static void au_write_byte16(struct mtd_info *mtd, u_char byte)
135{
136 struct nand_chip *this = mtd->priv;
137 writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
138 au_sync();
139}
140
141/**
142 * au_read_word - read one word from the chip
143 * @mtd: MTD device structure
144 *
145 * read function for 16bit buswith without
146 * endianess conversion
147 */
148static u16 au_read_word(struct mtd_info *mtd)
149{
150 struct nand_chip *this = mtd->priv;
151 u16 ret = readw(this->IO_ADDR_R);
152 au_sync();
153 return ret;
154}
155
156/**
157 * au_write_word - write one word to the chip
158 * @mtd: MTD device structure
159 * @word: data word to write
160 *
161 * write function for 16bit buswith without
162 * endianess conversion
163 */
164static void au_write_word(struct mtd_info *mtd, u16 word)
165{
166 struct nand_chip *this = mtd->priv;
167 writew(word, this->IO_ADDR_W);
168 au_sync();
169}
170
171/**
172 * au_write_buf - write buffer to chip
173 * @mtd: MTD device structure
174 * @buf: data buffer
175 * @len: number of bytes to write
176 *
177 * write function for 8bit buswith
178 */
179static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
180{
181 int i;
182 struct nand_chip *this = mtd->priv;
183
184 for (i=0; i<len; i++) {
185 writeb(buf[i], this->IO_ADDR_W);
186 au_sync();
187 }
188}
189
190/**
191 * au_read_buf - read chip data into buffer
192 * @mtd: MTD device structure
193 * @buf: buffer to store date
194 * @len: number of bytes to read
195 *
196 * read function for 8bit buswith
197 */
198static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
199{
200 int i;
201 struct nand_chip *this = mtd->priv;
202
203 for (i=0; i<len; i++) {
204 buf[i] = readb(this->IO_ADDR_R);
205 au_sync();
206 }
207}
208
209/**
210 * au_verify_buf - Verify chip data against buffer
211 * @mtd: MTD device structure
212 * @buf: buffer containing the data to compare
213 * @len: number of bytes to compare
214 *
215 * verify function for 8bit buswith
216 */
217static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
218{
219 int i;
220 struct nand_chip *this = mtd->priv;
221
222 for (i=0; i<len; i++) {
223 if (buf[i] != readb(this->IO_ADDR_R))
224 return -EFAULT;
225 au_sync();
226 }
227
228 return 0;
229}
230
231/**
232 * au_write_buf16 - write buffer to chip
233 * @mtd: MTD device structure
234 * @buf: data buffer
235 * @len: number of bytes to write
236 *
237 * write function for 16bit buswith
238 */
239static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
240{
241 int i;
242 struct nand_chip *this = mtd->priv;
243 u16 *p = (u16 *) buf;
244 len >>= 1;
245
246 for (i=0; i<len; i++) {
247 writew(p[i], this->IO_ADDR_W);
248 au_sync();
249 }
250
251}
252
253/**
254 * au_read_buf16 - read chip data into buffer
255 * @mtd: MTD device structure
256 * @buf: buffer to store date
257 * @len: number of bytes to read
258 *
259 * read function for 16bit buswith
260 */
261static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
262{
263 int i;
264 struct nand_chip *this = mtd->priv;
265 u16 *p = (u16 *) buf;
266 len >>= 1;
267
268 for (i=0; i<len; i++) {
269 p[i] = readw(this->IO_ADDR_R);
270 au_sync();
271 }
272}
273
274/**
275 * au_verify_buf16 - Verify chip data against buffer
276 * @mtd: MTD device structure
277 * @buf: buffer containing the data to compare
278 * @len: number of bytes to compare
279 *
280 * verify function for 16bit buswith
281 */
282static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
283{
284 int i;
285 struct nand_chip *this = mtd->priv;
286 u16 *p = (u16 *) buf;
287 len >>= 1;
288
289 for (i=0; i<len; i++) {
290 if (p[i] != readw(this->IO_ADDR_R))
291 return -EFAULT;
292 au_sync();
293 }
294 return 0;
295}
296
297
298static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
299{
300 register struct nand_chip *this = mtd->priv;
301
302 switch(cmd){
303
304 case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break;
305 case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
306
307 case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
308 case NAND_CTL_CLRALE:
309 this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
310 /* FIXME: Nobody knows why this is neccecary,
311 * but it works only that way */
312 udelay(1);
313 break;
314
315 case NAND_CTL_SETNCE:
316 /* assert (force assert) chip enable */
317 au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;
318 break;
319
320 case NAND_CTL_CLRNCE:
321 /* deassert chip enable */
322 au_writel(0, MEM_STNDCTL); break;
323 break;
324 }
325
326 this->IO_ADDR_R = this->IO_ADDR_W;
327
328 /* Drain the writebuffer */
329 au_sync();
330}
331
332int au1550_device_ready(struct mtd_info *mtd)
333{
334 int ret = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;
335 au_sync();
336 return ret;
337}
338
339/*
340 * Main initialization routine
341 */
342int __init au1550_init (void)
343{
344 struct nand_chip *this;
345 u16 boot_swapboot = 0; /* default value */
346 int retval;
347
348 /* Allocate memory for MTD device structure and private data */
349 au1550_mtd = kmalloc (sizeof(struct mtd_info) +
350 sizeof (struct nand_chip), GFP_KERNEL);
351 if (!au1550_mtd) {
352 printk ("Unable to allocate NAND MTD dev structure.\n");
353 return -ENOMEM;
354 }
355
356 /* Get pointer to private data */
357 this = (struct nand_chip *) (&au1550_mtd[1]);
358
359 /* Initialize structures */
360 memset((char *) au1550_mtd, 0, sizeof(struct mtd_info));
361 memset((char *) this, 0, sizeof(struct nand_chip));
362
363 /* Link the private data with the MTD structure */
364 au1550_mtd->priv = this;
365
366
367 /* MEM_STNDCTL: disable ints, disable nand boot */
368 au_writel(0, MEM_STNDCTL);
369
370#ifdef CONFIG_MIPS_PB1550
371 /* set gpio206 high */
372 au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);
373
374 boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
375 ((bcsr->status >> 6) & 0x1);
376 switch (boot_swapboot) {
377 case 0:
378 case 2:
379 case 8:
380 case 0xC:
381 case 0xD:
382 /* x16 NAND Flash */
383 nand_width = 0;
384 break;
385 case 1:
386 case 9:
387 case 3:
388 case 0xE:
389 case 0xF:
390 /* x8 NAND Flash */
391 nand_width = 1;
392 break;
393 default:
394 printk("Pb1550 NAND: bad boot:swap\n");
395 retval = -EINVAL;
396 goto outmem;
397 }
398#endif
399
400 /* Configure RCE1 - should be done by YAMON */
401 au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */
402 au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */
403 au_sync();
404
405 /* setup and enable chip select, MEM_STADDR1 */
406 /* we really need to decode offsets only up till 0x20 */
407 au_writel((1<<28) | (NAND_PHYS_ADDR>>4) |
408 (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18),
409 MEM_STADDR1);
410 au_sync();
411
412 p_nand = ioremap(NAND_PHYS_ADDR, 0x1000);
413
414 /* Set address of hardware control function */
415 this->hwcontrol = au1550_hwcontrol;
416 this->dev_ready = au1550_device_ready;
417 /* 30 us command delay time */
418 this->chip_delay = 30;
419 this->eccmode = NAND_ECC_SOFT;
420
421 this->options = NAND_NO_AUTOINCR;
422
423 if (!nand_width)
424 this->options |= NAND_BUSWIDTH_16;
425
426 this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;
427 this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
428 this->write_word = au_write_word;
429 this->read_word = au_read_word;
430 this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;
431 this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;
432 this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf;
433
434 /* Scan to find existence of the device */
435 if (nand_scan (au1550_mtd, 1)) {
436 retval = -ENXIO;
437 goto outio;
438 }
439
440 /* Register the partitions */
441 add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS);
442
443 return 0;
444
445 outio:
446 iounmap ((void *)p_nand);
447
448 outmem:
449 kfree (au1550_mtd);
450 return retval;
451}
452
453module_init(au1550_init);
454
455/*
456 * Clean up routine
457 */
458#ifdef MODULE
459static void __exit au1550_cleanup (void)
460{
461 struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1];
462
463 /* Release resources, unregister device */
464 nand_release (au1550_mtd);
465
466 /* Free the MTD device structure */
467 kfree (au1550_mtd);
468
469 /* Unmap */
470 iounmap ((void *)p_nand);
471}
472module_exit(au1550_cleanup);
473#endif
474
475MODULE_LICENSE("GPL");
476MODULE_AUTHOR("Embedded Edge, LLC");
477MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");