|
|
|
@ -88,6 +88,9 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef CFG_NAND_HW_ECC |
|
|
|
|
#ifdef CFG_DAVINCI_BROKEN_ECC |
|
|
|
|
/* Linux-compatible ECC uses MTD defaults. */ |
|
|
|
|
/* These layouts are not compatible with Linux or RBL/UBL. */ |
|
|
|
|
#ifdef CFG_NAND_LARGEPAGE |
|
|
|
|
static struct nand_ecclayout davinci_nand_ecclayout = { |
|
|
|
|
.eccbytes = 12, |
|
|
|
@ -112,6 +115,7 @@ static struct nand_ecclayout davinci_nand_ecclayout = { |
|
|
|
|
#else |
|
|
|
|
#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" |
|
|
|
|
#endif |
|
|
|
|
#endif /* CFG_DAVINCI_BROKEN_ECC */ |
|
|
|
|
|
|
|
|
|
static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) |
|
|
|
|
{ |
|
|
|
@ -150,6 +154,15 @@ static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region) |
|
|
|
|
static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) |
|
|
|
|
{ |
|
|
|
|
u_int32_t tmp; |
|
|
|
|
#ifdef CFG_DAVINCI_BROKEN_ECC |
|
|
|
|
/*
|
|
|
|
|
* This is not how you should read ECCs on large page Davinci devices. |
|
|
|
|
* The region parameter gets you ECCs for flash chips on different chip |
|
|
|
|
* selects, not the 4x512 byte pages in a 2048 byte page. |
|
|
|
|
* |
|
|
|
|
* Preserved for backwards compatibility though. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
int region, n; |
|
|
|
|
struct nand_chip *this = mtd->priv; |
|
|
|
|
|
|
|
|
@ -163,9 +176,26 @@ static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u |
|
|
|
|
*ecc_code++ = ((tmp >> 8) & 0x0f) | ((tmp >> 20) & 0xf0); |
|
|
|
|
region++; |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
const int region = 1; |
|
|
|
|
|
|
|
|
|
tmp = nand_davinci_readecc(mtd, region); |
|
|
|
|
|
|
|
|
|
/* Squeeze 4 bytes ECC into 3 bytes by removing RESERVED bits
|
|
|
|
|
* and shifting. RESERVED bits are 31 to 28 and 15 to 12. */ |
|
|
|
|
tmp = (tmp & 0x00000fff) | ((tmp & 0x0fff0000) >> 4); |
|
|
|
|
|
|
|
|
|
/* Invert so that erased block ECC is correct */ |
|
|
|
|
tmp = ~tmp; |
|
|
|
|
|
|
|
|
|
*ecc_code++ = tmp; |
|
|
|
|
*ecc_code++ = tmp >> 8; |
|
|
|
|
*ecc_code++ = tmp >> 16; |
|
|
|
|
#endif /* CFG_DAVINCI_BROKEN_ECC */ |
|
|
|
|
return(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef CFG_DAVINCI_BROKEN_ECC |
|
|
|
|
static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf) |
|
|
|
|
{ |
|
|
|
|
u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8); |
|
|
|
@ -282,13 +312,14 @@ static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t *ecc_calc, u_in |
|
|
|
|
return(-1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif /* CFG_DAVINCI_BROKEN_ECC */ |
|
|
|
|
|
|
|
|
|
static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) |
|
|
|
|
{ |
|
|
|
|
struct nand_chip *this; |
|
|
|
|
struct nand_chip *this = mtd->priv; |
|
|
|
|
#ifdef CFG_DAVINCI_BROKEN_ECC |
|
|
|
|
int block_count = 0, i, rc; |
|
|
|
|
|
|
|
|
|
this = mtd->priv; |
|
|
|
|
block_count = (this->ecc.size/512); |
|
|
|
|
for (i = 0; i < block_count; i++) { |
|
|
|
|
if (memcmp(read_ecc, calc_ecc, 3) != 0) { |
|
|
|
@ -301,9 +332,44 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char * |
|
|
|
|
calc_ecc += 3; |
|
|
|
|
dat += 512; |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
u_int32_t ecc_nand = read_ecc[0] | (read_ecc[1] << 8) | |
|
|
|
|
(read_ecc[2] << 16); |
|
|
|
|
u_int32_t ecc_calc = calc_ecc[0] | (calc_ecc[1] << 8) | |
|
|
|
|
(calc_ecc[2] << 16); |
|
|
|
|
u_int32_t diff = ecc_calc ^ ecc_nand; |
|
|
|
|
|
|
|
|
|
if (diff) { |
|
|
|
|
if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) { |
|
|
|
|
/* Correctable error */ |
|
|
|
|
if ((diff >> (12 + 3)) < this->ecc.size) { |
|
|
|
|
uint8_t find_bit = 1 << ((diff >> 12) & 7); |
|
|
|
|
uint32_t find_byte = diff >> (12 + 3); |
|
|
|
|
|
|
|
|
|
dat[find_byte] ^= find_bit; |
|
|
|
|
MTDDEBUG(MTD_DEBUG_LEVEL0, "Correcting single " |
|
|
|
|
"bit ECC error at offset: %d, bit: " |
|
|
|
|
"%d\n", find_byte, find_bit); |
|
|
|
|
return 1; |
|
|
|
|
} else { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
} else if (!(diff & (diff - 1))) { |
|
|
|
|
/* Single bit ECC error in the ECC itself,
|
|
|
|
|
nothing to fix */ |
|
|
|
|
MTDDEBUG(MTD_DEBUG_LEVEL0, "Single bit ECC error in " |
|
|
|
|
"ECC.\n"); |
|
|
|
|
return 1; |
|
|
|
|
} else { |
|
|
|
|
/* Uncorrectable error */ |
|
|
|
|
MTDDEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif /* CFG_DAVINCI_BROKEN_ECC */ |
|
|
|
|
return(0); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
#endif /* CFG_NAND_HW_ECC */ |
|
|
|
|
|
|
|
|
|
static int nand_davinci_dev_ready(struct mtd_info *mtd) |
|
|
|
|
{ |
|
|
|
@ -370,6 +436,8 @@ int board_nand_init(struct nand_chip *nand) |
|
|
|
|
#endif |
|
|
|
|
#ifdef CFG_NAND_HW_ECC |
|
|
|
|
nand->ecc.mode = NAND_ECC_HW; |
|
|
|
|
#ifdef CFG_DAVINCI_BROKEN_ECC |
|
|
|
|
nand->ecc.layout = &davinci_nand_ecclayout; |
|
|
|
|
#ifdef CFG_NAND_LARGEPAGE |
|
|
|
|
nand->ecc.size = 2048; |
|
|
|
|
nand->ecc.bytes = 12; |
|
|
|
@ -379,13 +447,16 @@ int board_nand_init(struct nand_chip *nand) |
|
|
|
|
#else |
|
|
|
|
#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" |
|
|
|
|
#endif |
|
|
|
|
nand->ecc.layout = &davinci_nand_ecclayout; |
|
|
|
|
#else |
|
|
|
|
nand->ecc.size = 512; |
|
|
|
|
nand->ecc.bytes = 3; |
|
|
|
|
#endif /* CFG_DAVINCI_BROKEN_ECC */ |
|
|
|
|
nand->ecc.calculate = nand_davinci_calculate_ecc; |
|
|
|
|
nand->ecc.correct = nand_davinci_correct_data; |
|
|
|
|
nand->ecc.hwctl = nand_davinci_enable_hwecc; |
|
|
|
|
#else |
|
|
|
|
nand->ecc.mode = NAND_ECC_SOFT; |
|
|
|
|
#endif |
|
|
|
|
#endif /* CFG_NAND_HW_ECC */ |
|
|
|
|
|
|
|
|
|
/* Set address of hardware control function */ |
|
|
|
|
nand->cmd_ctrl = nand_davinci_hwcontrol; |
|
|
|
|