blob: b3666be0ccfca7369ee664f598e7ba5391993768 [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 = {
Bastian Hechtaa32d1f2012-05-14 14:14:42 +020047 .eccbytes = 4 * 10,
48 .eccpos = {
49 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
50 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
51 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
52 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090053 .oobfree = {
Bastian Hechtaa32d1f2012-05-14 14:14:42 +020054 {.offset = 2, .length = 4},
55 {.offset = 16, .length = 6},
56 {.offset = 32, .length = 6},
57 {.offset = 48, .length = 6} },
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090058};
59
60static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
61
62static struct nand_bbt_descr flctl_4secc_smallpage = {
63 .options = NAND_BBT_SCAN2NDPAGE,
64 .offs = 11,
65 .len = 1,
66 .pattern = scan_ff_pattern,
67};
68
69static struct nand_bbt_descr flctl_4secc_largepage = {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +090070 .options = NAND_BBT_SCAN2NDPAGE,
Bastian Hechtaa32d1f2012-05-14 14:14:42 +020071 .offs = 0,
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090072 .len = 2,
73 .pattern = scan_ff_pattern,
74};
75
76static void empty_fifo(struct sh_flctl *flctl)
77{
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +020078 writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
79 writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090080}
81
82static void start_translation(struct sh_flctl *flctl)
83{
84 writeb(TRSTRT, FLTRCR(flctl));
85}
86
Magnus Dammb79c7ad2010-02-02 13:01:25 +090087static void timeout_error(struct sh_flctl *flctl, const char *str)
88{
Lucas De Marchi25985ed2011-03-30 22:57:33 -030089 dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
Magnus Dammb79c7ad2010-02-02 13:01:25 +090090}
91
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +090092static void wait_completion(struct sh_flctl *flctl)
93{
94 uint32_t timeout = LOOP_TIMEOUT_MAX;
95
96 while (timeout--) {
97 if (readb(FLTRCR(flctl)) & TREND) {
98 writeb(0x0, FLTRCR(flctl));
99 return;
100 }
101 udelay(1);
102 }
103
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900104 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900105 writeb(0x0, FLTRCR(flctl));
106}
107
108static void set_addr(struct mtd_info *mtd, int column, int page_addr)
109{
110 struct sh_flctl *flctl = mtd_to_flctl(mtd);
111 uint32_t addr = 0;
112
113 if (column == -1) {
114 addr = page_addr; /* ERASE1 */
115 } else if (page_addr != -1) {
116 /* SEQIN, READ0, etc.. */
Magnus Damm010ab822010-01-27 09:17:21 +0000117 if (flctl->chip.options & NAND_BUSWIDTH_16)
118 column >>= 1;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900119 if (flctl->page_size) {
120 addr = column & 0x0FFF;
121 addr |= (page_addr & 0xff) << 16;
122 addr |= ((page_addr >> 8) & 0xff) << 24;
123 /* big than 128MB */
124 if (flctl->rw_ADRCNT == ADRCNT2_E) {
125 uint32_t addr2;
126 addr2 = (page_addr >> 16) & 0xff;
127 writel(addr2, FLADR2(flctl));
128 }
129 } else {
130 addr = column;
131 addr |= (page_addr & 0xff) << 8;
132 addr |= ((page_addr >> 8) & 0xff) << 16;
133 addr |= ((page_addr >> 16) & 0xff) << 24;
134 }
135 }
136 writel(addr, FLADR(flctl));
137}
138
139static void wait_rfifo_ready(struct sh_flctl *flctl)
140{
141 uint32_t timeout = LOOP_TIMEOUT_MAX;
142
143 while (timeout--) {
144 uint32_t val;
145 /* check FIFO */
146 val = readl(FLDTCNTR(flctl)) >> 16;
147 if (val & 0xFF)
148 return;
149 udelay(1);
150 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900151 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900152}
153
154static void wait_wfifo_ready(struct sh_flctl *flctl)
155{
156 uint32_t len, timeout = LOOP_TIMEOUT_MAX;
157
158 while (timeout--) {
159 /* check FIFO */
160 len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
161 if (len >= 4)
162 return;
163 udelay(1);
164 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900165 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900166}
167
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900168static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900169{
170 uint32_t timeout = LOOP_TIMEOUT_MAX;
171 int checked[4];
172 void __iomem *ecc_reg[4];
173 int i;
174 uint32_t data, size;
175
176 memset(checked, 0, sizeof(checked));
177
178 while (timeout--) {
179 size = readl(FLDTCNTR(flctl)) >> 24;
180 if (size & 0xFF)
181 return 0; /* success */
182
183 if (readl(FL4ECCCR(flctl)) & _4ECCFA)
184 return 1; /* can't correct */
185
186 udelay(1);
187 if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
188 continue;
189
190 /* start error correction */
191 ecc_reg[0] = FL4ECCRESULT0(flctl);
192 ecc_reg[1] = FL4ECCRESULT1(flctl);
193 ecc_reg[2] = FL4ECCRESULT2(flctl);
194 ecc_reg[3] = FL4ECCRESULT3(flctl);
195
196 for (i = 0; i < 3; i++) {
197 data = readl(ecc_reg[i]);
198 if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
199 uint8_t org;
200 int index;
201
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900202 if (flctl->page_size)
203 index = (512 * sector_number) +
204 (data >> 16);
205 else
206 index = data >> 16;
207
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900208 org = flctl->done_buff[index];
209 flctl->done_buff[index] = org ^ (data & 0xFF);
210 checked[i] = 1;
211 }
212 }
213
214 writel(0, FL4ECCCR(flctl));
215 }
216
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900217 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900218 return 1; /* timeout */
219}
220
221static void wait_wecfifo_ready(struct sh_flctl *flctl)
222{
223 uint32_t timeout = LOOP_TIMEOUT_MAX;
224 uint32_t len;
225
226 while (timeout--) {
227 /* check FLECFIFO */
228 len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
229 if (len >= 4)
230 return;
231 udelay(1);
232 }
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900233 timeout_error(flctl, __func__);
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900234}
235
236static void read_datareg(struct sh_flctl *flctl, int offset)
237{
238 unsigned long data;
239 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
240
241 wait_completion(flctl);
242
243 data = readl(FLDATAR(flctl));
244 *buf = le32_to_cpu(data);
245}
246
247static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
248{
249 int i, len_4align;
250 unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
251 void *fifo_addr = (void *)FLDTFIFO(flctl);
252
253 len_4align = (rlen + 3) / 4;
254
255 for (i = 0; i < len_4align; i++) {
256 wait_rfifo_ready(flctl);
257 buf[i] = readl(fifo_addr);
258 buf[i] = be32_to_cpu(buf[i]);
259 }
260}
261
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900262static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector)
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900263{
264 int i;
265 unsigned long *ecc_buf = (unsigned long *)buff;
266 void *fifo_addr = (void *)FLECFIFO(flctl);
267
268 for (i = 0; i < 4; i++) {
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900269 if (wait_recfifo_ready(flctl , sector))
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900270 return 1;
271 ecc_buf[i] = readl(fifo_addr);
272 ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
273 }
274
275 return 0;
276}
277
278static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
279{
280 int i, len_4align;
281 unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
282 void *fifo_addr = (void *)FLDTFIFO(flctl);
283
284 len_4align = (rlen + 3) / 4;
285 for (i = 0; i < len_4align; i++) {
286 wait_wfifo_ready(flctl);
287 writel(cpu_to_be32(data[i]), fifo_addr);
288 }
289}
290
291static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
292{
293 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100294 uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900295 uint32_t flcmdcr_val, addr_len_bytes = 0;
296
297 /* Set SNAND bit if page size is 2048byte */
298 if (flctl->page_size)
299 flcmncr_val |= SNAND_E;
300 else
301 flcmncr_val &= ~SNAND_E;
302
303 /* default FLCMDCR val */
304 flcmdcr_val = DOCMD1_E | DOADR_E;
305
306 /* Set for FLCMDCR */
307 switch (cmd) {
308 case NAND_CMD_ERASE1:
309 addr_len_bytes = flctl->erase_ADRCNT;
310 flcmdcr_val |= DOCMD2_E;
311 break;
312 case NAND_CMD_READ0:
313 case NAND_CMD_READOOB:
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100314 case NAND_CMD_RNDOUT:
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900315 addr_len_bytes = flctl->rw_ADRCNT;
316 flcmdcr_val |= CDSRC_E;
Magnus Damm010ab822010-01-27 09:17:21 +0000317 if (flctl->chip.options & NAND_BUSWIDTH_16)
318 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda6028aa02008-10-14 21:23:26 +0900319 break;
320 case NAND_CMD_SEQIN:
321 /* This case is that cmd is READ0 or READ1 or READ00 */
322 flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */
323 break;
324 case NAND_CMD_PAGEPROG:
325 addr_len_bytes = flctl->rw_ADRCNT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900326 flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
Magnus Damm010ab822010-01-27 09:17:21 +0000327 if (flctl->chip.options & NAND_BUSWIDTH_16)
328 flcmncr_val |= SEL_16BIT;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900329 break;
330 case NAND_CMD_READID:
331 flcmncr_val &= ~SNAND_E;
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100332 flcmdcr_val |= CDSRC_E;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900333 addr_len_bytes = ADRCNT_1;
334 break;
335 case NAND_CMD_STATUS:
336 case NAND_CMD_RESET:
337 flcmncr_val &= ~SNAND_E;
338 flcmdcr_val &= ~(DOADR_E | DOSR_E);
339 break;
340 default:
341 break;
342 }
343
344 /* Set address bytes parameter */
345 flcmdcr_val |= addr_len_bytes;
346
347 /* Now actually write */
348 writel(flcmncr_val, FLCMNCR(flctl));
349 writel(flcmdcr_val, FLCMDCR(flctl));
350 writel(flcmcdr_val, FLCMCDR(flctl));
351}
352
353static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Brian Norris1fbb9382012-05-02 10:14:55 -0700354 uint8_t *buf, int oob_required, int page)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900355{
356 int i, eccsize = chip->ecc.size;
357 int eccbytes = chip->ecc.bytes;
358 int eccsteps = chip->ecc.steps;
359 uint8_t *p = buf;
360 struct sh_flctl *flctl = mtd_to_flctl(mtd);
361
362 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
363 chip->read_buf(mtd, p, eccsize);
364
365 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
366 if (flctl->hwecc_cant_correct[i])
367 mtd->ecc_stats.failed++;
368 else
Mike Dunn3f91e942012-04-25 12:06:09 -0700369 mtd->ecc_stats.corrected += 0; /* FIXME */
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900370 }
371
372 return 0;
373}
374
375static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Brian Norris1fbb9382012-05-02 10:14:55 -0700376 const uint8_t *buf, int oob_required)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900377{
378 int i, eccsize = chip->ecc.size;
379 int eccbytes = chip->ecc.bytes;
380 int eccsteps = chip->ecc.steps;
381 const uint8_t *p = buf;
382
383 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
384 chip->write_buf(mtd, p, eccsize);
385}
386
387static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
388{
389 struct sh_flctl *flctl = mtd_to_flctl(mtd);
390 int sector, page_sectors;
391
392 if (flctl->page_size)
393 page_sectors = 4;
394 else
395 page_sectors = 1;
396
397 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
398 FLCMNCR(flctl));
399
400 set_cmd_regs(mtd, NAND_CMD_READ0,
401 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
402
403 for (sector = 0; sector < page_sectors; sector++) {
404 int ret;
405
406 empty_fifo(flctl);
407 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
408 writel(page_addr << 2 | sector, FLADR(flctl));
409
410 start_translation(flctl);
411 read_fiforeg(flctl, 512, 512 * sector);
412
413 ret = read_ecfiforeg(flctl,
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900414 &flctl->done_buff[mtd->writesize + 16 * sector],
415 sector);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900416
417 if (ret)
418 flctl->hwecc_cant_correct[sector] = 1;
419
420 writel(0x0, FL4ECCCR(flctl));
421 wait_completion(flctl);
422 }
423 writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
424 FLCMNCR(flctl));
425}
426
427static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
428{
429 struct sh_flctl *flctl = mtd_to_flctl(mtd);
430
431 set_cmd_regs(mtd, NAND_CMD_READ0,
432 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
433
434 empty_fifo(flctl);
435 if (flctl->page_size) {
436 int i;
437 /* In case that the page size is 2k */
438 for (i = 0; i < 16 * 3; i++)
439 flctl->done_buff[i] = 0xFF;
440
441 set_addr(mtd, 3 * 528 + 512, page_addr);
442 writel(16, FLDTCNTR(flctl));
443
444 start_translation(flctl);
445 read_fiforeg(flctl, 16, 16 * 3);
446 wait_completion(flctl);
447 } else {
448 /* In case that the page size is 512b */
449 set_addr(mtd, 512, page_addr);
450 writel(16, FLDTCNTR(flctl));
451
452 start_translation(flctl);
453 read_fiforeg(flctl, 16, 0);
454 wait_completion(flctl);
455 }
456}
457
458static void execmd_write_page_sector(struct mtd_info *mtd)
459{
460 struct sh_flctl *flctl = mtd_to_flctl(mtd);
461 int i, page_addr = flctl->seqin_page_addr;
462 int sector, page_sectors;
463
464 if (flctl->page_size)
465 page_sectors = 4;
466 else
467 page_sectors = 1;
468
469 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
470
471 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
472 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
473
474 for (sector = 0; sector < page_sectors; sector++) {
475 empty_fifo(flctl);
476 writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
477 writel(page_addr << 2 | sector, FLADR(flctl));
478
479 start_translation(flctl);
480 write_fiforeg(flctl, 512, 512 * sector);
481
482 for (i = 0; i < 4; i++) {
483 wait_wecfifo_ready(flctl); /* wait for write ready */
484 writel(0xFFFFFFFF, FLECFIFO(flctl));
485 }
486 wait_completion(flctl);
487 }
488
489 writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
490}
491
492static void execmd_write_oob(struct mtd_info *mtd)
493{
494 struct sh_flctl *flctl = mtd_to_flctl(mtd);
495 int page_addr = flctl->seqin_page_addr;
496 int sector, page_sectors;
497
498 if (flctl->page_size) {
499 sector = 3;
500 page_sectors = 4;
501 } else {
502 sector = 0;
503 page_sectors = 1;
504 }
505
506 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
507 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
508
509 for (; sector < page_sectors; sector++) {
510 empty_fifo(flctl);
511 set_addr(mtd, sector * 528 + 512, page_addr);
512 writel(16, FLDTCNTR(flctl)); /* set read size */
513
514 start_translation(flctl);
515 write_fiforeg(flctl, 16, 16 * sector);
516 wait_completion(flctl);
517 }
518}
519
520static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
521 int column, int page_addr)
522{
523 struct sh_flctl *flctl = mtd_to_flctl(mtd);
524 uint32_t read_cmd = 0;
525
Bastian Hechtcfe78192012-03-18 15:13:20 +0100526 pm_runtime_get_sync(&flctl->pdev->dev);
527
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900528 flctl->read_bytes = 0;
529 if (command != NAND_CMD_PAGEPROG)
530 flctl->index = 0;
531
532 switch (command) {
533 case NAND_CMD_READ1:
534 case NAND_CMD_READ0:
535 if (flctl->hwecc) {
536 /* read page with hwecc */
537 execmd_read_page_sector(mtd, page_addr);
538 break;
539 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900540 if (flctl->page_size)
541 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
542 | command);
543 else
544 set_cmd_regs(mtd, command, command);
545
546 set_addr(mtd, 0, page_addr);
547
548 flctl->read_bytes = mtd->writesize + mtd->oobsize;
Magnus Damm010ab822010-01-27 09:17:21 +0000549 if (flctl->chip.options & NAND_BUSWIDTH_16)
550 column >>= 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900551 flctl->index += column;
552 goto read_normal_exit;
553
554 case NAND_CMD_READOOB:
555 if (flctl->hwecc) {
556 /* read page with hwecc */
557 execmd_read_oob(mtd, page_addr);
558 break;
559 }
560
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900561 if (flctl->page_size) {
562 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
563 | NAND_CMD_READ0);
564 set_addr(mtd, mtd->writesize, page_addr);
565 } else {
566 set_cmd_regs(mtd, command, command);
567 set_addr(mtd, 0, page_addr);
568 }
569 flctl->read_bytes = mtd->oobsize;
570 goto read_normal_exit;
571
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100572 case NAND_CMD_RNDOUT:
573 if (flctl->hwecc)
574 break;
575
576 if (flctl->page_size)
577 set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
578 | command);
579 else
580 set_cmd_regs(mtd, command, command);
581
582 set_addr(mtd, column, 0);
583
584 flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
585 goto read_normal_exit;
586
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900587 case NAND_CMD_READID:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900588 set_cmd_regs(mtd, command, command);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900589
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100590 /* READID is always performed using an 8-bit bus */
591 if (flctl->chip.options & NAND_BUSWIDTH_16)
592 column <<= 1;
593 set_addr(mtd, column, 0);
594
595 flctl->read_bytes = 8;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900596 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100597 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900598 start_translation(flctl);
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100599 read_fiforeg(flctl, flctl->read_bytes, 0);
600 wait_completion(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900601 break;
602
603 case NAND_CMD_ERASE1:
604 flctl->erase1_page_addr = page_addr;
605 break;
606
607 case NAND_CMD_ERASE2:
608 set_cmd_regs(mtd, NAND_CMD_ERASE1,
609 (command << 8) | NAND_CMD_ERASE1);
610 set_addr(mtd, -1, flctl->erase1_page_addr);
611 start_translation(flctl);
612 wait_completion(flctl);
613 break;
614
615 case NAND_CMD_SEQIN:
616 if (!flctl->page_size) {
617 /* output read command */
618 if (column >= mtd->writesize) {
619 column -= mtd->writesize;
620 read_cmd = NAND_CMD_READOOB;
621 } else if (column < 256) {
622 read_cmd = NAND_CMD_READ0;
623 } else {
624 column -= 256;
625 read_cmd = NAND_CMD_READ1;
626 }
627 }
628 flctl->seqin_column = column;
629 flctl->seqin_page_addr = page_addr;
630 flctl->seqin_read_cmd = read_cmd;
631 break;
632
633 case NAND_CMD_PAGEPROG:
634 empty_fifo(flctl);
635 if (!flctl->page_size) {
636 set_cmd_regs(mtd, NAND_CMD_SEQIN,
637 flctl->seqin_read_cmd);
638 set_addr(mtd, -1, -1);
639 writel(0, FLDTCNTR(flctl)); /* set 0 size */
640 start_translation(flctl);
641 wait_completion(flctl);
642 }
643 if (flctl->hwecc) {
644 /* write page with hwecc */
645 if (flctl->seqin_column == mtd->writesize)
646 execmd_write_oob(mtd);
647 else if (!flctl->seqin_column)
648 execmd_write_page_sector(mtd);
649 else
650 printk(KERN_ERR "Invalid address !?\n");
651 break;
652 }
653 set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
654 set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
655 writel(flctl->index, FLDTCNTR(flctl)); /* set write size */
656 start_translation(flctl);
657 write_fiforeg(flctl, flctl->index, 0);
658 wait_completion(flctl);
659 break;
660
661 case NAND_CMD_STATUS:
662 set_cmd_regs(mtd, command, command);
663 set_addr(mtd, -1, -1);
664
665 flctl->read_bytes = 1;
666 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
667 start_translation(flctl);
668 read_datareg(flctl, 0); /* read and end */
669 break;
670
671 case NAND_CMD_RESET:
672 set_cmd_regs(mtd, command, command);
673 set_addr(mtd, -1, -1);
674
675 writel(0, FLDTCNTR(flctl)); /* set 0 size */
676 start_translation(flctl);
677 wait_completion(flctl);
678 break;
679
680 default:
681 break;
682 }
Bastian Hechtcfe78192012-03-18 15:13:20 +0100683 goto runtime_exit;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900684
685read_normal_exit:
686 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100687 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900688 start_translation(flctl);
689 read_fiforeg(flctl, flctl->read_bytes, 0);
690 wait_completion(flctl);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100691runtime_exit:
692 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900693 return;
694}
695
696static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
697{
698 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100699 int ret;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900700
701 switch (chipnr) {
702 case -1:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100703 flctl->flcmncr_base &= ~CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100704
705 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100706 writel(flctl->flcmncr_base, FLCMNCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100707
708 if (flctl->qos_request) {
709 dev_pm_qos_remove_request(&flctl->pm_qos);
710 flctl->qos_request = 0;
711 }
712
713 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900714 break;
715 case 0:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100716 flctl->flcmncr_base |= CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100717
718 if (!flctl->qos_request) {
719 ret = dev_pm_qos_add_request(&flctl->pdev->dev,
720 &flctl->pm_qos, 100);
721 if (ret < 0)
722 dev_err(&flctl->pdev->dev,
723 "PM QoS request failed: %d\n", ret);
724 flctl->qos_request = 1;
725 }
726
727 if (flctl->holden) {
728 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100729 writel(HOLDEN, FLHOLDCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100730 pm_runtime_put_sync(&flctl->pdev->dev);
731 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900732 break;
733 default:
734 BUG();
735 }
736}
737
738static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
739{
740 struct sh_flctl *flctl = mtd_to_flctl(mtd);
741 int i, index = flctl->index;
742
743 for (i = 0; i < len; i++)
744 flctl->done_buff[index + i] = buf[i];
745 flctl->index += len;
746}
747
748static uint8_t flctl_read_byte(struct mtd_info *mtd)
749{
750 struct sh_flctl *flctl = mtd_to_flctl(mtd);
751 int index = flctl->index;
752 uint8_t data;
753
754 data = flctl->done_buff[index];
755 flctl->index++;
756 return data;
757}
758
Magnus Damm010ab822010-01-27 09:17:21 +0000759static uint16_t flctl_read_word(struct mtd_info *mtd)
760{
761 struct sh_flctl *flctl = mtd_to_flctl(mtd);
762 int index = flctl->index;
763 uint16_t data;
764 uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
765
766 data = *buf;
767 flctl->index += 2;
768 return data;
769}
770
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900771static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
772{
773 int i;
774
775 for (i = 0; i < len; i++)
776 buf[i] = flctl_read_byte(mtd);
777}
778
779static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
780{
781 int i;
782
783 for (i = 0; i < len; i++)
784 if (buf[i] != flctl_read_byte(mtd))
785 return -EFAULT;
786 return 0;
787}
788
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900789static int flctl_chip_init_tail(struct mtd_info *mtd)
790{
791 struct sh_flctl *flctl = mtd_to_flctl(mtd);
792 struct nand_chip *chip = &flctl->chip;
793
794 if (mtd->writesize == 512) {
795 flctl->page_size = 0;
796 if (chip->chipsize > (32 << 20)) {
797 /* big than 32MB */
798 flctl->rw_ADRCNT = ADRCNT_4;
799 flctl->erase_ADRCNT = ADRCNT_3;
800 } else if (chip->chipsize > (2 << 16)) {
801 /* big than 128KB */
802 flctl->rw_ADRCNT = ADRCNT_3;
803 flctl->erase_ADRCNT = ADRCNT_2;
804 } else {
805 flctl->rw_ADRCNT = ADRCNT_2;
806 flctl->erase_ADRCNT = ADRCNT_1;
807 }
808 } else {
809 flctl->page_size = 1;
810 if (chip->chipsize > (128 << 20)) {
811 /* big than 128MB */
812 flctl->rw_ADRCNT = ADRCNT2_E;
813 flctl->erase_ADRCNT = ADRCNT_3;
814 } else if (chip->chipsize > (8 << 16)) {
815 /* big than 512KB */
816 flctl->rw_ADRCNT = ADRCNT_4;
817 flctl->erase_ADRCNT = ADRCNT_2;
818 } else {
819 flctl->rw_ADRCNT = ADRCNT_3;
820 flctl->erase_ADRCNT = ADRCNT_1;
821 }
822 }
823
824 if (flctl->hwecc) {
825 if (mtd->writesize == 512) {
826 chip->ecc.layout = &flctl_4secc_oob_16;
827 chip->badblock_pattern = &flctl_4secc_smallpage;
828 } else {
829 chip->ecc.layout = &flctl_4secc_oob_64;
830 chip->badblock_pattern = &flctl_4secc_largepage;
831 }
832
833 chip->ecc.size = 512;
834 chip->ecc.bytes = 10;
Mike Dunn6a918ba2012-03-11 14:21:11 -0700835 chip->ecc.strength = 4;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900836 chip->ecc.read_page = flctl_read_page_hwecc;
837 chip->ecc.write_page = flctl_write_page_hwecc;
838 chip->ecc.mode = NAND_ECC_HW;
839
840 /* 4 symbols ECC enabled */
Bastian Hechtaa32d1f2012-05-14 14:14:42 +0200841 flctl->flcmncr_base |= _4ECCEN;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900842 } else {
843 chip->ecc.mode = NAND_ECC_SOFT;
844 }
845
846 return 0;
847}
848
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200849static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
850{
851 struct sh_flctl *flctl = dev_id;
852
853 dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
854 writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
855
856 return IRQ_HANDLED;
857}
858
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900859static int __devinit flctl_probe(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900860{
861 struct resource *res;
862 struct sh_flctl *flctl;
863 struct mtd_info *flctl_mtd;
864 struct nand_chip *nand;
865 struct sh_flctl_platform_data *pdata;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900866 int ret = -ENXIO;
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200867 int irq;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900868
869 pdata = pdev->dev.platform_data;
870 if (pdata == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900871 dev_err(&pdev->dev, "no platform data defined\n");
872 return -EINVAL;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900873 }
874
875 flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
876 if (!flctl) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900877 dev_err(&pdev->dev, "failed to allocate driver data\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900878 return -ENOMEM;
879 }
880
881 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
882 if (!res) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900883 dev_err(&pdev->dev, "failed to get I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100884 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900885 }
886
H Hartley Sweetencbd38a82009-12-14 16:59:27 -0500887 flctl->reg = ioremap(res->start, resource_size(res));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900888 if (flctl->reg == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900889 dev_err(&pdev->dev, "failed to remap I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100890 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900891 }
892
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200893 irq = platform_get_irq(pdev, 0);
894 if (irq < 0) {
895 dev_err(&pdev->dev, "failed to get flste irq data\n");
896 goto err_flste;
897 }
898
899 ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
900 if (ret) {
901 dev_err(&pdev->dev, "request interrupt failed.\n");
902 goto err_flste;
903 }
904
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900905 platform_set_drvdata(pdev, flctl);
906 flctl_mtd = &flctl->mtd;
907 nand = &flctl->chip;
908 flctl_mtd->priv = nand;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900909 flctl->pdev = pdev;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900910 flctl->hwecc = pdata->has_hwecc;
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100911 flctl->holden = pdata->use_holden;
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200912 flctl->flcmncr_base = pdata->flcmncr_val;
913 flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900914
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900915 /* Set address of hardware control function */
916 /* 20 us command delay time */
917 nand->chip_delay = 20;
918
919 nand->read_byte = flctl_read_byte;
920 nand->write_buf = flctl_write_buf;
921 nand->read_buf = flctl_read_buf;
922 nand->verify_buf = flctl_verify_buf;
923 nand->select_chip = flctl_select_chip;
924 nand->cmdfunc = flctl_cmdfunc;
925
Magnus Damm010ab822010-01-27 09:17:21 +0000926 if (pdata->flcmncr_val & SEL_16BIT) {
927 nand->options |= NAND_BUSWIDTH_16;
928 nand->read_word = flctl_read_word;
929 }
930
Bastian Hechtcfe78192012-03-18 15:13:20 +0100931 pm_runtime_enable(&pdev->dev);
932 pm_runtime_resume(&pdev->dev);
933
David Woodhouse5e81e882010-02-26 18:32:56 +0000934 ret = nand_scan_ident(flctl_mtd, 1, NULL);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900935 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100936 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900937
938 ret = flctl_chip_init_tail(flctl_mtd);
939 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100940 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900941
942 ret = nand_scan_tail(flctl_mtd);
943 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100944 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900945
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100946 mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900947
948 return 0;
949
Bastian Hechtcfe78192012-03-18 15:13:20 +0100950err_chip:
951 pm_runtime_disable(&pdev->dev);
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200952 free_irq(irq, flctl);
953err_flste:
Bastian Hechtcb547512012-05-14 14:14:40 +0200954 iounmap(flctl->reg);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100955err_iomap:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900956 kfree(flctl);
957 return ret;
958}
959
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900960static int __devexit flctl_remove(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900961{
962 struct sh_flctl *flctl = platform_get_drvdata(pdev);
963
964 nand_release(&flctl->mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100965 pm_runtime_disable(&pdev->dev);
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200966 free_irq(platform_get_irq(pdev, 0), flctl);
Bastian Hechtcb547512012-05-14 14:14:40 +0200967 iounmap(flctl->reg);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900968 kfree(flctl);
969
970 return 0;
971}
972
973static struct platform_driver flctl_driver = {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900974 .remove = flctl_remove,
975 .driver = {
976 .name = "sh_flctl",
977 .owner = THIS_MODULE,
978 },
979};
980
981static int __init flctl_nand_init(void)
982{
David Woodhouse894572a2009-09-19 16:07:34 -0700983 return platform_driver_probe(&flctl_driver, flctl_probe);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900984}
985
986static void __exit flctl_nand_cleanup(void)
987{
988 platform_driver_unregister(&flctl_driver);
989}
990
991module_init(flctl_nand_init);
992module_exit(flctl_nand_cleanup);
993
994MODULE_LICENSE("GPL");
995MODULE_AUTHOR("Yoshihiro Shimoda");
996MODULE_DESCRIPTION("SuperH FLCTL driver");
997MODULE_ALIAS("platform:sh_flctl");