diff options
author | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-07-18 10:42:15 +0200 |
---|---|---|
committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2018-07-19 23:14:14 +0200 |
commit | dbc44edbf8338d27639214be07fe7ab4f8a903e0 (patch) | |
tree | b4417f59196306a55eb0baecdda57894420b7205 /drivers/mtd/nand/raw/nand_micron.c | |
parent | 79e1ca37cc0c056f224cc1dd4a301b9dc2f94167 (diff) |
mtd: rawnand: micron: Fix on-die ECC detection logic
Basing the "mandatory on-die" detection on ID byte 2 does not work,
because Micron has plenty of NANDs using the same device ID code, and
not all of them have forcibly enabled on-die ECC.
Since the "Array Operation" feature does not provide the "ECC
enabled/disabled" bit when the ECC can't be disabled, let's try to use
the "ECC enabled/disabled" bit in the READ_ID bytes.
It seems that this bit is dynamically updated on NANDs where on-die ECC
can freely be enabled/disabled, so let's hope it stays at one when we
have a NAND with on-die ECC forcibly enabled.
Fixes: 51f3b3970a8c ("mtd: rawnand: micron: detect forced on-die ECC")
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Tested-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Diffstat (limited to 'drivers/mtd/nand/raw/nand_micron.c')
-rw-r--r-- | drivers/mtd/nand/raw/nand_micron.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index d30bd4df9b12..d85bb4d42686 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -196,6 +196,9 @@ enum { MICRON_ON_DIE_MANDATORY, }; +#define MICRON_ID_INTERNAL_ECC_MASK GENMASK(1, 0) +#define MICRON_ID_ECC_ENABLED BIT(7) + /* * Try to detect if the NAND support on-die ECC. To do this, we enable * the feature, and read back if it has been enabled as expected. We @@ -208,7 +211,7 @@ enum { */ static int micron_supports_on_die_ecc(struct nand_chip *chip) { - u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, }; + u8 id[5]; int ret; if (!chip->parameters.onfi.version) @@ -217,26 +220,37 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) if (chip->bits_per_cell != 1) return MICRON_ON_DIE_UNSUPPORTED; + /* + * We only support on-die ECC of 4/512 or 8/512 + */ + if (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8) + return MICRON_ON_DIE_UNSUPPORTED; + + /* 0x2 means on-die ECC is available. */ + if (chip->id.len != 5 || + (chip->id.data[4] & MICRON_ID_INTERNAL_ECC_MASK) != 0x2) + return MICRON_ON_DIE_UNSUPPORTED; + ret = micron_nand_on_die_ecc_setup(chip, true); if (ret) return MICRON_ON_DIE_UNSUPPORTED; - ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature); - if (ret < 0) - return ret; + ret = nand_readid_op(chip, 0, id, sizeof(id)); + if (ret) + return MICRON_ON_DIE_UNSUPPORTED; - if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0) + if (!(id[4] & MICRON_ID_ECC_ENABLED)) return MICRON_ON_DIE_UNSUPPORTED; ret = micron_nand_on_die_ecc_setup(chip, false); if (ret) return MICRON_ON_DIE_UNSUPPORTED; - ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature); - if (ret < 0) - return ret; + ret = nand_readid_op(chip, 0, id, sizeof(id)); + if (ret) + return MICRON_ON_DIE_UNSUPPORTED; - if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) + if (id[4] & MICRON_ID_ECC_ENABLED) return MICRON_ON_DIE_MANDATORY; /* |