Skip to content

Commit

Permalink
mtd: rawnand: Use the ECC framework user input parsing bits
Browse files Browse the repository at this point in the history
Many helpers are generic to all NAND chips, they should not be
raw-NAND specific, so use the generic ones.

To avoid moving all the raw NAND core "history" into the generic NAND
layer, we keep a part of this parsing in the raw NAND core to ensure
backward compatibility.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200827085208.16276-20-miquel.raynal@bootlin.com
  • Loading branch information
miquelraynal committed Sep 30, 2020
1 parent 8c12672 commit d7157ff
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 84 deletions.
142 changes: 70 additions & 72 deletions drivers/mtd/nand/raw/nand_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -4877,18 +4877,27 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
return ret;
}

static const char * const nand_ecc_modes[] = {
[NAND_ECC_NONE] = "none",
[NAND_ECC_SOFT] = "soft",
[NAND_ECC_HW] = "hw",
[NAND_ECC_HW_SYNDROME] = "hw_syndrome",
[NAND_ECC_ON_DIE] = "on-die",
};

static enum nand_ecc_engine_type
of_get_nand_ecc_engine_type(struct device_node *np)
{
enum nand_ecc_mode eng_type;
of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
{
enum nand_ecc_legacy_mode {
NAND_ECC_INVALID,
NAND_ECC_NONE,
NAND_ECC_SOFT,
NAND_ECC_SOFT_BCH,
NAND_ECC_HW,
NAND_ECC_HW_SYNDROME,
NAND_ECC_ON_DIE,
};
const char * const nand_ecc_legacy_modes[] = {
[NAND_ECC_NONE] = "none",
[NAND_ECC_SOFT] = "soft",
[NAND_ECC_SOFT_BCH] = "soft_bch",
[NAND_ECC_HW] = "hw",
[NAND_ECC_HW_SYNDROME] = "hw_syndrome",
[NAND_ECC_ON_DIE] = "on-die",
};
enum nand_ecc_legacy_mode eng_type;
const char *pm;
int err;

Expand All @@ -4897,12 +4906,13 @@ of_get_nand_ecc_engine_type(struct device_node *np)
return NAND_ECC_ENGINE_TYPE_INVALID;

for (eng_type = NAND_ECC_NONE;
eng_type < ARRAY_SIZE(nand_ecc_modes); eng_type++) {
if (!strcasecmp(pm, nand_ecc_modes[eng_type])) {
eng_type < ARRAY_SIZE(nand_ecc_legacy_modes); eng_type++) {
if (!strcasecmp(pm, nand_ecc_legacy_modes[eng_type])) {
switch (eng_type) {
case NAND_ECC_NONE:
return NAND_ECC_ENGINE_TYPE_NONE;
case NAND_ECC_SOFT:
case NAND_ECC_SOFT_BCH:
return NAND_ECC_ENGINE_TYPE_SOFT;
case NAND_ECC_HW:
case NAND_ECC_HW_SYNDROME:
Expand All @@ -4915,43 +4925,29 @@ of_get_nand_ecc_engine_type(struct device_node *np)
}
}

/*
* For backward compatibility we support few obsoleted values that don't
* have their mappings into the nand_ecc_engine_providers enum anymore
* (they were merged with other enums).
*/
if (!strcasecmp(pm, "soft_bch"))
return NAND_ECC_ENGINE_TYPE_SOFT;

return NAND_ECC_ENGINE_TYPE_INVALID;
}

static const char * const nand_ecc_algos[] = {
[NAND_ECC_ALGO_HAMMING] = "hamming",
[NAND_ECC_ALGO_BCH] = "bch",
[NAND_ECC_ALGO_RS] = "rs",
};

static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
static enum nand_ecc_placement
of_get_rawnand_ecc_placement_legacy(struct device_node *np)
{
enum nand_ecc_algo ecc_algo;
const char *pm;
int err;

err = of_property_read_string(np, "nand-ecc-algo", &pm);
err = of_property_read_string(np, "nand-ecc-mode", &pm);
if (!err) {
for (ecc_algo = NAND_ECC_ALGO_HAMMING;
ecc_algo < ARRAY_SIZE(nand_ecc_algos);
ecc_algo++) {
if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
return ecc_algo;
}
if (!strcasecmp(pm, "hw_syndrome"))
return NAND_ECC_PLACEMENT_INTERLEAVED;
}

/*
* For backward compatibility we also read "nand-ecc-mode" checking
* for some obsoleted values that were specifying ECC algorithm.
*/
return NAND_ECC_PLACEMENT_UNKNOWN;
}

static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
{
const char *pm;
int err;

err = of_property_read_string(np, "nand-ecc-mode", &pm);
if (!err) {
if (!strcasecmp(pm, "soft"))
Expand All @@ -4963,22 +4959,19 @@ static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
return NAND_ECC_ALGO_UNKNOWN;
}

static int of_get_nand_ecc_step_size(struct device_node *np)
static void of_get_nand_ecc_legacy_user_config(struct nand_chip *chip)
{
int ret;
u32 val;
struct device_node *dn = nand_get_flash_node(chip);
struct nand_ecc_props *user_conf = &chip->base.ecc.user_conf;

ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
return ret ? ret : val;
}
if (user_conf->engine_type == NAND_ECC_ENGINE_TYPE_INVALID)
user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn);

static int of_get_nand_ecc_strength(struct device_node *np)
{
int ret;
u32 val;
if (user_conf->algo == NAND_ECC_ALGO_UNKNOWN)
user_conf->algo = of_get_rawnand_ecc_algo_legacy(dn);

ret = of_property_read_u32(np, "nand-ecc-strength", &val);
return ret ? ret : val;
if (user_conf->placement == NAND_ECC_PLACEMENT_UNKNOWN)
user_conf->placement = of_get_rawnand_ecc_placement_legacy(dn);
}

static int of_get_nand_bus_width(struct device_node *np)
Expand All @@ -5002,12 +4995,10 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np)
return of_property_read_bool(np, "nand-on-flash-bbt");
}

static int nand_dt_init(struct nand_chip *chip)
static int rawnand_dt_init(struct nand_chip *chip)
{
struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip));
struct device_node *dn = nand_get_flash_node(chip);
enum nand_ecc_engine_type ecc_type;
enum nand_ecc_algo ecc_algo;
int ecc_strength, ecc_step;

