diff options
| -rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 6d0fa4cd1ddf..f5fd25461a09 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
| @@ -94,6 +94,7 @@ struct mxc_nand_host { | |||
| 94 | struct clk *clk; | 94 | struct clk *clk; |
| 95 | int clk_act; | 95 | int clk_act; |
| 96 | int irq; | 96 | int irq; |
| 97 | int eccsize; | ||
| 97 | 98 | ||
| 98 | wait_queue_head_t irq_waitq; | 99 | wait_queue_head_t irq_waitq; |
| 99 | 100 | ||
| @@ -342,7 +343,7 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) | |||
| 342 | */ | 343 | */ |
| 343 | } | 344 | } |
| 344 | 345 | ||
| 345 | static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | 346 | static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, |
| 346 | u_char *read_ecc, u_char *calc_ecc) | 347 | u_char *read_ecc, u_char *calc_ecc) |
| 347 | { | 348 | { |
| 348 | struct nand_chip *nand_chip = mtd->priv; | 349 | struct nand_chip *nand_chip = mtd->priv; |
| @@ -364,6 +365,40 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
| 364 | return 0; | 365 | return 0; |
| 365 | } | 366 | } |
| 366 | 367 | ||
| 368 | static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, | ||
| 369 | u_char *read_ecc, u_char *calc_ecc) | ||
| 370 | { | ||
| 371 | struct nand_chip *nand_chip = mtd->priv; | ||
| 372 | struct mxc_nand_host *host = nand_chip->priv; | ||
| 373 | u32 ecc_stat, err; | ||
| 374 | int no_subpages = 1; | ||
| 375 | int ret = 0; | ||
| 376 | u8 ecc_bit_mask, err_limit; | ||
| 377 | |||
| 378 | ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf; | ||
| 379 | err_limit = (host->eccsize == 4) ? 0x4 : 0x8; | ||
| 380 | |||
| 381 | no_subpages = mtd->writesize >> 9; | ||
| 382 | |||
| 383 | ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT); | ||
| 384 | |||
| 385 | do { | ||
| 386 | err = ecc_stat & ecc_bit_mask; | ||
| 387 | if (err > err_limit) { | ||
| 388 | printk(KERN_WARNING "UnCorrectable RS-ECC Error\n"); | ||
| 389 | return -1; | ||
| 390 | } else { | ||
| 391 | ret += err; | ||
| 392 | } | ||
| 393 | ecc_stat >>= 4; | ||
| 394 | } while (--no_subpages); | ||
| 395 | |||
| 396 | mtd->ecc_stats.corrected += ret; | ||
| 397 | pr_debug("%d Symbol Correctable RS-ECC Error\n", ret); | ||
| 398 | |||
| 399 | return ret; | ||
| 400 | } | ||
| 401 | |||
| 367 | static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | 402 | static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, |
| 368 | u_char *ecc_code) | 403 | u_char *ecc_code) |
| 369 | { | 404 | { |
| @@ -790,7 +825,10 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 790 | if (pdata->hw_ecc) { | 825 | if (pdata->hw_ecc) { |
| 791 | this->ecc.calculate = mxc_nand_calculate_ecc; | 826 | this->ecc.calculate = mxc_nand_calculate_ecc; |
| 792 | this->ecc.hwctl = mxc_nand_enable_hwecc; | 827 | this->ecc.hwctl = mxc_nand_enable_hwecc; |
| 793 | this->ecc.correct = mxc_nand_correct_data; | 828 | if (nfc_is_v1()) |
| 829 | this->ecc.correct = mxc_nand_correct_data_v1; | ||
| 830 | else | ||
| 831 | this->ecc.correct = mxc_nand_correct_data_v2_v3; | ||
| 794 | this->ecc.mode = NAND_ECC_HW; | 832 | this->ecc.mode = NAND_ECC_HW; |
| 795 | } else { | 833 | } else { |
| 796 | this->ecc.mode = NAND_ECC_SOFT; | 834 | this->ecc.mode = NAND_ECC_SOFT; |
