diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 57 |
1 files changed, 35 insertions, 22 deletions
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ce3449c50e12..f00ce27f61d0 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -85,6 +85,9 @@ | |||
85 | #define NDCR_INT_MASK (0xFFF) | 85 | #define NDCR_INT_MASK (0xFFF) |
86 | 86 | ||
87 | #define NDSR_MASK (0xfff) | 87 | #define NDSR_MASK (0xfff) |
88 | #define NDSR_ERR_CNT_OFF (16) | ||
89 | #define NDSR_ERR_CNT_MASK (0x1f) | ||
90 | #define NDSR_ERR_CNT(sr) ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK) | ||
88 | #define NDSR_RDY (0x1 << 12) | 91 | #define NDSR_RDY (0x1 << 12) |
89 | #define NDSR_FLASH_RDY (0x1 << 11) | 92 | #define NDSR_FLASH_RDY (0x1 << 11) |
90 | #define NDSR_CS0_PAGED (0x1 << 10) | 93 | #define NDSR_CS0_PAGED (0x1 << 10) |
@@ -93,8 +96,8 @@ | |||
93 | #define NDSR_CS1_CMDD (0x1 << 7) | 96 | #define NDSR_CS1_CMDD (0x1 << 7) |
94 | #define NDSR_CS0_BBD (0x1 << 6) | 97 | #define NDSR_CS0_BBD (0x1 << 6) |
95 | #define NDSR_CS1_BBD (0x1 << 5) | 98 | #define NDSR_CS1_BBD (0x1 << 5) |
96 | #define NDSR_DBERR (0x1 << 4) | 99 | #define NDSR_UNCORERR (0x1 << 4) |
97 | #define NDSR_SBERR (0x1 << 3) | 100 | #define NDSR_CORERR (0x1 << 3) |
98 | #define NDSR_WRDREQ (0x1 << 2) | 101 | #define NDSR_WRDREQ (0x1 << 2) |
99 | #define NDSR_RDDREQ (0x1 << 1) | 102 | #define NDSR_RDDREQ (0x1 << 1) |
100 | #define NDSR_WRCMDREQ (0x1) | 103 | #define NDSR_WRCMDREQ (0x1) |
@@ -135,9 +138,9 @@ enum { | |||
135 | ERR_NONE = 0, | 138 | ERR_NONE = 0, |
136 | ERR_DMABUSERR = -1, | 139 | ERR_DMABUSERR = -1, |
137 | ERR_SENDCMD = -2, | 140 | ERR_SENDCMD = -2, |
138 | ERR_DBERR = -3, | 141 | ERR_UNCORERR = -3, |
139 | ERR_BBERR = -4, | 142 | ERR_BBERR = -4, |
140 | ERR_SBERR = -5, | 143 | ERR_CORERR = -5, |
141 | }; | 144 | }; |
142 | 145 | ||
143 | enum { | 146 | enum { |
@@ -221,6 +224,8 @@ struct pxa3xx_nand_info { | |||
221 | unsigned int oob_size; | 224 | unsigned int oob_size; |
222 | unsigned int spare_size; | 225 | unsigned int spare_size; |
223 | unsigned int ecc_size; | 226 | unsigned int ecc_size; |
227 | unsigned int ecc_err_cnt; | ||
228 | unsigned int max_bitflips; | ||
224 | int retcode; | 229 | int retcode; |
225 | 230 | ||
226 | /* cached register value */ | 231 | /* cached register value */ |
@@ -567,10 +572,25 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
567 | 572 | ||
568 | status = nand_readl(info, NDSR); | 573 | status = nand_readl(info, NDSR); |
569 | 574 | ||
570 | if (status & NDSR_DBERR) | 575 | if (status & NDSR_UNCORERR) |
571 | info->retcode = ERR_DBERR; | 576 | info->retcode = ERR_UNCORERR; |
572 | if (status & NDSR_SBERR) | 577 | if (status & NDSR_CORERR) { |
573 | info->retcode = ERR_SBERR; | 578 | info->retcode = ERR_CORERR; |
579 | if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 && | ||
580 | info->ecc_bch) | ||
581 | info->ecc_err_cnt = NDSR_ERR_CNT(status); | ||
582 | else | ||
583 | info->ecc_err_cnt = 1; | ||
584 | |||
585 | /* | ||
586 | * Each chunk composing a page is corrected independently, | ||
587 | * and we need to store maximum number of corrected bitflips | ||
588 | * to return it to the MTD layer in ecc.read_page(). | ||
589 | */ | ||
590 | info->max_bitflips = max_t(unsigned int, | ||
591 | info->max_bitflips, | ||
592 | info->ecc_err_cnt); | ||
593 | } | ||
574 | if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { | 594 | if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { |
575 | /* whether use dma to transfer data */ | 595 | /* whether use dma to transfer data */ |
576 | if (info->use_dma) { | 596 | if (info->use_dma) { |
@@ -668,6 +688,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) | |||
668 | info->use_ecc = 0; | 688 | info->use_ecc = 0; |
669 | info->use_spare = 1; | 689 | info->use_spare = 1; |
670 | info->retcode = ERR_NONE; | 690 | info->retcode = ERR_NONE; |
691 | info->ecc_err_cnt = 0; | ||
671 | info->ndcb3 = 0; | 692 | info->ndcb3 = 0; |
672 | 693 | ||
673 | switch (command) { | 694 | switch (command) { |
@@ -1049,26 +1070,18 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, | |||
1049 | { | 1070 | { |
1050 | struct pxa3xx_nand_host *host = mtd->priv; | 1071 | struct pxa3xx_nand_host *host = mtd->priv; |
1051 | struct pxa3xx_nand_info *info = host->info_data; | 1072 | struct pxa3xx_nand_info *info = host->info_data; |
1052 | int max_bitflips = 0; | ||
1053 | 1073 | ||
1054 | chip->read_buf(mtd, buf, mtd->writesize); | 1074 | chip->read_buf(mtd, buf, mtd->writesize); |
1055 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | 1075 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
1056 | 1076 | ||
1057 | if (info->retcode == ERR_SBERR) { | 1077 | if (info->retcode == ERR_CORERR && info->use_ecc) { |
1058 | switch (info->use_ecc) { | 1078 | mtd->ecc_stats.corrected += info->ecc_err_cnt; |
1059 | case 1: | 1079 | |
1060 | max_bitflips = 1; | 1080 | } else if (info->retcode == ERR_UNCORERR) { |
1061 | mtd->ecc_stats.corrected++; | ||
1062 | break; | ||
1063 | case 0: | ||
1064 | default: | ||
1065 | break; | ||
1066 | } | ||
1067 | } else if (info->retcode == ERR_DBERR) { | ||
1068 | /* | 1081 | /* |
1069 | * for blank page (all 0xff), HW will calculate its ECC as | 1082 | * for blank page (all 0xff), HW will calculate its ECC as |
1070 | * 0, which is different from the ECC information within | 1083 | * 0, which is different from the ECC information within |
1071 | * OOB, ignore such double bit errors | 1084 | * OOB, ignore such uncorrectable errors |
1072 | */ | 1085 | */ |
1073 | if (is_buf_blank(buf, mtd->writesize)) | 1086 | if (is_buf_blank(buf, mtd->writesize)) |
1074 | info->retcode = ERR_NONE; | 1087 | info->retcode = ERR_NONE; |
@@ -1076,7 +1089,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, | |||
1076 | mtd->ecc_stats.failed++; | 1089 | mtd->ecc_stats.failed++; |
1077 | } | 1090 | } |
1078 | 1091 | ||
1079 | return max_bitflips; | 1092 | return info->max_bitflips; |
1080 | } | 1093 | } |
1081 | 1094 | ||
1082 | static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) | 1095 | static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) |