blob: e9b2b260de3ae081bbeb2e04bbff4d61902003b3 [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>
Bastian Hechtcfe78192012-03-18 15:13:20 +010029#include <linux/pm_runtime.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090030#include <linux/slab.h>
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090031
32#include <linux/mtd/mtd.h>
33#include <linux/mtd/nand.h>
34#include <linux/mtd/partitions.h>
35#include <linux/mtd/sh_flctl.h>
36
37static struct nand_ecclayout flctl_4secc_oob_16 = {
38 .eccbytes = 10,
39 .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
40 .oobfree = {
41 {.offset = 12,
42 . length = 4} },
43};
44
45static struct nand_ecclayout flctl_4secc_oob_64 = {
46 .eccbytes = 10,
47 .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
48 .oobfree = {
49 {.offset = 60,
50 . length = 4} },
51};
52
53static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
54
55static struct nand_bbt_descr flctl_4secc_smallpage = {
56 .options = NAND_BBT_SCAN2NDPAGE,
57 .offs = 11,
58 .len = 1,
59 .pattern = scan_ff_pattern,
60};
61
62static struct nand_bbt_descr flctl_4secc_largepage = {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +090063 .options = NAND_BBT_SCAN2NDPAGE,
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090064 .offs = 58,
65 .len = 2,
66 .pattern = scan_ff_pattern,
67};
68
69static void empty_fifo(struct sh_flctl *flctl)
70{
71 writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */
72 writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */
73}
74
75static void start_translation(struct sh_flctl *flctl)
76{
77 writeb(TRSTRT, FLTRCR(flctl));
78}
79
Magnus Dammb79c7ad2010-02-02 13:01:25 +090080static void timeout_error(struct sh_flctl *flctl, const char *str)
81{
Lucas De Marchi25985ed2011-03-30 22:57:33 -030082 dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
Magnus Dammb79c7ad2010-02-02 13:01:25 +090083}
84
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090085static void wait_completion(struct sh_flctl *flctl)
86{
87 uint32_t timeout = LOOP_TIMEOUT_MAX;
88
89 while (timeout--) {
90 if (readb(FLTRCR(flctl)) & TREND) {
91 writeb(0x0, FLTRCR(flctl));
92 return;
93 }
94 udelay(1);
95 }
96
Magnus Dammb79c7ad2010-02-02 13:01:25 +090097 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090098 writeb(0x0, FLTRCR(flctl));
99}
100
101static void set_addr(struct mtd_info *mtd, int column, int page_addr)
102{
103 struct sh_flctl *flctl = mtd_to_flctl(mtd);
104 uint32_t addr = 0;
105
106 if (column == -1) {
107 addr = page_addr; /* ERASE1 */
108 } else if (page_addr != -1) {
109 /* SEQIN, READ0, etc.. */
Magnus Damm010ab822010-01-27 09:17:21 +0000110 if (flctl->chip.options & NAND_BUSWIDTH_16)
111 column >>= 1;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900112 if (flctl->page_size) {
113 addr = column & 0x0FFF;
114 addr |= (page_addr & 0xff) << 16;
115 addr |= ((page_addr >> 8) & 0xff) << 24;
116 /* big than 128MB */
117 if (flctl->rw_ADRCNT == ADRCNT2_E) {
118 uint32_t addr2;
119 addr2 = (page_addr >> 16) & 0xff;
120 writel(addr2, FLADR2(flctl));
121 }
122 } else {
123 addr = column;
124 addr |= (page_addr & 0xff) << 8;
125 addr |= ((page_addr >> 8) & 0xff) << 16;
126 addr |= ((page_addr >> 16) & 0xff) << 24;
127 }
128 }
129 writel(addr, FLADR(flctl));
130}
131
132static void wait_rfifo_ready(struct sh_flctl *flctl)
133{
134 uint32_t timeout = LOOP_TIMEOUT_MAX;
135
136 while (timeout--) {
137 uint32_t val;
138 /* check FIFO */
139 val = readl(FLDTCNTR(flctl)) >> 16;
140 if (val & 0xFF)
141 return;
142 udelay(1);
143 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900144 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900145}
146
147static void wait_wfifo_ready(struct sh_flctl *flctl)
148{
149 uint32_t len, timeout = LOOP_TIMEOUT_MAX;
150
151 while (timeout--) {
152 /* check FIFO */
153 len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
154 if (len >= 4)
155 return;
156 udelay(1);
157 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900158 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900159}
160
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900161static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900162{
163 uint32_t timeout = LOOP_TIMEOUT_MAX;
164 int checked[4];
165 void __iomem *ecc_reg[4];
166 int i;
167 uint32_t data, size;
168
169 memset(checked, 0, sizeof(checked));
170
171 while (timeout--) {
172 size = readl(FLDTCNTR(flctl)) >> 24;
173 if (size & 0xFF)
174 return 0; /* success */
175
176 if (readl(FL4ECCCR(flctl)) & _4ECCFA)
177 return 1; /* can't correct */
178
179 udelay(1);
180 if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
181 continue;
182
183 /* start error correction */
184 ecc_reg[0] = FL4ECCRESULT0(flctl);
185 ecc_reg[1] = FL4ECCRESULT1(flctl);
186 ecc_reg[2] = FL4ECCRESULT2(flctl);
187 ecc_reg[3] = FL4ECCRESULT3(flctl);
188
189 for (i = 0; i < 3; i++) {
190 data = readl(ecc_reg[i]);
191 if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
192 uint8_t org;
193 int index;
194
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900195 if (flctl->page_size)
196 index = (512 * sector_number) +
197 (data >> 16);
198 else
199 index = data >> 16;
200
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900201 org = flctl->done_buff[index];
202 flctl->done_buff[index] = org ^ (data & 0xFF);
203 checked[i] = 1;
204 }
205 }
206
207 writel(0, FL4ECCCR(flctl));
208 }
209
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900210 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900211 return 1; /* timeout */
212}
213
214static void wait_wecfifo_ready(struct sh_flctl *flctl)
215{
216 uint32_t timeout = LOOP_TIMEOUT_MAX;
217 uint32_t len;
218
219 while (timeout--) {
220 /* check FLECFIFO */
221 len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
222 if (len >= 4)
223 return;
224 udelay(1);
225 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900226 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900227}
228
229static void read_datareg(struct sh_flctl *flctl, int offset)
230{
231 unsigned long data;
232 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
233
234 wait_completion(flctl);
235
236 data = readl(FLDATAR(flctl));
237 *buf = le32_to_cpu(data);
238}
239
240static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
241{
242 int i, len_4align;
243 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
244 void *fifo_addr = (void *)FLDTFIFO(flctl);
245
246 len_4align = (rlen + 3) / 4;
247
248 for (i = 0; i < len_4align; i++) {
249 wait_rfifo_ready(flctl);
250 buf[i] = readl(fifo_addr);
251 buf[i] = be32_to_cpu(buf[i]);
252 }
253}
254
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900255static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900256{
257 int i;
258 unsigned long *ecc_buf = (unsigned long *)buff;
259 void *fifo_addr = (void *)FLECFIFO(flctl);
260
261 for (i = 0; i < 4; i++) {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900262 if (wait_recfifo_ready(flctl , sector))
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900263 return 1;
264 ecc_buf[i] = readl(fifo_addr);
265 ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
266 }
267
268 return 0;
269}
270
271static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
272{
273 int i, len_4align;
274 unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
275 void *fifo_addr = (void *)FLDTFIFO(flctl);
276
277 len_4align = (rlen + 3) / 4;
278 for (i = 0; i < len_4align; i++) {
279 wait_wfifo_ready(flctl);
280 writel(cpu_to_be32(data[i]), fifo_addr);
281 }
282}
283
284static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
285{
286 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100287 uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900288 uint32_t flcmdcr_val, addr_len_bytes = 0;
289
290 /* Set SNAND bit if page size is 2048byte */
291 if (flctl->page_size)
292 flcmncr_val |= SNAND_E;
293 else
294 flcmncr_val &= ~SNAND_E;
295
296 /* default FLCMDCR val */
297 flcmdcr_val = DOCMD1_E | DOADR_E;
298
299 /* Set for FLCMDCR */
300 switch (cmd) {
301 case NAND_CMD_ERASE1:
302 addr_len_bytes = flctl->erase_ADRCNT;
303 flcmdcr_val |= DOCMD2_E;
304 break;
305 case NAND_CMD_READ0:
306 case NAND_CMD_READOOB:
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100307 case NAND_CMD_RNDOUT:
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900308 addr_len_bytes = flctl->rw_ADRCNT;
309 flcmdcr_val |= CDSRC_E;
Magnus Damm010ab822010-01-27 09:17:21 +0000310 if (flctl->chip.options & NAND_BUSWIDTH_16)
311 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900312 break;
313 case NAND_CMD_SEQIN:
314 /* This case is that cmd is READ0 or READ1 or READ00 */
315 flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */
316 break;
317 case NAND_CMD_PAGEPROG:
318 addr_len_bytes = flctl->rw_ADRCNT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900319 flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
Magnus Damm010ab822010-01-27 09:17:21 +0000320 if (flctl->chip.options & NAND_BUSWIDTH_16)
321 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900322 break;
323 case NAND_CMD_READID:
324 flcmncr_val &= ~SNAND_E;
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100325 flcmdcr_val |= CDSRC_E;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900326 addr_len_bytes = ADRCNT_1;
327 break;
328 case NAND_CMD_STATUS:
329 case NAND_CMD_RESET:
330 flcmncr_val &= ~SNAND_E;
331 flcmdcr_val &= ~(DOADR_E | DOSR_E);
332 break;
333 default:
334 break;
335 }
336
337 /* Set address bytes parameter */
338 flcmdcr_val |= addr_len_bytes;
339
340 /* Now actually write */
341 writel(flcmncr_val, FLCMNCR(flctl));
342 writel(flcmdcr_val, FLCMDCR(flctl));
343 writel(flcmcdr_val, FLCMCDR(flctl));
344}
345
346static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Sneha Narnakaje46a8cf22009-09-18 12:51:46 -0700347 uint8_t *buf, int page)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900348{
349 int i, eccsize = chip->ecc.size;
350 int eccbytes = chip->ecc.bytes;
351 int eccsteps = chip->ecc.steps;
352 uint8_t *p = buf;
353 struct sh_flctl *flctl = mtd_to_flctl(mtd);
354
355 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
356 chip->read_buf(mtd, p, eccsize);
357
358 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
359 if (flctl->hwecc_cant_correct[i])
360 mtd->ecc_stats.failed++;
361 else
362 mtd->ecc_stats.corrected += 0;
363 }
364
365 return 0;
366}
367
368static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
369 const uint8_t *buf)
370{
371 int i, eccsize = chip->ecc.size;
372 int eccbytes = chip->ecc.bytes;
373 int eccsteps = chip->ecc.steps;
374 const uint8_t *p = buf;
375
376 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
377 chip->write_buf(mtd, p, eccsize);
378}
379
380static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
381{
382 struct sh_flctl *flctl = mtd_to_flctl(mtd);
383 int sector, page_sectors;
384
385 if (flctl->page_size)
386 page_sectors = 4;
387 else
388 page_sectors = 1;
389
390 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
391 FLCMNCR(flctl));
392
393 set_cmd_regs(mtd, NAND_CMD_READ0,
394 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
395
396 for (sector = 0; sector < page_sectors; sector++) {
397 int ret;
398
399 empty_fifo(flctl);
400 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
401 writel(page_addr << 2 | sector, FLADR(flctl));
402
403 start_translation(flctl);
404 read_fiforeg(flctl, 512, 512 * sector);
405
406 ret = read_ecfiforeg(flctl,
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900407 &flctl->done_buff[mtd->writesize + 16 * sector],
408 sector);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900409
410 if (ret)
411 flctl->hwecc_cant_correct[sector] = 1;
412
413 writel(0x0, FL4ECCCR(flctl));
414 wait_completion(flctl);
415 }
416 writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
417 FLCMNCR(flctl));
418}
419
420static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
421{
422 struct sh_flctl *flctl = mtd_to_flctl(mtd);
423
424 set_cmd_regs(mtd, NAND_CMD_READ0,
425 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
426
427 empty_fifo(flctl);
428 if (flctl->page_size) {
429 int i;
430 /* In case that the page size is 2k */
431 for (i = 0; i < 16 * 3; i++)
432 flctl->done_buff[i] = 0xFF;
433
434 set_addr(mtd, 3 * 528 + 512, page_addr);
435 writel(16, FLDTCNTR(flctl));
436
437 start_translation(flctl);
438 read_fiforeg(flctl, 16, 16 * 3);
439 wait_completion(flctl);
440 } else {
441 /* In case that the page size is 512b */
442 set_addr(mtd, 512, page_addr);
443 writel(16, FLDTCNTR(flctl));
444
445 start_translation(flctl);
446 read_fiforeg(flctl, 16, 0);
447 wait_completion(flctl);
448 }
449}
450
451static void execmd_write_page_sector(struct mtd_info *mtd)
452{
453 struct sh_flctl *flctl = mtd_to_flctl(mtd);
454 int i, page_addr = flctl->seqin_page_addr;
455 int sector, page_sectors;
456
457 if (flctl->page_size)
458 page_sectors = 4;
459 else
460 page_sectors = 1;
461
462 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
463
464 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
465 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
466
467 for (sector = 0; sector < page_sectors; sector++) {
468 empty_fifo(flctl);
469 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
470 writel(page_addr << 2 | sector, FLADR(flctl));
471
472 start_translation(flctl);
473 write_fiforeg(flctl, 512, 512 * sector);
474
475 for (i = 0; i < 4; i++) {
476 wait_wecfifo_ready(flctl); /* wait for write ready */
477 writel(0xFFFFFFFF, FLECFIFO(flctl));
478 }
479 wait_completion(flctl);
480 }
481
482 writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
483}
484
485static void execmd_write_oob(struct mtd_info *mtd)
486{
487 struct sh_flctl *flctl = mtd_to_flctl(mtd);
488 int page_addr = flctl->seqin_page_addr;
489 int sector, page_sectors;
490
491 if (flctl->page_size) {
492 sector = 3;
493 page_sectors = 4;
494 } else {
495 sector = 0;
496 page_sectors = 1;
497 }
498
499 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
500 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
501
502 for (; sector < page_sectors; sector++) {
503 empty_fifo(flctl);
504 set_addr(mtd, sector * 528 + 512, page_addr);
505 writel(16, FLDTCNTR(flctl)); /* set read size */
506
507 start_translation(flctl);
508 write_fiforeg(flctl, 16, 16 * sector);
509 wait_completion(flctl);
510 }
511}
512
513static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
514 int column, int page_addr)
515{
516 struct sh_flctl *flctl = mtd_to_flctl(mtd);
517 uint32_t read_cmd = 0;
518
Bastian Hechtcfe78192012-03-18 15:13:20 +0100519 pm_runtime_get_sync(&flctl->pdev->dev);
520
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900521 flctl->read_bytes = 0;
522 if (command != NAND_CMD_PAGEPROG)
523 flctl->index = 0;
524
525 switch (command) {
526 case NAND_CMD_READ1:
527 case NAND_CMD_READ0:
528 if (flctl->hwecc) {
529 /* read page with hwecc */
530 execmd_read_page_sector(mtd, page_addr);
531 break;
532 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900533 if (flctl->page_size)
534 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
535 | command);
536 else
537 set_cmd_regs(mtd, command, command);
538
539 set_addr(mtd, 0, page_addr);
540
541 flctl->read_bytes = mtd->writesize + mtd->oobsize;
Magnus Damm010ab822010-01-27 09:17:21 +0000542 if (flctl->chip.options & NAND_BUSWIDTH_16)
543 column >>= 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900544 flctl->index += column;
545 goto read_normal_exit;
546
547 case NAND_CMD_READOOB:
548 if (flctl->hwecc) {
549 /* read page with hwecc */
550 execmd_read_oob(mtd, page_addr);
551 break;
552 }
553
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900554 if (flctl->page_size) {
555 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
556 | NAND_CMD_READ0);
557 set_addr(mtd, mtd->writesize, page_addr);
558 } else {
559 set_cmd_regs(mtd, command, command);
560 set_addr(mtd, 0, page_addr);
561 }
562 flctl->read_bytes = mtd->oobsize;
563 goto read_normal_exit;
564
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100565 case NAND_CMD_RNDOUT:
566 if (flctl->hwecc)
567 break;
568
569 if (flctl->page_size)
570 set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
571 | command);
572 else
573 set_cmd_regs(mtd, command, command);
574
575 set_addr(mtd, column, 0);
576
577 flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
578 goto read_normal_exit;
579
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900580 case NAND_CMD_READID:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900581 set_cmd_regs(mtd, command, command);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900582
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100583 /* READID is always performed using an 8-bit bus */
584 if (flctl->chip.options & NAND_BUSWIDTH_16)
585 column <<= 1;
586 set_addr(mtd, column, 0);
587
588 flctl->read_bytes = 8;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900589 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100590 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900591 start_translation(flctl);
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100592 read_fiforeg(flctl, flctl->read_bytes, 0);
593 wait_completion(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900594 break;
595
596 case NAND_CMD_ERASE1:
597 flctl->erase1_page_addr = page_addr;
598 break;
599
600 case NAND_CMD_ERASE2:
601 set_cmd_regs(mtd, NAND_CMD_ERASE1,
602 (command << 8) | NAND_CMD_ERASE1);
603 set_addr(mtd, -1, flctl->erase1_page_addr);
604 start_translation(flctl);
605 wait_completion(flctl);
606 break;
607
608 case NAND_CMD_SEQIN:
609 if (!flctl->page_size) {
610 /* output read command */
611 if (column >= mtd->writesize) {
612 column -= mtd->writesize;
613 read_cmd = NAND_CMD_READOOB;
614 } else if (column < 256) {
615 read_cmd = NAND_CMD_READ0;
616 } else {
617 column -= 256;
618 read_cmd = NAND_CMD_READ1;
619 }
620 }
621 flctl->seqin_column = column;
622 flctl->seqin_page_addr = page_addr;
623 flctl->seqin_read_cmd = read_cmd;
624 break;
625
626 case NAND_CMD_PAGEPROG:
627 empty_fifo(flctl);
628 if (!flctl->page_size) {
629 set_cmd_regs(mtd, NAND_CMD_SEQIN,
630 flctl->seqin_read_cmd);
631 set_addr(mtd, -1, -1);
632 writel(0, FLDTCNTR(flctl)); /* set 0 size */
633 start_translation(flctl);
634 wait_completion(flctl);
635 }
636 if (flctl->hwecc) {
637 /* write page with hwecc */
638 if (flctl->seqin_column == mtd->writesize)
639 execmd_write_oob(mtd);
640 else if (!flctl->seqin_column)
641 execmd_write_page_sector(mtd);
642 else
643 printk(KERN_ERR "Invalid address !?\n");
644 break;
645 }
646 set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
647 set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
648 writel(flctl->index, FLDTCNTR(flctl)); /* set write size */
649 start_translation(flctl);
650 write_fiforeg(flctl, flctl->index, 0);
651 wait_completion(flctl);
652 break;
653
654 case NAND_CMD_STATUS:
655 set_cmd_regs(mtd, command, command);
656 set_addr(mtd, -1, -1);
657
658 flctl->read_bytes = 1;
659 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
660 start_translation(flctl);
661 read_datareg(flctl, 0); /* read and end */
662 break;
663
664 case NAND_CMD_RESET:
665 set_cmd_regs(mtd, command, command);
666 set_addr(mtd, -1, -1);
667
668 writel(0, FLDTCNTR(flctl)); /* set 0 size */
669 start_translation(flctl);
670 wait_completion(flctl);
671 break;
672
673 default:
674 break;
675 }
Bastian Hechtcfe78192012-03-18 15:13:20 +0100676 goto runtime_exit;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900677
678read_normal_exit:
679 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100680 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900681 start_translation(flctl);
682 read_fiforeg(flctl, flctl->read_bytes, 0);
683 wait_completion(flctl);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100684runtime_exit:
685 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900686 return;
687}
688
689static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
690{
691 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100692 int ret;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900693
694 switch (chipnr) {
695 case -1:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100696 flctl->flcmncr_base &= ~CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100697
698 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100699 writel(flctl->flcmncr_base, FLCMNCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100700
701 if (flctl->qos_request) {
702 dev_pm_qos_remove_request(&flctl->pm_qos);
703 flctl->qos_request = 0;
704 }
705
706 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900707 break;
708 case 0:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100709 flctl->flcmncr_base |= CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100710
711 if (!flctl->qos_request) {
712 ret = dev_pm_qos_add_request(&flctl->pdev->dev,
713 &flctl->pm_qos, 100);
714 if (ret < 0)
715 dev_err(&flctl->pdev->dev,
716 "PM QoS request failed: %d\n", ret);
717 flctl->qos_request = 1;
718 }
719
720 if (flctl->holden) {
721 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100722 writel(HOLDEN, FLHOLDCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100723 pm_runtime_put_sync(&flctl->pdev->dev);
724 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900725 break;
726 default:
727 BUG();
728 }
729}
730
731static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
732{
733 struct sh_flctl *flctl = mtd_to_flctl(mtd);
734 int i, index = flctl->index;
735
736 for (i = 0; i < len; i++)
737 flctl->done_buff[index + i] = buf[i];
738 flctl->index += len;
739}
740
741static uint8_t flctl_read_byte(struct mtd_info *mtd)
742{
743 struct sh_flctl *flctl = mtd_to_flctl(mtd);
744 int index = flctl->index;
745 uint8_t data;
746
747 data = flctl->done_buff[index];
748 flctl->index++;
749 return data;
750}
751
Magnus Damm010ab822010-01-27 09:17:21 +0000752static uint16_t flctl_read_word(struct mtd_info *mtd)
753{
754 struct sh_flctl *flctl = mtd_to_flctl(mtd);
755 int index = flctl->index;
756 uint16_t data;
757 uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
758
759 data = *buf;
760 flctl->index += 2;
761 return data;
762}
763
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900764static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
765{
766 int i;
767
768 for (i = 0; i < len; i++)
769 buf[i] = flctl_read_byte(mtd);
770}
771
772static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
773{
774 int i;
775
776 for (i = 0; i < len; i++)
777 if (buf[i] != flctl_read_byte(mtd))
778 return -EFAULT;
779 return 0;
780}
781
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900782static int flctl_chip_init_tail(struct mtd_info *mtd)
783{
784 struct sh_flctl *flctl = mtd_to_flctl(mtd);
785 struct nand_chip *chip = &flctl->chip;
786
787 if (mtd->writesize == 512) {
788 flctl->page_size = 0;
789 if (chip->chipsize > (32 << 20)) {
790 /* big than 32MB */
791 flctl->rw_ADRCNT = ADRCNT_4;
792 flctl->erase_ADRCNT = ADRCNT_3;
793 } else if (chip->chipsize > (2 << 16)) {
794 /* big than 128KB */
795 flctl->rw_ADRCNT = ADRCNT_3;
796 flctl->erase_ADRCNT = ADRCNT_2;
797 } else {
798 flctl->rw_ADRCNT = ADRCNT_2;
799 flctl->erase_ADRCNT = ADRCNT_1;
800 }
801 } else {
802 flctl->page_size = 1;
803 if (chip->chipsize > (128 << 20)) {
804 /* big than 128MB */
805 flctl->rw_ADRCNT = ADRCNT2_E;
806 flctl->erase_ADRCNT = ADRCNT_3;
807 } else if (chip->chipsize > (8 << 16)) {
808 /* big than 512KB */
809 flctl->rw_ADRCNT = ADRCNT_4;
810 flctl->erase_ADRCNT = ADRCNT_2;
811 } else {
812 flctl->rw_ADRCNT = ADRCNT_3;
813 flctl->erase_ADRCNT = ADRCNT_1;
814 }
815 }
816
817 if (flctl->hwecc) {
818 if (mtd->writesize == 512) {
819 chip->ecc.layout = &flctl_4secc_oob_16;
820 chip->badblock_pattern = &flctl_4secc_smallpage;
821 } else {
822 chip->ecc.layout = &flctl_4secc_oob_64;
823 chip->badblock_pattern = &flctl_4secc_largepage;
824 }
825
826 chip->ecc.size = 512;
827 chip->ecc.bytes = 10;
Mike Dunn6a918ba2012-03-11 14:21:11 -0700828 chip->ecc.strength = 4;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900829 chip->ecc.read_page = flctl_read_page_hwecc;
830 chip->ecc.write_page = flctl_write_page_hwecc;
831 chip->ecc.mode = NAND_ECC_HW;
832
833 /* 4 symbols ECC enabled */
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100834 flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900835 } else {
836 chip->ecc.mode = NAND_ECC_SOFT;
837 }
838
839 return 0;
840}
841
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900842static int __devinit flctl_probe(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900843{
844 struct resource *res;
845 struct sh_flctl *flctl;
846 struct mtd_info *flctl_mtd;
847 struct nand_chip *nand;
848 struct sh_flctl_platform_data *pdata;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900849 int ret = -ENXIO;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900850
851 pdata = pdev->dev.platform_data;
852 if (pdata == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900853 dev_err(&pdev->dev, "no platform data defined\n");
854 return -EINVAL;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900855 }
856
857 flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
858 if (!flctl) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900859 dev_err(&pdev->dev, "failed to allocate driver data\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900860 return -ENOMEM;
861 }
862
863 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
864 if (!res) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900865 dev_err(&pdev->dev, "failed to get I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100866 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900867 }
868
H Hartley Sweetencbd38a82009-12-14 16:59:27 -0500869 flctl->reg = ioremap(res->start, resource_size(res));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900870 if (flctl->reg == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900871 dev_err(&pdev->dev, "failed to remap I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100872 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900873 }
874
875 platform_set_drvdata(pdev, flctl);
876 flctl_mtd = &flctl->mtd;
877 nand = &flctl->chip;
878 flctl_mtd->priv = nand;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900879 flctl->pdev = pdev;
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100880 flctl->flcmncr_base = pdata->flcmncr_val;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900881 flctl->hwecc = pdata->has_hwecc;
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100882 flctl->holden = pdata->use_holden;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900883
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900884 nand->options = NAND_NO_AUTOINCR;
885
886 /* Set address of hardware control function */
887 /* 20 us command delay time */
888 nand->chip_delay = 20;
889
890 nand->read_byte = flctl_read_byte;
891 nand->write_buf = flctl_write_buf;
892 nand->read_buf = flctl_read_buf;
893 nand->verify_buf = flctl_verify_buf;
894 nand->select_chip = flctl_select_chip;
895 nand->cmdfunc = flctl_cmdfunc;
896
Magnus Damm010ab822010-01-27 09:17:21 +0000897 if (pdata->flcmncr_val & SEL_16BIT) {
898 nand->options |= NAND_BUSWIDTH_16;
899 nand->read_word = flctl_read_word;
900 }
901
Bastian Hechtcfe78192012-03-18 15:13:20 +0100902 pm_runtime_enable(&pdev->dev);
903 pm_runtime_resume(&pdev->dev);
904
David Woodhouse5e81e882010-02-26 18:32:56 +0000905 ret = nand_scan_ident(flctl_mtd, 1, NULL);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900906 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100907 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900908
909 ret = flctl_chip_init_tail(flctl_mtd);
910 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100911 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900912
913 ret = nand_scan_tail(flctl_mtd);
914 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100915 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900916
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100917 mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900918
919 return 0;
920
Bastian Hechtcfe78192012-03-18 15:13:20 +0100921err_chip:
922 pm_runtime_disable(&pdev->dev);
923err_iomap:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900924 kfree(flctl);
925 return ret;
926}
927
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900928static int __devexit flctl_remove(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900929{
930 struct sh_flctl *flctl = platform_get_drvdata(pdev);
931
932 nand_release(&flctl->mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100933 pm_runtime_disable(&pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900934 kfree(flctl);
935
936 return 0;
937}
938
939static struct platform_driver flctl_driver = {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900940 .remove = flctl_remove,
941 .driver = {
942 .name = "sh_flctl",
943 .owner = THIS_MODULE,
944 },
945};
946
947static int __init flctl_nand_init(void)
948{
David Woodhouse894572a2009-09-19 16:07:34 -0700949 return platform_driver_probe(&flctl_driver, flctl_probe);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900950}
951
952static void __exit flctl_nand_cleanup(void)
953{
954 platform_driver_unregister(&flctl_driver);
955}
956
957module_init(flctl_nand_init);
958module_exit(flctl_nand_cleanup);
959
960MODULE_LICENSE("GPL");
961MODULE_AUTHOR("Yoshihiro Shimoda");
962MODULE_DESCRIPTION("SuperH FLCTL driver");
963MODULE_ALIAS("platform:sh_flctl");