Exynos5420: Add DDR3 initialization for 5420

This patch intends to add DDR3 initialization code for Exynos5420.

Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
Signed-off-by: Rajeshwari S Shinde <rajeshwari.s@samsung.com>
Acked-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
diff --git a/arch/arm/cpu/armv7/exynos/dmc_common.c b/arch/arm/cpu/armv7/exynos/dmc_common.c
index 53cfe6e..cca925e 100644
--- a/arch/arm/cpu/armv7/exynos/dmc_common.c
+++ b/arch/arm/cpu/armv7/exynos/dmc_common.c
@@ -1,5 +1,5 @@
 /*
- * Mem setup common file for different types of DDR present on SMDK5250 boards.
+ * Mem setup common file for different types of DDR present on Exynos boards.
  *
  * Copyright (C) 2012 Samsung Electronics
  *
@@ -15,9 +15,9 @@
 
 #define ZQ_INIT_TIMEOUT	10000
 
-int dmc_config_zq(struct mem_timings *mem,
-		  struct exynos5_phy_control *phy0_ctrl,
-		  struct exynos5_phy_control *phy1_ctrl)
+int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16,
+			uint32_t *phy1_con16, uint32_t *phy0_con17,
+			uint32_t *phy1_con17)
 {
 	unsigned long val = 0;
 	int i;
@@ -31,19 +31,19 @@
 	val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;
 	val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;
 	val |= ZQ_CLK_DIV_EN;
-	writel(val, &phy0_ctrl->phy_con16);
-	writel(val, &phy1_ctrl->phy_con16);
+	writel(val, phy0_con16);
+	writel(val, phy1_con16);
 
 	/* Disable termination */
 	if (mem->zq_mode_noterm)
 		val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
-	writel(val, &phy0_ctrl->phy_con16);
-	writel(val, &phy1_ctrl->phy_con16);
+	writel(val, phy0_con16);
+	writel(val, phy1_con16);
 
 	/* ZQ_MANUAL_START: Enable */
 	val |= ZQ_MANUAL_STR;
-	writel(val, &phy0_ctrl->phy_con16);
-	writel(val, &phy1_ctrl->phy_con16);
+	writel(val, phy0_con16);
+	writel(val, phy1_con16);
 
 	/* ZQ_MANUAL_START: Disable */
 	val &= ~ZQ_MANUAL_STR;
@@ -53,47 +53,47 @@
 	 * we are looping for the ZQ_init to complete.
 	 */
 	i = ZQ_INIT_TIMEOUT;
-	while ((readl(&phy0_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
+	while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
 		sdelay(100);
 		i--;
 	}
 	if (!i)
 		return -1;
-	writel(val, &phy0_ctrl->phy_con16);
+	writel(val, phy0_con16);
 
 	i = ZQ_INIT_TIMEOUT;
-	while ((readl(&phy1_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
+	while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
 		sdelay(100);
 		i--;
 	}
 	if (!i)
 		return -1;
-	writel(val, &phy1_ctrl->phy_con16);
+	writel(val, phy1_con16);
 
 	return 0;
 }
 
-void update_reset_dll(struct exynos5_dmc *dmc, enum ddr_mode mode)
+void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode)
 {
 	unsigned long val;
 
 	if (mode == DDR_MODE_DDR3) {
 		val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
-		writel(val, &dmc->phycontrol0);
+		writel(val, phycontrol0);
 	}
 
 	/* Update DLL Information: Force DLL Resyncronization */
-	val = readl(&dmc->phycontrol0);
+	val = readl(phycontrol0);
 	val |= FP_RSYNC;
-	writel(val, &dmc->phycontrol0);
+	writel(val, phycontrol0);
 
 	/* Reset Force DLL Resyncronization */
-	val = readl(&dmc->phycontrol0);
+	val = readl(phycontrol0);
 	val &= ~FP_RSYNC;
-	writel(val, &dmc->phycontrol0);
+	writel(val, phycontrol0);
 }
 
-void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)
+void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd)
 {
 	int channel, chip;
 
@@ -107,7 +107,7 @@
 			mask |= chip << DIRECT_CMD_CHIP_SHIFT;
 
 			/* Sending NOP command */
-			writel(DIRECT_CMD_NOP | mask, &dmc->directcmd);
+			writel(DIRECT_CMD_NOP | mask, directcmd);
 
 			/*
 			 * TODO(alim.akhtar@samsung.com): Do we need these
@@ -119,14 +119,14 @@
 			/* Sending EMRS/MRS commands */
 			for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
 				writel(mem->direct_cmd_msr[i] | mask,
-				       &dmc->directcmd);
+				       directcmd);
 				sdelay(0x10000);
 			}
 
 			if (mem->send_zq_init) {
 				/* Sending ZQINIT command */
 				writel(DIRECT_CMD_ZQINIT | mask,
-				       &dmc->directcmd);
+				       directcmd);
 
 				sdelay(10000);
 			}
