[coreboot-gerrit] Change in coreboot[master]: mediatek/mt8183: Add MediaTek DDR driver

Tristan Hsieh (Code Review) gerrit at coreboot.org
Mon Sep 3 05:51:07 CEST 2018


Tristan Hsieh has uploaded this change for review. ( https://review.coreboot.org/28437


Change subject: mediatek/mt8183: Add MediaTek DDR driver
......................................................................

mediatek/mt8183: Add MediaTek DDR driver

Add DDR driver to initialize memory.

BUG=b:80501386
BRANCH=none
TEST=Boots correctly on Kukui, and inits DRAM successfully with related
     patches.

Change-Id: Iaaa1db170c168a58b020095ae45d98355d8dfcb0
Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
---
M src/soc/mediatek/mt8183/Kconfig
M src/soc/mediatek/mt8183/Makefile.inc
A src/soc/mediatek/mt8183/dramc_pi_basic_api.c
A src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
M src/soc/mediatek/mt8183/emi.c
M src/soc/mediatek/mt8183/include/soc/addressmap.h
A src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h
A src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
A src/soc/mediatek/mt8183/include/soc/dramc_register.h
M src/soc/mediatek/mt8183/include/soc/emi.h
M src/soc/mediatek/mt8183/include/soc/memlayout.ld
A src/soc/mediatek/mt8183/memory.c
M src/soc/mediatek/mt8183/pll.c
13 files changed, 6,648 insertions(+), 5 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/37/28437/1

diff --git a/src/soc/mediatek/mt8183/Kconfig b/src/soc/mediatek/mt8183/Kconfig
index b58be7f..1c78b18 100644
--- a/src/soc/mediatek/mt8183/Kconfig
+++ b/src/soc/mediatek/mt8183/Kconfig
@@ -19,4 +19,14 @@
 	select VBOOT_STARTS_IN_BOOTBLOCK
 	select VBOOT_SEPARATE_VERSTAGE
 
+config DEBUG_DRAM
+	bool "Output verbose DRAM related debug message"
+	default n
+	help
+	  This option enables additional DRAM related debug messages.
+
+config MEMORY_TEST
+	bool
+	default y
+
 endif
diff --git a/src/soc/mediatek/mt8183/Makefile.inc b/src/soc/mediatek/mt8183/Makefile.inc
index 8fece79..2c128f9 100644
--- a/src/soc/mediatek/mt8183/Makefile.inc
+++ b/src/soc/mediatek/mt8183/Makefile.inc
@@ -21,6 +21,10 @@
 verstage-y += ../common/wdt.c
 
 romstage-y += ../common/cbmem.c emi.c
+romstage-y += dramc_pi_basic_api.c
+romstage-y += dramc_pi_calibration_api.c
+romstage-y += memory.c
+romstage-$(CONFIG_MEMORY_TEST) += ../common/memory_test.c
 romstage-y += ../common/gpio.c gpio.c
 romstage-y += ../common/mmu_operations.c mmu_operations.c
 romstage-$(CONFIG_SPI_FLASH) += ../common/spi.c spi.c
diff --git a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
new file mode 100644
index 0000000..6619540
--- /dev/null
+++ b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
@@ -0,0 +1,1852 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <delay.h>
+#include <soc/infracfg.h>
+#include <soc/spm.h>
+#include <soc/pll.h>
+#include <soc/dramc_register.h>
+#include <soc/dramc_pi_api.h>
+#include <soc/emi.h>
+
+void dramc_broadcast_onoff(u32 bOnOff)
+{
+	write32(&mt8183_infracfg->dramc_wbr, bOnOff);
+}
+
+u32 get_dramc_broadcast(void)
+{
+	return read32(&mt8183_infracfg->dramc_wbr);
+}
+
+static void transfer_pll_to_spm_control(void)
+{
+	u8 shu_level;
+	shu_level = read32(&ch[0].ao.shustatus);
+	shu_level = (shu_level & 0x00000006) >> 1;
+
+	/* set SPM project code and enable clock enable */
+	clrsetbits_le32(&mtk_spm->poweron_config_set,
+		(0xffff << 16) | (0x1 << 0),
+		(0xb16 << 16) | (0x1 << 0));
+
+	/* set SPM pinmux */
+	clrbits_le32(&mtk_spm->pcm_pwr_io_en, (0xff << 0) | (0xff << 16));
+	setbits_le32(&mtk_spm->dramc_dpy_clk_sw_con_sel,
+		0xffffffff << 0);
+	setbits_le32(&mtk_spm->dramc_dpy_clk_sw_con_sel2,
+		0xffffffff << 0);
+
+	setbits_le32(&mtk_spm->spm_power_on_val0,
+		(0x1 << 8) | (0xf << 12));
+	setbits_le32(&mtk_spm->spm_s1_mode_ch, (0x3 << 0));
+
+	shu_level = (shu_level == 1) ? 2 : 1;
+	clrsetbits_le32(&mtk_spm->spm_power_on_val0,
+		(0x3 << 28), (shu_level << 28));
+	clrsetbits_le32(&mtk_spm->dramc_dpy_clk_sw_con2,
+		(0x3 << 2), (shu_level << 2));
+
+	udelay(1);
+	for (u8 chn = CHANNEL_A; chn < CHANNEL_NUM; chn++) {
+		clrbits_le32(&ch[chn].phy.pll1, (0x1 << 31));
+		clrbits_le32(&ch[chn].phy.pll2, (0x1 << 31));
+	}
+}
+
+static void dramc_hw_dqs_gating_tracking(u8 chn)
+{
+	setbits_le32(&ch[chn].ao.stbcal,
+		(0x3 << 26) | (0x1 << 0));
+	clrsetbits_le32(&ch[chn].ao.stbcal1,
+		(0xffff << 16) | (0x1 << 8) | (0x1 << 6),
+		(0x1 << 16) | (0x1 << 8) | (0x0 << 6));
+
+	clrsetbits_le32(&ch[chn].phy.misc_ctrl0,
+		(0x1 << 24) | (0x1f << 11) | (0xf << 0),
+		(0x1 << 24) | (0x0 << 11) | (0x0 << 0));
+
+	clrbits_le32(&ch[chn].phy.b[0].dq[6], (0x1 << 31));
+	clrbits_le32(&ch[chn].phy.b[1].dq[6], (0x1 << 31));
+	clrbits_le32(&ch[chn].phy.ca_cmd[6], (0x1 << 31));
+}
+
+static void dramc_hw_gating_init(void)
+{
+	for (u8 chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrbits_le32(&ch[chn].ao.stbcal,
+			(0x7 << 22) | (0x3 << 14) | (0x1 << 19) | (0x1 << 21));
+		setbits_le32(&ch[chn].ao.stbcal,
+			(0x1 << 20) | (0x3 << 28));
+		setbits_le32(&ch[chn].phy.misc_ctrl1, (0x1 << 24));
+
+		dramc_hw_dqs_gating_tracking(chn);
+	}
+}
+
+static void dramc_rx_input_delay_tracking_init(u8 chn)
+{
+	/* Enable RX_FIFO macro DIV4 clock CG */
+	write32(&ch[chn].phy.misc_cg_ctrl1, 0xffffffff);
+
+	/* DVS mode to RG mode */
+	clrbits_le32(&ch[chn].phy.r[0].b[0].rxdvs[2], (0x3 << 30));
+	clrbits_le32(&ch[chn].phy.r[0].b[1].rxdvs[2], (0x3 << 30));
+	clrbits_le32(&ch[chn].phy.r[1].b[0].rxdvs[2], (0x3 << 30));
+	clrbits_le32(&ch[chn].phy.r[1].b[1].rxdvs[2], (0x3 << 30));
+
+	clrbits_le32(&ch[chn].phy.b0_rxdvs[0], (0x1 << 19));
+	clrbits_le32(&ch[chn].phy.b1_rxdvs[0], (0x1 << 19));
+	setbits_le32(&ch[chn].phy.b0_rxdvs[0], (0x1 << 9));
+	setbits_le32(&ch[chn].phy.b1_rxdvs[0], (0x1 << 9));
+
+	for (size_t b = 0; b < 2; b++) {
+		/* tracking rising and update rising/falling together */
+		clrbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[2], (0x1 << 29));
+		clrbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[2], (0x1 << 29));
+
+		/* DQS, DQ, DQM (DQ, DQM are tied together now)
+		 * -> controlled using DQM MAX_MIN */
+		clrsetbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[7],
+			(0x3f << 0) | (0x3f << 8) | (0x7f << 16) | (0x7f << 24),
+			(0x0 << 0) | (0x3f << 8) | (0x0 << 16) | (0x7f << 24));
+		clrsetbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[1],
+			(0xffff << 16) | (0xffff << 0),
+			(0x2 << 16) | (0x2 << 0));
+
+		/* DQ/DQS Rx DLY adjustment for tracking mode */
+		clrbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[2],
+			(0x3 << 26) | (0x3 << 24) | (0x3 << 18) | (0x3 << 16));
+
+		/* DQS, DQ, DQM (DQ, DQM are tied together now)
+		 * -> controlled using DQM MAX_MIN */
+		clrsetbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[7],
+			(0x3f << 0) | (0x3f << 8) | (0x7f << 16) | (0x7f << 24),
+			(0x0 << 0) | (0x3f << 8) | (0x0 << 16) | (0x7f << 24));
+		clrsetbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[1],
+			(0xffff << 16) | (0xffff << 0),
+			(0x2 << 16) | (0x2 << 0));
+
+		/* DQ/DQS Rx DLY adjustment for tracking mode */
+		clrbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[2],
+			(0x3 << 26) | (0x3 << 24));
+		clrbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[2],
+			(0x3 << 18) | (0x3 << 16));
+	}
+}
+
+static void dramc_rx_input_delay_tracking(u8 chn)
+{
+	clrbits_le32(&ch[chn].phy.ca_cmd[10],
+		(0x7 << 28) | (0x7 << 24));
+
+	/* Rx DLY tracking setting (Static) */
+	clrsetbits_le32(&ch[chn].phy.b0_rxdvs[0],
+		(0x1 << 29) | (0xf << 4) | (0x1 << 0),
+		(0x1 << 29) | (0x0 << 4) | (0x1 << 0));
+	clrsetbits_le32(&ch[chn].phy.b1_rxdvs[0],
+		(0x1 << 29) | (0xf << 4) | (0x1 << 0),
+		(0x1 << 29) | (0x0 << 4) | (0x1 << 0));
+
+	for (u8 b = 0; b < 2; b++) {
+		clrsetbits_le32(&ch[chn].phy.b[b].dq[9],
+			(0x7 << 28) | (0x7 << 24),
+			(0x1 << 28) | (0x0 << 24));
+		setbits_le32(&ch[chn].phy.b[b].dq[5], (0x1 << 31));
+	}
+
+	setbits_le32(&ch[chn].phy.b0_rxdvs[0], (0x1 << 28) | (0x1 << 31));
+	setbits_le32(&ch[chn].phy.b1_rxdvs[0], (0x1 << 28) | (0x1 << 31));
+
+	for (u8 rank = RANK_0; rank < RANK_MAX; rank++) {
+		/* Rx DLY tracking update enable (HW mode) */
+		clrsetbits_le32(&ch[chn].phy.r[rank].b[0].rxdvs[2],
+			(0x3 << 30) | (0x1 << 28) | (0x1 << 23),
+			(0x2 << 30) | (0x1 << 28) | (0x1 << 23));
+
+		clrsetbits_le32(&ch[chn].phy.r[rank].b[1].rxdvs[2],
+			(0x3 << 30) | (0x1 << 28) | (0x1 << 23),
+			(0x2 << 30) | (0x1 << 28) | (0x1 << 23));
+	}
+}
+
+static void dramc_impedance_tracking_enable(void)
+{
+	u8 chn;
+
+	setbits_le32(&ch[0].phy.misc_ctrl0, (0x1 << 10));
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		setbits_le32(&ch[chn].ao.impcal, (0x1 << 31) | (0x1 << 29) |
+			(0x1 << 26) | (0x1 << 17) | (0x7 << 11));
+		clrbits_le32(&ch[chn].ao.impcal, (0x1 << 30));
+		setbits_le32(&ch[chn].phy.misc_ctrl0, (0x1 << 18));
+		setbits_le32(&ch[chn].ao.impcal, (0x1 << 19));
+	}
+	setbits_le32(&ch[0].ao.impcal, (0x1 << 14));
+	setbits_le32(&ch[1].ao.refctrl0, (0x1 << 2));
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		setbits_le32(&ch[chn].ao.refctrl0, (0x1 << 3));
+}
+
+void dramc_runtime_config(void)
+{
+	u8 chn = 0, shu = 0, shuCnt = DRAM_DFS_SHUFFLE_MAX;
+
+	clrbits_le32(&ch[0].ao.refctrl0, (0x1 << 29));
+	clrbits_le32(&ch[1].ao.refctrl0, (0x1 << 29));
+
+	transfer_pll_to_spm_control();
+
+	setbits_le32(&mtk_spm->spm_power_on_val0, (0x3 << 25));
+
+	dramc_dbg("TX_TRACKING: OFF\n");
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		dramc_rx_input_delay_tracking_init(chn);
+		dramc_rx_input_delay_tracking(chn);
+	}
+	dramc_dbg("RX_TRACKING: ON\n");
+
+	dramc_hw_gating_init();
+	dramc_hw_gating_onoff(CHANNEL_A, GATING_ON);
+	dramc_dbg("HW_GATING: ON\n");
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrbits_le32(&ch[chn].ao.stbcal2,
+			(0x3 << 4) | (0x3 << 8) | (0x1 << 28));
+	}
+	dramc_dbg("HW_GATING DBG: OFF\n");
+
+	/* ZQCS_ENABLE_LP4 */
+	clrbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 30));
+	clrbits_le32(&ch[1].ao.spcmdctrl, (0x1 << 30));
+	dramc_dbg("ZQCS_ENABLE_LP4: OFF\n");
+
+	enable_dramc_phy_dcm(0);
+	dramc_dbg("LOWPOWER_GOLDEN_SETTINGS(DCM): OFF\n");
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		for (shu = 0; shu < shuCnt; shu++)
+			clrbits_le32(&ch[chn].ao.shu[shu].dqsg_retry,
+				(0x1 << 1) | (0x3 << 13));
+	}
+	dramc_dbg("DUMMY_READ_FOR_DQS_GATING_RETRY: OFF\n");
+
+	write32(&ch[0].phy.misc_spm_ctrl0, 0xfbffefff);
+	write32(&ch[1].phy.misc_spm_ctrl0, 0xfbffefff);
+	write32(&ch[0].phy.misc_spm_ctrl2, 0xffffffef);
+	write32(&ch[1].phy.misc_spm_ctrl2, 0x7fffffef);
+	dramc_dbg("SPM_CONTROL_AFTERK: ON\n");
+
+	dramc_impedance_tracking_enable();
+	dramc_dbg("IMPEDANCE_TRACKING: ON\n");
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrbits_le32(&ch[chn].ao.spcmdctrl, (0x3 << 28));
+		setbits_le32(&ch[chn].ao.hw_mrr_fun,
+			(0x1 << 0) | (0x1 << 11));
+		dramc_dbg("TEMP_SENSOR: ON\n");
+
+
+		clrbits_le32(&ch[0].ao.refctrl0, (0x1 << 18));
+		dramc_dbg("PER_BANK_REFRESH: OFF\n");
+
+		setbits_le32(&ch[chn].phy.dvfs_emi_clk, (0x1 << 24));
+		setbits_le32(&ch[chn].ao.dvfsdll, (0x1 << 7));
+	}
+}
+
+void cke_fix_onoff(int option, u8 chn)
+{
+	u8 on, off;
+
+	/* if CKE is dynamic, set both CKE fix On and Off as 0 */
+	if (option == CKE_DYNAMIC) {
+		/* After CKE FIX on/off,
+		 * CKE should be returned to dynamic (control by HW) */
+		on = off = 0;
+	} else {
+		/* if CKE fix on is set as 1,
+		 * CKE fix off should also be set as 0; vice versa */
+		on = option;
+		off = (1 - option);
+	}
+
+	clrsetbits_le32(&ch[chn].ao.ckectrl,
+		(0x1 << 6) | (0x1 << 7), (on << 6) | (off << 7));
+}
+
+static void auto_refresh_cke_off(void)
+{
+	u8 chn;
+	u32 broadcast_bak = get_dramc_broadcast();
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		setbits_le32(&ch[chn].ao.refctrl0, (0x1 << 29));
+
+	udelay(3);
+	cke_fix_onoff(CKE_FIXOFF, CHANNEL_A);
+	cke_fix_onoff(CKE_FIXOFF, CHANNEL_B);
+
+	dramc_broadcast_onoff(broadcast_bak);
+}
+
+static void dramc_set_rank_engine2(u8 chn, u8 u1RankSel)
+{
+	setbits_le32(&ch[chn].ao.dramctrl,
+		0x1 << DRAMCTRL_ADRDECEN_TARKMODE_SHIFT);
+	clrbits_le32(&ch[chn].ao.test2_4, TEST2_4_TESTAGENTRKSEL_MASK);
+	clrsetbits_le32(&ch[chn].ao.test2_4, TEST2_4_TESTAGENTRK_MASK,
+		(u1RankSel << TEST2_4_TESTAGENTRK_SHIFT));
+}
+
+static void save_restore_dummyrd(u8 chn, u8 type)
+{
+	static u32 uiReg0D0h = 0;
+
+	if (type == SAVE_VALUE)
+		uiReg0D0h = read32(&ch[chn].ao.dummy_rd);
+	else
+		write32(&ch[chn].ao.dummy_rd, uiReg0D0h);
+}
+
+void save_restore_multi_reg(u8 type, u32 **reg_addr, u32 reg_count)
+{
+	static u32 u4gpRegBackupVlaue[MAX_BACKUP_REG_CNT];
+	if (reg_count > MAX_BACKUP_REG_CNT) {
+		dramc_dbg("save restore count over %d\n", MAX_BACKUP_REG_CNT);
+		return;
+	}
+
+	if (type == SAVE_VALUE) {
+		for (int i = 0; i < reg_count; i++)
+			u4gpRegBackupVlaue[i] = read32(reg_addr[i]);
+	} else {
+		for (int i = 0; i < reg_count; i++)
+			write32(reg_addr[i], u4gpRegBackupVlaue[i]);
+	}
+}
+
+void dramc_engine2_init(u8 chn, u8 u1RankSel, u32 test2_1, u32 test2_2,
+	u8 testaudpat, u8 log2loopcount)
+{
+	dramc_set_rank_engine2(chn, u1RankSel);
+
+	save_restore_dummyrd(chn, SAVE_VALUE);
+	clrbits_le32(&ch[chn].ao.dummy_rd,
+		 (0x1 << DUMMY_RD_DQSG_DMYRD_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_DQSG_DMYWR_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_DUMMY_RD_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_SREF_DMYRD_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_DMY_RD_DBG_SHIFT) |
+		 (0x1 << DUMMY_RD_DMY_WR_DBG_SHIFT));
+	clrbits_le32(&ch[chn].nao.testchip_dma1,
+		0x1 << TESTCHIP_DMA1_DMA_LP4MATAB_OPT_SHIFT);
+
+	clrbits_le32(&ch[chn].ao.test2_3,
+		 (0x1 << TEST2_3_TEST2W_SHIFT) |
+		 (0x1 << TEST2_3_TEST2R_SHIFT) |
+		 (0x1 << TEST2_3_TEST1_SHIFT));
+	clrsetbits_le32(&ch[chn].ao.test2_0,
+		TEST2_0_PAT0_MASK | TEST2_0_PAT1_MASK,
+		(((test2_1 >> 24) & 0xff) << TEST2_0_PAT0_SHIFT) |
+		(((test2_2 >> 24) & 0xff) << TEST2_0_PAT1_SHIFT));
+
+	write32(&ch[chn].ao.test2_1, (test2_1 << 4) & 0x00ffffff);
+	write32(&ch[chn].ao.test2_2, (test2_2 << 4) & 0x00ffffff);
+
+	if (testaudpat == TEST_XTALK_PATTERN) {
+		clrsetbits_le32(&ch[chn].ao.test2_4,
+			0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT |
+			(0x1 << TEST2_4_TESTAUDMODE_SHIFT) |
+			(0x1 << TEST2_4_TESTAUDBITINV_SHIFT) |
+			(0x1 << TEST2_4_TESTSSOPAT_SHIFT) |
+			(0x1 << TEST2_4_TESTSSOXTALKPAT_SHIFT),
+			0x1 << TEST2_4_TESTXTALKPAT_SHIFT);
+		setbits_le32(&ch[chn].ao.perfctl0,
+			0x1 << PERFCTL0_RWOFOEN_SHIFT);
+		clrsetbits_le32(&ch[chn].ao.test2_3,
+			(0x1 << TEST2_3_TESTAUDPAT_SHIFT) |
+			TEST2_3_TESTCNT_MASK,
+			log2loopcount << TEST2_3_TESTCNT_SHIFT);
+	} else if (testaudpat == TEST_AUDIO_PATTERN) {
+		clrsetbits_le32(&ch[chn].ao.test2_4,
+			TEST2_4_TESTAUDINIT_MASK |
+			TEST2_4_TESTAUDINC_MASK |
+			(0x1 << TEST2_4_TESTXTALKPAT_SHIFT),
+			(0x00000011 << TEST2_4_TESTAUDINIT_SHIFT) |
+			(0x0000000d << TEST2_4_TESTAUDINC_SHIFT) |
+			(0x1 << TEST2_4_TESTAUDMODE_SHIFT) |
+			(0x1 << TEST2_4_TESTAUDBITINV_SHIFT));
+		clrsetbits_le32(&ch[chn].ao.test2_3, TEST2_3_TESTCNT_MASK,
+			(0x1 << TEST2_3_TESTAUDPAT_SHIFT) |
+			(log2loopcount << TEST2_3_TESTCNT_SHIFT));
+	} else {
+		clrsetbits_le32(&ch[chn].ao.test2_3,
+			(0x1 << TEST2_3_TESTAUDPAT_SHIFT) |
+			TEST2_3_TESTCNT_MASK,
+			(log2loopcount << TEST2_3_TESTCNT_SHIFT));
+		clrbits_le32(&ch[chn].ao.test2_4,
+			(0x1 << TEST2_4_TESTXTALKPAT_SHIFT));
+	}
+}
+
+static void dramc_engine2_check_complete(u8 chn)
+{
+	u32 u4loop_count = 0;
+	while ((read32(&ch[chn].nao.testrpt) &
+			(0x1 << TESTRPT_DM_CMP_CPT_RK0_SHIFT)) == 0) {
+		udelay(1);
+		u4loop_count++;
+
+		if (u4loop_count > MAX_CMP_CPT_WAIT_LOOP) {
+			dramc_dbg("MEASURE_A timeout\n");
+			break;
+		}
+	}
+
+}
+
+u32 dramc_engine2_run(u8 chn, enum dram_te_op wr, u8 testaudpat)
+{
+	u32 u4result = 0xffffffff;
+
+	if (wr == TE_OP_READ_CHECK) {
+		if ((testaudpat == TEST_AUDIO_PATTERN) ||
+			(testaudpat == TEST_XTALK_PATTERN))
+			clrbits_le32(&ch[chn].ao.test2_4,
+				(0x1 << TEST2_4_TESTAUDMODE_SHIFT));
+	} else if (wr == TE_OP_WRITE_READ_CHECK) {
+		clrsetbits_le32(&ch[chn].ao.test2_3,
+			(0x1 << TEST2_3_TEST2R_SHIFT) |
+			(0x1 << TEST2_3_TEST1_SHIFT),
+			(0x1 << TEST2_3_TEST2W_SHIFT));
+
+		dramc_engine2_check_complete(chn);
+		clrbits_le32(&ch[chn].ao.test2_3,
+			 (0x1 << TEST2_3_TEST2W_SHIFT) |
+			 (0x1 << TEST2_3_TEST2R_SHIFT) |
+			 (0x1 << TEST2_3_TEST1_SHIFT));
+		udelay(1);
+	}
+
+	/* do Read test */
+	clrsetbits_le32(&ch[chn].ao.test2_3,
+		(0x1 << TEST2_3_TEST2W_SHIFT) |
+		(0x1 << TEST2_3_TEST1_SHIFT),
+		(0x1 << TEST2_3_TEST2R_SHIFT));
+
+	dramc_engine2_check_complete(chn);
+
+	udelay(1);
+	u4result = read32(&ch[chn].nao.cmp_err);
+	clrbits_le32(&ch[chn].ao.test2_3,
+		 (0x1 << TEST2_3_TEST2W_SHIFT) |
+		 (0x1 << TEST2_3_TEST2R_SHIFT) |
+		 (0x1 << TEST2_3_TEST1_SHIFT));
+
+	return u4result;
+}
+
+void dramc_engine2_end(u8 chn)
+{
+	clrbits_le32(&ch[chn].ao.test2_4, (0x1 << 17));
+
+	save_restore_dummyrd(chn, RESTORE_VALUE);
+}
+
+static void ddr_phy_pll_setting(u8 chn)
+{
+	u8 u1CAP_SEL;
+	u8 u1MID_FINE_TUNE_SEL;
+	u8 u1VTH_SEL;
+
+	u1VTH_SEL = 0x2;
+	u1CAP_SEL = 0x0;
+	u1MID_FINE_TUNE_SEL = 0x2;
+
+	clrbits_le32(&ch[chn].phy.shu[0].pll[4], 0xFFFF);
+	clrbits_le32(&ch[chn].phy.shu[0].pll[6], 0xFFFF);
+
+	if (chn == 0)
+		setbits_le32(&ch[chn].phy.misc_shu_opt, 0x1 << 18);
+	else if (chn == 1)
+		setbits_le32(&ch[chn].phy.misc_shu_opt, 0x2 << 18);
+
+	clrsetbits_le32(&ch[chn].phy.ckmux_sel,
+		0x3 << 18 | 0x3 << 16, 0x0);
+	clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[0],
+		0x3 << 18, 0x1 << 18);
+
+	clrsetbits_le32(&ch[chn].ao.dvfsdll, 0x1 << 1, 0x0 << 1);
+
+	if (chn == DLL_MASTER_CH) {
+		clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[0],
+			0x1 << 31 | 0x1 << 30 | 0xf << 20 | 0xf << 16 |
+			0xf << 12 | 0x1 << 10 | 0x1 << 9 | 0x1 << 4,
+			0x0 << 31 | 0x0 << 30 | 0x6 << 20 | 0x9 << 16 |
+			0x8 << 12 | 0x1 << 10 | 0x1 << 9 | 0x1 << 4);
+		clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[1],
+			0x1 << 2 | 0x1 << 0, 0x1 << 2 | 0x0 << 0);
+		clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6],
+			0x1 << 7, 0x1 << 7);
+	} else {
+		clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[0],
+			0x1 << 31 | 0x1 << 30 | 0xf << 20 | 0xf << 16 |
+			0xf << 12 | 0x1 << 10 | 0x1 << 9 | 0x1 << 4,
+			0x1 << 31 | 0x1 << 30 | 0x7 << 20 | 0x7 << 16 |
+			0x8 << 12 | 0x1 << 10 | 0x1 << 9 | 0x0 << 4);
+		clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[1],
+			0x1 << 2 | 0x1 << 0, 0x0 << 2 | 0x1 << 0);
+		clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6],
+			0x1 << 7, 0x0 << 7);
+	}
+
+	u32 *u4RegBackup[] = {
+		&ch[chn].phy.b[0].dq[7],
+		&ch[chn].phy.b[1].dq[7],
+		&ch[chn].phy.ca_cmd[7],
+	};
+
+	save_restore_multi_reg(SAVE_VALUE,
+		u4RegBackup, ARRAY_SIZE(u4RegBackup));
+
+	for (size_t b = 0; b < 2; b++) {
+		setbits_le32(&ch[chn].phy.b[b].dq[7],
+			0x1 << 6 | 0x1 << 4 | 0x1 << 2 | 0x1 << 0);
+	}
+	setbits_le32(&ch[chn].phy.ca_cmd[7],
+		0x1 << 6 | 0x1 << 4 | 0x1 << 2 | 0x1 << 0);
+	setbits_le32(&ch[chn].phy.ca_cmd[2], 0x1 << 21);
+
+	/* 26M */
+	clrsetbits_le32(&ch[chn].phy.misc_cg_ctrl0, (0x3<<4), 0x0 << 4);
+
+	/* MID FINE_TUNE */
+	clrbits_le32(&ch[chn].phy.shu[0].b[0].dq[6], (0x1<<26)|(0x1<<27));
+	clrbits_le32(&ch[chn].phy.shu[0].b[1].dq[6], (0x1<<26)|(0x1<<27));
+	clrbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], (0x1<<26)|(0x1<<27));
+	clrbits_le32(&ch[chn].phy.pll4, (0x1<<16)|(0x1<<22));
+
+	/* PLL */
+	clrbits_le32(&ch[chn].phy.pll1, (0x1<<31));
+	clrbits_le32(&ch[chn].phy.pll2, (0x1<<31));
+
+	/* DLL */
+	clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[2],  (0x0<<0));
+	clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], (0x0<<0));
+	clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], (0x0<<0));
+	setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2],
+		(0x1<<10) | (0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) |
+		(0x1<<17) | (0x1<<19) | (0x1<<27) | (0x1<<31));
+	setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2],
+		(0x1<<10) | (0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) |
+		(0x1<<17) | (0x1<<19) | (0x1<<27) | (0x1<<31));
+	setbits_le32(&ch[chn].phy.ca_dll_fine_tune[2],
+		(0x1<<10) | (0x1<<11) | (0x1<<13) | (0x1<<15) | (0x1<<16) |
+		(0x1<<17) | (0x1<<19) | (0x1<<27) | (0x1<<31));
+
+	/* RESETB */
+	clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[0], (0x1<<3));
+	clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[0], (0x1<<3));
+	clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[0], (0x1<<3));
+
+	udelay(1);
+
+	/* MPLL 52M */
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll[8],
+		(0x7<<0)|(0x3<<18), (0x0<<0)|(0x1<<18));
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll[10],
+		(0x7<<0)|(0x3<<18), (0x0<<0)|(0x1<<18));
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll[5],
+		(0xffff<<16) | 0x1 << 0, (0x7b00<<16));
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll[7],
+		(0xffff<<16) | 0x1 << 0, (0x7b00<<16));
+
+	setbits_le32(&ch[chn].phy.ca_dll_fine_tune[0], (0x1<<1));
+	setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[0], (0x1<<1));
+	setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[0], (0x1<<1));
+
+	clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[1], (0x1<<11));
+	clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[1], (0x1<<19));
+	clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[1], (0x1<<19));
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[6],
+		(0x3<<22) | (0x3<<24) | (0x3<<28),
+		(u1MID_FINE_TUNE_SEL<<22) | (u1VTH_SEL<<24) | (u1CAP_SEL<<28));
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[6],
+		(0x3<<22) | (0x3<<24) | (0x3<<28),
+		(u1MID_FINE_TUNE_SEL<<22)|(u1VTH_SEL<<24) | (u1CAP_SEL<<28));
+	clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6],
+		(0x3<<22) | (0x3<<24) | (0x3<<28),
+		(u1MID_FINE_TUNE_SEL<<22) | (u1VTH_SEL<<24) | (u1CAP_SEL<<28));
+
+	/* RESETB */
+	setbits_le32(&ch[chn].phy.ca_dll_fine_tune[0], (0x1<<3));
+	setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[0], (0x1<<3));
+	setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[0], (0x1<<3));
+	udelay(1);
+
+	/* PLL EN */
+	setbits_le32(&ch[chn].phy.pll1, (0x1<<31));
+	setbits_le32(&ch[chn].phy.pll2, (0x1<<31));
+	udelay(100);
+
+	/* MID FINE_TUNE Init 1 */
+	setbits_le32(&ch[chn].phy.pll4, (0x1<<16)|(0x1<<22));
+	udelay(1);
+
+	/* MID FINE_TUNE Init 2 */
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[6],
+		(0x1<<26) | (0x1<<27), (0x1<<26) | (0x0<<27));
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[6],
+		(0x1<<26) | (0x1<<27), (0x1<<26) | (0x0<<27));
+	clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6],
+		(0x1<<26) | (0x1<<27), (0x1<<26) | (0x0<<27));
+	udelay(1);
+	if (chn == 0)
+		clrsetbits_le32(&ch[chn].phy.ca_dll_fine_tune[3],
+			(0x1<<13) | (0x1<<15) | (0x1<<16) |
+			(0x1<<17) | (0x1<<19),
+			(0x1<<13) | (0x1<<15) | (0x1<<16) |
+			(0x1<<17) | (0x1<<19));
+	else if (chn == 1)
+		clrsetbits_le32(&ch[chn].phy.ca_dll_fine_tune[3],
+			(0x1<<13) | (0x1<<15) | (0x1<<16) |
+			(0x1<<17) | (0x1<<19),
+			(0x1<<13) | (0x1<<15) | (0x1<<16) | (0x1<<17));
+
+	setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[3],
+		(0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) | (0x1<<17));
+	setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[3],
+		(0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) | (0x1<<17));
+
+	clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[2],
+		 (0x1 << 10) | (0x1 << 13) |
+		 (0x1 << 15) | (0x1 << 16) | (0x1 << 17) |
+		 (0x1 << 19) | (0x1 << 27) | (0x1 << 31));
+
+	clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2],
+		 (0x1 << 10) | (0x1 << 13) | (0x1 << 14) |
+		 (0x1 << 15)  | (0x1 << 17) |
+		 (0x1 << 19) | (0x1 << 27) | (0x1 << 31));
+	clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2],
+		 (0x1 << 10) | (0x1 << 13) |
+		 (0x1 << 14) | (0x1 << 15) | (0x1 << 17) |
+		 (0x1 << 19) | (0x1 << 27) | (0x1 << 31));
+
+	setbits_le32(&ch[chn].phy.ca_dll_fine_tune[2], (0x1 << 11));
+	clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], (0x1 << 11));
+	clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], (0x1 << 11));
+	udelay(2);
+
+	setbits_le32(&ch[chn].phy.misc_cg_ctrl0, (0x1 << 4));
+	udelay(1);
+
+	/* DLL */
+	setbits_le32(&ch[chn].phy.ca_dll_fine_tune[2], (0x1 << 0));
+	udelay(1);
+	setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], (0x1 << 0));
+	udelay(1);
+	setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], (0x1 << 0));
+	udelay(1);
+
+	clrbits_le32(&ch[chn].phy.ca_cmd[2], 0x1 << 21);
+
+	save_restore_multi_reg(RESTORE_VALUE,
+		u4RegBackup, ARRAY_SIZE(u4RegBackup));
+
+	cke_fix_onoff(CKE_DYNAMIC, CHANNEL_A);
+	cke_fix_onoff(CKE_DYNAMIC, CHANNEL_B);
+
+	setbits_le32(&ch[chn].phy.shu[0].pll[5], (0x1<<0));
+	setbits_le32(&ch[chn].phy.shu[0].pll[7], (0x1<<0));
+	setbits_le32(&ch[chn].phy.shu[0].pll[14], (0x1<<1));
+	setbits_le32(&ch[chn].phy.shu[0].pll20, (0x1<<1));
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll[14],
+		(0xffff<<16), 0x0208 << 16);
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll20,
+		(0xffff<<16), 0x0208 << 16);
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll[15],
+		(0xffffffff<<0), 0xC03 << 16);
+	clrsetbits_le32(&ch[chn].phy.shu[0].pll21,
+		(0xffffffff<<0), 0xC03 << 16);
+}
+
+static void update_initial_settings(void)
+{
+	u16 u2RXVrefDefault = 0x8;
+	u8 chn = 0;
+
+	setbits_le32(&ch[0].ao.shu[0].odtctrl, (0x1 << 0));
+	setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 15));
+	setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 15));
+
+	for (size_t b = 0; b < 2; b++)
+		for (size_t r = 0; r < 2; r++)
+			clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2],
+				 (0x1 << 23) | (0x1 << 28) | (0x3 << 30));
+	clrbits_le32(&ch[0].phy.shu[0].ca_cmd[7], (0xf << 0));
+
+	setbits_le32(&ch[0].phy.ca_cmd[3], (0x1 << 10));
+	setbits_le32(&ch[0].phy.ca_cmd[10], (0x1 << 5));
+	clrsetbits_le32(&ch[0].phy.ca_cmd[6], 0x3 << 14, 0x1 << 14);
+	setbits_le32(&ch[0].phy.b[0].dq[3],
+			(0x1 << 5) | (0x1 << 6) | (0x1 << 7));
+	setbits_le32(&ch[0].phy.b[1].dq[3],
+			(0x1 << 5) | (0x1 << 6) | (0x1 << 7));
+	setbits_le32(&ch[0].phy.ca_cmd[3], (0x1 << 5) | (0x1 << 7));
+	clrbits_le32(&ch[0].phy.b[0].dq[3], (0x1 << 1));
+	clrbits_le32(&ch[0].phy.b[1].dq[3], (0x1 << 1));
+	setbits_le32(&ch[0].phy.b[0].dq[5], (0x1 << 31));
+	setbits_le32(&ch[0].phy.b[1].dq[5], (0x1 << 31));
+	setbits_le32(&ch[0].phy.ca_cmd[5], (0x1 << 31));
+
+	clrsetbits_le32(&ch[0].phy.ca_cmd[6], 0xf << 16, 0x3 << 16);
+	clrsetbits_le32(&ch[0].phy.misc_imp_ctrl0,
+		(0x1 << 5) | (0x1 << 6),
+		(0x1 << 5) | (0x0 << 6));
+	setbits_le32(&ch[0].phy.b[0].dq[6], (0x1 << 9));
+	setbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 9));
+	setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 9));
+	clrsetbits_le32(&ch[0].phy.b[0].dq[6], (0x3 << 0), (0x1 << 0));
+	clrsetbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 0), (0x1 << 0));
+	clrsetbits_le32(&ch[0].phy.ca_cmd[6], (0x3 << 0), (0x1 << 0));
+
+	setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 6));
+	setbits_le32(&ch[0].phy.b[0].dq[6], (0x1 << 3));
+	setbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 3));
+	setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 3));
+	setbits_le32(&ch[0].phy.b[0].dq[6], (0x1 << 5));
+	setbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 5));
+	setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 5));
+
+	u2RXVrefDefault = 0xE;
+	for (u8 b = 0; b < 2; b++) {
+		clrsetbits_le32(&ch[0].phy.shu[0].b[b].dq[5],
+			(0x3f << 0), (u2RXVrefDefault << 0));
+		clrsetbits_le32(&ch[0].phy.b[b].dq[5],
+			(0x3f << 8), (u2RXVrefDefault << 8));
+	}
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		setbits_le32(&ch[chn].phy.b[0].dq[8],
+			(0x1 << 0) | (0x1 << 1) | (0x1 << 2));
+		setbits_le32(&ch[chn].phy.b[1].dq[8],
+			(0x1 << 0) | (0x1 << 1) | (0x1 << 2));
+		setbits_le32(&ch[chn].phy.ca_cmd[9],
+			(0x1 << 0) | (0x1 << 1) | (0x1 << 2));
+
+		dramc_gating_mode(chn, 1);
+	}
+
+	setbits_le32(&ch[0].phy.ca_cmd[8], (0x1 << 19));
+	clrbits_le32(&ch[0].phy.ca_cmd[8], (0x1 << 18));
+	clrsetbits_le32(&ch[0].ao.shu[0].misc, (0xf << 0), (0x2 << 0));
+	clrsetbits_le32(&ch[0].ao.shu[0].dqsg, (0x3f << 20) | (0x1 << 16),
+		(0x2a << 20) | (0x1 << 16));
+
+	clrbits_le32(&ch[0].phy.shu[0].b[0].dq[5], (0x3f << 8));
+	clrbits_le32(&ch[0].phy.shu[0].b[1].dq[5], (0x3f << 8));
+	clrbits_le32(&ch[0].phy.shu[0].ca_cmd[5], (0x3f << 8));
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrbits_le32(&ch[chn].phy.shu[0].b[0].dq[6], (0x3f << 0));
+		clrbits_le32(&ch[chn].phy.shu[0].b[1].dq[6], (0x3f << 0));
+		clrbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], (0x3f << 0));
+	}
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	/* IMP Tracking Init Settings */
+	clrsetbits_le32(&ch[0].ao.shu[0].impcal1,
+		(0x7 << 0) | (0x7 << 17) | (0xff << 20) | (0xf << 28),
+		(0x4 << 0) | (0x4 << 17) | (0x10 << 20) | (0x8 << 28));
+
+	setbits_le32(&ch[0].ao.srefctrl, (0xf << 12));
+	setbits_le32(&ch[0].ao.pre_tdqsck[0], (0x1 << 17));
+
+	setbits_le32(&ch[0].ao.shu[0].misc, (0xf << 12));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[8],
+		(0xffff << 0) | (0x1 << 15) | (0x3ff << 22),
+		(0x7fff << 0) | (0x0 << 15) | (0x3ff << 22));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[8],
+		(0xffff << 0) | (0x1 << 15) | (0x3ff << 22),
+		(0x7fff << 0) | (0x0 << 15) | (0x3ff << 22));
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[8],
+		(0xffff << 0) | (0x1 << 15) | (0x3ff << 22),
+		(0x7fff << 0) | (0x0 << 15) | (0x3ff << 22));
+	setbits_le32(&ch[0].phy.misc_ctrl3, (0x1 << 26));
+	clrbits_le32(&ch[0].phy.shu[0].b[0].dq[7],
+		(0xf << 8) | (0x1 << 12) | (0x1 << 13));
+	clrbits_le32(&ch[0].phy.shu[0].b[1].dq[7],
+		(0xf << 8) | (0x1 << 12) | (0x1 << 13));
+	clrsetbits_le32(&ch[0].ao.clkar,
+		(0xffff << 0) | (0x1 << 15),
+		(0x7fff << 0) | (0x1 << 15));
+
+	clrbits_le32(&ch[0].ao.shu[0].dqsg_retry, (0x1 << 29));
+	clrbits_le32(&ch[0].ao.write_lev, (0x1 << 2));
+	setbits_le32(&ch[0].ao.dummy_rd, (0x1 << 24));
+	clrbits_le32(&ch[0].ao.stbcal2, (0x1 << 0) | (0x1 << 1));
+	setbits_le32(&ch[0].ao.eyescan,
+		(0x1 << 8) | (0x1 << 9) | (0x1 << 10));
+	setbits_le32(&ch[0].ao.shu[0].odtctrl, (0x1 << 2) | (0x1 << 3));
+
+	setbits_le32(&ch[0].phy.shu[0].b[0].dll[0], (0x1 << 0));
+	setbits_le32(&ch[0].phy.shu[0].b[1].dll[0], (0x1 << 0));
+	setbits_le32(&ch[0].phy.ca_dll_fine_tune[1], (0x1 << 21));
+
+	setbits_le32(&ch[0].ao.perfctl0,
+		(0x1 << 15) | (0x1 << 19) | (0x1 << 26));
+	setbits_le32(&ch[0].ao.srefctrl, (0x1 << 22));
+	clrsetbits_le32(&ch[0].ao.shuctrl1, (0xff << 0), (0x1a << 0));
+	setbits_le32(&ch[0].phy.b[0].dq[6],
+		(0x1 << 7) | (0x1 << 12));
+	setbits_le32(&ch[0].phy.b[1].dq[6],
+		(0x1 << 7) | (0x1 << 12));
+	setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 7) | (0x1 << 12));
+	setbits_le32(&ch[0].ao.stbcal2, (0x1 << 16));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[7],
+		(0x7 << 29) | (0x1 << 28) | (0x7 << 25) | (0x1 << 24),
+		(0x0 << 29) | (0x1 << 28) | (0x1 << 25) | (0x1 << 24));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[7],
+		(0x7 << 29) | (0x1 << 28) | (0x7 << 25) | (0x1 << 24),
+		(0x0 << 29) | (0x1 << 28) | (0x1 << 25) | (0x1 << 24));
+
+	/* Disable RODT tracking */
+	clrbits_le32(&ch[0].ao.shu[0].rodtenstb, (0x1 << 0));
+
+	/* Rx Gating tracking settings */
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrsetbits_le32(&ch[chn].ao.shu[0].dqsg,
+			(0x1 << 11) | (0xf << 12),
+			(0x1 << 11) | (0x9 << 12));
+		clrsetbits_le32(&ch[chn].ao.shu[0].rk[0].dqscal,
+			(0x1 << 7) | (0x1 << 15),
+			(0x0 << 7) | (0x0 << 15));
+		clrsetbits_le32(&ch[chn].ao.shu[0].rk[1].dqscal,
+			(0x1 << 7) | (0x1 << 15),
+			(0x0 << 7) | (0x0 << 15));
+		clrsetbits_le32(&ch[chn].ao.shu[0].stbcal,
+			(0x7 << 4) | (0x1 << 8),
+			(0x1 << 4) | (0x1 << 8));
+	}
+
+	clrsetbits_le32(&ch[0].phy.b[0].dq[9],
+		(0xff << 8), (0x4 << 8));
+	clrsetbits_le32(&ch[0].phy.b[1].dq[9],
+		(0xff << 8), (0x4 << 8));
+	clrbits_le32(&ch[0].phy.ca_cmd[10], (0xff << 8));
+
+	setbits_le32(&ch[0].phy.shu[0].b[0].dq[8], (0x1 << 24));
+	setbits_le32(&ch[0].phy.shu[0].b[1].dq[8], (0x1 << 24));
+
+	/* Enable WDQS */
+	clrsetbits_le32(&ch[0].phy.shu[0].b[0].dll[1],
+		(0x1 << 16) | (0x1 << 17),
+		(0x0 << 16) | (0x1 << 17));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[1].dll[1],
+		(0x1 << 16) | (0x1 << 17),
+		(0x0 << 16) | (0x1 << 17));
+	setbits_le32(&ch[0].ao.shu[0].odtctrl,
+		(0x1 << 0) | (0x1 << 30) | (0x1 << 31));
+	setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 15));
+	setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 15));
+
+	setbits_le32(&ch[0].ao.drsctrl, (0x1 << 19));
+	setbits_le32(&ch[0].ao.refctrl0, (0x1 << 28));
+	setbits_le32(&ch[0].ao.zqcs, (0x1 << 19));
+	setbits_le32(&ch[0].ao.dummy_rd, (0x3 << 26));
+	setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 8));
+	clrsetbits_le32(&ch[0].ao.shuctrl3,
+		(0xff << 24), (0xb << 24));
+	setbits_le32(&ch[0].phy.misc_ctrl3, (0x1 << 27));
+
+	setbits_le32(&ch[0].phy.b[0].dll_fine_tune[1], (0x3 << 20));
+	setbits_le32(&ch[0].phy.b[1].dll_fine_tune[1], (0x3 << 20));
+	setbits_le32(&ch[0].phy.ca_dll_fine_tune[1], (0x1 << 20));
+	clrbits_le32(&ch[0].phy.misc_ctrl0, (0x1 << 27));
+	setbits_le32(&ch[0].phy.misc_rxdvs[2], (0x1 << 8));
+	setbits_le32(&ch[0].ao.clkctrl, (0x1 << 7));
+	setbits_le32(&ch[0].ao.refctrl1, (0x1 << 7));
+	clrsetbits_le32(&ch[0].ao.shuctrl,
+		(0x1 << 2) | (0x3 << 6) | (0x3 << 26),
+		(0x0 << 2) | (0x3 << 6) | (0x3 << 26));
+	setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 31) | (0x3 << 10));
+	clrbits_le32(&ch[0].ao.stbcal2, (0xf << 4));
+	clrbits_le32(&ch[0].ao.pre_tdqsck[0], (0x3 << 19));
+
+	setbits_le32(&ch[0].ao.ckectrl, (0x1 << 22));
+	clrsetbits_le32(&ch[0].phy.ca_tx_mck,
+		(0x1 << 31) | (0x1f << 21) | (0x1f << 26),
+		(0x1 << 31) | (0xa << 21) | (0xa << 26));
+
+	/* MP setting should set CKECTRL_CKELCKFIX as 1 */
+	setbits_le32(&ch[0].ao.ckectrl, (0x1 << 23));
+
+	/* Gating error problem happened in M17
+	 * has been solved by setting this RG as 0 */
+	clrbits_le32(&ch[0].ao.shu[0].rodtenstb, (0x1 << 31));
+}
+
+static void dramc_power_on_sequence(void)
+{
+	u8 chn;
+
+	/* reset dram = low */
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		clrbits_le32(&ch[chn].phy.misc_ctrl1, (0x1 << 13));
+
+	/* CKE low */
+	cke_fix_onoff(CKE_FIXOFF, CHANNEL_A);
+	cke_fix_onoff(CKE_FIXOFF, CHANNEL_B);
+
+	/* delay tINIT1=200us(min) & tINIT2=10ns(min)*/
+	udelay(200);
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		setbits_le32(&ch[chn].phy.misc_ctrl1, (0x1 << 13));
+
+	/* Disable HW MIOCK control to make CLK always on */
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		setbits_le32(&ch[chn].ao.dramc_pd_ctrl, (0x1 << 26));
+
+	udelay(2000);
+
+	/* CKE high */
+	cke_fix_onoff(CKE_FIXON, CHANNEL_A);
+	cke_fix_onoff(CKE_FIXON, CHANNEL_B);
+
+	udelay(2);
+	dramc_dbg("APPLY_LP4_POWER_INIT_SEQUENCE\n");
+}
+
+static void ddr_phy_reserved_rg_setting(void)
+{
+	u8 chn;
+
+	/* fine tune */
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[6],
+		(0xFFFF << 6), (0x3 << 6) | (0x4 << 8) | (0x3 << 17));
+	clrsetbits_le32(&ch[1].phy.shu[0].ca_cmd[6],
+		(0xFFFF << 6), (0x1 << 6) | (0x4 << 8) | (0x3 << 17));
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[1],
+			(0xf << 9) | (0x1f << 16) | (0x7ff << 21),
+			(0x1 << 8) | (0x7 << 13) | (0x4 << 16));
+
+		for (u8 b = 0; b < 2; b++) {
+			clrsetbits_le32(&ch[chn].phy.shu[0].b[b].dq[6],
+				(0x3f << 11) | (0x7 << 19),
+				(0x1 << 6) | (0x1 << 10) | (0x3 << 17));
+
+			/* TX */
+			clrsetbits_le32(&ch[chn].phy.shu[0].b[b].dll[1],
+				(0x3 << 8) | (0x3 << 11) |
+				(0x7 << 14) | (0x3fff << 18),
+				(0x1 << 10) | (0x1 << 13) | (0x1 << 17));
+		}
+	}
+}
+
+static void dramc_duty_set_clk_delay(u8 chn, s8 clkDelay)
+{
+	size_t rank;
+	u8 delay, delayb, revb0, revb1;
+
+	delay = (clkDelay < 0) ? -clkDelay : 0;
+	delayb = (clkDelay < 0) ? 0 : clkDelay;
+	revb0 = (delay) ? 1 : 0;
+	revb1 = (delayb) ? 1 : 0;
+
+	for (rank = 0; rank < RANK_MAX; rank++) {
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[1],
+			(0xf << 24) | (0xf << 28),
+			(delay << 24) | (delay << 28));
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[0],
+			(0xf << 24) | (0xf << 28),
+			(delayb << 24) | (delayb << 28));
+	}
+	clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[3],
+		(0x3 << 8), (revb0 << 8) | (revb1 << 9));
+}
+
+static void dramc_duty_set_dqs_delay(u8 chn, s8 dqsDelay)
+{
+	size_t rank, dqs;
+	u8 delay, delayb, revb0, revb1;
+
+	delay = (dqsDelay < 0) ? -dqsDelay : 0;
+	delayb = (dqsDelay < 0) ? 0 : dqsDelay;
+	revb0 = (delay) ? 1 : 0;
+	revb1 = (delayb) ? 1 : 0;
+
+	for (rank = 0; rank < RANK_MAX; rank++) {
+		for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+			clrsetbits_le32(
+				&ch[chn].phy.shu[0].rk[rank].b[dqs].dq[1],
+				(0xf << 24) | (0xf << 28) |
+				(0xf << 16) | (0xf << 20),
+				(delay << 24) | (delay << 28) |
+				(delayb << 16) | (delayb << 20));
+
+		}
+	}
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dll[1],
+		(0x3 << 8), (revb0 << 8) | (revb1 << 9));
+}
+
+static void dramc_duty_calibration(u8 chn, s8 clkDelay, s8 dqsDelay)
+{
+	dramc_duty_set_clk_delay(chn, clkDelay);
+	dramc_duty_set_dqs_delay(chn, dqsDelay);
+}
+
+static void dramc_mode_reg_init(void)
+{
+	u8 u1MR12Value[CHANNEL_NUM][RANK_MAX][FSP_MAX] = {
+		{{0x5d, 0x5d}, {0x5d, 0x5d} },
+		{{0x5d, 0x5d}, {0x5d, 0x5d} },
+	};
+
+	u8 u1MR14Value_06VDDQ[CHANNEL_NUM][RANK_MAX][FSP_MAX] = {
+		{{0x5d, 0x10}, {0x5d, 0x10} },
+		{{0x5d, 0x10}, {0x5d, 0x10} },
+	};
+
+	u8 chn, rank;
+	u32 broadcast_bak = get_dramc_broadcast();
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+
+	dramc_power_on_sequence();
+
+	/* Fix nWR value to 30 (MR01[6:4] = 101B) for DDR3200
+	 * Other vendors: Use default MR01 for each FSP
+	 * (Set in vInitGlobalVariablesByCondition() )
+	 */
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		u8 u1MR2Value[FSP_MAX] = { 0x0b, 0x2d};
+		u8 u1MR13Value_t = 0xc0 | (MR13_RRO << 4) | (1 << 3);
+		u8 u1MR01Value[FSP_MAX] = { 0x56, 0x56};
+		u8 u1MR11Value[FSP_MAX] = { 0x0, 0x23};
+		u8 u1MR13Value[FSP_MAX] = { 0x0 | (MR13_RRO << 4) | (1 << 3),
+					0x40 | (MR13_RRO << 4) | (1 << 3)};
+		u8 u1MR22Value[FSP_MAX] = {0x38, 0x34};
+		for (rank = 0; rank < 2; rank++) {
+			dramc_dbg("%s CH%u RK%u\n", __func__, chn, rank);
+			clrsetbits_le32(&ch[chn].ao.mrs,
+				(0x3 << 24), (rank << 24));
+
+			/* ZQ calobration should be done before CBT calibration
+			 * by switching to low frequency */
+			dramc_zq_calibration(chn, rank);
+
+			for (uint32_t fsp = FSP_0; fsp < FSP_MAX; fsp++) {
+				dramc_dbg("chn:%d,rank:%d,fsp%d\n",
+					chn, rank, fsp);
+
+				dramc_mode_reg_write(chn,
+					0xd, u1MR13Value[fsp]);
+
+				/* MR12 use previous value
+				 * MR12 VREF-CA */
+				dramc_mode_reg_write(chn,
+					0xc, u1MR12Value[chn][rank][fsp]);
+				dramc_mode_reg_write(chn,
+					0x1, u1MR01Value[fsp]);
+				dramc_mode_reg_write(chn,
+					0x2, u1MR2Value[fsp]);
+				dramc_mode_reg_write(chn,
+					0xb, u1MR11Value[fsp]); /* ODT */
+
+				/* SOC-ODT, ODTE-CK, ODTE-CS, Disable ODTD-CA */
+				dramc_mode_reg_write(chn,
+					0x16, u1MR22Value[fsp]);
+
+				/* MR14 use previous value
+				 * MR14 VREF-DQ */
+				dramc_mode_reg_write(chn, 0xe,
+					u1MR14Value_06VDDQ[chn][rank][fsp]);
+
+				/* MR3 set write-DBI and read-DBI */
+				u8 u1MR03Value = 0x30;
+				dramc_mode_reg_write(chn, 0x3, u1MR03Value);
+			}
+		}
+
+		/* FSP-1 */
+		u1MR13Value_t = 0xc0 | (MR13_RRO<<4) | (1<<3);
+		dramc_mode_reg_write_by_rank(chn, RANK_0,
+			0xd, u1MR13Value_t);
+		dramc_mode_reg_write_by_rank(chn, RANK_1,
+			0xd, u1MR13Value_t);
+
+		clrsetbits_le32(&ch[chn].ao.shu[0].hwset_mr13,
+			(0x1fff << 0) | (0xff << 16),
+			(13 << 0) | ((u1MR13Value_t | 0x1 << 3) << 16));
+
+		clrsetbits_le32(&ch[chn].ao.shu[0].hwset_vrcg,
+			(0x1fff << 0) | (0xff << 16),
+			(13 << 0) | ((u1MR13Value_t | (0x1 << 3)) << 16));
+
+		clrsetbits_le32(&ch[chn].ao.shu[0].hwset_mr2,
+			(0x1fff << 0) | (0xff << 16),
+			(2 << 0) | (u1MR2Value[FSP_1] << 16));
+	}
+
+	clrsetbits_le32(&ch[0].ao.mrs, (0x3 << 24), (RANK_0 << 24));
+	clrsetbits_le32(&ch[1].ao.mrs, (0x3 << 24), (RANK_0 << 24));
+
+	dramc_broadcast_onoff(broadcast_bak);
+}
+
+static u8 get_cbt_mode(const struct sdram_params *params)
+{
+	return params->cbt_mode_extern;
+}
+
+static void dramc_setting(const struct sdram_params *params)
+{
+	u8 chn;
+
+	auto_refresh_cke_off();
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+
+	/* before switch clock from 26M to PHY, need to init PHY clock first
+	 * move CKMUX_SEL_R_PHYCTRLMUX to here (it was originally between
+	 * MISC_CG_CTRL0_CLK_MEM_SEL and MISC_CTRL0_R_DMRDSEL_DIV2_OPT)
+	 * PHYCTRLDCM 1: follow DDRPHY_conf DCM settings,
+	 * 0: follow infra DCM settings */
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		setbits_le32(&ch[chn].phy.ckmux_sel,
+			(0x1 << 0) | (0x1 << 1));
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	setbits_le32(&ch[0].phy.misc_cg_ctrl0, (0x1 << 0));
+
+	/* 26M */
+	clrbits_le32(&ch[0].phy.misc_cg_ctrl0, (0x3 << 4));
+	clrbits_le32(&ch[0].phy.misc_ctrl0, (0x1 << 17));
+
+	/* LP4_3200_initial_setting_shu1 begin */
+	clrbits_le32(&ch[0].phy.misc_spm_ctrl1, (0x0000000f << 0));
+	write32(&ch[0].phy.misc_spm_ctrl2, ~(0xffffffff << 0));
+	write32(&ch[0].phy.misc_spm_ctrl0, ~(0xffffffff << 0));
+
+	write32(&ch[0].phy.misc_cg_ctrl2, 0x6003bf);
+	write32(&ch[0].phy.misc_cg_ctrl4, 0x333f3f00);
+	setbits_le32(&ch[0].phy.shu[0].pll[1], (0x1 << 4)|(0x7 << 1));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[7],
+		(0x3f << 0), (0x10 << 0)); /* combine */
+	clrbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x0f << 0));
+
+	clrsetbits_le32(&ch[0].phy.shu[0].pll[4],
+		 (0x3 << 18) | (0x3 << 24) | (0x3 << 26),
+		 (0x2 << 18) | (0x1 << 24) | (0x1 << 26));
+	clrsetbits_le32(&ch[0].phy.shu[0].pll[6],
+		(0x3 << 18) | (0x3 << 24) | (0x3 << 26),
+		(0x2 << 18) | (0x1 << 24) | (0x1 << 26));
+
+	clrbits_le32(&ch[0].phy.shu[0].pll[14], (0x1 << 1));
+	clrbits_le32(&ch[0].phy.shu[0].pll20, (0x1 << 1));
+	clrbits_le32(&ch[0].phy.ca_cmd[2], (0x3 << 16) | (0x3 << 20));
+	for (size_t b = 0; b < 2; b++)
+		clrbits_le32(&ch[0].phy.b[b].dq[2],
+			(0x3 << 16) | (0x3 << 20));
+	for (size_t b = 0; b < 2; b++)
+		clrsetbits_le32(&ch[0].phy.b[b].dq[9],
+			(0x7 << 28), (0x1 << 28));
+	clrbits_le32(&ch[0].phy.ca_cmd[10], (0x7 << 28));
+
+	setbits_le32(&ch[0].phy.b0_rxdvs[0], (0x1 << 28));
+	setbits_le32(&ch[0].phy.b1_rxdvs[0], (0x1 << 28));
+	setbits_le32(&ch[0].phy.b0_rxdvs[0], (0x1 << 9));
+	setbits_le32(&ch[0].phy.b1_rxdvs[0], (0x1 << 9));
+
+	for (size_t b = 0; b < 2; b++) {
+		for (size_t r = 0; r < 2; r++)
+			setbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2],
+					(0x1 << 29));
+		clrsetbits_le32(&ch[0].phy.shu[0].b[b].dq[5],
+			(0x7 << 20), (0x3 << 20));
+
+		for (size_t r = 0; r < 2; r++) {
+			clrsetbits_le32(&ch[0].phy.r[r].b[b].rxdvs[1],
+				(0xffff << 0) | (0xffff << 16),
+				(0x2 << 0) | (0x2 << 16));
+			clrsetbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2],
+				(0x1 << 23) | (0x1 << 28) | (0x3 << 30),
+				(0x1 << 23) | (0x1 << 28) | (0x2 << 30));
+		}
+	}
+
+	clrbits_le32(&ch[0].phy.b0_rxdvs[0], (0x1 << 28));
+	clrbits_le32(&ch[0].phy.b1_rxdvs[0], (0x1 << 28));
+
+	for (size_t b = 0; b < 2; b++) {
+		setbits_le32(&ch[0].phy.b[b].dq[9], (0x1 << 0));
+
+		for (size_t r = 0; r < 2; r++)
+			clrsetbits_le32(&ch[0].phy.shu[0].rk[r].b[b].dq[7],
+				(0x3f << 8) | (0x3f << 16),
+				(0x1f << 8) | (0x1f << 16));
+
+		clrsetbits_le32(&ch[0].phy.b[b].dq[4],
+			(0x7f << 0) | (0x7f << 8),
+			(0x10 << 0) | (0x10 << 8));
+		clrsetbits_le32(&ch[0].phy.b[b].dq[5],
+			(0xff << 0) | (0x3f << 8) | (0x1 << 16) | (0xf << 20) |
+			(0x1 << 24),
+			(0x10 << 0) | (0xe << 8) | (0x1 << 16) | (0x1 << 20) |
+			(0x0 << 24));
+		clrsetbits_le32(&ch[0].phy.b[b].dq[6],
+			(0x1 << 4) | (0x1 << 7) | (0x1 << 12) | (0x3 << 14) |
+			(0xf << 16) | (0x1 << 24),
+			(0x0 << 4) | (0x1 << 7) | (0x1 << 12) | (0x0 << 14) |
+			(0x3 << 16) | (0x1 << 24));
+		clrsetbits_le32(&ch[0].phy.b[b].dq[5],
+			(0xff << 0) | (0x1 << 25),
+			(0x0 << 0) | (0x1 << 25));
+	}
+
+	setbits_le32(&ch[0].phy.ca_cmd[3],
+			(0x1 << 2) | (0x1 << 3) | (0x1 << 7));
+	clrsetbits_le32(&ch[0].phy.ca_cmd[6],
+			(0x1 << 6) | (0x3 << 14) | (0x1 << 16),
+			(0x0 << 6) | (0x0 << 14) | (0x0 << 16));
+
+	clrbits_le32(&ch[0].phy.pll3, (0x1 < 0));
+	setbits_le32(&ch[0].phy.b[0].dq[3], (0x1 << 3));
+	setbits_le32(&ch[0].phy.b[1].dq[3], (0x1 << 3));
+
+	udelay(1);
+	clrsetbits_le32(&ch[0].phy.shu[0].pll[8],
+		(0x7 << 0) | (0x3 << 18),
+		(0x0 << 0) | (0x1 << 18));
+
+	udelay(1);
+	clrbits_le32(&ch[0].phy.shu[0].pll[9],
+		 (0x3 << 8) | (0x1 << 12) | (0x3 << 14) | (0x1 << 16));
+	clrbits_le32(&ch[0].phy.shu[0].pll[11],
+		 (0x3 << 8) | (0x1 << 12) | (0x3 << 14) | (0x1 << 16));
+	udelay(1);
+
+	clrsetbits_le32(&ch[0].phy.shu[0].pll[10],
+		(0x7 << 0) | (0x3 << 18), (0x0 << 0) | (0x1 << 18));
+	udelay(1);
+
+	/* PLL EN */
+	/* MID FINE_TUNE Init 1 */
+	clrsetbits_le32(&ch[0].phy.pll4,
+		(0x3 << 18) | (0x1 << 21), (0x3 << 18) | (0x0 << 21));
+
+	udelay(1);
+	clrsetbits_le32(&ch[0].phy.shu[0].pll[0],
+		(0xffff << 0), (0x3 << 0));
+
+	udelay(1);
+	setbits_le32(&ch[0].phy.ca_dll_fine_tune[1], (0x1 << 21));
+
+	for (size_t b = 0; b < 2; b++) {
+		setbits_le32(&ch[0].phy.b[b].dq[3],
+			(0x3 << 1) | (0x1 << 10));
+	}
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+	setbits_le32(&ch[0].phy.shu[0].ca_dll[0], (0x1 << 0));
+	setbits_le32(&ch[1].phy.shu[0].ca_dll[0], (0x1 << 0));
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	for (size_t b = 0; b < 2; b++)
+		clrsetbits_le32(&ch[0].phy.shu[0].b[b].dll[0],
+			(0x1 << 4) | (0x3 << 9) | (0xf << 12) |
+			(0xf << 16) | (0xf << 20) | (0x1 << 30),
+			(0x0 << 4) | (0x3 << 9) | (0x8 << 12) |
+			(0x7 << 16) | (0x7 << 20) | (0x1 << 30));
+
+	clrbits_le32(&ch[0].phy.shu[0].ca_cmd[5], (0x3f << 0));
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[0],
+		(0x1 << 4) | (0x7 << 12) | (0x1 << 20),
+		(0x1 << 4) | (0x4 << 12) | (0x1 << 20));
+
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[6],
+		(0xffff << 6), (0x3 << 6));
+	clrsetbits_le32(&ch[1].phy.shu[0].ca_cmd[6],
+		(0xffff << 6), (0x1 << 6));
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	for (size_t b = 0; b < 2; b++)
+		clrsetbits_le32(&ch[0].phy.shu[0].b[b].dq[6],
+				(0xffff << 6), 0x1 << 6);
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+	clrsetbits_le32(&ch[0].phy.misc_shu_opt,
+		(0x1 << 0) | (0x3 << 2) | (0x1 << 8) |
+		(0x3 << 10) | (0x1 << 16) | (0x3 << 18),
+		(0x1 << 0) | (0x2 << 2) | (0x1 << 8) |
+		(0x2 << 10) | (0x1 << 16) | (0x1 << 18));
+	clrsetbits_le32(&ch[1].phy.misc_shu_opt,
+		(0x1 << 0) | (0x3 << 2) | (0x1 << 8) |
+		(0x3 << 10) | (0x1 << 16) | (0x3 << 18),
+		(0x1 << 0) | (0x2 << 2) | (0x1 << 8) |
+		(0x2 << 10) | (0x1 << 16) | (0x2 << 18));
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+	udelay(9);
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_dll[1],
+		(0x1 << 0) | (0x1 << 2), (0x1 << 2));
+	clrsetbits_le32(&ch[1].phy.shu[0].ca_dll[1],
+		(0x1 << 0) | (0x1 << 2), (0x1 << 0));
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	for (size_t b = 0; b < 2; b++) {
+		clrsetbits_le32(&ch[0].phy.shu[0].b[b].dll[1],
+			(0x1 << 0) | (0x1 << 2), (0x1 << 0) | (0x0 << 2));
+	}
+
+	udelay(1);
+
+	clrbits_le32(&ch[0].phy.pll2, (0x1 << 31));
+	clrsetbits_le32(&ch[0].phy.misc_cg_ctrl0, 0xFFFFFFFF, 0xF);
+
+	udelay(1);
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+	ddr_phy_reserved_rg_setting();
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		ddr_phy_pll_setting(chn);
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	setbits_le32(&ch[0].ao.drsctrl, (0x1 << 29));
+	/* Set Run time MRR CKE fix to 1 in tMRRI old mode
+	 * to avoid no ACK from precharge all */
+	setbits_le32(&ch[0].ao.ckectrl, (0x1 << 27));
+	clrsetbits_le32(&ch[0].ao.dramctrl,
+		(0x1 << 15) | (0x1 << 17) | (0x1 << 23),
+		(0x0 << 15) | (0x1 << 17) | (0x1 << 23));
+	setbits_le32(&ch[0].ao.spcmdctrl,
+		(0x1 << 1) | (0x1 << 8) | (0x1 << 9) | (0x1 << 10));
+	setbits_le32(&ch[0].phy.b[0].dq[9], (0x1 << 4));
+	setbits_le32(&ch[0].phy.b[1].dq[9], (0x1 << 4));
+
+	clrsetbits_le32(&ch[0].ao.shu[0].rk[1].dqsien,
+		(0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24),
+		(0xf << 0) | (0xf << 8) | (0xf << 16) | (0xf << 24));
+	clrsetbits_le32(&ch[0].ao.stbcal1,
+		(0x1 << 4) | (0x1 << 8) | (0x1 << 12),
+		(0x1 << 4) | (0x1 << 8) | (0x0 << 12));
+	clrsetbits_le32(&ch[0].ao.shu[0].dqsg_retry,
+		(0x1 << 3) | (0xf << 8) | (0x1 << 21) | (0x1 << 31),
+		(0x1 << 3) | (0x6 << 8) | (0x1 << 21) | (0x1 << 31));
+
+	for (size_t i = 0; i < 4; i++) {
+		clrsetbits_le32(&ch[0].ao.shu[0].drving[i],
+			(0x1f << 0) | (0x1f << 5) | (0x1f << 10)
+			| (0x1f << 15) | (0x1f << 20) | (0x1f << 25),
+			(0xa << 0) | (0xa << 5) | (0xa << 10)
+			| (0xa << 15) | (0xa << 20) | (0xa << 25));
+	}
+
+	clrsetbits_le32(&ch[0].ao.shuctrl2,
+		(0x3f << 0) | (0x1 << 12) | (0x1 << 14) |
+		(0x1 << 15) | (0xff << 16) | (0x1 << 24),
+		(0xa << 0) | (0x1 << 12) | (0x1 << 14) |
+		(0x1 << 15) | (0x1 << 16) | (0x0 << 24));
+	setbits_le32(&ch[0].ao.dvfsdll, (0x1 << 0));
+	setbits_le32(&ch[0].ao.ddrconf0,
+		(0x1 << 12) | (0x1 << 15) | (0x1 << 20) | (0x1 << 26));
+	setbits_le32(&ch[0].ao.stbcal2,
+		(0x1 << 4) | (0x1 << 28) | (0x1 << 30));
+	setbits_le32(&ch[0].ao.stbcal2, (0x1 << 29));
+	clrbits_le32(&ch[0].ao.stbcal2, (0x1 << 29));
+	setbits_le32(&ch[0].ao.clkar, (0x1 << 19));
+
+	for (size_t b = 0; b < 2; b++)
+		clrsetbits_le32(&ch[0].phy.b[b].dq[9],
+			(0x7 << 20), (0x1 << 20));
+	clrsetbits_le32(&ch[0].phy.ca_cmd[10],
+		(0x7 << 20), (0x0 << 20));
+
+	if (get_cbt_mode(params) == CBT_BYTE_MODE1)
+		clrsetbits_le32(&ch[0].phy.misc_ctrl0,
+			(0xf << 0) | (0x1 << 9) | (0x7 << 18) |
+			(0x1 << 24) | (0x1 << 31),
+			(0xf << 0) | (0x1 << 9) | (0x1 << 18) |
+			(0x1 << 24) | (0x1 << 31));
+	else
+		setbits_le32(&ch[0].phy.misc_ctrl0,
+			(0xf << 0) | (0x1 << 9) | (0x1 << 24) | (0x1 << 31));
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++)
+		setbits_le32(&ch[chn].phy.misc_ctrl1,
+			 (0x1 << 2) | (0x1 << 3) | (0x1 << 15) | (0x1 << 24));
+	clrsetbits_le32(&ch[0].phy.b0_rxdvs[0],
+		(0x1 << 24), (0x1 << 24));
+	clrsetbits_le32(&ch[0].phy.b1_rxdvs[0],
+		(0x1 << 24), (0x1 << 24));
+
+	clrsetbits_le32(&ch[0].phy.ca_rxdvs0, (0x1 << 24), (0x0 << 24));
+
+	clrbits_le32(&ch[0].phy.ca_cmd[7], (0x1 << 4)|(0x1 << 6));
+	clrbits_le32(&ch[0].phy.b[0].dq[7], (0x1 << 6));
+	clrbits_le32(&ch[0].phy.b[1].dq[7], (0x1 << 6));
+
+	clrsetbits_le32(&ch[0].ao.shu[0].conf[0],
+		(0x3f << 0) | (0x1 << 7) | (0xf << 12) | (0x1 << 24) |
+		(0x1 << 29) | (0x3 << 30),
+		(0x3f << 0) | (0x1 << 7) | (0x1 << 12) | (0x1 << 24) |
+		(0x1 << 29) | (0x2 << 30));
+	clrsetbits_le32(&ch[0].ao.shu[0].odtctrl,
+		(0x1 << 0) | (0x1 << 1) | (0x7f << 16) | (0x1 << 30) |
+		(0x1 << 31),
+		(0x1 << 0) | (0x1 << 1) | (0x1 << 16) | (0x1 << 30) |
+		(0x1 << 31));
+	setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 15));
+	setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 15));
+
+	clrsetbits_le32(&ch[0].ao.refctrl0, (0xf << 24), (0x5 << 24));
+	clrbits_le32(&ch[0].ao.shu[0].selph_ca1,
+		 (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+		 (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28));
+	clrsetbits_le32(&ch[0].ao.shu[0].selph_ca2,
+		 (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 16) |
+		 (0x7 << 24),
+		 (0x0 << 0) | (0x0 << 4) | (0x0 << 8) | (0x7 << 16) |
+		 (0x0 << 24));
+	clrbits_le32(&ch[0].ao.shu[0].selph_ca3,
+		 (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+		 (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28));
+	clrbits_le32(&ch[0].ao.shu[0].selph_ca4,
+		 (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12)  |
+		 (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28));
+	clrbits_le32(&ch[0].ao.shu[0].selph_ca5, (0x7 << 8));
+	clrsetbits_le32(&ch[0].ao.shu[0].selph_dqs0,
+		(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+		(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+		(0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) |
+		(0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28));
+	clrsetbits_le32(&ch[0].ao.shu[0].selph_dqs1,
+		(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+		(0x7 << 16) | (0x7 << 20) |	(0x7 << 24) | (0x7 << 28),
+		(0x5 << 0) | (0x5 << 4) | (0x5 << 8) | (0x5 << 12) |
+		(0x2 << 16) | (0x2 << 20) | (0x2 << 24) | (0x2 << 28));
+
+	for (size_t i = 0; i < 2; i++) {
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[0],
+			(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+			(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+			(0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) |
+			(0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28));
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[1],
+			(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+			(0x7 << 16) | (0x7 << 20) | (0x7 << 24)	| (0x7 << 28),
+			(0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) |
+			(0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28));
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[2],
+			(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+			(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+			(0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) |
+			(0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28));
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[3],
+			(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+			(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+			(0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) |
+			(0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28));
+	}
+
+	for (int b = 0; b < 2; b++) {
+		clrsetbits_le32(&ch[0].phy.shu[0].rk[0].b[b].dq[7],
+			(0x3f << 8) | (0x3f << 16),
+			(0x1a << 8) | (0x1a << 16));
+		clrsetbits_le32(&ch[0].phy.shu[0].rk[1].b[b].dq[7],
+			(0x3f << 8) | (0x3f << 16),
+			(0x14 << 8) | (0x14 << 16));
+	}
+
+	udelay(1);
+
+	for (size_t b = 0; b < 2; b++) {
+		setbits_le32(&ch[0].phy.b[b].dq[9], (0x1 << 5));
+		clrsetbits_le32(&ch[0].phy.b[b].dq[6],
+				(0x3 << 14), (0x1 << 14));
+	}
+	setbits_le32(&ch[0].ao.stbcal, (0x1 << 31));
+	clrsetbits_le32(&ch[0].ao.srefctrl,
+		(0xf << 24) | (0x1 << 30), (0x8 << 24) | (0x0 << 30));
+	clrsetbits_le32(&ch[0].ao.shu[0].ckectrl,
+		(0x3 << 24) | (0x3 << 28),
+		(0x3 << 24) | (0x3 << 28));
+	setbits_le32(&ch[0].ao.shu[0].pipe, (0x1 << 30) | (0x1 << 31));
+	setbits_le32(&ch[0].ao.ckectrl, (0x1 << 13) | (0x1 << 31));
+	setbits_le32(&ch[0].ao.rkcfg, (0x1 << 2));
+
+	if (get_cbt_mode(params) == CBT_BYTE_MODE1) {
+		clrsetbits_le32(&ch[0].ao.shu[0].conf[2],
+			(0x7 << 16) | (0x1 << 28), (0x7 << 16) | (0x1 << 28));
+		clrsetbits_le32(&ch[0].ao.spcmdctrl,
+			(0x1 << 26), (0x1 << 26));
+		clrsetbits_le32(&ch[0].ao.shuctrl1, (0xff << 0), (0x40 << 0));
+	} else {
+		clrsetbits_le32(&ch[0].ao.shu[0].conf[2],
+			(0x7 << 16) | (0x1 << 28), (0x7 << 16) | (0x1 << 28));
+		clrsetbits_le32(&ch[0].ao.spcmdctrl,
+			(0x1 << 26), (0x1 << 26));
+		clrsetbits_le32(&ch[0].ao.shuctrl1, (0xff << 0), (0x40 << 0));
+	}
+
+	setbits_le32(&ch[0].ao.shuctrl, (0x1 << 16));
+	clrbits_le32(&ch[0].ao.refctrl1,
+		(0x1 << 1) | (0x1 << 2) | (0x1 << 3) | (0x1 << 6));
+
+	clrsetbits_le32(&ch[0].ao.refratre_filter, (0x1 << 15) | (0x1 << 23),
+		(0x1 << 15) | (0x0 << 23));
+
+	clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 9));
+	setbits_le32(&ch[0].ao.misctl0,
+		(0x1 << 19) | (0x1 << 24) | (0x1 << 31));
+	setbits_le32(&ch[0].ao.perfctl0,
+		(0x1 << 0) | (0x1 << 1) | (0x1 << 4) | (0x1 << 8) |
+		(0x1 << 9) | (0x1 << 10) | (0x1 << 11) |
+		(0x1 << 14) | (0x1 << 17));
+	clrsetbits_le32(&ch[0].ao.arbctl, (0xff << 0), (0x80 << 0));
+	clrsetbits_le32(&ch[0].ao.padctrl,
+		(0x3 << 0) | (0x1 << 3), (0x1 << 0) | (0x1 << 3));
+	setbits_le32(&ch[0].ao.dramc_pd_ctrl, (0x1 << 8));
+	setbits_le32(&ch[0].ao.clkctrl, (0x1 << 29));
+	clrsetbits_le32(&ch[0].ao.refctrl0,
+		(0x1 << 0) | (0x7 << 12), (0x1 << 0) | (0x4 << 12));
+
+	clrsetbits_le32(&ch[0].ao.shu[0].rankctl,
+		(0xf << 20) | (0xf << 24) | (0xf << 28),
+		(0x4 << 20) | (0x4 << 24) | (0x6 << 28));
+
+	udelay(2);
+
+	if (get_cbt_mode(params) == CBT_NORMAL_MODE) {
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[0].dqsien,
+			(0x7f << 0) | (0x7f << 8), (0x19 << 0) | (0x19 << 8));
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[1].dqsien,
+			(0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24),
+			(0x1b << 0) | (0x1b << 8) | (0x0 << 16) | (0x0 << 24));
+	}
+
+	setbits_le32(&ch[0].ao.dramctrl, (0x1 << 19));
+	clrsetbits_le32(&ch[0].ao.zqcs, (0xff << 0), (0x56 << 0));
+	udelay(1);
+
+	clrsetbits_le32(&ch[0].ao.shu[0].conf[3],
+		(0x1ff << 16), (0xff << 16));
+	setbits_le32(&ch[0].ao.refctrl0, (0x1 << 30));
+	setbits_le32(&ch[0].ao.srefctrl, (0x1 << 30));
+	setbits_le32(&ch[0].ao.mpc_option, (0x1 << 17));
+	setbits_le32(&ch[0].ao.dramc_pd_ctrl, (0x1 << 30));
+	setbits_le32(&ch[0].ao.dramc_pd_ctrl, (0x1 << 0));
+	clrsetbits_le32(&ch[0].ao.eyescan,
+		(0x1 << 1) | (0xf << 16), (0x0 << 1) | (0x1 << 16));
+	setbits_le32(&ch[0].ao.stbcal1, (0x1 << 10) | (0x1 << 11));
+	clrsetbits_le32(&ch[0].ao.test2_1, (0xfffffff << 4), (0x10000 << 4));
+	clrsetbits_le32(&ch[0].ao.test2_2, (0xfffffff << 4), (0x400 << 4));
+	clrsetbits_le32(&ch[0].ao.test2_3,
+		(0x1 << 7) | (0x7 << 8) | (0x1 << 28),
+		(0x1 << 7) | (0x4 << 8) | (0x1 << 28));
+	clrbits_le32(&ch[0].ao.rstmask, (0x1 << 29));
+	clrbits_le32(&ch[0].ao.rstmask, (0x1 << 30));
+
+	udelay(1);
+	clrsetbits_le32(&ch[0].ao.hw_mrr_fun, (0xf << 0) | (0xf << 4),
+		(0x8 << 0) | (0x6 << 4));
+
+	if (get_cbt_mode(params) == CBT_BYTE_MODE1) {
+		setbits_le32(&ch[0].ao.perfctl0, (0x1 << 27));
+		clrsetbits_le32(&ch[0].ao.perfctl0,
+			(0x1 << 18) | (0x1 << 19), (0x0 << 18) | (0x1 << 19));
+		clrbits_le32(&ch[0].ao.rstmask, (0x1 << 28));
+		setbits_le32(&ch[0].ao.rkcfg, (0x1 << 11));
+		setbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 28));
+		setbits_le32(&ch[0].ao.eyescan, (0x1 << 2));
+	} else {
+		clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 0));
+		clrsetbits_le32(&ch[0].ao.perfctl0,
+			(0x1 << 18) | (0x1 << 19),
+			(0x0 << 18) | (0x1 << 19));
+		setbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 28));
+		clrbits_le32(&ch[0].ao.rstmask, (0x1 << 28));
+		setbits_le32(&ch[0].ao.rkcfg, (0x1 << 11));
+		setbits_le32(&ch[0].ao.mpc_option, (0x1 << 17));
+		setbits_le32(&ch[0].ao.eyescan, (0x1 << 2));
+		setbits_le32(&ch[0].ao.shu[0].wodt, (0x1 << 29));
+		setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 7));
+		setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 7));
+		clrsetbits_le32(&ch[0].ao.shu[0].rankctl, (0xf << 20),
+			(0x4 << 20));
+
+		for (size_t r = 0; r < 2; r++) {
+			clrsetbits_le32(&ch[0].ao.shu[0].rk[r].selph_dq[0],
+				(0x7 << 0) | (0x7 << 4),
+				(0x2 << 0) | (0x2 << 4));
+			clrsetbits_le32(&ch[0].ao.shu[0].rk[r].selph_dq[1],
+				(0x7 << 0) | (0x7 << 4),
+				(0x2 << 0) | (0x2 << 4));
+		}
+	}
+	udelay(5);
+
+	clrsetbits_le32(&ch[0].ao.stbcal1, (0xffff << 16), (0x3 << 16));
+	clrsetbits_le32(&ch[0].ao.stbcal1, (0xffff << 16), (0x1 << 16));
+	clrsetbits_le32(&ch[0].ao.stbcal,
+		(0x1 << 0) | (0x1 << 22) | (0x1 << 24) |
+		(0x1 << 26) | (0x1 << 27),
+		(0x1 << 0) | (0x0 << 22) | (0x0 << 24) |
+		(0x1 << 26) | (0x1 << 27));
+	setbits_le32(&ch[0].ao.stbcal1, (0x1 << 6));
+	clrsetbits_le32(&ch[0].ao.shu[0].dqsg,
+		(0x1 << 11) | (0xf << 12), (0x1 << 11) | (0x9 << 12));
+	clrbits_le32(&ch[0].phy.misc_ctrl0, (0xf << 0));
+	setbits_le32(&ch[0].ao.shu[0].stbcal, (0x1 << 8));
+	setbits_le32(&ch[0].ao.stbcal, (0x1 << 17));
+
+	clrbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 14));
+	clrbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 14));
+	clrsetbits_le32(&ch[0].ao.shu[0].stbcal, (0x7 << 4), (0x1 << 4));
+
+	clrsetbits_le32(&ch[0].ao.shu[0].stbcal, (0x3 << 0), (0x2 << 0));
+
+	setbits_le32(&ch[0].ao.refctrl1, (0x1 << 0) | (0x1 << 5));
+	setbits_le32(&ch[0].ao.dqsoscr, (0x1 << 23) | (0x1 << 27));
+	clrbits_le32(&ch[0].ao.rstmask,
+		(0x1 << 24) | (0x1 << 25) | (0x1 << 26));
+	clrsetbits_le32(&ch[0].ao.rkcfg, (0x7 << 4), (0x1 << 4));
+
+	udelay(12);
+
+	if (get_cbt_mode(params) == CBT_BYTE_MODE1) {
+		clrsetbits_le32(&ch[0].ao.shu[0].rankctl,
+			(0xf << 20) | (0xf << 24) | (0xf << 28),
+			(0x3 << 20) | (0x3 << 24) | (0x5 << 28));
+	} else {
+		clrsetbits_le32(&ch[0].ao.shu[0].rankctl,
+			(0xf << 24) | (0xf << 28),
+			(0x4 << 24) | (0x6 << 28));
+	}
+
+	clrbits_le32(&ch[0].ao.shu[0].wodt, (0x1 << 31));
+	if (get_cbt_mode(params) == CBT_BYTE_MODE1) {
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[0].dqsien,
+			(0x7f << 0) | (0x7f << 8), (0x19 << 0) | (0x19 << 8));
+	}
+	clrsetbits_le32(&ch[0].ao.shu[0].rk[0].fine_tune,
+		(0x3f << 0) | (0x3f << 8) | (0x3f << 16) | (0x3f << 24),
+		(0x1a << 0) | (0x1a << 8) | (0x1a << 16) | (0x1a << 24));
+	clrsetbits_le32(&ch[0].ao.shu[0].rk[0].selph_dq[2],
+		(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+		(0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28));
+	clrsetbits_le32(&ch[0].ao.shu[0].rk[0].selph_dq[3],
+		(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+		(0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28));
+	if (get_cbt_mode(params) == CBT_BYTE_MODE1) {
+		clrsetbits_le32(&ch[0].ao.shu[0].rk[1].dqsien,
+			(0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24),
+			(0x1b << 0) | (0x1b << 8) | (0x0 << 16) | (0x0 << 24));
+	}
+	clrsetbits_le32(&ch[0].ao.shu[0].rk[1].fine_tune,
+		(0x3f << 0) | (0x3f << 8) | (0x3f << 16) | (0x3f << 24),
+		(0x14 << 0) | (0x14 << 8) | (0x14 << 16) | (0x14 << 24));
+	clrsetbits_le32(&ch[0].ao.shu[0].rk[1].selph_dq[2],
+		(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+		(0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28));
+	clrsetbits_le32(&ch[0].ao.shu[0].rk[1].selph_dq[3],
+		(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+		(0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28));
+	clrsetbits_le32(&ch[0].ao.shu[0].dqsg_retry,
+		(0x1 << 2) | (0xf << 8) | (0x1 << 14) | (0x3 << 24),
+		(0x1 << 2) | (0x5 << 8) | (0x0 << 14) | (0x1 << 24));
+
+	if (get_cbt_mode(params) == CBT_BYTE_MODE1) {
+		setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 12));
+		setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 12));
+	} else {
+		setbits_le32(&ch[0].phy.shu[0].b[0].dq[7],
+			(0x1 << 12) | (0x1 << 13));
+		setbits_le32(&ch[0].phy.shu[0].b[1].dq[7],
+			(0x1 << 12) | (0x1 << 13));
+	}
+
+	clrbits_le32(&ch[0].ao.shu[0].dqs2dq_tx, (0x1f << 0));
+	update_initial_settings();
+
+	clrbits_le32(&ch[0].ao.test2_4, (0x1 << 17));
+	clrsetbits_le32(&ch[0].ao.shu[0].conf[3], (0x1ff << 0), (0x5 << 0));
+	delay(1);
+
+	setbits_le32(&ch[0].ao.refctrl0, (0x1 << 17) | (0x1 << 18));
+	setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 24) | (0x1 << 25));
+	setbits_le32(&ch[0].ao.refctrl0, (0x1 << 29));
+	setbits_le32(&ch[0].ao.dramctrl, (0x1 << 26));
+	clrsetbits_le32(&ch[0].ao.dummy_rd,
+		(0x1 << 4) | (0x1 << 11) | (0x1 << 13) |
+		(0x1 << 14) | (0x3 << 16) | (0x1 << 22),
+		(0x1 << 4) | (0x1 << 11) | (0x1 << 13) |
+		(0x1 << 14) | (0x2 << 16) | (0x1 << 22));
+	clrsetbits_le32(&ch[0].ao.test2_4, (0x7 << 28), (0x4 << 28));
+	clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 0));
+
+	udelay(1);
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+
+	clrsetbits_le32(&ch[0].ao.shuctrl,
+		(0x1 << 5)|(0x1 << 17), (0x0 << 5)|(0x1 << 17));
+	setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 12));
+
+	clrsetbits_le32(&ch[1].ao.shuctrl,
+		(0x1 << 5)|(0x1 << 17), (0x1 << 5)|(0x0 << 17));
+	clrbits_le32(&ch[1].ao.shuctrl2, (0x1 << 12));
+
+	s8 clkDelay = params->clk_delay;
+	s8 dqsDelay[CHANNEL_NUM] = {params->dqs_delay[CHANNEL_A],
+		params->dqs_delay[CHANNEL_B]};
+	dramc_dbg("%s param: clkdelay:0x%x,"
+		" dqsDelay[0]:0x%x, dqsDelay[1]:0x%x\n", __func__,
+		clkDelay, dqsDelay[0], dqsDelay[1]);
+
+	dramc_duty_calibration(CHANNEL_A, clkDelay, dqsDelay[CHANNEL_A]);
+	dramc_duty_calibration(CHANNEL_B, clkDelay, dqsDelay[CHANNEL_B]);
+
+	dramc_mode_reg_init();
+}
+
+void dramc_ac_timing_optimize(void)
+{
+	u8 chn;
+	dramc_dbg("[ACTiming Optimize] For MR8[5:2] = 4 sample only\n");
+	dramc_dbg("16Gb per die (8Gb per channel)\n");
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[3],
+			(0xff << 16), (0x64 << 16));
+		clrbits_le32(&ch[chn].ao.shu[0].ac_time_05t, (0x1 << 2));
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[4],
+			(0x3ff << 0), (0x77 << 0));
+	}
+}
+
+static void ddr_update_ac_timing(void)
+{
+	u32 temp;
+
+	for (u8 chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[0],
+			(0xf << 24) | (0x7 << 16) | (0x1f << 8) | (0xf << 0),
+			(0x6 << 24) | (0x2 << 16) | (0xc << 8) | (0x7 << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[1],
+			(0x1f << 24) | (0xf << 16) | (0xf << 8) | (0x7 << 0),
+			(0x10 << 24) | (0x8 << 16) | (0x5 << 8) | (0x1 << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[2],
+			(0x1f << 24) | (0xf << 16) | (0x7 << 8) | (0x7 << 0),
+			(0x7 << 24) | (0x7 << 16) | (0x2 << 8) | (0x1 << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[3],
+			(0xff << 16) | (0xff << 24) | (0xff << 0),
+			(0x64 << 16) | (0x61 << 24) | (0x2c << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[4],
+			(0xff << 24) | (0xff << 16) | (0x3ff << 0),
+			(0x22 << 24) | (0x65 << 16) | (0x77 << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim[5],
+			(0xf << 24) | (0x1f << 8) | (0x1f << 0),
+			(0xa << 24) | (0xc << 8) | (0xb << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].actim_xrt,
+			(0xf << 24) | (0x7 << 16) | (0xf << 8) | (0x1f << 0),
+			(0x5 << 24) | (0x3 << 16) | (0x6 << 8) | (0x9 << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].ac_time_05t,
+			(0x1 << 25) | (0x0 << 24) | (0x1 << 16) | (0x0 << 15)|
+			(0x1 << 13) | (0x1 << 12) | (0x1 << 10) | (0x1 << 9) |
+			(0x1 << 8) | (0x1 << 7) | (0x1 << 6) | (0x1 << 5) |
+			(0x1 << 4) | (0x1 << 2) | (0x1 << 1) | (0x1 << 0),
+			(0x0 << 25) | (0x0 << 24) | (0x1 << 16) | (0x0 << 15) |
+			(0x0 << 13) | (0x0 << 12) | (0x1 << 10) | (0x1 << 9) |
+			(0x0 << 8) | (0x1 << 7) | (0x1 << 6) | (0x1 << 5) |
+			(0x0 << 4) | (0x0 << 2) | (0x0 << 1) | (0x1 << 0));
+		clrsetbits_le32(&ch[chn].ao.catraining1,
+			(0xff << 24) | (0xf << 20), (0xb << 24) | (0x0 << 20));
+
+		/* DQSINCTL related */
+		clrsetbits_le32(&ch[chn].ao.shu[0].rk[0].dqsctl,
+			(0xf << 0), (0x4 << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].rk[1].dqsctl,
+			(0xf << 0), (0x4 << 0));
+		clrsetbits_le32(&ch[chn].ao.shu[0].odtctrl,
+			(0xf << 4), (0x4 << 4));
+
+		/* DATLAT related, tREFBW */
+		clrsetbits_le32(&ch[chn].ao.shu[0].conf[1],
+			(0x1f << 0) | (0x1f << 8) |
+			(0x1f << 26) | (0x3ff << 16),
+			(0xf << 0) | (0xd << 8) | (0xd << 26) | (0x0 << 16));
+		clrsetbits_le32(&ch[chn].ao.shu[0].conf[2],
+			(0xff << 8), (0x64 << 8));
+		clrsetbits_le32(&ch[chn].ao.shu[0].scintv,
+			(0x1f << 13) | (0x1f << 6), (0xf << 13) | (0xc << 6));
+
+		/* CKEPRD - CKE pulse width */
+		clrsetbits_le32(&ch[chn].ao.shu[0].ckectrl,
+			(0x7 << 20), (0x2 << 20));
+
+		/* CKELCKCNT: Valid clock requirement after CKE input low */
+		clrsetbits_le32(&ch[chn].ao.ckectrl, (0x7 << 24), (0x0 << 24));
+
+		/* Ininital setting values are the same,
+		 * RANKINCTL_RXDLY = RANKINCTL = RANKINCTL_ROOT1
+		 * XRTR2R setting will be updated in RxdqsGatingPostProcess */
+		temp = (read32(&ch[chn].ao.shu[0].rankctl) & 0x00f00000) >> 20;
+		clrsetbits_le32(&ch[chn].ao.shu[0].rankctl,
+			(0xf << 0), (temp << 0));
+
+		u8 u1ROOT = 0, u1TXRANKINCTL = 1, u1TXDLY = 2;
+		clrsetbits_le32(&ch[chn].ao.shu[0].rankctl,
+			(0xf << 16) | (0xf << 12) | (0xf << 8),
+			(u1ROOT << 16) | (u1TXRANKINCTL << 12) |
+			(u1TXDLY << 8));
+	}
+}
+
+void dramc_init(const struct sdram_params *params)
+{
+	u8 dram_t = 3;
+	u8 dram_cbt_mode, dram_cbt_mode_r0, dram_cbt_mode_r1;
+
+	dramc_setting(params);
+
+	ddr_update_ac_timing();
+
+	clrsetbits_le32(&ch[0].ao.arbctl, (0x3 << 10), (dram_t << 10));
+
+	dram_cbt_mode = get_cbt_mode(params);
+	dram_cbt_mode_r0 = dram_cbt_mode_r1 = dram_cbt_mode;
+
+	clrsetbits_le32(&ch[0].ao.rstmask, (0x3 << 13), dram_cbt_mode);
+
+	clrsetbits_le32(&ch[0].ao.arbctl, (0x1 << 13),
+		dram_cbt_mode_r0 | dram_cbt_mode_r1);
+}
diff --git a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
new file mode 100644
index 0000000..f08a659
--- /dev/null
+++ b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
@@ -0,0 +1,2626 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <soc/dramc_register.h>
+#include <soc/dramc_pi_api.h>
+#include <soc/emi.h>
+#include <delay.h>
+#include <soc/infracfg.h>
+
+#define TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP 64
+#define IMP_LP4X_TERM_VREF_SEL		0x1b
+#define IMP_DRVP_LP4X_UNTERM_VREF_SEL	0x1a
+#define IMP_DRVN_LP4X_UNTERM_VREF_SEL	0x16
+#define IMP_TRACK_LP4X_UNTERM_VREF_SEL	0x1a
+
+enum {
+	DQ_DIV_SHIFT = 3,
+	DQ_DIV_MASK = BIT(DQ_DIV_SHIFT) - 1,
+	OEN_SHIFT = 16,
+};
+
+enum {
+	RX_VREF_BEGIN = 0,
+	RX_VREF_END = 12,
+	RX_VREF_STEP = 0x1,
+	TX_VREF_BEGIN = 8,
+	TX_VREF_END = 18,
+	TX_VREF_STEP = 1,
+};
+
+enum {
+	FIRST_DQ_DELAY = 0,
+	FIRST_DQS_DELAY = -27,
+	MAX_DQDLY_TAPS = 16,
+	MAX_RX_DQDLY_TAPS = 63,
+	MAX_TX_DQDLY_TAPS = 200,
+	MAX_TX_DQSDLY_TAPS = 63,
+	MAX_RX_DQSDLY_TAPS = 26
+};
+
+enum {
+	RX_WIN = 0,
+	STAGE_SETUP = 0,
+	STAGE_HOLD = 1,
+	STAGE_SETUP_RX_WIN = STAGE_SETUP | RX_WIN << 1,
+	STAGE_HOLD_RX_WIN = STAGE_HOLD | RX_WIN << 1,
+	STAGE_PRE_HOLD_RX_WIN,
+	TX_WIN_MOVE_DQ_ONLY,
+	TX_WIN_MOVE_DQ_DQM,
+};
+
+enum {
+	RX_DQ = 0,
+	RX_DQM,
+	RX_DQS,
+	TX_DQ,
+	TX_DQS,
+	TX_DQM
+};
+
+struct dqs_perbit_dly {
+	u8 vref;
+	s16 first_dqdly_pass;
+	s16 last_dqdly_pass;
+	s16 first_dqsdly_pass;
+	s16 last_dqsdly_pass;
+	s16 best_first_dqdly_pass;
+	s16 best_last_dqdly_pass;
+	s16 best_first_dqsdly_pass;
+	s16 best_last_dqsdly_pass;
+	s16 best_dqdly;
+	s16 best_dqsdly;
+};
+
+struct tx_dly_coarse_fine_tune {
+	u8 fine_tune;
+	u8 coarse_tune_large;
+	u8 coarse_tune_small;
+	u8 coarse_tune_large_oen;
+	u8 coarse_tune_small_oen;
+};
+
+struct per_byte_dly {
+	u16 max_center;
+	u16 min_center;
+	u16 final_dly;
+};
+
+static void auto_refresh_switch(u8 chn, u8 option)
+{
+	if (option == ENABLE) {
+		/* enable autorefresh */
+		clrbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_REFDIS_SHIFT);
+	} else {
+		/* disable autorefresh */
+		setbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_REFDIS_SHIFT);
+
+		/* because HW will actually disable autorefresh
+		 * after refresh_queue empty, we need to wait quene empty */
+		udelay(((read32(&ch[chn].nao.misc_statusa) &
+				MISC_STATUSA_REFRESH_QUEUE_CNT_MASK) >>
+				MISC_STATUSA_REFRESH_QUEUE_CNT_SHIFT)*4);
+	}
+}
+
+static void dramc_rank_swap(u8 chn, u8 rank)
+{
+	u8 multi_rank = 1;
+
+	dramc_dbg("[RankSwap] (Multi %d), Rank %d\n", multi_rank, rank);
+
+	clrsetbits_le32(&ch[chn].ao.rkcfg,
+		RKCFG_RKMODE_MASK | 1 << RKCFG_RKSWAP_SHIFT | RKCFG_TXRANK_MASK,
+		(multi_rank << RKCFG_RKMODE_SHIFT) |
+		(rank << RKCFG_RKSWAP_SHIFT) | (rank << RKCFG_TXRANK_SHIFT));
+
+	/* TXRANK should be set before TXRANKFIX */
+	clrsetbits_le32(&ch[chn].ao.rkcfg,
+		1 << RKCFG_TXRANKFIX_SHIFT, rank << RKCFG_TXRANKFIX_SHIFT);
+}
+
+static void move_dramc_dq_common(uint32_t *reg_0p5t, uint32_t *reg_2t,
+		u8 shift, s8 shift_coarse_tune)
+{
+	s32 tmp_0p5t, tmp_2t;
+	s32 sum = (((read32(reg_2t) >> shift) & DQ_DIV_MASK) << DQ_DIV_SHIFT) +
+		  ((read32(reg_0p5t) >> shift) & DQ_DIV_MASK) +
+		  shift_coarse_tune;
+
+	if (sum < 0)
+		sum = 0;
+
+	tmp_0p5t = sum & DQ_DIV_MASK;
+	tmp_2t = sum >> DQ_DIV_SHIFT;
+
+	clrsetbits_le32(reg_0p5t, DQ_DIV_MASK << shift, tmp_0p5t << shift);
+	clrsetbits_le32(reg_2t, DQ_DIV_MASK << shift, tmp_2t << shift);
+}
+
+static void move_dramc_tx_dqs(u8 chn, u8 byte_idx, s8 shift_coarse_tune)
+{
+	move_dramc_dq_common(&ch[chn].ao.shu[0].selph_dqs1,
+			     &ch[chn].ao.shu[0].selph_dqs0,
+			     byte_idx * 4, shift_coarse_tune);
+}
+
+static void move_dramc_tx_dqs_oen(u8 chn, u8 byte_idx,
+		s8 shift_coarse_tune)
+{
+	move_dramc_dq_common(&ch[chn].ao.shu[0].selph_dqs1,
+			     &ch[chn].ao.shu[0].selph_dqs0,
+			     (byte_idx * 4) + OEN_SHIFT, shift_coarse_tune);
+}
+
+static void move_dramc_tx_dq(u8 chn, u8 rank, u8 byte_idx, s8 shift_coarse_tune)
+{
+	move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[3],
+			     &ch[chn].ao.shu[0].rk[rank].selph_dq[1],
+			     byte_idx * 4, shift_coarse_tune);
+
+	move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[2],
+			     &ch[chn].ao.shu[0].rk[rank].selph_dq[0],
+			     byte_idx * 4, shift_coarse_tune);
+}
+
+static void move_dramc_tx_dq_oen(u8 chn, u8 rank,
+	u8 byte_idx, s8 shift_coarse_tune)
+{
+	move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[3],
+			     &ch[chn].ao.shu[0].rk[rank].selph_dq[1],
+			     (byte_idx * 4) + OEN_SHIFT, shift_coarse_tune);
+
+	move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[2],
+			     &ch[chn].ao.shu[0].rk[rank].selph_dq[0],
+			     (byte_idx * 4) + OEN_SHIFT, shift_coarse_tune);
+}
+
+static void write_leveling_move_dqs_instead_of_clk(u8 chn)
+{
+	for (u8 byte_idx = 0; byte_idx < DQS_NUMBER; byte_idx++) {
+		move_dramc_tx_dqs(chn, byte_idx, -1);
+		move_dramc_tx_dqs_oen(chn, byte_idx, -1);
+
+		for (u8 i = RANK_0; i < RANK_MAX; i++) {
+			move_dramc_tx_dq(chn, i, byte_idx, -1);
+			move_dramc_tx_dq_oen(chn, i, byte_idx, -1);
+		}
+	}
+}
+
+void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value)
+{
+	u32 rank = 0;
+	u32 u4reg_024;
+
+	u4reg_024 = read32(&ch[chn].ao.ckectrl);
+
+	cke_fix_onoff(CKE_FIXON, chn);
+
+	clrsetbits_le32(&ch[chn].ao.mrs,
+		MRS_MRSMA_MASK, mr_idx << MRS_MRSMA_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.mrs,
+		MRS_MRSOP_MASK, value << MRS_MRSOP_SHIFT);
+
+	setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_MRWEN_SHIFT);
+
+	while ((read32(&ch[chn].nao.spcmdresp) & 1) == 0) {
+		dramc_dbg("wait MRW command fired\n");
+		udelay(1);
+	}
+
+	clrbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_MRWEN_SHIFT);
+	setbits_le32(&ch[chn].ao.ckectrl, u4reg_024);
+
+	rank = (read32(&ch[chn].ao.mrs) & MRS_MRSRK_MASK) >>
+		MRS_MRSRK_SHIFT;
+
+	dramc_dbg("Write Rank%d MR%d =0x%x\n", rank, mr_idx, value);
+}
+
+void dramc_mode_reg_write_by_rank(u8 chn, u8 rank,
+	u8 mr_idx, u8 value)
+{
+	u32 u4RabnkBackup;
+
+	u4RabnkBackup = (read32(&ch[chn].ao.mrs) & MRS_MRSRK_MASK) >> 24;
+
+	clrsetbits_le32(&ch[chn].ao.mrs,
+		MRS_MRSRK_MASK, rank << MRS_MRSRK_SHIFT);
+	dramc_mode_reg_write(chn, mr_idx, value);
+
+	clrsetbits_le32(&ch[chn].ao.mrs,
+		MRS_MRSRK_MASK, u4RabnkBackup << MRS_MRSRK_SHIFT);
+}
+
+static void dramc_write_leveling(u8 chn, u8 rank,
+	const struct sdram_params *params)
+{
+	s32 wrlevel_dq_delay[DQS_NUMBER];
+	s32 wrlevel_dqs_final_delay[DQS_NUMBER];
+	s32 clock_delay_max = 0;
+
+	dramc_show("chn:%d, rank:%d params write level:0x%x, 0x%x\n",
+		chn, rank, params->wr_level[chn][rank][0],
+		params->wr_level[chn][rank][1]);
+
+	wrlevel_dqs_final_delay[0] = params->wr_level[chn][rank][0];
+	wrlevel_dqs_final_delay[1] = params->wr_level[chn][rank][1];
+
+	dramc_rank_swap(chn, rank);
+
+	if (rank == RANK_0)
+		write_leveling_move_dqs_instead_of_clk(chn);
+
+	dramc_dbg("No need to update CA/CS dly (CLK dly smaller than CA training)\n");
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[9],
+		SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_MASK,
+		clock_delay_max << SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_SHIFT);
+
+	dramc_dbg("Final Clk output dly = %d\n", clock_delay_max);
+
+	for (size_t i = 0; i < DQS_NUMBER; i++) {
+		dramc_dbg("DQS%zd dly: %d\n", i, wrlevel_dqs_final_delay[i]);
+	}
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7],
+		SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_MASK,
+		wrlevel_dqs_final_delay[0] <<
+		SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_SHIFT);
+	clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7],
+		SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_MASK,
+		wrlevel_dqs_final_delay[1] <<
+		SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_SHIFT);
+
+	for (u8 i = 0; i < DQS_NUMBER; i++) {
+		wrlevel_dq_delay[i] = wrlevel_dqs_final_delay[i] + 0x10;
+		if (wrlevel_dq_delay[i] >= 0x40) {
+			wrlevel_dq_delay[i] -= 0x40;
+			move_dramc_tx_dq(chn, rank, i, 2);
+			move_dramc_tx_dq_oen(chn, rank, i, 2);
+		}
+	}
+	dramc_show("chn:%d, rank:%d, dq_delay: 0x%x, 0x%x\n",
+		chn, rank, wrlevel_dq_delay[0], wrlevel_dq_delay[1]);
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7],
+		SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK |
+		SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK,
+		(wrlevel_dq_delay[0] <<
+		SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_SHIFT) |
+		(wrlevel_dq_delay[0] <<
+		SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_SHIFT));
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7],
+		SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK |
+		SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK,
+		(wrlevel_dq_delay[1] <<
+		SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_SHIFT) |
+		(wrlevel_dq_delay[1] <<
+		SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_SHIFT));
+
+	dramc_rank_swap(chn, RANK_0);
+}
+
+static void cmd_bus_training(u8 chn, u8 rank,
+	const struct sdram_params *params)
+{
+	u32 cbt_cs, i_mr12_value;
+
+	cbt_cs = params->cbt_cs[chn][rank];
+	i_mr12_value = params->cbt_mr12[chn][rank];
+
+	dramc_dbg("start chn:%d, rank:%d, "
+		"cbt_cs:0x%x, mr12_value:0x%x\n",
+		chn, rank, cbt_cs, i_mr12_value);
+
+	/* cbt_adjust_cs */
+	clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[9],
+		SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CS_MASK,
+		cbt_cs << 0);
+
+	/* cbt_set_vref */
+	dramc_mode_reg_write_by_rank(chn, rank, 12,  i_mr12_value);
+}
+
+void dramc_gating_mode(u8 chn, u8 mode)
+{
+	u8 VrefSel = 0, BurstE2 = 0;
+	if (mode == 0) {
+		VrefSel = 0;
+		BurstE2 = 0;
+	} else {
+		VrefSel = 2;
+		BurstE2 = 1;
+	}
+
+	clrsetbits_le32(&ch[chn].ao.stbcal1, (0x1 << 5), (BurstE2 << 5));
+	setbits_le32(&ch[chn].ao.stbcal, (0x1 << 30));
+
+	for (u8 b = 0; b < 2; b++) {
+		clrsetbits_le32(&ch[chn].phy.b[b].dq[6],
+				(0x3 << 14), (VrefSel << 14));
+		setbits_le32(&ch[chn].phy.b[b].dq[9], (0x1 << 5));
+
+		clrbits_le32(&ch[chn].phy.b[b].dq[9], (0x1 << 4) | (0x1 << 0));
+		udelay(1);
+		setbits_le32(&ch[chn].phy.b[b].dq[9], (0x1 << 4) | (0x1 << 0));
+	}
+}
+
+static void rx_dqs_isi_pulse_cg_en(u8 chn)
+{
+	dramc_dbg("CH %d RX DQS ISI pulse CG: enable\n", chn);
+
+	setbits_le32(&ch[chn].phy.b[0].dq[6],
+		1 << B0_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B0_SHIFT);
+	setbits_le32(&ch[chn].phy.b[1].dq[6],
+		1 << B1_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B1_SHIFT);
+}
+
+static void rx_dqs_isi_pulse_cg_dis(u8 chn)
+{
+	dramc_dbg("CH %d RX DQS ISI pulse CG: disable\n", chn);
+
+	clrbits_le32(&ch[chn].phy.b[0].dq[6],
+		1 << B0_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B0_SHIFT);
+	clrbits_le32(&ch[chn].phy.b[1].dq[6],
+		1 << B1_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B1_SHIFT);
+}
+
+static void dram_phy_reset(u8 chn)
+{
+	setbits_le32(&ch[chn].ao.ddrconf0, 1 << DDRCONF0_RDATRST_SHIFT);
+	setbits_le32(&ch[chn].phy.misc_ctrl1,
+		1 << MISC_CTRL1_R_DMPHYRST_SHIFT);
+
+	clrbits_le32(&ch[chn].phy.b[0].dq[9],
+		 (1 << 4) | (1 << 0));
+	clrbits_le32(&ch[chn].phy.b[1].dq[9],
+		 (1 << 4) | (1 << 0));
+
+	udelay(1);
+
+	setbits_le32(&ch[chn].phy.b[1].dq[9],
+		 (1 << 4) | (1 << 0));
+	setbits_le32(&ch[chn].phy.b[0].dq[9],
+		 (1 << 4) | (1 << 0));
+
+	clrbits_le32(&ch[chn].phy.misc_ctrl1,
+		1 << MISC_CTRL1_R_DMPHYRST_SHIFT);
+	clrbits_le32(&ch[chn].ao.ddrconf0,
+		1 << DDRCONF0_RDATRST_SHIFT);
+}
+
+static void find_gating_window(u32 result_r, u32 result_f, u32 *debug_cnt,
+	u8 dly_coarse_large, u8 dly_coarse_0p5t, u8 *pass_begin,
+	u8 *pass_count, u8 *dly_fine_xt, u32 *coarse_tune, u8 *dqs_high)
+{
+	u8 dqs;
+	u32 pass_byte_count = 0, current_pass = 0;
+	u16 debug_cnt_perbyte;
+	u8 pass_count_1[DQS_NUMBER], min_coarse_tune2t_1[DQS_NUMBER],
+	    min_coarse_tune0p5t_1[DQS_NUMBER], min_fine_tune_1[DQS_NUMBER];
+
+	u32 coarse_start = 18;
+	u32 coarse_end = coarse_start + 24;
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		if (pass_byte_count & (1 << dqs))
+			continue;
+
+		u8 dqs_result_r = (u8) ((result_r >> (8 * dqs)) & 0xff);
+		u8 dqs_result_f = (u8) ((result_f >> (8 * dqs)) & 0xff);
+		debug_cnt_perbyte = (u16) debug_cnt[dqs];
+
+		current_pass = 0;
+
+		if ((dqs_result_r == 0) && (dqs_result_f == 0) &&
+		    (debug_cnt_perbyte == GATING_GOLDEND_DQSCNT))
+			current_pass = 1;
+
+		if (current_pass) {
+			if (pass_begin[dqs] == 0) {
+				pass_begin[dqs] = 1;
+				pass_count_1[dqs] = 0;
+				min_coarse_tune2t_1[dqs] = dly_coarse_large;
+				min_coarse_tune0p5t_1[dqs] = dly_coarse_0p5t;
+				min_fine_tune_1[dqs] = *dly_fine_xt;
+				dramc_dbg("[Byte %d]First pass (%d, %d, %d)\n",
+					      dqs, dly_coarse_large,
+					      dly_coarse_0p5t, *dly_fine_xt);
+			}
+
+			if (pass_begin[dqs] == 1)
+				pass_count_1[dqs]++;
+
+			if ((pass_begin[dqs] == 1) &&
+			    (pass_count_1[dqs] * DQS_GW_FINE_STEP > 32))
+				dqs_high[dqs] = 0;
+
+			if ((pass_count_1[0] * DQS_GW_FINE_STEP > 32) &&
+			    (pass_count_1[1] * DQS_GW_FINE_STEP > 32)) {
+				dramc_dbg("All bytes gating window > 1 "
+					"coarse_tune, Early break\n");
+				*dly_fine_xt = 32;
+				*coarse_tune = coarse_end;
+			}
+		}
+	}
+}
+
+static void find_dly_tune(u8 chn, u8 dly_coarse_large, u8 dly_coarse_0p5t,
+	u8 dly_fine_xt, u8 *dqs_cnt1, u8 *dqs_cnt2, u8 *dqs_high,
+	u8 *dly_coarse_large_cnt, u8 *dly_coarse_0p5t_cnt,
+	u8 *dly_fine_tune_cnt, u8 *dqs_transition)
+{
+	for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		if (dqs == 0) {
+			dqs_cnt1[0] =
+				(read32(&ch[chn].phy_nao.misc_phy_stben_b0)
+				>> 16) & 1;
+			dqs_cnt2[0] =
+				(read32(&ch[chn].phy_nao.misc_phy_stben_b0)
+				>> 17) & 1;
+		} else {
+			dqs_cnt1[1] =
+				(read32(&ch[chn].phy_nao.misc_phy_stben_b1)
+				>> 16) & 1;
+			dqs_cnt2[1] =
+				(read32(&ch[chn].phy_nao.misc_phy_stben_b1)
+				>> 17) & 1;
+		}
+
+		if ((dqs_cnt1[dqs] == 1) && (dqs_cnt2[dqs] == 1))
+			dqs_high[dqs]++;
+
+		if (dqs_high[dqs] * DQS_GW_FINE_STEP <= 16)
+			continue;
+
+		if ((dqs_cnt1[dqs] == 1) && (dqs_cnt2[dqs] == 1)) {
+			dly_coarse_large_cnt[dqs] = dly_coarse_large;
+			dly_coarse_0p5t_cnt[dqs] = dly_coarse_0p5t;
+			dly_fine_tune_cnt[dqs] = dly_fine_xt;
+			dqs_transition[dqs] = 1;
+		} else if (((dqs_cnt1[dqs] == 1) && (dqs_cnt2[dqs] == 0)) ||
+			((dqs_cnt1[dqs] == 0) && (dqs_cnt2[dqs] == 1))) {
+			if (dqs_transition[dqs] == 1)
+				dramc_dbg("[Byte %d] cnt1/cnt2 falling Transition"
+					" (%d, %d, %d)\n",
+					dqs, dly_coarse_large_cnt[dqs],
+					dly_coarse_0p5t_cnt[dqs],
+					dly_fine_tune_cnt[dqs]);
+
+			dqs_transition[dqs]++;
+		} else if ((dqs_cnt1[dqs] == 0) && (dqs_cnt2[dqs] == 0)) {
+			dramc_dbg("[Byte %d] cnt1/cnt2 Transition tap number (%d)\n",
+				dqs, dqs_transition[dqs]);
+			dqs_high[dqs] = 0;
+		}
+	}
+}
+
+static void dramc_rx_dqs_gating_cal(u8 chn, u8 rank)
+{
+	u8 pass_begin[DQS_NUMBER], pass_count[DQS_NUMBER];
+	u8 min_coarse_tune2t[DQS_NUMBER], min_coarse_tune0p5t[DQS_NUMBER],
+		min_fine_tune[DQS_NUMBER];
+	u8 best_fine_tune[DQS_NUMBER], best_coarse_tune0p5t[DQS_NUMBER],
+		best_coarse_tune2t[DQS_NUMBER];
+	u8 best_fine_tune_p1[DQS_NUMBER], best_coarse_tune0p5t_p1[DQS_NUMBER],
+		best_coarse_tune2t_p1[DQS_NUMBER];
+
+	u8 best_coarse_large_rodt[DQS_NUMBER],
+		best_coarse_0p5t_rodt[DQS_NUMBER];
+	u8 best_coarse_large_rodt_p1[DQS_NUMBER],
+		best_coarse_0p5t_rodt_p1[DQS_NUMBER];
+	u32 coarse_start = 8, coarse_end = 8;
+	u32 debug_cnt[DQS_NUMBER];
+
+	u8 dqs_cnt1[DQS_NUMBER], dqs_cnt2[DQS_NUMBER],
+		dqs_high[DQS_NUMBER], dqs_transition[DQS_NUMBER];
+	u8 dly_coarse_large_cnt[DQS_NUMBER],
+		dly_coarse_0p5t_cnt[DQS_NUMBER],
+		dly_fine_tune_cnt[DQS_NUMBER];
+	u8 dqs;
+	u8 mr1_value[FSP_MAX] = { 0x56, 0x56 };
+
+	u32 *u4RegBackup[] = {
+		&ch[chn].ao.stbcal,
+		&ch[chn].ao.stbcal1,
+		&ch[chn].ao.ddrconf0,
+		&ch[chn].ao.spcmd,
+		&ch[chn].ao.refctrl0,
+		&ch[chn].phy.b[0].dq[6],
+		&ch[chn].phy.b[1].dq[6],
+	};
+
+	save_restore_multi_reg(SAVE_VALUE,
+		u4RegBackup, ARRAY_SIZE(u4RegBackup));
+
+	rx_dqs_isi_pulse_cg_dis(chn);
+	dramc_mode_reg_write_by_rank(chn, rank, 0x1, mr1_value[1] | 0x80);
+
+	clrbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_PBREFEN_SHIFT);
+
+	dramc_hw_gating_onoff(chn, GATING_OFF);
+
+	setbits_le32(&ch[chn].ao.stbcal1, 1 << STBCAL1_STBENCMPEN_SHIFT);
+	setbits_le32(&ch[chn].ao.stbcal1, 1 << STBCAL1_STBCNT_LATCH_EN_SHIFT);
+	clrbits_le32(&ch[chn].ao.ddrconf0, 1 << DDRCONF0_DM4TO1MODE_SHIFT);
+	setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_DQSGCNTEN_SHIFT);
+
+	udelay(4);
+
+	setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_DQSGCNTRST_SHIFT);
+	udelay(1);
+	clrbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_DQSGCNTRST_SHIFT);
+
+	clrsetbits_le32(&ch[chn].phy.misc_ctrl1,
+		1 << MISC_CTRL1_R_DMSTBENCMP_RK_OPT_SHIFT,
+		rank << MISC_CTRL1_R_DMSTBENCMP_RK_OPT_SHIFT);
+	dramc_engine2_init(chn, rank,
+		DEFAULT_TEST2_1_CAL, 0xaa000000 | GATING_PATTERN_NUM,
+		TEST_AUDIO_PATTERN, 0);
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		pass_begin[dqs] = 0;
+		pass_count[dqs] = 0;
+		dqs_cnt1[dqs] = 0;
+		dqs_cnt2[dqs] = 0;
+		dqs_high[dqs] = 0;
+		dqs_transition[dqs] = 0;
+
+		dly_coarse_large_cnt[dqs] = 0;
+		dly_coarse_0p5t_cnt[dqs] = 0;
+		dly_fine_tune_cnt[dqs] = 0;
+	}
+
+	dramc_show("[Gating]\n");
+
+	coarse_start = 18;
+	coarse_end = coarse_start + 24;
+
+	for (u32 coarse_tune = coarse_start; coarse_tune < coarse_end;
+	     coarse_tune += DQS_GW_COARSE_STEP) {
+		u32 dly_coarse_large_rodt = 0;
+		u32 dly_coarse_0p5t_rodt = 0;
+		u32 dly_coarse_large_rodt_p1 = 4;
+		u32 dly_coarse_0p5t_rodt_p1 = 4;
+
+		u8 dly_coarse_large = coarse_tune / RX_DQS_CTL_LOOP;
+		u8 dly_coarse_0p5t = coarse_tune % RX_DQS_CTL_LOOP;
+
+		u32 dly_coarse_large_p1 =
+			(coarse_tune + DQS_GW_FREQ_DIV) / RX_DQS_CTL_LOOP;
+		u32 dly_coarse_0p5t_p1 =
+			(coarse_tune + DQS_GW_FREQ_DIV) % RX_DQS_CTL_LOOP;
+
+		u32 value = (dly_coarse_large << 3) + dly_coarse_0p5t;
+
+		if (value >= 11) {
+			value -= 11;
+			dly_coarse_large_rodt = value >> 3;
+			dly_coarse_0p5t_rodt =
+				value - (dly_coarse_large_rodt << 3);
+
+			value = (dly_coarse_large << 3) + dly_coarse_0p5t - 11;
+			dly_coarse_large_rodt_p1 = value >> 3;
+			dly_coarse_0p5t_rodt_p1 =
+				value - (dly_coarse_large_rodt_p1 << 3);
+		}
+
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0,
+			((u32) dly_coarse_large <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_SHIFT) |
+			((u32) dly_coarse_large <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_SHIFT) |
+			(dly_coarse_large_p1 <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT) |
+			(dly_coarse_large_p1 <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_P1_SHIFT));
+
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg1,
+			((u32) dly_coarse_0p5t <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_SHIFT) |
+			((u32) dly_coarse_0p5t <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_SHIFT) |
+			(dly_coarse_0p5t_p1 <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_P1_SHIFT) |
+			(dly_coarse_0p5t_p1 <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_P1_SHIFT));
+
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_odten0,
+			(dly_coarse_large_rodt <<
+			SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_SHIFT) |
+			(dly_coarse_large_rodt <<
+			SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_SHIFT) |
+			(dly_coarse_large_rodt_p1 <<
+			SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_P1_SHIFT) |
+			(dly_coarse_large_rodt_p1 <<
+			SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_P1_SHIFT));
+
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_odten1,
+			(dly_coarse_0p5t_rodt <<
+			SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_SHIFT) |
+			(dly_coarse_0p5t_rodt <<
+			SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_SHIFT) |
+			(dly_coarse_0p5t_rodt_p1 <<
+			SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_P1_SHIFT) |
+			(dly_coarse_0p5t_rodt_p1 <<
+			SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_P1_SHIFT));
+
+		for (u8 dly_fine_xt = DQS_GW_FINE_START;
+			dly_fine_xt < DQS_GW_FINE_END;
+			dly_fine_xt += DQS_GW_FINE_STEP) {
+
+			dramc_gating_mode(chn, 0);
+
+			write32(&ch[chn].ao.shu[0].rk[rank].dqsien,
+				dly_fine_xt | (dly_fine_xt << 8));
+
+			dram_phy_reset(chn);
+
+			setbits_le32(&ch[chn].ao.spcmd,
+				1 << SPCMD_DQSGCNTRST_SHIFT);
+			udelay(1);
+			clrbits_le32(&ch[chn].ao.spcmd,
+				1 << SPCMD_DQSGCNTRST_SHIFT);
+
+			dramc_engine2_run(chn,
+				TE_OP_READ_CHECK, TEST_AUDIO_PATTERN);
+
+			u32 result_r =
+			    read32(&ch[chn].phy.misc_stberr_rk0_r)
+				    & MISC_STBERR_RK_R_STBERR_RK_R_MASK;
+			u32 result_f =
+			    read32(&ch[chn].phy.misc_stberr_rk0_f)
+				    & MISC_STBERR_RK_F_STBERR_RK_F_MASK;
+			debug_cnt[0] = read32(&ch[chn].nao.dqsgnwcnt[0]);
+			debug_cnt[1] = (debug_cnt[0] >> 16) & 0xffff;
+			debug_cnt[0] &= 0xffff;
+
+			dramc_gating_mode(chn, 1);
+			dramc_engine2_run(chn,
+				TE_OP_READ_CHECK, TEST_AUDIO_PATTERN);
+
+			find_dly_tune(chn, dly_coarse_large, dly_coarse_0p5t,
+				dly_fine_xt, &dqs_cnt1[0], &dqs_cnt2[0],
+				&dqs_high[0], &dly_coarse_large_cnt[0],
+				&dly_coarse_0p5t_cnt[0],
+				&dly_fine_tune_cnt[0], &dqs_transition[0]);
+
+			dramc_show("%d %d %d |",
+				dly_coarse_large, dly_coarse_0p5t,
+				dly_fine_xt);
+
+			for (dqs = 0; dqs < DQS_NUMBER; dqs++)
+				dramc_show("%X ", debug_cnt[dqs]);
+
+			dramc_show(" |");
+
+			for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+				dramc_show("(%X %X)",
+				(result_f >> (DQS_BIT_NUMBER * dqs)) & 0xff,
+				(result_r >> (DQS_BIT_NUMBER * dqs)) & 0xff);
+			}
+
+			dramc_show(" |");
+			for (dqs = 0; dqs < DQS_NUMBER; dqs++)
+				dramc_show("(%d %d)",
+					dqs_cnt1[dqs], dqs_cnt2[dqs]);
+
+			dramc_show("\n");
+
+
+			find_gating_window(result_r, result_f, &debug_cnt[0],
+				dly_coarse_large, dly_coarse_0p5t,
+				&pass_begin[0], &pass_count[0],
+				&dly_fine_xt, &coarse_tune, &dqs_high[0]);
+		}
+	}
+
+	dramc_engine2_end(chn);
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		pass_count[dqs] = dqs_transition[dqs];
+		min_fine_tune[dqs] = dly_fine_tune_cnt[dqs];
+		min_coarse_tune0p5t[dqs] = dly_coarse_0p5t_cnt[dqs];
+		min_coarse_tune2t[dqs] = dly_coarse_large_cnt[dqs];
+
+		u8 tmp_offset = pass_count[dqs] * DQS_GW_FINE_STEP / 2;
+		u8 tmp_value = min_fine_tune[dqs] + tmp_offset;
+		best_fine_tune[dqs] = tmp_value % RX_DLY_DQSIENSTB_LOOP;
+		best_fine_tune_p1[dqs] = best_fine_tune[dqs];
+
+		tmp_offset = tmp_value / RX_DLY_DQSIENSTB_LOOP;
+		tmp_value = min_coarse_tune0p5t[dqs] + tmp_offset;
+		best_coarse_tune0p5t[dqs] = tmp_value % RX_DQS_CTL_LOOP;
+
+		tmp_offset = tmp_value / RX_DQS_CTL_LOOP;
+		best_coarse_tune2t[dqs] =
+			min_coarse_tune2t[dqs] + tmp_offset;
+
+		tmp_value = best_coarse_tune0p5t[dqs] + DQS_GW_FREQ_DIV;
+		best_coarse_tune0p5t_p1[dqs] = tmp_value % RX_DQS_CTL_LOOP;
+
+		tmp_offset = tmp_value / RX_DQS_CTL_LOOP;
+		best_coarse_tune2t_p1[dqs] =
+			best_coarse_tune2t[dqs] + tmp_offset;
+	}
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++)
+		dramc_show("\nbest DQS%d dly(2T, 0.5T, fine tune)"
+			" = (%d, %d, %d)\n",
+			dqs, best_coarse_tune2t[dqs],
+			best_coarse_tune0p5t[dqs], best_fine_tune[dqs]);
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++)
+		dramc_show("\nbest DQS%d best coarse dly"
+			"(2T, 0.5T, fine tune) = (%d, %d, %d)\n",
+			dqs, best_coarse_tune2t_p1[dqs],
+			best_coarse_tune0p5t_p1[dqs],
+			best_fine_tune[dqs]);
+
+	save_restore_multi_reg(RESTORE_VALUE,
+		u4RegBackup, ARRAY_SIZE(u4RegBackup));
+
+	dramc_mode_reg_write_by_rank(chn, rank, 0x1, mr1_value[1] & 0x7f);
+
+	rx_dqs_isi_pulse_cg_en(chn);
+
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0,
+		((u32) best_coarse_tune2t[0] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_SHIFT) |
+		((u32) best_coarse_tune2t[1] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_SHIFT) |
+		((u32) best_coarse_tune2t_p1[0] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT) |
+		((u32) best_coarse_tune2t_p1[1] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_P1_SHIFT));
+
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg1,
+		((u32) best_coarse_tune0p5t[0] <<
+		SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_SHIFT) |
+		((u32) best_coarse_tune0p5t[1] <<
+		SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_SHIFT) |
+		((u32) best_coarse_tune0p5t_p1[0] <<
+		SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_P1_SHIFT) |
+		((u32) best_coarse_tune0p5t_p1[1] <<
+		   SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_P1_SHIFT));
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		u8 tmp_value = (best_coarse_tune2t[dqs] << 3)
+			+ best_coarse_tune0p5t[dqs];
+
+		if (tmp_value >= 11) {
+			tmp_value -= 11;
+			best_coarse_large_rodt[dqs] = tmp_value >> 3;
+			best_coarse_0p5t_rodt[dqs] =
+			    tmp_value - (best_coarse_large_rodt[dqs] << 3);
+
+			tmp_value = (best_coarse_tune2t_p1[dqs] << 3) +
+				best_coarse_tune0p5t_p1[dqs] - 11;
+			best_coarse_large_rodt_p1[dqs] = tmp_value >> 3;
+			best_coarse_0p5t_rodt_p1[dqs] =
+			    tmp_value - (best_coarse_large_rodt_p1[dqs] << 3);
+
+			dramc_dbg("\nbest RODT dly(2T, 0.5T) = (%d, %d)\n",
+				      best_coarse_large_rodt[dqs],
+				      best_coarse_0p5t_rodt[dqs]);
+		} else {
+
+			best_coarse_large_rodt[dqs] = 0;
+			best_coarse_0p5t_rodt[dqs] = 0;
+
+			best_coarse_large_rodt_p1[dqs] = 4;
+			best_coarse_0p5t_rodt_p1[dqs] = 4;
+
+			dramc_dbg
+			    ("[RxdqsGatingCal] Error: best_coarse_tune2t[%d]"
+			    " is already 0. RODT cannot be -1 coarse tune\n",
+			     dqs);
+		}
+	}
+
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_odten0,
+		((u32) best_coarse_large_rodt[0] <<
+		SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_SHIFT) |
+		((u32) best_coarse_large_rodt[1] <<
+		SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_SHIFT) |
+		((u32) best_coarse_large_rodt_p1[0] <<
+		SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_P1_SHIFT) |
+		((u32) best_coarse_large_rodt_p1[1] <<
+		   SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_P1_SHIFT));
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_odten1,
+		((u32) best_coarse_0p5t_rodt[0] <<
+		SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_SHIFT) |
+		((u32) best_coarse_0p5t_rodt[1] <<
+		SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_SHIFT) |
+		((u32) best_coarse_0p5t_rodt_p1[0] <<
+		SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_P1_SHIFT) |
+		((u32) best_coarse_0p5t_rodt_p1[1] <<
+		SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_P1_SHIFT));
+
+	write32(&ch[chn].ao.shu[0].rk[rank].dqsien,
+			best_fine_tune[0] | (best_fine_tune[1] << 8));
+
+	dram_phy_reset(chn);
+	dramc_dbg("[dramc_rx_dqs_gating_cal] Done\n\n");
+}
+
+static void dramc_rx_dqs_gating_post_process(u8 chn)
+{
+	u8 dqs, rank_rx_dvs, dbi_r_on = 0;
+	u8 rank, rank_max, rank_cur = 0;
+	s8 change_dqsinctl;
+	u32 read_dqsinctl, read_rodt;
+	u32 rankinctl_root, xrtr2r, reg_tx_dly_dqsgated_min = 0;
+	u8 txdly_cal_min = 0xff, txdly_cal_max = 0, tx_dly_dqs_gated = 0;
+	u32 best_coarse_tune2t[RANK_MAX][DQS_NUMBER];
+	u32 best_coarse_tune2t_p1[RANK_MAX][DQS_NUMBER];
+
+	reg_tx_dly_dqsgated_min = 3;
+	rank_rx_dvs = reg_tx_dly_dqsgated_min - 1;
+
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[7],
+		SHU1_B0_DQ7_R_DMRANKRXDVS_B0_MASK,
+		rank_rx_dvs << SHU1_B0_DQ7_R_DMRANKRXDVS_B0_SHIFT);
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[7],
+		SHU1_B1_DQ7_R_DMRANKRXDVS_B1_MASK,
+		rank_rx_dvs << SHU1_B1_DQ7_R_DMRANKRXDVS_B1_SHIFT);
+
+	if (((read32(&ch[chn].ao.rstmask)>>
+		 RSTMASK_RSV_DRAM_SUPPORT_RANK_NUM_SHIFT) & 1) == 0)
+		rank_max = RANK_MAX;
+	else
+		rank_max = RANK_1;
+
+	for (rank = 0; rank < rank_max; rank++) {
+		for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+			best_coarse_tune2t[rank][dqs] =
+			   (read32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0) >>
+			   (dqs * 8)) &
+			    SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_MASK;
+			best_coarse_tune2t_p1[rank][dqs] =
+			    ((read32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0)
+				>> (dqs * 8)) &
+			    SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_MASK) >>
+			    SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT;
+			dramc_dbg("\nrank%d best DQS%d dly(2T, (P1)2T) = (%d, %d)\n",
+			      (u32) rank, (u32) dqs,
+			      (u32) best_coarse_tune2t[rank][dqs],
+			      (u32) best_coarse_tune2t_p1[rank][dqs]);
+
+			tx_dly_dqs_gated = best_coarse_tune2t[rank][dqs];
+			if (tx_dly_dqs_gated < txdly_cal_min)
+				txdly_cal_min = tx_dly_dqs_gated;
+
+			tx_dly_dqs_gated = best_coarse_tune2t_p1[rank][dqs];
+			if (tx_dly_dqs_gated > txdly_cal_max)
+				txdly_cal_max = tx_dly_dqs_gated;
+		}
+	}
+
+	change_dqsinctl = reg_tx_dly_dqsgated_min - txdly_cal_min;
+
+	dramc_dbg
+	    ("ChangeDQSINCTL %d, tx_dly_dqsgated_min %d, txdly_cal_min %d\n",
+	     change_dqsinctl, reg_tx_dly_dqsgated_min, txdly_cal_min);
+
+	if (change_dqsinctl != 0) {
+		txdly_cal_min += change_dqsinctl;
+		txdly_cal_max += change_dqsinctl;
+
+		for (rank = 0; rank < rank_max; rank++) {
+			dramc_dbg("Rank: %d\n", rank);
+
+		for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+			best_coarse_tune2t[rank][dqs] += change_dqsinctl;
+			best_coarse_tune2t_p1[rank][dqs] += change_dqsinctl;
+
+			dramc_dbg("best DQS%d dly(2T) = (%d)\n", dqs,
+			      best_coarse_tune2t[rank][dqs]);
+		}
+
+			for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+				dramc_dbg("best DQS%d P1 dly(2T) = (%d)\n",
+					dqs,
+					best_coarse_tune2t_p1[rank][dqs]);
+			}
+		}
+
+		for (rank = 0; rank < rank_max; rank++) {
+			write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0,
+				(best_coarse_tune2t[rank][0] << 0) |
+				(best_coarse_tune2t[rank][1] << 8) |
+				(best_coarse_tune2t_p1[rank][0] << 4) |
+				(best_coarse_tune2t_p1[rank][1] << 12));
+		}
+	}
+
+	read_dqsinctl = read32(&ch[chn].ao.shu[0].rk[rank_cur].dqsctl) &
+				SHURK_DQSCTL_DQSINCTL_MASK;
+	read_dqsinctl -= change_dqsinctl;
+
+	if (dbi_r_on) {
+		read_dqsinctl++;
+		read_rodt =
+		    (read32(&ch[chn].ao.shu[0].odtctrl) &
+		    SHU_ODTCTRL_RODT_MASK) >> SHU_ODTCTRL_RODT_SHIFT;
+		clrsetbits_le32(&ch[chn].ao.shu[0].odtctrl,
+			SHU_ODTCTRL_RODT_MASK,
+			(read_rodt + 1) << SHU_ODTCTRL_RODT_SHIFT);
+	}
+
+	if (read_dqsinctl >= 3) {
+		rankinctl_root = read_dqsinctl - 3;
+	} else {
+		rankinctl_root = 0;
+		dramc_dbg("DQSINCTL < 3, Risk for supporting 1066/RL8\n");
+	}
+
+	clrsetbits_le32(&ch[chn].ao.shu[0].rk[0].dqsctl,
+		SHURK_DQSCTL_DQSINCTL_MASK,
+		read_dqsinctl << SHURK_DQSCTL_DQSINCTL_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.shu[0].rk[1].dqsctl,
+		SHURK_DQSCTL_DQSINCTL_MASK,
+		read_dqsinctl << SHURK_DQSCTL_DQSINCTL_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.shu[0].rankctl,
+		SHU_RANKCTL_RANKINCTL_PHY_MASK,
+		read_dqsinctl << SHU_RANKCTL_RANKINCTL_PHY_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.shu[0].rankctl,
+		SHU_RANKCTL_RANKINCTL_MASK,
+		rankinctl_root << SHU_RANKCTL_RANKINCTL_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.shu[0].rankctl,
+		SHU_RANKCTL_RANKINCTL_ROOT1_MASK,
+		rankinctl_root << SHU_RANKCTL_RANKINCTL_ROOT1_SHIFT);
+
+	xrtr2r = 8 + txdly_cal_max + 1;
+	if (xrtr2r > 12) {
+		xrtr2r = 12;
+		dramc_dbg("XRTR2R > 12, Max value is 12\n");
+	}
+
+	clrsetbits_le32(&ch[chn].ao.shu[0].actim_xrt,
+		SHU_ACTIM_XRT_XRTR2R_MASK,
+		xrtr2r << SHU_ACTIM_XRT_XRTR2R_SHIFT);
+
+	dramc_dbg("TX_dly_DQSgated check: min %d max %d, ChangeDQSINCTL=%d\n",
+			txdly_cal_min, txdly_cal_max, change_dqsinctl);
+	dramc_dbg("DQSINCTL=%d, RANKINCTL=%d, XRTR2R=%d\n",
+		read_dqsinctl, rankinctl_root, xrtr2r);
+}
+
+static void dramc_rd_dqc_init(u8 chn, u8 rank)
+{
+	u8 *lpddr_phy_mapping;
+	u16 temp_value = 0;
+	u8 mr15_golden_value = 0;
+	u8 mr20_golden_value = 0;
+	int i;
+	const u8 LPDDR4_PHY_Mapping_POP[CHANNEL_NUM][16] = {
+		/* CHA */
+		{
+			1, 0, 2, 4, 3, 7, 5, 6,
+			9, 8, 12, 11, 10, 15, 13, 14
+		},
+		/* CHB */
+		{
+			0, 1, 5, 6, 3, 7, 4, 2,
+			9, 8, 12, 15, 11, 14, 13, 10
+		}
+	};
+
+	clrbits_le32(&ch[chn].phy.shu[0].b[0].dq[7],
+	     0x1 << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT);
+	clrbits_le32(&ch[chn].phy.shu[0].b[1].dq[7],
+	     0x1 << SHU1_B1_DQ7_R_DMDQMDBI_SHU_B1_SHIFT);
+
+	if(rank == RANK_0)
+		clrsetbits_le32(&ch[chn].ao.mrs,
+			MRS_MRSRK_MASK, 0 << MRS_MRSRK_SHIFT);
+	else
+		clrsetbits_le32(&ch[chn].ao.mrs,
+			MRS_MRSRK_MASK, 1 << MRS_MRSRK_SHIFT);
+	setbits_le32(&ch[chn].ao.mpc_option,
+		(0x1 << MPC_OPTION_MPCRKEN_SHIFT));
+
+	lpddr_phy_mapping = (u8 *)LPDDR4_PHY_Mapping_POP[chn];
+	for (i = 0; i < 16; i++)
+		temp_value |= ((0x5555 >> i) & 0x1) << lpddr_phy_mapping[i];
+
+	mr15_golden_value = (u8) temp_value & 0xff;
+	mr20_golden_value = (u8) (temp_value >> 8) & 0xff;
+
+	clrsetbits_le32(&ch[chn].ao.mr_golden,
+		MR_GOLDEN_MR15_GOLDEN_MASK | MR_GOLDEN_MR20_GOLDEN_MASK,
+		mr15_golden_value << 8 | mr20_golden_value);
+}
+
+static u32 dramc_rd_dqc_run(u8 chn)
+{
+	u16 timeout_cnt = 100;
+	u8 response;
+	u32 result;
+
+	setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_RDDQCEN_SHIFT);
+	setbits_le32(&ch[chn].ao.spcmdctrl, 1 << SPCMDCTRL_RDDQCDIS_SHIFT);
+
+	do {
+		response =
+		    read32(&ch[chn].nao.spcmdresp)
+				& (0x1 << SPCMDRESP_RDDQC_RESPONSE_SHIFT);
+		timeout_cnt--;
+		udelay(1);
+	} while ((response == 0) && (timeout_cnt > 0));
+
+	if (timeout_cnt == 0)
+		dramc_dbg("[RxWinRDDQC] Resp fail (time out)\n");
+
+	result = read32(&ch[chn].nao.rdqc_cmp);
+	clrbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_RDDQCEN_SHIFT);
+	clrbits_le32(&ch[chn].ao.spcmdctrl, 1 << SPCMDCTRL_RDDQCDIS_SHIFT);
+
+	return result;
+}
+
+static void dramc_rd_dqc_end(u8 chn)
+{
+	clrsetbits_le32(&ch[chn].ao.mrs, MRS_MRSRK_MASK, 0 << MRS_MRSRK_SHIFT);
+}
+
+static void dramc_vref_enable(u8 chn)
+{
+	setbits_le32(&ch[chn].phy.b[0].dq[5],
+		0x1 << B0_DQ5_RG_RX_ARDQ_VREF_EN_B0_SHIFT);
+	setbits_le32(&ch[chn].phy.b[1].dq[5],
+		0x1 << B1_DQ5_RG_RX_ARDQ_VREF_EN_B1_SHIFT);
+}
+
+static void dramc_set_rx_vref(u8 chn, u8 value)
+{
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[5],
+		SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_MASK,
+		value << SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_SHIFT);
+	clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[5],
+		SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_MASK,
+		value << SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_SHIFT);
+}
+
+static void dramc_set_tx_vref(u8 chn, u8 rank, u16 value)
+{
+	dramc_mode_reg_write_by_rank(chn, rank, 14, value | 0 << 6);
+}
+
+static void set_rx_dly_factor(u8 chn, u8 rank, u8 type, u32 val)
+{
+	u8 i;
+	u32 value;
+	u32 mask;
+
+	switch (type) {
+	case RX_DQ:
+		value = (val << 24 | val << 16 | val << 8 | val);
+		for (i = 2; i < 6; i++) {
+			write32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[i],
+				value);
+			write32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[i],
+				value);
+		}
+		break;
+
+	case RX_DQM:
+		value = (val << 8 | val);
+		mask = SHU1_B0_DQ6_RK_RX_ARDQM0_F_DLY_B0_MASK |
+		    SHU1_B0_DQ6_RK_RX_ARDQM0_R_DLY_B0_MASK;
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[6],
+			mask, value);
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[6],
+			mask, value);
+		break;
+
+	case RX_DQS:
+		value = (val << 24 | val << 16);
+		mask = SHU1_B0_DQ6_RK_RX_ARDQS0_F_DLY_B0_MASK |
+			SHU1_B0_DQ6_RK_RX_ARDQS0_R_DLY_B0_MASK;
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[6],
+			mask, value);
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[6],
+			mask, value);
+
+	}
+}
+
+static void dramc_transfer_dly_tune(u8 chn, u32 dly,
+		struct tx_dly_coarse_fine_tune *dly_tune)
+{
+	u16 tmp_val;
+
+	dly_tune->fine_tune = dly & (TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP - 1);
+
+	tmp_val = (dly / TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP) << 1;
+	dly_tune->coarse_tune_small = tmp_val - ((tmp_val >> 3) << 3);
+	dly_tune->coarse_tune_large = tmp_val >> 3;
+
+	tmp_val -= 4;
+	dly_tune->coarse_tune_small_oen = tmp_val - ((tmp_val >> 3) << 3);
+	dly_tune->coarse_tune_large_oen = tmp_val >> 3;
+}
+
+static void set_tx_dly_factor(u32 chn, u8 rank, u8 type, u32 curr_val)
+{
+	u8 i;
+	struct tx_dly_coarse_fine_tune dly_tune = { };
+	u32 coarse_tune_large = 0;
+	u32 coarse_tune_large_oen = 0;
+	u32 coarse_tune_small = 0;
+	u32 coarse_tune_small_oen = 0;
+
+	dramc_transfer_dly_tune(chn, curr_val, &dly_tune);
+
+	for (i = 0; i < 4; i++) {
+		coarse_tune_large += dly_tune.coarse_tune_large << (i * 4);
+		coarse_tune_large_oen +=
+			dly_tune.coarse_tune_large_oen << (i * 4);
+		coarse_tune_small += dly_tune.coarse_tune_small << (i * 4);
+		coarse_tune_small_oen +=
+			dly_tune.coarse_tune_small_oen << (i * 4);
+	}
+	if (type == TX_DQM)
+		dramc_dbg("%3d |%d  %d  %2d | [0]", curr_val,
+		dly_tune.coarse_tune_large,
+		dly_tune.coarse_tune_small, dly_tune.fine_tune);
+
+	switch (type) {
+	case TX_DQM:
+		/* large coarse_tune setting */
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[0],
+			(coarse_tune_large_oen << 16) | coarse_tune_large);
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[2],
+			(coarse_tune_small_oen << 16) | coarse_tune_small);
+
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[1],
+			(coarse_tune_large_oen << 16) | coarse_tune_large);
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[3],
+			(coarse_tune_small_oen << 16) | coarse_tune_small);
+
+		/* fine_tune delay setting */
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7],
+			SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK,
+			dly_tune.fine_tune << 8);
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7],
+			SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK,
+			dly_tune.fine_tune << 8);
+
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7],
+			SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK,
+			dly_tune.fine_tune << 16);
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7],
+			SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK,
+			dly_tune.fine_tune << 16);
+		break;
+
+	case TX_DQ:
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[0],
+			(coarse_tune_large_oen << 16) | coarse_tune_large);
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[2],
+			(coarse_tune_small_oen << 16) | coarse_tune_small);
+
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7],
+			SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK,
+			dly_tune.fine_tune << 8);
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7],
+			SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK,
+			dly_tune.fine_tune << 8);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void set_dly_factor(u8 chn, u8 rank, u8 type, u32 dly)
+{
+	switch (type) {
+	case TX_WIN_MOVE_DQ_ONLY:
+		set_tx_dly_factor(chn, rank, TX_DQ, dly);
+		break;
+
+	case TX_WIN_MOVE_DQ_DQM:
+		set_tx_dly_factor(chn, rank, TX_DQM, dly);
+		break;
+
+	default:
+		dramc_dbg("%s Invalid type\n", __func__);
+		break;
+	}
+}
+
+static void dramc_engine2_setpat(u8 chn, u8 testaudpat,
+	u8 log2loopcount, u8 Use_Len1_Flag)
+{
+	if (testaudpat == TEST_XTALK_PATTERN) {
+		if (Use_Len1_Flag != 0)
+			setbits_le32(&ch[chn].ao.test2_4,
+				0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT);
+		else
+			clrbits_le32(&ch[chn].ao.test2_4,
+				0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT);
+		setbits_le32(&ch[chn].ao.perfctl0, 1 << PERFCTL0_RWOFOEN_SHIFT);
+
+		clrsetbits_le32(&ch[chn].ao.test2_3,
+			0x1 << TEST2_3_TESTAUDPAT_SHIFT | TEST2_3_TESTCNT_MASK,
+			log2loopcount << 0);
+
+		clrsetbits_le32(&ch[chn].ao.test2_4,
+			0x1 << TEST2_4_TESTXTALKPAT_SHIFT |
+			0x1 << TEST2_4_TESTAUDMODE_SHIFT |
+			0x1 << TEST2_4_TESTAUDBITINV_SHIFT,
+			0x1 << TEST2_4_TESTXTALKPAT_SHIFT);
+
+		clrbits_le32(&ch[chn].ao.test2_4,
+			1 << TEST2_4_TESTSSOPAT_SHIFT |
+			0x1 << TEST2_4_TESTSSOXTALKPAT_SHIFT);
+	} else if (testaudpat == TEST_AUDIO_PATTERN)   {
+		clrsetbits_le32(&ch[chn].ao.test2_4,
+			TEST2_4_TESTAUDINIT_MASK |
+			TEST2_4_TESTAUDINC_MASK |
+			(0x1 << TEST2_4_TESTXTALKPAT_SHIFT) |
+			(0x1 << TEST2_4_TESTAUDMODE_SHIFT) |
+			(0x1 << TEST2_4_TESTAUDBITINV_SHIFT),
+			(0x11 << 8) | (0xd << 0) | (0x1 << 14));
+
+		clrsetbits_le32(&ch[chn].ao.test2_3,
+			0x1 << TEST2_3_TESTAUDPAT_SHIFT | TEST2_3_TESTCNT_MASK,
+			0x1 << TEST2_3_TESTAUDPAT_SHIFT | log2loopcount << 0);
+	} else {
+		clrsetbits_le32(&ch[chn].ao.test2_3,
+			0x1 << TEST2_3_TESTAUDPAT_SHIFT | TEST2_3_TESTCNT_MASK,
+			log2loopcount << 0);
+		clrbits_le32(&ch[chn].ao.test2_4,
+			0x1 << TEST2_4_TESTXTALKPAT_SHIFT);
+		}
+}
+
+static u32 dram_k_perbit(u8 chn, u8 engine_type)
+{
+	u32 err_value = 0x0;
+
+	if (engine_type) {
+		dramc_engine2_setpat(chn, TEST_AUDIO_PATTERN, 0, 0);
+		err_value = dramc_engine2_run(chn,
+			TE_OP_WRITE_READ_CHECK, TEST_AUDIO_PATTERN);
+		dramc_engine2_setpat(chn, TEST_XTALK_PATTERN, 0, 0);
+		err_value |= dramc_engine2_run(chn,
+			TE_OP_WRITE_READ_CHECK, TEST_XTALK_PATTERN);
+	} else
+		err_value = dramc_rd_dqc_run(chn);
+	return err_value;
+}
+
+static void dramc_check_dq_win(struct dqs_perbit_dly *p,
+		s16 dly_step, s16 last_step, u32 fail_bit)
+{
+	s16 dqdly_pass_win, best_pass_win;
+
+	if (fail_bit == 0) {
+		if (p->first_dqdly_pass == -1) {
+			/* first DQ pass delay tap */
+			p->first_dqdly_pass = dly_step;
+		}
+
+		if ((p->last_dqdly_pass == -2) && (dly_step == last_step)) {
+			/* pass to the last tap */
+			p->last_dqdly_pass = dly_step;
+			dqdly_pass_win =
+				p->last_dqdly_pass - p->first_dqdly_pass;
+			best_pass_win =
+				p->best_last_dqdly_pass
+				- p->best_first_dqdly_pass;
+			if (dqdly_pass_win > best_pass_win) {
+				p->best_last_dqdly_pass = p->last_dqdly_pass;
+				p->best_first_dqdly_pass = p->first_dqdly_pass;
+			}
+			/* clear to find the next pass range if it has */
+			p->first_dqdly_pass = -1;
+			p->last_dqdly_pass = -2;
+		}
+	} else {
+		if ((p->first_dqdly_pass != -1)
+			&& (p->last_dqdly_pass == -2)) {
+			p->last_dqdly_pass = dly_step - 1;
+			dqdly_pass_win =
+				p->last_dqdly_pass - p->first_dqdly_pass;
+			best_pass_win =
+				p->best_last_dqdly_pass
+				- p->best_first_dqdly_pass;
+			if (dqdly_pass_win > best_pass_win) {
+				p->best_last_dqdly_pass = p->last_dqdly_pass;
+				p->best_first_dqdly_pass = p->first_dqdly_pass;
+			}
+			/* clear to find the next pass range if it has */
+			p->first_dqdly_pass = -1;
+			p->last_dqdly_pass = -2;
+		}
+	}
+}
+
+static int dramk_calcu_best_vref(u8 cal_type,
+	struct dqs_perbit_dly vref_dly[], struct dqs_perbit_dly delay[],
+	u32 min_win_size, u32 max_win_sum)
+{
+	u8 bit;
+	u32 win_size;
+	u32 win_size_sum = 0;
+	static u32 min_win_size_vref;
+
+	if (cal_type == (RX_WIN | (1 << 1))) {
+		for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+			win_size_sum +=
+			    (delay[bit].best_last_dqdly_pass -
+			    delay[bit].best_first_dqdly_pass + 1);
+			win_size_sum +=
+			    (delay[bit].best_last_dqsdly_pass -
+			    delay[bit].best_first_dqsdly_pass + 1);
+		}
+		if (win_size_sum > max_win_sum) {
+			max_win_sum = win_size_sum;
+			for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+				vref_dly[bit].vref = delay[bit].vref;
+				vref_dly[bit].best_dqdly =
+					delay[bit].best_dqdly;
+				vref_dly[bit].best_first_dqdly_pass =
+				    delay[bit].best_first_dqdly_pass;
+				vref_dly[bit].best_last_dqdly_pass =
+				    delay[bit].best_last_dqdly_pass;
+				vref_dly[bit].best_first_dqsdly_pass =
+				    delay[bit].best_first_dqsdly_pass;
+				vref_dly[bit].best_last_dqsdly_pass =
+				    delay[bit].best_last_dqsdly_pass;
+			}
+		}
+		if (win_size_sum < (max_win_sum * 95 / 100))
+			return 1;
+	} else if (cal_type == TX_DQ_DQS_MOVE_DQ_ONLY) {
+		for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+			win_size =
+			    (delay[bit].best_last_dqdly_pass -
+			    delay[bit].best_first_dqdly_pass + 1);
+			if (win_size < min_win_size)
+				min_win_size = win_size;
+			win_size_sum += win_size;
+		}
+
+		if ((win_size_sum > max_win_sum)
+		    && (min_win_size >= min_win_size_vref)) {
+			max_win_sum = win_size_sum;
+			min_win_size_vref = min_win_size;
+			for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+				vref_dly[bit].vref = delay[bit].vref;
+				vref_dly[bit].best_dqdly =
+					delay[bit].best_dqdly;
+				vref_dly[bit].best_first_dqdly_pass =
+				    delay[bit].best_first_dqdly_pass;
+				vref_dly[bit].best_last_dqdly_pass =
+				    delay[bit].best_last_dqdly_pass;
+			}
+		}
+
+	} else {
+		for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+			vref_dly[bit].vref = delay[bit].vref;
+			vref_dly[bit].best_dqdly = delay[bit].best_dqdly;
+			vref_dly[bit].best_first_dqdly_pass =
+				delay[bit].best_first_dqdly_pass;
+			vref_dly[bit].best_last_dqdly_pass =
+				delay[bit].best_last_dqdly_pass;
+			vref_dly[bit].best_first_dqsdly_pass =
+				delay[bit].best_first_dqsdly_pass;
+			vref_dly[bit].best_last_dqsdly_pass =
+				delay[bit].best_last_dqsdly_pass;
+		}
+	}
+	return 0;
+}
+
+static u8 dramc_calcu_best_dly(u8 bit,
+		struct dqs_perbit_dly *p, u32 *p_max_byte)
+{
+	u8 fail = 0;
+	u8 hold, setup;
+
+	hold = p->best_last_dqsdly_pass - p->best_first_dqsdly_pass + 1;
+	setup = p->best_last_dqdly_pass - p->best_first_dqdly_pass + 1;
+
+	if (hold > setup) {
+		p->best_dqdly = 0;
+		p->best_dqsdly = (setup != 0) ? (hold - setup) / 2 :
+		    (hold - setup) / 2 + p->best_first_dqsdly_pass;
+
+		if (p->best_dqsdly > *p_max_byte)
+			*p_max_byte = p->best_dqsdly;
+
+	} else if (hold < setup) {
+		p->best_dqsdly = 0;
+		p->best_dqdly = (hold != 0) ? (setup - hold) / 2 :
+		    (setup - hold) / 2 + p->best_first_dqdly_pass;
+
+	} else {		/* hold time == setup time */
+		p->best_dqsdly = 0;
+		p->best_dqdly = 0;
+
+		if (hold == 0) {
+			dramc_dbg("ERROR, error bit %d, "
+				"setup_time = hold_time = 0\n", bit);
+			fail = 1;
+		}
+	}
+
+	dramc_dbg("bit#%d : dq =%d dqs=%d win=%d (%d, %d)\n",
+		bit, setup, hold, setup + hold,
+		p->best_dqdly, p->best_dqsdly);
+
+	return fail;
+}
+
+static void dramc_calcu_tx_perbyte_dly(u8 bit,
+		struct dqs_perbit_dly *p, struct per_byte_dly *byte_delay_prop)
+{
+	s16 win_center;
+	win_center = (p->best_first_dqdly_pass + p->best_last_dqdly_pass) >> 1;
+
+	if (win_center < byte_delay_prop->min_center)
+		byte_delay_prop->min_center = win_center;
+	if (win_center > byte_delay_prop->max_center)
+		byte_delay_prop->max_center = win_center;
+}
+
+static void set_tx_best_dly_factor(u8 chn, u8 rank,
+			struct per_byte_dly *tx_perbyte_dly,
+			u16 dq_precal_result[])
+{
+	u8 i, rank_idx;
+	u32 coarse_tune_large = 0;
+	u32 coarse_tune_large_oen = 0;
+	u32 coarse_tune_small = 0;
+	u32 coarse_tune_small_oen = 0;
+	u16 dq_oen[DQS_NUMBER] = { }, dqm_oen[DQS_NUMBER] = { };
+	struct tx_dly_coarse_fine_tune perbyte_dqdly_tune[DQS_NUMBER] = { };
+	struct tx_dly_coarse_fine_tune perbyte_dqmdly_tune[DQS_NUMBER] = { };
+
+	for (i = 0; i < DQS_NUMBER; i++) {
+		dramc_transfer_dly_tune(chn, tx_perbyte_dly[i].final_dly,
+			&perbyte_dqdly_tune[i]);
+		dramc_transfer_dly_tune(chn, dq_precal_result[i],
+			&perbyte_dqmdly_tune[i]);
+
+		coarse_tune_large +=
+			perbyte_dqdly_tune[i].coarse_tune_large << (i * 4);
+		coarse_tune_large_oen +=
+			perbyte_dqdly_tune[i].coarse_tune_large_oen << (i * 4);
+		coarse_tune_small +=
+			perbyte_dqdly_tune[i].coarse_tune_small << (i * 4);
+		coarse_tune_small_oen +=
+			perbyte_dqdly_tune[i].coarse_tune_small_oen << (i * 4);
+		dq_oen[i] =
+		    (perbyte_dqdly_tune[i].coarse_tune_large_oen << 3) +
+		    (perbyte_dqdly_tune[i].coarse_tune_small_oen << 5) +
+		    perbyte_dqdly_tune[i].fine_tune;
+		dqm_oen[i] =
+		    (perbyte_dqmdly_tune[i].coarse_tune_large_oen << 3) +
+		    (perbyte_dqmdly_tune[i].coarse_tune_small_oen << 5) +
+		    perbyte_dqmdly_tune[i].fine_tune;
+	}
+
+	for (rank_idx = rank; rank_idx < RANK_MAX; rank_idx++) {
+		write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[0],
+			(coarse_tune_large_oen << 16) |
+			coarse_tune_large);
+		write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[2],
+			(coarse_tune_small_oen << 16) |
+			coarse_tune_small);
+
+		write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[1],
+			(coarse_tune_large_oen << 16) |
+			coarse_tune_large);
+		write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[3],
+			(coarse_tune_small_oen << 16) |
+			coarse_tune_small);
+	}
+
+	for (rank_idx = rank; rank_idx < RANK_MAX; rank_idx++) {
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank_idx].b[0].dq[7],
+			SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK |
+			SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK,
+			perbyte_dqdly_tune[0].fine_tune <<
+			SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_SHIFT |
+			perbyte_dqmdly_tune[0].fine_tune <<
+			SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_SHIFT);
+
+		clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank_idx].b[1].dq[7],
+			SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK |
+			SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK,
+			perbyte_dqdly_tune[1].fine_tune <<
+			SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_SHIFT |
+			perbyte_dqmdly_tune[1].fine_tune <<
+			SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_SHIFT);
+	}
+}
+
+static void set_rx_best_dly_factor(u8 chn, u8 rank,
+		struct dqs_perbit_dly *dqdqs_perbit_dly,
+		u32 *max_dqsdly_byte, u32 *ave_dqm_dly)
+{
+	u32 i, value = 0;
+	u8 index, byte;
+
+	for (i = 0; i < DQS_NUMBER; i++) {
+		value = (max_dqsdly_byte[i] << 24) |
+			(max_dqsdly_byte[i] << 16) |
+			(ave_dqm_dly[i] << 8) | (ave_dqm_dly[i] << 0);
+
+		/* Delay dqs/dqm */
+		write32(&ch[chn].phy.shu[0].rk[rank].b[i].dq[6], value);
+	}
+	dram_phy_reset(chn);
+
+	value = 0;
+	for (i = 0; i < DQ_DATA_WIDTH; i += 2) {
+		byte = i / DQS_BIT_NUMBER;
+		index = 2 + ((i % 8) * 2) / 4;
+		value =
+		    dqdqs_perbit_dly[i + 1].best_dqdly << 24 |
+		    dqdqs_perbit_dly[i + 1].best_dqdly << 16 |
+		    dqdqs_perbit_dly[i].best_dqdly << 8 |
+		    dqdqs_perbit_dly[i].best_dqdly;
+		write32(&ch[chn].phy.shu[0].rk[rank].b[byte].dq[index],
+				value);
+	}
+
+}
+
+static void dramc_get_vref_range(u8 cal_type, u8 enable,
+		u8 *begin, u8 *end, u8 *step)
+{
+	if (enable) {
+		if (cal_type == RX_WIN) {
+			*begin = RX_VREF_BEGIN;
+			*end = RX_VREF_END;
+			*step = RX_VREF_STEP;
+		} else if (cal_type == TX_WIN_MOVE_DQ_ONLY) {
+			*begin = TX_VREF_BEGIN;
+			*end = TX_VREF_END;
+			*step = TX_VREF_STEP;
+		}
+	} else {
+		*begin = 0;
+		*end = 1;
+		*step = 1;
+	}
+}
+
+static u32 dramc_get_smallest_dqs_dly(u8 chn, u8 rank)
+{
+	u32 dq_coarse_dly = 0;
+	u32 dq_fine_dly = 0;
+	u32 tmp_dly = 0;
+	u32 smallest_dqs_dly = 0xffff;
+	int i = 0;
+	const struct sdram_params *params = get_sdram_config();
+
+	for (i = 0; i < DQS_NUMBER; i++) {
+		dq_coarse_dly =
+			(read32(&ch[chn].ao.shu[0].selph_dqs0) >> (i << 2)) & 0x7;
+		dq_fine_dly =
+			(read32(&ch[chn].ao.shu[0].selph_dqs1) >> (i << 2)) & 0x7;
+
+		tmp_dly =
+			(((dq_coarse_dly << 3) + dq_fine_dly) << 5) + params->wr_level[chn][rank][i];
+		if (tmp_dly < smallest_dqs_dly)
+			smallest_dqs_dly = tmp_dly;
+	}
+
+	return smallest_dqs_dly;
+}
+static void dramc_get_dly_range(u8 chn, u8 rank,  u8 cal_type, u16 *pre_cal,
+		s16 *begin, s16 *end)
+{
+	u16 pre_dq_dly;
+
+	if (cal_type == TX_WIN_MOVE_DQ_DQM) {
+		*begin = dramc_get_smallest_dqs_dly(chn, rank);
+		*end = *begin + 256;
+	} else if (cal_type == TX_WIN_MOVE_DQ_ONLY) {
+		pre_dq_dly =
+			(pre_cal[0] > pre_cal[1]) ? pre_cal[1] : pre_cal[0];
+		if (pre_dq_dly > 24)
+			pre_dq_dly -= 24;
+		else
+			pre_dq_dly = 0;
+
+		*begin = pre_dq_dly;
+		*end = *begin + 64;
+	}
+}
+
+static void dramc_check_dqs_win(struct dqs_perbit_dly *p,
+		u8 dly_step, u8 last_step, u32 fail_bit)
+{
+	s8 dqsdly_pass_win, best_pass_win;
+
+	if (fail_bit == 0) {
+		if (p->first_dqsdly_pass == -1) {
+			/* first DQS pass delay tap */
+			p->first_dqsdly_pass = dly_step;
+		}
+		if ((p->last_dqsdly_pass == -2) && (dly_step == last_step)) {
+			/* pass to the last tap */
+			p->last_dqsdly_pass = dly_step;
+			dqsdly_pass_win = p->last_dqsdly_pass
+				- p->first_dqsdly_pass;
+			best_pass_win = p->best_last_dqsdly_pass
+				- p->best_first_dqsdly_pass;
+			if (dqsdly_pass_win > best_pass_win) {
+				p->best_last_dqsdly_pass =
+					p->last_dqsdly_pass;
+				p->best_first_dqsdly_pass =
+					p->first_dqsdly_pass;
+			}
+			/* clear to find the next pass range if it has */
+			p->first_dqsdly_pass = -1;
+			p->last_dqsdly_pass = -2;
+		}
+	} else {
+		if ((p->first_dqsdly_pass != -1)
+				&& (p->last_dqsdly_pass == -2)) {
+			p->last_dqsdly_pass = dly_step - 1;
+			dqsdly_pass_win = p->last_dqsdly_pass
+				- p->first_dqsdly_pass;
+			best_pass_win = p->best_last_dqsdly_pass
+				- p->best_first_dqsdly_pass;
+			if (dqsdly_pass_win > best_pass_win) {
+				p->best_last_dqsdly_pass
+					= p->last_dqsdly_pass;
+				p->best_first_dqsdly_pass
+					= p->first_dqsdly_pass;
+			}
+			/* clear to find the next pass range if it has */
+			p->first_dqsdly_pass = -1;
+			p->last_dqsdly_pass = -2;
+		}
+	}
+}
+
+static void dramc_set_dqdqs_dly(u8 chn, u8 rank, s32 dly)
+{
+	if (dly <= 0) {
+		/* Hold time calibration */
+		set_rx_dly_factor(chn, rank, RX_DQS, -dly);
+		dram_phy_reset(chn);
+	} else {
+		/* Setup time calibration */
+		set_rx_dly_factor(chn, rank, RX_DQS, 0);
+		set_rx_dly_factor(chn, rank, RX_DQM, dly);
+		dram_phy_reset(chn);
+		set_rx_dly_factor(chn, rank, RX_DQ, dly);
+	}
+}
+
+static u8 dramc_rx_window_perbit_cal(u8 chn, u8 cal_type,
+	u8 rank, u8 engine_type)
+{
+	u8 vref;
+	u8 vref_begin = 0, vref_end = 1, vref_step = 1;
+	u8 vref_scan_enable;
+	s8 fail = 0;
+	u8 i, bit, max_dq_taps;
+	u8 index, max_limit;
+	s16 dly;
+	u8 dly_step = 1;
+	u8 type = cal_type;
+	u32 err_value, fail_bit;
+	u32 min_win_size = 0xffff;
+	u32 max_win_size_sum = 0;
+	static u32 max_dqsdly_byte[DQS_NUMBER], ave_dqmdly_byte[DQS_NUMBER];
+	static struct dqs_perbit_dly vref_dq_perbit_dly[DQ_DATA_WIDTH];
+	struct dqs_perbit_dly dqdqs_perbit_dly[DQ_DATA_WIDTH];
+
+	if (engine_type && (rank == RANK_0)) {
+		vref_scan_enable = 1;
+		dramc_vref_enable(chn);
+	} else {
+		vref_scan_enable = 0;
+	}
+
+	dramc_dbg("%s [Rank %d] [Channel %d] Calibration Type:%d, engine:%d,vref_enable:%d\n",
+		__func__, rank, chn, type, engine_type, vref_scan_enable);
+
+	if (engine_type)
+		dramc_engine2_init(chn, rank, DEFAULT_TEST2_1_CAL,
+			DEFAULT_TEST2_2_CAL, TEST_XTALK_PATTERN, 0);
+	else
+		dramc_rd_dqc_init(chn, rank);
+
+	dramc_get_vref_range(type, vref_scan_enable,
+		&vref_begin, &vref_end, &vref_step);
+
+	/* if calibration data is allready stored in emmc,
+	 * Vref end need change */
+	for (vref = vref_begin; vref < vref_end; vref += vref_step) {
+		if (vref_scan_enable)
+			dramc_set_rx_vref(chn, vref);
+
+		for (i = 0; i < DQ_DATA_WIDTH; i++) {
+			dqdqs_perbit_dly[i].vref = vref;
+			dqdqs_perbit_dly[i].first_dqdly_pass = -1;
+			dqdqs_perbit_dly[i].last_dqdly_pass = -2;
+			dqdqs_perbit_dly[i].first_dqsdly_pass = -1;
+			dqdqs_perbit_dly[i].last_dqsdly_pass = -2;
+			dqdqs_perbit_dly[i].best_first_dqdly_pass = -1;
+			dqdqs_perbit_dly[i].best_last_dqdly_pass = -2;
+			dqdqs_perbit_dly[i].best_first_dqsdly_pass = -1;
+			dqdqs_perbit_dly[i].best_last_dqsdly_pass = -2;
+		}
+
+		set_rx_dly_factor(chn, rank, RX_DQM, FIRST_DQ_DELAY);
+		set_rx_dly_factor(chn, rank, RX_DQ, FIRST_DQ_DELAY);
+
+		max_dq_taps = MAX_RX_DQDLY_TAPS;
+		for (dly = FIRST_DQS_DELAY; dly < max_dq_taps;
+			dly += dly_step) {
+			dramc_set_dqdqs_dly(chn, rank, dly);
+			err_value = dram_k_perbit(chn, engine_type);
+			if (!vref_scan_enable)
+				dramc_dbg("delay %d ", dly);
+
+			for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+				fail_bit = err_value & ((u32) 1 << bit);
+				if (dly < 0) {
+					dramc_check_dqs_win(
+						&(dqdqs_perbit_dly[bit]),
+						-dly, -FIRST_DQS_DELAY,
+						fail_bit);
+				} else
+					dramc_check_dq_win(
+					&(dqdqs_perbit_dly[bit]),
+					dly, max_dq_taps, fail_bit);
+				if (!vref_scan_enable) {
+					if (fail_bit == 0)
+						dramc_dbg("o");
+					else
+						dramc_dbg("x");
+				}
+			}
+
+			if (!vref_scan_enable)
+				dramc_dbg(" [MSB]\n");
+		}
+		if (dramk_calcu_best_vref
+		    (type | (1 << engine_type), vref_dq_perbit_dly,
+		    dqdqs_perbit_dly, min_win_size, max_win_size_sum))
+			break;
+	}
+
+	if (engine_type)
+		dramc_engine2_end(chn);
+	else
+		dramc_rd_dqc_end(chn);
+
+	if (vref_scan_enable)
+		dramc_set_rx_vref(chn, vref_dq_perbit_dly[0].vref);
+	for (i = 0; i < DQS_NUMBER; i++) {
+		max_dqsdly_byte[i] = 0;
+		ave_dqmdly_byte[i] = 0;
+	}
+
+	for (i = 0; i < DQ_DATA_WIDTH; i++) {
+		index = i / DQS_BIT_NUMBER;
+		fail |= dramc_calcu_best_dly(i,
+			&vref_dq_perbit_dly[i], &max_dqsdly_byte[index]);
+	}
+
+	for (i = 0; i < DQ_DATA_WIDTH; i++) {
+		index = i / DQS_BIT_NUMBER;
+		/* set DQS to max for 8-bit */
+		if (dqdqs_perbit_dly[i].best_dqsdly < max_dqsdly_byte[index]) {
+			/* Delay DQ to compensate extra DQS delay */
+			dly = max_dqsdly_byte[index] -
+				vref_dq_perbit_dly[i].best_dqsdly;
+			vref_dq_perbit_dly[i].best_dqdly += dly;
+			max_limit = MAX_DQDLY_TAPS - 1;
+			if (vref_dq_perbit_dly[i].best_dqdly > max_limit)
+				vref_dq_perbit_dly[i].best_dqdly = max_limit;
+		}
+
+		ave_dqmdly_byte[index] += vref_dq_perbit_dly[i].best_dqdly;
+		if ((i + 1) % DQS_BIT_NUMBER == 0)
+			ave_dqmdly_byte[index] /= DQS_BIT_NUMBER;
+	}
+
+	if (fail == 1) {
+		dramc_dbg("FAIL on perbit_window_cal()\n");
+		return -1;
+	}
+
+	set_rx_best_dly_factor(chn, rank, vref_dq_perbit_dly, max_dqsdly_byte,
+			       ave_dqmdly_byte);
+	return 0;
+}
+
+static void dramc_tx_window_perbit_cal(u8 chn, u8 rank, u8 cal_type)
+{
+	u8 vref, vref_begin, vref_end, vref_step;
+	u8 vref_scan_enable;
+	s16 dly_begin = 0, dly_end = 0;
+	u8 i, bit, index;
+	s16 dly;
+	u8 dly_step = 1;
+	u32 win_sum;
+	u32 err_value, fail_bit;
+	struct per_byte_dly tx_perbyte_dly[DQS_NUMBER];
+	static u16 dq_precal_result[DQS_NUMBER];
+	struct dqs_perbit_dly dqdqs_perbit_dly[DQ_DATA_WIDTH];
+	struct dqs_perbit_dly vref_dqdqs_perbit_dly[DQ_DATA_WIDTH];
+	u32 min_win_size = 0xffff;
+	u32 max_win_size_sum = 0;
+
+	if (cal_type == TX_WIN_MOVE_DQ_ONLY)
+		vref_scan_enable = 1;
+	else
+		vref_scan_enable = 0;
+
+	dramc_dbg("%s [Rank %d][Channel %d] Calibration Type:%d\n",
+			__func__, rank, chn, cal_type);
+
+	write32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[0], 0);
+	write32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[0], 0);
+	clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[1], 0xf);
+	clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[1], 0xf);
+
+	setbits_le32(&ch[chn].phy.misc_ctrl1,
+		0x1 << MISC_CTRL1_R_DMAR_FINE_TUNE_DQ_SW_SHIFT);
+	setbits_le32(&ch[chn].ao.dqsoscr,
+		0x1 << DQSOSCR_AR_COARSE_TUNE_DQ_SW_SHIFT);
+
+	dramc_engine2_init(chn, rank, DEFAULT_TEST2_1_CAL, DEFAULT_TEST2_2_CAL,
+		 TEST_XTALK_PATTERN, 0);
+
+	dramc_get_vref_range(cal_type, vref_scan_enable,
+		&vref_begin, &vref_end, &vref_step);
+	for (vref = vref_begin; vref < vref_end; vref += vref_step) {
+
+		win_sum = 0;
+		for (i = 0; i < DQ_DATA_WIDTH; i++) {
+			dqdqs_perbit_dly[i].vref = vref;
+			dqdqs_perbit_dly[i].first_dqdly_pass = -1;
+			dqdqs_perbit_dly[i].last_dqdly_pass = -2;
+			dqdqs_perbit_dly[i].best_first_dqdly_pass = -1;
+			dqdqs_perbit_dly[i].best_last_dqdly_pass = -2;
+			}
+
+		if (vref_scan_enable)
+			dramc_set_tx_vref(chn, rank, vref);
+
+		dramc_get_dly_range(chn, rank, cal_type, dq_precal_result,
+			&dly_begin, &dly_end);
+
+		dramc_dbg("delay range: (%d - %d)\n", dly_begin, dly_end);
+		for (dly = dly_begin; dly < dly_end; dly += dly_step) {
+			set_dly_factor(chn, rank, cal_type, dly);
+			dramc_dbg("delay = %d ", dly);
+			err_value = dram_k_perbit(chn, 1);
+
+			for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+				fail_bit = err_value & ((u32) 1 << bit);
+				dramc_check_dq_win(&(dqdqs_perbit_dly[bit]),
+					dly, dly_end, fail_bit);
+				if (fail_bit == 0)
+					dramc_dbg("o");
+				else
+					dramc_dbg("x");
+			}
+
+			dramc_dbg(" [MSB]\n");
+		}
+
+		for (bit = 0; bit < DQ_DATA_WIDTH; bit++) {
+			dramc_dbg("dq[%d] win(%d ~ %d)\n",
+				bit, dqdqs_perbit_dly[bit].best_first_dqdly_pass,
+				dqdqs_perbit_dly[bit].best_last_dqdly_pass);
+		}
+
+		dramk_calcu_best_vref(cal_type, vref_dqdqs_perbit_dly,
+			dqdqs_perbit_dly, min_win_size, max_win_size_sum);
+			}
+	dramc_engine2_end(chn);
+
+	dramc_dbg("Final Vref is %d\n", vref_dqdqs_perbit_dly[0].vref);
+	if (vref_scan_enable)
+		dramc_set_tx_vref(chn, rank, vref_dqdqs_perbit_dly[0].vref);
+
+	for (i = 0; i < DQS_NUMBER; i++) {
+		tx_perbyte_dly[i].min_center = 0xffff;
+		tx_perbyte_dly[i].max_center = 0;
+	}
+
+	for (i = 0; i < DQ_DATA_WIDTH; i++) {
+		index = i / DQS_BIT_NUMBER;
+		dramc_calcu_tx_perbyte_dly(i, &vref_dqdqs_perbit_dly[i],
+					&tx_perbyte_dly[index]);
+	}
+
+	for (i = 0; i < DQS_NUMBER; i++) {
+		tx_perbyte_dly[i].final_dly =
+			(tx_perbyte_dly[i].max_center +
+			tx_perbyte_dly[i].min_center) >> 1;
+		dq_precal_result[i] = tx_perbyte_dly[i].final_dly;
+		dramc_dbg("dq_perbyte_dly[%d] = %d\n",
+			i, dq_precal_result[i]);
+	}
+
+	set_tx_best_dly_factor(chn, rank, tx_perbyte_dly, dq_precal_result);
+}
+
+static void dramc_read_dbi_onoff(u8 onoff)
+{
+	u8 chn;
+
+	/* DRAMC Read-DBI On/Off */
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[7],
+			0x1 << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT,
+			(onoff << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT));
+		clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[7],
+			0x1 << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT,
+			(onoff << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT));
+	}
+}
+
+static void dramc_write_dbi_onoff(u8 onoff)
+{
+	u8 u1value, chn;
+
+	/* DRAMC Write-DBI On/Off */
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		clrsetbits_le32(&ch[chn].ao.shu[0].wodt,
+			0x1 << SHU1_WODT_DBIWR_SHIFT,
+			(onoff << SHU1_WODT_DBIWR_SHIFT));
+	}
+
+	u1value = read32(&ch[0].ao.shu[0].wodt);
+	dramc_dbg("DRAMC Write-DBI On/Off = %d\n", u1value);
+}
+
+u8 dramc_zq_calibration(u8 chn, u8 rank)
+{
+	u32 u4Response;
+	u32 u4TimeCnt;
+	u32 *u4RegBackup[] = {
+		&ch[chn].ao.mrs,
+		&ch[chn].ao.dramc_pd_ctrl,
+		&ch[chn].ao.ckectrl,
+	};
+
+	dramc_dbg("[%s] rank:%d\n", __func__, rank);
+	u4TimeCnt = TIME_OUT_CNT;
+
+	save_restore_multi_reg(SAVE_VALUE,
+		u4RegBackup, ARRAY_SIZE(u4RegBackup));
+
+	setbits_le32(&ch[chn].ao.dramc_pd_ctrl, 0x1 << 26);
+
+	cke_fix_onoff(CKE_FIXON, chn);
+
+	clrsetbits_le32(&ch[chn].ao.mrs,
+		MRS_MPCRK_MASK, (rank << MRS_MPCRK_SHIFT));
+	setbits_le32(&ch[chn].ao.mpc_option,
+		(0x1 << MPC_OPTION_MPCRKEN_SHIFT));
+
+	setbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQCEN_SHIFT));
+	do {
+		u4Response =
+		    (read32(&ch[chn].nao.spcmdresp) &
+			    (0x1 << SPCMDRESP_ZQC_RESPONSE_SHIFT)) >>
+			    SPCMDRESP_ZQC_RESPONSE_SHIFT;
+		u4TimeCnt--;
+		udelay(1);
+		dramc_dbg("try:%d\n", u4TimeCnt);
+	} while ((u4Response == 0) && (u4TimeCnt > 0));
+
+	if (u4TimeCnt == 0) {
+		dramc_dbg("ZQCAL Start fail (time out)\n");
+		return 1;
+	}
+
+	clrbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQCEN_SHIFT));
+
+	udelay(1);
+	u4TimeCnt = TIME_OUT_CNT;
+
+	setbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQLATEN_SHIFT));
+	do {
+		u4Response = (read32(&ch[chn].nao.spcmdresp) &
+				    (0x1 << SPCMDRESP_ZQLAT_RESPONSE_SHIFT)) >>
+				    SPCMDRESP_ZQLAT_RESPONSE_SHIFT;
+		u4TimeCnt--;
+		udelay(1);
+		dramc_dbg("%d\n", u4TimeCnt);
+	} while ((u4Response == 0) && (u4TimeCnt > 0));
+
+	if (u4TimeCnt == 0) {
+		dramc_dbg("ZQCAL Latch fail (time out)\n");
+		return 1;
+	}
+
+	clrbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQLATEN_SHIFT));
+
+	udelay(1);
+
+	save_restore_multi_reg(RESTORE_VALUE,
+		u4RegBackup, ARRAY_SIZE(u4RegBackup));
+
+	return 0;
+}
+
+static void dle_factor_handler(u8 chn, u8 curr_val)
+{
+	if (curr_val < 2)
+		curr_val = 2;
+	clrsetbits_le32(&ch[chn].ao.shu[0].conf[1],
+		(SHU_CONF1_DATLAT_MASK) | (SHU_CONF1_DATLAT_DSEL_MASK) |
+		(SHU_CONF1_DATLAT_DSEL_PHY_MASK),
+		(curr_val << SHU_CONF1_DATLAT_SHIFT) |
+		((curr_val - 2) << SHU_CONF1_DATLAT_DSEL_SHIFT) |
+		((curr_val - 2) << SHU_CONF1_DATLAT_DSEL_PHY_SHIFT));
+	dram_phy_reset(chn);
+}
+
+static u32 rx_datlat_result(u8 chn, u8 rank, u8 type, u8 best_step)
+{
+	static u8 aru1RxDatlatResult[CHANNEL_NUM][RANK_MAX] = {0x0};
+
+	if (type == SAVE_VALUE) {
+		aru1RxDatlatResult[chn][rank] = best_step;
+		return 0;
+	}
+
+	return aru1RxDatlatResult[chn][rank];
+}
+
+static u8 dramc_rxdatlat_scan(u8 chn, u8 rank,
+	enum dram_datlat_type use_rxtx_scan)
+{
+	u8 ii;
+	u32 u4prv_register_080;
+	u32 u4err_value = 0xffffffff;
+	u8 ucfirst, ucbegin, ucsum, ucbest_step;
+	u16 u2DatlatBegin;
+
+	dramc_show("[DATLAT]\nCH%d RK%d, use_rxtx_scan=%d\n\n",
+		chn, rank, use_rxtx_scan);
+
+	u4prv_register_080 = read32(&ch[chn].ao.shu[0].conf[1]);
+	ucbest_step = (u8) (read32(&ch[chn].ao.shu[0].conf[1])
+				& (SHU_CONF1_DATLAT_MASK));
+	dramc_dbg("DATLAT Default: 0x%x\n", ucbest_step);
+
+	ucfirst = 0xff;
+	ucbegin = 0;
+	ucsum = 0;
+
+	dramc_engine2_init(chn, rank, DEFAULT_TEST2_1_CAL, DEFAULT_TEST2_2_CAL,
+		 TEST_XTALK_PATTERN, 0);
+
+	u2DatlatBegin = 7;
+	for (ii = u2DatlatBegin; ii < DATLAT_TAP_NUMBER; ii++) {
+		dle_factor_handler(chn, ii);
+
+		if (use_rxtx_scan == DATLAT_USE_DEFAULT) {
+			u4err_value =
+			    dramc_engine2_run(chn,
+					TE_OP_WRITE_READ_CHECK,
+					TEST_XTALK_PATTERN);
+		}
+		if (u4err_value == 0) {
+			if (ucbegin == 0) {
+				ucfirst = ii;
+				ucbegin = 1;
+			}
+			if (ucbegin == 1) {
+				ucsum++;
+				if (ucsum > 4)
+					break;
+			}
+		} else {
+			if (ucbegin == 1)
+				ucbegin = 0xff;
+		}
+
+		dramc_show("TAP=%2d, err_value=0x%8x, sum=%d\n",
+				ii, u4err_value, ucsum);
+	}
+
+	dramc_engine2_end(chn);
+
+	if (ucsum == 0)
+		dramc_show("no DATLAT taps pass, DATLAT calibration fail!\n");
+	else if (ucsum <= 3)
+		ucbest_step = ucfirst + (ucsum >> 1);
+	else
+		ucbest_step = ucfirst + 2;
+
+	rx_datlat_result(chn, rank, SAVE_VALUE, ucbest_step);
+	dramc_dbg("pattern=%d first_step=%d total pass=%d best_step=%d\n",
+		TEST_XTALK_PATTERN, ucfirst, ucsum, ucbest_step);
+
+	if (ucsum < 4)
+		dramc_dbg("[NOTICE] CH%d, DatlatSum %d\n", chn, ucsum);
+
+	if (ucsum == 0) {
+		dramc_show("DATLAT calibration fail,"
+			"write back to default values!\n");
+		write32(&ch[chn].ao.shu[0].conf[1], u4prv_register_080);
+	} else {
+		dle_factor_handler(chn, ucbest_step);
+	}
+
+	clrsetbits_le32(&ch[chn].ao.padctrl, (PADCTRL_DQIENQKEND_MASK),
+		(0x1 << PADCTRL_DQIENQKEND_SHIFT) |
+		(0x1 << PADCTRL_DQIENLATEBEGIN_SHIFT));
+	return ucsum;
+}
+
+static void dramc_rx_datlat_cal(u8 chn, u8 rank)
+{
+	u8 u1DatlatWindowSum;
+
+	u1DatlatWindowSum = dramc_rxdatlat_scan(chn, rank, DATLAT_USE_DEFAULT);
+}
+
+static void dramc_dual_rank_rx_datlat_cal(u8 chn)
+{
+	u8 u1FinalDatlat, u1Datlat0, u1Datlat1;
+
+	u1Datlat0 = rx_datlat_result(chn, RANK_0, RESTORE_VALUE, 0);
+	u1Datlat1 = rx_datlat_result(chn, RANK_1, RESTORE_VALUE, 0);
+
+	if (u1Datlat0 > u1Datlat1)
+		u1FinalDatlat = u1Datlat0;
+	else
+		u1FinalDatlat = u1Datlat1;
+
+	dle_factor_handler(chn, u1FinalDatlat);
+	dramc_dbg("[%s] RK0: %d, RK1: %d, Final_Datlat %d\n",
+		__func__, u1Datlat0, u1Datlat1, u1FinalDatlat);
+}
+
+static void imp_cal_vref_sel(u8 term_option, u8 u1ImpCalStage)
+{
+	u8 u1RegTmpValue = 0;
+
+	if (term_option == 1) {
+		u1RegTmpValue = IMP_LP4X_TERM_VREF_SEL;
+	} else {
+		if (u1ImpCalStage == IMPCAL_STAGE_DRVP)
+			u1RegTmpValue = IMP_DRVP_LP4X_UNTERM_VREF_SEL;
+		else if (u1ImpCalStage == IMPCAL_STAGE_DRVN)
+			u1RegTmpValue = IMP_DRVN_LP4X_UNTERM_VREF_SEL;
+		else
+			u1RegTmpValue = IMP_TRACK_LP4X_UNTERM_VREF_SEL;
+	}
+
+	dramc_dbg("[%s] IMP_VREF_SEL 0x%x\n", __func__, u1RegTmpValue);
+
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11],
+		0x3f << 8, u1RegTmpValue << 8);
+}
+
+void dramc_sw_impedance_save_register(const struct sdram_params *params)
+{
+	int tmp;
+	u32 broadcast_bak;
+	u8 term_opt, ca_term_option = 0, dq_term_option = 1;
+	u32 uSwImpedanceResult[2][4] = { {0}, {0} };
+
+	uSwImpedanceResult[0][0] = params->impedance[ca_term_option][0];
+	uSwImpedanceResult[0][1] = params->impedance[ca_term_option][1];
+	uSwImpedanceResult[0][2] = params->impedance[ca_term_option][2];
+	uSwImpedanceResult[0][3] = params->impedance[ca_term_option][3];
+
+	uSwImpedanceResult[1][0] = params->impedance[dq_term_option][0];
+	uSwImpedanceResult[1][1] = params->impedance[dq_term_option][1];
+	uSwImpedanceResult[1][2] = params->impedance[dq_term_option][2];
+	uSwImpedanceResult[1][3] = params->impedance[dq_term_option][3];
+
+	broadcast_bak = get_dramc_broadcast();
+
+	uSwImpedanceResult[ODT_OFF][2] = uSwImpedanceResult[ODT_ON][2];
+	uSwImpedanceResult[ODT_OFF][3] = uSwImpedanceResult[ODT_ON][3];
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	tmp = 3;
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11],
+		0xFF, tmp);
+
+	/* Set IMP_VREF_SEL value for DRVP */
+	imp_cal_vref_sel(dq_term_option, IMPCAL_STAGE_DRVP);
+
+	/* DQ */
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[0], (0x1F << 5)|(0x1F << 0),
+		(uSwImpedanceResult[dq_term_option][0] << 5) |
+		(uSwImpedanceResult[dq_term_option][1] << 0));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[1],
+		(0x1F << 25)|(0x1F << 20) | (1 << 31),
+		(uSwImpedanceResult[dq_term_option][0] << 25) |
+		(uSwImpedanceResult[dq_term_option][1] << 20) |
+		(!dq_term_option << 31));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[2], (0x1F << 5)|(0x1F << 0),
+		(uSwImpedanceResult[dq_term_option][2] << 5) |
+		(uSwImpedanceResult[dq_term_option][3] << 0));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[3], (0x1F << 25)|(0x1F << 20),
+		(uSwImpedanceResult[dq_term_option][2] << 25) |
+		(uSwImpedanceResult[dq_term_option][3] << 20));
+	/* DQS */
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[0], (0x1F << 25)|(0x1F << 20),
+		(uSwImpedanceResult[dq_term_option][0] << 25) |
+		(uSwImpedanceResult[dq_term_option][1] << 20));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[0], (0x1F << 15)|(0x1F << 10),
+		(uSwImpedanceResult[dq_term_option][0] << 15) |
+		(uSwImpedanceResult[dq_term_option][1] << 10));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[2], (0x1F << 25)|(0x1F << 20),
+		(uSwImpedanceResult[dq_term_option][2] << 25) |
+		(uSwImpedanceResult[dq_term_option][3] << 20));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[2], (0x1F << 15)|(0x1F << 10),
+		(uSwImpedanceResult[dq_term_option][2] << 15) |
+		(uSwImpedanceResult[dq_term_option][3] << 10));
+
+	/* CMD & CLK */
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[1], (0x1F << 15)|(0x1F << 10),
+		(uSwImpedanceResult[ca_term_option][0] << 15) |
+		(uSwImpedanceResult[ca_term_option][1] << 10));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[1], (0x1F << 5)|(0x1F << 0),
+		(uSwImpedanceResult[ca_term_option][0] << 5) |
+		(uSwImpedanceResult[ca_term_option][1] << 0));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[3], (0x1F << 15)|(0x1F << 10),
+		(uSwImpedanceResult[ca_term_option][2] << 15) |
+		(uSwImpedanceResult[ca_term_option][3] << 10));
+	clrsetbits_le32(&ch[0].ao.shu[0].drving[3], (0x1F << 5)|(0x1F << 0),
+		(uSwImpedanceResult[ca_term_option][2] << 5) |
+		(uSwImpedanceResult[ca_term_option][3] << 0));
+
+	/* RG_TX_*RCKE_DRVP/RG_TX_*RCKE_DRVN doesn't set, so set 0xA first */
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], (0x1f << 17),
+		(uSwImpedanceResult[ca_term_option][0] << 17));
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], (0x1f << 22),
+		(uSwImpedanceResult[ca_term_option][1] << 22));
+	/* DRVP[4:0] = RG_TX_ARCMD_PU_PRE<1:0>, RG_TX_ARCLK_DRVN_PRE<2:0> */
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[3],
+		SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_MASK,
+		(((8 >> 3) & 0x3) <<
+		SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_SHIFT));
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[0],
+		SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_MASK,
+		((8 & 0x7) << SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_SHIFT));
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+	clrsetbits_le32(&ch[0].phy.shu[0].ca_dll[1],
+		(0x1F << 16), (0x9 << 16));
+	clrsetbits_le32(&ch[1].phy.shu[0].ca_dll[1],
+		(0x1F << 16), (0x9 << 16));
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	for (term_opt = 0; term_opt < 2; term_opt++) {
+		dramc_show("term_opt=%d, Reg: DRVP=%d, DRVN=%d, ODTN=%d\n",
+				term_opt, uSwImpedanceResult[term_opt][0],
+				uSwImpedanceResult[term_opt][1],
+				uSwImpedanceResult[term_opt][3]);
+	}
+	dramc_broadcast_onoff(broadcast_bak);
+}
+
+static void enable_dramc_phy_dcm_2_channel(u8 chn, u8 bEn)
+{
+	u8 shu, shu_cnt = DRAM_DFS_SHUFFLE_MAX;
+
+	if (!bEn) {
+		clrsetbits_le32(&ch[chn].phy.misc_cg_ctrl0,
+			(0x1 << 20) | (0x1 << 19) | 0x3FF << 8,
+			(0x0 << 20) | (0x1 << 19) | 0x3FF << 8);
+
+		for (shu = DRAM_DFS_SHUFFLE_1; shu < shu_cnt; shu++) {
+			setbits_le32(&ch[chn].phy.shu[shu].b[0].dq[8],
+				0x1FFF << 19);
+			setbits_le32(&ch[chn].phy.shu[shu].b[1].dq[8],
+				0x1FFF << 19);
+			clrbits_le32(&ch[chn].phy.shu[shu].ca_cmd[8],
+				0x1FFF << 19);
+		}
+		clrbits_le32(&ch[chn].phy.misc_cg_ctrl5,
+			(0x7 << 16) | (0x7 << 20));
+	}
+}
+
+void enable_dramc_phy_dcm(u8 bEn)
+{
+	u32 broadcast_bak = get_dramc_broadcast();
+	u8 shu, shu_cnt = DRAM_DFS_SHUFFLE_MAX;
+	u8 chn = 0;
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+
+	for (chn = 0; chn < CHANNEL_NUM ; chn++) {
+		clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[1], (0x1 << 20));
+		clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[1], (0x1 << 20));
+		clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[1], (0x1 << 20));
+
+		for (shu = 0; shu < shu_cnt; shu++) {
+			setbits_le32(&ch[chn].phy.shu[shu].b[0].dll[0],
+				(0x1 << 0));
+			setbits_le32(&ch[chn].phy.shu[shu].b[1].dll[0],
+				(0x1 << 0));
+			setbits_le32(&ch[chn].phy.shu[shu].ca_dll[0],
+				(0x1 << 0));
+		}
+
+		if (bEn) { /* DCM on */
+			clrsetbits_le32(&ch[chn].ao.dramc_pd_ctrl,
+				(0x1 << 0) | (0x1 << 1) | (0x1 << 2) |
+				(0x1 << 5) |
+				(0x1 << 26) | (0x1 << 30) | (0x1 << 31),
+				(0x1 << 0) | (0x1 << 1) | (0x1 << 2) |
+				(0x0 << 5) |
+				(0x0 << 26) | (0x1 << 30) | (0x1 << 31));
+
+			/* CHANNEL_EMI free run */
+			write32(&ch[chn].phy.misc_cg_ctrl2, 0x806003BE);
+			write32(&ch[chn].phy.misc_cg_ctrl2, 0x806003BF);
+			write32(&ch[chn].phy.misc_cg_ctrl2, 0x806003BF);
+			clrbits_le32(&ch[chn].phy.misc_ctrl3, (0x3 << 26));
+
+			for (shu = 0; shu < shu_cnt; shu++) {
+				setbits_le32(&ch[chn].phy.shu[shu].b[0].dq[7],
+					(0x7 << 17));
+				setbits_le32(&ch[chn].phy.shu[shu].b[1].dq[7],
+					(0x7 << 17));
+				setbits_le32(&ch[chn].phy.shu[shu].ca_cmd[7],
+					(0x7 << 17));
+			}
+		} else {
+			clrsetbits_le32(&ch[chn].ao.dramc_pd_ctrl,
+				(0x1 << 0) | (0x1 << 1) | (0x1 << 2) |
+				(0x1 << 5) | (0x1 << 26) |
+				(0x1 << 30) | (0x1 << 31),
+				(0x0 << 0) | (0x0 << 1) | (0x0 << 2) |
+				(0x1 << 5) | (0x1 << 26) |
+				(0x0 << 30) | (0x0 << 31));
+
+			/* mem_dcm */
+			write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060037E);
+			write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060037F);
+			write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060037E);
+
+			setbits_le32(&ch[chn].phy.misc_ctrl3, (0x3 << 26));
+
+			for (shu = 0; shu < shu_cnt; shu++) {
+				clrbits_le32(&ch[chn].phy.shu[shu].b[0].dq[7],
+					(0x7 << 17));
+				clrbits_le32(&ch[chn].phy.shu[shu].b[1].dq[7],
+					(0x7 << 17));
+				clrbits_le32(&ch[chn].phy.shu[shu].ca_cmd[7],
+					(0x7 << 17));
+			}
+		}
+	}
+	enable_dramc_phy_dcm_2_channel(chn, bEn);
+
+	dramc_broadcast_onoff(broadcast_bak);
+}
+
+static void reset_delay_chain_before_calibration(void)
+{
+	u8 chn = 0, rank = 0;
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		for (rank = 0; rank < RANK_MAX; rank++) {
+			clrbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[0],
+				(0xffffff << 0));
+			clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[0],
+				(0xfffffff << 0));
+			clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[0],
+				(0xfffffff << 0));
+
+			clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[1],
+				(0xf << 0));
+
+			clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[1],
+				(0xf << 0));
+		}
+	}
+}
+
+void dramc_hw_gating_onoff(u8 chn, u8 u1OnOff)
+{
+	clrsetbits_le32(&ch[chn].ao.shuctrl2, (0x3 << 14),
+		(u1OnOff << 14) | (u1OnOff << 15));
+	clrsetbits_le32(&ch[chn].ao.stbcal2, (0x1 << 28), (u1OnOff << 28));
+	clrsetbits_le32(&ch[chn].ao.stbcal, (0x1 << 24), (u1OnOff << 24));
+	clrsetbits_le32(&ch[chn].ao.stbcal, (0x1 << 22), (u1OnOff << 22));
+}
+
+static void dramc_rx_input_delay_tracking_init_by_freq(void)
+{
+	u8 u1DVS_Delay;
+
+	u1DVS_Delay = 3;
+	clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[5],
+			(0x7 << 20), (u1DVS_Delay << 20));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[5],
+			(0x7 << 20), (u1DVS_Delay << 20));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[7],
+			(0x1 << 12) | (0x1 << 13), (0x0 << 12) | (0x0 << 13));
+	clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[7],
+			(0x1 << 12) | (0x1 << 13), (0x0 << 12) | (0x0 << 13));
+}
+
+void apply_config_before_calibration(void)
+{
+	u8 shuf = 0;
+
+	/* Clk free run */
+	enable_dramc_phy_dcm(0);
+
+	/* Set LP4 Rank0/1 CA/TX delay chain to 0
+	 * CA0~9 per bit delay line -> CHA_CA0 CHA_CA3 CHA_B0_DQ6 CHA_B0_DQ7
+	 * CHA_B0_DQ2 CHA_B0_DQ5 CHA_B0_DQ4 CHA_B0_DQ1 CHA_B0_DQ0 CHA_B0_DQ3 */
+	reset_delay_chain_before_calibration();
+
+	/* MR4 refresh cnt set to 0x1ff (2ms update) */
+	clrsetbits_le32(&ch[0].ao.shu[0].conf[3],
+			(0x1ff << 16), (0x1ff << 16));
+
+	/* The counter for Read MR4 cannot be reset
+	 * after SREF if DRAMC no power down. */
+	setbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 24));
+
+	/* ---- ZQ CS init -------- */
+	/* ZQ Calibration Time, unit: 38.46ns, tZQCAL min is 1 us.
+	 * need to set larger than 0x1b
+	 */
+	clrsetbits_le32(&ch[0].ao.shu[0].scintv,
+		(0x1f << 1), (0x1b << 1));
+	/* Every refresh number to issue ZQCS commands,
+	 * only for DDR3/LPDDR2/LPDDR3/LPDDR4
+	 */
+	for (shuf = DRAM_DFS_SHUFFLE_1; shuf < DRAM_DFS_SHUFFLE_MAX; shuf++)
+		setbits_le32(&ch[0].ao.shu[shuf].conf[3], (0x1ff << 0));
+
+	/* HW send ZQ command for both rank, disable it due to
+	 * some dram only have 1 ZQ pin for two rank.
+	 */
+	clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 18));
+
+	/* Disable LP4 HW ZQ */
+	/* ZQCSDISB=0 */
+	clrbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 31));
+	/* LP4 ZQCALDISB=0 */
+	clrbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 30));
+	/* End of ZQ CS init */
+
+	/* CBT_MODE = NORMAL_MODE */
+	clrbits_le32(&ch[0].ao.dqsoscr, (0x1 << 26));
+	clrbits_le32(&ch[0].ao.dqsoscr, (0x1 << 25));
+
+	/* Recover write-DBI of DRAMC */
+	dramc_write_dbi_onoff(DBI_OFF);
+	dramc_read_dbi_onoff(DBI_OFF);
+
+	for (int chn = 0; chn < CHANNEL_NUM; chn++) {
+		/* disable MR4 read, REFRDIS=1 */
+		setbits_le32(&ch[chn].ao.spcmdctrl, (0x1 << 29));
+		setbits_le32(&ch[chn].ao.dqsoscr, (0x1 << 24));
+		for (shuf = 0; shuf < DRAM_DFS_SHUFFLE_MAX; shuf++)
+			setbits_le32(&ch[chn].ao.shu[shuf].scintv,
+				(0x1 << 30));
+
+		clrbits_le32(&ch[chn].ao.dummy_rd, (0x1 << 7) | (0x7 << 20));
+
+		/* Disable HW gating tracking first, 0x1c0[31],
+		 * need to disable both coarse tune and fine tune tracking
+		 * or the gating delay reg won't be valid.
+		 */
+		dramc_hw_gating_onoff(chn, GATING_OFF);
+
+		/* Disable gating debug */
+		clrbits_le32(&ch[chn].ao.stbcal2, (0x1 << 28));
+	}
+
+	for (size_t r = 0; r < 2; r++) {
+		for (size_t b = 0; b < 2; b++) {
+			/* Disable RX delay tracking */
+			clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2],
+					(0x1 << 28));
+			clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2],
+					(0x1 << 23));
+
+			/* RX delay mux, delay vlaue from reg. */
+			clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2],
+					(0x3 << 30));
+		}
+		clrbits_le32(&ch[0].phy.r0_ca_rxdvs[2],
+				(0x3 << 30));
+	}
+
+	for (int chn = 0; chn < CHANNEL_NUM; chn++) {
+		setbits_le32(&ch[chn].phy.misc_ctrl1,
+			(0x1 << 7) | (0x1 << 11));
+
+		/* Set to all-bank refresh */
+		clrbits_le32(&ch[chn].ao.refctrl0, (0x1 << 18));
+
+		/* set MPCRK to 0, MPCRKEN alwasys set 1 */
+		clrbits_le32(&ch[chn].ao.mrs, (0x3 << 24));
+		setbits_le32(&ch[chn].ao.mpc_option, (0x1 << 17));
+
+		/* RG mode */
+		clrsetbits_le32(&ch[chn].phy.b[0].dq[6],
+			(0x3 << 0), (0x1 << 0));
+		clrsetbits_le32(&ch[chn].phy.b[1].dq[6],
+			(0x3 << 0), (0x1 << 0));
+		clrsetbits_le32(&ch[chn].phy.ca_cmd[6],
+			(0x3 << 0), (0x1 << 0));
+	}
+
+	dramc_rx_input_delay_tracking_init_by_freq();
+	for (int chn = 0; chn < CHANNEL_NUM; chn++) {
+		setbits_le32(&ch[chn].ao.dummy_rd, (0x1 << 25));
+		setbits_le32(&ch[chn].ao.drsctrl, (0x1 << 0));
+
+		clrbits_le32(&ch[chn].ao.shu[1].drving[1], 0x1 << 31);
+	}
+}
+
+void dram_calibration_all_channel(const struct sdram_params *params)
+{
+	for (u8 chn = 0; chn < CHANNEL_NUM; chn++) {
+		for (u8 rank = RANK_0; rank < RANK_MAX; rank++) {
+			dramc_show("start K ch:%d, rank:%d\n", chn, rank);
+			dramc_zq_calibration(chn, rank);
+			auto_refresh_switch(chn, 0);
+
+			cmd_bus_training(chn, rank, params);
+
+			/* Dram will be reset when finish write leveling */
+			dramc_write_leveling(chn, rank, params);
+
+			auto_refresh_switch(chn, 1);
+			dramc_rx_dqs_gating_cal(chn, rank);
+			dramc_rx_window_perbit_cal(chn, RX_WIN, rank, 0);
+
+			dramc_tx_window_perbit_cal(chn, rank,
+				TX_WIN_MOVE_DQ_DQM);
+			dramc_tx_window_perbit_cal(chn, rank,
+				TX_WIN_MOVE_DQ_ONLY);
+
+			dramc_rx_datlat_cal(chn, rank);
+			dramc_rx_window_perbit_cal(chn, RX_WIN, rank, 1);
+		}
+
+		/* ENABLE_TX_TRACKING */
+		dramc_rx_dqs_gating_post_process(chn);
+		dramc_dual_rank_rx_datlat_cal(chn);
+	}
+}
diff --git a/src/soc/mediatek/mt8183/emi.c b/src/soc/mediatek/mt8183/emi.c
index e37fd56..8ef1613 100644
--- a/src/soc/mediatek/mt8183/emi.c
+++ b/src/soc/mediatek/mt8183/emi.c
@@ -13,9 +13,312 @@
  * GNU General Public License for more details.
  */
 
+#include <arch/io.h>
+#include <soc/addressmap.h>
+#include <soc/dramc_pi_api.h>
+#include <soc/dramc_register.h>
 #include <soc/emi.h>
+#include <soc/infracfg.h>
+#include <soc/spm.h>
+#include <delay.h>
+
+struct emi_regs *emi_regs = (void *)EMI_BASE;
+
+void get_dram_rank_size(u64 *dram_rank_size)
+{
+	u32 col_bit, row_bit;
+	u32 shift_for_16bit = 1; /* data width = 2 bytes */
+	u64 ch0_rank0_size, ch0_rank1_size, ch1_rank0_size, ch1_rank1_size;
+	u64 ch_rank0_size = 0, ch_rank1_size = 0;
+
+	u32 emi_cona = read32(&emi_regs->cona);
+	u32 emi_conh = read32(&emi_regs->conh);
+
+	if (emi_cona & 0x2)
+		shift_for_16bit = 0; /* data width = 4 bytes */
+
+	dram_rank_size[0] = 0;
+	dram_rank_size[1] = 0;
+
+	ch0_rank0_size = (emi_conh >> 16) & 0xf;
+	ch0_rank1_size = (emi_conh >> 20) & 0xf;
+	ch1_rank0_size = (emi_conh >> 24) & 0xf;
+	ch1_rank1_size = (emi_conh >> 28) & 0xf;
+
+	/* CH0 EMI */
+	if (ch0_rank0_size == 0) {
+		/* rank 0 setting */
+		col_bit = ((emi_cona >> 4) & 0x03) + 9;
+		row_bit = ((((emi_cona >> 24) & 0x01) << 2) +
+			((emi_cona >> 12) & 0x03)) + 13;
+		/* data width (bytes) * 8 banks */
+		ch_rank0_size = ((u64)(1 << (row_bit + col_bit))) *
+		((u64)(4 >> shift_for_16bit) * 8);
+	} else {
+		ch_rank0_size = (ch0_rank0_size * 256 << 20);
+	}
+
+	/* dual rank enable */
+	if (0 != (emi_cona &  (1 << 17))) {
+		if (ch0_rank1_size == 0) {
+			col_bit = ((emi_cona >> 6) & 0x03) + 9;
+			row_bit = ((((emi_cona >> 25) & 0x01) << 2) +
+				((emi_cona >> 14) & 0x03)) + 13;
+			/* data width (bytes) * 8 banks */
+			ch_rank1_size = ((u64)(1 << (row_bit + col_bit))) *
+				((u64)(4 >> shift_for_16bit) * 8);
+		} else {
+			ch_rank1_size = (ch0_rank1_size * 256 << 20);
+		}
+	}
+
+	dram_rank_size[0] = ch_rank0_size;
+	dram_rank_size[1] = ch_rank1_size;
+
+	if (ch1_rank0_size == 0) {
+		/* rank0 setting */
+		col_bit = ((emi_cona >> 20) & 0x03) + 9;
+		row_bit = ((((emi_conh >> 4) & 0x01) << 2) +
+			((emi_cona >> 28) & 0x03)) + 13;
+
+		/* data width (bytes) * 8 banks */
+		ch_rank0_size = ((u64)(1 << (row_bit + col_bit))) *
+			((u64)(4 >> shift_for_16bit) * 8);
+	} else {
+		ch_rank0_size = (ch1_rank0_size * 256 << 20);
+	}
+
+	if (0 != (emi_cona &  (1 << 16))) {
+		if (ch1_rank1_size == 0) {
+			col_bit = ((emi_cona >> 22) & 0x03) + 9;
+			row_bit = ((((emi_conh >> 5) & 0x01) << 2) +
+				((emi_cona >> 30) & 0x03)) + 13;
+			/* data width (bytes) * 8 banks */
+			ch_rank1_size = ((u64)(1 << (row_bit + col_bit))) *
+				((u64)(4 >> shift_for_16bit) * 8);
+		} else {
+			ch_rank1_size = (ch1_rank1_size * 256 << 20);
+		}
+	}
+
+	dram_rank_size[0] += ch_rank0_size;
+	dram_rank_size[1] += ch_rank1_size;
+}
 
 size_t sdram_size(void)
 {
-	return (size_t)4 * GiB;
+	size_t dram_size = 0;
+	u64 rank_size[RANK_MAX];
+
+	get_dram_rank_size(&rank_size[0]);
+
+	for (int i = 0; i < RANK_MAX; i++) {
+		dram_size += rank_size[i];
+		dramc_show("rank%d size:0x%llx\n", i, rank_size[i]);
+	}
+
+	return dram_size;
+}
+
+static void set_rank_info_to_conf(const struct sdram_params *params)
+{
+	u8 u4value = 0;
+
+	/* CONA 17th bit 0: Disable dual rank mode
+	 * 1: Enable dual rank mode */
+	u4value = ((params->EMI_CONA_VAL & (0x1 << 17)) >> 17) ? 0 : 1;
+	clrsetbits_le32(&ch[0].ao.arbctl, 0x1 << 12, u4value << 12);
+}
+
+static void set_MRR_pinmux_mapping(void)
+{
+	u8 chn;
+	u8 phy_mapping[CHANNEL_NUM][16] = {
+		[CHANNEL_A] = {
+			1, 0, 2, 4, 3, 7, 5, 6,
+			9, 8, 12, 11, 10, 15, 13, 14
+		},
+
+		[CHANNEL_B] = {
+			0, 1, 5, 6, 3, 7, 4, 2,
+			9, 8, 12, 15, 11, 14, 13, 10
+		}
+	};
+
+	for (chn = 0; chn < CHANNEL_NUM; chn++) {
+		u8 *map = phy_mapping[chn];
+		write32(&ch[chn].ao.mrr_bit_mux1,
+			(map[0] << 0) | (map[1] << 8) |
+			(map[2] << 16) | (map[3] << 24));
+
+		write32(&ch[chn].ao.mrr_bit_mux2,
+			(map[4] << 0) | (map[5]<<8) |
+			(map[6] << 16) | (map[7] << 24));
+
+		write32(&ch[chn].ao.mrr_bit_mux3,
+			(map[8] << 0) | (map[9] << 8) |
+			(map[10] << 16) | (map[11]<<24));
+
+		write32(&ch[chn].ao.mrr_bit_mux4,
+			(map[12] << 0) | (map[13] << 8) |
+			(map[14] << 16) | (map[15] << 24));
+	}
+}
+
+static void global_option_init(const struct sdram_params *params)
+{
+	set_rank_info_to_conf(params);
+	set_MRR_pinmux_mapping();
+}
+
+static void emi_esl_setting1(void)
+{
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	write32(&emi_regs->cona, 0xa053a154);
+
+	write32(&emi_regs->conb, 0x17283544);
+	write32(&emi_regs->conc, 0x0a1a0b1a);
+	write32(&emi_regs->cond, 0x3657587a);
+	write32(&emi_regs->cone, 0x80400148);
+	write32(&emi_regs->conf, 0x00000000);
+	write32(&emi_regs->cong, 0x2b2b2a38);
+	write32(&emi_regs->conh, 0x00000000);
+
+	write32(&emi_regs->coni, 0x00008803);
+	write32(&emi_regs->conm, 0x000001ff);
+	write32(&emi_regs->conn, 0x00000000);
+	write32(&emi_regs->mdct, 0x11338c17);
+	write32(&emi_regs->mdct_2nd, 0x00001112);
+	write32(&emi_regs->iocl, 0xa8a8a8a8);
+	write32(&emi_regs->iocl_2nd, 0x25252525);
+	write32(&emi_regs->iocm, 0xa8a8a8a8);
+	write32(&emi_regs->iocm_2nd, 0x25252525);
+	write32(&emi_regs->testb, 0x00060037);
+	write32(&emi_regs->testc, 0x38460000);
+	write32(&emi_regs->testd, 0x00000000);
+
+	write32(&emi_regs->arba, 0x4020524f);
+	write32(&emi_regs->arbb, 0x4020504f);
+	write32(&emi_regs->arbc, 0xa0a050c6);
+	write32(&emi_regs->arbd, 0x000070cc);
+	write32(&emi_regs->arbe, 0x40406045);
+	write32(&emi_regs->arbf, 0xa0a070d5);
+	write32(&emi_regs->arbg, 0xa0a0504f);
+	write32(&emi_regs->arbh, 0xa0a0504f);
+
+	write32(&emi_regs->arbi, 0x00007108);
+	write32(&emi_regs->arbi_2nd, 0x00007108);
+	write32(&emi_regs->slct, 0x0001ff00);
+
+	write32(&ch[0].emi.chn_cona, 0x0400a051);
+	write32(&ch[0].emi.chn_conb, 0x00ff2048);
+	write32(&ch[0].emi.chn_conc, 0x00000000);
+	write32(&ch[0].emi.chn_mdct, 0x88008817);
+
+	write32(&ch[0].emi.chn_testb, 0x00030027);
+	write32(&ch[0].emi.chn_testc, 0x38460002);
+	write32(&ch[0].emi.chn_testd, 0x00000000);
+
+	write32(&ch[0].emi.chn_md_pre_mask, 0x00000f00);
+	write32(&ch[0].emi.chn_md_pre_mask_shf, 0x00000b00);
+
+	write32(&ch[0].emi.chn_arbi, 0x20406188);
+	write32(&ch[0].emi.chn_arbi_2nd, 0x20406188);
+
+	write32(&ch[0].emi.chn_arbj, 0x3719595e);
+	write32(&ch[0].emi.chn_arbj_2nd, 0x3719595e);
+	write32(&ch[0].emi.chn_arbk, 0x64f3fc79);
+	write32(&ch[0].emi.chn_arbk_2nd, 0x64f3fc79);
+	write32(&ch[0].emi.chn_slct, 0x00080888);
+	write32(&ch[0].emi.chn_arb_ref, 0x82410222);
+
+	write32(&ch[0].emi.chn_emi_shf0, 0x8a228c17);
+	write32(&ch[0].emi.chn_rkarb0, 0x0006002f);
+	write32(&ch[0].emi.chn_rkarb1, 0x01010101);
+	write32(&ch[0].emi.chn_rkarb2, 0x10100820);
+	write32(&ch[0].emi.chn_eco3, 0x00000000);
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+}
+
+static void emi_esl_setting2(void)
+{
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+
+	write32(&ch[0].emi.chn_conc, 0x01);
+	write32(&emi_regs->conm, 0x05ff);
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_OFF);
+}
+
+static void emi_init(const struct sdram_params *params)
+{
+	emi_esl_setting1();
+
+	write32(&emi_regs->cona, params->EMI_CONA_VAL);
+	write32(&emi_regs->conf, params->EMI_CONF_VAL);
+	write32(&emi_regs->conh, params->EMI_CONH_VAL);
+
+	for (size_t chn = CHANNEL_A; chn < CHANNEL_NUM; chn++) {
+		write32(&ch[chn].emi.chn_cona, params->CHN_EMI_CONA_VAL[chn]);
+		write32(&ch[chn].emi.chn_conc, 0);
+	}
+}
+
+static void emi_init2(const struct sdram_params *params)
+{
+	emi_esl_setting2();
+
+	setbits_le32(&emi_mpu->mpu_ctrl_d0 + 0x4 * 1, 0x1 << 4);
+	setbits_le32(&emi_mpu->mpu_ctrl_d0 + 0x4 * 7, 0x1 << 4);
+
+	write32(&emi_regs->bwct0, 0x0A000705);
+	write32(&emi_regs->bwct0_3rd, 0x0);
+
+	/* EMI QoS 0.5 */
+	write32(&emi_regs->bwct0_2nd, 0x00030023);
+	write32(&emi_regs->bwct0_4th, 0x00c00023);
+	write32(&emi_regs->bwct0_5th, 0x00240023);
+}
+
+static void dramc_init_pre_settings(void)
+{
+	clrsetbits_le32(&ch[0].phy.ca_cmd[8],
+		(0x1 << 21) | (0x1 << 20) | (0x1 << 19) | (0x1 << 18) |
+		(0x1F << 8) | (0x1f << 0),
+		(0x1 << 19) | (0xa << 8) | (0xa << 0));
+
+	setbits_le32(&ch[0].phy.misc_ctrl1, (0x1 << 12));
+	clrbits_le32(&ch[0].phy.misc_ctrl1, (0x1 << 13));
+	setbits_le32(&ch[0].phy.misc_ctrl1, (0x1 << 31));
+}
+
+static void init_dram(const struct sdram_params *params)
+{
+	global_option_init(params);
+	emi_init(params);
+
+	dramc_broadcast_onoff(DRAMC_BROADCAST_ON);
+	dramc_init_pre_settings();
+
+	dramc_sw_impedance_save_register(params);
+
+	dramc_init(params);
+	emi_init2(params);
+}
+
+static void do_calib(const struct sdram_params *params)
+{
+	apply_config_before_calibration();
+	dram_calibration_all_channel(params);
+
+	dramc_ac_timing_optimize();
+	dramc_runtime_config();
+}
+
+void mt_set_emi(const struct sdram_params *params)
+{
+	init_dram(params);
+	do_calib(params);
 }
diff --git a/src/soc/mediatek/mt8183/include/soc/addressmap.h b/src/soc/mediatek/mt8183/include/soc/addressmap.h
index de7eb1f..f8edf5b 100644
--- a/src/soc/mediatek/mt8183/include/soc/addressmap.h
+++ b/src/soc/mediatek/mt8183/include/soc/addressmap.h
@@ -19,7 +19,6 @@
 enum {
 	MCUCFG_BASE	= 0x0C530000,
 	IO_PHYS		= 0x10000000,
-	DDR_BASE	= 0x40000000
 };
 
 enum {
@@ -30,6 +29,9 @@
 	RGU_BASE                = IO_PHYS + 0x00007000,
 	GPT_BASE		= IO_PHYS + 0x00008000,
 	APMIXED_BASE		= IO_PHYS + 0x0000C000,
+	EMI_BASE		= IO_PHYS + 0x00219000,
+	EMI_MPU_BASE		= IO_PHYS + 0x00226000,
+	DRAMC_CH_BASE		= IO_PHYS + 0x00228000,
 	UART0_BASE		= IO_PHYS + 0x01002000,
 	SPI0_BASE               = IO_PHYS + 0x0100A000,
 	SPI1_BASE		= IO_PHYS + 0x01010000,
diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h
new file mode 100644
index 0000000..08b7b78
--- /dev/null
+++ b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DRAMC_COMMON_MT8183_H_
+#define _DRAMC_COMMON_MT8183_H_
+
+enum {
+	CHANNEL_A = 0,
+	CHANNEL_B,
+	CHANNEL_NUM
+};
+
+enum {
+	RANK_0 = 0,
+	RANK_1,
+	RANK_MAX
+};
+
+enum dram_odt_type {
+	ODT_OFF = 0,
+	ODT_ON
+};
+
+enum {
+	DQ_DATA_WIDTH = 16,
+	DQS_BIT_NUMBER = 8,
+	DQS_NUMBER = (DQ_DATA_WIDTH / DQS_BIT_NUMBER)
+};
+
+/*
+ * Internal CBT mode enum
+ * 1. Calibration flow uses vGet_Dram_CBT_Mode to
+ *    differentiate between mixed vs non-mixed LP4
+ * 2. Declared as dram_cbt_mode[RANK_MAX] internally to
+ *    store each rank's CBT mode type
+ */
+enum {
+	CBT_NORMAL_MODE = 0,
+	CBT_BYTE_MODE1
+};
+
+#endif   /* _DRAMC_COMMON_MT8183_H_ */
diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
new file mode 100644
index 0000000..409086f
--- /dev/null
+++ b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DRAMC_PI_API_MT8183_H
+#define _DRAMC_PI_API_MT8183_H
+
+#include <console/console.h>
+#include <soc/emi.h>
+#include <types.h>
+
+#define dramc_show(_x_...) printk(BIOS_INFO, _x_)
+#if IS_ENABLED(CONFIG_DEBUG_DRAM)
+#define dramc_dbg(_x_...) printk(BIOS_DEBUG, _x_)
+#else
+#define dramc_dbg(_x_...)
+#endif
+
+#define ENABLE  1
+#define DISABLE 0
+
+#define DATLAT_TAP_NUMBER 32
+#define DEFAULT_TEST2_1_CAL 0x55000000
+#define DEFAULT_TEST2_2_CAL 0xaa000400
+
+#define MAX_CMP_CPT_WAIT_LOOP 10000
+#define TIME_OUT_CNT 100
+
+#define DRAMC_BROADCAST_ON 0x1f
+#define DRAMC_BROADCAST_OFF 0x0
+#define MR13_RRO 1
+#define POS_BANK_NUM 16
+#define MAX_BACKUP_REG_CNT 64
+
+enum {
+	TEST_ISI_PATTERN = 0,
+	TEST_AUDIO_PATTERN,
+	TEST_XTALK_PATTERN,
+	TEST_TA1_SIMPLE,
+	TEST_TESTPAT4,
+	TEST_TESTPAT4_3,
+	TEST_MIX_PATTERN,
+	TEST_DMA,
+};
+
+enum dram_datlat_type {
+	DATLAT_USE_DEFAULT = 0,
+	DATLAT_USE_RX_SCAN,
+};
+
+enum dram_te_op {
+	TE_OP_WRITE_READ_CHECK = 0,
+	TE_OP_READ_CHECK
+};
+
+enum {
+	DBI_OFF = 0,
+	DBI_ON
+};
+
+enum {
+	FSP_0 = 0,
+	FSP_1,
+	FSP_MAX
+};
+
+enum {
+	DLL_MASTER_CH = CHANNEL_A,
+	DLL_SLAVE_CH = CHANNEL_B,
+};
+
+enum {
+	TX_DQ_DQS_MOVE_DQ_ONLY = 0,
+	TX_DQ_DQS_MOVE_DQM_ONLY,
+	TX_DQ_DQS_MOVE_DQ_DQM
+};
+
+enum {
+	MAX_CA_FINE_TUNE_DELAY = 63,
+	MAX_CS_FINE_TUNE_DELAY = 63,
+	MAX_CLK_FINE_TUNE_DELAY = 31,
+	CATRAINING_NUM = 6,
+	PASS_RANGE_NA = 0x7fff
+};
+
+enum {
+	CBT_LOW_FREQ = 0,
+	CBT_HIGH_FREQ = 1
+};
+
+enum {
+	CBT_OFF = 0,
+	CBT_ON = 1
+};
+
+enum {
+	GATING_OFF = 0,
+	GATING_ON = 1
+};
+
+enum {
+	CKE_FIXOFF = 0,
+	CKE_FIXON,
+	CKE_DYNAMIC
+};
+
+enum {
+	RANK_SINGLE = 1,
+	RANK_DUAL
+};
+
+enum {
+	GATING_PATTERN_NUM = 0x23,
+	GATING_GOLDEND_DQSCNT = 0x4646
+};
+
+enum {
+	IMPCAL_STAGE_DRVP = 0x1,
+	IMPCAL_STAGE_DRVN,
+	IMPCAL_STAGE_TRACKING,
+};
+
+enum {
+	DQS_GW_COARSE_STEP = 1,
+	DQS_GW_FINE_START = 0,
+	DQS_GW_FINE_END = 32,
+	DQS_GW_FINE_STEP = 4,
+	DQS_GW_FREQ_DIV = 4,
+	RX_DQS_CTL_LOOP = 8,
+	RX_DLY_DQSIENSTB_LOOP = 32
+};
+
+enum {
+	DRAM_DFS_SHUFFLE_1 = 0,
+	DRAM_DFS_SHUFFLE_2,
+	DRAM_DFS_SHUFFLE_3,
+	DRAM_DFS_SHUFFLE_MAX
+};
+
+enum {
+	TYPE_DDR1 = 1,
+	TYPE_LPDDR2,
+	TYPE_LPDDR3,
+	TYPE_PCDDR3,
+	TYPE_LPDDR4,
+	TYPE_LPDDR4X,
+	TYPE_LPDDR4P
+};
+
+enum {
+	AC_TIMING_DRAM_TYPE = 0,
+	AC_TIMING_FREQUENCY,
+	AC_TIMING_DBI_ONOFF,
+	AC_TIMING_BYTE_MODE,
+	AC_TIMING_TRAS,
+	AC_TIMING_TRP,
+	AC_TIMING_TRPAB,
+	AC_TIMING_TRC,
+	AC_TIMING_TRFC,
+	AC_TIMING_TRFCPB,
+	AC_TIMING_TXP,
+	AC_TIMING_TRTP,
+	AC_TIMING_TRCD,
+	AC_TIMING_TWR,
+	AC_TIMING_TWTR,
+	AC_TIMING_TRRD,
+	AC_TIMING_TFAW,
+	AC_TIMING_TRTW_ODT_OFF,
+	AC_TIMING_TRTW_ODT_ON,
+	AC_TIMING_REFCNT,
+	AC_TIMING_REFCNT_FR_CLK,
+	AC_TIMING_TXREFCNT,
+	AC_TIMING_TZQCS,
+	AC_TIMING_TRTPD,
+	AC_TIMING_TWTPD,
+	AC_TIMING_TMRR2W_ODT_OFF,
+	AC_TIMING_TMRR2W_ODT_ON,
+	AC_TIMING_TRAS_05T,
+	AC_TIMING_TRP_05T,
+	AC_TIMING_TRPAB_05T,
+	AC_TIMING_TRC_05T,
+	AC_TIMING_TRFC_05T,
+	AC_TIMING_TRFCPB_05T,
+	AC_TIMING_TXP_05T,
+	AC_TIMING_TRTP_05T,
+	AC_TIMING_TRCD_05T,
+	AC_TIMING_TWR_05T,
+	AC_TIMING_TWTR_05T,
+	AC_TIMING_TRRD_05T,
+	AC_TIMING_TFAW_05T,
+	AC_TIMING_TRTW_05T_ODT_OFF,
+	AC_TIMING_TRTW_05T_ODT_ON,
+	AC_TIMING_TRTPD_05T,
+	AC_TIMING_TWTPD_05T,
+	AC_TIMING_XRTW2W,
+	AC_TIMING_XRTW2R,
+	AC_TIMING_XRTR2W,
+	AC_TIMING_XRTR2R,
+	AC_TIMING_DMCATRAIN_INTV,
+	AC_TIMING_DQSINCTL_FOR_GATING,
+	AC_TIMING_DATLAT,
+	AC_TIMING_MODE_REG_WL,
+	AC_TIMING_MODE_REG_RL,
+	AC_TIMING_ITEM_NUM
+};
+
+enum {
+	SAVE_VALUE,
+	RESTORE_VALUE
+};
+
+void dramc_init(const struct sdram_params *params);
+void get_dram_rank_size(u64 *dram_rank_size);
+void dramc_runtime_config(void);
+void dram_calibration_all_channel(const struct sdram_params *params);
+void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value);
+void dramc_engine2_init(u8 chn, u8 u1RankSel, u32 test2_1, u32 test2_2,
+	u8 testaudpat, u8 log2loopcount);
+u32 dramc_engine2_run(u8 chn, enum dram_te_op wr, u8 testaudpat);
+void dramc_engine2_end(u8 chn);
+void dramc_sw_impedance_save_register(const struct sdram_params *params);
+void dramc_broadcast_onoff(u32 bOnOff);
+u32 get_dramc_broadcast(void);
+void apply_config_before_calibration(void);
+void dramc_gating_mode(u8 chn, u8 mode);
+void dramc_hw_gating_onoff(u8 chn, u8 u1OnOff);
+void dramc_ac_timing_optimize(void);
+void cke_fix_onoff(int option, u8 chn);
+void save_restore_multi_reg(u8 type, u32 **reg_addr, u32 reg_count);
+u8 dramc_zq_calibration(u8 chn, u8 rank);
+void dramc_mode_reg_write_by_rank(u8 chn, u8 rank, u8 mr_idx, u8 value);
+void enable_dramc_phy_dcm(u8 bEn);
+
+#endif /* _DRAMC_PI_API_MT8183_H */
diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_register.h b/src/soc/mediatek/mt8183/include/soc/dramc_register.h
new file mode 100644
index 0000000..9ebb5e4
--- /dev/null
+++ b/src/soc/mediatek/mt8183/include/soc/dramc_register.h
@@ -0,0 +1,1446 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DRAMC_REGISTER_H_
+#define _DRAMC_REGISTER_H_
+
+#include <types.h>
+#include <soc/addressmap.h>
+
+struct dramc_no_regs_rk_counter {
+	uint32_t pre_standby_counter;
+	uint32_t pre_powerdown_counter;
+	uint32_t act_standby_counter;
+	uint32_t act_powerdown_counter;
+};
+
+struct dramc_nao_regs_rk {
+	uint32_t dqsosc_status;
+	uint32_t dqsosc_delta;
+	uint32_t dqsosc_delta2;
+	uint32_t rsvd_1[1];
+	uint32_t current_tx_setting1;
+	uint32_t current_tx_setting2;
+	uint32_t current_tx_setting3;
+	uint32_t current_tx_setting4;
+	uint32_t dummy_rd_data[4];
+	uint32_t b0_stb_max_min_dly;
+	uint32_t b1_stb_max_min_dly;
+	uint32_t b2_stb_max_min_dly;
+	uint32_t b3_stb_max_min_dly;
+	uint32_t dqsiendly;
+	uint32_t dqsienuidly;
+	uint32_t dqsienuidly_p1;
+	uint32_t rsvd_2[1];
+	uint32_t dqs_stbcaldec_cnt1;
+	uint32_t dqs_stbcaldec_cnt2;
+	uint32_t dqs_stbcalinc_cnt1;
+	uint32_t dqs_stbcalinc_cnt2;
+	uint32_t fine_tune_dq_cal;
+	uint32_t dqsg_retry_flag;
+	uint32_t fine_tune_dqm_cal;
+	uint32_t rsvd_3[1];
+	uint32_t dqs0_stbcal_cnt;
+	uint32_t dqs1_stbcal_cnt;
+	uint32_t dqs2_stbcal_cnt;
+	uint32_t dqs3_stbcal_cnt;
+	uint32_t b01_stb_dbg_info[16];
+	uint32_t b23_stb_dbg_info[16];
+};
+
+struct dramc_nao_regs {
+	uint32_t testmode;
+	uint32_t lbwdat0;
+	uint32_t lbwdat1;
+	uint32_t lbwdat2;
+	uint32_t lbwdat3;
+	uint32_t reserved0[3];
+	uint32_t ckphchk;
+	uint32_t dmmonitor;
+	uint32_t reserved1[2];
+	uint32_t testchip_dma1;
+	uint32_t reserved2[19];
+	uint32_t misc_statusa;
+	uint32_t special_status;
+	uint32_t spcmdresp;
+	uint32_t mrr_status;
+	uint32_t mrr_status2;
+	uint32_t mrrdata0;
+	uint32_t mrrdata1;
+	uint32_t mrrdata2;
+	uint32_t mrrdata3;
+	uint32_t reserved3[1];
+	uint32_t drs_status;
+	uint32_t reserved4[4];
+	uint32_t jmeter_st;
+	uint32_t tcmdo1lat;
+	uint32_t rdqc_cmp;
+	uint32_t ckphchk_status;
+	uint32_t reserved5[16];
+	uint32_t hwmrr_push2pop_cnt;
+	uint32_t hwmrr_status;
+	uint32_t hw_refrate_mon;
+	uint32_t reserved6[2];
+	uint32_t testrpt;
+	uint32_t cmp_err;
+	uint32_t test_abit_status1;
+	uint32_t test_abit_status2;
+	uint32_t test_abit_status3;
+	uint32_t test_abit_status4;
+	uint32_t reserved7[6];
+	uint32_t dqsdly0;
+	uint32_t dq_cal_max[8];
+	uint32_t dqs_cal_min[8];
+	uint32_t dqs_cal_max[8];
+	uint32_t dqical0;
+	uint32_t dqical1;
+	uint32_t dqical2;
+	uint32_t dqical3;
+	uint32_t reserved8[15];
+	uint32_t testchip_dma_status[34];
+	uint32_t reserved9[30];
+	uint32_t refresh_pop_counter;
+	uint32_t freerun_26m_counter;
+	uint32_t dramc_idle_counter;
+	uint32_t r2r_page_hit_counter;
+	uint32_t r2r_page_miss_counter;
+	uint32_t r2r_interbank_counter;
+	uint32_t r2w_page_hit_counter;
+	uint32_t r2w_page_miss_counter;
+	uint32_t r2w_interbank_counter;
+	uint32_t w2r_page_hit_counter;
+	uint32_t w2r_page_miss_counter;
+	uint32_t w2r_interbank_counter;
+	uint32_t w2w_page_hit_counter;
+	uint32_t w2w_page_miss_counter;
+	uint32_t w2w_interbank_counter;
+	struct dramc_no_regs_rk_counter rk_counter[3];
+	uint32_t dq0_toggle_counter;
+	uint32_t dq1_toggle_counter;
+	uint32_t dq2_toggle_counter;
+	uint32_t dq3_toggle_counter;
+	uint32_t dq0_toggle_counter_r;
+	uint32_t dq1_toggle_counter_r;
+	uint32_t dq2_toggle_counter_r;
+	uint32_t dq3_toggle_counter_r;
+	uint32_t read_bytes_counter;
+	uint32_t write_bytes_counter;
+	uint32_t max_sref_req_to_ack_latency_counter;
+	uint32_t max_rk1_drs_long_req_to_ack_latency_counter;
+	uint32_t max_rk1_drs_req_to_ack_latency_counter;
+	uint32_t reserved10[8];
+	uint32_t lat_counter_cmd[8];
+	uint32_t lat_counter_aver;
+	uint32_t lat_counter_num;
+	uint32_t lat_counter_block_ale;
+	uint32_t reserved11[5];
+	uint32_t dqssamplev;
+	uint32_t reserved12[1];
+	uint32_t dqsgnwcnt[6];
+	uint32_t toggle_cnt;
+	uint32_t dqs0_err_cnt;
+	uint32_t dq_err_cnt0;
+	uint32_t dqs1_err_cnt;
+	uint32_t dq_err_cnt1;
+	uint32_t dqs2_err_cnt;
+	uint32_t dq_err_cnt2;
+	uint32_t dqs3_err_cnt;
+	uint32_t dq_err_cnt3;
+	uint32_t reserved13[3];
+	uint32_t iorgcnt;
+	uint32_t dqsg_retry_state;
+	uint32_t dqsg_retry_state1;
+	uint32_t reserved14[1];
+	uint32_t impcal_status1;
+	uint32_t impcal_status2;
+	uint32_t dqdrv_status;
+	uint32_t cmddrv_status;
+	uint32_t cmddrv1;
+	uint32_t cmddrv2;
+	uint32_t reserved15[98];
+	struct dramc_nao_regs_rk rk[3];
+	uint32_t reserved25[192];
+	uint32_t dvfs_dbg0;
+	uint32_t dvfs_dbg1;
+	uint32_t dramc_nao_regs_end;
+};
+
+check_member(dramc_nao_regs, testmode, 0x0000);
+check_member(dramc_nao_regs, lbwdat0, 0x0004);
+check_member(dramc_nao_regs, lbwdat1, 0x0008);
+check_member(dramc_nao_regs, lbwdat2, 0x000c);
+check_member(dramc_nao_regs, lbwdat3, 0x0010);
+check_member(dramc_nao_regs, ckphchk, 0x0020);
+check_member(dramc_nao_regs, dmmonitor, 0x0024);
+check_member(dramc_nao_regs, testchip_dma1, 0x0030);
+check_member(dramc_nao_regs, misc_statusa, 0x0080);
+check_member(dramc_nao_regs, special_status, 0x0084);
+check_member(dramc_nao_regs, spcmdresp, 0x0088);
+check_member(dramc_nao_regs, mrr_status, 0x008c);
+check_member(dramc_nao_regs, mrr_status2, 0x0090);
+check_member(dramc_nao_regs, mrrdata0, 0x0094);
+check_member(dramc_nao_regs, mrrdata1, 0x0098);
+check_member(dramc_nao_regs, mrrdata2, 0x009c);
+check_member(dramc_nao_regs, mrrdata3, 0x00a0);
+check_member(dramc_nao_regs, drs_status, 0x00a8);
+check_member(dramc_nao_regs, jmeter_st, 0x00bc);
+check_member(dramc_nao_regs, tcmdo1lat, 0x00c0);
+check_member(dramc_nao_regs, rdqc_cmp, 0x00c4);
+check_member(dramc_nao_regs, ckphchk_status, 0x00c8);
+check_member(dramc_nao_regs, hwmrr_push2pop_cnt, 0x010c);
+check_member(dramc_nao_regs, hwmrr_status, 0x0110);
+check_member(dramc_nao_regs, testrpt, 0x0120);
+check_member(dramc_nao_regs, cmp_err, 0x0124);
+check_member(dramc_nao_regs, test_abit_status1, 0x0128);
+check_member(dramc_nao_regs, test_abit_status2, 0x012c);
+check_member(dramc_nao_regs, test_abit_status3, 0x0130);
+check_member(dramc_nao_regs, test_abit_status4, 0x0134);
+check_member(dramc_nao_regs, dqsdly0, 0x0150);
+check_member(dramc_nao_regs, dq_cal_max[0], 0x0154);
+check_member(dramc_nao_regs, dqs_cal_min[0], 0x0174);
+check_member(dramc_nao_regs, dqs_cal_max[0], 0x0194);
+check_member(dramc_nao_regs, dqical0, 0x01b4);
+check_member(dramc_nao_regs, dqical1, 0x01b8);
+check_member(dramc_nao_regs, dqical2, 0x01bc);
+check_member(dramc_nao_regs, dqical3, 0x01c0);
+check_member(dramc_nao_regs, testchip_dma_status[0], 0x0200);
+check_member(dramc_nao_regs, refresh_pop_counter, 0x0300);
+check_member(dramc_nao_regs, freerun_26m_counter, 0x0304);
+check_member(dramc_nao_regs, dramc_idle_counter, 0x0308);
+check_member(dramc_nao_regs, r2r_page_hit_counter, 0x030c);
+check_member(dramc_nao_regs, r2r_page_miss_counter, 0x0310);
+check_member(dramc_nao_regs, r2r_interbank_counter, 0x0314);
+check_member(dramc_nao_regs, r2w_page_hit_counter, 0x0318);
+check_member(dramc_nao_regs, r2w_page_miss_counter, 0x031c);
+check_member(dramc_nao_regs, r2w_interbank_counter, 0x0320);
+check_member(dramc_nao_regs, w2r_page_hit_counter, 0x0324);
+check_member(dramc_nao_regs, w2r_page_miss_counter, 0x0328);
+check_member(dramc_nao_regs, w2r_interbank_counter, 0x032c);
+check_member(dramc_nao_regs, w2w_page_hit_counter, 0x0330);
+check_member(dramc_nao_regs, w2w_page_miss_counter, 0x0334);
+check_member(dramc_nao_regs, w2w_interbank_counter, 0x0338);
+check_member(dramc_nao_regs, dq0_toggle_counter, 0x036c);
+check_member(dramc_nao_regs, dq1_toggle_counter, 0x0370);
+check_member(dramc_nao_regs, dq2_toggle_counter, 0x0374);
+check_member(dramc_nao_regs, dq3_toggle_counter, 0x0378);
+check_member(dramc_nao_regs, dq0_toggle_counter_r, 0x037c);
+check_member(dramc_nao_regs, dq1_toggle_counter_r, 0x0380);
+check_member(dramc_nao_regs, dq2_toggle_counter_r, 0x0384);
+check_member(dramc_nao_regs, dq3_toggle_counter_r, 0x0388);
+check_member(dramc_nao_regs, read_bytes_counter, 0x038c);
+check_member(dramc_nao_regs, write_bytes_counter, 0x0390);
+check_member(dramc_nao_regs, dqssamplev, 0x0400);
+check_member(dramc_nao_regs, dqsgnwcnt[0], 0x0408);
+check_member(dramc_nao_regs, toggle_cnt, 0x0420);
+check_member(dramc_nao_regs, dqs0_err_cnt, 0x0424);
+check_member(dramc_nao_regs, dq_err_cnt0, 0x0428);
+check_member(dramc_nao_regs, dqs1_err_cnt, 0x042c);
+check_member(dramc_nao_regs, dq_err_cnt1, 0x0430);
+check_member(dramc_nao_regs, dqs2_err_cnt, 0x0434);
+check_member(dramc_nao_regs, dq_err_cnt2, 0x0438);
+check_member(dramc_nao_regs, dqs3_err_cnt, 0x043c);
+check_member(dramc_nao_regs, dq_err_cnt3, 0x0440);
+check_member(dramc_nao_regs, iorgcnt, 0x0450);
+check_member(dramc_nao_regs, dqsg_retry_state, 0x0454);
+check_member(dramc_nao_regs, dqsg_retry_state1, 0x0458);
+check_member(dramc_nao_regs, impcal_status1, 0x0460);
+check_member(dramc_nao_regs, impcal_status2, 0x0464);
+check_member(dramc_nao_regs, dqdrv_status, 0x0468);
+check_member(dramc_nao_regs, cmddrv_status, 0x046c);
+check_member(dramc_nao_regs, cmddrv1, 0x0470);
+check_member(dramc_nao_regs, cmddrv2, 0x0474);
+
+struct dramc_ao_regs_rk {
+	uint32_t dqsosc;
+	uint32_t rsvd_1[5];
+	uint32_t dummy_rd_wdata0;
+	uint32_t dummy_rd_wdata1;
+	uint32_t dummy_rd_wdata2;
+	uint32_t dummy_rd_wdata3;
+	uint32_t dummy_rd_adr;
+	uint32_t dummy_rd_bk;
+	uint32_t pre_tdqsck[12];
+	uint32_t rsvd_2[40];
+};
+
+struct dramc_ao_regs_shu_rk {
+	uint32_t dqsctl;
+	uint32_t dqsien;
+	uint32_t dqscal;
+	uint32_t fine_tune;
+	uint32_t dqsosc;
+	uint32_t rsvd_1[2];
+	uint32_t selph_odten0;
+	uint32_t selph_odten1;
+	uint32_t selph_dqsg0;
+	uint32_t selph_dqsg1;
+	uint32_t selph_dq[4];
+	uint32_t rsvd_2[1];
+	uint32_t dqs2dq_cal1;
+	uint32_t dqs2dq_cal2;
+	uint32_t dqs2dq_cal3;
+	uint32_t dqs2dq_cal4;
+	uint32_t dqs2dq_cal5;
+	uint32_t rsvd_3[43];
+};
+
+struct dramc_ao_regs {
+	uint32_t ddrconf0;
+	uint32_t dramctrl;
+	uint32_t misctl0;
+	uint32_t perfctl0;
+	uint32_t arbctl;
+	uint32_t reserved0[2];
+	uint32_t rstmask;
+	uint32_t padctrl;
+	uint32_t ckectrl;
+	uint32_t drsctrl;
+	uint32_t reserved1[2];
+	uint32_t rkcfg;
+	uint32_t dramc_pd_ctrl;
+	uint32_t clkar;
+	uint32_t clkctrl;
+	uint32_t selfref_hwsave_flag;
+	uint32_t srefctrl;
+	uint32_t refctrl0;
+	uint32_t refctrl1;
+	uint32_t refratre_filter;
+	uint32_t zqcs;
+	uint32_t mrs;
+	uint32_t spcmd;
+	uint32_t spcmdctrl;
+	uint32_t ppr_ctrl;
+	uint32_t mpc_option;
+	uint32_t refque_cnt;
+	uint32_t hw_mrr_fun;
+	uint32_t mrr_bit_mux1;
+	uint32_t mrr_bit_mux2;
+	uint32_t mrr_bit_mux3;
+	uint32_t mrr_bit_mux4;
+	uint32_t reserved2[1];
+	uint32_t test2_5;
+	uint32_t test2_0;
+	uint32_t test2_1;
+	uint32_t test2_2;
+	uint32_t test2_3;
+	uint32_t test2_4;
+	uint32_t wdt_dbg_signal;
+	uint32_t reserved3[1];
+	uint32_t lbtest;
+	uint32_t catraining1;
+	uint32_t catraining2;
+	uint32_t reserved4[1];
+	uint32_t write_lev;
+	uint32_t mr_golden;
+	uint32_t slp4_testmode;
+	uint32_t dqsoscr;
+	uint32_t reserved5[1];
+	uint32_t dummy_rd;
+	uint32_t shuctrl;
+	uint32_t shuctrl1;
+	uint32_t shuctrl2;
+	uint32_t shuctrl3;
+	uint32_t shustatus;
+	uint32_t reserved6[70];
+	uint32_t stbcal;
+	uint32_t stbcal1;
+	uint32_t stbcal2;
+	uint32_t eyescan;
+	uint32_t dvfsdll;
+	uint32_t reserved7[1];
+	uint32_t pre_tdqsck[4];
+	uint32_t reserved8[1];
+	uint32_t impcal;
+	uint32_t impedamce_ctrl1;
+	uint32_t impedamce_ctrl2;
+	uint32_t impedamce_ctrl3;
+	uint32_t impedamce_ctrl4;
+	uint32_t dramc_dbg_sel1;
+	uint32_t dramc_dbg_sel2;
+	uint32_t rsvd_10[46];
+	struct dramc_ao_regs_rk rk[3];
+	uint32_t rsvd_16[64];
+	struct {
+		uint32_t rsvd0[64];
+		uint32_t actim[7];
+		uint32_t actim_xrt;
+		uint32_t ac_time_05t;
+		uint32_t ac_derating0;
+		uint32_t ac_derating1;
+		uint32_t rsvd1[1];
+		uint32_t ac_derating_05t;
+		uint32_t rsvd2[3];
+		uint32_t conf[4];
+		uint32_t stbcal;
+		uint32_t dqsoscthrd;
+		uint32_t rankctl;
+		uint32_t ckectrl;
+		uint32_t odtctrl;
+		uint32_t impcal1;
+		uint32_t dqsosc_prd;
+		uint32_t dqsoscr;
+		uint32_t dqsoscr2;
+		uint32_t rodtenstb;
+		uint32_t pipe;
+		uint32_t test1;
+		uint32_t selph_ca1;
+		uint32_t selph_ca2;
+		uint32_t selph_ca3;
+		uint32_t selph_ca4;
+		uint32_t selph_ca5;
+		uint32_t selph_ca6;
+		uint32_t selph_ca7;
+		uint32_t selph_ca8;
+		uint32_t selph_dqs0;
+		uint32_t selph_dqs1;
+		uint32_t drving[6];
+		uint32_t wodt;
+		uint32_t dqsg;
+		uint32_t scintv;
+		uint32_t misc;
+		uint32_t dqs2dq_tx;
+		uint32_t hwset_mr2;
+		uint32_t hwset_mr13;
+		uint32_t hwset_vrcg;
+		uint32_t rsvd3[72];
+		union {
+			struct dramc_ao_regs_shu_rk rk[3];
+			struct {
+				uint32_t rsvd_63[149];
+				uint32_t dqsg_retry;
+			};
+		};
+	} shu[4];
+	uint32_t dramc_ao_regs_end;
+};
+
+check_member(dramc_ao_regs, ddrconf0, 0x0000);
+check_member(dramc_ao_regs, dramctrl, 0x0004);
+check_member(dramc_ao_regs, misctl0, 0x0008);
+check_member(dramc_ao_regs, perfctl0, 0x000c);
+check_member(dramc_ao_regs, arbctl, 0x0010);
+check_member(dramc_ao_regs, rstmask, 0x001c);
+check_member(dramc_ao_regs, padctrl, 0x0020);
+check_member(dramc_ao_regs, ckectrl, 0x0024);
+check_member(dramc_ao_regs, drsctrl, 0x0028);
+check_member(dramc_ao_regs, rkcfg, 0x0034);
+check_member(dramc_ao_regs, dramc_pd_ctrl, 0x0038);
+check_member(dramc_ao_regs, clkar, 0x003c);
+check_member(dramc_ao_regs, clkctrl, 0x0040);
+check_member(dramc_ao_regs, selfref_hwsave_flag, 0x0044);
+check_member(dramc_ao_regs, srefctrl, 0x0048);
+check_member(dramc_ao_regs, refctrl0, 0x004c);
+check_member(dramc_ao_regs, refctrl1, 0x0050);
+check_member(dramc_ao_regs, refratre_filter, 0x0054);
+check_member(dramc_ao_regs, zqcs, 0x0058);
+check_member(dramc_ao_regs, mrs, 0x005c);
+check_member(dramc_ao_regs, spcmd, 0x0060);
+check_member(dramc_ao_regs, spcmdctrl, 0x0064);
+check_member(dramc_ao_regs, ppr_ctrl, 0x0068);
+check_member(dramc_ao_regs, mpc_option, 0x006c);
+check_member(dramc_ao_regs, refque_cnt, 0x0070);
+check_member(dramc_ao_regs, hw_mrr_fun, 0x0074);
+check_member(dramc_ao_regs, mrr_bit_mux1, 0x0078);
+check_member(dramc_ao_regs, mrr_bit_mux2, 0x007c);
+check_member(dramc_ao_regs, mrr_bit_mux3, 0x0080);
+check_member(dramc_ao_regs, mrr_bit_mux4, 0x0084);
+check_member(dramc_ao_regs, test2_5, 0x008c);
+check_member(dramc_ao_regs, test2_0, 0x0090);
+check_member(dramc_ao_regs, test2_1, 0x0094);
+check_member(dramc_ao_regs, test2_2, 0x0098);
+check_member(dramc_ao_regs, test2_3, 0x009c);
+check_member(dramc_ao_regs, test2_4, 0x00a0);
+check_member(dramc_ao_regs, wdt_dbg_signal, 0x00a4);
+check_member(dramc_ao_regs, lbtest, 0x00ac);
+check_member(dramc_ao_regs, catraining1, 0x00b0);
+check_member(dramc_ao_regs, catraining2, 0x00b4);
+check_member(dramc_ao_regs, write_lev, 0x00bc);
+check_member(dramc_ao_regs, mr_golden, 0x00c0);
+check_member(dramc_ao_regs, slp4_testmode, 0x00c4);
+check_member(dramc_ao_regs, dqsoscr, 0x00c8);
+check_member(dramc_ao_regs, dummy_rd, 0x00d0);
+check_member(dramc_ao_regs, shuctrl, 0x00d4);
+check_member(dramc_ao_regs, shuctrl1, 0x00d8);
+check_member(dramc_ao_regs, shuctrl2, 0x00dc);
+check_member(dramc_ao_regs, shuctrl3, 0x00e0);
+check_member(dramc_ao_regs, shustatus, 0x00e4);
+check_member(dramc_ao_regs, stbcal, 0x0200);
+check_member(dramc_ao_regs, stbcal1, 0x0204);
+check_member(dramc_ao_regs, stbcal2, 0x0208);
+check_member(dramc_ao_regs, eyescan, 0x020c);
+check_member(dramc_ao_regs, dvfsdll, 0x0210);
+check_member(dramc_ao_regs, pre_tdqsck[0], 0x0218);
+check_member(dramc_ao_regs, pre_tdqsck[1], 0x021c);
+check_member(dramc_ao_regs, pre_tdqsck[2], 0x0220);
+check_member(dramc_ao_regs, pre_tdqsck[3], 0x0224);
+check_member(dramc_ao_regs, impcal, 0x022c);
+check_member(dramc_ao_regs, impedamce_ctrl1, 0x0230);
+check_member(dramc_ao_regs, impedamce_ctrl2, 0x0234);
+check_member(dramc_ao_regs, impedamce_ctrl3, 0x0238);
+check_member(dramc_ao_regs, impedamce_ctrl4, 0x023c);
+check_member(dramc_ao_regs, dramc_dbg_sel1, 0x0240);
+check_member(dramc_ao_regs, dramc_dbg_sel2, 0x0244);
+check_member(dramc_ao_regs, shu[0].actim[0], 0x0800);
+check_member(dramc_ao_regs, shu[0].actim_xrt, 0x081c);
+check_member(dramc_ao_regs, shu[0].ac_time_05t, 0x0820);
+check_member(dramc_ao_regs, shu[0].ac_derating0, 0x0824);
+check_member(dramc_ao_regs, shu[0].ac_derating1, 0x0828);
+check_member(dramc_ao_regs, shu[0].ac_derating_05t, 0x0830);
+check_member(dramc_ao_regs, shu[0].conf[0], 0x0840);
+check_member(dramc_ao_regs, shu[0].rankctl, 0x0858);
+check_member(dramc_ao_regs, shu[0].ckectrl, 0x085c);
+check_member(dramc_ao_regs, shu[0].odtctrl, 0x0860);
+check_member(dramc_ao_regs, shu[0].impcal1, 0x0864);
+check_member(dramc_ao_regs, shu[0].dqsosc_prd, 0x0868);
+check_member(dramc_ao_regs, shu[0].dqsoscr, 0x086c);
+check_member(dramc_ao_regs, shu[0].dqsoscr2, 0x0870);
+check_member(dramc_ao_regs, shu[0].rodtenstb, 0x0874);
+check_member(dramc_ao_regs, shu[0].pipe, 0x0878);
+check_member(dramc_ao_regs, shu[0].test1, 0x087c);
+check_member(dramc_ao_regs, shu[0].selph_ca1, 0x0880);
+check_member(dramc_ao_regs, shu[0].selph_dqs0, 0x08a0);
+check_member(dramc_ao_regs, shu[0].selph_dqs1, 0x08a4);
+check_member(dramc_ao_regs, shu[0].drving[0], 0x08a8);
+check_member(dramc_ao_regs, shu[0].wodt, 0x08c0);
+check_member(dramc_ao_regs, shu[0].dqsg, 0x08c4);
+check_member(dramc_ao_regs, shu[0].scintv, 0x08c8);
+check_member(dramc_ao_regs, shu[0].misc, 0x08cc);
+check_member(dramc_ao_regs, shu[0].dqs2dq_tx, 0x08d0);
+check_member(dramc_ao_regs, shu[0].hwset_mr2, 0x08d4);
+check_member(dramc_ao_regs, shu[0].hwset_mr13, 0x08d8);
+check_member(dramc_ao_regs, shu[0].hwset_vrcg, 0x08dc);
+check_member(dramc_ao_regs, shu[0].rk[0].dqsctl, 0x0A00);
+check_member(dramc_ao_regs, shu[0].dqsg_retry, 0x0c54);
+check_member(dramc_ao_regs, shu[1].dqsg_retry, 0x1254);
+check_member(dramc_ao_regs, shu[2].dqsg_retry, 0x1854);
+check_member(dramc_ao_regs, shu[3].dqsg_retry, 0x1e54);
+
+struct dramc_ddrphy_regs_misc_stberr_rk {
+	uint32_t r;
+	uint32_t f;
+};
+
+struct dramc_ddrphy_regs_shu_rk {
+	struct {
+		uint32_t dq[8];
+		uint32_t rsvd_20[12];
+	} b[2];
+	uint32_t ca_cmd[10];
+	uint32_t rsvd_22[14];
+};
+
+struct dramc_ddrphy_ao_regs {
+	uint32_t pll1;
+	uint32_t pll2;
+	uint32_t pll3;
+	uint32_t pll4;
+	uint32_t pll5;
+	uint32_t pll6;
+	uint32_t pll7;
+	uint32_t pll8;
+	uint32_t pll9;
+	uint32_t pll10;
+	uint32_t pll11;
+	uint32_t pll12;
+	uint32_t pll13;
+	uint32_t pll14;
+	uint32_t pll15;
+	uint32_t pll16;
+	uint32_t reserved0[16];
+	struct {
+		uint32_t dll_fine_tune[6];
+		uint32_t dq[10];
+		uint32_t _rsvd_0[4];
+		uint32_t tx_mck;
+		uint32_t _rsvd_1[11];
+	} b[2];
+	uint32_t ca_dll_fine_tune[6];
+	uint32_t ca_cmd[11];
+	uint32_t rfu_0x1c4;
+	uint32_t rfu_0x1c8;
+	uint32_t rfu_0x1cc;
+	uint32_t ca_tx_mck;
+	uint32_t reserved3[11];
+	uint32_t misc_extlb[24];
+	uint32_t dvfs_emi_clk;
+	uint32_t misc_vref_ctrl;
+	uint32_t misc_imp_ctrl0;
+	uint32_t misc_imp_ctrl1;
+	uint32_t misc_shu_opt;
+	uint32_t misc_spm_ctrl0;
+	uint32_t misc_spm_ctrl1;
+	uint32_t misc_spm_ctrl2;
+	uint32_t misc_spm_ctrl3;
+	uint32_t misc_cg_ctrl0;
+	uint32_t misc_cg_ctrl1;
+	uint32_t misc_cg_ctrl2;
+	uint32_t misc_cg_ctrl3;
+	uint32_t misc_cg_ctrl4;
+	uint32_t misc_cg_ctrl5;
+	uint32_t misc_ctrl0;
+	uint32_t misc_ctrl1;
+	uint32_t misc_ctrl2;
+	uint32_t misc_ctrl3;
+	uint32_t misc_ctrl4;
+	uint32_t misc_ctrl5;
+	uint32_t misc_extlb_rx[21];
+	uint32_t ckmux_sel;
+	uint32_t reserved4[129];
+	uint32_t misc_stberr_rk0_r;
+	uint32_t misc_stberr_rk0_f;
+	uint32_t misc_stberr_rk1_r;
+	uint32_t misc_stberr_rk1_f;
+	uint32_t misc_stberr_rk2_r;
+	uint32_t misc_stberr_rk2_f;
+	uint32_t reserved5[46];
+	uint32_t misc_rxdvs[3];
+	uint32_t rfu_0x5ec;
+	uint32_t b0_rxdvs[2];
+	uint32_t rfu_0x5f8;
+	uint32_t rfu_0x5fc;
+	union {
+		struct {
+			struct {
+				uint32_t rxdvs[8];
+				uint32_t _rsvd[24];
+			} b[2];
+			uint32_t rxdvs[10];
+			uint32_t _rsvd_b[54];
+		} r[3];
+		struct {
+			uint32_t rsvd_2[28];
+			uint32_t b1_rxdvs[2];
+			uint32_t rsvd_3[30];
+			uint32_t ca_rxdvs0;
+			uint32_t ca_rxdvs1;
+			uint32_t rsvd_4[2];
+			uint32_t r0_ca_rxdvs[10];
+		};
+	};
+
+	struct {
+		struct {
+			uint32_t dq[13];
+			uint32_t dll[2];
+			uint32_t rsvd_16[17];
+		} b[2];
+		uint32_t ca_cmd[13];
+		uint32_t ca_dll[2];
+		uint32_t rsvd_18[17];
+		uint32_t pll[16];
+		uint32_t rsvd_19[4];
+		uint32_t pll20;
+		uint32_t pll21;
+		uint32_t rsvd_20[6];
+		uint32_t misc0;
+		uint32_t rsvd_21[3];
+		struct dramc_ddrphy_regs_shu_rk rk[3];
+	} shu[4];
+};
+
+check_member(dramc_ddrphy_ao_regs, pll1, 0x0000);
+check_member(dramc_ddrphy_ao_regs, b[0].dll_fine_tune[0], 0x0080);
+check_member(dramc_ddrphy_ao_regs, b[0].dq[0], 0x0098);
+check_member(dramc_ddrphy_ao_regs, b[0].tx_mck, 0x00d0);
+check_member(dramc_ddrphy_ao_regs, ca_dll_fine_tune[0], 0x0180);
+check_member(dramc_ddrphy_ao_regs, ca_cmd[0], 0x0198);
+check_member(dramc_ddrphy_ao_regs, ca_tx_mck, 0x01d0);
+check_member(dramc_ddrphy_ao_regs, misc_extlb[0], 0x0200);
+check_member(dramc_ddrphy_ao_regs, dvfs_emi_clk, 0x0260);
+check_member(dramc_ddrphy_ao_regs, misc_vref_ctrl, 0x0264);
+check_member(dramc_ddrphy_ao_regs, misc_imp_ctrl0, 0x0268);
+check_member(dramc_ddrphy_ao_regs, misc_imp_ctrl1, 0x026c);
+check_member(dramc_ddrphy_ao_regs, misc_shu_opt, 0x0270);
+check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl0, 0x0274);
+check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl1, 0x0278);
+check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl2, 0x027c);
+check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl3, 0x0280);
+check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl0, 0x0284);
+check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl1, 0x0288);
+check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl2, 0x028c);
+check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl3, 0x0290);
+check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl4, 0x0294);
+check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl5, 0x0298);
+check_member(dramc_ddrphy_ao_regs, misc_ctrl0, 0x029c);
+check_member(dramc_ddrphy_ao_regs, misc_ctrl1, 0x02a0);
+check_member(dramc_ddrphy_ao_regs, misc_ctrl2, 0x02a4);
+check_member(dramc_ddrphy_ao_regs, misc_ctrl3, 0x02a8);
+check_member(dramc_ddrphy_ao_regs, misc_ctrl4, 0x02ac);
+check_member(dramc_ddrphy_ao_regs, misc_ctrl5, 0x02b0);
+check_member(dramc_ddrphy_ao_regs, misc_extlb_rx[0], 0x02b4);
+check_member(dramc_ddrphy_ao_regs, ckmux_sel, 0x0308);
+check_member(dramc_ddrphy_ao_regs, misc_rxdvs[0], 0x05e0);
+check_member(dramc_ddrphy_ao_regs, misc_rxdvs[1], 0x05e4);
+check_member(dramc_ddrphy_ao_regs, misc_rxdvs[2], 0x05e8);
+check_member(dramc_ddrphy_ao_regs, rfu_0x5ec, 0x05ec);
+check_member(dramc_ddrphy_ao_regs, b0_rxdvs[0], 0x05f0);
+check_member(dramc_ddrphy_ao_regs, r[0].b[0].rxdvs[0], 0x0600);
+check_member(dramc_ddrphy_ao_regs, b1_rxdvs[0], 0x0670);
+check_member(dramc_ddrphy_ao_regs, r[0].b[1].rxdvs[0], 0x0680);
+check_member(dramc_ddrphy_ao_regs, ca_rxdvs0, 0x06F0);
+check_member(dramc_ddrphy_ao_regs, r0_ca_rxdvs[0], 0x0700);
+check_member(dramc_ddrphy_ao_regs, r[1].b[1].rxdvs[0], 0x0880);
+check_member(dramc_ddrphy_ao_regs, r[1].rxdvs[0], 0x0900);
+check_member(dramc_ddrphy_ao_regs, shu[0].b[0].dq[0], 0x0c00);
+check_member(dramc_ddrphy_ao_regs, shu[0].b[1].dq[6], 0x0C98);
+check_member(dramc_ddrphy_ao_regs, shu[0].ca_cmd[0], 0x0d00);
+check_member(dramc_ddrphy_ao_regs, shu[0].ca_dll[0], 0x0d34);
+check_member(dramc_ddrphy_ao_regs, shu[0].pll[0], 0x0d80);
+check_member(dramc_ddrphy_ao_regs, shu[0].misc0, 0x0DF0);
+check_member(dramc_ddrphy_ao_regs, shu[0].rk[0].b[0].dq[0], 0x0e00);
+check_member(dramc_ddrphy_ao_regs, shu[0].rk[0].ca_cmd[9], 0x0ec4);
+check_member(dramc_ddrphy_ao_regs, shu[0].rk[1].b[0].dq[0], 0x0f00);
+check_member(dramc_ddrphy_ao_regs, shu[0].rk[1].ca_cmd[9], 0x0fc4);
+check_member(dramc_ddrphy_ao_regs, shu[0].rk[2].b[0].dq[0], 0x1000);
+check_member(dramc_ddrphy_ao_regs, shu[0].rk[2].ca_cmd[9], 0x10c4);
+check_member(dramc_ddrphy_ao_regs, shu[2].b[0].dq[0], 0x1600);
+check_member(dramc_ddrphy_ao_regs, shu[2].b[1].dq[0], 0x1680);
+check_member(dramc_ddrphy_ao_regs, shu[2].ca_cmd[0], 0x1700);
+check_member(dramc_ddrphy_ao_regs, shu[2].ca_dll[0], 0x1734);
+check_member(dramc_ddrphy_ao_regs, shu[2].pll[0], 0x1780);
+check_member(dramc_ddrphy_ao_regs, shu[2].misc0, 0x17F0);
+check_member(dramc_ddrphy_ao_regs, shu[2].rk[0].b[0].dq[0], 0x1800);
+check_member(dramc_ddrphy_ao_regs, shu[2].rk[0].ca_cmd[0], 0x18A0);
+check_member(dramc_ddrphy_ao_regs, shu[2].rk[1].b[0].dq[0], 0x1900);
+check_member(dramc_ddrphy_ao_regs, shu[2].rk[1].ca_cmd[0], 0x19A0);
+check_member(dramc_ddrphy_ao_regs, shu[2].rk[2].b[0].dq[0], 0x1A00);
+check_member(dramc_ddrphy_ao_regs, shu[2].rk[2].ca_cmd[0], 0x1AA0);
+check_member(dramc_ddrphy_ao_regs, shu[3].ca_cmd[0], 0x1C00);
+check_member(dramc_ddrphy_ao_regs, shu[3].pll[0], 0x1C80);
+check_member(dramc_ddrphy_ao_regs, shu[3].pll20, 0x1CD0);
+check_member(dramc_ddrphy_ao_regs, shu[3].misc0, 0x1CF0);
+check_member(dramc_ddrphy_ao_regs, shu[3].rk[0].ca_cmd[9], 0x1DC4);
+check_member(dramc_ddrphy_ao_regs, shu[3].rk[1].ca_cmd[9], 0x1EC4);
+check_member(dramc_ddrphy_ao_regs, shu[3].rk[2].ca_cmd[9], 0x1FC4);
+
+struct dramc_ddrphy_nao_regs {
+	uint32_t misc_sta_extlb[3];
+	uint32_t reserved0[29];
+	uint32_t misc_dq_rxdly_trro[32];
+	uint32_t misc_ca_rxdly_trro[32];
+	uint32_t misc_dqo1;
+	uint32_t misc_cao1;
+	uint32_t misc_ad_rx_dq_o1;
+	uint32_t misc_ad_rx_cmd_o1;
+	uint32_t misc_phy_rgs_dq;
+	uint32_t misc_phy_rgs_cmd;
+	uint32_t misc_phy_stben_b0;
+	uint32_t misc_phy_stben_b1;
+	uint32_t misc_phy_rgs_stben_cmd;
+	uint32_t dramc_ddrphy_nao_regs_end;
+};
+
+check_member(dramc_ddrphy_nao_regs, misc_sta_extlb[0], 0x0);
+check_member(dramc_ddrphy_nao_regs, misc_dq_rxdly_trro[0], 0x080);
+check_member(dramc_ddrphy_nao_regs, misc_dqo1, 0x0180);
+check_member(dramc_ddrphy_nao_regs, misc_cao1, 0x0184);
+check_member(dramc_ddrphy_nao_regs, misc_phy_rgs_dq, 0x0190);
+check_member(dramc_ddrphy_nao_regs, misc_phy_rgs_cmd, 0x0194);
+check_member(dramc_ddrphy_nao_regs, misc_phy_stben_b0, 0x0198);
+check_member(dramc_ddrphy_nao_regs, misc_phy_rgs_stben_cmd, 0x01A0);
+
+struct emi_regs {
+	uint32_t cona;
+	uint32_t reserved0[1];
+	uint32_t conb;
+	uint32_t reserved1[1];
+	uint32_t conc;
+	uint32_t reserved2[1];
+	uint32_t cond;
+	uint32_t reserved3[1];
+	uint32_t cone;
+	uint32_t reserved4[1];
+	uint32_t conf;
+	uint32_t reserved5[1];
+	uint32_t cong;
+	uint32_t reserved6[1];
+	uint32_t conh;
+	uint32_t conh_2nd;
+	uint32_t coni;
+	uint32_t reserved7[1];
+	uint32_t conj;
+	uint32_t reserved8[5];
+	uint32_t conm;
+	uint32_t reserved9[1];
+	uint32_t conn;
+	uint32_t reserved10[1];
+	uint32_t cono;
+	uint32_t reserved11[1];
+	uint32_t mdct;
+	uint32_t mdct_2nd;
+	uint32_t reserved12[20];
+	uint32_t iocl;
+	uint32_t iocl_2nd;
+	uint32_t iocm;
+	uint32_t iocm_2nd;
+	uint32_t reserved13[2];
+	uint32_t testb;
+	uint32_t reserved14[1];
+	uint32_t testc;
+	uint32_t reserved15[1];
+	uint32_t testd;
+	uint32_t reserved16[1];
+	uint32_t arba;
+	uint32_t reserved17[1];
+	uint32_t arbb;
+	uint32_t reserved18[1];
+	uint32_t arbc;
+	uint32_t reserved19[1];
+	uint32_t arbd;
+	uint32_t reserved20[1];
+	uint32_t arbe;
+	uint32_t reserved21[1];
+	uint32_t arbf;
+	uint32_t reserved22[1];
+	uint32_t arbg;
+	uint32_t reserved23[1];
+	uint32_t arbh;
+	uint32_t reserved24[1];
+	uint32_t arbi;
+	uint32_t arbi_2nd;
+	uint32_t reserved25[2];
+	uint32_t arbk;
+	uint32_t arbk_2nd;
+	uint32_t slct;
+	uint32_t reserved26[1];
+	uint32_t mpud_st[32];
+	uint32_t reserved27[4];
+	uint32_t mpus;
+	uint32_t reserved28[1];
+	uint32_t mput;
+	uint32_t mput_2nd;
+	uint32_t d_st2[32];
+	uint32_t reserved29[96];
+	uint32_t bmen;
+	uint32_t bstp;
+	uint32_t bcnt;
+	uint32_t reserved30[1];
+	uint32_t tact;
+	uint32_t reserved31[1];
+	uint32_t tsct;
+	uint32_t reserved32[1];
+	uint32_t wact;
+	uint32_t reserved33[1];
+	uint32_t wsct;
+	uint32_t reserved34[1];
+	uint32_t bact;
+	uint32_t reserved35[1];
+	uint32_t bsct;
+	uint32_t reserved36[1];
+	uint32_t msel;
+	uint32_t reserved37[1];
+	uint32_t tsct2;
+	uint32_t reserved38[1];
+	uint32_t tsct3;
+	uint32_t reserved39[1];
+	uint32_t wsct2;
+	uint32_t reserved40[1];
+	uint32_t wsct3;
+	uint32_t wsct4;
+	uint32_t msel2;
+	uint32_t reserved41[1];
+	uint32_t msel3;
+	uint32_t reserved42[1];
+	uint32_t msel4;
+	uint32_t reserved43[1];
+	uint32_t msel5;
+	uint32_t reserved44[1];
+	uint32_t msel6;
+	uint32_t reserved45[1];
+	uint32_t msel7;
+	uint32_t reserved46[1];
+	uint32_t msel8;
+	uint32_t reserved47[1];
+	uint32_t msel9;
+	uint32_t reserved48[1];
+	uint32_t msel10;
+	uint32_t reserved49[1];
+	uint32_t bmid0;
+	uint32_t bmid1;
+	uint32_t bmid2;
+	uint32_t bmid3;
+	uint32_t bmid4;
+	uint32_t bmid5;
+	uint32_t bmid6;
+	uint32_t bmid7;
+	uint32_t bmid8;
+	uint32_t bmid9;
+	uint32_t bmid10;
+	uint32_t reserved50[1];
+	uint32_t bmen1;
+	uint32_t reserved51[1];
+	uint32_t bmen2;
+	uint32_t reserved52[3];
+	uint32_t bmrw0;
+	uint32_t bmrw1;
+	uint32_t ttype1;
+	uint32_t reserved53[1];
+	uint32_t ttype2;
+	uint32_t reserved54[1];
+	uint32_t ttype3;
+	uint32_t reserved55[1];
+	uint32_t ttype4;
+	uint32_t reserved56[1];
+	uint32_t ttype5;
+	uint32_t reserved57[1];
+	uint32_t ttype6;
+	uint32_t reserved58[1];
+	uint32_t ttype7;
+	uint32_t reserved59[1];
+	uint32_t ttype8;
+	uint32_t reserved60[1];
+	uint32_t ttype9;
+	uint32_t reserved61[1];
+	uint32_t ttype10;
+	uint32_t reserved62[1];
+	uint32_t ttype11;
+	uint32_t reserved63[1];
+	uint32_t ttype12;
+	uint32_t reserved64[1];
+	uint32_t ttype13;
+	uint32_t reserved65[1];
+	uint32_t ttype14;
+	uint32_t reserved66[1];
+	uint32_t ttype15;
+	uint32_t reserved67[1];
+	uint32_t ttype16;
+	uint32_t reserved68[1];
+	uint32_t ttype17;
+	uint32_t reserved69[1];
+	uint32_t ttype18;
+	uint32_t reserved70[1];
+	uint32_t ttype19;
+	uint32_t reserved71[1];
+	uint32_t ttype20;
+	uint32_t reserved72[1];
+	uint32_t ttype21;
+	uint32_t reserved73[3];
+	uint32_t bwct0;
+	uint32_t bwct1;
+	uint32_t bwct2;
+	uint32_t bwct3;
+	uint32_t bwct4;
+	uint32_t bwst0;
+	uint32_t bwst1;
+	uint32_t reserved74[1];
+	uint32_t ex_con;
+	uint32_t ex_st0;
+	uint32_t ex_st1;
+	uint32_t ex_st2;
+	uint32_t wp_adr;
+	uint32_t wp_adr_2nd;
+	uint32_t wp_ctrl;
+	uint32_t reserved75[1];
+	uint32_t chker;
+	uint32_t chker_type;
+	uint32_t chker_adr;
+	uint32_t chker_adr_2nd;
+	uint32_t reserved76[40];
+	uint32_t bwct0_2nd;
+	uint32_t reserved77[43];
+	uint32_t ltct0_2nd;
+	uint32_t ltct1_2nd;
+	uint32_t ltct2_2nd;
+	uint32_t ltct3_2nd;
+	uint32_t reserved78[4];
+	uint32_t bwct0_3rd;
+	uint32_t reserved79[3];
+	uint32_t bwct0_4th;
+	uint32_t reserved80[11];
+	uint32_t bwct0_5th;
+	uint32_t reserved81[19];
+	uint32_t slva;
+};
+
+check_member(emi_regs, cona, 0x0000);
+check_member(emi_regs, conb, 0x0008);
+check_member(emi_regs, conc, 0x0010);
+check_member(emi_regs, cond, 0x0018);
+check_member(emi_regs, cone, 0x0020);
+check_member(emi_regs, conf, 0x0028);
+check_member(emi_regs, cong, 0x0030);
+check_member(emi_regs, conh, 0x0038);
+check_member(emi_regs, conh_2nd, 0x003c);
+check_member(emi_regs, coni, 0x0040);
+check_member(emi_regs, conj, 0x0048);
+check_member(emi_regs, conm, 0x0060);
+check_member(emi_regs, conn, 0x0068);
+check_member(emi_regs, cono, 0x0070);
+check_member(emi_regs, mdct, 0x0078);
+check_member(emi_regs, mdct_2nd, 0x007c);
+check_member(emi_regs, iocl, 0x00d0);
+check_member(emi_regs, iocl_2nd, 0x00d4);
+check_member(emi_regs, iocm, 0x00d8);
+check_member(emi_regs, iocm_2nd, 0x00dc);
+check_member(emi_regs, testb, 0x00e8);
+check_member(emi_regs, testc, 0x00f0);
+check_member(emi_regs, testd, 0x00f8);
+check_member(emi_regs, arba, 0x0100);
+check_member(emi_regs, arbb, 0x0108);
+check_member(emi_regs, arbc, 0x0110);
+check_member(emi_regs, arbd, 0x0118);
+check_member(emi_regs, arbe, 0x0120);
+check_member(emi_regs, arbf, 0x0128);
+check_member(emi_regs, arbg, 0x0130);
+check_member(emi_regs, arbh, 0x0138);
+check_member(emi_regs, arbi, 0x0140);
+check_member(emi_regs, arbi_2nd, 0x0144);
+check_member(emi_regs, slct, 0x0158);
+
+struct chn_emi_regs {
+	uint32_t chn_cona;
+	uint32_t rsvd_1[1];
+	uint32_t chn_conb;
+	uint32_t rsvd_2[1];
+	uint32_t chn_conc;
+	uint32_t rsvd_3[1];
+	uint32_t chn_mdct;
+	uint32_t rsvd_4[11];
+	uint32_t chn_testb;
+	uint32_t rsvd_5[1];
+	uint32_t chn_testc;
+	uint32_t rsvd_6[1];
+	uint32_t chn_testd;
+	uint32_t rsvd_7[9];
+	uint32_t chn_md_pre_mask;
+	uint32_t rsvd_8[1];
+	uint32_t chn_md_pre_mask_shf;
+	uint32_t rsvd_9[45];
+	uint32_t chn_arbi;
+	uint32_t chn_arbi_2nd;
+	uint32_t chn_arbj;
+	uint32_t chn_arbj_2nd;
+	uint32_t chn_arbk;
+	uint32_t chn_arbk_2nd;
+	uint32_t chn_slct;
+	uint32_t chn_arb_ref;
+	uint32_t rsvd_10[20];
+	uint32_t chn_rkarb0;
+	uint32_t chn_rkarb1;
+	uint32_t chn_rkarb2;
+	uint32_t rsvd_11[144];
+	uint32_t chn_eco3;
+	uint32_t rsvd_12[196];
+	uint32_t chn_emi_shf0;
+	uint32_t chn_emi_regs_end;
+
+};
+
+check_member(chn_emi_regs, chn_cona, 0x0000);
+check_member(chn_emi_regs, chn_conb, 0x0008);
+check_member(chn_emi_regs, chn_conc, 0x0010);
+check_member(chn_emi_regs, chn_mdct, 0x0018);
+check_member(chn_emi_regs, chn_testb, 0x0048);
+check_member(chn_emi_regs, chn_testc, 0x0050);
+check_member(chn_emi_regs, chn_testd, 0x0058);
+check_member(chn_emi_regs, chn_md_pre_mask, 0x0080);
+check_member(chn_emi_regs, chn_md_pre_mask_shf, 0x0088);
+check_member(chn_emi_regs, chn_arbi, 0x0140);
+check_member(chn_emi_regs, chn_arbi_2nd, 0x0144);
+check_member(chn_emi_regs, chn_arbj, 0x0148);
+check_member(chn_emi_regs, chn_arbj_2nd, 0x014c);
+check_member(chn_emi_regs, chn_arbk, 0x0150);
+check_member(chn_emi_regs, chn_arbk_2nd, 0x0154);
+check_member(chn_emi_regs, chn_slct, 0x0158);
+check_member(chn_emi_regs, chn_arb_ref, 0x015c);
+check_member(chn_emi_regs, chn_rkarb0, 0x01b0);
+check_member(chn_emi_regs, chn_rkarb1, 0x01b4);
+check_member(chn_emi_regs, chn_rkarb2, 0x01b8);
+check_member(chn_emi_regs, chn_eco3, 0x03fc);
+check_member(chn_emi_regs, chn_emi_shf0, 0x0710);
+
+struct emi_mpu_regs {
+	uint32_t mpu_ctrl;
+	uint32_t mpu_dbg;
+	uint32_t rsvd_2[62];
+	uint32_t mpu_sa0;
+	uint32_t rsvd_3[63];
+	uint32_t mpu_ea0;
+	uint32_t rsvd_4[63];
+	uint32_t mpu_apc0;
+	uint32_t rsvd_5[319];
+	uint32_t mpu_ctrl_d0;
+	uint32_t rsvd_6[63];
+	uint32_t rg_mask_d0;
+};
+
+check_member(emi_mpu_regs, mpu_dbg, 0x0004);
+check_member(emi_mpu_regs, mpu_sa0, 0x0100);
+check_member(emi_mpu_regs, mpu_ea0, 0x0200);
+check_member(emi_mpu_regs, mpu_apc0, 0x0300);
+check_member(emi_mpu_regs, mpu_ctrl_d0, 0x0800);
+check_member(emi_mpu_regs, rg_mask_d0, 0x0900);
+
+enum {
+	TESTCHIP_DMA1_DMA_LP4MATAB_OPT_SHIFT = 12,
+};
+
+enum {
+	MISC_STATUSA_REFRESH_QUEUE_CNT_SHIFT = 24,
+	MISC_STATUSA_REFRESH_QUEUE_CNT_MASK = 0x0f000000,
+};
+
+enum {
+	SPCMDRESP_RDDQC_RESPONSE_SHIFT = 7,
+	SPCMDRESP_ZQLAT_RESPONSE_SHIFT = 6,
+	SPCMDRESP_ZQC_RESPONSE_SHIFT = 4,
+};
+
+enum {
+	TESTRPT_DM_CMP_CPT_RK0_SHIFT = 0,
+};
+
+enum {
+	DDRCONF0_DM4TO1MODE_SHIFT = 22,
+	DDRCONF0_RDATRST_SHIFT = 0,
+};
+
+enum {
+	DRAMCTRL_ADRDECEN_TARKMODE_SHIFT = 1,
+};
+
+enum {
+	PERFCTL0_RWOFOEN_SHIFT = 4,
+};
+
+enum {
+	RSTMASK_RSV_DRAM_SUPPORT_RANK_NUM_SHIFT = 12,
+};
+
+enum {
+	PADCTRL_DQIENLATEBEGIN_SHIFT = 3,
+	PADCTRL_DQIENQKEND_SHIFT = 0,
+	PADCTRL_DQIENQKEND_MASK = 0x00000003,
+};
+
+enum {
+	RKCFG_RKSWAP_SHIFT = 7,
+	RKCFG_RKMODE_SHIFT = 4,
+	RKCFG_RKMODE_MASK = 0x00000070,
+	RKCFG_TXRANKFIX_SHIFT = 3,
+	RKCFG_TXRANK_SHIFT = 0,
+	RKCFG_TXRANK_MASK = 0x00000003,
+};
+enum {
+	REFCTRL0_REFDIS_SHIFT = 29,
+	REFCTRL0_PBREFEN_SHIFT = 18,
+};
+
+enum {
+	MRS_MPCRK_SHIFT = 28,
+	MRS_MPCRK_MASK = 0x30000000,
+	MRS_MRSRK_SHIFT = 24,
+	MRS_MRSRK_MASK = 0x03000000,
+	MRS_MRSMA_SHIFT = 8,
+	MRS_MRSMA_MASK = 0x001fff00,
+	MRS_MRSOP_SHIFT = 0,
+	MRS_MRSOP_MASK = 0x000000ff,
+};
+
+enum {
+	SPCMD_DQSGCNTRST_SHIFT = 9,
+	SPCMD_DQSGCNTEN_SHIFT = 8,
+	SPCMD_RDDQCEN_SHIFT = 7,
+	SPCMD_ZQLATEN_SHIFT = 6,
+	SPCMD_ZQCEN_SHIFT = 4,
+	SPCMD_MRWEN_SHIFT = 0,
+};
+
+enum {
+	SPCMDCTRL_RDDQCDIS_SHIFT = 11,
+};
+
+enum {
+	MPC_OPTION_MPCRKEN_SHIFT = 17,
+};
+
+enum {
+	TEST2_0_PAT0_SHIFT = 8,
+	TEST2_0_PAT0_MASK = 0x0000ff00,
+	TEST2_0_PAT1_SHIFT = 0,
+	TEST2_0_PAT1_MASK = 0x000000ff,
+};
+
+enum {
+	TEST2_3_TEST2W_SHIFT = 31,
+	TEST2_3_TEST2R_SHIFT = 30,
+	TEST2_3_TEST1_SHIFT = 29,
+	TEST2_3_TESTAUDPAT_SHIFT = 7,
+	TEST2_3_TESTCNT_SHIFT = 0,
+	TEST2_3_TESTCNT_MASK = 0x0000000f,
+};
+
+enum {
+	TEST2_4_TESTAGENTRKSEL_MASK = 0x70000000,
+	TEST2_4_TESTAGENTRK_SHIFT = 24,
+	TEST2_4_TESTAGENTRK_MASK = 0x03000000,
+	TEST2_4_TEST_REQ_LEN1_SHIFT = 17,
+	TEST2_4_TESTXTALKPAT_SHIFT = 16,
+	TEST2_4_TESTAUDMODE_SHIFT = 15,
+	TEST2_4_TESTAUDBITINV_SHIFT = 14,
+	TEST2_4_TESTAUDINIT_SHIFT = 8,
+	TEST2_4_TESTAUDINIT_MASK = 0x00001f00,
+	TEST2_4_TESTSSOXTALKPAT_SHIFT = 7,
+	TEST2_4_TESTSSOPAT_SHIFT = 6,
+	TEST2_4_TESTAUDINC_SHIFT = 0,
+	TEST2_4_TESTAUDINC_MASK = 0x0000001f,
+};
+
+enum {
+	MR_GOLDEN_MR15_GOLDEN_MASK = 0x0000ff00,
+	MR_GOLDEN_MR20_GOLDEN_MASK = 0x000000ff,
+};
+
+enum {
+	DQSOSCR_AR_COARSE_TUNE_DQ_SW_SHIFT = 7,
+};
+
+enum {
+	DUMMY_RD_DQSG_DMYWR_EN_SHIFT = 23,
+	DUMMY_RD_DQSG_DMYRD_EN_SHIFT = 22,
+	DUMMY_RD_SREF_DMYRD_EN_SHIFT = 21,
+	DUMMY_RD_DUMMY_RD_EN_SHIFT = 20,
+	DUMMY_RD_DMY_RD_DBG_SHIFT = 7,
+	DUMMY_RD_DMY_WR_DBG_SHIFT = 6,
+};
+
+enum {
+	SHUCTRL2_R_DVFS_OPTION_SHIFT = 15,
+	SHUCTRL2_R_DVFS_PARK_N_SHIFT = 14,
+};
+
+enum {
+	STBCAL_DQSIENMODE_SELPH_SHIFT = 30,
+	STBCAL_STBCALEN_SHIFT = 24,
+	STBCAL_STB_SELPHYCALEN_SHIFT = 22,
+};
+
+enum {
+	STBCAL1_STBCNT_LATCH_EN_SHIFT = 11,
+	STBCAL1_STBENCMPEN_SHIFT = 10,
+	STBCAL1_DQSIEN_7_COARSE_TUNE_EN_SHIFT = 5,
+};
+
+enum {
+	SHU_ACTIM_XRT_XRTR2R_SHIFT = 0,
+	SHU_ACTIM_XRT_XRTR2R_MASK = 0x0000000f,
+};
+
+enum {
+	SHU_CONF1_DATLAT_DSEL_PHY_SHIFT = 26,
+	SHU_CONF1_DATLAT_DSEL_PHY_MASK = 0x7c000000,
+	SHU_CONF1_DATLAT_DSEL_SHIFT = 8,
+	SHU_CONF1_DATLAT_DSEL_MASK = 0x00001f00,
+	SHU_CONF1_DATLAT_SHIFT = 0,
+	SHU_CONF1_DATLAT_MASK = 0x0000001f,
+};
+
+enum {
+	SHU_RANKCTL_RANKINCTL_PHY_SHIFT = 28,
+	SHU_RANKCTL_RANKINCTL_PHY_MASK = 0xf0000000,
+	SHU_RANKCTL_RANKINCTL_ROOT1_SHIFT = 24,
+	SHU_RANKCTL_RANKINCTL_ROOT1_MASK = 0x0f000000,
+	SHU_RANKCTL_RANKINCTL_SHIFT = 20,
+	SHU_RANKCTL_RANKINCTL_MASK = 0x00f00000,
+};
+
+enum {
+	SHU_ODTCTRL_RODT_SHIFT = 4,
+	SHU_ODTCTRL_RODT_MASK = 0x000000f0,
+};
+
+enum {
+	SHU1_WODT_DBIWR_SHIFT = 29,
+};
+
+enum {
+	SHURK_DQSCTL_DQSINCTL_SHIFT = 0,
+	SHURK_DQSCTL_DQSINCTL_MASK = 0x0000000f,
+};
+
+enum {
+	SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_P1_SHIFT = 12,
+	SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_SHIFT = 8,
+	SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_P1_SHIFT = 4,
+	SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_SHIFT = 0,
+};
+
+enum {
+	SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_P1_SHIFT = 12,
+	SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_SHIFT = 8,
+	SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_P1_SHIFT = 4,
+	SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_SHIFT = 0,
+};
+
+enum {
+	SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_P1_SHIFT = 12,
+	SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_SHIFT = 8,
+	SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT = 4,
+	SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_MASK = 0x00000070,
+	SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_SHIFT = 0,
+	SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_MASK = 0x00000007,
+};
+
+enum {
+	SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_P1_SHIFT = 12,
+	SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_SHIFT = 8,
+	SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_P1_SHIFT = 4,
+	SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_SHIFT = 0,
+};
+
+enum {
+	B0_DQ5_RG_RX_ARDQ_VREF_EN_B0_SHIFT = 16,
+};
+
+enum {
+	B0_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B0_SHIFT = 14,
+	B0_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B0_MASK = 0x0000c000,
+	B0_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B0_SHIFT = 5,
+};
+
+enum {
+	B1_DQ5_RG_RX_ARDQ_VREF_EN_B1_SHIFT = 16,
+};
+
+enum {
+	B1_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B1_SHIFT = 14,
+	B1_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B1_MASK = 0x0000c000,
+	B1_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B1_SHIFT = 5,
+};
+
+enum {
+	MISC_CTRL1_R_DMSTBENCMP_RK_OPT_SHIFT = 25,
+	MISC_CTRL1_R_DMAR_FINE_TUNE_DQ_SW_SHIFT = 7,
+	MISC_CTRL1_R_DMPHYRST_SHIFT = 1,
+};
+
+enum {
+	MISC_STBERR_RK_R_STBERR_RK_R_MASK = 0x0000ffff,
+};
+
+enum {
+	MISC_STBERR_RK_F_STBERR_RK_F_MASK = 0x0000ffff,
+};
+
+enum {
+	SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_SHIFT = 0,
+	SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_MASK = 0x0000003f,
+};
+
+enum {
+	SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT = 7,
+	SHU1_B0_DQ7_R_DMRANKRXDVS_B0_SHIFT = 0,
+	SHU1_B0_DQ7_R_DMRANKRXDVS_B0_MASK = 0x0000000f,
+};
+
+enum {
+	SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_SHIFT = 0,
+	SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_MASK = 0x0000003f,
+};
+
+enum {
+	SHU1_B1_DQ7_R_DMDQMDBI_SHU_B1_SHIFT = 7,
+	SHU1_B1_DQ7_R_DMRANKRXDVS_B1_SHIFT = 0,
+	SHU1_B1_DQ7_R_DMRANKRXDVS_B1_MASK = 0x0000000f,
+};
+
+enum {
+	SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_SHIFT = 12,
+	SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_MASK = 0x00007000,
+};
+
+enum {
+	SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_SHIFT = 10,
+	SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_MASK = 0x00000c00,
+};
+
+enum {
+	SHU1_B0_DQ6_RK_RX_ARDQS0_F_DLY_B0_MASK = 0x7f000000,
+	SHU1_B0_DQ6_RK_RX_ARDQS0_R_DLY_B0_MASK = 0x007f0000,
+	SHU1_B0_DQ6_RK_RX_ARDQM0_F_DLY_B0_MASK = 0x00003f00,
+	SHU1_B0_DQ6_RK_RX_ARDQM0_R_DLY_B0_MASK = 0x0000003f,
+};
+
+enum {
+	SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_SHIFT = 24,
+	SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_MASK = 0x3f000000,
+	SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_SHIFT = 16,
+	SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK = 0x003f0000,
+	SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_SHIFT = 8,
+	SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK = 0x00003f00,
+};
+
+enum {
+	SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_SHIFT = 24,
+	SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_MASK = 0x3f000000,
+	SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_SHIFT = 16,
+	SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK = 0x003f0000,
+	SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_SHIFT = 8,
+	SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK = 0x00003f00,
+};
+
+enum {
+	SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_SHIFT = 24,
+	SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_MASK = 0x3f000000,
+	SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CS_MASK = 0x0000003f,
+};
+
+enum {
+	SHU1_R2_B1_DQ1_RK2_TX_ARDQS0_DLY_B1_SHIFT = 24,
+	SHU1_R2_B1_DQ1_RK2_TX_ARDQS0_DLY_B1_MASK = 0x0f000000,
+	SHU1_R2_B1_DQ1_RK2_TX_ARDQM0_DLY_B1_SHIFT = 0,
+	SHU1_R2_B1_DQ1_RK2_TX_ARDQM0_DLY_B1_MASK = 0x0000000f,
+};
+
+enum {
+	SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_PBYTE_B1_SHIFT = 24,
+	SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_PBYTE_B1_MASK = 0x3f000000,
+	SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQM_B1_SHIFT = 16,
+	SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQM_B1_MASK = 0x003f0000,
+	SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQ_B1_SHIFT = 8,
+	SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQ_B1_MASK = 0x00003f00,
+};
+
+struct dramc_channel_regs {
+	union {
+		struct dramc_ddrphy_ao_regs phy;
+		uint8_t size_ddrphy_ao_regs[0x2000];
+	};
+
+	union {
+		struct dramc_ao_regs ao;
+		uint8_t size_ao_regs[0x2000];
+	};
+
+	union {
+		struct dramc_nao_regs nao;
+		uint8_t size_nao_regs[0x1000];
+	};
+
+	union {
+		struct chn_emi_regs emi;
+		uint8_t size_emi_regs[0x1000];
+	};
+
+	union {
+		struct dramc_ddrphy_nao_regs phy_nao;
+		uint8_t size_ddrphy_nao_regs[0x2000];
+	};
+};
+
+static struct dramc_channel_regs *const ch = (void *)DRAMC_CH_BASE;
+static struct emi_mpu_regs *const emi_mpu = (void *)EMI_MPU_BASE;
+
+#endif /* _DRAMC_REGISTER_H_ */
diff --git a/src/soc/mediatek/mt8183/include/soc/emi.h b/src/soc/mediatek/mt8183/include/soc/emi.h
index edc27a8..5969450 100644
--- a/src/soc/mediatek/mt8183/include/soc/emi.h
+++ b/src/soc/mediatek/mt8183/include/soc/emi.h
@@ -1,7 +1,7 @@
 /*
  * This file is part of the coreboot project.
  *
- * Copyright 2018 MediaTek Inc.
+ * Copyright 2017 MediaTek Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,7 +18,26 @@
 
 #include <stdint.h>
 #include <types.h>
+#include <soc/dramc_common_mt8183.h>
 
+struct sdram_params {
+	u32 impedance[2][4];
+	u8 wr_level[CHANNEL_NUM][RANK_MAX][DQS_NUMBER];
+	u8 cbt_cs[CHANNEL_NUM][RANK_MAX];
+	u8 cbt_mr12[CHANNEL_NUM][RANK_MAX];
+	s8 clk_delay;
+	s8 dqs_delay[CHANNEL_NUM];
+	u32 EMI_CONA_VAL;
+	u32 EMI_CONH_VAL;
+	u32 EMI_CONF_VAL;
+	u32 CHN_EMI_CONA_VAL[CHANNEL_NUM];
+	u32 cbt_mode_extern;
+};
+
+int complex_mem_test(u8 *start, unsigned int len);
 size_t sdram_size(void);
+const struct sdram_params *get_sdram_config(void);
+void mt_set_emi(const struct sdram_params *params);
+void mt_mem_init(const struct sdram_params *params);
 
-#endif
+#endif /* SOC_MEDIATEK_MT8183_EMI_H */
diff --git a/src/soc/mediatek/mt8183/include/soc/memlayout.ld b/src/soc/mediatek/mt8183/include/soc/memlayout.ld
index f148eed..2a6d42d 100644
--- a/src/soc/mediatek/mt8183/include/soc/memlayout.ld
+++ b/src/soc/mediatek/mt8183/include/soc/memlayout.ld
@@ -39,7 +39,7 @@
 	SRAM_END(0x00120000)
 
 	SRAM_L2C_START(0x00200000)
