diff --git a/README b/README
index 766e9e0..46def00 100644
--- a/README
+++ b/README
@@ -538,6 +538,12 @@ The following options need to be configured:
 		interleaving mode, handled by Dickens for Freescale layerscape
 		SoCs with ARM core.
 
+		CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS
+		Number of controllers used as main memory.
+
+		CONFIG_SYS_FSL_OTHER_DDR_NUM_CTRLS
+		Number of controllers used for other than main memory.
+
 - Intel Monahans options:
 		CONFIG_SYS_MONAHANS_RUN_MODE_OSC_RATIO
 
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/Makefile b/arch/arm/cpu/armv8/fsl-lsch3/Makefile
index 9249537..f920eeb 100644
--- a/arch/arm/cpu/armv8/fsl-lsch3/Makefile
+++ b/arch/arm/cpu/armv8/fsl-lsch3/Makefile
@@ -7,3 +7,5 @@
 obj-y += cpu.o
 obj-y += lowlevel.o
 obj-y += speed.o
+obj-$(CONFIG_MP) += mp.o
+obj-$(CONFIG_OF_LIBFDT) += fdt.o
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/cpu.c b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c
index c129d03..47b947f 100644
--- a/arch/arm/cpu/armv8/fsl-lsch3/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c
@@ -11,6 +11,7 @@
 #include <asm/io.h>
 #include <asm/arch-fsl-lsch3/immap_lsch3.h>
 #include "cpu.h"
+#include "mp.h"
 #include "speed.h"
 #include <fsl_mc.h>
 
@@ -434,3 +435,15 @@ int cpu_eth_init(bd_t *bis)
 #endif
 	return error;
 }
+
+
+int arch_early_init_r(void)
+{
+	int rv;
+	rv = fsl_lsch3_wake_seconday_cores();
+
+	if (rv)
+		printf("Did not wake secondary cores\n");
+
+	return 0;
+}
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/cpu.h b/arch/arm/cpu/armv8/fsl-lsch3/cpu.h
index 28544d7..2e3312b 100644
--- a/arch/arm/cpu/armv8/fsl-lsch3/cpu.h
+++ b/arch/arm/cpu/armv8/fsl-lsch3/cpu.h
@@ -5,3 +5,4 @@
  */
 
 int fsl_qoriq_core_to_cluster(unsigned int core);
+u32 cpu_mask(void);
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/fdt.c b/arch/arm/cpu/armv8/fsl-lsch3/fdt.c
new file mode 100644
index 0000000..e392eb9
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/fdt.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include "mp.h"
+
+#ifdef CONFIG_MP
+void ft_fixup_cpu(void *blob)
+{
+	int off;
+	__maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr();
+	fdt32_t *reg;
+	int addr_cells;
+	u64 val;
+	size_t *boot_code_size = &(__secondary_boot_code_size);
+
+	off = fdt_path_offset(blob, "/cpus");
+	if (off < 0) {
+		puts("couldn't find /cpus node\n");
+		return;
+	}
+	of_bus_default_count_cells(blob, off, &addr_cells, NULL);
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+	while (off != -FDT_ERR_NOTFOUND) {
+		reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0);
+		if (reg) {
+			val = spin_tbl_addr;
+			val += id_to_core(of_read_number(reg, addr_cells))
+				* SPIN_TABLE_ELEM_SIZE;
+			val = cpu_to_fdt64(val);
+			fdt_setprop_string(blob, off, "enable-method",
+					   "spin-table");
+			fdt_setprop(blob, off, "cpu-release-addr",
+				    &val, sizeof(val));
+		} else {
+			puts("Warning: found cpu node without reg property\n");
+		}
+		off = fdt_node_offset_by_prop_value(blob, off, "device_type",
+						    "cpu", 4);
+	}
+
+	fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code,
+			*boot_code_size);
+}
+#endif
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_MP
+	ft_fixup_cpu(blob);
+#endif
+}
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S b/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S
index ad32b6c..2a88aab 100644
--- a/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S
+++ b/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S
@@ -8,7 +8,9 @@
 
 #include <config.h>
 #include <linux/linkage.h>
+#include <asm/gic.h>
 #include <asm/macro.h>
+#include "mp.h"
 
 ENTRY(lowlevel_init)
 	mov	x29, lr			/* Save LR */
@@ -35,31 +37,114 @@ ENTRY(lowlevel_init)
 #endif
 #endif
 
-	branch_if_master x0, x1, 1f
+	branch_if_master x0, x1, 2f
 
+	ldr	x0, =secondary_boot_func
+	blr	x0
+2:
+	mov	lr, x29			/* Restore LR */
+	ret
+ENDPROC(lowlevel_init)
+
+	/* Keep literals not used by the secondary boot code outside it */
+	.ltorg
+
+	/* Using 64 bit alignment since the spin table is accessed as data */
+	.align 4
+	.global secondary_boot_code
+	/* Secondary Boot Code starts here */
+secondary_boot_code:
+	.global __spin_table
+__spin_table:
+	.space CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE
+
+	.align 2
+ENTRY(secondary_boot_func)
 	/*
-	 * Slave should wait for master clearing spin table.
-	 * This sync prevent salves observing incorrect
-	 * value of spin table and jumping to wrong place.
+	 * MPIDR_EL1 Fields:
+	 * MPIDR[1:0] = AFF0_CPUID <- Core ID (0,1)
+	 * MPIDR[7:2] = AFF0_RES
+	 * MPIDR[15:8] = AFF1_CLUSTERID <- Cluster ID (0,1,2,3)
+	 * MPIDR[23:16] = AFF2_CLUSTERID
+	 * MPIDR[24] = MT
+	 * MPIDR[29:25] = RES0
+	 * MPIDR[30] = U
+	 * MPIDR[31] = ME
+	 * MPIDR[39:32] = AFF3
+	 *
+	 * Linear Processor ID (LPID) calculation from MPIDR_EL1:
+	 * (We only use AFF0_CPUID and AFF1_CLUSTERID for now
+	 * until AFF2_CLUSTERID and AFF3 have non-zero values)
+	 *
+	 * LPID = MPIDR[15:8] | MPIDR[1:0]
 	 */
-#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
-#ifdef CONFIG_GICV2
-	ldr	x0, =GICC_BASE
-#endif
-	bl	gic_wait_for_interrupt
-#endif
-
+	mrs	x0, mpidr_el1
+	ubfm	x1, x0, #8, #15
+	ubfm	x2, x0, #0, #1
+	orr	x10, x2, x1, lsl #2	/* x10 has LPID */
+	ubfm    x9, x0, #0, #15         /* x9 contains MPIDR[15:0] */
 	/*
-	 * All processors will enter EL2 and optionally EL1.
+	 * offset of the spin table element for this core from start of spin
+	 * table (each elem is padded to 64 bytes)
 	 */
-	bl	armv8_switch_to_el2
+	lsl	x1, x10, #6
+	ldr	x0, =__spin_table
+	/* physical address of this cpus spin table element */
+	add	x11, x1, x0
+
+	str	x9, [x11, #16]	/* LPID */
+	mov	x4, #1
+	str	x4, [x11, #8]	/* STATUS */
+	dsb	sy
+#if defined(CONFIG_GICV3)
+	gic_wait_for_interrupt_m x0
+#elif defined(CONFIG_GICV2)
+        ldr     x0, =GICC_BASE
+        gic_wait_for_interrupt_m x0, w1
+#endif
+
+	bl secondary_switch_to_el2
 #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
-	bl	armv8_switch_to_el1
+	bl secondary_switch_to_el1
 #endif
-	b	2f
 
-1:
-2:
-	mov	lr, x29			/* Restore LR */
-	ret
-ENDPROC(lowlevel_init)
+slave_cpu:
+	wfe
+	ldr	x0, [x11]
+	cbz	x0, slave_cpu
+#ifndef CONFIG_ARMV8_SWITCH_TO_EL1
+	mrs     x1, sctlr_el2
+#else
+	mrs     x1, sctlr_el1
+#endif
+	tbz     x1, #25, cpu_is_le
+	rev     x0, x0                  /* BE to LE conversion */
+cpu_is_le:
+	br	x0			/* branch to the given address */
+ENDPROC(secondary_boot_func)
+
+ENTRY(secondary_switch_to_el2)
+	switch_el x0, 1f, 0f, 0f
+0:	ret
+1:	armv8_switch_to_el2_m x0
+ENDPROC(secondary_switch_to_el2)
+
+ENTRY(secondary_switch_to_el1)
+	switch_el x0, 0f, 1f, 0f
+0:	ret
+1:	armv8_switch_to_el1_m x0, x1
+ENDPROC(secondary_switch_to_el1)
+
+	/* Ensure that the literals used by the secondary boot code are
+	 * assembled within it (this is required so that we can protect
+	 * this area with a single memreserve region
+	 */
+	.ltorg
+
+	/* 64 bit alignment for elements accessed as data */
+	.align 4
+	.globl __secondary_boot_code_size
+	.type __secondary_boot_code_size, %object
+	/* Secondary Boot Code ends here */
+__secondary_boot_code_size:
+	.quad .-secondary_boot_code
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/mp.c b/arch/arm/cpu/armv8/fsl-lsch3/mp.c
new file mode 100644
index 0000000..94998bf
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/mp.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/arch-fsl-lsch3/immap_lsch3.h>
+#include "mp.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void *get_spin_tbl_addr(void)
+{
+	return &__spin_table;
+}
+
+phys_addr_t determine_mp_bootpg(void)
+{
+	return (phys_addr_t)&secondary_boot_code;
+}
+
+int fsl_lsch3_wake_seconday_cores(void)
+{
+	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+	struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
+	u32 cores, cpu_up_mask = 1;
+	int i, timeout = 10;
+	u64 *table = get_spin_tbl_addr();
+
+	cores = cpu_mask();
+	/* Clear spin table so that secondary processors
+	 * observe the correct value after waking up from wfe.
+	 */
+	memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE);
+	flush_dcache_range((unsigned long)table,
+			   (unsigned long)table +
+			   (CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE));
+
+	printf("Waking secondary cores to start from %lx\n", gd->relocaddr);
+	out_le32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32));
+	out_le32(&gur->bootlocptrl, (u32)gd->relocaddr);
+	out_le32(&gur->scratchrw[6], 1);
+	asm volatile("dsb st" : : : "memory");
+	rst->brrl = cores;
+	asm volatile("dsb st" : : : "memory");
+
+	/* This is needed as a precautionary measure.
+	 * If some code before this has accidentally  released the secondary
+	 * cores then the pre-bootloader code will trap them in a "wfe" unless
+	 * the scratchrw[6] is set. In this case we need a sev here to get these
+	 * cores moving again.
+	 */
+	asm volatile("sev");
+
+	while (timeout--) {
+		flush_dcache_range((unsigned long)table, (unsigned long)table +
+				   CONFIG_MAX_CPUS * 64);
+		for (i = 1; i < CONFIG_MAX_CPUS; i++) {
+			if (table[i * WORDS_PER_SPIN_TABLE_ENTRY +
+					SPIN_TABLE_ELEM_STATUS_IDX])
+				cpu_up_mask |= 1 << i;
+		}
+		if (hweight32(cpu_up_mask) == hweight32(cores))
+			break;
+		udelay(10);
+	}
+	if (timeout <= 0) {
+		printf("Not all cores (0x%x) are up (0x%x)\n",
+		       cores, cpu_up_mask);
+		return 1;
+	}
+	printf("All (%d) cores are up.\n", hweight32(cores));
+
+	return 0;
+}
+
+int is_core_valid(unsigned int core)
+{
+	return !!((1 << core) & cpu_mask());
+}
+
+int cpu_reset(int nr)
+{
+	puts("Feature is not implemented.\n");
+
+	return 0;
+}
+
+int cpu_disable(int nr)
+{
+	puts("Feature is not implemented.\n");
+
+	return 0;
+}
+
+int core_to_pos(int nr)
+{
+	u32 cores = cpu_mask();
+	int i, count = 0;
+
+	if (nr == 0) {
+		return 0;
+	} else if (nr >= hweight32(cores)) {
+		puts("Not a valid core number.\n");
+		return -1;
+	}
+
+	for (i = 1; i < 32; i++) {
+		if (is_core_valid(i)) {
+			count++;
+			if (count == nr)
+				break;
+		}
+	}
+
+	return count;
+}
+
+int cpu_status(int nr)
+{
+	u64 *table;
+	int pos;
+
+	if (nr == 0) {
+		table = (u64 *)get_spin_tbl_addr();
+		printf("table base @ 0x%p\n", table);
+	} else {
+		pos = core_to_pos(nr);
+		if (pos < 0)
+			return -1;
+		table = (u64 *)get_spin_tbl_addr() + pos *
+			WORDS_PER_SPIN_TABLE_ENTRY;
+		printf("table @ 0x%p\n", table);
+		printf("   addr - 0x%016llx\n",
+		       table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]);
+		printf("   status   - 0x%016llx\n",
+		       table[SPIN_TABLE_ELEM_STATUS_IDX]);
+		printf("   lpid  - 0x%016llx\n",
+		       table[SPIN_TABLE_ELEM_LPID_IDX]);
+	}
+
+	return 0;
+}
+
+int cpu_release(int nr, int argc, char * const argv[])
+{
+	u64 boot_addr;
+	u64 *table = (u64 *)get_spin_tbl_addr();
+	int pos;
+
+	pos = core_to_pos(nr);
+	if (pos <= 0)
+		return -1;
+
+	table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
+	boot_addr = simple_strtoull(argv[0], NULL, 16);
+	table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr;
+	flush_dcache_range((unsigned long)table,
+			   (unsigned long)table + SPIN_TABLE_ELEM_SIZE);
+	asm volatile("dsb st");
+	smp_kick_all_cpus();	/* only those with entry addr set will run */
+
+	return 0;
+}
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/mp.h b/arch/arm/cpu/armv8/fsl-lsch3/mp.h
new file mode 100644
index 0000000..06ac0bc
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/mp.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014, Freescale Semiconductor
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _FSL_CH3_MP_H
+#define _FSL_CH3_MP_H
+
+/*
+* Each spin table element is defined as
+* struct {
+*      uint64_t entry_addr;
+*      uint64_t status;
+*      uint64_t lpid;
+* };
+* we pad this struct to 64 bytes so each entry is in its own cacheline
+* the actual spin table is an array of these structures
+*/
+#define SPIN_TABLE_ELEM_ENTRY_ADDR_IDX	0
+#define SPIN_TABLE_ELEM_STATUS_IDX	1
+#define SPIN_TABLE_ELEM_LPID_IDX	2
+#define WORDS_PER_SPIN_TABLE_ENTRY	8	/* pad to 64 bytes */
+#define SPIN_TABLE_ELEM_SIZE		64
+
+#define id_to_core(x)	((x & 3) | (x >> 6))
+#ifndef __ASSEMBLY__
+extern u64 __spin_table[];
+extern u64 *secondary_boot_code;
+extern size_t __secondary_boot_code_size;
+int fsl_lsch3_wake_seconday_cores(void);
+void *get_spin_tbl_addr(void);
+phys_addr_t determine_mp_bootpg(void);
+void secondary_boot_func(void);
+#endif
+#endif /* _FSL_CH3_MP_H */
diff --git a/arch/arm/cpu/armv8/transition.S b/arch/arm/cpu/armv8/transition.S
index 38dea5c..ade1cde 100644
--- a/arch/arm/cpu/armv8/transition.S
+++ b/arch/arm/cpu/armv8/transition.S
@@ -14,70 +14,11 @@
 ENTRY(armv8_switch_to_el2)
 	switch_el x0, 1f, 0f, 0f
 0:	ret