@@ -134,7 +134,7 @@
 	}
 }
 
-void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc)
+void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd)
 {
 	int channel, chip;
 
@@ -146,20 +146,12 @@
 			mask |= chip << DIRECT_CMD_CHIP_SHIFT;
 
 			/* PALL (all banks precharge) CMD */
-			writel(DIRECT_CMD_PALL | mask, &dmc->directcmd);
+			writel(DIRECT_CMD_PALL | mask, directcmd);
 			sdelay(0x10000);
 		}
 	}
 }
 
-void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc)
-{
-	writel(mem->memconfig, &dmc->memconfig0);
-	writel(mem->memconfig, &dmc->memconfig1);
-	writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0);
-	writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1);
-}
-
 void mem_ctrl_init(int reset)
 {
 	struct spl_machine_param *param = spl_get_machine_params();
diff --git a/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c b/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c
index 5f5914e..487e6f4 100644
--- a/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c
+++ b/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c
@@ -1,5 +1,5 @@
 /*
- * DDR3 mem setup file for SMDK5250 board based on EXYNOS5
+ * DDR3 mem setup file for board based on EXYNOS5
  *
  * Copyright (C) 2012 Samsung Electronics
  *
@@ -11,12 +11,14 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/dmc.h>
+#include <asm/arch/power.h>
 #include "common_setup.h"
 #include "exynos5_setup.h"
 #include "clock_init.h"
 
-#define RDLVL_COMPLETE_TIMEOUT	10000
+#define TIMEOUT	10000
 
+#ifdef CONFIG_EXYNOS5250
 static void reset_phy_ctrl(void)
 {
 	struct exynos5_clock *clk =
@@ -57,7 +59,8 @@
 	writel(val, &phy1_ctrl->phy_con42);
 
 	/* ZQ Calibration */
-	if (dmc_config_zq(mem, phy0_ctrl, phy1_ctrl))
+	if (dmc_config_zq(mem, &phy0_ctrl->phy_con16, &phy1_ctrl->phy_con16,
+			  &phy0_ctrl->phy_con17, &phy1_ctrl->phy_con17))
 		return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
 
 	/* DQ Signal */
@@ -68,7 +71,7 @@
 		| (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),
 		&dmc->concontrol);
 
-	update_reset_dll(dmc, DDR_MODE_DDR3);
+	update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);
 
 	/* DQS Signal */
 	writel(mem->phy0_dqs, &phy0_ctrl->phy_con4);
@@ -93,7 +96,7 @@
 	writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
 	       &phy1_ctrl->phy_con12);
 
-	update_reset_dll(dmc, DDR_MODE_DDR3);
+	update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);
 
 	writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
 	       &dmc->concontrol);
@@ -124,10 +127,10 @@
 	writel(mem->timing_power, &dmc->timingpower);
 
 	/* Send PALL command */
-	dmc_config_prech(mem, dmc);
+	dmc_config_prech(mem, &dmc->directcmd);
 
 	/* Send NOP, MRS and ZQINIT commands */
-	dmc_config_mrs(mem, dmc);
+	dmc_config_mrs(mem, &dmc->directcmd);
 
 	if (mem->gate_leveling_enable) {
 		val = PHY_CON0_RESET_VAL;
@@ -174,7 +177,7 @@
 		writel(val, &phy1_ctrl->phy_con1);
 
 		writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config);