-	OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 92K)
+	OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 110K)
 	BOOTBLOCK(0x00227000, 89K)
 	VERSTAGE(0x0023E000, 114K)
 	SRAM_L2C_END(0x00280000)
diff --git a/src/soc/mediatek/mt8183/memory.c b/src/soc/mediatek/mt8183/memory.c
new file mode 100644
index 0000000..7fee8b8
--- /dev/null
+++ b/src/soc/mediatek/mt8183/memory.c
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <assert.h>
+#include <console/console.h>
+#include <soc/dramc_pi_api.h>
+#include <soc/emi.h>
+#include <symbols.h>
+
+void mt_mem_init(const struct sdram_params *params)
+{
+	u64 rank_size[RANK_MAX];
+
+	/* memory calibration */
+	mt_set_emi(params);
+
+	if (IS_ENABLED(CONFIG_MEMORY_TEST)) {
+		size_t r;
+		u8 *addr = _dram;
+
+		get_dram_rank_size(&rank_size[0]);
+
+		for (r = RANK_0; r < RANK_MAX; r++) {
+			int i;
+
+			if (rank_size[r] == 0)
+				break;
+
+			i = complex_mem_test(addr, 0x2000);
+
+			printk(BIOS_DEBUG, "[MEM] complex R/W mem test %s : %d\n",
+			       (i == 0) ? "pass" : "fail", i);
+
+			ASSERT(i == 0);
+
+			addr += rank_size[r];
+		}
+	}
+}
diff --git a/src/soc/mediatek/mt8183/pll.c b/src/soc/mediatek/mt8183/pll.c
index e0dd388..b099e99 100644
--- a/src/soc/mediatek/mt8183/pll.c
+++ b/src/soc/mediatek/mt8183/pll.c
@@ -280,6 +280,35 @@
 	setbits_le32(pll->div_reg, PLL_PCW_CHG);
 }
 
+static void mem_pll_init(void)
+{
+	unsigned int tmp;
+
+	/* CLKSQ Enable */
+	setbits_le32(&mtk_apmixed->ap_pll_con0, 0x85);
+	udelay(100);
+
+	/* CLKSQ LPF Enable */
+	setbits_le32(&mtk_apmixed->ap_pll_con0, 0x87);
+	udelay(1);
+
+	/* power on MPLL */
+	setbits_le32(&mtk_apmixed->mpll_pwr_con0, 0x3);
+	udelay(1);
+
+	/* turn off ISO of MPLL */
+	setbits_le32(&mtk_apmixed->mpll_pwr_con0, 0x1);
+	udelay(1);
+	tmp = read32(&mtk_apmixed->mpll_con1);
+
+	/* Config MPLL freq */
+	setbits_le32(&mtk_apmixed->mpll_con1, tmp | 0x80000000);
+
+	/* enable MPLL */
+	setbits_le32(&mtk_apmixed->mpll_con0, 0x181);
+	udelay(20);
+}
+
 void mt_pll_init(void)
 {
 	int i;
@@ -348,4 +377,6 @@
 
 	/* enable [14] dramc_pll104m_ck */
 	setbits_le32(&mtk_topckgen->clk_misc_cfg_0, 1 << 14);
+
+	mem_pll_init();
 }

-- 
To view, visit https://review.coreboot.org/28437
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaaa1db170c168a58b020095ae45d98355d8dfcb0
Gerrit-Change-Number: 28437
Gerrit-PatchSet: 1
Gerrit-Owner: Tristan Hsieh <tristan.shieh at mediatek.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20180903/9374bbfc/attachment-0001.html>


More information about the coreboot-gerrit mailing list