blob: 407acb51469cd2b2b1af4a0ee2521513cdcd2b1c [file] [log] [blame]
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +09001/*
2 * SuperH FLCTL nand controller
3 *
Magnus Dammb79c7ad2010-02-02 13:01:25 +09004 * Copyright (c) 2008 Renesas Solutions Corp.
5 * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +09006 *
Magnus Dammb79c7ad2010-02-02 13:01:25 +09007 * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +09008 *
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090029#include <linux/slab.h>
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090030
31#include <linux/mtd/mtd.h>
32#include <linux/mtd/nand.h>
33#include <linux/mtd/partitions.h>
34#include <linux/mtd/sh_flctl.h>
35
36static struct nand_ecclayout flctl_4secc_oob_16 = {
37 .eccbytes = 10,
38 .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
39 .oobfree = {
40 {.offset = 12,
41 . length = 4} },
42};
43
44static struct nand_ecclayout flctl_4secc_oob_64 = {
45 .eccbytes = 10,
46 .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
47 .oobfree = {
48 {.offset = 60,
49 . length = 4} },
50};
51
52static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
53
54static struct nand_bbt_descr flctl_4secc_smallpage = {
55 .options = NAND_BBT_SCAN2NDPAGE,
56 .offs = 11,
57 .len = 1,
58 .pattern = scan_ff_pattern,
59};
60
61static struct nand_bbt_descr flctl_4secc_largepage = {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +090062 .options = NAND_BBT_SCAN2NDPAGE,
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090063 .offs = 58,
64 .len = 2,
65 .pattern = scan_ff_pattern,
66};
67
68static void empty_fifo(struct sh_flctl *flctl)
69{
70 writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */
71 writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */
72}
73
74static void start_translation(struct sh_flctl *flctl)
75{
76 writeb(TRSTRT, FLTRCR(flctl));
77}
78
Magnus Dammb79c7ad2010-02-02 13:01:25 +090079static void timeout_error(struct sh_flctl *flctl, const char *str)
80{
Lucas De Marchi25985ed2011-03-30 22:57:33 -030081 dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
Magnus Dammb79c7ad2010-02-02 13:01:25 +090082}
83
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090084static void wait_completion(struct sh_flctl *flctl)
85{
86 uint32_t timeout = LOOP_TIMEOUT_MAX;
87
88 while (timeout--) {
89 if (readb(FLTRCR(flctl)) & TREND) {
90 writeb(0x0, FLTRCR(flctl));
91 return;
92 }
93 udelay(1);
94 }
95
Magnus Dammb79c7ad2010-02-02 13:01:25 +090096 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090097 writeb(0x0, FLTRCR(flctl));
98}
99
100static void set_addr(struct mtd_info *mtd, int column, int page_addr)
101{
102 struct sh_flctl *flctl = mtd_to_flctl(mtd);
103 uint32_t addr = 0;
104
105 if (column == -1) {
106 addr = page_addr; /* ERASE1 */
107 } else if (page_addr != -1) {
108 /* SEQIN, READ0, etc.. */
Magnus Damm010ab822010-01-27 09:17:21 +0000109 if (flctl->chip.options & NAND_BUSWIDTH_16)
110 column >>= 1;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900111 if (flctl->page_size) {
112 addr = column & 0x0FFF;
113 addr |= (page_addr & 0xff) << 16;
114 addr |= ((page_addr >> 8) & 0xff) << 24;
115 /* big than 128MB */
116 if (flctl->rw_ADRCNT == ADRCNT2_E) {
117 uint32_t addr2;
118 addr2 = (page_addr >> 16) & 0xff;
119 writel(addr2, FLADR2(flctl));
120 }
121 } else {
122 addr = column;
123 addr |= (page_addr & 0xff) << 8;
124 addr |= ((page_addr >> 8) & 0xff) << 16;
125 addr |= ((page_addr >> 16) & 0xff) << 24;
126 }
127 }
128 writel(addr, FLADR(flctl));
129}
130
131static void wait_rfifo_ready(struct sh_flctl *flctl)
132{
133 uint32_t timeout = LOOP_TIMEOUT_MAX;
134
135 while (timeout--) {
136 uint32_t val;
137 /* check FIFO */
138 val = readl(FLDTCNTR(flctl)) >> 16;
139 if (val & 0xFF)
140 return;
141 udelay(1);
142 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900143 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900144}
145
146static void wait_wfifo_ready(struct sh_flctl *flctl)
147{
148 uint32_t len, timeout = LOOP_TIMEOUT_MAX;
149
150 while (timeout--) {
151 /* check FIFO */
152 len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
153 if (len >= 4)
154 return;
155 udelay(1);
156 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900157 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900158}
159
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900160static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900161{
162 uint32_t timeout = LOOP_TIMEOUT_MAX;
163 int checked[4];
164 void __iomem *ecc_reg[4];
165 int i;
166 uint32_t data, size;
167
168 memset(checked, 0, sizeof(checked));
169
170 while (timeout--) {
171 size = readl(FLDTCNTR(flctl)) >> 24;
172 if (size & 0xFF)
173 return 0; /* success */
174
175 if (readl(FL4ECCCR(flctl)) & _4ECCFA)
176 return 1; /* can't correct */
177
178 udelay(1);
179 if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
180 continue;
181
182 /* start error correction */
183 ecc_reg[0] = FL4ECCRESULT0(flctl);
184 ecc_reg[1] = FL4ECCRESULT1(flctl);
185 ecc_reg[2] = FL4ECCRESULT2(flctl);
186 ecc_reg[3] = FL4ECCRESULT3(flctl);
187
188 for (i = 0; i < 3; i++) {
189 data = readl(ecc_reg[i]);
190 if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
191 uint8_t org;
192 int index;
193
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900194 if (flctl->page_size)
195 index = (512 * sector_number) +
196 (data >> 16);
197 else
198 index = data >> 16;
199
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900200 org = flctl->done_buff[index];
201 flctl->done_buff[index] = org ^ (data & 0xFF);
202 checked[i] = 1;
203 }
204 }
205
206 writel(0, FL4ECCCR(flctl));
207 }
208
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900209 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900210 return 1; /* timeout */
211}
212
213static void wait_wecfifo_ready(struct sh_flctl *flctl)
214{
215 uint32_t timeout = LOOP_TIMEOUT_MAX;
216 uint32_t len;
217
218 while (timeout--) {
219 /* check FLECFIFO */
220 len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
221 if (len >= 4)
222 return;
223 udelay(1);
224 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900225 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900226}
227
228static void read_datareg(struct sh_flctl *flctl, int offset)
229{
230 unsigned long data;
231 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
232
233 wait_completion(flctl);
234
235 data = readl(FLDATAR(flctl));
236 *buf = le32_to_cpu(data);
237}
238
239static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
240{
241 int i, len_4align;
242 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
243 void *fifo_addr = (void *)FLDTFIFO(flctl);
244
245 len_4align = (rlen + 3) / 4;
246
247 for (i = 0; i < len_4align; i++) {
248 wait_rfifo_ready(flctl);
249 buf[i] = readl(fifo_addr);
250 buf[i] = be32_to_cpu(buf[i]);
251 }
252}
253
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900254static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900255{
256 int i;
257 unsigned long *ecc_buf = (unsigned long *)buff;
258 void *fifo_addr = (void *)FLECFIFO(flctl);
259
260 for (i = 0; i < 4; i++) {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900261 if (wait_recfifo_ready(flctl , sector))
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900262 return 1;
263 ecc_buf[i] = readl(fifo_addr);
264 ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
265 }
266
267 return 0;
268}
269
270static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
271{
272 int i, len_4align;
273 unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
274 void *fifo_addr = (void *)FLDTFIFO(flctl);
275
276 len_4align = (rlen + 3) / 4;
277 for (i = 0; i < len_4align; i++) {
278 wait_wfifo_ready(flctl);
279 writel(cpu_to_be32(data[i]), fifo_addr);
280 }
281}
282
283static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
284{
285 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Magnus Damm010ab822010-01-27 09:17:21 +0000286 uint32_t flcmncr_val = readl(FLCMNCR(flctl)) & ~SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900287 uint32_t flcmdcr_val, addr_len_bytes = 0;
288
289 /* Set SNAND bit if page size is 2048byte */
290 if (flctl->page_size)
291 flcmncr_val |= SNAND_E;
292 else
293 flcmncr_val &= ~SNAND_E;
294
295 /* default FLCMDCR val */
296 flcmdcr_val = DOCMD1_E | DOADR_E;
297
298 /* Set for FLCMDCR */
299 switch (cmd) {
300 case NAND_CMD_ERASE1:
301 addr_len_bytes = flctl->erase_ADRCNT;
302 flcmdcr_val |= DOCMD2_E;
303 break;
304 case NAND_CMD_READ0:
305 case NAND_CMD_READOOB:
306 addr_len_bytes = flctl->rw_ADRCNT;
307 flcmdcr_val |= CDSRC_E;
Magnus Damm010ab822010-01-27 09:17:21 +0000308 if (flctl->chip.options & NAND_BUSWIDTH_16)
309 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900310 break;
311 case NAND_CMD_SEQIN:
312 /* This case is that cmd is READ0 or READ1 or READ00 */
313 flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */
314 break;
315 case NAND_CMD_PAGEPROG:
316 addr_len_bytes = flctl->rw_ADRCNT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900317 flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
Magnus Damm010ab822010-01-27 09:17:21 +0000318 if (flctl->chip.options & NAND_BUSWIDTH_16)
319 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900320 break;
321 case NAND_CMD_READID:
322 flcmncr_val &= ~SNAND_E;
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100323 flcmdcr_val |= CDSRC_E;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900324 addr_len_bytes = ADRCNT_1;
325 break;
326 case NAND_CMD_STATUS:
327 case NAND_CMD_RESET:
328 flcmncr_val &= ~SNAND_E;
329 flcmdcr_val &= ~(DOADR_E | DOSR_E);
330 break;
331 default:
332 break;
333 }
334
335 /* Set address bytes parameter */
336 flcmdcr_val |= addr_len_bytes;
337
338 /* Now actually write */
339 writel(flcmncr_val, FLCMNCR(flctl));
340 writel(flcmdcr_val, FLCMDCR(flctl));
341 writel(flcmcdr_val, FLCMCDR(flctl));
342}
343
344static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Sneha Narnakaje46a8cf22009-09-18 12:51:46 -0700345 uint8_t *buf, int page)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900346{
347 int i, eccsize = chip->ecc.size;
348 int eccbytes = chip->ecc.bytes;
349 int eccsteps = chip->ecc.steps;
350 uint8_t *p = buf;
351 struct sh_flctl *flctl = mtd_to_flctl(mtd);
352
353 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
354 chip->read_buf(mtd, p, eccsize);
355
356 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
357 if (flctl->hwecc_cant_correct[i])
358 mtd->ecc_stats.failed++;
359 else
360 mtd->ecc_stats.corrected += 0;
361 }
362
363 return 0;
364}
365
366static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
367 const uint8_t *buf)
368{
369 int i, eccsize = chip->ecc.size;
370 int eccbytes = chip->ecc.bytes;
371 int eccsteps = chip->ecc.steps;
372 const uint8_t *p = buf;
373
374 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
375 chip->write_buf(mtd, p, eccsize);
376}
377
378static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
379{
380 struct sh_flctl *flctl = mtd_to_flctl(mtd);
381 int sector, page_sectors;
382
383 if (flctl->page_size)
384 page_sectors = 4;
385 else
386 page_sectors = 1;
387
388 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
389 FLCMNCR(flctl));
390
391 set_cmd_regs(mtd, NAND_CMD_READ0,
392 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
393
394 for (sector = 0; sector < page_sectors; sector++) {
395 int ret;
396
397 empty_fifo(flctl);
398 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
399 writel(page_addr << 2 | sector, FLADR(flctl));
400
401 start_translation(flctl);
402 read_fiforeg(flctl, 512, 512 * sector);
403
404 ret = read_ecfiforeg(flctl,
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900405 &flctl->done_buff[mtd->writesize + 16 * sector],
406 sector);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900407
408 if (ret)
409 flctl->hwecc_cant_correct[sector] = 1;
410
411 writel(0x0, FL4ECCCR(flctl));
412 wait_completion(flctl);
413 }
414 writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
415 FLCMNCR(flctl));
416}
417
418static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
419{
420 struct sh_flctl *flctl = mtd_to_flctl(mtd);
421
422 set_cmd_regs(mtd, NAND_CMD_READ0,
423 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
424
425 empty_fifo(flctl);
426 if (flctl->page_size) {
427 int i;
428 /* In case that the page size is 2k */
429 for (i = 0; i < 16 * 3; i++)
430 flctl->done_buff[i] = 0xFF;
431
432 set_addr(mtd, 3 * 528 + 512, page_addr);
433 writel(16, FLDTCNTR(flctl));
434
435 start_translation(flctl);
436 read_fiforeg(flctl, 16, 16 * 3);
437 wait_completion(flctl);
438 } else {
439 /* In case that the page size is 512b */
440 set_addr(mtd, 512, page_addr);
441 writel(16, FLDTCNTR(flctl));
442
443 start_translation(flctl);
444 read_fiforeg(flctl, 16, 0);
445 wait_completion(flctl);
446 }
447}
448
449static void execmd_write_page_sector(struct mtd_info *mtd)
450{
451 struct sh_flctl *flctl = mtd_to_flctl(mtd);
452 int i, page_addr = flctl->seqin_page_addr;
453 int sector, page_sectors;
454
455 if (flctl->page_size)
456 page_sectors = 4;
457 else
458 page_sectors = 1;
459
460 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
461
462 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
463 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
464
465 for (sector = 0; sector < page_sectors; sector++) {
466 empty_fifo(flctl);
467 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
468 writel(page_addr << 2 | sector, FLADR(flctl));
469
470 start_translation(flctl);
471 write_fiforeg(flctl, 512, 512 * sector);
472
473 for (i = 0; i < 4; i++) {
474 wait_wecfifo_ready(flctl); /* wait for write ready */
475 writel(0xFFFFFFFF, FLECFIFO(flctl));
476 }
477 wait_completion(flctl);
478 }
479
480 writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
481}
482
483static void execmd_write_oob(struct mtd_info *mtd)
484{
485 struct sh_flctl *flctl = mtd_to_flctl(mtd);
486 int page_addr = flctl->seqin_page_addr;
487 int sector, page_sectors;
488
489 if (flctl->page_size) {
490 sector = 3;
491 page_sectors = 4;
492 } else {
493 sector = 0;
494 page_sectors = 1;
495 }
496
497 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
498 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
499
500 for (; sector < page_sectors; sector++) {
501 empty_fifo(flctl);
502 set_addr(mtd, sector * 528 + 512, page_addr);
503 writel(16, FLDTCNTR(flctl)); /* set read size */
504
505 start_translation(flctl);
506 write_fiforeg(flctl, 16, 16 * sector);
507 wait_completion(flctl);
508 }
509}
510
511static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
512 int column, int page_addr)
513{
514 struct sh_flctl *flctl = mtd_to_flctl(mtd);
515 uint32_t read_cmd = 0;
516
517 flctl->read_bytes = 0;
518 if (command != NAND_CMD_PAGEPROG)
519 flctl->index = 0;
520
521 switch (command) {
522 case NAND_CMD_READ1:
523 case NAND_CMD_READ0:
524 if (flctl->hwecc) {
525 /* read page with hwecc */
526 execmd_read_page_sector(mtd, page_addr);
527 break;
528 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900529 if (flctl->page_size)
530 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
531 | command);
532 else
533 set_cmd_regs(mtd, command, command);
534
535 set_addr(mtd, 0, page_addr);
536
537 flctl->read_bytes = mtd->writesize + mtd->oobsize;
Magnus Damm010ab822010-01-27 09:17:21 +0000538 if (flctl->chip.options & NAND_BUSWIDTH_16)
539 column >>= 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900540 flctl->index += column;
541 goto read_normal_exit;
542
543 case NAND_CMD_READOOB:
544 if (flctl->hwecc) {
545 /* read page with hwecc */
546 execmd_read_oob(mtd, page_addr);
547 break;
548 }
549
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900550 if (flctl->page_size) {
551 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
552 | NAND_CMD_READ0);
553 set_addr(mtd, mtd->writesize, page_addr);
554 } else {
555 set_cmd_regs(mtd, command, command);
556 set_addr(mtd, 0, page_addr);
557 }
558 flctl->read_bytes = mtd->oobsize;
559 goto read_normal_exit;
560
561 case NAND_CMD_READID:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900562 set_cmd_regs(mtd, command, command);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900563
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100564 /* READID is always performed using an 8-bit bus */
565 if (flctl->chip.options & NAND_BUSWIDTH_16)
566 column <<= 1;
567 set_addr(mtd, column, 0);
568
569 flctl->read_bytes = 8;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900570 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100571 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900572 start_translation(flctl);
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100573 read_fiforeg(flctl, flctl->read_bytes, 0);
574 wait_completion(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900575 break;
576
577 case NAND_CMD_ERASE1:
578 flctl->erase1_page_addr = page_addr;
579 break;
580
581 case NAND_CMD_ERASE2:
582 set_cmd_regs(mtd, NAND_CMD_ERASE1,
583 (command << 8) | NAND_CMD_ERASE1);
584 set_addr(mtd, -1, flctl->erase1_page_addr);
585 start_translation(flctl);
586 wait_completion(flctl);
587 break;
588
589 case NAND_CMD_SEQIN:
590 if (!flctl->page_size) {
591 /* output read command */
592 if (column >= mtd->writesize) {
593 column -= mtd->writesize;
594 read_cmd = NAND_CMD_READOOB;
595 } else if (column < 256) {
596 read_cmd = NAND_CMD_READ0;
597 } else {
598 column -= 256;
599 read_cmd = NAND_CMD_READ1;
600 }
601 }
602 flctl->seqin_column = column;
603 flctl->seqin_page_addr = page_addr;
604 flctl->seqin_read_cmd = read_cmd;
605 break;
606
607 case NAND_CMD_PAGEPROG:
608 empty_fifo(flctl);
609 if (!flctl->page_size) {
610 set_cmd_regs(mtd, NAND_CMD_SEQIN,
611 flctl->seqin_read_cmd);
612 set_addr(mtd, -1, -1);
613 writel(0, FLDTCNTR(flctl)); /* set 0 size */
614 start_translation(flctl);
615 wait_completion(flctl);
616 }
617 if (flctl->hwecc) {
618 /* write page with hwecc */
619 if (flctl->seqin_column == mtd->writesize)
620 execmd_write_oob(mtd);
621 else if (!flctl->seqin_column)
622 execmd_write_page_sector(mtd);
623 else
624 printk(KERN_ERR "Invalid address !?\n");
625 break;
626 }
627 set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
628 set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
629 writel(flctl->index, FLDTCNTR(flctl)); /* set write size */
630 start_translation(flctl);
631 write_fiforeg(flctl, flctl->index, 0);
632 wait_completion(flctl);
633 break;
634
635 case NAND_CMD_STATUS:
636 set_cmd_regs(mtd, command, command);
637 set_addr(mtd, -1, -1);
638
639 flctl->read_bytes = 1;
640 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
641 start_translation(flctl);
642 read_datareg(flctl, 0); /* read and end */
643 break;
644
645 case NAND_CMD_RESET:
646 set_cmd_regs(mtd, command, command);
647 set_addr(mtd, -1, -1);
648
649 writel(0, FLDTCNTR(flctl)); /* set 0 size */
650 start_translation(flctl);
651 wait_completion(flctl);
652 break;
653
654 default:
655 break;
656 }
657 return;
658
659read_normal_exit:
660 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100661 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900662 start_translation(flctl);
663 read_fiforeg(flctl, flctl->read_bytes, 0);
664 wait_completion(flctl);
665 return;
666}
667
668static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
669{
670 struct sh_flctl *flctl = mtd_to_flctl(mtd);
671 uint32_t flcmncr_val = readl(FLCMNCR(flctl));
672
673 switch (chipnr) {
674 case -1:
675 flcmncr_val &= ~CE0_ENABLE;
676 writel(flcmncr_val, FLCMNCR(flctl));
677 break;
678 case 0:
679 flcmncr_val |= CE0_ENABLE;
680 writel(flcmncr_val, FLCMNCR(flctl));
681 break;
682 default:
683 BUG();
684 }
685}
686
687static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
688{
689 struct sh_flctl *flctl = mtd_to_flctl(mtd);
690 int i, index = flctl->index;
691
692 for (i = 0; i < len; i++)
693 flctl->done_buff[index + i] = buf[i];
694 flctl->index += len;
695}
696
697static uint8_t flctl_read_byte(struct mtd_info *mtd)
698{
699 struct sh_flctl *flctl = mtd_to_flctl(mtd);
700 int index = flctl->index;
701 uint8_t data;
702
703 data = flctl->done_buff[index];
704 flctl->index++;
705 return data;
706}
707
Magnus Damm010ab822010-01-27 09:17:21 +0000708static uint16_t flctl_read_word(struct mtd_info *mtd)
709{
710 struct sh_flctl *flctl = mtd_to_flctl(mtd);
711 int index = flctl->index;
712 uint16_t data;
713 uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
714
715 data = *buf;
716 flctl->index += 2;
717 return data;
718}
719
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900720static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
721{
722 int i;
723
724 for (i = 0; i < len; i++)
725 buf[i] = flctl_read_byte(mtd);
726}
727
728static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
729{
730 int i;
731
732 for (i = 0; i < len; i++)
733 if (buf[i] != flctl_read_byte(mtd))
734 return -EFAULT;
735 return 0;
736}
737
738static void flctl_register_init(struct sh_flctl *flctl, unsigned long val)
739{
740 writel(val, FLCMNCR(flctl));
741}
742
743static int flctl_chip_init_tail(struct mtd_info *mtd)
744{
745 struct sh_flctl *flctl = mtd_to_flctl(mtd);
746 struct nand_chip *chip = &flctl->chip;
747
748 if (mtd->writesize == 512) {
749 flctl->page_size = 0;
750 if (chip->chipsize > (32 << 20)) {
751 /* big than 32MB */
752 flctl->rw_ADRCNT = ADRCNT_4;
753 flctl->erase_ADRCNT = ADRCNT_3;
754 } else if (chip->chipsize > (2 << 16)) {
755 /* big than 128KB */
756 flctl->rw_ADRCNT = ADRCNT_3;
757 flctl->erase_ADRCNT = ADRCNT_2;
758 } else {
759 flctl->rw_ADRCNT = ADRCNT_2;
760 flctl->erase_ADRCNT = ADRCNT_1;
761 }
762 } else {
763 flctl->page_size = 1;
764 if (chip->chipsize > (128 << 20)) {
765 /* big than 128MB */
766 flctl->rw_ADRCNT = ADRCNT2_E;
767 flctl->erase_ADRCNT = ADRCNT_3;
768 } else if (chip->chipsize > (8 << 16)) {
769 /* big than 512KB */
770 flctl->rw_ADRCNT = ADRCNT_4;
771 flctl->erase_ADRCNT = ADRCNT_2;
772 } else {
773 flctl->rw_ADRCNT = ADRCNT_3;
774 flctl->erase_ADRCNT = ADRCNT_1;
775 }
776 }
777
778 if (flctl->hwecc) {
779 if (mtd->writesize == 512) {
780 chip->ecc.layout = &flctl_4secc_oob_16;
781 chip->badblock_pattern = &flctl_4secc_smallpage;
782 } else {
783 chip->ecc.layout = &flctl_4secc_oob_64;
784 chip->badblock_pattern = &flctl_4secc_largepage;
785 }
786
787 chip->ecc.size = 512;
788 chip->ecc.bytes = 10;
789 chip->ecc.read_page = flctl_read_page_hwecc;
790 chip->ecc.write_page = flctl_write_page_hwecc;
791 chip->ecc.mode = NAND_ECC_HW;
792
793 /* 4 symbols ECC enabled */
794 writel(readl(FLCMNCR(flctl)) | _4ECCEN | ECCPOS2 | ECCPOS_02,
795 FLCMNCR(flctl));
796 } else {
797 chip->ecc.mode = NAND_ECC_SOFT;
798 }
799
800 return 0;
801}
802
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900803static int __devinit flctl_probe(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900804{
805 struct resource *res;
806 struct sh_flctl *flctl;
807 struct mtd_info *flctl_mtd;
808 struct nand_chip *nand;
809 struct sh_flctl_platform_data *pdata;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900810 int ret = -ENXIO;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900811
812 pdata = pdev->dev.platform_data;
813 if (pdata == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900814 dev_err(&pdev->dev, "no platform data defined\n");
815 return -EINVAL;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900816 }
817
818 flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
819 if (!flctl) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900820 dev_err(&pdev->dev, "failed to allocate driver data\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900821 return -ENOMEM;
822 }
823
824 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
825 if (!res) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900826 dev_err(&pdev->dev, "failed to get I/O memory\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900827 goto err;
828 }
829
H Hartley Sweetencbd38a82009-12-14 16:59:27 -0500830 flctl->reg = ioremap(res->start, resource_size(res));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900831 if (flctl->reg == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900832 dev_err(&pdev->dev, "failed to remap I/O memory\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900833 goto err;
834 }
835
836 platform_set_drvdata(pdev, flctl);
837 flctl_mtd = &flctl->mtd;
838 nand = &flctl->chip;
839 flctl_mtd->priv = nand;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900840 flctl->pdev = pdev;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900841 flctl->hwecc = pdata->has_hwecc;
842
843 flctl_register_init(flctl, pdata->flcmncr_val);
844
845 nand->options = NAND_NO_AUTOINCR;
846
847 /* Set address of hardware control function */
848 /* 20 us command delay time */
849 nand->chip_delay = 20;
850
851 nand->read_byte = flctl_read_byte;
852 nand->write_buf = flctl_write_buf;
853 nand->read_buf = flctl_read_buf;
854 nand->verify_buf = flctl_verify_buf;
855 nand->select_chip = flctl_select_chip;
856 nand->cmdfunc = flctl_cmdfunc;
857
Magnus Damm010ab822010-01-27 09:17:21 +0000858 if (pdata->flcmncr_val & SEL_16BIT) {
859 nand->options |= NAND_BUSWIDTH_16;
860 nand->read_word = flctl_read_word;
861 }
862
David Woodhouse5e81e882010-02-26 18:32:56 +0000863 ret = nand_scan_ident(flctl_mtd, 1, NULL);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900864 if (ret)
865 goto err;
866
867 ret = flctl_chip_init_tail(flctl_mtd);
868 if (ret)
869 goto err;
870
871 ret = nand_scan_tail(flctl_mtd);
872 if (ret)
873 goto err;
874
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100875 mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900876
877 return 0;
878
879err:
880 kfree(flctl);
881 return ret;
882}
883
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900884static int __devexit flctl_remove(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900885{
886 struct sh_flctl *flctl = platform_get_drvdata(pdev);
887
888 nand_release(&flctl->mtd);
889 kfree(flctl);
890
891 return 0;
892}
893
894static struct platform_driver flctl_driver = {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900895 .remove = flctl_remove,
896 .driver = {
897 .name = "sh_flctl",
898 .owner = THIS_MODULE,
899 },
900};
901
902static int __init flctl_nand_init(void)
903{
David Woodhouse894572a2009-09-19 16:07:34 -0700904 return platform_driver_probe(&flctl_driver, flctl_probe);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900905}
906
907static void __exit flctl_nand_cleanup(void)
908{
909 platform_driver_unregister(&flctl_driver);
910}
911
912module_init(flctl_nand_init);
913module_exit(flctl_nand_cleanup);
914
915MODULE_LICENSE("GPL");
916MODULE_AUTHOR("Yoshihiro Shimoda");
917MODULE_DESCRIPTION("SuperH FLCTL driver");
918MODULE_ALIAS("platform:sh_flctl");