[U-Boot] [PATCH v2 16/22] omap4: calculate EMIF register values

Aneesh V aneesh at ti.com
Sun May 15 17:21:34 CEST 2011


Calculate EMIF register values based on AC timing parameters
from the SDRAM datasheet and the DDR frequency rather than
using the hard-coded values.

For a new board the user doen't have to go through the tedious
process of calculating the register values. Instead, just
provide the AC timings from the device data sheet as input
and the driver will automatically calculate the register values.

Signed-off-by: Aneesh V <aneesh at ti.com>
---
V2:
* Changes for the make file changes
---
 arch/arm/cpu/armv7/omap-common/Makefile     |    1 +
 arch/arm/cpu/armv7/omap-common/utils.c      |   61 ++
 arch/arm/cpu/armv7/omap4/Makefile           |    1 -
 arch/arm/cpu/armv7/omap4/board.c            |    9 +-
 arch/arm/cpu/armv7/omap4/emif.c             |  861 ++++++++++++++++++++++++++-
 arch/arm/cpu/armv7/omap4/sdram_elpida.c     |  152 +++++-
 arch/arm/include/asm/arch-omap4/emif.h      |  304 ++++++++++-
 arch/arm/include/asm/arch-omap4/omap4.h     |   18 +-
 arch/arm/include/asm/arch-omap4/sys_proto.h |    1 +
 include/configs/omap4_sdp4430.h             |    5 +
 spl/board/ti/omap4.mk                       |    7 +-
 11 files changed, 1404 insertions(+), 16 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/omap-common/utils.c

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 at 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:
-- 
1.7.0.4



More information about the U-Boot mailing list