diff options
| -rw-r--r-- | plat/rockchip/rk3399/drivers/dram/dcf_code.inc | 364 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/drivers/dram/dram.c | 2564 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/drivers/dram/dram.h | 329 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c | 1323 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h | 538 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/drivers/soc/soc.h | 37 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/plat_sip_calls.c | 38 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/platform.mk | 5 | ||||
| -rw-r--r-- | plat/rockchip/rk3399/rk3399_def.h | 23 | 
9 files changed, 5220 insertions, 1 deletions
| diff --git a/plat/rockchip/rk3399/drivers/dram/dcf_code.inc b/plat/rockchip/rk3399/drivers/dram/dcf_code.inc new file mode 100644 index 00000000..53196a02 --- /dev/null +++ b/plat/rockchip/rk3399/drivers/dram/dcf_code.inc @@ -0,0 +1,364 @@ +    0x0 , +    0x4f8c120c , +    0x0 , +    0x4f8c1210 , +    0x100000 , +    0x1f310019 , +    0x0 , +    0xb0000001 , +    0x58 , +    0xd0000000 , +    0x1300 , +    0x1f760329 , +    0x0 , +    0xb0000001 , +    0x40 , +    0xd0000000 , +    0xc , +    0x1f760371 , +    0x0 , +    0xb0000001 , +    0x28 , +    0xd0000000 , +    0x400000 , +    0x1f900009 , +    0x0 , +    0xb0000001 , +    0x10 , +    0xd0000000 , +    0x1 , +    0x4f8c120c , +    0x100000 , +    0x1f310019 , +    0x0 , +    0xb0000001 , +    0x58 , +    0xd0000000 , +    0x2c00 , +    0x1f760329 , +    0x0 , +    0xb0000001 , +    0x40 , +    0xd0000000 , +    0xc0 , +    0x1f760371 , +    0x0 , +    0xb0000001 , +    0x28 , +    0xd0000000 , +    0x400000 , +    0x1f8f0009 , +    0x0 , +    0xb0000001 , +    0x10 , +    0xd0000000 , +    0x1 , +    0x4f8c1210 , +    0x0 , +    0x4f8c1220 , +    0x0 , +    0x4f8c121c , +    0x0 , +    0xaf8c120d , +    0x108 , +    0xd0000000 , +    0x2000 , +    0x1f900009 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x0 , +    0x4f8c1220 , +    0x0 , +    0x4f8c121c , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0xb0 , +    0xd0000000 , +    0x8000 , +    0x1f900009 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x1 , +    0x4f8c1220 , +    0x1 , +    0x4f8c121c , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0x70 , +    0xd0000000 , +    0x4000 , +    0x1f900009 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x0 , +    0x4f8c1220 , +    0x1 , +    0x4f8c121c , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x1000 , +    0x1f900009 , +    0x0 , +    0xa0000001 , +    0x18 , +    0xd0000000 , +    0x0 , +    0x4f8c1220 , +    0x1 , +    0x4f8c121c , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0x100 , +    0xd0000000 , +    0x0 , +    0xaf8c1211 , +    0xf0 , +    0xd0000000 , +    0x2000 , +    0x1f8f0009 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x0 , +    0x4f8c1220 , +    0x0 , +    0x4f8c121c , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0xb0 , +    0xd0000000 , +    0x8000 , +    0x1f8f0009 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x1 , +    0x4f8c1220 , +    0x1 , +    0x4f8c121c , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0x70 , +    0xd0000000 , +    0x4000 , +    0x1f8f0009 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x0 , +    0x4f8c1220 , +    0x1 , +    0x4f8c121c , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0x30 , +    0xd0000000 , +    0x1000 , +    0x1f8f0009 , +    0x0 , +    0xa0000001 , +    0x18 , +    0xd0000000 , +    0x0 , +    0x4f8c1220 , +    0x1 , +    0x4f8c121c , +    0x0 , +    0xaf8c120d , +    0x40 , +    0xd0000000 , +    0x80008000 , +    0x7f900284 , +    0x1 , +    0x0 , +    0x8000 , +    0x1f90028d , +    0x0 , +    0x60000001 , +    0x0 , +    0x10000001 , +    0x0 , +    0xa0000001 , +    0x38 , +    0xd0000000 , +    0x0 , +    0xaf8c1211 , +    0x28 , +    0xd0000000 , +    0x80008000 , +    0x7f8f0284 , +    0x1 , +    0x0 , +    0x8000 , +    0x1f8f028d , +    0x0 , +    0x60000001 , +    0xffffffff , +    0x4f77e200 , +    0xffffffff , +    0x4f77e204 , +    0xffffffff , +    0x4f77e208 , +    0xffffffff , +    0x4f77e20c , +    0x70007000 , +    0x4f77e210 , +    0x3fffffff , +    0x7f750130 , +    0x0 , +    0x2f310061 , +    0xc0000 , +    0x20000001 , +    0x0 , +    0x4f310061 , +    0xc0000 , +    0x1f310065 , +    0xc0000 , +    0xb0000001 , +    0x10 , +    0xc0000000 , +    0x0 , +    0xaf8c121d , +    0x48 , +    0xd0000000 , +    0x0 , +    0xaf8c120d , +    0x18 , +    0xd0000000 , +    0x80000000 , +    0x2f90000d , +    0x0 , +    0x4f90000d , +    0x0 , +    0xaf8c1211 , +    0x18 , +    0xd0000000 , +    0x80000000 , +    0x2f90000d , +    0x0 , +    0x4f8f000d , +    0x0 , +    0x2f8c101d , +    0x350005 , +    0x20000001 , +    0x0 , +    0x4f620001 , +    0x1 , +    0x0 , +    0x4 , +    0x1f620011 , +    0x0 , +    0x60000001 , +    0x3000000 , +    0x7f76004c , +    0x18 , +    0x0 , +    0x10001 , +    0x7f76004c , +    0x0 , +    0x2f8c1005 , +    0x0 , +    0x4f760041 , +    0x0 , +    0x2f8c1009 , +    0x0 , +    0x4f760045 , +    0x10000 , +    0x7f76004c , +    0x18 , +    0x0 , +    0x1 , +    0x0 , +    0x80000000 , +    0x1f760049 , +    0x0 , +    0x60000001 , +    0x3000100 , +    0x7f76004c , +    0x3e8 , +    0x0 , +    0x20002 , +    0x4f620000 , +    0x1 , +    0x0 , +    0x1 , +    0x1f620011 , +    0x0 , +    0x60000001 , +    0x0 , +    0xaf8c121d , +    0x48 , +    0xd0000000 , +    0x0 , +    0xaf8c120d , +    0x18 , +    0xd0000000 , +    0x7fffffff , +    0x1f90000d , +    0x0 , +    0x4f90000d , +    0x0 , +    0xaf8c1211 , +    0x18 , +    0xd0000000 , +    0x7fffffff , +    0x1f90000d , +    0x0 , +    0x4f8f000d , +    0xfff3ffff , +    0x1f310061 , +    0x0 , +    0x7f310061 , +    0xc0000 , +    0x1f310065 , +    0x0 , +    0xb0000001 , +    0x10 , +    0xc0000000 , +    0x0 , +    0x7f750130 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x1 , +    0x0 , +    0x0 , +    0xe0000000 , diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c new file mode 100644 index 00000000..ddae84d3 --- /dev/null +++ b/plat/rockchip/rk3399/drivers/dram/dram.c @@ -0,0 +1,2564 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <debug.h> +#include <mmio.h> +#include <plat_private.h> +#include "dram.h" +#include "dram_spec_timing.h" +#include "string.h" +#include "soc.h" +#include "pmu.h" + +#include <delay_timer.h> + +#define CTL_TRAINING	(1) +#define PI_TRAINING		(!CTL_TRAINING) + +#define EN_READ_GATE_TRAINING	(1) +#define EN_CA_TRAINING		(0) +#define EN_WRITE_LEVELING	(0) +#define EN_READ_LEVELING	(0) +#define EN_WDQ_LEVELING	(0) + +#define ENPER_CS_TRAINING_FREQ	(933) + +struct pll_div { +	unsigned int mhz; +	unsigned int refdiv; +	unsigned int fbdiv; +	unsigned int postdiv1; +	unsigned int postdiv2; +	unsigned int frac; +	unsigned int freq; +}; + +static const struct pll_div dpll_rates_table[] = { + +	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */ +	{.mhz = 933, .refdiv = 3, .fbdiv = 350, .postdiv1 = 3, .postdiv2 = 1}, +	{.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1}, +	{.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1}, +	{.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1}, +	{.mhz = 600, .refdiv = 1, .fbdiv = 50, .postdiv1 = 2, .postdiv2 = 1}, +	{.mhz = 528, .refdiv = 1, .fbdiv = 66, .postdiv1 = 3, .postdiv2 = 1}, +	{.mhz = 400, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1}, +	{.mhz = 300, .refdiv = 1, .fbdiv = 50, .postdiv1 = 4, .postdiv2 = 1}, +	{.mhz = 200, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 2}, +}; + +static struct rk3399_ddr_cic_regs *const rk3399_ddr_cic = (void *)CIC_BASE; +static struct rk3399_ddr_pctl_regs *const rk3399_ddr_pctl[2] = { +	(void *)DDRC0_BASE, (void *)DDRC1_BASE +}; + +static struct rk3399_ddr_pi_regs *const rk3399_ddr_pi[2] = { +	(void *)DDRC0_PI_BASE, (void *)DDRC1_PI_BASE +}; + +static struct rk3399_ddr_publ_regs *const rk3399_ddr_publ[2] = { +	(void *)DDRC0_PHY_BASE, (void *)DDRC1_PHY_BASE +}; + +struct rk3399_dram_status { +	uint32_t current_index; +	uint32_t index_freq[2]; +	uint32_t low_power_stat; +	struct timing_related_config timing_config; +	struct drv_odt_lp_config drv_odt_lp_cfg; +}; + +static struct rk3399_dram_status rk3399_dram_status; +static struct ddr_dts_config_timing dts_parameter = { +	.available = 0 +}; + +static struct rk3399_sdram_default_config ddr3_default_config = { +	.bl = 8, +	.ap = 0, +	.dramds = 40, +	.dramodt = 120, +	.burst_ref_cnt = 1, +	.zqcsi = 0 +}; + +static struct drv_odt_lp_config ddr3_drv_odt_default_config = { +	.ddr3_speed_bin = DDR3_DEFAULT, +	.pd_idle = 0, +	.sr_idle = 0, +	.sr_mc_gate_idle = 0, +	.srpd_lite_idle = 0, +	.standby_idle = 0, + +	.ddr3_dll_dis_freq = 300, +	.phy_dll_dis_freq = 125, +	.odt_dis_freq = 933, + +	.dram_side_drv = 40, +	.dram_side_dq_odt = 120, +	.dram_side_ca_odt = 120, + +	.phy_side_ca_drv = 40, +	.phy_side_ck_cs_drv = 40, +	.phy_side_dq_drv = 40, +	.phy_side_odt = 240, +}; + +static struct rk3399_sdram_default_config lpddr3_default_config = { +	.bl = 8, +	.ap = 0, +	.dramds = 34, +	.dramodt = 240, +	.burst_ref_cnt = 1, +	.zqcsi = 0 +}; + +static struct drv_odt_lp_config lpddr3_drv_odt_default_config = { +	.ddr3_speed_bin = DDR3_DEFAULT, +	.pd_idle = 0, +	.sr_idle = 0, +	.sr_mc_gate_idle = 0, +	.srpd_lite_idle = 0, +	.standby_idle = 0, + +	.ddr3_dll_dis_freq = 300, +	.phy_dll_dis_freq = 125, +	.odt_dis_freq = 666, + +	.dram_side_drv = 40, +	.dram_side_dq_odt = 120, +	.dram_side_ca_odt = 120, + +	.phy_side_ca_drv = 40, +	.phy_side_ck_cs_drv = 40, +	.phy_side_dq_drv = 40, +	.phy_side_odt = 240, +}; + +static struct rk3399_sdram_default_config lpddr4_default_config = { +	.bl = 16, +	.ap = 0, +	.dramds = 40, +	.dramodt = 240, +	.caodt = 240, +	.burst_ref_cnt = 1, +	.zqcsi = 0 +}; + +static struct drv_odt_lp_config lpddr4_drv_odt_default_config = { +	.ddr3_speed_bin = DDR3_DEFAULT, +	.pd_idle = 0, +	.sr_idle = 0, +	.sr_mc_gate_idle = 0, +	.srpd_lite_idle = 0, +	.standby_idle = 0, + +	.ddr3_dll_dis_freq = 300, +	.phy_dll_dis_freq = 125, +	.odt_dis_freq = 933, + +	.dram_side_drv = 60, +	.dram_side_dq_odt = 40, +	.dram_side_ca_odt = 40, + +	.phy_side_ca_drv = 40, +	.phy_side_ck_cs_drv = 80, +	.phy_side_dq_drv = 80, +	.phy_side_odt = 60, +}; + +uint32_t dcf_code[] = { +#include "dcf_code.inc" +}; + + +#define write_32(addr, value)\ +	mmio_write_32((uintptr_t)(addr), (uint32_t)(value)) + +#define read_32(addr) \ +		mmio_read_32((uintptr_t)(addr)) +#define clrbits_32(addr, clear)\ +		mmio_clrbits_32((uintptr_t)(addr), (uint32_t)(clear)) +#define setbits_32(addr, set)\ +	mmio_setbits_32((uintptr_t)(addr), (uint32_t)(set)) +#define clrsetbits_32(addr, clear, set)\ +	mmio_clrsetbits_32((uintptr_t)(addr), (uint32_t)(clear),\ +					(uint32_t)(set)) + +#define DCF_START_ADDR	(SRAM_BASE + 0x1400) +#define DCF_PARAM_ADDR	(SRAM_BASE + 0x1000) + +/* DCF_PAMET */ +#define PARAM_DRAM_FREQ		(0) +#define PARAM_DPLL_CON0		(4) +#define PARAM_DPLL_CON1		(8) +#define PARAM_DPLL_CON2		(0xc) +#define PARAM_DPLL_CON3		(0x10) +#define PARAM_DPLL_CON4		(0x14) +#define PARAM_DPLL_CON5		(0x18) +/* equal to fn<<4 */ +#define PARAM_FREQ_SELECT	(0x1c) + +static unsigned int get_cs_die_capability(struct rk3399_sdram_config +					  *psdram_config, unsigned int channel, +					  unsigned int cs) +{ +	unsigned int die; +	unsigned int cs_cap; +	unsigned int row[2]; + +	row[0] = psdram_config->ch[channel].cs0_row; +	row[1] = psdram_config->ch[channel].cs1_row; +	die = psdram_config->ch[channel].bus_width / +	    psdram_config->ch[channel].each_die_bus_width; +	cs_cap = (1 << (row[cs] + +			(psdram_config->ch[channel].bank / 4 + 1) + +			psdram_config->ch[channel].col + +			(psdram_config->ch[channel].bus_width / 16))); +	if (psdram_config->ch[channel].each_die_6gb_or_12gb) +		cs_cap = cs_cap * 3 / 4; + +	return (cs_cap / die); +} + +static void sdram_config_init(struct rk3399_sdram_config *psdram_config) +{ +	uint32_t os_reg2_val, i; + +	os_reg2_val = read_32(PMUGRF_BASE + PMUGRF_OSREG(2)); + +	for (i = 0; i < READ_CH_CNT(os_reg2_val); i++) { +		psdram_config->ch[i].bank = 1 << READ_BK_INFO(os_reg2_val, i); +		psdram_config->ch[i].bus_width = +		    8 * (1 << READ_BW_INFO(os_reg2_val, i)); +		psdram_config->ch[i].col = READ_COL_INFO(os_reg2_val, i); +		psdram_config->ch[i].cs0_row = +		    READ_CS0_ROW_INFO(os_reg2_val, i); +		psdram_config->ch[i].cs1_row = +		    READ_CS1_ROW_INFO(os_reg2_val, i); +		psdram_config->ch[i].cs_cnt = READ_CS_INFO(os_reg2_val, i); +		psdram_config->ch[i].each_die_6gb_or_12gb = +		    READ_CH_ROW_INFO(os_reg2_val, i); +		psdram_config->ch[i].each_die_bus_width = +		    8 * (1 << READ_DIE_BW_INFO(os_reg2_val, i)); +	} +	psdram_config->dramtype = READ_DRAMTYPE_INFO(os_reg2_val); +	psdram_config->channal_num = READ_CH_CNT(os_reg2_val); +} + +static void drv_odt_lp_cfg_init(uint32_t dram_type, +				struct ddr_dts_config_timing *dts_timing, +				struct drv_odt_lp_config *drv_config) +{ +	if ((dts_timing) && (dts_timing->available)) { +		drv_config->ddr3_speed_bin = dts_timing->ddr3_speed_bin; +		drv_config->pd_idle = dts_timing->pd_idle; +		drv_config->sr_idle = dts_timing->sr_idle; +		drv_config->sr_mc_gate_idle = dts_timing->sr_mc_gate_idle; +		drv_config->srpd_lite_idle = dts_timing->srpd_lite_idle; +		drv_config->standby_idle = dts_timing->standby_idle; +		drv_config->ddr3_dll_dis_freq = dts_timing->ddr3_dll_dis_freq; +		drv_config->phy_dll_dis_freq = dts_timing->phy_dll_dis_freq; +	} + +	switch (dram_type) { +	case DDR3: +		if ((dts_timing) && (dts_timing->available)) { +			drv_config->odt_dis_freq = +			    dts_timing->ddr3_odt_dis_freq; +			drv_config->dram_side_drv = dts_timing->ddr3_drv; +			drv_config->dram_side_dq_odt = dts_timing->ddr3_odt; +			drv_config->phy_side_ca_drv = +			    dts_timing->phy_ddr3_ca_drv; +			drv_config->phy_side_ck_cs_drv = +			    dts_timing->phy_ddr3_ca_drv; +			drv_config->phy_side_dq_drv = +			    dts_timing->phy_ddr3_dq_drv; +			drv_config->phy_side_odt = dts_timing->phy_ddr3_odt; +		} else { +			memcpy(drv_config, &ddr3_drv_odt_default_config, +			       sizeof(struct drv_odt_lp_config)); +		} +		break; +	case LPDDR3: +		if ((dts_timing) && (dts_timing->available)) { +			drv_config->odt_dis_freq = +			    dts_timing->lpddr3_odt_dis_freq; +			drv_config->dram_side_drv = dts_timing->lpddr3_drv; +			drv_config->dram_side_dq_odt = dts_timing->lpddr3_odt; +			drv_config->phy_side_ca_drv = +			    dts_timing->phy_lpddr3_ca_drv; +			drv_config->phy_side_ck_cs_drv = +			    dts_timing->phy_lpddr3_ca_drv; +			drv_config->phy_side_dq_drv = +			    dts_timing->phy_lpddr3_dq_drv; +			drv_config->phy_side_odt = dts_timing->phy_lpddr3_odt; + +		} else { +			memcpy(drv_config, &lpddr3_drv_odt_default_config, +			       sizeof(struct drv_odt_lp_config)); +		} +		break; +	case LPDDR4: +	default: +		if ((dts_timing) && (dts_timing->available)) { +			drv_config->odt_dis_freq = +			    dts_timing->lpddr4_odt_dis_freq; +			drv_config->dram_side_drv = dts_timing->lpddr4_drv; +			drv_config->dram_side_dq_odt = +			    dts_timing->lpddr4_dq_odt; +			drv_config->dram_side_ca_odt = +			    dts_timing->lpddr4_ca_odt; +			drv_config->phy_side_ca_drv = +			    dts_timing->phy_lpddr4_ca_drv; +			drv_config->phy_side_ck_cs_drv = +			    dts_timing->phy_lpddr4_ck_cs_drv; +			drv_config->phy_side_dq_drv = +			    dts_timing->phy_lpddr4_dq_drv; +			drv_config->phy_side_odt = dts_timing->phy_lpddr4_odt; +		} else { +			memcpy(drv_config, &lpddr4_drv_odt_default_config, +			       sizeof(struct drv_odt_lp_config)); +		} +		break; +	} + +	switch (drv_config->phy_side_ca_drv) { +	case 240: +		drv_config->phy_side_ca_drv = PHY_DRV_ODT_240; +		break; +	case 120: +		drv_config->phy_side_ca_drv = PHY_DRV_ODT_120; +		break; +	case 80: +		drv_config->phy_side_ca_drv = PHY_DRV_ODT_80; +		break; +	case 60: +		drv_config->phy_side_ca_drv = PHY_DRV_ODT_60; +		break; +	case 48: +		drv_config->phy_side_ca_drv = PHY_DRV_ODT_48; +		break; +	case 40: +		drv_config->phy_side_ca_drv = PHY_DRV_ODT_40; +		break; +	default: +		drv_config->phy_side_ca_drv = PHY_DRV_ODT_34_3; +		break; +	}; + +	switch (drv_config->phy_side_ck_cs_drv) { +	case 240: +		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_240; +		break; +	case 120: +		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_120; +		break; +	case 80: +		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_80; +		break; +	case 60: +		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_60; +		break; +	case 48: +		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_48; +		break; +	case 40: +		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_40; +		break; +	default: +		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_34_3; +		break; +	} + +	switch (drv_config->phy_side_dq_drv) { +	case 240: +		drv_config->phy_side_dq_drv = PHY_DRV_ODT_240; +		break; +	case 120: +		drv_config->phy_side_dq_drv = PHY_DRV_ODT_120; +		break; +	case 80: +		drv_config->phy_side_dq_drv = PHY_DRV_ODT_80; +		break; +	case 60: +		drv_config->phy_side_dq_drv = PHY_DRV_ODT_60; +		break; +	case 48: +		drv_config->phy_side_dq_drv = PHY_DRV_ODT_48; +		break; +	case 40: +		drv_config->phy_side_dq_drv = PHY_DRV_ODT_40; +		break; +	default: +		drv_config->phy_side_dq_drv = PHY_DRV_ODT_34_3; +		break; +	} + +	switch (drv_config->phy_side_odt) { +	case 240: +		drv_config->phy_side_odt = PHY_DRV_ODT_240; +		break; +	case 120: +		drv_config->phy_side_odt = PHY_DRV_ODT_120; +		break; +	case 80: +		drv_config->phy_side_odt = PHY_DRV_ODT_80; +		break; +	case 60: +		drv_config->phy_side_odt = PHY_DRV_ODT_60; +		break; +	case 48: +		drv_config->phy_side_odt = PHY_DRV_ODT_48; +		break; +	case 40: +		drv_config->phy_side_odt = PHY_DRV_ODT_40; +		break; +	default: +		drv_config->phy_side_odt = PHY_DRV_ODT_34_3; +		break; +	} +} + +static void sdram_timing_cfg_init(struct timing_related_config *ptiming_config, +				  struct rk3399_sdram_config *psdram_config, +				  struct drv_odt_lp_config *drv_config) +{ +	uint32_t i, j; + +	for (i = 0; i < psdram_config->channal_num; i++) { +		ptiming_config->dram_info[i].speed_rate = +		    drv_config->ddr3_speed_bin; +		ptiming_config->dram_info[i].cs_cnt = +		    psdram_config->ch[i].cs_cnt; +		for (j = 0; j < psdram_config->ch[i].cs_cnt; j++) { +			ptiming_config->dram_info[i].per_die_capability[j] = +			    get_cs_die_capability(psdram_config, i, j); +		} +	} +	ptiming_config->dram_type = psdram_config->dramtype; +	ptiming_config->ch_cnt = psdram_config->channal_num; +	switch (psdram_config->dramtype) { +	case DDR3: +		ptiming_config->bl = ddr3_default_config.bl; +		ptiming_config->ap = ddr3_default_config.ap; +		break; +	case LPDDR3: +		ptiming_config->bl = lpddr3_default_config.bl; +		ptiming_config->ap = lpddr3_default_config.ap; +		break; +	case LPDDR4: +		ptiming_config->bl = lpddr4_default_config.bl; +		ptiming_config->ap = lpddr4_default_config.ap; +		ptiming_config->rdbi = 0; +		ptiming_config->wdbi = 0; +		break; +	} +	ptiming_config->dramds = drv_config->dram_side_drv; +	ptiming_config->dramodt = drv_config->dram_side_dq_odt; +	ptiming_config->caodt = drv_config->dram_side_ca_odt; +} + +struct lat_adj_pair { +	uint32_t cl; +	uint32_t rdlat_adj; +	uint32_t cwl; +	uint32_t wrlat_adj; +}; + +const struct lat_adj_pair ddr3_lat_adj[] = { +	{6, 5, 5, 4}, +	{8, 7, 6, 5}, +	{10, 9, 7, 6}, +	{11, 9, 8, 7}, +	{13, 0xb, 9, 8}, +	{14, 0xb, 0xa, 9} +}; + +const struct lat_adj_pair lpddr3_lat_adj[] = { +	{3, 2, 1, 0}, +	{6, 5, 3, 2}, +	{8, 7, 4, 3}, +	{9, 8, 5, 4}, +	{10, 9, 6, 5}, +	{11, 9, 6, 5}, +	{12, 0xa, 6, 5}, +	{14, 0xc, 8, 7}, +	{16, 0xd, 8, 7} +}; + +const struct lat_adj_pair lpddr4_lat_adj[] = { +	{6, 5, 4, 2}, +	{10, 9, 6, 4}, +	{14, 0xc, 8, 6}, +	{20, 0x11, 0xa, 8}, +	{24, 0x15, 0xc, 0xa}, +	{28, 0x18, 0xe, 0xc}, +	{32, 0x1b, 0x10, 0xe}, +	{36, 0x1e, 0x12, 0x10} +}; + +static uint32_t get_rdlat_adj(uint32_t dram_type, uint32_t cl) +{ +	const struct lat_adj_pair *p; +	uint32_t cnt; +	uint32_t i; + +	if (dram_type == DDR3) { +		p = ddr3_lat_adj; +		cnt = ARRAY_SIZE(ddr3_lat_adj); +	} else if (dram_type == LPDDR3) { +		p = lpddr3_lat_adj; +		cnt = ARRAY_SIZE(lpddr3_lat_adj); +	} else { +		p = lpddr4_lat_adj; +		cnt = ARRAY_SIZE(lpddr4_lat_adj); +	} + +	for (i = 0; i < cnt; i++) { +		if (cl == p[i].cl) +			return p[i].rdlat_adj; +	} +	/* fail */ +	return 0xff; +} + +static uint32_t get_wrlat_adj(uint32_t dram_type, uint32_t cwl) +{ +	const struct lat_adj_pair *p; +	uint32_t cnt; +	uint32_t i; + +	if (dram_type == DDR3) { +		p = ddr3_lat_adj; +		cnt = ARRAY_SIZE(ddr3_lat_adj); +	} else if (dram_type == LPDDR3) { +		p = lpddr3_lat_adj; +		cnt = ARRAY_SIZE(lpddr3_lat_adj); +	} else { +		p = lpddr4_lat_adj; +		cnt = ARRAY_SIZE(lpddr4_lat_adj); +	} + +	for (i = 0; i < cnt; i++) { +		if (cwl == p[i].cwl) +			return p[i].wrlat_adj; +	} +	/* fail */ +	return 0xff; +} + +#define PI_REGS_DIMM_SUPPORT	(0) +#define PI_ADD_LATENCY	(0) +#define PI_DOUBLEFREEK	(1) + +#define PI_PAD_DELAY_PS_VALUE	(1000) +#define PI_IE_ENABLE_VALUE	(3000) +#define PI_TSEL_ENABLE_VALUE	(700) + +static uint32_t get_pi_rdlat_adj(struct dram_timing_t *pdram_timing) +{ +	/*[DLLSUBTYPE2] == "STD_DENALI_HS" */ +	uint32_t rdlat, delay_adder, ie_enable, hs_offset, tsel_adder, +	    extra_adder, tsel_enable; + +	ie_enable = PI_IE_ENABLE_VALUE; +	tsel_enable = PI_TSEL_ENABLE_VALUE; + +	rdlat = pdram_timing->cl + PI_ADD_LATENCY; +	delay_adder = ie_enable / (1000000 / pdram_timing->mhz); +	if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) +		delay_adder++; +	hs_offset = 0; +	tsel_adder = 0; +	extra_adder = 0; +	/* rdlat = rdlat - (PREAMBLE_SUPPORT & 0x1); */ +	tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz); +	if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0) +		tsel_adder++; +	delay_adder = delay_adder - 1; +	if (tsel_adder > delay_adder) +		extra_adder = tsel_adder - delay_adder; +	else +		extra_adder = 0; +	if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK) +		hs_offset = 2; +	else +		hs_offset = 1; + +	if (delay_adder > (rdlat - 1 - hs_offset)) { +		rdlat = rdlat - tsel_adder; +	} else { +		if ((rdlat - delay_adder) < 2) +			rdlat = 2; +		else +			rdlat = rdlat - delay_adder - extra_adder; +	} + +	return rdlat; +} + +static uint32_t get_pi_wrlat(struct dram_timing_t *pdram_timing, +			     struct timing_related_config *timing_config) +{ +	uint32_t tmp; + +	if (timing_config->dram_type == LPDDR3) { +		tmp = pdram_timing->cl; +		if (tmp >= 14) +			tmp = 8; +		else if (tmp >= 10) +			tmp = 6; +		else if (tmp == 9) +			tmp = 5; +		else if (tmp == 8) +			tmp = 4; +		else if (tmp == 6) +			tmp = 3; +		else +			tmp = 1; +	} else { +		tmp = 1; +	} + +	return tmp; +} + +static uint32_t get_pi_wrlat_adj(struct dram_timing_t *pdram_timing, +				 struct timing_related_config *timing_config) +{ +	return get_pi_wrlat(pdram_timing, timing_config) + PI_ADD_LATENCY - 1; +} + +static uint32_t get_pi_tdfi_phy_rdlat(struct dram_timing_t *pdram_timing, +			struct timing_related_config *timing_config) +{ +	/* [DLLSUBTYPE2] == "STD_DENALI_HS" */ +	uint32_t cas_lat, delay_adder, ie_enable, hs_offset, ie_delay_adder; +	uint32_t mem_delay_ps, round_trip_ps; +	uint32_t phy_internal_delay, lpddr_adder, dfi_adder, rdlat_delay; + +	ie_enable = PI_IE_ENABLE_VALUE; + +	delay_adder = ie_enable / (1000000 / pdram_timing->mhz); +	if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) +		delay_adder++; +	delay_adder = delay_adder - 1; +	if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK) +		hs_offset = 2; +	else +		hs_offset = 1; + +	cas_lat = pdram_timing->cl + PI_ADD_LATENCY; + +	if (delay_adder > (cas_lat - 1 - hs_offset)) { +		ie_delay_adder = 0; +	} else { +		ie_delay_adder = ie_enable / (1000000 / pdram_timing->mhz); +		if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) +			ie_delay_adder++; +	} + +	if (timing_config->dram_type == DDR3) { +		mem_delay_ps = 0; +	} else if (timing_config->dram_type == LPDDR4) { +		mem_delay_ps = 3600; +	} else if (timing_config->dram_type == LPDDR3) { +		mem_delay_ps = 5500; +	} else { +		printf("get_pi_tdfi_phy_rdlat:dramtype unsupport\n"); +		return 0; +	} +	round_trip_ps = 1100 + 500 + mem_delay_ps + 500 + 600; +	delay_adder = round_trip_ps / (1000000 / pdram_timing->mhz); +	if ((round_trip_ps % (1000000 / pdram_timing->mhz)) != 0) +		delay_adder++; + +	phy_internal_delay = 5 + 2 + 4; +	lpddr_adder = mem_delay_ps / (1000000 / pdram_timing->mhz); +	if ((mem_delay_ps % (1000000 / pdram_timing->mhz)) != 0) +		lpddr_adder++; +	dfi_adder = 0; +	phy_internal_delay = phy_internal_delay + 2; +	rdlat_delay = delay_adder + phy_internal_delay + +	    ie_delay_adder + lpddr_adder + dfi_adder; + +	rdlat_delay = rdlat_delay + 2; +	return rdlat_delay; +} + +static uint32_t get_pi_todtoff_min(struct dram_timing_t *pdram_timing, +				   struct timing_related_config *timing_config) +{ +	uint32_t tmp, todtoff_min_ps; + +	if (timing_config->dram_type == LPDDR3) +		todtoff_min_ps = 2500; +	else if (timing_config->dram_type == LPDDR4) +		todtoff_min_ps = 1500; +	else +		todtoff_min_ps = 0; +	/* todtoff_min */ +	tmp = todtoff_min_ps / (1000000 / pdram_timing->mhz); +	if ((todtoff_min_ps % (1000000 / pdram_timing->mhz)) != 0) +		tmp++; +	return tmp; +} + +static uint32_t get_pi_todtoff_max(struct dram_timing_t *pdram_timing, +				   struct timing_related_config *timing_config) +{ +	uint32_t tmp, todtoff_max_ps; + +	if ((timing_config->dram_type == LPDDR4) +	    || (timing_config->dram_type == LPDDR3)) +		todtoff_max_ps = 3500; +	else +		todtoff_max_ps = 0; + +	/* todtoff_max */ +	tmp = todtoff_max_ps / (1000000 / pdram_timing->mhz); +	if ((todtoff_max_ps % (1000000 / pdram_timing->mhz)) != 0) +		tmp++; +	return tmp; +} + +static void gen_rk3399_ctl_params_f0(struct timing_related_config +				     *timing_config, +				     struct dram_timing_t *pdram_timing) +{ +	uint32_t i; +	uint32_t tmp, tmp1; + +	for (i = 0; i < timing_config->ch_cnt; i++) { +		if (timing_config->dram_type == DDR3) { +			tmp = ((700000 + 10) * timing_config->freq + +				999) / 1000; +			tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) + +			    pdram_timing->tmod + pdram_timing->tzqinit; +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[5], tmp); + +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[22], +				      0xffff, pdram_timing->tdllk); + +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[32], +				 (pdram_timing->tmod << 8) | +				 pdram_timing->tmrd); + +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[59], +				      0xffff << 16, +				      (pdram_timing->txsr - +				       pdram_timing->trcd) << 16); +		} else if (timing_config->dram_type == LPDDR4) { +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[5], +				 pdram_timing->tinit1 + pdram_timing->tinit3); +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[32], +				 (pdram_timing->tmrd << 8) | +				 pdram_timing->tmrd); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[59], +				      0xffff << 16, pdram_timing->txsr << 16); +		} else { +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[5], +				 pdram_timing->tinit1); +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[7], +				 pdram_timing->tinit4); +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[32], +				 (pdram_timing->tmrd << 8) | +				 pdram_timing->tmrd); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[59], +				      0xffff << 16, pdram_timing->txsr << 16); +		} +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[6], +			 pdram_timing->tinit3); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[8], +			 pdram_timing->tinit5); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[23], (0x7f << 16), +			      ((pdram_timing->cl * 2) << 16)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[23], (0x1f << 24), +			      (pdram_timing->cwl << 24)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], 0x3f, +			      pdram_timing->al); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[26], 0xffff << 16, +			      (pdram_timing->trc << 24) | +			      (pdram_timing->trrd << 16)); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[27], +			 (pdram_timing->tfaw << 24) | +			 (pdram_timing->trppb << 16) | +			 (pdram_timing->twtr << 8) | pdram_timing->tras_min); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[31], 0xff << 24, +			      max(4, pdram_timing->trtp) << 24); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[33], +			 (pdram_timing->tcke << 24) | pdram_timing->tras_max); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34], 0xff, +			      max(1, pdram_timing->tckesr)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[39], +			      (0x3f << 16) | (0xff << 8), +			      (pdram_timing->twr << 16) | +			      (pdram_timing->trcd << 8)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[42], 0x1f << 16, +			      pdram_timing->tmrz << 16); +		tmp = pdram_timing->tdal ? pdram_timing->tdal : +		       (pdram_timing->twr + pdram_timing->trp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[44], 0xff, tmp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[45], 0xff, +			      pdram_timing->trp); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[48], +			 ((pdram_timing->trefi - 8) << 16) | +			 pdram_timing->trfc); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[52], 0xffff, +			      pdram_timing->txp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[53], 0xffff << 16, +			      pdram_timing->txpdll << 16); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[55], 0xf << 24, +			      pdram_timing->tcscke << 24); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[55], 0xff, +			      pdram_timing->tmrri); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[56], +			 (pdram_timing->tzqcke << 24) | +			 (pdram_timing->tmrwckel << 16) | +			 (pdram_timing->tckehcs << 8) | pdram_timing->tckelcs); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60], 0xffff, +			      pdram_timing->txsnr); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[62], 0xffff << 16, +			      (pdram_timing->tckehcmd << 24) | +			      (pdram_timing->tckelcmd << 16)); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[63], +			 (pdram_timing->tckelpd << 24) | +			 (pdram_timing->tescke << 16) | +			 (pdram_timing->tsr << 8) | pdram_timing->tckckel); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[64], 0xfff, +			      (pdram_timing->tcmdcke << 8) | +			      pdram_timing->tcsckeh); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[92], +			      (0xffff << 8), +			      (pdram_timing->tcksrx << 16) | +			      (pdram_timing->tcksre << 8)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[108], (0x1 << 24), +			      (timing_config->dllbp << 24)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[122], +			      (0x3FF << 16), +			      (pdram_timing->tvrcg_enable << 16)); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[123], +			 (pdram_timing->tfc_long << 16) | +			 pdram_timing->tvrcg_disable); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[124], +			 (pdram_timing->tvref_long << 16) | +			 (pdram_timing->tckfspx << 8) | +			 pdram_timing->tckfspe); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[133], +			 (pdram_timing->mr[1] << 16) | pdram_timing->mr[0]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[134], 0xffff, +			      pdram_timing->mr[2]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[138], 0xffff, +			      pdram_timing->mr[3]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[139], 0xff << 24, +			      pdram_timing->mr11 << 24); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[147], +			 (pdram_timing->mr[1] << 16) | pdram_timing->mr[0]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[148], 0xffff, +			      pdram_timing->mr[2]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[152], 0xffff, +			      pdram_timing->mr[3]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[153], 0xff << 24, +			      pdram_timing->mr11 << 24); +		if (timing_config->dram_type == LPDDR4) { +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[140], +				      0xffff << 16, pdram_timing->mr12 << 16); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[142], +				      0xffff << 16, pdram_timing->mr14 << 16); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[145], +				      0xffff << 16, pdram_timing->mr22 << 16); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[154], +				      0xffff << 16, pdram_timing->mr12 << 16); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[156], +				      0xffff << 16, pdram_timing->mr14 << 16); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[159], +				      0xffff << 16, pdram_timing->mr22 << 16); +		} +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[179], 0xfff << 8, +			      pdram_timing->tzqinit << 8); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[180], +			 (pdram_timing->tzqcs << 16) | +			 (pdram_timing->tzqinit / 2)); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[181], +			 (pdram_timing->tzqlat << 16) | pdram_timing->tzqcal); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[212], 0xff << 8, +			      pdram_timing->todton << 8); + +		if (timing_config->odt) { +			setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213], +				   1 << 16); +			if (timing_config->freq < 400) +				tmp = 4 << 24; +			else +				tmp = 8 << 24; +		} else { +			clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213], +				   1 << 16); +			tmp = 2 << 24; +		} + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[216], +			      0x1f << 24, tmp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[221], +			      (0x3 << 16) | (0xf << 8), +			      (pdram_timing->tdqsck << 16) | +			      (pdram_timing->tdqsck_max << 8)); +		tmp = +		    (get_wrlat_adj(timing_config->dram_type, pdram_timing->cwl) +		     << 8) | get_rdlat_adj(timing_config->dram_type, +					   pdram_timing->cl); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[284], 0xffff, +			      tmp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[82], 0xffff << 16, +			      (4 * pdram_timing->trefi) << 16); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[83], 0xffff, +			      (2 * pdram_timing->trefi) & 0xffff); + +		if ((timing_config->dram_type == LPDDR3) || +		    (timing_config->dram_type == LPDDR4)) { +			tmp = get_pi_wrlat(pdram_timing, timing_config); +			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); +			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; +		} else { +			tmp = 0; +		} +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[214], 0x3f << 16, +			      (tmp & 0x3f) << 16); + +		if ((timing_config->dram_type == LPDDR3) || +		    (timing_config->dram_type == LPDDR4)) { +			/* min_rl_preamble= cl+TDQSCK_MIN-1 */ +			tmp = pdram_timing->cl + +			    get_pi_todtoff_min(pdram_timing, timing_config) - 1; +			/* todtoff_max */ +			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); +			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; +		} else { +			tmp = pdram_timing->cl - pdram_timing->cwl; +		} +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[215], 0x3f << 8, +			      (tmp & 0x3f) << 8); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[275], 0xff << 16, +			      (get_pi_tdfi_phy_rdlat +			       (pdram_timing, timing_config) +			       & 0xff) << 16); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[277], 0xffff, +			      (2 * pdram_timing->trefi) & 0xffff); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[282], 0xffff, +			      (2 * pdram_timing->trefi) & 0xffff); + +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[283], +			 20 * pdram_timing->trefi); + +		/* CTL_308 TDFI_CALVL_CAPTURE_F0:RW:16:10 */ +		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; +		if ((20000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp1++; +		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[308], 0x3ff << 16, +				tmp << 16); + +		/* CTL_308 TDFI_CALVL_CC_F0:RW:0:10 */ +		tmp = tmp + 18; +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[308], 0x3ff, +				tmp); + +		/* CTL_314 TDFI_WRCSLAT_F0:RW:8:8 */ +		tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config); +		if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) { +			if (tmp1 < 5) { +				if (tmp1 == 0) +					tmp = 0; +				else +					tmp = tmp1 - 1; +			} else { +				tmp = tmp1 - 5; +			} +		} else { +			tmp = tmp1 - 2; +		} +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff << 8, +				tmp << 8); + +		/* CTL_314 TDFI_RDCSLAT_F0:RW:0:8 */ +		if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) && +			(pdram_timing->cl >= 5)) +			tmp = pdram_timing->cl - 5; +		else +			tmp = pdram_timing->cl - 2; +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff, +				tmp); +	} +} + +static void gen_rk3399_ctl_params_f1(struct timing_related_config +				     *timing_config, +				     struct dram_timing_t *pdram_timing) +{ +	uint32_t i; +	uint32_t tmp, tmp1; + +	for (i = 0; i < timing_config->ch_cnt; i++) { +		if (timing_config->dram_type == DDR3) { +			tmp = +			    ((700000 + 10) * timing_config->freq + +			      999) / 1000; +			tmp += +			    pdram_timing->txsnr + (pdram_timing->tmrd * 3) + +			    pdram_timing->tmod + pdram_timing->tzqinit; +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[9], tmp); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[22], +				      0xffff << 16, pdram_timing->tdllk << 16); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34], +				      0xffffff00, +				      (pdram_timing->tmod << 24) | +				      (pdram_timing->tmrd << 16) | +				      (pdram_timing->trtp << 8)); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60], +				      0xffff << 16, +				      (pdram_timing->txsr - +				       pdram_timing->trcd) << 16); +		} else if (timing_config->dram_type == LPDDR4) { +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[9], +				 pdram_timing->tinit1 + pdram_timing->tinit3); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34], +				      0xffffff00, +				      (pdram_timing->tmrd << 24) | +				      (pdram_timing->tmrd << 16) | +				      (pdram_timing->trtp << 8)); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60], +				      0xffff << 16, pdram_timing->txsr << 16); +		} else { +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[9], +				 pdram_timing->tinit1); +			write_32(&rk3399_ddr_pctl[i]->denali_ctl[11], +				 pdram_timing->tinit4); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34], +				      0xffffff00, +				      (pdram_timing->tmrd << 24) | +				      (pdram_timing->tmrd << 16) | +				      (pdram_timing->trtp << 8)); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60], +				      0xffff << 16, pdram_timing->txsr << 16); +		} +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[10], +			 pdram_timing->tinit3); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[12], +			 pdram_timing->tinit5); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], (0x7f << 8), +			      ((pdram_timing->cl * 2) << 8)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], (0x1f << 16), +			      (pdram_timing->cwl << 16)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], 0x3f << 24, +			      pdram_timing->al << 24); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[28], 0xffffff00, +			      (pdram_timing->tras_min << 24) | +			      (pdram_timing->trc << 16) | +			      (pdram_timing->trrd << 8)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[29], 0xffffff, +			      (pdram_timing->tfaw << 16) | +			      (pdram_timing->trppb << 8) | pdram_timing->twtr); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[35], +			 (pdram_timing->tcke << 24) | pdram_timing->tras_max); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[36], 0xff, +			      max(1, pdram_timing->tckesr)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[39], +			      (0xff << 24), (pdram_timing->trcd << 24)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[40], +			      0x3f, pdram_timing->twr); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[42], 0x1f << 24, +			      pdram_timing->tmrz << 24); +		tmp = pdram_timing->tdal ? pdram_timing->tdal : +		       (pdram_timing->twr + pdram_timing->trp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[44], 0xff << 8, +			      tmp << 8); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[45], 0xff << 8, +			      pdram_timing->trp << 8); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[49], +			 ((pdram_timing->trefi - 8) << 16) | +			 pdram_timing->trfc); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[52], 0xffff << 16, +			      pdram_timing->txp << 16); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[54], 0xffff, +			      pdram_timing->txpdll); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[55], 0xff << 8, +			      pdram_timing->tmrri << 8); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[57], +			 (pdram_timing->tmrwckel << 24) | +			 (pdram_timing->tckehcs << 16) | +			 (pdram_timing->tckelcs << 8) | pdram_timing->tcscke); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[58], 0xf, +			      pdram_timing->tzqcke); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[61], 0xffff, +			      pdram_timing->txsnr); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[64], 0xffff << 16, +			      (pdram_timing->tckehcmd << 24) | +			      (pdram_timing->tckelcmd << 16)); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[65], +			 (pdram_timing->tckelpd << 24) | +			 (pdram_timing->tescke << 16) | +			 (pdram_timing->tsr << 8) | pdram_timing->tckckel); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[66], 0xfff, +			      (pdram_timing->tcmdcke << 8) | +			      pdram_timing->tcsckeh); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[92], (0xff << 24), +			      (pdram_timing->tcksre << 24)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[93], 0xff, +			      pdram_timing->tcksrx); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[108], (0x1 << 25), +			      (timing_config->dllbp << 25)); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[125], +			 (pdram_timing->tvrcg_disable << 16) | +			 pdram_timing->tvrcg_enable); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[126], +			 (pdram_timing->tckfspx << 24) | +			 (pdram_timing->tckfspe << 16) | +			 pdram_timing->tfc_long); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[127], 0xffff, +			      pdram_timing->tvref_long); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[134], +			      0xffff << 16, pdram_timing->mr[0] << 16); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[135], +			 (pdram_timing->mr[2] << 16) | pdram_timing->mr[1]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[138], +			      0xffff << 16, pdram_timing->mr[3] << 16); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[140], 0xff, +			      pdram_timing->mr11); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[148], +			      0xffff << 16, pdram_timing->mr[0] << 16); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[149], +			 (pdram_timing->mr[2] << 16) | pdram_timing->mr[1]); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[152], +			      0xffff << 16, pdram_timing->mr[3] << 16); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[154], 0xff, +			      pdram_timing->mr11); +		if (timing_config->dram_type == LPDDR4) { +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[141], +				      0xffff, pdram_timing->mr12); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[143], +				      0xffff, pdram_timing->mr14); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[146], +				      0xffff, pdram_timing->mr22); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[155], +				      0xffff, pdram_timing->mr12); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[157], +				      0xffff, pdram_timing->mr14); +			clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[160], +				      0xffff, pdram_timing->mr22); +		} +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[182], +			 ((pdram_timing->tzqinit / 2) << 16) | +			 pdram_timing->tzqinit); +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[183], +			 (pdram_timing->tzqcal << 16) | pdram_timing->tzqcs); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[184], 0x3f, +			      pdram_timing->tzqlat); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[188], 0xfff, +			      pdram_timing->tzqreset); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[212], 0xff << 16, +			      pdram_timing->todton << 16); + +		if (timing_config->odt) { +			setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213], +				   (1 << 24)); +			if (timing_config->freq < 400) +				tmp = 4 << 24; +			else +				tmp = 8 << 24; +		} else { +			clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213], +				   (1 << 24)); +			tmp = 2 << 24; +		} +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[217], 0x1f << 24, +			      tmp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[221], 0xf << 24, +			      (pdram_timing->tdqsck_max << 24)); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[222], 0x3, +			      pdram_timing->tdqsck); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[291], 0xffff, +			      (get_wrlat_adj(timing_config->dram_type, +					     pdram_timing->cwl) << 8) | +			      get_rdlat_adj(timing_config->dram_type, +					    pdram_timing->cl)); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[84], 0xffff, +			      (4 * pdram_timing->trefi) & 0xffff); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[84], 0xffff << 16, +			      ((2 * pdram_timing->trefi) & 0xffff) << 16); + +		if ((timing_config->dram_type == LPDDR3) || +		    (timing_config->dram_type == LPDDR4)) { +			tmp = get_pi_wrlat(pdram_timing, timing_config); +			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); +			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; +		} else { +			tmp = 0; +		} +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[214], 0x3f << 24, +			      (tmp & 0x3f) << 24); + +		if ((timing_config->dram_type == LPDDR3) || +		    (timing_config->dram_type == LPDDR4)) { +			/* min_rl_preamble= cl+TDQSCK_MIN-1 */ +			tmp = pdram_timing->cl + +			    get_pi_todtoff_min(pdram_timing, timing_config) - 1; +			/* todtoff_max */ +			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); +			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; +		} else { +			tmp = pdram_timing->cl - pdram_timing->cwl; +		} +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[215], 0x3f << 16, +			      (tmp & 0x3f) << 16); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[275], 0xff << 24, +			      (get_pi_tdfi_phy_rdlat +			       (pdram_timing, timing_config) +			       & 0xff) << 24); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[284], +			      0xffff << 16, +			      ((2 * pdram_timing->trefi) & 0xffff) << 16); + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[289], 0xffff, +			      (2 * pdram_timing->trefi) & 0xffff); + +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[290], +			 20 * pdram_timing->trefi); + +		/* CTL_309 TDFI_CALVL_CAPTURE_F1:RW:16:10 */ +		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; +		if ((20000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp1++; +		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[309], 0x3ff << 16, +				tmp << 16); + +		/* CTL_309 TDFI_CALVL_CC_F1:RW:0:10 */ +		tmp = tmp + 18; +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[309], 0x3ff, +				tmp); + +		/* CTL_314 TDFI_WRCSLAT_F1:RW:24:8 */ +		tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config); +		if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) { +			if (tmp1 < 5) { +				if (tmp1 == 0) +					tmp = 0; +				else +					tmp = tmp1 - 1; +			} else { +				tmp = tmp1 - 5; +			} +		} else { +			tmp = tmp1 - 2; +		} + +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff << 24, +				tmp << 24); + +		/* CTL_314 TDFI_RDCSLAT_F1:RW:16:8 */ +		if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) && +			(pdram_timing->cl >= 5)) +			tmp = pdram_timing->cl - 5; +		else +			tmp = pdram_timing->cl - 2; +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff << 16, +				tmp << 16); +	} +} + +static void gen_rk3399_ctl_params(struct timing_related_config *timing_config, +				  struct dram_timing_t *pdram_timing, +				  uint32_t fn) +{ +	if (fn == 0) +		gen_rk3399_ctl_params_f0(timing_config, pdram_timing); +	else +		gen_rk3399_ctl_params_f1(timing_config, pdram_timing); + +#if CTL_TRAINING +	uint32_t i, tmp0, tmp1; + +	tmp0 = tmp1 = 0; +#if EN_READ_GATE_TRAINING +	tmp1 = 1; +#endif + +#if EN_CA_TRAINING +	tmp0 |= (1 << 8); +#endif + +#if EN_WRITE_LEVELING +	tmp0 |= (1 << 16); +#endif + +#if EN_READ_LEVELING +	tmp0 |= (1 << 24); +#endif +	for (i = 0; i < timing_config->ch_cnt; i++) { +		if (tmp0 | tmp1) +			setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[305], +				   1 << 16); +		if (tmp0) +			setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[70], tmp0); +		if (tmp1) +			setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[71], tmp1); +	} +#endif +} + +static void gen_rk3399_pi_params_f0(struct timing_related_config *timing_config, +				    struct dram_timing_t *pdram_timing) +{ +	uint32_t tmp, tmp1, tmp2; +	uint32_t i; + +	for (i = 0; i < timing_config->ch_cnt; i++) { +		/* PI_02 PI_TDFI_PHYMSTR_MAX_F0:RW:0:32 */ +		tmp = 4 * pdram_timing->trefi; +		write_32(&rk3399_ddr_pi[i]->denali_pi[2], tmp); +		/* PI_03 PI_TDFI_PHYMSTR_RESP_F0:RW:0:16 */ +		tmp = 2 * pdram_timing->trefi; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[3], 0xffff, tmp); +		/* PI_07 PI_TDFI_PHYUPD_RESP_F0:RW:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[7], 0xffff << 16, +			      tmp << 16); + +		/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F0:RW:0:8 */ +		if (timing_config->dram_type == LPDDR4) +			tmp = 2; +		else +			tmp = 0; +		tmp = (pdram_timing->bl / 2) + 4 + +		    (get_pi_rdlat_adj(pdram_timing) - 2) + tmp + +		    get_pi_tdfi_phy_rdlat(pdram_timing, timing_config); +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[42], 0xff, tmp); +		/* PI_43 PI_WRLAT_F0:RW:0:5 */ +		if (timing_config->dram_type == LPDDR3) { +			tmp = get_pi_wrlat(pdram_timing, timing_config); +			clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43], 0x1f, +				      tmp); +		} +		/* PI_43 PI_ADDITIVE_LAT_F0:RW:8:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43], 0x3f << 8, +			      PI_ADD_LATENCY << 8); + +		/* PI_43 PI_CASLAT_LIN_F0:RW:16:7 */ +		tmp = pdram_timing->cl * 2; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43], 0x7f << 16, +			      tmp << 16); +		/* PI_46 PI_TREF_F0:RW:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[46], 0xffff << 16, +			      pdram_timing->trefi << 16); +		/* PI_46 PI_TRFC_F0:RW:0:10 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[46], 0x3ff, +			      pdram_timing->trfc); +		/* PI_66 PI_TODTL_2CMD_F0:RW:24:8 */ +		if (timing_config->dram_type == LPDDR3) { +			tmp = get_pi_todtoff_max(pdram_timing, timing_config); +			clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[66], +				      0xff << 24, tmp << 24); +		} +		/* PI_72 PI_WR_TO_ODTH_F0:RW:16:6 */ +		if ((timing_config->dram_type == LPDDR3) || +		    (timing_config->dram_type == LPDDR4)) { +			tmp1 = get_pi_wrlat(pdram_timing, timing_config); +			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); +			if (tmp1 > tmp2) +				tmp = tmp1 - tmp2; +			else +				tmp = 0; +		} else if (timing_config->dram_type == DDR3) { +			tmp = 0; +		} +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[72], 0x3f << 16, +			      tmp << 16); +		/* PI_73 PI_RD_TO_ODTH_F0:RW:8:6 */ +		if ((timing_config->dram_type == LPDDR3) || +		    (timing_config->dram_type == LPDDR4)) { +			/* min_rl_preamble= cl+TDQSCK_MIN-1 */ +			tmp1 = pdram_timing->cl + +			    get_pi_todtoff_min(pdram_timing, timing_config) - 1; +			/* todtoff_max */ +			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); +			if (tmp1 > tmp2) +				tmp = tmp1 - tmp2; +			else +				tmp = 0; +		} else if (timing_config->dram_type == DDR3) { +			tmp = pdram_timing->cl - pdram_timing->cwl; +		} +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[73], 0x3f << 8, +			      tmp << 8); +		/* PI_89 PI_RDLAT_ADJ_F0:RW:16:8 */ +		tmp = get_pi_rdlat_adj(pdram_timing); +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[89], 0xff << 16, +			      tmp << 16); +		/* PI_90 PI_WRLAT_ADJ_F0:RW:16:8 */ +		tmp = get_pi_wrlat_adj(pdram_timing, timing_config); +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[90], 0xff << 16, +			      tmp << 16); +		/* PI_91 PI_TDFI_WRCSLAT_F0:RW:16:8 */ +		tmp1 = tmp; +		if (tmp1 < 5) { +			if (tmp1 == 0) +				tmp = 0; +			else +				tmp = tmp1 - 1; +		} else { +			tmp = tmp1 - 5; +		} +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[91], 0xff << 16, +			      tmp << 16); +		/* PI_95 PI_TDFI_CALVL_CAPTURE_F0:RW:16:10 */ +		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; +		if ((20000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp1++; +		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[95], 0x3ff << 16, +			      tmp << 16); +		/* PI_95 PI_TDFI_CALVL_CC_F0:RW:0:10 */ +		tmp = tmp + 18; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[95], 0x3ff, tmp); +		/* PI_102 PI_TMRZ_F0:RW:8:5 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[102], 0x1f << 8, +			      pdram_timing->tmrz << 8); +		/* PI_111 PI_TDFI_CALVL_STROBE_F0:RW:8:4 */ +		tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz); +		if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp1++; +		/* pi_tdfi_calvl_strobe=tds_train+5 */ +		tmp = tmp1 + 5; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[111], 0xf << 8, +			      tmp << 8); +		/* PI_116 PI_TCKEHDQS_F0:RW:16:6 */ +		tmp = 10000 / (1000000 / pdram_timing->mhz); +		if ((10000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp++; +		if (pdram_timing->mhz <= 100) +			tmp = tmp + 1; +		else +			tmp = tmp + 8; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[116], 0x3f << 16, +			      tmp << 16); +		/* PI_125 PI_MR1_DATA_F0_0:RW+:8:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[125], 0xffff << 8, +			      pdram_timing->mr[1] << 8); +		/* PI_133 PI_MR1_DATA_F0_1:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[133], 0xffff, +			      pdram_timing->mr[1]); +		/* PI_140 PI_MR1_DATA_F0_2:RW+:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[140], 0xffff << 16, +			      pdram_timing->mr[1] << 16); +		/* PI_148 PI_MR1_DATA_F0_3:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[148], 0xffff, +			      pdram_timing->mr[1]); +		/* PI_126 PI_MR2_DATA_F0_0:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[126], 0xffff, +			      pdram_timing->mr[2]); +		/* PI_133 PI_MR2_DATA_F0_1:RW+:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[133], 0xffff << 16, +			      pdram_timing->mr[2] << 16); +		/* PI_141 PI_MR2_DATA_F0_2:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[141], 0xffff, +			      pdram_timing->mr[2]); +		/* PI_148 PI_MR2_DATA_F0_3:RW+:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[148], 0xffff << 16, +			      pdram_timing->mr[2] << 16); +		/* PI_156 PI_TFC_F0:RW:0:10 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[156], 0x3ff, +			      pdram_timing->trfc); +		/* PI_158 PI_TWR_F0:RW:24:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0x3f << 24, +			      pdram_timing->twr << 24); +		/* PI_158 PI_TWTR_F0:RW:16:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0x3f << 16, +			      pdram_timing->twtr << 16); +		/* PI_158 PI_TRCD_F0:RW:8:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0xff << 8, +			      pdram_timing->trcd << 8); +		/* PI_158 PI_TRP_F0:RW:0:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0xff, +			      pdram_timing->trp); +		/* PI_157 PI_TRTP_F0:RW:24:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[157], 0xff << 24, +			      pdram_timing->trtp << 24); +		/* PI_159 PI_TRAS_MIN_F0:RW:24:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[159], 0xff << 24, +			      pdram_timing->tras_min << 24); +		/* PI_159 PI_TRAS_MAX_F0:RW:0:17 */ +		tmp = pdram_timing->tras_max * 99 / 100; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[159], 0x1ffff, tmp); +		/* PI_160 PI_TMRD_F0:RW:16:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[160], 0x3f << 16, +			      pdram_timing->tmrd << 16); +		/*PI_160 PI_TDQSCK_MAX_F0:RW:0:4 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[160], 0xf, +			      pdram_timing->tdqsck_max); +		/* PI_187 PI_TDFI_CTRLUPD_MAX_F0:RW:8:16 */ +		tmp = 2 * pdram_timing->trefi; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[187], 0xffff << 8, +			      tmp << 8); +		/* PI_188 PI_TDFI_CTRLUPD_INTERVAL_F0:RW:0:32 */ +		tmp = 20 * pdram_timing->trefi; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[188], 0xffffffff, +			      tmp); +	} +} + +static void gen_rk3399_pi_params_f1(struct timing_related_config *timing_config, +				    struct dram_timing_t *pdram_timing) +{ +	uint32_t tmp, tmp1, tmp2; +	uint32_t i; + +	for (i = 0; i < timing_config->ch_cnt; i++) { +		/* PI_04 PI_TDFI_PHYMSTR_MAX_F1:RW:0:32 */ +		tmp = 4 * pdram_timing->trefi; +		write_32(&rk3399_ddr_pi[i]->denali_pi[4], tmp); +		/* PI_05 PI_TDFI_PHYMSTR_RESP_F1:RW:0:16 */ +		tmp = 2 * pdram_timing->trefi; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[5], 0xffff, tmp); +		/* PI_12 PI_TDFI_PHYUPD_RESP_F1:RW:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[12], 0xffff, tmp); + +		/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F1:RW:8:8 */ +		if (timing_config->dram_type == LPDDR4) +			tmp = 2; +		else +			tmp = 0; +		tmp = (pdram_timing->bl / 2) + 4 + +		    (get_pi_rdlat_adj(pdram_timing) - 2) + tmp + +		    get_pi_tdfi_phy_rdlat(pdram_timing, timing_config); +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[42], 0xff << 8, +			      tmp << 8); +		/* PI_43 PI_WRLAT_F1:RW:24:5 */ +		if (timing_config->dram_type == LPDDR3) { +			tmp = get_pi_wrlat(pdram_timing, timing_config); +			clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43], +				      0x1f << 24, tmp << 24); +		} +		/* PI_44 PI_ADDITIVE_LAT_F1:RW:0:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[44], 0x3f, +			      PI_ADD_LATENCY); +		/* PI_44 PI_CASLAT_LIN_F1:RW:8:7:=0x18 */ +		tmp = pdram_timing->cl * 2; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[44], 0x7f << 8, +			      tmp << 8); +		/* PI_47 PI_TREF_F1:RW:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[47], 0xffff << 16, +			      pdram_timing->trefi << 16); +		/* PI_47 PI_TRFC_F1:RW:0:10 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[47], 0x3ff, +			      pdram_timing->trfc); +		/* PI_67 PI_TODTL_2CMD_F1:RW:8:8 */ +		if (timing_config->dram_type == LPDDR3) { +			tmp = get_pi_todtoff_max(pdram_timing, timing_config); +			clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[67], +				      0xff << 8, tmp << 8); +		} +		/* PI_72 PI_WR_TO_ODTH_F1:RW:24:6 */ +		if ((timing_config->dram_type == LPDDR3) +		    || (timing_config->dram_type == LPDDR4)) { +			tmp1 = get_pi_wrlat(pdram_timing, timing_config); +			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); +			if (tmp1 > tmp2) +				tmp = tmp1 - tmp2; +			else +				tmp = 0; +		} else if (timing_config->dram_type == DDR3) { +			tmp = 0; +		} +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[72], 0x3f << 24, +			      tmp << 24); +		/* PI_73 PI_RD_TO_ODTH_F1:RW:16:6 */ +		if ((timing_config->dram_type == LPDDR3) +		    || (timing_config->dram_type == LPDDR4)) { +			/* min_rl_preamble= cl+TDQSCK_MIN-1 */ +			tmp1 = +			    pdram_timing->cl + get_pi_todtoff_min(pdram_timing, +								  timing_config) +			    - 1; +			/* todtoff_max */ +			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); +			if (tmp1 > tmp2) +				tmp = tmp1 - tmp2; +			else +				tmp = 0; +		} else if (timing_config->dram_type == DDR3) { +			tmp = pdram_timing->cl - pdram_timing->cwl; +		} +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[73], 0x3f << 16, +			      tmp << 16); +		/*P I_89 PI_RDLAT_ADJ_F1:RW:24:8 */ +		tmp = get_pi_rdlat_adj(pdram_timing); +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[89], 0xff << 24, +			      tmp << 24); +		/* PI_90 PI_WRLAT_ADJ_F1:RW:24:8 */ +		tmp = get_pi_wrlat_adj(pdram_timing, timing_config); +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[90], 0xff << 24, +			      tmp << 24); +		/* PI_91 PI_TDFI_WRCSLAT_F1:RW:24:8 */ +		tmp1 = tmp; +		if (tmp1 < 5) { +			if (tmp1 == 0) +				tmp = 0; +			else +				tmp = tmp1 - 1; +		} else { +			tmp = tmp1 - 5; +		} +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[91], 0xff << 24, +			      tmp << 24); +		/*PI_96 PI_TDFI_CALVL_CAPTURE_F1:RW:16:10 */ +		/* tadr=20ns */ +		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; +		if ((20000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp1++; +		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[96], 0x3ff << 16, +			      tmp << 16); +		/* PI_96 PI_TDFI_CALVL_CC_F1:RW:0:10 */ +		tmp = tmp + 18; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[96], 0x3ff, tmp); +		/*PI_103 PI_TMRZ_F1:RW:0:5 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[103], 0x1f, +			      pdram_timing->tmrz); +		/*PI_111 PI_TDFI_CALVL_STROBE_F1:RW:16:4 */ +		/* tds_train=ceil(2/ns) */ +		tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz); +		if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp1++; +		/* pi_tdfi_calvl_strobe=tds_train+5 */ +		tmp = tmp1 + 5; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[111], 0xf << 16, +			      tmp << 16); +		/* PI_116 PI_TCKEHDQS_F1:RW:24:6 */ +		tmp = 10000 / (1000000 / pdram_timing->mhz); +		if ((10000 % (1000000 / pdram_timing->mhz)) != 0) +			tmp++; +		if (pdram_timing->mhz <= 100) +			tmp = tmp + 1; +		else +			tmp = tmp + 8; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[116], 0x3f << 24, +			      tmp << 24); +		/* PI_128 PI_MR1_DATA_F1_0:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[128], 0xffff, +			      pdram_timing->mr[1]); +		/* PI_135 PI_MR1_DATA_F1_1:RW+:8:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[135], 0xffff << 8, +			      pdram_timing->mr[1] << 8); +		/* PI_143 PI_MR1_DATA_F1_2:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[143], 0xffff, +			      pdram_timing->mr[1]); +		/* PI_150 PI_MR1_DATA_F1_3:RW+:8:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[150], 0xffff << 8, +			      pdram_timing->mr[1] << 8); +		/* PI_128 PI_MR2_DATA_F1_0:RW+:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[128], 0xffff << 16, +			      pdram_timing->mr[2] << 16); +		/* PI_136 PI_MR2_DATA_F1_1:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[136], 0xffff, +			      pdram_timing->mr[2]); +		/* PI_143 PI_MR2_DATA_F1_2:RW+:16:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[143], 0xffff << 16, +			      pdram_timing->mr[2] << 16); +		/* PI_151 PI_MR2_DATA_F1_3:RW+:0:16 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[151], 0xffff, +			      pdram_timing->mr[2]); +		/* PI_156 PI_TFC_F1:RW:16:10 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[156], 0x3ff << 16, +			      pdram_timing->trfc << 16); +		/* PI_162 PI_TWR_F1:RW:8:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[162], 0x3f << 8, +			      pdram_timing->twr << 8); +		/* PI_162 PI_TWTR_F1:RW:0:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[162], 0x3f, +			      pdram_timing->twtr); +		/* PI_161 PI_TRCD_F1:RW:24:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[161], 0xff << 24, +			      pdram_timing->trcd << 24); +		/* PI_161 PI_TRP_F1:RW:16:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[161], 0xff << 16, +			      pdram_timing->trp << 16); +		/* PI_161 PI_TRTP_F1:RW:8:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[161], 0xff << 8, +			      pdram_timing->trtp << 8); +		/* PI_163 PI_TRAS_MIN_F1:RW:24:8 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[163], 0xff << 24, +			      pdram_timing->tras_min << 24); +		/* PI_163 PI_TRAS_MAX_F1:RW:0:17 */ +		tmp = pdram_timing->tras_max * 99 / 100; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[163], 0x1ffff, tmp); +		/* PI_164 PI_TMRD_F1:RW:16:6 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[164], 0x3f << 16, +			      pdram_timing->tmrd << 16); +		/* PI_164 PI_TDQSCK_MAX_F1:RW:0:4 */ +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[164], 0xf, +			      pdram_timing->tdqsck_max); +		/* PI_189 PI_TDFI_CTRLUPD_MAX_F1:RW:0:16 */ +		tmp = 2 * pdram_timing->trefi; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[189], 0xffff, tmp); +		/* PI_190 PI_TDFI_CTRLUPD_INTERVAL_F1:RW:0:32 */ +		tmp = 20 * pdram_timing->trefi; +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[190], 0xffffffff, +			      tmp); +	} +} + +static void gen_rk3399_pi_params(struct timing_related_config *timing_config, +				 struct dram_timing_t *pdram_timing, +				 uint32_t fn) +{ +	if (fn == 0) +		gen_rk3399_pi_params_f0(timing_config, pdram_timing); +	else +		gen_rk3399_pi_params_f1(timing_config, pdram_timing); + +#if PI_TRAINING +		uint32_t i; + +		for (i = 0; i < timing_config->ch_cnt; i++) { +#if EN_READ_GATE_TRAINING +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[80], 3 << 24, +			      2 << 24); +#endif + +#if EN_CA_TRAINING +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[100], 3 << 8, +			      2 << 8); +#endif + +#if EN_WRITE_LEVELING +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[60], 3 << 8, +			      2 << 8); +#endif + +#if EN_READ_LEVELING +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[80], 3 << 16, +			      2 << 16); +#endif + +#if EN_WDQ_LEVELING +		clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[124], 3 << 16, +			      2 << 16); +#endif +		} +#endif +} + +static void gen_rk3399_set_odt(uint32_t odt_en) +{ +	uint32_t drv_odt_val; +	uint32_t i; + +	for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) { +		drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 16; +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[5], +				  0x7 << 16, drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[133], +				  0x7 << 16, drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[261], +				  0x7 << 16, drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[389], +				  0x7 << 16, drv_odt_val); +		drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 24; +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[6], +				  0x7 << 24, drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[134], +				  0x7 << 24, drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[262], +				  0x7 << 24, drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[390], +				  0x7 << 24, drv_odt_val); +	} +} + +static void gen_rk3399_set_ds_odt(struct timing_related_config *timing_config, +				  struct drv_odt_lp_config *drv_config) +{ +	uint32_t i, drv_odt_val; + +	for (i = 0; i < timing_config->ch_cnt; i++) { +		if (timing_config->dram_type == LPDDR4) +			drv_odt_val = drv_config->phy_side_odt | +				(PHY_DRV_ODT_Hi_Z << 4) | +				(drv_config->phy_side_dq_drv << 8) | +				(drv_config->phy_side_dq_drv << 12); +		else if (timing_config->dram_type == LPDDR3) +			drv_odt_val = PHY_DRV_ODT_Hi_Z | +				(drv_config->phy_side_odt << 4) | +				(drv_config->phy_side_dq_drv << 8) | +				(drv_config->phy_side_dq_drv << 12); +		else +			drv_odt_val = drv_config->phy_side_odt | +				(drv_config->phy_side_odt << 4) | +				(drv_config->phy_side_dq_drv << 8) | +				(drv_config->phy_side_dq_drv << 12); + +		/* DQ drv odt set */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[6], 0xffffff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[134], 0xffffff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[262], 0xffffff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[390], 0xffffff, +				  drv_odt_val); +		/* DQS drv odt set */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[7], 0xffffff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[135], 0xffffff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[263], 0xffffff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[391], 0xffffff, +				  drv_odt_val); + +		gen_rk3399_set_odt(timing_config->odt); + +		/* CA drv set */ +		drv_odt_val = drv_config->phy_side_ca_drv | +			(drv_config->phy_side_ca_drv << 4); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[544], 0xff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[672], 0xff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[800], 0xff, +				  drv_odt_val); + +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[928], 0xff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[937], 0xff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[935], 0xff, +				  drv_odt_val); + +		drv_odt_val = drv_config->phy_side_ck_cs_drv | +			(drv_config->phy_side_ck_cs_drv << 4); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[929], 0xff, +				  drv_odt_val); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[939], 0xff, +				  drv_odt_val); +	} +} + +static void gen_rk3399_phy_params(struct timing_related_config *timing_config, +				  struct drv_odt_lp_config *drv_config, +				  struct dram_timing_t *pdram_timing, +				  uint32_t fn) +{ +	uint32_t tmp, i, div, j; +	uint32_t mem_delay_ps, pad_delay_ps, total_delay_ps, delay_frac_ps; +	uint32_t trpre_min_ps, gate_delay_ps, gate_delay_frac_ps; +	uint32_t ie_enable, tsel_enable, cas_lat, rddata_en_ie_dly, tsel_adder; +	uint32_t extra_adder, delta, hs_offset; + +	for (i = 0; i < timing_config->ch_cnt; i++) { + +		pad_delay_ps = PI_PAD_DELAY_PS_VALUE; +		ie_enable = PI_IE_ENABLE_VALUE; +		tsel_enable = PI_TSEL_ENABLE_VALUE; + +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[896], +			      (0x3 << 8) | 1, fn << 8); + +		/* PHY_LOW_FREQ_SEL */ +		/* DENALI_PHY_913 1bit offset_0 */ +		if (timing_config->freq > 400) +			clrbits_32(&rk3399_ddr_publ[i]->denali_phy[913], 1); +		else +			setbits_32(&rk3399_ddr_publ[i]->denali_phy[913], 1); + +		/* PHY_RPTR_UPDATE_x */ +		/* DENALI_PHY_87/215/343/471 4bit offset_16 */ +		tmp = 2500 / (1000000 / pdram_timing->mhz) + 3; +		if ((2500 % (1000000 / pdram_timing->mhz)) != 0) +			tmp++; +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[87], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[215], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[343], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[471], 0xf << 16, +			      tmp << 16); + +		/* PHY_PLL_CTRL */ +		/* DENALI_PHY_911 13bits offset_0 */ +		/* PHY_LP4_BOOT_PLL_CTRL */ +		/* DENALI_PHY_919 13bits offset_0 */ +		if (pdram_timing->mhz <= 150) +			tmp = 3; +		else if (pdram_timing->mhz <= 300) +			tmp = 2; +		else if (pdram_timing->mhz <= 600) +			tmp = 1; +		else +			tmp = 0; +		tmp = (1 << 12) | (tmp << 9) | (2 << 7) | (1 << 1); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[911], 0x1fff, +			      tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[919], 0x1fff, +			      tmp); + +		/* PHY_PLL_CTRL_CA */ +		/* DENALI_PHY_911 13bits offset_16 */ +		/* PHY_LP4_BOOT_PLL_CTRL_CA */ +		/* DENALI_PHY_919 13bits offset_16 */ +		if (pdram_timing->mhz <= 150) +			tmp = 3; +		else if (pdram_timing->mhz <= 300) +			tmp = 2; +		else if (pdram_timing->mhz <= 600) +			tmp = 1; +		else +			tmp = 0; +		tmp = (tmp << 9) | (2 << 7) | (1 << 5) | (1 << 1); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[911], +			      0x1fff << 16, tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[919], +			      0x1fff << 16, tmp << 16); + +		/* PHY_TCKSRE_WAIT */ +		/* DENALI_PHY_922 4bits offset_24 */ +		if (pdram_timing->mhz <= 400) +			tmp = 1; +		else if (pdram_timing->mhz <= 800) +			tmp = 3; +		else if (pdram_timing->mhz <= 1000) +			tmp = 4; +		else +			tmp = 5; +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[922], 0xf << 24, +			      tmp << 24); +		/* PHY_CAL_CLK_SELECT_0:RW8:3 */ +		div = pdram_timing->mhz / (2 * 20); +		for (j = 2, tmp = 1; j <= 128; j <<= 1, tmp++) { +			if (div < j) +				break; +		} +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[947], 0x7 << 8, +			      tmp << 8); +		setbits_32(&rk3399_ddr_publ[i]->denali_phy[927], (1 << 22)); + +		if (timing_config->dram_type == DDR3) { +			mem_delay_ps = 0; +			trpre_min_ps = 1000; +		} else if (timing_config->dram_type == LPDDR4) { +			mem_delay_ps = 1500; +			trpre_min_ps = 900; +		} else if (timing_config->dram_type == LPDDR3) { +			mem_delay_ps = 2500; +			trpre_min_ps = 900; +		} else { +			ERROR("gen_rk3399_phy_params:dramtype unsupport\n"); +			return; +		} +		total_delay_ps = mem_delay_ps + pad_delay_ps; +		delay_frac_ps = +		    1000 * total_delay_ps / (1000000 / pdram_timing->mhz); +		gate_delay_ps = delay_frac_ps + 1000 - (trpre_min_ps / 2); +		gate_delay_frac_ps = +		    gate_delay_ps - gate_delay_ps / 1000 * 1000; +		tmp = gate_delay_frac_ps * 0x200 / 1000; +		/* PHY_RDDQS_GATE_BYPASS_SLAVE_DELAY */ +		/* DENALI_PHY_2/130/258/386 10bits offset_0 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[2], 0x2ff, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[130], 0x2ff, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[258], 0x2ff, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[386], 0x2ff, tmp); +		/* PHY_RDDQS_GATE_SLAVE_DELAY */ +		/* DENALI_PHY_77/205/333/461 10bits offset_16 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[77], 0x2ff << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[205], 0x2ff << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[333], 0x2ff << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[461], 0x2ff << 16, +			      tmp << 16); + +		tmp = gate_delay_ps / 1000; +		/* PHY_LP4_BOOT_RDDQS_LATENCY_ADJUST */ +		/* DENALI_PHY_10/138/266/394 4bit offset_0 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[10], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[138], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[266], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[394], 0xf, tmp); +		/* PHY_RDDQS_LATENCY_ADJUST */ +		/* DENALI_PHY_78/206/334/462 4bits offset_0 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[78], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[206], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[334], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[462], 0xf, tmp); +		/* PHY_GTLVL_LAT_ADJ_START */ +		/* DENALI_PHY_80/208/336/464 4bits offset_16 */ +		tmp = delay_frac_ps / 1000; +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[80], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[208], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[336], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[464], 0xf << 16, +			      tmp << 16); + +		cas_lat = pdram_timing->cl + PI_ADD_LATENCY; +		rddata_en_ie_dly = ie_enable / (1000000 / pdram_timing->mhz); +		if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) +			rddata_en_ie_dly++; +		rddata_en_ie_dly = rddata_en_ie_dly - 1; +		tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz); +		if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0) +			tsel_adder++; +		if (rddata_en_ie_dly > tsel_adder) +			extra_adder = rddata_en_ie_dly - tsel_adder; +		else +			extra_adder = 0; +		delta = cas_lat - rddata_en_ie_dly; +		if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK) +			hs_offset = 2; +		else +			hs_offset = 1; +		if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset)) { +			tmp = 0; +		} else { +			if ((delta == 2) || (delta == 1)) +				tmp = rddata_en_ie_dly - 0 - extra_adder; +			else +				tmp = extra_adder; +		} +		/* PHY_LP4_BOOT_RDDATA_EN_TSEL_DLY */ +		/* DENALI_PHY_9/137/265/393 4bit offset_16 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[9], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[137], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[265], 0xf << 16, +			      tmp << 16); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[393], 0xf << 16, +			      tmp << 16); +		/* PHY_RDDATA_EN_TSEL_DLY */ +		/* DENALI_PHY_86/214/342/470 4bit offset_0 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[86], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[214], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[342], 0xf, tmp); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[470], 0xf, tmp); + +		if (tsel_adder > rddata_en_ie_dly) +			extra_adder = tsel_adder - rddata_en_ie_dly; +		else +			extra_adder = 0; +		if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset)) +			tmp = tsel_adder; +		else +			tmp = rddata_en_ie_dly - 0 + extra_adder; +		/* PHY_LP4_BOOT_RDDATA_EN_DLY */ +		/* DENALI_PHY_9/137/265/393 4bit offset_8 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[9], 0xf << 8, +			      tmp << 8); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[137], 0xf << 8, +			      tmp << 8); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[265], 0xf << 8, +			      tmp << 8); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[393], 0xf << 8, +			      tmp << 8); +		/* PHY_RDDATA_EN_DLY */ +		/* DENALI_PHY_85/213/341/469 4bit offset_24 */ +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[85], 0xf << 24, +			      tmp << 24); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[213], 0xf << 24, +			      tmp << 24); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[341], 0xf << 24, +			      tmp << 24); +		clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[469], 0xf << 24, +			      tmp << 24); + +		if (pdram_timing->mhz <= ENPER_CS_TRAINING_FREQ) { + +			/* +			 * Note:Per-CS Training is not compatible at speeds +			 * under 533 MHz. If the PHY is running at a speed +			 * less than 533MHz, all phy_per_cs_training_en_X +			 * parameters must be cleared to 0. +			 */ + +			/*DENALI_PHY_84/212/340/468 1bit offset_16 */ +			clrbits_32(&rk3399_ddr_publ[i]->denali_phy[84], +				   0x1 << 16); +			clrbits_32(&rk3399_ddr_publ[i]->denali_phy[212], +				   0x1 << 16); +			clrbits_32(&rk3399_ddr_publ[i]->denali_phy[340], +				   0x1 << 16); +			clrbits_32(&rk3399_ddr_publ[i]->denali_phy[468], +				   0x1 << 16); +		} else { +			setbits_32(&rk3399_ddr_publ[i]->denali_phy[84], +				   0x1 << 16); +			setbits_32(&rk3399_ddr_publ[i]->denali_phy[212], +				   0x1 << 16); +			setbits_32(&rk3399_ddr_publ[i]->denali_phy[340], +				   0x1 << 16); +			setbits_32(&rk3399_ddr_publ[i]->denali_phy[468], +				   0x1 << 16); +		} +	} +} + +static int to_get_clk_index(unsigned int mhz) +{ +	int pll_cnt, i; + +	pll_cnt = sizeof(dpll_rates_table) / sizeof(struct pll_div); + +	/* Assumming rate_table is in descending order */ +	for (i = 0; i < pll_cnt; i++) { +		if (mhz >= dpll_rates_table[i].mhz) +			break; +	} + +	return i; +} + +uint32_t rkclk_prepare_pll_timing(unsigned int mhz) +{ +	unsigned int refdiv, postdiv1, fbdiv, postdiv2; +	int index; + +	index = to_get_clk_index(mhz); +	refdiv = dpll_rates_table[index].refdiv; +	fbdiv = dpll_rates_table[index].fbdiv; +	postdiv1 = dpll_rates_table[index].postdiv1; +	postdiv2 = dpll_rates_table[index].postdiv2; +	write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(fbdiv)); +	write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON1, POSTDIV2(postdiv2) | +		 POSTDIV1(postdiv1) | REFDIV(refdiv)); +	return (24 * fbdiv) / refdiv / postdiv1 / postdiv2; +} + +uint64_t ddr_get_rate(void) +{ +	uint32_t refdiv, postdiv1, fbdiv, postdiv2; + +	refdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) & 0x3f; +	fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff; +	postdiv1 = +		(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 8) & 0x7; +	postdiv2 = +		(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 12) & 0x7; + +	return (24 / refdiv * fbdiv / postdiv1 / postdiv2) * 1000 * 1000; +} + +/* + * return: bit12: channel 1, external self-refresh + *         bit11: channel 1, stdby_mode + *         bit10: channel 1, self-refresh with controller and memory clock gate + *         bit9: channel 1, self-refresh + *         bit8: channel 1, power-down + * + *         bit4: channel 1, external self-refresh + *         bit3: channel 0, stdby_mode + *         bit2: channel 0, self-refresh with controller and memory clock gate + *         bit1: channel 0, self-refresh + *         bit0: channel 0, power-down + */ +uint32_t exit_low_power(void) +{ +	struct rk3399_ddr_pctl_regs *ddr_pctl_regs; +	uint32_t low_power = 0; +	uint32_t channel_mask; +	uint32_t channel; +	uint32_t tmp; + +	channel_mask = (read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3; +	for (channel = 0; channel < 2; channel++) { +		ddr_pctl_regs = rk3399_ddr_pctl[channel]; +		if (!(channel_mask & (1 << channel))) +			continue; + +		/* exit stdby mode */ +		write_32(&rk3399_ddr_cic->cic_ctrl1, +			 (1 << (channel + 16)) | (0 << channel)); +		/* exit external self-refresh */ +		tmp = channel ? 12 : 8; +		low_power |= ((read_32(PMU_BASE + PMU_SFT_CON) >> tmp) & 0x1) +		    << (4 + 8 * channel); +		clrbits_32(PMU_BASE + PMU_SFT_CON, 1 << tmp); +		while (!(read_32(PMU_BASE + PMU_DDR_SREF_ST) & +				(1 << channel))) +			; +		/* exit auto low-power */ +		clrbits_32(&ddr_pctl_regs->denali_ctl[101], 0x7); +		/* lp_cmd to exit */ +		if (((read_32(&ddr_pctl_regs->denali_ctl[100]) >> 24) & +			      0x7f) != 0x40) { +			while (read_32(&ddr_pctl_regs->denali_ctl[200]) & 0x1) +				; +			clrsetbits_32(&ddr_pctl_regs->denali_ctl[93], +				      0xff << 24, 0x69 << 24); +			while (((read_32(&ddr_pctl_regs->denali_ctl[100]) >> +					  24) & 0x7f) != 0x40) +				; +		} +	} +	return low_power; +} + +void resume_low_power(uint32_t low_power) +{ +	struct rk3399_ddr_pctl_regs *ddr_pctl_regs; +	uint32_t channel_mask; +	uint32_t channel; +	uint32_t tmp; +	uint32_t val; + +	channel_mask = (read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3; +	for (channel = 0; channel < 2; channel++) { +		ddr_pctl_regs = rk3399_ddr_pctl[channel]; +		if (!(channel_mask & (1 << channel))) +			continue; + +		/* resume external self-refresh */ +		tmp = channel ? 12 : 8; +		val = (low_power >> (4 + 8 * channel)) & 0x1; +		setbits_32(PMU_BASE + PMU_SFT_CON, val << tmp); +		/* resume auto low-power */ +		val = (low_power >> (8 * channel)) & 0x7; +		setbits_32(&ddr_pctl_regs->denali_ctl[101], val); +		/* resume stdby mode */ +		val = (low_power >> (3 + 8 * channel)) & 0x1; +		write_32(&rk3399_ddr_cic->cic_ctrl1, +			 (1 << (channel + 16)) | (val << channel)); +	} +} + +static void wait_dcf_done(void) +{ +	while ((read_32(DCF_BASE + DCF_DCF_ISR) & (DCF_DONE)) == 0) +		continue; +} + +void clr_dcf_irq(void) +{ +	/* clear dcf irq status */ +	mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE); +} + +static void enable_dcf(uint32_t dcf_addr) +{ +	/* config DCF start addr */ +	write_32(DCF_BASE + DCF_DCF_ADDR, dcf_addr); +	/* wait dcf done */ +	while (read_32(DCF_BASE + DCF_DCF_CTRL) & 1) +		continue; +	/* clear dcf irq status */ +	write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE); +	/* DCF start */ +	setbits_32(DCF_BASE + DCF_DCF_CTRL, DCF_START); +} + +void dcf_code_init(void) +{ +	memcpy((void *)DCF_START_ADDR, (void *)dcf_code, sizeof(dcf_code)); +	/* set dcf master secure */ +	write_32(SGRF_BASE + 0xe01c, ((0x3 << 0) << 16) | (0 << 0)); +	write_32(DCF_BASE + DCF_DCF_TOSET, 0x80000000); +} + +static void dcf_start(uint32_t freq, uint32_t index) +{ +	write_32(CRU_BASE + CRU_SOFTRST_CON(10), (0x1 << (1 + 16)) | (1 << 1)); +	write_32(CRU_BASE + CRU_SOFTRST_CON(11), (0x1 << (0 + 16)) | (1 << 0)); +	write_32(DCF_PARAM_ADDR + PARAM_FREQ_SELECT, index << 4); + +	write_32(DCF_PARAM_ADDR + PARAM_DRAM_FREQ, freq); + +	rkclk_prepare_pll_timing(freq); +	udelay(10); +	write_32(CRU_BASE + CRU_SOFTRST_CON(10), (0x1 << (1 + 16)) | (0 << 1)); +	write_32(CRU_BASE + CRU_SOFTRST_CON(11), (0x1 << (0 + 16)) | (0 << 0)); +	udelay(10); +	enable_dcf(DCF_START_ADDR); +} + +static void dram_low_power_config(struct drv_odt_lp_config *lp_config) +{ +	uint32_t tmp, tmp1, i; +	uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt; +	uint32_t dram_type = rk3399_dram_status.timing_config.dram_type; +	uint32_t *low_power = &rk3399_dram_status.low_power_stat; + +	if (dram_type == LPDDR4) +		tmp = (lp_config->srpd_lite_idle << 16) | +		      lp_config->pd_idle; +	else +		tmp = lp_config->pd_idle; + +	if (dram_type == DDR3) +		tmp1 = (2 << 16) | (0x7 << 8) | 7; +	else +		tmp1 = (3 << 16) | (0x7 << 8) | 7; + +	*low_power = 0; + +	for (i = 0; i < ch_cnt; i++) { +		write_32(&rk3399_ddr_pctl[i]->denali_ctl[102], tmp); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[103], 0xffff, +			      (lp_config->sr_mc_gate_idle << 8) | +			      lp_config->sr_idle); +		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[101], +			      0x70f0f, tmp1); +		*low_power |= (7 << (8 * i)); +	} + +	/* standby idle */ +	write_32(&rk3399_ddr_cic->cic_idle_th, lp_config->standby_idle); +	write_32(&rk3399_ddr_cic->cic_cg_wait_th, 0x640008); + +	if (ch_cnt == 2) { +		write_32(GRF_BASE + GRF_DDRC1_CON1, +			 (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) | +			 ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7))); +		if (lp_config->standby_idle) { +			tmp = 0x002a002a; +			*low_power |= (1 << 11); +		} else { +			tmp = 0; +		} +		write_32(&rk3399_ddr_cic->cic_ctrl1, tmp); +	} + +	write_32(GRF_BASE + GRF_DDRC0_CON1, +		 (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) | +		 ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7))); +	if (lp_config->standby_idle) { +		tmp = 0x00150015; +		*low_power |= (1 << 3); +	} else { +		tmp = 0; +	} +	write_32(&rk3399_ddr_cic->cic_ctrl1, tmp); +} + + +static void dram_related_init(struct ddr_dts_config_timing *dts_timing) +{ +	uint32_t trefi0, trefi1; +	uint32_t i; +	struct rk3399_sdram_config sdram_config; + +	dcf_code_init(); + +	/* get sdram config for os reg */ +	sdram_config_init(&sdram_config); +	drv_odt_lp_cfg_init(sdram_config.dramtype, dts_timing, +			    &rk3399_dram_status.drv_odt_lp_cfg); +	sdram_timing_cfg_init(&rk3399_dram_status.timing_config, +			      &sdram_config, +			      &rk3399_dram_status.drv_odt_lp_cfg); + +	trefi0 = ((read_32(&rk3399_ddr_pctl[0]->denali_ctl[48]) >> +		   16) & 0xffff) + 8; +	trefi1 = ((read_32(&rk3399_ddr_pctl[0]->denali_ctl[49]) >> +		   16) & 0xffff) + 8; + +	rk3399_dram_status.index_freq[0] = trefi0 * 10 / 39; +	rk3399_dram_status.index_freq[1] = trefi1 * 10 / 39; +	rk3399_dram_status.current_index = +	    (read_32(&rk3399_ddr_pctl[0]->denali_ctl[111]) +	     >> 16) & 0x3; +	if (rk3399_dram_status.timing_config.dram_type == DDR3) { +		rk3399_dram_status.index_freq[0] /= 2; +		rk3399_dram_status.index_freq[1] /= 2; +	} +	rk3399_dram_status.index_freq[(rk3399_dram_status.current_index + 1) +				      & 0x1] = 0; + +	/* disable all training by ctl and pi */ +	for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) { +		clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[70], (1 << 24) | +				(1 << 16) | (1 << 8) | 1); +		clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[71], 1); + +		clrbits_32(&rk3399_ddr_pi[i]->denali_pi[60], 0x3 << 8); +		clrbits_32(&rk3399_ddr_pi[i]->denali_pi[80], (0x3 << 24) | +				(0x3 << 16)); +		clrbits_32(&rk3399_ddr_pi[i]->denali_pi[100], 0x3 << 8); +		clrbits_32(&rk3399_ddr_pi[i]->denali_pi[124], 0x3 << 16); +	} + +	/* init drv odt */ +	if (rk3399_dram_status.index_freq[rk3399_dram_status.current_index] < +		rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq) +		rk3399_dram_status.timing_config.odt = 0; +	else +		rk3399_dram_status.timing_config.odt = 1; +	gen_rk3399_set_ds_odt(&rk3399_dram_status.timing_config, +			&rk3399_dram_status.drv_odt_lp_cfg); +	dram_low_power_config(&rk3399_dram_status.drv_odt_lp_cfg); +} + +static uint32_t prepare_ddr_timing(uint32_t mhz) +{ +	uint32_t index; +	struct dram_timing_t dram_timing; + +	rk3399_dram_status.timing_config.freq = mhz; + +	if (mhz < rk3399_dram_status.drv_odt_lp_cfg.ddr3_dll_dis_freq) +		rk3399_dram_status.timing_config.dllbp = 1; +	else +		rk3399_dram_status.timing_config.dllbp = 0; +	if (mhz < rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq) { +		rk3399_dram_status.timing_config.odt = 0; +	} else { +		rk3399_dram_status.timing_config.odt = 1; +		gen_rk3399_set_odt(1); +	} + +	index = (rk3399_dram_status.current_index + 1) & 0x1; +	if (rk3399_dram_status.index_freq[index] == mhz) +		goto out; + +	/* +	 * checking if having available gate traiing timing for +	 * target freq. +	 */ +	dram_get_parameter(&rk3399_dram_status.timing_config, &dram_timing); + +	gen_rk3399_ctl_params(&rk3399_dram_status.timing_config, +			      &dram_timing, index); +	gen_rk3399_pi_params(&rk3399_dram_status.timing_config, +			     &dram_timing, index); +	gen_rk3399_phy_params(&rk3399_dram_status.timing_config, +			      &rk3399_dram_status.drv_odt_lp_cfg, +			      &dram_timing, index); +	rk3399_dram_status.index_freq[index] = mhz; + + +out: +	return index; +} + +void print_dram_status_info(void) +{ +	uint32_t *p; +	uint32_t i; + +	p = (uint32_t *) &rk3399_dram_status.timing_config; +	INFO("rk3399_dram_status.timing_config:\n"); +	for (i = 0; i < sizeof(struct timing_related_config) / 4; i++) +		tf_printf("%u\n", p[i]); +	p = (uint32_t *) &rk3399_dram_status.drv_odt_lp_cfg; +	INFO("rk3399_dram_status.drv_odt_lp_cfg:\n"); +	for (i = 0; i < sizeof(struct drv_odt_lp_config) / 4; i++) +		tf_printf("%u\n", p[i]); +} + +uint64_t ddr_set_rate(uint64_t hz) +{ +	uint32_t low_power, index; +	uint32_t mhz = hz / (1000 * 1000); + +	if (mhz == +	    rk3399_dram_status.index_freq[rk3399_dram_status.current_index]) +		goto out; + +	low_power = exit_low_power(); +	index = prepare_ddr_timing(mhz); +	if (index > 1) { +		/* set timing error, quit */ +		mhz = 0; +		goto out; +	} + +	dcf_start(mhz, index); +	wait_dcf_done(); +	if (rk3399_dram_status.timing_config.odt == 0) +		gen_rk3399_set_odt(0); + +	rk3399_dram_status.current_index = index; + +	if (mhz < dts_parameter.auto_pd_dis_freq) +		low_power |= rk3399_dram_status.low_power_stat; + +	resume_low_power(low_power); +out: +	return mhz; +} + +uint64_t ddr_round_rate(uint64_t hz) +{ +	int index; +	uint32_t mhz = hz / (1000 * 1000); + +	index = to_get_clk_index(mhz); + +	return dpll_rates_table[index].mhz * 1000 * 1000; +} + +uint64_t dts_timing_receive(uint64_t timing, uint64_t index) +{ +	uint32_t *p = (uint32_t *) &dts_parameter; +	static uint32_t receive_nums; + +	if (index < (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) { +		p[index] = (uint32_t)timing; +		receive_nums++; +	} else { +		dts_parameter.available = 0; +		return -1; +	} + +	/* receive all parameter */ +	if (receive_nums  == (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) { +		dts_parameter.available = 1; +		receive_nums = 0; +	} + +	return index; +} + +void ddr_init(void) +{ +	dram_related_init(&dts_parameter); +} diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h new file mode 100644 index 00000000..62c5170a --- /dev/null +++ b/plat/rockchip/rk3399/drivers/dram/dram.h @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SOC_ROCKCHIP_RK3399_SDRAM_H__ +#define __SOC_ROCKCHIP_RK3399_SDRAM_H__ + +struct rk3399_ddr_cic_regs { +	uint32_t cic_ctrl0; +	uint32_t cic_ctrl1; +	uint32_t cic_idle_th; +	uint32_t cic_cg_wait_th; +	uint32_t cic_status0; +	uint32_t cic_status1; +	uint32_t cic_ctrl2; +	uint32_t cic_ctrl3; +	uint32_t cic_ctrl4; +}; + +/* DENALI_CTL_00 */ +#define START		(1) + +/* DENALI_CTL_68 */ +#define PWRUP_SREFRESH_EXIT	(1 << 16) + +/* DENALI_CTL_274 */ +#define MEM_RST_VALID	(1) + +struct rk3399_ddr_pctl_regs { +	uint32_t denali_ctl[332]; +}; + +struct rk3399_ddr_publ_regs { +	uint32_t denali_phy[959]; +}; + +#define PHY_DRV_ODT_Hi_Z	(0x0) +#define PHY_DRV_ODT_240		(0x1) +#define PHY_DRV_ODT_120		(0x8) +#define PHY_DRV_ODT_80		(0x9) +#define PHY_DRV_ODT_60		(0xc) +#define PHY_DRV_ODT_48		(0xd) +#define PHY_DRV_ODT_40		(0xe) +#define PHY_DRV_ODT_34_3	(0xf) + +struct rk3399_ddr_pi_regs { +	uint32_t denali_pi[200]; +}; +union noc_ddrtiminga0 { +	uint32_t d32; +	struct { +		unsigned acttoact : 6; +		unsigned reserved0 : 2; +		unsigned rdtomiss : 6; +		unsigned reserved1 : 2; +		unsigned wrtomiss : 6; +		unsigned reserved2 : 2; +		unsigned readlatency : 8; +	} b; +}; + +union noc_ddrtimingb0 { +	uint32_t d32; +	struct { +		unsigned rdtowr : 5; +		unsigned reserved0 : 3; +		unsigned wrtord : 5; +		unsigned reserved1 : 3; +		unsigned rrd : 4; +		unsigned reserved2 : 4; +		unsigned faw : 6; +		unsigned reserved3 : 2; +	} b; +}; + +union noc_ddrtimingc0 { +	uint32_t d32; +	struct { +		unsigned burstpenalty : 4; +		unsigned reserved0 : 4; +		unsigned wrtomwr : 6; +		unsigned reserved1 : 18; +	} b; +}; + +union noc_devtodev0 { +	uint32_t d32; +	struct { +		unsigned busrdtord : 3; +		unsigned reserved0 : 1; +		unsigned busrdtowr : 3; +		unsigned reserved1 : 1; +		unsigned buswrtord : 3; +		unsigned reserved2 : 1; +		unsigned buswrtowr : 3; +		unsigned reserved3 : 17; +	} b; +}; + +union noc_ddrmode { +	uint32_t d32; +	struct { +		unsigned autoprecharge : 1; +		unsigned bypassfiltering : 1; +		unsigned fawbank : 1; +		unsigned burstsize : 2; +		unsigned mwrsize : 2; +		unsigned reserved2 : 1; +		unsigned forceorder : 8; +		unsigned forceorderstate : 8; +		unsigned reserved3 : 8; +	} b; +}; + +struct rk3399_msch_regs { +	uint32_t coreid; +	uint32_t revisionid; +	uint32_t ddrconf; +	uint32_t ddrsize; +	union noc_ddrtiminga0 ddrtiminga0; +	union noc_ddrtimingb0 ddrtimingb0; +	union noc_ddrtimingc0 ddrtimingc0; +	union noc_devtodev0 devtodev0; +	uint32_t reserved0[(0x110-0x20)/4]; +	union noc_ddrmode ddrmode; +	uint32_t reserved1[(0x1000-0x114)/4]; +	uint32_t agingx0; +}; + +struct rk3399_msch_timings { +	union noc_ddrtiminga0 ddrtiminga0; +	union noc_ddrtimingb0 ddrtimingb0; +	union noc_ddrtimingc0 ddrtimingc0; +	union noc_devtodev0 devtodev0; +	union noc_ddrmode ddrmode; +	uint32_t agingx0; +}; +#if 1 +struct rk3399_sdram_channel { +	unsigned char rank; +	/* col = 0, means this channel is invalid */ +	unsigned char col; +	/* 3:8bank, 2:4bank */ +	unsigned char bk; +	/* channel buswidth, 2:32bit, 1:16bit, 0:8bit */ +	unsigned char bw; +	/* die buswidth, 2:32bit, 1:16bit, 0:8bit */ +	unsigned char dbw; +	/* row_3_4 = 1: 6Gb or 12Gb die +	 * row_3_4 = 0: normal die, power of 2 +	 */ +	unsigned char row_3_4; +	unsigned char cs0_row; +	unsigned char cs1_row; +	uint32_t ddrconfig; +	struct rk3399_msch_timings noc_timings; +}; + +struct rk3399_sdram_params { +	struct rk3399_sdram_channel ch[2]; +	uint32_t ddr_freq; +	unsigned char dramtype; +	unsigned char num_channels; +	unsigned char stride; +	unsigned char odt; +	struct rk3399_ddr_pctl_regs pctl_regs; +	struct rk3399_ddr_pi_regs pi_regs; +	struct rk3399_ddr_publ_regs phy_regs; +}; +#endif +struct rk3399_sdram_channel_config { +	uint32_t bus_width; +	uint32_t cs_cnt; +	uint32_t cs0_row; +	uint32_t cs1_row; +	uint32_t bank; +	uint32_t col; +	uint32_t each_die_bus_width; +	uint32_t each_die_6gb_or_12gb; +}; + +struct rk3399_sdram_config { +	struct rk3399_sdram_channel_config ch[2]; +	uint32_t dramtype; +	uint32_t channal_num; +}; + +struct rk3399_sdram_default_config { +	unsigned char bl; +	/* 1:auto precharge, 0:never auto precharge */ +	unsigned char ap; +	/* dram driver strength */ +	unsigned char dramds; +	/* dram ODT, if odt=0, this parameter invalid */ +	unsigned char dramodt; +	/* ca ODT, if odt=0, this parameter invalid +	 * only used by LPDDR4 +	 */ +	unsigned char caodt; +	unsigned char burst_ref_cnt; +	/* zqcs period, unit(s) */ +	unsigned char zqcsi; +}; + +struct  ddr_dts_config_timing { +	unsigned int ddr3_speed_bin; +	unsigned int pd_idle; +	unsigned int sr_idle; +	unsigned int sr_mc_gate_idle; +	unsigned int srpd_lite_idle; +	unsigned int standby_idle; +	unsigned int auto_pd_dis_freq; +	unsigned int ddr3_dll_dis_freq; +	unsigned int phy_dll_dis_freq; +	unsigned int ddr3_odt_dis_freq; +	unsigned int ddr3_drv; +	unsigned int ddr3_odt; +	unsigned int phy_ddr3_ca_drv; +	unsigned int phy_ddr3_dq_drv; +	unsigned int phy_ddr3_odt; +	unsigned int lpddr3_odt_dis_freq; +	unsigned int lpddr3_drv; +	unsigned int lpddr3_odt; +	unsigned int phy_lpddr3_ca_drv; +	unsigned int phy_lpddr3_dq_drv; +	unsigned int phy_lpddr3_odt; +	unsigned int lpddr4_odt_dis_freq; +	unsigned int lpddr4_drv; +	unsigned int lpddr4_dq_odt; +	unsigned int lpddr4_ca_odt; +	unsigned int phy_lpddr4_ca_drv; +	unsigned int phy_lpddr4_ck_cs_drv; +	unsigned int phy_lpddr4_dq_drv; +	unsigned int phy_lpddr4_odt; +	uint32_t available; +}; + +struct drv_odt_lp_config { +	uint32_t ddr3_speed_bin; +	uint32_t pd_idle; +	uint32_t sr_idle; +	uint32_t sr_mc_gate_idle; +	uint32_t srpd_lite_idle; +	uint32_t standby_idle; + +	uint32_t ddr3_dll_dis_freq;/* for ddr3 only */ +	uint32_t phy_dll_dis_freq; +	uint32_t odt_dis_freq; + +	uint32_t dram_side_drv; +	uint32_t dram_side_dq_odt; +	uint32_t dram_side_ca_odt; + +	uint32_t phy_side_ca_drv; +	uint32_t phy_side_ck_cs_drv; +	uint32_t phy_side_dq_drv; +	uint32_t phy_side_odt; +}; + +#define KHz (1000) +#define MHz (1000*KHz) +#define GHz (1000*MHz) + +#define PI_CA_TRAINING	(1 << 0) +#define PI_WRITE_LEVELING	(1 << 1) +#define PI_READ_GATE_TRAINING	(1 << 2) +#define PI_READ_LEVELING	(1 << 3) +#define PI_WDQ_LEVELING	(1 << 4) +#define PI_FULL_TARINING	(0xff) + +#define READ_CH_CNT(val)			(1+((val>>12)&0x1)) +#define READ_CH_INFO(val)			((val>>28)&0x3) +/* row_3_4:0=normal, 1=6Gb or 12Gb */ +#define READ_CH_ROW_INFO(val, ch)	((val>>(30+(ch)))&0x1) + +#define READ_DRAMTYPE_INFO(val)		((val>>13)&0x7) +#define READ_CS_INFO(val, ch)		((((val)>>(11+(ch)*16))&0x1)+1) +#define READ_BW_INFO(val, ch)		(2>>(((val)>>(2+(ch)*16))&0x3)) +#define READ_COL_INFO(val, ch)		(9+(((val)>>(9+(ch)*16))&0x3)) +#define READ_BK_INFO(val, ch)		(3-(((val)>>(8+(ch)*16))&0x1)) +#define READ_CS0_ROW_INFO(val, ch)	(13+(((val)>>(6+(ch)*16))&0x3)) +#define READ_CS1_ROW_INFO(val, ch)	(13+(((val)>>(4+(ch)*16))&0x3)) +#define READ_DIE_BW_INFO(val, ch)	(2>>((val>>((ch)*16))&0x3)) + +#define __sramdata __attribute__((section(".sram.data"))) +#define __sramconst __attribute__((section(".sram.rodata"))) +#define __sramlocalfunc __attribute__((section(".sram.text"))) +#define __sramfunc __attribute__((section(".sram.text"))) \ +					__attribute__((noinline)) + + +#define DDR_SAVE_SP(save_sp)   (save_sp = ddr_save_sp(((uint32_t)\ +				(SRAM_CODE_BASE + 0x2000) & (~7)))) + +#define DDR_RESTORE_SP(save_sp)   ddr_save_sp(save_sp) + +void ddr_init(void); +uint64_t ddr_set_rate(uint64_t hz); +uint64_t ddr_round_rate(uint64_t hz); +uint64_t ddr_get_rate(void); +void clr_dcf_irq(void); +uint64_t dts_timing_receive(uint64_t timing, uint64_t index); +#endif diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c new file mode 100644 index 00000000..b015db74 --- /dev/null +++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c @@ -0,0 +1,1323 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdint.h> +#include "dram_spec_timing.h" + +static const uint8_t ddr3_cl_cwl[][7] = { +	/* +	 * speed 0~330 331 ~ 400 401 ~ 533 534~666 667~800 801~933 934~1066 +	 * tCK>3 2.5~3 1.875~2.5 1.5~1.875 1.25~1.5 1.07~1.25 0.938~1.07 +	 * cl<<4, cwl  cl<<4, cwl  cl<<4, cwl +	 */ +	/* DDR3_800D (5-5-5) */ +	{((5 << 4) | 5), ((5 << 4) | 5), 0, 0, 0, 0, 0}, +	/* DDR3_800E (6-6-6) */ +	{((5 << 4) | 5), ((6 << 4) | 5), 0, 0, 0, 0, 0}, +	/* DDR3_1066E (6-6-6) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), 0, 0, 0, 0}, +	/* DDR3_1066F (7-7-7) */ +	{((5 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), 0, 0, 0, 0}, +	/* DDR3_1066G (8-8-8) */ +	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), 0, 0, 0, 0}, +	/* DDR3_1333F (7-7-7) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7), +	 0, 0, 0}, +	/* DDR3_1333G (8-8-8) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((8 << 4) | 7), +	 0, 0, 0}, +	/* DDR3_1333H (9-9-9) */ +	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((9 << 4) | 7), +	 0, 0, 0}, +	/* DDR3_1333J (10-10-10) */ +	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), +	 0, 0, 0}, +	/* DDR3_1600G (8-8-8) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7), +	 ((8 << 4) | 8), 0, 0}, +	/* DDR3_1600H (9-9-9) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7), +	 ((9 << 4) | 8), 0, 0}, +	/* DDR3_1600J (10-10-10) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), +	 ((10 << 4) | 8), 0, 0}, +	/* DDR3_1600K (11-11-11) */ +	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), +	 ((11 << 4) | 8), 0, 0}, +	/* DDR3_1866J (10-10-10) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7), +	 ((9 << 4) | 8), ((11 << 4) | 9), 0}, +	/* DDR3_1866K (11-11-11) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((8 << 4) | 7), +	 ((10 << 4) | 8), ((11 << 4) | 9), 0}, +	/* DDR3_1866L (12-12-12) */ +	{((6 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), +	 ((11 << 4) | 8), ((12 << 4) | 9), 0}, +	/* DDR3_1866M (13-13-13) */ +	{((6 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), +	 ((11 << 4) | 8), ((13 << 4) | 9), 0}, +	/* DDR3_2133K (11-11-11) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7), +	 ((9 << 4) | 8), ((10 << 4) | 9), ((11 << 4) | 10)}, +	/* DDR3_2133L (12-12-12) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7), +	 ((9 << 4) | 8), ((11 << 4) | 9), ((12 << 4) | 10)}, +	/* DDR3_2133M (13-13-13) */ +	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), +	 ((10 << 4) | 8), ((12 << 4) | 9), ((13 << 4) | 10)}, +	/* DDR3_2133N (14-14-14) */ +	{((6 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), +	 ((11 << 4) | 8), ((13 << 4) | 9), ((14 << 4) | 10)}, +	/* DDR3_DEFAULT */ +	{((6 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), +	 ((11 << 4) | 8), ((13 << 4) | 9), ((14 << 4) | 10)} +}; + +static const uint16_t ddr3_trc_tfaw[] = { +	/* tRC      tFAW */ +	((50 << 8) | 50),	/* DDR3_800D (5-5-5) */ +	((53 << 8) | 50),	/* DDR3_800E (6-6-6) */ + +	((49 << 8) | 50),	/* DDR3_1066E (6-6-6) */ +	((51 << 8) | 50),	/* DDR3_1066F (7-7-7) */ +	((53 << 8) | 50),	/* DDR3_1066G (8-8-8) */ + +	((47 << 8) | 45),	/* DDR3_1333F (7-7-7) */ +	((48 << 8) | 45),	/* DDR3_1333G (8-8-8) */ +	((50 << 8) | 45),	/* DDR3_1333H (9-9-9) */ +	((51 << 8) | 45),	/* DDR3_1333J (10-10-10) */ + +	((45 << 8) | 40),	/* DDR3_1600G (8-8-8) */ +	((47 << 8) | 40),	/* DDR3_1600H (9-9-9)*/ +	((48 << 8) | 40),	/* DDR3_1600J (10-10-10) */ +	((49 << 8) | 40),	/* DDR3_1600K (11-11-11) */ + +	((45 << 8) | 35),	/* DDR3_1866J (10-10-10) */ +	((46 << 8) | 35),	/* DDR3_1866K (11-11-11) */ +	((47 << 8) | 35),	/* DDR3_1866L (12-12-12) */ +	((48 << 8) | 35),	/* DDR3_1866M (13-13-13) */ + +	((44 << 8) | 35),	/* DDR3_2133K (11-11-11) */ +	((45 << 8) | 35),	/* DDR3_2133L (12-12-12) */ +	((46 << 8) | 35),	/* DDR3_2133M (13-13-13) */ +	((47 << 8) | 35),	/* DDR3_2133N (14-14-14) */ + +	((53 << 8) | 50)	/* DDR3_DEFAULT */ +}; + +static uint32_t get_max_speed_rate(struct timing_related_config *timing_config) +{ +	if (timing_config->ch_cnt > 1) +		return max(timing_config->dram_info[0].speed_rate, +					timing_config->dram_info[1].speed_rate); +	else +		return timing_config->dram_info[0].speed_rate; +} + +static uint32_t +get_max_die_capability(struct timing_related_config *timing_config) +{ +	uint32_t die_cap = 0; +	uint32_t cs, ch; + +	for (ch = 0; ch < timing_config->ch_cnt; ch++) { +		for (cs = 0; cs < timing_config->dram_info[ch].cs_cnt; cs++) { +			die_cap = max(die_cap, +				      timing_config-> +				      dram_info[ch].per_die_capability[cs]); +		} +	} +	return die_cap; +} + +/* tRSTL, 100ns */ +#define DDR3_TRSTL		(100) +/* trsth, 500us */ +#define DDR3_TRSTH		(500000) +/* trefi, 7.8us */ +#define DDR3_TREFI_7_8_US	(7800) +/* tWR, 15ns */ +#define DDR3_TWR		(15) +/* tRTP, max(4 tCK,7.5ns) */ +#define DDR3_TRTP		(7) +/* tRRD = max(4nCK, 10ns) */ +#define DDR3_TRRD		(10) +/* tCK */ +#define DDR3_TCCD		(4) +/*tWTR, max(4 tCK,7.5ns)*/ +#define DDR3_TWTR		(7) +/* tCK */ +#define DDR3_TRTW		(0) +/* tRAS, 37.5ns(400MHz) 37.5ns(533MHz) */ +#define DDR3_TRAS		(37) +/* ns */ +#define DDR3_TRFC_512MBIT	(90) +/* ns */ +#define DDR3_TRFC_1GBIT		(110) +/* ns */ +#define DDR3_TRFC_2GBIT		(160) +/* ns */ +#define DDR3_TRFC_4GBIT		(300) +/* ns */ +#define DDR3_TRFC_8GBIT		(350) + +/*pd and sr*/ +#define DDR3_TXP		(7) /* tXP, max(3 tCK, 7.5ns)( < 933MHz) */ +#define DDR3_TXPDLL		(24) /* tXPDLL, max(10 tCK, 24ns) */ +#define DDR3_TDLLK		(512) /* tXSR, tDLLK=512 tCK */ +#define DDR3_TCKE_400MHZ	(7) /* tCKE, max(3 tCK,7.5ns)(400MHz) */ +#define DDR3_TCKE_533MHZ	(6) /* tCKE, max(3 tCK,5.625ns)(533MHz) */ +#define DDR3_TCKSRE		(10) /* tCKSRX, max(5 tCK, 10ns) */ + +/*mode register timing*/ +#define DDR3_TMOD		(15) /* tMOD, max(12 tCK,15ns) */ +#define DDR3_TMRD		(4) /* tMRD, 4 tCK */ + +/* ZQ */ +#define DDR3_TZQINIT		(640) /* tZQinit, max(512 tCK, 640ns) */ +#define DDR3_TZQCS		(80) /* tZQCS, max(64 tCK, 80ns) */ +#define DDR3_TZQOPER		(320) /* tZQoper, max(256 tCK, 320ns) */ + +/* Write leveling */ +#define DDR3_TWLMRD		(40) /* tCK */ +#define DDR3_TWLO		(9) /* max 7.5ns */ +#define DDR3_TWLDQSEN		(25) /* tCK */ + +/* + * Description: depend on input parameter "timing_config", + *		and calculate all ddr3 + *		spec timing to "pdram_timing" + * parameters: + *   input: timing_config + *   output: pdram_timing + */ +static void ddr3_get_parameter(struct timing_related_config *timing_config, +			       struct dram_timing_t *pdram_timing) +{ +	uint32_t nmhz = timing_config->freq; +	uint32_t ddr_speed_bin = get_max_speed_rate(timing_config); +	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); +	uint32_t tmp; + +	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t)); +	pdram_timing->mhz = nmhz; +	pdram_timing->al = 0; +	pdram_timing->bl = timing_config->bl; +	if (nmhz <= 330) +		tmp = 0; +	else if (nmhz <= 400) +		tmp = 1; +	else if (nmhz <= 533) +		tmp = 2; +	else if (nmhz <= 666) +		tmp = 3; +	else if (nmhz <= 800) +		tmp = 4; +	else if (nmhz <= 933) +		tmp = 5; +	else +		tmp = 6; + +	/* when dll bypss cl = cwl = 6 */ +	if (nmhz < 300) { +		pdram_timing->cl = 6; +		pdram_timing->cwl = 6; +	} else { +		pdram_timing->cl = (ddr3_cl_cwl[ddr_speed_bin][tmp] >> 4) & 0xf; +		pdram_timing->cwl = ddr3_cl_cwl[ddr_speed_bin][tmp] & 0xf; +	} + +	switch (timing_config->dramds) { +	case 40: +		tmp = DDR3_DS_40; +		break; +	case 34: +	default: +		tmp = DDR3_DS_34; +		break; +	} + +	switch (timing_config->dramodt) { +	case 60: +		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_60; +		break; +	case 40: +		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_40; +		break; +	case 120: +		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_120; +		break; +	case 0: +	default: +		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_DIS; +		break; +	} + +	pdram_timing->mr[2] = DDR3_MR2_CWL(pdram_timing->cwl); +	pdram_timing->mr[3] = 0; + +	pdram_timing->trstl = ((DDR3_TRSTL * nmhz + 999) / 1000); +	pdram_timing->trsth = ((DDR3_TRSTH * nmhz + 999) / 1000); +	/* tREFI, average periodic refresh interval, 7.8us */ +	pdram_timing->trefi = ((DDR3_TREFI_7_8_US * nmhz + 999) / 1000); +	/* base timing */ +	pdram_timing->trcd = pdram_timing->cl; +	pdram_timing->trp = pdram_timing->cl; +	pdram_timing->trppb = pdram_timing->cl; +	tmp = ((DDR3_TWR * nmhz + 999) / 1000); +	pdram_timing->twr = tmp; +	pdram_timing->tdal = tmp + pdram_timing->trp; +	if (tmp < 9) { +		tmp = tmp - 4; +	} else { +		tmp += (tmp & 0x1) ? 1 : 0; +		tmp = tmp >> 1; +	} +	if (pdram_timing->bl == 4) +		pdram_timing->mr[0] = DDR3_BC4 +				| DDR3_CL(pdram_timing->cl) +				| DDR3_WR(tmp); +	else +		pdram_timing->mr[0] = DDR3_BL8 +				| DDR3_CL(pdram_timing->cl) +				| DDR3_WR(tmp); +	tmp = ((DDR3_TRTP * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->trtp = max(4, tmp); +	pdram_timing->trc = +		(((ddr3_trc_tfaw[ddr_speed_bin] >> 8) * nmhz + 999) / 1000); +	tmp = ((DDR3_TRRD * nmhz + 999) / 1000); +	pdram_timing->trrd = max(4, tmp); +	pdram_timing->tccd = DDR3_TCCD; +	tmp = ((DDR3_TWTR * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->twtr = max(4, tmp); +	pdram_timing->trtw = DDR3_TRTW; +	pdram_timing->tras_max = 9 * pdram_timing->trefi; +	pdram_timing->tras_min = ((DDR3_TRAS * nmhz + (nmhz >> 1) + 999) +		/ 1000); +	pdram_timing->tfaw = +		(((ddr3_trc_tfaw[ddr_speed_bin] & 0x0ff) * nmhz + 999) +						/ 1000); +	/* tRFC, 90ns(512Mb),110ns(1Gb),160ns(2Gb),300ns(4Gb),350ns(8Gb) */ +	if (ddr_capability_per_die <= 0x4000000) +		tmp = DDR3_TRFC_512MBIT; +	else if (ddr_capability_per_die <= 0x8000000) +		tmp = DDR3_TRFC_1GBIT; +	else if (ddr_capability_per_die <= 0x10000000) +		tmp = DDR3_TRFC_2GBIT; +	else if (ddr_capability_per_die <= 0x20000000) +		tmp = DDR3_TRFC_4GBIT; +	else +		tmp = DDR3_TRFC_8GBIT; +	pdram_timing->trfc = (tmp * nmhz + 999) / 1000; +	pdram_timing->txsnr = max(5, (((tmp + 10) * nmhz + 999) / 1000)); +	pdram_timing->tdqsck_max = 0; +	/*pd and sr*/ +	pdram_timing->txsr = DDR3_TDLLK; +	tmp = ((DDR3_TXP * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->txp = max(3, tmp); +	tmp = ((DDR3_TXPDLL * nmhz + 999) / 1000); +	pdram_timing->txpdll = max(10, tmp); +	pdram_timing->tdllk = DDR3_TDLLK; +	if (nmhz >= 533) +		tmp = ((DDR3_TCKE_533MHZ * nmhz + 999) / 1000); +	else +		tmp = ((DDR3_TCKE_400MHZ * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->tcke = max(3, tmp); +	pdram_timing->tckesr = (pdram_timing->tcke + 1); +	tmp = ((DDR3_TCKSRE * nmhz + 999) / 1000); +	pdram_timing->tcksre = max(5, tmp); +	pdram_timing->tcksrx = max(5, tmp); +	/*mode register timing*/ +	tmp = ((DDR3_TMOD * nmhz + 999) / 1000); +	pdram_timing->tmod = max(12, tmp); +	pdram_timing->tmrd = DDR3_TMRD; +	pdram_timing->tmrr = 0; +	/*ODT*/ +	pdram_timing->todton = pdram_timing->cwl - 2; +	/*ZQ*/ +	tmp = ((DDR3_TZQINIT * nmhz + 999) / 1000); +	pdram_timing->tzqinit = max(512, tmp); +	tmp = ((DDR3_TZQCS * nmhz + 999) / 1000); +	pdram_timing->tzqcs = max(64, tmp); +	tmp = ((DDR3_TZQOPER * nmhz + 999) / 1000); +	pdram_timing->tzqoper = max(256, tmp); +	/* write leveling */ +	pdram_timing->twlmrd = DDR3_TWLMRD; +	pdram_timing->twldqsen = DDR3_TWLDQSEN; +	pdram_timing->twlo = ((DDR3_TWLO * nmhz + (nmhz >> 1) + 999) / 1000); +} + +#define LPDDR2_TINIT1		(100) /* ns */ +#define LPDDR2_TINIT2		(5) /* tCK */ +#define LPDDR2_TINIT3		(200000) /* 200us */ +#define LPDDR2_TINIT4		(1000) /* 1us */ +#define LPDDR2_TINIT5		(10000) /* 10us */ +#define LPDDR2_TRSTL		(0) /* tCK */ +#define LPDDR2_TRSTH		(500000) /* 500us */ +#define LPDDR2_TREFI_3_9_US	(3900) /* 3.9us */ +#define LPDDR2_TREFI_7_8_US	(7800) /* 7.8us */ + +/* base timing */ +#define LPDDR2_TRCD		(24) /* tRCD,15ns(Fast)18ns(Typ)24ns(Slow) */ +#define LPDDR2_TRP_PB		(18) /* tRPpb,15ns(Fast)18ns(Typ)24ns(Slow) */ +#define LPDDR2_TRP_AB_8_BANK	(21) /* tRPab,18ns(Fast)21ns(Typ)27ns(Slow) */ +#define LPDDR2_TWR		(15) /* tWR, max(3tCK,15ns) */ +#define LPDDR2_TRTP		(7) /* tRTP, max(2tCK, 7.5ns) */ +#define LPDDR2_TRRD		(10) /* tRRD, max(2tCK,10ns) */ +#define LPDDR2_TCCD		(2) /* tCK */ +#define LPDDR2_TWTR_GREAT_200MHZ	(7) /* ns */ +#define LPDDR2_TWTR_LITTLE_200MHZ	(10) /* ns */ +#define LPDDR2_TRTW		(0) /* tCK */ +#define LPDDR2_TRAS_MAX		(70000) /* 70us */ +#define LPDDR2_TRAS		(42) /* tRAS, max(3tCK,42ns) */ +#define LPDDR2_TFAW_GREAT_200MHZ	(50) /* max(8tCK,50ns) */ +#define LPDDR2_TFAW_LITTLE_200MHZ	(60) /* max(8tCK,60ns) */ +#define LPDDR2_TRFC_8GBIT	(210) /* ns */ +#define LPDDR2_TRFC_4GBIT	(130) /* ns */ +#define LPDDR2_TDQSCK_MIN	(2) /* tDQSCKmin, 2.5ns */ +#define LPDDR2_TDQSCK_MAX	(5) /* tDQSCKmax, 5.5ns */ + +/*pd and sr*/ +#define LPDDR2_TXP		(7) /* tXP, max(2tCK,7.5ns) */ +#define LPDDR2_TXPDLL		(0) +#define LPDDR2_TDLLK		(0) /* tCK */ +#define LPDDR2_TCKE		(3) /* tCK */ +#define LPDDR2_TCKESR		(15) /* tCKESR, max(3tCK,15ns) */ +#define LPDDR2_TCKSRE		(1) /* tCK */ +#define LPDDR2_TCKSRX		(2) /* tCK */ + +/*mode register timing*/ +#define LPDDR2_TMOD		(0) +#define LPDDR2_TMRD		(5) /* tMRD, (=tMRW), 5 tCK */ +#define LPDDR2_TMRR		(2) /* tCK */ + +/*ZQ*/ +#define LPDDR2_TZQINIT		(1000) /* ns */ +#define LPDDR2_TZQCS		(90) /* tZQCS, max(6tCK,90ns) */ +#define LPDDR2_TZQCL		(360) /* tZQCL, max(6tCK,360ns) */ +#define LPDDR2_TZQRESET		(50) /* ZQreset, max(3tCK,50ns) */ + +/* + * Description: depend on input parameter "timing_config", + *		and calculate all lpddr2 + *		spec timing to "pdram_timing" + * parameters: + *   input: timing_config + *   output: pdram_timing + */ +static void lpddr2_get_parameter(struct timing_related_config *timing_config, +				 struct dram_timing_t *pdram_timing) +{ +	uint32_t nmhz = timing_config->freq; +	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); +	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp; + +	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t)); +	pdram_timing->mhz = nmhz; +	pdram_timing->al = 0; +	pdram_timing->bl = timing_config->bl; + +	/*	   1066 933 800 667 533 400 333 +	 * RL,	 8	 7	 6	 5	 4	 3	 3 +	 * WL,	 4	 4	 3	 2	 2	 1	 1 +	 */ +	if (nmhz <= 266) { +		pdram_timing->cl = 4; +		pdram_timing->cwl = 2; +		pdram_timing->mr[2] = LPDDR2_RL4_WL2; +	} else if (nmhz <= 333) { +		pdram_timing->cl = 5; +		pdram_timing->cwl = 2; +		pdram_timing->mr[2] = LPDDR2_RL5_WL2; +	} else if (nmhz <= 400) { +		pdram_timing->cl = 6; +		pdram_timing->cwl = 3; +		pdram_timing->mr[2] = LPDDR2_RL6_WL3; +	} else if (nmhz <= 466) { +		pdram_timing->cl = 7; +		pdram_timing->cwl = 4; +		pdram_timing->mr[2] = LPDDR2_RL7_WL4; +	} else { +		pdram_timing->cl = 8; +		pdram_timing->cwl = 4; +		pdram_timing->mr[2] = LPDDR2_RL8_WL4; +	} +	switch (timing_config->dramds) { +	case 120: +		pdram_timing->mr[3] = LPDDR2_DS_120; +		break; +	case 80: +		pdram_timing->mr[3] = LPDDR2_DS_80; +		break; +	case 60: +		pdram_timing->mr[3] = LPDDR2_DS_60; +		break; +	case 48: +		pdram_timing->mr[3] = LPDDR2_DS_48; +		break; +	case 40: +		pdram_timing->mr[3] = LPDDR2_DS_40; +		break; +	case 34: +	default: +		pdram_timing->mr[3] = LPDDR2_DS_34; +		break; +	} +	pdram_timing->mr[0] = 0; + +	pdram_timing->tinit1 = (LPDDR2_TINIT1 * nmhz + 999) / 1000; +	pdram_timing->tinit2 = LPDDR2_TINIT2; +	pdram_timing->tinit3 = (LPDDR2_TINIT3 * nmhz + 999) / 1000; +	pdram_timing->tinit4 = (LPDDR2_TINIT4 * nmhz + 999) / 1000; +	pdram_timing->tinit5 = (LPDDR2_TINIT5 * nmhz + 999) / 1000; +	pdram_timing->trstl = LPDDR2_TRSTL; +	pdram_timing->trsth = (LPDDR2_TRSTH * nmhz + 999) / 1000; +	/* +	 * tREFI, average periodic refresh interval, +	 * 15.6us(<256Mb) 7.8us(256Mb-1Gb) 3.9us(2Gb-8Gb) +	 */ +	if (ddr_capability_per_die >= 0x10000000) +		pdram_timing->trefi = (LPDDR2_TREFI_3_9_US * nmhz + 999) +							/ 1000; +	else +		pdram_timing->trefi = (LPDDR2_TREFI_7_8_US * nmhz + 999) +							/ 1000; +	/* base timing */ +	tmp = ((LPDDR2_TRCD * nmhz + 999) / 1000); +	pdram_timing->trcd = max(3, tmp); +	/* +	 * tRPpb, max(3tCK, 15ns(Fast) 18ns(Typ) 24ns(Slow), +	 */ +	trppb_tmp = ((LPDDR2_TRP_PB * nmhz + 999) / 1000); +	trppb_tmp = max(3, trppb_tmp); +	pdram_timing->trppb = trppb_tmp; +	/* +	 * tRPab, max(3tCK, 4-bank:15ns(Fast) 18ns(Typ) 24ns(Slow), +	 *	8-bank:18ns(Fast) 21ns(Typ) 27ns(Slow)) +	 */ +	trp_tmp = ((LPDDR2_TRP_AB_8_BANK * nmhz + 999) / 1000); +	trp_tmp = max(3, trp_tmp); +	pdram_timing->trp = trp_tmp; +	twr_tmp = ((LPDDR2_TWR * nmhz + 999) / 1000); +	twr_tmp = max(3, twr_tmp); +	pdram_timing->twr = twr_tmp; +	bl_tmp = (pdram_timing->bl == 16) ? LPDDR2_BL16 : +			((pdram_timing->bl == 8) ? LPDDR2_BL8 : LPDDR2_BL4); +	pdram_timing->mr[1] = bl_tmp | LPDDR2_N_WR(twr_tmp); +	tmp = ((LPDDR2_TRTP * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->trtp = max(2, tmp); +	tras_tmp = ((LPDDR2_TRAS * nmhz + 999) / 1000); +	tras_tmp = max(3, tras_tmp); +	pdram_timing->tras_min = tras_tmp; +	pdram_timing->tras_max = ((LPDDR2_TRAS_MAX * nmhz + 999) / 1000); +	pdram_timing->trc = (tras_tmp + trp_tmp); +	tmp = ((LPDDR2_TRRD * nmhz + 999) / 1000); +	pdram_timing->trrd = max(2, tmp); +	pdram_timing->tccd = LPDDR2_TCCD; +	/* tWTR, max(2tCK, 7.5ns(533-266MHz)  10ns(200-166MHz)) */ +	if (nmhz > 200) +		tmp = ((LPDDR2_TWTR_GREAT_200MHZ * nmhz + (nmhz >> 1) + +			  999) / 1000); +	else +		tmp = ((LPDDR2_TWTR_LITTLE_200MHZ * nmhz + 999) / 1000); +	pdram_timing->twtr = max(2, tmp); +	pdram_timing->trtw = LPDDR2_TRTW; +	if (nmhz <= 200) +		pdram_timing->tfaw = (LPDDR2_TFAW_LITTLE_200MHZ * nmhz + 999) +							/ 1000; +	else +		pdram_timing->tfaw = (LPDDR2_TFAW_GREAT_200MHZ * nmhz + 999) +							/ 1000; +	/* tRFC, 90ns(<=512Mb) 130ns(1Gb-4Gb) 210ns(8Gb) */ +	if (ddr_capability_per_die >= 0x40000000) { +		pdram_timing->trfc = +			(LPDDR2_TRFC_8GBIT * nmhz + 999) / 1000; +		tmp = (((LPDDR2_TRFC_8GBIT + 10) * nmhz + 999) / 1000); +	} else { +		pdram_timing->trfc = +			(LPDDR2_TRFC_4GBIT * nmhz + 999) / 1000; +		tmp = (((LPDDR2_TRFC_4GBIT + 10) * nmhz + 999) / 1000); +	} +	if (tmp < 2) +		tmp = 2; +	pdram_timing->txsr = tmp; +	pdram_timing->txsnr = tmp; +	/* tdqsck use rounded down */ +	pdram_timing->tdqsck = ((LPDDR2_TDQSCK_MIN * nmhz + (nmhz >> 1)) +					/ 1000); +	pdram_timing->tdqsck_max = +			((LPDDR2_TDQSCK_MAX * nmhz + (nmhz >> 1) + 999) +					/ 1000); +	/* pd and sr */ +	tmp = ((LPDDR2_TXP * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->txp = max(2, tmp); +	pdram_timing->txpdll = LPDDR2_TXPDLL; +	pdram_timing->tdllk = LPDDR2_TDLLK; +	pdram_timing->tcke = LPDDR2_TCKE; +	tmp = ((LPDDR2_TCKESR * nmhz + 999) / 1000); +	pdram_timing->tckesr = max(3, tmp); +	pdram_timing->tcksre = LPDDR2_TCKSRE; +	pdram_timing->tcksrx = LPDDR2_TCKSRX; +	/* mode register timing */ +	pdram_timing->tmod = LPDDR2_TMOD; +	pdram_timing->tmrd = LPDDR2_TMRD; +	pdram_timing->tmrr = LPDDR2_TMRR; +	/* ZQ */ +	pdram_timing->tzqinit = (LPDDR2_TZQINIT * nmhz + 999) / 1000; +	tmp = ((LPDDR2_TZQCS * nmhz + 999) / 1000); +	pdram_timing->tzqcs = max(6, tmp); +	tmp = ((LPDDR2_TZQCL * nmhz + 999) / 1000); +	pdram_timing->tzqoper = max(6, tmp); +	tmp = ((LPDDR2_TZQRESET * nmhz + 999) / 1000); +	pdram_timing->tzqreset = max(3, tmp); +} + +#define LPDDR3_TINIT1		(100) /* ns */ +#define LPDDR3_TINIT2		(5) /* tCK */ +#define LPDDR3_TINIT3		(200000) /* 200us */ +#define LPDDR3_TINIT4		(1000) /* 1us */ +#define LPDDR3_TINIT5		(10000) /* 10us */ +#define LPDDR3_TRSTL		(0) +#define LPDDR3_TRSTH		(0) /* 500us */ +#define LPDDR3_TREFI_3_9_US	(3900) /* 3.9us */ + +/* base timging */ +#define LPDDR3_TRCD	(18) /* tRCD,15ns(Fast)18ns(Typ)24ns(Slow) */ +#define LPDDR3_TRP_PB	(18) /* tRPpb, 15ns(Fast) 18ns(Typ) 24ns(Slow) */ +#define LPDDR3_TRP_AB	(21) /* tRPab, 18ns(Fast) 21ns(Typ) 27ns(Slow) */ +#define LPDDR3_TWR	(15) /* tWR, max(4tCK,15ns) */ +#define LPDDR3_TRTP	(7) /* tRTP, max(4tCK, 7.5ns) */ +#define LPDDR3_TRRD	(10) /* tRRD, max(2tCK,10ns) */ +#define LPDDR3_TCCD	(4) /* tCK */ +#define LPDDR3_TWTR	(7) /* tWTR, max(4tCK, 7.5ns) */ +#define LPDDR3_TRTW	(0) /* tCK register min valid value */ +#define LPDDR3_TRAS_MAX	(70000) /* 70us */ +#define LPDDR3_TRAS	(42) /* tRAS, max(3tCK,42ns) */ +#define LPDDR3_TFAW	(50) /* tFAW,max(8tCK, 50ns) */ +#define LPDDR3_TRFC_8GBIT	(210) /* tRFC, 130ns(4Gb) 210ns(>4Gb) */ +#define LPDDR3_TRFC_4GBIT	(130) /* ns */ +#define LPDDR3_TDQSCK_MIN	(2) /* tDQSCKmin,2.5ns */ +#define LPDDR3_TDQSCK_MAX	(5) /* tDQSCKmax,5.5ns */ + +/* pd and sr */ +#define LPDDR3_TXP	(7) /* tXP, max(3tCK,7.5ns) */ +#define LPDDR3_TXPDLL	(0) +#define LPDDR3_TCKE	(7) /* tCKE, (max 7.5ns,3 tCK) */ +#define LPDDR3_TCKESR	(15) /* tCKESR, max(3tCK,15ns) */ +#define LPDDR3_TCKSRE	(2) /* tCKSRE=tCPDED, 2 tCK */ +#define LPDDR3_TCKSRX	(2) /* tCKSRX, 2 tCK */ + +/* mode register timing */ +#define LPDDR3_TMOD	(0) +#define LPDDR3_TMRD	(14) /* tMRD, (=tMRW), max(14ns, 10 tCK) */ +#define LPDDR3_TMRR	(4) /* tMRR, 4 tCK */ +#define LPDDR3_TMRRI	LPDDR3_TRCD + +/* ODT */ +#define LPDDR3_TODTON	(3) /* 3.5ns */ + +/* ZQ */ +#define LPDDR3_TZQINIT	(1000) /* 1us */ +#define LPDDR3_TZQCS	(90) /* tZQCS, 90ns */ +#define LPDDR3_TZQCL	(360) /* 360ns */ +#define LPDDR3_TZQRESET	(50) /* ZQreset, max(3tCK,50ns) */ +/* write leveling */ +#define LPDDR3_TWLMRD	(40) /* ns */ +#define LPDDR3_TWLO	(20) /* ns */ +#define LPDDR3_TWLDQSEN	(25) /* ns */ +/* CA training */ +#define LPDDR3_TCACKEL	(10) /* tCK */ +#define LPDDR3_TCAENT	(10) /* tCK */ +#define LPDDR3_TCAMRD	(20) /* tCK */ +#define LPDDR3_TCACKEH	(10) /* tCK */ +#define LPDDR3_TCAEXT	(10) /* tCK */ +#define LPDDR3_TADR	(20) /* ns */ +#define LPDDR3_TMRZ	(3) /* ns */ + +/* + * Description: depend on input parameter "timing_config", + *		and calculate all lpddr3 + *		spec timing to "pdram_timing" + * parameters: + *   input: timing_config + *   output: pdram_timing + */ +static void lpddr3_get_parameter(struct timing_related_config *timing_config, +				 struct dram_timing_t *pdram_timing) +{ +	uint32_t nmhz = timing_config->freq; +	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); +	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp; + +	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t)); +	pdram_timing->mhz = nmhz; +	pdram_timing->al = 0; +	pdram_timing->bl = timing_config->bl; + +	/* +	 * Only support Write Latency Set A here +	 *     1066 933 800 733 667 600 533 400 166 +	 * RL, 16   14  12  11  10  9   8   6   3 +	 * WL, 8    8   6   6   6   5   4   3   1 +	 */ +	if (nmhz <= 400) { +		pdram_timing->cl = 6; +		pdram_timing->cwl = 3; +		pdram_timing->mr[2] = LPDDR3_RL6_WL3; +	} else if (nmhz <= 533) { +		pdram_timing->cl = 8; +		pdram_timing->cwl = 4; +		pdram_timing->mr[2] = LPDDR3_RL8_WL4; +	} else if (nmhz <= 600) { +		pdram_timing->cl = 9; +		pdram_timing->cwl = 5; +		pdram_timing->mr[2] = LPDDR3_RL9_WL5; +	} else if (nmhz <= 667) { +		pdram_timing->cl = 10; +		pdram_timing->cwl = 6; +		pdram_timing->mr[2] = LPDDR3_RL10_WL6; +	} else if (nmhz <= 733) { +		pdram_timing->cl = 11; +		pdram_timing->cwl = 6; +		pdram_timing->mr[2] = LPDDR3_RL11_WL6; +	} else if (nmhz <= 800) { +		pdram_timing->cl = 12; +		pdram_timing->cwl = 6; +		pdram_timing->mr[2] = LPDDR3_RL12_WL6; +	} else if (nmhz <= 933) { +		pdram_timing->cl = 14; +		pdram_timing->cwl = 8; +		pdram_timing->mr[2] = LPDDR3_RL14_WL8; +	} else { +		pdram_timing->cl = 16; +		pdram_timing->cwl = 8; +		pdram_timing->mr[2] = LPDDR3_RL16_WL8; +	} +	switch (timing_config->dramds) { +	case 80: +		pdram_timing->mr[3] = LPDDR3_DS_80; +		break; +	case 60: +		pdram_timing->mr[3] = LPDDR3_DS_60; +		break; +	case 48: +		pdram_timing->mr[3] = LPDDR3_DS_48; +		break; +	case 40: +		pdram_timing->mr[3] = LPDDR3_DS_40; +		break; +	case 3440: +		pdram_timing->mr[3] = LPDDR3_DS_34D_40U; +		break; +	case 4048: +		pdram_timing->mr[3] = LPDDR3_DS_40D_48U; +		break; +	case 3448: +		pdram_timing->mr[3] = LPDDR3_DS_34D_48U; +		break; +	case 34: +	default: +		pdram_timing->mr[3] = LPDDR3_DS_34; +		break; +	} +	pdram_timing->mr[0] = 0; +	switch (timing_config->dramodt) { +	case 60: +		pdram_timing->mr11 = LPDDR3_ODT_60; +		break; +	case 120: +		pdram_timing->mr11 = LPDDR3_ODT_120; +		break; +	case 240: +	default: +		pdram_timing->mr11 = LPDDR3_ODT_240; +		break; +	} + +	pdram_timing->tinit1 = (LPDDR3_TINIT1 * nmhz + 999) / 1000; +	pdram_timing->tinit2 = LPDDR3_TINIT2; +	pdram_timing->tinit3 = (LPDDR3_TINIT3 * nmhz + 999) / 1000; +	pdram_timing->tinit4 = (LPDDR3_TINIT4 * nmhz + 999) / 1000; +	pdram_timing->tinit5 = (LPDDR3_TINIT5 * nmhz + 999) / 1000; +	pdram_timing->trstl = LPDDR3_TRSTL; +	pdram_timing->trsth = (LPDDR3_TRSTH * nmhz + 999) / 1000; +	/* tREFI, average periodic refresh interval, 3.9us(4Gb-16Gb) */ +	pdram_timing->trefi = (LPDDR3_TREFI_3_9_US * nmhz + 999) / 1000; +	/* base timing */ +	tmp = ((LPDDR3_TRCD * nmhz + 999) / 1000); +	pdram_timing->trcd = max(3, tmp); +	trppb_tmp = ((LPDDR3_TRP_PB * nmhz + 999) / 1000); +	trppb_tmp = max(3, trppb_tmp); +	pdram_timing->trppb = trppb_tmp; +	trp_tmp = ((LPDDR3_TRP_AB * nmhz + 999) / 1000); +	trp_tmp = max(3, trp_tmp); +	pdram_timing->trp = trp_tmp; +	twr_tmp = ((LPDDR3_TWR * nmhz + 999) / 1000); +	twr_tmp = max(4, twr_tmp); +	pdram_timing->twr = twr_tmp; +	if (twr_tmp <= 6) +		twr_tmp = 6; +	else if (twr_tmp <= 8) +		twr_tmp = 8; +	else if (twr_tmp <= 12) +		twr_tmp = twr_tmp; +	else if (twr_tmp <= 14) +		twr_tmp = 14; +	else +		twr_tmp = 16; +	if (twr_tmp > 9) +		pdram_timing->mr[2] |= (1 << 4); /*enable nWR > 9*/ +	twr_tmp = (twr_tmp > 9) ? (twr_tmp - 10) : (twr_tmp - 2); +	bl_tmp = LPDDR3_BL8; +	pdram_timing->mr[1] = bl_tmp | LPDDR3_N_WR(twr_tmp); +	tmp = ((LPDDR3_TRTP * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->trtp = max(4, tmp); +	tras_tmp = ((LPDDR3_TRAS * nmhz + 999) / 1000); +	tras_tmp = max(3, tras_tmp); +	pdram_timing->tras_min = tras_tmp; +	pdram_timing->trc = (tras_tmp + trp_tmp); +	tmp = ((LPDDR3_TRRD * nmhz + 999) / 1000); +	pdram_timing->trrd = max(2, tmp); +	pdram_timing->tccd = LPDDR3_TCCD; +	tmp = ((LPDDR3_TWTR * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->twtr = max(4, tmp); +	pdram_timing->trtw =  ((LPDDR3_TRTW * nmhz + 999) / 1000); +	pdram_timing->tras_max = ((LPDDR3_TRAS_MAX * nmhz + 999) / 1000); +	tmp = (LPDDR3_TFAW * nmhz + 999) / 1000; +	pdram_timing->tfaw = max(8, tmp); +	if (ddr_capability_per_die > 0x20000000) { +		pdram_timing->trfc = +			(LPDDR3_TRFC_8GBIT * nmhz + 999) / 1000; +		tmp = (((LPDDR3_TRFC_8GBIT + 10) * nmhz + 999) / 1000); +	} else { +		pdram_timing->trfc = +			(LPDDR3_TRFC_4GBIT * nmhz + 999) / 1000; +		tmp = (((LPDDR3_TRFC_4GBIT + 10) * nmhz + 999) / 1000); +	} +	pdram_timing->txsr = max(2, tmp); +	pdram_timing->txsnr = max(2, tmp); +	/* tdqsck use rounded down */ +	pdram_timing->tdqsck = +			((LPDDR3_TDQSCK_MIN * nmhz + (nmhz >> 1)) +					/ 1000); +	pdram_timing->tdqsck_max = +			((LPDDR3_TDQSCK_MAX * nmhz + (nmhz >> 1) + 999) +					/ 1000); +	/*pd and sr*/ +	tmp = ((LPDDR3_TXP * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->txp = max(3, tmp); +	pdram_timing->txpdll = LPDDR3_TXPDLL; +	tmp = ((LPDDR3_TCKE * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->tcke = max(3, tmp); +	tmp = ((LPDDR3_TCKESR * nmhz + 999) / 1000); +	pdram_timing->tckesr = max(3, tmp); +	pdram_timing->tcksre = LPDDR3_TCKSRE; +	pdram_timing->tcksrx = LPDDR3_TCKSRX; +	/*mode register timing*/ +	pdram_timing->tmod = LPDDR3_TMOD; +	tmp = ((LPDDR3_TMRD * nmhz + 999) / 1000); +	pdram_timing->tmrd = max(10, tmp); +	pdram_timing->tmrr = LPDDR3_TMRR; +	tmp = ((LPDDR3_TRCD * nmhz + 999) / 1000); +	pdram_timing->tmrri = max(3, tmp); +	/* ODT */ +	pdram_timing->todton = (LPDDR3_TODTON * nmhz + (nmhz >> 1) + 999) +				/ 1000; +	/* ZQ */ +	pdram_timing->tzqinit = (LPDDR3_TZQINIT * nmhz + 999) / 1000; +	pdram_timing->tzqcs = +		((LPDDR3_TZQCS * nmhz + 999) / 1000); +	pdram_timing->tzqoper = +		((LPDDR3_TZQCL * nmhz + 999) / 1000); +	tmp = ((LPDDR3_TZQRESET * nmhz + 999) / 1000); +	pdram_timing->tzqreset = max(3, tmp); +	/* write leveling */ +	pdram_timing->twlmrd = (LPDDR3_TWLMRD * nmhz + 999) / 1000; +	pdram_timing->twlo = (LPDDR3_TWLO * nmhz + 999) / 1000; +	pdram_timing->twldqsen = (LPDDR3_TWLDQSEN * nmhz + 999) / 1000; +	/* CA training */ +	pdram_timing->tcackel = LPDDR3_TCACKEL; +	pdram_timing->tcaent = LPDDR3_TCAENT; +	pdram_timing->tcamrd = LPDDR3_TCAMRD; +	pdram_timing->tcackeh = LPDDR3_TCACKEH; +	pdram_timing->tcaext = LPDDR3_TCAEXT; +	pdram_timing->tadr = (LPDDR3_TADR * nmhz + 999) / 1000; +	pdram_timing->tmrz = (LPDDR3_TMRZ * nmhz + 999) / 1000; +	pdram_timing->tcacd = pdram_timing->tadr + 2; +} + +#define LPDDR4_TINIT1	(200000) /* 200us */ +#define LPDDR4_TINIT2	(10) /* 10ns */ +#define LPDDR4_TINIT3	(2000000) /* 2ms */ +#define LPDDR4_TINIT4	(5) /* tCK */ +#define LPDDR4_TINIT5	(2000) /* 2us */ +#define LPDDR4_TRSTL		LPDDR4_TINIT1 +#define LPDDR4_TRSTH		LPDDR4_TINIT3 +#define LPDDR4_TREFI_3_9_US	(3900) /* 3.9us */ + +/* base timging */ +#define LPDDR4_TRCD	(18) /* tRCD, max(18ns,4tCK) */ +#define LPDDR4_TRP_PB	(18) /* tRPpb, max(18ns, 4tCK) */ +#define LPDDR4_TRP_AB	(21) /* tRPab, max(21ns, 4tCK) */ +#define LPDDR4_TRRD	(10) /* tRRD, max(4tCK,10ns) */ +#define LPDDR4_TCCD_BL16	(8) /* tCK */ +#define LPDDR4_TCCD_BL32	(16) /* tCK */ +#define LPDDR4_TWTR	(10) /* tWTR, max(8tCK, 10ns) */ +#define LPDDR4_TRTW	(0) /* tCK register min valid value */ +#define LPDDR4_TRAS_MAX (70000) /* 70us */ +#define LPDDR4_TRAS	(42) /* tRAS, max(3tCK,42ns) */ +#define LPDDR4_TFAW	(40) /* tFAW,min 40ns) */ +#define LPDDR4_TRFC_12GBIT	(280) /* tRFC, 280ns(>=12Gb) */ +#define LPDDR4_TRFC_6GBIT	(180) /* 6Gb/8Gb 180ns */ +#define LPDDR4_TRFC_4GBIT	(130) /* 4Gb 130ns */ +#define LPDDR4_TDQSCK_MIN	(1) /* tDQSCKmin,1.5ns */ +#define LPDDR4_TDQSCK_MAX	(3) /* tDQSCKmax,3.5ns */ +#define LPDDR4_TPPD		(4) /* tCK */ + +/* pd and sr */ +#define LPDDR4_TXP	(7) /* tXP, max(5tCK,7.5ns) */ +#define LPDDR4_TCKE	(7) /* tCKE, max(7.5ns,4 tCK) */ +#define LPDDR4_TESCKE	(1) /* tESCKE, max(1.75ns, 3tCK) */ +#define LPDDR4_TSR	(15) /* tSR, max(15ns, 3tCK) */ +#define LPDDR4_TCMDCKE	(1) /* max(1.75ns, 3tCK) */ +#define LPDDR4_TCSCKE	(1) /* 1.75ns */ +#define LPDDR4_TCKELCS	(5) /* max(5ns, 5tCK) */ +#define LPDDR4_TCSCKEH	(1) /* 1.75ns */ +#define LPDDR4_TCKEHCS	(7) /* max(7.5ns, 5tCK) */ +#define LPDDR4_TMRWCKEL	(14) /* max(14ns, 10tCK) */ +#define LPDDR4_TCKELCMD	(7) /* max(7.5ns, 3tCK) */ +#define LPDDR4_TCKEHCMD	(7) /* max(7.5ns, 3tCK) */ +#define LPDDR4_TCKELPD	(7) /* max(7.5ns, 3tCK) */ +#define LPDDR4_TCKCKEL	(7) /* max(7.5ns, 3tCK) */ + +/* mode register timing */ +#define LPDDR4_TMRD	(14) /* tMRD, (=tMRW), max(14ns, 10 tCK) */ +#define LPDDR4_TMRR	(8) /* tMRR, 8 tCK */ + +/* ODT */ +#define LPDDR4_TODTON	(3) /* 3.5ns */ + +/* ZQ */ +#define LPDDR4_TZQCAL	(1000) /* 1us */ +#define LPDDR4_TZQLAT	(30) /* tZQLAT, max(30ns,8tCK) */ +#define LPDDR4_TZQRESET (50) /* ZQreset, max(3tCK,50ns) */ +#define LPDDR4_TZQCKE	(1) /* tZQCKE, max(1.75ns, 3tCK) */ + +/* write leveling */ +#define LPDDR4_TWLMRD	(40) /* tCK */ +#define LPDDR4_TWLO	(20) /* ns */ +#define LPDDR4_TWLDQSEN (20) /* tCK */ + +/* CA training */ +#define LPDDR4_TCAENT	(250) /* ns */ +#define LPDDR4_TADR	(20) /* ns */ +#define LPDDR4_TMRZ	(1) /* 1.5ns */ +#define LPDDR4_TVREF_LONG	(250) /* ns */ +#define LPDDR4_TVREF_SHORT	(100) /* ns */ + +/* VRCG */ +#define LPDDR4_TVRCG_ENABLE	(200) /* ns */ +#define LPDDR4_TVRCG_DISABLE	(100) /* ns */ + +/* FSP */ +#define LPDDR4_TFC_LONG		(250) /* ns */ +#define LPDDR4_TCKFSPE		(7) /* max(7.5ns, 4tCK) */ +#define LPDDR4_TCKFSPX		(7) /* max(7.5ns, 4tCK) */ + +/* + * Description: depend on input parameter "timing_config", + *              and calculate all lpddr4 + *              spec timing to "pdram_timing" + * parameters: + *   input: timing_config + *   output: pdram_timing + */ +static void lpddr4_get_parameter(struct timing_related_config *timing_config, +				 struct dram_timing_t *pdram_timing) +{ +	uint32_t nmhz = timing_config->freq; +	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); +	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp; + +	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t)); +	pdram_timing->mhz = nmhz; +	pdram_timing->al = 0; +	pdram_timing->bl = timing_config->bl; + +	/* +	 * Only support Write Latency Set A here +	 *      2133 1866 1600 1333 1066 800 533 266 +	 *  RL, 36   32   28   24   20   14  10  6 +	 *  WL, 18   16   14   12   10   8   6   4 +	 * nWR, 40   34   30   24   20   16  10  6 +	 * nRTP,16   14   12   10   8    8   8   8 +	 */ +	tmp = (timing_config->bl == 32) ? 1 : 0; + +	/* +	 * we always use WR preamble = 2tCK +	 * RD preamble = Static +	 */ +	tmp |= (1 << 2); +	if (nmhz <= 266) { +		pdram_timing->cl = 6; +		pdram_timing->cwl = 4; +		pdram_timing->twr = 6; +		pdram_timing->trtp = 8; +		pdram_timing->mr[2] = LPDDR4_RL6_NRTP8 | LPDDR4_A_WL4; +	} else if (nmhz <= 533) { +		if (timing_config->rdbi) { +			pdram_timing->cl = 12; +			pdram_timing->mr[2] = LPDDR4_RL12_NRTP8 | LPDDR4_A_WL6; +		} else { +			pdram_timing->cl = 10; +			pdram_timing->mr[2] = LPDDR4_RL10_NRTP8 | LPDDR4_A_WL6; +		} +		pdram_timing->cwl = 6; +		pdram_timing->twr = 10; +		pdram_timing->trtp = 8; +		tmp |= (1 << 4); +	} else if (nmhz <= 800) { +		if (timing_config->rdbi) { +			pdram_timing->cl = 16; +			pdram_timing->mr[2] = LPDDR4_RL16_NRTP8 | LPDDR4_A_WL8; +		} else { +			pdram_timing->cl = 14; +			pdram_timing->mr[2] = LPDDR4_RL14_NRTP8 | LPDDR4_A_WL8; +		} +		pdram_timing->cwl = 8; +		pdram_timing->twr = 16; +		pdram_timing->trtp = 8; +		tmp |= (2 << 4); +	} else if (nmhz <= 1066) { +		if (timing_config->rdbi) { +			pdram_timing->cl = 22; +			pdram_timing->mr[2] = LPDDR4_RL22_NRTP8 | LPDDR4_A_WL10; +		} else { +			pdram_timing->cl = 20; +			pdram_timing->mr[2] = LPDDR4_RL20_NRTP8 | LPDDR4_A_WL10; +		} +		pdram_timing->cwl = 10; +		pdram_timing->twr = 20; +		pdram_timing->trtp = 8; +		tmp |= (3 << 4); +	} else if (nmhz <= 1333) { +		if (timing_config->rdbi) { +			pdram_timing->cl = 28; +			pdram_timing->mr[2] = LPDDR4_RL28_NRTP10 | +						LPDDR4_A_WL12; +		} else { +			pdram_timing->cl = 24; +			pdram_timing->mr[2] = LPDDR4_RL24_NRTP10 | +						LPDDR4_A_WL12; +		} +		pdram_timing->cwl = 12; +		pdram_timing->twr = 24; +		pdram_timing->trtp = 10; +		tmp |= (4 << 4); +	} else if (nmhz <= 1600) { +		if (timing_config->rdbi) { +			pdram_timing->cl = 32; +			pdram_timing->mr[2] = LPDDR4_RL32_NRTP12 | +						LPDDR4_A_WL14; +		} else { +			pdram_timing->cl = 28; +			pdram_timing->mr[2] = LPDDR4_RL28_NRTP12 | +						LPDDR4_A_WL14; +		} +		pdram_timing->cwl = 14; +		pdram_timing->twr = 30; +		pdram_timing->trtp = 12; +		tmp |= (5 << 4); +	} else if (nmhz <= 1866) { +		if (timing_config->rdbi) { +			pdram_timing->cl = 36; +			pdram_timing->mr[2] = LPDDR4_RL36_NRTP14 | +						LPDDR4_A_WL16; +		} else { +			pdram_timing->cl = 32; +			pdram_timing->mr[2] = LPDDR4_RL32_NRTP14 | +						LPDDR4_A_WL16; +		} +		pdram_timing->cwl = 16; +		pdram_timing->twr = 34; +		pdram_timing->trtp = 14; +		tmp |= (6 << 4); +	} else { +		if (timing_config->rdbi) { +			pdram_timing->cl = 40; +			pdram_timing->mr[2] = LPDDR4_RL40_NRTP16 | +						LPDDR4_A_WL18; +		} else { +			pdram_timing->cl = 36; +			pdram_timing->mr[2] = LPDDR4_RL36_NRTP16 | +						LPDDR4_A_WL18; +		} +		pdram_timing->cwl = 18; +		pdram_timing->twr = 40; +		pdram_timing->trtp = 16; +		tmp |= (7 << 4); +	} +	pdram_timing->mr[1] = tmp; +	tmp = (timing_config->rdbi ? LPDDR4_DBI_RD_EN : 0) | +	      (timing_config->wdbi ? LPDDR4_DBI_WR_EN : 0); +	switch (timing_config->dramds) { +	case 240: +		pdram_timing->mr[3] = LPDDR4_PDDS_240 | tmp; +		break; +	case 120: +		pdram_timing->mr[3] = LPDDR4_PDDS_120 | tmp; +		break; +	case 80: +		pdram_timing->mr[3] = LPDDR4_PDDS_80 | tmp; +		break; +	case 60: +		pdram_timing->mr[3] = LPDDR4_PDDS_60 | tmp; +		break; +	case 48: +		pdram_timing->mr[3] = LPDDR4_PDDS_48 | tmp; +		break; +	case 40: +	default: +		pdram_timing->mr[3] = LPDDR4_PDDS_40 | tmp; +		break; +	} +	pdram_timing->mr[0] = 0; +	switch (timing_config->dramodt) { +	case 240: +		tmp = LPDDR4_DQODT_240; +		break; +	case 120: +		tmp = LPDDR4_DQODT_120; +		break; +	case 80: +		tmp = LPDDR4_DQODT_80; +		break; +	case 60: +		tmp = LPDDR4_DQODT_60; +		break; +	case 48: +		tmp = LPDDR4_DQODT_48; +		break; +	case 40: +	default: +		tmp = LPDDR4_DQODT_40; +		break; +	} +	switch (timing_config->caodt) { +	case 240: +		pdram_timing->mr11 = LPDDR4_CAODT_240 | tmp; +		break; +	case 120: +		pdram_timing->mr11 = LPDDR4_CAODT_120 | tmp; +		break; +	case 80: +		pdram_timing->mr11 = LPDDR4_CAODT_80 | tmp; +		break; +	case 60: +		pdram_timing->mr11 = LPDDR4_CAODT_60 | tmp; +		break; +	case 48: +		pdram_timing->mr11 = LPDDR4_CAODT_48 | tmp; +		break; +	case 40: +	default: +		pdram_timing->mr11 = LPDDR4_CAODT_40 | tmp; +		break; +	} + +	pdram_timing->tinit1 = (LPDDR4_TINIT1 * nmhz + 999) / 1000; +	pdram_timing->tinit2 = (LPDDR4_TINIT2 * nmhz + 999) / 1000; +	pdram_timing->tinit3 = (LPDDR4_TINIT3 * nmhz + 999) / 1000; +	pdram_timing->tinit4 = (LPDDR4_TINIT4 * nmhz + 999) / 1000; +	pdram_timing->tinit5 = (LPDDR4_TINIT5 * nmhz + 999) / 1000; +	pdram_timing->trstl = (LPDDR4_TRSTL * nmhz + 999) / 1000; +	pdram_timing->trsth = (LPDDR4_TRSTH * nmhz + 999) / 1000; +	/* tREFI, average periodic refresh interval, 3.9us(4Gb-16Gb) */ +	pdram_timing->trefi = (LPDDR4_TREFI_3_9_US * nmhz + 999) / 1000; +	/* base timing */ +	tmp = ((LPDDR4_TRCD * nmhz + 999) / 1000); +	pdram_timing->trcd = max(4, tmp); +	trppb_tmp = ((LPDDR4_TRP_PB * nmhz + 999) / 1000); +	trppb_tmp = max(4, trppb_tmp); +	pdram_timing->trppb = trppb_tmp; +	trp_tmp = ((LPDDR4_TRP_AB * nmhz + 999) / 1000); +	trp_tmp = max(4, trp_tmp); +	pdram_timing->trp = trp_tmp; +	tras_tmp = ((LPDDR4_TRAS * nmhz + 999) / 1000); +	tras_tmp = max(3, tras_tmp); +	pdram_timing->tras_min = tras_tmp; +	pdram_timing->trc = (tras_tmp + trp_tmp); +	tmp = ((LPDDR4_TRRD * nmhz + 999) / 1000); +	pdram_timing->trrd = max(4, tmp); +	if (timing_config->bl == 32) +		pdram_timing->tccd = LPDDR4_TCCD_BL16; +	else +		pdram_timing->tccd = LPDDR4_TCCD_BL32; +	pdram_timing->tccdmw = 4 * pdram_timing->tccd; +	tmp = ((LPDDR4_TWTR * nmhz + 999) / 1000); +	pdram_timing->twtr = max(8, tmp); +	pdram_timing->trtw =  ((LPDDR4_TRTW * nmhz + 999) / 1000); +	pdram_timing->tras_max = ((LPDDR4_TRAS_MAX * nmhz + 999) / 1000); +	pdram_timing->tfaw = (LPDDR4_TFAW * nmhz + 999) / 1000; +	if (ddr_capability_per_die > 0x60000000) { +		/* >= 12Gb */ +		pdram_timing->trfc = +			(LPDDR4_TRFC_12GBIT * nmhz + 999) / 1000; +		tmp = (((LPDDR4_TRFC_12GBIT + 7) * nmhz + (nmhz >> 1) + +				999) / 1000); +	} else if (ddr_capability_per_die > 0x30000000) { +		pdram_timing->trfc = +			(LPDDR4_TRFC_6GBIT * nmhz + 999) / 1000; +		tmp = (((LPDDR4_TRFC_6GBIT + 7) * nmhz + (nmhz >> 1) + +				999) / 1000); +	} else { +		pdram_timing->trfc = +			(LPDDR4_TRFC_4GBIT * nmhz + 999) / 1000; +		tmp = (((LPDDR4_TRFC_4GBIT + 7) * nmhz + (nmhz >> 1) + +				999) / 1000); +	} +	pdram_timing->txsr = max(2, tmp); +	pdram_timing->txsnr = max(2, tmp); +	/* tdqsck use rounded down */ +	pdram_timing->tdqsck =  ((LPDDR4_TDQSCK_MIN * nmhz + +				(nmhz >> 1)) / 1000); +	pdram_timing->tdqsck_max =  ((LPDDR4_TDQSCK_MAX * nmhz + +				(nmhz >> 1) + 999) / 1000); +	pdram_timing->tppd = LPDDR4_TPPD; +	/* pd and sr */ +	tmp = ((LPDDR4_TXP * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->txp = max(5, tmp); +	tmp = ((LPDDR4_TCKE * nmhz + (nmhz >> 1) + 999) / 1000); +	pdram_timing->tcke = max(4, tmp); +	tmp = ((LPDDR4_TESCKE * nmhz + +		((nmhz * 3) / 4) + +		999) / 1000); +	pdram_timing->tescke = max(3, tmp); +	tmp = ((LPDDR4_TSR * nmhz + 999) / 1000); +	pdram_timing->tsr = max(3, tmp); +	tmp = ((LPDDR4_TCMDCKE * nmhz + +		((nmhz * 3) / 4) + +		999) / 1000); +	pdram_timing->tcmdcke = max(3, tmp); +	pdram_timing->tcscke = ((LPDDR4_TCSCKE * nmhz + +		((nmhz * 3) / 4) + +		999) / 1000); +	tmp = ((LPDDR4_TCKELCS * nmhz + 999) / 1000); +	pdram_timing->tckelcs = max(5, tmp); +	pdram_timing->tcsckeh = ((LPDDR4_TCSCKEH * nmhz + +		((nmhz * 3) / 4) + +		999) / 1000); +	tmp = ((LPDDR4_TCKEHCS * nmhz + +		(nmhz >> 1) + 999) / 1000); +	pdram_timing->tckehcs = max(5, tmp); +	tmp = ((LPDDR4_TMRWCKEL * nmhz + 999) / 1000); +	pdram_timing->tmrwckel = max(10, tmp); +	tmp = ((LPDDR4_TCKELCMD * nmhz + (nmhz >> 1) + +		999) / 1000); +	pdram_timing->tckelcmd = max(3, tmp); +	tmp = ((LPDDR4_TCKEHCMD * nmhz + (nmhz >> 1) + +		999) / 1000); +	pdram_timing->tckehcmd = max(3, tmp); +	tmp = ((LPDDR4_TCKELPD * nmhz + (nmhz >> 1) + +		999) / 1000); +	pdram_timing->tckelpd = max(3, tmp); +	tmp = ((LPDDR4_TCKCKEL * nmhz + (nmhz >> 1) + +		999) / 1000); +	pdram_timing->tckckel = max(3, tmp); +	/* mode register timing */ +	tmp = ((LPDDR4_TMRD * nmhz + 999) / 1000); +	pdram_timing->tmrd = max(10, tmp); +	pdram_timing->tmrr = LPDDR4_TMRR; +	pdram_timing->tmrri = pdram_timing->trcd + 3; +	/* ODT */ +	pdram_timing->todton = (LPDDR4_TODTON * nmhz + (nmhz >> 1) + 999) +				/ 1000; +	/* ZQ */ +	pdram_timing->tzqcal = (LPDDR4_TZQCAL * nmhz + 999) / 1000; +	tmp = ((LPDDR4_TZQLAT * nmhz + 999) / 1000); +	pdram_timing->tzqlat = max(8, tmp); +	tmp = ((LPDDR4_TZQRESET * nmhz + 999) / 1000); +	pdram_timing->tzqreset = max(3, tmp); +	tmp = ((LPDDR4_TZQCKE * nmhz + +		((nmhz * 3) / 4) + +		999) / 1000); +	pdram_timing->tzqcke = max(3, tmp); +	/* write leveling */ +	pdram_timing->twlmrd = LPDDR4_TWLMRD; +	pdram_timing->twlo = (LPDDR4_TWLO * nmhz + 999) / 1000; +	pdram_timing->twldqsen = LPDDR4_TWLDQSEN; +	/* CA training */ +	pdram_timing->tcaent = (LPDDR4_TCAENT * nmhz + 999) / 1000; +	pdram_timing->tadr = (LPDDR4_TADR * nmhz + 999) / 1000; +	pdram_timing->tmrz = (LPDDR4_TMRZ * nmhz + (nmhz >> 1) + 999) / 1000; +	pdram_timing->tvref_long = (LPDDR4_TVREF_LONG * nmhz + 999) / 1000; +	pdram_timing->tvref_short = (LPDDR4_TVREF_SHORT * nmhz + 999) / 1000; +	/* VRCG */ +	pdram_timing->tvrcg_enable = (LPDDR4_TVRCG_ENABLE * nmhz + +					999) / 1000; +	pdram_timing->tvrcg_disable = (LPDDR4_TVRCG_DISABLE * nmhz + +					999) / 1000; +	/* FSP */ +	pdram_timing->tfc_long = (LPDDR4_TFC_LONG * nmhz + 999) / 1000; +	tmp = (LPDDR4_TCKFSPE * nmhz + (nmhz >> 1) + 999) / 1000; +	pdram_timing->tckfspe = max(4, tmp); +	tmp = (LPDDR4_TCKFSPX * nmhz + (nmhz >> 1) + 999) / 1000; +	pdram_timing->tckfspx = max(4, tmp); +} + +/* + * Description: depend on input parameter "timing_config", + *              and calculate correspond "dram_type" + *              spec timing to "pdram_timing" + * parameters: + *   input: timing_config + *   output: pdram_timing + * NOTE: MR ODT is set, need to disable by controller + */ +void dram_get_parameter(struct timing_related_config *timing_config, +			struct dram_timing_t *pdram_timing) +{ +	switch (timing_config->dram_type) { +	case DDR3: +		ddr3_get_parameter(timing_config, pdram_timing); +		break; +	case LPDDR2: +		lpddr2_get_parameter(timing_config, pdram_timing); +		break; +	case LPDDR3: +		lpddr3_get_parameter(timing_config, pdram_timing); +		break; +	case LPDDR4: +		lpddr4_get_parameter(timing_config, pdram_timing); +		break; +	} +} diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h new file mode 100644 index 00000000..2008332f --- /dev/null +++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DRAM_SPEC_TIMING_HEAD_ +#define _DRAM_SPEC_TIMING_HEAD_ +#include <stdint.h> + +enum { +	DDR3 = 3, +	LPDDR2 = 5, +	LPDDR3 = 6, +	LPDDR4 = 7, +	UNUSED = 0xFF +}; + +enum ddr3_speed_rate { +	/* 5-5-5 */ +	DDR3_800D = 0, +	/* 6-6-6 */ +	DDR3_800E = 1, +	/* 6-6-6 */ +	DDR3_1066E = 2, +	/* 7-7-7 */ +	DDR3_1066F = 3, +	/* 8-8-8 */ +	DDR3_1066G = 4, +	/* 7-7-7 */ +	DDR3_1333F = 5, +	/* 8-8-8 */ +	DDR3_1333G = 6, +	/* 9-9-9 */ +	DDR3_1333H = 7, +	/* 10-10-10 */ +	DDR3_1333J = 8, +	/* 8-8-8 */ +	DDR3_1600G = 9, +	/* 9-9-9 */ +	DDR3_1600H = 10, +	/* 10-10-10 */ +	DDR3_1600J = 11, +	/* 11-11-11 */ +	DDR3_1600K = 12, +	/* 10-10-10 */ +	DDR3_1866J = 13, +	/* 11-11-11 */ +	DDR3_1866K = 14, +	/* 12-12-12 */ +	DDR3_1866L = 15, +	/* 13-13-13 */ +	DDR3_1866M = 16, +	/* 11-11-11 */ +	DDR3_2133K = 17, +	/* 12-12-12 */ +	DDR3_2133L = 18, +	/* 13-13-13 */ +	DDR3_2133M = 19, +	/* 14-14-14 */ +	DDR3_2133N = 20, +	DDR3_DEFAULT = 21, +}; + +#define max(a, b)  (((a) > (b)) ? (a) : (b)) +#define range(mi, val, ma)  (((ma) > (val)) ? (max(mi, val)) : (ma)) + +struct dram_timing_t { +	/* unit MHz */ +	uint32_t mhz; +	/* some timing unit is us */ +	uint32_t tinit1; +	uint32_t tinit2; +	uint32_t tinit3; +	uint32_t tinit4; +	uint32_t tinit5; +	/* reset low, DDR3:200us */ +	uint32_t trstl; +	/* reset high to CKE high, DDR3:500us  */ +	uint32_t trsth; +	uint32_t trefi; +	/* base */ +	uint32_t trcd; +	/* trp per bank */ +	uint32_t trppb; +	/* trp all bank */ +	uint32_t trp; +	uint32_t twr; +	uint32_t tdal; +	uint32_t trtp; +	uint32_t trc; +	uint32_t trrd; +	uint32_t tccd; +	uint32_t twtr; +	uint32_t trtw; +	uint32_t tras_max; +	uint32_t tras_min; +	uint32_t tfaw; +	uint32_t trfc; +	uint32_t tdqsck; +	uint32_t tdqsck_max; +	/* pd or sr */ +	uint32_t txsr; +	uint32_t txsnr; +	uint32_t txp; +	uint32_t txpdll; +	uint32_t tdllk; +	uint32_t tcke; +	uint32_t tckesr; +	uint32_t tcksre; +	uint32_t tcksrx; +	uint32_t tdpd; +	/* mode regiter timing */ +	uint32_t tmod; +	uint32_t tmrd; +	uint32_t tmrr; +	uint32_t tmrri; +	/* ODT */ +	uint32_t todton; +	/* ZQ */ +	uint32_t tzqinit; +	uint32_t tzqcs; +	uint32_t tzqoper; +	uint32_t tzqreset; +	/* Write Leveling */ +	uint32_t twlmrd; +	uint32_t twlo; +	uint32_t twldqsen; +	/* CA Training */ +	uint32_t tcackel; +	uint32_t tcaent; +	uint32_t tcamrd; +	uint32_t tcackeh; +	uint32_t tcaext; +	uint32_t tadr; +	uint32_t tmrz; +	uint32_t tcacd; +	/* mode register */ +	uint32_t mr[4]; +	uint32_t mr11; +	/* lpddr4 spec */ +	uint32_t mr12; +	uint32_t mr13; +	uint32_t mr14; +	uint32_t mr16; +	uint32_t mr17; +	uint32_t mr20; +	uint32_t mr22; +	uint32_t tccdmw; +	uint32_t tppd; +	uint32_t tescke; +	uint32_t tsr; +	uint32_t tcmdcke; +	uint32_t tcscke; +	uint32_t tckelcs; +	uint32_t tcsckeh; +	uint32_t tckehcs; +	uint32_t tmrwckel; +	uint32_t tzqcal; +	uint32_t tzqlat; +	uint32_t tzqcke; +	uint32_t tvref_long; +	uint32_t tvref_short; +	uint32_t tvrcg_enable; +	uint32_t tvrcg_disable; +	uint32_t tfc_long; +	uint32_t tckfspe; +	uint32_t tckfspx; +	uint32_t tckehcmd; +	uint32_t tckelcmd; +	uint32_t tckelpd; +	uint32_t tckckel; +	/* other */ +	uint32_t al; +	uint32_t cl; +	uint32_t cwl; +	uint32_t bl; +}; + +struct dram_info_t { +	/* speed_rate only used when DDR3 */ +	enum ddr3_speed_rate speed_rate; +	/* 1: use CS0, 2: use CS0 and CS1 */ +	uint32_t cs_cnt; +	/* give the max per-die capability on each rank/cs */ +	uint32_t per_die_capability[2]; +}; + +struct timing_related_config { +	struct dram_info_t dram_info[2]; +	uint32_t dram_type; +	/* MHz */ +	uint32_t freq; +	uint32_t ch_cnt; +	uint32_t bl; +	/* 1:auto precharge, 0:never auto precharge */ +	uint32_t ap; +	/* +	 * 1:dll bypass, 0:dll normal +	 * dram and controller dll bypass at the same time +	 */ +	uint32_t dllbp; +	/* 1:odt enable, 0:odt disable */ +	uint32_t odt; +	/* 1:enable, 0:disabe */ +	uint32_t rdbi; +	uint32_t wdbi; +	/* dram driver strength */ +	uint32_t dramds; +	/* dram ODT, if odt=0, this parameter invalid */ +	uint32_t dramodt; +	/* +	 * ca ODT, if odt=0, this parameter invalid +	 * it only used by LPDDR4 +	 */ +	uint32_t caodt; +}; + +/* mr0 for ddr3 */ +#define DDR3_BL8		(0) +#define DDR3_BC4_8		(1) +#define DDR3_BC4		(2) +#define DDR3_CL(n)		(((((n) - 4) & 0x7) << 4)\ +				| ((((n) - 4) & 0x8) >> 1)) +#define DDR3_WR(n)		(((n) & 0x7) << 9) +#define DDR3_DLL_RESET		(1 << 8) +#define DDR3_DLL_DERESET	(0 << 8) + +/* mr1 for ddr3 */ +#define DDR3_DLL_ENABLE		(0) +#define DDR3_DLL_DISABLE	(1) +#define DDR3_MR1_AL(n)		(((n) & 0x3) << 3) + +#define DDR3_DS_40		(0) +#define DDR3_DS_34		(1 << 1) +#define DDR3_RTT_NOM_DIS	(0) +#define DDR3_RTT_NOM_60		(1 << 2) +#define DDR3_RTT_NOM_120	(1 << 6) +#define DDR3_RTT_NOM_40		((1 << 2) | (1 << 6)) +#define DDR3_TDQS		(1 << 11) + +/* mr2 for ddr3 */ +#define DDR3_MR2_CWL(n)		((((n) - 5) & 0x7) << 3) +#define DDR3_RTT_WR_DIS		(0) +#define DDR3_RTT_WR_60		(1 << 9) +#define DDR3_RTT_WR_120		(2 << 9) + +/* + * MR0 (Device Information) + * 0:DAI complete, 1:DAI still in progress + */ +#define LPDDR2_DAI		(0x1) +/* 0:S2 or S4 SDRAM, 1:NVM */ +#define LPDDR2_DI		(0x1 << 1) +/* 0:DNV not supported, 1:DNV supported */ +#define LPDDR2_DNVI		(0x1 << 2) +#define LPDDR2_RZQI		(0x3 << 3) + +/* + * 00:RZQ self test not supported, + * 01:ZQ-pin may connect to VDDCA or float + * 10:ZQ-pin may short to GND. + * 11:ZQ-pin self test completed, no error condition detected. + */ + +/* MR1 (Device Feature) */ +#define LPDDR2_BL4		(0x2) +#define LPDDR2_BL8		(0x3) +#define LPDDR2_BL16		(0x4) +#define LPDDR2_N_WR(n)		(((n) - 2) << 5) + +/* MR2 (Device Feature 2) */ +#define LPDDR2_RL3_WL1		(0x1) +#define LPDDR2_RL4_WL2		(0x2) +#define LPDDR2_RL5_WL2		(0x3) +#define LPDDR2_RL6_WL3		(0x4) +#define LPDDR2_RL7_WL4		(0x5) +#define LPDDR2_RL8_WL4		(0x6) + +/* MR3 (IO Configuration 1) */ +#define LPDDR2_DS_34		(0x1) +#define LPDDR2_DS_40		(0x2) +#define LPDDR2_DS_48		(0x3) +#define LPDDR2_DS_60		(0x4) +#define LPDDR2_DS_80		(0x6) +/* optional */ +#define LPDDR2_DS_120		(0x7) + +/* MR4 (Device Temperature) */ +#define LPDDR2_TREF_MASK	(0x7) +#define LPDDR2_4_TREF		(0x1) +#define LPDDR2_2_TREF		(0x2) +#define LPDDR2_1_TREF		(0x3) +#define LPDDR2_025_TREF		(0x5) +#define LPDDR2_025_TREF_DERATE	(0x6) + +#define LPDDR2_TUF		(0x1 << 7) + +/* MR8 (Basic configuration 4) */ +#define LPDDR2_S4		(0x0) +#define LPDDR2_S2		(0x1) +#define LPDDR2_N		(0x2) +/* Unit:MB */ +#define LPDDR2_DENSITY(mr8)	(8 << (((mr8) >> 2) & 0xf)) +#define LPDDR2_IO_WIDTH(mr8)	(32 >> (((mr8) >> 6) & 0x3)) + +/* MR10 (Calibration) */ +#define LPDDR2_ZQINIT		(0xff) +#define LPDDR2_ZQCL		(0xab) +#define LPDDR2_ZQCS		(0x56) +#define LPDDR2_ZQRESET		(0xc3) + +/* MR16 (PASR Bank Mask), S2 SDRAM Only */ +#define LPDDR2_PASR_FULL	(0x0) +#define LPDDR2_PASR_1_2		(0x1) +#define LPDDR2_PASR_1_4		(0x2) +#define LPDDR2_PASR_1_8		(0x3) + +/* + * MR0 (Device Information) + * 0:DAI complete, + * 1:DAI still in progress + */ +#define LPDDR3_DAI		(0x1) +/* + * 00:RZQ self test not supported, + * 01:ZQ-pin may connect to VDDCA or float + * 10:ZQ-pin may short to GND. + * 11:ZQ-pin self test completed, no error condition detected. + */ +#define LPDDR3_RZQI		(0x3 << 3) +/* + * 0:DRAM does not support WL(Set B), + * 1:DRAM support WL(Set B) + */ +#define LPDDR3_WL_SUPOT		(1 << 6) +/* + * 0:DRAM does not support RL=3,nWR=3,WL=1; + * 1:DRAM supports RL=3,nWR=3,WL=1 for frequencies <=166 + */ +#define LPDDR3_RL3_SUPOT	(1 << 7) + +/* MR1 (Device Feature) */ +#define LPDDR3_BL8		(0x3) +#define LPDDR3_N_WR(n)		((n) << 5) + +/* MR2 (Device Feature 2), WL Set A,default */ +/* <=166MHz,optional*/ +#define LPDDR3_RL3_WL1		(0x1) +/* <=400MHz*/ +#define LPDDR3_RL6_WL3		(0x4) +/* <=533MHz*/ +#define LPDDR3_RL8_WL4		(0x6) +/* <=600MHz*/ +#define LPDDR3_RL9_WL5		(0x7) +/* <=667MHz,default*/ +#define LPDDR3_RL10_WL6		(0x8) +/* <=733MHz*/ +#define LPDDR3_RL11_WL6		(0x9) +/* <=800MHz*/ +#define LPDDR3_RL12_WL6		(0xa) +/* <=933MHz*/ +#define LPDDR3_RL14_WL8		(0xc) +/* <=1066MHz*/ +#define LPDDR3_RL16_WL8		(0xe) + +/* WL Set B, optional */ +/* <=667MHz,default*/ +#define LPDDR3_RL10_WL8		(0x8) +/* <=733MHz*/ +#define LPDDR3_RL11_WL9		(0x9) +/* <=800MHz*/ +#define LPDDR3_RL12_WL9		(0xa) +/* <=933MHz*/ +#define LPDDR3_RL14_WL11	(0xc) +/* <=1066MHz*/ +#define LPDDR3_RL16_WL13	(0xe) + +/* 1:enable nWR programming > 9(default)*/ +#define LPDDR3_N_WRE		(1 << 4) +/* 1:Select WL Set B*/ +#define LPDDR3_WL_S		(1 << 6) +/* 1:enable*/ +#define LPDDR3_WR_LEVEL		(1 << 7) + +/* MR3 (IO Configuration 1) */ +#define LPDDR3_DS_34		(0x1) +#define LPDDR3_DS_40		(0x2) +#define LPDDR3_DS_48		(0x3) +#define LPDDR3_DS_60		(0x4) +#define LPDDR3_DS_80		(0x6) +#define LPDDR3_DS_34D_40U	(0x9) +#define LPDDR3_DS_40D_48U	(0xa) +#define LPDDR3_DS_34D_48U	(0xb) + +/* MR4 (Device Temperature) */ +#define LPDDR3_TREF_MASK	(0x7) +/* SDRAM Low temperature operating limit exceeded */ +#define LPDDR3_LT_EXED		(0x0) +#define LPDDR3_4_TREF		(0x1) +#define LPDDR3_2_TREF		(0x2) +#define LPDDR3_1_TREF		(0x3) +#define LPDDR3_05_TREF		(0x4) +#define LPDDR3_025_TREF		(0x5) +#define LPDDR3_025_TREF_DERATE	(0x6) +/* SDRAM High temperature operating limit exceeded */ +#define LPDDR3_HT_EXED		(0x7) + +/* 1:value has changed since last read of MR4 */ +#define LPDDR3_TUF		(0x1 << 7) + +/* MR8 (Basic configuration 4) */ +#define LPDDR3_S8		(0x3) +#define LPDDR3_DENSITY(mr8)	(8 << (((mr8) >> 2) & 0xf)) +#define LPDDR3_IO_WIDTH(mr8)	(32 >> (((mr8) >> 6) & 0x3)) + +/* MR10 (Calibration) */ +#define LPDDR3_ZQINIT		(0xff) +#define LPDDR3_ZQCL		(0xab) +#define LPDDR3_ZQCS		(0x56) +#define LPDDR3_ZQRESET		(0xc3) + +/* MR11 (ODT Control) */ +#define LPDDR3_ODT_60		(1) +#define LPDDR3_ODT_120		(2) +#define LPDDR3_ODT_240		(3) +#define LPDDR3_ODT_DIS		(0) + +/* MR2 (Device Feature 2) */ +/* RL & nRTP for DBI-RD Disabled */ +#define LPDDR4_RL6_NRTP8	(0x0) +#define LPDDR4_RL10_NRTP8	(0x1) +#define LPDDR4_RL14_NRTP8	(0x2) +#define LPDDR4_RL20_NRTP8	(0x3) +#define LPDDR4_RL24_NRTP10	(0x4) +#define LPDDR4_RL28_NRTP12	(0x5) +#define LPDDR4_RL32_NRTP14	(0x6) +#define LPDDR4_RL36_NRTP16	(0x7) +/* RL & nRTP for DBI-RD Disabled */ +#define LPDDR4_RL12_NRTP8	(0x1) +#define LPDDR4_RL16_NRTP8	(0x2) +#define LPDDR4_RL22_NRTP8	(0x3) +#define LPDDR4_RL28_NRTP10	(0x4) +#define LPDDR4_RL32_NRTP12	(0x5) +#define LPDDR4_RL36_NRTP14	(0x6) +#define LPDDR4_RL40_NRTP16	(0x7) +/* WL Set A,default */ +#define LPDDR4_A_WL4		(0x0) +#define LPDDR4_A_WL6		(0x1) +#define LPDDR4_A_WL8		(0x2) +#define LPDDR4_A_WL10		(0x3) +#define LPDDR4_A_WL12		(0x4) +#define LPDDR4_A_WL14		(0x5) +#define LPDDR4_A_WL16		(0x6) +#define LPDDR4_A_WL18		(0x7) +/* WL Set B, optional */ +#define LPDDR4_B_WL4		(0x0 << 3) +#define LPDDR4_B_WL8		(0x1 << 3) +#define LPDDR4_B_WL12		(0x2 << 3) +#define LPDDR4_B_WL18		(0x3 << 3) +#define LPDDR4_B_WL22		(0x4 << 3) +#define LPDDR4_B_WL26		(0x5 << 3) +#define LPDDR4_B_WL30		(0x6 << 3) +#define LPDDR4_B_WL34		(0x7 << 3) +/* 1:Select WL Set B*/ +#define LPDDR4_WL_B		(1 << 6) +/* 1:enable*/ +#define LPDDR4_WR_LEVEL		(1 << 7) + +/* MR3 */ +#define LPDDR4_VDDQ_2_5		(0) +#define LPDDR4_VDDQ_3		(1) +#define LPDDR4_WRPST_0_5_TCK	(0 << 1) +#define LPDDR4_WRPST_1_5_TCK	(1 << 1) +#define LPDDR4_PPR_EN		(1 << 2) +/* PDDS */ +#define LPDDR4_PDDS_240		(0x1 << 3) +#define LPDDR4_PDDS_120		(0x2 << 3) +#define LPDDR4_PDDS_80		(0x3 << 3) +#define LPDDR4_PDDS_60		(0x4 << 3) +#define LPDDR4_PDDS_48		(0x5 << 3) +#define LPDDR4_PDDS_40		(0x6 << 3) +#define LPDDR4_DBI_RD_EN	(1 << 6) +#define LPDDR4_DBI_WR_EN	(1 << 7) + +/* MR11 (ODT Control) */ +#define LPDDR4_DQODT_240	(1) +#define LPDDR4_DQODT_120	(2) +#define LPDDR4_DQODT_80		(3) +#define LPDDR4_DQODT_60		(4) +#define LPDDR4_DQODT_48		(5) +#define LPDDR4_DQODT_40		(6) +#define LPDDR4_DQODT_DIS	(0) +#define LPDDR4_CAODT_240	(1 << 4) +#define LPDDR4_CAODT_120	(2 << 4) +#define LPDDR4_CAODT_80		(3 << 4) +#define LPDDR4_CAODT_60		(4 << 4) +#define LPDDR4_CAODT_48		(5 << 4) +#define LPDDR4_CAODT_40		(6 << 4) +#define LPDDR4_CAODT_DIS	(0 << 4) + +/* + * Description: depend on input parameter "timing_config", + *		and calculate correspond "dram_type" + *		spec timing to "pdram_timing" + * parameters: + *   input: timing_config + *   output: pdram_timing + * NOTE: MR ODT is set, need to disable by controller + */ +void dram_get_parameter(struct timing_related_config *timing_config, +			struct dram_timing_t *pdram_timing); + +#endif /* _DRAM_SPEC_TIMING_HEAD_ */ diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h index 1ea6e5e1..906452a3 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.h +++ b/plat/rockchip/rk3399/drivers/soc/soc.h @@ -48,6 +48,12 @@  #define NO_PLL_BYPASS			(0x00)  #define NO_PLL_PWRDN			(0x00) +#define FBDIV(n)		((0xfff << 16) | n) +#define POSTDIV2(n)		((0x7 << (12 + 16)) | (n << 12)) +#define POSTDIV1(n)		((0x7 << (8 + 16)) | (n << 8)) +#define REFDIV(n)		((0x3F << 16) | n) +#define PLL_LOCK(n)		((n >> 31) & 0x1) +  #define PLL_SLOW_MODE			BITS_WITH_WMASK(SLOW_MODE,\  						PLL_MODE_MSK, PLL_MODE_SHIFT) @@ -107,6 +113,31 @@ struct deepsleep_data_s {  	uint32_t pmucru_gate_con[PMUCRU_GATE_COUNT];  }; +/************************************************** + * pmugrf reg, offset + **************************************************/ +#define PMUGRF_OSREG(n)		(0x300 + (n) * 4) + +/************************************************** + * DCF reg, offset + **************************************************/ +#define DCF_DCF_CTRL		0x0 +#define DCF_DCF_ADDR		0x8 +#define DCF_DCF_ISR		0xc +#define DCF_DCF_TOSET		0x14 +#define DCF_DCF_TOCMD		0x18 +#define DCF_DCF_CMD_CFG		0x1c + +/* DCF_DCF_ISR */ +#define DCF_TIMEOUT		(1 << 2) +#define DCF_ERR			(1 << 1) +#define	DCF_DONE		(1 << 0) + +/* DCF_DCF_CTRL */ +#define DCF_VOP_HW_EN		(1 << 2) +#define DCF_STOP		(1 << 1) +#define DCF_START		(1 << 0) +  #define CYCL_24M_CNT_US(us)	(24 * us)  #define CYCL_24M_CNT_MS(ms)	(ms * CYCL_24M_CNT_US(1000))  #define CYCL_32K_CNT_MS(ms)	(ms * 32) @@ -256,6 +287,12 @@ struct deepsleep_data_s {  #define PWM_DISABLE			(0 << 0)  #define PWM_ENABLE			(1 << 0) +/* grf reg offset */ +#define GRF_DDRC0_CON0		0xe380 +#define GRF_DDRC0_CON1		0xe384 +#define GRF_DDRC1_CON0		0xe388 +#define GRF_DDRC1_CON1		0xe38c +  /*   * When system reset in running state, we want the cpus to be reboot   * from maskrom (system reboot), diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c index 3d2f39a7..6069be2a 100644 --- a/plat/rockchip/rk3399/plat_sip_calls.c +++ b/plat/rockchip/rk3399/plat_sip_calls.c @@ -29,6 +29,42 @@  #include <plat_sip_calls.h>  #include <rockchip_sip_svc.h>  #include <runtime_svc.h> +#include <dram.h> + +#define RK_SIP_DDR_CFG64	0x82000008 +#define CONFIG_DRAM_INIT	0x00 +#define CONFIG_DRAM_SET_RATE	0x01 +#define CONFIG_DRAM_ROUND_RATE	0x02 +#define CONFIG_DRAM_SET_AT_SR	0x03 +#define CONFIG_DRAM_GET_BW	0x04 +#define CONFIG_DRAM_GET_RATE	0x05 +#define CONFIG_DRAM_CLR_IRQ	0x06 +#define CONFIG_DRAM_SET_PARAM   0x07 + +uint64_t ddr_smc_handler(uint64_t arg0, uint64_t arg1, uint64_t id) +{ +	switch (id) { +	case CONFIG_DRAM_INIT: +		ddr_init(); +		break; +	case CONFIG_DRAM_SET_RATE: +		return ddr_set_rate(arg0); +	case CONFIG_DRAM_ROUND_RATE: +		return ddr_round_rate(arg0); +	case CONFIG_DRAM_GET_RATE: +		return ddr_get_rate(); +	case CONFIG_DRAM_CLR_IRQ: +		clr_dcf_irq(); +		break; +	case CONFIG_DRAM_SET_PARAM: +		dts_timing_receive(arg0, arg1); +		break; +	default: +		break; +	} + +	return 0; +}  uint64_t rockchip_plat_sip_handler(uint32_t smc_fid,  				   uint64_t x1, @@ -40,6 +76,8 @@ uint64_t rockchip_plat_sip_handler(uint32_t smc_fid,  				   uint64_t flags)  {  	switch (smc_fid) { +	case RK_SIP_DDR_CFG64: +		SMC_RET1(handle, ddr_smc_handler(x1, x2, x3));  	default:  		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);  		SMC_RET1(handle, SMC_UNK); diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk index 94992f6b..36278573 100644 --- a/plat/rockchip/rk3399/platform.mk +++ b/plat/rockchip/rk3399/platform.mk @@ -40,6 +40,7 @@ PLAT_INCLUDES           :=	-I${RK_PLAT_COMMON}/				\                                  -I${RK_PLAT_SOC}/drivers/pmu/                   \  				-I${RK_PLAT_SOC}/drivers/pwm/			\                                  -I${RK_PLAT_SOC}/drivers/soc/                   \ +                                -I${RK_PLAT_SOC}/drivers/dram/			\                                  -I${RK_PLAT_SOC}/include/                       \  RK_GIC_SOURCES          :=      drivers/arm/gic/common/gic_common.c     \ @@ -76,6 +77,8 @@ BL31_SOURCES            +=      ${RK_GIC_SOURCES}  				${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c	\                                  ${RK_PLAT_SOC}/drivers/pmu/pmu.c                \  				${RK_PLAT_SOC}/drivers/pwm/pwm.c	\ -                                ${RK_PLAT_SOC}/drivers/soc/soc.c +                                ${RK_PLAT_SOC}/drivers/soc/soc.c		\ +				${RK_PLAT_SOC}/drivers/dram/dram.c		\ +				${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c  ENABLE_PLAT_COMPAT      :=      0 diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h index 8ee71a88..fdf93fd6 100644 --- a/plat/rockchip/rk3399/rk3399_def.h +++ b/plat/rockchip/rk3399/rk3399_def.h @@ -61,6 +61,12 @@  #define PWM_BASE		(MMIO_BASE + 0x1420000)  #define PWM_SIZE		SIZE_K(64) +#define CIC_BASE		(MMIO_BASE + 0x1620000) +#define CIC_SIZE		SIZE_K(4) + +#define DCF_BASE		(MMIO_BASE + 0x16a0000) +#define DCF_SIZE		SIZE_K(4) +  #define GPIO0_BASE		(MMIO_BASE + 0x1720000)  #define GPIO0_SIZE		SIZE_K(64) @@ -85,12 +91,21 @@  #define STIME_BASE		(MMIO_BASE + 0x1860000)  #define STIME_SIZE		SIZE_K(64) +#define SRAM_BASE		(MMIO_BASE + 0x18c0000) +#define SRAM_SIZE		SIZE_K(192) +  #define SERVICE_NOC_0_BASE	(MMIO_BASE + 0x1a50000)  #define NOC_0_SIZE		SIZE_K(192) +#define DDRC0_BASE		(MMIO_BASE + 0x1a80000) +#define DDRC0_SIZE		SIZE_K(32) +  #define SERVICE_NOC_1_BASE	(MMIO_BASE + 0x1a84000)  #define NOC_1_SIZE		SIZE_K(16) +#define DDRC1_BASE		(MMIO_BASE + 0x1a88000) +#define DDRC1_SIZE		SIZE_K(32) +  #define SERVICE_NOC_2_BASE	(MMIO_BASE + 0x1a8c000)  #define NOC_2_SIZE		SIZE_K(16) @@ -100,6 +115,14 @@  #define CCI500_BASE		(MMIO_BASE + 0x1b00000)  #define CCI500_SIZE		SIZE_M(1) +#define DDR_PI_OFFSET		0x800 +#define DDR_PHY_OFFSET		0x2000 + +#define DDRC0_PI_BASE		(DDRC0_BASE + DDR_PI_OFFSET) +#define DDRC0_PHY_BASE		(DDRC0_BASE + DDR_PHY_OFFSET) +#define DDRC1_PI_BASE		(DDRC1_BASE + DDR_PI_OFFSET) +#define DDRC1_PHY_BASE		(DDRC1_BASE + DDR_PHY_OFFSET) +  /* Aggregate of all devices in the first GB */  #define RK3399_DEV_RNG0_BASE	MMIO_BASE  #define RK3399_DEV_RNG0_SIZE	0x1d00000 | 
