]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/mtd/nand/sh_flctl.c
600a76f5580e93d373b71177bc49c08c2084534f
[linux-2.6-omap-h63xx.git] / drivers / mtd / nand / sh_flctl.c
1 /*
2  * SuperH FLCTL nand controller
3  *
4  * Copyright © 2008 Renesas Solutions Corp.
5  * Copyright © 2008 Atom Create Engineering Co., Ltd.
6  *
7  * Based on fsl_elbc_nand.c, Copyright © 2006-2007 Freescale Semiconductor
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; version 2 of the License.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/delay.h>
27 #include <linux/io.h>
28 #include <linux/platform_device.h>
29
30 #include <linux/mtd/mtd.h>
31 #include <linux/mtd/nand.h>
32 #include <linux/mtd/partitions.h>
33 #include <linux/mtd/sh_flctl.h>
34
35 static struct nand_ecclayout flctl_4secc_oob_16 = {
36         .eccbytes = 10,
37         .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
38         .oobfree = {
39                 {.offset = 12,
40                 . length = 4} },
41 };
42
43 static struct nand_ecclayout flctl_4secc_oob_64 = {
44         .eccbytes = 10,
45         .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
46         .oobfree = {
47                 {.offset = 60,
48                 . length = 4} },
49 };
50
51 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
52
53 static struct nand_bbt_descr flctl_4secc_smallpage = {
54         .options = NAND_BBT_SCAN2NDPAGE,
55         .offs = 11,
56         .len = 1,
57         .pattern = scan_ff_pattern,
58 };
59
60 static struct nand_bbt_descr flctl_4secc_largepage = {
61         .options = 0,
62         .offs = 58,
63         .len = 2,
64         .pattern = scan_ff_pattern,
65 };
66
67 static void empty_fifo(struct sh_flctl *flctl)
68 {
69         writel(0x000c0000, FLINTDMACR(flctl));  /* FIFO Clear */
70         writel(0x00000000, FLINTDMACR(flctl));  /* Clear Error flags */
71 }
72
73 static void start_translation(struct sh_flctl *flctl)
74 {
75         writeb(TRSTRT, FLTRCR(flctl));
76 }
77
78 static void wait_completion(struct sh_flctl *flctl)
79 {
80         uint32_t timeout = LOOP_TIMEOUT_MAX;
81
82         while (timeout--) {
83                 if (readb(FLTRCR(flctl)) & TREND) {
84                         writeb(0x0, FLTRCR(flctl));
85                         return;
86                 }
87                 udelay(1);
88         }
89
90         printk(KERN_ERR "wait_completion(): Timeout occured \n");
91         writeb(0x0, FLTRCR(flctl));
92 }
93
94 static void set_addr(struct mtd_info *mtd, int column, int page_addr)
95 {
96         struct sh_flctl *flctl = mtd_to_flctl(mtd);
97         uint32_t addr = 0;
98
99         if (column == -1) {
100                 addr = page_addr;       /* ERASE1 */
101         } else if (page_addr != -1) {
102                 /* SEQIN, READ0, etc.. */
103                 if (flctl->page_size) {
104                         addr = column & 0x0FFF;
105                         addr |= (page_addr & 0xff) << 16;
106                         addr |= ((page_addr >> 8) & 0xff) << 24;
107                         /* big than 128MB */
108                         if (flctl->rw_ADRCNT == ADRCNT2_E) {
109                                 uint32_t        addr2;
110                                 addr2 = (page_addr >> 16) & 0xff;
111                                 writel(addr2, FLADR2(flctl));
112                         }
113                 } else {
114                         addr = column;
115                         addr |= (page_addr & 0xff) << 8;
116                         addr |= ((page_addr >> 8) & 0xff) << 16;
117                         addr |= ((page_addr >> 16) & 0xff) << 24;
118                 }
119         }
120         writel(addr, FLADR(flctl));
121 }
122
123 static void wait_rfifo_ready(struct sh_flctl *flctl)
124 {
125         uint32_t timeout = LOOP_TIMEOUT_MAX;
126
127         while (timeout--) {
128                 uint32_t val;
129                 /* check FIFO */
130                 val = readl(FLDTCNTR(flctl)) >> 16;
131                 if (val & 0xFF)
132                         return;
133                 udelay(1);
134         }
135         printk(KERN_ERR "wait_rfifo_ready(): Timeout occured \n");
136 }
137
138 static void wait_wfifo_ready(struct sh_flctl *flctl)
139 {
140         uint32_t len, timeout = LOOP_TIMEOUT_MAX;
141
142         while (timeout--) {
143                 /* check FIFO */
144                 len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
145                 if (len >= 4)
146                         return;
147                 udelay(1);
148         }
149         printk(KERN_ERR "wait_wfifo_ready(): Timeout occured \n");
150 }
151
152 static int wait_recfifo_ready(struct sh_flctl *flctl)
153 {
154         uint32_t timeout = LOOP_TIMEOUT_MAX;
155         int checked[4];
156         void __iomem *ecc_reg[4];
157         int i;
158         uint32_t data, size;
159
160         memset(checked, 0, sizeof(checked));
161
162         while (timeout--) {
163                 size = readl(FLDTCNTR(flctl)) >> 24;
164                 if (size & 0xFF)
165                         return 0;       /* success */
166
167                 if (readl(FL4ECCCR(flctl)) & _4ECCFA)
168                         return 1;       /* can't correct */
169
170                 udelay(1);
171                 if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
172                         continue;
173
174                 /* start error correction */
175                 ecc_reg[0] = FL4ECCRESULT0(flctl);
176                 ecc_reg[1] = FL4ECCRESULT1(flctl);
177                 ecc_reg[2] = FL4ECCRESULT2(flctl);
178                 ecc_reg[3] = FL4ECCRESULT3(flctl);
179
180                 for (i = 0; i < 3; i++) {
181                         data = readl(ecc_reg[i]);
182                         if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
183                                 uint8_t org;
184                                 int index;
185
186                                 index = data >> 16;
187                                 org = flctl->done_buff[index];
188                                 flctl->done_buff[index] = org ^ (data & 0xFF);
189                                 checked[i] = 1;
190                         }
191                 }
192
193                 writel(0, FL4ECCCR(flctl));
194         }
195
196         printk(KERN_ERR "wait_recfifo_ready(): Timeout occured \n");
197         return 1;       /* timeout */
198 }
199
200 static void wait_wecfifo_ready(struct sh_flctl *flctl)
201 {
202         uint32_t timeout = LOOP_TIMEOUT_MAX;
203         uint32_t len;
204
205         while (timeout--) {
206                 /* check FLECFIFO */
207                 len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
208                 if (len >= 4)
209                         return;
210                 udelay(1);
211         }
212         printk(KERN_ERR "wait_wecfifo_ready(): Timeout occured \n");
213 }
214
215 static void read_datareg(struct sh_flctl *flctl, int offset)
216 {
217         unsigned long data;
218         unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
219
220         wait_completion(flctl);
221
222         data = readl(FLDATAR(flctl));
223         *buf = le32_to_cpu(data);
224 }
225
226 static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
227 {
228         int i, len_4align;
229         unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
230         void *fifo_addr = (void *)FLDTFIFO(flctl);
231
232         len_4align = (rlen + 3) / 4;
233
234         for (i = 0; i < len_4align; i++) {
235                 wait_rfifo_ready(flctl);
236                 buf[i] = readl(fifo_addr);
237                 buf[i] = be32_to_cpu(buf[i]);
238         }
239 }
240
241 static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff)
242 {
243         int i;
244         unsigned long *ecc_buf = (unsigned long *)buff;
245         void *fifo_addr = (void *)FLECFIFO(flctl);
246
247         for (i = 0; i < 4; i++) {
248                 if (wait_recfifo_ready(flctl))
249                         return 1;
250                 ecc_buf[i] = readl(fifo_addr);
251                 ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
252         }
253
254         return 0;
255 }
256
257 static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
258 {
259         int i, len_4align;
260         unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
261         void *fifo_addr = (void *)FLDTFIFO(flctl);
262
263         len_4align = (rlen + 3) / 4;
264         for (i = 0; i < len_4align; i++) {
265                 wait_wfifo_ready(flctl);
266                 writel(cpu_to_be32(data[i]), fifo_addr);
267         }
268 }
269
270 static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
271 {
272         struct sh_flctl *flctl = mtd_to_flctl(mtd);
273         uint32_t flcmncr_val = readl(FLCMNCR(flctl));
274         uint32_t flcmdcr_val, addr_len_bytes = 0;
275
276         /* Set SNAND bit if page size is 2048byte */
277         if (flctl->page_size)
278                 flcmncr_val |= SNAND_E;
279         else
280                 flcmncr_val &= ~SNAND_E;
281
282         /* default FLCMDCR val */
283         flcmdcr_val = DOCMD1_E | DOADR_E;
284
285         /* Set for FLCMDCR */
286         switch (cmd) {
287         case NAND_CMD_ERASE1:
288                 addr_len_bytes = flctl->erase_ADRCNT;
289                 flcmdcr_val |= DOCMD2_E;
290                 break;
291         case NAND_CMD_READ0:
292         case NAND_CMD_READOOB:
293                 addr_len_bytes = flctl->rw_ADRCNT;
294                 flcmdcr_val |= CDSRC_E;
295                 break;
296         case NAND_CMD_SEQIN:
297                 /* This case is that cmd is READ0 or READ1 or READ00 */
298                 flcmdcr_val &= ~DOADR_E;        /* ONLY execute 1st cmd */
299                 break;
300         case NAND_CMD_PAGEPROG:
301                 addr_len_bytes = flctl->rw_ADRCNT;