Commit d7157ff4 authored by Miquel Raynal's avatar Miquel Raynal
Browse files

mtd: rawnand: Use the ECC framework user input parsing bits



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: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200827085208.16276-20-miquel.raynal@bootlin.com
parent 8c126720
Loading
Loading
Loading
Loading
+70 −72
Original line number Diff line number Diff line
@@ -4877,18 +4877,27 @@ free_detect_allocation:
	return ret;
}

static const char * const nand_ecc_modes[] = {
static enum nand_ecc_engine_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",
	};

static enum nand_ecc_engine_type
of_get_nand_ecc_engine_type(struct device_node *np)
{
	enum nand_ecc_mode eng_type;
	enum nand_ecc_legacy_mode eng_type;
	const char *pm;
	int err;

@@ -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:
@@ -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;
	}

	return NAND_ECC_PLACEMENT_UNKNOWN;
}

	/*
	 * For backward compatibility we also read "nand-ecc-mode" checking
	 * for some obsoleted values that were specifying ECC algorithm.
	 */
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"))
@@ -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)
@@ -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;
@@ -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;
}
@@ -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;

+0 −12
Original line number Diff line number Diff line
@@ -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
 */