Commit 76e1a008 authored by Miquel Raynal's avatar Miquel Raynal Committed by Boris Brezillon

mtd: rawnand: gpmi: support ->setup_data_interface()

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: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Tested-by: default avatarHan Xu <han.xu@nxp.com>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@bootlin.com>
parent bd0b6434
This diff is collapsed.
......@@ -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;
}
......@@ -1955,14 +1976,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;
}
......@@ -1983,6 +1996,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;
......@@ -2141,7 +2155,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);
......@@ -2155,9 +2168,6 @@ static int gpmi_pm_resume(struct device *dev)
return ret;
}
/* re-init others */
gpmi_extra_init(this);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
......
......@@ -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;
......@@ -204,35 +241,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
......@@ -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 *,
......
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