From 3376ed2b01dc8d43d268a5778ddfe58e73622caf Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 5 Nov 2020 16:25:15 +0100 Subject: mtd: nand: atmel: Fix pmecc ecc settings pmecc has hardcoded steps of 1 and ecc size of the nand chips page size. This is wrong, the ECC engine does 512 or 1024 bytes per step. Adjust ecc size and step size accordingly. Also, fix ecc strength which was hardcoded to 1. With this the correct number of bitflips is reported, which should be the number of bitflips per ecc step, not the one for the whole page. Signed-off-by: Sascha Hauer --- drivers/mtd/nand/atmel_nand.c | 58 ++++++++++++------------------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 438a967bd6..db13f5b7e4 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -107,8 +107,6 @@ struct atmel_nand_host { void *ecc_code; }; -static struct nand_ecclayout atmel_pmecc_oobinfo; - /* * Enable NAND. */ @@ -201,22 +199,6 @@ static int pmecc_get_ecc_bytes(int cap, int sector_size) return (m * cap + 7) / 8; } -static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, - int oobsize, int ecc_len) -{ - int i; - - layout->eccbytes = ecc_len; - - /* ECC will occupy the last ecc_len bytes continuously */ - for (i = 0; i < ecc_len; i++) - layout->eccpos[i] = oobsize - ecc_len + i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = - oobsize - ecc_len - layout->oobfree[0].offset; -} - static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) { int table_size; @@ -574,7 +556,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf) { struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; - int i, err_nbr, ret, bitflips = 0; + int i, err_nbr, ret, max_bitflips = 0; uint8_t *buf_pos; uint8_t *ecc_code = host->ecc_code; @@ -583,7 +565,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf) if (ret) return ret; - for (i = 0; i < nand_chip->ecc.bytes; i++) + for (i = 0; i < nand_chip->ecc.bytes * nand_chip->ecc.steps; i++) if (ecc_code[i] != 0xff) goto normal_check; /* Erased page, return OK */ @@ -608,13 +590,13 @@ normal_check: pmecc_correct_data(mtd, buf_pos, ecc_code, i, host->pmecc_bytes_per_sector, err_nbr); mtd->ecc_stats.corrected += err_nbr; - bitflips += err_nbr; + max_bitflips = max(max_bitflips, err_nbr); } } pmecc_stat >>= 1; } - return bitflips; + return max_bitflips; } static int atmel_nand_pmecc_read_page(struct nand_chip *chip, uint8_t *buf, @@ -622,7 +604,6 @@ static int atmel_nand_pmecc_read_page(struct nand_chip *chip, uint8_t *buf, { struct mtd_info *mtd = nand_to_mtd(chip); struct atmel_nand_host *host = chip->priv; - int eccsize = chip->ecc.size; uint32_t stat; int ret; @@ -636,7 +617,7 @@ static int atmel_nand_pmecc_read_page(struct nand_chip *chip, uint8_t *buf, nand_read_page_op(chip, page, 0, NULL, 0); - chip->legacy.read_buf(chip, buf, eccsize); + chip->legacy.read_buf(chip, buf, mtd->writesize); chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); ret = wait_on_timeout(PMECC_MAX_TIMEOUT_MS, @@ -711,7 +692,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; uint32_t val = 0; - struct nand_ecclayout *ecc_layout; + int eccbytes; pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); @@ -758,11 +739,10 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) | PMECC_CFG_AUTO_DISABLE); pmecc_writel(host->ecc, CFG, val); - ecc_layout = host->ecclayout; + eccbytes = host->pmecc_sector_number * host->pmecc_bytes_per_sector; pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); - pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]); - pmecc_writel(host->ecc, EADDR, - ecc_layout->eccpos[ecc_layout->eccbytes - 1]); + pmecc_writel(host->ecc, SADDR, mtd->oobsize - eccbytes); + pmecc_writel(host->ecc, EADDR, mtd->oobsize - 1); /* See datasheet about PMECC Clock Control Register */ pmecc_writel(host->ecc, CLK, 2); pmecc_writel(host->ecc, IDR, 0xff); @@ -914,9 +894,6 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, host->board->pmecc_lookup_table_offset = 0; } - /* ECC is calculated for the whole page (1 step) */ - nand_chip->ecc.size = mtd->writesize; - /* set ECC page size and oob layout */ switch (mtd->writesize) { case 2048: @@ -932,18 +909,16 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, host->pmecc_index_of = host->pmecc_rom_base + host->board->pmecc_lookup_table_offset; - nand_chip->ecc.steps = 1; - nand_chip->ecc.bytes = host->pmecc_bytes_per_sector * - host->pmecc_sector_number; + nand_chip->ecc.steps = host->pmecc_sector_number; + nand_chip->ecc.bytes = host->pmecc_bytes_per_sector; + nand_chip->ecc.size = sector_size; + nand_chip->ecc.strength = cap; + if (nand_chip->ecc.bytes > mtd->oobsize - 2) { dev_err(host->dev, "No room for ECC bytes\n"); return -EINVAL; } - pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, - mtd->oobsize, - nand_chip->ecc.bytes); - host->ecclayout = &atmel_pmecc_oobinfo; - mtd_set_ecclayout(mtd, host->ecclayout); + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); break; case 512: case 1024: @@ -1016,7 +991,6 @@ static int atmel_nand_read_page(struct nand_chip *chip, uint8_t *buf, { struct mtd_info *mtd = nand_to_mtd(chip); struct atmel_nand_host *host = chip->priv; - int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; uint32_t *eccpos = host->ecclayout->eccpos; uint8_t *p = buf; @@ -1027,7 +1001,7 @@ static int atmel_nand_read_page(struct nand_chip *chip, uint8_t *buf, nand_read_page_op(chip, page, 0, NULL, 0); /* read the page */ - chip->legacy.read_buf(chip, p, eccsize); + chip->legacy.read_buf(chip, p, mtd->writesize); /* move to ECC position if needed */ if (eccpos[0] != 0) { -- cgit v1.2.3