Merge pull request #750 from jwerner-chromium/m0_build

RK3399 M0 build system improvements
diff --git a/Makefile b/Makefile
index b73a4dd..abfc156 100644
--- a/Makefile
+++ b/Makefile
@@ -666,7 +666,7 @@
 
 checkpatch:		locate-checkpatch
 	@echo "  CHECKING STYLE"
-	${Q}git log -p ${BASE_COMMIT}..HEAD -- ${CHECK_PATHS} | ${CHECKPATCH} - || true
+	${Q}git format-patch --stdout ${BASE_COMMIT}..HEAD -- ${CHECK_PATHS} | ${CHECKPATCH} - || true
 
 certtool: ${CRTTOOL}
 
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index aa014f1..7534e39 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -1087,13 +1087,15 @@
 
     Argument : uintptr_t mem_base, unsigned int mem_size,
                unsigned int flags
-    Return   : void
+    Return   : int
 
 BL1 calls this function while handling FWU copy and authenticate SMCs. The
 platform must ensure that the provided `mem_base` and `mem_size` are mapped into
 BL1, and that this memory corresponds to either a secure or non-secure memory
 region as indicated by the security state of the `flags` argument.
 
+This function must return 0 on success, a non-null error code otherwise.
+
 The default implementation of this function asserts therefore platforms must
 override it when using the FWU feature.
 
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 5b73b66..140977e 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -466,6 +466,12 @@
     Note: `TRUSTED_BOARD_BOOT` is currently not supported when `LOAD_IMAGE_V2`
     is enabled.
 
