Commit 35b6bcc9 authored by Miquel Raynal's avatar Miquel Raynal

mtd: rawnand: Allocate the interface configurations dynamically

Instead of manipulating the statically allocated structure and copy
timings around, allocate one at identification time and save it in the
nand_chip structure once it has been initialized.

All NAND chips using the same interface configuration during reset and
startup, we define a helper to retrieve a single reset interface
configuration object, shared across all NAND chips.

We use a second pointer to always have a reference on the currently
applied interface configuration, which may either point to the "best
interface configuration" or to the "default reset interface
configuration".
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-29-miquel.raynal@bootlin.com
parent a69ad111
...@@ -93,6 +93,7 @@ onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings); ...@@ -93,6 +93,7 @@ onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings);
int nand_choose_best_sdr_timings(struct nand_chip *chip, int nand_choose_best_sdr_timings(struct nand_chip *chip,
struct nand_interface_config *iface, struct nand_interface_config *iface,
struct nand_sdr_timings *spec_timings); struct nand_sdr_timings *spec_timings);
const struct nand_interface_config *nand_get_reset_interface_config(void);
int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); 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); int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
......
...@@ -928,9 +928,9 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr) ...@@ -928,9 +928,9 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr)
* timings to timing mode 0. * timings to timing mode 0.
*/ */
onfi_fill_interface_config(chip, &chip->interface_config, chip->current_interface_config = nand_get_reset_interface_config();
NAND_SDR_IFACE, 0); ret = ops->setup_interface(chip, chipnr,
ret = ops->setup_interface(chip, chipnr, &chip->interface_config); chip->current_interface_config);
if (ret) if (ret)
pr_err("Failed to configure data interface to SDR timing mode 0\n"); pr_err("Failed to configure data interface to SDR timing mode 0\n");
...@@ -949,13 +949,25 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr) ...@@ -949,13 +949,25 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr)
*/ */
static int nand_setup_interface(struct nand_chip *chip, int chipnr) static int nand_setup_interface(struct nand_chip *chip, int chipnr)
{ {
u8 mode = chip->interface_config.timings.mode; const struct nand_controller_ops *ops = chip->controller->ops;
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { mode, }; u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { };
int ret; int ret;
if (!nand_controller_can_setup_interface(chip)) if (!nand_controller_can_setup_interface(chip))
return 0; 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) */ /* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) { if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
...@@ -967,14 +979,13 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr) ...@@ -967,14 +979,13 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr)
} }
/* Change the mode on the controller side */ /* Change the mode on the controller side */
ret = chip->controller->ops->setup_interface(chip, chipnr, ret = ops->setup_interface(chip, chipnr, chip->best_interface_config);
&chip->interface_config);
if (ret) if (ret)
return ret; return ret;
/* Check the mode has been accepted by the chip, if supported */ /* Check the mode has been accepted by the chip, if supported */
if (!nand_supports_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) 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); memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
...@@ -984,12 +995,15 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr) ...@@ -984,12 +995,15 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr)
if (ret) if (ret)
goto err_reset_chip; goto err_reset_chip;
if (tmode_param[0] != mode) { if (tmode_param[0] != chip->best_interface_config->timings.mode) {
pr_warn("timing mode %d not acknowledged by the NAND chip\n", pr_warn("timing mode %d not acknowledged by the NAND chip\n",
mode); chip->best_interface_config->timings.mode);
goto err_reset_chip; goto err_reset_chip;
} }
update_interface_config:
chip->current_interface_config = chip->best_interface_config;
return 0; return 0;
err_reset_chip: err_reset_chip:
...@@ -1031,8 +1045,10 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, ...@@ -1031,8 +1045,10 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
/* Verify the controller supports the requested interface */ /* Verify the controller supports the requested interface */
ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
iface); iface);
if (!ret) if (!ret) {
chip->best_interface_config = iface;
return ret; return ret;
}
/* Fallback to slower modes */ /* Fallback to slower modes */
best_mode = iface->timings.mode; best_mode = iface->timings.mode;
...@@ -1046,9 +1062,11 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, ...@@ -1046,9 +1062,11 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
iface); iface);
if (!ret) if (!ret)
return 0; break;
} }
chip->best_interface_config = iface;
return 0; return 0;
} }
...@@ -1067,15 +1085,25 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, ...@@ -1067,15 +1085,25 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
*/ */
static int nand_choose_interface_config(struct nand_chip *chip) static int nand_choose_interface_config(struct nand_chip *chip)
{ {
struct nand_interface_config *iface;
int ret;
if (!nand_controller_can_setup_interface(chip)) if (!nand_controller_can_setup_interface(chip))
return 0; return 0;
iface = kzalloc(sizeof(*iface), GFP_KERNEL);
if (!iface)
return -ENOMEM;
if (chip->ops.choose_interface_config) if (chip->ops.choose_interface_config)
return chip->ops.choose_interface_config(chip, ret = chip->ops.choose_interface_config(chip, iface);
&chip->interface_config); else
ret = nand_choose_best_sdr_timings(chip, iface, NULL);
return nand_choose_best_sdr_timings(chip, &chip->interface_config, if (ret)
NULL); kfree(iface);
return ret;
} }
/** /**
...@@ -2501,7 +2529,6 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len); ...@@ -2501,7 +2529,6 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
*/ */
int nand_reset(struct nand_chip *chip, int chipnr) int nand_reset(struct nand_chip *chip, int chipnr)
{ {
struct nand_interface_config saved_intf_config = chip->interface_config;
int ret; int ret;
ret = nand_reset_interface(chip, chipnr); ret = nand_reset_interface(chip, chipnr);
...@@ -2519,18 +2546,6 @@ int nand_reset(struct nand_chip *chip, int chipnr) ...@@ -2519,18 +2546,6 @@ int nand_reset(struct nand_chip *chip, int chipnr)
if (ret) if (ret)
return ret; return ret;
/*
* 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 (!memcmp(&chip->interface_config, &saved_intf_config,
sizeof(saved_intf_config)))
return 0;
chip->interface_config = saved_intf_config;
ret = nand_setup_interface(chip, chipnr); ret = nand_setup_interface(chip, chipnr);
if (ret) if (ret)
return ret; return ret;
...@@ -5198,7 +5213,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, ...@@ -5198,7 +5213,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
mutex_init(&chip->lock); mutex_init(&chip->lock);
/* Enforce the right timings for reset/detection */ /* Enforce the right timings for reset/detection */
onfi_fill_interface_config(chip, &chip->interface_config, NAND_SDR_IFACE, 0); chip->current_interface_config = nand_get_reset_interface_config();
ret = nand_dt_init(chip); ret = nand_dt_init(chip);
if (ret) if (ret)
...@@ -5994,7 +6009,7 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5994,7 +6009,7 @@ static int nand_scan_tail(struct nand_chip *chip)
for (i = 0; i < nanddev_ntargets(&chip->base); i++) { for (i = 0; i < nanddev_ntargets(&chip->base); i++) {
ret = nand_setup_interface(chip, i); ret = nand_setup_interface(chip, i);
if (ret) if (ret)
goto err_nanddev_cleanup; goto err_free_interface_config;
} }
/* Check, if we should skip the bad block table scan */ /* Check, if we should skip the bad block table scan */
...@@ -6004,10 +6019,12 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -6004,10 +6019,12 @@ static int nand_scan_tail(struct nand_chip *chip)
/* Build bad block table */ /* Build bad block table */
ret = nand_create_bbt(chip); ret = nand_create_bbt(chip);
if (ret) if (ret)
goto err_nanddev_cleanup; goto err_free_interface_config;
return 0; return 0;
err_free_interface_config:
kfree(chip->best_interface_config);
err_nanddev_cleanup: err_nanddev_cleanup:
nanddev_cleanup(&chip->base); nanddev_cleanup(&chip->base);
...@@ -6101,6 +6118,9 @@ void nand_cleanup(struct nand_chip *chip) ...@@ -6101,6 +6118,9 @@ void nand_cleanup(struct nand_chip *chip)
& NAND_BBT_DYNAMICSTRUCT) & NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern); kfree(chip->badblock_pattern);
/* Free the data interface */
kfree(chip->best_interface_config);
/* Free manufacturer priv data. */ /* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip); nand_manufacturer_cleanup(chip);
......
...@@ -292,6 +292,12 @@ static const struct nand_interface_config onfi_sdr_timings[] = { ...@@ -292,6 +292,12 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
}, },
}; };
/* All NAND chips share the same reset data interface: SDR mode 0 */
const struct nand_interface_config *nand_get_reset_interface_config(void)
{
return &onfi_sdr_timings[0];
}
/** /**
* onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a * onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a
* set of timings * set of timings
......
...@@ -1069,7 +1069,11 @@ struct nand_manufacturer { ...@@ -1069,7 +1069,11 @@ struct nand_manufacturer {
* @options: Various chip options. They can partly be set to inform nand_scan * @options: Various chip options. They can partly be set to inform nand_scan
* about special functionality. See the defines for further * about special functionality. See the defines for further
* explanation. * explanation.
* @interface_config: NAND interface timing information * @current_interface_config: The currently used NAND interface configuration
* @best_interface_config: The best NAND interface configuration which fits both
* the NAND chip and NAND controller constraints. If
* unset, the default reset interface configuration must
* be used.
* @bbt_erase_shift: Number of address bits in a bbt entry * @bbt_erase_shift: Number of address bits in a bbt entry
* @bbt_options: Bad block table specific options. All options used here must * @bbt_options: Bad block table specific options. All options used here must
* come from bbm.h. By default, these options will be copied to * come from bbm.h. By default, these options will be copied to
...@@ -1116,7 +1120,8 @@ struct nand_chip { ...@@ -1116,7 +1120,8 @@ struct nand_chip {
unsigned int options; unsigned int options;
/* Data interface */ /* Data interface */
struct nand_interface_config interface_config; const struct nand_interface_config *current_interface_config;
struct nand_interface_config *best_interface_config;
/* Bad block information */ /* Bad block information */
unsigned int bbt_erase_shift; unsigned int bbt_erase_shift;
...@@ -1209,7 +1214,7 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) ...@@ -1209,7 +1214,7 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
static inline const struct nand_interface_config * static inline const struct nand_interface_config *
nand_get_interface_config(struct nand_chip *chip) nand_get_interface_config(struct nand_chip *chip)
{ {
return &chip->interface_config; return chip->current_interface_config;
} }
/* /*
......
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