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