[SUNSU]: Fix bogus locking in sunsu_change_mouse_baud()
[linux-2.6] / drivers / mtd / nand / au1550nd.c
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  */
44 static struct mtd_info *au1550_mtd = NULL;
45 static void __iomem *p_nand;
46 static int nand_width = 1; /* default x8*/
47
48 #define NAND_CS 1
49
50 /*
51  * Define partitions for flash device
52  */
53 const 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  */
89 static 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  */
104 static 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  */
118 static 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  */
134 static 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  */
148 static 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  */
164 static 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  */
179 static 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  */
198 static 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  */
217 static 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  */
239 static 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  */
261 static 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  */
282 static 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
298 static 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
332 int 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  */
342 int __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
453 module_init(au1550_init);
454
455 /*
456  * Clean up routine
457  */
458 #ifdef MODULE
459 static 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 }
472 module_exit(au1550_cleanup);
473 #endif
474
475 MODULE_LICENSE("GPL");
476 MODULE_AUTHOR("Embedded Edge, LLC");
477 MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");