-1:
-	mov	x0, #0x5b1	/* Non-secure EL0/EL1 | HVC | 64bit EL2 */
-	msr	scr_el3, x0
-	msr	cptr_el3, xzr	/* Disable coprocessor traps to EL3 */
-	mov	x0, #0x33ff
-	msr	cptr_el2, x0	/* Disable coprocessor traps to EL2 */
-
-	/* Initialize SCTLR_EL2 */
-	msr	sctlr_el2, xzr
-
-	/* Return to the EL2_SP2 mode from EL3 */
-	mov	x0, sp
-	msr	sp_el2, x0	/* Migrate SP */
-	mrs	x0, vbar_el3
-	msr	vbar_el2, x0	/* Migrate VBAR */
-	mov	x0, #0x3c9
-	msr	spsr_el3, x0	/* EL2_SP2 | D | A | I | F */
-	msr	elr_el3, lr
-	eret
+1:	armv8_switch_to_el2_m x0
 ENDPROC(armv8_switch_to_el2)
 
 ENTRY(armv8_switch_to_el1)
 	switch_el x0, 0f, 1f, 0f
 0:	ret
-1:
-	/* Initialize Generic Timers */
-	mrs	x0, cnthctl_el2
-	orr	x0, x0, #0x3		/* Enable EL1 access to timers */
-	msr	cnthctl_el2, x0
-	msr	cntvoff_el2, xzr
-	mrs	x0, cntkctl_el1
-	orr	x0, x0, #0x3		/* Enable EL0 access to timers */
-	msr	cntkctl_el1, x0
-
-	/* Initilize MPID/MPIDR registers */
-	mrs	x0, midr_el1
-	mrs	x1, mpidr_el1
-	msr	vpidr_el2, x0
-	msr	vmpidr_el2, x1
-
-	/* Disable coprocessor traps */
-	mov	x0, #0x33ff
-	msr	cptr_el2, x0		/* Disable coprocessor traps to EL2 */
-	msr	hstr_el2, xzr		/* Disable coprocessor traps to EL2 */
-	mov	x0, #3 << 20
-	msr	cpacr_el1, x0		/* Enable FP/SIMD at EL1 */
-
-	/* Initialize HCR_EL2 */
-	mov	x0, #(1 << 31)		/* 64bit EL1 */
-	orr	x0, x0, #(1 << 29)	/* Disable HVC */
-	msr	hcr_el2, x0
-
-	/* SCTLR_EL1 initialization */
-	mov	x0, #0x0800
-	movk	x0, #0x30d0, lsl #16
-	msr	sctlr_el1, x0
-
-	/* Return to the EL1_SP1 mode from EL2 */
-	mov	x0, sp
-	msr	sp_el1, x0		/* Migrate SP */
-	mrs	x0, vbar_el2
-	msr	vbar_el1, x0		/* Migrate VBAR */
-	mov	x0, #0x3c5
-	msr	spsr_el2, x0		/* EL1_SP1 | D | A | I | F */
-	msr	elr_el2, lr
-	eret
+1:	armv8_switch_to_el1_m x0, x1
 ENDPROC(armv8_switch_to_el1)
diff --git a/arch/arm/include/asm/arch-fsl-lsch3/config.h b/arch/arm/include/asm/arch-fsl-lsch3/config.h
index b17410a..da551e8 100644
--- a/arch/arm/include/asm/arch-fsl-lsch3/config.h
+++ b/arch/arm/include/asm/arch-fsl-lsch3/config.h
@@ -8,7 +8,7 @@
 #define _ASM_ARMV8_FSL_LSCH3_CONFIG_
 
 #include <fsl_ddrc_version.h>
-
+#define CONFIG_MP
 #define CONFIG_SYS_FSL_OCRAM_BASE	0x18000000	/* initial RAM */
 /* Link Definitions */
 #define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_FSL_OCRAM_BASE + 0xfff0)
@@ -16,8 +16,10 @@
 #define CONFIG_SYS_IMMR				0x01000000
 #define CONFIG_SYS_FSL_DDR_ADDR			(CONFIG_SYS_IMMR + 0x00080000)
 #define CONFIG_SYS_FSL_DDR2_ADDR		(CONFIG_SYS_IMMR + 0x00090000)
+#define CONFIG_SYS_FSL_DDR3_ADDR		0x08210000
 #define CONFIG_SYS_FSL_GUTS_ADDR		(CONFIG_SYS_IMMR + 0x00E00000)
 #define CONFIG_SYS_FSL_PMU_ADDR			(CONFIG_SYS_IMMR + 0x00E30000)
+#define CONFIG_SYS_FSL_RST_ADDR			(CONFIG_SYS_IMMR + 0x00E60000)
 #define CONFIG_SYS_FSL_CH3_CLK_GRPA_ADDR	(CONFIG_SYS_IMMR + 0x00300000)
 #define CONFIG_SYS_FSL_CH3_CLK_GRPB_ADDR	(CONFIG_SYS_IMMR + 0x00310000)
 #define CONFIG_SYS_FSL_CH3_CLK_CTRL_ADDR	(CONFIG_SYS_IMMR + 0x00370000)
@@ -60,7 +62,7 @@
 #ifdef CONFIG_LS2085A
 #define CONFIG_MAX_CPUS				16
 #define CONFIG_SYS_FSL_IFC_BANK_COUNT		8
-#define CONFIG_NUM_DDR_CONTROLLERS		2
+#define CONFIG_NUM_DDR_CONTROLLERS		3
 #define CONFIG_SYS_FSL_CLUSTER_CLOCKS		{ 1, 1, 4, 4 }
 #else
 #error SoC not defined
diff --git a/arch/arm/include/asm/arch-fsl-lsch3/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-lsch3/immap_lsch3.h
index 18e66bd..ee1d651 100644
--- a/arch/arm/include/asm/arch-fsl-lsch3/immap_lsch3.h
+++ b/arch/arm/include/asm/arch-fsl-lsch3/immap_lsch3.h
@@ -113,4 +113,39 @@ struct ccsr_clk_ctrl {
 		u8  res_04[0x20-0x04];
 	} clkcncsr[8];
 };
+
+struct ccsr_reset {
+	u32 rstcr;			/* 0x000 */
+	u32 rstcrsp;			/* 0x004 */
+	u8 res_008[0x10-0x08];		/* 0x008 */
+	u32 rstrqmr1;			/* 0x010 */
+	u32 rstrqmr2;			/* 0x014 */
+	u32 rstrqsr1;			/* 0x018 */
+	u32 rstrqsr2;			/* 0x01c */
+	u32 rstrqwdtmrl;		/* 0x020 */
+	u32 rstrqwdtmru;		/* 0x024 */
+	u8 res_028[0x30-0x28];		/* 0x028 */
+	u32 rstrqwdtsrl;		/* 0x030 */
+	u32 rstrqwdtsru;		/* 0x034 */
+	u8 res_038[0x60-0x38];		/* 0x038 */
+	u32 brrl;			/* 0x060 */
+	u32 brru;			/* 0x064 */
+	u8 res_068[0x80-0x68];		/* 0x068 */
+	u32 pirset;			/* 0x080 */
+	u32 pirclr;			/* 0x084 */
+	u8 res_088[0x90-0x88];		/* 0x088 */
+	u32 brcorenbr;			/* 0x090 */
+	u8 res_094[0x100-0x94];		/* 0x094 */
+	u32 rcw_reqr;			/* 0x100 */
+	u32 rcw_completion;		/* 0x104 */
+	u8 res_108[0x110-0x108];	/* 0x108 */
+	u32 pbi_reqr;			/* 0x110 */
+	u32 pbi_completion;		/* 0x114 */
+	u8 res_118[0xa00-0x118];	/* 0x118 */
+	u32 qmbm_warmrst;		/* 0xa00 */
+	u32 soc_warmrst;		/* 0xa04 */
+	u8 res_a08[0xbf8-0xa08];	/* 0xa08 */
+	u32 ip_rev1;			/* 0xbf8 */
+	u32 ip_rev2;			/* 0xbfc */
+};
 #endif /* __ARCH_FSL_LSCH3_IMMAP_H */
