mirror of https://github.com/torvalds/linux.git
mtd: rawnand: cadence: Add support for NV-DDR interface mode
Add support for NV-DDR mode in the Cadence NAND controller driver. Signed-off-by: Niravkumar L Rabara <niravkumarlaxmidas.rabara@altera.com> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
parent
050553c683
commit
bf425fa103
|
|
@ -199,6 +199,7 @@
|
||||||
|
|
||||||
/* Common settings. */
|
/* Common settings. */
|
||||||
#define COMMON_SET 0x1008
|
#define COMMON_SET 0x1008
|
||||||
|
#define OPR_MODE_NVDDR BIT(0)
|
||||||
/* 16 bit device connected to the NAND Flash interface. */
|
/* 16 bit device connected to the NAND Flash interface. */
|
||||||
#define COMMON_SET_DEVICE_16BIT BIT(8)
|
#define COMMON_SET_DEVICE_16BIT BIT(8)
|
||||||
|
|
||||||
|
|
@ -211,12 +212,20 @@
|
||||||
#define SKIP_BYTES_OFFSET_VALUE GENMASK(23, 0)
|
#define SKIP_BYTES_OFFSET_VALUE GENMASK(23, 0)
|
||||||
|
|
||||||
/* Timings configuration. */
|
/* Timings configuration. */
|
||||||
|
#define TOGGLE_TIMINGS_0 0x1014
|
||||||
|
#define TOGGLE_TIMINGS_1 0x1018
|
||||||
|
|
||||||
#define ASYNC_TOGGLE_TIMINGS 0x101c
|
#define ASYNC_TOGGLE_TIMINGS 0x101c
|
||||||
#define ASYNC_TOGGLE_TIMINGS_TRH GENMASK(28, 24)
|
#define ASYNC_TOGGLE_TIMINGS_TRH GENMASK(28, 24)
|
||||||
#define ASYNC_TOGGLE_TIMINGS_TRP GENMASK(20, 16)
|
#define ASYNC_TOGGLE_TIMINGS_TRP GENMASK(20, 16)
|
||||||
#define ASYNC_TOGGLE_TIMINGS_TWH GENMASK(12, 8)
|
#define ASYNC_TOGGLE_TIMINGS_TWH GENMASK(12, 8)
|
||||||
#define ASYNC_TOGGLE_TIMINGS_TWP GENMASK(4, 0)
|
#define ASYNC_TOGGLE_TIMINGS_TWP GENMASK(4, 0)
|
||||||
|
|
||||||
|
#define SYNC_TIMINGS 0x1020
|
||||||
|
#define SYNC_TCKWR GENMASK(21, 16)
|
||||||
|
#define SYNC_TWRCK GENMASK(13, 8)
|
||||||
|
#define SYNC_TCAD GENMASK(5, 0)
|
||||||
|
|
||||||
#define TIMINGS0 0x1024
|
#define TIMINGS0 0x1024
|
||||||
#define TIMINGS0_TADL GENMASK(31, 24)
|
#define TIMINGS0_TADL GENMASK(31, 24)
|
||||||
#define TIMINGS0_TCCS GENMASK(23, 16)
|
#define TIMINGS0_TCCS GENMASK(23, 16)
|
||||||
|
|
@ -226,6 +235,7 @@
|
||||||
#define TIMINGS1 0x1028
|
#define TIMINGS1 0x1028
|
||||||
#define TIMINGS1_TRHZ GENMASK(31, 24)
|
#define TIMINGS1_TRHZ GENMASK(31, 24)
|
||||||
#define TIMINGS1_TWB GENMASK(23, 16)
|
#define TIMINGS1_TWB GENMASK(23, 16)
|
||||||
|
#define TIMINGS1_TCWAW GENMASK(15, 8)
|
||||||
#define TIMINGS1_TVDLY GENMASK(7, 0)
|
#define TIMINGS1_TVDLY GENMASK(7, 0)
|
||||||
|
|
||||||
#define TIMINGS2 0x102c
|
#define TIMINGS2 0x102c
|
||||||
|
|
@ -243,14 +253,23 @@
|
||||||
|
|
||||||
/* Register controlling DQ related timing. */
|
/* Register controlling DQ related timing. */
|
||||||
#define PHY_DQ_TIMING 0x2000
|
#define PHY_DQ_TIMING 0x2000
|
||||||
|
#define PHY_DQ_TIMING_OE_END GENMASK(2, 0)
|
||||||
|
#define PHY_DQ_TIMING_OE_START GENMASK(6, 4)
|
||||||
|
#define PHY_DQ_TIMING_TSEL_END GENMASK(11, 8)
|
||||||
|
#define PHY_DQ_TIMING_TSEL_START GENMASK(15, 12)
|
||||||
|
|
||||||
/* Register controlling DSQ related timing. */
|
/* Register controlling DSQ related timing. */
|
||||||
#define PHY_DQS_TIMING 0x2004
|
#define PHY_DQS_TIMING 0x2004
|
||||||
#define PHY_DQS_TIMING_DQS_SEL_OE_END GENMASK(3, 0)
|
#define PHY_DQS_TIMING_DQS_SEL_OE_END GENMASK(3, 0)
|
||||||
|
#define PHY_DQS_TIMING_DQS_SEL_OE_START GENMASK(7, 4)
|
||||||
|
#define PHY_DQS_TIMING_DQS_SEL_TSEL_END GENMASK(11, 8)
|
||||||
#define PHY_DQS_TIMING_PHONY_DQS_SEL BIT(16)
|
#define PHY_DQS_TIMING_PHONY_DQS_SEL BIT(16)
|
||||||
#define PHY_DQS_TIMING_USE_PHONY_DQS BIT(20)
|
#define PHY_DQS_TIMING_USE_PHONY_DQS BIT(20)
|
||||||
|
|
||||||
/* Register controlling the gate and loopback control related timing. */
|
/* Register controlling the gate and loopback control related timing. */
|
||||||
#define PHY_GATE_LPBK_CTRL 0x2008
|
#define PHY_GATE_LPBK_CTRL 0x2008
|
||||||
|
#define PHY_GATE_LPBK_CTRL_GATE_CFG GENMASK(3, 0)
|
||||||
|
#define PHY_GATE_LPBK_CTRL_GATE_CFG_CLOSE GENMASK(5, 4)
|
||||||
#define PHY_GATE_LPBK_CTRL_RDS GENMASK(24, 19)
|
#define PHY_GATE_LPBK_CTRL_RDS GENMASK(24, 19)
|
||||||
|
|
||||||
/* Register holds the control for the master DLL logic. */
|
/* Register holds the control for the master DLL logic. */
|
||||||
|
|
@ -260,6 +279,12 @@
|
||||||
/* Register holds the control for the slave DLL logic. */
|
/* Register holds the control for the slave DLL logic. */
|
||||||
#define PHY_DLL_SLAVE_CTRL 0x2010
|
#define PHY_DLL_SLAVE_CTRL 0x2010
|
||||||
|
|
||||||
|
/* Register controls the DQS related timing. */
|
||||||
|
#define PHY_IE_TIMING 0x2014
|
||||||
|
#define PHY_IE_TIMING_DQS_IE_START GENMASK(10, 8)
|
||||||
|
#define PHY_IE_TIMING_DQ_IE_START GENMASK(18, 16)
|
||||||
|
#define PHY_IE_TIMING_IE_ALWAYS_ON BIT(20)
|
||||||
|
|
||||||
/* This register handles the global control settings for the PHY. */
|
/* This register handles the global control settings for the PHY. */
|
||||||
#define PHY_CTRL 0x2080
|
#define PHY_CTRL 0x2080
|
||||||
#define PHY_CTRL_SDR_DQS BIT(14)
|
#define PHY_CTRL_SDR_DQS BIT(14)
|
||||||
|
|
@ -375,15 +400,41 @@
|
||||||
#define BCH_MAX_NUM_CORR_CAPS 8
|
#define BCH_MAX_NUM_CORR_CAPS 8
|
||||||
#define BCH_MAX_NUM_SECTOR_SIZES 2
|
#define BCH_MAX_NUM_SECTOR_SIZES 2
|
||||||
|
|
||||||
|
/* NVDDR mode specific parameters and register values based on cadence specs */
|
||||||
|
#define NVDDR_PHY_RD_DELAY 29
|
||||||
|
#define NVDDR_PHY_RD_DELAY_MAX 31
|
||||||
|
#define NVDDR_GATE_CFG_OPT 14
|
||||||
|
#define NVDDR_GATE_CFG_STD 7
|
||||||
|
#define NVDDR_GATE_CFG_MAX 15
|
||||||
|
#define NVDDR_DATA_SEL_OE_START 1
|
||||||
|
#define NVDDR_DATA_SEL_OE_START_MAX 7
|
||||||
|
#define NVDDR_DATA_SEL_OE_END 6
|
||||||
|
#define NVDDR_DATA_SEL_OE_END_MIN 4
|
||||||
|
#define NVDDR_DATA_SEL_OE_END_MAX 15
|
||||||
|
#define NVDDR_RS_HIGH_WAIT_CNT 7
|
||||||
|
#define NVDDR_RS_IDLE_CNT 7
|
||||||
|
#define NVDDR_TCWAW_DELAY 250000
|
||||||
|
#define NVDDR_TVDLY_DELAY 500000
|
||||||
|
#define NVDDR_TOGGLE_TIMINGS_0 0x00000301
|
||||||
|
#define NVDDR_TOGGLE_TIMINGS_1 0x0a060102
|
||||||
|
#define NVDDR_ASYNC_TOGGLE_TIMINGS 0
|
||||||
|
#define NVDDR_PHY_CTRL 0x00004000
|
||||||
|
#define NVDDR_PHY_TSEL 0
|
||||||
|
#define NVDDR_PHY_DLL_MASTER_CTRL 0x00140004
|
||||||
|
#define NVDDR_PHY_DLL_SLAVE_CTRL 0x00003c3c
|
||||||
|
|
||||||
struct cadence_nand_timings {
|
struct cadence_nand_timings {
|
||||||
u32 async_toggle_timings;
|
u32 async_toggle_timings;
|
||||||
|
u32 sync_timings;
|
||||||
u32 timings0;
|
u32 timings0;
|
||||||
u32 timings1;
|
u32 timings1;
|
||||||
u32 timings2;
|
u32 timings2;
|
||||||
u32 dll_phy_ctrl;
|
u32 dll_phy_ctrl;
|
||||||
u32 phy_ctrl;
|
u32 phy_ctrl;
|
||||||
|
u32 phy_dq_timing;
|
||||||
u32 phy_dqs_timing;
|
u32 phy_dqs_timing;
|
||||||
u32 phy_gate_lpbk_ctrl;
|
u32 phy_gate_lpbk_ctrl;
|
||||||
|
u32 phy_ie_timing;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Command DMA descriptor. */
|
/* Command DMA descriptor. */
|
||||||
|
|
@ -2345,11 +2396,9 @@ static inline u32 calc_tdvw(u32 trp_cnt, u32 clk_period, u32 trhoh_min,
|
||||||
return (trp_cnt + 1) * clk_period + trhoh_min - trea_max;
|
return (trp_cnt + 1) * clk_period + trhoh_min - trea_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cadence_nand_setup_sdr_interface(struct nand_chip *chip,
|
||||||
cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
|
const struct nand_sdr_timings *sdr)
|
||||||
const struct nand_interface_config *conf)
|
|
||||||
{
|
{
|
||||||
const struct nand_sdr_timings *sdr;
|
|
||||||
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
|
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
|
||||||
struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
|
struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
|
||||||
struct cadence_nand_timings *t = &cdns_chip->timings;
|
struct cadence_nand_timings *t = &cdns_chip->timings;
|
||||||
|
|
@ -2370,13 +2419,8 @@ cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
|
||||||
u32 dll_phy_dqs_timing = 0, phony_dqs_timing = 0, rd_del_sel = 0;
|
u32 dll_phy_dqs_timing = 0, phony_dqs_timing = 0, rd_del_sel = 0;
|
||||||
u32 sampling_point;
|
u32 sampling_point;
|
||||||
|
|
||||||
sdr = nand_get_sdr_timings(conf);
|
|
||||||
if (IS_ERR(sdr))
|
|
||||||
return PTR_ERR(sdr);
|
|
||||||
|
|
||||||
memset(t, 0, sizeof(*t));
|
memset(t, 0, sizeof(*t));
|
||||||
/* Sampling point calculation. */
|
/* Sampling point calculation. */
|
||||||
|
|
||||||
if (cdns_ctrl->caps2.is_phy_type_dll)
|
if (cdns_ctrl->caps2.is_phy_type_dll)
|
||||||
phony_dqs_mod = 2;
|
phony_dqs_mod = 2;
|
||||||
else
|
else
|
||||||
|
|
@ -2633,10 +2677,221 @@ cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
|
||||||
PHY_DLL_MASTER_CTRL_BYPASS_MODE);
|
PHY_DLL_MASTER_CTRL_BYPASS_MODE);
|
||||||
dev_dbg(cdns_ctrl->dev, "PHY_DLL_SLAVE_CTRL_REG_SDR\t%x\n", 0);
|
dev_dbg(cdns_ctrl->dev, "PHY_DLL_SLAVE_CTRL_REG_SDR\t%x\n", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cadence_nand_setup_nvddr_interface(struct nand_chip *chip,
|
||||||
|
const struct nand_nvddr_timings *nvddr)
|
||||||
|
{
|
||||||
|
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
|
||||||
|
struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
|
||||||
|
struct cadence_nand_timings *t = &cdns_chip->timings;
|
||||||
|
u32 board_delay = cdns_ctrl->board_delay;
|
||||||
|
u32 clk_period = DIV_ROUND_DOWN_ULL(1000000000000ULL,
|
||||||
|
cdns_ctrl->nf_clk_rate);
|
||||||
|
u32 ddr_clk_ctrl_period = clk_period * 2;
|
||||||
|
u32 if_skew = cdns_ctrl->caps1->if_skew;
|
||||||
|
u32 tceh_cnt, tcs_cnt, tadl_cnt, tccs_cnt;
|
||||||
|
u32 twrck_cnt, tcad_cnt, tckwr_cnt = 0;
|
||||||
|
u32 tfeat_cnt, trhz_cnt, tvdly_cnt, tcwaw_cnt;
|
||||||
|
u32 trhw_cnt, twb_cnt, twhr_cnt;
|
||||||
|
u32 oe_start, oe_end, oe_end_dqsd;
|
||||||
|
u32 rd_del_sel = 0;
|
||||||
|
u32 dqs_driven_by_device, dqs_toogle_by_device, gate_open_delay;
|
||||||
|
u32 dll_phy_gate_open_delay, gate_close_delay, ie_start;
|
||||||
|
u32 dll_phy_rd_delay;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
memset(t, 0, sizeof(*t));
|
||||||
|
twrck_cnt = calc_cycl(nvddr->tWRCK_min, ddr_clk_ctrl_period);
|
||||||
|
tcad_cnt = calc_cycl(nvddr->tCAD_min, ddr_clk_ctrl_period);
|
||||||
|
|
||||||
|
reg = FIELD_PREP(SYNC_TWRCK, twrck_cnt);
|
||||||
|
reg |= FIELD_PREP(SYNC_TCAD, tcad_cnt);
|
||||||
|
t->sync_timings = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "SYNC_TIMINGS_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
tadl_cnt = calc_cycl((nvddr->tADL_min + if_skew), ddr_clk_ctrl_period);
|
||||||
|
tccs_cnt = calc_cycl((nvddr->tCCS_min + if_skew), ddr_clk_ctrl_period);
|
||||||
|
twhr_cnt = calc_cycl((nvddr->tWHR_min + if_skew), ddr_clk_ctrl_period);
|
||||||
|
trhw_cnt = calc_cycl((nvddr->tRHW_min + if_skew), ddr_clk_ctrl_period);
|
||||||
|
reg = FIELD_PREP(TIMINGS0_TADL, tadl_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS0_TCCS, tccs_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS0_TWHR, twhr_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS0_TRHW, trhw_cnt);
|
||||||
|
t->timings0 = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "TIMINGS0_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
twb_cnt = calc_cycl((nvddr->tWB_max + board_delay),
|
||||||
|
ddr_clk_ctrl_period);
|
||||||
|
/*
|
||||||
|
* Because of the two stage syncflop the value must be increased by 3
|
||||||
|
* first value is related with sync, second value is related
|
||||||
|
* with output if delay.
|
||||||
|
*/
|
||||||
|
twb_cnt = twb_cnt + 3 + 5;
|
||||||
|
tvdly_cnt = calc_cycl(NVDDR_TVDLY_DELAY + if_skew, ddr_clk_ctrl_period);
|
||||||
|
tcwaw_cnt = calc_cycl(NVDDR_TCWAW_DELAY, ddr_clk_ctrl_period);
|
||||||
|
trhz_cnt = 1;
|
||||||
|
reg = FIELD_PREP(TIMINGS1_TWB, twb_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS1_TVDLY, tvdly_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS1_TRHZ, trhz_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS1_TCWAW, tcwaw_cnt);
|
||||||
|
t->timings1 = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "TIMINGS1_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
tfeat_cnt = calc_cycl(nvddr->tFEAT_max, ddr_clk_ctrl_period);
|
||||||
|
if (tfeat_cnt < twb_cnt)
|
||||||
|
tfeat_cnt = twb_cnt;
|
||||||
|
|
||||||
|
tceh_cnt = calc_cycl(nvddr->tCEH_min, ddr_clk_ctrl_period);
|
||||||
|
tcs_cnt = calc_cycl((nvddr->tCS_min + if_skew), ddr_clk_ctrl_period);
|
||||||
|
reg = FIELD_PREP(TIMINGS2_TFEAT, tfeat_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS2_CS_HOLD_TIME, tceh_cnt);
|
||||||
|
reg |= FIELD_PREP(TIMINGS2_CS_SETUP_TIME, tcs_cnt);
|
||||||
|
t->timings2 = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "TIMINGS2_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
reg = FIELD_PREP(DLL_PHY_CTRL_RS_HIGH_WAIT_CNT, NVDDR_RS_HIGH_WAIT_CNT);
|
||||||
|
reg |= FIELD_PREP(DLL_PHY_CTRL_RS_IDLE_CNT, NVDDR_RS_IDLE_CNT);
|
||||||
|
t->dll_phy_ctrl = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "DLL_PHY_CTRL_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
reg = PHY_CTRL_SDR_DQS;
|
||||||
|
t->phy_ctrl = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "PHY_CTRL_REG_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
dqs_driven_by_device = (nvddr->tDQSD_max + board_delay) / 1000 +
|
||||||
|
if_skew;
|
||||||
|
dqs_toogle_by_device = (nvddr->tDQSCK_max + board_delay) / 1000 -
|
||||||
|
if_skew;
|
||||||
|
gate_open_delay = dqs_toogle_by_device / (clk_period / 1000);
|
||||||
|
if (dqs_toogle_by_device > clk_period / 1000) {
|
||||||
|
if (gate_open_delay > NVDDR_GATE_CFG_OPT)
|
||||||
|
dll_phy_gate_open_delay = NVDDR_GATE_CFG_MAX;
|
||||||
|
else
|
||||||
|
dll_phy_gate_open_delay = gate_open_delay + 1;
|
||||||
|
gate_close_delay = 0;
|
||||||
|
} else {
|
||||||
|
twrck_cnt = calc_cycl(dqs_driven_by_device * 1000, clk_period);
|
||||||
|
dll_phy_gate_open_delay = 1;
|
||||||
|
gate_close_delay = 0;
|
||||||
|
|
||||||
|
reg = FIELD_PREP(SYNC_TCKWR, tckwr_cnt);
|
||||||
|
reg |= FIELD_PREP(SYNC_TWRCK, twrck_cnt);
|
||||||
|
reg |= FIELD_PREP(SYNC_TCAD, tcad_cnt);
|
||||||
|
t->sync_timings = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "SYNC_TIMINGS_NVDDR\t%08x\n", reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dll_phy_gate_open_delay > NVDDR_GATE_CFG_STD)
|
||||||
|
ie_start = NVDDR_GATE_CFG_STD;
|
||||||
|
else
|
||||||
|
ie_start = dll_phy_gate_open_delay;
|
||||||
|
|
||||||
|
dll_phy_rd_delay = ((nvddr->tDQSCK_max + board_delay) +
|
||||||
|
(clk_period / 2)) / clk_period;
|
||||||
|
if (dll_phy_rd_delay <= NVDDR_PHY_RD_DELAY)
|
||||||
|
rd_del_sel = dll_phy_rd_delay + 2;
|
||||||
|
else
|
||||||
|
rd_del_sel = NVDDR_PHY_RD_DELAY_MAX;
|
||||||
|
|
||||||
|
reg = FIELD_PREP(PHY_GATE_LPBK_CTRL_GATE_CFG, dll_phy_gate_open_delay);
|
||||||
|
reg |= FIELD_PREP(PHY_GATE_LPBK_CTRL_GATE_CFG_CLOSE, gate_close_delay);
|
||||||
|
reg |= FIELD_PREP(PHY_GATE_LPBK_CTRL_RDS, rd_del_sel);
|
||||||
|
t->phy_gate_lpbk_ctrl = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "PHY_GATE_LPBK_CTRL_REG_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
oe_end_dqsd = ((nvddr->tDQSD_max / 1000) / ((clk_period / 2) / 1000))
|
||||||
|
+ NVDDR_DATA_SEL_OE_END_MIN;
|
||||||
|
oe_end = (NVDDR_DATA_SEL_OE_END_MIN + oe_end_dqsd) / 2;
|
||||||
|
if (oe_end > NVDDR_DATA_SEL_OE_END_MAX)
|
||||||
|
oe_end = NVDDR_DATA_SEL_OE_END_MAX;
|
||||||
|
|
||||||
|
oe_start = ((nvddr->tDQSHZ_max / 1000) / ((clk_period / 2) / 1000)) + 1;
|
||||||
|
if (oe_start > NVDDR_DATA_SEL_OE_START_MAX)
|
||||||
|
oe_start = NVDDR_DATA_SEL_OE_START_MAX;
|
||||||
|
|
||||||
|
reg = FIELD_PREP(PHY_DQ_TIMING_OE_END, NVDDR_DATA_SEL_OE_END);
|
||||||
|
reg |= FIELD_PREP(PHY_DQ_TIMING_OE_START, NVDDR_DATA_SEL_OE_START);
|
||||||
|
reg |= FIELD_PREP(PHY_DQ_TIMING_TSEL_END, NVDDR_DATA_SEL_OE_END);
|
||||||
|
reg |= FIELD_PREP(PHY_DQ_TIMING_TSEL_START, NVDDR_DATA_SEL_OE_START);
|
||||||
|
t->phy_dq_timing = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "PHY_DQ_TIMING_REG_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
reg = FIELD_PREP(PHY_DQS_TIMING_DQS_SEL_OE_END, oe_end);
|
||||||
|
reg |= FIELD_PREP(PHY_DQS_TIMING_DQS_SEL_OE_START, oe_start);
|
||||||
|
reg |= FIELD_PREP(PHY_DQS_TIMING_DQS_SEL_TSEL_END, oe_end);
|
||||||
|
t->phy_dqs_timing = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "PHY_DQS_TIMING_REG_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
reg = FIELD_PREP(PHY_IE_TIMING_DQS_IE_START, ie_start);
|
||||||
|
reg |= FIELD_PREP(PHY_IE_TIMING_DQ_IE_START, ie_start);
|
||||||
|
reg |= FIELD_PREP(PHY_IE_TIMING_IE_ALWAYS_ON, 0);
|
||||||
|
t->phy_ie_timing = reg;
|
||||||
|
dev_dbg(cdns_ctrl->dev, "PHY_IE_TIMING_REG_NVDDR\t%08x\n", reg);
|
||||||
|
|
||||||
|
reg = readl_relaxed(cdns_ctrl->reg + DLL_PHY_CTRL);
|
||||||
|
reg &= ~(DLL_PHY_CTRL_DLL_RST_N |
|
||||||
|
DLL_PHY_CTRL_EXTENDED_RD_MODE |
|
||||||
|
DLL_PHY_CTRL_EXTENDED_WR_MODE);
|
||||||
|
writel_relaxed(reg, cdns_ctrl->reg + DLL_PHY_CTRL);
|
||||||
|
writel_relaxed(OPR_MODE_NVDDR, cdns_ctrl->reg + COMMON_SET);
|
||||||
|
writel_relaxed(NVDDR_TOGGLE_TIMINGS_0,
|
||||||
|
cdns_ctrl->reg + TOGGLE_TIMINGS_0);
|
||||||
|
writel_relaxed(NVDDR_TOGGLE_TIMINGS_1,
|
||||||
|
cdns_ctrl->reg + TOGGLE_TIMINGS_1);
|
||||||
|
writel_relaxed(NVDDR_ASYNC_TOGGLE_TIMINGS,
|
||||||
|
cdns_ctrl->reg + ASYNC_TOGGLE_TIMINGS);
|
||||||
|
writel_relaxed(t->sync_timings, cdns_ctrl->reg + SYNC_TIMINGS);
|
||||||
|
writel_relaxed(t->timings0, cdns_ctrl->reg + TIMINGS0);
|
||||||
|
writel_relaxed(t->timings1, cdns_ctrl->reg + TIMINGS1);
|
||||||
|
writel_relaxed(t->timings2, cdns_ctrl->reg + TIMINGS2);
|
||||||
|
writel_relaxed(t->dll_phy_ctrl, cdns_ctrl->reg + DLL_PHY_CTRL);
|
||||||
|
writel_relaxed(t->phy_ctrl, cdns_ctrl->reg + PHY_CTRL);
|
||||||
|
writel_relaxed(NVDDR_PHY_TSEL, cdns_ctrl->reg + PHY_TSEL);
|
||||||
|
writel_relaxed(t->phy_dq_timing, cdns_ctrl->reg + PHY_DQ_TIMING);
|
||||||
|
writel_relaxed(t->phy_dqs_timing, cdns_ctrl->reg + PHY_DQS_TIMING);
|
||||||
|
writel_relaxed(t->phy_gate_lpbk_ctrl,
|
||||||
|
cdns_ctrl->reg + PHY_GATE_LPBK_CTRL);
|
||||||
|
writel_relaxed(NVDDR_PHY_DLL_MASTER_CTRL,
|
||||||
|
cdns_ctrl->reg + PHY_DLL_MASTER_CTRL);
|
||||||
|
writel_relaxed(NVDDR_PHY_DLL_SLAVE_CTRL,
|
||||||
|
cdns_ctrl->reg + PHY_DLL_SLAVE_CTRL);
|
||||||
|
writel_relaxed(t->phy_ie_timing, cdns_ctrl->reg + PHY_IE_TIMING);
|
||||||
|
writel_relaxed((reg | DLL_PHY_CTRL_DLL_RST_N),
|
||||||
|
cdns_ctrl->reg + DLL_PHY_CTRL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
|
||||||
|
const struct nand_interface_config *conf)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (chipnr < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (nand_interface_is_sdr(conf)) {
|
||||||
|
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
|
||||||
|
|
||||||
|
if (IS_ERR(sdr))
|
||||||
|
return PTR_ERR(sdr);
|
||||||
|
|
||||||
|
ret = cadence_nand_setup_sdr_interface(chip, sdr);
|
||||||
|
} else {
|
||||||
|
const struct nand_nvddr_timings *nvddr = nand_get_nvddr_timings(conf);
|
||||||
|
|
||||||
|
if (IS_ERR(nvddr))
|
||||||
|
return PTR_ERR(nvddr);
|
||||||
|
|
||||||
|
ret = cadence_nand_setup_nvddr_interface(chip, nvddr);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int cadence_nand_attach_chip(struct nand_chip *chip)
|
static int cadence_nand_attach_chip(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
|
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue