Re: [U-Boot] [PATCH] am335x: NAND, add BCH16 and 4k page size support

Please ignore this.
This enables BCH16 by default, which shouldn't happen. I'll will fix this and send again
On Mon, Jan 28, 2013 at 1:35 PM, Jordy van Wolferen < jordyvanwolferen@gmail.com> wrote:
arch/arm/include/asm/arch-am33xx/cpu.h | 8 +- arch/arm/include/asm/arch-am33xx/omap_gpmc.h | 43 ++++++++ drivers/mtd/nand/omap_gpmc.c | 154 +++++++++++++++++---------- include/linux/mtd/mtd-abi.h | 2 +- 4 files changed, 150 insertions(+), 57 deletions(-)
diff --git a/arch/arm/include/asm/arch-am33xx/cpu.h b/arch/arm/include/asm/arch-am33xx/cpu.h index 16e8a80..0a1f1ff 100644 --- a/arch/arm/include/asm/arch-am33xx/cpu.h +++ b/arch/arm/include/asm/arch-am33xx/cpu.h @@ -78,6 +78,10 @@ struct bch_res_0_3 { u32 bch_result_x[4]; };
+struct bch_res_4_6 {
u32 bch_result_x[3];
+};
struct gpmc { u8 res1[0x10]; u32 sysconfig; /* 0x10 */ @@ -107,7 +111,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; /* 0x240 */
u32 dummy[44]; /* not used */
struct bch_res_4_6 bch_result_4_6; /* 300 */
};
/* 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 572f9d0..534fa6e 100644 --- a/arch/arm/include/asm/arch-am33xx/omap_gpmc.h +++ b/arch/arm/include/asm/arch-am33xx/omap_gpmc.h @@ -117,4 +117,47 @@ {.offset = 106,\ .length = 8 } } \ }
+#define GPMC_NAND_4K_HW_BCH8_ECC_LAYOUT {\
.eccbytes = 112,\
.eccpos = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27,\
28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39,\
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51,\
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63,\
64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75,\
76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
86, 87,\
88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99,\
100, 101, 102, 103, 104, 105, 106, 107,
108, 109,\
110, 111, 112, 113},\
.oobfree = {\
{.offset = 114,\
.length = 110 } } \
+}
+#define GPMC_NAND_4K_HW_BCH16_ECC_LAYOUT {\
.eccbytes = 208,\
.eccpos = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27,\
28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39,\
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51,\
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63,\
64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75,\
76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
86, 87,\
88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99,\
100, 101, 102, 103, 104, 105, 106, 107,
108, 109,\
110, 111, 112, 113, 114, 115, 116, 117,
118, 119,\
120, 121, 122, 123, 124, 125, 126, 127,
128, 129,\
130, 131, 132, 133, 134, 135, 136, 137,
138, 139,\
140, 141, 142, 143, 144, 145, 146, 147,
148, 149,\
150, 151, 152, 153, 154, 155, 156, 157,
158, 159,\
160, 161, 162, 163, 164, 165, 166, 167,
168, 169,\
170, 171, 172, 173, 174, 175, 176, 177,
178, 179,\
180, 181, 182, 183, 184, 185, 186, 187,
188, 189,\
190, 191, 192, 193, 194, 195, 196, 197,
198, 199,\
200, 201, 202, 203, 204, 205, 206, 207,
208, 209},\
.oobfree = {\
{.offset = 210,\
.length = 14 } } \
+} #endif /* __ASM_ARCH_OMAP_GPMC_H */ diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index cee394e..5cdacc2 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -76,8 +76,8 @@ int omap_spl_dev_ready(struct mtd_info *mtd)
/*
- omap_hwecc_init - Initialize the Hardware ECC for NAND flash in
GPMC controller
- @mtd: MTD device structure
GPMC controller
*/
- @mtd: MTD device structure
static void __maybe_unused omap_hwecc_init(struct nand_chip *chip) @@ -170,19 +170,19 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat, }
/*
- omap_calculate_ecc - Generate non-inverted ECC bytes.
omap_calculate_ecc - Generate non-inverted ECC bytes.
- Using noninverted ECC can be considered ugly since writing a blank
- page ie. padding will clear the ECC bytes. This is no problem as
- long nobody is trying to write data on the seemingly unused page.
- Reading an erased page will produce an ECC mismatch between
- generated and read ECC bytes that has to be dealt with separately.
- E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
- is used, the result of read will be 0x0 while the ECC offsets of the
- spare area will be 0xFF which will result in an ECC mismatch.
- @mtd: MTD structure
- @dat: unused
- @ecc_code: ecc_code buffer
Using noninverted ECC can be considered ugly since writing a blank
page ie. padding will clear the ECC bytes. This is no problem as
long nobody is trying to write data on the seemingly unused page.
Reading an erased page will produce an ECC mismatch between
generated and read ECC bytes that has to be dealt with separately.
E.g. if page is 0xFF (fresh erased), and if HW ECC engine within
GPMC
is used, the result of read will be 0x0 while the ECC offsets of
the
spare area will be 0xFF which will result in an ECC mismatch.
@mtd: MTD structure
@dat: unused
*/
@ecc_code: ecc_code buffer
static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) @@ -207,8 +207,8 @@ static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
/*
- omap_enable_ecc - This function enables the hardware ecc functionality
- @mtd: MTD device structure
- @mode: Read/Write mode
- @mtd: MTD device structure
*/
- @mode: Read/Write mode
static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) { @@ -258,12 +258,12 @@ struct nand_bch_priv { #define ECC_BCH8_NIBBLES 26 #define ECC_BCH16_NIBBLES 52
-static struct nand_ecclayout hw_bch8_nand_oob = GPMC_NAND_HW_BCH8_ECC_LAYOUT; +static struct nand_ecclayout nand_ecclayout = GPMC_NAND_4K_HW_BCH16_ECC_LAYOUT;
static struct nand_bch_priv bch_priv = { .mode = NAND_ECC_HW_BCH,
.type = ECC_BCH8,
.nibbles = ECC_BCH8_NIBBLES
.type = ECC_BCH16,
.nibbles = ECC_BCH16_NIBBLES
};
/* @@ -280,21 +280,21 @@ static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian, int8_t i = 0, j;
if (big_endian) {
ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
ptr = &gpmc_cfg->bch_result_0_3.bch_result_x[3]; ecc_code[i++] = readl(ptr) & 0xFF; ptr--; for (j = 0; j < 3; 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) >> 8) & 0xFF; ecc_code[i++] = readl(ptr) & 0xFF; ptr--; } } else {
ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0];
ptr = &gpmc_cfg->bch_result_0_3.bch_result_x[0]; for (j = 0; j < 3; j++) { ecc_code[i++] = readl(ptr) & 0xFF;
ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
ecc_code[i++] = (readl(ptr) >> 8) & 0xFF; ecc_code[i++] = (readl(ptr) >> 16) & 0xFF; ecc_code[i++] = (readl(ptr) >> 24) & 0xFF; ptr++;
@@ -304,6 +304,53 @@ static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian, } }
+static void omap_read_bch16_result(struct mtd_info *mtd, uint8_t big_endian,
uint8_t *ecc_code)
+{
uint32_t *ptr;
int8_t i = 0, j;
uint32_t data;
if(big_endian) {
ptr = &gpmc_cfg->bch_result_4_6.bch_result_x[2];
for (j = 0; j < 7; j++) {
if(j == 3) {
ptr =
&gpmc_cfg->bch_result_0_3.bch_result_x[3];
}
data = readl(ptr);
ptr--;
if(i > 0) {
ecc_code[i++] = (data >> 24) & 0xFF;
ecc_code[i++] = (data >> 16) & 0xFF;
}
ecc_code[i++] = (data >> 8) & 0xFF;
ecc_code[i++] = data & 0xFF;
}
ecc_code[i++] = 0;
ecc_code[i++] = 0;
}
else {
ptr = &gpmc_cfg->bch_result_0_3.bch_result_x[0];
for (j = 0; j < 7; j++) {
if(j == 4) {
ptr =
&gpmc_cfg->bch_result_4_6.bch_result_x[0];
}
data = readl(ptr);
ptr++;
ecc_code[i++] = data & 0xFF;
ecc_code[i++] = (data >> 8) & 0xFF;
ecc_code[i++] = (data >> 16) & 0xFF;
ecc_code[i++] = (data >> 24) & 0xFF;
}
}
+}
/*
- omap_ecc_disable - Disable H/W ECC calculation
@@ -330,7 +377,7 @@ static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc, struct nand_chip *chip = mtd->priv; struct nand_bch_priv *bch = chip->priv; uint8_t n_bytes = 0;
int8_t i, j;
int8_t i; switch (bch->type) { case ECC_BCH4:
@@ -338,7 +385,12 @@ static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc, break;
case ECC_BCH16:
n_bytes = 28;
n_bytes = 26;
/* Last 2 register of ELM need to be zero */
syndrome[26] = 0;
syndrome[27] = 0;
break; case ECC_BCH8:
@@ -347,16 +399,17 @@ static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc, break; }
for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--)
syndrome[i] = calc_ecc[j];
for (i = 0; i < n_bytes; i++) {
syndrome[i] = calc_ecc[(n_bytes-1)-i];
}
}
/*
- omap_calculate_ecc_bch - Read BCH ECC result
omap_calculate_ecc_bch - Read BCH ECC result
- @mtd: MTD structure
- @dat: unused
- @ecc_code: ecc_code buffer
@mtd: MTD structure
@dat: unused
*/
@ecc_code: ecc_code buffer
static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) @@ -368,7 +421,9 @@ static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
if (bch->type == ECC_BCH8) omap_read_bch8_result(mtd, big_endian, ecc_code);
else /* BCH4 and BCH16 currently not supported */
else if(bch->type == ECC_BCH16)
omap_read_bch16_result(mtd, big_endian, ecc_code);
else /* BCH4 currently not supported */ ret = -1; /*
@@ -434,7 +489,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, struct nand_bch_priv *bch = chip->priv; uint8_t syndrome[28]; uint32_t error_count = 0;
uint32_t error_loc[8];
uint32_t error_loc[16]; uint32_t i, ecc_flag; ecc_flag = 0;
@@ -470,7 +525,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, /*
- omap_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in
GPMC controller
- @mtd: MTD device structure
*/
- @mtd: MTD device structure
- @mode: Read/Write mode
static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode) @@ -525,8 +580,8 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
/*
- omap_enable_ecc_bch- This function enables the bch h/w ecc
functionality
- @mtd: MTD device structure
- @mode: Read/Write mode
- @mtd: MTD device structure
*/
- @mode: Read/Write mode
static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode) @@ -611,12 +666,13 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, */ void omap_nand_switch_ecc(int32_t hardware) { +#ifndef CONFIG_AM33XX struct nand_chip *nand; struct mtd_info *mtd;
if (nand_curr_device < 0 ||
nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
!nand_info[nand_curr_device].name) {
nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
!nand_info[nand_curr_device].name) { printf("Error: Can't switch ecc, no devices available\n"); return; }
@@ -646,19 +702,6 @@ void omap_nand_switch_ecc(int32_t hardware) nand->ecc.calculate = omap_calculate_ecc; omap_hwecc_init(nand); printf("HW ECC selected\n"); -#ifdef CONFIG_AM33XX
} else if (hardware == 2) {
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.layout = &hw_bch8_nand_oob;
nand->ecc.size = 512;
nand->ecc.bytes = 14;
nand->ecc.read_page = omap_read_page_bch;
nand->ecc.hwctl = omap_enable_ecc_bch;
nand->ecc.correct = omap_correct_data_bch;
nand->ecc.calculate = omap_calculate_ecc_bch;
omap_hwecc_init_bch(nand, NAND_ECC_READ);
printf("HW BCH8 selected\n");
-#endif } else { nand->ecc.mode = NAND_ECC_SOFT; /* Use mtd default settings */ @@ -671,6 +714,7 @@ void omap_nand_switch_ecc(int32_t hardware) nand_scan_tail(mtd);
nand->options &= ~NAND_OWN_BUFFERS;
+#endif } #endif /* CONFIG_SPL_BUILD */
@@ -684,10 +728,10 @@ void omap_nand_switch_ecc(int32_t hardware)
- ecc.hwctl: function to enable (reset) hardware ecc generator
- ecc.mode: mode of ecc, see defines
- chip_delay: chip dependent delay for transfering data from array to
- read regs (tR)
read regs (tR)
- options: various chip options. They can partly be set to inform
- nand_scan about special functionality. See the defines for further
- explanation
nand_scan about special functionality. See the defines for further
*/
explanation
int board_nand_init(struct nand_chip *nand) { @@ -742,7 +786,7 @@ int board_nand_init(struct nand_chip *nand) /* Default ECC mode */ #ifdef CONFIG_AM33XX nand->ecc.mode = NAND_ECC_HW;
nand->ecc.layout = &hw_bch8_nand_oob;
nand->ecc.layout = &nand_ecclayout; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; nand->ecc.hwctl = omap_enable_ecc_bch;
diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h index 8bdd231..6979a2a 100644 --- a/include/linux/mtd/mtd-abi.h +++ b/include/linux/mtd/mtd-abi.h @@ -125,7 +125,7 @@ struct nand_oobfree { */ struct nand_ecclayout { uint32_t eccbytes;
uint32_t eccpos[128];
uint32_t eccpos[208]; uint32_t oobavail; struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};
1.8.1.1
participants (1)
-
Jordy van Wolferen