mtd: nand: omap_gpmc: Fix NAND in SPL for AM335x
AM335x uses a special driver "am335x_spl_bch.c" as SPL NAND loader. This driver expects 1 sector at a time ECC and doesn't work well with multi-sector ECC that was implemented in commit04fcd25873. Switch back to 1 sector at a time read/ECC. Fixes:04fcd25873("mtd: rawnand: omap_gpmc: Fix BCH6/16 HW based correction") Signed-off-by: Roger Quadros <rogerq@kernel.org>
This commit is contained in:
parent
2d30da97ed
commit
c0176ab8dd
|
|
@ -293,7 +293,7 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd,
|
||||||
break;
|
break;
|
||||||
case OMAP_ECC_BCH8_CODE_HW:
|
case OMAP_ECC_BCH8_CODE_HW:
|
||||||
bch_type = 1;
|
bch_type = 1;
|
||||||
nsectors = chip->ecc.steps;
|
nsectors = 1;
|
||||||
if (mode == NAND_ECC_READ) {
|
if (mode == NAND_ECC_READ) {
|
||||||
wr_mode = BCH_WRAPMODE_1;
|
wr_mode = BCH_WRAPMODE_1;
|
||||||
ecc_size0 = BCH8R_ECC_SIZE0;
|
ecc_size0 = BCH8R_ECC_SIZE0;
|
||||||
|
|
@ -306,7 +306,7 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd,
|
||||||
break;
|
break;
|
||||||
case OMAP_ECC_BCH16_CODE_HW:
|
case OMAP_ECC_BCH16_CODE_HW:
|
||||||
bch_type = 0x2;
|
bch_type = 0x2;
|
||||||
nsectors = chip->ecc.steps;
|
nsectors = 1;
|
||||||
if (mode == NAND_ECC_READ) {
|
if (mode == NAND_ECC_READ) {
|
||||||
wr_mode = 0x01;
|
wr_mode = 0x01;
|
||||||
ecc_size0 = 52; /* ECC bits in nibbles per sector */
|
ecc_size0 = 52; /* ECC bits in nibbles per sector */
|
||||||
|
|
@ -345,17 +345,16 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _omap_calculate_ecc_bch - Generate BCH ECC bytes for one sector
|
* omap_calculate_ecc_bch - Generate BCH ECC bytes for one sector
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @dat: The pointer to data on which ecc is computed
|
* @dat: The pointer to data on which ecc is computed
|
||||||
* @ecc_code: The ecc_code buffer
|
* @ecc_code: The ecc_code buffer
|
||||||
* @sector: The sector number (for a multi sector page)
|
|
||||||
*
|
*
|
||||||
* Support calculating of BCH4/8/16 ECC vectors for one sector
|
* Support calculating of BCH4/8/16 ECC vectors for one sector
|
||||||
* within a page. Sector number is in @sector.
|
* within a page. Sector number is in @sector.
|
||||||
*/
|
*/
|
||||||
static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
|
static int omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
|
||||||
u8 *ecc_code, int sector)
|
u8 *ecc_code)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
struct omap_nand_info *info = nand_get_controller_data(chip);
|
struct omap_nand_info *info = nand_get_controller_data(chip);
|
||||||
|
|
@ -368,7 +367,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
|
||||||
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
||||||
#endif
|
#endif
|
||||||
case OMAP_ECC_BCH8_CODE_HW:
|
case OMAP_ECC_BCH8_CODE_HW:
|
||||||
ptr = &gpmc_cfg->bch_result_0_3[sector].bch_result_x[3];
|
ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
|
||||||
val = readl(ptr);
|
val = readl(ptr);
|
||||||
ecc_code[i++] = (val >> 0) & 0xFF;
|
ecc_code[i++] = (val >> 0) & 0xFF;
|
||||||
ptr--;
|
ptr--;
|
||||||
|
|
@ -383,21 +382,21 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case OMAP_ECC_BCH16_CODE_HW:
|
case OMAP_ECC_BCH16_CODE_HW:
|
||||||
val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[2]);
|
val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]);
|
||||||
ecc_code[i++] = (val >> 8) & 0xFF;
|
ecc_code[i++] = (val >> 8) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 0) & 0xFF;
|
ecc_code[i++] = (val >> 0) & 0xFF;
|
||||||
val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[1]);
|
val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]);
|
||||||
ecc_code[i++] = (val >> 24) & 0xFF;
|
ecc_code[i++] = (val >> 24) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 16) & 0xFF;
|
ecc_code[i++] = (val >> 16) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 8) & 0xFF;
|
ecc_code[i++] = (val >> 8) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 0) & 0xFF;
|
ecc_code[i++] = (val >> 0) & 0xFF;
|
||||||
val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[0]);
|
val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]);
|
||||||
ecc_code[i++] = (val >> 24) & 0xFF;
|
ecc_code[i++] = (val >> 24) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 16) & 0xFF;
|
ecc_code[i++] = (val >> 16) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 8) & 0xFF;
|
ecc_code[i++] = (val >> 8) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 0) & 0xFF;
|
ecc_code[i++] = (val >> 0) & 0xFF;
|
||||||
for (j = 3; j >= 0; j--) {
|
for (j = 3; j >= 0; j--) {
|
||||||
val = readl(&gpmc_cfg->bch_result_0_3[sector].bch_result_x[j]
|
val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j]
|
||||||
);
|
);
|
||||||
ecc_code[i++] = (val >> 24) & 0xFF;
|
ecc_code[i++] = (val >> 24) & 0xFF;
|
||||||
ecc_code[i++] = (val >> 16) & 0xFF;
|
ecc_code[i++] = (val >> 16) & 0xFF;
|
||||||
|
|
@ -431,22 +430,6 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* omap_calculate_ecc_bch - ECC generator for 1 sector
|
|
||||||
* @mtd: MTD device structure
|
|
||||||
* @dat: The pointer to data on which ecc is computed
|
|
||||||
* @ecc_code: The ecc_code buffer
|
|
||||||
*
|
|
||||||
* Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
|
|
||||||
* when SW based correction is required as ECC is required for one sector
|
|
||||||
* at a time.
|
|
||||||
*/
|
|
||||||
static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
|
|
||||||
const u_char *dat, u_char *ecc_calc)
|
|
||||||
{
|
|
||||||
return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
|
|
@ -572,34 +555,6 @@ static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||||
|
|
||||||
#ifdef CONFIG_NAND_OMAP_ELM
|
#ifdef CONFIG_NAND_OMAP_ELM
|
||||||
|
|
||||||
/**
|
|
||||||
* omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
|
|
||||||
* @mtd: MTD device structure
|
|
||||||
* @dat: The pointer to data on which ecc is computed
|
|
||||||
* @ecc_code: The ecc_code buffer
|
|
||||||
*
|
|
||||||
* Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
|
|
||||||
*/
|
|
||||||
static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd,
|
|
||||||
const u_char *dat, u_char *ecc_calc)
|
|
||||||
{
|
|
||||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
|
||||||
int eccbytes = chip->ecc.bytes;
|
|
||||||
unsigned long nsectors;
|
|
||||||
int i, ret;
|
|
||||||
|
|
||||||
nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1;
|
|
||||||
for (i = 0; i < nsectors; i++) {
|
|
||||||
ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ecc_calc += eccbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* omap_reverse_list - re-orders list elements in reverse order [internal]
|
* omap_reverse_list - re-orders list elements in reverse order [internal]
|
||||||
* @list: pointer to start of list
|
* @list: pointer to start of list
|
||||||
|
|
@ -752,32 +707,38 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
{
|
{
|
||||||
int i, eccsize = chip->ecc.size;
|
int i, eccsize = chip->ecc.size;
|
||||||
int eccbytes = chip->ecc.bytes;
|
int eccbytes = chip->ecc.bytes;
|
||||||
int ecctotal = chip->ecc.total;
|
|
||||||
int eccsteps = chip->ecc.steps;
|
int eccsteps = chip->ecc.steps;
|
||||||
uint8_t *p = buf;
|
uint8_t *p = buf;
|
||||||
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
||||||
uint8_t *ecc_code = chip->buffers->ecccode;
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
||||||
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
||||||
uint8_t *oob = chip->oob_poi;
|
uint8_t *oob = chip->oob_poi;
|
||||||
|
uint32_t data_pos;
|
||||||
uint32_t oob_pos;
|
uint32_t oob_pos;
|
||||||
|
|
||||||
|
data_pos = 0;
|
||||||
/* oob area start */
|
/* oob area start */
|
||||||
oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
|
oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
|
||||||
oob += chip->ecc.layout->eccpos[0];
|
oob += chip->ecc.layout->eccpos[0];
|
||||||
|
|
||||||
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
|
||||||
|
oob += eccbytes) {
|
||||||
/* Enable ECC engine */
|
/* Enable ECC engine */
|
||||||
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||||
|
|
||||||
/* read entire page */
|
/* read data */
|
||||||
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1);
|
||||||
chip->read_buf(mtd, buf, mtd->writesize);
|
chip->read_buf(mtd, p, eccsize);
|
||||||
|
|
||||||
/* read all ecc bytes from oob area */
|
/* read respective ecc from oob area */
|
||||||
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
|
||||||
chip->read_buf(mtd, oob, ecctotal);
|
chip->read_buf(mtd, oob, eccbytes);
|
||||||
|
/* read syndrome */
|
||||||
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||||
|
|
||||||
/* Calculate ecc bytes */
|
data_pos += eccsize;
|
||||||
omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
|
oob_pos += eccbytes;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < chip->ecc.total; i++)
|
for (i = 0; i < chip->ecc.total; i++)
|
||||||
ecc_code[i] = chip->oob_poi[eccpos[i]];
|
ecc_code[i] = chip->oob_poi[eccpos[i]];
|
||||||
|
|
@ -945,6 +906,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand,
|
||||||
nand->ecc.hwctl = omap_enable_hwecc_bch;
|
nand->ecc.hwctl = omap_enable_hwecc_bch;
|
||||||
nand->ecc.correct = omap_correct_data_bch_sw;
|
nand->ecc.correct = omap_correct_data_bch_sw;
|
||||||
nand->ecc.calculate = omap_calculate_ecc_bch;
|
nand->ecc.calculate = omap_calculate_ecc_bch;
|
||||||
|
nand->ecc.steps = eccsteps;
|
||||||
/* define ecc-layout */
|
/* define ecc-layout */
|
||||||
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
||||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
||||||
|
|
@ -987,6 +949,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand,
|
||||||
nand->ecc.correct = omap_correct_data_bch;
|
nand->ecc.correct = omap_correct_data_bch;
|
||||||
nand->ecc.calculate = omap_calculate_ecc_bch;
|
nand->ecc.calculate = omap_calculate_ecc_bch;
|
||||||
nand->ecc.read_page = omap_read_page_bch;
|
nand->ecc.read_page = omap_read_page_bch;
|
||||||
|
nand->ecc.steps = eccsteps;
|
||||||
/* define ecc-layout */
|
/* define ecc-layout */
|
||||||
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
||||||
for (i = 0; i < ecclayout->eccbytes; i++)
|
for (i = 0; i < ecclayout->eccbytes; i++)
|
||||||
|
|
@ -1020,6 +983,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand,
|
||||||
nand->ecc.correct = omap_correct_data_bch;
|
nand->ecc.correct = omap_correct_data_bch;
|
||||||
nand->ecc.calculate = omap_calculate_ecc_bch;
|
nand->ecc.calculate = omap_calculate_ecc_bch;
|
||||||
nand->ecc.read_page = omap_read_page_bch;
|
nand->ecc.read_page = omap_read_page_bch;
|
||||||
|
nand->ecc.steps = eccsteps;
|
||||||
/* define ecc-layout */
|
/* define ecc-layout */
|
||||||
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
||||||
for (i = 0; i < ecclayout->eccbytes; i++)
|
for (i = 0; i < ecclayout->eccbytes; i++)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue