From 9fd6c6c18c1a4a3220473c76fd447c5708b5ecf9 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Tue, 15 Apr 2014 00:32:05 +0200 Subject: =?UTF-8?q?mtd:=20nand:=20omap:=20fix=20compile=20warning=20on=20?= =?UTF-8?q?=E2=80=98erased=5Fsector=5Fbitflips=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 2c9f2365 (mtd: nand: omap: ecc.calculate: merge omap3_calculate_ecc_bch4 in omap_calculate_ecc_bch) introduced minor compile warning "‘erased_sector_bitflips’ defined but not used [-Wunused-function]" when compiling without CONFIG_MTD_NAND_OMAP_BCH. Move function erased_sector_bitflips() into the same ifdef section as the only caller. Signed-off-by: Christian Engelmayer Reviewed-by: Jingoo Han Acked-by: Pekon Gupta Signed-off-by: Brian Norris --- drivers/mtd/nand/omap2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand/omap2.c') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 1ff49b8..1b800bc 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1237,6 +1237,7 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, return 0; } +#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * erased_sector_bitflips - count bit flips * @data: data sector buffer @@ -1276,7 +1277,6 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, return flip_bits; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * omap_elm_correct_data - corrects page data area in case error reported * @mtd: MTD device structure -- cgit v1.1 From f306e8c3b667632952f1a4a74ffb910bbc06255f Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Thu, 20 Mar 2014 18:49:58 +0530 Subject: mtd: nand: omap: fix BCHx ecc.correct to return detected bit-flips in erased-page fixes: commit 62116e5171e00f85a8d53f76e45b84423c89ff34 mtd: nand: omap2: Support for hardware BCH error correction. In omap_elm_correct_data(), if bitflip_count in an erased-page is within the correctable limit (< ecc.strength), then it is not indicated back to the caller ecc->read_page(). This mis-guides upper layers like MTD and UBIFS layer to assume erased-page as perfectly clean and use it for writing even if actual bitflip_count was dangerously high (bitflip_count > mtd->bitflip_threshold). This patch fixes this above issue, by returning 'stats' to caller ecc->read_page() under all scenarios. Reported-by: Brian Norris Signed-off-by: Pekon Gupta Cc: # 3.9.x+ Signed-off-by: Brian Norris --- drivers/mtd/nand/omap2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand/omap2.c') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 1b800bc..10c319e 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1382,7 +1382,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, /* Check if any error reported */ if (!is_error_reported) - return 0; + return stat; /* Decode BCH error using ELM module */ elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec); -- cgit v1.1 From 9748fff96484cfc8bb382ef1436823aefe065c9c Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 24 Mar 2014 16:50:05 +0530 Subject: mtd: nand: omap: add support for BCH16_ECC - NAND driver updates This patch add support for BCH16 ecc-scheme in OMAP NAND driver, by extending following functions: - omap_enable_hwecc (nand_chip->ecc.hwctl): configure GPMC controller - omap_calculate_ecc_bch (nand_chip->ecc.calculate): fetch ECC signature from GPMC controller - omap_elm_correct_data (nand_chip->ecc.correct): detect and correct ECC errors using ELM (a) BCH16 ecc-scheme can detect and correct 16 bit-flips per 512Bytes of data. (b) BCH16 ecc-scheme generates 26-bytes of ECC syndrome / 512B. Due to (b) this scheme can only be used with NAND devices which have enough OOB to satisfy the relation: "OOBsize per page >= 26 * (page-size / 512)" Signed-off-by: Pekon Gupta Signed-off-by: Brian Norris --- drivers/mtd/nand/omap2.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'drivers/mtd/nand/omap2.c') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 10c319e..cbe87a8 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -137,6 +137,10 @@ #define BADBLOCK_MARKER_LENGTH 2 #ifdef CONFIG_MTD_NAND_OMAP_BCH +static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, + 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, + 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, + 0x07, 0x0e}; static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; @@ -1114,6 +1118,19 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode) ecc_size1 = BCH_ECC_SIZE1; } break; + case OMAP_ECC_BCH16_CODE_HW: + bch_type = 0x2; + nsectors = chip->ecc.steps; + if (mode == NAND_ECC_READ) { + wr_mode = 0x01; + ecc_size0 = 52; /* ECC bits in nibbles per sector */ + ecc_size1 = 0; /* non-ECC bits in nibbles per sector */ + } else { + wr_mode = 0x01; + ecc_size0 = 0; /* extra bits in nibbles per sector */ + ecc_size1 = 52; /* OOB bits in nibbles per sector */ + } + break; default: return; } @@ -1162,6 +1179,7 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, struct gpmc_nand_regs *gpmc_regs = &info->reg; u8 *ecc_code; unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4; + u32 val; int i; nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; @@ -1201,6 +1219,41 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, *ecc_code++ = ((bch_val1 >> 4) & 0xFF); *ecc_code++ = ((bch_val1 & 0xF) << 4); break; + case OMAP_ECC_BCH16_CODE_HW: + val = readl(gpmc_regs->gpmc_bch_result6[i]); + ecc_code[0] = ((val >> 8) & 0xFF); + ecc_code[1] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result5[i]); + ecc_code[2] = ((val >> 24) & 0xFF); + ecc_code[3] = ((val >> 16) & 0xFF); + ecc_code[4] = ((val >> 8) & 0xFF); + ecc_code[5] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result4[i]); + ecc_code[6] = ((val >> 24) & 0xFF); + ecc_code[7] = ((val >> 16) & 0xFF); + ecc_code[8] = ((val >> 8) & 0xFF); + ecc_code[9] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result3[i]); + ecc_code[10] = ((val >> 24) & 0xFF); + ecc_code[11] = ((val >> 16) & 0xFF); + ecc_code[12] = ((val >> 8) & 0xFF); + ecc_code[13] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result2[i]); + ecc_code[14] = ((val >> 24) & 0xFF); + ecc_code[15] = ((val >> 16) & 0xFF); + ecc_code[16] = ((val >> 8) & 0xFF); + ecc_code[17] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result1[i]); + ecc_code[18] = ((val >> 24) & 0xFF); + ecc_code[19] = ((val >> 16) & 0xFF); + ecc_code[20] = ((val >> 8) & 0xFF); + ecc_code[21] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result0[i]); + ecc_code[22] = ((val >> 24) & 0xFF); + ecc_code[23] = ((val >> 16) & 0xFF); + ecc_code[24] = ((val >> 8) & 0xFF); + ecc_code[25] = ((val >> 0) & 0xFF); + break; default: return -EINVAL; } @@ -1227,6 +1280,8 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, /* Set 14th ECC byte as 0x0 for ROM compatibility */ ecc_calc[eccbytes - 1] = 0x0; break; + case OMAP_ECC_BCH16_CODE_HW: + break; default: return -EINVAL; } @@ -1318,6 +1373,10 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, actual_eccbytes = ecc->bytes - 1; erased_ecc_vec = bch8_vector; break; + case OMAP_ECC_BCH16_CODE_HW: + actual_eccbytes = ecc->bytes; + erased_ecc_vec = bch16_vector; + break; default: pr_err("invalid driver configuration\n"); return -EINVAL; @@ -1401,6 +1460,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, BCH4_BIT_PAD; break; case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: pos = err_vec[i].error_loc[j]; break; default: @@ -1912,6 +1972,40 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; #endif + case OMAP_ECC_BCH16_CODE_HW: +#ifdef CONFIG_MTD_NAND_OMAP_BCH + pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.size = 512; + nand_chip->ecc.bytes = 26; + nand_chip->ecc.strength = 16; + nand_chip->ecc.hwctl = omap_enable_hwecc_bch; + nand_chip->ecc.correct = omap_elm_correct_data; + nand_chip->ecc.calculate = omap_calculate_ecc_bch; + nand_chip->ecc.read_page = omap_read_page_bch; + nand_chip->ecc.write_page = omap_write_page_bch; + /* This ECC scheme requires ELM H/W block */ + err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); + if (err < 0) { + pr_err("ELM is required for this ECC scheme\n"); + goto return_error; + } + /* define ECC layout */ + ecclayout->eccbytes = nand_chip->ecc.bytes * + (mtd->writesize / + nand_chip->ecc.size); + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + /* reserved marker already included in ecclayout->eccbytes */ + ecclayout->oobfree->offset = + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; + break; +#else + pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); + err = -EINVAL; + goto return_error; +#endif default: pr_err("nand: error: invalid or unsupported ECC scheme\n"); err = -EINVAL; -- cgit v1.1 From 2913aae5f9eae2f857cdeff5388bb22d0751aa08 Mon Sep 17 00:00:00 2001 From: Ted Juan Date: Wed, 28 May 2014 22:33:06 +0800 Subject: mtd: nand: omap: fix omap_calculate_ecc_bch() for-loop error Fixes: 2c9f2365d1e1d0e318b068f683f18c99515b80f8 mtd: nand: omap: ecc.calculate: merge omap3_calculate_ecc_bch4 in omap_calculate_ecc_bch Fixes: 7bcd1dca1d587ad29f9825ba4414620440e8c8da mtd: nand: omap: ecc.calculate: merge omap3_calculate_ecc_bch8 in omap_calculate_ecc_bch Cc: # 3.13.x+ Signed-off-by: Ted Juan Acked-by: Pekon Gupta Signed-off-by: Brian Norris --- drivers/mtd/nand/omap2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mtd/nand/omap2.c') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index cbe87a8..f0ed92e 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1180,7 +1180,7 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, u8 *ecc_code; unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4; u32 val; - int i; + int i, j; nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; for (i = 0; i < nsectors; i++) { @@ -1263,8 +1263,8 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: /* Add constant polynomial to remainder, so that * ECC of blank pages results in 0x0 on reading back */ - for (i = 0; i < eccbytes; i++) - ecc_calc[i] ^= bch4_polynomial[i]; + for (j = 0; j < eccbytes; j++) + ecc_calc[j] ^= bch4_polynomial[j]; break; case OMAP_ECC_BCH4_CODE_HW: /* Set 8th ECC byte as 0x0 for ROM compatibility */ @@ -1273,8 +1273,8 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: /* Add constant polynomial to remainder, so that * ECC of blank pages results in 0x0 on reading back */ - for (i = 0; i < eccbytes; i++) - ecc_calc[i] ^= bch8_polynomial[i]; + for (j = 0; j < eccbytes; j++) + ecc_calc[j] ^= bch8_polynomial[j]; break; case OMAP_ECC_BCH8_CODE_HW: /* Set 14th ECC byte as 0x0 for ROM compatibility */ -- cgit v1.1