diff --git a/arch/arm/include/asm/arch-ls102xa/config.h b/arch/arm/include/asm/arch-ls102xa/config.h
index ed78c33..a500b5b 100644
--- a/arch/arm/include/asm/arch-ls102xa/config.h
+++ b/arch/arm/include/asm/arch-ls102xa/config.h
@@ -50,7 +50,11 @@
 #ifdef CONFIG_DDR_SPD
 #define CONFIG_SYS_FSL_DDR_BE
 #define CONFIG_VERY_BIG_RAM
+#ifdef CONFIG_SYS_FSL_DDR4
+#define CONFIG_SYS_FSL_DDRC_GEN4
+#else
 #define CONFIG_SYS_FSL_DDRC_ARM_GEN3
+#endif
 #define CONFIG_SYS_FSL_DDR
 #define CONFIG_SYS_LS1_DDR_BLOCK1_SIZE		((phys_size_t)2 << 30)
 #define CONFIG_MAX_MEM_MAPPED			CONFIG_SYS_LS1_DDR_BLOCK1_SIZE
@@ -71,6 +75,7 @@
 #define CONFIG_MAX_CPUS				2
 #define CONFIG_SYS_FSL_IFC_BANK_COUNT		8
 #define CONFIG_NUM_DDR_CONTROLLERS		1
+#define CONFIG_SYS_FSL_DDR_VER			FSL_DDR_VER_5_0
 #else
 #error SoC not defined
 #endif
diff --git a/arch/arm/include/asm/macro.h b/arch/arm/include/asm/macro.h
index f77e4b8..541b443 100644
--- a/arch/arm/include/asm/macro.h
+++ b/arch/arm/include/asm/macro.h
@@ -105,6 +105,99 @@ lr	.req	x30
 	cbz	\xreg1, \master_label
 .endm
 
+.macro armv8_switch_to_el2_m, xreg1
+	/* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1 */
+	mov	\xreg1, #0x5b1
+	msr	scr_el3, \xreg1
+	msr	cptr_el3, xzr		/* Disable coprocessor traps to EL3 */
+	mov	\xreg1, #0x33ff
+	msr	cptr_el2, \xreg1	/* Disable coprocessor traps to EL2 */
+
+	/* Initialize SCTLR_EL2
+	 *
+	 * setting RES1 bits (29,28,23,22,18,16,11,5,4) to 1
+	 * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
+	 * EE,WXN,I,SA,C,A,M to 0
+	 */
+	mov	\xreg1, #0x0830
+	movk	\xreg1, #0x30C5, lsl #16
+	msr	sctlr_el2, \xreg1
+
+	/* Return to the EL2_SP2 mode from EL3 */
+	mov	\xreg1, sp
+	msr	sp_el2, \xreg1		/* Migrate SP */
+	mrs	\xreg1, vbar_el3
+	msr	vbar_el2, \xreg1	/* Migrate VBAR */
+	mov	\xreg1, #0x3c9
+	msr	spsr_el3, \xreg1	/* EL2_SP2 | D | A | I | F */
+	msr	elr_el3, lr
+	eret
+.endm
+
+.macro armv8_switch_to_el1_m, xreg1, xreg2
+	/* Initialize Generic Timers */
+	mrs	\xreg1, cnthctl_el2
+	orr	\xreg1, \xreg1, #0x3	/* Enable EL1 access to timers */
+	msr	cnthctl_el2, \xreg1
+	msr	cntvoff_el2, xzr
+
+	/* Initilize MPID/MPIDR registers */
+	mrs	\xreg1, midr_el1
+	mrs	\xreg2, mpidr_el1
+	msr	vpidr_el2, \xreg1
+	msr	vmpidr_el2, \xreg2
+
+	/* Disable coprocessor traps */
+	mov	\xreg1, #0x33ff
+	msr	cptr_el2, \xreg1	/* Disable coprocessor traps to EL2 */
+	msr	hstr_el2, xzr		/* Disable coprocessor traps to EL2 */
+	mov	\xreg1, #3 << 20
+	msr	cpacr_el1, \xreg1	/* Enable FP/SIMD at EL1 */
+
+	/* Initialize HCR_EL2 */
+	mov	\xreg1, #(1 << 31)		/* 64bit EL1 */
+	orr	\xreg1, \xreg1, #(1 << 29)	/* Disable HVC */
+	msr	hcr_el2, \xreg1
+
+	/* SCTLR_EL1 initialization
+	 *
+	 * setting RES1 bits (29,28,23,22,20,11) to 1
+	 * and RES0 bits (31,30,27,21,17,13,10,6) +
+	 * UCI,EE,EOE,WXN,nTWE,nTWI,UCT,DZE,I,UMA,SED,ITD,
+	 * CP15BEN,SA0,SA,C,A,M to 0
+	 */
+	mov	\xreg1, #0x0800
+	movk	\xreg1, #0x30d0, lsl #16
+	msr	sctlr_el1, \xreg1
+
+	/* Return to the EL1_SP1 mode from EL2 */
+	mov	\xreg1, sp
+	msr	sp_el1, \xreg1		/* Migrate SP */
+	mrs	\xreg1, vbar_el2
+	msr	vbar_el1, \xreg1	/* Migrate VBAR */
+	mov	\xreg1, #0x3c5
+	msr	spsr_el2, \xreg1	/* EL1_SP1 | D | A | I | F */
+	msr	elr_el2, lr
+	eret
+.endm
+
+#if defined(CONFIG_GICV3)
+.macro gic_wait_for_interrupt_m xreg1
+0 :	wfi
+	mrs     \xreg1, ICC_IAR1_EL1
+	msr     ICC_EOIR1_EL1, \xreg1
+	cbnz    \xreg1, 0b
+.endm
+#elif defined(CONFIG_GICV2)
+.macro gic_wait_for_interrupt_m xreg1, wreg2
+0 :	wfi
+	ldr     \wreg2, [\xreg1, GICC_AIAR]
+	str     \wreg2, [\xreg1, GICC_AEOIR]
+	and	\wreg2, \wreg2, #3ff
+	cbnz    \wreg2, 0b
+.endm
+#endif
+
 #endif /* CONFIG_ARM64 */
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm/lib/gic_64.S b/arch/arm/lib/gic_64.S
index d56396e..a3e18f7 100644
--- a/arch/arm/lib/gic_64.S
+++ b/arch/arm/lib/gic_64.S
@@ -10,8 +10,8 @@
 #include <asm-offsets.h>
 #include <config.h>
 #include <linux/linkage.h>
-#include <asm/macro.h>
 #include <asm/gic.h>
+#include <asm/macro.h>
 
 
 /*************************************************************************
@@ -181,14 +181,10 @@ ENDPROC(gic_kick_secondary_cpus)
  *
  *************************************************************************/
 ENTRY(gic_wait_for_interrupt)
-0:	wfi
 #if defined(CONFIG_GICV3)
-	mrs	x9, ICC_IAR1_EL1
-	msr	ICC_EOIR1_EL1, x9
+	gic_wait_for_interrupt_m x9
 #elif defined(CONFIG_GICV2)
-	ldr	w9, [x0, GICC_AIAR]
-	str	w9, [x0, GICC_AEOIR]
+	gic_wait_for_interrupt_m x0, w9
 #endif
-	cbnz	w9, 0b
 	ret
 ENDPROC(gic_wait_for_interrupt)
diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c
index 6274f92..3d6ec84 100644
--- a/arch/powerpc/cpu/mpc85xx/cpu.c
+++ b/arch/powerpc/cpu/mpc85xx/cpu.c
@@ -441,7 +441,7 @@ phys_size_t initdram(int board_type)
 
 /* Board-specific functions defined in each board's ddr.c */
 void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
-	unsigned int ctrl_num);
+	unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl);
 void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn,
 		       phys_addr_t *rpn);
 unsigned int
@@ -459,7 +459,7 @@ static void dump_spd_ddr_reg(void)
 		spd[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR];
 
 	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
-		fsl_ddr_get_spd(spd[i], i);
+		fsl_ddr_get_spd(spd[i], i, CONFIG_DIMM_SLOTS_PER_CTLR);
 
 	puts("SPD data of all dimms (zero vaule is omitted)...\n");
 	puts("Byte (hex)  ");
diff --git a/board/freescale/ls1021aqds/MAINTAINERS b/board/freescale/ls1021aqds/MAINTAINERS
index 021d82b..ccf4513 100644
--- a/board/freescale/ls1021aqds/MAINTAINERS
+++ b/board/freescale/ls1021aqds/MAINTAINERS
@@ -4,3 +4,4 @@ S:	Maintained
 F:	board/freescale/ls1021aqds/
 F:	include/configs/ls1021aqds.h
 F:	configs/ls1021aqds_nor_defconfig
+F:	configs/ls1021aqds_ddr4_nor_defconfig
diff --git a/board/freescale/ls1021aqds/ddr.c b/board/freescale/ls1021aqds/ddr.c
index 679c654..5898e33 100644
--- a/board/freescale/ls1021aqds/ddr.c
+++ b/board/freescale/ls1021aqds/ddr.c
@@ -79,7 +79,6 @@ found:
 	 */
 	popts->wrlvl_override = 1;
 	popts->wrlvl_sample = 0xf;
-	popts->cswl_override = DDR_CSWL_CS0;
 
 	/*
 	 * Rtt and Rtt_WR override
@@ -89,9 +88,17 @@ found:
 	/* Enable ZQ calibration */
 	popts->zq_en = 1;
 
+#ifdef CONFIG_SYS_FSL_DDR4
+	popts->ddr_cdr1 = DDR_CDR1_DHC_EN | DDR_CDR1_ODT(DDR_CDR_ODT_80ohm);
+	popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_80ohm) |
+			  DDR_CDR2_VREF_OVRD(70);	/* Vref = 70% */
+#else
+	popts->cswl_override = DDR_CSWL_CS0;
+
 	/* DHC_EN =1, ODT = 75 Ohm */
 	popts->ddr_cdr1 = DDR_CDR1_DHC_EN | DDR_CDR1_ODT(DDR_CDR_ODT_75ohm);
 	popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_75ohm);
+#endif
 }
 
 #ifdef CONFIG_SYS_DDR_RAW_TIMING
