diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile
index dc01ee5..8f698f8 100644
--- a/arch/arm/cpu/armv7/omap-common/Makefile
+++ b/arch/arm/cpu/armv7/omap-common/Makefile
@@ -28,6 +28,7 @@ LIB	= $(obj)libomap-common.o
 SOBJS	:= reset.o
 
 COBJS	:= timer.o
+COBJS	+= utils.o
 
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/arch/arm/cpu/armv7/omap-common/utils.c b/arch/arm/cpu/armv7/omap-common/utils.c
new file mode 100644
index 0000000..7dce7f1
--- /dev/null
+++ b/arch/arm/cpu/armv7/omap-common/utils.c
@@ -0,0 +1,61 @@
+/*
+ * Utility functions for OMAP4
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Aneesh V <aneesh@ti.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+static void do_cancel_out(u32 *num, u32 *den, u32 factor)
+{
+	while (1) {
+		if (((*num)/factor*factor == (*num)) &&
+		   ((*den)/factor*factor == (*den))) {
+			(*num) /= factor;
+			(*den) /= factor;
+		} else
+			break;
+	}
+}
+
+/*
+ * Cancel out the denominator and numerator of a fraction
+ * to get smaller numerator and denominator.
+ */
+void cancel_out(u32 *num, u32 *den, u32 den_limit)
+{
+	do_cancel_out(num, den, 2);
+	do_cancel_out(num, den, 3);
+	do_cancel_out(num, den, 5);
+	do_cancel_out(num, den, 7);
+	do_cancel_out(num, den, 11);
+	do_cancel_out(num, den, 13);
+	do_cancel_out(num, den, 17);
+	while ((*den) > den_limit) {
+		*num /= 2;
+		/*
+		 * Round up the denominator so that the final fraction
+		 * (num/den) is always <= the desired value
+		 */
+		*den = (*den + 1) / 2;
+	}
+}
diff --git a/arch/arm/cpu/armv7/omap4/Makefile b/arch/arm/cpu/armv7/omap4/Makefile
index d9714fe..0b525e1 100644
--- a/arch/arm/cpu/armv7/omap4/Makefile
+++ b/arch/arm/cpu/armv7/omap4/Makefile
@@ -34,7 +34,6 @@ COBJS	+= clocks.o
 COBJS	+= emif.o
 COBJS	+= sdram_elpida.o
 
-
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
 
diff --git a/arch/arm/cpu/armv7/omap4/board.c b/arch/arm/cpu/armv7/omap4/board.c
index 7add46b..a51d1bb 100644
--- a/arch/arm/cpu/armv7/omap4/board.c
+++ b/arch/arm/cpu/armv7/omap4/board.c
@@ -32,6 +32,7 @@
 #include <asm/arch/cpu.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/sizes.h>
+#include <asm/arch/emif.h>
 #include "omap4_mux_data.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -148,13 +149,13 @@ u32 sdram_size(void)
 {
 	u32 section, i, total_size = 0, size, addr;
 	for (i = 0; i < 4; i++) {
-		section	= __raw_readl(DMM_LISA_MAP_BASE + i*4);
-		addr = section & DMM_LISA_MAP_SYS_ADDR_MASK;
+		section	= __raw_readl(OMAP44XX_DMM_LISA_MAP_BASE + i*4);
+		addr = section & OMAP44XX_SYS_ADDR_MASK;
 		/* See if the address is valid */
 		if ((addr >= OMAP44XX_DRAM_ADDR_SPACE_START) &&
 		    (addr < OMAP44XX_DRAM_ADDR_SPACE_END)) {
-			size	= ((section & DMM_LISA_MAP_SYS_SIZE_MASK) >>
-				    DMM_LISA_MAP_SYS_SIZE_SHIFT);
+			size	= ((section & OMAP44XX_SYS_SIZE_MASK) >>
+				   OMAP44XX_SYS_SIZE_SHIFT);
 			size	= 1 << size;
 			size	*= SZ_16M;
 			total_size += size;
diff --git a/arch/arm/cpu/armv7/omap4/emif.c b/arch/arm/cpu/armv7/omap4/emif.c
index 9591fb0..baa5ed6 100644
--- a/arch/arm/cpu/armv7/omap4/emif.c
+++ b/arch/arm/cpu/armv7/omap4/emif.c
@@ -32,6 +32,589 @@
 #include <asm/omap_common.h>
 #include <asm/utils.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
+#define print_timing_reg(reg) debug(#reg" - 0x%08x\n", (reg))
+
+static u32 *const T_num = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_T_NUM;
+static u32 *const T_den = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_T_DEN;
+static u32 *const emif_sizes = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_SIZE;
+
+/*
+ * Organization and refresh requirements for LPDDR2 devices of different
+ * types and densities. Derived from JESD209-2 section 2.4
+ */
+const struct lpddr2_addressing addressing_table[] = {
+	/* Banks tREFIx10     rowx32,rowx16      colx32,colx16	density */
+	{BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_7, COL_8} },/*64M */
+	{BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_8, COL_9} },/*128M */
+	{BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_8, COL_9} },/*256M */
+	{BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} },/*512M */
+	{BANKS8, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} },/*1GS4 */
+	{BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_9, COL_10} },/*2GS4 */
+	{BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_10, COL_11} },/*4G */
+	{BANKS8, T_REFI_3_9, {ROW_15, ROW_15}, {COL_10, COL_11} },/*8G */
+	{BANKS4, T_REFI_7_8, {ROW_14, ROW_14}, {COL_9, COL_10} },/*1GS2 */
+	{BANKS4, T_REFI_3_9, {ROW_15, ROW_15}, {COL_9, COL_10} },/*2GS2 */
+};
+
+static const u32 lpddr2_density_2_size_in_mbytes[] = {
+	8,			/* 64Mb */
+	16,			/* 128Mb */
+	32,			/* 256Mb */
+	64,			/* 512Mb */
+	128,			/* 1Gb   */
+	256,			/* 2Gb   */
+	512,			/* 4Gb   */
+	1024,			/* 8Gb   */
+	2048,			/* 16Gb  */
+	4096			/* 32Gb  */
+};
+
+#ifdef CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS
+/* Base AC Timing values specified by JESD209-2 for 400MHz operation */
+static const struct lpddr2_ac_timings timings_jedec_400_mhz = {
+	.max_freq = 400000000,
+	.RL = 6,
+	.tRPab = 21,
+	.tRCD = 18,
+	.tWR = 15,
+	.tRASmin = 42,
+	.tRRD = 10,
+	.tWTRx2 = 15,
+	.tXSR = 140,
+	.tXPx2 = 15,
+	.tRFCab = 130,
+	.tRTPx2 = 15,
+	.tCKE = 3,
+	.tCKESR = 15,
+	.tZQCS = 90,
+	.tZQCL = 360,
+	.tZQINIT = 1000,
+	.tDQSCKMAXx2 = 11,
+	.tRASmax = 70,
+	.tFAW = 50
+};
+
+/* Base AC Timing values specified by JESD209-2 for 333 MHz operation */
+static const struct lpddr2_ac_timings timings_jedec_333_mhz = {
+	.max_freq = 333000000,
+	.RL = 5,
+	.tRPab = 21,
+	.tRCD = 18,
+	.tWR = 15,
+	.tRASmin = 42,
+	.tRRD = 10,
+	.tWTRx2 = 15,
+	.tXSR = 140,
+	.tXPx2 = 15,
+	.tRFCab = 130,
+	.tRTPx2 = 15,
+	.tCKE = 3,
+	.tCKESR = 15,
+	.tZQCS = 90,
+	.tZQCL = 360,
+	.tZQINIT = 1000,
+	.tDQSCKMAXx2 = 11,
+	.tRASmax = 70,
+	.tFAW = 50
+};
+
+/* Base AC Timing values specified by JESD209-2 for 200 MHz operation */
+static const struct lpddr2_ac_timings timings_jedec_200_mhz = {
+	.max_freq = 200000000,
+	.RL = 3,
+	.tRPab = 21,
+	.tRCD = 18,
+	.tWR = 15,
+	.tRASmin = 42,
+	.tRRD = 10,
+	.tWTRx2 = 20,
+	.tXSR = 140,
+	.tXPx2 = 15,
+	.tRFCab = 130,
+	.tRTPx2 = 15,
+	.tCKE = 3,
+	.tCKESR = 15,
+	.tZQCS = 90,
+	.tZQCL = 360,
+	.tZQINIT = 1000,
+	.tDQSCKMAXx2 = 11,
+	.tRASmax = 70,
+	.tFAW = 50
+};
+
+/*
+ * Min tCK values specified by JESD209-2
+ * Min tCK specifies the minimum duration of some AC timing parameters in terms
+ * of the number of cycles. If the calculated number of cycles based on the
+ * absolute time value is less than the min tCK value, min tCK value should
+ * be used instead. This typically happens at low frequencies.
+ */
+static const struct lpddr2_min_tck min_tck_jedec = {
+	.tRL = 3,
+	.tRP_AB = 3,
+	.tRCD = 3,
+	.tWR = 3,
+	.tRAS_MIN = 3,
+	.tRRD = 2,
+	.tWTR = 2,
+	.tXP = 2,
+	.tRTP = 2,
+	.tCKE = 3,
+	.tCKESR = 3,
+	.tFAW = 8
+};
+
+static const struct lpddr2_ac_timings *jedec_ac_timings[MAX_NUM_SPEEDBINS] = {
+	&timings_jedec_200_mhz,
+	&timings_jedec_333_mhz,
+	&timings_jedec_400_mhz
+};
+
+static const struct lpddr2_device_timings jedec_default_timings = {
+	.ac_timings = jedec_ac_timings,
+	.min_tck = &min_tck_jedec
+};
+#endif /* CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS */
+
+/*
+ * Calculate the period of DDR clock from frequency value and set the
+ * denominator and numerator in global variables for easy access later
+ */
+static void set_ddr_clk_period(u32 freq)
+{
+	/*
+	 * period = 1/freq
+	 * period_in_ns = 10^9/freq
+	 */
+	*T_num = 1000000000;
+	*T_den = freq;
+	cancel_out(T_num, T_den, 200);
+
+}
+
+/*
+ * Convert time in nano seconds to number of cycles of DDR clock
+ */
+static inline u32 ns_2_cycles(u32 ns)
+{
+	return ((ns * (*T_den)) + (*T_num) - 1) / (*T_num);
+}
+
+/*
+ * ns_2_cycles with the difference that the time passed is 2 times the actual
+ * value(to avoid fractions). The cycles returned is for the original value of
+ * the timing parameter
+ */
+static inline u32 ns_x2_2_cycles(u32 ns)
+{
+	return ((ns * (*T_den)) + (*T_num) * 2 - 1) / ((*T_num) * 2);
+}
+
+/*
+ * Find addressing table index based on the device's type(S2 or S4) and
+ * density
+ */
+s8 addressing_table_index(u8 type, u8 density, u8 width)
+{
+	u8 index;
+	if ((density > LPDDR2_DENSITY_8Gb) || (width == LPDDR2_IO_WIDTH_8))
+		return -1;
+
+	/*
+	 * Look at the way ADDR_TABLE_INDEX* values have been defined
+	 * in emif.h compared to LPDDR2_DENSITY_* values
+	 * The table is layed out in the increasing order of density
+	 * (ignoring type). The exceptions 1GS2 and 2GS2 have been placed
+	 * at the end
+	 */
+	if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_1Gb))
+		index = ADDR_TABLE_INDEX1GS2;
+	else if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_2Gb))
+		index = ADDR_TABLE_INDEX2GS2;
+	else
+		index = density;
+
+	debug("emif: addressing table index %d\n", index);
+
+	return index;
+}
+
+/*
+ * Find the the right timing table from the array of timing
+ * tables of the device using DDR clock frequency
+ */
+static const struct lpddr2_ac_timings *get_timings_table(const struct
+			lpddr2_ac_timings const *const *device_timings,
+			u32 freq)
+{
+	u32 i, temp, freq_nearest;
+	const struct lpddr2_ac_timings *timings = 0;
+
+	emif_assert(freq <= MAX_LPDDR2_FREQ);
+	emif_assert(device_timings);
+
+	/*
+	 * Start with the maximum allowed frequency - that is always safe
+	 */
+	freq_nearest = MAX_LPDDR2_FREQ;
+	/*
+	 * Find the timings table that has the max frequency value:
+	 *   i.  Above or equal to the DDR frequency - safe
+	 *   ii. The lowest that satisfies condition (i) - optimal
+	 */
+	for (i = 0; (i < MAX_NUM_SPEEDBINS) && device_timings[i]; i++) {
+		temp = device_timings[i]->max_freq;
+		if ((temp >= freq) && (temp <= freq_nearest)) {
+			freq_nearest = temp;
+			timings = device_timings[i];
+		}
+	}
+	debug("emif: timings table: %d\n", freq_nearest);
+	return timings;
+}
+
+/*
+ * Finds the value of emif_sdram_config_reg
+ * All parameters are programmed based on the device on CS0.
+ * If there is a device on CS1, it will be same as that on CS0 or
+ * it will be NVM. We don't support NVM yet.
+ * If cs1_device pointer is NULL it is assumed that there is no device
+ * on CS1
+ */
+static u32 get_sdram_config_reg(const struct lpddr2_device_details *cs0_device,
+				const struct lpddr2_device_details *cs1_device,
+				const struct lpddr2_addressing *addressing,
+				u8 RL)
+{
+	u32 config_reg = 0;
+
+	set_bit_field(config_reg, OMAP44XX_REG_SDRAM_TYPE_SHIFT,
+		      OMAP44XX_REG_SDRAM_TYPE_MASK, cs0_device->type + 4);
+
+	set_bit_field(config_reg, OMAP44XX_REG_IBANK_POS_SHIFT,
+		      OMAP44XX_REG_IBANK_POS_MASK,
+		      EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING);
+
+	set_bit_field(config_reg, OMAP44XX_REG_NARROW_MODE_SHIFT,
+		      OMAP44XX_REG_NARROW_MODE_MASK, cs0_device->io_width);
+
+	set_bit_field(config_reg, OMAP44XX_REG_CL_SHIFT, OMAP44XX_REG_CL_MASK,
+		      RL);
+
+	set_bit_field(config_reg, OMAP44XX_REG_ROWSIZE_SHIFT,
+		      OMAP44XX_REG_ROWSIZE_MASK,
+		      addressing->row_sz[cs0_device->io_width]);
+
+	set_bit_field(config_reg, OMAP44XX_REG_IBANK_SHIFT,
+		      OMAP44XX_REG_IBANK_MASK, addressing->num_banks);
+
+	set_bit_field(config_reg, OMAP44XX_REG_EBANK_SHIFT,
+		      OMAP44XX_REG_EBANK_MASK,
+		      (cs1_device ? EBANK_CS1_EN : EBANK_CS1_DIS));
+
+	set_bit_field(config_reg, OMAP44XX_REG_PAGESIZE_SHIFT,
+		      OMAP44XX_REG_PAGESIZE_MASK,
+		      addressing->col_sz[cs0_device->io_width]);
+
+	return config_reg;
+}
+
+static u32 get_sdram_ref_ctrl(u32 freq,
+			      const struct lpddr2_addressing *addressing)
+{
+	u32 ref_ctrl = 0, val = 0, freq_khz;
+	freq_khz = freq / 1000;
+	/*
+	 * refresh rate to be set is 'tREFI * freq in MHz
+	 * division by 10000 to account for khz and x10 in t_REFI_us_x10
+	 */
+	val = addressing->t_REFI_us_x10 * freq_khz / 10000;
+	set_bit_field(ref_ctrl, OMAP44XX_REG_REFRESH_RATE_SHIFT,
+		      OMAP44XX_REG_REFRESH_RATE_MASK, val);
+
+	return ref_ctrl;
+}
+
+static u32 get_sdram_tim_1_reg(const struct lpddr2_ac_timings *timings,
+			       const struct lpddr2_min_tck *min_tck,
+			       const struct lpddr2_addressing *addressing)
+{
+	u32 tim1 = 0, val = 0;
+	val = max(min_tck->tWTR, ns_x2_2_cycles(timings->tWTRx2)) - 1;
+	set_bit_field(tim1, OMAP44XX_REG_T_WTR_SHIFT, OMAP44XX_REG_T_WTR_MASK,
+		      val);
+
+	if (addressing->num_banks == BANKS8)
+		val = (timings->tFAW * (*T_den) + 4 * (*T_num) - 1) /
+							(4 * (*T_num)) - 1;
+	else
+		val = max(min_tck->tRRD, ns_2_cycles(timings->tRRD)) - 1;
+
+	set_bit_field(tim1, OMAP44XX_REG_T_RRD_SHIFT, OMAP44XX_REG_T_RRD_MASK,
+		      val);
+
+	val = ns_2_cycles(timings->tRASmin + timings->tRPab) - 1;
+	set_bit_field(tim1, OMAP44XX_REG_T_RC_SHIFT, OMAP44XX_REG_T_RC_MASK,
+		      val);
+
+	val = max(min_tck->tRAS_MIN, ns_2_cycles(timings->tRASmin)) - 1;
+	set_bit_field(tim1, OMAP44XX_REG_T_RAS_SHIFT, OMAP44XX_REG_T_RAS_MASK,
+		      val);
+
+	val = max(min_tck->tWR, ns_2_cycles(timings->tWR)) - 1;
+	set_bit_field(tim1, OMAP44XX_REG_T_WR_SHIFT, OMAP44XX_REG_T_WR_MASK,
+		      val);
+
+	val = max(min_tck->tRCD, ns_2_cycles(timings->tRCD)) - 1;
+	set_bit_field(tim1, OMAP44XX_REG_T_RCD_SHIFT, OMAP44XX_REG_T_RCD_MASK,
+		      val);
+	val = max(min_tck->tRP_AB, ns_2_cycles(timings->tRPab)) - 1;
+	set_bit_field(tim1, OMAP44XX_REG_T_RP_SHIFT, OMAP44XX_REG_T_RP_MASK,
+		      val);
+
+	return tim1;
+}
+
+static u32 get_sdram_tim_2_reg(const struct lpddr2_ac_timings *timings,
+			       const struct lpddr2_min_tck *min_tck)
+{
+	u32 tim2 = 0, val = 0;
+	val = max(min_tck->tCKE, timings->tCKE) - 1;
+	set_bit_field(tim2, OMAP44XX_REG_T_CKE_SHIFT, OMAP44XX_REG_T_CKE_MASK,
+		      val);
+
+	val = max(min_tck->tRTP, ns_x2_2_cycles(timings->tRTPx2)) - 1;
+	set_bit_field(tim2, OMAP44XX_REG_T_RTP_SHIFT, OMAP44XX_REG_T_RTP_MASK,
+		      val);
+
+	/*
+	 * tXSRD = tRFCab + 10 ns. XSRD and XSNR should have the
+	 * same value
+	 */
+	val = ns_2_cycles(timings->tXSR) - 1;
+	set_bit_field(tim2, OMAP44XX_REG_T_XSRD_SHIFT, OMAP44XX_REG_T_XSRD_MASK,
+		      val);
+	set_bit_field(tim2, OMAP44XX_REG_T_XSNR_SHIFT, OMAP44XX_REG_T_XSNR_MASK,
+		      val);
+
+	val = max(min_tck->tXP, ns_x2_2_cycles(timings->tXPx2)) - 1;
+	set_bit_field(tim2, OMAP44XX_REG_T_XP_SHIFT, OMAP44XX_REG_T_XP_MASK,
+		      val);
+
+	return tim2;
+}
+
+static u32 get_sdram_tim_3_reg(const struct lpddr2_ac_timings *timings,
+			       const struct lpddr2_min_tck *min_tck,
+			       const struct lpddr2_addressing *addressing)
+{
+	u32 tim3 = 0, val = 0;
+	val = min(timings->tRASmax * 10 / addressing->t_REFI_us_x10 - 1, 0xF);
+	set_bit_field(tim3, OMAP44XX_REG_T_RAS_MAX_SHIFT,
+		      OMAP44XX_REG_T_RAS_MAX_MASK, val);
+
+	val = ns_2_cycles(timings->tRFCab) - 1;
+	set_bit_field(tim3, OMAP44XX_REG_T_RFC_SHIFT, OMAP44XX_REG_T_RFC_MASK,
+		      val);
+
+	val = ns_x2_2_cycles(timings->tDQSCKMAXx2) - 1;
+	set_bit_field(tim3, OMAP44XX_REG_T_TDQSCKMAX_SHIFT,
+		      OMAP44XX_REG_T_TDQSCKMAX_MASK, val);
+
+	val = ns_2_cycles(timings->tZQCS) - 1;
+	set_bit_field(tim3, OMAP44XX_REG_ZQ_ZQCS_SHIFT,
+		      OMAP44XX_REG_ZQ_ZQCS_MASK, val);
+
+	val = max(min_tck->tCKESR, ns_2_cycles(timings->tCKESR)) - 1;
+	set_bit_field(tim3, OMAP44XX_REG_T_CKESR_SHIFT,
+		      OMAP44XX_REG_T_CKESR_MASK, val);
+
+	return tim3;
+}
+
+static u32 get_zq_config_reg(const struct lpddr2_device_details *cs1_device,
+			     const struct lpddr2_addressing *addressing,
+			     u8 volt_ramp)
+{
+	u32 zq = 0, val = 0;
+	if (volt_ramp)
+		val =
+		    EMIF_ZQCS_INTERVAL_DVFS_IN_US * 10 /
+		    addressing->t_REFI_us_x10;
+	else
+		val =
+		    EMIF_ZQCS_INTERVAL_NORMAL_IN_US * 10 /
+		    addressing->t_REFI_us_x10;
+	set_bit_field(zq, OMAP44XX_REG_ZQ_REFINTERVAL_SHIFT,
+		      OMAP44XX_REG_ZQ_REFINTERVAL_MASK, val);
+
+	set_bit_field(zq, OMAP44XX_REG_ZQ_ZQCL_MULT_SHIFT,
+		      OMAP44XX_REG_ZQ_ZQCL_MULT_MASK, REG_ZQ_ZQCL_MULT - 1);
+
+	set_bit_field(zq, OMAP44XX_REG_ZQ_ZQINIT_MULT_SHIFT,
+		      OMAP44XX_REG_ZQ_ZQINIT_MULT_MASK, REG_ZQ_ZQINIT_MULT - 1);
+
+	set_bit_field(zq, OMAP44XX_REG_ZQ_SFEXITEN_SHIFT,
+		      OMAP44XX_REG_ZQ_SFEXITEN_MASK, REG_ZQ_SFEXITEN_ENABLE);
+
+	/*
+	 * Assuming that two chipselects have a single calibration resistor
+	 * If there are indeed two calibration resistors, then this flag should
+	 * be enabled to take advantage of dual calibration feature.
+	 * This data should ideally come from board files. But considering
+	 * that none of the boards today have calibration resistors per CS,
+	 * it would be an unnecessary overhead.
+	 */
+	set_bit_field(zq, OMAP44XX_REG_ZQ_DUALCALEN_SHIFT,
+		      OMAP44XX_REG_ZQ_DUALCALEN_MASK, REG_ZQ_DUALCALEN_DISABLE);
+
+	set_bit_field(zq, OMAP44XX_REG_ZQ_CS0EN_SHIFT,
+		      OMAP44XX_REG_ZQ_CS0EN_MASK, REG_ZQ_CS0EN_ENABLE);
+
+	set_bit_field(zq, OMAP44XX_REG_ZQ_CS1EN_SHIFT,
+		      OMAP44XX_REG_ZQ_CS1EN_MASK, (cs1_device ? 1 : 0));
+
+	return zq;
+}
+
+static u32 get_temp_alert_config(const struct lpddr2_device_details *cs1_device,
+				 const struct lpddr2_addressing *addressing,
+				 u8 is_derated)
+{
+	u32 alert = 0, interval;
+	interval =
+	    TEMP_ALERT_POLL_INTERVAL_MS * 10000 / addressing->t_REFI_us_x10;
+	if (is_derated)
+		interval *= 4;
+	set_bit_field(alert, OMAP44XX_REG_TA_REFINTERVAL_SHIFT,
+		      OMAP44XX_REG_TA_REFINTERVAL_MASK, interval);
+
+	set_bit_field(alert, OMAP44XX_REG_TA_DEVCNT_SHIFT,
+		      OMAP44XX_REG_TA_DEVCNT_MASK, TEMP_ALERT_CONFIG_DEVCT_1);
+
+	set_bit_field(alert, OMAP44XX_REG_TA_DEVWDT_SHIFT,
+		      OMAP44XX_REG_TA_DEVWDT_MASK, TEMP_ALERT_CONFIG_DEVWDT_32);
+
+	set_bit_field(alert, OMAP44XX_REG_TA_SFEXITEN_SHIFT,
+		      OMAP44XX_REG_TA_SFEXITEN_MASK, 1);
+
+	set_bit_field(alert, OMAP44XX_REG_TA_CS0EN_SHIFT,
+		      OMAP44XX_REG_TA_CS0EN_MASK, 1);
+
+	set_bit_field(alert, OMAP44XX_REG_TA_CS1EN_SHIFT,
+		      OMAP44XX_REG_TA_CS1EN_MASK, (cs1_device ? 1 : 0));
+
+	return alert;
+}
+
+static u32 get_read_idle_ctrl_reg(u8 volt_ramp)
+{
+	u32 idle = 0, val = 0;
+	if (volt_ramp)
+		val = ns_2_cycles(READ_IDLE_INTERVAL_DVFS) / 64 + 1;
+	else
+		/*Maximum value in normal conditions - suggested by hw team */
+		val = 0x1FF;
+	set_bit_field(idle, OMAP44XX_REG_READ_IDLE_INTERVAL_SHIFT,
+		      OMAP44XX_REG_READ_IDLE_INTERVAL_MASK, val);
+
+	set_bit_field(idle, OMAP44XX_REG_READ_IDLE_LEN_SHIFT,
+		      OMAP44XX_REG_READ_IDLE_LEN_MASK,
+		      EMIF_REG_READ_IDLE_LEN_VAL);
+
+	return idle;
+}
+
+static u32 get_ddr_phy_ctrl_1(u32 freq, u8 RL)
+{
+	u32 phy = 0, val = 0;
+
+	set_bit_field(phy, OMAP44XX_REG_READ_LATENCY_SHIFT,
+		      OMAP44XX_REG_READ_LATENCY_MASK, RL + 2);
+
+	if (freq <= 100000000)
+		val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS;
+	else if (freq <= 200000000)
+		val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ;
+	else
+		val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ;
+	set_bit_field(phy, OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHIFT,
+		      OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_MASK, val);
+
+	/* Other fields are constant magic values. Hardcode them together */
+	set_bit_field(phy, OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHIFT,
+		      OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_MASK,
+		      EMIF_DDR_PHY_CTRL_1_BASE_VAL);
+
+	return phy;
+}
+
+const char *get_lpddr2_type(u8 type_id)
+{
+	switch (type_id) {
+	case LPDDR2_TYPE_S4:
+		return "LPDDR2-S4";
+	case LPDDR2_TYPE_S2:
+		return "LPDDR2-S2";
+	default:
+		return NULL;
+	}
+}
+
+const char *get_lpddr2_io_width(u8 width_id)
+{
+	switch (width_id) {
+	case LPDDR2_IO_WIDTH_8:
+		return "x8";
+	case LPDDR2_IO_WIDTH_16:
+		return "x16";
+	case LPDDR2_IO_WIDTH_32:
+		return "x32";
+	default:
+		return NULL;
+	}
+}
+
+const char *get_lpddr2_manufacturer(u32 manufacturer)
+{
+	switch (manufacturer) {
+	case LPDDR2_MANUFACTURER_SAMSUNG:
+		return "Samsung";
+	case LPDDR2_MANUFACTURER_QIMONDA:
+		return "Qimonda";
+	case LPDDR2_MANUFACTURER_ELPIDA:
+		return "Elpida";
+	case LPDDR2_MANUFACTURER_ETRON:
+		return "Etron";
+	case LPDDR2_MANUFACTURER_NANYA:
+		return "Nanya";
+	case LPDDR2_MANUFACTURER_HYNIX:
+		return "Hynix";
+	case LPDDR2_MANUFACTURER_MOSEL:
+		return "Mosel";
+	case LPDDR2_MANUFACTURER_WINBOND:
+		return "Winbond";
+	case LPDDR2_MANUFACTURER_ESMT:
+		return "ESMT";
+	case LPDDR2_MANUFACTURER_SPANSION:
+		return "Spansion";
+	case LPDDR2_MANUFACTURER_SST:
+		return "SST";
+	case LPDDR2_MANUFACTURER_ZMOS:
+		return "ZMOS";
+	case LPDDR2_MANUFACTURER_INTEL:
+		return "Intel";
+	case LPDDR2_MANUFACTURER_NUMONYX:
+		return "Numonyx";
+	case LPDDR2_MANUFACTURER_MICRON:
+		return "Micron";
+	default:
+		return NULL;
+	}
+}
+
 static inline u32 emif_num(u32 base)
 {
 	if (base == OMAP44XX_EMIF1)
@@ -66,6 +649,127 @@ static inline void set_mr(u32 base, u32 cs, u32 mr_addr, u32 mr_val)
 	writel(mr_addr, &emif->emif_lpddr2_mode_reg_cfg);
 	writel(mr_val, &emif->emif_lpddr2_mode_reg_data);
 }