+*   `ENABLE_RUNTIME_INSTRUMENTATION`: Boolean option to enable runtime
+    instrumentation which injects timestamp collection points into
+    Trusted Firmware to allow runtime performance to be measured.
+    Currently, only PSCI is instrumented. Enabling this option enables
+    the `ENABLE_PMF` build option as well. Default is 0.
+
 #### ARM development platform specific build options
 
 *   `ARM_TSP_RAM_LOCATION`: location of the TSP binary. Options:
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.c b/plat/rockchip/rk3399/drivers/dram/dfs.c
new file mode 100644
index 0000000..4fdd389
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.c
@@ -0,0 +1,2339 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <mmio.h>
+#include <plat_private.h>
+#include "dfs.h"
+#include "dram.h"
+#include "dram_spec_timing.h"
+#include "string.h"
+#include "soc.h"
+#include "pmu.h"
+
+#include <delay_timer.h>
+
+#define CTL_TRAINING	(1)
+#define PI_TRAINING		(!CTL_TRAINING)
+
+#define EN_READ_GATE_TRAINING	(1)
+#define EN_CA_TRAINING		(0)
+#define EN_WRITE_LEVELING	(0)
+#define EN_READ_LEVELING	(0)
+#define EN_WDQ_LEVELING	(0)
+
+#define ENPER_CS_TRAINING_FREQ	(933)
+
+struct pll_div {
+	unsigned int mhz;
+	unsigned int refdiv;
+	unsigned int fbdiv;
+	unsigned int postdiv1;
+	unsigned int postdiv2;
+	unsigned int frac;
+	unsigned int freq;
+};
+
+static const struct pll_div dpll_rates_table[] = {
+
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */
+	{.mhz = 933, .refdiv = 3, .fbdiv = 350, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1},
+	{.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1},
+	{.mhz = 600, .refdiv = 1, .fbdiv = 50, .postdiv1 = 2, .postdiv2 = 1},
+	{.mhz = 528, .refdiv = 1, .fbdiv = 66, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 400, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 300, .refdiv = 1, .fbdiv = 50, .postdiv1 = 4, .postdiv2 = 1},
+	{.mhz = 200, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 2},
+};
+
+struct rk3399_dram_status {
+	uint32_t current_index;
+	uint32_t index_freq[2];
+	uint32_t low_power_stat;
+	struct timing_related_config timing_config;
+	struct drv_odt_lp_config drv_odt_lp_cfg;
+};
+
+static struct rk3399_dram_status rk3399_dram_status;
+static struct ddr_dts_config_timing dts_parameter = {
+	.available = 0
+};
+
+static struct rk3399_sdram_default_config ddr3_default_config = {
+	.bl = 8,
+	.ap = 0,
+	.dramds = 40,
+	.dramodt = 120,
+	.burst_ref_cnt = 1,
+	.zqcsi = 0
+};
+
+static struct drv_odt_lp_config ddr3_drv_odt_default_config = {
+	.ddr3_speed_bin = DDR3_DEFAULT,
+	.pd_idle = 0,
+	.sr_idle = 0,
+	.sr_mc_gate_idle = 0,
+	.srpd_lite_idle = 0,
+	.standby_idle = 0,
+
+	.ddr3_dll_dis_freq = 300,
+	.phy_dll_dis_freq = 125,
+	.odt_dis_freq = 933,
+
+	.dram_side_drv = 40,
+	.dram_side_dq_odt = 120,
+	.dram_side_ca_odt = 120,
+
+	.phy_side_ca_drv = 40,
+	.phy_side_ck_cs_drv = 40,
+	.phy_side_dq_drv = 40,
+	.phy_side_odt = 240,
+};
+
+static struct rk3399_sdram_default_config lpddr3_default_config = {
+	.bl = 8,
+	.ap = 0,
+	.dramds = 34,
+	.dramodt = 240,
+	.burst_ref_cnt = 1,
+	.zqcsi = 0
+};
+
+static struct drv_odt_lp_config lpddr3_drv_odt_default_config = {
+	.ddr3_speed_bin = DDR3_DEFAULT,
+	.pd_idle = 0,
+	.sr_idle = 0,
+	.sr_mc_gate_idle = 0,
+	.srpd_lite_idle = 0,
+	.standby_idle = 0,
+
+	.ddr3_dll_dis_freq = 300,
+	.phy_dll_dis_freq = 125,
+	.odt_dis_freq = 666,
+
+	.dram_side_drv = 40,
+	.dram_side_dq_odt = 120,
+	.dram_side_ca_odt = 120,
+
+	.phy_side_ca_drv = 40,
+	.phy_side_ck_cs_drv = 40,
+	.phy_side_dq_drv = 40,
+	.phy_side_odt = 240,
+};
+
+static struct rk3399_sdram_default_config lpddr4_default_config = {
+	.bl = 16,
+	.ap = 0,
+	.dramds = 40,
+	.dramodt = 240,
+	.caodt = 240,
+	.burst_ref_cnt = 1,
+	.zqcsi = 0
+};
+
+static struct drv_odt_lp_config lpddr4_drv_odt_default_config = {
+	.ddr3_speed_bin = DDR3_DEFAULT,
+	.pd_idle = 0,
+	.sr_idle = 0,
+	.sr_mc_gate_idle = 0,
+	.srpd_lite_idle = 0,
+	.standby_idle = 0,
+
+	.ddr3_dll_dis_freq = 300,
+	.phy_dll_dis_freq = 125,
+	.odt_dis_freq = 933,
+
+	.dram_side_drv = 60,
+	.dram_side_dq_odt = 40,
+	.dram_side_ca_odt = 40,
+
+	.phy_side_ca_drv = 40,
+	.phy_side_ck_cs_drv = 80,
+	.phy_side_dq_drv = 80,
+	.phy_side_odt = 60,
+};
+
+uint32_t dcf_code[] = {
+#include "dcf_code.inc"
+};
+
+#define 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 uint32_t get_cs_die_capability(struct rk3399_sdram_params *sdram_config,
+		uint8_t channel, uint8_t cs)
+{
+	struct rk3399_sdram_channel *ch = &sdram_config->ch[channel];
+	uint32_t bandwidth;
+	uint32_t die_bandwidth;
+	uint32_t die;
+	uint32_t cs_cap;
+	uint32_t row;
+
+	row = cs == 0 ? ch->cs0_row : ch->cs1_row;
+	bandwidth = 8 * (1 << ch->bw);
+	die_bandwidth = 8 * (1 << ch->dbw);
+	die = bandwidth / die_bandwidth;
+	cs_cap = (1 << (row + ((1 << ch->bk) / 4 + 1) + ch->col +
+		  (bandwidth / 16)));
+	if (ch->row_3_4)
+		cs_cap = cs_cap * 3 / 4;
+
+	return (cs_cap / die);
+}
+
+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_params *sdram_params,
+				  struct drv_odt_lp_config *drv_config)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < sdram_params->num_channels; i++) {
+		ptiming_config->dram_info[i].speed_rate =
+		    drv_config->ddr3_speed_bin;
+		ptiming_config->dram_info[i].cs_cnt = sdram_params->ch[i].rank;
+		for (j = 0; j < sdram_params->ch[i].rank; j++) {
+			ptiming_config->dram_info[i].per_die_capability[j] =
+			    get_cs_die_capability(sdram_params, i, j);
+		}
+	}
+	ptiming_config->dram_type = sdram_params->dramtype;
+	ptiming_config->ch_cnt = sdram_params->num_channels;
+	switch (sdram_params->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;
+			mmio_write_32(CTL_REG(i, 5), tmp);
+
+			mmio_clrsetbits_32(CTL_REG(i, 22), 0xffff,
+					   pdram_timing->tdllk);
+
+			mmio_write_32(CTL_REG(i, 32),
+				      (pdram_timing->tmod << 8) |
+				       pdram_timing->tmrd);
+
+			mmio_clrsetbits_32(CTL_REG(i, 59), 0xffff << 16,
+					   (pdram_timing->txsr -
+					    pdram_timing->trcd) << 16);
+		} else if (timing_config->dram_type == LPDDR4) {
+			mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1 +
+						     pdram_timing->tinit3);
+			mmio_write_32(CTL_REG(i, 32),
+				      (pdram_timing->tmrd << 8) |
+				      pdram_timing->tmrd);
+			mmio_clrsetbits_32(CTL_REG(i, 59), 0xffff << 16,
+					   pdram_timing->txsr << 16);
+		} else {
+			mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1);
+			mmio_write_32(CTL_REG(i, 7), pdram_timing->tinit4);
+			mmio_write_32(CTL_REG(i, 32),
+				      (pdram_timing->tmrd << 8) |
+				      pdram_timing->tmrd);
+			mmio_clrsetbits_32(CTL_REG(i, 59), 0xffff << 16,
+					   pdram_timing->txsr << 16);
+		}
+		mmio_write_32(CTL_REG(i, 6), pdram_timing->tinit3);
+		mmio_write_32(CTL_REG(i, 8), pdram_timing->tinit5);
+		mmio_clrsetbits_32(CTL_REG(i, 23), (0x7f << 16),
+				   ((pdram_timing->cl * 2) << 16));
+		mmio_clrsetbits_32(CTL_REG(i, 23), (0x1f << 24),
+				   (pdram_timing->cwl << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f, pdram_timing->al);
+		mmio_clrsetbits_32(CTL_REG(i, 26), 0xffff << 16,
+				   (pdram_timing->trc << 24) |
+				   (pdram_timing->trrd << 16));
+		mmio_write_32(CTL_REG(i, 27),
+			      (pdram_timing->tfaw << 24) |
+			      (pdram_timing->trppb << 16) |
+			      (pdram_timing->twtr << 8) |
+			      pdram_timing->tras_min);
+
+		mmio_clrsetbits_32(CTL_REG(i, 31), 0xff << 24,
+				   max(4, pdram_timing->trtp) << 24);
+		mmio_write_32(CTL_REG(i, 33), (pdram_timing->tcke << 24) |
+					      pdram_timing->tras_max);
+		mmio_clrsetbits_32(CTL_REG(i, 34), 0xff,
+				   max(1, pdram_timing->tckesr));
+		mmio_clrsetbits_32(CTL_REG(i, 39),
+				   (0x3f << 16) | (0xff << 8),
+				   (pdram_timing->twr << 16) |
+				   (pdram_timing->trcd << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 16,
+				   pdram_timing->tmrz << 16);
+		tmp = pdram_timing->tdal ? pdram_timing->tdal :
+		      (pdram_timing->twr + pdram_timing->trp);
+		mmio_clrsetbits_32(CTL_REG(i, 44), 0xff, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 45), 0xff, pdram_timing->trp);
+		mmio_write_32(CTL_REG(i, 48),
+			      ((pdram_timing->trefi - 8) << 16) |
+			      pdram_timing->trfc);
+		mmio_clrsetbits_32(CTL_REG(i, 52), 0xffff, pdram_timing->txp);
+		mmio_clrsetbits_32(CTL_REG(i, 53), 0xffff << 16,
+				   pdram_timing->txpdll << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 55), 0xf << 24,
+				   pdram_timing->tcscke << 24);
+		mmio_clrsetbits_32(CTL_REG(i, 55), 0xff, pdram_timing->tmrri);
+		mmio_write_32(CTL_REG(i, 56),
+			      (pdram_timing->tzqcke << 24) |
+			      (pdram_timing->tmrwckel << 16) |
+			      (pdram_timing->tckehcs << 8) |
+			      pdram_timing->tckelcs);
+		mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff, pdram_timing->txsnr);
+		mmio_clrsetbits_32(CTL_REG(i, 62), 0xffff << 16,
+				   (pdram_timing->tckehcmd << 24) |
+				   (pdram_timing->tckelcmd << 16));
+		mmio_write_32(CTL_REG(i, 63),
+			      (pdram_timing->tckelpd << 24) |
+			      (pdram_timing->tescke << 16) |
+			      (pdram_timing->tsr << 8) |
+			      pdram_timing->tckckel);
+		mmio_clrsetbits_32(CTL_REG(i, 64), 0xfff,
+				   (pdram_timing->tcmdcke << 8) |
+				   pdram_timing->tcsckeh);
+		mmio_clrsetbits_32(CTL_REG(i, 92), 0xffff << 8,
+				   (pdram_timing->tcksrx << 16) |
+				   (pdram_timing->tcksre << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 108), 0x1 << 24,
+				   (timing_config->dllbp << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 122), 0x3ff << 16,
+				   (pdram_timing->tvrcg_enable << 16));
+		mmio_write_32(CTL_REG(i, 123), (pdram_timing->tfc_long << 16) |
+					       pdram_timing->tvrcg_disable);
+		mmio_write_32(CTL_REG(i, 124),
+			      (pdram_timing->tvref_long << 16) |
+			      (pdram_timing->tckfspx << 8) |
+			      pdram_timing->tckfspe);
+		mmio_write_32(CTL_REG(i, 133), (pdram_timing->mr[1] << 16) |
+					       pdram_timing->mr[0]);
+		mmio_clrsetbits_32(CTL_REG(i, 134), 0xffff,
+				   pdram_timing->mr[2]);
+		mmio_clrsetbits_32(CTL_REG(i, 138), 0xffff,
+				   pdram_timing->mr[3]);
+		mmio_clrsetbits_32(CTL_REG(i, 139), 0xff << 24,
+				   pdram_timing->mr11 << 24);
+		mmio_write_32(CTL_REG(i, 147),
+			      (pdram_timing->mr[1] << 16) |
+			      pdram_timing->mr[0]);
+		mmio_clrsetbits_32(CTL_REG(i, 148), 0xffff,
+				   pdram_timing->mr[2]);
+		mmio_clrsetbits_32(CTL_REG(i, 152), 0xffff,
+				   pdram_timing->mr[3]);
+		mmio_clrsetbits_32(CTL_REG(i, 153), 0xff << 24,
+				   pdram_timing->mr11 << 24);
+		if (timing_config->dram_type == LPDDR4) {
+			mmio_clrsetbits_32(CTL_REG(i, 140), 0xffff << 16,
+					   pdram_timing->mr12 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 142), 0xffff << 16,
+					   pdram_timing->mr14 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 145), 0xffff << 16,
+					   pdram_timing->mr22 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 154), 0xffff << 16,
+					   pdram_timing->mr12 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 156), 0xffff << 16,
+					   pdram_timing->mr14 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 159), 0xffff << 16,
+					   pdram_timing->mr22 << 16);
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 179), 0xfff << 8,
+				   pdram_timing->tzqinit << 8);
+		mmio_write_32(CTL_REG(i, 180), (pdram_timing->tzqcs << 16) |
+					       (pdram_timing->tzqinit / 2));
+		mmio_write_32(CTL_REG(i, 181), (pdram_timing->tzqlat << 16) |
+					       pdram_timing->tzqcal);
+		mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 8,
+				   pdram_timing->todton << 8);
+
+		if (timing_config->odt) {
+			mmio_setbits_32(CTL_REG(i, 213), 1 << 16);
+			if (timing_config->freq < 400)
+				tmp = 4 << 24;
+			else
+				tmp = 8 << 24;
+		} else {
+			mmio_clrbits_32(CTL_REG(i, 213), 1 << 16);
+			tmp = 2 << 24;
+		}
+
+		mmio_clrsetbits_32(CTL_REG(i, 216), 0x1f << 24, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 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);
+		mmio_clrsetbits_32(CTL_REG(i, 284), 0xffff, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 82), 0xffff << 16,
+				   (4 * pdram_timing->trefi) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 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;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 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;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 8,
+				   (tmp & 0x3f) << 8);
+
+		mmio_clrsetbits_32(CTL_REG(i, 275), 0xff << 16,
+				   (get_pi_tdfi_phy_rdlat(pdram_timing,
+							  timing_config) &
+				    0xff) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 277), 0xffff,
+				   (2 * pdram_timing->trefi) & 0xffff);
+
+		mmio_clrsetbits_32(CTL_REG(i, 282), 0xffff,
+				   (2 * pdram_timing->trefi) & 0xffff);
+
+		mmio_write_32(CTL_REG(i, 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;
+		mmio_clrsetbits_32(CTL_REG(i, 308), 0x3ff << 16, tmp << 16);
+
+		/* CTL_308 TDFI_CALVL_CC_F0:RW:0:10 */
+		tmp = tmp + 18;
+		mmio_clrsetbits_32(CTL_REG(i, 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 == 0)
+				tmp = 0;
+			else if (tmp1 < 5)
+				tmp = tmp1 - 1;
+			else
+				tmp = tmp1 - 5;
+		} else {
+			tmp = tmp1 - 2;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 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;
+		mmio_clrsetbits_32(CTL_REG(i, 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;
+			mmio_write_32(CTL_REG(i, 9), tmp);
+			mmio_clrsetbits_32(CTL_REG(i, 22), 0xffff << 16,
+					   pdram_timing->tdllk << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
+					   (pdram_timing->tmod << 24) |
+					   (pdram_timing->tmrd << 16) |
+					   (pdram_timing->trtp << 8));
+			mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff << 16,
+					   (pdram_timing->txsr -
+					    pdram_timing->trcd) << 16);
+		} else if (timing_config->dram_type == LPDDR4) {
+			mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1 +
+						     pdram_timing->tinit3);
+			mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
+					   (pdram_timing->tmrd << 24) |
+					   (pdram_timing->tmrd << 16) |
+					   (pdram_timing->trtp << 8));
+			mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff << 16,
+					   pdram_timing->txsr << 16);
+		} else {
+			mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1);
+			mmio_write_32(CTL_REG(i, 11), pdram_timing->tinit4);
+			mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
+					   (pdram_timing->tmrd << 24) |
+					   (pdram_timing->tmrd << 16) |
+					   (pdram_timing->trtp << 8));
+			mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff << 16,
+					   pdram_timing->txsr << 16);
+		}
+		mmio_write_32(CTL_REG(i, 10), pdram_timing->tinit3);
+		mmio_write_32(CTL_REG(i, 12), pdram_timing->tinit5);
+		mmio_clrsetbits_32(CTL_REG(i, 24), (0x7f << 8),
+				   ((pdram_timing->cl * 2) << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 24), (0x1f << 16),
+				   (pdram_timing->cwl << 16));
+		mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f << 24,
+				   pdram_timing->al << 24);
+		mmio_clrsetbits_32(CTL_REG(i, 28), 0xffffff00,
+				   (pdram_timing->tras_min << 24) |
+				   (pdram_timing->trc << 16) |
+				   (pdram_timing->trrd << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 29), 0xffffff,
+				   (pdram_timing->tfaw << 16) |
+				   (pdram_timing->trppb << 8) |
+				   pdram_timing->twtr);
+		mmio_write_32(CTL_REG(i, 35), (pdram_timing->tcke << 24) |
+					      pdram_timing->tras_max);
+		mmio_clrsetbits_32(CTL_REG(i, 36), 0xff,
+				   max(1, pdram_timing->tckesr));
+		mmio_clrsetbits_32(CTL_REG(i, 39), (0xff << 24),
+				   (pdram_timing->trcd << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 40), 0x3f, pdram_timing->twr);
+		mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 24,
+				   pdram_timing->tmrz << 24);
+		tmp = pdram_timing->tdal ? pdram_timing->tdal :
+		      (pdram_timing->twr + pdram_timing->trp);
+		mmio_clrsetbits_32(CTL_REG(i, 44), 0xff << 8, tmp << 8);
+		mmio_clrsetbits_32(CTL_REG(i, 45), 0xff << 8,
+				   pdram_timing->trp << 8);
+		mmio_write_32(CTL_REG(i, 49),
+			      ((pdram_timing->trefi - 8) << 16) |
+			      pdram_timing->trfc);
+		mmio_clrsetbits_32(CTL_REG(i, 52), 0xffff << 16,
+				   pdram_timing->txp << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 54), 0xffff,
+				   pdram_timing->txpdll);
+		mmio_clrsetbits_32(CTL_REG(i, 55), 0xff << 8,
+				   pdram_timing->tmrri << 8);
+		mmio_write_32(CTL_REG(i, 57), (pdram_timing->tmrwckel << 24) |
+					      (pdram_timing->tckehcs << 16) |
+					      (pdram_timing->tckelcs << 8) |
+					      pdram_timing->tcscke);
+		mmio_clrsetbits_32(CTL_REG(i, 58), 0xf, pdram_timing->tzqcke);
+		mmio_clrsetbits_32(CTL_REG(i, 61), 0xffff, pdram_timing->txsnr);
+		mmio_clrsetbits_32(CTL_REG(i, 64), 0xffff << 16,
+				   (pdram_timing->tckehcmd << 24) |
+				   (pdram_timing->tckelcmd << 16));
+		mmio_write_32(CTL_REG(i, 65), (pdram_timing->tckelpd << 24) |
+					      (pdram_timing->tescke << 16) |
+					      (pdram_timing->tsr << 8) |
+					      pdram_timing->tckckel);
+		mmio_clrsetbits_32(CTL_REG(i, 66), 0xfff,
+				   (pdram_timing->tcmdcke << 8) |
+				   pdram_timing->tcsckeh);
+		mmio_clrsetbits_32(CTL_REG(i, 92), (0xff << 24),
+				   (pdram_timing->tcksre << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 93), 0xff,
+				   pdram_timing->tcksrx);
+		mmio_clrsetbits_32(CTL_REG(i, 108), (0x1 << 25),
+				   (timing_config->dllbp << 25));
+		mmio_write_32(CTL_REG(i, 125),
+			      (pdram_timing->tvrcg_disable << 16) |
+			      pdram_timing->tvrcg_enable);
+		mmio_write_32(CTL_REG(i, 126), (pdram_timing->tckfspx << 24) |
+					       (pdram_timing->tckfspe << 16) |
+					       pdram_timing->tfc_long);
+		mmio_clrsetbits_32(CTL_REG(i, 127), 0xffff,
+				   pdram_timing->tvref_long);
+		mmio_clrsetbits_32(CTL_REG(i, 134), 0xffff << 16,
+				   pdram_timing->mr[0] << 16);
+		mmio_write_32(CTL_REG(i, 135), (pdram_timing->mr[2] << 16) |
+					       pdram_timing->mr[1]);
+		mmio_clrsetbits_32(CTL_REG(i, 138), 0xffff << 16,
+				   pdram_timing->mr[3] << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 140), 0xff, pdram_timing->mr11);
+		mmio_clrsetbits_32(CTL_REG(i, 148), 0xffff << 16,
+				   pdram_timing->mr[0] << 16);
+		mmio_write_32(CTL_REG(i, 149), (pdram_timing->mr[2] << 16) |
+					       pdram_timing->mr[1]);
+		mmio_clrsetbits_32(CTL_REG(i, 152), 0xffff << 16,
+				   pdram_timing->mr[3] << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 154), 0xff, pdram_timing->mr11);
+		if (timing_config->dram_type == LPDDR4) {
+			mmio_clrsetbits_32(CTL_REG(i, 141), 0xffff,
+					   pdram_timing->mr12);
+			mmio_clrsetbits_32(CTL_REG(i, 143), 0xffff,
+					   pdram_timing->mr14);
+			mmio_clrsetbits_32(CTL_REG(i, 146), 0xffff,
+					   pdram_timing->mr22);
+			mmio_clrsetbits_32(CTL_REG(i, 155), 0xffff,
+					   pdram_timing->mr12);
+			mmio_clrsetbits_32(CTL_REG(i, 157), 0xffff,
+					   pdram_timing->mr14);
+			mmio_clrsetbits_32(CTL_REG(i, 160), 0xffff,
+					   pdram_timing->mr22);
+		}
+		mmio_write_32(CTL_REG(i, 182),
+			      ((pdram_timing->tzqinit / 2) << 16) |
+			      pdram_timing->tzqinit);
+		mmio_write_32(CTL_REG(i, 183), (pdram_timing->tzqcal << 16) |
+					       pdram_timing->tzqcs);
+		mmio_clrsetbits_32(CTL_REG(i, 184), 0x3f, pdram_timing->tzqlat);
+		mmio_clrsetbits_32(CTL_REG(i, 188), 0xfff,
+				   pdram_timing->tzqreset);
+		mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 16,
+				   pdram_timing->todton << 16);
+
+		if (timing_config->odt) {
+			mmio_setbits_32(CTL_REG(i, 213), (1 << 24));
+			if (timing_config->freq < 400)
+				tmp = 4 << 24;
+			else
+				tmp = 8 << 24;
+		} else {
+			mmio_clrbits_32(CTL_REG(i, 213), (1 << 24));
+			tmp = 2 << 24;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 217), 0x1f << 24, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 221), 0xf << 24,
+				   (pdram_timing->tdqsck_max << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 222), 0x3, pdram_timing->tdqsck);
+		mmio_clrsetbits_32(CTL_REG(i, 291), 0xffff,
+				   (get_wrlat_adj(timing_config->dram_type,
+						  pdram_timing->cwl) << 8) |
+				   get_rdlat_adj(timing_config->dram_type,
+						 pdram_timing->cl));
+
+		mmio_clrsetbits_32(CTL_REG(i, 84), 0xffff,
+				   (4 * pdram_timing->trefi) & 0xffff);
+
+		mmio_clrsetbits_32(CTL_REG(i, 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;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 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);
+			tmp--;
+			/* 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;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 16,
+				   (tmp & 0x3f) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 275), 0xff << 24,
+				   (get_pi_tdfi_phy_rdlat(pdram_timing,
+							  timing_config) &
+				    0xff) << 24);
+
+		mmio_clrsetbits_32(CTL_REG(i, 284), 0xffff << 16,
+				   ((2 * pdram_timing->trefi) & 0xffff) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 289), 0xffff,
+				   (2 * pdram_timing->trefi) & 0xffff);
+
+		mmio_write_32(CTL_REG(i, 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;
+		mmio_clrsetbits_32(CTL_REG(i, 309), 0x3ff << 16, tmp << 16);
+
+		/* CTL_309 TDFI_CALVL_CC_F1:RW:0:10 */
+		tmp = tmp + 18;
+		mmio_clrsetbits_32(CTL_REG(i, 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 == 0)
+				tmp = 0;
+			else if (tmp1 < 5)
+				tmp = tmp1 - 1;
+			else
+				tmp = tmp1 - 5;
+		} else {
+			tmp = tmp1 - 2;
+		}
+
+		mmio_clrsetbits_32(CTL_REG(i, 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;
+		mmio_clrsetbits_32(CTL_REG(i, 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)
+			mmio_setbits_32(CTL_REG(i, 305), 1 << 16);
+		if (tmp0)
+			mmio_setbits_32(CTL_REG(i, 70), tmp0);
+		if (tmp1)
+			mmio_setbits_32(CTL_REG(i, 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;
+		mmio_write_32(PI_REG(i, 2), tmp);
+		/* PI_03 PI_TDFI_PHYMSTR_RESP_F0:RW:0:16 */
+		tmp = 2 * pdram_timing->trefi;
+		mmio_clrsetbits_32(PI_REG(i, 3), 0xffff, tmp);
+		/* PI_07 PI_TDFI_PHYUPD_RESP_F0:RW:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 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);
+		mmio_clrsetbits_32(PI_REG(i, 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);
+			mmio_clrsetbits_32(PI_REG(i, 43), 0x1f, tmp);
+		}
+		/* PI_43 PI_ADDITIVE_LAT_F0:RW:8:6 */
+		mmio_clrsetbits_32(PI_REG(i, 43), 0x3f << 8,
+				   PI_ADD_LATENCY << 8);
+
+		/* PI_43 PI_CASLAT_LIN_F0:RW:16:7 */
+		mmio_clrsetbits_32(PI_REG(i, 43), 0x7f << 16,
+				   (pdram_timing->cl * 2) << 16);
+		/* PI_46 PI_TREF_F0:RW:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 46), 0xffff << 16,
+				   pdram_timing->trefi << 16);
+		/* PI_46 PI_TRFC_F0:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 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);
+			mmio_clrsetbits_32(PI_REG(i, 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;
+		}
+		mmio_clrsetbits_32(PI_REG(i, 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;
+			tmp1 += get_pi_todtoff_min(pdram_timing, timing_config);
+			tmp1--;
+			/* 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;
+		}
+		mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 8, tmp << 8);
+		/* PI_89 PI_RDLAT_ADJ_F0:RW:16:8 */
+		tmp = get_pi_rdlat_adj(pdram_timing);
+		mmio_clrsetbits_32(PI_REG(i, 89), 0xff << 16, tmp << 16);
+		/* PI_90 PI_WRLAT_ADJ_F0:RW:16:8 */
+		tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
+		mmio_clrsetbits_32(PI_REG(i, 90), 0xff << 16, tmp << 16);
+		/* PI_91 PI_TDFI_WRCSLAT_F0:RW:16:8 */
+		tmp1 = tmp;
+		if (tmp1 == 0)
+			tmp = 0;
+		else if (tmp1 < 5)
+			tmp = tmp1 - 1;
+		else
+			tmp = tmp1 - 5;
+		mmio_clrsetbits_32(PI_REG(i, 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;
+		mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff << 16, tmp << 16);
+		/* PI_95 PI_TDFI_CALVL_CC_F0:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff, tmp + 18);
+		/* PI_102 PI_TMRZ_F0:RW:8:5 */
+		mmio_clrsetbits_32(PI_REG(i, 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;
+		mmio_clrsetbits_32(PI_REG(i, 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;
+		mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 16, tmp << 16);
+		/* PI_125 PI_MR1_DATA_F0_0:RW+:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 125), 0xffff << 8,
+				   pdram_timing->mr[1] << 8);
+		/* PI_133 PI_MR1_DATA_F0_1:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 133), 0xffff, pdram_timing->mr[1]);
+		/* PI_140 PI_MR1_DATA_F0_2:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 140), 0xffff << 16,
+				   pdram_timing->mr[1] << 16);
+		/* PI_148 PI_MR1_DATA_F0_3:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 148), 0xffff, pdram_timing->mr[1]);
+		/* PI_126 PI_MR2_DATA_F0_0:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 126), 0xffff, pdram_timing->mr[2]);
+		/* PI_133 PI_MR2_DATA_F0_1:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 133), 0xffff << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_141 PI_MR2_DATA_F0_2:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 141), 0xffff, pdram_timing->mr[2]);
+		/* PI_148 PI_MR2_DATA_F0_3:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 148), 0xffff << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_156 PI_TFC_F0:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff, pdram_timing->trfc);
+		/* PI_158 PI_TWR_F0:RW:24:6 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 24,
+				   pdram_timing->twr << 24);
+		/* PI_158 PI_TWTR_F0:RW:16:6 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 16,
+				   pdram_timing->twtr << 16);
+		/* PI_158 PI_TRCD_F0:RW:8:8 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0xff << 8,
+				   pdram_timing->trcd << 8);
+		/* PI_158 PI_TRP_F0:RW:0:8 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0xff, pdram_timing->trp);
+		/* PI_157 PI_TRTP_F0:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 157), 0xff << 24,
+				   pdram_timing->trtp << 24);
+		/* PI_159 PI_TRAS_MIN_F0:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 159), 0xff << 24,
+				   pdram_timing->tras_min << 24);
+		/* PI_159 PI_TRAS_MAX_F0:RW:0:17 */
+		tmp = pdram_timing->tras_max * 99 / 100;
+		mmio_clrsetbits_32(PI_REG(i, 159), 0x1ffff, tmp);
+		/* PI_160 PI_TMRD_F0:RW:16:6 */
+		mmio_clrsetbits_32(PI_REG(i, 160), 0x3f << 16,
+				   pdram_timing->tmrd << 16);
+		/*PI_160 PI_TDQSCK_MAX_F0:RW:0:4 */
+		mmio_clrsetbits_32(PI_REG(i, 160), 0xf,
+				   pdram_timing->tdqsck_max);
+		/* PI_187 PI_TDFI_CTRLUPD_MAX_F0:RW:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 187), 0xffff << 8,
+				   (2 * pdram_timing->trefi) << 8);
+		/* PI_188 PI_TDFI_CTRLUPD_INTERVAL_F0:RW:0:32 */
+		mmio_clrsetbits_32(PI_REG(i, 188), 0xffffffff,
+				   20 * pdram_timing->trefi);
+	}
+}
+
+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;
+		mmio_write_32(PI_REG(i, 4), tmp);
+		/* PI_05 PI_TDFI_PHYMSTR_RESP_F1:RW:0:16 */
+		tmp = 2 * pdram_timing->trefi;
+		mmio_clrsetbits_32(PI_REG(i, 5), 0xffff, tmp);
+		/* PI_12 PI_TDFI_PHYUPD_RESP_F1:RW:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 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);
+		mmio_clrsetbits_32(PI_REG(i, 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);
+			mmio_clrsetbits_32(PI_REG(i, 43), 0x1f << 24,
+					   tmp << 24);
+		}
+		/* PI_44 PI_ADDITIVE_LAT_F1:RW:0:6 */
+		mmio_clrsetbits_32(PI_REG(i, 44), 0x3f, PI_ADD_LATENCY);
+		/* PI_44 PI_CASLAT_LIN_F1:RW:8:7:=0x18 */
+		mmio_clrsetbits_32(PI_REG(i, 44), 0x7f << 8,
+				   pdram_timing->cl * 2);
+		/* PI_47 PI_TREF_F1:RW:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 47), 0xffff << 16,
+				   pdram_timing->trefi << 16);
+		/* PI_47 PI_TRFC_F1:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 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);
+			mmio_clrsetbits_32(PI_REG(i, 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;
+		}
+		mmio_clrsetbits_32(PI_REG(i, 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);
+			tmp1--;
+			/* 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;
+
+		mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 16, tmp << 16);
+		/*P I_89 PI_RDLAT_ADJ_F1:RW:24:8 */
+		tmp = get_pi_rdlat_adj(pdram_timing);
+		mmio_clrsetbits_32(PI_REG(i, 89), 0xff << 24, tmp << 24);
+		/* PI_90 PI_WRLAT_ADJ_F1:RW:24:8 */
+		tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
+		mmio_clrsetbits_32(PI_REG(i, 90), 0xff << 24, tmp << 24);
+		/* PI_91 PI_TDFI_WRCSLAT_F1:RW:24:8 */
+		tmp1 = tmp;
+		if (tmp1 == 0)
+			tmp = 0;
+		else if (tmp1 < 5)
+			tmp = tmp1 - 1;
+		else
+			tmp = tmp1 - 5;
+		mmio_clrsetbits_32(PI_REG(i, 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;
+		mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff << 16, tmp << 16);
+		/* PI_96 PI_TDFI_CALVL_CC_F1:RW:0:10 */
+		tmp = tmp + 18;
+		mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff, tmp);
+		/*PI_103 PI_TMRZ_F1:RW:0:5 */
+		mmio_clrsetbits_32(PI_REG(i, 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;
+		mmio_clrsetbits_32(PI_REG(i, 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;
+		mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 24,
+				   tmp << 24);
+		/* PI_128 PI_MR1_DATA_F1_0:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 128), 0xffff, pdram_timing->mr[1]);
+		/* PI_135 PI_MR1_DATA_F1_1:RW+:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 135), 0xffff << 8,
+				   pdram_timing->mr[1] << 8);
+		/* PI_143 PI_MR1_DATA_F1_2:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 143), 0xffff, pdram_timing->mr[1]);
+		/* PI_150 PI_MR1_DATA_F1_3:RW+:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 150), 0xffff << 8,
+				   pdram_timing->mr[1] << 8);
+		/* PI_128 PI_MR2_DATA_F1_0:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 128), 0xffff << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_136 PI_MR2_DATA_F1_1:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 136), 0xffff, pdram_timing->mr[2]);
+		/* PI_143 PI_MR2_DATA_F1_2:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 143), 0xffff << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_151 PI_MR2_DATA_F1_3:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 151), 0xffff, pdram_timing->mr[2]);
+		/* PI_156 PI_TFC_F1:RW:16:10 */
+		mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff << 16,
+				   pdram_timing->trfc << 16);
+		/* PI_162 PI_TWR_F1:RW:8:6 */
+		mmio_clrsetbits_32(PI_REG(i, 162), 0x3f << 8,
+				   pdram_timing->twr << 8);
+		/* PI_162 PI_TWTR_F1:RW:0:6 */
+		mmio_clrsetbits_32(PI_REG(i, 162), 0x3f, pdram_timing->twtr);
+		/* PI_161 PI_TRCD_F1:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 24,
+				   pdram_timing->trcd << 24);
+		/* PI_161 PI_TRP_F1:RW:16:8 */
+		mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 16,
+				   pdram_timing->trp << 16);
+		/* PI_161 PI_TRTP_F1:RW:8:8 */
+		mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 8,
+				   pdram_timing->trtp << 8);
+		/* PI_163 PI_TRAS_MIN_F1:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 163), 0xff << 24,
+				   pdram_timing->tras_min << 24);
+		/* PI_163 PI_TRAS_MAX_F1:RW:0:17 */
+		mmio_clrsetbits_32(PI_REG(i, 163), 0x1ffff,
+				   pdram_timing->tras_max * 99 / 100);
+		/* PI_164 PI_TMRD_F1:RW:16:6 */
+		mmio_clrsetbits_32(PI_REG(i, 164), 0x3f << 16,
+				   pdram_timing->tmrd << 16);
+		/* PI_164 PI_TDQSCK_MAX_F1:RW:0:4 */
+		mmio_clrsetbits_32(PI_REG(i, 164), 0xf,
+				   pdram_timing->tdqsck_max);
+		/* PI_189 PI_TDFI_CTRLUPD_MAX_F1:RW:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 189), 0xffff,
+				   2 * pdram_timing->trefi);
+		/* PI_190 PI_TDFI_CTRLUPD_INTERVAL_F1:RW:0:32 */
+		mmio_clrsetbits_32(PI_REG(i, 190), 0xffffffff,
+				   20 * pdram_timing->trefi);
+	}
+}
+
+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
+		mmio_clrsetbits_32(PI_REG(i, 80), 3 << 24, 2 << 24);
+#endif
+
+#if EN_CA_TRAINING
+		mmio_clrsetbits_32(PI_REG(i, 100), 3 << 8, 2 << 8);
+#endif
+
+#if EN_WRITE_LEVELING
+		mmio_clrsetbits_32(PI_REG(i, 60), 3 << 8, 2 << 8);
+#endif
+
+#if EN_READ_LEVELING
+		mmio_clrsetbits_32(PI_REG(i, 80), 3 << 16, 2 << 16);
+#endif
+
+#if EN_WDQ_LEVELING
+		mmio_clrsetbits_32(PI_REG(i, 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;
+		mmio_clrsetbits_32(PHY_REG(i, 5), 0x7 << 16, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 133), 0x7 << 16, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 261), 0x7 << 16, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 389), 0x7 << 16, drv_odt_val);
+		drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 24;
+		mmio_clrsetbits_32(PHY_REG(i, 6), 0x7 << 24, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 134), 0x7 << 24, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 262), 0x7 << 24, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 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 */
+		mmio_clrsetbits_32(PHY_REG(i, 6), 0xffffff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 134), 0xffffff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 262), 0xffffff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 390), 0xffffff, drv_odt_val);
+		/* DQS drv odt set */
+		mmio_clrsetbits_32(PHY_REG(i, 7), 0xffffff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 135), 0xffffff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 263), 0xffffff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 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);
+		mmio_clrsetbits_32(PHY_REG(i, 544), 0xff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 672), 0xff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 800), 0xff, drv_odt_val);
+
+		mmio_clrsetbits_32(PHY_REG(i, 928), 0xff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 937), 0xff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 935), 0xff, drv_odt_val);
+
+		drv_odt_val = drv_config->phy_side_ck_cs_drv |
+			      (drv_config->phy_side_ck_cs_drv << 4);
+		mmio_clrsetbits_32(PHY_REG(i, 929), 0xff, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 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;
+
+		mmio_clrsetbits_32(PHY_REG(i, 896), (0x3 << 8) | 1, fn << 8);
+
+		/* PHY_LOW_FREQ_SEL */
+		/* DENALI_PHY_913 1bit offset_0 */
+		if (timing_config->freq > 400)
+			mmio_clrbits_32(PHY_REG(i, 913), 1);
+		else
+			mmio_setbits_32(PHY_REG(i, 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++;
+		mmio_clrsetbits_32(PHY_REG(i, 87), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 215), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 343), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 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);
+		mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 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);
+		mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 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;
+		mmio_clrsetbits_32(PHY_REG(i, 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;
+		}
+		mmio_clrsetbits_32(PHY_REG(i, 947), 0x7 << 8, tmp << 8);
+		mmio_setbits_32(PHY_REG(i, 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 % 1000;
+		tmp = gate_delay_frac_ps * 0x200 / 1000;
+		/* PHY_RDDQS_GATE_BYPASS_SLAVE_DELAY */
+		/* DENALI_PHY_2/130/258/386 10bits offset_0 */
+		mmio_clrsetbits_32(PHY_REG(i, 2), 0x2ff, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 130), 0x2ff, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 258), 0x2ff, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 386), 0x2ff, tmp);
+		/* PHY_RDDQS_GATE_SLAVE_DELAY */
+		/* DENALI_PHY_77/205/333/461 10bits offset_16 */
+		mmio_clrsetbits_32(PHY_REG(i, 77), 0x2ff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 205), 0x2ff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 333), 0x2ff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 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 */
+		mmio_clrsetbits_32(PHY_REG(i, 10), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 138), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 266), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 394), 0xf, tmp);
+		/* PHY_RDDQS_LATENCY_ADJUST */
+		/* DENALI_PHY_78/206/334/462 4bits offset_0 */
+		mmio_clrsetbits_32(PHY_REG(i, 78), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 206), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 334), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 462), 0xf, tmp);
+		/* PHY_GTLVL_LAT_ADJ_START */
+		/* DENALI_PHY_80/208/336/464 4bits offset_16 */
+		tmp = delay_frac_ps / 1000;
+		mmio_clrsetbits_32(PHY_REG(i, 80), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 208), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 336), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 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 */
+		mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 16, tmp << 16);
+		/* PHY_RDDATA_EN_TSEL_DLY */
+		/* DENALI_PHY_86/214/342/470 4bit offset_0 */
+		mmio_clrsetbits_32(PHY_REG(i, 86), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 214), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 342), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 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 */
+		mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 8, tmp << 8);
+		mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 8, tmp << 8);
+		mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 8, tmp << 8);
+		mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 8, tmp << 8);
+		/* PHY_RDDATA_EN_DLY */
+		/* DENALI_PHY_85/213/341/469 4bit offset_24 */
+		mmio_clrsetbits_32(PHY_REG(i, 85), 0xf << 24, tmp << 24);
+		mmio_clrsetbits_32(PHY_REG(i, 213), 0xf << 24, tmp << 24);
+		mmio_clrsetbits_32(PHY_REG(i, 341), 0xf << 24, tmp << 24);
+		mmio_clrsetbits_32(PHY_REG(i, 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 */
+			mmio_clrbits_32(PHY_REG(i, 84), 0x1 << 16);
+			mmio_clrbits_32(PHY_REG(i, 212), 0x1 << 16);
+			mmio_clrbits_32(PHY_REG(i, 340), 0x1 << 16);
+			mmio_clrbits_32(PHY_REG(i, 468), 0x1 << 16);
+		} else {
+			mmio_setbits_32(PHY_REG(i, 84), 0x1 << 16);
+			mmio_setbits_32(PHY_REG(i, 212), 0x1 << 16);
+			mmio_setbits_32(PHY_REG(i, 340), 0x1 << 16);
+			mmio_setbits_32(PHY_REG(i, 468), 0x1 << 16);
+		}
+	}
+}
+
+static int to_get_clk_index(unsigned int mhz)
+{
+	int pll_cnt, i;
+
+	pll_cnt = ARRAY_SIZE(dpll_rates_table);
+
+	/* Assumming rate_table is in descending order */
+	for (i = 0; i < pll_cnt; i++) {
+		if (mhz >= dpll_rates_table[i].mhz)
+			break;
+	}
+
+	/* if mhz lower than lowest frequency in table, use lowest frequency */
+	if (i == pll_cnt)
+		i = pll_cnt - 1;
+
+	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;
+	mmio_write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(fbdiv));
+	mmio_write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON1,
+		      POSTDIV2(postdiv2) | POSTDIV1(postdiv1) | REFDIV(refdiv));
+	return (24 * fbdiv) / refdiv / postdiv1 / postdiv2;
+}
+
+uint32_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)
+{
+	uint32_t low_power = 0;
+	uint32_t channel_mask;
+	uint32_t tmp, i;
+
+	channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) &
+			0x3;
+	for (i = 0; i < 2; i++) {
+		if (!(channel_mask & (1 << i)))
+			continue;
+
+		/* exit stdby mode */
+		mmio_write_32(CIC_BASE + CIC_CTRL1,
+			      (1 << (i + 16)) | (0 << i));
+		/* exit external self-refresh */
+		tmp = i ? 12 : 8;
+		low_power |= ((mmio_read_32(PMU_BASE + PMU_SFT_CON) >> tmp) &
+			      0x1) << (4 + 8 * i);
+		mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 1 << tmp);
+		while (!(mmio_read_32(PMU_BASE + PMU_DDR_SREF_ST) & (1 << i)))
+			;
+		/* exit auto low-power */
+		mmio_clrbits_32(CTL_REG(i, 101), 0x7);
+		/* lp_cmd to exit */
+		if (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) !=
+		    0x40) {
+			while (mmio_read_32(CTL_REG(i, 200)) & 0x1)
+				;
+			mmio_clrsetbits_32(CTL_REG(i, 93), 0xff << 24,
+					   0x69 << 24);
+			while (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) !=
+			       0x40)
+				;
+		}
+	}
+	return low_power;
+}
+
+void resume_low_power(uint32_t low_power)
+{
+	uint32_t channel_mask;
+	uint32_t tmp, i, val;
+
+	channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) &
+		       0x3;
+	for (i = 0; i < 2; i++) {
+		if (!(channel_mask & (1 << i)))
+			continue;
+
+		/* resume external self-refresh */
+		tmp = i ? 12 : 8;
+		val = (low_power >> (4 + 8 * i)) & 0x1;
+		mmio_setbits_32(PMU_BASE + PMU_SFT_CON, val << tmp);
+		/* resume auto low-power */
+		val = (low_power >> (8 * i)) & 0x7;
+		mmio_setbits_32(CTL_REG(i, 101), val);
+		/* resume stdby mode */
+		val = (low_power >> (3 + 8 * i)) & 0x1;
+		mmio_write_32(CIC_BASE + CIC_CTRL1,
+			      (1 << (i + 16)) | (val << i));
+	}
+}
+
+static void wait_dcf_done(void)
+{
+	while ((mmio_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 */
+	mmio_write_32(DCF_BASE + DCF_DCF_ADDR, dcf_addr);
+	/* wait dcf done */
+	while (mmio_read_32(DCF_BASE + DCF_DCF_CTRL) & 1)
+		continue;
+	/* clear dcf irq status */
+	mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
+	/* DCF start */
+	mmio_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 */
+	mmio_write_32(SGRF_BASE + 0xe01c, ((0x3 << 0) << 16) | (0 << 0));
+	mmio_write_32(DCF_BASE + DCF_DCF_TOSET, 0x80000000);
+}
+
+static void dcf_start(uint32_t freq, uint32_t index)
+{
+	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
+		      (0x1 << (1 + 16)) | (1 << 1));
+	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(11),
+		      (0x1 << (0 + 16)) | (1 << 0));
+	mmio_write_32(DCF_PARAM_ADDR + PARAM_FREQ_SELECT, index << 4);
+
+	mmio_write_32(DCF_PARAM_ADDR + PARAM_DRAM_FREQ, freq);
+
+	rkclk_prepare_pll_timing(freq);
+	udelay(10);
+	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
+		      (0x1 << (1 + 16)) | (0 << 1));
+	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(11),
+		      (0x1 << (0 + 16)) | (0 << 0));
+	udelay(10);
+	enable_dcf(DCF_START_ADDR);
+}
+
+static void dram_low_power_config(struct drv_odt_lp_config *lp_config)
+{
+	uint32_t tmp, tmp1, i;
+	uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt;
+	uint32_t dram_type = rk3399_dram_status.timing_config.dram_type;
+	uint32_t *low_power = &rk3399_dram_status.low_power_stat;
+
+	if (dram_type == LPDDR4)
+		tmp = (lp_config->srpd_lite_idle << 16) |
+		      lp_config->pd_idle;
+	else
+		tmp = lp_config->pd_idle;
+
+	if (dram_type == DDR3)
+		tmp1 = (2 << 16) | (0x7 << 8) | 7;
+	else
+		tmp1 = (3 << 16) | (0x7 << 8) | 7;
+
+	*low_power = 0;
+
+	for (i = 0; i < ch_cnt; i++) {
+		mmio_write_32(CTL_REG(i, 102), tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 103), 0xffff,
+				   (lp_config->sr_mc_gate_idle << 8) |
+				   lp_config->sr_idle);
+		mmio_clrsetbits_32(CTL_REG(i, 101), 0x70f0f, tmp1);
+		*low_power |= (7 << (8 * i));
+	}
+
+	/* standby idle */
+	mmio_write_32(CIC_BASE + CIC_IDLE_TH, lp_config->standby_idle);
+	mmio_write_32(CIC_BASE + CIC_CG_WAIT_TH, 0x640008);
+
+	if (ch_cnt == 2) {
+		mmio_write_32(GRF_BASE + GRF_DDRC1_CON1,
+			      (((0x1<<4) | (0x1<<5) | (0x1<<6) |
+				(0x1<<7)) << 16) |
+			      ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
+		if (lp_config->standby_idle) {
+			tmp = 0x002a002a;
+			*low_power |= (1 << 11);
+		} else
+			tmp = 0;
+		mmio_write_32(CIC_BASE + CIC_CTRL1, tmp);
+	}
+
+	mmio_write_32(GRF_BASE + GRF_DDRC0_CON1,
+		      (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
+		      ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
+	if (lp_config->standby_idle) {
+		tmp = 0x00150015;
+		*low_power |= (1 << 3);
+	} else
+		tmp = 0;
+	mmio_write_32(CIC_BASE + CIC_CTRL1, tmp);
+}
+
+
+static void dram_related_init(struct ddr_dts_config_timing *dts_timing)
+{
+	uint32_t trefi0, trefi1;
+	uint32_t i;
+
+	dcf_code_init();
+
+	/* get sdram config for os reg */
+	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 = ((mmio_read_32(CTL_REG(0, 48)) >> 16) & 0xffff) + 8;
+	trefi1 = ((mmio_read_32(CTL_REG(0, 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 =
+		(mmio_read_32(CTL_REG(0, 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++) {
+		mmio_clrbits_32(CTL_REG(i, 70), (1 << 24) |
+				(1 << 16) | (1 << 8) | 1);
+		mmio_clrbits_32(CTL_REG(i, 71), 1);
+
+		mmio_clrbits_32(PI_REG(i, 60), 0x3 << 8);
+		mmio_clrbits_32(PI_REG(i, 80), (0x3 << 24) | (0x3 << 16));
+		mmio_clrbits_32(PI_REG(i, 100), 0x3 << 8);
+		mmio_clrbits_32(PI_REG(i, 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]);
+}
+
+uint32_t ddr_set_rate(uint32_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;
+
+	index = to_get_clk_index(mhz);
+	mhz = dpll_rates_table[index].mhz;
+
+	low_power = exit_low_power();
+	index = prepare_ddr_timing(mhz);
+	if (index > 1)
+		goto out;
+
+	dcf_start(mhz, index);
+	wait_dcf_done();
+	if (rk3399_dram_status.timing_config.odt == 0)
+		gen_rk3399_set_odt(0);
+
+	rk3399_dram_status.current_index = index;
+
+	if (mhz < dts_parameter.auto_pd_dis_freq)
+		low_power |= rk3399_dram_status.low_power_stat;
+
+	resume_low_power(low_power);
+out:
+	return mhz;
+}
+
+uint32_t ddr_round_rate(uint32_t hz)
+{
+	int index;
+	uint32_t mhz = hz / (1000 * 1000);
+
+	index = to_get_clk_index(mhz);
+
+	return dpll_rates_table[index].mhz * 1000 * 1000;
+}
+
+uint32_t dts_timing_receive(uint32_t timing, uint32_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_dfs_init(void)
+{
+	dram_related_init(&dts_parameter);
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.h b/plat/rockchip/rk3399/drivers/dram/dfs.h
new file mode 100644
index 0000000..1da0903
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.h
@@ -0,0 +1,112 @@
+/*
+ * 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_DFS_H__
+#define __SOC_ROCKCHIP_RK3399_DFS_H__
+
+struct rk3399_sdram_default_config {
+	unsigned char bl;
+	/* 1:auto precharge, 0:never auto precharge */
+	unsigned char ap;
+	/* dram driver strength */
+	unsigned char dramds;
+	/* dram ODT, if odt=0, this parameter invalid */
+	unsigned char dramodt;
+	/* ca ODT, if odt=0, this parameter invalid
+	 * only used by LPDDR4
+	 */
+	unsigned char caodt;
+	unsigned char burst_ref_cnt;
+	/* zqcs period, unit(s) */
+	unsigned char zqcsi;
+};
+
+struct  ddr_dts_config_timing {
+	unsigned int ddr3_speed_bin;
+	unsigned int pd_idle;
+	unsigned int sr_idle;
+	unsigned int sr_mc_gate_idle;
+	unsigned int srpd_lite_idle;
+	unsigned int standby_idle;
+	unsigned int auto_pd_dis_freq;
+	unsigned int ddr3_dll_dis_freq;
+	unsigned int phy_dll_dis_freq;
+	unsigned int ddr3_odt_dis_freq;
+	unsigned int ddr3_drv;
+	unsigned int ddr3_odt;
+	unsigned int phy_ddr3_ca_drv;
+	unsigned int phy_ddr3_dq_drv;
+	unsigned int phy_ddr3_odt;
+	unsigned int lpddr3_odt_dis_freq;
+	unsigned int lpddr3_drv;
+	unsigned int lpddr3_odt;
+	unsigned int phy_lpddr3_ca_drv;
+	unsigned int phy_lpddr3_dq_drv;
+	unsigned int phy_lpddr3_odt;
+	unsigned int lpddr4_odt_dis_freq;
+	unsigned int lpddr4_drv;
+	unsigned int lpddr4_dq_odt;
+	unsigned int lpddr4_ca_odt;
+	unsigned int phy_lpddr4_ca_drv;
+	unsigned int phy_lpddr4_ck_cs_drv;
+	unsigned int phy_lpddr4_dq_drv;
+	unsigned int phy_lpddr4_odt;
+	uint32_t available;
+};
+
+struct drv_odt_lp_config {
+	uint32_t ddr3_speed_bin;
+	uint32_t pd_idle;
+	uint32_t sr_idle;
+	uint32_t sr_mc_gate_idle;
+	uint32_t srpd_lite_idle;
+	uint32_t standby_idle;
+
+	uint32_t ddr3_dll_dis_freq;/* for ddr3 only */
+	uint32_t phy_dll_dis_freq;
+	uint32_t odt_dis_freq;
+
+	uint32_t dram_side_drv;
+	uint32_t dram_side_dq_odt;
+	uint32_t dram_side_ca_odt;
+
+	uint32_t phy_side_ca_drv;
+	uint32_t phy_side_ck_cs_drv;
+	uint32_t phy_side_dq_drv;
+	uint32_t phy_side_odt;
+};
+
+void ddr_dfs_init(void);
+uint32_t ddr_set_rate(uint32_t hz);
+uint32_t ddr_round_rate(uint32_t hz);
+uint32_t ddr_get_rate(void);
+void clr_dcf_irq(void);
+uint32_t dts_timing_receive(uint32_t timing, uint32_t index);
+#endif
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
index 94aa076..5f6f0fc 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -28,2540 +28,49 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <debug.h>
-#include <mmio.h>
+#include <dram.h>
 #include <plat_private.h>
-#include "dram.h"
-#include "dram_spec_timing.h"
-#include "string.h"
-#include "soc.h"
-#include "pmu.h"
+#include <soc.h>
+#include <rk3399_def.h>
 
-#include <delay_timer.h>
+__sramdata struct rk3399_sdram_params sdram_config;
 
-#define CTL_TRAINING	(1)
-#define PI_TRAINING		(!CTL_TRAINING)
-
-#define EN_READ_GATE_TRAINING	(1)
-#define EN_CA_TRAINING		(0)
-#define EN_WRITE_LEVELING	(0)
-#define EN_READ_LEVELING	(0)
-#define EN_WDQ_LEVELING	(0)
-
-#define ENPER_CS_TRAINING_FREQ	(933)
-
-struct pll_div {
-	unsigned int mhz;
-	unsigned int refdiv;
-	unsigned int fbdiv;
-	unsigned int postdiv1;
-	unsigned int postdiv2;
-	unsigned int frac;
-	unsigned int freq;
-};
-
-static const struct pll_div dpll_rates_table[] = {
-
-	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */
-	{.mhz = 933, .refdiv = 3, .fbdiv = 350, .postdiv1 = 3, .postdiv2 = 1},
-	{.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1},
-	{.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1},
-	{.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1},
-	{.mhz = 600, .refdiv = 1, .fbdiv = 50, .postdiv1 = 2, .postdiv2 = 1},
-	{.mhz = 528, .refdiv = 1, .fbdiv = 66, .postdiv1 = 3, .postdiv2 = 1},
-	{.mhz = 400, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1},
-	{.mhz = 300, .refdiv = 1, .fbdiv = 50, .postdiv1 = 4, .postdiv2 = 1},
-	{.mhz = 200, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 2},
-};
-
-static struct rk3399_ddr_cic_regs *const rk3399_ddr_cic = (void *)CIC_BASE;
-static struct rk3399_ddr_pctl_regs *const rk3399_ddr_pctl[2] = {
-	(void *)DDRC0_BASE, (void *)DDRC1_BASE
-};
-
-static struct rk3399_ddr_pi_regs *const rk3399_ddr_pi[2] = {
-	(void *)DDRC0_PI_BASE, (void *)DDRC1_PI_BASE
-};
-
-static struct rk3399_ddr_publ_regs *const rk3399_ddr_publ[2] = {
-	(void *)DDRC0_PHY_BASE, (void *)DDRC1_PHY_BASE
-};
-
-struct rk3399_dram_status {
-	uint32_t current_index;
-	uint32_t index_freq[2];
-	uint32_t low_power_stat;
-	struct timing_related_config timing_config;
-	struct drv_odt_lp_config drv_odt_lp_cfg;
-};
-
-static struct rk3399_dram_status rk3399_dram_status;
-static struct ddr_dts_config_timing dts_parameter = {
-	.available = 0
-};
-
-static struct rk3399_sdram_default_config ddr3_default_config = {
-	.bl = 8,
-	.ap = 0,
-	.dramds = 40,
-	.dramodt = 120,
-	.burst_ref_cnt = 1,
-	.zqcsi = 0
-};
-
-static struct drv_odt_lp_config ddr3_drv_odt_default_config = {
-	.ddr3_speed_bin = DDR3_DEFAULT,
-	.pd_idle = 0,
-	.sr_idle = 0,
-	.sr_mc_gate_idle = 0,
-	.srpd_lite_idle = 0,
-	.standby_idle = 0,
-
-	.ddr3_dll_dis_freq = 300,
-	.phy_dll_dis_freq = 125,
-	.odt_dis_freq = 933,
-
-	.dram_side_drv = 40,
-	.dram_side_dq_odt = 120,
-	.dram_side_ca_odt = 120,
-
-	.phy_side_ca_drv = 40,
-	.phy_side_ck_cs_drv = 40,
-	.phy_side_dq_drv = 40,
-	.phy_side_odt = 240,
-};
-
-static struct rk3399_sdram_default_config lpddr3_default_config = {
-	.bl = 8,
-	.ap = 0,
-	.dramds = 34,
-	.dramodt = 240,
-	.burst_ref_cnt = 1,
-	.zqcsi = 0
-};
-
-static struct drv_odt_lp_config lpddr3_drv_odt_default_config = {
-	.ddr3_speed_bin = DDR3_DEFAULT,
-	.pd_idle = 0,
-	.sr_idle = 0,
-	.sr_mc_gate_idle = 0,
-	.srpd_lite_idle = 0,
-	.standby_idle = 0,
-
-	.ddr3_dll_dis_freq = 300,
-	.phy_dll_dis_freq = 125,
-	.odt_dis_freq = 666,
-
-	.dram_side_drv = 40,
-	.dram_side_dq_odt = 120,
-	.dram_side_ca_odt = 120,
-
-	.phy_side_ca_drv = 40,
-	.phy_side_ck_cs_drv = 40,
-	.phy_side_dq_drv = 40,
-	.phy_side_odt = 240,
-};
-
-static struct rk3399_sdram_default_config lpddr4_default_config = {
-	.bl = 16,
-	.ap = 0,
-	.dramds = 40,
-	.dramodt = 240,
-	.caodt = 240,
-	.burst_ref_cnt = 1,
-	.zqcsi = 0
-};
-
-static struct drv_odt_lp_config lpddr4_drv_odt_default_config = {
-	.ddr3_speed_bin = DDR3_DEFAULT,
-	.pd_idle = 0,
-	.sr_idle = 0,
-	.sr_mc_gate_idle = 0,
-	.srpd_lite_idle = 0,
-	.standby_idle = 0,
-
-	.ddr3_dll_dis_freq = 300,
-	.phy_dll_dis_freq = 125,
-	.odt_dis_freq = 933,
-
-	.dram_side_drv = 60,
-	.dram_side_dq_odt = 40,
-	.dram_side_ca_odt = 40,
-
-	.phy_side_ca_drv = 40,
-	.phy_side_ck_cs_drv = 80,
-	.phy_side_dq_drv = 80,
-	.phy_side_odt = 60,
-};
-
-uint32_t dcf_code[] = {
-#include "dcf_code.inc"
-};
-
-
-#define write_32(addr, value)\
-	mmio_write_32((uintptr_t)(addr), (uint32_t)(value))
-
-#define read_32(addr) \
-		mmio_read_32((uintptr_t)(addr))
-#define clrbits_32(addr, clear)\
-		mmio_clrbits_32((uintptr_t)(addr), (uint32_t)(clear))
-#define setbits_32(addr, set)\
-	mmio_setbits_32((uintptr_t)(addr), (uint32_t)(set))
-#define clrsetbits_32(addr, clear, set)\
-	mmio_clrsetbits_32((uintptr_t)(addr), (uint32_t)(clear),\
-					(uint32_t)(set))
-
-#define DCF_START_ADDR	(SRAM_BASE + 0x1400)
-#define DCF_PARAM_ADDR	(SRAM_BASE + 0x1000)
-
-/* DCF_PAMET */
-#define PARAM_DRAM_FREQ		(0)
-#define PARAM_DPLL_CON0		(4)
-#define PARAM_DPLL_CON1		(8)
-#define PARAM_DPLL_CON2		(0xc)
-#define PARAM_DPLL_CON3		(0x10)
-#define PARAM_DPLL_CON4		(0x14)
-#define PARAM_DPLL_CON5		(0x18)
-/* equal to fn<<4 */
-#define PARAM_FREQ_SELECT	(0x1c)
-
-static unsigned int get_cs_die_capability(struct rk3399_sdram_config
-					  *psdram_config, unsigned int channel,
-					  unsigned int cs)
-{
-	unsigned int die;
-	unsigned int cs_cap;
-	unsigned int row[2];
-
-	row[0] = psdram_config->ch[channel].cs0_row;
-	row[1] = psdram_config->ch[channel].cs1_row;
-	die = psdram_config->ch[channel].bus_width /
-	    psdram_config->ch[channel].each_die_bus_width;
-	cs_cap = (1 << (row[cs] +
-			(psdram_config->ch[channel].bank / 4 + 1) +
-			psdram_config->ch[channel].col +
-			(psdram_config->ch[channel].bus_width / 16)));
-	if (psdram_config->ch[channel].each_die_6gb_or_12gb)
-		cs_cap = cs_cap * 3 / 4;
-
-	return (cs_cap / die);
-}
-
-static void sdram_config_init(struct rk3399_sdram_config *psdram_config)
+void dram_init(void)
 {
 	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)
+	os_reg2_val = mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2));
+	sdram_config.dramtype = SYS_REG_DEC_DDRTYPE(os_reg2_val);
+	sdram_config.num_channels = SYS_REG_DEC_NUM_CH(os_reg2_val);
+	sdram_config.stride = (mmio_read_32(SGRF_BASE + SGRF_SOC_CON3_7(4)) >>
+				10) & 0x1f;
 
-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;
+	for (i = 0; i < 2; i++) {
+		struct rk3399_sdram_channel *ch = &sdram_config.ch[i];
+		struct rk3399_msch_timings *noc = &ch->noc_timings;
 
-	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 = ARRAY_SIZE(dpll_rates_table);
-
-	/* Assumming rate_table is in descending order */
-	for (i = 0; i < pll_cnt; i++) {
-		if (mhz >= dpll_rates_table[i].mhz)
-			break;
-	}
-
-	/* if mhz lower than lowest frequency in table, use lowest frequency */
-	if (i == pll_cnt)
-		i = pll_cnt - 1;
-
-	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;
-}
-
-uint32_t ddr_get_rate(void)
-{
-	uint32_t refdiv, postdiv1, fbdiv, postdiv2;
-
-	refdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) & 0x3f;
-	fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
-	postdiv1 =
-		(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 8) & 0x7;
-	postdiv2 =
-		(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 12) & 0x7;
-
-	return (24 / refdiv * fbdiv / postdiv1 / postdiv2) * 1000 * 1000;
-}
-
-/*
- * return: bit12: channel 1, external self-refresh
- *         bit11: channel 1, stdby_mode
- *         bit10: channel 1, self-refresh with controller and memory clock gate
- *         bit9: channel 1, self-refresh
- *         bit8: channel 1, power-down
- *
- *         bit4: channel 1, external self-refresh
- *         bit3: channel 0, stdby_mode
- *         bit2: channel 0, self-refresh with controller and memory clock gate
- *         bit1: channel 0, self-refresh
- *         bit0: channel 0, power-down
- */
-uint32_t exit_low_power(void)
-{
-	struct rk3399_ddr_pctl_regs *ddr_pctl_regs;
-	uint32_t low_power = 0;
-	uint32_t channel_mask;
-	uint32_t channel;
-	uint32_t tmp;
-
-	channel_mask = (read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3;
-	for (channel = 0; channel < 2; channel++) {
-		ddr_pctl_regs = rk3399_ddr_pctl[channel];
-		if (!(channel_mask & (1 << channel)))
-			continue;
-
-		/* exit stdby mode */
-		write_32(&rk3399_ddr_cic->cic_ctrl1,
-			 (1 << (channel + 16)) | (0 << channel));
-		/* exit external self-refresh */
-		tmp = channel ? 12 : 8;
-		low_power |= ((read_32(PMU_BASE + PMU_SFT_CON) >> tmp) & 0x1)
-		    << (4 + 8 * channel);
-		clrbits_32(PMU_BASE + PMU_SFT_CON, 1 << tmp);
-		while (!(read_32(PMU_BASE + PMU_DDR_SREF_ST) &
-				(1 << channel)))
-			;
-		/* exit auto low-power */
-		clrbits_32(&ddr_pctl_regs->denali_ctl[101], 0x7);
-		/* lp_cmd to exit */
-		if (((read_32(&ddr_pctl_regs->denali_ctl[100]) >> 24) &
-			      0x7f) != 0x40) {
-			while (read_32(&ddr_pctl_regs->denali_ctl[200]) & 0x1)
-				;
-			clrsetbits_32(&ddr_pctl_regs->denali_ctl[93],
-				      0xff << 24, 0x69 << 24);
-			while (((read_32(&ddr_pctl_regs->denali_ctl[100]) >>
-					  24) & 0x7f) != 0x40)
-				;
-		}
-	}
-	return low_power;
-}
-
-void resume_low_power(uint32_t low_power)
-{
-	struct rk3399_ddr_pctl_regs *ddr_pctl_regs;
-	uint32_t channel_mask;
-	uint32_t channel;
-	uint32_t tmp;
-	uint32_t val;
-
-	channel_mask = (read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3;
-	for (channel = 0; channel < 2; channel++) {
-		ddr_pctl_regs = rk3399_ddr_pctl[channel];
-		if (!(channel_mask & (1 << channel)))
+		if (!(SYS_REG_DEC_CHINFO(os_reg2_val, i)))
 			continue;
 
-		/* resume external self-refresh */
-		tmp = channel ? 12 : 8;
-		val = (low_power >> (4 + 8 * channel)) & 0x1;
-		setbits_32(PMU_BASE + PMU_SFT_CON, val << tmp);
-		/* resume auto low-power */
-		val = (low_power >> (8 * channel)) & 0x7;
-		setbits_32(&ddr_pctl_regs->denali_ctl[101], val);
-		/* resume stdby mode */
-		val = (low_power >> (3 + 8 * channel)) & 0x1;
-		write_32(&rk3399_ddr_cic->cic_ctrl1,
-			 (1 << (channel + 16)) | (val << channel));
-	}
-}
-
-static void wait_dcf_done(void)
-{
-	while ((read_32(DCF_BASE + DCF_DCF_ISR) & (DCF_DONE)) == 0)
-		continue;
-}
-
-void clr_dcf_irq(void)
-{
-	/* clear dcf irq status */
-	mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
-}
-
-static void enable_dcf(uint32_t dcf_addr)
-{
-	/* config DCF start addr */
-	write_32(DCF_BASE + DCF_DCF_ADDR, dcf_addr);
-	/* wait dcf done */
-	while (read_32(DCF_BASE + DCF_DCF_CTRL) & 1)
-		continue;
-	/* clear dcf irq status */
-	write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
-	/* DCF start */
-	setbits_32(DCF_BASE + DCF_DCF_CTRL, DCF_START);
-}
-
-void dcf_code_init(void)
-{
-	memcpy((void *)DCF_START_ADDR, (void *)dcf_code, sizeof(dcf_code));
-	/* set dcf master secure */
-	write_32(SGRF_BASE + 0xe01c, ((0x3 << 0) << 16) | (0 << 0));
-	write_32(DCF_BASE + DCF_DCF_TOSET, 0x80000000);
-}
-
-static void dcf_start(uint32_t freq, uint32_t index)
-{
-	write_32(CRU_BASE + CRU_SOFTRST_CON(10), (0x1 << (1 + 16)) | (1 << 1));
-	write_32(CRU_BASE + CRU_SOFTRST_CON(11), (0x1 << (0 + 16)) | (1 << 0));
-	write_32(DCF_PARAM_ADDR + PARAM_FREQ_SELECT, index << 4);
-
-	write_32(DCF_PARAM_ADDR + PARAM_DRAM_FREQ, freq);
-
-	rkclk_prepare_pll_timing(freq);
-	udelay(10);
-	write_32(CRU_BASE + CRU_SOFTRST_CON(10), (0x1 << (1 + 16)) | (0 << 1));
-	write_32(CRU_BASE + CRU_SOFTRST_CON(11), (0x1 << (0 + 16)) | (0 << 0));
-	udelay(10);
-	enable_dcf(DCF_START_ADDR);
-}
-
-static void dram_low_power_config(struct drv_odt_lp_config *lp_config)
-{
-	uint32_t tmp, tmp1, i;
-	uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt;
-	uint32_t dram_type = rk3399_dram_status.timing_config.dram_type;
-	uint32_t *low_power = &rk3399_dram_status.low_power_stat;
+		ch->rank = SYS_REG_DEC_RANK(os_reg2_val, i);
+		ch->col = SYS_REG_DEC_COL(os_reg2_val, i);
+		ch->bk = SYS_REG_DEC_BK(os_reg2_val, i);
+		ch->bw = SYS_REG_DEC_BW(os_reg2_val, i);
+		ch->dbw = SYS_REG_DEC_DBW(os_reg2_val, i);
+		ch->row_3_4 = SYS_REG_DEC_ROW_3_4(os_reg2_val, i);
+		ch->cs0_row = SYS_REG_DEC_CS0_ROW(os_reg2_val, i);
+		ch->cs1_row = SYS_REG_DEC_CS1_ROW(os_reg2_val, i);
+		ch->ddrconfig = mmio_read_32(MSCH_BASE(i) + MSCH_DEVICECONF);
 
-	if (dram_type == LPDDR4)
-		tmp = (lp_config->srpd_lite_idle << 16) |
-		      lp_config->pd_idle;
-	else
-		tmp = lp_config->pd_idle;
-
-	if (dram_type == DDR3)
-		tmp1 = (2 << 16) | (0x7 << 8) | 7;
-	else
-		tmp1 = (3 << 16) | (0x7 << 8) | 7;
-
-	*low_power = 0;
-
-	for (i = 0; i < ch_cnt; i++) {
-		write_32(&rk3399_ddr_pctl[i]->denali_ctl[102], tmp);
-		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[103], 0xffff,
-			      (lp_config->sr_mc_gate_idle << 8) |
-			      lp_config->sr_idle);
-		clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[101],
-			      0x70f0f, tmp1);
-		*low_power |= (7 << (8 * i));
-	}
-
-	/* standby idle */
-	write_32(&rk3399_ddr_cic->cic_idle_th, lp_config->standby_idle);
-	write_32(&rk3399_ddr_cic->cic_cg_wait_th, 0x640008);
-
-	if (ch_cnt == 2) {
-		write_32(GRF_BASE + GRF_DDRC1_CON1,
-			 (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
-			 ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
-		if (lp_config->standby_idle) {
-			tmp = 0x002a002a;
-			*low_power |= (1 << 11);
-		} else {
-			tmp = 0;
-		}
-		write_32(&rk3399_ddr_cic->cic_ctrl1, tmp);
-	}
-
-	write_32(GRF_BASE + GRF_DDRC0_CON1,
-		 (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
-		 ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
-	if (lp_config->standby_idle) {
-		tmp = 0x00150015;
-		*low_power |= (1 << 3);
-	} else {
-		tmp = 0;
-	}
-	write_32(&rk3399_ddr_cic->cic_ctrl1, tmp);
-}
-
-
-static void dram_related_init(struct ddr_dts_config_timing *dts_timing)
-{
-	uint32_t trefi0, trefi1;
-	uint32_t i;
-	struct rk3399_sdram_config sdram_config;
-
-	dcf_code_init();
-
-	/* get sdram config for os reg */
-	sdram_config_init(&sdram_config);
-	drv_odt_lp_cfg_init(sdram_config.dramtype, dts_timing,
-			    &rk3399_dram_status.drv_odt_lp_cfg);
-	sdram_timing_cfg_init(&rk3399_dram_status.timing_config,
-			      &sdram_config,
-			      &rk3399_dram_status.drv_odt_lp_cfg);
-
-	trefi0 = ((read_32(&rk3399_ddr_pctl[0]->denali_ctl[48]) >>
-		   16) & 0xffff) + 8;
-	trefi1 = ((read_32(&rk3399_ddr_pctl[0]->denali_ctl[49]) >>
-		   16) & 0xffff) + 8;
-
-	rk3399_dram_status.index_freq[0] = trefi0 * 10 / 39;
-	rk3399_dram_status.index_freq[1] = trefi1 * 10 / 39;
-	rk3399_dram_status.current_index =
-	    (read_32(&rk3399_ddr_pctl[0]->denali_ctl[111])
-	     >> 16) & 0x3;
-	if (rk3399_dram_status.timing_config.dram_type == DDR3) {
-		rk3399_dram_status.index_freq[0] /= 2;
-		rk3399_dram_status.index_freq[1] /= 2;
+		noc->ddrtiminga0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DDRTIMINGA0);
+		noc->ddrtimingb0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DDRTIMINGB0);
+		noc->ddrtimingc0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DDRTIMINGC0);
+		noc->devtodev0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DEVTODEV0);
+		noc->ddrmode.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DDRMODE);
+		noc->agingx0 = mmio_read_32(MSCH_BASE(i) + MSCH_AGINGX0);
 	}
-	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]);
-}
-
-uint32_t ddr_set_rate(uint32_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;
-
-	index = to_get_clk_index(mhz);
-	mhz = dpll_rates_table[index].mhz;
-
-	low_power = exit_low_power();
-	index = prepare_ddr_timing(mhz);
-	if (index > 1)
-		goto out;
-
-	dcf_start(mhz, index);
-	wait_dcf_done();
-	if (rk3399_dram_status.timing_config.odt == 0)
-		gen_rk3399_set_odt(0);
-
-	rk3399_dram_status.current_index = index;
-
-	if (mhz < dts_parameter.auto_pd_dis_freq)
-		low_power |= rk3399_dram_status.low_power_stat;
-
-	resume_low_power(low_power);
-out:
-	return mhz;
-}
-
-uint32_t ddr_round_rate(uint32_t hz)
-{
-	int index;
-	uint32_t mhz = hz / (1000 * 1000);
-
-	index = to_get_clk_index(mhz);
-
-	return dpll_rates_table[index].mhz * 1000 * 1000;
-}
-
-uint32_t dts_timing_receive(uint32_t timing, uint32_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
index 4f99070..44dfbbd 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.h
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -28,49 +28,131 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __SOC_ROCKCHIP_RK3399_SDRAM_H__
-#define __SOC_ROCKCHIP_RK3399_SDRAM_H__
+#ifndef __SOC_ROCKCHIP_RK3399_DRAM_H__
+#define __SOC_ROCKCHIP_RK3399_DRAM_H__
+#include <plat_private.h>
+#include <stdint.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;
-};
+#define CTL_BASE(ch)		(0xffa80000 + (ch) * 0x8000)
+#define CTL_REG(ch, n)		(CTL_BASE(ch) + (n) * 0x4)
+
+#define PI_OFFSET		0x800
+#define PI_BASE(ch)		(CTL_BASE(ch) + PI_OFFSET)
+#define PI_REG(ch, n)		(PI_BASE(ch) + (n) * 0x4)
+
+#define PHY_OFFSET		0x2000
+#define PHY_BASE(ch)		(CTL_BASE(ch) + PHY_OFFSET)
+#define PHY_REG(ch, n)		(PHY_BASE(ch) + (n) * 0x4)
+
+#define MSCH_BASE(ch)		(0xffa84000 + (ch) * 0x8000)
+#define MSCH_ID_COREID		0x0
+#define MSCH_ID_REVISIONID	0x4
+#define MSCH_DEVICECONF		0x8
+#define MSCH_DEVICESIZE		0xc
+#define MSCH_DDRTIMINGA0	0x10
+#define MSCH_DDRTIMINGB0	0x14
+#define MSCH_DDRTIMINGC0	0x18
+#define MSCH_DEVTODEV0		0x1c
+#define MSCH_DDRMODE		0x110
+#define MSCH_AGINGX0		0x1000
+
+#define CIC_CTRL0	0x0
+#define CIC_CTRL1	0x4
+#define CIC_IDLE_TH	0x8
+#define CIC_CG_WAIT_TH	0xc
+#define CIC_STATUS0	0x10
+#define CIC_STATUS1	0x14
+#define CIC_CTRL2	0x18
+#define CIC_CTRL3	0x1c
+#define CIC_CTRL4	0x20
 
 /* DENALI_CTL_00 */
-#define START		(1)
+#define START			1
 
 /* DENALI_CTL_68 */
 #define PWRUP_SREFRESH_EXIT	(1 << 16)
 
 /* DENALI_CTL_274 */
-#define MEM_RST_VALID	(1)
+#define MEM_RST_VALID		1
+
+#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
+
+/*
+ * sys_reg bitfield struct
+ * [31] row_3_4_ch1
+ * [30] row_3_4_ch0
+ * [29:28] chinfo
+ * [27] rank_ch1
+ * [26:25] col_ch1
+ * [24] bk_ch1
+ * [23:22] cs0_row_ch1
+ * [21:20] cs1_row_ch1
+ * [19:18] bw_ch1
+ * [17:16] dbw_ch1;
+ * [15:13] ddrtype
+ * [12] channelnum
+ * [11] rank_ch0
+ * [10:9] col_ch0
+ * [8] bk_ch0
+ * [7:6] cs0_row_ch0
+ * [5:4] cs1_row_ch0
+ * [3:2] bw_ch0
+ * [1:0] dbw_ch0
+ */
+#define SYS_REG_ENC_ROW_3_4(n, ch)	((n) << (30 + (ch)))
+#define SYS_REG_DEC_ROW_3_4(n, ch)	(((n) >> (30 + (ch))) & 0x1)
+#define SYS_REG_ENC_CHINFO(ch)		(1 << (28 + (ch)))
+#define SYS_REG_DEC_CHINFO(n, ch)	(((n) >> (28 + (ch))) & 0x1)
+#define SYS_REG_ENC_DDRTYPE(n)		((n) << 13)
+#define SYS_REG_DEC_DDRTYPE(n)		(((n) >> 13) & 0x7)
+#define SYS_REG_ENC_NUM_CH(n)		(((n) - 1) << 12)
+#define SYS_REG_DEC_NUM_CH(n)		(1 + (((n) >> 12) & 0x1))
+#define SYS_REG_ENC_RANK(n, ch)		(((n) - 1) << (11 + (ch) * 16))
+#define SYS_REG_DEC_RANK(n, ch)		(1 + (((n) >> (11 + (ch) * 16)) & 0x1))
+#define SYS_REG_ENC_COL(n, ch)		(((n) - 9) << (9 + (ch) * 16))
+#define SYS_REG_DEC_COL(n, ch)		(9 + (((n) >> (9 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_BK(n, ch)		(((n) == 3 ? 0 : 1) << (8 + (ch) * 16))
+#define SYS_REG_DEC_BK(n, ch)		(3 - (((n) >> (8 + (ch) * 16)) & 0x1))
+#define SYS_REG_ENC_CS0_ROW(n, ch)	(((n) - 13) << (6 + (ch) * 16))
+#define SYS_REG_DEC_CS0_ROW(n, ch)	(13 + (((n) >> (6 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_CS1_ROW(n, ch)	(((n) - 13) << (4 + (ch) * 16))
+#define SYS_REG_DEC_CS1_ROW(n, ch)	(13 + (((n) >> (4 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_BW(n, ch)		((2 >> (n)) << (2 + (ch) * 16))
+#define SYS_REG_DEC_BW(n, ch)		(2 >> (((n) >> (2 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_DBW(n, ch)		((2 >> (n)) << (0 + (ch) * 16))
+#define SYS_REG_DEC_DBW(n, ch)		(2 >> (((n) >> (0 + (ch) * 16)) & 0x3))
+#define DDR_STRIDE(n)		mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(4), \
+					      (0x1f<<(10+16))|((n)<<10))
+
+#define CTL_REG_NUM		332
+#define PHY_REG_NUM		959
+#define PI_REG_NUM		200
+
+enum {
+	DDR3 = 3,
+	LPDDR2 = 5,
+	LPDDR3 = 6,
+	LPDDR4 = 7,
+	UNUSED = 0xff
+};
 
 struct rk3399_ddr_pctl_regs {
-	uint32_t denali_ctl[332];
+	uint32_t denali_ctl[CTL_REG_NUM];
 };
 
 struct rk3399_ddr_publ_regs {
-	uint32_t denali_phy[959];
+	uint32_t denali_phy[PHY_REG_NUM];
 };
 
-#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];
+	uint32_t denali_pi[PI_REG_NUM];
 };
 union noc_ddrtiminga0 {
 	uint32_t d32;
@@ -138,21 +220,6 @@
 	} 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;
@@ -161,7 +228,7 @@
 	union noc_ddrmode ddrmode;
 	uint32_t agingx0;
 };
-#if 1
+
 struct rk3399_sdram_channel {
 	unsigned char rank;
 	/* col = 0, means this channel is invalid */
@@ -193,137 +260,9 @@
 	struct rk3399_ddr_pi_regs pi_regs;
 	struct rk3399_ddr_publ_regs phy_regs;
 };
-#endif
-struct rk3399_sdram_channel_config {
-	uint32_t bus_width;
-	uint32_t cs_cnt;
-	uint32_t cs0_row;
-	uint32_t cs1_row;
-	uint32_t bank;
-	uint32_t col;
-	uint32_t each_die_bus_width;
-	uint32_t each_die_6gb_or_12gb;
-};
-
-struct rk3399_sdram_config {
-	struct rk3399_sdram_channel_config ch[2];
-	uint32_t dramtype;
-	uint32_t channal_num;
-};
-
-struct rk3399_sdram_default_config {
-	unsigned char bl;
-	/* 1:auto precharge, 0:never auto precharge */
-	unsigned char ap;
-	/* dram driver strength */
-	unsigned char dramds;
-	/* dram ODT, if odt=0, this parameter invalid */
-	unsigned char dramodt;
-	/* ca ODT, if odt=0, this parameter invalid
-	 * only used by LPDDR4
-	 */
-	unsigned char caodt;
-	unsigned char burst_ref_cnt;
-	/* zqcs period, unit(s) */
-	unsigned char zqcsi;
-};
-
-struct  ddr_dts_config_timing {
-	unsigned int ddr3_speed_bin;
-	unsigned int pd_idle;
-	unsigned int sr_idle;
-	unsigned int sr_mc_gate_idle;
-	unsigned int srpd_lite_idle;
-	unsigned int standby_idle;
-	unsigned int auto_pd_dis_freq;
-	unsigned int ddr3_dll_dis_freq;
-	unsigned int phy_dll_dis_freq;
-	unsigned int ddr3_odt_dis_freq;
-	unsigned int ddr3_drv;
-	unsigned int ddr3_odt;
-	unsigned int phy_ddr3_ca_drv;
-	unsigned int phy_ddr3_dq_drv;
-	unsigned int phy_ddr3_odt;
-	unsigned int lpddr3_odt_dis_freq;
-	unsigned int lpddr3_drv;
-	unsigned int lpddr3_odt;
-	unsigned int phy_lpddr3_ca_drv;
-	unsigned int phy_lpddr3_dq_drv;
-	unsigned int phy_lpddr3_odt;
-	unsigned int lpddr4_odt_dis_freq;
-	unsigned int lpddr4_drv;
-	unsigned int lpddr4_dq_odt;
-	unsigned int lpddr4_ca_odt;
-	unsigned int phy_lpddr4_ca_drv;
-	unsigned int phy_lpddr4_ck_cs_drv;
-	unsigned int phy_lpddr4_dq_drv;
-	unsigned int phy_lpddr4_odt;
-	uint32_t available;
-};
-
-struct drv_odt_lp_config {
-	uint32_t ddr3_speed_bin;
-	uint32_t pd_idle;
-	uint32_t sr_idle;
-	uint32_t sr_mc_gate_idle;
-	uint32_t srpd_lite_idle;
-	uint32_t standby_idle;
-
-	uint32_t ddr3_dll_dis_freq;/* for ddr3 only */
-	uint32_t phy_dll_dis_freq;
-	uint32_t odt_dis_freq;
-
-	uint32_t dram_side_drv;
-	uint32_t dram_side_dq_odt;
-	uint32_t dram_side_ca_odt;
-
-	uint32_t phy_side_ca_drv;
-	uint32_t phy_side_ck_cs_drv;
-	uint32_t phy_side_dq_drv;
-	uint32_t phy_side_odt;
-};
-
-#define KHz (1000)
-#define MHz (1000*KHz)
-#define GHz (1000*MHz)
-
-#define PI_CA_TRAINING	(1 << 0)
-#define PI_WRITE_LEVELING	(1 << 1)
-#define PI_READ_GATE_TRAINING	(1 << 2)
-#define PI_READ_LEVELING	(1 << 3)
-#define PI_WDQ_LEVELING	(1 << 4)
-#define PI_FULL_TARINING	(0xff)
-
-#define READ_CH_CNT(val)			(1+((val>>12)&0x1))
-#define READ_CH_INFO(val)			((val>>28)&0x3)
-/* row_3_4:0=normal, 1=6Gb or 12Gb */
-#define READ_CH_ROW_INFO(val, ch)	((val>>(30+(ch)))&0x1)
-
-#define READ_DRAMTYPE_INFO(val)		((val>>13)&0x7)
-#define READ_CS_INFO(val, ch)		((((val)>>(11+(ch)*16))&0x1)+1)
-#define READ_BW_INFO(val, ch)		(2>>(((val)>>(2+(ch)*16))&0x3))
-#define READ_COL_INFO(val, ch)		(9+(((val)>>(9+(ch)*16))&0x3))
-#define READ_BK_INFO(val, ch)		(3-(((val)>>(8+(ch)*16))&0x1))
-#define READ_CS0_ROW_INFO(val, ch)	(13+(((val)>>(6+(ch)*16))&0x3))
-#define READ_CS1_ROW_INFO(val, ch)	(13+(((val)>>(4+(ch)*16))&0x3))
-#define READ_DIE_BW_INFO(val, ch)	(2>>((val>>((ch)*16))&0x3))
-
-#define __sramdata __attribute__((section(".sram.data")))
-#define __sramconst __attribute__((section(".sram.rodata")))
-#define __sramlocalfunc __attribute__((section(".sram.text")))
-#define __sramfunc __attribute__((section(".sram.text"))) \
-					__attribute__((noinline))
-
 
-#define DDR_SAVE_SP(save_sp)   (save_sp = ddr_save_sp(((uint32_t)\
-				(SRAM_CODE_BASE + 0x2000) & (~7))))
+extern __sramdata struct rk3399_sdram_params sdram_config;
 
-#define DDR_RESTORE_SP(save_sp)   ddr_save_sp(save_sp)
+void dram_init(void);
 
-void ddr_init(void);
-uint32_t ddr_set_rate(uint32_t hz);
-uint32_t ddr_round_rate(uint32_t hz);
-uint32_t ddr_get_rate(void);
-void clr_dcf_irq(void);
-uint32_t dts_timing_receive(uint32_t timing, uint32_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
index b015db7..fbf1d39 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
@@ -30,6 +30,7 @@
 
 #include <string.h>
 #include <stdint.h>
+#include <dram.h>
 #include "dram_spec_timing.h"
 
 static const uint8_t ddr3_cl_cwl[][7] = {
diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h
index 2008332..662aeab 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h
@@ -32,14 +32,6 @@
 #define _DRAM_SPEC_TIMING_HEAD_
 #include <stdint.h>
 
-enum {
-	DDR3 = 3,
-	LPDDR2 = 5,
-	LPDDR3 = 6,
-	LPDDR4 = 7,
-	UNUSED = 0xFF
-};
-
 enum ddr3_speed_rate {
 	/* 5-5-5 */
 	DDR3_800D = 0,
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.c b/plat/rockchip/rk3399/drivers/dram/suspend.c
new file mode 100644
index 0000000..f408d67
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.c
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <debug.h>
+#include <arch_helpers.h>
+#include <platform_def.h>
+#include <plat_private.h>
+#include <dram.h>
+#include <pmu_regs.h>
+#include <rk3399_def.h>
+#include <soc.h>
+#include <suspend.h>
+
+#define PMUGRF_OS_REG0			0x300
+#define PMUGRF_OS_REG1			0x304
+#define PMUGRF_OS_REG2			0x308
+#define PMUGRF_OS_REG3			0x30c
+
+#define CRU_SFTRST_DDR_CTRL(ch, n)	((0x1 << (8 + 16 + (ch) * 4)) | \
+					 ((n) << (8 + (ch) * 4)))
+#define CRU_SFTRST_DDR_PHY(ch, n)	((0x1 << (9 + 16 + (ch) * 4)) | \
+					 ((n) << (9 + (ch) * 4)))
+
+#define FBDIV_ENC(n)			((n) << 16)
+#define FBDIV_DEC(n)			(((n) >> 16) & 0xfff)
+#define POSTDIV2_ENC(n)			((n) << 12)
+#define POSTDIV2_DEC(n)			(((n) >> 12) & 0x7)
+#define POSTDIV1_ENC(n)			((n) << 8)
+#define POSTDIV1_DEC(n)			(((n) >> 8) & 0x7)
+#define REFDIV_ENC(n)			(n)
+#define REFDIV_DEC(n)			((n) & 0x3f)
+
+/* PMU CRU */
+#define PMUCRU_RSTNHOLD_CON0		0x120
+#define PMUCRU_RSTNHOLD_CON1		0x124
+
+#define PRESET_GPIO0_HOLD(n)		(((n) << 7) | WMSK_BIT(7))
+#define PRESET_GPIO1_HOLD(n)		(((n) << 8) | WMSK_BIT(8))
+
+#define SYS_COUNTER_FREQ_IN_MHZ		(SYS_COUNTER_FREQ_IN_TICKS / 1000000)
+
+/*
+ * Copy @num registers from @src to @dst
+ */
+__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num)
+{
+	while (num--) {
+		mmio_write_32(dst, mmio_read_32(src));
+		dst += sizeof(uint32_t);
+		src += sizeof(uint32_t);
+	}
+}
+
+static __sramfunc uint32_t sram_get_timer_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+static __sramfunc void sram_udelay(uint32_t usec)
+{
+	uint32_t start, cnt, delta, delta_us;
+
+	/* counter is decreasing */
+	start = sram_get_timer_value();
+	do {
+		cnt = sram_get_timer_value();
+		if (cnt > start) {
+			delta = UINT32_MAX - cnt;
+			delta += start;
+		} else
+			delta = start - cnt;
+		delta_us = (delta * SYS_COUNTER_FREQ_IN_MHZ);
+	} while (delta_us < usec);
+}
+
+static __sramfunc void configure_sgrf(void)
+{
+	/*
+	 * SGRF_DDR_RGN_DPLL_CLK and SGRF_DDR_RGN_RTC_CLK:
+	 * IC ECO bug, need to set this register.
+	 *
+	 * SGRF_DDR_RGN_BYPS:
+	 * After the PD_CENTER suspend/resume, the DDR region
+	 * related registers in the SGRF will be reset, we
+	 * need to re-initialize them.
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+		      SGRF_DDR_RGN_DPLL_CLK |
+		      SGRF_DDR_RGN_RTC_CLK |
+		      SGRF_DDR_RGN_BYPS);
+}
+
+static __sramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl,
+		uint32_t phy)
+{
+	channel &= 0x1;
+	ctl &= 0x1;
+	phy &= 0x1;
+	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(4),
+		      CRU_SFTRST_DDR_CTRL(channel, ctl) |
+		      CRU_SFTRST_DDR_PHY(channel, phy));
+}
+
+static __sramfunc void phy_pctrl_reset(uint32_t ch)
+{
+	rkclk_ddr_reset(ch, 1, 1);
+	sram_udelay(10);
+	rkclk_ddr_reset(ch, 1, 0);
+	sram_udelay(10);
+	rkclk_ddr_reset(ch, 0, 0);
+	sram_udelay(10);
+}
+
+static __sramfunc void phy_dll_bypass_set(uint32_t ch, uint32_t hz)
+{
+	if (hz <= 125 * MHz) {
+		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
+		mmio_setbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
+		mmio_setbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
+		mmio_setbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
+		mmio_setbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
+		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
+		mmio_setbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
+		mmio_setbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
+		mmio_setbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
+	} else {
+		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
+		mmio_clrbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
+		mmio_clrbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
+		mmio_clrbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
+		mmio_clrbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
+		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
+		mmio_clrbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
+		mmio_clrbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
+		mmio_clrbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
+	}
+}
+
+static __sramfunc void set_cs_training_index(uint32_t ch, uint32_t rank)
+{
+	/* PHY_8/136/264/392 phy_per_cs_training_index_X 1bit offset_24 */
+	mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 24, rank << 24);
+	mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 24, rank << 24);
+	mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 24, rank << 24);
+	mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 24, rank << 24);
+}
+
+static __sramfunc void select_per_cs_training_index(uint32_t ch, uint32_t rank)
+{
+	/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
+	if ((mmio_read_32(PHY_REG(ch, 84)) >> 16) & 1)
+		set_cs_training_index(ch, rank);
+}
+
+static void override_write_leveling_value(uint32_t ch)
+{
+	uint32_t byte;
+
+	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
+	mmio_setbits_32(PHY_REG(ch, 896), 1);
+
+	/*
+	 * PHY_8/136/264/392
+	 * phy_per_cs_training_multicast_en_X 1bit offset_16
+	 */
+	mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 16, 1 << 16);
+	mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 16, 1 << 16);
+	mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 16, 1 << 16);
+	mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 16, 1 << 16);
+
+	for (byte = 0; byte < 4; byte++)
+		mmio_clrsetbits_32(PHY_REG(ch, 63 + (128 * byte)),
+				   0xffff << 16,
+				   0x200 << 16);
+
+	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
+	mmio_clrbits_32(PHY_REG(ch, 896), 1);
+
+	/* CTL_200 ctrlupd_req 1bit offset_8 */
+	mmio_clrsetbits_32(CTL_REG(ch, 200), 0x1 << 8, 0x1 << 8);
+}
+
+static __sramfunc int data_training(uint32_t ch,
+		struct rk3399_sdram_params *sdram_params,
+		uint32_t training_flag)
+{
+	uint32_t obs_0, obs_1, obs_2, obs_3, obs_err = 0;
+	uint32_t rank = sdram_params->ch[ch].rank;
+	uint32_t rank_mask;
+	uint32_t i, tmp;
+
+	if (sdram_params->dramtype == LPDDR4)
+		rank_mask = (rank == 1) ? 0x5 : 0xf;
+	else
+		rank_mask = (rank == 1) ? 0x1 : 0x3;
+
+	/* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
+	mmio_setbits_32(PHY_REG(ch, 927), (1 << 22));
+
+	if (training_flag == PI_FULL_TRAINING) {
+		if (sdram_params->dramtype == LPDDR4) {
+			training_flag = PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING |
+					PI_READ_LEVELING |
+					PI_WDQ_LEVELING;
+		} else if (sdram_params->dramtype == LPDDR3) {
+			training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING;
+		} else if (sdram_params->dramtype == DDR3) {
+			training_flag = PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING |
+					PI_READ_LEVELING;
+		}
+	}
+
+	/* ca training(LPDDR4,LPDDR3 support) */
+	if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
+		for (i = 0; i < 4; i++) {
+			if (!(rank_mask & (1 << i)))
+				continue;
+
+			select_per_cs_training_index(ch, i);
+			/* PI_100 PI_CALVL_EN:RW:8:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 100), 0x3 << 8, 0x2 << 8);
+
+			/* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 92),
+					   (0x1 << 16) | (0x3 << 24),
+					   (0x1 << 16) | (i << 24));
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * check status obs
+				 * PHY_532/660/788 phy_adr_calvl_obs1_:0:32
+				 */
+				obs_0 = mmio_read_32(PHY_REG(ch, 532));
+				obs_1 = mmio_read_32(PHY_REG(ch, 660));
+				obs_2 = mmio_read_32(PHY_REG(ch, 788));
+				if (((obs_0 >> 30) & 0x3) ||
+				    ((obs_1 >> 30) & 0x3) ||
+				    ((obs_2 >> 30) & 0x3))
+					obs_err = 1;
+				if ((((tmp >> 11) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 5) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 5) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 100), 0x3 << 8);
+	}
+
+	/* write leveling(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(ch, i);
+			/* PI_60 PI_WRLVL_EN:RW:8:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 60), 0x3 << 8, 0x2 << 8);
+			/* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 59),
+					   (0x1 << 8) | (0x3 << 16),
+					   (0x1 << 8) | (i << 16));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * check status obs, if error maybe can not
+				 * get leveling done PHY_40/168/296/424
+				 * phy_wrlvl_status_obs_X:0:13
+				 */
+				obs_0 = mmio_read_32(PHY_REG(ch, 40));
+				obs_1 = mmio_read_32(PHY_REG(ch, 168));
+				obs_2 = mmio_read_32(PHY_REG(ch, 296));
+				obs_3 = mmio_read_32(PHY_REG(ch, 424));
+				if (((obs_0 >> 12) & 0x1) ||
+				    ((obs_1 >> 12) & 0x1) ||
+				    ((obs_2 >> 12) & 0x1) ||
+				    ((obs_3 >> 12) & 0x1))
+					obs_err = 1;
+				if ((((tmp >> 10) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 4) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 4) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		override_write_leveling_value(ch);
+		mmio_clrbits_32(PI_REG(ch, 60), 0x3 << 8);
+	}
+
+	/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(ch, i);
+			/* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 24,
+					   0x2 << 24);
+			/*
+			 * PI_74 PI_RDLVL_GATE_REQ:WR:16:1
+			 * PI_RDLVL_CS:RW:24:2
+			 */
+			mmio_clrsetbits_32(PI_REG(ch, 74),
+					   (0x1 << 16) | (0x3 << 24),
+					   (0x1 << 16) | (i << 24));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * check status obs
+				 * PHY_43/171/299/427
+				 *     PHY_GTLVL_STATUS_OBS_x:16:8
+				 */
+				obs_0 = mmio_read_32(PHY_REG(ch, 43));
+				obs_1 = mmio_read_32(PHY_REG(ch, 171));
+				obs_2 = mmio_read_32(PHY_REG(ch, 299));
+				obs_3 = mmio_read_32(PHY_REG(ch, 427));
+				if (((obs_0 >> (16 + 6)) & 0x3) ||
+				    ((obs_1 >> (16 + 6)) & 0x3) ||
+				    ((obs_2 >> (16 + 6)) & 0x3) ||
+				    ((obs_3 >> (16 + 6)) & 0x3))
+					obs_err = 1;
+				if ((((tmp >> 9) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 3) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 3) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 24);
+	}
+
+	/* read leveling(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(ch, i);
+			/* PI_80 PI_RDLVL_EN:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 16,
+					   0x2 << 16);
+			/* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 74),
+					   (0x1 << 8) | (0x3 << 24),
+					   (0x1 << 8) | (i << 24));
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * make sure status obs not report error bit
+				 * PHY_46/174/302/430
+				 *     phy_rdlvl_status_obs_X:16:8
+				 */
+				if ((((tmp >> 8) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 2) & 0x1) == 0x0))
+					break;
+				else if (((tmp >> 2) & 0x1) == 0x1)
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 16);
+	}
+
+	/* wdq leveling(LPDDR4 support) */
+	if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
+		for (i = 0; i < 4; i++) {
+			if (!(rank_mask & (1 << i)))
+				continue;
+
+			select_per_cs_training_index(ch, i);
+			/*
+			 * disable PI_WDQLVL_VREF_EN before wdq leveling?
+			 * PI_181 PI_WDQLVL_VREF_EN:RW:8:1
+			 */
+			mmio_clrbits_32(PI_REG(ch, 181), 0x1 << 8);
+			/* PI_124 PI_WDQLVL_EN:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 124), 0x3 << 16,
+					   0x2 << 16);
+			/* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 121),
+					   (0x1 << 8) | (0x3 << 16),
+					   (0x1 << 8) | (i << 16));
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+				if ((((tmp >> 12) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 6) & 0x1) == 0x0))
+					break;
+				else if (((tmp >> 6) & 0x1) == 0x1)
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 124), 0x3 << 16);
+	}
+
+	/* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
+	mmio_clrbits_32(PHY_REG(ch, 927), (1 << 22));
+
+	return 0;
+}
+
+static __sramfunc void set_ddrconfig(struct rk3399_sdram_params *sdram_params,
+		unsigned char channel, uint32_t ddrconfig)
+{
+	/* only need to set ddrconfig */
+	struct rk3399_sdram_channel *ch = &sdram_params->ch[channel];
+	unsigned int cs0_cap = 0;
+	unsigned int cs1_cap = 0;
+
+	cs0_cap = (1 << (ch->cs0_row + ch->col + ch->bk + ch->bw - 20));
+	if (ch->rank > 1)
+		cs1_cap = cs0_cap >> (ch->cs0_row - ch->cs1_row);
+	if (ch->row_3_4) {
+		cs0_cap = cs0_cap * 3 / 4;
+		cs1_cap = cs1_cap * 3 / 4;
+	}
+
+	mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICECONF,
+		      ddrconfig | (ddrconfig << 6));
+	mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICESIZE,
+		      ((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8));
+}
+
+static __sramfunc void dram_all_config(struct rk3399_sdram_params *sdram_params)
+{
+	unsigned int i;
+
+	for (i = 0; i < 2; i++) {
+		struct rk3399_sdram_channel *info = &sdram_params->ch[i];
+		struct rk3399_msch_timings *noc = &info->noc_timings;
+
+		if (sdram_params->ch[i].col == 0)
+			continue;
+
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGA0,
+			      noc->ddrtiminga0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGB0,
+			      noc->ddrtimingb0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGC0,
+			      noc->ddrtimingc0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DEVTODEV0,
+			      noc->devtodev0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRMODE, noc->ddrmode.d32);
+
+		/* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */
+		if (sdram_params->ch[i].rank == 1)
+			mmio_setbits_32(CTL_REG(i, 276), 1 << 17);
+	}
+
+	DDR_STRIDE(sdram_params->stride);
+
+	/* reboot hold register set */
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
+		      CRU_PMU_SGRF_RST_RLS |
+		      PRESET_GPIO0_HOLD(1) |
+		      PRESET_GPIO1_HOLD(1));
+	mmio_clrsetbits_32(CRU_BASE + CRU_GLB_RST_CON, 0x3, 0x3);
+}
+
+static __sramfunc void pctl_cfg(uint32_t ch,
+		struct rk3399_sdram_params *sdram_params)
+{
+	const uint32_t *params_ctl = sdram_params->pctl_regs.denali_ctl;
+	const uint32_t *params_phy = sdram_params->phy_regs.denali_phy;
+	const uint32_t *params_pi = sdram_params->pi_regs.denali_pi;
+	uint32_t tmp, tmp1, tmp2;
+
+	/*
+	 * Workaround controller bug:
+	 * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
+	 */
+	sram_regcpy(CTL_REG(ch, 1), (uintptr_t)&params_ctl[1],
+		    CTL_REG_NUM - 1);
+	mmio_write_32(CTL_REG(ch, 0), params_ctl[0]);
+	sram_regcpy(PI_REG(ch, 0), (uintptr_t)&params_pi[0],
+		    PI_REG_NUM);
+
+	mmio_write_32(PHY_REG(ch, 910), params_phy[910]);
+	mmio_write_32(PHY_REG(ch, 911), params_phy[911]);
+	mmio_write_32(PHY_REG(ch, 912), params_phy[912]);
+
+	mmio_clrsetbits_32(CTL_REG(ch, 68), PWRUP_SREFRESH_EXIT,
+				PWRUP_SREFRESH_EXIT);
+
+	/* PHY_DLL_RST_EN */
+	mmio_clrsetbits_32(PHY_REG(ch, 957), 0x3 << 24, 1 << 24);
+	dmbst();
+
+	mmio_setbits_32(PI_REG(ch, 0), START);
+	mmio_setbits_32(CTL_REG(ch, 0), START);
+
+	/* wait lock */
+	while (1) {
+		tmp = mmio_read_32(PHY_REG(ch, 920));
+		tmp1 = mmio_read_32(PHY_REG(ch, 921));
+		tmp2 = mmio_read_32(PHY_REG(ch, 922));
+		if ((((tmp >> 16) & 0x1) == 0x1) &&
+		     (((tmp1 >> 16) & 0x1) == 0x1) &&
+		     (((tmp1 >> 0) & 0x1) == 0x1) &&
+		     (((tmp2 >> 0) & 0x1) == 0x1))
+			break;
+		/* if PLL bypass,don't need wait lock */
+		if (mmio_read_32(PHY_REG(ch, 911)) & 0x1)
+			break;
+	}
+
+	sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&params_phy[896], 63);
+	sram_regcpy(PHY_REG(ch, 0), (uintptr_t)&params_phy[0], 91);
+	sram_regcpy(PHY_REG(ch, 128), (uintptr_t)&params_phy[128], 91);
+	sram_regcpy(PHY_REG(ch, 256), (uintptr_t)&params_phy[256], 91);
+	sram_regcpy(PHY_REG(ch, 384), (uintptr_t)&params_phy[384], 91);
+	sram_regcpy(PHY_REG(ch, 512), (uintptr_t)&params_phy[512], 38);
+	sram_regcpy(PHY_REG(ch, 640), (uintptr_t)&params_phy[640], 38);
+	sram_regcpy(PHY_REG(ch, 768), (uintptr_t)&params_phy[768], 38);
+}
+
+static __sramfunc int dram_switch_to_phy_index1(
+		struct rk3399_sdram_params *sdram_params)
+{
+	uint32_t ch, ch_count;
+
+	mmio_write_32(CIC_BASE + CIC_CTRL0,
+		      (((0x3 << 4) | (1 << 2) | 1) << 16) |
+		      (1 << 4) | (1 << 2) | 1);
+	while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2)))
+		;
+
+	mmio_write_32(CIC_BASE + CIC_CTRL0, 0x20002);
+	while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 0)))
+		;
+
+	ch_count = sdram_params->num_channels;
+
+	/* LPDDR4 f2 cann't do training, all training will fail */
+	for (ch = 0; ch < ch_count; ch++) {
+		mmio_clrsetbits_32(PHY_REG(ch, 896), (0x3 << 8) | 1,
+				   1 << 8);
+
+		/* data_training failed */
+		if (data_training(ch, sdram_params, PI_FULL_TRAINING))
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Needs to be done for both channels at once in case of a shared reset signal
+ * between channels.
+ */
+static __sramfunc int pctl_start(uint32_t channel_mask,
+		struct rk3399_sdram_params *sdram_params)
+{
+	uint32_t count;
+
+	mmio_setbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
+	mmio_setbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
+
+	/* need de-access IO retention before controller START */
+	if (channel_mask & (1 << 0))
+		mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 19));
+	if (channel_mask & (1 << 1))
+		mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 23));
+
+	/* PHY_DLL_RST_EN */
+	if (channel_mask & (1 << 0))
+		mmio_clrsetbits_32(PHY_REG(0, 957), 0x3 << 24,
+				   0x2 << 24);
+	if (channel_mask & (1 << 1))
+		mmio_clrsetbits_32(PHY_REG(1, 957), 0x3 << 24,
+				   0x2 << 24);
+
+	/* check ERROR bit */
+	if (channel_mask & (1 << 0)) {
+		count = 0;
+		while (!(mmio_read_32(CTL_REG(0, 203)) & (1 << 3))) {
+			/* CKE is low, loop 10ms */
+			if (count > 100)
+				return -1;
+
+			sram_udelay(100);
+			count++;
+		}
+
+		mmio_clrbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
+	}
+	if (channel_mask & (1 << 1)) {
+		count = 0;
+		while (!(mmio_read_32(CTL_REG(1, 203)) & (1 << 3))) {
+			/* CKE is low, loop 10ms */
+			if (count > 100)
+				return -1;
+
+			sram_udelay(100);
+			count++;
+		}
+
+		mmio_clrbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
+	}
+
+	return 0;
+}
+
+void dmc_save(void)
+{
+	struct rk3399_sdram_params *sdram_params = &sdram_config;
+	uint32_t *params_ctl;
+	uint32_t *params_pi;
+	uint32_t *params_phy;
+	uint32_t refdiv, postdiv2, postdiv1, fbdiv;
+	uint32_t tmp;
+
+	params_ctl = sdram_params->pctl_regs.denali_ctl;
+	params_pi = sdram_params->pi_regs.denali_pi;
+	params_phy = sdram_params->phy_regs.denali_phy;
+
+	fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
+	tmp = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1));
+	postdiv2 = POSTDIV2_DEC(tmp);
+	postdiv1 = POSTDIV1_DEC(tmp);
+	refdiv = REFDIV_DEC(tmp);
+
+	sdram_params->ddr_freq = ((fbdiv * 24) /
+				(refdiv * postdiv1 * postdiv2)) * MHz;
+
+	INFO("sdram_params->ddr_freq = %d\n", sdram_params->ddr_freq);
+	sdram_params->odt = (((mmio_read_32(PHY_REG(0, 5)) >> 16) &
+			       0x7) != 0) ? 1 : 0;
+
+	/* copy the registers CTL PI and PHY */
+	sram_regcpy((uintptr_t)&params_ctl[0], CTL_REG(0, 0), CTL_REG_NUM);
+
+	/* mask DENALI_CTL_00_DATA.START, only copy here, will trigger later */
+	params_ctl[0] &= ~(0x1 << 0);
+
+	sram_regcpy((uintptr_t)&params_pi[0], PI_REG(0, 0),
+		    PI_REG_NUM);
+
+	/* mask DENALI_PI_00_DATA.START, only copy here, will trigger later*/
+	params_pi[0] &= ~(0x1 << 0);
+
+	sram_regcpy((uintptr_t)&params_phy[0], PHY_REG(0, 0), 91);
+	sram_regcpy((uintptr_t)&params_phy[128], PHY_REG(0, 128), 91);
+	sram_regcpy((uintptr_t)&params_phy[256], PHY_REG(0, 256), 91);
+	sram_regcpy((uintptr_t)&params_phy[384], PHY_REG(0, 384), 91);
+	sram_regcpy((uintptr_t)&params_phy[512], PHY_REG(0, 512), 38);
+	sram_regcpy((uintptr_t)&params_phy[640], PHY_REG(0, 640), 38);
+	sram_regcpy((uintptr_t)&params_phy[768], PHY_REG(0, 768), 38);
+	sram_regcpy((uintptr_t)&params_phy[896], PHY_REG(0, 896), 63);
+
+	/* set DENALI_PHY_957_DATA.PHY_DLL_RST_EN = 0x1 */
+	params_phy[957] &= ~(0x3 << 24);
+	params_phy[957] |= 1 << 24;
+	params_phy[896] |= 1;
+	params_phy[896] &= ~(0x3 << 8);
+}
+
+__sramfunc void dmc_restore(void)
+{
+	struct rk3399_sdram_params *sdram_params = &sdram_config;
+	uint32_t channel_mask = 0;
+	uint32_t channel;
+
+	configure_sgrf();
+
+retry:
+	for (channel = 0; channel < sdram_params->num_channels; channel++) {
+		phy_pctrl_reset(channel);
+		phy_dll_bypass_set(channel, sdram_params->ddr_freq);
+		if (channel >= sdram_params->num_channels)
+			continue;
+
+		pctl_cfg(channel, sdram_params);
+	}
+
+	for (channel = 0; channel < 2; channel++) {
+		if (sdram_params->ch[channel].col)
+			channel_mask |= 1 << channel;
+	}
+
+	if (pctl_start(channel_mask, sdram_params) < 0)
+		goto retry;
+
+	for (channel = 0; channel < sdram_params->num_channels; channel++) {
+		/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
+		if (sdram_params->dramtype == LPDDR3)
+			sram_udelay(10);
+
+		/* If traning fail, retry to do it again. */
+		if (data_training(channel, sdram_params, PI_FULL_TRAINING))
+			goto retry;
+
+		set_ddrconfig(sdram_params, channel,
+			      sdram_params->ch[channel].ddrconfig);
+	}
+
+	dram_all_config(sdram_params);
+
+	/* Switch to index 1 and prepare for DDR frequency switch. */
+	dram_switch_to_phy_index1(sdram_params);
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.h b/plat/rockchip/rk3399/drivers/dram/suspend.h
new file mode 100644
index 0000000..2159861
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.h
@@ -0,0 +1,50 @@
+/*
+ * 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_SUSPEND_H__
+#define __SOC_ROCKCHIP_RK3399_SUSPEND_H__
+#include <dram.h>
+
+#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_TRAINING	(0xff)
+
+void dmc_save(void);
+__sramfunc void dmc_restore(void);
+__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num);
+
+#endif /* __DRAM_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
index 7241964..405e1d5 100644
--- a/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
+++ b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
@@ -27,9 +27,25 @@
 #include <arch.h>
 #include <asm_macros.S>
 #include <platform_def.h>
+#include <pmu_regs.h>
 
 	.globl	clst_warmboot_data
 
+	.macro sram_func _name
+	.section .sram.text, "ax"
+	.type \_name, %function
+	.func \_name
+	\_name:
+	.endm
+
+#define CRU_CLKSEL_CON6	0x118
+
+#define DDRCTL0_C_SYSREQ_CFG 0x0100
+#define DDRCTL1_C_SYSREQ_CFG 0x1000
+
+#define DDRC0_SREF_DONE_EXT 0x01
+#define DDRC1_SREF_DONE_EXT 0x04
+
 #define PLL_MODE_SHIFT	(0x8)
 #define PLL_NORMAL_MODE	((0x3 << (PLL_MODE_SHIFT + 16)) | \
 						 (0x1 << PLL_MODE_SHIFT))
@@ -65,3 +81,75 @@
 	.word	0
 	.endr
 .endm
+
+	/* -----------------------------------------------
+	 * void sram_func_set_ddrctl_pll(uint32_t pll_src)
+	 * Function to switch the PLL source for ddrctrl
+	 * In: x0 - The PLL of the clk_ddrc clock source
+	 * out: None
+	 * Clobber list : x0 - x3, x5, x8 - x10
+	 * -----------------------------------------------
+	 */
+
+	.globl	sram_func_set_ddrctl_pll
+
+sram_func sram_func_set_ddrctl_pll
+	/* backup parameter */
+	mov	x8, x0
+
+	/* disable the MMU at EL3 */
+	mrs 	x9, sctlr_el3
+	bic	x10, x9, #(SCTLR_M_BIT)
+	msr 	sctlr_el3, x10
+	isb
+	dsb 	sy
+
+	/* enable ddrctl0_1 idle request */
+	mov	x5, PMU_BASE
+	ldr	w0, [x5, #PMU_SFT_CON]
+	orr	w0, w0, #DDRCTL0_C_SYSREQ_CFG
+	orr	w0, w0, #DDRCTL1_C_SYSREQ_CFG
+	str	w0, [x5, #PMU_SFT_CON]
+
+check_ddrc0_1_sref_enter:
+	ldr	w1, [x5, #PMU_DDR_SREF_ST]
+	and	w2, w1, #DDRC0_SREF_DONE_EXT
+	and	w3, w1, #DDRC1_SREF_DONE_EXT
+	orr	w2, w2, w3
+	cmp	w2, #(DDRC0_SREF_DONE_EXT | DDRC1_SREF_DONE_EXT)
+	b.eq	check_ddrc0_1_sref_enter
+
+	/*
+	 * select a PLL for ddrctrl:
+	 * x0 = 0: ALPLL
+	 * x0 = 1: ABPLL
+	 * x0 = 2: DPLL
+	 * x0 = 3: GPLLL
+	 */
+	mov     x5, CRU_BASE
+	lsl	w0, w8, #4
+	orr	w0, w0, #0x00300000
+	str 	w0, [x5, #CRU_CLKSEL_CON6]
+
+	/* disable ddrctl0_1 idle request */
+	mov	x5, PMU_BASE
+	ldr	w0, [x5, #PMU_SFT_CON]
+	bic	w0, w0, #DDRCTL0_C_SYSREQ_CFG
+	bic	w0, w0, #DDRCTL1_C_SYSREQ_CFG
+	str	w0, [x5, #PMU_SFT_CON]
+
+check_ddrc0_1_sref_exit:
+	ldr	w1, [x5, #PMU_DDR_SREF_ST]
+	and	w2, w1, #DDRC0_SREF_DONE_EXT
+	and	w3, w1, #DDRC1_SREF_DONE_EXT
+	orr	w2, w2, w3
+	cmp	w2, #0x0
+	b.eq	check_ddrc0_1_sref_exit
+
+	/* reenable the MMU at EL3 */
+	msr 	sctlr_el3, x9
+	isb
+	dsb 	sy
+
+	ret
+endfunc sram_func_set_ddrctl_pll
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 8d3f482..5a385cb 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -46,9 +46,9 @@
 #include <pmu.h>
 #include <pmu_com.h>
 #include <pwm.h>
-#include <soc.h>
 #include <bl31.h>
 #include <rk3399m0.h>
+#include <suspend.h>
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
@@ -102,7 +102,6 @@
 		     mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK),
 		     bus_ack);
 	}
-
 }
 
 struct pmu_slpdata_s pmu_slpdata;
@@ -818,10 +817,19 @@
 	mmio_write_32(PMU_BASE + PMU_GPU_PWRUP_CNT, CYCL_24M_CNT_US(1));
 }
 
+static uint32_t clk_ddrc_save;
+
 static void sys_slp_config(void)
 {
 	uint32_t slp_mode_cfg = 0;
 
+	/* keep enabling clk_ddrc_bpll_src_en gate for DDRC */
+	clk_ddrc_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(3));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3), WMSK_BIT(1));
+
+	prepare_abpll_for_ddrctrl();
+	sram_func_set_ddrctl_pll(ABPLL_ID);
+
 	mmio_write_32(GRF_BASE + GRF_SOC_CON4, CCI_FORCE_WAKEUP);
 	mmio_write_32(PMU_BASE + PMU_CCI500_CON,
 		      BIT_WITH_WMSK(PMU_CLR_PREQ_CCI500_HW) |
@@ -849,6 +857,7 @@
 		       BIT(PMU_DDRIO0_RET_EN) |
 		       BIT(PMU_DDRIO1_RET_EN) |
 		       BIT(PMU_DDRIO_RET_HW_DE_REQ) |
+		       BIT(PMU_CENTER_PD_EN) |
 		       BIT(PMU_PLL_PD_EN) |
 		       BIT(PMU_CLK_CENTER_SRC_GATE_EN) |
 		       BIT(PMU_OSC_DIS) |
@@ -857,7 +866,6 @@
 	mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_GPIO_WKUP_EN));
 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg);
 
-
 	mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW);
 	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K);
 	mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /* 32k iomux */
@@ -1094,6 +1102,9 @@
 	uint32_t wait_cnt = 0;
 	uint32_t status = 0;
 
+	dmc_save();
+	pmu_scu_b_pwrdn();
+
 	pmu_power_domains_suspend();
 	set_hw_idle(BIT(PMU_CLR_CENTER1) |
 		    BIT(PMU_CLR_ALIVE) |
@@ -1114,8 +1125,6 @@
 		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
 		      CPU_BOOT_ADDR_WMASK);
 
-	pmu_scu_b_pwrdn();
-
 	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
 		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
 		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_SW) |
@@ -1134,6 +1143,7 @@
 		}
 	}
 	mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
+
 	/*
 	 * Disabling PLLs/PWM/DVFS is approaching WFI which is
 	 * the last steps in suspend.
@@ -1163,6 +1173,10 @@
 	enable_dvfs_plls();
 	plls_resume_finish();
 
+	/* restore clk_ddrc_bpll_src_en gate */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3),
+		      BITS_WITH_WMASK(clk_ddrc_save, 0xff, 0));
+
 	/*
 	 * The wakeup status is not cleared by itself, we need to clear it
 	 * manually. Otherwise we will alway query some interrupt next time.
@@ -1209,8 +1223,12 @@
 
 	pmu_sgrf_rst_hld_release();
 	pmu_scu_b_pwrup();
-
 	pmu_power_domains_resume();
+
+	restore_dpll();
+	sram_func_set_ddrctl_pll(DPLL_ID);
+	restore_abpll();
+
 	clr_hw_idle(BIT(PMU_CLR_CENTER1) |
 				BIT(PMU_CLR_ALIVE) |
 				BIT(PMU_CLR_MSCH0) |
@@ -1301,9 +1319,10 @@
 	for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++)
 		clst_warmboot_data[cpu] = 0;
 
-	psram_sleep_cfg->ddr_func = 0x00;
-	psram_sleep_cfg->ddr_data = 0x00;
-	psram_sleep_cfg->ddr_flag = 0x00;
+	psram_sleep_cfg->ddr_func = (uint64_t)dmc_restore;
+	psram_sleep_cfg->ddr_data = (uint64_t)&sdram_config;
+	psram_sleep_cfg->ddr_flag = 0x01;
+
 	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
 
 	/* config cpu's warm boot address */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
index ab2896b..22c8c63 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.h
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -31,6 +31,9 @@
 #ifndef __PMU_H__
 #define __PMU_H__
 
+#include <pmu_regs.h>
+#include <soc.h>
+
 /* Allocate sp reginon in pmusram */
 #define PSRAM_SP_SIZE		0x80
 #define PSRAM_SP_BOTTOM		(PSRAM_SP_TOP - PSRAM_SP_SIZE)
@@ -751,72 +754,7 @@
 	STANDBY_BY_WFIL2_CLUSTER_B,
 };
 
-#define PMU_WKUP_CFG0		0x00
-#define PMU_WKUP_CFG1		0x04
-#define PMU_WKUP_CFG2		0x08
-#define PMU_WKUP_CFG3		0x0c
-#define PMU_WKUP_CFG4		0x10
-#define PMU_PWRDN_CON		0x14
-#define PMU_PWRDN_ST		0x18
-#define PMU_PLL_CON		0x1c
-#define PMU_PWRMODE_CON		0x20
-#define PMU_SFT_CON		0x24
-#define PMU_INT_CON		0x28
-#define PMU_INT_ST		0x2c
-#define PMU_GPIO0_POS_INT_CON	0x30
-#define PMU_GPIO0_NEG_INT_CON	0x34
-#define PMU_GPIO1_POS_INT_CON	0x38
-#define PMU_GPIO1_NEG_INT_CON	0x3c
-#define PMU_GPIO0_POS_INT_ST	0x40
-#define PMU_GPIO0_NEG_INT_ST	0x44
-#define PMU_GPIO1_POS_INT_ST	0x48
-#define PMU_GPIO1_NEG_INT_ST	0x4c
-#define PMU_PWRDN_INTEN		0x50
-#define PMU_PWRDN_STATUS	0x54
-#define PMU_WAKEUP_STATUS	0x58
-#define PMU_BUS_CLR		0x5c
-#define PMU_BUS_IDLE_REQ	0x60
-#define PMU_BUS_IDLE_ST		0x64
-#define PMU_BUS_IDLE_ACK	0x68
-#define PMU_CCI500_CON		0x6c
-#define PMU_ADB400_CON		0x70
-#define PMU_ADB400_ST		0x74
-#define PMU_POWER_ST		0x78
-#define PMU_CORE_PWR_ST		0x7c
-#define PMU_OSC_CNT		0x80
-#define PMU_PLLLOCK_CNT		0x84
-#define PMU_PLLRST_CNT		0x88
-#define PMU_STABLE_CNT		0x8c
-#define PMU_DDRIO_PWRON_CNT	0x90
-#define PMU_WAKEUP_RST_CLR_CNT	0x94
-#define PMU_DDR_SREF_ST		0x98
-#define PMU_SCU_L_PWRDN_CNT	0x9c
-#define PMU_SCU_L_PWRUP_CNT	0xa0
-#define PMU_SCU_B_PWRDN_CNT	0xa4
-#define PMU_SCU_B_PWRUP_CNT	0xa8
-#define PMU_GPU_PWRDN_CNT	0xac
-#define PMU_GPU_PWRUP_CNT	0xb0
-#define PMU_CENTER_PWRDN_CNT	0xb4
-#define PMU_CENTER_PWRUP_CNT	0xb8
-#define PMU_TIMEOUT_CNT		0xbc
-#define PMU_CPU0APM_CON		0xc0
-#define PMU_CPU1APM_CON		0xc4
-#define PMU_CPU2APM_CON		0xc8
-#define PMU_CPU3APM_CON		0xcc
-#define PMU_CPU0BPM_CON		0xd0
-#define PMU_CPU1BPM_CON		0xd4
-#define PMU_NOC_AUTO_ENA	0xd8
-#define PMU_PWRDN_CON1		0xdc
-
-#define PMUGRF_GPIO0A_IOMUX	0x00
-#define PMUGRF_GPIO1A_IOMUX	0x10
-#define PMUGRF_GPIO1C_IOMUX	0x18
-
-#define PMUGRF_GPIO0A6_IOMUX_SHIFT      12
-#define PMUGRF_GPIO0A6_IOMUX_PWM        0x1
-#define PMUGRF_GPIO1C3_IOMUX_SHIFT      6
-#define PMUGRF_GPIO1C3_IOMUX_PWM        0x1
-
+/* Specific features required  */
 #define AP_PWROFF		0x0a
 
 #define GPIO0A0_SMT_ENABLE	BITS_WITH_WMASK(1, 3, 0)
@@ -824,51 +762,6 @@
 
 #define TSADC_INT_PIN		38
 #define CORES_PM_DISABLE	0x0
-#define CPU_AXI_QOS_ID_COREID		0x00
-#define CPU_AXI_QOS_REVISIONID		0x04
-#define CPU_AXI_QOS_PRIORITY		0x08
-#define CPU_AXI_QOS_MODE		0x0c
-#define CPU_AXI_QOS_BANDWIDTH		0x10
-#define CPU_AXI_QOS_SATURATION		0x14
-#define CPU_AXI_QOS_EXTCONTROL		0x18
-#define CPU_AXI_QOS_NUM_REGS		0x07
-
-#define CPU_AXI_CCI_M0_QOS_BASE		0xffa50000
-#define CPU_AXI_CCI_M1_QOS_BASE		0xffad8000
-#define CPU_AXI_DMAC0_QOS_BASE		0xffa64200
-#define CPU_AXI_DMAC1_QOS_BASE		0xffa64280
-#define CPU_AXI_DCF_QOS_BASE		0xffa64180
-#define CPU_AXI_CRYPTO0_QOS_BASE	0xffa64100
-#define CPU_AXI_CRYPTO1_QOS_BASE	0xffa64080
-#define CPU_AXI_PMU_CM0_QOS_BASE	0xffa68000
-#define CPU_AXI_PERI_CM1_QOS_BASE	0xffa64300
-#define CPU_AXI_GIC_QOS_BASE		0xffa78000
-#define CPU_AXI_SDIO_QOS_BASE		0xffa76000
-#define CPU_AXI_SDMMC_QOS_BASE		0xffa74000
-#define CPU_AXI_EMMC_QOS_BASE		0xffa58000
-#define CPU_AXI_GMAC_QOS_BASE		0xffa5c000
-#define CPU_AXI_USB_OTG0_QOS_BASE	0xffa70000
-#define CPU_AXI_USB_OTG1_QOS_BASE	0xffa70080
-#define CPU_AXI_USB_HOST0_QOS_BASE	0xffa60100
-#define CPU_AXI_USB_HOST1_QOS_BASE	0xffa60180
-#define CPU_AXI_GPU_QOS_BASE		0xffae0000
-#define CPU_AXI_VIDEO_M0_QOS_BASE	0xffab8000
-#define CPU_AXI_VIDEO_M1_R_QOS_BASE	0xffac0000
-#define CPU_AXI_VIDEO_M1_W_QOS_BASE	0xffac0080
-#define CPU_AXI_RGA_R_QOS_BASE		0xffab0000
-#define CPU_AXI_RGA_W_QOS_BASE		0xffab0080
-#define CPU_AXI_IEP_QOS_BASE		0xffa98000
-#define CPU_AXI_VOP_BIG_R_QOS_BASE	0xffac8000
-#define CPU_AXI_VOP_BIG_W_QOS_BASE	0xffac8080
-#define CPU_AXI_VOP_LITTLE_QOS_BASE	0xffad0000
-#define CPU_AXI_ISP0_M0_QOS_BASE	0xffaa0000
-#define CPU_AXI_ISP0_M1_QOS_BASE	0xffaa0080
-#define CPU_AXI_ISP1_M0_QOS_BASE	0xffaa8000
-#define CPU_AXI_ISP1_M1_QOS_BASE	0xffaa8080
-#define CPU_AXI_HDCP_QOS_BASE		0xffa90000
-#define CPU_AXI_PERIHP_NSP_QOS_BASE	0xffad8080
-#define CPU_AXI_PERILP_NSP_QOS_BASE	0xffad8180
-#define CPU_AXI_PERILPSLV_NSP_QOS_BASE	0xffad8100
 
 #define PD_CTR_LOOP		500
 #define CHK_CPU_LOOP		500
