diff options
Diffstat (limited to 'drivers/mtd/nand/sh_flctl.c')
-rw-r--r-- | drivers/mtd/nand/sh_flctl.c | 327 |
1 files changed, 181 insertions, 146 deletions
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index aa9b8a5e0b8f..4fbfe96e37a1 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c | |||
@@ -24,10 +24,12 @@ | |||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | ||
27 | #include <linux/io.h> | 28 | #include <linux/io.h> |
28 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
29 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
30 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/string.h> | ||
31 | 33 | ||
32 | #include <linux/mtd/mtd.h> | 34 | #include <linux/mtd/mtd.h> |
33 | #include <linux/mtd/nand.h> | 35 | #include <linux/mtd/nand.h> |
@@ -43,11 +45,17 @@ static struct nand_ecclayout flctl_4secc_oob_16 = { | |||
43 | }; | 45 | }; |
44 | 46 | ||
45 | static struct nand_ecclayout flctl_4secc_oob_64 = { | 47 | static struct nand_ecclayout flctl_4secc_oob_64 = { |
46 | .eccbytes = 10, | 48 | .eccbytes = 4 * 10, |
47 | .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57}, | 49 | .eccpos = { |
50 | 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
51 | 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
52 | 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, | ||
53 | 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, | ||
48 | .oobfree = { | 54 | .oobfree = { |
49 | {.offset = 60, | 55 | {.offset = 2, .length = 4}, |
50 | . length = 4} }, | 56 | {.offset = 16, .length = 6}, |
57 | {.offset = 32, .length = 6}, | ||
58 | {.offset = 48, .length = 6} }, | ||
51 | }; | 59 | }; |
52 | 60 | ||
53 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 61 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
@@ -61,15 +69,15 @@ static struct nand_bbt_descr flctl_4secc_smallpage = { | |||
61 | 69 | ||
62 | static struct nand_bbt_descr flctl_4secc_largepage = { | 70 | static struct nand_bbt_descr flctl_4secc_largepage = { |
63 | .options = NAND_BBT_SCAN2NDPAGE, | 71 | .options = NAND_BBT_SCAN2NDPAGE, |
64 | .offs = 58, | 72 | .offs = 0, |
65 | .len = 2, | 73 | .len = 2, |
66 | .pattern = scan_ff_pattern, | 74 | .pattern = scan_ff_pattern, |
67 | }; | 75 | }; |
68 | 76 | ||
69 | static void empty_fifo(struct sh_flctl *flctl) | 77 | static void empty_fifo(struct sh_flctl *flctl) |
70 | { | 78 | { |
71 | writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */ | 79 | writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl)); |
72 | writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */ | 80 | writel(flctl->flintdmacr_base, FLINTDMACR(flctl)); |
73 | } | 81 | } |
74 | 82 | ||
75 | static void start_translation(struct sh_flctl *flctl) | 83 | static void start_translation(struct sh_flctl *flctl) |
@@ -158,27 +166,56 @@ static void wait_wfifo_ready(struct sh_flctl *flctl) | |||
158 | timeout_error(flctl, __func__); | 166 | timeout_error(flctl, __func__); |
159 | } | 167 | } |
160 | 168 | ||
161 | static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) | 169 | static enum flctl_ecc_res_t wait_recfifo_ready |
170 | (struct sh_flctl *flctl, int sector_number) | ||
162 | { | 171 | { |
163 | uint32_t timeout = LOOP_TIMEOUT_MAX; | 172 | uint32_t timeout = LOOP_TIMEOUT_MAX; |
164 | int checked[4]; | ||
165 | void __iomem *ecc_reg[4]; | 173 | void __iomem *ecc_reg[4]; |
166 | int i; | 174 | int i; |
175 | int state = FL_SUCCESS; | ||
167 | uint32_t data, size; | 176 | uint32_t data, size; |
168 | 177 | ||
169 | memset(checked, 0, sizeof(checked)); | 178 | /* |
170 | 179 | * First this loops checks in FLDTCNTR if we are ready to read out the | |
180 | * oob data. This is the case if either all went fine without errors or | ||
181 | * if the bottom part of the loop corrected the errors or marked them as | ||
182 | * uncorrectable and the controller is given time to push the data into | ||
183 | * the FIFO. | ||
184 | */ | ||
171 | while (timeout--) { | 185 | while (timeout--) { |
186 | /* check if all is ok and we can read out the OOB */ | ||
172 | size = readl(FLDTCNTR(flctl)) >> 24; | 187 | size = readl(FLDTCNTR(flctl)) >> 24; |
173 | if (size & 0xFF) | 188 | if ((size & 0xFF) == 4) |
174 | return 0; /* success */ | 189 | return state; |
190 | |||
191 | /* check if a correction code has been calculated */ | ||
192 | if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) { | ||
193 | /* | ||
194 | * either we wait for the fifo to be filled or a | ||
195 | * correction pattern is being generated | ||
196 | */ | ||
197 | udelay(1); | ||
198 | continue; | ||
199 | } | ||
175 | 200 | ||
176 | if (readl(FL4ECCCR(flctl)) & _4ECCFA) | 201 | /* check for an uncorrectable error */ |
177 | return 1; /* can't correct */ | 202 | if (readl(FL4ECCCR(flctl)) & _4ECCFA) { |
203 | /* check if we face a non-empty page */ | ||
204 | for (i = 0; i < 512; i++) { | ||
205 | if (flctl->done_buff[i] != 0xff) { | ||
206 | state = FL_ERROR; /* can't correct */ | ||
207 | break; | ||
208 | } | ||
209 | } | ||
178 | 210 | ||
179 | udelay(1); | 211 | if (state == FL_SUCCESS) |
180 | if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) | 212 | dev_dbg(&flctl->pdev->dev, |
213 | "reading empty sector %d, ecc error ignored\n", | ||
214 | sector_number); | ||
215 | |||
216 | writel(0, FL4ECCCR(flctl)); | ||
181 | continue; | 217 | continue; |
218 | } | ||
182 | 219 | ||
183 | /* start error correction */ | 220 | /* start error correction */ |
184 | ecc_reg[0] = FL4ECCRESULT0(flctl); | 221 | ecc_reg[0] = FL4ECCRESULT0(flctl); |
@@ -187,28 +224,26 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) | |||
187 | ecc_reg[3] = FL4ECCRESULT3(flctl); | 224 | ecc_reg[3] = FL4ECCRESULT3(flctl); |
188 | 225 | ||
189 | for (i = 0; i < 3; i++) { | 226 | for (i = 0; i < 3; i++) { |
227 | uint8_t org; | ||
228 | int index; | ||
229 | |||
190 | data = readl(ecc_reg[i]); | 230 | data = readl(ecc_reg[i]); |
191 | if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) { | ||
192 | uint8_t org; | ||
193 | int index; | ||
194 | |||
195 | if (flctl->page_size) | ||
196 | index = (512 * sector_number) + | ||
197 | (data >> 16); | ||
198 | else | ||
199 | index = data >> 16; | ||
200 | |||
201 | org = flctl->done_buff[index]; | ||
202 | flctl->done_buff[index] = org ^ (data & 0xFF); | ||
203 | checked[i] = 1; | ||
204 | } | ||
205 | } | ||
206 | 231 | ||
232 | if (flctl->page_size) | ||
233 | index = (512 * sector_number) + | ||
234 | (data >> 16); | ||
235 | else | ||
236 | index = data >> 16; | ||
237 | |||
238 | org = flctl->done_buff[index]; | ||
239 | flctl->done_buff[index] = org ^ (data & 0xFF); | ||
240 | } | ||
241 | state = FL_REPAIRABLE; | ||
207 | writel(0, FL4ECCCR(flctl)); | 242 | writel(0, FL4ECCCR(flctl)); |
208 | } | 243 | } |
209 | 244 | ||
210 | timeout_error(flctl, __func__); | 245 | timeout_error(flctl, __func__); |
211 | return 1; /* timeout */ | 246 | return FL_TIMEOUT; /* timeout */ |
212 | } | 247 | } |
213 | 248 | ||
214 | static void wait_wecfifo_ready(struct sh_flctl *flctl) | 249 | static void wait_wecfifo_ready(struct sh_flctl *flctl) |
@@ -241,31 +276,33 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | |||
241 | { | 276 | { |
242 | int i, len_4align; | 277 | int i, len_4align; |
243 | unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; | 278 | unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; |
244 | void *fifo_addr = (void *)FLDTFIFO(flctl); | ||
245 | 279 | ||
246 | len_4align = (rlen + 3) / 4; | 280 | len_4align = (rlen + 3) / 4; |
247 | 281 | ||
248 | for (i = 0; i < len_4align; i++) { | 282 | for (i = 0; i < len_4align; i++) { |
249 | wait_rfifo_ready(flctl); | 283 | wait_rfifo_ready(flctl); |
250 | buf[i] = readl(fifo_addr); | 284 | buf[i] = readl(FLDTFIFO(flctl)); |
251 | buf[i] = be32_to_cpu(buf[i]); | 285 | buf[i] = be32_to_cpu(buf[i]); |
252 | } | 286 | } |
253 | } | 287 | } |
254 | 288 | ||
255 | static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector) | 289 | static enum flctl_ecc_res_t read_ecfiforeg |
290 | (struct sh_flctl *flctl, uint8_t *buff, int sector) | ||
256 | { | 291 | { |
257 | int i; | 292 | int i; |
293 | enum flctl_ecc_res_t res; | ||
258 | unsigned long *ecc_buf = (unsigned long *)buff; | 294 | unsigned long *ecc_buf = (unsigned long *)buff; |
259 | void *fifo_addr = (void *)FLECFIFO(flctl); | ||
260 | 295 | ||
261 | for (i = 0; i < 4; i++) { | 296 | res = wait_recfifo_ready(flctl , sector); |
262 | if (wait_recfifo_ready(flctl , sector)) | 297 | |
263 | return 1; | 298 | if (res != FL_ERROR) { |
264 | ecc_buf[i] = readl(fifo_addr); | 299 | for (i = 0; i < 4; i++) { |
265 | ecc_buf[i] = be32_to_cpu(ecc_buf[i]); | 300 | ecc_buf[i] = readl(FLECFIFO(flctl)); |
301 | ecc_buf[i] = be32_to_cpu(ecc_buf[i]); | ||
302 | } | ||
266 | } | 303 | } |
267 | 304 | ||
268 | return 0; | 305 | return res; |
269 | } | 306 | } |
270 | 307 | ||
271 | static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | 308 | static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) |
@@ -281,6 +318,18 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | |||
281 | } | 318 | } |
282 | } | 319 | } |
283 | 320 | ||
321 | static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | ||
322 | { | ||
323 | int i, len_4align; | ||
324 | unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; | ||
325 | |||
326 | len_4align = (rlen + 3) / 4; | ||
327 | for (i = 0; i < len_4align; i++) { | ||
328 | wait_wecfifo_ready(flctl); | ||
329 | writel(cpu_to_be32(data[i]), FLECFIFO(flctl)); | ||
330 | } | ||
331 | } | ||
332 | |||
284 | static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val) | 333 | static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val) |
285 | { | 334 | { |
286 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 335 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
@@ -346,73 +395,65 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va | |||
346 | static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 395 | static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
347 | uint8_t *buf, int oob_required, int page) | 396 | uint8_t *buf, int oob_required, int page) |
348 | { | 397 | { |
349 | int i, eccsize = chip->ecc.size; | 398 | chip->read_buf(mtd, buf, mtd->writesize); |
350 | int eccbytes = chip->ecc.bytes; | 399 | if (oob_required) |
351 | int eccsteps = chip->ecc.steps; | 400 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
352 | uint8_t *p = buf; | ||
353 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
354 | |||
355 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | ||
356 | chip->read_buf(mtd, p, eccsize); | ||
357 | |||
358 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | ||
359 | if (flctl->hwecc_cant_correct[i]) | ||
360 | mtd->ecc_stats.failed++; | ||
361 | else | ||
362 | mtd->ecc_stats.corrected += 0; /* FIXME */ | ||
363 | } | ||
364 | |||
365 | return 0; | 401 | return 0; |
366 | } | 402 | } |
367 | 403 | ||
368 | static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 404 | static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
369 | const uint8_t *buf, int oob_required) | 405 | const uint8_t *buf, int oob_required) |
370 | { | 406 | { |
371 | int i, eccsize = chip->ecc.size; | 407 | chip->write_buf(mtd, buf, mtd->writesize); |
372 | int eccbytes = chip->ecc.bytes; | 408 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); |
373 | int eccsteps = chip->ecc.steps; | 409 | return 0; |
374 | const uint8_t *p = buf; | ||
375 | |||
376 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | ||
377 | chip->write_buf(mtd, p, eccsize); | ||
378 | } | 410 | } |
379 | 411 | ||
380 | static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) | 412 | static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) |
381 | { | 413 | { |
382 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 414 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
383 | int sector, page_sectors; | 415 | int sector, page_sectors; |
416 | enum flctl_ecc_res_t ecc_result; | ||
384 | 417 | ||
385 | if (flctl->page_size) | 418 | page_sectors = flctl->page_size ? 4 : 1; |
386 | page_sectors = 4; | ||
387 | else | ||
388 | page_sectors = 1; | ||
389 | |||
390 | writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT, | ||
391 | FLCMNCR(flctl)); | ||
392 | 419 | ||
393 | set_cmd_regs(mtd, NAND_CMD_READ0, | 420 | set_cmd_regs(mtd, NAND_CMD_READ0, |
394 | (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); | 421 | (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); |
395 | 422 | ||
396 | for (sector = 0; sector < page_sectors; sector++) { | 423 | writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT, |
397 | int ret; | 424 | FLCMNCR(flctl)); |
425 | writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl)); | ||
426 | writel(page_addr << 2, FLADR(flctl)); | ||
398 | 427 | ||
399 | empty_fifo(flctl); | 428 | empty_fifo(flctl); |
400 | writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl)); | 429 | start_translation(flctl); |
401 | writel(page_addr << 2 | sector, FLADR(flctl)); | ||
402 | 430 | ||
403 | start_translation(flctl); | 431 | for (sector = 0; sector < page_sectors; sector++) { |
404 | read_fiforeg(flctl, 512, 512 * sector); | 432 | read_fiforeg(flctl, 512, 512 * sector); |
405 | 433 | ||
406 | ret = read_ecfiforeg(flctl, | 434 | ecc_result = read_ecfiforeg(flctl, |
407 | &flctl->done_buff[mtd->writesize + 16 * sector], | 435 | &flctl->done_buff[mtd->writesize + 16 * sector], |
408 | sector); | 436 | sector); |
409 | 437 | ||
410 | if (ret) | 438 | switch (ecc_result) { |
411 | flctl->hwecc_cant_correct[sector] = 1; | 439 | case FL_REPAIRABLE: |
412 | 440 | dev_info(&flctl->pdev->dev, | |
413 | writel(0x0, FL4ECCCR(flctl)); | 441 | "applied ecc on page 0x%x", page_addr); |
414 | wait_completion(flctl); | 442 | flctl->mtd.ecc_stats.corrected++; |
443 | break; | ||
444 | case FL_ERROR: | ||
445 | dev_warn(&flctl->pdev->dev, | ||
446 | "page 0x%x contains corrupted data\n", | ||
447 | page_addr); | ||
448 | flctl->mtd.ecc_stats.failed++; | ||
449 | break; | ||
450 | default: | ||
451 | ; | ||
452 | } | ||
415 | } | 453 | } |
454 | |||
455 | wait_completion(flctl); | ||
456 | |||
416 | writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT), | 457 | writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT), |
417 | FLCMNCR(flctl)); | 458 | FLCMNCR(flctl)); |
418 | } | 459 | } |
@@ -420,30 +461,20 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) | |||
420 | static void execmd_read_oob(struct mtd_info *mtd, int page_addr) | 461 | static void execmd_read_oob(struct mtd_info *mtd, int page_addr) |
421 | { | 462 | { |
422 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 463 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
464 | int page_sectors = flctl->page_size ? 4 : 1; | ||
465 | int i; | ||
423 | 466 | ||
424 | set_cmd_regs(mtd, NAND_CMD_READ0, | 467 | set_cmd_regs(mtd, NAND_CMD_READ0, |
425 | (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); | 468 | (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); |
426 | 469 | ||
427 | empty_fifo(flctl); | 470 | empty_fifo(flctl); |
428 | if (flctl->page_size) { | ||
429 | int i; | ||
430 | /* In case that the page size is 2k */ | ||
431 | for (i = 0; i < 16 * 3; i++) | ||
432 | flctl->done_buff[i] = 0xFF; | ||
433 | |||
434 | set_addr(mtd, 3 * 528 + 512, page_addr); | ||
435 | writel(16, FLDTCNTR(flctl)); | ||
436 | 471 | ||
437 | start_translation(flctl); | 472 | for (i = 0; i < page_sectors; i++) { |
438 | read_fiforeg(flctl, 16, 16 * 3); | 473 | set_addr(mtd, (512 + 16) * i + 512 , page_addr); |
439 | wait_completion(flctl); | ||
440 | } else { | ||
441 | /* In case that the page size is 512b */ | ||
442 | set_addr(mtd, 512, page_addr); | ||
443 | writel(16, FLDTCNTR(flctl)); | 474 | writel(16, FLDTCNTR(flctl)); |
444 | 475 | ||
445 | start_translation(flctl); | 476 | start_translation(flctl); |
446 | read_fiforeg(flctl, 16, 0); | 477 | read_fiforeg(flctl, 16, 16 * i); |
447 | wait_completion(flctl); | 478 | wait_completion(flctl); |
448 | } | 479 | } |
449 | } | 480 | } |
@@ -451,34 +482,26 @@ static void execmd_read_oob(struct mtd_info *mtd, int page_addr) | |||
451 | static void execmd_write_page_sector(struct mtd_info *mtd) | 482 | static void execmd_write_page_sector(struct mtd_info *mtd) |
452 | { | 483 | { |
453 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 484 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
454 | int i, page_addr = flctl->seqin_page_addr; | 485 | int page_addr = flctl->seqin_page_addr; |
455 | int sector, page_sectors; | 486 | int sector, page_sectors; |
456 | 487 | ||
457 | if (flctl->page_size) | 488 | page_sectors = flctl->page_size ? 4 : 1; |
458 | page_sectors = 4; | ||
459 | else | ||
460 | page_sectors = 1; | ||
461 | |||
462 | writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl)); | ||
463 | 489 | ||
464 | set_cmd_regs(mtd, NAND_CMD_PAGEPROG, | 490 | set_cmd_regs(mtd, NAND_CMD_PAGEPROG, |
465 | (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); | 491 | (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); |
466 | 492 | ||
467 | for (sector = 0; sector < page_sectors; sector++) { | 493 | empty_fifo(flctl); |
468 | empty_fifo(flctl); | 494 | writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl)); |
469 | writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl)); | 495 | writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl)); |
470 | writel(page_addr << 2 | sector, FLADR(flctl)); | 496 | writel(page_addr << 2, FLADR(flctl)); |
497 | start_translation(flctl); | ||
471 | 498 | ||
472 | start_translation(flctl); | 499 | for (sector = 0; sector < page_sectors; sector++) { |
473 | write_fiforeg(flctl, 512, 512 * sector); | 500 | write_fiforeg(flctl, 512, 512 * sector); |
474 | 501 | write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector); | |
475 | for (i = 0; i < 4; i++) { | ||
476 | wait_wecfifo_ready(flctl); /* wait for write ready */ | ||
477 | writel(0xFFFFFFFF, FLECFIFO(flctl)); | ||
478 | } | ||
479 | wait_completion(flctl); | ||
480 | } | 502 | } |
481 | 503 | ||
504 | wait_completion(flctl); | ||
482 | writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl)); | 505 | writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl)); |
483 | } | 506 | } |
484 | 507 | ||
@@ -488,18 +511,12 @@ static void execmd_write_oob(struct mtd_info *mtd) | |||
488 | int page_addr = flctl->seqin_page_addr; | 511 | int page_addr = flctl->seqin_page_addr; |
489 | int sector, page_sectors; | 512 | int sector, page_sectors; |
490 | 513 | ||
491 | if (flctl->page_size) { | 514 | page_sectors = flctl->page_size ? 4 : 1; |
492 | sector = 3; | ||
493 | page_sectors = 4; | ||
494 | } else { | ||
495 | sector = 0; | ||
496 | page_sectors = 1; | ||
497 | } | ||
498 | 515 | ||
499 | set_cmd_regs(mtd, NAND_CMD_PAGEPROG, | 516 | set_cmd_regs(mtd, NAND_CMD_PAGEPROG, |
500 | (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); | 517 | (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); |
501 | 518 | ||
502 | for (; sector < page_sectors; sector++) { | 519 | for (sector = 0; sector < page_sectors; sector++) { |
503 | empty_fifo(flctl); | 520 | empty_fifo(flctl); |
504 | set_addr(mtd, sector * 528 + 512, page_addr); | 521 | set_addr(mtd, sector * 528 + 512, page_addr); |
505 | writel(16, FLDTCNTR(flctl)); /* set read size */ | 522 | writel(16, FLDTCNTR(flctl)); /* set read size */ |
@@ -731,10 +748,9 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr) | |||
731 | static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 748 | static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
732 | { | 749 | { |
733 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 750 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
734 | int i, index = flctl->index; | 751 | int index = flctl->index; |
735 | 752 | ||
736 | for (i = 0; i < len; i++) | 753 | memcpy(&flctl->done_buff[index], buf, len); |
737 | flctl->done_buff[index + i] = buf[i]; | ||
738 | flctl->index += len; | 754 | flctl->index += len; |
739 | } | 755 | } |
740 | 756 | ||
@@ -763,20 +779,11 @@ static uint16_t flctl_read_word(struct mtd_info *mtd) | |||
763 | 779 | ||
764 | static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | 780 | static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
765 | { | 781 | { |
766 | int i; | 782 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
767 | 783 | int index = flctl->index; | |
768 | for (i = 0; i < len; i++) | ||
769 | buf[i] = flctl_read_byte(mtd); | ||
770 | } | ||
771 | |||
772 | static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
773 | { | ||
774 | int i; | ||
775 | 784 | ||
776 | for (i = 0; i < len; i++) | 785 | memcpy(buf, &flctl->done_buff[index], len); |
777 | if (buf[i] != flctl_read_byte(mtd)) | 786 | flctl->index += len; |
778 | return -EFAULT; | ||
779 | return 0; | ||
780 | } | 787 | } |
781 | 788 | ||
782 | static int flctl_chip_init_tail(struct mtd_info *mtd) | 789 | static int flctl_chip_init_tail(struct mtd_info *mtd) |
@@ -831,7 +838,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) | |||
831 | chip->ecc.mode = NAND_ECC_HW; | 838 | chip->ecc.mode = NAND_ECC_HW; |
832 | 839 | ||
833 | /* 4 symbols ECC enabled */ | 840 | /* 4 symbols ECC enabled */ |
834 | flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02; | 841 | flctl->flcmncr_base |= _4ECCEN; |
835 | } else { | 842 | } else { |
836 | chip->ecc.mode = NAND_ECC_SOFT; | 843 | chip->ecc.mode = NAND_ECC_SOFT; |
837 | } | 844 | } |
@@ -839,6 +846,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) | |||
839 | return 0; | 846 | return 0; |
840 | } | 847 | } |
841 | 848 | ||
849 | static 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 | |||
842 | static int __devinit flctl_probe(struct platform_device *pdev) | 859 | static int __devinit flctl_probe(struct platform_device *pdev) |
843 | { | 860 | { |
844 | struct resource *res; | 861 | struct resource *res; |
@@ -847,6 +864,7 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
847 | struct nand_chip *nand; | 864 | struct nand_chip *nand; |
848 | struct sh_flctl_platform_data *pdata; | 865 | struct sh_flctl_platform_data *pdata; |
849 | int ret = -ENXIO; | 866 | int ret = -ENXIO; |
867 | int irq; | ||
850 | 868 | ||
851 | pdata = pdev->dev.platform_data; | 869 | pdata = pdev->dev.platform_data; |
852 | if (pdata == NULL) { | 870 | if (pdata == NULL) { |
@@ -872,14 +890,27 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
872 | goto err_iomap; | 890 | goto err_iomap; |
873 | } | 891 | } |
874 | 892 | ||
893 | 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 | |||
875 | platform_set_drvdata(pdev, flctl); | 905 | platform_set_drvdata(pdev, flctl); |
876 | flctl_mtd = &flctl->mtd; | 906 | flctl_mtd = &flctl->mtd; |
877 | nand = &flctl->chip; | 907 | nand = &flctl->chip; |
878 | flctl_mtd->priv = nand; | 908 | flctl_mtd->priv = nand; |
879 | flctl->pdev = pdev; | 909 | flctl->pdev = pdev; |
880 | flctl->flcmncr_base = pdata->flcmncr_val; | ||
881 | flctl->hwecc = pdata->has_hwecc; | 910 | flctl->hwecc = pdata->has_hwecc; |
882 | flctl->holden = pdata->use_holden; | 911 | flctl->holden = pdata->use_holden; |
912 | flctl->flcmncr_base = pdata->flcmncr_val; | ||
913 | flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE; | ||
883 | 914 | ||
884 | /* Set address of hardware control function */ | 915 | /* Set address of hardware control function */ |
885 | /* 20 us command delay time */ | 916 | /* 20 us command delay time */ |
@@ -888,7 +919,6 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
888 | nand->read_byte = flctl_read_byte; | 919 | nand->read_byte = flctl_read_byte; |
889 | nand->write_buf = flctl_write_buf; | 920 | nand->write_buf = flctl_write_buf; |
890 | nand->read_buf = flctl_read_buf; | 921 | nand->read_buf = flctl_read_buf; |
891 | nand->verify_buf = flctl_verify_buf; | ||
892 | nand->select_chip = flctl_select_chip; | 922 | nand->select_chip = flctl_select_chip; |
893 | nand->cmdfunc = flctl_cmdfunc; | 923 | nand->cmdfunc = flctl_cmdfunc; |
894 | 924 | ||
@@ -918,6 +948,9 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
918 | 948 | ||
919 | err_chip: | 949 | err_chip: |
920 | pm_runtime_disable(&pdev->dev); | 950 | pm_runtime_disable(&pdev->dev); |
951 | free_irq(irq, flctl); | ||
952 | err_flste: | ||
953 | iounmap(flctl->reg); | ||
921 | err_iomap: | 954 | err_iomap: |
922 | kfree(flctl); | 955 | kfree(flctl); |
923 | return ret; | 956 | return ret; |
@@ -929,6 +962,8 @@ static int __devexit flctl_remove(struct platform_device *pdev) | |||
929 | 962 | ||
930 | nand_release(&flctl->mtd); | 963 | nand_release(&flctl->mtd); |
931 | pm_runtime_disable(&pdev->dev); | 964 | pm_runtime_disable(&pdev->dev); |
965 | free_irq(platform_get_irq(pdev, 0), flctl); | ||
966 | iounmap(flctl->reg); | ||
932 | kfree(flctl); | 967 | kfree(flctl); |
933 | 968 | ||
934 | return 0; | 969 | return 0; |