if (!dn)
return 0;
Expand All @@ -5021,25 +5012,32 @@ static int nand_dt_init(struct nand_chip *chip)
if (of_get_nand_on_flash_bbt(dn))
chip->bbt_options |= NAND_BBT_USE_FLASH;

ecc_type = of_get_nand_ecc_engine_type(dn);
ecc_algo = of_get_nand_ecc_algo(dn);
ecc_strength = of_get_nand_ecc_strength(dn);
ecc_step = of_get_nand_ecc_step_size(dn);

if (ecc_type != NAND_ECC_ENGINE_TYPE_INVALID)
chip->ecc.engine_type = ecc_type;
if (of_property_read_bool(dn, "nand-ecc-maximize"))
chip->ecc.options |= NAND_ECC_MAXIMIZE;

if (ecc_algo != NAND_ECC_ALGO_UNKNOWN)
chip->ecc.algo = ecc_algo;
of_get_nand_ecc_user_config(nand);
of_get_nand_ecc_legacy_user_config(chip);

if (ecc_strength >= 0)
chip->ecc.strength = ecc_strength;
/*
* If neither the user nor the NAND controller have requested a specific
* ECC engine type, we will default to NAND_ECC_ENGINE_TYPE_ON_HOST.
*/
nand->ecc.defaults.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;

if (ecc_step > 0)
chip->ecc.size = ecc_step;
/*
* Use the user requested engine type, unless there is none, in this
* case default to the NAND controller choice, otherwise fallback to
* the raw NAND default one.
*/
if (nand->ecc.user_conf.engine_type != NAND_ECC_ENGINE_TYPE_INVALID)
chip->ecc.engine_type = nand->ecc.user_conf.engine_type;
if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID)
chip->ecc.engine_type = nand->ecc.defaults.engine_type;

if (of_property_read_bool(dn, "nand-ecc-maximize"))
chip->ecc.options |= NAND_ECC_MAXIMIZE;
chip->ecc.placement = nand->ecc.user_conf.placement;
chip->ecc.algo = nand->ecc.user_conf.algo;
chip->ecc.strength = nand->ecc.user_conf.strength;
chip->ecc.size = nand->ecc.user_conf.step_size;

return 0;
}
Expand Down Expand Up @@ -5077,7 +5075,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
/* Enforce the right timings for reset/detection */
chip->current_interface_config = nand_get_reset_interface_config();

ret = nand_dt_init(chip);
ret = rawnand_dt_init(chip);
if (ret)
return ret;

Expand Down
12 changes: 0 additions & 12 deletions include/linux/mtd/rawnand.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,6 @@ struct nand_chip;

#define NAND_DATA_IFACE_CHECK_ONLY -1

/*
* Constants for ECC_MODES
*/
enum nand_ecc_mode {
NAND_ECC_INVALID,
NAND_ECC_NONE,
NAND_ECC_SOFT,
NAND_ECC_HW,
NAND_ECC_HW_SYNDROME,
NAND_ECC_ON_DIE,
};

/*
* Constants for Hardware ECC
*/
Expand Down

0 comments on commit d7157ff

Please sign in to comment.