blob: 48d5da0ec758a1d9e8f5ba972aee8720834507ef [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);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100286 uint32_t flcmncr_val = flctl->flcmncr_base & ~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:
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100306 case NAND_CMD_RNDOUT:
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900307 addr_len_bytes = flctl->rw_ADRCNT;
308 flcmdcr_val |= CDSRC_E;
Magnus Damm010ab822010-01-27 09:17:21 +0000309 if (flctl->chip.options & NAND_BUSWIDTH_16)
310 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900311 break;
312 case NAND_CMD_SEQIN:
313 /* This case is that cmd is READ0 or READ1 or READ00 */
314 flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */
315 break;
316 case NAND_CMD_PAGEPROG:
317 addr_len_bytes = flctl->rw_ADRCNT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900318 flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
Magnus Damm010ab822010-01-27 09:17:21 +0000319 if (flctl->chip.options & NAND_BUSWIDTH_16)
320 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900321 break;
322 case NAND_CMD_READID:
323 flcmncr_val &= ~SNAND_E;
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100324 flcmdcr_val |= CDSRC_E;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900325 addr_len_bytes = ADRCNT_1;
326 break;
327 case NAND_CMD_STATUS:
328 case NAND_CMD_RESET:
329 flcmncr_val &= ~SNAND_E;
330 flcmdcr_val &= ~(DOADR_E | DOSR_E);
331 break;
332 default:
333 break;
334 }
335
336 /* Set address bytes parameter */
337 flcmdcr_val |= addr_len_bytes;
338
339 /* Now actually write */
340 writel(flcmncr_val, FLCMNCR(flctl));
341 writel(flcmdcr_val, FLCMDCR(flctl));
342 writel(flcmcdr_val, FLCMCDR(flctl));
343}
344
345static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Sneha Narnakaje46a8cf22009-09-18 12:51:46 -0700346 uint8_t *buf, int page)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900347{
348 int i, eccsize = chip->ecc.size;
349 int eccbytes = chip->ecc.bytes;
350 int eccsteps = chip->ecc.steps;
351 uint8_t *p = buf;
352 struct sh_flctl *flctl = mtd_to_flctl(mtd);
353
354 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
355 chip->read_buf(mtd, p, eccsize);
356
357 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
358 if (flctl->hwecc_cant_correct[i])
359 mtd->ecc_stats.failed++;
360 else
361 mtd->ecc_stats.corrected += 0;
362 }
363
364 return 0;
365}
366
367static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
368 const uint8_t *buf)
369{
370 int i, eccsize = chip->ecc.size;
371 int eccbytes = chip->ecc.bytes;
372 int eccsteps = chip->ecc.steps;
373 const uint8_t *p = buf;
374
375 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
376 chip->write_buf(mtd, p, eccsize);
377}
378
379static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
380{
381 struct sh_flctl *flctl = mtd_to_flctl(mtd);
382 int sector, page_sectors;
383
384 if (flctl->page_size)
385 page_sectors = 4;
386 else
387 page_sectors = 1;
388
389 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
390 FLCMNCR(flctl));
391
392 set_cmd_regs(mtd, NAND_CMD_READ0,
393 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
394
395 for (sector = 0; sector < page_sectors; sector++) {
396 int ret;
397
398 empty_fifo(flctl);
399 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
400 writel(page_addr << 2 | sector, FLADR(flctl));
401
402 start_translation(flctl);
403 read_fiforeg(flctl, 512, 512 * sector);
404
405 ret = read_ecfiforeg(flctl,
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900406 &flctl->done_buff[mtd->writesize + 16 * sector],
407 sector);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900408
409 if (ret)
410 flctl->hwecc_cant_correct[sector] = 1;
411
412 writel(0x0, FL4ECCCR(flctl));
413 wait_completion(flctl);
414 }
415 writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
416 FLCMNCR(flctl));
417}
418
419static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
420{
421 struct sh_flctl *flctl = mtd_to_flctl(mtd);
422
423 set_cmd_regs(mtd, NAND_CMD_READ0,
424 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
425
426 empty_fifo(flctl);
427 if (flctl->page_size) {
428 int i;
429 /* In case that the page size is 2k */
430 for (i = 0; i < 16 * 3; i++)
431 flctl->done_buff[i] = 0xFF;
432
433 set_addr(mtd, 3 * 528 + 512, page_addr);
434 writel(16, FLDTCNTR(flctl));
435
436 start_translation(flctl);
437 read_fiforeg(flctl, 16, 16 * 3);
438 wait_completion(flctl);
439 } else {
440 /* In case that the page size is 512b */
441 set_addr(mtd, 512, page_addr);
442 writel(16, FLDTCNTR(flctl));
443
444 start_translation(flctl);
445 read_fiforeg(flctl, 16, 0);
446 wait_completion(flctl);
447 }
448}
449
450static void execmd_write_page_sector(struct mtd_info *mtd)
451{
452 struct sh_flctl *flctl = mtd_to_flctl(mtd);
453 int i, page_addr = flctl->seqin_page_addr;
454 int sector, page_sectors;
455
456 if (flctl->page_size)
457 page_sectors = 4;
458 else
459 page_sectors = 1;
460
461 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
462
463 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
464 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
465
466 for (sector = 0; sector < page_sectors; sector++) {
467 empty_fifo(flctl);
468 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
469 writel(page_addr << 2 | sector, FLADR(flctl));
470
471 start_translation(flctl);
472 write_fiforeg(flctl, 512, 512 * sector);
473
474 for (i = 0; i < 4; i++) {
475 wait_wecfifo_ready(flctl); /* wait for write ready */
476 writel(0xFFFFFFFF, FLECFIFO(flctl));
477 }
478 wait_completion(flctl);
479 }
480
481 writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
482}
483
484static void execmd_write_oob(struct mtd_info *mtd)
485{
486 struct sh_flctl *flctl = mtd_to_flctl(mtd);
487 int page_addr = flctl->seqin_page_addr;
488 int sector, page_sectors;
489
490 if (flctl->page_size) {
491 sector = 3;
492 page_sectors = 4;
493 } else {
494 sector = 0;
495 page_sectors = 1;
496 }
497
498 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
499 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
500
501 for (; sector < page_sectors; sector++) {
502 empty_fifo(flctl);
503 set_addr(mtd, sector * 528 + 512, page_addr);
504 writel(16, FLDTCNTR(flctl)); /* set read size */
505
506 start_translation(flctl);
507 write_fiforeg(flctl, 16, 16 * sector);
508 wait_completion(flctl);
509 }
510}
511
512static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
513 int column, int page_addr)
514{
515 struct sh_flctl *flctl = mtd_to_flctl(mtd);
516 uint32_t read_cmd = 0;
517
518 flctl->read_bytes = 0;
519 if (command != NAND_CMD_PAGEPROG)
520 flctl->index = 0;
521
522 switch (command) {
523 case NAND_CMD_READ1:
524 case NAND_CMD_READ0:
525 if (flctl->hwecc) {
526 /* read page with hwecc */
527 execmd_read_page_sector(mtd, page_addr);
528 break;
529 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900530 if (flctl->page_size)
531 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
532 | command);
533 else
534 set_cmd_regs(mtd, command, command);
535
536 set_addr(mtd, 0, page_addr);
537
538 flctl->read_bytes = mtd->writesize + mtd->oobsize;
Magnus Damm010ab822010-01-27 09:17:21 +0000539 if (flctl->chip.options & NAND_BUSWIDTH_16)
540 column >>= 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900541 flctl->index += column;
542 goto read_normal_exit;
543
544 case NAND_CMD_READOOB:
545 if (flctl->hwecc) {
546 /* read page with hwecc */
547 execmd_read_oob(mtd, page_addr);
548 break;
549 }
550
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900551 if (flctl->page_size) {
552 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
553 | NAND_CMD_READ0);
554 set_addr(mtd, mtd->writesize, page_addr);
555 } else {
556 set_cmd_regs(mtd, command, command);
557 set_addr(mtd, 0, page_addr);
558 }
559 flctl->read_bytes = mtd->oobsize;
560 goto read_normal_exit;
561
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100562 case NAND_CMD_RNDOUT:
563 if (flctl->hwecc)
564 break;
565
566 if (flctl->page_size)
567 set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
568 | command);
569 else
570 set_cmd_regs(mtd, command, command);
571
572 set_addr(mtd, column, 0);
573
574 flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
575 goto read_normal_exit;
576
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900577 case NAND_CMD_READID:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900578 set_cmd_regs(mtd, command, command);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900579
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100580 /* READID is always performed using an 8-bit bus */
581 if (flctl->chip.options & NAND_BUSWIDTH_16)
582 column <<= 1;
583 set_addr(mtd, column, 0);
584
585 flctl->read_bytes = 8;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900586 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100587 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900588 start_translation(flctl);
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100589 read_fiforeg(flctl, flctl->read_bytes, 0);
590 wait_completion(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900591 break;
592
593 case NAND_CMD_ERASE1:
594 flctl->erase1_page_addr = page_addr;
595 break;
596
597 case NAND_CMD_ERASE2:
598 set_cmd_regs(mtd, NAND_CMD_ERASE1,
599 (command << 8) | NAND_CMD_ERASE1);
600 set_addr(mtd, -1, flctl->erase1_page_addr);
601 start_translation(flctl);
602 wait_completion(flctl);
603 break;
604
605 case NAND_CMD_SEQIN:
606 if (!flctl->page_size) {
607 /* output read command */
608 if (column >= mtd->writesize) {
609 column -= mtd->writesize;
610 read_cmd = NAND_CMD_READOOB;
611 } else if (column < 256) {
612 read_cmd = NAND_CMD_READ0;
613 } else {
614 column -= 256;
615 read_cmd = NAND_CMD_READ1;
616 }
617 }
618 flctl->seqin_column = column;
619 flctl->seqin_page_addr = page_addr;
620 flctl->seqin_read_cmd = read_cmd;
621 break;
622
623 case NAND_CMD_PAGEPROG:
624 empty_fifo(flctl);
625 if (!flctl->page_size) {
626 set_cmd_regs(mtd, NAND_CMD_SEQIN,
627 flctl->seqin_read_cmd);
628 set_addr(mtd, -1, -1);
629 writel(0, FLDTCNTR(flctl)); /* set 0 size */
630 start_translation(flctl);
631 wait_completion(flctl);
632 }
633 if (flctl->hwecc) {
634 /* write page with hwecc */
635 if (flctl->seqin_column == mtd->writesize)
636 execmd_write_oob(mtd);
637 else if (!flctl->seqin_column)
638 execmd_write_page_sector(mtd);
639 else
640 printk(KERN_ERR "Invalid address !?\n");
641 break;
642 }
643 set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
644 set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
645 writel(flctl->index, FLDTCNTR(flctl)); /* set write size */
646 start_translation(flctl);
647 write_fiforeg(flctl, flctl->index, 0);
648 wait_completion(flctl);
649 break;
650
651 case NAND_CMD_STATUS:
652 set_cmd_regs(mtd, command, command);
653 set_addr(mtd, -1, -1);
654
655 flctl->read_bytes = 1;
656 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
657 start_translation(flctl);
658 read_datareg(flctl, 0); /* read and end */
659 break;
660
661 case NAND_CMD_RESET:
662 set_cmd_regs(mtd, command, command);
663 set_addr(mtd, -1, -1);
664
665 writel(0, FLDTCNTR(flctl)); /* set 0 size */
666 start_translation(flctl);
667 wait_completion(flctl);
668 break;
669
670 default:
671 break;
672 }
673 return;
674
675read_normal_exit:
676 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100677 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900678 start_translation(flctl);
679 read_fiforeg(flctl, flctl->read_bytes, 0);
680 wait_completion(flctl);
681 return;
682}
683
684static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
685{
686 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900687
688 switch (chipnr) {
689 case -1:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100690 flctl->flcmncr_base &= ~CE0_ENABLE;
691 writel(flctl->flcmncr_base, FLCMNCR(flctl));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900692 break;
693 case 0:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100694 flctl->flcmncr_base |= CE0_ENABLE;
695 writel(flctl->flcmncr_base, FLCMNCR(flctl));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900696 break;
697 default:
698 BUG();
699 }
700}
701
702static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
703{
704 struct sh_flctl *flctl = mtd_to_flctl(mtd);
705 int i, index = flctl->index;
706
707 for (i = 0; i < len; i++)
708 flctl->done_buff[index + i] = buf[i];
709 flctl->index += len;
710}
711
712static uint8_t flctl_read_byte(struct mtd_info *mtd)
713{
714 struct sh_flctl *flctl = mtd_to_flctl(mtd);
715 int index = flctl->index;
716 uint8_t data;
717
718 data = flctl->done_buff[index];
719 flctl->index++;
720 return data;
721}
722
Magnus Damm010ab822010-01-27 09:17:21 +0000723static uint16_t flctl_read_word(struct mtd_info *mtd)
724{
725 struct sh_flctl *flctl = mtd_to_flctl(mtd);
726 int index = flctl->index;
727 uint16_t data;
728 uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
729
730 data = *buf;
731 flctl->index += 2;
732 return data;
733}
734
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900735static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
736{
737 int i;
738
739 for (i = 0; i < len; i++)
740 buf[i] = flctl_read_byte(mtd);
741}
742
743static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
744{
745 int i;
746
747 for (i = 0; i < len; i++)
748 if (buf[i] != flctl_read_byte(mtd))
749 return -EFAULT;
750 return 0;
751}
752
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900753static int flctl_chip_init_tail(struct mtd_info *mtd)
754{
755 struct sh_flctl *flctl = mtd_to_flctl(mtd);
756 struct nand_chip *chip = &flctl->chip;
757
758 if (mtd->writesize == 512) {
759 flctl->page_size = 0;
760 if (chip->chipsize > (32 << 20)) {
761 /* big than 32MB */
762 flctl->rw_ADRCNT = ADRCNT_4;
763 flctl->erase_ADRCNT = ADRCNT_3;
764 } else if (chip->chipsize > (2 << 16)) {
765 /* big than 128KB */
766 flctl->rw_ADRCNT = ADRCNT_3;
767 flctl->erase_ADRCNT = ADRCNT_2;
768 } else {
769 flctl->rw_ADRCNT = ADRCNT_2;
770 flctl->erase_ADRCNT = ADRCNT_1;
771 }
772 } else {
773 flctl->page_size = 1;
774 if (chip->chipsize > (128 << 20)) {
775 /* big than 128MB */
776 flctl->rw_ADRCNT = ADRCNT2_E;
777 flctl->erase_ADRCNT = ADRCNT_3;
778 } else if (chip->chipsize > (8 << 16)) {
779 /* big than 512KB */
780 flctl->rw_ADRCNT = ADRCNT_4;
781 flctl->erase_ADRCNT = ADRCNT_2;
782 } else {
783 flctl->rw_ADRCNT = ADRCNT_3;
784 flctl->erase_ADRCNT = ADRCNT_1;
785 }
786 }
787
788 if (flctl->hwecc) {
789 if (mtd->writesize == 512) {
790 chip->ecc.layout = &flctl_4secc_oob_16;
791 chip->badblock_pattern = &flctl_4secc_smallpage;
792 } else {
793 chip->ecc.layout = &flctl_4secc_oob_64;
794 chip->badblock_pattern = &flctl_4secc_largepage;
795 }
796
797 chip->ecc.size = 512;
798 chip->ecc.bytes = 10;
799 chip->ecc.read_page = flctl_read_page_hwecc;
800 chip->ecc.write_page = flctl_write_page_hwecc;
801 chip->ecc.mode = NAND_ECC_HW;
802
803 /* 4 symbols ECC enabled */
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100804 flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900805 } else {
806 chip->ecc.mode = NAND_ECC_SOFT;
807 }
808
809 return 0;
810}
811
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900812static int __devinit flctl_probe(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900813{
814 struct resource *res;
815 struct sh_flctl *flctl;
816 struct mtd_info *flctl_mtd;
817 struct nand_chip *nand;
818 struct sh_flctl_platform_data *pdata;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900819 int ret = -ENXIO;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900820
821 pdata = pdev->dev.platform_data;
822 if (pdata == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900823 dev_err(&pdev->dev, "no platform data defined\n");
824 return -EINVAL;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900825 }
826
827 flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
828 if (!flctl) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900829 dev_err(&pdev->dev, "failed to allocate driver data\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900830 return -ENOMEM;
831 }
832
833 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
834 if (!res) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900835 dev_err(&pdev->dev, "failed to get I/O memory\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900836 goto err;
837 }
838
H Hartley Sweetencbd38a82009-12-14 16:59:27 -0500839 flctl->reg = ioremap(res->start, resource_size(res));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900840 if (flctl->reg == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900841 dev_err(&pdev->dev, "failed to remap I/O memory\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900842 goto err;
843 }
844
845 platform_set_drvdata(pdev, flctl);
846 flctl_mtd = &flctl->mtd;
847 nand = &flctl->chip;
848 flctl_mtd->priv = nand;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900849 flctl->pdev = pdev;
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100850 flctl->flcmncr_base = pdata->flcmncr_val;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900851 flctl->hwecc = pdata->has_hwecc;
852
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900853 nand->options = NAND_NO_AUTOINCR;
854
855 /* Set address of hardware control function */
856 /* 20 us command delay time */
857 nand->chip_delay = 20;
858
859 nand->read_byte = flctl_read_byte;
860 nand->write_buf = flctl_write_buf;
861 nand->read_buf = flctl_read_buf;
862 nand->verify_buf = flctl_verify_buf;
863 nand->select_chip = flctl_select_chip;
864 nand->cmdfunc = flctl_cmdfunc;
865
Magnus Damm010ab822010-01-27 09:17:21 +0000866 if (pdata->flcmncr_val & SEL_16BIT) {
867 nand->options |= NAND_BUSWIDTH_16;
868 nand->read_word = flctl_read_word;
869 }
870
David Woodhouse5e81e882010-02-26 18:32:56 +0000871 ret = nand_scan_ident(flctl_mtd, 1, NULL);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900872 if (ret)
873 goto err;
874
875 ret = flctl_chip_init_tail(flctl_mtd);
876 if (ret)
877 goto err;
878
879 ret = nand_scan_tail(flctl_mtd);
880 if (ret)
881 goto err;
882
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100883 mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900884
885 return 0;
886
887err:
888 kfree(flctl);
889 return ret;
890}
891
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900892static int __devexit flctl_remove(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900893{
894 struct sh_flctl *flctl = platform_get_drvdata(pdev);
895
896 nand_release(&flctl->mtd);
897 kfree(flctl);
898
899 return 0;
900}
901
902static struct platform_driver flctl_driver = {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900903 .remove = flctl_remove,
904 .driver = {
905 .name = "sh_flctl",
906 .owner = THIS_MODULE,
907 },
908};
909
910static int __init flctl_nand_init(void)
911{
David Woodhouse894572a2009-09-19 16:07:34 -0700912 return platform_driver_probe(&flctl_driver, flctl_probe);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900913}
914
915static void __exit flctl_nand_cleanup(void)
916{
917 platform_driver_unregister(&flctl_driver);
918}
919
920module_init(flctl_nand_init);
921module_exit(flctl_nand_cleanup);
922
923MODULE_LICENSE("GPL");
924MODULE_AUTHOR("Yoshihiro Shimoda");
925MODULE_DESCRIPTION("SuperH FLCTL driver");
926MODULE_ALIAS("platform:sh_flctl");