diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/rtc_from4.c | 94 |
1 files changed, 89 insertions, 5 deletions
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index a4d8d2e62e9e..031051cbde76 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: rtc_from4.c,v 1.8 2005/01/17 19:44:36 dmarlin Exp $ | 9 | * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -83,9 +83,14 @@ static struct mtd_info *rtc_from4_mtd = NULL; | |||
83 | #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) | 83 | #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) |
84 | #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) | 84 | #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) |
85 | 85 | ||
86 | #define ERR_STAT_ECC_AVAILABLE 0x20 | ||
87 | |||
86 | /* Undefine for software ECC */ | 88 | /* Undefine for software ECC */ |
87 | #define RTC_FROM4_HWECC 1 | 89 | #define RTC_FROM4_HWECC 1 |
88 | 90 | ||
91 | /* Define as 1 for no virtual erase blocks (in JFFS2) */ | ||
92 | #define RTC_FROM4_NO_VIRTBLOCKS 0 | ||
93 | |||
89 | /* | 94 | /* |
90 | * Module stuff | 95 | * Module stuff |
91 | */ | 96 | */ |
@@ -267,7 +272,6 @@ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip) | |||
267 | } | 272 | } |
268 | 273 | ||
269 | 274 | ||
270 | |||
271 | /* | 275 | /* |
272 | * rtc_from4_nand_device_ready - hardware specific ready/busy check | 276 | * rtc_from4_nand_device_ready - hardware specific ready/busy check |
273 | * @mtd: MTD device structure | 277 | * @mtd: MTD device structure |
@@ -363,6 +367,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | |||
363 | 367 | ||
364 | } | 368 | } |
365 | 369 | ||
370 | |||
366 | /* | 371 | /* |
367 | * rtc_from4_calculate_ecc - hardware specific code to read ECC code | 372 | * rtc_from4_calculate_ecc - hardware specific code to read ECC code |
368 | * @mtd: MTD device structure | 373 | * @mtd: MTD device structure |
@@ -390,6 +395,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
390 | ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ | 395 | ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ |
391 | } | 396 | } |
392 | 397 | ||
398 | |||
393 | /* | 399 | /* |
394 | * rtc_from4_correct_data - hardware specific code to correct data using ECC code | 400 | * rtc_from4_correct_data - hardware specific code to correct data using ECC code |
395 | * @mtd: MTD device structure | 401 | * @mtd: MTD device structure |
@@ -399,10 +405,8 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
399 | * | 405 | * |
400 | * The FPGA tells us fast, if there's an error or not. If no, we go back happy | 406 | * The FPGA tells us fast, if there's an error or not. If no, we go back happy |
401 | * else we read the ecc results from the fpga and call the rs library to decode | 407 | * else we read the ecc results from the fpga and call the rs library to decode |
402 | * and hopefully correct the error | 408 | * and hopefully correct the error. |
403 | * | 409 | * |
404 | * For now I use the code, which we read from the FLASH to use the RS lib, | ||
405 | * as the syndrom conversion has a unresolved issue. | ||
406 | */ | 410 | */ |
407 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) | 411 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) |
408 | { | 412 | { |
@@ -457,8 +461,79 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
457 | } | 461 | } |
458 | return res; | 462 | return res; |
459 | } | 463 | } |
464 | |||
465 | |||
466 | /** | ||
467 | * rtc_from4_errstat - perform additional error status checks | ||
468 | * @mtd: MTD device structure | ||
469 | * @this: NAND chip structure | ||
470 | * @state: state or the operation | ||
471 | * @status: status code returned from read status | ||
472 | * @page: startpage inside the chip, must be called with (page & this->pagemask) | ||
473 | * | ||
474 | * Perform additional error status checks on erase and write failures | ||
475 | * to determine if errors are correctable. For this device, correctable | ||
476 | * 1-bit errors on erase and write are considered acceptable. | ||
477 | * | ||
478 | * note: see pages 34..37 of data sheet for details. | ||
479 | * | ||
480 | */ | ||
481 | static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) | ||
482 | { | ||
483 | int er_stat=0; | ||
484 | int rtn, retlen; | ||
485 | size_t len; | ||
486 | uint8_t *buf; | ||
487 | int i; | ||
488 | |||
489 | this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1); | ||
490 | |||
491 | if (state == FL_ERASING) { | ||
492 | for (i=0; i<4; i++) { | ||
493 | if (status & 1<<(i+1)) { | ||
494 | this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); | ||
495 | rtn = this->read_byte(mtd); | ||
496 | this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); | ||
497 | if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { | ||
498 | er_stat |= 1<<(i+1); /* err_ecc_not_avail */ | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | } else if (state == FL_WRITING) { | ||
503 | /* single bank write logic */ | ||
504 | this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1); | ||
505 | rtn = this->read_byte(mtd); | ||
506 | this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); | ||
507 | if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { | ||
508 | er_stat |= 1<<1; /* err_ecc_not_avail */ | ||
509 | } else { | ||
510 | len = mtd->oobblock; | ||
511 | buf = kmalloc (len, GFP_KERNEL); | ||
512 | if (!buf) { | ||
513 | printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n"); | ||
514 | er_stat = 1; /* if we can't check, assume failed */ | ||
515 | } else { | ||
516 | /* recovery read */ | ||
517 | /* page read */ | ||
518 | rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1); | ||
519 | if (rtn) { /* if read failed or > 1-bit error corrected */ | ||
520 | er_stat |= 1<<1; /* ECC read failed */ | ||
521 | } | ||
522 | kfree(buf); | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | |||
527 | rtn = status; | ||
528 | if (er_stat == 0) { /* if ECC is available */ | ||
529 | rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ | ||
530 | } | ||
531 | |||
532 | return rtn; | ||
533 | } | ||
460 | #endif | 534 | #endif |
461 | 535 | ||
536 | |||
462 | /* | 537 | /* |
463 | * Main initialization routine | 538 | * Main initialization routine |
464 | */ | 539 | */ |
@@ -518,6 +593,8 @@ int __init rtc_from4_init (void) | |||
518 | 593 | ||
519 | this->eccmode = NAND_ECC_HW8_512; | 594 | this->eccmode = NAND_ECC_HW8_512; |
520 | this->options |= NAND_HWECC_SYNDROME; | 595 | this->options |= NAND_HWECC_SYNDROME; |
596 | /* return the status of extra status and ECC checks */ | ||
597 | this->errstat = rtc_from4_errstat; | ||
521 | /* set the nand_oobinfo to support FPGA H/W error detection */ | 598 | /* set the nand_oobinfo to support FPGA H/W error detection */ |
522 | this->autooob = &rtc_from4_nand_oobinfo; | 599 | this->autooob = &rtc_from4_nand_oobinfo; |
523 | this->enable_hwecc = rtc_from4_enable_hwecc; | 600 | this->enable_hwecc = rtc_from4_enable_hwecc; |
@@ -544,6 +621,13 @@ int __init rtc_from4_init (void) | |||
544 | deplete(rtc_from4_mtd, i); | 621 | deplete(rtc_from4_mtd, i); |
545 | } | 622 | } |
546 | 623 | ||
624 | #if RTC_FROM4_NO_VIRTBLOCKS | ||
625 | /* use a smaller erase block to minimize wasted space when a block is bad */ | ||
626 | /* note: this uses eight times as much RAM as using the default and makes */ | ||
627 | /* mounts take four times as long. */ | ||
628 | rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS; | ||
629 | #endif | ||
630 | |||
547 | /* Register the partitions */ | 631 | /* Register the partitions */ |
548 | add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); | 632 | add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); |
549 | 633 | ||