diff --git a/board/freescale/ls1021aqds/ddr.h b/board/freescale/ls1021aqds/ddr.h
index 16d87cb..f819c99 100644
--- a/board/freescale/ls1021aqds/ddr.h
+++ b/board/freescale/ls1021aqds/ddr.h
@@ -30,6 +30,13 @@ static const struct board_specific_parameters udimm0[] = {
 	 *   num|  hi| rank|  clk| wrlvl |   wrlvl   |  wrlvl | cpo  |wrdata|2T
 	 * ranks| mhz| GB  |adjst| start |   ctl2    |  ctl3  |      |delay |
 	 */
+#ifdef CONFIG_SYS_FSL_DDR4
+	{2,  1666, 0, 4,     7, 0x0808090B, 0x0C0D0E0A,},
+	{2,  1900, 0, 4,     6, 0x08080A0C, 0x0D0E0F0A,},
+	{1,  1666, 0, 4,     8, 0x090A0B0B, 0x0C0D0E0C,},
+	{1,  1900, 0, 4,     9, 0x0A0B0C0B, 0x0D0E0F0D,},
+	{1,  2200, 0, 4,    10, 0x0B0C0D0C, 0x0E0F110E,},
+#elif defined(CONFIG_SYS_FSL_DDR3)
 	{1,  833,  1, 6,     8, 0x06060607, 0x08080807,   0x1f,    2,  0},
 	{1,  1350, 1, 6,     8, 0x0708080A, 0x0A0B0C09,   0x1f,    2,  0},
 	{1,  833,  2, 6,     8, 0x06060607, 0x08080807,   0x1f,    2,  0},
@@ -39,6 +46,9 @@ static const struct board_specific_parameters udimm0[] = {
 	{2,  1350, 0, 6,     8, 0x0708080A, 0x0A0B0C09,   0x1f,    2,  0},
 	{2,  1666, 4, 4,   0xa, 0x0B08090C, 0x0B0E0D0A,   0x1f,    2,  0},
 	{2,  1666, 0, 4,   0xa, 0x0B08090C, 0x0B0E0D0A,   0x1f,    2,  0},
+#else
+#error DDR type not defined
+#endif
 	{}
 };
 
diff --git a/board/freescale/ls2085a/ddr.c b/board/freescale/ls2085a/ddr.c
index 257bc16..b4a3fc9 100644
--- a/board/freescale/ls2085a/ddr.c
+++ b/board/freescale/ls2085a/ddr.c
@@ -30,9 +30,9 @@ void fsl_ddr_board_options(memctl_options_t *popts,
 	 * to  pbsp = rdimms[ctrl_num] or pbsp = udimms[ctrl_num];
 	 */
 	if (popts->registered_dimm_en)
-		pbsp = rdimms[0];
+		pbsp = rdimms[ctrl_num];
 	else
-		pbsp = udimms[0];
+		pbsp = udimms[ctrl_num];
 
 
 	/* Get clk_adjust, wrlvl_start, wrlvl_ctl, according to the board ddr
@@ -72,6 +72,12 @@ found:
 		pbsp->clk_adjust, pbsp->wrlvl_start, pbsp->wrlvl_ctl_2,
 		pbsp->wrlvl_ctl_3);
 
+	if (ctrl_num == CONFIG_DP_DDR_CTRL) {
+		/* force DDR bus width to 32 bits */
+		popts->data_bus_width = 1;
+		popts->otf_burst_chop_en = 0;
+		popts->burst_length = DDR_BL8;
+	}
 	/*
 	 * Factors to consider for half-strength driver enable:
 	 *	- number of DIMMs installed
@@ -163,6 +169,10 @@ phys_size_t initdram(int board_type)
 
 void dram_init_banksize(void)
 {
+#ifdef CONFIG_SYS_DP_DDR_BASE_PHY
+	phys_size_t dp_ddr_size;
+#endif
+
 	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
 	if (gd->ram_size > CONFIG_SYS_LS2_DDR_BLOCK1_SIZE) {
 		gd->bd->bi_dram[0].size = CONFIG_SYS_LS2_DDR_BLOCK1_SIZE;
@@ -172,4 +182,24 @@ void dram_init_banksize(void)
 	} else {
 		gd->bd->bi_dram[0].size = gd->ram_size;
 	}
+
+#ifdef CONFIG_SYS_DP_DDR_BASE_PHY
+	/* initialize DP-DDR here */
+	puts("DP-DDR:  ");
+	/*
+	 * DDR controller use 0 as the base address for binding.
+	 * It is mapped to CONFIG_SYS_DP_DDR_BASE for core to access.
+	 */
+	dp_ddr_size = fsl_other_ddr_sdram(CONFIG_SYS_DP_DDR_BASE_PHY,
+					  CONFIG_DP_DDR_CTRL,
+					  CONFIG_DP_DDR_NUM_CTRLS,
+					  CONFIG_DP_DDR_DIMM_SLOTS_PER_CTLR,
+					  NULL, NULL, NULL);
+	if (dp_ddr_size) {
+		gd->bd->bi_dram[2].start = CONFIG_SYS_DP_DDR_BASE;
+		gd->bd->bi_dram[2].size = dp_ddr_size;
+	} else {
+		puts("Not detected");
+	}
+#endif
 }
diff --git a/board/freescale/ls2085a/ddr.h b/board/freescale/ls2085a/ddr.h
index 77f6aaf..9958a68 100644
--- a/board/freescale/ls2085a/ddr.h
+++ b/board/freescale/ls2085a/ddr.h
@@ -33,6 +33,18 @@ static const struct board_specific_parameters udimm0[] = {
 	{}
 };
 
+/* DP-DDR DIMM */
+static const struct board_specific_parameters udimm2[] = {
+	/*
+	 * memory controller 2
+	 *   num|  hi| rank|  clk| wrlvl |   wrlvl   |  wrlvl
+	 * ranks| mhz| GB  |adjst| start |   ctl2    |  ctl3
+	 */
+	{2,  2140, 0, 4,     4, 0x0, 0x0},
+	{1,  2140, 0, 4,     4, 0x0, 0x0},
+	{}
+};
+
 static const struct board_specific_parameters rdimm0[] = {
 	/*
 	 * memory controller 0
@@ -45,12 +57,29 @@ static const struct board_specific_parameters rdimm0[] = {
 	{}
 };
 
+/* DP-DDR DIMM */
+static const struct board_specific_parameters rdimm2[] = {
+	/*
+	 * memory controller 2
+	 *   num|  hi| rank|  clk| wrlvl |   wrlvl   |  wrlvl
+	 * ranks| mhz| GB  |adjst| start |   ctl2    |  ctl3
+	 */
+	{4,  2140, 0, 5,     4, 0x0, 0x0},
+	{2,  2140, 0, 5,     4, 0x0, 0x0},
+	{1,  2140, 0, 4,     4, 0x0, 0x0},
+	{}
+};
+
 static const struct board_specific_parameters *udimms[] = {
 	udimm0,
+	udimm0,
+	udimm2,
 };
 
 static const struct board_specific_parameters *rdimms[] = {
 	rdimm0,
+	rdimm0,
+	rdimm2,
 };
 
 
diff --git a/board/freescale/ls2085a/ls2085a.c b/board/freescale/ls2085a/ls2085a.c
index a18db1d..2c79a71 100644
--- a/board/freescale/ls2085a/ls2085a.c
+++ b/board/freescale/ls2085a/ls2085a.c
@@ -13,12 +13,18 @@
 #include <fdt_support.h>
 #include <libfdt.h>
 #include <fsl_mc.h>
+#include <environment.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 int board_init(void)
 {
 	init_final_memctl_regs();
+
+#ifdef CONFIG_ENV_IS_NOWHERE
+	gd->env_addr = (ulong)&default_environment[0];
+#endif
+
 	return 0;
 }
 
@@ -29,9 +35,20 @@ int board_early_init_f(void)
 	return 0;
 }
 
+void detail_board_ddr_info(void)
+{
+	puts("\nDDR    ");
+	print_size(gd->bd->bi_dram[0].size + gd->bd->bi_dram[1].size, "");
+	print_ddr_info(0);
+	if (gd->bd->bi_dram[2].size) {
+		puts("\nDP-DDR ");
+		print_size(gd->bd->bi_dram[2].size, "");
+		print_ddr_info(CONFIG_DP_DDR_CTRL);
+	}
+}
+
 int dram_init(void)
 {
-	printf("DRAM:  ");
 	gd->ram_size = initdram(0);
 
 	return 0;
@@ -88,6 +105,8 @@ void ft_board_setup(void *blob, bd_t *bd)
 	phys_addr_t base;
 	phys_size_t size;
 
+	ft_cpu_setup(blob, bd);
+
 	/* limit the memory size to bank 1 until Linux can handle 40-bit PA */
 	base = getenv_bootm_low();
 	size = getenv_bootm_size();
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 784a570..3f64156 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -930,15 +930,6 @@ void fdt_del_node_and_alias(void *blob, const char *alias)
 	fdt_delprop(blob, off, alias);
 }
 
-/* Helper to read a big number; size is in cells (not bytes) */
-static inline u64 of_read_number(const fdt32_t *cell, int size)
-{
-	u64 r = 0;
-	while (size--)
-		r = (r << 32) | fdt32_to_cpu(*(cell++));
-	return r;
-}
-
 #define PRu64	"%llx"
 
 /* Max address size we deal with */
@@ -972,7 +963,7 @@ struct of_bus {
 };
 
 /* Default translator (generic bus) */
