[U-Boot] [PATCH v2 2/3] mtd: nand: omap: add support for BCH16_ECC - NAND driver updates
Pekon Gupta
pekon at ti.com
Tue Sep 10 09:25:07 CEST 2013
With increase in NAND flash densities occurence of bit-flips has increased.
Thus stronger ECC schemes are required for detecting and correcting multiple
simultaneous bit-flips in same NAND page. But stronger ECC schemes have large
ECC syndrome which require more space in OOB/Spare.
This patch add support for BCH16_ECC:
(a) BCH16_ECC can correct 16 bit-flips per 512Bytes of data.
(b) BCH16_ECC 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 following equation:
OOBsize per page >= 26 * (page-size / 512)
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
arch/arm/include/asm/arch-am33xx/cpu.h | 15 ++++-
arch/arm/include/asm/arch-am33xx/omap_gpmc.h | 4 +-
drivers/mtd/nand/omap_gpmc.c | 87 +++++++++++++++++++++++-----
include/mtd/mtd-abi.h | 3 +-
4 files changed, 90 insertions(+), 19 deletions(-)
diff --git a/arch/arm/include/asm/arch-am33xx/cpu.h b/arch/arm/include/asm/arch-am33xx/cpu.h
index 10b56e0..1de92e6 100644
--- a/arch/arm/include/asm/arch-am33xx/cpu.h
+++ b/arch/arm/include/asm/arch-am33xx/cpu.h
@@ -63,7 +63,16 @@ struct gpmc_cs {
};
struct bch_res_0_3 {
- u32 bch_result_x[4];
+ u32 bch_result0;
+ u32 bch_result1;
+ u32 bch_result2;
+ u32 bch_result3;
+};
+
+struct bch_res_4_6 {
+ u32 bch_result4;
+ u32 bch_result5;
+ u32 bch_result6;
};
struct gpmc {
@@ -95,7 +104,9 @@ struct gpmc {
u8 res7[12]; /* 0x224 */
u32 testmomde_ctrl; /* 0x230 */
u8 res8[12]; /* 0x234 */
- struct bch_res_0_3 bch_result_0_3[2]; /* 0x240 */
+ struct bch_res_0_3 bch_result_0_3[8]; /* 0x240 - 0x2BF */
+ u8 res9[16 * 4]; /* 0x2C0 - 0x2FF */
+ struct bch_res_4_6 bch_result_4_6[8]; /* 0x300 - 0x37F */
};
/* Used for board specific gpmc initialization */
diff --git a/arch/arm/include/asm/arch-am33xx/omap_gpmc.h b/arch/arm/include/asm/arch-am33xx/omap_gpmc.h
index 69982c1..ade0ca4 100644
--- a/arch/arm/include/asm/arch-am33xx/omap_gpmc.h
+++ b/arch/arm/include/asm/arch-am33xx/omap_gpmc.h
@@ -16,7 +16,9 @@ enum omap_ecc {
/* 8-bit ECC calculation by GPMC, Error detection by Software */
OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
/* 8-bit ECC calculation by GPMC, Error detection by ELM */
- OMAP_ECC_BCH8_CODE_HW
+ OMAP_ECC_BCH8_CODE_HW,
+ /* 16-bit ECC calculation by GPMC, Error detection by ELM */
+ OMAP_ECC_BCH16_CODE_HW,
};
#endif /* __ASM_ARCH_OMAP_GPMC_H */
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index c1a7317..b044f00 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -154,21 +154,10 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
struct nand_bch_priv {
uint8_t mode;
uint8_t type;
- uint8_t nibbles;
struct bch_control *control;
enum omap_ecc ecc_scheme;
};
-/* bch types */
-#define ECC_BCH4 0
-#define ECC_BCH8 1
-#define ECC_BCH16 2
-
-/* BCH nibbles for diff bch levels */
-#define ECC_BCH4_NIBBLES 13
-#define ECC_BCH8_NIBBLES 26
-#define ECC_BCH16_NIBBLES 52
-
/*
* This can be a single instance cause all current users have only one NAND
* with nearly the same setup (BCH8, some with ELM and others with sw BCH
@@ -177,7 +166,6 @@ struct nand_bch_priv {
*/
static __maybe_unused struct nand_bch_priv bch_priv = {
.type = ECC_BCH8,
- .nibbles = ECC_BCH8_NIBBLES,
.control = NULL
};
@@ -243,6 +231,19 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
eccsize1 = 2; /* non-ECC bits in nibbles per sector */
}
break;
+ case OMAP_ECC_BCH16_CODE_HW:
+ ecc_algo = 0x1;
+ bch_type = 0x2;
+ if (mode == NAND_ECC_WRITE) {
+ bch_wrapmode = 0x01;
+ eccsize0 = 0; /* extra bits in nibbles per sector */
+ eccsize1 = 52; /* OOB bits in nibbles per sector */
+ } else {
+ bch_wrapmode = 0x01;
+ eccsize0 = 52; /* ECC bits in nibbles per sector */
+ eccsize1 = 0; /* non-ECC bits in nibbles per sector */
+ }
+ break;
default:
return;
}
@@ -295,7 +296,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
break;
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
case OMAP_ECC_BCH8_CODE_HW:
- ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
+ ptr = &gpmc_cfg->bch_result_0_3[0].bch_result3;
val = readl(ptr);
ecc_code[i++] = (val >> 0) & 0xFF;
ptr--;
@@ -308,6 +309,27 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
ptr--;
}
break;
+ case OMAP_ECC_BCH16_CODE_HW:
+ ptr = &gpmc_cfg->bch_result_4_6[0].bch_result6;
+ ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
+ ecc_code[i++] = (readl(ptr) >> 0) & 0xFF;
+ ptr--;
+ for (j = 0; j < 2; j++) {
+ ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
+ ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
+ ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
+ ecc_code[i++] = (readl(ptr) >> 0) & 0xFF;
+ ptr--;
+ }
+ ptr = &gpmc_cfg->bch_result_0_3[0].bch_result3;
+ for (j = 0; j < 4; j++) {
+ ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
+ ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
+ ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
+ ecc_code[i++] = (readl(ptr) >> 0) & 0xFF;
+ ptr--;
+ }
+ break;
default:
return -EINVAL;
}
@@ -326,6 +348,8 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
case OMAP_ECC_BCH8_CODE_HW:
ecc_code[chip->ecc.bytes - 1] = 0x00;
break;
+ case OMAP_ECC_BCH16_CODE_HW:
+ break;
}
return 0;
}
@@ -376,12 +400,15 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
case OMAP_ECC_BCH8_CODE_HW:
omap_reverse_list(calc_ecc, eccbytes - 1);
break;
+ case OMAP_ECC_BCH16_CODE_HW:
+ omap_reverse_list(calc_ecc, eccbytes);
+ break;
default:
return -EINVAL;
}
/* use elm module to check for errors */
- elm_config((enum bch_level)(bch->type));
- if (elm_check_error(calc_ecc, bch->nibbles, &error_count, error_loc)) {
+ elm_config(bch->type);
+ if (elm_check_error(calc_ecc, bch->type, &error_count, error_loc)) {
printf("nand: error: uncorrectable ECC errors\n");
return -EINVAL;
}
@@ -392,6 +419,9 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
/* 14th byte in ECC is reserved to match ROM layout */
error_max = SECTOR_BYTES + (eccbytes - 1);
break;
+ case ECC_BCH16:
+ error_max = SECTOR_BYTES + eccbytes;
+ break;
default:
return -EINVAL;
}
@@ -614,6 +644,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, int ecc_scheme,
printf("nand: error: could not init_bch()\n");
return -ENODEV;
}
+ bch_priv.type = ECC_BCH8;
/* define ecc-layout */
ecclayout->eccbytes = nand->ecc.bytes *
(pagesize / SECTOR_BYTES);
@@ -638,6 +669,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, int ecc_scheme,
nand->ecc.read_page = omap_read_page_bch;
/* ELM is used for ECC error detection */
elm_init();
+ bch_priv.type = ECC_BCH8;
/* define ecc-layout */
ecclayout->eccbytes = nand->ecc.bytes *
(pagesize / SECTOR_BYTES);
@@ -650,6 +682,31 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, int ecc_scheme,
BADBLOCK_MARKER_LENGTH;
bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW;
break;
+ case OMAP_ECC_BCH16_CODE_HW:
+ debug("nand: using OMAP_ECC_BCH16_CODE_HW\n");
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.size = SECTOR_BYTES;
+ nand->ecc.bytes = 26;
+ nand->ecc.strength = 16;
+ nand->ecc.hwctl = omap_enable_hwecc;
+ nand->ecc.correct = omap_correct_data_bch;
+ nand->ecc.calculate = omap_calculate_ecc;
+ nand->ecc.read_page = omap_read_page_bch;
+ /* ELM is used for ECC error detection */
+ elm_init();
+ bch_priv.type = ECC_BCH16;
+ /* define ecc-layout */
+ ecclayout->eccbytes = nand->ecc.bytes *
+ (pagesize / SECTOR_BYTES);
+ for (i = 0; i < ecclayout->eccbytes; i++)
+ ecclayout->eccpos[i] = i +
+ BADBLOCK_MARKER_LENGTH;
+ ecclayout->oobfree[0].offset = i +
+ BADBLOCK_MARKER_LENGTH;
+ ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes -
+ BADBLOCK_MARKER_LENGTH;
+ bch->ecc_scheme = OMAP_ECC_BCH16_CODE_HW;
+ break;
default:
debug("nand: error: ecc scheme not enabled or supported\n");
return -EINVAL;
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index d51c1ab..f7040be 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -156,13 +156,14 @@ struct nand_oobfree {
};
#define MTD_MAX_OOBFREE_ENTRIES 8
+#define MTD_MAX_ECCPOS_ENTRIES 256
/*
* ECC layout control structure. Exported to userspace for
* diagnosis and to allow creation of raw images
*/
struct nand_ecclayout {
uint32_t eccbytes;
- uint32_t eccpos[128];
+ uint32_t eccpos[MTD_MAX_ECCPOS_ENTRIES];
uint32_t oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};
--
1.8.1
More information about the U-Boot
mailing list