[U-Boot] [PATCH v2 1/3] am33xx: elm: add support for BCH16_ECC - ELM driver updates

Pekon Gupta pekon at ti.com
Tue Sep 10 09:25:06 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/cpu/armv7/am33xx/elm.c        | 95 ++++++++++++++++++++++------------
 arch/arm/include/asm/arch-am33xx/elm.h | 16 +++---
 2 files changed, 69 insertions(+), 42 deletions(-)

diff --git a/arch/arm/cpu/armv7/am33xx/elm.c b/arch/arm/cpu/armv7/am33xx/elm.c
index 8f1d6af..0196034 100644
--- a/arch/arm/cpu/armv7/am33xx/elm.c
+++ b/arch/arm/cpu/armv7/am33xx/elm.c
@@ -25,31 +25,27 @@
 struct elm *elm_cfg;
 
 /**
- * elm_load_syndromes - Load BCH syndromes based on nibble selection
+ * elm_load_syndromes - Load calc_ecc in ELM registers for error detection
  * @syndrome: BCH syndrome
- * @nibbles:
  * @poly: Syndrome Polynomial set to use
- *
- * Load BCH syndromes based on nibble selection
  */
-static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly)
+static int elm_load_syndromes(u8 *syndrome, u32 bch_type, u8 poly)
 {
 	u32 *ptr;
 	u32 val;
 
-	/* reg 0 */
-	ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0];
-	val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) |
-				(syndrome[3] << 24);
-	writel(val, ptr);
-	/* reg 1 */
-	ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1];
-	val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) |
-				(syndrome[7] << 24);
-	writel(val, ptr);
-
-	/* BCH 8-bit with 26 nibbles (4*8=32) */
-	if (nibbles > 13) {
+	switch (bch_type) {
+	case ECC_BCH16:
+		/* reg 0 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0];
+		val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) |
+					(syndrome[3] << 24);
+		writel(val, ptr);
+		/* reg 1 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1];
+		val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) |
+					(syndrome[7] << 24);
+		writel(val, ptr);
 		/* reg 2 */
 		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2];
 		val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) |
@@ -60,34 +56,65 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly)
 		val = syndrome[12] | (syndrome[13] << 8) |
 			(syndrome[14] << 16) | (syndrome[15] << 24);
 		writel(val, ptr);
-	}
-
-	/* BCH 16-bit with 52 nibbles (7*8=56) */
-	if (nibbles > 26) {
 		/* reg 4 */
 		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4];
 		val = syndrome[16] | (syndrome[17] << 8) |
 			(syndrome[18] << 16) | (syndrome[19] << 24);
 		writel(val, ptr);
-
 		/* reg 5 */
 		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5];
 		val = syndrome[20] | (syndrome[21] << 8) |
 			(syndrome[22] << 16) | (syndrome[23] << 24);
 		writel(val, ptr);
-
 		/* reg 6 */
 		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6];
-		val = syndrome[24] | (syndrome[25] << 8) |
-			(syndrome[26] << 16) | (syndrome[27] << 24);
+		val = syndrome[24] | (syndrome[25] << 8);
 		writel(val, ptr);
+		break;
+	case ECC_BCH8:
+		/* reg 0 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0];
+		val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) |
+					(syndrome[3] << 24);
+		writel(val, ptr);
+		/* reg 1 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1];
+		val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) |
+					(syndrome[7] << 24);
+		writel(val, ptr);
+		/* reg 2 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2];
+		val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) |
+				(syndrome[11] << 24);
+		writel(val, ptr);
+		/* reg 3 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3];
+		val = syndrome[12];
+		writel(val, ptr);
+		break;
+	case ECC_BCH4:
+		/* reg 0 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0];
+		val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) |
+					(syndrome[3] << 24);
+		writel(val, ptr);
+		/* reg 1 */
+		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1];
+		val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) |
+					(syndrome[7] << 24);
+		writel(val, ptr);
+		break;
+	default:
+		return -1;
 	}
+
+	return 0;
 }
 
 /**
- * elm_check_errors - Check for BCH errors and return error locations
+ * elm_check_error - Check for BCH errors and return error locations
  * @syndrome: BCH syndrome
- * @nibbles:
+ * @bch_type: BCH4/BCH8/BCH16
  * @error_count: Returns number of errrors in the syndrome
  * @error_locations: Returns error locations (in decimal) in this array
  *
@@ -95,15 +122,17 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly)
  * and locations in the array passed. Returns -1 if error is not correctable,
  * else returns 0
  */
-int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count,
+int elm_check_error(u8 *syndrome, u32 bch_type, u32 *error_count,
 		u32 *error_locations)
 {
 	u8 poly = ELM_DEFAULT_POLY;
 	s8 i;
 	u32 location_status;
 
-	elm_load_syndromes(syndrome, nibbles, poly);
-
+	if (elm_load_syndromes(syndrome, bch_type, poly)) {
+		printf("ELM: *Error: invalid driver configuration\n");
+		return -1;
+	}
 	/* start processing */
 	writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6])
 				| ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID),
@@ -143,14 +172,14 @@ int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count,
  * Currently we are using only syndrome 0 and syndromes 1 to 6 are not used.
  * Also, the mode is set only for syndrome 0
  */
-int elm_config(enum bch_level level)
+int elm_config(u32 bch_type)
 {
 	u32 val;
 	u8 poly = ELM_DEFAULT_POLY;
 	u32 buffer_size = 0x7FF;
 
 	/* config size and level */
-	val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK;
+	val = bch_type & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK;
 	val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) &
 				ELM_LOCATION_CONFIG_ECC_SIZE_MASK);
 	writel(val, &elm_cfg->location_config);
diff --git a/arch/arm/include/asm/arch-am33xx/elm.h b/arch/arm/include/asm/arch-am33xx/elm.h
index 45454ea..857dc27 100644
--- a/arch/arm/include/asm/arch-am33xx/elm.h
+++ b/arch/arm/include/asm/arch-am33xx/elm.h
@@ -24,14 +24,12 @@
 #define ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK	(0x100)
 #define ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK		(0x1F)
 
-#ifndef __ASSEMBLY__
-
-enum bch_level {
-	BCH_4_BIT = 0,
-	BCH_8_BIT,
-	BCH_16_BIT
-};
+/* bch types */
+#define ECC_BCH4	0
+#define ECC_BCH8	1
+#define ECC_BCH16	2
 
+#ifndef __ASSEMBLY__
 
 /* BCH syndrome registers */
 struct syndrome {
@@ -68,9 +66,9 @@ struct elm {
 	struct location  error_location[8];	/* 0x800 */
 };
 
-int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count,
+int elm_check_error(u8 *syndrome, u32 bch_type, u32 *error_count,
 		u32 *error_locations);
-int elm_config(enum bch_level level);
+int elm_config(u32 bch_type);
 void elm_reset(void);
 void elm_init(void);
 #endif /* __ASSEMBLY__ */
-- 
1.8.1



More information about the U-Boot mailing list