-static void of_bus_default_count_cells(void *blob, int parentoffset,
+void of_bus_default_count_cells(void *blob, int parentoffset,
 					int *addrc, int *sizec)
 {
 	const fdt32_t *prop;
diff --git a/configs/ls1021aqds_ddr4_nor_defconfig b/configs/ls1021aqds_ddr4_nor_defconfig
new file mode 100644
index 0000000..3c57481
--- /dev/null
+++ b/configs/ls1021aqds_ddr4_nor_defconfig
@@ -0,0 +1,3 @@
+CONFIG_SYS_EXTRA_OPTIONS="SYS_FSL_DDR4"
+CONFIG_ARM=y
+CONFIG_TARGET_LS1021AQDS=y
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index d9cac22..9a156bf 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -297,10 +297,13 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
 	unsigned char taxpd_mclk = 0;
 	/* Mode register set cycle time (tMRD). */
 	unsigned char tmrd_mclk;
+#if defined(CONFIG_SYS_FSL_DDR4) || defined(CONFIG_SYS_FSL_DDR3)
+	const unsigned int mclk_ps = get_memory_clk_period_ps();
+#endif
 
 #ifdef CONFIG_SYS_FSL_DDR4
 	/* tXP=max(4nCK, 6ns) */
-	int txp = max((get_memory_clk_period_ps() * 4), 6000); /* unit=ps */
+	int txp = max(mclk_ps * 4, 6000); /* unit=ps */
 	trwt_mclk = 2;
 	twrt_mclk = 1;
 	act_pd_exit_mclk = picos_to_mclk(txp);
@@ -311,16 +314,19 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
 	 */
 	tmrd_mclk = max(24, picos_to_mclk(15000));
 #elif defined(CONFIG_SYS_FSL_DDR3)
+	unsigned int data_rate = get_ddr_freq(0);
+	int txp;
 	/*
 	 * (tXARD and tXARDS). Empirical?
 	 * The DDR3 spec has not tXARD,
 	 * we use the tXP instead of it.
-	 * tXP=max(3nCK, 7.5ns) for DDR3.
+	 * tXP=max(3nCK, 7.5ns) for DDR3-800, 1066
+	 *     max(3nCK, 6ns) for DDR3-1333, 1600, 1866, 2133
 	 * spec has not the tAXPD, we use
 	 * tAXPD=1, need design to confirm.
 	 */
-	int txp = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */
-	unsigned int data_rate = get_ddr_freq(0);
+	txp = max(mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000));
+
 	tmrd_mclk = 4;
 	/* set the turnaround time */
 
@@ -578,6 +584,9 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
 	unsigned char cke_pls;
 	/* Window for four activates (tFAW) */
 	unsigned short four_act;
+#ifdef CONFIG_SYS_FSL_DDR3
+	const unsigned int mclk_ps = get_memory_clk_period_ps();
+#endif
 
 	/* FIXME add check that this must be less than acttorw_mclk */
 	add_lat_mclk = additive_latency;
@@ -619,10 +628,17 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
 #ifdef CONFIG_SYS_FSL_DDR4
 	cpo = 0;
 	cke_pls = max(3, picos_to_mclk(5000));
+#elif defined(CONFIG_SYS_FSL_DDR3)
+	/*
+	 * cke pulse = max(3nCK, 7.5ns) for DDR3-800
+	 *             max(3nCK, 5.625ns) for DDR3-1066, 1333
+	 *             max(3nCK, 5ns) for DDR3-1600, 1866, 2133
+	 */
+	cke_pls = max(3, picos_to_mclk(mclk_ps > 1870 ? 7500 :
+				       (mclk_ps > 1245 ? 5625 : 5000)));
 #else
-	cke_pls = picos_to_mclk(popts->tcke_clock_pulse_width_ps);
+	cke_pls = FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR;
 #endif
-
 	four_act = picos_to_mclk(popts->tfaw_window_four_activates_ps);
 
 	ddr->timing_cfg_2 = (0
@@ -1886,9 +1902,12 @@ static void set_timing_cfg_9(fsl_ddr_cfg_regs_t *ddr)
 	debug("FSLDDR: timing_cfg_9 = 0x%08x\n", ddr->timing_cfg_9);
 }
 
+/* This function needs to be called after set_ddr_sdram_cfg() is called */
 static void set_ddr_dq_mapping(fsl_ddr_cfg_regs_t *ddr,
 			       const dimm_params_t *dimm_params)
 {
+	unsigned int acc_ecc_en = (ddr->ddr_sdram_cfg >> 2) & 0x1;
+
 	ddr->dq_map_0 = ((dimm_params->dq_mapping[0] & 0x3F) << 26) |
 			((dimm_params->dq_mapping[1] & 0x3F) << 20) |
 			((dimm_params->dq_mapping[2] & 0x3F) << 14) |
@@ -1907,9 +1926,11 @@ static void set_ddr_dq_mapping(fsl_ddr_cfg_regs_t *ddr,
 			((dimm_params->dq_mapping[15] & 0x3F) << 8) |
 			((dimm_params->dq_mapping[16] & 0x3F) << 2);
 
+	/* dq_map for ECC[4:7] is set to 0 if accumulated ECC is enabled */
 	ddr->dq_map_3 = ((dimm_params->dq_mapping[17] & 0x3F) << 26) |
 			((dimm_params->dq_mapping[8] & 0x3F) << 20) |
-			((dimm_params->dq_mapping[9] & 0x3F) << 14) |
+			(acc_ecc_en ? 0 :
+			 (dimm_params->dq_mapping[9] & 0x3F) << 14) |
 			dimm_params->dq_mapping_ors;
 
 	debug("FSLDDR: dq_map_0 = 0x%08x\n", ddr->dq_map_0);
@@ -2276,7 +2297,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 	if (ip_rev > 0x40400)
 		unq_mrs_en = 1;
 
-	if (ip_rev > 0x40700)
+	if ((ip_rev > 0x40700) && (popts->cswl_override != 0))
 		ddr->debug[18] = popts->cswl_override;
 
 	set_ddr_sdram_cfg_2(ddr, popts, unq_mrs_en);
diff --git a/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c
index 4745b7f..2418dca 100644
--- a/drivers/ddr/fsl/ddr4_dimm_params.c
+++ b/drivers/ddr/fsl/ddr4_dimm_params.c
@@ -113,7 +113,7 @@ compute_ranksize(const struct ddr4_spd_eeprom_s *spd)
 #define spd_to_ps(mtb, ftb)	\
 	(mtb * pdimm->mtb_ps + (ftb * pdimm->ftb_10th_ps) / 10)
 /*
- * ddr_compute_dimm_parameters for DDR3 SPD
+ * ddr_compute_dimm_parameters for DDR4 SPD
  *
  * Compute DIMM parameters based upon the SPD information in spd.
  * Writes the results to the dimm_params_t structure pointed by pdimm.
@@ -165,17 +165,17 @@ ddr_compute_dimm_parameters(const generic_spd_eeprom_t *spd,
 			  + pdimm->ec_sdram_width;
 	pdimm->device_width = 1 << ((spd->organization & 0x7) + 2);
 
-	/* These are the types defined by the JEDEC DDR3 SPD spec */
+	/* These are the types defined by the JEDEC SPD spec */
 	pdimm->mirrored_dimm = 0;
 	pdimm->registered_dimm = 0;
-	switch (spd->module_type & DDR3_SPD_MODULETYPE_MASK) {
-	case DDR3_SPD_MODULETYPE_RDIMM:
+	switch (spd->module_type & DDR4_SPD_MODULETYPE_MASK) {
+	case DDR4_SPD_MODULETYPE_RDIMM:
 		/* Registered/buffered DIMMs */
 		pdimm->registered_dimm = 1;
 		break;
 
-	case DDR3_SPD_MODULETYPE_UDIMM:
-	case DDR3_SPD_MODULETYPE_SO_DIMM:
+	case DDR4_SPD_MODULETYPE_UDIMM:
+	case DDR4_SPD_MODULETYPE_SO_DIMM:
 		/* Unbuffered DIMMs */
 		if (spd->mod_section.unbuffered.addr_mapping & 0x1)
 			pdimm->mirrored_dimm = 1;
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index bfc76b3..e024db9 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -216,7 +216,7 @@ step2:
 	 * For example, 2GB on 666MT/s 64-bit bus takes about 402ms
 	 * Let's wait for 800ms
 	 */
-	bus_width = 3 - ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK)
+	bus_width = 3 - ((ddr_in32(&ddr->sdram_cfg) & SDRAM_CFG_DBW_MASK)
 			>> SDRAM_CFG_DBW_SHIFT);
 	timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 /
 		(get_ddr_freq(0) >> 20)) << 2;
@@ -233,5 +233,4 @@ step2:
 
 	if (timeout <= 0)
 		printf("Waiting for D_INIT timeout. Memory may not work.\n");
-
 }
diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c
index 6aa16b2..32ba6d8 100644
--- a/drivers/ddr/fsl/interactive.c
+++ b/drivers/ddr/fsl/interactive.c
@@ -517,7 +517,6 @@ static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo,
 		CTRL_OPTIONS(rcw_2),
 		CTRL_OPTIONS(ddr_cdr1),
 		CTRL_OPTIONS(ddr_cdr2),
-		CTRL_OPTIONS(tcke_clock_pulse_width_ps),
 		CTRL_OPTIONS(tfaw_window_four_activates_ps),
 		CTRL_OPTIONS(trwt_override),
 		CTRL_OPTIONS(trwt),
@@ -808,7 +807,6 @@ static void print_memctl_options(const memctl_options_t *popts)
 		CTRL_OPTIONS(rcw_2),
 		CTRL_OPTIONS_HEX(ddr_cdr1),
 		CTRL_OPTIONS_HEX(ddr_cdr2),
-		CTRL_OPTIONS(tcke_clock_pulse_width_ps),
 		CTRL_OPTIONS(tfaw_window_four_activates_ps),
 		CTRL_OPTIONS(trwt_override),
 		CTRL_OPTIONS(trwt),
diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c
index 5e001fc..b43b669 100644
--- a/drivers/ddr/fsl/main.c
+++ b/drivers/ddr/fsl/main.c
@@ -135,7 +135,7 @@ __attribute__((weak, alias("__get_spd")))
 void get_spd(generic_spd_eeprom_t *spd, u8 i2c_address);
 
 void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
-		      unsigned int ctrl_num)
+		      unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl)
 {
 	unsigned int i;
 	unsigned int i2c_address = 0;
@@ -145,14 +145,14 @@ void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
 		return;
 	}
 
-	for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
+	for (i = 0; i < dimm_slots_per_ctrl; i++) {
 		i2c_address = spd_i2c_addr[ctrl_num][i];
 		get_spd(&(ctrl_dimms_spd[i]), i2c_address);
 	}
 }
 #else
 void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
-		      unsigned int ctrl_num)
+		      unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl)
 {
 }
 #endif /* SPD_EEPROM_ADDRESSx */
@@ -231,9 +231,11 @@ const char * step_to_string(unsigned int step) {
 static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
 			  unsigned int dbw_cap_adj[])
 {
-	int i, j;
+	unsigned int i, j;
 	unsigned long long total_mem, current_mem_base, total_ctlr_mem;
 	unsigned long long rank_density, ctlr_density = 0;
+	unsigned int first_ctrl = pinfo->first_ctrl;
+	unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
 
 	/*
 	 * If a reduced data width is requested, but the SPD
@@ -241,7 +243,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
 	 * computed dimm capacities accordingly before
 	 * assigning addresses.
 	 */
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+	for (i = first_ctrl; i <= last_ctrl; i++) {
 		unsigned int found = 0;
 
 		switch (pinfo->memctl_opts[i].data_bus_width) {
@@ -295,12 +297,12 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
 		debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);
 	}
 
-	current_mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+	current_mem_base = pinfo->mem_base;
 	total_mem = 0;
-	if (pinfo->memctl_opts[0].memctl_interleaving) {
-		rank_density = pinfo->dimm_params[0][0].rank_density >>
-					dbw_cap_adj[0];
-		switch (pinfo->memctl_opts[0].ba_intlv_ctl &
+	if (pinfo->memctl_opts[first_ctrl].memctl_interleaving) {
+		rank_density = pinfo->dimm_params[first_ctrl][0].rank_density >>
+					dbw_cap_adj[first_ctrl];
+		switch (pinfo->memctl_opts[first_ctrl].ba_intlv_ctl &
 					FSL_DDR_CS0_CS1_CS2_CS3) {
 		case FSL_DDR_CS0_CS1_CS2_CS3:
 			ctlr_density = 4 * rank_density;
@@ -316,7 +318,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
 		}
 		debug("rank density is 0x%llx, ctlr density is 0x%llx\n",
 			rank_density, ctlr_density);
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			if (pinfo->memctl_opts[i].memctl_interleaving) {
 				switch (pinfo->memctl_opts[i].memctl_interleaving_mode) {
 				case FSL_DDR_256B_INTERLEAVING:
@@ -372,7 +374,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
 		 * Simple linear assignment if memory
 		 * controllers are not interleaved.
 		 */
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			total_ctlr_mem = 0;
 			pinfo->common_timing_params[i].base_address =
 						current_mem_base;
@@ -408,18 +410,23 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 {
 	unsigned int i, j;
 	unsigned long long total_mem = 0;
-	int assert_reset;
+	int assert_reset = 0;
+	unsigned int first_ctrl =  pinfo->first_ctrl;
+	unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
+	__maybe_unused int retval;
+	__maybe_unused bool goodspd = false;
+	__maybe_unused int dimm_slots_per_ctrl = pinfo->dimm_slots_per_ctrl;
 
 	fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
 	common_timing_params_t *timing_params = pinfo->common_timing_params;
-	assert_reset = board_need_mem_reset();
+	if (pinfo->board_need_mem_reset)
+		assert_reset = pinfo->board_need_mem_reset();
 
 	/* data bus width capacity adjust shift amount */
 	unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS];
 
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+	for (i = first_ctrl; i <= last_ctrl; i++)
 		dbw_capacity_adjust[i] = 0;
-	}
 
 	debug("starting at step %u (%s)\n",
 	      start_step, step_to_string(start_step));
@@ -428,28 +435,28 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 	case STEP_GET_SPD:
 #if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM)
 		/* STEP 1:  Gather all DIMM SPD data */
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-			fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i);
+		for (i = first_ctrl; i <= last_ctrl; i++) {
+			fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i,
+					dimm_slots_per_ctrl);
 		}
 
 	case STEP_COMPUTE_DIMM_PARMS:
 		/* STEP 2:  Compute DIMM parameters from SPD data */
 
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
-				unsigned int retval;
 				generic_spd_eeprom_t *spd =
 					&(pinfo->spd_installed_dimms[i][j]);
 				dimm_params_t *pdimm =
 					&(pinfo->dimm_params[i][j]);
-
 				retval = compute_dimm_parameters(spd, pdimm, i);
 #ifdef CONFIG_SYS_DDR_RAW_TIMING
 				if (!i && !j && retval) {
 					printf("SPD error on controller %d! "
 					"Trying fallback to raw timing "
 					"calculation\n", i);
-					fsl_ddr_get_dimm_params(pdimm, i, j);
+					retval = fsl_ddr_get_dimm_params(pdimm,
+									 i, j);
 				}
 #else
 				if (retval == 2) {
@@ -463,13 +470,26 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 					debug("Warning: compute_dimm_parameters"
 					" non-zero return value for memctl=%u "
 					"dimm=%u\n", i, j);
+				} else {
+					goodspd = true;
 				}
 			}
 		}
+		if (!goodspd) {
+			/*
+			 * No valid SPD found
+			 * Throw an error if this is for main memory, i.e.
+			 * first_ctrl == 0. Otherwise, siliently return 0
+			 * as the memory size.
+			 */
+			if (first_ctrl == 0)
+				printf("Error: No valid SPD detected.\n");
 
+			return 0;
+		}
 #elif defined(CONFIG_SYS_DDR_RAW_TIMING)
 	case STEP_COMPUTE_DIMM_PARMS:
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
 				dimm_params_t *pdimm =
 					&(pinfo->dimm_params[i][j]);
@@ -483,7 +503,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 		 * STEP 3: Compute a common set of timing parameters
 		 * suitable for all of the DIMMs on each memory controller
 		 */
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			debug("Computing lowest common DIMM"
 				" parameters for memctl=%u\n", i);
 			compute_lowest_common_dimm_parameters(
@@ -494,7 +514,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 
 	case STEP_GATHER_OPTS:
 		/* STEP 4:  Gather configuration requirements from user */
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			debug("Reloading memory controller "
 				"configuration options for memctl=%u\n", i);
 			/*
@@ -516,9 +536,13 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 			if (timing_params[i].all_dimms_registered)
 				assert_reset = 1;
 		}
-		if (assert_reset) {
-			debug("Asserting mem reset\n");
-			board_assert_mem_reset();
+		if (assert_reset && !size_only) {
+			if (pinfo->board_mem_reset) {
+				debug("Asserting mem reset\n");
+				pinfo->board_mem_reset();
+			} else {
+				debug("Asserting mem reset missing\n");
+			}
 		}
 
 	case STEP_ASSIGN_ADDRESSES:
@@ -530,7 +554,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 	case STEP_COMPUTE_REGS:
 		/* STEP 6:  compute controller register values */
 		debug("FSL Memory ctrl register computation\n");
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			if (timing_params[i].ndimms_present == 0) {
 				memset(&ddr_reg[i], 0,
 					sizeof(fsl_ddr_cfg_regs_t));
@@ -558,7 +582,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 		 */
 		unsigned int max_end = 0;
 
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) {
 				fsl_ddr_cfg_regs_t *reg = &ddr_reg[i];
 				if (reg->cs[j].config & 0x80000000) {
@@ -578,53 +602,45 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 		}
 
 		total_mem = 1 + (((unsigned long long)max_end << 24ULL) |
-			    0xFFFFFFULL) - CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+			    0xFFFFFFULL) - pinfo->mem_base;
 	}
 
 	return total_mem;
 }
 
