Commit 97baea1e authored by Miquel Raynal's avatar Miquel Raynal Committed by Boris Brezillon

mtd: rawnand: use wrappers to call onfi GET/SET_FEATURES

Prepare the fact that some features managed by GET/SET_FEATURES could be
overloaded by vendor code. To handle this logic, use new wrappers
instead of directly call the ->get/set_features() hooks.
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@bootlin.com>
parent b958758e
...@@ -934,15 +934,13 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) ...@@ -934,15 +934,13 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
/* [1] send SET FEATURE command to NAND */ /* [1] send SET FEATURE command to NAND */
feature[0] = mode; feature[0] = mode;
ret = nand->set_features(mtd, nand, ret = nand_set_features(nand, ONFI_FEATURE_ADDR_TIMING_MODE, feature);
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret) if (ret)
goto err_out; goto err_out;
/* [2] send GET FEATURE command to double-check the timing mode */ /* [2] send GET FEATURE command to double-check the timing mode */
memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN); memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
ret = nand->get_features(mtd, nand, ret = nand_get_features(nand, ONFI_FEATURE_ADDR_TIMING_MODE, feature);
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret || feature[0] != mode) if (ret || feature[0] != mode)
goto err_out; goto err_out;
......
...@@ -1160,6 +1160,55 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -1160,6 +1160,55 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
return status; return status;
} }
static bool nand_supports_set_get_features(struct nand_chip *chip)
{
return (chip->onfi_version &&
(le16_to_cpu(chip->onfi_params.opt_cmd) &
ONFI_OPT_CMD_SET_GET_FEATURES));
}
/**
* nand_get_features - wrapper to perform a GET_FEATURE
* @chip: NAND chip info structure
* @addr: feature address
* @subfeature_param: the subfeature parameters, a four bytes array
*
* Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
* operation cannot be handled.
*/
int nand_get_features(struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (!nand_supports_set_get_features(chip))
return -ENOTSUPP;
return chip->get_features(mtd, chip, addr, subfeature_param);
}
EXPORT_SYMBOL_GPL(nand_get_features);
/**
* nand_set_features - wrapper to perform a SET_FEATURE
* @chip: NAND chip info structure
* @addr: feature address
* @subfeature_param: the subfeature parameters, a four bytes array
*
* Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
* operation cannot be handled.
*/
int nand_set_features(struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (!nand_supports_set_get_features(chip))
return -ENOTSUPP;
return chip->set_features(mtd, chip, addr, subfeature_param);
}
EXPORT_SYMBOL_GPL(nand_set_features);
/** /**
* nand_reset_data_interface - Reset data interface and timings * nand_reset_data_interface - Reset data interface and timings
* @chip: The NAND chip * @chip: The NAND chip
...@@ -1215,32 +1264,22 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) ...@@ -1215,32 +1264,22 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
int ret; int ret;
if (!chip->setup_data_interface) if (!chip->setup_data_interface)
return 0; return 0;
/* /* Change the mode on the chip side */
* Ensure the timing mode has been changed on the chip side ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
* before changing timings on the controller side. tmode_param);
*/ if (ret)
if (chip->onfi_version && return ret;
(le16_to_cpu(chip->onfi_params.opt_cmd) &
ONFI_OPT_CMD_SET_GET_FEATURES)) {
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
ret = chip->set_features(mtd, chip,
ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
if (ret)
goto err;
}
ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface); /* Change the mode on the controller side */
err: return chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
return ret;
} }
/** /**
...@@ -4779,11 +4818,6 @@ static int nand_default_set_features(struct mtd_info *mtd, ...@@ -4779,11 +4818,6 @@ static int nand_default_set_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr, struct nand_chip *chip, int addr,
uint8_t *subfeature_param) uint8_t *subfeature_param)
{ {
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
return nand_set_features_op(chip, addr, subfeature_param); return nand_set_features_op(chip, addr, subfeature_param);
} }
...@@ -4798,11 +4832,6 @@ static int nand_default_get_features(struct mtd_info *mtd, ...@@ -4798,11 +4832,6 @@ static int nand_default_get_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr, struct nand_chip *chip, int addr,
uint8_t *subfeature_param) uint8_t *subfeature_param)
{ {
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
return nand_get_features_op(chip, addr, subfeature_param); return nand_get_features_op(chip, addr, subfeature_param);
} }
......
...@@ -48,8 +48,7 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) ...@@ -48,8 +48,7 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
return chip->set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
feature);
} }
/* /*
...@@ -108,8 +107,7 @@ static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable) ...@@ -108,8 +107,7 @@ static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
if (enable) if (enable)
feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN; feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
return chip->set_features(nand_to_mtd(chip), chip, return nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
ONFI_FEATURE_ON_DIE_ECC, feature);
} }
static int static int
...@@ -219,8 +217,10 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) ...@@ -219,8 +217,10 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
if (ret) if (ret)
return MICRON_ON_DIE_UNSUPPORTED; return MICRON_ON_DIE_UNSUPPORTED;
chip->get_features(nand_to_mtd(chip), chip, ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
ONFI_FEATURE_ON_DIE_ECC, feature); if (ret < 0)
return ret;
if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0) if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
return MICRON_ON_DIE_UNSUPPORTED; return MICRON_ON_DIE_UNSUPPORTED;
...@@ -228,8 +228,10 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) ...@@ -228,8 +228,10 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
if (ret) if (ret)
return MICRON_ON_DIE_UNSUPPORTED; return MICRON_ON_DIE_UNSUPPORTED;
chip->get_features(nand_to_mtd(chip), chip, ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
ONFI_FEATURE_ON_DIE_ECC, feature); if (ret < 0)
return ret;
if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
return MICRON_ON_DIE_MANDATORY; return MICRON_ON_DIE_MANDATORY;
......
...@@ -1629,6 +1629,9 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); ...@@ -1629,6 +1629,9 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page); int page);
/* Wrapper to use in order for controllers/vendors to GET/SET FEATURES */
int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
/* Stub used by drivers that do not support GET/SET FEATURES operations */ /* Stub used by drivers that do not support GET/SET FEATURES operations */
int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip, int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
int addr, u8 *subfeature_param); int addr, u8 *subfeature_param);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment