Software ECC engine was not partially working but more importantly was unaligned with the default software layout that has been in place for decades due to the fact that the driver was enforcing the hardware ECC layout (for wrong reasons). Fix the software ECC implementation, which has the side effect of also aligning it with Linux and making the interoperability work.
Reported-by: Andrea Scian <[email protected]> Signed-off-by: Miquel Raynal (DAVE) <[email protected]> --- drivers/mtd/nand/raw/zynq_nand.c | 88 +++++----------------------------------- 1 file changed, 11 insertions(+), 77 deletions(-) diff --git a/drivers/mtd/nand/raw/zynq_nand.c b/drivers/mtd/nand/raw/zynq_nand.c index be080cbb0743..a697557c722c 100644 --- a/drivers/mtd/nand/raw/zynq_nand.c +++ b/drivers/mtd/nand/raw/zynq_nand.c @@ -631,34 +631,6 @@ static int zynq_nand_write_page_hwecc(struct mtd_info *mtd, return 0; } -/* - * zynq_nand_write_page_swecc - [REPLACABLE] software ecc based page - * write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB - */ -static int zynq_nand_write_page_swecc(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - u8 *ecc_calc = chip->buffers->ecccalc; - const u8 *p = buf; - u32 *eccpos = chip->ecc.layout->eccpos; - - /* Software ecc calculation */ - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - return chip->ecc.write_page_raw(mtd, chip, buf, 1, page); -} - /* * nand_read_page_hwecc - Hardware ECC based page read function * @mtd: Pointer to the mtd info structure @@ -736,48 +708,6 @@ static int zynq_nand_read_page_hwecc(struct mtd_info *mtd, return 0; } -/* - * zynq_nand_read_page_swecc - [REPLACABLE] software ecc based page - * read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read - */ -static int zynq_nand_read_page_swecc(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - u8 *p = buf; - u8 *ecc_calc = chip->buffers->ecccalc; - u8 *ecc_code = chip->buffers->ecccode; - u32 *eccpos = chip->ecc.layout->eccpos; - - chip->ecc.read_page_raw(mtd, chip, buf, 1, page); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - /* * zynq_nand_select_chip - Select the flash device * @mtd: Pointer to the mtd_info structure @@ -1219,6 +1149,16 @@ static int zynq_nand_probe(struct udevice *dev) /* Use the BBT pattern descriptors */ nand_chip->bbt_td = &bbt_main_descr; nand_chip->bbt_md = &bbt_mirror_descr; + } else if (nand_chip->ecc.mode == NAND_ECC_SOFT || + nand_chip->ecc.mode == NAND_ECC_SOFT_BCH || + nand_chip->ecc.mode == NAND_ECC_NONE) { + /* Make sure the ECC engine is off */ + ecc_cfg = readl(&smc->reg->emcr); + ecc_cfg &= ~ZYNQ_MEMC_NAND_ECC_MODE_MASK; + writel(ecc_cfg, &smc->reg->emcr); + + nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw; + nand_chip->ecc.write_page_raw = zynq_nand_write_page_raw; } else { /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ nand_chip->ecc.mode = NAND_ECC_HW; @@ -1255,13 +1195,7 @@ static int zynq_nand_probe(struct udevice *dev) &smc->reg->emcr); break; default: - nand_chip->ecc.mode = NAND_ECC_SOFT; - nand_chip->ecc.calculate = nand_calculate_ecc; - nand_chip->ecc.correct = nand_correct_data; - nand_chip->ecc.read_page = zynq_nand_read_page_swecc; - nand_chip->ecc.write_page = zynq_nand_write_page_swecc; - nand_chip->ecc.size = 256; - break; + return -EINVAL; } if (mtd->oobsize == 16) -- 2.53.0