-/*
- * fsl_ddr_sdram() -- this is the main function to be called by
- *	initdram() in the board file.
- *
- * It returns amount of memory configured in bytes.
- */
-phys_size_t fsl_ddr_sdram(void)
+phys_size_t __fsl_ddr_sdram(fsl_ddr_info_t *pinfo)
 {
-	unsigned int i;
+	unsigned int i, first_ctrl, last_ctrl;
 #ifdef CONFIG_PPC
 	unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
 #endif
 	unsigned long long total_memory;
-	fsl_ddr_info_t info;
-	int deassert_reset;
+	int deassert_reset = 0;
 
-	/* Reset info structure. */
-	memset(&info, 0, sizeof(fsl_ddr_info_t));
+	first_ctrl = pinfo->first_ctrl;
+	last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
 
 	/* Compute it once normally. */
 #ifdef CONFIG_FSL_DDR_INTERACTIVE
 	if (tstc() && (getc() == 'd')) {	/* we got a key press of 'd' */
-		total_memory = fsl_ddr_interactive(&info, 0);
+		total_memory = fsl_ddr_interactive(pinfo, 0);
 	} else if (fsl_ddr_interactive_env_var_exists()) {
-		total_memory = fsl_ddr_interactive(&info, 1);
+		total_memory = fsl_ddr_interactive(pinfo, 1);
 	} else
 #endif
-		total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
+		total_memory = fsl_ddr_compute(pinfo, STEP_GET_SPD, 0);
 
 	/* setup 3-way interleaving before enabling DDRC */
-	if (info.memctl_opts[0].memctl_interleaving) {
-		switch (info.memctl_opts[0].memctl_interleaving_mode) {
-		case FSL_DDR_3WAY_1KB_INTERLEAVING:
-		case FSL_DDR_3WAY_4KB_INTERLEAVING:
-		case FSL_DDR_3WAY_8KB_INTERLEAVING:
-			fsl_ddr_set_intl3r(
-				info.memctl_opts[0].memctl_interleaving_mode);
-			break;
-		default:
-			break;
-		}
+	switch (pinfo->memctl_opts[first_ctrl].memctl_interleaving_mode) {
+	case FSL_DDR_3WAY_1KB_INTERLEAVING:
+	case FSL_DDR_3WAY_4KB_INTERLEAVING:
+	case FSL_DDR_3WAY_8KB_INTERLEAVING:
+		fsl_ddr_set_intl3r(
+			pinfo->memctl_opts[first_ctrl].
+			memctl_interleaving_mode);
+		break;
+	default:
+		break;
 	}
 
 	/*
@@ -637,14 +653,15 @@ phys_size_t fsl_ddr_sdram(void)
 	 * For non-registered DIMMs, initialization can go through but it is
 	 * also OK to follow the same flow.
 	 */
-	deassert_reset = board_need_mem_reset();
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-		if (info.common_timing_params[i].all_dimms_registered)
+	if (pinfo->board_need_mem_reset)
+		deassert_reset = pinfo->board_need_mem_reset();
+	for (i = first_ctrl; i <= last_ctrl; i++) {
+		if (pinfo->common_timing_params[i].all_dimms_registered)
 			deassert_reset = 1;
 	}
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+	for (i = first_ctrl; i <= last_ctrl; i++) {
 		debug("Programming controller %u\n", i);
-		if (info.common_timing_params[i].ndimms_present == 0) {
+		if (pinfo->common_timing_params[i].ndimms_present == 0) {
 			debug("No dimms present on controller %u; "
 					"skipping programming\n", i);
 			continue;
@@ -653,45 +670,58 @@ phys_size_t fsl_ddr_sdram(void)
 		 * The following call with step = 1 returns before enabling
 		 * the controller. It has to finish with step = 2 later.
 		 */
-		fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i,
+		fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]), i,
 					deassert_reset ? 1 : 0);
 	}
 	if (deassert_reset) {
 		/* Use board FPGA or GPIO to deassert reset signal */
-		debug("Deasserting mem reset\n");
-		board_deassert_mem_reset();
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		if (pinfo->board_mem_de_reset) {
+			debug("Deasserting mem reset\n");
+			pinfo->board_mem_de_reset();
+		} else {
+			debug("Deasserting mem reset missing\n");
+		}
+		for (i = first_ctrl; i <= last_ctrl; i++) {
 			/* Call with step = 2 to continue initialization */
-			fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]),
+			fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]),
 						i, 2);
 		}
 	}
 
 #ifdef CONFIG_PPC
 	/* program LAWs */
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-		if (info.memctl_opts[i].memctl_interleaving) {
-			switch (info.memctl_opts[i].memctl_interleaving_mode) {
+	for (i = first_ctrl; i <= last_ctrl; i++) {
+		if (pinfo->memctl_opts[i].memctl_interleaving) {
+			switch (pinfo->memctl_opts[i].
+				memctl_interleaving_mode) {
 			case FSL_DDR_CACHE_LINE_INTERLEAVING:
 			case FSL_DDR_PAGE_INTERLEAVING:
 			case FSL_DDR_BANK_INTERLEAVING:
 			case FSL_DDR_SUPERBANK_INTERLEAVING:
+				if (i % 2)
+					break;
 				if (i == 0) {
 					law_memctl = LAW_TRGT_IF_DDR_INTRLV;
-					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+					fsl_ddr_set_lawbar(
+						&pinfo->common_timing_params[i],
 						law_memctl, i);
-				} else if (i == 2) {
+				}
+#if CONFIG_NUM_DDR_CONTROLLERS > 3
+				else if (i == 2) {
 					law_memctl = LAW_TRGT_IF_DDR_INTLV_34;
-					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+					fsl_ddr_set_lawbar(
+						&pinfo->common_timing_params[i],
 						law_memctl, i);
 				}
+#endif
 				break;
 			case FSL_DDR_3WAY_1KB_INTERLEAVING:
 			case FSL_DDR_3WAY_4KB_INTERLEAVING:
 			case FSL_DDR_3WAY_8KB_INTERLEAVING:
 				law_memctl = LAW_TRGT_IF_DDR_INTLV_123;
 				if (i == 0) {
-					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+					fsl_ddr_set_lawbar(
+						&pinfo->common_timing_params[i],
 						law_memctl, i);
 				}
 				break;
@@ -700,7 +730,8 @@ phys_size_t fsl_ddr_sdram(void)
 			case FSL_DDR_4WAY_8KB_INTERLEAVING:
 				law_memctl = LAW_TRGT_IF_DDR_INTLV_1234;
 				if (i == 0)
-					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+					fsl_ddr_set_lawbar(
+						&pinfo->common_timing_params[i],
 						law_memctl, i);
 				/* place holder for future 4-way interleaving */
 				break;
@@ -724,8 +755,8 @@ phys_size_t fsl_ddr_sdram(void)
 			default:
 				break;
 			}
-			fsl_ddr_set_lawbar(&info.common_timing_params[i],
-					law_memctl, i);
+			fsl_ddr_set_lawbar(&pinfo->common_timing_params[i],
+					   law_memctl, i);
 		}
 	}
 #endif
@@ -734,7 +765,7 @@ phys_size_t fsl_ddr_sdram(void)
 
 #if !defined(CONFIG_PHYS_64BIT)
 	/* Check for 4G or more.  Bad. */
-	if (total_memory >= (1ull << 32)) {
+	if ((first_ctrl == 0) && (total_memory >= (1ull << 32))) {
 		puts("Detected ");
 		print_size(total_memory, " of memory\n");
 		printf("       This U-Boot only supports < 4G of DDR\n");
@@ -748,8 +779,56 @@ phys_size_t fsl_ddr_sdram(void)
 }
 
 /*
- * fsl_ddr_sdram_size() - This function only returns the size of the total
- * memory without setting ddr control registers.
+ * fsl_ddr_sdram(void) -- this is the main function to be
+ * called by initdram() in the board file.
+ *
+ * It returns amount of memory configured in bytes.
+ */
+phys_size_t fsl_ddr_sdram(void)
+{
+	fsl_ddr_info_t info;
+
+	/* Reset info structure. */
+	memset(&info, 0, sizeof(fsl_ddr_info_t));
+	info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+	info.first_ctrl = 0;
+	info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
+	info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
+	info.board_need_mem_reset = board_need_mem_reset;
+	info.board_mem_reset = board_assert_mem_reset;
+	info.board_mem_de_reset = board_deassert_mem_reset;
+
+	return __fsl_ddr_sdram(&info);
+}
+
+#ifdef CONFIG_SYS_FSL_OTHER_DDR_NUM_CTRLS
+phys_size_t fsl_other_ddr_sdram(unsigned long long base,
+				unsigned int first_ctrl,
+				unsigned int num_ctrls,
+				unsigned int dimm_slots_per_ctrl,
+				int (*board_need_reset)(void),
+				void (*board_reset)(void),
+				void (*board_de_reset)(void))
+{
+	fsl_ddr_info_t info;
+
+	/* Reset info structure. */
+	memset(&info, 0, sizeof(fsl_ddr_info_t));
+	info.mem_base = base;
+	info.first_ctrl = first_ctrl;
+	info.num_ctrls = num_ctrls;
+	info.dimm_slots_per_ctrl = dimm_slots_per_ctrl;
+	info.board_need_mem_reset = board_need_reset;
+	info.board_mem_reset = board_reset;
+	info.board_mem_de_reset = board_de_reset;
+
+	return __fsl_ddr_sdram(&info);
+}
+#endif
+
+/*
+ * fsl_ddr_sdram_size(first_ctrl, last_intlv) - This function only returns the
+ * size of the total memory without setting ddr control registers.
  */
 phys_size_t
 fsl_ddr_sdram_size(void)
@@ -758,6 +837,11 @@ fsl_ddr_sdram_size(void)
 	unsigned long long total_memory = 0;
 
 	memset(&info, 0 , sizeof(fsl_ddr_info_t));
+	info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+	info.first_ctrl = 0;
+	info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
+	info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
+	info.board_need_mem_reset = NULL;
 
 	/* Compute it once normally. */
 	total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1);
diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c
index 5986e1a..6d098d1 100644
--- a/drivers/ddr/fsl/options.c
+++ b/drivers/ddr/fsl/options.c
@@ -777,10 +777,6 @@ unsigned int populate_memctl_options(int all_dimms_registered,
 	 */
 	popts->bstopre = 0x100;
 
-	/* Minimum CKE pulse width -- tCKE(MIN) */
-	popts->tcke_clock_pulse_width_ps
-		= mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR);
-
 	/*
 	 * Window for four activates -- tFAW
 	 *
@@ -1065,18 +1061,21 @@ void check_interleaving_options(fsl_ddr_info_t *pinfo)
 	unsigned int check_intlv, check_n_row_addr, check_n_col_addr;
 	unsigned long long check_rank_density;
 	struct dimm_params_s *dimm;
+	int first_ctrl = pinfo->first_ctrl;
+	int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
+
 	/*
 	 * Check if all controllers are configured for memory
 	 * controller interleaving. Identical dimms are recommended. At least
 	 * the size, row and col address should be checked.
 	 */
 	j = 0;
-	check_n_ranks = pinfo->dimm_params[0][0].n_ranks;
-	check_rank_density = pinfo->dimm_params[0][0].rank_density;
-	check_n_row_addr =  pinfo->dimm_params[0][0].n_row_addr;
-	check_n_col_addr = pinfo->dimm_params[0][0].n_col_addr;
-	check_intlv = pinfo->memctl_opts[0].memctl_interleaving_mode;
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+	check_n_ranks = pinfo->dimm_params[first_ctrl][0].n_ranks;
+	check_rank_density = pinfo->dimm_params[first_ctrl][0].rank_density;
+	check_n_row_addr =  pinfo->dimm_params[first_ctrl][0].n_row_addr;
+	check_n_col_addr = pinfo->dimm_params[first_ctrl][0].n_col_addr;
+	check_intlv = pinfo->memctl_opts[first_ctrl].memctl_interleaving_mode;
+	for (i = first_ctrl; i <= last_ctrl; i++) {
 		dimm = &pinfo->dimm_params[i][0];
 		if (!pinfo->memctl_opts[i].memctl_interleaving) {
 			continue;
@@ -1094,7 +1093,7 @@ void check_interleaving_options(fsl_ddr_info_t *pinfo)
 
 	}
 	if (intlv_invalid) {
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+		for (i = first_ctrl; i <= last_ctrl; i++)
 			pinfo->memctl_opts[i].memctl_interleaving = 0;
 		printf("Not all DIMMs are identical. "
 			"Memory controller interleaving disabled.\n");
@@ -1123,10 +1122,10 @@ void check_interleaving_options(fsl_ddr_info_t *pinfo)
 		}
 		debug("%d of %d controllers are interleaving.\n", j, k);
 		if (j && (j != k)) {
-			for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+			for (i = first_ctrl; i <= last_ctrl; i++)
 				pinfo->memctl_opts[i].memctl_interleaving = 0;
-			printf("Not all controllers have compatible "
-				"interleaving mode. All disabled.\n");
+			if ((last_ctrl - first_ctrl) > 1)
+				puts("Not all controllers have compatible interleaving mode. All disabled.\n");
 		}
 	}
 	debug("Checking interleaving options completed\n");
diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c
index 7a22aa3..58b519b 100644
--- a/drivers/ddr/fsl/util.c
+++ b/drivers/ddr/fsl/util.c
@@ -149,7 +149,7 @@ u32 fsl_ddr_get_intl3r(void)
 	return val;
 }
 
-void board_add_ram_info(int use_default)
+void print_ddr_info(unsigned int start_ctrl)
 {
 	struct ccsr_ddr __iomem *ddr =
 		(struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR);
@@ -164,17 +164,25 @@ void board_add_ram_info(int use_default)
 	int cas_lat;
 
 #if CONFIG_NUM_DDR_CONTROLLERS >= 2
-	if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+	if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) ||
+	    (start_ctrl == 1)) {
 		ddr = (void __iomem *)CONFIG_SYS_FSL_DDR2_ADDR;
 		sdram_cfg = ddr_in32(&ddr->sdram_cfg);
 	}
 #endif
 #if CONFIG_NUM_DDR_CONTROLLERS >= 3
