blob: 96e242adda6a0eae516732a3ef44ade4bd83a1b7 [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{
Bastian Hecht50ed3992012-05-14 14:14:44 +0200356 chip->read_buf(mtd, buf, mtd->writesize);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900357 return 0;
358}
359
360static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
Brian Norris1fbb9382012-05-02 10:14:55 -0700361 const uint8_t *buf, int oob_required)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900362{
Bastian Hecht50ed3992012-05-14 14:14:44 +0200363 chip->write_buf(mtd, buf, mtd->writesize);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900364}
365
366static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
367{
368 struct sh_flctl *flctl = mtd_to_flctl(mtd);
369 int sector, page_sectors;
370
Bastian Hecht623c55c2012-05-14 14:14:45 +0200371 page_sectors = flctl->page_size ? 4 : 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900372
373 set_cmd_regs(mtd, NAND_CMD_READ0,
374 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
375
Bastian Hecht623c55c2012-05-14 14:14:45 +0200376 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
377 FLCMNCR(flctl));
378 writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
379 writel(page_addr << 2, FLADR(flctl));
380
381 empty_fifo(flctl);
382 start_translation(flctl);
383
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900384 for (sector = 0; sector < page_sectors; sector++) {
385 int ret;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900386 read_fiforeg(flctl, 512, 512 * sector);
387
388 ret = read_ecfiforeg(flctl,
Yoshihiro Shimodac0e66162009-03-24 18:27:24 +0900389 &flctl->done_buff[mtd->writesize + 16 * sector],
390 sector);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900391
392 if (ret)
393 flctl->hwecc_cant_correct[sector] = 1;
394
395 writel(0x0, FL4ECCCR(flctl));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900396 }
Bastian Hecht623c55c2012-05-14 14:14:45 +0200397
398 wait_completion(flctl);
399
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900400 writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
401 FLCMNCR(flctl));
402}
403
404static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
405{
406 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hechtef4ce0b2012-05-14 14:14:43 +0200407 int page_sectors = flctl->page_size ? 4 : 1;
408 int i;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900409
410 set_cmd_regs(mtd, NAND_CMD_READ0,
411 (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
412
413 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900414
Bastian Hechtef4ce0b2012-05-14 14:14:43 +0200415 for (i = 0; i < page_sectors; i++) {
416 set_addr(mtd, (512 + 16) * i + 512 , page_addr);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900417 writel(16, FLDTCNTR(flctl));
418
419 start_translation(flctl);
Bastian Hechtef4ce0b2012-05-14 14:14:43 +0200420 read_fiforeg(flctl, 16, 16 * i);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900421 wait_completion(flctl);
422 }
423}
424
425static void execmd_write_page_sector(struct mtd_info *mtd)
426{
427 struct sh_flctl *flctl = mtd_to_flctl(mtd);
428 int i, page_addr = flctl->seqin_page_addr;
429 int sector, page_sectors;
430
Bastian Hecht623c55c2012-05-14 14:14:45 +0200431 page_sectors = flctl->page_size ? 4 : 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900432
433 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
434 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
435
Bastian Hecht623c55c2012-05-14 14:14:45 +0200436 empty_fifo(flctl);
437 writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
438 writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
439 writel(page_addr << 2, FLADR(flctl));
440 start_translation(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900441
Bastian Hecht623c55c2012-05-14 14:14:45 +0200442 for (sector = 0; sector < page_sectors; sector++) {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900443 write_fiforeg(flctl, 512, 512 * sector);
444
445 for (i = 0; i < 4; i++) {
446 wait_wecfifo_ready(flctl); /* wait for write ready */
447 writel(0xFFFFFFFF, FLECFIFO(flctl));
448 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900449 }
450
Bastian Hecht623c55c2012-05-14 14:14:45 +0200451 wait_completion(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900452 writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
453}
454
455static void execmd_write_oob(struct mtd_info *mtd)
456{
457 struct sh_flctl *flctl = mtd_to_flctl(mtd);
458 int page_addr = flctl->seqin_page_addr;
459 int sector, page_sectors;
460
Bastian Hechtef4ce0b2012-05-14 14:14:43 +0200461 page_sectors = flctl->page_size ? 4 : 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900462
463 set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
464 (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
465
Bastian Hechtef4ce0b2012-05-14 14:14:43 +0200466 for (sector = 0; sector < page_sectors; sector++) {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900467 empty_fifo(flctl);
468 set_addr(mtd, sector * 528 + 512, page_addr);
469 writel(16, FLDTCNTR(flctl)); /* set read size */
470
471 start_translation(flctl);
472 write_fiforeg(flctl, 16, 16 * sector);
473 wait_completion(flctl);
474 }
475}
476
477static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
478 int column, int page_addr)
479{
480 struct sh_flctl *flctl = mtd_to_flctl(mtd);
481 uint32_t read_cmd = 0;
482
Bastian Hechtcfe78192012-03-18 15:13:20 +0100483 pm_runtime_get_sync(&flctl->pdev->dev);
484
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900485 flctl->read_bytes = 0;
486 if (command != NAND_CMD_PAGEPROG)
487 flctl->index = 0;
488
489 switch (command) {
490 case NAND_CMD_READ1:
491 case NAND_CMD_READ0:
492 if (flctl->hwecc) {
493 /* read page with hwecc */
494 execmd_read_page_sector(mtd, page_addr);
495 break;
496 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900497 if (flctl->page_size)
498 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
499 | command);
500 else
501 set_cmd_regs(mtd, command, command);
502
503 set_addr(mtd, 0, page_addr);
504
505 flctl->read_bytes = mtd->writesize + mtd->oobsize;
Magnus Damm010ab822010-01-27 09:17:21 +0000506 if (flctl->chip.options & NAND_BUSWIDTH_16)
507 column >>= 1;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900508 flctl->index += column;
509 goto read_normal_exit;
510
511 case NAND_CMD_READOOB:
512 if (flctl->hwecc) {
513 /* read page with hwecc */
514 execmd_read_oob(mtd, page_addr);
515 break;
516 }
517
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900518 if (flctl->page_size) {
519 set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
520 | NAND_CMD_READ0);
521 set_addr(mtd, mtd->writesize, page_addr);
522 } else {
523 set_cmd_regs(mtd, command, command);
524 set_addr(mtd, 0, page_addr);
525 }
526 flctl->read_bytes = mtd->oobsize;
527 goto read_normal_exit;
528
Bastian Hechtdd5ab242012-03-01 10:48:38 +0100529 case NAND_CMD_RNDOUT:
530 if (flctl->hwecc)
531 break;
532
533 if (flctl->page_size)
534 set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
535 | command);
536 else
537 set_cmd_regs(mtd, command, command);
538
539 set_addr(mtd, column, 0);
540
541 flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
542 goto read_normal_exit;
543
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900544 case NAND_CMD_READID:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900545 set_cmd_regs(mtd, command, command);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900546
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100547 /* READID is always performed using an 8-bit bus */
548 if (flctl->chip.options & NAND_BUSWIDTH_16)
549 column <<= 1;
550 set_addr(mtd, column, 0);
551
552 flctl->read_bytes = 8;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900553 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100554 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900555 start_translation(flctl);
Bastian Hecht7b6b2302012-03-01 10:48:37 +0100556 read_fiforeg(flctl, flctl->read_bytes, 0);
557 wait_completion(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900558 break;
559
560 case NAND_CMD_ERASE1:
561 flctl->erase1_page_addr = page_addr;
562 break;
563
564 case NAND_CMD_ERASE2:
565 set_cmd_regs(mtd, NAND_CMD_ERASE1,
566 (command << 8) | NAND_CMD_ERASE1);
567 set_addr(mtd, -1, flctl->erase1_page_addr);
568 start_translation(flctl);
569 wait_completion(flctl);
570 break;
571
572 case NAND_CMD_SEQIN:
573 if (!flctl->page_size) {
574 /* output read command */
575 if (column >= mtd->writesize) {
576 column -= mtd->writesize;
577 read_cmd = NAND_CMD_READOOB;
578 } else if (column < 256) {
579 read_cmd = NAND_CMD_READ0;
580 } else {
581 column -= 256;
582 read_cmd = NAND_CMD_READ1;
583 }
584 }
585 flctl->seqin_column = column;
586 flctl->seqin_page_addr = page_addr;
587 flctl->seqin_read_cmd = read_cmd;
588 break;
589
590 case NAND_CMD_PAGEPROG:
591 empty_fifo(flctl);
592 if (!flctl->page_size) {
593 set_cmd_regs(mtd, NAND_CMD_SEQIN,
594 flctl->seqin_read_cmd);
595 set_addr(mtd, -1, -1);
596 writel(0, FLDTCNTR(flctl)); /* set 0 size */
597 start_translation(flctl);
598 wait_completion(flctl);
599 }
600 if (flctl->hwecc) {
601 /* write page with hwecc */
602 if (flctl->seqin_column == mtd->writesize)
603 execmd_write_oob(mtd);
604 else if (!flctl->seqin_column)
605 execmd_write_page_sector(mtd);
606 else
607 printk(KERN_ERR "Invalid address !?\n");
608 break;
609 }
610 set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
611 set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
612 writel(flctl->index, FLDTCNTR(flctl)); /* set write size */
613 start_translation(flctl);
614 write_fiforeg(flctl, flctl->index, 0);
615 wait_completion(flctl);
616 break;
617
618 case NAND_CMD_STATUS:
619 set_cmd_regs(mtd, command, command);
620 set_addr(mtd, -1, -1);
621
622 flctl->read_bytes = 1;
623 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
624 start_translation(flctl);
625 read_datareg(flctl, 0); /* read and end */
626 break;
627
628 case NAND_CMD_RESET:
629 set_cmd_regs(mtd, command, command);
630 set_addr(mtd, -1, -1);
631
632 writel(0, FLDTCNTR(flctl)); /* set 0 size */
633 start_translation(flctl);
634 wait_completion(flctl);
635 break;
636
637 default:
638 break;
639 }
Bastian Hechtcfe78192012-03-18 15:13:20 +0100640 goto runtime_exit;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900641
642read_normal_exit:
643 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
Bastian Hechtabb59ef2012-03-01 10:48:36 +0100644 empty_fifo(flctl);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900645 start_translation(flctl);
646 read_fiforeg(flctl, flctl->read_bytes, 0);
647 wait_completion(flctl);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100648runtime_exit:
649 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900650 return;
651}
652
653static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
654{
655 struct sh_flctl *flctl = mtd_to_flctl(mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100656 int ret;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900657
658 switch (chipnr) {
659 case -1:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100660 flctl->flcmncr_base &= ~CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100661
662 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100663 writel(flctl->flcmncr_base, FLCMNCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100664
665 if (flctl->qos_request) {
666 dev_pm_qos_remove_request(&flctl->pm_qos);
667 flctl->qos_request = 0;
668 }
669
670 pm_runtime_put_sync(&flctl->pdev->dev);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900671 break;
672 case 0:
Bastian Hecht0b3f0d12012-03-01 10:48:39 +0100673 flctl->flcmncr_base |= CE0_ENABLE;
Bastian Hechtcfe78192012-03-18 15:13:20 +0100674
675 if (!flctl->qos_request) {
676 ret = dev_pm_qos_add_request(&flctl->pdev->dev,
677 &flctl->pm_qos, 100);
678 if (ret < 0)
679 dev_err(&flctl->pdev->dev,
680 "PM QoS request failed: %d\n", ret);
681 flctl->qos_request = 1;
682 }
683
684 if (flctl->holden) {
685 pm_runtime_get_sync(&flctl->pdev->dev);
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100686 writel(HOLDEN, FLHOLDCR(flctl));
Bastian Hechtcfe78192012-03-18 15:13:20 +0100687 pm_runtime_put_sync(&flctl->pdev->dev);
688 }
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900689 break;
690 default:
691 BUG();
692 }
693}
694
695static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
696{
697 struct sh_flctl *flctl = mtd_to_flctl(mtd);
698 int i, index = flctl->index;
699
700 for (i = 0; i < len; i++)
701 flctl->done_buff[index + i] = buf[i];
702 flctl->index += len;
703}
704
705static uint8_t flctl_read_byte(struct mtd_info *mtd)
706{
707 struct sh_flctl *flctl = mtd_to_flctl(mtd);
708 int index = flctl->index;
709 uint8_t data;
710
711 data = flctl->done_buff[index];
712 flctl->index++;
713 return data;
714}
715
Magnus Damm010ab822010-01-27 09:17:21 +0000716static uint16_t flctl_read_word(struct mtd_info *mtd)
717{
718 struct sh_flctl *flctl = mtd_to_flctl(mtd);
719 int index = flctl->index;
720 uint16_t data;
721 uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
722
723 data = *buf;
724 flctl->index += 2;
725 return data;
726}
727
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900728static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
729{
730 int i;
731
732 for (i = 0; i < len; i++)
733 buf[i] = flctl_read_byte(mtd);
734}
735
736static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
737{
738 int i;
739
740 for (i = 0; i < len; i++)
741 if (buf[i] != flctl_read_byte(mtd))
742 return -EFAULT;
743 return 0;
744}
745
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900746static int flctl_chip_init_tail(struct mtd_info *mtd)
747{
748 struct sh_flctl *flctl = mtd_to_flctl(mtd);
749 struct nand_chip *chip = &flctl->chip;
750
751 if (mtd->writesize == 512) {
752 flctl->page_size = 0;
753 if (chip->chipsize > (32 << 20)) {
754 /* big than 32MB */
755 flctl->rw_ADRCNT = ADRCNT_4;
756 flctl->erase_ADRCNT = ADRCNT_3;
757 } else if (chip->chipsize > (2 << 16)) {
758 /* big than 128KB */
759 flctl->rw_ADRCNT = ADRCNT_3;
760 flctl->erase_ADRCNT = ADRCNT_2;
761 } else {
762 flctl->rw_ADRCNT = ADRCNT_2;
763 flctl->erase_ADRCNT = ADRCNT_1;
764 }
765 } else {
766 flctl->page_size = 1;
767 if (chip->chipsize > (128 << 20)) {
768 /* big than 128MB */
769 flctl->rw_ADRCNT = ADRCNT2_E;
770 flctl->erase_ADRCNT = ADRCNT_3;
771 } else if (chip->chipsize > (8 << 16)) {
772 /* big than 512KB */
773 flctl->rw_ADRCNT = ADRCNT_4;
774 flctl->erase_ADRCNT = ADRCNT_2;
775 } else {
776 flctl->rw_ADRCNT = ADRCNT_3;
777 flctl->erase_ADRCNT = ADRCNT_1;
778 }
779 }
780
781 if (flctl->hwecc) {
782 if (mtd->writesize == 512) {
783 chip->ecc.layout = &flctl_4secc_oob_16;
784 chip->badblock_pattern = &flctl_4secc_smallpage;
785 } else {
786 chip->ecc.layout = &flctl_4secc_oob_64;
787 chip->badblock_pattern = &flctl_4secc_largepage;
788 }
789
790 chip->ecc.size = 512;
791 chip->ecc.bytes = 10;
Mike Dunn6a918ba2012-03-11 14:21:11 -0700792 chip->ecc.strength = 4;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900793 chip->ecc.read_page = flctl_read_page_hwecc;
794 chip->ecc.write_page = flctl_write_page_hwecc;
795 chip->ecc.mode = NAND_ECC_HW;
796
797 /* 4 symbols ECC enabled */
Bastian Hechtaa32d1f2012-05-14 14:14:42 +0200798 flctl->flcmncr_base |= _4ECCEN;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900799 } else {
800 chip->ecc.mode = NAND_ECC_SOFT;
801 }
802
803 return 0;
804}
805
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200806static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
807{
808 struct sh_flctl *flctl = dev_id;
809
810 dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
811 writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
812
813 return IRQ_HANDLED;
814}
815
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900816static int __devinit flctl_probe(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900817{
818 struct resource *res;
819 struct sh_flctl *flctl;
820 struct mtd_info *flctl_mtd;
821 struct nand_chip *nand;
822 struct sh_flctl_platform_data *pdata;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900823 int ret = -ENXIO;
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200824 int irq;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900825
826 pdata = pdev->dev.platform_data;
827 if (pdata == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900828 dev_err(&pdev->dev, "no platform data defined\n");
829 return -EINVAL;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900830 }
831
832 flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
833 if (!flctl) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900834 dev_err(&pdev->dev, "failed to allocate driver data\n");
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900835 return -ENOMEM;
836 }
837
838 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
839 if (!res) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900840 dev_err(&pdev->dev, "failed to get I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100841 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900842 }
843
H Hartley Sweetencbd38a82009-12-14 16:59:27 -0500844 flctl->reg = ioremap(res->start, resource_size(res));
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900845 if (flctl->reg == NULL) {
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900846 dev_err(&pdev->dev, "failed to remap I/O memory\n");
Bastian Hechtcfe78192012-03-18 15:13:20 +0100847 goto err_iomap;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900848 }
849
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200850 irq = platform_get_irq(pdev, 0);
851 if (irq < 0) {
852 dev_err(&pdev->dev, "failed to get flste irq data\n");
853 goto err_flste;
854 }
855
856 ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
857 if (ret) {
858 dev_err(&pdev->dev, "request interrupt failed.\n");
859 goto err_flste;
860 }
861
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900862 platform_set_drvdata(pdev, flctl);
863 flctl_mtd = &flctl->mtd;
864 nand = &flctl->chip;
865 flctl_mtd->priv = nand;
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900866 flctl->pdev = pdev;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900867 flctl->hwecc = pdata->has_hwecc;
Bastian Hecht3f2e9242012-03-01 10:48:40 +0100868 flctl->holden = pdata->use_holden;
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200869 flctl->flcmncr_base = pdata->flcmncr_val;
870 flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900871
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900872 /* Set address of hardware control function */
873 /* 20 us command delay time */
874 nand->chip_delay = 20;
875
876 nand->read_byte = flctl_read_byte;
877 nand->write_buf = flctl_write_buf;
878 nand->read_buf = flctl_read_buf;
879 nand->verify_buf = flctl_verify_buf;
880 nand->select_chip = flctl_select_chip;
881 nand->cmdfunc = flctl_cmdfunc;
882
Magnus Damm010ab822010-01-27 09:17:21 +0000883 if (pdata->flcmncr_val & SEL_16BIT) {
884 nand->options |= NAND_BUSWIDTH_16;
885 nand->read_word = flctl_read_word;
886 }
887
Bastian Hechtcfe78192012-03-18 15:13:20 +0100888 pm_runtime_enable(&pdev->dev);
889 pm_runtime_resume(&pdev->dev);
890
David Woodhouse5e81e882010-02-26 18:32:56 +0000891 ret = nand_scan_ident(flctl_mtd, 1, NULL);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900892 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100893 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900894
895 ret = flctl_chip_init_tail(flctl_mtd);
896 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100897 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900898
899 ret = nand_scan_tail(flctl_mtd);
900 if (ret)
Bastian Hechtcfe78192012-03-18 15:13:20 +0100901 goto err_chip;
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900902
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100903 mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900904
905 return 0;
906
Bastian Hechtcfe78192012-03-18 15:13:20 +0100907err_chip:
908 pm_runtime_disable(&pdev->dev);
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200909 free_irq(irq, flctl);
910err_flste:
Bastian Hechtcb547512012-05-14 14:14:40 +0200911 iounmap(flctl->reg);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100912err_iomap:
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900913 kfree(flctl);
914 return ret;
915}
916
Magnus Dammb79c7ad2010-02-02 13:01:25 +0900917static int __devexit flctl_remove(struct platform_device *pdev)
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900918{
919 struct sh_flctl *flctl = platform_get_drvdata(pdev);
920
921 nand_release(&flctl->mtd);
Bastian Hechtcfe78192012-03-18 15:13:20 +0100922 pm_runtime_disable(&pdev->dev);
Bastian Hecht3c7ea4e2012-05-14 14:14:41 +0200923 free_irq(platform_get_irq(pdev, 0), flctl);
Bastian Hechtcb547512012-05-14 14:14:40 +0200924 iounmap(flctl->reg);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900925 kfree(flctl);
926
927 return 0;
928}
929
930static struct platform_driver flctl_driver = {
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900931 .remove = flctl_remove,
932 .driver = {
933 .name = "sh_flctl",
934 .owner = THIS_MODULE,
935 },
936};
937
938static int __init flctl_nand_init(void)
939{
David Woodhouse894572a2009-09-19 16:07:34 -0700940 return platform_driver_probe(&flctl_driver, flctl_probe);
Yoshihiro Shimoda35a34792008-10-20 17:17:44 +0900941}
942
943static void __exit flctl_nand_cleanup(void)
944{
945 platform_driver_unregister(&flctl_driver);
946}
947
948module_init(flctl_nand_init);
949module_exit(flctl_nand_cleanup);
950
951MODULE_LICENSE("GPL");
952MODULE_AUTHOR("Yoshihiro Shimoda");
953MODULE_DESCRIPTION("SuperH FLCTL driver");
954MODULE_ALIAS("platform:sh_flctl");