|
@@ -151,8 +151,15 @@ err_clk:
|
|
return ret;
|
|
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)
|
|
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_MIN_PROP_DELAY 5
|
|
#define DEF_MAX_PROP_DELAY 9
|
|
#define DEF_MAX_PROP_DELAY 9
|
|
/* Apply timing to current hardware conditions. */
|
|
/* 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 timing_threshold *nfc = &timing_default_threshold;
|
|
- struct resources *r = &this->resources;
|
|
|
|
struct nand_chip *nand = &this->nand;
|
|
struct nand_chip *nand = &this->nand;
|
|
struct nand_timing target = this->timing;
|
|
struct nand_timing target = this->timing;
|
|
- bool improved_timing_is_available;
|
|
|
|
unsigned long clock_frequency_in_hz;
|
|
unsigned long clock_frequency_in_hz;
|
|
unsigned int clock_period_in_ns;
|
|
unsigned int clock_period_in_ns;
|
|
bool dll_use_half_periods;
|
|
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 min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
|
|
unsigned int max_prop_delay_in_ns = DEF_MAX_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
|
|
* If there are multiple chips, we need to relax the timings to allow
|
|
* for signal distortion due to higher capacitance.
|
|
* 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;
|
|
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. */
|
|
/* 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_frequency_in_hz = nfc->clock_frequency_in_hz;
|
|
clock_period_in_ns = NSEC_PER_SEC / clock_frequency_in_hz;
|
|
clock_period_in_ns = NSEC_PER_SEC / clock_frequency_in_hz;
|
|
|
|
|
|
@@ -481,65 +484,6 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
|
|
max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
|
|
max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * 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
|
|
* Fold the read setup time required by the NFC into the maximum
|
|
* propagation delay.
|
|
* 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;
|
|
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_setup_in_cycles = data_setup_in_cycles;
|
|
hw->data_hold_in_cycles = data_hold_in_cycles;
|
|
hw->data_hold_in_cycles = data_hold_in_cycles;
|
|
hw->address_setup_in_cycles = address_setup_in_cycles;
|
|
hw->address_setup_in_cycles = address_setup_in_cycles;
|
|
@@ -769,9 +711,6 @@ return_results:
|
|
hw->sample_delay_factor = sample_delay_factor;
|
|
hw->sample_delay_factor = sample_delay_factor;
|
|
hw->device_busy_timeout = GPMI_DEFAULT_BUSY_TIMEOUT;
|
|
hw->device_busy_timeout = GPMI_DEFAULT_BUSY_TIMEOUT;
|
|
hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
|
|
hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
|
|
-
|
|
|
|
- /* Return success. */
|
|
|
|
- return 0;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -857,19 +796,17 @@ return_results:
|
|
* So we only support the mode 4 and mode 5. It is no need to
|
|
* So we only support the mode 4 and mode 5. It is no need to
|
|
* support other modes.
|
|
* 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;
|
|
int dll_threshold = this->devdata->max_chain_delay;
|
|
unsigned long delay;
|
|
unsigned long delay;
|
|
unsigned long clk_period;
|
|
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:
|
|
* [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_setup_in_cycles = 1;
|
|
hw->data_hold_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 */
|
|
/* [2] for GPMI_HW_GPMI_TIMING1 */
|
|
hw->device_busy_timeout = 0x9000;
|
|
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}.
|
|
* Enlarge 10 times for the numerator and denominator in {3}.
|
|
* This make us to get more accurate result.
|
|
* 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;
|
|
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 */
|
|
t_rp = clk_period * 1; /* DATA_SETUP is 1 */
|
|
|
|
|
|
if (clk_period > dll_threshold) {
|
|
if (clk_period > dll_threshold) {
|
|
@@ -911,127 +846,41 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
|
|
* Multiply the numerator with 10, we could do a round off:
|
|
* Multiply the numerator with 10, we could do a round off:
|
|
* 7.8 round up to 8; 7.4 round down to 7.
|
|
* 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;
|
|
delay = (delay + 5) / 10;
|
|
|
|
|
|
hw->sample_delay_factor = delay;
|
|
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_set_features(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_get_features(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->parameters.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;
|
|
struct resources *r = &this->resources;
|
|
void __iomem *gpmi_regs = r->gpmi_regs;
|
|
void __iomem *gpmi_regs = r->gpmi_regs;
|
|
unsigned int clock_period_in_ns;
|
|
unsigned int clock_period_in_ns;
|
|
uint32_t reg;
|
|
uint32_t reg;
|
|
unsigned int dll_wait_time_in_us;
|
|
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 */
|
|
/* [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);
|
|
writel(reg, gpmi_regs + HW_GPMI_TIMING0);
|
|
|
|
|
|
/* [2] Set HW_GPMI_TIMING1 */
|
|
/* [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. */
|
|
/* [3] The following code is to set the HW_GPMI_CTRL1. */
|
|
|
|
|
|
/* Set the WRN_DLY_SEL */
|
|
/* Set the WRN_DLY_SEL */
|
|
writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
|
|
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. */
|
|
/* 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);
|
|
writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
|
|
@@ -1041,12 +890,12 @@ void gpmi_begin(struct gpmi_nand_data *this)
|
|
writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
|
|
writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
|
|
|
|
|
|
/* If no sample delay is called for, return immediately. */
|
|
/* If no sample delay is called for, return immediately. */
|
|
- if (!hw.sample_delay_factor)
|
|
|
|
|
|
+ if (!hw->sample_delay_factor)
|
|
return;
|
|
return;
|
|
|
|
|
|
/* Set RDN_DELAY or HALF_PERIOD. */
|
|
/* 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);
|
|
writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
|
|
|
|
|
|
@@ -1058,7 +907,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
|
|
* we can use the GPMI. Calculate the amount of time we need to wait,
|
|
* we can use the GPMI. Calculate the amount of time we need to wait,
|
|
* in microseconds.
|
|
* 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;
|
|
dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
|
|
|
|
|
|
if (!dll_wait_time_in_us)
|
|
if (!dll_wait_time_in_us)
|
|
@@ -1066,14 +915,45 @@ void gpmi_begin(struct gpmi_nand_data *this)
|
|
|
|
|
|
/* Wait for the DLL to settle. */
|
|
/* Wait for the DLL to settle. */
|
|
udelay(dll_wait_time_in_us);
|
|
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. */
|
|
/* Clears a BCH interrupt. */
|