-	if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+	if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) ||
+	    (start_ctrl == 2)) {
 		ddr = (void __iomem *)CONFIG_SYS_FSL_DDR3_ADDR;
 		sdram_cfg = ddr_in32(&ddr->sdram_cfg);
 	}
 #endif
+
+	if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+		puts(" (DDR not enabled)\n");
+		return;
+	}
+
 	puts(" (DDR");
 	switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
 		SDRAM_CFG_SDRAM_TYPE_SHIFT) {
@@ -241,7 +249,7 @@ void board_add_ram_info(int use_default)
 #endif
 #endif
 #if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
-	if (cs0_config & 0x20000000) {
+	if ((cs0_config & 0x20000000) && (start_ctrl == 0)) {
 		puts("\n");
 		puts("       DDR Controller Interleaving Mode: ");
 
@@ -290,3 +298,13 @@ void board_add_ram_info(int use_default)
 		}
 	}
 }
+
+void __weak detail_board_ddr_info(void)
+{
+	print_ddr_info(0);
+}
+
+void board_add_ram_info(int use_default)
+{
+	detail_board_ddr_info();
+}
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 7e1e6ec..3372b64 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -37,7 +37,6 @@
 
 #define MAX_BANKS 8
 #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
-#define FCM_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for FCM */
 
 #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
 
@@ -199,7 +198,8 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
 	struct fsl_elbc_mtd *priv = chip->priv;
 	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
 	fsl_lbc_t *lbc = ctrl->regs;
-	long long end_tick;
+	u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
+	u32 time_start;
 	u32 ltesr;
 
 	/* Setup the FMR[OP] to execute without write protection */
@@ -218,10 +218,10 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
 	out_be32(&lbc->lsor, priv->bank);
 
 	/* wait for FCM complete flag or timeout */
-	end_tick = usec2ticks(FCM_TIMEOUT_MSECS * 1000) + get_ticks();
+	time_start = get_timer(0);
 
 	ltesr = 0;
