diff options
author | Miquel Raynal <miquel.raynal@bootlin.com> | 2018-07-19 12:21:19 +0200 |
---|---|---|
committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2018-10-03 11:12:25 +0200 |
commit | 7fd130f7416f1c67c2b976d42c1b64371c3a7bd2 (patch) | |
tree | efd24805dfc987d2d283609a27a651e85d59d6ce /drivers/mtd | |
parent | mtd: rawnand: marvell: rework BCH engine failure path (diff) | |
download | linux-7fd130f7416f1c67c2b976d42c1b64371c3a7bd2.tar.xz linux-7fd130f7416f1c67c2b976d42c1b64371c3a7bd2.zip |
mtd: rawnand: marvell: support 8b/512B strength for 2kiB pages layout
Add support for the layout used by 2kiB page NAND chips requesting at
least 8-bit of correction per 512 bytes. This layout requires a bit of
handling as:
1/ It can only fit if the NAND chip has at least 128 OOB bytes.
2/ The Bad Block Markers are located in the middle of the data bytes
and shall not be used.
3/ It has been experimentally observed that, for certain layouts, the ECC
engine tries to correct data while it should not because the errors
are uncorrectable. While this is harmless for truly bad pages, it
creates bitflips in empty pages. To avoid such scenario that
augments artificially the number of bitflips we re-read in raw mode
the entire page instead of just the ECC bytes. This is done only
for this layout to avoid an unneeded penalty with other setups.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/raw/marvell_nand.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index a08858cca804..6639f2e2cea2 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -284,6 +284,7 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = { MARVELL_LAYOUT( 512, 512, 1, 1, 1, 512, 8, 8, 0, 0, 0), MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0), MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0), + MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30), MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0), MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30), }; @@ -1348,9 +1349,11 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip, * page is empty. In this case, it is normal that the ECC check failed * and we just ignore the error. * - * However, for any subpage read error reported by ->correct(), the ECC - * bytes must be read in raw mode and the full subpage must be checked - * to see if it is entirely empty of if there was an actual error. + * However, it has been empirically observed that for some layouts (e.g + * 2k page, 8b strength per 512B chunk), the controller tries to correct + * bits and may create itself bitflips in the erased area. To overcome + * this strange behavior, the whole page is re-read in raw mode, not + * only the ECC bytes. */ for (chunk = 0; chunk < lt->nchunks; chunk++) { int data_off_in_page, spare_off_in_page, ecc_off_in_page; @@ -1383,6 +1386,21 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip, ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes : lt->last_ecc_bytes; + /* + * Only re-read the ECC bytes, unless we are using the 2k/8b + * layout which is buggy in the sense that the ECC engine will + * try to correct data bytes anyway, creating bitflips. In this + * case, re-read the entire page. + */ + if (lt->writesize == 2048 && lt->strength == 8) { + nand_change_read_column_op(chip, data_off_in_page, + buf + data_off, data_len, + false); + nand_change_read_column_op(chip, spare_off_in_page, + chip->oob_poi + spare_off, spare_len, + false); + } + nand_change_read_column_op(chip, ecc_off_in_page, chip->oob_poi + ecc_off, ecc_len, false); @@ -2166,6 +2184,16 @@ static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, return -ENOTSUPP; } + /* Special care for the layout 2k/8-bit/512B */ + if (l->writesize == 2048 && l->strength == 8) { + if (mtd->oobsize < 128) { + dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n"); + return -ENOTSUPP; + } else { + chip->bbt_options |= NAND_BBT_NO_OOB_BBM; + } + } + mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops); ecc->steps = l->nchunks; ecc->size = l->data_bytes; |