-		i = RDLVL_COMPLETE_TIMEOUT;
+		i = TIMEOUT;
 		while ((readl(&dmc->phystatus) &
 			(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=
 			(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) {
@@ -202,11 +205,11 @@
 		writel(val, &phy0_ctrl->phy_con12);
 		writel(val, &phy1_ctrl->phy_con12);
 
-		update_reset_dll(dmc, DDR_MODE_DDR3);
+		update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);
 	}
 
 	/* Send PALL command */
-	dmc_config_prech(mem, dmc);
+	dmc_config_prech(mem, &dmc->directcmd);
 
 	writel(mem->memcontrol, &dmc->memcontrol);
 
@@ -215,3 +218,419 @@
 		| (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol);
 	return 0;
 }
+#endif
+
+#ifdef CONFIG_EXYNOS5420
+int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
+		       int reset)
+{
+	struct exynos5420_clock *clk =
+		(struct exynos5420_clock *)samsung_get_base_clock();
+	struct exynos5420_power *power =
+		(struct exynos5420_power *)samsung_get_base_power();
+	struct exynos5420_phy_control *phy0_ctrl, *phy1_ctrl;
+	struct exynos5420_dmc *drex0, *drex1;
+	struct exynos5420_tzasc *tzasc0, *tzasc1;
+	uint32_t val, n_lock_r, n_lock_w_phy0, n_lock_w_phy1;
+	int chip;
+	int i;
+
+	phy0_ctrl = (struct exynos5420_phy_control *)samsung_get_base_dmc_phy();
+	phy1_ctrl = (struct exynos5420_phy_control *)(samsung_get_base_dmc_phy()
+							+ DMC_OFFSET);
+	drex0 = (struct exynos5420_dmc *)samsung_get_base_dmc_ctrl();
+	drex1 = (struct exynos5420_dmc *)(samsung_get_base_dmc_ctrl()
+							+ DMC_OFFSET);
+	tzasc0 = (struct exynos5420_tzasc *)samsung_get_base_dmc_tzasc();
+	tzasc1 = (struct exynos5420_tzasc *)(samsung_get_base_dmc_tzasc()
+							+ DMC_OFFSET);
+
+	/* Enable PAUSE for DREX */
+	setbits_le32(&clk->pause, ENABLE_BIT);
+
+	/* Enable BYPASS mode */
+	setbits_le32(&clk->bpll_con1, BYPASS_EN);
+
+	writel(MUX_BPLL_SEL_FOUTBPLL, &clk->src_cdrex);
+	do {
+		val = readl(&clk->mux_stat_cdrex);
+		val &= BPLL_SEL_MASK;
+	} while (val != FOUTBPLL);
+
+	clrbits_le32(&clk->bpll_con1, BYPASS_EN);
+
+	/* Specify the DDR memory type as DDR3 */
+	val = readl(&phy0_ctrl->phy_con0);
+	val &= ~(PHY_CON0_CTRL_DDR_MODE_MASK << PHY_CON0_CTRL_DDR_MODE_SHIFT);
+	val |= (DDR_MODE_DDR3 << PHY_CON0_CTRL_DDR_MODE_SHIFT);
+	writel(val, &phy0_ctrl->phy_con0);
+
+	val = readl(&phy1_ctrl->phy_con0);
+	val &= ~(PHY_CON0_CTRL_DDR_MODE_MASK << PHY_CON0_CTRL_DDR_MODE_SHIFT);
+	val |= (DDR_MODE_DDR3 << PHY_CON0_CTRL_DDR_MODE_SHIFT);
+	writel(val, &phy1_ctrl->phy_con0);
+
+	/* Set Read Latency and Burst Length for PHY0 and PHY1 */
+	val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) |
+		(mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT);
+	writel(val, &phy0_ctrl->phy_con42);
+	writel(val, &phy1_ctrl->phy_con42);
+
+	val = readl(&phy0_ctrl->phy_con26);
+	val &= ~(T_WRDATA_EN_MASK << T_WRDATA_EN_OFFSET);
+	val |= (T_WRDATA_EN_DDR3 << T_WRDATA_EN_OFFSET);
+	writel(val, &phy0_ctrl->phy_con26);
+
+	val = readl(&phy1_ctrl->phy_con26);
+	val &= ~(T_WRDATA_EN_MASK << T_WRDATA_EN_OFFSET);
+	val |= (T_WRDATA_EN_DDR3 << T_WRDATA_EN_OFFSET);
+	writel(val, &phy1_ctrl->phy_con26);
+
+	/*
+	 * Set Driver strength for CK, CKE, CS & CA to 0x7
+	 * Set Driver strength for Data Slice 0~3 to 0x7
+	 */
+	val = (0x7 << CA_CK_DRVR_DS_OFFSET) | (0x7 << CA_CKE_DRVR_DS_OFFSET) |
+		(0x7 << CA_CS_DRVR_DS_OFFSET) | (0x7 << CA_ADR_DRVR_DS_OFFSET);
+	val |= (0x7 << DA_3_DS_OFFSET) | (0x7 << DA_2_DS_OFFSET) |
+		(0x7 << DA_1_DS_OFFSET) | (0x7 << DA_0_DS_OFFSET);
+	writel(val, &phy0_ctrl->phy_con39);
+	writel(val, &phy1_ctrl->phy_con39);
+
+	/* ZQ Calibration */
+	if (dmc_config_zq(mem, &phy0_ctrl->phy_con16, &phy1_ctrl->phy_con16,
+			  &phy0_ctrl->phy_con17, &phy1_ctrl->phy_con17))
+		return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
+
+	clrbits_le32(&phy0_ctrl->phy_con16, ZQ_CLK_DIV_EN);
+	clrbits_le32(&phy1_ctrl->phy_con16, ZQ_CLK_DIV_EN);
+
+	/* DQ Signal */
+	val = readl(&phy0_ctrl->phy_con14);
+	val |= mem->phy0_pulld_dqs;
+	writel(val, &phy0_ctrl->phy_con14);
+	val = readl(&phy1_ctrl->phy_con14);
+	val |= mem->phy1_pulld_dqs;
+	writel(val, &phy1_ctrl->phy_con14);
+
+	val = MEM_TERM_EN | PHY_TERM_EN;
+	writel(val, &drex0->phycontrol0);
+	writel(val, &drex1->phycontrol0);
+
+	writel(mem->concontrol |
+		(mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT) |
+		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
+		&drex0->concontrol);
+	writel(mem->concontrol |
+		(mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT) |
+		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
+		&drex1->concontrol);
+
+	do {
+		val = readl(&drex0->phystatus);
+	} while ((val & DFI_INIT_COMPLETE) != DFI_INIT_COMPLETE);
+	do {
+		val = readl(&drex1->phystatus);
+	} while ((val & DFI_INIT_COMPLETE) != DFI_INIT_COMPLETE);
+
+	clrbits_le32(&drex0->concontrol, DFI_INIT_START);
+	clrbits_le32(&drex1->concontrol, DFI_INIT_START);
+
+	update_reset_dll(&drex0->phycontrol0, DDR_MODE_DDR3);
+	update_reset_dll(&drex1->phycontrol0, DDR_MODE_DDR3);
+
+	/*
+	 * Set Base Address:
+	 * 0x2000_0000 ~ 0x5FFF_FFFF
+	 * 0x6000_0000 ~ 0x9FFF_FFFF
+	 */
+	/* MEMBASECONFIG0 */
+	val = DMC_MEMBASECONFIGX_CHIP_BASE(DMC_CHIP_BASE_0) |
+		DMC_MEMBASECONFIGX_CHIP_MASK(DMC_CHIP_MASK);
+	writel(val, &tzasc0->membaseconfig0);
+	writel(val, &tzasc1->membaseconfig0);
+
+	/* MEMBASECONFIG1 */
+	val = DMC_MEMBASECONFIGX_CHIP_BASE(DMC_CHIP_BASE_1) |
+		DMC_MEMBASECONFIGX_CHIP_MASK(DMC_CHIP_MASK);
+	writel(val, &tzasc0->membaseconfig1);
+	writel(val, &tzasc1->membaseconfig1);
+
+	/*
+	 * Memory Channel Inteleaving Size
+	 * Ares Channel interleaving = 128 bytes
+	 */
+	/* MEMCONFIG0/1 */
+	writel(mem->memconfig, &tzasc0->memconfig0);
+	writel(mem->memconfig, &tzasc1->memconfig0);
+	writel(mem->memconfig, &tzasc0->memconfig1);
+	writel(mem->memconfig, &tzasc1->memconfig1);
+
+	/* Precharge Configuration */
+	writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
+	       &drex0->prechconfig0);
+	writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
+	       &drex1->prechconfig0);
+
+	/*
+	 * TimingRow, TimingData, TimingPower and Timingaref
+	 * values as per Memory AC parameters
+	 */
+	writel(mem->timing_ref, &drex0->timingref);
+	writel(mem->timing_ref, &drex1->timingref);
+	writel(mem->timing_row, &drex0->timingrow0);
+	writel(mem->timing_row, &drex1->timingrow0);
+	writel(mem->timing_data, &drex0->timingdata0);
+	writel(mem->timing_data, &drex1->timingdata0);
+	writel(mem->timing_power, &drex0->timingpower0);
+	writel(mem->timing_power, &drex1->timingpower0);
+
+	if (reset) {
+		/*
+		 * Send NOP, MRS and ZQINIT commands
+		 * Sending MRS command will reset the DRAM. We should not be
+		 * reseting the DRAM after resume, this will lead to memory
+		 * corruption as DRAM content is lost after DRAM reset
+		 */
+		dmc_config_mrs(mem, &drex0->directcmd);
+		dmc_config_mrs(mem, &drex1->directcmd);
+	} else {
+		/*
+		 * During Suspend-Resume & S/W-Reset, as soon as PMU releases
+		 * pad retention, CKE goes high. This causes memory contents
+		 * not to be retained during DRAM initialization. Therfore,
+		 * there is a new control register(0x100431e8[28]) which lets us
+		 * release pad retention and retain the memory content until the
+		 * initialization is complete.
+		 */
+		writel(PAD_RETENTION_DRAM_COREBLK_VAL,
+		       &power->pad_retention_dram_coreblk_option);
+		do {
+			val = readl(&power->pad_retention_dram_status);
+		} while (val != 0x1);
+
+		/*
+		 * CKE PAD retention disables DRAM self-refresh mode.
+		 * Send auto refresh command for DRAM refresh.
+		 */
+		for (i = 0; i < 128; i++) {
+			for (chip = 0; chip < mem->chips_to_configure; chip++) {
+				writel(DIRECT_CMD_REFA |
+				       (chip << DIRECT_CMD_CHIP_SHIFT),
+				       &drex0->directcmd);
+				writel(DIRECT_CMD_REFA |
+				       (chip << DIRECT_CMD_CHIP_SHIFT),
+				       &drex1->directcmd);
+			}
+		}
+	}
+
+	if (mem->gate_leveling_enable) {
+		writel(PHY_CON0_RESET_VAL, &phy0_ctrl->phy_con0);
+		writel(PHY_CON0_RESET_VAL, &phy1_ctrl->phy_con0);
+
+		setbits_le32(&phy0_ctrl->phy_con0, P0_CMD_EN);
+		setbits_le32(&phy1_ctrl->phy_con0, P0_CMD_EN);
+
+		val = PHY_CON2_RESET_VAL;
+		val |= INIT_DESKEW_EN;
+		writel(val, &phy0_ctrl->phy_con2);
+		writel(val, &phy1_ctrl->phy_con2);
+
+		val =  readl(&phy0_ctrl->phy_con1);
+		val |= (RDLVL_PASS_ADJ_VAL << RDLVL_PASS_ADJ_OFFSET);
+		writel(val, &phy0_ctrl->phy_con1);
+
+		val =  readl(&phy1_ctrl->phy_con1);
+		val |= (RDLVL_PASS_ADJ_VAL << RDLVL_PASS_ADJ_OFFSET);
+		writel(val, &phy1_ctrl->phy_con1);
+
+		n_lock_r = readl(&phy0_ctrl->phy_con13);
+		n_lock_w_phy0 = (n_lock_r & CTRL_LOCK_COARSE_MASK) >> 2;
+		n_lock_r = readl(&phy0_ctrl->phy_con12);
+		n_lock_r &= ~CTRL_DLL_ON;
+		n_lock_r |= n_lock_w_phy0;
+		writel(n_lock_r, &phy0_ctrl->phy_con12);
+
+		n_lock_r = readl(&phy1_ctrl->phy_con13);
+		n_lock_w_phy1 = (n_lock_r & CTRL_LOCK_COARSE_MASK) >> 2;
+		n_lock_r = readl(&phy1_ctrl->phy_con12);
+		n_lock_r &= ~CTRL_DLL_ON;
+		n_lock_r |= n_lock_w_phy1;
+		writel(n_lock_r, &phy1_ctrl->phy_con12);
+
+		val = (0x3 << DIRECT_CMD_BANK_SHIFT) | 0x4;
+		for (chip = 0; chip < mem->chips_to_configure; chip++) {
+			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+			       &drex0->directcmd);
+			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+			       &drex1->directcmd);
+		}
+
+		setbits_le32(&phy0_ctrl->phy_con2, RDLVL_GATE_EN);
+		setbits_le32(&phy1_ctrl->phy_con2, RDLVL_GATE_EN);
+
+		setbits_le32(&phy0_ctrl->phy_con0, CTRL_SHGATE);
+		setbits_le32(&phy1_ctrl->phy_con0, CTRL_SHGATE);
+
+		val = readl(&phy0_ctrl->phy_con1);
+		val &= ~(CTRL_GATEDURADJ_MASK);
+		writel(val, &phy0_ctrl->phy_con1);
+
+		val = readl(&phy1_ctrl->phy_con1);
+		val &= ~(CTRL_GATEDURADJ_MASK);
+		writel(val, &phy1_ctrl->phy_con1);
+
+		writel(CTRL_RDLVL_GATE_ENABLE, &drex0->rdlvl_config);
+		i = TIMEOUT;
+		while (((readl(&drex0->phystatus) & RDLVL_COMPLETE_CHO) !=
+			RDLVL_COMPLETE_CHO) && (i > 0)) {
+			/*
+			 * TODO(waihong): Comment on how long this take to
+			 * timeout
+			 */
+			sdelay(100);
+			i--;
+		}
+		if (!i)
+			return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
+		writel(CTRL_RDLVL_GATE_DISABLE, &drex0->rdlvl_config);
+
+		writel(CTRL_RDLVL_GATE_ENABLE, &drex1->rdlvl_config);
+		i = TIMEOUT;
+		while (((readl(&drex1->phystatus) & RDLVL_COMPLETE_CHO) !=
+			RDLVL_COMPLETE_CHO) && (i > 0)) {
+			/*
+			 * TODO(waihong): Comment on how long this take to
+			 * timeout
+			 */
+			sdelay(100);
+			i--;
+		}
+		if (!i)
+			return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
+		writel(CTRL_RDLVL_GATE_DISABLE, &drex1->rdlvl_config);
+
+		writel(0, &phy0_ctrl->phy_con14);
+		writel(0, &phy1_ctrl->phy_con14);
+
+		val = (0x3 << DIRECT_CMD_BANK_SHIFT);
+		for (chip = 0; chip < mem->chips_to_configure; chip++) {
+			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+			       &drex0->directcmd);
+			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+			       &drex1->directcmd);
+		}
+
+		if (mem->read_leveling_enable) {
+			/* Set Read DQ Calibration */
+			val = (0x3 << DIRECT_CMD_BANK_SHIFT) | 0x4;
+			for (chip = 0; chip < mem->chips_to_configure; chip++) {
+				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+				       &drex0->directcmd);
+				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+				       &drex1->directcmd);
+			}
+
+			val = readl(&phy0_ctrl->phy_con1);
+			val |= READ_LEVELLING_DDR3;
+			writel(val, &phy0_ctrl->phy_con1);
+			val = readl(&phy1_ctrl->phy_con1);
+			val |= READ_LEVELLING_DDR3;
+			writel(val, &phy1_ctrl->phy_con1);
+
+			val = readl(&phy0_ctrl->phy_con2);
+			val |= (RDLVL_EN | RDLVL_INCR_ADJ);
+			writel(val, &phy0_ctrl->phy_con2);
+			val = readl(&phy1_ctrl->phy_con2);
+			val |= (RDLVL_EN | RDLVL_INCR_ADJ);
+			writel(val, &phy1_ctrl->phy_con2);
+
+			setbits_le32(&drex0->rdlvl_config,
+				     CTRL_RDLVL_DATA_ENABLE);
+			i = TIMEOUT;
+			while (((readl(&drex0->phystatus) & RDLVL_COMPLETE_CHO)
+				 != RDLVL_COMPLETE_CHO) && (i > 0)) {
+				/*
+				 * TODO(waihong): Comment on how long this take
+				 * to timeout
+				 */
+				sdelay(100);
+				i--;
+			}
+			if (!i)
+				return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
+
+			clrbits_le32(&drex0->rdlvl_config,
+				     CTRL_RDLVL_DATA_ENABLE);
+			setbits_le32(&drex1->rdlvl_config,
+				     CTRL_RDLVL_DATA_ENABLE);
+			i = TIMEOUT;
+			while (((readl(&drex1->phystatus) & RDLVL_COMPLETE_CHO)
+				 != RDLVL_COMPLETE_CHO) && (i > 0)) {
+				/*
+				 * TODO(waihong): Comment on how long this take
+				 * to timeout
+				 */
+				sdelay(100);
+				i--;
+			}
+			if (!i)
+				return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
+
+			clrbits_le32(&drex1->rdlvl_config,
+				     CTRL_RDLVL_DATA_ENABLE);
+
+			val = (0x3 << DIRECT_CMD_BANK_SHIFT);
+			for (chip = 0; chip < mem->chips_to_configure; chip++) {
+				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+				       &drex0->directcmd);
+				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
+				       &drex1->directcmd);
+			}
+
+			update_reset_dll(&drex0->phycontrol0, DDR_MODE_DDR3);
+			update_reset_dll(&drex1->phycontrol0, DDR_MODE_DDR3);
+		}
+
+		/* Common Settings for Leveling */
+		val = PHY_CON12_RESET_VAL;
+		writel((val + n_lock_w_phy0), &phy0_ctrl->phy_con12);
+		writel((val + n_lock_w_phy1), &phy1_ctrl->phy_con12);
+
+		setbits_le32(&phy0_ctrl->phy_con2, DLL_DESKEW_EN);
+		setbits_le32(&phy1_ctrl->phy_con2, DLL_DESKEW_EN);
+	}
+
+	/* Send PALL command */
+	dmc_config_prech(mem, &drex0->directcmd);
+	dmc_config_prech(mem, &drex1->directcmd);
+
+	writel(mem->memcontrol, &drex0->memcontrol);
+	writel(mem->memcontrol, &drex1->memcontrol);
+
+	/*
+	 * Set DMC Concontrol: Enable auto-refresh counter, provide
+	 * read data fetch cycles and enable DREX auto set powerdown
+	 * for input buffer of I/O in none read memory state.
+	 */
+	writel(mem->concontrol | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT) |
+		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)|
+		DMC_CONCONTROL_IO_PD_CON(0x2),
+		&drex0->concontrol);
+	writel(mem->concontrol | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT) |
+		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)|
+		DMC_CONCONTROL_IO_PD_CON(0x2),
+		&drex1->concontrol);
+
+	/*
+	 * Enable Clock Gating Control for DMC
+	 * this saves around 25 mw dmc power as compared to the power
+	 * consumption without these bits enabled
+	 */
+	setbits_le32(&drex0->cgcontrol, DMC_INTERNAL_CG);
+	setbits_le32(&drex1->cgcontrol, DMC_INTERNAL_CG);
+
+	return 0;
+}
+#endif
diff --git a/arch/arm/cpu/armv7/exynos/exynos5_setup.h b/arch/arm/cpu/armv7/exynos/exynos5_setup.h
index c8d6515..53b0ace 100644
--- a/arch/arm/cpu/armv7/exynos/exynos5_setup.h
+++ b/arch/arm/cpu/armv7/exynos/exynos5_setup.h
@@ -696,6 +696,7 @@
 #define CLK_DIV_CPERI1_VAL	NOT_AVAILABLE
 
 #else
+#define PAD_RETENTION_DRAM_COREBLK_VAL	0x10000000
 
 /* APLL_CON1 */
 #define APLL_CON1_VAL	(0x0020F300)
@@ -907,37 +908,38 @@
  * Configure ZQ I/O interface
  *
  * @param mem		Memory timings for this memory type.
- * @param phy0_ctrl	Pointer to struct containing PHY0 control reg
- * @param phy1_ctrl	Pointer to struct containing PHY1 control reg
+ * @param phy0_con16	Register address for dmc_phy0->phy_con16
+ * @param phy1_con16	Register address for dmc_phy1->phy_con16
+ * @param phy0_con17	Register address for dmc_phy0->phy_con17
+ * @param phy1_con17	Register address for dmc_phy1->phy_con17
  * @return 0 if ok, -1 on error
  */
-int dmc_config_zq(struct mem_timings *mem,
-		  struct exynos5_phy_control *phy0_ctrl,
-		  struct exynos5_phy_control *phy1_ctrl);
-
+int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16,
+			uint32_t *phy1_con16, uint32_t *phy0_con17,
+			uint32_t *phy1_con17);
 /*
  * Send NOP and MRS/EMRS Direct commands
  *
  * @param mem		Memory timings for this memory type.
- * @param dmc		Pointer to struct of DMC registers
+ * @param directcmd	Register address for dmc_phy->directcmd
  */
-void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc);
+void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd);
 
 /*
  * Send PALL Direct commands
  *
  * @param mem		Memory timings for this memory type.
- * @param dmc		Pointer to struct of DMC registers
+ * @param directcmd	Register address for dmc_phy->directcmd
  */
-void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc);
+void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd);
 
 /*
  * Reset the DLL. This function is common between DDR3 and LPDDR2.
  * However, the reset value is different. So we are passing a flag
  * ddr_mode to distinguish between LPDDR2 and DDR3.
  *
- * @param exynos5_dmc	Pointer to struct of DMC registers
+ * @param phycontrol0	Register address for dmc_phy->phycontrol0
  * @param ddr_mode	Type of DDR memory
  */
-void update_reset_dll(struct exynos5_dmc *, enum ddr_mode);
+void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode);
 #endif
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h
index 2b44210..573f755 100644
--- a/arch/arm/include/asm/arch-exynos/cpu.h
+++ b/arch/arm/include/asm/arch-exynos/cpu.h
@@ -53,6 +53,7 @@
 #define EXYNOS4_AUDIOSS_BASE		DEVICE_NOT_AVAILABLE
 #define EXYNOS4_USB_HOST_XHCI_BASE	DEVICE_NOT_AVAILABLE
 #define EXYNOS4_USB3PHY_BASE		DEVICE_NOT_AVAILABLE
+#define EXYNOS4_DMC_TZASC_BASE		DEVICE_NOT_AVAILABLE
 
 /* EXYNOS4X12 */
 #define EXYNOS4X12_GPIO_PART3_BASE	0x03860000
@@ -91,6 +92,7 @@
 #define EXYNOS4X12_AUDIOSS_BASE		DEVICE_NOT_AVAILABLE
 #define EXYNOS4X12_USB_HOST_XHCI_BASE	DEVICE_NOT_AVAILABLE
 #define EXYNOS4X12_USB3PHY_BASE		DEVICE_NOT_AVAILABLE
+#define EXYNOS4X12_DMC_TZASC_BASE	DEVICE_NOT_AVAILABLE
 
 /* EXYNOS5 */
 #define EXYNOS5_I2C_SPACING		0x10000
@@ -129,6 +131,7 @@
 
 #define EXYNOS5_ADC_BASE		DEVICE_NOT_AVAILABLE
 #define EXYNOS5_MODEM_BASE		DEVICE_NOT_AVAILABLE
+#define EXYNOS5_DMC_TZASC_BASE		DEVICE_NOT_AVAILABLE
 
 /* EXYNOS5420 */
 #define EXYNOS5420_AUDIOSS_BASE		0x03810000
@@ -143,8 +146,7 @@
 #define EXYNOS5420_ACE_SFR_BASE		0x10830000
 #define EXYNOS5420_DMC_PHY_BASE		0x10C00000
 #define EXYNOS5420_DMC_CTRL_BASE	0x10C20000
-#define EXYNOS5420_DMC_TZASC0_BASE	0x10D40000
-#define EXYNOS5420_DMC_TZASC1_BASE	0x10D50000
+#define EXYNOS5420_DMC_TZASC_BASE	0x10D40000
 #define EXYNOS5420_USB_HOST_EHCI_BASE	0x12110000
 #define EXYNOS5420_MMC_BASE		0x12200000
 #define EXYNOS5420_SROMC_BASE		0x12250000
@@ -284,6 +286,7 @@
 SAMSUNG_BASE(tzpc, TZPC_BASE)
 SAMSUNG_BASE(dmc_ctrl, DMC_CTRL_BASE)
 SAMSUNG_BASE(dmc_phy, DMC_PHY_BASE)
+SAMSUNG_BASE(dmc_tzasc, DMC_TZASC_BASE)
 SAMSUNG_BASE(audio_ass, AUDIOSS_BASE)
 #endif
 
diff --git a/arch/arm/include/asm/arch-exynos/dmc.h b/arch/arm/include/asm/arch-exynos/dmc.h
index 32ad3ae..d78536d 100644
--- a/arch/arm/include/asm/arch-exynos/dmc.h
+++ b/arch/arm/include/asm/arch-exynos/dmc.h
@@ -419,6 +419,15 @@
 	unsigned int phy_con42;
 };
 
+struct exynos5420_tzasc {
+	unsigned char res1[0xf00];
+	unsigned int membaseconfig0;
+	unsigned int membaseconfig1;
+	unsigned char res2[0x8];
+	unsigned int memconfig0;
+	unsigned int memconfig1;
+};
+
 enum ddr_mode {
 	DDR_MODE_DDR2,
 	DDR_MODE_DDR3,
@@ -453,6 +462,7 @@
 #define PHY_CON0_T_WRRDCMD_SHIFT	17
 #define PHY_CON0_T_WRRDCMD_MASK		(0x7 << PHY_CON0_T_WRRDCMD_SHIFT)
 #define PHY_CON0_CTRL_DDR_MODE_SHIFT	11
+#define PHY_CON0_CTRL_DDR_MODE_MASK	0x3
 
 /* PHY_CON1 register fields */
 #define PHY_CON1_RDLVL_RDDATA_ADJ_SHIFT	0