blob: c835b136e7cbabbde410b8ef54af9bc6f7a89991 [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>
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +020027#include <linux/interrupt.h>
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090028#include <linux/io.h>
29#include <linux/platform_device.h>
Bastian Hechtcfe78192012-03-18 15:13:20 +010030#include <linux/pm_runtime.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090031#include <linux/slab.h>
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090032
33#include <linux/mtd/mtd.h>
34#include <linux/mtd/nand.h>
35#include <linux/mtd/partitions.h>
36#include <linux/mtd/sh_flctl.h>
37
38static struct nand_ecclayout flctl_4secc_oob_16 = {
39 .eccbytes = 10,
40 .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
41 .oobfree = {
42 {.offset = 12,
43 . length = 4} },
44};
45
46static struct nand_ecclayout flctl_4secc_oob_64 = {
47 .eccbytes = 10,
48 .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
49 .oobfree = {
50 {.offset = 60,
51 . length = 4} },
52};
53
54static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
55
56static struct nand_bbt_descr flctl_4secc_smallpage = {
57 .options = NAND_BBT_SCAN2NDPAGE,
58 .offs = 11,
59 .len = 1,
60 .pattern = scan_ff_pattern,
61};
62
63static struct nand_bbt_descr flctl_4secc_largepage = {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +090064 .options = NAND_BBT_SCAN2NDPAGE,
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090065 .offs = 58,
66 .len = 2,
67 .pattern = scan_ff_pattern,
68};
69
70static void empty_fifo(struct sh_flctl *flctl)
71{
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +020072 writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
73 writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090074}
75
76static void start_translation(struct sh_flctl *flctl)
77{
78 writeb(TRSTRT, FLTRCR(flctl));
79}
80
Magnus Dammb79c7ad2010-02-02 13:01:25 +090081static void timeout_error(struct sh_flctl *flctl, const char *str)
82{
Lucas De Marchi25985ed2011-03-30 22:57:33 -030083 dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
Magnus Dammb79c7ad2010-02-02 13:01:25 +090084}
85
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090086static void wait_completion(struct sh_flctl *flctl)
87{
88 uint32_t timeout = LOOP_TIMEOUT_MAX;
89
90 while (timeout--) {
91 if (readb(FLTRCR(flctl)) & TREND) {
92 writeb(0x0, FLTRCR(flctl));
93 return;
94 }
95 udelay(1);
96 }
97
Magnus Dammb79c7ad2010-02-02 13:01:25 +090098 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090099 writeb(0x0, FLTRCR(flctl));
100}
101
102static void set_addr(struct mtd_info *mtd, int column, int page_addr)
103{
104 struct sh_flctl *flctl = mtd_to_flctl(mtd);
105 uint32_t addr = 0;
106
107 if (column == -1) {
108 addr = page_addr; /* ERASE1 */
109 } else if (page_addr != -1) {
110 /* SEQIN, READ0, etc.. */
Magnus Damm010ab822010-01-27 09:17:21 +0000111 if (flctl->chip.options & NAND_BUSWIDTH_16)
112 column >>= 1;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900113 if (flctl->page_size) {
114 addr = column & 0x0FFF;
115 addr |= (page_addr & 0xff) << 16;
116 addr |= ((page_addr >> 8) & 0xff) << 24;
117 /* big than 128MB */
118 if (flctl->rw_ADRCNT == ADRCNT2_E) {
119 uint32_t addr2;
120 addr2 = (page_addr >> 16) & 0xff;
121 writel(addr2, FLADR2(flctl));
122 }
123 } else {
124 addr = column;
125 addr |= (page_addr & 0xff) << 8;
126 addr |= ((page_addr >> 8) & 0xff) << 16;
127 addr |= ((page_addr >> 16) & 0xff) << 24;
128 }
129 }
130 writel(addr, FLADR(flctl));
131}
132
133static void wait_rfifo_ready(struct sh_flctl *flctl)
134{
135 uint32_t timeout = LOOP_TIMEOUT_MAX;
136
137 while (timeout--) {
138 uint32_t val;
139 /* check FIFO */
140 val = readl(FLDTCNTR(flctl)) >> 16;
141 if (val & 0xFF)
142 return;
143 udelay(1);
144 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900145 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900146}
147
148static void wait_wfifo_ready(struct sh_flctl *flctl)
149{
150 uint32_t len, timeout = LOOP_TIMEOUT_MAX;
151
152 while (timeout--) {
153 /* check FIFO */
154 len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
155 if (len >= 4)
156 return;
157 udelay(1);
158 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900159 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900160}
161
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900162static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900163{
164 uint32_t timeout = LOOP_TIMEOUT_MAX;
165 int checked[4];
166 void __iomem *ecc_reg[4];
167 int i;
168 uint32_t data, size;
169
170 memset(checked, 0, sizeof(checked));
171
172 while (timeout--) {
173 size = readl(FLDTCNTR(flctl)) >> 24;
174 if (size & 0xFF)
175 return 0; /* success */
176
177 if (readl(FL4ECCCR(flctl)) & _4ECCFA)
178 return 1; /* can't correct */
179
180 udelay(1);
181 if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
182 continue;
183
184 /* start error correction */
185 ecc_reg[0] = FL4ECCRESULT0(flctl);
186 ecc_reg[1] = FL4ECCRESULT1(flctl);
187 ecc_reg[2] = FL4ECCRESULT2(flctl);
188 ecc_reg[3] = FL4ECCRESULT3(flctl);
189
190 for (i = 0; i < 3; i++) {
191 data = readl(ecc_reg[i]);
192 if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
193 uint8_t org;
194 int index;
195
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900196 if (flctl->page_size)
197 index = (512 * sector_number) +
198 (data >> 16);
199 else
200 index = data >> 16;
201
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900202 org = flctl->done_buff[index];
203 flctl->done_buff[index] = org ^ (data & 0xFF);
204 checked[i] = 1;
205 }
206 }
207
208 writel(0, FL4ECCCR(flctl));
209 }
210
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900211 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900212 return 1; /* timeout */
213}
214
215static void wait_wecfifo_ready(struct sh_flctl *flctl)
216{
217 uint32_t timeout = LOOP_TIMEOUT_MAX;
218 uint32_t len;
219
220 while (timeout--) {
221 /* check FLECFIFO */
222 len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
223 if (len >= 4)
224 return;
225 udelay(1);
226 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900227 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900228}
229
230static void read_datareg(struct sh_flctl *flctl, int offset)
231{
232 unsigned long data;
233 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
234
235 wait_completion(flctl);
236
237 data = readl(FLDATAR(flctl));
238 *buf = le32_to_cpu(data);
239}
240
241static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
242{
243 int i, len_4align;
244 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
245 void *fifo_addr = (void *)FLDTFIFO(flctl);
246
247 len_4align = (rlen + 3) / 4;
248
249 for (i = 0; i < len_4align; i++) {
250 wait_rfifo_ready(flctl);
251 buf[i] = readl(fifo_addr);
252 buf[i] = be32_to_cpu(buf[i]);
253 }
254}
255
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900256static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900257{
258 int i;
259 unsigned long *ecc_buf = (unsigned long *)buff;
260 void *fifo_addr = (void *)FLECFIFO(flctl);
261
262 for (i = 0; i < 4; i++) {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900263 if (wait_recfifo_ready(flctl , sector))
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900264 return 1;
265 ecc_buf[i] = readl(fifo_addr);
266 ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
267 }
268
269 return 0;
270}
271
272static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
273{
274 int i, len_4align;
275 unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
276 void *fifo_addr = (void *)FLDTFIFO(flctl);
277
278 len_4align = (rlen + 3) / 4;
279 for (i = 0; i < len_4align; i++) {
280 wait_wfifo_ready(flctl);
281 writel(cpu_to_be32(data[i]), fifo_addr);
282 }
283}
284
285static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
286{
287 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100288 uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900289 uint32_t flcmdcr_val, addr_len_bytes = 0;
290
291 /* Set SNAND bit if page size is 2048byte */
292 if (flctl->page_size)
293 flcmncr_val |= SNAND_E;
294 else
295 flcmncr_val &= ~SNAND_E;
296
297 /* default FLCMDCR val */
298 flcmdcr_val = DOCMD1_E | DOADR_E;
299
300 /* Set for FLCMDCR */
301 switch (cmd) {
302 case NAND_CMD_ERASE1:
303 addr_len_bytes = flctl->erase_ADRCNT;
304 flcmdcr_val |= DOCMD2_E;
305 break;
306 case NAND_CMD_READ0:
307 case NAND_CMD_READOOB:
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100308 case NAND_CMD_RNDOUT:
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900309 addr_len_bytes = flctl->rw_ADRCNT;
310 flcmdcr_val |= CDSRC_E;
Magnus Damm010ab822010-01-27 09:17:21 +0000311 if (flctl->chip.options & NAND_BUSWIDTH_16)
312 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900313 break;
314 case NAND_CMD_SEQIN:
315 /* This case is that cmd is READ0 or READ1 or READ00 */
316 flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */
317 break;
318 case NAND_CMD_PAGEPROG:
319 addr_len_bytes = flctl->rw_ADRCNT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900320 flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
Magnus Damm010ab822010-01-27 09:17:21 +0000321 if (flctl->chip.options & NAND_BUSWIDTH_16)
322 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900323 break;
324 case NAND_CMD_READID:
325 flcmncr_val &= ~SNAND_E;
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100326 flcmdcr_val |= CDSRC_E;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900327 addr_len_bytes = ADRCNT_1;
328 break;
329 case NAND_CMD_STATUS:
330 case NAND_CMD_RESET:
331 flcmncr_val &= ~SNAND_E;
332 flcmdcr_val &= ~(DOADR_E | DOSR_E);
333 break;
334 default:
335 break;
336 }
337
338 /* Set address bytes parameter */
339 flcmdcr_val |= addr_len_bytes;
340
341 /* Now actually write */
342 writel(flcmncr_val, FLCMNCR(flctl));
343 writel(flcmdcr_val, FLCMDCR(flctl));
344 writel(flcmcdr_val, FLCMCDR(flctl));
345}
346
347static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Brian Norris1fbb9382012-05-02 10:14:55 -0700348 uint8_t *buf, int oob_required, int page)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900349{
350 int i, eccsize = chip->ecc.size;
351 int eccbytes = chip->ecc.bytes;
352 int eccsteps = chip->ecc.steps;
353 uint8_t *p = buf;
354 struct sh_flctl *flctl = mtd_to_flctl(mtd);
355
356 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
357 chip->read_buf(mtd, p, eccsize);
358
359 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
360 if (flctl->hwecc_cant_correct[i])
361 mtd->ecc_stats.failed++;
362 else
Mike Dunn3f91e942012-04-25 12:06:09 -0700363 mtd->ecc_stats.corrected += 0; /* FIXME */
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900364 }
365
366 return 0;
367}
368
369static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Brian Norris1fbb9382012-05-02 10:14:55 -0700370 const uint8_t *buf, int oob_required)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900371{
372 int i, eccsize = chip->ecc.size;
373 int eccbytes = chip->ecc.bytes;
374 int eccsteps = chip->ecc.steps;
375 const uint8_t *p = buf;
376
377 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
378 chip->write_buf(mtd, p, eccsize);
379}
380
381static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
382{
383 struct sh_flctl *flctl = mtd_to_flctl(mtd);
384 int sector, page_sectors;
385
386 if (flctl->page_size)
387 page_sectors = 4;
388 else
389 page_sectors = 1;
390
391 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
392 FLCMNCR(flctl));
393
394 set_cmd_regs(mtd, NAND_CMD_READ0,
395 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
396
397 for (sector = 0; sector < page_sectors; sector++) {
398 int ret;
399
400 empty_fifo(flctl);
401 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
402 writel(page_addr << 2 | sector, FLADR(flctl));
403
404 start_translation(flctl);
405 read_fiforeg(flctl, 512, 512 * sector);
406
407 ret = read_ecfiforeg(flctl,
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900408 &flctl->done_buff[mtd->writesize + 16 * sector],
409 sector);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900410
411 if (ret)
412 flctl->hwecc_cant_correct[sector] = 1;
413
414 writel(0x0, FL4ECCCR(flctl));
415 wait_completion(flctl);
416 }
417 writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
418 FLCMNCR(flctl));
419}
420
421static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
422{
423 struct sh_flctl *flctl = mtd_to_flctl(mtd);
424
425 set_cmd_regs(mtd, NAND_CMD_READ0,
426 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
427
428 empty_fifo(flctl);
429 if (flctl->page_size) {
430 int i;
431 /* In case that the page size is 2k */
432 for (i = 0; i < 16 * 3; i++)
433 flctl->done_buff[i] = 0xFF;
434
435 set_addr(mtd, 3 * 528 + 512, page_addr);
436 writel(16, FLDTCNTR(flctl));
437
438 start_translation(flctl);
439 read_fiforeg(flctl, 16, 16 * 3);
440 wait_completion(flctl);
441 } else {
442 /* In case that the page size is 512b */
443 set_addr(mtd, 512, page_addr);
444 writel(16, FLDTCNTR(flctl));
445
446 start_translation(flctl);
447 read_fiforeg(flctl, 16, 0);
448 wait_completion(flctl);
449 }
450}
451
452static void execmd_write_page_sector(struct mtd_info *mtd)
453{
454 struct sh_flctl *flctl = mtd_to_flctl(mtd);
455 int i, page_addr = flctl->seqin_page_addr;
456 int sector, page_sectors;
457
458 if (flctl->page_size)
459 page_sectors = 4;
460 else
461 page_sectors = 1;
462
463 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
464
465 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
466 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
467
468 for (sector = 0; sector < page_sectors; sector++) {
469 empty_fifo(flctl);
470 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
471 writel(page_addr << 2 | sector, FLADR(flctl));
472
473 start_translation(flctl);
474 write_fiforeg(flctl, 512, 512 * sector);
475
476 for (i = 0; i < 4; i++) {
477 wait_wecfifo_ready(flctl); /* wait for write ready */
478 writel(0xFFFFFFFF, FLECFIFO(flctl));
479 }
480 wait_completion(flctl);
481 }
482
483 writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
484}
485
486static void execmd_write_oob(struct mtd_info *mtd)
487{
488 struct sh_flctl *flctl = mtd_to_flctl(mtd);
489 int page_addr = flctl->seqin_page_addr;
490 int sector, page_sectors;
491
492 if (flctl->page_size) {
493 sector = 3;
494 page_sectors = 4;
495 } else {
496 sector = 0;
497 page_sectors = 1;
498 }
499
500 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
501 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
502
503 for (; sector < page_sectors; sector++) {
504 empty_fifo(flctl);
505 set_addr(mtd, sector * 528 + 512, page_addr);
506 writel(16, FLDTCNTR(flctl)); /* set read size */
507
508 start_translation(flctl);
509 write_fiforeg(flctl, 16, 16 * sector);
510 wait_completion(flctl);
511 }
512}
513
514static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
515 int column, int page_addr)
516{
517 struct sh_flctl *flctl = mtd_to_flctl(mtd);
518 uint32_t read_cmd = 0;
519
Bastian Hechtcfe78192012-03-18 15:13:20 +0100520 pm_runtime_get_sync(&flctl->pdev->dev);
521
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900522 flctl->read_bytes = 0;
523 if (command != NAND_CMD_PAGEPROG)
524 flctl->index = 0;
525
526 switch (command) {
527 case NAND_CMD_READ1:
528 case NAND_CMD_READ0:
529 if (flctl->hwecc) {
530 /* read page with hwecc */
531 execmd_read_page_sector(mtd, page_addr);
532 break;
533 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900534 if (flctl->page_size)
535 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
536 | command);
537 else
538 set_cmd_regs(mtd, command, command);
539
540 set_addr(mtd, 0, page_addr);
541
542 flctl->read_bytes = mtd->writesize + mtd->oobsize;
Magnus Damm010ab822010-01-27 09:17:21 +0000543 if (flctl->chip.options & NAND_BUSWIDTH_16)
544 column >>= 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900545 flctl->index += column;
546 goto read_normal_exit;
547
548 case NAND_CMD_READOOB:
549 if (flctl->hwecc) {
550 /* read page with hwecc */
551 execmd_read_oob(mtd, page_addr);
552 break;
553 }
554
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900555 if (flctl->page_size) {
556 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
557 | NAND_CMD_READ0);
558 set_addr(mtd, mtd->writesize, page_addr);
559 } else {
560 set_cmd_regs(mtd, command, command);
561 set_addr(mtd, 0, page_addr);
562 }
563 flctl->read_bytes = mtd->oobsize;
564 goto read_normal_exit;
565
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100566 case NAND_CMD_RNDOUT:
567 if (flctl->hwecc)
568 break;
569
570 if (flctl->page_size)
571 set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
572 | command);
573 else
574 set_cmd_regs(mtd, command, command);
575
576 set_addr(mtd, column, 0);
577
578 flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
579 goto read_normal_exit;
580
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900581 case NAND_CMD_READID:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900582 set_cmd_regs(mtd, command, command);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900583
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100584 /* READID is always performed using an 8-bit bus */
585 if (flctl->chip.options & NAND_BUSWIDTH_16)
586 column <<= 1;
587 set_addr(mtd, column, 0);
588
589 flctl->read_bytes = 8;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900590 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100591 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900592 start_translation(flctl);
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100593 read_fiforeg(flctl, flctl->read_bytes, 0);
594 wait_completion(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900595 break;
596
597 case NAND_CMD_ERASE1:
598 flctl->erase1_page_addr = page_addr;
599 break;
600
601 case NAND_CMD_ERASE2:
602 set_cmd_regs(mtd, NAND_CMD_ERASE1,
603 (command << 8) | NAND_CMD_ERASE1);
604 set_addr(mtd, -1, flctl->erase1_page_addr);
605 start_translation(flctl);
606 wait_completion(flctl);
607 break;
608
609 case NAND_CMD_SEQIN:
610 if (!flctl->page_size) {
611 /* output read command */
612 if (column >= mtd->writesize) {
613 column -= mtd->writesize;
614 read_cmd = NAND_CMD_READOOB;
615 } else if (column < 256) {
616 read_cmd = NAND_CMD_READ0;
617 } else {
618 column -= 256;
619 read_cmd = NAND_CMD_READ1;
620 }
621 }
622 flctl->seqin_column = column;
623 flctl->seqin_page_addr = page_addr;
624 flctl->seqin_read_cmd = read_cmd;
625 break;
626
627 case NAND_CMD_PAGEPROG:
628 empty_fifo(flctl);
629 if (!flctl->page_size) {
630 set_cmd_regs(mtd, NAND_CMD_SEQIN,
631 flctl->seqin_read_cmd);
632 set_addr(mtd, -1, -1);
633 writel(0, FLDTCNTR(flctl)); /* set 0 size */
634 start_translation(flctl);
635 wait_completion(flctl);
636 }
637 if (flctl->hwecc) {
638 /* write page with hwecc */
639 if (flctl->seqin_column == mtd->writesize)
640 execmd_write_oob(mtd);
641 else if (!flctl->seqin_column)
642 execmd_write_page_sector(mtd);
643 else
644 printk(KERN_ERR "Invalid address !?\n");
645 break;
646 }
647 set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
648 set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
649 writel(flctl->index, FLDTCNTR(flctl)); /* set write size */
650 start_translation(flctl);
651 write_fiforeg(flctl, flctl->index, 0);
652 wait_completion(flctl);
653 break;
654
655 case NAND_CMD_STATUS:
656 set_cmd_regs(mtd, command, command);
657 set_addr(mtd, -1, -1);
658
659 flctl->read_bytes = 1;
660 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
661 start_translation(flctl);
662 read_datareg(flctl, 0); /* read and end */
663 break;
664
665 case NAND_CMD_RESET:
666 set_cmd_regs(mtd, command, command);
667 set_addr(mtd, -1, -1);
668
669 writel(0, FLDTCNTR(flctl)); /* set 0 size */
670 start_translation(flctl);
671 wait_completion(flctl);
672 break;
673
674 default:
675 break;
676 }
Bastian Hechtcfe78192012-03-18 15:13:20 +0100677 goto runtime_exit;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900678
679read_normal_exit:
680 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100681 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900682 start_translation(flctl);
683 read_fiforeg(flctl, flctl->read_bytes, 0);
684 wait_completion(flctl);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100685runtime_exit:
686 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900687 return;
688}
689
690static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
691{
692 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100693 int ret;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900694
695 switch (chipnr) {
696 case -1:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100697 flctl->flcmncr_base &= ~CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100698
699 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100700 writel(flctl->flcmncr_base, FLCMNCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100701
702 if (flctl->qos_request) {
703 dev_pm_qos_remove_request(&flctl->pm_qos);
704 flctl->qos_request = 0;
705 }
706
707 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900708 break;
709 case 0:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100710 flctl->flcmncr_base |= CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100711
712 if (!flctl->qos_request) {
713 ret = dev_pm_qos_add_request(&flctl->pdev->dev,
714 &flctl->pm_qos, 100);
715 if (ret < 0)
716 dev_err(&flctl->pdev->dev,
717 "PM QoS request failed: %d\n", ret);
718 flctl->qos_request = 1;
719 }
720
721 if (flctl->holden) {
722 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100723 writel(HOLDEN, FLHOLDCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100724 pm_runtime_put_sync(&flctl->pdev->dev);
725 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900726 break;
727 default:
728 BUG();
729 }
730}
731
732static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
733{
734 struct sh_flctl *flctl = mtd_to_flctl(mtd);
735 int i, index = flctl->index;
736
737 for (i = 0; i < len; i++)
738 flctl->done_buff[index + i] = buf[i];
739 flctl->index += len;
740}
741
742static uint8_t flctl_read_byte(struct mtd_info *mtd)
743{
744 struct sh_flctl *flctl = mtd_to_flctl(mtd);
745 int index = flctl->index;
746 uint8_t data;
747
748 data = flctl->done_buff[index];
749 flctl->index++;
750 return data;
751}
752
Magnus Damm010ab822010-01-27 09:17:21 +0000753static uint16_t flctl_read_word(struct mtd_info *mtd)
754{
755 struct sh_flctl *flctl = mtd_to_flctl(mtd);
756 int index = flctl->index;
757 uint16_t data;
758 uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
759
760 data = *buf;
761 flctl->index += 2;
762 return data;
763}
764
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900765static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
766{
767 int i;
768
769 for (i = 0; i < len; i++)
770 buf[i] = flctl_read_byte(mtd);
771}
772
773static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
774{
775 int i;
776
777 for (i = 0; i < len; i++)
778 if (buf[i] != flctl_read_byte(mtd))
779 return -EFAULT;
780 return 0;
781}
782
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900783static int flctl_chip_init_tail(struct mtd_info *mtd)
784{
785 struct sh_flctl *flctl = mtd_to_flctl(mtd);
786 struct nand_chip *chip = &flctl->chip;
787
788 if (mtd->writesize == 512) {
789 flctl->page_size = 0;
790 if (chip->chipsize > (32 << 20)) {
791 /* big than 32MB */
792 flctl->rw_ADRCNT = ADRCNT_4;
793 flctl->erase_ADRCNT = ADRCNT_3;
794 } else if (chip->chipsize > (2 << 16)) {
795 /* big than 128KB */
796 flctl->rw_ADRCNT = ADRCNT_3;
797 flctl->erase_ADRCNT = ADRCNT_2;
798 } else {
799 flctl->rw_ADRCNT = ADRCNT_2;
800 flctl->erase_ADRCNT = ADRCNT_1;
801 }
802 } else {
803 flctl->page_size = 1;
804 if (chip->chipsize > (128 << 20)) {
805 /* big than 128MB */
806 flctl->rw_ADRCNT = ADRCNT2_E;
807 flctl->erase_ADRCNT = ADRCNT_3;
808 } else if (chip->chipsize > (8 << 16)) {
809 /* big than 512KB */
810 flctl->rw_ADRCNT = ADRCNT_4;
811 flctl->erase_ADRCNT = ADRCNT_2;
812 } else {
813 flctl->rw_ADRCNT = ADRCNT_3;
814 flctl->erase_ADRCNT = ADRCNT_1;
815 }
816 }
817
818 if (flctl->hwecc) {
819 if (mtd->writesize == 512) {
820 chip->ecc.layout = &flctl_4secc_oob_16;
821 chip->badblock_pattern = &flctl_4secc_smallpage;
822 } else {
823 chip->ecc.layout = &flctl_4secc_oob_64;
824 chip->badblock_pattern = &flctl_4secc_largepage;
825 }
826
827 chip->ecc.size = 512;
828 chip->ecc.bytes = 10;
Mike Dunn6a918ba2012-03-11 14:21:11 -0700829 chip->ecc.strength = 4;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900830 chip->ecc.read_page = flctl_read_page_hwecc;
831 chip->ecc.write_page = flctl_write_page_hwecc;
832 chip->ecc.mode = NAND_ECC_HW;
833
834 /* 4 symbols ECC enabled */
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100835 flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900836 } else {
837 chip->ecc.mode = NAND_ECC_SOFT;
838 }
839
840 return 0;
841}
842
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200843static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
844{
845 struct sh_flctl *flctl = dev_id;
846
847 dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
848 writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
849
850 return IRQ_HANDLED;
851}
852
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900853static int __devinit flctl_probe(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900854{
855 struct resource *res;
856 struct sh_flctl *flctl;
857 struct mtd_info *flctl_mtd;
858 struct nand_chip *nand;
859 struct sh_flctl_platform_data *pdata;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900860 int ret = -ENXIO;
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200861 int irq;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900862
863 pdata = pdev->dev.platform_data;
864 if (pdata == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900865 dev_err(&pdev->dev, "no platform data defined\n");
866 return -EINVAL;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900867 }
868
869 flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
870 if (!flctl) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900871 dev_err(&pdev->dev, "failed to allocate driver data\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900872 return -ENOMEM;
873 }
874
875 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
876 if (!res) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900877 dev_err(&pdev->dev, "failed to get I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100878 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900879 }
880
H Hartley Sweetencbd38a82009-12-14 16:59:27 -0500881 flctl->reg = ioremap(res->start, resource_size(res));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900882 if (flctl->reg == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900883 dev_err(&pdev->dev, "failed to remap I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100884 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900885 }
886
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200887 irq = platform_get_irq(pdev, 0);
888 if (irq < 0) {
889 dev_err(&pdev->dev, "failed to get flste irq data\n");
890 goto err_flste;
891 }
892
893 ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
894 if (ret) {
895 dev_err(&pdev->dev, "request interrupt failed.\n");
896 goto err_flste;
897 }
898
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900899 platform_set_drvdata(pdev, flctl);
900 flctl_mtd = &flctl->mtd;
901 nand = &flctl->chip;
902 flctl_mtd->priv = nand;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900903 flctl->pdev = pdev;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900904 flctl->hwecc = pdata->has_hwecc;
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100905 flctl->holden = pdata->use_holden;
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200906 flctl->flcmncr_base = pdata->flcmncr_val;
907 flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900908
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900909 /* Set address of hardware control function */
910 /* 20 us command delay time */
911 nand->chip_delay = 20;
912
913 nand->read_byte = flctl_read_byte;
914 nand->write_buf = flctl_write_buf;
915 nand->read_buf = flctl_read_buf;
916 nand->verify_buf = flctl_verify_buf;
917 nand->select_chip = flctl_select_chip;
918 nand->cmdfunc = flctl_cmdfunc;
919
Magnus Damm010ab822010-01-27 09:17:21 +0000920 if (pdata->flcmncr_val & SEL_16BIT) {
921 nand->options |= NAND_BUSWIDTH_16;
922 nand->read_word = flctl_read_word;
923 }
924
Bastian Hechtcfe78192012-03-18 15:13:20 +0100925 pm_runtime_enable(&pdev->dev);
926 pm_runtime_resume(&pdev->dev);
927
David Woodhouse5e81e882010-02-26 18:32:56 +0000928 ret = nand_scan_ident(flctl_mtd, 1, NULL);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900929 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100930 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900931
932 ret = flctl_chip_init_tail(flctl_mtd);
933 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100934 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900935
936 ret = nand_scan_tail(flctl_mtd);
937 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100938 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900939
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100940 mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900941
942 return 0;
943
Bastian Hechtcfe78192012-03-18 15:13:20 +0100944err_chip:
945 pm_runtime_disable(&pdev->dev);
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200946 free_irq(irq, flctl);
947err_flste:
Bastian Hechtcb547512012-05-14 14:14:40 +0200948 iounmap(flctl->reg);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100949err_iomap:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900950 kfree(flctl);
951 return ret;
952}
953
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900954static int __devexit flctl_remove(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900955{
956 struct sh_flctl *flctl = platform_get_drvdata(pdev);
957
958 nand_release(&flctl->mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100959 pm_runtime_disable(&pdev->dev);
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200960 free_irq(platform_get_irq(pdev, 0), flctl);
Bastian Hechtcb547512012-05-14 14:14:40 +0200961 iounmap(flctl->reg);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900962 kfree(flctl);
963
964 return 0;
965}
966
967static struct platform_driver flctl_driver = {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900968 .remove = flctl_remove,
969 .driver = {
970 .name = "sh_flctl",
971 .owner = THIS_MODULE,
972 },
973};
974
975static int __init flctl_nand_init(void)
976{
David Woodhouse894572a2009-09-19 16:07:34 -0700977 return platform_driver_probe(&flctl_driver, flctl_probe);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900978}
979
980static void __exit flctl_nand_cleanup(void)
981{
982 platform_driver_unregister(&flctl_driver);
983}
984
985module_init(flctl_nand_init);
986module_exit(flctl_nand_cleanup);
987
988MODULE_LICENSE("GPL");
989MODULE_AUTHOR("Yoshihiro Shimoda");
990MODULE_DESCRIPTION("SuperH FLCTL driver");
991MODULE_ALIAS("platform:sh_flctl");