@@ -876,32 +769,6 @@
 
 #define	GRF_SOC_CON4		0x0e210
 
-#define GRF_GPIO2A_IOMUX	0xe000
-#define GRF_GPIO2B_IOMUX	0xe004
-#define GRF_GPIO2C_IOMUX	0xe008
-#define GRF_GPIO2D_IOMUX	0xe00c
-#define GRF_GPIO3A_IOMUX	0xe010
-#define GRF_GPIO3B_IOMUX	0xe014
-#define GRF_GPIO3C_IOMUX	0xe018
-#define GRF_GPIO3D_IOMUX	0xe01c
-#define GRF_GPIO4A_IOMUX	0xe020
-#define GRF_GPIO4B_IOMUX	0xe024
-#define GRF_GPIO4C_IOMUX	0xe028
-#define GRF_GPIO4D_IOMUX	0xe02c
-
-#define GRF_GPIO2A_P		0xe040
-#define GRF_GPIO2B_P		0xe044
-#define GRF_GPIO2C_P		0xe048
-#define GRF_GPIO2D_P		0xe04C
-#define GRF_GPIO3A_P		0xe050
-#define GRF_GPIO3B_P		0xe054
-#define GRF_GPIO3C_P		0xe058
-#define GRF_GPIO3D_P		0xe05C
-#define GRF_GPIO4A_P		0xe060
-#define GRF_GPIO4B_P		0xe064
-#define GRF_GPIO4C_P		0xe068
-#define GRF_GPIO4D_P		0xe06C
-
 #define PMUGRF_GPIO0A_SMT	0x0120
 #define PMUGRF_SOC_CON0		0x0180
 