+
+static void emif_calculate_regs(
+		const struct emif_device_details *emif_dev_details,
+		u32 freq, struct emif_regs *regs)
+{
+	u32 temp, sys_freq;
+	const struct lpddr2_addressing *addressing;
+	const struct lpddr2_ac_timings *timings;
+	const struct lpddr2_min_tck *min_tck;
+	const struct lpddr2_device_details *cs0_dev_details =
+					emif_dev_details->cs0_device_details;
+	const struct lpddr2_device_details *cs1_dev_details =
+					emif_dev_details->cs1_device_details;
+	const struct lpddr2_device_timings *cs0_dev_timings =
+					emif_dev_details->cs0_device_timings;
+
+	emif_assert(emif_dev_details);
+	emif_assert(regs);
+	/*
+	 * You can not have a device on CS1 without one on CS0
+	 * So configuring EMIF without a device on CS0 doesn't
+	 * make sense
+	 */
+	emif_assert(cs0_dev_details);
+	emif_assert(cs0_dev_details->type != LPDDR2_TYPE_NVM);
+	/*
+	 * If there is a device on CS1 it should be same type as CS0
+	 * (or NVM. But NVM is not supported in this driver yet)
+	 */
+	emif_assert((cs1_dev_details == NULL) ||
+		    (cs1_dev_details->type == LPDDR2_TYPE_NVM) ||
+		    (cs0_dev_details->type == cs1_dev_details->type));
+	emif_assert(freq <= MAX_LPDDR2_FREQ);
+
+	set_ddr_clk_period(freq);
+
+	/*
+	 * The device on CS0 is used for all timing calculations
+	 * There is only one set of registers for timings per EMIF. So, if the
+	 * second CS(CS1) has a device, it should have the same timings as the
+	 * device on CS0
+	 */
+	timings = get_timings_table(cs0_dev_timings->ac_timings, freq);
+	emif_assert(timings);
+	min_tck = cs0_dev_timings->min_tck;
+
+	temp = addressing_table_index(cs0_dev_details->type,
+				      cs0_dev_details->density,
+				      cs0_dev_details->io_width);
+
+	emif_assert((temp >= 0));
+	addressing = &(addressing_table[temp]);
+	emif_assert(addressing);
+
+	sys_freq = get_sys_clk_freq();
+
+	regs->sdram_config_init = get_sdram_config_reg(cs0_dev_details,
+							cs1_dev_details,
+							addressing, RL_BOOT);
+
+	regs->sdram_config = get_sdram_config_reg(cs0_dev_details,
+						cs1_dev_details,
+						addressing, RL_FINAL);
+
+	regs->ref_ctrl = get_sdram_ref_ctrl(freq, addressing);
+
+	regs->sdram_tim1 = get_sdram_tim_1_reg(timings, min_tck, addressing);
+
+	regs->sdram_tim2 = get_sdram_tim_2_reg(timings, min_tck);
+
+	regs->sdram_tim3 = get_sdram_tim_3_reg(timings, min_tck, addressing);
+
+	regs->read_idle_ctrl = get_read_idle_ctrl_reg(LPDDR2_VOLTAGE_STABLE);
+
+	regs->temp_alert_config =
+	    get_temp_alert_config(cs1_dev_details, addressing, 0);
+
+	regs->zq_config = get_zq_config_reg(cs1_dev_details, addressing,
+					    LPDDR2_VOLTAGE_STABLE);
+
+	regs->emif_ddr_phy_ctlr_1_init =
+			get_ddr_phy_ctrl_1(sys_freq / 2, RL_BOOT);
+
+	regs->emif_ddr_phy_ctlr_1 =
+			get_ddr_phy_ctrl_1(freq, RL_FINAL);
+
+	regs->freq = freq;
+
+	print_timing_reg(regs->sdram_config_init);
+	print_timing_reg(regs->sdram_config);
+	print_timing_reg(regs->ref_ctrl);
+	print_timing_reg(regs->sdram_tim1);
+	print_timing_reg(regs->sdram_tim2);
+	print_timing_reg(regs->sdram_tim3);
+	print_timing_reg(regs->read_idle_ctrl);
+	print_timing_reg(regs->temp_alert_config);
+	print_timing_reg(regs->zq_config);
+	print_timing_reg(regs->emif_ddr_phy_ctlr_1);
+	print_timing_reg(regs->emif_ddr_phy_ctlr_1_init);
+}
+
+static u32 get_emif_mem_size(struct emif_device_details *devices)
+{
+	u32 size_mbytes = 0, temp;
+
+	if (!devices)
+		return 0;
+
+	if (devices->cs0_device_details) {
+		temp = devices->cs0_device_details->density;
+		size_mbytes += lpddr2_density_2_size_in_mbytes[temp];
+	}
+
+	if (devices->cs1_device_details) {
+		temp = devices->cs1_device_details->density;
+		size_mbytes += lpddr2_density_2_size_in_mbytes[temp];
+	}
+	/* convert to bytes */
+	return size_mbytes << 20;
+}
+
 void emif_reset_phy(u32 base)
 {
 	struct emif_reg_struct *emif = (struct emif_reg_struct *)base;
@@ -175,14 +879,66 @@ static void emif_update_timings(u32 base, const struct emif_regs *regs)
 
 static void do_sdram_init(u32 base)
 {
-	const struct emif_regs *regs, *tmp_regs;
+	struct emif_device_details dev_details;
+	const struct emif_regs *regs;
+
 	u32 in_sdram, emif_nr;
 
 	in_sdram = running_from_sdram();
 	emif_nr = (base == OMAP44XX_EMIF1) ? 1 : 2;
 
+#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
+	const struct emif_regs *tmp_regs;
 	emif_get_reg_dump(&regs, &tmp_regs);
 	regs = (emif_nr == 1) ? regs : tmp_regs;
+#else
+	/*
+	 * The user has not provided the register values. We need to
+	 * calculate it based on the timings and the DDR frequency
+	 */
+
+	const struct emif_device_details *dev_details_user_provided;
+	const struct emif_device_details *tmp_details;
+	struct emif_regs calculated_regs;
+
+	/* We need some input about the devices from the user */
+	emif_get_device_details(&dev_details_user_provided, &tmp_details);
+	dev_details_user_provided = (emif_nr == 1) ? dev_details_user_provided
+						   : tmp_details;
+	if (!dev_details_user_provided)
+		return;
+
+	dev_details.cs0_device_details =
+			dev_details_user_provided->cs0_device_details;
+	dev_details.cs1_device_details =
+			dev_details_user_provided->cs1_device_details;
+
+	/* Return if no devices on this EMIF */
+	if (!dev_details.cs0_device_details &&
+	    !dev_details.cs1_device_details) {
+		emif_sizes[emif_nr - 1] = 0;
+		return;
+	}
+
+	if (!in_sdram)
+		emif_sizes[emif_nr - 1] = get_emif_mem_size(&dev_details);
+
+#ifdef CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS
+	/* Use the base timings specified by JESD209-2 */
+	dev_details.cs0_device_timings = &jedec_default_timings;
+	dev_details.cs1_device_timings = &jedec_default_timings;
+
+#else /* CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS */
+	dev_details.cs0_device_timings =
+			dev_details_user_provided->cs0_device_timings;
+	dev_details.cs1_device_timings =
+			dev_details_user_provided->cs1_device_timings;
+#endif /* CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS */
+	/* Calculate the register values */
+	emif_calculate_regs(&dev_details, omap4_ddr_clk(), &calculated_regs);
+	regs = &calculated_regs;
+
+#endif /* CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */
 
 	/*
 	 * Initializing the LPDDR2 device can not happen from SDRAM.
@@ -232,12 +988,111 @@ static void emif_post_init_config(u32 base)
 		writel(0x80000000, &emif->emif_pwr_mgmt_ctrl);
 }
 
+/* Gets the encoding corresponding to a given DMM section size */
+u32 get_dmm_section_size_map(u32 section_size)
+{
+	/*
+	 * Section size mapping:
+	 * 0x0: 16-MiB section
+	 * 0x1: 32-MiB section
+	 * 0x2: 64-MiB section
+	 * 0x3: 128-MiB section
+	 * 0x4: 256-MiB section
+	 * 0x5: 512-MiB section
+	 * 0x6: 1-GiB section
+	 * 0x7: 2-GiB section
+	 */
+	section_size >>= 24; /* divide by 16 MB */
+	return log_2_n_round_down(section_size);
+}
+
 static void dmm_init(u32 base)
 {
 	const struct dmm_lisa_map_regs *lisa_map_regs;
 
+#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
 	emif_get_dmm_regs(&lisa_map_regs);
+#else
+	u32 emif1_size, emif2_size, mapped_size, section_map;
+	u32 section_cnt, sys_addr;
+	struct dmm_lisa_map_regs lis_map_regs_calculated;
+
+	mapped_size = 0;
+	section_cnt = 3;
+	sys_addr = CONFIG_SYS_SDRAM_BASE;
+	emif1_size = emif_sizes[0];
+	emif2_size = emif_sizes[1];
+	debug("emif1_size 0x%x emif2_size 0x%x\n", emif1_size, emif2_size);
 
+	if (!emif1_size && !emif2_size)
+		return;
+
+	/* symmetric interleaved section */
+	if (emif1_size && emif2_size) {
+		mapped_size = min(emif1_size, emif2_size);
+		section_map = DMM_LISA_MAP_INTERLEAVED_BASE_VAL;
+		set_bit_field(section_map, OMAP44XX_SDRC_ADDR_SHIFT,
+				OMAP44XX_SDRC_ADDR_MASK,
+				0);
+		set_bit_field(section_map, OMAP44XX_SYS_ADDR_SHIFT,
+				OMAP44XX_SYS_ADDR_MASK,
+				sys_addr >> 24); /* only MSB */
+		set_bit_field(section_map, OMAP44XX_SYS_SIZE_SHIFT,
+				OMAP44XX_SYS_SIZE_MASK,
+				get_dmm_section_size_map(mapped_size * 2));
+		lis_map_regs_calculated.dmm_lisa_map_3 = section_map;
+		emif1_size -= mapped_size;
+		emif2_size -= mapped_size;
+		sys_addr += (mapped_size * 2);
+		section_cnt--;
+	}
+
+	/*
+	 * Single EMIF section(we can have a maximum of 1 single EMIF
+	 * section- either EMIF1 or EMIF2 or none, but not both)
+	 */
+	if (emif1_size) {
+		section_map = DMM_LISA_MAP_EMIF1_ONLY_BASE_VAL;
+		set_bit_field(section_map, OMAP44XX_SYS_SIZE_SHIFT,
+				OMAP44XX_SYS_SIZE_MASK,
+				get_dmm_section_size_map(emif1_size));
+		set_bit_field(section_map, OMAP44XX_SDRC_ADDR_SHIFT,
+				OMAP44XX_SDRC_ADDR_MASK,
+				mapped_size >> 24); /* only MSB */
+		set_bit_field(section_map, OMAP44XX_SYS_ADDR_SHIFT,
+				OMAP44XX_SYS_ADDR_MASK,
+				sys_addr >> 24); /* only MSB */
+		section_cnt--;
+	}
+	if (emif2_size) {
+		section_map = DMM_LISA_MAP_EMIF2_ONLY_BASE_VAL;
+		set_bit_field(section_map, OMAP44XX_SYS_SIZE_SHIFT,
+			      OMAP44XX_SYS_SIZE_MASK,
+			      get_dmm_section_size_map(emif2_size));
+		set_bit_field(section_map, OMAP44XX_SDRC_ADDR_SHIFT,
+				OMAP44XX_SDRC_ADDR_MASK,
+				mapped_size >> 24); /* only MSB */
+		set_bit_field(section_map, OMAP44XX_SYS_ADDR_SHIFT,
+				OMAP44XX_SYS_ADDR_MASK,
+				sys_addr >> 24); /* only MSB */
+		section_cnt--;
+	}
+
+	if (section_cnt == 2) {
+		/* Only 1 section - either symmetric or single EMIF */
+		lis_map_regs_calculated.dmm_lisa_map_3 = section_map;
+		lis_map_regs_calculated.dmm_lisa_map_2 = 0;
+		lis_map_regs_calculated.dmm_lisa_map_1 = 0;
+	} else {
+		/* 2 sections - 1 symmetric, 1 single EMIF */
+		lis_map_regs_calculated.dmm_lisa_map_2 = section_map;
+		lis_map_regs_calculated.dmm_lisa_map_1 = 0;
+	}
+	/* TRAP for invalid TILER mappings in section 0 */
+	lis_map_regs_calculated.dmm_lisa_map_0 = DMM_LISA_MAP_0_INVAL_ADDR_TRAP;
+
+	lisa_map_regs = &lis_map_regs_calculated;
+#endif
 	struct dmm_lisa_map_regs *hw_lisa_map_regs =
 	    (struct dmm_lisa_map_regs *)base;
 
@@ -275,8 +1130,10 @@ static void dmm_init(u32 base)
  */
 void sdram_init(void)
 {
-	u32 in_sdram;
+	if (omap4_hw_init_context() == OMAP_INIT_CONTEXT_UBOOT_LOADED_BY_SPL)
+		return;
 
+	u32 in_sdram;
 	in_sdram = running_from_sdram();
 
 	if (!in_sdram) {
diff --git a/arch/arm/cpu/armv7/omap4/sdram_elpida.c b/arch/arm/cpu/armv7/omap4/sdram_elpida.c
index 37e808c..e7d2bd5 100644
--- a/arch/arm/cpu/armv7/omap4/sdram_elpida.c
+++ b/arch/arm/cpu/armv7/omap4/sdram_elpida.c
@@ -29,6 +29,8 @@
 #include <asm/arch/emif.h>
 #include <asm/arch/sys_proto.h>
 
+#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
+
 static const struct emif_regs emif_regs_elpida_200_mhz_2cs = {
 	.sdram_config_init		= 0x80000eb9,
 	.sdram_config			= 0x80001ab9,
@@ -86,6 +88,131 @@ const struct dmm_lisa_map_regs lisa_map_2G_x_2_x_2 = {
 
 void emif_get_reg_dump_sdp(const struct emif_regs **emif1_regs,
 			const struct emif_regs **emif2_regs)
+
+#else
+
+static const struct lpddr2_ac_timings timings_elpida_400_mhz = {
+	.max_freq	= 400000000,
+	.RL		= 6,
+	.tRPab		= 21,
+	.tRCD		= 18,
+	.tWR		= 15,
+	.tRASmin	= 42,
+	.tRRD		= 10,
+	.tWTRx2		= 15,
+	.tXSR		= 140,
+	.tXPx2		= 15,
+	.tRFCab		= 130,
+	.tRTPx2		= 15,
+	.tCKE		= 3,
+	.tCKESR		= 15,
+	.tZQCS		= 90,
+	.tZQCL		= 360,
+	.tZQINIT	= 1000,
+	.tDQSCKMAXx2	= 11,
+	.tRASmax	= 70,
+	.tFAW		= 50
+};
+
+static const struct lpddr2_ac_timings timings_elpida_333_mhz = {
+	.max_freq	= 333000000,
+	.RL		= 5,
+	.tRPab		= 21,
+	.tRCD		= 18,
+	.tWR		= 15,
+	.tRASmin	= 42,
+	.tRRD		= 10,
+	.tWTRx2		= 15,
+	.tXSR		= 140,
+	.tXPx2		= 15,
+	.tRFCab		= 130,
+	.tRTPx2		= 15,
+	.tCKE		= 3,
+	.tCKESR		= 15,
+	.tZQCS		= 90,
+	.tZQCL		= 360,
+	.tZQINIT	= 1000,
+	.tDQSCKMAXx2	= 11,
+	.tRASmax	= 70,
+	.tFAW		= 50
+};
+
+static const struct lpddr2_ac_timings timings_elpida_200_mhz = {
+	.max_freq	= 200000000,
+	.RL		= 3,
+	.tRPab		= 21,
+	.tRCD		= 18,
+	.tWR		= 15,
+	.tRASmin	= 42,
+	.tRRD		= 10,
+	.tWTRx2		= 20,
+	.tXSR		= 140,
+	.tXPx2		= 15,
+	.tRFCab		= 130,
+	.tRTPx2		= 15,
+	.tCKE		= 3,
+	.tCKESR		= 15,
+	.tZQCS		= 90,
+	.tZQCL		= 360,
+	.tZQINIT	= 1000,
+	.tDQSCKMAXx2	= 11,
+	.tRASmax	= 70,
+	.tFAW		= 50
+};
+
+static const struct lpddr2_min_tck min_tck_elpida = {
+	.tRL		= 3,
+	.tRP_AB		= 3,
+	.tRCD		= 3,
+	.tWR		= 3,
+	.tRAS_MIN	= 3,
+	.tRRD		= 2,
+	.tWTR		= 2,
+	.tXP		= 2,
+	.tRTP		= 2,
+	.tCKE		= 3,
+	.tCKESR		= 3,
+	.tFAW		= 8
+};
+
+static const struct lpddr2_ac_timings *elpida_ac_timings[MAX_NUM_SPEEDBINS] = {
+		&timings_elpida_200_mhz,
+		&timings_elpida_333_mhz,
+		&timings_elpida_400_mhz,
+};
+
+static const struct lpddr2_device_details elpida_2G_S4_details = {
+	.type		= LPDDR2_TYPE_S4,
+	.density	= LPDDR2_DENSITY_2Gb,
+	.io_width	= LPDDR2_IO_WIDTH_32,
+	.manufacturer	= LPDDR2_MANUFACTURER_ELPIDA
+};
+
+static const struct lpddr2_device_timings elpida_2G_S4_timings = {
+	.ac_timings	= elpida_ac_timings,
+	.min_tck	= &min_tck_elpida,
+};
+
+static const struct emif_device_details elpida_2G_S4_x_2 = {
+	.cs0_device_details = &elpida_2G_S4_details,
+	.cs1_device_details = &elpida_2G_S4_details,
+	.cs0_device_timings = &elpida_2G_S4_timings,
+	.cs1_device_timings = &elpida_2G_S4_timings
+};
+
+static const struct emif_device_details elpida_2G_S4_x_1 = {
+	.cs0_device_details = &elpida_2G_S4_details,
+	.cs1_device_details = NULL,
+	.cs0_device_timings = &elpida_2G_S4_timings,
+	.cs1_device_timings = NULL
+};
+
+#endif /* ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */
+
+#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
+
+static void emif_get_reg_dump_sdp(const struct emif_regs **emif1_regs,
+			const struct emif_regs **emif2_regs)
 {
 	u32 omap4_rev = omap4_revision();
 
@@ -104,7 +231,8 @@ void emif_get_reg_dump(const struct emif_regs **emif1_regs,
 			const struct emif_regs **emif2_regs)
 	__attribute__((weak, alias("emif_get_reg_dump_sdp")));
 
-void emif_get_dmm_regs_sdp(const struct dmm_lisa_map_regs **dmm_lisa_regs)
+static void emif_get_dmm_regs_sdp(const struct dmm_lisa_map_regs
+						**dmm_lisa_regs)
 {
 	u32 omap_rev = omap4_revision();
 
@@ -116,3 +244,25 @@ void emif_get_dmm_regs_sdp(const struct dmm_lisa_map_regs **dmm_lisa_regs)
 
 void emif_get_dmm_regs(const struct dmm_lisa_map_regs **dmm_lisa_regs)
 	__attribute__((weak, alias("emif_get_dmm_regs_sdp")));
+
+#else
+
+static void emif_get_device_details_sdp(
+			const struct emif_device_details **emif1_details,
+			const struct emif_device_details **emif2_details)
+{
+	u32 omap_rev = omap4_revision();
+
+	if (omap_rev == OMAP4430_ES1_0) {
+		*emif1_details = &elpida_2G_S4_x_1;
+		*emif2_details = &elpida_2G_S4_x_1;
+	} else {
+		*emif1_details = &elpida_2G_S4_x_2;
+		*emif2_details = &elpida_2G_S4_x_2;
+	}
+}
+
+void emif_get_device_details(const struct emif_device_details **emif1_details,
+			     const struct emif_device_details **emif2_details)
+	__attribute__((weak, alias("emif_get_device_details_sdp")));
+#endif
diff --git a/arch/arm/include/asm/arch-omap4/emif.h b/arch/arm/include/asm/arch-omap4/emif.h
index f2d54cb..8cc3230 100644
--- a/arch/arm/include/asm/arch-omap4/emif.h
+++ b/arch/arm/include/asm/arch-omap4/emif.h
@@ -591,10 +591,142 @@ struct __attribute__ ((__packed__)) dmm_lisa_map_regs {
 
 #define CS0	0
 #define CS1	1
+/* The maximum frequency at which the LPDDR2 interface can operate in Hz*/
+#define MAX_LPDDR2_FREQ	400000000	/* 400 MHz */
+
+/*
+ * The period of DDR clk is represented as numerator and denominator for
+ * better accuracy in integer based calculations. However, if the numerator
+ * and denominator are very huge there may be chances of overflow in
+ * calculations. So, as a trade-off keep denominator(and consequently
+ * numerator) within a limit sacrificing some accuracy - but not much
+ * If denominator and numerator are already small (such as at 400 MHz)
+ * no adjustment is needed
+ */
+#define EMIF_PERIOD_DEN_LIMIT	1000
+/*
+ * Maximum number of different frequencies supported by EMIF driver
+ * Determines the number of entries in the pointer array for register
+ * cache
+ */
+#define EMIF_MAX_NUM_FREQUENCIES	6
+/*
+ * Indices into the Addressing Table array.
+ * One entry each for all the different types of devices with different
+ * addressing schemes
+ */
+#define ADDR_TABLE_INDEX64M	0
+#define ADDR_TABLE_INDEX128M	1
+#define ADDR_TABLE_INDEX256M	2
+#define ADDR_TABLE_INDEX512M	3
+#define ADDR_TABLE_INDEX1GS4	4
+#define ADDR_TABLE_INDEX2GS4	5
+#define ADDR_TABLE_INDEX4G	6
+#define ADDR_TABLE_INDEX8G	7
+#define ADDR_TABLE_INDEX1GS2	8
+#define ADDR_TABLE_INDEX2GS2	9
+#define ADDR_TABLE_INDEXMAX	10
+
+/* Number of Row bits */
+#define ROW_9  0
+#define ROW_10 1
+#define ROW_11 2
+#define ROW_12 3
+#define ROW_13 4
+#define ROW_14 5
+#define ROW_15 6
+#define ROW_16 7
+
+/* Number of Column bits */
+#define COL_8   0
+#define COL_9   1
+#define COL_10  2
+#define COL_11  3
+#define COL_7   4 /*Not supported by OMAP included for completeness */
+
+/* Number of Banks*/
+#define BANKS1 0
+#define BANKS2 1
+#define BANKS4 2
+#define BANKS8 3
+
+/* Refresh rate in micro seconds x 10 */
+#define T_REFI_15_6	156
+#define T_REFI_7_8	78
+#define T_REFI_3_9	39
+
+#define EBANK_CS1_DIS	0
+#define EBANK_CS1_EN	1
+
 /* Read Latency used by the device at reset */
 #define RL_BOOT		3
 /* Read Latency for the highest frequency you want to use */
 #define RL_FINAL	6
+
+/* Interleaving policies at EMIF level- between banks and Chip Selects */
+#define EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING	0
+#define EMIF_INTERLEAVING_POLICY_NO_BANK_INTERLEAVING	3
+
+/*
+ * Interleaving policy to be used
+ * Currently set to MAX interleaving for better performance
+ */
+#define EMIF_INTERLEAVING_POLICY EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING
+
+/* State of the core voltage:
+ * This is important for some parameters such as read idle control and
+ * ZQ calibration timings. Timings are much stricter when voltage ramp
+ * is happening compared to when the voltage is stable.
+ * We need to calculate two sets of values for these parameters and use
+ * them accordingly
+ */
+#define LPDDR2_VOLTAGE_STABLE	0
+#define LPDDR2_VOLTAGE_RAMPING	1
+
+/* Length of the forced read idle period in terms of cycles */
+#define EMIF_REG_READ_IDLE_LEN_VAL	5
+
+/* Interval between forced 'read idles' */
+/* To be used when voltage is changed for DPS/DVFS - 1us */
+#define READ_IDLE_INTERVAL_DVFS		(1*1000)
+/*
+ * To be used when voltage is not scaled except by Smart Reflex
+ * 50us - or maximum value will do
+ */
+#define READ_IDLE_INTERVAL_NORMAL	(50*1000)
+
+
+/*
+ * Unless voltage is changing due to DVFS one ZQCS command every 50ms should
+ * be enough. This shoule be enough also in the case when voltage is changing
+ * due to smart-reflex.
+ */
+#define EMIF_ZQCS_INTERVAL_NORMAL_IN_US	(50*1000)
+/*
+ * If voltage is changing due to DVFS ZQCS should be performed more
+ * often(every 50us)
+ */
+#define EMIF_ZQCS_INTERVAL_DVFS_IN_US	50
+
+/* The interval between ZQCL commands as a multiple of ZQCS interval */
+#define REG_ZQ_ZQCL_MULT		4
+/* The interval between ZQINIT commands as a multiple of ZQCL interval */
+#define REG_ZQ_ZQINIT_MULT		3
+/* Enable ZQ Calibration on exiting Self-refresh */
+#define REG_ZQ_SFEXITEN_ENABLE		1
+/*
+ * ZQ Calibration simultaneously on both chip-selects:
+ * Needs one calibration resistor per CS
+ * None of the boards that we know of have this capability
+ * So disabled by default
+ */
+#define REG_ZQ_DUALCALEN_DISABLE	0
+/*
+ * Enable ZQ Calibration by default on CS0. If we are asked to program
+ * the EMIF there will be something connected to CS0 for sure
+ */
+#define REG_ZQ_CS0EN_ENABLE		1
+
 /* EMIF_PWR_MGMT_CTRL register */
 /* Low power modes */
 #define LP_MODE_DISABLE		0
@@ -634,6 +766,16 @@ struct __attribute__ ((__packed__)) dmm_lisa_map_regs {
 
 /* EMIF_L3_CONFIG register value for ES1*/
 #define EMIF_L3_CONFIG_VAL_SYS_THRESH_0A_LL_THRESH_00	0x0A0000FF
+/*
+ * Value of bits 12:31 of DDR_PHY_CTRL_1 register:
+ * All these fields have magic values dependent on frequency and
+ * determined by PHY and DLL integration with EMIF. Setting the magic
+ * values suggested by hw team.
+ */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL			0x049FF
+#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ			0x41
+#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ			0x80
+#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS	0xFF
 
 /*
 * MR1 value:
@@ -657,16 +799,51 @@ struct __attribute__ ((__packed__)) dmm_lisa_map_regs {
 #define MR10_ZQ_ZQINIT		0xFF
 #define MR10_ZQ_ZQRESET		0xC3
 
+/* TEMP_ALERT_CONFIG */
+#define TEMP_ALERT_POLL_INTERVAL_MS	360 /* for temp gradient - 5 C/s */
+#define TEMP_ALERT_CONFIG_DEVCT_1	0
+#define TEMP_ALERT_CONFIG_DEVWDT_32	2
+
 /* MR16 value: refresh full array(no partial array self refresh) */
 #define MR16_REF_FULL_ARRAY	0
 
-/* LPDDR2 IO reg values */
+/* LPDDR2 IO regs */
 #define CONTROL_LPDDR2IO_SLEW_125PS_DRV8_PULL_DOWN	0x1C1C1C1C
 #define CONTROL_LPDDR2IO_SLEW_325PS_DRV8_GATE_KEEPER	0x9E9E9E9E
 
 /* CONTROL_EFUSE_2 */
 #define CONTROL_EFUSE_2_NMOS_PMOS_PTV_CODE_1		0x00ffc000
 
+/*
+ * Maximum number of entries we keep in our array of timing tables
+ * We need not keep all the speed bins supported by the device
+ * We need to keep timing tables for only the speed bins that we
+ * are interested in
+ */
+#define MAX_NUM_SPEEDBINS	4
+
+/* LPDDR2 Densities */
+#define LPDDR2_DENSITY_64Mb	0
+#define LPDDR2_DENSITY_128Mb	1
+#define LPDDR2_DENSITY_256Mb	2
+#define LPDDR2_DENSITY_512Mb	3
+#define LPDDR2_DENSITY_1Gb	4
+#define LPDDR2_DENSITY_2Gb	5
+#define LPDDR2_DENSITY_4Gb	6
+#define LPDDR2_DENSITY_8Gb	7
+#define LPDDR2_DENSITY_16Gb	8
+#define LPDDR2_DENSITY_32Gb	9
+
+/* LPDDR2 type */
+#define	LPDDR2_TYPE_S4	0
+#define	LPDDR2_TYPE_S2	1
+#define	LPDDR2_TYPE_NVM	2
+
+/* LPDDR2 IO width */
+#define	LPDDR2_IO_WIDTH_32	0
+#define	LPDDR2_IO_WIDTH_16	1
+#define	LPDDR2_IO_WIDTH_8	2
+
 /* Mode register numbers */
 #define LPDDR2_MR0	0
 #define LPDDR2_MR1	1
@@ -692,6 +869,119 @@ struct __attribute__ ((__packed__)) dmm_lisa_map_regs {
 #define LPDDR2_MR0_DNVI_SHIFT	2
 #define LPDDR2_MR0_DNVI_MASK	(1 << 2)
 
+/* MR4 */
+#define MR4_SDRAM_REF_RATE_SHIFT	0
+#define MR4_SDRAM_REF_RATE_MASK		7
+#define MR4_TUF_SHIFT			7
+#define MR4_TUF_MASK			(1 << 7)
+
+/* MR4 SDRAM Refresh Rate field values */
+#define SDRAM_TEMP_LESS_LOW_SHUTDOWN			0x0
+#define SDRAM_TEMP_LESS_4X_REFRESH_AND_TIMINGS		0x1
+#define SDRAM_TEMP_LESS_2X_REFRESH_AND_TIMINGS		0x2
+#define SDRAM_TEMP_NOMINAL				0x3
+#define SDRAM_TEMP_RESERVED_4				0x4
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH			0x5
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS	0x6
+#define SDRAM_TEMP_VERY_HIGH_SHUTDOWN			0x7
+
+#define LPDDR2_MANUFACTURER_SAMSUNG	1
+#define LPDDR2_MANUFACTURER_QIMONDA	2
+#define LPDDR2_MANUFACTURER_ELPIDA	3
+#define LPDDR2_MANUFACTURER_ETRON	4
+#define LPDDR2_MANUFACTURER_NANYA	5
+#define LPDDR2_MANUFACTURER_HYNIX	6
+#define LPDDR2_MANUFACTURER_MOSEL	7
+#define LPDDR2_MANUFACTURER_WINBOND	8
+#define LPDDR2_MANUFACTURER_ESMT	9
+#define LPDDR2_MANUFACTURER_SPANSION 11
+#define LPDDR2_MANUFACTURER_SST		12
+#define LPDDR2_MANUFACTURER_ZMOS	13
+#define LPDDR2_MANUFACTURER_INTEL	14
+#define LPDDR2_MANUFACTURER_NUMONYX	254
+#define LPDDR2_MANUFACTURER_MICRON	255
+
+/* MR8 register fields */
+#define MR8_TYPE_SHIFT		0x0
+#define MR8_TYPE_MASK		0x3
+#define MR8_DENSITY_SHIFT	0x2
+#define MR8_DENSITY_MASK	(0xF << 0x2)
+#define MR8_IO_WIDTH_SHIFT	0x6
+#define MR8_IO_WIDTH_MASK	(0x3 << 0x6)
+
+struct lpddr2_addressing {
+	u8	num_banks;
+	u8	t_REFI_us_x10;
+	u8	row_sz[2]; /* One entry each for x32 and x16 */
+	u8	col_sz[2]; /* One entry each for x32 and x16 */
+};
+
+/* Structure for timings from the DDR datasheet */
+struct lpddr2_ac_timings {
+	u32 max_freq;
+	u8 RL;
+	u8 tRPab;
+	u8 tRCD;
+	u8 tWR;
+	u8 tRASmin;
+	u8 tRRD;
+	u8 tWTRx2;
+	u8 tXSR;
+	u8 tXPx2;
+	u8 tRFCab;
+	u8 tRTPx2;
+	u8 tCKE;
+	u8 tCKESR;
+	u8 tZQCS;
+	u32 tZQCL;
+	u32 tZQINIT;
+	u8 tDQSCKMAXx2;
+	u8 tRASmax;
+	u8 tFAW;
+
+};
+
+/*
+ * Min tCK values for some of the parameters:
+ * If the calculated clock cycles for the respective parameter is
+ * less than the corresponding min tCK value, we need to set the min
+ * tCK value. This may happen at lower frequencies.
+ */
+struct lpddr2_min_tck {
+	u32 tRL;
+	u32 tRP_AB;
+	u32 tRCD;
+	u32 tWR;
+	u32 tRAS_MIN;
+	u32 tRRD;
+	u32 tWTR;
+	u32 tXP;
+	u32 tRTP;
+	u8  tCKE;
+	u32 tCKESR;
+	u32 tFAW;
+};
+
+struct lpddr2_device_details {
+	u8	type;
+	u8	density;
+	u8	io_width;
+	u8	manufacturer;
+};
+
+struct lpddr2_device_timings {
+	const struct lpddr2_ac_timings **ac_timings;
+	const struct lpddr2_min_tck *min_tck;
+};
+
+/* Details of the devices connected to each chip-select of an EMIF instance */
+struct emif_device_details {
+	const struct lpddr2_device_details *cs0_device_details;
+	const struct lpddr2_device_details *cs1_device_details;
+	const struct lpddr2_device_timings *cs0_device_timings;
+	const struct lpddr2_device_timings *cs1_device_timings;
+};
+
 /*
  * Structure containing shadow of important registers in EMIF
  * The calculation function fills in this structure to be later used for
@@ -712,8 +1002,20 @@ struct emif_regs {
 	u32 emif_ddr_phy_ctlr_1;
 };
 
+/* assert macros */
+#if defined(DEBUG)
+#define emif_assert(c)	({ if (!(c)) for (;;); })
+#else
+#define emif_assert(c)	({ if (0) hang(); })
+#endif
+
+#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
 void emif_get_reg_dump(const struct emif_regs **emif1_regs,
 			const struct emif_regs **emif2_regs);
 void emif_get_dmm_regs(const struct dmm_lisa_map_regs **dmm_lisa_regs);
+#else
+void emif_get_device_details(const struct emif_device_details **emif1_details,
+			     const struct emif_device_details **emif2_details);
+#endif
 
 #endif
diff --git a/arch/arm/include/asm/arch-omap4/omap4.h b/arch/arm/include/asm/arch-omap4/omap4.h
index a1c4883..fd8fb10 100644
--- a/arch/arm/include/asm/arch-omap4/omap4.h
+++ b/arch/arm/include/asm/arch-omap4/omap4.h
@@ -86,12 +86,7 @@
 /* GPMC */
 #define OMAP44XX_GPMC_BASE	0x50000000
 
-/* DMM */
-#define OMAP44XX_DMM_BASE		0x4E000000
-#define DMM_LISA_MAP_BASE		(OMAP44XX_DMM_BASE + 0x40)
-#define DMM_LISA_MAP_SYS_SIZE_MASK	(7 << 20)
-#define DMM_LISA_MAP_SYS_SIZE_SHIFT	20
-#define DMM_LISA_MAP_SYS_ADDR_MASK	(0xFF << 24)
+
 /*
  * Hardware Register Details
  */
@@ -137,6 +132,17 @@ struct s32ktimer {
 /* Temporary SRAM stack used while low level init is done */
 #define LOW_LEVEL_SRAM_STACK	NON_SECURE_SRAM_END
 
+#define SRAM_SCRATCH_SPACE_ADDR		NON_SECURE_SRAM_START
+
+/*
+ * SRAM scratch space entries
+ */
+
+/* Boot parameter passed from SPL to U-Boot */
+#define OMAP4_SRAM_SCRATCH_EMIF_SIZE	SRAM_SCRATCH_SPACE_ADDR
+#define OMAP4_SRAM_SCRATCH_EMIF_T_NUM	(SRAM_SCRATCH_SPACE_ADDR + 0x8)
+#define OMAP4_SRAM_SCRATCH_EMIF_T_DEN	(SRAM_SCRATCH_SPACE_ADDR + 0xC)
+
 /* Silicon revisions */
 #define OMAP4430_SILICON_ID_INVALID	0
 #define OMAP4430_ES1_0	1
diff --git a/arch/arm/include/asm/arch-omap4/sys_proto.h b/arch/arm/include/asm/arch-omap4/sys_proto.h
index 3fce576..46064f1 100644
--- a/arch/arm/include/asm/arch-omap4/sys_proto.h
+++ b/arch/arm/include/asm/arch-omap4/sys_proto.h
@@ -44,6 +44,7 @@ void bypass_dpll(u32 base);
 void freq_update_core(void);
 u32 get_sys_clk_freq(void);
 u32 omap4_ddr_clk(void);
+void cancel_out(u32 *num, u32 *den, u32 den_limit);
 void sdram_init(void);
 u32 omap4_revision(void);
 const char *omap4_rev_string(void);
diff --git a/include/configs/omap4_sdp4430.h b/include/configs/omap4_sdp4430.h
index ae009d6..d5f98dc 100644
--- a/include/configs/omap4_sdp4430.h
+++ b/include/configs/omap4_sdp4430.h
@@ -249,6 +249,11 @@
 /* Defines for Clock init */
 #define CONFIG_SYS_OMAP4_ABE_SYSCK
 
+/* Defines for SDRAM init */
+#ifndef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
+#define CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS	1
+#endif
+
 /* Defines for SPL */
 #define CONFIG_SPL
 #define CONFIG_SYS_SPL_TEXT_BASE	0x40304350
diff --git a/spl/board/ti/omap4.mk b/spl/board/ti/omap4.mk
index 85b40ca..a0e2142 100644
--- a/spl/board/ti/omap4.mk
+++ b/spl/board/ti/omap4.mk
@@ -97,8 +97,13 @@ $(obj)spl-omap.c:
 	@rm -f $@
 	@ln -s $(TOPDIR)/spl/board/ti/spl-omap.c $@
 
+$(obj)utils.c:
+	@rm -f $@
+	@ln -s $(TOPDIR)/arch/arm/cpu/armv7/omap-common/utils.c $@
+
+
 SOBJS	+= reset.o
-COBJS	+= timer.o spl-omap.o
+COBJS	+= timer.o spl-omap.o utils.o
 
 # omap4
 $(obj)lowlevel_init.S:
