[PATCH 2/2] mtd: nand: gpmi: Support ->setup_data_interface()
Boris Brezillon
boris.brezillon at free-electrons.com
Sat Jan 6 02:24:31 PST 2018
On Fri, 22 Dec 2017 18:28:53 +0100
Miquel Raynal <miquel.raynal at free-electrons.com> 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 | 266 ++++++++++-----------------------
> drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 33 ++--
> drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 146 +++++++++---------
> 3 files changed, 168 insertions(+), 277 deletions(-)
>
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> index 97787246af41..ae47cd8414bf 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)
> +inline int gpmi_enable_clk(struct gpmi_nand_data *this)
Drop the inline here.
> +{
> + return __gpmi_enable_clk(this, true);
> +}
> +
> +inline int gpmi_disable_clk(struct gpmi_nand_data *this)
Ditto.
> +{
> + return __gpmi_enable_clk(this, false);
> +}
>
> int gpmi_init(struct gpmi_nand_data *this)
> {
> @@ -326,11 +333,11 @@ 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;
> @@ -349,6 +356,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 +373,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 +486,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 +705,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 +712,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,12 +797,9 @@ 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)
> {
> - 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;
> @@ -871,6 +808,9 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
> int t_rp;
> int rp;
>
> + /* Set the main clock to: 100MHz (mode 5) or 80MHz (mode 4) */
> + hw->clk_rate = (hw->timing_mode == 5) ? 100000000 : 80000000;
> +
> /*
> * [1] for GPMI_HW_GPMI_TIMING0:
> * The async mode requires 40MHz for mode 4, 50MHz for mode 5.
> @@ -880,7 +820,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 = (hw->timing_mode == 5) ? 1 : 0;
>
> /* [2] for GPMI_HW_GPMI_TIMING1 */
> hw->device_busy_timeout = 0x9000;
> @@ -892,9 +832,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;
> + t_rea = (hw->timing_mode == 5 ? 16 : 20) * 10;
Why don't you use the tREA_max value provided in nand_sdr_timings?
> c *= 10;
>
> t_rp = clk_period * 1; /* DATA_SETUP is 1 */
> @@ -917,123 +857,36 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
> 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 +896,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 +913,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 +921,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;
> +
> + if (chip->onfi_timing_mode_default < 0 ||
> + chip->onfi_timing_mode_default > 5)
> + return -ENOTSUPP;
I'd prefer if you could check conf instead of
->onfi_timing_mode_default. I still hope that one day we'll support
per-chip timings for those chips that are not ONFI compliant, and that
means ->onfi_timing_mode_default will be invalid in this case.
> +
> + /* Only MX6 GPMI controller can reach EDO timings */
> + if (chip->onfi_timing_mode_default >= 4 && !GPMI_IS_MX6(this))
> + return -ENOTSUPP;
Ditto: base your check on tRC/tWC.
> +
> + if (chipnr < 0)
> + return 0;
> +
> + this->hw.timing_mode = chip->onfi_timing_mode_default;
Do you really need to keep a copy of the ONFI timing mode?
> +
> + sdr = nand_get_sdr_timings(conf);
> + if (IS_ERR(sdr))
> + return PTR_ERR(sdr);
> +
> + 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 (this->hw.timing_mode >= 4)
> + gpmi_nfc_compute_edo_timings(this);
> + else
> + gpmi_nfc_compute_hardware_timings(this);
> +
> + gpmi_nfc_apply_timings(this);
Please add a comment saying that this gpmi_nfc_apply_timings()
call should be moved to ->select_chip() if we want to support multiple
NAND chips with different timings. Actually, if that's not to much
effort, I'd prefer to have this moved in gpmi_select_chip() now.
> +
> + 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..04986cd89c99 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> @@ -938,11 +938,23 @@ 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);
> + /*
> + * This driver currently supports only one NAND chip. So once timings
> + * have been decided, they will not change. Furthermore, dies share the
> + * same configuration, so for power consumption matters, we only
> + * disable/enable the clock.
> + */
> + 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->current_chip = chipnr;
> }
> @@ -1947,14 +1959,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 +1979,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 +2138,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 +2151,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..4890e1378475 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
> @@ -135,11 +135,77 @@ struct gpmi_devdata {
> const int clks_count;
> };
>
> +/**
> + * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
> + * @timing_mode: The timing mode to comply with.
> + * @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;
> + 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;
Hm, why not having 3 u32 fields containing the values to program in
TIMING0, TIMING1 and CTRL1?
> +};
> +
> +/**
> + * struct timing_threshold - Timing threshold
> + * @max_data_setup_cycles: The maximum number of data setup cycles that
> + * can be expressed in the hardware.
> + * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires
> + * for data read internal setup. In the Reference
> + * Manual, see the chapter "High-Speed NAND
> + * Timing" for more details.
> + * @max_sample_delay_factor: The maximum sample delay factor that can be
> + * expressed in the hardware.
> + * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the
> + * sample delay DLL hardware can possibly work
> + * with (the DLL is unusable with longer periods).
> + * If the full-cycle period is greater than HALF
> + * this value, the DLL must be configured to use
> + * half-periods.
> + * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the
> + * DLL can implement.
> + * @clock_frequency_in_hz: The clock frequency, in Hz, during the current
> + * I/O transaction. If no I/O transaction is in
> + * progress, this is the clock frequency during
> + * the most recent I/O transaction.
> + */
> +struct timing_threshold {
> + const unsigned int max_chip_count;
> + const unsigned int max_data_setup_cycles;
> + const unsigned int internal_data_setup_in_ns;
> + const unsigned int max_sample_delay_factor;
> + const unsigned int max_dll_clock_period_in_ns;
> + const unsigned int max_dll_delay_in_ns;
> + unsigned long clock_frequency_in_hz;
> +
> +};
Not sure why you're moving this definition here.
> +
> 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 +218,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;
> @@ -204,69 +271,6 @@ struct gpmi_nand_data {
> void *private;
> };
>
> -/**
> - * 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.
> - * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires
> - * for data read internal setup. In the Reference
> - * Manual, see the chapter "High-Speed NAND
> - * Timing" for more details.
> - * @max_sample_delay_factor: The maximum sample delay factor that can be
> - * expressed in the hardware.
> - * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the
> - * sample delay DLL hardware can possibly work
> - * with (the DLL is unusable with longer periods).
> - * If the full-cycle period is greater than HALF
> - * this value, the DLL must be configured to use
> - * half-periods.
> - * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the
> - * DLL can implement.
> - * @clock_frequency_in_hz: The clock frequency, in Hz, during the current
> - * I/O transaction. If no I/O transaction is in
> - * progress, this is the clock frequency during
> - * the most recent I/O transaction.
> - */
> -struct timing_threshold {
> - const unsigned int max_chip_count;
> - const unsigned int max_data_setup_cycles;
> - const unsigned int internal_data_setup_in_ns;
> - const unsigned int max_sample_delay_factor;
> - const unsigned int max_dll_clock_period_in_ns;
> - const unsigned int max_dll_delay_in_ns;
> - unsigned long clock_frequency_in_hz;
> -
> -};
> -
> /* Common Services */
> int common_nfc_set_geometry(struct gpmi_nand_data *);
> struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
> @@ -279,14 +283,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 *,
More information about the linux-mtd
mailing list