diff --git a/README b/README
index 70dd97d64d8ef1bb253c5dac7525b2b892f6ada2..573666eeedd0da6b2019a3b469ab6fe2d01db8ee 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/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c
index 6274f929dd0fa3d035052187f4f7e9a9f889f78a..3d6ec843df3f156b7961975f6931552c434cb2ad 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/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c
index 4745b7fb1bfff841d037d5a662d1a9e37c4d59f5..2418dca6ab9468c729ecd3bcccf81d1d69f05a31 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/main.c b/drivers/ddr/fsl/main.c
index 5e001fcb99474605d0c5fadde287e1ef257184b5..b43b669e41ffc9be2b1bf812de30fa1eb714d6ff 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 5986e1a0b9da3b5099fcdac4b46594c9b1fc3180..31cc2bfecd2db8401945fd79fa2bf0934b92ba77 100644
--- a/drivers/ddr/fsl/options.c
+++ b/drivers/ddr/fsl/options.c
@@ -1065,18 +1065,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 +1097,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 +1126,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 7a22aa398865655b0cb8f8ca8069b648bfb1c463..58b519b4036aca64690bf9cd2e261b03934898ae 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/include/fsl_ddr.h b/include/fsl_ddr.h
index 5c49b229dafe19b14fe5866187b826385534b549..675557ad1fd3605f07fab75477f8c61f6cd58fae 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 987119b014ee513166fd4ba6cbaf47d405f2ef85..d03901fe7c46346da45d7ee61c6747fda0a19429 100644
--- a/include/fsl_ddr_sdram.h
+++ b/include/fsl_ddr_sdram.h
@@ -379,12 +379,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)
 {