-	while (end_tick > get_ticks()) {
+	while (get_timer(time_start) < timeo) {
 		ltesr = in_be32(&lbc->ltesr);
 		if (ltesr & LTESR_CC)
 			break;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 2f04c69..81b5070 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -26,8 +26,6 @@
 #define MAX_BANKS	CONFIG_SYS_FSL_IFC_BANK_COUNT
 #define ERR_BYTE	0xFF /* Value returned for read bytes
 				when read failed */
-#define IFC_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for IFC
-				NAND Machine */
 
 struct fsl_ifc_ctrl;
 
@@ -292,7 +290,8 @@ static int fsl_ifc_run_command(struct mtd_info *mtd)
 	struct fsl_ifc_mtd *priv = chip->priv;
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
 	struct fsl_ifc *ifc = ctrl->regs;
-	long long end_tick;
+	u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
+	u32 time_start;
 	u32 eccstat[4];
 	int i;
 
@@ -304,9 +303,9 @@ static int fsl_ifc_run_command(struct mtd_info *mtd)
 		  IFC_NAND_SEQ_STRT_FIR_STRT);
 
 	/* wait for NAND Machine complete flag or timeout */
-	end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
+	time_start = get_timer(0);
 
-	while (end_tick > get_ticks()) {
+	while (get_timer(time_start) < timeo) {
 		ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
 
 		if (ctrl->status & IFC_NAND_EVTER_STAT_OPC)
@@ -812,15 +811,16 @@ static int fsl_ifc_sram_init(uint32_t ver)
 	struct fsl_ifc *ifc = ifc_ctrl->regs;
 	uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0;
 	uint32_t ncfgr = 0;
-	long long end_tick;
+	u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
+	u32 time_start;
 
 	if (ver > FSL_IFC_V1_1_0) {
 		ncfgr = ifc_in32(&ifc->ifc_nand.ncfgr);
 		ifc_out32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN);
 
 		/* wait for  SRAM_INIT bit to be clear or timeout */
-		end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
-		while (end_tick > get_ticks()) {
+		time_start = get_timer(0);
+		while (get_timer(time_start) < timeo) {
 			ifc_ctrl->status =
 				ifc_in32(&ifc->ifc_nand.nand_evter_stat);
 
@@ -863,10 +863,9 @@ static int fsl_ifc_sram_init(uint32_t ver)
 	/* start read seq */
 	ifc_out32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
 
-	/* wait for NAND Machine complete flag or timeout */
-	end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
+	time_start = get_timer(0);
 
-	while (end_tick > get_ticks()) {
+	while (get_timer(time_start) < timeo) {
 		ifc_ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
 
 		if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC)
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index 657e3b6..bb47813 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -49,10 +49,12 @@ unsigned long get_board_ddr_clk(void);
 #define CONFIG_DDR_SPD
 #define SPD_EEPROM_ADDRESS		0x51
 #define CONFIG_SYS_SPD_BUS_NUM		0
-#define CONFIG_SYS_DDR_RAW_TIMING
 
 #define CONFIG_FSL_DDR_INTERACTIVE	/* Interactive debugging */
+#ifndef CONFIG_SYS_FSL_DDR4
 #define CONFIG_SYS_FSL_DDR3		/* Use DDR3 memory */
+#define CONFIG_SYS_DDR_RAW_TIMING
+#endif
 #define CONFIG_DIMM_SLOTS_PER_CTLR	1
 #define CONFIG_CHIP_SELECTS_PER_CTRL	4
 
diff --git a/include/configs/ls2085a_common.h b/include/configs/ls2085a_common.h
index 2bd5a47..a72e1f3 100644
--- a/include/configs/ls2085a_common.h
+++ b/include/configs/ls2085a_common.h
@@ -15,9 +15,11 @@
 #define CONFIG_GICV3
 
 /* Link Definitions */
-#define CONFIG_SYS_TEXT_BASE		0x30000000
+#define CONFIG_SYS_TEXT_BASE		0x30001000
 
+#ifdef CONFIG_EMU
 #define CONFIG_SYS_NO_FLASH
+#endif
 
 #define CONFIG_SUPPORT_RAW_INITRD
 
@@ -45,13 +47,27 @@
 
 #define CONFIG_SYS_FSL_DDR_INTLV_256B	/* force 256 byte interleaving */
 
-/* SMP Definitions */
-#define CPU_RELEASE_ADDR		CONFIG_SYS_INIT_SP_ADDR
-
 #define CONFIG_SYS_DDR_SDRAM_BASE	0x80000000UL
 #define CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY	0
 #define CONFIG_SYS_SDRAM_BASE		CONFIG_SYS_DDR_SDRAM_BASE
 #define CONFIG_SYS_DDR_BLOCK2_BASE	0x8080000000ULL
+#define CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS	2
+
+/*
+ * SMP Definitinos
+ */
+#define CPU_RELEASE_ADDR		secondary_boot_func
+
+#define CONFIG_SYS_FSL_OTHER_DDR_NUM_CTRLS
+#define CONFIG_SYS_DP_DDR_BASE		0x6000000000ULL
+/*
+ * DDR controller use 0 as the base address for binding.
+ * It is mapped to CONFIG_SYS_DP_DDR_BASE for core to access.
+ */
+#define CONFIG_SYS_DP_DDR_BASE_PHY	0
+#define CONFIG_DP_DDR_CTRL		2
+#define CONFIG_DP_DDR_NUM_CTRLS		1
+#define CONFIG_DP_DDR_DIMM_SLOTS_PER_CTLR	1
 
 /* Generic Timer Definitions */
 #define COUNTER_FREQUENCY		12000000	/* 12MHz */
@@ -118,6 +134,66 @@
 #define CONFIG_SYS_NOR_FTIM3	0x04000000
 #define CONFIG_SYS_IFC_CCR	0x01000000
 
+#ifndef CONFIG_SYS_NO_FLASH
+#define CONFIG_FLASH_CFI_DRIVER
+#define CONFIG_SYS_FLASH_CFI
+#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+#define CONFIG_SYS_FLASH_QUIET_TEST
+#define CONFIG_FLASH_SHOW_PROGRESS	45 /* count down from 45/5: 9..1 */
+
+#define CONFIG_SYS_MAX_FLASH_BANKS	1	/* number of banks */
+#define CONFIG_SYS_MAX_FLASH_SECT	1024	/* sectors per device */
+#define CONFIG_SYS_FLASH_ERASE_TOUT	60000	/* Flash Erase Timeout (ms) */
+#define CONFIG_SYS_FLASH_WRITE_TOUT	500	/* Flash Write Timeout (ms) */
+
+#define CONFIG_SYS_FLASH_EMPTY_INFO
+#define CONFIG_SYS_FLASH_BANKS_LIST	{ CONFIG_SYS_FLASH_BASE }
+#endif
+
+#define CONFIG_NAND_FSL_IFC
+#define CONFIG_SYS_NAND_MAX_ECCPOS	256
+#define CONFIG_SYS_NAND_MAX_OOBFREE	2
+#define CONFIG_SYS_NAND_BASE		0x520000000
+#define CONFIG_SYS_NAND_BASE_PHYS	0x20000000
+
+#define CONFIG_SYS_NAND_CSPR_EXT	(0x0)
+#define CONFIG_SYS_NAND_CSPR	(CSPR_PHYS_ADDR(CONFIG_SYS_NAND_BASE_PHYS) \
+				| CSPR_PORT_SIZE_8 /* Port Size = 8 bit */ \
+				| CSPR_MSEL_NAND	/* MSEL = NAND */ \
+				| CSPR_V)
+#define CONFIG_SYS_NAND_AMASK	IFC_AMASK(64 * 1024)
+
+#define CONFIG_SYS_NAND_CSOR    (CSOR_NAND_ECC_ENC_EN   /* ECC on encode */ \
+				| CSOR_NAND_ECC_DEC_EN  /* ECC on decode */ \
+				| CSOR_NAND_ECC_MODE_4  /* 4-bit ECC */ \
+				| CSOR_NAND_RAL_3	/* RAL = 2Byes */ \
+				| CSOR_NAND_PGS_2K	/* Page Size = 2K */ \
+				| CSOR_NAND_SPRZ_64/* Spare size = 64 */ \
+				| CSOR_NAND_PB(64))	/*Pages Per Block = 64*/
+
+#define CONFIG_SYS_NAND_ONFI_DETECTION
+
+/* ONFI NAND Flash mode0 Timing Params */
+#define CONFIG_SYS_NAND_FTIM0		(FTIM0_NAND_TCCST(0x07) | \
+					FTIM0_NAND_TWP(0x18)   | \
+					FTIM0_NAND_TWCHT(0x07) | \
+					FTIM0_NAND_TWH(0x0a))
+#define CONFIG_SYS_NAND_FTIM1		(FTIM1_NAND_TADLE(0x32) | \
+					FTIM1_NAND_TWBE(0x39)  | \
+					FTIM1_NAND_TRR(0x0e)   | \
+					FTIM1_NAND_TRP(0x18))
+#define CONFIG_SYS_NAND_FTIM2		(FTIM2_NAND_TRAD(0x0f) | \
+					FTIM2_NAND_TREH(0x0a) | \
+					FTIM2_NAND_TWHRE(0x1e))
+#define CONFIG_SYS_NAND_FTIM3		0x0
+
+#define CONFIG_SYS_NAND_BASE_LIST	{ CONFIG_SYS_NAND_BASE }
+#define CONFIG_SYS_MAX_NAND_DEVICE	1
+#define CONFIG_MTD_NAND_VERIFY_WRITE
+#define CONFIG_CMD_NAND
+
+#define CONFIG_SYS_NAND_BLOCK_SIZE	(128 * 1024)
+
 #define CONFIG_SYS_CSPR0_EXT		CONFIG_SYS_NOR0_CSPR_EXT
 #define CONFIG_SYS_CSPR0		CONFIG_SYS_NOR0_CSPR_EARLY
 #define CONFIG_SYS_CSPR0_FINAL		CONFIG_SYS_NOR0_CSPR
@@ -167,6 +243,7 @@
 
 /* Miscellaneous configurable options */
 #define CONFIG_SYS_LOAD_ADDR	(CONFIG_SYS_DDR_SDRAM_BASE + 0x10000000)
+#define CONFIG_ARCH_EARLY_INIT_R
 
 /* Physical Memory Map */
 /* fixme: these need to be checked against the board */
@@ -174,7 +251,7 @@
 #define CONFIG_SYS_CLK_FREQ	133333333
 
 
-#define CONFIG_NR_DRAM_BANKS		2
+#define CONFIG_NR_DRAM_BANKS		3
 
 #define CONFIG_SYS_HZ			1000
 
diff --git a/include/configs/ls2085a_emu.h b/include/configs/ls2085a_emu.h
index a5cea63..487cd99 100644
--- a/include/configs/ls2085a_emu.h
+++ b/include/configs/ls2085a_emu.h
@@ -13,6 +13,7 @@
 #define CONFIG_SYS_FSL_DDR_EMU		/* Support emulator */
 #define SPD_EEPROM_ADDRESS1	0x51
 #define SPD_EEPROM_ADDRESS2	0x52
+#define SPD_EEPROM_ADDRESS3	0x53
 #define SPD_EEPROM_ADDRESS	SPD_EEPROM_ADDRESS1
 #define CONFIG_SYS_SPD_BUS_NUM	1	/* SPD on I2C bus 1 */
 
diff --git a/include/configs/ls2085a_simu.h b/include/configs/ls2085a_simu.h
index 46d47b0..0f40b78 100644
--- a/include/configs/ls2085a_simu.h
+++ b/include/configs/ls2085a_simu.h
@@ -13,4 +13,13 @@
 #define CONFIG_SMC91111
 #define CONFIG_SMC91111_BASE	(0x2210000)
 
+#define CONFIG_SYS_CSPR1_EXT		CONFIG_SYS_NAND_CSPR_EXT
+#define CONFIG_SYS_CSPR1		CONFIG_SYS_NAND_CSPR
+#define CONFIG_SYS_AMASK1		CONFIG_SYS_NAND_AMASK
+#define CONFIG_SYS_CSOR1		CONFIG_SYS_NAND_CSOR
+#define CONFIG_SYS_CS1_FTIM0		CONFIG_SYS_NAND_FTIM0
+#define CONFIG_SYS_CS1_FTIM1		CONFIG_SYS_NAND_FTIM1
+#define CONFIG_SYS_CS1_FTIM2		CONFIG_SYS_NAND_FTIM2
+#define CONFIG_SYS_CS1_FTIM3		CONFIG_SYS_NAND_FTIM3
+
 #endif /* __LS2_SIMU_H */
diff --git a/include/fdt_support.h b/include/fdt_support.h
index 1bda686..c3d1fbc 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -133,6 +133,18 @@ static inline int fdt_status_fail_by_alias(void *fdt, const char *alias)
 	return fdt_set_status_by_alias(fdt, alias, FDT_STATUS_FAIL, 0);
 }
 
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline u64 of_read_number(const fdt32_t *cell, int size)
+{
+	u64 r = 0;
+	while (size--)
+		r = (r << 32) | fdt32_to_cpu(*(cell++));
+	return r;
+}
+
+void of_bus_default_count_cells(void *blob, int parentoffset,
+					int *addrc, int *sizec);
+
 #endif /* ifdef CONFIG_OF_LIBFDT */
 
 #ifdef USE_HOSTCC
diff --git a/include/fsl_ddr.h b/include/fsl_ddr.h
index 5c49b22..675557a 100644
--- a/include/fsl_ddr.h
+++ b/include/fsl_ddr.h
@@ -15,6 +15,11 @@
 
 #include <common_timing_params.h>
 
+#ifndef CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS
+/* All controllers are for main memory */
+#define CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS	CONFIG_NUM_DDR_CONTROLLERS
+#endif
+
 #ifdef CONFIG_SYS_FSL_DDR_LE
 #define ddr_in32(a)	in_le32(a)
 #define ddr_out32(a, v)	out_le32(a, v)
@@ -57,6 +62,13 @@ typedef struct {
 	memctl_options_t memctl_opts[CONFIG_SYS_NUM_DDR_CTLRS];
 	common_timing_params_t common_timing_params[CONFIG_SYS_NUM_DDR_CTLRS];
 	fsl_ddr_cfg_regs_t fsl_ddr_config_reg[CONFIG_SYS_NUM_DDR_CTLRS];
+	unsigned int first_ctrl;
+	unsigned int num_ctrls;
+	unsigned long long mem_base;
+	unsigned int dimm_slots_per_ctrl;
+	int (*board_need_mem_reset)(void);
+	void (*board_mem_reset)(void);
+	void (*board_mem_de_reset)(void);
 } fsl_ddr_info_t;
 
 /* Compute steps */
@@ -72,7 +84,6 @@ typedef struct {
 unsigned long long
 fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 				       unsigned int size_only);
-
 const char *step_to_string(unsigned int step);
 
 unsigned int compute_fsl_memctl_config_regs(const memctl_options_t *popts,
@@ -102,7 +113,7 @@ void fsl_ddr_set_lawbar(
 int fsl_ddr_interactive_env_var_exists(void);
 unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo, int var_is_set);
 void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
-			   unsigned int ctrl_num);
+		     unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl);
 
 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 unsigned int check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr);
diff --git a/include/fsl_ddr_sdram.h b/include/fsl_ddr_sdram.h
index 987119b..5b03c14 100644
--- a/include/fsl_ddr_sdram.h
+++ b/include/fsl_ddr_sdram.h
@@ -51,7 +51,6 @@ typedef ddr2_spd_eeprom_t generic_spd_eeprom_t;
 #define CONFIG_FSL_SDRAM_TYPE	SDRAM_TYPE_DDR2
 #endif
 #elif defined(CONFIG_SYS_FSL_DDR3)
-#define FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR	(3)	/* FIXME */
 typedef ddr3_spd_eeprom_t generic_spd_eeprom_t;
 #ifndef CONFIG_FSL_SDRAM_TYPE
 #define CONFIG_FSL_SDRAM_TYPE	SDRAM_TYPE_DDR3
@@ -352,7 +351,6 @@ typedef struct memctl_options_s {
 	unsigned int twot_en;
 	unsigned int threet_en;
 	unsigned int bstopre;
-	unsigned int tcke_clock_pulse_width_ps;	/* tCKE */
 	unsigned int tfaw_window_four_activates_ps;	/* tFAW --  FOUR_ACT */
 
 	/* Rtt impedance */
@@ -379,12 +377,20 @@ typedef struct memctl_options_s {
 	unsigned int trwt;			/* read-to-write turnaround */
 } memctl_options_t;
 
-extern phys_size_t fsl_ddr_sdram(void);
-extern phys_size_t fsl_ddr_sdram_size(void);
+phys_size_t fsl_ddr_sdram(void);
+phys_size_t fsl_ddr_sdram_size(void);
+phys_size_t fsl_other_ddr_sdram(unsigned long long base,
+				unsigned int first_ctrl,
+				unsigned int num_ctrls,
+				unsigned int dimm_slots_per_ctrl,
+				int (*board_need_reset)(void),
+				void (*board_reset)(void),
+				void (*board_de_reset)(void));
 extern int fsl_use_spd(void);
-extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
-					unsigned int ctrl_num, int step);
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+			     unsigned int ctrl_num, int step);
 u32 fsl_ddr_get_intl3r(void);
+void print_ddr_info(unsigned int start_ctrl);
 
 static void __board_assert_mem_reset(void)
 {