mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
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
1 changed files with 23 additions and 9 deletions
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue