summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2020-11-05 16:25:15 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2020-11-10 08:42:29 +0100
commit3376ed2b01dc8d43d268a5778ddfe58e73622caf (patch)
treef935b8a427da365fe6be37bb133a654384d349b4 /drivers
parent9217c043d49c5df4f689b485407f324751798cd1 (diff)
downloadbarebox-3376ed2b01dc8d43d268a5778ddfe58e73622caf.tar.gz
barebox-3376ed2b01dc8d43d268a5778ddfe58e73622caf.tar.xz
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 <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/atmel_nand.c58
1 files 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) {