@@ -977,4 +844,7 @@
 };
 
 extern uint32_t clst_warmboot_data[PLATFORM_CLUSTER_COUNT];
+
+extern void sram_func_set_ddrctl_pll(uint32_t pll_src);
+
 #endif /* __PMU_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_regs.h b/plat/rockchip/rk3399/drivers/pmu/pmu_regs.h
new file mode 100644
index 0000000..399d844
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu_regs.h
@@ -0,0 +1,172 @@
+/*
+ * 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 __PMU_REGS_H__
+#define __PMU_REGS_H__
+
+#define PMU_WKUP_CFG0		0x00
+#define PMU_WKUP_CFG1		0x04
+#define PMU_WKUP_CFG2		0x08
+#define PMU_WKUP_CFG3		0x0c
+#define PMU_WKUP_CFG4		0x10
+#define PMU_PWRDN_CON		0x14
+#define PMU_PWRDN_ST		0x18
+#define PMU_PLL_CON		0x1c
+#define PMU_PWRMODE_CON		0x20
+#define PMU_SFT_CON		0x24
+#define PMU_INT_CON		0x28
+#define PMU_INT_ST		0x2c
+#define PMU_GPIO0_POS_INT_CON	0x30
+#define PMU_GPIO0_NEG_INT_CON	0x34
+#define PMU_GPIO1_POS_INT_CON	0x38
+#define PMU_GPIO1_NEG_INT_CON	0x3c
+#define PMU_GPIO0_POS_INT_ST	0x40
+#define PMU_GPIO0_NEG_INT_ST	0x44
+#define PMU_GPIO1_POS_INT_ST	0x48
+#define PMU_GPIO1_NEG_INT_ST	0x4c
+#define PMU_PWRDN_INTEN		0x50
+#define PMU_PWRDN_STATUS	0x54
+#define PMU_WAKEUP_STATUS	0x58
+#define PMU_BUS_CLR		0x5c
+#define PMU_BUS_IDLE_REQ	0x60
+#define PMU_BUS_IDLE_ST		0x64
+#define PMU_BUS_IDLE_ACK	0x68
+#define PMU_CCI500_CON		0x6c
+#define PMU_ADB400_CON		0x70
+#define PMU_ADB400_ST		0x74
+#define PMU_POWER_ST		0x78
+#define PMU_CORE_PWR_ST		0x7c
+#define PMU_OSC_CNT		0x80
+#define PMU_PLLLOCK_CNT		0x84
+#define PMU_PLLRST_CNT		0x88
+#define PMU_STABLE_CNT		0x8c
+#define PMU_DDRIO_PWRON_CNT	0x90
+#define PMU_WAKEUP_RST_CLR_CNT	0x94
+#define PMU_DDR_SREF_ST		0x98
+#define PMU_SCU_L_PWRDN_CNT	0x9c
+#define PMU_SCU_L_PWRUP_CNT	0xa0
+#define PMU_SCU_B_PWRDN_CNT	0xa4
+#define PMU_SCU_B_PWRUP_CNT	0xa8
+#define PMU_GPU_PWRDN_CNT	0xac
+#define PMU_GPU_PWRUP_CNT	0xb0
+#define PMU_CENTER_PWRDN_CNT	0xb4
+#define PMU_CENTER_PWRUP_CNT	0xb8
+#define PMU_TIMEOUT_CNT		0xbc
+#define PMU_CPU0APM_CON		0xc0
+#define PMU_CPU1APM_CON		0xc4
+#define PMU_CPU2APM_CON		0xc8
+#define PMU_CPU3APM_CON		0xcc
+#define PMU_CPU0BPM_CON		0xd0
+#define PMU_CPU1BPM_CON		0xd4
+#define PMU_NOC_AUTO_ENA	0xd8
+#define PMU_PWRDN_CON1		0xdc
+
+#define PMUGRF_GPIO0A_IOMUX	0x00
+#define PMUGRF_GPIO1A_IOMUX	0x10
+#define PMUGRF_GPIO1C_IOMUX	0x18
+
+#define PMUGRF_GPIO0A6_IOMUX_SHIFT      12
+#define PMUGRF_GPIO0A6_IOMUX_PWM        0x1
+#define PMUGRF_GPIO1C3_IOMUX_SHIFT      6
+#define PMUGRF_GPIO1C3_IOMUX_PWM        0x1
+
+#define CPU_AXI_QOS_ID_COREID		0x00
+#define CPU_AXI_QOS_REVISIONID		0x04
+#define CPU_AXI_QOS_PRIORITY		0x08
+#define CPU_AXI_QOS_MODE		0x0c
+#define CPU_AXI_QOS_BANDWIDTH		0x10
+#define CPU_AXI_QOS_SATURATION		0x14
+#define CPU_AXI_QOS_EXTCONTROL		0x18
+#define CPU_AXI_QOS_NUM_REGS		0x07
+
+#define CPU_AXI_CCI_M0_QOS_BASE		0xffa50000
+#define CPU_AXI_CCI_M1_QOS_BASE		0xffad8000
+#define CPU_AXI_DMAC0_QOS_BASE		0xffa64200
+#define CPU_AXI_DMAC1_QOS_BASE		0xffa64280
+#define CPU_AXI_DCF_QOS_BASE		0xffa64180
+#define CPU_AXI_CRYPTO0_QOS_BASE	0xffa64100
+#define CPU_AXI_CRYPTO1_QOS_BASE	0xffa64080
+#define CPU_AXI_PMU_CM0_QOS_BASE	0xffa68000
+#define CPU_AXI_PERI_CM1_QOS_BASE	0xffa64300
+#define CPU_AXI_GIC_QOS_BASE		0xffa78000
+#define CPU_AXI_SDIO_QOS_BASE		0xffa76000
+#define CPU_AXI_SDMMC_QOS_BASE		0xffa74000
+#define CPU_AXI_EMMC_QOS_BASE		0xffa58000
+#define CPU_AXI_GMAC_QOS_BASE		0xffa5c000
+#define CPU_AXI_USB_OTG0_QOS_BASE	0xffa70000
+#define CPU_AXI_USB_OTG1_QOS_BASE	0xffa70080
+#define CPU_AXI_USB_HOST0_QOS_BASE	0xffa60100
+#define CPU_AXI_USB_HOST1_QOS_BASE	0xffa60180
+#define CPU_AXI_GPU_QOS_BASE		0xffae0000
+#define CPU_AXI_VIDEO_M0_QOS_BASE	0xffab8000
+#define CPU_AXI_VIDEO_M1_R_QOS_BASE	0xffac0000
+#define CPU_AXI_VIDEO_M1_W_QOS_BASE	0xffac0080
+#define CPU_AXI_RGA_R_QOS_BASE		0xffab0000
+#define CPU_AXI_RGA_W_QOS_BASE		0xffab0080
+#define CPU_AXI_IEP_QOS_BASE		0xffa98000
+#define CPU_AXI_VOP_BIG_R_QOS_BASE	0xffac8000
+#define CPU_AXI_VOP_BIG_W_QOS_BASE	0xffac8080
+#define CPU_AXI_VOP_LITTLE_QOS_BASE	0xffad0000
+#define CPU_AXI_ISP0_M0_QOS_BASE	0xffaa0000
+#define CPU_AXI_ISP0_M1_QOS_BASE	0xffaa0080
+#define CPU_AXI_ISP1_M0_QOS_BASE	0xffaa8000
+#define CPU_AXI_ISP1_M1_QOS_BASE	0xffaa8080
+#define CPU_AXI_HDCP_QOS_BASE		0xffa90000
+#define CPU_AXI_PERIHP_NSP_QOS_BASE	0xffad8080
+#define CPU_AXI_PERILP_NSP_QOS_BASE	0xffad8180
+#define CPU_AXI_PERILPSLV_NSP_QOS_BASE	0xffad8100
+
+#define GRF_GPIO2A_IOMUX	0xe000
+#define GRF_GPIO2B_IOMUX	0xe004
+#define GRF_GPIO2C_IOMUX	0xe008
+#define GRF_GPIO2D_IOMUX	0xe00c
+#define GRF_GPIO3A_IOMUX	0xe010
+#define GRF_GPIO3B_IOMUX	0xe014
+#define GRF_GPIO3C_IOMUX	0xe018
+#define GRF_GPIO3D_IOMUX	0xe01c
+#define GRF_GPIO4A_IOMUX	0xe020
+#define GRF_GPIO4B_IOMUX	0xe024
+#define GRF_GPIO4C_IOMUX	0xe028
+#define GRF_GPIO4D_IOMUX	0xe02c
+
+#define GRF_GPIO2A_P		0xe040
+#define GRF_GPIO2B_P		0xe044
+#define GRF_GPIO2C_P		0xe048
+#define GRF_GPIO2D_P		0xe04C
+#define GRF_GPIO3A_P		0xe050
+#define GRF_GPIO3B_P		0xe054
+#define GRF_GPIO3C_P		0xe058
+#define GRF_GPIO3D_P		0xe05C
+#define GRF_GPIO4A_P		0xe060
+#define GRF_GPIO4B_P		0xe064
+#define GRF_GPIO4C_P		0xe068
+#define GRF_GPIO4D_P		0xe06C
+
+#endif /* __PMU_REGS_H__ */
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
index e99db19..9529cb2 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.c
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -34,6 +34,7 @@
 #include <mmio.h>
 #include <platform_def.h>
 #include <plat_private.h>
+#include <dram.h>
 #include <rk3399_def.h>
 #include <rk3399m0.h>
 #include <soc.h>
@@ -42,6 +43,8 @@
 const mmap_region_t plat_rk_mmap[] = {
 	MAP_REGION_FLAT(RK3399_DEV_RNG0_BASE, RK3399_DEV_RNG0_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
 
 	{ 0 }
 };
@@ -237,21 +240,105 @@
 	set_pll_bypass(pll_id);
 }
 
+/**
+ * disable_dvfs_plls - To suspend the specific PLLs
+ *
+ * When we close the center logic, the DPLL will be closed,
+ * so we need to keep the ABPLL and switch to it to supply
+ * clock for DDR during suspend, then we should not close
+ * the ABPLL and exclude ABPLL_ID.
+ */
 void disable_dvfs_plls(void)
 {
 	_pll_suspend(CPLL_ID);
 	_pll_suspend(NPLL_ID);
 	_pll_suspend(VPLL_ID);
 	_pll_suspend(GPLL_ID);
-	_pll_suspend(ABPLL_ID);
 	_pll_suspend(ALPLL_ID);
 }
 
+/**
+ * disable_nodvfs_plls - To suspend the PPLL
+ */
 void disable_nodvfs_plls(void)
 {
 	_pll_suspend(PPLL_ID);
 }
 
+/**
+ * restore_pll - Copy PLL settings from memory to a PLL.
+ *
+ * This will copy PLL settings from an array in memory to the memory mapped
+ * registers for a PLL.
+ *
+ * Note that: above the PLL exclude PPLL.
+ *
+ * pll_id: One of the values from enum plls_id
+ * src: Pointer to the array of values to restore from
+ */
+static void restore_pll(int pll_id, uint32_t *src)
+{
+	/* Nice to have PLL off while configuring */
+	mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE);
+
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 0), src[0] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 1), src[1] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 2), src[2]);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 4), src[4] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 5), src[5] | REG_SOC_WMSK);
+
+	/* Do PLL_CON3 since that will enable things */
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), src[3] | REG_SOC_WMSK);
+
+	/* Wait for PLL lock done */
+	while ((mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 2)) &
+		0x80000000) == 0x0)
+		;
+}
+
+/**
+ * save_pll - Copy PLL settings a PLL to memory
+ *
+ * This will copy PLL settings from the memory mapped registers for a PLL to
+ * an array in memory.
+ *
+ * Note that: above the PLL exclude PPLL.
+ *
+ * pll_id: One of the values from enum plls_id
+ * src: Pointer to the array of values to save to.
+ */
+static void save_pll(uint32_t *dst, int pll_id)
+{
+	int i;
+
+	for (i = 0; i < PLL_CON_COUNT; i++)
+		dst[i] = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, i));
+}
+
+/**
+ * prepare_abpll_for_ddrctrl - Copy DPLL settings to ABPLL
+ *
+ * This will copy DPLL settings from the memory mapped registers for a PLL to
+ * an array in memory.
+ */
+void prepare_abpll_for_ddrctrl(void)
+{
+	save_pll(slp_data.plls_con[ABPLL_ID], ABPLL_ID);
+	save_pll(slp_data.plls_con[DPLL_ID], DPLL_ID);
+
+	restore_pll(ABPLL_ID, slp_data.plls_con[DPLL_ID]);
+}
+
+void restore_abpll(void)
+{
+	restore_pll(ABPLL_ID, slp_data.plls_con[ABPLL_ID]);
+}
+
+void restore_dpll(void)
+{
+	restore_pll(DPLL_ID, slp_data.plls_con[DPLL_ID]);
+}
+
 void plls_suspend_prepare(void)
 {
 	uint32_t i, pll_id;
@@ -342,16 +429,25 @@
 			      REG_SOC_WMSK | slp_data.pmucru_clksel_con[i]);
 }
 
+/**
+ * enable_dvfs_plls - To resume the specific PLLs
+ *
+ * Please see the comment at the disable_dvfs_plls()
+ * we don't suspend the ABPLL, so don't need resume
+ * it too.
+ */
 void enable_dvfs_plls(void)
 {
 	_pll_resume(ALPLL_ID);
-	_pll_resume(ABPLL_ID);
 	_pll_resume(GPLL_ID);
 	_pll_resume(VPLL_ID);
 	_pll_resume(NPLL_ID);
 	_pll_resume(CPLL_ID);
 }
 
+/**
+ * enable_nodvfs_plls - To resume the PPLL
+ */
 void enable_nodvfs_plls(void)
 {
 	_pll_resume(PPLL_ID);
@@ -410,4 +506,5 @@
 	soc_global_soft_reset_init();
 	plat_rockchip_gpio_init();
 	soc_m0_init();
+	dram_init();
 }
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
index 9693f57..16897cc 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -245,6 +245,8 @@
 #define SGRF_PMU_SLV_CON1_CFG		(SGRF_SLV_S_WMSK | \
 					SGRF_PMUSRAM_S)
 /* ddr region */
+#define SGRF_DDR_RGN_DPLL_CLK	BIT_WITH_WMSK(15) /* DDR PLL output clock */
+#define SGRF_DDR_RGN_RTC_CLK	BIT_WITH_WMSK(14) /* 32K clock for DDR PLL */
 #define SGRF_DDR_RGN_BYPS	BIT_WITH_WMSK(9) /* All of ddr rgn  is ns */
 
 /* The MST access the ddr rgn n with secure attribution */
@@ -334,7 +336,11 @@
 void plls_resume_finish(void);
 void enable_dvfs_plls(void);
 void enable_nodvfs_plls(void);
+void prepare_abpll_for_ddrctrl(void);
+void restore_abpll(void);
+void restore_dpll(void);
 void clk_gate_con_save(void);
 void clk_gate_con_disable(void);
 void clk_gate_con_restore(void);
+void sgrf_init(void);
 #endif /* __SOC_H__ */
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
index a20ee2d..dfda6da 100644
--- a/plat/rockchip/rk3399/plat_sip_calls.c
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -29,7 +29,7 @@
 #include <plat_sip_calls.h>
 #include <rockchip_sip_svc.h>
 #include <runtime_svc.h>
-#include <dram.h>
+#include <dfs.h>
 
 #define RK_SIP_DDR_CFG		0x82000008
 #define DRAM_INIT		0x00
@@ -45,7 +45,7 @@
 {
 	switch (id) {
 	case DRAM_INIT:
-		ddr_init();
+		ddr_dfs_init();
 		break;
 	case DRAM_SET_RATE:
 		return ddr_set_rate((uint32_t)arg0);
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 059ee7b..3628dc3 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -79,6 +79,8 @@
                                 ${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c             \
 				${RK_PLAT_SOC}/drivers/pwm/pwm.c	\
                                 ${RK_PLAT_SOC}/drivers/soc/soc.c		\
+				${RK_PLAT_SOC}/drivers/dram/dfs.c		\
+                                ${RK_PLAT_SOC}/drivers/dram/suspend.c           \
 				${RK_PLAT_SOC}/drivers/dram/dram.c		\
 				${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c
 
diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c
index 97a9fbd..010bb8f 100644
--- a/services/std_svc/std_svc_setup.c
+++ b/services/std_svc/std_svc_setup.c
@@ -81,9 +81,14 @@
 		uint64_t ret;
 
 #if ENABLE_RUNTIME_INSTRUMENTATION
+
+		/*
+		 * Flush cache line so that even if CPU power down happens
+		 * the timestamp update is reflected in memory.
+		 */
 		PMF_WRITE_TIMESTAMP(rt_instr_svc,
 		    RT_INSTR_ENTER_PSCI,
-		    PMF_NO_CACHE_MAINT,
+		    PMF_CACHE_MAINT,
 		    get_cpu_data(cpu_data_pmf_ts[CPU_DATA_PMF_TS0_IDX]));
 #endif