From fe877779ee7bfd1c244be5104a3c89c95ce039b0 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 25 Aug 2016 08:37:42 +0800 Subject: [PATCH] rockchip: rk3399: add dram driver add dram driver, and kernel can through sip function talk to bl31 to do ddr frequency scaling. and ddr auto powerdown. Change-Id: I0d0f2869aed95e336c6e23ba96a9310985c84840 --- .../rockchip/rk3399/drivers/dram/dcf_code.inc | 364 +++ plat/rockchip/rk3399/drivers/dram/dram.c | 2556 +++++++++++++++++ plat/rockchip/rk3399/drivers/dram/dram.h | 328 +++ .../rk3399/drivers/dram/dram_spec_timing.c | 1323 +++++++++ .../rk3399/drivers/dram/dram_spec_timing.h | 538 ++++ plat/rockchip/rk3399/drivers/soc/soc.h | 37 + plat/rockchip/rk3399/plat_sip_calls.c | 38 + plat/rockchip/rk3399/platform.mk | 5 +- plat/rockchip/rk3399/rk3399_def.h | 23 + 9 files changed, 5211 insertions(+), 1 deletion(-) create mode 100644 plat/rockchip/rk3399/drivers/dram/dcf_code.inc create mode 100644 plat/rockchip/rk3399/drivers/dram/dram.c create mode 100644 plat/rockchip/rk3399/drivers/dram/dram.h create mode 100644 plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c create mode 100644 plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h 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..3b39e8b2 --- /dev/null +++ b/plat/rockchip/rk3399/drivers/dram/dram.c @@ -0,0 +1,2556 @@ +/* + * 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 +#include +#include +#include "dram.h" +#include "dram_spec_timing.h" +#include "string.h" +#include "soc.h" +#include "pmu.h" + +#include + +#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]; + 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 */ + low_power |= + ((read_32(&rk3399_ddr_cic->cic_ctrl1) >> + channel) & 0x1) << (3 + 8 * channel); + 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 */ + low_power |= (read_32(&ddr_pctl_regs->denali_ctl[101]) & + 0xf) << (8 * channel); + clrbits_32(&ddr_pctl_regs->denali_ctl[101], 0xf); + /* 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)) & 0xf; + 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; + + 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; + + 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); + } + + /* 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; + 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; + 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; + 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..ad344e20 --- /dev/null +++ b/plat/rockchip/rk3399/drivers/dram/dram.h @@ -0,0 +1,328 @@ +/* + * 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 { + 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; + uint32_t phy_dll_dis_freq; + uint32_t ddr3_odt_dis_freq; + uint32_t ddr3_drv; + uint32_t ddr3_odt; + uint32_t phy_ddr3_ca_drv; + uint32_t phy_ddr3_dq_drv; + uint32_t phy_ddr3_odt; + uint32_t lpddr3_odt_dis_freq; + uint32_t lpddr3_drv; + uint32_t lpddr3_odt; + uint32_t phy_lpddr3_ca_drv; + uint32_t phy_lpddr3_dq_drv; + uint32_t phy_lpddr3_odt; + uint32_t lpddr4_odt_dis_freq; + uint32_t lpddr4_drv; + uint32_t lpddr4_dq_odt; + uint32_t lpddr4_ca_odt; + uint32_t phy_lpddr4_ca_drv; + uint32_t phy_lpddr4_ck_cs_drv; + uint32_t phy_lpddr4_dq_drv; + uint32_t 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 +#include +#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 + +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 #include #include +#include + +#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 e8d4d41d..624440a1 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 -- 2.30.2