mtd: rawnand: Use nanddev_get/set_ecc_requirements() when relevant
Instead of accessing ->strength/step_size directly. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/20200827085208.16276-15-miquel.raynal@bootlin.com
This commit is contained in:
parent
3316c8e3ad
commit
53576c7bfc
|
@ -1043,6 +1043,8 @@ static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip,
|
||||||
|
|
||||||
static int atmel_nand_pmecc_init(struct nand_chip *chip)
|
static int atmel_nand_pmecc_init(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||||
struct atmel_nand_controller *nc;
|
struct atmel_nand_controller *nc;
|
||||||
|
@ -1072,15 +1074,15 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
|
||||||
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
|
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
|
||||||
else if (chip->ecc.strength)
|
else if (chip->ecc.strength)
|
||||||
req.ecc.strength = chip->ecc.strength;
|
req.ecc.strength = chip->ecc.strength;
|
||||||
else if (chip->base.eccreq.strength)
|
else if (requirements->strength)
|
||||||
req.ecc.strength = chip->base.eccreq.strength;
|
req.ecc.strength = requirements->strength;
|
||||||
else
|
else
|
||||||
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
|
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
|
||||||
|
|
||||||
if (chip->ecc.size)
|
if (chip->ecc.size)
|
||||||
req.ecc.sectorsize = chip->ecc.size;
|
req.ecc.sectorsize = chip->ecc.size;
|
||||||
else if (chip->base.eccreq.step_size)
|
else if (requirements->step_size)
|
||||||
req.ecc.sectorsize = chip->base.eccreq.step_size;
|
req.ecc.sectorsize = requirements->step_size;
|
||||||
else
|
else
|
||||||
req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
|
req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
|
||||||
|
|
||||||
|
|
|
@ -2532,6 +2532,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = nand_to_mtd(&host->chip);
|
struct mtd_info *mtd = nand_to_mtd(&host->chip);
|
||||||
struct nand_chip *chip = &host->chip;
|
struct nand_chip *chip = &host->chip;
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
struct brcmnand_controller *ctrl = host->ctrl;
|
struct brcmnand_controller *ctrl = host->ctrl;
|
||||||
struct brcmnand_cfg *cfg = &host->hwcfg;
|
struct brcmnand_cfg *cfg = &host->hwcfg;
|
||||||
char msg[128];
|
char msg[128];
|
||||||
|
@ -2589,10 +2591,10 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
|
||||||
|
|
||||||
if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
|
if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
|
||||||
(!chip->ecc.size || !chip->ecc.strength)) {
|
(!chip->ecc.size || !chip->ecc.strength)) {
|
||||||
if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
|
if (requirements->step_size && requirements->strength) {
|
||||||
/* use detected ECC parameters */
|
/* use detected ECC parameters */
|
||||||
chip->ecc.size = chip->base.eccreq.step_size;
|
chip->ecc.size = requirements->step_size;
|
||||||
chip->ecc.strength = chip->base.eccreq.strength;
|
chip->ecc.strength = requirements->strength;
|
||||||
dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n",
|
dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n",
|
||||||
chip->ecc.size, chip->ecc.strength);
|
chip->ecc.size, chip->ecc.strength);
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,8 +272,8 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this,
|
||||||
default:
|
default:
|
||||||
dev_err(this->dev,
|
dev_err(this->dev,
|
||||||
"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
|
"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
|
||||||
chip->base.eccreq.strength,
|
nanddev_get_ecc_requirements(&chip->base)->strength,
|
||||||
chip->base.eccreq.step_size);
|
nanddev_get_ecc_requirements(&chip->base)->step_size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
geo->ecc_chunk_size = ecc_step;
|
geo->ecc_chunk_size = ecc_step;
|
||||||
|
@ -510,6 +510,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
|
||||||
static int common_nfc_set_geometry(struct gpmi_nand_data *this)
|
static int common_nfc_set_geometry(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = &this->nand;
|
struct nand_chip *chip = &this->nand;
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
|
|
||||||
if (chip->ecc.strength > 0 && chip->ecc.size > 0)
|
if (chip->ecc.strength > 0 && chip->ecc.size > 0)
|
||||||
return set_geometry_by_ecc_info(this, chip->ecc.strength,
|
return set_geometry_by_ecc_info(this, chip->ecc.strength,
|
||||||
|
@ -517,13 +519,12 @@ static int common_nfc_set_geometry(struct gpmi_nand_data *this)
|
||||||
|
|
||||||
if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
|
if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
|
||||||
|| legacy_set_geometry(this)) {
|
|| legacy_set_geometry(this)) {
|
||||||
if (!(chip->base.eccreq.strength > 0 &&
|
if (!(requirements->strength > 0 && requirements->step_size > 0))
|
||||||
chip->base.eccreq.step_size > 0))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return set_geometry_by_ecc_info(this,
|
return set_geometry_by_ecc_info(this,
|
||||||
chip->base.eccreq.strength,
|
requirements->strength,
|
||||||
chip->base.eccreq.step_size);
|
requirements->step_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -2247,14 +2247,16 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd,
|
||||||
struct nand_ecc_ctrl *ecc)
|
struct nand_ecc_ctrl *ecc)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
|
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
|
if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
|
||||||
(!ecc->size || !ecc->strength)) {
|
(!ecc->size || !ecc->strength)) {
|
||||||
if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
|
if (requirements->step_size && requirements->strength) {
|
||||||
ecc->size = chip->base.eccreq.step_size;
|
ecc->size = requirements->step_size;
|
||||||
ecc->strength = chip->base.eccreq.strength;
|
ecc->strength = requirements->strength;
|
||||||
} else {
|
} else {
|
||||||
dev_info(nfc->dev,
|
dev_info(nfc->dev,
|
||||||
"No minimum ECC strength, using 1b/512B\n");
|
"No minimum ECC strength, using 1b/512B\n");
|
||||||
|
|
|
@ -1253,6 +1253,8 @@ static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
|
||||||
static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
|
static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&nand->base);
|
||||||
struct mtk_nfc *nfc = nand_get_controller_data(nand);
|
struct mtk_nfc *nfc = nand_get_controller_data(nand);
|
||||||
u32 spare;
|
u32 spare;
|
||||||
int free, ret;
|
int free, ret;
|
||||||
|
@ -1266,8 +1268,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
|
||||||
/* if optional dt settings not present */
|
/* if optional dt settings not present */
|
||||||
if (!nand->ecc.size || !nand->ecc.strength) {
|
if (!nand->ecc.size || !nand->ecc.strength) {
|
||||||
/* use datasheet requirements */
|
/* use datasheet requirements */
|
||||||
nand->ecc.strength = nand->base.eccreq.strength;
|
nand->ecc.strength = requirements->strength;
|
||||||
nand->ecc.size = nand->base.eccreq.step_size;
|
nand->ecc.size = requirements->step_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* align eccstrength and eccsize
|
* align eccstrength and eccsize
|
||||||
|
|
|
@ -4750,6 +4750,8 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
|
||||||
static bool find_full_id_nand(struct nand_chip *chip,
|
static bool find_full_id_nand(struct nand_chip *chip,
|
||||||
struct nand_flash_dev *type)
|
struct nand_flash_dev *type)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
|
struct nand_ecc_props requirements;
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct nand_memory_organization *memorg;
|
struct nand_memory_organization *memorg;
|
||||||
u8 *id_data = chip->id.data;
|
u8 *id_data = chip->id.data;
|
||||||
|
@ -4771,8 +4773,9 @@ static bool find_full_id_nand(struct nand_chip *chip,
|
||||||
memorg->pagesize *
|
memorg->pagesize *
|
||||||
memorg->pages_per_eraseblock);
|
memorg->pages_per_eraseblock);
|
||||||
chip->options |= type->options;
|
chip->options |= type->options;
|
||||||
chip->base.eccreq.strength = NAND_ECC_STRENGTH(type);
|
requirements.strength = NAND_ECC_STRENGTH(type);
|
||||||
chip->base.eccreq.step_size = NAND_ECC_STEP(type);
|
requirements.step_size = NAND_ECC_STEP(type);
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
|
|
||||||
chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
|
chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
|
||||||
if (!chip->parameters.model)
|
if (!chip->parameters.model)
|
||||||
|
@ -5472,10 +5475,12 @@ static int
|
||||||
nand_match_ecc_req(struct nand_chip *chip,
|
nand_match_ecc_req(struct nand_chip *chip,
|
||||||
const struct nand_ecc_caps *caps, int oobavail)
|
const struct nand_ecc_caps *caps, int oobavail)
|
||||||
{
|
{
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
const struct nand_ecc_step_info *stepinfo;
|
const struct nand_ecc_step_info *stepinfo;
|
||||||
int req_step = chip->base.eccreq.step_size;
|
int req_step = requirements->step_size;
|
||||||
int req_strength = chip->base.eccreq.strength;
|
int req_strength = requirements->strength;
|
||||||
int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
|
int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
|
||||||
int best_step, best_strength, best_ecc_bytes;
|
int best_step, best_strength, best_ecc_bytes;
|
||||||
int best_ecc_bytes_total = INT_MAX;
|
int best_ecc_bytes_total = INT_MAX;
|
||||||
|
@ -5666,9 +5671,11 @@ static bool nand_ecc_strength_good(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
int corr, ds_corr;
|
int corr, ds_corr;
|
||||||
|
|
||||||
if (ecc->size == 0 || chip->base.eccreq.step_size == 0)
|
if (ecc->size == 0 || requirements->step_size == 0)
|
||||||
/* Not enough information */
|
/* Not enough information */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -5677,10 +5684,10 @@ static bool nand_ecc_strength_good(struct nand_chip *chip)
|
||||||
* the correction density.
|
* the correction density.
|
||||||
*/
|
*/
|
||||||
corr = (mtd->writesize * ecc->strength) / ecc->size;
|
corr = (mtd->writesize * ecc->strength) / ecc->size;
|
||||||
ds_corr = (mtd->writesize * chip->base.eccreq.strength) /
|
ds_corr = (mtd->writesize * requirements->strength) /
|
||||||
chip->base.eccreq.step_size;
|
requirements->step_size;
|
||||||
|
|
||||||
return corr >= ds_corr && ecc->strength >= chip->base.eccreq.strength;
|
return corr >= ds_corr && ecc->strength >= requirements->strength;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
|
static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
|
||||||
|
@ -5967,8 +5974,8 @@ static int nand_scan_tail(struct nand_chip *chip)
|
||||||
if (!nand_ecc_strength_good(chip))
|
if (!nand_ecc_strength_good(chip))
|
||||||
pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n",
|
pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n",
|
||||||
mtd->name, chip->ecc.strength, chip->ecc.size,
|
mtd->name, chip->ecc.strength, chip->ecc.size,
|
||||||
chip->base.eccreq.strength,
|
nanddev_get_ecc_requirements(&chip->base)->strength,
|
||||||
chip->base.eccreq.step_size);
|
nanddev_get_ecc_requirements(&chip->base)->step_size);
|
||||||
|
|
||||||
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
|
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
|
||||||
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
|
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
|
||||||
|
|
|
@ -10,27 +10,32 @@
|
||||||
|
|
||||||
static void esmt_nand_decode_id(struct nand_chip *chip)
|
static void esmt_nand_decode_id(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
|
struct nand_ecc_props requirements = {};
|
||||||
|
|
||||||
nand_decode_ext_id(chip);
|
nand_decode_ext_id(chip);
|
||||||
|
|
||||||
/* Extract ECC requirements from 5th id byte. */
|
/* Extract ECC requirements from 5th id byte. */
|
||||||
if (chip->id.len >= 5 && nand_is_slc(chip)) {
|
if (chip->id.len >= 5 && nand_is_slc(chip)) {
|
||||||
chip->base.eccreq.step_size = 512;
|
requirements.step_size = 512;
|
||||||
switch (chip->id.data[4] & 0x3) {
|
switch (chip->id.data[4] & 0x3) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
chip->base.eccreq.strength = 4;
|
requirements.strength = 4;
|
||||||
break;
|
break;
|
||||||
case 0x1:
|
case 0x1:
|
||||||
chip->base.eccreq.strength = 2;
|
requirements.strength = 2;
|
||||||
break;
|
break;
|
||||||
case 0x2:
|
case 0x2:
|
||||||
chip->base.eccreq.strength = 1;
|
requirements.strength = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN(1, "Could not get ECC info");
|
WARN(1, "Could not get ECC info");
|
||||||
chip->base.eccreq.step_size = 0;
|
requirements.step_size = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int esmt_nand_init(struct nand_chip *chip)
|
static int esmt_nand_init(struct nand_chip *chip)
|
||||||
|
|
|
@ -495,34 +495,36 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
|
||||||
static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
|
static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
|
||||||
bool valid_jedecid)
|
bool valid_jedecid)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
|
struct nand_ecc_props requirements = {};
|
||||||
u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
|
u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
|
||||||
|
|
||||||
if (valid_jedecid) {
|
if (valid_jedecid) {
|
||||||
/* Reference: H27UCG8T2E datasheet */
|
/* Reference: H27UCG8T2E datasheet */
|
||||||
chip->base.eccreq.step_size = 1024;
|
requirements.step_size = 1024;
|
||||||
|
|
||||||
switch (ecc_level) {
|
switch (ecc_level) {
|
||||||
case 0:
|
case 0:
|
||||||
chip->base.eccreq.step_size = 0;
|
requirements.step_size = 0;
|
||||||
chip->base.eccreq.strength = 0;
|
requirements.strength = 0;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
chip->base.eccreq.strength = 4;
|
requirements.strength = 4;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
chip->base.eccreq.strength = 24;
|
requirements.strength = 24;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
chip->base.eccreq.strength = 32;
|
requirements.strength = 32;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
chip->base.eccreq.strength = 40;
|
requirements.strength = 40;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
chip->base.eccreq.strength = 50;
|
requirements.strength = 50;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
chip->base.eccreq.strength = 60;
|
requirements.strength = 60;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
|
@ -543,14 +545,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
|
||||||
if (nand_tech < 3) {
|
if (nand_tech < 3) {
|
||||||
/* > 26nm, reference: H27UBG8T2A datasheet */
|
/* > 26nm, reference: H27UBG8T2A datasheet */
|
||||||
if (ecc_level < 5) {
|
if (ecc_level < 5) {
|
||||||
chip->base.eccreq.step_size = 512;
|
requirements.step_size = 512;
|
||||||
chip->base.eccreq.strength = 1 << ecc_level;
|
requirements.strength = 1 << ecc_level;
|
||||||
} else if (ecc_level < 7) {
|
} else if (ecc_level < 7) {
|
||||||
if (ecc_level == 5)
|
if (ecc_level == 5)
|
||||||
chip->base.eccreq.step_size = 2048;
|
requirements.step_size = 2048;
|
||||||
else
|
else
|
||||||
chip->base.eccreq.step_size = 1024;
|
requirements.step_size = 1024;
|
||||||
chip->base.eccreq.strength = 24;
|
requirements.strength = 24;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* We should never reach this case, but if that
|
* We should never reach this case, but if that
|
||||||
|
@ -563,18 +565,20 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
|
||||||
} else {
|
} else {
|
||||||
/* <= 26nm, reference: H27UBG8T2B datasheet */
|
/* <= 26nm, reference: H27UBG8T2B datasheet */
|
||||||
if (!ecc_level) {
|
if (!ecc_level) {
|
||||||
chip->base.eccreq.step_size = 0;
|
requirements.step_size = 0;
|
||||||
chip->base.eccreq.strength = 0;
|
requirements.strength = 0;
|
||||||
} else if (ecc_level < 5) {
|
} else if (ecc_level < 5) {
|
||||||
chip->base.eccreq.step_size = 512;
|
requirements.step_size = 512;
|
||||||
chip->base.eccreq.strength = 1 << (ecc_level - 1);
|
requirements.strength = 1 << (ecc_level - 1);
|
||||||
} else {
|
} else {
|
||||||
chip->base.eccreq.step_size = 1024;
|
requirements.step_size = 1024;
|
||||||
chip->base.eccreq.strength = 24 +
|
requirements.strength = 24 +
|
||||||
(8 * (ecc_level - 5));
|
(8 * (ecc_level - 5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
|
static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
int nand_jedec_detect(struct nand_chip *chip)
|
int nand_jedec_detect(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct nand_memory_organization *memorg;
|
struct nand_memory_organization *memorg;
|
||||||
struct nand_jedec_params *p;
|
struct nand_jedec_params *p;
|
||||||
|
@ -120,8 +121,12 @@ int nand_jedec_detect(struct nand_chip *chip)
|
||||||
ecc = &p->ecc_info[0];
|
ecc = &p->ecc_info[0];
|
||||||
|
|
||||||
if (ecc->codeword_size >= 9) {
|
if (ecc->codeword_size >= 9) {
|
||||||
chip->base.eccreq.strength = ecc->ecc_bits;
|
struct nand_ecc_props requirements = {
|
||||||
chip->base.eccreq.step_size = 1 << ecc->codeword_size;
|
.strength = ecc->ecc_bits,
|
||||||
|
.step_size = 1 << ecc->codeword_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
} else {
|
} else {
|
||||||
pr_warn("Invalid codeword size\n");
|
pr_warn("Invalid codeword size\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,6 +413,8 @@ enum {
|
||||||
*/
|
*/
|
||||||
static int micron_supports_on_die_ecc(struct nand_chip *chip)
|
static int micron_supports_on_die_ecc(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
u8 id[5];
|
u8 id[5];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -425,7 +427,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
|
||||||
/*
|
/*
|
||||||
* We only support on-die ECC of 4/512 or 8/512
|
* We only support on-die ECC of 4/512 or 8/512
|
||||||
*/
|
*/
|
||||||
if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
|
if (requirements->strength != 4 && requirements->strength != 8)
|
||||||
return MICRON_ON_DIE_UNSUPPORTED;
|
return MICRON_ON_DIE_UNSUPPORTED;
|
||||||
|
|
||||||
/* 0x2 means on-die ECC is available. */
|
/* 0x2 means on-die ECC is available. */
|
||||||
|
@ -466,7 +468,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
|
||||||
/*
|
/*
|
||||||
* We only support on-die ECC of 4/512 or 8/512
|
* We only support on-die ECC of 4/512 or 8/512
|
||||||
*/
|
*/
|
||||||
if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
|
if (requirements->strength != 4 && requirements->strength != 8)
|
||||||
return MICRON_ON_DIE_UNSUPPORTED;
|
return MICRON_ON_DIE_UNSUPPORTED;
|
||||||
|
|
||||||
return MICRON_ON_DIE_SUPPORTED;
|
return MICRON_ON_DIE_SUPPORTED;
|
||||||
|
@ -474,6 +476,9 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
|
||||||
|
|
||||||
static int micron_nand_init(struct nand_chip *chip)
|
static int micron_nand_init(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(base);
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct micron_nand *micron;
|
struct micron_nand *micron;
|
||||||
int ondie;
|
int ondie;
|
||||||
|
@ -523,7 +528,7 @@ static int micron_nand_init(struct nand_chip *chip)
|
||||||
* That's not needed for 8-bit ECC, because the status expose
|
* That's not needed for 8-bit ECC, because the status expose
|
||||||
* a better approximation of the number of bitflips in a page.
|
* a better approximation of the number of bitflips in a page.
|
||||||
*/
|
*/
|
||||||
if (chip->base.eccreq.strength == 4) {
|
if (requirements->strength == 4) {
|
||||||
micron->ecc.rawbuf = kmalloc(mtd->writesize +
|
micron->ecc.rawbuf = kmalloc(mtd->writesize +
|
||||||
mtd->oobsize,
|
mtd->oobsize,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
@ -533,16 +538,16 @@ static int micron_nand_init(struct nand_chip *chip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->base.eccreq.strength == 4)
|
if (requirements->strength == 4)
|
||||||
mtd_set_ooblayout(mtd,
|
mtd_set_ooblayout(mtd,
|
||||||
µn_nand_on_die_4_ooblayout_ops);
|
µn_nand_on_die_4_ooblayout_ops);
|
||||||
else
|
else
|
||||||
mtd_set_ooblayout(mtd,
|
mtd_set_ooblayout(mtd,
|
||||||
µn_nand_on_die_8_ooblayout_ops);
|
µn_nand_on_die_8_ooblayout_ops);
|
||||||
|
|
||||||
chip->ecc.bytes = chip->base.eccreq.strength * 2;
|
chip->ecc.bytes = requirements->strength * 2;
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
chip->ecc.strength = chip->base.eccreq.strength;
|
chip->ecc.strength = requirements->strength;
|
||||||
chip->ecc.algo = NAND_ECC_ALGO_BCH;
|
chip->ecc.algo = NAND_ECC_ALGO_BCH;
|
||||||
chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
|
chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
|
||||||
chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
|
chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
|
||||||
|
|
|
@ -34,6 +34,8 @@ u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
|
||||||
static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
|
static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
|
||||||
struct nand_onfi_params *p)
|
struct nand_onfi_params *p)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
|
struct nand_ecc_props requirements;
|
||||||
struct onfi_ext_param_page *ep;
|
struct onfi_ext_param_page *ep;
|
||||||
struct onfi_ext_section *s;
|
struct onfi_ext_section *s;
|
||||||
struct onfi_ext_ecc_info *ecc;
|
struct onfi_ext_ecc_info *ecc;
|
||||||
|
@ -94,8 +96,10 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
|
||||||
goto ext_out;
|
goto ext_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
chip->base.eccreq.strength = ecc->ecc_bits;
|
requirements.strength = ecc->ecc_bits;
|
||||||
chip->base.eccreq.step_size = 1 << ecc->codeword_size;
|
requirements.step_size = 1 << ecc->codeword_size;
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
ext_out:
|
ext_out:
|
||||||
|
@ -139,6 +143,7 @@ static void nand_bit_wise_majority(const void **srcbufs,
|
||||||
*/
|
*/
|
||||||
int nand_onfi_detect(struct nand_chip *chip)
|
int nand_onfi_detect(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct nand_memory_organization *memorg;
|
struct nand_memory_organization *memorg;
|
||||||
struct nand_onfi_params *p = NULL, *pbuf;
|
struct nand_onfi_params *p = NULL, *pbuf;
|
||||||
|
@ -265,8 +270,12 @@ int nand_onfi_detect(struct nand_chip *chip)
|
||||||
chip->options |= NAND_BUSWIDTH_16;
|
chip->options |= NAND_BUSWIDTH_16;
|
||||||
|
|
||||||
if (p->ecc_bits != 0xff) {
|
if (p->ecc_bits != 0xff) {
|
||||||
chip->base.eccreq.strength = p->ecc_bits;
|
struct nand_ecc_props requirements = {
|
||||||
chip->base.eccreq.step_size = 512;
|
.strength = p->ecc_bits,
|
||||||
|
.step_size = 512,
|
||||||
|
};
|
||||||
|
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
} else if (onfi_version >= 21 &&
|
} else if (onfi_version >= 21 &&
|
||||||
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
|
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
static void samsung_nand_decode_id(struct nand_chip *chip)
|
static void samsung_nand_decode_id(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
|
struct nand_ecc_props requirements = {};
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct nand_memory_organization *memorg;
|
struct nand_memory_organization *memorg;
|
||||||
|
|
||||||
|
@ -71,23 +73,23 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
|
||||||
/* Extract ECC requirements from 5th id byte*/
|
/* Extract ECC requirements from 5th id byte*/
|
||||||
extid = (chip->id.data[4] >> 4) & 0x07;
|
extid = (chip->id.data[4] >> 4) & 0x07;
|
||||||
if (extid < 5) {
|
if (extid < 5) {
|
||||||
chip->base.eccreq.step_size = 512;
|
requirements.step_size = 512;
|
||||||
chip->base.eccreq.strength = 1 << extid;
|
requirements.strength = 1 << extid;
|
||||||
} else {
|
} else {
|
||||||
chip->base.eccreq.step_size = 1024;
|
requirements.step_size = 1024;
|
||||||
switch (extid) {
|
switch (extid) {
|
||||||
case 5:
|
case 5:
|
||||||
chip->base.eccreq.strength = 24;
|
requirements.strength = 24;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
chip->base.eccreq.strength = 40;
|
requirements.strength = 40;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
chip->base.eccreq.strength = 60;
|
requirements.strength = 60;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN(1, "Could not decode ECC info");
|
WARN(1, "Could not decode ECC info");
|
||||||
chip->base.eccreq.step_size = 0;
|
requirements.step_size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,8 +99,8 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
|
||||||
switch (chip->id.data[1]) {
|
switch (chip->id.data[1]) {
|
||||||
/* K9F4G08U0D-S[I|C]B0(T00) */
|
/* K9F4G08U0D-S[I|C]B0(T00) */
|
||||||
case 0xDC:
|
case 0xDC:
|
||||||
chip->base.eccreq.step_size = 512;
|
requirements.step_size = 512;
|
||||||
chip->base.eccreq.strength = 1;
|
requirements.strength = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* K9F1G08U0E 21nm chips do not support subpage write */
|
/* K9F1G08U0E 21nm chips do not support subpage write */
|
||||||
|
@ -112,6 +114,8 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int samsung_nand_init(struct nand_chip *chip)
|
static int samsung_nand_init(struct nand_chip *chip)
|
||||||
|
|
|
@ -145,6 +145,8 @@ static void toshiba_nand_benand_init(struct nand_chip *chip)
|
||||||
|
|
||||||
static void toshiba_nand_decode_id(struct nand_chip *chip)
|
static void toshiba_nand_decode_id(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
struct nand_device *base = &chip->base;
|
||||||
|
struct nand_ecc_props requirements = {};
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
struct nand_memory_organization *memorg;
|
struct nand_memory_organization *memorg;
|
||||||
|
|
||||||
|
@ -175,23 +177,25 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
|
||||||
* - 24nm: 8 bit ECC for each 512Byte is required.
|
* - 24nm: 8 bit ECC for each 512Byte is required.
|
||||||
*/
|
*/
|
||||||
if (chip->id.len >= 6 && nand_is_slc(chip)) {
|
if (chip->id.len >= 6 && nand_is_slc(chip)) {
|
||||||
chip->base.eccreq.step_size = 512;
|
requirements.step_size = 512;
|
||||||
switch (chip->id.data[5] & 0x7) {
|
switch (chip->id.data[5] & 0x7) {
|
||||||
case 0x4:
|
case 0x4:
|
||||||
chip->base.eccreq.strength = 1;
|
requirements.strength = 1;
|
||||||
break;
|
break;
|
||||||
case 0x5:
|
case 0x5:
|
||||||
chip->base.eccreq.strength = 4;
|
requirements.strength = 4;
|
||||||
break;
|
break;
|
||||||
case 0x6:
|
case 0x6:
|
||||||
chip->base.eccreq.strength = 8;
|
requirements.strength = 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN(1, "Could not get ECC info");
|
WARN(1, "Could not get ECC info");
|
||||||
chip->base.eccreq.step_size = 0;
|
requirements.step_size = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nanddev_set_ecc_requirements(base, &requirements);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -1732,6 +1732,8 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
|
||||||
|
|
||||||
static int sunxi_nand_attach_chip(struct nand_chip *nand)
|
static int sunxi_nand_attach_chip(struct nand_chip *nand)
|
||||||
{
|
{
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&nand->base);
|
||||||
struct nand_ecc_ctrl *ecc = &nand->ecc;
|
struct nand_ecc_ctrl *ecc = &nand->ecc;
|
||||||
struct device_node *np = nand_get_flash_node(nand);
|
struct device_node *np = nand_get_flash_node(nand);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1745,8 +1747,8 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand)
|
||||||
nand->options |= NAND_SUBPAGE_READ;
|
nand->options |= NAND_SUBPAGE_READ;
|
||||||
|
|
||||||
if (!ecc->size) {
|
if (!ecc->size) {
|
||||||
ecc->size = nand->base.eccreq.step_size;
|
ecc->size = requirements->step_size;
|
||||||
ecc->strength = nand->base.eccreq.strength;
|
ecc->strength = requirements->strength;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ecc->size || !ecc->strength)
|
if (!ecc->size || !ecc->strength)
|
||||||
|
|
|
@ -840,6 +840,8 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength,
|
||||||
int strength_len, int bits_per_step,
|
int strength_len, int bits_per_step,
|
||||||
int oobsize)
|
int oobsize)
|
||||||
{
|
{
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
bool maximize = chip->ecc.options & NAND_ECC_MAXIMIZE;
|
bool maximize = chip->ecc.options & NAND_ECC_MAXIMIZE;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -855,7 +857,7 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength,
|
||||||
} else {
|
} else {
|
||||||
strength_sel = strength[i];
|
strength_sel = strength[i];
|
||||||
|
|
||||||
if (strength_sel < chip->base.eccreq.strength)
|
if (strength_sel < requirements->strength)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -908,6 +910,8 @@ static int tegra_nand_select_strength(struct nand_chip *chip, int oobsize)
|
||||||
static int tegra_nand_attach_chip(struct nand_chip *chip)
|
static int tegra_nand_attach_chip(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
|
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
|
||||||
|
const struct nand_ecc_props *requirements =
|
||||||
|
nanddev_get_ecc_requirements(&chip->base);
|
||||||
struct tegra_nand_chip *nand = to_tegra_chip(chip);
|
struct tegra_nand_chip *nand = to_tegra_chip(chip);
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
int bits_per_step;
|
int bits_per_step;
|
||||||
|
@ -919,9 +923,9 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
|
||||||
chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
|
chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
chip->ecc.steps = mtd->writesize / chip->ecc.size;
|
chip->ecc.steps = mtd->writesize / chip->ecc.size;
|
||||||
if (chip->base.eccreq.step_size != 512) {
|
if (requirements->step_size != 512) {
|
||||||
dev_err(ctrl->dev, "Unsupported step size %d\n",
|
dev_err(ctrl->dev, "Unsupported step size %d\n",
|
||||||
chip->base.eccreq.step_size);
|
requirements->step_size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,7 +956,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(ctrl->dev,
|
dev_err(ctrl->dev,
|
||||||
"No valid strength found, minimum %d\n",
|
"No valid strength found, minimum %d\n",
|
||||||
chip->base.eccreq.strength);
|
requirements->strength);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -902,7 +902,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nand->memorg = table[i].memorg;
|
nand->memorg = table[i].memorg;
|
||||||
nand->eccreq = table[i].eccreq;
|
nanddev_set_ecc_requirements(nand, &table[i].eccreq);
|
||||||
spinand->eccinfo = table[i].eccinfo;
|
spinand->eccinfo = table[i].eccinfo;
|
||||||
spinand->flags = table[i].flags;
|
spinand->flags = table[i].flags;
|
||||||
spinand->id.len = 1 + table[i].devid.len;
|
spinand->id.len = 1 + table[i].devid.len;
|
||||||
|
|
Loading…
Reference in New Issue