aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/mtd/nand/raw/nand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/raw/nand_base.c')
-rw-r--r--drivers/mtd/nand/raw/nand_base.c275
1 files changed, 154 insertions, 121 deletions
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 45124dbb1835..0c768cb88f96 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -773,7 +773,7 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
return -ENOTSUPP;
/* Wait tWB before polling the STATUS reg. */
- timings = nand_get_sdr_timings(&chip->data_interface);
+ timings = nand_get_sdr_timings(nand_get_interface_config(chip));
ndelay(PSEC_TO_NSEC(timings->tWB_max));
ret = nand_status_op(chip, NULL);
@@ -898,7 +898,7 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr)
}
/**
- * nand_reset_data_interface - Reset data interface and timings
+ * nand_reset_interface - Reset data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
*
@@ -906,11 +906,12 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr)
*
* Returns 0 for success or negative error code otherwise.
*/
-static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
+static int nand_reset_interface(struct nand_chip *chip, int chipnr)
{
+ const struct nand_controller_ops *ops = chip->controller->ops;
int ret;
- if (!nand_has_setup_data_iface(chip))
+ if (!nand_controller_can_setup_interface(chip))
return 0;
/*
@@ -927,9 +928,9 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
* timings to timing mode 0.
*/
- onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
- ret = chip->controller->ops->setup_data_interface(chip, chipnr,
- &chip->data_interface);
+ chip->current_interface_config = nand_get_reset_interface_config();
+ ret = ops->setup_interface(chip, chipnr,
+ chip->current_interface_config);
if (ret)
pr_err("Failed to configure data interface to SDR timing mode 0\n");
@@ -937,28 +938,36 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
}
/**
- * nand_setup_data_interface - Setup the best data interface and timings
+ * nand_setup_interface - Setup the best data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
*
- * Find and configure the best data interface and NAND timings supported by
- * the chip and the driver.
- * First tries to retrieve supported timing modes from ONFI information,
- * and if the NAND chip does not support ONFI, relies on the
- * ->onfi_timing_mode_default specified in the nand_ids table.
+ * Configure what has been reported to be the best data interface and NAND
+ * timings supported by the chip and the driver.
*
* Returns 0 for success or negative error code otherwise.
*/
-static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
+static int nand_setup_interface(struct nand_chip *chip, int chipnr)
{
- u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
- chip->onfi_timing_mode_default,
- };
+ const struct nand_controller_ops *ops = chip->controller->ops;
+ u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { };
int ret;
- if (!nand_has_setup_data_iface(chip))
+ if (!nand_controller_can_setup_interface(chip))
return 0;
+ /*
+ * A nand_reset_interface() put both the NAND chip and the NAND
+ * controller in timings mode 0. If the default mode for this chip is
+ * also 0, no need to proceed to the change again. Plus, at probe time,
+ * nand_setup_interface() uses ->set/get_features() which would
+ * fail anyway as the parameter page is not available yet.
+ */
+ if (!chip->best_interface_config)
+ return 0;
+
+ tmode_param[0] = chip->best_interface_config->timings.mode;
+
/* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
nand_select_target(chip, chipnr);
@@ -970,14 +979,13 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
}
/* Change the mode on the controller side */
- ret = chip->controller->ops->setup_data_interface(chip, chipnr,
- &chip->data_interface);
+ ret = ops->setup_interface(chip, chipnr, chip->best_interface_config);
if (ret)
return ret;
/* Check the mode has been accepted by the chip, if supported */
if (!nand_supports_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE))
- return 0;
+ goto update_interface_config;
memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
nand_select_target(chip, chipnr);
@@ -987,12 +995,15 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
if (ret)
goto err_reset_chip;
- if (tmode_param[0] != chip->onfi_timing_mode_default) {
+ if (tmode_param[0] != chip->best_interface_config->timings.mode) {
pr_warn("timing mode %d not acknowledged by the NAND chip\n",
- chip->onfi_timing_mode_default);
+ chip->best_interface_config->timings.mode);
goto err_reset_chip;
}
+update_interface_config:
+ chip->current_interface_config = chip->best_interface_config;
+
return 0;
err_reset_chip:
@@ -1000,7 +1011,7 @@ err_reset_chip:
* Fallback to mode 0 if the chip explicitly did not ack the chosen
* timing mode.
*/
- nand_reset_data_interface(chip, chipnr);
+ nand_reset_interface(chip, chipnr);
nand_select_target(chip, chipnr);
nand_reset_op(chip);
nand_deselect_target(chip);
@@ -1009,62 +1020,93 @@ err_reset_chip:
}
/**
- * nand_init_data_interface - find the best data interface and timings
- * @chip: The NAND chip
- *
- * Find the best data interface and NAND timings supported by the chip
- * and the driver.
- * First tries to retrieve supported timing modes from ONFI information,
- * and if the NAND chip does not support ONFI, relies on the
- * ->onfi_timing_mode_default specified in the nand_ids table. After this
- * function nand_chip->data_interface is initialized with the best timing mode
- * available.
+ * nand_choose_best_sdr_timings - Pick up the best SDR timings that both the
+ * NAND controller and the NAND chip support
+ * @chip: the NAND chip
+ * @iface: the interface configuration (can eventually be updated)
+ * @spec_timings: specific timings, when not fitting the ONFI specification
*
- * Returns 0 for success or negative error code otherwise.
+ * If specific timings are provided, use them. Otherwise, retrieve supported
+ * timing modes from ONFI information.
*/
-static int nand_init_data_interface(struct nand_chip *chip)
+int nand_choose_best_sdr_timings(struct nand_chip *chip,
+ struct nand_interface_config *iface,
+ struct nand_sdr_timings *spec_timings)
{
- int modes, mode, ret;
+ const struct nand_controller_ops *ops = chip->controller->ops;
+ int best_mode = 0, mode, ret;
- if (!nand_has_setup_data_iface(chip))
- return 0;
+ iface->type = NAND_SDR_IFACE;
- /*
- * First try to identify the best timings from ONFI parameters and
- * if the NAND does not support ONFI, fallback to the default ONFI
- * timing mode.
- */
- if (chip->parameters.onfi) {
- modes = chip->parameters.onfi->async_timing_mode;
- } else {
- if (!chip->onfi_timing_mode_default)
- return 0;
+ if (spec_timings) {
+ iface->timings.sdr = *spec_timings;
+ iface->timings.mode = onfi_find_closest_sdr_mode(spec_timings);
- modes = GENMASK(chip->onfi_timing_mode_default, 0);
+ /* Verify the controller supports the requested interface */
+ ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
+ iface);
+ if (!ret) {
+ chip->best_interface_config = iface;
+ return ret;
+ }
+
+ /* Fallback to slower modes */
+ best_mode = iface->timings.mode;
+ } else if (chip->parameters.onfi) {
+ best_mode = fls(chip->parameters.onfi->async_timing_mode) - 1;
}
- for (mode = fls(modes) - 1; mode >= 0; mode--) {
- ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
- if (ret)
- continue;
+ for (mode = best_mode; mode >= 0; mode--) {
+ onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, mode);
- /*
- * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
- * controller supports the requested timings.
- */
- ret = chip->controller->ops->setup_data_interface(chip,
- NAND_DATA_IFACE_CHECK_ONLY,
- &chip->data_interface);
- if (!ret) {
- chip->onfi_timing_mode_default = mode;
+ ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
+ iface);
+ if (!ret)
break;
- }
}
+ chip->best_interface_config = iface;
+
return 0;
}
/**
+ * nand_choose_interface_config - find the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find the best data interface and NAND timings supported by the chip
+ * and the driver. Eventually let the NAND manufacturer driver propose his own
+ * set of timings.
+ *
+ * After this function nand_chip->interface_config is initialized with the best
+ * timing mode available.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_choose_interface_config(struct nand_chip *chip)
+{
+ struct nand_interface_config *iface;
+ int ret;
+
+ if (!nand_controller_can_setup_interface(chip))
+ return 0;
+
+ iface = kzalloc(sizeof(*iface), GFP_KERNEL);
+ if (!iface)
+ return -ENOMEM;
+
+ if (chip->ops.choose_interface_config)
+ ret = chip->ops.choose_interface_config(chip, iface);
+ else
+ ret = nand_choose_best_sdr_timings(chip, iface, NULL);
+
+ if (ret)
+ kfree(iface);
+
+ return ret;
+}
+
+/**
* nand_fill_column_cycles - fill the column cycles of an address
* @chip: The NAND chip
* @addrs: Array of address cycles to fill
@@ -1122,9 +1164,9 @@ static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf,
unsigned int len)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 addrs[4];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
@@ -1166,7 +1208,7 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int len)
{
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[5];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
@@ -1263,7 +1305,7 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_PARAM, 0),
NAND_OP_ADDR(1, &page, PSEC_TO_NSEC(sdr->tWB_max)),
@@ -1318,7 +1360,7 @@ int nand_change_read_column_op(struct nand_chip *chip,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[2] = {};
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDOUT, 0),
@@ -1392,9 +1434,9 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, const void *buf,
unsigned int len, bool prog)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 addrs[5] = {};
struct nand_op_instr instrs[] = {
/*
@@ -1517,7 +1559,7 @@ int nand_prog_page_end_op(struct nand_chip *chip)
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_PAGEPROG,
PSEC_TO_NSEC(sdr->tWB_max)),
@@ -1624,7 +1666,7 @@ int nand_change_write_column_op(struct nand_chip *chip,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[2];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDIN, 0),
@@ -1679,7 +1721,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READID, 0),
NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)),
@@ -1718,7 +1760,7 @@ int nand_status_op(struct nand_chip *chip, u8 *status)
{
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_STATUS,
PSEC_TO_NSEC(sdr->tADL_min)),
@@ -1787,7 +1829,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[3] = { page, page >> 8, page >> 16 };
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_ERASE1, 0),
@@ -1846,7 +1888,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_SET_FEATURES, 0),
NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tADL_min)),
@@ -1893,7 +1935,7 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_GET_FEATURES, 0),
NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tWB_max)),
@@ -1950,7 +1992,7 @@ int nand_reset_op(struct nand_chip *chip)
{
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(&chip->data_interface);
+ nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0),
@@ -2480,17 +2522,16 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
* @chipnr: Internal die id
*
* Save the timings data structure, then apply SDR timings mode 0 (see
- * nand_reset_data_interface for details), do the reset operation, and
- * apply back the previous timings.
+ * nand_reset_interface for details), do the reset operation, and apply
+ * back the previous timings.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_reset(struct nand_chip *chip, int chipnr)
{
- struct nand_data_interface saved_data_intf = chip->data_interface;
int ret;
- ret = nand_reset_data_interface(chip, chipnr);
+ ret = nand_reset_interface(chip, chipnr);
if (ret)
return ret;
@@ -2505,18 +2546,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
if (ret)
return ret;
- /*
- * A nand_reset_data_interface() put both the NAND chip and the NAND
- * controller in timings mode 0. If the default mode for this chip is
- * also 0, no need to proceed to the change again. Plus, at probe time,
- * nand_setup_data_interface() uses ->set/get_features() which would
- * fail anyway as the parameter page is not available yet.
- */
- if (!chip->onfi_timing_mode_default)
- return 0;
-
- chip->data_interface = saved_data_intf;
- ret = nand_setup_data_interface(chip, chipnr);
+ ret = nand_setup_interface(chip, chipnr);
if (ret)
return ret;
@@ -3215,10 +3245,10 @@ static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
if (retry_mode >= chip->read_retries)
return -EINVAL;
- if (!chip->setup_read_retry)
+ if (!chip->ops.setup_read_retry)
return -EOPNOTSUPP;
- return chip->setup_read_retry(chip, retry_mode);
+ return chip->ops.setup_read_retry(chip, retry_mode);
}
static void nand_wait_readrdy(struct nand_chip *chip)
@@ -3228,7 +3258,7 @@ static void nand_wait_readrdy(struct nand_chip *chip)
if (!(chip->options & NAND_NEED_READRDY))
return;
- sdr = nand_get_sdr_timings(&chip->data_interface);
+ sdr = nand_get_sdr_timings(nand_get_interface_config(chip));
WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0));
}
@@ -4462,8 +4492,8 @@ static int nand_suspend(struct mtd_info *mtd)
int ret = 0;
mutex_lock(&chip->lock);
- if (chip->suspend)
- ret = chip->suspend(chip);
+ if (chip->ops.suspend)
+ ret = chip->ops.suspend(chip);
if (!ret)
chip->suspended = 1;
mutex_unlock(&chip->lock);
@@ -4481,8 +4511,8 @@ static void nand_resume(struct mtd_info *mtd)
mutex_lock(&chip->lock);
if (chip->suspended) {
- if (chip->resume)
- chip->resume(chip);
+ if (chip->ops.resume)
+ chip->ops.resume(chip);
chip->suspended = 0;
} else {
pr_err("%s called for a chip which is not in suspended state\n",
@@ -4511,10 +4541,10 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
- if (!chip->lock_area)
+ if (!chip->ops.lock_area)
return -ENOTSUPP;
- return chip->lock_area(chip, ofs, len);
+ return chip->ops.lock_area(chip, ofs, len);
}
/**
@@ -4527,10 +4557,10 @@ static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
- if (!chip->unlock_area)
+ if (!chip->ops.unlock_area)
return -ENOTSUPP;
- return chip->unlock_area(chip, ofs, len);
+ return chip->ops.unlock_area(chip, ofs, len);
}
/* Set default functions */
@@ -4743,8 +4773,6 @@ static bool find_full_id_nand(struct nand_chip *chip,
chip->options |= type->options;
chip->base.eccreq.strength = NAND_ECC_STRENGTH(type);
chip->base.eccreq.step_size = NAND_ECC_STEP(type);
- chip->onfi_timing_mode_default =
- type->onfi_timing_mode_default;
chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
if (!chip->parameters.model)
@@ -4810,9 +4838,9 @@ static void nand_manufacturer_cleanup(struct nand_chip *chip)
}
static const char *
-nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
+nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc)
{
- return manufacturer ? manufacturer->name : "Unknown";
+ return manufacturer_desc ? manufacturer_desc->name : "Unknown";
}
/*
@@ -4820,7 +4848,7 @@ nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
*/
static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
{
- const struct nand_manufacturer *manufacturer;
+ const struct nand_manufacturer_desc *manufacturer_desc;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
int busw, ret;
@@ -4877,8 +4905,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data));
/* Try to identify manufacturer */
- manufacturer = nand_get_manufacturer(maf_id);
- chip->manufacturer.desc = manufacturer;
+ manufacturer_desc = nand_get_manufacturer_desc(maf_id);
+ chip->manufacturer.desc = manufacturer_desc;
if (!type)
type = nand_flash_ids;
@@ -4957,7 +4985,7 @@ ident_done:
*/
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
maf_id, dev_id);
- pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+ pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc),
mtd->name);
pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
@@ -4992,7 +5020,7 @@ ident_done:
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
maf_id, dev_id);
- pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+ pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc),
chip->parameters.model);
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(targetsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
@@ -5185,7 +5213,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
mutex_init(&chip->lock);
/* Enforce the right timings for reset/detection */
- onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
+ chip->current_interface_config = nand_get_reset_interface_config();
ret = nand_dt_init(chip);
if (ret)
@@ -5972,16 +6000,16 @@ static int nand_scan_tail(struct nand_chip *chip)
if (!mtd->bitflip_threshold)
mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
- /* Initialize the ->data_interface field. */
- ret = nand_init_data_interface(chip);
+ /* Find the fastest data interface for this chip */
+ ret = nand_choose_interface_config(chip);
if (ret)
goto err_nanddev_cleanup;
/* Enter fastest possible mode on all dies. */
for (i = 0; i < nanddev_ntargets(&chip->base); i++) {
- ret = nand_setup_data_interface(chip, i);
+ ret = nand_setup_interface(chip, i);
if (ret)
- goto err_nanddev_cleanup;
+ goto err_free_interface_config;
}
/* Check, if we should skip the bad block table scan */
@@ -5991,10 +6019,12 @@ static int nand_scan_tail(struct nand_chip *chip)
/* Build bad block table */
ret = nand_create_bbt(chip);
if (ret)
- goto err_nanddev_cleanup;
+ goto err_free_interface_config;
return 0;
+err_free_interface_config:
+ kfree(chip->best_interface_config);
err_nanddev_cleanup:
nanddev_cleanup(&chip->base);
@@ -6088,6 +6118,9 @@ void nand_cleanup(struct nand_chip *chip)
& NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern);
+ /* Free the data interface */
+ kfree(chip->best_interface_config);
+
/* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip);