[PATCH v3 2/2] mtd: nand: gpmi: Support ->setup_data_interface()

Han Xu han.xu at nxp.com
Mon Feb 12 14:48:17 PST 2018



On 01/19/2018 07:58 AM, Miquel Raynal wrote:
> Until now the GPMI driver had its own timings logic while the core
> already handles that and request the NAND controller drivers to support
> the ->setup_data_interface() hook. Implement that hook by reusing the
> already existing function. No real glue is necessary between core timing
> delays and GPMI registers because the driver already translates the
> ONFI timing modes into register values.
>
> Make use of the core's tREA, tRLOH and tRHOH values that allow computing
> more precise timings for mode [0-3] and get significantly better values
> (+20% with an i.MX6 Sabre Auto board). Otherwise use the existing logic.
>
> Signed-off-by: Miquel Raynal <miquel.raynal at free-electrons.com>
> ---
>   drivers/mtd/nand/gpmi-nand/gpmi-lib.c  | 277 ++++++++++-----------------------
>   drivers/mtd/nand/gpmi-nand/gpmi-nand.c |  42 +++--
>   drivers/mtd/nand/gpmi-nand/gpmi-nand.h |  82 +++++-----
>   drivers/mtd/nand/nand_base.c           |   3 +-
>   4 files changed, 152 insertions(+), 252 deletions(-)
>
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> index 97787246af41..9a58661eb3b1 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> @@ -151,8 +151,15 @@ static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
>   	return ret;
>   }
>   
> -#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
> -#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
> +int gpmi_enable_clk(struct gpmi_nand_data *this)
> +{
> +	return __gpmi_enable_clk(this, true);
> +}
> +
> +int gpmi_disable_clk(struct gpmi_nand_data *this)
> +{
> +	return __gpmi_enable_clk(this, false);
> +}
>   
>   int gpmi_init(struct gpmi_nand_data *this)
>   {
> @@ -326,14 +333,13 @@ static unsigned int ns_to_cycles(unsigned int time,
>   #define DEF_MIN_PROP_DELAY	5
>   #define DEF_MAX_PROP_DELAY	9
>   /* Apply timing to current hardware conditions. */
> -static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
> -					struct gpmi_nfc_hardware_timing *hw)
> +static void
> +gpmi_nfc_compute_hardware_timings(struct gpmi_nand_data *this)
>   {
> +	struct gpmi_nfc_hardware_timing *hw = &this->hw;
>   	struct timing_threshold *nfc = &timing_default_threshold;
> -	struct resources *r = &this->resources;
>   	struct nand_chip *nand = &this->nand;
>   	struct nand_timing target = this->timing;
> -	bool improved_timing_is_available;
>   	unsigned long clock_frequency_in_hz;
>   	unsigned int clock_period_in_ns;
>   	bool dll_use_half_periods;
> @@ -349,6 +355,9 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
>   	unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
>   	unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
>   
> +	/* Clock rate for non-EDO modes */
> +	hw->clk_rate = 22000000;
> +
>   	/*
>   	 * If there are multiple chips, we need to relax the timings to allow
>   	 * for signal distortion due to higher capacitance.
> @@ -363,14 +372,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
>   		target.address_setup_in_ns += 5;
>   	}
>   
> -	/* Check if improved timing information is available. */
> -	improved_timing_is_available =
> -		(target.tREA_in_ns  >= 0) &&
> -		(target.tRLOH_in_ns >= 0) &&
> -		(target.tRHOH_in_ns >= 0);
> -
>   	/* Inspect the clock. */
> -	nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
> +	nfc->clock_frequency_in_hz = hw->clk_rate;
>   	clock_frequency_in_hz = nfc->clock_frequency_in_hz;
>   	clock_period_in_ns    = NSEC_PER_SEC / clock_frequency_in_hz;
>   
> @@ -482,65 +485,6 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
>   	}
>   
>   	/*
> -	 * Check if improved timing information is available. If not, we have to
> -	 * use a less-sophisticated algorithm.
> -	 */
> -	if (!improved_timing_is_available) {
> -		/*
> -		 * Fold the read setup time required by the NFC into the ideal
> -		 * sample delay.
> -		 */
> -		ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns +
> -						nfc->internal_data_setup_in_ns;
> -
> -		/*
> -		 * The ideal sample delay may be greater than the maximum
> -		 * allowed by the NFC. If so, we can trade off sample delay time
> -		 * for more data setup time.
> -		 *
> -		 * In each iteration of the following loop, we add a cycle to
> -		 * the data setup time and subtract a corresponding amount from
> -		 * the sample delay until we've satisified the constraints or
> -		 * can't do any better.
> -		 */
> -		while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
> -			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
> -
> -			data_setup_in_cycles++;
> -			ideal_sample_delay_in_ns -= clock_period_in_ns;
> -
> -			if (ideal_sample_delay_in_ns < 0)
> -				ideal_sample_delay_in_ns = 0;
> -
> -		}
> -
> -		/*
> -		 * Compute the sample delay factor that corresponds most closely
> -		 * to the ideal sample delay. If the result is too large for the
> -		 * NFC, use the maximum value.
> -		 *
> -		 * Notice that we use the ns_to_cycles function to compute the
> -		 * sample delay factor. We do this because the form of the
> -		 * computation is the same as that for calculating cycles.
> -		 */
> -		sample_delay_factor =
> -			ns_to_cycles(
> -				ideal_sample_delay_in_ns << dll_delay_shift,
> -							clock_period_in_ns, 0);
> -
> -		if (sample_delay_factor > nfc->max_sample_delay_factor)
> -			sample_delay_factor = nfc->max_sample_delay_factor;
> -
> -		/* Skip to the part where we return our results. */
> -		goto return_results;
> -	}
> -
> -	/*
> -	 * If control arrives here, we have more detailed timing information,
> -	 * so we can use a better algorithm.
> -	 */
> -
> -	/*
>   	 * Fold the read setup time required by the NFC into the maximum
>   	 * propagation delay.
>   	 */
> @@ -760,8 +704,6 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
>   			sample_delay_factor = nfc->max_sample_delay_factor;
>   	}
>   
> -	/* Control arrives here when we're ready to return our results. */
> -return_results:
>   	hw->data_setup_in_cycles    = data_setup_in_cycles;
>   	hw->data_hold_in_cycles     = data_hold_in_cycles;
>   	hw->address_setup_in_cycles = address_setup_in_cycles;
> @@ -769,9 +711,6 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
>   	hw->sample_delay_factor     = sample_delay_factor;
>   	hw->device_busy_timeout     = GPMI_DEFAULT_BUSY_TIMEOUT;
>   	hw->wrn_dly_sel             = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
> -
> -	/* Return success. */
> -	return 0;
>   }
>   
>   /*
> @@ -857,19 +796,17 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
>    *       So we only support the mode 4 and mode 5. It is no need to
>    *       support other modes.
>    */
> -static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
> -			struct gpmi_nfc_hardware_timing *hw)
> +static void gpmi_nfc_compute_edo_timings(struct gpmi_nand_data *this,
> +					 int mode)
>   {
> -	struct resources *r = &this->resources;
> -	unsigned long rate = clk_get_rate(r->clock[0]);
> -	int mode = this->timing_mode;
> +	struct gpmi_nfc_hardware_timing *hw = &this->hw;
>   	int dll_threshold = this->devdata->max_chain_delay;
>   	unsigned long delay;
>   	unsigned long clk_period;
> -	int t_rea;
> -	int c = 4;
> -	int t_rp;
> -	int rp;
> +	int t_rp, t_rea, rp;
> +
> +	/* Set the main clock to: 100MHz (mode 5) or 80MHz (mode 4) */
> +	hw->clk_rate = (mode == 5) ? 100000000 : 80000000;
>   
>   	/*
>   	 * [1] for GPMI_HW_GPMI_TIMING0:
> @@ -880,7 +817,7 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
>   	 */
>   	hw->data_setup_in_cycles = 1;
>   	hw->data_hold_in_cycles = 1;
> -	hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0);
> +	hw->address_setup_in_cycles = (mode == 5) ? 1 : 0;
>   
>   	/* [2] for GPMI_HW_GPMI_TIMING1 */
>   	hw->device_busy_timeout = 0x9000;
> @@ -892,11 +829,9 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
>   	 * Enlarge 10 times for the numerator and denominator in {3}.
>   	 * This make us to get more accurate result.
>   	 */
> -	clk_period = NSEC_PER_SEC / (rate / 10);
> +	clk_period = NSEC_PER_SEC / (hw->clk_rate / 10);
>   	dll_threshold *= 10;
> -	t_rea = ((mode == 5) ? 16 : 20) * 10;
> -	c *= 10;
> -
> +	t_rea = this->timing.tREA_in_ns * 10;
>   	t_rp = clk_period * 1; /* DATA_SETUP is 1 */
>   
>   	if (clk_period > dll_threshold) {
> @@ -911,129 +846,42 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
>   	 * Multiply the numerator with 10, we could do a round off:
>   	 *      7.8 round up to 8; 7.4 round down to 7.
>   	 */
> -	delay  = (((t_rea + c - t_rp) * 8) * 10) / rp;
> +	delay  = (((t_rea + 40 - t_rp) * 8) * 10) / rp;
>   	delay = (delay + 5) / 10;
>   
>   	hw->sample_delay_factor = delay;
>   }
>   
> -static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
> -{
> -	struct resources  *r = &this->resources;
> -	struct nand_chip *nand = &this->nand;
> -	struct mtd_info	 *mtd = nand_to_mtd(nand);
> -	uint8_t *feature;
> -	unsigned long rate;
> -	int ret;
> -
> -	feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
> -	if (!feature)
> -		return -ENOMEM;
> -
> -	nand->select_chip(mtd, 0);
> -
> -	/* [1] send SET FEATURE command to NAND */
> -	feature[0] = mode;
> -	ret = nand->onfi_set_features(mtd, nand,
> -				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
> -	if (ret)
> -		goto err_out;
> -
> -	/* [2] send GET FEATURE command to double-check the timing mode */
> -	memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
> -	ret = nand->onfi_get_features(mtd, nand,
> -				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
> -	if (ret || feature[0] != mode)
> -		goto err_out;
> -
> -	nand->select_chip(mtd, -1);
> -
> -	/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
> -	rate = (mode == 5) ? 100000000 : 80000000;
> -	clk_set_rate(r->clock[0], rate);
> -
> -	/* Let the gpmi_begin() re-compute the timing again. */
> -	this->flags &= ~GPMI_TIMING_INIT_OK;
> -
> -	this->flags |= GPMI_ASYNC_EDO_ENABLED;
> -	this->timing_mode = mode;
> -	kfree(feature);
> -	dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
> -	return 0;
> -
> -err_out:
> -	nand->select_chip(mtd, -1);
> -	kfree(feature);
> -	dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
> -	return -EINVAL;
> -}
> -
> -int gpmi_extra_init(struct gpmi_nand_data *this)
> -{
> -	struct nand_chip *chip = &this->nand;
> -
> -	/* Enable the asynchronous EDO feature. */
> -	if (GPMI_IS_MX6(this) && chip->onfi_version) {
> -		int mode = onfi_get_async_timing_mode(chip);
> -
> -		/* We only support the timing mode 4 and mode 5. */
> -		if (mode & ONFI_TIMING_MODE_5)
> -			mode = 5;
> -		else if (mode & ONFI_TIMING_MODE_4)
> -			mode = 4;
> -		else
> -			return 0;
> -
> -		return enable_edo_mode(this, mode);
> -	}
> -	return 0;
> -}
> -
>   /* Begin the I/O */
> -void gpmi_begin(struct gpmi_nand_data *this)
> +void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
>   {
> +	struct gpmi_nfc_hardware_timing *hw = &this->hw;
>   	struct resources *r = &this->resources;
>   	void __iomem *gpmi_regs = r->gpmi_regs;
>   	unsigned int   clock_period_in_ns;
>   	uint32_t       reg;
>   	unsigned int   dll_wait_time_in_us;
> -	struct gpmi_nfc_hardware_timing  hw;
> -	int ret;
> -
> -	/* Enable the clock. */
> -	ret = gpmi_enable_clk(this);
> -	if (ret) {
> -		dev_err(this->dev, "We failed in enable the clk\n");
> -		goto err_out;
> -	}
>   
> -	/* Only initialize the timing once */
> -	if (this->flags & GPMI_TIMING_INIT_OK)
> -		return;
> -	this->flags |= GPMI_TIMING_INIT_OK;
> -
> -	if (this->flags & GPMI_ASYNC_EDO_ENABLED)
> -		gpmi_compute_edo_timing(this, &hw);
> -	else
> -		gpmi_nfc_compute_hardware_timing(this, &hw);
> +	/* [0] Set the main clock rate */
> +	clk_set_rate(r->clock[0], hw->clk_rate);
>   
>   	/* [1] Set HW_GPMI_TIMING0 */
> -	reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
> -		BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles)         |
> -		BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
> +	reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw->address_setup_in_cycles) |
> +		BF_GPMI_TIMING0_DATA_HOLD(hw->data_hold_in_cycles) |
> +		BF_GPMI_TIMING0_DATA_SETUP(hw->data_setup_in_cycles);
>   
>   	writel(reg, gpmi_regs + HW_GPMI_TIMING0);
>   
>   	/* [2] Set HW_GPMI_TIMING1 */
> -	writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout),
> -		gpmi_regs + HW_GPMI_TIMING1);
> +	writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw->device_busy_timeout),
> +	       gpmi_regs + HW_GPMI_TIMING1);
>   
>   	/* [3] The following code is to set the HW_GPMI_CTRL1. */
>   
>   	/* Set the WRN_DLY_SEL */
>   	writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
> -	writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel),
> -					gpmi_regs + HW_GPMI_CTRL1_SET);
> +	writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw->wrn_dly_sel),
> +	       gpmi_regs + HW_GPMI_CTRL1_SET);
>   
>   	/* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */
>   	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
> @@ -1043,12 +891,12 @@ void gpmi_begin(struct gpmi_nand_data *this)
>   	writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
>   
>   	/* If no sample delay is called for, return immediately. */
> -	if (!hw.sample_delay_factor)
> +	if (!hw->sample_delay_factor)
>   		return;
>   
>   	/* Set RDN_DELAY or HALF_PERIOD. */
> -	reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
> -		| BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor);
> +	reg = ((hw->use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
> +		| BF_GPMI_CTRL1_RDN_DELAY(hw->sample_delay_factor);
>   
>   	writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
>   
> @@ -1060,7 +908,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
>   	 * we can use the GPMI. Calculate the amount of time we need to wait,
>   	 * in microseconds.
>   	 */
> -	clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]);
> +	clock_period_in_ns = NSEC_PER_SEC / hw->clk_rate;
>   	dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
>   
>   	if (!dll_wait_time_in_us)
> @@ -1068,14 +916,45 @@ void gpmi_begin(struct gpmi_nand_data *this)
>   
>   	/* Wait for the DLL to settle. */
>   	udelay(dll_wait_time_in_us);
> -
> -err_out:
> -	return;
>   }
>   
> -void gpmi_end(struct gpmi_nand_data *this)
> +int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
> +			      const struct nand_data_interface *conf)
>   {
> -	gpmi_disable_clk(this);
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	struct gpmi_nand_data *this = nand_get_controller_data(chip);
> +	const struct nand_sdr_timings *sdr;
> +	bool edo_mode = false;
> +
> +	/* Retrieve required NAND timings */
> +	sdr = nand_get_sdr_timings(conf);
> +	if (IS_ERR(sdr))
> +		return PTR_ERR(sdr);
> +
> +	if (sdr->tRC_min <= 25000)
> +		edo_mode = true;
> +
> +	/* Only MX6 GPMI controller can reach EDO timings */
> +	if (edo_mode && !GPMI_IS_MX6(this))
> +		return -ENOTSUPP;
> +
> +	if (chipnr < 0)
> +		return 0;
> +
> +	this->timing.tREA_in_ns = sdr->tREA_max / 1000;
> +	this->timing.tRLOH_in_ns = sdr->tRLOH_min / 1000;
> +	this->timing.tRHOH_in_ns = sdr->tRHOH_min / 1000;
> +
> +	/* Compute GPMI parameters depending on the mode */
> +	if (edo_mode)
> +		gpmi_nfc_compute_edo_timings(this,
> +					     sdr->tRC_min > 20000 ? 4 : 5);
> +	else
> +		gpmi_nfc_compute_hardware_timings(this);
> +
> +	this->hw.must_apply_timings = true;
> +
> +	return 0;
>   }
>   
>   /* Clears a BCH interrupt. */
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> index b51db8c85405..459b7fb5e15b 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> @@ -938,11 +938,32 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
>   {
>   	struct nand_chip *chip = mtd_to_nand(mtd);
>   	struct gpmi_nand_data *this = nand_get_controller_data(chip);
> +	int ret;
>   
> -	if ((this->current_chip < 0) && (chipnr >= 0))
> -		gpmi_begin(this);
> -	else if ((this->current_chip >= 0) && (chipnr < 0))
> -		gpmi_end(this);
> +	/*
> +	 * For power consumption matters, disable/enable the clock each time a
> +	 * die is selected/unselected.
> +	 */
> +	if (this->current_chip < 0 && chipnr >= 0) {
> +		ret = gpmi_enable_clk(this);
> +		if (ret)
> +			dev_err(this->dev, "Failed to enable the clock\n");
> +	} else if (this->current_chip >= 0 && chipnr < 0) {
> +		ret = gpmi_disable_clk(this);
> +		if (ret)
> +			dev_err(this->dev, "Failed to disable the clock\n");
> +	}
> +
> +	/*
> +	 * This driver currently supports only one NAND chip. Plus, dies share
> +	 * the same configuration. So once timings have been applied on the
> +	 * controller side, they will not change anymore. When the time will
> +	 * come, the check on must_apply_timings will have to be dropped.
> +	 */
> +	if (chipnr >= 0 && this->hw.must_apply_timings) {
> +		this->hw.must_apply_timings = false;
> +		gpmi_nfc_apply_timings(this);
> +	}
>   
>   	this->current_chip = chipnr;
>   }
> @@ -1947,14 +1968,6 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
>   		chip->options |= NAND_SUBPAGE_READ;
>   	}
>   
> -	/*
> -	 * Can we enable the extra features? such as EDO or Sync mode.
> -	 *
> -	 * We do not check the return value now. That's means if we fail in
> -	 * enable the extra features, we still can run in the normal way.
> -	 */
> -	gpmi_extra_init(this);
> -
>   	return 0;
>   }
>   
> @@ -1975,6 +1988,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
>   	nand_set_controller_data(chip, this);
>   	nand_set_flash_node(chip, this->pdev->dev.of_node);
>   	chip->select_chip	= gpmi_select_chip;
> +	chip->setup_data_interface = gpmi_setup_data_interface;
>   	chip->cmd_ctrl		= gpmi_cmd_ctrl;
>   	chip->dev_ready		= gpmi_dev_ready;
>   	chip->read_byte		= gpmi_read_byte;
> @@ -2133,7 +2147,6 @@ static int gpmi_pm_resume(struct device *dev)
>   		return ret;
>   
>   	/* re-init the GPMI registers */
> -	this->flags &= ~GPMI_TIMING_INIT_OK;
>   	ret = gpmi_init(this);
>   	if (ret) {
>   		dev_err(this->dev, "Error setting GPMI : %d\n", ret);
> @@ -2147,9 +2160,6 @@ static int gpmi_pm_resume(struct device *dev)
>   		return ret;
>   	}
>   
> -	/* re-init others */
> -	gpmi_extra_init(this);
> -
>   	return 0;
>   }
>   #endif /* CONFIG_PM_SLEEP */
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
> index 06c1f993912c..23f9030cf6d2 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
> @@ -135,11 +135,47 @@ struct gpmi_devdata {
>   	const int clks_count;
>   };
>   
> +/**
> + * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
> + * @timing_mode:               The timing mode to comply with.
> + * @must_apply_timings:        Whether controller timings have already been
> + *                             applied or not (useful only while there is
> + *                             support for only one chip select)
> + * @clk_rate:                  The clock rate that must be used to derive the
> + *                             following parameters.
> + * @data_setup_in_cycles:      The data setup time, in cycles.
> + * @data_hold_in_cycles:       The data hold time, in cycles.
> + * @address_setup_in_cycles:   The address setup time, in cycles.
> + * @device_busy_timeout:       The timeout waiting for NAND Ready/Busy,
> + *                             this value is the number of cycles multiplied
> + *                             by 4096.
> + * @use_half_periods:          Indicates the clock is running slowly, so the
> + *                             NFC DLL should use half-periods.
> + * @sample_delay_factor:       The sample delay factor.
> + * @wrn_dly_sel:               The delay on the GPMI write strobe.
> + */
> +struct gpmi_nfc_hardware_timing {
> +	unsigned int timing_mode;
> +	bool must_apply_timings;
> +	unsigned long int clk_rate;
> +
> +	/* for HW_GPMI_TIMING0 */
> +	u8 data_setup_in_cycles;
> +	u8 data_hold_in_cycles;
> +	u8 address_setup_in_cycles;
> +
> +	/* for HW_GPMI_TIMING1 */
> +	u16 device_busy_timeout;
> +#define GPMI_DEFAULT_BUSY_TIMEOUT	0x500 /* default busy timeout value.*/
> +
> +	/* for HW_GPMI_CTRL1 */
> +	bool use_half_periods;
> +	u8 sample_delay_factor;
> +	u8 wrn_dly_sel;
> +};
> +
>   struct gpmi_nand_data {
> -	/* flags */
> -#define GPMI_ASYNC_EDO_ENABLED	(1 << 0)
> -#define GPMI_TIMING_INIT_OK	(1 << 1)
> -	int			flags;
> +	/* Devdata */
>   	const struct gpmi_devdata *devdata;
>   
>   	/* System Interface */
> @@ -152,6 +188,7 @@ struct gpmi_nand_data {
>   	/* Flash Hardware */
>   	struct nand_timing	timing;
>   	int			timing_mode;
> +	struct gpmi_nfc_hardware_timing hw;
>   
>   	/* BCH */
>   	struct bch_geometry	bch_geometry;
> @@ -205,35 +242,6 @@ struct gpmi_nand_data {
>   };
>   
>   /**
> - * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
> - * @data_setup_in_cycles:      The data setup time, in cycles.
> - * @data_hold_in_cycles:       The data hold time, in cycles.
> - * @address_setup_in_cycles:   The address setup time, in cycles.
> - * @device_busy_timeout:       The timeout waiting for NAND Ready/Busy,
> - *                             this value is the number of cycles multiplied
> - *                             by 4096.
> - * @use_half_periods:          Indicates the clock is running slowly, so the
> - *                             NFC DLL should use half-periods.
> - * @sample_delay_factor:       The sample delay factor.
> - * @wrn_dly_sel:               The delay on the GPMI write strobe.
> - */
> -struct gpmi_nfc_hardware_timing {
> -	/* for HW_GPMI_TIMING0 */
> -	uint8_t  data_setup_in_cycles;
> -	uint8_t  data_hold_in_cycles;
> -	uint8_t  address_setup_in_cycles;
> -
> -	/* for HW_GPMI_TIMING1 */
> -	uint16_t device_busy_timeout;
> -#define GPMI_DEFAULT_BUSY_TIMEOUT	0x500 /* default busy timeout value.*/
> -
> -	/* for HW_GPMI_CTRL1 */
> -	bool     use_half_periods;
> -	uint8_t  sample_delay_factor;
> -	uint8_t  wrn_dly_sel;
> -};
> -
> -/**
>    * struct timing_threshold - Timing threshold
>    * @max_data_setup_cycles:       The maximum number of data setup cycles that
>    *                               can be expressed in the hardware.
> @@ -279,14 +287,16 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *,
>   
>   /* GPMI-NAND helper function library */
>   int gpmi_init(struct gpmi_nand_data *);
> -int gpmi_extra_init(struct gpmi_nand_data *);
>   void gpmi_clear_bch(struct gpmi_nand_data *);
>   void gpmi_dump_info(struct gpmi_nand_data *);
>   int bch_set_geometry(struct gpmi_nand_data *);
>   int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
>   int gpmi_send_command(struct gpmi_nand_data *);
> -void gpmi_begin(struct gpmi_nand_data *);
> -void gpmi_end(struct gpmi_nand_data *);
> +int gpmi_enable_clk(struct gpmi_nand_data *this);
> +int gpmi_disable_clk(struct gpmi_nand_data *this);
> +int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
> +			      const struct nand_data_interface *conf);
> +void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
>   int gpmi_read_data(struct gpmi_nand_data *);
>   int gpmi_send_data(struct gpmi_nand_data *);
>   int gpmi_send_page(struct gpmi_nand_data *,
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index e209a65a17e0..9602d17845e2 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -1267,7 +1267,8 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
>   	return 0;
>   
>   err_reset_chip:
> -	onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
> +	/* Fallback to timing mode 0 */
> +	nand_reset_data_interface(chip, chipnr);
>   	chip->select_chip(mtd, chipnr);
>   	nand_reset_op(chip);
>   	chip->select_chip(mtd, -1);
Tested-by: Han Xu <han.xu at nxp.com>


More information about the linux-mtd mailing list