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>
This commit is contained in:
parent
79e1ca37cc
commit
dbc44edbf8
@ -196,6 +196,9 @@ enum {
|
|||||||
MICRON_ON_DIE_MANDATORY,
|
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
|
* 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
|
* 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)
|
static int micron_supports_on_die_ecc(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
|
u8 id[5];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!chip->parameters.onfi.version)
|
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)
|
if (chip->bits_per_cell != 1)
|
||||||
return MICRON_ON_DIE_UNSUPPORTED;
|
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);
|
ret = micron_nand_on_die_ecc_setup(chip, true);
|
||||||
if (ret)
|
if (ret)
|
||||||
return MICRON_ON_DIE_UNSUPPORTED;
|
return MICRON_ON_DIE_UNSUPPORTED;
|
||||||
|
|
||||||
ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
|
ret = nand_readid_op(chip, 0, id, sizeof(id));
|
||||||
if (ret < 0)
|
if (ret)
|
||||||
return 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;
|
return MICRON_ON_DIE_UNSUPPORTED;
|
||||||
|
|
||||||
ret = micron_nand_on_die_ecc_setup(chip, false);
|
ret = micron_nand_on_die_ecc_setup(chip, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
return MICRON_ON_DIE_UNSUPPORTED;
|
return MICRON_ON_DIE_UNSUPPORTED;
|
||||||
|
|
||||||
ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
|
ret = nand_readid_op(chip, 0, id, sizeof(id));
|
||||||
if (ret < 0)
|
if (ret)
|
||||||
return 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;
|
return MICRON_ON_DIE_MANDATORY;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user