Merge git://git.denx.de/u-boot-usb
diff --git a/Makefile b/Makefile
index b6f83a5..54ef2cd 100644
--- a/Makefile
+++ b/Makefile
@@ -887,7 +887,7 @@
 	-T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE)
 
 MKIMAGEFLAGS_u-boot-spl.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \
-	-T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE)
+	-T kwbimage -a $(CONFIG_SPL_TEXT_BASE) -e $(CONFIG_SPL_TEXT_BASE)
 
 MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \
 		-R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage
@@ -1259,7 +1259,7 @@
 
 spl/u-boot-spl.bin: spl/u-boot-spl
 	@:
-spl/u-boot-spl: tools prepare
+spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)
 	$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
 
 spl/sunxi-spl.bin: spl/u-boot-spl
diff --git a/arch/arm/cpu/u-boot-spl.lds b/arch/arm/cpu/u-boot-spl.lds
index a8be204..c5b4f7c 100644
--- a/arch/arm/cpu/u-boot-spl.lds
+++ b/arch/arm/cpu/u-boot-spl.lds
@@ -32,17 +32,17 @@
 	}
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*_i2c_*)));
-	}
-
-	. = .;
 #ifdef CONFIG_SPL_DM
 	.u_boot_list : {
 		KEEP(*(SORT(.u_boot_list_*_driver_*)));
 		KEEP(*(SORT(.u_boot_list_*_uclass_*)));
 	}
 #endif
+	. = .;
+	.u_boot_list : {
+		KEEP(*(SORT(.u_boot_list*_i2c_*)));
+	}
+
 	. = ALIGN(4);
 
 	__image_copy_end = .;
@@ -66,7 +66,7 @@
 		 . = ALIGN(4);
 		__bss_end = .;
 	}
-
+	__bss_size = __bss_end - __bss_start;
 	.dynsym _image_binary_end : { *(.dynsym) }
 	.dynbss : { *(.dynbss) }
 	.dynstr : { *(.dynstr*) }
diff --git a/arch/arm/dts/uniphier-ph1-sld3.dtsi b/arch/arm/dts/uniphier-ph1-sld3.dtsi
index 2fa42a6..5e29436 100644
--- a/arch/arm/dts/uniphier-ph1-sld3.dtsi
+++ b/arch/arm/dts/uniphier-ph1-sld3.dtsi
@@ -129,6 +129,15 @@
 			status = "disabled";
 		};
 
+		i2c4: i2c@58600000 {
+			compatible = "panasonic,uniphier-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x58600000 0x40>;
+			clock-frequency = <400000>;
+			status = "okay";
+		};
+
 		system-bus-controller-misc@59800000 {
 			compatible = "socionext,uniphier-system-bus-controller-misc",
 				     "syscon";
diff --git a/arch/arm/dts/uniphier-ref-daughter.dtsi b/arch/arm/dts/uniphier-ref-daughter.dtsi
index 84b2206..b8960fd 100644
--- a/arch/arm/dts/uniphier-ref-daughter.dtsi
+++ b/arch/arm/dts/uniphier-ref-daughter.dtsi
@@ -8,7 +8,7 @@
 
 &i2c0 {
 	eeprom {
-		compatible = "i2c-eeprom";
+		compatible = "microchip,24lc128", "i2c-eeprom";
 		reg = <0x50>;
 		u-boot,i2c-offset-len = <2>;
 	};
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 4f477cd..446ce04 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -20,5 +20,7 @@
 obj-$(CONFIG_SPL_BUILD) += spl.o
 obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o
 
-obj-y	+= serdes/
+obj-$(CONFIG_SYS_MVEBU_DDR_A38X) += serdes/a38x/
+obj-$(CONFIG_SYS_MVEBU_DDR_AXP)	+= serdes/axp/
+
 endif
diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c
index 9bc9f00..9496d5f 100644
--- a/arch/arm/mach-mvebu/cpu.c
+++ b/arch/arm/mach-mvebu/cpu.c
@@ -163,6 +163,14 @@
 	}
 }
 
+void mmu_disable(void)
+{
+	asm volatile(
+		"mrc p15, 0, r0, c1, c0, 0\n"
+		"bic r0, #1\n"
+		"mcr p15, 0, r0, c1, c0, 0\n");
+}
+
 #ifdef CONFIG_ARCH_CPU_INIT
 static void set_cbar(u32 addr)
 {
@@ -172,6 +180,16 @@
 
 int arch_cpu_init(void)
 {
+#ifndef CONFIG_SPL_BUILD
+	/*
+	 * Only with disabled MMU its possible to switch the base
+	 * register address on Armada 38x. Without this the SDRAM
+	 * located at >= 0x4000.0000 is also not accessible, as its
+	 * still locked to cache.
+	 */
+	mmu_disable();
+#endif
+
 	/* Linux expects the internal registers to be at 0xf1000000 */
 	writel(SOC_REGS_PHY_BASE, INTREG_BASE_ADDR_REG);
 	set_cbar(SOC_REGS_PHY_BASE + 0xC000);
diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h
index 4bdb633..8bcdef6 100644
--- a/arch/arm/mach-mvebu/include/mach/cpu.h
+++ b/arch/arm/mach-mvebu/include/mach/cpu.h
@@ -125,7 +125,7 @@
 /*
  * DDR3 init / training code ported from Marvell bin_hdr. Now
  * available in mainline U-Boot in:
- * drivers/ddr/mvebu/
+ * drivers/ddr/marvell
  */
 int ddr3_init(void);
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h
index 1aaea67..125b5f2 100644
--- a/arch/arm/mach-mvebu/include/mach/soc.h
+++ b/arch/arm/mach-mvebu/include/mach/soc.h
@@ -28,7 +28,17 @@
 /* SOC specific definations */
 #define INTREG_BASE		0xd0000000
 #define INTREG_BASE_ADDR_REG	(INTREG_BASE + 0x20080)
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYS_MVEBU_DDR_A38X)
+/*
+ * On A38x switching the regs base address without running from
+ * SDRAM doesn't seem to work. So let the SPL still use the
+ * default base address and switch to the new address in the
+ * main u-boot later.
+ */
+#define SOC_REGS_PHY_BASE	0xd0000000
+#else
 #define SOC_REGS_PHY_BASE	0xf1000000
+#endif
 #define MVEBU_REGISTER(x)	(SOC_REGS_PHY_BASE + x)
 
 #define MVEBU_SDRAM_SCRATCH	(MVEBU_REGISTER(0x01504))
@@ -52,6 +62,7 @@
 #define MVEBU_USB20_BASE	(MVEBU_REGISTER(0x58000))
 #define MVEBU_EGIGA0_BASE	(MVEBU_REGISTER(0x70000))
 #define MVEBU_EGIGA1_BASE	(MVEBU_REGISTER(0x74000))
+#define MVEBU_AXP_SATA_BASE	(MVEBU_REGISTER(0xa0000))
 #define MVEBU_SATA0_BASE	(MVEBU_REGISTER(0xa8000))
 #define MVEBU_SDIO_BASE		(MVEBU_REGISTER(0xd8000))
 
diff --git a/arch/arm/mach-mvebu/serdes/a38x/Makefile b/arch/arm/mach-mvebu/serdes/a38x/Makefile
new file mode 100644
index 0000000..1503da8
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/Makefile
@@ -0,0 +1,10 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD)	= ctrl_pex.o
+obj-$(CONFIG_SPL_BUILD)	+= high_speed_env_spec.o
+obj-$(CONFIG_SPL_BUILD)	+= high_speed_env_spec-38x.o
+obj-$(CONFIG_SPL_BUILD)	+= high_speed_topology_spec-38x.o
+obj-$(CONFIG_SPL_BUILD)	+= seq_exec.o
+obj-$(CONFIG_SPL_BUILD)	+= sys_env_lib.o
diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
new file mode 100644
index 0000000..5f223f9
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ctrl_pex.h"
+#include "sys_env_lib.h"
+
+int hws_pex_config(struct serdes_map *serdes_map)
+{
+	u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg,
+	    temp_reg, addr, dev_id, ctrl_mode;
+	enum serdes_type serdes_type;
+	u32 idx, max_lane_num;
+
+	DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
+
+	max_lane_num = hws_serdes_get_max_lane();
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		/* configuration for PEX only */
+		if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
+		    (serdes_type != PEX2) && (serdes_type != PEX3))
+			continue;
+
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		pex_idx = serdes_type - PEX0;
+		tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx));
+		tmp &= ~(0xf << 20);
+		tmp |= (0x4 << 20);
+		reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp);
+	}
+
+	tmp = reg_read(SOC_CTRL_REG);
+	tmp &= ~0x03;
+
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		switch (serdes_type) {
+		case PEX0:
+			tmp |= 0x1 << PCIE0_ENABLE_OFFS;
+			break;
+		case PEX1:
+			tmp |= 0x1 << PCIE1_ENABLE_OFFS;
+			break;
+		case PEX2:
+			tmp |= 0x1 << PCIE2_ENABLE_OFFS;
+			break;
+		case PEX3:
+			tmp |= 0x1 << PCIE3_ENABLE_OFFS;
+			break;
+		default:
+			break;
+		}
+	}
+
+	reg_write(SOC_CTRL_REG, tmp);
+
+	/* Support gen1/gen2 */
+	DEBUG_INIT_FULL_S("Support gen1/gen2\n");
+	next_busno = 0;
+	mdelay(150);
+
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		DEBUG_INIT_FULL_S(" serdes_type=0x");
+		DEBUG_INIT_FULL_D(serdes_type, 8);
+		DEBUG_INIT_FULL_S("\n");
+		DEBUG_INIT_FULL_S(" idx=0x");
+		DEBUG_INIT_FULL_D(idx, 8);
+		DEBUG_INIT_FULL_S("\n");
+
+		/* Configuration for PEX only */
+		if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
+		    (serdes_type != PEX2) && (serdes_type != PEX3))
+			continue;
+
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		pex_idx = serdes_type - PEX0;
+		tmp = reg_read(PEX_DBG_STATUS_REG(pex_idx));
+
+		first_busno = next_busno;
+		if ((tmp & 0x7f) != 0x7e) {
+			DEBUG_INIT_S("PCIe, Idx ");
+			DEBUG_INIT_D(pex_idx, 1);
+			DEBUG_INIT_S(": detected no link\n");
+			continue;
+		}
+
+		next_busno++;
+		temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS
+					 (pex_idx, PEX_LINK_CAPABILITY_REG)));
+		temp_pex_reg &= 0xf;
+		if (temp_pex_reg != 0x2)
+			continue;
+
+		temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS(
+					     pex_idx,
+					     PEX_LINK_CTRL_STAT_REG)) &
+			    0xf0000) >> 16;
+
+		/* Check if the link established is GEN1 */
+		DEBUG_INIT_FULL_S
+			("Checking if the link established is gen1\n");
+		if (temp_reg != 0x1)
+			continue;
+
+		pex_local_bus_num_set(pex_idx, first_busno);
+		pex_local_dev_num_set(pex_idx, 1);
+		DEBUG_INIT_FULL_S("PCIe, Idx ");
+		DEBUG_INIT_FULL_D(pex_idx, 1);
+
+		DEBUG_INIT_S(":** Link is Gen1, check the EP capability\n");
+		/* link is Gen1, check the EP capability */
+		addr = pex_config_read(pex_idx, first_busno, 0, 0, 0x34) & 0xff;
+		DEBUG_INIT_FULL_C("pex_config_read: return addr=0x%x", addr, 4);
+		if (addr == 0xff) {
+			DEBUG_INIT_FULL_C
+				("pex_config_read: return 0xff -->PCIe (%d): Detected No Link.",
+				 pex_idx, 1);
+			continue;
+		}
+
+		while ((pex_config_read(pex_idx, first_busno, 0, 0, addr)
+			& 0xff) != 0x10) {
+			addr = (pex_config_read(pex_idx, first_busno, 0,
+						0, addr) & 0xff00) >> 8;
+		}
+
+		/* Check for Gen2 and above */
+		if ((pex_config_read(pex_idx, first_busno, 0, 0,
+				     addr + 0xc) & 0xf) < 0x2) {
+			DEBUG_INIT_S("PCIe, Idx ");
+			DEBUG_INIT_D(pex_idx, 1);
+			DEBUG_INIT_S(": remains Gen1\n");
+			continue;
+		}
+
+		tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx));
+		DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
+		tmp &= ~(BIT(0) | BIT(1));
+		tmp |= BIT(1);
+		tmp |= BIT(6);	/* Select Deemphasize (-3.5d_b) */
+		reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
+		DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
+
+		tmp = reg_read(PEX_CTRL_REG(pex_idx));
+		DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp);
+		tmp |= BIT(10);
+		reg_write(PEX_CTRL_REG(pex_idx), tmp);
+		DEBUG_WR_REG(PEX_CTRL_REG(pex_idx), tmp);
+
+		/*
+		 * We need to wait 10ms before reading the PEX_DBG_STATUS_REG
+		 * in order not to read the status of the former state
+		 */
+		mdelay(10);
+
+		DEBUG_INIT_S("PCIe, Idx ");
+		DEBUG_INIT_D(pex_idx, 1);
+		DEBUG_INIT_S
+			(": Link upgraded to Gen2 based on client cpabilities\n");
+	}
+
+	/* Update pex DEVICE ID */
+	ctrl_mode = sys_env_model_get();
+
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		/* configuration for PEX only */
+		if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
+		    (serdes_type != PEX2) && (serdes_type != PEX3))
+			continue;
+
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		pex_idx = serdes_type - PEX0;
+		dev_id = reg_read(PEX_CFG_DIRECT_ACCESS
+				  (pex_idx, PEX_DEVICE_AND_VENDOR_ID));
+		dev_id &= 0xffff;
+		dev_id |= ((ctrl_mode << 16) & 0xffff0000);
+		reg_write(PEX_CFG_DIRECT_ACCESS
+			  (pex_idx, PEX_DEVICE_AND_VENDOR_ID), dev_id);
+	}
+	DEBUG_INIT_FULL_C("Update PEX Device ID ", ctrl_mode, 4);
+
+	return MV_OK;
+}
+
+int pex_local_bus_num_set(u32 pex_if, u32 bus_num)
+{
+	u32 pex_status;
+
+	DEBUG_INIT_FULL_S("\n### pex_local_bus_num_set ###\n");
+
+	if (bus_num >= MAX_PEX_BUSSES) {
+		DEBUG_INIT_C("pex_local_bus_num_set: Illegal bus number %d\n",
+			     bus_num, 4);
+		return MV_BAD_PARAM;
+	}
+
+	pex_status = reg_read(PEX_STATUS_REG(pex_if));
+	pex_status &= ~PXSR_PEX_BUS_NUM_MASK;
+	pex_status |=
+	    (bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK;
+	reg_write(PEX_STATUS_REG(pex_if), pex_status);
+
+	return MV_OK;
+}
+
+int pex_local_dev_num_set(u32 pex_if, u32 dev_num)
+{
+	u32 pex_status;
+
+	DEBUG_INIT_FULL_S("\n### pex_local_dev_num_set ###\n");
+
+	pex_status = reg_read(PEX_STATUS_REG(pex_if));
+	pex_status &= ~PXSR_PEX_DEV_NUM_MASK;
+	pex_status |=
+	    (dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK;
+	reg_write(PEX_STATUS_REG(pex_if), pex_status);
+
+	return MV_OK;
+}
+
+/*
+ * pex_config_read - Read from configuration space
+ *
+ * DESCRIPTION:
+ *       This function performs a 32 bit read from PEX configuration space.
+ *       It supports both type 0 and type 1 of Configuration Transactions
+ *       (local and over bridge). In order to read from local bus segment, use
+ *       bus number retrieved from pex_local_bus_num_get(). Other bus numbers
+ *       will result configuration transaction of type 1 (over bridge).
+ *
+ * INPUT:
+ *       pex_if   - PEX interface number.
+ *       bus      - PEX segment bus number.
+ *       dev      - PEX device number.
+ *       func     - Function number.
+ *       reg_offs - Register offset.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       32bit register data, 0xffffffff on error
+ */
+u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off)
+{
+	u32 pex_data = 0;
+	u32 local_dev, local_bus;
+	u32 pex_status;
+
+	pex_status = reg_read(PEX_STATUS_REG(pex_if));
+	local_dev =
+	    ((pex_status & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS);
+	local_bus =
+	    ((pex_status & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS);
+
+	/*
+	 * In PCI Express we have only one device number
+	 * and this number is the first number we encounter
+	 * else that the local_dev
+	 * spec pex define return on config read/write on any device
+	 */
+	if (bus == local_bus) {
+		if (local_dev == 0) {
+			/*
+			 * if local dev is 0 then the first number we encounter
+			 * after 0 is 1
+			 */
+			if ((dev != 1) && (dev != local_dev))
+				return MV_ERROR;
+		} else {
+			/*
+			 * if local dev is not 0 then the first number we
+			 * encounter is 0
+			 */
+			if ((dev != 0) && (dev != local_dev))
+				return MV_ERROR;
+		}
+	}
+
+	/* Creating PEX address to be passed */
+	pex_data = (bus << PXCAR_BUS_NUM_OFFS);
+	pex_data |= (dev << PXCAR_DEVICE_NUM_OFFS);
+	pex_data |= (func << PXCAR_FUNC_NUM_OFFS);
+	/* Legacy register space */
+	pex_data |= (reg_off & PXCAR_REG_NUM_MASK);
+	/* Extended register space */
+	pex_data |= (((reg_off & PXCAR_REAL_EXT_REG_NUM_MASK) >>
+		      PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS);
+	pex_data |= PXCAR_CONFIG_EN;
+
+	/* Write the address to the PEX configuration address register */
+	reg_write(PEX_CFG_ADDR_REG(pex_if), pex_data);
+
+	/*
+	 * In order to let the PEX controller absorbed the address
+	 * of the read transaction we perform a validity check that
+	 * the address was written
+	 */
+	if (pex_data != reg_read(PEX_CFG_ADDR_REG(pex_if)))
+		return MV_ERROR;
+
+	/* Cleaning Master Abort */
+	reg_bit_set(PEX_CFG_DIRECT_ACCESS(pex_if, PEX_STATUS_AND_COMMAND),
+		    PXSAC_MABORT);
+	/* Read the Data returned in the PEX Data register */
+	pex_data = reg_read(PEX_CFG_DATA_REG(pex_if));
+
+	DEBUG_INIT_FULL_C(" --> ", pex_data, 4);
+
+	return pex_data;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
new file mode 100644
index 0000000..df395bf
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _CTRL_PEX_H
+#define _CTRL_PEX_H
+
+#include "high_speed_env_spec.h"
+
+/* Sample at Reset */
+#define MPP_SAMPLE_AT_RESET(id)		(0xe4200 + (id * 4))
+
+/* PCI Express Control and Status Registers */
+#define MAX_PEX_BUSSES			256
+
+#define MISC_REGS_OFFSET		0x18200
+#define MV_MISC_REGS_BASE		MISC_REGS_OFFSET
+#define SOC_CTRL_REG			(MV_MISC_REGS_BASE + 0x4)
+
+#define PEX_IF_REGS_OFFSET(if)		((if) > 0 ?			\
+					 (0x40000 + ((if) - 1) * 0x4000) : \
+					 0x80000)
+#define PEX_IF_REGS_BASE(if)		(PEX_IF_REGS_OFFSET(if))
+#define PEX_CAPABILITIES_REG(if)	((PEX_IF_REGS_BASE(if)) + 0x60)
+#define PEX_LINK_CTRL_STATUS2_REG(if)	((PEX_IF_REGS_BASE(if)) + 0x90)
+#define PEX_CTRL_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x1a00)
+#define PEX_STATUS_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x1a04)
+#define PEX_DBG_STATUS_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x1a64)
+#define PEX_LINK_CAPABILITY_REG		0x6c
+#define PEX_LINK_CTRL_STAT_REG		0x70
+#define PXSR_PEX_DEV_NUM_OFFS		16  /* Device Number Indication */
+#define PXSR_PEX_DEV_NUM_MASK		(0x1f << PXSR_PEX_DEV_NUM_OFFS)
+#define PXSR_PEX_BUS_NUM_OFFS		8 /* Bus Number Indication */
+#define PXSR_PEX_BUS_NUM_MASK		(0xff << PXSR_PEX_BUS_NUM_OFFS)
+
+/* PEX_CAPABILITIES_REG fields */
+#define PCIE0_ENABLE_OFFS		0
+#define PCIE0_ENABLE_MASK		(0x1 << PCIE0_ENABLE_OFFS)
+#define PCIE1_ENABLE_OFFS		1
+#define PCIE1_ENABLE_MASK		(0x1 << PCIE1_ENABLE_OFFS)
+#define PCIE2_ENABLE_OFFS		2
+#define PCIE2_ENABLE_MASK		(0x1 << PCIE2_ENABLE_OFFS)
+#define PCIE3_ENABLE_OFFS		3
+#define PCIE4_ENABLE_MASK		(0x1 << PCIE3_ENABLE_OFFS)
+
+/* Controller revision info */
+#define PEX_DEVICE_AND_VENDOR_ID	0x000
+
+/* PCI Express Configuration Address Register */
+#define PXCAR_REG_NUM_OFFS		2
+#define PXCAR_REG_NUM_MAX		0x3f
+#define PXCAR_REG_NUM_MASK		(PXCAR_REG_NUM_MAX << \
+					 PXCAR_REG_NUM_OFFS)
+#define PXCAR_FUNC_NUM_OFFS		8
+#define PXCAR_FUNC_NUM_MAX		0x7
+#define PXCAR_FUNC_NUM_MASK		(PXCAR_FUNC_NUM_MAX << \
+					 PXCAR_FUNC_NUM_OFFS)
+#define PXCAR_DEVICE_NUM_OFFS		11
+#define PXCAR_DEVICE_NUM_MAX		0x1f
+#define PXCAR_DEVICE_NUM_MASK		(PXCAR_DEVICE_NUM_MAX << \
+					 PXCAR_DEVICE_NUM_OFFS)
+#define PXCAR_BUS_NUM_OFFS		16
+#define PXCAR_BUS_NUM_MAX		0xff
+#define PXCAR_BUS_NUM_MASK		(PXCAR_BUS_NUM_MAX << \
+					 PXCAR_BUS_NUM_OFFS)
+#define PXCAR_EXT_REG_NUM_OFFS		24
+#define PXCAR_EXT_REG_NUM_MAX		0xf
+
+#define PEX_CFG_ADDR_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x18f8)
+#define PEX_CFG_DATA_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x18fc)
+
+#define PXCAR_REAL_EXT_REG_NUM_OFFS	8
+#define PXCAR_REAL_EXT_REG_NUM_MASK	(0xf << PXCAR_REAL_EXT_REG_NUM_OFFS)
+
+#define PXCAR_CONFIG_EN			BIT(31)
+#define PEX_STATUS_AND_COMMAND		0x004
+#define PXSAC_MABORT			BIT(29) /* Recieved Master Abort */
+
+int hws_pex_config(struct serdes_map *serdes_map);
+int pex_local_bus_num_set(u32 pex_if, u32 bus_num);
+int pex_local_dev_num_set(u32 pex_if, u32 dev_num);
+u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off);
+
+#endif
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c
new file mode 100644
index 0000000..5ff8567
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_env_spec.h"
+#include "sys_env_lib.h"
+
+#define SERDES_VERION	"2.0"
+
+u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = {
+	/* 0  1    2    3    4    5 */
+	{0x1, 0x1, NA,  NA,  NA,  NA},		/* PEX0 */
+	{NA,  0x2, 0x1, NA,  0x1, NA},		/* PEX1 */
+	{NA,  NA,  0x2, NA,  NA,  0x1},		/* PEX2 */
+	{NA,  NA,  NA,  0x1, NA,  NA},		/* PEX3 */
+	{0x2, 0x3, NA,  NA,  NA,  NA},		/* SATA0 */
+	{NA,  NA,  0x3, NA,  0x2, NA},		/* SATA1 */
+	{NA,  NA,  NA,  NA,  0x6, 0x2},		/* SATA2 */
+	{NA,  NA,  NA,  0x3, NA,  NA},		/* SATA3 */
+	{0x3, 0x4, NA,  NA,  NA,  NA},		/* SGMII0 */
+	{NA,  0x5, 0x4, NA,  0x3, NA},		/* SGMII1 */
+	{NA,  NA,  NA,  0x4, NA,  0x3},		/* SGMII2 */
+	{NA,  0x7, NA,  NA,  NA,  NA},		/* QSGMII */
+	{NA,  0x6, NA,  NA,  0x4, NA},		/* USB3_HOST0 */
+	{NA,  NA,  NA,  0x5, NA,  0x4},		/* USB3_HOST1 */
+	{NA,  NA,  NA,  0x6, 0x5, 0x5},		/* USB3_DEVICE */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}		/* DEFAULT_SERDES */
+};
+
+int hws_serdes_seq_init(void)
+{
+	DEBUG_INIT_FULL_S("\n### serdes_seq_init ###\n");
+
+	if (hws_serdes_seq_db_init() != MV_OK) {
+		printf("hws_serdes_seq_init: Error: Serdes initialization fail\n");
+		return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up,
+			     enum serdes_type serdes_type,
+			     enum serdes_speed baud_rate,
+			     enum serdes_mode serdes_mode,
+			     enum ref_clock ref_clock)
+{
+	return MV_NOT_SUPPORTED;
+}
+
+u32 hws_serdes_silicon_ref_clock_get(void)
+{
+	DEBUG_INIT_FULL_S("\n### hws_serdes_silicon_ref_clock_get ###\n");
+
+	return REF_CLOCK_25MHZ;
+}
+
+u32 hws_serdes_get_max_lane(void)
+{
+	switch (sys_env_device_id_get()) {
+	case MV_6811:		/* A381/A3282: 6811/6821: single/dual cpu */
+		return 4;
+	case MV_6810:
+		return 5;
+	case MV_6820:
+	case MV_6828:
+		return 6;
+	default:		/* not the right module */
+		printf("%s: Device ID Error, using 4 SerDes lanes\n",
+		       __func__);
+		return 4;
+	}
+	return 6;
+}
+
+int hws_is_serdes_active(u8 lane_num)
+{
+	int ret = 1;
+
+	/* Maximum lane count for A388 (6828) is 6 */
+	if (lane_num > 6)
+		ret = 0;
+
+	/* 4th Lane (#4 on Device 6810 is not Active */
+	if (sys_env_device_id_get() == MV_6810 && lane_num == 4) {
+		printf("%s: Error: Lane#4 on Device 6810 is not Active.\n",
+		       __func__);
+		return 0;
+	}
+
+	/*
+	 * 6th Lane (#5) on Device 6810 is Active, even though 6810
+	 * has only 5 lanes
+	 */
+	if (sys_env_device_id_get() == MV_6810 && lane_num == 5)
+		return 1;
+
+	if (lane_num >= hws_serdes_get_max_lane())
+		ret = 0;
+
+	return ret;
+}
+
+int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset,
+			  u32 *unit_base_reg, u32 *unit_offset)
+{
+	*unit_base_reg = base_addr;
+	*unit_offset = unit_base_offset;
+
+	return MV_OK;
+}
+
+/*
+ * hws_serdes_get_phy_selector_val
+ *
+ * DESCRIPTION: Get the mapping of Serdes Selector values according to the
+ *              Serdes revision number
+ * INPUT:    serdes_num - Serdes number
+ *           serdes_type - Serdes type
+ * OUTPUT: None
+ * RETURN:
+ *       Mapping of Serdes Selector values
+ */
+u32 hws_serdes_get_phy_selector_val(int serdes_num,
+				    enum serdes_type serdes_type)
+{
+	if (serdes_type >= LAST_SERDES_TYPE)
+		return 0xff;
+
+	if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+		return selectors_serdes_rev1_map
+			[serdes_type][serdes_num];
+	} else
+		return selectors_serdes_rev2_map
+			[serdes_type][serdes_num];
+}
+
+u32 hws_get_physical_serdes_num(u32 serdes_num)
+{
+	if ((serdes_num == 4) && (sys_env_device_id_get() == MV_6810)) {
+		/*
+		 * For 6810, there are 5 Serdes and Serdes Num 4 doesn't
+		 * exist. Instead Serdes Num 5 is connected.
+		 */
+		return 5;
+	} else {
+		return serdes_num;
+	}
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
new file mode 100644
index 0000000..23af769
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
@@ -0,0 +1,2228 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_env_spec.h"
+#include "high_speed_topology_spec.h"
+#include "sys_env_lib.h"
+#include "ctrl_pex.h"
+
+#if defined(CONFIG_ARMADA_38X)
+#elif defined(CONFIG_ARMADA_39X)
+#else
+#error "No device is defined"
+#endif
+
+/*
+ * The board topology map, initialized in the beginning of
+ * ctrl_high_speed_serdes_phy_config
+ */
+struct serdes_map serdes_configuration_map[MAX_SERDES_LANES];
+
+/*
+ * serdes_seq_db - holds all serdes sequences, their size and the
+ * relevant index in the data array initialized in serdes_seq_init
+ */
+struct cfg_seq serdes_seq_db[SERDES_LAST_SEQ];
+
+#define	SERDES_VERION		"2.0"
+#define ENDED_OK		"High speed PHY - Ended Successfully\n"
+
+#define LINK_WAIT_CNTR		100
+#define LINK_WAIT_SLEEP		100
+
+#define MAX_UNIT_NUMB		4
+#define TOPOLOGY_TEST_OK	0
+#define WRONG_NUMBER_OF_UNITS	1
+#define SERDES_ALREADY_IN_USE	2
+#define UNIT_NUMBER_VIOLATION	3
+
+/*
+ * serdes_lane_in_use_count contains the exact amount of serdes lanes
+ * needed per type
+ */
+u8 serdes_lane_in_use_count[MAX_UNITS_ID][MAX_UNIT_NUMB] = {
+	/* 0  1  2  3  */
+	{  1, 1, 1, 1 },	/* PEX     */
+	{  1, 1, 1, 1 },	/* ETH_GIG */
+	{  1, 1, 0, 0 },	/* USB3H   */
+	{  1, 1, 1, 0 },	/* USB3D   */
+	{  1, 1, 1, 1 },	/* SATA    */
+	{  1, 0, 0, 0 },	/* QSGMII  */
+	{  4, 0, 0, 0 },	/* XAUI    */
+	{  2, 0, 0, 0 }		/* RXAUI   */
+};
+
+/*
+ * serdes_unit_count count unit number.
+ * (i.e a single XAUI is counted as 1 unit)
+ */
+u8 serdes_unit_count[MAX_UNITS_ID] = { 0 };
+
+/* Selector mapping for A380-A0 and A390-Z1 */
+u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = {
+	/* 0      1      2       3       4       5       6 */
+	{ 0x1,   0x1,    NA,	 NA,	 NA,	 NA,     NA  }, /* PEX0 */
+	{ NA,    NA,     0x1,	 NA,	 0x1,	 NA,     0x1 }, /* PEX1 */
+	{ NA,    NA,     NA,	 NA,	 0x7,	 0x1,    NA  }, /* PEX2 */
+	{ NA,    NA,     NA,	 0x1,	 NA,	 NA,     NA  }, /* PEX3 */
+	{ 0x2,   0x3,    NA,	 NA,	 NA,	 NA,     NA  }, /* SATA0 */
+	{ NA,    NA,     0x3,	 NA,	 NA,	 NA,     NA  }, /* SATA1 */
+	{ NA,    NA,     NA,	 NA,	 0x6,	 0x2,    NA  }, /* SATA2 */
+	{ NA,	 NA,     NA,	 0x3,	 NA,	 NA,     NA  }, /* SATA3 */
+	{ 0x3,   0x4,    NA,     NA,	 NA,	 NA,     NA  }, /* SGMII0 */
+	{ NA,    0x5,    0x4,    NA,	 0x3,	 NA,     NA  }, /* SGMII1 */
+	{ NA,    NA,     NA,	 0x4,	 NA,	 0x3,    NA  }, /* SGMII2 */
+	{ NA,    0x7,    NA,	 NA,	 NA,	 NA,     NA  }, /* QSGMII */
+	{ NA,    0x6,    NA,	 NA,	 0x4,	 NA,     NA  }, /* USB3_HOST0 */
+	{ NA,    NA,     NA,	 0x5,	 NA,	 0x4,    NA  }, /* USB3_HOST1 */
+	{ NA,    NA,     NA,	 0x6,	 0x5,	 0x5,    NA  }, /* USB3_DEVICE */
+#ifdef CONFIG_ARMADA_39X
+	{ NA,    NA,     0x5,	 NA,	 0x8,	 NA,     0x2 }, /* SGMII3 */
+	{ NA,    NA,     NA,	 0x8,	 0x9,	 0x8,    0x4 }, /* XAUI */
+	{ NA,    NA,     NA,	 NA,	 NA,	 0x8,    0x4 }, /* RXAUI */
+#endif
+	{ 0x0,   0x0,    0x0,	 0x0,	 0x0,	 0x0,    NA  }  /* DEFAULT_SERDES */
+};
+
+/* Selector mapping for PEX by 4 confiuration */
+u8 common_phys_selectors_pex_by4_lanes[] = { 0x1, 0x2, 0x2, 0x2 };
+
+static const char *const serdes_type_to_string[] = {
+	"PCIe0",
+	"PCIe1",
+	"PCIe2",
+	"PCIe3",
+	"SATA0",
+	"SATA1",
+	"SATA2",
+	"SATA3",
+	"SGMII0",
+	"SGMII1",
+	"SGMII2",
+	"QSGMII",
+	"USB3 HOST0",
+	"USB3 HOST1",
+	"USB3 DEVICE",
+	"SGMII3",
+	"XAUI",
+	"RXAUI",
+	"DEFAULT SERDES",
+	"LAST_SERDES_TYPE"
+};
+
+struct serdes_unit_data {
+	u8 serdes_unit_id;
+	u8 serdes_unit_num;
+};
+
+static struct serdes_unit_data serdes_type_to_unit_info[] = {
+	{PEX_UNIT_ID, 0,},
+	{PEX_UNIT_ID, 1,},
+	{PEX_UNIT_ID, 2,},
+	{PEX_UNIT_ID, 3,},
+	{SATA_UNIT_ID, 0,},
+	{SATA_UNIT_ID, 1,},
+	{SATA_UNIT_ID, 2,},
+	{SATA_UNIT_ID, 3,},
+	{ETH_GIG_UNIT_ID, 0,},
+	{ETH_GIG_UNIT_ID, 1,},
+	{ETH_GIG_UNIT_ID, 2,},
+	{QSGMII_UNIT_ID, 0,},
+	{USB3H_UNIT_ID, 0,},
+	{USB3H_UNIT_ID, 1,},
+	{USB3D_UNIT_ID, 0,},
+	{ETH_GIG_UNIT_ID, 3,},
+	{XAUI_UNIT_ID, 0,},
+	{RXAUI_UNIT_ID, 0,},
+};
+
+/* Sequences DB */
+
+/*
+ * SATA and SGMII
+ */
+
+struct op_params sata_port0_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Access to reg 0x48(OOB param 1) */
+	{SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0},
+	/* OOB Com_wake and Com_reset spacing upper limit data */
+	{SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0},
+	/* Access to reg 0xa(PHY Control) */
+	{SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0},
+	/* Rx clk and Tx clk select non-inverted mode */
+	{SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0},
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0},
+	/* Power Down Sata Port 0 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40040,}, 0, 0},
+};
+
+struct op_params sata_port1_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Access to reg 0x48(OOB param 1) */
+	{SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0},
+	/* OOB Com_wake and Com_reset spacing upper limit data */
+	{SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0},
+	/* Access to reg 0xa(PHY Control) */
+	{SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0},
+	/* Rx clk and Tx clk select non-inverted mode */
+	{SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0},
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0},
+	/* Power Down Sata Port 1 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc44000,}, 0, 0},
+};
+
+/* SATA and SGMII - power up seq */
+struct op_params sata_and_sgmii_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	/* Power Up */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x90006, {0x80002, 0x80002},
+	 0, 0},
+	/* Unreset */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0x6000}, 0, 0},
+	/* Phy Selector */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x0e0, {0x0, 0x80}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x440, {0x440, 0x400}, 0, 0}
+};
+
+/* SATA and SGMII - speed config seq */
+struct op_params sata_and_sgmii_speed_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data,
+	 * SGMII (1.25G), SGMII (3.125G), wait_time, num_of_loops
+	 */
+	/* Baud Rate */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000,
+	 {0x8800000, 0x19800000, 0x22000000}, 0, 0},
+	/* Select Baud Rate for SATA only */
+	{INTERFACE_REG, 0x800, 0xc00, {0x800, NO_DATA, NO_DATA}, 0, 0},
+	/* Phy Gen RX and TX */
+	{ISOLATE_REG, 0x800, 0xff, {NO_DATA, 0x66, 0x66}, 0, 0},
+	/* Bus Width */
+	{LOOPBACK_REG, 0x800, 0xe, {0x4, 0x2, 0x2}, 0, 0}
+};
+
+/* SATA and SGMII - TX config seq */
+struct op_params sata_and_sgmii_tx_config_params1[] = {
+	/*
+	 * unitunit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	{GLUE_REG, 0x800, 0x1800, {NO_DATA, 0x800}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0},
+	/* Power up PLL, RX and TX */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0000, {0x70000, 0x70000},
+	 0, 0}
+};
+
+struct op_params sata_port0_tx_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0},
+	/* Power Down Sata  Port 0 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40000}, 0, 0},
+	/* Regret bit addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0},
+	/* Regret bit data */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0}
+};
+
+struct op_params sata_port1_tx_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0},
+	/* Power Down Sata Port 1 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc40000}, 0, 0},
+	/* Regret bit addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0},
+	/* Regret bit data */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0}
+};
+
+struct op_params sata_and_sgmii_tx_config_serdes_rev1_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000},
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000}
+};
+
+struct op_params sata_and_sgmii_tx_config_serdes_rev2_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000},
+	/* Assert Rx Init for SGMII */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x40000000},
+	 0, 0},
+	/* Assert Rx Init for SATA */
+	{ISOLATE_REG, 0x800, 0x400, {0x400, NA}, 0, 0},
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000},
+	/* De-assert Rx Init for SGMII */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x0}, 0, 0},
+	/* De-assert Rx Init for SATA */
+	{ISOLATE_REG, 0x800, 0x400, {0x0, NA}, 0, 0},
+	/* os_ph_offset_force (align 90) */
+	{RX_REG3, 0x800, 0xff, {0xde, NO_DATA}, 0, 0},
+	/* Set os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0},
+	/* Unset os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0},
+};
+
+struct op_params sata_electrical_config_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* enable SSC and DFE update enable */
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000,}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000,}, 0, 0},
+	/* SQ_THRESH and FFE Setting */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x6cf,}, 0, 0},
+	/* G1_TX SLEW, EMPH1 and AMP */
+	{G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32,}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9,}, 0, 0},
+	/* G2_TX SLEW, EMPH1 and AMP */
+	{G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c,}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0},
+	/* G3_TX SLEW, EMPH1 and AMP */
+	{G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e,}, 0, 0},
+	/* G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G3_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0},
+	/* Cal rxclkalign90 ext enable and Cal os ph ext */
+	{CAL_REG6, 0x800, 0xff00, {0xdd00,}, 0, 0},
+	/* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0},
+};
+
+struct op_params sata_electrical_config_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* SQ_THRESH and FFE Setting */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xf00, {0x600}, 0, 0},
+	/* enable SSC and DFE update enable */
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000}, 0, 0},
+	/* G1_TX SLEW, EMPH1 and AMP */
+	{G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G2_TX SLEW, EMPH1 and AMP */
+	{G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0},
+	/* G3_TX SLEW, EMPH1 and AMP */
+	{G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e}, 0, 0},
+	/*
+	 * G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI & DFE_En Gen3,
+	 * DC wander calibration dis
+	 */
+	{G3_SETTINGS_1_REG, 0x800, 0x47ff, {0x7d2}, 0, 0},
+	/* Bit[12]=0x0 idle_sync_en */
+	{PCIE_REG0, 0x800, 0x1000, {0x0}, 0, 0},
+	/* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0},
+	/* DFE_STEP_FINE_FX[3:0] =0xa */
+	{DFE_REG0, 0x800, 0xa00f, {0x800a}, 0, 0},
+	/* DFE_EN and Dis Update control from pin disable */
+	{DFE_REG3, 0x800, 0xc000, {0x0}, 0, 0},
+	/* FFE Force FFE_REs and cap settings for Gen1 */
+	{G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0},
+	/* FFE Force FFE_REs and cap settings for Gen2 */
+	{G2_SETTINGS_3_REG, 0x800, 0xff, {0xbf}, 0, 0},
+	/* FE Force FFE_REs=4 and cap settings for Gen3n */
+	{G3_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0},
+	/* Set DFE Gen 3 Resolution to 3 */
+	{G3_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0},
+};
+
+struct op_params sgmii_electrical_config_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G),
+	 * wait_time, num_of_loops
+	 */
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0},
+	/* SQ_THRESH and FFE Setting */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x8f, 0xbf}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000, 0x4000}, 0, 0},
+};
+
+struct op_params sgmii_electrical_config_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G),
+	 * wait_time, num_of_loops
+	 */
+	/* Set Slew_rate, Emph and Amp */
+	{G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8fa, 0x8fa}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0},
+	/* DTL_FLOOP_EN */
+	{RX_REG2, 0x800, 0x4, {0x0, 0x0}, 0, 0},
+	/* G1 FFE Setting Force, RES and CAP */
+	{G1_SETTINGS_3_REG, 0x800, 0xff, {0x8f, 0xbf}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000, 0x3000}, 0, 0},
+};
+
+/*
+ * PEX and USB3
+ */
+
+/* PEX and USB3 - power up seq for Serdes Rev 1.2 */
+struct op_params pex_and_usb3_power_up_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806,
+	 {0x4471804, 0x4479804}, 0, 0},
+	{COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0},
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0},
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0},
+	{GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0}
+};
+
+/* PEX and USB3 - power up seq for Serdes Rev 2.1 */
+struct op_params pex_and_usb3_power_up_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806,
+	 {0x4471804, 0x4479804}, 0, 0},
+	{COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0},
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0},
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0},
+	{GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0},
+	{GLOBAL_MISC_CTRL, 0x800, 0xc0, {0x0, NO_DATA}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0}
+};
+
+/* PEX and USB3 - speed config seq */
+struct op_params pex_and_usb3_speed_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	/* Maximal PHY Generation Setting */
+	{INTERFACE_REG, 0x800, 0xc00, {0x400, 0x400, 0x400, 0x400, 0x400},
+	 0, 0},
+};
+
+struct op_params usb3_electrical_config_serdes_rev1_params[] = {
+	/* Spread Spectrum Clock Enable */
+	{LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0},
+	/* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */
+	{G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0},
+	/* FFE Setting Force, RES and CAP */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xef}, 0, 0},
+	/* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70}, 0, 0},
+	/* cal_rxclkalign90_ext_en and cal_os_ph_ext */
+	{CAL_REG6, 0x800, 0xff00, {0xd500}, 0, 0},
+	/* vco_cal_vth_sel */
+	{REF_REG0, 0x800, 0x38, {0x20}, 0, 0},
+};
+
+struct op_params usb3_electrical_config_serdes_rev2_params[] = {
+	/* Spread Spectrum Clock Enable */
+	{LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0},
+	/* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */
+	{G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0},
+	/* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70}, 0, 0},
+	/* vco_cal_vth_sel */
+	{REF_REG0, 0x800, 0x38, {0x20}, 0, 0},
+	/* Spread Spectrum Clock Enable */
+	{LANE_CFG5_REG, 0x800, 0x4, {0x4}, 0, 0},
+};
+
+/* PEX and USB3 - TX config seq */
+
+/*
+ * For PEXx1: the pex_and_usb3_tx_config_params1/2/3 configurations should run
+ *            one by one on the lane.
+ * For PEXx4: the pex_and_usb3_tx_config_params1/2/3 configurations should run
+ *            by setting each sequence for all 4 lanes.
+ */
+struct op_params pex_and_usb3_tx_config_params1[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	{GLOBAL_CLK_CTRL, 0x800, 0x1, {0x0, 0x0}, 0, 0},
+	/* 10ms delay */
+	{0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0},
+	/* os_ph_offset_force (align 90) */
+	{RX_REG3, 0x800, 0xff, {0xdc, NO_DATA}, 0, 0},
+	/* Set os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0},
+	/* Unset os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0},
+};
+
+struct op_params pex_and_usb3_tx_config_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0},
+};
+
+struct op_params pex_and_usb3_tx_config_params3[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0},
+	/* 10ms delay */
+	{0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0}
+};
+
+/* PEX by 4 config seq */
+struct op_params pex_by4_config_params[] = {
+	/* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */
+	{GLOBAL_CLK_SRC_HI, 0x800, 0x7, {0x5, 0x0, 0x0, 0x2}, 0, 0},
+	/* Lane Alignement enable */
+	{LANE_ALIGN_REG0, 0x800, 0x1000, {0x0, 0x0, 0x0, 0x0}, 0, 0},
+	/* Max PLL phy config */
+	{CALIBRATION_CTRL_REG, 0x800, 0x1000, {0x1000, 0x1000, 0x1000, 0x1000},
+	 0, 0},
+	/* Max PLL pipe config */
+	{LANE_CFG1_REG, 0x800, 0x600, {0x600, 0x600, 0x600, 0x600}, 0, 0},
+};
+
+/* USB3 device donfig seq */
+struct op_params usb3_device_config_params[] = {
+	/* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */
+	{LANE_CFG4_REG, 0x800, 0x200, {0x200}, 0, 0}
+};
+
+/* PEX - electrical configuration seq Rev 1.2 */
+struct op_params pex_electrical_config_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */
+	{G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* CFG_DFE_EN_SEL */
+	{LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0},
+	/* FFE Setting Force, RES and CAP */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xaf}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0},
+	/* cal_rxclkalign90_ext_en and cal_os_ph_ext */
+	{CAL_REG6, 0x800, 0xff00, {0xdc00}, 0, 0},
+};
+
+/* PEX - electrical configuration seq Rev 2.1 */
+struct op_params pex_electrical_config_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */
+	{G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G1 FFE Setting Force, RES and CAP */
+	{G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G2 FFE Setting Force, RES and CAP */
+	{G2_SETTINGS_3_REG, 0x800, 0xff, {0xaf}, 0, 0},
+	/* G2 DFE resolution value */
+	{G2_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0},
+	/* DFE resolution force */
+	{DFE_REG0, 0x800, 0x8000, {0x8000}, 0, 0},
+	/* Tx amplitude for Tx Margin 0 */
+	{PCIE_REG1, 0x800, 0xf80, {0xd00}, 0, 0},
+	/* Tx_Emph value for -3.5d_b and -6d_b */
+	{PCIE_REG3, 0x800, 0xff00, {0xaf00}, 0, 0},
+	/* CFG_DFE_EN_SEL */
+	{LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0},
+};
+
+/* PEX - configuration seq for REF_CLOCK_25MHz */
+struct op_params pex_config_ref_clock25_m_hz[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* Bits[4:0]=0x2 - REF_FREF_SEL */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x2}, 0, 0},
+	/* Bit[10]=0x1   - REFCLK_SEL */
+	{MISC_REG, 0x800, 0x400, {0x400}, 0, 0},
+	/* Bits[7:0]=0x7 - CFG_PM_RXDLOZ_WAIT */
+	{GLOBAL_PM_CTRL, 0x800, 0xff, {0x7}, 0, 0},
+};
+
+/* PEX - configuration seq for REF_CLOCK_40MHz */
+struct op_params pex_config_ref_clock40_m_hz[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* Bits[4:0]=0x3 - REF_FREF_SEL */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x3}, 0, 0},
+	/* Bits[10]=0x1  - REFCLK_SEL */
+	{MISC_REG, 0x800, 0x400, {0x400}, 0, 0},
+	/* Bits[7:0]=0xc - CFG_PM_RXDLOZ_WAIT */
+	{GLOBAL_PM_CTRL, 0x800, 0xff, {0xc}, 0, 0},
+};
+
+/* PEX - configuration seq for REF_CLOCK_100MHz */
+struct op_params pex_config_ref_clock100_m_hz[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* Bits[4:0]=0x0  - REF_FREF_SEL */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x0}, 0, 0},
+	/* Bit[10]=0x0    - REFCLK_SEL */
+	{MISC_REG, 0x800, 0x400, {0x0}, 0, 0},
+	/* Bits[7:0]=0x1e - CFG_PM_RXDLOZ_WAIT */
+	{GLOBAL_PM_CTRL, 0x800, 0xff, {0x1e}, 0, 0},
+};
+
+/*
+ *    USB2
+ */
+
+struct op_params usb2_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, USB2 data, wait_time,
+	 * num_of_loops
+	 */
+	/* Init phy 0 */
+	{0x18440, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0},
+	/* Init phy 1 */
+	{0x18444, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0},
+	/* Init phy 2 */
+	{0x18448, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0},
+	/* Phy offset 0x0 - PLL_CONTROL0  */
+	{0xc0000, 0x0 /*NA*/, 0xffffffff, {0x40605205}, 0, 0},
+	{0xc001c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0},
+	{0xc201c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0},
+	{0xc401c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0},
+	/* Phy offset 0x1 - PLL_CONTROL1 */
+	{0xc0004, 0x0 /*NA*/, 0x1, {0x1}, 0, 0},
+	/* Phy0 register 3  - TX Channel control 0 */
+	{0xc000c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
+	/* Phy0 register 3  - TX Channel control 0 */
+	{0xc200c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
+	/* Phy0 register 3  - TX Channel control 0 */
+	{0xc400c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
+	/* check PLLCAL_DONE is set and IMPCAL_DONE is set */
+	{0xc0008, 0x0 /*NA*/, 0x80800000, {0x80800000}, 1, 1000},
+	/* check REG_SQCAL_DONE  is set */
+	{0xc0018, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000},
+	/* check PLL_READY  is set */
+	{0xc0000, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000}
+};
+
+/*
+ *    QSGMII
+ */
+
+/* QSGMII - power up seq */
+struct op_params qsgmii_port_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Connect the QSGMII to Gigabit Ethernet units */
+	{QSGMII_CONTROL_REG1, 0x0, 0x40000000, {0x40000000}, 0, 0},
+	/* Power Up */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0006, {0x80002}, 0, 0},
+	/* Unreset */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000}, 0, 0},
+	/* Phy Selector */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0xff, {0xfc81}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x4c0, {0x480}, 0, 0}
+};
+
+/* QSGMII - speed config seq */
+struct op_params qsgmii_port_speed_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Baud Rate */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000, {0xcc00000}, 0, 0},
+	/* Phy Gen RX and TX */
+	{ISOLATE_REG, 0x800, 0xff, {0x33}, 0, 0},
+	/* Bus Width */
+	{LOOPBACK_REG, 0x800, 0xe, {0x2}, 0, 0}
+};
+
+/* QSGMII - Select electrical param seq */
+struct op_params qsgmii_port_electrical_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Slew rate and emphasis */
+	{G1_SETTINGS_0_REG, 0x800, 0x8000, {0x0}, 0, 0}
+};
+
+/* QSGMII - TX config seq */
+struct op_params qsgmii_port_tx_config_params1[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	{GLUE_REG, 0x800, 0x1800, {0x800}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x401}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x0}, 0, 0},
+	/* Lane align */
+	{LANE_ALIGN_REG0, 0x800, 0x1000, {0x1000}, 0, 0},
+	/* Power up PLL, RX and TX */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x70000, {0x70000}, 0, 0},
+	/* Tx driver output idle */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x80000, {0x80000}, 0, 0}
+};
+
+struct op_params qsgmii_port_tx_config_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc}, 10, 1000},
+	/* Assert Rx Init and Tx driver output valid */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40080000, {0x40000000}, 0, 0},
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1}, 1, 1000},
+	/* De-assert Rx Init */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {0x0}, 0, 0}
+};
+
+/* SERDES_POWER_DOWN */
+struct op_params serdes_power_down_params[] = {
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, (0xf << 11), {(0x3 << 11)},
+	 0, 0},
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, (0x7 << 16), {0}, 0, 0}
+};
+
+/*
+ * hws_ctrl_serdes_rev_get
+ *
+ * DESCRIPTION: Get the Serdes revision number
+ *
+ * INPUT: config_field - Field description enum
+ *
+ * OUTPUT: None
+ *
+ * RETURN:
+ *		8bit Serdes revision number
+ */
+u8 hws_ctrl_serdes_rev_get(void)
+{
+#ifdef CONFIG_ARMADA_38X
+	/* for A38x-Z1 */
+	if (sys_env_device_rev_get() == MV_88F68XX_Z1_ID)
+		return MV_SERDES_REV_1_2;
+#endif
+
+	/* for A39x-Z1, A38x-A0 */
+	return MV_SERDES_REV_2_1;
+}
+
+u32 hws_serdes_topology_verify(enum serdes_type serdes_type, u32 serdes_id,
+			       enum serdes_mode serdes_mode)
+{
+	u32 test_result = 0;
+	u8 serd_max_num, unit_numb;
+	enum unit_id unit_id;
+
+	if (serdes_type > RXAUI) {
+		printf("%s: Warning: Wrong serdes type %s serdes#%d\n",
+		       __func__, serdes_type_to_string[serdes_type], serdes_id);
+		return MV_FAIL;
+	}
+
+	unit_id = serdes_type_to_unit_info[serdes_type].serdes_unit_id;
+	unit_numb = serdes_type_to_unit_info[serdes_type].serdes_unit_num;
+	serd_max_num = sys_env_unit_max_num_get(unit_id);
+
+	/* if didn't exceed amount of required Serdes lanes for current type */
+	if (serdes_lane_in_use_count[unit_id][unit_numb] != 0) {
+		/* update amount of required Serdes lanes for current type */
+		serdes_lane_in_use_count[unit_id][unit_numb]--;
+
+		/*
+		 * If reached the exact amount of required Serdes lanes for
+		 * current type
+		 */
+		if (serdes_lane_in_use_count[unit_id][unit_numb] == 0) {
+			if (((serdes_type <= PEX3)) &&
+			    ((serdes_mode == PEX_END_POINT_X4) ||
+			     (serdes_mode == PEX_ROOT_COMPLEX_X4))) {
+				/* PCiex4 uses 2 SerDes */
+				serdes_unit_count[PEX_UNIT_ID] += 2;
+			} else {
+				serdes_unit_count[unit_id]++;
+			}
+
+			/* test SoC unit count limitation */
+			if (serdes_unit_count[unit_id] > serd_max_num) {
+				test_result = WRONG_NUMBER_OF_UNITS;
+			} else if (unit_numb >= serd_max_num) {
+				/* test SoC unit number limitation */
+				test_result = UNIT_NUMBER_VIOLATION;
+			}
+		}
+	} else {
+		test_result = SERDES_ALREADY_IN_USE;
+		if (test_result == SERDES_ALREADY_IN_USE) {
+			printf("%s: Error: serdes lane %d is configured to type %s: type already in use\n",
+			       __func__, serdes_id,
+			       serdes_type_to_string[serdes_type]);
+			return MV_FAIL;
+		} else if (test_result == WRONG_NUMBER_OF_UNITS) {
+			printf("%s: Warning: serdes lane %d is set to type %s.\n",
+			       __func__, serdes_id,
+			       serdes_type_to_string[serdes_type]);
+			printf("%s: Maximum supported lanes are already set to this type (limit = %d)\n",
+			       __func__, serd_max_num);
+			return MV_FAIL;
+		} else if (test_result == UNIT_NUMBER_VIOLATION) {
+			printf("%s: Warning: serdes lane %d type is %s: current device support only %d units of this type.\n",
+			       __func__, serdes_id,
+			       serdes_type_to_string[serdes_type],
+			       serd_max_num);
+			return MV_FAIL;
+		}
+	}
+
+	return MV_OK;
+}
+
+void hws_serdes_xaui_topology_verify(void)
+{
+	/*
+	 * If XAUI is in use - serdes_lane_in_use_count has to be = 0;
+	 * if it is not in use hast be = 4
+	 */
+	if ((serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 0) &&
+	    (serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 4)) {
+		printf("%s: Warning: wrong number of lanes is set to XAUI - %d\n",
+		       __func__, serdes_lane_in_use_count[XAUI_UNIT_ID][0]);
+		printf("%s: XAUI has to be defined on 4 lanes\n", __func__);
+	}
+
+	/*
+	 * If RXAUI is in use - serdes_lane_in_use_count has to be = 0;
+	 * if it is not in use hast be = 2
+	 */
+	if ((serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 0) &&
+	    (serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 2)) {
+		printf("%s: Warning: wrong number of lanes is set to RXAUI - %d\n",
+		       __func__, serdes_lane_in_use_count[RXAUI_UNIT_ID][0]);
+		printf("%s: RXAUI has to be defined on 2 lanes\n", __func__);
+	}
+}
+
+int hws_serdes_seq_db_init(void)
+{
+	u8 serdes_rev = hws_ctrl_serdes_rev_get();
+
+	DEBUG_INIT_FULL_S("\n### serdes_seq38x_init ###\n");
+
+	if (serdes_rev == MV_SERDES_REV_NA) {
+		printf("hws_serdes_seq_db_init: serdes revision number is not supported\n");
+		return MV_NOT_SUPPORTED;
+	}
+
+	/* SATA_PORT_0_ONLY_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].op_params_ptr =
+	    sata_port0_power_up_params;
+	serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_port0_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].data_arr_idx = SATA;
+
+	/* SATA_PORT_1_ONLY_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].op_params_ptr =
+	    sata_port1_power_up_params;
+	serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_port1_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].data_arr_idx = SATA;
+
+	/* SATA_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SATA_POWER_UP_SEQ].op_params_ptr =
+	    sata_and_sgmii_power_up_params;
+	serdes_seq_db[SATA_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_POWER_UP_SEQ].data_arr_idx = SATA;
+
+	/* SATA_1_5_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_3_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_6_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sata_electrical_config_serdes_rev1_params;
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sata_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sata_electrical_config_serdes_rev2_params;
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sata_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_TX_CONFIG_SEQ1].op_params_ptr =
+	    sata_and_sgmii_tx_config_params1;
+	serdes_seq_db[SATA_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[SATA_TX_CONFIG_SEQ1].data_arr_idx = SATA;
+
+	/* SATA_PORT_0_ONLY_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].op_params_ptr =
+	    sata_port0_tx_config_params;
+	serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_port0_tx_config_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_PORT_1_ONLY_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].op_params_ptr =
+	    sata_port1_tx_config_params;
+	serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_port1_tx_config_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_TX_CONFIG_SEQ2 sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev1_params2;
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev2_params2;
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SATA_TX_CONFIG_SEQ2].data_arr_idx = SATA;
+
+	/* SGMII_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SGMII_POWER_UP_SEQ].op_params_ptr =
+	    sata_and_sgmii_power_up_params;
+	serdes_seq_db[SGMII_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SGMII_POWER_UP_SEQ].data_arr_idx = SGMII;
+
+	/* SGMII_1_25_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].data_arr_idx = SGMII;
+
+	/* SGMII_3_125_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].data_arr_idx = SGMII_3_125;
+
+	/* SGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sgmii_electrical_config_serdes_rev1_params;
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sgmii_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sgmii_electrical_config_serdes_rev2_params;
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sgmii_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SGMII;
+
+	/* SGMII_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ1].op_params_ptr =
+	    sata_and_sgmii_tx_config_params1;
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ1].data_arr_idx = SGMII;
+
+	/* SGMII_TX_CONFIG_SEQ sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev1_params2;
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev2_params2;
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ2].data_arr_idx = SGMII;
+
+	/* PEX_POWER_UP_SEQ sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev1_params;
+		serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev2_params;
+		serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[PEX_POWER_UP_SEQ].data_arr_idx = PEX;
+
+	/* PEX_2_5_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].data_arr_idx =
+		PEXSERDES_SPEED_2_5_GBPS;
+
+	/* PEX_5_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].data_arr_idx =
+		PEXSERDES_SPEED_5_GBPS;
+
+	/* PEX_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    pex_electrical_config_serdes_rev1_params;
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(pex_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    pex_electrical_config_serdes_rev2_params;
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(pex_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].data_arr_idx = PEX;
+
+	/* PEX_TX_CONFIG_SEQ1 sequence init */
+	serdes_seq_db[PEX_TX_CONFIG_SEQ1].op_params_ptr =
+	    pex_and_usb3_tx_config_params1;
+	serdes_seq_db[PEX_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[PEX_TX_CONFIG_SEQ1].data_arr_idx = PEX;
+
+	/* PEX_TX_CONFIG_SEQ2 sequence init */
+	serdes_seq_db[PEX_TX_CONFIG_SEQ2].op_params_ptr =
+	    pex_and_usb3_tx_config_params2;
+	serdes_seq_db[PEX_TX_CONFIG_SEQ2].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params);
+	serdes_seq_db[PEX_TX_CONFIG_SEQ2].data_arr_idx = PEX;
+
+	/* PEX_TX_CONFIG_SEQ3 sequence init */
+	serdes_seq_db[PEX_TX_CONFIG_SEQ3].op_params_ptr =
+	    pex_and_usb3_tx_config_params3;
+	serdes_seq_db[PEX_TX_CONFIG_SEQ3].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params);
+	serdes_seq_db[PEX_TX_CONFIG_SEQ3].data_arr_idx = PEX;
+
+	/* PEX_BY_4_CONFIG_SEQ sequence init */
+	serdes_seq_db[PEX_BY_4_CONFIG_SEQ].op_params_ptr =
+	    pex_by4_config_params;
+	serdes_seq_db[PEX_BY_4_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_by4_config_params) / sizeof(struct op_params);
+	serdes_seq_db[PEX_BY_4_CONFIG_SEQ].data_arr_idx = PEX;
+
+	/* PEX_CONFIG_REF_CLOCK_25MHZ_SEQ sequence init */
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].op_params_ptr =
+	    pex_config_ref_clock25_m_hz;
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].cfg_seq_size =
+	    sizeof(pex_config_ref_clock25_m_hz) / sizeof(struct op_params);
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].data_arr_idx = PEX;
+
+	/* PEX_ELECTRICAL_CONFIG_REF_CLOCK_40MHZ_SEQ sequence init */
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].op_params_ptr =
+	    pex_config_ref_clock40_m_hz;
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].cfg_seq_size =
+	    sizeof(pex_config_ref_clock40_m_hz) / sizeof(struct op_params);
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].data_arr_idx = PEX;
+
+	/* PEX_CONFIG_REF_CLOCK_100MHZ_SEQ sequence init */
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].op_params_ptr =
+	    pex_config_ref_clock100_m_hz;
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].cfg_seq_size =
+	    sizeof(pex_config_ref_clock100_m_hz) / sizeof(struct op_params);
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].data_arr_idx = PEX;
+
+	/* USB3_POWER_UP_SEQ sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev1_params;
+		serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev2_params;
+		serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[USB3_POWER_UP_SEQ].data_arr_idx = USB3;
+
+	/* USB3_HOST_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].data_arr_idx =
+	    USB3SERDES_SPEED_5_GBPS_HOST;
+
+	/* USB3_DEVICE_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].data_arr_idx =
+	    USB3SERDES_SPEED_5_GBPS_DEVICE;
+
+	/* USB3_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    usb3_electrical_config_serdes_rev1_params;
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(usb3_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    usb3_electrical_config_serdes_rev2_params;
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(usb3_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].data_arr_idx = USB3;
+
+	/* USB3_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_TX_CONFIG_SEQ1].op_params_ptr =
+	    pex_and_usb3_tx_config_params1;
+	serdes_seq_db[USB3_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[USB3_TX_CONFIG_SEQ1].data_arr_idx = USB3;
+
+	/* USB3_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_TX_CONFIG_SEQ2].op_params_ptr =
+	    pex_and_usb3_tx_config_params2;
+	serdes_seq_db[USB3_TX_CONFIG_SEQ2].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params);
+	serdes_seq_db[USB3_TX_CONFIG_SEQ2].data_arr_idx = USB3;
+
+	/* USB3_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_TX_CONFIG_SEQ3].op_params_ptr =
+	    pex_and_usb3_tx_config_params3;
+	serdes_seq_db[USB3_TX_CONFIG_SEQ3].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params);
+	serdes_seq_db[USB3_TX_CONFIG_SEQ3].data_arr_idx = USB3;
+
+	/* USB2_POWER_UP_SEQ sequence init */
+	serdes_seq_db[USB2_POWER_UP_SEQ].op_params_ptr = usb2_power_up_params;
+	serdes_seq_db[USB2_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(usb2_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[USB2_POWER_UP_SEQ].data_arr_idx = 0;
+
+	/* USB3_DEVICE_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].op_params_ptr =
+	    usb3_device_config_params;
+	serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(usb3_device_config_params) / sizeof(struct op_params);
+	serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].data_arr_idx = 0;	/* Not relevant */
+
+	/* SERDES_POWER_DOWN_SEQ sequence init */
+	serdes_seq_db[SERDES_POWER_DOWN_SEQ].op_params_ptr =
+	    serdes_power_down_params;
+	serdes_seq_db[SERDES_POWER_DOWN_SEQ].cfg_seq_size =
+	    sizeof(serdes_power_down_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SERDES_POWER_DOWN_SEQ].data_arr_idx = FIRST_CELL;
+
+	if (serdes_rev == MV_SERDES_REV_2_1) {
+		/* QSGMII_POWER_UP_SEQ sequence init */
+		serdes_seq_db[QSGMII_POWER_UP_SEQ].op_params_ptr =
+		    qsgmii_port_power_up_params;
+		serdes_seq_db[QSGMII_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(qsgmii_port_power_up_params) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_POWER_UP_SEQ].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_5_SPEED_CONFIG_SEQ sequence init */
+		serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].op_params_ptr =
+		    qsgmii_port_speed_config_params;
+		serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(qsgmii_port_speed_config_params) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */
+		serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    qsgmii_port_electrical_config_params;
+		serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(qsgmii_port_electrical_config_params) /
+		    sizeof(struct op_params);
+		serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_TX_CONFIG_SEQ sequence init */
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].op_params_ptr =
+		    qsgmii_port_tx_config_params1;
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].cfg_seq_size =
+		    sizeof(qsgmii_port_tx_config_params1) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_TX_CONFIG_SEQ sequence init */
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].op_params_ptr =
+		    qsgmii_port_tx_config_params2;
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(qsgmii_port_tx_config_params2) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+	}
+
+	return MV_OK;
+}
+
+enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type,
+					      enum serdes_speed baud_rate)
+{
+	enum serdes_seq seq_id = SERDES_LAST_SEQ;
+
+	DEBUG_INIT_FULL_S("\n### serdes_type_and_speed_to_speed_seq ###\n");
+	switch (serdes_type) {
+	case PEX0:
+	case PEX1:
+	case PEX2:
+	case PEX3:
+		if (baud_rate == SERDES_SPEED_2_5_GBPS)
+			seq_id = PEX_2_5_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_5_GBPS)
+			seq_id = PEX_5_SPEED_CONFIG_SEQ;
+		break;
+	case USB3_HOST0:
+	case USB3_HOST1:
+		if (baud_rate == SERDES_SPEED_5_GBPS)
+			seq_id = USB3_HOST_SPEED_CONFIG_SEQ;
+		break;
+	case USB3_DEVICE:
+		if (baud_rate == SERDES_SPEED_5_GBPS)
+			seq_id = USB3_DEVICE_SPEED_CONFIG_SEQ;
+		break;
+	case SATA0:
+	case SATA1:
+	case SATA2:
+	case SATA3:
+		if (baud_rate == SERDES_SPEED_1_5_GBPS)
+			seq_id = SATA_1_5_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_3_GBPS)
+			seq_id = SATA_3_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_6_GBPS)
+			seq_id = SATA_6_SPEED_CONFIG_SEQ;
+		break;
+	case SGMII0:
+	case SGMII1:
+	case SGMII2:
+#ifdef CONFIG_ARMADA_39X
+	case SGMII3:
+#endif
+		if (baud_rate == SERDES_SPEED_1_25_GBPS)
+			seq_id = SGMII_1_25_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_3_125_GBPS)
+			seq_id = SGMII_3_125_SPEED_CONFIG_SEQ;
+		break;
+	case QSGMII:
+		seq_id = QSGMII_5_SPEED_CONFIG_SEQ;
+		break;
+#ifdef CONFIG_ARMADA_39X
+	case XAUI:
+		seq_id = XAUI_3_125_SPEED_CONFIG_SEQ;
+		break;
+	case RXAUI:
+		seq_id = RXAUI_6_25_SPEED_CONFIG_SEQ;
+		break;
+#endif
+	default:
+		return SERDES_LAST_SEQ;
+	}
+
+	return seq_id;
+}
+
+/*
+ * This is the weak default function for the Marvell evaluation or
+ * development boarrds. Like the DB-88F6820-GP and others.
+ * Custom boards should define this function in their board
+ * code (board directory). And overwrite this default function
+ * with this custom specific code.
+ */
+__weak int hws_board_topology_load(struct serdes_map *serdes_map_array)
+{
+	u32 board_id = mv_board_id_get();
+	u32 board_id_index = mv_board_id_index_get(board_id);
+
+	DEBUG_INIT_FULL_S("\n### hws_board_topology_load ###\n");
+	/* getting board topology according to the board id */
+	DEBUG_INIT_FULL_S("Getting board topology according to the board id\n");
+
+	CHECK_STATUS(load_topology_func_arr[board_id_index] (serdes_map_array));
+
+	return MV_OK;
+}
+
+void print_topology_details(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+
+	DEBUG_INIT_S("board SerDes lanes topology details:\n");
+
+	DEBUG_INIT_S(" | Lane #  | Speed |  Type       |\n");
+	DEBUG_INIT_S(" --------------------------------\n");
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		if (serdes_map_array[lane_num].serdes_type == DEFAULT_SERDES)
+			continue;
+		DEBUG_INIT_S(" |   ");
+		DEBUG_INIT_D(hws_get_physical_serdes_num(lane_num), 1);
+		DEBUG_INIT_S("    |  ");
+		DEBUG_INIT_D(serdes_map_array[lane_num].serdes_speed, 2);
+		DEBUG_INIT_S("   |  ");
+		DEBUG_INIT_S((char *)
+			     serdes_type_to_string[serdes_map_array[lane_num].
+						   serdes_type]);
+		DEBUG_INIT_S("\t|\n");
+	}
+	DEBUG_INIT_S(" --------------------------------\n");
+}
+
+int hws_pre_serdes_init_config(void)
+{
+	u32 data;
+
+	/*
+	 * Configure Core PLL
+	 */
+	/*
+	 * set PLL parameters
+	 * bits[2:0]  =0x3 (Core-PLL Kdiv)
+	 * bits[20:12]=0x9f (Core-PLL Ndiv)
+	 * bits[24:21]=0x7(Core-PLL VCO Band)
+	 * bits[28:25]=0x1(Core-PLL Rlf)
+	 * bits[31:29]=0x2(Core-PLL charge-pump adjust)
+	 */
+	reg_write(CORE_PLL_PARAMETERS_REG, 0x42e9f003);
+
+	/* Enable PLL Configuration */
+	data = reg_read(CORE_PLL_CONFIG_REG);
+	data = SET_BIT(data, 9);
+	reg_write(CORE_PLL_CONFIG_REG, data);
+
+	return MV_OK;
+}
+
+int serdes_phy_config(void)
+{
+	DEBUG_INIT_FULL_S("\n### ctrl_high_speed_serdes_phy_config ###\n");
+
+	DEBUG_INIT_S("High speed PHY - Version: ");
+	DEBUG_INIT_S(SERDES_VERION);
+	DEBUG_INIT_S("\n");
+
+	/* Init serdes sequences DB */
+	if (hws_serdes_seq_init() != MV_OK) {
+		printf("hws_ctrl_high_speed_serdes_phy_config: Error: Serdes initialization fail\n");
+		return MV_FAIL;
+	}
+
+	/* I2C init */
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	/* Board topology load */
+	DEBUG_INIT_FULL_S
+	    ("ctrl_high_speed_serdes_phy_config: Loading board topology..\n");
+	CHECK_STATUS(hws_board_topology_load(serdes_configuration_map));
+
+	/* print topology */
+	print_topology_details(serdes_configuration_map);
+	CHECK_STATUS(hws_pre_serdes_init_config());
+
+	/* Power-Up sequence */
+	DEBUG_INIT_FULL_S
+		("ctrl_high_speed_serdes_phy_config: Starting serdes power up sequence\n");
+
+	CHECK_STATUS(hws_power_up_serdes_lanes(serdes_configuration_map));
+
+	DEBUG_INIT_FULL_S
+		("\n### ctrl_high_speed_serdes_phy_config ended successfully ###\n");
+
+	DEBUG_INIT_S(ENDED_OK);
+
+	return MV_OK;
+}
+
+int serdes_polarity_config(u32 serdes_num, int is_rx)
+{
+	u32 data;
+	u32 reg_addr;
+	u8 bit_off = (is_rx) ? 11 : 10;
+
+	reg_addr = SERDES_REGS_LANE_BASE_OFFSET(serdes_num) + SYNC_PATTERN_REG;
+	data = reg_read(reg_addr);
+	data = SET_BIT(data, bit_off);
+	reg_write(reg_addr, data);
+
+	return MV_OK;
+}
+
+int hws_power_up_serdes_lanes(struct serdes_map *serdes_config_map)
+{
+	u32 serdes_id, serdes_lane_num;
+	enum ref_clock ref_clock;
+	enum serdes_type serdes_type;
+	enum serdes_speed serdes_speed;
+	enum serdes_mode serdes_mode;
+	int serdes_rx_polarity_swap;
+	int serdes_tx_polarity_swap;
+	int is_pex_enabled = 0;
+
+	/*
+	 * is_pex_enabled:
+	 * Flag which indicates that one of the Serdes is of PEX.
+	 * In this case, PEX unit will be initialized after Serdes power-up
+	 */
+
+	DEBUG_INIT_FULL_S("\n### hws_power_up_serdes_lanes ###\n");
+
+	/* COMMON PHYS SELECTORS register configuration */
+	DEBUG_INIT_FULL_S
+	    ("hws_power_up_serdes_lanes: Updating COMMON PHYS SELECTORS reg\n");
+	CHECK_STATUS(hws_update_serdes_phy_selectors(serdes_configuration_map));
+
+	/* per Serdes Power Up */
+	for (serdes_id = 0; serdes_id < hws_serdes_get_max_lane();
+	     serdes_id++) {
+		DEBUG_INIT_FULL_S
+		    ("calling serdes_power_up_ctrl: serdes lane number ");
+		DEBUG_INIT_FULL_D_10(serdes_lane_num, 1);
+		DEBUG_INIT_FULL_S("\n");
+
+		serdes_lane_num = hws_get_physical_serdes_num(serdes_id);
+		serdes_type = serdes_config_map[serdes_id].serdes_type;
+		serdes_speed = serdes_config_map[serdes_id].serdes_speed;
+		serdes_mode = serdes_config_map[serdes_id].serdes_mode;
+		serdes_rx_polarity_swap = serdes_config_map[serdes_id].swap_rx;
+		serdes_tx_polarity_swap = serdes_config_map[serdes_id].swap_tx;
+
+		/* serdes lane is not in use */
+		if (serdes_type == DEFAULT_SERDES)
+			continue;
+		else if (serdes_type <= PEX3)	/* PEX type */
+			is_pex_enabled = 1;
+
+		ref_clock = hws_serdes_get_ref_clock_val(serdes_type);
+		if (ref_clock == REF_CLOCK_UNSUPPORTED) {
+			DEBUG_INIT_S
+			    ("hws_power_up_serdes_lanes: unsupported ref clock\n");
+			return MV_NOT_SUPPORTED;
+		}
+		CHECK_STATUS(serdes_power_up_ctrl(serdes_lane_num,
+						  1,
+						  serdes_type,
+						  serdes_speed,
+						  serdes_mode, ref_clock));
+
+		/* RX Polarity config */
+		if (serdes_rx_polarity_swap)
+			CHECK_STATUS(serdes_polarity_config
+				     (serdes_lane_num, 1));
+
+		/* TX Polarity config */
+		if (serdes_tx_polarity_swap)
+			CHECK_STATUS(serdes_polarity_config
+				     (serdes_lane_num, 0));
+	}
+
+	if (is_pex_enabled) {
+		/* Set PEX_TX_CONFIG_SEQ sequence for PEXx4 mode.
+		   After finish the Power_up sequence for all lanes,
+		   the lanes should be released from reset state.       */
+		CHECK_STATUS(hws_pex_tx_config_seq(serdes_config_map));
+
+		/* PEX configuration */
+		CHECK_STATUS(hws_pex_config(serdes_config_map));
+	}
+
+	/* USB2 configuration */
+	DEBUG_INIT_FULL_S("hws_power_up_serdes_lanes: init USB2 Phys\n");
+	CHECK_STATUS(mv_seq_exec(0 /* not relevant */ , USB2_POWER_UP_SEQ));
+
+	DEBUG_INIT_FULL_S
+	    ("### hws_power_up_serdes_lanes ended successfully ###\n");
+
+	return MV_OK;
+}
+
+int ctrl_high_speed_serdes_phy_config(void)
+{
+	return hws_ctrl_high_speed_serdes_phy_config();
+}
+
+static int serdes_pex_usb3_pipe_delay_w_a(u32 serdes_num, u8 serdes_type)
+{
+	u32 reg_data;
+
+	/* WA for A380 Z1 relevant for lanes 3,4,5 only */
+	if (serdes_num >= 3) {
+		reg_data = reg_read(GENERAL_PURPOSE_RESERVED0_REG);
+		/* set delay on pipe -
+		 * When lane 3 is connected to a MAC of Pex -> set bit 7 to 1.
+		 * When lane 3 is connected to a MAC of USB3 -> set bit 7 to 0.
+		 * When lane 4 is connected to a MAC of Pex -> set bit 8 to 1.
+		 * When lane 4 is connected to a MAC of USB3 -> set bit 8 to 0.
+		 * When lane 5 is connected to a MAC of Pex -> set bit 8 to 1.
+		 * When lane 5 is connected to a MAC of USB3 -> set bit 8 to 0.
+		 */
+		if (serdes_type == PEX)
+			reg_data |= 1 << (7 + (serdes_num - 3));
+		if (serdes_type == USB3) {
+			/* USB3 */
+			reg_data &= ~(1 << (7 + (serdes_num - 3)));
+		}
+		reg_write(GENERAL_PURPOSE_RESERVED0_REG, reg_data);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * hws_serdes_pex_ref_clock_satr_get -
+ *
+ * DESCRIPTION: Get the reference clock value from DEVICE_SAMPLE_AT_RESET1_REG
+ *              and check:
+ *              bit[2] for PEX#0, bit[3] for PEX#1, bit[30] for PEX#2, bit[31]
+ *              for PEX#3.
+ *              If bit=0 --> REF_CLOCK_100MHz
+ *              If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=0
+ *              --> REF_CLOCK_25MHz
+ *              If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=1
+ *              --> REF_CLOCK_40MHz
+ *
+ * INPUT:        serdes_type - Type of Serdes
+ *
+ * OUTPUT:       pex_satr   -  Return the REF_CLOCK value:
+ *                            REF_CLOCK_25MHz, REF_CLOCK_40MHz or REF_CLOCK_100MHz
+ *
+ * RETURNS:      MV_OK        - for success
+ *               MV_BAD_PARAM - for fail
+ */
+int hws_serdes_pex_ref_clock_satr_get(enum serdes_type serdes_type, u32 *pex_satr)
+{
+	u32 data, reg_satr1;
+
+	reg_satr1 = reg_read(DEVICE_SAMPLE_AT_RESET1_REG);
+
+	switch (serdes_type) {
+	case PEX0:
+		data = REF_CLK_SELECTOR_VAL_PEX0(reg_satr1);
+		break;
+	case PEX1:
+		data = REF_CLK_SELECTOR_VAL_PEX1(reg_satr1);
+		break;
+	case PEX2:
+		data = REF_CLK_SELECTOR_VAL_PEX2(reg_satr1);
+		break;
+	case PEX3:
+		data = REF_CLK_SELECTOR_VAL_PEX3(reg_satr1);
+		break;
+	default:
+		printf("%s: Error: SerDes type %d is not supported\n",
+		       __func__, serdes_type);
+		return MV_BAD_PARAM;
+	}
+
+	*pex_satr = data;
+
+	return MV_OK;
+}
+
+u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type)
+{
+	u32 pex_satr;
+	enum ref_clock ref_clock;
+
+	DEBUG_INIT_FULL_S("\n### hws_serdes_get_ref_clock_val ###\n");
+
+	if (serdes_type >= LAST_SERDES_TYPE)
+		return REF_CLOCK_UNSUPPORTED;
+
+	/* read ref clock from S@R */
+	ref_clock = hws_serdes_silicon_ref_clock_get();
+
+	if (serdes_type > PEX3) {
+		/* for all Serdes types but PCIe */
+		return ref_clock;
+	}
+
+	/* for PCIe, need also to check PCIe S@R */
+	CHECK_STATUS(hws_serdes_pex_ref_clock_satr_get
+		     (serdes_type, &pex_satr));
+
+	if (pex_satr == 0) {
+		return REF_CLOCK_100MHZ;
+	} else if (pex_satr == 1) {
+		/* value of 1 means we can use ref clock from SoC (as other Serdes types) */
+		return ref_clock;
+	} else {
+		printf
+		    ("%s: Error: REF_CLK_SELECTOR_VAL for SerDes type %d is wrong\n",
+		     __func__, serdes_type);
+		return REF_CLOCK_UNSUPPORTED;
+	}
+}
+
+int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up,
+			 enum serdes_type serdes_type,
+			 enum serdes_speed baud_rate,
+			 enum serdes_mode serdes_mode, enum ref_clock ref_clock)
+{
+	u32 sata_idx, pex_idx, sata_port;
+	enum serdes_seq speed_seq_id;
+	u32 reg_data;
+	int is_pex_by1;
+
+	DEBUG_INIT_FULL_S("\n### serdes_power_up_ctrl ###\n");
+
+	if (serdes_power_up == 1) {	/* Serdes power up */
+		DEBUG_INIT_FULL_S
+		    ("serdes_power_up_ctrl: executing power up.. ");
+		DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 2);
+		DEBUG_INIT_FULL_C("serdes type = ", serdes_type, 2);
+
+		DEBUG_INIT_FULL_S("Going access 1");
+
+		/* Getting the Speed Select sequence id */
+		speed_seq_id =
+			serdes_type_and_speed_to_speed_seq(serdes_type,
+							   baud_rate);
+		if (speed_seq_id == SERDES_LAST_SEQ) {
+			printf
+			    ("serdes_power_up_ctrl: serdes type %d and speed %d are not supported together\n",
+			     serdes_type, baud_rate);
+
+			return MV_BAD_PARAM;
+		}
+
+		/* Executing power up, ref clock set, speed config and TX config */
+		switch (serdes_type) {
+		case PEX0:
+		case PEX1:
+		case PEX2:
+		case PEX3:
+			if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+				CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a
+					     (serdes_num, PEX));
+			}
+
+			is_pex_by1 = (serdes_mode == PEX_ROOT_COMPLEX_X1) ||
+				(serdes_mode == PEX_END_POINT_X1);
+			pex_idx = serdes_type - PEX0;
+
+			if ((is_pex_by1 == 1) || (serdes_type == PEX0)) {
+				/* For PEX by 4, init only the PEX 0 */
+				reg_data = reg_read(SOC_CONTROL_REG1);
+				if (is_pex_by1 == 1)
+					reg_data |= 0x4000;
+				else
+					reg_data &= ~0x4000;
+				reg_write(SOC_CONTROL_REG1, reg_data);
+
+				reg_data =
+				    reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+					      0x6c));
+				reg_data &= ~0x3f0;
+				if (is_pex_by1 == 1)
+					reg_data |= 0x10;
+				else
+					reg_data |= 0x40;
+				reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c),
+					  reg_data);
+
+				reg_data =
+				    reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+					      0x6c));
+				reg_data &= ~0xf;
+				reg_data |= 0x2;
+				reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c),
+					  reg_data);
+
+				reg_data =
+				    reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+					      0x70));
+				reg_data &= ~0x40;
+				reg_data |= 0x40;
+				reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x70),
+					  reg_data);
+			}
+
+			CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ));
+			if (is_pex_by1 == 0) {
+				/*
+				 * for PEX by 4 - use the PEX index as the
+				 * seq array index
+				 */
+				serdes_seq_db[PEX_BY_4_CONFIG_SEQ].
+				    data_arr_idx = pex_idx;
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_BY_4_CONFIG_SEQ));
+			}
+
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, PEX_ELECTRICAL_CONFIG_SEQ));
+
+			if (is_pex_by1 == 1) {
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_TX_CONFIG_SEQ2));
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_TX_CONFIG_SEQ3));
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_TX_CONFIG_SEQ1));
+			}
+			udelay(20);
+
+			break;
+		case USB3_HOST0:
+		case USB3_HOST1:
+		case USB3_DEVICE:
+			if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+				CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a
+					     (serdes_num, USB3));
+			}
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			if (serdes_type == USB3_DEVICE) {
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num,
+					      USB3_DEVICE_CONFIG_SEQ));
+			}
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_TX_CONFIG_SEQ2));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_TX_CONFIG_SEQ3));
+
+			udelay(10000);
+			break;
+		case SATA0:
+		case SATA1:
+		case SATA2:
+		case SATA3:
+			sata_idx = ((serdes_type == SATA0) ||
+				    (serdes_type == SATA1)) ? 0 : 1;
+			sata_port = ((serdes_type == SATA0) ||
+				     (serdes_type == SATA2)) ? 0 : 1;
+
+			CHECK_STATUS(mv_seq_exec
+				     (sata_idx, (sata_port == 0) ?
+				      SATA_PORT_0_ONLY_POWER_UP_SEQ :
+				      SATA_PORT_1_ONLY_POWER_UP_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (sata_idx, (sata_port == 0) ?
+				      SATA_PORT_0_ONLY_TX_CONFIG_SEQ :
+				      SATA_PORT_1_ONLY_TX_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_TX_CONFIG_SEQ2));
+
+			udelay(10000);
+			break;
+		case SGMII0:
+		case SGMII1:
+		case SGMII2:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_TX_CONFIG_SEQ2));
+
+			/* GBE configuration */
+			reg_data = reg_read(GBE_CONFIGURATION_REG);
+			/* write the SGMII index */
+			reg_data |= 0x1 << (serdes_type - SGMII0);
+			reg_write(GBE_CONFIGURATION_REG, reg_data);
+
+			break;
+		case QSGMII:
+			if (hws_ctrl_serdes_rev_get() < MV_SERDES_REV_2_1)
+				return MV_NOT_SUPPORTED;
+
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, QSGMII_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      QSGMII_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, QSGMII_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, QSGMII_TX_CONFIG_SEQ2));
+			break;
+		case SGMII3:
+		case XAUI:
+		case RXAUI:
+			CHECK_STATUS(serdes_power_up_ctrl_ext
+				     (serdes_num, serdes_power_up, serdes_type,
+				      baud_rate, serdes_mode, ref_clock));
+			break;
+		default:
+			DEBUG_INIT_S
+			    ("serdes_power_up_ctrl: bad serdes_type parameter\n");
+			return MV_BAD_PARAM;
+		}
+	} else {		/* Serdes power down */
+		DEBUG_INIT_FULL_S("serdes_power_up: executing power down.. ");
+		DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 1);
+
+		CHECK_STATUS(mv_seq_exec(serdes_num, SERDES_POWER_DOWN_SEQ));
+	}
+
+	DEBUG_INIT_FULL_C(
+		"serdes_power_up_ctrl ended successfully for serdes ",
+		serdes_num, 2);
+
+	return MV_OK;
+}
+
+int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map)
+{
+	u32 lane_data, idx, serdes_lane_hw_num, reg_data = 0;
+	enum serdes_type serdes_type;
+	enum serdes_mode serdes_mode;
+	u8 select_bit_off;
+	int is_pex_x4 = 0;
+	int updated_topology_print = 0;
+
+	DEBUG_INIT_FULL_S("\n### hws_update_serdes_phy_selectors ###\n");
+	DEBUG_INIT_FULL_S
+	    ("Updating the COMMON PHYS SELECTORS register with the serdes types\n");
+
+	if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2)
+		select_bit_off = 3;
+	else
+		select_bit_off = 4;
+
+	/*
+	 * Updating bits 0-17 in the COMMON PHYS SELECTORS register
+	 * according to the serdes types
+	 */
+	for (idx = 0; idx < hws_serdes_get_max_lane();
+	     idx++) {
+		serdes_type = serdes_config_map[idx].serdes_type;
+		serdes_mode = serdes_config_map[idx].serdes_mode;
+		serdes_lane_hw_num = hws_get_physical_serdes_num(idx);
+
+		lane_data =
+		    hws_serdes_get_phy_selector_val(serdes_lane_hw_num,
+						    serdes_type);
+
+		if (serdes_type == DEFAULT_SERDES)
+			continue;
+
+		if (hws_serdes_topology_verify
+		    (serdes_type, idx, serdes_mode) != MV_OK) {
+			serdes_config_map[idx].serdes_type =
+			    DEFAULT_SERDES;
+			printf("%s: SerDes lane #%d is  disabled\n", __func__,
+			       serdes_lane_hw_num);
+			updated_topology_print = 1;
+			continue;
+		}
+
+		/*
+		 * Checking if the board topology configuration includes
+		 * PEXx4 - for the next step
+		 */
+		if ((serdes_mode == PEX_END_POINT_X4) ||
+		    (serdes_mode == PEX_ROOT_COMPLEX_X4)) {
+			/* update lane data to the 3 next SERDES lanes */
+			lane_data =
+			    common_phys_selectors_pex_by4_lanes
+			    [serdes_lane_hw_num];
+			if (serdes_type == PEX0)
+				is_pex_x4 = 1;
+		}
+
+		if (lane_data == NA) {
+			printf
+			    ("%s: Warning: SerDes lane #%d and type %d are not supported together\n",
+			     __func__, serdes_lane_hw_num, serdes_mode);
+			serdes_config_map[idx].serdes_type =
+				DEFAULT_SERDES;
+			printf("%s: SerDes lane #%d is  disabled\n", __func__,
+			       serdes_lane_hw_num);
+			continue;
+		}
+
+		/*
+		 * Updating the data that will be written to
+		 * COMMON_PHYS_SELECTORS_REG
+		 */
+		reg_data |= (lane_data <<
+			     (select_bit_off * serdes_lane_hw_num));
+	}
+
+	/*
+	 * Check that number of used lanes for XAUI and RXAUI
+	 * (if used) is right
+	 */
+	hws_serdes_xaui_topology_verify();
+
+	/* Print topology */
+	if (updated_topology_print)
+		print_topology_details(serdes_config_map);
+
+	/*
+	 * Updating the PEXx4 Enable bit in the COMMON PHYS SELECTORS
+	 * register for PEXx4 mode
+	 */
+	reg_data |= (is_pex_x4 == 1) ? (0x1 << PEX_X4_ENABLE_OFFS) : 0;
+
+	/* Updating the COMMON PHYS SELECTORS register */
+	reg_write(COMMON_PHYS_SELECTORS_REG, reg_data);
+
+	return MV_OK;
+}
+
+int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type,
+		      enum ref_clock ref_clock)
+{
+	u32 data1 = 0, data2 = 0, data3 = 0, reg_data;
+
+	DEBUG_INIT_FULL_S("\n### hws_ref_clock_set ###\n");
+
+	if (hws_is_serdes_active(serdes_num) != 1) {
+		printf("%s: SerDes lane #%d is not Active\n", __func__,
+		       serdes_num);
+		return MV_BAD_PARAM;
+	}
+
+	switch (serdes_type) {
+	case PEX0:
+	case PEX1:
+	case PEX2:
+	case PEX3:
+		switch (ref_clock) {
+		case REF_CLOCK_25MHZ:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      PEX_CONFIG_REF_CLOCK_25MHZ_SEQ));
+			return MV_OK;
+		case REF_CLOCK_100MHZ:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      PEX_CONFIG_REF_CLOCK_100MHZ_SEQ));
+			return MV_OK;
+#ifdef CONFIG_ARMADA_39X
+		case REF_CLOCK_40MHZ:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      PEX_CONFIG_REF_CLOCK_40MHZ_SEQ));
+			return MV_OK;
+#endif
+		default:
+			printf
+			    ("%s: Error: ref_clock %d for SerDes lane #%d, type %d is not supported\n",
+			     __func__, ref_clock, serdes_num, serdes_type);
+			return MV_BAD_PARAM;
+		}
+	case USB3_HOST0:
+	case USB3_HOST1:
+	case USB3_DEVICE:
+		if (ref_clock == REF_CLOCK_25MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2;
+			data2 = GLOBAL_PM_CTRL_REG_25MHZ_VAL;
+			data3 = LANE_CFG4_REG_25MHZ_VAL;
+		} else if (ref_clock == REF_CLOCK_40MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+			data2 = GLOBAL_PM_CTRL_REG_40MHZ_VAL;
+			data3 = LANE_CFG4_REG_40MHZ_VAL;
+		} else {
+			printf
+			    ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+			     serdes_type);
+			return MV_BAD_PARAM;
+		}
+		break;
+	case SATA0:
+	case SATA1:
+	case SATA2:
+	case SATA3:
+	case SGMII0:
+	case SGMII1:
+	case SGMII2:
+	case QSGMII:
+		if (ref_clock == REF_CLOCK_25MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1;
+		} else if (ref_clock == REF_CLOCK_40MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+		} else {
+			printf
+			    ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+			     serdes_type);
+			return MV_BAD_PARAM;
+		}
+		break;
+#ifdef CONFIG_ARMADA_39X
+	case SGMII3:
+	case XAUI:
+	case RXAUI:
+		if (ref_clock == REF_CLOCK_25MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1;
+		} else if (ref_clock == REF_CLOCK_40MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+		} else {
+			printf
+			    ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+			     serdes_type);
+			return MV_BAD_PARAM;
+		}
+		break;
+#endif
+	default:
+		DEBUG_INIT_S("hws_ref_clock_set: not supported serdes type\n");
+		return MV_BAD_PARAM;
+	}
+
+	/*
+	 * Write the ref_clock to relevant SELECT_REF_CLOCK_REG bits and
+	 * offset
+	 */
+	reg_data = reg_read(POWER_AND_PLL_CTRL_REG +
+			    SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+	reg_data &= POWER_AND_PLL_CTRL_REG_MASK;
+	reg_data |= data1;
+	reg_write(POWER_AND_PLL_CTRL_REG +
+		  SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+
+	if ((serdes_type == USB3_HOST0) || (serdes_type == USB3_HOST1) ||
+	    (serdes_type == USB3_DEVICE)) {
+		reg_data = reg_read(GLOBAL_PM_CTRL +
+				    SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+		reg_data &= GLOBAL_PM_CTRL_REG_MASK;
+		reg_data |= data2;
+		reg_write(GLOBAL_PM_CTRL +
+			  SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+
+		reg_data = reg_read(LANE_CFG4_REG +
+				    SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+		reg_data &= LANE_CFG4_REG_MASK;
+		reg_data |= data3;
+		reg_write(LANE_CFG4_REG +
+			  SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * hws_pex_tx_config_seq -
+ *
+ * DESCRIPTION:          Set PEX_TX_CONFIG_SEQ sequence init for PEXx4 mode
+ * INPUT:                serdes_map       - The board topology map
+ * OUTPUT:               None
+ * RETURNS:              MV_OK           - for success
+ *                       MV_BAD_PARAM    - for fail
+ */
+int hws_pex_tx_config_seq(struct serdes_map *serdes_map)
+{
+	enum serdes_mode serdes_mode;
+	u32 serdes_lane_id, serdes_lane_hw_num;
+
+	DEBUG_INIT_FULL_S("\n### hws_pex_tx_config_seq ###\n");
+
+	/*
+	 * For PEXx4: the pex_and_usb3_tx_config_params1/2/3
+	 * configurations should run by setting each sequence for
+	 * all 4 lanes.
+	 */
+
+	/* relese pipe soft reset for all lanes */
+	for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+	     serdes_lane_id++) {
+		serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+		serdes_lane_hw_num =
+		    hws_get_physical_serdes_num(serdes_lane_id);
+
+		if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		    (serdes_mode == PEX_END_POINT_X4)) {
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ1));
+		}
+	}
+
+	/* set phy soft reset for all lanes */
+	for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+	     serdes_lane_id++) {
+		serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+		serdes_lane_hw_num =
+		    hws_get_physical_serdes_num(serdes_lane_id);
+		if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		    (serdes_mode == PEX_END_POINT_X4)) {
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ2));
+		}
+	}
+
+	/* set phy soft reset for all lanes */
+	for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+	     serdes_lane_id++) {
+		serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+		serdes_lane_hw_num =
+		    hws_get_physical_serdes_num(serdes_lane_id);
+		if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		    (serdes_mode == PEX_END_POINT_X4)) {
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ3));
+		}
+	}
+
+	return MV_OK;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
new file mode 100644
index 0000000..2508721
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _HIGH_SPEED_ENV_SPEC_H
+#define _HIGH_SPEED_ENV_SPEC_H
+
+#include "seq_exec.h"
+
+/*
+ * For setting or clearing a certain bit (bit is a number between 0 and 31)
+ * in the data
+ */
+#define SET_BIT(data, bit)		((data) | (0x1 << (bit)))
+#define CLEAR_BIT(data, bit)		((data) & (~(0x1 << (bit))))
+
+#define MAX_SERDES_LANES		7	/* as in a39x */
+
+/* Serdes revision */
+/* Serdes revision 1.2 (for A38x-Z1) */
+#define MV_SERDES_REV_1_2		0x0
+/* Serdes revision 2.1 (for A39x-Z1, A38x-A0) */
+#define MV_SERDES_REV_2_1		0x1
+#define MV_SERDES_REV_NA		0xff
+
+#define	SERDES_REGS_LANE_BASE_OFFSET(lane)	(0x800 * (lane))
+
+#define PEX_X4_ENABLE_OFFS						\
+	(hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2 ? 18 : 31)
+
+/* Serdes lane types */
+enum serdes_type {
+	PEX0,
+	PEX1,
+	PEX2,
+	PEX3,
+	SATA0,
+	SATA1,
+	SATA2,
+	SATA3,
+	SGMII0,
+	SGMII1,
+	SGMII2,
+	QSGMII,
+	USB3_HOST0,
+	USB3_HOST1,
+	USB3_DEVICE,
+	SGMII3,
+	XAUI,
+	RXAUI,
+	DEFAULT_SERDES,
+	LAST_SERDES_TYPE
+};
+
+/* Serdes baud rates */
+enum serdes_speed {
+	SERDES_SPEED_1_25_GBPS,
+	SERDES_SPEED_1_5_GBPS,
+	SERDES_SPEED_2_5_GBPS,
+	SERDES_SPEED_3_GBPS,
+	SERDES_SPEED_3_125_GBPS,
+	SERDES_SPEED_5_GBPS,
+	SERDES_SPEED_6_GBPS,
+	SERDES_SPEED_6_25_GBPS,
+	LAST_SERDES_SPEED
+};
+
+/* Serdes modes */
+enum serdes_mode {
+	PEX_ROOT_COMPLEX_X1,
+	PEX_ROOT_COMPLEX_X4,
+	PEX_END_POINT_X1,
+	PEX_END_POINT_X4,
+
+	SERDES_DEFAULT_MODE, /* not pex */
+
+	SERDES_LAST_MODE
+};
+
+struct serdes_map {
+	enum serdes_type	serdes_type;
+	enum serdes_speed	serdes_speed;
+	enum serdes_mode	serdes_mode;
+	int			swap_rx;
+	int			swap_tx;
+};
+
+/* Serdes ref clock options */
+enum ref_clock {
+	REF_CLOCK_25MHZ,
+	REF_CLOCK_100MHZ,
+	REF_CLOCK_40MHZ,
+	REF_CLOCK_UNSUPPORTED
+};
+
+/* Serdes sequences */
+enum serdes_seq {
+	SATA_PORT_0_ONLY_POWER_UP_SEQ,
+	SATA_PORT_1_ONLY_POWER_UP_SEQ,
+	SATA_POWER_UP_SEQ,
+	SATA_1_5_SPEED_CONFIG_SEQ,
+	SATA_3_SPEED_CONFIG_SEQ,
+	SATA_6_SPEED_CONFIG_SEQ,
+	SATA_ELECTRICAL_CONFIG_SEQ,
+	SATA_TX_CONFIG_SEQ1,
+	SATA_PORT_0_ONLY_TX_CONFIG_SEQ,
+	SATA_PORT_1_ONLY_TX_CONFIG_SEQ,
+	SATA_TX_CONFIG_SEQ2,
+
+	SGMII_POWER_UP_SEQ,
+	SGMII_1_25_SPEED_CONFIG_SEQ,
+	SGMII_3_125_SPEED_CONFIG_SEQ,
+	SGMII_ELECTRICAL_CONFIG_SEQ,
+	SGMII_TX_CONFIG_SEQ1,
+	SGMII_TX_CONFIG_SEQ2,
+
+	PEX_POWER_UP_SEQ,
+	PEX_2_5_SPEED_CONFIG_SEQ,
+	PEX_5_SPEED_CONFIG_SEQ,
+	PEX_ELECTRICAL_CONFIG_SEQ,
+	PEX_TX_CONFIG_SEQ1,
+	PEX_TX_CONFIG_SEQ2,
+	PEX_TX_CONFIG_SEQ3,
+	PEX_BY_4_CONFIG_SEQ,
+	PEX_CONFIG_REF_CLOCK_25MHZ_SEQ,
+	PEX_CONFIG_REF_CLOCK_100MHZ_SEQ,
+	PEX_CONFIG_REF_CLOCK_40MHZ_SEQ,
+
+	USB3_POWER_UP_SEQ,
+	USB3_HOST_SPEED_CONFIG_SEQ,
+	USB3_DEVICE_SPEED_CONFIG_SEQ,
+	USB3_ELECTRICAL_CONFIG_SEQ,
+	USB3_TX_CONFIG_SEQ1,
+	USB3_TX_CONFIG_SEQ2,
+	USB3_TX_CONFIG_SEQ3,
+	USB3_DEVICE_CONFIG_SEQ,
+
+	USB2_POWER_UP_SEQ,
+
+	SERDES_POWER_DOWN_SEQ,
+
+	SGMII3_POWER_UP_SEQ,
+	SGMII3_1_25_SPEED_CONFIG_SEQ,
+	SGMII3_TX_CONFIG_SEQ1,
+	SGMII3_TX_CONFIG_SEQ2,
+
+	QSGMII_POWER_UP_SEQ,
+	QSGMII_5_SPEED_CONFIG_SEQ,
+	QSGMII_ELECTRICAL_CONFIG_SEQ,
+	QSGMII_TX_CONFIG_SEQ1,
+	QSGMII_TX_CONFIG_SEQ2,
+
+	XAUI_POWER_UP_SEQ,
+	XAUI_3_125_SPEED_CONFIG_SEQ,
+	XAUI_ELECTRICAL_CONFIG_SEQ,
+	XAUI_TX_CONFIG_SEQ1,
+	XAUI_TX_CONFIG_SEQ2,
+
+	RXAUI_POWER_UP_SEQ,
+	RXAUI_6_25_SPEED_CONFIG_SEQ,
+	RXAUI_ELECTRICAL_CONFIG_SEQ,
+	RXAUI_TX_CONFIG_SEQ1,
+	RXAUI_TX_CONFIG_SEQ2,
+
+	SERDES_LAST_SEQ
+};
+
+/* The different sequence types for PEX and USB3 */
+enum {
+	PEX,
+	USB3,
+	LAST_PEX_USB_SEQ_TYPE
+};
+
+enum {
+	PEXSERDES_SPEED_2_5_GBPS,
+	PEXSERDES_SPEED_5_GBPS,
+	USB3SERDES_SPEED_5_GBPS_HOST,
+	USB3SERDES_SPEED_5_GBPS_DEVICE,
+	LAST_PEX_USB_SPEED_SEQ_TYPE
+};
+
+/* The different sequence types for SATA and SGMII */
+enum {
+	SATA,
+	SGMII,
+	SGMII_3_125,
+	LAST_SATA_SGMII_SEQ_TYPE
+};
+
+enum {
+	QSGMII_SEQ_IDX,
+	LAST_QSGMII_SEQ_TYPE
+};
+
+enum {
+	XAUI_SEQ_IDX,
+	RXAUI_SEQ_IDX,
+	LAST_XAUI_RXAUI_SEQ_TYPE
+};
+
+enum {
+	SATASERDES_SPEED_1_5_GBPS,
+	SATASERDES_SPEED_3_GBPS,
+	SATASERDES_SPEED_6_GBPS,
+	SGMIISERDES_SPEED_1_25_GBPS,
+	SGMIISERDES_SPEED_3_125_GBPS,
+	LAST_SATA_SGMII_SPEED_SEQ_TYPE
+};
+
+extern u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES];
+extern u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES];
+
+u8 hws_ctrl_serdes_rev_get(void);
+int mv_update_serdes_select_phy_mode_seq(void);
+int hws_board_topology_load(struct serdes_map *serdes_map_array);
+enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type,
+						   enum serdes_speed baud_rate);
+int hws_serdes_seq_init(void);
+int hws_serdes_seq_db_init(void);
+int hws_power_up_serdes_lanes(struct serdes_map *serdes_config_map);
+int hws_ctrl_high_speed_serdes_phy_config(void);
+int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up,
+			 enum serdes_type serdes_type,
+			 enum serdes_speed baud_rate,
+			 enum serdes_mode serdes_mode,
+			 enum ref_clock ref_clock);
+int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up,
+			     enum serdes_type serdes_type,
+			     enum serdes_speed baud_rate,
+			     enum serdes_mode serdes_mode,
+			     enum ref_clock ref_clock);
+u32 hws_serdes_silicon_ref_clock_get(void);
+int hws_serdes_pex_ref_clock_get(enum serdes_type serdes_type,
+				 enum ref_clock *ref_clock);
+int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type,
+		      enum ref_clock ref_clock);
+int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map);
+u32 hws_serdes_get_phy_selector_val(int serdes_num,
+				    enum serdes_type serdes_type);
+u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type);
+u32 hws_serdes_get_max_lane(void);
+int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset,
+			  u32 *unit_base_reg, u32 *unit_offset);
+int hws_pex_tx_config_seq(struct serdes_map *serdes_map);
+u32 hws_get_physical_serdes_num(u32 serdes_num);
+int hws_is_serdes_active(u8 lane_num);
+
+#endif /* _HIGH_SPEED_ENV_SPEC_H */
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c
new file mode 100644
index 0000000..5f2c3eb
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_topology_spec.h"
+#include "sys_env_lib.h"
+
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+/*
+ * This is an example implementation for this custom board
+ * specific function
+ */
+static struct serdes_map custom_board_topology_config[] = {
+	/* Customer Board Topology - reference from Marvell DB-GP board */
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+int hws_board_topology_load(struct serdes_map *serdes_map_array)
+{
+	serdes_map_array = custom_board_topology_config;
+}
+#endif
+
+load_topology_func_ptr load_topology_func_arr[] = {
+	load_topology_rd,	/* RD NAS */
+	load_topology_db,	/* 6820 DB-BP (A38x) */
+	load_topology_rd,	/* RD AP */
+	load_topology_db_ap,	/* DB AP */
+	load_topology_db_gp,	/* DB GP */
+	load_topology_db_381,	/* 6821 DB-BP (A381) */
+	load_topology_db_amc,	/* DB-AMC */
+};
+
+/*****************************************/
+/** Load topology - Marvell 380 DB - BP **/
+/*****************************************/
+/* Configuration options */
+struct serdes_map db_config_default[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1363_c[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+};
+
+struct serdes_map db_config_slm1363_d[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1363_e[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1363_f[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1364_d[MAX_SERDES_LANES] = {
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1364_e[MAX_SERDES_LANES] = {
+	{SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}
+};
+
+struct serdes_map db_config_slm1364_f[MAX_SERDES_LANES] = {
+	{SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}
+};
+
+/*************************************************************************/
+/** The following structs are mapping for DB board 'SatR' configuration **/
+/*************************************************************************/
+struct serdes_map db_satr_config_lane1[SATR_DB_LANE1_MAX_OPTIONS] = {
+	/* 0 */ {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 1 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 2 */ {SATA0, SERDES_SPEED_3_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 3 */ {SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 4 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 5 */ {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 6 */ {QSGMII, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_satr_config_lane2[SATR_DB_LANE2_MAX_OPTIONS] = {
+	/* 0 */ {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 1 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 2 */ {SATA1, SERDES_SPEED_3_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 3 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0}
+};
+
+/*******************************************************/
+/* Configuration options DB ****************************/
+/* mapping from TWSI address data to configuration map */
+/*******************************************************/
+struct serdes_map *topology_config_db[] = {
+	db_config_slm1363_c,
+	db_config_slm1363_d,
+	db_config_slm1363_e,
+	db_config_slm1363_f,
+	db_config_slm1364_d,
+	db_config_slm1364_e,
+	db_config_slm1364_f,
+	db_config_default
+};
+
+/*************************************/
+/** Load topology - Marvell DB - AP **/
+/*************************************/
+struct serdes_map db_ap_config_default[MAX_SERDES_LANES] = {
+	/* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 1 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 2 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 3 */ {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 4 */ {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 5 */ {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}
+};
+
+/*************************************/
+/** Load topology - Marvell DB - GP **/
+/*************************************/
+struct serdes_map db_gp_config_default[MAX_SERDES_LANES] = {
+	/* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 1 */ {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 2 */ {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 3 */ {SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 4 */ {SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 5 */ {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0}
+};
+
+struct serdes_map db_amc_config_default[MAX_SERDES_LANES] = {
+	/* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 1 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 2 */ {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 3 */ {PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 4 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 5 */ {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+};
+
+/*****************************************/
+/** Load topology - Marvell 381 DB - BP **/
+/*****************************************/
+/* Configuration options */
+struct serdes_map db381_config_default[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1427[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 1, 1},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 1, 1}
+};
+
+struct serdes_map db_config_slm1426[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 1, 1}
+};
+
+/*
+ * this array must be aligned with enum topology_config_db381 enum,
+ * every update to this array requires update to enum topology_config_db381
+ * enum
+ */
+struct serdes_map *topology_config_db_381[] = {
+	db_config_slm1427,
+	db_config_slm1426,
+	db381_config_default,
+};
+
+u8 topology_config_db_mode_get(void)
+{
+	u8 mode;
+
+	DEBUG_INIT_FULL_S("\n### topology_config_db_mode_get ###\n");
+
+	/* Default - return DB_CONFIG_DEFAULT */
+
+	if (!i2c_read(DB_GET_MODE_SLM1363_ADDR, 0, 1, &mode, 1)) {
+		switch (mode & 0xf) {
+		case 0xc:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 C topology\n");
+			return DB_CONFIG_SLM1363_C;
+		case 0xd:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 D topology\n");
+			return DB_CONFIG_SLM1363_D;
+		case 0xe:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 E topology\n");
+			return DB_CONFIG_SLM1363_E;
+		case 0xf:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 F topology\n");
+			return DB_CONFIG_SLM1363_F;
+		default:	/* not the right module */
+			break;
+		}
+	}
+
+	/* SLM1364 Module */
+	if (i2c_read(DB_GET_MODE_SLM1364_ADDR, 0, 1, &mode, 1)) {
+		DEBUG_INIT_S("\nInit DB board default topology\n");
+		return DB_CONFIG_DEFAULT;
+	}
+
+	switch (mode & 0xf) {
+	case 0xd:
+		DEBUG_INIT_S("\nInit DB board SLM 1364 D topology\n");
+		return DB_CONFIG_SLM1364_D;
+	case 0xe:
+		DEBUG_INIT_S("\nInit DB board SLM 1364 E topology\n");
+		return DB_CONFIG_SLM1364_E;
+	case 0xf:
+		DEBUG_INIT_S("\nInit DB board SLM 1364 F topology\n");
+		return DB_CONFIG_SLM1364_F;
+	default:		/* Default configuration */
+		DEBUG_INIT_S("\nInit DB board default topology\n");
+		return DB_CONFIG_DEFAULT;
+	}
+}
+
+u8 topology_config_db_381_mode_get(void)
+{
+	u8 mode;
+
+	DEBUG_INIT_FULL_S("\n### topology_config_db_381_mode_get ###\n");
+
+	if (!i2c_read(DB381_GET_MODE_SLM1426_1427_ADDR, 0, 2, &mode, 1)) {
+		switch (mode & 0xf) {
+		case 0x1:
+			DEBUG_INIT_S("\nInit DB-381 board SLM 1427 topology\n");
+			return DB_CONFIG_SLM1427;
+		case 0x2:
+			DEBUG_INIT_S("\nInit DB-381 board SLM 1426 topology\n");
+			return DB_CONFIG_SLM1426;
+		default:	/* not the right module */
+			break;
+		}
+	}
+
+	/* in case not detected any supported module, use default topology */
+	DEBUG_INIT_S("\nInit DB-381 board default topology\n");
+	return DB_381_CONFIG_DEFAULT;
+}
+
+/*
+ * Read SatR field 'sgmiispeed' and update lane topology SGMII entries
+ * speed setup
+ */
+int update_topology_sgmii_speed(struct serdes_map *serdes_map_array)
+{
+	u32 serdes_type, lane_num;
+	u8 config_val;
+
+	/* Update SGMII speed settings by 'sgmiispeed' SatR value */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_type = serdes_map_array[lane_num].serdes_type;
+		/*Read SatR configuration for SGMII speed */
+		if ((serdes_type == SGMII0) || (serdes_type == SGMII1) ||
+		    (serdes_type == SGMII2)) {
+			/* Read SatR 'sgmiispeed' value */
+			if (i2c_read(EEPROM_I2C_ADDR, 0, 2, &config_val, 1)) {
+				printf("%s: TWSI Read of 'sgmiispeed' failed\n",
+				       __func__);
+				return MV_FAIL;
+			}
+
+			if (0 == (config_val & 0x40)) {
+				serdes_map_array[lane_num].serdes_speed =
+					SERDES_SPEED_1_25_GBPS;
+			} else {
+				serdes_map_array[lane_num].serdes_speed =
+					SERDES_SPEED_3_125_GBPS;
+			}
+		}
+	}
+	return MV_OK;
+}
+
+struct serdes_map default_lane = {
+	DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE
+};
+int is_custom_topology = 0;	/* indicate user of non-default topology */
+
+/*
+ * Read SatR fields (dbserdes1/2 , gpserdes1/2/5) and update lane
+ * topology accordingly
+ */
+int update_topology_satr(struct serdes_map *serdes_map_array)
+{
+	u8 config_val, lane_select, i;
+	u32 board_id = mv_board_id_get();
+
+	switch (board_id) {
+	case DB_68XX_ID:	/* read 'dbserdes1' & 'dbserdes2' */
+	case DB_BP_6821_ID:
+		if (i2c_read(EEPROM_I2C_ADDR, 1, 2, &config_val, 1)) {
+			printf("%s: TWSI Read of 'dbserdes1/2' failed\n",
+			       __func__);
+			return MV_FAIL;
+		}
+
+		/* Lane #1 */
+		lane_select = (config_val & SATR_DB_LANE1_CFG_MASK) >>
+			SATR_DB_LANE1_CFG_OFFSET;
+		if (lane_select >= SATR_DB_LANE1_MAX_OPTIONS) {
+			printf("\n\%s: Error: invalid value for SatR field 'dbserdes1' (%x)\n",
+			       __func__, lane_select);
+			printf("\t_skipping Topology update (run 'SatR write default')\n");
+			return MV_FAIL;
+		}
+
+		/*
+		 * If modified default serdes_type for lane#1, update
+		 * topology and mark it as custom
+		 */
+		if (serdes_map_array[1].serdes_type !=
+		    db_satr_config_lane1[lane_select].serdes_type) {
+			serdes_map_array[1] = db_satr_config_lane1[lane_select];
+			is_custom_topology = 1;
+			/* DB 381/2 board has inverted SerDes polarity */
+			if (board_id == DB_BP_6821_ID)
+				serdes_map_array[1].swap_rx =
+					serdes_map_array[1].swap_tx = 1;
+		}
+
+		/* Lane #2 */
+		lane_select = (config_val & SATR_DB_LANE2_CFG_MASK) >>
+			SATR_DB_LANE2_CFG_OFFSET;
+		if (lane_select >= SATR_DB_LANE2_MAX_OPTIONS) {
+			printf("\n\%s: Error: invalid value for SatR field 'dbserdes2' (%x)\n",
+			       __func__, lane_select);
+			printf("\t_skipping Topology update (run 'SatR write default')\n");
+			return MV_FAIL;
+		}
+
+		/*
+		 * If modified default serdes_type for lane@2, update
+		 * topology and mark it as custom
+		 */
+		if (serdes_map_array[2].serdes_type !=
+		    db_satr_config_lane2[lane_select].serdes_type) {
+			serdes_map_array[2] = db_satr_config_lane2[lane_select];
+			is_custom_topology = 1;
+			/* DB 381/2 board has inverted SerDes polarity */
+			if (board_id == DB_BP_6821_ID)
+				serdes_map_array[2].swap_rx =
+					serdes_map_array[2].swap_tx = 1;
+		}
+
+		if (is_custom_topology == 1) {
+			/*
+			 * Check for conflicts with detected lane #1 and
+			 * lane #2 (Disable conflicted lanes)
+			 */
+			for (i = 0; i < hws_serdes_get_max_lane(); i++) {
+				if (i != 1 && serdes_map_array[1].serdes_type ==
+				    serdes_map_array[i].serdes_type) {
+					printf("\t_lane #%d Type conflicts with Lane #1 (Lane #%d disabled)\n",
+					       i, i);
+					serdes_map_array[i] =
+						db_satr_config_lane1[0];
+				}
+
+				if (i != 2 &&
+				    serdes_map_array[2].serdes_type ==
+				    serdes_map_array[i].serdes_type) {
+					printf("\t_lane #%d Type conflicts with Lane #2 (Lane #%d disabled)\n",
+					       i, i);
+					serdes_map_array[i] =
+						db_satr_config_lane1[0];
+				}
+			}
+		}
+
+		break;		/* case DB_68XX_ID */
+	case DB_GP_68XX_ID:	/* read 'gpserdes1' & 'gpserdes2' */
+		if (i2c_read(EEPROM_I2C_ADDR, 2, 2, &config_val, 1)) {
+			printf("%s: TWSI Read of 'gpserdes1/2' failed\n",
+			       __func__);
+			return MV_FAIL;
+		}
+
+		/*
+		 * Lane #1:
+		 * lane_select = 0 --> SATA0,
+		 * lane_select = 1 --> PCIe0 (mini PCIe)
+		 */
+		lane_select = (config_val & SATR_GP_LANE1_CFG_MASK) >>
+			SATR_GP_LANE1_CFG_OFFSET;
+		if (lane_select == 1) {
+			serdes_map_array[1].serdes_mode = PEX0;
+			serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS;
+			serdes_map_array[1].serdes_type = PEX_ROOT_COMPLEX_X1;
+			/*
+			 * If lane 1 is set to PCIe0 --> disable PCIe0
+			 * on lane 0
+			 */
+			serdes_map_array[0] = default_lane;
+			/* indicate user of non-default topology */
+			is_custom_topology = 1;
+		}
+		printf("Lane 1 detection: %s\n",
+		       lane_select ? "PCIe0 (mini PCIe)" : "SATA0");
+
+		/*
+		 * Lane #2:
+		 * lane_select = 0 --> SATA1,
+		 * lane_select = 1 --> PCIe1 (mini PCIe)
+		 */
+		lane_select = (config_val & SATR_GP_LANE2_CFG_MASK) >>
+			SATR_GP_LANE2_CFG_OFFSET;
+		if (lane_select == 1) {
+			serdes_map_array[2].serdes_type = PEX1;
+			serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS;
+			serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1;
+			/* indicate user of non-default topology */
+			is_custom_topology = 1;
+		}
+		printf("Lane 2 detection: %s\n",
+		       lane_select ? "PCIe1 (mini PCIe)" : "SATA1");
+		break;		/* case DB_GP_68XX_ID */
+	}
+
+	if (is_custom_topology)
+		printf("\nDetected custom SerDes topology (to restore default run 'SatR write default')\n\n");
+
+	return MV_OK;
+}
+
+/*
+ * hws_update_device_toplogy
+ * DESCRIPTION: Update the default board topology for specific device Id
+ * INPUT:
+ *	topology_config_ptr - pointer to the Serdes mapping
+ *	topology_mode - topology mode (index)
+ * OUTPUT: None
+ * RRETURNS:
+ *	MV_OK - if updating the board topology success
+ *	MV_BAD_PARAM - if the input parameter is wrong
+ */
+int hws_update_device_toplogy(struct serdes_map *topology_config_ptr,
+			      enum topology_config_db topology_mode)
+{
+	u32 dev_id = sys_env_device_id_get();
+	u32 board_id = mv_board_id_get();
+
+	switch (topology_mode) {
+	case DB_CONFIG_DEFAULT:
+		switch (dev_id) {
+		case MV_6810:
+			/*
+			 * DB-AP : default for Lane3=SGMII2 -->
+			 * 6810 supports only 2 SGMII interfaces:
+			 * lane 3 disabled
+			 */
+			if (board_id == DB_AP_68XX_ID) {
+				printf("Device 6810 supports only 2 SGMII interfaces: SGMII-2 @ lane3 disabled\n");
+				topology_config_ptr[3] = default_lane;
+			}
+
+			/*
+			 * 6810 has only 4 SerDes and the forth one is
+			 * Serdes number 5 (i.e. Serdes 4 is not connected),
+			 * therefore we need to copy SerDes 5 configuration
+			 * to SerDes 4
+			 */
+			printf("Device 6810 does not supports SerDes Lane #4: replaced topology entry with lane #5\n");
+			topology_config_ptr[4] = topology_config_ptr[5];
+
+			/*
+			 * No break between cases since the 1st
+			 * 6820 limitation apply on 6810
+			 */
+		case MV_6820:
+			/*
+			 * DB-GP & DB-BP: default for Lane3=SATA3 -->
+			 * 6810/20 supports only 2 SATA interfaces:
+			 * lane 3 disabled
+			 */
+			if ((board_id == DB_68XX_ID) ||
+			    (board_id == DB_GP_68XX_ID)) {
+				printf("Device 6810/20 supports only 2 SATA interfaces: SATA Port 3 @ lane3 disabled\n");
+				topology_config_ptr[3] = default_lane;
+			}
+			/*
+			 * DB-GP on 6820 only: default for Lane4=SATA2
+			 * --> 6820 supports only 2 SATA interfaces:
+			 * lane 3 disabled
+			 */
+			if (board_id == DB_GP_68XX_ID && dev_id == MV_6820) {
+				printf("Device 6820 supports only 2 SATA interfaces: SATA Port 2 @ lane4 disabled\n");
+				topology_config_ptr[4] = default_lane;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+
+	default:
+		printf("sys_env_update_device_toplogy: selected topology is not supported by this routine\n");
+		break;
+	}
+
+	return MV_OK;
+}
+
+int load_topology_db_381(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	u8 topology_mode;
+	struct serdes_map *topology_config_ptr;
+	u8 twsi_data;
+	u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0;
+
+	printf("\nInitialize DB-88F6821-BP board topology\n");
+
+	/* Getting the relevant topology mode (index) */
+	topology_mode = topology_config_db_381_mode_get();
+	topology_config_ptr = topology_config_db_381[topology_mode];
+
+	/* Read USB3.0 mode: HOST/DEVICE */
+	if (load_topology_usb_mode_get(&twsi_data) == MV_OK) {
+		usb3_host0_or_device = (twsi_data & 0x1);
+		/* Only one USB3 device is enabled */
+		if (usb3_host0_or_device == 0)
+			usb3_host1_or_device = ((twsi_data >> 1) & 0x1);
+	}
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+
+		/* Update USB3 device if needed */
+		if (usb3_host0_or_device == 1 &&
+		    serdes_map_array[lane_num].serdes_type == USB3_HOST0)
+			serdes_map_array[lane_num].serdes_type = USB3_DEVICE;
+
+		if (usb3_host1_or_device == 1 &&
+		    serdes_map_array[lane_num].serdes_type == USB3_HOST1)
+			serdes_map_array[lane_num].serdes_type = USB3_DEVICE;
+	}
+
+	/* If not detected any SerDes Site module, read 'SatR' lane setup */
+	if (topology_mode == DB_381_CONFIG_DEFAULT)
+		update_topology_satr(serdes_map_array);
+
+	/* update 'sgmiispeed' settings */
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	u8 topology_mode;
+	struct serdes_map *topology_config_ptr;
+	u8 twsi_data;
+	u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0;
+
+	printf("\nInitialize DB-88F6820-BP board topology\n");
+
+	/* Getting the relevant topology mode (index) */
+	topology_mode = topology_config_db_mode_get();
+
+	if (topology_mode == DB_NO_TOPOLOGY)
+		topology_mode = DB_CONFIG_DEFAULT;
+
+	topology_config_ptr = topology_config_db[topology_mode];
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, topology_mode));
+
+	/* Read USB3.0 mode: HOST/DEVICE */
+	if (load_topology_usb_mode_get(&twsi_data) == MV_OK) {
+		usb3_host0_or_device = (twsi_data & 0x1);
+		/* Only one USB3 device is enabled */
+		if (usb3_host0_or_device == 0)
+			usb3_host1_or_device = ((twsi_data >> 1) & 0x1);
+	}
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+
+		/*
+		 * Update USB3 device if needed - relevant for
+		 * lane 3,4,5 only
+		 */
+		if (lane_num >= 3) {
+			if ((serdes_map_array[lane_num].serdes_type ==
+			     USB3_HOST0) && (usb3_host0_or_device == 1))
+				serdes_map_array[lane_num].serdes_type =
+					USB3_DEVICE;
+
+			if ((serdes_map_array[lane_num].serdes_type ==
+			     USB3_HOST1) && (usb3_host1_or_device == 1))
+				serdes_map_array[lane_num].serdes_type =
+					USB3_DEVICE;
+		}
+	}
+
+	/* If not detected any SerDes Site module, read 'SatR' lane setup */
+	if (topology_mode == DB_CONFIG_DEFAULT)
+		update_topology_satr(serdes_map_array);
+
+	/* update 'sgmiispeed' settings */
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db_ap(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	struct serdes_map *topology_config_ptr;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_db_ap ###\n");
+
+	printf("\nInitialize DB-AP board topology\n");
+	topology_config_ptr = db_ap_config_default;
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+	}
+
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db_gp(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	struct serdes_map *topology_config_ptr;
+	int is_sgmii = 0;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_db_gp ###\n");
+
+	topology_config_ptr = db_gp_config_default;
+
+	printf("\nInitialize DB-GP board topology\n");
+
+	/* check S@R: if lane 5 is USB3 or SGMII */
+	if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK)
+		printf("%s: TWSI Read failed - Loading Default Topology\n",
+		       __func__);
+	else {
+		topology_config_ptr[5].serdes_type =
+			is_sgmii ? SGMII2 : USB3_HOST1;
+		topology_config_ptr[5].serdes_speed = is_sgmii ?
+			SERDES_SPEED_3_125_GBPS : SERDES_SPEED_5_GBPS;
+		topology_config_ptr[5].serdes_mode = SERDES_DEFAULT_MODE;
+	}
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+	}
+
+	/*
+	 * Update 'gpserdes1/2/3' lane configuration , and 'sgmiispeed'
+	 * for SGMII lanes
+	 */
+	update_topology_satr(serdes_map_array);
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db_amc(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	struct serdes_map *topology_config_ptr;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_db_amc ###\n");
+
+	printf("\nInitialize DB-AMC board topology\n");
+	topology_config_ptr = db_amc_config_default;
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+	}
+
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_rd(struct serdes_map *serdes_map_array)
+{
+	u8 mode;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_rd ###\n");
+
+	DEBUG_INIT_S("\nInit RD board ");
+
+	/* Reading mode */
+	DEBUG_INIT_FULL_S("load_topology_rd: getting mode\n");
+	if (i2c_read(EEPROM_I2C_ADDR, 0, 2, &mode, 1)) {
+		DEBUG_INIT_S("load_topology_rd: TWSI Read failed\n");
+		return MV_FAIL;
+	}
+
+	/* Updating the topology map */
+	DEBUG_INIT_FULL_S("load_topology_rd: Loading board topology details\n");
+
+	/* RD mode: 0 = NAS, 1 = AP */
+	if (((mode >> 1) & 0x1) == 0) {
+		CHECK_STATUS(load_topology_rd_nas(serdes_map_array));
+	} else {
+		CHECK_STATUS(load_topology_rd_ap(serdes_map_array));
+	}
+
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_rd_nas(struct serdes_map *serdes_map_array)
+{
+	int is_sgmii = 0;
+	u32 i;
+
+	DEBUG_INIT_S("\nInit RD NAS topology ");
+
+	/* check if lane 4 is USB3 or SGMII */
+	if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) {
+		DEBUG_INIT_S("load_topology_rd NAS: TWSI Read failed\n");
+		return MV_FAIL;
+	}
+
+	/* Lane 0 */
+	serdes_map_array[0].serdes_type = PEX0;
+	serdes_map_array[0].serdes_speed = SERDES_SPEED_5_GBPS;
+	serdes_map_array[0].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+	/* Lane 1 */
+	serdes_map_array[1].serdes_type = SATA0;
+	serdes_map_array[1].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[1].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 2 */
+	serdes_map_array[2].serdes_type = SATA1;
+	serdes_map_array[2].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[2].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 3 */
+	serdes_map_array[3].serdes_type = SATA3;
+	serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 4 */
+	if (is_sgmii == 1) {
+		DEBUG_INIT_S("Serdes Lane 4 is SGMII\n");
+		serdes_map_array[4].serdes_type = SGMII1;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	} else {
+		DEBUG_INIT_S("Serdes Lane 4 is USB3\n");
+		serdes_map_array[4].serdes_type = USB3_HOST0;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	}
+
+	/* Lane 5 */
+	serdes_map_array[5].serdes_type = SATA2;
+	serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* init swap configuration */
+	for (i = 0; i <= 5; i++) {
+		serdes_map_array[i].swap_rx = 0;
+		serdes_map_array[i].swap_tx = 0;
+	}
+
+	return MV_OK;
+}
+
+int load_topology_rd_ap(struct serdes_map *serdes_map_array)
+{
+	int is_sgmii = 0;
+	u32 i;
+
+	DEBUG_INIT_S("\nInit RD AP topology ");
+
+	/* check if lane 4 is USB3 or SGMII */
+	if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) {
+		DEBUG_INIT_S("load_topology_rd AP: TWSI Read failed\n");
+		return MV_FAIL;
+	}
+
+	/* Lane 0 */
+	serdes_map_array[0].serdes_type = DEFAULT_SERDES;
+	serdes_map_array[0].serdes_speed = LAST_SERDES_SPEED;
+	serdes_map_array[0].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 1 */
+	serdes_map_array[1].serdes_type = PEX0;
+	serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS;
+	serdes_map_array[1].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+	/* Lane 2 */
+	serdes_map_array[2].serdes_type = PEX1;
+	serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS;
+	serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+	/* Lane 3 */
+	serdes_map_array[3].serdes_type = SATA3;
+	serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 4 */
+	if (is_sgmii == 1) {
+		DEBUG_INIT_S("Serdes Lane 4 is SGMII\n");
+		serdes_map_array[4].serdes_type = SGMII1;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	} else {
+		DEBUG_INIT_S("Serdes Lane 4 is USB3\n");
+		serdes_map_array[4].serdes_type = USB3_HOST0;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	}
+
+	/* Lane 5 */
+	serdes_map_array[5].serdes_type = SATA2;
+	serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* init swap configuration */
+	for (i = 0; i <= 5; i++) {
+		serdes_map_array[i].swap_rx = 0;
+		serdes_map_array[i].swap_tx = 0;
+	}
+
+	return MV_OK;
+}
+
+int load_topology_rd_sgmii_usb(int *is_sgmii)
+{
+	u8 mode;
+
+	/*
+	 * DB-GP board: Device 6810 supports only 2 GbE ports:
+	 * SGMII2 not supported (USE USB3 Host instead)
+	 */
+	if (sys_env_device_id_get() == MV_6810) {
+		printf("Device 6810 supports only 2 GbE ports: SGMII-2 @ lane5 disabled (setting USB3.0 H1 instead)\n");
+		*is_sgmii = 0;
+		return MV_OK;
+	}
+
+	if (!i2c_read(RD_GET_MODE_ADDR, 1, 2, &mode, 1)) {
+		*is_sgmii = ((mode >> 2) & 0x1);
+	} else {
+		/* else use the default - USB3 */
+		*is_sgmii = 0;
+	}
+
+	if (*is_sgmii)
+		is_custom_topology = 1;
+
+	printf("Lane 5 detection: %s\n",
+	       *is_sgmii ? "SGMII2" : "USB3.0 Host Port 1");
+
+	return MV_OK;
+}
+
+/*
+ * 'usb3port0'/'usb3port1' fields are located in EEPROM,
+ * at 3rd byte(offset=2), bit 0:1 (respectively)
+ */
+int load_topology_usb_mode_get(u8 *twsi_data)
+{
+	if (!i2c_read(EEPROM_I2C_ADDR, 2, 2, twsi_data, 1))
+		return MV_OK;
+
+	return MV_ERROR;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h
new file mode 100644
index 0000000..3cfb1c7
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _HIGHSPEED_TOPOLOGY_SPEC_H
+#define _HIGHSPEED_TOPOLOGY_SPEC_H
+
+#include "high_speed_env_spec.h"
+
+/* Topology map options for the DB_A38X_BP board */
+enum topology_config_db {
+	DB_CONFIG_SLM1363_C,
+	DB_CONFIG_SLM1363_D,
+	DB_CONFIG_SLM1363_E,
+	DB_CONFIG_SLM1363_F,
+	DB_CONFIG_SLM1364_D,
+	DB_CONFIG_SLM1364_E,
+	DB_CONFIG_SLM1364_F,
+	DB_CONFIG_DEFAULT,
+	DB_NO_TOPOLOGY
+};
+
+/*
+ * this enum must be aligned with topology_config_db_381 array,
+ * every update to this enum requires update to topology_config_db_381
+ * array
+ */
+enum topology_config_db381 {
+	DB_CONFIG_SLM1427,	/* enum for db_config_slm1427 */
+	DB_CONFIG_SLM1426,	/* enum for db_config_slm1426 */
+	DB_381_CONFIG_DEFAULT,
+	DB_381_NO_TOPOLOGY
+};
+
+/* A generic function pointer for loading the board topology map */
+typedef int (*load_topology_func_ptr)(struct serdes_map *serdes_map_array);
+
+extern load_topology_func_ptr load_topology_func_arr[];
+
+/*
+ * topology_config_db_mode_get -
+ *
+ * DESCRIPTION:		Gets the relevant topology mode (index).
+ *			for load_topology_db use only.
+ * INPUT:		None.
+ * OUTPUT:		None.
+ * RETURNS:		the topology mode
+ */
+u8 topology_config_db_mode_get(void);
+
+/*
+ * load_topology_xxx -
+ *
+ * DESCRIPTION:		Loads the board topology for the XXX board
+ * INPUT:		serdes_map_array - The struct that will contain
+ *			the board topology map
+ * OUTPUT:		The board topology map.
+ * RETURNS:		MV_OK   for success
+ *			MV_FAIL	for failure (a wrong topology mode was read
+ *			from the board)
+ */
+
+/* load_topology_db - Loads the board topology for DB Board */
+int load_topology_db(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd - Loads the board topology for RD Board */
+int load_topology_rd(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd_nas - Loads the board topology for RD NAS Board */
+int load_topology_rd_nas(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd_ap - Loads the board topology for RD Ap Board */
+int load_topology_rd_ap(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_ap - Loads the board topology for DB-AP Board */
+int load_topology_db_ap(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_gp - Loads the board topology for DB GP Board */
+int load_topology_db_gp(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_381 - Loads the board topology for 381 DB-BP Board */
+int load_topology_db_381(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_amc - Loads the board topology for DB-AMC Board */
+int load_topology_db_amc(struct serdes_map *serdes_map_array);
+
+/*
+ * hws_update_device_toplogy
+ * DESCRIPTION: Update the default board topology for specific device Id
+ * INPUT:
+ *	topology_config_ptr - pointer to the Serdes mapping
+ *	topology_mode - topology mode (index)
+ * OUTPUT: None
+ * RRETURNS:
+ *	MV_OK - if updating the board topology success
+ *	MV_BAD_PARAM - if the input parameter is wrong
+ */
+int hws_update_device_toplogy(struct serdes_map *topology_config_ptr,
+			      enum topology_config_db topology_mode);
+
+/*
+ * load_topology_rd_sgmii_usb -
+ *
+ * DESCRIPTION:			For RD board check if lane 4 is USB3 or SGMII
+ * INPUT:			None
+ * OUTPUT:			is_sgmii - return 1 if lane 4 is SGMII
+ *				return 0 if lane 4 is USB.
+ * RETURNS:			MV_OK for success
+ */
+int load_topology_rd_sgmii_usb(int *is_sgmii);
+
+/*
+ * load_topology_usb_mode_get -
+ *
+ * DESCRIPTION:			For DB board check if USB3.0 mode
+ * INPUT:			None
+ * OUTPUT:			twsi_data - return data read from S@R via I2C
+ * RETURNS:			MV_OK for success
+ */
+int load_topology_usb_mode_get(u8 *twsi_data);
+
+#endif /* _HIGHSPEED_TOPOLOGY_SPEC_H */
diff --git a/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
new file mode 100644
index 0000000..ee2305b
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "seq_exec.h"
+#include "high_speed_env_spec.h"
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
+
+#if defined(MV_DEBUG_INIT_FULL) || defined(MV_DEBUG)
+#define DB(x)	x
+#else
+#define DB(x)
+#endif
+
+/* Array for mapping the operation (write, poll or delay) functions */
+op_execute_func_ptr op_execute_func_arr[] = {
+	write_op_execute,
+	delay_op_execute,
+	poll_op_execute
+};
+
+int write_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+	u32 unit_base_reg, unit_offset, data, mask, reg_data, reg_addr;
+
+	/* Getting write op params from the input parameter */
+	data = params->data[data_arr_idx];
+	mask = params->mask;
+
+	/* an empty operation */
+	if (data == NO_DATA)
+		return MV_OK;
+
+	/* get updated base address since it can be different between Serdes */
+	CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
+					   params->unit_offset,
+					   &unit_base_reg, &unit_offset));
+
+	/* Address calculation */
+	reg_addr = unit_base_reg + unit_offset * serdes_num;
+
+#ifdef SEQ_DEBUG
+	printf("Write: 0x%x: 0x%x (mask 0x%x) - ", reg_addr, data, mask);
+#endif
+	/* Reading old value */
+	reg_data = reg_read(reg_addr);
+	reg_data &= (~mask);
+
+	/* Writing new data */
+	data &= mask;
+	reg_data |= data;
+	reg_write(reg_addr, reg_data);
+
+#ifdef SEQ_DEBUG
+	printf(" - 0x%x\n", reg_data);
+#endif
+
+	return MV_OK;
+}
+
+int delay_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+	u32 delay;
+
+	/* Getting delay op params from the input parameter */
+	delay = params->wait_time;
+#ifdef SEQ_DEBUG
+	printf("Delay: %d\n", delay);
+#endif
+	mdelay(delay);
+
+	return MV_OK;
+}
+
+int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+	u32 unit_base_reg, unit_offset, data, mask, num_of_loops, wait_time;
+	u32 poll_counter = 0;
+	u32 reg_addr, reg_data;
+
+	/* Getting poll op params from the input parameter */
+	data = params->data[data_arr_idx];
+	mask = params->mask;
+	num_of_loops = params->num_of_loops;
+	wait_time = params->wait_time;
+
+	/* an empty operation */
+	if (data == NO_DATA)
+		return MV_OK;
+
+	/* get updated base address since it can be different between Serdes */
+	CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
+					   params->unit_offset,
+					   &unit_base_reg, &unit_offset));
+
+	/* Address calculation */
+	reg_addr = unit_base_reg + unit_offset * serdes_num;
+
+	/* Polling */
+#ifdef SEQ_DEBUG
+	printf("Poll:  0x%x: 0x%x (mask 0x%x)\n", reg_addr, data, mask);
+#endif
+
+	do {
+		reg_data = reg_read(reg_addr) & mask;
+		poll_counter++;
+		udelay(wait_time);
+	} while ((reg_data != data) && (poll_counter < num_of_loops));
+
+	if ((poll_counter >= num_of_loops) && (reg_data != data)) {
+		DEBUG_INIT_S("poll_op_execute: TIMEOUT\n");
+		return MV_TIMEOUT;
+	}
+
+	return MV_OK;
+}
+
+enum mv_op get_cfg_seq_op(struct op_params *params)
+{
+	if (params->wait_time == 0)
+		return WRITE_OP;
+	else if (params->num_of_loops == 0)
+		return DELAY_OP;
+
+	return POLL_OP;
+}
+
+int mv_seq_exec(u32 serdes_num, u32 seq_id)
+{
+	u32 seq_idx;
+	struct op_params *seq_arr;
+	u32 seq_size;
+	u32 data_arr_idx;
+	enum mv_op curr_op;
+
+	DB(printf("\n### mv_seq_exec ###\n"));
+	DB(printf("seq id: %d\n", seq_id));
+
+	if (hws_is_serdes_active(serdes_num) != 1) {
+		printf("mv_seq_exec_ext:Error: SerDes lane %d is not valid\n",
+		       serdes_num);
+		return MV_BAD_PARAM;
+	}
+
+	seq_arr = serdes_seq_db[seq_id].op_params_ptr;
+	seq_size = serdes_seq_db[seq_id].cfg_seq_size;
+	data_arr_idx = serdes_seq_db[seq_id].data_arr_idx;
+
+	DB(printf("seq_size: %d\n", seq_size));
+	DB(printf("data_arr_idx: %d\n", data_arr_idx));
+
+	/* Executing the sequence operations */
+	for (seq_idx = 0; seq_idx < seq_size; seq_idx++) {
+		curr_op = get_cfg_seq_op(&seq_arr[seq_idx]);
+		op_execute_func_arr[curr_op](serdes_num, &seq_arr[seq_idx],
+					     data_arr_idx);
+	}
+
+	return MV_OK;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h
new file mode 100644
index 0000000..14f406a
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _SEQ_EXEC_H
+#define _SEQ_EXEC_H
+
+#define NA			0xff
+#define DEFAULT_PARAM		0
+#define MV_BOARD_TCLK_ERROR	0xffffffff
+
+#define NO_DATA			0xffffffff
+#define MAX_DATA_ARRAY		5
+#define FIRST_CELL		0
+
+/* Operation types */
+enum mv_op {
+	WRITE_OP,
+	DELAY_OP,
+	POLL_OP,
+};
+
+/* Operation parameters */
+struct op_params {
+	u32 unit_base_reg;
+	u32 unit_offset;
+	u32 mask;
+	u32 data[MAX_DATA_ARRAY];	/* data array */
+	u8 wait_time;			/* msec */
+	u16 num_of_loops;		/* for polling only */
+};
+
+/*
+ * Sequence parameters. Each sequence contains:
+ * 1. Sequence id.
+ * 2. Sequence size (total amount of operations during the sequence)
+ * 3. a series of operations. operations can be write, poll or delay
+ * 4. index in the data array (the entry where the relevant data sits)
+ */
+struct cfg_seq {
+	struct op_params *op_params_ptr;
+	u8 cfg_seq_size;
+	u8 data_arr_idx;
+};
+
+extern struct cfg_seq serdes_seq_db[];
+
+/*
+ * A generic function type for executing an operation (write, poll or delay)
+ */
+typedef int (*op_execute_func_ptr)(u32 serdes_num, struct op_params *params,
+				   u32 data_arr_idx);
+
+/* Specific functions for executing each operation */
+int write_op_execute(u32 serdes_num, struct op_params *params,
+		     u32 data_arr_idx);
+int delay_op_execute(u32 serdes_num, struct op_params *params,
+		     u32 data_arr_idx);
+int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx);
+enum mv_op get_cfg_seq_op(struct op_params *params);
+int mv_seq_exec(u32 serdes_num, u32 seq_id);
+
+#endif /*_SEQ_EXEC_H*/
diff --git a/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
new file mode 100644
index 0000000..efd3873
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "seq_exec.h"
+#include "sys_env_lib.h"
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_a38x.h"
+
+#ifdef CONFIG_ARMADA_38X
+enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
+/*                     6820    6810     6811     6828     */
+/* PEX_UNIT_ID      */ { 4,     3,       3,       4},
+/* ETH_GIG_UNIT_ID  */ { 3,	2,       3,       3},
+/* USB3H_UNIT_ID    */ { 2,     2,       2,       2},
+/* USB3D_UNIT_ID    */ { 1,     1,       1,       1},
+/* SATA_UNIT_ID     */ { 2,     2,       2,       4},
+/* QSGMII_UNIT_ID   */ { 1,     0,       0,       1},
+/* XAUI_UNIT_ID     */ { 0,     0,       0,       0},
+/* RXAUI_UNIT_ID    */ { 0,     0,       0,       0}
+};
+#else  /* if (CONFIG_ARMADA_39X) */
+enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
+/*                      6920     6928     */
+/* PEX_UNIT_ID      */ { 4,       4},
+/* ETH_GIG_UNIT_ID  */ { 3,       4},
+/* USB3H_UNIT_ID    */ { 1,       2},
+/* USB3D_UNIT_ID    */ { 0,       1},
+/* SATA_UNIT_ID     */ { 0,       4},
+/* QSGMII_UNIT_ID   */ { 0,       1},
+/* XAUI_UNIT_ID     */ { 1,       1},
+/* RXAUI_UNIT_ID    */ { 1,	  1}
+};
+#endif
+
+u32 g_dev_id = -1;
+
+u32 mv_board_id_get(void)
+{
+#if defined(CONFIG_DB_88F6820_GP)
+	return DB_GP_68XX_ID;
+#else
+	/*
+	 * Return 0 here for custom board as this should not be used
+	 * for custom boards.
+	 */
+	return 0;
+#endif
+}
+
+u32 mv_board_tclk_get(void)
+{
+	u32 value;
+
+	value = (reg_read(DEVICE_SAMPLE_AT_RESET1_REG) >> 15) & 0x1;
+
+	switch (value) {
+	case (0x0):
+		return 250000000;
+	case (0x1):
+		return 200000000;
+	default:
+		return 0xffffffff;
+	}
+}
+
+u32 mv_board_id_index_get(u32 board_id)
+{
+	/*
+	 * Marvell Boards use 0x10 as base for Board ID:
+	 * mask MSB to receive index for board ID
+	 */
+	return board_id & (MARVELL_BOARD_ID_MASK - 1);
+}
+
+/*
+ * sys_env_suspend_wakeup_check
+ * DESCRIPTION:		Reads GPIO input for suspend-wakeup indication.
+ * INPUT:		None.
+ * OUTPUT:
+ * RETURNS:		u32 indicating suspend wakeup status:
+ * 0 - Not supported,
+ * 1 - supported: read magic word detect wakeup,
+ * 2 - detected wakeup from GPIO.
+ */
+enum suspend_wakeup_status sys_env_suspend_wakeup_check(void)
+{
+	u32 reg, board_id_index, gpio;
+	struct board_wakeup_gpio board_gpio[] = MV_BOARD_WAKEUP_GPIO_INFO;
+
+	board_id_index = mv_board_id_index_get(mv_board_id_get());
+	if (!(sizeof(board_gpio) / sizeof(struct board_wakeup_gpio) >
+	      board_id_index)) {
+		printf("\n_failed loading Suspend-Wakeup information (invalid board ID)\n");
+		return SUSPEND_WAKEUP_DISABLED;
+	}
+
+	/*
+	 * - Detect if Suspend-Wakeup is supported on current board
+	 * - Fetch the GPIO number for wakeup status input indication
+	 */
+	if (board_gpio[board_id_index].gpio_num == -1) {
+		/* Suspend to RAM is not supported */
+		return SUSPEND_WAKEUP_DISABLED;
+	} else if (board_gpio[board_id_index].gpio_num == -2) {
+		/*
+		 * Suspend to RAM is supported but GPIO indication is
+		 * not implemented - Skip
+		 */
+		return SUSPEND_WAKEUP_ENABLED;
+	} else {
+		gpio = board_gpio[board_id_index].gpio_num;
+	}
+
+	/* Initialize MPP for GPIO (set MPP = 0x0) */
+	reg = reg_read(MPP_CONTROL_REG(MPP_REG_NUM(gpio)));
+	/* reset MPP21 to 0x0, keep rest of MPP settings*/
+	reg &= ~MPP_MASK(gpio);
+	reg_write(MPP_CONTROL_REG(MPP_REG_NUM(gpio)), reg);
+
+	/* Initialize GPIO as input */
+	reg = reg_read(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)));
+	reg |= GPP_MASK(gpio);
+	reg_write(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)), reg);
+
+	/*
+	 * Check GPP for input status from PIC: 0 - regular init,
+	 * 1 - suspend wakeup
+	 */
+	reg = reg_read(GPP_DATA_IN_REG(GPP_REG_NUM(gpio)));
+
+	/* if GPIO is ON: wakeup from S2RAM indication detected */
+	return (reg & GPP_MASK(gpio)) ? SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED :
+		SUSPEND_WAKEUP_DISABLED;
+}
+
+/*
+ * mv_ctrl_dev_id_index_get
+ *
+ * DESCRIPTION: return SOC device index
+ * INPUT: None
+ * OUTPUT: None
+ * RETURN:
+ *        return SOC device index
+ */
+u32 sys_env_id_index_get(u32 ctrl_model)
+{
+	switch (ctrl_model) {
+	case MV_6820_DEV_ID:
+		return MV_6820_INDEX;
+	case MV_6810_DEV_ID:
+		return MV_6810_INDEX;
+	case MV_6811_DEV_ID:
+		return MV_6811_INDEX;
+	case MV_6828_DEV_ID:
+		return MV_6828_INDEX;
+	case MV_6920_DEV_ID:
+		return MV_6920_INDEX;
+	case MV_6928_DEV_ID:
+		return MV_6928_INDEX;
+	default:
+		return MV_6820_INDEX;
+	}
+}
+
+u32 sys_env_unit_max_num_get(enum unit_id unit)
+{
+	u32 dev_id_index;
+
+	if (unit >= MAX_UNITS_ID) {
+		printf("%s: Error: Wrong unit type (%u)\n", __func__, unit);
+		return 0;
+	}
+
+	dev_id_index = sys_env_id_index_get(sys_env_model_get());
+	return sys_env_soc_unit_nums[unit][dev_id_index];
+}
+
+/*
+ * sys_env_model_get
+ * DESCRIPTION:	Returns 16bit describing the device model (ID) as defined
+ *		in Vendor ID configuration register
+ */
+u16 sys_env_model_get(void)
+{
+	u32 default_ctrl_id, ctrl_id = reg_read(DEV_ID_REG);
+	ctrl_id = (ctrl_id & (DEV_ID_REG_DEVICE_ID_MASK)) >>
+		DEV_ID_REG_DEVICE_ID_OFFS;
+
+	switch (ctrl_id) {
+	case MV_6820_DEV_ID:
+	case MV_6810_DEV_ID:
+	case MV_6811_DEV_ID:
+	case MV_6828_DEV_ID:
+	case MV_6920_DEV_ID:
+	case MV_6928_DEV_ID:
+		return ctrl_id;
+	default:
+		/* Device ID Default for A38x: 6820 , for A39x: 6920 */
+	#ifdef CONFIG_ARMADA_38X
+		default_ctrl_id =  MV_6820_DEV_ID;
+	#else
+		default_ctrl_id = MV_6920_DEV_ID;
+	#endif
+		printf("%s: Error retrieving device ID (%x), using default ID = %x\n",
+		       __func__, ctrl_id, default_ctrl_id);
+		return default_ctrl_id;
+	}
+}
+
+/*
+ * sys_env_device_id_get
+ * DESCRIPTION:	Returns enum (0..7) index of the device model (ID)
+ */
+u32 sys_env_device_id_get(void)
+{
+	char *device_id_str[7] = {
+		"6810", "6820", "6811", "6828", "NONE", "6920", "6928"
+	};
+
+	if (g_dev_id != -1)
+		return g_dev_id;
+
+	g_dev_id = reg_read(DEVICE_SAMPLE_AT_RESET1_REG);
+	g_dev_id = g_dev_id >> SAR_DEV_ID_OFFS & SAR_DEV_ID_MASK;
+	printf("Detected Device ID %s\n", device_id_str[g_dev_id]);
+
+	return g_dev_id;
+}
+
+#ifdef MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI
+/*
+* sys_env_get_topology_update_info
+* DESCRIPTION: Read TWSI fields to update DDR topology structure
+* INPUT: None
+* OUTPUT: None, 0 means no topology update
+* RETURN:
+*       Bit mask of changes topology features
+*/
+#ifdef CONFIG_ARMADA_39X
+u32 sys_env_get_topology_update_info(
+	struct topology_update_info *tui)
+{
+	/* Set 16/32 bit configuration*/
+	tui->update_width = 1;
+	tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+
+#ifdef CONFIG_DDR3
+	if (1 == sys_env_config_get(MV_CONFIG_DDR_BUSWIDTH)) {
+		/* 16bit */
+		tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+	} else {
+		/* 32bit */
+		tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+	}
+#endif
+
+	/* Set ECC/no ECC bit configuration */
+	tui->update_ecc = 1;
+	if (0 == sys_env_config_get(MV_CONFIG_DDR_ECC_EN)) {
+		/* NO ECC */
+		tui->ecc = TOPOLOGY_UPDATE_ECC_OFF;
+	} else {
+		/* ECC */
+		tui->ecc = TOPOLOGY_UPDATE_ECC_ON;
+	}
+
+	tui->update_ecc_pup3_mode = 1;
+	tui->ecc_pup_mode_offset = TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+
+	return MV_OK;
+}
+#else /*CONFIG_ARMADA_38X*/
+u32 sys_env_get_topology_update_info(
+	struct topology_update_info *tui)
+{
+	u8 config_val;
+	u8 ecc_mode[A38X_MV_MAX_MARVELL_BOARD_ID -
+		    A38X_MARVELL_BOARD_ID_BASE][5] = TOPOLOGY_UPDATE;
+	u8 board_id = mv_board_id_get();
+	int ret;
+
+	board_id = mv_board_id_index_get(board_id);
+	ret = i2c_read(EEPROM_I2C_ADDR, 0, 2, &config_val, 1);
+	if (ret) {
+		DEBUG_INIT_S("sys_env_get_topology_update_info: TWSI Read failed\n");
+		return 0;
+	}
+
+	/* Set 16/32 bit configuration */
+	if ((0 == (config_val & DDR_SATR_CONFIG_MASK_WIDTH)) ||
+	    (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] == 0)) {
+		/* 16bit by SatR of 32bit mode not supported for the board */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT] != 0)) {
+			tui->update_width = 1;
+			tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+		}
+	} else {
+		/* 32bit */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] != 0)) {
+			tui->update_width = 1;
+			tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+		}
+	}
+
+	/* Set ECC/no ECC bit configuration */
+	if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC)) {
+		/* NO ECC */
+		tui->update_ecc = 1;
+		tui->ecc = TOPOLOGY_UPDATE_ECC_OFF;
+	} else {
+		/* ECC */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) ||
+		    (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0) ||
+		    (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) {
+			tui->update_ecc = 1;
+			tui->ecc = TOPOLOGY_UPDATE_ECC_ON;
+		}
+	}
+
+	/* Set ECC pup bit configuration */
+	if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC_PUP)) {
+		/* PUP3 */
+		/*
+		 * Check if PUP3 configuration allowed, if not -
+		 * force Pup4 with warning message
+		 */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) {
+			if (tui->width == TOPOLOGY_UPDATE_WIDTH_16BIT) {
+				tui->update_ecc_pup3_mode = 1;
+				tui->ecc_pup_mode_offset =
+					TOPOLOGY_UPDATE_ECC_OFFSET_PUP3;
+			} else {
+				if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0)) {
+					printf("DDR Topology Update: ECC PUP3 not valid for 32bit mode, force ECC in PUP4\n");
+					tui->update_ecc_pup3_mode = 1;
+					tui->ecc_pup_mode_offset =
+						TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+				}
+			}
+		} else {
+			if (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] !=
+			    0) {
+				printf("DDR Topology Update: ECC on PUP3 not supported, force ECC on PUP4\n");
+				tui->update_ecc_pup3_mode = 1;
+				tui->ecc_pup_mode_offset =
+					TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+			}
+		}
+	} else {
+		/* PUP4 */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) ||
+		    (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0)) {
+			tui->update_ecc_pup3_mode = 1;
+			tui->ecc_pup_mode_offset =
+				TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+		}
+	}
+
+	/*
+	 * Check for forbidden ECC mode,
+	 * if by default width and pup selection set 32bit ECC mode and this
+	 * mode not supported for the board - config 16bit with ECC on PUP3
+	 */
+	if ((tui->ecc == TOPOLOGY_UPDATE_ECC_ON) &&
+	    (tui->width == TOPOLOGY_UPDATE_WIDTH_32BIT)) {
+		if (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] == 0) {
+			printf("DDR Topology Update: 32bit mode with ECC not allowed on this board, forced  16bit with ECC on PUP3\n");
+			tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+			tui->update_ecc_pup3_mode = 1;
+			tui->ecc_pup_mode_offset =
+				TOPOLOGY_UPDATE_ECC_OFFSET_PUP3;
+		}
+	}
+
+	return MV_OK;
+}
+#endif /* CONFIG_ARMADA_38X */
+#endif /* MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI */
diff --git a/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h
new file mode 100644
index 0000000..3e5373c
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _SYS_ENV_LIB_H
+#define _SYS_ENV_LIB_H
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
+#include "../../../drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h"
+
+/* Serdes definitions */
+#define COMMON_PHY_BASE_ADDR		0x18300
+
+#define DEVICE_CONFIGURATION_REG0	0x18284
+#define DEVICE_CONFIGURATION_REG1	0x18288
+#define COMMON_PHY_CONFIGURATION1_REG	0x18300
+#define COMMON_PHY_CONFIGURATION2_REG	0x18304
+#define COMMON_PHY_CONFIGURATION4_REG	0x1830c
+#define COMMON_PHY_STATUS1_REG		0x18318
+#define COMMON_PHYS_SELECTORS_REG	0x183fc
+#define SOC_CONTROL_REG1		0x18204
+#define GENERAL_PURPOSE_RESERVED0_REG	0x182e0
+#define GBE_CONFIGURATION_REG		0x18460
+#define DEVICE_SAMPLE_AT_RESET1_REG	0x18600
+#define DEVICE_SAMPLE_AT_RESET2_REG	0x18604
+#define DEV_ID_REG			0x18238
+
+#define CORE_PLL_PARAMETERS_REG		0xe42e0
+#define CORE_PLL_CONFIG_REG		0xe42e4
+
+#define QSGMII_CONTROL_REG1		0x18494
+
+#define DEV_ID_REG_DEVICE_ID_OFFS	16
+#define DEV_ID_REG_DEVICE_ID_MASK	0xffff0000
+
+#define SAR_DEV_ID_OFFS			27
+#define SAR_DEV_ID_MASK			0x7
+
+#define POWER_AND_PLL_CTRL_REG		0xa0004
+#define CALIBRATION_CTRL_REG		0xa0008
+#define DFE_REG0			0xa001c
+#define DFE_REG3			0xa0028
+#define RESET_DFE_REG			0xa0148
+#define LOOPBACK_REG			0xa008c
+#define SYNC_PATTERN_REG		0xa0090
+#define INTERFACE_REG			0xa0094
+#define ISOLATE_REG			0xa0098
+#define MISC_REG			0xa013c
+#define GLUE_REG			0xa0140
+#define GENERATION_DIVIDER_FORCE_REG	0xa0144
+#define PCIE_REG0			0xa0120
+#define LANE_ALIGN_REG0			0xa0124
+#define SQUELCH_FFE_SETTING_REG		0xa0018
+#define G1_SETTINGS_0_REG		0xa0034
+#define G1_SETTINGS_1_REG		0xa0038
+#define G1_SETTINGS_3_REG		0xa0440
+#define G1_SETTINGS_4_REG		0xa0444
+#define G2_SETTINGS_0_REG		0xa003c
+#define G2_SETTINGS_1_REG		0xa0040
+#define G2_SETTINGS_2_REG		0xa00f8
+#define G2_SETTINGS_3_REG		0xa0448
+#define G2_SETTINGS_4_REG		0xa044c
+#define G3_SETTINGS_0_REG		0xa0044
+#define G3_SETTINGS_1_REG		0xa0048
+#define G3_SETTINGS_3_REG		0xa0450
+#define G3_SETTINGS_4_REG		0xa0454
+#define VTHIMPCAL_CTRL_REG		0xa0104
+#define REF_REG0			0xa0134
+#define CAL_REG6			0xa0168
+#define RX_REG2				0xa0184
+#define RX_REG3				0xa0188
+#define PCIE_REG1			0xa0288
+#define PCIE_REG3			0xa0290
+#define LANE_CFG1_REG			0xa0604
+#define LANE_CFG4_REG			0xa0620
+#define LANE_CFG5_REG			0xa0624
+#define GLOBAL_CLK_CTRL			0xa0704
+#define GLOBAL_MISC_CTRL		0xa0718
+#define GLOBAL_CLK_SRC_HI		0xa0710
+
+#define GLOBAL_CLK_CTRL			0xa0704
+#define GLOBAL_MISC_CTRL		0xa0718
+#define GLOBAL_PM_CTRL			0xa0740
+
+/* SATA registers */
+#define SATA_CTRL_REG_IND_ADDR		0xa80a0
+#define SATA_CTRL_REG_IND_DATA		0xa80a4
+
+#define SATA_VENDOR_PORT_0_REG_ADDR	0xa8178
+#define SATA_VENDOR_PORT_1_REG_ADDR	0xa81f8
+#define SATA_VENDOR_PORT_0_REG_DATA	0xa817c
+#define SATA_VENDOR_PORT_1_REG_DATA	0xa81fc
+
+/* Reference clock values and mask */
+#define POWER_AND_PLL_CTRL_REG_100MHZ_VAL	0x0
+#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1	0x1
+#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2	0x2
+#define POWER_AND_PLL_CTRL_REG_40MHZ_VAL	0x3
+#define GLOBAL_PM_CTRL_REG_25MHZ_VAL		0x7
+#define GLOBAL_PM_CTRL_REG_40MHZ_VAL		0xc
+#define LANE_CFG4_REG_25MHZ_VAL			0x200
+#define LANE_CFG4_REG_40MHZ_VAL			0x300
+
+#define POWER_AND_PLL_CTRL_REG_MASK		(~(0x1f))
+#define GLOBAL_PM_CTRL_REG_MASK			(~(0xff))
+#define LANE_CFG4_REG_MASK			(~(0x1f00))
+
+#define REF_CLK_SELECTOR_VAL_PEX0(reg_val)	(reg_val >> 2) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX1(reg_val)	(reg_val >> 3) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX2(reg_val)	(reg_val >> 30) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX3(reg_val)	(reg_val >> 31) & 0x1
+#define REF_CLK_SELECTOR_VAL(reg_val)		(reg_val & 0x1)
+
+#define MAX_SELECTOR_VAL			10
+
+/* TWSI addresses */
+/* starting from A38x A0, i2c address of EEPROM is 0x57 */
+#ifdef CONFIG_ARMADA_39X
+#define EEPROM_I2C_ADDR			0x50
+#else
+#define EEPROM_I2C_ADDR			(sys_env_device_rev_get() == \
+					 MV_88F68XX_Z1_ID ? 0x50 : 0x57)
+#endif
+#define RD_GET_MODE_ADDR		0x4c
+#define DB_GET_MODE_SLM1363_ADDR	0x25
+#define DB_GET_MODE_SLM1364_ADDR	0x24
+#define DB381_GET_MODE_SLM1426_1427_ADDR 0x56
+
+/* DB-BP Board 'SatR' mapping */
+#define SATR_DB_LANE1_MAX_OPTIONS	7
+#define SATR_DB_LANE1_CFG_MASK		0x7
+#define SATR_DB_LANE1_CFG_OFFSET	0
+#define SATR_DB_LANE2_MAX_OPTIONS	4
+#define SATR_DB_LANE2_CFG_MASK		0x38
+#define SATR_DB_LANE2_CFG_OFFSET	3
+
+/* GP Board 'SatR' mapping */
+#define SATR_GP_LANE1_CFG_MASK		0x4
+#define SATR_GP_LANE1_CFG_OFFSET	2
+#define SATR_GP_LANE2_CFG_MASK		0x8
+#define SATR_GP_LANE2_CFG_OFFSET	3
+
+/* For setting MPP2 and MPP3 to be TWSI mode and MPP 0,1 to UART mode */
+#define MPP_CTRL_REG			0x18000
+#define MPP_SET_MASK			(~(0xffff))
+#define MPP_SET_DATA			(0x1111)
+#define MPP_UART1_SET_MASK		(~(0xff000))
+#define MPP_UART1_SET_DATA		(0x66000)
+
+#define AVS_DEBUG_CNTR_REG		0xe4124
+#define AVS_DEBUG_CNTR_DEFAULT_VALUE	0x08008073
+
+#define AVS_ENABLED_CONTROL		0xe4130
+#define AVS_LOW_VDD_LIMIT_OFFS		4
+#define AVS_LOW_VDD_LIMIT_MASK		(0xff << AVS_LOW_VDD_LIMIT_OFFS)
+#define AVS_LOW_VDD_LIMIT_VAL		(0x27 << AVS_LOW_VDD_LIMIT_OFFS)
+
+#define AVS_HIGH_VDD_LIMIT_OFFS		12
+#define AVS_HIGH_VDD_LIMIT_MASK		(0xff << AVS_HIGH_VDD_LIMIT_OFFS)
+#define AVS_HIGH_VDD_LIMIT_VAL		(0x27 << AVS_HIGH_VDD_LIMIT_OFFS)
+
+/* Board ID numbers */
+#define MARVELL_BOARD_ID_MASK		0x10
+/* Customer boards for A38x */
+#define A38X_CUSTOMER_BOARD_ID_BASE	0x0
+#define A38X_CUSTOMER_BOARD_ID0		(A38X_CUSTOMER_BOARD_ID_BASE + 0)
+#define A38X_CUSTOMER_BOARD_ID1		(A38X_CUSTOMER_BOARD_ID_BASE + 1)
+#define A38X_MV_MAX_CUSTOMER_BOARD_ID	(A38X_CUSTOMER_BOARD_ID_BASE + 2)
+#define A38X_MV_CUSTOMER_BOARD_NUM	(A38X_MV_MAX_CUSTOMER_BOARD_ID - \
+					 A38X_CUSTOMER_BOARD_ID_BASE)
+
+/* Marvell boards for A38x */
+#define A38X_MARVELL_BOARD_ID_BASE	0x10
+#define RD_NAS_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 0)
+#define DB_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 1)
+#define RD_AP_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 2)
+#define DB_AP_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 3)
+#define DB_GP_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 4)
+#define DB_BP_6821_ID			(A38X_MARVELL_BOARD_ID_BASE + 5)
+#define DB_AMC_6820_ID			(A38X_MARVELL_BOARD_ID_BASE + 6)
+#define A38X_MV_MAX_MARVELL_BOARD_ID	(A38X_MARVELL_BOARD_ID_BASE + 7)
+#define A38X_MV_MARVELL_BOARD_NUM	(A38X_MV_MAX_MARVELL_BOARD_ID - \
+					 A38X_MARVELL_BOARD_ID_BASE)
+
+/* Customer boards for A39x */
+#define A39X_CUSTOMER_BOARD_ID_BASE	0x20
+#define A39X_CUSTOMER_BOARD_ID0		(A39X_CUSTOMER_BOARD_ID_BASE + 0)
+#define A39X_CUSTOMER_BOARD_ID1		(A39X_CUSTOMER_BOARD_ID_BASE + 1)
+#define A39X_MV_MAX_CUSTOMER_BOARD_ID	(A39X_CUSTOMER_BOARD_ID_BASE + 2)
+#define A39X_MV_CUSTOMER_BOARD_NUM	(A39X_MV_MAX_CUSTOMER_BOARD_ID - \
+					 A39X_CUSTOMER_BOARD_ID_BASE)
+
+/* Marvell boards for A39x */
+#define A39X_MARVELL_BOARD_ID_BASE	0x30
+#define A39X_DB_69XX_ID			(A39X_MARVELL_BOARD_ID_BASE + 0)
+#define A39X_RD_69XX_ID			(A39X_MARVELL_BOARD_ID_BASE + 1)
+#define A39X_MV_MAX_MARVELL_BOARD_ID	(A39X_MARVELL_BOARD_ID_BASE + 2)
+#define A39X_MV_MARVELL_BOARD_NUM	(A39X_MV_MAX_MARVELL_BOARD_ID - \
+					 A39X_MARVELL_BOARD_ID_BASE)
+
+#ifdef CONFIG_ARMADA_38X
+#define CUTOMER_BOARD_ID_BASE		A38X_CUSTOMER_BOARD_ID_BASE
+#define CUSTOMER_BOARD_ID0		A38X_CUSTOMER_BOARD_ID0
+#define CUSTOMER_BOARD_ID1		A38X_CUSTOMER_BOARD_ID1
+#define MV_MAX_CUSTOMER_BOARD_ID	A38X_MV_MAX_CUSTOMER_BOARD_ID
+#define MV_CUSTOMER_BOARD_NUM		A38X_MV_CUSTOMER_BOARD_NUM
+#define MARVELL_BOARD_ID_BASE		A38X_MARVELL_BOARD_ID_BASE
+#define MV_MAX_MARVELL_BOARD_ID		A38X_MV_MAX_MARVELL_BOARD_ID
+#define MV_MARVELL_BOARD_NUM		A38X_MV_MARVELL_BOARD_NUM
+#define MV_DEFAULT_BOARD_ID		DB_68XX_ID
+#define MV_DEFAULT_DEVICE_ID		MV_6811
+#elif defined(CONFIG_ARMADA_39X)
+#define CUTOMER_BOARD_ID_BASE		A39X_CUSTOMER_BOARD_ID_BASE
+#define CUSTOMER_BOARD_ID0		A39X_CUSTOMER_BOARD_ID0
+#define CUSTOMER_BOARD_ID1		A39X_CUSTOMER_BOARD_ID1
+#define MV_MAX_CUSTOMER_BOARD_ID	A39X_MV_MAX_CUSTOMER_BOARD_ID
+#define MV_CUSTOMER_BOARD_NUM		A39X_MV_CUSTOMER_BOARD_NUM
+#define MARVELL_BOARD_ID_BASE		A39X_MARVELL_BOARD_ID_BASE
+#define MV_MAX_MARVELL_BOARD_ID		A39X_MV_MAX_MARVELL_BOARD_ID
+#define MV_MARVELL_BOARD_NUM		A39X_MV_MARVELL_BOARD_NUM
+#define MV_DEFAULT_BOARD_ID		A39X_DB_69XX_ID
+#define MV_DEFAULT_DEVICE_ID		MV_6920
+#endif
+
+#define MV_INVALID_BOARD_ID		0xffffffff
+
+/* device revesion */
+#define DEV_VERSION_ID_REG		0x1823c
+#define REVISON_ID_OFFS			8
+#define REVISON_ID_MASK			0xf00
+
+/* A38x revisions */
+#define MV_88F68XX_Z1_ID		0x0
+#define MV_88F68XX_A0_ID		0x4
+/* A39x revisions */
+#define MV_88F69XX_Z1_ID		0x2
+
+#define MPP_CONTROL_REG(id)		(0x18000 + (id * 4))
+#define GPP_DATA_OUT_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x00)
+#define GPP_DATA_OUT_EN_REG(grp)	(MV_GPP_REGS_BASE(grp) + 0x04)
+#define GPP_DATA_IN_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x10)
+#define MV_GPP_REGS_BASE(unit)		(0x18100 + ((unit) * 0x40))
+
+#define MPP_REG_NUM(GPIO_NUM)		(GPIO_NUM / 8)
+#define MPP_MASK(GPIO_NUM)		(0xf << 4 * (GPIO_NUM - \
+					(MPP_REG_NUM(GPIO_NUM) * 8)));
+#define GPP_REG_NUM(GPIO_NUM)		(GPIO_NUM / 32)
+#define GPP_MASK(GPIO_NUM)		(1 << GPIO_NUM % 32)
+
+/* device ID */
+/* Armada 38x Family */
+#define MV_6810_DEV_ID		0x6810
+#define MV_6811_DEV_ID		0x6811
+#define MV_6820_DEV_ID		0x6820
+#define MV_6828_DEV_ID		0x6828
+/* Armada 39x Family */
+#define MV_6920_DEV_ID		0x6920
+#define MV_6928_DEV_ID		0x6928
+
+enum {
+	MV_6810,
+	MV_6820,
+	MV_6811,
+	MV_6828,
+	MV_NONE,
+	MV_6920,
+	MV_6928,
+	MV_MAX_DEV_ID,
+};
+
+#define MV_6820_INDEX			0
+#define MV_6810_INDEX			1
+#define MV_6811_INDEX			2
+#define MV_6828_INDEX			3
+
+#define MV_6920_INDEX			0
+#define MV_6928_INDEX			1
+
+#ifdef CONFIG_ARMADA_38X
+#define MAX_DEV_ID_NUM			4
+#else
+#define MAX_DEV_ID_NUM			2
+#endif
+
+#define MV_6820_INDEX			0
+#define MV_6810_INDEX			1
+#define MV_6811_INDEX			2
+#define MV_6828_INDEX			3
+#define MV_6920_INDEX			0
+#define MV_6928_INDEX			1
+
+enum unit_id {
+	PEX_UNIT_ID,
+	ETH_GIG_UNIT_ID,
+	USB3H_UNIT_ID,
+	USB3D_UNIT_ID,
+	SATA_UNIT_ID,
+	QSGMII_UNIT_ID,
+	XAUI_UNIT_ID,
+	RXAUI_UNIT_ID,
+	MAX_UNITS_ID
+};
+
+struct board_wakeup_gpio {
+	u32 board_id;
+	int gpio_num;
+};
+
+enum suspend_wakeup_status {
+	SUSPEND_WAKEUP_DISABLED,
+	SUSPEND_WAKEUP_ENABLED,
+	SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED,
+};
+
+/*
+ * GPIO status indication for Suspend Wakeup:
+ * If suspend to RAM is supported and GPIO inidcation is implemented,
+ * set the gpio number
+ * If suspend to RAM is supported but GPIO indication is not implemented
+ * set '-2'
+ * If suspend to RAM is not supported set '-1'
+ */
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+#ifdef CONFIG_ARMADA_38X
+#define MV_BOARD_WAKEUP_GPIO_INFO {		\
+	{A38X_CUSTOMER_BOARD_ID0,	-1 },	\
+	{A38X_CUSTOMER_BOARD_ID0,	-1 },	\
+};
+#else
+#define MV_BOARD_WAKEUP_GPIO_INFO {		\
+	{A39X_CUSTOMER_BOARD_ID0,	-1 },	\
+	{A39X_CUSTOMER_BOARD_ID0,	-1 },	\
+};
+#endif /* CONFIG_ARMADA_38X */
+
+#else
+
+#ifdef CONFIG_ARMADA_38X
+#define MV_BOARD_WAKEUP_GPIO_INFO {	\
+	{RD_NAS_68XX_ID, -2 },		\
+	{DB_68XX_ID,	 -1 },		\
+	{RD_AP_68XX_ID,	 -2 },		\
+	{DB_AP_68XX_ID,	 -2 },		\
+	{DB_GP_68XX_ID,	 -2 },		\
+	{DB_BP_6821_ID,	 -2 },		\
+	{DB_AMC_6820_ID, -2 },		\
+};
+#else
+#define MV_BOARD_WAKEUP_GPIO_INFO {	\
+	{A39X_RD_69XX_ID, -1 },		\
+	{A39X_DB_69XX_ID, -1 },		\
+};
+#endif /* CONFIG_ARMADA_38X */
+#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */
+
+u32 mv_board_tclk_get(void);
+u32 mv_board_id_get(void);
+u32 mv_board_id_index_get(u32 board_id);
+u32 sys_env_unit_max_num_get(enum unit_id unit);
+enum suspend_wakeup_status sys_env_suspend_wakeup_check(void);
+u8 sys_env_device_rev_get(void);
+u32 sys_env_device_id_get(void);
+u16 sys_env_model_get(void);
+struct dlb_config *sys_env_dlb_config_ptr_get(void);
+u32 sys_env_get_topology_update_info(
+	struct topology_update_info *topology_update_info);
+u32 sys_env_get_cs_ena_from_reg(void);
+
+#endif /* _SYS_ENV_LIB_H */
diff --git a/arch/arm/mach-mvebu/serdes/Makefile b/arch/arm/mach-mvebu/serdes/axp/Makefile
similarity index 100%
rename from arch/arm/mach-mvebu/serdes/Makefile
rename to arch/arm/mach-mvebu/serdes/axp/Makefile
diff --git a/arch/arm/mach-mvebu/serdes/board_env_spec.h b/arch/arm/mach-mvebu/serdes/axp/board_env_spec.h
similarity index 100%
rename from arch/arm/mach-mvebu/serdes/board_env_spec.h
rename to arch/arm/mach-mvebu/serdes/axp/board_env_spec.h
diff --git a/arch/arm/mach-mvebu/serdes/high_speed_env_lib.c b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c
similarity index 100%
rename from arch/arm/mach-mvebu/serdes/high_speed_env_lib.c
rename to arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c
diff --git a/arch/arm/mach-mvebu/serdes/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c
similarity index 100%
rename from arch/arm/mach-mvebu/serdes/high_speed_env_spec.c
rename to arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c
diff --git a/arch/arm/mach-mvebu/serdes/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h
similarity index 97%
rename from arch/arm/mach-mvebu/serdes/high_speed_env_spec.h
rename to arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h
index e5aa1b0..e10574e 100644
--- a/arch/arm/mach-mvebu/serdes/high_speed_env_spec.h
+++ b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h
@@ -7,7 +7,7 @@
 #ifndef __HIGHSPEED_ENV_SPEC_H
 #define __HIGHSPEED_ENV_SPEC_H
 
-#include "../../../drivers/ddr/mvebu/ddr3_hw_training.h"
+#include "../../../drivers/ddr/marvell/axp/ddr3_hw_training.h"
 
 typedef enum {
 	SERDES_UNIT_UNCONNECTED	= 0x0,
diff --git a/arch/arm/mach-mvebu/spl.c b/arch/arm/mach-mvebu/spl.c
index 402e520..af61ded 100644
--- a/arch/arm/mach-mvebu/spl.c
+++ b/arch/arm/mach-mvebu/spl.c
@@ -14,10 +14,21 @@
 
 u32 spl_boot_device(void)
 {
-	/* Right now only booting via SPI NOR flash is supported */
+#if defined(CONFIG_SPL_SPI_FLASH_SUPPORT)
 	return BOOT_DEVICE_SPI;
+#endif
+#if defined(CONFIG_SPL_MMC_SUPPORT)
+	return BOOT_DEVICE_MMC1;
+#endif
 }
 
+#ifdef CONFIG_SPL_MMC_SUPPORT
+u32 spl_boot_mode(void)
+{
+	return MMCSD_MODE_RAW;
+}
+#endif
+
 void board_init_f(ulong dummy)
 {
 	/* Set global data pointer */
@@ -26,8 +37,17 @@
 	/* Linux expects the internal registers to be at 0xf1000000 */
 	arch_cpu_init();
 
+	/*
+	 * Pin muxing needs to be done before UART output, since
+	 * on A38x the UART pins need some re-muxing for output
+	 * to work.
+	 */
+	board_early_init_f();
+
 	preloader_console_init();
 
+	timer_init();
+
 	/* First init the serdes PHY's */
 	serdes_phy_config();
 
diff --git a/arch/arm/mach-mvebu/timer.c b/arch/arm/mach-mvebu/timer.c
index 40c4bc2..c516c41 100644
--- a/arch/arm/mach-mvebu/timer.c
+++ b/arch/arm/mach-mvebu/timer.c
@@ -41,6 +41,8 @@
 #define timestamp			gd->arch.tbl
 #define lastdec				gd->arch.lastinc
 
+static int init_done;
+
 /* Timer reload and current value registers */
 struct kwtmr_val {
 	u32 reload;	/* Timer reload reg */
@@ -112,6 +114,11 @@
  */
 int timer_init(void)
 {
+	/* Only init the timer once */
+	if (init_done)
+		return 0;
+	init_done = 1;
+
 	/* load value into timer */
 	writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR));
 	writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR));
diff --git a/arch/arm/mach-uniphier/Kconfig b/arch/arm/mach-uniphier/Kconfig
index feda49e..7b49ad3 100644
--- a/arch/arm/mach-uniphier/Kconfig
+++ b/arch/arm/mach-uniphier/Kconfig
@@ -10,13 +10,17 @@
 	prompt "UniPhier SoC select"
 	default MACH_PH1_PRO4
 
-config MACH_PH1_PRO4
-	bool "PH1-Pro4"
+config MACH_PH1_SLD3
+	bool "PH1-sLD3"
 	select UNIPHIER_SMP
 
 config MACH_PH1_LD4
 	bool "PH1-LD4"
 
+config MACH_PH1_PRO4
+	bool "PH1-Pro4"
+	select UNIPHIER_SMP
+
 config MACH_PH1_SLD8
 	bool "PH1-sLD8"
 
@@ -64,11 +68,11 @@
 
 config DDR_FREQ_1600
 	bool "DDR3 1600"
-	depends on MACH_PH1_PRO4 || MACH_PH1_LD4
+	depends on MACH_PH1_SLD3 || MACH_PH1_LD4 || MACH_PH1_PRO4
 
 config DDR_FREQ_1333
 	bool "DDR3 1333"
-	depends on MACH_PH1_LD4 || MACH_PH1_SLD8
+	depends on MACH_PH1_SLD3 || MACH_PH1_LD4 || MACH_PH1_SLD8
 
 endchoice
 
diff --git a/arch/arm/mach-uniphier/Makefile b/arch/arm/mach-uniphier/Makefile
index 24591d6..103db6d 100644
--- a/arch/arm/mach-uniphier/Makefile
+++ b/arch/arm/mach-uniphier/Makefile
@@ -32,6 +32,7 @@
 obj-$(CONFIG_PFC_MICRO_SUPPORT_CARD) += support_card.o
 obj-$(CONFIG_DCC_MICRO_SUPPORT_CARD) += support_card.o
 
-obj-$(CONFIG_MACH_PH1_LD4) += ph1-ld4/
-obj-$(CONFIG_MACH_PH1_PRO4) += ph1-pro4/
-obj-$(CONFIG_MACH_PH1_SLD8) += ph1-sld8/
+obj-$(CONFIG_MACH_PH1_SLD3)	+= ph1-sld3/
+obj-$(CONFIG_MACH_PH1_LD4)	+= ph1-ld4/
+obj-$(CONFIG_MACH_PH1_PRO4)	+= ph1-pro4/
+obj-$(CONFIG_MACH_PH1_SLD8)	+= ph1-sld8/
diff --git a/arch/arm/mach-uniphier/include/mach/sc-regs.h b/arch/arm/mach-uniphier/include/mach/sc-regs.h
index 20878e2..df50294 100644
--- a/arch/arm/mach-uniphier/include/mach/sc-regs.h
+++ b/arch/arm/mach-uniphier/include/mach/sc-regs.h
@@ -1,7 +1,7 @@
 /*
  * UniPhier SC (System Control) block registers
  *
- * Copyright (C) 2011-2015 Panasonic Corporation
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
  *
  * SPDX-License-Identifier:	GPL-2.0+
  */
@@ -9,7 +9,11 @@
 #ifndef ARCH_SC_REGS_H
 #define ARCH_SC_REGS_H
 
+#if defined(CONFIG_MACH_PH1_SLD3)
+#define SC_BASE_ADDR			0xf1840000
+#else
 #define SC_BASE_ADDR			0x61840000
+#endif
 
 #define SC_DPLLCTRL			(SC_BASE_ADDR | 0x1200)
 #define SC_DPLLCTRL_SSC_EN		(0x1 << 31)
diff --git a/arch/arm/mach-uniphier/include/mach/sg-regs.h b/arch/arm/mach-uniphier/include/mach/sg-regs.h
index a65f058..43a6c35 100644
--- a/arch/arm/mach-uniphier/include/mach/sg-regs.h
+++ b/arch/arm/mach-uniphier/include/mach/sg-regs.h
@@ -55,11 +55,12 @@
 
 #if defined(CONFIG_MACH_PH1_PRO4)
 # define SG_PINCTRL(n)			(SG_PINCTRL_BASE + (n) * 8)
-#elif defined(CONFIG_MACH_PH1_LD4) || defined(CONFIG_MACH_PH1_SLD8)
+#elif defined(CONFIG_MACH_PH1_SLD3) || defined(CONFIG_MACH_PH1_LD4) || \
+	defined(CONFIG_MACH_PH1_SLD8)
 # define SG_PINCTRL(n)			(SG_PINCTRL_BASE + (n) * 4)
 #endif
 
-#if defined(CONFIG_MACH_PH1_PRO4)
+#if defined(CONFIG_MACH_PH1_SLD3) || defined(CONFIG_MACH_PH1_PRO4)
 #define SG_PINSELBITS			4
 #elif defined(CONFIG_MACH_PH1_LD4) || defined(CONFIG_MACH_PH1_SLD8)
 #define SG_PINSELBITS			8
diff --git a/arch/arm/mach-uniphier/ph1-sld3/Makefile b/arch/arm/mach-uniphier/ph1-sld3/Makefile
new file mode 100644
index 0000000..f3f7ad4
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/Makefile
@@ -0,0 +1,16 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_DEBUG_LL) += lowlevel_debug.o
+obj-y += bcu_init.o memconf.o sg_init.o pll_init.o early_clkrst_init.o \
+	early_pinctrl.o pll_spectrum.o umc_init.o
+obj-$(CONFIG_PFC_MICRO_SUPPORT_CARD) += sbc_init.o
+obj-$(CONFIG_DCC_MICRO_SUPPORT_CARD) += sbc_init_3cs.o
+obj-$(CONFIG_SPL_DM) += platdevice.o
+else
+obj-$(CONFIG_BOARD_EARLY_INIT_F) += pinctrl.o clkrst_init.o
+endif
+
+obj-y += boot-mode.o
diff --git a/arch/arm/mach-uniphier/ph1-sld3/bcu_init.c b/arch/arm/mach-uniphier/ph1-sld3/bcu_init.c
new file mode 100644
index 0000000..ccc6897
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/bcu_init.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <mach/bcu-regs.h>
+
+#define ch(x) ((x) >= 32 ? 0 : (x) < 0 ? 0x11111111 : 0x11111111 << (x))
+
+void bcu_init(void)
+{
+	int shift;
+
+	writel(0x11111111, BCSCR2); /* 0x80000000-0x9fffffff: IPPC/IPPD-bus */
+	writel(0x11111111, BCSCR3); /* 0xa0000000-0xbfffffff: IPPC/IPPD-bus */
+	writel(0x11111111, BCSCR4); /* 0xc0000000-0xdfffffff: IPPC/IPPD-bus */
+	/*
+	 * 0xe0000000-0xefffffff: Ex-bus
+	 * 0xf0000000-0xfbffffff: ASM bus
+	 * 0xfc000000-0xffffffff: OCM bus
+	 */
+	writel(0x24440000, BCSCR5);
+
+	/* Specify DDR channel */
+	shift = (CONFIG_SDRAM1_BASE - CONFIG_SDRAM0_BASE) / 0x04000000 * 4;
+	writel(ch(shift), BCIPPCCHR2); /* 0x80000000-0x9fffffff */
+
+	shift -= 32;
+	writel(ch(shift), BCIPPCCHR3); /* 0xa0000000-0xbfffffff */
+
+	shift -= 32;
+	writel(ch(shift), BCIPPCCHR4); /* 0xc0000000-0xdfffffff */
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/boot-mode.c b/arch/arm/mach-uniphier/ph1-sld3/boot-mode.c
new file mode 100644
index 0000000..40000af
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/boot-mode.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <linux/io.h>
+#include <mach/boot-device.h>
+#include <mach/sg-regs.h>
+#include <mach/sbc-regs.h>
+
+struct boot_device_info boot_device_table[] = {
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "External Master"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_MMC1, "eMMC (3.3V, Boot Oparation)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_MMC1, "eMMC (1.8V, Boot Oparation)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_MMC1, "eMMC (3.3V, Normal)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_MMC1, "eMMC (1.8V, Normal)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC  8, EraseSize 128KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC  8, EraseSize 256KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC  8, EraseSize 512KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 256KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 512KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 4, ECC 24, EraseSize   1MB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC  8, EraseSize 128KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC  8, EraseSize 256KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC  8, EraseSize 512KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 256KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 512KB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 24, EraseSize   1MB, Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC  8, ONFI,            Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI,            Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 4, ECC 24, ONFI,            Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC  8, ONFI,            Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI,            Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 24, ONFI,            Addr 5)"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{BOOT_DEVICE_NONE, "Reserved"},
+	{ /* sentinel */ }
+};
+
+int get_boot_mode_sel(void)
+{
+	return readl(SG_PINMON0) & 0x3f;
+}
+
+u32 spl_boot_device(void)
+{
+	int boot_mode;
+
+	if (boot_is_swapped())
+		return BOOT_DEVICE_NOR;
+
+	boot_mode = get_boot_mode_sel();
+
+	return boot_device_table[boot_mode].type;
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/clkrst_init.c b/arch/arm/mach-uniphier/ph1-sld3/clkrst_init.c
new file mode 100644
index 0000000..3a3dab7
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/clkrst_init.c
@@ -0,0 +1 @@
+#include "../ph1-pro4/clkrst_init.c"
diff --git a/arch/arm/mach-uniphier/ph1-sld3/early_clkrst_init.c b/arch/arm/mach-uniphier/ph1-sld3/early_clkrst_init.c
new file mode 100644
index 0000000..d7ef16b
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/early_clkrst_init.c
@@ -0,0 +1 @@
+#include "../ph1-pro4/early_clkrst_init.c"
diff --git a/arch/arm/mach-uniphier/ph1-sld3/early_pinctrl.c b/arch/arm/mach-uniphier/ph1-sld3/early_pinctrl.c
new file mode 100644
index 0000000..f113e65
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/early_pinctrl.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <mach/sg-regs.h>
+
+void early_pin_init(void)
+{
+	/* Comment format:    PAD Name -> Function Name */
+
+#ifdef CONFIG_UNIPHIER_SERIAL
+	sg_set_pinsel(63, 0);	/* RXD0 */
+	sg_set_pinsel(64, 1);	/* TXD0 */
+
+	sg_set_pinsel(65, 0);	/* RXD1 */
+	sg_set_pinsel(66, 1);	/* TXD1 */
+
+	sg_set_pinsel(96, 2);	/* RXD2 */
+	sg_set_pinsel(102, 2);	/* TXD2 */
+#endif
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/lowlevel_debug.S b/arch/arm/mach-uniphier/ph1-sld3/lowlevel_debug.S
new file mode 100644
index 0000000..9d1fd2c
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/lowlevel_debug.S
@@ -0,0 +1,31 @@
+/*
+ * On-chip UART initializaion for low-level debugging
+ *
+ * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <linux/linkage.h>
+#include <mach/bcu-regs.h>
+#include <mach/sc-regs.h>
+#include <mach/sg-regs.h>
+#include <mach/debug-uart.S>
+
+ENTRY(setup_lowlevel_debug)
+		ldr		r0, =BCSCR5
+		ldr		r1, =0x24440000
+		str		r1, [r0]
+
+		ldr		r0, =SC_CLKCTRL
+		ldr		r1, [r0]
+		orr		r1, r1, #SC_CLKCTRL_CEN_PERI
+		str		r1, [r0]
+
+		init_debug_uart	r0, r1, r2
+
+		set_pinsel	63, 0, r0, r1
+		set_pinsel	64, 1, r0, r1
+
+		mov		pc, lr
+ENDPROC(setup_lowlevel_debug)
diff --git a/arch/arm/mach-uniphier/ph1-sld3/memconf.c b/arch/arm/mach-uniphier/ph1-sld3/memconf.c
new file mode 100644
index 0000000..553a9e3
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/memconf.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <linux/sizes.h>
+#include <mach/sg-regs.h>
+
+static inline u32 sg_memconf_val_ch2(unsigned long size, int num)
+{
+	int size_mb = size / num;
+	u32 ret;
+
+	switch (size_mb) {
+	case SZ_64M:
+		ret = SG_MEMCONF_CH2_SZ_64M;
+		break;
+	case SZ_128M:
+		ret = SG_MEMCONF_CH2_SZ_128M;
+		break;
+	case SZ_256M:
+		ret = SG_MEMCONF_CH2_SZ_256M;
+		break;
+	case SZ_512M:
+		ret = SG_MEMCONF_CH2_SZ_512M;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	switch (num) {
+	case 1:
+		ret |= SG_MEMCONF_CH2_NUM_1;
+		break;
+	case 2:
+		ret |= SG_MEMCONF_CH2_NUM_2;
+		break;
+	default:
+		BUG();
+		break;
+	}
+	return ret;
+}
+
+u32 memconf_additional_val(void)
+{
+	return sg_memconf_val_ch2(CONFIG_SDRAM2_SIZE, CONFIG_DDR_NUM_CH2);
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/pinctrl.c b/arch/arm/mach-uniphier/ph1-sld3/pinctrl.c
new file mode 100644
index 0000000..5ecbe4c
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/pinctrl.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <mach/sg-regs.h>
+
+void pin_init(void)
+{
+#ifdef CONFIG_USB_EHCI_UNIPHIER
+	sg_set_pinsel(13, 0);	/* USB0OC */
+	sg_set_pinsel(14, 1);	/* USB0VBUS */
+
+	sg_set_pinsel(15, 0);	/* USB1OC */
+	sg_set_pinsel(16, 1);	/* USB1VBUS */
+
+	sg_set_pinsel(17, 0);	/* USB2OC */
+	sg_set_pinsel(18, 1);	/* USB2VBUS */
+
+	sg_set_pinsel(19, 0);	/* USB3OC */
+	sg_set_pinsel(20, 1);	/* USB3VBUS */
+#endif
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/platdevice.c b/arch/arm/mach-uniphier/ph1-sld3/platdevice.c
new file mode 100644
index 0000000..6521067
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/platdevice.c
@@ -0,0 +1 @@
+#include "../ph1-ld4/platdevice.c"
diff --git a/arch/arm/mach-uniphier/ph1-sld3/pll_init.c b/arch/arm/mach-uniphier/ph1-sld3/pll_init.c
new file mode 100644
index 0000000..ebd1c31
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/pll_init.c
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+void pll_init(void)
+{
+	/* add pll init code here */
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/pll_spectrum.c b/arch/arm/mach-uniphier/ph1-sld3/pll_spectrum.c
new file mode 100644
index 0000000..fcf2ad2
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/pll_spectrum.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <mach/sc-regs.h>
+
+void enable_dpll_ssc(void)
+{
+	u32 tmp;
+
+	tmp = readl(SC_DPLLCTRL);
+	tmp |= SC_DPLLCTRL_SSC_EN;
+	writel(tmp, SC_DPLLCTRL);
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/sbc_init.c b/arch/arm/mach-uniphier/ph1-sld3/sbc_init.c
new file mode 100644
index 0000000..d66f89e
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/sbc_init.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <mach/sbc-regs.h>
+#include <mach/sg-regs.h>
+
+void sbc_init(void)
+{
+	/* only address/data multiplex mode is supported */
+
+	/*
+	 * Only CS1 is connected to support card.
+	 * BKSZ[1:0] should be set to "01".
+	 */
+	writel(SBCTRL0_ADMULTIPLX_MEM_VALUE, SBCTRL10);
+	writel(SBCTRL1_ADMULTIPLX_MEM_VALUE, SBCTRL11);
+	writel(SBCTRL2_ADMULTIPLX_MEM_VALUE, SBCTRL12);
+
+	if (boot_is_swapped()) {
+		/*
+		 * Boot Swap On: boot from external NOR/SRAM
+		 * 0x02000000-0x03ffffff is a mirror of 0x00000000-0x01ffffff.
+		 *
+		 * 0x00000000-0x01efffff, 0x02000000-0x03efffff: memory bank
+		 * 0x01f00000-0x01ffffff, 0x03f00000-0x03ffffff: peripherals
+		 */
+		writel(0x0000bc01, SBBASE0);
+	} else {
+		/*
+		 * Boot Swap Off: boot from mask ROM
+		 * 0x00000000-0x01ffffff: mask ROM
+		 * 0x02000000-0x03efffff: memory bank (31MB)
+		 * 0x03f00000-0x03ffffff: peripherals (1MB)
+		 */
+		writel(0x0000be01, SBBASE0); /* dummy */
+		writel(0x0200be01, SBBASE1);
+	}
+
+	sg_set_pinsel(99, 1);	/* GPIO26 -> EA24 */
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/sbc_init_3cs.c b/arch/arm/mach-uniphier/ph1-sld3/sbc_init_3cs.c
new file mode 100644
index 0000000..f5e2446
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/sbc_init_3cs.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <mach/sbc-regs.h>
+#include <mach/sg-regs.h>
+
+void sbc_init(void)
+{
+	/* only address/data multiplex mode is supported */
+
+	/* XECS0 : boot/sub memory (boot swap = off/on) */
+	writel(SBCTRL0_ADMULTIPLX_MEM_VALUE, SBCTRL00);
+	writel(SBCTRL1_ADMULTIPLX_MEM_VALUE, SBCTRL01);
+	writel(SBCTRL2_ADMULTIPLX_MEM_VALUE, SBCTRL02);
+
+	/* XECS1 : sub/boot memory (boot swap = off/on) */
+	writel(SBCTRL0_ADMULTIPLX_MEM_VALUE, SBCTRL10);
+	writel(SBCTRL1_ADMULTIPLX_MEM_VALUE, SBCTRL11);
+	writel(SBCTRL2_ADMULTIPLX_MEM_VALUE, SBCTRL12);
+
+	/* XECS2 : peripherals */
+	writel(SBCTRL0_ADMULTIPLX_PERI_VALUE, SBCTRL20);
+	writel(SBCTRL1_ADMULTIPLX_PERI_VALUE, SBCTRL21);
+	writel(SBCTRL2_ADMULTIPLX_PERI_VALUE, SBCTRL22);
+
+	/* base address regsiters */
+	writel(0x0000bc01, SBBASE0);
+	writel(0x0400bc01, SBBASE1);
+	writel(0x0800bf01, SBBASE2);
+
+	sg_set_pinsel(99, 1);	/* GPIO26 -> EA24 */
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/sg_init.c b/arch/arm/mach-uniphier/ph1-sld3/sg_init.c
new file mode 100644
index 0000000..ca3cb9c
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/sg_init.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+void sg_init(void)
+{
+}
diff --git a/arch/arm/mach-uniphier/ph1-sld3/umc_init.c b/arch/arm/mach-uniphier/ph1-sld3/umc_init.c
new file mode 100644
index 0000000..91ee3de
--- /dev/null
+++ b/arch/arm/mach-uniphier/ph1-sld3/umc_init.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+
+int umc_init(void)
+{
+	/* add UMC init code here */
+	printf("Implement memory init code\n");
+
+	return 0;
+}
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c
index d2885dc..6444be8 100644
--- a/arch/arm/mach-zynq/clk.c
+++ b/arch/arm/mach-zynq/clk.c
@@ -48,11 +48,11 @@
 struct clk;
 
 /**
- * struct clk_ops:
+ * struct zynq_clk_ops:
  * @set_rate:	Function pointer to set_rate() implementation
  * @get_rate:	Function pointer to get_rate() implementation
  */
-struct clk_ops {
+struct zynq_clk_ops {
 	int (*set_rate)(struct clk *clk, unsigned long rate);
 	unsigned long (*get_rate)(struct clk *clk);
 };
@@ -72,7 +72,7 @@
 	enum zynq_clk	parent;
 	unsigned int	flags;
 	u32		*reg;
-	struct clk_ops	ops;
+	struct zynq_clk_ops	ops;
 };
 #define ZYNQ_CLK_FLAGS_HAS_2_DIVS	1
 
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index e6ddb17..3a7f5a0 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -20,7 +20,7 @@
 unsigned long map_len;
 #endif
 
-void reset_cpu(ulong ignored)
+void sandbox_exit(void)
 {
 	/* Do this here while it still has an effect */
 	os_fd_restore();
@@ -34,13 +34,6 @@
 	os_exit(0);
 }
 
-int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	reset_cpu(0);
-
-	return 0;
-}
-
 /* delay x useconds */
 void __udelay(unsigned long usec)
 {
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index cae731c..7e5d03e 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -345,6 +345,10 @@
 	state->ram_buf = os_malloc(state->ram_size);
 	assert(state->ram_buf);
 
+	/* No reset yet, so mark it as such. Always allow power reset */
+	state->last_reset = RESET_COUNT;
+	state->reset_allowed[RESET_POWER] = true;
+
 	/*
 	 * Example of how to use GPIOs:
 	 *
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index c25614a..c948df8 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -4,7 +4,7 @@
 	model = "sandbox";
 	compatible = "sandbox";
 	#address-cells = <1>;
-	#size-cells = <0>;
+	#size-cells = <1>;
 
 	aliases {
 		console = &uart0;
@@ -28,7 +28,7 @@
 	};
 
 	a-test {
-		reg = <0>;
+		reg = <0 1>;
 		compatible = "denx,u-boot-fdt-test";
 		ping-expect = <0>;
 		ping-add = <0>;
@@ -41,16 +41,16 @@
 	};
 
 	junk {
-		reg = <1>;
+		reg = <1 1>;
 		compatible = "not,compatible";
 	};
 
 	no-compatible {
-		reg = <2>;
+		reg = <2 1>;
 	};
 
 	b-test {
-		reg = <3>;
+		reg = <3 1>;
 		compatible = "denx,u-boot-fdt-test";
 		ping-expect = <3>;
 		ping-add = <3>;
@@ -60,7 +60,7 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "denx,u-boot-test-bus";
-		reg = <3>;
+		reg = <3 1>;
 		ping-expect = <4>;
 		ping-add = <4>;
 		c-test@5 {
@@ -84,14 +84,14 @@
 	};
 
 	d-test {
-		reg = <3>;
+		reg = <3 1>;
 		ping-expect = <6>;
 		ping-add = <6>;
 		compatible = "google,another-fdt-test";
 	};
 
 	e-test {
-		reg = <3>;
+		reg = <3 1>;
 		ping-expect = <6>;
 		ping-add = <6>;
 		compatible = "google,another-fdt-test";
@@ -105,6 +105,10 @@
 		compatible = "denx,u-boot-fdt-test";
 	};
 
+	clk@0 {
+		compatible = "sandbox,clk";
+	};
+
 	eth@10002000 {
 		compatible = "sandbox,eth";
 		reg = <0x10002000 0x1000>;
@@ -142,7 +146,7 @@
 	i2c@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		reg = <0>;
+		reg = <0 1>;
 		compatible = "sandbox,i2c";
 		clock-frequency = <100000>;
 		eeprom@2c {
@@ -176,6 +180,24 @@
 		};
 	};
 
+	leds {
+		compatible = "gpio-leds";
+
+		iracibble {
+			gpios = <&gpio_a 1 0>;
+			label = "sandbox:red";
+		};
+
+		martinet {
+			gpios = <&gpio_a 2 0>;
+			label = "sandbox:green";
+		};
+	};
+
+	mmc {
+		compatible = "sandbox,mmc";
+	};
+
 	pci: pci-controller {
 		compatible = "sandbox,pci";
 		device_type = "pci";
@@ -192,10 +214,22 @@
 		};
 	};
 
+	ram {
+		compatible = "sandbox,ram";
+	};
+
+	reset@0 {
+		compatible = "sandbox,warm-reset";
+	};
+
+	reset@1 {
+		compatible = "sandbox,reset";
+	};
+
 	spi@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		reg = <0>;
+		reg = <0 1>;
 		compatible = "sandbox,spi";
 		cs-gpios = <0>, <&gpio_a 0>;
 		spi.bin@0 {
@@ -206,6 +240,19 @@
 		};
 	};
 
+	syscon@0 {
+		compatible = "sandbox,syscon0";
+		reg = <0x10 4>;
+	};
+
+	syscon@1 {
+		compatible = "sandbox,syscon1";
+		reg = <0x20 5
+			0x28 6
+			0x30 7
+			0x38 8>;
+	};
+
 	uart0: serial {
 		compatible = "sandbox,serial";
 		u-boot,dm-pre-reloc;
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index a57480a..2bd28f6 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -7,6 +7,7 @@
 #define __SANDBOX_STATE_H
 
 #include <config.h>
+#include <reset.h>
 #include <stdbool.h>
 #include <linux/stringify.h>
 
@@ -59,6 +60,8 @@
 	bool write_state;		/* Write sandbox state on exit */
 	bool ignore_missing_state_on_read;	/* No error if state missing */
 	bool show_lcd;			/* Show LCD on start-up */
+	enum reset_t last_reset;	/* Last reset type */
+	bool reset_allowed[RESET_COUNT];	/* Allowed reset types */
 	enum state_terminal_raw term_raw;	/* Terminal raw/cooked */
 
 	/* Pointer to information for each SPI bus/cs */
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 91a5c79..d3c7851 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -17,6 +17,25 @@
 #define SANDBOX_PCI_CLASS_CODE		PCI_CLASS_CODE_COMM
 #define SANDBOX_PCI_CLASS_SUB_CODE	PCI_CLASS_SUB_CODE_COMM_SERIAL
 
+#define SANDBOX_CLK_RATE		32768
+
+enum {
+	PERIPH_ID_FIRST = 0,
+	PERIPH_ID_SPI = PERIPH_ID_FIRST,
+	PERIPH_ID_I2C,
+	PERIPH_ID_PCI,
+
+	PERIPH_ID_COUNT,
+};
+
+/* System controller driver data */
+enum {
+	SYSCON0		= 32,
+	SYSCON1,
+
+	SYSCON_COUNT
+};
+
 /**
  * sandbox_i2c_set_test_mode() - set test mode for running unit tests
  *
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h
index da87cc3..2f3c3f9 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -83,4 +83,7 @@
  */
 int sandbox_read_fdt_from_file(void);
 
+/* Exit sandbox (quit U-Boot) */
+void sandbox_exit(void);
+
 #endif	/* _U_BOOT_SANDBOX_H_ */
diff --git a/arch/x86/include/asm/interrupt.h b/arch/x86/include/asm/interrupt.h
index 0a75f89..00cbe07 100644
--- a/arch/x86/include/asm/interrupt.h
+++ b/arch/x86/include/asm/interrupt.h
@@ -16,10 +16,6 @@
 /* arch/x86/cpu/interrupts.c */
 void set_vector(u8 intnum, void *routine);
 
-/* arch/x86/lib/interrupts.c */
-void disable_irq(int irq);
-void enable_irq(int irq);
-
 /* Architecture specific functions */
 void mask_irq(int irq);
 void unmask_irq(int irq);
diff --git a/board/Marvell/db-88f6820-gp/README b/board/Marvell/db-88f6820-gp/README
new file mode 100644
index 0000000..9bea5b3
--- /dev/null
+++ b/board/Marvell/db-88f6820-gp/README
@@ -0,0 +1,18 @@
+Update from original Marvell U-Boot to mainline U-Boot:
+-------------------------------------------------------
+
+The resulting image including the SPL binary with the
+full DDR setup is "u-boot-spl.kwb".
+
+To update the SPI NOR flash, please use the following
+command:
+
+=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\
+sf update 2000000 0 60000
+
+Note that the original Marvell U-Boot seems to have
+problems with the "sf update" command. This does not
+work reliable. So here this command should be used:
+
+=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\
+sf erase 0 60000;sf write 2000000 0 60000
diff --git a/board/Marvell/db-88f6820-gp/db-88f6820-gp.c b/board/Marvell/db-88f6820-gp/db-88f6820-gp.c
index 51ac495..e661fa1 100644
--- a/board/Marvell/db-88f6820-gp/db-88f6820-gp.c
+++ b/board/Marvell/db-88f6820-gp/db-88f6820-gp.c
@@ -11,6 +11,8 @@
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
 
+#include "../drivers/ddr/marvell/a38x/ddr3_a38x_topology.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #define BIT(nr)				(1UL << (nr))
@@ -54,6 +56,35 @@
 	{ 0x21, 3, 0xC0 }  /* Output Data, register#1 */
 };
 
+/*
+ * Define the DDR layout / topology here in the board file. This will
+ * be used by the DDR3 init code in the SPL U-Boot version to configure
+ * the DDR3 controller.
+ */
+static struct hws_topology_map board_topology_map = {
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X PUPs */
+	{ { { {0x1, 0, 0, 0},
+	      {0x1, 0, 0, 0},
+	      {0x1, 0, 0, 0},
+	      {0x1, 0, 0, 0},
+	      {0x1, 0, 0, 0} },
+	    SPEED_BIN_DDR_1866L,	/* speed_bin */
+	    BUS_WIDTH_8,		/* memory_width */
+	    MEM_4G,			/* mem_size */
+	    DDR_FREQ_800,		/* frequency */
+	    0, 0,			/* cas_l cas_wl */
+	    HWS_TEMP_LOW} },		/* temperature */
+	5,				/* Num Of Bus Per Interface*/
+	BUS_MASK_32BIT			/* Busses mask */
+};
+
+struct hws_topology_map *ddr3_get_topology_map(void)
+{
+	/* Return the board topology as defined in the board code */
+	return &board_topology_map;
+}
+
 int board_early_init_f(void)
 {
 	/* Configure MPP */
diff --git a/board/Marvell/db-88f6820-gp/kwbimage.cfg b/board/Marvell/db-88f6820-gp/kwbimage.cfg
index e812454..cc05792 100644
--- a/board/Marvell/db-88f6820-gp/kwbimage.cfg
+++ b/board/Marvell/db-88f6820-gp/kwbimage.cfg
@@ -9,4 +9,4 @@
 BOOT_FROM	spi
 
 # Binary Header (bin_hdr) with DDR3 training code
-BINARY board/Marvell/db-88f6820-gp/binary.0 0000005b 00000068
+BINARY spl/u-boot-spl.bin 0000005b 00000068
diff --git a/board/maxbcm/maxbcm.c b/board/maxbcm/maxbcm.c
index 2fbb90c..119ba4c 100644
--- a/board/maxbcm/maxbcm.c
+++ b/board/maxbcm/maxbcm.c
@@ -11,8 +11,8 @@
 #include <asm/arch/soc.h>
 #include <linux/mbus.h>
 
-#include "../drivers/ddr/mvebu/ddr3_hw_training.h"
-#include "../arch/arm/mach-mvebu/serdes/high_speed_env_spec.h"
+#include "../drivers/ddr/marvell/axp/ddr3_hw_training.h"
+#include "../arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
diff --git a/common/cmd_tsi148.c b/common/cmd_tsi148.c
index dc488b2..ea96d0f 100644
--- a/common/cmd_tsi148.c
+++ b/common/cmd_tsi148.c
@@ -16,8 +16,8 @@
 
 #include <tsi148.h>
 
-#define PCI_VENDOR PCI_VENDOR_ID_TUNDRA
-#define PCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
+#define LPCI_VENDOR PCI_VENDOR_ID_TUNDRA
+#define LPCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
 
 typedef struct _TSI148_DEV TSI148_DEV;
 
@@ -41,7 +41,7 @@
 	pci_dev_t busdevfn;
 	unsigned int val;
 
-	busdevfn = pci_find_device(PCI_VENDOR, PCI_DEVICE, 0);
+	busdevfn = pci_find_device(LPCI_VENDOR, LPCI_DEVICE, 0);
 	if (busdevfn == -1) {
 		puts("Tsi148: No Tundra Tsi148 found!\n");
 		return -1;
@@ -68,7 +68,7 @@
 	/* check mapping */
 	debug("Tsi148: Read via mapping, PCI_ID = %08X\n",
 	      readl(&dev->uregs->pci_id));
-	if (((PCI_DEVICE << 16) | PCI_VENDOR) != readl(&dev->uregs->pci_id)) {
+	if (((LPCI_DEVICE << 16) | LPCI_VENDOR) != readl(&dev->uregs->pci_id)) {
 		printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n",
 		       readl(&dev->uregs->pci_id));
 		result = -1;
diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index eab55cd..0ade775 100644
--- a/common/cmd_usb.c
+++ b/common/cmd_usb.c
@@ -22,8 +22,8 @@
 #ifdef CONFIG_USB_STORAGE
 static int usb_stor_curr_dev = -1; /* current device */
 #endif
-#ifdef CONFIG_USB_HOST_ETHER
-static int usb_ether_curr_dev = -1; /* current ethernet device */
+#if defined(CONFIG_USB_HOST_ETHER) && !defined(CONFIG_DM_ETH)
+static int __maybe_unused usb_ether_curr_dev = -1; /* current ethernet device */
 #endif
 
 /* some display routines (info command) */
@@ -355,12 +355,12 @@
 #endif
 	/* check if we are the last one */
 #ifdef CONFIG_DM_USB
-	last_child = device_is_last_sibling(dev->dev);
+	/* Not the root of the usb tree? */
+	if (device_get_uclass_id(dev->dev->parent) != UCLASS_USB) {
+		last_child = device_is_last_sibling(dev->dev);
 #else
-	last_child = (dev->parent != NULL);
-#endif
-	if (last_child) {
-#ifndef CONFIG_DM_USB
+	if (dev->parent != NULL) { /* not root? */
+		last_child = 1;
 		for (i = 0; i < dev->parent->maxchild; i++) {
 			/* search for children */
 			if (dev->parent->children[i] == dev) {
@@ -530,11 +530,14 @@
 	/* try to recognize storage devices immediately */
 	usb_stor_curr_dev = usb_stor_scan(1);
 #endif
-#endif
 #ifdef CONFIG_USB_HOST_ETHER
+# ifdef CONFIG_DM_ETH
+#  error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
+# endif
 	/* try to recognize ethernet devices immediately */
 	usb_ether_curr_dev = usb_host_eth_scan(1);
 #endif
+#endif
 #ifdef CONFIG_USB_KEYBOARD
 	drv_usb_kbd_init();
 #endif
@@ -630,12 +633,11 @@
 		     bus;
 		     uclass_next_device(&bus)) {
 			struct usb_device *udev;
-			struct udevice *hub;
+			struct udevice *dev;
 
-			device_find_first_child(bus, &hub);
-			if (device_get_uclass_id(hub) == UCLASS_USB_HUB &&
-			    device_active(hub)) {
-				udev = dev_get_parentdata(hub);
+			device_find_first_child(bus, &dev);
+			if (dev && device_active(dev)) {
+				udev = dev_get_parentdata(dev);
 				usb_show_tree(udev);
 			}
 		}
diff --git a/common/console.c b/common/console.c
index 0058222..ace206c 100644
--- a/common/console.c
+++ b/common/console.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <debug_uart.h>
 #include <stdarg.h>
 #include <iomux.h>
 #include <malloc.h>
@@ -455,11 +456,19 @@
 void putc(const char c)
 {
 #ifdef CONFIG_SANDBOX
+	/* sandbox can send characters to stdout before it has a console */
 	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
 		os_putc(c);
 		return;
 	}
 #endif
+#ifdef CONFIG_DEBUG_UART
+	/* if we don't have a console yet, use the debug UART */
+	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+		printch(c);
+		return;
+	}
+#endif
 #ifdef CONFIG_SILENT_CONSOLE
 	if (gd->flags & GD_FLG_SILENT)
 		return;
@@ -491,7 +500,18 @@
 		return;
 	}
 #endif
+#ifdef CONFIG_DEBUG_UART
+	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+		while (*s) {
+			int ch = *s++;
 
+			printch(ch);
+			if (ch == '\n')
+				printch('\r');
+		}
+		return;
+	}
+#endif
 #ifdef CONFIG_SILENT_CONSOLE
 	if (gd->flags & GD_FLG_SILENT)
 		return;
@@ -521,11 +541,6 @@
 	uint i;
 	char printbuffer[CONFIG_SYS_PBSIZE];
 
-#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_PRE_CONSOLE_BUFFER)
-	if (!gd->have_console)
-		return 0;
-#endif
-
 	va_start(args, fmt);
 
 	/* For this to work, printbuffer must be larger than
diff --git a/common/image.c b/common/image.c
index f0f0135..9efacf8 100644
--- a/common/image.c
+++ b/common/image.c
@@ -543,6 +543,15 @@
 }
 #endif
 
+const table_entry_t *get_table_entry(const table_entry_t *table, int id)
+{
+	for (; table->id >= 0; ++table) {
+		if (table->id == id)
+			return table;
+	}
+	return NULL;
+}
+
 /**
  * get_table_entry_name - translate entry id to long name
  * @table: pointer to a translation table for entries of a specific type
@@ -559,15 +568,14 @@
  */
 char *get_table_entry_name(const table_entry_t *table, char *msg, int id)
 {
-	for (; table->id >= 0; ++table) {
-		if (table->id == id)
+	table = get_table_entry(table, id);
+	if (!table)
+		return msg;
 #if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
-			return table->lname;
+	return table->lname;
 #else
-			return table->lname + gd->reloc_off;
+	return table->lname + gd->reloc_off;
 #endif
-	}
-	return (msg);
 }
 
 const char *genimg_get_os_name(uint8_t os)
@@ -586,6 +594,20 @@
 	return (get_table_entry_name(uimage_type, "Unknown Image", type));
 }
 
+const char *genimg_get_type_short_name(uint8_t type)
+{
+	const table_entry_t *table;
+
+	table = get_table_entry(uimage_type, type);
+	if (!table)
+		return "unknown";
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+	return table->sname;
+#else
+	return table->sname + gd->reloc_off;
+#endif
+}
+
 const char *genimg_get_comp_name(uint8_t comp)
 {
 	return (get_table_entry_name(uimage_comp, "Unknown Compression",
@@ -610,34 +632,18 @@
 		const char *table_name, const char *name)
 {
 	const table_entry_t *t;
-#ifdef USE_HOSTCC
-	int first = 1;
 
 	for (t = table; t->id >= 0; ++t) {
-		if (t->sname && strcasecmp(t->sname, name) == 0)
-			return(t->id);
-	}
-
-	fprintf(stderr, "\nInvalid %s Type - valid names are", table_name);
-	for (t = table; t->id >= 0; ++t) {
-		if (t->sname == NULL)
-			continue;
-		fprintf(stderr, "%c %s", (first) ? ':' : ',', t->sname);
-		first = 0;
-	}
-	fprintf(stderr, "\n");
-#else
-	for (t = table; t->id >= 0; ++t) {
 #ifdef CONFIG_NEEDS_MANUAL_RELOC
-		if (t->sname && strcmp(t->sname + gd->reloc_off, name) == 0)
+		if (t->sname && strcasecmp(t->sname + gd->reloc_off, name) == 0)
 #else
-		if (t->sname && strcmp(t->sname, name) == 0)
+		if (t->sname && strcasecmp(t->sname, name) == 0)
 #endif
 			return (t->id);
 	}
 	debug("Invalid %s Type: %s\n", table_name, name);
-#endif /* USE_HOSTCC */
-	return (-1);
+
+	return -1;
 }
 
 int genimg_get_os_id(const char *name)
diff --git a/common/spl/spl.c b/common/spl/spl.c
index aeb0645..94b01da 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -148,18 +148,12 @@
 }
 #endif
 
-void board_init_r(gd_t *dummy1, ulong dummy2)
+int spl_init(void)
 {
-	u32 boot_device;
 	int ret;
 
-	debug(">>spl:board_init_r()\n");
-
-#if defined(CONFIG_SYS_SPL_MALLOC_START)
-	mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
-			CONFIG_SYS_SPL_MALLOC_SIZE);
-	gd->flags |= GD_FLG_FULL_MALLOC_INIT;
-#elif defined(CONFIG_SYS_MALLOC_F_LEN)
+	debug("spl_init()\n");
+#if defined(CONFIG_SYS_MALLOC_F_LEN)
 	gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
 	gd->malloc_ptr = 0;
 #endif
@@ -168,17 +162,36 @@
 		ret = fdtdec_setup();
 		if (ret) {
 			debug("fdtdec_setup() returned error %d\n", ret);
-			hang();
+			return ret;
 		}
 	}
 	if (IS_ENABLED(CONFIG_SPL_DM)) {
 		ret = dm_init_and_scan(true);
 		if (ret) {
 			debug("dm_init_and_scan() returned error %d\n", ret);
-			hang();
+			return ret;
 		}
 	}
+	gd->flags |= GD_FLG_SPL_INIT;
 
+	return 0;
+}
+
+void board_init_r(gd_t *dummy1, ulong dummy2)
+{
+	u32 boot_device;
+
+	debug(">>spl:board_init_r()\n");
+
+#if defined(CONFIG_SYS_SPL_MALLOC_START)
+	mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
+			CONFIG_SYS_SPL_MALLOC_SIZE);
+	gd->flags |= GD_FLG_FULL_MALLOC_INIT;
+#endif
+	if (!(gd->flags & GD_FLG_SPL_INIT)) {
+		if (spl_init())
+			hang();
+	}
 #ifndef CONFIG_PPC
 	/*
 	 * timer_init() does not exist on PPC systems. The timer is initialized
@@ -285,6 +298,7 @@
 	      gd->malloc_ptr / 1024);
 #endif
 
+	debug("loaded - jumping to U-Boot...");
 	jump_to_image_no_args(&spl_image);
 }
 
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 552f80d..494f683 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -7,6 +7,7 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 #include <common.h>
+#include <dm.h>
 #include <spl.h>
 #include <linux/compiler.h>
 #include <asm/u-boot.h>
@@ -26,11 +27,14 @@
 
 	/* read image header to find the image size & load address */
 	count = mmc->block_dev.block_read(0, sector, 1, header);
+	debug("read sector %lx, count=%lu\n", sector, count);
 	if (count == 0)
 		goto end;
 
-	if (image_get_magic(header) != IH_MAGIC)
+	if (image_get_magic(header) != IH_MAGIC) {
+		puts("bad magic\n");
 		return -1;
+	}
 
 	spl_parse_image_header(header);
 
@@ -40,7 +44,9 @@
 
 	/* Read the header too to avoid extra memcpy */
 	count = mmc->block_dev.block_read(0, sector, image_size_sectors,
-					  (void *) spl_image.load_addr);
+					  (void *)spl_image.load_addr);
+	debug("read %x sectors to %x\n", image_size_sectors,
+	      spl_image.load_addr);
 
 end:
 	if (count == 0) {
@@ -67,7 +73,12 @@
 		return -1;
 	}
 
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
+	return mmc_load_image_raw_sector(mmc, info.start +
+					 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
+#else
 	return mmc_load_image_raw_sector(mmc, info.start);
+#endif
 }
 #endif
 
@@ -96,9 +107,18 @@
 {
 	struct mmc *mmc;
 	u32 boot_mode;
-	int err;
+	int err = 0;
 	__maybe_unused int part;
 
+#ifdef CONFIG_DM_MMC
+	struct udevice *dev;
+
+	mmc_initialize(NULL);
+	err = uclass_get_device(UCLASS_MMC, 0, &dev);
+	mmc = NULL;
+	if (!err)
+		mmc = mmc_get_mmc_dev(dev);
+#else
 	mmc_initialize(gd->bd);
 
 	/* We register only one device. So, the dev id is always 0 */
@@ -109,8 +129,11 @@
 #endif
 		hang();
 	}
+#endif
 
-	err = mmc_init(mmc);
+	if (!err)
+		err = mmc_init(mmc);
+
 	if (err) {
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
 		printf("spl: mmc init failed with error: %d\n", err);
diff --git a/common/usb.c b/common/usb.c
index 7ff8ac5..fbaf8ec 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -911,26 +911,24 @@
 }
 #endif /* !CONFIG_DM_USB */
 
-#ifndef CONFIG_DM_USB
-int usb_legacy_port_reset(struct usb_device *hub, int portnr)
+static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub)
 {
 	if (hub) {
 		unsigned short portstatus;
 		int err;
 
 		/* reset the port for the second time */
-		err = legacy_hub_port_reset(hub, portnr - 1, &portstatus);
+		err = legacy_hub_port_reset(hub, dev->portnr - 1, &portstatus);
 		if (err < 0) {
-			printf("\n     Couldn't reset port %i\n", portnr);
+			printf("\n     Couldn't reset port %i\n", dev->portnr);
 			return err;
 		}
 	} else {
-		usb_reset_root_port();
+		usb_reset_root_port(dev);
 	}
 
 	return 0;
 }
-#endif
 
 static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
 {
@@ -1032,7 +1030,7 @@
 }
 
 static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
-			      struct usb_device *parent, int portnr)
+			      struct usb_device *parent)
 {
 	int err;
 
@@ -1050,7 +1048,7 @@
 	err = usb_setup_descriptor(dev, do_read);
 	if (err)
 		return err;
-	err = usb_legacy_port_reset(parent, portnr);
+	err = usb_hub_port_reset(dev, parent);
 	if (err)
 		return err;
 
@@ -1128,7 +1126,7 @@
 }
 
 int usb_setup_device(struct usb_device *dev, bool do_read,
-		     struct usb_device *parent, int portnr)
+		     struct usb_device *parent)
 {
 	int addr;
 	int ret;
@@ -1137,7 +1135,7 @@
 	addr = dev->devnum;
 	dev->devnum = 0;
 
-	ret = usb_prepare_device(dev, addr, do_read, parent, portnr);
+	ret = usb_prepare_device(dev, addr, do_read, parent);
 	if (ret)
 		return ret;
 	ret = usb_select_config(dev);
@@ -1167,7 +1165,7 @@
 #ifdef CONFIG_USB_XHCI
 	do_read = false;
 #endif
-	err = usb_setup_device(dev, do_read, dev->parent, dev->portnr);
+	err = usb_setup_device(dev, do_read, dev->parent);
 	if (err)
 		return err;
 
diff --git a/common/usb_hub.c b/common/usb_hub.c
index be01f4f..f621ddb 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -652,6 +652,6 @@
 	{ }	/* Terminating entry */
 };
 
-USB_DEVICE(usb_generic_hub, hub_id_table);
+U_BOOT_USB_DEVICE(usb_generic_hub, hub_id_table);
 
 #endif
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index e2af67d..0227024 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -540,8 +540,8 @@
 	debug("%s: Probing for keyboard\n", __func__);
 #ifdef CONFIG_DM_USB
 	/*
-	 * TODO: We should add USB_DEVICE() declarations to each USB ethernet
-	 * driver and then most of this file can be removed.
+	 * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
+	 * keyboard driver and then most of this file can be removed.
 	 */
 	struct udevice *bus;
 	struct uclass *uc;
diff --git a/common/usb_storage.c b/common/usb_storage.c
index cc9b3e3..b978430 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -1442,6 +1442,6 @@
 	{ }		/* Terminating entry */
 };
 
-USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
 
 #endif
diff --git a/configs/db-88f6820-gp_defconfig b/configs/db-88f6820-gp_defconfig
index 569ddfd..0ff6706 100644
--- a/configs/db-88f6820-gp_defconfig
+++ b/configs/db-88f6820-gp_defconfig
@@ -1,3 +1,4 @@
+CONFIG_SPL=y
 CONFIG_ARM=y
 CONFIG_TARGET_DB_88F6820_GP=y
 # CONFIG_CMD_IMLS is not set
diff --git a/configs/ph1_ld4_defconfig b/configs/ph1_ld4_defconfig
index a71511c..f84dcdf 100644
--- a/configs/ph1_ld4_defconfig
+++ b/configs/ph1_ld4_defconfig
@@ -4,8 +4,6 @@
 CONFIG_PFC_MICRO_SUPPORT_CARD=y
 CONFIG_SYS_TEXT_BASE=0x84000000
 CONFIG_DEFAULT_DEVICE_TREE="uniphier-ph1-ld4-ref"
-CONFIG_FIT=y
-CONFIG_FIT_VERBOSE=y
 CONFIG_HUSH_PARSER=y
 # CONFIG_CMD_XIMG is not set
 # CONFIG_CMD_ENV_EXISTS is not set
diff --git a/configs/ph1_pro4_defconfig b/configs/ph1_pro4_defconfig
index d02712e..2fc844d 100644
--- a/configs/ph1_pro4_defconfig
+++ b/configs/ph1_pro4_defconfig
@@ -3,8 +3,6 @@
 CONFIG_PFC_MICRO_SUPPORT_CARD=y
 CONFIG_SYS_TEXT_BASE=0x84000000
 CONFIG_DEFAULT_DEVICE_TREE="uniphier-ph1-pro4-ref"
-CONFIG_FIT=y
-CONFIG_FIT_VERBOSE=y
 CONFIG_HUSH_PARSER=y
 # CONFIG_CMD_XIMG is not set
 # CONFIG_CMD_ENV_EXISTS is not set
diff --git a/configs/ph1_sld3_defconfig b/configs/ph1_sld3_defconfig
new file mode 100644
index 0000000..386a0d1
--- /dev/null
+++ b/configs/ph1_sld3_defconfig
@@ -0,0 +1,28 @@
+CONFIG_ARM=y
+CONFIG_ARCH_UNIPHIER=y
+CONFIG_MACH_PH1_SLD3=y
+CONFIG_PFC_MICRO_SUPPORT_CARD=y
+CONFIG_SYS_TEXT_BASE=0x84000000
+CONFIG_DEFAULT_DEVICE_TREE="uniphier-ph1-sld3-ref"
+CONFIG_HUSH_PARSER=y
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_ENV_EXISTS is not set
+CONFIG_CMD_NAND=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_USB=y
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_TIME=y
+# CONFIG_CMD_MISC is not set
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_SPL_DM=y
+CONFIG_NAND_DENALI=y
+CONFIG_SYS_NAND_DENALI_64BIT=y
+CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
+CONFIG_SPL_NAND_DENALI=y
+CONFIG_UNIPHIER_SERIAL=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_STORAGE=y
diff --git a/configs/ph1_sld8_defconfig b/configs/ph1_sld8_defconfig
index ee4cebc..2af45d2 100644
--- a/configs/ph1_sld8_defconfig
+++ b/configs/ph1_sld8_defconfig
@@ -4,8 +4,6 @@
 CONFIG_PFC_MICRO_SUPPORT_CARD=y
 CONFIG_SYS_TEXT_BASE=0x84000000
 CONFIG_DEFAULT_DEVICE_TREE="uniphier-ph1-sld8-ref"
-CONFIG_FIT=y
-CONFIG_FIT_VERBOSE=y
 CONFIG_HUSH_PARSER=y
 # CONFIG_CMD_XIMG is not set
 # CONFIG_CMD_ENV_EXISTS is not set
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 598519d..5535746 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -18,6 +18,7 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_SANDBOX=y
 CONFIG_CMD_CROS_EC=y
+CONFIG_CMD_DHRYSTONE=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_SANDBOX=y
 CONFIG_DM_ETH=y
@@ -44,3 +45,10 @@
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
+CONFIG_CLK=y
+CONFIG_RESET=y
+CONFIG_RAM=y
+CONFIG_DM_MMC=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_SYSCON=y
diff --git a/doc/README.uniphier b/doc/README.uniphier
index 4902533..52d681b 100644
--- a/doc/README.uniphier
+++ b/doc/README.uniphier
@@ -28,14 +28,18 @@
 Compile the source
 ------------------
 
-PH1-Pro4:
-    $ make ph1_pro4_defconfig
+PH1-sLD3:
+    $ make ph1_sld3_defconfig
     $ make CROSS_COMPILE=arm-linux-gnueabi-
 
 PH1-LD4:
     $ make ph1_ld4_defconfig
     $ make CROSS_COMPILE=arm-linux-gnueabi-
 
+PH1-Pro4:
+    $ make ph1_pro4_defconfig
+    $ make CROSS_COMPILE=arm-linux-gnueabi-
+
 PH1-sLD8:
     $ make ph1_sld8_defconfig
     $ make CROSS_COMPILE=arm-linux-gnueabi-
@@ -81,6 +85,48 @@
  - Support card (SRAM, NOR flash, some peripherals)
 
 
+Micro Support Card
+------------------
+
+The recommended bit switch settings are as follows:
+
+ SW2    OFF(1)/ON(0)   Description
+ ------------------------------------------
+ bit 1   <----         BKSZ[0]
+ bit 2   ---->         BKSZ[1]
+ bit 3   <----         SoC Bus Width 16/32
+ bit 4   <----         SERIAL_SEL[0]
+ bit 5   ---->         SERIAL_SEL[1]
+ bit 6   ---->         BOOTSWAP_EN
+ bit 7   <----         CS1/CS5
+ bit 8   <----         SOC_SERIAL_DISABLE
+
+ SW8    OFF(1)/ON(0)   Description
+ ------------------------------------------
+ bit 1    ---->        CS1_SPLIT
+ bit 2    <----        CASE9_ON
+ bit 3    <----        CASE10_ON
+ bit 4  Don't Care     Reserve
+ bit 5  Don't Care     Reserve
+ bit 6  Don't Care     Reserve
+ bit 7    ---->        BURST_EN
+ bit 8    ---->        FLASHBUS32_16
+
+The BKSZ[1:0] specifies the address range of memory slot and peripherals
+as follows:
+
+ BKSZ    Description              RAM slot            Peripherals
+ --------------------------------------------------------------------
+ 0b00   15MB RAM / 1MB Peri    00000000-0effffff    0f000000-0fffffff
+ 0b01   31MB RAM / 1MB Peri    00000000-1effffff    1f000000-1fffffff
+ 0b10   64MB RAM / 1MB Peri    00000000-3effffff    3f000000-3fffffff
+ 0b11  127MB RAM / 1MB Peri    00000000-7effffff    7f000000-7fffffff
+
+Set BSKZ[1:0] to 0b01 for U-Boot.
+This mode is the most handy because EA[24] is always supported by the save pin
+mode of the system bus.  On the other hand, EA[25] is not supported for some
+newer SoCs.  Even if it is, EA[25] is not connected on most of the boards.
+
 --
-Masahiro Yamada <yamada.m@jp.panasonic.com>
-Feb. 2015
+Masahiro Yamada <yamada.masahiro@socionext.com>
+Jul. 2015
diff --git a/doc/device-tree-bindings/leds/common.txt b/doc/device-tree-bindings/leds/common.txt
new file mode 100644
index 0000000..2d88816
--- /dev/null
+++ b/doc/device-tree-bindings/leds/common.txt
@@ -0,0 +1,23 @@
+Common leds properties.
+
+Optional properties for child nodes:
+- label : The label for this LED.  If omitted, the label is
+  taken from the node name (excluding the unit address).
+
+- linux,default-trigger :  This parameter, if present, is a
+    string defining the trigger assigned to the LED.  Current triggers are:
+     "backlight" - LED will act as a back-light, controlled by the framebuffer
+		   system
+     "default-on" - LED will turn on (but for leds-gpio see "default-state"
+		    property in Documentation/devicetree/bindings/gpio/led.txt)
+     "heartbeat" - LED "double" flashes at a load average based rate
+     "ide-disk" - LED indicates disk activity
+     "timer" - LED flashes at a fixed, configurable rate
+
+Examples:
+
+system-status {
+	label = "Status";
+	linux,default-trigger = "heartbeat";
+	...
+};
diff --git a/doc/device-tree-bindings/leds/leds-gpio.txt b/doc/device-tree-bindings/leds/leds-gpio.txt
new file mode 100644
index 0000000..df1b308
--- /dev/null
+++ b/doc/device-tree-bindings/leds/leds-gpio.txt
@@ -0,0 +1,52 @@
+LEDs connected to GPIO lines
+
+Required properties:
+- compatible : should be "gpio-leds".
+
+Each LED is represented as a sub-node of the gpio-leds device.  Each
+node's name represents the name of the corresponding LED.
+
+LED sub-node properties:
+- gpios :  Should specify the LED's GPIO, see "gpios property" in
+  Documentation/devicetree/bindings/gpio/gpio.txt.  Active low LEDs should be
+  indicated using flags in the GPIO specifier.
+- label :  (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger :  (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- default-state:  (optional) The initial state of the LED.  Valid
+  values are "on", "off", and "keep".  If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on).  The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
+
+Examples:
+
+leds {
+	compatible = "gpio-leds";
+	hdd {
+		label = "IDE Activity";
+		gpios = <&mcu_pio 0 1>; /* Active low */
+		linux,default-trigger = "ide-disk";
+	};
+
+	fault {
+		gpios = <&mcu_pio 1 0>;
+		/* Keep LED on if BIOS detected hardware fault */
+		default-state = "keep";
+	};
+};
+
+run-control {
+	compatible = "gpio-leds";
+	red {
+		gpios = <&mpc8572 6 0>;
+		default-state = "off";
+	};
+	green {
+		gpios = <&mpc8572 7 0>;
+		default-state = "on";
+	};
+};
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index f0276b1..b891e84 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -301,6 +301,15 @@
 Platform Data
 -------------
 
+*** Note: platform data is the old way of doing things. It is
+*** basically a C structure which is passed to drivers to tell them about
+*** platform-specific settings like the address of its registers, bus
+*** speed, etc. Device tree is now the preferred way of handling this.
+*** Unless you have a good reason not to use device tree (the main one
+*** being you need serial support in SPL and don't have enough SRAM for
+*** the cut-down device tree and libfdt libraries) you should stay away
+*** from platform data.
+
 Platform data is like Linux platform data, if you are familiar with that.
 It provides the board-specific information to start up a device.
 
@@ -366,8 +375,12 @@
 -----------
 
 While platdata is useful, a more flexible way of providing device data is
-by using device tree. With device tree we replace the above code with the
-following device tree fragment:
+by using device tree. In U-Boot you should use this where possible. Avoid
+sending patches which make use of the U_BOOT_DEVICE() macro unless strictly
+necessary.
+
+With device tree we replace the above code with the following device tree
+fragment:
 
 	red-square {
 		compatible = "demo-shape";
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c7e526c..092bc02 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,7 @@
 menu "Device Drivers"
 
+source "drivers/clk/Kconfig"
+
 source "drivers/core/Kconfig"
 
 source "drivers/cpu/Kconfig"
@@ -20,6 +22,8 @@
 
 source "drivers/input/Kconfig"
 
+source "drivers/led/Kconfig"
+
 source "drivers/serial/Kconfig"
 
 source "drivers/tpm/Kconfig"
@@ -32,6 +36,8 @@
 
 source "drivers/power/Kconfig"
 
+source "drivers/ram/Kconfig"
+
 source "drivers/hwmon/Kconfig"
 
 source "drivers/watchdog/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 405b64b..5a35148 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_CLK) += clk/
 obj-$(CONFIG_DM) += core/
 obj-$(CONFIG_DM_DEMO) += demo/
 obj-$(CONFIG_BIOSEMU) += bios_emulator/
@@ -7,9 +8,11 @@
 obj-y += crypto/
 obj-$(CONFIG_FPGA) += fpga/
 obj-y += hwmon/
+obj-$(CONFIG_LED) += led/
 obj-y += misc/
 obj-y += pcmcia/
 obj-y += dfu/
+obj-$(CONFIG_RAM) += ram/
 obj-y += rtc/
 obj-y += sound/
 obj-y += tpm/
diff --git a/drivers/block/mvsata_ide.c b/drivers/block/mvsata_ide.c
index e54d564..52c1602 100644
--- a/drivers/block/mvsata_ide.c
+++ b/drivers/block/mvsata_ide.c
@@ -13,6 +13,8 @@
 #include <asm/arch/orion5x.h>
 #elif defined(CONFIG_KIRKWOOD)
 #include <asm/arch/soc.h>
+#elif defined(CONFIG_ARMADA_XP)
+#include <linux/mbus.h>
 #endif
 
 /* SATA port registers */
@@ -90,6 +92,41 @@
 #define MVSATA_STATUS_TIMEOUT	-1
 
 /*
+ * Registers for SATA MBUS memory windows
+ */
+
+#define MVSATA_WIN_CONTROL(w)	(MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4))
+#define MVSATA_WIN_BASE(w)	(MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4))
+
+/*
+ * Initialize SATA memory windows for Armada XP
+ */
+
+#ifdef CONFIG_ARMADA_XP
+static void mvsata_ide_conf_mbus_windows(void)
+{
+	const struct mbus_dram_target_info *dram;
+	int i;
+
+	dram = mvebu_mbus_dram_info();
+
+	/* Disable windows, Set Size/Base to 0  */
+	for (i = 0; i < 4; i++) {
+		writel(0, MVSATA_WIN_CONTROL(i));
+		writel(0, MVSATA_WIN_BASE(i));
+	}
+
+	for (i = 0; i < dram->num_cs; i++) {
+		const struct mbus_dram_window *cs = dram->cs + i;
+		writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
+				(dram->mbus_dram_target_id << 4) | 1,
+				MVSATA_WIN_CONTROL(i));
+		writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i));
+	}
+}
+#endif
+
+/*
  * Initialize one MVSATAHC port: set SControl's IPM to "always active"
  * and DET to "reset", then wait for SStatus's DET to become "device and
  * comm ok" (or time out after 50 us if no device), then set SControl's
@@ -137,6 +174,10 @@
 	int ret = MVSATA_STATUS_TIMEOUT;
 	int status;
 
+#ifdef CONFIG_ARMADA_XP
+	mvsata_ide_conf_mbus_windows();
+#endif
+
 	/* Enable ATA port 0 (could be SATA port 0 or 1) if declared */
 #if defined(CONFIG_SYS_ATA_IDE0_OFFSET)
 	status = mvsata_ide_initialize_port(
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
new file mode 100644
index 0000000..07eb54c
--- /dev/null
+++ b/drivers/clk/Kconfig
@@ -0,0 +1,19 @@
+config CLK
+	bool "Enable clock driver support"
+	depends on DM
+	help
+	  This allows drivers to be provided for clock generators, including
+	  oscillators and PLLs. Devices can use a common clock API to request
+	  a particular clock rate and check on available clocks. Clocks can
+	  feed into other clocks in a tree structure, with multiplexers to
+	  choose the source for each clock.
+
+config SPL_CLK_SUPPORT
+	bool "Enable clock support in SPL"
+	depends on CLK
+	help
+	  The clock subsystem adds a small amount of overhead to the image.
+	  If this is acceptable and you have a need to use clock drivers in
+	  SPL, enable this option. It might provide a cleaner interface to
+	  setting up clocks within SPL, and allows the same drivers to be
+	  used as U-Boot proper.
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
new file mode 100644
index 0000000..bb89fb9
--- /dev/null
+++ b/drivers/clk/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+obj-$(CONFIG_CLK) += clk-uclass.o
+obj-$(CONFIG_SANDBOX) += clk_sandbox.o
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
new file mode 100644
index 0000000..73dfd7d
--- /dev/null
+++ b/drivers/clk/clk-uclass.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+ulong clk_get_rate(struct udevice *dev)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->get_rate)
+		return -ENOSYS;
+
+	return ops->get_rate(dev);
+}
+
+ulong clk_set_rate(struct udevice *dev, ulong rate)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->set_rate)
+		return -ENOSYS;
+
+	return ops->set_rate(dev, rate);
+}
+
+ulong clk_get_periph_rate(struct udevice *dev, int periph)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->get_periph_rate)
+		return -ENOSYS;
+
+	return ops->get_periph_rate(dev, periph);
+}
+
+ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->set_periph_rate)
+		return -ENOSYS;
+
+	return ops->set_periph_rate(dev, periph, rate);
+}
+
+UCLASS_DRIVER(clk) = {
+	.id		= UCLASS_CLK,
+	.name		= "clk",
+};
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
new file mode 100644
index 0000000..058225a
--- /dev/null
+++ b/drivers/clk/clk_sandbox.c
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/test.h>
+
+struct sandbox_clk_priv {
+	ulong rate;
+	ulong periph_rate[PERIPH_ID_COUNT];
+};
+
+static ulong sandbox_clk_get_rate(struct udevice *dev)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	return priv->rate;
+}
+
+static ulong sandbox_clk_set_rate(struct udevice *dev, ulong rate)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	if (!rate)
+		return -EINVAL;
+	priv->rate = rate;
+	return 0;
+}
+
+ulong sandbox_get_periph_rate(struct udevice *dev, int periph)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
+		return -EINVAL;
+	return priv->periph_rate[periph];
+}
+
+ulong sandbox_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+	ulong old_rate;
+
+	if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
+		return -EINVAL;
+	old_rate = priv->periph_rate[periph];
+	priv->periph_rate[periph] = rate;
+
+	return old_rate;
+}
+
+static int sandbox_clk_probe(struct udevice *dev)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	priv->rate = SANDBOX_CLK_RATE;
+
+	return 0;
+}
+
+static struct clk_ops sandbox_clk_ops = {
+	.get_rate	= sandbox_clk_get_rate,
+	.set_rate	= sandbox_clk_set_rate,
+	.get_periph_rate = sandbox_get_periph_rate,
+	.set_periph_rate = sandbox_set_periph_rate,
+};
+
+static const struct udevice_id sandbox_clk_ids[] = {
+	{ .compatible = "sandbox,clk" },
+	{ }
+};
+
+U_BOOT_DRIVER(clk_sandbox) = {
+	.name		= "clk_sandbox",
+	.id		= UCLASS_CLK,
+	.of_match	= sandbox_clk_ids,
+	.ops		= &sandbox_clk_ops,
+	.priv_auto_alloc_size = sizeof(struct sandbox_clk_priv),
+	.probe		= sandbox_clk_probe,
+};
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 2861b43..e40372d 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -38,6 +38,10 @@
 	  device. This is not normally required in SPL, so by default this
 	  option is disabled for SPL.
 
+	  Note that this may have undesirable results in the USB subsystem as
+	  it causes unplugged devices to linger around in the dm-tree, and it
+	  causes USB host controllers to not be stopped when booting the OS.
+
 config DM_STDIO
 	bool "Support stdio registration"
 	depends on DM
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index a3fec38..5c2ead8 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -4,8 +4,11 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-$(CONFIG_DM)	+= device.o lists.o root.o uclass.o util.o
+obj-y	+= device.o lists.o root.o uclass.o util.o
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_OF_CONTROL) += simple-bus.o
 endif
 obj-$(CONFIG_DM_DEVICE_REMOVE)	+= device-remove.o
+obj-$(CONFIG_DM)	+= dump.o
+obj-$(CONFIG_OF_CONTROL)	+= regmap.o
+obj-$(CONFIG_OF_CONTROL)	+= syscon-uclass.o
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 6a16b4f..6b87f86 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -18,16 +18,7 @@
 #include <dm/uclass-internal.h>
 #include <dm/util.h>
 
-/**
- * device_chld_unbind() - Unbind all device's children from the device
- *
- * On error, the function continues to unbind all children, and reports the
- * first error.
- *
- * @dev:	The device that is to be stripped of its children
- * @return 0 on success, -ve on error
- */
-static int device_chld_unbind(struct udevice *dev)
+int device_unbind_children(struct udevice *dev)
 {
 	struct udevice *pos, *n;
 	int ret, saved_ret = 0;
@@ -43,12 +34,7 @@
 	return saved_ret;
 }
 
-/**
- * device_chld_remove() - Stop all device's children
- * @dev:	The device whose children are to be removed
- * @return 0 on success, -ve on error
- */
-static int device_chld_remove(struct udevice *dev)
+int device_remove_children(struct udevice *dev)
 {
 	struct udevice *pos, *n;
 	int ret;
@@ -84,7 +70,7 @@
 			return ret;
 	}
 
-	ret = device_chld_unbind(dev);
+	ret = device_unbind_children(dev);
 	if (ret)
 		return ret;
 
@@ -159,7 +145,7 @@
 	if (ret)
 		return ret;
 
-	ret = device_chld_remove(dev);
+	ret = device_remove_children(dev);
 	if (ret)
 		goto err;
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 85fd1fc..51b1b44 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -284,7 +284,6 @@
 			goto fail;
 	}
 
-	dev->flags |= DM_FLAG_ACTIVATED;
 	if (drv->probe) {
 		ret = drv->probe(dev);
 		if (ret) {
@@ -330,7 +329,7 @@
 void *dev_get_parent_platdata(struct udevice *dev)
 {
 	if (!dev) {
-		dm_warn("%s: null device", __func__);
+		dm_warn("%s: null device\n", __func__);
 		return NULL;
 	}
 
@@ -340,7 +339,7 @@
 void *dev_get_uclass_platdata(struct udevice *dev)
 {
 	if (!dev) {
-		dm_warn("%s: null device", __func__);
+		dm_warn("%s: null device\n", __func__);
 		return NULL;
 	}
 
@@ -459,17 +458,42 @@
 	return -ENODEV;
 }
 
-int device_get_child_by_of_offset(struct udevice *parent, int seq,
+int device_get_child_by_of_offset(struct udevice *parent, int node,
 				  struct udevice **devp)
 {
 	struct udevice *dev;
 	int ret;
 
 	*devp = NULL;
-	ret = device_find_child_by_of_offset(parent, seq, &dev);
+	ret = device_find_child_by_of_offset(parent, node, &dev);
 	return device_get_device_tail(dev, ret, devp);
 }
 
+static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
+							int of_offset)
+{
+	struct udevice *dev, *found;
+
+	if (parent->of_offset == of_offset)
+		return parent;
+
+	list_for_each_entry(dev, &parent->child_head, sibling_node) {
+		found = _device_find_global_by_of_offset(dev, of_offset);
+		if (found)
+			return found;
+	}
+
+	return NULL;
+}
+
+int device_get_global_by_of_offset(int of_offset, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	dev = _device_find_global_by_of_offset(gd->dm_root, of_offset);
+	return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
+}
+
 int device_find_first_child(struct udevice *parent, struct udevice **devp)
 {
 	if (list_empty(&parent->child_head)) {
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
new file mode 100644
index 0000000..fd4596e
--- /dev/null
+++ b/drivers/core/dump.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <dm/root.h>
+
+static void show_devices(struct udevice *dev, int depth, int last_flag)
+{
+	int i, is_last;
+	struct udevice *child;
+	char class_name[12];
+
+	/* print the first 11 characters to not break the tree-format. */
+	strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
+	printf(" %-11s [ %c ]    ", class_name,
+	       dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
+
+	for (i = depth; i >= 0; i--) {
+		is_last = (last_flag >> i) & 1;
+		if (i) {
+			if (is_last)
+				printf("    ");
+			else
+				printf("|   ");
+		} else {
+			if (is_last)
+				printf("`-- ");
+			else
+				printf("|-- ");
+		}
+	}
+
+	printf("%s\n", dev->name);
+
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		is_last = list_is_last(&child->sibling_node, &dev->child_head);
+		show_devices(child, depth + 1, (last_flag << 1) | is_last);
+	}
+}
+
+void dm_dump_all(void)
+{
+	struct udevice *root;
+
+	root = dm_root();
+	if (root) {
+		printf(" Class       Probed   Name\n");
+		printf("----------------------------------------\n");
+		show_devices(root, -1, 0);
+	}
+}
+
+/**
+ * dm_display_line() - Display information about a single device
+ *
+ * Displays a single line of information with an option prefix
+ *
+ * @dev:	Device to display
+ */
+static void dm_display_line(struct udevice *dev)
+{
+	printf("- %c %s @ %08lx",
+	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
+	       dev->name, (ulong)map_to_sysmem(dev));
+	if (dev->seq != -1 || dev->req_seq != -1)
+		printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
+	puts("\n");
+}
+
+void dm_dump_uclass(void)
+{
+	struct uclass *uc;
+	int ret;
+	int id;
+
+	for (id = 0; id < UCLASS_COUNT; id++) {
+		struct udevice *dev;
+
+		ret = uclass_get(id, &uc);
+		if (ret)
+			continue;
+
+		printf("uclass %d: %s\n", id, uc->uc_drv->name);
+		if (list_empty(&uc->dev_head))
+			continue;
+		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+			dm_display_line(dev);
+		}
+		puts("\n");
+	}
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 0c49d99..2e52500 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -86,13 +86,13 @@
 
 	drv = lists_driver_lookup_name(drv_name);
 	if (!drv) {
-		printf("Cannot find driver '%s'\n", drv_name);
+		debug("Cannot find driver '%s'\n", drv_name);
 		return -ENOENT;
 	}
 	ret = device_bind(parent, drv, dev_name, NULL, node, devp);
 	if (ret) {
-		printf("Cannot create device named '%s' (err=%d)\n",
-		       dev_name, ret);
+		debug("Cannot create device named '%s' (err=%d)\n",
+		      dev_name, ret);
 		return ret;
 	}
 
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
new file mode 100644
index 0000000..519832f
--- /dev/null
+++ b/drivers/core/regmap.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <regmap.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
+{
+	const void *blob = gd->fdt_blob;
+	struct regmap_range *range;
+	const fdt32_t *cell;
+	struct regmap *map;
+	int count;
+	int addr_len, size_len, both_len;
+	int parent;
+	int len;
+
+	parent = dev->parent->of_offset;
+	addr_len = fdt_address_cells(blob, parent);
+	size_len = fdt_size_cells(blob, parent);
+	both_len = addr_len + size_len;
+
+	cell = fdt_getprop(blob, dev->of_offset, "reg", &len);
+	len /= sizeof(*cell);
+	count = len / both_len;
+	if (!cell || !count)
+		return -EINVAL;
+
+	map = malloc(sizeof(struct regmap));
+	if (!map)
+		return -ENOMEM;
+
+	if (count <= 1) {
+		map->range = &map->base_range;
+	} else {
+		map->range = malloc(count * sizeof(struct regmap_range));
+		if (!map->range) {
+			free(map);
+			return -ENOMEM;
+		}
+	}
+
+	map->base = fdtdec_get_number(cell, addr_len);
+	map->range_count = count;
+
+	for (range = map->range; count > 0;
+	     count--, cell += both_len, range++) {
+		range->start = fdtdec_get_number(cell, addr_len);
+		range->size = fdtdec_get_number(cell + addr_len, size_len);
+	}
+
+	*mapp = map;
+
+	return 0;
+}
+
+void *regmap_get_range(struct regmap *map, unsigned int range_num)
+{
+	struct regmap_range *range;
+
+	if (range_num >= map->range_count)
+		return NULL;
+	range = &map->range[range_num];
+
+	return map_sysmem(range->start, range->size);
+}
+
+int regmap_uninit(struct regmap *map)
+{
+	if (map->range_count > 1)
+		free(map->range);
+	free(map);
+
+	return 0;
+}
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
new file mode 100644
index 0000000..686c320
--- /dev/null
+++ b/drivers/core/syscon-uclass.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <syscon.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+struct regmap *syscon_get_regmap(struct udevice *dev)
+{
+	struct syscon_uc_info *priv;
+
+	if (device_get_uclass_id(dev) != UCLASS_SYSCON)
+		return ERR_PTR(-ENOEXEC);
+	priv = dev_get_uclass_priv(dev);
+	return priv->regmap;
+}
+
+static int syscon_pre_probe(struct udevice *dev)
+{
+	struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
+
+	return regmap_init_mem(dev, &priv->regmap);
+}
+
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_SYSCON, &uc);
+	if (ret)
+		return ERR_PTR(ret);
+	uclass_foreach_dev(dev, uc) {
+		if (dev->driver_data == driver_data) {
+			struct syscon_uc_info *priv;
+			int ret;
+
+			ret = device_probe(dev);
+			if (ret)
+				return ERR_PTR(ret);
+			priv = dev_get_uclass_priv(dev);
+
+			return priv->regmap;
+		}
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+void *syscon_get_first_range(ulong driver_data)
+{
+	struct regmap *map;
+
+	map = syscon_get_regmap_by_driver_data(driver_data);
+	if (IS_ERR(map))
+		return map;
+	return regmap_get_range(map, 0);
+}
+
+UCLASS_DRIVER(syscon) = {
+	.id		= UCLASS_SYSCON,
+	.name		= "syscon",
+	.per_device_auto_alloc_size = sizeof(struct syscon_uc_info),
+	.pre_probe = syscon_pre_probe,
+};
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 7de8173..aba9880 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -56,8 +56,8 @@
 	*ucp = NULL;
 	uc_drv = lists_uclass_lookup(id);
 	if (!uc_drv) {
-		dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
-			id);
+		debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
+		      id);
 		return -ENOENT;
 	}
 	uc = calloc(1, sizeof(*uc));
diff --git a/drivers/ddr/marvell/a38x/Makefile b/drivers/ddr/marvell/a38x/Makefile
new file mode 100644
index 0000000..bf6ea49
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/Makefile
@@ -0,0 +1,19 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD) += ddr3_a38x.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_a38x_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_debug.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_hws_hw_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_init.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_bist.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_centralization.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_db.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_hw_algo.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_ip_engine.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_leveling.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_pbs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_training_static.o
+obj-$(CONFIG_SPL_BUILD) += xor.o
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x.c b/drivers/ddr/marvell/a38x/ddr3_a38x.c
new file mode 100644
index 0000000..f469907
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x.c
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define A38X_NUMBER_OF_INTERFACES	5
+
+#define SAR_DEV_ID_OFFS			27
+#define SAR_DEV_ID_MASK			0x7
+
+/* Termal Sensor Registers */
+#define TSEN_STATE_REG			0xe4070
+#define TSEN_STATE_OFFSET		31
+#define TSEN_STATE_MASK			(0x1 << TSEN_STATE_OFFSET)
+#define TSEN_CONF_REG			0xe4074
+#define TSEN_CONF_RST_OFFSET		8
+#define TSEN_CONF_RST_MASK		(0x1 << TSEN_CONF_RST_OFFSET)
+#define TSEN_STATUS_REG			0xe4078
+#define TSEN_STATUS_READOUT_VALID_OFFSET	10
+#define TSEN_STATUS_READOUT_VALID_MASK	(0x1 <<				\
+					 TSEN_STATUS_READOUT_VALID_OFFSET)
+#define TSEN_STATUS_TEMP_OUT_OFFSET	0
+#define TSEN_STATUS_TEMP_OUT_MASK	(0x3ff << TSEN_STATUS_TEMP_OUT_OFFSET)
+
+static struct dfx_access interface_map[] = {
+	/* Pipe	Client */
+	{ 0, 17 },
+	{ 1, 7 },
+	{ 1, 11 },
+	{ 0, 3 },
+	{ 1, 25 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 }
+};
+
+/* This array hold the board round trip delay (DQ and CK) per <interface,bus> */
+struct trip_delay_element a38x_board_round_trip_delay_array[] = {
+	/* 1st board */
+	/* Interface bus DQS-delay CK-delay */
+	{ 3952, 5060 },
+	{ 3192, 4493 },
+	{ 4785, 6677 },
+	{ 3413, 7267 },
+	{ 4282, 6086 },	/* ECC PUP */
+	{ 3952, 5134 },
+	{ 3192, 4567 },
+	{ 4785, 6751 },
+	{ 3413, 7341 },
+	{ 4282, 6160 },	/* ECC PUP */
+
+	/* 2nd board */
+	/* Interface bus DQS-delay CK-delay */
+	{ 3952, 5060 },
+	{ 3192, 4493 },
+	{ 4785, 6677 },
+	{ 3413, 7267 },
+	{ 4282, 6086 },	/* ECC PUP */
+	{ 3952, 5134 },
+	{ 3192, 4567 },
+	{ 4785, 6751 },
+	{ 3413, 7341 },
+	{ 4282, 6160 }	/* ECC PUP */
+};
+
+#ifdef STATIC_ALGO_SUPPORT
+/* package trace */
+static struct trip_delay_element a38x_package_round_trip_delay_array[] = {
+	/* IF BUS DQ_DELAY CK_DELAY */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 }
+};
+
+static int a38x_silicon_delay_offset[] = {
+	/* board 0 */
+	0,
+	/* board 1 */
+	0,
+	/* board 2 */
+	0
+};
+#endif
+
+static u8 a38x_bw_per_freq[DDR_FREQ_LIMIT] = {
+	0x3,			/* DDR_FREQ_100 */
+	0x4,			/* DDR_FREQ_400 */
+	0x4,			/* DDR_FREQ_533 */
+	0x5,			/* DDR_FREQ_667 */
+	0x5,			/* DDR_FREQ_800 */
+	0x5,			/* DDR_FREQ_933 */
+	0x5,			/* DDR_FREQ_1066 */
+	0x3,			/* DDR_FREQ_311 */
+	0x3,			/* DDR_FREQ_333 */
+	0x4,			/* DDR_FREQ_467 */
+	0x5,			/* DDR_FREQ_850 */
+	0x5,			/* DDR_FREQ_600 */
+	0x3,			/* DDR_FREQ_300 */
+	0x5,			/* DDR_FREQ_900 */
+	0x3,			/* DDR_FREQ_360 */
+	0x5			/* DDR_FREQ_1000 */
+};
+
+static u8 a38x_rate_per_freq[DDR_FREQ_LIMIT] = {
+	 /*TBD*/ 0x1,		/* DDR_FREQ_100 */
+	0x2,			/* DDR_FREQ_400 */
+	0x2,			/* DDR_FREQ_533 */
+	0x2,			/* DDR_FREQ_667 */
+	0x2,			/* DDR_FREQ_800 */
+	0x3,			/* DDR_FREQ_933 */
+	0x3,			/* DDR_FREQ_1066 */
+	0x1,			/* DDR_FREQ_311 */
+	0x1,			/* DDR_FREQ_333 */
+	0x2,			/* DDR_FREQ_467 */
+	0x2,			/* DDR_FREQ_850 */
+	0x2,			/* DDR_FREQ_600 */
+	0x1,			/* DDR_FREQ_300 */
+	0x2,			/* DDR_FREQ_900 */
+	0x1,			/* DDR_FREQ_360 */
+	0x2			/* DDR_FREQ_1000 */
+};
+
+static u16 a38x_vco_freq_per_sar[] = {
+	666,			/* 0 */
+	1332,
+	800,
+	1600,
+	1066,
+	2132,
+	1200,
+	2400,
+	1332,
+	1332,
+	1500,
+	1500,
+	1600,			/* 12 */
+	1600,
+	1700,
+	1700,
+	1866,
+	1866,
+	1800,			/* 18 */
+	2000,
+	2000,
+	4000,
+	2132,
+	2132,
+	2300,
+	2300,
+	2400,
+	2400,
+	2500,
+	2500,
+	800
+};
+
+u32 pipe_multicast_mask;
+
+u32 dq_bit_map_2_phy_pin[] = {
+	1, 0, 2, 6, 9, 8, 3, 7,	/* 0 */
+	8, 9, 1, 7, 2, 6, 3, 0,	/* 1 */
+	3, 9, 7, 8, 1, 0, 2, 6,	/* 2 */
+	1, 0, 6, 2, 8, 3, 7, 9,	/* 3 */
+	0, 1, 2, 9, 7, 8, 3, 6,	/* 4 */
+};
+
+static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
+				     enum hws_ddr_freq freq);
+
+/*
+ * Read temperature TJ value
+ */
+u32 ddr3_ctrl_get_junc_temp(u8 dev_num)
+{
+	int reg = 0;
+
+	/* Initiates TSEN hardware reset once */
+	if ((reg_read(TSEN_CONF_REG) & TSEN_CONF_RST_MASK) == 0)
+		reg_bit_set(TSEN_CONF_REG, TSEN_CONF_RST_MASK);
+	mdelay(10);
+
+	/* Check if the readout field is valid */
+	if ((reg_read(TSEN_STATUS_REG) & TSEN_STATUS_READOUT_VALID_MASK) == 0) {
+		printf("%s: TSEN not ready\n", __func__);
+		return 0;
+	}
+
+	reg = reg_read(TSEN_STATUS_REG);
+	reg = (reg & TSEN_STATUS_TEMP_OUT_MASK) >> TSEN_STATUS_TEMP_OUT_OFFSET;
+
+	return ((((10000 * reg) / 21445) * 1000) - 272674) / 1000;
+}
+
+/*
+ * Name:     ddr3_tip_a38x_get_freq_config.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum hws_ddr_freq freq,
+				  struct hws_tip_freq_config_info
+				  *freq_config_info)
+{
+	if (a38x_bw_per_freq[freq] == 0xff)
+		return MV_NOT_SUPPORTED;
+
+	if (freq_config_info == NULL)
+		return MV_BAD_PARAM;
+
+	freq_config_info->bw_per_freq = a38x_bw_per_freq[freq];
+	freq_config_info->rate_per_freq = a38x_rate_per_freq[freq];
+	freq_config_info->is_supported = 1;
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_tip_a38x_pipe_enable.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_pipe_enable(u8 dev_num, enum hws_access_type interface_access,
+			      u32 if_id, int enable)
+{
+	u32 data_value, pipe_enable_mask = 0;
+
+	if (enable == 0) {
+		pipe_enable_mask = 0;
+	} else {
+		if (interface_access == ACCESS_TYPE_MULTICAST)
+			pipe_enable_mask = pipe_multicast_mask;
+		else
+			pipe_enable_mask = (1 << interface_map[if_id].pipe);
+	}
+
+	CHECK_STATUS(ddr3_tip_reg_read
+		     (dev_num, PIPE_ENABLE_ADDR, &data_value, MASK_ALL_BITS));
+	data_value = (data_value & (~0xff)) | pipe_enable_mask;
+	CHECK_STATUS(ddr3_tip_reg_write(dev_num, PIPE_ENABLE_ADDR, data_value));
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_tip_a38x_if_write.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_if_write(u8 dev_num, enum hws_access_type interface_access,
+			   u32 if_id, u32 reg_addr, u32 data_value,
+			   u32 mask)
+{
+	u32 ui_data_read;
+
+	if (mask != MASK_ALL_BITS) {
+		CHECK_STATUS(ddr3_tip_a38x_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, reg_addr,
+			      &ui_data_read, MASK_ALL_BITS));
+		data_value = (ui_data_read & (~mask)) | (data_value & mask);
+	}
+
+	reg_write(reg_addr, data_value);
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_tip_a38x_if_read.
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_if_read(u8 dev_num, enum hws_access_type interface_access,
+			  u32 if_id, u32 reg_addr, u32 *data, u32 mask)
+{
+	*data = reg_read(reg_addr) & mask;
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_tip_a38x_select_ddr_controller.
+ * Desc:     Enable/Disable access to Marvell's server.
+ * Args:     dev_num     - device number
+ *           enable        - whether to enable or disable the server
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_tip_a38x_select_ddr_controller(u8 dev_num, int enable)
+{
+	u32 reg;
+
+	reg = reg_read(CS_ENABLE_REG);
+
+	if (enable)
+		reg |= (1 << 6);
+	else
+		reg &= ~(1 << 6);
+
+	reg_write(CS_ENABLE_REG, reg);
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_tip_init_a38x_silicon.
+ * Desc:     init Training SW DB.
+ * Args:
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+static int ddr3_tip_init_a38x_silicon(u32 dev_num, u32 board_id)
+{
+	struct hws_tip_config_func_db config_func;
+	enum hws_ddr_freq ddr_freq;
+	int status;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* new read leveling version */
+	config_func.tip_dunit_read_func = ddr3_tip_a38x_if_read;
+	config_func.tip_dunit_write_func = ddr3_tip_a38x_if_write;
+	config_func.tip_dunit_mux_select_func =
+		ddr3_tip_a38x_select_ddr_controller;
+	config_func.tip_get_freq_config_info_func =
+		ddr3_tip_a38x_get_freq_config;
+	config_func.tip_set_freq_divider_func = ddr3_tip_a38x_set_divider;
+	config_func.tip_get_device_info_func = ddr3_tip_a38x_get_device_info;
+	config_func.tip_get_temperature = ddr3_ctrl_get_junc_temp;
+
+	ddr3_tip_init_config_func(dev_num, &config_func);
+
+	ddr3_tip_register_dq_table(dev_num, dq_bit_map_2_phy_pin);
+
+#ifdef STATIC_ALGO_SUPPORT
+	{
+		struct hws_tip_static_config_info static_config;
+		u32 board_offset =
+		    board_id * A38X_NUMBER_OF_INTERFACES *
+		    tm->num_of_bus_per_interface;
+
+		static_config.silicon_delay =
+			a38x_silicon_delay_offset[board_id];
+		static_config.package_trace_arr =
+			a38x_package_round_trip_delay_array;
+		static_config.board_trace_arr =
+			&a38x_board_round_trip_delay_array[board_offset];
+		ddr3_tip_init_static_config_db(dev_num, &static_config);
+	}
+#endif
+	status = ddr3_tip_a38x_get_init_freq(dev_num, &ddr_freq);
+	if (MV_OK != status) {
+		DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR,
+				      ("DDR3 silicon get target frequency - FAILED 0x%x\n",
+				       status));
+		return status;
+	}
+
+	rl_version = 1;
+	mask_tune_func = (SET_LOW_FREQ_MASK_BIT |
+			  LOAD_PATTERN_MASK_BIT |
+			  SET_MEDIUM_FREQ_MASK_BIT | WRITE_LEVELING_MASK_BIT |
+			  /* LOAD_PATTERN_2_MASK_BIT | */
+			  WRITE_LEVELING_SUPP_MASK_BIT |
+			  READ_LEVELING_MASK_BIT |
+			  PBS_RX_MASK_BIT |
+			  PBS_TX_MASK_BIT |
+			  SET_TARGET_FREQ_MASK_BIT |
+			  WRITE_LEVELING_TF_MASK_BIT |
+			  WRITE_LEVELING_SUPP_TF_MASK_BIT |
+			  READ_LEVELING_TF_MASK_BIT |
+			  CENTRALIZATION_RX_MASK_BIT |
+			  CENTRALIZATION_TX_MASK_BIT);
+	rl_mid_freq_wa = 1;
+
+	if ((ddr_freq == DDR_FREQ_333) || (ddr_freq == DDR_FREQ_400)) {
+		mask_tune_func = (WRITE_LEVELING_MASK_BIT |
+				  LOAD_PATTERN_2_MASK_BIT |
+				  WRITE_LEVELING_SUPP_MASK_BIT |
+				  READ_LEVELING_MASK_BIT |
+				  PBS_RX_MASK_BIT |
+				  PBS_TX_MASK_BIT |
+				  CENTRALIZATION_RX_MASK_BIT |
+				  CENTRALIZATION_TX_MASK_BIT);
+		rl_mid_freq_wa = 0; /* WA not needed if 333/400 is TF */
+	}
+
+	/* Supplementary not supported for ECC modes */
+	if (1 == ddr3_if_ecc_enabled()) {
+		mask_tune_func &= ~WRITE_LEVELING_SUPP_TF_MASK_BIT;
+		mask_tune_func &= ~WRITE_LEVELING_SUPP_MASK_BIT;
+		mask_tune_func &= ~PBS_TX_MASK_BIT;
+		mask_tune_func &= ~PBS_RX_MASK_BIT;
+	}
+
+	if (ck_delay == -1)
+		ck_delay = 160;
+	if (ck_delay_16 == -1)
+		ck_delay_16 = 160;
+	ca_delay = 0;
+	delay_enable = 1;
+
+	calibration_update_control = 1;
+
+	init_freq = tm->interface_params[first_active_if].memory_freq;
+
+	ddr3_tip_a38x_get_medium_freq(dev_num, &medium_freq);
+
+	return MV_OK;
+}
+
+int ddr3_a38x_update_topology_map(u32 dev_num, struct hws_topology_map *tm)
+{
+	u32 if_id = 0;
+	enum hws_ddr_freq freq;
+
+	ddr3_tip_a38x_get_init_freq(dev_num, &freq);
+	tm->interface_params[if_id].memory_freq = freq;
+
+	/*
+	 * re-calc topology parameters according to topology updates
+	 * (if needed)
+	 */
+	CHECK_STATUS(hws_ddr3_tip_load_topology_map(dev_num, tm));
+
+	return MV_OK;
+}
+
+int ddr3_tip_init_a38x(u32 dev_num, u32 board_id)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (NULL == tm)
+		return MV_FAIL;
+
+	ddr3_a38x_update_topology_map(dev_num, tm);
+	ddr3_tip_init_a38x_silicon(dev_num, board_id);
+
+	return MV_OK;
+}
+
+int ddr3_tip_a38x_get_init_freq(int dev_num, enum hws_ddr_freq *freq)
+{
+	u32 reg;
+
+	/* Read sample at reset setting */
+	reg = (reg_read(REG_DEVICE_SAR1_ADDR) >>
+	       RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) &
+		RST2_CPU_DDR_CLOCK_SELECT_IN_MASK;
+	switch (reg) {
+	case 0x0:
+	case 0x1:
+		*freq = DDR_FREQ_333;
+		break;
+	case 0x2:
+	case 0x3:
+		*freq = DDR_FREQ_400;
+		break;
+	case 0x4:
+	case 0xd:
+		*freq = DDR_FREQ_533;
+		break;
+	case 0x6:
+		*freq = DDR_FREQ_600;
+		break;
+	case 0x8:
+	case 0x11:
+	case 0x14:
+		*freq = DDR_FREQ_667;
+		break;
+	case 0xc:
+	case 0x15:
+	case 0x1b:
+		*freq = DDR_FREQ_800;
+		break;
+	case 0x10:
+		*freq = DDR_FREQ_933;
+		break;
+	case 0x12:
+		*freq = DDR_FREQ_900;
+		break;
+	case 0x13:
+		*freq = DDR_FREQ_900;
+		break;
+	default:
+		*freq = 0;
+		return MV_NOT_SUPPORTED;
+	}
+
+	return MV_OK;
+}
+
+int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq)
+{
+	u32 reg;
+
+	/* Read sample at reset setting */
+	reg = (reg_read(REG_DEVICE_SAR1_ADDR) >>
+	       RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) &
+		RST2_CPU_DDR_CLOCK_SELECT_IN_MASK;
+	switch (reg) {
+	case 0x0:
+	case 0x1:
+		/* Medium is same as TF to run PBS in this freq */
+		*freq = DDR_FREQ_333;
+		break;
+	case 0x2:
+	case 0x3:
+		/* Medium is same as TF to run PBS in this freq */
+		*freq = DDR_FREQ_400;
+		break;
+	case 0x4:
+	case 0xd:
+		*freq = DDR_FREQ_533;
+		break;
+	case 0x8:
+	case 0x11:
+	case 0x14:
+		*freq = DDR_FREQ_333;
+		break;
+	case 0xc:
+	case 0x15:
+	case 0x1b:
+		*freq = DDR_FREQ_400;
+		break;
+	case 0x6:
+		*freq = DDR_FREQ_300;
+		break;
+	case 0x12:
+		*freq = DDR_FREQ_360;
+		break;
+	case 0x13:
+		*freq = DDR_FREQ_400;
+		break;
+	default:
+		*freq = 0;
+		return MV_NOT_SUPPORTED;
+	}
+
+	return MV_OK;
+}
+
+u32 ddr3_tip_get_init_freq(void)
+{
+	enum hws_ddr_freq freq;
+
+	ddr3_tip_a38x_get_init_freq(0, &freq);
+
+	return freq;
+}
+
+static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
+				     enum hws_ddr_freq frequency)
+{
+	u32 divider = 0;
+	u32 sar_val;
+
+	if (if_id != 0) {
+		DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR,
+				      ("A38x does not support interface 0x%x\n",
+				       if_id));
+		return MV_BAD_PARAM;
+	}
+
+	/* get VCO freq index */
+	sar_val = (reg_read(REG_DEVICE_SAR1_ADDR) >>
+		   RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) &
+		RST2_CPU_DDR_CLOCK_SELECT_IN_MASK;
+	divider = a38x_vco_freq_per_sar[sar_val] / freq_val[frequency];
+
+	/* Set Sync mode */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x20220, 0x0,
+		      0x1000));
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe42f4, 0x0,
+		      0x200));
+
+	/* cpupll_clkdiv_reset_mask */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0x1f,
+		      0xff));
+
+	/* cpupll_clkdiv_reload_smooth */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260,
+		      (0x2 << 8), (0xff << 8)));
+
+	/* cpupll_clkdiv_relax_en */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260,
+		      (0x2 << 24), (0xff << 24)));
+
+	/* write the divider */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4268,
+		      (divider << 8), (0x3f << 8)));
+
+	/* set cpupll_clkdiv_reload_ratio */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264,
+		      (1 << 8), (1 << 8)));
+
+	/* undet cpupll_clkdiv_reload_ratio */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0,
+		      (1 << 8)));
+
+	/* clear cpupll_clkdiv_reload_force */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, 0,
+		      (0xff << 8)));
+
+	/* clear cpupll_clkdiv_relax_en */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, 0,
+		      (0xff << 24)));
+
+	/* clear cpupll_clkdiv_reset_mask */
+	CHECK_STATUS(ddr3_tip_a38x_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0,
+		      0xff));
+
+	/* Dunit training clock + 1:1 mode */
+	if ((frequency == DDR_FREQ_LOW_FREQ) || (freq_val[frequency] <= 400)) {
+		CHECK_STATUS(ddr3_tip_a38x_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x18488,
+			      (1 << 16), (1 << 16)));
+		CHECK_STATUS(ddr3_tip_a38x_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1524,
+			      (0 << 15), (1 << 15)));
+	} else {
+		CHECK_STATUS(ddr3_tip_a38x_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x18488,
+			      0, (1 << 16)));
+		CHECK_STATUS(ddr3_tip_a38x_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1524,
+			      (1 << 15), (1 << 15)));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * external read from memory
+ */
+int ddr3_tip_ext_read(u32 dev_num, u32 if_id, u32 reg_addr,
+		      u32 num_of_bursts, u32 *data)
+{
+	u32 burst_num;
+
+	for (burst_num = 0; burst_num < num_of_bursts * 8; burst_num++)
+		data[burst_num] = readl(reg_addr + 4 * burst_num);
+
+	return MV_OK;
+}
+
+/*
+ * external write to memory
+ */
+int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr,
+		       u32 num_of_bursts, u32 *data) {
+	u32 burst_num;
+
+	for (burst_num = 0; burst_num < num_of_bursts * 8; burst_num++)
+		writel(data[burst_num], reg_addr + 4 * burst_num);
+
+	return MV_OK;
+}
+
+int ddr3_silicon_pre_init(void)
+{
+	int result;
+
+	result = ddr3_silicon_init();
+
+	return result;
+}
+
+int ddr3_post_run_alg(void)
+{
+	return MV_OK;
+}
+
+int ddr3_silicon_post_init(void)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* Set half bus width */
+	if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask)) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+			      REG_SDRAM_CONFIG_ADDR, 0x0, 0x8000));
+	}
+
+	return MV_OK;
+}
+
+int ddr3_tip_a38x_get_device_info(u8 dev_num, struct ddr3_device_info *info_ptr)
+{
+	info_ptr->device_id = 0x6800;
+	info_ptr->ck_delay = ck_delay;
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x.h b/drivers/ddr/marvell/a38x/ddr3_a38x.h
new file mode 100644
index 0000000..49621bc
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_A38X_H
+#define _DDR3_A38X_H
+
+#define MAX_INTERFACE_NUM		1
+#define MAX_BUS_NUM			5
+
+#include "ddr3_hws_hw_training_def.h"
+
+/* Allow topolgy update from board TWSI device*/
+#if !defined(CONFIG_CUSTOMER_BOARD_SUPPORT)
+#define MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI
+#endif
+
+#define ECC_SUPPORT
+
+/* right now, we're not supporting this in mainline */
+#undef SUPPORT_STATIC_DUNIT_CONFIG
+
+/* Controler bus divider 1 for 32 bit, 2 for 64 bit */
+#define DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER	1
+
+/* Tune internal training params values */
+#define TUNE_TRAINING_PARAMS_CK_DELAY		160
+#define TUNE_TRAINING_PARAMS_CK_DELAY_16	160
+#define TUNE_TRAINING_PARAMS_PFINGER		41
+#define TUNE_TRAINING_PARAMS_NFINGER		43
+#define TUNE_TRAINING_PARAMS_PHYREG3VAL		0xa
+
+#define MARVELL_BOARD				MARVELL_BOARD_ID_BASE
+
+
+#define REG_DEVICE_SAR1_ADDR			0xe4204
+#define RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET	17
+#define RST2_CPU_DDR_CLOCK_SELECT_IN_MASK	0x1f
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_5_CTRL_ADDR		0x20050
+#define REG_XBAR_WIN_5_BASE_ADDR		0x20054
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_4_CTRL_ADDR                0x20040
+#define REG_XBAR_WIN_4_BASE_ADDR                0x20044
+#define REG_XBAR_WIN_4_REMAP_ADDR               0x20048
+#define REG_XBAR_WIN_7_REMAP_ADDR               0x20078
+#define REG_XBAR_WIN_16_CTRL_ADDR               0x200d0
+#define REG_XBAR_WIN_16_BASE_ADDR               0x200d4
+#define REG_XBAR_WIN_16_REMAP_ADDR              0x200dc
+#define REG_XBAR_WIN_19_CTRL_ADDR               0x200e8
+
+#define REG_FASTPATH_WIN_BASE_ADDR(win)         (0x20180 + (0x8 * win))
+#define REG_FASTPATH_WIN_CTRL_ADDR(win)         (0x20184 + (0x8 * win))
+
+/* SatR defined too change topology busWidth and ECC configuration */
+#define DDR_SATR_CONFIG_MASK_WIDTH		0x8
+#define DDR_SATR_CONFIG_MASK_ECC		0x10
+#define DDR_SATR_CONFIG_MASK_ECC_PUP		0x20
+
+#define	REG_SAMPLE_RESET_HIGH_ADDR		0x18600
+
+#define MV_BOARD_REFCLK				MV_BOARD_REFCLK_25MHZ
+
+/* Matrix enables DRAM modes (bus width/ECC) per boardId */
+#define TOPOLOGY_UPDATE_32BIT			0
+#define TOPOLOGY_UPDATE_32BIT_ECC		1
+#define TOPOLOGY_UPDATE_16BIT			2
+#define TOPOLOGY_UPDATE_16BIT_ECC		3
+#define TOPOLOGY_UPDATE_16BIT_ECC_PUP3		4
+#define TOPOLOGY_UPDATE { \
+		/* 32Bit, 32bit ECC, 16bit, 16bit ECC PUP4, 16bit ECC PUP3 */ \
+		{1, 1, 1, 1, 1},	/* RD_NAS_68XX_ID */ \
+		{1, 1, 1, 1, 1},	/* DB_68XX_ID	  */ \
+		{1, 0, 1, 0, 1},	/* RD_AP_68XX_ID  */ \
+		{1, 0, 1, 0, 1},	/* DB_AP_68XX_ID  */ \
+		{1, 0, 1, 0, 1},	/* DB_GP_68XX_ID  */ \
+		{0, 0, 1, 1, 0},	/* DB_BP_6821_ID  */ \
+		{1, 1, 1, 1, 1}		/* DB_AMC_6820_ID */ \
+	};
+
+enum {
+	CPU_1066MHZ_DDR_400MHZ,
+	CPU_RESERVED_DDR_RESERVED0,
+	CPU_667MHZ_DDR_667MHZ,
+	CPU_800MHZ_DDR_800MHZ,
+	CPU_RESERVED_DDR_RESERVED1,
+	CPU_RESERVED_DDR_RESERVED2,
+	CPU_RESERVED_DDR_RESERVED3,
+	LAST_FREQ
+};
+
+#define ACTIVE_INTERFACE_MASK			0x1
+
+#endif /* _DDR3_A38X_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h b/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h
new file mode 100644
index 0000000..b879a01
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_A38X_MC_STATIC_H
+#define _DDR3_A38X_MC_STATIC_H
+
+#include "ddr3_a38x.h"
+
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+static struct reg_data ddr3_customer_800[] = {
+	/* parameters for customer board (based on 800MHZ) */
+	{0x1400,	0x7b00cc30, 0xffffffff},
+	{0x1404,	0x36301820, 0xffffffff},
+	{0x1408,	0x5415baab, 0xffffffff},
+	{0x140c,	0x38411def, 0xffffffff},
+	{0x1410,	0x18300000, 0xffffffff},
+	{0x1414,	0x00000700, 0xffffffff},
+	{0x1424,	0x0060f3ff, 0xffffffff},
+	{0x1428,	0x0011a940, 0xffffffff},
+	{0x142c,	0x28c5134,  0xffffffff},
+	{0x1474,	0x00000000, 0xffffffff},
+	{0x147c,	0x0000d771, 0xffffffff},
+	{0x1494,	0x00030000, 0xffffffff},
+	{0x149c,	0x00000300, 0xffffffff},
+	{0x14a8,	0x00000000, 0xffffffff},
+	{0x14cc,	0xbd09000d, 0xffffffff},
+	{0x1504,	0xfffffff1, 0xffffffff},
+	{0x150c,	0xffffffe5, 0xffffffff},
+	{0x1514,	0x00000000, 0xffffffff},
+	{0x151c,	0x00000000, 0xffffffff},
+	{0x1538,	0x00000b0b, 0xffffffff},
+	{0x153c,	0x00000c0c, 0xffffffff},
+	{0x15d0,	0x00000670, 0xffffffff},
+	{0x15d4,	0x00000046, 0xffffffff},
+	{0x15d8,	0x00000010, 0xffffffff},
+	{0x15dc,	0x00000000, 0xffffffff},
+	{0x15e0,	0x00000023, 0xffffffff},
+	{0x15e4,	0x00203c18, 0xffffffff},
+	{0x15ec,	0xf8000019, 0xffffffff},
+	{0x16a0,	0xcc000006, 0xffffffff},	/* Clock Delay */
+	{0xe4124,	0x08008073, 0xffffffff},	/* AVS BG default */
+	{0, 0, 0}
+};
+
+#else /* CONFIG_CUSTOMER_BOARD_SUPPORT */
+
+struct reg_data ddr3_a38x_933[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* parameters for 933MHZ */
+	{0x1400,	0x7b00ce3a, 0xffffffff},
+	{0x1404,	0x36301820, 0xffffffff},
+	{0x1408,	0x7417eccf, 0xffffffff},
+	{0x140c,	0x3e421f98, 0xffffffff},
+	{0x1410,	0x1a300000, 0xffffffff},
+	{0x1414,	0x00000700, 0xffffffff},
+	{0x1424,	0x0060f3ff, 0xffffffff},
+	{0x1428,	0x0013ca50, 0xffffffff},
+	{0x142c,	0x028c5165, 0xffffffff},
+	{0x1474,	0x00000000, 0xffffffff},
+	{0x147c,	0x0000e871, 0xffffffff},
+	{0x1494,	0x00010000, 0xffffffff},
+	{0x149c,	0x00000001, 0xffffffff},
+	{0x14a8,	0x00000000, 0xffffffff},
+	{0x14cc,	0xbd09000d, 0xffffffff},
+	{0x1504,	0xffffffe1, 0xffffffff},
+	{0x150c,	0xffffffe5, 0xffffffff},
+	{0x1514,	0x00000000, 0xffffffff},
+	{0x151c,	0x00000000, 0xffffffff},
+	{0x1538,	0x00000d0d, 0xffffffff},
+	{0x153c,	0x00000d0d, 0xffffffff},
+	{0x15d0,	0x00000608, 0xffffffff},
+	{0x15d4,	0x00000044, 0xffffffff},
+	{0x15d8,	0x00000020, 0xffffffff},
+	{0x15dc,	0x00000000, 0xffffffff},
+	{0x15e0,	0x00000021, 0xffffffff},
+	{0x15e4,	0x00203c18, 0xffffffff},
+	{0x15ec,	0xf8000019, 0xffffffff},
+	{0x16a0,	0xcc000006, 0xffffffff},	/* Clock Delay */
+	{0xe4124,	0x08008073, 0xffffffff},	/* AVS BG default */
+	{0, 0, 0}
+};
+
+static struct reg_data ddr3_a38x_800[] = {
+	/* parameters for 800MHZ */
+	{0x1400,	0x7b00cc30, 0xffffffff},
+	{0x1404,	0x36301820, 0xffffffff},
+	{0x1408,	0x5415baab, 0xffffffff},
+	{0x140c,	0x38411def, 0xffffffff},
+	{0x1410,	0x18300000, 0xffffffff},
+	{0x1414,	0x00000700, 0xffffffff},
+	{0x1424,	0x0060f3ff, 0xffffffff},
+	{0x1428,	0x0011a940, 0xffffffff},
+	{0x142c,	0x28c5134,  0xffffffff},
+	{0x1474,	0x00000000, 0xffffffff},
+	{0x147c,	0x0000d771, 0xffffffff},
+	{0x1494,	0x00030000, 0xffffffff},
+	{0x149c,	0x00000300, 0xffffffff},
+	{0x14a8,	0x00000000, 0xffffffff},
+	{0x14cc,	0xbd09000d, 0xffffffff},
+	{0x1504,	0xfffffff1, 0xffffffff},
+	{0x150c,	0xffffffe5, 0xffffffff},
+	{0x1514,	0x00000000, 0xffffffff},
+	{0x151c,	0x00000000, 0xffffffff},
+	{0x1538,	0x00000b0b, 0xffffffff},
+	{0x153c,	0x00000c0c, 0xffffffff},
+	{0x15d0,	0x00000670, 0xffffffff},
+	{0x15d4,	0x00000046, 0xffffffff},
+	{0x15d8,	0x00000010, 0xffffffff},
+	{0x15dc,	0x00000000, 0xffffffff},
+	{0x15e0,	0x00000023, 0xffffffff},
+	{0x15e4,	0x00203c18, 0xffffffff},
+	{0x15ec,	0xf8000019, 0xffffffff},
+	{0x16a0,	0xcc000006, 0xffffffff},	/* Clock Delay */
+	{0xe4124,	0x08008073, 0xffffffff},	/* AVS BG default */
+	{0,   0, 0}
+};
+
+static struct reg_data ddr3_a38x_667[] = {
+	/* parameters for 667MHZ */
+	/* DDR SDRAM Configuration Register */
+	{0x1400,    0x7b00ca28, 0xffffffff},
+	/* Dunit Control Low Register - kw28 bit12 low (disable CLK1) */
+	{0x1404,    0x36301820, 0xffffffff},
+	/* DDR SDRAM Timing (Low) Register */
+	{0x1408,    0x43149997, 0xffffffff},
+	/* DDR SDRAM Timing (High) Register */
+	{0x140c,    0x38411bc7, 0xffffffff},
+	/* DDR SDRAM Address Control Register */
+	{0x1410,    0x14330000, 0xffffffff},
+	/* DDR SDRAM Open Pages Control Register */
+	{0x1414,    0x00000700, 0xffffffff},
+	/* Dunit Control High Register (2 :1 - bits 15:12 = 0xd) */
+	{0x1424,    0x0060f3ff, 0xffffffff},
+	/* Dunit Control High Register */
+	{0x1428,    0x000f8830, 0xffffffff},
+	/* Dunit Control High Register  (2:1 -  bit 29 = '1') */
+	{0x142c,    0x28c50f8,  0xffffffff},
+	{0x147c,    0x0000c671, 0xffffffff},
+	/* DDR SDRAM ODT Control (Low) Register */
+	{0x1494,    0x00030000, 0xffffffff},
+	/* DDR SDRAM ODT Control (High) Register, will be configured at WL */
+	{0x1498,    0x00000000, 0xffffffff},
+	/* DDR Dunit ODT Control Register */
+	{0x149c,    0x00000300, 0xffffffff},
+	{0x14a8,    0x00000000, 0xffffffff}, /*  */
+	{0x14cc,    0xbd09000d, 0xffffffff}, /*  */
+	{0x1474,    0x00000000, 0xffffffff},
+	/* Read Data Sample Delays Register */
+	{0x1538,    0x00000009, 0xffffffff},
+	/* Read Data Ready Delay Register */
+	{0x153c,    0x0000000c, 0xffffffff},
+	{0x1504,    0xfffffff1, 0xffffffff}, /*  */
+	{0x150c,    0xffffffe5, 0xffffffff}, /*  */
+	{0x1514,    0x00000000, 0xffffffff}, /*  */
+	{0x151c,    0x0,	0xffffffff}, /*  */
+	{0x15d0,    0x00000650, 0xffffffff}, /* MR0 */
+	{0x15d4,    0x00000046, 0xffffffff}, /* MR1 */
+	{0x15d8,    0x00000010, 0xffffffff}, /* MR2 */
+	{0x15dc,    0x00000000, 0xffffffff}, /* MR3 */
+	{0x15e0,    0x23,	0xffffffff}, /*  */
+	{0x15e4,    0x00203c18, 0xffffffff}, /* ZQC Configuration Register */
+	{0x15ec,    0xf8000019, 0xffffffff}, /* DDR PHY */
+	{0x16a0,    0xcc000006, 0xffffffff}, /* Clock Delay */
+	{0xe4124,   0x08008073, 0xffffffff}, /* AVS BG default */
+	{0, 0, 0}
+};
+
+static struct reg_data ddr3_a38x_533[] = {
+	/* parameters for 533MHZ */
+	/* DDR SDRAM Configuration Register */
+	{0x1400,    0x7b00d040, 0xffffffff},
+	/* Dunit Control Low Register - kw28 bit12 low (disable CLK1) */
+	{0x1404,    0x36301820, 0xffffffff},
+	/* DDR SDRAM Timing (Low) Register */
+	{0x1408,    0x33137772, 0xffffffff},
+	/* DDR SDRAM Timing (High) Register */
+	{0x140c,    0x3841199f, 0xffffffff},
+	/* DDR SDRAM Address Control Register */
+	{0x1410,    0x10330000, 0xffffffff},
+	/* DDR SDRAM Open Pages Control Register */
+	{0x1414,    0x00000700, 0xffffffff},
+	/* Dunit Control High Register (2 :1 - bits 15:12 = 0xd) */
+	{0x1424,    0x0060f3ff, 0xffffffff},
+	/* Dunit Control High Register */
+	{0x1428,    0x000d6720, 0xffffffff},
+	/* Dunit Control High Register  (2:1 -  bit 29 = '1') */
+	{0x142c,    0x028c50c3, 0xffffffff},
+	{0x147c,    0x0000b571, 0xffffffff},
+	/* DDR SDRAM ODT Control (Low) Register */
+	{0x1494,    0x00030000, 0xffffffff},
+	/* DDR SDRAM ODT Control (High) Register, will be configured at WL */
+	{0x1498,    0x00000000, 0xffffffff},
+	/* DDR Dunit ODT Control Register */
+	{0x149c,    0x00000003, 0xffffffff},
+	{0x14a8,    0x00000000, 0xffffffff}, /*  */
+	{0x14cc,    0xbd09000d, 0xffffffff}, /*  */
+	{0x1474,    0x00000000, 0xffffffff},
+	/* Read Data Sample Delays Register */
+	{0x1538,    0x00000707, 0xffffffff},
+	/* Read Data Ready Delay Register */
+	{0x153c,    0x00000707, 0xffffffff},
+	{0x1504,    0xffffffe1, 0xffffffff}, /*  */
+	{0x150c,    0xffffffe5, 0xffffffff}, /*  */
+	{0x1514,    0x00000000, 0xffffffff}, /*  */
+	{0x151c,    0x00000000,	0xffffffff}, /*  */
+	{0x15d0,    0x00000630, 0xffffffff}, /* MR0 */
+	{0x15d4,    0x00000046, 0xffffffff}, /* MR1 */
+	{0x15d8,    0x00000008, 0xffffffff}, /* MR2 */
+	{0x15dc,    0x00000000, 0xffffffff}, /* MR3 */
+	{0x15e0,    0x00000023,	0xffffffff}, /*  */
+	{0x15e4,    0x00203c18, 0xffffffff}, /* ZQC Configuration Register */
+	{0x15ec,    0xf8000019, 0xffffffff}, /* DDR PHY */
+	{0x16a0,    0xcc000006, 0xffffffff}, /* Clock Delay */
+	{0xe4124,   0x08008073, 0xffffffff}, /* AVS BG default */
+	{0, 0, 0}
+};
+
+#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */
+
+#endif /* SUPPORT_STATIC_DUNIT_CONFIG */
+
+#endif /* _DDR3_A38X_MC_STATIC_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h b/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h
new file mode 100644
index 0000000..f27bbff7
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_A38X_TOPOLOGY_H
+#define _DDR3_A38X_TOPOLOGY_H
+
+#include "ddr_topology_def.h"
+
+/* Bus mask variants */
+#define BUS_MASK_32BIT			0xf
+#define BUS_MASK_32BIT_ECC		0x1f
+#define BUS_MASK_16BIT			0x3
+#define BUS_MASK_16BIT_ECC		0x13
+#define BUS_MASK_16BIT_ECC_PUP3		0xb
+
+#define DYNAMIC_CS_SIZE_CONFIG
+#define DISABLE_L2_FILTERING_DURING_DDR_TRAINING
+
+#endif /* _DDR3_A38X_TOPOLOGY_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_training.c b/drivers/ddr/marvell/a38x/ddr3_a38x_training.c
new file mode 100644
index 0000000..52c43f7
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_a38x_training.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+/*
+ * Name:     ddr3_tip_init_silicon
+ * Desc:     initiate silicon parameters
+ * Args:
+ * Notes:
+ * Returns:  required value
+ */
+int ddr3_silicon_init(void)
+{
+	int status;
+	static int init_done;
+
+	if (init_done == 1)
+		return MV_OK;
+
+	status = ddr3_tip_init_a38x(0, 0);
+	if (MV_OK != status) {
+		printf("DDR3 A38x silicon init - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	init_done = 1;
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_debug.c b/drivers/ddr/marvell/a38x/ddr3_debug.c
new file mode 100644
index 0000000..1d72bc5
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_debug.c
@@ -0,0 +1,1551 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+u8 is_reg_dump = 0;
+u8 debug_pbs = DEBUG_LEVEL_ERROR;
+
+/*
+ * API to change flags outside of the lib
+ */
+#ifndef SILENT_LIB
+/* Debug flags for other Training modules */
+u8 debug_training_static = DEBUG_LEVEL_ERROR;
+u8 debug_training = DEBUG_LEVEL_ERROR;
+u8 debug_leveling = DEBUG_LEVEL_ERROR;
+u8 debug_centralization = DEBUG_LEVEL_ERROR;
+u8 debug_training_ip = DEBUG_LEVEL_ERROR;
+u8 debug_training_bist = DEBUG_LEVEL_ERROR;
+u8 debug_training_hw_alg = DEBUG_LEVEL_ERROR;
+u8 debug_training_access = DEBUG_LEVEL_ERROR;
+u8 debug_training_a38x = DEBUG_LEVEL_ERROR;
+
+void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level)
+{
+	switch (block) {
+	case DEBUG_BLOCK_STATIC:
+		debug_training_static = level;
+		break;
+	case DEBUG_BLOCK_TRAINING_MAIN:
+		debug_training = level;
+		break;
+	case DEBUG_BLOCK_LEVELING:
+		debug_leveling = level;
+		break;
+	case DEBUG_BLOCK_CENTRALIZATION:
+		debug_centralization = level;
+		break;
+	case DEBUG_BLOCK_PBS:
+		debug_pbs = level;
+		break;
+	case DEBUG_BLOCK_ALG:
+		debug_training_hw_alg = level;
+		break;
+	case DEBUG_BLOCK_DEVICE:
+		debug_training_a38x = level;
+		break;
+	case DEBUG_BLOCK_ACCESS:
+		debug_training_access = level;
+		break;
+	case DEBUG_STAGES_REG_DUMP:
+		if (level == DEBUG_LEVEL_TRACE)
+			is_reg_dump = 1;
+		else
+			is_reg_dump = 0;
+		break;
+	case DEBUG_BLOCK_ALL:
+	default:
+		debug_training_static = level;
+		debug_training = level;
+		debug_leveling = level;
+		debug_centralization = level;
+		debug_pbs = level;
+		debug_training_hw_alg = level;
+		debug_training_access = level;
+		debug_training_a38x = level;
+	}
+}
+#else
+void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level)
+{
+	return;
+}
+#endif
+
+struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM];
+u8 is_default_centralization = 0;
+u8 is_tune_result = 0;
+u8 is_validate_window_per_if = 0;
+u8 is_validate_window_per_pup = 0;
+u8 sweep_cnt = 1;
+u32 is_bist_reset_bit = 1;
+static struct hws_xsb_info xsb_info[HWS_MAX_DEVICE_NUM];
+
+/*
+ * Dump Dunit & Phy registers
+ */
+int ddr3_tip_reg_dump(u32 dev_num)
+{
+	u32 if_id, reg_addr, data_value, bus_id;
+	u32 read_data[MAX_INTERFACE_NUM];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	printf("-- dunit registers --\n");
+	for (reg_addr = 0x1400; reg_addr < 0x19f0; reg_addr += 4) {
+		printf("0x%x ", reg_addr);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			CHECK_STATUS(ddr3_tip_if_read
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id, reg_addr, read_data,
+				      MASK_ALL_BITS));
+			printf("0x%x ", read_data[if_id]);
+		}
+		printf("\n");
+	}
+
+	printf("-- Phy registers --\n");
+	for (reg_addr = 0; reg_addr <= 0xff; reg_addr++) {
+		printf("0x%x ", reg_addr);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			for (bus_id = 0;
+			     bus_id < tm->num_of_bus_per_interface;
+			     bus_id++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, bus_id,
+					      DDR_PHY_DATA, reg_addr,
+					      &data_value));
+				printf("0x%x ", data_value);
+			}
+			for (bus_id = 0;
+			     bus_id < tm->num_of_bus_per_interface;
+			     bus_id++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, bus_id,
+					      DDR_PHY_CONTROL, reg_addr,
+					      &data_value));
+				printf("0x%x ", data_value);
+			}
+		}
+		printf("\n");
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Register access func registration
+ */
+int ddr3_tip_init_config_func(u32 dev_num,
+			      struct hws_tip_config_func_db *config_func)
+{
+	if (config_func == NULL)
+		return MV_BAD_PARAM;
+
+	memcpy(&config_func_info[dev_num], config_func,
+	       sizeof(struct hws_tip_config_func_db));
+
+	return MV_OK;
+}
+
+/*
+ * Read training result table
+ */
+int hws_ddr3_tip_read_training_result(
+	u32 dev_num, enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM])
+{
+	dev_num = dev_num;
+
+	if (result == NULL)
+		return MV_BAD_PARAM;
+	memcpy(result, training_result, sizeof(result));
+
+	return MV_OK;
+}
+
+/*
+ * Get training result info pointer
+ */
+enum hws_result *ddr3_tip_get_result_ptr(u32 stage)
+{
+	return training_result[stage];
+}
+
+/*
+ * Device info read
+ */
+int ddr3_tip_get_device_info(u32 dev_num, struct ddr3_device_info *info_ptr)
+{
+	if (config_func_info[dev_num].tip_get_device_info_func != NULL) {
+		return config_func_info[dev_num].
+			tip_get_device_info_func((u8) dev_num, info_ptr);
+	}
+
+	return MV_FAIL;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Convert freq to character string
+ */
+static char *convert_freq(enum hws_ddr_freq freq)
+{
+	switch (freq) {
+	case DDR_FREQ_LOW_FREQ:
+		return "DDR_FREQ_LOW_FREQ";
+	case DDR_FREQ_400:
+		return "400";
+
+	case DDR_FREQ_533:
+		return "533";
+	case DDR_FREQ_667:
+		return "667";
+
+	case DDR_FREQ_800:
+		return "800";
+
+	case DDR_FREQ_933:
+		return "933";
+
+	case DDR_FREQ_1066:
+		return "1066";
+	case DDR_FREQ_311:
+		return "311";
+
+	case DDR_FREQ_333:
+		return "333";
+
+	case DDR_FREQ_467:
+		return "467";
+
+	case DDR_FREQ_850:
+		return "850";
+
+	case DDR_FREQ_900:
+		return "900";
+
+	case DDR_FREQ_360:
+		return "DDR_FREQ_360";
+
+	case DDR_FREQ_1000:
+		return "DDR_FREQ_1000";
+	default:
+		return "Unknown Frequency";
+	}
+}
+
+/*
+ * Convert device ID to character string
+ */
+static char *convert_dev_id(u32 dev_id)
+{
+	switch (dev_id) {
+	case 0x6800:
+		return "A38xx";
+	case 0x6900:
+		return "A39XX";
+	case 0xf400:
+		return "AC3";
+	case 0xfc00:
+		return "BC2";
+
+	default:
+		return "Unknown Device";
+	}
+}
+
+/*
+ * Convert device ID to character string
+ */
+static char *convert_mem_size(u32 dev_id)
+{
+	switch (dev_id) {
+	case 0:
+		return "512 MB";
+	case 1:
+		return "1 GB";
+	case 2:
+		return "2 GB";
+	case 3:
+		return "4 GB";
+	case 4:
+		return "8 GB";
+
+	default:
+		return "wrong mem size";
+	}
+}
+
+int print_device_info(u8 dev_num)
+{
+	struct ddr3_device_info info_ptr;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	CHECK_STATUS(ddr3_tip_get_device_info(dev_num, &info_ptr));
+	printf("=== DDR setup START===\n");
+	printf("\tDevice ID: %s\n", convert_dev_id(info_ptr.device_id));
+	printf("\tDDR3  CK delay: %d\n", info_ptr.ck_delay);
+	print_topology(tm);
+	printf("=== DDR setup END===\n");
+
+	return MV_OK;
+}
+
+void hws_ddr3_tip_sweep_test(int enable)
+{
+	if (enable) {
+		is_validate_window_per_if = 1;
+		is_validate_window_per_pup = 1;
+		debug_training = DEBUG_LEVEL_TRACE;
+	} else {
+		is_validate_window_per_if = 0;
+		is_validate_window_per_pup = 0;
+	}
+}
+#endif
+
+char *ddr3_tip_convert_tune_result(enum hws_result tune_result)
+{
+	switch (tune_result) {
+	case TEST_FAILED:
+		return "FAILED";
+	case TEST_SUCCESS:
+		return "PASS";
+	case NO_TEST_DONE:
+		return "NOT COMPLETED";
+	default:
+		return "Un-KNOWN";
+	}
+}
+
+/*
+ * Print log info
+ */
+int ddr3_tip_print_log(u32 dev_num, u32 mem_addr)
+{
+	u32 if_id = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	mem_addr = mem_addr;
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+	if ((is_validate_window_per_if != 0) ||
+	    (is_validate_window_per_pup != 0)) {
+		u32 is_pup_log = 0;
+		enum hws_ddr_freq freq;
+
+		freq = tm->interface_params[first_active_if].memory_freq;
+
+		is_pup_log = (is_validate_window_per_pup != 0) ? 1 : 0;
+		printf("===VALIDATE WINDOW LOG START===\n");
+		printf("DDR Frequency: %s   ======\n", convert_freq(freq));
+		/* print sweep windows */
+		ddr3_tip_run_sweep_test(dev_num, sweep_cnt, 1, is_pup_log);
+		ddr3_tip_run_sweep_test(dev_num, sweep_cnt, 0, is_pup_log);
+		ddr3_tip_print_all_pbs_result(dev_num);
+		ddr3_tip_print_wl_supp_result(dev_num);
+		printf("===VALIDATE WINDOW LOG END ===\n");
+		CHECK_STATUS(ddr3_tip_restore_dunit_regs(dev_num));
+		ddr3_tip_reg_dump(dev_num);
+	}
+#endif
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("IF %d Status:\n", if_id));
+
+		if (mask_tune_func & INIT_CONTROLLER_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tInit Controller: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[INIT_CONTROLLER]
+					    [if_id])));
+		}
+		if (mask_tune_func & SET_LOW_FREQ_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tLow freq Config: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[SET_LOW_FREQ]
+					    [if_id])));
+		}
+		if (mask_tune_func & LOAD_PATTERN_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tLoad Pattern: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[LOAD_PATTERN]
+					    [if_id])));
+		}
+		if (mask_tune_func & SET_MEDIUM_FREQ_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tMedium freq Config: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[SET_MEDIUM_FREQ]
+					    [if_id])));
+		}
+		if (mask_tune_func & WRITE_LEVELING_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tWL: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[WRITE_LEVELING]
+					    [if_id])));
+		}
+		if (mask_tune_func & LOAD_PATTERN_2_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tLoad Pattern: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[LOAD_PATTERN_2]
+					    [if_id])));
+		}
+		if (mask_tune_func & READ_LEVELING_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tRL: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[READ_LEVELING]
+					    [if_id])));
+		}
+		if (mask_tune_func & WRITE_LEVELING_SUPP_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tWL Supp: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[WRITE_LEVELING_SUPP]
+					    [if_id])));
+		}
+		if (mask_tune_func & PBS_RX_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tPBS RX: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[PBS_RX]
+					    [if_id])));
+		}
+		if (mask_tune_func & PBS_TX_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tPBS TX: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[PBS_TX]
+					    [if_id])));
+		}
+		if (mask_tune_func & SET_TARGET_FREQ_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tTarget freq Config: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[SET_TARGET_FREQ]
+					    [if_id])));
+		}
+		if (mask_tune_func & WRITE_LEVELING_TF_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tWL TF: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[WRITE_LEVELING_TF]
+					    [if_id])));
+		}
+		if (mask_tune_func & READ_LEVELING_TF_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tRL TF: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[READ_LEVELING_TF]
+					    [if_id])));
+		}
+		if (mask_tune_func & WRITE_LEVELING_SUPP_TF_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tWL TF Supp: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result
+					    [WRITE_LEVELING_SUPP_TF]
+					    [if_id])));
+		}
+		if (mask_tune_func & CENTRALIZATION_RX_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tCentr RX: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[CENTRALIZATION_RX]
+					    [if_id])));
+		}
+		if (mask_tune_func & VREF_CALIBRATION_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tVREF_CALIBRATION: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[VREF_CALIBRATION]
+					    [if_id])));
+		}
+		if (mask_tune_func & CENTRALIZATION_TX_MASK_BIT) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("\tCentr TX: %s\n",
+					   ddr3_tip_convert_tune_result
+					   (training_result[CENTRALIZATION_TX]
+					    [if_id])));
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Print stability log info
+ */
+int ddr3_tip_print_stability_log(u32 dev_num)
+{
+	u8 if_id = 0, csindex = 0, bus_id = 0, idx = 0;
+	u32 reg_data;
+	u32 read_data[MAX_INTERFACE_NUM];
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* Title print */
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		printf("Title: I/F# , Tj, Calibration_n0, Calibration_p0, Calibration_n1, Calibration_p1, Calibration_n2, Calibration_p2,");
+		for (csindex = 0; csindex < max_cs; csindex++) {
+			printf("CS%d , ", csindex);
+			printf("\n");
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			printf("VWTx, VWRx, WL_tot, WL_ADLL, WL_PH, RL_Tot, RL_ADLL, RL_PH, RL_Smp, Cen_tx, Cen_rx, Vref, DQVref,");
+			printf("\t\t");
+			for (idx = 0; idx < 11; idx++)
+				printf("PBSTx-Pad%d,", idx);
+			printf("\t\t");
+			for (idx = 0; idx < 11; idx++)
+				printf("PBSRx-Pad%d,", idx);
+		}
+	}
+	printf("\n");
+
+	/* Data print */
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+		printf("Data: %d,%d,", if_id,
+		       (config_func_info[dev_num].tip_get_temperature != NULL)
+		       ? (config_func_info[dev_num].
+			  tip_get_temperature(dev_num)) : (0));
+
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x14c8,
+			      read_data, MASK_ALL_BITS));
+		printf("%d,%d,", ((read_data[if_id] & 0x3f0) >> 4),
+		       ((read_data[if_id] & 0xfc00) >> 10));
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x17c8,
+			      read_data, MASK_ALL_BITS));
+		printf("%d,%d,", ((read_data[if_id] & 0x3f0) >> 4),
+		       ((read_data[if_id] & 0xfc00) >> 10));
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1dc8,
+			      read_data, MASK_ALL_BITS));
+		printf("%d,%d,", ((read_data[if_id] & 0x3f0000) >> 16),
+		       ((read_data[if_id] & 0xfc00000) >> 22));
+
+		for (csindex = 0; csindex < max_cs; csindex++) {
+			printf("CS%d , ", csindex);
+			for (bus_id = 0; bus_id < MAX_BUS_NUM; bus_id++) {
+				printf("\n");
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST,
+						  bus_id, DDR_PHY_DATA,
+						  RESULT_DB_PHY_REG_ADDR +
+						  csindex, &reg_data);
+				printf("%d,%d,", (reg_data & 0x1f),
+				       ((reg_data & 0x3e0) >> 5));
+				/* WL */
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST,
+						  bus_id, DDR_PHY_DATA,
+						  WL_PHY_REG +
+						  csindex * 4, &reg_data);
+				printf("%d,%d,%d,",
+				       (reg_data & 0x1f) +
+				       ((reg_data & 0x1c0) >> 6) * 32,
+				       (reg_data & 0x1f),
+				       (reg_data & 0x1c0) >> 6);
+				/* RL */
+				CHECK_STATUS(ddr3_tip_if_read
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id,
+					      READ_DATA_SAMPLE_DELAY,
+					      read_data, MASK_ALL_BITS));
+				read_data[if_id] =
+					(read_data[if_id] &
+					 (0xf << (4 * csindex))) >>
+					(4 * csindex);
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, bus_id,
+						  DDR_PHY_DATA,
+						  RL_PHY_REG + csindex * 4,
+						  &reg_data);
+				printf("%d,%d,%d,%d,",
+				       (reg_data & 0x1f) +
+				       ((reg_data & 0x1c0) >> 6) * 32 +
+				       read_data[if_id] * 64,
+				       (reg_data & 0x1f),
+				       ((reg_data & 0x1c0) >> 6),
+				       read_data[if_id]);
+				/* Centralization */
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, bus_id,
+						  DDR_PHY_DATA,
+						  WRITE_CENTRALIZATION_PHY_REG
+						  + csindex * 4, &reg_data);
+				printf("%d,", (reg_data & 0x3f));
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, bus_id,
+						  DDR_PHY_DATA,
+						  READ_CENTRALIZATION_PHY_REG
+						  + csindex * 4, &reg_data);
+				printf("%d,", (reg_data & 0x1f));
+				/* Vref */
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, bus_id,
+						  DDR_PHY_DATA,
+						  PAD_CONFIG_PHY_REG,
+						  &reg_data);
+				printf("%d,", (reg_data & 0x7));
+				/* DQVref */
+				/* Need to add the Read Function from device */
+				printf("%d,", 0);
+				printf("\t\t");
+				for (idx = 0; idx < 11; idx++) {
+					ddr3_tip_bus_read(dev_num, if_id,
+							  ACCESS_TYPE_UNICAST,
+							  bus_id, DDR_PHY_DATA,
+							  0xd0 +
+							  12 * csindex +
+							  idx, &reg_data);
+					printf("%d,", (reg_data & 0x3f));
+				}
+				printf("\t\t");
+				for (idx = 0; idx < 11; idx++) {
+					ddr3_tip_bus_read(dev_num, if_id,
+							  ACCESS_TYPE_UNICAST,
+							  bus_id, DDR_PHY_DATA,
+							  0x10 +
+							  16 * csindex +
+							  idx, &reg_data);
+					printf("%d,", (reg_data & 0x3f));
+				}
+				printf("\t\t");
+				for (idx = 0; idx < 11; idx++) {
+					ddr3_tip_bus_read(dev_num, if_id,
+							  ACCESS_TYPE_UNICAST,
+							  bus_id, DDR_PHY_DATA,
+							  0x50 +
+							  16 * csindex +
+							  idx, &reg_data);
+					printf("%d,", (reg_data & 0x3f));
+				}
+			}
+		}
+	}
+	printf("\n");
+
+	return MV_OK;
+}
+
+/*
+ * Register XSB information
+ */
+int ddr3_tip_register_xsb_info(u32 dev_num, struct hws_xsb_info *xsb_info_table)
+{
+	memcpy(&xsb_info[dev_num], xsb_info_table, sizeof(struct hws_xsb_info));
+	return MV_OK;
+}
+
+/*
+ * Read ADLL Value
+ */
+int read_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+		    int reg_addr, u32 mask)
+{
+	u32 data_value;
+	u32 if_id = 0, bus_id = 0;
+	u32 dev_num = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/*
+	 * multi CS support - reg_addr is calucalated in calling function
+	 * with CS offset
+	 */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+		     bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id,
+						       ACCESS_TYPE_UNICAST,
+						       bus_id,
+						       DDR_PHY_DATA, reg_addr,
+						       &data_value));
+			pup_values[if_id *
+				   tm->num_of_bus_per_interface + bus_id] =
+				data_value & mask;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Write ADLL Value
+ */
+int write_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+		     int reg_addr)
+{
+	u32 if_id = 0, bus_id = 0;
+	u32 dev_num = 0, data;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/*
+	 * multi CS support - reg_addr is calucalated in calling function
+	 * with CS offset
+	 */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+		     bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			data = pup_values[if_id *
+					  tm->num_of_bus_per_interface +
+					  bus_id];
+			CHECK_STATUS(ddr3_tip_bus_write(dev_num,
+							ACCESS_TYPE_UNICAST,
+							if_id,
+							ACCESS_TYPE_UNICAST,
+							bus_id, DDR_PHY_DATA,
+							reg_addr, data));
+		}
+	}
+
+	return 0;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+u32 rl_version = 1;		/* 0 - old RL machine */
+struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM];
+u32 start_xsb_offset = 0;
+u8 is_rl_old = 0;
+u8 is_freq_old = 0;
+u8 is_dfs_disabled = 0;
+u32 default_centrlization_value = 0x12;
+u32 vref = 0x4;
+u32 activate_select_before_run_alg = 1, activate_deselect_after_run_alg = 1,
+	rl_test = 0, reset_read_fifo = 0;
+int debug_acc = 0;
+u32 ctrl_sweepres[ADLL_LENGTH][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u32 ctrl_adll[MAX_CS_NUM * MAX_INTERFACE_NUM * MAX_BUS_NUM];
+u8 cs_mask_reg[] = {
+	0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+u32 xsb_test_table[][8] = {
+	{0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555,
+	 0x66666666, 0x77777777},
+	{0x88888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd,
+	 0xeeeeeeee, 0xffffffff},
+	{0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+	 0x00000000, 0xffffffff},
+	{0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+	 0x00000000, 0xffffffff},
+	{0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+	 0x00000000, 0xffffffff},
+	{0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+	 0x00000000, 0xffffffff},
+	{0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	 0xffffffff, 0xffffffff},
+	{0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000,
+	 0x00000000, 0x00000000},
+	{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+	 0xffffffff, 0xffffffff}
+};
+
+static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr);
+
+int ddr3_tip_print_adll(void)
+{
+	u32 bus_cnt = 0, if_id, data_p1, data_p2, ui_data3, dev_num = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+		     bus_cnt++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id,
+				      ACCESS_TYPE_UNICAST, bus_cnt,
+				      DDR_PHY_DATA, 0x1, &data_p1));
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id, ACCESS_TYPE_UNICAST,
+				      bus_cnt, DDR_PHY_DATA, 0x2, &data_p2));
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id, ACCESS_TYPE_UNICAST,
+				      bus_cnt, DDR_PHY_DATA, 0x3, &ui_data3));
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+					  (" IF %d bus_cnt %d  phy_reg_1_data 0x%x phy_reg_2_data 0x%x phy_reg_3_data 0x%x\n",
+					   if_id, bus_cnt, data_p1, data_p2,
+					   ui_data3));
+			}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Set attribute value
+ */
+int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value)
+{
+	int ret;
+	u32 *ptr_flag = NULL;
+
+	ret = ddr3_tip_access_atr(dev_num, flag_id, value, &ptr_flag);
+	if (ptr_flag != NULL) {
+		printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x (was 0x%x)\n",
+		       flag_id, value, *ptr_flag);
+		*ptr_flag = value;
+	} else {
+		printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x\n",
+		       flag_id, value);
+	}
+
+	return ret;
+}
+
+/*
+ * Access attribute
+ */
+static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr)
+{
+	u32 tmp_val = 0, if_id = 0, pup_id = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	dev_num = dev_num;
+	*ptr = NULL;
+
+	switch (flag_id) {
+	case 0:
+		*ptr = (u32 *)&(tm->if_act_mask);
+		break;
+
+	case 0x1:
+		*ptr = (u32 *)&mask_tune_func;
+		break;
+
+	case 0x2:
+		*ptr = (u32 *)&low_freq;
+		break;
+
+	case 0x3:
+		*ptr = (u32 *)&medium_freq;
+		break;
+
+	case 0x4:
+		*ptr = (u32 *)&generic_init_controller;
+		break;
+
+	case 0x5:
+		*ptr = (u32 *)&rl_version;
+		break;
+
+	case 0x8:
+		*ptr = (u32 *)&start_xsb_offset;
+		break;
+
+	case 0x20:
+		*ptr = (u32 *)&is_rl_old;
+		break;
+
+	case 0x21:
+		*ptr = (u32 *)&is_freq_old;
+		break;
+
+	case 0x23:
+		*ptr = (u32 *)&is_dfs_disabled;
+		break;
+
+	case 0x24:
+		*ptr = (u32 *)&is_pll_before_init;
+		break;
+
+	case 0x25:
+		*ptr = (u32 *)&is_adll_calib_before_init;
+		break;
+#ifdef STATIC_ALGO_SUPPORT
+	case 0x26:
+		*ptr = (u32 *)&(silicon_delay[0]);
+		break;
+
+	case 0x27:
+		*ptr = (u32 *)&wl_debug_delay;
+		break;
+#endif
+	case 0x28:
+		*ptr = (u32 *)&is_tune_result;
+		break;
+
+	case 0x29:
+		*ptr = (u32 *)&is_validate_window_per_if;
+		break;
+
+	case 0x2a:
+		*ptr = (u32 *)&is_validate_window_per_pup;
+		break;
+
+	case 0x30:
+		*ptr = (u32 *)&sweep_cnt;
+		break;
+
+	case 0x31:
+		*ptr = (u32 *)&is_bist_reset_bit;
+		break;
+
+	case 0x32:
+		*ptr = (u32 *)&is_dfs_in_init;
+		break;
+
+	case 0x33:
+		*ptr = (u32 *)&p_finger;
+		break;
+
+	case 0x34:
+		*ptr = (u32 *)&n_finger;
+		break;
+
+	case 0x35:
+		*ptr = (u32 *)&init_freq;
+		break;
+
+	case 0x36:
+		*ptr = (u32 *)&(freq_val[DDR_FREQ_LOW_FREQ]);
+		break;
+
+	case 0x37:
+		*ptr = (u32 *)&start_pattern;
+		break;
+
+	case 0x38:
+		*ptr = (u32 *)&end_pattern;
+		break;
+
+	case 0x39:
+		*ptr = (u32 *)&phy_reg0_val;
+		break;
+
+	case 0x4a:
+		*ptr = (u32 *)&phy_reg1_val;
+		break;
+
+	case 0x4b:
+		*ptr = (u32 *)&phy_reg2_val;
+		break;
+
+	case 0x4c:
+		*ptr = (u32 *)&phy_reg3_val;
+		break;
+
+	case 0x4e:
+		*ptr = (u32 *)&sweep_pattern;
+		break;
+
+	case 0x50:
+		*ptr = (u32 *)&is_rzq6;
+		break;
+
+	case 0x51:
+		*ptr = (u32 *)&znri_data_phy_val;
+		break;
+
+	case 0x52:
+		*ptr = (u32 *)&zpri_data_phy_val;
+		break;
+
+	case 0x53:
+		*ptr = (u32 *)&finger_test;
+		break;
+
+	case 0x54:
+		*ptr = (u32 *)&n_finger_start;
+		break;
+
+	case 0x55:
+		*ptr = (u32 *)&n_finger_end;
+		break;
+
+	case 0x56:
+		*ptr = (u32 *)&p_finger_start;
+		break;
+
+	case 0x57:
+		*ptr = (u32 *)&p_finger_end;
+		break;
+
+	case 0x58:
+		*ptr = (u32 *)&p_finger_step;
+		break;
+
+	case 0x59:
+		*ptr = (u32 *)&n_finger_step;
+		break;
+
+	case 0x5a:
+		*ptr = (u32 *)&znri_ctrl_phy_val;
+		break;
+
+	case 0x5b:
+		*ptr = (u32 *)&zpri_ctrl_phy_val;
+		break;
+
+	case 0x5c:
+		*ptr = (u32 *)&is_reg_dump;
+		break;
+
+	case 0x5d:
+		*ptr = (u32 *)&vref;
+		break;
+
+	case 0x5e:
+		*ptr = (u32 *)&mode2_t;
+		break;
+
+	case 0x5f:
+		*ptr = (u32 *)&xsb_validate_type;
+		break;
+
+	case 0x60:
+		*ptr = (u32 *)&xsb_validation_base_address;
+		break;
+
+	case 0x67:
+		*ptr = (u32 *)&activate_select_before_run_alg;
+		break;
+
+	case 0x68:
+		*ptr = (u32 *)&activate_deselect_after_run_alg;
+		break;
+
+	case 0x69:
+		*ptr = (u32 *)&odt_additional;
+		break;
+
+	case 0x70:
+		*ptr = (u32 *)&debug_mode;
+		break;
+
+	case 0x71:
+		*ptr = (u32 *)&pbs_pattern;
+		break;
+
+	case 0x72:
+		*ptr = (u32 *)&delay_enable;
+		break;
+
+	case 0x73:
+		*ptr = (u32 *)&ck_delay;
+		break;
+
+	case 0x74:
+		*ptr = (u32 *)&ck_delay_16;
+		break;
+
+	case 0x75:
+		*ptr = (u32 *)&ca_delay;
+		break;
+
+	case 0x100:
+		*ptr = (u32 *)&debug_dunit;
+		break;
+
+	case 0x101:
+		debug_acc = (int)value;
+		break;
+
+	case 0x102:
+		debug_training = (u8)value;
+		break;
+
+	case 0x103:
+		debug_training_bist = (u8)value;
+		break;
+
+	case 0x104:
+		debug_centralization = (u8)value;
+		break;
+
+	case 0x105:
+		debug_training_ip = (u8)value;
+		break;
+
+	case 0x106:
+		debug_leveling = (u8)value;
+		break;
+
+	case 0x107:
+		debug_pbs = (u8)value;
+		break;
+
+	case 0x108:
+		debug_training_static = (u8)value;
+		break;
+
+	case 0x109:
+		debug_training_access = (u8)value;
+		break;
+
+	case 0x112:
+		*ptr = &start_pattern;
+		break;
+
+	case 0x113:
+		*ptr = &end_pattern;
+		break;
+
+	default:
+		if ((flag_id >= 0x200) && (flag_id < 0x210)) {
+			if_id = flag_id - 0x200;
+			*ptr = (u32 *)&(tm->interface_params
+					[if_id].memory_freq);
+		} else if ((flag_id >= 0x210) && (flag_id < 0x220)) {
+			if_id = flag_id - 0x210;
+			*ptr = (u32 *)&(tm->interface_params
+					[if_id].speed_bin_index);
+		} else if ((flag_id >= 0x220) && (flag_id < 0x230)) {
+			if_id = flag_id - 0x220;
+			*ptr = (u32 *)&(tm->interface_params
+					[if_id].bus_width);
+		} else if ((flag_id >= 0x230) && (flag_id < 0x240)) {
+			if_id = flag_id - 0x230;
+			*ptr = (u32 *)&(tm->interface_params
+					[if_id].memory_size);
+		} else if ((flag_id >= 0x240) && (flag_id < 0x250)) {
+			if_id = flag_id - 0x240;
+			*ptr = (u32 *)&(tm->interface_params
+					[if_id].cas_l);
+		} else if ((flag_id >= 0x250) && (flag_id < 0x260)) {
+			if_id = flag_id - 0x250;
+			*ptr = (u32 *)&(tm->interface_params
+					[if_id].cas_wl);
+		} else if ((flag_id >= 0x270) && (flag_id < 0x2cf)) {
+			if_id = (flag_id - 0x270) / MAX_BUS_NUM;
+			pup_id = (flag_id - 0x270) % MAX_BUS_NUM;
+			*ptr = (u32 *)&(tm->interface_params[if_id].
+					as_bus_params[pup_id].is_ck_swap);
+		} else if ((flag_id >= 0x2d0) && (flag_id < 0x32f)) {
+			if_id = (flag_id - 0x2d0) / MAX_BUS_NUM;
+			pup_id = (flag_id - 0x2d0) % MAX_BUS_NUM;
+			*ptr = (u32 *)&(tm->interface_params[if_id].
+					as_bus_params[pup_id].is_dqs_swap);
+		} else if ((flag_id >= 0x330) && (flag_id < 0x38f)) {
+			if_id = (flag_id - 0x330) / MAX_BUS_NUM;
+			pup_id = (flag_id - 0x330) % MAX_BUS_NUM;
+			*ptr = (u32 *)&(tm->interface_params[if_id].
+					as_bus_params[pup_id].cs_bitmask);
+		} else if ((flag_id >= 0x390) && (flag_id < 0x3ef)) {
+			if_id = (flag_id - 0x390) / MAX_BUS_NUM;
+			pup_id = (flag_id - 0x390) % MAX_BUS_NUM;
+			*ptr = (u32 *)&(tm->interface_params
+					[if_id].as_bus_params
+					[pup_id].mirror_enable_bitmask);
+		} else if ((flag_id >= 0x500) && (flag_id <= 0x50f)) {
+			tmp_val = flag_id - 0x320;
+			*ptr = (u32 *)&(clamp_tbl[tmp_val]);
+		} else {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("flag_id out of boundary %d\n",
+					   flag_id));
+			return MV_BAD_PARAM;
+		}
+	}
+
+	return MV_OK;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Print ADLL
+ */
+int print_adll(u32 dev_num, u32 adll[MAX_INTERFACE_NUM * MAX_BUS_NUM])
+{
+	u32 i, j;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	dev_num = dev_num;
+
+	for (j = 0; j < tm->num_of_bus_per_interface; j++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, j);
+		for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+			printf("%d ,",
+			       adll[i * tm->num_of_bus_per_interface + j]);
+		}
+	}
+	printf("\n");
+
+	return MV_OK;
+}
+#endif
+
+/* byte_index - only byte 0, 1, 2, or 3, oxff - test all bytes */
+static u32 ddr3_tip_compare(u32 if_id, u32 *p_src, u32 *p_dst,
+			    u32 byte_index)
+{
+	u32 burst_cnt = 0, addr_offset, i_id;
+	int b_is_fail = 0;
+
+	addr_offset =
+		(byte_index ==
+		 0xff) ? (u32) 0xffffffff : (u32) (0xff << (byte_index * 8));
+	for (burst_cnt = 0; burst_cnt < EXT_ACCESS_BURST_LENGTH; burst_cnt++) {
+		if ((p_src[burst_cnt] & addr_offset) !=
+		    (p_dst[burst_cnt] & addr_offset))
+			b_is_fail = 1;
+	}
+
+	if (b_is_fail == 1) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("IF %d exp: ", if_id));
+		for (i_id = 0; i_id <= MAX_INTERFACE_NUM - 1; i_id++) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("0x%8x ", p_src[i_id]));
+		}
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("\n_i_f %d rcv: ", if_id));
+		for (i_id = 0; i_id <= MAX_INTERFACE_NUM - 1; i_id++) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("(0x%8x ", p_dst[i_id]));
+		}
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("\n "));
+	}
+
+	return b_is_fail;
+}
+
+/* test_type = 0-tx , 1-rx */
+int ddr3_tip_sweep_test(u32 dev_num, u32 test_type,
+			u32 mem_addr, u32 is_modify_adll,
+			u32 start_if, u32 end_if, u32 startpup, u32 endpup)
+{
+	u32 bus_cnt = 0, adll_val = 0, if_id, ui_prev_adll, ui_mask_bit,
+		end_adll, start_adll;
+	u32 reg_addr = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	mem_addr = mem_addr;
+
+	if (test_type == 0) {
+		reg_addr = 1;
+		ui_mask_bit = 0x3f;
+		start_adll = 0;
+		end_adll = ui_mask_bit;
+	} else {
+		reg_addr = 3;
+		ui_mask_bit = 0x1f;
+		start_adll = 0;
+		end_adll = ui_mask_bit;
+	}
+
+	DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+			  ("==============================\n"));
+	DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+			  ("Test type %d (0-tx, 1-rx)\n", test_type));
+
+	for (if_id = start_if; if_id <= end_if; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_cnt = startpup; bus_cnt < endpup; bus_cnt++) {
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id, ACCESS_TYPE_UNICAST,
+				      bus_cnt, DDR_PHY_DATA, reg_addr,
+				      &ui_prev_adll));
+
+			for (adll_val = start_adll; adll_val <= end_adll;
+			     adll_val++) {
+				if (is_modify_adll == 1) {
+					CHECK_STATUS(ddr3_tip_bus_read_modify_write
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id, bus_cnt,
+						      DDR_PHY_DATA, reg_addr,
+						      adll_val, ui_mask_bit));
+				}
+			}
+			if (is_modify_adll == 1) {
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      bus_cnt, DDR_PHY_DATA, reg_addr,
+					      ui_prev_adll));
+			}
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("\n"));
+		}
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("\n"));
+	}
+
+	return MV_OK;
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Sweep validation
+ */
+int ddr3_tip_run_sweep_test(int dev_num, u32 repeat_num, u32 direction,
+			    u32 mode)
+{
+	u32 pup = 0, start_pup = 0, end_pup = 0;
+	u32 adll = 0;
+	u32 res[MAX_INTERFACE_NUM] = { 0 };
+	int if_id = 0;
+	u32 adll_value = 0;
+	int reg = (direction == 0) ? WRITE_CENTRALIZATION_PHY_REG :
+		READ_CENTRALIZATION_PHY_REG;
+	enum hws_access_type pup_access;
+	u32 cs;
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	repeat_num = repeat_num;
+
+	if (mode == 1) {
+		/* per pup */
+		start_pup = 0;
+		end_pup = tm->num_of_bus_per_interface - 1;
+		pup_access = ACCESS_TYPE_UNICAST;
+	} else {
+		start_pup = 0;
+		end_pup = 0;
+		pup_access = ACCESS_TYPE_MULTICAST;
+	}
+
+	for (cs = 0; cs < max_cs; cs++) {
+		for (adll = 0; adll < ADLL_LENGTH; adll++) {
+			for (if_id = 0;
+			     if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE
+					(tm->if_act_mask,
+					 if_id);
+				for (pup = start_pup; pup <= end_pup; pup++) {
+					ctrl_sweepres[adll][if_id][pup] =
+						0;
+				}
+			}
+		}
+
+		for (adll = 0; adll < (MAX_INTERFACE_NUM * MAX_BUS_NUM); adll++)
+			ctrl_adll[adll] = 0;
+		/* Save DQS value(after algorithm run) */
+		read_adll_value(ctrl_adll,
+				(reg + (cs * CS_REGISTER_ADDR_OFFSET)),
+				MASK_ALL_BITS);
+
+		/*
+		 * Sweep ADLL  from 0:31 on all I/F on all Pup and perform
+		 * BIST on each stage.
+		 */
+		for (pup = start_pup; pup <= end_pup; pup++) {
+			for (adll = 0; adll < ADLL_LENGTH; adll++) {
+				adll_value =
+					(direction == 0) ? (adll * 2) : adll;
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_MULTICAST, 0,
+					      pup_access, pup, DDR_PHY_DATA,
+					      reg + CS_REG_VALUE(cs),
+					      adll_value));
+				hws_ddr3_run_bist(dev_num, sweep_pattern, res,
+						  cs);
+				/* ddr3_tip_reset_fifo_ptr(dev_num); */
+				for (if_id = 0;
+				     if_id <= MAX_INTERFACE_NUM - 1;
+				     if_id++) {
+					VALIDATE_ACTIVE
+						(tm->if_act_mask,
+						 if_id);
+					ctrl_sweepres[adll][if_id][pup]
+						= res[if_id];
+					if (mode == 1) {
+						CHECK_STATUS
+							(ddr3_tip_bus_write
+							 (dev_num,
+							  ACCESS_TYPE_UNICAST,
+							  if_id,
+							  ACCESS_TYPE_UNICAST,
+							  pup,
+							  DDR_PHY_DATA,
+							  reg + CS_REG_VALUE(cs),
+							  ctrl_adll[if_id *
+								    cs *
+								    tm->num_of_bus_per_interface
+								    + pup]));
+					}
+				}
+			}
+		}
+		printf("Final, CS %d,%s, Sweep, Result, Adll,", cs,
+		       ((direction == 0) ? "TX" : "RX"));
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			if (mode == 1) {
+				for (pup = start_pup; pup <= end_pup; pup++) {
+					VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+					printf("I/F%d-PHY%d , ", if_id, pup);
+				}
+			} else {
+				printf("I/F%d , ", if_id);
+			}
+		}
+		printf("\n");
+
+		for (adll = 0; adll < ADLL_LENGTH; adll++) {
+			adll_value = (direction == 0) ? (adll * 2) : adll;
+			printf("Final,%s, Sweep, Result, %d ,",
+			       ((direction == 0) ? "TX" : "RX"), adll_value);
+
+			for (if_id = 0;
+			     if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				for (pup = start_pup; pup <= end_pup; pup++) {
+					printf("%d , ",
+					       ctrl_sweepres[adll][if_id]
+					       [pup]);
+				}
+			}
+			printf("\n");
+		}
+
+		/*
+		 * Write back to the phy the Rx DQS value, we store in
+		 * the beginning.
+		 */
+		write_adll_value(ctrl_adll,
+				 (reg + cs * CS_REGISTER_ADDR_OFFSET));
+		/* print adll results */
+		read_adll_value(ctrl_adll, (reg + cs * CS_REGISTER_ADDR_OFFSET),
+				MASK_ALL_BITS);
+		printf("%s, DQS, ADLL,,,", (direction == 0) ? "Tx" : "Rx");
+		print_adll(dev_num, ctrl_adll);
+	}
+	ddr3_tip_reset_fifo_ptr(dev_num);
+
+	return 0;
+}
+
+void print_topology(struct hws_topology_map *topology_db)
+{
+	u32 ui, uj;
+
+	printf("\tinterface_mask: 0x%x\n", topology_db->if_act_mask);
+	printf("\tNum Bus:  %d\n", topology_db->num_of_bus_per_interface);
+	printf("\tbus_act_mask: 0x%x\n", topology_db->bus_act_mask);
+
+	for (ui = 0; ui < MAX_INTERFACE_NUM; ui++) {
+		VALIDATE_ACTIVE(topology_db->if_act_mask, ui);
+		printf("\n\tInterface ID: %d\n", ui);
+		printf("\t\tDDR Frequency: %s\n",
+		       convert_freq(topology_db->
+				    interface_params[ui].memory_freq));
+		printf("\t\tSpeed_bin: %d\n",
+		       topology_db->interface_params[ui].speed_bin_index);
+		printf("\t\tBus_width: %d\n",
+		       (4 << topology_db->interface_params[ui].bus_width));
+		printf("\t\tMem_size: %s\n",
+		       convert_mem_size(topology_db->
+					interface_params[ui].memory_size));
+		printf("\t\tCAS-WL: %d\n",
+		       topology_db->interface_params[ui].cas_wl);
+		printf("\t\tCAS-L: %d\n",
+		       topology_db->interface_params[ui].cas_l);
+		printf("\t\tTemperature: %d\n",
+		       topology_db->interface_params[ui].interface_temp);
+		printf("\n");
+		for (uj = 0; uj < 4; uj++) {
+			printf("\t\tBus %d parameters- CS Mask: 0x%x\t", uj,
+			       topology_db->interface_params[ui].
+			       as_bus_params[uj].cs_bitmask);
+			printf("Mirror: 0x%x\t",
+			       topology_db->interface_params[ui].
+			       as_bus_params[uj].mirror_enable_bitmask);
+			printf("DQS Swap is %s \t",
+			       (topology_db->
+				interface_params[ui].as_bus_params[uj].
+				is_dqs_swap == 1) ? "enabled" : "disabled");
+			printf("Ck Swap:%s\t",
+			       (topology_db->
+				interface_params[ui].as_bus_params[uj].
+				is_ck_swap == 1) ? "enabled" : "disabled");
+			printf("\n");
+		}
+	}
+}
+#endif
+
+/*
+ * Execute XSB Test transaction (rd/wr/both)
+ */
+int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type,
+		 u32 read_type, u32 burst_length)
+{
+	u32 seq = 0, if_id = 0, addr, cnt;
+	int ret = MV_OK, ret_tmp;
+	u32 data_read[MAX_INTERFACE_NUM];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		addr = mem_addr;
+		for (cnt = 0; cnt <= burst_length; cnt++) {
+			seq = (seq + 1) % 8;
+			if (write_type != 0) {
+				CHECK_STATUS(ddr3_tip_ext_write
+					     (dev_num, if_id, addr, 1,
+					      xsb_test_table[seq]));
+			}
+			if (read_type != 0) {
+				CHECK_STATUS(ddr3_tip_ext_read
+					     (dev_num, if_id, addr, 1,
+					      data_read));
+			}
+			if ((read_type != 0) && (write_type != 0)) {
+				ret_tmp =
+					ddr3_tip_compare(if_id,
+							 xsb_test_table[seq],
+							 data_read,
+							 0xff);
+				addr += (EXT_ACCESS_BURST_LENGTH * 4);
+				ret = (ret != MV_OK) ? ret : ret_tmp;
+			}
+		}
+	}
+
+	return ret;
+}
+
+#else /*EXCLUDE_SWITCH_DEBUG */
+
+u32 rl_version = 1;		/* 0 - old RL machine */
+u32 vref = 0x4;
+u32 start_xsb_offset = 0;
+u8 cs_mask_reg[] = {
+	0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type,
+		 u32 read_type, u32 burst_length)
+{
+	return MV_OK;
+}
+
+#endif
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c
new file mode 100644
index 0000000..560da7e
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define REG_READ_DATA_SAMPLE_DELAYS_ADDR	0x1538
+#define REG_READ_DATA_SAMPLE_DELAYS_MASK	0x1f
+#define REG_READ_DATA_SAMPLE_DELAYS_OFFS	8
+
+#define REG_READ_DATA_READY_DELAYS_ADDR		0x153c
+#define REG_READ_DATA_READY_DELAYS_MASK		0x1f
+#define REG_READ_DATA_READY_DELAYS_OFFS		8
+
+int ddr3_if_ecc_enabled(void)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask) ||
+	    DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))
+		return 1;
+	else
+		return 0;
+}
+
+int ddr3_pre_algo_config(void)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* Set Bus3 ECC training mode */
+	if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask)) {
+		/* Set Bus3 ECC MUX */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+			      REG_SDRAM_PINS_MUX, 0x100, 0x100));
+	}
+
+	/* Set regular ECC training mode (bus4 and bus 3) */
+	if ((DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask)) ||
+	    (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))) {
+		/* Enable ECC Write MUX */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x100, 0x100));
+		/* General ECC enable */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+			      REG_SDRAM_CONFIG_ADDR, 0x40000, 0x40000));
+		/* Disable Read Data ECC MUX */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x0, 0x2));
+	}
+
+	return MV_OK;
+}
+
+int ddr3_post_algo_config(void)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+	int status;
+
+	status = ddr3_post_run_alg();
+	if (MV_OK != status) {
+		printf("DDR3 Post Run Alg - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	/* Un_set ECC training mode */
+	if ((DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask)) ||
+	    (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))) {
+		/* Disable ECC Write MUX */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x0, 0x100));
+		/* General ECC and Bus3 ECC MUX remains enabled */
+	}
+
+	return MV_OK;
+}
+
+int ddr3_hws_hw_training(void)
+{
+	enum hws_algo_type algo_mode = ALGO_TYPE_DYNAMIC;
+	int status;
+	struct init_cntr_param init_param;
+
+	status = ddr3_silicon_pre_init();
+	if (MV_OK != status) {
+		printf("DDR3 Pre silicon Config - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	init_param.do_mrs_phy = 1;
+#if defined(CONFIG_ARMADA_38X)  || defined(CONFIG_ARMADA_39X)
+	init_param.is_ctrl64_bit = 0;
+#else
+	init_param.is_ctrl64_bit = 1;
+#endif
+#if defined(CONFIG_ALLEYCAT3) || defined(CONFIG_ARMADA_38X) || \
+	defined(CONFIG_ARMADA_39X)
+	init_param.init_phy = 1;
+#else
+	init_param.init_phy = 0;
+#endif
+	init_param.msys_init = 1;
+	status = hws_ddr3_tip_init_controller(0, &init_param);
+	if (MV_OK != status) {
+		printf("DDR3 init controller - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	status = ddr3_silicon_post_init();
+	if (MV_OK != status) {
+		printf("DDR3 Post Init - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	status = ddr3_pre_algo_config();
+	if (MV_OK != status) {
+		printf("DDR3 Pre Algo Config - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	/* run algorithm in order to configure the PHY */
+	status = hws_ddr3_tip_run_alg(0, algo_mode);
+	if (MV_OK != status) {
+		printf("DDR3 run algorithm - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	status = ddr3_post_algo_config();
+	if (MV_OK != status) {
+		printf("DDR3 Post Algo Config - FAILED 0x%x\n", status);
+		return status;
+	}
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h
new file mode 100644
index 0000000..17a0953
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_HWS_HW_TRAINING_H
+#define _DDR3_HWS_HW_TRAINING_H
+
+/* struct used for DLB configuration array */
+struct dlb_config {
+	u32 reg_addr;
+	u32 reg_data;
+};
+
+/* Topology update structure */
+struct topology_update_info {
+	int	update_ecc;
+	u8	ecc;
+	int	update_width;
+	u8	width;
+	int	update_ecc_pup3_mode;
+	u8	ecc_pup_mode_offset;
+};
+
+/* Topology update defines */
+#define TOPOLOGY_UPDATE_WIDTH_16BIT		1
+#define TOPOLOGY_UPDATE_WIDTH_32BIT		0
+#define TOPOLOGY_UPDATE_WIDTH_32BIT_MASK	0xf
+#define TOPOLOGY_UPDATE_WIDTH_16BIT_MASK	0x3
+
+#define TOPOLOGY_UPDATE_ECC_ON			1
+#define TOPOLOGY_UPDATE_ECC_OFF			0
+#define TOPOLOGY_UPDATE_ECC_OFFSET_PUP4		4
+#define TOPOLOGY_UPDATE_ECC_OFFSET_PUP3		3
+
+/*
+ * 1. L2 filter should be set at binary header to 0xd000000,
+ *    to avoid conflict with internal register IO.
+ * 2. U-Boot modifies internal registers base to 0xf100000,
+ *    and than should update L2 filter accordingly to 0xf000000 (3.75 GB)
+ */
+/* temporary limit l2 filter to 3GiB (LSP issue) */
+#define L2_FILTER_FOR_MAX_MEMORY_SIZE 0xc0000000
+#define ADDRESS_FILTERING_END_REGISTER 0x8c04
+
+#define SUB_VERSION	0
+
+#endif /* _DDR3_HWS_HW_TRAINING_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h
new file mode 100644
index 0000000..7500a72
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_HWS_HW_TRAINING_DEF_H
+#define _DDR3_HWS_HW_TRAINING_DEF_H
+
+#define SAR_DDR3_FREQ_MASK		0xfe00000
+#define SAR_CPU_FAB_GET(cpu, fab)	(((cpu & 0x7) << 21) | \
+					 ((fab & 0xf) << 24))
+
+#define MAX_CS				4
+
+#define MIN_DIMM_ADDR			0x50
+#define FAR_END_DIMM_ADDR		0x50
+#define MAX_DIMM_ADDR			0x60
+
+#define SDRAM_CS_SIZE			0xfffffff
+#define SDRAM_CS_BASE			0x0
+#define SDRAM_DIMM_SIZE			0x80000000
+
+#define CPU_CONFIGURATION_REG(id)	(0x21800 + (id * 0x100))
+#define CPU_MRVL_ID_OFFSET		0x10
+#define SAR1_CPU_CORE_MASK		0x00000018
+#define SAR1_CPU_CORE_OFFSET		3
+
+#define NEW_FABRIC_TWSI_ADDR		0x4e
+#ifdef DB_784MP_GP
+#define BUS_WIDTH_ECC_TWSI_ADDR		0x4e
+#else
+#define BUS_WIDTH_ECC_TWSI_ADDR		0x4f
+#endif
+#define MV_MAX_DDR3_STATIC_SIZE		50
+#define MV_DDR3_MODES_NUMBER		30
+
+#define RESUME_RL_PATTERNS_ADDR		0xfe0000
+#define RESUME_RL_PATTERNS_SIZE		0x100
+#define RESUME_TRAINING_VALUES_ADDR	(RESUME_RL_PATTERNS_ADDR + \
+					 RESUME_RL_PATTERNS_SIZE)
+#define RESUME_TRAINING_VALUES_MAX	0xcd0
+#define BOOT_INFO_ADDR			(RESUME_RL_PATTERNS_ADDR + 0x1000)
+#define CHECKSUM_RESULT_ADDR		(BOOT_INFO_ADDR + 0x1000)
+#define NUM_OF_REGISTER_ADDR		(CHECKSUM_RESULT_ADDR + 4)
+#define SUSPEND_MAGIC_WORD		0xdeadb002
+#define REGISTER_LIST_END		0xffffffff
+
+/* MISC */
+#define INTER_REGS_BASE			SOC_REGS_PHY_BASE
+
+/* DDR */
+#define REG_SDRAM_CONFIG_ADDR			0x1400
+#define REG_SDRAM_CONFIG_MASK			0x9fffffff
+#define REG_SDRAM_CONFIG_RFRS_MASK		0x3fff
+#define REG_SDRAM_CONFIG_WIDTH_OFFS		15
+#define REG_SDRAM_CONFIG_REGDIMM_OFFS		17
+#define REG_SDRAM_CONFIG_ECC_OFFS		18
+#define REG_SDRAM_CONFIG_IERR_OFFS		19
+#define REG_SDRAM_CONFIG_PUPRSTDIV_OFFS		28
+#define REG_SDRAM_CONFIG_RSTRD_OFFS		30
+
+#define REG_SDRAM_PINS_MUX			0x19d4
+
+#define REG_DUNIT_CTRL_LOW_ADDR			0x1404
+#define REG_DUNIT_CTRL_LOW_2T_OFFS		3
+#define REG_DUNIT_CTRL_LOW_2T_MASK		0x3
+#define REG_DUNIT_CTRL_LOW_DPDE_OFFS		14
+
+#define REG_SDRAM_TIMING_LOW_ADDR		0x1408
+#define REG_SDRAM_TIMING_HIGH_ADDR		0x140c
+#define REG_SDRAM_TIMING_H_R2R_OFFS		7
+#define REG_SDRAM_TIMING_H_R2R_MASK		0x3
+#define REG_SDRAM_TIMING_H_R2W_W2R_OFFS		9
+#define REG_SDRAM_TIMING_H_R2W_W2R_MASK		0x3
+#define REG_SDRAM_TIMING_H_W2W_OFFS		11
+#define REG_SDRAM_TIMING_H_W2W_MASK		0x1f
+#define REG_SDRAM_TIMING_H_R2R_H_OFFS		19
+#define REG_SDRAM_TIMING_H_R2R_H_MASK		0x7
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS	22
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_MASK	0x7
+
+#define REG_SDRAM_ADDRESS_CTRL_ADDR		0x1410
+#define REG_SDRAM_ADDRESS_SIZE_OFFS		2
+#define REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS	18
+#define REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS	4
+
+#define REG_SDRAM_OPEN_PAGES_ADDR		0x1414
+#define REG_SDRAM_OPERATION_CS_OFFS		8
+
+#define REG_SDRAM_OPERATION_ADDR		0x1418
+#define REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS	24
+#define REG_SDRAM_OPERATION_CWA_DATA_OFFS	20
+#define REG_SDRAM_OPERATION_CWA_DATA_MASK	0xf
+#define REG_SDRAM_OPERATION_CWA_RC_OFFS		16
+#define REG_SDRAM_OPERATION_CWA_RC_MASK		0xf
+#define REG_SDRAM_OPERATION_CMD_MR0		0xf03
+#define REG_SDRAM_OPERATION_CMD_MR1		0xf04
+#define REG_SDRAM_OPERATION_CMD_MR2		0xf08
+#define REG_SDRAM_OPERATION_CMD_MR3		0xf09
+#define REG_SDRAM_OPERATION_CMD_RFRS		0xf02
+#define REG_SDRAM_OPERATION_CMD_CWA		0xf0e
+#define REG_SDRAM_OPERATION_CMD_RFRS_DONE	0xf
+#define REG_SDRAM_OPERATION_CMD_MASK		0xf
+#define REG_SDRAM_OPERATION_CS_OFFS		8
+
+#define REG_OUDDR3_TIMING_ADDR			0x142c
+
+#define REG_SDRAM_MODE_ADDR			0x141c
+
+#define REG_SDRAM_EXT_MODE_ADDR			0x1420
+
+#define REG_DDR_CONT_HIGH_ADDR			0x1424
+
+#define REG_ODT_TIME_LOW_ADDR			0x1428
+#define REG_ODT_ON_CTL_RD_OFFS                  12
+#define REG_ODT_OFF_CTL_RD_OFFS                 16
+#define REG_SDRAM_ERROR_ADDR                    0x1454
+#define REG_SDRAM_AUTO_PWR_SAVE_ADDR            0x1474
+#define REG_ODT_TIME_HIGH_ADDR			0x147c
+
+#define REG_SDRAM_INIT_CTRL_ADDR		0x1480
+#define REG_SDRAM_INIT_CTRL_OFFS		0
+#define REG_SDRAM_INIT_CKE_ASSERT_OFFS		2
+#define REG_SDRAM_INIT_RESET_DEASSERT_OFFS	3
+#define REG_SDRAM_INIT_RESET_MASK_OFFS		1
+
+#define REG_SDRAM_ODT_CTRL_LOW_ADDR		0x1494
+
+#define REG_SDRAM_ODT_CTRL_HIGH_ADDR		0x1498
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK	0x0
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA	0x3
+
+#define REG_DUNIT_ODT_CTRL_ADDR			0x149c
+#define REG_DUNIT_ODT_CTRL_OVRD_OFFS            8
+#define REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS        9
+
+#define REG_DRAM_FIFO_CTRL_ADDR			0x14a0
+
+#define REG_DRAM_AXI_CTRL_ADDR			0x14a8
+#define REG_DRAM_AXI_CTRL_AXIDATABUSWIDTH_OFFS	0
+
+#define REG_METAL_MASK_ADDR			0x14b0
+#define REG_METAL_MASK_MASK			0xdfffffff
+#define REG_METAL_MASK_RETRY_OFFS		0
+
+#define REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR	0x14c0
+
+#define REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR	0x14c4
+#define REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR      0x14c8
+#define REG_DRAM_MAIN_PADS_CAL_ADDR		0x14cc
+
+#define REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR      0x17c8
+
+#define REG_CS_SIZE_SCRATCH_ADDR		0x1504
+#define REG_DYNAMIC_POWER_SAVE_ADDR             0x1520
+#define REG_DDR_IO_ADDR				0x1524
+#define REG_DDR_IO_CLK_RATIO_OFFS		15
+
+#define REG_DFS_ADDR				0x1528
+#define REG_DFS_DLLNEXTSTATE_OFFS		0
+#define REG_DFS_BLOCK_OFFS			1
+#define REG_DFS_SR_OFFS				2
+#define REG_DFS_ATSR_OFFS			3
+#define REG_DFS_RECONF_OFFS			4
+#define REG_DFS_CL_NEXT_STATE_OFFS		8
+#define REG_DFS_CL_NEXT_STATE_MASK		0xf
+#define REG_DFS_CWL_NEXT_STATE_OFFS		12
+#define REG_DFS_CWL_NEXT_STATE_MASK		0x7
+
+#define REG_READ_DATA_SAMPLE_DELAYS_ADDR	0x1538
+#define REG_READ_DATA_SAMPLE_DELAYS_MASK	0x1f
+#define REG_READ_DATA_SAMPLE_DELAYS_OFFS	8
+
+#define REG_READ_DATA_READY_DELAYS_ADDR		0x153c
+#define REG_READ_DATA_READY_DELAYS_MASK		0x1f
+#define REG_READ_DATA_READY_DELAYS_OFFS		8
+
+#define START_BURST_IN_ADDR			1
+
+#define REG_DRAM_TRAINING_SHADOW_ADDR		0x18488
+#define REG_DRAM_TRAINING_ADDR			0x15b0
+#define REG_DRAM_TRAINING_LOW_FREQ_OFFS		0
+#define REG_DRAM_TRAINING_PATTERNS_OFFS		4
+#define REG_DRAM_TRAINING_MED_FREQ_OFFS		2
+#define REG_DRAM_TRAINING_WL_OFFS		3
+#define REG_DRAM_TRAINING_RL_OFFS		6
+#define REG_DRAM_TRAINING_DQS_RX_OFFS		15
+#define REG_DRAM_TRAINING_DQS_TX_OFFS		16
+#define REG_DRAM_TRAINING_CS_OFFS		20
+#define REG_DRAM_TRAINING_RETEST_OFFS		24
+#define REG_DRAM_TRAINING_DFS_FREQ_OFFS		27
+#define REG_DRAM_TRAINING_DFS_REQ_OFFS		29
+#define REG_DRAM_TRAINING_ERROR_OFFS		30
+#define REG_DRAM_TRAINING_AUTO_OFFS		31
+#define REG_DRAM_TRAINING_RETEST_PAR		0x3
+#define REG_DRAM_TRAINING_RETEST_MASK		0xf8ffffff
+#define REG_DRAM_TRAINING_CS_MASK		0xff0fffff
+#define REG_DRAM_TRAINING_PATTERNS_MASK		0xff0f0000
+
+#define REG_DRAM_TRAINING_1_ADDR		0x15b4
+#define REG_DRAM_TRAINING_1_TRNBPOINT_OFFS	16
+
+#define REG_DRAM_TRAINING_2_ADDR		0x15b8
+#define REG_DRAM_TRAINING_2_OVERRUN_OFFS	17
+#define REG_DRAM_TRAINING_2_FIFO_RST_OFFS	4
+#define REG_DRAM_TRAINING_2_RL_MODE_OFFS	3
+#define REG_DRAM_TRAINING_2_WL_MODE_OFFS	2
+#define REG_DRAM_TRAINING_2_ECC_MUX_OFFS	1
+#define REG_DRAM_TRAINING_2_SW_OVRD_OFFS	0
+
+#define REG_DRAM_TRAINING_PATTERN_BASE_ADDR	0x15bc
+#define REG_DRAM_TRAINING_PATTERN_BASE_OFFS	3
+
+#define REG_TRAINING_DEBUG_2_ADDR		0x15c4
+#define REG_TRAINING_DEBUG_2_OFFS		16
+#define REG_TRAINING_DEBUG_2_MASK		0x3
+
+#define REG_TRAINING_DEBUG_3_ADDR		0x15c8
+#define REG_TRAINING_DEBUG_3_OFFS		3
+#define REG_TRAINING_DEBUG_3_MASK		0x7
+
+#define	MR_CS_ADDR_OFFS				4
+
+#define	REG_DDR3_MR0_ADDR			0x15d0
+#define	REG_DDR3_MR0_CS_ADDR			0x1870
+#define REG_DDR3_MR0_CL_MASK			0x74
+#define	REG_DDR3_MR0_CL_OFFS			2
+#define	REG_DDR3_MR0_CL_HIGH_OFFS		3
+#define	CL_MASK					0xf
+
+#define	REG_DDR3_MR1_ADDR			0x15d4
+#define	REG_DDR3_MR1_CS_ADDR			0x1874
+#define REG_DDR3_MR1_RTT_MASK			0xfffffdbb
+#define REG_DDR3_MR1_DLL_ENA_OFFS		0
+#define REG_DDR3_MR1_RTT_DISABLED		0x0
+#define REG_DDR3_MR1_RTT_RZQ2			0x40
+#define REG_DDR3_MR1_RTT_RZQ4			0x2
+#define REG_DDR3_MR1_RTT_RZQ6			0x42
+#define REG_DDR3_MR1_RTT_RZQ8			0x202
+#define REG_DDR3_MR1_RTT_RZQ12			0x4
+/* WL-disabled, OB-enabled */
+#define REG_DDR3_MR1_OUTBUF_WL_MASK		0xffffef7f
+/* Output Buffer Disabled */
+#define REG_DDR3_MR1_OUTBUF_DIS_OFFS		12
+#define REG_DDR3_MR1_WL_ENA_OFFS		7
+#define REG_DDR3_MR1_WL_ENA			0x80	/* WL Enabled */
+#define REG_DDR3_MR1_ODT_MASK			0xfffffdbb
+
+#define	REG_DDR3_MR2_ADDR			0x15d8
+#define	REG_DDR3_MR2_CS_ADDR			0x1878
+#define	REG_DDR3_MR2_CWL_OFFS			3
+#define	REG_DDR3_MR2_CWL_MASK			0x7
+#define REG_DDR3_MR2_ODT_MASK			0xfffff9ff
+#define	REG_DDR3_MR3_ADDR			0x15dc
+#define	REG_DDR3_MR3_CS_ADDR			0x187c
+
+#define REG_DDR3_RANK_CTRL_ADDR			0x15e0
+#define REG_DDR3_RANK_CTRL_CS_ENA_MASK		0xf
+#define REG_DDR3_RANK_CTRL_MIRROR_OFFS		4
+
+#define REG_ZQC_CONF_ADDR			0x15e4
+
+#define REG_DRAM_PHY_CONFIG_ADDR		0x15ec
+#define REG_DRAM_PHY_CONFIG_MASK		0x3fffffff
+
+#define REG_ODPG_CNTRL_ADDR			0x1600
+#define REG_ODPG_CNTRL_OFFS			21
+
+#define REG_PHY_LOCK_MASK_ADDR			0x1670
+#define REG_PHY_LOCK_MASK_MASK			0xfffff000
+
+#define REG_PHY_LOCK_STATUS_ADDR		0x1674
+#define REG_PHY_LOCK_STATUS_LOCK_OFFS		9
+#define REG_PHY_LOCK_STATUS_LOCK_MASK		0xfff
+#define REG_PHY_LOCK_APLL_ADLL_STATUS_MASK	0x7ff
+
+#define REG_PHY_REGISTRY_FILE_ACCESS_ADDR	0x16a0
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_WR	0xc0000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_RD	0x80000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE	0x80000000
+#define REG_PHY_BC_OFFS				27
+#define REG_PHY_CNTRL_OFFS			26
+#define REG_PHY_CS_OFFS				16
+#define REG_PHY_DQS_REF_DLY_OFFS		10
+#define REG_PHY_PHASE_OFFS			8
+#define REG_PHY_PUP_OFFS			22
+
+#define REG_TRAINING_WL_ADDR			0x16ac
+#define REG_TRAINING_WL_CS_MASK			0xfffffffc
+#define REG_TRAINING_WL_UPD_OFFS		2
+#define REG_TRAINING_WL_CS_DONE_OFFS		3
+#define REG_TRAINING_WL_RATIO_MASK		0xffffff0f
+#define REG_TRAINING_WL_1TO1			0x50
+#define REG_TRAINING_WL_2TO1			0x10
+#define REG_TRAINING_WL_DELAYEXP_MASK		0x20000000
+#define REG_TRAINING_WL_RESULTS_MASK		0x000001ff
+#define REG_TRAINING_WL_RESULTS_OFFS		20
+
+#define REG_REGISTERED_DRAM_CTRL_ADDR		0x16d0
+#define REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS	15
+#define REG_REGISTERED_DRAM_CTRL_PARITY_MASK	0x3f
+
+/* DLB */
+#define REG_STATIC_DRAM_DLB_CONTROL		0x1700
+#define DLB_BUS_OPTIMIZATION_WEIGHTS_REG	0x1704
+#define DLB_AGING_REGISTER			0x1708
+#define DLB_EVICTION_CONTROL_REG		0x170c
+#define DLB_EVICTION_TIMERS_REGISTER_REG	0x1710
+#define DLB_USER_COMMAND_REG			0x1714
+#define DLB_BUS_WEIGHTS_DIFF_CS			0x1770
+#define DLB_BUS_WEIGHTS_DIFF_BG			0x1774
+#define DLB_BUS_WEIGHTS_SAME_BG			0x1778
+#define DLB_BUS_WEIGHTS_RD_WR			0x177c
+#define DLB_BUS_WEIGHTS_ATTR_SYS_PRIO		0x1780
+#define DLB_MAIN_QUEUE_MAP			0x1784
+#define DLB_LINE_SPLIT				0x1788
+
+#define DLB_ENABLE				0x1
+#define DLB_WRITE_COALESING			(0x1 << 2)
+#define DLB_AXI_PREFETCH_EN			(0x1 << 3)
+#define DLB_MBUS_PREFETCH_EN			(0x1 << 4)
+#define PREFETCH_N_LN_SZ_TR			(0x1 << 6)
+#define DLB_INTERJECTION_ENABLE			(0x1 << 3)
+
+/* CPU */
+#define REG_BOOTROM_ROUTINE_ADDR		0x182d0
+#define REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS	12
+
+#define REG_DRAM_INIT_CTRL_STATUS_ADDR		0x18488
+#define REG_DRAM_INIT_CTRL_TRN_CLK_OFFS		16
+#define REG_CPU_DIV_CLK_CTRL_0_NEW_RATIO	0x000200ff
+#define REG_DRAM_INIT_CTRL_STATUS_2_ADDR	0x1488
+
+#define REG_CPU_DIV_CLK_CTRL_0_ADDR		0x18700
+
+#define REG_CPU_DIV_CLK_CTRL_1_ADDR		0x18704
+#define REG_CPU_DIV_CLK_CTRL_2_ADDR		0x18708
+
+#define REG_CPU_DIV_CLK_CTRL_3_ADDR		0x1870c
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK	0xffffc0ff
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS	8
+
+#define REG_CPU_DIV_CLK_CTRL_4_ADDR		0x18710
+
+#define REG_CPU_DIV_CLK_STATUS_0_ADDR		0x18718
+#define REG_CPU_DIV_CLK_ALL_STABLE_OFFS		8
+
+#define REG_CPU_PLL_CTRL_0_ADDR			0x1871c
+#define REG_CPU_PLL_STATUS_0_ADDR		0x18724
+#define REG_CORE_DIV_CLK_CTRL_ADDR		0x18740
+#define REG_CORE_DIV_CLK_STATUS_ADDR		0x18744
+#define REG_DDRPHY_APLL_CTRL_ADDR		0x18780
+
+#define REG_DDRPHY_APLL_CTRL_2_ADDR		0x18784
+#define REG_SFABRIC_CLK_CTRL_ADDR		0x20858
+#define REG_SFABRIC_CLK_CTRL_SMPL_OFFS		8
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_19_CTRL_ADDR		0x200e8
+#define REG_XBAR_WIN_4_CTRL_ADDR		0x20040
+#define REG_XBAR_WIN_4_BASE_ADDR		0x20044
+#define REG_XBAR_WIN_4_REMAP_ADDR		0x20048
+#define REG_FASTPATH_WIN_0_CTRL_ADDR		0x20184
+#define REG_XBAR_WIN_7_REMAP_ADDR               0x20078
+
+/* SRAM */
+#define REG_CDI_CONFIG_ADDR			0x20220
+#define REG_SRAM_WINDOW_0_ADDR			0x20240
+#define REG_SRAM_WINDOW_0_ENA_OFFS		0
+#define REG_SRAM_WINDOW_1_ADDR			0x20244
+#define REG_SRAM_L2_ENA_ADDR			0x8500
+#define REG_SRAM_CLEAN_BY_WAY_ADDR		0x87bc
+
+/* Timers */
+#define REG_TIMERS_CTRL_ADDR			0x20300
+#define REG_TIMERS_EVENTS_ADDR			0x20304
+#define REG_TIMER0_VALUE_ADDR			0x20314
+#define REG_TIMER1_VALUE_ADDR			0x2031c
+#define REG_TIMER0_ENABLE_MASK			0x1
+
+#define MV_BOARD_REFCLK_25MHZ			25000000
+#define CNTMR_RELOAD_REG(tmr)	(REG_TIMERS_CTRL_ADDR  + 0x10 + (tmr * 8))
+#define CNTMR_VAL_REG(tmr)	(REG_TIMERS_CTRL_ADDR  + 0x14 + (tmr * 8))
+#define CNTMR_CTRL_REG(tmr)	(REG_TIMERS_CTRL_ADDR)
+#define CTCR_ARM_TIMER_EN_OFFS(timer)	(timer * 2)
+#define CTCR_ARM_TIMER_EN_MASK(timer)	(1 << CTCR_ARM_TIMER_EN_OFFS(timer))
+#define CTCR_ARM_TIMER_EN(timer)	(1 << CTCR_ARM_TIMER_EN_OFFS(timer))
+
+#define CTCR_ARM_TIMER_AUTO_OFFS(timer)	(1 + (timer * 2))
+#define CTCR_ARM_TIMER_AUTO_MASK(timer)	(1 << CTCR_ARM_TIMER_EN_OFFS(timer))
+#define CTCR_ARM_TIMER_AUTO_EN(timer)	(1 << CTCR_ARM_TIMER_AUTO_OFFS(timer))
+
+/* PMU */
+#define REG_PMU_I_F_CTRL_ADDR			0x1c090
+#define REG_PMU_DUNIT_BLK_OFFS			16
+#define REG_PMU_DUNIT_RFRS_OFFS			20
+#define REG_PMU_DUNIT_ACK_OFFS			24
+
+/* MBUS */
+#define MBUS_UNITS_PRIORITY_CONTROL_REG		(MBUS_REGS_OFFSET + 0x420)
+#define FABRIC_UNITS_PRIORITY_CONTROL_REG	(MBUS_REGS_OFFSET + 0x424)
+#define MBUS_UNITS_PREFETCH_CONTROL_REG		(MBUS_REGS_OFFSET + 0x428)
+#define FABRIC_UNITS_PREFETCH_CONTROL_REG	(MBUS_REGS_OFFSET + 0x42c)
+
+#define REG_PM_STAT_MASK_ADDR			0x2210c
+#define REG_PM_STAT_MASK_CPU0_IDLE_MASK_OFFS	16
+
+#define REG_PM_EVENT_STAT_MASK_ADDR		0x22120
+#define REG_PM_EVENT_STAT_MASK_DFS_DONE_OFFS	17
+
+#define REG_PM_CTRL_CONFIG_ADDR			0x22104
+#define REG_PM_CTRL_CONFIG_DFS_REQ_OFFS		18
+
+#define REG_FABRIC_LOCAL_IRQ_MASK_ADDR		0x218c4
+#define REG_FABRIC_LOCAL_IRQ_PMU_MASK_OFFS	18
+
+/* Controller revision info */
+#define PCI_CLASS_CODE_AND_REVISION_ID		0x008
+#define PCCRIR_REVID_OFFS			0	/* Revision ID */
+#define PCCRIR_REVID_MASK			(0xff << PCCRIR_REVID_OFFS)
+
+/* Power Management Clock Gating Control Register */
+#define POWER_MNG_CTRL_REG			0x18220
+#define PEX_DEVICE_AND_VENDOR_ID		0x000
+#define PEX_CFG_DIRECT_ACCESS(if, reg)	(PEX_IF_REGS_BASE(if) + (reg))
+#define PMC_PEXSTOPCLOCK_OFFS(p)	((p) < 8 ? (5 + (p)) : (18 + (p)))
+#define PMC_PEXSTOPCLOCK_MASK(p)	(1 << PMC_PEXSTOPCLOCK_OFFS(p))
+#define PMC_PEXSTOPCLOCK_EN(p)		(1 << PMC_PEXSTOPCLOCK_OFFS(p))
+#define PMC_PEXSTOPCLOCK_STOP(p)	(0 << PMC_PEXSTOPCLOCK_OFFS(p))
+
+/* TWSI */
+#define TWSI_DATA_ADDR_MASK		0x7
+#define TWSI_DATA_ADDR_OFFS		1
+
+/* General */
+#define MAX_CS				4
+
+/* Frequencies */
+#define FAB_OPT				21
+#define CLK_CPU				12
+#define CLK_VCO				(2 * CLK_CPU)
+#define CLK_DDR				12
+
+/* CPU Frequencies: */
+#define CLK_CPU_1000			0
+#define CLK_CPU_1066			1
+#define CLK_CPU_1200			2
+#define CLK_CPU_1333			3
+#define CLK_CPU_1500			4
+#define CLK_CPU_1666			5
+#define CLK_CPU_1800			6
+#define CLK_CPU_2000			7
+#define CLK_CPU_600			8
+#define CLK_CPU_667			9
+#define CLK_CPU_800			0xa
+
+/* Extra Cpu Frequencies: */
+#define CLK_CPU_1600			11
+#define CLK_CPU_2133			12
+#define CLK_CPU_2200			13
+#define CLK_CPU_2400			14
+
+#define SAR1_CPU_CORE_MASK		0x00000018
+#define SAR1_CPU_CORE_OFFSET		3
+
+#endif /* _DDR3_HWS_HW_TRAINING_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h b/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h
new file mode 100644
index 0000000..544237a
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_HWS_SIL_TRAINING_H
+#define _DDR3_HWS_SIL_TRAINING_H
+
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_prv_if.h"
+
+int ddr3_silicon_pre_config(void);
+int ddr3_silicon_init(void);
+int ddr3_silicon_get_ddr_target_freq(u32 *ddr_freq);
+
+#endif /* _DDR3_HWS_SIL_TRAINING_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_init.c b/drivers/ddr/marvell/a38x/ddr3_init.c
new file mode 100644
index 0000000..d6ed8e0
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_init.c
@@ -0,0 +1,852 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#include "../../../../arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h"
+
+static struct dlb_config ddr3_dlb_config_table[] = {
+	{REG_STATIC_DRAM_DLB_CONTROL, 0x2000005c},
+	{DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x00880000},
+	{DLB_AGING_REGISTER, 0x0f7f007f},
+	{DLB_EVICTION_CONTROL_REG, 0x0000129f},
+	{DLB_EVICTION_TIMERS_REGISTER_REG, 0x00ff0000},
+	{DLB_BUS_WEIGHTS_DIFF_CS, 0x04030802},
+	{DLB_BUS_WEIGHTS_DIFF_BG, 0x00000a02},
+	{DLB_BUS_WEIGHTS_SAME_BG, 0x09000a01},
+	{DLB_BUS_WEIGHTS_RD_WR, 0x00020005},
+	{DLB_BUS_WEIGHTS_ATTR_SYS_PRIO, 0x00060f10},
+	{DLB_MAIN_QUEUE_MAP, 0x00000543},
+	{DLB_LINE_SPLIT, 0x00000000},
+	{DLB_USER_COMMAND_REG, 0x00000000},
+	{0x0, 0x0}
+};
+
+static struct dlb_config ddr3_dlb_config_table_a0[] = {
+	{REG_STATIC_DRAM_DLB_CONTROL, 0x2000005c},
+	{DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x00880000},
+	{DLB_AGING_REGISTER, 0x0f7f007f},
+	{DLB_EVICTION_CONTROL_REG, 0x0000129f},
+	{DLB_EVICTION_TIMERS_REGISTER_REG, 0x00ff0000},
+	{DLB_BUS_WEIGHTS_DIFF_CS, 0x04030802},
+	{DLB_BUS_WEIGHTS_DIFF_BG, 0x00000a02},
+	{DLB_BUS_WEIGHTS_SAME_BG, 0x09000a01},
+	{DLB_BUS_WEIGHTS_RD_WR, 0x00020005},
+	{DLB_BUS_WEIGHTS_ATTR_SYS_PRIO, 0x00060f10},
+	{DLB_MAIN_QUEUE_MAP, 0x00000543},
+	{DLB_LINE_SPLIT, 0x00000000},
+	{DLB_USER_COMMAND_REG, 0x00000000},
+	{0x0, 0x0}
+};
+
+#if defined(CONFIG_ARMADA_38X)
+struct dram_modes {
+	char *mode_name;
+	u8 cpu_freq;
+	u8 fab_freq;
+	u8 chip_id;
+	u8 chip_board_rev;
+	struct reg_data *regs;
+};
+
+struct dram_modes ddr_modes[] = {
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+	/* Conf name, CPUFreq, Fab_freq, Chip ID, Chip/Board, MC regs*/
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+	{"a38x_customer_0_800", DDR_FREQ_800, 0, 0x0, A38X_CUSTOMER_BOARD_ID0,
+	 ddr3_customer_800},
+	{"a38x_customer_1_800", DDR_FREQ_800, 0, 0x0, A38X_CUSTOMER_BOARD_ID1,
+	 ddr3_customer_800},
+#else
+	{"a38x_533", DDR_FREQ_533, 0, 0x0, MARVELL_BOARD, ddr3_a38x_533},
+	{"a38x_667", DDR_FREQ_667, 0, 0x0, MARVELL_BOARD, ddr3_a38x_667},
+	{"a38x_800", DDR_FREQ_800, 0, 0x0, MARVELL_BOARD, ddr3_a38x_800},
+	{"a38x_933", DDR_FREQ_933, 0, 0x0, MARVELL_BOARD, ddr3_a38x_933},
+#endif
+#endif
+};
+#endif /* defined(CONFIG_ARMADA_38X) */
+
+/* Translates topology map definitions to real memory size in bits */
+u32 mem_size[] = {
+	ADDR_SIZE_512MB, ADDR_SIZE_1GB, ADDR_SIZE_2GB, ADDR_SIZE_4GB,
+	ADDR_SIZE_8GB
+};
+
+static char *ddr_type = "DDR3";
+
+/*
+ * Set 1 to use dynamic DUNIT configuration,
+ * set 0 (supported for A380 and AC3) to configure DUNIT in values set by
+ * ddr3_tip_init_specific_reg_config
+ */
+u8 generic_init_controller = 1;
+
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+static u32 ddr3_get_static_ddr_mode(void);
+#endif
+static int ddr3_hws_tune_training_params(u8 dev_num);
+static int ddr3_update_topology_map(struct hws_topology_map *topology_map);
+
+/* device revision */
+#define DEV_VERSION_ID_REG		0x1823c
+#define REVISON_ID_OFFS			8
+#define REVISON_ID_MASK			0xf00
+
+/* A38x revisions */
+#define MV_88F68XX_Z1_ID		0x0
+#define MV_88F68XX_A0_ID		0x4
+/* A39x revisions */
+#define MV_88F69XX_Z1_ID		0x2
+
+/*
+ * sys_env_device_rev_get - Get Marvell controller device revision number
+ *
+ * DESCRIPTION:
+ *       This function returns 8bit describing the device revision as defined
+ *       Revision ID Register.
+ *
+ * INPUT:
+ *       None.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       8bit desscribing Marvell controller revision number
+ */
+u8 sys_env_device_rev_get(void)
+{
+	u32 value;
+
+	value = reg_read(DEV_VERSION_ID_REG);
+	return (value & (REVISON_ID_MASK)) >> REVISON_ID_OFFS;
+}
+
+/*
+ * sys_env_dlb_config_ptr_get
+ *
+ * DESCRIPTION: defines pointer to to DLB COnfiguration table
+ *
+ * INPUT: none
+ *
+ * OUTPUT: pointer to DLB COnfiguration table
+ *
+ * RETURN:
+ *       returns pointer to DLB COnfiguration table
+ */
+struct dlb_config *sys_env_dlb_config_ptr_get(void)
+{
+#ifdef CONFIG_ARMADA_39X
+	return &ddr3_dlb_config_table_a0[0];
+#else
+	if (sys_env_device_rev_get() == MV_88F68XX_A0_ID)
+		return &ddr3_dlb_config_table_a0[0];
+	else
+		return &ddr3_dlb_config_table[0];
+#endif
+}
+
+/*
+ * sys_env_get_cs_ena_from_reg
+ *
+ * DESCRIPTION: Get bit mask of enabled CS
+ *
+ * INPUT: None
+ *
+ * OUTPUT: None
+ *
+ * RETURN:
+ *       Bit mask of enabled CS, 1 if only CS0 enabled,
+ *       3 if both CS0 and CS1 enabled
+ */
+u32 sys_env_get_cs_ena_from_reg(void)
+{
+	return reg_read(REG_DDR3_RANK_CTRL_ADDR) &
+		REG_DDR3_RANK_CTRL_CS_ENA_MASK;
+}
+
+static void ddr3_restore_and_set_final_windows(u32 *win)
+{
+	u32 win_ctrl_reg, num_of_win_regs;
+	u32 cs_ena = sys_env_get_cs_ena_from_reg();
+	u32 ui;
+
+	win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+	num_of_win_regs = 16;
+
+	/* Return XBAR windows 4-7 or 16-19 init configuration */
+	for (ui = 0; ui < num_of_win_regs; ui++)
+		reg_write((win_ctrl_reg + 0x4 * ui), win[ui]);
+
+	printf("%s Training Sequence - Switching XBAR Window to FastPath Window\n",
+	       ddr_type);
+
+#if defined DYNAMIC_CS_SIZE_CONFIG
+	if (ddr3_fast_path_dynamic_cs_size_config(cs_ena) != MV_OK)
+		printf("ddr3_fast_path_dynamic_cs_size_config FAILED\n");
+#else
+	u32 reg, cs;
+	reg = 0x1fffffe1;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			reg |= (cs << 2);
+			break;
+		}
+	}
+	/* Open fast path Window to - 0.5G */
+	reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, reg);
+#endif
+}
+
+static int ddr3_save_and_set_training_windows(u32 *win)
+{
+	u32 cs_ena;
+	u32 reg, tmp_count, cs, ui;
+	u32 win_ctrl_reg, win_base_reg, win_remap_reg;
+	u32 num_of_win_regs, win_jump_index;
+	win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+	win_base_reg = REG_XBAR_WIN_4_BASE_ADDR;
+	win_remap_reg = REG_XBAR_WIN_4_REMAP_ADDR;
+	win_jump_index = 0x10;
+	num_of_win_regs = 16;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+#ifdef DISABLE_L2_FILTERING_DURING_DDR_TRAINING
+	/*
+	 * Disable L2 filtering during DDR training
+	 * (when Cross Bar window is open)
+	 */
+	reg_write(ADDRESS_FILTERING_END_REGISTER, 0);
+#endif
+
+	cs_ena = tm->interface_params[0].as_bus_params[0].cs_bitmask;
+
+	/* Close XBAR Window 19 - Not needed */
+	/* {0x000200e8}  -   Open Mbus Window - 2G */
+	reg_write(REG_XBAR_WIN_19_CTRL_ADDR, 0);
+
+	/* Save XBAR Windows 4-19 init configurations */
+	for (ui = 0; ui < num_of_win_regs; ui++)
+		win[ui] = reg_read(win_ctrl_reg + 0x4 * ui);
+
+	/* Open XBAR Windows 4-7 or 16-19 for other CS */
+	reg = 0;
+	tmp_count = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			switch (cs) {
+			case 0:
+				reg = 0x0e00;
+				break;
+			case 1:
+				reg = 0x0d00;
+				break;
+			case 2:
+				reg = 0x0b00;
+				break;
+			case 3:
+				reg = 0x0700;
+				break;
+			}
+			reg |= (1 << 0);
+			reg |= (SDRAM_CS_SIZE & 0xffff0000);
+
+			reg_write(win_ctrl_reg + win_jump_index * tmp_count,
+				  reg);
+			reg = (((SDRAM_CS_SIZE + 1) * (tmp_count)) &
+			       0xffff0000);
+			reg_write(win_base_reg + win_jump_index * tmp_count,
+				  reg);
+
+			if (win_remap_reg <= REG_XBAR_WIN_7_REMAP_ADDR)
+				reg_write(win_remap_reg +
+					  win_jump_index * tmp_count, 0);
+
+			tmp_count++;
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_init - Main DDR3 Init function
+ * Desc:     This routine initialize the DDR3 MC and runs HW training.
+ * Args:     None.
+ * Notes:
+ * Returns:  None.
+ */
+int ddr3_init(void)
+{
+	u32 reg = 0;
+	u32 soc_num;
+	int status;
+	u32 win[16];
+
+	/* SoC/Board special Initializtions */
+	/* Get version from internal library */
+	ddr3_print_version();
+
+	/*Add sub_version string */
+	DEBUG_INIT_C("", SUB_VERSION, 1);
+
+	/* Switching CPU to MRVL ID */
+	soc_num = (reg_read(REG_SAMPLE_RESET_HIGH_ADDR) & SAR1_CPU_CORE_MASK) >>
+		SAR1_CPU_CORE_OFFSET;
+	switch (soc_num) {
+	case 0x3:
+		reg_bit_set(CPU_CONFIGURATION_REG(3), CPU_MRVL_ID_OFFSET);
+		reg_bit_set(CPU_CONFIGURATION_REG(2), CPU_MRVL_ID_OFFSET);
+	case 0x1:
+		reg_bit_set(CPU_CONFIGURATION_REG(1), CPU_MRVL_ID_OFFSET);
+	case 0x0:
+		reg_bit_set(CPU_CONFIGURATION_REG(0), CPU_MRVL_ID_OFFSET);
+	default:
+		break;
+	}
+
+	/*
+	 * Set DRAM Reset Mask in case detected GPIO indication of wakeup from
+	 * suspend i.e the DRAM values will not be overwritten / reset when
+	 * waking from suspend
+	 */
+	if (sys_env_suspend_wakeup_check() ==
+	    SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED) {
+		reg_bit_set(REG_SDRAM_INIT_CTRL_ADDR,
+			    1 << REG_SDRAM_INIT_RESET_MASK_OFFS);
+	}
+
+	/*
+	 * Stage 0 - Set board configuration
+	 */
+
+	/* Check if DRAM is already initialized  */
+	if (reg_read(REG_BOOTROM_ROUTINE_ADDR) &
+	    (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) {
+		printf("%s Training Sequence - 2nd boot - Skip\n", ddr_type);
+		return MV_OK;
+	}
+
+	/*
+	 * Stage 1 - Dunit Setup
+	 */
+
+	/* Fix read ready phases for all SOC in reg 0x15c8 */
+	reg = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+	reg &= ~(REG_TRAINING_DEBUG_3_MASK);
+	reg |= 0x4;		/* Phase 0 */
+	reg &= ~(REG_TRAINING_DEBUG_3_MASK << REG_TRAINING_DEBUG_3_OFFS);
+	reg |= (0x4 << (1 * REG_TRAINING_DEBUG_3_OFFS));	/* Phase 1 */
+	reg &= ~(REG_TRAINING_DEBUG_3_MASK << (3 * REG_TRAINING_DEBUG_3_OFFS));
+	reg |= (0x6 << (3 * REG_TRAINING_DEBUG_3_OFFS));	/* Phase 3 */
+	reg &= ~(REG_TRAINING_DEBUG_3_MASK << (4 * REG_TRAINING_DEBUG_3_OFFS));
+	reg |= (0x6 << (4 * REG_TRAINING_DEBUG_3_OFFS));
+	reg &= ~(REG_TRAINING_DEBUG_3_MASK << (5 * REG_TRAINING_DEBUG_3_OFFS));
+	reg |= (0x6 << (5 * REG_TRAINING_DEBUG_3_OFFS));
+	reg_write(REG_TRAINING_DEBUG_3_ADDR, reg);
+
+	/*
+	 * Axi_bresp_mode[8] = Compliant,
+	 * Axi_addr_decode_cntrl[11] = Internal,
+	 * Axi_data_bus_width[0] = 128bit
+	 * */
+	/* 0x14a8 - AXI Control Register */
+	reg_write(REG_DRAM_AXI_CTRL_ADDR, 0);
+
+	/*
+	 * Stage 2 - Training Values Setup
+	 */
+	/* Set X-BAR windows for the training sequence */
+	ddr3_save_and_set_training_windows(win);
+
+#ifdef SUPPORT_STATIC_DUNIT_CONFIG
+	/*
+	 * Load static controller configuration (in case dynamic/generic init
+	 * is not enabled
+	 */
+	if (generic_init_controller == 0) {
+		ddr3_tip_init_specific_reg_config(0,
+						  ddr_modes
+						  [ddr3_get_static_ddr_mode
+						   ()].regs);
+	}
+#endif
+
+	/* Load topology for New Training IP */
+	status = ddr3_load_topology_map();
+	if (MV_OK != status) {
+		printf("%s Training Sequence topology load - FAILED\n",
+		       ddr_type);
+		return status;
+	}
+
+	/* Tune training algo paramteres */
+	status = ddr3_hws_tune_training_params(0);
+	if (MV_OK != status)
+		return status;
+
+	/* Set log level for training lib */
+	ddr3_hws_set_log_level(DEBUG_BLOCK_ALL, DEBUG_LEVEL_ERROR);
+
+	/* Start New Training IP */
+	status = ddr3_hws_hw_training();
+	if (MV_OK != status) {
+		printf("%s Training Sequence - FAILED\n", ddr_type);
+		return status;
+	}
+
+	/*
+	 * Stage 3 - Finish
+	 */
+	/* Restore and set windows */
+	ddr3_restore_and_set_final_windows(win);
+
+	/* Update DRAM init indication in bootROM register */
+	reg = reg_read(REG_BOOTROM_ROUTINE_ADDR);
+	reg_write(REG_BOOTROM_ROUTINE_ADDR,
+		  reg | (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS));
+
+	/* DLB config */
+	ddr3_new_tip_dlb_config();
+
+#if defined(ECC_SUPPORT)
+	if (ddr3_if_ecc_enabled())
+		ddr3_new_tip_ecc_scrub();
+#endif
+
+	printf("%s Training Sequence - Ended Successfully\n", ddr_type);
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_get_cpu_freq
+ * Desc:     read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns:  required value
+ */
+u32 ddr3_get_cpu_freq(void)
+{
+	return ddr3_tip_get_init_freq();
+}
+
+/*
+ * Name:     ddr3_get_fab_opt
+ * Desc:     read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns:  required value
+ */
+u32 ddr3_get_fab_opt(void)
+{
+	return 0;		/* No fabric */
+}
+
+/*
+ * Name:     ddr3_get_static_m_cValue - Init Memory controller with
+ *           static parameters
+ * Desc:     Use this routine to init the controller without the HW training
+ *           procedure.
+ *           User must provide compatible header file with registers data.
+ * Args:     None.
+ * Notes:
+ * Returns:  None.
+ */
+u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1,
+			     u32 offset2, u32 mask2)
+{
+	u32 reg, temp;
+
+	reg = reg_read(reg_addr);
+
+	temp = (reg >> offset1) & mask1;
+	if (mask2)
+		temp |= (reg >> offset2) & mask2;
+
+	return temp;
+}
+
+/*
+ * Name:     ddr3_get_static_ddr_mode - Init Memory controller with
+ *           static parameters
+ * Desc:     Use this routine to init the controller without the HW training
+ *           procedure.
+ *           User must provide compatible header file with registers data.
+ * Args:     None.
+ * Notes:
+ * Returns:  None.
+ */
+u32 ddr3_get_static_ddr_mode(void)
+{
+	u32 chip_board_rev, i;
+	u32 size;
+
+	/* Valid only for A380 only, MSYS using dynamic controller config */
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+	/*
+	 * Customer boards select DDR mode according to
+	 * board ID & Sample@Reset
+	 */
+	chip_board_rev = mv_board_id_get();
+#else
+	/* Marvell boards select DDR mode according to Sample@Reset only */
+	chip_board_rev = MARVELL_BOARD;
+#endif
+
+	size = ARRAY_SIZE(ddr_modes);
+	for (i = 0; i < size; i++) {
+		if ((ddr3_get_cpu_freq() == ddr_modes[i].cpu_freq) &&
+		    (ddr3_get_fab_opt() == ddr_modes[i].fab_freq) &&
+		    (chip_board_rev == ddr_modes[i].chip_board_rev))
+			return i;
+	}
+
+	DEBUG_INIT_S("\n*** Error: ddr3_get_static_ddr_mode: No match for requested DDR mode. ***\n\n");
+
+	return 0;
+}
+
+/******************************************************************************
+ * Name:     ddr3_get_cs_num_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_num_from_reg(void)
+{
+	u32 cs_ena = sys_env_get_cs_ena_from_reg();
+	u32 cs_count = 0;
+	u32 cs;
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs))
+			cs_count++;
+	}
+
+	return cs_count;
+}
+
+/*
+ * Name:     ddr3_load_topology_map
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+int ddr3_load_topology_map(void)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI)
+	/* Update topology data */
+	if (MV_OK != ddr3_update_topology_map(tm)) {
+		DEBUG_INIT_FULL_S("Failed update of DDR3 Topology map\n");
+	}
+#endif
+
+	return MV_OK;
+}
+
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps)
+{
+	u32 tmp, hclk = 200;
+
+	switch (freq_mode) {
+	case 4:
+		tmp = 1;	/* DDR_400; */
+		hclk = 200;
+		break;
+	case 0x8:
+		tmp = 1;	/* DDR_666; */
+		hclk = 333;
+		break;
+	case 0xc:
+		tmp = 1;	/* DDR_800; */
+		hclk = 400;
+		break;
+	default:
+		*ddr_freq = 0;
+		*hclk_ps = 0;
+		break;
+	}
+
+	*ddr_freq = tmp;		/* DDR freq define */
+	*hclk_ps = 1000000 / hclk;	/* values are 1/HCLK in ps */
+
+	return;
+}
+
+void ddr3_new_tip_dlb_config(void)
+{
+	u32 reg, i = 0;
+	struct dlb_config *config_table_ptr = sys_env_dlb_config_ptr_get();
+
+	/* Write the configuration */
+	while (config_table_ptr[i].reg_addr != 0) {
+		reg_write(config_table_ptr[i].reg_addr,
+			  config_table_ptr[i].reg_data);
+		i++;
+	}
+
+	/* Enable DLB */
+	reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+	reg |= DLB_ENABLE | DLB_WRITE_COALESING | DLB_AXI_PREFETCH_EN |
+		DLB_MBUS_PREFETCH_EN | PREFETCH_N_LN_SZ_TR;
+	reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+}
+
+int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena)
+{
+	u32 reg, cs;
+	u32 mem_total_size = 0;
+	u32 cs_mem_size = 0;
+	u32 mem_total_size_c, cs_mem_size_c;
+
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+	u32 physical_mem_size;
+	u32 max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+#endif
+
+	/* Open fast path windows */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			/* get CS size */
+			if (ddr3_calc_mem_cs_size(cs, &cs_mem_size) != MV_OK)
+				return MV_FAIL;
+
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+			/*
+			 * if number of address pins doesn't allow to use max
+			 * mem size that is defined in topology
+			 * mem size is defined by DEVICE_MAX_DRAM_ADDRESS_SIZE
+			 */
+			physical_mem_size = mem_size
+				[tm->interface_params[0].memory_size];
+
+			if (ddr3_get_device_width(cs) == 16) {
+				/*
+				 * 16bit mem device can be twice more - no need
+				 * in less significant pin
+				 */
+				max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE * 2;
+			}
+
+			if (physical_mem_size > max_mem_size) {
+				cs_mem_size = max_mem_size *
+					(ddr3_get_bus_width() /
+					 ddr3_get_device_width(cs));
+				printf("Updated Physical Mem size is from 0x%x to %x\n",
+				       physical_mem_size,
+				       DEVICE_MAX_DRAM_ADDRESS_SIZE);
+			}
+#endif
+
+			/* set fast path window control for the cs */
+			reg = 0xffffe1;
+			reg |= (cs << 2);
+			reg |= (cs_mem_size - 1) & 0xffff0000;
+			/*Open fast path Window */
+			reg_write(REG_FASTPATH_WIN_CTRL_ADDR(cs), reg);
+
+			/* Set fast path window base address for the cs */
+			reg = ((cs_mem_size) * cs) & 0xffff0000;
+			/* Set base address */
+			reg_write(REG_FASTPATH_WIN_BASE_ADDR(cs), reg);
+
+			/*
+			 * Since memory size may be bigger than 4G the summ may
+			 * be more than 32 bit word,
+			 * so to estimate the result divide mem_total_size and
+			 * cs_mem_size by 0x10000 (it is equal to >> 16)
+			 */
+			mem_total_size_c = mem_total_size >> 16;
+			cs_mem_size_c = cs_mem_size >> 16;
+			/* if the sum less than 2 G - calculate the value */
+			if (mem_total_size_c + cs_mem_size_c < 0x10000)
+				mem_total_size += cs_mem_size;
+			else	/* put max possible size */
+				mem_total_size = L2_FILTER_FOR_MAX_MEMORY_SIZE;
+		}
+	}
+
+	/* Set L2 filtering to Max Memory size */
+	reg_write(ADDRESS_FILTERING_END_REGISTER, mem_total_size);
+
+	return MV_OK;
+}
+
+u32 ddr3_get_bus_width(void)
+{
+	u32 bus_width;
+
+	bus_width = (reg_read(REG_SDRAM_CONFIG_ADDR) & 0x8000) >>
+		REG_SDRAM_CONFIG_WIDTH_OFFS;
+
+	return (bus_width == 0) ? 16 : 32;
+}
+
+u32 ddr3_get_device_width(u32 cs)
+{
+	u32 device_width;
+
+	device_width = (reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR) &
+			(0x3 << (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs))) >>
+		(REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs);
+
+	return (device_width == 0) ? 8 : 16;
+}
+
+float ddr3_get_device_size(u32 cs)
+{
+	u32 device_size_low, device_size_high, device_size;
+	u32 data, cs_low_offset, cs_high_offset;
+
+	cs_low_offset = REG_SDRAM_ADDRESS_SIZE_OFFS + cs * 4;
+	cs_high_offset = REG_SDRAM_ADDRESS_SIZE_OFFS +
+		REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS + cs;
+
+	data = reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR);
+	device_size_low = (data >> cs_low_offset) & 0x3;
+	device_size_high = (data >> cs_high_offset) & 0x1;
+
+	device_size = device_size_low | (device_size_high << 2);
+
+	switch (device_size) {
+	case 0:
+		return 2;
+	case 2:
+		return 0.5;
+	case 3:
+		return 1;
+	case 4:
+		return 4;
+	case 5:
+		return 8;
+	case 1:
+	default:
+		DEBUG_INIT_C("Error: Wrong device size of Cs: ", cs, 1);
+		/*
+		 * Small value will give wrong emem size in
+		 * ddr3_calc_mem_cs_size
+		 */
+		return 0.01;
+	}
+}
+
+int ddr3_calc_mem_cs_size(u32 cs, u32 *cs_size)
+{
+	float cs_mem_size;
+
+	/* Calculate in GiB */
+	cs_mem_size = ((ddr3_get_bus_width() / ddr3_get_device_width(cs)) *
+		       ddr3_get_device_size(cs)) / 8;
+
+	/*
+	 * Multiple controller bus width, 2x for 64 bit
+	 * (SoC controller may be 32 or 64 bit,
+	 * so bit 15 in 0x1400, that means if whole bus used or only half,
+	 * have a differnt meaning
+	 */
+	cs_mem_size *= DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER;
+
+	if (cs_mem_size == 0.125) {
+		*cs_size = 128 << 20;
+	} else if (cs_mem_size == 0.25) {
+		*cs_size = 256 << 20;
+	} else if (cs_mem_size == 0.5) {
+		*cs_size = 512 << 20;
+	} else if (cs_mem_size == 1) {
+		*cs_size = 1 << 30;
+	} else if (cs_mem_size == 2) {
+		*cs_size = 2 << 30;
+	} else {
+		DEBUG_INIT_C("Error: Wrong Memory size of Cs: ", cs, 1);
+		return MV_BAD_VALUE;
+	}
+
+	return MV_OK;
+}
+
+#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI)
+/*
+ * Name:     ddr3_update_topology_map
+ * Desc:
+ * Args:
+ * Notes: Update topology map by Sat_r values
+ * Returns:
+ */
+static int ddr3_update_topology_map(struct hws_topology_map *tm)
+{
+	struct topology_update_info topology_update_info;
+
+	topology_update_info.update_width = 0;
+	topology_update_info.update_ecc = 0;
+	topology_update_info.update_ecc_pup3_mode = 0;
+	sys_env_get_topology_update_info(&topology_update_info);
+	if (topology_update_info.update_width) {
+		tm->bus_act_mask &=
+		    ~(TOPOLOGY_UPDATE_WIDTH_32BIT_MASK);
+		if (topology_update_info.width == TOPOLOGY_UPDATE_WIDTH_16BIT)
+			tm->bus_act_mask =
+			    TOPOLOGY_UPDATE_WIDTH_16BIT_MASK;
+		else
+			tm->bus_act_mask =
+			    TOPOLOGY_UPDATE_WIDTH_32BIT_MASK;
+	}
+
+	if (topology_update_info.update_ecc) {
+		if (topology_update_info.ecc == TOPOLOGY_UPDATE_ECC_OFF) {
+			tm->bus_act_mask &=
+			    ~(1 << topology_update_info.ecc_pup_mode_offset);
+		} else {
+			tm->bus_act_mask |=
+			    topology_update_info.
+			    ecc << topology_update_info.ecc_pup_mode_offset;
+		}
+	}
+
+	return MV_OK;
+}
+#endif
+
+/*
+ * Name:     ddr3_hws_tune_training_params
+ * Desc:
+ * Args:
+ * Notes: Tune internal training params
+ * Returns:
+ */
+static int ddr3_hws_tune_training_params(u8 dev_num)
+{
+	struct tune_train_params params;
+	int status;
+
+	/* NOTE: do not remove any field initilization */
+	params.ck_delay = TUNE_TRAINING_PARAMS_CK_DELAY;
+	params.ck_delay_16 = TUNE_TRAINING_PARAMS_CK_DELAY_16;
+	params.p_finger = TUNE_TRAINING_PARAMS_PFINGER;
+	params.n_finger = TUNE_TRAINING_PARAMS_NFINGER;
+	params.phy_reg3_val = TUNE_TRAINING_PARAMS_PHYREG3VAL;
+
+	status = ddr3_tip_tune_training_params(dev_num, &params);
+	if (MV_OK != status) {
+		printf("%s Training Sequence - FAILED\n", ddr_type);
+		return status;
+	}
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_init.h b/drivers/ddr/marvell/a38x/ddr3_init.h
new file mode 100644
index 0000000..e2ff040
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_init.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_INIT_H
+#define _DDR3_INIT_H
+
+#if defined(CONFIG_ARMADA_38X)
+#include "ddr3_a38x.h"
+#include "ddr3_a38x_mc_static.h"
+#include "ddr3_a38x_topology.h"
+#endif
+#include "ddr3_hws_hw_training.h"
+#include "ddr3_hws_sil_training.h"
+#include "ddr3_logging_def.h"
+#include "ddr3_training_hw_algo.h"
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_centralization.h"
+#include "ddr3_training_ip_engine.h"
+#include "ddr3_training_ip_flow.h"
+#include "ddr3_training_ip_pbs.h"
+#include "ddr3_training_ip_prv_if.h"
+#include "ddr3_training_ip_static.h"
+#include "ddr3_training_leveling.h"
+#include "xor.h"
+
+/*
+ * MV_DEBUG_INIT need to be defines, otherwise the output of the
+ * DDR2 training code is not complete and misleading
+ */
+#define MV_DEBUG_INIT
+
+#define BIT(x)				(1 << (x))
+
+#ifdef MV_DEBUG_INIT
+#define DEBUG_INIT_S(s)			puts(s)
+#define DEBUG_INIT_D(d, l)		printf("%x", d)
+#define DEBUG_INIT_D_10(d, l)		printf("%d", d)
+#else
+#define DEBUG_INIT_S(s)
+#define DEBUG_INIT_D(d, l)
+#define DEBUG_INIT_D_10(d, l)
+#endif
+
+#ifdef MV_DEBUG_INIT_FULL
+#define DEBUG_INIT_FULL_S(s)		puts(s)
+#define DEBUG_INIT_FULL_D(d, l)		printf("%x", d)
+#define DEBUG_INIT_FULL_D_10(d, l)	printf("%d", d)
+#define DEBUG_WR_REG(reg, val) \
+	{ DEBUG_INIT_S("Write Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+	  DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#define DEBUG_RD_REG(reg, val) \
+	{ DEBUG_INIT_S("Read  Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+	  DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#else
+#define DEBUG_INIT_FULL_S(s)
+#define DEBUG_INIT_FULL_D(d, l)
+#define DEBUG_INIT_FULL_D_10(d, l)
+#define DEBUG_WR_REG(reg, val)
+#define DEBUG_RD_REG(reg, val)
+#endif
+
+#define DEBUG_INIT_FULL_C(s, d, l)			\
+	{ DEBUG_INIT_FULL_S(s);				\
+	  DEBUG_INIT_FULL_D(d, l);			\
+	  DEBUG_INIT_FULL_S("\n"); }
+#define DEBUG_INIT_C(s, d, l) \
+	{ DEBUG_INIT_S(s); DEBUG_INIT_D(d, l); DEBUG_INIT_S("\n"); }
+
+/*
+ * Debug (Enable/Disable modules) and Error report
+ */
+
+#ifdef BASIC_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS_RESULTS
+#endif
+
+#ifdef FULL_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS
+
+#define MV_DEBUG_PBS
+#define MV_DEBUG_DFS
+#define MV_DEBUG_MAIN_FULL
+#define MV_DEBUG_DFS_FULL
+#define MV_DEBUG_DQS_FULL
+#define MV_DEBUG_RL_FULL
+#define MV_DEBUG_WL_FULL
+#endif
+
+#if defined(CONFIG_ARMADA_38X)
+#include "ddr3_a38x.h"
+#include "ddr3_a38x_topology.h"
+#endif
+
+/* The following is a list of Marvell status */
+#define MV_ERROR	(-1)
+#define MV_OK		(0x00)	/* Operation succeeded                   */
+#define MV_FAIL		(0x01)	/* Operation failed                      */
+#define MV_BAD_VALUE	(0x02)	/* Illegal value (general)               */
+#define MV_OUT_OF_RANGE	(0x03)	/* The value is out of range             */
+#define MV_BAD_PARAM	(0x04)	/* Illegal parameter in function called  */
+#define MV_BAD_PTR	(0x05)	/* Illegal pointer value                 */
+#define MV_BAD_SIZE	(0x06)	/* Illegal size                          */
+#define MV_BAD_STATE	(0x07)	/* Illegal state of state machine        */
+#define MV_SET_ERROR	(0x08)	/* Set operation failed                  */
+#define MV_GET_ERROR	(0x09)	/* Get operation failed                  */
+#define MV_CREATE_ERROR	(0x0a)	/* Fail while creating an item           */
+#define MV_NOT_FOUND	(0x0b)	/* Item not found                        */
+#define MV_NO_MORE	(0x0c)	/* No more items found                   */
+#define MV_NO_SUCH	(0x0d)	/* No such item                          */
+#define MV_TIMEOUT	(0x0e)	/* Time Out                              */
+#define MV_NO_CHANGE	(0x0f)	/* Parameter(s) is already in this value */
+#define MV_NOT_SUPPORTED (0x10)	/* This request is not support           */
+#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented*/
+#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized          */
+#define MV_NO_RESOURCE	(0x13)	/* Resource not available (memory ...)   */
+#define MV_FULL		(0x14)	/* Item is full (Queue or table etc...)  */
+#define MV_EMPTY	(0x15)	/* Item is empty (Queue or table etc...) */
+#define MV_INIT_ERROR	(0x16)	/* Error occured while INIT process      */
+#define MV_HW_ERROR	(0x17)	/* Hardware error                        */
+#define MV_TX_ERROR	(0x18)	/* Transmit operation not succeeded      */
+#define MV_RX_ERROR	(0x19)	/* Recieve operation not succeeded       */
+#define MV_NOT_READY	(0x1a)	/* The other side is not ready yet       */
+#define MV_ALREADY_EXIST (0x1b)	/* Tried to create existing item         */
+#define MV_OUT_OF_CPU_MEM   (0x1c) /* Cpu memory allocation failed.      */
+#define MV_NOT_STARTED	(0x1d)	/* Not started yet                       */
+#define MV_BUSY		(0x1e)	/* Item is busy.                         */
+#define MV_TERMINATE	(0x1f)	/* Item terminates it's work.            */
+#define MV_NOT_ALIGNED	(0x20)	/* Wrong alignment                       */
+#define MV_NOT_ALLOWED	(0x21)	/* Operation NOT allowed                 */
+#define MV_WRITE_PROTECT (0x22)	/* Write protected                       */
+#define MV_INVALID	(int)(-1)
+
+/* For checking function return values */
+#define CHECK_STATUS(orig_func)		\
+	{				\
+		int status;		\
+		status = orig_func;	\
+		if (MV_OK != status)	\
+			return status;	\
+	}
+
+enum log_level  {
+	MV_LOG_LEVEL_0,
+	MV_LOG_LEVEL_1,
+	MV_LOG_LEVEL_2,
+	MV_LOG_LEVEL_3
+};
+
+/* Globals */
+extern u8 debug_training;
+extern u8 is_reg_dump;
+extern u8 generic_init_controller;
+extern u32 freq_val[];
+extern u32 is_pll_old;
+extern struct cl_val_per_freq cas_latency_table[];
+extern struct pattern_info pattern_table[];
+extern struct cl_val_per_freq cas_write_latency_table[];
+extern u8 debug_training;
+extern u8 debug_centralization, debug_training_ip, debug_training_bist,
+	debug_pbs, debug_training_static, debug_leveling;
+extern u32 pipe_multicast_mask;
+extern struct hws_tip_config_func_db config_func_info[];
+extern u8 cs_mask_reg[];
+extern u8 twr_mask_table[];
+extern u8 cl_mask_table[];
+extern u8 cwl_mask_table[];
+extern u16 rfc_table[];
+extern u32 speed_bin_table_t_rc[];
+extern u32 speed_bin_table_t_rcd_t_rp[];
+extern u32 ck_delay, ck_delay_16;
+
+extern u32 g_zpri_data;
+extern u32 g_znri_data;
+extern u32 g_zpri_ctrl;
+extern u32 g_znri_ctrl;
+extern u32 g_zpodt_data;
+extern u32 g_znodt_data;
+extern u32 g_zpodt_ctrl;
+extern u32 g_znodt_ctrl;
+extern u32 g_dic;
+extern u32 g_odt_config;
+extern u32 g_rtt_nom;
+
+extern u8 debug_training_access;
+extern u8 debug_training_a38x;
+extern u32 first_active_if;
+extern enum hws_ddr_freq init_freq;
+extern u32 delay_enable, ck_delay, ck_delay_16, ca_delay;
+extern u32 mask_tune_func;
+extern u32 rl_version;
+extern int rl_mid_freq_wa;
+extern u8 calibration_update_control; /* 2 external only, 1 is internal only */
+extern enum hws_ddr_freq medium_freq;
+
+extern u32 ck_delay, ck_delay_16;
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern u32 first_active_if;
+extern u32 mask_tune_func;
+extern u32 freq_val[];
+extern enum hws_ddr_freq init_freq;
+extern enum hws_ddr_freq low_freq;
+extern enum hws_ddr_freq medium_freq;
+extern u8 generic_init_controller;
+extern enum auto_tune_stage training_stage;
+extern u32 is_pll_before_init;
+extern u32 is_adll_calib_before_init;
+extern u32 is_dfs_in_init;
+extern int wl_debug_delay;
+extern u32 silicon_delay[HWS_MAX_DEVICE_NUM];
+extern u32 p_finger;
+extern u32 n_finger;
+extern u32 freq_val[DDR_FREQ_LIMIT];
+extern u32 start_pattern, end_pattern;
+extern u32 phy_reg0_val;
+extern u32 phy_reg1_val;
+extern u32 phy_reg2_val;
+extern u32 phy_reg3_val;
+extern enum hws_pattern sweep_pattern;
+extern enum hws_pattern pbs_pattern;
+extern u8 is_rzq6;
+extern u32 znri_data_phy_val;
+extern u32 zpri_data_phy_val;
+extern u32 znri_ctrl_phy_val;
+extern u32 zpri_ctrl_phy_val;
+extern u8 debug_training_access;
+extern u32 finger_test, p_finger_start, p_finger_end, n_finger_start,
+	n_finger_end, p_finger_step, n_finger_step;
+extern u32 mode2_t;
+extern u32 xsb_validate_type;
+extern u32 xsb_validation_base_address;
+extern u32 odt_additional;
+extern u32 debug_mode;
+extern u32 delay_enable;
+extern u32 ca_delay;
+extern u32 debug_dunit;
+extern u32 clamp_tbl[];
+extern u32 freq_mask[HWS_MAX_DEVICE_NUM][DDR_FREQ_LIMIT];
+extern u32 start_pattern, end_pattern;
+
+extern u32 maxt_poll_tries;
+extern u32 is_bist_reset_bit;
+extern u8 debug_training_bist;
+
+extern u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+extern u32 debug_mode;
+extern u32 effective_cs;
+extern int ddr3_tip_centr_skip_min_win_check;
+extern u32 *dq_map_table;
+extern enum auto_tune_stage training_stage;
+extern u8 debug_centralization;
+
+extern u32 delay_enable;
+extern u32 start_pattern, end_pattern;
+extern u32 freq_val[DDR_FREQ_LIMIT];
+extern u8 debug_training_hw_alg;
+extern enum auto_tune_stage training_stage;
+
+extern u8 debug_training_ip;
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern enum auto_tune_stage training_stage;
+extern u32 effective_cs;
+
+extern u8 debug_leveling;
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern enum auto_tune_stage training_stage;
+extern u32 rl_version;
+extern struct cl_val_per_freq cas_latency_table[];
+extern u32 start_xsb_offset;
+extern u32 debug_mode;
+extern u32 odt_config;
+extern u32 effective_cs;
+extern u32 phy_reg1_val;
+
+extern u8 debug_pbs;
+extern u32 effective_cs;
+extern u16 mask_results_dq_reg_map[];
+extern enum hws_ddr_freq medium_freq;
+extern u32 freq_val[];
+extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+extern enum auto_tune_stage training_stage;
+extern u32 debug_mode;
+extern u32 *dq_map_table;
+
+extern u32 vref;
+extern struct cl_val_per_freq cas_latency_table[];
+extern u32 target_freq;
+extern struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM];
+extern u32 clamp_tbl[];
+extern u32 init_freq;
+/* list of allowed frequency listed in order of enum hws_ddr_freq */
+extern u32 freq_val[];
+extern u8 debug_training_static;
+extern u32 first_active_if;
+
+/* Prototypes */
+int ddr3_tip_enable_init_sequence(u32 dev_num);
+
+int ddr3_tip_init_a38x(u32 dev_num, u32 board_id);
+
+int ddr3_hws_hw_training(void);
+int ddr3_silicon_pre_init(void);
+int ddr3_silicon_post_init(void);
+int ddr3_post_run_alg(void);
+int ddr3_if_ecc_enabled(void);
+void ddr3_new_tip_ecc_scrub(void);
+
+void ddr3_print_version(void);
+void ddr3_new_tip_dlb_config(void);
+struct hws_topology_map *ddr3_get_topology_map(void);
+
+int ddr3_if_ecc_enabled(void);
+int ddr3_tip_reg_write(u32 dev_num, u32 reg_addr, u32 data);
+int ddr3_tip_reg_read(u32 dev_num, u32 reg_addr, u32 *data, u32 reg_mask);
+int ddr3_silicon_get_ddr_target_freq(u32 *ddr_freq);
+int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum hws_ddr_freq freq,
+				  struct hws_tip_freq_config_info
+				  *freq_config_info);
+int ddr3_a38x_update_topology_map(u32 dev_num,
+				  struct hws_topology_map *topology_map);
+int ddr3_tip_a38x_get_init_freq(int dev_num, enum hws_ddr_freq *freq);
+int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq);
+int ddr3_tip_a38x_if_read(u8 dev_num, enum hws_access_type interface_access,
+			  u32 if_id, u32 reg_addr, u32 *data, u32 mask);
+int ddr3_tip_a38x_if_write(u8 dev_num, enum hws_access_type interface_access,
+			   u32 if_id, u32 reg_addr, u32 data, u32 mask);
+int ddr3_tip_a38x_get_device_info(u8 dev_num,
+				  struct ddr3_device_info *info_ptr);
+
+int ddr3_tip_init_a38x(u32 dev_num, u32 board_id);
+
+int print_adll(u32 dev_num, u32 adll[MAX_INTERFACE_NUM * MAX_BUS_NUM]);
+int ddr3_tip_restore_dunit_regs(u32 dev_num);
+void print_topology(struct hws_topology_map *topology_db);
+
+u32 mv_board_id_get(void);
+
+int ddr3_load_topology_map(void);
+int ddr3_tip_init_specific_reg_config(u32 dev_num,
+				      struct reg_data *reg_config_arr);
+u32 ddr3_tip_get_init_freq(void);
+void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level);
+int ddr3_tip_tune_training_params(u32 dev_num,
+				  struct tune_train_params *params);
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena);
+void ddr3_fast_path_static_cs_size_config(u32 cs_ena);
+u32 ddr3_get_device_width(u32 cs);
+u32 mv_board_id_index_get(u32 board_id);
+u32 mv_board_id_get(void);
+u32 ddr3_get_bus_width(void);
+void ddr3_set_log_level(u32 n_log_level);
+int ddr3_calc_mem_cs_size(u32 cs, u32 *cs_size);
+
+int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr);
+
+int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode);
+int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode);
+
+int ddr3_tip_static_round_trip_arr_build(u32 dev_num,
+					 struct trip_delay_element *table_ptr,
+					 int is_wl, u32 *round_trip_delay_arr);
+
+u32 hws_ddr3_tip_max_cs_get(void);
+
+/*
+ * Accessor functions for the registers
+ */
+static inline void reg_write(u32 addr, u32 val)
+{
+	writel(val, INTER_REGS_BASE + addr);
+}
+
+static inline u32 reg_read(u32 addr)
+{
+	return readl(INTER_REGS_BASE + addr);
+}
+
+static inline void reg_bit_set(u32 addr, u32 mask)
+{
+	setbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+static inline void reg_bit_clr(u32 addr, u32 mask)
+{
+	clrbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+#endif /* _DDR3_INIT_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_logging_def.h b/drivers/ddr/marvell/a38x/ddr3_logging_def.h
new file mode 100644
index 0000000..2de7c4f
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_logging_def.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_LOGGING_CONFIG_H
+#define _DDR3_LOGGING_CONFIG_H
+
+#ifdef SILENT_LIB
+#define DEBUG_TRAINING_BIST_ENGINE(level, s)
+#define DEBUG_TRAINING_IP(level, s)
+#define DEBUG_CENTRALIZATION_ENGINE(level, s)
+#define DEBUG_TRAINING_HW_ALG(level, s)
+#define DEBUG_TRAINING_IP_ENGINE(level, s)
+#define DEBUG_LEVELING(level, s)
+#define DEBUG_PBS_ENGINE(level, s)
+#define DEBUG_TRAINING_STATIC_IP(level, s)
+#define DEBUG_TRAINING_ACCESS(level, s)
+#else
+#ifdef LIB_FUNCTIONAL_DEBUG_ONLY
+#define DEBUG_TRAINING_BIST_ENGINE(level, s)
+#define DEBUG_TRAINING_IP_ENGINE(level, s)
+#define DEBUG_TRAINING_IP(level, s)		\
+	if (level >= debug_training)		\
+		printf s
+#define DEBUG_CENTRALIZATION_ENGINE(level, s)	\
+	if (level >= debug_centralization)	\
+		printf s
+#define DEBUG_TRAINING_HW_ALG(level, s)		\
+	if (level >= debug_training_hw_alg)	\
+		printf s
+#define DEBUG_LEVELING(level, s)		\
+	if (level >= debug_leveling)		\
+		printf s
+#define DEBUG_PBS_ENGINE(level, s)		\
+	if (level >= debug_pbs)			\
+		printf s
+#define DEBUG_TRAINING_STATIC_IP(level, s)	\
+	if (level >= debug_training_static)	\
+		printf s
+#define DEBUG_TRAINING_ACCESS(level, s)		\
+	if (level >= debug_training_access)	\
+		printf s
+#else
+#define DEBUG_TRAINING_BIST_ENGINE(level, s)	\
+	if (level >= debug_training_bist)	\
+		printf s
+
+#define DEBUG_TRAINING_IP_ENGINE(level, s)	\
+	if (level >= debug_training_ip)		\
+		printf s
+#define DEBUG_TRAINING_IP(level, s)		\
+	if (level >= debug_training)		\
+		printf s
+#define DEBUG_CENTRALIZATION_ENGINE(level, s)	\
+	if (level >= debug_centralization)	\
+		printf s
+#define DEBUG_TRAINING_HW_ALG(level, s)		\
+	if (level >= debug_training_hw_alg)	\
+		printf s
+#define DEBUG_LEVELING(level, s)		\
+	if (level >= debug_leveling)		\
+		printf s
+#define DEBUG_PBS_ENGINE(level, s)		\
+	if (level >= debug_pbs)			\
+		printf s
+#define DEBUG_TRAINING_STATIC_IP(level, s)	\
+	if (level >= debug_training_static)	\
+		printf s
+#define DEBUG_TRAINING_ACCESS(level, s)		\
+	if (level >= debug_training_access)	\
+		printf s
+#endif
+#endif
+
+/* Logging defines */
+#define DEBUG_LEVEL_TRACE	1
+#define DEBUG_LEVEL_INFO	2
+#define DEBUG_LEVEL_ERROR	3
+
+enum ddr_lib_debug_block {
+	DEBUG_BLOCK_STATIC,
+	DEBUG_BLOCK_TRAINING_MAIN,
+	DEBUG_BLOCK_LEVELING,
+	DEBUG_BLOCK_CENTRALIZATION,
+	DEBUG_BLOCK_PBS,
+	DEBUG_BLOCK_IP,
+	DEBUG_BLOCK_BIST,
+	DEBUG_BLOCK_ALG,
+	DEBUG_BLOCK_DEVICE,
+	DEBUG_BLOCK_ACCESS,
+	DEBUG_STAGES_REG_DUMP,
+	/* All excluding IP and REG_DUMP, should be enabled separatelly */
+	DEBUG_BLOCK_ALL
+};
+
+int ddr3_tip_print_log(u32 dev_num, u32 mem_addr);
+int ddr3_tip_print_stability_log(u32 dev_num);
+
+#endif /* _DDR3_LOGGING_CONFIG_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h b/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h
new file mode 100644
index 0000000..0ce0479
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __DDR3_PATTERNS_64_H
+#define __DDR3_PATTERNS_64_H
+
+/*
+ * Patterns Declerations
+ */
+
+u32 wl_sup_pattern[LEN_WL_SUP_PATTERN] __aligned(32) = {
+	0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d,
+	0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d,
+	0x24232221, 0x28272625, 0x2c2b2a29, 0x302f2e2d,
+	0x34333231, 0x38373635, 0x3c3b3a39, 0x403f3e3d,
+	0x44434241, 0x48474645, 0x4c4b4a49, 0x504f4e4d,
+	0x54535251, 0x58575655, 0x5c5b5a59, 0x605f5e5d,
+	0x64636261, 0x68676665, 0x6c6b6a69, 0x706f6e6d,
+	0x74737271, 0x78777675, 0x7c7b7a79, 0x807f7e7d
+};
+
+u32 pbs_pattern_32b[2][LEN_PBS_PATTERN] __aligned(32) = {
+	{
+		0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555,
+		0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555,
+		0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555,
+		0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555
+	},
+	{
+		0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa,
+		0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa,
+		0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa,
+		0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa
+	}
+};
+
+u32 pbs_pattern_64b[2][LEN_PBS_PATTERN] __aligned(32) = {
+	{
+		0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555,
+		0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555,
+		0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555,
+		0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555
+	},
+	{
+		0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa,
+		0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa,
+		0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa,
+		0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa
+	}
+};
+
+u32 rl_pattern[LEN_STD_PATTERN] __aligned(32) = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x01010101, 0x01010101, 0x01010101, 0x01010101
+};
+
+u32 killer_pattern_32b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+	{
+		0x01010101, 0x00000000, 0x01010101, 0xffffffff,
+		0x01010101, 0x00000000, 0x01010101, 0xffffffff,
+		0xfefefefe, 0xfefefefe, 0x01010101, 0xfefefefe,
+		0xfefefefe, 0xfefefefe, 0x01010101, 0xfefefefe,
+		0x01010101, 0xfefefefe, 0x01010101, 0x01010101,
+		0x01010101, 0xfefefefe, 0x01010101, 0x01010101,
+		0xfefefefe, 0x01010101, 0xfefefefe, 0x00000000,
+		0xfefefefe, 0x01010101, 0xfefefefe, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x01010101,
+		0xffffffff, 0x00000000, 0xffffffff, 0x01010101,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0xfefefefe,
+		0x00000000, 0x00000000, 0x00000000, 0xfefefefe,
+		0xfefefefe, 0xffffffff, 0x00000000, 0x00000000,
+		0xfefefefe, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0xfefefefe, 0x00000000, 0xfefefefe, 0x00000000,
+		0xfefefefe, 0x00000000, 0xfefefefe, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x01010101,
+		0x00000000, 0xffffffff, 0xffffffff, 0x01010101,
+		0xffffffff, 0xffffffff, 0x01010101, 0x00000000,
+		0xffffffff, 0xffffffff, 0x01010101, 0x00000000,
+		0x01010101, 0xffffffff, 0xfefefefe, 0xfefefefe,
+		0x01010101, 0xffffffff, 0xfefefefe, 0xfefefefe
+	},
+	{
+		0x02020202, 0x00000000, 0x02020202, 0xffffffff,
+		0x02020202, 0x00000000, 0x02020202, 0xffffffff,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd,
+		0x02020202, 0xfdfdfdfd, 0x02020202, 0x02020202,
+		0x02020202, 0xfdfdfdfd, 0x02020202, 0x02020202,
+		0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, 0x00000000,
+		0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x02020202,
+		0xffffffff, 0x00000000, 0xffffffff, 0x02020202,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0xfdfdfdfd,
+		0x00000000, 0x00000000, 0x00000000, 0xfdfdfdfd,
+		0xfdfdfdfd, 0xffffffff, 0x00000000, 0x00000000,
+		0xfdfdfdfd, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0xfdfdfdfd, 0x00000000, 0xfdfdfdfd, 0x00000000,
+		0xfdfdfdfd, 0x00000000, 0xfdfdfdfd, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x02020202,
+		0x00000000, 0xffffffff, 0xffffffff, 0x02020202,
+		0xffffffff, 0xffffffff, 0x02020202, 0x00000000,
+		0xffffffff, 0xffffffff, 0x02020202, 0x00000000,
+		0x02020202, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x02020202, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd
+	},
+	{
+		0x04040404, 0x00000000, 0x04040404, 0xffffffff,
+		0x04040404, 0x00000000, 0x04040404, 0xffffffff,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb,
+		0x04040404, 0xfbfbfbfb, 0x04040404, 0x04040404,
+		0x04040404, 0xfbfbfbfb, 0x04040404, 0x04040404,
+		0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, 0x00000000,
+		0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x04040404,
+		0xffffffff, 0x00000000, 0xffffffff, 0x04040404,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0xfbfbfbfb,
+		0x00000000, 0x00000000, 0x00000000, 0xfbfbfbfb,
+		0xfbfbfbfb, 0xffffffff, 0x00000000, 0x00000000,
+		0xfbfbfbfb, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0xfbfbfbfb, 0x00000000, 0xfbfbfbfb, 0x00000000,
+		0xfbfbfbfb, 0x00000000, 0xfbfbfbfb, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x04040404,
+		0x00000000, 0xffffffff, 0xffffffff, 0x04040404,
+		0xffffffff, 0xffffffff, 0x04040404, 0x00000000,
+		0xffffffff, 0xffffffff, 0x04040404, 0x00000000,
+		0x04040404, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x04040404, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb
+	},
+	{
+		0x08080808, 0x00000000, 0x08080808, 0xffffffff,
+		0x08080808, 0x00000000, 0x08080808, 0xffffffff,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7,
+		0x08080808, 0xf7f7f7f7, 0x08080808, 0x08080808,
+		0x08080808, 0xf7f7f7f7, 0x08080808, 0x08080808,
+		0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, 0x00000000,
+		0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x08080808,
+		0xffffffff, 0x00000000, 0xffffffff, 0x08080808,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0xf7f7f7f7,
+		0x00000000, 0x00000000, 0x00000000, 0xf7f7f7f7,
+		0xf7f7f7f7, 0xffffffff, 0x00000000, 0x00000000,
+		0xf7f7f7f7, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0xf7f7f7f7, 0x00000000, 0xf7f7f7f7, 0x00000000,
+		0xf7f7f7f7, 0x00000000, 0xf7f7f7f7, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x08080808,
+		0x00000000, 0xffffffff, 0xffffffff, 0x08080808,
+		0xffffffff, 0xffffffff, 0x08080808, 0x00000000,
+		0xffffffff, 0xffffffff, 0x08080808, 0x00000000,
+		0x08080808, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x08080808, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7
+	},
+	{
+		0x10101010, 0x00000000, 0x10101010, 0xffffffff,
+		0x10101010, 0x00000000, 0x10101010, 0xffffffff,
+		0xefefefef, 0xefefefef, 0x10101010, 0xefefefef,
+		0xefefefef, 0xefefefef, 0x10101010, 0xefefefef,
+		0x10101010, 0xefefefef, 0x10101010, 0x10101010,
+		0x10101010, 0xefefefef, 0x10101010, 0x10101010,
+		0xefefefef, 0x10101010, 0xefefefef, 0x00000000,
+		0xefefefef, 0x10101010, 0xefefefef, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x10101010,
+		0xffffffff, 0x00000000, 0xffffffff, 0x10101010,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0xefefefef,
+		0x00000000, 0x00000000, 0x00000000, 0xefefefef,
+		0xefefefef, 0xffffffff, 0x00000000, 0x00000000,
+		0xefefefef, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0xefefefef, 0x00000000, 0xefefefef, 0x00000000,
+		0xefefefef, 0x00000000, 0xefefefef, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x10101010,
+		0x00000000, 0xffffffff, 0xffffffff, 0x10101010,
+		0xffffffff, 0xffffffff, 0x10101010, 0x00000000,
+		0xffffffff, 0xffffffff, 0x10101010, 0x00000000,
+		0x10101010, 0xffffffff, 0xefefefef, 0xefefefef,
+		0x10101010, 0xffffffff, 0xefefefef, 0xefefefef
+	},
+	{
+		0x20202020, 0x00000000, 0x20202020, 0xffffffff,
+		0x20202020, 0x00000000, 0x20202020, 0xffffffff,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf,
+		0x20202020, 0xdfdfdfdf, 0x20202020, 0x20202020,
+		0x20202020, 0xdfdfdfdf, 0x20202020, 0x20202020,
+		0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, 0x00000000,
+		0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x20202020,
+		0xffffffff, 0x00000000, 0xffffffff, 0x20202020,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0xdfdfdfdf,
+		0x00000000, 0x00000000, 0x00000000, 0xdfdfdfdf,
+		0xdfdfdfdf, 0xffffffff, 0x00000000, 0x00000000,
+		0xdfdfdfdf, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0xdfdfdfdf, 0x00000000, 0xdfdfdfdf, 0x00000000,
+		0xdfdfdfdf, 0x00000000, 0xdfdfdfdf, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x20202020,
+		0x00000000, 0xffffffff, 0xffffffff, 0x20202020,
+		0xffffffff, 0xffffffff, 0x20202020, 0x00000000,
+		0xffffffff, 0xffffffff, 0x20202020, 0x00000000,
+		0x20202020, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x20202020, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf
+	},
+	{
+		0x40404040, 0x00000000, 0x40404040, 0xffffffff,
+		0x40404040, 0x00000000, 0x40404040, 0xffffffff,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf,
+		0x40404040, 0xbfbfbfbf, 0x40404040, 0x40404040,
+		0x40404040, 0xbfbfbfbf, 0x40404040, 0x40404040,
+		0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, 0x00000000,
+		0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x40404040,
+		0xffffffff, 0x00000000, 0xffffffff, 0x40404040,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0xbfbfbfbf,
+		0x00000000, 0x00000000, 0x00000000, 0xbfbfbfbf,
+		0xbfbfbfbf, 0xffffffff, 0x00000000, 0x00000000,
+		0xbfbfbfbf, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0xbfbfbfbf, 0x00000000, 0xbfbfbfbf, 0x00000000,
+		0xbfbfbfbf, 0x00000000, 0xbfbfbfbf, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x40404040,
+		0x00000000, 0xffffffff, 0xffffffff, 0x40404040,
+		0xffffffff, 0xffffffff, 0x40404040, 0x00000000,
+		0xffffffff, 0xffffffff, 0x40404040, 0x00000000,
+		0x40404040, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x40404040, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf
+	},
+	{
+		0x80808080, 0x00000000, 0x80808080, 0xffffffff,
+		0x80808080, 0x00000000, 0x80808080, 0xffffffff,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f,
+		0x80808080, 0x7f7f7f7f, 0x80808080, 0x80808080,
+		0x80808080, 0x7f7f7f7f, 0x80808080, 0x80808080,
+		0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, 0x00000000,
+		0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+		0xffffffff, 0x00000000, 0xffffffff, 0x80808080,
+		0xffffffff, 0x00000000, 0xffffffff, 0x80808080,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x7f7f7f7f,
+		0x00000000, 0x00000000, 0x00000000, 0x7f7f7f7f,
+		0x7f7f7f7f, 0xffffffff, 0x00000000, 0x00000000,
+		0x7f7f7f7f, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+		0x7f7f7f7f, 0x00000000, 0x7f7f7f7f, 0x00000000,
+		0x7f7f7f7f, 0x00000000, 0x7f7f7f7f, 0x00000000,
+		0x00000000, 0xffffffff, 0xffffffff, 0x80808080,
+		0x00000000, 0xffffffff, 0xffffffff, 0x80808080,
+		0xffffffff, 0xffffffff, 0x80808080, 0x00000000,
+		0xffffffff, 0xffffffff, 0x80808080, 0x00000000,
+		0x80808080, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x80808080, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f
+	}
+};
+
+u32 killer_pattern_64b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+	{
+		0x01010101, 0x01010101, 0x00000000, 0x00000000,
+		0x01010101, 0x01010101, 0xffffffff, 0xffffffff,
+		0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe,
+		0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+		0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+		0x01010101, 0x01010101, 0x01010101, 0x01010101,
+		0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+		0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x01010101, 0x01010101,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xfefefefe, 0xfefefefe,
+		0xfefefefe, 0xfefefefe, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000,
+		0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x01010101, 0x01010101,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x01010101, 0x01010101, 0x00000000, 0x00000000,
+		0x01010101, 0x01010101, 0xffffffff, 0xffffffff,
+		0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe
+	},
+	{
+		0x02020202, 0x02020202, 0x00000000, 0x00000000,
+		0x02020202, 0x02020202, 0xffffffff, 0xffffffff,
+		0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x02020202, 0x02020202, 0x02020202, 0x02020202,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x02020202, 0x02020202,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xfdfdfdfd, 0xfdfdfdfd,
+		0xfdfdfdfd, 0xfdfdfdfd, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x02020202, 0x02020202,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x02020202, 0x02020202, 0x00000000, 0x00000000,
+		0x02020202, 0x02020202, 0xffffffff, 0xffffffff,
+		0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd
+	},
+	{
+		0x04040404, 0x04040404, 0x00000000, 0x00000000,
+		0x04040404, 0x04040404, 0xffffffff, 0xffffffff,
+		0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x04040404, 0x04040404, 0x04040404, 0x04040404,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x04040404, 0x04040404,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xfbfbfbfb, 0xfbfbfbfb,
+		0xfbfbfbfb, 0xfbfbfbfb, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x04040404, 0x04040404,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x04040404, 0x04040404, 0x00000000, 0x00000000,
+		0x04040404, 0x04040404, 0xffffffff, 0xffffffff,
+		0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb
+	},
+	{
+		0x08080808, 0x08080808, 0x00000000, 0x00000000,
+		0x08080808, 0x08080808, 0xffffffff, 0xffffffff,
+		0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x08080808, 0x08080808, 0x08080808, 0x08080808,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x08080808, 0x08080808,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xf7f7f7f7, 0xf7f7f7f7,
+		0xf7f7f7f7, 0xf7f7f7f7, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x08080808, 0x08080808,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x08080808, 0x08080808, 0x00000000, 0x00000000,
+		0x08080808, 0x08080808, 0xffffffff, 0xffffffff,
+		0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7
+	},
+	{
+		0x10101010, 0x10101010, 0x00000000, 0x00000000,
+		0x10101010, 0x10101010, 0xffffffff, 0xffffffff,
+		0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef,
+		0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+		0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+		0x10101010, 0x10101010, 0x10101010, 0x10101010,
+		0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+		0xefefefef, 0xefefefef, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x10101010, 0x10101010,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xefefefef, 0xefefefef,
+		0xefefefef, 0xefefefef, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xefefefef, 0xefefefef, 0x00000000, 0x00000000,
+		0xefefefef, 0xefefefef, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x10101010, 0x10101010,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x10101010, 0x10101010, 0x00000000, 0x00000000,
+		0x10101010, 0x10101010, 0xffffffff, 0xffffffff,
+		0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef
+	},
+	{
+		0x20202020, 0x20202020, 0x00000000, 0x00000000,
+		0x20202020, 0x20202020, 0xffffffff, 0xffffffff,
+		0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x20202020, 0x20202020, 0x20202020, 0x20202020,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x20202020, 0x20202020,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xdfdfdfdf, 0xdfdfdfdf,
+		0xdfdfdfdf, 0xdfdfdfdf, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x20202020, 0x20202020,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x20202020, 0x20202020, 0x00000000, 0x00000000,
+		0x20202020, 0x20202020, 0xffffffff, 0xffffffff,
+		0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf
+	},
+	{
+		0x40404040, 0x40404040, 0x00000000, 0x00000000,
+		0x40404040, 0x40404040, 0xffffffff, 0xffffffff,
+		0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x40404040, 0x40404040, 0x40404040, 0x40404040,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x40404040, 0x40404040,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xbfbfbfbf, 0xbfbfbfbf,
+		0xbfbfbfbf, 0xbfbfbfbf, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x40404040, 0x40404040,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x40404040, 0x40404040, 0x00000000, 0x00000000,
+		0x40404040, 0x40404040, 0xffffffff, 0xffffffff,
+		0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf
+	},
+	{
+		0x80808080, 0x80808080, 0x00000000, 0x00000000,
+		0x80808080, 0x80808080, 0xffffffff, 0xffffffff,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x80808080, 0x80808080, 0x80808080, 0x80808080,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x80808080, 0x80808080,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x7f7f7f7f, 0x7f7f7f7f, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x80808080, 0x80808080,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x80808080, 0x80808080, 0x00000000, 0x00000000,
+		0x80808080, 0x80808080, 0xffffffff, 0xffffffff,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f
+	}
+};
+
+u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN] __aligned(32) = {
+	{
+		0x00000000, 0x00000000, 0x01010101, 0x01010101,
+		0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe,
+		0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+		0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+		0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101,
+		0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+		0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x01010101, 0x01010101, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe,
+		0x00000000, 0x00000000, 0xfefefefe, 0xfefefefe,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x01010101, 0x01010101, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x01010101, 0x01010101,
+		0x00000000, 0x00000000, 0x01010101, 0x01010101,
+		0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe,
+		0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000
+	},
+	{
+		0x00000000, 0x00000000, 0x02020202, 0x02020202,
+		0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202,
+		0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x02020202, 0x02020202, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x00000000, 0x00000000, 0xfdfdfdfd, 0xfdfdfdfd,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x02020202, 0x02020202, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x02020202, 0x02020202,
+		0x00000000, 0x00000000, 0x02020202, 0x02020202,
+		0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd,
+		0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000
+	},
+	{
+		0x00000000, 0x00000000, 0x04040404, 0x04040404,
+		0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404,
+		0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x04040404, 0x04040404, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x00000000, 0x00000000, 0xfbfbfbfb, 0xfbfbfbfb,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x04040404, 0x04040404, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x04040404, 0x04040404,
+		0x00000000, 0x00000000, 0x04040404, 0x04040404,
+		0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb,
+		0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000
+	},
+	{
+		0x00000000, 0x00000000, 0x08080808, 0x08080808,
+		0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808,
+		0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x08080808, 0x08080808, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x00000000, 0x00000000, 0xf7f7f7f7, 0xf7f7f7f7,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x08080808, 0x08080808, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x08080808, 0x08080808,
+		0x00000000, 0x00000000, 0x08080808, 0x08080808,
+		0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7,
+		0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000
+	},
+	{
+		0x00000000, 0x00000000, 0x10101010, 0x10101010,
+		0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef,
+		0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+		0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+		0xefefefef, 0xefefefef, 0x10101010, 0x10101010,
+		0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+		0x10101010, 0x10101010, 0xefefefef, 0xefefefef,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x10101010, 0x10101010, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef,
+		0x00000000, 0x00000000, 0xefefefef, 0xefefefef,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x10101010, 0x10101010, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x10101010, 0x10101010,
+		0x00000000, 0x00000000, 0x10101010, 0x10101010,
+		0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef,
+		0xefefefef, 0xefefefef, 0x00000000, 0x00000000
+	},
+	{
+		0x00000000, 0x00000000, 0x20202020, 0x20202020,
+		0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020,
+		0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x20202020, 0x20202020, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x00000000, 0x00000000, 0xdfdfdfdf, 0xdfdfdfdf,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x20202020, 0x20202020, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x20202020, 0x20202020,
+		0x00000000, 0x00000000, 0x20202020, 0x20202020,
+		0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf,
+		0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000
+	},
+	{
+		0x00000000, 0x00000000, 0x40404040, 0x40404040,
+		0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040,
+		0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x40404040, 0x40404040, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x00000000, 0x00000000, 0xbfbfbfbf, 0xbfbfbfbf,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x40404040, 0x40404040, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x40404040, 0x40404040,
+		0x00000000, 0x00000000, 0x40404040, 0x40404040,
+		0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf,
+		0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000
+	},
+	{
+		0x00000000, 0x00000000, 0x80808080, 0x80808080,
+		0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080,
+		0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0x80808080, 0x80808080, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x00000000, 0x00000000, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000,
+		0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+		0x80808080, 0x80808080, 0xffffffff, 0xffffffff,
+		0xffffffff, 0xffffffff, 0x80808080, 0x80808080,
+		0x00000000, 0x00000000, 0x80808080, 0x80808080,
+		0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f,
+		0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000
+	}
+};
+
+/* Fabric ratios table */
+u32 fabric_ratio[FAB_OPT] = {
+	0x04010204,
+	0x04020202,
+	0x08020306,
+	0x08020303,
+	0x04020303,
+	0x04020204,
+	0x04010202,
+	0x08030606,
+	0x08030505,
+	0x04020306,
+	0x0804050a,
+	0x04030606,
+	0x04020404,
+	0x04030306,
+	0x04020505,
+	0x08020505,
+	0x04010303,
+	0x08050a0a,
+	0x04030408,
+	0x04010102,
+	0x08030306
+};
+
+u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM] = {
+	{3, 2, 5, 7, 1, 0, 6, 4},
+	{2, 3, 6, 7, 1, 0, 4, 5},
+	{1, 3, 5, 6, 0, 2, 4, 7},
+	{0, 2, 4, 7, 1, 3, 5, 6},
+	{3, 0, 4, 6, 1, 2, 5, 7},
+	{0, 3, 5, 7, 1, 2, 4, 6},
+	{2, 3, 5, 7, 1, 0, 4, 6},
+	{0, 2, 5, 4, 1, 3, 6, 7},
+	{2, 3, 4, 7, 0, 1, 5, 6}
+};
+
+#endif /* __DDR3_PATTERNS_64_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_topology_def.h b/drivers/ddr/marvell/a38x/ddr3_topology_def.h
new file mode 100644
index 0000000..64a0447
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_topology_def.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TOPOLOGY_DEF_H
+#define _DDR3_TOPOLOGY_DEF_H
+
+/* TOPOLOGY */
+
+enum hws_speed_bin {
+	SPEED_BIN_DDR_800D,
+	SPEED_BIN_DDR_800E,
+	SPEED_BIN_DDR_1066E,
+	SPEED_BIN_DDR_1066F,
+	SPEED_BIN_DDR_1066G,
+	SPEED_BIN_DDR_1333F,
+	SPEED_BIN_DDR_1333G,
+	SPEED_BIN_DDR_1333H,
+	SPEED_BIN_DDR_1333J,
+	SPEED_BIN_DDR_1600G,
+	SPEED_BIN_DDR_1600H,
+	SPEED_BIN_DDR_1600J,
+	SPEED_BIN_DDR_1600K,
+	SPEED_BIN_DDR_1866J,
+	SPEED_BIN_DDR_1866K,
+	SPEED_BIN_DDR_1866L,
+	SPEED_BIN_DDR_1866M,
+	SPEED_BIN_DDR_2133K,
+	SPEED_BIN_DDR_2133L,
+	SPEED_BIN_DDR_2133M,
+	SPEED_BIN_DDR_2133N,
+
+	SPEED_BIN_DDR_1333H_EXT,
+	SPEED_BIN_DDR_1600K_EXT,
+	SPEED_BIN_DDR_1866M_EXT
+};
+
+enum hws_ddr_freq {
+	DDR_FREQ_LOW_FREQ,
+	DDR_FREQ_400,
+	DDR_FREQ_533,
+	DDR_FREQ_667,
+	DDR_FREQ_800,
+	DDR_FREQ_933,
+	DDR_FREQ_1066,
+	DDR_FREQ_311,
+	DDR_FREQ_333,
+	DDR_FREQ_467,
+	DDR_FREQ_850,
+	DDR_FREQ_600,
+	DDR_FREQ_300,
+	DDR_FREQ_900,
+	DDR_FREQ_360,
+	DDR_FREQ_1000,
+	DDR_FREQ_LIMIT
+};
+
+enum speed_bin_table_elements {
+	SPEED_BIN_TRCD,
+	SPEED_BIN_TRP,
+	SPEED_BIN_TRAS,
+	SPEED_BIN_TRC,
+	SPEED_BIN_TRRD1K,
+	SPEED_BIN_TRRD2K,
+	SPEED_BIN_TPD,
+	SPEED_BIN_TFAW1K,
+	SPEED_BIN_TFAW2K,
+	SPEED_BIN_TWTR,
+	SPEED_BIN_TRTP,
+	SPEED_BIN_TWR,
+	SPEED_BIN_TMOD
+};
+
+#endif /* _DDR3_TOPOLOGY_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c
new file mode 100644
index 0000000..80ef050
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training.c
@@ -0,0 +1,2644 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define GET_MAX_VALUE(x, y)			\
+	((x) > (y)) ? (x) : (y)
+#define CEIL_DIVIDE(x, y)					\
+	((x - (x / y) * y) == 0) ? ((x / y) - 1) : (x / y)
+
+#define TIME_2_CLOCK_CYCLES	CEIL_DIVIDE
+
+#define GET_CS_FROM_MASK(mask)	(cs_mask2_num[mask])
+#define CS_CBE_VALUE(cs_num)	(cs_cbe_reg[cs_num])
+
+u32 window_mem_addr = 0;
+u32 phy_reg0_val = 0;
+u32 phy_reg1_val = 8;
+u32 phy_reg2_val = 0;
+u32 phy_reg3_val = 0xa;
+enum hws_ddr_freq init_freq = DDR_FREQ_667;
+enum hws_ddr_freq low_freq = DDR_FREQ_LOW_FREQ;
+enum hws_ddr_freq medium_freq;
+u32 debug_dunit = 0;
+u32 odt_additional = 1;
+u32 *dq_map_table = NULL;
+u32 odt_config = 1;
+
+#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ALLEYCAT3) ||	\
+	defined(CONFIG_ARMADA_39X)
+u32 is_pll_before_init = 0, is_adll_calib_before_init = 0, is_dfs_in_init = 0;
+u32 dfs_low_freq = 130;
+#else
+u32 is_pll_before_init = 0, is_adll_calib_before_init = 1, is_dfs_in_init = 0;
+u32 dfs_low_freq = 100;
+#endif
+u32 g_rtt_nom_c_s0, g_rtt_nom_c_s1;
+u8 calibration_update_control;	/* 2 external only, 1 is internal only */
+
+enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM];
+enum auto_tune_stage training_stage = INIT_CONTROLLER;
+u32 finger_test = 0, p_finger_start = 11, p_finger_end = 64,
+	n_finger_start = 11, n_finger_end = 64,
+	p_finger_step = 3, n_finger_step = 3;
+u32 clamp_tbl[] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };
+
+/* Initiate to 0xff, this variable is define by user in debug mode */
+u32 mode2_t = 0xff;
+u32 xsb_validate_type = 0;
+u32 xsb_validation_base_address = 0xf000;
+u32 first_active_if = 0;
+u32 dfs_low_phy1 = 0x1f;
+u32 multicast_id = 0;
+int use_broadcast = 0;
+struct hws_tip_freq_config_info *freq_info_table = NULL;
+u8 is_cbe_required = 0;
+u32 debug_mode = 0;
+u32 delay_enable = 0;
+int rl_mid_freq_wa = 0;
+
+u32 effective_cs = 0;
+
+u32 mask_tune_func = (SET_MEDIUM_FREQ_MASK_BIT |
+		      WRITE_LEVELING_MASK_BIT |
+		      LOAD_PATTERN_2_MASK_BIT |
+		      READ_LEVELING_MASK_BIT |
+		      SET_TARGET_FREQ_MASK_BIT | WRITE_LEVELING_TF_MASK_BIT |
+		      READ_LEVELING_TF_MASK_BIT |
+		      CENTRALIZATION_RX_MASK_BIT | CENTRALIZATION_TX_MASK_BIT);
+
+void ddr3_print_version(void)
+{
+	printf(DDR3_TIP_VERSION_STRING);
+}
+
+static int ddr3_tip_ddr3_training_main_flow(u32 dev_num);
+static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type,
+			      u32 if_id, u32 cl_value, u32 cwl_value);
+static int ddr3_tip_ddr3_auto_tune(u32 dev_num);
+static int is_bus_access_done(u32 dev_num, u32 if_id,
+			      u32 dunit_reg_adrr, u32 bit);
+#ifdef ODT_TEST_SUPPORT
+static int odt_test(u32 dev_num, enum hws_algo_type algo_type);
+#endif
+
+int adll_calibration(u32 dev_num, enum hws_access_type access_type,
+		     u32 if_id, enum hws_ddr_freq frequency);
+static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type,
+			       u32 if_id, enum hws_ddr_freq frequency);
+
+static struct page_element page_param[] = {
+	/*
+	 * 8bits	16 bits
+	 * page-size(K)	page-size(K)	mask
+	 */
+	{ 1,		2,		2},
+	/* 512M */
+	{ 1,		2,		3},
+	/* 1G */
+	{ 1,		2,		0},
+	/* 2G */
+	{ 1,		2,		4},
+	/* 4G */
+	{ 2,		2,		5}
+	/* 8G */
+};
+
+static u8 mem_size_config[MEM_SIZE_LAST] = {
+	0x2,			/* 512Mbit  */
+	0x3,			/* 1Gbit    */
+	0x0,			/* 2Gbit    */
+	0x4,			/* 4Gbit    */
+	0x5			/* 8Gbit    */
+};
+
+static u8 cs_mask2_num[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
+
+static struct reg_data odpg_default_value[] = {
+	{0x1034, 0x38000, MASK_ALL_BITS},
+	{0x1038, 0x0, MASK_ALL_BITS},
+	{0x10b0, 0x0, MASK_ALL_BITS},
+	{0x10b8, 0x0, MASK_ALL_BITS},
+	{0x10c0, 0x0, MASK_ALL_BITS},
+	{0x10f0, 0x0, MASK_ALL_BITS},
+	{0x10f4, 0x0, MASK_ALL_BITS},
+	{0x10f8, 0xff, MASK_ALL_BITS},
+	{0x10fc, 0xffff, MASK_ALL_BITS},
+	{0x1130, 0x0, MASK_ALL_BITS},
+	{0x1830, 0x2000000, MASK_ALL_BITS},
+	{0x14d0, 0x0, MASK_ALL_BITS},
+	{0x14d4, 0x0, MASK_ALL_BITS},
+	{0x14d8, 0x0, MASK_ALL_BITS},
+	{0x14dc, 0x0, MASK_ALL_BITS},
+	{0x1454, 0x0, MASK_ALL_BITS},
+	{0x1594, 0x0, MASK_ALL_BITS},
+	{0x1598, 0x0, MASK_ALL_BITS},
+	{0x159c, 0x0, MASK_ALL_BITS},
+	{0x15a0, 0x0, MASK_ALL_BITS},
+	{0x15a4, 0x0, MASK_ALL_BITS},
+	{0x15a8, 0x0, MASK_ALL_BITS},
+	{0x15ac, 0x0, MASK_ALL_BITS},
+	{0x1604, 0x0, MASK_ALL_BITS},
+	{0x1608, 0x0, MASK_ALL_BITS},
+	{0x160c, 0x0, MASK_ALL_BITS},
+	{0x1610, 0x0, MASK_ALL_BITS},
+	{0x1614, 0x0, MASK_ALL_BITS},
+	{0x1618, 0x0, MASK_ALL_BITS},
+	{0x1624, 0x0, MASK_ALL_BITS},
+	{0x1690, 0x0, MASK_ALL_BITS},
+	{0x1694, 0x0, MASK_ALL_BITS},
+	{0x1698, 0x0, MASK_ALL_BITS},
+	{0x169c, 0x0, MASK_ALL_BITS},
+	{0x14b8, 0x6f67, MASK_ALL_BITS},
+	{0x1630, 0x0, MASK_ALL_BITS},
+	{0x1634, 0x0, MASK_ALL_BITS},
+	{0x1638, 0x0, MASK_ALL_BITS},
+	{0x163c, 0x0, MASK_ALL_BITS},
+	{0x16b0, 0x0, MASK_ALL_BITS},
+	{0x16b4, 0x0, MASK_ALL_BITS},
+	{0x16b8, 0x0, MASK_ALL_BITS},
+	{0x16bc, 0x0, MASK_ALL_BITS},
+	{0x16c0, 0x0, MASK_ALL_BITS},
+	{0x16c4, 0x0, MASK_ALL_BITS},
+	{0x16c8, 0x0, MASK_ALL_BITS},
+	{0x16cc, 0x1, MASK_ALL_BITS},
+	{0x16f0, 0x1, MASK_ALL_BITS},
+	{0x16f4, 0x0, MASK_ALL_BITS},
+	{0x16f8, 0x0, MASK_ALL_BITS},
+	{0x16fc, 0x0, MASK_ALL_BITS}
+};
+
+static int ddr3_tip_bus_access(u32 dev_num, enum hws_access_type interface_access,
+			       u32 if_id, enum hws_access_type phy_access,
+			       u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+			       u32 data_value, enum hws_operation oper_type);
+static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id);
+static int ddr3_tip_rank_control(u32 dev_num, u32 if_id);
+
+/*
+ * Update global training parameters by data from user
+ */
+int ddr3_tip_tune_training_params(u32 dev_num,
+				  struct tune_train_params *params)
+{
+	if (params->ck_delay != -1)
+		ck_delay = params->ck_delay;
+	if (params->ck_delay_16 != -1)
+		ck_delay_16 = params->ck_delay_16;
+	if (params->phy_reg3_val != -1)
+		phy_reg3_val = params->phy_reg3_val;
+
+	return MV_OK;
+}
+
+/*
+ * Configure CS
+ */
+int ddr3_tip_configure_cs(u32 dev_num, u32 if_id, u32 cs_num, u32 enable)
+{
+	u32 data, addr_hi, data_high;
+	u32 mem_index;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (enable == 1) {
+		data = (tm->interface_params[if_id].bus_width ==
+			BUS_WIDTH_8) ? 0 : 1;
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      SDRAM_ACCESS_CONTROL_REG, (data << (cs_num * 4)),
+			      0x3 << (cs_num * 4)));
+		mem_index = tm->interface_params[if_id].memory_size;
+
+		addr_hi = mem_size_config[mem_index] & 0x3;
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      SDRAM_ACCESS_CONTROL_REG,
+			      (addr_hi << (2 + cs_num * 4)),
+			      0x3 << (2 + cs_num * 4)));
+
+		data_high = (mem_size_config[mem_index] & 0x4) >> 2;
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      SDRAM_ACCESS_CONTROL_REG,
+			      data_high << (20 + cs_num), 1 << (20 + cs_num)));
+
+		/* Enable Address Select Mode */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      SDRAM_ACCESS_CONTROL_REG, 1 << (16 + cs_num),
+			      1 << (16 + cs_num)));
+	}
+	switch (cs_num) {
+	case 0:
+	case 1:
+	case 2:
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      DDR_CONTROL_LOW_REG, (enable << (cs_num + 11)),
+			      1 << (cs_num + 11)));
+		break;
+	case 3:
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      DDR_CONTROL_LOW_REG, (enable << 15), 1 << 15));
+		break;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Calculate number of CS
+ */
+static int calc_cs_num(u32 dev_num, u32 if_id, u32 *cs_num)
+{
+	u32 cs;
+	u32 bus_cnt;
+	u32 cs_count;
+	u32 cs_bitmask;
+	u32 curr_cs_num = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+		cs_count = 0;
+		cs_bitmask = tm->interface_params[if_id].
+			as_bus_params[bus_cnt].cs_bitmask;
+		for (cs = 0; cs < MAX_CS_NUM; cs++) {
+			if ((cs_bitmask >> cs) & 1)
+				cs_count++;
+		}
+
+		if (curr_cs_num == 0) {
+			curr_cs_num = cs_count;
+		} else if (cs_count != curr_cs_num) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("CS number is different per bus (IF %d BUS %d cs_num %d curr_cs_num %d)\n",
+					   if_id, bus_cnt, cs_count,
+					   curr_cs_num));
+			return MV_NOT_SUPPORTED;
+		}
+	}
+	*cs_num = curr_cs_num;
+
+	return MV_OK;
+}
+
+/*
+ * Init Controller Flow
+ */
+int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_prm)
+{
+	u32 if_id;
+	u32 cs_num;
+	u32 t_refi = 0, t_hclk = 0, t_ckclk = 0, t_faw = 0, t_pd = 0,
+		t_wr = 0, t2t = 0, txpdll = 0;
+	u32 data_value = 0, bus_width = 0, page_size = 0, cs_cnt = 0,
+		mem_mask = 0, bus_index = 0;
+	enum hws_speed_bin speed_bin_index = SPEED_BIN_DDR_2133N;
+	enum hws_mem_size memory_size = MEM_2G;
+	enum hws_ddr_freq freq = init_freq;
+	u32 cs_mask = 0;
+	u32 cl_value = 0, cwl_val = 0;
+	u32 refresh_interval_cnt = 0, bus_cnt = 0, adll_tap = 0;
+	enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
+	u32 data_read[MAX_INTERFACE_NUM];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+			  ("Init_controller, do_mrs_phy=%d, is_ctrl64_bit=%d\n",
+			   init_cntr_prm->do_mrs_phy,
+			   init_cntr_prm->is_ctrl64_bit));
+
+	if (init_cntr_prm->init_phy == 1) {
+		CHECK_STATUS(ddr3_tip_configure_phy(dev_num));
+	}
+
+	if (generic_init_controller == 1) {
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+					  ("active IF %d\n", if_id));
+			mem_mask = 0;
+			for (bus_index = 0;
+			     bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+			     bus_index++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+				mem_mask |=
+					tm->interface_params[if_id].
+					as_bus_params[bus_index].mirror_enable_bitmask;
+			}
+
+			if (mem_mask != 0) {
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, ACCESS_TYPE_MULTICAST,
+					      if_id, CS_ENABLE_REG, 0,
+					      0x8));
+			}
+
+			memory_size =
+				tm->interface_params[if_id].
+				memory_size;
+			speed_bin_index =
+				tm->interface_params[if_id].
+				speed_bin_index;
+			freq = init_freq;
+			t_refi =
+				(tm->interface_params[if_id].
+				 interface_temp ==
+				 HWS_TEMP_HIGH) ? TREFI_HIGH : TREFI_LOW;
+			t_refi *= 1000;	/* psec */
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+					  ("memy_size %d speed_bin_ind %d freq %d t_refi %d\n",
+					   memory_size, speed_bin_index, freq,
+					   t_refi));
+			/* HCLK & CK CLK in 2:1[ps] */
+			/* t_ckclk is external clock */
+			t_ckclk = (MEGA / freq_val[freq]);
+			/* t_hclk is internal clock */
+			t_hclk = 2 * t_ckclk;
+			refresh_interval_cnt = t_refi / t_hclk;	/* no units */
+			bus_width =
+				(DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask)
+				 == 1) ? (16) : (32);
+
+			if (init_cntr_prm->is_ctrl64_bit)
+				bus_width = 64;
+
+			data_value =
+				(refresh_interval_cnt | 0x4000 |
+				 ((bus_width ==
+				   32) ? 0x8000 : 0) | 0x1000000) & ~(1 << 26);
+
+			/* Interface Bus Width */
+			/* SRMode */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      SDRAM_CONFIGURATION_REG, data_value,
+				      0x100ffff));
+
+			/* Interleave first command pre-charge enable (TBD) */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      SDRAM_OPEN_PAGE_CONTROL_REG, (1 << 10),
+				      (1 << 10)));
+
+			/* PHY configuration */
+			/*
+			 * Postamble Length = 1.5cc, Addresscntl to clk skew
+			 * \BD, Preamble length normal, parralal ADLL enable
+			 */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DRAM_PHY_CONFIGURATION, 0x28, 0x3e));
+			if (init_cntr_prm->is_ctrl64_bit) {
+				/* positive edge */
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, access_type, if_id,
+					      DRAM_PHY_CONFIGURATION, 0x0,
+					      0xff80));
+			}
+
+			/* calibration block disable */
+			/* Xbar Read buffer select (for Internal access) */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      CALIB_MACHINE_CTRL_REG, 0x1200c,
+				      0x7dffe01c));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      CALIB_MACHINE_CTRL_REG,
+				      calibration_update_control << 3, 0x3 << 3));
+
+			/* Pad calibration control - enable */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      CALIB_MACHINE_CTRL_REG, 0x1, 0x1));
+
+			cs_mask = 0;
+			data_value = 0x7;
+			/*
+			 * Address ctrl \96 Part of the Generic code
+			 * The next configuration is done:
+			 * 1)  Memory Size
+			 * 2) Bus_width
+			 * 3) CS#
+			 * 4) Page Number
+			 * 5) t_faw
+			 * Per Dunit get from the Map_topology the parameters:
+			 * Bus_width
+			 * t_faw is per Dunit not per CS
+			 */
+			page_size =
+				(tm->interface_params[if_id].
+				 bus_width ==
+				 BUS_WIDTH_8) ? page_param[memory_size].
+				page_size_8bit : page_param[memory_size].
+				page_size_16bit;
+
+			t_faw =
+				(page_size == 1) ? speed_bin_table(speed_bin_index,
+								   SPEED_BIN_TFAW1K)
+				: speed_bin_table(speed_bin_index,
+						  SPEED_BIN_TFAW2K);
+
+			data_value = TIME_2_CLOCK_CYCLES(t_faw, t_ckclk);
+			data_value = data_value << 24;
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      SDRAM_ACCESS_CONTROL_REG, data_value,
+				      0x7f000000));
+
+			data_value =
+				(tm->interface_params[if_id].
+				 bus_width == BUS_WIDTH_8) ? 0 : 1;
+
+			/* create merge cs mask for all cs available in dunit */
+			for (bus_cnt = 0;
+			     bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+			     bus_cnt++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+				cs_mask |=
+					tm->interface_params[if_id].
+					as_bus_params[bus_cnt].cs_bitmask;
+			}
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+					  ("Init_controller IF %d cs_mask %d\n",
+					   if_id, cs_mask));
+			/*
+			 * Configure the next upon the Map Topology \96 If the
+			 * Dunit is CS0 Configure CS0 if it is multi CS
+			 * configure them both:  The Bust_width it\92s the
+			 * Memory Bus width \96 x8 or x16
+			 */
+			for (cs_cnt = 0; cs_cnt < NUM_OF_CS; cs_cnt++) {
+				ddr3_tip_configure_cs(dev_num, if_id, cs_cnt,
+						      ((cs_mask & (1 << cs_cnt)) ? 1
+						       : 0));
+			}
+
+			if (init_cntr_prm->do_mrs_phy) {
+				/*
+				 * MR0 \96 Part of the Generic code
+				 * The next configuration is done:
+				 * 1) Burst Length
+				 * 2) CAS Latency
+				 * get for each dunit what is it Speed_bin &
+				 * Target Frequency. From those both parameters
+				 * get the appropriate Cas_l from the CL table
+				 */
+				cl_value =
+					tm->interface_params[if_id].
+					cas_l;
+				cwl_val =
+					tm->interface_params[if_id].
+					cas_wl;
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+						  ("cl_value 0x%x cwl_val 0x%x\n",
+						   cl_value, cwl_val));
+
+				data_value =
+					((cl_mask_table[cl_value] & 0x1) << 2) |
+					((cl_mask_table[cl_value] & 0xe) << 3);
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, access_type, if_id,
+					      MR0_REG, data_value,
+					      (0x7 << 4) | (1 << 2)));
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, access_type, if_id,
+					      MR0_REG, twr_mask_table[t_wr + 1],
+					      0xe00));
+
+				/*
+				 * MR1: Set RTT and DIC Design GL values
+				 * configured by user
+				 */
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, ACCESS_TYPE_MULTICAST,
+					      PARAM_NOT_CARE, MR1_REG,
+					      g_dic | g_rtt_nom, 0x266));
+
+				/* MR2 - Part of the Generic code */
+				/*
+				 * The next configuration is done:
+				 * 1)  SRT
+				 * 2) CAS Write Latency
+				 */
+				data_value = (cwl_mask_table[cwl_val] << 3);
+				data_value |=
+					((tm->interface_params[if_id].
+					  interface_temp ==
+					  HWS_TEMP_HIGH) ? (1 << 7) : 0);
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, access_type, if_id,
+					      MR2_REG, data_value,
+					      (0x7 << 3) | (0x1 << 7) | (0x3 <<
+									 9)));
+			}
+
+			ddr3_tip_write_odt(dev_num, access_type, if_id,
+					   cl_value, cwl_val);
+			ddr3_tip_set_timing(dev_num, access_type, if_id, freq);
+
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DUNIT_CONTROL_HIGH_REG, 0x177,
+				      0x1000177));
+
+			if (init_cntr_prm->is_ctrl64_bit) {
+				/* disable 0.25 cc delay */
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, access_type, if_id,
+					      DUNIT_CONTROL_HIGH_REG, 0x0,
+					      0x800));
+			}
+
+			/* reset bit 7 */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DUNIT_CONTROL_HIGH_REG,
+				      (init_cntr_prm->msys_init << 7), (1 << 7)));
+
+			if (mode2_t != 0xff) {
+				t2t = mode2_t;
+			} else {
+				/* calculate number of CS (per interface) */
+				CHECK_STATUS(calc_cs_num
+					     (dev_num, if_id, &cs_num));
+				t2t = (cs_num == 1) ? 0 : 1;
+			}
+
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DDR_CONTROL_LOW_REG, t2t << 3,
+				      0x3 << 3));
+			/* move the block to ddr3_tip_set_timing - start */
+			t_pd = GET_MAX_VALUE(t_ckclk * 3,
+					     speed_bin_table(speed_bin_index,
+							     SPEED_BIN_TPD));
+			t_pd = TIME_2_CLOCK_CYCLES(t_pd, t_ckclk);
+			txpdll = GET_MAX_VALUE(t_ckclk * 10, 24);
+			txpdll = CEIL_DIVIDE((txpdll - 1), t_ckclk);
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DDR_TIMING_REG, txpdll << 4,
+				      0x1f << 4));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DDR_TIMING_REG, 0x28 << 9, 0x3f << 9));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DDR_TIMING_REG, 0xa << 21, 0xff << 21));
+
+			/* move the block to ddr3_tip_set_timing - end */
+			/* AUTO_ZQC_TIMING */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      TIMING_REG, (AUTO_ZQC_TIMING | (2 << 20)),
+				      0x3fffff));
+			CHECK_STATUS(ddr3_tip_if_read
+				     (dev_num, access_type, if_id,
+				      DRAM_PHY_CONFIGURATION, data_read, 0x30));
+			data_value =
+				(data_read[if_id] == 0) ? (1 << 11) : 0;
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DUNIT_CONTROL_HIGH_REG, data_value,
+				      (1 << 11)));
+
+			/* Set Active control for ODT write transactions */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, ACCESS_TYPE_MULTICAST,
+				      PARAM_NOT_CARE, 0x1494, g_odt_config,
+				      MASK_ALL_BITS));
+		}
+	} else {
+#ifdef STATIC_ALGO_SUPPORT
+		CHECK_STATUS(ddr3_tip_static_init_controller(dev_num));
+#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X)
+		CHECK_STATUS(ddr3_tip_static_phy_init_controller(dev_num));
+#endif
+#endif /* STATIC_ALGO_SUPPORT */
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(ddr3_tip_rank_control(dev_num, if_id));
+
+		if (init_cntr_prm->do_mrs_phy) {
+			CHECK_STATUS(ddr3_tip_pad_inv(dev_num, if_id));
+		}
+
+		/* Pad calibration control - disable */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      CALIB_MACHINE_CTRL_REG, 0x0, 0x1));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      CALIB_MACHINE_CTRL_REG,
+			      calibration_update_control << 3, 0x3 << 3));
+	}
+
+	CHECK_STATUS(ddr3_tip_enable_init_sequence(dev_num));
+
+	if (delay_enable != 0) {
+		adll_tap = MEGA / (freq_val[freq] * 64);
+		ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Load Topology map
+ */
+int hws_ddr3_tip_load_topology_map(u32 dev_num, struct hws_topology_map *tm)
+{
+	enum hws_speed_bin speed_bin_index;
+	enum hws_ddr_freq freq = DDR_FREQ_LIMIT;
+	u32 if_id;
+
+	freq_val[DDR_FREQ_LOW_FREQ] = dfs_low_freq;
+	tm = ddr3_get_topology_map();
+	CHECK_STATUS(ddr3_tip_get_first_active_if
+		     ((u8)dev_num, tm->if_act_mask,
+		      &first_active_if));
+	DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+			  ("board IF_Mask=0x%x num_of_bus_per_interface=0x%x\n",
+			   tm->if_act_mask,
+			   tm->num_of_bus_per_interface));
+
+	/*
+	 * if CL, CWL values are missing in topology map, then fill them
+	 * according to speedbin tables
+	 */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		speed_bin_index =
+			tm->interface_params[if_id].speed_bin_index;
+		/* TBD memory frequency of interface 0 only is used ! */
+		freq = tm->interface_params[first_active_if].memory_freq;
+
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+				  ("speed_bin_index =%d freq=%d cl=%d cwl=%d\n",
+				   speed_bin_index, freq_val[freq],
+				   tm->interface_params[if_id].
+				   cas_l,
+				   tm->interface_params[if_id].
+				   cas_wl));
+
+		if (tm->interface_params[if_id].cas_l == 0) {
+			tm->interface_params[if_id].cas_l =
+				cas_latency_table[speed_bin_index].cl_val[freq];
+		}
+
+		if (tm->interface_params[if_id].cas_wl == 0) {
+			tm->interface_params[if_id].cas_wl =
+				cas_write_latency_table[speed_bin_index].cl_val[freq];
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * RANK Control Flow
+ */
+static int ddr3_tip_rank_control(u32 dev_num, u32 if_id)
+{
+	u32 data_value = 0, bus_cnt;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (bus_cnt = 1; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+		if ((tm->interface_params[if_id].
+		     as_bus_params[0].cs_bitmask !=
+		     tm->interface_params[if_id].
+		     as_bus_params[bus_cnt].cs_bitmask) ||
+		    (tm->interface_params[if_id].
+		     as_bus_params[0].mirror_enable_bitmask !=
+		     tm->interface_params[if_id].
+		     as_bus_params[bus_cnt].mirror_enable_bitmask))
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("WARNING:Wrong configuration for pup #%d CS mask and CS mirroring for all pups should be the same\n",
+					   bus_cnt));
+	}
+
+	data_value |= tm->interface_params[if_id].
+		as_bus_params[0].cs_bitmask;
+	data_value |= tm->interface_params[if_id].
+		as_bus_params[0].mirror_enable_bitmask << 4;
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, RANK_CTRL_REG,
+		      data_value, 0xff));
+
+	return MV_OK;
+}
+
+/*
+ * PAD Inverse Flow
+ */
+static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id)
+{
+	u32 bus_cnt, data_value, ck_swap_pup_ctrl;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+		if (tm->interface_params[if_id].
+		    as_bus_params[bus_cnt].is_dqs_swap == 1) {
+			/* dqs swap */
+			ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST,
+						       if_id, bus_cnt,
+						       DDR_PHY_DATA,
+						       PHY_CONTROL_PHY_REG, 0xc0,
+						       0xc0);
+		}
+
+		if (tm->interface_params[if_id].
+		    as_bus_params[bus_cnt].is_ck_swap == 1) {
+			if (bus_cnt <= 1)
+				data_value = 0x5 << 2;
+			else
+				data_value = 0xa << 2;
+
+			/* mask equals data */
+			/* ck swap pup is only control pup #0 ! */
+			ck_swap_pup_ctrl = 0;
+			ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST,
+						       if_id, ck_swap_pup_ctrl,
+						       DDR_PHY_CONTROL,
+						       PHY_CONTROL_PHY_REG,
+						       data_value, data_value);
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Run Training Flow
+ */
+int hws_ddr3_tip_run_alg(u32 dev_num, enum hws_algo_type algo_type)
+{
+	int ret = MV_OK, ret_tune = MV_OK;
+
+#ifdef ODT_TEST_SUPPORT
+	if (finger_test == 1)
+		return odt_test(dev_num, algo_type);
+#endif
+
+	if (algo_type == ALGO_TYPE_DYNAMIC) {
+		ret = ddr3_tip_ddr3_auto_tune(dev_num);
+	} else {
+#ifdef STATIC_ALGO_SUPPORT
+		{
+			enum hws_ddr_freq freq;
+			freq = init_freq;
+
+			/* add to mask */
+			if (is_adll_calib_before_init != 0) {
+				printf("with adll calib before init\n");
+				adll_calibration(dev_num, ACCESS_TYPE_MULTICAST,
+						 0, freq);
+			}
+			/*
+			 * Frequency per interface is not relevant,
+			 * only interface 0
+			 */
+			ret = ddr3_tip_run_static_alg(dev_num,
+						      freq);
+		}
+#endif
+	}
+
+	if (ret != MV_OK) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("Run_alg: tuning failed %d\n", ret_tune));
+	}
+
+	return ret;
+}
+
+#ifdef ODT_TEST_SUPPORT
+/*
+ * ODT Test
+ */
+static int odt_test(u32 dev_num, enum hws_algo_type algo_type)
+{
+	int ret = MV_OK, ret_tune = MV_OK;
+	int pfinger_val = 0, nfinger_val;
+
+	for (pfinger_val = p_finger_start; pfinger_val <= p_finger_end;
+	     pfinger_val += p_finger_step) {
+		for (nfinger_val = n_finger_start; nfinger_val <= n_finger_end;
+		     nfinger_val += n_finger_step) {
+			if (finger_test != 0) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+						  ("pfinger_val %d nfinger_val %d\n",
+						   pfinger_val, nfinger_val));
+				p_finger = pfinger_val;
+				n_finger = nfinger_val;
+			}
+
+			if (algo_type == ALGO_TYPE_DYNAMIC) {
+				ret = ddr3_tip_ddr3_auto_tune(dev_num);
+			} else {
+				/*
+				 * Frequency per interface is not relevant,
+				 * only interface 0
+				 */
+				ret = ddr3_tip_run_static_alg(dev_num,
+							      init_freq);
+			}
+		}
+	}
+
+	if (ret_tune != MV_OK) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("Run_alg: tuning failed %d\n", ret_tune));
+		ret = (ret == MV_OK) ? ret_tune : ret;
+	}
+
+	return ret;
+}
+#endif
+
+/*
+ * Select Controller
+ */
+int hws_ddr3_tip_select_ddr_controller(u32 dev_num, int enable)
+{
+	if (config_func_info[dev_num].tip_dunit_mux_select_func != NULL) {
+		return config_func_info[dev_num].
+			tip_dunit_mux_select_func((u8)dev_num, enable);
+	}
+
+	return MV_FAIL;
+}
+
+/*
+ * Dunit Register Write
+ */
+int ddr3_tip_if_write(u32 dev_num, enum hws_access_type interface_access,
+		      u32 if_id, u32 reg_addr, u32 data_value, u32 mask)
+{
+	if (config_func_info[dev_num].tip_dunit_write_func != NULL) {
+		return config_func_info[dev_num].
+			tip_dunit_write_func((u8)dev_num, interface_access,
+					     if_id, reg_addr,
+					     data_value, mask);
+	}
+
+	return MV_FAIL;
+}
+
+/*
+ * Dunit Register Read
+ */
+int ddr3_tip_if_read(u32 dev_num, enum hws_access_type interface_access,
+		     u32 if_id, u32 reg_addr, u32 *data, u32 mask)
+{
+	if (config_func_info[dev_num].tip_dunit_read_func != NULL) {
+		return config_func_info[dev_num].
+			tip_dunit_read_func((u8)dev_num, interface_access,
+					    if_id, reg_addr,
+					    data, mask);
+	}
+
+	return MV_FAIL;
+}
+
+/*
+ * Dunit Register Polling
+ */
+int ddr3_tip_if_polling(u32 dev_num, enum hws_access_type access_type,
+			u32 if_id, u32 exp_value, u32 mask, u32 offset,
+			u32 poll_tries)
+{
+	u32 poll_cnt = 0, interface_num = 0, start_if, end_if;
+	u32 read_data[MAX_INTERFACE_NUM];
+	int ret;
+	int is_fail = 0, is_if_fail;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (access_type == ACCESS_TYPE_MULTICAST) {
+		start_if = 0;
+		end_if = MAX_INTERFACE_NUM - 1;
+	} else {
+		start_if = if_id;
+		end_if = if_id;
+	}
+
+	for (interface_num = start_if; interface_num <= end_if; interface_num++) {
+		/* polling bit 3 for n times */
+		VALIDATE_ACTIVE(tm->if_act_mask, interface_num);
+
+		is_if_fail = 0;
+		for (poll_cnt = 0; poll_cnt < poll_tries; poll_cnt++) {
+			ret =
+				ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST,
+						 interface_num, offset, read_data,
+						 mask);
+			if (ret != MV_OK)
+				return ret;
+
+			if (read_data[interface_num] == exp_value)
+				break;
+		}
+
+		if (poll_cnt >= poll_tries) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("max poll IF #%d\n", interface_num));
+			is_fail = 1;
+			is_if_fail = 1;
+		}
+
+		training_result[training_stage][interface_num] =
+			(is_if_fail == 1) ? TEST_FAILED : TEST_SUCCESS;
+	}
+
+	return (is_fail == 0) ? MV_OK : MV_FAIL;
+}
+
+/*
+ * Bus read access
+ */
+int ddr3_tip_bus_read(u32 dev_num, u32 if_id,
+		      enum hws_access_type phy_access, u32 phy_id,
+		      enum hws_ddr_phy phy_type, u32 reg_addr, u32 *data)
+{
+	u32 bus_index = 0;
+	u32 data_read[MAX_INTERFACE_NUM];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (phy_access == ACCESS_TYPE_MULTICAST) {
+		for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+		     bus_index++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+			CHECK_STATUS(ddr3_tip_bus_access
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id, ACCESS_TYPE_UNICAST,
+				      bus_index, phy_type, reg_addr, 0,
+				      OPERATION_READ));
+			CHECK_STATUS(ddr3_tip_if_read
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      PHY_REG_FILE_ACCESS, data_read,
+				      MASK_ALL_BITS));
+			data[bus_index] = (data_read[if_id] & 0xffff);
+		}
+	} else {
+		CHECK_STATUS(ddr3_tip_bus_access
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      phy_access, phy_id, phy_type, reg_addr, 0,
+			      OPERATION_READ));
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      PHY_REG_FILE_ACCESS, data_read, MASK_ALL_BITS));
+
+		/*
+		 * only 16 lsb bit are valid in Phy (each register is different,
+		 * some can actually be less than 16 bits)
+		 */
+		*data = (data_read[if_id] & 0xffff);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Bus write access
+ */
+int ddr3_tip_bus_write(u32 dev_num, enum hws_access_type interface_access,
+		       u32 if_id, enum hws_access_type phy_access,
+		       u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+		       u32 data_value)
+{
+	CHECK_STATUS(ddr3_tip_bus_access
+		     (dev_num, interface_access, if_id, phy_access,
+		      phy_id, phy_type, reg_addr, data_value, OPERATION_WRITE));
+
+	return MV_OK;
+}
+
+/*
+ * Bus access routine (relevant for both read & write)
+ */
+static int ddr3_tip_bus_access(u32 dev_num, enum hws_access_type interface_access,
+			       u32 if_id, enum hws_access_type phy_access,
+			       u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+			       u32 data_value, enum hws_operation oper_type)
+{
+	u32 addr_low = 0x3f & reg_addr;
+	u32 addr_hi = ((0xc0 & reg_addr) >> 6);
+	u32 data_p1 =
+		(oper_type << 30) + (addr_hi << 28) + (phy_access << 27) +
+		(phy_type << 26) + (phy_id << 22) + (addr_low << 16) +
+		(data_value & 0xffff);
+	u32 data_p2 = data_p1 + (1 << 31);
+	u32 start_if, end_if;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, interface_access, if_id, PHY_REG_FILE_ACCESS,
+		      data_p1, MASK_ALL_BITS));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, interface_access, if_id, PHY_REG_FILE_ACCESS,
+		      data_p2, MASK_ALL_BITS));
+
+	if (interface_access == ACCESS_TYPE_UNICAST) {
+		start_if = if_id;
+		end_if = if_id;
+	} else {
+		start_if = 0;
+		end_if = MAX_INTERFACE_NUM - 1;
+	}
+
+	/* polling for read/write execution done */
+	for (if_id = start_if; if_id <= end_if; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(is_bus_access_done
+			     (dev_num, if_id, PHY_REG_FILE_ACCESS, 31));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Check bus access done
+ */
+static int is_bus_access_done(u32 dev_num, u32 if_id, u32 dunit_reg_adrr,
+			      u32 bit)
+{
+	u32 rd_data = 1;
+	u32 cnt = 0;
+	u32 data_read[MAX_INTERFACE_NUM];
+
+	CHECK_STATUS(ddr3_tip_if_read
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, dunit_reg_adrr,
+		      data_read, MASK_ALL_BITS));
+	rd_data = data_read[if_id];
+	rd_data &= (1 << bit);
+
+	while (rd_data != 0) {
+		if (cnt++ >= MAX_POLLING_ITERATIONS)
+			break;
+
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      dunit_reg_adrr, data_read, MASK_ALL_BITS));
+		rd_data = data_read[if_id];
+		rd_data &= (1 << bit);
+	}
+
+	if (cnt < MAX_POLLING_ITERATIONS)
+		return MV_OK;
+	else
+		return MV_FAIL;
+}
+
+/*
+ * Phy read-modify-write
+ */
+int ddr3_tip_bus_read_modify_write(u32 dev_num, enum hws_access_type access_type,
+				   u32 interface_id, u32 phy_id,
+				   enum hws_ddr_phy phy_type, u32 reg_addr,
+				   u32 data_value, u32 reg_mask)
+{
+	u32 data_val = 0, if_id, start_if, end_if;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (access_type == ACCESS_TYPE_MULTICAST) {
+		start_if = 0;
+		end_if = MAX_INTERFACE_NUM - 1;
+	} else {
+		start_if = interface_id;
+		end_if = interface_id;
+	}
+
+	for (if_id = start_if; if_id <= end_if; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(ddr3_tip_bus_read
+			     (dev_num, if_id, ACCESS_TYPE_UNICAST, phy_id,
+			      phy_type, reg_addr, &data_val));
+		data_value = (data_val & (~reg_mask)) | (data_value & reg_mask);
+		CHECK_STATUS(ddr3_tip_bus_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      ACCESS_TYPE_UNICAST, phy_id, phy_type, reg_addr,
+			      data_value));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * ADLL Calibration
+ */
+int adll_calibration(u32 dev_num, enum hws_access_type access_type,
+		     u32 if_id, enum hws_ddr_freq frequency)
+{
+	struct hws_tip_freq_config_info freq_config_info;
+	u32 bus_cnt = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* Reset Diver_b assert -> de-assert */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+		      0, 0x10000000));
+	mdelay(10);
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+		      0x10000000, 0x10000000));
+
+	if (config_func_info[dev_num].tip_get_freq_config_info_func != NULL) {
+		CHECK_STATUS(config_func_info[dev_num].
+			     tip_get_freq_config_info_func((u8)dev_num, frequency,
+							   &freq_config_info));
+	} else {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("tip_get_freq_config_info_func is NULL"));
+		return MV_NOT_INITIALIZED;
+	}
+
+	for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, access_type, if_id, bus_cnt,
+			      DDR_PHY_DATA, BW_PHY_REG,
+			      freq_config_info.bw_per_freq << 8, 0x700));
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, access_type, if_id, bus_cnt,
+			      DDR_PHY_DATA, RATE_PHY_REG,
+			      freq_config_info.rate_per_freq, 0x7));
+	}
+
+	/* DUnit to Phy drive post edge, ADLL reset assert de-assert */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, if_id, DRAM_PHY_CONFIGURATION,
+		      0, (0x80000000 | 0x40000000)));
+	mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ]));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, if_id, DRAM_PHY_CONFIGURATION,
+		      (0x80000000 | 0x40000000), (0x80000000 | 0x40000000)));
+
+	/* polling for ADLL Done */
+	if (ddr3_tip_if_polling(dev_num, access_type, if_id,
+				0x3ff03ff, 0x3ff03ff, PHY_LOCK_STATUS_REG,
+				MAX_POLLING_ITERATIONS) != MV_OK) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("Freq_set: DDR3 poll failed(1)"));
+	}
+
+	/* pup data_pup reset assert-> deassert */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+		      0, 0x60000000));
+	mdelay(10);
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG,
+		      0x60000000, 0x60000000));
+
+	return MV_OK;
+}
+
+int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type,
+		      u32 if_id, enum hws_ddr_freq frequency)
+{
+	u32 cl_value = 0, cwl_value = 0, mem_mask = 0, val = 0,
+		bus_cnt = 0, t_hclk = 0, t_wr = 0,
+		refresh_interval_cnt = 0, cnt_id;
+	u32 t_refi = 0, end_if, start_if;
+	u32 bus_index = 0;
+	int is_dll_off = 0;
+	enum hws_speed_bin speed_bin_index = 0;
+	struct hws_tip_freq_config_info freq_config_info;
+	enum hws_result *flow_result = training_result[training_stage];
+	u32 adll_tap = 0;
+	u32 cs_mask[MAX_INTERFACE_NUM];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+			  ("dev %d access %d IF %d freq %d\n", dev_num,
+			   access_type, if_id, frequency));
+
+	if (frequency == DDR_FREQ_LOW_FREQ)
+		is_dll_off = 1;
+	if (access_type == ACCESS_TYPE_MULTICAST) {
+		start_if = 0;
+		end_if = MAX_INTERFACE_NUM - 1;
+	} else {
+		start_if = if_id;
+		end_if = if_id;
+	}
+
+	/* calculate interface cs mask - Oferb 4/11 */
+	/* speed bin can be different for each interface */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		/* cs enable is active low */
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		cs_mask[if_id] = CS_BIT_MASK;
+		training_result[training_stage][if_id] = TEST_SUCCESS;
+		ddr3_tip_calc_cs_mask(dev_num, if_id, effective_cs,
+				      &cs_mask[if_id]);
+	}
+
+	/* speed bin can be different for each interface */
+	/*
+	 * moti b - need to remove the loop for multicas access functions
+	 * and loop the unicast access functions
+	 */
+	for (if_id = start_if; if_id <= end_if; if_id++) {
+		if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+			continue;
+
+		flow_result[if_id] = TEST_SUCCESS;
+		speed_bin_index =
+			tm->interface_params[if_id].speed_bin_index;
+		if (tm->interface_params[if_id].memory_freq ==
+		    frequency) {
+			cl_value =
+				tm->interface_params[if_id].cas_l;
+			cwl_value =
+				tm->interface_params[if_id].cas_wl;
+		} else {
+			cl_value =
+				cas_latency_table[speed_bin_index].cl_val[frequency];
+			cwl_value =
+				cas_write_latency_table[speed_bin_index].
+				cl_val[frequency];
+		}
+
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+				  ("Freq_set dev 0x%x access 0x%x if 0x%x freq 0x%x speed %d:\n\t",
+				   dev_num, access_type, if_id,
+				   frequency, speed_bin_index));
+
+		for (cnt_id = 0; cnt_id < DDR_FREQ_LIMIT; cnt_id++) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE,
+					  ("%d ",
+					   cas_latency_table[speed_bin_index].
+					   cl_val[cnt_id]));
+		}
+
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("\n"));
+		mem_mask = 0;
+		for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+		     bus_index++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+			mem_mask |=
+				tm->interface_params[if_id].
+				as_bus_params[bus_index].mirror_enable_bitmask;
+		}
+
+		if (mem_mask != 0) {
+			/* motib redundent in KW28 */
+			CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+						       if_id,
+						       CS_ENABLE_REG, 0, 0x8));
+		}
+
+		/* dll state after exiting SR */
+		if (is_dll_off == 1) {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DFS_REG, 0x1, 0x1));
+		} else {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      DFS_REG, 0, 0x1));
+		}
+
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      DUNIT_MMASK_REG, 0, 0x1));
+		/* DFS  - block  transactions */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      DFS_REG, 0x2, 0x2));
+
+		/* disable ODT in case of dll off */
+		if (is_dll_off == 1) {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      0x1874, 0, 0x244));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      0x1884, 0, 0x244));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      0x1894, 0, 0x244));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id,
+				      0x18a4, 0, 0x244));
+		}
+
+		/* DFS  - Enter Self-Refresh */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, DFS_REG, 0x4,
+			      0x4));
+		/* polling on self refresh entry */
+		if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST,
+					if_id, 0x8, 0x8, DFS_REG,
+					MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("Freq_set: DDR3 poll failed on SR entry\n"));
+		}
+
+		/* PLL configuration */
+		if (config_func_info[dev_num].tip_set_freq_divider_func != NULL) {
+			config_func_info[dev_num].
+				tip_set_freq_divider_func(dev_num, if_id,
+							  frequency);
+		}
+
+		/* PLL configuration End */
+
+		/* adjust t_refi to new frequency */
+		t_refi = (tm->interface_params[if_id].interface_temp ==
+			  HWS_TEMP_HIGH) ? TREFI_LOW : TREFI_HIGH;
+		t_refi *= 1000;	/*psec */
+
+		/* HCLK in[ps] */
+		t_hclk = MEGA / (freq_val[frequency] / 2);
+		refresh_interval_cnt = t_refi / t_hclk;	/* no units */
+		val = 0x4000 | refresh_interval_cnt;
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      SDRAM_CONFIGURATION_REG, val, 0x7fff));
+
+		/* DFS  - CL/CWL/WR parameters after exiting SR */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, DFS_REG,
+			      (cl_mask_table[cl_value] << 8), 0xf00));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, DFS_REG,
+			      (cwl_mask_table[cwl_value] << 12), 0x7000));
+		t_wr = speed_bin_table(speed_bin_index, SPEED_BIN_TWR);
+		t_wr = (t_wr / 1000);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, DFS_REG,
+			      (twr_mask_table[t_wr + 1] << 16), 0x70000));
+
+		/* Restore original RTT values if returning from DLL OFF mode */
+		if (is_dll_off == 1) {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id, 0x1874,
+				      g_dic | g_rtt_nom, 0x266));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id, 0x1884,
+				      g_dic | g_rtt_nom, 0x266));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id, 0x1894,
+				      g_dic | g_rtt_nom, 0x266));
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, if_id, 0x18a4,
+				      g_dic | g_rtt_nom, 0x266));
+		}
+
+		/* Reset Diver_b assert -> de-assert */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      SDRAM_CONFIGURATION_REG, 0, 0x10000000));
+		mdelay(10);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      SDRAM_CONFIGURATION_REG, 0x10000000, 0x10000000));
+
+		/* Adll configuration function of process and Frequency */
+		if (config_func_info[dev_num].tip_get_freq_config_info_func != NULL) {
+			CHECK_STATUS(config_func_info[dev_num].
+				     tip_get_freq_config_info_func(dev_num, frequency,
+								   &freq_config_info));
+		}
+		/* TBD check milo5 using device ID ? */
+		for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+		     bus_cnt++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+			CHECK_STATUS(ddr3_tip_bus_read_modify_write
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id, bus_cnt, DDR_PHY_DATA,
+				      0x92,
+				      freq_config_info.
+				      bw_per_freq << 8
+				      /*freq_mask[dev_num][frequency] << 8 */
+				      , 0x700));
+			CHECK_STATUS(ddr3_tip_bus_read_modify_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      bus_cnt, DDR_PHY_DATA, 0x94,
+				      freq_config_info.rate_per_freq, 0x7));
+		}
+
+		/* DUnit to Phy drive post edge, ADLL reset assert de-assert */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      DRAM_PHY_CONFIGURATION, 0,
+			      (0x80000000 | 0x40000000)));
+		mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ]));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      DRAM_PHY_CONFIGURATION, (0x80000000 | 0x40000000),
+			      (0x80000000 | 0x40000000)));
+
+		/* polling for ADLL Done */
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x3ff03ff,
+		     0x3ff03ff, PHY_LOCK_STATUS_REG,
+		     MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("Freq_set: DDR3 poll failed(1)\n"));
+		}
+
+		/* pup data_pup reset assert-> deassert */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      SDRAM_CONFIGURATION_REG, 0, 0x60000000));
+		mdelay(10);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      SDRAM_CONFIGURATION_REG, 0x60000000, 0x60000000));
+
+		/* Set proper timing params before existing Self-Refresh */
+		ddr3_tip_set_timing(dev_num, access_type, if_id, frequency);
+		if (delay_enable != 0) {
+			adll_tap = MEGA / (freq_val[frequency] * 64);
+			ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap);
+		}
+
+		/* Exit SR */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, DFS_REG, 0,
+			      0x4));
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x8, DFS_REG,
+		     MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("Freq_set: DDR3 poll failed(2)"));
+		}
+
+		/* Refresh Command */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      SDRAM_OPERATION_REG, 0x2, 0xf1f));
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f,
+		     SDRAM_OPERATION_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("Freq_set: DDR3 poll failed(3)"));
+		}
+
+		/* Release DFS Block */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, DFS_REG, 0,
+			      0x2));
+		/* Controller to MBUS Retry - normal */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, DUNIT_MMASK_REG,
+			      0x1, 0x1));
+
+		/* MRO: Burst Length 8, CL , Auto_precharge 0x16cc */
+		val =
+			((cl_mask_table[cl_value] & 0x1) << 2) |
+			((cl_mask_table[cl_value] & 0xe) << 3);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id, MR0_REG,
+			      val, (0x7 << 4) | (1 << 2)));
+		/* MR2:  CWL = 10 , Auto Self-Refresh - disable */
+		val = (cwl_mask_table[cwl_value] << 3);
+		/*
+		 * nklein 24.10.13 - should not be here - leave value as set in
+		 * the init configuration val |= (1 << 9);
+		 * val |= ((tm->interface_params[if_id].
+		 * interface_temp == HWS_TEMP_HIGH) ? (1 << 7) : 0);
+		 */
+		/* nklein 24.10.13 - see above comment */
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+					       if_id, MR2_REG,
+					       val, (0x7 << 3)));
+
+		/* ODT TIMING */
+		val = ((cl_value - cwl_value + 1) << 4) |
+			((cl_value - cwl_value + 6) << 8) |
+			((cl_value - 1) << 12) | ((cl_value + 6) << 16);
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+					       if_id, ODT_TIMING_LOW,
+					       val, 0xffff0));
+		val = 0x71 | ((cwl_value - 1) << 8) | ((cwl_value + 5) << 12);
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+					       if_id, ODT_TIMING_HI_REG,
+					       val, 0xffff));
+
+		/* ODT Active */
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+					       if_id,
+					       DUNIT_ODT_CONTROL_REG,
+					       0xf, 0xf));
+
+		/* re-write CL */
+		val = ((cl_mask_table[cl_value] & 0x1) << 2) |
+			((cl_mask_table[cl_value] & 0xe) << 3);
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+					       0, MR0_REG, val,
+					       (0x7 << 4) | (1 << 2)));
+
+		/* re-write CWL */
+		val = (cwl_mask_table[cwl_value] << 3);
+		CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask, MRS2_CMD,
+						    val, (0x7 << 3)));
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+					       0, MR2_REG, val, (0x7 << 3)));
+
+		if (mem_mask != 0) {
+			CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+						       if_id,
+						       CS_ENABLE_REG,
+						       1 << 3, 0x8));
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Set ODT values
+ */
+static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type,
+			      u32 if_id, u32 cl_value, u32 cwl_value)
+{
+	/* ODT TIMING */
+	u32 val = (cl_value - cwl_value + 6);
+
+	val = ((cl_value - cwl_value + 1) << 4) | ((val & 0xf) << 8) |
+		(((cl_value - 1) & 0xf) << 12) |
+		(((cl_value + 6) & 0xf) << 16) | (((val & 0x10) >> 4) << 21);
+	val |= (((cl_value - 1) >> 4) << 22) | (((cl_value + 6) >> 4) << 23);
+
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       ODT_TIMING_LOW, val, 0xffff0));
+	val = 0x71 | ((cwl_value - 1) << 8) | ((cwl_value + 5) << 12);
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       ODT_TIMING_HI_REG, val, 0xffff));
+	if (odt_additional == 1) {
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type,
+					       if_id,
+					       SDRAM_ODT_CONTROL_HIGH_REG,
+					       0xf, 0xf));
+	}
+
+	/* ODT Active */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       DUNIT_ODT_CONTROL_REG, 0xf, 0xf));
+
+	return MV_OK;
+}
+
+/*
+ * Set Timing values for training
+ */
+static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type,
+			       u32 if_id, enum hws_ddr_freq frequency)
+{
+	u32 t_ckclk = 0, t_ras = 0;
+	u32 t_rcd = 0, t_rp = 0, t_wr = 0, t_wtr = 0, t_rrd = 0, t_rtp = 0,
+		t_rfc = 0, t_mod = 0;
+	u32 val = 0, page_size = 0;
+	enum hws_speed_bin speed_bin_index;
+	enum hws_mem_size memory_size = MEM_2G;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	speed_bin_index = tm->interface_params[if_id].speed_bin_index;
+	memory_size = tm->interface_params[if_id].memory_size;
+	page_size =
+		(tm->interface_params[if_id].bus_width ==
+		 BUS_WIDTH_8) ? page_param[memory_size].
+		page_size_8bit : page_param[memory_size].page_size_16bit;
+	t_ckclk = (MEGA / freq_val[frequency]);
+	t_rrd =	(page_size == 1) ? speed_bin_table(speed_bin_index,
+						   SPEED_BIN_TRRD1K) :
+		speed_bin_table(speed_bin_index, SPEED_BIN_TRRD2K);
+	t_rrd = GET_MAX_VALUE(t_ckclk * 4, t_rrd);
+	t_rtp =	GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index,
+							   SPEED_BIN_TRTP));
+	t_wtr = GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index,
+							   SPEED_BIN_TWTR));
+	t_ras = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+						    SPEED_BIN_TRAS),
+				    t_ckclk);
+	t_rcd = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+						    SPEED_BIN_TRCD),
+				    t_ckclk);
+	t_rp = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+						   SPEED_BIN_TRP),
+				   t_ckclk);
+	t_wr = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index,
+						   SPEED_BIN_TWR),
+				   t_ckclk);
+	t_wtr = TIME_2_CLOCK_CYCLES(t_wtr, t_ckclk);
+	t_rrd = TIME_2_CLOCK_CYCLES(t_rrd, t_ckclk);
+	t_rtp = TIME_2_CLOCK_CYCLES(t_rtp, t_ckclk);
+	t_rfc = TIME_2_CLOCK_CYCLES(rfc_table[memory_size] * 1000, t_ckclk);
+	t_mod = GET_MAX_VALUE(t_ckclk * 24, 15000);
+	t_mod = TIME_2_CLOCK_CYCLES(t_mod, t_ckclk);
+
+	/* SDRAM Timing Low */
+	val = (t_ras & 0xf) | (t_rcd << 4) | (t_rp << 8) | (t_wr << 12) |
+		(t_wtr << 16) | (((t_ras & 0x30) >> 4) << 20) | (t_rrd << 24) |
+		(t_rtp << 28);
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_LOW_REG, val, 0xff3fffff));
+
+	/* SDRAM Timing High */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       t_rfc & 0x7f, 0x7f));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       0x180, 0x180));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       0x600, 0x600));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       0x1800, 0xf800));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       ((t_rfc & 0x380) >> 7) << 16, 0x70000));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG, 0,
+				       0x380000));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       (t_mod & 0xf) << 25, 0x1e00000));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       (t_mod >> 4) << 30, 0xc0000000));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       0x16000000, 0x1e000000));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       SDRAM_TIMING_HIGH_REG,
+				       0x40000000, 0xc0000000));
+
+	return MV_OK;
+}
+
+/*
+ * Mode Read
+ */
+int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info)
+{
+	u32 ret;
+
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			       MR0_REG, mode_info->reg_mr0, MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			       MR1_REG, mode_info->reg_mr1, MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			       MR2_REG, mode_info->reg_mr2, MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			       MR3_REG, mode_info->reg_mr2, MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			       READ_DATA_SAMPLE_DELAY, mode_info->read_data_sample,
+			       MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			       READ_DATA_READY_DELAY, mode_info->read_data_ready,
+			       MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+
+	return MV_OK;
+}
+
+/*
+ * Get first active IF
+ */
+int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask,
+				 u32 *interface_id)
+{
+	u32 if_id;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (interface_mask & (1 << if_id)) {
+			*interface_id = if_id;
+			break;
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Write CS Result
+ */
+int ddr3_tip_write_cs_result(u32 dev_num, u32 offset)
+{
+	u32 if_id, bus_num, cs_bitmask, data_val, cs_num;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_num = 0; bus_num < tm->num_of_bus_per_interface;
+		     bus_num++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+			cs_bitmask =
+				tm->interface_params[if_id].
+				as_bus_params[bus_num].cs_bitmask;
+			if (cs_bitmask != effective_cs) {
+				cs_num = GET_CS_FROM_MASK(cs_bitmask);
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, bus_num,
+						  DDR_PHY_DATA,
+						  offset +
+						  CS_REG_VALUE(effective_cs),
+						  &data_val);
+				ddr3_tip_bus_write(dev_num,
+						   ACCESS_TYPE_UNICAST,
+						   if_id,
+						   ACCESS_TYPE_UNICAST,
+						   bus_num, DDR_PHY_DATA,
+						   offset +
+						   CS_REG_VALUE(cs_num),
+						   data_val);
+			}
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Write MRS
+ */
+int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, u32 cmd,
+			   u32 data, u32 mask)
+{
+	u32 if_id, reg;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	reg = (cmd == MRS1_CMD) ? MR1_REG : MR2_REG;
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       PARAM_NOT_CARE, reg, data, mask));
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      SDRAM_OPERATION_REG,
+			      (cs_mask_arr[if_id] << 8) | cmd, 0xf1f));
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+					0x1f, SDRAM_OPERATION_REG,
+					MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("write_mrs_cmd: Poll cmd fail"));
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Reset XSB Read FIFO
+ */
+int ddr3_tip_reset_fifo_ptr(u32 dev_num)
+{
+	u32 if_id = 0;
+
+	/* Configure PHY reset value to 0 in order to "clean" the FIFO */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       if_id, 0x15c8, 0, 0xff000000));
+	/*
+	 * Move PHY to RL mode (only in RL mode the PHY overrides FIFO values
+	 * during FIFO reset)
+	 */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       if_id, TRAINING_SW_2_REG,
+				       0x1, 0x9));
+	/* In order that above configuration will influence the PHY */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       if_id, 0x15b0,
+				       0x80000000, 0x80000000));
+	/* Reset read fifo assertion */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       if_id, 0x1400, 0, 0x40000000));
+	/* Reset read fifo deassertion */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       if_id, 0x1400,
+				       0x40000000, 0x40000000));
+	/* Move PHY back to functional mode */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       if_id, TRAINING_SW_2_REG,
+				       0x8, 0x9));
+	/* Stop training machine */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       if_id, 0x15b4, 0x10000, 0x10000));
+
+	return MV_OK;
+}
+
+/*
+ * Reset Phy registers
+ */
+int ddr3_tip_ddr3_reset_phy_regs(u32 dev_num)
+{
+	u32 if_id, phy_id, cs;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (phy_id = 0; phy_id < tm->num_of_bus_per_interface;
+		     phy_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, phy_id);
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id, ACCESS_TYPE_UNICAST,
+				      phy_id, DDR_PHY_DATA,
+				      WL_PHY_REG +
+				      CS_REG_VALUE(effective_cs),
+				      phy_reg0_val));
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA,
+				      RL_PHY_REG + CS_REG_VALUE(effective_cs),
+				      phy_reg2_val));
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA,
+				      READ_CENTRALIZATION_PHY_REG +
+				      CS_REG_VALUE(effective_cs), phy_reg3_val));
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA,
+				      WRITE_CENTRALIZATION_PHY_REG +
+				      CS_REG_VALUE(effective_cs), phy_reg3_val));
+		}
+	}
+
+	/* Set Receiver Calibration value */
+	for (cs = 0; cs < MAX_CS_NUM; cs++) {
+		/* PHY register 0xdb bits[5:0] - configure to 63 */
+		CHECK_STATUS(ddr3_tip_bus_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      DDR_PHY_DATA, CSN_IOB_VREF_REG(cs), 63));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Restore Dunit registers
+ */
+int ddr3_tip_restore_dunit_regs(u32 dev_num)
+{
+	u32 index_cnt;
+
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       PARAM_NOT_CARE, CALIB_MACHINE_CTRL_REG,
+				       0x1, 0x1));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       PARAM_NOT_CARE, CALIB_MACHINE_CTRL_REG,
+				       calibration_update_control << 3,
+				       0x3 << 3));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST,
+				       PARAM_NOT_CARE,
+				       ODPG_WRITE_READ_MODE_ENABLE_REG,
+				       0xffff, MASK_ALL_BITS));
+
+	for (index_cnt = 0; index_cnt < ARRAY_SIZE(odpg_default_value);
+	     index_cnt++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      odpg_default_value[index_cnt].reg_addr,
+			      odpg_default_value[index_cnt].reg_data,
+			      odpg_default_value[index_cnt].reg_mask));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Auto tune main flow
+ */
+static int ddr3_tip_ddr3_training_main_flow(u32 dev_num)
+{
+	enum hws_ddr_freq freq = init_freq;
+	struct init_cntr_param init_cntr_prm;
+	int ret = MV_OK;
+	u32 if_id;
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+	if (debug_training == DEBUG_LEVEL_TRACE) {
+		CHECK_STATUS(print_device_info((u8)dev_num));
+	}
+#endif
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		CHECK_STATUS(ddr3_tip_ddr3_reset_phy_regs(dev_num));
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	freq = init_freq;
+	if (is_pll_before_init != 0) {
+		for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			config_func_info[dev_num].tip_set_freq_divider_func(
+				(u8)dev_num, if_id, freq);
+		}
+	}
+
+	if (is_adll_calib_before_init != 0) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("with adll calib before init\n"));
+		adll_calibration(dev_num, ACCESS_TYPE_MULTICAST, 0, freq);
+	}
+
+	if (is_reg_dump != 0) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("Dump before init controller\n"));
+		ddr3_tip_reg_dump(dev_num);
+	}
+
+	if (mask_tune_func & INIT_CONTROLLER_MASK_BIT) {
+		training_stage = INIT_CONTROLLER;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("INIT_CONTROLLER_MASK_BIT\n"));
+		init_cntr_prm.do_mrs_phy = 1;
+		init_cntr_prm.is_ctrl64_bit = 0;
+		init_cntr_prm.init_phy = 1;
+		init_cntr_prm.msys_init = 0;
+		ret = hws_ddr3_tip_init_controller(dev_num, &init_cntr_prm);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("hws_ddr3_tip_init_controller failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+#ifdef STATIC_ALGO_SUPPORT
+	if (mask_tune_func & STATIC_LEVELING_MASK_BIT) {
+		training_stage = STATIC_LEVELING;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("STATIC_LEVELING_MASK_BIT\n"));
+		ret = ddr3_tip_run_static_alg(dev_num, freq);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_run_static_alg failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+#endif
+
+	if (mask_tune_func & SET_LOW_FREQ_MASK_BIT) {
+		training_stage = SET_LOW_FREQ;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("SET_LOW_FREQ_MASK_BIT %d\n",
+				   freq_val[low_freq]));
+		ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST,
+					PARAM_NOT_CARE, low_freq);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_freq_set failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & LOAD_PATTERN_MASK_BIT) {
+			training_stage = LOAD_PATTERN;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("LOAD_PATTERN_MASK_BIT #%d\n",
+					   effective_cs));
+			ret = ddr3_tip_load_all_pattern_to_mem(dev_num);
+			if (is_reg_dump != 0)
+				ddr3_tip_reg_dump(dev_num);
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_load_all_pattern_to_mem failure CS #%d\n",
+						   effective_cs));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	if (mask_tune_func & SET_MEDIUM_FREQ_MASK_BIT) {
+		training_stage = SET_MEDIUM_FREQ;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("SET_MEDIUM_FREQ_MASK_BIT %d\n",
+				   freq_val[medium_freq]));
+		ret =
+			ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST,
+					  PARAM_NOT_CARE, medium_freq);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_freq_set failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	if (mask_tune_func & WRITE_LEVELING_MASK_BIT) {
+		training_stage = WRITE_LEVELING;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("WRITE_LEVELING_MASK_BIT\n"));
+		if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) {
+			ret = ddr3_tip_dynamic_write_leveling(dev_num);
+		} else {
+			/* Use old WL */
+			ret = ddr3_tip_legacy_dynamic_write_leveling(dev_num);
+		}
+
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_dynamic_write_leveling failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & LOAD_PATTERN_2_MASK_BIT) {
+			training_stage = LOAD_PATTERN_2;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("LOAD_PATTERN_2_MASK_BIT CS #%d\n",
+					   effective_cs));
+			ret = ddr3_tip_load_all_pattern_to_mem(dev_num);
+			if (is_reg_dump != 0)
+				ddr3_tip_reg_dump(dev_num);
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_load_all_pattern_to_mem failure CS #%d\n",
+						   effective_cs));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	if (mask_tune_func & READ_LEVELING_MASK_BIT) {
+		training_stage = READ_LEVELING;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("READ_LEVELING_MASK_BIT\n"));
+		if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) {
+			ret = ddr3_tip_dynamic_read_leveling(dev_num, medium_freq);
+		} else {
+			/* Use old RL */
+			ret = ddr3_tip_legacy_dynamic_read_leveling(dev_num);
+		}
+
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_dynamic_read_leveling failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	if (mask_tune_func & WRITE_LEVELING_SUPP_MASK_BIT) {
+		training_stage = WRITE_LEVELING_SUPP;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("WRITE_LEVELING_SUPP_MASK_BIT\n"));
+		ret = ddr3_tip_dynamic_write_leveling_supp(dev_num);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_dynamic_write_leveling_supp failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & PBS_RX_MASK_BIT) {
+			training_stage = PBS_RX;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("PBS_RX_MASK_BIT CS #%d\n",
+					   effective_cs));
+			ret = ddr3_tip_pbs_rx(dev_num);
+			if (is_reg_dump != 0)
+				ddr3_tip_reg_dump(dev_num);
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_pbs_rx failure CS #%d\n",
+						   effective_cs));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & PBS_TX_MASK_BIT) {
+			training_stage = PBS_TX;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("PBS_TX_MASK_BIT CS #%d\n",
+					   effective_cs));
+			ret = ddr3_tip_pbs_tx(dev_num);
+			if (is_reg_dump != 0)
+				ddr3_tip_reg_dump(dev_num);
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_pbs_tx failure CS #%d\n",
+						   effective_cs));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	if (mask_tune_func & SET_TARGET_FREQ_MASK_BIT) {
+		training_stage = SET_TARGET_FREQ;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("SET_TARGET_FREQ_MASK_BIT %d\n",
+				   freq_val[tm->
+					    interface_params[first_active_if].
+					    memory_freq]));
+		ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST,
+					PARAM_NOT_CARE,
+					tm->interface_params[first_active_if].
+					memory_freq);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_freq_set failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	if (mask_tune_func & WRITE_LEVELING_TF_MASK_BIT) {
+		training_stage = WRITE_LEVELING_TF;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("WRITE_LEVELING_TF_MASK_BIT\n"));
+		ret = ddr3_tip_dynamic_write_leveling(dev_num);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_dynamic_write_leveling TF failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	if (mask_tune_func & LOAD_PATTERN_HIGH_MASK_BIT) {
+		training_stage = LOAD_PATTERN_HIGH;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("LOAD_PATTERN_HIGH\n"));
+		ret = ddr3_tip_load_all_pattern_to_mem(dev_num);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_load_all_pattern_to_mem failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	if (mask_tune_func & READ_LEVELING_TF_MASK_BIT) {
+		training_stage = READ_LEVELING_TF;
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+				  ("READ_LEVELING_TF_MASK_BIT\n"));
+		ret = ddr3_tip_dynamic_read_leveling(dev_num, tm->
+						     interface_params[first_active_if].
+						     memory_freq);
+		if (is_reg_dump != 0)
+			ddr3_tip_reg_dump(dev_num);
+		if (ret != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("ddr3_tip_dynamic_read_leveling TF failure\n"));
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+
+	if (mask_tune_func & DM_PBS_TX_MASK_BIT) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("DM_PBS_TX_MASK_BIT\n"));
+	}
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & VREF_CALIBRATION_MASK_BIT) {
+			training_stage = VREF_CALIBRATION;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("VREF\n"));
+			ret = ddr3_tip_vref(dev_num);
+			if (is_reg_dump != 0) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("VREF Dump\n"));
+				ddr3_tip_reg_dump(dev_num);
+			}
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_vref failure\n"));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & CENTRALIZATION_RX_MASK_BIT) {
+			training_stage = CENTRALIZATION_RX;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("CENTRALIZATION_RX_MASK_BIT CS #%d\n",
+					   effective_cs));
+			ret = ddr3_tip_centralization_rx(dev_num);
+			if (is_reg_dump != 0)
+				ddr3_tip_reg_dump(dev_num);
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_centralization_rx failure CS #%d\n",
+						   effective_cs));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & WRITE_LEVELING_SUPP_TF_MASK_BIT) {
+			training_stage = WRITE_LEVELING_SUPP_TF;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("WRITE_LEVELING_SUPP_TF_MASK_BIT CS #%d\n",
+					   effective_cs));
+			ret = ddr3_tip_dynamic_write_leveling_supp(dev_num);
+			if (is_reg_dump != 0)
+				ddr3_tip_reg_dump(dev_num);
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_dynamic_write_leveling_supp TF failure CS #%d\n",
+						   effective_cs));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		if (mask_tune_func & CENTRALIZATION_TX_MASK_BIT) {
+			training_stage = CENTRALIZATION_TX;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("CENTRALIZATION_TX_MASK_BIT CS #%d\n",
+					   effective_cs));
+			ret = ddr3_tip_centralization_tx(dev_num);
+			if (is_reg_dump != 0)
+				ddr3_tip_reg_dump(dev_num);
+			if (ret != MV_OK) {
+				DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+						  ("ddr3_tip_centralization_tx failure CS #%d\n",
+						   effective_cs));
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("restore registers to default\n"));
+	/* restore register values */
+	CHECK_STATUS(ddr3_tip_restore_dunit_regs(dev_num));
+
+	if (is_reg_dump != 0)
+		ddr3_tip_reg_dump(dev_num);
+
+	return MV_OK;
+}
+
+/*
+ * DDR3 Dynamic training flow
+ */
+static int ddr3_tip_ddr3_auto_tune(u32 dev_num)
+{
+	u32 if_id, stage, ret;
+	int is_if_fail = 0, is_auto_tune_fail = 0;
+
+	training_stage = INIT_CONTROLLER;
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		for (stage = 0; stage < MAX_STAGE_LIMIT; stage++)
+			training_result[stage][if_id] = NO_TEST_DONE;
+	}
+
+	ret = ddr3_tip_ddr3_training_main_flow(dev_num);
+
+	/* activate XSB test */
+	if (xsb_validate_type != 0) {
+		run_xsb_test(dev_num, xsb_validation_base_address, 1, 1,
+			     0x1024);
+	}
+
+	if (is_reg_dump != 0)
+		ddr3_tip_reg_dump(dev_num);
+
+	/* print log */
+	CHECK_STATUS(ddr3_tip_print_log(dev_num, window_mem_addr));
+
+	if (ret != MV_OK) {
+		CHECK_STATUS(ddr3_tip_print_stability_log(dev_num));
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		is_if_fail = 0;
+		for (stage = 0; stage < MAX_STAGE_LIMIT; stage++) {
+			if (training_result[stage][if_id] == TEST_FAILED)
+				is_if_fail = 1;
+		}
+		if (is_if_fail == 1) {
+			is_auto_tune_fail = 1;
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO,
+					  ("Auto Tune failed for IF %d\n",
+					   if_id));
+		}
+	}
+
+	if ((ret == MV_FAIL) || (is_auto_tune_fail == 1))
+		return MV_FAIL;
+	else
+		return MV_OK;
+}
+
+/*
+ * Enable init sequence
+ */
+int ddr3_tip_enable_init_sequence(u32 dev_num)
+{
+	int is_fail = 0;
+	u32 if_id = 0, mem_mask = 0, bus_index = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* Enable init sequence */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, 0,
+				       SDRAM_INIT_CONTROL_REG, 0x1, 0x1));
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1,
+		     SDRAM_INIT_CONTROL_REG,
+		     MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("polling failed IF %d\n",
+					   if_id));
+			is_fail = 1;
+			continue;
+		}
+
+		mem_mask = 0;
+		for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES();
+		     bus_index++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+			mem_mask |=
+				tm->interface_params[if_id].
+				as_bus_params[bus_index].mirror_enable_bitmask;
+		}
+
+		if (mem_mask != 0) {
+			/* Disable Multi CS */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, ACCESS_TYPE_MULTICAST,
+				      if_id, CS_ENABLE_REG, 1 << 3,
+				      1 << 3));
+		}
+	}
+
+	return (is_fail == 0) ? MV_OK : MV_FAIL;
+}
+
+int ddr3_tip_register_dq_table(u32 dev_num, u32 *table)
+{
+	dq_map_table = table;
+
+	return MV_OK;
+}
+
+/*
+ * Check if pup search is locked
+ */
+int ddr3_tip_is_pup_lock(u32 *pup_buf, enum hws_training_result read_mode)
+{
+	u32 bit_start = 0, bit_end = 0, bit_id;
+
+	if (read_mode == RESULT_PER_BIT) {
+		bit_start = 0;
+		bit_end = BUS_WIDTH_IN_BITS - 1;
+	} else {
+		bit_start = 0;
+		bit_end = 0;
+	}
+
+	for (bit_id = bit_start; bit_id <= bit_end; bit_id++) {
+		if (GET_LOCK_RESULT(pup_buf[bit_id]) == 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Get minimum buffer value
+ */
+u8 ddr3_tip_get_buf_min(u8 *buf_ptr)
+{
+	u8 min_val = 0xff;
+	u8 cnt = 0;
+
+	for (cnt = 0; cnt < BUS_WIDTH_IN_BITS; cnt++) {
+		if (buf_ptr[cnt] < min_val)
+			min_val = buf_ptr[cnt];
+	}
+
+	return min_val;
+}
+
+/*
+ * Get maximum buffer value
+ */
+u8 ddr3_tip_get_buf_max(u8 *buf_ptr)
+{
+	u8 max_val = 0;
+	u8 cnt = 0;
+
+	for (cnt = 0; cnt < BUS_WIDTH_IN_BITS; cnt++) {
+		if (buf_ptr[cnt] > max_val)
+			max_val = buf_ptr[cnt];
+	}
+
+	return max_val;
+}
+
+/*
+ * The following functions return memory parameters:
+ * bus and device width, device size
+ */
+
+u32 hws_ddr3_get_bus_width(void)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	return (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) ==
+		1) ? 16 : 32;
+}
+
+u32 hws_ddr3_get_device_width(u32 if_id)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	return (tm->interface_params[if_id].bus_width ==
+		BUS_WIDTH_8) ? 8 : 16;
+}
+
+u32 hws_ddr3_get_device_size(u32 if_id)
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (tm->interface_params[if_id].memory_size >=
+	    MEM_SIZE_LAST) {
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("Error: Wrong device size of Cs: %d",
+				   tm->interface_params[if_id].memory_size));
+		return 0;
+	} else {
+		return 1 << tm->interface_params[if_id].memory_size;
+	}
+}
+
+int hws_ddr3_calc_mem_cs_size(u32 if_id, u32 cs, u32 *cs_size)
+{
+	u32 cs_mem_size, dev_size;
+
+	dev_size = hws_ddr3_get_device_size(if_id);
+	if (dev_size != 0) {
+		cs_mem_size = ((hws_ddr3_get_bus_width() /
+				hws_ddr3_get_device_width(if_id)) * dev_size);
+
+		/* the calculated result in Gbytex16 to avoid float using */
+
+		if (cs_mem_size == 2) {
+			*cs_size = _128M;
+		} else if (cs_mem_size == 4) {
+			*cs_size = _256M;
+		} else if (cs_mem_size == 8) {
+			*cs_size = _512M;
+		} else if (cs_mem_size == 16) {
+			*cs_size = _1G;
+		} else if (cs_mem_size == 32) {
+			*cs_size = _2G;
+		} else {
+			DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+					  ("Error: Wrong Memory size of Cs: %d", cs));
+			return MV_FAIL;
+		}
+		return MV_OK;
+	} else {
+		return MV_FAIL;
+	}
+}
+
+int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr)
+{
+	u32 cs_mem_size = 0;
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+	u32 physical_mem_size;
+	u32 max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE;
+#endif
+
+	if (hws_ddr3_calc_mem_cs_size(if_id, cs, &cs_mem_size) != MV_OK)
+		return MV_FAIL;
+
+#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+	/*
+	 * if number of address pins doesn't allow to use max mem size that
+	 * is defined in topology mem size is defined by
+	 * DEVICE_MAX_DRAM_ADDRESS_SIZE
+	 */
+	physical_mem_size =
+		mv_hwsmem_size[tm->interface_params[0].memory_size];
+
+	if (hws_ddr3_get_device_width(cs) == 16) {
+		/*
+		 * 16bit mem device can be twice more - no need in less
+		 * significant pin
+		 */
+		max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE * 2;
+	}
+
+	if (physical_mem_size > max_mem_size) {
+		cs_mem_size = max_mem_size *
+			(hws_ddr3_get_bus_width() /
+			 hws_ddr3_get_device_width(if_id));
+		DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR,
+				  ("Updated Physical Mem size is from 0x%x to %x\n",
+				   physical_mem_size,
+				   DEVICE_MAX_DRAM_ADDRESS_SIZE));
+	}
+#endif
+
+	/* calculate CS base addr */
+	*cs_base_addr = ((cs_mem_size) * cs) & 0xffff0000;
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_bist.c b/drivers/ddr/marvell/a38x/ddr3_training_bist.c
new file mode 100644
index 0000000..bd0e260
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_bist.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+static u32 bist_offset = 32;
+enum hws_pattern sweep_pattern = PATTERN_KILLER_DQ0;
+
+static int ddr3_tip_bist_operation(u32 dev_num,
+				   enum hws_access_type access_type,
+				   u32 if_id,
+				   enum hws_bist_operation oper_type);
+
+/*
+ * BIST activate
+ */
+int ddr3_tip_bist_activate(u32 dev_num, enum hws_pattern pattern,
+			   enum hws_access_type access_type, u32 if_num,
+			   enum hws_dir direction,
+			   enum hws_stress_jump addr_stress_jump,
+			   enum hws_pattern_duration duration,
+			   enum hws_bist_operation oper_type,
+			   u32 offset, u32 cs_num, u32 pattern_addr_length)
+{
+	u32 tx_burst_size;
+	u32 delay_between_burst;
+	u32 rd_mode, val;
+	u32 poll_cnt = 0, max_poll = 1000, i, start_if, end_if;
+	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+	u32 read_data[MAX_INTERFACE_NUM];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* ODPG Write enable from BIST */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+				       ODPG_DATA_CONTROL_REG, 0x1, 0x1));
+	/* ODPG Read enable/disable from BIST */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+				       ODPG_DATA_CONTROL_REG,
+				       (direction == OPER_READ) ?
+				       0x2 : 0, 0x2));
+	CHECK_STATUS(ddr3_tip_load_pattern_to_odpg(dev_num, access_type, if_num,
+						   pattern, offset));
+
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+				       ODPG_DATA_BUF_SIZE_REG,
+				       pattern_addr_length, MASK_ALL_BITS));
+	tx_burst_size = (direction == OPER_WRITE) ?
+		pattern_table[pattern].tx_burst_size : 0;
+	delay_between_burst = (direction == OPER_WRITE) ? 2 : 0;
+	rd_mode = (direction == OPER_WRITE) ? 1 : 0;
+	CHECK_STATUS(ddr3_tip_configure_odpg
+		     (dev_num, access_type, if_num, direction,
+		      pattern_table[pattern].num_of_phases_tx, tx_burst_size,
+		      pattern_table[pattern].num_of_phases_rx,
+		      delay_between_burst,
+		      rd_mode, cs_num, addr_stress_jump, duration));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+				       ODPG_PATTERN_ADDR_OFFSET_REG,
+				       offset, MASK_ALL_BITS));
+	if (oper_type == BIST_STOP) {
+		CHECK_STATUS(ddr3_tip_bist_operation(dev_num, access_type,
+						     if_num, BIST_STOP));
+	} else {
+		CHECK_STATUS(ddr3_tip_bist_operation(dev_num, access_type,
+						     if_num, BIST_START));
+		if (duration != DURATION_CONT) {
+			/*
+			 * This pdelay is a WA, becuase polling fives "done"
+			 * also the odpg did nmot finish its task
+			 */
+			if (access_type == ACCESS_TYPE_MULTICAST) {
+				start_if = 0;
+				end_if = MAX_INTERFACE_NUM - 1;
+			} else {
+				start_if = if_num;
+				end_if = if_num;
+			}
+
+			for (i = start_if; i <= end_if; i++) {
+				VALIDATE_ACTIVE(tm->
+						   if_act_mask, i);
+
+				for (poll_cnt = 0; poll_cnt < max_poll;
+				     poll_cnt++) {
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_num, ODPG_BIST_DONE,
+						      read_data,
+						      MASK_ALL_BITS));
+					val = read_data[i];
+					if ((val & 0x1) == 0x0) {
+						/*
+						 * In SOC type devices this bit
+						 * is self clear so, if it was
+						 * cleared all good
+						 */
+						break;
+					}
+				}
+
+				if (poll_cnt >= max_poll) {
+					DEBUG_TRAINING_BIST_ENGINE
+						(DEBUG_LEVEL_ERROR,
+						 ("Bist poll failure 2\n"));
+					CHECK_STATUS(ddr3_tip_if_write
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_num,
+						      ODPG_DATA_CONTROL_REG, 0,
+						      MASK_ALL_BITS));
+					return MV_FAIL;
+				}
+			}
+
+			CHECK_STATUS(ddr3_tip_bist_operation
+				     (dev_num, access_type, if_num, BIST_STOP));
+		}
+	}
+
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num,
+				       ODPG_DATA_CONTROL_REG, 0,
+				       MASK_ALL_BITS));
+
+	return MV_OK;
+}
+
+/*
+ * BIST read result
+ */
+int ddr3_tip_bist_read_result(u32 dev_num, u32 if_id,
+			      struct bist_result *pst_bist_result)
+{
+	int ret;
+	u32 read_data[MAX_INTERFACE_NUM];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+		return MV_NOT_SUPPORTED;
+	DEBUG_TRAINING_BIST_ENGINE(DEBUG_LEVEL_TRACE,
+				   ("ddr3_tip_bist_read_result if_id %d\n",
+				    if_id));
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+			       ODPG_BIST_FAILED_DATA_HI_REG, read_data,
+			       MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+	pst_bist_result->bist_fail_high = read_data[if_id];
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+			       ODPG_BIST_FAILED_DATA_LOW_REG, read_data,
+			       MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+	pst_bist_result->bist_fail_low = read_data[if_id];
+
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+			       ODPG_BIST_LAST_FAIL_ADDR_REG, read_data,
+			       MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+	pst_bist_result->bist_last_fail_addr = read_data[if_id];
+	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
+			       ODPG_BIST_DATA_ERROR_COUNTER_REG, read_data,
+			       MASK_ALL_BITS);
+	if (ret != MV_OK)
+		return ret;
+	pst_bist_result->bist_error_cnt = read_data[if_id];
+
+	return MV_OK;
+}
+
+/*
+ * BIST flow - Activate & read result
+ */
+int hws_ddr3_run_bist(u32 dev_num, enum hws_pattern pattern, u32 *result,
+		      u32 cs_num)
+{
+	int ret;
+	u32 i = 0;
+	u32 win_base;
+	struct bist_result st_bist_result;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, i);
+		hws_ddr3_cs_base_adr_calc(i, cs_num, &win_base);
+		ret = ddr3_tip_bist_activate(dev_num, pattern,
+					     ACCESS_TYPE_UNICAST,
+					     i, OPER_WRITE, STRESS_NONE,
+					     DURATION_SINGLE, BIST_START,
+					     bist_offset + win_base,
+					     cs_num, 15);
+		if (ret != MV_OK) {
+			printf("ddr3_tip_bist_activate failed (0x%x)\n", ret);
+			return ret;
+		}
+
+		ret = ddr3_tip_bist_activate(dev_num, pattern,
+					     ACCESS_TYPE_UNICAST,
+					     i, OPER_READ, STRESS_NONE,
+					     DURATION_SINGLE, BIST_START,
+					     bist_offset + win_base,
+					     cs_num, 15);
+		if (ret != MV_OK) {
+			printf("ddr3_tip_bist_activate failed (0x%x)\n", ret);
+			return ret;
+		}
+
+		ret = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result);
+		if (ret != MV_OK) {
+			printf("ddr3_tip_bist_read_result failed\n");
+			return ret;
+		}
+		result[i] = st_bist_result.bist_error_cnt;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Set BIST Operation
+ */
+
+static int ddr3_tip_bist_operation(u32 dev_num,
+				   enum hws_access_type access_type,
+				   u32 if_id, enum hws_bist_operation oper_type)
+{
+	if (oper_type == BIST_STOP) {
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+					       ODPG_BIST_DONE, 1 << 8, 1 << 8));
+	} else {
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+					       ODPG_BIST_DONE, 1, 1));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Print BIST result
+ */
+void ddr3_tip_print_bist_res(void)
+{
+	u32 dev_num = 0;
+	u32 i;
+	struct bist_result st_bist_result[MAX_INTERFACE_NUM];
+	int res;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+		if (IS_ACTIVE(tm->if_act_mask, i) == 0)
+			continue;
+
+		res = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result[i]);
+		if (res != MV_OK) {
+			DEBUG_TRAINING_BIST_ENGINE(
+				DEBUG_LEVEL_ERROR,
+				("ddr3_tip_bist_read_result failed\n"));
+			return;
+		}
+	}
+
+	DEBUG_TRAINING_BIST_ENGINE(
+		DEBUG_LEVEL_INFO,
+		("interface | error_cnt | fail_low | fail_high | fail_addr\n"));
+
+	for (i = 0; i < MAX_INTERFACE_NUM; i++) {
+		if (IS_ACTIVE(tm->if_act_mask, i) ==
+		    0)
+			continue;
+
+		DEBUG_TRAINING_BIST_ENGINE(
+			DEBUG_LEVEL_INFO,
+			("%d |  0x%08x  |  0x%08x  |  0x%08x  | 0x%08x\n",
+			 i, st_bist_result[i].bist_error_cnt,
+			 st_bist_result[i].bist_fail_low,
+			 st_bist_result[i].bist_fail_high,
+			 st_bist_result[i].bist_last_fail_addr));
+	}
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
new file mode 100644
index 0000000..9d216da
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define VALIDATE_WIN_LENGTH(e1, e2, maxsize)		\
+	(((e2) + 1 > (e1) + (u8)MIN_WINDOW_SIZE) &&	\
+	 ((e2) + 1 < (e1) + (u8)maxsize))
+#define IS_WINDOW_OUT_BOUNDARY(e1, e2, maxsize)			\
+	(((e1) == 0 && (e2) != 0) ||				\
+	 ((e1) != (maxsize - 1) && (e2) == (maxsize - 1)))
+#define CENTRAL_TX		0
+#define CENTRAL_RX		1
+#define NUM_OF_CENTRAL_TYPES	2
+
+u32 start_pattern = PATTERN_KILLER_DQ0, end_pattern = PATTERN_KILLER_DQ7;
+u32 start_if = 0, end_if = (MAX_INTERFACE_NUM - 1);
+u8 bus_end_window[NUM_OF_CENTRAL_TYPES][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 bus_start_window[NUM_OF_CENTRAL_TYPES][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 centralization_state[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+static u8 ddr3_tip_special_rx_run_once_flag;
+
+static int ddr3_tip_centralization(u32 dev_num, u32 mode);
+
+/*
+ * Centralization RX Flow
+ */
+int ddr3_tip_centralization_rx(u32 dev_num)
+{
+	CHECK_STATUS(ddr3_tip_special_rx(dev_num));
+	CHECK_STATUS(ddr3_tip_centralization(dev_num, CENTRAL_RX));
+
+	return MV_OK;
+}
+
+/*
+ * Centralization TX Flow
+ */
+int ddr3_tip_centralization_tx(u32 dev_num)
+{
+	CHECK_STATUS(ddr3_tip_centralization(dev_num, CENTRAL_TX));
+
+	return MV_OK;
+}
+
+/*
+ * Centralization Flow
+ */
+static int ddr3_tip_centralization(u32 dev_num, u32 mode)
+{
+	enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM];
+	u32 if_id, pattern_id, bit_id;
+	u8 bus_id;
+	u8 cur_start_win[BUS_WIDTH_IN_BITS];
+	u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS];
+	u8 cur_end_win[BUS_WIDTH_IN_BITS];
+	u8 current_window[BUS_WIDTH_IN_BITS];
+	u8 opt_window, waste_window, start_window_skew, end_window_skew;
+	u8 final_pup_window[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+	enum hws_training_result result_type = RESULT_PER_BIT;
+	enum hws_dir direction;
+	u32 *result[HWS_SEARCH_DIR_LIMIT];
+	u32 reg_phy_off, reg;
+	u8 max_win_size;
+	int lock_success = 1;
+	u8 cur_end_win_min, cur_start_win_max;
+	u32 cs_enable_reg_val[MAX_INTERFACE_NUM];
+	int is_if_fail = 0;
+	enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage);
+	u32 pup_win_length = 0;
+	enum hws_search_dir search_dir_id;
+	u8 cons_tap = (mode == CENTRAL_TX) ? (64) : (0);
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/* save current cs enable reg val */
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS));
+		/* enable single cs */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, (1 << 3), (1 << 3)));
+	}
+
+	if (mode == CENTRAL_TX) {
+		max_win_size = MAX_WINDOW_SIZE_TX;
+		reg_phy_off = WRITE_CENTRALIZATION_PHY_REG + (effective_cs * 4);
+		direction = OPER_WRITE;
+	} else {
+		max_win_size = MAX_WINDOW_SIZE_RX;
+		reg_phy_off = READ_CENTRALIZATION_PHY_REG + (effective_cs * 4);
+		direction = OPER_READ;
+	}
+
+	/* DB initialization */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_id = 0;
+		     bus_id < tm->num_of_bus_per_interface; bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			centralization_state[if_id][bus_id] = 0;
+			bus_end_window[mode][if_id][bus_id] =
+				(max_win_size - 1) + cons_tap;
+			bus_start_window[mode][if_id][bus_id] = 0;
+			centralization_result[if_id][bus_id] = 0;
+		}
+	}
+
+	/* start flow */
+	for (pattern_id = start_pattern; pattern_id <= end_pattern;
+	     pattern_id++) {
+		ddr3_tip_ip_training_wrapper(dev_num, ACCESS_TYPE_MULTICAST,
+					     PARAM_NOT_CARE,
+					     ACCESS_TYPE_MULTICAST,
+					     PARAM_NOT_CARE, result_type,
+					     HWS_CONTROL_ELEMENT_ADLL,
+					     PARAM_NOT_CARE, direction,
+					     tm->
+					     if_act_mask, 0x0,
+					     max_win_size - 1,
+					     max_win_size - 1,
+					     pattern_id, EDGE_FPF, CS_SINGLE,
+					     PARAM_NOT_CARE, training_result);
+
+		for (if_id = start_if; if_id <= end_if; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			for (bus_id = 0;
+			     bus_id <= tm->num_of_bus_per_interface - 1;
+			     bus_id++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+
+				for (search_dir_id = HWS_LOW2HIGH;
+				     search_dir_id <= HWS_HIGH2LOW;
+				     search_dir_id++) {
+					CHECK_STATUS
+						(ddr3_tip_read_training_result
+						 (dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, bus_id,
+						  ALL_BITS_PER_PUP,
+						  search_dir_id,
+						  direction, result_type,
+						  TRAINING_LOAD_OPERATION_UNLOAD,
+						  CS_SINGLE,
+						  &result[search_dir_id],
+						  1, 0, 0));
+					DEBUG_CENTRALIZATION_ENGINE
+						(DEBUG_LEVEL_INFO,
+						 ("%s pat %d IF %d pup %d Regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+						  ((mode ==
+						    CENTRAL_TX) ? "TX" : "RX"),
+						  pattern_id, if_id, bus_id,
+						  result[search_dir_id][0],
+						  result[search_dir_id][1],
+						  result[search_dir_id][2],
+						  result[search_dir_id][3],
+						  result[search_dir_id][4],
+						  result[search_dir_id][5],
+						  result[search_dir_id][6],
+						  result[search_dir_id][7]));
+				}
+
+				for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS;
+				     bit_id++) {
+					/* check if this code is valid for 2 edge, probably not :( */
+					cur_start_win[bit_id] =
+						GET_TAP_RESULT(result
+							       [HWS_LOW2HIGH]
+							       [bit_id],
+							       EDGE_1);
+					cur_end_win[bit_id] =
+						GET_TAP_RESULT(result
+							       [HWS_HIGH2LOW]
+							       [bit_id],
+							       EDGE_1);
+					/* window length */
+					current_window[bit_id] =
+						cur_end_win[bit_id] -
+						cur_start_win[bit_id] + 1;
+					DEBUG_CENTRALIZATION_ENGINE
+						(DEBUG_LEVEL_TRACE,
+						 ("cs %x patern %d IF %d pup %d cur_start_win %d cur_end_win %d current_window %d\n",
+						  effective_cs, pattern_id,
+						  if_id, bus_id,
+						  cur_start_win[bit_id],
+						  cur_end_win[bit_id],
+						  current_window[bit_id]));
+				}
+
+				if ((ddr3_tip_is_pup_lock
+				     (result[HWS_LOW2HIGH], result_type)) &&
+				    (ddr3_tip_is_pup_lock
+				     (result[HWS_HIGH2LOW], result_type))) {
+					/* read result success */
+					DEBUG_CENTRALIZATION_ENGINE
+						(DEBUG_LEVEL_INFO,
+						 ("Pup locked, pat %d IF %d pup %d\n",
+						  pattern_id, if_id, bus_id));
+				} else {
+					/* read result failure */
+					DEBUG_CENTRALIZATION_ENGINE
+						(DEBUG_LEVEL_INFO,
+						 ("fail Lock, pat %d IF %d pup %d\n",
+						  pattern_id, if_id, bus_id));
+					if (centralization_state[if_id][bus_id]
+					    == 1) {
+						/* continue with next pup */
+						DEBUG_CENTRALIZATION_ENGINE
+							(DEBUG_LEVEL_TRACE,
+							 ("continue to next pup %d %d\n",
+							  if_id, bus_id));
+						continue;
+					}
+
+					for (bit_id = 0;
+					     bit_id < BUS_WIDTH_IN_BITS;
+					     bit_id++) {
+						/*
+						 * the next check is relevant
+						 * only when using search
+						 * machine 2 edges
+						 */
+						if (cur_start_win[bit_id] > 0 &&
+						    cur_end_win[bit_id] == 0) {
+							cur_end_win
+								[bit_id] =
+								max_win_size - 1;
+							DEBUG_CENTRALIZATION_ENGINE
+								(DEBUG_LEVEL_TRACE,
+								 ("fail, IF %d pup %d bit %d fail #1\n",
+								  if_id, bus_id,
+								  bit_id));
+							/* the next bit */
+							continue;
+						} else {
+							centralization_state
+								[if_id][bus_id] = 1;
+							DEBUG_CENTRALIZATION_ENGINE
+								(DEBUG_LEVEL_TRACE,
+								 ("fail, IF %d pup %d bit %d fail #2\n",
+								  if_id, bus_id,
+								  bit_id));
+						}
+					}
+
+					if (centralization_state[if_id][bus_id]
+					    == 1) {
+						/* going to next pup */
+						continue;
+					}
+				}	/*bit */
+
+				opt_window =
+					ddr3_tip_get_buf_min(current_window);
+				/* final pup window length */
+				final_pup_window[if_id][bus_id] =
+					ddr3_tip_get_buf_min(cur_end_win) -
+					ddr3_tip_get_buf_max(cur_start_win) +
+					1;
+				waste_window =
+					opt_window -
+					final_pup_window[if_id][bus_id];
+				start_window_skew =
+					ddr3_tip_get_buf_max(cur_start_win) -
+					ddr3_tip_get_buf_min(
+						cur_start_win);
+				end_window_skew =
+					ddr3_tip_get_buf_max(
+						cur_end_win) -
+					ddr3_tip_get_buf_min(
+						cur_end_win);
+				/* min/max updated with pattern change */
+				cur_end_win_min =
+					ddr3_tip_get_buf_min(
+						cur_end_win);
+				cur_start_win_max =
+					ddr3_tip_get_buf_max(
+						cur_start_win);
+				bus_end_window[mode][if_id][bus_id] =
+					GET_MIN(bus_end_window[mode][if_id]
+						[bus_id],
+						cur_end_win_min);
+				bus_start_window[mode][if_id][bus_id] =
+					GET_MAX(bus_start_window[mode][if_id]
+						[bus_id],
+						cur_start_win_max);
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("pat %d IF %d pup %d opt_win %d final_win %d waste_win %d st_win_skew %d end_win_skew %d cur_st_win_max %d cur_end_win_min %d bus_st_win %d bus_end_win %d\n",
+					 pattern_id, if_id, bus_id, opt_window,
+					 final_pup_window[if_id][bus_id],
+					 waste_window, start_window_skew,
+					 end_window_skew,
+					 cur_start_win_max,
+					 cur_end_win_min,
+					 bus_start_window[mode][if_id][bus_id],
+					 bus_end_window[mode][if_id][bus_id]));
+
+				/* check if window is valid */
+				if (ddr3_tip_centr_skip_min_win_check == 0) {
+					if ((VALIDATE_WIN_LENGTH
+					     (bus_start_window[mode][if_id]
+					      [bus_id],
+					      bus_end_window[mode][if_id]
+					      [bus_id],
+					      max_win_size) == 1) ||
+					    (IS_WINDOW_OUT_BOUNDARY
+					     (bus_start_window[mode][if_id]
+					      [bus_id],
+					      bus_end_window[mode][if_id]
+					      [bus_id],
+					      max_win_size) == 1)) {
+						DEBUG_CENTRALIZATION_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 ("win valid, pat %d IF %d pup %d\n",
+							  pattern_id, if_id,
+							  bus_id));
+						/* window is valid */
+					} else {
+						DEBUG_CENTRALIZATION_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 ("fail win, pat %d IF %d pup %d bus_st_win %d bus_end_win %d\n",
+							  pattern_id, if_id, bus_id,
+							  bus_start_window[mode]
+							  [if_id][bus_id],
+							  bus_end_window[mode]
+							  [if_id][bus_id]));
+						centralization_state[if_id]
+							[bus_id] = 1;
+						if (debug_mode == 0)
+							return MV_FAIL;
+					}
+				}	/* ddr3_tip_centr_skip_min_win_check */
+			}	/* pup */
+		}		/* interface */
+	}			/* pattern */
+
+	for (if_id = start_if; if_id <= end_if; if_id++) {
+		if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+			continue;
+
+		is_if_fail = 0;
+		flow_result[if_id] = TEST_SUCCESS;
+
+		for (bus_id = 0;
+		     bus_id <= (tm->num_of_bus_per_interface - 1); bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+
+			/* continue only if lock */
+			if (centralization_state[if_id][bus_id] != 1) {
+				if (ddr3_tip_centr_skip_min_win_check == 0)	{
+					if ((bus_end_window
+					     [mode][if_id][bus_id] ==
+					     (max_win_size - 1)) &&
+					    ((bus_end_window
+					      [mode][if_id][bus_id] -
+					      bus_start_window[mode][if_id]
+					      [bus_id]) < MIN_WINDOW_SIZE) &&
+					    ((bus_end_window[mode][if_id]
+					      [bus_id] - bus_start_window
+					      [mode][if_id][bus_id]) > 2)) {
+						/* prevent false lock */
+						/* TBD change to enum */
+						centralization_state
+							[if_id][bus_id] = 2;
+					}
+
+					if ((bus_end_window[mode][if_id][bus_id]
+					     == 0) &&
+					    ((bus_end_window[mode][if_id]
+					      [bus_id] -
+					      bus_start_window[mode][if_id]
+					      [bus_id]) < MIN_WINDOW_SIZE) &&
+					    ((bus_end_window[mode][if_id]
+					      [bus_id] -
+					      bus_start_window[mode][if_id]
+					      [bus_id]) > 2))
+						/*prevent false lock */
+						centralization_state[if_id]
+							[bus_id] = 3;
+				}
+
+				if ((bus_end_window[mode][if_id][bus_id] >
+				     (max_win_size - 1)) && direction ==
+				    OPER_WRITE) {
+					DEBUG_CENTRALIZATION_ENGINE
+						(DEBUG_LEVEL_INFO,
+						 ("Tx special pattern\n"));
+					cons_tap = 64;
+				}
+			}
+
+			/* check states */
+			if (centralization_state[if_id][bus_id] == 3) {
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("SSW - TBD IF %d pup %d\n",
+					 if_id, bus_id));
+				lock_success = 1;
+			} else if (centralization_state[if_id][bus_id] == 2) {
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("SEW - TBD IF %d pup %d\n",
+					 if_id, bus_id));
+				lock_success = 1;
+			} else if (centralization_state[if_id][bus_id] == 0) {
+				lock_success = 1;
+			} else {
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_ERROR,
+					("fail, IF %d pup %d\n",
+					 if_id, bus_id));
+				lock_success = 0;
+			}
+
+			if (lock_success == 1) {
+				centralization_result[if_id][bus_id] =
+					(bus_end_window[mode][if_id][bus_id] +
+					 bus_start_window[mode][if_id][bus_id])
+					/ 2 - cons_tap;
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_TRACE,
+					(" bus_id %d Res= %d\n", bus_id,
+					 centralization_result[if_id][bus_id]));
+				/* copy results to registers  */
+				pup_win_length =
+					bus_end_window[mode][if_id][bus_id] -
+					bus_start_window[mode][if_id][bus_id] +
+					1;
+
+				ddr3_tip_bus_read(dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, bus_id,
+						  DDR_PHY_DATA,
+						  RESULT_DB_PHY_REG_ADDR +
+						  effective_cs, &reg);
+				reg = (reg & (~0x1f <<
+					      ((mode == CENTRAL_TX) ?
+					       (RESULT_DB_PHY_REG_TX_OFFSET) :
+					       (RESULT_DB_PHY_REG_RX_OFFSET))))
+					| pup_win_length <<
+					((mode == CENTRAL_TX) ?
+					 (RESULT_DB_PHY_REG_TX_OFFSET) :
+					 (RESULT_DB_PHY_REG_RX_OFFSET));
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      bus_id, DDR_PHY_DATA,
+					      RESULT_DB_PHY_REG_ADDR +
+					      effective_cs, reg));
+
+				/* offset per CS is calculated earlier */
+				CHECK_STATUS(
+					ddr3_tip_bus_write(dev_num,
+							   ACCESS_TYPE_UNICAST,
+							   if_id,
+							   ACCESS_TYPE_UNICAST,
+							   bus_id,
+							   DDR_PHY_DATA,
+							   reg_phy_off,
+							   centralization_result
+							   [if_id]
+							   [bus_id]));
+			} else {
+				is_if_fail = 1;
+			}
+		}
+
+		if (is_if_fail == 1)
+			flow_result[if_id] = TEST_FAILED;
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		/* restore cs enable value */
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST,
+					       if_id, CS_ENABLE_REG,
+					       cs_enable_reg_val[if_id],
+					       MASK_ALL_BITS));
+	}
+
+	return is_if_fail;
+}
+
+/*
+ * Centralization Flow
+ */
+int ddr3_tip_special_rx(u32 dev_num)
+{
+	enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM];
+	u32 if_id, pup_id, pattern_id, bit_id;
+	u8 cur_start_win[BUS_WIDTH_IN_BITS];
+	u8 cur_end_win[BUS_WIDTH_IN_BITS];
+	enum hws_training_result result_type = RESULT_PER_BIT;
+	enum hws_dir direction;
+	enum hws_search_dir search_dir_id;
+	u32 *result[HWS_SEARCH_DIR_LIMIT];
+	u32 max_win_size;
+	u8 cur_end_win_min, cur_start_win_max;
+	u32 cs_enable_reg_val[MAX_INTERFACE_NUM];
+	u32 temp = 0;
+	int pad_num = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (ddr3_tip_special_rx_run_once_flag != 0)
+		return MV_OK;
+
+	ddr3_tip_special_rx_run_once_flag = 1;
+
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/* save current cs enable reg val */
+		CHECK_STATUS(ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, CS_ENABLE_REG,
+					      cs_enable_reg_val,
+					      MASK_ALL_BITS));
+		/* enable single cs */
+		CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST,
+					       if_id, CS_ENABLE_REG,
+					       (1 << 3), (1 << 3)));
+	}
+
+	max_win_size = MAX_WINDOW_SIZE_RX;
+	direction = OPER_READ;
+	pattern_id = PATTERN_VREF;
+
+	/* start flow */
+	ddr3_tip_ip_training_wrapper(dev_num, ACCESS_TYPE_MULTICAST,
+				     PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
+				     PARAM_NOT_CARE, result_type,
+				     HWS_CONTROL_ELEMENT_ADLL,
+				     PARAM_NOT_CARE, direction,
+				     tm->if_act_mask, 0x0,
+				     max_win_size - 1, max_win_size - 1,
+				     pattern_id, EDGE_FPF, CS_SINGLE,
+				     PARAM_NOT_CARE, training_result);
+
+	for (if_id = start_if; if_id <= end_if; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (pup_id = 0;
+		     pup_id <= tm->num_of_bus_per_interface; pup_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+
+			for (search_dir_id = HWS_LOW2HIGH;
+			     search_dir_id <= HWS_HIGH2LOW;
+			     search_dir_id++) {
+				CHECK_STATUS(ddr3_tip_read_training_result
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, pup_id,
+					      ALL_BITS_PER_PUP, search_dir_id,
+					      direction, result_type,
+					      TRAINING_LOAD_OPERATION_UNLOAD,
+					      CS_SINGLE, &result[search_dir_id],
+					      1, 0, 0));
+				DEBUG_CENTRALIZATION_ENGINE(DEBUG_LEVEL_INFO,
+							    ("Special: pat %d IF %d pup %d Regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+							     pattern_id, if_id,
+							     pup_id,
+							     result
+							     [search_dir_id][0],
+							     result
+							     [search_dir_id][1],
+							     result
+							     [search_dir_id][2],
+							     result
+							     [search_dir_id][3],
+							     result
+							     [search_dir_id][4],
+							     result
+							     [search_dir_id][5],
+							     result
+							     [search_dir_id][6],
+							     result
+							     [search_dir_id]
+							     [7]));
+			}
+
+			for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; bit_id++) {
+				/*
+				 * check if this code is valid for 2 edge,
+				 * probably not :(
+				 */
+				cur_start_win[bit_id] =
+					GET_TAP_RESULT(result[HWS_LOW2HIGH]
+						       [bit_id], EDGE_1);
+				cur_end_win[bit_id] =
+					GET_TAP_RESULT(result[HWS_HIGH2LOW]
+						       [bit_id], EDGE_1);
+			}
+			if (!((ddr3_tip_is_pup_lock
+			       (result[HWS_LOW2HIGH], result_type)) &&
+			      (ddr3_tip_is_pup_lock
+			       (result[HWS_HIGH2LOW], result_type)))) {
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_ERROR,
+					("Special: Pup lock fail, pat %d IF %d pup %d\n",
+					 pattern_id, if_id, pup_id));
+				return MV_FAIL;
+			}
+
+			cur_end_win_min =
+				ddr3_tip_get_buf_min(cur_end_win);
+			cur_start_win_max =
+				ddr3_tip_get_buf_max(cur_start_win);
+
+			if (cur_start_win_max <= 1) {	/* Align left */
+				for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS;
+				     bit_id++) {
+					pad_num =
+						dq_map_table[bit_id +
+							     pup_id *
+							     BUS_WIDTH_IN_BITS +
+							     if_id *
+							     BUS_WIDTH_IN_BITS *
+							     tm->
+							     num_of_bus_per_interface];
+					CHECK_STATUS(ddr3_tip_bus_read
+						     (dev_num, if_id,
+						      ACCESS_TYPE_UNICAST,
+						      pup_id, DDR_PHY_DATA,
+						      PBS_RX_PHY_REG + pad_num,
+						      &temp));
+					temp = (temp + 0xa > 31) ?
+						(31) : (temp + 0xa);
+					CHECK_STATUS(ddr3_tip_bus_write
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      ACCESS_TYPE_UNICAST,
+						      pup_id, DDR_PHY_DATA,
+						      PBS_RX_PHY_REG + pad_num,
+						      temp));
+				}
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("Special: PBS:: I/F# %d , Bus# %d fix align to the Left\n",
+					 if_id, pup_id));
+			}
+
+			if (cur_end_win_min > 30) { /* Align right */
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, pup_id,
+					      DDR_PHY_DATA, PBS_RX_PHY_REG + 4,
+					      &temp));
+				temp += 0xa;
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      pup_id, DDR_PHY_DATA,
+					      PBS_RX_PHY_REG + 4, temp));
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, pup_id,
+					      DDR_PHY_DATA, PBS_RX_PHY_REG + 5,
+					      &temp));
+				temp += 0xa;
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      pup_id, DDR_PHY_DATA,
+					      PBS_RX_PHY_REG + 5, temp));
+				DEBUG_CENTRALIZATION_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("Special: PBS:: I/F# %d , Bus# %d fix align to the right\n",
+					 if_id, pup_id));
+			}
+
+			vref_window_size[if_id][pup_id] =
+				cur_end_win_min -
+				cur_start_win_max + 1;
+			DEBUG_CENTRALIZATION_ENGINE(
+				DEBUG_LEVEL_INFO,
+				("Special: Winsize I/F# %d , Bus# %d is %d\n",
+				 if_id, pup_id, vref_window_size
+				 [if_id][pup_id]));
+		}		/* pup */
+	}			/* end of interface */
+
+	return MV_OK;
+}
+
+/*
+ * Print Centralization Result
+ */
+int ddr3_tip_print_centralization_result(u32 dev_num)
+{
+	u32 if_id = 0, bus_id = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	dev_num = dev_num;
+
+	printf("Centralization Results\n");
+	printf("I/F0 Result[0 - success 1-fail 2 - state_2 3 - state_3] ...\n");
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+		     bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			printf("%d ,\n", centralization_state[if_id][bus_id]);
+		}
+	}
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_db.c b/drivers/ddr/marvell/a38x/ddr3_training_db.c
new file mode 100644
index 0000000..861dfb1
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_db.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+/* List of allowed frequency listed in order of enum hws_ddr_freq */
+u32 freq_val[DDR_FREQ_LIMIT] = {
+	0,			/*DDR_FREQ_LOW_FREQ */
+	400,			/*DDR_FREQ_400, */
+	533,			/*DDR_FREQ_533, */
+	666,			/*DDR_FREQ_667, */
+	800,			/*DDR_FREQ_800, */
+	933,			/*DDR_FREQ_933, */
+	1066,			/*DDR_FREQ_1066, */
+	311,			/*DDR_FREQ_311, */
+	333,			/*DDR_FREQ_333, */
+	467,			/*DDR_FREQ_467, */
+	850,			/*DDR_FREQ_850, */
+	600,			/*DDR_FREQ_600 */
+	300,			/*DDR_FREQ_300 */
+	900,			/*DDR_FREQ_900 */
+	360,			/*DDR_FREQ_360 */
+	1000			/*DDR_FREQ_1000 */
+};
+
+/* Table for CL values per frequency for each speed bin index */
+struct cl_val_per_freq cas_latency_table[] = {
+	/*
+	 * 400M   667M     933M   311M     467M  600M    360
+	 * 100M    533M    800M    1066M   333M    850M      900
+	 * 1000 (the order is 100, 400, 533 etc.)
+	 */
+	/* DDR3-800D */
+	{ {6, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
+	/* DDR3-800E */
+	{ {6, 6, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 6, 0, 6, 0} },
+	/* DDR3-1066E */
+	{ {6, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 0, 5, 0, 5, 0} },
+	/* DDR3-1066F */
+	{ {6, 6, 7, 0, 0, 0, 0, 6, 6, 7, 0, 0, 6, 0, 6, 0} },
+	/* DDR3-1066G */
+	{ {6, 6, 8, 0, 0, 0, 0, 6, 6, 8, 0, 0, 6, 0, 6, 0} },
+	/* DDR3-1333F* */
+	{ {6, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1333G */
+	{ {6, 5, 7, 8, 0, 0, 0, 5, 5, 7, 0, 8, 5, 0, 5, 0} },
+	/* DDR3-1333H */
+	{ {6, 6, 8, 9, 0, 0, 0, 6, 6, 8, 0, 9, 6, 0, 6, 0} },
+	/* DDR3-1333J* */
+	{ {6, 6, 8, 10, 0, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6,  0}
+	 /* DDR3-1600G* */},
+	{ {6, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1600H */
+	{ {6, 5, 6, 8, 9, 0, 0, 5, 5, 6, 0, 8, 5, 0, 5, 0} },
+	/* DDR3-1600J */
+	{ {6, 5, 7, 9, 10, 0, 0, 5, 5, 7, 0, 9, 5, 0, 5, 0} },
+	/* DDR3-1600K */
+	{ {6, 6, 8, 10, 11, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6, 0 } },
+	/* DDR3-1866J* */
+	{ {6, 5, 6, 8, 9, 11, 0, 5, 5, 6, 11, 8, 5, 0, 5, 0} },
+	/* DDR3-1866K */
+	{ {6, 5, 7, 8, 10, 11, 0, 5, 5, 7, 11, 8, 5, 11, 5, 11} },
+	/* DDR3-1866L */
+	{ {6, 6, 7, 9, 11, 12, 0, 6, 6, 7, 12, 9, 6, 12, 6, 12} },
+	/* DDR3-1866M* */
+	{ {6, 6, 8, 10, 11, 13, 0, 6, 6, 8, 13, 10, 6, 13, 6, 13} },
+	/* DDR3-2133K* */
+	{ {6, 5, 6, 7, 9, 10, 11, 5, 5, 6, 10, 7, 5, 11, 5, 11} },
+	/* DDR3-2133L */
+	{ {6, 5, 6, 8, 9, 11, 12, 5, 5, 6, 11, 8, 5, 12, 5, 12} },
+	/* DDR3-2133M */
+	{ {6, 5, 7, 9, 10, 12, 13, 5, 5, 7, 12, 9, 5, 13, 5, 13} },
+	/* DDR3-2133N* */
+	{ {6, 6, 7, 9, 11, 13, 14, 6, 6, 7, 13, 9, 6, 14,  6, 14} },
+	/* DDR3-1333H-ext */
+	{ {6, 6, 7, 9, 0, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} },
+	/* DDR3-1600K-ext */
+	{ {6, 6, 7, 9, 11, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} },
+	/* DDR3-1866M-ext */
+	{ {6, 6, 7, 9, 11, 13, 0, 6, 6, 7, 13, 9, 6, 13, 6, 13} },
+};
+
+/* Table for CWL values per speedbin index */
+struct cl_val_per_freq cas_write_latency_table[] = {
+	/*
+	 * 400M   667M     933M   311M     467M  600M    360
+	 * 100M    533M    800M    1066M   333M    850M      900
+	 * (the order is 100, 400, 533 etc.)
+	 */
+	/* DDR3-800D  */
+	{ {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
+	/* DDR3-800E  */
+	{ {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
+	/* DDR3-1066E  */
+	{ {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1066F  */
+	{ {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1066G  */
+	{ {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1333F*  */
+	{ {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1333G  */
+	{ {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1333H  */
+	{ {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1333J*  */
+	{ {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1600G*  */
+	{ {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1600H  */
+	{ {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1600J  */
+	{ {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1600K  */
+	{ {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1866J*  */
+	{ {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} },
+	/* DDR3-1866K  */
+	{ {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} },
+	/* DDR3-1866L  */
+	{ {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
+	/* DDR3-1866M*   */
+	{ {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
+	/* DDR3-2133K*  */
+	{ {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+	/* DDR3-2133L  */
+	{ {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+	/* DDR3-2133M  */
+	{ {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+	/* DDR3-2133N*  */
+	{ {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
+	/* DDR3-1333H-ext  */
+	{ {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1600K-ext  */
+	{ {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
+	/* DDR3-1866M-ext  */
+	{ {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
+};
+
+u8 twr_mask_table[] = {
+	10,
+	10,
+	10,
+	10,
+	10,
+	1,			/*5 */
+	2,			/*6 */
+	3,			/*7 */
+	10,
+	10,
+	5,			/*10 */
+	10,
+	6,			/*12 */
+	10,
+	7,			/*14 */
+	10,
+	0			/*16 */
+};
+
+u8 cl_mask_table[] = {
+	0,
+	0,
+	0,
+	0,
+	0,
+	0x2,
+	0x4,
+	0x6,
+	0x8,
+	0xa,
+	0xc,
+	0xe,
+	0x1,
+	0x3,
+	0x5,
+	0x5
+};
+
+u8 cwl_mask_table[] = {
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0x1,
+	0x2,
+	0x3,
+	0x4,
+	0x5,
+	0x6,
+	0x7,
+	0x8,
+	0x9,
+	0x9
+};
+
+/* RFC values (in ns) */
+u16 rfc_table[] = {
+	90,			/* 512M */
+	110,			/* 1G */
+	160,			/* 2G */
+	260,			/* 4G */
+	350			/* 8G */
+};
+
+u32 speed_bin_table_t_rc[] = {
+	50000,
+	52500,
+	48750,
+	50625,
+	52500,
+	46500,
+	48000,
+	49500,
+	51000,
+	45000,
+	46250,
+	47500,
+	48750,
+	44700,
+	45770,
+	46840,
+	47910,
+	43285,
+	44220,
+	45155,
+	46900
+};
+
+u32 speed_bin_table_t_rcd_t_rp[] = {
+	12500,
+	15000,
+	11250,
+	13125,
+	15000,
+	10500,
+	12000,
+	13500,
+	15000,
+	10000,
+	11250,
+	12500,
+	13750,
+	10700,
+	11770,
+	12840,
+	13910,
+	10285,
+	11022,
+	12155,
+	13090,
+};
+
+enum {
+	PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR = 0,
+	PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM
+};
+
+static u8 pattern_killer_pattern_table_map[KILLER_PATTERN_LENGTH * 2][2] = {
+	/*Aggressor / Victim */
+	{1, 0},
+	{0, 0},
+	{1, 0},
+	{1, 1},
+	{0, 1},
+	{0, 1},
+	{1, 0},
+	{0, 1},
+	{1, 0},
+	{0, 1},
+	{1, 0},
+	{1, 0},
+	{0, 1},
+	{1, 0},
+	{0, 1},
+	{0, 0},
+	{1, 1},
+	{0, 0},
+	{1, 1},
+	{0, 0},
+	{1, 1},
+	{0, 0},
+	{1, 1},
+	{1, 0},
+	{0, 0},
+	{1, 1},
+	{0, 0},
+	{1, 1},
+	{0, 0},
+	{0, 0},
+	{0, 0},
+	{0, 1},
+	{0, 1},
+	{1, 1},
+	{0, 0},
+	{0, 0},
+	{1, 1},
+	{1, 1},
+	{0, 0},
+	{1, 1},
+	{0, 0},
+	{1, 1},
+	{1, 1},
+	{0, 0},
+	{0, 0},
+	{1, 1},
+	{0, 0},
+	{1, 1},
+	{0, 1},
+	{0, 0},
+	{0, 1},
+	{0, 1},
+	{0, 0},
+	{1, 1},
+	{1, 1},
+	{1, 0},
+	{1, 0},
+	{1, 1},
+	{1, 1},
+	{1, 1},
+	{1, 1},
+	{1, 1},
+	{1, 1},
+	{1, 1}
+};
+
+static u8 pattern_vref_pattern_table_map[] = {
+	/* 1 means 0xffffffff, 0 is 0x0 */
+	0xb8,
+	0x52,
+	0x55,
+	0x8a,
+	0x33,
+	0xa6,
+	0x6d,
+	0xfe
+};
+
+/* Return speed Bin value for selected index and t* element */
+u32 speed_bin_table(u8 index, enum speed_bin_table_elements element)
+{
+	u32 result = 0;
+
+	switch (element) {
+	case SPEED_BIN_TRCD:
+	case SPEED_BIN_TRP:
+		result = speed_bin_table_t_rcd_t_rp[index];
+		break;
+	case SPEED_BIN_TRAS:
+		if (index < 6)
+			result = 37500;
+		else if (index < 10)
+			result = 36000;
+		else if (index < 14)
+			result = 35000;
+		else if (index < 18)
+			result = 34000;
+		else
+			result = 33000;
+		break;
+	case SPEED_BIN_TRC:
+		result = speed_bin_table_t_rc[index];
+		break;
+	case SPEED_BIN_TRRD1K:
+		if (index < 3)
+			result = 10000;
+		else if (index < 6)
+			result = 7005;
+		else if (index < 14)
+			result = 6000;
+		else
+			result = 5000;
+		break;
+	case SPEED_BIN_TRRD2K:
+		if (index < 6)
+			result = 10000;
+		else if (index < 14)
+			result = 7005;
+		else
+			result = 6000;
+		break;
+	case SPEED_BIN_TPD:
+		if (index < 3)
+			result = 7500;
+		else if (index < 10)
+			result = 5625;
+		else
+			result = 5000;
+		break;
+	case SPEED_BIN_TFAW1K:
+		if (index < 3)
+			result = 40000;
+		else if (index < 6)
+			result = 37500;
+		else if (index < 14)
+			result = 30000;
+		else if (index < 18)
+			result = 27000;
+		else
+			result = 25000;
+		break;
+	case SPEED_BIN_TFAW2K:
+		if (index < 6)
+			result = 50000;
+		else if (index < 10)
+			result = 45000;
+		else if (index < 14)
+			result = 40000;
+		else
+			result = 35000;
+		break;
+	case SPEED_BIN_TWTR:
+		result = 7500;
+		break;
+	case SPEED_BIN_TRTP:
+		result = 7500;
+		break;
+	case SPEED_BIN_TWR:
+		result = 15000;
+		break;
+	case SPEED_BIN_TMOD:
+		result = 15000;
+		break;
+	default:
+		break;
+	}
+
+	return result;
+}
+
+static inline u32 pattern_table_get_killer_word(u8 dqs, u8 index)
+{
+	u8 i, byte = 0;
+	u8 role;
+
+	for (i = 0; i < 8; i++) {
+		role = (i == dqs) ?
+			(PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
+			(PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
+		byte |= pattern_killer_pattern_table_map[index][role] << i;
+	}
+
+	return byte | (byte << 8) | (byte << 16) | (byte << 24);
+}
+
+static inline u32 pattern_table_get_killer_word16(u8 dqs, u8 index)
+{
+	u8 i, byte0 = 0, byte1 = 0;
+	u8 role;
+
+	for (i = 0; i < 8; i++) {
+		role = (i == dqs) ?
+			(PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
+			(PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
+		byte0 |= pattern_killer_pattern_table_map[index * 2][role] << i;
+	}
+
+	for (i = 0; i < 8; i++) {
+		role = (i == dqs) ?
+			(PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
+			(PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
+		byte1 |= pattern_killer_pattern_table_map
+			[index * 2 + 1][role] << i;
+	}
+
+	return byte0 | (byte0 << 8) | (byte1 << 16) | (byte1 << 24);
+}
+
+static inline u32 pattern_table_get_sso_word(u8 sso, u8 index)
+{
+	u8 step = sso + 1;
+
+	if (0 == ((index / step) & 1))
+		return 0x0;
+	else
+		return 0xffffffff;
+}
+
+static inline u32 pattern_table_get_vref_word(u8 index)
+{
+	if (0 == ((pattern_vref_pattern_table_map[index / 8] >>
+		   (index % 8)) & 1))
+		return 0x0;
+	else
+		return 0xffffffff;
+}
+
+static inline u32 pattern_table_get_vref_word16(u8 index)
+{
+	if (0 == pattern_killer_pattern_table_map
+	    [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
+	    0 == pattern_killer_pattern_table_map
+	    [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
+		return 0x00000000;
+	else if (1 == pattern_killer_pattern_table_map
+		 [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
+		 0 == pattern_killer_pattern_table_map
+		 [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
+		return 0xffff0000;
+	else if (0 == pattern_killer_pattern_table_map
+		 [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
+		 1 == pattern_killer_pattern_table_map
+		 [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
+		return 0x0000ffff;
+	else
+		return 0xffffffff;
+}
+
+static inline u32 pattern_table_get_static_pbs_word(u8 index)
+{
+	u16 temp;
+
+	temp = ((0x00ff << (index / 3)) & 0xff00) >> 8;
+
+	return temp | (temp << 8) | (temp << 16) | (temp << 24);
+}
+
+inline u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index)
+{
+	u32 pattern;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0) {
+		/* 32bit patterns */
+		switch (type) {
+		case PATTERN_PBS1:
+		case PATTERN_PBS2:
+			if (index == 0 || index == 2 || index == 5 ||
+			    index == 7)
+				pattern = PATTERN_55;
+			else
+				pattern = PATTERN_AA;
+			break;
+		case PATTERN_PBS3:
+			if (0 == (index & 1))
+				pattern = PATTERN_55;
+			else
+				pattern = PATTERN_AA;
+			break;
+		case PATTERN_RL:
+			if (index < 6)
+				pattern = PATTERN_00;
+			else
+				pattern = PATTERN_80;
+			break;
+		case PATTERN_STATIC_PBS:
+			pattern = pattern_table_get_static_pbs_word(index);
+			break;
+		case PATTERN_KILLER_DQ0:
+		case PATTERN_KILLER_DQ1:
+		case PATTERN_KILLER_DQ2:
+		case PATTERN_KILLER_DQ3:
+		case PATTERN_KILLER_DQ4:
+		case PATTERN_KILLER_DQ5:
+		case PATTERN_KILLER_DQ6:
+		case PATTERN_KILLER_DQ7:
+			pattern = pattern_table_get_killer_word(
+				(u8)(type - PATTERN_KILLER_DQ0), index);
+			break;
+		case PATTERN_RL2:
+			if (index < 6)
+				pattern = PATTERN_00;
+			else
+				pattern = PATTERN_01;
+			break;
+		case PATTERN_TEST:
+			if (index > 1 && index < 6)
+				pattern = PATTERN_20;
+			else
+				pattern = PATTERN_00;
+			break;
+		case PATTERN_FULL_SSO0:
+		case PATTERN_FULL_SSO1:
+		case PATTERN_FULL_SSO2:
+		case PATTERN_FULL_SSO3:
+			pattern = pattern_table_get_sso_word(
+				(u8)(type - PATTERN_FULL_SSO0), index);
+			break;
+		case PATTERN_VREF:
+			pattern = pattern_table_get_vref_word(index);
+			break;
+		default:
+			pattern = 0;
+			break;
+		}
+	} else {
+		/* 16bit patterns */
+		switch (type) {
+		case PATTERN_PBS1:
+		case PATTERN_PBS2:
+		case PATTERN_PBS3:
+			pattern = PATTERN_55AA;
+			break;
+		case PATTERN_RL:
+			if (index < 3)
+				pattern = PATTERN_00;
+			else
+				pattern = PATTERN_80;
+			break;
+		case PATTERN_STATIC_PBS:
+			pattern = PATTERN_00FF;
+			break;
+		case PATTERN_KILLER_DQ0:
+		case PATTERN_KILLER_DQ1:
+		case PATTERN_KILLER_DQ2:
+		case PATTERN_KILLER_DQ3:
+		case PATTERN_KILLER_DQ4:
+		case PATTERN_KILLER_DQ5:
+		case PATTERN_KILLER_DQ6:
+		case PATTERN_KILLER_DQ7:
+			pattern = pattern_table_get_killer_word16(
+				(u8)(type - PATTERN_KILLER_DQ0), index);
+			break;
+		case PATTERN_RL2:
+			if (index < 3)
+				pattern = PATTERN_00;
+			else
+				pattern = PATTERN_01;
+			break;
+		case PATTERN_TEST:
+			pattern = PATTERN_0080;
+			break;
+		case PATTERN_FULL_SSO0:
+			pattern = 0x0000ffff;
+			break;
+		case PATTERN_FULL_SSO1:
+		case PATTERN_FULL_SSO2:
+		case PATTERN_FULL_SSO3:
+			pattern = pattern_table_get_sso_word(
+				(u8)(type - PATTERN_FULL_SSO1), index);
+			break;
+		case PATTERN_VREF:
+			pattern = pattern_table_get_vref_word16(index);
+			break;
+		default:
+			pattern = 0;
+			break;
+		}
+	}
+
+	return pattern;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c
new file mode 100644
index 0000000..56fce17
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c
@@ -0,0 +1,686 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define VREF_INITIAL_STEP		3
+#define VREF_SECOND_STEP		1
+#define VREF_MAX_INDEX			7
+#define MAX_VALUE			(1024 - 1)
+#define MIN_VALUE			(-MAX_VALUE)
+#define GET_RD_SAMPLE_DELAY(data, cs)	((data >> rd_sample_mask[cs]) & 0xf)
+
+u32 ck_delay = (u32)-1, ck_delay_16 = (u32)-1;
+u32 ca_delay;
+int ddr3_tip_centr_skip_min_win_check = 0;
+u8 current_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u8 last_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u16 current_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u16 last_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u8 lim_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+u8 interface_state[MAX_INTERFACE_NUM];
+u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 vref_window_size_th = 12;
+
+static u8 pup_st[MAX_BUS_NUM][MAX_INTERFACE_NUM];
+
+static u32 rd_sample_mask[] = {
+	0,
+	8,
+	16,
+	24
+};
+
+#define	VREF_STEP_1		0
+#define	VREF_STEP_2		1
+#define	VREF_CONVERGE		2
+
+/*
+ * ODT additional timing
+ */
+int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id)
+{
+	u32 cs_num = 0, max_read_sample = 0, min_read_sample = 0;
+	u32 data_read[MAX_INTERFACE_NUM] = { 0 };
+	u32 read_sample[MAX_CS_NUM];
+	u32 val;
+	u32 pup_index;
+	int max_phase = MIN_VALUE, current_phase;
+	enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       DUNIT_ODT_CONTROL_REG,
+				       0 << 8, 0x3 << 8));
+	CHECK_STATUS(ddr3_tip_if_read(dev_num, access_type, if_id,
+				      READ_DATA_SAMPLE_DELAY,
+				      data_read, MASK_ALL_BITS));
+	val = data_read[if_id];
+
+	for (cs_num = 0; cs_num < MAX_CS_NUM; cs_num++) {
+		read_sample[cs_num] = GET_RD_SAMPLE_DELAY(val, cs_num);
+
+		/* find maximum of read_samples */
+		if (read_sample[cs_num] >= max_read_sample) {
+			if (read_sample[cs_num] == max_read_sample)
+				max_phase = MIN_VALUE;
+			else
+				max_read_sample = read_sample[cs_num];
+
+			for (pup_index = 0;
+			     pup_index < tm->num_of_bus_per_interface;
+			     pup_index++) {
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, pup_index,
+					      DDR_PHY_DATA,
+					      RL_PHY_REG + CS_REG_VALUE(cs_num),
+					      &val));
+
+				current_phase = ((int)val & 0xe0) >> 6;
+				if (current_phase >= max_phase)
+					max_phase = current_phase;
+			}
+		}
+
+		/* find minimum */
+		if (read_sample[cs_num] < min_read_sample)
+			min_read_sample = read_sample[cs_num];
+	}
+
+	min_read_sample = min_read_sample - 1;
+	max_read_sample = max_read_sample + 4 + (max_phase + 1) / 2 + 1;
+	if (min_read_sample >= 0xf)
+		min_read_sample = 0xf;
+	if (max_read_sample >= 0x1f)
+		max_read_sample = 0x1f;
+
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       ODT_TIMING_LOW,
+				       ((min_read_sample - 1) << 12),
+				       0xf << 12));
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
+				       ODT_TIMING_LOW,
+				       (max_read_sample << 16),
+				       0x1f << 16));
+
+	return MV_OK;
+}
+
+int get_valid_win_rx(u32 dev_num, u32 if_id, u8 res[4])
+{
+	u32 reg_pup = RESULT_DB_PHY_REG_ADDR;
+	u32 reg_data;
+	u32 cs_num;
+	int i;
+
+	cs_num = 0;
+
+	/* TBD */
+	reg_pup += cs_num;
+
+	for (i = 0; i < 4; i++) {
+		CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id,
+					       ACCESS_TYPE_UNICAST, i,
+					       DDR_PHY_DATA, reg_pup,
+					       &reg_data));
+		res[i] = (reg_data >> RESULT_DB_PHY_REG_RX_OFFSET) & 0x1f;
+	}
+
+	return 0;
+}
+
+/*
+ * This algorithm deals with the vertical optimum from Voltage point of view
+ * of the sample signal.
+ * Voltage sample point can improve the Eye / window size of the bit and the
+ * pup.
+ * The problem is that it is tune for all DQ the same so there isn't any
+ * PBS like code.
+ * It is more like centralization.
+ * But because we don't have The training SM support we do it a bit more
+ * smart search to save time.
+ */
+int ddr3_tip_vref(u32 dev_num)
+{
+	/*
+	 * The Vref register have non linear order. Need to check what will be
+	 * in future projects.
+	 */
+	u32 vref_map[8] = {
+		1, 2, 3, 4, 5, 6, 7, 0
+	};
+	/* State and parameter definitions */
+	u32 initial_step = VREF_INITIAL_STEP;
+	/* need to be assign with minus ????? */
+	u32 second_step = VREF_SECOND_STEP;
+	u32 algo_run_flag = 0, currrent_vref = 0;
+	u32 while_count = 0;
+	u32 pup = 0, if_id = 0, num_pup = 0, rep = 0;
+	u32 val = 0;
+	u32 reg_addr = 0xa8;
+	u32 copy_start_pattern, copy_end_pattern;
+	enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage);
+	u8 res[4];
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	CHECK_STATUS(ddr3_tip_special_rx(dev_num));
+
+	/* save start/end pattern */
+	copy_start_pattern = start_pattern;
+	copy_end_pattern = end_pattern;
+
+	/* set vref as centralization pattern */
+	start_pattern = PATTERN_VREF;
+	end_pattern = PATTERN_VREF;
+
+	/* init params */
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (pup = 0;
+		     pup < tm->num_of_bus_per_interface; pup++) {
+			current_vref[pup][if_id] = 0;
+			last_vref[pup][if_id] = 0;
+			lim_vref[pup][if_id] = 0;
+			current_valid_window[pup][if_id] = 0;
+			last_valid_window[pup][if_id] = 0;
+			if (vref_window_size[if_id][pup] >
+			    vref_window_size_th) {
+				pup_st[pup][if_id] = VREF_CONVERGE;
+				DEBUG_TRAINING_HW_ALG(
+					DEBUG_LEVEL_INFO,
+					("VREF config, IF[ %d ]pup[ %d ] - Vref tune not requered (%d)\n",
+					 if_id, pup, __LINE__));
+			} else {
+				pup_st[pup][if_id] = VREF_STEP_1;
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr, &val));
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      pup, DDR_PHY_DATA, reg_addr,
+					      (val & (~0xf)) | vref_map[0]));
+				DEBUG_TRAINING_HW_ALG(
+					DEBUG_LEVEL_INFO,
+					("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+					 if_id, pup,
+					 (val & (~0xf)) | vref_map[0],
+					 __LINE__));
+			}
+		}
+		interface_state[if_id] = 0;
+	}
+
+	/* TODO: Set number of active interfaces */
+	num_pup = tm->num_of_bus_per_interface * MAX_INTERFACE_NUM;
+
+	while ((algo_run_flag <= num_pup) & (while_count < 10)) {
+		while_count++;
+		for (rep = 1; rep < 4; rep++) {
+			ddr3_tip_centr_skip_min_win_check = 1;
+			ddr3_tip_centralization_rx(dev_num);
+			ddr3_tip_centr_skip_min_win_check = 0;
+
+			/* Read Valid window results only for non converge pups */
+			for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				if (interface_state[if_id] != 4) {
+					get_valid_win_rx(dev_num, if_id, res);
+					for (pup = 0;
+					     pup < tm->num_of_bus_per_interface;
+					     pup++) {
+						VALIDATE_ACTIVE
+							(tm->bus_act_mask, pup);
+						if (pup_st[pup]
+						    [if_id] ==
+						    VREF_CONVERGE)
+							continue;
+
+						current_valid_window[pup]
+							[if_id] =
+							(current_valid_window[pup]
+							 [if_id] * (rep - 1) +
+							 1000 * res[pup]) / rep;
+					}
+				}
+			}
+		}
+
+		for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			DEBUG_TRAINING_HW_ALG(
+				DEBUG_LEVEL_TRACE,
+				("current_valid_window: IF[ %d ] - ", if_id));
+
+			for (pup = 0;
+			     pup < tm->num_of_bus_per_interface; pup++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
+						      ("%d ",
+						       current_valid_window
+						       [pup][if_id]));
+			}
+			DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, ("\n"));
+		}
+
+		/* Compare results and respond as function of state */
+		for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			for (pup = 0;
+			     pup < tm->num_of_bus_per_interface; pup++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
+						      ("I/F[ %d ], pup[ %d ] STATE #%d (%d)\n",
+						       if_id, pup,
+						       pup_st[pup]
+						       [if_id], __LINE__));
+
+				if (pup_st[pup][if_id] == VREF_CONVERGE)
+					continue;
+
+				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
+						      ("I/F[ %d ], pup[ %d ] CHECK progress - Current %d Last %d, limit VREF %d (%d)\n",
+						       if_id, pup,
+						       current_valid_window[pup]
+						       [if_id],
+						       last_valid_window[pup]
+						       [if_id], lim_vref[pup]
+						       [if_id], __LINE__));
+
+				/*
+				 * The -1 is for solution resolution +/- 1 tap
+				 * of ADLL
+				 */
+				if (current_valid_window[pup][if_id] + 200 >=
+				    (last_valid_window[pup][if_id])) {
+					if (pup_st[pup][if_id] == VREF_STEP_1) {
+						/*
+						 * We stay in the same state and
+						 * step just update the window
+						 * size (take the max) and Vref
+						 */
+						if (current_vref[pup]
+						    [if_id] == VREF_MAX_INDEX) {
+							/*
+							 * If we step to the end
+							 * and didn't converge
+							 * to some particular
+							 * better Vref value
+							 * define the pup as
+							 * converge and step
+							 * back to nominal
+							 * Vref.
+							 */
+							pup_st[pup]
+								[if_id] =
+								VREF_CONVERGE;
+							algo_run_flag++;
+							interface_state
+								[if_id]++;
+							DEBUG_TRAINING_HW_ALG
+								(DEBUG_LEVEL_TRACE,
+								 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+								  if_id, pup,
+								  current_vref[pup]
+								  [if_id],
+								  __LINE__));
+						} else {
+							/* continue to update the Vref index */
+							current_vref[pup]
+								[if_id] =
+								((current_vref[pup]
+								  [if_id] +
+								  initial_step) >
+								 VREF_MAX_INDEX) ?
+								VREF_MAX_INDEX
+								: (current_vref[pup]
+								   [if_id] +
+								   initial_step);
+							if (current_vref[pup]
+							    [if_id] ==
+							    VREF_MAX_INDEX) {
+								pup_st[pup]
+									[if_id]
+									=
+									VREF_STEP_2;
+							}
+							lim_vref[pup]
+								[if_id] =
+								last_vref[pup]
+								[if_id] =
+								current_vref[pup]
+								[if_id];
+						}
+
+						last_valid_window[pup]
+							[if_id] =
+							GET_MAX(current_valid_window
+								[pup][if_id],
+								last_valid_window
+								[pup]
+								[if_id]);
+
+						/* update the Vref for next stage */
+						currrent_vref =
+							current_vref[pup]
+							[if_id];
+						CHECK_STATUS
+							(ddr3_tip_bus_read
+							 (dev_num, if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  &val));
+						CHECK_STATUS
+							(ddr3_tip_bus_write
+							 (dev_num,
+							  ACCESS_TYPE_UNICAST,
+							  if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  (val & (~0xf)) |
+							  vref_map[currrent_vref]));
+						DEBUG_TRAINING_HW_ALG
+							(DEBUG_LEVEL_TRACE,
+							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+							  if_id, pup,
+							  (val & (~0xf)) |
+							  vref_map[currrent_vref],
+							  __LINE__));
+					} else if (pup_st[pup][if_id]
+						   == VREF_STEP_2) {
+						/*
+						 * We keep on search back with
+						 * the same step size.
+						 */
+						last_valid_window[pup]
+							[if_id] =
+							GET_MAX(current_valid_window
+								[pup][if_id],
+								last_valid_window
+								[pup]
+								[if_id]);
+						last_vref[pup][if_id] =
+							current_vref[pup]
+							[if_id];
+
+						/* we finish all search space */
+						if ((current_vref[pup]
+						     [if_id] - second_step) == lim_vref[pup][if_id]) {
+							/*
+							 * If we step to the end
+							 * and didn't converge
+							 * to some particular
+							 * better Vref value
+							 * define the pup as
+							 * converge and step
+							 * back to nominal
+							 * Vref.
+							 */
+							pup_st[pup]
+								[if_id] =
+								VREF_CONVERGE;
+							algo_run_flag++;
+
+							interface_state
+								[if_id]++;
+
+							current_vref[pup]
+								[if_id] =
+								(current_vref[pup]
+								 [if_id] -
+								 second_step);
+
+							DEBUG_TRAINING_HW_ALG
+								(DEBUG_LEVEL_TRACE,
+								 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+								  if_id, pup,
+								  current_vref[pup]
+								  [if_id],
+								  __LINE__));
+						} else
+							/* we finish all search space */
+							if (current_vref[pup]
+							    [if_id] ==
+							    lim_vref[pup]
+							    [if_id]) {
+								/*
+								 * If we step to the end
+								 * and didn't converge
+								 * to some particular
+								 * better Vref value
+								 * define the pup as
+								 * converge and step
+								 * back to nominal
+								 * Vref.
+								 */
+								pup_st[pup]
+									[if_id] =
+									VREF_CONVERGE;
+
+								algo_run_flag++;
+								interface_state
+									[if_id]++;
+								DEBUG_TRAINING_HW_ALG
+									(DEBUG_LEVEL_TRACE,
+									 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+									  if_id, pup,
+									  current_vref[pup]
+									  [if_id],
+									  __LINE__));
+							} else {
+								current_vref[pup]
+									[if_id] =
+									current_vref[pup]
+									[if_id] -
+									second_step;
+							}
+
+						/* Update the Vref for next stage */
+						currrent_vref =
+							current_vref[pup]
+							[if_id];
+						CHECK_STATUS
+							(ddr3_tip_bus_read
+							 (dev_num, if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  &val));
+						CHECK_STATUS
+							(ddr3_tip_bus_write
+							 (dev_num,
+							  ACCESS_TYPE_UNICAST,
+							  if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  (val & (~0xf)) |
+							  vref_map[currrent_vref]));
+						DEBUG_TRAINING_HW_ALG
+							(DEBUG_LEVEL_TRACE,
+							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+							  if_id, pup,
+							  (val & (~0xf)) |
+							  vref_map[currrent_vref],
+							  __LINE__));
+					}
+				} else {
+					/* we change state and change step */
+					if (pup_st[pup][if_id] == VREF_STEP_1) {
+						pup_st[pup][if_id] =
+							VREF_STEP_2;
+						lim_vref[pup][if_id] =
+							current_vref[pup]
+							[if_id] - initial_step;
+						last_valid_window[pup]
+							[if_id] =
+							current_valid_window[pup]
+							[if_id];
+						last_vref[pup][if_id] =
+							current_vref[pup]
+							[if_id];
+						current_vref[pup][if_id] =
+							last_vref[pup][if_id] -
+							second_step;
+
+						/* Update the Vref for next stage */
+						CHECK_STATUS
+							(ddr3_tip_bus_read
+							 (dev_num, if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  &val));
+						CHECK_STATUS
+							(ddr3_tip_bus_write
+							 (dev_num,
+							  ACCESS_TYPE_UNICAST,
+							  if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  (val & (~0xf)) |
+							  vref_map[current_vref[pup]
+								   [if_id]]));
+						DEBUG_TRAINING_HW_ALG
+							(DEBUG_LEVEL_TRACE,
+							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+							  if_id, pup,
+							  (val & (~0xf)) |
+							  vref_map[current_vref[pup]
+								   [if_id]],
+							  __LINE__));
+
+					} else if (pup_st[pup][if_id] == VREF_STEP_2) {
+						/*
+						 * The last search was the max
+						 * point set value and exit
+						 */
+						CHECK_STATUS
+							(ddr3_tip_bus_read
+							 (dev_num, if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  &val));
+						CHECK_STATUS
+							(ddr3_tip_bus_write
+							 (dev_num,
+							  ACCESS_TYPE_UNICAST,
+							  if_id,
+							  ACCESS_TYPE_UNICAST, pup,
+							  DDR_PHY_DATA, reg_addr,
+							  (val & (~0xf)) |
+							  vref_map[last_vref[pup]
+								   [if_id]]));
+						DEBUG_TRAINING_HW_ALG
+							(DEBUG_LEVEL_TRACE,
+							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
+							  if_id, pup,
+							  (val & (~0xf)) |
+							  vref_map[last_vref[pup]
+								   [if_id]],
+							  __LINE__));
+						pup_st[pup][if_id] =
+							VREF_CONVERGE;
+						algo_run_flag++;
+						interface_state[if_id]++;
+						DEBUG_TRAINING_HW_ALG
+							(DEBUG_LEVEL_TRACE,
+							 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
+							  if_id, pup,
+							  current_vref[pup]
+							  [if_id], __LINE__));
+					}
+				}
+			}
+		}
+	}
+
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (pup = 0;
+		     pup < tm->num_of_bus_per_interface; pup++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id,
+				      ACCESS_TYPE_UNICAST, pup,
+				      DDR_PHY_DATA, reg_addr, &val));
+			DEBUG_TRAINING_HW_ALG(
+				DEBUG_LEVEL_INFO,
+				("FINAL values: I/F[ %d ], pup[ %d ] - Vref = %X (%d)\n",
+				 if_id, pup, val, __LINE__));
+		}
+	}
+
+	flow_result[if_id] = TEST_SUCCESS;
+
+	/* restore start/end pattern */
+	start_pattern = copy_start_pattern;
+	end_pattern = copy_end_pattern;
+
+	return 0;
+}
+
+/*
+ * CK/CA Delay
+ */
+int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap)
+{
+	u32 if_id = 0;
+	u32 ck_num_adll_tap = 0, ca_num_adll_tap = 0, data = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/*
+	 * ck_delay_table is delaying the of the clock signal only.
+	 * (to overcome timing issues between_c_k & command/address signals)
+	 */
+	/*
+	 * ca_delay is delaying the of the entire command & Address signals
+	 * (include Clock signal to overcome DGL error on the Clock versus
+	 * the DQS).
+	 */
+
+	/* Calc ADLL Tap */
+	if ((ck_delay == -1) || (ck_delay_16 == -1)) {
+		DEBUG_TRAINING_HW_ALG(
+			DEBUG_LEVEL_ERROR,
+			("ERROR: One of ck_delay values not initialized!!!\n"));
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/* Calc delay ps in ADLL tap */
+		if (tm->interface_params[if_id].bus_width ==
+		    BUS_WIDTH_16)
+			ck_num_adll_tap = ck_delay_16 / adll_tap;
+		else
+			ck_num_adll_tap = ck_delay / adll_tap;
+
+		ca_num_adll_tap = ca_delay / adll_tap;
+		data = (ck_num_adll_tap & 0x3f) +
+			((ca_num_adll_tap & 0x3f) << 10);
+
+		/*
+		 * Set the ADLL number to the CK ADLL for Interfaces for
+		 * all Pup
+		 */
+		DEBUG_TRAINING_HW_ALG(
+			DEBUG_LEVEL_TRACE,
+			("ck_num_adll_tap %d ca_num_adll_tap %d adll_tap %d\n",
+			 ck_num_adll_tap, ca_num_adll_tap, adll_tap));
+
+		CHECK_STATUS(ddr3_tip_bus_write(dev_num, ACCESS_TYPE_UNICAST,
+						if_id, ACCESS_TYPE_MULTICAST,
+						PARAM_NOT_CARE, DDR_PHY_CONTROL,
+						0x0, data));
+	}
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h
new file mode 100644
index 0000000..6e1bab2
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_HW_ALGO_H_
+#define _DDR3_TRAINING_HW_ALGO_H_
+
+int ddr3_tip_vref(u32 dev_num);
+int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id);
+int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap);
+
+#endif /* _DDR3_TRAINING_HW_ALGO_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip.h b/drivers/ddr/marvell/a38x/ddr3_training_ip.h
new file mode 100644
index 0000000..76a1b6a0
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_H_
+#define _DDR3_TRAINING_IP_H_
+
+#include "ddr3_training_ip_def.h"
+#include "ddr_topology_def.h"
+#include "ddr_training_ip_db.h"
+
+#define DDR3_TIP_VERSION_STRING "DDR3 Training Sequence - Ver TIP-1.29."
+
+#define MAX_CS_NUM		4
+#define MAX_TOTAL_BUS_NUM	(MAX_INTERFACE_NUM * MAX_BUS_NUM)
+#define MAX_DQ_NUM		40
+
+#define GET_MIN(arg1, arg2)	((arg1) < (arg2)) ? (arg1) : (arg2)
+#define GET_MAX(arg1, arg2)	((arg1) < (arg2)) ? (arg2) : (arg1)
+
+#define INIT_CONTROLLER_MASK_BIT	0x00000001
+#define STATIC_LEVELING_MASK_BIT	0x00000002
+#define SET_LOW_FREQ_MASK_BIT		0x00000004
+#define LOAD_PATTERN_MASK_BIT		0x00000008
+#define SET_MEDIUM_FREQ_MASK_BIT	0x00000010
+#define WRITE_LEVELING_MASK_BIT		0x00000020
+#define LOAD_PATTERN_2_MASK_BIT		0x00000040
+#define READ_LEVELING_MASK_BIT		0x00000080
+#define SW_READ_LEVELING_MASK_BIT	0x00000100
+#define WRITE_LEVELING_SUPP_MASK_BIT	0x00000200
+#define PBS_RX_MASK_BIT			0x00000400
+#define PBS_TX_MASK_BIT			0x00000800
+#define SET_TARGET_FREQ_MASK_BIT	0x00001000
+#define ADJUST_DQS_MASK_BIT		0x00002000
+#define WRITE_LEVELING_TF_MASK_BIT	0x00004000
+#define LOAD_PATTERN_HIGH_MASK_BIT	0x00008000
+#define READ_LEVELING_TF_MASK_BIT	0x00010000
+#define WRITE_LEVELING_SUPP_TF_MASK_BIT	0x00020000
+#define DM_PBS_TX_MASK_BIT		0x00040000
+#define CENTRALIZATION_RX_MASK_BIT	0x00100000
+#define CENTRALIZATION_TX_MASK_BIT	0x00200000
+#define TX_EMPHASIS_MASK_BIT		0x00400000
+#define PER_BIT_READ_LEVELING_TF_MASK_BIT	0x00800000
+#define VREF_CALIBRATION_MASK_BIT	0x01000000
+
+enum hws_result {
+	TEST_FAILED = 0,
+	TEST_SUCCESS = 1,
+	NO_TEST_DONE = 2
+};
+
+enum hws_training_result {
+	RESULT_PER_BIT,
+	RESULT_PER_BYTE
+};
+
+enum auto_tune_stage {
+	INIT_CONTROLLER,
+	STATIC_LEVELING,
+	SET_LOW_FREQ,
+	LOAD_PATTERN,
+	SET_MEDIUM_FREQ,
+	WRITE_LEVELING,
+	LOAD_PATTERN_2,
+	READ_LEVELING,
+	WRITE_LEVELING_SUPP,
+	PBS_RX,
+	PBS_TX,
+	SET_TARGET_FREQ,
+	ADJUST_DQS,
+	WRITE_LEVELING_TF,
+	READ_LEVELING_TF,
+	WRITE_LEVELING_SUPP_TF,
+	DM_PBS_TX,
+	VREF_CALIBRATION,
+	CENTRALIZATION_RX,
+	CENTRALIZATION_TX,
+	TX_EMPHASIS,
+	LOAD_PATTERN_HIGH,
+	PER_BIT_READ_LEVELING_TF,
+	MAX_STAGE_LIMIT
+};
+
+enum hws_access_type {
+	ACCESS_TYPE_UNICAST = 0,
+	ACCESS_TYPE_MULTICAST = 1
+};
+
+enum hws_algo_type {
+	ALGO_TYPE_DYNAMIC,
+	ALGO_TYPE_STATIC
+};
+
+struct init_cntr_param {
+	int is_ctrl64_bit;
+	int do_mrs_phy;
+	int init_phy;
+	int msys_init;
+};
+
+struct pattern_info {
+	u8 num_of_phases_tx;
+	u8 tx_burst_size;
+	u8 delay_between_bursts;
+	u8 num_of_phases_rx;
+	u32 start_addr;
+	u8 pattern_len;
+};
+
+/* CL value for each frequency */
+struct cl_val_per_freq {
+	u8 cl_val[DDR_FREQ_LIMIT];
+};
+
+struct cs_element {
+	u8 cs_num;
+	u8 num_of_cs;
+};
+
+struct mode_info {
+	/* 32 bits representing MRS bits */
+	u32 reg_mr0[MAX_INTERFACE_NUM];
+	u32 reg_mr1[MAX_INTERFACE_NUM];
+	u32 reg_mr2[MAX_INTERFACE_NUM];
+	u32 reg_m_r3[MAX_INTERFACE_NUM];
+	/*
+	 * Each element in array represent read_data_sample register delay for
+	 * a specific interface.
+	 * Each register, 4 bits[0+CS*8 to 4+CS*8] represent Number of DDR
+	 * cycles from read command until data is ready to be fetched from
+	 * the PHY, when accessing CS.
+	 */
+	u32 read_data_sample[MAX_INTERFACE_NUM];
+	/*
+	 * Each element in array represent read_data_sample register delay for
+	 * a specific interface.
+	 * Each register, 4 bits[0+CS*8 to 4+CS*8] represent the total delay
+	 * from read command until opening the read mask, when accessing CS.
+	 * This field defines the delay in DDR cycles granularity.
+	 */
+	u32 read_data_ready[MAX_INTERFACE_NUM];
+};
+
+struct hws_tip_freq_config_info {
+	u8 is_supported;
+	u8 bw_per_freq;
+	u8 rate_per_freq;
+};
+
+struct hws_cs_config_info {
+	u32 cs_reg_value;
+	u32 cs_cbe_value;
+};
+
+struct dfx_access {
+	u8 pipe;
+	u8 client;
+};
+
+struct hws_xsb_info {
+	struct dfx_access *dfx_table;
+};
+
+int ddr3_tip_register_dq_table(u32 dev_num, u32 *table);
+int hws_ddr3_tip_select_ddr_controller(u32 dev_num, int enable);
+int hws_ddr3_tip_init_controller(u32 dev_num,
+				 struct init_cntr_param *init_cntr_prm);
+int hws_ddr3_tip_load_topology_map(u32 dev_num,
+				   struct hws_topology_map *topology);
+int hws_ddr3_tip_run_alg(u32 dev_num, enum hws_algo_type algo_type);
+int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info);
+int hws_ddr3_tip_read_training_result(u32 dev_num,
+		enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]);
+int ddr3_tip_is_pup_lock(u32 *pup_buf, enum hws_training_result read_mode);
+u8 ddr3_tip_get_buf_min(u8 *buf_ptr);
+u8 ddr3_tip_get_buf_max(u8 *buf_ptr);
+
+#endif /* _DDR3_TRAINING_IP_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h
new file mode 100644
index 0000000..5c9bfe9
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_BIST_H_
+#define _DDR3_TRAINING_IP_BIST_H_
+
+#include "ddr3_training_ip.h"
+
+enum hws_bist_operation {
+	BIST_STOP = 0,
+	BIST_START = 1
+};
+
+enum  hws_stress_jump {
+	STRESS_NONE = 0,
+	STRESS_ENABLE = 1
+};
+
+enum hws_pattern_duration {
+	DURATION_SINGLE = 0,
+	DURATION_STOP_AT_FAIL = 1,
+	DURATION_ADDRESS = 2,
+	DURATION_CONT = 4
+};
+
+struct bist_result {
+	u32 bist_error_cnt;
+	u32 bist_fail_low;
+	u32 bist_fail_high;
+	u32 bist_last_fail_addr;
+};
+
+int ddr3_tip_bist_read_result(u32 dev_num, u32 if_id,
+			      struct bist_result *pst_bist_result);
+int ddr3_tip_bist_activate(u32 dev_num, enum hws_pattern pattern,
+			   enum hws_access_type access_type,
+			   u32 if_num, enum hws_dir direction,
+			   enum hws_stress_jump addr_stress_jump,
+			   enum hws_pattern_duration duration,
+			   enum hws_bist_operation oper_type,
+			   u32 offset, u32 cs_num, u32 pattern_addr_length);
+int hws_ddr3_run_bist(u32 dev_num, enum hws_pattern pattern, u32 *result,
+		      u32 cs_num);
+int ddr3_tip_run_sweep_test(int dev_num, u32 repeat_num, u32 direction,
+			    u32 mode);
+int ddr3_tip_print_regs(u32 dev_num);
+int ddr3_tip_reg_dump(u32 dev_num);
+int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type, u32 read_type,
+		 u32 burst_length);
+
+#endif /* _DDR3_TRAINING_IP_BIST_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h
new file mode 100644
index 0000000..7c57603
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_CENTRALIZATION_H
+#define _DDR3_TRAINING_IP_CENTRALIZATION_H
+
+int ddr3_tip_centralization_tx(u32 dev_num);
+int ddr3_tip_centralization_rx(u32 dev_num);
+int ddr3_tip_print_centralization_result(u32 dev_num);
+int ddr3_tip_special_rx(u32 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_CENTRALIZATION_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h
new file mode 100644
index 0000000..c0afa77
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_DB_H_
+#define _DDR3_TRAINING_IP_DB_H_
+
+enum hws_pattern {
+	PATTERN_PBS1,
+	PATTERN_PBS2,
+	PATTERN_RL,
+	PATTERN_STATIC_PBS,
+	PATTERN_KILLER_DQ0,
+	PATTERN_KILLER_DQ1,
+	PATTERN_KILLER_DQ2,
+	PATTERN_KILLER_DQ3,
+	PATTERN_KILLER_DQ4,
+	PATTERN_KILLER_DQ5,
+	PATTERN_KILLER_DQ6,
+	PATTERN_KILLER_DQ7,
+	PATTERN_PBS3,
+	PATTERN_RL2,
+	PATTERN_TEST,
+	PATTERN_FULL_SSO0,
+	PATTERN_FULL_SSO1,
+	PATTERN_FULL_SSO2,
+	PATTERN_FULL_SSO3,
+	PATTERN_VREF,
+	PATTERN_LIMIT
+};
+
+#endif /* _DDR3_TRAINING_IP_DB_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h
new file mode 100644
index 0000000..51a66d8
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_DEF_H
+#define _DDR3_TRAINING_IP_DEF_H
+
+#include "silicon_if.h"
+
+#define PATTERN_55			0x55555555
+#define PATTERN_AA			0xaaaaaaaa
+#define PATTERN_80			0x80808080
+#define PATTERN_20			0x20202020
+#define PATTERN_01			0x01010101
+#define PATTERN_FF			0xffffffff
+#define PATTERN_00			0x00000000
+
+/* 16bit bus width patterns */
+#define PATTERN_55AA			0x5555aaaa
+#define PATTERN_00FF			0x0000ffff
+#define PATTERN_0080			0x00008080
+
+#define INVALID_VALUE			0xffffffff
+#define MAX_NUM_OF_DUNITS		32
+/*
+ * length *2 = length in words of pattern, first low address,
+ * second high address
+ */
+#define TEST_PATTERN_LENGTH		4
+#define KILLER_PATTERN_DQ_NUMBER	8
+#define SSO_DQ_NUMBER			4
+#define PATTERN_MAXIMUM_LENGTH		64
+#define ADLL_TX_LENGTH			64
+#define ADLL_RX_LENGTH			32
+
+#define PARAM_NOT_CARE			0
+
+#define READ_LEVELING_PHY_OFFSET	2
+#define WRITE_LEVELING_PHY_OFFSET	0
+
+#define MASK_ALL_BITS			0xffffffff
+
+#define CS_BIT_MASK			0xf
+
+/* DFX access */
+#define BROADCAST_ID			28
+#define MULTICAST_ID			29
+
+#define XSB_BASE_ADDR			0x00004000
+#define XSB_CTRL_0_REG			0x00000000
+#define XSB_CTRL_1_REG			0x00000004
+#define XSB_CMD_REG			0x00000008
+#define XSB_ADDRESS_REG			0x0000000c
+#define XSB_DATA_REG			0x00000010
+#define PIPE_ENABLE_ADDR		0x000f8000
+#define ENABLE_DDR_TUNING_ADDR		0x000f829c
+
+#define CLIENT_BASE_ADDR		0x00002000
+#define CLIENT_CTRL_REG			0x00000000
+
+#define TARGET_INT			0x1801
+#define TARGET_EXT			0x180e
+#define BYTE_EN				0
+#define CMD_READ			0
+#define CMD_WRITE			1
+
+#define INTERNAL_ACCESS_PORT		1
+#define EXECUTING			1
+#define ACCESS_EXT			1
+#define CS2_EXIST_BIT			2
+#define TRAINING_ID			0xf
+#define EXT_TRAINING_ID			1
+#define EXT_MODE			0x4
+
+#define GET_RESULT_STATE(res)		(res)
+#define SET_RESULT_STATE(res, state)	(res = state)
+
+#define _1K				0x00000400
+#define _4K				0x00001000
+#define _8K				0x00002000
+#define _16K				0x00004000
+#define _32K				0x00008000
+#define _64K				0x00010000
+#define _128K				0x00020000
+#define _256K				0x00040000
+#define _512K				0x00080000
+
+#define _1M				0x00100000
+#define _2M				0x00200000
+#define _4M				0x00400000
+#define _8M				0x00800000
+#define _16M				0x01000000
+#define _32M				0x02000000
+#define _64M				0x04000000
+#define _128M				0x08000000
+#define _256M				0x10000000
+#define _512M				0x20000000
+
+#define _1G				0x40000000
+#define _2G				0x80000000
+
+#define ADDR_SIZE_512MB			0x04000000
+#define ADDR_SIZE_1GB			0x08000000
+#define ADDR_SIZE_2GB			0x10000000
+#define ADDR_SIZE_4GB			0x20000000
+#define ADDR_SIZE_8GB			0x40000000
+
+enum hws_edge_compare {
+	EDGE_PF,
+	EDGE_FP,
+	EDGE_FPF,
+	EDGE_PFP
+};
+
+enum hws_control_element {
+	HWS_CONTROL_ELEMENT_ADLL,		/* per bit 1 edge */
+	HWS_CONTROL_ELEMENT_DQ_SKEW,
+	HWS_CONTROL_ELEMENT_DQS_SKEW
+};
+
+enum hws_search_dir {
+	HWS_LOW2HIGH,
+	HWS_HIGH2LOW,
+	HWS_SEARCH_DIR_LIMIT
+};
+
+enum hws_page_size {
+	PAGE_SIZE_1K,
+	PAGE_SIZE_2K
+};
+
+enum hws_operation {
+	OPERATION_READ = 0,
+	OPERATION_WRITE = 1
+};
+
+enum hws_training_ip_stat {
+	HWS_TRAINING_IP_STATUS_FAIL,
+	HWS_TRAINING_IP_STATUS_SUCCESS,
+	HWS_TRAINING_IP_STATUS_TIMEOUT
+};
+
+enum hws_ddr_cs {
+	CS_SINGLE,
+	CS_NON_SINGLE
+};
+
+enum hws_ddr_phy {
+	DDR_PHY_DATA = 0,
+	DDR_PHY_CONTROL = 1
+};
+
+enum hws_dir {
+	OPER_WRITE,
+	OPER_READ,
+	OPER_WRITE_AND_READ
+};
+
+enum hws_wl_supp {
+	PHASE_SHIFT,
+	CLOCK_SHIFT,
+	ALIGN_SHIFT
+};
+
+struct reg_data {
+	u32 reg_addr;
+	u32 reg_data;
+	u32 reg_mask;
+};
+
+#endif /* _DDR3_TRAINING_IP_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c
new file mode 100644
index 0000000..011824a
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c
@@ -0,0 +1,1354 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define PATTERN_1	0x55555555
+#define PATTERN_2	0xaaaaaaaa
+
+#define VALIDATE_TRAINING_LIMIT(e1, e2)			\
+	((((e2) - (e1) + 1) > 33) && ((e1) < 67))
+
+u32 phy_reg_bk[MAX_INTERFACE_NUM][MAX_BUS_NUM][BUS_WIDTH_IN_BITS];
+
+u32 training_res[MAX_INTERFACE_NUM * MAX_BUS_NUM * BUS_WIDTH_IN_BITS *
+		 HWS_SEARCH_DIR_LIMIT];
+
+u16 mask_results_dq_reg_map[] = {
+	RESULT_CONTROL_PUP_0_BIT_0_REG, RESULT_CONTROL_PUP_0_BIT_1_REG,
+	RESULT_CONTROL_PUP_0_BIT_2_REG, RESULT_CONTROL_PUP_0_BIT_3_REG,
+	RESULT_CONTROL_PUP_0_BIT_4_REG, RESULT_CONTROL_PUP_0_BIT_5_REG,
+	RESULT_CONTROL_PUP_0_BIT_6_REG, RESULT_CONTROL_PUP_0_BIT_7_REG,
+	RESULT_CONTROL_PUP_1_BIT_0_REG, RESULT_CONTROL_PUP_1_BIT_1_REG,
+	RESULT_CONTROL_PUP_1_BIT_2_REG, RESULT_CONTROL_PUP_1_BIT_3_REG,
+	RESULT_CONTROL_PUP_1_BIT_4_REG, RESULT_CONTROL_PUP_1_BIT_5_REG,
+	RESULT_CONTROL_PUP_1_BIT_6_REG, RESULT_CONTROL_PUP_1_BIT_7_REG,
+	RESULT_CONTROL_PUP_2_BIT_0_REG, RESULT_CONTROL_PUP_2_BIT_1_REG,
+	RESULT_CONTROL_PUP_2_BIT_2_REG, RESULT_CONTROL_PUP_2_BIT_3_REG,
+	RESULT_CONTROL_PUP_2_BIT_4_REG, RESULT_CONTROL_PUP_2_BIT_5_REG,
+	RESULT_CONTROL_PUP_2_BIT_6_REG, RESULT_CONTROL_PUP_2_BIT_7_REG,
+	RESULT_CONTROL_PUP_3_BIT_0_REG, RESULT_CONTROL_PUP_3_BIT_1_REG,
+	RESULT_CONTROL_PUP_3_BIT_2_REG, RESULT_CONTROL_PUP_3_BIT_3_REG,
+	RESULT_CONTROL_PUP_3_BIT_4_REG, RESULT_CONTROL_PUP_3_BIT_5_REG,
+	RESULT_CONTROL_PUP_3_BIT_6_REG, RESULT_CONTROL_PUP_3_BIT_7_REG,
+	RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG,
+	RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG,
+	RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG,
+	RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG,
+};
+
+u16 mask_results_pup_reg_map[] = {
+	RESULT_CONTROL_BYTE_PUP_0_REG, RESULT_CONTROL_BYTE_PUP_1_REG,
+	RESULT_CONTROL_BYTE_PUP_2_REG, RESULT_CONTROL_BYTE_PUP_3_REG,
+	RESULT_CONTROL_BYTE_PUP_4_REG
+};
+
+u16 mask_results_dq_reg_map_pup3_ecc[] = {
+	RESULT_CONTROL_PUP_0_BIT_0_REG, RESULT_CONTROL_PUP_0_BIT_1_REG,
+	RESULT_CONTROL_PUP_0_BIT_2_REG, RESULT_CONTROL_PUP_0_BIT_3_REG,
+	RESULT_CONTROL_PUP_0_BIT_4_REG, RESULT_CONTROL_PUP_0_BIT_5_REG,
+	RESULT_CONTROL_PUP_0_BIT_6_REG, RESULT_CONTROL_PUP_0_BIT_7_REG,
+	RESULT_CONTROL_PUP_1_BIT_0_REG, RESULT_CONTROL_PUP_1_BIT_1_REG,
+	RESULT_CONTROL_PUP_1_BIT_2_REG, RESULT_CONTROL_PUP_1_BIT_3_REG,
+	RESULT_CONTROL_PUP_1_BIT_4_REG, RESULT_CONTROL_PUP_1_BIT_5_REG,
+	RESULT_CONTROL_PUP_1_BIT_6_REG, RESULT_CONTROL_PUP_1_BIT_7_REG,
+	RESULT_CONTROL_PUP_2_BIT_0_REG, RESULT_CONTROL_PUP_2_BIT_1_REG,
+	RESULT_CONTROL_PUP_2_BIT_2_REG, RESULT_CONTROL_PUP_2_BIT_3_REG,
+	RESULT_CONTROL_PUP_2_BIT_4_REG, RESULT_CONTROL_PUP_2_BIT_5_REG,
+	RESULT_CONTROL_PUP_2_BIT_6_REG, RESULT_CONTROL_PUP_2_BIT_7_REG,
+	RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG,
+	RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG,
+	RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG,
+	RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG,
+	RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG,
+	RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG,
+	RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG,
+	RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG,
+};
+
+u16 mask_results_pup_reg_map_pup3_ecc[] = {
+	RESULT_CONTROL_BYTE_PUP_0_REG, RESULT_CONTROL_BYTE_PUP_1_REG,
+	RESULT_CONTROL_BYTE_PUP_2_REG, RESULT_CONTROL_BYTE_PUP_4_REG,
+	RESULT_CONTROL_BYTE_PUP_4_REG
+};
+
+struct pattern_info pattern_table_16[] = {
+	/*
+	 * num tx phases, tx burst, delay between, rx pattern,
+	 * start_address, pattern_len
+	 */
+	{1, 1, 2, 1, 0x0080, 2},	/* PATTERN_PBS1 */
+	{1, 1, 2, 1, 0x00c0, 2},	/* PATTERN_PBS2 */
+	{1, 1, 2, 1, 0x0100, 2},	/* PATTERN_RL */
+	{0xf, 0x7, 2, 0x7, 0x0140, 16},	/* PATTERN_STATIC_PBS */
+	{0xf, 0x7, 2, 0x7, 0x0190, 16},	/* PATTERN_KILLER_DQ0 */
+	{0xf, 0x7, 2, 0x7, 0x01d0, 16},	/* PATTERN_KILLER_DQ1 */
+	{0xf, 0x7, 2, 0x7, 0x0210, 16},	/* PATTERN_KILLER_DQ2 */
+	{0xf, 0x7, 2, 0x7, 0x0250, 16},	/* PATTERN_KILLER_DQ3 */
+	{0xf, 0x7, 2, 0x7, 0x0290, 16},	/* PATTERN_KILLER_DQ4 */
+	{0xf, 0x7, 2, 0x7, 0x02d0, 16},	/* PATTERN_KILLER_DQ5 */
+	{0xf, 0x7, 2, 0x7, 0x0310, 16},	/* PATTERN_KILLER_DQ6 */
+	{0xf, 0x7, 2, 0x7, 0x0350, 16},	/* PATTERN_KILLER_DQ7 */
+	{1, 1, 2, 1, 0x0380, 2},	/* PATTERN_PBS3 */
+	{1, 1, 2, 1, 0x0000, 2},	/* PATTERN_RL2 */
+	{1, 1, 2, 1, 0x0040, 2},	/* PATTERN_TEST */
+	{0xf, 0x7, 2, 0x7, 0x03c0, 16},	/* PATTERN_FULL_SSO_1T */
+	{0xf, 0x7, 2, 0x7, 0x0400, 16},	/* PATTERN_FULL_SSO_2T */
+	{0xf, 0x7, 2, 0x7, 0x0440, 16},	/* PATTERN_FULL_SSO_3T */
+	{0xf, 0x7, 2, 0x7, 0x0480, 16},	/* PATTERN_FULL_SSO_4T */
+	{0xf, 0x7, 2, 0x7, 0x04c0, 16}	/* PATTERN_VREF */
+	/*Note: actual start_address is <<3 of defined addess */
+};
+
+struct pattern_info pattern_table_32[] = {
+	/*
+	 * num tx phases, tx burst, delay between, rx pattern,
+	 * start_address, pattern_len
+	 */
+	{3, 3, 2, 3, 0x0080, 4},	/* PATTERN_PBS1 */
+	{3, 3, 2, 3, 0x00c0, 4},	/* PATTERN_PBS2 */
+	{3, 3, 2, 3, 0x0100, 4},	/* PATTERN_RL */
+	{0x1f, 0xf, 2, 0xf, 0x0140, 32},	/* PATTERN_STATIC_PBS */
+	{0x1f, 0xf, 2, 0xf, 0x0190, 32},	/* PATTERN_KILLER_DQ0 */
+	{0x1f, 0xf, 2, 0xf, 0x01d0, 32},	/* PATTERN_KILLER_DQ1 */
+	{0x1f, 0xf, 2, 0xf, 0x0210, 32},	/* PATTERN_KILLER_DQ2 */
+	{0x1f, 0xf, 2, 0xf, 0x0250, 32},	/* PATTERN_KILLER_DQ3 */
+	{0x1f, 0xf, 2, 0xf, 0x0290, 32},	/* PATTERN_KILLER_DQ4 */
+	{0x1f, 0xf, 2, 0xf, 0x02d0, 32},	/* PATTERN_KILLER_DQ5 */
+	{0x1f, 0xf, 2, 0xf, 0x0310, 32},	/* PATTERN_KILLER_DQ6 */
+	{0x1f, 0xf, 2, 0xf, 0x0350, 32},	/* PATTERN_KILLER_DQ7 */
+	{3, 3, 2, 3, 0x0380, 4},	/* PATTERN_PBS3 */
+	{3, 3, 2, 3, 0x0000, 4},	/* PATTERN_RL2 */
+	{3, 3, 2, 3, 0x0040, 4},	/* PATTERN_TEST */
+	{0x1f, 0xf, 2, 0xf, 0x03c0, 32},	/* PATTERN_FULL_SSO_1T */
+	{0x1f, 0xf, 2, 0xf, 0x0400, 32},	/* PATTERN_FULL_SSO_2T */
+	{0x1f, 0xf, 2, 0xf, 0x0440, 32},	/* PATTERN_FULL_SSO_3T */
+	{0x1f, 0xf, 2, 0xf, 0x0480, 32},	/* PATTERN_FULL_SSO_4T */
+	{0x1f, 0xf, 2, 0xf, 0x04c0, 32}	/* PATTERN_VREF */
+	/*Note: actual start_address is <<3 of defined addess */
+};
+
+u32 train_dev_num;
+enum hws_ddr_cs traintrain_cs_type;
+u32 train_pup_num;
+enum hws_training_result train_result_type;
+enum hws_control_element train_control_element;
+enum hws_search_dir traine_search_dir;
+enum hws_dir train_direction;
+u32 train_if_select;
+u32 train_init_value;
+u32 train_number_iterations;
+enum hws_pattern train_pattern;
+enum hws_edge_compare train_edge_compare;
+u32 train_cs_num;
+u32 train_if_acess, train_if_id, train_pup_access;
+u32 max_polling_for_done = 1000000;
+
+u32 *ddr3_tip_get_buf_ptr(u32 dev_num, enum hws_search_dir search,
+			  enum hws_training_result result_type,
+			  u32 interface_num)
+{
+	u32 *buf_ptr = NULL;
+
+	buf_ptr = &training_res
+		[MAX_INTERFACE_NUM * MAX_BUS_NUM * BUS_WIDTH_IN_BITS * search +
+		 interface_num * MAX_BUS_NUM * BUS_WIDTH_IN_BITS];
+
+	return buf_ptr;
+}
+
+/*
+ * IP Training search
+ * Note: for one edge search only from fail to pass, else jitter can
+ * be be entered into solution.
+ */
+int ddr3_tip_ip_training(u32 dev_num, enum hws_access_type access_type,
+			 u32 interface_num,
+			 enum hws_access_type pup_access_type,
+			 u32 pup_num, enum hws_training_result result_type,
+			 enum hws_control_element control_element,
+			 enum hws_search_dir search_dir, enum hws_dir direction,
+			 u32 interface_mask, u32 init_value, u32 num_iter,
+			 enum hws_pattern pattern,
+			 enum hws_edge_compare edge_comp,
+			 enum hws_ddr_cs cs_type, u32 cs_num,
+			 enum hws_training_ip_stat *train_status)
+{
+	u32 mask_dq_num_of_regs, mask_pup_num_of_regs, index_cnt, poll_cnt,
+		reg_data, pup_id;
+	u32 tx_burst_size;
+	u32 delay_between_burst;
+	u32 rd_mode;
+	u32 read_data[MAX_INTERFACE_NUM];
+	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+	u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+	u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (pup_num >= tm->num_of_bus_per_interface) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("pup_num %d not valid\n", pup_num));
+	}
+	if (interface_num >= MAX_INTERFACE_NUM) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("if_id %d not valid\n",
+					  interface_num));
+	}
+	if (train_status == NULL) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("error param 4\n"));
+		return MV_BAD_PARAM;
+	}
+
+	/* load pattern */
+	if (cs_type == CS_SINGLE) {
+		/* All CSs to CS0     */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, interface_num,
+			      CS_ENABLE_REG, 1 << 3, 1 << 3));
+		/* All CSs to CS0     */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, interface_num,
+			      ODPG_DATA_CONTROL_REG,
+			      (0x3 | (effective_cs << 26)), 0xc000003));
+	} else {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, interface_num,
+			      CS_ENABLE_REG, 0, 1 << 3));
+		/*  CS select */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, interface_num,
+			      ODPG_DATA_CONTROL_REG, 0x3 | cs_num << 26,
+			      0x3 | 3 << 26));
+	}
+
+	/* load pattern to ODPG */
+	ddr3_tip_load_pattern_to_odpg(dev_num, access_type, interface_num,
+				      pattern,
+				      pattern_table[pattern].start_addr);
+	tx_burst_size =	(direction == OPER_WRITE) ?
+		pattern_table[pattern].tx_burst_size : 0;
+	delay_between_burst = (direction == OPER_WRITE) ? 2 : 0;
+	rd_mode = (direction == OPER_WRITE) ? 1 : 0;
+	CHECK_STATUS(ddr3_tip_configure_odpg
+		     (dev_num, access_type, interface_num, direction,
+		      pattern_table[pattern].num_of_phases_tx, tx_burst_size,
+		      pattern_table[pattern].num_of_phases_rx,
+		      delay_between_burst, rd_mode, effective_cs, STRESS_NONE,
+		      DURATION_SINGLE));
+	reg_data = (direction == OPER_READ) ? 0 : (0x3 << 30);
+	reg_data |= (direction == OPER_READ) ? 0x60 : 0xfa;
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, interface_num,
+		      ODPG_WRITE_READ_MODE_ENABLE_REG, reg_data,
+		      MASK_ALL_BITS));
+	reg_data = (edge_comp == EDGE_PF || edge_comp == EDGE_FP) ? 0 : 1 << 6;
+	reg_data |= (edge_comp == EDGE_PF || edge_comp == EDGE_PFP) ?
+		(1 << 7) : 0;
+
+	/* change from Pass to Fail will lock the result */
+	if (pup_access_type == ACCESS_TYPE_MULTICAST)
+		reg_data |= 0xe << 14;
+	else
+		reg_data |= pup_num << 14;
+
+	if (edge_comp == EDGE_FP) {
+		/* don't search for readl edge change, only the state */
+		reg_data |= (0 << 20);
+	} else if (edge_comp == EDGE_FPF) {
+		reg_data |= (0 << 20);
+	} else {
+		reg_data |= (3 << 20);
+	}
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, interface_num,
+		      ODPG_TRAINING_CONTROL_REG,
+		      reg_data | (0x7 << 8) | (0x7 << 11),
+		      (0x3 | (0x3 << 2) | (0x3 << 6) | (1 << 5) | (0x7 << 8) |
+		       (0x7 << 11) | (0xf << 14) | (0x3 << 18) | (3 << 20))));
+	reg_data = (search_dir == HWS_LOW2HIGH) ? 0 : (1 << 8);
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, interface_num, ODPG_OBJ1_OPCODE_REG,
+		      1 | reg_data | init_value << 9 | (1 << 25) | (1 << 26),
+		      0xff | (1 << 8) | (0xffff << 9) | (1 << 25) | (1 << 26)));
+
+	/*
+	 * Write2_dunit(0x10b4, Number_iteration , [15:0])
+	 * Max number of iterations
+	 */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, interface_num,
+				       ODPG_OBJ1_ITER_CNT_REG, num_iter,
+				       0xffff));
+	if (control_element == HWS_CONTROL_ELEMENT_DQ_SKEW &&
+	    direction == OPER_READ) {
+		/*
+		 * Write2_dunit(0x10c0, 0x5f , [7:0])
+		 * MC PBS Reg Address at DDR PHY
+		 */
+		reg_data = 0x5f +
+			effective_cs * CALIBRATED_OBJECTS_REG_ADDR_OFFSET;
+	} else if (control_element == HWS_CONTROL_ELEMENT_DQ_SKEW &&
+		   direction == OPER_WRITE) {
+		reg_data = 0x1f +
+			effective_cs * CALIBRATED_OBJECTS_REG_ADDR_OFFSET;
+	} else if (control_element == HWS_CONTROL_ELEMENT_ADLL &&
+		   direction == OPER_WRITE) {
+		/*
+		 * LOOP         0x00000001 + 4*n:
+		 * where n (0-3) represents M_CS number
+		 */
+		/*
+		 * Write2_dunit(0x10c0, 0x1 , [7:0])
+		 * ADLL WR Reg Address at DDR PHY
+		 */
+		reg_data = 1 + effective_cs * CS_REGISTER_ADDR_OFFSET;
+	} else if (control_element == HWS_CONTROL_ELEMENT_ADLL &&
+		   direction == OPER_READ) {
+		/* ADLL RD Reg Address at DDR PHY */
+		reg_data = 3 + effective_cs * CS_REGISTER_ADDR_OFFSET;
+	} else if (control_element == HWS_CONTROL_ELEMENT_DQS_SKEW &&
+		   direction == OPER_WRITE) {
+		/* TBD not defined in 0.5.0 requirement  */
+	} else if (control_element == HWS_CONTROL_ELEMENT_DQS_SKEW &&
+		   direction == OPER_READ) {
+		/* TBD not defined in 0.5.0 requirement */
+	}
+
+	reg_data |= (0x6 << 28);
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, interface_num, CALIB_OBJ_PRFA_REG,
+		      reg_data | (init_value << 8),
+		      0xff | (0xffff << 8) | (0xf << 24) | (u32) (0xf << 28)));
+
+	mask_dq_num_of_regs = tm->num_of_bus_per_interface * BUS_WIDTH_IN_BITS;
+	mask_pup_num_of_regs = tm->num_of_bus_per_interface;
+
+	if (result_type == RESULT_PER_BIT) {
+		for (index_cnt = 0; index_cnt < mask_dq_num_of_regs;
+		     index_cnt++) {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, interface_num,
+				      mask_results_dq_reg_map[index_cnt], 0,
+				      1 << 24));
+		}
+
+		/* Mask disabled buses */
+		for (pup_id = 0; pup_id < tm->num_of_bus_per_interface;
+		     pup_id++) {
+			if (IS_ACTIVE(tm->bus_act_mask, pup_id) == 1)
+				continue;
+
+			for (index_cnt = (mask_dq_num_of_regs - pup_id * 8);
+			     index_cnt <
+				     (mask_dq_num_of_regs - (pup_id + 1) * 8);
+			     index_cnt++) {
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, access_type,
+					      interface_num,
+					      mask_results_dq_reg_map
+					      [index_cnt], (1 << 24), 1 << 24));
+			}
+		}
+
+		for (index_cnt = 0; index_cnt < mask_pup_num_of_regs;
+		     index_cnt++) {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, interface_num,
+				      mask_results_pup_reg_map[index_cnt],
+				      (1 << 24), 1 << 24));
+		}
+	} else if (result_type == RESULT_PER_BYTE) {
+		/* write to adll */
+		for (index_cnt = 0; index_cnt < mask_pup_num_of_regs;
+		     index_cnt++) {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, interface_num,
+				      mask_results_pup_reg_map[index_cnt], 0,
+				      1 << 24));
+		}
+		for (index_cnt = 0; index_cnt < mask_dq_num_of_regs;
+		     index_cnt++) {
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, access_type, interface_num,
+				      mask_results_dq_reg_map[index_cnt],
+				      (1 << 24), (1 << 24)));
+		}
+	}
+
+	/* Start Training Trigger */
+	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, interface_num,
+				       ODPG_TRAINING_TRIGGER_REG, 1, 1));
+	/* wait for all RFU tests to finish (or timeout) */
+	/* WA for 16 bit mode, more investigation needed */
+	mdelay(1);
+
+	/* Training "Done ?" */
+	for (index_cnt = 0; index_cnt < MAX_INTERFACE_NUM; index_cnt++) {
+		if (IS_ACTIVE(tm->if_act_mask, index_cnt) == 0)
+			continue;
+
+		if (interface_mask & (1 << index_cnt)) {
+			/* need to check results for this Dunit */
+			for (poll_cnt = 0; poll_cnt < max_polling_for_done;
+			     poll_cnt++) {
+				CHECK_STATUS(ddr3_tip_if_read
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      index_cnt,
+					      ODPG_TRAINING_STATUS_REG,
+					      &reg_data, MASK_ALL_BITS));
+				if ((reg_data & 0x2) != 0) {
+					/*done */
+					train_status[index_cnt] =
+						HWS_TRAINING_IP_STATUS_SUCCESS;
+					break;
+				}
+			}
+
+			if (poll_cnt == max_polling_for_done) {
+				train_status[index_cnt] =
+					HWS_TRAINING_IP_STATUS_TIMEOUT;
+			}
+		}
+		/* Be sure that ODPG done */
+		CHECK_STATUS(is_odpg_access_done(dev_num, index_cnt));
+	}
+
+	/* Write ODPG done in Dunit */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_STATUS_DONE_REG, 0, 0x1));
+
+	/* wait for all Dunit tests to finish (or timeout) */
+	/* Training "Done ?" */
+	/* Training "Pass ?" */
+	for (index_cnt = 0; index_cnt < MAX_INTERFACE_NUM; index_cnt++) {
+		if (IS_ACTIVE(tm->if_act_mask, index_cnt) == 0)
+			continue;
+
+		if (interface_mask & (1 << index_cnt)) {
+			/* need to check results for this Dunit */
+			for (poll_cnt = 0; poll_cnt < max_polling_for_done;
+			     poll_cnt++) {
+				CHECK_STATUS(ddr3_tip_if_read
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      index_cnt,
+					      ODPG_TRAINING_TRIGGER_REG,
+					      read_data, MASK_ALL_BITS));
+				reg_data = read_data[index_cnt];
+				if ((reg_data & 0x2) != 0) {
+					/* done */
+					if ((reg_data & 0x4) == 0) {
+						train_status[index_cnt] =
+							HWS_TRAINING_IP_STATUS_SUCCESS;
+					} else {
+						train_status[index_cnt] =
+							HWS_TRAINING_IP_STATUS_FAIL;
+					}
+					break;
+				}
+			}
+
+			if (poll_cnt == max_polling_for_done) {
+				train_status[index_cnt] =
+					HWS_TRAINING_IP_STATUS_TIMEOUT;
+			}
+		}
+	}
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+	return MV_OK;
+}
+
+/*
+ * Load expected Pattern to ODPG
+ */
+int ddr3_tip_load_pattern_to_odpg(u32 dev_num, enum hws_access_type access_type,
+				  u32 if_id, enum hws_pattern pattern,
+				  u32 load_addr)
+{
+	u32 pattern_length_cnt = 0;
+	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+
+	for (pattern_length_cnt = 0;
+	     pattern_length_cnt < pattern_table[pattern].pattern_len;
+	     pattern_length_cnt++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      ODPG_PATTERN_DATA_LOW_REG,
+			      pattern_table_get_word(dev_num, pattern,
+						     (u8) (pattern_length_cnt *
+							   2)), MASK_ALL_BITS));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      ODPG_PATTERN_DATA_HI_REG,
+			      pattern_table_get_word(dev_num, pattern,
+						     (u8) (pattern_length_cnt *
+							   2 + 1)),
+			      MASK_ALL_BITS));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, access_type, if_id,
+			      ODPG_PATTERN_ADDR_REG, pattern_length_cnt,
+			      MASK_ALL_BITS));
+	}
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, access_type, if_id,
+		      ODPG_PATTERN_ADDR_OFFSET_REG, load_addr, MASK_ALL_BITS));
+
+	return MV_OK;
+}
+
+/*
+ * Configure ODPG
+ */
+int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type,
+			    u32 if_id, enum hws_dir direction, u32 tx_phases,
+			    u32 tx_burst_size, u32 rx_phases,
+			    u32 delay_between_burst, u32 rd_mode, u32 cs_num,
+			    u32 addr_stress_jump, u32 single_pattern)
+{
+	u32 data_value = 0;
+	int ret;
+
+	data_value = ((single_pattern << 2) | (tx_phases << 5) |
+		      (tx_burst_size << 11) | (delay_between_burst << 15) |
+		      (rx_phases << 21) | (rd_mode << 25) | (cs_num << 26) |
+		      (addr_stress_jump << 29));
+	ret = ddr3_tip_if_write(dev_num, access_type, if_id,
+				ODPG_DATA_CONTROL_REG, data_value, 0xaffffffc);
+	if (ret != MV_OK)
+		return ret;
+
+	return MV_OK;
+}
+
+int ddr3_tip_process_result(u32 *ar_result, enum hws_edge e_edge,
+			    enum hws_edge_search e_edge_search,
+			    u32 *edge_result)
+{
+	u32 i, res;
+	int tap_val, max_val = -10000, min_val = 10000;
+	int lock_success = 1;
+
+	for (i = 0; i < BUS_WIDTH_IN_BITS; i++) {
+		res = GET_LOCK_RESULT(ar_result[i]);
+		if (res == 0) {
+			lock_success = 0;
+			break;
+		}
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("lock failed for bit %d\n", i));
+	}
+
+	if (lock_success == 1) {
+		for (i = 0; i < BUS_WIDTH_IN_BITS; i++) {
+			tap_val = GET_TAP_RESULT(ar_result[i], e_edge);
+			if (tap_val > max_val)
+				max_val = tap_val;
+			if (tap_val < min_val)
+				min_val = tap_val;
+			if (e_edge_search == TRAINING_EDGE_MAX)
+				*edge_result = (u32) max_val;
+			else
+				*edge_result = (u32) min_val;
+
+			DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+						 ("i %d ar_result[i] 0x%x tap_val %d max_val %d min_val %d Edge_result %d\n",
+						  i, ar_result[i], tap_val,
+						  max_val, min_val,
+						  *edge_result));
+		}
+	} else {
+		return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Read training search result
+ */
+int ddr3_tip_read_training_result(u32 dev_num, u32 if_id,
+				  enum hws_access_type pup_access_type,
+				  u32 pup_num, u32 bit_num,
+				  enum hws_search_dir search,
+				  enum hws_dir direction,
+				  enum hws_training_result result_type,
+				  enum hws_training_load_op operation,
+				  u32 cs_num_type, u32 **load_res,
+				  int is_read_from_db, u8 cons_tap,
+				  int is_check_result_validity)
+{
+	u32 reg_offset, pup_cnt, start_pup, end_pup, start_reg, end_reg;
+	u32 *interface_train_res = NULL;
+	u16 *reg_addr = NULL;
+	u32 read_data[MAX_INTERFACE_NUM];
+	u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+	u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/*
+	 * Agreed assumption: all CS mask contain same number of bits,
+	 * i.e. in multi CS, the number of CS per memory is the same for
+	 * all pups
+	 */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id, CS_ENABLE_REG,
+		      (cs_num_type == 0) ? 1 << 3 : 0, (1 << 3)));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+		      ODPG_DATA_CONTROL_REG, (cs_num_type << 26), (3 << 26)));
+	DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_TRACE,
+				 ("Read_from_d_b %d cs_type %d oper %d result_type %d direction %d search %d pup_num %d if_id %d pup_access_type %d\n",
+				  is_read_from_db, cs_num_type, operation,
+				  result_type, direction, search, pup_num,
+				  if_id, pup_access_type));
+
+	if ((load_res == NULL) && (is_read_from_db == 1)) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("ddr3_tip_read_training_result load_res = NULL"));
+		return MV_FAIL;
+	}
+	if (pup_num >= tm->num_of_bus_per_interface) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("pup_num %d not valid\n", pup_num));
+	}
+	if (if_id >= MAX_INTERFACE_NUM) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("if_id %d not valid\n", if_id));
+	}
+	if (result_type == RESULT_PER_BIT)
+		reg_addr = mask_results_dq_reg_map;
+	else
+		reg_addr = mask_results_pup_reg_map;
+	if (pup_access_type == ACCESS_TYPE_UNICAST) {
+		start_pup = pup_num;
+		end_pup = pup_num;
+	} else {		/*pup_access_type == ACCESS_TYPE_MULTICAST) */
+
+		start_pup = 0;
+		end_pup = tm->num_of_bus_per_interface - 1;
+	}
+
+	for (pup_cnt = start_pup; pup_cnt <= end_pup; pup_cnt++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup_cnt);
+		DEBUG_TRAINING_IP_ENGINE(
+			DEBUG_LEVEL_TRACE,
+			("if_id %d start_pup %d end_pup %d pup_cnt %d\n",
+			 if_id, start_pup, end_pup, pup_cnt));
+		if (result_type == RESULT_PER_BIT) {
+			if (bit_num == ALL_BITS_PER_PUP) {
+				start_reg = pup_cnt * BUS_WIDTH_IN_BITS;
+				end_reg = (pup_cnt + 1) * BUS_WIDTH_IN_BITS - 1;
+			} else {
+				start_reg =
+					pup_cnt * BUS_WIDTH_IN_BITS + bit_num;
+				end_reg = pup_cnt * BUS_WIDTH_IN_BITS + bit_num;
+			}
+		} else {
+			start_reg = pup_cnt;
+			end_reg = pup_cnt;
+		}
+
+		interface_train_res =
+			ddr3_tip_get_buf_ptr(dev_num, search, result_type,
+					     if_id);
+		DEBUG_TRAINING_IP_ENGINE(
+			DEBUG_LEVEL_TRACE,
+			("start_reg %d end_reg %d interface %p\n",
+			 start_reg, end_reg, interface_train_res));
+		if (interface_train_res == NULL) {
+			DEBUG_TRAINING_IP_ENGINE(
+				DEBUG_LEVEL_ERROR,
+				("interface_train_res is NULL\n"));
+			return MV_FAIL;
+		}
+
+		for (reg_offset = start_reg; reg_offset <= end_reg;
+		     reg_offset++) {
+			if (operation == TRAINING_LOAD_OPERATION_UNLOAD) {
+				if (is_read_from_db == 0) {
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      reg_addr[reg_offset],
+						      read_data,
+						      MASK_ALL_BITS));
+					if (is_check_result_validity == 1) {
+						if ((read_data[if_id] &
+						     0x02000000) == 0) {
+							interface_train_res
+								[reg_offset] =
+								0x02000000 +
+								64 + cons_tap;
+						} else {
+							interface_train_res
+								[reg_offset] =
+								read_data
+								[if_id] +
+								cons_tap;
+						}
+					} else {
+						interface_train_res[reg_offset]
+							= read_data[if_id] +
+							cons_tap;
+					}
+					DEBUG_TRAINING_IP_ENGINE
+						(DEBUG_LEVEL_TRACE,
+						 ("reg_offset %d value 0x%x addr %p\n",
+						  reg_offset,
+						  interface_train_res
+						  [reg_offset],
+						  &interface_train_res
+						  [reg_offset]));
+				} else {
+					*load_res =
+						&interface_train_res[start_reg];
+					DEBUG_TRAINING_IP_ENGINE
+						(DEBUG_LEVEL_TRACE,
+						 ("*load_res %p\n", *load_res));
+				}
+			} else {
+				DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_TRACE,
+							 ("not supported\n"));
+			}
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Load all pattern to memory using ODPG
+ */
+int ddr3_tip_load_all_pattern_to_mem(u32 dev_num)
+{
+	u32 pattern = 0, if_id;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		training_result[training_stage][if_id] = TEST_SUCCESS;
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/* enable single cs */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, (1 << 3), (1 << 3)));
+	}
+
+	for (pattern = 0; pattern < PATTERN_LIMIT; pattern++)
+		ddr3_tip_load_pattern_to_mem(dev_num, pattern);
+
+	return MV_OK;
+}
+
+/*
+ * Wait till ODPG access is ready
+ */
+int is_odpg_access_done(u32 dev_num, u32 if_id)
+{
+	u32 poll_cnt = 0, data_value;
+	u32 read_data[MAX_INTERFACE_NUM];
+
+	for (poll_cnt = 0; poll_cnt < MAX_POLLING_ITERATIONS; poll_cnt++) {
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      ODPG_BIST_DONE, read_data, MASK_ALL_BITS));
+		data_value = read_data[if_id];
+		if (((data_value >> ODPG_BIST_DONE_BIT_OFFS) & 0x1) ==
+		    ODPG_BIST_DONE_BIT_VALUE) {
+				data_value = data_value & 0xfffffffe;
+				CHECK_STATUS(ddr3_tip_if_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ODPG_BIST_DONE, data_value,
+					      MASK_ALL_BITS));
+				break;
+			}
+	}
+
+	if (poll_cnt >= MAX_POLLING_ITERATIONS) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("Bist Activate: poll failure 2\n"));
+		return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Load specific pattern to memory using ODPG
+ */
+int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern pattern)
+{
+	u32 reg_data, if_id;
+	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* load pattern to memory */
+	/*
+	 * Write Tx mode, CS0, phases, Tx burst size, delay between burst,
+	 * rx pattern phases
+	 */
+	reg_data =
+		0x1 | (pattern_table[pattern].num_of_phases_tx << 5) |
+		(pattern_table[pattern].tx_burst_size << 11) |
+		(pattern_table[pattern].delay_between_bursts << 15) |
+		(pattern_table[pattern].num_of_phases_rx << 21) | (0x1 << 25) |
+		(effective_cs << 26);
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_DATA_CONTROL_REG, reg_data, MASK_ALL_BITS));
+	/* ODPG Write enable from BIST */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_DATA_CONTROL_REG, (0x1 | (effective_cs << 26)),
+		      0xc000003));
+	/* disable error injection */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_WRITE_DATA_ERROR_REG, 0, 0x1));
+	/* load pattern to ODPG */
+	ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST,
+				      PARAM_NOT_CARE, pattern,
+				      pattern_table[pattern].start_addr);
+
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		if (IS_ACTIVE(tm->if_act_mask, if_id) == 0)
+			continue;
+
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1498,
+			      0x3, 0xf));
+	}
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_ENABLE_REG, 0x1 << ODPG_ENABLE_OFFS,
+		      (0x1 << ODPG_ENABLE_OFFS)));
+
+	mdelay(1);
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(is_odpg_access_done(dev_num, if_id));
+	}
+
+	/* Disable ODPG and stop write to memory */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_DATA_CONTROL_REG, (0x1 << 30), (u32) (0x3 << 30)));
+
+	/* return to default */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+	/* Disable odt0 for CS0 training - need to adjust for multy CS */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x1498,
+		      0x0, 0xf));
+
+	/* temporary added */
+	mdelay(1);
+
+	return MV_OK;
+}
+
+/*
+ * Load specific pattern to memory using CPU
+ */
+int ddr3_tip_load_pattern_to_mem_by_cpu(u32 dev_num, enum hws_pattern pattern,
+					u32 offset)
+{
+	/* eranba - TBD */
+	return MV_OK;
+}
+
+/*
+ * Training search routine
+ */
+int ddr3_tip_ip_training_wrapper_int(u32 dev_num,
+				     enum hws_access_type access_type,
+				     u32 if_id,
+				     enum hws_access_type pup_access_type,
+				     u32 pup_num, u32 bit_num,
+				     enum hws_training_result result_type,
+				     enum hws_control_element control_element,
+				     enum hws_search_dir search_dir,
+				     enum hws_dir direction,
+				     u32 interface_mask, u32 init_value_l2h,
+				     u32 init_value_h2l, u32 num_iter,
+				     enum hws_pattern pattern,
+				     enum hws_edge_compare edge_comp,
+				     enum hws_ddr_cs train_cs_type, u32 cs_num,
+				     enum hws_training_ip_stat *train_status)
+{
+	u32 interface_num = 0, start_if, end_if, init_value_used;
+	enum hws_search_dir search_dir_id, start_search, end_search;
+	enum hws_edge_compare edge_comp_used;
+	u8 cons_tap = (direction == OPER_WRITE) ? (64) : (0);
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (train_status == NULL) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("train_status is NULL\n"));
+		return MV_FAIL;
+	}
+
+	if ((train_cs_type > CS_NON_SINGLE) ||
+	    (edge_comp >= EDGE_PFP) ||
+	    (pattern >= PATTERN_LIMIT) ||
+	    (direction > OPER_WRITE_AND_READ) ||
+	    (search_dir > HWS_HIGH2LOW) ||
+	    (control_element > HWS_CONTROL_ELEMENT_DQS_SKEW) ||
+	    (result_type > RESULT_PER_BYTE) ||
+	    (pup_num >= tm->num_of_bus_per_interface) ||
+	    (pup_access_type > ACCESS_TYPE_MULTICAST) ||
+	    (if_id > 11) || (access_type > ACCESS_TYPE_MULTICAST)) {
+		DEBUG_TRAINING_IP_ENGINE(
+			DEBUG_LEVEL_ERROR,
+			("wrong parameter train_cs_type %d edge_comp %d pattern %d direction %d search_dir %d control_element %d result_type %d pup_num %d pup_access_type %d if_id %d access_type %d\n",
+			 train_cs_type, edge_comp, pattern, direction,
+			 search_dir, control_element, result_type, pup_num,
+			 pup_access_type, if_id, access_type));
+		return MV_FAIL;
+	}
+
+	if (edge_comp == EDGE_FPF) {
+		start_search = HWS_LOW2HIGH;
+		end_search = HWS_HIGH2LOW;
+		edge_comp_used = EDGE_FP;
+	} else {
+		start_search = search_dir;
+		end_search = search_dir;
+		edge_comp_used = edge_comp;
+	}
+
+	for (search_dir_id = start_search; search_dir_id <= end_search;
+	     search_dir_id++) {
+		init_value_used = (search_dir_id == HWS_LOW2HIGH) ?
+			init_value_l2h : init_value_h2l;
+		DEBUG_TRAINING_IP_ENGINE(
+			DEBUG_LEVEL_TRACE,
+			("dev_num %d, access_type %d, if_id %d, pup_access_type %d,pup_num %d, result_type %d, control_element %d search_dir_id %d, direction %d, interface_mask %d,init_value_used %d, num_iter %d, pattern %d, edge_comp_used %d, train_cs_type %d, cs_num %d\n",
+			 dev_num, access_type, if_id, pup_access_type, pup_num,
+			 result_type, control_element, search_dir_id,
+			 direction, interface_mask, init_value_used, num_iter,
+			 pattern, edge_comp_used, train_cs_type, cs_num));
+
+		ddr3_tip_ip_training(dev_num, access_type, if_id,
+				     pup_access_type, pup_num, result_type,
+				     control_element, search_dir_id, direction,
+				     interface_mask, init_value_used, num_iter,
+				     pattern, edge_comp_used, train_cs_type,
+				     cs_num, train_status);
+		if (access_type == ACCESS_TYPE_MULTICAST) {
+			start_if = 0;
+			end_if = MAX_INTERFACE_NUM - 1;
+		} else {
+			start_if = if_id;
+			end_if = if_id;
+		}
+
+		for (interface_num = start_if; interface_num <= end_if;
+		     interface_num++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, interface_num);
+			cs_num = 0;
+			CHECK_STATUS(ddr3_tip_read_training_result
+				     (dev_num, interface_num, pup_access_type,
+				      pup_num, bit_num, search_dir_id,
+				      direction, result_type,
+				      TRAINING_LOAD_OPERATION_UNLOAD,
+				      train_cs_type, NULL, 0, cons_tap,
+				      0));
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Training search & read result routine
+ */
+int ddr3_tip_ip_training_wrapper(u32 dev_num, enum hws_access_type access_type,
+				 u32 if_id,
+				 enum hws_access_type pup_access_type,
+				 u32 pup_num,
+				 enum hws_training_result result_type,
+				 enum hws_control_element control_element,
+				 enum hws_search_dir search_dir,
+				 enum hws_dir direction, u32 interface_mask,
+				 u32 init_value_l2h, u32 init_value_h2l,
+				 u32 num_iter, enum hws_pattern pattern,
+				 enum hws_edge_compare edge_comp,
+				 enum hws_ddr_cs train_cs_type, u32 cs_num,
+				 enum hws_training_ip_stat *train_status)
+{
+	u8 e1, e2;
+	u32 interface_cnt, bit_id, start_if, end_if, bit_end = 0;
+	u32 *result[HWS_SEARCH_DIR_LIMIT] = { 0 };
+	u8 cons_tap = (direction == OPER_WRITE) ? (64) : (0);
+	u8 bit_bit_mask[MAX_BUS_NUM] = { 0 }, bit_bit_mask_active = 0;
+	u8 pup_id;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (pup_num >= tm->num_of_bus_per_interface) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("pup_num %d not valid\n", pup_num));
+	}
+
+	if (if_id >= MAX_INTERFACE_NUM) {
+		DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR,
+					 ("if_id %d not valid\n", if_id));
+	}
+
+	CHECK_STATUS(ddr3_tip_ip_training_wrapper_int
+		     (dev_num, access_type, if_id, pup_access_type, pup_num,
+		      ALL_BITS_PER_PUP, result_type, control_element,
+		      search_dir, direction, interface_mask, init_value_l2h,
+		      init_value_h2l, num_iter, pattern, edge_comp,
+		      train_cs_type, cs_num, train_status));
+
+	if (access_type == ACCESS_TYPE_MULTICAST) {
+		start_if = 0;
+		end_if = MAX_INTERFACE_NUM - 1;
+	} else {
+		start_if = if_id;
+		end_if = if_id;
+	}
+
+	for (interface_cnt = start_if; interface_cnt <= end_if;
+	     interface_cnt++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, interface_cnt);
+		for (pup_id = 0;
+		     pup_id <= (tm->num_of_bus_per_interface - 1); pup_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+			if (result_type == RESULT_PER_BIT)
+				bit_end = BUS_WIDTH_IN_BITS - 1;
+			else
+				bit_end = 0;
+
+			bit_bit_mask[pup_id] = 0;
+			for (bit_id = 0; bit_id <= bit_end; bit_id++) {
+				enum hws_search_dir search_dir_id;
+				for (search_dir_id = HWS_LOW2HIGH;
+				     search_dir_id <= HWS_HIGH2LOW;
+				     search_dir_id++) {
+					CHECK_STATUS
+						(ddr3_tip_read_training_result
+						 (dev_num, interface_cnt,
+						  ACCESS_TYPE_UNICAST, pup_id,
+						  bit_id, search_dir_id,
+						  direction, result_type,
+						  TRAINING_LOAD_OPERATION_UNLOAD,
+						  CS_SINGLE,
+						  &result[search_dir_id],
+						  1, 0, 0));
+				}
+				e1 = GET_TAP_RESULT(result[HWS_LOW2HIGH][0],
+						    EDGE_1);
+				e2 = GET_TAP_RESULT(result[HWS_HIGH2LOW][0],
+						    EDGE_1);
+				DEBUG_TRAINING_IP_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("wrapper if_id %d pup_id %d bit %d l2h 0x%x (e1 0x%x) h2l 0x%x (e2 0x%x)\n",
+					 interface_cnt, pup_id, bit_id,
+					 result[HWS_LOW2HIGH][0], e1,
+					 result[HWS_HIGH2LOW][0], e2));
+				/* TBD validate is valid only for tx */
+				if (VALIDATE_TRAINING_LIMIT(e1, e2) == 1 &&
+				    GET_LOCK_RESULT(result[HWS_LOW2HIGH][0]) &&
+				    GET_LOCK_RESULT(result[HWS_LOW2HIGH][0])) {
+					/* Mark problem bits */
+					bit_bit_mask[pup_id] |= 1 << bit_id;
+					bit_bit_mask_active = 1;
+				}
+			}	/* For all bits */
+		}		/* For all PUPs */
+
+		/* Fix problem bits */
+		if (bit_bit_mask_active != 0) {
+			u32 *l2h_if_train_res = NULL;
+			u32 *h2l_if_train_res = NULL;
+			l2h_if_train_res =
+				ddr3_tip_get_buf_ptr(dev_num, HWS_LOW2HIGH,
+						     result_type,
+						     interface_cnt);
+			h2l_if_train_res =
+				ddr3_tip_get_buf_ptr(dev_num, HWS_HIGH2LOW,
+						     result_type,
+						     interface_cnt);
+
+			ddr3_tip_ip_training(dev_num, ACCESS_TYPE_UNICAST,
+					     interface_cnt,
+					     ACCESS_TYPE_MULTICAST,
+					     PARAM_NOT_CARE, result_type,
+					     control_element, HWS_LOW2HIGH,
+					     direction, interface_mask,
+					     num_iter / 2, num_iter / 2,
+					     pattern, EDGE_FP, train_cs_type,
+					     cs_num, train_status);
+
+			for (pup_id = 0;
+			     pup_id <= (tm->num_of_bus_per_interface - 1);
+			     pup_id++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+
+				if (bit_bit_mask[pup_id] == 0)
+					continue;
+
+				for (bit_id = 0; bit_id <= bit_end; bit_id++) {
+					if ((bit_bit_mask[pup_id] &
+					     (1 << bit_id)) == 0)
+						continue;
+					CHECK_STATUS
+						(ddr3_tip_read_training_result
+						 (dev_num, interface_cnt,
+						  ACCESS_TYPE_UNICAST, pup_id,
+						  bit_id, HWS_LOW2HIGH,
+						  direction,
+						  result_type,
+						  TRAINING_LOAD_OPERATION_UNLOAD,
+						  CS_SINGLE, &l2h_if_train_res,
+						  0, 0, 1));
+				}
+			}
+
+			ddr3_tip_ip_training(dev_num, ACCESS_TYPE_UNICAST,
+					     interface_cnt,
+					     ACCESS_TYPE_MULTICAST,
+					     PARAM_NOT_CARE, result_type,
+					     control_element, HWS_HIGH2LOW,
+					     direction, interface_mask,
+					     num_iter / 2, num_iter / 2,
+					     pattern, EDGE_FP, train_cs_type,
+					     cs_num, train_status);
+
+			for (pup_id = 0;
+			     pup_id <= (tm->num_of_bus_per_interface - 1);
+			     pup_id++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, pup_id);
+
+				if (bit_bit_mask[pup_id] == 0)
+					continue;
+
+				for (bit_id = 0; bit_id <= bit_end; bit_id++) {
+					if ((bit_bit_mask[pup_id] &
+					     (1 << bit_id)) == 0)
+						continue;
+					CHECK_STATUS
+						(ddr3_tip_read_training_result
+						 (dev_num, interface_cnt,
+						  ACCESS_TYPE_UNICAST, pup_id,
+						  bit_id, HWS_HIGH2LOW, direction,
+						  result_type,
+						  TRAINING_LOAD_OPERATION_UNLOAD,
+						  CS_SINGLE, &h2l_if_train_res,
+						  0, cons_tap, 1));
+				}
+			}
+		}		/* if bit_bit_mask_active */
+	}			/* For all Interfacess */
+
+	return MV_OK;
+}
+
+/*
+ * Load phy values
+ */
+int ddr3_tip_load_phy_values(int b_load)
+{
+	u32 bus_cnt = 0, if_id, dev_num = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES();
+		     bus_cnt++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+			if (b_load == 1) {
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, bus_cnt,
+					      DDR_PHY_DATA,
+					      WRITE_CENTRALIZATION_PHY_REG +
+					      (effective_cs *
+					       CS_REGISTER_ADDR_OFFSET),
+					      &phy_reg_bk[if_id][bus_cnt]
+					      [0]));
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, bus_cnt,
+					      DDR_PHY_DATA,
+					      RL_PHY_REG +
+					      (effective_cs *
+					       CS_REGISTER_ADDR_OFFSET),
+					      &phy_reg_bk[if_id][bus_cnt]
+					      [1]));
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, bus_cnt,
+					      DDR_PHY_DATA,
+					      READ_CENTRALIZATION_PHY_REG +
+					      (effective_cs *
+					       CS_REGISTER_ADDR_OFFSET),
+					      &phy_reg_bk[if_id][bus_cnt]
+					      [2]));
+			} else {
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      bus_cnt, DDR_PHY_DATA,
+					      WRITE_CENTRALIZATION_PHY_REG +
+					      (effective_cs *
+					       CS_REGISTER_ADDR_OFFSET),
+					      phy_reg_bk[if_id][bus_cnt]
+					      [0]));
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      bus_cnt, DDR_PHY_DATA,
+					      RL_PHY_REG +
+					      (effective_cs *
+					       CS_REGISTER_ADDR_OFFSET),
+					      phy_reg_bk[if_id][bus_cnt]
+					      [1]));
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST,
+					      bus_cnt, DDR_PHY_DATA,
+					      READ_CENTRALIZATION_PHY_REG +
+					      (effective_cs *
+					       CS_REGISTER_ADDR_OFFSET),
+					      phy_reg_bk[if_id][bus_cnt]
+					      [2]));
+			}
+		}
+	}
+
+	return MV_OK;
+}
+
+int ddr3_tip_training_ip_test(u32 dev_num, enum hws_training_result result_type,
+			      enum hws_search_dir search_dir,
+			      enum hws_dir direction,
+			      enum hws_edge_compare edge,
+			      u32 init_val1, u32 init_val2,
+			      u32 num_of_iterations,
+			      u32 start_pattern, u32 end_pattern)
+{
+	u32 pattern, if_id, pup_id;
+	enum hws_training_ip_stat train_status[MAX_INTERFACE_NUM];
+	u32 *res = NULL;
+	u32 search_state = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	ddr3_tip_load_phy_values(1);
+
+	for (pattern = start_pattern; pattern <= end_pattern; pattern++) {
+		for (search_state = 0; search_state < HWS_SEARCH_DIR_LIMIT;
+		     search_state++) {
+			ddr3_tip_ip_training_wrapper(dev_num,
+						     ACCESS_TYPE_MULTICAST, 0,
+						     ACCESS_TYPE_MULTICAST, 0,
+						     result_type,
+						     HWS_CONTROL_ELEMENT_ADLL,
+						     search_dir, direction,
+						     0xfff, init_val1,
+						     init_val2,
+						     num_of_iterations, pattern,
+						     edge, CS_SINGLE,
+						     PARAM_NOT_CARE,
+						     train_status);
+
+			for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				for (pup_id = 0; pup_id <
+					     tm->num_of_bus_per_interface;
+				     pup_id++) {
+					VALIDATE_ACTIVE(tm->bus_act_mask,
+							pup_id);
+					CHECK_STATUS
+						(ddr3_tip_read_training_result
+						 (dev_num, if_id,
+						  ACCESS_TYPE_UNICAST, pup_id,
+						  ALL_BITS_PER_PUP,
+						  search_state,
+						  direction, result_type,
+						  TRAINING_LOAD_OPERATION_UNLOAD,
+						  CS_SINGLE, &res, 1, 0,
+						  0));
+					if (result_type == RESULT_PER_BYTE) {
+						DEBUG_TRAINING_IP_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 ("search_state %d if_id %d pup_id %d 0x%x\n",
+							  search_state, if_id,
+							  pup_id, res[0]));
+					} else {
+						DEBUG_TRAINING_IP_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 ("search_state %d if_id %d pup_id %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+							  search_state, if_id,
+							  pup_id, res[0],
+							  res[1], res[2],
+							  res[3], res[4],
+							  res[5], res[6],
+							  res[7]));
+					}
+				}
+			}	/* interface */
+		}		/* search */
+	}			/* pattern */
+
+	ddr3_tip_load_phy_values(0);
+
+	return MV_OK;
+}
+
+struct pattern_info *ddr3_tip_get_pattern_table()
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0)
+		return pattern_table_32;
+	else
+		return pattern_table_16;
+}
+
+u16 *ddr3_tip_get_mask_results_dq_reg()
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))
+		return mask_results_dq_reg_map_pup3_ecc;
+	else
+		return mask_results_dq_reg_map;
+}
+
+u16 *ddr3_tip_get_mask_results_pup_reg_map()
+{
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))
+		return mask_results_pup_reg_map_pup3_ecc;
+	else
+		return mask_results_pup_reg_map;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h
new file mode 100644
index 0000000..25b1462
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_ENGINE_H_
+#define _DDR3_TRAINING_IP_ENGINE_H_
+
+#include "ddr3_training_ip_def.h"
+#include "ddr3_training_ip_flow.h"
+
+#define EDGE_1				0
+#define EDGE_2				1
+#define ALL_PUP_TRAINING		0xe
+#define PUP_RESULT_EDGE_1_MASK		0xff
+#define PUP_RESULT_EDGE_2_MASK		(0xff << 8)
+#define PUP_LOCK_RESULT_BIT		25
+
+#define GET_TAP_RESULT(reg, edge)				 \
+	(((edge) == EDGE_1) ? ((reg) & PUP_RESULT_EDGE_1_MASK) : \
+	 (((reg) & PUP_RESULT_EDGE_2_MASK) >> 8));
+#define GET_LOCK_RESULT(reg)						\
+	(((reg) & (1<<PUP_LOCK_RESULT_BIT)) >> PUP_LOCK_RESULT_BIT)
+
+#define EDGE_FAILURE			128
+#define ALL_BITS_PER_PUP		128
+
+#define MIN_WINDOW_SIZE			6
+#define MAX_WINDOW_SIZE_RX		32
+#define MAX_WINDOW_SIZE_TX		64
+
+int ddr3_tip_training_ip_test(u32 dev_num, enum hws_training_result result_type,
+			      enum hws_search_dir search_dir,
+			      enum hws_dir direction,
+			      enum hws_edge_compare edge,
+			      u32 init_val1, u32 init_val2,
+			      u32 num_of_iterations, u32 start_pattern,
+			      u32 end_pattern);
+int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern pattern);
+int ddr3_tip_load_pattern_to_mem_by_cpu(u32 dev_num, enum hws_pattern pattern,
+					u32 offset);
+int ddr3_tip_load_all_pattern_to_mem(u32 dev_num);
+int ddr3_tip_read_training_result(u32 dev_num, u32 if_id,
+				  enum hws_access_type pup_access_type,
+				  u32 pup_num, u32 bit_num,
+				  enum hws_search_dir search,
+				  enum hws_dir direction,
+				  enum hws_training_result result_type,
+				  enum hws_training_load_op operation,
+				  u32 cs_num_type, u32 **load_res,
+				  int is_read_from_db, u8 cons_tap,
+				  int is_check_result_validity);
+int ddr3_tip_ip_training(u32 dev_num, enum hws_access_type access_type,
+			 u32 interface_num,
+			 enum hws_access_type pup_access_type,
+			 u32 pup_num, enum hws_training_result result_type,
+			 enum hws_control_element control_element,
+			 enum hws_search_dir search_dir, enum hws_dir direction,
+			 u32 interface_mask, u32 init_value, u32 num_iter,
+			 enum hws_pattern pattern,
+			 enum hws_edge_compare edge_comp,
+			 enum hws_ddr_cs cs_type, u32 cs_num,
+			 enum hws_training_ip_stat *train_status);
+int ddr3_tip_ip_training_wrapper(u32 dev_num, enum hws_access_type access_type,
+				 u32 if_id,
+				 enum hws_access_type pup_access_type,
+				 u32 pup_num,
+				 enum hws_training_result result_type,
+				 enum hws_control_element control_element,
+				 enum hws_search_dir search_dir,
+				 enum hws_dir direction,
+				 u32 interface_mask, u32 init_value1,
+				 u32 init_value2, u32 num_iter,
+				 enum hws_pattern pattern,
+				 enum hws_edge_compare edge_comp,
+				 enum hws_ddr_cs train_cs_type, u32 cs_num,
+				 enum hws_training_ip_stat *train_status);
+int is_odpg_access_done(u32 dev_num, u32 if_id);
+void ddr3_tip_print_bist_res(void);
+struct pattern_info *ddr3_tip_get_pattern_table(void);
+u16 *ddr3_tip_get_mask_results_dq_reg(void);
+u16 *ddr3_tip_get_mask_results_pup_reg_map(void);
+
+#endif /* _DDR3_TRAINING_IP_ENGINE_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h
new file mode 100644
index 0000000..22d7ce2
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_FLOW_H_
+#define _DDR3_TRAINING_IP_FLOW_H_
+
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_pbs.h"
+
+#define MRS0_CMD			0x3
+#define MRS1_CMD			0x4
+#define MRS2_CMD			0x8
+#define MRS3_CMD			0x9
+
+/*
+ * Definitions of INTERFACE registers
+ */
+
+#define READ_BUFFER_SELECT		0x14a4
+
+/*
+ * Definitions of PHY registers
+ */
+
+#define KILLER_PATTERN_LENGTH		32
+#define EXT_ACCESS_BURST_LENGTH		8
+
+#define IS_ACTIVE(if_mask , if_id) \
+	((if_mask) & (1 << (if_id)))
+#define VALIDATE_ACTIVE(mask, id)		\
+	{					\
+	if (IS_ACTIVE(mask, id) == 0)		\
+		continue;			\
+	}
+
+#define GET_TOPOLOGY_NUM_OF_BUSES() \
+	(ddr3_get_topology_map()->num_of_bus_per_interface)
+
+#define DDR3_IS_ECC_PUP3_MODE(if_mask) \
+	(((if_mask) == 0xb) ? 1 : 0)
+#define DDR3_IS_ECC_PUP4_MODE(if_mask) \
+	(((((if_mask) & 0x10) == 0)) ? 0 : 1)
+#define DDR3_IS_16BIT_DRAM_MODE(mask) \
+	(((((mask) & 0x4) == 0)) ? 1 : 0)
+
+#define MEGA				1000000
+#define BUS_WIDTH_IN_BITS		8
+
+/*
+ * DFX address Space
+ * Table 2: DFX address space
+ * Address Bits   Value   Description
+ * [31 : 20]   0x? DFX base address bases PCIe mapping
+ * [19 : 15]   0...Number_of_client-1   Client Index inside pipe.
+ *             See also Table 1 Multi_cast = 29 Broadcast = 28
+ * [14 : 13]   2'b01   Access to Client Internal Register
+ * [12 : 0]   Client Internal Register offset   See related Client Registers
+ * [14 : 13]   2'b00   Access to Ram Wrappers Internal Register
+ * [12 : 6]   0 Number_of_rams-1   Ram Index inside Client
+ * [5 : 0]   Ram Wrapper Internal Register offset   See related Ram Wrappers
+ * Registers
+ */
+
+/* nsec */
+#define  TREFI_LOW				7800
+#define  TREFI_HIGH				3900
+
+#define  TR2R_VALUE_REG				0x180
+#define  TR2R_MASK_REG				0x180
+#define  TRFC_MASK_REG				0x7f
+#define  TR2W_MASK_REG				0x600
+#define  TW2W_HIGH_VALUE_REG			0x1800
+#define  TW2W_HIGH_MASK_REG			0xf800
+#define  TRFC_HIGH_VALUE_REG			0x20000
+#define  TRFC_HIGH_MASK_REG			0x70000
+#define  TR2R_HIGH_VALUE_REG			0x0
+#define  TR2R_HIGH_MASK_REG			0x380000
+#define  TMOD_VALUE_REG				0x16000000
+#define  TMOD_MASK_REG				0x1e000000
+#define  T_VALUE_REG				0x40000000
+#define  T_MASK_REG				0xc0000000
+#define  AUTO_ZQC_TIMING			15384
+#define  WRITE_XBAR_PORT1			0xc03f8077
+#define  READ_XBAR_PORT1			0xc03f8073
+#define  DISABLE_DDR_TUNING_DATA		0x02294285
+#define  ENABLE_DDR_TUNING_DATA			0x12294285
+
+#define ODPG_TRAINING_STATUS_REG		0x18488
+#define ODPG_TRAINING_TRIGGER_REG		0x1030
+#define ODPG_STATUS_DONE_REG			0x16fc
+#define ODPG_ENABLE_REG				0x186d4
+#define ODPG_ENABLE_OFFS			0
+#define ODPG_DISABLE_OFFS			8
+
+#define ODPG_TRAINING_CONTROL_REG		0x1034
+#define ODPG_OBJ1_OPCODE_REG			0x103c
+#define ODPG_OBJ1_ITER_CNT_REG			0x10b4
+#define CALIB_OBJ_PRFA_REG			0x10c4
+#define ODPG_WRITE_LEVELING_DONE_CNTR_REG	0x10f8
+#define ODPG_WRITE_READ_MODE_ENABLE_REG		0x10fc
+#define TRAINING_OPCODE_1_REG			0x10b4
+#define SDRAM_CONFIGURATION_REG			0x1400
+#define DDR_CONTROL_LOW_REG			0x1404
+#define SDRAM_TIMING_LOW_REG			0x1408
+#define SDRAM_TIMING_HIGH_REG			0x140c
+#define SDRAM_ACCESS_CONTROL_REG		0x1410
+#define SDRAM_OPEN_PAGE_CONTROL_REG		0x1414
+#define SDRAM_OPERATION_REG			0x1418
+#define DUNIT_CONTROL_HIGH_REG			0x1424
+#define ODT_TIMING_LOW				0x1428
+#define DDR_TIMING_REG				0x142c
+#define ODT_TIMING_HI_REG			0x147c
+#define SDRAM_INIT_CONTROL_REG			0x1480
+#define SDRAM_ODT_CONTROL_HIGH_REG		0x1498
+#define DUNIT_ODT_CONTROL_REG			0x149c
+#define READ_BUFFER_SELECT_REG			0x14a4
+#define DUNIT_MMASK_REG				0x14b0
+#define CALIB_MACHINE_CTRL_REG			0x14cc
+#define DRAM_DLL_TIMING_REG			0x14e0
+#define DRAM_ZQ_INIT_TIMIMG_REG			0x14e4
+#define DRAM_ZQ_TIMING_REG			0x14e8
+#define DFS_REG					0x1528
+#define READ_DATA_SAMPLE_DELAY			0x1538
+#define READ_DATA_READY_DELAY			0x153c
+#define TRAINING_REG				0x15b0
+#define TRAINING_SW_1_REG			0x15b4
+#define TRAINING_SW_2_REG			0x15b8
+#define TRAINING_PATTERN_BASE_ADDRESS_REG	0x15bc
+#define TRAINING_DBG_1_REG			0x15c0
+#define TRAINING_DBG_2_REG			0x15c4
+#define TRAINING_DBG_3_REG			0x15c8
+#define RANK_CTRL_REG				0x15e0
+#define TIMING_REG				0x15e4
+#define DRAM_PHY_CONFIGURATION			0x15ec
+#define MR0_REG					0x15d0
+#define MR1_REG					0x15d4
+#define MR2_REG					0x15d8
+#define MR3_REG					0x15dc
+#define TIMING_REG				0x15e4
+#define ODPG_CTRL_CONTROL_REG			0x1600
+#define ODPG_DATA_CONTROL_REG			0x1630
+#define ODPG_PATTERN_ADDR_OFFSET_REG		0x1638
+#define ODPG_DATA_BUF_SIZE_REG			0x163c
+#define PHY_LOCK_STATUS_REG			0x1674
+#define PHY_REG_FILE_ACCESS			0x16a0
+#define TRAINING_WRITE_LEVELING_REG		0x16ac
+#define ODPG_PATTERN_ADDR_REG			0x16b0
+#define ODPG_PATTERN_DATA_HI_REG		0x16b4
+#define ODPG_PATTERN_DATA_LOW_REG		0x16b8
+#define ODPG_BIST_LAST_FAIL_ADDR_REG		0x16bc
+#define ODPG_BIST_DATA_ERROR_COUNTER_REG	0x16c0
+#define ODPG_BIST_FAILED_DATA_HI_REG		0x16c4
+#define ODPG_BIST_FAILED_DATA_LOW_REG		0x16c8
+#define ODPG_WRITE_DATA_ERROR_REG		0x16cc
+#define CS_ENABLE_REG				0x16d8
+#define WR_LEVELING_DQS_PATTERN_REG		0x16dc
+
+#define ODPG_BIST_DONE				0x186d4
+#define ODPG_BIST_DONE_BIT_OFFS			0
+#define ODPG_BIST_DONE_BIT_VALUE		0
+
+#define RESULT_CONTROL_BYTE_PUP_0_REG		0x1830
+#define RESULT_CONTROL_BYTE_PUP_1_REG		0x1834
+#define RESULT_CONTROL_BYTE_PUP_2_REG		0x1838
+#define RESULT_CONTROL_BYTE_PUP_3_REG		0x183c
+#define RESULT_CONTROL_BYTE_PUP_4_REG		0x18b0
+
+#define RESULT_CONTROL_PUP_0_BIT_0_REG		0x18b4
+#define RESULT_CONTROL_PUP_0_BIT_1_REG		0x18b8
+#define RESULT_CONTROL_PUP_0_BIT_2_REG		0x18bc
+#define RESULT_CONTROL_PUP_0_BIT_3_REG		0x18c0
+#define RESULT_CONTROL_PUP_0_BIT_4_REG		0x18c4
+#define RESULT_CONTROL_PUP_0_BIT_5_REG		0x18c8
+#define RESULT_CONTROL_PUP_0_BIT_6_REG		0x18cc
+#define RESULT_CONTROL_PUP_0_BIT_7_REG		0x18f0
+#define RESULT_CONTROL_PUP_1_BIT_0_REG		0x18f4
+#define RESULT_CONTROL_PUP_1_BIT_1_REG		0x18f8
+#define RESULT_CONTROL_PUP_1_BIT_2_REG		0x18fc
+#define RESULT_CONTROL_PUP_1_BIT_3_REG		0x1930
+#define RESULT_CONTROL_PUP_1_BIT_4_REG		0x1934
+#define RESULT_CONTROL_PUP_1_BIT_5_REG		0x1938
+#define RESULT_CONTROL_PUP_1_BIT_6_REG		0x193c
+#define RESULT_CONTROL_PUP_1_BIT_7_REG		0x19b0
+#define RESULT_CONTROL_PUP_2_BIT_0_REG		0x19b4
+#define RESULT_CONTROL_PUP_2_BIT_1_REG		0x19b8
+#define RESULT_CONTROL_PUP_2_BIT_2_REG		0x19bc
+#define RESULT_CONTROL_PUP_2_BIT_3_REG		0x19c0
+#define RESULT_CONTROL_PUP_2_BIT_4_REG		0x19c4
+#define RESULT_CONTROL_PUP_2_BIT_5_REG		0x19c8
+#define RESULT_CONTROL_PUP_2_BIT_6_REG		0x19cc
+#define RESULT_CONTROL_PUP_2_BIT_7_REG		0x19f0
+#define RESULT_CONTROL_PUP_3_BIT_0_REG		0x19f4
+#define RESULT_CONTROL_PUP_3_BIT_1_REG		0x19f8
+#define RESULT_CONTROL_PUP_3_BIT_2_REG		0x19fc
+#define RESULT_CONTROL_PUP_3_BIT_3_REG		0x1a30
+#define RESULT_CONTROL_PUP_3_BIT_4_REG		0x1a34
+#define RESULT_CONTROL_PUP_3_BIT_5_REG		0x1a38
+#define RESULT_CONTROL_PUP_3_BIT_6_REG		0x1a3c
+#define RESULT_CONTROL_PUP_3_BIT_7_REG		0x1ab0
+#define RESULT_CONTROL_PUP_4_BIT_0_REG		0x1ab4
+#define RESULT_CONTROL_PUP_4_BIT_1_REG		0x1ab8
+#define RESULT_CONTROL_PUP_4_BIT_2_REG		0x1abc
+#define RESULT_CONTROL_PUP_4_BIT_3_REG		0x1ac0
+#define RESULT_CONTROL_PUP_4_BIT_4_REG		0x1ac4
+#define RESULT_CONTROL_PUP_4_BIT_5_REG		0x1ac8
+#define RESULT_CONTROL_PUP_4_BIT_6_REG		0x1acc
+#define RESULT_CONTROL_PUP_4_BIT_7_REG		0x1af0
+
+#define WL_PHY_REG				0x0
+#define WRITE_CENTRALIZATION_PHY_REG		0x1
+#define RL_PHY_REG				0x2
+#define READ_CENTRALIZATION_PHY_REG		0x3
+#define PBS_RX_PHY_REG				0x50
+#define PBS_TX_PHY_REG				0x10
+#define PHY_CONTROL_PHY_REG			0x90
+#define BW_PHY_REG				0x92
+#define RATE_PHY_REG				0x94
+#define CMOS_CONFIG_PHY_REG			0xa2
+#define PAD_ZRI_CALIB_PHY_REG			0xa4
+#define PAD_ODT_CALIB_PHY_REG			0xa6
+#define PAD_CONFIG_PHY_REG			0xa8
+#define PAD_PRE_DISABLE_PHY_REG			0xa9
+#define TEST_ADLL_REG				0xbf
+#define CSN_IOB_VREF_REG(cs)			(0xdb + (cs * 12))
+#define CSN_IO_BASE_VREF_REG(cs)		(0xd0 + (cs * 12))
+
+#define RESULT_DB_PHY_REG_ADDR			0xc0
+#define RESULT_DB_PHY_REG_RX_OFFSET		5
+#define RESULT_DB_PHY_REG_TX_OFFSET		0
+
+/* TBD - for NP5 use only CS 0 */
+#define PHY_WRITE_DELAY(cs)			WL_PHY_REG
+/*( ( _cs_ == 0 ) ? 0x0 : 0x4 )*/
+/* TBD - for NP5 use only CS 0 */
+#define PHY_READ_DELAY(cs)			RL_PHY_REG
+
+#define DDR0_ADDR_1				0xf8258
+#define DDR0_ADDR_2				0xf8254
+#define DDR1_ADDR_1				0xf8270
+#define DDR1_ADDR_2				0xf8270
+#define DDR2_ADDR_1				0xf825c
+#define DDR2_ADDR_2				0xf825c
+#define DDR3_ADDR_1				0xf8264
+#define DDR3_ADDR_2				0xf8260
+#define DDR4_ADDR_1				0xf8274
+#define DDR4_ADDR_2				0xf8274
+
+#define GENERAL_PURPOSE_RESERVED0_REG		0x182e0
+
+#define GET_BLOCK_ID_MAX_FREQ(dev_num, block_id)	800000
+#define CS0_RD_LVL_REF_DLY_OFFS			0
+#define CS0_RD_LVL_REF_DLY_LEN			0
+#define CS0_RD_LVL_PH_SEL_OFFS			0
+#define CS0_RD_LVL_PH_SEL_LEN			0
+
+#define CS_REGISTER_ADDR_OFFSET			4
+#define CALIBRATED_OBJECTS_REG_ADDR_OFFSET	0x10
+
+#define MAX_POLLING_ITERATIONS			100000
+
+#define PHASE_REG_OFFSET			32
+#define NUM_BYTES_IN_BURST			31
+#define NUM_OF_CS				4
+#define CS_REG_VALUE(cs_num)			(cs_mask_reg[cs_num])
+#define ADLL_LENGTH				32
+
+struct write_supp_result {
+	enum hws_wl_supp stage;
+	int is_pup_fail;
+};
+
+struct page_element {
+	enum hws_page_size page_size_8bit;
+	/* page size in 8 bits bus width */
+	enum hws_page_size page_size_16bit;
+	/* page size in 16 bits bus width */
+	u32 ui_page_mask;
+	/* Mask used in register */
+};
+
+int ddr3_tip_write_leveling_static_config(u32 dev_num, u32 if_id,
+					  enum hws_ddr_freq frequency,
+					  u32 *round_trip_delay_arr);
+int ddr3_tip_read_leveling_static_config(u32 dev_num, u32 if_id,
+					 enum hws_ddr_freq frequency,
+					 u32 *total_round_trip_delay_arr);
+int ddr3_tip_if_write(u32 dev_num, enum hws_access_type interface_access,
+		      u32 if_id, u32 reg_addr, u32 data_value, u32 mask);
+int ddr3_tip_if_polling(u32 dev_num, enum hws_access_type access_type,
+			u32 if_id, u32 exp_value, u32 mask, u32 offset,
+			u32 poll_tries);
+int ddr3_tip_if_read(u32 dev_num, enum hws_access_type interface_access,
+		     u32 if_id, u32 reg_addr, u32 *data, u32 mask);
+int ddr3_tip_bus_read_modify_write(u32 dev_num,
+				   enum hws_access_type access_type,
+				   u32 if_id, u32 phy_id,
+				   enum hws_ddr_phy phy_type,
+				   u32 reg_addr, u32 data_value, u32 reg_mask);
+int ddr3_tip_bus_read(u32 dev_num, u32 if_id, enum hws_access_type phy_access,
+		      u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr,
+		      u32 *data);
+int ddr3_tip_bus_write(u32 dev_num, enum hws_access_type e_interface_access,
+		       u32 if_id, enum hws_access_type e_phy_access, u32 phy_id,
+		       enum hws_ddr_phy e_phy_type, u32 reg_addr,
+		       u32 data_value);
+int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type e_access, u32 if_id,
+		      enum hws_ddr_freq memory_freq);
+int ddr3_tip_adjust_dqs(u32 dev_num);
+int ddr3_tip_init_controller(u32 dev_num);
+int ddr3_tip_ext_read(u32 dev_num, u32 if_id, u32 reg_addr,
+		      u32 num_of_bursts, u32 *addr);
+int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr,
+		       u32 num_of_bursts, u32 *addr);
+int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 ui_freq);
+int ddr3_tip_legacy_dynamic_read_leveling(u32 dev_num);
+int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 ui_freq);
+int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num);
+int ddr3_tip_dynamic_write_leveling(u32 dev_num);
+int ddr3_tip_dynamic_write_leveling_supp(u32 dev_num);
+int ddr3_tip_static_init_controller(u32 dev_num);
+int ddr3_tip_configure_phy(u32 dev_num);
+int ddr3_tip_load_pattern_to_odpg(u32 dev_num, enum hws_access_type access_type,
+				  u32 if_id, enum hws_pattern pattern,
+				  u32 load_addr);
+int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern e_pattern);
+int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type,
+			    u32 if_id, enum hws_dir direction, u32 tx_phases,
+			    u32 tx_burst_size, u32 rx_phases,
+			    u32 delay_between_burst, u32 rd_mode, u32 cs_num,
+			    u32 addr_stress_jump, u32 single_pattern);
+int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value);
+int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, u32 cmd, u32 data,
+			   u32 mask);
+int ddr3_tip_write_cs_result(u32 dev_num, u32 offset);
+int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask, u32 *if_id);
+int ddr3_tip_reset_fifo_ptr(u32 dev_num);
+int read_pup_value(int pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+		   int reg_addr, u32 mask);
+int read_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+		    int reg_addr, u32 mask);
+int write_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM],
+		     int reg_addr);
+int ddr3_tip_tune_training_params(u32 dev_num,
+				  struct tune_train_params *params);
+
+#endif /* _DDR3_TRAINING_IP_FLOW_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h
new file mode 100644
index 0000000..c6be67c
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_PBS_H_
+#define _DDR3_TRAINING_IP_PBS_H_
+
+enum {
+	EBA_CONFIG,
+	EEBA_CONFIG,
+	SBA_CONFIG
+};
+
+enum hws_training_load_op {
+	TRAINING_LOAD_OPERATION_UNLOAD,
+	TRAINING_LOAD_OPERATION_LOAD
+};
+
+enum hws_edge {
+	TRAINING_EDGE_1,
+	TRAINING_EDGE_2
+};
+
+enum hws_edge_search {
+	TRAINING_EDGE_MAX,
+	TRAINING_EDGE_MIN
+};
+
+enum pbs_dir {
+	PBS_TX_MODE = 0,
+	PBS_RX_MODE,
+	NUM_OF_PBS_MODES
+};
+
+int ddr3_tip_pbs_rx(u32 dev_num);
+int ddr3_tip_print_all_pbs_result(u32 dev_num);
+int ddr3_tip_pbs_tx(u32 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_PBS_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h
new file mode 100644
index 0000000..724b106
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_PRV_IF_H
+#define _DDR3_TRAINING_IP_PRV_IF_H
+
+#include "ddr3_training_ip.h"
+#include "ddr3_training_ip_flow.h"
+#include "ddr3_training_ip_bist.h"
+
+enum hws_static_config_type {
+	WRITE_LEVELING_STATIC,
+	READ_LEVELING_STATIC
+};
+
+struct ddr3_device_info {
+	u32 device_id;
+	u32 ck_delay;
+};
+
+typedef int (*HWS_TIP_DUNIT_MUX_SELECT_FUNC_PTR)(u8 dev_num, int enable);
+typedef int (*HWS_TIP_DUNIT_REG_READ_FUNC_PTR)(
+	u8 dev_num, enum hws_access_type interface_access, u32 if_id,
+	u32 offset, u32 *data, u32 mask);
+typedef int (*HWS_TIP_DUNIT_REG_WRITE_FUNC_PTR)(
+	u8 dev_num, enum hws_access_type interface_access, u32 if_id,
+	u32 offset, u32 data, u32 mask);
+typedef int (*HWS_TIP_GET_FREQ_CONFIG_INFO)(
+	u8 dev_num, enum hws_ddr_freq freq,
+	struct hws_tip_freq_config_info *freq_config_info);
+typedef int (*HWS_TIP_GET_DEVICE_INFO)(
+	u8 dev_num, struct ddr3_device_info *info_ptr);
+typedef int (*HWS_GET_CS_CONFIG_FUNC_PTR)(
+	u8 dev_num, u32 cs_mask, struct hws_cs_config_info *cs_info);
+typedef int (*HWS_SET_FREQ_DIVIDER_FUNC_PTR)(
+	u8 dev_num, u32 if_id, enum hws_ddr_freq freq);
+typedef int (*HWS_GET_INIT_FREQ)(u8 dev_num, enum hws_ddr_freq *freq);
+typedef int (*HWS_TRAINING_IP_IF_WRITE_FUNC_PTR)(
+	u32 dev_num, enum hws_access_type access_type, u32 dunit_id,
+	u32 reg_addr, u32 data, u32 mask);
+typedef int (*HWS_TRAINING_IP_IF_READ_FUNC_PTR)(
+	u32 dev_num, enum hws_access_type access_type, u32 dunit_id,
+	u32 reg_addr, u32 *data, u32 mask);
+typedef int (*HWS_TRAINING_IP_BUS_WRITE_FUNC_PTR)(
+	u32 dev_num, enum hws_access_type dunit_access_type, u32 if_id,
+	enum hws_access_type phy_access_type, u32 phy_id,
+	enum hws_ddr_phy phy_type, u32 reg_addr, u32 data);
+typedef int (*HWS_TRAINING_IP_BUS_READ_FUNC_PTR)(
+	u32 dev_num, u32 if_id, enum hws_access_type phy_access_type,
+	u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr, u32 *data);
+typedef int (*HWS_TRAINING_IP_ALGO_RUN_FUNC_PTR)(
+	u32 dev_num, enum hws_algo_type algo_type);
+typedef int (*HWS_TRAINING_IP_SET_FREQ_FUNC_PTR)(
+	u32 dev_num, enum hws_access_type access_type, u32 if_id,
+	enum hws_ddr_freq frequency);
+typedef int (*HWS_TRAINING_IP_INIT_CONTROLLER_FUNC_PTR)(
+	u32 dev_num, struct init_cntr_param *init_cntr_prm);
+typedef int (*HWS_TRAINING_IP_PBS_RX_FUNC_PTR)(u32 dev_num);
+typedef int (*HWS_TRAINING_IP_PBS_TX_FUNC_PTR)(u32 dev_num);
+typedef int (*HWS_TRAINING_IP_SELECT_CONTROLLER_FUNC_PTR)(
+	u32 dev_num, int enable);
+typedef int (*HWS_TRAINING_IP_TOPOLOGY_MAP_LOAD_FUNC_PTR)(
+	u32 dev_num, struct hws_topology_map *topology_map);
+typedef int (*HWS_TRAINING_IP_STATIC_CONFIG_FUNC_PTR)(
+	u32 dev_num, enum hws_ddr_freq frequency,
+	enum hws_static_config_type static_config_type, u32 if_id);
+typedef int (*HWS_TRAINING_IP_EXTERNAL_READ_PTR)(
+	u32 dev_num, u32 if_id, u32 ddr_addr, u32 num_bursts, u32 *data);
+typedef int (*HWS_TRAINING_IP_EXTERNAL_WRITE_PTR)(
+	u32 dev_num, u32 if_id, u32 ddr_addr, u32 num_bursts, u32 *data);
+typedef int (*HWS_TRAINING_IP_BIST_ACTIVATE)(
+	u32 dev_num, enum hws_pattern pattern, enum hws_access_type access_type,
+	u32 if_num, enum hws_dir direction,
+	enum hws_stress_jump addr_stress_jump,
+	enum hws_pattern_duration duration,
+	enum hws_bist_operation oper_type, u32 offset, u32 cs_num,
+	u32 pattern_addr_length);
+typedef int (*HWS_TRAINING_IP_BIST_READ_RESULT)(
+	u32 dev_num, u32 if_id, struct bist_result *pst_bist_result);
+typedef int (*HWS_TRAINING_IP_LOAD_TOPOLOGY)(u32 dev_num, u32 config_num);
+typedef int (*HWS_TRAINING_IP_READ_LEVELING)(u32 dev_num, u32 config_num);
+typedef int (*HWS_TRAINING_IP_WRITE_LEVELING)(u32 dev_num, u32 config_num);
+typedef u32 (*HWS_TRAINING_IP_GET_TEMP)(u8 dev_num);
+
+struct hws_tip_config_func_db {
+	HWS_TIP_DUNIT_MUX_SELECT_FUNC_PTR tip_dunit_mux_select_func;
+	HWS_TIP_DUNIT_REG_READ_FUNC_PTR tip_dunit_read_func;
+	HWS_TIP_DUNIT_REG_WRITE_FUNC_PTR tip_dunit_write_func;
+	HWS_TIP_GET_FREQ_CONFIG_INFO tip_get_freq_config_info_func;
+	HWS_TIP_GET_DEVICE_INFO tip_get_device_info_func;
+	HWS_SET_FREQ_DIVIDER_FUNC_PTR tip_set_freq_divider_func;
+	HWS_GET_CS_CONFIG_FUNC_PTR tip_get_cs_config_info;
+	HWS_TRAINING_IP_GET_TEMP tip_get_temperature;
+};
+
+int ddr3_tip_init_config_func(u32 dev_num,
+			      struct hws_tip_config_func_db *config_func);
+int ddr3_tip_register_xsb_info(u32 dev_num,
+			       struct hws_xsb_info *xsb_info_table);
+enum hws_result *ddr3_tip_get_result_ptr(u32 stage);
+int ddr3_set_freq_config_info(struct hws_tip_freq_config_info *table);
+int print_device_info(u8 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_PRV_IF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h
new file mode 100644
index 0000000..878068b
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_IP_STATIC_H_
+#define _DDR3_TRAINING_IP_STATIC_H_
+
+#include "ddr3_training_ip_def.h"
+#include "ddr3_training_ip.h"
+
+struct trip_delay_element {
+	u32 dqs_delay;		/* DQS delay (m_sec) */
+	u32 ck_delay;		/* CK Delay  (m_sec) */
+};
+
+struct hws_tip_static_config_info {
+	u32 silicon_delay;
+	struct trip_delay_element *package_trace_arr;
+	struct trip_delay_element *board_trace_arr;
+};
+
+int ddr3_tip_run_static_alg(u32 dev_num, enum hws_ddr_freq freq);
+int ddr3_tip_init_static_config_db(
+	u32 dev_num, struct hws_tip_static_config_info *static_config_info);
+int ddr3_tip_init_specific_reg_config(u32 dev_num,
+				      struct reg_data *reg_config_arr);
+int ddr3_tip_static_phy_init_controller(u32 dev_num);
+
+#endif /* _DDR3_TRAINING_IP_STATIC_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.c b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c
new file mode 100644
index 0000000..3c40f19
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c
@@ -0,0 +1,1836 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define WL_ITERATION_NUM		10
+#define ONE_CLOCK_ERROR_SHIFT		2
+#define ALIGN_ERROR_SHIFT		-2
+
+static u32 pup_mask_table[] = {
+	0x000000ff,
+	0x0000ff00,
+	0x00ff0000,
+	0xff000000
+};
+
+static struct write_supp_result wr_supp_res[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+
+static int ddr3_tip_dynamic_write_leveling_seq(u32 dev_num);
+static int ddr3_tip_dynamic_read_leveling_seq(u32 dev_num);
+static int ddr3_tip_dynamic_per_bit_read_leveling_seq(u32 dev_num);
+static int ddr3_tip_wl_supp_align_err_shift(u32 dev_num, u32 if_id, u32 bus_id,
+					    u32 bus_id_delta);
+static int ddr3_tip_wl_supp_align_phase_shift(u32 dev_num, u32 if_id,
+					      u32 bus_id, u32 offset,
+					      u32 bus_id_delta);
+static int ddr3_tip_xsb_compare_test(u32 dev_num, u32 if_id, u32 bus_id,
+				     u32 edge_offset, u32 bus_id_delta);
+static int ddr3_tip_wl_supp_one_clk_err_shift(u32 dev_num, u32 if_id,
+					      u32 bus_id, u32 bus_id_delta);
+
+u32 hws_ddr3_tip_max_cs_get(void)
+{
+	u32 c_cs;
+	static u32 max_cs;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (!max_cs) {
+		for (c_cs = 0; c_cs < NUM_OF_CS; c_cs++) {
+			VALIDATE_ACTIVE(tm->
+					interface_params[0].as_bus_params[0].
+					cs_bitmask, c_cs);
+			max_cs++;
+		}
+	}
+
+	return max_cs;
+}
+
+/*****************************************************************************
+Dynamic read leveling
+******************************************************************************/
+int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 freq)
+{
+	u32 data, mask;
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+	u32 bus_num, if_id, cl_val;
+	enum hws_speed_bin speed_bin_index;
+	/* save current CS value */
+	u32 cs_enable_reg_val[MAX_INTERFACE_NUM] = { 0 };
+	int is_any_pup_fail = 0;
+	u32 data_read[MAX_INTERFACE_NUM + 1] = { 0 };
+	u8 rl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM];
+	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+	u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	if (rl_version == 0) {
+		/* OLD RL machine */
+		data = 0x40;
+		data |= (1 << 20);
+
+		/* TBD multi CS */
+		CHECK_STATUS(ddr3_tip_if_write(
+				     dev_num, ACCESS_TYPE_MULTICAST,
+				     PARAM_NOT_CARE, TRAINING_REG,
+				     data, 0x11ffff));
+		CHECK_STATUS(ddr3_tip_if_write(
+				     dev_num, ACCESS_TYPE_MULTICAST,
+				     PARAM_NOT_CARE,
+				     TRAINING_PATTERN_BASE_ADDRESS_REG,
+				     0, 0xfffffff8));
+		CHECK_STATUS(ddr3_tip_if_write(
+				     dev_num, ACCESS_TYPE_MULTICAST,
+				     PARAM_NOT_CARE, TRAINING_REG,
+				     (u32)(1 << 31), (u32)(1 << 31)));
+
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			training_result[training_stage][if_id] = TEST_SUCCESS;
+			if (ddr3_tip_if_polling
+			    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+			     (u32)(1 << 31), TRAINING_REG,
+			     MAX_POLLING_ITERATIONS) != MV_OK) {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_ERROR,
+					("RL: DDR3 poll failed(1) IF %d\n",
+					 if_id));
+				training_result[training_stage][if_id] =
+					TEST_FAILED;
+
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+
+		/* read read-leveling result */
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_REG, data_read, 1 << 30));
+		/* exit read leveling mode */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x8, 0x9));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_1_REG, 1 << 16, 1 << 16));
+
+		/* disable RL machine all Trn_CS[3:0] , [16:0] */
+
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_REG, 0, 0xf1ffff));
+
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			if ((data_read[if_id] & (1 << 30)) == 0) {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_ERROR,
+					("\n_read Leveling failed for IF %d\n",
+					 if_id));
+				training_result[training_stage][if_id] =
+					TEST_FAILED;
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+		return MV_OK;
+	}
+
+	/* NEW RL machine */
+	for (effective_cs = 0; effective_cs < NUM_OF_CS; effective_cs++)
+		for (bus_num = 0; bus_num < MAX_BUS_NUM; bus_num++)
+			for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++)
+				rl_values[effective_cs][bus_num][if_id] = 0;
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			training_result[training_stage][if_id] = TEST_SUCCESS;
+
+			/* save current cs enable reg val */
+			CHECK_STATUS(ddr3_tip_if_read
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      CS_ENABLE_REG, cs_enable_reg_val,
+				      MASK_ALL_BITS));
+			/* enable single cs */
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      CS_ENABLE_REG, (1 << 3), (1 << 3)));
+		}
+
+		ddr3_tip_reset_fifo_ptr(dev_num);
+
+		/*
+		 *     Phase 1: Load pattern (using ODPG)
+		 *
+		 * enter Read Leveling mode
+		 * only 27 bits are masked
+		 * assuming non multi-CS configuration
+		 * write to CS = 0 for the non multi CS configuration, note
+		 * that the results shall be read back to the required CS !!!
+		 */
+
+		/* BUS count is 0 shifted 26 */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_DATA_CONTROL_REG, 0x3, 0x3));
+		CHECK_STATUS(ddr3_tip_configure_odpg
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0,
+			      pattern_table[PATTERN_RL].num_of_phases_tx, 0,
+			      pattern_table[PATTERN_RL].num_of_phases_rx, 0, 0,
+			      effective_cs, STRESS_NONE, DURATION_SINGLE));
+
+		/* load pattern to ODPG */
+		ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST,
+					      PARAM_NOT_CARE, PATTERN_RL,
+					      pattern_table[PATTERN_RL].
+					      start_addr);
+
+		/*
+		 *     Phase 2: ODPG to Read Leveling mode
+		 */
+
+		/* General Training Opcode register */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_WRITE_READ_MODE_ENABLE_REG, 0,
+			      MASK_ALL_BITS));
+
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_TRAINING_CONTROL_REG,
+			      (0x301b01 | effective_cs << 2), 0x3c3fef));
+
+		/* Object1 opcode register 0 & 1 */
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			speed_bin_index =
+				tm->interface_params[if_id].speed_bin_index;
+			cl_val =
+				cas_latency_table[speed_bin_index].cl_val[freq];
+			data = (cl_val << 17) | (0x3 << 25);
+			mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25);
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ODPG_OBJ1_OPCODE_REG, data, mask));
+		}
+
+		/* Set iteration count to max value */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_OPCODE_1_REG, 0xd00, 0xd00));
+
+		/*
+		 *     Phase 2: Mask config
+		 */
+
+		ddr3_tip_dynamic_read_leveling_seq(dev_num);
+
+		/*
+		 *     Phase 3: Read Leveling execution
+		 */
+
+		/* temporary jira dunit=14751 */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_DBG_1_REG, 0, (u32)(1 << 31)));
+		/* configure phy reset value */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_DBG_3_REG, (0x7f << 24),
+			      (u32)(0xff << 24)));
+		/* data pup rd reset enable  */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      SDRAM_CONFIGURATION_REG, 0, (1 << 30)));
+		/* data pup rd reset disable */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      SDRAM_CONFIGURATION_REG, (1 << 30), (1 << 30)));
+		/* training SW override & training RL mode */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x1, 0x9));
+		/* training enable */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_REG, (1 << 24) | (1 << 20),
+			      (1 << 24) | (1 << 20)));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_REG, (u32)(1 << 31), (u32)(1 << 31)));
+
+		/********* trigger training *******************/
+		/* Trigger, poll on status and disable ODPG */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_TRAINING_STATUS_REG, 0x1, 0x1));
+
+		/* check for training done + results pass */
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x2, 0x2,
+		     ODPG_TRAINING_STATUS_REG,
+		     MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("Training Done Failed\n"));
+			return MV_FAIL;
+		}
+
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			CHECK_STATUS(ddr3_tip_if_read
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id,
+				      ODPG_TRAINING_TRIGGER_REG, data_read,
+				      0x4));
+			data = data_read[if_id];
+			if (data != 0x0) {
+				DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+					       ("Training Result Failed\n"));
+			}
+		}
+
+		/*disable ODPG - Back to functional mode */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_ENABLE_REG, 0x1 << ODPG_DISABLE_OFFS,
+			      (0x1 << ODPG_DISABLE_OFFS)));
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x0, 0x1,
+		     ODPG_ENABLE_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("ODPG disable failed "));
+			return MV_FAIL;
+		}
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+		/* double loop on bus, pup */
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			/* check training done */
+			is_any_pup_fail = 0;
+			for (bus_num = 0;
+			     bus_num < tm->num_of_bus_per_interface;
+			     bus_num++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+				if (ddr3_tip_if_polling
+				    (dev_num, ACCESS_TYPE_UNICAST,
+				     if_id, (1 << 25), (1 << 25),
+				     mask_results_pup_reg_map[bus_num],
+				     MAX_POLLING_ITERATIONS) != MV_OK) {
+					DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+						       ("\n_r_l: DDR3 poll failed(2) for bus %d",
+							bus_num));
+					is_any_pup_fail = 1;
+				} else {
+					/* read result per pup */
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      mask_results_pup_reg_map
+						      [bus_num], data_read,
+						      0xff));
+					rl_values[effective_cs][bus_num]
+						[if_id] = (u8)data_read[if_id];
+				}
+			}
+
+			if (is_any_pup_fail == 1) {
+				training_result[training_stage][if_id] =
+					TEST_FAILED;
+				if (debug_mode == 0)
+					return MV_FAIL;
+			}
+		}
+
+		DEBUG_LEVELING(DEBUG_LEVEL_INFO, ("RL exit read leveling\n"));
+
+		/*
+		 *     Phase 3: Exit Read Leveling
+		 */
+
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, (1 << 3), (1 << 3)));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_1_REG, (1 << 16), (1 << 16)));
+		/* set ODPG to functional */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+
+		/*
+		 * Copy the result from the effective CS search to the
+		 * real Functional CS
+		 */
+		/*ddr3_tip_write_cs_result(dev_num, RL_PHY_REG); */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+	}
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		/* double loop on bus, pup */
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			for (bus_num = 0;
+			     bus_num < tm->num_of_bus_per_interface;
+			     bus_num++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+				/* read result per pup from arry */
+				data = rl_values[effective_cs][bus_num][if_id];
+				data = (data & 0x1f) |
+					(((data & 0xe0) >> 5) << 6);
+				ddr3_tip_bus_write(dev_num,
+						   ACCESS_TYPE_UNICAST,
+						   if_id,
+						   ACCESS_TYPE_UNICAST,
+						   bus_num, DDR_PHY_DATA,
+						   RL_PHY_REG +
+						   ((effective_cs ==
+						     0) ? 0x0 : 0x4), data);
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/* restore cs enable value */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, cs_enable_reg_val[if_id],
+			      MASK_ALL_BITS));
+		if (odt_config != 0) {
+			CHECK_STATUS(ddr3_tip_write_additional_odt_setting
+				     (dev_num, if_id));
+		}
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (training_result[training_stage][if_id] == TEST_FAILED)
+			return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Legacy Dynamic write leveling
+ */
+int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num)
+{
+	u32 c_cs, if_id, cs_mask = 0;
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/*
+	 * In TRAINIUNG reg (0x15b0) write 0x80000008 | cs_mask:
+	 * Trn_start
+	 * cs_mask = 0x1 <<20 Trn_CS0 - CS0 is included in the DDR3 training
+	 * cs_mask = 0x1 <<21 Trn_CS1 - CS1 is included in the DDR3 training
+	 * cs_mask = 0x1 <<22 Trn_CS2 - CS2 is included in the DDR3 training
+	 * cs_mask = 0x1 <<23 Trn_CS3 - CS3 is included in the DDR3 training
+	 * Trn_auto_seq =  write leveling
+	 */
+	for (c_cs = 0; c_cs < max_cs; c_cs++)
+		cs_mask = cs_mask | 1 << (20 + c_cs);
+
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, 0,
+			      TRAINING_REG, (0x80000008 | cs_mask),
+			      0xffffffff));
+		mdelay(20);
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+		     (u32)0x80000000, TRAINING_REG,
+		     MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("polling failed for Old WL result\n"));
+			return MV_FAIL;
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Legacy Dynamic read leveling
+ */
+int ddr3_tip_legacy_dynamic_read_leveling(u32 dev_num)
+{
+	u32 c_cs, if_id, cs_mask = 0;
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/*
+	 * In TRAINIUNG reg (0x15b0) write 0x80000040 | cs_mask:
+	 * Trn_start
+	 * cs_mask = 0x1 <<20 Trn_CS0 - CS0 is included in the DDR3 training
+	 * cs_mask = 0x1 <<21 Trn_CS1 - CS1 is included in the DDR3 training
+	 * cs_mask = 0x1 <<22 Trn_CS2 - CS2 is included in the DDR3 training
+	 * cs_mask = 0x1 <<23 Trn_CS3 - CS3 is included in the DDR3 training
+	 * Trn_auto_seq =  Read Leveling using training pattern
+	 */
+	for (c_cs = 0; c_cs < max_cs; c_cs++)
+		cs_mask = cs_mask | 1 << (20 + c_cs);
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, 0, TRAINING_REG,
+		      (0x80000040 | cs_mask), 0xffffffff));
+	mdelay(100);
+
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0,
+		     (u32)0x80000000, TRAINING_REG,
+		     MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("polling failed for Old RL result\n"));
+			return MV_FAIL;
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Dynamic per bit read leveling
+ */
+int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 freq)
+{
+	u32 data, mask;
+	u32 bus_num, if_id, cl_val, bit_num;
+	u32 curr_numb, curr_min_delay;
+	int adll_array[3] = { 0, -0xa, 0x14 };
+	u32 phyreg3_arr[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+	enum hws_speed_bin speed_bin_index;
+	int is_any_pup_fail = 0;
+	int break_loop = 0;
+	u32 cs_enable_reg_val[MAX_INTERFACE_NUM]; /* save current CS value */
+	u32 data_read[MAX_INTERFACE_NUM];
+	int per_bit_rl_pup_status[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+	u32 data2_write[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+	u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_num = 0;
+		     bus_num <= tm->num_of_bus_per_interface; bus_num++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+			per_bit_rl_pup_status[if_id][bus_num] = 0;
+			data2_write[if_id][bus_num] = 0;
+			/* read current value of phy register 0x3 */
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id, ACCESS_TYPE_UNICAST,
+				      bus_num, DDR_PHY_DATA,
+				      READ_CENTRALIZATION_PHY_REG,
+				      &phyreg3_arr[if_id][bus_num]));
+		}
+	}
+
+	/* NEW RL machine */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		training_result[training_stage][if_id] = TEST_SUCCESS;
+
+		/* save current cs enable reg val */
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, &cs_enable_reg_val[if_id],
+			      MASK_ALL_BITS));
+		/* enable single cs */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, (1 << 3), (1 << 3)));
+	}
+
+	ddr3_tip_reset_fifo_ptr(dev_num);
+	for (curr_numb = 0; curr_numb < 3; curr_numb++) {
+		/*
+		 *     Phase 1: Load pattern (using ODPG)
+		 *
+		 * enter Read Leveling mode
+		 * only 27 bits are masked
+		 * assuming non multi-CS configuration
+		 * write to CS = 0 for the non multi CS configuration, note that
+		 * the results shall be read back to the required CS !!!
+		 */
+
+		/* BUS count is 0 shifted 26 */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_DATA_CONTROL_REG, 0x3, 0x3));
+		CHECK_STATUS(ddr3_tip_configure_odpg
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0,
+			      pattern_table[PATTERN_TEST].num_of_phases_tx, 0,
+			      pattern_table[PATTERN_TEST].num_of_phases_rx, 0,
+			      0, 0, STRESS_NONE, DURATION_SINGLE));
+
+		/* load pattern to ODPG */
+		ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST,
+					      PARAM_NOT_CARE, PATTERN_TEST,
+					      pattern_table[PATTERN_TEST].
+					      start_addr);
+
+		/*
+		 *     Phase 2: ODPG to Read Leveling mode
+		 */
+
+		/* General Training Opcode register */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_WRITE_READ_MODE_ENABLE_REG, 0,
+			      MASK_ALL_BITS));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_TRAINING_CONTROL_REG, 0x301b01, 0x3c3fef));
+
+		/* Object1 opcode register 0 & 1 */
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			speed_bin_index =
+				tm->interface_params[if_id].speed_bin_index;
+			cl_val =
+				cas_latency_table[speed_bin_index].cl_val[freq];
+			data = (cl_val << 17) | (0x3 << 25);
+			mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25);
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ODPG_OBJ1_OPCODE_REG, data, mask));
+		}
+
+		/* Set iteration count to max value */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_OPCODE_1_REG, 0xd00, 0xd00));
+
+		/*
+		 *     Phase 2: Mask config
+		 */
+
+		ddr3_tip_dynamic_per_bit_read_leveling_seq(dev_num);
+
+		/*
+		 *     Phase 3: Read Leveling execution
+		 */
+
+		/* temporary jira dunit=14751 */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_DBG_1_REG, 0, (u32)(1 << 31)));
+		/* configure phy reset value */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_DBG_3_REG, (0x7f << 24),
+			      (u32)(0xff << 24)));
+		/* data pup rd reset enable  */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      SDRAM_CONFIGURATION_REG, 0, (1 << 30)));
+		/* data pup rd reset disable */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      SDRAM_CONFIGURATION_REG, (1 << 30), (1 << 30)));
+		/* training SW override & training RL mode */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x1, 0x9));
+		/* training enable */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_REG, (1 << 24) | (1 << 20),
+			      (1 << 24) | (1 << 20)));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_REG, (u32)(1 << 31), (u32)(1 << 31)));
+
+		/********* trigger training *******************/
+		/* Trigger, poll on status and disable ODPG */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1));
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_TRAINING_STATUS_REG, 0x1, 0x1));
+
+		/*check for training done + results pass */
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x2, 0x2,
+		     ODPG_TRAINING_STATUS_REG,
+		     MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("Training Done Failed\n"));
+			return MV_FAIL;
+		}
+
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			CHECK_STATUS(ddr3_tip_if_read
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id,
+				      ODPG_TRAINING_TRIGGER_REG, data_read,
+				      0x4));
+			data = data_read[if_id];
+			if (data != 0x0) {
+				DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+					       ("Training Result Failed\n"));
+			}
+		}
+
+		/*disable ODPG - Back to functional mode */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_ENABLE_REG, 0x1 << ODPG_DISABLE_OFFS,
+			      (0x1 << ODPG_DISABLE_OFFS)));
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x0, 0x1,
+		     ODPG_ENABLE_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("ODPG disable failed "));
+			return MV_FAIL;
+		}
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS));
+
+		/* double loop on bus, pup */
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			/* check training done */
+			for (bus_num = 0;
+			     bus_num < tm->num_of_bus_per_interface;
+			     bus_num++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+
+				if (per_bit_rl_pup_status[if_id][bus_num]
+				    == 0) {
+					curr_min_delay = 0;
+					for (bit_num = 0; bit_num < 8;
+					     bit_num++) {
+						if (ddr3_tip_if_polling
+						    (dev_num,
+						     ACCESS_TYPE_UNICAST,
+						     if_id, (1 << 25),
+						     (1 << 25),
+						     mask_results_dq_reg_map
+						     [bus_num * 8 + bit_num],
+						     MAX_POLLING_ITERATIONS) !=
+						    MV_OK) {
+							DEBUG_LEVELING
+								(DEBUG_LEVEL_ERROR,
+								 ("\n_r_l: DDR3 poll failed(2) for bus %d bit %d\n",
+								  bus_num,
+								  bit_num));
+						} else {
+							/* read result per pup */
+							CHECK_STATUS
+								(ddr3_tip_if_read
+								 (dev_num,
+								  ACCESS_TYPE_UNICAST,
+								  if_id,
+								  mask_results_dq_reg_map
+								  [bus_num * 8 +
+								   bit_num],
+								  data_read,
+								  MASK_ALL_BITS));
+							data =
+								(data_read
+								 [if_id] &
+								 0x1f) |
+								((data_read
+								  [if_id] &
+								  0xe0) << 1);
+							if (curr_min_delay == 0)
+								curr_min_delay =
+									data;
+							else if (data <
+								 curr_min_delay)
+								curr_min_delay =
+									data;
+							if (data > data2_write[if_id][bus_num])
+								data2_write
+									[if_id]
+									[bus_num] =
+									data;
+						}
+					}
+
+					if (data2_write[if_id][bus_num] <=
+					    (curr_min_delay +
+					     MAX_DQ_READ_LEVELING_DELAY)) {
+						per_bit_rl_pup_status[if_id]
+							[bus_num] = 1;
+					}
+				}
+			}
+		}
+
+		/* check if there is need to search new phyreg3 value */
+		if (curr_numb < 2) {
+			/* if there is DLL that is not checked yet */
+			for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				for (bus_num = 0;
+				     bus_num < tm->num_of_bus_per_interface;
+				     bus_num++) {
+					VALIDATE_ACTIVE(tm->bus_act_mask,
+							bus_num);
+					if (per_bit_rl_pup_status[if_id]
+					    [bus_num] != 1) {
+						/* go to next ADLL value */
+						CHECK_STATUS
+							(ddr3_tip_bus_write
+							 (dev_num,
+							  ACCESS_TYPE_UNICAST,
+							  if_id,
+							  ACCESS_TYPE_UNICAST,
+							  bus_num, DDR_PHY_DATA,
+							  READ_CENTRALIZATION_PHY_REG,
+							  (phyreg3_arr[if_id]
+							   [bus_num] +
+							   adll_array[curr_numb])));
+						break_loop = 1;
+						break;
+					}
+				}
+				if (break_loop)
+					break;
+			}
+		}		/* if (curr_numb < 2) */
+		if (!break_loop)
+			break;
+	}		/* for ( curr_numb = 0; curr_numb <3; curr_numb++) */
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_num = 0; bus_num < tm->num_of_bus_per_interface;
+		     bus_num++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_num);
+			if (per_bit_rl_pup_status[if_id][bus_num] == 1)
+				ddr3_tip_bus_write(dev_num,
+						   ACCESS_TYPE_UNICAST,
+						   if_id,
+						   ACCESS_TYPE_UNICAST,
+						   bus_num, DDR_PHY_DATA,
+						   RL_PHY_REG +
+						   CS_REG_VALUE(effective_cs),
+						   data2_write[if_id]
+						   [bus_num]);
+			else
+				is_any_pup_fail = 1;
+		}
+
+		/* TBD flow does not support multi CS */
+		/*
+		 * cs_bitmask = tm->interface_params[if_id].
+		 * as_bus_params[bus_num].cs_bitmask;
+		 */
+		/* divide by 4 is used for retrieving the CS number */
+		/*
+		 * TBD BC2 - what is the PHY address for other
+		 * CS ddr3_tip_write_cs_result() ???
+		 */
+		/*
+		 * find what should be written to PHY
+		 * - max delay that is less than threshold
+		 */
+		if (is_any_pup_fail == 1) {
+			training_result[training_stage][if_id] = TEST_FAILED;
+			if (debug_mode == 0)
+				return MV_FAIL;
+		}
+	}
+	DEBUG_LEVELING(DEBUG_LEVEL_INFO, ("RL exit read leveling\n"));
+
+	/*
+	 *     Phase 3: Exit Read Leveling
+	 */
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      TRAINING_SW_2_REG, (1 << 3), (1 << 3)));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      TRAINING_SW_1_REG, (1 << 16), (1 << 16)));
+	/* set ODPG to functional */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+	/*
+	 * Copy the result from the effective CS search to the real
+	 * Functional CS
+	 */
+	ddr3_tip_write_cs_result(dev_num, RL_PHY_REG);
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS));
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/* restore cs enable value */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, cs_enable_reg_val[if_id],
+			      MASK_ALL_BITS));
+		if (odt_config != 0) {
+			CHECK_STATUS(ddr3_tip_write_additional_odt_setting
+				     (dev_num, if_id));
+		}
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (training_result[training_stage][if_id] == TEST_FAILED)
+			return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+int ddr3_tip_calc_cs_mask(u32 dev_num, u32 if_id, u32 effective_cs,
+			  u32 *cs_mask)
+{
+	u32 all_bus_cs = 0, same_bus_cs;
+	u32 bus_cnt;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	*cs_mask = same_bus_cs = CS_BIT_MASK;
+
+	/*
+	 * In some of the devices (such as BC2), the CS is per pup and there
+	 * for mixed mode is valid on like other devices where CS configuration
+	 * is per interface.
+	 * In order to know that, we do 'Or' and 'And' operation between all
+	 * CS (of the pups).
+	 * If they are they are not the same then it's mixed mode so all CS
+	 * should be configured (when configuring the MRS)
+	 */
+	for (bus_cnt = 0; bus_cnt < tm->num_of_bus_per_interface; bus_cnt++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+
+		all_bus_cs |= tm->interface_params[if_id].
+			as_bus_params[bus_cnt].cs_bitmask;
+		same_bus_cs &= tm->interface_params[if_id].
+			as_bus_params[bus_cnt].cs_bitmask;
+
+		/* cs enable is active low */
+		*cs_mask &= ~tm->interface_params[if_id].
+			as_bus_params[bus_cnt].cs_bitmask;
+	}
+
+	if (all_bus_cs == same_bus_cs)
+		*cs_mask = (*cs_mask | (~(1 << effective_cs))) & CS_BIT_MASK;
+
+	return MV_OK;
+}
+
+/*
+ * Dynamic write leveling
+ */
+int ddr3_tip_dynamic_write_leveling(u32 dev_num)
+{
+	u32 reg_data = 0, iter, if_id, bus_cnt;
+	u32 cs_enable_reg_val[MAX_INTERFACE_NUM] = { 0 };
+	u32 cs_mask[MAX_INTERFACE_NUM];
+	u32 read_data_sample_delay_vals[MAX_INTERFACE_NUM] = { 0 };
+	u32 read_data_ready_delay_vals[MAX_INTERFACE_NUM] = { 0 };
+	/* 0 for failure */
+	u32 res_values[MAX_INTERFACE_NUM * MAX_BUS_NUM] = { 0 };
+	u32 test_res = 0;	/* 0 - success for all pup */
+	u32 data_read[MAX_INTERFACE_NUM];
+	u8 wl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM];
+	u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+	u32 cs_mask0[MAX_INTERFACE_NUM] = { 0 };
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+		training_result[training_stage][if_id] = TEST_SUCCESS;
+
+		/* save Read Data Sample Delay */
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      READ_DATA_SAMPLE_DELAY,
+			      read_data_sample_delay_vals, MASK_ALL_BITS));
+		/* save Read Data Ready Delay */
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      READ_DATA_READY_DELAY, read_data_ready_delay_vals,
+			      MASK_ALL_BITS));
+		/* save current cs reg val */
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS));
+	}
+
+	/*
+	 *     Phase 1: DRAM 2 Write Leveling mode
+	 */
+
+	/*Assert 10 refresh commands to DRAM to all CS */
+	for (iter = 0; iter < WL_ITERATION_NUM; iter++) {
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			CHECK_STATUS(ddr3_tip_if_write
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id, SDRAM_OPERATION_REG,
+				      (u32)((~(0xf) << 8) | 0x2), 0xf1f));
+		}
+	}
+	/* check controller back to normal */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (ddr3_tip_if_polling
+		    (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f,
+		     SDRAM_OPERATION_REG, MAX_POLLING_ITERATIONS) != MV_OK) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("WL: DDR3 poll failed(3)"));
+		}
+	}
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		/*enable write leveling to all cs  - Q off , WL n */
+		/* calculate interface cs mask */
+		CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask0, MRS1_CMD,
+						    0x1000, 0x1080));
+
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			/* cs enable is active low */
+			ddr3_tip_calc_cs_mask(dev_num, if_id, effective_cs,
+					      &cs_mask[if_id]);
+		}
+
+		/* Enable Output buffer to relevant CS - Q on , WL on */
+		CHECK_STATUS(ddr3_tip_write_mrs_cmd
+			     (dev_num, cs_mask, MRS1_CMD, 0x80, 0x1080));
+
+		/*enable odt for relevant CS */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      0x1498, (0x3 << (effective_cs * 2)), 0xf));
+
+		/*
+		 *     Phase 2: Set training IP to write leveling mode
+		 */
+
+		CHECK_STATUS(ddr3_tip_dynamic_write_leveling_seq(dev_num));
+
+		/*
+		 *     Phase 3: Trigger training
+		 */
+
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1));
+
+		for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+			/* training done */
+			if (ddr3_tip_if_polling
+			    (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			     (1 << 1), (1 << 1), ODPG_TRAINING_STATUS_REG,
+			     MAX_POLLING_ITERATIONS) != MV_OK) {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_ERROR,
+					("WL: DDR3 poll (4) failed (Data: 0x%x)\n",
+					 reg_data));
+			}
+#if !defined(CONFIG_ARMADA_38X)	/*Disabled. JIRA #1498 */
+			else {
+				CHECK_STATUS(ddr3_tip_if_read
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id,
+					      ODPG_TRAINING_TRIGGER_REG,
+					      &reg_data, (1 << 2)));
+				if (reg_data != 0) {
+					DEBUG_LEVELING(
+						DEBUG_LEVEL_ERROR,
+						("WL: WL failed IF %d reg_data=0x%x\n",
+						 if_id, reg_data));
+				}
+			}
+#endif
+		}
+
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			/* training done */
+			if (ddr3_tip_if_polling
+			    (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			     (1 << 1), (1 << 1), ODPG_TRAINING_STATUS_REG,
+			     MAX_POLLING_ITERATIONS) != MV_OK) {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_ERROR,
+					("WL: DDR3 poll (4) failed (Data: 0x%x)\n",
+					 reg_data));
+			} else {
+#if !defined(CONFIG_ARMADA_38X)	/*Disabled. JIRA #1498 */
+				CHECK_STATUS(ddr3_tip_if_read
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id,
+					      ODPG_TRAINING_STATUS_REG,
+					      data_read, (1 << 2)));
+				reg_data = data_read[if_id];
+				if (reg_data != 0) {
+					DEBUG_LEVELING(
+						DEBUG_LEVEL_ERROR,
+						("WL: WL failed IF %d reg_data=0x%x\n",
+						 if_id, reg_data));
+				}
+#endif
+
+				/* check for training completion per bus */
+				for (bus_cnt = 0;
+				     bus_cnt < tm->num_of_bus_per_interface;
+				     bus_cnt++) {
+					VALIDATE_ACTIVE(tm->bus_act_mask,
+							bus_cnt);
+					/* training status */
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      mask_results_pup_reg_map
+						      [bus_cnt], data_read,
+						      (1 << 25)));
+					reg_data = data_read[if_id];
+					DEBUG_LEVELING(
+						DEBUG_LEVEL_TRACE,
+						("WL: IF %d BUS %d reg 0x%x\n",
+						 if_id, bus_cnt, reg_data));
+					if (reg_data == 0) {
+						res_values[
+							(if_id *
+							 tm->num_of_bus_per_interface)
+							+ bus_cnt] = 1;
+					}
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      mask_results_pup_reg_map
+						      [bus_cnt], data_read,
+						      0xff));
+					/*
+					 * Save the read value that should be
+					 * write to PHY register
+					 */
+					wl_values[effective_cs]
+						[bus_cnt][if_id] =
+						(u8)data_read[if_id];
+				}
+			}
+		}
+
+		/*
+		 *     Phase 4: Exit write leveling mode
+		 */
+
+		/* disable DQs toggling */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      WR_LEVELING_DQS_PATTERN_REG, 0x0, 0x1));
+
+		/* Update MRS 1 (WL off) */
+		CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask0, MRS1_CMD,
+						    0x1000, 0x1080));
+
+		/* Update MRS 1 (return to functional mode - Q on , WL off) */
+		CHECK_STATUS(ddr3_tip_write_mrs_cmd
+			     (dev_num, cs_mask0, MRS1_CMD, 0x0, 0x1080));
+
+		/* set phy to normal mode */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x5, 0x7));
+
+		/* exit sw override mode  */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      TRAINING_SW_2_REG, 0x4, 0x7));
+	}
+
+	/*
+	 *     Phase 5: Load WL values to each PHY
+	 */
+
+	for (effective_cs = 0; effective_cs < max_cs; effective_cs++) {
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			test_res = 0;
+			for (bus_cnt = 0;
+			     bus_cnt < tm->num_of_bus_per_interface;
+			     bus_cnt++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt);
+				/* check if result == pass */
+				if (res_values
+				    [(if_id *
+				      tm->num_of_bus_per_interface) +
+				     bus_cnt] == 0) {
+					/*
+					 * read result control register
+					 * according to pup
+					 */
+					reg_data =
+						wl_values[effective_cs][bus_cnt]
+						[if_id];
+					/*
+					 * Write into write leveling register
+					 * ([4:0] ADLL, [8:6] Phase, [15:10]
+					 * (centralization) ADLL + 0x10)
+					 */
+					reg_data =
+						(reg_data & 0x1f) |
+						(((reg_data & 0xe0) >> 5) << 6) |
+						(((reg_data & 0x1f) +
+						  phy_reg1_val) << 10);
+					ddr3_tip_bus_write(
+						dev_num,
+						ACCESS_TYPE_UNICAST,
+						if_id,
+						ACCESS_TYPE_UNICAST,
+						bus_cnt,
+						DDR_PHY_DATA,
+						WL_PHY_REG +
+						effective_cs *
+						CS_REGISTER_ADDR_OFFSET,
+						reg_data);
+				} else {
+					test_res = 1;
+					/*
+					 * read result control register
+					 * according to pup
+					 */
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      mask_results_pup_reg_map
+						      [bus_cnt], data_read,
+						      0xff));
+					reg_data = data_read[if_id];
+					DEBUG_LEVELING(
+						DEBUG_LEVEL_ERROR,
+						("WL: IF %d BUS %d failed, reg 0x%x\n",
+						 if_id, bus_cnt, reg_data));
+				}
+			}
+
+			if (test_res != 0) {
+				training_result[training_stage][if_id] =
+					TEST_FAILED;
+			}
+		}
+	}
+	/* Set to 0 after each loop to avoid illegal value may be used */
+	effective_cs = 0;
+
+	/*
+	 * Copy the result from the effective CS search to the real
+	 * Functional CS
+	 */
+	/* ddr3_tip_write_cs_result(dev_num, WL_PHY_REG); */
+	/* restore saved values */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/* restore Read Data Sample Delay */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      READ_DATA_SAMPLE_DELAY,
+			      read_data_sample_delay_vals[if_id],
+			      MASK_ALL_BITS));
+
+		/* restore Read Data Ready Delay */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      READ_DATA_READY_DELAY,
+			      read_data_ready_delay_vals[if_id],
+			      MASK_ALL_BITS));
+
+		/* enable multi cs */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, cs_enable_reg_val[if_id],
+			      MASK_ALL_BITS));
+	}
+
+	/* Disable modt0 for CS0 training - need to adjust for multy CS */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x1498,
+		      0x0, 0xf));
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (training_result[training_stage][if_id] == TEST_FAILED)
+			return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Dynamic write leveling supplementary
+ */
+int ddr3_tip_dynamic_write_leveling_supp(u32 dev_num)
+{
+	int adll_offset;
+	u32 if_id, bus_id, data, data_tmp;
+	int is_if_fail = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		is_if_fail = 0;
+
+		for (bus_id = 0; bus_id < GET_TOPOLOGY_NUM_OF_BUSES();
+		     bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			wr_supp_res[if_id][bus_id].is_pup_fail = 1;
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id, ACCESS_TYPE_UNICAST,
+				      bus_id, DDR_PHY_DATA,
+				      WRITE_CENTRALIZATION_PHY_REG +
+				      effective_cs * CS_REGISTER_ADDR_OFFSET,
+				      &data));
+			DEBUG_LEVELING(
+				DEBUG_LEVEL_TRACE,
+				("WL Supp: adll_offset=0 data delay = %d\n",
+				 data));
+			if (ddr3_tip_wl_supp_align_phase_shift
+			    (dev_num, if_id, bus_id, 0, 0) == MV_OK) {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_TRACE,
+					("WL Supp: IF %d bus_id %d adll_offset=0 Success !\n",
+					 if_id, bus_id));
+				continue;
+			}
+
+			/* change adll */
+			adll_offset = 5;
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, bus_id, DDR_PHY_DATA,
+				      WRITE_CENTRALIZATION_PHY_REG +
+				      effective_cs * CS_REGISTER_ADDR_OFFSET,
+				      data + adll_offset));
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id, ACCESS_TYPE_UNICAST,
+				      bus_id, DDR_PHY_DATA,
+				      WRITE_CENTRALIZATION_PHY_REG +
+				      effective_cs * CS_REGISTER_ADDR_OFFSET,
+				      &data_tmp));
+			DEBUG_LEVELING(
+				DEBUG_LEVEL_TRACE,
+				("WL Supp: adll_offset= %d data delay = %d\n",
+				 adll_offset, data_tmp));
+
+			if (ddr3_tip_wl_supp_align_phase_shift
+			    (dev_num, if_id, bus_id, adll_offset, 0) == MV_OK) {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_TRACE,
+					("WL Supp: IF %d bus_id %d adll_offset= %d Success !\n",
+					 if_id, bus_id, adll_offset));
+				continue;
+			}
+
+			/* change adll */
+			adll_offset = -5;
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, bus_id, DDR_PHY_DATA,
+				      WRITE_CENTRALIZATION_PHY_REG +
+				      effective_cs * CS_REGISTER_ADDR_OFFSET,
+				      data + adll_offset));
+			CHECK_STATUS(ddr3_tip_bus_read
+				     (dev_num, if_id, ACCESS_TYPE_UNICAST,
+				      bus_id, DDR_PHY_DATA,
+				      WRITE_CENTRALIZATION_PHY_REG +
+				      effective_cs * CS_REGISTER_ADDR_OFFSET,
+				      &data_tmp));
+			DEBUG_LEVELING(
+				DEBUG_LEVEL_TRACE,
+				("WL Supp: adll_offset= %d data delay = %d\n",
+				 adll_offset, data_tmp));
+			if (ddr3_tip_wl_supp_align_phase_shift
+			    (dev_num, if_id, bus_id, adll_offset, 0) == MV_OK) {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_TRACE,
+					("WL Supp: IF %d bus_id %d adll_offset= %d Success !\n",
+					 if_id, bus_id, adll_offset));
+				continue;
+			} else {
+				DEBUG_LEVELING(
+					DEBUG_LEVEL_ERROR,
+					("WL Supp: IF %d bus_id %d Failed !\n",
+					 if_id, bus_id));
+				is_if_fail = 1;
+			}
+		}
+		DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+			       ("WL Supp: IF %d bus_id %d is_pup_fail %d\n",
+				if_id, bus_id, is_if_fail));
+
+		if (is_if_fail == 1) {
+			DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+				       ("WL Supp: IF %d failed\n", if_id));
+			training_result[training_stage][if_id] = TEST_FAILED;
+		} else {
+			training_result[training_stage][if_id] = TEST_SUCCESS;
+		}
+	}
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		if (training_result[training_stage][if_id] == TEST_FAILED)
+			return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Phase Shift
+ */
+static int ddr3_tip_wl_supp_align_phase_shift(u32 dev_num, u32 if_id,
+					      u32 bus_id, u32 offset,
+					      u32 bus_id_delta)
+{
+	wr_supp_res[if_id][bus_id].stage = PHASE_SHIFT;
+	if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id,
+				      0, bus_id_delta) == MV_OK) {
+		wr_supp_res[if_id][bus_id].is_pup_fail = 0;
+		return MV_OK;
+	} else if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id,
+					     ONE_CLOCK_ERROR_SHIFT,
+					     bus_id_delta) == MV_OK) {
+		/* 1 clock error */
+		wr_supp_res[if_id][bus_id].stage = CLOCK_SHIFT;
+		DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+			       ("Supp: 1 error clock for if %d pup %d with ofsset %d success\n",
+				if_id, bus_id, offset));
+		ddr3_tip_wl_supp_one_clk_err_shift(dev_num, if_id, bus_id, 0);
+		wr_supp_res[if_id][bus_id].is_pup_fail = 0;
+		return MV_OK;
+	} else if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id,
+					     ALIGN_ERROR_SHIFT,
+					     bus_id_delta) == MV_OK) {
+		/* align error */
+		DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+			       ("Supp: align error for if %d pup %d with ofsset %d success\n",
+				if_id, bus_id, offset));
+		wr_supp_res[if_id][bus_id].stage = ALIGN_SHIFT;
+		ddr3_tip_wl_supp_align_err_shift(dev_num, if_id, bus_id, 0);
+		wr_supp_res[if_id][bus_id].is_pup_fail = 0;
+		return MV_OK;
+	} else {
+		wr_supp_res[if_id][bus_id].is_pup_fail = 1;
+		return MV_FAIL;
+	}
+}
+
+/*
+ * Compare Test
+ */
+static int ddr3_tip_xsb_compare_test(u32 dev_num, u32 if_id, u32 bus_id,
+				     u32 edge_offset, u32 bus_id_delta)
+{
+	u32 num_of_succ_byte_compare, word_in_pattern, abs_offset;
+	u32 word_offset, i;
+	u32 read_pattern[TEST_PATTERN_LENGTH * 2];
+	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
+	u32 pattern_test_pattern_table[8];
+
+	for (i = 0; i < 8; i++) {
+		pattern_test_pattern_table[i] =
+			pattern_table_get_word(dev_num, PATTERN_TEST, (u8)i);
+	}
+
+	/* extern write, than read and compare */
+	CHECK_STATUS(ddr3_tip_ext_write
+		     (dev_num, if_id,
+		      (pattern_table[PATTERN_TEST].start_addr +
+		       ((SDRAM_CS_SIZE + 1) * effective_cs)), 1,
+		      pattern_test_pattern_table));
+
+	CHECK_STATUS(ddr3_tip_reset_fifo_ptr(dev_num));
+
+	CHECK_STATUS(ddr3_tip_ext_read
+		     (dev_num, if_id,
+		      (pattern_table[PATTERN_TEST].start_addr +
+		       ((SDRAM_CS_SIZE + 1) * effective_cs)), 1, read_pattern));
+
+	DEBUG_LEVELING(
+		DEBUG_LEVEL_TRACE,
+		("XSB-compt: IF %d bus_id %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+		 if_id, bus_id, read_pattern[0], read_pattern[1],
+		 read_pattern[2], read_pattern[3], read_pattern[4],
+		 read_pattern[5], read_pattern[6], read_pattern[7]));
+
+	/* compare byte per pup */
+	num_of_succ_byte_compare = 0;
+	for (word_in_pattern = start_xsb_offset;
+	     word_in_pattern < (TEST_PATTERN_LENGTH * 2); word_in_pattern++) {
+		word_offset = word_in_pattern + edge_offset;
+		if ((word_offset > (TEST_PATTERN_LENGTH * 2 - 1)) ||
+		    (word_offset < 0))
+			continue;
+
+		if ((read_pattern[word_in_pattern] & pup_mask_table[bus_id]) ==
+		    (pattern_test_pattern_table[word_offset] &
+		     pup_mask_table[bus_id]))
+			num_of_succ_byte_compare++;
+	}
+
+	abs_offset = (edge_offset > 0) ? edge_offset : -edge_offset;
+	if (num_of_succ_byte_compare == ((TEST_PATTERN_LENGTH * 2) -
+					 abs_offset - start_xsb_offset)) {
+		DEBUG_LEVELING(
+			DEBUG_LEVEL_TRACE,
+			("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Success\n",
+			 if_id, bus_id, num_of_succ_byte_compare));
+		return MV_OK;
+	} else {
+		DEBUG_LEVELING(
+			DEBUG_LEVEL_TRACE,
+			("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Fail !\n",
+			 if_id, bus_id, num_of_succ_byte_compare));
+
+		DEBUG_LEVELING(
+			DEBUG_LEVEL_TRACE,
+			("XSB-compt: expected 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+			 pattern_test_pattern_table[0],
+			 pattern_test_pattern_table[1],
+			 pattern_test_pattern_table[2],
+			 pattern_test_pattern_table[3],
+			 pattern_test_pattern_table[4],
+			 pattern_test_pattern_table[5],
+			 pattern_test_pattern_table[6],
+			 pattern_test_pattern_table[7]));
+		DEBUG_LEVELING(
+			DEBUG_LEVEL_TRACE,
+			("XSB-compt: recieved 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+			 read_pattern[0], read_pattern[1],
+			 read_pattern[2], read_pattern[3],
+			 read_pattern[4], read_pattern[5],
+			 read_pattern[6], read_pattern[7]));
+
+		DEBUG_LEVELING(
+			DEBUG_LEVEL_TRACE,
+			("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Fail !\n",
+			 if_id, bus_id, num_of_succ_byte_compare));
+
+		return MV_FAIL;
+	}
+}
+
+/*
+ * Clock error shift - function moves the write leveling delay 1cc forward
+ */
+static int ddr3_tip_wl_supp_one_clk_err_shift(u32 dev_num, u32 if_id,
+					      u32 bus_id, u32 bus_id_delta)
+{
+	int phase, adll;
+	u32 data;
+	DEBUG_LEVELING(DEBUG_LEVEL_TRACE, ("One_clk_err_shift\n"));
+
+	CHECK_STATUS(ddr3_tip_bus_read
+		     (dev_num, if_id, ACCESS_TYPE_UNICAST, bus_id,
+		      DDR_PHY_DATA, WL_PHY_REG, &data));
+	phase = ((data >> 6) & 0x7);
+	adll = data & 0x1f;
+	DEBUG_LEVELING(DEBUG_LEVEL_TRACE,
+		       ("One_clk_err_shift: IF %d bus_id %d phase %d adll %d\n",
+			if_id, bus_id, phase, adll));
+
+	if ((phase == 0) || (phase == 1)) {
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, bus_id,
+			      DDR_PHY_DATA, 0, (phase + 2), 0x1f));
+	} else if (phase == 2) {
+		if (adll < 6) {
+			data = (3 << 6) + (0x1f);
+			CHECK_STATUS(ddr3_tip_bus_read_modify_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      bus_id, DDR_PHY_DATA, 0, data,
+				      (0x7 << 6 | 0x1f)));
+			data = 0x2f;
+			CHECK_STATUS(ddr3_tip_bus_read_modify_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      bus_id, DDR_PHY_DATA, 1, data, 0x3f));
+		}
+	} else {
+		/* phase 3 */
+		return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Align error shift
+ */
+static int ddr3_tip_wl_supp_align_err_shift(u32 dev_num, u32 if_id,
+					    u32 bus_id, u32 bus_id_delta)
+{
+	int phase, adll;
+	u32 data;
+
+	/* Shift WL result 1 phase back */
+	CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id, ACCESS_TYPE_UNICAST,
+				       bus_id, DDR_PHY_DATA, WL_PHY_REG,
+				       &data));
+	phase = ((data >> 6) & 0x7);
+	adll = data & 0x1f;
+	DEBUG_LEVELING(
+		DEBUG_LEVEL_TRACE,
+		("Wl_supp_align_err_shift: IF %d bus_id %d phase %d adll %d\n",
+		 if_id, bus_id, phase, adll));
+
+	if (phase < 2) {
+		if (adll > 0x1a) {
+			if (phase == 0)
+				return MV_FAIL;
+
+			if (phase == 1) {
+				data = 0;
+				CHECK_STATUS(ddr3_tip_bus_read_modify_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, bus_id, DDR_PHY_DATA,
+					      0, data, (0x7 << 6 | 0x1f)));
+				data = 0xf;
+				CHECK_STATUS(ddr3_tip_bus_read_modify_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, bus_id, DDR_PHY_DATA,
+					      1, data, 0x1f));
+				return MV_OK;
+			}
+		} else {
+			return MV_FAIL;
+		}
+	} else if ((phase == 2) || (phase == 3)) {
+		phase = phase - 2;
+		data = (phase << 6) + (adll & 0x1f);
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id, bus_id,
+			      DDR_PHY_DATA, 0, data, (0x7 << 6 | 0x1f)));
+		return MV_OK;
+	} else {
+		DEBUG_LEVELING(DEBUG_LEVEL_ERROR,
+			       ("Wl_supp_align_err_shift: unexpected phase\n"));
+
+		return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Dynamic write leveling sequence
+ */
+static int ddr3_tip_dynamic_write_leveling_seq(u32 dev_num)
+{
+	u32 bus_id, dq_id;
+	u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+	u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      TRAINING_SW_2_REG, 0x1, 0x5));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      TRAINING_WRITE_LEVELING_REG, 0x50, 0xff));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      TRAINING_WRITE_LEVELING_REG, 0x5c, 0xff));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_TRAINING_CONTROL_REG, 0x381b82, 0x3c3faf));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_OBJ1_OPCODE_REG, (0x3 << 25), (0x3ffff << 9)));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_OBJ1_ITER_CNT_REG, 0x80, 0xffff));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_WRITE_LEVELING_DONE_CNTR_REG, 0x14, 0xff));
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      TRAINING_WRITE_LEVELING_REG, 0xff5c, 0xffff));
+
+	/* mask PBS */
+	for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_dq_reg_map[dq_id], 0x1 << 24,
+			      0x1 << 24));
+	}
+
+	/* Mask all results */
+	for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_pup_reg_map[bus_id], 0x1 << 24,
+			      0x1 << 24));
+	}
+
+	/* Unmask only wanted */
+	for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_pup_reg_map[bus_id], 0, 0x1 << 24));
+	}
+
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      WR_LEVELING_DQS_PATTERN_REG, 0x1, 0x1));
+
+	return MV_OK;
+}
+
+/*
+ * Dynamic read leveling sequence
+ */
+static int ddr3_tip_dynamic_read_leveling_seq(u32 dev_num)
+{
+	u32 bus_id, dq_id;
+	u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+	u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* mask PBS */
+	for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_dq_reg_map[dq_id], 0x1 << 24,
+			      0x1 << 24));
+	}
+
+	/* Mask all results */
+	for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_pup_reg_map[bus_id], 0x1 << 24,
+			      0x1 << 24));
+	}
+
+	/* Unmask only wanted */
+	for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_pup_reg_map[bus_id], 0, 0x1 << 24));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Dynamic read leveling sequence
+ */
+static int ddr3_tip_dynamic_per_bit_read_leveling_seq(u32 dev_num)
+{
+	u32 bus_id, dq_id;
+	u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map();
+	u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* mask PBS */
+	for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_dq_reg_map[dq_id], 0x1 << 24,
+			      0x1 << 24));
+	}
+
+	/* Mask all results */
+	for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_pup_reg_map[bus_id], 0x1 << 24,
+			      0x1 << 24));
+	}
+
+	/* Unmask only wanted */
+	for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, dq_id / 8);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      mask_results_dq_reg_map[dq_id], 0x0 << 24,
+			      0x1 << 24));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Print write leveling supplementary results
+ */
+int ddr3_tip_print_wl_supp_result(u32 dev_num)
+{
+	u32 bus_id = 0, if_id = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	DEBUG_LEVELING(DEBUG_LEVEL_INFO,
+		       ("I/F0 PUP0 Result[0 - success, 1-fail] ...\n"));
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+		     bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			DEBUG_LEVELING(DEBUG_LEVEL_INFO,
+				       ("%d ,", wr_supp_res[if_id]
+					[bus_id].is_pup_fail));
+		}
+	}
+	DEBUG_LEVELING(
+		DEBUG_LEVEL_INFO,
+		("I/F0 PUP0 Stage[0-phase_shift, 1-clock_shift, 2-align_shift] ...\n"));
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_id = 0; bus_id < tm->num_of_bus_per_interface;
+		     bus_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_id);
+			DEBUG_LEVELING(DEBUG_LEVEL_INFO,
+				       ("%d ,", wr_supp_res[if_id]
+					[bus_id].stage));
+		}
+	}
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.h b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h
new file mode 100644
index 0000000..f2b4177
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR3_TRAINING_LEVELING_H_
+#define _DDR3_TRAINING_LEVELING_H_
+
+#define MAX_DQ_READ_LEVELING_DELAY 15
+
+int ddr3_tip_print_wl_supp_result(u32 dev_num);
+int ddr3_tip_calc_cs_mask(u32 dev_num, u32 if_id, u32 effective_cs,
+			  u32 *cs_mask);
+u32 hws_ddr3_tip_max_cs_get(void);
+
+#endif /* _DDR3_TRAINING_LEVELING_H_ */
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_pbs.c b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c
new file mode 100644
index 0000000..2b4a58f
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c
@@ -0,0 +1,995 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#define TYPICAL_PBS_VALUE	12
+
+u32 nominal_adll[MAX_INTERFACE_NUM * MAX_BUS_NUM];
+enum hws_training_ip_stat train_status[MAX_INTERFACE_NUM];
+u8 result_mat[MAX_INTERFACE_NUM][MAX_BUS_NUM][BUS_WIDTH_IN_BITS];
+u8 result_mat_rx_dqs[MAX_INTERFACE_NUM][MAX_BUS_NUM][MAX_CS_NUM];
+/* 4-EEWA, 3-EWA, 2-SWA, 1-Fail, 0-Pass */
+u8 result_all_bit[MAX_BUS_NUM * BUS_WIDTH_IN_BITS * MAX_INTERFACE_NUM];
+u8 max_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 min_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 max_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 min_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u32 pbsdelay_per_pup[NUM_OF_PBS_MODES][MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 adll_shift_lock[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+u8 adll_shift_val[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+enum hws_pattern pbs_pattern = PATTERN_VREF;
+static u8 pup_state[MAX_INTERFACE_NUM][MAX_BUS_NUM];
+
+/*
+ * Name:     ddr3_tip_pbs
+ * Desc:     PBS
+ * Args:     TBD
+ * Notes:
+ * Returns:  OK if success, other error code if fail.
+ */
+int ddr3_tip_pbs(u32 dev_num, enum pbs_dir pbs_mode)
+{
+	u32 res0[MAX_INTERFACE_NUM];
+	int adll_tap = MEGA / freq_val[medium_freq] / 64;
+	int pad_num = 0;
+	enum hws_search_dir search_dir =
+		(pbs_mode == PBS_RX_MODE) ? HWS_HIGH2LOW : HWS_LOW2HIGH;
+	enum hws_dir dir = (pbs_mode == PBS_RX_MODE) ? OPER_READ : OPER_WRITE;
+	int iterations = (pbs_mode == PBS_RX_MODE) ? 31 : 63;
+	u32 res_valid_mask = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
+	int init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations;
+	enum hws_edge_compare search_edge = EDGE_FP;
+	u32 pup = 0, bit = 0, if_id = 0, all_lock = 0, cs_num = 0;
+	int reg_addr = 0;
+	u32 validation_val = 0;
+	u32 cs_enable_reg_val[MAX_INTERFACE_NUM];
+	u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
+	u8 temp = 0;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/* save current cs enable reg val */
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+		/* save current cs enable reg val */
+		CHECK_STATUS(ddr3_tip_if_read
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS));
+
+		/* enable single cs */
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, (1 << 3), (1 << 3)));
+	}
+
+	reg_addr = (pbs_mode == PBS_RX_MODE) ?
+		(READ_CENTRALIZATION_PHY_REG +
+		 (effective_cs * CS_REGISTER_ADDR_OFFSET)) :
+		(WRITE_CENTRALIZATION_PHY_REG +
+		 (effective_cs * CS_REGISTER_ADDR_OFFSET));
+	read_adll_value(nominal_adll, reg_addr, MASK_ALL_BITS);
+
+	/* stage 1 shift ADLL */
+	ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
+			     PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
+			     PARAM_NOT_CARE, RESULT_PER_BIT,
+			     HWS_CONTROL_ELEMENT_ADLL, search_dir, dir,
+			     tm->if_act_mask, init_val, iterations,
+			     pbs_pattern, search_edge, CS_SINGLE, cs_num,
+			     train_status);
+	validation_val = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0;
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			min_adll_per_pup[if_id][pup] =
+				(pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
+			pup_state[if_id][pup] = 0x3;
+			adll_shift_lock[if_id][pup] = 1;
+			max_adll_per_pup[if_id][pup] = 0x0;
+		}
+	}
+
+	/* EBA */
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+			CHECK_STATUS(ddr3_tip_if_read
+				     (dev_num, ACCESS_TYPE_MULTICAST,
+				      PARAM_NOT_CARE,
+				      mask_results_dq_reg_map[
+					      bit + pup * BUS_WIDTH_IN_BITS],
+				      res0, MASK_ALL_BITS));
+			for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+						 ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+						  if_id, bit, pup,
+						  res0[if_id]));
+				if (pup_state[if_id][pup] != 3)
+					continue;
+				/* if not EBA state than move to next pup */
+
+				if ((res0[if_id] & 0x2000000) == 0) {
+					DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+							 ("-- Fail Training IP\n"));
+					/* training machine failed */
+					pup_state[if_id][pup] = 1;
+					adll_shift_lock[if_id][pup] = 0;
+					continue;
+				}
+
+				else if ((res0[if_id] & res_valid_mask) ==
+					 validation_val) {
+					DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+							 ("-- FAIL EBA %d %d %d %d\n",
+							  if_id, bit, pup,
+							  res0[if_id]));
+					pup_state[if_id][pup] = 4;
+					/* this pup move to EEBA */
+					adll_shift_lock[if_id][pup] = 0;
+					continue;
+				} else {
+					/*
+					 * The search ended in Pass we need
+					 * Fail
+					 */
+					res0[if_id] =
+						(pbs_mode == PBS_RX_MODE) ?
+						((res0[if_id] &
+						  res_valid_mask) + 1) :
+						((res0[if_id] &
+						  res_valid_mask) - 1);
+					max_adll_per_pup[if_id][pup] =
+						(max_adll_per_pup[if_id][pup] <
+						 res0[if_id]) ?
+						(u8)res0[if_id] :
+						max_adll_per_pup[if_id][pup];
+					min_adll_per_pup[if_id][pup] =
+						(res0[if_id] >
+						 min_adll_per_pup[if_id][pup]) ?
+						min_adll_per_pup[if_id][pup] :
+						(u8)
+						res0[if_id];
+					/*
+					 * vs the Rx we are searching for the
+					 * smallest value of DQ shift so all
+					 * Bus would fail
+					 */
+					adll_shift_val[if_id][pup] =
+						(pbs_mode == PBS_RX_MODE) ?
+						max_adll_per_pup[if_id][pup] :
+						min_adll_per_pup[if_id][pup];
+				}
+			}
+		}
+	}
+
+	/* EEBA */
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+			if (pup_state[if_id][pup] != 4)
+				continue;
+			/*
+			 * if pup state different from EEBA than move to
+			 * next pup
+			 */
+			reg_addr = (pbs_mode == PBS_RX_MODE) ?
+				(0x54 + effective_cs * 0x10) :
+				(0x14 + effective_cs * 0x10);
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
+				      reg_addr, 0x1f));
+			reg_addr = (pbs_mode == PBS_RX_MODE) ?
+				(0x55 + effective_cs * 0x10) :
+				(0x15 + effective_cs * 0x10);
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
+				      reg_addr, 0x1f));
+			/* initialize the Edge2 Max. */
+			adll_shift_val[if_id][pup] = 0;
+			min_adll_per_pup[if_id][pup] =
+				(pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
+			max_adll_per_pup[if_id][pup] = 0x0;
+
+			ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
+					     PARAM_NOT_CARE,
+					     ACCESS_TYPE_MULTICAST,
+					     PARAM_NOT_CARE, RESULT_PER_BIT,
+					     HWS_CONTROL_ELEMENT_ADLL,
+					     search_dir, dir,
+					     tm->if_act_mask, init_val,
+					     iterations, pbs_pattern,
+					     search_edge, CS_SINGLE, cs_num,
+					     train_status);
+			DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+					 ("ADLL shift results:\n"));
+
+			for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+				CHECK_STATUS(ddr3_tip_if_read
+					     (dev_num, ACCESS_TYPE_MULTICAST,
+					      PARAM_NOT_CARE,
+					      mask_results_dq_reg_map[
+						      bit + pup *
+						      BUS_WIDTH_IN_BITS],
+					      res0, MASK_ALL_BITS));
+				DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+						 ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+						  if_id, bit, pup,
+						  res0[if_id]));
+
+				if ((res0[if_id] & 0x2000000) == 0) {
+					DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+							 (" -- EEBA Fail\n"));
+					bit = BUS_WIDTH_IN_BITS;
+					/* exit bit loop */
+					DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+							 ("-- EEBA Fail Training IP\n"));
+					/*
+					 * training machine failed but pass
+					 * before in the EBA so maybe the DQS
+					 * shift change env.
+					 */
+					pup_state[if_id][pup] = 2;
+					adll_shift_lock[if_id][pup] = 0;
+					reg_addr = (pbs_mode == PBS_RX_MODE) ?
+						(0x54 + effective_cs * 0x10) :
+						(0x14 + effective_cs * 0x10);
+					CHECK_STATUS(ddr3_tip_bus_write
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      ACCESS_TYPE_UNICAST, pup,
+						      DDR_PHY_DATA, reg_addr,
+						      0x0));
+					reg_addr = (pbs_mode == PBS_RX_MODE) ?
+						(0x55 + effective_cs * 0x10) :
+						(0x15 + effective_cs * 0x10);
+					CHECK_STATUS(ddr3_tip_bus_write
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      ACCESS_TYPE_UNICAST, pup,
+						      DDR_PHY_DATA, reg_addr,
+						      0x0));
+					continue;
+				} else if ((res0[if_id] & res_valid_mask) ==
+					   validation_val) {
+					/* exit bit loop */
+					bit = BUS_WIDTH_IN_BITS;
+					DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+							 ("-- FAIL EEBA\n"));
+					/* this pup move to SBA */
+					pup_state[if_id][pup] = 2;
+					adll_shift_lock[if_id][pup] = 0;
+					reg_addr = (pbs_mode == PBS_RX_MODE) ?
+						(0x54 + effective_cs * 0x10) :
+						(0x14 + effective_cs * 0x10);
+					CHECK_STATUS(ddr3_tip_bus_write
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      ACCESS_TYPE_UNICAST, pup,
+						      DDR_PHY_DATA, reg_addr,
+						      0x0));
+					reg_addr = (pbs_mode == PBS_RX_MODE) ?
+						(0x55 + effective_cs * 0x10) :
+						(0x15 + effective_cs * 0x10);
+					CHECK_STATUS(ddr3_tip_bus_write
+						     (dev_num,
+						      ACCESS_TYPE_UNICAST,
+						      if_id,
+						      ACCESS_TYPE_UNICAST, pup,
+						      DDR_PHY_DATA, reg_addr,
+						      0x0));
+					continue;
+				} else {
+					adll_shift_lock[if_id][pup] = 1;
+					/*
+					 * The search ended in Pass we need
+					 * Fail
+					 */
+					res0[if_id] =
+						(pbs_mode == PBS_RX_MODE) ?
+						((res0[if_id] &
+						  res_valid_mask) + 1) :
+						((res0[if_id] &
+						  res_valid_mask) - 1);
+					max_adll_per_pup[if_id][pup] =
+						(max_adll_per_pup[if_id][pup] <
+						 res0[if_id]) ?
+						(u8)res0[if_id] :
+						max_adll_per_pup[if_id][pup];
+					min_adll_per_pup[if_id][pup] =
+						(res0[if_id] >
+						 min_adll_per_pup[if_id][pup]) ?
+						min_adll_per_pup[if_id][pup] :
+						(u8)res0[if_id];
+					/*
+					 * vs the Rx we are searching for the
+					 * smallest value of DQ shift so all Bus
+					 * would fail
+					 */
+					adll_shift_val[if_id][pup] =
+						(pbs_mode == PBS_RX_MODE) ?
+						max_adll_per_pup[if_id][pup] :
+						min_adll_per_pup[if_id][pup];
+				}
+			}
+		}
+	}
+
+	/* Print Stage result */
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+					 ("FP I/F %d, ADLL Shift for EBA: pup[%d] Lock status = %d Lock Val = %d,%d\n",
+					  if_id, pup,
+					  adll_shift_lock[if_id][pup],
+					  max_adll_per_pup[if_id][pup],
+					  min_adll_per_pup[if_id][pup]));
+		}
+	}
+	DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+			 ("Update ADLL Shift of all pups:\n"));
+
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			if (adll_shift_lock[if_id][pup] != 1)
+				continue;
+			/* if pup not locked continue to next pup */
+
+			reg_addr = (pbs_mode == PBS_RX_MODE) ?
+				(0x3 + effective_cs * 4) :
+				(0x1 + effective_cs * 4);
+			CHECK_STATUS(ddr3_tip_bus_write
+				     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+				      ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
+				      reg_addr, adll_shift_val[if_id][pup]));
+			DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
+					 ("FP I/F %d, Pup[%d] = %d\n", if_id,
+					  pup, adll_shift_val[if_id][pup]));
+		}
+	}
+
+	/* PBS EEBA&EBA */
+	/* Start the Per Bit Skew search */
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			max_pbs_per_pup[if_id][pup] = 0x0;
+			min_pbs_per_pup[if_id][pup] = 0x1f;
+			for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+				/* reset result for PBS */
+				result_all_bit[bit + pup * BUS_WIDTH_IN_BITS +
+					       if_id * MAX_BUS_NUM *
+					       BUS_WIDTH_IN_BITS] = 0;
+			}
+		}
+	}
+
+	iterations = 31;
+	search_dir = HWS_LOW2HIGH;
+	/* !!!!! ran sh (search_dir == HWS_LOW2HIGH)?0:iterations; */
+	init_val = 0;
+
+	ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			     ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			     RESULT_PER_BIT, HWS_CONTROL_ELEMENT_DQ_SKEW,
+			     search_dir, dir, tm->if_act_mask, init_val,
+			     iterations, pbs_pattern, search_edge,
+			     CS_SINGLE, cs_num, train_status);
+
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			if (adll_shift_lock[if_id][pup] != 1) {
+				/* if pup not lock continue to next pup */
+				continue;
+			}
+
+			for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+				CHECK_STATUS(ddr3_tip_if_read
+					     (dev_num, ACCESS_TYPE_MULTICAST,
+					      PARAM_NOT_CARE,
+					      mask_results_dq_reg_map[
+						      bit +
+						      pup * BUS_WIDTH_IN_BITS],
+					      res0, MASK_ALL_BITS));
+				DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+						 ("Per Bit Skew search, FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+						  if_id, bit, pup,
+						  res0[if_id]));
+				if ((res0[if_id] & 0x2000000) == 0) {
+					DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+							 ("--EBA PBS Fail - Training IP machine\n"));
+					/* exit the bit loop */
+					bit = BUS_WIDTH_IN_BITS;
+					/*
+					 * ADLL is no long in lock need new
+					 * search
+					 */
+					adll_shift_lock[if_id][pup] = 0;
+					/* Move to SBA */
+					pup_state[if_id][pup] = 2;
+					max_pbs_per_pup[if_id][pup] = 0x0;
+					min_pbs_per_pup[if_id][pup] = 0x1f;
+					continue;
+				} else {
+					temp = (u8)(res0[if_id] &
+						    res_valid_mask);
+					max_pbs_per_pup[if_id][pup] =
+						(temp >
+						 max_pbs_per_pup[if_id][pup]) ?
+						temp :
+						max_pbs_per_pup[if_id][pup];
+					min_pbs_per_pup[if_id][pup] =
+						(temp <
+						 min_pbs_per_pup[if_id][pup]) ?
+						temp :
+						min_pbs_per_pup[if_id][pup];
+					result_all_bit[bit +
+						       pup * BUS_WIDTH_IN_BITS +
+						       if_id * MAX_BUS_NUM *
+						       BUS_WIDTH_IN_BITS] =
+						temp;
+				}
+			}
+		}
+	}
+
+	/* Check all Pup lock */
+	all_lock = 1;
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			all_lock = all_lock * adll_shift_lock[if_id][pup];
+		}
+	}
+
+	/* Only if not all Pups Lock */
+	if (all_lock == 0) {
+		DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+				 ("##########ADLL shift for SBA###########\n"));
+
+		/* ADLL shift for SBA */
+		search_dir = (pbs_mode == PBS_RX_MODE) ? HWS_LOW2HIGH :
+			HWS_HIGH2LOW;
+		init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations;
+		for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+			for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				if (adll_shift_lock[if_id][pup] == 1) {
+					/*if pup lock continue to next pup */
+					continue;
+				}
+				/*init the var altogth init before */
+				adll_shift_lock[if_id][pup] = 0;
+				reg_addr = (pbs_mode == PBS_RX_MODE) ?
+					(0x54 + effective_cs * 0x10) :
+					(0x14 + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr, 0));
+				reg_addr = (pbs_mode == PBS_RX_MODE) ?
+					(0x55 + effective_cs * 0x10) :
+					(0x15 + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr, 0));
+				reg_addr = (pbs_mode == PBS_RX_MODE) ?
+					(0x5f + effective_cs * 0x10) :
+					(0x1f + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr, 0));
+				/* initilaze the Edge2 Max. */
+				adll_shift_val[if_id][pup] = 0;
+				min_adll_per_pup[if_id][pup] = 0x1f;
+				max_adll_per_pup[if_id][pup] = 0x0;
+
+				ddr3_tip_ip_training(dev_num,
+						     ACCESS_TYPE_MULTICAST,
+						     PARAM_NOT_CARE,
+						     ACCESS_TYPE_MULTICAST,
+						     PARAM_NOT_CARE,
+						     RESULT_PER_BIT,
+						     HWS_CONTROL_ELEMENT_ADLL,
+						     search_dir, dir,
+						     tm->if_act_mask,
+						     init_val, iterations,
+						     pbs_pattern,
+						     search_edge, CS_SINGLE,
+						     cs_num, train_status);
+
+				for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_MULTICAST,
+						      PARAM_NOT_CARE,
+						      mask_results_dq_reg_map
+						      [bit +
+						       pup *
+						       BUS_WIDTH_IN_BITS],
+						      res0, MASK_ALL_BITS));
+					DEBUG_PBS_ENGINE(
+						DEBUG_LEVEL_INFO,
+						("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
+						 if_id, bit, pup, res0[if_id]));
+					if ((res0[if_id] & 0x2000000) == 0) {
+						/* exit the bit loop */
+						bit = BUS_WIDTH_IN_BITS;
+						/* Fail SBA --> Fail PBS */
+						pup_state[if_id][pup] = 1;
+						DEBUG_PBS_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 (" SBA Fail\n"));
+						continue;
+					} else {
+						/*
+						 * - increment to get all
+						 * 8 bit lock.
+						 */
+						adll_shift_lock[if_id][pup]++;
+						/*
+						 * The search ended in Pass
+						 * we need Fail
+						 */
+						res0[if_id] =
+							(pbs_mode == PBS_RX_MODE) ?
+							((res0[if_id] & res_valid_mask) + 1) :
+							((res0[if_id] & res_valid_mask) - 1);
+						max_adll_per_pup[if_id][pup] =
+							(max_adll_per_pup[if_id]
+							 [pup] < res0[if_id]) ?
+							(u8)res0[if_id] :
+							max_adll_per_pup[if_id][pup];
+						min_adll_per_pup[if_id][pup] =
+							(res0[if_id] >
+							 min_adll_per_pup[if_id]
+							 [pup]) ?
+							min_adll_per_pup[if_id][pup] :
+							(u8)res0[if_id];
+						/*
+						 * vs the Rx we are searching for
+						 * the smallest value of DQ shift
+						 * so all Bus would fail
+						 */
+						adll_shift_val[if_id][pup] =
+							(pbs_mode == PBS_RX_MODE) ?
+							max_adll_per_pup[if_id][pup] :
+							min_adll_per_pup[if_id][pup];
+					}
+				}
+				/* 1 is lock */
+				adll_shift_lock[if_id][pup] =
+					(adll_shift_lock[if_id][pup] == 8) ?
+					1 : 0;
+				reg_addr = (pbs_mode == PBS_RX_MODE) ?
+					(0x3 + effective_cs * 4) :
+					(0x1 + effective_cs * 4);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr,
+					      adll_shift_val[if_id][pup]));
+				DEBUG_PBS_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("adll_shift_lock[%x][%x] = %x\n",
+					 if_id, pup,
+					 adll_shift_lock[if_id][pup]));
+			}
+		}
+
+		/* End ADLL Shift for SBA */
+		/* Start the Per Bit Skew search */
+		/* The ADLL shift finished with a Pass */
+		search_edge = (pbs_mode == PBS_RX_MODE) ? EDGE_PF : EDGE_FP;
+		search_dir = (pbs_mode == PBS_RX_MODE) ?
+			HWS_LOW2HIGH : HWS_HIGH2LOW;
+		iterations = 0x1f;
+		/* - The initial value is different in Rx and Tx mode */
+		init_val = (pbs_mode == PBS_RX_MODE) ? 0 : iterations;
+
+		ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
+				     PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
+				     PARAM_NOT_CARE, RESULT_PER_BIT,
+				     HWS_CONTROL_ELEMENT_DQ_SKEW,
+				     search_dir, dir, tm->if_act_mask,
+				     init_val, iterations, pbs_pattern,
+				     search_edge, CS_SINGLE, cs_num,
+				     train_status);
+
+		for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+			for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+					CHECK_STATUS(ddr3_tip_if_read
+						     (dev_num,
+						      ACCESS_TYPE_MULTICAST,
+						      PARAM_NOT_CARE,
+						      mask_results_dq_reg_map
+						      [bit +
+						       pup *
+						       BUS_WIDTH_IN_BITS],
+						      res0, MASK_ALL_BITS));
+					if (pup_state[if_id][pup] != 2) {
+						/*
+						 * if pup is not SBA continue
+						 * to next pup
+						 */
+						bit = BUS_WIDTH_IN_BITS;
+						continue;
+					}
+					DEBUG_PBS_ENGINE(
+						DEBUG_LEVEL_INFO,
+						("Per Bit Skew search, PF I/F %d, bit:%d, pup:%d res0 0x%x\n",
+						 if_id, bit, pup, res0[if_id]));
+					if ((res0[if_id] & 0x2000000) == 0) {
+						DEBUG_PBS_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 ("SBA Fail\n"));
+
+						max_pbs_per_pup[if_id][pup] =
+							0x1f;
+						result_all_bit[
+							bit + pup *
+							BUS_WIDTH_IN_BITS +
+							if_id * MAX_BUS_NUM *
+							BUS_WIDTH_IN_BITS] =
+							0x1f;
+					} else {
+						temp = (u8)(res0[if_id] &
+							    res_valid_mask);
+						max_pbs_per_pup[if_id][pup] =
+							(temp >
+							 max_pbs_per_pup[if_id]
+							 [pup]) ? temp :
+							max_pbs_per_pup
+							[if_id][pup];
+						min_pbs_per_pup[if_id][pup] =
+							(temp <
+							 min_pbs_per_pup[if_id]
+							 [pup]) ? temp :
+							min_pbs_per_pup
+							[if_id][pup];
+						result_all_bit[
+							bit + pup *
+							BUS_WIDTH_IN_BITS +
+							if_id * MAX_BUS_NUM *
+							BUS_WIDTH_IN_BITS] =
+							temp;
+						adll_shift_lock[if_id][pup] = 1;
+					}
+				}
+			}
+		}
+
+		/* Check all Pup state */
+		all_lock = 1;
+		for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+			/*
+			 * DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+			 * ("pup_state[%d][%d] = %d\n",if_id,pup,pup_state
+			 * [if_id][pup]));
+			*/
+		}
+	}
+
+	/* END OF SBA */
+	/* Norm */
+	for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+		for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+			for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
+			     if_id++) {
+				VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+				/* if pup not lock continue to next pup */
+				if (adll_shift_lock[if_id][pup] != 1) {
+					DEBUG_PBS_ENGINE(
+						DEBUG_LEVEL_ERROR,
+						("PBS failed for IF #%d\n",
+						 if_id));
+					training_result[training_stage][if_id]
+						= TEST_FAILED;
+
+					result_mat[if_id][pup][bit] = 0;
+					max_pbs_per_pup[if_id][pup] = 0;
+					min_pbs_per_pup[if_id][pup] = 0;
+				} else {
+					training_result[
+						training_stage][if_id] =
+						(training_result[training_stage]
+						 [if_id] == TEST_FAILED) ?
+						TEST_FAILED : TEST_SUCCESS;
+					result_mat[if_id][pup][bit] =
+						result_all_bit[
+							bit + pup *
+							BUS_WIDTH_IN_BITS +
+							if_id * MAX_BUS_NUM *
+							BUS_WIDTH_IN_BITS] -
+						min_pbs_per_pup[if_id][pup];
+				}
+				DEBUG_PBS_ENGINE(
+					DEBUG_LEVEL_INFO,
+					("The abs min_pbs[%d][%d] = %d\n",
+					 if_id, pup,
+					 min_pbs_per_pup[if_id][pup]));
+			}
+		}
+	}
+
+	/* Clean all results */
+	ddr3_tip_clean_pbs_result(dev_num, pbs_mode);
+
+	/* DQ PBS register update with the final result */
+	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+
+			DEBUG_PBS_ENGINE(
+				DEBUG_LEVEL_INFO,
+				("Final Results: if_id %d, pup %d, Pup State: %d\n",
+				 if_id, pup, pup_state[if_id][pup]));
+			for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+				if (dq_map_table == NULL) {
+					DEBUG_PBS_ENGINE(
+						DEBUG_LEVEL_ERROR,
+						("dq_map_table not initialized\n"));
+					return MV_FAIL;
+				}
+				pad_num = dq_map_table[
+					bit + pup * BUS_WIDTH_IN_BITS +
+					if_id * BUS_WIDTH_IN_BITS *
+					tm->num_of_bus_per_interface];
+				DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
+						 ("result_mat: %d ",
+						  result_mat[if_id][pup]
+						  [bit]));
+				reg_addr = (pbs_mode == PBS_RX_MODE) ?
+					(PBS_RX_PHY_REG + effective_cs * 0x10) :
+					(PBS_TX_PHY_REG + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr + pad_num,
+					      result_mat[if_id][pup][bit]));
+			}
+			pbsdelay_per_pup[pbs_mode][if_id][pup] =
+				(max_pbs_per_pup[if_id][pup] ==
+				 min_pbs_per_pup[if_id][pup]) ?
+				TYPICAL_PBS_VALUE :
+				((max_adll_per_pup[if_id][pup] -
+				  min_adll_per_pup[if_id][pup]) * adll_tap /
+				 (max_pbs_per_pup[if_id][pup] -
+				  min_pbs_per_pup[if_id][pup]));
+
+			/* RX results ready, write RX also */
+			if (pbs_mode == PBS_TX_MODE) {
+				/* Write TX results */
+				reg_addr = (0x14 + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr,
+					      (max_pbs_per_pup[if_id][pup] -
+					       min_pbs_per_pup[if_id][pup]) /
+					      2));
+				reg_addr = (0x15 + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr,
+					      (max_pbs_per_pup[if_id][pup] -
+					       min_pbs_per_pup[if_id][pup]) /
+					      2));
+
+				/* Write previously stored RX results */
+				reg_addr = (0x54 + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr,
+					      result_mat_rx_dqs[if_id][pup]
+					      [effective_cs]));
+				reg_addr = (0x55 + effective_cs * 0x10);
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr,
+					      result_mat_rx_dqs[if_id][pup]
+					      [effective_cs]));
+			} else {
+				/*
+				 * RX results may affect RL results correctess,
+				 * so just store the results that will written
+				 * in TX stage
+				 */
+				result_mat_rx_dqs[if_id][pup][effective_cs] =
+					(max_pbs_per_pup[if_id][pup] -
+					 min_pbs_per_pup[if_id][pup]) / 2;
+			}
+			DEBUG_PBS_ENGINE(
+				DEBUG_LEVEL_INFO,
+				(", PBS tap=%d [psec] ==> skew observed = %d\n",
+				 pbsdelay_per_pup[pbs_mode][if_id][pup],
+				 ((max_pbs_per_pup[if_id][pup] -
+				   min_pbs_per_pup[if_id][pup]) *
+				  pbsdelay_per_pup[pbs_mode][if_id][pup])));
+		}
+	}
+
+	/* Write back to the phy the default values */
+	reg_addr = (pbs_mode == PBS_RX_MODE) ?
+		(READ_CENTRALIZATION_PHY_REG + effective_cs * 4) :
+		(WRITE_CENTRALIZATION_PHY_REG + effective_cs * 4);
+	write_adll_value(nominal_adll, reg_addr);
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		reg_addr = (pbs_mode == PBS_RX_MODE) ?
+			(0x5a + effective_cs * 0x10) :
+			(0x1a + effective_cs * 0x10);
+		CHECK_STATUS(ddr3_tip_bus_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA, reg_addr,
+			      0));
+
+		/* restore cs enable value */
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      CS_ENABLE_REG, cs_enable_reg_val[if_id],
+			      MASK_ALL_BITS));
+	}
+
+	/* exit test mode */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ODPG_WRITE_READ_MODE_ENABLE_REG, 0xffff, MASK_ALL_BITS));
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		/*
+		 * meaning that there is no VW exist at all (No lock at
+		 * the EBA ADLL shift at EBS)
+		 */
+		if (pup_state[if_id][pup] == 1)
+			return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_tip_pbs_rx.
+ * Desc:     PBS TX
+ * Args:     TBD
+ * Notes:
+ * Returns:  OK if success, other error code if fail.
+ */
+int ddr3_tip_pbs_rx(u32 uidev_num)
+{
+	return ddr3_tip_pbs(uidev_num, PBS_RX_MODE);
+}
+
+/*
+ * Name:     ddr3_tip_pbs_tx.
+ * Desc:     PBS TX
+ * Args:     TBD
+ * Notes:
+ * Returns:  OK if success, other error code if fail.
+ */
+int ddr3_tip_pbs_tx(u32 uidev_num)
+{
+	return ddr3_tip_pbs(uidev_num, PBS_TX_MODE);
+}
+
+#ifndef EXCLUDE_SWITCH_DEBUG
+/*
+ * Print PBS Result
+ */
+int ddr3_tip_print_all_pbs_result(u32 dev_num)
+{
+	u32 curr_cs;
+	u32 max_cs = hws_ddr3_tip_max_cs_get();
+
+	for (curr_cs = 0; curr_cs < max_cs; curr_cs++) {
+		ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_RX_MODE);
+		ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_TX_MODE);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Print PBS Result
+ */
+int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode)
+{
+	u32 data_value = 0, bit = 0, if_id = 0, pup = 0;
+	u32 reg_addr = (pbs_mode == PBS_RX_MODE) ?
+		(PBS_RX_PHY_REG + cs_num * 0x10) :
+		(PBS_TX_PHY_REG + cs_num * 0x10);
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	printf("CS%d, %s ,PBS\n", cs_num,
+	       (pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx");
+
+	for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
+		printf("%s, DQ", (pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx");
+		for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+			VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+			printf("%d ,PBS,,, ", bit);
+			for (pup = 0; pup <= tm->num_of_bus_per_interface;
+			     pup++) {
+				VALIDATE_ACTIVE(tm->bus_act_mask, pup);
+				CHECK_STATUS(ddr3_tip_bus_read
+					     (dev_num, if_id,
+					      ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr + bit,
+					      &data_value));
+				printf("%d , ", data_value);
+			}
+		}
+		printf("\n");
+	}
+	printf("\n");
+
+	return MV_OK;
+}
+#endif
+
+/*
+ * Fixup PBS Result
+ */
+int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode)
+{
+	u32 if_id, pup, bit;
+	u32 reg_addr = (pbs_mode == PBS_RX_MODE) ?
+		(PBS_RX_PHY_REG + effective_cs * 0x10) :
+		(PBS_TX_PHY_REG + effective_cs * 0x10);
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (pup = 0; pup <= tm->num_of_bus_per_interface; pup++) {
+			for (bit = 0; bit <= BUS_WIDTH_IN_BITS + 3; bit++) {
+				CHECK_STATUS(ddr3_tip_bus_write
+					     (dev_num, ACCESS_TYPE_UNICAST,
+					      if_id, ACCESS_TYPE_UNICAST, pup,
+					      DDR_PHY_DATA, reg_addr + bit, 0));
+			}
+		}
+	}
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_static.c b/drivers/ddr/marvell/a38x/ddr3_training_static.c
new file mode 100644
index 0000000..5101f3f
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr3_training_static.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+/* Design Guidelines parameters */
+u32 g_zpri_data = 123;		/* controller data - P drive strength */
+u32 g_znri_data = 123;		/* controller data - N drive strength */
+u32 g_zpri_ctrl = 74;		/* controller C/A - P drive strength */
+u32 g_znri_ctrl = 74;		/* controller C/A - N drive strength */
+u32 g_zpodt_data = 45;		/* controller data - P ODT */
+u32 g_znodt_data = 45;		/* controller data - N ODT */
+u32 g_zpodt_ctrl = 45;		/* controller data - P ODT */
+u32 g_znodt_ctrl = 45;		/* controller data - N ODT */
+u32 g_odt_config = 0x120012;
+u32 g_rtt_nom = 0x44;
+u32 g_dic = 0x2;
+
+#ifdef STATIC_ALGO_SUPPORT
+
+#define PARAM_NOT_CARE		0
+#define MAX_STATIC_SEQ		48
+
+u32 silicon_delay[HWS_MAX_DEVICE_NUM];
+struct hws_tip_static_config_info static_config[HWS_MAX_DEVICE_NUM];
+static reg_data *static_init_controller_config[HWS_MAX_DEVICE_NUM];
+
+/* debug delay in write leveling */
+int wl_debug_delay = 0;
+/* pup register #3 for functional board */
+int function_reg_value = 8;
+u32 silicon;
+
+u32 read_ready_delay_phase_offset[] = { 4, 4, 4, 4, 6, 6, 6, 6 };
+
+static struct cs_element chip_select_map[] = {
+	/* CS Value (single only)  Num_CS */
+	{0, 0},
+	{0, 1},
+	{1, 1},
+	{0, 2},
+	{2, 1},
+	{0, 2},
+	{0, 2},
+	{0, 3},
+	{3, 1},
+	{0, 2},
+	{0, 2},
+	{0, 3},
+	{0, 2},
+	{0, 3},
+	{0, 3},
+	{0, 4}
+};
+
+/*
+ * Register static init controller DB
+ */
+int ddr3_tip_init_specific_reg_config(u32 dev_num, reg_data *reg_config_arr)
+{
+	static_init_controller_config[dev_num] = reg_config_arr;
+	return MV_OK;
+}
+
+/*
+ * Register static info DB
+ */
+int ddr3_tip_init_static_config_db(
+	u32 dev_num, struct hws_tip_static_config_info *static_config_info)
+{
+	static_config[dev_num].board_trace_arr =
+		static_config_info->board_trace_arr;
+	static_config[dev_num].package_trace_arr =
+		static_config_info->package_trace_arr;
+	silicon_delay[dev_num] = static_config_info->silicon_delay;
+
+	return MV_OK;
+}
+
+/*
+ * Static round trip flow - Calculates the total round trip delay.
+ */
+int ddr3_tip_static_round_trip_arr_build(u32 dev_num,
+					 struct trip_delay_element *table_ptr,
+					 int is_wl, u32 *round_trip_delay_arr)
+{
+	u32 bus_index, global_bus;
+	u32 if_id;
+	u32 bus_per_interface;
+	int sign;
+	u32 temp;
+	u32 board_trace;
+	struct trip_delay_element *pkg_delay_ptr;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	/*
+	 * In WL we calc the diff between Clock to DQs in RL we sum the round
+	 * trip of Clock and DQs
+	 */
+	sign = (is_wl) ? -1 : 1;
+
+	bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES();
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		for (bus_index = 0; bus_index < bus_per_interface;
+		     bus_index++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+			global_bus = (if_id * bus_per_interface) + bus_index;
+
+			/* calculate total trip delay (package and board) */
+			board_trace = (table_ptr[global_bus].dqs_delay * sign) +
+				table_ptr[global_bus].ck_delay;
+			temp = (board_trace * 163) / 1000;
+
+			/* Convert the length to delay in psec units */
+			pkg_delay_ptr =
+				static_config[dev_num].package_trace_arr;
+			round_trip_delay_arr[global_bus] = temp +
+				(int)(pkg_delay_ptr[global_bus].dqs_delay *
+				      sign) +
+				(int)pkg_delay_ptr[global_bus].ck_delay +
+				(int)((is_wl == 1) ? wl_debug_delay :
+				      (int)silicon_delay[dev_num]);
+			DEBUG_TRAINING_STATIC_IP(
+				DEBUG_LEVEL_TRACE,
+				("Round Trip Build round_trip_delay_arr[0x%x]: 0x%x    temp 0x%x\n",
+				 global_bus, round_trip_delay_arr[global_bus],
+				 temp));
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Write leveling for static flow - calculating the round trip delay of the
+ * DQS signal.
+ */
+int ddr3_tip_write_leveling_static_config(u32 dev_num, u32 if_id,
+					  enum hws_ddr_freq frequency,
+					  u32 *round_trip_delay_arr)
+{
+	u32 bus_index;		/* index to the bus loop */
+	u32 bus_start_index;
+	u32 bus_per_interface;
+	u32 phase = 0;
+	u32 adll = 0, adll_cen, adll_inv, adll_final;
+	u32 adll_period = MEGA / freq_val[frequency] / 64;
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("ddr3_tip_write_leveling_static_config\n"));
+	DEBUG_TRAINING_STATIC_IP(
+		DEBUG_LEVEL_TRACE,
+		("dev_num 0x%x IF 0x%x freq %d (adll_period 0x%x)\n",
+		 dev_num, if_id, frequency, adll_period));
+
+	bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES();
+	bus_start_index = if_id * bus_per_interface;
+	for (bus_index = bus_start_index;
+	     bus_index < (bus_start_index + bus_per_interface); bus_index++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+		phase = round_trip_delay_arr[bus_index] / (32 * adll_period);
+		adll = (round_trip_delay_arr[bus_index] -
+			(phase * 32 * adll_period)) / adll_period;
+		adll = (adll > 31) ? 31 : adll;
+		adll_cen = 16 + adll;
+		adll_inv = adll_cen / 32;
+		adll_final = adll_cen - (adll_inv * 32);
+		adll_final = (adll_final > 31) ? 31 : adll_final;
+
+		DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+					 ("\t%d - phase 0x%x adll 0x%x\n",
+					  bus_index, phase, adll));
+		/*
+		 * Writing to all 4 phy of Interface number,
+		 * bit 0 \96 4 \96 ADLL, bit 6-8 phase
+		 */
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      (bus_index % 4), DDR_PHY_DATA,
+			      PHY_WRITE_DELAY(cs),
+			      ((phase << 6) + (adll & 0x1f)), 0x1df));
+		CHECK_STATUS(ddr3_tip_bus_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      ACCESS_TYPE_UNICAST, (bus_index % 4),
+			      DDR_PHY_DATA, WRITE_CENTRALIZATION_PHY_REG,
+			      ((adll_inv & 0x1) << 5) + adll_final));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Read leveling for static flow
+ */
+int ddr3_tip_read_leveling_static_config(u32 dev_num,
+					 u32 if_id,
+					 enum hws_ddr_freq frequency,
+					 u32 *total_round_trip_delay_arr)
+{
+	u32 cs, data0, data1, data3 = 0;
+	u32 bus_index;		/* index to the bus loop */
+	u32 bus_start_index;
+	u32 phase0, phase1, max_phase;
+	u32 adll0, adll1;
+	u32 cl_value;
+	u32 min_delay;
+	u32 sdr_period = MEGA / freq_val[frequency];
+	u32 ddr_period = MEGA / freq_val[frequency] / 2;
+	u32 adll_period = MEGA / freq_val[frequency] / 64;
+	enum hws_speed_bin speed_bin_index;
+	u32 rd_sample_dly[MAX_CS_NUM] = { 0 };
+	u32 rd_ready_del[MAX_CS_NUM] = { 0 };
+	u32 bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES();
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("ddr3_tip_read_leveling_static_config\n"));
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("dev_num 0x%x ifc 0x%x freq %d\n", dev_num,
+				  if_id, frequency));
+	DEBUG_TRAINING_STATIC_IP(
+		DEBUG_LEVEL_TRACE,
+		("Sdr_period 0x%x Ddr_period 0x%x adll_period 0x%x\n",
+		 sdr_period, ddr_period, adll_period));
+
+	if (tm->interface_params[first_active_if].memory_freq ==
+	    frequency) {
+		cl_value = tm->interface_params[first_active_if].cas_l;
+		DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+					 ("cl_value 0x%x\n", cl_value));
+	} else {
+		speed_bin_index = tm->interface_params[if_id].speed_bin_index;
+		cl_value = cas_latency_table[speed_bin_index].cl_val[frequency];
+		DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+					 ("cl_value 0x%x speed_bin_index %d\n",
+					  cl_value, speed_bin_index));
+	}
+
+	bus_start_index = if_id * bus_per_interface;
+
+	for (bus_index = bus_start_index;
+	     bus_index < (bus_start_index + bus_per_interface);
+	     bus_index += 2) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+		cs = chip_select_map[
+			tm->interface_params[if_id].as_bus_params[
+				(bus_index % 4)].cs_bitmask].cs_num;
+
+		/* read sample delay calculation */
+		min_delay = (total_round_trip_delay_arr[bus_index] <
+			     total_round_trip_delay_arr[bus_index + 1]) ?
+			total_round_trip_delay_arr[bus_index] :
+			total_round_trip_delay_arr[bus_index + 1];
+		/* round down */
+		rd_sample_dly[cs] = 2 * (min_delay / (sdr_period * 2));
+		DEBUG_TRAINING_STATIC_IP(
+			DEBUG_LEVEL_TRACE,
+			("\t%d - min_delay 0x%x cs 0x%x rd_sample_dly[cs] 0x%x\n",
+			 bus_index, min_delay, cs, rd_sample_dly[cs]));
+
+		/* phase calculation */
+		phase0 = (total_round_trip_delay_arr[bus_index] -
+			  (sdr_period * rd_sample_dly[cs])) / (ddr_period);
+		phase1 = (total_round_trip_delay_arr[bus_index + 1] -
+			  (sdr_period * rd_sample_dly[cs])) / (ddr_period);
+		max_phase = (phase0 > phase1) ? phase0 : phase1;
+		DEBUG_TRAINING_STATIC_IP(
+			DEBUG_LEVEL_TRACE,
+			("\tphase0 0x%x phase1 0x%x max_phase 0x%x\n",
+			 phase0, phase1, max_phase));
+
+		/* ADLL calculation */
+		adll0 = (u32)((total_round_trip_delay_arr[bus_index] -
+			       (sdr_period * rd_sample_dly[cs]) -
+			       (ddr_period * phase0)) / adll_period);
+		adll0 = (adll0 > 31) ? 31 : adll0;
+		adll1 = (u32)((total_round_trip_delay_arr[bus_index + 1] -
+			       (sdr_period * rd_sample_dly[cs]) -
+			       (ddr_period * phase1)) / adll_period);
+		adll1 = (adll1 > 31) ? 31 : adll1;
+
+		/* The Read delay close the Read FIFO */
+		rd_ready_del[cs] = rd_sample_dly[cs] +
+			read_ready_delay_phase_offset[max_phase];
+		DEBUG_TRAINING_STATIC_IP(
+			DEBUG_LEVEL_TRACE,
+			("\tadll0 0x%x adll1 0x%x rd_ready_del[cs] 0x%x\n",
+			 adll0, adll1, rd_ready_del[cs]));
+
+		/*
+		 * Write to the phy of Interface (bit 0 \96 4 \96 ADLL,
+		 * bit 6-8 phase)
+		 */
+		data0 = ((phase0 << 6) + (adll0 & 0x1f));
+		data1 = ((phase1 << 6) + (adll1 & 0x1f));
+
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      (bus_index % 4), DDR_PHY_DATA, PHY_READ_DELAY(cs),
+			      data0, 0x1df));
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      ((bus_index + 1) % 4), DDR_PHY_DATA,
+			      PHY_READ_DELAY(cs), data1, 0x1df));
+	}
+
+	for (bus_index = 0; bus_index < bus_per_interface; bus_index++) {
+		VALIDATE_ACTIVE(tm->bus_act_mask, bus_index);
+		CHECK_STATUS(ddr3_tip_bus_read_modify_write
+			     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+			      bus_index, DDR_PHY_DATA, 0x3, data3, 0x1f));
+	}
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+		      READ_DATA_SAMPLE_DELAY,
+		      (rd_sample_dly[0] + cl_value) + (rd_sample_dly[1] << 8),
+		      MASK_ALL_BITS));
+
+	/* Read_ready_del0 bit 0-4 , CS bits 8-12 */
+	CHECK_STATUS(ddr3_tip_if_write
+		     (dev_num, ACCESS_TYPE_UNICAST, if_id,
+		      READ_DATA_READY_DELAY,
+		      rd_ready_del[0] + (rd_ready_del[1] << 8) + cl_value,
+		      MASK_ALL_BITS));
+
+	return MV_OK;
+}
+
+/*
+ * DDR3 Static flow
+ */
+int ddr3_tip_run_static_alg(u32 dev_num, enum hws_ddr_freq freq)
+{
+	u32 if_id = 0;
+	struct trip_delay_element *table_ptr;
+	u32 wl_total_round_trip_delay_arr[MAX_TOTAL_BUS_NUM];
+	u32 rl_total_round_trip_delay_arr[MAX_TOTAL_BUS_NUM];
+	struct init_cntr_param init_cntr_prm;
+	int ret;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("ddr3_tip_run_static_alg"));
+
+	init_cntr_prm.do_mrs_phy = 1;
+	init_cntr_prm.is_ctrl64_bit = 0;
+	init_cntr_prm.init_phy = 1;
+	ret = hws_ddr3_tip_init_controller(dev_num, &init_cntr_prm);
+	if (ret != MV_OK) {
+		DEBUG_TRAINING_STATIC_IP(
+			DEBUG_LEVEL_ERROR,
+			("hws_ddr3_tip_init_controller failure\n"));
+	}
+
+	/* calculate the round trip delay for Write Leveling */
+	table_ptr = static_config[dev_num].board_trace_arr;
+	CHECK_STATUS(ddr3_tip_static_round_trip_arr_build
+		     (dev_num, table_ptr, 1,
+		      wl_total_round_trip_delay_arr));
+	/* calculate the round trip delay  for Read Leveling */
+	CHECK_STATUS(ddr3_tip_static_round_trip_arr_build
+		     (dev_num, table_ptr, 0,
+		      rl_total_round_trip_delay_arr));
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		/* check if the interface is enabled */
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+		/*
+		 * Static frequency is defined according to init-frequency
+		 * (not target)
+		 */
+		DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+					 ("Static IF %d freq %d\n",
+					  if_id, freq));
+		CHECK_STATUS(ddr3_tip_write_leveling_static_config
+			     (dev_num, if_id, freq,
+			      wl_total_round_trip_delay_arr));
+		CHECK_STATUS(ddr3_tip_read_leveling_static_config
+			     (dev_num, if_id, freq,
+			      rl_total_round_trip_delay_arr));
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Init controller for static flow
+ */
+int ddr3_tip_static_init_controller(u32 dev_num)
+{
+	u32 index_cnt = 0;
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("ddr3_tip_static_init_controller\n"));
+	while (static_init_controller_config[dev_num][index_cnt].reg_addr !=
+	       0) {
+		CHECK_STATUS(ddr3_tip_if_write
+			     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+			      static_init_controller_config[dev_num][index_cnt].
+			      reg_addr,
+			      static_init_controller_config[dev_num][index_cnt].
+			      reg_data,
+			      static_init_controller_config[dev_num][index_cnt].
+			      reg_mask));
+
+		DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+					 ("Init_controller index_cnt %d\n",
+					  index_cnt));
+		index_cnt++;
+	}
+
+	return MV_OK;
+}
+
+int ddr3_tip_static_phy_init_controller(u32 dev_num)
+{
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("Phy Init Controller 2\n"));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa4,
+		      0x3dfe));
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("Phy Init Controller 3\n"));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa6,
+		      0xcb2));
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("Phy Init Controller 4\n"));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa9,
+		      0));
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("Static Receiver Calibration\n"));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xd0,
+		      0x1f));
+
+	DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE,
+				 ("Static V-REF Calibration\n"));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa8,
+		      0x434));
+
+	return MV_OK;
+}
+#endif
+
+/*
+ * Configure phy (called by static init controller) for static flow
+ */
+int ddr3_tip_configure_phy(u32 dev_num)
+{
+	u32 if_id, phy_id;
+	struct hws_topology_map *tm = ddr3_get_topology_map();
+
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+		      PAD_ZRI_CALIB_PHY_REG,
+		      ((0x7f & g_zpri_data) << 7 | (0x7f & g_znri_data))));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL,
+		      PAD_ZRI_CALIB_PHY_REG,
+		      ((0x7f & g_zpri_ctrl) << 7 | (0x7f & g_znri_ctrl))));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+		      PAD_ODT_CALIB_PHY_REG,
+		      ((0x3f & g_zpodt_data) << 6 | (0x3f & g_znodt_data))));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL,
+		      PAD_ODT_CALIB_PHY_REG,
+		      ((0x3f & g_zpodt_ctrl) << 6 | (0x3f & g_znodt_ctrl))));
+
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+		      PAD_PRE_DISABLE_PHY_REG, 0));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA,
+		      CMOS_CONFIG_PHY_REG, 0));
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL,
+		      CMOS_CONFIG_PHY_REG, 0));
+
+	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
+		/* check if the interface is enabled */
+		VALIDATE_ACTIVE(tm->if_act_mask, if_id);
+
+		for (phy_id = 0;
+		     phy_id < tm->num_of_bus_per_interface;
+		     phy_id++) {
+			VALIDATE_ACTIVE(tm->bus_act_mask, phy_id);
+			/* Vref & clamp */
+			CHECK_STATUS(ddr3_tip_bus_read_modify_write
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id, phy_id, DDR_PHY_DATA,
+				      PAD_CONFIG_PHY_REG,
+				      ((clamp_tbl[if_id] << 4) | vref),
+				      ((0x7 << 4) | 0x7)));
+			/* clamp not relevant for control */
+			CHECK_STATUS(ddr3_tip_bus_read_modify_write
+				     (dev_num, ACCESS_TYPE_UNICAST,
+				      if_id, phy_id, DDR_PHY_CONTROL,
+				      PAD_CONFIG_PHY_REG, 0x4, 0x7));
+		}
+	}
+
+	CHECK_STATUS(ddr3_tip_bus_write
+		     (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
+		      ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0x90,
+		      0x6002));
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/marvell/a38x/ddr_topology_def.h b/drivers/ddr/marvell/a38x/ddr_topology_def.h
new file mode 100644
index 0000000..f8894e8
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr_topology_def.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:     GPL-2.0
+ */
+
+#ifndef _DDR_TOPOLOGY_DEF_H
+#define _DDR_TOPOLOGY_DEF_H
+
+#include "ddr3_training_ip_def.h"
+#include "ddr3_topology_def.h"
+
+#if defined(CONFIG_ARMADA_38X)
+#include "ddr3_a38x.h"
+#endif
+
+/* bus width in bits */
+enum hws_bus_width {
+	BUS_WIDTH_4,
+	BUS_WIDTH_8,
+	BUS_WIDTH_16,
+	BUS_WIDTH_32
+};
+
+enum hws_temperature {
+	HWS_TEMP_LOW,
+	HWS_TEMP_NORMAL,
+	HWS_TEMP_HIGH
+};
+
+enum hws_mem_size {
+	MEM_512M,
+	MEM_1G,
+	MEM_2G,
+	MEM_4G,
+	MEM_8G,
+	MEM_SIZE_LAST
+};
+
+struct bus_params {
+	/* Chip Select (CS) bitmask (bits 0-CS0, bit 1- CS1 ...) */
+	u8 cs_bitmask;
+
+	/*
+	 * mirror enable/disable
+	 * (bits 0-CS0 mirroring, bit 1- CS1 mirroring ...)
+	 */
+	int mirror_enable_bitmask;
+
+	/* DQS Swap (polarity) - true if enable */
+	int is_dqs_swap;
+
+	/* CK swap (polarity) - true if enable */
+	int is_ck_swap;
+};
+
+struct if_params {
+	/* bus configuration */
+	struct bus_params as_bus_params[MAX_BUS_NUM];
+
+	/* Speed Bin Table */
+	enum hws_speed_bin speed_bin_index;
+
+	/* bus width of memory */
+	enum hws_bus_width bus_width;
+
+	/* Bus memory size (MBit) */
+	enum hws_mem_size memory_size;
+
+	/* The DDR frequency for each interfaces */
+	enum hws_ddr_freq memory_freq;
+
+	/*
+	 * delay CAS Write Latency
+	 * - 0 for using default value (jedec suggested)
+	 */
+	u8 cas_wl;
+
+	/*
+	 * delay CAS Latency
+	 * - 0 for using default value (jedec suggested)
+	 */
+	u8 cas_l;
+
+	/* operation temperature */
+	enum hws_temperature interface_temp;
+};
+
+struct hws_topology_map {
+	/* Number of interfaces (default is 12) */
+	u8 if_act_mask;
+
+	/* Controller configuration per interface */
+	struct if_params interface_params[MAX_INTERFACE_NUM];
+
+	/* BUS per interface (default is 4) */
+	u8 num_of_bus_per_interface;
+
+	/* Bit mask for active buses */
+	u8 bus_act_mask;
+};
+
+/* DDR3 training global configuration parameters */
+struct tune_train_params {
+	u32 ck_delay;
+	u32 ck_delay_16;
+	u32 p_finger;
+	u32 n_finger;
+	u32 phy_reg3_val;
+};
+
+#endif /* _DDR_TOPOLOGY_DEF_H */
diff --git a/drivers/ddr/marvell/a38x/ddr_training_ip_db.h b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h
new file mode 100644
index 0000000..ff5f817
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _DDR_TRAINING_IP_DB_H_
+#define _DDR_TRAINING_IP_DB_H_
+
+#include "ddr_topology_def.h"
+#include "ddr3_training_ip_db.h"
+
+u32 speed_bin_table(u8 index, enum speed_bin_table_elements element);
+u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index);
+
+#endif /* _DDR3_TRAINING_IP_DB_H_ */
diff --git a/drivers/ddr/marvell/a38x/silicon_if.h b/drivers/ddr/marvell/a38x/silicon_if.h
new file mode 100644
index 0000000..7fce27d
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/silicon_if.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __silicon_if_H
+#define __silicon_if_H
+
+/* max number of devices supported by driver */
+#ifdef CO_CPU_RUN
+#define HWS_MAX_DEVICE_NUM (1)
+#else
+#define HWS_MAX_DEVICE_NUM (16)
+#endif
+
+#endif /* __silicon_if_H */
diff --git a/drivers/ddr/marvell/a38x/xor.c b/drivers/ddr/marvell/a38x/xor.c
new file mode 100644
index 0000000..9c73c54
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/xor.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+#include "xor_regs.h"
+
+/* defines  */
+#ifdef MV_DEBUG
+#define DB(x)	x
+#else
+#define DB(x)
+#endif
+
+static u32 ui_xor_regs_ctrl_backup;
+static u32 ui_xor_regs_base_backup[MAX_CS];
+static u32 ui_xor_regs_mask_backup[MAX_CS];
+
+void mv_sys_xor_init(u32 num_of_cs, u32 cs_ena, u32 cs_size, u32 base_delta)
+{
+	u32 reg, ui, base, cs_count;
+
+	ui_xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
+	for (ui = 0; ui < MAX_CS; ui++)
+		ui_xor_regs_base_backup[ui] =
+			reg_read(XOR_BASE_ADDR_REG(0, ui));
+	for (ui = 0; ui < MAX_CS; ui++)
+		ui_xor_regs_mask_backup[ui] =
+			reg_read(XOR_SIZE_MASK_REG(0, ui));
+
+	reg = 0;
+	for (ui = 0; ui < (num_of_cs); ui++) {
+		/* Enable Window x for each CS */
+		reg |= (0x1 << (ui));
+		/* Enable Window x for each CS */
+		reg |= (0x3 << ((ui * 2) + 16));
+	}
+
+	reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg);
+
+	cs_count = 0;
+	for (ui = 0; ui < num_of_cs; ui++) {
+		if (cs_ena & (1 << ui)) {
+			/*
+			 * window x - Base - 0x00000000,
+			 * Attribute 0x0e - DRAM
+			 */
+			base = cs_size * ui + base_delta;
+			switch (ui) {
+			case 0:
+				base |= 0xe00;
+				break;
+			case 1:
+				base |= 0xd00;
+				break;
+			case 2:
+				base |= 0xb00;
+				break;
+			case 3:
+				base |= 0x700;
+				break;
+			}
+
+			reg_write(XOR_BASE_ADDR_REG(0, cs_count), base);
+
+			/* window x - Size */
+			reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x7fff0000);
+			cs_count++;
+		}
+	}
+
+	mv_xor_hal_init(1);
+
+	return;
+}
+
+void mv_sys_xor_finish(void)
+{
+	u32 ui;
+
+	reg_write(XOR_WINDOW_CTRL_REG(0, 0), ui_xor_regs_ctrl_backup);
+	for (ui = 0; ui < MAX_CS; ui++)
+		reg_write(XOR_BASE_ADDR_REG(0, ui),
+			  ui_xor_regs_base_backup[ui]);
+	for (ui = 0; ui < MAX_CS; ui++)
+		reg_write(XOR_SIZE_MASK_REG(0, ui),
+			  ui_xor_regs_mask_backup[ui]);
+
+	reg_write(XOR_ADDR_OVRD_REG(0, 0), 0);
+}
+
+/*
+ * mv_xor_hal_init - Initialize XOR engine
+ *
+ * DESCRIPTION:
+ *               This function initialize XOR unit.
+ * INPUT:
+ *       None.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ */
+void mv_xor_hal_init(u32 xor_chan_num)
+{
+	u32 i;
+
+	/* Abort any XOR activity & set default configuration */
+	for (i = 0; i < xor_chan_num; i++) {
+		mv_xor_command_set(i, MV_STOP);
+		mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) |
+				(4 << XEXCR_DST_BURST_LIMIT_OFFS) |
+				(4 << XEXCR_SRC_BURST_LIMIT_OFFS));
+	}
+}
+
+/*
+ * mv_xor_ctrl_set - Set XOR channel control registers
+ *
+ * DESCRIPTION:
+ *
+ * INPUT:
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ * NOTE:
+ *  This function does not modify the Operation_mode field of control register.
+ */
+int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
+{
+	u32 old_value;
+
+	/* update the XOR Engine [0..1] Configuration Registers (XEx_c_r) */
+	old_value = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))) &
+		XEXCR_OPERATION_MODE_MASK;
+	xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
+	xor_ctrl |= old_value;
+	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl);
+
+	return MV_OK;
+}
+
+int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size,
+		    u32 init_val_high, u32 init_val_low)
+{
+	u32 temp;
+
+	/* Parameter checking */
+	if (chan >= MV_XOR_MAX_CHAN)
+		return MV_BAD_PARAM;
+
+	if (MV_ACTIVE == mv_xor_state_get(chan))
+		return MV_BUSY;
+
+	if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) ||
+	    (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE))
+		return MV_BAD_PARAM;
+
+	/* set the operation mode to Memory Init */
+	temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+	temp &= ~XEXCR_OPERATION_MODE_MASK;
+	temp |= XEXCR_OPERATION_MODE_MEM_INIT;
+	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp);
+
+	/*
+	 * update the start_ptr field in XOR Engine [0..1] Destination Pointer
+	 * Register
+	 */
+	reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
+
+	/*
+	 * update the Block_size field in the XOR Engine[0..1] Block Size
+	 * Registers
+	 */
+	reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+		  block_size);
+
+	/*
+	 * update the field Init_val_l in the XOR Engine Initial Value Register
+	 * Low (XEIVRL)
+	 */
+	reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low);
+
+	/*
+	 * update the field Init_val_h in the XOR Engine Initial Value Register
+	 * High (XEIVRH)
+	 */
+	reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high);
+
+	/* start transfer */
+	reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+		    XEXACTR_XESTART_MASK);
+
+	return MV_OK;
+}
+
+/*
+ * mv_xor_state_get - Get XOR channel state.
+ *
+ * DESCRIPTION:
+ *       XOR channel activity state can be active, idle, paused.
+ *       This function retrunes the channel activity state.
+ *
+ * INPUT:
+ *       chan     - the channel number
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       XOR_CHANNEL_IDLE    - If the engine is idle.
+ *       XOR_CHANNEL_ACTIVE  - If the engine is busy.
+ *       XOR_CHANNEL_PAUSED  - If the engine is paused.
+ *       MV_UNDEFINED_STATE  - If the engine state is undefind or there is no
+ *                             such engine
+ */
+enum mv_state mv_xor_state_get(u32 chan)
+{
+	u32 state;
+
+	/* Parameter checking   */
+	if (chan >= MV_XOR_MAX_CHAN) {
+		DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
+		return MV_UNDEFINED_STATE;
+	}
+
+	/* read the current state */
+	state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+	state &= XEXACTR_XESTATUS_MASK;
+
+	/* return the state */
+	switch (state) {
+	case XEXACTR_XESTATUS_IDLE:
+		return MV_IDLE;
+	case XEXACTR_XESTATUS_ACTIVE:
+		return MV_ACTIVE;
+	case XEXACTR_XESTATUS_PAUSED:
+		return MV_PAUSED;
+	}
+
+	return MV_UNDEFINED_STATE;
+}
+
+/*
+ * mv_xor_command_set - Set command of XOR channel
+ *
+ * DESCRIPTION:
+ *       XOR channel can be started, idle, paused and restarted.
+ *       Paused can be set only if channel is active.
+ *       Start can be set only if channel is idle or paused.
+ *       Restart can be set only if channel is paused.
+ *       Stop can be set only if channel is active.
+ *
+ * INPUT:
+ *       chan     - The channel number
+ *       command  - The command type (start, stop, restart, pause)
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on
+ *       undefind XOR engine mode
+ */
+int mv_xor_command_set(u32 chan, enum mv_command command)
+{
+	enum mv_state state;
+
+	/* Parameter checking */
+	if (chan >= MV_XOR_MAX_CHAN) {
+		DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
+		return MV_BAD_PARAM;
+	}
+
+	/* get the current state */
+	state = mv_xor_state_get(chan);
+
+	if ((command == MV_START) && (state == MV_IDLE)) {
+		/* command is start and current state is idle */
+		reg_bit_set(XOR_ACTIVATION_REG
+			    (XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XESTART_MASK);
+		return MV_OK;
+	} else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
+		/* command is stop and current state is active */
+		reg_bit_set(XOR_ACTIVATION_REG
+			    (XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XESTOP_MASK);
+		return MV_OK;
+	} else if (((enum mv_state)command == MV_PAUSED) &&
+		   (state == MV_ACTIVE)) {
+		/* command is paused and current state is active */
+		reg_bit_set(XOR_ACTIVATION_REG
+			    (XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XEPAUSE_MASK);
+		return MV_OK;
+	} else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
+		/* command is restart and current state is paused */
+		reg_bit_set(XOR_ACTIVATION_REG
+			    (XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XERESTART_MASK);
+		return MV_OK;
+	} else if ((command == MV_STOP) && (state == MV_IDLE)) {
+		/* command is stop and current state is active */
+		return MV_OK;
+	}
+
+	/* illegal command */
+	DB(printf("%s: ERR. Illegal command\n", __func__));
+
+	return MV_BAD_PARAM;
+}
+
+void ddr3_new_tip_ecc_scrub(void)
+{
+	u32 cs_c, max_cs;
+	u32 cs_ena = 0;
+
+	printf("DDR3 Training Sequence - Start scrubbing\n");
+
+	max_cs = hws_ddr3_tip_max_cs_get();
+	for (cs_c = 0; cs_c < max_cs; cs_c++)
+		cs_ena |= 1 << cs_c;
+
+	mv_sys_xor_init(max_cs, cs_ena, 0x80000000, 0);
+
+	mv_xor_mem_init(0, 0x00000000, 0x80000000, 0xdeadbeef, 0xdeadbeef);
+	/* wait for previous transfer completion */
+	while (mv_xor_state_get(0) != MV_IDLE)
+		;
+
+	mv_xor_mem_init(0, 0x80000000, 0x40000000, 0xdeadbeef, 0xdeadbeef);
+
+	/* wait for previous transfer completion */
+	while (mv_xor_state_get(0) != MV_IDLE)
+		;
+
+	/* Return XOR State */
+	mv_sys_xor_finish();
+
+	printf("DDR3 Training Sequence - End scrubbing\n");
+}
diff --git a/drivers/ddr/marvell/a38x/xor.h b/drivers/ddr/marvell/a38x/xor.h
new file mode 100644
index 0000000..7b1e316
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/xor.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _XOR_H
+#define _XOR_H
+
+#define SRAM_BASE		0x40000000
+
+#include "ddr3_hws_hw_training_def.h"
+
+#define MV_XOR_MAX_UNIT		2	/* XOR unit == XOR engine */
+#define MV_XOR_MAX_CHAN		4	/* total channels for all units */
+#define MV_XOR_MAX_CHAN_PER_UNIT 2	/* channels for units */
+
+#define MV_IS_POWER_OF_2(num)	(((num) != 0) && (((num) & ((num) - 1)) == 0))
+
+/*
+ * This structure describes address space window. Window base can be
+ * 64 bit, window size up to 4GB
+ */
+struct addr_win {
+	u32 base_low;		/* 32bit base low       */
+	u32 base_high;		/* 32bit base high      */
+	u32 size;		/* 32bit size           */
+};
+
+/* This structure describes SoC units address decode window	*/
+struct unit_win_info {
+	struct addr_win addr_win;	/* An address window */
+	int enable;		/* Address decode window is enabled/disabled  */
+	u8 attrib;		/* chip select attributes */
+	u8 target_id;		/* Target Id of this MV_TARGET */
+};
+
+/*
+ * This enumerator describes the type of functionality the XOR channel
+ * can have while using the same data structures.
+ */
+enum xor_type {
+	MV_XOR,			/* XOR channel functions as XOR accelerator   */
+	MV_DMA,			/* XOR channel functions as IDMA channel      */
+	MV_CRC32		/* XOR channel functions as CRC 32 calculator */
+};
+
+enum mv_state {
+	MV_IDLE,
+	MV_ACTIVE,
+	MV_PAUSED,
+	MV_UNDEFINED_STATE
+};
+
+/*
+ * This enumerator describes the set of commands that can be applied on
+ * an engine (e.g. IDMA, XOR). Appling a comman depends on the current
+ * status (see MV_STATE enumerator)
+ *
+ * Start can be applied only when status is IDLE
+ * Stop can be applied only when status is IDLE, ACTIVE or PAUSED
+ * Pause can be applied only when status is ACTIVE
+ * Restart can be applied only when status is PAUSED
+ */
+enum mv_command {
+	MV_START,		/* Start     */
+	MV_STOP,		/* Stop     */
+	MV_PAUSE,		/* Pause    */
+	MV_RESTART		/* Restart  */
+};
+
+enum xor_override_target {
+	SRC_ADDR0,		/* Source Address #0 Control */
+	SRC_ADDR1,		/* Source Address #1 Control */
+	SRC_ADDR2,		/* Source Address #2 Control */
+	SRC_ADDR3,		/* Source Address #3 Control */
+	SRC_ADDR4,		/* Source Address #4 Control */
+	SRC_ADDR5,		/* Source Address #5 Control */
+	SRC_ADDR6,		/* Source Address #6 Control */
+	SRC_ADDR7,		/* Source Address #7 Control */
+	XOR_DST_ADDR,		/* Destination Address Control */
+	XOR_NEXT_DESC		/* Next Descriptor Address Control */
+};
+
+enum mv_state mv_xor_state_get(u32 chan);
+void mv_xor_hal_init(u32 xor_chan_num);
+int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl);
+int mv_xor_command_set(u32 chan, enum mv_command command);
+int mv_xor_override_set(u32 chan, enum xor_override_target target, u32 win_num,
+			int enable);
+
+#endif
diff --git a/drivers/ddr/marvell/a38x/xor_regs.h b/drivers/ddr/marvell/a38x/xor_regs.h
new file mode 100644
index 0000000..cc1546e
--- /dev/null
+++ b/drivers/ddr/marvell/a38x/xor_regs.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _XOR_REGS_h
+#define _XOR_REGS_h
+
+/*
+ * For controllers that have two XOR units, then chans 2 & 3 will be
+ * mapped to channels 0 & 1 of unit 1
+ */
+#define XOR_UNIT(chan)	((chan) >> 1)
+#define XOR_CHAN(chan)  ((chan) & 1)
+
+#define MV_XOR_REGS_OFFSET(unit)	(0x60900)
+#define MV_XOR_REGS_BASE(unit)		(MV_XOR_REGS_OFFSET(unit))
+
+/* XOR Engine Control Register Map */
+#define XOR_CHANNEL_ARBITER_REG(unit)	(MV_XOR_REGS_BASE(unit))
+#define XOR_CONFIG_REG(unit, chan)	(MV_XOR_REGS_BASE(unit) + \
+					 (0x10 + ((chan) * 4)))
+#define XOR_ACTIVATION_REG(unit, chan)	(MV_XOR_REGS_BASE(unit) + \
+					 (0x20 + ((chan) * 4)))
+
+/* XOR Engine Interrupt Register Map */
+#define XOR_CAUSE_REG(unit)		(MV_XOR_REGS_BASE(unit)+(0x30))
+#define XOR_MASK_REG(unit)		(MV_XOR_REGS_BASE(unit)+(0x40))
+#define XOR_ERROR_CAUSE_REG(unit)	(MV_XOR_REGS_BASE(unit)+(0x50))
+#define XOR_ERROR_ADDR_REG(unit)	(MV_XOR_REGS_BASE(unit)+(0x60))
+
+/* XOR Engine Descriptor Register Map */
+#define XOR_NEXT_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+					   (0x200 + ((chan) * 4)))
+#define XOR_CURR_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \
+					   (0x210 + ((chan) * 4)))
+#define XOR_BYTE_COUNT_REG(unit, chan)	(MV_XOR_REGS_BASE(unit) + \
+					 (0x220 + ((chan) * 4)))
+
+/* XOR Engine ECC/Mem_init Register Map */
+#define XOR_DST_PTR_REG(unit, chan)	(MV_XOR_REGS_BASE(unit) + \
+					 (0x2b0 + ((chan) * 4)))
+#define XOR_BLOCK_SIZE_REG(unit, chan)	(MV_XOR_REGS_BASE(unit) + \
+					 (0x2c0 + ((chan) * 4)))
+#define XOR_TIMER_MODE_CTRL_REG(unit)	(MV_XOR_REGS_BASE(unit) + (0x2d0))
+#define XOR_TIMER_MODE_INIT_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d4))
+#define XOR_TIMER_MODE_CURR_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d8))
+#define XOR_INIT_VAL_LOW_REG(unit)	(MV_XOR_REGS_BASE(unit) + (0x2e0))
+#define XOR_INIT_VAL_HIGH_REG(unit)	(MV_XOR_REGS_BASE(unit) + (0x2e4))
+
+/* XOR Engine Debug Register Map */
+#define XOR_DEBUG_REG(unit)		(MV_XOR_REGS_BASE(unit) + (0x70))
+
+/* XOR register fileds */
+
+/* XOR Engine Channel Arbiter Register */
+#define XECAR_SLICE_OFFS(slice_num)	(slice_num)
+#define XECAR_SLICE_MASK(slice_num)	(1 << (XECAR_SLICE_OFFS(slice_num)))
+
+/* XOR Engine [0..1] Configuration Registers */
+#define XEXCR_OPERATION_MODE_OFFS	(0)
+#define XEXCR_OPERATION_MODE_MASK	(7 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_XOR	(0 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_CRC	(1 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_DMA	(2 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_ECC	(3 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_MEM_INIT	(4 << XEXCR_OPERATION_MODE_OFFS)
+
+#define XEXCR_SRC_BURST_LIMIT_OFFS	(4)
+#define XEXCR_SRC_BURST_LIMIT_MASK	(7 << XEXCR_SRC_BURST_LIMIT_OFFS)
+#define XEXCR_DST_BURST_LIMIT_OFFS	(8)
+#define XEXCR_DST_BURST_LIMIT_MASK	(7 << XEXCR_DST_BURST_LIMIT_OFFS)
+#define XEXCR_DRD_RES_SWP_OFFS		(12)
+#define XEXCR_DRD_RES_SWP_MASK		(1 << XEXCR_DRD_RES_SWP_OFFS)
+#define XEXCR_DWR_REQ_SWP_OFFS		(13)
+#define XEXCR_DWR_REQ_SWP_MASK		(1 << XEXCR_DWR_REQ_SWP_OFFS)
+#define XEXCR_DES_SWP_OFFS		(14)
+#define XEXCR_DES_SWP_MASK		(1 << XEXCR_DES_SWP_OFFS)
+#define XEXCR_REG_ACC_PROTECT_OFFS	(15)
+#define XEXCR_REG_ACC_PROTECT_MASK	(1 << XEXCR_REG_ACC_PROTECT_OFFS)
+
+/* XOR Engine [0..1] Activation Registers */
+#define XEXACTR_XESTART_OFFS		(0)
+#define XEXACTR_XESTART_MASK		(1 << XEXACTR_XESTART_OFFS)
+#define XEXACTR_XESTOP_OFFS		(1)
+#define XEXACTR_XESTOP_MASK		(1 << XEXACTR_XESTOP_OFFS)
+#define XEXACTR_XEPAUSE_OFFS		(2)
+#define XEXACTR_XEPAUSE_MASK		(1 << XEXACTR_XEPAUSE_OFFS)
+#define XEXACTR_XERESTART_OFFS		(3)
+#define XEXACTR_XERESTART_MASK		(1 << XEXACTR_XERESTART_OFFS)
+#define XEXACTR_XESTATUS_OFFS		(4)
+#define XEXACTR_XESTATUS_MASK		(3 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_IDLE		(0 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_ACTIVE		(1 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_PAUSED		(2 << XEXACTR_XESTATUS_OFFS)
+
+/* XOR Engine Interrupt Cause Register (XEICR) */
+#define XEICR_CHAN_OFFS			16
+#define XEICR_CAUSE_OFFS(chan)		(chan * XEICR_CHAN_OFFS)
+#define XEICR_CAUSE_MASK(chan, cause)	(1 << (cause + XEICR_CAUSE_OFFS(chan)))
+#define XEICR_COMP_MASK_ALL		0x000f000f
+#define XEICR_COMP_MASK(chan)		(0x000f << XEICR_CAUSE_OFFS(chan))
+#define XEICR_ERR_MASK			0x03800380
+
+/* XOR Engine Error Cause Register (XEECR) */
+#define XEECR_ERR_TYPE_OFFS		0
+#define XEECR_ERR_TYPE_MASK		(0x1f << XEECR_ERR_TYPE_OFFS)
+
+/* XOR Engine Error Address Register (XEEAR) */
+#define XEEAR_ERR_ADDR_OFFS		(0)
+#define XEEAR_ERR_ADDR_MASK		(0xffffffff << XEEAR_ERR_ADDR_OFFS)
+
+/* XOR Engine [0..1] Next Descriptor Pointer Register */
+#define XEXNDPR_NEXT_DESC_PTR_OFFS	(0)
+#define XEXNDPR_NEXT_DESC_PTR_MASK	(0xffffffff << \
+					 XEXNDPR_NEXT_DESC_PTR_OFFS)
+
+/* XOR Engine [0..1] Current Descriptor Pointer Register */
+#define XEXCDPR_CURRENT_DESC_PTR_OFFS	(0)
+#define XEXCDPR_CURRENT_DESC_PTR_MASK	(0xffffffff << \
+					 XEXCDPR_CURRENT_DESC_PTR_OFFS)
+
+/* XOR Engine [0..1] Byte Count Register */
+#define XEXBCR_BYTE_CNT_OFFS		(0)
+#define XEXBCR_BYTE_CNT_MASK		(0xffffffff << XEXBCR_BYTE_CNT_OFFS)
+
+/* XOR Engine [0..1] Destination Pointer Register */
+#define XEXDPR_DST_PTR_OFFS		(0)
+#define XEXDPR_DST_PTR_MASK		(0xffffffff << XEXDPR_DST_PTR_OFFS)
+#define XEXDPR_DST_PTR_XOR_MASK		(0x3f)
+#define XEXDPR_DST_PTR_DMA_MASK		(0x1f)
+#define XEXDPR_DST_PTR_CRC_MASK		(0x1f)
+
+/* XOR Engine[0..1] Block Size Registers */
+#define XEXBSR_BLOCK_SIZE_OFFS		(0)
+#define XEXBSR_BLOCK_SIZE_MASK		(0xffffffff << XEXBSR_BLOCK_SIZE_OFFS)
+#define XEXBSR_BLOCK_SIZE_MIN_VALUE	(128)
+#define XEXBSR_BLOCK_SIZE_MAX_VALUE	(0xffffffff)
+
+/* XOR Engine Timer Mode Control Register (XETMCR) */
+#define XETMCR_TIMER_EN_OFFS		(0)
+#define XETMCR_TIMER_EN_MASK		(1 << XETMCR_TIMER_EN_OFFS)
+#define XETMCR_TIMER_EN_ENABLE		(1 << XETMCR_TIMER_EN_OFFS)
+#define XETMCR_TIMER_EN_DISABLE		(0 << XETMCR_TIMER_EN_OFFS)
+#define XETMCR_SECTION_SIZE_CTRL_OFFS	(8)
+#define XETMCR_SECTION_SIZE_CTRL_MASK	(0x1f << XETMCR_SECTION_SIZE_CTRL_OFFS)
+#define XETMCR_SECTION_SIZE_MIN_VALUE	(7)
+#define XETMCR_SECTION_SIZE_MAX_VALUE	(31)
+
+/* XOR Engine Timer Mode Initial Value Register (XETMIVR) */
+#define XETMIVR_TIMER_INIT_VAL_OFFS	(0)
+#define XETMIVR_TIMER_INIT_VAL_MASK	(0xffffffff << \
+					 XETMIVR_TIMER_INIT_VAL_OFFS)
+
+/* XOR Engine Timer Mode Current Value Register (XETMCVR) */
+#define XETMCVR_TIMER_CRNT_VAL_OFFS	(0)
+#define XETMCVR_TIMER_CRNT_VAL_MASK	(0xffffffff << \
+					 XETMCVR_TIMER_CRNT_VAL_OFFS)
+
+/* XOR Engine Initial Value Register Low (XEIVRL) */
+#define XEIVRL_INIT_VAL_L_OFFS		(0)
+#define XEIVRL_INIT_VAL_L_MASK		(0xffffffff << XEIVRL_INIT_VAL_L_OFFS)
+
+/* XOR Engine Initial Value Register High (XEIVRH) */
+#define XEIVRH_INIT_VAL_H_OFFS		(0)
+#define XEIVRH_INIT_VAL_H_MASK		(0xffffffff << XEIVRH_INIT_VAL_H_OFFS)
+
+/* XOR Engine Debug Register (XEDBR) */
+#define XEDBR_PARITY_ERR_INSR_OFFS	(0)
+#define XEDBR_PARITY_ERR_INSR_MASK	(1 << XEDBR_PARITY_ERR_INSR_OFFS)
+#define XEDBR_XBAR_ERR_INSR_OFFS	(1)
+#define XEDBR_XBAR_ERR_INSR_MASK	(1 << XEDBR_XBAR_ERR_INSR_OFFS)
+
+/* XOR Engine address decode registers.	*/
+/* Maximum address decode windows */
+#define XOR_MAX_ADDR_DEC_WIN		8
+/* Maximum address arbiter windows */
+#define XOR_MAX_REMAP_WIN		4
+
+/* XOR Engine Address Decoding Register Map */
+#define XOR_WINDOW_CTRL_REG(unit, chan)	(MV_XOR_REGS_BASE(unit) + \
+					 (0x240 + ((chan) * 4)))
+#define XOR_BASE_ADDR_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+					  (0x250 + ((win_num) * 4)))
+#define XOR_SIZE_MASK_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+					  (0x270 + ((win_num) * 4)))
+#define XOR_HIGH_ADDR_REMAP_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+						(0x290 + ((win_num) * 4)))
+#define XOR_ADDR_OVRD_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \
+					  (0x2a0 + ((win_num) * 4)))
+
+/* XOR Engine [0..1] Window Control Registers */
+#define XEXWCR_WIN_EN_OFFS(win_num)	(win_num)
+#define XEXWCR_WIN_EN_MASK(win_num)	(1 << (XEXWCR_WIN_EN_OFFS(win_num)))
+#define XEXWCR_WIN_EN_ENABLE(win_num)	(1 << (XEXWCR_WIN_EN_OFFS(win_num)))
+#define XEXWCR_WIN_EN_DISABLE(win_num)	(0 << (XEXWCR_WIN_EN_OFFS(win_num)))
+
+#define XEXWCR_WIN_ACC_OFFS(win_num)	((2 * win_num) + 16)
+#define XEXWCR_WIN_ACC_MASK(win_num)	(3 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+#define XEXWCR_WIN_ACC_NO_ACC(win_num)	(0 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+#define XEXWCR_WIN_ACC_RO(win_num)	(1 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+#define XEXWCR_WIN_ACC_RW(win_num)	(3 << (XEXWCR_WIN_ACC_OFFS(win_num)))
+
+/* XOR Engine Base Address Registers (XEBARx) */
+#define XEBARX_TARGET_OFFS		(0)
+#define XEBARX_TARGET_MASK		(0xf << XEBARX_TARGET_OFFS)
+#define XEBARX_ATTR_OFFS		(8)
+#define XEBARX_ATTR_MASK		(0xff << XEBARX_ATTR_OFFS)
+#define XEBARX_BASE_OFFS		(16)
+#define XEBARX_BASE_MASK		(0xffff << XEBARX_BASE_OFFS)
+
+/* XOR Engine Size Mask Registers (XESMRx) */
+#define XESMRX_SIZE_MASK_OFFS		(16)
+#define XESMRX_SIZE_MASK_MASK		(0xffff << XESMRX_SIZE_MASK_OFFS)
+#define XOR_WIN_SIZE_ALIGN		_64K
+
+/* XOR Engine High Address Remap Register (XEHARRx1) */
+#define XEHARRX_REMAP_OFFS		(0)
+#define XEHARRX_REMAP_MASK		(0xffffffff << XEHARRX_REMAP_OFFS)
+
+#define XOR_OVERRIDE_CTRL_REG(chan)	(MV_XOR_REGS_BASE(XOR_UNIT(chan)) + \
+					 (0x2a0 + ((XOR_CHAN(chan)) * 4)))
+
+/* XOR Engine [0..1] Address Override Control Register */
+#define XEXAOCR_OVR_EN_OFFS(target)	(3 * target)
+#define XEXAOCR_OVR_EN_MASK(target)	(1 << (XEXAOCR_OVR_EN_OFFS(target)))
+#define XEXAOCR_OVR_PTR_OFFS(target)	((3 * target) + 1)
+#define XEXAOCR_OVR_PTR_MASK(target)	(3 << (XEXAOCR_OVR_PTR_OFFS(target)))
+#define XEXAOCR_OVR_BAR(win_num, target) (win_num << \
+					  (XEXAOCR_OVR_PTR_OFFS(target)))
+
+/* Maximum address override windows */
+#define XOR_MAX_OVERRIDE_WIN		4
+
+#endif /* _XOR_REGS_h */
diff --git a/drivers/ddr/mvebu/Makefile b/drivers/ddr/marvell/axp/Makefile
similarity index 100%
rename from drivers/ddr/mvebu/Makefile
rename to drivers/ddr/marvell/axp/Makefile
diff --git a/drivers/ddr/mvebu/ddr3_axp.h b/drivers/ddr/marvell/axp/ddr3_axp.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_axp.h
rename to drivers/ddr/marvell/axp/ddr3_axp.h
diff --git a/drivers/ddr/mvebu/ddr3_axp_config.h b/drivers/ddr/marvell/axp/ddr3_axp_config.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_axp_config.h
rename to drivers/ddr/marvell/axp/ddr3_axp_config.h
diff --git a/drivers/ddr/mvebu/ddr3_axp_mc_static.h b/drivers/ddr/marvell/axp/ddr3_axp_mc_static.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_axp_mc_static.h
rename to drivers/ddr/marvell/axp/ddr3_axp_mc_static.h
diff --git a/drivers/ddr/mvebu/ddr3_axp_training_static.h b/drivers/ddr/marvell/axp/ddr3_axp_training_static.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_axp_training_static.h
rename to drivers/ddr/marvell/axp/ddr3_axp_training_static.h
diff --git a/drivers/ddr/mvebu/ddr3_axp_vars.h b/drivers/ddr/marvell/axp/ddr3_axp_vars.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_axp_vars.h
rename to drivers/ddr/marvell/axp/ddr3_axp_vars.h
diff --git a/drivers/ddr/mvebu/ddr3_dfs.c b/drivers/ddr/marvell/axp/ddr3_dfs.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_dfs.c
rename to drivers/ddr/marvell/axp/ddr3_dfs.c
diff --git a/drivers/ddr/mvebu/ddr3_dqs.c b/drivers/ddr/marvell/axp/ddr3_dqs.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_dqs.c
rename to drivers/ddr/marvell/axp/ddr3_dqs.c
diff --git a/drivers/ddr/mvebu/ddr3_hw_training.c b/drivers/ddr/marvell/axp/ddr3_hw_training.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_hw_training.c
rename to drivers/ddr/marvell/axp/ddr3_hw_training.c
diff --git a/drivers/ddr/mvebu/ddr3_hw_training.h b/drivers/ddr/marvell/axp/ddr3_hw_training.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_hw_training.h
rename to drivers/ddr/marvell/axp/ddr3_hw_training.h
diff --git a/drivers/ddr/mvebu/ddr3_init.c b/drivers/ddr/marvell/axp/ddr3_init.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_init.c
rename to drivers/ddr/marvell/axp/ddr3_init.c
diff --git a/drivers/ddr/mvebu/ddr3_init.h b/drivers/ddr/marvell/axp/ddr3_init.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_init.h
rename to drivers/ddr/marvell/axp/ddr3_init.h
diff --git a/drivers/ddr/mvebu/ddr3_patterns_64bit.h b/drivers/ddr/marvell/axp/ddr3_patterns_64bit.h
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_patterns_64bit.h
rename to drivers/ddr/marvell/axp/ddr3_patterns_64bit.h
diff --git a/drivers/ddr/mvebu/ddr3_pbs.c b/drivers/ddr/marvell/axp/ddr3_pbs.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_pbs.c
rename to drivers/ddr/marvell/axp/ddr3_pbs.c
diff --git a/drivers/ddr/mvebu/ddr3_read_leveling.c b/drivers/ddr/marvell/axp/ddr3_read_leveling.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_read_leveling.c
rename to drivers/ddr/marvell/axp/ddr3_read_leveling.c
diff --git a/drivers/ddr/mvebu/ddr3_sdram.c b/drivers/ddr/marvell/axp/ddr3_sdram.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_sdram.c
rename to drivers/ddr/marvell/axp/ddr3_sdram.c
diff --git a/drivers/ddr/mvebu/ddr3_spd.c b/drivers/ddr/marvell/axp/ddr3_spd.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_spd.c
rename to drivers/ddr/marvell/axp/ddr3_spd.c
diff --git a/drivers/ddr/mvebu/ddr3_write_leveling.c b/drivers/ddr/marvell/axp/ddr3_write_leveling.c
similarity index 100%
rename from drivers/ddr/mvebu/ddr3_write_leveling.c
rename to drivers/ddr/marvell/axp/ddr3_write_leveling.c
diff --git a/drivers/ddr/mvebu/xor.c b/drivers/ddr/marvell/axp/xor.c
similarity index 100%
rename from drivers/ddr/mvebu/xor.c
rename to drivers/ddr/marvell/axp/xor.c
diff --git a/drivers/ddr/mvebu/xor.h b/drivers/ddr/marvell/axp/xor.h
similarity index 100%
rename from drivers/ddr/mvebu/xor.h
rename to drivers/ddr/marvell/axp/xor.h
diff --git a/drivers/ddr/mvebu/xor_regs.h b/drivers/ddr/marvell/axp/xor_regs.h
similarity index 100%
rename from drivers/ddr/mvebu/xor_regs.h
rename to drivers/ddr/marvell/axp/xor_regs.h
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 5864850..67c6374 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -6,13 +6,9 @@
 #
 
 ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
 obj-$(CONFIG_AXP_GPIO)		+= axp_gpio.o
 endif
-/* TODO(sjg@chromium.org): Only tegra supports driver model in SPL */
-ifdef CONFIG_TEGRA_GPIO
 obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
-endif
 
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index bf982b9..4efda31 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -48,8 +48,7 @@
 	return ret ? ret : -ENOENT;
 }
 
-int gpio_lookup_name(const char *name, struct udevice **devp,
-		     unsigned int *offsetp, unsigned int *gpiop)
+int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
 {
 	struct gpio_dev_priv *uc_priv = NULL;
 	struct udevice *dev;
@@ -57,8 +56,6 @@
 	int numeric;
 	int ret;
 
-	if (devp)
-		*devp = NULL;
 	numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
 	     dev;
@@ -84,12 +81,33 @@
 	if (!dev)
 		return ret ? ret : -EINVAL;
 
+	desc->dev = dev;
+	desc->offset = offset;
+
+	return 0;
+}
+
+int gpio_lookup_name(const char *name, struct udevice **devp,
+		     unsigned int *offsetp, unsigned int *gpiop)
+{
+	struct gpio_desc desc;
+	int ret;
+
 	if (devp)
-		*devp = dev;
+		*devp = NULL;
+	ret = dm_gpio_lookup_name(name, &desc);
+	if (ret)
+		return ret;
+
+	if (devp)
+		*devp = desc.dev;
 	if (offsetp)
-		*offsetp = offset;
-	if (gpiop)
-		*gpiop = uc_priv->gpio_base + offset;
+		*offsetp = desc.offset;
+	if (gpiop) {
+		struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc.dev);
+
+		*gpiop = uc_priv->gpio_base + desc.offset;
+	}
 
 	return 0;
 }
@@ -109,7 +127,7 @@
 	return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
 }
 
-static int dm_gpio_request(struct gpio_desc *desc, const char *label)
+int dm_gpio_request(struct gpio_desc *desc, const char *label)
 {
 	struct udevice *dev = desc->dev;
 	struct gpio_dev_priv *uc_priv;
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig
new file mode 100644
index 0000000..de5feea
--- /dev/null
+++ b/drivers/led/Kconfig
@@ -0,0 +1,26 @@
+config LED
+	bool "Enable LED support"
+	depends on DM
+	help
+	  Many boards have LEDs which can be used to signal status or alerts.
+	  U-Boot provides a uclass API to implement this feature. LED drivers
+	  can provide access to board-specific LEDs. Use of the device tree
+	  for configuration is encouraged.
+
+config SPL_LED_SUPPORT
+	bool "Enable LED support in SPL"
+	depends on LED
+	help
+	  The LED subsystem adds a small amount of overhead to the image.
+	  If this is acceptable and you have a need to use LEDs in SPL,
+	  enable this option. You will need to enable device tree in SPL
+	  for this to work.
+
+config LED_GPIO
+	bool "LED support for GPIO-connected LEDs"
+	depends on LED && DM_GPIO
+	help
+	  Enable support for LEDs which are connected to GPIO lines. These
+	  GPIOs may be on the SoC or some other device which provides GPIOs.
+	  The GPIO driver must used driver model. LEDs are configured using
+	  the device tree.
diff --git a/drivers/led/Makefile b/drivers/led/Makefile
new file mode 100644
index 0000000..990129e
--- /dev/null
+++ b/drivers/led/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_LED) += led-uclass.o
+obj-$(CONFIG_LED_GPIO) += led_gpio.o
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c
new file mode 100644
index 0000000..784ac87
--- /dev/null
+++ b/drivers/led/led-uclass.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+
+int led_get_by_label(const char *label, struct udevice **devp)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_LED, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev);
+
+		/* Ignore the top-level LED node */
+		if (uc_plat->label && !strcmp(label, uc_plat->label))
+			return uclass_get_device_tail(dev, 0, devp);
+	}
+
+	return -ENODEV;
+}
+
+int led_set_on(struct udevice *dev, int on)
+{
+	struct led_ops *ops = led_get_ops(dev);
+
+	if (!ops->set_on)
+		return -ENOSYS;
+
+	return ops->set_on(dev, on);
+}
+
+UCLASS_DRIVER(led) = {
+	.id		= UCLASS_LED,
+	.name		= "led",
+	.per_device_platdata_auto_alloc_size = sizeof(struct led_uclass_plat),
+};
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
new file mode 100644
index 0000000..cb6e996
--- /dev/null
+++ b/drivers/led/led_gpio.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <asm/gpio.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct led_gpio_priv {
+	struct gpio_desc gpio;
+};
+
+static int gpio_led_set_on(struct udevice *dev, int on)
+{
+	struct led_gpio_priv *priv = dev_get_priv(dev);
+
+	if (!dm_gpio_is_valid(&priv->gpio))
+		return -EREMOTEIO;
+
+	return dm_gpio_set_value(&priv->gpio, on);
+}
+
+static int led_gpio_probe(struct udevice *dev)
+{
+	struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev);
+	struct led_gpio_priv *priv = dev_get_priv(dev);
+
+	/* Ignore the top-level LED node */
+	if (!uc_plat->label)
+		return 0;
+	return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
+}
+
+static int led_gpio_remove(struct udevice *dev)
+{
+	/*
+	 * The GPIO driver may have already been removed. We will need to
+	 * address this more generally.
+	 */
+#ifndef CONFIG_SANDBOX
+	struct led_gpio_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->gpio))
+		dm_gpio_free(dev, &priv->gpio);
+#endif
+
+	return 0;
+}
+
+static int led_gpio_bind(struct udevice *parent)
+{
+	const void *blob = gd->fdt_blob;
+	struct udevice *dev;
+	int node;
+	int ret;
+
+	for (node = fdt_first_subnode(blob, parent->of_offset);
+	     node > 0;
+	     node = fdt_next_subnode(blob, node)) {
+		struct led_uclass_plat *uc_plat;
+		const char *label;
+
+		label = fdt_getprop(blob, node, "label", NULL);
+		if (!label) {
+			debug("%s: node %s has no label\n", __func__,
+			      fdt_get_name(blob, node, NULL));
+			return -EINVAL;
+		}
+		ret = device_bind_driver_to_node(parent, "gpio_led",
+						 fdt_get_name(blob, node, NULL),
+						 node, &dev);
+		if (ret)
+			return ret;
+		uc_plat = dev_get_uclass_platdata(dev);
+		uc_plat->label = label;
+	}
+
+	return 0;
+}
+
+static const struct led_ops gpio_led_ops = {
+	.set_on		= gpio_led_set_on,
+};
+
+static const struct udevice_id led_gpio_ids[] = {
+	{ .compatible = "gpio-leds" },
+	{ }
+};
+
+U_BOOT_DRIVER(led_gpio) = {
+	.name	= "gpio_led",
+	.id	= UCLASS_LED,
+	.of_match = led_gpio_ids,
+	.ops	= &gpio_led_ops,
+	.priv_auto_alloc_size = sizeof(struct led_gpio_priv),
+	.bind	= led_gpio_bind,
+	.probe	= led_gpio_probe,
+	.remove	= led_gpio_remove,
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 64b07a3..3b7f76a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -73,3 +73,12 @@
 	default 0x60
 	help
 	  The I2C address of the PCA9551 LED controller.
+
+config RESET
+	bool "Enable support for reset drivers"
+	depends on DM
+	help
+	  Enable reset drivers which can be used to reset the CPU or board.
+	  Each driver can provide a reset method which will be called to
+	  effect a reset. The uclass will try all available drivers when
+	  reset_walk() is called.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 120babc..5218b91 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -22,13 +22,16 @@
 obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
 obj-$(CONFIG_NS87308) += ns87308.o
 obj-$(CONFIG_PDSP188x) += pdsp188x.o
+obj-$(CONFIG_SANDBOX) += reset_sandbox.o
 ifdef CONFIG_DM_I2C
 obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
 endif
 obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
 obj-$(CONFIG_STATUS_LED) += status_led.o
 obj-$(CONFIG_SANDBOX) += swap_case.o
+obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
 obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
 obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
+obj-$(CONFIG_RESET) += reset-uclass.o
diff --git a/drivers/misc/reset-uclass.c b/drivers/misc/reset-uclass.c
new file mode 100644
index 0000000..fdb5c6f
--- /dev/null
+++ b/drivers/misc/reset-uclass.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <reset.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+int reset_request(struct udevice *dev, enum reset_t type)
+{
+	struct reset_ops *ops = reset_get_ops(dev);
+
+	if (!ops->request)
+		return -ENOSYS;
+
+	return ops->request(dev, type);
+}
+
+int reset_walk(enum reset_t type)
+{
+	struct udevice *dev;
+	int ret = -ENOSYS;
+
+	while (ret != -EINPROGRESS && type < RESET_COUNT) {
+		for (uclass_first_device(UCLASS_RESET, &dev);
+		     dev;
+		     uclass_next_device(&dev)) {
+			ret = reset_request(dev, type);
+			if (ret == -EINPROGRESS)
+				break;
+		}
+		type++;
+	}
+
+	return ret;
+}
+
+void reset_walk_halt(enum reset_t type)
+{
+	int ret;
+
+	ret = reset_walk(type);
+
+	/* Wait for the reset to take effect */
+	if (ret == -EINPROGRESS)
+		mdelay(100);
+
+	/* Still no reset? Give up */
+	printf("Reset not supported on this platform\n");
+	hang();
+}
+
+/**
+ * reset_cpu() - calls reset_walk(RESET_WARM)
+ */
+void reset_cpu(ulong addr)
+{
+	reset_walk_halt(RESET_WARM);
+}
+
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	reset_walk_halt(RESET_WARM);
+
+	return 0;
+}
+
+UCLASS_DRIVER(reset) = {
+	.id		= UCLASS_RESET,
+	.name		= "reset",
+};
diff --git a/drivers/misc/reset_sandbox.c b/drivers/misc/reset_sandbox.c
new file mode 100644
index 0000000..917121b
--- /dev/null
+++ b/drivers/misc/reset_sandbox.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset.h>
+#include <asm/state.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_warm_reset_request(struct udevice *dev, enum reset_t type)
+{
+	struct sandbox_state *state = state_get_current();
+
+	switch (type) {
+	case RESET_WARM:
+		state->last_reset = type;
+		break;
+	default:
+		return -ENOSYS;
+	}
+	if (!state->reset_allowed[type])
+		return -EACCES;
+
+	return -EINPROGRESS;
+}
+
+static int sandbox_reset_request(struct udevice *dev, enum reset_t type)
+{
+	struct sandbox_state *state = state_get_current();
+
+	/*
+	 * If we have a device tree, the device we created from platform data
+	 * (see the U_BOOT_DEVICE() declaration below) should not do anything.
+	 * If we are that device, return an error.
+	 */
+	if (gd->fdt_blob && dev->of_offset == -1)
+		return -ENODEV;
+
+	switch (type) {
+	case RESET_COLD:
+		state->last_reset = type;
+		break;
+	case RESET_POWER:
+		state->last_reset = type;
+		if (!state->reset_allowed[type])
+			return -EACCES;
+		sandbox_exit();
+		break;
+	default:
+		return -ENOSYS;
+	}
+	if (!state->reset_allowed[type])
+		return -EACCES;
+
+	return -EINPROGRESS;
+}
+
+static struct reset_ops sandbox_reset_ops = {
+	.request	= sandbox_reset_request,
+};
+
+static const struct udevice_id sandbox_reset_ids[] = {
+	{ .compatible = "sandbox,reset" },
+	{ }
+};
+
+U_BOOT_DRIVER(reset_sandbox) = {
+	.name		= "reset_sandbox",
+	.id		= UCLASS_RESET,
+	.of_match	= sandbox_reset_ids,
+	.ops		= &sandbox_reset_ops,
+};
+
+static struct reset_ops sandbox_warm_reset_ops = {
+	.request	= sandbox_warm_reset_request,
+};
+
+static const struct udevice_id sandbox_warm_reset_ids[] = {
+	{ .compatible = "sandbox,warm-reset" },
+	{ }
+};
+
+U_BOOT_DRIVER(warm_reset_sandbox) = {
+	.name		= "warm_reset_sandbox",
+	.id		= UCLASS_RESET,
+	.of_match	= sandbox_warm_reset_ids,
+	.ops		= &sandbox_warm_reset_ops,
+};
+
+/* This is here in case we don't have a device tree */
+U_BOOT_DEVICE(reset_sandbox_non_fdt) = {
+	.name = "reset_sandbox",
+};
diff --git a/drivers/misc/syscon_sandbox.c b/drivers/misc/syscon_sandbox.c
new file mode 100644
index 0000000..ccfab3e
--- /dev/null
+++ b/drivers/misc/syscon_sandbox.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id sandbox_syscon_ids[] = {
+	{ .compatible = "sandbox,syscon0", .data = SYSCON0 },
+	{ .compatible = "sandbox,syscon1", .data = SYSCON1 },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_syscon) = {
+	.name	= "sandbox_syscon",
+	.id	= UCLASS_SYSCON,
+	.of_match = sandbox_syscon_ids,
+};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 7ba85a2..3e835f7 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -1,5 +1,15 @@
 menu "MMC Host controller Support"
 
+config DM_MMC
+	bool "Enable MMC controllers using Driver Model"
+	depends on DM
+	help
+	  This enables the MultiMediaCard (MMC) uclass which suports MMC and
+	  Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.)
+	  and non-removable (e.g. eMMC chip) devices are supported. These
+	  appear as block devices in U-Boot and can support filesystems such
+	  as EXT4 and FAT.
+
 config SH_SDHI
 	bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support"
 	depends on RMOBILE
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index ed73687..286df2f 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -5,6 +5,8 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-$(CONFIG_DM_MMC) += mmc-uclass.o
+
 obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
 obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
 obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o
@@ -29,6 +31,7 @@
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
 obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
 obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+obj-$(CONFIG_SANDBOX) += sandbox_mmc.o
 obj-$(CONFIG_SDHCI) += sdhci.o
 obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
new file mode 100644
index 0000000..777489f
--- /dev/null
+++ b/drivers/mmc/mmc-uclass.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+struct mmc *mmc_get_mmc_dev(struct udevice *dev)
+{
+	struct mmc_uclass_priv *upriv;
+
+	if (!device_active(dev))
+		return NULL;
+	upriv = dev_get_uclass_priv(dev);
+	return upriv->mmc;
+}
+
+U_BOOT_DRIVER(mmc) = {
+	.name	= "mmc",
+	.id	= UCLASS_MMC,
+};
+
+UCLASS_DRIVER(mmc) = {
+	.id		= UCLASS_MMC,
+	.name		= "mmc",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv),
+};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 79e6fee..da47037 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -250,14 +250,18 @@
 		return 0;
 	}
 
-	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
+	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
+		debug("%s: Failed to set blocklen\n", __func__);
 		return 0;
+	}
 
 	do {
 		cur = (blocks_todo > mmc->cfg->b_max) ?
 			mmc->cfg->b_max : blocks_todo;
-		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
+		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
+			debug("%s: Failed to read blocks\n", __func__);
 			return 0;
+		}
 		blocks_todo -= cur;
 		start += cur;
 		dst += cur * mmc->read_bl_len;
@@ -1761,8 +1765,10 @@
 	INIT_LIST_HEAD (&mmc_devices);
 	cur_dev_num = 0;
 
+#ifndef CONFIG_DM_MMC
 	if (board_mmc_init(bis) < 0)
 		cpu_mmc_init(bis);
+#endif
 
 #ifndef CONFIG_SPL_BUILD
 	print_mmc_devices(',');
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
new file mode 100644
index 0000000..f4646a8
--- /dev/null
+++ b/drivers/mmc/sandbox_mmc.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mmc.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id sandbox_mmc_ids[] = {
+	{ .compatible = "sandbox,mmc" },
+	{ }
+};
+
+U_BOOT_DRIVER(warm_mmc_sandbox) = {
+	.name		= "mmc_sandbox",
+	.id		= UCLASS_MMC,
+	.of_match	= sandbox_mmc_ids,
+};
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 645ca64..bcae842 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -528,7 +528,7 @@
 	return _dw_eth_send(priv, packet, length);
 }
 
-static int designware_eth_recv(struct udevice *dev, uchar **packetp)
+static int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct dw_eth_dev *priv = dev_get_priv(dev);
 
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index 958488c..7b6e20f 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -41,10 +41,13 @@
  * Modified to use le32_to_cpu and cpu_to_le32 properly
  */
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <malloc.h>
 #include <net.h>
+#ifndef CONFIG_DM_ETH
 #include <netdev.h>
+#endif
 #include <asm/io.h>
 #include <pci.h>
 
@@ -281,6 +284,8 @@
 	u32 buf_Haddr;
 };
 
+static unsigned char rxdata[RX_BUF_LEN];
+
 #define RTL8169_DESC_SIZE 16
 
 #if ARCH_DMA_MINALIGN > 256
@@ -299,7 +304,8 @@
  * the driver to allocate descriptors from a pool of non-cached memory.
  */
 #if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN
-#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \
+	!defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86)
 #warning cache-line size is larger than descriptor size
 #endif
 #endif
@@ -317,6 +323,7 @@
 DEFINE_ALIGN_BUFFER(u8, rxb, NUM_RX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
 
 struct rtl8169_private {
+	ulong iobase;
 	void *mmio_addr;	/* memory map physical address */
 	int chipset;
 	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
@@ -338,9 +345,9 @@
     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
 static struct pci_device_id supported[] = {
-	{PCI_VENDOR_ID_REALTEK, 0x8167},
-	{PCI_VENDOR_ID_REALTEK, 0x8168},
-	{PCI_VENDOR_ID_REALTEK, 0x8169},
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169) },
 	{}
 };
 
@@ -380,7 +387,7 @@
 	return value;
 }
 
-static int rtl8169_init_board(struct eth_device *dev)
+static int rtl8169_init_board(unsigned long dev_iobase, const char *name)
 {
 	int i;
 	u32 tmp;
@@ -388,7 +395,7 @@
 #ifdef DEBUG_RTL8169
 	printf ("%s\n", __FUNCTION__);
 #endif
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	/* Soft reset the chip. */
 	RTL_W8(ChipCmd, CmdReset);
@@ -412,7 +419,8 @@
 	}
 
 	/* if unknown chip, assume array element #0, original RTL-8169 in this case */
-	printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name);
+	printf("PCI device %s: unknown chip version, assuming RTL-8169\n",
+	       name);
 	printf("PCI device: TxConfig = 0x%lX\n", (unsigned long) RTL_R32(TxConfig));
 	tpc->chipset = 0;
 
@@ -504,7 +512,8 @@
 /**************************************************************************
 RECV - Receive a frame
 ***************************************************************************/
-static int rtl_recv(struct eth_device *dev)
+static int rtl_recv_common(pci_dev_t bdf, unsigned long dev_iobase,
+			   uchar **packetp)
 {
 	/* return true if there's an ethernet packet ready to read */
 	/* nic->packet should contain data on return */
@@ -515,7 +524,7 @@
 #ifdef DEBUG_RTL8169_RX
 	printf ("%s\n", __FUNCTION__);
 #endif
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	cur_rx = tpc->cur_rx;
 
@@ -523,7 +532,6 @@
 
 	if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) {
 		if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) {
-			unsigned char rxdata[RX_BUF_LEN];
 			length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx].
 						status) & 0x00001FFF) - 4;
 
@@ -536,17 +544,22 @@
 			else
 				tpc->RxDescArray[cur_rx].status =
 					cpu_to_le32(OWNbit + RX_BUF_SIZE);
-			tpc->RxDescArray[cur_rx].buf_addr =
-				cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx]));
+			tpc->RxDescArray[cur_rx].buf_addr = cpu_to_le32(
+				pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)
+				tpc->RxBufferRing[cur_rx]));
 			rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]);
-
+#ifdef CONFIG_DM_ETH
+			*packetp = rxdata;
+#else
 			net_process_received_packet(rxdata, length);
+#endif
 		} else {
 			puts("Error Rx");
+			length = -EIO;
 		}
 		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
 		tpc->cur_rx = cur_rx;
-		return 1;
+		return length;
 
 	} else {
 		ushort sts = RTL_R8(IntrStatus);
@@ -557,11 +570,26 @@
 	return (0);		/* initially as this is called to flush the input */
 }
 
+#ifdef CONFIG_DM_ETH
+int rtl8169_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct rtl8169_private *priv = dev_get_priv(dev);
+
+	return rtl_recv_common(pci_get_bdf(dev), priv->iobase, packetp);
+}
+#else
+static int rtl_recv(struct eth_device *dev)
+{
+	return rtl_recv_common((pci_dev_t)dev->priv, dev->iobase, NULL);
+}
+#endif /* nCONFIG_DM_ETH */
+
 #define HZ 1000
 /**************************************************************************
 SEND - Transmit a frame
 ***************************************************************************/
-static int rtl_send(struct eth_device *dev, void *packet, int length)
+static int rtl_send_common(pci_dev_t bdf, unsigned long dev_iobase,
+			   void *packet, int length)
 {
 	/* send the packet to destination */
 
@@ -577,7 +605,7 @@
 	printf("sending %d bytes\n", len);
 #endif
 
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	/* point to the current txb incase multiple tx_rings are used */
 	ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
@@ -588,7 +616,8 @@
 		ptxb[len++] = '\0';
 
 	tpc->TxDescArray[entry].buf_Haddr = 0;
-	tpc->TxDescArray[entry].buf_addr = cpu_to_le32(bus_to_phys(ptxb));
+	tpc->TxDescArray[entry].buf_addr = cpu_to_le32(
+		pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)ptxb));
 	if (entry != (NUM_TX_DESC - 1)) {
 		tpc->TxDescArray[entry].status =
 			cpu_to_le32((OWNbit | FSbit | LSbit) |
@@ -625,7 +654,23 @@
 	return ret;
 }
 
-static void rtl8169_set_rx_mode(struct eth_device *dev)
+#ifdef CONFIG_DM_ETH
+int rtl8169_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct rtl8169_private *priv = dev_get_priv(dev);
+
+	return rtl_send_common(pci_get_bdf(dev), priv->iobase, packet, length);
+}
+
+#else
+static int rtl_send(struct eth_device *dev, void *packet, int length)
+{
+	return rtl_send_common((pci_dev_t)dev->priv, dev->iobase, packet,
+			       length);
+}
+#endif
+
+static void rtl8169_set_rx_mode(void)
 {
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int rx_mode;
@@ -648,7 +693,7 @@
 	RTL_W32(MAR0 + 4, mc_filter[1]);
 }
 
-static void rtl8169_hw_start(struct eth_device *dev)
+static void rtl8169_hw_start(pci_dev_t bdf)
 {
 	u32 i;
 
@@ -693,9 +738,11 @@
 
 	tpc->cur_rx = 0;
 
-	RTL_W32(TxDescStartAddrLow, bus_to_phys(tpc->TxDescArray));
+	RTL_W32(TxDescStartAddrLow, pci_mem_to_phys(bdf,
+			(pci_addr_t)(unsigned long)tpc->TxDescArray));
 	RTL_W32(TxDescStartAddrHigh, (unsigned long)0);
-	RTL_W32(RxDescStartAddrLow, bus_to_phys(tpc->RxDescArray));
+	RTL_W32(RxDescStartAddrLow, pci_mem_to_phys(
+			bdf, (pci_addr_t)(unsigned long)tpc->RxDescArray));
 	RTL_W32(RxDescStartAddrHigh, (unsigned long)0);
 
 	/* RTL-8169sc/8110sc or later version */
@@ -707,7 +754,7 @@
 
 	RTL_W32(RxMissed, 0);
 
-	rtl8169_set_rx_mode(dev);
+	rtl8169_set_rx_mode();
 
 	/* no early-rx interrupts */
 	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
@@ -717,7 +764,7 @@
 #endif
 }
 
-static void rtl8169_init_ring(struct eth_device *dev)
+static void rtl8169_init_ring(pci_dev_t bdf)
 {
 	int i;
 
@@ -745,8 +792,8 @@
 				cpu_to_le32(OWNbit + RX_BUF_SIZE);
 
 		tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
-		tpc->RxDescArray[i].buf_addr =
-			cpu_to_le32(bus_to_phys(tpc->RxBufferRing[i]));
+		tpc->RxDescArray[i].buf_addr = cpu_to_le32(pci_mem_to_phys(
+			bdf, (pci_addr_t)(unsigned long)tpc->RxBufferRing[i]));
 		rtl_flush_rx_desc(&tpc->RxDescArray[i]);
 	}
 
@@ -755,10 +802,7 @@
 #endif
 }
 
-/**************************************************************************
-RESET - Finish setting up the ethernet interface
-***************************************************************************/
-static int rtl_reset(struct eth_device *dev, bd_t *bis)
+static void rtl8169_common_start(pci_dev_t bdf, unsigned char *enetaddr)
 {
 	int i;
 
@@ -767,30 +811,47 @@
 	printf ("%s\n", __FUNCTION__);
 #endif
 
-	rtl8169_init_ring(dev);
-	rtl8169_hw_start(dev);
+	rtl8169_init_ring(bdf);
+	rtl8169_hw_start(bdf);
 	/* Construct a perfect filter frame with the mac address as first match
 	 * and broadcast for all others */
 	for (i = 0; i < 192; i++)
 		txb[i] = 0xFF;
 
-	txb[0] = dev->enetaddr[0];
-	txb[1] = dev->enetaddr[1];
-	txb[2] = dev->enetaddr[2];
-	txb[3] = dev->enetaddr[3];
-	txb[4] = dev->enetaddr[4];
-	txb[5] = dev->enetaddr[5];
+	txb[0] = enetaddr[0];
+	txb[1] = enetaddr[1];
+	txb[2] = enetaddr[2];
+	txb[3] = enetaddr[3];
+	txb[4] = enetaddr[4];
+	txb[5] = enetaddr[5];
 
 #ifdef DEBUG_RTL8169
 	printf("%s elapsed time : %lu\n", __func__, currticks()-stime);
 #endif
-	return 0;
 }
 
+#ifdef CONFIG_DM_ETH
+static int rtl8169_eth_start(struct udevice *dev)
+{
+	struct eth_pdata *plat = dev_get_platdata(dev);
+
+	rtl8169_common_start(pci_get_bdf(dev), plat->enetaddr);
+
+	return 0;
+}
+#else
 /**************************************************************************
-HALT - Turn off ethernet interface
+RESET - Finish setting up the ethernet interface
 ***************************************************************************/
-static void rtl_halt(struct eth_device *dev)
+static int rtl_reset(struct eth_device *dev, bd_t *bis)
+{
+	rtl8169_common_start((pci_dev_t)dev->priv, dev->enetaddr);
+
+	return 0;
+}
+#endif /* nCONFIG_DM_ETH */
+
+static void rtl_halt_common(unsigned long dev_iobase)
 {
 	int i;
 
@@ -798,7 +859,7 @@
 	printf ("%s\n", __FUNCTION__);
 #endif
 
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	/* Stop the chip's Tx and Rx DMA processes. */
 	RTL_W8(ChipCmd, 0x00);
@@ -813,13 +874,31 @@
 	}
 }
 
+#ifdef CONFIG_DM_ETH
+void rtl8169_eth_stop(struct udevice *dev)
+{
+	struct rtl8169_private *priv = dev_get_priv(dev);
+
+	rtl_halt_common(priv->iobase);
+}
+#else
+/**************************************************************************
+HALT - Turn off ethernet interface
+***************************************************************************/
+static void rtl_halt(struct eth_device *dev)
+{
+	rtl_halt_common(dev->iobase);
+}
+#endif
+
 /**************************************************************************
 INIT - Look for an adapter, this routine's visible to the outside
 ***************************************************************************/
 
 #define board_found 1
 #define valid_link 0
-static int rtl_init(struct eth_device *dev, bd_t *bis)
+static int rtl_init(unsigned long dev_ioaddr, const char *name,
+		    unsigned char *enetaddr)
 {
 	static int board_idx = -1;
 	int i, rc;
@@ -828,33 +907,32 @@
 #ifdef DEBUG_RTL8169
 	printf ("%s\n", __FUNCTION__);
 #endif
-
-	ioaddr = dev->iobase;
+	ioaddr = dev_ioaddr;
 
 	board_idx++;
 
 	/* point to private storage */
 	tpc = &tpx;
 
-	rc = rtl8169_init_board(dev);
+	rc = rtl8169_init_board(ioaddr, name);
 	if (rc)
 		return rc;
 
 	/* Get MAC address.  FIXME: read EEPROM */
 	for (i = 0; i < MAC_ADDR_LEN; i++)
-		dev->enetaddr[i] = RTL_R8(MAC0 + i);
+		enetaddr[i] = RTL_R8(MAC0 + i);
 
 #ifdef DEBUG_RTL8169
 	printf("chipset = %d\n", tpc->chipset);
 	printf("MAC Address");
 	for (i = 0; i < MAC_ADDR_LEN; i++)
-		printf(":%02x", dev->enetaddr[i]);
+		printf(":%02x", enetaddr[i]);
 	putc('\n');
 #endif
 
 #ifdef DEBUG_RTL8169
 	/* Print out some hardware info */
-	printf("%s: at ioaddr 0x%lx\n", dev->name, ioaddr);
+	printf("%s: at ioaddr 0x%lx\n", name, ioaddr);
 #endif
 
 	/* if TBI is not endbled */
@@ -964,6 +1042,7 @@
 	return 0;
 }
 
+#ifndef CONFIG_DM_ETH
 int rtl8169_initialize(bd_t *bis)
 {
 	pci_dev_t devno;
@@ -1014,7 +1093,7 @@
 		dev->send = rtl_send;
 		dev->recv = rtl_recv;
 
-		err = rtl_init(dev, bis);
+		err = rtl_init(dev->iobase, dev->name, dev->enetaddr);
 		if (err < 0) {
 			printf(pr_fmt("failed to initialize card: %d\n"), err);
 			free(dev);
@@ -1027,3 +1106,62 @@
 	}
 	return card_number;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int rtl8169_eth_probe(struct udevice *dev)
+{
+	struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
+	struct rtl8169_private *priv = dev_get_priv(dev);
+	struct eth_pdata *plat = dev_get_platdata(dev);
+	u32 iobase;
+	int region;
+	int ret;
+
+	debug("rtl8169: REALTEK RTL8169 @0x%x\n", iobase);
+	switch (pplat->device) {
+	case 0x8168:
+		region = 2;
+		break;
+	default:
+		region = 1;
+		break;
+	}
+	pci_read_config32(pci_get_bdf(dev), PCI_BASE_ADDRESS_0 + region * 4,
+			  &iobase);
+	iobase &= ~0xf;
+	priv->iobase = (int)pci_mem_to_phys(pci_get_bdf(dev), iobase);
+
+	ret = rtl_init(priv->iobase, dev->name, plat->enetaddr);
+	if (ret < 0) {
+		printf(pr_fmt("failed to initialize card: %d\n"), ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct eth_ops rtl8169_eth_ops = {
+	.start	= rtl8169_eth_start,
+	.send	= rtl8169_eth_send,
+	.recv	= rtl8169_eth_recv,
+	.stop	= rtl8169_eth_stop,
+};
+
+static const struct udevice_id rtl8169_eth_ids[] = {
+	{ .compatible = "realtek,rtl8169" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_rtl8169) = {
+	.name	= "eth_rtl8169",
+	.id	= UCLASS_ETH,
+	.of_match = rtl8169_eth_ids,
+	.probe	= rtl8169_eth_probe,
+	.ops	= &rtl8169_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct rtl8169_private),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+U_BOOT_PCI_DEVICE(eth_rtl8169, supported);
+#endif
diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c
index 45c3b18..5912427 100644
--- a/drivers/net/sandbox-raw.c
+++ b/drivers/net/sandbox-raw.c
@@ -65,7 +65,7 @@
 	return sandbox_eth_raw_os_send(packet, length, priv);
 }
 
-static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp)
+static int sb_eth_raw_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c
index 4e083d3..6763a24 100644
--- a/drivers/net/sandbox.c
+++ b/drivers/net/sandbox.c
@@ -152,7 +152,7 @@
 	return 0;
 }
 
-static int sb_eth_recv(struct udevice *dev, uchar **packetp)
+static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
 
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
index e939bf2..11cd0ea 100644
--- a/drivers/net/sunxi_emac.c
+++ b/drivers/net/sunxi_emac.c
@@ -527,7 +527,7 @@
 	return _sunxi_emac_eth_send(priv, packet, length);
 }
 
-static int sunxi_emac_eth_recv(struct udevice *dev, uchar **packetp)
+static int sunxi_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct emac_eth_dev *priv = dev_get_priv(dev);
 	int rx_len;
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 5b91fe3..3be76c9 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -30,6 +30,14 @@
 	return dev_get_uclass_priv(bus);
 }
 
+pci_dev_t pci_get_bdf(struct udevice *dev)
+{
+	struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
+	struct udevice *bus = dev->parent;
+
+	return PCI_ADD_BUS(bus->seq, pplat->devfn);
+}
+
 /**
  * pci_get_bus_max() - returns the bus number of the last active bus
  *
@@ -295,19 +303,14 @@
 	for (ret = device_find_first_child(bus, &dev);
 	     !ret && dev;
 	     ret = device_find_next_child(&dev)) {
-		struct pci_child_platdata *pplat;
 		struct pci_controller *ctlr_hose;
-
-		pplat = dev_get_parent_platdata(dev);
 		unsigned int max_bus;
-		pci_dev_t bdf;
 
-		bdf = PCI_ADD_BUS(bus->seq, pplat->devfn);
 		debug("%s: device %s\n", __func__, dev->name);
 
 		/* The root controller has the region information */
 		ctlr_hose = hose->ctlr->uclass_priv;
-		max_bus = pciauto_config_device(ctlr_hose, bdf);
+		max_bus = pciauto_config_device(ctlr_hose, pci_get_bdf(dev));
 		sub_bus = max(sub_bus, max_bus);
 	}
 	debug("%s: done\n", __func__);
@@ -353,6 +356,101 @@
 	return sub_bus;
 }
 
+/**
+ * pci_match_one_device - Tell if a PCI device structure has a matching
+ *                        PCI device id structure
+ * @id: single PCI device id structure to match
+ * @dev: the PCI device structure to match against
+ *
+ * Returns the matching pci_device_id structure or %NULL if there is no match.
+ */
+static bool pci_match_one_id(const struct pci_device_id *id,
+			     const struct pci_device_id *find)
+{
+	if ((id->vendor == PCI_ANY_ID || id->vendor == find->vendor) &&
+	    (id->device == PCI_ANY_ID || id->device == find->device) &&
+	    (id->subvendor == PCI_ANY_ID || id->subvendor == find->subvendor) &&
+	    (id->subdevice == PCI_ANY_ID || id->subdevice == find->subdevice) &&
+	    !((id->class ^ find->class) & id->class_mask))
+		return true;
+
+	return false;
+}
+
+/**
+ * pci_find_and_bind_driver() - Find and bind the right PCI driver
+ *
+ * This only looks at certain fields in the descriptor.
+ */
+static int pci_find_and_bind_driver(struct udevice *parent,
+				    struct pci_device_id *find_id, int devfn,
+				    struct udevice **devp)
+{
+	struct pci_driver_entry *start, *entry;
+	const char *drv;
+	int n_ents;
+	int ret;
+	char name[30], *str;
+
+	*devp = NULL;
+
+	debug("%s: Searching for driver: vendor=%x, device=%x\n", __func__,
+	      find_id->vendor, find_id->device);
+	start = ll_entry_start(struct pci_driver_entry, pci_driver_entry);
+	n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry);
+	for (entry = start; entry != start + n_ents; entry++) {
+		const struct pci_device_id *id;
+		struct udevice *dev;
+		const struct driver *drv;
+
+		for (id = entry->match;
+		     id->vendor || id->subvendor || id->class_mask;
+		     id++) {
+			if (!pci_match_one_id(id, find_id))
+				continue;
+
+			drv = entry->driver;
+			/*
+			 * We could pass the descriptor to the driver as
+			 * platdata (instead of NULL) and allow its bind()
+			 * method to return -ENOENT if it doesn't support this
+			 * device. That way we could continue the search to
+			 * find another driver. For now this doesn't seem
+			 * necesssary, so just bind the first match.
+			 */
+			ret = device_bind(parent, drv, drv->name, NULL, -1,
+					  &dev);
+			if (ret)
+				goto error;
+			debug("%s: Match found: %s\n", __func__, drv->name);
+			dev->driver_data = find_id->driver_data;
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	/* Bind a generic driver so that the device can be used */
+	sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(devfn),
+		PCI_FUNC(devfn));
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	drv = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI ? "pci_bridge_drv" :
+			"pci_generic_drv";
+	ret = device_bind_driver(parent, drv, str, devp);
+	if (ret) {
+		debug("%s: Failed to bind generic driver: %d", __func__, ret);
+		return ret;
+	}
+	debug("%s: No match found: bound generic driver instead\n", __func__);
+
+	return 0;
+
+error:
+	debug("%s: No match found: error %d\n", __func__, ret);
+	return ret;
+}
+
 int pci_bind_bus_devices(struct udevice *bus)
 {
 	ulong vendor, device;
@@ -387,25 +485,33 @@
 		      bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));
 		pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device,
 				    PCI_SIZE_16);
-		pci_bus_read_config(bus, devfn, PCI_CLASS_DEVICE, &class,
-				    PCI_SIZE_16);
+		pci_bus_read_config(bus, devfn, PCI_CLASS_REVISION, &class,
+				    PCI_SIZE_32);
+		class >>= 8;
 
 		/* Find this device in the device tree */
 		ret = pci_bus_find_devfn(bus, devfn, &dev);
 
+		/* Search for a driver */
+
 		/* If nothing in the device tree, bind a generic device */
 		if (ret == -ENODEV) {
-			char name[30], *str;
-			const char *drv;
+			struct pci_device_id find_id;
+			ulong val;
 
-			sprintf(name, "pci_%x:%x.%x", bus->seq,
-				PCI_DEV(devfn), PCI_FUNC(devfn));
-			str = strdup(name);
-			if (!str)
-				return -ENOMEM;
-			drv = class == PCI_CLASS_BRIDGE_PCI ?
-				"pci_bridge_drv" : "pci_generic_drv";
-			ret = device_bind_driver(bus, drv, str, &dev);
+			memset(&find_id, '\0', sizeof(find_id));
+			find_id.vendor = vendor;
+			find_id.device = device;
+			find_id.class = class;
+			if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
+				pci_bus_read_config(bus, devfn,
+						    PCI_SUBSYSTEM_VENDOR_ID,
+						    &val, PCI_SIZE_32);
+				find_id.subvendor = val & 0xffff;
+				find_id.subdevice = val >> 16;
+			}
+			ret = pci_find_and_bind_driver(bus, &find_id, devfn,
+						       &dev);
 		}
 		if (ret)
 			return ret;
diff --git a/drivers/pci/pci_compat.c b/drivers/pci/pci_compat.c
index d6938c1..05c3510 100644
--- a/drivers/pci/pci_compat.c
+++ b/drivers/pci/pci_compat.c
@@ -31,13 +31,9 @@
 
 pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
 {
-	struct pci_child_platdata *pplat;
-	struct udevice *bus, *dev;
+	struct udevice *dev;
 
 	if (pci_find_device_id(ids, index, &dev))
 		return -1;
-	bus = dev->parent;
-	pplat = dev_get_parent_platdata(dev);
-
-	return PCI_ADD_BUS(bus->seq, pplat->devfn);
+	return pci_get_bdf(dev);
 }
diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c
index 812ac13..d99cb9a 100644
--- a/drivers/power/pmic/pmic-uclass.c
+++ b/drivers/power/pmic/pmic-uclass.c
@@ -9,6 +9,7 @@
 #include <fdtdec.h>
 #include <errno.h>
 #include <dm.h>
+#include <vsprintf.h>
 #include <dm/lists.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
@@ -17,16 +18,6 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static ulong str_get_num(const char *ptr, const char *maxptr)
-{
-	if (!ptr || !maxptr)
-		return 0;
-
-	while (!isdigit(*ptr) && ptr++ < maxptr);
-
-	return simple_strtoul(ptr, NULL, 0);
-}
-
 int pmic_bind_children(struct udevice *pmic, int offset,
 		       const struct pmic_child_info *child_info)
 {
@@ -35,7 +26,6 @@
 	struct driver *drv;
 	struct udevice *child;
 	const char *node_name;
-	int node_name_len;
 	int bind_count = 0;
 	int node;
 	int prefix_len;
@@ -47,19 +37,19 @@
 	for (node = fdt_first_subnode(blob, offset);
 	     node > 0;
 	     node = fdt_next_subnode(blob, node)) {
-		node_name = fdt_get_name(blob, node, &node_name_len);
+		node_name = fdt_get_name(blob, node, NULL);
 
 		debug("* Found child node: '%s' at offset:%d\n", node_name,
 								 node);
 
 		child = NULL;
 		for (info = child_info; info->prefix && info->driver; info++) {
-			prefix_len = strlen(info->prefix);
-			if (strncasecmp(info->prefix, node_name, prefix_len))
-				continue;
-
 			debug("  - compatible prefix: '%s'\n", info->prefix);
 
+			prefix_len = strlen(info->prefix);
+			if (strncmp(info->prefix, node_name, prefix_len))
+				continue;
+
 			drv = lists_driver_lookup_name(info->driver);
 			if (!drv) {
 				debug("  - driver: '%s' not found!\n",
@@ -78,10 +68,7 @@
 
 			debug("  - bound child device: '%s'\n", child->name);
 
-			child->driver_data = str_get_num(node_name +
-							 prefix_len,
-							 node_name +
-							 node_name_len);
+			child->driver_data = trailing_strtol(node_name);
 
 			debug("  - set 'child->driver_data': %lu\n",
 			      child->driver_data);
@@ -139,6 +126,38 @@
 	return ops->write(dev, reg, buffer, len);
 }
 
+int pmic_reg_read(struct udevice *dev, uint reg)
+{
+	u8 byte;
+	int ret;
+
+	ret = pmic_read(dev, reg, &byte, 1);
+	debug("%s: reg=%x, value=%x\n", __func__, reg, byte);
+
+	return ret ? ret : byte;
+}
+
+int pmic_reg_write(struct udevice *dev, uint reg, uint value)
+{
+	u8 byte = value;
+
+	debug("%s: reg=%x, value=%x\n", __func__, reg, value);
+	return pmic_read(dev, reg, &byte, 1);
+}
+
+int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set)
+{
+	u8 byte;
+	int ret;
+
+	ret = pmic_reg_read(dev, reg);
+	if (ret < 0)
+		return ret;
+	byte = (ret & ~clr) | set;
+
+	return pmic_reg_write(dev, reg, byte);
+}
+
 UCLASS_DRIVER(pmic) = {
 	.id		= UCLASS_PMIC,
 	.name		= "pmic",
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index 31ffd44..12e141b 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -138,87 +138,57 @@
 	return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
 }
 
-static int failed(int ret, bool verbose, const char *fmt, ...)
+int regulator_autoset(struct udevice *dev)
 {
-	va_list args;
-	char buf[64];
+	struct dm_regulator_uclass_platdata *uc_pdata;
+	int ret = 0;
 
-	if (verbose == false)
-		return ret;
+	uc_pdata = dev_get_uclass_platdata(dev);
+	if (!uc_pdata->always_on && !uc_pdata->boot_on)
+		return -EMEDIUMTYPE;
 
-	va_start(args, fmt);
-	vscnprintf(buf, sizeof(buf), fmt, args);
-	va_end(args);
-
-	printf(buf);
+	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+		ret = regulator_set_value(dev, uc_pdata->min_uV);
+	if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
+		ret = regulator_set_current(dev, uc_pdata->min_uA);
 
 	if (!ret)
-		return 0;
-
-	printf(" (ret: %d)", ret);
+		ret = regulator_set_enable(dev, true);
 
 	return ret;
 }
 
-int regulator_autoset(const char *platname,
-		      struct udevice **devp,
-		      bool verbose)
+static void regulator_show(struct udevice *dev, int ret)
 {
 	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+
+	printf("%s@%s: ", dev->name, uc_pdata->name);
+	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+		printf("set %d uV", uc_pdata->min_uV);
+	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
+		printf("; set %d uA", uc_pdata->min_uA);
+	printf("; enabling");
+	if (ret)
+		printf(" (ret: %d)\n", ret);
+	printf("\n");
+}
+
+int regulator_autoset_by_name(const char *platname, struct udevice **devp)
+{
 	struct udevice *dev;
 	int ret;
 
-	if (devp)
-		*devp = NULL;
-
 	ret = regulator_get_by_platname(platname, &dev);
+	if (devp)
+		*devp = dev;
 	if (ret) {
-		error("Can get the regulator: %s!", platname);
+		debug("Can get the regulator: %s!", platname);
 		return ret;
 	}
 
-	uc_pdata = dev_get_uclass_platdata(dev);
-	if (!uc_pdata) {
-		error("Can get the regulator %s uclass platdata!", platname);
-		return -ENXIO;
-	}
-
-	if (!uc_pdata->always_on && !uc_pdata->boot_on)
-		goto retdev;
-
-	if (verbose)
-		printf("%s@%s: ", dev->name, uc_pdata->name);
-
-	/* Those values are optional (-ENODATA if unset) */
-	if ((uc_pdata->min_uV != -ENODATA) &&
-	    (uc_pdata->max_uV != -ENODATA) &&
-	    (uc_pdata->min_uV == uc_pdata->max_uV)) {
-		ret = regulator_set_value(dev, uc_pdata->min_uV);
-		if (failed(ret, verbose, "set %d uV", uc_pdata->min_uV))
-			goto exit;
-	}
-
-	/* Those values are optional (-ENODATA if unset) */
-	if ((uc_pdata->min_uA != -ENODATA) &&
-	    (uc_pdata->max_uA != -ENODATA) &&
-	    (uc_pdata->min_uA == uc_pdata->max_uA)) {
-		ret = regulator_set_current(dev, uc_pdata->min_uA);
-		if (failed(ret, verbose, "; set %d uA", uc_pdata->min_uA))
-			goto exit;
-	}
-
-	ret = regulator_set_enable(dev, true);
-	if (failed(ret, verbose, "; enabling", uc_pdata->min_uA))
-		goto exit;
-
-retdev:
-	if (devp)
-		*devp = dev;
-exit:
-	if (verbose)
-		printf("\n");
-
-	return ret;
+	return regulator_autoset(dev);
 }
 
 int regulator_list_autoset(const char *list_platname[],
@@ -229,7 +199,9 @@
 	int error = 0, i = 0, ret;
 
 	while (list_platname[i]) {
-		ret = regulator_autoset(list_platname[i], &dev, verbose);
+		ret = regulator_autoset_by_name(list_platname[i], &dev);
+		if (ret != -EMEDIUMTYPE && verbose)
+			regulator_show(dev, ret);
 		if (ret & !error)
 			error = ret;
 
@@ -290,7 +262,7 @@
 	if (regulator_name_is_unique(dev, uc_pdata->name))
 		return 0;
 
-	error("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
+	debug("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
 	      property, dev->name, uc_pdata->name);
 
 	return -EINVAL;
@@ -319,9 +291,43 @@
 	uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
 					    "regulator-boot-on");
 
+	/* Those values are optional (-ENODATA if unset) */
+	if ((uc_pdata->min_uV != -ENODATA) &&
+	    (uc_pdata->max_uV != -ENODATA) &&
+	    (uc_pdata->min_uV == uc_pdata->max_uV))
+		uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
+
+	/* Those values are optional (-ENODATA if unset) */
+	if ((uc_pdata->min_uA != -ENODATA) &&
+	    (uc_pdata->max_uA != -ENODATA) &&
+	    (uc_pdata->min_uA == uc_pdata->max_uA))
+		uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
+
 	return 0;
 }
 
+int regulators_enable_boot_on(bool verbose)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_REGULATOR, &uc);
+	if (ret)
+		return ret;
+	for (uclass_first_device(UCLASS_REGULATOR, &dev);
+	     dev && !ret;
+	     uclass_next_device(&dev)) {
+		ret = regulator_autoset(dev);
+		if (ret == -EMEDIUMTYPE)
+			continue;
+		if (verbose)
+			regulator_show(dev, ret);
+	}
+
+	return ret;
+}
+
 UCLASS_DRIVER(regulator) = {
 	.id		= UCLASS_REGULATOR,
 	.name		= "regulator",
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
new file mode 100644
index 0000000..642a2d8
--- /dev/null
+++ b/drivers/ram/Kconfig
@@ -0,0 +1,18 @@
+config RAM
+	bool "Enable RAM drivers using Driver Model"
+	depends on DM
+	help
+	  This allows drivers to be provided for SDRAM and other RAM
+	  controllers and their type to be specified in the board's device
+	  tree. Generally some parameters are required to set up the RAM and
+	  the RAM size can either be statically defined or dynamically
+	  detected.
+
+config SPL_RAM_SUPPORT
+	bool "Enable RAM support in SPL"
+	depends on RAM
+	help
+	  The RAM subsystem adds a small amount of overhead to the image.
+	  If this is acceptable and you have a need to use RAM drivers in
+	  SPL, enable this option. It might provide a cleaner interface to
+	  setting up RAM (e.g. SDRAM / DDR) within SPL.
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
new file mode 100644
index 0000000..0e10249
--- /dev/null
+++ b/drivers/ram/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+obj-$(CONFIG_RAM) += ram-uclass.o
+obj-$(CONFIG_SANDBOX) += sandbox_ram.o
diff --git a/drivers/ram/ram-uclass.c b/drivers/ram/ram-uclass.c
new file mode 100644
index 0000000..2f1fbe7
--- /dev/null
+++ b/drivers/ram/ram-uclass.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <ram.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+int ram_get_info(struct udevice *dev, struct ram_info *info)
+{
+	struct ram_ops *ops = ram_get_ops(dev);
+
+	if (!ops->get_info)
+		return -ENOSYS;
+
+	return ops->get_info(dev, info);
+}
+
+UCLASS_DRIVER(ram) = {
+	.id		= UCLASS_RAM,
+	.name		= "ram",
+};
diff --git a/drivers/ram/sandbox_ram.c b/drivers/ram/sandbox_ram.c
new file mode 100644
index 0000000..06bf3ec
--- /dev/null
+++ b/drivers/ram/sandbox_ram.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <ram.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_get_info(struct udevice *dev, struct ram_info *info)
+{
+	info->base = 0;
+	info->size = gd->ram_size;
+
+	return 0;
+}
+
+static const struct ram_ops sandbox_ram_ops = {
+	.get_info	= sandbox_get_info,
+};
+
+static const struct udevice_id sandbox_ram_ids[] = {
+	{ .compatible = "sandbox,ram" },
+	{ }
+};
+
+U_BOOT_DRIVER(warm_ram_sandbox) = {
+	.name		= "ram_sandbox",
+	.id		= UCLASS_RAM,
+	.of_match	= sandbox_ram_ids,
+	.ops		= &sandbox_ram_ops,
+};
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 9b044a3..c8a77e2 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -246,6 +246,17 @@
 
 #include <debug_uart.h>
 
+#define serial_dout(reg, value)	\
+	serial_out_shift((char *)com_port + \
+		((char *)reg - (char *)com_port) * \
+			(1 << CONFIG_DEBUG_UART_SHIFT), \
+		CONFIG_DEBUG_UART_SHIFT, value)
+#define serial_din(reg) \
+	serial_in_shift((char *)com_port + \
+		((char *)reg - (char *)com_port) * \
+			(1 << CONFIG_DEBUG_UART_SHIFT), \
+		CONFIG_DEBUG_UART_SHIFT)
+
 void debug_uart_init(void)
 {
 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
@@ -259,28 +270,23 @@
 	 */
 	baud_divisor = calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
 				    CONFIG_BAUDRATE);
-	serial_out_shift(&com_port->ier, CONFIG_DEBUG_UART_SHIFT,
-			 CONFIG_SYS_NS16550_IER);
-	serial_out_shift(&com_port->mcr, CONFIG_DEBUG_UART_SHIFT, UART_MCRVAL);
-	serial_out_shift(&com_port->fcr, CONFIG_DEBUG_UART_SHIFT, UART_FCRVAL);
+	serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
+	serial_dout(&com_port->mcr, UART_MCRVAL);
+	serial_dout(&com_port->fcr, UART_FCRVAL);
 
-	serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
-			 UART_LCR_BKSE | UART_LCRVAL);
-	serial_out_shift(&com_port->dll, CONFIG_DEBUG_UART_SHIFT,
-			 baud_divisor & 0xff);
-	serial_out_shift(&com_port->dlm, CONFIG_DEBUG_UART_SHIFT,
-			 (baud_divisor >> 8) & 0xff);
-	serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
-			 UART_LCRVAL);
+	serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
+	serial_dout(&com_port->dll, baud_divisor & 0xff);
+	serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
+	serial_dout(&com_port->lcr, UART_LCRVAL);
 }
 
 static inline void _debug_uart_putc(int ch)
 {
 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
 
-	while (!(serial_in_shift(&com_port->lsr, 0) & UART_LSR_THRE))
+	while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
 		;
-	serial_out_shift(&com_port->thr, CONFIG_DEBUG_UART_SHIFT, ch);
+	serial_dout(&com_port->thr, ch);
 }
 
 DEBUG_UART_FUNCS
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 737ae64..d666272 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -95,13 +95,13 @@
 	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
-int spi_post_bind(struct udevice *dev)
+static int spi_post_bind(struct udevice *dev)
 {
 	/* Scan the bus for devices */
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
-int spi_child_post_bind(struct udevice *dev)
+static int spi_child_post_bind(struct udevice *dev)
 {
 	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 
@@ -111,7 +111,7 @@
 	return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
 }
 
-int spi_post_probe(struct udevice *bus)
+static int spi_post_probe(struct udevice *bus)
 {
 	struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
 
@@ -121,7 +121,7 @@
 	return 0;
 }
 
-int spi_child_pre_probe(struct udevice *dev)
+static int spi_child_pre_probe(struct udevice *dev)
 {
 	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 	struct spi_slave *slave = dev_get_parentdata(dev);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 637ef3d..3fa5b2e 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -46,8 +46,8 @@
 
 	  Much of the code is shared but with this option enabled the USB
 	  uclass takes care of device enumeration. USB devices can be
-	  declared with the USB_DEVICE() macro and will be automatically
-	  probed when found on the bus.
+	  declared with the U_BOOT_USB_DEVICE() macro and will be
+	  automatically probed when found on the bus.
 
 source "drivers/usb/host/Kconfig"
 
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
index c8697ae..72ec41e 100644
--- a/drivers/usb/eth/asix.c
+++ b/drivers/usb/eth/asix.c
@@ -5,11 +5,11 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <usb.h>
+#include <malloc.h>
 #include <linux/mii.h>
 #include "usb_ether.h"
-#include <malloc.h>
-
 
 /* ASIX AX8817X based USB 2.0 Ethernet Devices */
 
@@ -92,14 +92,20 @@
 #define FLAG_TYPE_AX88772B	(1U << 2)
 #define FLAG_EEPROM_MAC		(1U << 3) /* initial mac address in eeprom */
 
-/* local vars */
-static int curr_eth_dev; /* index for name of next device detected */
 
 /* driver private */
 struct asix_private {
 	int flags;
+#ifdef CONFIG_DM_ETH
+	struct ueth_data ueth;
+#endif
 };
 
+#ifndef CONFIG_DM_ETH
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+#endif
+
 /*
  * Asix infrastructure commands
  */
@@ -284,13 +290,12 @@
 	return ret;
 }
 
-static int asix_write_hwaddr(struct eth_device *eth)
+static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr)
 {
-	struct ueth_data *dev = (struct ueth_data *)eth->priv;
 	int ret;
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
 
-	memcpy(buf, eth->enetaddr, ETH_ALEN);
+	memcpy(buf, enetaddr, ETH_ALEN);
 
 	ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf);
 	if (ret < 0)
@@ -325,12 +330,11 @@
 	return r;
 }
 
-static int asix_read_mac(struct eth_device *eth)
+static int asix_read_mac_common(struct ueth_data *dev,
+				struct asix_private *priv, uint8_t *enetaddr)
 {
-	struct ueth_data *dev = (struct ueth_data *)eth->priv;
-	struct asix_private *priv = (struct asix_private *)dev->dev_priv;
-	int i;
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
+	int i;
 
 	if (priv->flags & FLAG_EEPROM_MAC) {
 		for (i = 0; i < (ETH_ALEN >> 1); i++) {
@@ -339,7 +343,7 @@
 				debug("Failed to read SROM address 04h.\n");
 				return -1;
 			}
-			memcpy((eth->enetaddr + i * 2), buf, 2);
+			memcpy(enetaddr + i * 2, buf, 2);
 		}
 	} else {
 		if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
@@ -347,7 +351,7 @@
 			debug("Failed to read MAC address.\n");
 			return -1;
 		}
-		memcpy(eth->enetaddr, buf, ETH_ALEN);
+		memcpy(enetaddr, buf, ETH_ALEN);
 	}
 
 	return 0;
@@ -414,12 +418,8 @@
 	return 0;
 }
 
-/*
- * Asix callbacks
- */
-static int asix_init(struct eth_device *eth, bd_t *bd)
+static int asix_init_common(struct ueth_data *dev)
 {
-	struct ueth_data	*dev = (struct ueth_data *)eth->priv;
 	int timeout = 0;
 #define TIMEOUT_RESOLUTION 50	/* ms */
 	int link_detected;
@@ -452,9 +452,8 @@
 	return -1;
 }
 
-static int asix_send(struct eth_device *eth, void *packet, int length)
+static int asix_send_common(struct ueth_data *dev, void *packet, int length)
 {
-	struct ueth_data *dev = (struct ueth_data *)eth->priv;
 	int err;
 	u32 packet_len;
 	int actual_len;
@@ -481,6 +480,24 @@
 	return err;
 }
 
+#ifndef CONFIG_DM_ETH
+/*
+ * Asix callbacks
+ */
+static int asix_init(struct eth_device *eth, bd_t *bd)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_init_common(dev);
+}
+
+static int asix_send(struct eth_device *eth, void *packet, int length)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_send_common(dev, packet, length);
+}
+
 static int asix_recv(struct eth_device *eth)
 {
 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
@@ -552,6 +569,13 @@
 	debug("** %s()\n", __func__);
 }
 
+static int asix_write_hwaddr(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_write_hwaddr_common(dev, eth->enetaddr);
+}
+
 /*
  * Asix probing functions
  */
@@ -694,9 +718,180 @@
 		return 0;
 
 	/* Get the MAC address */
-	if (asix_read_mac(eth))
+	if (asix_read_mac_common(ss, priv, eth->enetaddr))
 		return 0;
 	debug("MAC %pM\n", eth->enetaddr);
 
 	return 1;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int asix_eth_start(struct udevice *dev)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_init_common(&priv->ueth);
+}
+
+void asix_eth_stop(struct udevice *dev)
+{
+	debug("** %s()\n", __func__);
+}
+
+int asix_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_send_common(&priv->ueth, packet, length);
+}
+
+int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	uint8_t *ptr;
+	int ret, len;
+	u32 packet_len;
+
+	len = usb_ether_get_rx_bytes(ueth, &ptr);
+	debug("%s: first try, len=%d\n", __func__, len);
+	if (!len) {
+		if (!(flags & ETH_RECV_CHECK_DEVICE))
+			return -EAGAIN;
+		ret = usb_ether_receive(ueth, AX_RX_URB_SIZE);
+		if (ret == -EAGAIN)
+			return ret;
+
+		len = usb_ether_get_rx_bytes(ueth, &ptr);
+		debug("%s: second try, len=%d\n", __func__, len);
+	}
+
+	/*
+	 * 1st 4 bytes contain the length of the actual data as two
+	 * complementary 16-bit words. Extract the length of the data.
+	 */
+	if (len < sizeof(packet_len)) {
+		debug("Rx: incomplete packet length\n");
+		goto err;
+	}
+	memcpy(&packet_len, ptr, sizeof(packet_len));
+	le32_to_cpus(&packet_len);
+	if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
+		debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
+		      packet_len, (~packet_len >> 16) & 0x7ff,
+		      packet_len & 0x7ff);
+		goto err;
+	}
+	packet_len = packet_len & 0x7ff;
+	if (packet_len > len - sizeof(packet_len)) {
+		debug("Rx: too large packet: %d\n", packet_len);
+		goto err;
+	}
+
+	*packetp = ptr + sizeof(packet_len);
+	return packet_len;
+
+err:
+	usb_ether_advance_rxbuf(ueth, -1);
+	return -EINVAL;
+}
+
+static int asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	if (packet_len & 1)
+		packet_len++;
+	usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+	return 0;
+}
+
+int asix_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+
+	if (priv->flags & FLAG_TYPE_AX88172)
+		return -ENOSYS;
+
+	return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr);
+}
+
+static int asix_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ss = &priv->ueth;
+	int ret;
+
+	priv->flags = dev->driver_data;
+	ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE);
+	if (ret)
+		return ret;
+
+	ret = asix_basic_reset(ss);
+	if (ret)
+		goto err;
+
+	/* Get the MAC address */
+	ret = asix_read_mac_common(ss, priv, pdata->enetaddr);
+	if (ret)
+		goto err;
+	debug("MAC %pM\n", pdata->enetaddr);
+
+	return 0;
+
+err:
+	return usb_ether_deregister(ss);
+}
+
+static const struct eth_ops asix_eth_ops = {
+	.start	= asix_eth_start,
+	.send	= asix_eth_send,
+	.recv	= asix_eth_recv,
+	.free_pkt = asix_free_pkt,
+	.stop	= asix_eth_stop,
+	.write_hwaddr = asix_write_hwaddr,
+};
+
+U_BOOT_DRIVER(asix_eth) = {
+	.name	= "asix_eth",
+	.id	= UCLASS_ETH,
+	.probe = asix_eth_probe,
+	.ops	= &asix_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct asix_private),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id asix_eth_id_table[] = {
+	/* Apple USB Ethernet Adapter */
+	{ USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 },
+	/* D-Link DUB-E100 H/W Ver B1 */
+	{ USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+	/* D-Link DUB-E100 H/W Ver C1 */
+	{ USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 },
+	/* Cables-to-Go USB Ethernet Adapter */
+	{ USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 },
+	/* Trendnet TU2-ET100 V3.0R */
+	{ USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+	/* SMC */
+	{ USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 },
+	/* MSI - ASIX 88772a */
+	{ USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 },
+	/* Linksys 200M v2.1 */
+	{ USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 },
+	/* 0Q0 cable ethernet */
+	{ USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+	/* DLink DUB-E100 H/W Ver B1 Alternate */
+	{ USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+	/* ASIX 88772B */
+	{ USB_DEVICE(0x0b95, 0x772b),
+		.driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
+	{ USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B },
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table);
+#endif
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c
index c72b7e4..63785a9 100644
--- a/drivers/usb/eth/usb_ether.c
+++ b/drivers/usb/eth/usb_ether.c
@@ -6,11 +6,137 @@
 
 #include <common.h>
 #include <dm.h>
+#include <malloc.h>
 #include <usb.h>
 #include <dm/device-internal.h>
 
 #include "usb_ether.h"
 
+#ifdef CONFIG_DM_ETH
+
+#define USB_BULK_RECV_TIMEOUT 500
+
+int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize)
+{
+	struct usb_device *udev = dev_get_parentdata(dev);
+	struct usb_interface_descriptor *iface_desc;
+	bool ep_in_found = false, ep_out_found = false;
+	struct usb_interface *iface;
+	const int ifnum = 0; /* Always use interface 0 */
+	int ret, i;
+
+	iface = &udev->config.if_desc[ifnum];
+	iface_desc = &udev->config.if_desc[ifnum].desc;
+
+	/* Initialize the ueth_data structure with some useful info */
+	ueth->ifnum = ifnum;
+	ueth->subclass = iface_desc->bInterfaceSubClass;
+	ueth->protocol = iface_desc->bInterfaceProtocol;
+
+	/*
+	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		int ep_addr = iface->ep_desc[i].bEndpointAddress;
+
+		/* is it an BULK endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+			if (ep_addr & USB_DIR_IN && !ep_in_found) {
+				ueth->ep_in = ep_addr &
+					USB_ENDPOINT_NUMBER_MASK;
+				ep_in_found = true;
+			} else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
+				ueth->ep_out = ep_addr &
+					USB_ENDPOINT_NUMBER_MASK;
+				ep_out_found = true;
+			}
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ueth->ep_int = iface->ep_desc[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+			ueth->irqinterval = iface->ep_desc[i].bInterval;
+		}
+	}
+	debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out,
+	      ueth->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) {
+		debug("%s: %s: Cannot find endpoints\n", __func__, dev->name);
+		return -ENXIO;
+	}
+
+	ueth->rxsize = rxsize;
+	ueth->rxbuf = memalign(rxsize, ARCH_DMA_MINALIGN);
+	if (!ueth->rxbuf)
+		return -ENOMEM;
+
+	ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum);
+	if (ret) {
+		debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name,
+		      ret);
+		return ret;
+	}
+	ueth->pusb_dev = udev;
+
+	return 0;
+}
+
+int usb_ether_deregister(struct ueth_data *ueth)
+{
+	return 0;
+}
+
+int usb_ether_receive(struct ueth_data *ueth, int rxsize)
+{
+	int actual_len;
+	int ret;
+
+	if (rxsize > ueth->rxsize)
+		return -EINVAL;
+	ret = usb_bulk_msg(ueth->pusb_dev,
+			   usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in),
+			   ueth->rxbuf, rxsize, &actual_len,
+			   USB_BULK_RECV_TIMEOUT);
+	debug("Rx: len = %u, actual = %u, err = %d\n", rxsize, actual_len, ret);
+	if (ret) {
+		printf("Rx: failed to receive: %d\n", ret);
+		return ret;
+	}
+	if (actual_len > rxsize) {
+		debug("Rx: received too many bytes %d\n", actual_len);
+		return -ENOSPC;
+	}
+	ueth->rxlen = actual_len;
+	ueth->rxptr = 0;
+
+	return actual_len ? 0 : -EAGAIN;
+}
+
+void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes)
+{
+	ueth->rxptr += num_bytes;
+	if (num_bytes < 0 || ueth->rxptr >= ueth->rxlen)
+		ueth->rxlen = 0;
+}
+
+int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp)
+{
+	if (!ueth->rxlen)
+		return 0;
+
+	*ptrp = &ueth->rxbuf[ueth->rxptr];
+
+	return ueth->rxlen - ueth->rxptr;
+}
+
+#else
+
 typedef void (*usb_eth_before_probe)(void);
 typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum,
 			struct ueth_data *ss);
@@ -140,8 +266,8 @@
 	usb_max_eth_dev = 0;
 #ifdef CONFIG_DM_USB
 	/*
-	 * TODO: We should add USB_DEVICE() declarations to each USB ethernet
-	 * driver and then most of this file can be removed.
+	 * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
+	 * Ethernet driver and then most of this file can be removed.
 	 */
 	struct udevice *bus;
 	struct uclass *uc;
@@ -197,3 +323,4 @@
 		return 0;
 	return -1;
 }
+#endif
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index bf02221..3a0d32e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -5,20 +5,7 @@
  *
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0
  */
 #include <common.h>
 #include <dm.h>
@@ -321,7 +308,7 @@
 		struct udevice *dev = parent;
 
 		if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
-			printf("ehci: Error cannot find high speed parent of usb-1 device\n");
+			printf("ehci: Error cannot find high-speed parent of usb-1 device\n");
 			return;
 		}
 
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index b9eabc5..0cb9fcc 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -2,29 +2,49 @@
  * Copyright (c) 2007-2008, Juniper Networks, Inc.
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <pci.h>
 #include <usb.h>
 
 #include "ehci.h"
 
+/* Information about a USB port */
+struct ehci_pci_priv {
+	struct ehci_ctrl ehci;
+};
+
+static void ehci_pci_common_init(pci_dev_t pdev, struct ehci_hccr **ret_hccr,
+				 struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	uint32_t cmd;
+
+	hccr = (struct ehci_hccr *)pci_map_bar(pdev,
+			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+	hcor = (struct ehci_hcor *)((uint32_t) hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
+	      (uint32_t)hccr, (uint32_t)hcor,
+	      (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	/* enable busmaster */
+	pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER;
+	pci_write_config_dword(pdev, PCI_COMMAND, cmd);
+}
+
+#ifndef CONFIG_DM_USB
+
 #ifdef CONFIG_PCI_EHCI_DEVICE
 static struct pci_device_id ehci_pci_ids[] = {
 	/* Please add supported PCI EHCI controller ids here */
@@ -33,7 +53,6 @@
 	{0x12D8, 0x400F},	/* Pericom */
 	{0, 0}
 };
-#else
 #endif
 
 /*
@@ -44,9 +63,6 @@
 		struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
 {
 	pci_dev_t pdev;
-	uint32_t cmd;
-	struct ehci_hccr *hccr;
-	struct ehci_hcor *hcor;
 
 #ifdef CONFIG_PCI_EHCI_DEVICE
 	pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
@@ -57,23 +73,8 @@
 		printf("EHCI host controller not found\n");
 		return -1;
 	}
+	ehci_pci_common_init(pdev, ret_hccr, ret_hcor);
 
-	hccr = (struct ehci_hccr *)pci_map_bar(pdev,
-			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
-	hcor = (struct ehci_hcor *)((uint32_t) hccr +
-			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
-	debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
-			(uint32_t)hccr, (uint32_t)hcor,
-			(uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
-	*ret_hccr = hccr;
-	*ret_hcor = hcor;
-
-	/* enable busmaster */
-	pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
-	cmd |= PCI_COMMAND_MASTER;
-	pci_write_config_dword(pdev, PCI_COMMAND, cmd);
 	return 0;
 }
 
@@ -85,3 +86,46 @@
 {
 	return 0;
 }
+#endif /* nCONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+static int ehci_pci_probe(struct udevice *dev)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+
+	ehci_pci_common_init(pci_get_bdf(dev), &hccr, &hcor);
+
+	return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_pci_remove(struct udevice *dev)
+{
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ehci_pci) = {
+	.name	= "ehci_pci",
+	.id	= UCLASS_USB,
+	.probe = ehci_pci_probe,
+	.remove = ehci_pci_remove,
+	.ops	= &ehci_usb_ops,
+	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
+	.priv_auto_alloc_size = sizeof(struct ehci_pci_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static struct pci_device_id ehci_pci_supported[] = {
+	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0) },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(ehci_pci, ehci_pci_supported);
+
+#endif /* CONFIG_DM_USB */
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 774282d..3379c29 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -3,20 +3,7 @@
  * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #ifndef USB_EHCI_H
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 6f33456..373e04c 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -3,19 +3,7 @@
  *
  * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #include <common.h>
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index ca1b671..67dc3c4 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -3,19 +3,7 @@
  *
  * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #ifndef __R8A66597_H__
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 6e86f4a..c5d1e7f 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -128,6 +128,17 @@
 	return ops->alloc_device(bus, udev);
 }
 
+int usb_reset_root_port(struct usb_device *udev)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->reset_root_port)
+		return -ENOSYS;
+
+	return ops->reset_root_port(bus, udev);
+}
+
 int usb_stop(void)
 {
 	struct udevice *bus;
@@ -146,6 +157,9 @@
 		ret = device_remove(bus);
 		if (ret && !err)
 			err = ret;
+		ret = device_unbind_children(bus);
+		if (ret && !err)
+			err = ret;
 	}
 
 #ifdef CONFIG_SANDBOX
@@ -265,11 +279,6 @@
 	return usb_started ? 0 : -1;
 }
 
-int usb_reset_root_port(void)
-{
-	return -ENOSYS;
-}
-
 static struct usb_device *find_child_devnum(struct udevice *parent, int devnum)
 {
 	struct usb_device *udev;
@@ -294,14 +303,14 @@
 
 struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
 {
-	struct udevice *hub;
+	struct udevice *dev;
 	int devnum = index + 1; /* Addresses are allocated from 1 on USB */
 
-	device_find_first_child(bus, &hub);
-	if (device_get_uclass_id(hub) == UCLASS_USB_HUB)
-		return find_child_devnum(hub, devnum);
+	device_find_first_child(bus, &dev);
+	if (!dev)
+		return NULL;
 
-	return NULL;
+	return find_child_devnum(dev, devnum);
 }
 
 int usb_post_bind(struct udevice *dev)
@@ -310,35 +319,6 @@
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
-int usb_port_reset(struct usb_device *parent, int portnr)
-{
-	unsigned short portstatus;
-	int ret;
-
-	debug("%s: start\n", __func__);
-
-	if (parent) {
-		/* reset the port for the second time */
-		assert(portnr > 0);
-		debug("%s: reset %d\n", __func__, portnr - 1);
-		ret = legacy_hub_port_reset(parent, portnr - 1, &portstatus);
-		if (ret < 0) {
-			printf("\n     Couldn't reset port %i\n", portnr);
-			return ret;
-		}
-	} else {
-		debug("%s: reset root\n", __func__);
-		usb_reset_root_port();
-	}
-
-	return 0;
-}
-
-int usb_legacy_port_reset(struct usb_device *parent, int portnr)
-{
-	return usb_port_reset(parent, portnr);
-}
-
 int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
 {
 	struct usb_platdata *plat;
@@ -511,15 +491,14 @@
 }
 
 /**
- * usb_find_child() - Find an existing device which matches our needs
- *
- *
+ * usb_find_emul_child() - Find an existing device for emulated devices
  */
-static int usb_find_child(struct udevice *parent,
-			  struct usb_device_descriptor *desc,
-			  struct usb_interface_descriptor *iface,
-			  struct udevice **devp)
+static int usb_find_emul_child(struct udevice *parent,
+			       struct usb_device_descriptor *desc,
+			       struct usb_interface_descriptor *iface,
+			       struct udevice **devp)
 {
+#ifdef CONFIG_SANDBOX
 	struct udevice *dev;
 
 	*devp = NULL;
@@ -538,7 +517,7 @@
 			return 0;
 		}
 	}
-
+#endif
 	return -ENOENT;
 }
 
@@ -594,12 +573,12 @@
 	debug("Calling usb_setup_device(), portnr=%d\n", udev->portnr);
 	parent_udev = device_get_uclass_id(parent) == UCLASS_USB_HUB ?
 		dev_get_parentdata(parent) : NULL;
-	ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev, port);
+	ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev);
 	debug("read_descriptor for '%s': ret=%d\n", parent->name, ret);
 	if (ret)
 		return ret;
-	ret = usb_find_child(parent, &udev->descriptor, iface, &dev);
-	debug("** usb_find_child returns %d\n", ret);
+	ret = usb_find_emul_child(parent, &udev->descriptor, iface, &dev);
+	debug("** usb_find_emul_child returns %d\n", ret);
 	if (ret) {
 		if (ret != -ENOENT)
 			return ret;
diff --git a/drivers/usb/musb-new/am35x.c b/drivers/usb/musb-new/am35x.c
index 857d7eb..d158454 100644
--- a/drivers/usb/musb-new/am35x.c
+++ b/drivers/usb/musb-new/am35x.c
@@ -100,7 +100,11 @@
 /*
  * am35x_musb_enable - enable interrupts
  */
+#ifndef __UBOOT__
 static void am35x_musb_enable(struct musb *musb)
+#else
+static int am35x_musb_enable(struct musb *musb)
+#endif
 {
 	void __iomem *reg_base = musb->ctrl_base;
 	u32 epmask;
@@ -116,6 +120,9 @@
 	if (is_otg_enabled(musb))
 		musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
 			    AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
+#ifdef __UBOOT__
+	return 0;
+#endif
 }
 
 /*
diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
index 242cc30..f530af4 100644
--- a/drivers/usb/musb-new/musb_core.c
+++ b/drivers/usb/musb-new/musb_core.c
@@ -926,10 +926,17 @@
 /*
 * Program the HDRC to start (enable interrupts, dma, etc.).
 */
+#ifndef __UBOOT__
 void musb_start(struct musb *musb)
+#else
+int musb_start(struct musb *musb)
+#endif
 {
 	void __iomem	*regs = musb->mregs;
 	u8		devctl = musb_readb(regs, MUSB_DEVCTL);
+#ifdef __UBOOT__
+	int ret;
+#endif
 
 	dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
 
@@ -972,8 +979,21 @@
 		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
 			musb->is_active = 1;
 	}
+
+#ifndef __UBOOT__
 	musb_platform_enable(musb);
+#else
+	ret = musb_platform_enable(musb);
+	if (ret) {
+		musb->is_active = 0;
+		return ret;
+	}
+#endif
 	musb_writeb(regs, MUSB_DEVCTL, devctl);
+
+#ifdef __UBOOT__
+	return 0;
+#endif
 }
 
 
diff --git a/drivers/usb/musb-new/musb_core.h b/drivers/usb/musb-new/musb_core.h
index 2695742..8727f64 100644
--- a/drivers/usb/musb-new/musb_core.h
+++ b/drivers/usb/musb-new/musb_core.h
@@ -231,7 +231,11 @@
 	int	(*init)(struct musb *musb);
 	int	(*exit)(struct musb *musb);
 
+#ifndef __UBOOT__
 	void	(*enable)(struct musb *musb);
+#else
+	int	(*enable)(struct musb *musb);
+#endif
 	void	(*disable)(struct musb *musb);
 
 	int	(*set_mode)(struct musb *musb, u8 mode);
@@ -546,7 +550,11 @@
 
 extern const char musb_driver_name[];
 
+#ifndef __UBOOT__
 extern void musb_start(struct musb *musb);
+#else
+extern int musb_start(struct musb *musb);
+#endif
 extern void musb_stop(struct musb *musb);
 
 extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
@@ -564,11 +572,21 @@
 		musb->ops->set_vbus(musb, is_on);
 }
 
+#ifndef __UBOOT__
 static inline void musb_platform_enable(struct musb *musb)
 {
 	if (musb->ops->enable)
 		musb->ops->enable(musb);
 }
+#else
+static inline int musb_platform_enable(struct musb *musb)
+{
+	if (!musb->ops->enable)
+		return 0;
+
+	return musb->ops->enable(musb);
+}
+#endif
 
 static inline void musb_platform_disable(struct musb *musb)
 {
diff --git a/drivers/usb/musb-new/musb_dsps.c b/drivers/usb/musb-new/musb_dsps.c
index 17ed224..8959397 100644
--- a/drivers/usb/musb-new/musb_dsps.c
+++ b/drivers/usb/musb-new/musb_dsps.c
@@ -156,7 +156,11 @@
 /**
  * dsps_musb_enable - enable interrupts
  */
+#ifndef __UBOOT__
 static void dsps_musb_enable(struct musb *musb)
+#else
+static int dsps_musb_enable(struct musb *musb)
+#endif
 {
 #ifndef __UBOOT__
 	struct device *dev = musb->controller;
@@ -181,6 +185,8 @@
 	if (is_otg_enabled(musb))
 		dsps_writel(reg_base, wrp->coreintr_set,
 			    (1 << wrp->drvvbus) << wrp->usb_shift);
+#else
+	return 0;
 #endif
 }
 
diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c
index 5a71501..415a9f2 100644
--- a/drivers/usb/musb-new/musb_gadget_ep0.c
+++ b/drivers/usb/musb-new/musb_gadget_ep0.c
@@ -43,6 +43,7 @@
 #else
 #include <common.h>
 #include "linux-compat.h"
+#include <asm/processor.h>
 #endif
 
 #include "musb_core.h"
diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c
index 437309c..40b9c66 100644
--- a/drivers/usb/musb-new/musb_host.c
+++ b/drivers/usb/musb-new/musb_host.c
@@ -2067,7 +2067,11 @@
 
 	/* precompute addressing for external hub/tt ports */
 	if (musb->is_multipoint) {
+#ifndef __UBOOT__
 		struct usb_device	*parent = urb->dev->parent;
+#else
+		struct usb_device	*parent = usb_dev_get_parent(urb->dev);
+#endif
 
 #ifndef __UBOOT__
 		if (parent != hcd->self.root_hub) {
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index d1ee5f8..9b56e90 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -13,6 +13,7 @@
 #include "musb_core.h"
 #include "musb_host.h"
 #include "musb_gadget.h"
+#include "musb_uboot.h"
 
 #ifdef CONFIG_MUSB_HOST
 struct int_queue {
@@ -20,9 +21,9 @@
 	struct urb urb;
 };
 
-static struct musb *host;
-static struct usb_hcd hcd;
-static enum usb_device_speed host_speed;
+#ifndef CONFIG_DM_USB
+struct musb_host_data musb_host;
+#endif
 
 static void musb_host_complete_urb(struct urb *urb)
 {
@@ -30,9 +31,6 @@
 	urb->dev->act_len = urb->actual_length;
 }
 
-static struct usb_host_endpoint hep;
-static struct urb urb;
-
 static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
 			  struct usb_device *dev, int endpoint_type,
 			  unsigned long pipe, void *buffer, int len,
@@ -90,38 +88,40 @@
 	return urb->status;
 }
 
-int submit_control_msg(struct usb_device *dev, unsigned long pipe,
-			void *buffer, int len, struct devrequest *setup)
+static int _musb_submit_control_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe,
+	void *buffer, int len, struct devrequest *setup)
 {
-	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe,
-		      buffer, len, setup, 0);
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_CONTROL,
+		      pipe, buffer, len, setup, 0);
 
 	/* Fix speed for non hub-attached devices */
-	if (!dev->parent)
-		dev->speed = host_speed;
+	if (!usb_dev_get_parent(dev))
+		dev->speed = host->host_speed;
 
-	return submit_urb(&hcd, &urb);
+	return submit_urb(&host->hcd, &host->urb);
 }
 
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
-					void *buffer, int len)
+static int _musb_submit_bulk_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe, void *buffer, int len)
 {
-	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_BULK, pipe,
-		      buffer, len, NULL, 0);
-	return submit_urb(&hcd, &urb);
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_BULK,
+		      pipe, buffer, len, NULL, 0);
+	return submit_urb(&host->hcd, &host->urb);
 }
 
-int submit_int_msg(struct usb_device *dev, unsigned long pipe,
-				void *buffer, int len, int interval)
+static int _musb_submit_int_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe,
+	void *buffer, int len, int interval)
 {
-	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_INT, pipe,
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_INT, pipe,
 		      buffer, len, NULL, interval);
-	return submit_urb(&hcd, &urb);
+	return submit_urb(&host->hcd, &host->urb);
 }
 
-struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
-	int queuesize, int elementsize, void *buffer, int interval)
+static struct int_queue *_musb_create_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe, int queuesize,
+	int elementsize, void *buffer, int interval)
 {
 	struct int_queue *queue;
 	int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
@@ -143,7 +143,7 @@
 	construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
 		      pipe, buffer, elementsize, NULL, interval);
 
-	ret = musb_urb_enqueue(&hcd, &queue->urb, 0);
+	ret = musb_urb_enqueue(&host->hcd, &queue->urb, 0);
 	if (ret < 0) {
 		printf("Failed to enqueue URB to controller\n");
 		free(queue);
@@ -154,25 +154,27 @@
 	return queue;
 }
 
-int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+static int _musb_destroy_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, struct int_queue *queue)
 {
 	int index = usb_pipein(queue->urb.pipe) * 16 + 
 		    usb_pipeendpoint(queue->urb.pipe);
 
 	if (queue->urb.status == -EINPROGRESS)
-		musb_urb_dequeue(&hcd, &queue->urb, -ETIME);
+		musb_urb_dequeue(&host->hcd, &queue->urb, -ETIME);
 
 	dev->int_pending &= ~(1 << index);
 	free(queue);
 	return 0;
 }
 
-void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+static void *_musb_poll_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, struct int_queue *queue)
 {
 	if (queue->urb.status != -EINPROGRESS)
 		return NULL; /* URB has already completed in a prev. poll */
 
-	host->isr(0, host);
+	host->host->isr(0, host->host);
 
 	if (queue->urb.status != -EINPROGRESS)
 		return queue->urb.transfer_buffer; /* Done */
@@ -180,9 +182,10 @@
 	return NULL; /* URB still pending */
 }
 
-int usb_reset_root_port(void)
+static int _musb_reset_root_port(struct musb_host_data *host,
+	struct usb_device *dev)
 {
-	void *mbase = host->mregs;
+	void *mbase = host->host->mregs;
 	u8 power;
 
 	power = musb_readb(mbase, MUSB_POWER);
@@ -202,29 +205,33 @@
 #ifdef CONFIG_ARCH_SUNXI
 	sunxi_usb_phy_enable_squelch_detect(0, 1);
 #endif
-	host->isr(0, host);
-	host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
+	host->host->isr(0, host->host);
+	host->host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
 			USB_SPEED_HIGH :
 			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
 			USB_SPEED_FULL : USB_SPEED_LOW;
-	mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+	mdelay((host->host_speed == USB_SPEED_LOW) ? 200 : 50);
 
 	return 0;
 }
 
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+int musb_lowlevel_init(struct musb_host_data *host)
 {
 	void *mbase;
 	/* USB spec says it may take up to 1 second for a device to connect */
 	unsigned long timeout = get_timer(0) + 1000;
+	int ret;
 
-	if (!host) {
+	if (!host->host) {
 		printf("MUSB host is not registered\n");
 		return -ENODEV;
 	}
 
-	musb_start(host);
-	mbase = host->mregs;
+	ret = musb_start(host->host);
+	if (ret)
+		return ret;
+
+	mbase = host->host->mregs;
 	do {
 		if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
 			break;
@@ -232,23 +239,135 @@
 	if (get_timer(0) >= timeout)
 		return -ENODEV;
 
-	usb_reset_root_port();
-	host->is_active = 1;
-	hcd.hcd_priv = host;
+	_musb_reset_root_port(host, NULL);
+	host->host->is_active = 1;
+	host->hcd.hcd_priv = host->host;
 
 	return 0;
 }
 
+#ifndef CONFIG_DM_USB
 int usb_lowlevel_stop(int index)
 {
-	if (!host) {
+	if (!musb_host.host) {
 		printf("MUSB host is not registered\n");
 		return -ENODEV;
 	}
 
-	musb_stop(host);
+	musb_stop(musb_host.host);
 	return 0;
 }
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+			    void *buffer, int length)
+{
+	return _musb_submit_bulk_msg(&musb_host, dev, pipe, buffer, length);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+		       void *buffer, int length, struct devrequest *setup)
+{
+	return _musb_submit_control_msg(&musb_host, dev, pipe, buffer, length, setup);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+		   void *buffer, int length, int interval)
+{
+	return _musb_submit_int_msg(&musb_host, dev, pipe, buffer, length, interval);
+}
+
+struct int_queue *create_int_queue(struct usb_device *dev,
+		unsigned long pipe, int queuesize, int elementsize,
+		void *buffer, int interval)
+{
+	return _musb_create_int_queue(&musb_host, dev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _musb_poll_int_queue(&musb_host, dev, queue);
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _musb_destroy_int_queue(&musb_host, dev, queue);
+}
+
+int usb_reset_root_port(struct usb_device *dev)
+{
+	return _musb_reset_root_port(&musb_host, dev);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	return musb_lowlevel_init(&musb_host);
+}
+#endif /* !CONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+static int musb_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_control_msg(host, udev, pipe, buffer, length, setup);
+}
+
+static int musb_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_bulk_msg(host, udev, pipe, buffer, length);
+}
+
+static int musb_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_int_msg(host, udev, pipe, buffer, length, interval);
+}
+
+static struct int_queue *musb_create_int_queue(struct udevice *dev,
+		struct usb_device *udev, unsigned long pipe, int queuesize,
+		int elementsize, void *buffer, int interval)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_create_int_queue(host, udev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+static void *musb_poll_int_queue(struct udevice *dev, struct usb_device *udev,
+				 struct int_queue *queue)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_poll_int_queue(host, udev, queue);
+}
+
+static int musb_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
+				  struct int_queue *queue)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_destroy_int_queue(host, udev, queue);
+}
+
+static int musb_reset_root_port(struct udevice *dev, struct usb_device *udev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_reset_root_port(host, udev);
+}
+
+struct dm_usb_ops musb_usb_ops = {
+	.control = musb_submit_control_msg,
+	.bulk = musb_submit_bulk_msg,
+	.interrupt = musb_submit_int_msg,
+	.create_int_queue = musb_create_int_queue,
+	.poll_int_queue = musb_poll_int_queue,
+	.destroy_int_queue = musb_destroy_int_queue,
+	.reset_root_port = musb_reset_root_port,
+};
+#endif /* CONFIG_DM_USB */
 #endif /* CONFIG_MUSB_HOST */
 
 #ifdef CONFIG_MUSB_GADGET
@@ -309,9 +428,9 @@
 	struct musb **musbp;
 
 	switch (plat->mode) {
-#ifdef CONFIG_MUSB_HOST
+#if defined(CONFIG_MUSB_HOST) && !defined(CONFIG_DM_USB)
 	case MUSB_HOST:
-		musbp = &host;
+		musbp = &musb_host.host;
 		break;
 #endif
 #ifdef CONFIG_MUSB_GADGET
diff --git a/drivers/usb/musb-new/musb_uboot.h b/drivers/usb/musb-new/musb_uboot.h
new file mode 100644
index 0000000..6312cd2
--- /dev/null
+++ b/drivers/usb/musb-new/musb_uboot.h
@@ -0,0 +1,28 @@
+/*
+ * MUSB OTG driver u-boot specific functions
+ *
+ * Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef __MUSB_UBOOT_H__
+#define __MUSB_UBOOT_H__
+
+#include <usb.h>
+#include "linux-compat.h"
+#include "usb-compat.h"
+#include "musb_core.h"
+
+struct musb_host_data {
+	struct musb *host;
+	struct usb_hcd hcd;
+	enum usb_device_speed host_speed;
+	struct usb_host_endpoint hep;
+	struct urb urb;
+};
+
+extern struct dm_usb_ops musb_usb_ops;
+
+int musb_lowlevel_init(struct musb_host_data *host);
+
+#endif
diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c
index 31a280e..77273a4 100644
--- a/drivers/usb/musb-new/omap2430.c
+++ b/drivers/usb/musb-new/omap2430.c
@@ -400,7 +400,11 @@
 	return status;
 }
 
+#ifndef __UBOOT__
 static void omap2430_musb_enable(struct musb *musb)
+#else
+static int omap2430_musb_enable(struct musb *musb)
+#endif
 {
 #ifndef __UBOOT__
 	u8		devctl;
@@ -445,6 +449,7 @@
 				__PRETTY_FUNCTION__);
 	}
 #endif
+	return 0;
 #endif
 }
 
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 052e065..c123d61 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -199,12 +199,12 @@
 /* musb_core does not call enable / disable in a balanced manner <sigh> */
 static bool enabled = false;
 
-static void sunxi_musb_enable(struct musb *musb)
+static int sunxi_musb_enable(struct musb *musb)
 {
 	pr_debug("%s():\n", __func__);
 
 	if (enabled)
-		return;
+		return 0;
 
 	/* select PIO mode */
 	musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
@@ -215,6 +215,7 @@
 	USBC_ForceVbusValidToHigh(musb->mregs);
 
 	enabled = true;
+	return 0;
 }
 
 static void sunxi_musb_disable(struct musb *musb)
diff --git a/drivers/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h
index 50bad37..53fe4ff 100644
--- a/drivers/usb/musb-new/usb-compat.h
+++ b/drivers/usb/musb-new/usb-compat.h
@@ -1,6 +1,7 @@
 #ifndef __USB_COMPAT_H__
 #define __USB_COMPAT_H__
 
+#include <dm.h>
 #include "usb.h"
 
 struct usb_hcd {
@@ -66,6 +67,68 @@
 	return 0;
 }
 
+#ifdef CONFIG_DM_USB
+static inline u16 find_tt(struct usb_device *udev)
+{
+	struct udevice *parent;
+	struct usb_device *uparent, *ttdev;
+
+	/*
+	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
+	 * to the parent udevice, not the actual udevice belonging to the
+	 * udev as the device is not instantiated yet. So when searching
+	 * for the first usb-2 parent start with udev->dev not
+	 * udev->dev->parent .
+	 */
+	ttdev = udev;
+	parent = udev->dev;
+	uparent = dev_get_parentdata(parent);
+
+	while (uparent->speed != USB_SPEED_HIGH) {
+		struct udevice *dev = parent;
+
+		if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
+			printf("musb: Error cannot find high speed parent of usb-1 device\n");
+			return 0;
+		}
+
+		ttdev = dev_get_parentdata(dev);
+		parent = dev->parent;
+		uparent = dev_get_parentdata(parent);
+	}
+
+	return (uparent->devnum << 8) | (ttdev->portnr - 1);
+}
+
+static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
+{
+	struct udevice *parent = udev->dev->parent;
+
+	/*
+	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
+	 * to the parent udevice, not the actual udevice belonging to the
+	 * udev as the device is not instantiated yet.
+	 *
+	 * If dev is an usb-bus, then we are called from usb_scan_device() for
+	 * an usb-device plugged directly into the root port, return NULL.
+	 */
+	if (device_get_uclass_id(udev->dev) == UCLASS_USB)
+		return NULL;
+
+	/*
+	 * If these 2 are not the same we are being called from
+	 * usb_scan_device() and udev itself is the parent.
+	 */
+	if (dev_get_parentdata(udev->dev) != udev)
+		return udev;
+
+	/* We are being called normally, use the parent pointer */
+	if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
+		return dev_get_parentdata(parent);
+
+	return NULL;
+}
+#else
 static inline u16 find_tt(struct usb_device *dev)
 {
 	u8 chid;
@@ -86,4 +149,11 @@
 
 	return (hub << 8) | chid;
 }
+
+static inline struct usb_device *usb_dev_get_parent(struct usb_device *dev)
+{
+	return dev->parent;
+}
+#endif
+
 #endif /* __USB_COMPAT_H__ */
diff --git a/dts/Kconfig b/dts/Kconfig
index 957f5c7..09cfefb 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -56,4 +56,16 @@
 	  It can be overridden from the command line:
 	  $ make DEVICE_TREE=<device-tree-name>
 
+config OF_SPL_REMOVE_PROPS
+	string "List of device tree properties to drop for SPL"
+	depends on OF_CONTROL && SPL
+	default "pinctrl-0 pinctrl-names clocks clock-names interrupt-parent"
+	help
+	  Since SPL normally runs in a reduced memory space, the device tree
+	  is cut down to only what is needed to load and start U-Boot. Only
+	  nodes marked with the property "u-boot,dm-pre-reloc" will be
+	  included. In addition, some properties are not used by U-Boot and
+	  can be discarded. This option defines the list of properties to
+	  discard.
+
 endmenu
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index db0550b..7ef3e25 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -116,5 +116,6 @@
 #define GD_FLG_ENV_READY	0x00080	/* Env. imported into hash table   */
 #define GD_FLG_SERIAL_READY	0x00100	/* Pre-reloc serial console ready  */
 #define GD_FLG_FULL_MALLOC_INIT	0x00200	/* Full malloc() is ready	   */
+#define GD_FLG_SPL_INIT		0x00400	/* spl_init() has been called	   */
 
 #endif /* __ASM_GENERIC_GBL_DATA_H */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index de91e57..0af599f 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -322,6 +322,19 @@
 const char *gpio_get_bank_info(struct udevice *dev, int *offset_count);
 
 /**
+ * dm_gpio_lookup_name() - Look up a named GPIO and return its description
+ *
+ * The name of a GPIO is typically its bank name followed by a number from 0.
+ * For example A0 is the first GPIO in bank A. Each bank is a separate driver
+ * model device.
+ *
+ * @name:	Name to look up
+ * @desc:	Returns description, on success
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc);
+
+/**
  * gpio_lookup_name - Look up a GPIO name and return its details
  *
  * This is used to convert a named GPIO into a device, offset and GPIO
@@ -421,6 +434,18 @@
 			      int flags);
 
 /**
+ * dm_gpio_request() - manually request a GPIO
+ *
+ * Note: This function should only be used for testing / debugging. Instead.
+ * use gpio_request_by_name() to pull GPIOs from the device tree.
+ *
+ * @desc:	GPIO description of GPIO to request (see dm_gpio_lookup_name())
+ * @label:	Label to attach to the GPIO while claimed
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_request(struct gpio_desc *desc, const char *label);
+
+/**
  * gpio_get_list_count() - Returns the number of GPIOs in a list
  *
  * Counts the GPIOs in a list. See gpio_request_by_name() for additional
diff --git a/include/clk.h b/include/clk.h
index df4570c..254ad2b 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -1,6 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
 #ifndef _CLK_H_
 #define _CLK_H_
 
 int soc_clk_dump(void);
 
+struct clk_ops {
+	/**
+	 * get_rate() - Get current clock rate
+	 *
+	 * @dev:	Device to check (UCLASS_CLK)
+	 * @return clock rate in Hz, or -ve error code
+	 */
+	ulong (*get_rate)(struct udevice *dev);
+
+	/**
+	 * set_rate() - Set current clock rate
+	 *
+	 * @dev:	Device to adjust
+	 * @rate:	New clock rate in Hz
+	 * @return new rate, or -ve error code
+	 */
+	ulong (*set_rate)(struct udevice *dev, ulong rate);
+
+	/**
+	* clk_set_periph_rate() - Set clock rate for a peripheral
+	*
+	* @dev:	Device to adjust (UCLASS_CLK)
+	* @rate:	New clock rate in Hz
+	* @return new clock rate in Hz, or -ve error code
+	*/
+	ulong (*get_periph_rate)(struct udevice *dev, int periph);
+
+	/**
+	 * clk_set_periph_rate() - Set current clock rate for a peripheral
+	 *
+	 * @dev:	Device to update (UCLASS_CLK)
+	 * @periph:	Peripheral ID to cupdate
+	 * @return new clock rate in Hz, or -ve error code
+	 */
+	ulong (*set_periph_rate)(struct udevice *dev, int periph, ulong rate);
+};
+
+#define clk_get_ops(dev)	((struct clk_ops *)(dev)->driver->ops)
+
+/**
+ * clk_get_rate() - Get current clock rate
+ *
+ * @dev:	Device to check (UCLASS_CLK)
+ * @return clock rate in Hz, or -ve error code
+ */
+ulong clk_get_rate(struct udevice *dev);
+
+/**
+ * set_rate() - Set current clock rate
+ *
+ * @dev:	Device to adjust
+ * @rate:	New clock rate in Hz
+ * @return new rate, or -ve error code
+ */
+ulong clk_set_rate(struct udevice *dev, ulong rate);
+
+/**
+ * clk_get_periph_rate() - Get current clock rate for a peripheral
+ *
+ * @dev:	Device to check (UCLASS_CLK)
+ * @return clock rate in Hz, -ve error code
+ */
+ulong clk_get_periph_rate(struct udevice *dev, int periph);
+
+/**
+ * clk_set_periph_rate() - Set current clock rate for a peripheral
+ *
+ * @dev:	Device to update (UCLASS_CLK)
+ * @periph:	Peripheral ID to cupdate
+ * @return new clock rate in Hz, or -ve error code
+ */
+ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate);
+
 #endif /* _CLK_H_ */
diff --git a/include/common.h b/include/common.h
index 8f4b2ec..4566bd1 100644
--- a/include/common.h
+++ b/include/common.h
@@ -1010,6 +1010,17 @@
 #define DEFINE_CACHE_ALIGN_BUFFER(type, name, size)			\
 	DEFINE_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
 
+/*
+ * check_member() - Check the offset of a structure member
+ *
+ * @structure:	Name of structure (e.g. global_data)
+ * @member:	Name of member (e.g. baudrate)
+ * @offset:	Expected offset in bytes
+ */
+#define check_member(structure, member, offset) _Static_assert( \
+	offsetof(struct structure, member) == offset, \
+	"`struct " #structure "` offset for `" #member "` is not " #offset)
+
 /* Pull in stuff for the build system */
 #ifdef DO_DEPS_ONLY
 # include <environment.h>
diff --git a/include/configs/db-88f6820-gp.h b/include/configs/db-88f6820-gp.h
index a429107..739c2bf 100644
--- a/include/configs/db-88f6820-gp.h
+++ b/include/configs/db-88f6820-gp.h
@@ -11,6 +11,7 @@
  * High Level Configuration Options (easy to change)
  */
 #define CONFIG_ARMADA_XP		/* SOC Family Name */
+#define CONFIG_ARMADA_38X
 #define CONFIG_DB_88F6820_GP		/* Board target name for DDR training */
 
 #define CONFIG_SYS_L2_PL310
@@ -108,6 +109,68 @@
 	"fdt_high=0x10000000\0"		\
 	"initrd_high=0x10000000\0"
 
+/* SPL */
+/*
+ * Select the boot device here
+ *
+ * Currently supported are:
+ * SPL_BOOT_SPI_NOR_FLASH	- Booting via SPI NOR flash
+ * SPL_BOOT_SDIO_MMC_CARD	- Booting via SDIO/MMC card (partition 1)
+ */
+#define SPL_BOOT_SPI_NOR_FLASH		1
+#define SPL_BOOT_SDIO_MMC_CARD		2
+#define CONFIG_SPL_BOOT_DEVICE		SPL_BOOT_SPI_NOR_FLASH
+
+/* Defines for SPL */
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_SIZE			(140 << 10)
+#define CONFIG_SPL_TEXT_BASE		0x40000030
+#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - 0x0030)
+
+#define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + CONFIG_SPL_SIZE)
+#define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
+
+#define CONFIG_SYS_SPL_MALLOC_START	(CONFIG_SPL_BSS_START_ADDR + \
+					 CONFIG_SPL_BSS_MAX_SIZE)
+#define CONFIG_SYS_SPL_MALLOC_SIZE	(16 << 10)
+
+#define CONFIG_SPL_STACK		(0x40000000 + ((192 - 16) << 10))
+#define CONFIG_SPL_BOOTROM_SAVE		(CONFIG_SPL_STACK + 4)
+
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_I2C_SUPPORT
+
+#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SPI_NOR_FLASH
+/* SPL related SPI defines */
+#define CONFIG_SPL_SPI_SUPPORT
+#define CONFIG_SPL_SPI_FLASH_SUPPORT
+#define CONFIG_SPL_SPI_LOAD
+#define CONFIG_SPL_SPI_BUS		0
+#define CONFIG_SPL_SPI_CS		0
+#define CONFIG_SYS_SPI_U_BOOT_OFFS	0x20000
+#define CONFIG_SYS_U_BOOT_OFFS		CONFIG_SYS_SPI_U_BOOT_OFFS
+#endif
+
+#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SDIO_MMC_CARD
+/* SPL related MMC defines */
+#define CONFIG_SPL_MMC_SUPPORT
+#define CONFIG_SPL_LIBDISK_SUPPORT
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 1
+#define CONFIG_SYS_MMC_U_BOOT_OFFS		(160 << 10)
+#define CONFIG_SYS_U_BOOT_OFFS			CONFIG_SYS_MMC_U_BOOT_OFFS
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR	(CONFIG_SYS_U_BOOT_OFFS / 512)
+#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS	((512 << 10) / 512) /* 512KiB */
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_FIXED_SDHCI_ALIGNED_BUFFER	0x00180000	/* in SDRAM */
+#endif
+#endif
+
+/* Enable DDR support in SPL (DDR3 training from Marvell bin_hdr) */
+#define CONFIG_SYS_MVEBU_DDR_A38X
+#define CONFIG_DDR3
+
 /*
  * mv-common.h should be defined after CMD configs since it used them
  * to enable certain macros
diff --git a/include/configs/db-mv784mp-gp.h b/include/configs/db-mv784mp-gp.h
index c33a588..41e6fdc 100644
--- a/include/configs/db-mv784mp-gp.h
+++ b/include/configs/db-mv784mp-gp.h
@@ -27,6 +27,7 @@
 #define CONFIG_CMD_DHCP
 #define CONFIG_CMD_ENV
 #define CONFIG_CMD_I2C
+#define CONFIG_CMD_IDE
 #define CONFIG_CMD_PING
 #define CONFIG_CMD_SF
 #define CONFIG_CMD_SPI
@@ -60,6 +61,34 @@
 #define CONFIG_SYS_CONSOLE_INFO_QUIET	/* don't print console @ startup */
 #define CONFIG_SYS_ALT_MEMTEST
 
+/* SATA support */
+#ifdef CONFIG_CMD_IDE
+#define __io
+#define CONFIG_IDE_PREINIT
+#define CONFIG_MVSATA_IDE
+
+/* Needs byte-swapping for ATA data register */
+#define CONFIG_IDE_SWAP_IO
+
+#define CONFIG_SYS_ATA_REG_OFFSET	0x0100 /* Offset for register access */
+#define CONFIG_SYS_ATA_DATA_OFFSET	0x0100 /* Offset for data I/O */
+#define CONFIG_SYS_ATA_ALT_OFFSET	0x0100
+
+/* Each 8-bit ATA register is aligned to a 4-bytes address */
+#define CONFIG_SYS_ATA_STRIDE		4
+
+/* CONFIG_CMD_IDE requires some #defines for ATA registers */
+#define CONFIG_SYS_IDE_MAXBUS		2
+#define CONFIG_SYS_IDE_MAXDEVICE	CONFIG_SYS_IDE_MAXBUS
+
+/* ATA registers base is at SATA controller base */
+#define CONFIG_SYS_ATA_BASE_ADDR	MVEBU_AXP_SATA_BASE
+#define CONFIG_SYS_ATA_IDE0_OFFSET	0x2000
+#define CONFIG_SYS_ATA_IDE1_OFFSET	0x4000
+
+#define CONFIG_DOS_PARTITION
+#endif /* CONFIG_CMD_IDE */
+
 /*
  * mv-common.h should be defined after CMD configs since it used them
  * to enable certain macros
@@ -109,7 +138,7 @@
 #define CONFIG_SYS_SPI_U_BOOT_OFFS	0x20000
 
 /* Enable DDR support in SPL (DDR3 training from Marvell bin_hdr) */
-#define CONFIG_SYS_MVEBU_DDR
+#define CONFIG_SYS_MVEBU_DDR_AXP
 #define CONFIG_SPD_EEPROM		0x4e
 
 #endif /* _CONFIG_DB_MV7846MP_GP_H */
diff --git a/include/configs/maxbcm.h b/include/configs/maxbcm.h
index 4826044..0fb117f 100644
--- a/include/configs/maxbcm.h
+++ b/include/configs/maxbcm.h
@@ -108,7 +108,7 @@
 #define CONFIG_SYS_SPI_U_BOOT_OFFS	0x20000
 
 /* Enable DDR support in SPL (DDR3 training from Marvell bin_hdr) */
-#define CONFIG_SYS_MVEBU_DDR
+#define CONFIG_SYS_MVEBU_DDR_AXP
 #define CONFIG_DDR_FIXED_SIZE		(1 << 20)	/* 1GiB */
 
 #endif /* _CONFIG_DB_MV7846MP_GP_H */
diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h
index af36ac5..4781e79 100644
--- a/include/configs/minnowmax.h
+++ b/include/configs/minnowmax.h
@@ -60,9 +60,6 @@
 #define CONFIG_FIT_SIGNATURE
 #define CONFIG_RSA
 
-/* Avoid a warning in the Realtek Ethernet driver */
-#define CONFIG_SYS_CACHELINE_SIZE 16
-
 #define CONFIG_ENV_SECT_SIZE		0x1000
 #define CONFIG_ENV_OFFSET		0x007fe000
 
diff --git a/include/configs/mv-common.h b/include/configs/mv-common.h
index b654fff..b90de14 100644
--- a/include/configs/mv-common.h
+++ b/include/configs/mv-common.h
@@ -95,7 +95,7 @@
 #define CONFIG_SYS_MEMTEST_START 0x00800000	/* 8M */
 #define CONFIG_SYS_MEMTEST_END	0x00ffffff	/*(_16M -1) */
 #define CONFIG_SYS_RESET_ADDRESS 0xffff0000	/* Rst Vector Adr */
-#define CONFIG_SYS_MAXARGS	16	/* max number of command args */
+#define CONFIG_SYS_MAXARGS	32	/* max number of command args */
 
 /* ====> Include platform Common Definitions */
 #include <asm/arch/config.h>
diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h
index 5c7a342..908be26 100644
--- a/include/configs/uniphier.h
+++ b/include/configs/uniphier.h
@@ -9,15 +9,18 @@
 #ifndef __CONFIG_UNIPHIER_COMMON_H__
 #define __CONFIG_UNIPHIER_COMMON_H__
 
-#if defined(CONFIG_MACH_PH1_PRO4)
+#if defined(CONFIG_MACH_PH1_SLD3)
 #define CONFIG_DDR_NUM_CH0 2
-#define CONFIG_DDR_NUM_CH1 2
+#define CONFIG_DDR_NUM_CH1 1
+#define CONFIG_DDR_NUM_CH2 1
 
 /* Physical start address of SDRAM */
 #define CONFIG_SDRAM0_BASE	0x80000000
 #define CONFIG_SDRAM0_SIZE	0x20000000
-#define CONFIG_SDRAM1_BASE	0xa0000000
+#define CONFIG_SDRAM1_BASE	0xc0000000
 #define CONFIG_SDRAM1_SIZE	0x20000000
+#define CONFIG_SDRAM2_BASE	0xc0000000
+#define CONFIG_SDRAM2_SIZE	0x10000000
 #endif
 
 #if defined(CONFIG_MACH_PH1_LD4)
@@ -31,6 +34,17 @@
 #define CONFIG_SDRAM1_SIZE	0x10000000
 #endif
 
+#if defined(CONFIG_MACH_PH1_PRO4)
+#define CONFIG_DDR_NUM_CH0 2
+#define CONFIG_DDR_NUM_CH1 2
+
+/* Physical start address of SDRAM */
+#define CONFIG_SDRAM0_BASE	0x80000000
+#define CONFIG_SDRAM0_SIZE	0x20000000
+#define CONFIG_SDRAM1_BASE	0xa0000000
+#define CONFIG_SDRAM1_SIZE	0x20000000
+#endif
+
 #if defined(CONFIG_MACH_PH1_SLD8)
 #define CONFIG_DDR_NUM_CH0 1
 #define CONFIG_DDR_NUM_CH1 1
@@ -177,8 +191,13 @@
 
 #define CONFIG_NAND_DENALI_ECC_SIZE			1024
 
+#ifdef CONFIG_MACH_PH1_SLD3
+#define CONFIG_SYS_NAND_REGS_BASE			0xf8100000
+#define CONFIG_SYS_NAND_DATA_BASE			0xf8000000
+#else
 #define CONFIG_SYS_NAND_REGS_BASE			0x68100000
 #define CONFIG_SYS_NAND_DATA_BASE			0x68000000
+#endif
 
 #define CONFIG_SYS_NAND_BASE		(CONFIG_SYS_NAND_DATA_BASE + 0x10)
 
@@ -209,7 +228,6 @@
 
 #define CONFIG_LOADADDR			0x84000000
 #define CONFIG_SYS_LOAD_ADDR		CONFIG_LOADADDR
-#define CONFIG_BOOTFILE			"fit.itb"
 
 #define CONFIG_CMDLINE_EDITING		/* add command line history	*/
 
@@ -222,25 +240,61 @@
 	"ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname:$netdev:off;" \
 	"tftpboot; bootm;"
 
-#define CONFIG_BOOTARGS		" user_debug=0x1f init=/sbin/init"
+#define CONFIG_BOOTARGS		" earlyprintk loglevel=8"
 
-#define	CONFIG_EXTRA_ENV_SETTINGS		\
-	"netdev=eth0\0"				\
-	"image_offset=0x00080000\0"		\
-	"image_size=0x00f00000\0"		\
-	"verify=n\0"				\
-	"nandupdate=nand erase 0 0x100000 &&"				\
-		   "tftpboot u-boot-spl.bin &&"				\
-		   "nand write $loadaddr 0 0x10000 &&"			\
-		   "tftpboot u-boot-dtb.img &&"				\
-		   "nand write $loadaddr 0x10000 0xf0000\0"		\
-	"norboot=run add_default_bootargs &&"				\
-		"bootm $image_offset\0"					\
-	"nandboot=run add_default_bootargs &&"				\
-		 "nand read $loadaddr $image_offset $image_size &&"	\
-		 "bootm\0"						\
-	"add_default_bootargs=setenv bootargs $bootargs"		\
-		" console=ttyS0,$baudrate\0"				\
+#ifdef CONFIG_FIT
+#define CONFIG_BOOTFILE			"fitImage"
+#define LINUXBOOT_ENV_SETTINGS \
+	"fit_addr=0x00100000\0" \
+	"fit_addr_r=0x84100000\0" \
+	"fit_size=0x00f00000\0" \
+	"norboot=run add_default_bootargs &&" \
+		"bootm $fit_addr\0" \
+	"nandboot=run add_default_bootargs &&" \
+		"nand read $fit_addr_r $fit_addr $fit_size &&" \
+		"bootm $fit_addr_r\0" \
+	"tftpboot=run add_default_bootargs &&" \
+		"tftpboot $fit_addr_r $bootfile &&" \
+		"bootm $fit_addr_r\0"
+#else
+#define CONFIG_BOOTFILE			"uImage"
+#define LINUXBOOT_ENV_SETTINGS \
+	"fdt_addr=0x00100000\0" \
+	"fdt_addr_r=0x84100000\0" \
+	"fdt_size=0x00008000\0" \
+	"fdt_file=" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0" \
+	"kernel_addr=0x00200000\0" \
+	"kernel_addr_r=0x84200000\0" \
+	"kernel_size=0x00800000\0" \
+	"ramdisk_addr=0x00a00000\0" \
+	"ramdisk_addr_r=0x84a00000\0" \
+	"ramdisk_size=0x00600000\0" \
+	"ramdisk_file=rootfs.cpio.uboot\0" \
+	"norboot=run add_default_bootargs &&" \
+		"bootm $kernel_addr $ramdisk_addr $fdt_addr\0" \
+	"nandboot=run add_default_bootargs &&" \
+		"nand read $kernel_addr_r $kernel_addr $kernel_size &&" \
+		"nand read $ramdisk_addr_r $ramdisk_addr $ramdisk_size &&" \
+		"nand read $fdt_addr_r $fdt_addr $fdt_size &&" \
+		"bootm $kernel_addr_r $ramdisk_addr_r $fdt_addr_r\0" \
+	"tftpboot=run add_default_bootargs &&" \
+		"tftpboot $kernel_addr_r $bootfile &&" \
+		"tftpboot $ramdisk_addr_r $ramdisk_file &&" \
+		"tftpboot $fdt_addr_r $fdt_file &&" \
+		"bootm $kernel_addr_r $ramdisk_addr_r $fdt_addr_r\0"
+#endif
+
+#define	CONFIG_EXTRA_ENV_SETTINGS				\
+	"netdev=eth0\0"						\
+	"verify=n\0"						\
+	"nandupdate=nand erase 0 0x00100000 &&"			\
+		"tftpboot u-boot-spl.bin &&"			\
+		"nand write $loadaddr 0 0x00010000 &&"		\
+		"tftpboot u-boot-dtb.img &&"			\
+		"nand write $loadaddr 0x00010000 0x000f0000\0"	\
+	"add_default_bootargs=setenv bootargs $bootargs"	\
+		" console=ttyS0,$baudrate\0"			\
+	LINUXBOOT_ENV_SETTINGS
 
 /* Open Firmware flat tree */
 #define CONFIG_OF_LIBFDT
@@ -259,7 +313,8 @@
 #define CONFIG_SYS_SDRAM_SIZE	(CONFIG_SDRAM0_SIZE)
 #endif
 
-#if defined(CONFIG_MACH_PH1_LD4) || defined(CONFIG_MACH_PH1_SLD8)
+#if defined(CONFIG_MACH_PH1_SLD3) || defined(CONFIG_MACH_PH1_LD4) || \
+	defined(CONFIG_MACH_PH1_SLD8)
 #define CONFIG_SPL_TEXT_BASE		0x00040000
 #endif
 #if defined(CONFIG_MACH_PH1_PRO4)
diff --git a/include/debug_uart.h b/include/debug_uart.h
index f56797b..a75e377 100644
--- a/include/debug_uart.h
+++ b/include/debug_uart.h
@@ -10,8 +10,6 @@
 #ifndef _DEBUG_UART_H
 #define _DEBUG_UART_H
 
-#include <linux/linkage.h>
-
 /*
  * The debug UART is intended for use very early in U-Boot to debug problems
  * when an ICE or other debug mechanism is not available.
@@ -64,46 +62,46 @@
  *
  * @ch:		Character to output
  */
-asmlinkage void printch(int ch);
+void printch(int ch);
 
 /**
  * printascii() - Output an ASCII string to the debug UART
  *
  * @str:	String to output
  */
-asmlinkage void printascii(const char *str);
+void printascii(const char *str);
 
 /**
  * printhex2() - Output a 2-digit hex value
  *
  * @value:	Value to output
  */
-asmlinkage void printhex2(uint value);
+void printhex2(uint value);
 
 /**
  * printhex4() - Output a 4-digit hex value
  *
  * @value:	Value to output
  */
-asmlinkage void printhex4(uint value);
+void printhex4(uint value);
 
 /**
  * printhex8() - Output a 8-digit hex value
  *
  * @value:	Value to output
  */
-asmlinkage void printhex8(uint value);
+void printhex8(uint value);
 
 /*
  * Now define some functions - this should be inserted into the serial driver
  */
 #define DEBUG_UART_FUNCS \
-	asmlinkage void printch(int ch) \
+	void printch(int ch) \
 	{ \
 		_debug_uart_putc(ch); \
 	} \
 \
-	asmlinkage void printascii(const char *str) \
+	void printascii(const char *str) \
 	{ \
 		while (*str) \
 			_debug_uart_putc(*str++); \
@@ -121,17 +119,17 @@
 			printhex1(value >> (4 * digits)); \
 	} \
 \
-	asmlinkage void printhex2(uint value) \
+	void printhex2(uint value) \
 	{ \
 		printhex(value, 2); \
 	} \
 \
-	asmlinkage void printhex4(uint value) \
+	void printhex4(uint value) \
 	{ \
 		printhex(value, 4); \
 	} \
 \
-	asmlinkage void printhex8(uint value) \
+	void printhex8(uint value) \
 	{ \
 		printhex(value, 8); \
 	}
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 687462b..402304f 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -107,6 +107,32 @@
 static inline int device_unbind(struct udevice *dev) { return 0; }
 #endif
 
+/**
+ * device_remove_children() - Stop all device's children
+ * @dev:	The device whose children are to be removed
+ * @return 0 on success, -ve on error
+ */
+#ifdef CONFIG_DM_DEVICE_REMOVE
+int device_remove_children(struct udevice *dev);
+#else
+static inline int device_remove_children(struct udevice *dev) { return 0; }
+#endif
+
+/**
+ * device_unbind_children() - Unbind all device's children from the device
+ *
+ * On error, the function continues to unbind all children, and reports the
+ * first error.
+ *
+ * @dev:	The device that is to be stripped of its children
+ * @return 0 on success, -ve on error
+ */
+#ifdef CONFIG_DM_DEVICE_REMOVE
+int device_unbind_children(struct udevice *dev);
+#else
+static inline int device_unbind_children(struct udevice *dev) { return 0; }
+#endif
+
 #ifdef CONFIG_DM_DEVICE_REMOVE
 void device_free(struct udevice *dev);
 #else
diff --git a/include/dm/device.h b/include/dm/device.h
index 18296bb..9fa0048 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -386,10 +386,24 @@
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
  * @return 0 if OK, -ve on error
  */
-int device_get_child_by_of_offset(struct udevice *parent, int seq,
+int device_get_child_by_of_offset(struct udevice *parent, int of_offset,
 				  struct udevice **devp);
 
 /**
+ * device_get_global_by_of_offset() - Get a device based on FDT offset
+ *
+ * Locates a device by its device tree offset, searching globally throughout
+ * the all driver model devices.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @of_offset: Device tree offset to find
+ * @devp: Returns pointer to device if found, otherwise this is set to NULL
+ * @return 0 if OK, -ve on error
+ */
+int device_get_global_by_of_offset(int of_offset, struct udevice **devp);
+
+/**
  * device_find_first_child() - Find the first child of a device
  *
  * @parent: Parent device to search
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
index fbc8a6b..6f4f001 100644
--- a/include/dm/platdata.h
+++ b/include/dm/platdata.h
@@ -16,6 +16,10 @@
 /**
  * struct driver_info - Information required to instantiate a device
  *
+ * NOTE: Avoid using this except in extreme circumstances, where device tree
+ * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
+ * available). U-Boot's driver model uses device tree for configuration.
+ *
  * @name:	Driver name
  * @platdata:	Driver-specific platform data
  */
@@ -24,6 +28,11 @@
 	const void *platdata;
 };
 
+/**
+ * NOTE: Avoid using these except in extreme circumstances, where device tree
+ * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
+ * available). U-Boot's driver model uses device tree for configuration.
+ */
 #define U_BOOT_DEVICE(__name)						\
 	ll_entry_declare(struct driver_info, __name, driver_info)
 
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index c7310d7..bc057d7 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -25,27 +25,33 @@
 	UCLASS_SIMPLE_BUS,	/* bus with child devices */
 
 	/* U-Boot uclasses start here - in alphabetical order */
+	UCLASS_CLK,		/* Clock source, e.g. used by peripherals */
 	UCLASS_CPU,		/* CPU, typically part of an SoC */
 	UCLASS_CROS_EC,		/* Chrome OS EC */
 	UCLASS_DISPLAY_PORT,	/* Display port video */
+	UCLASS_RAM,		/* RAM controller */
 	UCLASS_ETH,		/* Ethernet device */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
 	UCLASS_I2C,		/* I2C bus */
 	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
 	UCLASS_I2C_GENERIC,	/* Generic I2C device */
+	UCLASS_LED,		/* Light-emitting diode (LED) */
 	UCLASS_LPC,		/* x86 'low pin count' interface */
 	UCLASS_MASS_STORAGE,	/* Mass storage device */
+	UCLASS_MMC,		/* SD / MMC card or chip */
 	UCLASS_MOD_EXP,		/* RSA Mod Exp device */
 	UCLASS_PCH,		/* x86 platform controller hub */
 	UCLASS_PCI,		/* PCI bus */
 	UCLASS_PCI_GENERIC,	/* Generic PCI bus device */
 	UCLASS_PMIC,		/* PMIC I/O device */
 	UCLASS_REGULATOR,	/* Regulator device */
+	UCLASS_RESET,		/* Reset device */
 	UCLASS_RTC,		/* Real time clock device */
 	UCLASS_SERIAL,		/* Serial UART */
 	UCLASS_SPI,		/* SPI bus */
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
+	UCLASS_SYSCON,		/* System configuration device */
 	UCLASS_THERMAL,		/* Thermal sensor */
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
diff --git a/include/dm/util.h b/include/dm/util.h
index 0cec17b..7dbed67 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -33,4 +33,10 @@
  */
 int list_count_items(struct list_head *head);
 
+/* Dump out a tree of all devices */
+void dm_dump_all(void);
+
+/* Dump out a list of uclasses and their devices */
+void dm_dump_uclass(void);
+
 #endif
diff --git a/include/dwmmc.h b/include/dwmmc.h
index 86a5491..7a7555a 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -129,8 +129,24 @@
 /* quirks */
 #define DWMCI_QUIRK_DISABLE_SMU		(1 << 0)
 
+/**
+ * struct dwmci_host - Information about a designware MMC host
+ *
+ * @name:	Device name
+ * @ioaddr:	Base I/O address of controller
+ * @quirks:	Quick flags - see DWMCI_QUIRK_...
+ * @caps:	Capabilities - see MMC_MODE_...
+ * @bus_hz:	Bus speed in Hz, if @get_mmc_clk() is NULL
+ * @div:	Arbitrary clock divider value for use by controller
+ * @dev_index:	Arbitrary device index for use by controller
+ * @dev_id:	Arbitrary device ID for use by controller
+ * @buswidth:	Bus width in bits (8 or 4)
+ * @fifoth_val:	Value for FIFOTH register (or 0 to leave unset)
+ * @mmc:	Pointer to generic MMC structure for this device
+ * @priv:	Private pointer for use by controller
+ */
 struct dwmci_host {
-	char *name;
+	const char *name;
 	void *ioaddr;
 	unsigned int quirks;
 	unsigned int caps;
diff --git a/include/image.h b/include/image.h
index b6eb57e..63c3d37 100644
--- a/include/image.h
+++ b/include/image.h
@@ -246,6 +246,8 @@
 #define IH_TYPE_LPC32XXIMAGE	21	/* x86 setup.bin Image		*/
 #define IH_TYPE_LOADABLE	22	/* A list of typeless images	*/
 
+#define IH_TYPE_COUNT		23	/* Number of image types */
+
 /*
  * Compression Types
  */
@@ -411,6 +413,15 @@
 const char *genimg_get_os_name(uint8_t os);
 const char *genimg_get_arch_name(uint8_t arch);
 const char *genimg_get_type_name(uint8_t type);
+
+/**
+ * genimg_get_type_short_name() - get the short name for an image type
+ *
+ * @param type	Image type (IH_TYPE_...)
+ * @return image short name, or "unknown" if unknown
+ */
+const char *genimg_get_type_short_name(uint8_t type);
+
 const char *genimg_get_comp_name(uint8_t comp);
 int genimg_get_os_id(const char *name);
 int genimg_get_arch_id(const char *name);
diff --git a/include/led.h b/include/led.h
new file mode 100644
index 0000000..b929d0c
--- /dev/null
+++ b/include/led.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __LED_H
+#define __LED_H
+
+/**
+ * struct led_uclass_plat - Platform data the uclass stores about each device
+ *
+ * @label:	LED label
+ */
+struct led_uclass_plat {
+	const char *label;
+};
+
+struct led_ops {
+	/**
+	 * set_on() - set the state of an LED
+	 *
+	 * @dev:	LED device to change
+	 * @on:		1 to turn the LED on, 0 to turn it off
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*set_on)(struct udevice *dev, int on);
+};
+
+#define led_get_ops(dev)	((struct led_ops *)(dev)->driver->ops)
+
+/**
+ * led_get_by_label() - Find an LED device by label
+ *
+ * @label:	LED label to look up
+ * @devp:	Returns the associated device, if found
+ * @return 0 if found, -ENODEV if not found, other -ve on error
+ */
+int led_get_by_label(const char *label, struct udevice **devp);
+
+/**
+ * led_set_on() - set the state of an LED
+ *
+ * @dev:	LED device to change
+ * @on:		1 to turn the LED on, 0 to turn it off
+ * @return 0 if OK, -ve on error
+ */
+int led_set_on(struct udevice *dev, int on);
+
+#endif
diff --git a/include/libfdt.h b/include/libfdt.h
index 421d64f..e48c21a 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -121,7 +121,12 @@
 	/* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
 	 * or similar property with a bad format or value */
 
-#define FDT_ERR_MAX		14
+#define FDT_ERR_TOODEEP		15
+	/* FDT_ERR_TOODEEP: The depth of a node has exceeded the internal
+	 * libfdt limit. This can happen if you have more than
+	 * FDT_MAX_DEPTH nested nodes. */
+
+#define FDT_ERR_MAX		15
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -1646,11 +1651,99 @@
 
 const char *fdt_strerror(int errval);
 
+/**
+ * fdt_remove_unused_strings() - Remove any unused strings from an FDT
+ *
+ * This creates a new device tree in @new with unused strings removed. The
+ * called can then use fdt_pack() to minimise the space consumed.
+ *
+ * @old:	Old device tree blog
+ * @new:	Place to put new device tree blob, which must be as large as
+ *		@old
+ * @return
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, corrupt device tree
+ *	-FDT_ERR_NOSPACE, out of space, which should not happen unless there
+ *		is something very wrong with the device tree input
+ */
+int fdt_remove_unused_strings(const void *old, void *new);
+
 struct fdt_region {
 	int offset;
 	int size;
 };
 
+/*
+ * Flags for fdt_find_regions()
+ *
+ * Add a region for the string table (always the last region)
+ */
+#define FDT_REG_ADD_STRING_TAB		(1 << 0)
+
+/*
+ * Add all supernodes of a matching node/property, useful for creating a
+ * valid subset tree
+ */
+#define FDT_REG_SUPERNODES		(1 << 1)
+
+/* Add the FDT_BEGIN_NODE tags of subnodes, including their names */
+#define FDT_REG_DIRECT_SUBNODES	(1 << 2)
+
+/* Add all subnodes of a matching node */
+#define FDT_REG_ALL_SUBNODES		(1 << 3)
+
+/* Add a region for the mem_rsvmap table (always the first region) */
+#define FDT_REG_ADD_MEM_RSVMAP		(1 << 4)
+
+/* Indicates what an fdt part is (node, property, value) */
+#define FDT_IS_NODE			(1 << 0)
+#define FDT_IS_PROP			(1 << 1)
+#define FDT_IS_VALUE			(1 << 2)	/* not supported */
+#define FDT_IS_COMPAT			(1 << 3)	/* used internally */
+#define FDT_NODE_HAS_PROP		(1 << 4)	/* node contains prop */
+
+#define FDT_ANY_GLOBAL		(FDT_IS_NODE | FDT_IS_PROP | FDT_IS_VALUE | \
+					FDT_IS_COMPAT)
+#define FDT_IS_ANY			0x1f		/* all the above */
+
+/* We set a reasonable limit on the number of nested nodes */
+#define FDT_MAX_DEPTH			32
+
+/* Decribes what we want to include from the current tag */
+enum want_t {
+	WANT_NOTHING,
+	WANT_NODES_ONLY,		/* No properties */
+	WANT_NODES_AND_PROPS,		/* Everything for one level */
+	WANT_ALL_NODES_AND_PROPS	/* Everything for all levels */
+};
+
+/* Keeps track of the state at parent nodes */
+struct fdt_subnode_stack {
+	int offset;		/* Offset of node */
+	enum want_t want;	/* The 'want' value here */
+	int included;		/* 1 if we included this node, 0 if not */
+};
+
+struct fdt_region_ptrs {
+	int depth;			/* Current tree depth */
+	int done;			/* What we have completed scanning */
+	enum want_t want;		/* What we are currently including */
+	char *end;			/* Pointer to end of full node path */
+	int nextoffset;			/* Next node offset to check */
+};
+
+/* The state of our finding algortihm */
+struct fdt_region_state {
+	struct fdt_subnode_stack stack[FDT_MAX_DEPTH];	/* node stack */
+	struct fdt_region *region;	/* Contains list of regions found */
+	int count;			/* Numnber of regions found */
+	const void *fdt;		/* FDT blob */
+	int max_regions;		/* Maximum regions to find */
+	int can_merge;		/* 1 if we can merge with previous region */
+	int start;			/* Start position of current region */
+	struct fdt_region_ptrs ptrs;	/* Pointers for what we are up to */
+};
+
 /**
  * fdt_find_regions() - find regions in device tree
  *
@@ -1710,4 +1803,165 @@
 		     struct fdt_region region[], int max_regions,
 		     char *path, int path_len, int add_string_tab);
 
+/**
+ * fdt_first_region() - find regions in device tree
+ *
+ * Given a nodes and properties to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The use for this function is twofold. Firstly it provides a convenient
+ * way of performing a structure-aware grep of the tree. For example it is
+ * possible to grep for a node and get all the properties associated with
+ * that node. Trees can be subsetted easily, by specifying the nodes that
+ * are required, and then writing out the regions returned by this function.
+ * This is useful for small resource-constrained systems, such as boot
+ * loaders, which want to use an FDT but do not need to know about all of
+ * it.
+ *
+ * Secondly it makes it easy to hash parts of the tree and detect changes.
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ * Note that semantically null changes in order could still cause false
+ * hash misses. Such reordering might happen if the tree is regenerated
+ * from source, and nodes are reordered (the bytes-stream will be emitted
+ * in a different order and mnay hash functions will detect this). However
+ * if an existing tree is modified using libfdt functions, such as
+ * fdt_add_subnode() and fdt_setprop(), then this problem is avoided.
+ *
+ * The nodes/properties to include/exclude are defined by a function
+ * provided by the caller. This function is called for each node and
+ * property, and must return:
+ *
+ *    0 - to exclude this part
+ *    1 - to include this part
+ *   -1 - for FDT_IS_PROP only: no information is available, so include
+ *		if its containing node is included
+ *
+ * The last case is only used to deal with properties. Often a property is
+ * included if its containing node is included - this is the case where
+ * -1 is returned.. However if the property is specifically required to be
+ * included/excluded, then 0 or 1 can be returned. Note that including a
+ * property when the FDT_REG_SUPERNODES flag is given will force its
+ * containing node to be included since it is not valid to have a property
+ * that is not in a node.
+ *
+ * Using the information provided, the inclusion of a node can be controlled
+ * either by a node name or its compatible string, or any other property
+ * that the function can determine.
+ *
+ * As an example, including node "/" means to include the root node and all
+ * root properties. A flag provides a way of also including supernodes (of
+ * which there is none for the root node), and another flag includes
+ * immediate subnodes, so in this case we would get the FDT_BEGIN_NODE and
+ * FDT_END_NODE of all subnodes of /.
+ *
+ * The subnode feature helps in a hashing situation since it prevents the
+ * root node from changing at all. Any change to non-excluded properties,
+ * names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too. This is always
+ * the last region.
+ *
+ * The FDT also has a mem_rsvmap table which can also be included, and is
+ * always the first region if so.
+ *
+ * The device tree header is not included in the region list. Since the
+ * contents of the FDT are changing (shrinking, often), the caller will need
+ * to regenerate the header anyway.
+ *
+ * @fdt:	Device tree to check
+ * @h_include:	Function to call to determine whether to include a part or
+ *		not:
+ *
+ *		@priv: Private pointer as passed to fdt_find_regions()
+ *		@fdt: Pointer to FDT blob
+ *		@offset: Offset of this node / property
+ *		@type: Type of this part, FDT_IS_...
+ *		@data: Pointer to data (node name, property name, compatible
+ *			string, value (not yet supported)
+ *		@size: Size of data, or 0 if none
+ *		@return 0 to exclude, 1 to include, -1 if no information is
+ *		available
+ * @priv:	Private pointer passed to h_include
+ * @region:	Returns list of regions, sorted by offset
+ * @max_regions: Maximum length of region list
+ * @path:	Pointer to a temporary string for the function to use for
+ *		building path names
+ * @path_len:	Length of path, must be large enough to hold the longest
+ *		path in the tree
+ * @flags:	Various flags that control the region algortihm, see
+ *		FDT_REG_...
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again. Only the first max_regions elements are available in the
+ * array.
+ *
+ * On error a -ve value is return, which can be:
+ *
+ *	-FDT_ERR_BADSTRUCTURE (too deep or more END tags than BEGIN tags
+ *	-FDT_ERR_BADLAYOUT
+ *	-FDT_ERR_NOSPACE (path area is too small)
+ */
+int fdt_first_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info);
+
+/** fdt_next_region() - find next region
+ *
+ * See fdt_first_region() for full description. This function finds the
+ * next region according to the provided parameters, which must be the same
+ * as passed to fdt_first_region().
+ *
+ * This function can additionally return -FDT_ERR_NOTFOUND when there are no
+ * more regions
+ */
+int fdt_next_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info);
+
+/**
+ * fdt_add_alias_regions() - find aliases that point to existing regions
+ *
+ * Once a device tree grep is complete some of the nodes will be present
+ * and some will have been dropped. This function checks all the alias nodes
+ * to figure out which points point to nodes which are still present. These
+ * aliases need to be kept, along with the nodes they reference.
+ *
+ * Given a list of regions function finds the aliases that still apply and
+ * adds more regions to the list for these. This function is called after
+ * fdt_next_region() has finished returning regions and requires the same
+ * state.
+ *
+ * @fdt:	Device tree file to reference
+ * @region:	List of regions that will be kept
+ * @count:	Number of regions
+ * @max_regions: Number of entries that can fit in @region
+ * @info:	Region state as returned from fdt_next_region()
+ * @return new number of regions in @region (i.e. count + the number added)
+ * or -FDT_ERR_NOSPACE if there was not enough space.
+ */
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+			  int max_regions, struct fdt_region_state *info);
+
 #endif /* _LIBFDT_H */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 6ff3915..fbebf91 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -36,10 +36,25 @@
 #define KERN_INFO
 #define KERN_DEBUG
 
+#define GFP_ATOMIC ((gfp_t) 0)
+#define GFP_KERNEL ((gfp_t) 0)
+#define GFP_NOFS ((gfp_t) 0)
+#define GFP_USER ((gfp_t) 0)
+#define __GFP_NOWARN ((gfp_t) 0)
+#define __GFP_ZERO	((__force gfp_t)0x8000u)	/* Return zeroed page on success */
+
 void *kmalloc(size_t size, int flags);
-void *kzalloc(size_t size, int flags);
+
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+	return kmalloc(size, flags | __GFP_ZERO);
+}
 #define vmalloc(size)	kmalloc(size, 0)
 #define __vmalloc(size, flags, pgsz)	kmalloc(size, flags)
+static inline void *vzalloc(unsigned long size)
+{
+	return kzalloc(size, 0);
+}
 #define kfree(ptr)	free(ptr)
 #define vfree(ptr)	free(ptr)
 
@@ -73,13 +88,6 @@
 /* drivers/char/random.c */
 #define get_random_bytes(...)
 
-/* idr.c */
-#define GFP_ATOMIC ((gfp_t) 0)
-#define GFP_KERNEL ((gfp_t) 0)
-#define GFP_NOFS ((gfp_t) 0)
-#define GFP_USER ((gfp_t) 0)
-#define __GFP_NOWARN ((gfp_t) 0)
-
 /* include/linux/leds.h */
 struct led_trigger {};
 
@@ -189,8 +197,6 @@
 unsigned long copy_from_user(void *dest, const void *src,
 			     unsigned long count);
 
-void *vzalloc(unsigned long size);
-
 typedef unused_t spinlock_t;
 typedef int	wait_queue_head_t;
 
@@ -315,8 +321,6 @@
 
 typedef unsigned long dmaaddr_t;
 
-#define cpu_relax() do {} while (0)
-
 #define pm_runtime_get_sync(dev) do {} while (0)
 #define pm_runtime_put(dev) do {} while (0)
 #define pm_runtime_put_sync(dev) do {} while (0)
diff --git a/include/mmc.h b/include/mmc.h
index dd98b3b..cda9a19 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -266,6 +266,28 @@
 #define MMC_NUM_BOOT_PARTITION	2
 #define MMC_PART_RPMB           3       /* RPMB partition number */
 
+/* Driver model support */
+
+/**
+ * struct mmc_uclass_priv - Holds information about a device used by the uclass
+ */
+struct mmc_uclass_priv {
+	struct mmc *mmc;
+};
+
+/**
+ * mmc_get_mmc_dev() - get the MMC struct pointer for a device
+ *
+ * Provided that the device is already probed and ready for use, this value
+ * will be available.
+ *
+ * @dev:	Device
+ * @return associated mmc struct pointer if available, else NULL
+ */
+struct mmc *mmc_get_mmc_dev(struct udevice *dev);
+
+/* End of driver model support */
+
 struct mmc_cid {
 	unsigned long psn;
 	unsigned short oid;
diff --git a/include/net.h b/include/net.h
index d17173d..d09bec9 100644
--- a/include/net.h
+++ b/include/net.h
@@ -93,6 +93,14 @@
 	int phy_interface;
 };
 
+enum eth_recv_flags {
+	/*
+	 * Check hardware device for new packets (otherwise only return those
+	 * which are already in the memory buffer ready to process)
+	 */
+	ETH_RECV_CHECK_DEVICE		= 1 << 0,
+};
+
 /**
  * struct eth_ops - functions of Ethernet MAC controllers
  *
@@ -111,7 +119,9 @@
  * mcast: Join or leave a multicast group (for TFTP) - optional
  * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
  *		 on some platforms like ARM). This function expects the
- *		 eth_pdata::enetaddr field to be populated - optional
+ *		 eth_pdata::enetaddr field to be populated. The method can
+ *		 return -ENOSYS to indicate that this is not implemented for
+		 this hardware - optional.
  * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
  *		    ROM on the board. This is how the driver should expose it
  *		    to the network stack. This function should fill in the
@@ -120,7 +130,7 @@
 struct eth_ops {
 	int (*start)(struct udevice *dev);
 	int (*send)(struct udevice *dev, void *packet, int length);
-	int (*recv)(struct udevice *dev, uchar **packetp);
+	int (*recv)(struct udevice *dev, int flags, uchar **packetp);
 	int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
 	void (*stop)(struct udevice *dev);
 #ifdef CONFIG_MCAST_TFTP
diff --git a/include/pci.h b/include/pci.h
index 542e68b..94bca97 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -468,7 +468,10 @@
 #define PCI_ANY_ID		(~0)
 
 struct pci_device_id {
-	unsigned int vendor, device;		/* Vendor and device ID or PCI_ANY_ID */
+	unsigned int vendor, device;	/* Vendor and device ID or PCI_ANY_ID */
+	unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
+	unsigned int class, class_mask;	/* (class,subclass,prog-if) triplet */
+	unsigned long driver_data;	/* Data private to the driver */
 };
 
 struct pci_controller;
@@ -805,6 +808,14 @@
 #define pci_get_ops(dev)	((struct dm_pci_ops *)(dev)->driver->ops)
 
 /**
+ * pci_get_bdf() - Get the BDF value for a device
+ *
+ * @dev:	Device to check
+ * @return bus/device/function value (see PCI_BDF())
+ */
+pci_dev_t pci_get_bdf(struct udevice *dev);
+
+/**
  * pci_bind_bus_devices() - scan a PCI bus and bind devices
  *
  * Scan a PCI bus looking for devices. Bind each one that is found. If
@@ -1101,7 +1112,79 @@
 int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
 			 struct udevice **emulp);
 
-#endif
+#endif /* CONFIG_DM_PCI */
+
+/**
+ * PCI_DEVICE - macro used to describe a specific pci device
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device.  The subvendor and subdevice fields will be set to
+ * PCI_ANY_ID.
+ */
+#define PCI_DEVICE(vend, dev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_DEVICE_SUB - macro used to describe a specific pci device with subsystem
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ * @subvend: the 16 bit PCI Subvendor ID
+ * @subdev: the 16 bit PCI Subdevice ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device with subsystem information.
+ */
+#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = (subvend), .subdevice = (subdev)
+
+/**
+ * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
+ * @dev_class: the class, subclass, prog-if triple for this device
+ * @dev_class_mask: the class mask for this device
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI class.  The vendor, device, subvendor, and subdevice
+ * fields will be set to PCI_ANY_ID.
+ */
+#define PCI_DEVICE_CLASS(dev_class, dev_class_mask) \
+	.class = (dev_class), .class_mask = (dev_class_mask), \
+	.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_VDEVICE - macro used to describe a specific pci device in short form
+ * @vend: the vendor name
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI device.  The subvendor, and subdevice fields will be set
+ * to PCI_ANY_ID. The macro allows the next field to follow as the device
+ * private data.
+ */
+
+#define PCI_VDEVICE(vend, dev) \
+	.vendor = PCI_VENDOR_ID_##vend, .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0
+
+/**
+ * struct pci_driver_entry - Matches a driver to its pci_device_id list
+ * @driver: Driver to use
+ * @match: List of match records for this driver, terminated by {}
+ */
+struct pci_driver_entry {
+	struct driver *driver;
+	const struct pci_device_id *match;
+};
+
+#define U_BOOT_PCI_DEVICE(__name, __match)				\
+	ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\
+		.driver = llsym(struct driver, __name, driver), \
+		.match = __match, \
+		}
 
 #endif /* __ASSEMBLY__ */
 #endif /* _PCI_H */
diff --git a/include/power/pmic.h b/include/power/pmic.h
index eb152ef..6ba4b6e 100644
--- a/include/power/pmic.h
+++ b/include/power/pmic.h
@@ -264,6 +264,40 @@
  */
 int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len);
 int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len);
+
+/**
+ * pmic_reg_read() - read a PMIC register value
+ *
+ * @dev:	PMIC device to read
+ * @reg:	Register to read
+ * @return value read on success or negative value of errno.
+ */
+int pmic_reg_read(struct udevice *dev, uint reg);
+
+/**
+ * pmic_reg_write() - write a PMIC register value
+ *
+ * @dev:	PMIC device to write
+ * @reg:	Register to write
+ * @value:	Value to write
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_reg_write(struct udevice *dev, uint reg, uint value);
+
+/**
+ * pmic_clrsetbits() - clear and set bits in a PMIC register
+ *
+ * This reads a register, optionally clears some bits, optionally sets some
+ * bits, then writes the register.
+ *
+ * @dev:	PMIC device to update
+ * @reg:	Register to update
+ * @clr:	Bit mask to clear (set those bits that you want cleared)
+ * @set:	Bit mask to set (set those bits that you want set)
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set);
+
 #endif /* CONFIG_DM_PMIC */
 
 #ifdef CONFIG_POWER
diff --git a/include/power/regulator.h b/include/power/regulator.h
index 03a2cef..0152290 100644
--- a/include/power/regulator.h
+++ b/include/power/regulator.h
@@ -128,6 +128,11 @@
 	const char *name;
 };
 
+enum regulator_flag {
+	REGULATOR_FLAG_AUTOSET_UV	= 1 << 0,
+	REGULATOR_FLAG_AUTOSET_UA	= 1 << 1,
+};
+
 /**
  * struct dm_regulator_uclass_platdata - pointed by dev->uclass_platdata, and
  * allocated on each regulator bind. This structure holds an information
@@ -143,6 +148,8 @@
  * @max_uA*    - maximum amperage (micro Amps)
  * @always_on* - bool type, true or false
  * @boot_on*   - bool type, true or false
+ * TODO(sjg@chromium.org): Consider putting the above two into @flags
+ * @flags:     - flags value (see REGULATOR_FLAG_...)
  * @name**     - fdt regulator name - should be taken from the device tree
  *
  * Note:
@@ -162,6 +169,7 @@
 	bool always_on;
 	bool boot_on;
 	const char *name;
+	int flags;
 };
 
 /* Regulator device operations */
@@ -308,9 +316,39 @@
 int regulator_set_mode(struct udevice *dev, int mode_id);
 
 /**
- * regulator_autoset: setup the regulator given by its uclass's platform data
- * name field. The setup depends on constraints found in device's uclass's
- * platform data (struct dm_regulator_uclass_platdata):
+ * regulators_enable_boot_on() - enable regulators needed for boot
+ *
+ * This enables all regulators which are marked to be on at boot time. This
+ * only works for regulators which don't have a range for voltage/current,
+ * since in that case it is not possible to know which value to use.
+ *
+ * This effectively calls regulator_autoset() for every regulator.
+ */
+int regulators_enable_boot_on(bool verbose);
+
+/**
+ * regulator_autoset: setup the voltage/current on a regulator
+ *
+ * The setup depends on constraints found in device's uclass's platform data
+ * (struct dm_regulator_uclass_platdata):
+ *
+ * - Enable - will set - if any of: 'always_on' or 'boot_on' is set to true,
+ *   or if both are unset, then the function returns
+ * - Voltage value - will set - if '.min_uV' and '.max_uV' values are equal
+ * - Current limit - will set - if '.min_uA' and '.max_uA' values are equal
+ *
+ * The function returns on the first-encountered error.
+ *
+ * @platname - expected string for dm_regulator_uclass_platdata .name field
+ * @devp     - returned pointer to the regulator device - if non-NULL passed
+ * @return: 0 on success or negative value of errno.
+ */
+int regulator_autoset(struct udevice *dev);
+
+/**
+ * regulator_autoset_by_name: setup the regulator given by its uclass's
+ * platform data name field. The setup depends on constraints found in device's
+ * uclass's platform data (struct dm_regulator_uclass_platdata):
  * - Enable - will set - if any of: 'always_on' or 'boot_on' is set to true,
  *   or if both are unset, then the function returns
  * - Voltage value - will set - if '.min_uV' and '.max_uV' values are equal
@@ -320,21 +358,18 @@
  *
  * @platname - expected string for dm_regulator_uclass_platdata .name field
  * @devp     - returned pointer to the regulator device - if non-NULL passed
- * @verbose  - (true/false) print regulator setup info, or be quiet
  * @return: 0 on success or negative value of errno.
  *
  * The returned 'regulator' device can be used with:
  * - regulator_get/set_*
  */
-int regulator_autoset(const char *platname,
-		      struct udevice **devp,
-		      bool verbose);
+int regulator_autoset_by_name(const char *platname, struct udevice **devp);
 
 /**
  * regulator_list_autoset: setup the regulators given by list of their uclass's
  * platform data name field. The setup depends on constraints found in device's
  * uclass's platform data. The function loops with calls to:
- * regulator_autoset() for each name from the list.
+ * regulator_autoset_by_name() for each name from the list.
  *
  * @list_platname - an array of expected strings for .name field of each
  *                  regulator's uclass platdata
@@ -375,7 +410,7 @@
  * Search by name, found in regulator uclass platdata.
  *
  * @platname - expected string for uc_pdata->name of regulator uclass platdata
- * @devp     - returned pointer to the regulator device
+ * @devp     - returns pointer to the regulator device or NULL on error
  * @return 0 on success or negative value of errno.
  *
  * The returned 'regulator' device is probed and can be used with:
diff --git a/include/power/sandbox_pmic.h b/include/power/sandbox_pmic.h
index ae14292..8547674 100644
--- a/include/power/sandbox_pmic.h
+++ b/include/power/sandbox_pmic.h
@@ -117,11 +117,11 @@
 
 /*
  * Expected regulators setup after call of:
- * - regulator_autoset()
+ * - regulator_autoset_by_name()
  * - regulator_list_autoset()
  */
 
-/* BUCK1: for testing regulator_autoset() */
+/* BUCK1: for testing regulator_autoset_by_name() */
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UV	1200000
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UA	200000
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_ENABLE	true
diff --git a/include/ram.h b/include/ram.h
new file mode 100644
index 0000000..e2172a8
--- /dev/null
+++ b/include/ram.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __RAM_H
+#define __RAM_H
+
+struct ram_info {
+	phys_addr_t base;
+	size_t size;
+};
+
+struct ram_ops {
+	/**
+	 * get_info() - Get basic memory info
+	 *
+	 * @dev:	Device to check (UCLASS_RAM)
+	 * @info:	Place to put info
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*get_info)(struct udevice *dev, struct ram_info *info);
+};
+
+#define ram_get_ops(dev)        ((struct ram_ops *)(dev)->driver->ops)
+
+/**
+ * ram_get_info() - Get information about a RAM device
+ *
+ * @dev:	Device to check (UCLASS_RAM)
+ * @info:	Returns RAM info
+ * @return 0 if OK, -ve on error
+ */
+int ram_get_info(struct udevice *dev, struct ram_info *info);
+
+#endif
diff --git a/include/rc4.h b/include/rc4.h
new file mode 100644
index 0000000..ea409c2
--- /dev/null
+++ b/include/rc4.h
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __RC4_H
+#define __RC4_H
+
+/**
+ * rc4_encode() - encode a buf with the RC4 cipher
+ *
+ * @buf:	Buffer to encode (it is overwrite in the process
+ * @len:	Length of buffer in bytes
+ * @key:	16-byte key to use
+ */
+void rc4_encode(unsigned char *buf, unsigned int len, unsigned char key[16]);
+
+#endif
diff --git a/include/regmap.h b/include/regmap.h
new file mode 100644
index 0000000..eccf770
--- /dev/null
+++ b/include/regmap.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __REGMAP_H
+#define __REGMAP_H
+
+/**
+ * struct regmap_range - a register map range
+ *
+ * @start:	Start address
+ * @size:	Size in bytes
+ */
+struct regmap_range {
+	ulong start;
+	ulong size;
+};
+
+/**
+ * struct regmap - a way of accessing hardware/bus registers
+ *
+ * @base:	Base address of register map
+ * @range_count: Number of ranges available within the map
+ * @range:	Pointer to the list of ranges, allocated if @range_count > 1
+ * @base_range:	If @range_count is <= 1, @range points here
+ */
+struct regmap {
+	phys_addr_t base;
+	int range_count;
+	struct regmap_range *range, base_range;
+};
+
+/*
+ * Interface to provide access to registers either through a direct memory
+ * bus or through a peripheral bus like I2C, SPI.
+ */
+int regmap_write(struct regmap *map, uint offset, uint val);
+int regmap_read(struct regmap *map, uint offset, uint *valp);
+
+#define regmap_write32(map, ptr, member, val) \
+	regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val)
+
+#define regmap_read32(map, ptr, member, valp) \
+	regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp)
+
+/**
+ * regmap_init_mem() - Set up a new register map that uses memory access
+ *
+ * Use regmap_uninit() to free it.
+ *
+ * @dev:	Device that uses this map
+ * @mapp:	Returns allocated map
+ */
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
+
+/**
+ * regmap_get_range() - Obtain the base memory address of a regmap range
+ *
+ * @map:	Regmap to query
+ * @range_num:	Range to look up
+ */
+void *regmap_get_range(struct regmap *map, unsigned int range_num);
+
+/**
+ * regmap_uninit() - free a previously inited regmap
+ */
+int regmap_uninit(struct regmap *map);
+
+#endif
diff --git a/include/reset.h b/include/reset.h
new file mode 100644
index 0000000..383761e
--- /dev/null
+++ b/include/reset.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __RESET_H
+#define __RESET_H
+
+enum reset_t {
+	RESET_WARM,	/* Reset CPU, keep GPIOs active */
+	RESET_COLD,	/* Reset CPU and GPIOs */
+	RESET_POWER,	/* Reset PMIC (remove and restore power) */
+
+	RESET_COUNT,
+};
+
+struct reset_ops {
+	/**
+	 * request() - request a reset of the given type
+	 *
+	 * Note that this function may return before the reset takes effect.
+	 *
+	 * @type:	Reset type to request
+	 * @return -EINPROGRESS if the reset has been started and
+	 *		will complete soon, -EPROTONOSUPPORT if not supported
+	 *		by this device, 0 if the reset has already happened
+	 *		(in which case this method will not actually return)
+	 */
+	int (*request)(struct udevice *dev, enum reset_t type);
+};
+
+#define reset_get_ops(dev)        ((struct reset_ops *)(dev)->driver->ops)
+
+/**
+ * reset_request() - request a reset
+ *
+ * @type:	Reset type to request
+ * @return 0 if OK, -EPROTONOSUPPORT if not supported by this device
+ */
+int reset_request(struct udevice *dev, enum reset_t type);
+
+/**
+ * reset_walk() - cause a reset
+ *
+ * This works through the available reset devices until it finds one that can
+ * perform a reset. If the provided reset type is not available, the next one
+ * will be tried.
+ *
+ * If this function fails to reset, it will display a message and halt
+ *
+ * @type:	Reset type to request
+ * @return -EINPROGRESS if a reset is in progress, -ENOSYS if not available
+ */
+int reset_walk(enum reset_t type);
+
+/**
+ * reset_walk_halt() - try to reset, otherwise halt
+ *
+ * This calls reset_walk(). If it returns, indicating that reset is not
+ * supported, it prints a message and halts.
+ */
+void reset_walk_halt(enum reset_t type);
+
+/**
+ * reset_cpu() - calls reset_walk(RESET_WARM)
+ */
+void reset_cpu(ulong addr);
+
+#endif
diff --git a/include/spl.h b/include/spl.h
index d19940f..8e53426 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -81,6 +81,18 @@
 int spl_load_image_ext(block_dev_desc_t *block_dev, int partition, const char *filename);
 int spl_load_image_ext_os(block_dev_desc_t *block_dev, int partition);
 
+/**
+ * spl_init() - Set up device tree and driver model in SPL if enabled
+ *
+ * Call this function in board_init_f() if you want to use device tree and
+ * driver model early, before board_init_r() is called. This function will
+ * be called from board_init_r() if not called earlier.
+ *
+ * If this is not called, then driver model will be inactive in SPL's
+ * board_init_f(), and no device tree will be available.
+ */
+int spl_init(void);
+
 #ifdef CONFIG_SPL_BOARD_INIT
 void spl_board_init(void);
 #endif
diff --git a/include/syscon.h b/include/syscon.h
new file mode 100644
index 0000000..c62ccd6
--- /dev/null
+++ b/include/syscon.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __SYSCON_H
+#define __SYSCON_H
+
+/**
+ * struct syscon_uc_info - Information stored by the syscon UCLASS_UCLASS
+ *
+ * @regmap:	Register map for this controller
+ */
+struct syscon_uc_info {
+	struct regmap *regmap;
+};
+
+/* So far there are no ops so this is a placeholder */
+struct syscon_ops {
+};
+
+#define syscon_get_ops(dev)        ((struct syscon_ops *)(dev)->driver->ops)
+
+/**
+ * syscon_get_regmap() - Get access to a register map
+ *
+ * @dev:	Device to check (UCLASS_SCON)
+ * @info:	Returns regmap for the device
+ * @return 0 if OK, -ve on error
+ */
+struct regmap *syscon_get_regmap(struct udevice *dev);
+
+/**
+ * syscon_get_regmap_by_driver_data() - Look up a controller by its ID
+ *
+ * Each system controller can be accessed by its driver data, which is
+ * assumed to be unique through the scope of all system controllers that
+ * are in use. This function looks up the regmap given this driver data.
+ *
+ * @driver_data:	Driver data value to look up
+ * @return register map correponding to @driver_data, or -ve error code
+ */
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data);
+
+/**
+ * syscon_get_first_range() - get the first memory range from a syscon regmap
+ *
+ * @driver_data:	Driver data value to look up
+ * @return first region of register map correponding to @driver_data, or
+ *			-ve error code
+ */
+void *syscon_get_first_range(ulong driver_data);
+
+#endif
diff --git a/include/test/ut.h b/include/test/ut.h
index 5e5aa6c..da7c1a9 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -9,6 +9,8 @@
 #ifndef __TEST_UT_H
 #define __TEST_UT_H
 
+#include <linux/err.h>
+
 struct unit_test_state;
 
 /**
@@ -101,6 +103,19 @@
 	}								\
 }
 
+/* Assert that a pointer is not an error pointer */
+#define ut_assertok_ptr(expr) {					\
+	const void *val = (expr);					\
+									\
+	if (IS_ERR(val)) {						\
+		ut_failf(uts, __FILE__, __LINE__, __func__,		\
+			 #expr " = NULL",				\
+			 "Expected pointer, got error %ld",		\
+			 PTR_ERR(val));					\
+		return CMD_RET_FAILURE;					\
+	}								\
+}
+
 /* Assert that an operation succeeds (returns 0) */
 #define ut_assertok(cond)	ut_asserteq(0, cond)
 
diff --git a/include/usb.h b/include/usb.h
index dca512d..cf00ffd 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -175,9 +175,9 @@
 int usb_lowlevel_stop(int index);
 
 #if defined(CONFIG_MUSB_HOST) || defined(CONFIG_DM_USB)
-int usb_reset_root_port(void);
+int usb_reset_root_port(struct usb_device *dev);
 #else
-#define usb_reset_root_port()
+#define usb_reset_root_port(dev)
 #endif
 
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
@@ -493,15 +493,31 @@
 
 /**
  * struct usb_driver_entry - Matches a driver to its usb_device_ids
- * @compatible: Compatible string
- * @data: Data for this compatible string
+ * @driver: Driver to use
+ * @match: List of match records for this driver, terminated by {}
  */
 struct usb_driver_entry {
 	struct driver *driver;
 	const struct usb_device_id *match;
 };
 
-#define USB_DEVICE(__name, __match)					\
+#define USB_DEVICE_ID_MATCH_DEVICE \
+		(USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+
+/**
+ * USB_DEVICE - macro used to describe a specific usb device
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific device.
+ */
+#define USB_DEVICE(vend, prod) \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+	.idVendor = (vend), \
+	.idProduct = (prod)
+
+#define U_BOOT_USB_DEVICE(__name, __match) \
 	ll_entry_declare(struct usb_driver_entry, __name, usb_driver_entry) = {\
 		.driver = llsym(struct driver, __name, driver), \
 		.match = __match, \
@@ -705,15 +721,16 @@
 	 * is read). This should be NULL for EHCI, which does not need this.
 	 */
 	int (*alloc_device)(struct udevice *bus, struct usb_device *udev);
+
+	/**
+	 * reset_root_port() - Reset usb root port
+	 */
+	int (*reset_root_port)(struct udevice *bus, struct usb_device *udev);
 };
 
 #define usb_get_ops(dev)	((struct dm_usb_ops *)(dev)->driver->ops)
 #define usb_get_emul_ops(dev)	((struct dm_usb_ops *)(dev)->driver->ops)
 
-#ifdef CONFIG_MUSB_HOST
-int usb_reset_root_port(void);
-#endif
-
 /**
  * usb_get_dev_index() - look up a device index number
  *
@@ -730,26 +747,18 @@
 struct usb_device *usb_get_dev_index(struct udevice *bus, int index);
 
 /**
- * usb_legacy_port_reset() - Legacy function to reset a hub port
- *
- * @hub:	Hub device
- * @portnr:	Port number (1=first)
- */
-int usb_legacy_port_reset(struct usb_device *hub, int portnr);
-
-/**
  * usb_setup_device() - set up a device ready for use
  *
  * @dev:	USB device pointer. This need not be a real device - it is
  *		common for it to just be a local variable with its ->dev
- *		member (i.e. @dev->dev) set to the parent device
+ *		member (i.e. @dev->dev) set to the parent device and
+ *		dev->portnr set to the port number on the hub (1=first)
  * @do_read:	true to read the device descriptor before an address is set
  *		(should be false for XHCI buses, true otherwise)
  * @parent:	Parent device (either UCLASS_USB or UCLASS_USB_HUB)
- * @portnr:	Port number on hub (1=first) or 0 for none
  * @return 0 if OK, -ve on error */
 int usb_setup_device(struct usb_device *dev, bool do_read,
-		     struct usb_device *parent, int portnr);
+		     struct usb_device *parent);
 
 /**
  * usb_hub_scan() - Scan a hub and find its devices
diff --git a/include/usb_ether.h b/include/usb_ether.h
index 23507e1..c6d1416 100644
--- a/include/usb_ether.h
+++ b/include/usb_ether.h
@@ -19,25 +19,91 @@
 #define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
 #define ETH_FRAME_LEN	PKTSIZE_ALIGN	/* Max. octets in frame sans FCS */
 
+/* TODO(sjg@chromium.org): Remove @pusb_dev when all boards use CONFIG_DM_ETH */
 struct ueth_data {
 	/* eth info */
-	struct eth_device eth_dev;		/* used with eth_register */
-	int phy_id;						/* mii phy id */
+#ifdef CONFIG_DM_ETH
+	uint8_t *rxbuf;
+	int rxsize;
+	int rxlen;			/* Total bytes available in rxbuf */
+	int rxptr;			/* Current position in rxbuf */
+#else
+	struct eth_device eth_dev;	/* used with eth_register */
+	/* driver private */
+	void *dev_priv;
+#endif
+	int phy_id;			/* mii phy id */
 
 	/* usb info */
 	struct usb_device *pusb_dev;	/* this usb_device */
-	unsigned char	ifnum;			/* interface number */
-	unsigned char	ep_in;			/* in endpoint */
-	unsigned char	ep_out;			/* out ....... */
-	unsigned char	ep_int;			/* interrupt . */
-	unsigned char	subclass;		/* as in overview */
-	unsigned char	protocol;		/* .............. */
+	unsigned char	ifnum;		/* interface number */
+	unsigned char	ep_in;		/* in endpoint */
+	unsigned char	ep_out;		/* out ....... */
+	unsigned char	ep_int;		/* interrupt . */
+	unsigned char	subclass;	/* as in overview */
+	unsigned char	protocol;	/* .............. */
 	unsigned char	irqinterval;	/* Intervall for IRQ Pipe */
-
-	/* driver private */
-	void *dev_priv;
 };
 
+#ifdef CONFIG_DM_ETH
+/**
+ * usb_ether_register() - register a new USB ethernet device
+ *
+ * This selects the correct USB interface and figures out the endpoints to use.
+ *
+ * @dev:	USB device
+ * @ss:		Place to put USB ethernet data
+ * @rxsize:	Maximum size to allocate for the receive buffer
+ * @return 0 if OK, -ve on error
+ */
+int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize);
+
+/**
+ * usb_ether_deregister() - deregister a USB ethernet device
+ *
+ * @ueth:	USB Ethernet device
+ * @return 0
+ */
+int usb_ether_deregister(struct ueth_data *ueth);
+
+/**
+ * usb_ether_receive() - recieve a packet from the bulk in endpoint
+ *
+ * The packet is stored in the internal buffer ready for processing.
+ *
+ * @ueth:	USB Ethernet device
+ * @rxsize:	Maximum size to receive
+ * @return 0 if a packet was received, -EAGAIN if not, -ENOSPC if @rxsize is
+ * larger than the size passed ot usb_ether_register(), other -ve on error
+ */
+int usb_ether_receive(struct ueth_data *ueth, int rxsize);
+
+/**
+ * usb_ether_get_rx_bytes() - obtain bytes from the internal packet buffer
+ *
+ * This should be called repeatedly to obtain packet data until it returns 0.
+ * After each packet is processed, call usb_ether_advance_rxbuf() to move to
+ * the next one.
+ *
+ * @ueth:	USB Ethernet device
+ * @ptrp:	Returns a pointer to the start of the next packet if there is
+ *		one available
+ * @return number of bytes available, or 0 if none
+ */
+int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp);
+
+/**
+ * usb_ether_advance_rxbuf() - Advance to the next packet in the internal buffer
+ *
+ * After processing the data returned by usb_ether_get_rx_bytes(), call this
+ * function to move to the next packet. You must specify the number of bytes
+ * you have processed in @num_bytes.
+ *
+ * @ueth:	USB Ethernet device
+ * @num_bytes:	Number of bytes to skip, or -1 to skip all bytes
+ */
+void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes);
+#else
 /*
  * Function definitions for each USB ethernet driver go here
  * (declaration is unconditional, compilation is conditional)
@@ -65,5 +131,6 @@
 			struct ueth_data *ss);
 int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
 			struct eth_device *eth);
+#endif
 
 #endif /* __USB_ETHER_H__ */
diff --git a/include/vsprintf.h b/include/vsprintf.h
index d2fcca3..b5bc9c1 100644
--- a/include/vsprintf.h
+++ b/include/vsprintf.h
@@ -41,6 +41,32 @@
 long simple_strtol(const char *cp, char **endp, unsigned int base);
 
 /**
+ * trailing_strtol() - extract a trailing integer from a string
+ *
+ * Given a string this finds a trailing number on the string and returns it.
+ * For example, "abc123" would return 123.
+ *
+ * @str:	String to exxamine
+ * @return training number if found, else -1
+ */
+long trailing_strtol(const char *str);
+
+/**
+ * trailing_strtoln() - extract a trailing integer from a fixed-length string
+ *
+ * Given a fixed-length string this finds a trailing number on the string
+ * and returns it. For example, "abc123" would return 123. Only the
+ * characters between @str and @end - 1 are examined. If @end is NULL, it is
+ * set to str + strlen(str).
+ *
+ * @str:	String to exxamine
+ * @end:	Pointer to end of string to examine, or NULL to use the
+ *		whole string
+ * @return training number if found, else -1
+ */
+long trailing_strtoln(const char *str, const char *end);
+
+/**
  * panic() - Print a message and reset/hang
  *
  * Prints a message on the console(s) and then resets. If CONFIG_PANIC_HANG is
diff --git a/lib/Kconfig b/lib/Kconfig
index c98d399..972ac17 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -50,6 +50,8 @@
 	help
 	  This library provides pseudo-random number generator functions.
 
+source lib/dhry/Kconfig
+
 source lib/rsa/Kconfig
 
 menu "Hashing Support"
diff --git a/lib/Makefile b/lib/Makefile
index 97ed398..fd106b9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -15,12 +15,15 @@
 obj-$(CONFIG_TIZEN) += tizen/
 obj-$(CONFIG_OF_LIBFDT) += libfdt/
 obj-$(CONFIG_FIT) += libfdt/
+obj-$(CONFIG_FIT) += libfdt/
+obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
 
 obj-$(CONFIG_AES) += aes.o
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
 obj-y += crc8.o
 obj-y += crc16.o
+obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-$(CONFIG_FIT) += fdtdec_common.o
 obj-$(CONFIG_OF_CONTROL) += fdtdec_common.o
 obj-$(CONFIG_OF_CONTROL) += fdtdec.o
@@ -34,6 +37,7 @@
 obj-y += net_utils.o
 obj-$(CONFIG_PHYSMEM) += physmem.o
 obj-y += qsort.o
+obj-y += rc4.o
 obj-$(CONFIG_SHA1) += sha1.o
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o
 obj-$(CONFIG_SHA256) += sha256.o
@@ -57,7 +61,6 @@
 obj-$(CONFIG_ADDR_MAP) += addr_map.o
 obj-y += hashtable.o
 obj-y += errno.o
-obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-y += display_options.o
 obj-$(CONFIG_BCH) += bch.o
 obj-y += crc32.o
diff --git a/lib/dhry/Kconfig b/lib/dhry/Kconfig
new file mode 100644
index 0000000..641b806
--- /dev/null
+++ b/lib/dhry/Kconfig
@@ -0,0 +1,7 @@
+config CMD_DHRYSTONE
+	bool "Support the 'dhry' command to run the dhrystone benchmark"
+	help
+	  Dhrystone is an old benchmark in the public domain that gives a
+	  rough idea of CPU performance. This enables a 'dhry' command
+	  which runs this benchmark within U-Boot and reports the performance.
+	  The number of 'Dhrystone MIPS' is also reported.
diff --git a/lib/dhry/Makefile b/lib/dhry/Makefile
new file mode 100644
index 0000000..926c0d6
--- /dev/null
+++ b/lib/dhry/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015 Google, Inc
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += cmd_dhry.o dhry_1.o dhry_2.o
diff --git a/lib/dhry/cmd_dhry.c b/lib/dhry/cmd_dhry.c
new file mode 100644
index 0000000..5dc191e
--- /dev/null
+++ b/lib/dhry/cmd_dhry.c
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include "dhry.h"
+
+static int do_dhry(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	ulong start, duration, dhry_per_sec, vax_mips;
+	int iterations = 1000000;
+
+	if (argc > 1)
+		iterations = simple_strtoul(argv[1], NULL, 10);
+
+	start = get_timer(0);
+	dhry(iterations);
+	duration = get_timer(start);
+	dhry_per_sec = iterations * 1000 / duration;
+	vax_mips = dhry_per_sec / 1757;
+	printf("%d iterations in %lu ms: %lu/s, %lu DMIPS\n", iterations,
+	       duration, dhry_per_sec, vax_mips);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	dhry,	2,	1,	do_dhry,
+	"[iterations] - run dhrystone benchmark",
+	"\n    - run the Dhrystone 2.1 benchmark, a rough measure of CPU speed\n"
+);
diff --git a/lib/dhry/dhry.h b/lib/dhry/dhry.h
new file mode 100644
index 0000000..49d4223
--- /dev/null
+++ b/lib/dhry/dhry.h
@@ -0,0 +1,442 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry.h   SID: 3.4 5/15/91 19:30:21
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *	Ben Smith, Rick Grehan or Tom Yager
+ *	ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *  Modification Log:
+ *  addapted from:
+ *
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry.h (part 1 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *                      Siemens AG, AUT E 51
+ *                      Postfach 3220
+ *                      8520 Erlangen
+ *                      Germany (West)
+ *                              Phone:  [+49]-9131-7-20330
+ *                                      (8-17 Central European Time)
+ *                              Usenet: ..!mcvax!unido!estevax!weicker
+ *
+ *              Original Version (in Ada) published in
+ *              "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
+ *              pp. 1013 - 1030, together with the statistics
+ *              on which the distribution of statements etc. is based.
+ *
+ *              In this C version, the following C library functions are used:
+ *              - strcpy, strcmp (inside the measurement loop)
+ *              - printf, scanf (outside the measurement loop)
+ *              In addition, Berkeley UNIX system calls "times ()" or "time ()"
+ *              are used for execution time measurement. For measurements
+ *              on other systems, these calls have to be changed.
+ *
+ *  Collection of Results:
+ *              Reinhold Weicker (address see above) and
+ *              
+ *              Rick Richardson
+ *              PC Research. Inc.
+ *              94 Apple Orchard Drive
+ *              Tinton Falls, NJ 07724
+ *                      Phone:  (201) 834-1378 (9-17 EST)               
+ *                      Usenet: ...!seismo!uunet!pcrat!rick
+ *
+ *      Please send results to Rick Richardson and/or Reinhold Weicker.
+ *      Complete information should be given on hardware and software used.
+ *      Hardware information includes: Machine type, CPU, type and size
+ *      of caches; for microprocessors: clock frequency, memory speed
+ *      (number of wait states).
+ *      Software information includes: Compiler (and runtime library)
+ *      manufacturer and version, compilation switches, OS version.
+ *      The Operating System version may give an indication about the
+ *      compiler; Dhrystone itself performs no OS calls in the measurement loop.
+ *
+ *      The complete output generated by the program should be mailed
+ *      such that at least some checks for correctness can be made.
+ *
+ ***************************************************************************
+ *
+ *  History:    This version C/2.1 has been made for two reasons:
+ *
+ *              1) There is an obvious need for a common C version of
+ *              Dhrystone, since C is at present the most popular system
+ *              programming language for the class of processors
+ *              (microcomputers, minicomputers) where Dhrystone is used most.
+ *              There should be, as far as possible, only one C version of
+ *              Dhrystone such that results can be compared without
+ *              restrictions. In the past, the C versions distributed
+ *              by Rick Richardson (Version 1.1) and by Reinhold Weicker
+ *              had small (though not significant) differences.
+ *
+ *              2) As far as it is possible without changes to the Dhrystone
+ *              statistics, optimizing compilers should be prevented from
+ *              removing significant statements.
+ *
+ *              This C version has been developed in cooperation with
+ *              Rick Richardson (Tinton Falls, NJ), it incorporates many
+ *              ideas from the "Version 1.1" distributed previously by
+ *              him over the UNIX network Usenet.
+ *              I also thank Chaim Benedelac (National Semiconductor),
+ *              David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
+ *              Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
+ *              for their help with comments on earlier versions of the
+ *              benchmark.
+ *
+ *  Changes:    In the initialization part, this version follows mostly
+ *              Rick Richardson's version distributed via Usenet, not the
+ *              version distributed earlier via floppy disk by Reinhold Weicker.
+ *              As a concession to older compilers, names have been made
+ *              unique within the first 8 characters.
+ *              Inside the measurement loop, this version follows the
+ *              version previously distributed by Reinhold Weicker.
+ *
+ *              At several places in the benchmark, code has been added,
+ *              but within the measurement loop only in branches that 
+ *              are not executed. The intention is that optimizing compilers
+ *              should be prevented from moving code out of the measurement
+ *              loop, or from removing code altogether. Since the statements
+ *              that are executed within the measurement loop have NOT been
+ *              changed, the numbers defining the "Dhrystone distribution"
+ *              (distribution of statements, operand types and locality)
+ *              still hold. Except for sophisticated optimizing compilers,
+ *              execution times for this version should be the same as
+ *              for previous versions.
+ *              
+ *              Since it has proven difficult to subtract the time for the
+ *              measurement loop overhead in a correct way, the loop check
+ *              has been made a part of the benchmark. This does have
+ *              an impact - though a very minor one - on the distribution
+ *              statistics which have been updated for this version.
+ *
+ *              All changes within the measurement loop are described
+ *              and discussed in the companion paper "Rationale for
+ *              Dhrystone version 2".
+ *
+ *              Because of the self-imposed limitation that the order and
+ *              distribution of the executed statements should not be
+ *              changed, there are still cases where optimizing compilers
+ *              may not generate code for some statements. To a certain
+ *              degree, this is unavoidable for small synthetic benchmarks.
+ *              Users of the benchmark are advised to check code listings
+ *              whether code is generated for all statements of Dhrystone.
+ *
+ *              Version 2.1 is identical to version 2.0 distributed via
+ *              the UNIX network Usenet in March 1988 except that it corrects
+ *              some minor deficiencies that were found by users of version 2.0.
+ *              The only change within the measurement loop is that a
+ *              non-executed "else" part was added to the "if" statement in
+ *              Func_3, and a non-executed "else" part removed from Proc_3.
+ *
+ ***************************************************************************
+ *
+ * Defines:     The following "Defines" are possible:
+ *              -DREG=register          (default: Not defined)
+ *                      As an approximation to what an average C programmer
+ *                      might do, the "register" storage class is applied
+ *                      (if enabled by -DREG=register)
+ *                      - for local variables, if they are used (dynamically)
+ *                        five or more times
+ *                      - for parameters if they are used (dynamically)
+ *                        six or more times
+ *                      Note that an optimal "register" strategy is
+ *                      compiler-dependent, and that "register" declarations
+ *                      do not necessarily lead to faster execution.
+ *              -DNOSTRUCTASSIGN        (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      assignment of structures.
+ *              -DNOENUMS               (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      enumeration types.
+ *              -DTIMES                 (default)
+ *              -DTIME
+ *                      The "times" function of UNIX (returning process times)
+ *                      or the "time" function (returning wallclock time)
+ *                      is used for measurement. 
+ *                      For single user machines, "time ()" is adequate. For
+ *                      multi-user machines where you cannot get single-user
+ *                      access, use the "times ()" function. If you have
+ *                      neither, use a stopwatch in the dead of night.
+ *                      "printf"s are provided marking the points "Start Timer"
+ *                      and "Stop Timer". DO NOT use the UNIX "time(1)"
+ *                      command, as this will measure the total time to
+ *                      run this program, which will (erroneously) include
+ *                      the time to allocate storage (malloc) and to perform
+ *                      the initialization.
+ *              -DHZ=nnn
+ *                      In Berkeley UNIX, the function "times" returns process
+ *                      time in 1/HZ seconds, with HZ = 60 for most systems.
+ *                      CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
+ *                      A VALUE.
+ *
+ ***************************************************************************
+ *
+ *  Compilation model and measurement (IMPORTANT):
+ *
+ *  This C version of Dhrystone consists of three files:
+ *  - dhry.h (this file, containing global definitions and comments)
+ *  - dhry_1.c (containing the code corresponding to Ada package Pack_1)
+ *  - dhry_2.c (containing the code corresponding to Ada package Pack_2)
+ *
+ *  The following "ground rules" apply for measurements:
+ *  - Separate compilation
+ *  - No procedure merging
+ *  - Otherwise, compiler optimizations are allowed but should be indicated
+ *  - Default results are those without register declarations
+ *  See the companion paper "Rationale for Dhrystone Version 2" for a more
+ *  detailed discussion of these ground rules.
+ *
+ *  For 16-Bit processors (e.g. 80186, 80286), times for all compilation
+ *  models ("small", "medium", "large" etc.) should be given if possible,
+ *  together with a definition of these models for the compiler system used.
+ *
+ **************************************************************************
+ *
+ *  Dhrystone (C version) statistics:
+ *
+ *  [Comment from the first distribution, updated for version 2.
+ *   Note that because of language differences, the numbers are slightly
+ *   different from the Ada version.]
+ *
+ *  The following program contains statements of a high level programming
+ *  language (here: C) in a distribution considered representative:           
+ *
+ *    assignments                  52 (51.0 %)
+ *    control statements           33 (32.4 %)
+ *    procedure, function calls    17 (16.7 %)
+ *
+ *  103 statements are dynamically executed. The program is balanced with
+ *  respect to the three aspects:                                             
+ *
+ *    - statement type
+ *    - operand type
+ *    - operand locality
+ *         operand global, local, parameter, or constant.                     
+ *
+ *  The combination of these three aspects is balanced only approximately.    
+ *
+ *  1. Statement Type:                                                        
+ *  -----------------             number
+ *
+ *     V1 = V2                     9
+ *       (incl. V1 = F(..)
+ *     V = Constant               12
+ *     Assignment,                 7
+ *       with array element
+ *     Assignment,                 6
+ *       with record component
+ *                                --
+ *                                34       34
+ *
+ *     X = Y +|-|"&&"|"|" Z        5
+ *     X = Y +|-|"==" Constant     6
+ *     X = X +|- 1                 3
+ *     X = Y *|/ Z                 2
+ *     X = Expression,             1
+ *           two operators
+ *     X = Expression,             1
+ *           three operators
+ *                                --
+ *                                18       18
+ *
+ *     if ....                    14
+ *       with "else"      7
+ *       without "else"   7
+ *           executed        3
+ *           not executed    4
+ *     for ...                     7  |  counted every time
+ *     while ...                   4  |  the loop condition
+ *     do ... while                1  |  is evaluated
+ *     switch ...                  1
+ *     break                       1
+ *     declaration with            1
+ *       initialization
+ *                                --
+ *                                34       34
+ *
+ *     P (...)  procedure call    11
+ *       user procedure      10
+ *       library procedure    1
+ *     X = F (...)
+ *             function  call      6
+ *       user function        5                                         
+ *       library function     1                                               
+ *                                --                                          
+ *                                17       17
+ *                                        ---
+ *                                        103
+ *
+ *    The average number of parameters in procedure or function calls
+ *    is 1.82 (not counting the function values as implicit parameters).
+ *
+ *
+ *  2. Operators
+ *  ------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *    Arithmetic             32          50.8                                 
+ *
+ *       +                     21          33.3                              
+ *       -                      7          11.1                              
+ *       *                      3           4.8
+ *       / (int div)            1           1.6
+ *
+ *    Comparison             27           42.8
+ *
+ *       ==                     9           14.3
+ *       /=                     4            6.3
+ *       >                      1            1.6
+ *       <                      3            4.8
+ *       >=                     1            1.6
+ *       <=                     9           14.3
+ *
+ *    Logic                   4            6.3
+ *
+ *       && (AND-THEN)          1            1.6
+ *       |  (OR)                1            1.6
+ *       !  (NOT)               2            3.2
+ * 
+ *                           --          -----
+ *                           63          100.1
+ *
+ *
+ *  3. Operand Type (counted once per operand reference):
+ *  ---------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *     Integer               175        72.3 %
+ *     Character              45        18.6 %
+ *     Pointer                12         5.0 %
+ *     String30                6         2.5 %
+ *     Array                   2         0.8 %
+ *     Record                  2         0.8 %
+ *                           ---       -------
+ *                           242       100.0 %
+ *
+ *  When there is an access path leading to the final operand (e.g. a record
+ *  component), only the final data type on the access path is counted.       
+ *
+ *
+ *  4. Operand Locality:                                                      
+ *  -------------------
+ *                                number    approximate
+ *                                          percentage
+ *
+ *     local variable              114        47.1 %
+ *     global variable              22         9.1 %
+ *     parameter                    45        18.6 %
+ *        value                        23         9.5 %
+ *        reference                    22         9.1 %
+ *     function result               6         2.5 %
+ *     constant                     55        22.7 %
+ *                                 ---       -------
+ *                                 242       100.0 %
+ *
+ *
+ *  The program does not compute anything meaningful, but it is syntactically
+ *  and semantically correct. All variables have a value assigned to them
+ *  before they are used as a source operand.
+ *
+ *  There has been no explicit effort to account for the effects of a
+ *  cache, or to balance the use of long or short displacements for code or
+ *  data.
+ *
+ ***************************************************************************
+ */
+
+
+/* Compiler and system dependent definitions: */
+
+#ifndef TIME
+#define TIMES
+#endif
+                /* Use times(2) time function unless    */
+                /* explicitly defined otherwise         */
+
+#define Mic_secs_Per_Second     1000000.0
+                /* Berkeley UNIX C returns process times in seconds/HZ */
+
+#ifdef  NOSTRUCTASSIGN
+#define structassign(d, s)      memcpy(&(d), &(s), sizeof(d))
+#else
+#define structassign(d, s)      d = s
+#endif
+
+#ifdef  NOENUM
+#define Ident_1 0
+#define Ident_2 1
+#define Ident_3 2
+#define Ident_4 3
+#define Ident_5 4
+  typedef int   Enumeration;
+#else
+  typedef       enum    {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
+                Enumeration;
+#endif
+        /* for boolean and enumeration types in Ada, Pascal */
+
+/* General definitions: */
+
+#define Null 0 
+                /* Value of a Null pointer */
+#define true  1
+#define false 0
+
+typedef int     One_Thirty;
+typedef int     One_Fifty;
+typedef char    Capital_Letter;
+typedef int     Boolean;
+typedef char    Str_30 [31];
+typedef int     Arr_1_Dim [50];
+typedef int     Arr_2_Dim [50] [50];
+
+typedef struct record 
+    {
+    struct record *Ptr_Comp;
+    Enumeration    Discr;
+    union {
+          struct {
+                  Enumeration Enum_Comp;
+                  int         Int_Comp;
+                  char        Str_Comp [31];
+                  } var_1;
+          struct {
+                  Enumeration E_Comp_2;
+                  char        Str_2_Comp [31];
+                  } var_2;
+          struct {
+                  char        Ch_1_Comp;
+                  char        Ch_2_Comp;
+                  } var_3;
+          } variant;
+      } Rec_Type, *Rec_Pointer;
+
+
+/*
+ * dhry() - run dhrystone for a given number of iterations
+ *
+ * @iterations:	Number of iterations to run
+ */
+void dhry(int iterations);
diff --git a/lib/dhry/dhry_1.c b/lib/dhry/dhry_1.c
new file mode 100644
index 0000000..be63710
--- /dev/null
+++ b/lib/dhry/dhry_1.c
@@ -0,0 +1,421 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry_1.c   SID: 3.4 5/15/91 19:30:21
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *	Ben Smith, Rick Grehan or Tom Yager
+ *	ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *
+ * *** WARNING ****  With BYTE's modifications applied, results obtained with
+ *     *******       this version of the Dhrystone program may not be applicable
+ *                   to other versions.
+ *                  
+ *  Modification Log:
+ *  10/22/97 - code cleanup to remove ANSI C compiler warnings
+ *             Andy Kahn <kahn@zk3.dec.com>
+ *
+ *  Adapted from:
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry_1.c (part 2 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ***************************************************************************/
+char SCCSid[] = "@(#) @(#)dhry_1.c:3.4 -- 5/15/91 19:30:21";
+
+#include <common.h>
+#include <malloc.h>
+
+#include "dhry.h"
+
+unsigned long Run_Index;
+
+void report(void)
+{
+	printf("%ld loops\n", Run_Index);
+}
+
+/* Global Variables: */
+
+Rec_Pointer     Ptr_Glob,
+                Next_Ptr_Glob;
+int             Int_Glob;
+Boolean         Bool_Glob;
+char            Ch_1_Glob,
+                Ch_2_Glob;
+int             Arr_1_Glob [50];
+int             Arr_2_Glob [50] [50];
+
+Enumeration     Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val);
+  /* forward declaration necessary since Enumeration may not simply be int */
+
+#ifndef REG
+        Boolean Reg = false;
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#else
+        Boolean Reg = true;
+#endif
+
+/* variables for time measurement: */
+
+#ifdef TIMES
+#define Too_Small_Time 120
+                /* Measurements should last at least about 2 seconds */
+#endif
+#ifdef TIME
+extern long     time();
+                /* see library function "time"  */
+#define Too_Small_Time 2
+                /* Measurements should last at least 2 seconds */
+#endif
+
+long            Begin_Time,
+                End_Time,
+                User_Time;
+
+/* end of variables for time measurement */
+
+void Proc_1 (REG Rec_Pointer Ptr_Val_Par);
+void Proc_2 (One_Fifty   *Int_Par_Ref);
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par);
+void Proc_4 (void);
+void Proc_5 (void);
+
+
+extern Boolean Func_2(Str_30, Str_30);
+extern void Proc_6(Enumeration, Enumeration *);
+extern void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
+extern void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
+
+void dhry(int Number_Of_Runs)
+  /* main program, corresponds to procedures        */
+  /* Main and Proc_0 in the Ada version             */
+{
+        One_Fifty       Int_1_Loc;
+  REG   One_Fifty       Int_2_Loc;
+        One_Fifty       Int_3_Loc;
+  REG   char            Ch_Index;
+        Enumeration     Enum_Loc;
+        Str_30          Str_1_Loc;
+        Str_30          Str_2_Loc;
+
+  /* Initializations */
+
+  Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+  Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+
+  Ptr_Glob->Ptr_Comp                    = Next_Ptr_Glob;
+  Ptr_Glob->Discr                       = Ident_1;
+  Ptr_Glob->variant.var_1.Enum_Comp     = Ident_3;
+  Ptr_Glob->variant.var_1.Int_Comp      = 40;
+  strcpy (Ptr_Glob->variant.var_1.Str_Comp, 
+          "DHRYSTONE PROGRAM, SOME STRING");
+  strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+
+  Arr_2_Glob [8][7] = 10;
+        /* Was missing in published program. Without this statement,    */
+        /* Arr_2_Glob [8][7] would have an undefined value.             */
+        /* Warning: With 16-Bit processors and Number_Of_Runs > 32000,  */
+        /* overflow may occur for this array element.                   */
+
+#ifdef PRATTLE
+  printf ("\n");
+  printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+  printf ("\n");
+  if (Reg)
+  {
+    printf ("Program compiled with 'register' attribute\n");
+    printf ("\n");
+  }
+  else
+  {
+    printf ("Program compiled without 'register' attribute\n");
+    printf ("\n");
+  }
+  printf ("Please give the number of runs through the benchmark: ");
+  {
+    int n;
+    scanf ("%d", &n);
+    Number_Of_Runs = n;
+  }
+  printf ("\n");
+
+  printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
+#endif /* PRATTLE */
+
+  Run_Index = 0;
+
+  /***************/
+  /* Start timer */
+  /***************/
+ 
+#ifdef SELF_TIMED
+#ifdef TIMES
+  times (&time_info);
+  Begin_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  Begin_Time = time ( (long *) 0);
+#endif
+#endif /* SELF_TIMED */
+
+  for (Run_Index = 1; Run_Index < Number_Of_Runs; ++Run_Index)
+  {
+
+    Proc_5();
+    Proc_4();
+      /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+    Int_1_Loc = 2;
+    Int_2_Loc = 3;
+    strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+    Enum_Loc = Ident_2;
+    Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
+      /* Bool_Glob == 1 */
+    while (Int_1_Loc < Int_2_Loc)  /* loop body executed once */
+    {
+      Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+        /* Int_3_Loc == 7 */
+      Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+        /* Int_3_Loc == 7 */
+      Int_1_Loc += 1;
+    } /* while */
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+      /* Int_Glob == 5 */
+    Proc_1 (Ptr_Glob);
+    for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
+                             /* loop body executed twice */
+    {
+      if (Enum_Loc == Func_1 (Ch_Index, 'C'))
+          /* then, not executed */
+        {
+        Proc_6 (Ident_1, &Enum_Loc);
+        strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+        Int_2_Loc = Run_Index;
+        Int_Glob = Run_Index;
+        }
+    }
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Int_2_Loc = Int_2_Loc * Int_1_Loc;
+    Int_1_Loc = Int_2_Loc / Int_3_Loc;
+    Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+      /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+    Proc_2 (&Int_1_Loc);
+      /* Int_1_Loc == 5 */
+
+  } /* loop "for Run_Index" */
+
+  /**************/
+  /* Stop timer */
+  /**************/
+#ifdef SELF_TIMED 
+#ifdef TIMES
+  times (&time_info);
+  End_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  End_Time = time ( (long *) 0);
+#endif
+#endif /* SELF_TIMED */
+
+  /* BYTE version never executes this stuff */
+#ifdef SELF_TIMED
+  printf ("Execution ends\n");
+  printf ("\n");
+  printf ("Final values of the variables used in the benchmark:\n");
+  printf ("\n");
+  printf ("Int_Glob:            %d\n", Int_Glob);
+  printf ("        should be:   %d\n", 5);
+  printf ("Bool_Glob:           %d\n", Bool_Glob);
+  printf ("        should be:   %d\n", 1);
+  printf ("Ch_1_Glob:           %c\n", Ch_1_Glob);
+  printf ("        should be:   %c\n", 'A');
+  printf ("Ch_2_Glob:           %c\n", Ch_2_Glob);
+  printf ("        should be:   %c\n", 'B');
+  printf ("Arr_1_Glob[8]:       %d\n", Arr_1_Glob[8]);
+  printf ("        should be:   %d\n", 7);
+  printf ("Arr_2_Glob[8][7]:    %d\n", Arr_2_Glob[8][7]);
+  printf ("        should be:   Number_Of_Runs + 10\n");
+  printf ("Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent)\n");
+  printf ("  Discr:             %d\n", Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 2);
+  printf ("  Int_Comp:          %d\n", Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 17);
+  printf ("  Str_Comp:          %s\n", Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Next_Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent), same as above\n");
+  printf ("  Discr:             %d\n", Next_Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 1);
+  printf ("  Int_Comp:          %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 18);
+  printf ("  Str_Comp:          %s\n",
+                                Next_Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Int_1_Loc:           %d\n", Int_1_Loc);
+  printf ("        should be:   %d\n", 5);
+  printf ("Int_2_Loc:           %d\n", Int_2_Loc);
+  printf ("        should be:   %d\n", 13);
+  printf ("Int_3_Loc:           %d\n", Int_3_Loc);
+  printf ("        should be:   %d\n", 7);
+  printf ("Enum_Loc:            %d\n", Enum_Loc);
+  printf ("        should be:   %d\n", 1);
+  printf ("Str_1_Loc:           %s\n", Str_1_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 1'ST STRING\n");
+  printf ("Str_2_Loc:           %s\n", Str_2_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 2'ND STRING\n");
+  printf ("\n");
+
+  User_Time = End_Time - Begin_Time;
+
+  if (User_Time < Too_Small_Time)
+  {
+    printf ("Measured time too small to obtain meaningful results\n");
+    printf ("Please increase number of runs\n");
+    printf ("\n");
+  }
+  else
+  {
+#ifdef TIME
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / (float) Number_Of_Runs;
+    Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
+#else
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / ((float) HZ * ((float) Number_Of_Runs));
+    Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
+                        / (float) User_Time;
+#endif
+    printf ("Microseconds for one run through Dhrystone: ");
+    printf ("%6.1f \n", Microseconds);
+    printf ("Dhrystones per Second:                      ");
+    printf ("%6.1f \n", Dhrystones_Per_Second);
+    printf ("\n");
+  }
+#endif /* SELF_TIMED */
+}
+
+
+void Proc_1 (REG Rec_Pointer Ptr_Val_Par)
+    /* executed once */
+{
+  REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;  
+                                        /* == Ptr_Glob_Next */
+  /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp,    */
+  /* corresponds to "rename" in Ada, "with" in Pascal           */
+  
+  structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); 
+  Ptr_Val_Par->variant.var_1.Int_Comp = 5;
+  Next_Record->variant.var_1.Int_Comp 
+        = Ptr_Val_Par->variant.var_1.Int_Comp;
+  Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
+  Proc_3 (&Next_Record->Ptr_Comp);
+    /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp 
+                        == Ptr_Glob->Ptr_Comp */
+  if (Next_Record->Discr == Ident_1)
+    /* then, executed */
+  {
+    Next_Record->variant.var_1.Int_Comp = 6;
+    Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, 
+           &Next_Record->variant.var_1.Enum_Comp);
+    Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
+    Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, 
+           &Next_Record->variant.var_1.Int_Comp);
+  }
+  else /* not executed */
+    structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
+} /* Proc_1 */
+
+
+void Proc_2 (One_Fifty   *Int_Par_Ref)
+    /* executed once */
+    /* *Int_Par_Ref == 1, becomes 4 */
+{
+  One_Fifty  Int_Loc;  
+  Enumeration   Enum_Loc;
+
+  Enum_Loc = 0;
+
+  Int_Loc = *Int_Par_Ref + 10;
+  do /* executed once */
+    if (Ch_1_Glob == 'A')
+      /* then, executed */
+    {
+      Int_Loc -= 1;
+      *Int_Par_Ref = Int_Loc - Int_Glob;
+      Enum_Loc = Ident_1;
+    } /* if */
+  while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par)
+    /* executed once */
+    /* Ptr_Ref_Par becomes Ptr_Glob */
+{
+  if (Ptr_Glob != Null)
+    /* then, executed */
+    *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
+  Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+
+void Proc_4 (void) /* without parameters */
+    /* executed once */
+{
+  Boolean Bool_Loc;
+
+  Bool_Loc = Ch_1_Glob == 'A';
+  Bool_Glob = Bool_Loc | Bool_Glob;
+  Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+void Proc_5 (void) /* without parameters */
+/*******/
+    /* executed once */
+{
+  Ch_1_Glob = 'A';
+  Bool_Glob = false;
+} /* Proc_5 */
+
+
+        /* Procedure for the assignment of structures,          */
+        /* if the C compiler doesn't support this feature       */
+#ifdef  NOSTRUCTASSIGN
+memcpy (d, s, l)
+register char   *d;
+register char   *s;
+register int    l;
+{
+        while (l--) *d++ = *s++;
+}
+#endif
diff --git a/lib/dhry/dhry_2.c b/lib/dhry/dhry_2.c
new file mode 100644
index 0000000..59aa458
--- /dev/null
+++ b/lib/dhry/dhry_2.c
@@ -0,0 +1,217 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry_2.c   SID: 3.4 5/15/91 19:30:22
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *	Ben Smith, Rick Grehan or Tom Yager
+ *	ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *  Modification Log:
+ *  10/22/97 - code cleanup to remove ANSI C compiler warnings
+ *             Andy Kahn <kahn@zk3.dec.com>
+ *
+ *  Adapted from:
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ * **** WARNING **** See warning in n.dhry_1.c
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry_2.c (part 3 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************/
+/* SCCSid is defined in dhry_1.c */
+
+#include <common.h>
+#include "dhry.h"
+
+#ifndef REG
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#endif
+
+extern  int     Int_Glob;
+extern  char    Ch_1_Glob;
+
+void Proc_6(Enumeration, Enumeration *);
+void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
+void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
+Enumeration Func_1(Capital_Letter, Capital_Letter);
+Boolean Func_2(Str_30, Str_30);
+Boolean Func_3(Enumeration);
+
+void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par)
+    /* executed once */
+    /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
+{
+  *Enum_Ref_Par = Enum_Val_Par;
+  if (! Func_3 (Enum_Val_Par))
+    /* then, not executed */
+    *Enum_Ref_Par = Ident_4;
+  switch (Enum_Val_Par)
+  {
+    case Ident_1: 
+      *Enum_Ref_Par = Ident_1;
+      break;
+    case Ident_2: 
+      if (Int_Glob > 100)
+        /* then */
+      *Enum_Ref_Par = Ident_1;
+      else *Enum_Ref_Par = Ident_4;
+      break;
+    case Ident_3: /* executed */
+      *Enum_Ref_Par = Ident_2;
+      break;
+    case Ident_4: break;
+    case Ident_5: 
+      *Enum_Ref_Par = Ident_3;
+      break;
+  } /* switch */
+} /* Proc_6 */
+
+void Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
+One_Fifty       Int_1_Par_Val;
+One_Fifty       Int_2_Par_Val;
+One_Fifty      *Int_Par_Ref;
+/**********************************************/
+    /* executed three times                                      */ 
+    /* first call:      Int_1_Par_Val == 2, Int_2_Par_Val == 3,  */
+    /*                  Int_Par_Ref becomes 7                    */
+    /* second call:     Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
+    /*                  Int_Par_Ref becomes 17                   */
+    /* third call:      Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
+    /*                  Int_Par_Ref becomes 18                   */
+{
+  One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 2;
+  *Int_Par_Ref = Int_2_Par_Val + Int_Loc;
+} /* Proc_7 */
+
+
+void Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
+/*********************************************************************/
+    /* executed once      */
+    /* Int_Par_Val_1 == 3 */
+    /* Int_Par_Val_2 == 7 */
+Arr_1_Dim       Arr_1_Par_Ref;
+Arr_2_Dim       Arr_2_Par_Ref;
+int             Int_1_Par_Val;
+int             Int_2_Par_Val;
+{
+  REG One_Fifty Int_Index;
+  REG One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 5;
+  Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
+  Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
+  Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
+  for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
+    Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
+  Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
+  Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
+  Int_Glob = 5;
+} /* Proc_8 */
+
+
+Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
+/*************************************************/
+    /* executed three times                                         */
+    /* first call:      Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R'    */
+    /* second call:     Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C'    */
+    /* third call:      Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C'    */
+{
+  Capital_Letter        Ch_1_Loc;
+  Capital_Letter        Ch_2_Loc;
+
+  Ch_1_Loc = Ch_1_Par_Val;
+  Ch_2_Loc = Ch_1_Loc;
+  if (Ch_2_Loc != Ch_2_Par_Val)
+    /* then, executed */
+    return (Ident_1);
+  else  /* not executed */
+  {
+    Ch_1_Glob = Ch_1_Loc;
+    return (Ident_2);
+   }
+} /* Func_1 */
+
+
+
+Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
+/*************************************************/
+    /* executed once */
+    /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
+    /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
+
+Str_30  Str_1_Par_Ref;
+Str_30  Str_2_Par_Ref;
+{
+  REG One_Thirty        Int_Loc;
+      Capital_Letter    Ch_Loc;
+
+  Ch_Loc = 'A';
+  Int_Loc = 2;
+  while (Int_Loc <= 2) /* loop body executed once */
+    if (Func_1 (Str_1_Par_Ref[Int_Loc],
+                Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
+      /* then, executed */
+    {
+      Ch_Loc = 'A';
+      Int_Loc += 1;
+    } /* if, while */
+  if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
+    /* then, not executed */
+    Int_Loc = 7;
+  if (Ch_Loc == 'R')
+    /* then, not executed */
+    return (true);
+  else /* executed */
+  {
+    if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
+      /* then, not executed */
+    {
+      Int_Loc += 7;
+      Int_Glob = Int_Loc;
+      return (true);
+    }
+    else /* executed */
+      return (false);
+  } /* if Ch_Loc */
+} /* Func_2 */
+
+
+Boolean Func_3 (Enum_Par_Val)
+/***************************/
+    /* executed once        */
+    /* Enum_Par_Val == Ident_3 */
+Enumeration Enum_Par_Val;
+{
+  Enumeration Enum_Loc;
+
+  Enum_Loc = Enum_Par_Val;
+  if (Enum_Loc == Ident_3)
+    /* then, executed */
+    return (true);
+  else /* not executed */
+    return (false);
+} /* Func_3 */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 9c6b361..232ca74 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -505,8 +505,7 @@
 		const char *prop;
 		const char *name;
 		const char *slash;
-		const char *p;
-		int len;
+		int len, val;
 
 		prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
 		debug("   - %s, %s\n", name, prop);
@@ -517,12 +516,11 @@
 		slash = strrchr(prop, '/');
 		if (strcmp(slash + 1, find_name))
 			continue;
-		for (p = name + strlen(name) - 1; p > name; p--) {
-			if (!isdigit(*p)) {
-				*seqp = simple_strtoul(p + 1, NULL, 10);
-				debug("Found seq %d\n", *seqp);
-				return 0;
-			}
+		val = trailing_strtol(name);
+		if (val != -1) {
+			*seqp = val;
+			debug("Found seq %d\n", *seqp);
+			return 0;
 		}
 	}
 
@@ -570,6 +568,13 @@
 		puts("Missing DTB\n");
 #else
 		puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+# ifdef DEBUG
+		if (gd->fdt_blob) {
+			printf("fdt_blob=%p\n", gd->fdt_blob);
+			print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
+				     32, 0);
+		}
+# endif
 #endif
 		return -1;
 	}
diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile
index 2f5413f..934d614 100644
--- a/lib/libfdt/Makefile
+++ b/lib/libfdt/Makefile
@@ -6,4 +6,4 @@
 #
 
 obj-y += fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o fdt_wip.o \
-	fdt_empty_tree.o fdt_addresses.o
+	fdt_empty_tree.o fdt_addresses.o fdt_region.o
diff --git a/lib/libfdt/fdt_region.c b/lib/libfdt/fdt_region.c
new file mode 100644
index 0000000..9fea775
--- /dev/null
+++ b/lib/libfdt/fdt_region.c
@@ -0,0 +1,492 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2013 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * SPDX-License-Identifier:	GPL-2.0+ BSD-2-Clause
+ */
+
+#include "libfdt_env.h"
+
+#ifndef USE_HOSTCC
+#include <fdt.h>
+#include <libfdt.h>
+#else
+#include "fdt_host.h"
+#endif
+
+#include "libfdt_internal.h"
+
+/**
+ * fdt_add_region() - Add a new region to our list
+ *
+ * The region is added if there is space, but in any case we increment the
+ * count. If permitted, and the new region overlaps the last one, we merge
+ * them.
+ *
+ * @info: State information
+ * @offset: Start offset of region
+ * @size: Size of region
+ */
+static int fdt_add_region(struct fdt_region_state *info, int offset, int size)
+{
+	struct fdt_region *reg;
+
+	reg = info->region ? &info->region[info->count - 1] : NULL;
+	if (info->can_merge && info->count &&
+	    info->count <= info->max_regions &&
+	    reg && offset <= reg->offset + reg->size) {
+		reg->size = offset + size - reg->offset;
+	} else if (info->count++ < info->max_regions) {
+		if (reg) {
+			reg++;
+			reg->offset = offset;
+			reg->size = size;
+		}
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int region_list_contains_offset(struct fdt_region_state *info,
+				       const void *fdt, int target)
+{
+	struct fdt_region *reg;
+	int num;
+
+	target += fdt_off_dt_struct(fdt);
+	for (reg = info->region, num = 0; num < info->count; reg++, num++) {
+		if (target >= reg->offset && target < reg->offset + reg->size)
+			return 1;
+	}
+
+	return 0;
+}
+
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+			  int max_regions, struct fdt_region_state *info)
+{
+	int base = fdt_off_dt_struct(fdt);
+	int node, node_end, offset;
+	int did_alias_header;
+
+	node = fdt_subnode_offset(fdt, 0, "aliases");
+	if (node < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	/* The aliases node must come before the others */
+	node_end = fdt_next_subnode(fdt, node);
+	if (node_end <= 0)
+		return -FDT_ERR_BADLAYOUT;
+	node_end -= sizeof(fdt32_t);
+
+	did_alias_header = 0;
+	info->region = region;
+	info->count = count;
+	info->can_merge = 0;
+	info->max_regions = max_regions;
+
+	for (offset = fdt_first_property_offset(fdt, node);
+	     offset >= 0;
+	     offset = fdt_next_property_offset(fdt, offset)) {
+		const struct fdt_property *prop;
+		const char *name;
+		int target, next;
+
+		prop = fdt_get_property_by_offset(fdt, offset, NULL);
+		name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+		target = fdt_path_offset(fdt, name);
+		if (!region_list_contains_offset(info, fdt, target))
+			continue;
+		next = fdt_next_property_offset(fdt, offset);
+		if (next < 0)
+			next = node_end - sizeof(fdt32_t);
+
+		if (!did_alias_header) {
+			fdt_add_region(info, base + node, 12);
+			did_alias_header = 1;
+		}
+		fdt_add_region(info, base + offset, next - offset);
+	}
+
+	/* Add the 'end' tag */
+	if (did_alias_header)
+		fdt_add_region(info, base + node_end, sizeof(fdt32_t));
+
+	return info->count < max_regions ? info->count : -FDT_ERR_NOSPACE;
+}
+
+/**
+ * fdt_include_supernodes() - Include supernodes required by this node
+ *
+ * When we decided to include a node or property which is not at the top
+ * level, this function forces the inclusion of higher level nodes. For
+ * example, given this tree:
+ *
+ * / {
+ *     testing {
+ *     }
+ * }
+ *
+ * If we decide to include testing then we need the root node to have a valid
+ * tree. This function adds those regions.
+ *
+ * @info: State information
+ * @depth: Current stack depth
+ */
+static int fdt_include_supernodes(struct fdt_region_state *info, int depth)
+{
+	int base = fdt_off_dt_struct(info->fdt);
+	int start, stop_at;
+	int i;
+
+	/*
+	 * Work down the stack looking for supernodes that we didn't include.
+	 * The algortihm here is actually pretty simple, since we know that
+	 * no previous subnode had to include these nodes, or if it did, we
+	 * marked them as included (on the stack) already.
+	 */
+	for (i = 0; i <= depth; i++) {
+		if (!info->stack[i].included) {
+			start = info->stack[i].offset;
+
+			/* Add the FDT_BEGIN_NODE tag of this supernode */
+			fdt_next_tag(info->fdt, start, &stop_at);
+			if (fdt_add_region(info, base + start, stop_at - start))
+				return -1;
+
+			/* Remember that this supernode is now included */
+			info->stack[i].included = 1;
+			info->can_merge = 1;
+		}
+
+		/* Force (later) generation of the FDT_END_NODE tag */
+		if (!info->stack[i].want)
+			info->stack[i].want = WANT_NODES_ONLY;
+	}
+
+	return 0;
+}
+
+enum {
+	FDT_DONE_NOTHING,
+	FDT_DONE_MEM_RSVMAP,
+	FDT_DONE_STRUCT,
+	FDT_DONE_END,
+	FDT_DONE_STRINGS,
+	FDT_DONE_ALL,
+};
+
+int fdt_first_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info)
+{
+	struct fdt_region_ptrs *p = &info->ptrs;
+
+	/* Set up our state */
+	info->fdt = fdt;
+	info->can_merge = 1;
+	info->max_regions = 1;
+	info->start = -1;
+	p->want = WANT_NOTHING;
+	p->end = path;
+	*p->end = '\0';
+	p->nextoffset = 0;
+	p->depth = -1;
+	p->done = FDT_DONE_NOTHING;
+
+	return fdt_next_region(fdt, h_include, priv, region,
+			       path, path_len, flags, info);
+}
+
+/*
+ * Theory of operation
+ *
+ *
+ *
+
+Note: in this description 'included' means that a node (or other part of
+the tree) should be included in the region list, i.e. it will have a region
+which covers its part of the tree.
+
+This function maintains some state from the last time it is called. It
+checks the next part of the tree that it is supposed to look at
+(p.nextoffset) to see if that should be included or not. When it finds
+something to include, it sets info->start to its offset. This marks the
+start of the region we want to include.
+
+Once info->start is set to the start (i.e. not -1), we continue scanning
+until we find something that we don't want included. This will be the end
+of a region. At this point we can close off the region and add it to the
+list. So we do so, and reset info->start to -1.
+
+One complication here is that we want to merge regions. So when we come to
+add another region later, we may in fact merge it with the previous one if
+one ends where the other starts.
+
+The function fdt_add_region() will return -1 if it fails to add the region,
+because we already have a region ready to be returned, and the new one
+cannot be merged in with it. In this case, we must return the region we
+found, and wait for another call to this function. When it comes, we will
+repeat the processing of the tag and again try to add a region. This time it
+will succeed.
+
+The current state of the pointers (stack, offset, etc.) is maintained in
+a ptrs member. At the start of every loop iteration we make a copy of it.
+The copy is then updated as the tag is processed. Only if we get to the end
+of the loop iteration (and successfully call fdt_add_region() if we need
+to) can we commit the changes we have made to these pointers. For example,
+if we see an FDT_END_NODE tag we will decrement the depth value. But if we
+need to add a region for this tag (let's say because the previous tag is
+included and this FDT_END_NODE tag is not included) then we will only commit
+the result if we were able to add the region. That allows us to retry again
+next time.
+
+We keep track of a variable called 'want' which tells us what we want to
+include when there is no specific information provided by the h_include
+function for a particular property. This basically handles the inclusion of
+properties which are pulled in by virtue of the node they are in. So if you
+include a node, its properties are also included. In this case 'want' will
+be WANT_NODES_AND_PROPS. The FDT_REG_DIRECT_SUBNODES feature also makes use
+of 'want'. While we are inside the subnode, 'want' will be set to
+WANT_NODES_ONLY, so that only the subnode's FDT_BEGIN_NODE and FDT_END_NODE
+tags will be included, and properties will be skipped. If WANT_NOTHING is
+selected, then we will just rely on what the h_include() function tells us.
+
+Using 'want' we work out 'include', which tells us whether this current tag
+should be included or not. As you can imagine, if the value of 'include'
+changes, that means we are on a boundary between nodes to include and nodes
+to exclude. At this point we either close off a previous region and add it
+to the list, or mark the start of a new region.
+
+Apart from the nodes, we have mem_rsvmap, the FDT_END tag and the string
+list. Each of these dealt with as a whole (i.e. we create a region for each
+if it is to be included). For mem_rsvmap we don't allow it to merge with
+the first struct region. For the stringlist we don't allow it to merge with
+the last struct region (which contains at minimum the FDT_END tag).
+*/
+int fdt_next_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info)
+{
+	int base = fdt_off_dt_struct(fdt);
+	int last_node = 0;
+	const char *str;
+
+	info->region = region;
+	info->count = 0;
+	if (info->ptrs.done < FDT_DONE_MEM_RSVMAP &&
+	    (flags & FDT_REG_ADD_MEM_RSVMAP)) {
+		/* Add the memory reserve map into its own region */
+		if (fdt_add_region(info, fdt_off_mem_rsvmap(fdt),
+				   fdt_off_dt_struct(fdt) -
+				   fdt_off_mem_rsvmap(fdt)))
+			return 0;
+		info->can_merge = 0;	/* Don't allow merging with this */
+		info->ptrs.done = FDT_DONE_MEM_RSVMAP;
+	}
+
+	/*
+	 * Work through the tags one by one, deciding whether each needs to
+	 * be included or not. We set the variable 'include' to indicate our
+	 * decision. 'want' is used to track what we want to include - it
+	 * allows us to pick up all the properties (and/or subnode tags) of
+	 * a node.
+	 */
+	while (info->ptrs.done < FDT_DONE_STRUCT) {
+		const struct fdt_property *prop;
+		struct fdt_region_ptrs p;
+		const char *name;
+		int include = 0;
+		int stop_at = 0;
+		uint32_t tag;
+		int offset;
+		int val;
+		int len;
+
+		/*
+		 * Make a copy of our pointers. If we make it to the end of
+		 * this block then we will commit them back to info->ptrs.
+		 * Otherwise we can try again from the same starting state
+		 * next time we are called.
+		 */
+		p = info->ptrs;
+
+		/*
+		 * Find the tag, and the offset of the next one. If we need to
+		 * stop including tags, then by default we stop *after*
+		 * including the current tag
+		 */
+		offset = p.nextoffset;
+		tag = fdt_next_tag(fdt, offset, &p.nextoffset);
+		stop_at = p.nextoffset;
+
+		switch (tag) {
+		case FDT_PROP:
+			stop_at = offset;
+			prop = fdt_get_property_by_offset(fdt, offset, NULL);
+			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+			val = h_include(priv, fdt, last_node, FDT_IS_PROP, str,
+					    strlen(str) + 1);
+			if (val == -1) {
+				include = p.want >= WANT_NODES_AND_PROPS;
+			} else {
+				include = val;
+				/*
+				 * Make sure we include the } for this block.
+				 * It might be more correct to have this done
+				 * by the call to fdt_include_supernodes() in
+				 * the case where it adds the node we are
+				 * currently in, but this is equivalent.
+				 */
+				if ((flags & FDT_REG_SUPERNODES) && val &&
+				    !p.want)
+					p.want = WANT_NODES_ONLY;
+			}
+
+			/* Value grepping is not yet supported */
+			break;
+
+		case FDT_NOP:
+			include = p.want >= WANT_NODES_AND_PROPS;
+			stop_at = offset;
+			break;
+
+		case FDT_BEGIN_NODE:
+			last_node = offset;
+			p.depth++;
+			if (p.depth == FDT_MAX_DEPTH)
+				return -FDT_ERR_TOODEEP;
+			name = fdt_get_name(fdt, offset, &len);
+			if (p.end - path + 2 + len >= path_len)
+				return -FDT_ERR_NOSPACE;
+
+			/* Build the full path of this node */
+			if (p.end != path + 1)
+				*p.end++ = '/';
+			strcpy(p.end, name);
+			p.end += len;
+			info->stack[p.depth].want = p.want;
+			info->stack[p.depth].offset = offset;
+
+			/*
+			 * If we are not intending to include this node unless
+			 * it matches, make sure we stop *before* its tag.
+			 */
+			if (p.want == WANT_NODES_ONLY ||
+			    !(flags & (FDT_REG_DIRECT_SUBNODES |
+				       FDT_REG_ALL_SUBNODES))) {
+				stop_at = offset;
+				p.want = WANT_NOTHING;
+			}
+			val = h_include(priv, fdt, offset, FDT_IS_NODE, path,
+					p.end - path + 1);
+
+			/* Include this if requested */
+			if (val) {
+				p.want = (flags & FDT_REG_ALL_SUBNODES) ?
+					WANT_ALL_NODES_AND_PROPS :
+					WANT_NODES_AND_PROPS;
+			}
+
+			/* If not requested, decay our 'p.want' value */
+			else if (p.want) {
+				if (p.want != WANT_ALL_NODES_AND_PROPS)
+					p.want--;
+
+			/* Not including this tag, so stop now */
+			} else {
+				stop_at = offset;
+			}
+
+			/*
+			 * Decide whether to include this tag, and update our
+			 * stack with the state for this node
+			 */
+			include = p.want;
+			info->stack[p.depth].included = include;
+			break;
+
+		case FDT_END_NODE:
+			include = p.want;
+			if (p.depth < 0)
+				return -FDT_ERR_BADSTRUCTURE;
+
+			/*
+			 * If we don't want this node, stop right away, unless
+			 * we are including subnodes
+			 */
+			if (!p.want && !(flags & FDT_REG_DIRECT_SUBNODES))
+				stop_at = offset;
+			p.want = info->stack[p.depth].want;
+			p.depth--;
+			while (p.end > path && *--p.end != '/')
+				;
+			*p.end = '\0';
+			break;
+
+		case FDT_END:
+			/* We always include the end tag */
+			include = 1;
+			p.done = FDT_DONE_STRUCT;
+			break;
+		}
+
+		/* If this tag is to be included, mark it as region start */
+		if (include && info->start == -1) {
+			/* Include any supernodes required by this one */
+			if (flags & FDT_REG_SUPERNODES) {
+				if (fdt_include_supernodes(info, p.depth))
+					return 0;
+			}
+			info->start = offset;
+		}
+
+		/*
+		 * If this tag is not to be included, finish up the current
+		 * region.
+		 */
+		if (!include && info->start != -1) {
+			if (fdt_add_region(info, base + info->start,
+					   stop_at - info->start))
+				return 0;
+			info->start = -1;
+			info->can_merge = 1;
+		}
+
+		/* If we have made it this far, we can commit our pointers */
+		info->ptrs = p;
+	}
+
+	/* Add a region for the END tag and a separate one for string table */
+	if (info->ptrs.done < FDT_DONE_END) {
+		if (info->ptrs.nextoffset != fdt_size_dt_struct(fdt))
+			return -FDT_ERR_BADSTRUCTURE;
+
+		if (fdt_add_region(info, base + info->start,
+				   info->ptrs.nextoffset - info->start))
+			return 0;
+		info->ptrs.done++;
+	}
+	if (info->ptrs.done < FDT_DONE_STRINGS) {
+		if (flags & FDT_REG_ADD_STRING_TAB) {
+			info->can_merge = 0;
+			if (fdt_off_dt_strings(fdt) <
+			    base + info->ptrs.nextoffset)
+				return -FDT_ERR_BADLAYOUT;
+			if (fdt_add_region(info, fdt_off_dt_strings(fdt),
+					   fdt_size_dt_strings(fdt)))
+				return 0;
+		}
+		info->ptrs.done++;
+	}
+
+	return info->count > 0 ? 0 : -FDT_ERR_NOTFOUND;
+}
diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c
index bec8b8a..1a358a8 100644
--- a/lib/libfdt/fdt_rw.c
+++ b/lib/libfdt/fdt_rw.c
@@ -449,3 +449,35 @@
 
 	return 0;
 }
+
+int fdt_remove_unused_strings(const void *old, void *new)
+{
+	const struct fdt_property *old_prop;
+	struct fdt_property *new_prop;
+	int size = fdt_totalsize(old);
+	int next_offset, offset;
+	const char *str;
+	int ret;
+	int tag = FDT_PROP;
+
+	/* Make a copy and remove the strings */
+	memcpy(new, old, size);
+	fdt_set_size_dt_strings(new, 0);
+
+	/* Add every property name back into the new string table */
+	for (offset = 0; tag != FDT_END; offset = next_offset) {
+		tag = fdt_next_tag(old, offset, &next_offset);
+		if (tag != FDT_PROP)
+			continue;
+		old_prop = fdt_get_property_by_offset(old, offset, NULL);
+		new_prop = (struct fdt_property *)(unsigned long)
+			fdt_get_property_by_offset(new, offset, NULL);
+		str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff));
+		ret = _fdt_find_add_string(new, str);
+		if (ret < 0)
+			return ret;
+		new_prop->nameoff = cpu_to_fdt32(ret);
+	}
+
+	return 0;
+}
diff --git a/lib/linux_compat.c b/lib/linux_compat.c
index a3d4675..a936a7e 100644
--- a/lib/linux_compat.c
+++ b/lib/linux_compat.c
@@ -16,19 +16,13 @@
 
 void *kmalloc(size_t size, int flags)
 {
-	return memalign(ARCH_DMA_MINALIGN, size);
-}
+	void *p;
 
-void *kzalloc(size_t size, int flags)
-{
-	void *ptr = kmalloc(size, flags);
-	memset(ptr, 0, size);
-	return ptr;
-}
+	p = memalign(ARCH_DMA_MINALIGN, size);
+	if (flags & __GFP_ZERO)
+		memset(p, 0, size);
 
-void *vzalloc(unsigned long size)
-{
-	return kzalloc(size, 0);
+	return p;
 }
 
 struct kmem_cache *get_mem(int element_sz)
diff --git a/lib/rc4.c b/lib/rc4.c
new file mode 100644
index 0000000..89d15f3
--- /dev/null
+++ b/lib/rc4.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ *
+ * Rivest Cipher 4 (RC4) implementation
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#endif
+#include <rc4.h>
+
+void rc4_encode(unsigned char *buf, unsigned int len, unsigned char key[16])
+{
+	unsigned char s[256], k[256], temp;
+	unsigned short i, j, t;
+	int ptr;
+
+	j = 0;
+	for (i = 0; i < 256; i++) {
+		s[i] = (unsigned char)i;
+		j &= 0x0f;
+		k[i] = key[j];
+		j++;
+	}
+
+	j = 0;
+	for (i = 0; i < 256; i++) {
+		j = (j + s[i] + k[i]) % 256;
+		temp = s[i];
+		s[i] = s[j];
+		s[j] = temp;
+	}
+
+	i = 0;
+	j = 0;
+	for (ptr = 0; ptr < len; ptr++) {
+		i = (i + 1) % 256;
+		j = (j + s[i]) % 256;
+		temp = s[i];
+		s[i] = s[j];
+		s[j] = temp;
+		t = (s[i] + (s[j] % 256)) % 256;
+		buf[ptr] = buf[ptr] ^ s[t];
+	}
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a9b8a3a..4c82837 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -166,6 +166,25 @@
 	return result;
 }
 
+long trailing_strtoln(const char *str, const char *end)
+{
+	const char *p;
+
+	if (!end)
+		end = str + strlen(str);
+	for (p = end - 1; p > str; p--) {
+		if (!isdigit(*p))
+			return simple_strtoul(p + 1, NULL, 10);
+	}
+
+	return -1;
+}
+
+long trailing_strtol(const char *str)
+{
+	return trailing_strtoln(str, NULL);
+}
+
 /* we use this so that we can do without the ctype library */
 #define is_digit(c)	((c) >= '0' && (c) <= '9')
 
diff --git a/net/eth.c b/net/eth.c
index 953b731..d3ec8d6 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -287,7 +287,13 @@
 			return -EINVAL;
 		}
 
+		/*
+		 * Drivers are allowed to decide not to implement this at
+		 * run-time. E.g. Some devices may use it and some may not.
+		 */
 		ret = eth_get_ops(dev)->write_hwaddr(dev);
+		if (ret == -ENOSYS)
+			ret = 0;
 		if (ret)
 			printf("\nWarning: %s failed to set MAC address\n",
 			       dev->name);
@@ -404,6 +410,7 @@
 {
 	struct udevice *current;
 	uchar *packet;
+	int flags;
 	int ret;
 	int i;
 
@@ -415,8 +422,10 @@
 		return -EINVAL;
 
 	/* Process up to 32 packets at one time */
+	flags = ETH_RECV_CHECK_DEVICE;
 	for (i = 0; i < 32; i++) {
-		ret = eth_get_ops(current)->recv(current, &packet);
+		ret = eth_get_ops(current)->recv(current, flags, &packet);
+		flags = 0;
 		if (ret > 0)
 			net_process_received_packet(packet, ret);
 		if (ret >= 0 && eth_get_ops(current)->free_pkt)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index fd572f4..b1047b5 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -54,18 +54,22 @@
 libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
 libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/
 libs-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/
+libs-$(CONFIG_SPL_CLK_SUPPORT) += drivers/clk/
 libs-$(CONFIG_SPL_DM) += drivers/core/
 libs-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/
 libs-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/
 libs-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/
 libs-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += drivers/ddr/fsl/
-libs-$(CONFIG_SYS_MVEBU_DDR) += drivers/ddr/mvebu/
+libs-$(CONFIG_SYS_MVEBU_DDR_A38X) += drivers/ddr/marvell/a38x/
+libs-$(CONFIG_SYS_MVEBU_DDR_AXP) += drivers/ddr/marvell/axp/
 libs-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/
 libs-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/
 libs-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/
 libs-y += fs/
+libs-$(CONFIG_SPL_LED_SUPPORT) += drivers/led/
 libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/
 libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/ drivers/power/pmic/
+libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/regulator/
 libs-$(CONFIG_SPL_MTD_SUPPORT) += drivers/mtd/
 libs-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/
 libs-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += drivers/misc/
@@ -76,6 +80,7 @@
 libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/
 libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/
 libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/
+libs-$(CONFIG_SPL_RAM_SUPPORT) += drivers/ram/
 libs-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/
 libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/
 libs-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/
@@ -151,6 +156,8 @@
 
 ALL-y	+= $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).cfg
 
+ALL-$(CONFIG_OF_SEPARATE) += $(obj)/$(SPL_BIN)-pad.bin $(obj)/$(SPL_BIN)-dtb.bin
+
 ifdef CONFIG_SAMSUNG
 ALL-y	+= $(obj)/$(BOARD)-spl.bin
 endif
@@ -165,6 +172,32 @@
 
 all:	$(ALL-y)
 
+quiet_cmd_cat = CAT     $@
+cmd_cat = cat $(filter-out $(PHONY), $^) > $@
+
+$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN)-pad.bin \
+		$(obj)/$(SPL_BIN).dtb FORCE
+	$(call if_changed,cat)
+
+# Create a file that pads from the end of u-boot-spl.bin to bss_end
+$(obj)/$(SPL_BIN)-pad.bin: $(obj)/$(SPL_BIN)
+	@bss_size_str=$(shell $(NM) $< | awk 'BEGIN {size = 0} /__bss_size/ {size = $$1} END {print "ibase=16; " toupper(size)}' | bc); \
+	dd if=/dev/zero of=$@ bs=1 count=$${bss_size_str} 2>/dev/null;
+
+# Pass the original device tree file through fdtgrep twice. The first pass
+# removes any unwanted nodes (i.e. those which don't have the
+# 'u-boot,dm-pre-reloc' property and thus are not needed by SPL. The second
+# pass removes various unused properties from the remaining nodes.
+# The output is typically a much smaller device tree file.
+quiet_cmd_fdtgrep = FDTGREP $@
+      cmd_fdtgrep = $(objtree)/tools/fdtgrep -b u-boot,dm-pre-reloc -RT $< \
+		-n /chosen -O dtb | \
+	$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
+		$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
+
+$(obj)/$(SPL_BIN).dtb: dts/dt.dtb
+	$(call cmd,fdtgrep)
+
 quiet_cmd_cpp_cfg = CFG     $@
 cmd_cpp_cfg = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \
 	-DDO_DEPS_ONLY -D__ASSEMBLY__ -x assembler-with-cpp -P -dM -E -o $@ $<
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 19ad2fb..eda9643 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -15,13 +15,20 @@
 # subsystem you must add sandbox tests here.
 obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
+obj-$(CONFIG_CLK) += clk.o
 obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_I2C) += i2c.o
+obj-$(CONFIG_LED) += led.o
+obj-$(CONFIG_DM_MMC) += mmc.o
 obj-$(CONFIG_DM_PCI) += pci.o
+obj-$(CONFIG_RAM) += ram.o
+obj-y += regmap.o
+obj-$(CONFIG_RESET) += reset.o
 obj-$(CONFIG_DM_RTC) += rtc.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_DM_SPI) += spi.o
+obj-y += syscon.o
 obj-$(CONFIG_DM_USB) += usb.o
 obj-$(CONFIG_DM_PMIC) += pmic.o
 obj-$(CONFIG_DM_REGULATOR) += regulator.o
diff --git a/test/dm/clk.c b/test/dm/clk.c
new file mode 100644
index 0000000..9ff6d95
--- /dev/null
+++ b/test/dm/clk.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <linux/err.h>
+#include <test/ut.h>
+
+/* Test that we can find and adjust clocks */
+static int dm_test_clk_base(struct unit_test_state *uts)
+{
+	struct udevice *clk;
+	ulong rate;
+
+	ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
+	rate = clk_get_rate(clk);
+	ut_asserteq(SANDBOX_CLK_RATE, rate);
+	ut_asserteq(-EINVAL, clk_set_rate(clk, 0));
+	ut_assertok(clk_set_rate(clk, rate * 2));
+	ut_asserteq(SANDBOX_CLK_RATE * 2, clk_get_rate(clk));
+
+	return 0;
+}
+DM_TEST(dm_test_clk_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that peripheral clocks work as expected */
+static int dm_test_clk_periph(struct unit_test_state *uts)
+{
+	struct udevice *clk;
+	ulong rate;
+
+	ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
+	rate = clk_set_periph_rate(clk, PERIPH_ID_COUNT, 123);
+	ut_asserteq(-EINVAL, rate);
+	ut_asserteq(1, IS_ERR_VALUE(rate));
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 123);
+	ut_asserteq(0, rate);
+	ut_asserteq(123, clk_get_periph_rate(clk, PERIPH_ID_SPI));
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
+	ut_asserteq(123, rate);
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_I2C, 567);
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
+	ut_asserteq(1234, rate);
+
+	ut_asserteq(567, clk_get_periph_rate(clk, PERIPH_ID_I2C));
+
+	return 0;
+}
+DM_TEST(dm_test_clk_periph, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 5bb2a99..5c501ec 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -14,96 +14,20 @@
 #include <errno.h>
 #include <asm/io.h>
 #include <dm/root.h>
-#include <dm/uclass-internal.h>
-
-static void show_devices(struct udevice *dev, int depth, int last_flag)
-{
-	int i, is_last;
-	struct udevice *child;
-	char class_name[12];
-
-	/* print the first 11 characters to not break the tree-format. */
-	strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
-	printf(" %-11s [ %c ]    ", class_name,
-	       dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
-
-	for (i = depth; i >= 0; i--) {
-		is_last = (last_flag >> i) & 1;
-		if (i) {
-			if (is_last)
-				printf("    ");
-			else
-				printf("|   ");
-		} else {
-			if (is_last)
-				printf("`-- ");
-			else
-				printf("|-- ");
-		}
-	}
-
-	printf("%s\n", dev->name);
-
-	list_for_each_entry(child, &dev->child_head, sibling_node) {
-		is_last = list_is_last(&child->sibling_node, &dev->child_head);
-		show_devices(child, depth + 1, (last_flag << 1) | is_last);
-	}
-}
+#include <dm/util.h>
 
 static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc,
 			  char * const argv[])
 {
-	struct udevice *root;
-
-	root = dm_root();
-	if (root) {
-		printf(" Class       Probed   Name\n");
-		printf("----------------------------------------\n");
-		show_devices(root, -1, 0);
-	}
+	dm_dump_all();
 
 	return 0;
 }
 
-/**
- * dm_display_line() - Display information about a single device
- *
- * Displays a single line of information with an option prefix
- *
- * @dev:	Device to display
- */
-static void dm_display_line(struct udevice *dev)
-{
-	printf("- %c %s @ %08lx",
-	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
-	       dev->name, (ulong)map_to_sysmem(dev));
-	if (dev->seq != -1 || dev->req_seq != -1)
-		printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
-	puts("\n");
-}
-
 static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
 			     char * const argv[])
 {
-	struct uclass *uc;
-	int ret;
-	int id;
-
-	for (id = 0; id < UCLASS_COUNT; id++) {
-		struct udevice *dev;
-
-		ret = uclass_get(id, &uc);
-		if (ret)
-			continue;
-
-		printf("uclass %d: %s\n", id, uc->uc_drv->name);
-		if (list_empty(&uc->dev_head))
-			continue;
-		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
-			dm_display_line(dev);
-		}
-		puts("\n");
-	}
+	dm_dump_uclass();
 
 	return 0;
 }
diff --git a/test/dm/led.c b/test/dm/led.c
new file mode 100644
index 0000000..8ee075c
--- /dev/null
+++ b/test/dm/led.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <led.h>
+#include <asm/gpio.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of the led uclass */
+static int dm_test_led_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	/* Get the top-level device */
+	ut_assertok(uclass_get_device(UCLASS_LED, 0, &dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 2, &dev));
+	ut_asserteq(-ENODEV, uclass_get_device(UCLASS_LED, 3, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_led_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test of the led uclass using the led_gpio driver */
+static int dm_test_led_gpio(struct unit_test_state *uts)
+{
+	const int offset = 1;
+	struct udevice *dev, *gpio;
+
+	/*
+	 * Check that we can manipulate an LED. LED 1 is connected to GPIO
+	 * bank gpio_a, offset 1.
+	 */
+	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
+	ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+	led_set_on(dev, 1);
+	ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
+	led_set_on(dev, 0);
+	ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+
+	return 0;
+}
+DM_TEST(dm_test_led_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test obtaining an LED by label */
+static int dm_test_led_label(struct unit_test_state *uts)
+{
+	struct udevice *dev, *cmp;
+
+	ut_assertok(led_get_by_label("sandbox:red", &dev));
+	ut_asserteq(1, device_active(dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 1, &cmp));
+	ut_asserteq_ptr(dev, cmp);
+
+	ut_assertok(led_get_by_label("sandbox:green", &dev));
+	ut_asserteq(1, device_active(dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 2, &cmp));
+	ut_asserteq_ptr(dev, cmp);
+
+	ut_asserteq(-ENODEV, led_get_by_label("sandbox:blue", &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_led_label, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/mmc.c b/test/dm/mmc.c
new file mode 100644
index 0000000..0461423
--- /dev/null
+++ b/test/dm/mmc.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mmc.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Basic test of the mmc uclass. We could expand this by implementing an MMC
+ * stack for sandbox, or at least implementing the basic operation.
+ */
+static int dm_test_mmc_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_mmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/ram.c b/test/dm/ram.c
new file mode 100644
index 0000000..3a7c5ff
--- /dev/null
+++ b/test/dm/ram.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Basic test of the ram uclass */
+static int dm_test_ram_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct ram_info info;
+
+	ut_assertok(uclass_get_device(UCLASS_RAM, 0, &dev));
+	ut_assertok(ram_get_info(dev, &info));
+	ut_asserteq(0, info.base);
+	ut_asserteq(gd->ram_size, info.size);
+
+	return 0;
+}
+DM_TEST(dm_test_ram_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/regmap.c b/test/dm/regmap.c
new file mode 100644
index 0000000..7f66058
--- /dev/null
+++ b/test/dm/regmap.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+2 *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of register maps */
+static int dm_test_regmap_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct regmap *map;
+	int i;
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
+	map = syscon_get_regmap(dev);
+	ut_assertok_ptr(map);
+	ut_asserteq(1, map->range_count);
+	ut_asserteq(0x10, map->base);
+	ut_asserteq(0x10, map->range->start);
+	ut_asserteq(4, map->range->size);
+	ut_asserteq_ptr(&map->base_range, map->range);
+	ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0)));
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
+	map = syscon_get_regmap(dev);
+	ut_assertok_ptr(map);
+	ut_asserteq(4, map->range_count);
+	ut_asserteq(0x20, map->base);
+	ut_assert(&map->base_range != map->range);
+	for (i = 0; i < 4; i++) {
+		const unsigned long addr = 0x20 + 8 * i;
+
+		ut_asserteq(addr, map->range[i].start);
+		ut_asserteq(5 + i, map->range[i].size);
+		ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i)));
+	}
+
+	/* Check that we can't pretend a different device is a syscon */
+	ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev));
+	map = syscon_get_regmap(dev);
+	ut_asserteq_ptr(ERR_PTR(-ENOEXEC), map);
+
+	return 0;
+}
+DM_TEST(dm_test_regmap_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test we can access a regmap through syscon */
+static int dm_test_regmap_syscon(struct unit_test_state *uts)
+{
+	struct regmap *map;
+
+	map = syscon_get_regmap_by_driver_data(SYSCON0);
+	ut_assertok_ptr(map);
+	ut_asserteq(1, map->range_count);
+
+	map = syscon_get_regmap_by_driver_data(SYSCON1);
+	ut_assertok_ptr(map);
+	ut_asserteq(4, map->range_count);
+
+	map = syscon_get_regmap_by_driver_data(SYSCON_COUNT);
+	ut_asserteq_ptr(ERR_PTR(-ENODEV), map);
+
+	ut_asserteq(0x10, map_to_sysmem(syscon_get_first_range(SYSCON0)));
+	ut_asserteq(0x20, map_to_sysmem(syscon_get_first_range(SYSCON1)));
+	ut_asserteq_ptr(ERR_PTR(-ENODEV),
+			syscon_get_first_range(SYSCON_COUNT));
+
+	return 0;
+}
+
+DM_TEST(dm_test_regmap_syscon, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/regulator.c b/test/dm/regulator.c
index d279c04..3d0056f 100644
--- a/test/dm/regulator.c
+++ b/test/dm/regulator.c
@@ -210,7 +210,7 @@
 	 * Expected output state: uV=1200000; uA=200000; output enabled
 	 */
 	platname = regulator_names[BUCK1][PLATNAME];
-	ut_assertok(regulator_autoset(platname, &dev_autoset, false));
+	ut_assertok(regulator_autoset_by_name(platname, &dev_autoset));
 
 	/* Check, that the returned device is proper */
 	ut_assertok(regulator_get_by_platname(platname, &dev));
diff --git a/test/dm/reset.c b/test/dm/reset.c
new file mode 100644
index 0000000..5d53f25
--- /dev/null
+++ b/test/dm/reset.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset.h>
+#include <asm/state.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Test that we can use particular reset devices */
+static int dm_test_reset_base(struct unit_test_state *uts)
+{
+	struct sandbox_state *state = state_get_current();
+	struct udevice *dev;
+
+	/* Device 0 is the platform data device - it should never respond */
+	ut_assertok(uclass_get_device(UCLASS_RESET, 0, &dev));
+	ut_asserteq(-ENODEV, reset_request(dev, RESET_WARM));
+	ut_asserteq(-ENODEV, reset_request(dev, RESET_COLD));
+	ut_asserteq(-ENODEV, reset_request(dev, RESET_POWER));
+
+	/* Device 1 is the warm reset device */
+	ut_assertok(uclass_get_device(UCLASS_RESET, 1, &dev));
+	ut_asserteq(-EACCES, reset_request(dev, RESET_WARM));
+	ut_asserteq(-ENOSYS, reset_request(dev, RESET_COLD));
+	ut_asserteq(-ENOSYS, reset_request(dev, RESET_POWER));
+
+	state->reset_allowed[RESET_WARM] = true;
+	ut_asserteq(-EINPROGRESS, reset_request(dev, RESET_WARM));
+	state->reset_allowed[RESET_WARM] = false;
+
+	/* Device 2 is the cold reset device */
+	ut_assertok(uclass_get_device(UCLASS_RESET, 2, &dev));
+	ut_asserteq(-ENOSYS, reset_request(dev, RESET_WARM));
+	ut_asserteq(-EACCES, reset_request(dev, RESET_COLD));
+	state->reset_allowed[RESET_POWER] = false;
+	ut_asserteq(-EACCES, reset_request(dev, RESET_POWER));
+	state->reset_allowed[RESET_POWER] = true;
+
+	return 0;
+}
+DM_TEST(dm_test_reset_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that we can walk through the reset devices */
+static int dm_test_reset_walk(struct unit_test_state *uts)
+{
+	struct sandbox_state *state = state_get_current();
+
+	/* If we generate a power reset, we will exit sandbox! */
+	state->reset_allowed[RESET_POWER] = false;
+	ut_asserteq(-EACCES, reset_walk(RESET_WARM));
+	ut_asserteq(-EACCES, reset_walk(RESET_COLD));
+	ut_asserteq(-EACCES, reset_walk(RESET_POWER));
+
+	/*
+	 * Enable cold reset - this should make cold reset work, plus a warm
+	 * reset should be promoted to cold, since this is the next step
+	 * along.
+	 */
+	state->reset_allowed[RESET_COLD] = true;
+	ut_asserteq(-EINPROGRESS, reset_walk(RESET_WARM));
+	ut_asserteq(-EINPROGRESS, reset_walk(RESET_COLD));
+	ut_asserteq(-EACCES, reset_walk(RESET_POWER));
+	state->reset_allowed[RESET_COLD] = false;
+	state->reset_allowed[RESET_POWER] = true;
+
+	return 0;
+}
+DM_TEST(dm_test_reset_walk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/syscon.c b/test/dm/syscon.c
new file mode 100644
index 0000000..3642481
--- /dev/null
+++ b/test/dm/syscon.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of system controllers */
+static int dm_test_syscon_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
+	ut_asserteq(SYSCON0, dev->driver_data);
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
+	ut_asserteq(SYSCON1, dev->driver_data);
+
+	ut_asserteq(-ENODEV, uclass_get_device(UCLASS_SYSCON, 2, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_syscon_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-main.c b/test/dm/test-main.c
index 0477d2f..0e43ab9 100644
--- a/test/dm/test-main.c
+++ b/test/dm/test-main.c
@@ -76,6 +76,7 @@
 	struct unit_test_state *uts = &global_dm_test_state;
 	uts->priv = &_global_priv_dm_test_state;
 	struct unit_test *test;
+	int run_count;
 
 	/*
 	 * If we have no device tree, or it only has a root node, then these
@@ -90,10 +91,17 @@
 	if (!test_name)
 		printf("Running %d driver model tests\n", n_ents);
 
+	run_count = 0;
 	for (test = tests; test < tests + n_ents; test++) {
-		if (test_name && strcmp(test_name, test->name))
+		const char *name = test->name;
+
+		/* All tests have this prefix */
+		if (!strncmp(name, "dm_test_", 8))
+			name += 8;
+		if (test_name && strcmp(test_name, name))
 			continue;
 		printf("Test: %s\n", test->name);
+		run_count++;
 		ut_assertok(dm_test_init(uts));
 
 		uts->start = mallinfo();
@@ -109,7 +117,10 @@
 		ut_assertok(dm_test_destroy(uts));
 	}
 
-	printf("Failures: %d\n", uts->fail_count);
+	if (test_name && !run_count)
+		printf("Test '%s' not found\n", test_name);
+	else
+		printf("Failures: %d\n", uts->fail_count);
 
 	gd->dm_root = NULL;
 	ut_assertok(dm_init());
diff --git a/tools/Makefile b/tools/Makefile
index 8ff9c2e..db55bcf 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -58,7 +58,8 @@
 FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o
 # Flattened device tree objects
 LIBFDT_OBJS := $(addprefix lib/libfdt/, \
-			fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o)
+			fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o \
+			fdt_region.o)
 RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \
 					rsa-sign.o rsa-verify.o rsa-checksum.o \
 					rsa-mod-exp.o)
@@ -116,8 +117,8 @@
 HOST_EXTRACFLAGS	+= -DCONFIG_FIT_SIGNATURE
 endif
 
-ifdef CONFIG_SYS_SPI_U_BOOT_OFFS
-HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_SPI_U_BOOT_OFFS=$(CONFIG_SYS_SPI_U_BOOT_OFFS)
+ifdef CONFIG_SYS_U_BOOT_OFFS
+HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_U_BOOT_OFFS=$(CONFIG_SYS_U_BOOT_OFFS)
 endif
 
 # MXSImage needs LibSSL
@@ -155,6 +156,9 @@
 hostprogs-y += proftool
 hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela
 
+hostprogs-y += fdtgrep
+fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o
+
 # We build some files with extra pedantic flags to try to minimize things
 # that won't build on some weird host compiler -- though there are lots of
 # exceptions for files that aren't complaint.
diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c
new file mode 100644
index 0000000..caaf600
--- /dev/null
+++ b/tools/fdtgrep.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Perform a grep of an FDT either displaying the source subset or producing
+ * a new .dtb subset which can be used as required.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <../include/libfdt.h>
+#include <libfdt_internal.h>
+
+/* Define DEBUG to get some debugging output on stderr */
+#ifdef DEBUG
+#define debug(a, b...) fprintf(stderr, a, ## b)
+#else
+#define debug(a, b...)
+#endif
+
+/* A linked list of values we are grepping for */
+struct value_node {
+	int type;		/* Types this value matches (FDT_IS... mask) */
+	int include;		/* 1 to include matches, 0 to exclude */
+	const char *string;	/* String to match */
+	struct value_node *next;	/* Pointer to next node, or NULL */
+};
+
+/* Output formats we support */
+enum output_t {
+	OUT_DTS,		/* Device tree source */
+	OUT_DTB,		/* Valid device tree binary */
+	OUT_BIN,		/* Fragment of .dtb, for hashing */
+};
+
+/* Holds information which controls our output and options */
+struct display_info {
+	enum output_t output;	/* Output format */
+	int add_aliases;	/* Add aliases node to output */
+	int all;		/* Display all properties/nodes */
+	int colour;		/* Display output in ANSI colour */
+	int region_list;	/* Output a region list */
+	int flags;		/* Flags (FDT_REG_...) */
+	int list_strings;	/* List strings in string table */
+	int show_offset;	/* Show offset */
+	int show_addr;		/* Show address */
+	int header;		/* Output an FDT header */
+	int diff;		/* Show +/- diff markers */
+	int include_root;	/* Include the root node and all properties */
+	int remove_strings;	/* Remove unused strings */
+	int show_dts_version;	/* Put '/dts-v1/;' on the first line */
+	int types_inc;		/* Mask of types that we include (FDT_IS...) */
+	int types_exc;		/* Mask of types that we exclude (FDT_IS...) */
+	int invert;		/* Invert polarity of match */
+	struct value_node *value_head;	/* List of values to match */
+	const char *output_fname;	/* Output filename */
+	FILE *fout;		/* File to write dts/dtb output */
+};
+
+static void report_error(const char *where, int err)
+{
+	fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
+}
+
+/* Supported ANSI colours */
+enum {
+	COL_BLACK,
+	COL_RED,
+	COL_GREEN,
+	COL_YELLOW,
+	COL_BLUE,
+	COL_MAGENTA,
+	COL_CYAN,
+	COL_WHITE,
+
+	COL_NONE = -1,
+};
+
+/**
+ * print_ansi_colour() - Print out the ANSI sequence for a colour
+ *
+ * @fout:	Output file
+ * @col:	Colour to output (COL_...), or COL_NONE to reset colour
+ */
+static void print_ansi_colour(FILE *fout, int col)
+{
+	if (col == COL_NONE)
+		fprintf(fout, "\033[0m");
+	else
+		fprintf(fout, "\033[1;%dm", col + 30);
+}
+
+
+/**
+ * value_add() - Add a new value to our list of things to grep for
+ *
+ * @disp:	Display structure, holding info about our options
+ * @headp:	Pointer to header pointer of list
+ * @type:	Type of this value (FDT_IS_...)
+ * @include:	1 if we want to include matches, 0 to exclude
+ * @str:	String value to match
+ */
+static int value_add(struct display_info *disp, struct value_node **headp,
+		     int type, int include, const char *str)
+{
+	struct value_node *node;
+
+	/*
+	 * Keep track of which types we are excluding/including. We don't
+	 * allow both including and excluding things, because it doesn't make
+	 * sense. 'Including' means that everything not mentioned is
+	 * excluded. 'Excluding' means that everything not mentioned is
+	 * included. So using the two together would be meaningless.
+	 */
+	if (include)
+		disp->types_inc |= type;
+	else
+		disp->types_exc |= type;
+	if (disp->types_inc & disp->types_exc & type) {
+		fprintf(stderr,
+			"Cannot use both include and exclude for '%s'\n", str);
+		return -1;
+	}
+
+	str = strdup(str);
+	node = malloc(sizeof(*node));
+	if (!str || !node) {
+		fprintf(stderr, "Out of memory\n");
+		return -1;
+	}
+	node->next = *headp;
+	node->type = type;
+	node->include = include;
+	node->string = str;
+	*headp = node;
+
+	return 0;
+}
+
+static bool util_is_printable_string(const void *data, int len)
+{
+	const char *s = data;
+	const char *ss, *se;
+
+	/* zero length is not */
+	if (len == 0)
+		return 0;
+
+	/* must terminate with zero */
+	if (s[len - 1] != '\0')
+		return 0;
+
+	se = s + len;
+
+	while (s < se) {
+		ss = s;
+		while (s < se && *s && isprint((unsigned char)*s))
+			s++;
+
+		/* not zero, or not done yet */
+		if (*s != '\0' || s == ss)
+			return 0;
+
+		s++;
+	}
+
+	return 1;
+}
+
+static void utilfdt_print_data(const char *data, int len)
+{
+	int i;
+	const char *p = data;
+	const char *s;
+
+	/* no data, don't print */
+	if (len == 0)
+		return;
+
+	if (util_is_printable_string(data, len)) {
+		printf(" = ");
+
+		s = data;
+		do {
+			printf("\"%s\"", s);
+			s += strlen(s) + 1;
+			if (s < data + len)
+				printf(", ");
+		} while (s < data + len);
+
+	} else if ((len % 4) == 0) {
+		const uint32_t *cell = (const uint32_t *)data;
+
+		printf(" = <");
+		for (i = 0, len /= 4; i < len; i++)
+			printf("0x%08x%s", fdt32_to_cpu(cell[i]),
+			       i < (len - 1) ? " " : "");
+		printf(">");
+	} else {
+		printf(" = [");
+		for (i = 0; i < len; i++)
+			printf("%02x%s", *p++, i < len - 1 ? " " : "");
+		printf("]");
+	}
+}
+
+/**
+ * display_fdt_by_regions() - Display regions of an FDT source
+ *
+ * This dumps an FDT as source, but only certain regions of it. This is the
+ * final stage of the grep - we have a list of regions we want to display,
+ * and this function displays them.
+ *
+ * @disp:	Display structure, holding info about our options
+ * @blob:	FDT blob to display
+ * @region:	List of regions to display
+ * @count:	Number of regions
+ */
+static int display_fdt_by_regions(struct display_info *disp, const void *blob,
+		struct fdt_region region[], int count)
+{
+	struct fdt_region *reg = region, *reg_end = region + count;
+	uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
+	int base = fdt_off_dt_struct(blob);
+	int version = fdt_version(blob);
+	int offset, nextoffset;
+	int tag, depth, shift;
+	FILE *f = disp->fout;
+	uint64_t addr, size;
+	int in_region;
+	int file_ofs;
+	int i;
+
+	if (disp->show_dts_version)
+		fprintf(f, "/dts-v1/;\n");
+
+	if (disp->header) {
+		fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
+		fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
+			fdt_totalsize(blob));
+		fprintf(f, "// off_dt_struct:\t0x%x\n",
+			fdt_off_dt_struct(blob));
+		fprintf(f, "// off_dt_strings:\t0x%x\n",
+			fdt_off_dt_strings(blob));
+		fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
+		fprintf(f, "// version:\t\t%d\n", version);
+		fprintf(f, "// last_comp_version:\t%d\n",
+			fdt_last_comp_version(blob));
+		if (version >= 2) {
+			fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
+				fdt_boot_cpuid_phys(blob));
+		}
+		if (version >= 3) {
+			fprintf(f, "// size_dt_strings:\t0x%x\n",
+				fdt_size_dt_strings(blob));
+		}
+		if (version >= 17) {
+			fprintf(f, "// size_dt_struct:\t0x%x\n",
+				fdt_size_dt_struct(blob));
+		}
+		fprintf(f, "\n");
+	}
+
+	if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
+		const struct fdt_reserve_entry *p_rsvmap;
+
+		p_rsvmap = (const struct fdt_reserve_entry *)
+				((const char *)blob + off_mem_rsvmap);
+		for (i = 0; ; i++) {
+			addr = fdt64_to_cpu(p_rsvmap[i].address);
+			size = fdt64_to_cpu(p_rsvmap[i].size);
+			if (addr == 0 && size == 0)
+				break;
+
+			fprintf(f, "/memreserve/ %llx %llx;\n",
+				(unsigned long long)addr,
+				(unsigned long long)size);
+		}
+	}
+
+	depth = 0;
+	nextoffset = 0;
+	shift = 4;	/* 4 spaces per indent */
+	do {
+		const struct fdt_property *prop;
+		const char *name;
+		int show;
+		int len;
+
+		offset = nextoffset;
+
+		/*
+		 * Work out the file offset of this offset, and decide
+		 * whether it is in the region list or not
+		 */
+		file_ofs = base + offset;
+		if (reg < reg_end && file_ofs >= reg->offset + reg->size)
+			reg++;
+		in_region = reg < reg_end && file_ofs >= reg->offset &&
+				file_ofs < reg->offset + reg->size;
+		tag = fdt_next_tag(blob, offset, &nextoffset);
+
+		if (tag == FDT_END)
+			break;
+		show = in_region || disp->all;
+		if (show && disp->diff)
+			fprintf(f, "%c", in_region ? '+' : '-');
+
+		if (!show) {
+			/* Do this here to avoid 'if (show)' in every 'case' */
+			if (tag == FDT_BEGIN_NODE)
+				depth++;
+			else if (tag == FDT_END_NODE)
+				depth--;
+			continue;
+		}
+		if (tag != FDT_END) {
+			if (disp->show_addr)
+				fprintf(f, "%4x: ", file_ofs);
+			if (disp->show_offset)
+				fprintf(f, "%4x: ", file_ofs - base);
+		}
+
+		/* Green means included, red means excluded */
+		if (disp->colour)
+			print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
+
+		switch (tag) {
+		case FDT_PROP:
+			prop = fdt_get_property_by_offset(blob, offset, NULL);
+			name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
+			fprintf(f, "%*s%s", depth * shift, "", name);
+			utilfdt_print_data(prop->data,
+					   fdt32_to_cpu(prop->len));
+			fprintf(f, ";");
+			break;
+
+		case FDT_NOP:
+			fprintf(f, "%*s// [NOP]", depth * shift, "");
+			break;
+
+		case FDT_BEGIN_NODE:
+			name = fdt_get_name(blob, offset, &len);
+			fprintf(f, "%*s%s {", depth++ * shift, "",
+				*name ? name : "/");
+			break;
+
+		case FDT_END_NODE:
+			fprintf(f, "%*s};", --depth * shift, "");
+			break;
+		}
+
+		/* Reset colour back to normal before end of line */
+		if (disp->colour)
+			print_ansi_colour(f, COL_NONE);
+		fprintf(f, "\n");
+	} while (1);
+
+	/* Print a list of strings if requested */
+	if (disp->list_strings) {
+		const char *str;
+		int str_base = fdt_off_dt_strings(blob);
+
+		for (offset = 0; offset < fdt_size_dt_strings(blob);
+				offset += strlen(str) + 1) {
+			str = fdt_string(blob, offset);
+			int len = strlen(str) + 1;
+			int show;
+
+			/* Only print strings that are in the region */
+			file_ofs = str_base + offset;
+			in_region = reg < reg_end &&
+					file_ofs >= reg->offset &&
+					file_ofs + len < reg->offset +
+						reg->size;
+			show = in_region || disp->all;
+			if (show && disp->diff)
+				printf("%c", in_region ? '+' : '-');
+			if (disp->show_addr)
+				printf("%4x: ", file_ofs);
+			if (disp->show_offset)
+				printf("%4x: ", offset);
+			printf("%s\n", str);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * dump_fdt_regions() - Dump regions of an FDT as binary data
+ *
+ * This dumps an FDT as binary, but only certain regions of it. This is the
+ * final stage of the grep - we have a list of regions we want to dump,
+ * and this function dumps them.
+ *
+ * The output of this function may or may not be a valid FDT. To ensure it
+ * is, these disp->flags must be set:
+ *
+ *   FDT_REG_SUPERNODES: ensures that subnodes are preceeded by their
+ *		parents. Without this option, fragments of subnode data may be
+ *		output without the supernodes above them. This is useful for
+ *		hashing but cannot produce a valid FDT.
+ *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
+ *		Without this none of the properties will have names
+ *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
+ *		without this.
+ *
+ * @disp:	Display structure, holding info about our options
+ * @blob:	FDT blob to display
+ * @region:	List of regions to display
+ * @count:	Number of regions
+ * @out:	Output destination
+ */
+static int dump_fdt_regions(struct display_info *disp, const void *blob,
+		struct fdt_region region[], int count, char *out)
+{
+	struct fdt_header *fdt;
+	int size, struct_start;
+	int ptr;
+	int i;
+
+	/* Set up a basic header (even if we don't actually write it) */
+	fdt = (struct fdt_header *)out;
+	memset(fdt, '\0', sizeof(*fdt));
+	fdt_set_magic(fdt, FDT_MAGIC);
+	struct_start = FDT_ALIGN(sizeof(struct fdt_header),
+					sizeof(struct fdt_reserve_entry));
+	fdt_set_off_mem_rsvmap(fdt, struct_start);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+
+	/*
+	 * Calculate the total size of the regions we are writing out. The
+	 * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
+	 * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
+	 * is set.
+	 */
+	for (i = size = 0; i < count; i++)
+		size += region[i].size;
+
+	/* Bring in the mem_rsvmap section from the old file if requested */
+	if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
+		struct_start += region[0].size;
+		size -= region[0].size;
+	}
+	fdt_set_off_dt_struct(fdt, struct_start);
+
+	/* Update the header to have the correct offsets/sizes */
+	if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
+		int str_size;
+
+		str_size = region[count - 1].size;
+		fdt_set_size_dt_struct(fdt, size - str_size);
+		fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
+		fdt_set_size_dt_strings(fdt, str_size);
+		fdt_set_totalsize(fdt, struct_start + size);
+	}
+
+	/* Write the header if required */
+	ptr = 0;
+	if (disp->header) {
+		ptr = sizeof(*fdt);
+		while (ptr < fdt_off_mem_rsvmap(fdt))
+			out[ptr++] = '\0';
+	}
+
+	/* Output all the nodes including any mem_rsvmap/string table */
+	for (i = 0; i < count; i++) {
+		struct fdt_region *reg = &region[i];
+
+		memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
+		ptr += reg->size;
+	}
+
+	return ptr;
+}
+
+/**
+ * show_region_list() - Print out a list of regions
+ *
+ * The list includes the region offset (absolute offset from start of FDT
+ * blob in bytes) and size
+ *
+ * @reg:	List of regions to print
+ * @count:	Number of regions
+ */
+static void show_region_list(struct fdt_region *reg, int count)
+{
+	int i;
+
+	printf("Regions: %d\n", count);
+	for (i = 0; i < count; i++, reg++) {
+		printf("%d:  %-10x  %-10x\n", i, reg->offset,
+		       reg->offset + reg->size);
+	}
+}
+
+static int check_type_include(void *priv, int type, const char *data, int size)
+{
+	struct display_info *disp = priv;
+	struct value_node *val;
+	int match, none_match = FDT_IS_ANY;
+
+	/* If none of our conditions mention this type, we know nothing */
+	debug("type=%x, data=%s\n", type, data ? data : "(null)");
+	if (!((disp->types_inc | disp->types_exc) & type)) {
+		debug("   - not in any condition\n");
+		return -1;
+	}
+
+	/*
+	 * Go through the list of conditions. For inclusive conditions, we
+	 * return 1 at the first match. For exclusive conditions, we must
+	 * check that there are no matches.
+	 */
+	for (val = disp->value_head; val; val = val->next) {
+		if (!(type & val->type))
+			continue;
+		match = fdt_stringlist_contains(data, size, val->string);
+		debug("      - val->type=%x, str='%s', match=%d\n",
+		      val->type, val->string, match);
+		if (match && val->include) {
+			debug("   - match inc %s\n", val->string);
+			return 1;
+		}
+		if (match)
+			none_match &= ~val->type;
+	}
+
+	/*
+	 * If this is an exclusive condition, and nothing matches, then we
+	 * should return 1.
+	 */
+	if ((type & disp->types_exc) && (none_match & type)) {
+		debug("   - match exc\n");
+		/*
+		 * Allow FDT_IS_COMPAT to make the final decision in the
+		 * case where there is no specific type
+		 */
+		if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
+			debug("   - supressed exc node\n");
+			return -1;
+		}
+		return 1;
+	}
+
+	/*
+	 * Allow FDT_IS_COMPAT to make the final decision in the
+	 * case where there is no specific type (inclusive)
+	 */
+	if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
+		return -1;
+
+	debug("   - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
+	      disp->types_inc, disp->types_exc, none_match);
+
+	return 0;
+}
+
+/**
+ * h_include() - Include handler function for fdt_find_regions()
+ *
+ * This function decides whether to include or exclude a node, property or
+ * compatible string. The function is defined by fdt_find_regions().
+ *
+ * The algorithm is documented in the code - disp->invert is 0 for normal
+ * operation, and 1 to invert the sense of all matches.
+ *
+ * See
+ */
+static int h_include(void *priv, const void *fdt, int offset, int type,
+		     const char *data, int size)
+{
+	struct display_info *disp = priv;
+	int inc, len;
+
+	inc = check_type_include(priv, type, data, size);
+	if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
+		return 1;
+
+	/*
+	 * If the node name does not tell us anything, check the
+	 * compatible string
+	 */
+	if (inc == -1 && type == FDT_IS_NODE) {
+		debug("   - checking compatible2\n");
+		data = fdt_getprop(fdt, offset, "compatible", &len);
+		inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
+	}
+
+	/* If we still have no idea, check for properties in the node */
+	if (inc != 1 && type == FDT_IS_NODE &&
+	    (disp->types_inc & FDT_NODE_HAS_PROP)) {
+		debug("   - checking node '%s'\n",
+		      fdt_get_name(fdt, offset, NULL));
+		for (offset = fdt_first_property_offset(fdt, offset);
+		     offset > 0 && inc != 1;
+		     offset = fdt_next_property_offset(fdt, offset)) {
+			const struct fdt_property *prop;
+			const char *str;
+
+			prop = fdt_get_property_by_offset(fdt, offset, NULL);
+			if (!prop)
+				continue;
+			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+			inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
+						 strlen(str));
+		}
+		if (inc == -1)
+			inc = 0;
+	}
+
+	switch (inc) {
+	case 1:
+		inc = !disp->invert;
+		break;
+	case 0:
+		inc = disp->invert;
+		break;
+	}
+	debug("   - returning %d\n", inc);
+
+	return inc;
+}
+
+static int h_cmp_region(const void *v1, const void *v2)
+{
+	const struct fdt_region *region1 = v1, *region2 = v2;
+
+	return region1->offset - region2->offset;
+}
+
+static int fdtgrep_find_regions(const void *fdt,
+		int (*include_func)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		struct display_info *disp, struct fdt_region *region,
+		int max_regions, char *path, int path_len, int flags)
+{
+	struct fdt_region_state state;
+	int count;
+	int ret;
+
+	count = 0;
+	ret = fdt_first_region(fdt, include_func, disp,
+			&region[count++], path, path_len,
+			disp->flags, &state);
+	while (ret == 0) {
+		ret = fdt_next_region(fdt, include_func, disp,
+				count < max_regions ? &region[count] : NULL,
+				path, path_len, disp->flags, &state);
+		if (!ret)
+			count++;
+	}
+
+	/* Find all the aliases and add those regions back in */
+	if (disp->add_aliases && count < max_regions) {
+		int new_count;
+
+		new_count = fdt_add_alias_regions(fdt, region, count,
+						  max_regions, &state);
+		if (new_count > max_regions) {
+			region = malloc(new_count * sizeof(struct fdt_region));
+			if (!region) {
+				fprintf(stderr,
+					"Out of memory for %d regions\n",
+					count);
+				return -1;
+			}
+			memcpy(region, state.region,
+			       count * sizeof(struct fdt_region));
+			free(state.region);
+			new_count = fdt_add_alias_regions(fdt, region, count,
+							  max_regions, &state);
+		}
+
+		/*
+		 * The alias regions will now be at the end of the list. Sort
+		 * the regions by offset to get things into the right order
+		 */
+		qsort(region, new_count, sizeof(struct fdt_region),
+		      h_cmp_region);
+		count = new_count;
+	}
+
+	if (ret != -FDT_ERR_NOTFOUND)
+		return ret;
+
+	return count;
+}
+
+int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
+{
+	int fd = 0;	/* assume stdin */
+	char *buf = NULL;
+	off_t bufsize = 1024, offset = 0;
+	int ret = 0;
+
+	*buffp = NULL;
+	if (strcmp(filename, "-") != 0) {
+		fd = open(filename, O_RDONLY);
+		if (fd < 0)
+			return errno;
+	}
+
+	/* Loop until we have read everything */
+	buf = malloc(bufsize);
+	if (!buf)
+		return -ENOMEM;
+	do {
+		/* Expand the buffer to hold the next chunk */
+		if (offset == bufsize) {
+			bufsize *= 2;
+			buf = realloc(buf, bufsize);
+			if (!buf)
+				return -ENOMEM;
+		}
+
+		ret = read(fd, &buf[offset], bufsize - offset);
+		if (ret < 0) {
+			ret = errno;
+			break;
+		}
+		offset += ret;
+	} while (ret != 0);
+
+	/* Clean up, including closing stdin; return errno on error */
+	close(fd);
+	if (ret)
+		free(buf);
+	else
+		*buffp = buf;
+	*len = bufsize;
+	return ret;
+}
+
+int utilfdt_read_err(const char *filename, char **buffp)
+{
+	off_t len;
+	return utilfdt_read_err_len(filename, buffp, &len);
+}
+
+char *utilfdt_read_len(const char *filename, off_t *len)
+{
+	char *buff;
+	int ret = utilfdt_read_err_len(filename, &buff, len);
+
+	if (ret) {
+		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
+			strerror(ret));
+		return NULL;
+	}
+	/* Successful read */
+	return buff;
+}
+
+char *utilfdt_read(const char *filename)
+{
+	off_t len;
+	return utilfdt_read_len(filename, &len);
+}
+
+/**
+ * Run the main fdtgrep operation, given a filename and valid arguments
+ *
+ * @param disp		Display information / options
+ * @param filename	Filename of blob file
+ * @param return 0 if ok, -ve on error
+ */
+static int do_fdtgrep(struct display_info *disp, const char *filename)
+{
+	struct fdt_region *region;
+	int max_regions;
+	int count = 100;
+	char path[1024];
+	char *blob;
+	int i, ret;
+
+	blob = utilfdt_read(filename);
+	if (!blob)
+		return -1;
+	ret = fdt_check_header(blob);
+	if (ret) {
+		fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
+		return ret;
+	}
+
+	/* Allow old files, but they are untested */
+	if (fdt_version(blob) < 17 && disp->value_head) {
+		fprintf(stderr,
+			"Warning: fdtgrep does not fully support version %d files\n",
+			fdt_version(blob));
+	}
+
+	/*
+	 * We do two passes, since we don't know how many regions we need.
+	 * The first pass will count the regions, but if it is too many,
+	 * we do another pass to actually record them.
+	 */
+	for (i = 0; i < 2; i++) {
+		region = malloc(count * sizeof(struct fdt_region));
+		if (!region) {
+			fprintf(stderr, "Out of memory for %d regions\n",
+				count);
+			return -1;
+		}
+		max_regions = count;
+		count = fdtgrep_find_regions(blob,
+				h_include, disp,
+				region, max_regions, path, sizeof(path),
+				disp->flags);
+		if (count < 0) {
+			report_error("fdt_find_regions", count);
+			return -1;
+		}
+		if (count <= max_regions)
+			break;
+		free(region);
+	}
+
+	/* Optionally print a list of regions */
+	if (disp->region_list)
+		show_region_list(region, count);
+
+	/* Output either source .dts or binary .dtb */
+	if (disp->output == OUT_DTS) {
+		ret = display_fdt_by_regions(disp, blob, region, count);
+	} else {
+		void *fdt;
+		/* Allow reserved memory section to expand slightly */
+		int size = fdt_totalsize(blob) + 16;
+
+		fdt = malloc(size);
+		if (!fdt) {
+			fprintf(stderr, "Out_of_memory\n");
+			ret = -1;
+			goto err;
+		}
+		size = dump_fdt_regions(disp, blob, region, count, fdt);
+		if (disp->remove_strings) {
+			void *out;
+
+			out = malloc(size);
+			if (!out) {
+				fprintf(stderr, "Out_of_memory\n");
+				ret = -1;
+				goto err;
+			}
+			ret = fdt_remove_unused_strings(fdt, out);
+			if (ret < 0) {
+				fprintf(stderr,
+					"Failed to remove unused strings: err=%d\n",
+					ret);
+				goto err;
+			}
+			free(fdt);
+			fdt = out;
+			ret = fdt_pack(fdt);
+			if (ret < 0) {
+				fprintf(stderr, "Failed to pack: err=%d\n",
+					ret);
+				goto err;
+			}
+			size = fdt_totalsize(fdt);
+		}
+
+		if (size != fwrite(fdt, 1, size, disp->fout)) {
+			fprintf(stderr, "Write failure, %d bytes\n", size);
+			free(fdt);
+			ret = 1;
+			goto err;
+		}
+		free(fdt);
+	}
+err:
+	free(blob);
+	free(region);
+
+	return ret;
+}
+
+static const char usage_synopsis[] =
+	"fdtgrep - extract portions from device tree\n"
+	"\n"
+	"Usage:\n"
+	"	fdtgrep <options> <dt file>|-\n\n"
+	"Output formats are:\n"
+	"\tdts - device tree soure text\n"
+	"\tdtb - device tree blob (sets -Hmt automatically)\n"
+	"\tbin - device tree fragment (may not be a valid .dtb)";
+
+/* Helper for usage_short_opts string constant */
+#define USAGE_COMMON_SHORT_OPTS "hV"
+
+/* Helper for aligning long_opts array */
+#define a_argument required_argument
+
+/* Helper for usage_long_opts option array */
+#define USAGE_COMMON_LONG_OPTS \
+	{"help",      no_argument, NULL, 'h'}, \
+	{"version",   no_argument, NULL, 'V'}, \
+	{NULL,        no_argument, NULL, 0x0}
+
+/* Helper for usage_opts_help array */
+#define USAGE_COMMON_OPTS_HELP \
+	"Print this help and exit", \
+	"Print version and exit", \
+	NULL
+
+/* Helper for getopt case statements */
+#define case_USAGE_COMMON_FLAGS \
+	case 'h': usage(NULL); \
+	case 'V': util_version(); \
+	case '?': usage("unknown option");
+
+static const char usage_short_opts[] =
+		"haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
+		USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+	{"show-address",	no_argument, NULL, 'a'},
+	{"colour",		no_argument, NULL, 'A'},
+	{"include-node-with-prop", a_argument, NULL, 'b'},
+	{"include-compat",	a_argument, NULL, 'c'},
+	{"exclude-compat",	a_argument, NULL, 'C'},
+	{"diff",		no_argument, NULL, 'd'},
+	{"enter-node",		no_argument, NULL, 'e'},
+	{"show-offset",		no_argument, NULL, 'f'},
+	{"include-match",	a_argument, NULL, 'g'},
+	{"exclude-match",	a_argument, NULL, 'G'},
+	{"show-header",		no_argument, NULL, 'H'},
+	{"show-version",	no_argument, NULL, 'I'},
+	{"list-regions",	no_argument, NULL, 'l'},
+	{"list-strings",	no_argument, NULL, 'L'},
+	{"include-mem",		no_argument, NULL, 'm'},
+	{"include-node",	a_argument, NULL, 'n'},
+	{"exclude-node",	a_argument, NULL, 'N'},
+	{"include-prop",	a_argument, NULL, 'p'},
+	{"exclude-prop",	a_argument, NULL, 'P'},
+	{"remove-strings",	no_argument, NULL, 'r'},
+	{"include-root",	no_argument, NULL, 'R'},
+	{"show-subnodes",	no_argument, NULL, 's'},
+	{"skip-supernodes",	no_argument, NULL, 'S'},
+	{"show-stringtab",	no_argument, NULL, 't'},
+	{"show-aliases",	no_argument, NULL, 'T'},
+	{"out",			a_argument, NULL, 'o'},
+	{"out-format",		a_argument, NULL, 'O'},
+	{"invert-match",	no_argument, NULL, 'v'},
+	USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+	"Display address",
+	"Show all nodes/tags, colour those that match",
+	"Include contains containing property",
+	"Compatible nodes to include in grep",
+	"Compatible nodes to exclude in grep",
+	"Diff: Mark matching nodes with +, others with -",
+	"Enter direct subnode names of matching nodes",
+	"Display offset",
+	"Node/property/compatible string to include in grep",
+	"Node/property/compatible string to exclude in grep",
+	"Output a header",
+	"Put \"/dts-v1/;\" on first line of dts output",
+	"Output a region list",
+	"List strings in string table",
+	"Include mem_rsvmap section in binary output",
+	"Node to include in grep",
+	"Node to exclude in grep",
+	"Property to include in grep",
+	"Property to exclude in grep",
+	"Remove unused strings from string table",
+	"Include root node and all properties",
+	"Show all subnodes matching nodes",
+	"Don't include supernodes of matching nodes",
+	"Include string table in binary output",
+	"Include matching aliases in output",
+	"-o <output file>",
+	"-O <output format>",
+	"Invert the sense of matching (select non-matching lines)",
+	USAGE_COMMON_OPTS_HELP
+};
+
+/**
+ * Call getopt_long() with standard options
+ *
+ * Since all util code runs getopt in the same way, provide a helper.
+ */
+#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
+				       usage_long_opts, NULL)
+
+void util_usage(const char *errmsg, const char *synopsis,
+		const char *short_opts, struct option const long_opts[],
+		const char * const opts_help[])
+{
+	FILE *fp = errmsg ? stderr : stdout;
+	const char a_arg[] = "<arg>";
+	size_t a_arg_len = strlen(a_arg) + 1;
+	size_t i;
+	int optlen;
+
+	fprintf(fp,
+		"Usage: %s\n"
+		"\n"
+		"Options: -[%s]\n", synopsis, short_opts);
+
+	/* prescan the --long opt length to auto-align */
+	optlen = 0;
+	for (i = 0; long_opts[i].name; ++i) {
+		/* +1 is for space between --opt and help text */
+		int l = strlen(long_opts[i].name) + 1;
+		if (long_opts[i].has_arg == a_argument)
+			l += a_arg_len;
+		if (optlen < l)
+			optlen = l;
+	}
+
+	for (i = 0; long_opts[i].name; ++i) {
+		/* helps when adding new applets or options */
+		assert(opts_help[i] != NULL);
+
+		/* first output the short flag if it has one */
+		if (long_opts[i].val > '~')
+			fprintf(fp, "      ");
+		else
+			fprintf(fp, "  -%c, ", long_opts[i].val);
+
+		/* then the long flag */
+		if (long_opts[i].has_arg == no_argument) {
+			fprintf(fp, "--%-*s", optlen, long_opts[i].name);
+		} else {
+			fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
+				(int)(optlen - strlen(long_opts[i].name) -
+				a_arg_len), "");
+		}
+
+		/* finally the help text */
+		fprintf(fp, "%s\n", opts_help[i]);
+	}
+
+	if (errmsg) {
+		fprintf(fp, "\nError: %s\n", errmsg);
+		exit(EXIT_FAILURE);
+	} else {
+		exit(EXIT_SUCCESS);
+	}
+}
+
+/**
+ * Show usage and exit
+ *
+ * If you name all your usage variables with usage_xxx, then you can call this
+ * help macro rather than expanding all arguments yourself.
+ *
+ * @param errmsg	If non-NULL, an error message to display
+ */
+#define usage(errmsg) \
+	util_usage(errmsg, usage_synopsis, usage_short_opts, \
+		   usage_long_opts, usage_opts_help)
+
+void util_version(void)
+{
+	printf("Version: %s\n", "(U-Boot)");
+	exit(0);
+}
+
+static void scan_args(struct display_info *disp, int argc, char *argv[])
+{
+	int opt;
+
+	while ((opt = util_getopt_long()) != EOF) {
+		int type = 0;
+		int inc = 1;
+
+		switch (opt) {
+		case_USAGE_COMMON_FLAGS
+		case 'a':
+			disp->show_addr = 1;
+			break;
+		case 'A':
+			disp->all = 1;
+			break;
+		case 'b':
+			type = FDT_NODE_HAS_PROP;
+			break;
+		case 'C':
+			inc = 0;
+			/* no break */
+		case 'c':
+			type = FDT_IS_COMPAT;
+			break;
+		case 'd':
+			disp->diff = 1;
+			break;
+		case 'e':
+			disp->flags |= FDT_REG_DIRECT_SUBNODES;
+			break;
+		case 'f':
+			disp->show_offset = 1;
+			break;
+		case 'G':
+			inc = 0;
+			/* no break */
+		case 'g':
+			type = FDT_ANY_GLOBAL;
+			break;
+		case 'H':
+			disp->header = 1;
+			break;
+		case 'l':
+			disp->region_list = 1;
+			break;
+		case 'L':
+			disp->list_strings = 1;
+			break;
+		case 'm':
+			disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
+			break;
+		case 'N':
+			inc = 0;
+			/* no break */
+		case 'n':
+			type = FDT_IS_NODE;
+			break;
+		case 'o':
+			disp->output_fname = optarg;
+			break;
+		case 'O':
+			if (!strcmp(optarg, "dtb"))
+				disp->output = OUT_DTB;
+			else if (!strcmp(optarg, "dts"))
+				disp->output = OUT_DTS;
+			else if (!strcmp(optarg, "bin"))
+				disp->output = OUT_BIN;
+			else
+				usage("Unknown output format");
+			break;
+		case 'P':
+			inc = 0;
+			/* no break */
+		case 'p':
+			type = FDT_IS_PROP;
+			break;
+		case 'r':
+			disp->remove_strings = 1;
+			break;
+		case 'R':
+			disp->include_root = 1;
+			break;
+		case 's':
+			disp->flags |= FDT_REG_ALL_SUBNODES;
+			break;
+		case 'S':
+			disp->flags &= ~FDT_REG_SUPERNODES;
+			break;
+		case 't':
+			disp->flags |= FDT_REG_ADD_STRING_TAB;
+			break;
+		case 'T':
+			disp->add_aliases = 1;
+			break;
+		case 'v':
+			disp->invert = 1;
+			break;
+		case 'I':
+			disp->show_dts_version = 1;
+			break;
+		}
+
+		if (type && value_add(disp, &disp->value_head, type, inc,
+				      optarg))
+			usage("Cannot add value");
+	}
+
+	if (disp->invert && disp->types_exc)
+		usage("-v has no meaning when used with 'exclude' conditions");
+}
+
+int main(int argc, char *argv[])
+{
+	char *filename = NULL;
+	struct display_info disp;
+	int ret;
+
+	/* set defaults */
+	memset(&disp, '\0', sizeof(disp));
+	disp.flags = FDT_REG_SUPERNODES;	/* Default flags */
+
+	scan_args(&disp, argc, argv);
+
+	/* Show matched lines in colour if we can */
+	disp.colour = disp.all && isatty(0);
+
+	/* Any additional arguments can match anything, just like -g */
+	while (optind < argc - 1) {
+		if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
+			      argv[optind++]))
+			usage("Cannot add value");
+	}
+
+	if (optind < argc)
+		filename = argv[optind++];
+	if (!filename)
+		usage("Missing filename");
+
+	/* If a valid .dtb is required, set flags to ensure we get one */
+	if (disp.output == OUT_DTB) {
+		disp.header = 1;
+		disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
+	}
+
+	if (disp.output_fname) {
+		disp.fout = fopen(disp.output_fname, "w");
+		if (!disp.fout)
+			usage("Cannot open output file");
+	} else {
+		disp.fout = stdout;
+	}
+
+	/* Run the grep and output the results */
+	ret = do_fdtgrep(&disp, filename);
+	if (disp.output_fname)
+		fclose(disp.fout);
+	if (ret)
+		return 1;
+
+	return 0;
+}
diff --git a/tools/imagetool.h b/tools/imagetool.h
index b7874f4..99bbf2f 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -59,6 +59,7 @@
 	const char *keydest;	/* Destination .dtb for public key */
 	const char *comment;	/* Comment to add to signature node */
 	int require_keys;	/* 1 to mark signing keys as 'required' */
+	int file_size;		/* Total size of output file */
 };
 
 /*
diff --git a/tools/kwbimage.c b/tools/kwbimage.c
index 1ff17ca..3fa90d3 100644
--- a/tools/kwbimage.c
+++ b/tools/kwbimage.c
@@ -115,6 +115,7 @@
 	{ 0x78, "sata" },
 	{ 0x9C, "pex"  },
 	{ 0x69, "uart" },
+	{ 0xAE, "sdio" },
 	{},
 };
 
@@ -420,15 +421,15 @@
 			*hasext = 1;
 	}
 
-#if defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
-	if (headersz > CONFIG_SYS_SPI_U_BOOT_OFFS) {
+#if defined(CONFIG_SYS_U_BOOT_OFFS)
+	if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
 		fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
-		fprintf(stderr, "header=0x%x CONFIG_SYS_SPI_U_BOOT_OFFS=0x%x!\n",
-			(int)headersz, CONFIG_SYS_SPI_U_BOOT_OFFS);
-		fprintf(stderr, "Increase CONFIG_SYS_SPI_U_BOOT_OFFS!\n");
+		fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
+			(int)headersz, CONFIG_SYS_U_BOOT_OFFS);
+		fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
 		return 0;
 	} else {
-		headersz = CONFIG_SYS_SPI_U_BOOT_OFFS;
+		headersz = CONFIG_SYS_U_BOOT_OFFS;
 	}
 #endif
 
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 5ccd951..e81d455 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -26,8 +26,48 @@
 	.imagename2 = "",
 };
 
-int
-main (int argc, char **argv)
+static int h_compare_image_name(const void *vtype1, const void *vtype2)
+{
+	const int *type1 = vtype1;
+	const int *type2 = vtype2;
+	const char *name1 = genimg_get_type_short_name(*type1);
+	const char *name2 = genimg_get_type_short_name(*type2);
+
+	return strcmp(name1, name2);
+}
+
+/* Show all image types supported by mkimage */
+static void show_image_types(void)
+{
+	struct image_type_params *tparams;
+	int order[IH_TYPE_COUNT];
+	int count;
+	int type;
+	int i;
+
+	/* Sort the names in order of short name for easier reading */
+	memset(order, '\0', sizeof(order));
+	for (count = 0, type = 0; type < IH_TYPE_COUNT; type++) {
+		tparams = imagetool_get_type(type);
+		if (tparams)
+			order[count++] = type;
+	}
+	qsort(order, count, sizeof(int), h_compare_image_name);
+
+	fprintf(stderr, "\nInvalid image type. Supported image types:\n");
+	for (i = 0; i < count; i++) {
+		type = order[i];
+		tparams = imagetool_get_type(type);
+		if (tparams) {
+			fprintf(stderr, "\t%-15s  %s\n",
+				genimg_get_type_short_name(type),
+				genimg_get_type_name(type));
+		}
+	}
+	fprintf(stderr, "\n");
+}
+
+int main(int argc, char **argv)
 {
 	int ifd = -1;
 	struct stat sbuf;
@@ -35,6 +75,7 @@
 	int retval = 0;
 	struct image_type_params *tparams = NULL;
 	int pad_len = 0;
+	int dfd;
 
 	params.cmdname = *argv;
 	params.addr = params.ep = 0;
@@ -75,12 +116,16 @@
 					usage ();
 				goto NXTARG;
 			case 'T':
-				if ((--argc <= 0) ||
-					(params.type =
-					genimg_get_type_id (*++argv)) < 0)
-					usage ();
+				params.type = -1;
+				if (--argc >= 0 && argv[1]) {
+					params.type =
+						genimg_get_type_id(*++argv);
+				}
+				if (params.type < 0) {
+					show_image_types();
+					usage();
+				}
 				goto NXTARG;
-
 			case 'a':
 				if (--argc <= 0)
 					usage ();
@@ -266,6 +311,22 @@
 		exit (retval);
 	}
 
+	dfd = open(params.datafile, O_RDONLY | O_BINARY);
+	if (dfd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			params.cmdname, params.datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			params.cmdname, params.datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	params.file_size = sbuf.st_size + tparams->header_size;
+	close(dfd);
+
 	/*
 	 * In case there an header with a variable
 	 * length will be added, the corresponding
@@ -365,6 +426,7 @@
 			params.cmdname, params.imagefile, strerror(errno));
 		exit (EXIT_FAILURE);
 	}
+	params.file_size = sbuf.st_size;
 
 	ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
 	if (ptr == MAP_FAILED) {
@@ -546,6 +608,7 @@
 #endif
 	fprintf (stderr, "       %s -V ==> print version information and exit\n",
 		params.cmdname);
+	fprintf(stderr, "Use -T to see a list of available image types\n");
 
 	exit (EXIT_FAILURE);
 }