Merge git://git.denx.de/u-boot-marvell
diff --git a/Makefile b/Makefile
index 92faed6..76bae8b 100644
--- a/Makefile
+++ b/Makefile
@@ -856,12 +856,18 @@
 MKIMAGEFLAGS_u-boot.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \
 	-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)
+
 MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \
 		-R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage
 
 u-boot.img u-boot.kwb u-boot.pbl: u-boot.bin FORCE
 	$(call if_changed,mkimage)
 
+u-boot-spl.kwb: u-boot.img spl/u-boot-spl.bin FORCE
+	$(call if_changed,mkimage)
+
 MKIMAGEFLAGS_u-boot-dtb.img = $(MKIMAGEFLAGS_u-boot.img)
 
 u-boot-dtb.img: u-boot-dtb.bin FORCE
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 986b4c5..47806f8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -236,10 +236,12 @@
 config TARGET_DB_MV784MP_GP
 	bool "Support db-mv784mp-gp"
 	select CPU_V7
+	select SUPPORT_SPL
 
 config TARGET_MAXBCM
 	bool "Support maxbcm"
 	select CPU_V7
+	select SUPPORT_SPL
 
 config TARGET_DEVKIT3250
 	bool "Support devkit3250"
diff --git a/arch/arm/cpu/armv7/armada-xp/Makefile b/arch/arm/cpu/armv7/armada-xp/Makefile
index 885dcee..737159b 100644
--- a/arch/arm/cpu/armv7/armada-xp/Makefile
+++ b/arch/arm/cpu/armv7/armada-xp/Makefile
@@ -5,3 +5,5 @@
 #
 
 obj-y	= cpu.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
+obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o
diff --git a/arch/arm/cpu/armv7/armada-xp/lowlevel_spl.S b/arch/arm/cpu/armv7/armada-xp/lowlevel_spl.S
new file mode 100644
index 0000000..1febd7b
--- /dev/null
+++ b/arch/arm/cpu/armv7/armada-xp/lowlevel_spl.S
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+#include <linux/linkage.h>
+
+ENTRY(save_boot_params)
+	bx	lr
+ENDPROC(save_boot_params)
+
+/*
+ * cache_inv - invalidate Cache line
+ * r0 - dest
+ */
+	.global cache_inv
+	.type  cache_inv, %function
+	cache_inv:
+
+	stmfd   sp!, {r1-r12}
+
+	mcr     p15, 0, r0, c7, c6, 1
+
+	ldmfd   sp!, {r1-r12}
+	bx      lr
+
+
+/*
+ * flush_l1_v6 - l1 cache clean invalidate
+ * r0 - dest
+ */
+	.global flush_l1_v6
+	.type	flush_l1_v6, %function
+	flush_l1_v6:
+
+	stmfd   sp!, {r1-r12}
+
+	mcr     p15, 0, r0, c7, c10, 5	/* @ data memory barrier */
+	mcr     p15, 0, r0, c7, c14, 1	/* @ clean & invalidate D line */
+	mcr     p15, 0, r0, c7, c10, 4	/* @ data sync barrier */
+
+	ldmfd   sp!, {r1-r12}
+	bx      lr
+
+
+/*
+ * flush_l1_v7 - l1 cache clean invalidate
+ * r0 - dest
+ */
+	.global flush_l1_v7
+	.type	flush_l1_v7, %function
+	flush_l1_v7:
+
+	stmfd   sp!, {r1-r12}
+
+	dmb				/* @data memory barrier */
+	mcr     p15, 0, r0, c7, c14, 1	/* @ clean & invalidate D line */
+	dsb				/* @data sync barrier */
+
+	ldmfd   sp!, {r1-r12}
+	bx      lr
diff --git a/arch/arm/cpu/armv7/armada-xp/spl.c b/arch/arm/cpu/armv7/armada-xp/spl.c
new file mode 100644
index 0000000..402e520
--- /dev/null
+++ b/arch/arm/cpu/armv7/armada-xp/spl.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 Stefan Roese <sr@denx.de>
+ *
+ * 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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+u32 spl_boot_device(void)
+{
+	/* Right now only booting via SPI NOR flash is supported */
+	return BOOT_DEVICE_SPI;
+}
+
+void board_init_f(ulong dummy)
+{
+	/* Set global data pointer */
+	gd = &gdata;
+
+	/* Linux expects the internal registers to be at 0xf1000000 */
+	arch_cpu_init();
+
+	preloader_console_init();
+
+	/* First init the serdes PHY's */
+	serdes_phy_config();
+
+	/* Setup DDR */
+	ddr3_init();
+
+	board_init_r(NULL, 0);
+}
diff --git a/arch/arm/include/asm/arch-armada-xp/config.h b/arch/arm/include/asm/arch-armada-xp/config.h
index 00ee775..f9fd424 100644
--- a/arch/arm/include/asm/arch-armada-xp/config.h
+++ b/arch/arm/include/asm/arch-armada-xp/config.h
@@ -31,7 +31,11 @@
 #endif /* CONFIG_SYS_KWD_CONFIG */
 
 /* Add target to build it automatically upon "make" */
+#ifdef CONFIG_SPL
+#define CONFIG_BUILD_TARGET	"u-boot-spl.kwb"
+#else
 #define CONFIG_BUILD_TARGET	"u-boot.kwb"
+#endif
 
 /* end of 16M scrubbed by training in bootrom */
 #define CONFIG_SYS_INIT_SP_ADDR		0x00FF0000
diff --git a/arch/arm/include/asm/arch-armada-xp/cpu.h b/arch/arm/include/asm/arch-armada-xp/cpu.h
index 6b60c21..4f5ff96 100644
--- a/arch/arm/include/asm/arch-armada-xp/cpu.h
+++ b/arch/arm/include/asm/arch-armada-xp/cpu.h
@@ -96,6 +96,9 @@
 	u32 irq_level;
 };
 
+/* Needed for dynamic (board-specific) mbus configuration */
+extern struct mvebu_mbus_state mbus_state;
+
 /*
  * functions
  */
@@ -103,5 +106,18 @@
 unsigned int mvebu_sdram_bs(enum memory_bank bank);
 void mvebu_sdram_size_adjust(enum memory_bank bank);
 int mvebu_mbus_probe(struct mbus_win windows[], int count);
+
+/*
+ * Highspeed SERDES PHY config init, ported from bin_hdr
+ * to mainline U-Boot
+ */
+int serdes_phy_config(void);
+
+/*
+ * DDR3 init / training code ported from Marvell bin_hdr. Now
+ * available in mainline U-Boot in:
+ * drivers/ddr/mvebu/
+ */
+int ddr3_init(void);
 #endif /* __ASSEMBLY__ */
 #endif /* _ARMADA_XP_CPU_H */
diff --git a/arch/arm/mvebu-common/Makefile b/arch/arm/mvebu-common/Makefile
index 9dcab69..de243fe 100644
--- a/arch/arm/mvebu-common/Makefile
+++ b/arch/arm/mvebu-common/Makefile
@@ -10,3 +10,5 @@
 obj-y	+= gpio.o
 obj-$(CONFIG_ARMADA_XP) += mbus.o
 obj-y	+= timer.o
+
+obj-y	+= serdes/
diff --git a/arch/arm/mvebu-common/serdes/Makefile b/arch/arm/mvebu-common/serdes/Makefile
new file mode 100644
index 0000000..a380fee
--- /dev/null
+++ b/arch/arm/mvebu-common/serdes/Makefile
@@ -0,0 +1,6 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD)	= high_speed_env_lib.o
+obj-$(CONFIG_SPL_BUILD)	+= high_speed_env_spec.o
diff --git a/arch/arm/mvebu-common/serdes/board_env_spec.h b/arch/arm/mvebu-common/serdes/board_env_spec.h
new file mode 100644
index 0000000..36e0ed8
--- /dev/null
+++ b/arch/arm/mvebu-common/serdes/board_env_spec.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __BOARD_ENV_SPEC
+#define __BOARD_ENV_SPEC
+
+/* Board specific configuration */
+
+/* KW40 */
+#define MV_6710_DEV_ID			0x6710
+
+#define MV_6710_Z1_REV			0x0
+#define MV_6710_Z1_ID			((MV_6710_DEV_ID << 16) | MV_6710_Z1_REV)
+#define MV_6710_Z1_NAME			"MV6710 Z1"
+
+/* Armada XP Family */
+#define MV_78130_DEV_ID			0x7813
+#define MV_78160_DEV_ID			0x7816
+#define MV_78230_DEV_ID			0x7823
+#define MV_78260_DEV_ID			0x7826
+#define MV_78460_DEV_ID			0x7846
+#define MV_78000_DEV_ID			0x7888
+
+#define MV_FPGA_DEV_ID			0x2107
+
+#define MV_78XX0_Z1_REV			0x0
+
+/* boards ID numbers */
+#define BOARD_ID_BASE			0x0
+
+/* New board ID numbers */
+#define DB_88F78XX0_BP_ID		(BOARD_ID_BASE)
+#define RD_78460_SERVER_ID		(DB_88F78XX0_BP_ID + 1)
+#define DB_78X60_PCAC_ID		(RD_78460_SERVER_ID + 1)
+#define FPGA_88F78XX0_ID		(DB_78X60_PCAC_ID + 1)
+#define DB_88F78XX0_BP_REV2_ID		(FPGA_88F78XX0_ID + 1)
+#define RD_78460_NAS_ID			(DB_88F78XX0_BP_REV2_ID + 1)
+#define DB_78X60_AMC_ID			(RD_78460_NAS_ID + 1)
+#define DB_78X60_PCAC_REV2_ID		(DB_78X60_AMC_ID + 1)
+#define RD_78460_SERVER_REV2_ID		(DB_78X60_PCAC_REV2_ID + 1)
+#define DB_784MP_GP_ID			(RD_78460_SERVER_REV2_ID + 1)
+#define RD_78460_CUSTOMER_ID		(DB_784MP_GP_ID + 1)
+#define MV_MAX_BOARD_ID			(RD_78460_CUSTOMER_ID + 1)
+#define INVALID_BAORD_ID		0xFFFFFFFF
+
+/* Sample at Reset */
+#define MPP_SAMPLE_AT_RESET(id)		(0x18230 + (id * 4))
+
+/* BIOS Modes related defines */
+
+#define SAR0_BOOTWIDTH_OFFSET		3
+#define SAR0_BOOTWIDTH_MASK		(0x3 << SAR0_BOOTWIDTH_OFFSET)
+#define SAR0_BOOTSRC_OFFSET		5
+#define SAR0_BOOTSRC_MASK		(0xF << SAR0_BOOTSRC_OFFSET)
+
+#define SAR0_L2_SIZE_OFFSET		19
+#define SAR0_L2_SIZE_MASK		(0x3 << SAR0_L2_SIZE_OFFSET)
+#define SAR0_CPU_FREQ_OFFSET		21
+#define SAR0_CPU_FREQ_MASK		(0x7 << SAR0_CPU_FREQ_OFFSET)
+#define SAR0_FABRIC_FREQ_OFFSET		24
+#define SAR0_FABRIC_FREQ_MASK		(0xF << SAR0_FABRIC_FREQ_OFFSET)
+#define SAR0_CPU0CORE_OFFSET		31
+#define SAR0_CPU0CORE_MASK		(0x1 << SAR0_CPU0CORE_OFFSET)
+#define SAR1_CPU0CORE_OFFSET		0
+#define SAR1_CPU0CORE_MASK		(0x1 << SAR1_CPU0CORE_OFFSET)
+
+#define PEX_CLK_100MHZ_OFFSET		2
+#define PEX_CLK_100MHZ_MASK		(0x1 << PEX_CLK_100MHZ_OFFSET)
+
+#define SAR1_FABRIC_MODE_OFFSET		19
+#define SAR1_FABRIC_MODE_MASK		(0x1 << SAR1_FABRIC_MODE_OFFSET)
+#define SAR1_CPU_MODE_OFFSET		20
+#define SAR1_CPU_MODE_MASK		(0x1 << SAR1_CPU_MODE_OFFSET)
+
+#define SAR_CPU_FAB_GET(cpu, fab)	(((cpu & 0x7) << 21) | ((fab & 0xF) << 24))
+
+
+#define CORE_AVS_CONTROL_0REG		0x18300
+#define CORE_AVS_CONTROL_2REG		0x18308
+#define CPU_AVS_CONTROL2_REG		0x20868
+#define CPU_AVS_CONTROL0_REG		0x20860
+#define GENERAL_PURPOSE_RESERVED0_REG	0x182E0
+
+#define MSAR_TCLK_OFFS			28
+#define MSAR_TCLK_MASK			(0x1 << MSAR_TCLK_OFFS)
+
+
+/* Controler environment registers offsets */
+#define GEN_PURP_RES_1_REG		0x182F4
+#define GEN_PURP_RES_2_REG		0x182F8
+
+/* registers offsets */
+#define MV_GPP_REGS_OFFSET(unit)	(0x18100 + ((unit) * 0x40))
+#define MPP_CONTROL_REG(id)		(0x18000 + (id * 4))
+#define MV_GPP_REGS_BASE(unit)		(MV_GPP_REGS_OFFSET(unit))
+#define MV_GPP_REGS_BASE_0		(MV_GPP_REGS_OFFSET_0)
+
+#define GPP_DATA_OUT_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x00)
+#define GPP_DATA_OUT_REG_0		(MV_GPP_REGS_BASE_0 + 0x00)	/* Used in .S files */
+#define GPP_DATA_OUT_EN_REG(grp)	(MV_GPP_REGS_BASE(grp) + 0x04)
+#define GPP_BLINK_EN_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x08)
+#define GPP_DATA_IN_POL_REG(grp)	(MV_GPP_REGS_BASE(grp) + 0x0C)
+#define GPP_DATA_IN_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x10)
+#define GPP_INT_CAUSE_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x14)
+#define GPP_INT_MASK_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x18)
+#define GPP_INT_LVL_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x1C)
+#define GPP_OUT_SET_REG(grp)		(0x18130 + ((grp) * 0x40))
+#define GPP_64_66_DATA_OUT_SET_REG	0x181A4
+#define GPP_OUT_CLEAR_REG(grp)		(0x18134 + ((grp) * 0x40))
+#define GPP_64_66_DATA_OUT_CLEAR_REG	0x181B0
+#define GPP_FUNC_SELECT_REG		(MV_GPP_REGS_BASE(0) + 0x40)
+
+#define MV_GPP66			(1 << 2)
+
+/* Relevant for MV78XX0 */
+#define GPP_DATA_OUT_SET_REG		(MV_GPP_REGS_BASE(0) + 0x20)
+#define GPP_DATA_OUT_CLEAR_REG		(MV_GPP_REGS_BASE(0) + 0x24)
+
+/* This define describes the maximum number of supported PEX Interfaces */
+#define MV_PEX_MAX_IF			10
+#define MV_PEX_MAX_UNIT			4
+
+#define MV_SERDES_NUM_TO_PEX_NUM(num)	((num < 8) ? (num) : (8 + (num / 12)))
+
+#define PEX_PHY_ACCESS_REG(unit)	(0x40000 + ((unit) % 2 * 0x40000) + \
+					 ((unit)/2 * 0x2000) + 0x1B00)
+
+#define SATA_BASE_REG(port)		(0xA2000 + (port)*0x2000)
+
+#define SATA_PWR_PLL_CTRL_REG(port)	(SATA_BASE_REG(port) + 0x804)
+#define SATA_DIG_LP_ENA_REG(port)	(SATA_BASE_REG(port) + 0x88C)
+#define SATA_REF_CLK_SEL_REG(port)	(SATA_BASE_REG(port) + 0x918)
+#define SATA_COMPHY_CTRL_REG(port)	(SATA_BASE_REG(port) + 0x920)
+#define SATA_LP_PHY_EXT_CTRL_REG(port)	(SATA_BASE_REG(port) + 0x058)
+#define SATA_LP_PHY_EXT_STAT_REG(port)	(SATA_BASE_REG(port) + 0x05C)
+#define SATA_IMP_TX_SSC_CTRL_REG(port)	(SATA_BASE_REG(port) + 0x810)
+#define SATA_GEN_1_SET_0_REG(port)	(SATA_BASE_REG(port) + 0x834)
+#define SATA_GEN_1_SET_1_REG(port)	(SATA_BASE_REG(port) + 0x838)
+#define SATA_GEN_2_SET_0_REG(port)	(SATA_BASE_REG(port) + 0x83C)
+#define SATA_GEN_2_SET_1_REG(port)	(SATA_BASE_REG(port) + 0x840)
+
+#define MV_ETH_BASE_ADDR		(0x72000)
+#define MV_ETH_REGS_OFFSET(port)	(MV_ETH_BASE_ADDR - ((port) / 2) * \
+					 0x40000 + ((port) % 2) * 0x4000)
+#define MV_ETH_REGS_BASE(port)		MV_ETH_REGS_OFFSET(port)
+
+
+#define SGMII_PWR_PLL_CTRL_REG(port)	(MV_ETH_REGS_BASE(port) + 0xE04)
+#define SGMII_DIG_LP_ENA_REG(port)	(MV_ETH_REGS_BASE(port) + 0xE8C)
+#define SGMII_REF_CLK_SEL_REG(port)	(MV_ETH_REGS_BASE(port) + 0xF18)
+#define SGMII_SERDES_CFG_REG(port)	(MV_ETH_REGS_BASE(port) + 0x4A0)
+#define SGMII_SERDES_STAT_REG(port)	(MV_ETH_REGS_BASE(port) + 0x4A4)
+#define SGMII_COMPHY_CTRL_REG(port)	(MV_ETH_REGS_BASE(port) + 0xF20)
+#define QSGMII_GEN_1_SETTING_REG(port)	(MV_ETH_REGS_BASE(port) + 0xE38)
+#define QSGMII_SERDES_CFG_REG(port)	(MV_ETH_REGS_BASE(port) + 0x4a0)
+
+#define SERDES_LINE_MUX_REG_0_7		0x18270
+#define SERDES_LINE_MUX_REG_8_15	0x18274
+#define QSGMII_CONTROL_1_REG		0x18404
+
+/* SOC_CTRL_REG fields */
+#define SCR_PEX_ENA_OFFS(pex)		((pex) & 0x3)
+#define SCR_PEX_ENA_MASK(pex)		(1 << pex)
+
+#define PCIE0_QUADX1_EN			(1<<7)
+#define PCIE1_QUADX1_EN			(1<<8)
+
+#define SCR_PEX_4BY1_OFFS(pex)		((pex) + 7)
+#define SCR_PEX_4BY1_MASK(pex)		(1 << SCR_PEX_4BY1_OFFS(pex))
+
+#define PCIE1_CLK_OUT_EN_OFF		5
+#define PCIE1_CLK_OUT_EN_MASK		(1 << PCIE1_CLK_OUT_EN_OFF)
+
+#define PCIE0_CLK_OUT_EN_OFF		4
+#define PCIE0_CLK_OUT_EN_MASK		(1 << PCIE0_CLK_OUT_EN_OFF)
+
+#define SCR_PEX0_4BY1_OFFS		7
+#define SCR_PEX0_4BY1_MASK		(1 << SCR_PEX0_4BY1_OFFS)
+
+#define SCR_PEX1_4BY1_OFFS		8
+#define SCR_PEX1_4BY1_MASK		(1 << SCR_PEX1_4BY1_OFFS)
+
+
+#define MV_MISC_REGS_OFFSET		(0x18200)
+#define MV_MISC_REGS_BASE		(MV_MISC_REGS_OFFSET)
+#define SOC_CTRL_REG			(MV_MISC_REGS_BASE + 0x4)
+
+/*
+ * PCI Express Control and Status Registers
+ */
+#define MAX_PEX_DEVICES			32
+#define MAX_PEX_FUNCS			8
+#define MAX_PEX_BUSSES			256
+
+#define PXSR_PEX_BUS_NUM_OFFS		8	/* Bus Number Indication */
+#define PXSR_PEX_BUS_NUM_MASK		(0xff << PXSR_PEX_BUS_NUM_OFFS)
+
+#define PXSR_PEX_DEV_NUM_OFFS		16	/* Device Number Indication */
+#define PXSR_PEX_DEV_NUM_MASK		(0x1f << PXSR_PEX_DEV_NUM_OFFS)
+
+#define PXSR_DL_DOWN			0x1	/* DL_Down indication. */
+#define PXCAR_CONFIG_EN			(1 << 31)
+#define PEX_STATUS_AND_COMMAND		0x004
+#define PXSAC_MABORT			(1 << 29) /* Recieved Master Abort */
+
+/* PCI Express Configuration Address Register */
+
+/* PEX_CFG_ADDR_REG (PXCAR) */
+#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 PXCAR_REAL_EXT_REG_NUM_OFFS     8
+#define PXCAR_REAL_EXT_REG_NUM_MASK     (0xF << PXCAR_REAL_EXT_REG_NUM_OFFS)
+
+
+#define PEX_CAPABILITIES_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x60)
+#define PEX_LINK_CAPABILITIES_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x6C)
+#define PEX_LINK_CTRL_STATUS_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x70)
+#define PEX_LINK_CTRL_STATUS2_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x90)
+#define PEX_CTRL_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x1A00)
+#define PEX_STATUS_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x1A04)
+#define PEX_COMPLT_TMEOUT_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x1A10)
+#define PEX_PWR_MNG_EXT_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x1A18)
+#define PEX_FLOW_CTRL_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x1A20)
+#define PEX_DYNMC_WIDTH_MNG_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x1A30)
+#define PEX_ROOT_CMPLX_SSPL_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x1A0C)
+#define PEX_RAM_PARITY_CTRL_REG(if)	((MV_PEX_IF_REGS_BASE(if)) + 0x1A50)
+#define PEX_DBG_CTRL_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x1A60)
+#define PEX_DBG_STATUS_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x1A64)
+
+#define PXLCSR_NEG_LNK_GEN_OFFS		16	/* Negotiated Link GEN */
+#define PXLCSR_NEG_LNK_GEN_MASK		(0xf << PXLCSR_NEG_LNK_GEN_OFFS)
+#define PXLCSR_NEG_LNK_GEN_1_1		(0x1 << PXLCSR_NEG_LNK_GEN_OFFS)
+#define PXLCSR_NEG_LNK_GEN_2_0		(0x2 << PXLCSR_NEG_LNK_GEN_OFFS)
+
+#define PEX_CFG_ADDR_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x18F8)
+#define PEX_CFG_DATA_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x18FC)
+#define PEX_CAUSE_REG(if)		((MV_PEX_IF_REGS_BASE(if)) + 0x1900)
+
+#define PEX_CAPABILITY_REG		0x60
+#define PEX_DEV_CAPABILITY_REG		0x64
+#define PEX_DEV_CTRL_STAT_REG		0x68
+#define PEX_LINK_CAPABILITY_REG		0x6C
+#define PEX_LINK_CTRL_STAT_REG		0x70
+#define PEX_LINK_CTRL_STAT_2_REG	0x90
+
+#endif /* __BOARD_ENV_SPEC */
diff --git a/arch/arm/mvebu-common/serdes/high_speed_env_lib.c b/arch/arm/mvebu-common/serdes/high_speed_env_lib.c
new file mode 100644
index 0000000..702273a
--- /dev/null
+++ b/arch/arm/mvebu-common/serdes/high_speed_env_lib.c
@@ -0,0 +1,1572 @@
+/*
+ * 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 "board_env_spec.h"
+
+#define	SERDES_VERION	"2.1.5"
+#define ENDED_OK	"High speed PHY - Ended Successfully\n"
+
+static const u8 serdes_cfg[][SERDES_LAST_UNIT] = BIN_SERDES_CFG;
+
+extern MV_BIN_SERDES_CFG *serdes_info_tbl[];
+
+extern u8 rd78460gp_twsi_dev[];
+extern u8 db88f78xx0rev2_twsi_dev[];
+
+u32 pex_cfg_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 offs);
+int pex_local_bus_num_set(u32 pex_if, u32 bus_num);
+int pex_local_dev_num_set(u32 pex_if, u32 dev_num);
+
+#define MV_BOARD_PEX_MODULE_ADDR		0x23
+#define MV_BOARD_PEX_MODULE_ID			1
+#define MV_BOARD_ETM_MODULE_ID			2
+
+#define	PEX_MODULE_DETECT		1
+#define	ETM_MODULE_DETECT               2
+
+#define PEX_MODE_GET(satr)		((satr & 0x6) >> 1)
+#define PEX_CAPABILITY_GET(satr)	(satr & 1)
+#define MV_PEX_UNIT_TO_IF(pex_unit)	((pex_unit < 3) ? (pex_unit * 4) : 9)
+
+/* Static parametes */
+static int config_module;
+static int switch_module;
+
+/* Local function */
+static u32 board_id_get(void)
+{
+#if defined(CONFIG_DB_88F78X60)
+	return DB_88F78XX0_BP_ID;
+#elif defined(CONFIG_RD_88F78460_SERVER)
+	return RD_78460_SERVER_ID;
+#elif defined(CONFIG_RD_78460_SERVER_REV2)
+	return RD_78460_SERVER_REV2_ID;
+#elif defined(CONFIG_DB_78X60_PCAC)
+	return DB_78X60_PCAC_ID;
+#elif defined(CONFIG_DB_88F78X60_REV2)
+	return DB_88F78XX0_BP_REV2_ID;
+#elif defined(CONFIG_RD_78460_NAS)
+	return RD_78460_NAS_ID;
+#elif defined(CONFIG_DB_78X60_AMC)
+	return DB_78X60_AMC_ID;
+#elif defined(CONFIG_DB_78X60_PCAC_REV2)
+	return DB_78X60_PCAC_REV2_ID;
+#elif defined(CONFIG_DB_784MP_GP)
+	return DB_784MP_GP_ID;
+#elif defined(CONFIG_RD_78460_CUSTOMER)
+	return RD_78460_CUSTOMER_ID;
+#else
+	/*
+	 * Return 0 here for custom board as this should not be used
+	 * for custom boards.
+	 */
+	return 0;
+#endif
+}
+
+static u8 board_sat_r_get(u8 dev_num, u8 reg)
+{
+	u8 data;
+	u8 *dev;
+	u32 board_id = board_id_get();
+	int ret;
+
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	switch (board_id) {
+	case DB_784MP_GP_ID:
+		dev = rd78460gp_twsi_dev;
+
+		break;
+	case DB_88F78XX0_BP_ID:
+	case DB_88F78XX0_BP_REV2_ID:
+		dev = db88f78xx0rev2_twsi_dev;
+		break;
+
+	case DB_78X60_PCAC_ID:
+	case FPGA_88F78XX0_ID:
+	case DB_78X60_PCAC_REV2_ID:
+	case RD_78460_SERVER_REV2_ID:
+	default:
+		return 0;
+	}
+
+	/* Read MPP module ID */
+	ret = i2c_read(dev[dev_num], 0, 1, (u8 *)&data, 1);
+	if (ret)
+		return MV_ERROR;
+
+	return data;
+}
+
+static int board_modules_scan(void)
+{
+	u8 val;
+	u32 board_id = board_id_get();
+	int ret;
+
+	/* Perform scan only for DB board */
+	if ((board_id == DB_88F78XX0_BP_ID) ||
+	    (board_id == DB_88F78XX0_BP_REV2_ID)) {
+		/* reset modules flags */
+		config_module = 0;
+
+		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+		/* SERDES module (only PEX model is supported now) */
+		ret = i2c_read(MV_BOARD_PEX_MODULE_ADDR, 0, 1, (u8 *)&val, 1);
+		if (ret)
+			return MV_ERROR;
+
+		if (val == MV_BOARD_PEX_MODULE_ID)
+			config_module = PEX_MODULE_DETECT;
+		if (val == MV_BOARD_ETM_MODULE_ID)
+			config_module = ETM_MODULE_DETECT;
+	} else if (board_id == RD_78460_NAS_ID) {
+		switch_module = 0;
+		if ((reg_read(GPP_DATA_IN_REG(2)) & MV_GPP66) == 0x0)
+			switch_module = 1;
+	}
+
+	return MV_OK;
+}
+
+u32 pex_max_unit_get(void)
+{
+	/*
+	 * TODO:
+	 * Right now only MV78460 is supported. Other SoC's might need
+	 * a different value here.
+	 */
+	return MV_PEX_MAX_UNIT;
+}
+
+u32 pex_max_if_get(void)
+{
+	/*
+	 * TODO:
+	 * Right now only MV78460 is supported. Other SoC's might need
+	 * a different value here.
+	 */
+	return MV_PEX_MAX_IF;
+}
+
+u8 board_cpu_freq_get(void)
+{
+	u32 sar;
+	u32 sar_msb;
+
+	sar = reg_read(MPP_SAMPLE_AT_RESET(0));
+	sar_msb = reg_read(MPP_SAMPLE_AT_RESET(1));
+	return ((sar_msb & 0x100000) >> 17) | ((sar & 0xe00000) >> 21);
+}
+
+__weak MV_BIN_SERDES_CFG *board_serdes_cfg_get(u8 pex_mode)
+{
+	u32 board_id;
+	u32 serdes_cfg_val = 0;	/* default */
+
+	board_id = board_id_get();
+
+	switch (board_id) {
+	case DB_784MP_GP_ID:
+		serdes_cfg_val = 0;
+		break;
+	}
+
+	return &serdes_info_tbl[board_id - BOARD_ID_BASE][serdes_cfg_val];
+}
+
+u16 ctrl_model_get(void)
+{
+	/* Right now only MV78460 supported */
+	return MV_78460_DEV_ID;
+}
+
+u32 get_line_cfg(u32 line_num, MV_BIN_SERDES_CFG *info)
+{
+	if (line_num < 8)
+		return (info->line0_7 >> (line_num << 2)) & 0xF;
+	else
+		return (info->line8_15 >> ((line_num - 8) << 2)) & 0xF;
+}
+
+int serdes_phy_config(void)
+{
+	int status = MV_OK;
+	u32 line_cfg;
+	u8 line_num;
+	/* addr/value for each line @ every setup step */
+	u32 addr[16][11], val[16][11];
+	u8 pex_unit, pex_line_num;
+	u8 sgmii_port = 0;
+	u32 tmp;
+	u32 in_direct;
+	u8 max_serdes_lines;
+	MV_BIN_SERDES_CFG *info;
+	u8 satr11;
+	u8 sata_port;
+	u8 freq;
+	u8 device_rev;
+	u32 rx_high_imp_mode;
+	u16 ctrl_mode;
+	u32 board_id = board_id_get();
+	u32 pex_if;
+	u32 pex_if_num;
+
+	/*
+	 * TODO:
+	 * Right now we only support the MV78460 with 16 serdes lines
+	 */
+	max_serdes_lines = 16;
+	if (max_serdes_lines == 0)
+		return MV_OK;
+
+	switch (board_id) {
+	case DB_78X60_AMC_ID:
+	case DB_78X60_PCAC_REV2_ID:
+	case RD_78460_CUSTOMER_ID:
+	case RD_78460_SERVER_ID:
+	case RD_78460_SERVER_REV2_ID:
+	case DB_78X60_PCAC_ID:
+		satr11 = (0x1 << 1) | 1;
+		break;
+	case FPGA_88F78XX0_ID:
+	case RD_78460_NAS_ID:
+		satr11 = (0x0 << 1) | 1;
+		break;
+	case DB_88F78XX0_BP_REV2_ID:
+	case DB_784MP_GP_ID:
+	case DB_88F78XX0_BP_ID:
+		satr11 = board_sat_r_get(1, 1);
+		if ((u8) MV_ERROR == (u8) satr11)
+			return MV_ERROR;
+		break;
+	}
+
+	board_modules_scan();
+	memset(addr, 0, sizeof(addr));
+	memset(val, 0, sizeof(val));
+
+	/* Check if DRAM is already initialized  */
+	if (reg_read(REG_BOOTROM_ROUTINE_ADDR) &
+	    (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) {
+		DEBUG_INIT_S("High speed PHY - Version: ");
+		DEBUG_INIT_S(SERDES_VERION);
+		DEBUG_INIT_S(" - 2nd boot - Skip\n");
+		return MV_OK;
+	}
+	DEBUG_INIT_S("High speed PHY - Version: ");
+	DEBUG_INIT_S(SERDES_VERION);
+	DEBUG_INIT_S(" (COM-PHY-V20)\n");
+
+	/*
+	 * AVS :  disable AVS for frequency less than 1333
+	 */
+	freq = board_cpu_freq_get();
+	device_rev = mv_ctrl_rev_get();
+
+	if (device_rev == 2) {	/*   for B0 only */
+		u32 cpu_avs;
+		u8 fabric_freq;
+		cpu_avs = reg_read(CPU_AVS_CONTROL2_REG);
+		DEBUG_RD_REG(CPU_AVS_CONTROL2_REG, cpu_avs);
+		cpu_avs &= ~(1 << 9);
+
+		if ((0x4 == freq) || (0xB == freq)) {
+			u32 tmp2;
+
+			tmp2 = reg_read(CPU_AVS_CONTROL0_REG);
+			DEBUG_RD_REG(CPU_AVS_CONTROL0_REG, tmp2);
+			/* cpu upper limit = 1.1V  cpu lower limit = 0.9125V  */
+			tmp2 |= 0x0FF;
+			reg_write(CPU_AVS_CONTROL0_REG, tmp2);
+			DEBUG_WR_REG(CPU_AVS_CONTROL0_REG, tmp2);
+			cpu_avs |= (1 << 9);	/* cpu avs enable */
+			cpu_avs |= (1 << 18);	/* AvsAvddDetEn enable  */
+			fabric_freq = (reg_read(MPP_SAMPLE_AT_RESET(0)) &
+				       SAR0_FABRIC_FREQ_MASK) >> SAR0_FABRIC_FREQ_OFFSET;
+			if ((0xB == freq) && (5 == fabric_freq)) {
+				u32 core_avs;
+
+				core_avs = reg_read(CORE_AVS_CONTROL_0REG);
+				DEBUG_RD_REG(CORE_AVS_CONTROL_0REG, core_avs);
+
+				/*
+				 * Set core lower limit = 0.9V &
+				 * core upper limit = 0.9125V
+				 */
+				core_avs &= ~(0xff);
+				core_avs |= 0x0E;
+				reg_write(CORE_AVS_CONTROL_0REG, core_avs);
+				DEBUG_WR_REG(CORE_AVS_CONTROL_0REG, core_avs);
+
+				core_avs = reg_read(CORE_AVS_CONTROL_2REG);
+				DEBUG_RD_REG(CORE_AVS_CONTROL_2REG, core_avs);
+				core_avs |= (1 << 9);	/*  core AVS enable  */
+				reg_write(CORE_AVS_CONTROL_2REG, core_avs);
+				DEBUG_WR_REG(CORE_AVS_CONTROL_2REG, core_avs);
+
+				tmp2 = reg_read(GENERAL_PURPOSE_RESERVED0_REG);
+				DEBUG_RD_REG(GENERAL_PURPOSE_RESERVED0_REG,
+					     tmp2);
+				tmp2 |= 0x1;	/*  AvsCoreAvddDetEn enable   */
+				reg_write(GENERAL_PURPOSE_RESERVED0_REG, tmp2);
+				DEBUG_WR_REG(GENERAL_PURPOSE_RESERVED0_REG,
+					     tmp2);
+			}
+		}
+		reg_write(CPU_AVS_CONTROL2_REG, cpu_avs);
+		DEBUG_WR_REG(CPU_AVS_CONTROL2_REG, cpu_avs);
+	}
+
+	info = board_serdes_cfg_get(PEX_MODE_GET(satr11));
+	DEBUG_INIT_FULL_S("info->line0_7= 0x");
+	DEBUG_INIT_FULL_D(info->line0_7, 8);
+	DEBUG_INIT_FULL_S("   info->line8_15= 0x");
+	DEBUG_INIT_FULL_D(info->line8_15, 8);
+	DEBUG_INIT_FULL_S("\n");
+
+	if (info == NULL) {
+		DEBUG_INIT_S("Hight speed PHY Error #1\n");
+		return MV_ERROR;
+	}
+
+	if (config_module & ETM_MODULE_DETECT) {	/* step 0.9 ETM */
+		DEBUG_INIT_FULL_S("ETM module detect Step 0.9:\n");
+		reg_write(SERDES_LINE_MUX_REG_0_7, 0x11111111);
+		DEBUG_WR_REG(SERDES_LINE_MUX_REG_0_7, 0x11111111);
+		info->pex_mode[1] = PEX_BUS_DISABLED;	/* pex unit 1 is configure for ETM */
+		mdelay(100);
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x002 << 16) | 0xf44d);	/* SETM0 - start calibration         */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x002 << 16) | 0xf44d);	/* SETM0 - start calibration         */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x302 << 16) | 0xf44d);	/* SETM1 - start calibration         */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x302 << 16) | 0xf44d);	/* SETM1 - start calibration         */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x001 << 16) | 0xf801);	/* SETM0 - SATA mode & 25MHz ref clk */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x001 << 16) | 0xf801);	/* SETM0 - SATA mode & 25MHz ref clk */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x301 << 16) | 0xf801);	/* SETM1 - SATA mode & 25MHz ref clk */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x301 << 16) | 0xf801);	/* SETM1 - SATA mode & 25MHz ref clk */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x011 << 16) | 0x0BFF);	/* SETM0 - G3 full swing AMP         */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x011 << 16) | 0x0BFF);	/* SETM0 - G3 full swing AMP         */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x311 << 16) | 0x0BFF);	/* SETM1 - G3 full swing AMP         */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x311 << 16) | 0x0BFF);	/* SETM1 - G3 full swing AMP         */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x023 << 16) | 0x0800);	/* SETM0 - 40 data bit width         */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x023 << 16) | 0x0800);	/* SETM0 - 40 data bit width         */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x323 << 16) | 0x0800);	/* SETM1 - 40 data bit width         */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x323 << 16) | 0x0800);	/* SETM1 - 40 data bit width         */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x046 << 16) | 0x0400);	/* lane0(serdes4)                    */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x046 << 16) | 0x0400);	/* lane0(serdes4)                    */
+		reg_write(PEX_PHY_ACCESS_REG(1), (0x346 << 16) | 0x0400);	/* lane3(serdes7)                    */
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(1), (0x346 << 16) | 0x0400);	/* lane3(serdes7)                    */
+	}
+
+	/* STEP -1 [PEX-Only] First phase of PEX-PIPE Configuration: */
+	DEBUG_INIT_FULL_S("Step 1: First phase of PEX-PIPE Configuration\n");
+	for (pex_unit = 0; pex_unit < pex_max_unit_get(); pex_unit++) {
+		if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED)
+			continue;
+
+		/* 1.   GLOB_CLK_CTRL Reset and Clock Control */
+		reg_write(PEX_PHY_ACCESS_REG(pex_unit), (0xC1 << 16) | 0x25);
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit), (0xC1 << 16) | 0x25);
+
+		/* 2.   GLOB_TEST_CTRL Test Mode Control */
+		if (info->pex_mode[pex_unit] == PEX_BUS_MODE_X4) {
+			reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+				  (0xC2 << 16) | 0x200);
+			DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+				     (0xC2 << 16) | 0x200);
+		}
+
+		/* 3.   GLOB_CLK_SRC_LO Clock Source Low */
+		if (info->pex_mode[pex_unit] == PEX_BUS_MODE_X1) {
+			reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+				  (0xC3 << 16) | 0x0F);
+			DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+				     (0xC3 << 16) | 0x0F);
+		}
+
+		reg_write(PEX_PHY_ACCESS_REG(pex_unit), (0xC5 << 16) | 0x11F);
+		DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+			     (0xC5 << 16) | 0x11F);
+	}
+
+	/*
+	 * 2 Configure the desire PIN_PHY_GEN and do power down to the PU_PLL,
+	 * PU_RX,PU_TX. (bits[12:5])
+	 */
+	DEBUG_INIT_FULL_S("Step 2: Configure the desire PIN_PHY_GEN\n");
+	for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+		line_cfg = get_line_cfg(line_num, info);
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_UNCONNECTED])
+			continue;
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_PEX])
+			continue;
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SATA]) {
+			switch (line_num) {
+			case 4:
+			case 6:
+				sata_port = 0;
+				break;
+			case 5:
+				sata_port = 1;
+				break;
+			default:
+				DEBUG_INIT_C
+				    ("SATA port error for serdes line: ",
+				     line_num, 2);
+				return MV_ERROR;
+			}
+			tmp = reg_read(SATA_LP_PHY_EXT_CTRL_REG(sata_port));
+			DEBUG_RD_REG(SATA_LP_PHY_EXT_CTRL_REG(sata_port), tmp);
+			tmp &= ~((0x1ff << 5) | 0x7);
+			tmp |= ((info->bus_speed & (1 << line_num)) != 0) ?
+				(0x11 << 5) : 0x0;
+
+			reg_write(SATA_LP_PHY_EXT_CTRL_REG(sata_port), tmp);
+			DEBUG_WR_REG(SATA_LP_PHY_EXT_CTRL_REG(sata_port), tmp);
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_QSGMII]) {
+			/*
+			 * 4) Configure the desire PIN_PHY_GEN and do power
+			 * down to the PU_PLL,PU_RX,PU_TX. (bits[12:5])
+			 */
+			tmp = reg_read(SGMII_SERDES_CFG_REG(0));
+			DEBUG_RD_REG(SGMII_SERDES_CFG_REG(0), tmp);
+			tmp &= ~((0x1ff << 5) | 0x7);
+			tmp |= 0x660;
+			reg_write(SGMII_SERDES_CFG_REG(0), tmp);
+			DEBUG_WR_REG(SGMII_SERDES_CFG_REG(0), tmp);
+			continue;
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII0])
+			sgmii_port = 0;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII1])
+			sgmii_port = 1;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII2])
+			sgmii_port = 2;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII3])
+			sgmii_port = 3;
+		else
+			continue;
+
+		tmp = reg_read(SGMII_SERDES_CFG_REG(sgmii_port));
+		DEBUG_RD_REG(SGMII_SERDES_CFG_REG(sgmii_port), tmp);
+		tmp &= ~((0x1ff << 5) | 0x7);
+		tmp |= (((info->bus_speed & (1 << line_num)) != 0) ?
+			(0x88 << 5) : (0x66 << 5));
+		reg_write(SGMII_SERDES_CFG_REG(sgmii_port), tmp);
+		DEBUG_WR_REG(SGMII_SERDES_CFG_REG(sgmii_port), tmp);
+	}
+
+	/* Step 3 - QSGMII enable */
+	DEBUG_INIT_FULL_S("Step 3 QSGMII enable\n");
+	for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+		line_cfg = get_line_cfg(line_num, info);
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_QSGMII]) {
+			/* QSGMII Active bit set to true */
+			tmp = reg_read(QSGMII_CONTROL_1_REG);
+			DEBUG_RD_REG(QSGMII_CONTROL_1_REG, tmp);
+			tmp |= (1 << 30);
+#ifdef ERRATA_GL_6572255
+			tmp |= (1 << 27);
+#endif
+			reg_write(QSGMII_CONTROL_1_REG, tmp);
+			DEBUG_WR_REG(QSGMII_CONTROL_1_REG, tmp);
+		}
+	}
+
+	/* Step 4 - configure SERDES MUXes */
+	DEBUG_INIT_FULL_S("Step 4: Configure SERDES MUXes\n");
+	if (config_module & ETM_MODULE_DETECT) {
+		reg_write(SERDES_LINE_MUX_REG_0_7, 0x40041111);
+		DEBUG_WR_REG(SERDES_LINE_MUX_REG_0_7, 0x40041111);
+	} else {
+		reg_write(SERDES_LINE_MUX_REG_0_7, info->line0_7);
+		DEBUG_WR_REG(SERDES_LINE_MUX_REG_0_7, info->line0_7);
+	}
+	reg_write(SERDES_LINE_MUX_REG_8_15, info->line8_15);
+	DEBUG_WR_REG(SERDES_LINE_MUX_REG_8_15, info->line8_15);
+
+	/* Step 5: Activate the RX High Impedance Mode  */
+	DEBUG_INIT_FULL_S("Step 5: Activate the RX High Impedance Mode\n");
+	rx_high_imp_mode = 0x8080;
+	if (device_rev == 2)	/*   for B0 only */
+		rx_high_imp_mode |= 4;
+
+	for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+		/* for each serdes lane */
+		DEBUG_INIT_FULL_S("SERDES  ");
+		DEBUG_INIT_FULL_D_10(line_num, 2);
+		line_cfg = get_line_cfg(line_num, info);
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_UNCONNECTED]) {
+			DEBUG_INIT_FULL_S(" unconnected ***\n");
+			continue;
+		}
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_PEX]) {
+			pex_unit = line_num >> 2;
+			pex_line_num = line_num % 4;
+			DEBUG_INIT_FULL_S(" - PEX unit ");
+			DEBUG_INIT_FULL_D_10(pex_unit, 1);
+			DEBUG_INIT_FULL_S(" line=  ");
+			DEBUG_INIT_FULL_D_10(pex_line_num, 1);
+			DEBUG_INIT_FULL_S("\n");
+
+			/* Needed for PEX_PHY_ACCESS_REG macro */
+			if ((line_num > 7) &&
+			    (info->pex_mode[3] == PEX_BUS_MODE_X8))
+				/* lines 8 - 15 are belong to PEX3 in x8 mode */
+				pex_unit = 3;
+
+			if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED)
+				continue;
+
+			/*
+			 * 8)  Activate the RX High Impedance Mode field
+			 * (bit [2]) in register /PCIe_USB Control (Each MAC
+			 * contain different Access to reach its
+			 * Serdes-Regfile).
+			 * [PEX-Only] Set bit[12]: The analog part latches idle
+			 * if PU_TX = 1 and PU_PLL =1.
+			 */
+
+			/* Termination enable */
+			if (info->pex_mode[pex_unit] == PEX_BUS_MODE_X1) {
+				in_direct = (0x48 << 16) | (pex_line_num << 24) |
+					0x1000 | rx_high_imp_mode;	/* x1 */
+			} else if ((info->pex_mode[pex_unit] ==
+				    PEX_BUS_MODE_X4) && (pex_line_num == 0))
+				in_direct = (0x48 << 16) | (pex_line_num << 24) |
+					0x1000 | (rx_high_imp_mode & 0xff);	/* x4 */
+			else
+				in_direct = 0;
+
+			if (in_direct) {
+				reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+					  in_direct);
+				DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+					     in_direct);
+			}
+
+			continue;
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SATA]) {
+			/*
+			 * port 0 for serdes lines 4,6,  and port 1 for
+			 * serdes lines 5
+			 */
+			sata_port = line_num & 1;
+			DEBUG_INIT_FULL_S(" - SATA port  ");
+			DEBUG_INIT_FULL_D_10(sata_port, 2);
+			DEBUG_INIT_FULL_S("\n");
+			reg_write(SATA_COMPHY_CTRL_REG(sata_port),
+				  rx_high_imp_mode);
+			DEBUG_WR_REG(SATA_COMPHY_CTRL_REG(sata_port),
+				     rx_high_imp_mode);
+			continue;
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_QSGMII]) {
+			DEBUG_INIT_FULL_S(" - QSGMII\n");
+			reg_write(SGMII_COMPHY_CTRL_REG(0), rx_high_imp_mode);
+			DEBUG_WR_REG(SGMII_COMPHY_CTRL_REG(0),
+				     rx_high_imp_mode);
+			continue;
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII0])
+			sgmii_port = 0;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII1])
+			sgmii_port = 1;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII2])
+			sgmii_port = 2;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII3])
+			sgmii_port = 3;
+		else
+			continue;
+		DEBUG_INIT_FULL_S(" - SGMII port  ");
+		DEBUG_INIT_FULL_D_10(sgmii_port, 2);
+		DEBUG_INIT_FULL_S("\n");
+		reg_write(SGMII_COMPHY_CTRL_REG(sgmii_port), rx_high_imp_mode);
+		DEBUG_WR_REG(SGMII_COMPHY_CTRL_REG(sgmii_port),
+			     rx_high_imp_mode);
+	}			/* for each serdes lane */
+
+	/* Step 6 [PEX-Only] PEX-Main configuration (X4 or X1): */
+	DEBUG_INIT_FULL_S("Step 6: [PEX-Only] PEX-Main configuration (X4 or X1)\n");
+	tmp = reg_read(SOC_CTRL_REG);
+	DEBUG_RD_REG(SOC_CTRL_REG, tmp);
+	tmp &= 0x200;
+	if (info->pex_mode[0] == PEX_BUS_MODE_X1)
+		tmp |= PCIE0_QUADX1_EN;
+	if (info->pex_mode[1] == PEX_BUS_MODE_X1)
+		tmp |= PCIE1_QUADX1_EN;
+	if (((reg_read(MPP_SAMPLE_AT_RESET(0)) & PEX_CLK_100MHZ_MASK) >>
+	     PEX_CLK_100MHZ_OFFSET) == 0x1)
+		tmp |= (PCIE0_CLK_OUT_EN_MASK | PCIE1_CLK_OUT_EN_MASK);
+
+	reg_write(SOC_CTRL_REG, tmp);
+	DEBUG_WR_REG(SOC_CTRL_REG, tmp);
+
+	/* 6.2 PCI Express Link Capabilities */
+	DEBUG_INIT_FULL_S("Step 6.2: [PEX-Only] PCI Express Link Capabilities\n");
+
+	for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+		line_cfg = get_line_cfg(line_num, info);
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_PEX]) {
+			/*
+			 * PCI Express Control
+			 * 0xX1A00 [0]:
+			 * 0x0 X4-Link.
+			 * 0x1 X1-Link
+			 */
+			pex_unit = line_num >> 2;
+			pex_if = MV_SERDES_NUM_TO_PEX_NUM(line_num);
+			if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED)
+				continue;
+
+			/*  set Common Clock Configuration */
+			tmp = reg_read(PEX_LINK_CTRL_STATUS_REG(pex_if));
+			DEBUG_RD_REG(PEX_LINK_CTRL_STATUS_REG(pex_if), tmp);
+			tmp |= (1 << 6);
+			reg_write(PEX_LINK_CTRL_STATUS_REG(pex_if), tmp);
+			DEBUG_WR_REG(PEX_LINK_CTRL_STATUS_REG(pex_if), tmp);
+
+			tmp = reg_read(PEX_LINK_CAPABILITIES_REG(pex_if));
+			DEBUG_RD_REG(PEX_LINK_CAPABILITIES_REG(pex_if), tmp);
+			tmp &= ~(0x3FF);
+			if (info->pex_mode[pex_unit] == PEX_BUS_MODE_X1)
+				tmp |= (0x1 << 4);
+			if (info->pex_mode[pex_unit] == PEX_BUS_MODE_X4)
+				tmp |= (0x4 << 4);
+			if (0 == PEX_CAPABILITY_GET(satr11))
+				tmp |= 0x1;
+			else
+				tmp |= 0x2;
+			DEBUG_INIT_FULL_S("Step 6.2: PEX ");
+			DEBUG_INIT_FULL_D(pex_if, 1);
+			DEBUG_INIT_FULL_C(" set GEN", (tmp & 3), 1);
+			reg_write(PEX_LINK_CAPABILITIES_REG(pex_if), tmp);
+			DEBUG_WR_REG(PEX_LINK_CAPABILITIES_REG(pex_if), tmp);
+
+			/*
+			 * If pex is X4, no need to pass thru the other
+			 * 3X1 serdes lines
+			 */
+			if (info->pex_mode[pex_unit] == PEX_BUS_MODE_X4)
+				line_num += 3;
+		}
+	}
+
+	/*
+	 * Step 7 [PEX-X4 Only] To create PEX-Link that contain 4-lanes you
+	 * need to config the register SOC_Misc/General Purpose2
+	 * (Address= 182F8)
+	 */
+	DEBUG_INIT_FULL_S("Step 7: [PEX-X4 Only] To create PEX-Link\n");
+	tmp = reg_read(GEN_PURP_RES_2_REG);
+	DEBUG_RD_REG(GEN_PURP_RES_2_REG, tmp);
+
+	tmp &= 0xFFFF0000;
+	if (info->pex_mode[0] == PEX_BUS_MODE_X4)
+		tmp |= 0x0000000F;
+
+	if (info->pex_mode[1] == PEX_BUS_MODE_X4)
+		tmp |= 0x000000F0;
+
+	if (info->pex_mode[2] == PEX_BUS_MODE_X4)
+		tmp |= 0x00000F00;
+
+	if (info->pex_mode[3] == PEX_BUS_MODE_X4)
+		tmp |= 0x0000F000;
+
+	reg_write(GEN_PURP_RES_2_REG, tmp);
+	DEBUG_WR_REG(GEN_PURP_RES_2_REG, tmp);
+
+	/* Steps  8 , 9 ,10 - use prepared REG addresses and values */
+	DEBUG_INIT_FULL_S("Steps 7,8,9,10 and 11\n");
+
+	/* Prepare PHY parameters for each step according to  MUX selection */
+	for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+		/* for each serdes lane */
+
+		line_cfg = get_line_cfg(line_num, info);
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_UNCONNECTED])
+			continue;
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_PEX]) {
+			pex_unit = line_num >> 2;
+			pex_line_num = line_num % 4;
+
+			if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED)
+				continue;
+			/*
+			 * 8)   Configure the desire PHY_MODE (bits [7:5])
+			 * and REF_FREF_SEL (bits[4:0]) in the register Power
+			 * and PLL Control (Each MAC contain different Access
+			 * to reach its Serdes-Regfile).
+			 */
+			if (((info->pex_mode[pex_unit] == PEX_BUS_MODE_X4) &&
+			     (0 == pex_line_num))
+			    || ((info->pex_mode[pex_unit] == PEX_BUS_MODE_X1))) {
+				reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+					  (0x01 << 16) | (pex_line_num << 24) |
+					  0xFC60);
+				DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+					     (0x01 << 16) | (pex_line_num << 24)
+					     | 0xFC60);
+				/*
+				 * Step 8.1: [PEX-Only] Configure Max PLL Rate
+				 * (bit 8 in  KVCO Calibration Control and
+				 * bits[10:9] in
+				 */
+				/* Use Maximum PLL Rate(Bit 8) */
+				reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+					  (0x02 << 16) | (1 << 31) |
+					  (pex_line_num << 24)); /* read command */
+				DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+					     (0x02 << 16) | (1 << 31) |
+					     (pex_line_num << 24));
+				tmp = reg_read(PEX_PHY_ACCESS_REG(pex_unit));
+				DEBUG_RD_REG(PEX_PHY_ACCESS_REG(pex_unit), tmp);
+				tmp &= ~(1 << 31);
+				tmp |= (1 << 8);
+				reg_write(PEX_PHY_ACCESS_REG(pex_unit), tmp);
+				DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit), tmp);
+
+				/* Use Maximum PLL Rate(Bits [10:9]) */
+				reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+					  (0x81 << 16) | (1 << 31) |
+					  (pex_line_num << 24)); /* read command */
+				DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+					     (0x81 << 16) | (1 << 31) |
+					     (pex_line_num << 24));
+				tmp = reg_read(PEX_PHY_ACCESS_REG(pex_unit));
+				DEBUG_RD_REG(PEX_PHY_ACCESS_REG(pex_unit), tmp);
+				tmp &= ~(1 << 31);
+				tmp |= (3 << 9);
+				reg_write(PEX_PHY_ACCESS_REG(pex_unit), tmp);
+				DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit), tmp);
+			}
+
+			continue;
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SATA]) {
+			/*
+			 * Port 0 for serdes lines 4,6,  and port 1 for serdes
+			 * lines 5
+			 */
+			sata_port = line_num & 1;
+
+			/*
+			 * 8) Configure the desire PHY_MODE (bits [7:5]) and
+			 * REF_FREF_SEL (bits[4:0]) in the register Power
+			 * and PLL Control (Each MAC contain different Access
+			 * to reach its Serdes-Regfile).
+			 */
+			reg_write(SATA_PWR_PLL_CTRL_REG(sata_port), 0xF801);
+			DEBUG_WR_REG(SATA_PWR_PLL_CTRL_REG(sata_port), 0xF801);
+
+			/*  9)  Configure the desire SEL_BITS  */
+			reg_write(SATA_DIG_LP_ENA_REG(sata_port), 0x400);
+			DEBUG_WR_REG(SATA_DIG_LP_ENA_REG(sata_port), 0x400);
+
+			/* 10)  Configure the desire REFCLK_SEL */
+
+			reg_write(SATA_REF_CLK_SEL_REG(sata_port), 0x400);
+			DEBUG_WR_REG(SATA_REF_CLK_SEL_REG(sata_port), 0x400);
+
+			/* 11)  Power up to the PU_PLL,PU_RX,PU_TX.   */
+			tmp = reg_read(SATA_LP_PHY_EXT_CTRL_REG(sata_port));
+			DEBUG_RD_REG(SATA_LP_PHY_EXT_CTRL_REG(sata_port), tmp);
+			tmp |= 7;
+			reg_write(SATA_LP_PHY_EXT_CTRL_REG(sata_port), tmp);
+			DEBUG_WR_REG(SATA_LP_PHY_EXT_CTRL_REG(sata_port), tmp);
+
+			continue;
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_QSGMII]) {
+			/*
+			 * 8)   Configure the desire PHY_MODE (bits [7:5])
+			 * and REF_FREF_SEL (bits[4:0]) in the register
+			 */
+			reg_write(SGMII_PWR_PLL_CTRL_REG(0), 0xF881);
+			DEBUG_WR_REG(SGMII_PWR_PLL_CTRL_REG(0), 0xF881);
+
+			/*
+			 * 9)   Configure the desire SEL_BITS (bits [11:0]
+			 * in register
+			 */
+			reg_write(SGMII_DIG_LP_ENA_REG(0), 0x400);
+			DEBUG_WR_REG(SGMII_DIG_LP_ENA_REG(0), 0x400);
+
+			/*
+			 * 10)  Configure the desire REFCLK_SEL (bit [10])
+			 * in register
+			 */
+			reg_write(SGMII_REF_CLK_SEL_REG(0), 0x400);
+			DEBUG_WR_REG(SGMII_REF_CLK_SEL_REG(0), 0x400);
+
+			/* 11)  Power up to the PU_PLL,PU_RX,PU_TX.  */
+			tmp = reg_read(SGMII_SERDES_CFG_REG(0));
+			DEBUG_RD_REG(SGMII_SERDES_CFG_REG(0), tmp);
+			tmp |= 7;
+			reg_write(SGMII_SERDES_CFG_REG(0), tmp);
+			DEBUG_WR_REG(SGMII_SERDES_CFG_REG(0), tmp);
+			continue;
+		}
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII0])
+			sgmii_port = 0;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII1])
+			sgmii_port = 1;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII2])
+			sgmii_port = 2;
+		else if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SGMII3])
+			sgmii_port = 3;
+		else
+			continue;
+
+		/*
+		 * 8)   Configure the desire PHY_MODE (bits [7:5]) and
+		 * REF_FREF_SEL (bits[4:0]) in the register
+		 */
+		reg_write(SGMII_PWR_PLL_CTRL_REG(sgmii_port), 0xF881);
+		DEBUG_WR_REG(SGMII_PWR_PLL_CTRL_REG(sgmii_port), 0xF881);
+
+		/* 9)   Configure the desire SEL_BITS (bits [11:0] in register */
+		reg_write(SGMII_DIG_LP_ENA_REG(sgmii_port), 0);
+		DEBUG_WR_REG(SGMII_DIG_LP_ENA_REG(sgmii_port), 0);
+
+		/* 10)  Configure the desire REFCLK_SEL (bit [10]) in register  */
+		reg_write(SGMII_REF_CLK_SEL_REG(sgmii_port), 0x400);
+		DEBUG_WR_REG(SGMII_REF_CLK_SEL_REG(sgmii_port), 0x400);
+
+		/* 11)  Power up to the PU_PLL,PU_RX,PU_TX.  */
+		tmp = reg_read(SGMII_SERDES_CFG_REG(sgmii_port));
+		DEBUG_RD_REG(SGMII_SERDES_CFG_REG(sgmii_port), tmp);
+		tmp |= 7;
+		reg_write(SGMII_SERDES_CFG_REG(sgmii_port), tmp);
+		DEBUG_WR_REG(SGMII_SERDES_CFG_REG(sgmii_port), tmp);
+
+	}			/* for each serdes lane */
+
+	/* Step 12 [PEX-Only] Last phase of PEX-PIPE Configuration */
+	DEBUG_INIT_FULL_S("Steps 12: [PEX-Only] Last phase of PEX-PIPE Configuration\n");
+	for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+		/* for each serdes lane */
+
+		line_cfg = get_line_cfg(line_num, info);
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_UNCONNECTED])
+			continue;
+
+		if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_PEX]) {
+			pex_unit = line_num >> 2;
+			pex_line_num = line_num % 4;
+			if (0 == pex_line_num) {
+				reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+					  (0xC1 << 16) | 0x24);
+				DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),
+					     (0xC1 << 16) | 0x24);
+			}
+		}
+	}
+
+	/*--------------------------------------------------------------*/
+	/* Step 13: Wait 15ms before checking results */
+	DEBUG_INIT_FULL_S("Steps 13: Wait 15ms before checking results");
+	mdelay(15);
+	tmp = 20;
+	while (tmp) {
+		status = MV_OK;
+		for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+			u32 tmp;
+			line_cfg = get_line_cfg(line_num, info);
+			if (line_cfg ==
+			    serdes_cfg[line_num][SERDES_UNIT_UNCONNECTED])
+				continue;
+
+			if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_PEX])
+				continue;
+
+			if (line_cfg == serdes_cfg[line_num][SERDES_UNIT_SATA]) {
+				/*
+				 * Port 0 for serdes lines 4,6,  and port 1
+				 * for serdes lines 5
+				 */
+				sata_port = line_num & 1;
+
+				tmp =
+				    reg_read(SATA_LP_PHY_EXT_STAT_REG
+					     (sata_port));
+				DEBUG_RD_REG(SATA_LP_PHY_EXT_STAT_REG
+					     (sata_port), tmp);
+				if ((tmp & 0x7) != 0x7)
+					status = MV_ERROR;
+				continue;
+			}
+
+			if (line_cfg ==
+			    serdes_cfg[line_num][SERDES_UNIT_QSGMII]) {
+				tmp = reg_read(SGMII_SERDES_STAT_REG(0));
+				DEBUG_RD_REG(SGMII_SERDES_STAT_REG(0), tmp);
+				if ((tmp & 0x7) != 0x7)
+					status = MV_ERROR;
+				continue;
+			}
+
+			if (line_cfg ==
+			    serdes_cfg[line_num][SERDES_UNIT_SGMII0])
+				sgmii_port = 0;
+			else if (line_cfg ==
+				 serdes_cfg[line_num][SERDES_UNIT_SGMII1])
+				sgmii_port = 1;
+			else if (line_cfg ==
+				 serdes_cfg[line_num][SERDES_UNIT_SGMII2])
+				sgmii_port = 2;
+			else if (line_cfg ==
+				 serdes_cfg[line_num][SERDES_UNIT_SGMII3])
+				sgmii_port = 3;
+			else
+				continue;
+
+			tmp = reg_read(SGMII_SERDES_STAT_REG(sgmii_port));
+			DEBUG_RD_REG(SGMII_SERDES_STAT_REG(sgmii_port), tmp);
+			if ((tmp & 0x7) != 0x7)
+				status = MV_ERROR;
+		}
+
+		if (status == MV_OK)
+			break;
+		mdelay(5);
+		tmp--;
+	}
+
+	/*
+	 * Step14 [PEX-Only]  In order to configure RC/EP mode please write
+	 * to register 0x0060 bits
+	 */
+	DEBUG_INIT_FULL_S("Steps 14: [PEX-Only]  In order to configure\n");
+	for (pex_unit = 0; pex_unit < pex_max_unit_get(); pex_unit++) {
+		if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED)
+			continue;
+		tmp =
+		    reg_read(PEX_CAPABILITIES_REG(MV_PEX_UNIT_TO_IF(pex_unit)));
+		DEBUG_RD_REG(PEX_CAPABILITIES_REG(MV_PEX_UNIT_TO_IF(pex_unit)),
+			     tmp);
+		tmp &= ~(0xf << 20);
+		if (info->pex_type == MV_PEX_ROOT_COMPLEX)
+			tmp |= (0x4 << 20);
+		else
+			tmp |= (0x1 << 20);
+		reg_write(PEX_CAPABILITIES_REG(MV_PEX_UNIT_TO_IF(pex_unit)),
+			  tmp);
+		DEBUG_WR_REG(PEX_CAPABILITIES_REG(MV_PEX_UNIT_TO_IF(pex_unit)),
+			     tmp);
+	}
+
+	/*
+	 * Step 15 [PEX-Only] Only for EP mode set to Zero bits 19 and 16 of
+	 * register 0x1a60
+	 */
+	DEBUG_INIT_FULL_S("Steps 15: [PEX-Only]  In order to configure\n");
+	for (pex_unit = 0; pex_unit < pex_max_unit_get(); pex_unit++) {
+		if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED)
+			continue;
+		if (info->pex_type == MV_PEX_END_POINT) {
+			tmp =
+			    reg_read(PEX_DBG_CTRL_REG
+				     (MV_PEX_UNIT_TO_IF(pex_unit)));
+			DEBUG_RD_REG(PEX_DBG_CTRL_REG
+				     (MV_PEX_UNIT_TO_IF(pex_unit)), tmp);
+			tmp &= 0xfff6ffff;
+			reg_write(PEX_DBG_CTRL_REG(MV_PEX_UNIT_TO_IF(pex_unit)),
+				  tmp);
+			DEBUG_WR_REG(PEX_DBG_CTRL_REG
+				     (MV_PEX_UNIT_TO_IF(pex_unit)), tmp);
+		}
+	}
+
+	if (info->serdes_m_phy_change) {
+		MV_SERDES_CHANGE_M_PHY *serdes_m_phy_change;
+		u32 bus_speed;
+		for (line_num = 0; line_num < max_serdes_lines; line_num++) {
+			line_cfg = get_line_cfg(line_num, info);
+			if (line_cfg ==
+			    serdes_cfg[line_num][SERDES_UNIT_UNCONNECTED])
+				continue;
+			serdes_m_phy_change = info->serdes_m_phy_change;
+			bus_speed = info->bus_speed & (1 << line_num);
+			while (serdes_m_phy_change->type !=
+			       SERDES_UNIT_UNCONNECTED) {
+				switch (serdes_m_phy_change->type) {
+				case SERDES_UNIT_PEX:
+					if (line_cfg != SERDES_UNIT_PEX)
+						break;
+					pex_unit = line_num >> 2;
+					pex_line_num = line_num % 4;
+					if (info->pex_mode[pex_unit] ==
+					    PEX_BUS_DISABLED)
+						break;
+					if ((info->pex_mode[pex_unit] ==
+					     PEX_BUS_MODE_X4) && pex_line_num)
+						break;
+
+					if (bus_speed) {
+						reg_write(PEX_PHY_ACCESS_REG
+							  (pex_unit),
+							  (pex_line_num << 24) |
+							  serdes_m_phy_change->val_hi_speed);
+						DEBUG_WR_REG(PEX_PHY_ACCESS_REG
+							     (pex_unit),
+							     (pex_line_num <<
+							      24) |
+							     serdes_m_phy_change->val_hi_speed);
+					} else {
+						reg_write(PEX_PHY_ACCESS_REG
+							  (pex_unit),
+							  (pex_line_num << 24) |
+							  serdes_m_phy_change->val_low_speed);
+						DEBUG_WR_REG(PEX_PHY_ACCESS_REG
+							     (pex_unit),
+							     (pex_line_num <<
+							      24) |
+							     serdes_m_phy_change->val_low_speed);
+					}
+					break;
+				case SERDES_UNIT_SATA:
+					if (line_cfg != SERDES_UNIT_SATA)
+						break;
+					/*
+					 * Port 0 for serdes lines 4,6,  and
+					 * port 1 for serdes lines 5
+					 */
+					sata_port = line_num & 1;
+					if (bus_speed) {
+						reg_write(SATA_BASE_REG
+							  (sata_port) |
+							  serdes_m_phy_change->reg_hi_speed,
+							  serdes_m_phy_change->val_hi_speed);
+						DEBUG_WR_REG(SATA_BASE_REG
+							     (sata_port) |
+							     serdes_m_phy_change->reg_hi_speed,
+							     serdes_m_phy_change->val_hi_speed);
+					} else {
+						reg_write(SATA_BASE_REG
+							  (sata_port) |
+							  serdes_m_phy_change->reg_low_speed,
+							  serdes_m_phy_change->val_low_speed);
+						DEBUG_WR_REG(SATA_BASE_REG
+							     (sata_port) |
+							     serdes_m_phy_change->reg_low_speed,
+							     serdes_m_phy_change->val_low_speed);
+					}
+					break;
+				case SERDES_UNIT_SGMII0:
+				case SERDES_UNIT_SGMII1:
+				case SERDES_UNIT_SGMII2:
+				case SERDES_UNIT_SGMII3:
+					if (line_cfg == serdes_cfg[line_num]
+					    [SERDES_UNIT_SGMII0])
+						sgmii_port = 0;
+					else if (line_cfg ==
+						 serdes_cfg[line_num]
+						 [SERDES_UNIT_SGMII1])
+						sgmii_port = 1;
+					else if (line_cfg ==
+						 serdes_cfg[line_num]
+						 [SERDES_UNIT_SGMII2])
+						sgmii_port = 2;
+					else if (line_cfg ==
+						 serdes_cfg[line_num]
+						 [SERDES_UNIT_SGMII3])
+						sgmii_port = 3;
+					else
+						break;
+					if (bus_speed) {
+						reg_write(MV_ETH_REGS_BASE
+							  (sgmii_port) |
+							  serdes_m_phy_change->reg_hi_speed,
+							  serdes_m_phy_change->val_hi_speed);
+						DEBUG_WR_REG(MV_ETH_REGS_BASE
+							     (sgmii_port) |
+							     serdes_m_phy_change->reg_hi_speed,
+							     serdes_m_phy_change->val_hi_speed);
+					} else {
+						reg_write(MV_ETH_REGS_BASE
+							  (sgmii_port) |
+							  serdes_m_phy_change->reg_low_speed,
+							  serdes_m_phy_change->val_low_speed);
+						DEBUG_WR_REG(MV_ETH_REGS_BASE
+							     (sgmii_port) |
+							     serdes_m_phy_change->reg_low_speed,
+							     serdes_m_phy_change->val_low_speed);
+					}
+					break;
+				case SERDES_UNIT_QSGMII:
+					if (line_cfg != SERDES_UNIT_QSGMII)
+						break;
+					if (bus_speed) {
+						reg_write
+						    (serdes_m_phy_change->reg_hi_speed,
+						     serdes_m_phy_change->val_hi_speed);
+						DEBUG_WR_REG
+						    (serdes_m_phy_change->reg_hi_speed,
+						     serdes_m_phy_change->val_hi_speed);
+					} else {
+						reg_write
+						    (serdes_m_phy_change->reg_low_speed,
+						     serdes_m_phy_change->val_low_speed);
+						DEBUG_WR_REG
+						    (serdes_m_phy_change->reg_low_speed,
+						     serdes_m_phy_change->val_low_speed);
+					}
+					break;
+				default:
+					break;
+				}
+				serdes_m_phy_change++;
+			}
+		}
+	}
+
+	/* Step 16 [PEX-Only] Training Enable */
+	DEBUG_INIT_FULL_S("Steps 16: [PEX-Only] Training Enable");
+	tmp = reg_read(SOC_CTRL_REG);
+	DEBUG_RD_REG(SOC_CTRL_REG, tmp);
+	tmp &= ~(0x0F);
+	for (pex_unit = 0; pex_unit < pex_max_unit_get(); pex_unit++) {
+		reg_write(PEX_CAUSE_REG(pex_unit), 0);
+		DEBUG_WR_REG(PEX_CAUSE_REG(pex_unit), 0);
+		if (info->pex_mode[pex_unit] != PEX_BUS_DISABLED)
+			tmp |= (0x1 << pex_unit);
+	}
+	reg_write(SOC_CTRL_REG, tmp);
+	DEBUG_WR_REG(SOC_CTRL_REG, tmp);
+
+	/* Step 17: Speed change to target speed and width */
+	{
+		u32 tmp_reg, tmp_pex_reg;
+		u32 addr;
+		u32 first_busno, next_busno;
+		u32 max_link_width = 0;
+		u32 neg_link_width = 0;
+		pex_if_num = pex_max_if_get();
+		mdelay(150);
+		DEBUG_INIT_FULL_C("step 17: max_if= 0x", pex_if_num, 1);
+		next_busno = 0;
+		for (pex_if = 0; pex_if < pex_if_num; pex_if++) {
+			line_num = (pex_if <= 8) ? pex_if : 12;
+			line_cfg = get_line_cfg(line_num, info);
+			if (line_cfg != serdes_cfg[line_num][SERDES_UNIT_PEX])
+				continue;
+			pex_unit = (pex_if < 9) ? (pex_if >> 2) : 3;
+			DEBUG_INIT_FULL_S("step 17:  PEX");
+			DEBUG_INIT_FULL_D(pex_if, 1);
+			DEBUG_INIT_FULL_C("  pex_unit= ", pex_unit, 1);
+
+			if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED) {
+				DEBUG_INIT_FULL_C("PEX disabled interface ",
+						  pex_if, 1);
+				if (pex_if < 8)
+					pex_if += 3;
+				continue;
+			}
+			first_busno = next_busno;
+			if ((info->pex_type == MV_PEX_END_POINT) &&
+			    (0 == pex_if)) {
+				if ((pex_if < 8) && (info->pex_mode[pex_unit] ==
+						     PEX_BUS_MODE_X4))
+					pex_if += 3;
+				continue;
+			}
+
+			tmp = reg_read(PEX_DBG_STATUS_REG(pex_if));
+			DEBUG_RD_REG(PEX_DBG_STATUS_REG(pex_if), tmp);
+			if ((tmp & 0x7f) == 0x7e) {
+				next_busno++;
+				tmp = reg_read(PEX_LINK_CAPABILITIES_REG(pex_if));
+				max_link_width = tmp;
+				DEBUG_RD_REG((PEX_LINK_CAPABILITIES_REG
+					      (pex_if)), tmp);
+				max_link_width = ((max_link_width >> 4) & 0x3F);
+				neg_link_width =
+				    reg_read(PEX_LINK_CTRL_STATUS_REG(pex_if));
+				DEBUG_RD_REG((PEX_LINK_CTRL_STATUS_REG(pex_if)),
+					     neg_link_width);
+				neg_link_width = ((neg_link_width >> 20) & 0x3F);
+				if (max_link_width > neg_link_width) {
+					tmp &= ~(0x3F << 4);
+					tmp |= (neg_link_width << 4);
+					reg_write(PEX_LINK_CAPABILITIES_REG
+						  (pex_if), tmp);
+					DEBUG_WR_REG((PEX_LINK_CAPABILITIES_REG
+						      (pex_if)), tmp);
+					mdelay(1);	/* wait 1ms before reading  capability for speed */
+					DEBUG_INIT_S("PEX");
+					DEBUG_INIT_D(pex_if, 1);
+					DEBUG_INIT_C(": change width to X",
+						     neg_link_width, 1);
+				}
+				tmp_pex_reg =
+				    reg_read((PEX_CFG_DIRECT_ACCESS
+					      (pex_if,
+					       PEX_LINK_CAPABILITY_REG)));
+				DEBUG_RD_REG((PEX_CFG_DIRECT_ACCESS
+					      (pex_if,
+					       PEX_LINK_CAPABILITY_REG)),
+					     tmp_pex_reg);
+				tmp_pex_reg &= (0xF);
+				if (tmp_pex_reg == 0x2) {
+					tmp_reg =
+					    (reg_read
+					     (PEX_CFG_DIRECT_ACCESS
+					      (pex_if,
+					       PEX_LINK_CTRL_STAT_REG)) &
+					     0xF0000) >> 16;
+					DEBUG_RD_REG(PEX_CFG_DIRECT_ACCESS
+						     (pex_if,
+						      PEX_LINK_CTRL_STAT_REG),
+						     tmp_pex_reg);
+					/* check if the link established is GEN1 */
+					if (tmp_reg == 0x1) {
+						pex_local_bus_num_set(pex_if,
+								      first_busno);
+						pex_local_dev_num_set(pex_if,
+								      1);
+
+						DEBUG_INIT_FULL_S("** Link is Gen1, check the EP capability\n");
+						/* link is Gen1, check the EP capability */
+						addr =
+						    pex_cfg_read(pex_if,
+								 first_busno, 0,
+								 0,
+								 0x34) & 0xFF;
+						DEBUG_INIT_FULL_C("pex_cfg_read: return addr=0x%x",
+						     addr, 4);
+						if (addr == 0xff) {
+							DEBUG_INIT_FULL_C("pex_cfg_read: return 0xff -->PEX (%d): Detected No Link.",
+									  pex_if, 1);
+							continue;
+						}
+						while ((pex_cfg_read
+							(pex_if, first_busno, 0,
+							 0,
+							 addr) & 0xFF) !=
+						       0x10) {
+							addr =
+							    (pex_cfg_read
+							     (pex_if,
+							      first_busno, 0, 0,
+							      addr) & 0xFF00) >>
+							    8;
+						}
+						if ((pex_cfg_read
+						     (pex_if, first_busno, 0, 0,
+						      addr + 0xC) & 0xF) >=
+						    0x2) {
+							tmp =
+							    reg_read
+							    (PEX_LINK_CTRL_STATUS2_REG
+							     (pex_if));
+							DEBUG_RD_REG
+							    (PEX_LINK_CTRL_STATUS2_REG
+							     (pex_if), tmp);
+							tmp &= ~(0x1 | 1 << 1);
+							tmp |= (1 << 1);
+							reg_write
+							    (PEX_LINK_CTRL_STATUS2_REG
+							     (pex_if), tmp);
+							DEBUG_WR_REG
+							    (PEX_LINK_CTRL_STATUS2_REG
+							     (pex_if), tmp);
+
+							tmp =
+							    reg_read
+							    (PEX_CTRL_REG
+							     (pex_if));
+							DEBUG_RD_REG
+							    (PEX_CTRL_REG
+							     (pex_if), tmp);
+							tmp |= (1 << 10);
+							reg_write(PEX_CTRL_REG
+								  (pex_if),
+								  tmp);
+							DEBUG_WR_REG
+							    (PEX_CTRL_REG
+							     (pex_if), tmp);
+							mdelay(10);	/* We need to wait 10ms before reading the PEX_DBG_STATUS_REG in order not to read the status of the former state */
+							DEBUG_INIT_FULL_S
+							    ("Gen2 client!\n");
+						} else {
+							DEBUG_INIT_FULL_S
+							    ("GEN1 client!\n");
+						}
+					}
+				}
+			} else {
+				DEBUG_INIT_FULL_S("PEX");
+				DEBUG_INIT_FULL_D(pex_if, 1);
+				DEBUG_INIT_FULL_S(" : Detected No Link. Status Reg(0x");
+				DEBUG_INIT_FULL_D(PEX_DBG_STATUS_REG(pex_if),
+						  8);
+				DEBUG_INIT_FULL_C(") = 0x", tmp, 8);
+			}
+
+			if ((pex_if < 8) &&
+			    (info->pex_mode[pex_unit] == PEX_BUS_MODE_X4))
+				pex_if += 3;
+		}
+	}
+
+	/* Step 18: update pex DEVICE ID */
+	{
+		u32 devId;
+		pex_if_num = pex_max_if_get();
+		ctrl_mode = ctrl_model_get();
+		for (pex_if = 0; pex_if < pex_if_num; pex_if++) {
+			pex_unit = (pex_if < 9) ? (pex_if >> 2) : 3;
+			if (info->pex_mode[pex_unit] == PEX_BUS_DISABLED) {
+				if ((pex_if < 8) &&
+				    (info->pex_mode[pex_unit] == PEX_BUS_MODE_X4))
+					pex_if += 3;
+				continue;
+			}
+
+			devId = reg_read(PEX_CFG_DIRECT_ACCESS(
+						 pex_if, PEX_DEVICE_AND_VENDOR_ID));
+			devId &= 0xFFFF;
+			devId |= ((ctrl_mode << 16) & 0xffff0000);
+			DEBUG_INIT_S("Update Device ID PEX");
+			DEBUG_INIT_D(pex_if, 1);
+			DEBUG_INIT_D(devId, 8);
+			DEBUG_INIT_S("\n");
+			reg_write(PEX_CFG_DIRECT_ACCESS
+				  (pex_if, PEX_DEVICE_AND_VENDOR_ID), devId);
+			if ((pex_if < 8) &&
+			    (info->pex_mode[pex_unit] == PEX_BUS_MODE_X4))
+				pex_if += 3;
+		}
+		DEBUG_INIT_S("Update PEX Device ID 0x");
+		DEBUG_INIT_D(ctrl_mode, 4);
+		DEBUG_INIT_S("0\n");
+	}
+	tmp = reg_read(PEX_DBG_STATUS_REG(0));
+	DEBUG_RD_REG(PEX_DBG_STATUS_REG(0), tmp);
+
+	DEBUG_INIT_S(ENDED_OK);
+	return MV_OK;
+}
+
+/* PEX configuration space read write */
+
+/*
+ * pex_cfg_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 mvPexLocalBusNumGet(). 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.
+ *       offss - Register offset.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       32bit register data, 0xffffffff on error
+ *
+ */
+u32 pex_cfg_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 offs)
+{
+	u32 pex_data = 0;
+	u32 local_dev, local_bus;
+	u32 val;
+
+	if (pex_if >= MV_PEX_MAX_IF)
+		return 0xFFFFFFFF;
+
+	if (dev >= MAX_PEX_DEVICES) {
+		DEBUG_INIT_C("pex_cfg_read: ERR. device number illigal ", dev,
+			     1);
+		return 0xFFFFFFFF;
+	}
+
+	if (func >= MAX_PEX_FUNCS) {
+		DEBUG_INIT_C("pex_cfg_read: ERR. function num illigal ", func,
+			     1);
+		return 0xFFFFFFFF;
+	}
+
+	if (bus >= MAX_PEX_BUSSES) {
+		DEBUG_INIT_C("pex_cfg_read: ERR. bus number illigal ", bus, 1);
+		return MV_ERROR;
+	}
+	val = reg_read(PEX_STATUS_REG(pex_if));
+
+	local_dev =
+	    ((val & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS);
+	local_bus =
+	    ((val & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS);
+
+	/* Speed up the process. In case on no link, return MV_ERROR */
+	if ((dev != local_dev) || (bus != local_bus)) {
+		pex_data = reg_read(PEX_STATUS_REG(pex_if));
+
+		if ((pex_data & PXSR_DL_DOWN))
+			return MV_ERROR;
+	}
+
+	/*
+	 * 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);
+	pex_data |= (offs & PXCAR_REG_NUM_MASK);	/* lgacy register space */
+	/* extended register space */
+	pex_data |= (((offs & 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;
+}
+
+/*
+ * pex_local_bus_num_set - Set PEX interface local bus number.
+ *
+ * DESCRIPTION:
+ *       This function sets given PEX interface its local bus number.
+ *       Note: In case the PEX interface is PEX-X, the information is read-only.
+ *
+ * INPUT:
+ *       pex_if  - PEX interface number.
+ *       bus_num - Bus number.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       MV_NOT_ALLOWED in case PEX interface is PEX-X.
+ *		MV_BAD_PARAM on bad parameters ,
+ *       otherwise MV_OK
+ *
+ */
+int pex_local_bus_num_set(u32 pex_if, u32 bus_num)
+{
+	u32 val;
+
+	if (bus_num >= MAX_PEX_BUSSES) {
+		DEBUG_INIT_C("pex_local_bus_num_set: ERR. bus number illigal %d\n",
+		     bus_num, 4);
+		return MV_ERROR;
+	}
+
+	val = reg_read(PEX_STATUS_REG(pex_if));
+	val &= ~PXSR_PEX_BUS_NUM_MASK;
+	val |= (bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK;
+	reg_write(PEX_STATUS_REG(pex_if), val);
+
+	return MV_OK;
+}
+
+/*
+ * pex_local_dev_num_set - Set PEX interface local device number.
+ *
+ * DESCRIPTION:
+ *       This function sets given PEX interface its local device number.
+ *       Note: In case the PEX interface is PEX-X, the information is read-only.
+ *
+ * INPUT:
+ *       pex_if  - PEX interface number.
+ *       dev_num - Device number.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       MV_NOT_ALLOWED in case PEX interface is PEX-X.
+ *		MV_BAD_PARAM on bad parameters ,
+ *       otherwise MV_OK
+ *
+ */
+int pex_local_dev_num_set(u32 pex_if, u32 dev_num)
+{
+	u32 val;
+
+	if (pex_if >= MV_PEX_MAX_IF)
+		return MV_BAD_PARAM;
+
+	val = reg_read(PEX_STATUS_REG(pex_if));
+	val &= ~PXSR_PEX_DEV_NUM_MASK;
+	val |= (dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK;
+	reg_write(PEX_STATUS_REG(pex_if), val);
+
+	return MV_OK;
+}
diff --git a/arch/arm/mvebu-common/serdes/high_speed_env_spec.c b/arch/arm/mvebu-common/serdes/high_speed_env_spec.c
new file mode 100644
index 0000000..115ec2c
--- /dev/null
+++ b/arch/arm/mvebu-common/serdes/high_speed_env_spec.c
@@ -0,0 +1,185 @@
+/*
+ * 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"
+
+MV_SERDES_CHANGE_M_PHY serdes_change_m_phy[] = {
+	/* SERDES TYPE, Low REG OFFS, Low REG VALUE, Hi REG OFS, Hi REG VALUE */
+	{
+		/* PEX: Change of Slew Rate port0   */
+		SERDES_UNIT_PEX, 0x0,
+		(0x0F << 16) | 0x2a21, 0x0, (0x0F << 16) | 0x2a21
+	}, {
+		/* PEX: Change PLL BW port0                   */
+		SERDES_UNIT_PEX, 0x0,
+		(0x4F << 16) | 0x6219, 0x0, (0x4F << 16) | 0x6219
+	}, {
+		/* SATA: Slew rate change port 0  */
+		SERDES_UNIT_SATA, 0x0083C, 0x8a31, 0x0083C, 0x8a31
+	}, {
+		/* SATA: Slew rate change port 0  */
+		SERDES_UNIT_SATA, 0x00834, 0xc928, 0x00834, 0xc928
+	}, {
+		/* SATA: Slew rate change port 0  */
+		SERDES_UNIT_SATA, 0x00838, 0x30f0, 0x00838, 0x30f0
+	}, {
+		/* SATA: Slew rate change port 0  */
+		SERDES_UNIT_SATA, 0x00840, 0x30f5, 0x00840, 0x30f5
+	}, {
+		/* SGMII: FFE setting Port0         */
+		SERDES_UNIT_SGMII0, 0x00E18, 0x989F, 0x00E18, 0x989F
+	}, {
+		/* SGMII: SELMUP and SELMUF Port0   */
+		SERDES_UNIT_SGMII0, 0x00E38, 0x10FA, 0x00E38, 0x10FA
+	}, {
+		/* SGMII: Amplitude new setting gen2 Port3 */
+		SERDES_UNIT_SGMII0, 0x00E34, 0xC968, 0x00E34, 0xC66C
+	}, {
+		/* QSGMII: Amplitude and slew rate change  */
+		SERDES_UNIT_QSGMII, 0x72E34, 0xaa58, 0x72E34, 0xaa58
+	}, {
+		/* QSGMII: SELMUP and SELMUF               */
+		SERDES_UNIT_QSGMII, 0x72e38, 0x10aF, 0x72e38, 0x10aF
+	}, {
+		/* QSGMII: 0x72e18                         */
+		SERDES_UNIT_QSGMII, 0x72e18, 0x98AC, 0x72e18, 0x98AC
+	}, {
+		/* Null terminated */
+		SERDES_UNIT_UNCONNECTED, 0, 0
+	}
+};
+
+MV_BIN_SERDES_CFG db88f78xx0_serdes_cfg[] = {
+	/* Z1B */
+	{MV_PEX_ROOT_COMPLEX, 0x32221111, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy},			/* Default */
+	{MV_PEX_ROOT_COMPLEX, 0x31211111, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy},			/* PEX module */
+	/* Z1A */
+	{MV_PEX_ROOT_COMPLEX, 0x32220000, 0x00000000,
+	 {PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED,
+	  PEX_BUS_DISABLED}, 0x0030, serdes_change_m_phy}, /* Default - Z1A */
+	{MV_PEX_ROOT_COMPLEX, 0x31210000, 0x00000000,
+	 {PEX_BUS_DISABLED, PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0030, serdes_change_m_phy}	/* PEX module - Z1A */
+};
+
+MV_BIN_SERDES_CFG db88f78xx0rev2_serdes_cfg[] = {
+	/* A0 */
+	{MV_PEX_ROOT_COMPLEX, 0x33221111, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}, /* Default: No Pex module, PEX0 x1, disabled */
+	{MV_PEX_ROOT_COMPLEX, 0x33211111, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x1, PEX1 x1 */
+	{MV_PEX_ROOT_COMPLEX, 0x33221111, 0x11111111,
+	 {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}, /* no Pex module, PEX0 x4, PEX1 disabled */
+	{MV_PEX_ROOT_COMPLEX, 0x33211111, 0x11111111,
+	 {PEX_BUS_MODE_X4, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x4, PEX1 x1 */
+	{MV_PEX_ROOT_COMPLEX, 0x11111111, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x1, PEX1 x4 */
+	{MV_PEX_ROOT_COMPLEX, 0x11111111, 0x11111111,
+	 {PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x4, PEX1 x4 */
+};
+
+MV_BIN_SERDES_CFG rd78460nas_serdes_cfg[] = {
+	{MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}, /* Default */
+	{MV_PEX_ROOT_COMPLEX, 0x33320201, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x00f4, serdes_change_m_phy}, /* Switch module */
+};
+
+MV_BIN_SERDES_CFG rd78460_serdes_cfg[] = {
+	{MV_PEX_ROOT_COMPLEX, 0x22321111, 0x00000000,
+	 {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0010, serdes_change_m_phy}, /* CPU0 */
+	{MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
+	 {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0010, serdes_change_m_phy} /* CPU1-3 */
+};
+
+MV_BIN_SERDES_CFG rd78460server_rev2_serdes_cfg[] = {
+	{MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
+	 {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0010, serdes_change_m_phy}, /* CPU0 */
+	{MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
+	 {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0010, serdes_change_m_phy} /* CPU1-3 */
+};
+
+MV_BIN_SERDES_CFG db78X60pcac_serdes_cfg[] = {
+	{MV_PEX_END_POINT, 0x22321111, 0x00000000,
+	 {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0010, serdes_change_m_phy}	/* Default */
+};
+
+MV_BIN_SERDES_CFG db78X60pcacrev2_serdes_cfg[] = {
+	{MV_PEX_END_POINT, 0x23321111, 0x00000000,
+	 {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0010, serdes_change_m_phy}	/* Default */
+};
+
+MV_BIN_SERDES_CFG fpga88f78xx0_serdes_cfg[] = {
+	{MV_PEX_ROOT_COMPLEX, 0x00000000, 0x00000000,
+	 {PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+	 0x0000, serdes_change_m_phy}	/* No PEX in FPGA */
+};
+
+MV_BIN_SERDES_CFG db78X60amc_serdes_cfg[] = {
+	{MV_PEX_ROOT_COMPLEX, 0x33111111, 0x00010001,
+	 {PEX_BUS_MODE_X4, PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X1},
+	 0x0030, serdes_change_m_phy}	/* Default */
+};
+
+/*
+ * ARMADA-XP CUSTOMER BOARD
+ */
+MV_BIN_SERDES_CFG rd78460customer_serdes_cfg[] = {
+	{MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x00000030, serdes_change_m_phy}, /* Default */
+	{MV_PEX_ROOT_COMPLEX, 0x33320201, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x00000030, serdes_change_m_phy}, /* Switch module */
+};
+
+MV_BIN_SERDES_CFG rd78460AXP_GP_serdes_cfg[] = {
+	{MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
+	 {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+	 0x0030, serdes_change_m_phy}	/* Default */
+};
+
+MV_BIN_SERDES_CFG *serdes_info_tbl[] = {
+	db88f78xx0_serdes_cfg,
+	rd78460_serdes_cfg,
+	db78X60pcac_serdes_cfg,
+	fpga88f78xx0_serdes_cfg,
+	db88f78xx0rev2_serdes_cfg,
+	rd78460nas_serdes_cfg,
+	db78X60amc_serdes_cfg,
+	db78X60pcacrev2_serdes_cfg,
+	rd78460server_rev2_serdes_cfg,
+	rd78460AXP_GP_serdes_cfg,
+	rd78460customer_serdes_cfg
+};
+
+u8 rd78460gp_twsi_dev[] = { 0x4C, 0x4D, 0x4E };
+u8 db88f78xx0rev2_twsi_dev[] = { 0x4C, 0x4D, 0x4E, 0x4F };
diff --git a/arch/arm/mvebu-common/serdes/high_speed_env_spec.h b/arch/arm/mvebu-common/serdes/high_speed_env_spec.h
new file mode 100644
index 0000000..e5aa1b0
--- /dev/null
+++ b/arch/arm/mvebu-common/serdes/high_speed_env_spec.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __HIGHSPEED_ENV_SPEC_H
+#define __HIGHSPEED_ENV_SPEC_H
+
+#include "../../../drivers/ddr/mvebu/ddr3_hw_training.h"
+
+typedef enum {
+	SERDES_UNIT_UNCONNECTED	= 0x0,
+	SERDES_UNIT_PEX		= 0x1,
+	SERDES_UNIT_SATA	= 0x2,
+	SERDES_UNIT_SGMII0	= 0x3,
+	SERDES_UNIT_SGMII1	= 0x4,
+	SERDES_UNIT_SGMII2	= 0x5,
+	SERDES_UNIT_SGMII3	= 0x6,
+	SERDES_UNIT_QSGMII	= 0x7,
+	SERDES_UNIT_SETM        = 0x8,
+	SERDES_LAST_UNIT
+} MV_BIN_SERDES_UNIT_INDX;
+
+
+typedef enum {
+	PEX_BUS_DISABLED	= 0,
+	PEX_BUS_MODE_X1		= 1,
+	PEX_BUS_MODE_X4		= 2,
+	PEX_BUS_MODE_X8		= 3
+} MV_PEX_UNIT_CFG;
+
+typedef enum pex_type {
+	MV_PEX_ROOT_COMPLEX,	/* root complex device */
+	MV_PEX_END_POINT	/* end point device */
+} MV_PEX_TYPE;
+
+typedef struct serdes_change_m_phy {
+	MV_BIN_SERDES_UNIT_INDX type;
+	u32 reg_low_speed;
+	u32 val_low_speed;
+	u32 reg_hi_speed;
+	u32 val_hi_speed;
+} MV_SERDES_CHANGE_M_PHY;
+
+/*
+ * Configuration per SERDES line. Each nibble is MV_SERDES_LINE_TYPE
+ */
+typedef struct board_serdes_conf {
+	MV_PEX_TYPE pex_type; /* MV_PEX_ROOT_COMPLEX MV_PEX_END_POINT */
+	u32 line0_7; /* Lines 0 to 7 SERDES MUX one nibble per line */
+	u32 line8_15; /* Lines 8 to 15 SERDES MUX one nibble per line */
+	MV_PEX_UNIT_CFG pex_mode[4];
+
+	/*
+	 * Bus speed - one bit per SERDES line:
+	 *		Low speed (0)		High speed (1)
+	 * PEX		2.5 G (10 bit)		5 G (20 bit)
+	 * SATA		1.5 G			3 G
+	 * SGMII	1.25 Gbps		3.125 Gbps
+	 */
+	u32	bus_speed;
+
+	MV_SERDES_CHANGE_M_PHY *serdes_m_phy_change;
+} MV_BIN_SERDES_CFG;
+
+
+#define BIN_SERDES_CFG {	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 0 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1,  2}, /* Lane 1 */	\
+	{0, 1, -1 ,  2, -1, -1, -1, -1,  3}, /* Lane 2 */	\
+	{0, 1, -1 , -1,  2, -1, -1,  3, -1}, /* Lane 3 */	\
+	{0, 1,  2 , -1, -1,  3, -1, -1,  4}, /* Lane 4 */	\
+	{0, 1,  2 , -1,  3, -1, -1,  4, -1}, /* Lane 5 */	\
+	{0, 1,  2 ,  4, -1,  3, -1, -1, -1}, /* Lane 6 */	\
+	{0, 1, -1 ,  2, -1, -1,  3, -1,  4}, /* Lane 7*/	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 8 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 9 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 10 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 11 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 12 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 13 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 14 */	\
+	{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 15 */	\
+}
+
+#endif /* __HIGHSPEED_ENV_SPEC_H */
diff --git a/arch/arm/mvebu-common/u-boot-spl.lds b/arch/arm/mvebu-common/u-boot-spl.lds
new file mode 100644
index 0000000..eee1db4
--- /dev/null
+++ b/arch/arm/mvebu-common/u-boot-spl.lds
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *	Aneesh V <aneesh@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
+		LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+		LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+	.text      :
+	{
+		__start = .;
+		arch/arm/cpu/armv7/start.o	(.text*)
+		*(.text*)
+		*(.vectors)
+	} >.sram
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+	. = ALIGN(4);
+	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+	. = ALIGN(4);
+	.u_boot_list : {
+		KEEP(*(SORT(.u_boot_list*_i2c_*)));
+	} >.sram
+
+	. = ALIGN(4);
+	__image_copy_end = .;
+
+	.end :
+	{
+		*(.__end)
+	}
+
+	.bss :
+	{
+		. = ALIGN(4);
+		__bss_start = .;
+		*(.bss*)
+		. = ALIGN(4);
+		__bss_end = .;
+	} >.sdram
+}
diff --git a/board/Marvell/db-mv784mp-gp/binary.0 b/board/Marvell/db-mv784mp-gp/binary.0
deleted file mode 100644
index 17bfad9..0000000
--- a/board/Marvell/db-mv784mp-gp/binary.0
+++ /dev/null
@@ -1,17 +0,0 @@
---------
-WARNING:
---------
-This file should contain the bin_hdr generated by the original Marvell
-U-Boot implementation. As this is currently not included in this
-U-Boot version, we have added this placeholder, so that the U-Boot
-image can be generated without errors.
-
-If you have a known to be working bin_hdr for your board, then you
-just need to replace this text file here with the binary header
-and recompile U-Boot.
-
-In a few weeks, mainline U-Boot will get support to generate the
-bin_hdr with the DDR training code itself. By implementing this code
-as SPL U-Boot. Then this file will not be needed any more and will
-get removed.
-
diff --git a/board/Marvell/db-mv784mp-gp/kwbimage.cfg b/board/Marvell/db-mv784mp-gp/kwbimage.cfg
index d7ef407..cc05792 100644
--- a/board/Marvell/db-mv784mp-gp/kwbimage.cfg
+++ b/board/Marvell/db-mv784mp-gp/kwbimage.cfg
@@ -9,4 +9,4 @@
 BOOT_FROM	spi
 
 # Binary Header (bin_hdr) with DDR3 training code
-BINARY board/Marvell/db-mv784mp-gp/binary.0 0000005b 00000068
+BINARY spl/u-boot-spl.bin 0000005b 00000068
diff --git a/board/maxbcm/binary.0 b/board/maxbcm/binary.0
deleted file mode 100644
index 17bfad9..0000000
--- a/board/maxbcm/binary.0
+++ /dev/null
@@ -1,17 +0,0 @@
---------
-WARNING:
---------
-This file should contain the bin_hdr generated by the original Marvell
-U-Boot implementation. As this is currently not included in this
-U-Boot version, we have added this placeholder, so that the U-Boot
-image can be generated without errors.
-
-If you have a known to be working bin_hdr for your board, then you
-just need to replace this text file here with the binary header
-and recompile U-Boot.
-
-In a few weeks, mainline U-Boot will get support to generate the
-bin_hdr with the DDR training code itself. By implementing this code
-as SPL U-Boot. Then this file will not be needed any more and will
-get removed.
-
diff --git a/board/maxbcm/kwbimage.cfg b/board/maxbcm/kwbimage.cfg
index 5a3bc67..cc05792 100644
--- a/board/maxbcm/kwbimage.cfg
+++ b/board/maxbcm/kwbimage.cfg
@@ -9,4 +9,4 @@
 BOOT_FROM	spi
 
 # Binary Header (bin_hdr) with DDR3 training code
-BINARY board/maxbcm/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 7fc83ee..46b16ac 100644
--- a/board/maxbcm/maxbcm.c
+++ b/board/maxbcm/maxbcm.c
@@ -11,6 +11,9 @@
 #include <asm/arch/soc.h>
 #include <linux/mbus.h>
 
+#include "../drivers/ddr/mvebu/ddr3_hw_training.h"
+#include "../arch/arm/mvebu-common/serdes/high_speed_env_spec.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /* Base addresses for the external device chip selects */
@@ -19,8 +22,84 @@
 #define DEV_CS2_BASE		0xe2000000
 #define DEV_CS3_BASE		0xe3000000
 
-/* Needed for dynamic (board-specific) mbus configuration */
-extern struct mvebu_mbus_state mbus_state;
+/* DDR3 static configuration */
+MV_DRAM_MC_INIT ddr3_b0_maxbcm[MV_MAX_DDR3_STATIC_SIZE] = {
+	{0x00001400, 0x7301CC30},	/* DDR SDRAM Configuration Register */
+	{0x00001404, 0x30000820},	/* Dunit Control Low Register */
+	{0x00001408, 0x5515BAAB},	/* DDR SDRAM Timing (Low) Register */
+	{0x0000140C, 0x38DA3F97},	/* DDR SDRAM Timing (High) Register */
+	{0x00001410, 0x20100005},	/* DDR SDRAM Address Control Register */
+	{0x00001414, 0x0000F3FF},	/* DDR SDRAM Open Pages Control Reg */
+	{0x00001418, 0x00000e00},	/* DDR SDRAM Operation Register */
+	{0x0000141C, 0x00000672},	/* DDR SDRAM Mode Register */
+	{0x00001420, 0x00000004},	/* DDR SDRAM Extended Mode Register */
+	{0x00001424, 0x0000F3FF},	/* Dunit Control High Register */
+	{0x00001428, 0x0011A940},	/* Dunit Control High Register */
+	{0x0000142C, 0x014C5134},	/* Dunit Control High Register */
+	{0x0000147C, 0x0000D771},
+
+	{0x00001494, 0x00010000},	/* DDR SDRAM ODT Control (Low) Reg */
+	{0x0000149C, 0x00000001},	/* DDR Dunit ODT Control Register */
+	{0x000014A0, 0x00000001},
+	{0x000014A8, 0x00000101},
+
+	/* Recommended Settings from Marvell for 4 x 16 bit devices: */
+	{0x000014C0, 0x192424C9},	/* DRAM addr and Ctrl Driving Strenght*/
+	{0x000014C4, 0xAAA24C9},	/* DRAM Data and DQS Driving Strenght */
+
+	/*
+	 * DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the
+	 * training sequence
+	 */
+	{0x000200e8, 0x3FFF0E01},
+	{0x00020184, 0x3FFFFFE0},	/* Close fast path Window to - 2G */
+
+	{0x0001504, 0x3FFFFFE1},	/* CS0 Size */
+	{0x000150C, 0x00000000},	/* CS1 Size */
+	{0x0001514, 0x00000000},	/* CS2 Size */
+	{0x000151C, 0x00000000},	/* CS3 Size */
+
+	{0x0020220, 0x00000007},	/* Reserved */
+
+	{0x00001538, 0x0000000B},	/* Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000B},	/* Read Data Ready Delay Register */
+
+	{0x000015D0, 0x00000670},	/* MR0 */
+	{0x000015D4, 0x00000044},	/* MR1 */
+	{0x000015D8, 0x00000018},	/* MR2 */
+	{0x000015DC, 0x00000000},	/* MR3 */
+	{0x000015E0, 0x00000001},
+	{0x000015E4, 0x00203c18},	/* ZQDS Configuration Register */
+	{0x000015EC, 0xF800A225},	/* DDR PHY */
+
+	{0x0, 0x0}
+};
+
+MV_DRAM_MODES maxbcm_ddr_modes[MV_DDR3_MODES_NUMBER] = {
+	{"maxbcm_1600-800", 0xB, 0x5, 0x0, A0, ddr3_b0_maxbcm,  NULL},
+};
+
+extern MV_SERDES_CHANGE_M_PHY serdes_change_m_phy[];
+
+/* MAXBCM: SERDES 0-4 PCIE, Serdes 7 = SGMII 0, all others =  unconnected */
+MV_BIN_SERDES_CFG maxbcm_serdes_cfg[] = {
+	{ MV_PEX_ROOT_COMPLEX, 0x20011111, 0x00000000,
+	  { PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_DISABLED,
+	    PEX_BUS_DISABLED },
+	  0x1f, serdes_change_m_phy
+	}
+};
+
+MV_DRAM_MODES *ddr3_get_static_ddr_mode(void)
+{
+	/* Only one mode supported for this board */
+	return &maxbcm_ddr_modes[0];
+}
+
+MV_BIN_SERDES_CFG *board_serdes_cfg_get(u8 pex_mode)
+{
+	return &maxbcm_serdes_cfg[0];
+}
 
 int board_early_init_f(void)
 {
@@ -63,9 +142,7 @@
 /* Configure and enable MV88E6185 switch */
 void reset_phy(void)
 {
-	u16 devadr = CONFIG_PHY_BASE_ADDR;
 	char *name = "neta0";
-	u16 reg;
 
 	if (miiphy_set_current_dev(name))
 		return;
diff --git a/configs/db-mv784mp-gp_defconfig b/configs/db-mv784mp-gp_defconfig
index 7aa216c..a7f13e2 100644
--- a/configs/db-mv784mp-gp_defconfig
+++ b/configs/db-mv784mp-gp_defconfig
@@ -1,2 +1,3 @@
-CONFIG_ARM=y
-CONFIG_TARGET_DB_MV784MP_GP=y
+CONFIG_SPL=y
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_DB_MV784MP_GP=y
diff --git a/configs/maxbcm_defconfig b/configs/maxbcm_defconfig
index 4bcffd8..219586a 100644
--- a/configs/maxbcm_defconfig
+++ b/configs/maxbcm_defconfig
@@ -1,2 +1,3 @@
-CONFIG_ARM=y
-CONFIG_TARGET_MAXBCM=y
+CONFIG_SPL=y
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_MAXBCM=y
diff --git a/drivers/ddr/mvebu/Makefile b/drivers/ddr/mvebu/Makefile
new file mode 100644
index 0000000..50a69ea
--- /dev/null
+++ b/drivers/ddr/mvebu/Makefile
@@ -0,0 +1,14 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD) += ddr3_dfs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_dqs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_hw_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_init.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_pbs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_read_leveling.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_sdram.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_spd.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_write_leveling.o
+obj-$(CONFIG_SPL_BUILD) += xor.o
diff --git a/drivers/ddr/mvebu/ddr3_axp.h b/drivers/ddr/mvebu/ddr3_axp.h
new file mode 100644
index 0000000..bf65f6b
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp.h
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __DDR3_AXP_H
+#define __DDR3_AXP_H
+
+#define MV_78XX0_Z1_REV			0x0
+#define MV_78XX0_A0_REV			0x1
+#define MV_78XX0_B0_REV			0x2
+
+#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
+
+#ifndef CONFIG_DDR_FIXED_SIZE
+#define SDRAM_CS_SIZE			0xFFFFFFF
+#else
+#define SDRAM_CS_SIZE			(CONFIG_DDR_FIXED_SIZE - 1)
+#endif
+#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 ECC_SUPPORT
+#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)
+
+/*
+ * Registers offset
+ */
+
+#define REG_SAMPLE_RESET_LOW_ADDR		0x18230
+#define REG_SAMPLE_RESET_HIGH_ADDR		0x18234
+#define	REG_SAMPLE_RESET_CPU_FREQ_OFFS		21
+#define	REG_SAMPLE_RESET_CPU_FREQ_MASK		0x00E00000
+#define	REG_SAMPLE_RESET_FAB_OFFS		24
+#define	REG_SAMPLE_RESET_FAB_MASK		0xF000000
+#define	REG_SAMPLE_RESET_TCLK_OFFS		28
+#define	REG_SAMPLE_RESET_CPU_ARCH_OFFS		31
+#define	REG_SAMPLE_RESET_HIGH_CPU_FREQ_OFFS	20
+
+/* MISC */
+/*
+ * In mainline U-Boot we're re-configuring the mvebu base address
+ * register to 0xf1000000. So need to use this value for the DDR
+ * training code as well.
+ */
+#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_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_ODT_CTRL_LOW_ADDR		0x1494
+
+#define REG_SDRAM_ODT_CTRL_HIGH_ADDR		0x1498
+/*#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK	0xFFFFFF55 */
+#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
+#define REG_DDR3_MR1_OUTBUF_WL_MASK		0xFFFFEF7F	/* WL-disabled,OB-enabled */
+#define REG_DDR3_MR1_OUTBUF_DIS_OFFS		12	/* Output Buffer Disabled */
+#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_ENABLE				0x1
+#define DLB_WRITE_COALESING			(0x1 << 2)
+#define DLB_AXI_PREFETCH_EN			(0x1 << 3)
+#define DLB_MBUS_PREFETCH_EN			(0x1 << 4)
+#define PREFETCH_NLNSZTR			(0x1 << 6)
+
+/* 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
+
+/* 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		(MV_MBUS_REGS_OFFSET + 0x420)
+#define FABRIC_UNITS_PRIORITY_CONTROL_REG	(MV_MBUS_REGS_OFFSET + 0x424)
+#define MBUS_UNITS_PREFETCH_CONTROL_REG		(MV_MBUS_REGS_OFFSET + 0x428)
+#define FABRIC_UNITS_PREFETCH_CONTROL_REG	(MV_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 MV_PEX_IF_REGS_OFFSET(if) \
+	(if < 8 ? (0x40000 + ((if) / 4) * 0x40000 + ((if) % 4) * 0x4000) \
+	 : (0x42000 + ((if) % 8) * 0x40000))
+#define MV_PEX_IF_REGS_BASE(unit)		(MV_PEX_IF_REGS_OFFSET(unit))
+#define POWER_MNG_CTRL_REG			0x18220
+#define PEX_DEVICE_AND_VENDOR_ID		0x000
+#define PEX_CFG_DIRECT_ACCESS(if, reg)		(MV_PEX_IF_REGS_BASE(if) + (reg))
+#define PMC_PEXSTOPCLOCK_OFFS(port)		((port) < 8 ? (5 + (port)) : (18 + (port)))
+#define PMC_PEXSTOPCLOCK_MASK(port)		(1 << PMC_PEXSTOPCLOCK_OFFS(port))
+#define PMC_PEXSTOPCLOCK_EN(port)		(1 << PMC_PEXSTOPCLOCK_OFFS(port))
+#define PMC_PEXSTOPCLOCK_STOP(port)		(0 << PMC_PEXSTOPCLOCK_OFFS(port))
+
+/* 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
+
+/* DDR3 Frequencies: */
+#define DDR_100					0
+#define DDR_300					1
+#define DDR_333					1
+#define DDR_360					2
+#define DDR_400					3
+#define DDR_444					4
+#define DDR_500					5
+#define DDR_533					6
+#define DDR_600					7
+#define DDR_640					8
+#define DDR_666					8
+#define DDR_720					9
+#define DDR_750					9
+#define DDR_800					10
+#define DDR_833					11
+#define DDR_HCLK				20
+#define DDR_S					12
+#define DDR_S_1TO1				13
+#define MARGIN_FREQ				DDR_400
+#define DFS_MARGIN				DDR_100
+
+#define ODT_OPT					16
+#define ODT20					0x200
+#define ODT30					0x204
+#define ODT40					0x44
+#define ODT120					0x40
+#define ODT120D					0x400
+
+#define MRS_DELAY				100
+
+#define SDRAM_WL_SW_OFFS			0x100
+#define SDRAM_RL_OFFS				0x0
+#define SDRAM_PBS_I_OFFS			0x140
+#define SDRAM_PBS_II_OFFS			0x180
+#define SDRAM_PBS_NEXT_OFFS			(SDRAM_PBS_II_OFFS - SDRAM_PBS_I_OFFS)
+#define SDRAM_PBS_TX_OFFS			0x180
+#define SDRAM_PBS_TX_DM_OFFS			576
+#define SDRAM_DQS_RX_OFFS			1024
+#define SDRAM_DQS_TX_OFFS			2048
+#define SDRAM_DQS_RX_SPECIAL_OFFS		5120
+
+#define LEN_STD_PATTERN				16
+#define LEN_KILLER_PATTERN			128
+#define LEN_SPECIAL_PATTERN			128
+#define LEN_PBS_PATTERN				16
+
+#endif /* __DDR3_AXP_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_config.h b/drivers/ddr/mvebu/ddr3_axp_config.h
new file mode 100644
index 0000000..800d2d1
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_config.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __DDR3_AXP_CONFIG_H
+#define __DDR3_AXP_CONFIG_H
+
+/*
+ * DDR3_LOG_LEVEL Information
+ *
+ * Level 0: Provides an error code in a case of failure, RL, WL errors
+ *          and other algorithm failure
+ * Level 1: Provides the D-Unit setup (SPD/Static configuration)
+ * Level 2: Provides the windows margin as a results of DQS centeralization
+ * Level 3: Provides the windows margin of each DQ as a results of DQS
+ *          centeralization
+ */
+#ifdef CONFIG_DDR_LOG_LEVEL
+#define	DDR3_LOG_LEVEL	CONFIG_DDR_LOG_LEVEL
+#else
+#define	DDR3_LOG_LEVEL	0
+#endif
+
+#define DDR3_PBS        1
+
+/* This flag allows the execution of SW WL/RL upon HW failure */
+#define DDR3_RUN_SW_WHEN_HW_FAIL    1
+
+/*
+ * General Configurations
+ *
+ * The following parameters are required for proper setup:
+ *
+ * DDR_TARGET_FABRIC   - Set desired fabric configuration
+ *                       (for sample@Reset fabfreq parameter)
+ * DRAM_ECC            - Set ECC support 1/0
+ * BUS_WIDTH           - 64/32 bit
+ * CONFIG_SPD_EEPROM   - Enables auto detection of DIMMs and their timing values
+ * DQS_CLK_ALIGNED     - Set this if CLK and DQS signals are aligned on board
+ * MIXED_DIMM_STATIC   - Mixed DIMM + On board devices support (ODT registers
+ *                       values are taken statically)
+ * DDR3_TRAINING_DEBUG - Debug prints of internal code
+ */
+#define DDR_TARGET_FABRIC			5
+#define DRAM_ECC				0
+
+#ifdef MV_DDR_32BIT
+#define BUS_WIDTH                               32
+#else
+#define BUS_WIDTH				64
+#endif
+
+#undef DQS_CLK_ALIGNED
+#undef MIXED_DIMM_STATIC
+#define DDR3_TRAINING_DEBUG			0
+#define REG_DIMM_SKIP_WL			0
+
+/* Marvell boards specific configurations */
+#if defined(DB_78X60_PCAC)
+#undef CONFIG_SPD_EEPROM
+#define STATIC_TRAINING
+#endif
+
+#if defined(DB_78X60_AMC)
+#undef CONFIG_SPD_EEPROM
+#undef  DRAM_ECC
+#define DRAM_ECC				1
+#endif
+
+#ifdef CONFIG_SPD_EEPROM
+/*
+ * DIMM support parameters:
+ * DRAM_2T - Set Desired 2T Mode - 0 - 1T, 0x1 - 2T, 0x2 - 3T
+ * DIMM_CS_BITMAP - bitmap representing the optional CS in DIMMs
+ * (0xF=CS0+CS1+CS2+CS3, 0xC=CS2+CS3...)
+ */
+#define DRAM_2T					0x0
+#define DIMM_CS_BITMAP				0xF
+#define DUNIT_SPD
+#endif
+
+#ifdef DRAM_ECC
+/*
+ * ECC support parameters:
+ *
+ * U_BOOT_START_ADDR, U_BOOT_SCRUB_SIZE - relevant when using ECC and need
+ * to configure the scrubbing area
+ */
+#define TRAINING_SIZE				0x20000
+#define U_BOOT_START_ADDR			0
+#define U_BOOT_SCRUB_SIZE			0x1000000 /* TRAINING_SIZE */
+#endif
+
+/*
+ * Registered DIMM Support - In case registered DIMM is attached,
+ * please supply the following values:
+ * (see JEDEC - JESD82-29A "Definition of the SSTE32882 Registering Clock
+ * Driver with Parity and Quad Chip
+ * Selects for DDR3/DDR3L/DDR3U RDIMM 1.5 V/1.35 V/1.25 V Applications")
+ * RC0: Global Features Control Word
+ * RC1: Clock Driver Enable Control Word
+ * RC2: Timing Control Word
+ * RC3-RC5 - taken from SPD
+ * RC8: Additional IBT Setting Control Word
+ * RC9: Power Saving Settings Control Word
+ * RC10: Encoding for RDIMM Operating Speed
+ * RC11: Operating Voltage VDD and VREFCA Control Word
+ */
+#define RDIMM_RC0				0
+#define RDIMM_RC1				0
+#define RDIMM_RC2				0
+#define RDIMM_RC8				0
+#define RDIMM_RC9				0
+#define RDIMM_RC10				0x2
+#define RDIMM_RC11				0x0
+
+#if defined(MIXED_DIMM_STATIC) || !defined(CONFIG_SPD_EEPROM)
+#define DUNIT_STATIC
+#endif
+
+#if defined(MIXED_DIMM_STATIC) || defined(CONFIG_SPD_EEPROM)
+/*
+ * This flag allows the user to change the dram refresh cycle in ps,
+ * only in case of SPD or MIX DIMM topology
+ */
+#define TREFI_USER_EN
+
+#ifdef TREFI_USER_EN
+#define TREFI_USER				3900000
+#endif
+#endif
+
+#ifdef CONFIG_SPD_EEPROM
+/*
+ * AUTO_DETECTION_SUPPORT - relevant ONLY for Marvell DB boards.
+ * Enables I2C auto detection different options
+ */
+#if defined(CONFIG_DB_88F78X60) || defined(CONFIG_DB_88F78X60_REV2) || \
+    defined(CONFIG_DB_784MP_GP)
+#define AUTO_DETECTION_SUPPORT
+#endif
+#endif
+
+#endif /* __DDR3_AXP_CONFIG_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_mc_static.h b/drivers/ddr/mvebu/ddr3_axp_mc_static.h
new file mode 100644
index 0000000..2c0e9075
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_mc_static.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __AXP_MC_STATIC_H
+#define __AXP_MC_STATIC_H
+
+MV_DRAM_MC_INIT ddr3_A0_db_667[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+	{0x00001400, 0x7301c924},	/*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+	{0x00001400, 0x7301CA28},	/*DDR SDRAM Configuration Register */
+#endif
+	{0x00001404, 0x3630b800},	/*Dunit Control Low Register */
+	{0x00001408, 0x43149775},	/*DDR SDRAM Timing (Low) Register */
+	/* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+	{0x0000140C, 0x38d83fe0},	/*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+	{0x00001410, 0x040F0001},	/*DDR SDRAM Address Control Register */
+#else
+	{0x00001410, 0x040F0000},	/*DDR SDRAM Open Pages Control Register */
+#endif
+
+	{0x00001414, 0x00000000},	/*DDR SDRAM Open Pages Control Register */
+	{0x00001418, 0x00000e00},	/*DDR SDRAM Operation Register */
+	{0x00001420, 0x00000004},	/*DDR SDRAM Extended Mode Register */
+	{0x00001424, 0x0000D3FF},	/*Dunit Control High Register */
+	{0x00001428, 0x000F8830},	/*Dunit Control High Register */
+	{0x0000142C, 0x214C2F38},	/*Dunit Control High Register */
+	{0x0000147C, 0x0000c671},
+
+	{0x000014a0, 0x000002A9},
+	{0x000014a8, 0x00000101},	/*2:1 */
+	{0x00020220, 0x00000007},
+
+	{0x00001494, 0x00010000},	/*DDR SDRAM ODT Control (Low) Register */
+	{0x00001498, 0x00000000},	/*DDR SDRAM ODT Control (High) Register */
+	{0x0000149C, 0x00000301},	/*DDR Dunit ODT Control Register */
+
+	{0x000014C0, 0x192434e9},	/* DRAM address and Control Driving Strenght  */
+	{0x000014C4, 0x092434e9},	/* DRAM Data and DQS Driving Strenght  */
+
+	{0x000200e8, 0x3FFF0E01},	/* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+	{0x00020184, 0x3FFFFFE0},	/* DO NOT Modify - Close fast path Window to - 2G */
+
+	{0x0001504, 0x7FFFFFF1},	/* CS0 Size */
+	{0x000150C, 0x00000000},	/* CS1 Size */
+	{0x0001514, 0x00000000},	/* CS2 Size */
+	{0x000151C, 0x00000000},	/* CS3 Size */
+
+	/*     {0x00001524, 0x0000C800},  */
+	{0x00001538, 0x0000000b},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000d},	/*Read Data Ready Delay Register */
+
+	{0x000015D0, 0x00000640},	/*MR0 */
+	{0x000015D4, 0x00000046},	/*MR1 */
+	{0x000015D8, 0x00000010},	/*MR2 */
+	{0x000015DC, 0x00000000},	/*MR3 */
+
+	{0x000015E4, 0x00203c18},	/*ZQC Configuration Register */
+	{0x000015EC, 0xd800aa25},	/*DDR PHY */
+	{0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_A0_AMC_667[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+	{0x00001400, 0x7301c924},	/*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+	{0x00001400, 0x7301CA28},	/*DDR SDRAM Configuration Register */
+#endif
+	{0x00001404, 0x3630b800},	/*Dunit Control Low Register */
+	{0x00001408, 0x43149775},	/*DDR SDRAM Timing (Low) Register */
+	/* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+	{0x0000140C, 0x38d83fe0},	/*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+	{0x00001410, 0x040F0001},	/*DDR SDRAM Address Control Register */
+#else
+	{0x00001410, 0x040F000C},	/*DDR SDRAM Open Pages Control Register */
+#endif
+
+	{0x00001414, 0x00000000},	/*DDR SDRAM Open Pages Control Register */
+	{0x00001418, 0x00000e00},	/*DDR SDRAM Operation Register */
+	{0x00001420, 0x00000004},	/*DDR SDRAM Extended Mode Register */
+	{0x00001424, 0x0000D3FF},	/*Dunit Control High Register */
+	{0x00001428, 0x000F8830},	/*Dunit Control High Register */
+	{0x0000142C, 0x214C2F38},	/*Dunit Control High Register */
+	{0x0000147C, 0x0000c671},
+
+	{0x000014a0, 0x000002A9},
+	{0x000014a8, 0x00000101},	/*2:1 */
+	{0x00020220, 0x00000007},
+
+	{0x00001494, 0x00010000},	/*DDR SDRAM ODT Control (Low) Register */
+	{0x00001498, 0x00000000},	/*DDR SDRAM ODT Control (High) Register */
+	{0x0000149C, 0x00000301},	/*DDR Dunit ODT Control Register */
+
+	{0x000014C0, 0x192434e9},	/* DRAM address and Control Driving Strenght  */
+	{0x000014C4, 0x092434e9},	/* DRAM Data and DQS Driving Strenght  */
+
+	{0x000200e8, 0x3FFF0E01},	/* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+	{0x00020184, 0x3FFFFFE0},	/* DO NOT Modify - Close fast path Window to - 2G */
+
+	{0x0001504, 0x3FFFFFF1},	/* CS0 Size */
+	{0x000150C, 0x00000000},	/* CS1 Size */
+	{0x0001514, 0x00000000},	/* CS2 Size */
+	{0x000151C, 0x00000000},	/* CS3 Size */
+
+	/*     {0x00001524, 0x0000C800},  */
+	{0x00001538, 0x0000000b},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000d},	/*Read Data Ready Delay Register */
+
+	{0x000015D0, 0x00000640},	/*MR0 */
+	{0x000015D4, 0x00000046},	/*MR1 */
+	{0x000015D8, 0x00000010},	/*MR2 */
+	{0x000015DC, 0x00000000},	/*MR3 */
+
+	{0x000015E4, 0x00203c18},	/*ZQC Configuration Register */
+	{0x000015EC, 0xd800aa25},	/*DDR PHY */
+	{0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_A0_db_400[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+	{0x00001400, 0x73004C30},	/*DDR SDRAM Configuration Register */
+#else /* MV_DDR_64BIT */
+	{0x00001400, 0x7300CC30},	/*DDR SDRAM Configuration Register */
+#endif
+	{0x00001404, 0x3630B840},	/*Dunit Control Low Register */
+	{0x00001408, 0x33137663},	/*DDR SDRAM Timing (Low) Register */
+	{0x0000140C, 0x38000C55},	/*DDR SDRAM Timing (High) Register */
+	{0x00001410, 0x040F0000},	/*DDR SDRAM Address Control Register */
+	{0x00001414, 0x00000000},	/*DDR SDRAM Open Pages Control Register */
+	{0x00001418, 0x00000e00},	/*DDR SDRAM Operation Register */
+	{0x0000141C, 0x00000672},	/*DDR SDRAM Mode Register */
+	{0x00001420, 0x00000004},	/*DDR SDRAM Extended Mode Register */
+	{0x00001424, 0x0100D3FF},	/*Dunit Control High Register */
+	{0x00001428, 0x000D6720},	/*Dunit Control High Register */
+	{0x0000142C, 0x014C2F38},	/*Dunit Control High Register */
+	{0x0000147C, 0x00006571},
+
+	{0x00001494, 0x00010000},	/*DDR SDRAM ODT Control (Low) Register */
+	{0x00001498, 0x00000000},	/*DDR SDRAM ODT Control (High) Register */
+	{0x0000149C, 0x00000301},	/*DDR Dunit ODT Control Register */
+
+	{0x000014a0, 0x000002A9},
+	{0x000014a8, 0x00000101},	/*2:1 */
+	{0x00020220, 0x00000007},
+
+	{0x000014C0, 0x192424C8},	/* DRAM address and Control Driving Strenght  */
+	{0x000014C4, 0xEFB24C8},	/* DRAM Data and DQS Driving Strenght  */
+
+	{0x000200e8, 0x3FFF0E01},	/* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+	{0x00020184, 0x3FFFFFE0},	/* DO NOT Modify - Close fast path Window to - 2G */
+
+	{0x0001504, 0x7FFFFFF1},	/* CS0 Size */
+	{0x000150C, 0x00000000},	/* CS1 Size */
+	{0x0001514, 0x00000000},	/* CS2 Size */
+	{0x000151C, 0x00000000},	/* CS3 Size */
+
+	{0x00001538, 0x00000008},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000A},	/*Read Data Ready Delay Register */
+
+	{0x000015D0, 0x00000630},	/*MR0 */
+	{0x000015D4, 0x00000046},	/*MR1 */
+	{0x000015D8, 0x00000008},	/*MR2 */
+	{0x000015DC, 0x00000000},	/*MR3 */
+
+	{0x000015E4, 0x00203c18},	/*ZQDS Configuration Register */
+	/* {0x000015EC, 0xDE000025}, *//*DDR PHY */
+	{0x000015EC, 0xF800AA25},	/*DDR PHY */
+	{0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_Z1_db_600[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+	{0x00001400, 0x73014A28},	/*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+	{0x00001400, 0x7301CA28},	/*DDR SDRAM Configuration Register */
+#endif
+	{0x00001404, 0x3630B040},	/*Dunit Control Low Register */
+	{0x00001408, 0x44149887},	/*DDR SDRAM Timing (Low) Register */
+	/* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+	{0x0000140C, 0x38D83FE0},	/*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+	{0x00001410, 0x040F0001},	/*DDR SDRAM Address Control Register */
+#else
+	{0x00001410, 0x040F0000},	/*DDR SDRAM Open Pages Control Register */
+#endif
+
+	{0x00001414, 0x00000000},	/*DDR SDRAM Open Pages Control Register */
+	{0x00001418, 0x00000e00},	/*DDR SDRAM Operation Register */
+	{0x00001420, 0x00000004},	/*DDR SDRAM Extended Mode Register */
+	{0x00001424, 0x0100D1FF},	/*Dunit Control High Register */
+	{0x00001428, 0x000F8830},	/*Dunit Control High Register */
+	{0x0000142C, 0x214C2F38},	/*Dunit Control High Register */
+	{0x0000147C, 0x0000c671},
+
+	{0x000014a8, 0x00000101},	/*2:1 */
+	{0x00020220, 0x00000007},
+
+	{0x00001494, 0x00010000},	/*DDR SDRAM ODT Control (Low) Register */
+	{0x00001498, 0x00000000},	/*DDR SDRAM ODT Control (High) Register */
+	{0x0000149C, 0x00000301},	/*DDR Dunit ODT Control Register */
+
+	{0x000014C0, 0x192424C8},	/* DRAM address and Control Driving Strenght  */
+	{0x000014C4, 0xEFB24C8},	/* DRAM Data and DQS Driving Strenght  */
+
+	{0x000200e8, 0x3FFF0E01},	/* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+	{0x00020184, 0x3FFFFFE0},	/* DO NOT Modify - Close fast path Window to - 2G */
+
+	{0x0001504, 0x7FFFFFF1},	/* CS0 Size */
+	{0x000150C, 0x00000000},	/* CS1 Size */
+	{0x0001514, 0x00000000},	/* CS2 Size */
+	{0x000151C, 0x00000000},	/* CS3 Size */
+
+	/*     {0x00001524, 0x0000C800},  */
+	{0x00001538, 0x0000000b},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000d},	/*Read Data Ready Delay Register */
+
+	{0x000015D0, 0x00000650},	/*MR0 */
+	{0x000015D4, 0x00000046},	/*MR1 */
+	{0x000015D8, 0x00000010},	/*MR2 */
+	{0x000015DC, 0x00000000},	/*MR3 */
+
+	{0x000015E4, 0x00203c18},	/*ZQC Configuration Register */
+	{0x000015EC, 0xDE000025},	/*DDR PHY */
+	{0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_Z1_db_300[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+	{0x00001400, 0x73004C30},	/*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+	{0x00001400, 0x7300CC30},	/*DDR SDRAM Configuration Register */
+	/*{0x00001400, 0x7304CC30},  *//*DDR SDRAM Configuration Register */
+#endif
+	{0x00001404, 0x3630B840},	/*Dunit Control Low Register */
+	{0x00001408, 0x33137663},	/*DDR SDRAM Timing (Low) Register */
+	{0x0000140C, 0x38000C55},	/*DDR SDRAM Timing (High) Register */
+	{0x00001410, 0x040F0000},	/*DDR SDRAM Address Control Register */
+	{0x00001414, 0x00000000},	/*DDR SDRAM Open Pages Control Register */
+	{0x00001418, 0x00000e00},	/*DDR SDRAM Operation Register */
+	{0x0000141C, 0x00000672},	/*DDR SDRAM Mode Register */
+	{0x00001420, 0x00000004},	/*DDR SDRAM Extended Mode Register */
+	{0x00001424, 0x0100F1FF},	/*Dunit Control High Register */
+	{0x00001428, 0x000D6720},	/*Dunit Control High Register */
+	{0x0000142C, 0x014C2F38},	/*Dunit Control High Register */
+	{0x0000147C, 0x00006571},
+
+	{0x00001494, 0x00010000},	/*DDR SDRAM ODT Control (Low) Register */
+	{0x00001498, 0x00000000},	/*DDR SDRAM ODT Control (High) Register */
+	{0x0000149C, 0x00000301},	/*DDR Dunit ODT Control Register */
+
+	{0x000014C0, 0x192424C8},	/* DRAM address and Control Driving Strenght  */
+	{0x000014C4, 0xEFB24C8},	/* DRAM Data and DQS Driving Strenght  */
+
+	{0x000200e8, 0x3FFF0E01},	/* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+	{0x00020184, 0x3FFFFFE0},	/* DO NOT Modify - Close fast path Window to - 2G */
+
+	{0x0001504, 0x7FFFFFF1},	/* CS0 Size */
+	{0x000150C, 0x00000000},	/* CS1 Size */
+	{0x0001514, 0x00000000},	/* CS2 Size */
+	{0x000151C, 0x00000000},	/* CS3 Size */
+
+	{0x00001538, 0x00000008},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000A},	/*Read Data Ready Delay Register */
+
+	{0x000015D0, 0x00000630},	/*MR0 */
+	{0x000015D4, 0x00000046},	/*MR1 */
+	{0x000015D8, 0x00000008},	/*MR2 */
+	{0x000015DC, 0x00000000},	/*MR3 */
+
+	{0x000015E4, 0x00203c18},	/*ZQDS Configuration Register */
+	{0x000015EC, 0xDE000025},	/*DDR PHY */
+
+	{0x0, 0x0}
+};
+
+#endif /* __AXP_MC_STATIC_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_training_static.h b/drivers/ddr/mvebu/ddr3_axp_training_static.h
new file mode 100644
index 0000000..4e61547
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_training_static.h
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __AXP_TRAINING_STATIC_H
+#define __AXP_TRAINING_STATIC_H
+
+/*
+ * STATIC_TRAINING - Set only if static parameters for training are set and
+ * required
+ */
+
+MV_DRAM_TRAINING_INIT ddr3_db_rev2_667[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0     */
+	{0x000016A0, 0xC002011A},
+	/*1 */
+	{0x000016A0, 0xC0420100},
+	/*2 */
+	{0x000016A0, 0xC082020A},
+	/*3 */
+	{0x000016A0, 0xC0C20017},
+	/*4 */
+	{0x000016A0, 0xC1020113},
+	/*5 */
+	{0x000016A0, 0xC1420107},
+	/*6 */
+	{0x000016A0, 0xC182011F},
+	/*7 */
+	{0x000016A0, 0xC1C2001C},
+	/*8 */
+	{0x000016A0, 0xC202010D},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0004A06},
+	/*1 */
+	{0x000016A0, 0xC040690D},
+	/*2 */
+	{0x000016A0, 0xC0806A0D},
+	/*3 */
+	{0x000016A0, 0xC0C0A01B},
+	/*4 */
+	{0x000016A0, 0xC1003A01},
+	/*5 */
+	{0x000016A0, 0xC1408113},
+	/*6 */
+	{0x000016A0, 0xC1805609},
+	/*7 */
+	{0x000016A0, 0xC1C04504},
+	/*8 */
+	{0x000016A0, 0xC2009518},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000F},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_rev2_800[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0     */
+	{0x000016A0, 0xC0020301},
+	/*1 */
+	{0x000016A0, 0xC0420202},
+	/*2 */
+	{0x000016A0, 0xC0820314},
+	/*3 */
+	{0x000016A0, 0xC0C20117},
+	/*4 */
+	{0x000016A0, 0xC1020219},
+	/*5 */
+	{0x000016A0, 0xC142020B},
+	/*6 */
+	{0x000016A0, 0xC182030A},
+	/*7 */
+	{0x000016A0, 0xC1C2011D},
+	/*8 */
+	{0x000016A0, 0xC2020212},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0007A12},
+	/*1 */
+	{0x000016A0, 0xC0408D16},
+	/*2 */
+	{0x000016A0, 0xC0809E1B},
+	/*3 */
+	{0x000016A0, 0xC0C0AC1F},
+	/*4 */
+	{0x000016A0, 0xC1005E0A},
+	/*5 */
+	{0x000016A0, 0xC140A91D},
+	/*6 */
+	{0x000016A0, 0xC1808E17},
+	/*7 */
+	{0x000016A0, 0xC1C05509},
+	/*8 */
+	{0x000016A0, 0xC2003A01},
+
+	/* PBS Leveling */
+	/*0 */
+	{0x000016A0, 0xC0007A12},
+	/*1 */
+	{0x000016A0, 0xC0408D16},
+	/*2 */
+	{0x000016A0, 0xC0809E1B},
+	/*3 */
+	{0x000016A0, 0xC0C0AC1F},
+	/*4 */
+	{0x000016A0, 0xC1005E0A},
+	/*5 */
+	{0x000016A0, 0xC140A91D},
+	/*6 */
+	{0x000016A0, 0xC1808E17},
+	/*7 */
+	{0x000016A0, 0xC1C05509},
+	/*8 */
+	{0x000016A0, 0xC2003A01},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000B},
+
+	{0x00001538, 0x0000000D},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x00000011},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_400[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0             2               4               15 */
+	{0x000016A0, 0xC002010C},
+	/*1             2               4               2 */
+	{0x000016A0, 0xC042001C},
+	/*2             2               4               27 */
+	{0x000016A0, 0xC0820115},
+	/*3             2               4               0 */
+	{0x000016A0, 0xC0C20019},
+	/*4             2               4               13 */
+	{0x000016A0, 0xC1020108},
+	/*5             2               4               5 */
+	{0x000016A0, 0xC1420100},
+	/*6             2               4               19 */
+	{0x000016A0, 0xC1820111},
+	/*7             2               4               0 */
+	{0x000016A0, 0xC1C2001B},
+	/*8             2               4               10 */
+	/*{0x000016A0, 0xC2020117}, */
+	{0x000016A0, 0xC202010C},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0005508},
+	/*1 */
+	{0x000016A0, 0xC0409819},
+	/*2 */
+	{0x000016A0, 0xC080650C},
+	/*3 */
+	{0x000016A0, 0xC0C0700F},
+	/*4 */
+	{0x000016A0, 0xC1004103},
+	/*5 */
+	{0x000016A0, 0xC140A81D},
+	/*6 */
+	{0x000016A0, 0xC180650C},
+	/*7 */
+	{0x000016A0, 0xC1C08013},
+	/*8 */
+	{0x000016A0, 0xC2005508},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x00000008},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000A},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_533[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0             2               4               15 */
+	{0x000016A0, 0xC002040C},
+	/*1             2               4               2 */
+	{0x000016A0, 0xC0420117},
+	/*2             2               4               27 */
+	{0x000016A0, 0xC082041B},
+	/*3             2               4               0 */
+	{0x000016A0, 0xC0C20117},
+	/*4             2               4               13 */
+	{0x000016A0, 0xC102040A},
+	/*5             2               4               5 */
+	{0x000016A0, 0xC1420117},
+	/*6             2               4               19 */
+	{0x000016A0, 0xC1820419},
+	/*7             2               4               0 */
+	{0x000016A0, 0xC1C20117},
+	/*8             2               4               10 */
+	{0x000016A0, 0xC2020117},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0008113},
+	/*1 */
+	{0x000016A0, 0xC0404504},
+	/*2 */
+	{0x000016A0, 0xC0808514},
+	/*3 */
+	{0x000016A0, 0xC0C09418},
+	/*4 */
+	{0x000016A0, 0xC1006D0E},
+	/*5 */
+	{0x000016A0, 0xC1405508},
+	/*6 */
+	{0x000016A0, 0xC1807D12},
+	/*7 */
+	{0x000016A0, 0xC1C0b01F},
+	/*8 */
+	{0x000016A0, 0xC2005D0A},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x00000008},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000A},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_600[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0             2               3               1 */
+	{0x000016A0, 0xC0020104},
+	/*1             2               2               6 */
+	{0x000016A0, 0xC0420010},
+	/*2             2               3               16 */
+	{0x000016A0, 0xC0820112},
+	/*3             2               1               26 */
+	{0x000016A0, 0xC0C20009},
+	/*4             2               2               29 */
+	{0x000016A0, 0xC102001F},
+	/*5             2               2               13 */
+	{0x000016A0, 0xC1420014},
+	/*6             2               3               6 */
+	{0x000016A0, 0xC1820109},
+	/*7             2               1               31 */
+	{0x000016A0, 0xC1C2000C},
+	/*8             2               2               22 */
+	{0x000016A0, 0xC2020112},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0009919},
+	/*1 */
+	{0x000016A0, 0xC0405508},
+	/*2 */
+	{0x000016A0, 0xC0809919},
+	/*3 */
+	{0x000016A0, 0xC0C09C1A},
+	/*4 */
+	{0x000016A0, 0xC1008113},
+	/*5 */
+	{0x000016A0, 0xC140650C},
+	/*6 */
+	{0x000016A0, 0xC1809518},
+	/*7 */
+	{0x000016A0, 0xC1C04103},
+	/*8 */
+	{0x000016A0, 0xC2006D0E},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000F},	/*Read Data Ready Delay Register */
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_667[MV_MAX_DDR3_STATIC_SIZE] = {
+
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0             2               3               1 */
+	{0x000016A0, 0xC0020103},
+	/*1            2               2               6 */
+	{0x000016A0, 0xC0420012},
+	/*2            2               3               16 */
+	{0x000016A0, 0xC0820113},
+	/*3            2               1               26 */
+	{0x000016A0, 0xC0C20012},
+	/*4            2               2               29 */
+	{0x000016A0, 0xC1020100},
+	/*5            2               2               13 */
+	{0x000016A0, 0xC1420016},
+	/*6            2               3               6 */
+	{0x000016A0, 0xC1820109},
+	/*7            2               1               31 */
+	{0x000016A0, 0xC1C20010},
+	/*8            2               2               22 */
+	{0x000016A0, 0xC2020112},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC000b11F},
+	/*1 */
+	{0x000016A0, 0xC040690D},
+	/*2 */
+	{0x000016A0, 0xC0803600},
+	/*3 */
+	{0x000016A0, 0xC0C0a81D},
+	/*4 */
+	{0x000016A0, 0xC1009919},
+	/*5 */
+	{0x000016A0, 0xC1407911},
+	/*6 */
+	{0x000016A0, 0xC180ad1e},
+	/*7 */
+	{0x000016A0, 0xC1C04d06},
+	/*8 */
+	{0x000016A0, 0xC2008514},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000F},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_800[MV_MAX_DDR3_STATIC_SIZE] = {
+
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0             2               3               1 */
+	{0x000016A0, 0xC0020213},
+	/*1            2               2               6 */
+	{0x000016A0, 0xC0420108},
+	/*2            2               3               16 */
+	{0x000016A0, 0xC0820210},
+	/*3            2               1               26 */
+	{0x000016A0, 0xC0C20108},
+	/*4            2               2               29 */
+	{0x000016A0, 0xC102011A},
+	/*5            2               2               13 */
+	{0x000016A0, 0xC1420300},
+	/*6            2               3               6 */
+	{0x000016A0, 0xC1820204},
+	/*7            2               1               31 */
+	{0x000016A0, 0xC1C20106},
+	/*8            2               2               22 */
+	{0x000016A0, 0xC2020112},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC000620B},
+	/*1 */
+	{0x000016A0, 0xC0408D16},
+	/*2 */
+	{0x000016A0, 0xC0806A0D},
+	/*3 */
+	{0x000016A0, 0xC0C03D02},
+	/*4 */
+	{0x000016A0, 0xC1004a05},
+	/*5 */
+	{0x000016A0, 0xC140A11B},
+	/*6 */
+	{0x000016A0, 0xC1805E0A},
+	/*7 */
+	{0x000016A0, 0xC1C06D0E},
+	/*8 */
+	{0x000016A0, 0xC200AD1E},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000C},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000E},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_0[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0 */
+	{0x000016A0, 0xC002010E},
+	/*1 */
+	{0x000016A0, 0xC042001E},
+	/*2 */
+	{0x000016A0, 0xC0820118},
+	/*3 */
+	{0x000016A0, 0xC0C2001E},
+	/*4 */
+	{0x000016A0, 0xC102010C},
+	/*5 */
+	{0x000016A0, 0xC1420102},
+	/*6 */
+	{0x000016A0, 0xC1820111},
+	/*7 */
+	{0x000016A0, 0xC1C2001C},
+	/*8 */
+	{0x000016A0, 0xC2020109},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0003600},
+	/*1 */
+	{0x000016A0, 0xC040690D},
+	/*2 */
+	{0x000016A0, 0xC0805207},
+	/*3 */
+	{0x000016A0, 0xC0C0A81D},
+	/*4 */
+	{0x000016A0, 0xC1009919},
+	/*5 */
+	{0x000016A0, 0xC1407911},
+	/*6 */
+	{0x000016A0, 0xC1803E02},
+	/*7 */
+	{0x000016A0, 0xC1C05107},
+	/*8 */
+	{0x000016A0, 0xC2008113},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000F},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_1[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0 */
+	{0x000016A0, 0xC0020106},
+	/*1 */
+	{0x000016A0, 0xC0420016},
+	/*2 */
+	{0x000016A0, 0xC0820117},
+	/*3 */
+	{0x000016A0, 0xC0C2000F},
+	/*4 */
+	{0x000016A0, 0xC1020105},
+	/*5 */
+	{0x000016A0, 0xC142001B},
+	/*6 */
+	{0x000016A0, 0xC182010C},
+	/*7 */
+	{0x000016A0, 0xC1C20011},
+	/*8 */
+	{0x000016A0, 0xC2020101},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0003600},
+	/*1 */
+	{0x000016A0, 0xC0406D0E},
+	/*2 */
+	{0x000016A0, 0xC0803600},
+	/*3 */
+	{0x000016A0, 0xC0C04504},
+	/*4 */
+	{0x000016A0, 0xC1009919},
+	/*5 */
+	{0x000016A0, 0xC1407911},
+	/*6 */
+	{0x000016A0, 0xC1803600},
+	/*7 */
+	{0x000016A0, 0xC1C0610B},
+	/*8 */
+	{0x000016A0, 0xC2008113},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000F},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_2[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0 */
+	{0x000016A0, 0xC002010C},
+	/*1 */
+	{0x000016A0, 0xC042001B},
+	/*2 */
+	{0x000016A0, 0xC082011D},
+	/*3 */
+	{0x000016A0, 0xC0C20015},
+	/*4 */
+	{0x000016A0, 0xC102010B},
+	/*5 */
+	{0x000016A0, 0xC1420101},
+	/*6 */
+	{0x000016A0, 0xC1820113},
+	/*7 */
+	{0x000016A0, 0xC1C20017},
+	/*8 */
+	{0x000016A0, 0xC2020107},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0003600},
+	/*1 */
+	{0x000016A0, 0xC0406D0E},
+	/*2 */
+	{0x000016A0, 0xC0803600},
+	/*3 */
+	{0x000016A0, 0xC0C04504},
+	/*4 */
+	{0x000016A0, 0xC1009919},
+	/*5 */
+	{0x000016A0, 0xC1407911},
+	/*6 */
+	{0x000016A0, 0xC180B11F},
+	/*7 */
+	{0x000016A0, 0xC1C0610B},
+	/*8 */
+	{0x000016A0, 0xC2008113},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000F},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_667_M[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/* CS 0 */
+	/*0             2               3               1 */
+	{0x000016A0, 0xC0020103},
+	/*1            2               2               6 */
+	{0x000016A0, 0xC0420012},
+	/*2            2               3               16 */
+	{0x000016A0, 0xC0820113},
+	/*3            2               1               26 */
+	{0x000016A0, 0xC0C20012},
+	/*4            2               2               29 */
+	{0x000016A0, 0xC1020100},
+	/*5            2               2               13 */
+	{0x000016A0, 0xC1420016},
+	/*6            2               3               6 */
+	{0x000016A0, 0xC1820109},
+	/*7            2               1               31 */
+	{0x000016A0, 0xC1C20010},
+	/*8            2               2               22 */
+	{0x000016A0, 0xC2020112},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC000b11F},
+	/*1 */
+	{0x000016A0, 0xC040690D},
+	/*2 */
+	{0x000016A0, 0xC0803600},
+	/*3 */
+	{0x000016A0, 0xC0C0a81D},
+	/*4 */
+	{0x000016A0, 0xC1009919},
+	/*5 */
+	{0x000016A0, 0xC1407911},
+	/*6 */
+	{0x000016A0, 0xC180ad1e},
+	/*7 */
+	{0x000016A0, 0xC1C04d06},
+	/*8 */
+	{0x000016A0, 0xC2008514},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	/* CS 1 */
+
+	{0x000016A0, 0xC0060103},
+	/*1            2               2               6 */
+	{0x000016A0, 0xC0460012},
+	/*2            2               3               16 */
+	{0x000016A0, 0xC0860113},
+	/*3            2               1               26 */
+	{0x000016A0, 0xC0C60012},
+	/*4            2               2               29 */
+	{0x000016A0, 0xC1060100},
+	/*5            2               2               13 */
+	{0x000016A0, 0xC1460016},
+	/*6            2               3               6 */
+	{0x000016A0, 0xC1860109},
+	/*7            2               1               31 */
+	{0x000016A0, 0xC1C60010},
+	/*8            2               2               22 */
+	{0x000016A0, 0xC2060112},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC004b11F},
+	/*1 */
+	{0x000016A0, 0xC044690D},
+	/*2 */
+	{0x000016A0, 0xC0843600},
+	/*3 */
+	{0x000016A0, 0xC0C4a81D},
+	/*4 */
+	{0x000016A0, 0xC1049919},
+	/*5 */
+	{0x000016A0, 0xC1447911},
+	/*6 */
+	{0x000016A0, 0xC184ad1e},
+	/*7 */
+	{0x000016A0, 0xC1C44d06},
+	/*8 */
+	{0x000016A0, 0xC2048514},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC807000F},
+
+	/* Both CS */
+
+	{0x00001538, 0x00000B0B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x00000F0F},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_3[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0 */
+	{0x000016A0, 0xC0020118},
+	/*1 */
+	{0x000016A0, 0xC0420108},
+	/*2 */
+	{0x000016A0, 0xC0820202},
+	/*3 */
+	{0x000016A0, 0xC0C20108},
+	/*4 */
+	{0x000016A0, 0xC1020117},
+	/*5 */
+	{0x000016A0, 0xC142010C},
+	/*6 */
+	{0x000016A0, 0xC182011B},
+	/*7 */
+	{0x000016A0, 0xC1C20107},
+	/*8 */
+	{0x000016A0, 0xC2020113},
+
+	/* Write Leveling */
+	/*0 */
+	{0x000016A0, 0xC0003600},
+	/*1 */
+	{0x000016A0, 0xC0406D0E},
+	/*2 */
+	{0x000016A0, 0xC0805207},
+	/*3 */
+	{0x000016A0, 0xC0C0A81D},
+	/*4 */
+	{0x000016A0, 0xC1009919},
+	/*5 */
+	{0x000016A0, 0xC1407911},
+	/*6 */
+	{0x000016A0, 0xC1803E02},
+	/*7 */
+	{0x000016A0, 0xC1C04D06},
+	/*8 */
+	{0x000016A0, 0xC2008113},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+
+	{0x00001538, 0x0000000B},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000F},	/*Read Data Ready Delay Register */
+
+	/*init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_pcac_600[MV_MAX_DDR3_STATIC_SIZE] = {
+	/* Read Leveling */
+	/*PUP   RdSampleDly (+CL)       Phase   RL ADLL value */
+	/*0 */
+	{0x000016A0, 0xC0020404},
+	/* 1           2               2               6 */
+	{0x000016A0, 0xC042031E},
+	/* 2           2               3               16 */
+	{0x000016A0, 0xC0820411},
+	/* 3           2               1               26 */
+	{0x000016A0, 0xC0C20400},
+	/* 4           2               2               29 */
+	{0x000016A0, 0xC1020404},
+	/* 5           2               2               13 */
+	{0x000016A0, 0xC142031D},
+	/* 6           2               3               6 */
+	{0x000016A0, 0xC182040C},
+	/* 7           2               1               31 */
+	{0x000016A0, 0xC1C2031B},
+	/* 8           2               2               22 */
+	{0x000016A0, 0xC2020112},
+
+	/*  Write Leveling */
+	/* 0 */
+	{0x000016A0, 0xC0004905},
+	/* 1 */
+	{0x000016A0, 0xC040A81D},
+	/* 2 */
+	{0x000016A0, 0xC0804504},
+	/* 3 */
+	{0x000016A0, 0xC0C08013},
+	/* 4 */
+	{0x000016A0, 0xC1004504},
+	/* 5 */
+	{0x000016A0, 0xC140A81D},
+	/* 6 */
+	{0x000016A0, 0xC1805909},
+	/* 7 */
+	{0x000016A0, 0xC1C09418},
+	/* 8 */
+	{0x000016A0, 0xC2006D0E},
+
+	/*center DQS on read cycle */
+	{0x000016A0, 0xC803000F},
+	{0x00001538, 0x00000009},	/*Read Data Sample Delays Register */
+	{0x0000153C, 0x0000000D},	/*Read Data Ready Delay Register */
+	/* init DRAM */
+	{0x00001480, 0x00000001},
+	{0x0, 0x0}
+};
+
+#endif /* __AXP_TRAINING_STATIC_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_vars.h b/drivers/ddr/mvebu/ddr3_axp_vars.h
new file mode 100644
index 0000000..1b0ab56
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_vars.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __AXP_VARS_H
+#define __AXP_VARS_H
+
+#include "ddr3_axp_config.h"
+#include "ddr3_axp_mc_static.h"
+#include "ddr3_axp_training_static.h"
+
+MV_DRAM_MODES ddr_modes[MV_DDR3_MODES_NUMBER] = {
+	/*      Conf name               CPUFreq         FabFreq         Chip ID Chip/Board      MC regs                 Training Values */
+	/* db board values: */
+	{"db_800-400", 0xA, 0x5, 0x0, A0, ddr3_A0_db_400, NULL},
+	{"db_1200-300", 0x2, 0xC, 0x0, A0, ddr3_A0_db_400, NULL},
+	{"db_1200-600", 0x2, 0x5, 0x0, A0, NULL, NULL},
+	{"db_1333-667", 0x3, 0x5, 0x0, A0, ddr3_A0_db_667, ddr3_db_rev2_667},
+	{"db_1600-800", 0xB, 0x5, 0x0, A0, ddr3_A0_db_667, ddr3_db_rev2_800},
+	{"amc_1333-667", 0x3, 0x5, 0x0, A0_AMC, ddr3_A0_AMC_667, NULL},
+	{"db_667-667", 0x9, 0x13, 0x0, Z1, ddr3_Z1_db_600, ddr3_db_667},
+	{"db_800-400", 0xA, 0x1, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_400},
+	{"db_1066-533", 0x1, 0x1, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_533},
+	{"db_1200-300", 0x2, 0xC, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_667},
+	{"db_1200-600", 0x2, 0x5, 0x0, Z1, ddr3_Z1_db_600, NULL},
+	{"db_1333-333", 0x3, 0xC, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_400},
+	{"db_1333-667", 0x3, 0x5, 0x0, Z1, ddr3_Z1_db_600, ddr3_db_667},
+	/* pcac board values (Z1 device): */
+	{"pcac_1200-600", 0x2, 0x5, 0x0, Z1_PCAC, ddr3_Z1_db_600,
+	 ddr3_pcac_600},
+	/* rd board values (Z1 device): */
+	{"rd_667_0", 0x3, 0x5, 0x0, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_0},
+	{"rd_667_1", 0x3, 0x5, 0x1, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_1},
+	{"rd_667_2", 0x3, 0x5, 0x2, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_2},
+	{"rd_667_3", 0x3, 0x5, 0x3, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_3}
+};
+
+/* ODT settings - if needed update the following tables: (ODT_OPT - represents the CS configuration bitmap) */
+
+u16 odt_static[ODT_OPT][MAX_CS] = {	/*        NearEnd/FarEnd */
+	{0, 0, 0, 0},		/* 0000         0/0 - Not supported */
+	{ODT40, 0, 0, 0},	/* 0001         0/1 */
+	{0, 0, 0, 0},		/* 0010         0/0 - Not supported */
+	{ODT40, ODT40, 0, 0},	/* 0011         0/2 */
+	{0, 0, ODT40, 0},	/* 0100         1/0 */
+	{ODT30, 0, ODT30, 0},	/* 0101         1/1 */
+	{0, 0, 0, 0},		/* 0110         0/0 - Not supported */
+	{ODT120, ODT20, ODT20, 0},	/* 0111         1/2 */
+	{0, 0, 0, 0},		/* 1000         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 1001         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 1010         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 1011         0/0 - Not supported */
+	{0, 0, ODT40, 0},	/* 1100         2/0 */
+	{ODT20, 0, ODT120, ODT20},	/* 1101         2/1 */
+	{0, 0, 0, 0},		/* 1110         0/0 - Not supported */
+	{ODT120, ODT30, ODT120, ODT30}	/* 1111         2/2 */
+};
+
+u16 odt_dynamic[ODT_OPT][MAX_CS] = {	/*        NearEnd/FarEnd */
+	{0, 0, 0, 0},		/* 0000         0/0 */
+	{0, 0, 0, 0},		/* 0001         0/1 */
+	{0, 0, 0, 0},		/* 0010         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 0011         0/2 */
+	{0, 0, 0, 0},		/* 0100         1/0 */
+	{ODT120D, 0, ODT120D, 0},	/* 0101         1/1 */
+	{0, 0, 0, 0},		/* 0110         0/0 - Not supported */
+	{0, 0, ODT120D, 0},	/* 0111         1/2 */
+	{0, 0, 0, 0},		/* 1000         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 1001         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 1010         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 1011         0/0 - Not supported */
+	{0, 0, 0, 0},		/* 1100         2/0 */
+	{ODT120D, 0, 0, 0},	/* 1101         2/1 */
+	{0, 0, 0, 0},		/* 1110         0/0 - Not supported */
+	{0, 0, 0, 0}		/* 1111         2/2 */
+};
+
+u32 odt_config[ODT_OPT] = {
+	0, 0x00010000, 0, 0x00030000, 0x04000000, 0x05050104, 0, 0x07430340, 0,
+	    0, 0, 0,
+	0x30000, 0x1C0D100C, 0, 0x3CC330C0
+};
+
+/*
+ * User can manually set SPD values (in case SPD is not available on
+ * DIMM/System).
+ * SPD Values can simplify calculating the DUNIT registers values
+ */
+u8 spd_data[SPD_SIZE] = {
+	/* AXP DB Board DIMM SPD Values - manually set */
+	0x92, 0x10, 0x0B, 0x2, 0x3, 0x19, 0x0, 0x9, 0x09, 0x52, 0x1, 0x8, 0x0C,
+	0x0, 0x7E, 0x0, 0x69, 0x78,
+	0x69, 0x30, 0x69, 0x11, 0x20, 0x89, 0x0, 0x5, 0x3C, 0x3C, 0x0, 0xF0,
+	0x82, 0x5, 0x80, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0F, 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x80, 0x2C, 0x1, 0x10, 0x23, 0x35, 0x28, 0xEB, 0xCA, 0x19, 0x8F
+};
+
+/*
+ * Controller Specific configurations Starts Here - DO NOT MODIFY
+ */
+
+/* Frequency - values are 1/HCLK in ps */
+u32 cpu_fab_clk_to_hclk[FAB_OPT][CLK_CPU] =
+/* CPU Frequency:
+	1000	1066	1200	1333	1500	1666	1800	2000	600		667		800		1600	Fabric */
+{
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 2500, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 4500, 3750, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 2500, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{4000, 3750, 3333, 3000, 2666, 2400, 0, 0, 0, 0, 5000, 2500},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{2500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 5000, 0, 4000, 0, 0, 0, 0, 0, 0, 3750},
+	{5000, 0, 0, 3750, 3333, 0, 0, 0, 0, 0, 0, 3125},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 3330, 3000, 0, 0, 0, 0, 0, 0, 0, 2500},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3750},
+	{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, 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, 3000, 2500, 0},
+	{3000, 0, 2500, 0, 0, 0, 0, 0, 0, 0, 3750, 0}
+};
+
+u32 cpu_ddr_ratios[FAB_OPT][CLK_CPU] =
+/* CPU Frequency:
+	1000	1066	1200	1333	1500	1666	1800	2000	600		667		800		1600	Fabric */
+{
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_333, DDR_400, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_444, DDR_533, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, DDR_400, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DDR_500, DDR_533, DDR_600, DDR_666, DDR_750, DDR_833, 0, 0, 0, 0,
+	 DDR_400, DDR_800},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_333, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DDR_400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, DDR_400, 0, DDR_500, 0, 0, 0, 0, 0, 0, DDR_533},
+	{DDR_400, 0, 0, DDR_533, DDR_600, 0, 0, 0, 0, 0, 0, DDR_640},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, DDR_300, DDR_333, 0, 0, 0, 0, 0, 0, 0, DDR_400},
+	{0, 0, 0, 0, 0, 0, DDR_600, DDR_666, 0, 0, 0, DDR_533},
+	{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, 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, DDR_666, DDR_800, 0},
+	{DDR_666, 0, DDR_800, 0, 0, 0, 0, 0, 0, 0, DDR_533, 0}
+};
+
+u8 div_ratio1to1[CLK_VCO][CLK_DDR] =
+/* DDR Frequency:
+	100		300	360	400	444	500	533	600	666	750	800	833  */
+{ {0xA, 3, 0, 3, 0, 2, 0, 0, 0, 0, 0, 0},	/*  1:1     CLK_CPU_1000  */
+{0xB, 3, 0, 3, 0, 0, 2, 0, 0, 0, 0, 0},	/*  1:1     CLK_CPU_1066  */
+{0xC, 4, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0},	/*  1:1     CLK_CPU_1200  */
+{0xD, 4, 0, 4, 0, 0, 0, 0, 2, 0, 0, 0},	/*      1:1     CLK_CPU_1333  */
+{0xF, 5, 0, 4, 0, 3, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_1500  */
+{0x11, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_1666  */
+{0x12, 6, 5, 4, 0, 0, 0, 3, 0, 0, 0, 0},	/*      1:1     CLK_CPU_1800  */
+{0x14, 7, 0, 5, 0, 4, 0, 0, 3, 0, 0, 0},	/*      1:1     CLK_CPU_2000  */
+{0x6, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1 CLK_CPU_600   */
+{0x6, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_667   */
+{0x8, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1 CLK_CPU_800   */
+{0x10, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1 CLK_CPU_1600   */
+{0x14, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0},	/*  1:1     CLK_CPU_1000 VCO_2000 */
+{0x15, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0},	/*  1:1     CLK_CPU_1066 VCO_2133 */
+{0x18, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0},	/*  1:1     CLK_CPU_1200 VCO_2400 */
+{0x1A, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_1333 VCO_2666 */
+{0x1E, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_1500 VCO_3000 */
+{0x21, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_1666 VCO_3333 */
+{0x24, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_1800 VCO_3600 */
+{0x28, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_2000 VCO_4000 */
+{0xC, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1 CLK_CPU_600 VCO_1200 */
+{0xD, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0},	/*      1:1     CLK_CPU_667 VCO_1333 */
+{0x10, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0},	/*  1:1 CLK_CPU_800 VCO_1600 */
+{0x20, 10, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}	/*      1:1 CLK_CPU_1600 VCO_3200 */
+};
+
+u8 div_ratio2to1[CLK_VCO][CLK_DDR] =
+/* DDR Frequency:
+		100	300	360	400	444	500	533	600	666	750	800	833  */
+{ {0, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0},	/*      2:1     CLK_CPU_1000  */
+{0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_1066  */
+{0, 0, 0, 3, 5, 0, 0, 2, 0, 0, 3, 3},	/*      2:1     CLK_CPU_1200  */
+{0, 0, 0, 0, 0, 0, 5, 0, 2, 0, 3, 0},	/*      2:1     CLK_CPU_1333  */
+{0, 0, 0, 0, 0, 3, 0, 5, 0, 2, 0, 0},	/*      2:1     CLK_CPU_1500  */
+{0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 2},	/*      2:1     CLK_CPU_1666  */
+{0, 0, 0, 0, 0, 0, 0, 3, 0, 5, 0, 0},	/*      2:1     CLK_CPU_1800  */
+{0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 5},	/*      2:1     CLK_CPU_2000  */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_600   */
+{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},	/*  2:1 CLK_CPU_667   */
+{0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0},	/*      2:1 CLK_CPU_800   */
+{0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0},	/*      2:1 CLK_CPU_1600   */
+{0, 0, 0, 5, 0, 0, 0, 0, 3, 0, 0, 0},	/*      2:1     CLK_CPU_1000 VCO_2000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_1066 VCO_2133 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0},	/*      2:1     CLK_CPU_1200 VCO_2400 */
+{0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_1333 VCO_2666 */
+{0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0},	/*      2:1     CLK_CPU_1500 VCO_3000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_1666 VCO_3333 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_1800 VCO_3600 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_2000 VCO_4000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/*      2:1     CLK_CPU_600 VCO_1200 */
+{0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0},	/*  2:1 CLK_CPU_667 VCO_1333 */
+{0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0},	/*      2:1 CLK_CPU_800 VCO_1600 */
+{0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0}	/*      2:1 CLK_CPU_1600 VCO_3200 */
+};
+
+#endif /* __AXP_VARS_H */
diff --git a/drivers/ddr/mvebu/ddr3_dfs.c b/drivers/ddr/mvebu/ddr3_dfs.c
new file mode 100644
index 0000000..9347773
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_dfs.c
@@ -0,0 +1,1552 @@
+/*
+ * 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_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_DFS_C(s, d, l) \
+	DEBUG_DFS_S(s); DEBUG_DFS_D(d, l); DEBUG_DFS_S("\n")
+#define DEBUG_DFS_FULL_C(s, d, l) \
+	DEBUG_DFS_FULL_S(s); DEBUG_DFS_FULL_D(d, l); DEBUG_DFS_FULL_S("\n")
+
+#ifdef MV_DEBUG_DFS
+#define DEBUG_DFS_S(s)			puts(s)
+#define DEBUG_DFS_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_DFS_S(s)
+#define DEBUG_DFS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_DFS_FULL
+#define DEBUG_DFS_FULL_S(s)		puts(s)
+#define DEBUG_DFS_FULL_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_DFS_FULL_S(s)
+#define DEBUG_DFS_FULL_D(d, l)
+#endif
+
+#if defined(MV88F672X)
+extern u8 div_ratio[CLK_VCO][CLK_DDR];
+extern void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+#else
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+extern u8 div_ratio1to1[CLK_CPU][CLK_DDR];
+extern u8 div_ratio2to1[CLK_CPU][CLK_DDR];
+#endif
+extern u16 odt_static[ODT_OPT][MAX_CS];
+
+extern u32 cpu_fab_clk_to_hclk[FAB_OPT][CLK_CPU];
+
+extern u32 ddr3_get_vco_freq(void);
+
+u32 ddr3_get_freq_parameter(u32 target_freq, int ratio_2to1);
+
+#ifdef MV_DEBUG_DFS
+static inline void dfs_reg_write(u32 addr, u32 val)
+{
+	printf("\n write reg 0x%08x = 0x%08x", addr, val);
+	writel(val, INTER_REGS_BASE + addr);
+}
+#else
+static inline void dfs_reg_write(u32 addr, u32 val)
+{
+	writel(val, INTER_REGS_BASE + addr);
+}
+#endif
+
+static void wait_refresh_op_complete(void)
+{
+	u32 reg;
+
+	/* Poll - Wait for Refresh operation completion */
+	do {
+		reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+			REG_SDRAM_OPERATION_CMD_RFRS_DONE;
+	} while (reg);		/* Wait for '0' */
+}
+
+/*
+ * Name:     ddr3_get_freq_parameter
+ * Desc:     Finds CPU/DDR frequency ratio according to Sample@reset and table.
+ * Args:     target_freq - target frequency
+ * Notes:
+ * Returns:  freq_par - the ratio parameter
+ */
+u32 ddr3_get_freq_parameter(u32 target_freq, int ratio_2to1)
+{
+	u32 ui_vco_freq, freq_par;
+
+	ui_vco_freq = ddr3_get_vco_freq();
+
+#if defined(MV88F672X)
+	freq_par = div_ratio[ui_vco_freq][target_freq];
+#else
+	/* Find the ratio between PLL frequency and ddr-clk */
+	if (ratio_2to1)
+		freq_par = div_ratio2to1[ui_vco_freq][target_freq];
+	else
+		freq_par = div_ratio1to1[ui_vco_freq][target_freq];
+#endif
+
+	return freq_par;
+}
+
+/*
+ * Name:     ddr3_dfs_high_2_low
+ * Desc:
+ * Args:     freq - target frequency
+ * Notes:
+ * Returns:  MV_OK - success, MV_FAIL - fail
+ */
+int ddr3_dfs_high_2_low(u32 freq, MV_DRAM_INFO *dram_info)
+{
+#if defined(MV88F78X60) || defined(MV88F672X)
+	/* This Flow is relevant for ArmadaXP A0 */
+	u32 reg, freq_par, tmp;
+	u32 cs = 0;
+
+	DEBUG_DFS_C("DDR3 - DFS - High To Low - Starting DFS procedure to Frequency - ",
+		    freq, 1);
+
+	/* target frequency - 100MHz */
+	freq_par = ddr3_get_freq_parameter(freq, 0);
+
+#if defined(MV88F672X)
+	u32 hclk;
+	u32 cpu_freq = ddr3_get_cpu_freq();
+	get_target_freq(cpu_freq, &tmp, &hclk);
+#endif
+
+	/* Configure - DRAM DLL final state after DFS is complete - Enable */
+	reg = reg_read(REG_DFS_ADDR);
+	/* [0] - DfsDllNextState - Disable */
+	reg |= (1 << REG_DFS_DLLNEXTSTATE_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Configure - XBAR Retry response during Block to enable internal
+	 * access - Disable
+	 */
+	reg = reg_read(REG_METAL_MASK_ADDR);
+	/* [0] - RetryMask - Disable */
+	reg &= ~(1 << REG_METAL_MASK_RETRY_OFFS);
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	/* Configure - Block new external transactions - Enable */
+	reg = reg_read(REG_DFS_ADDR);
+	reg |= (1 << REG_DFS_BLOCK_OFFS);	/* [1] - DfsBlock - Enable  */
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Registered DIMM support */
+	if (dram_info->reg_dimm) {
+		/*
+		 * Configure - Disable Register DIMM CKE Power
+		 * Down mode - CWA_RC
+		 */
+		reg = (0x9 & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+			REG_SDRAM_OPERATION_CWA_RC_OFFS;
+		/*
+		 * Configure - Disable Register DIMM CKE Power
+		 * Down mode - CWA_DATA
+		 */
+		reg |= ((0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+			REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+
+		/*
+		 * Configure - Disable Register DIMM CKE Power
+		 * Down mode - Set Delay - tMRD
+		 */
+		reg |= (0 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+
+		/* Configure - Issue CWA command with the above parameters */
+		reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+			~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+		/* 0x1418 - SDRAM Operation Register */
+		dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+		/* Poll - Wait for CWA operation completion */
+		do {
+			reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+			       (REG_SDRAM_OPERATION_CMD_MASK);
+		} while (reg);
+
+		/* Configure - Disable outputs floating during Self Refresh */
+		reg = reg_read(REG_REGISTERED_DRAM_CTRL_ADDR);
+		/* [15] - SRFloatEn - Disable */
+		reg &= ~(1 << REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS);
+		/* 0x16D0 - DDR3 Registered DRAM Control */
+		dfs_reg_write(REG_REGISTERED_DRAM_CTRL_ADDR, reg);
+	}
+
+	/* Optional - Configure - DDR3_Rtt_nom_CS# */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			reg = reg_read(REG_DDR3_MR1_CS_ADDR +
+				       (cs << MR_CS_ADDR_OFFS));
+			reg &= REG_DDR3_MR1_RTT_MASK;
+			dfs_reg_write(REG_DDR3_MR1_CS_ADDR +
+				      (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	/* Configure - Move DRAM into Self Refresh */
+	reg = reg_read(REG_DFS_ADDR);
+	reg |= (1 << REG_DFS_SR_OFFS);	/* [2] - DfsSR - Enable */
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Poll - Wait for Self Refresh indication */
+	do {
+		reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+	} while (reg == 0x0);	/* 0x1528 [3] - DfsAtSR - Wait for '1' */
+
+	/* Start of clock change procedure (PLL) */
+#if defined(MV88F672X)
+	/* avantaLP */
+	/* Configure    cpupll_clkdiv_reset_mask */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+	reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL0_MASK;
+	/* 0xE8264[7:0]   0xff CPU Clock Dividers Reset mask */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, (reg + 0xFF));
+
+	/* Configure    cpu_clkdiv_reload_smooth    */
+	reg = reg_read(CPU_PLL_CNTRL0);
+	reg &= CPU_PLL_CNTRL0_RELOAD_SMOOTH_MASK;
+	/* 0xE8260   [15:8]  0x2 CPU Clock Dividers Reload Smooth enable */
+	dfs_reg_write(CPU_PLL_CNTRL0,
+		      (reg + (2 << CPU_PLL_CNTRL0_RELOAD_SMOOTH_OFFS)));
+
+	/* Configure    cpupll_clkdiv_relax_en */
+	reg = reg_read(CPU_PLL_CNTRL0);
+	reg &= CPU_PLL_CNTRL0_RELAX_EN_MASK;
+	/* 0xE8260 [31:24] 0x2 Relax Enable */
+	dfs_reg_write(CPU_PLL_CNTRL0,
+		      (reg + (2 << CPU_PLL_CNTRL0_RELAX_EN_OFFS)));
+
+	/* Configure    cpupll_clkdiv_ddr_clk_ratio */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL1);
+	/*
+	 * 0xE8268  [13:8]  N   Set Training clock:
+	 * APLL Out Clock (VCO freq) / N = 100 MHz
+	 */
+	reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL1_MASK;
+	reg |= (freq_par << 8);	/* full Integer ratio from PLL-out to ddr-clk */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL1, reg);
+
+	/* Configure    cpupll_clkdiv_reload_ratio  */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+	reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+	/* 0xE8264 [8]=0x1 CPU Clock Dividers Reload Ratio trigger set */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0,
+		      (reg + (1 << CPU_PLL_CLOCK_RELOAD_RATIO_OFFS)));
+
+	udelay(1);
+
+	/* Configure    cpupll_clkdiv_reload_ratio  */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+	reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+	/* 0xE8264 [8]=0x0 CPU Clock Dividers Reload Ratio trigger clear */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, reg);
+
+	udelay(5);
+
+#else
+	/*
+	 * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+	 * and in the same chance, block reassertions of reset [15:8] and
+	 * force reserved bits[7:0].
+	 */
+	reg = 0x0000FDFF;
+	/* 0x18700 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	/*
+	 * RelaX whenever reset is asserted to that channel
+	 * (good for any case)
+	 */
+	reg = 0x0000FF00;
+	/* 0x18704 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+	reg = reg_read(REG_CPU_DIV_CLK_CTRL_2_ADDR) &
+		REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+
+	/* full Integer ratio from PLL-out to ddr-clk */
+	reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+	/* 0x1870C - CPU Div CLK control 3 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_2_ADDR, reg);
+
+	/*
+	 * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+	 * All the rest are kept as is (forced, but could be read-modify-write).
+	 * This is done now by RMW above.
+	 */
+
+	/* Clock is not shut off gracefully - keep it running */
+	reg = 0x000FFF02;
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+	/* Wait before replacing the clock on the DDR Phy Channel. */
+	udelay(1);
+
+	/*
+	 * This for triggering the frequency update. Bit[24] is the
+	 * central control
+	 * bits [23:16] == which channels to change ==2 ==>
+	 *                 only DDR Phy (smooth transition)
+	 * bits [15:8] == mask reset reassertion due to clock modification
+	 *                to these channels.
+	 * bits [7:0] == not in use
+	 */
+	reg = 0x0102FDFF;
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	udelay(1);		/* Wait 1usec */
+
+	/*
+	 * Poll Div CLK status 0 register - indication that the clocks
+	 * are active - 0x18718 [8]
+	 */
+	do {
+		reg = (reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR)) &
+			(1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+	} while (reg == 0);
+
+	/*
+	 * Clean the CTRL0, to be ready for next resets and next requests
+	 * of ratio modifications.
+	 */
+	reg = 0x000000FF;
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	udelay(5);
+#endif
+	/* End of clock change procedure (PLL) */
+
+	/* Configure - Select normal clock for the DDR PHY - Enable */
+	reg = reg_read(REG_DRAM_INIT_CTRL_STATUS_ADDR);
+	/* [16] - ddr_phy_trn_clk_sel - Enable  */
+	reg |= (1 << REG_DRAM_INIT_CTRL_TRN_CLK_OFFS);
+	/* 0x18488 - DRAM Init control status register */
+	dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+	/* Configure - Set Correct Ratio - 1:1 */
+	/* [15] - Phy2UnitClkRatio = 0 - Set 1:1 Ratio between Dunit and Phy */
+
+	reg = reg_read(REG_DDR_IO_ADDR) & ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+	dfs_reg_write(REG_DDR_IO_ADDR, reg);	/* 0x1524 - DDR IO Register */
+
+	/* Configure - 2T Mode - Restore original configuration */
+	reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+	/* [3:4] 2T - 1T Mode - low freq */
+	reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+	/* 0x1404 - DDR Controller Control Low Register */
+	dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+	/* Configure - Restore CL and CWL - MRS Commands */
+	reg = reg_read(REG_DFS_ADDR);
+	reg &= ~(REG_DFS_CL_NEXT_STATE_MASK << REG_DFS_CL_NEXT_STATE_OFFS);
+	reg &= ~(REG_DFS_CWL_NEXT_STATE_MASK << REG_DFS_CWL_NEXT_STATE_OFFS);
+	/* [8] - DfsCLNextState - MRS CL=6 after DFS (due to DLL-off mode) */
+	reg |= (0x4 << REG_DFS_CL_NEXT_STATE_OFFS);
+	/* [12] - DfsCWLNextState - MRS CWL=6 after DFS (due to DLL-off mode) */
+	reg |= (0x1 << REG_DFS_CWL_NEXT_STATE_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Poll - Wait for APLL + ADLLs lock on new frequency */
+	do {
+		reg = (reg_read(REG_PHY_LOCK_STATUS_ADDR)) &
+			REG_PHY_LOCK_APLL_ADLL_STATUS_MASK;
+		/* 0x1674 [10:0] - Phy lock status Register */
+	} while (reg != REG_PHY_LOCK_APLL_ADLL_STATUS_MASK);
+
+	/* Configure - Reset the PHY Read FIFO and Write channels - Set Reset */
+	reg = (reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK);
+	/* [30:29] = 0 - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	/*
+	 * Configure - DRAM Data PHY Read [30], Write [29] path
+	 * reset - Release Reset
+	 */
+	reg = (reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK);
+	/* [30:29] = '11' - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	/* Registered DIMM support */
+	if (dram_info->reg_dimm) {
+		/*
+		 * Configure - Change register DRAM operating speed
+		 * (below 400MHz) - CWA_RC
+		 */
+		reg = (0xA & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+			REG_SDRAM_OPERATION_CWA_RC_OFFS;
+
+		/*
+		 * Configure - Change register DRAM operating speed
+		 * (below 400MHz) - CWA_DATA
+		 */
+		reg |= ((0x0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+			REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+
+		/* Configure - Set Delay - tSTAB */
+		reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+
+		/* Configure - Issue CWA command with the above parameters */
+		reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+			~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+		/* 0x1418 - SDRAM Operation Register */
+		dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+		/* Poll - Wait for CWA operation completion */
+		do {
+			reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+				(REG_SDRAM_OPERATION_CMD_MASK);
+		} while (reg);
+	}
+
+	/* Configure - Exit Self Refresh */
+	/* [2] - DfsSR  */
+	reg = (reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS));
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Poll - DFS Register - 0x1528 [3] - DfsAtSR - All DRAM devices
+	 * on all ranks are NOT in self refresh mode
+	 */
+	do {
+		reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+	} while (reg);		/* Wait for '0' */
+
+	/* Configure - Issue Refresh command */
+	/* [3-0] = 0x2 - Refresh Command, [11-8] - enabled Cs */
+	reg = REG_SDRAM_OPERATION_CMD_RFRS;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs))
+			reg &= ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+	}
+
+	/* 0x1418 - SDRAM Operation Register */
+	dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+	/* Poll - Wait for Refresh operation completion */
+	wait_refresh_op_complete();
+
+	/* Configure - Block new external transactions - Disable */
+	reg = reg_read(REG_DFS_ADDR);
+	reg &= ~(1 << REG_DFS_BLOCK_OFFS);	/* [1] - DfsBlock - Disable  */
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Configure -  XBAR Retry response during Block to enable
+	 * internal access - Disable
+	 */
+	reg = reg_read(REG_METAL_MASK_ADDR);
+	/* [0] - RetryMask - Enable */
+	reg |= (1 << REG_METAL_MASK_RETRY_OFFS);
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			/* Configure - Set CL */
+			reg = reg_read(REG_DDR3_MR0_CS_ADDR +
+				       (cs << MR_CS_ADDR_OFFS)) &
+				~REG_DDR3_MR0_CL_MASK;
+			tmp = 0x4;	/* CL=6 - 0x4 */
+			reg |= ((tmp & 0x1) << REG_DDR3_MR0_CL_OFFS);
+			reg |= ((tmp & 0xE) << REG_DDR3_MR0_CL_HIGH_OFFS);
+			dfs_reg_write(REG_DDR3_MR0_CS_ADDR +
+				      (cs << MR_CS_ADDR_OFFS), reg);
+
+			/* Configure - Set CWL */
+			reg = reg_read(REG_DDR3_MR2_CS_ADDR +
+				       (cs << MR_CS_ADDR_OFFS))
+				& ~(REG_DDR3_MR2_CWL_MASK << REG_DDR3_MR2_CWL_OFFS);
+			/* CWL=6 - 0x1 */
+			reg |= ((0x1) << REG_DDR3_MR2_CWL_OFFS);
+			dfs_reg_write(REG_DDR3_MR2_CS_ADDR +
+				      (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	DEBUG_DFS_C("DDR3 - DFS - High To Low - Ended successfuly - new Frequency - ",
+		    freq, 1);
+
+	return MV_OK;
+#else
+	/* This Flow is relevant for Armada370 A0 and ArmadaXP Z1 */
+
+	u32 reg, freq_par;
+	u32 cs = 0;
+
+	DEBUG_DFS_C("DDR3 - DFS - High To Low - Starting DFS procedure to Frequency - ",
+		    freq, 1);
+
+	/* target frequency - 100MHz */
+	freq_par = ddr3_get_freq_parameter(freq, 0);
+
+	reg = 0x0000FF00;
+	/* 0x18700 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+	/* 0x1600 - ODPG_CNTRL_Control */
+	reg = reg_read(REG_ODPG_CNTRL_ADDR);
+	/* [21] = 1 - auto refresh disable */
+	reg |= (1 << REG_ODPG_CNTRL_OFFS);
+	dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+	/* 0x1670 - PHY lock mask register */
+	reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+	reg &= REG_PHY_LOCK_MASK_MASK;	/* [11:0] = 0 */
+	dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+	reg = reg_read(REG_DFS_ADDR);	/* 0x1528 - DFS register */
+
+	/* Disable reconfig */
+	reg &= ~0x10;	/* [4] - Enable reconfig MR registers after DFS_ERG */
+	reg |= 0x1;	/* [0] - DRAM DLL disabled after DFS */
+
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	reg = reg_read(REG_METAL_MASK_ADDR) & ~(1 << 0); /* [0] - disable */
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	/* [1] - DFS Block enable  */
+	reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_BLOCK_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* [2] - DFS Self refresh enable  */
+	reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_SR_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Poll DFS Register - 0x1528 [3] - DfsAtSR -
+	 * All DRAM devices on all ranks are in self refresh mode -
+	 * DFS can be executed afterwards
+	 */
+	do {
+		reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+	} while (reg == 0x0);	/* Wait for '1' */
+
+	/* Disable ODT on DLL-off mode */
+	dfs_reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR,
+		      REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK);
+
+	/* [11:0] = 0 */
+	reg = (reg_read(REG_PHY_LOCK_MASK_ADDR) & REG_PHY_LOCK_MASK_MASK);
+	/* 0x1670 - PHY lock mask register */
+	dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+	/* Add delay between entering SR and start ratio modification */
+	udelay(1);
+
+	/*
+	 * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+	 * and in the same chance, block reassertions of reset [15:8] and
+	 * force reserved bits[7:0].
+	 */
+	reg = 0x0000FDFF;
+	/* 0x18700 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	/*
+	 * RelaX whenever reset is asserted to that channel (good for any case)
+	 */
+	reg = 0x0000FF00;
+	/* 0x18700 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+	reg = reg_read(REG_CPU_DIV_CLK_CTRL_3_ADDR) &
+		REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+	/* Full Integer ratio from PLL-out to ddr-clk */
+	reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+	/* 0x1870C - CPU Div CLK control 3 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_3_ADDR, reg);
+
+	/*
+	 * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+	 * All the rest are kept as is (forced, but could be read-modify-write).
+	 * This is done now by RMW above.
+	 */
+
+	/* Clock is not shut off gracefully - keep it running */
+	reg = 0x000FFF02;
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+	/* Wait before replacing the clock on the DDR Phy Channel. */
+	udelay(1);
+
+	/*
+	 * This for triggering the frequency update. Bit[24] is the
+	 * central control
+	 * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+	 *                 (smooth transition)
+	 * bits [15:8] == mask reset reassertion due to clock modification
+	 *                to these channels.
+	 * bits [7:0] == not in use
+	 */
+	reg = 0x0102FDFF;
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	udelay(1);		/* Wait 1usec */
+
+	/*
+	 * Poll Div CLK status 0 register - indication that the clocks
+	 * are active - 0x18718 [8]
+	 */
+	do {
+		reg = (reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR)) &
+			(1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+	} while (reg == 0);
+
+	/*
+	 * Clean the CTRL0, to be ready for next resets and next requests of
+	 * ratio modifications.
+	 */
+	reg = 0x000000FF;
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	udelay(5);
+
+	/* Switch HCLK Mux to training clk (100Mhz), keep DFS request bit */
+	reg = 0x20050000;
+	/* 0x18488 - DRAM Init control status register */
+	dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+	reg = reg_read(REG_DDR_IO_ADDR) & ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+	/* [15] = 0 - Set 1:1 Ratio between Dunit and Phy */
+	dfs_reg_write(REG_DDR_IO_ADDR, reg);	/* 0x1524 - DDR IO Regist */
+
+	reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK;
+	/* [31:30]] - reset pup data ctrl ADLL */
+	/* 0x15EC - DRAM PHY Config register */
+	dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+	reg = (reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK);
+	/* [31:30] - normal pup data ctrl ADLL */
+	/* 0x15EC - DRAM PHY Config register */
+	dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+	udelay(1);		/* Wait 1usec */
+
+	/* 0x1404 */
+	reg = (reg_read(REG_DUNIT_CTRL_LOW_ADDR) & 0xFFFFFFE7);
+	dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+	/* Poll Phy lock status register - APLL lock indication - 0x1674 */
+	do {
+		reg = (reg_read(REG_PHY_LOCK_STATUS_ADDR)) &
+			REG_PHY_LOCK_STATUS_LOCK_MASK;
+	} while (reg != REG_PHY_LOCK_STATUS_LOCK_MASK);	/* Wait for '0xFFF' */
+
+	reg = (reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK);
+	/* [30:29] = 0 - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+	/* [30:29] = '11' - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	udelay(1000);		/* Wait 1msec */
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			/* Poll - Wait for Refresh operation completion */
+			wait_refresh_op_complete();
+
+			/* Config CL and CWL with MR0 and MR2 registers */
+			reg = reg_read(REG_DDR3_MR0_ADDR);
+			reg &= ~0x74;	/* CL [3:0]; [6:4],[2] */
+			reg |= (1 << 5);	/* CL = 4, CAS is 6 */
+			dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+			reg = REG_SDRAM_OPERATION_CMD_MR0 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/* 0x1418 - SDRAM Operation Register */
+			dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			/* Poll - Wait for Refresh operation completion */
+			wait_refresh_op_complete();
+
+			reg = reg_read(REG_DDR3_MR2_ADDR);
+			reg &= ~0x38;	/* CWL [5:3] */
+			reg |= (1 << 3);	/* CWL = 1, CWL is 6 */
+			dfs_reg_write(REG_DDR3_MR2_ADDR, reg);
+
+			reg = REG_SDRAM_OPERATION_CMD_MR2 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/* 0x1418 - SDRAM Operation Register */
+			dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			/* Poll - Wait for Refresh operation completion */
+			wait_refresh_op_complete();
+
+			/* Set current rd_sample_delay  */
+			reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+			reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+				 (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+			reg |= (5 << (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+			dfs_reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+			/* Set current rd_ready_delay  */
+			reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+			reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+				 (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+			reg |= ((6) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+			dfs_reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+		}
+	}
+
+	/* [2] - DFS Self refresh disable  */
+	reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* [1] - DFS Block enable  */
+	reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_BLOCK_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Poll DFS Register - 0x1528 [3] - DfsAtSR -
+	 * All DRAM devices on all ranks are in self refresh mode - DFS can
+	 * be executed afterwards
+	 */
+	do {
+		reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+	} while (reg);		/* Wait for '1' */
+
+	reg = (reg_read(REG_METAL_MASK_ADDR) | (1 << 0));
+	/* [0] - Enable Dunit to crossbar retry */
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	/* 0x1600 - PHY lock mask register */
+	reg = reg_read(REG_ODPG_CNTRL_ADDR);
+	reg &= ~(1 << REG_ODPG_CNTRL_OFFS);	/* [21] = 0 */
+	dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+	/* 0x1670 - PHY lock mask register */
+	reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+	reg |= ~REG_PHY_LOCK_MASK_MASK;	/* [11:0] = FFF */
+	dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+	DEBUG_DFS_C("DDR3 - DFS - High To Low - Ended successfuly - new Frequency - ",
+		    freq, 1);
+
+	return MV_OK;
+#endif
+}
+
+/*
+ * Name:     ddr3_dfs_low_2_high
+ * Desc:
+ * Args:     freq - target frequency
+ * Notes:
+ * Returns:  MV_OK - success, MV_FAIL - fail
+ */
+int ddr3_dfs_low_2_high(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+#if defined(MV88F78X60) || defined(MV88F672X)
+	/* This Flow is relevant for ArmadaXP A0 */
+	u32 reg, freq_par, tmp;
+	u32 cs = 0;
+
+	DEBUG_DFS_C("DDR3 - DFS - Low To High - Starting DFS procedure to Frequency - ",
+		    freq, 1);
+
+	/* target frequency - freq */
+	freq_par = ddr3_get_freq_parameter(freq, ratio_2to1);
+
+#if defined(MV88F672X)
+	u32 hclk;
+	u32 cpu_freq = ddr3_get_cpu_freq();
+	get_target_freq(cpu_freq, &tmp, &hclk);
+#endif
+
+	/* Configure - DRAM DLL final state after DFS is complete - Enable */
+	reg = reg_read(REG_DFS_ADDR);
+	/* [0] - DfsDllNextState - Enable */
+	reg &= ~(1 << REG_DFS_DLLNEXTSTATE_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Configure -  XBAR Retry response during Block to enable
+	 * internal access - Disable
+	 */
+	reg = reg_read(REG_METAL_MASK_ADDR);
+	/* [0] - RetryMask - Disable */
+	reg &= ~(1 << REG_METAL_MASK_RETRY_OFFS);
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	/* Configure - Block new external transactions - Enable */
+	reg = reg_read(REG_DFS_ADDR);
+	reg |= (1 << REG_DFS_BLOCK_OFFS);	/* [1] - DfsBlock - Enable  */
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Configure - Move DRAM into Self Refresh */
+	reg = reg_read(REG_DFS_ADDR);
+	reg |= (1 << REG_DFS_SR_OFFS);	/* [2] - DfsSR - Enable */
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Poll - Wait for Self Refresh indication */
+	do {
+		reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+	} while (reg == 0x0);	/* 0x1528 [3] - DfsAtSR - Wait for '1' */
+
+	/* Start of clock change procedure (PLL) */
+#if defined(MV88F672X)
+	/* avantaLP */
+	/* Configure    cpupll_clkdiv_reset_mask */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+	reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL0_MASK;
+	/* 0xE8264[7:0]   0xff CPU Clock Dividers Reset mask */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, (reg + 0xFF));
+
+	/* Configure    cpu_clkdiv_reload_smooth    */
+	reg = reg_read(CPU_PLL_CNTRL0);
+	reg &= CPU_PLL_CNTRL0_RELOAD_SMOOTH_MASK;
+	/* 0xE8260   [15:8]  0x2 CPU Clock Dividers Reload Smooth enable */
+	dfs_reg_write(CPU_PLL_CNTRL0,
+		      reg + (2 << CPU_PLL_CNTRL0_RELOAD_SMOOTH_OFFS));
+
+	/* Configure    cpupll_clkdiv_relax_en */
+	reg = reg_read(CPU_PLL_CNTRL0);
+	reg &= CPU_PLL_CNTRL0_RELAX_EN_MASK;
+	/* 0xE8260 [31:24] 0x2 Relax Enable */
+	dfs_reg_write(CPU_PLL_CNTRL0,
+		      reg + (2 << CPU_PLL_CNTRL0_RELAX_EN_OFFS));
+
+	/* Configure    cpupll_clkdiv_ddr_clk_ratio */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL1);
+	/*
+	 * 0xE8268  [13:8]  N   Set Training clock:
+	 * APLL Out Clock (VCO freq) / N = 100 MHz
+	 */
+	reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL1_MASK;
+	reg |= (freq_par << 8);	/* full Integer ratio from PLL-out to ddr-clk */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL1, reg);
+	/* Configure    cpupll_clkdiv_reload_ratio  */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+	reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+	/* 0xE8264 [8]=0x1 CPU Clock Dividers Reload Ratio trigger set */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0,
+		      reg + (1 << CPU_PLL_CLOCK_RELOAD_RATIO_OFFS));
+
+	udelay(1);
+
+	/* Configure    cpupll_clkdiv_reload_ratio  */
+	reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+	reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+	/* 0xE8264 [8]=0x0 CPU Clock Dividers Reload Ratio trigger clear */
+	dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, reg);
+
+	udelay(5);
+
+#else
+	/*
+	 * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+	 * and in the same chance, block reassertions of reset [15:8]
+	 * and force reserved bits[7:0].
+	 */
+	reg = 0x0000FFFF;
+
+	/* 0x18700 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	/*
+	 * RelaX whenever reset is asserted to that channel (good for any case)
+	 */
+	reg = 0x0000FF00;
+	/* 0x18704 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+	reg = reg_read(REG_CPU_DIV_CLK_CTRL_2_ADDR) &
+		REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+	reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+	/* full Integer ratio from PLL-out to ddr-clk */
+	/* 0x1870C - CPU Div CLK control 3 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_2_ADDR, reg);
+
+	/*
+	 * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+	 * All the rest are kept as is (forced, but could be read-modify-write).
+	 * This is done now by RMW above.
+	 */
+	reg = 0x000FFF02;
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+	/* Wait before replacing the clock on the DDR Phy Channel. */
+	udelay(1);
+
+	reg = 0x0102FDFF;
+	/*
+	 * This for triggering the frequency update. Bit[24] is the
+	 * central control
+	 * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+	 *                 (smooth transition)
+	 * bits [15:8] == mask reset reassertion due to clock modification
+	 *                to these channels.
+	 * bits [7:0] == not in use
+	 */
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	udelay(1);
+
+	/*
+	 * Poll Div CLK status 0 register - indication that the clocks
+	 * are active - 0x18718 [8]
+	 */
+	do {
+		reg = reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR) &
+			(1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+	} while (reg == 0);
+
+	reg = 0x000000FF;
+	/*
+	 * Clean the CTRL0, to be ready for next resets and next requests
+	 * of ratio modifications.
+	 */
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+#endif
+	/* End of clock change procedure (PLL) */
+
+	if (ratio_2to1) {
+		/* Configure - Select normal clock for the DDR PHY - Disable */
+		reg = reg_read(REG_DRAM_INIT_CTRL_STATUS_ADDR);
+		/* [16] - ddr_phy_trn_clk_sel - Disable  */
+		reg &= ~(1 << REG_DRAM_INIT_CTRL_TRN_CLK_OFFS);
+		/* 0x18488 - DRAM Init control status register */
+		dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+	}
+
+	/*
+	 * Configure - Set Correct Ratio - according to target ratio
+	 * parameter - 2:1/1:1
+	 */
+	if (ratio_2to1) {
+		/*
+		 * [15] - Phy2UnitClkRatio = 1 - Set 2:1 Ratio between
+		 * Dunit and Phy
+		 */
+		reg = reg_read(REG_DDR_IO_ADDR) |
+			(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+	} else {
+		/*
+		 * [15] - Phy2UnitClkRatio = 0 - Set 1:1 Ratio between
+		 * Dunit and Phy
+		 */
+		reg = reg_read(REG_DDR_IO_ADDR) &
+			~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+	}
+	dfs_reg_write(REG_DDR_IO_ADDR, reg);	/* 0x1524 - DDR IO Register */
+
+	/* Configure - 2T Mode - Restore original configuration */
+	reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+	/* [3:4] 2T - Restore value */
+	reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+	reg |= ((dram_info->mode_2t & REG_DUNIT_CTRL_LOW_2T_MASK) <<
+		REG_DUNIT_CTRL_LOW_2T_OFFS);
+	/* 0x1404 - DDR Controller Control Low Register */
+	dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+	/* Configure - Restore CL and CWL - MRS Commands */
+	reg = reg_read(REG_DFS_ADDR);
+	reg &= ~(REG_DFS_CL_NEXT_STATE_MASK << REG_DFS_CL_NEXT_STATE_OFFS);
+	reg &= ~(REG_DFS_CWL_NEXT_STATE_MASK << REG_DFS_CWL_NEXT_STATE_OFFS);
+
+	if (freq == DDR_400) {
+		if (dram_info->target_frequency == 0x8)
+			tmp = ddr3_cl_to_valid_cl(5);
+		else
+			tmp = ddr3_cl_to_valid_cl(6);
+	} else {
+		tmp = ddr3_cl_to_valid_cl(dram_info->cl);
+	}
+
+	/* [8] - DfsCLNextState */
+	reg |= ((tmp & REG_DFS_CL_NEXT_STATE_MASK) << REG_DFS_CL_NEXT_STATE_OFFS);
+	if (freq == DDR_400) {
+		/* [12] - DfsCWLNextState */
+		reg |= (((0) & REG_DFS_CWL_NEXT_STATE_MASK) <<
+			REG_DFS_CWL_NEXT_STATE_OFFS);
+	} else {
+		/* [12] - DfsCWLNextState */
+		reg |= (((dram_info->cwl) & REG_DFS_CWL_NEXT_STATE_MASK) <<
+			REG_DFS_CWL_NEXT_STATE_OFFS);
+	}
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Optional - Configure - DDR3_Rtt_nom_CS# */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			reg = reg_read(REG_DDR3_MR1_CS_ADDR +
+				       (cs << MR_CS_ADDR_OFFS));
+			reg &= REG_DDR3_MR1_RTT_MASK;
+			reg |= odt_static[dram_info->cs_ena][cs];
+			dfs_reg_write(REG_DDR3_MR1_CS_ADDR +
+				      (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	/* Configure - Reset ADLLs - Set Reset */
+	reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK;
+	/* [31:30]] - reset pup data ctrl ADLL */
+	/* 0x15EC - DRAM PHY Config Register */
+	dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+	/* Configure - Reset ADLLs - Release Reset */
+	reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK;
+	/* [31:30] - normal pup data ctrl ADLL */
+	/* 0x15EC - DRAM PHY Config register */
+	dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+	/* Poll - Wait for APLL + ADLLs lock on new frequency */
+	do {
+		reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+			REG_PHY_LOCK_APLL_ADLL_STATUS_MASK;
+		/* 0x1674 [10:0] - Phy lock status Register */
+	} while (reg != REG_PHY_LOCK_APLL_ADLL_STATUS_MASK);
+
+	/* Configure - Reset the PHY SDR clock divider */
+	if (ratio_2to1) {
+		/* Pup Reset Divider B - Set Reset */
+		/* [28] - DataPupRdRST = 0 */
+		reg = reg_read(REG_SDRAM_CONFIG_ADDR) &
+			~(1 << REG_SDRAM_CONFIG_PUPRSTDIV_OFFS);
+		/* [28] - DataPupRdRST = 1 */
+		tmp = reg_read(REG_SDRAM_CONFIG_ADDR) |
+			(1 << REG_SDRAM_CONFIG_PUPRSTDIV_OFFS);
+		/* 0x1400 - SDRAM Configuration register */
+		dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+		/* Pup Reset Divider B - Release Reset */
+		/* 0x1400 - SDRAM Configuration register */
+		dfs_reg_write(REG_SDRAM_CONFIG_ADDR, tmp);
+	}
+
+	/* Configure - Reset the PHY Read FIFO and Write channels - Set Reset */
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK;
+	/* [30:29] = 0 - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	/*
+	 * Configure - DRAM Data PHY Read [30], Write [29] path reset -
+	 * Release Reset
+	 */
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+	/* [30:29] = '11' - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	/* Registered DIMM support */
+	if (dram_info->reg_dimm) {
+		/*
+		 * Configure - Change register DRAM operating speed
+		 * (DDR3-1333 / DDR3-1600) - CWA_RC
+		 */
+		reg = (0xA & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+			REG_SDRAM_OPERATION_CWA_RC_OFFS;
+		if (freq <= DDR_400) {
+			/*
+			 * Configure - Change register DRAM operating speed
+			 * (DDR3-800) - CWA_DATA
+			 */
+			reg |= ((0x0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+				REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+		} else if ((freq > DDR_400) && (freq <= DDR_533)) {
+			/*
+			 * Configure - Change register DRAM operating speed
+			 * (DDR3-1066) - CWA_DATA
+			 */
+			reg |= ((0x1 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+				REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+		} else if ((freq > DDR_533) && (freq <= DDR_666)) {
+			/*
+			 * Configure - Change register DRAM operating speed
+			 * (DDR3-1333) - CWA_DATA
+			 */
+			reg |= ((0x2 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+				REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+		} else {
+			/*
+			 * Configure - Change register DRAM operating speed
+			 * (DDR3-1600) - CWA_DATA
+			 */
+			reg |= ((0x3 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+				REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+		}
+
+		/* Configure - Set Delay - tSTAB */
+		reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+		/* Configure - Issue CWA command with the above parameters */
+		reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+			~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+		/* 0x1418 - SDRAM Operation Register */
+		dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+		/* Poll - Wait for CWA operation completion */
+		do {
+			reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+				REG_SDRAM_OPERATION_CMD_MASK;
+		} while (reg);
+	}
+
+	/* Configure - Exit Self Refresh */
+	/* [2] - DfsSR  */
+	reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Poll - DFS Register - 0x1528 [3] - DfsAtSR - All DRAM
+	 * devices on all ranks are NOT in self refresh mode
+	 */
+	do {
+		reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+	} while (reg);		/* Wait for '0' */
+
+	/* Configure - Issue Refresh command */
+	/* [3-0] = 0x2 - Refresh Command, [11-8] - enabled Cs */
+	reg = REG_SDRAM_OPERATION_CMD_RFRS;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs))
+			reg &= ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+	}
+
+	/* 0x1418 - SDRAM Operation Register */
+	dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+	/* Poll - Wait for Refresh operation completion */
+	wait_refresh_op_complete();
+
+	/* Configure - Block new external transactions - Disable */
+	reg = reg_read(REG_DFS_ADDR);
+	reg &= ~(1 << REG_DFS_BLOCK_OFFS);	/* [1] - DfsBlock - Disable  */
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Configure -  XBAR Retry response during Block to enable
+	 * internal access - Disable
+	 */
+	reg = reg_read(REG_METAL_MASK_ADDR);
+	/* [0] - RetryMask - Enable */
+	reg |= (1 << REG_METAL_MASK_RETRY_OFFS);
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			/* Configure - Set CL */
+			reg = reg_read(REG_DDR3_MR0_CS_ADDR +
+				       (cs << MR_CS_ADDR_OFFS)) &
+				~REG_DDR3_MR0_CL_MASK;
+			if (freq == DDR_400)
+				tmp = ddr3_cl_to_valid_cl(6);
+			else
+				tmp = ddr3_cl_to_valid_cl(dram_info->cl);
+			reg |= ((tmp & 0x1) << REG_DDR3_MR0_CL_OFFS);
+			reg |= ((tmp & 0xE) << REG_DDR3_MR0_CL_HIGH_OFFS);
+			dfs_reg_write(REG_DDR3_MR0_CS_ADDR +
+				      (cs << MR_CS_ADDR_OFFS), reg);
+
+			/* Configure - Set CWL */
+			reg = reg_read(REG_DDR3_MR2_CS_ADDR +
+				       (cs << MR_CS_ADDR_OFFS)) &
+				~(REG_DDR3_MR2_CWL_MASK << REG_DDR3_MR2_CWL_OFFS);
+			if (freq == DDR_400)
+				reg |= ((0) << REG_DDR3_MR2_CWL_OFFS);
+			else
+				reg |= ((dram_info->cwl) << REG_DDR3_MR2_CWL_OFFS);
+			dfs_reg_write(REG_DDR3_MR2_CS_ADDR +
+				      (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	DEBUG_DFS_C("DDR3 - DFS - Low To High - Ended successfuly - new Frequency - ",
+		    freq, 1);
+
+	return MV_OK;
+
+#else
+
+	/* This Flow is relevant for Armada370 A0 and ArmadaXP Z1 */
+
+	u32 reg, freq_par, tmp;
+	u32 cs = 0;
+
+	DEBUG_DFS_C("DDR3 - DFS - Low To High - Starting DFS procedure to Frequency - ",
+		    freq, 1);
+
+	/* target frequency - freq */
+	freq_par = ddr3_get_freq_parameter(freq, ratio_2to1);
+
+	reg = 0x0000FF00;
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+	/* 0x1600 - PHY lock mask register */
+	reg = reg_read(REG_ODPG_CNTRL_ADDR);
+	reg |= (1 << REG_ODPG_CNTRL_OFFS);	/* [21] = 1 */
+	dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+	/* 0x1670 - PHY lock mask register */
+	reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+	reg &= REG_PHY_LOCK_MASK_MASK;	/* [11:0] = 0 */
+	dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+	/* Enable reconfig MR Registers after DFS */
+	reg = reg_read(REG_DFS_ADDR);	/* 0x1528 - DFS register */
+	/* [4] - Disable - reconfig MR registers after DFS_ERG */
+	reg &= ~0x11;
+	/* [0] - Enable - DRAM DLL after DFS */
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Disable DRAM Controller to crossbar retry */
+	/* [0] - disable */
+	reg = reg_read(REG_METAL_MASK_ADDR) & ~(1 << 0);
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	/* Enable DRAM Blocking */
+	/* [1] - DFS Block enable  */
+	reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_BLOCK_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Enable Self refresh */
+	/* [2] - DFS Self refresh enable  */
+	reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_SR_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Poll DFS Register - All DRAM devices on all ranks are in
+	 * self refresh mode - DFS can be executed afterwards
+	 */
+	/* 0x1528 [3] - DfsAtSR  */
+	do {
+		reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+	} while (reg == 0x0);	/* Wait for '1' */
+
+	/*
+	 * Set Correct Ratio - if freq>MARGIN_FREQ use 2:1 ratio
+	 * else use 1:1 ratio
+	 */
+	if (ratio_2to1) {
+		/* [15] = 1 - Set 2:1 Ratio between Dunit and Phy */
+		reg = reg_read(REG_DDR_IO_ADDR) |
+			(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+	} else {
+		/* [15] = 0 - Set 1:1 Ratio between Dunit and Phy */
+		reg = reg_read(REG_DDR_IO_ADDR) &
+			~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+	}
+	dfs_reg_write(REG_DDR_IO_ADDR, reg);	/* 0x1524 - DDR IO Register */
+
+	/* Switch HCLK Mux from (100Mhz) [16]=0, keep DFS request bit */
+	reg = 0x20040000;
+	/*
+	 * [29] - training logic request DFS, [28:27] -
+	 * preload patterns frequency [18]
+	 */
+
+	/* 0x18488 - DRAM Init control status register */
+	dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+	/* Add delay between entering SR and start ratio modification */
+	udelay(1);
+
+	/*
+	 * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+	 * and in the same chance, block reassertions of reset [15:8] and
+	 * force reserved bits[7:0].
+	 */
+	reg = 0x0000FFFF;
+	/* 0x18700 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	/*
+	 * RelaX whenever reset is asserted to that channel (good for any case)
+	 */
+	reg = 0x0000FF00;
+	/* 0x18704 - CPU Div CLK control 0 */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+	reg = reg_read(REG_CPU_DIV_CLK_CTRL_3_ADDR) &
+		REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+	reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+	/* Full Integer ratio from PLL-out to ddr-clk */
+	/* 0x1870C - CPU Div CLK control 3 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_3_ADDR, reg);
+
+	/*
+	 * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+	 * All the rest are kept as is (forced, but could be read-modify-write).
+	 * This is done now by RMW above.
+	 */
+
+	reg = 0x000FFF02;
+
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+	/* Wait before replacing the clock on the DDR Phy Channel. */
+	udelay(1);
+
+	reg = 0x0102FDFF;
+	/*
+	 * This for triggering the frequency update. Bit[24] is the
+	 * central control
+	 * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+	 *                 (smooth transition)
+	 * bits [15:8] == mask reset reassertion due to clock modification
+	 *                to these channels.
+	 * bits [7:0] == not in use
+	 */
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	udelay(1);
+
+	/*
+	 * Poll Div CLK status 0 register - indication that the clocks are
+	 * active - 0x18718 [8]
+	 */
+	do {
+		reg = reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR) &
+			(1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+	} while (reg == 0);
+
+	reg = 0x000000FF;
+	/*
+	 * Clean the CTRL0, to be ready for next resets and next requests of
+	 * ratio modifications.
+	 */
+	/* 0x18700 - CPU Div CLK control 0 register */
+	dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+	udelay(5);
+
+	if (ratio_2to1) {
+		/* Pup Reset Divider B - Set Reset */
+		/* [28] = 0 - Pup Reset Divider B */
+		reg = reg_read(REG_SDRAM_CONFIG_ADDR) & ~(1 << 28);
+		/* [28] = 1 - Pup Reset Divider B */
+		tmp = reg_read(REG_SDRAM_CONFIG_ADDR) | (1 << 28);
+		/* 0x1400 - SDRAM Configuration register */
+		dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+		/* Pup Reset Divider B - Release Reset */
+		/* 0x1400 - SDRAM Configuration register */
+		dfs_reg_write(REG_SDRAM_CONFIG_ADDR, tmp);
+	}
+
+	/* DRAM Data PHYs ADLL Reset - Set Reset */
+	reg = (reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK);
+	/* [31:30]] - reset pup data ctrl ADLL */
+	/* 0x15EC - DRAM PHY Config Register */
+	dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+	udelay(25);
+
+	/* APLL lock indication - Poll Phy lock status Register - 0x1674 [9] */
+	do {
+		reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+			(1 << REG_PHY_LOCK_STATUS_LOCK_OFFS);
+	} while (reg == 0);
+
+	/* DRAM Data PHYs ADLL Reset - Release Reset */
+	reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK;
+	/* [31:30] - normal pup data ctrl ADLL */
+	/* 0x15EC - DRAM PHY Config register */
+	dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+	udelay(10000);		/* Wait 10msec */
+
+	/*
+	 * APLL lock indication - Poll Phy lock status Register - 0x1674 [11:0]
+	 */
+	do {
+		reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+			REG_PHY_LOCK_STATUS_LOCK_MASK;
+	} while (reg != REG_PHY_LOCK_STATUS_LOCK_MASK);
+
+	/* DRAM Data PHY Read [30], Write [29] path reset - Set Reset */
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK;
+	/* [30:29] = 0 - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	/* DRAM Data PHY Read [30], Write [29] path reset - Release Reset */
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+	/* [30:29] = '11' - Data Pup R/W path reset */
+	/* 0x1400 - SDRAM Configuration register */
+	dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	/* Disable DFS Reconfig */
+	reg = reg_read(REG_DFS_ADDR) & ~(1 << 4);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* [2] - DFS Self refresh disable  */
+	reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/*
+	 * Poll DFS Register - 0x1528 [3] - DfsAtSR - All DRAM devices on
+	 * all ranks are NOT in self refresh mode
+	 */
+	do {
+		reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+	} while (reg);		/* Wait for '0' */
+
+	/* 0x1404 */
+	reg = (reg_read(REG_DUNIT_CTRL_LOW_ADDR) & 0xFFFFFFE7) | 0x2;
+
+	/* Configure - 2T Mode - Restore original configuration */
+	/* [3:4] 2T - Restore value */
+	reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+	reg |= ((dram_info->mode_2t & REG_DUNIT_CTRL_LOW_2T_MASK) <<
+		REG_DUNIT_CTRL_LOW_2T_OFFS);
+	dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+	udelay(1);		/* Wait 1us */
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			reg = (reg_read(REG_DDR3_MR1_ADDR));
+			/* DLL Enable */
+			reg &= ~(1 << REG_DDR3_MR1_DLL_ENA_OFFS);
+			dfs_reg_write(REG_DDR3_MR1_ADDR, reg);
+
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			/* Poll - Wait for Refresh operation completion */
+			wait_refresh_op_complete();
+
+			/* DLL Reset - MR0 */
+			reg = reg_read(REG_DDR3_MR0_ADDR);
+			dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR0 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			/* Poll - Wait for Refresh operation completion */
+			wait_refresh_op_complete();
+
+			reg = reg_read(REG_DDR3_MR0_ADDR);
+			reg &= ~0x74;	/* CL [3:0]; [6:4],[2] */
+
+			if (freq == DDR_400)
+				tmp = ddr3_cl_to_valid_cl(6) & 0xF;
+			else
+				tmp = ddr3_cl_to_valid_cl(dram_info->cl) & 0xF;
+
+			reg |= ((tmp & 0x1) << 2);
+			reg |= ((tmp >> 1) << 4);	/* to bit 4 */
+			dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+
+			reg = REG_SDRAM_OPERATION_CMD_MR0 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/* 0x1418 - SDRAM Operation Register */
+			dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			/* Poll - Wait for Refresh operation completion */
+			wait_refresh_op_complete();
+
+			reg = reg_read(REG_DDR3_MR2_ADDR);
+			reg &= ~0x38;	/* CWL [5:3] */
+			/* CWL = 0 ,for 400 MHg is 5 */
+			if (freq != DDR_400)
+				reg |= dram_info->cwl << REG_DDR3_MR2_CWL_OFFS;
+			dfs_reg_write(REG_DDR3_MR2_ADDR, reg);
+			reg = REG_SDRAM_OPERATION_CMD_MR2 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/* 0x1418 - SDRAM Operation Register */
+			dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			/* Poll - Wait for Refresh operation completion */
+			wait_refresh_op_complete();
+
+			/* Set current rd_sample_delay  */
+			reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+			reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+				 (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+			reg |= (dram_info->cl <<
+				(REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+			dfs_reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+			/* Set current rd_ready_delay  */
+			reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+			reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+				 (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+			reg |= ((dram_info->cl + 1) <<
+				(REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+			dfs_reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+		}
+	}
+
+	/* Enable ODT on DLL-on mode */
+	dfs_reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, 0);
+
+	/* [1] - DFS Block disable  */
+	reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_BLOCK_OFFS);
+	dfs_reg_write(REG_DFS_ADDR, reg);	/* 0x1528 - DFS register */
+
+	/* Change DDR frequency to 100MHz procedure: */
+	/* 0x1600 - PHY lock mask register */
+	reg = reg_read(REG_ODPG_CNTRL_ADDR);
+	reg &= ~(1 << REG_ODPG_CNTRL_OFFS);	/* [21] = 0 */
+	dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+	/* Change DDR frequency to 100MHz procedure: */
+	/* 0x1670 - PHY lock mask register */
+	reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+	reg |= ~REG_PHY_LOCK_MASK_MASK;	/* [11:0] = FFF */
+	dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+	reg = reg_read(REG_METAL_MASK_ADDR) | (1 << 0);	/* [0] - disable */
+	/* 0x14B0 - Dunit MMask Register */
+	dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+	DEBUG_DFS_C("DDR3 - DFS - Low To High - Ended successfuly - new Frequency - ",
+		    freq, 1);
+	return MV_OK;
+#endif
+}
diff --git a/drivers/ddr/mvebu/ddr3_dqs.c b/drivers/ddr/mvebu/ddr3_dqs.c
new file mode 100644
index 0000000..71a986d
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_dqs.c
@@ -0,0 +1,1374 @@
+/*
+ * 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_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_DQS_C(s, d, l) \
+	DEBUG_DQS_S(s); DEBUG_DQS_D(d, l); DEBUG_DQS_S("\n")
+#define DEBUG_DQS_FULL_C(s, d, l) \
+	DEBUG_DQS_FULL_S(s); DEBUG_DQS_FULL_D(d, l); DEBUG_DQS_FULL_S("\n")
+#define DEBUG_DQS_RESULTS_C(s, d, l) \
+	DEBUG_DQS_RESULTS_S(s); DEBUG_DQS_RESULTS_D(d, l); DEBUG_DQS_RESULTS_S("\n")
+#define DEBUG_PER_DQ_C(s, d, l) \
+	puts(s); printf("%x", d); puts("\n")
+
+#define DEBUG_DQS_RESULTS_S(s) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_DQS_RESULTS_D(d, l) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+
+#define DEBUG_PER_DQ_S(s) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%s", s)
+#define DEBUG_PER_DQ_D(d, l) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%x", d)
+#define DEBUG_PER_DQ_DD(d, l) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%d", d)
+
+#ifdef MV_DEBUG_DQS
+#define DEBUG_DQS_S(s)			puts(s)
+#define DEBUG_DQS_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_DQS_S(s)
+#define DEBUG_DQS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_DQS_FULL
+#define DEBUG_DQS_FULL_S(s)		puts(s)
+#define DEBUG_DQS_FULL_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_DQS_FULL_S(s)
+#define DEBUG_DQS_FULL_D(d, l)
+#endif
+
+/* State machine for centralization - find low & high limit */
+enum {
+	PUP_ADLL_LIMITS_STATE_FAIL,
+	PUP_ADLL_LIMITS_STATE_PASS,
+	PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS,
+};
+
+/* Hold centralization low results */
+static int centralization_low_limit[MAX_PUP_NUM] = { 0 };
+/* Hold centralization high results */
+static int centralization_high_limit[MAX_PUP_NUM] = { 0 };
+
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx);
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+			  int *size_valid);
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+			    int is_tx);
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+			      int is_tx, u32 special_pattern_pup);
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+				   int is_tx, u32 special_pattern_pup);
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+				    int is_tx);
+
+#ifdef MV88F78X60
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern u32 killer_pattern_64b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#else
+extern u32 killer_pattern[DQ_NUM][LEN_16BIT_KILLER_PATTERN];
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+#if defined(MV88F672X)
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#endif
+#endif
+extern u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN];
+
+static u32 *ddr3_dqs_choose_pattern(MV_DRAM_INFO *dram_info, u32 victim_dq)
+{
+	u32 *pattern_ptr;
+
+	/* Choose pattern */
+	switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+	case 16:
+		pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+		break;
+#endif
+	case 32:
+		pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+		break;
+#if defined(MV88F78X60)
+	case 64:
+		pattern_ptr = (u32 *)&killer_pattern_64b[victim_dq];
+		break;
+#endif
+	default:
+#if defined(MV88F78X60)
+		pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+#else
+		pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+#endif
+		break;
+	}
+
+	return pattern_ptr;
+}
+
+/*
+ * Name:     ddr3_dqs_centralization_rx
+ * Desc:     Execute the DQS centralization RX phase.
+ * Args:     dram_info
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_rx(MV_DRAM_INFO *dram_info)
+{
+	u32 cs, ecc, reg;
+	int status;
+
+	DEBUG_DQS_S("DDR3 - DQS Centralization RX - Starting procedure\n");
+
+	/* Enable SW override */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	DEBUG_DQS_S("DDR3 - DQS Centralization RX - SW Override Enabled\n");
+
+	reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	/* Loop for each CS */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			DEBUG_DQS_FULL_C("DDR3 - DQS Centralization RX - CS - ",
+					 (u32) cs, 1);
+
+			for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+
+				/* ECC Support - Switch ECC Mux on ecc=1 */
+				reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+					~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg |= (dram_info->ecc_ena *
+					ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+				if (ecc)
+					DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Enabled\n");
+				else
+					DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Disabled\n");
+
+				DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Find all limits\n");
+
+				status = ddr3_find_adll_limits(dram_info, cs,
+							       ecc, 0);
+				if (MV_OK != status)
+					return status;
+
+				DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Start calculating center\n");
+
+				status = ddr3_center_calc(dram_info, cs, ecc,
+							  0);
+				if (MV_OK != status)
+					return status;
+			}
+		}
+	}
+
+	/* ECC Support - Disable ECC MUX */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+		~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+		(1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+	reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_dqs_centralization_tx
+ * Desc:     Execute the DQS centralization TX phase.
+ * Args:     dram_info
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_tx(MV_DRAM_INFO *dram_info)
+{
+	u32 cs, ecc, reg;
+	int status;
+
+	DEBUG_DQS_S("DDR3 - DQS Centralization TX - Starting procedure\n");
+
+	/* Enable SW override */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	DEBUG_DQS_S("DDR3 - DQS Centralization TX - SW Override Enabled\n");
+
+	reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	/* Loop for each CS */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			DEBUG_DQS_FULL_C("DDR3 - DQS Centralization TX - CS - ",
+					 (u32) cs, 1);
+			for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+				/* ECC Support - Switch ECC Mux on ecc=1 */
+				reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+					~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg |= (dram_info->ecc_ena *
+					ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+				if (ecc)
+					DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Enabled\n");
+				else
+					DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Disabled\n");
+
+				DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Find all limits\n");
+
+				status = ddr3_find_adll_limits(dram_info, cs,
+							       ecc, 1);
+				if (MV_OK != status)
+					return status;
+
+				DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Start calculating center\n");
+
+				status = ddr3_center_calc(dram_info, cs, ecc,
+							  1);
+				if (MV_OK != status)
+					return status;
+			}
+		}
+	}
+
+	/* ECC Support - Disable ECC MUX */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+		~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+		(1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+	reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_find_adll_limits
+ * Desc:     Execute the Find ADLL limits phase.
+ * Args:     dram_info
+ *           cs
+ *           ecc_ena
+ *           is_tx             Indicate whether Rx or Tx
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx)
+{
+	u32 victim_dq, pup, tmp;
+	u32 adll_addr;
+	u32 max_pup;		/* maximal pup index */
+	u32 pup_mask = 0;
+	u32 unlock_pup;		/* bit array of un locked pups */
+	u32 new_unlock_pup;	/* bit array of compare failed pups */
+	u32 curr_adll;
+	u32 adll_start_val;	/* adll start loop value - for rx or tx limit */
+	u32 high_limit;	/* holds found High Limit */
+	u32 low_limit;		/* holds found Low Limit */
+	int win_valid;
+	int update_win;
+	u32 sdram_offset;
+	u32 uj, cs_count, cs_tmp, ii;
+	u32 *pattern_ptr;
+	u32 dq;
+	u32 adll_end_val;	/* adll end of loop val - for rx or tx limit */
+	u8 analog_pbs[DQ_NUM][MAX_PUP_NUM][DQ_NUM][2];
+	u8 analog_pbs_sum[MAX_PUP_NUM][DQ_NUM][2];
+	int pup_adll_limit_state[MAX_PUP_NUM];	/* hold state of each pup */
+
+	adll_addr = ((is_tx == 1) ? PUP_DQS_WR : PUP_DQS_RD);
+	adll_end_val = ((is_tx == 1) ? ADLL_MIN : ADLL_MAX);
+	adll_start_val = ((is_tx == 1) ? ADLL_MAX : ADLL_MIN);
+	max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+	DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - Starting Find ADLL Limits\n");
+
+	/* init the array */
+	for (pup = 0; pup < max_pup; pup++) {
+		centralization_low_limit[pup] = ADLL_MIN;
+		centralization_high_limit[pup] = ADLL_MAX;
+	}
+
+	/* Killer Pattern */
+	cs_count = 0;
+	for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+		if (dram_info->cs_ena & (1 << cs_tmp))
+			cs_count++;
+	}
+	sdram_offset = cs_count * (SDRAM_CS_SIZE + 1);
+	sdram_offset += ((is_tx == 1) ?
+			 SDRAM_DQS_TX_OFFS : SDRAM_DQS_RX_OFFS);
+
+	/* Prepare pup masks */
+	for (pup = 0; pup < max_pup; pup++)
+		pup_mask |= (1 << pup);
+
+	for (pup = 0; pup < max_pup; pup++) {
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			analog_pbs_sum[pup][dq][0] = adll_start_val;
+			analog_pbs_sum[pup][dq][1] = adll_end_val;
+		}
+	}
+
+	/* Loop - use different pattern for each victim_dq */
+	for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+		DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Victim DQ - ",
+				 (u32)victim_dq, 1);
+		/*
+		 * The pups 3 bit arrays represent state machine. with
+		 * 3 stages for each pup.
+		 * 1. fail and didn't get pass in earlier compares.
+		 * 2. pass compare
+		 * 3. fail after pass - end state.
+		 * The window limits are the adll values where the adll
+		 * was in the pass stage.
+		 */
+
+		/* Set all states to Fail (1st state) */
+		for (pup = 0; pup < max_pup; pup++)
+			pup_adll_limit_state[pup] = PUP_ADLL_LIMITS_STATE_FAIL;
+
+		/* Set current valid pups */
+		unlock_pup = pup_mask;
+
+		/* Set ADLL to start value */
+		curr_adll = adll_start_val;
+
+#if defined(MV88F78X60)
+		for (pup = 0; pup < max_pup; pup++) {
+			for (dq = 0; dq < DQ_NUM; dq++) {
+				analog_pbs[victim_dq][pup][dq][0] =
+					adll_start_val;
+				analog_pbs[victim_dq][pup][dq][1] =
+					adll_end_val;
+				per_bit_data[pup][dq] = 0;
+			}
+		}
+#endif
+
+		for (uj = 0; uj < ADLL_MAX; uj++) {
+			DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Setting ADLL to ",
+					 curr_adll, 2);
+			for (pup = 0; pup < max_pup; pup++) {
+				if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+					tmp = ((is_tx == 1) ? curr_adll +
+					       dram_info->wl_val[cs]
+					       [pup * (1 - ecc) + ecc * ECC_PUP]
+					       [D] : curr_adll);
+					ddr3_write_pup_reg(adll_addr, cs, pup +
+						(ecc * ECC_PUP), 0, tmp);
+				}
+			}
+
+			/* Choose pattern */
+			pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+							      victim_dq);
+
+			/* '1' - means pup failed, '0' - means pup pass */
+			new_unlock_pup = 0;
+
+			/* Read and compare results for Victim_DQ# */
+			for (ii = 0; ii < 3; ii++) {
+				u32 tmp = 0;
+				if (MV_OK != ddr3_sdram_dqs_compare(dram_info,
+							   unlock_pup, &tmp,
+							   pattern_ptr,
+							   LEN_KILLER_PATTERN,
+							   sdram_offset +
+							   LEN_KILLER_PATTERN *
+							   4 * victim_dq,
+							   is_tx, 0, NULL,
+							   0))
+					return MV_DDR3_TRAINING_ERR_DRAM_COMPARE;
+
+				new_unlock_pup |= tmp;
+			}
+
+			pup = 0;
+			DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - UnlockPup: ",
+					 unlock_pup, 2);
+			DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - NewUnlockPup: ",
+					 new_unlock_pup, 2);
+
+			/* Update pup state */
+			for (pup = 0; pup < max_pup; pup++) {
+				if (IS_PUP_ACTIVE(unlock_pup, pup) == 0) {
+					DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Skipping pup ",
+							 pup, 1);
+					continue;
+				}
+
+				/*
+				 * Still didn't find the window limit of the pup
+				 */
+				if (IS_PUP_ACTIVE(new_unlock_pup, pup) == 1) {
+					/* Current compare result == fail */
+					if (pup_adll_limit_state[pup] ==
+					    PUP_ADLL_LIMITS_STATE_PASS) {
+						/*
+						 * If now it failed but passed
+						 * earlier
+						 */
+						DEBUG_DQS_S("DDR3 - DQS Find Limits - PASS to FAIL: CS - ");
+						DEBUG_DQS_D(cs, 1);
+						DEBUG_DQS_S(", DQ - ");
+						DEBUG_DQS_D(victim_dq, 1);
+						DEBUG_DQS_S(", Pup - ");
+						DEBUG_DQS_D(pup, 1);
+						DEBUG_DQS_S(", ADLL - ");
+						DEBUG_DQS_D(curr_adll, 2);
+						DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+						for (dq = 0; dq < DQ_NUM; dq++) {
+							if ((analog_pbs[victim_dq][pup][dq][0] != adll_start_val)
+							    && (analog_pbs[victim_dq][pup]
+								[dq][1] == adll_end_val))
+								analog_pbs
+									[victim_dq]
+									[pup][dq]
+									[1] =
+									curr_adll;
+						}
+#endif
+						win_valid = 1;
+						update_win = 0;
+
+						/* Keep min / max limit value */
+						if (is_tx == 0) {
+							/* RX - found upper limit */
+							if (centralization_high_limit[pup] >
+							    (curr_adll - 1)) {
+								high_limit =
+									curr_adll - 1;
+								low_limit =
+									centralization_low_limit[pup];
+								update_win = 1;
+							}
+						} else {
+							/* TX - found lower limit */
+							if (centralization_low_limit[pup] < (curr_adll + 1)) {
+								high_limit =
+									centralization_high_limit
+									[pup];
+								low_limit =
+									curr_adll + 1;
+								update_win =
+									1;
+							}
+						}
+
+						if (update_win == 1) {
+							/*
+							 * Before updating
+							 * window limits we need
+							 * to check that the
+							 * limits are valid
+							 */
+							if (MV_OK !=
+							    ddr3_check_window_limits
+							    (pup, high_limit,
+							     low_limit, is_tx,
+							     &win_valid))
+								return MV_DDR3_TRAINING_ERR_WIN_LIMITS;
+
+							if (win_valid == 1) {
+								/*
+								 * Window limits
+								 * should be
+								 * updated
+								 */
+								centralization_low_limit
+									[pup] =
+									low_limit;
+								centralization_high_limit
+									[pup] =
+									high_limit;
+							}
+						}
+
+						if (win_valid == 1) {
+							/* Found end of window - lock the pup */
+							pup_adll_limit_state[pup] =
+								PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS;
+							unlock_pup &= ~(1 << pup);
+						} else {
+							/* Probably false pass - reset status */
+							pup_adll_limit_state[pup] =
+								PUP_ADLL_LIMITS_STATE_FAIL;
+
+#if defined(MV88F78X60)
+							/* Clear logging array of win size (per Dq) */
+							for (dq = 0;
+							     dq < DQ_NUM;
+							     dq++) {
+								analog_pbs
+									[victim_dq]
+									[pup][dq]
+									[0] =
+									adll_start_val;
+								analog_pbs
+									[victim_dq]
+									[pup][dq]
+									[1] =
+									adll_end_val;
+								per_bit_data
+									[pup][dq]
+									= 0;
+							}
+#endif
+						}
+					}
+				} else {
+					/* Current compare result == pass */
+					if (pup_adll_limit_state[pup] ==
+					    PUP_ADLL_LIMITS_STATE_FAIL) {
+						/* If now it passed but failed earlier */
+						DEBUG_DQS_S("DDR3 - DQS Find Limits - FAIL to PASS: CS - ");
+						DEBUG_DQS_D(cs, 1);
+						DEBUG_DQS_S(", DQ - ");
+						DEBUG_DQS_D(victim_dq, 1);
+						DEBUG_DQS_S(", Pup - ");
+						DEBUG_DQS_D(pup, 1);
+						DEBUG_DQS_S(", ADLL - ");
+						DEBUG_DQS_D(curr_adll, 2);
+						DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+						for (dq = 0; dq < DQ_NUM;
+						     dq++) {
+							if (analog_pbs[victim_dq][pup][dq][0] == adll_start_val)
+								analog_pbs
+								    [victim_dq]
+								    [pup][dq]
+								    [0] =
+								    curr_adll;
+						}
+#endif
+						/* Found start of window */
+						pup_adll_limit_state[pup] =
+						    PUP_ADLL_LIMITS_STATE_PASS;
+
+						/* Keep min / max limit value */
+						if (is_tx == 0) {
+							/* RX - found low limit */
+							if (centralization_low_limit[pup] <= curr_adll)
+								centralization_low_limit
+								    [pup] =
+								    curr_adll;
+						} else {
+							/* TX - found high limit */
+							if (centralization_high_limit[pup] >= curr_adll)
+								centralization_high_limit
+								    [pup] =
+								    curr_adll;
+						}
+					}
+				}
+			}
+
+			if (unlock_pup == 0) {
+				/* Found limit to all pups */
+				DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - found PUP limit\n");
+				break;
+			}
+
+			/*
+			 * Increment / decrement (Move to right / left
+			 * one phase - ADLL) dqs RX / TX delay (for all un
+			 * lock pups
+			 */
+			if (is_tx == 0)
+				curr_adll++;
+			else
+				curr_adll--;
+		}
+
+		if (unlock_pup != 0) {
+			/*
+			 * Found pups that didn't reach to the end of the
+			 * state machine
+			 */
+			DEBUG_DQS_C("DDR3 - DQS Find Limits - Pups that didn't reached end of the state machine: ",
+				    unlock_pup, 1);
+
+			for (pup = 0; pup < max_pup; pup++) {
+				if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+					if (pup_adll_limit_state[pup] ==
+					    PUP_ADLL_LIMITS_STATE_FAIL) {
+						/* ERROR - found fail for all window size */
+						DEBUG_DQS_S("DDR3 - DQS Find Limits - Got FAIL for the complete range on pup - ");
+						DEBUG_DQS_D(pup, 1);
+						DEBUG_DQS_C(" victim DQ ",
+							    victim_dq, 1);
+
+						/* For debug - set min limit to illegal limit */
+						centralization_low_limit[pup]
+							= ADLL_ERROR;
+						/*
+						 * In case the pup is in mode
+						 * PASS - the limit is the min
+						 * / max adll, no need to
+						 * update because of the results
+						 * array default value
+						 */
+						return MV_DDR3_TRAINING_ERR_PUP_RANGE;
+					}
+				}
+			}
+		}
+	}
+
+	DEBUG_DQS_S("DDR3 - DQS Find Limits - DQ values per victim results:\n");
+	for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+		for (pup = 0; pup < max_pup; pup++) {
+			DEBUG_DQS_S("Victim DQ-");
+			DEBUG_DQS_D(victim_dq, 1);
+			DEBUG_DQS_S(", PUP-");
+			DEBUG_DQS_D(pup, 1);
+			for (dq = 0; dq < DQ_NUM; dq++) {
+				DEBUG_DQS_S(", DQ-");
+				DEBUG_DQS_D(dq, 1);
+				DEBUG_DQS_S(",S-");
+				DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+					    [0], 2);
+				DEBUG_DQS_S(",E-");
+				DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+					    [1], 2);
+
+				if (is_tx == 0) {
+					if (analog_pbs[victim_dq][pup][dq][0]
+					    > analog_pbs_sum[pup][dq][0])
+						analog_pbs_sum[pup][dq][0] =
+						    analog_pbs[victim_dq][pup]
+						    [dq][0];
+					if (analog_pbs[victim_dq][pup][dq][1]
+					    < analog_pbs_sum[pup][dq][1])
+						analog_pbs_sum[pup][dq][1] =
+						    analog_pbs[victim_dq][pup]
+						    [dq][1];
+				} else {
+					if (analog_pbs[victim_dq][pup][dq][0]
+					    < analog_pbs_sum[pup][dq][0])
+						analog_pbs_sum[pup][dq][0] =
+						    analog_pbs[victim_dq][pup]
+						    [dq][0];
+					if (analog_pbs[victim_dq][pup][dq][1]
+					    > analog_pbs_sum[pup][dq][1])
+						analog_pbs_sum[pup][dq][1] =
+						    analog_pbs[victim_dq][pup]
+						    [dq][1];
+				}
+			}
+			DEBUG_DQS_S("\n");
+		}
+	}
+
+	if (ddr3_get_log_level() >= MV_LOG_LEVEL_3) {
+		u32 dq;
+
+		DEBUG_PER_DQ_S("\n########## LOG LEVEL 3(Windows margins per-DQ) ##########\n");
+		if (is_tx) {
+			DEBUG_PER_DQ_C("DDR3 - TX  CS: ", cs, 1);
+		} else {
+			DEBUG_PER_DQ_C("DDR3 - RX  CS: ", cs, 1);
+		}
+
+		if (ecc == 0) {
+			DEBUG_PER_DQ_S("\n DATA RESULTS:\n");
+		} else {
+			DEBUG_PER_DQ_S("\n ECC RESULTS:\n");
+		}
+
+		/* Since all dq has the same value we take 0 as representive */
+		dq = 0;
+		for (pup = 0; pup < max_pup; pup++) {
+			if (ecc == 0) {
+				DEBUG_PER_DQ_S("\nBYTE:");
+				DEBUG_PER_DQ_D(pup, 1);
+				DEBUG_PER_DQ_S("\n");
+			} else {
+				DEBUG_PER_DQ_S("\nECC BYTE:\n");
+			}
+			DEBUG_PER_DQ_S("  DQ's        LOW       HIGH       WIN-SIZE\n");
+			DEBUG_PER_DQ_S("============================================\n");
+			for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+				if (ecc == 0) {
+					DEBUG_PER_DQ_S("DQ[");
+					DEBUG_PER_DQ_DD((victim_dq +
+							 DQ_NUM * pup), 2);
+					DEBUG_PER_DQ_S("]");
+				} else {
+					DEBUG_PER_DQ_S("CB[");
+					DEBUG_PER_DQ_DD(victim_dq, 2);
+					DEBUG_PER_DQ_S("]");
+				}
+				if (is_tx) {
+					DEBUG_PER_DQ_S("      0x");
+					DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1], 2);	/* low value */
+					DEBUG_PER_DQ_S("        0x");
+					DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2);	/* high value */
+					DEBUG_PER_DQ_S("        0x");
+					DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0] - analog_pbs[victim_dq][pup][dq][1], 2);	/* win-size */
+				} else {
+					DEBUG_PER_DQ_S("     0x");
+					DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2);	/* low value */
+					DEBUG_PER_DQ_S("       0x");
+					DEBUG_PER_DQ_D((analog_pbs[victim_dq][pup][dq][1] - 1), 2);	/* high value */
+					DEBUG_PER_DQ_S("       0x");
+					DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1] - analog_pbs[victim_dq][pup][dq][0], 2);	/* win-size */
+				}
+				DEBUG_PER_DQ_S("\n");
+			}
+		}
+		DEBUG_PER_DQ_S("\n");
+	}
+
+	if (is_tx) {
+		DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+	} else {
+		DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+	}
+
+	for (pup = 0; pup < max_pup; pup++) {
+		DEBUG_DQS_S("PUP-");
+		DEBUG_DQS_D(pup, 1);
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			DEBUG_DQS_S(", DQ-");
+			DEBUG_DQS_D(dq, 1);
+			DEBUG_DQS_S(",S-");
+			DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+			DEBUG_DQS_S(",E-");
+			DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+		}
+		DEBUG_DQS_S("\n");
+	}
+
+	if (is_tx) {
+		DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+	} else {
+		DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+	}
+
+	for (pup = 0; pup < max_pup; pup++) {
+		if (max_pup == 1) {
+			/* For ECC PUP */
+			DEBUG_DQS_S("DDR3 - DQS8");
+		} else {
+			DEBUG_DQS_S("DDR3 - DQS");
+			DEBUG_DQS_D(pup, 1);
+		}
+
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			DEBUG_DQS_S(", DQ-");
+			DEBUG_DQS_D(dq, 1);
+			DEBUG_DQS_S("::S-");
+			DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+			DEBUG_DQS_S(",E-");
+			DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+		}
+		DEBUG_DQS_S("\n");
+	}
+
+	DEBUG_DQS_S("DDR3 - DQS Find Limits - Ended\n");
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_check_window_limits
+ * Desc:     Check window High & Low limits.
+ * Args:     pup                pup index
+ *           high_limit           window high limit
+ *           low_limit            window low limit
+ *           is_tx                Indicate whether Rx or Tx
+ *           size_valid          Indicate whether window size is valid
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+			     int *size_valid)
+{
+	DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Starting\n");
+
+	if (low_limit > high_limit) {
+		DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+		DEBUG_DQS_D(pup, 1);
+		DEBUG_DQS_S(" Low Limit grater than High Limit\n");
+		*size_valid = 0;
+		return MV_OK;
+	}
+
+	/*
+	 * Check that window size is valid, if not it was probably false pass
+	 * before
+	 */
+	if ((high_limit - low_limit) < MIN_WIN_SIZE) {
+		/*
+		 * Since window size is too small probably there was false
+		 * pass
+		 */
+		*size_valid = 0;
+
+		DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+		DEBUG_DQS_D(pup, 1);
+		DEBUG_DQS_S(" Window size is smaller than MIN_WIN_SIZE\n");
+
+	} else if ((high_limit - low_limit) > ADLL_MAX) {
+		*size_valid = 0;
+
+		DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+		DEBUG_DQS_D(pup, 1);
+		DEBUG_DQS_S
+		    (" Window size is bigger than max ADLL taps (31)  Exiting.\n");
+
+		return MV_FAIL;
+
+	} else {
+		*size_valid = 1;
+
+		DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Pup ");
+		DEBUG_DQS_FULL_D(pup, 1);
+		DEBUG_DQS_FULL_C(" window size is ", (high_limit - low_limit),
+				 2);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_center_calc
+ * Desc:     Execute the calculate the center of windows phase.
+ * Args:     pDram Info
+ *           is_tx             Indicate whether Rx or Tx
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+			    int is_tx)
+{
+	/* bit array of pups that need specail search */
+	u32 special_pattern_i_pup = 0;
+	u32 special_pattern_ii_pup = 0;
+	u32 pup;
+	u32 max_pup;
+
+	max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+	for (pup = 0; pup < max_pup; pup++) {
+		if (is_tx == 0) {
+			/* Check special pattern I */
+			/*
+			 * Special pattern Low limit search - relevant only
+			 * for Rx, win size < threshold and low limit = 0
+			 */
+			if (((centralization_high_limit[pup] -
+			      centralization_low_limit[pup]) < VALID_WIN_THRS)
+			    && (centralization_low_limit[pup] == MIN_DELAY))
+				special_pattern_i_pup |= (1 << pup);
+
+			/* Check special pattern II */
+			/*
+			 * Special pattern High limit search - relevant only
+			 * for Rx, win size < threshold and high limit = 31
+			 */
+			if (((centralization_high_limit[pup] -
+			      centralization_low_limit[pup]) < VALID_WIN_THRS)
+			    && (centralization_high_limit[pup] == MAX_DELAY))
+				special_pattern_ii_pup |= (1 << pup);
+		}
+	}
+
+	/* Run special pattern Low limit search - for relevant pup */
+	if (special_pattern_i_pup != 0) {
+		DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern I for Low limit search\n");
+		if (MV_OK !=
+		    ddr3_special_pattern_i_search(dram_info, cs, ecc, is_tx,
+					      special_pattern_i_pup))
+			return MV_DDR3_TRAINING_ERR_DQS_LOW_LIMIT_SEARCH;
+	}
+
+	/* Run special pattern High limit search - for relevant pup */
+	if (special_pattern_ii_pup != 0) {
+		DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern II for High limit search\n");
+		if (MV_OK !=
+		    ddr3_special_pattern_ii_search(dram_info, cs, ecc, is_tx,
+						   special_pattern_ii_pup))
+			return MV_DDR3_TRAINING_ERR_DQS_HIGH_LIMIT_SEARCH;
+	}
+
+	/* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+	return ddr3_set_dqs_centralization_results(dram_info, cs, ecc, is_tx);
+}
+
+/*
+ * Name:     ddr3_special_pattern_i_search
+ * Desc:     Execute special pattern low limit search.
+ * Args:
+ *           special_pattern_pup  The pups that need the special search
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+				  int is_tx, u32 special_pattern_pup)
+{
+	u32 victim_dq;		/* loop index - victim DQ */
+	u32 adll_idx;
+	u32 pup;
+	u32 unlock_pup;		/* bit array of the unlock pups  */
+	u32 first_fail;	/* bit array - of pups that  get first fail */
+	u32 new_lockup_pup;	/* bit array of compare failed pups */
+	u32 pass_pup;		/* bit array of compare pass pup */
+	u32 sdram_offset;
+	u32 max_pup;
+	u32 comp_val;
+	u32 special_res[MAX_PUP_NUM];	/* hold tmp results */
+
+	DEBUG_DQS_S("DDR3 - DQS - Special Pattern I Search - Starting\n");
+
+	max_pup = ecc + (1 - ecc) * dram_info->num_of_std_pups;
+
+	/* Init the temporary results to max ADLL value */
+	for (pup = 0; pup < max_pup; pup++)
+		special_res[pup] = ADLL_MAX;
+
+	/* Run special pattern for all DQ - use the same pattern */
+	for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+		unlock_pup = special_pattern_pup;
+		first_fail = 0;
+
+		sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS +
+			LEN_KILLER_PATTERN * 4 * victim_dq;
+
+		for (pup = 0; pup < max_pup; pup++) {
+			/* Set adll value per PUP. adll = high limit per pup */
+			if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+				/* only for pups that need special search */
+				ddr3_write_pup_reg(PUP_DQS_RD, cs,
+						   pup + (ecc * ECC_PUP), 0,
+						   centralization_high_limit
+						   [pup]);
+			}
+		}
+
+		adll_idx = 0;
+		do {
+			/*
+			 * Perform read and compare simultaneously for all
+			 * un-locked MC use the special pattern mask
+			 */
+			new_lockup_pup = 0;
+
+			if (MV_OK !=
+			    ddr3_sdram_dqs_compare(dram_info, unlock_pup,
+						   &new_lockup_pup,
+						   special_pattern
+						   [victim_dq],
+						   LEN_SPECIAL_PATTERN,
+						   sdram_offset, 0,
+						   0, NULL, 1))
+				return MV_FAIL;
+
+			DEBUG_DQS_S("DDR3 - DQS - Special I - ADLL value is: ");
+			DEBUG_DQS_D(adll_idx, 2);
+			DEBUG_DQS_S(", UnlockPup: ");
+			DEBUG_DQS_D(unlock_pup, 2);
+			DEBUG_DQS_S(", NewLockPup: ");
+			DEBUG_DQS_D(new_lockup_pup, 2);
+			DEBUG_DQS_S("\n");
+
+			if (unlock_pup != new_lockup_pup)
+				DEBUG_DQS_S("DDR3 - DQS - Special I - Some Pup passed!\n");
+
+			/* Search for pups with passed compare & already fail */
+			pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+			first_fail |= new_lockup_pup;
+			unlock_pup &= ~pass_pup;
+
+			/* Get pass pups */
+			if (pass_pup != 0) {
+				for (pup = 0; pup < max_pup; pup++) {
+					if (IS_PUP_ACTIVE(pass_pup, pup) ==
+					    1) {
+						/* If pup passed and has first fail = 1 */
+						/* keep min value of ADLL max value - current adll */
+						/* (centralization_high_limit[pup] + adll_idx) = current adll !!! */
+						comp_val =
+						    (ADLL_MAX -
+						     (centralization_high_limit
+						      [pup] + adll_idx));
+
+						DEBUG_DQS_C
+						    ("DDR3 - DQS - Special I - Pup - ",
+						     pup, 1);
+						DEBUG_DQS_C
+						    (" comp_val = ",
+						     comp_val, 2);
+
+						if (comp_val <
+						    special_res[pup]) {
+							special_res[pup] =
+							    comp_val;
+							centralization_low_limit
+							    [pup] =
+							    (-1) *
+							    comp_val;
+
+							DEBUG_DQS_C
+							    ("DDR3 - DQS - Special I - Pup - ",
+							     pup, 1);
+							DEBUG_DQS_C
+							    (" Changed Low limit to ",
+							     centralization_low_limit
+							     [pup], 2);
+						}
+					}
+				}
+			}
+
+			/*
+			 * Did all PUP found missing window?
+			 * Check for each pup if adll (different for each pup)
+			 * reach maximum if reach max value - lock the pup
+			 * if not - increment (Move to right one phase - ADLL)
+			 * dqs RX delay
+			 */
+			adll_idx++;
+			for (pup = 0; pup < max_pup; pup++) {
+				if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+					/* Check only unlocked pups */
+					if ((centralization_high_limit[pup] +
+					     adll_idx) >= ADLL_MAX) {
+						/* reach maximum - lock the pup */
+						DEBUG_DQS_C("DDR3 - DQS - Special I - reach maximum - lock pup ",
+							    pup, 1);
+						unlock_pup &= ~(1 << pup);
+					} else {
+						/* Didn't reach maximum - increment ADLL */
+						ddr3_write_pup_reg(PUP_DQS_RD,
+								   cs,
+								   pup +
+								   (ecc *
+								    ECC_PUP), 0,
+								   (centralization_high_limit
+								    [pup] +
+								    adll_idx));
+					}
+				}
+			}
+		} while (unlock_pup != 0);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_special_pattern_ii_search
+ * Desc:     Execute special pattern high limit search.
+ * Args:
+ *           special_pattern_pup  The pups that need the special search
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+				   int is_tx, u32 special_pattern_pup)
+{
+	u32 victim_dq;		/* loop index - victim DQ */
+	u32 adll_idx;
+	u32 pup;
+	u32 unlock_pup;		/* bit array of the unlock pups  */
+	u32 first_fail;	/* bit array - of pups that  get first fail */
+	u32 new_lockup_pup;	/* bit array of compare failed pups */
+	u32 pass_pup;		/* bit array of compare pass pup */
+	u32 sdram_offset;
+	u32 max_pup;
+	u32 comp_val;
+	u32 special_res[MAX_PUP_NUM];	/* hold tmp results */
+
+	DEBUG_DQS_S("DDR3 - DQS - Special Pattern II Search - Starting\n");
+
+	max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+	/* init the tmporary results to max ADLL value */
+	for (pup = 0; pup < max_pup; pup++)
+		special_res[pup] = ADLL_MAX;
+
+	sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS;
+
+	/* run special pattern for all DQ - use the same pattern */
+	for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+		unlock_pup = special_pattern_pup;
+		first_fail = 0;
+
+		for (pup = 0; pup < max_pup; pup++) {
+			/* Set adll value per PUP. adll = 0 */
+			if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+				/* Only for pups that need special search */
+				ddr3_write_pup_reg(PUP_DQS_RD, cs,
+						   pup + (ecc * ECC_PUP), 0,
+						   ADLL_MIN);
+			}
+		}
+
+		adll_idx = 0;
+		do {
+			/*
+			 * Perform read and compare simultaneously for all
+			 * un-locked MC use the special pattern mask
+			 */
+			new_lockup_pup = 0;
+
+			if (MV_OK != ddr3_sdram_dqs_compare(
+				    dram_info, unlock_pup, &new_lockup_pup,
+				    special_pattern[victim_dq],
+				    LEN_SPECIAL_PATTERN,
+				    sdram_offset, 0, 0, NULL, 0))
+				return MV_FAIL;
+
+			DEBUG_DQS_S("DDR3 - DQS - Special II - ADLL value is ");
+			DEBUG_DQS_D(adll_idx, 2);
+			DEBUG_DQS_S("unlock_pup ");
+			DEBUG_DQS_D(unlock_pup, 1);
+			DEBUG_DQS_S("new_lockup_pup ");
+			DEBUG_DQS_D(new_lockup_pup, 1);
+			DEBUG_DQS_S("\n");
+
+			if (unlock_pup != new_lockup_pup) {
+				DEBUG_DQS_S("DDR3 - DQS - Special II - Some Pup passed!\n");
+			}
+
+			/* Search for pups with passed compare & already fail */
+			pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+			first_fail |= new_lockup_pup;
+			unlock_pup &= ~pass_pup;
+
+			/* Get pass pups */
+			if (pass_pup != 0) {
+				for (pup = 0; pup < max_pup; pup++) {
+					if (IS_PUP_ACTIVE(pass_pup, pup) ==
+					    1) {
+						/* If pup passed and has first fail = 1 */
+						/* keep min value of ADLL max value - current adll */
+						/* (adll_idx) = current adll !!! */
+						comp_val = adll_idx;
+
+						DEBUG_DQS_C("DDR3 - DQS - Special II - Pup - ",
+							    pup, 1);
+						DEBUG_DQS_C(" comp_val = ",
+							    comp_val, 1);
+
+						if (comp_val <
+						    special_res[pup]) {
+							special_res[pup] =
+							    comp_val;
+							centralization_high_limit
+							    [pup] =
+							    ADLL_MAX +
+							    comp_val;
+
+							DEBUG_DQS_C
+							    ("DDR3 - DQS - Special II - Pup - ",
+							     pup, 1);
+							DEBUG_DQS_C
+							    (" Changed High limit to ",
+							     centralization_high_limit
+							     [pup], 2);
+						}
+					}
+				}
+			}
+
+			/*
+			 * Did all PUP found missing window?
+			 * Check for each pup if adll (different for each pup)
+			 * reach maximum if reach max value - lock the pup
+			 * if not - increment (Move to right one phase - ADLL)
+			 * dqs RX delay
+			 */
+			adll_idx++;
+			for (pup = 0; pup < max_pup; pup++) {
+				if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+					/* Check only unlocked pups */
+					if ((adll_idx) >= ADLL_MAX) {
+						/* Reach maximum - lock the pup */
+						DEBUG_DQS_C("DDR3 - DQS - Special II - reach maximum - lock pup ",
+							    pup, 1);
+						unlock_pup &= ~(1 << pup);
+					} else {
+						/* Didn't reach maximum - increment ADLL */
+						ddr3_write_pup_reg(PUP_DQS_RD,
+								   cs,
+								   pup +
+								   (ecc *
+								    ECC_PUP), 0,
+								   (adll_idx));
+					}
+				}
+			}
+		} while (unlock_pup != 0);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_set_dqs_centralization_results
+ * Desc:     Set to HW the DQS centralization phase results.
+ * Args:
+ *           is_tx             Indicates whether to set Tx or RX results
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs,
+					u32 ecc, int is_tx)
+{
+	u32 pup, pup_num;
+	int addl_val;
+	u32 max_pup;
+
+	max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+	DEBUG_DQS_RESULTS_S("\n############ LOG LEVEL 2(Windows margins) ############\n");;
+
+	if (is_tx) {
+		DEBUG_DQS_RESULTS_C("DDR3 - DQS TX - Set Dqs Centralization Results - CS: ",
+				    cs, 1);
+	} else {
+		DEBUG_DQS_RESULTS_C("DDR3 - DQS RX - Set Dqs Centralization Results - CS: ",
+				    cs, 1);
+	}
+
+	/* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+	DEBUG_DQS_RESULTS_S("\nDQS    LOW     HIGH     WIN-SIZE      Set\n");
+	DEBUG_DQS_RESULTS_S("==============================================\n");
+	for (pup = 0; pup < max_pup; pup++) {
+		addl_val = (centralization_high_limit[pup] +
+			    centralization_low_limit[pup]) / 2;
+
+		pup_num = pup * (1 - ecc) + ecc * ECC_PUP;
+
+		DEBUG_DQS_RESULTS_D(pup_num, 1);
+		DEBUG_DQS_RESULTS_S("     0x");
+		DEBUG_DQS_RESULTS_D(centralization_low_limit[pup], 2);
+		DEBUG_DQS_RESULTS_S("      0x");
+		DEBUG_DQS_RESULTS_D(centralization_high_limit[pup], 2);
+		DEBUG_DQS_RESULTS_S("      0x");
+		DEBUG_DQS_RESULTS_D(centralization_high_limit[pup] -
+				    centralization_low_limit[pup], 2);
+		DEBUG_DQS_RESULTS_S("       0x");
+		DEBUG_DQS_RESULTS_D(addl_val, 2);
+		DEBUG_DQS_RESULTS_S("\n");
+
+		if (addl_val < ADLL_MIN) {
+			addl_val = ADLL_MIN;
+			DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MIN (since it was lower than 0)\n");
+		}
+
+		if (addl_val > ADLL_MAX) {
+			addl_val = ADLL_MAX;
+			DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MAX (since it was higher than 31)\n");
+		}
+
+		if (is_tx) {
+			ddr3_write_pup_reg(PUP_DQS_WR, cs, pup_num, 0,
+					   addl_val +
+					   dram_info->wl_val[cs][pup_num][D]);
+		} else {
+			ddr3_write_pup_reg(PUP_DQS_RD, cs, pup_num, 0,
+					   addl_val);
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info)
+{
+	u32 cs, cs_count, cs_tmp, victim_dq;
+	u32 sdram_addr;
+	u32 *pattern_ptr;
+
+	/* Loop for each CS */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			cs_count = 0;
+			for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+				if (dram_info->cs_ena & (1 << cs_tmp))
+					cs_count++;
+			}
+
+			/* Init killer pattern */
+			sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+				      SDRAM_DQS_RX_OFFS);
+			for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+				pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+								      victim_dq);
+				if (MV_OK != ddr3_sdram_dqs_compare(
+					    dram_info, (u32)NULL, NULL,
+					    pattern_ptr, LEN_KILLER_PATTERN,
+					    sdram_addr + LEN_KILLER_PATTERN *
+					    4 * victim_dq, 1, 0, NULL,
+					    0))
+					return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+			}
+
+			/* Init special-killer pattern */
+			sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+				      SDRAM_DQS_RX_SPECIAL_OFFS);
+			for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+				if (MV_OK != ddr3_sdram_dqs_compare(
+					    dram_info, (u32)NULL, NULL,
+					    special_pattern[victim_dq],
+					    LEN_KILLER_PATTERN, sdram_addr +
+					    LEN_KILLER_PATTERN * 4 * victim_dq,
+					    1, 0, NULL, 0))
+					return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+			}
+		}
+	}
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/mvebu/ddr3_hw_training.c b/drivers/ddr/mvebu/ddr3_hw_training.c
new file mode 100644
index 0000000..a8c5e6a
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_hw_training.c
@@ -0,0 +1,1115 @@
+/*
+ * 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 "ddr3_hw_training.h"
+#include "xor.h"
+
+#ifdef MV88F78X60
+#include "ddr3_patterns_64bit.h"
+#else
+#include "ddr3_patterns_16bit.h"
+#if defined(MV88F672X)
+#include "ddr3_patterns_16bit.h"
+#endif
+#endif
+
+/*
+ * Debug
+ */
+
+#define DEBUG_MAIN_C(s, d, l) \
+	DEBUG_MAIN_S(s); DEBUG_MAIN_D(d, l); DEBUG_MAIN_S("\n")
+#define DEBUG_MAIN_FULL_C(s, d, l) \
+	DEBUG_MAIN_FULL_S(s); DEBUG_MAIN_FULL_D(d, l); DEBUG_MAIN_FULL_S("\n")
+
+#ifdef MV_DEBUG_MAIN
+#define DEBUG_MAIN_S(s)			puts(s)
+#define DEBUG_MAIN_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_MAIN_S(s)
+#define DEBUG_MAIN_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_MAIN_FULL
+#define DEBUG_MAIN_FULL_S(s)		puts(s)
+#define DEBUG_MAIN_FULL_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_MAIN_FULL_S(s)
+#define DEBUG_MAIN_FULL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_SUSPEND_RESUME
+#define DEBUG_SUSPEND_RESUME_S(s)	puts(s)
+#define DEBUG_SUSPEND_RESUME_D(d, l)	printf("%x", d)
+#else
+#define DEBUG_SUSPEND_RESUME_S(s)
+#define DEBUG_SUSPEND_RESUME_D(d, l)
+#endif
+
+static u32 ddr3_sw_wl_rl_debug;
+static u32 ddr3_run_pbs = 1;
+
+void ddr3_print_version(void)
+{
+	puts("DDR3 Training Sequence - Ver 5.7.");
+}
+
+void ddr3_set_sw_wl_rl_debug(u32 val)
+{
+	ddr3_sw_wl_rl_debug = val;
+}
+
+void ddr3_set_pbs(u32 val)
+{
+	ddr3_run_pbs = val;
+}
+
+int ddr3_hw_training(u32 target_freq, u32 ddr_width, int xor_bypass,
+		     u32 scrub_offs, u32 scrub_size, int dqs_clk_aligned,
+		     int debug_mode, int reg_dimm_skip_wl)
+{
+	/* A370 has no PBS mechanism */
+	__maybe_unused u32 first_loop_flag = 0;
+	u32 freq, reg;
+	MV_DRAM_INFO dram_info;
+	int ratio_2to1 = 0;
+	int tmp_ratio = 1;
+	int status;
+
+	if (debug_mode)
+		DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 1\n");
+
+	memset(&dram_info, 0, sizeof(dram_info));
+	dram_info.num_cs = ddr3_get_cs_num_from_reg();
+	dram_info.cs_ena = ddr3_get_cs_ena_from_reg();
+	dram_info.target_frequency = target_freq;
+	dram_info.ddr_width = ddr_width;
+	dram_info.num_of_std_pups = ddr_width / PUP_SIZE;
+	dram_info.rl400_bug = 0;
+	dram_info.multi_cs_mr_support = 0;
+#ifdef MV88F67XX
+	dram_info.rl400_bug = 1;
+#endif
+
+	/* Ignore ECC errors - if ECC is enabled */
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+	if (reg & (1 << REG_SDRAM_CONFIG_ECC_OFFS)) {
+		dram_info.ecc_ena = 1;
+		reg |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
+		reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+	} else {
+		dram_info.ecc_ena = 0;
+	}
+
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+	if (reg & (1 << REG_SDRAM_CONFIG_REGDIMM_OFFS))
+		dram_info.reg_dimm = 1;
+	else
+		dram_info.reg_dimm = 0;
+
+	dram_info.num_of_total_pups = ddr_width / PUP_SIZE + dram_info.ecc_ena;
+
+	/* Get target 2T value */
+	reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+	dram_info.mode_2t = (reg >> REG_DUNIT_CTRL_LOW_2T_OFFS) &
+		REG_DUNIT_CTRL_LOW_2T_MASK;
+
+	/* Get target CL value */
+#ifdef MV88F67XX
+	reg = reg_read(REG_DDR3_MR0_ADDR) >> 2;
+#else
+	reg = reg_read(REG_DDR3_MR0_CS_ADDR) >> 2;
+#endif
+
+	reg = (((reg >> 1) & 0xE) | (reg & 0x1)) & 0xF;
+	dram_info.cl = ddr3_valid_cl_to_cl(reg);
+
+	/* Get target CWL value */
+#ifdef MV88F67XX
+	reg = reg_read(REG_DDR3_MR2_ADDR) >> REG_DDR3_MR2_CWL_OFFS;
+#else
+	reg = reg_read(REG_DDR3_MR2_CS_ADDR) >> REG_DDR3_MR2_CWL_OFFS;
+#endif
+
+	reg &= REG_DDR3_MR2_CWL_MASK;
+	dram_info.cwl = reg;
+#if !defined(MV88F67XX)
+	/* A370 has no PBS mechanism */
+#if defined(MV88F78X60)
+	if ((dram_info.target_frequency > DDR_400) && (ddr3_run_pbs))
+		first_loop_flag = 1;
+#else
+	/* first_loop_flag = 1; skip mid freq at ALP/A375 */
+	if ((dram_info.target_frequency > DDR_400) && (ddr3_run_pbs) &&
+	    (mv_ctrl_revision_get() >= UMC_A0))
+		first_loop_flag = 1;
+	else
+		first_loop_flag = 0;
+#endif
+#endif
+
+	freq = dram_info.target_frequency;
+
+	/* Set ODT to always on */
+	ddr3_odt_activate(1);
+
+	/* Init XOR */
+	mv_sys_xor_init(&dram_info);
+
+	/* Get DRAM/HCLK ratio */
+	if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+		ratio_2to1 = 1;
+
+	/*
+	 * Xor Bypass - ECC support in AXP is currently available for 1:1
+	 * modes frequency modes.
+	 * Not all frequency modes support the ddr3 training sequence
+	 * (Only 1200/300).
+	 * Xor Bypass allows using the Xor initializations and scrubbing
+	 * inside the ddr3 training sequence without running the training
+	 * itself.
+	 */
+	if (xor_bypass == 0) {
+		if (ddr3_run_pbs) {
+			DEBUG_MAIN_S("DDR3 Training Sequence - Run with PBS.\n");
+		} else {
+			DEBUG_MAIN_S("DDR3 Training Sequence - Run without PBS.\n");
+		}
+
+		if (dram_info.target_frequency > DFS_MARGIN) {
+			tmp_ratio = 0;
+			freq = DDR_100;
+
+			if (dram_info.reg_dimm == 1)
+				freq = DDR_300;
+
+			if (MV_OK != ddr3_dfs_high_2_low(freq, &dram_info)) {
+				/* Set low - 100Mhz DDR Frequency by HW */
+				DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs High2Low)\n");
+				return MV_DDR3_TRAINING_ERR_DFS_H2L;
+			}
+
+			if ((dram_info.reg_dimm == 1) &&
+			    (reg_dimm_skip_wl == 0)) {
+				if (MV_OK !=
+				    ddr3_write_leveling_hw_reg_dimm(freq,
+								    &dram_info))
+					DEBUG_MAIN_S("DDR3 Training Sequence - Registered DIMM Low WL - SKIP\n");
+			}
+
+			if (ddr3_get_log_level() >= MV_LOG_LEVEL_1)
+				ddr3_print_freq(freq);
+
+			if (debug_mode)
+				DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 2\n");
+		} else {
+			if (!dqs_clk_aligned) {
+#ifdef MV88F67XX
+				/*
+				 * If running training sequence without DFS,
+				 * we must run Write leveling before writing
+				 * the patterns
+				 */
+
+				/*
+				 * ODT - Multi CS system use SW WL,
+				 * Single CS System use HW WL
+				 */
+				if (dram_info.cs_ena > 1) {
+					if (MV_OK !=
+					    ddr3_write_leveling_sw(
+						    freq, tmp_ratio,
+						    &dram_info)) {
+						DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+						return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+					}
+				} else {
+					if (MV_OK !=
+					    ddr3_write_leveling_hw(freq,
+								   &dram_info)) {
+						DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+						return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+					}
+				}
+#else
+				if (MV_OK != ddr3_write_leveling_hw(
+					    freq, &dram_info)) {
+					DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+					if (ddr3_sw_wl_rl_debug) {
+						if (MV_OK !=
+						    ddr3_write_leveling_sw(
+							    freq, tmp_ratio,
+							    &dram_info)) {
+							DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+							return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+						}
+					} else {
+						return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+					}
+				}
+#endif
+			}
+
+			if (debug_mode)
+				DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 3\n");
+		}
+
+		if (MV_OK != ddr3_load_patterns(&dram_info, 0)) {
+			DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Loading Patterns)\n");
+			return MV_DDR3_TRAINING_ERR_LOAD_PATTERNS;
+		}
+
+		/*
+		 * TODO:
+		 * The mainline U-Boot port of the bin_hdr DDR training code
+		 * needs a delay of minimum 20ms here (10ms is a bit too short
+		 * and the CPU hangs). The bin_hdr code doesn't have this delay.
+		 * To be save here, lets add a delay of 50ms here.
+		 *
+		 * Tested on the Marvell DB-MV784MP-GP board
+		 */
+		mdelay(50);
+
+		do {
+			freq = dram_info.target_frequency;
+			tmp_ratio = ratio_2to1;
+			DEBUG_MAIN_FULL_S("DDR3 Training Sequence - DEBUG - 4\n");
+
+#if defined(MV88F78X60)
+			/*
+			 * There is a difference on the DFS frequency at the
+			 * first iteration of this loop
+			 */
+			if (first_loop_flag) {
+				freq = DDR_400;
+				tmp_ratio = 0;
+			}
+#endif
+
+			if (MV_OK != ddr3_dfs_low_2_high(freq, tmp_ratio,
+							 &dram_info)) {
+				DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs Low2High)\n");
+				return MV_DDR3_TRAINING_ERR_DFS_H2L;
+			}
+
+			if (ddr3_get_log_level() >= MV_LOG_LEVEL_1) {
+				ddr3_print_freq(freq);
+			}
+
+			if (debug_mode)
+				DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 5\n");
+
+			/* Write leveling */
+			if (!dqs_clk_aligned) {
+#ifdef MV88F67XX
+				/*
+				 * ODT - Multi CS system that not support Multi
+				 * CS MRS commands must use SW WL
+				 */
+				if (dram_info.cs_ena > 1) {
+					if (MV_OK != ddr3_write_leveling_sw(
+						    freq, tmp_ratio, &dram_info)) {
+						DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+						return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+					}
+				} else {
+					if (MV_OK != ddr3_write_leveling_hw(
+						    freq, &dram_info)) {
+						DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+						return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+					}
+				}
+#else
+				if ((dram_info.reg_dimm == 1) &&
+				    (freq == DDR_400)) {
+					if (reg_dimm_skip_wl == 0) {
+						if (MV_OK != ddr3_write_leveling_hw_reg_dimm(
+							    freq, &dram_info))
+							DEBUG_MAIN_S("DDR3 Training Sequence - Registered DIMM WL - SKIP\n");
+					}
+				} else {
+					if (MV_OK != ddr3_write_leveling_hw(
+						    freq, &dram_info)) {
+						DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+						if (ddr3_sw_wl_rl_debug) {
+							if (MV_OK != ddr3_write_leveling_sw(
+								    freq, tmp_ratio, &dram_info)) {
+								DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+								return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+							}
+						} else {
+							return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+						}
+					}
+				}
+#endif
+				if (debug_mode)
+					DEBUG_MAIN_S
+					    ("DDR3 Training Sequence - DEBUG - 6\n");
+			}
+
+			/* Read Leveling */
+			/*
+			 * Armada 370 - Support for HCLK @ 400MHZ - must use
+			 * SW read leveling
+			 */
+			if (freq == DDR_400 && dram_info.rl400_bug) {
+				status = ddr3_read_leveling_sw(freq, tmp_ratio,
+						       &dram_info);
+				if (MV_OK != status) {
+					DEBUG_MAIN_S
+					    ("DDR3 Training Sequence - FAILED (Read Leveling Sw)\n");
+					return status;
+				}
+			} else {
+				if (MV_OK != ddr3_read_leveling_hw(
+					    freq, &dram_info)) {
+					DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Hw)\n");
+					if (ddr3_sw_wl_rl_debug) {
+						if (MV_OK != ddr3_read_leveling_sw(
+							    freq, tmp_ratio,
+							    &dram_info)) {
+							DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Sw)\n");
+							return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+						}
+					} else {
+						return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+					}
+				}
+			}
+
+			if (debug_mode)
+				DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 7\n");
+
+			if (MV_OK != ddr3_wl_supplement(&dram_info)) {
+				DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hi-Freq Sup)\n");
+				return MV_DDR3_TRAINING_ERR_WR_LVL_HI_FREQ;
+			}
+
+			if (debug_mode)
+				DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 8\n");
+#if !defined(MV88F67XX)
+			/* A370 has no PBS mechanism */
+#if defined(MV88F78X60) || defined(MV88F672X)
+			if (first_loop_flag == 1) {
+				first_loop_flag = 0;
+
+				status = MV_OK;
+				status = ddr3_pbs_rx(&dram_info);
+				if (MV_OK != status) {
+					DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (PBS RX)\n");
+					return status;
+				}
+
+				if (debug_mode)
+					DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 9\n");
+
+				status = ddr3_pbs_tx(&dram_info);
+				if (MV_OK != status) {
+					DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (PBS TX)\n");
+					return status;
+				}
+
+				if (debug_mode)
+					DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 10\n");
+			}
+#endif
+#endif
+		} while (freq != dram_info.target_frequency);
+
+		status = ddr3_dqs_centralization_rx(&dram_info);
+		if (MV_OK != status) {
+			DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (DQS Centralization RX)\n");
+			return status;
+		}
+
+		if (debug_mode)
+			DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 11\n");
+
+		status = ddr3_dqs_centralization_tx(&dram_info);
+		if (MV_OK != status) {
+			DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (DQS Centralization TX)\n");
+			return status;
+		}
+
+		if (debug_mode)
+			DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 12\n");
+	}
+
+	ddr3_set_performance_params(&dram_info);
+
+	if (dram_info.ecc_ena) {
+		/* Need to SCRUB the DRAM memory area to load U-boot */
+		mv_sys_xor_finish();
+		dram_info.num_cs = 1;
+		dram_info.cs_ena = 1;
+		mv_sys_xor_init(&dram_info);
+		mv_xor_mem_init(0, scrub_offs, scrub_size, 0xdeadbeef,
+				0xdeadbeef);
+
+		/* Wait for previous transfer completion */
+		while (mv_xor_state_get(0) != MV_IDLE)
+			;
+
+		if (debug_mode)
+			DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 13\n");
+	}
+
+	/* Return XOR State */
+	mv_sys_xor_finish();
+
+#if defined(MV88F78X60)
+	/* Save training results in memeory for resume state */
+	ddr3_save_training(&dram_info);
+#endif
+	/* Clear ODT always on */
+	ddr3_odt_activate(0);
+
+	/* Configure Dynamic read ODT */
+	ddr3_odt_read_dynamic_config(&dram_info);
+
+	return MV_OK;
+}
+
+void ddr3_set_performance_params(MV_DRAM_INFO *dram_info)
+{
+	u32 twr2wr, trd2rd, trd2wr_wr2rd;
+	u32 tmp1, tmp2, reg;
+
+	DEBUG_MAIN_FULL_C("Max WL Phase: ", dram_info->wl_max_phase, 2);
+	DEBUG_MAIN_FULL_C("Min WL Phase: ", dram_info->wl_min_phase, 2);
+	DEBUG_MAIN_FULL_C("Max RL Phase: ", dram_info->rl_max_phase, 2);
+	DEBUG_MAIN_FULL_C("Min RL Phase: ", dram_info->rl_min_phase, 2);
+
+	if (dram_info->wl_max_phase < 2)
+		twr2wr = 0x2;
+	else
+		twr2wr = 0x3;
+
+	trd2rd = 0x1 + (dram_info->rl_max_phase + 1) / 2 +
+		(dram_info->rl_max_phase + 1) % 2;
+
+	tmp1 = (dram_info->rl_max_phase - dram_info->wl_min_phase) / 2 +
+		(((dram_info->rl_max_phase - dram_info->wl_min_phase) % 2) >
+		 0 ? 1 : 0);
+	tmp2 = (dram_info->wl_max_phase - dram_info->rl_min_phase) / 2 +
+		((dram_info->wl_max_phase - dram_info->rl_min_phase) % 2 >
+		 0 ? 1 : 0);
+	trd2wr_wr2rd = (tmp1 >= tmp2) ? tmp1 : tmp2;
+
+	trd2wr_wr2rd += 2;
+	trd2rd += 2;
+	twr2wr += 2;
+
+	DEBUG_MAIN_FULL_C("WR 2 WR: ", twr2wr, 2);
+	DEBUG_MAIN_FULL_C("RD 2 RD: ", trd2rd, 2);
+	DEBUG_MAIN_FULL_C("RD 2 WR / WR 2 RD: ", trd2wr_wr2rd, 2);
+
+	reg = reg_read(REG_SDRAM_TIMING_HIGH_ADDR);
+
+	reg &= ~(REG_SDRAM_TIMING_H_W2W_MASK << REG_SDRAM_TIMING_H_W2W_OFFS);
+	reg |= ((twr2wr & REG_SDRAM_TIMING_H_W2W_MASK) <<
+		REG_SDRAM_TIMING_H_W2W_OFFS);
+
+	reg &= ~(REG_SDRAM_TIMING_H_R2R_MASK << REG_SDRAM_TIMING_H_R2R_OFFS);
+	reg &= ~(REG_SDRAM_TIMING_H_R2R_H_MASK <<
+		 REG_SDRAM_TIMING_H_R2R_H_OFFS);
+	reg |= ((trd2rd & REG_SDRAM_TIMING_H_R2R_MASK) <<
+		REG_SDRAM_TIMING_H_R2R_OFFS);
+	reg |= (((trd2rd >> 2) & REG_SDRAM_TIMING_H_R2R_H_MASK) <<
+		REG_SDRAM_TIMING_H_R2R_H_OFFS);
+
+	reg &= ~(REG_SDRAM_TIMING_H_R2W_W2R_MASK <<
+		 REG_SDRAM_TIMING_H_R2W_W2R_OFFS);
+	reg &= ~(REG_SDRAM_TIMING_H_R2W_W2R_H_MASK <<
+		 REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS);
+	reg |= ((trd2wr_wr2rd & REG_SDRAM_TIMING_H_R2W_W2R_MASK) <<
+		REG_SDRAM_TIMING_H_R2W_W2R_OFFS);
+	reg |= (((trd2wr_wr2rd >> 2) & REG_SDRAM_TIMING_H_R2W_W2R_H_MASK) <<
+		REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS);
+
+	reg_write(REG_SDRAM_TIMING_HIGH_ADDR, reg);
+}
+
+/*
+ * Perform DDR3 PUP Indirect Write
+ */
+void ddr3_write_pup_reg(u32 mode, u32 cs, u32 pup, u32 phase, u32 delay)
+{
+	u32 reg = 0;
+
+	if (pup == PUP_BC)
+		reg |= (1 << REG_PHY_BC_OFFS);
+	else
+		reg |= (pup << REG_PHY_PUP_OFFS);
+
+	reg |= ((0x4 * cs + mode) << REG_PHY_CS_OFFS);
+	reg |= (phase << REG_PHY_PHASE_OFFS) | delay;
+
+	if (mode == PUP_WL_MODE)
+		reg |= ((INIT_WL_DELAY + delay) << REG_PHY_DQS_REF_DLY_OFFS);
+
+	reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg);	/* 0x16A0 */
+	reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+	reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg);	/* 0x16A0 */
+
+	do {
+		reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+			REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+	} while (reg);	/* Wait for '0' to mark the end of the transaction */
+
+	/* If read Leveling mode - need to write to register 3 separetly */
+	if (mode == PUP_RL_MODE) {
+		reg = 0;
+
+		if (pup == PUP_BC)
+			reg |= (1 << REG_PHY_BC_OFFS);
+		else
+			reg |= (pup << REG_PHY_PUP_OFFS);
+
+		reg |= ((0x4 * cs + mode + 1) << REG_PHY_CS_OFFS);
+		reg |= (INIT_RL_DELAY);
+
+		reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+		reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+		reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+		do {
+			reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+				REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+		} while (reg);
+	}
+}
+
+/*
+ * Perform DDR3 PUP Indirect Read
+ */
+u32 ddr3_read_pup_reg(u32 mode, u32 cs, u32 pup)
+{
+	u32 reg;
+
+	reg = (pup << REG_PHY_PUP_OFFS) |
+		((0x4 * cs + mode) << REG_PHY_CS_OFFS);
+	reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg);	/* 0x16A0 */
+
+	reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_RD;
+	reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg);	/* 0x16A0 */
+
+	do {
+		reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+			REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+	} while (reg);	/* Wait for '0' to mark the end of the transaction */
+
+	return reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR);	/* 0x16A0 */
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_patterns(MV_DRAM_INFO *dram_info, int resume)
+{
+	u32 reg;
+
+	/* Enable SW override - Required for the ECC Pup */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	if (resume == 0) {
+#if defined(MV88F78X60) || defined(MV88F672X)
+		ddr3_load_pbs_patterns(dram_info);
+#endif
+		ddr3_load_dqs_patterns(dram_info);
+	}
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+		(1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+	reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+	/* Set Base Addr */
+#if defined(MV88F67XX)
+	reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR, 0);
+#else
+	if (resume == 0)
+		reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR, 0);
+	else
+		reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR,
+			  RESUME_RL_PATTERNS_ADDR);
+#endif
+
+	/* Set Patterns */
+	if (resume == 0) {
+		reg = (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS) |
+			(1 << REG_DRAM_TRAINING_PATTERNS_OFFS);
+	} else {
+		reg = (0x1 << REG_DRAM_TRAINING_CS_OFFS) |
+			(1 << REG_DRAM_TRAINING_PATTERNS_OFFS);
+	}
+
+	reg |= (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+	udelay(100);
+
+	/* Check if Successful */
+	if (reg_read(REG_DRAM_TRAINING_ADDR) &
+	    (1 << REG_DRAM_TRAINING_ERROR_OFFS))
+		return MV_OK;
+	else
+		return MV_FAIL;
+}
+
+#if !defined(MV88F67XX)
+/*
+ * Name:     ddr3_save_training(MV_DRAM_INFO *dram_info)
+ * Desc:     saves the training results to memeory (RL,WL,PBS,Rx/Tx
+ *           Centeralization)
+ * Args:     MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns:  None.
+ */
+void ddr3_save_training(MV_DRAM_INFO *dram_info)
+{
+	u32 val, pup, tmp_cs, cs, i, dq;
+	u32 crc = 0;
+	u32 regs = 0;
+	u32 *sdram_offset = (u32 *)RESUME_TRAINING_VALUES_ADDR;
+	u32 mode_config[MAX_TRAINING_MODE];
+
+	mode_config[DQS_WR_MODE] = PUP_DQS_WR;
+	mode_config[WL_MODE_] = PUP_WL_MODE;
+	mode_config[RL_MODE_] = PUP_RL_MODE;
+	mode_config[DQS_RD_MODE] = PUP_DQS_RD;
+	mode_config[PBS_TX_DM_MODE] = PUP_PBS_TX_DM;
+	mode_config[PBS_TX_MODE] = PUP_PBS_TX;
+	mode_config[PBS_RX_MODE] = PUP_PBS_RX;
+
+	/* num of training modes */
+	for (i = 0; i < MAX_TRAINING_MODE; i++) {
+		tmp_cs = dram_info->cs_ena;
+		/* num of CS */
+		for (cs = 0; cs < MAX_CS; cs++) {
+			if (tmp_cs & (1 << cs)) {
+				/* num of PUPs */
+				for (pup = 0; pup < dram_info->num_of_total_pups;
+				     pup++) {
+					if (pup == dram_info->num_of_std_pups &&
+					    dram_info->ecc_ena)
+						pup = ECC_PUP;
+					if (i == PBS_TX_DM_MODE) {
+						/*
+						 * Change CS bitmask because
+						 * PBS works only with CS0
+						 */
+						tmp_cs = 0x1;
+						val = ddr3_read_pup_reg(
+							mode_config[i], CS0, pup);
+					} else if (i == PBS_TX_MODE ||
+						   i == PBS_RX_MODE) {
+						/*
+						 * Change CS bitmask because
+						 * PBS works only with CS0
+						 */
+						tmp_cs = 0x1;
+						for (dq = 0; dq <= DQ_NUM;
+						     dq++) {
+							val = ddr3_read_pup_reg(
+								mode_config[i] + dq,
+								CS0,
+								pup);
+							(*sdram_offset) = val;
+							crc += *sdram_offset;
+							sdram_offset++;
+							regs++;
+						}
+						continue;
+					} else {
+						val = ddr3_read_pup_reg(
+							mode_config[i], cs, pup);
+					}
+
+					*sdram_offset = val;
+					crc += *sdram_offset;
+					sdram_offset++;
+					regs++;
+				}
+			}
+		}
+	}
+
+	*sdram_offset = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+	crc += *sdram_offset;
+	sdram_offset++;
+	regs++;
+	*sdram_offset = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+	crc += *sdram_offset;
+	sdram_offset++;
+	regs++;
+	sdram_offset = (u32 *)NUM_OF_REGISTER_ADDR;
+	*sdram_offset = regs;
+	DEBUG_SUSPEND_RESUME_S("Training Results CheckSum write= ");
+	DEBUG_SUSPEND_RESUME_D(crc, 8);
+	DEBUG_SUSPEND_RESUME_S("\n");
+	sdram_offset = (u32 *)CHECKSUM_RESULT_ADDR;
+	*sdram_offset = crc;
+}
+
+/*
+ * Name:     ddr3_read_training_results()
+ * Desc:     Reads the training results from memeory (RL,WL,PBS,Rx/Tx
+ *           Centeralization)
+ *           and writes them to the relevant registers
+ * Args:     MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns:  None.
+ */
+int ddr3_read_training_results(void)
+{
+	u32 val, reg, idx, dqs_wr_idx = 0, crc = 0;
+	u32 *sdram_offset = (u32 *)RESUME_TRAINING_VALUES_ADDR;
+	u32 training_val[RESUME_TRAINING_VALUES_MAX] = { 0 };
+	u32 regs = *((u32 *)NUM_OF_REGISTER_ADDR);
+
+	/*
+	 * Read Training results & Dunit registers from memory and write
+	 * it to an array
+	 */
+	for (idx = 0; idx < regs; idx++) {
+		training_val[idx] = *sdram_offset;
+		crc += *sdram_offset;
+		sdram_offset++;
+	}
+
+	sdram_offset = (u32 *)CHECKSUM_RESULT_ADDR;
+
+	if ((*sdram_offset) == crc) {
+		DEBUG_SUSPEND_RESUME_S("Training Results CheckSum read PASS= ");
+		DEBUG_SUSPEND_RESUME_D(crc, 8);
+		DEBUG_SUSPEND_RESUME_S("\n");
+	} else {
+		DEBUG_MAIN_S("Wrong Training Results CheckSum\n");
+		return MV_FAIL;
+	}
+
+	/*
+	 * We iterate through all the registers except for the last 2 since
+	 * they are Dunit registers (and not PHY registers)
+	 */
+	for (idx = 0; idx < (regs - 2); idx++) {
+		val = training_val[idx];
+		reg = (val >> REG_PHY_CS_OFFS) & 0x3F; /*read the phy address */
+
+		/* Check if the values belongs to the DQS WR */
+		if (reg == PUP_WL_MODE) {
+			/* bit[5:0] in DQS_WR are delay */
+			val = (training_val[dqs_wr_idx++] & 0x3F);
+			/*
+			 * bit[15:10] are DQS_WR delay & bit[9:0] are
+			 * WL phase & delay
+			 */
+			val = (val << REG_PHY_DQS_REF_DLY_OFFS) |
+				(training_val[idx] & 0x3C003FF);
+			/* Add Request pending and write operation bits */
+			val |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+		} else if (reg == PUP_DQS_WR) {
+			/*
+			 * Do nothing since DQS_WR will be done in PUP_WL_MODE
+			 */
+			continue;
+		}
+
+		val |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+		reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, val);
+		do {
+			val = (reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR)) &
+				REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+		} while (val);	/* Wait for '0' to mark the end of the transaction */
+	}
+
+	/* write last 2 Dunit configurations */
+	val = training_val[idx];
+	reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, val);	/* reg 0x1538 */
+	val = training_val[idx + 1];
+	reg_write(REG_READ_DATA_READY_DELAYS_ADDR, val);	/* reg 0x153c */
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_check_if_resume_mode()
+ * Desc:     Reads the address (0x3000) of the Resume Magic word (0xDEADB002)
+ * Args:     MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns:  return (magic_word == SUSPEND_MAGIC_WORD)
+ */
+int ddr3_check_if_resume_mode(MV_DRAM_INFO *dram_info, u32 freq)
+{
+	u32 magic_word;
+	u32 *sdram_offset = (u32 *)BOOT_INFO_ADDR;
+
+	if (dram_info->reg_dimm != 1) {
+		/*
+		 * Perform write levleling in order initiate the phy with
+		 * low frequency
+		 */
+		if (MV_OK != ddr3_write_leveling_hw(freq, dram_info)) {
+			DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+			return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+		}
+	}
+
+	if (MV_OK != ddr3_load_patterns(dram_info, 1)) {
+		DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Loading Patterns)\n");
+		return MV_DDR3_TRAINING_ERR_LOAD_PATTERNS;
+	}
+
+	/* Enable CS0 only for RL */
+	dram_info->cs_ena = 0x1;
+
+	/* Perform Read levleling in order to get stable memory */
+	if (MV_OK != ddr3_read_leveling_hw(freq, dram_info)) {
+		DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Hw)\n");
+		return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+	}
+
+	/* Back to relevant CS */
+	dram_info->cs_ena = ddr3_get_cs_ena_from_reg();
+
+	magic_word = *sdram_offset;
+	return magic_word == SUSPEND_MAGIC_WORD;
+}
+
+/*
+ * Name:     ddr3_training_suspend_resume()
+ * Desc:     Execute the Resume state
+ * Args:     MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns:  return (magic_word == SUSPEND_MAGIC_WORD)
+ */
+int ddr3_training_suspend_resume(MV_DRAM_INFO *dram_info)
+{
+	u32 freq, reg;
+	int tmp_ratio;
+
+	/* Configure DDR */
+	if (MV_OK != ddr3_read_training_results())
+		return MV_FAIL;
+
+	/* Reset read FIFO */
+	reg = reg_read(REG_DRAM_TRAINING_ADDR);
+
+	/* Start Auto Read Leveling procedure */
+	reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+
+	/* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	udelay(2);
+
+	reg = reg_read(REG_DRAM_TRAINING_ADDR);
+	/* Clear Auto Read Leveling procedure */
+	reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	/* Return to target frequency */
+	freq = dram_info->target_frequency;
+	tmp_ratio = 1;
+	if (MV_OK != ddr3_dfs_low_2_high(freq, tmp_ratio, dram_info)) {
+		DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs Low2High)\n");
+		return MV_DDR3_TRAINING_ERR_DFS_H2L;
+	}
+
+	if (dram_info->ecc_ena) {
+		/* Scabbling the RL area pattern and the training area */
+		mv_sys_xor_finish();
+		dram_info->num_cs = 1;
+		dram_info->cs_ena = 1;
+		mv_sys_xor_init(dram_info);
+		mv_xor_mem_init(0, RESUME_RL_PATTERNS_ADDR,
+				RESUME_RL_PATTERNS_SIZE, 0xFFFFFFFF, 0xFFFFFFFF);
+
+		/* Wait for previous transfer completion */
+
+		while (mv_xor_state_get(0) != MV_IDLE)
+			;
+
+		/* Return XOR State */
+		mv_sys_xor_finish();
+	}
+
+	return MV_OK;
+}
+#endif
+
+void ddr3_print_freq(u32 freq)
+{
+	u32 tmp_freq;
+
+	switch (freq) {
+	case 0:
+		tmp_freq = 100;
+		break;
+	case 1:
+		tmp_freq = 300;
+		break;
+	case 2:
+		tmp_freq = 360;
+		break;
+	case 3:
+		tmp_freq = 400;
+		break;
+	case 4:
+		tmp_freq = 444;
+		break;
+	case 5:
+		tmp_freq = 500;
+		break;
+	case 6:
+		tmp_freq = 533;
+		break;
+	case 7:
+		tmp_freq = 600;
+		break;
+	case 8:
+		tmp_freq = 666;
+		break;
+	case 9:
+		tmp_freq = 720;
+		break;
+	case 10:
+		tmp_freq = 800;
+		break;
+	default:
+		tmp_freq = 100;
+	}
+
+	printf("Current frequency is: %dMHz\n", tmp_freq);
+}
+
+int ddr3_get_min_max_read_sample_delay(u32 cs_enable, u32 reg, u32 *min,
+				       u32 *max, u32 *cs_max)
+{
+	u32 cs, delay;
+
+	*min = 0xFFFFFFFF;
+	*max = 0x0;
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if ((cs_enable & (1 << cs)) == 0)
+			continue;
+
+		delay = ((reg >> (cs * 8)) & 0x1F);
+
+		if (delay < *min)
+			*min = delay;
+
+		if (delay > *max) {
+			*max = delay;
+			*cs_max = cs;
+		}
+	}
+
+	return MV_OK;
+}
+
+int ddr3_get_min_max_rl_phase(MV_DRAM_INFO *dram_info, u32 *min, u32 *max,
+			      u32 cs)
+{
+	u32 pup, reg, phase;
+
+	*min = 0xFFFFFFFF;
+	*max = 0x0;
+
+	for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+		reg = ddr3_read_pup_reg(PUP_RL_MODE, cs, pup);
+		phase = ((reg >> 8) & 0x7);
+
+		if (phase < *min)
+			*min = phase;
+
+		if (phase > *max)
+			*max = phase;
+	}
+
+	return MV_OK;
+}
+
+int ddr3_odt_activate(int activate)
+{
+	u32 reg, mask;
+
+	mask = (1 << REG_DUNIT_ODT_CTRL_OVRD_OFFS) |
+		(1 << REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS);
+	/* {0x0000149C}  -   DDR Dunit ODT Control Register */
+	reg = reg_read(REG_DUNIT_ODT_CTRL_ADDR);
+	if (activate)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	reg_write(REG_DUNIT_ODT_CTRL_ADDR, reg);
+
+	return MV_OK;
+}
+
+int ddr3_odt_read_dynamic_config(MV_DRAM_INFO *dram_info)
+{
+	u32 min_read_sample_delay, max_read_sample_delay, max_rl_phase;
+	u32 min, max, cs_max;
+	u32 cs_ena, reg;
+
+	reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+	cs_ena = ddr3_get_cs_ena_from_reg();
+
+	/* Get minimum and maximum of read sample delay of all CS */
+	ddr3_get_min_max_read_sample_delay(cs_ena, reg, &min_read_sample_delay,
+					   &max_read_sample_delay, &cs_max);
+
+	/*
+	 * Get minimum and maximum read leveling phase which belongs to the
+	 * maximal read sample delay
+	 */
+	ddr3_get_min_max_rl_phase(dram_info, &min, &max, cs_max);
+	max_rl_phase = max;
+
+	/* DDR ODT Timing (Low) Register calculation */
+	reg = reg_read(REG_ODT_TIME_LOW_ADDR);
+	reg &= ~(0x1FF << REG_ODT_ON_CTL_RD_OFFS);
+	reg |= (((min_read_sample_delay - 1) & 0xF) << REG_ODT_ON_CTL_RD_OFFS);
+	reg |= (((max_read_sample_delay + 4 + (((max_rl_phase + 1) / 2) + 1)) &
+		 0x1F) << REG_ODT_OFF_CTL_RD_OFFS);
+	reg_write(REG_ODT_TIME_LOW_ADDR, reg);
+
+	return MV_OK;
+}
diff --git a/drivers/ddr/mvebu/ddr3_hw_training.h b/drivers/ddr/mvebu/ddr3_hw_training.h
new file mode 100644
index 0000000..cffa7c4
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_hw_training.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __DDR3_TRAINING_H
+#define __DDR3_TRAINING_H
+
+#include "ddr3_init.h"
+
+#ifdef MV88F78X60
+#include "ddr3_axp.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375.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)
+
+/*
+ * 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
+
+/*
+ * General Consts
+ */
+
+#define SDRAM_READ_WRITE_LEN_IN_WORDS           16
+#define SDRAM_READ_WRITE_LEN_IN_DOUBLE_WORDS    8
+#define CACHE_LINE_SIZE                         0x20
+
+#define SDRAM_CS_BASE                           0x0
+
+#define SRAM_BASE                               0x40000000
+#define SRAM_SIZE                               0xFFF
+
+#define LEN_64BIT_STD_PATTERN                   16
+#define LEN_64BIT_KILLER_PATTERN                128
+#define LEN_64BIT_SPECIAL_PATTERN               128
+#define LEN_64BIT_PBS_PATTERN                   16
+#define LEN_WL_SUP_PATTERN		                32
+
+#define LEN_16BIT_STD_PATTERN                   4
+#define LEN_16BIT_KILLER_PATTERN                128
+#define LEN_16BIT_SPECIAL_PATTERN               128
+#define LEN_16BIT_PBS_PATTERN                   4
+
+#define CMP_BYTE_SHIFT                          8
+#define CMP_BYTE_MASK                           0xFF
+#define PUP_SIZE                                8
+
+#define S 0
+#define C 1
+#define P 2
+#define D 3
+#define DQS 6
+#define PS 2
+#define DS 3
+#define PE 4
+#define DE 5
+
+#define CS0                                     0
+#define MAX_DIMM_NUM                            2
+#define MAX_DELAY                               0x1F
+
+/*
+ * Invertion limit and phase1 limit are WA for the RL @ 1:1 design bug -
+ * Armada 370 & AXP Z1
+ */
+#define MAX_DELAY_INV_LIMIT                     0x5
+#define MIN_DELAY_PHASE_1_LIMIT                 0x10
+
+#define MAX_DELAY_INV                           (0x3F - MAX_DELAY_INV_LIMIT)
+#define MIN_DELAY                               0
+#define MAX_PUP_NUM                             9
+#define ECC_PUP                                 8
+#define DQ_NUM                                  8
+#define DQS_DQ_NUM                              8
+#define INIT_WL_DELAY                           13
+#define INIT_RL_DELAY                           15
+#define TWLMRD_DELAY                            20
+#define TCLK_3_DELAY                            3
+#define ECC_BIT                                 8
+#define DMA_SIZE                                64
+#define MV_DMA_0                                0
+#define MAX_TRAINING_RETRY                      10
+
+#define PUP_RL_MODE                             0x2
+#define PUP_WL_MODE                             0
+#define PUP_PBS_TX                              0x10
+#define PUP_PBS_TX_DM                           0x1A
+#define PUP_PBS_RX                              0x30
+#define PUP_DQS_WR                              0x1
+#define PUP_DQS_RD                              0x3
+#define PUP_BC                                  10
+#define PUP_DELAY_MASK                          0x1F
+#define PUP_PHASE_MASK                          0x7
+#define PUP_NUM_64BIT                           8
+#define PUP_NUM_32BIT                           4
+#define PUP_NUM_16BIT                           2
+
+/* control PHY registers */
+#define CNTRL_PUP_DESKEW                        0x10
+
+/* WL */
+#define COUNT_WL_HI_FREQ                        2
+#define COUNT_WL                                2
+#define COUNT_WL_RFRS                           9
+#define WL_HI_FREQ_SHIFT                        2
+#define WL_HI_FREQ_STATE                        1
+#define COUNT_HW_WL                             2
+
+/* RL */
+/*
+ * RL_MODE - this define uses the RL mode SW RL instead of the functional
+ * window SW RL
+ */
+#define RL_MODE
+#define RL_WINDOW_WA
+#define MAX_PHASE_1TO1                          2
+#define MAX_PHASE_2TO1                          4
+
+#define MAX_PHASE_RL_UL_1TO1                    0
+#define MAX_PHASE_RL_L_1TO1                     4
+#define MAX_PHASE_RL_UL_2TO1                    3
+#define MAX_PHASE_RL_L_2TO1                     7
+
+#define RL_UNLOCK_STATE                         0
+#define RL_WINDOW_STATE                         1
+#define RL_FINAL_STATE                          2
+#define RL_RETRY_COUNT                          2
+#define COUNT_HW_RL                             2
+
+/* PBS */
+#define MAX_PBS                                 31
+#define MIN_PBS                                 0
+#define COUNT_PBS_PATTERN                       2
+#define COUNT_PBS_STARTOVER                     2
+#define COUNT_PBS_REPEAT                        3
+#define COUNT_PBS_COMP_RETRY_NUM                2
+#define PBS_DIFF_LIMIT                          31
+#define PATTERN_PBS_TX_A                        0x55555555
+#define PATTERN_PBS_TX_B                        0xAAAAAAAA
+
+/* DQS */
+#define ADLL_ERROR                              0x55
+#define ADLL_MAX                                31
+#define ADLL_MIN                                0
+#define MIN_WIN_SIZE                            4
+#define VALID_WIN_THRS                          MIN_WIN_SIZE
+
+#define MODE_2TO1                               1
+#define MODE_1TO1                               0
+
+/*
+ * Macros
+ */
+#define IS_PUP_ACTIVE(_data_, _pup_)        (((_data_) >> (_pup_)) & 0x1)
+
+/*
+ * Internal ERROR codes
+ */
+#define MV_DDR3_TRAINING_ERR_WR_LVL_HW              0xDD302001
+#define MV_DDR3_TRAINING_ERR_LOAD_PATTERNS          0xDD302002
+#define MV_DDR3_TRAINING_ERR_WR_LVL_HI_FREQ         0xDD302003
+#define MV_DDR3_TRAINING_ERR_DFS_H2L                0xDD302004
+#define MV_DDR3_TRAINING_ERR_DRAM_COMPARE           0xDD302005
+#define MV_DDR3_TRAINING_ERR_WIN_LIMITS             0xDD302006
+#define MV_DDR3_TRAINING_ERR_PUP_RANGE              0xDD302025
+#define MV_DDR3_TRAINING_ERR_DQS_LOW_LIMIT_SEARCH   0xDD302007
+#define MV_DDR3_TRAINING_ERR_DQS_HIGH_LIMIT_SEARCH  0xDD302008
+#define MV_DDR3_TRAINING_ERR_DQS_PATTERN            0xDD302009
+#define MV_DDR3_TRAINING_ERR_PBS_ADLL_SHR_1PHASE    0xDD302010
+#define MV_DDR3_TRAINING_ERR_PBS_TX_MAX_VAL         0xDD302011
+#define MV_DDR3_TRAINING_ERR_PBS_RX_PER_BIT         0xDD302012
+#define MV_DDR3_TRAINING_ERR_PBS_TX_PER_BIT         0xDD302013
+#define MV_DDR3_TRAINING_ERR_PBS_RX_MAX_VAL         0xDD302014
+#define MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP 0xDD302015
+#define MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_MAX_VAL  0xDD302016
+#define MV_DDR3_TRAINING_ERR_RD_LVL_RL_PATTERN      0xDD302017
+#define MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK   0xDD302018
+#define MV_DDR3_TRAINING_ERR_RD_LVL_PUP_UNLOCK      0xDD302019
+#define MV_DDR3_TRAINING_ERR_WR_LVL_SW              0xDD302020
+#define MV_DDR3_TRAINING_ERR_PRBS_RX                0xDD302021
+#define MV_DDR3_TRAINING_ERR_DQS_RX                 0xDD302022
+#define MV_DDR3_TRAINING_ERR_PRBS_TX                0xDD302023
+#define MV_DDR3_TRAINING_ERR_DQS_TX                 0xDD302024
+
+/*
+ * DRAM information structure
+ */
+typedef struct dram_info {
+	u32 num_cs;
+	u32 cs_ena;
+	u32 num_of_std_pups;	/* Q value = ddrWidth/8 - Without ECC!! */
+	u32 num_of_total_pups;	/* numOfStdPups + eccEna */
+	u32 target_frequency;	/* DDR Frequency */
+	u32 ddr_width;		/* 32/64 Bit or 16/32 Bit */
+	u32 ecc_ena;		/* 0/1 */
+	u32 wl_val[MAX_CS][MAX_PUP_NUM][7];
+	u32 rl_val[MAX_CS][MAX_PUP_NUM][7];
+	u32 rl_max_phase;
+	u32 rl_min_phase;
+	u32 wl_max_phase;
+	u32 wl_min_phase;
+	u32 rd_smpl_dly;
+	u32 rd_rdy_dly;
+	u32 cl;
+	u32 cwl;
+	u32 mode_2t;
+	int rl400_bug;
+	int multi_cs_mr_support;
+	int reg_dimm;
+} MV_DRAM_INFO;
+
+enum training_modes  {
+	DQS_WR_MODE,
+	WL_MODE_,
+	RL_MODE_,
+	DQS_RD_MODE,
+	PBS_TX_DM_MODE,
+	PBS_TX_MODE,
+	PBS_RX_MODE,
+	MAX_TRAINING_MODE,
+};
+
+typedef struct dram_training_init {
+	u32 reg_addr;
+	u32 reg_value;
+} MV_DRAM_TRAINING_INIT;
+
+typedef struct dram_mv_init {
+	u32 reg_addr;
+	u32 reg_value;
+} MV_DRAM_MC_INIT;
+
+/* Board/Soc revisions define */
+enum board_rev {
+	Z1,
+	Z1_PCAC,
+	Z1_RD_SLED,
+	A0,
+	A0_AMC
+};
+
+typedef struct dram_modes {
+	char *mode_name;
+	u8 cpu_freq;
+	u8 fab_freq;
+	u8 chip_id;
+	int chip_board_rev;
+	MV_DRAM_MC_INIT *regs;
+	MV_DRAM_TRAINING_INIT *vals;
+} MV_DRAM_MODES;
+
+/*
+ * Function Declarations
+ */
+
+u32 cache_inv(u32 addr);
+void flush_l1_v7(u32 line);
+void flush_l1_v6(u32 line);
+
+u32 ddr3_cl_to_valid_cl(u32 cl);
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl);
+
+void ddr3_write_pup_reg(u32 mode, u32 cs, u32 pup, u32 phase, u32 delay);
+u32 ddr3_read_pup_reg(u32 mode, u32 cs, u32 pup);
+
+int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked, int is_tx,
+			   u32 pbs_pattern_idx, u32 pbs_curr_val,
+			   u32 pbs_lock_val, u32 *skew_array,
+			   u8 *unlock_pup_dq_array, u32 ecc);
+
+int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+			   u32 *new_locked_pup, u32 *pattern,
+			   u32 pattern_len, u32 sdram_offset, int write,
+			   int mask, u32 *mask_pattern, int b_special_compare);
+
+int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+		       u32 *new_locked_pup, u32 *pattern, u32 pattern_len,
+		       u32 sdram_offset, int write, int mask,
+		       u32 *mask_pattern, int b_special_compare);
+
+int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+			      u32 *new_locked_pup, u32 *pattern,
+			      u32 pattern_len, u32 sdram_offset, int write,
+			      int mask, u32 *mask_pattern);
+
+int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+			  u32 *new_locked_pup, u32 *pattern,
+			  u32 sdram_offset);
+int ddr3_dram_sram_read(u32 src, u32 dst, u32 len);
+int ddr3_load_patterns(MV_DRAM_INFO *dram_info, int resume);
+
+int ddr3_read_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_read_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+
+int ddr3_write_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_write_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+int ddr3_write_leveling_hw_reg_dimm(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_wl_supplement(MV_DRAM_INFO *dram_info);
+
+int ddr3_dfs_high_2_low(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_dfs_low_2_high(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+
+int ddr3_pbs_tx(MV_DRAM_INFO *dram_info);
+int ddr3_pbs_rx(MV_DRAM_INFO *dram_info);
+int ddr3_load_pbs_patterns(MV_DRAM_INFO *dram_info);
+
+int ddr3_dqs_centralization_rx(MV_DRAM_INFO *dram_info);
+int ddr3_dqs_centralization_tx(MV_DRAM_INFO *dram_info);
+int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info);
+
+void ddr3_static_training_init(void);
+
+u8 ddr3_get_eprom_fabric(void);
+void ddr3_set_performance_params(MV_DRAM_INFO *dram_info);
+int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len);
+void ddr3_save_training(MV_DRAM_INFO *dram_info);
+int ddr3_read_training_results(void);
+int ddr3_training_suspend_resume(MV_DRAM_INFO *dram_info);
+int ddr3_get_min_max_read_sample_delay(u32 cs_enable, u32 reg, u32 *min,
+				       u32 *max, u32 *cs_max);
+int ddr3_get_min_max_rl_phase(MV_DRAM_INFO *dram_info, u32 *min, u32 *max,
+			      u32 cs);
+int ddr3_odt_activate(int activate);
+int ddr3_odt_read_dynamic_config(MV_DRAM_INFO *dram_info);
+void ddr3_print_freq(u32 freq);
+void ddr3_reset_phy_read_fifo(void);
+
+#endif /* __DDR3_TRAINING_H */
diff --git a/drivers/ddr/mvebu/ddr3_init.c b/drivers/ddr/mvebu/ddr3_init.c
new file mode 100644
index 0000000..11b8591
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_init.c
@@ -0,0 +1,1219 @@
+/*
+ * 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"
+
+#if defined(MV88F78X60)
+#include "ddr3_axp_vars.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370_vars.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375_vars.h"
+#endif
+
+#ifdef STATIC_TRAINING
+static void ddr3_static_training_init(void);
+#endif
+#ifdef DUNIT_STATIC
+static void ddr3_static_mc_init(void);
+#endif
+#if defined(DUNIT_STATIC) || defined(STATIC_TRAINING)
+MV_DRAM_MODES *ddr3_get_static_ddr_mode(void);
+#endif
+#if defined(MV88F672X)
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+#endif
+u32 mv_board_id_get(void);
+extern void ddr3_set_sw_wl_rl_debug(u32);
+extern void ddr3_set_pbs(u32);
+extern void ddr3_set_log_level(u32 val);
+
+static u32 log_level = DDR3_LOG_LEVEL;
+
+static u32 ddr3_init_main(void);
+
+/*
+ * Name:     ddr3_set_log_level
+ * Desc:     This routine initialize the log_level acording to nLogLevel
+ *           which getting from user
+ * Args:     nLogLevel
+ * Notes:
+ * Returns:  None.
+ */
+void ddr3_set_log_level(u32 val)
+{
+	log_level = val;
+}
+
+/*
+ * Name:     ddr3_get_log_level
+ * Desc:     This routine returns the log level
+ * Args:     none
+ * Notes:
+ * Returns:  log level.
+ */
+u32 ddr3_get_log_level(void)
+{
+	return log_level;
+}
+
+static void debug_print_reg(u32 reg)
+{
+	printf("0x%08x = 0x%08x\n", reg, reg_read(reg));
+}
+
+static void print_dunit_setup(void)
+{
+	puts("\n########### LOG LEVEL 1 (D-UNIT SETUP)###########\n");
+
+#ifdef DUNIT_STATIC
+	puts("\nStatic D-UNIT Setup:\n");
+#endif
+#ifdef DUNIT_SPD
+	puts("\nDynamic(using SPD) D-UNIT Setup:\n");
+#endif
+	debug_print_reg(REG_SDRAM_CONFIG_ADDR);
+	debug_print_reg(REG_DUNIT_CTRL_LOW_ADDR);
+	debug_print_reg(REG_SDRAM_TIMING_LOW_ADDR);
+	debug_print_reg(REG_SDRAM_TIMING_HIGH_ADDR);
+	debug_print_reg(REG_SDRAM_ADDRESS_CTRL_ADDR);
+	debug_print_reg(REG_SDRAM_OPEN_PAGES_ADDR);
+	debug_print_reg(REG_SDRAM_OPERATION_ADDR);
+	debug_print_reg(REG_SDRAM_MODE_ADDR);
+	debug_print_reg(REG_SDRAM_EXT_MODE_ADDR);
+	debug_print_reg(REG_DDR_CONT_HIGH_ADDR);
+	debug_print_reg(REG_ODT_TIME_LOW_ADDR);
+	debug_print_reg(REG_SDRAM_ERROR_ADDR);
+	debug_print_reg(REG_SDRAM_AUTO_PWR_SAVE_ADDR);
+	debug_print_reg(REG_OUDDR3_TIMING_ADDR);
+	debug_print_reg(REG_ODT_TIME_HIGH_ADDR);
+	debug_print_reg(REG_SDRAM_ODT_CTRL_LOW_ADDR);
+	debug_print_reg(REG_SDRAM_ODT_CTRL_HIGH_ADDR);
+	debug_print_reg(REG_DUNIT_ODT_CTRL_ADDR);
+#ifndef MV88F67XX
+	debug_print_reg(REG_DRAM_FIFO_CTRL_ADDR);
+	debug_print_reg(REG_DRAM_AXI_CTRL_ADDR);
+	debug_print_reg(REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR);
+	debug_print_reg(REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR);
+	debug_print_reg(REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR);
+	debug_print_reg(REG_DRAM_MAIN_PADS_CAL_ADDR);
+	debug_print_reg(REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR);
+	debug_print_reg(REG_CS_SIZE_SCRATCH_ADDR);
+	debug_print_reg(REG_DYNAMIC_POWER_SAVE_ADDR);
+	debug_print_reg(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+	debug_print_reg(REG_READ_DATA_READY_DELAYS_ADDR);
+	debug_print_reg(REG_DDR3_MR0_ADDR);
+	debug_print_reg(REG_DDR3_MR1_ADDR);
+	debug_print_reg(REG_DDR3_MR2_ADDR);
+	debug_print_reg(REG_DDR3_MR3_ADDR);
+	debug_print_reg(REG_DDR3_RANK_CTRL_ADDR);
+	debug_print_reg(REG_DRAM_PHY_CONFIG_ADDR);
+	debug_print_reg(REG_STATIC_DRAM_DLB_CONTROL);
+	debug_print_reg(DLB_BUS_OPTIMIZATION_WEIGHTS_REG);
+	debug_print_reg(DLB_AGING_REGISTER);
+	debug_print_reg(DLB_EVICTION_CONTROL_REG);
+	debug_print_reg(DLB_EVICTION_TIMERS_REGISTER_REG);
+#if defined(MV88F672X)
+	debug_print_reg(REG_FASTPATH_WIN_CTRL_ADDR(0));
+	debug_print_reg(REG_FASTPATH_WIN_BASE_ADDR(0));
+	debug_print_reg(REG_FASTPATH_WIN_CTRL_ADDR(1));
+	debug_print_reg(REG_FASTPATH_WIN_BASE_ADDR(1));
+#else
+	debug_print_reg(REG_FASTPATH_WIN_0_CTRL_ADDR);
+#endif
+	debug_print_reg(REG_CDI_CONFIG_ADDR);
+#endif
+}
+
+#if !defined(STATIC_TRAINING)
+static void ddr3_restore_and_set_final_windows(u32 *win_backup)
+{
+	u32 ui, reg, cs;
+	u32 win_ctrl_reg, num_of_win_regs;
+	u32 cs_ena = ddr3_get_cs_ena_from_reg();
+
+#if defined(MV88F672X)
+	if (DDR3_FAST_PATH_EN == 0)
+		return;
+#endif
+
+#if defined(MV88F672X)
+	win_ctrl_reg = REG_XBAR_WIN_16_CTRL_ADDR;
+	num_of_win_regs = 8;
+#else
+	win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+	num_of_win_regs = 16;
+#endif
+
+	/* 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_backup[ui]);
+
+	DEBUG_INIT_FULL_S("DDR3 Training Sequence - Switching XBAR Window to FastPath Window\n");
+
+#if defined(MV88F672X)
+	/* Set L2 filtering to 1G */
+	reg_write(0x8c04, 0x40000000);
+
+	/* Open fast path windows */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			/* set fast path window control for the cs */
+			reg = 0x1FFFFFE1;
+			reg |= (cs << 2);
+			reg |= (SDRAM_CS_SIZE & 0xFFFF0000);
+			/* Open fast path Window */
+			reg_write(REG_FASTPATH_WIN_CTRL_ADDR(cs), reg);
+			/* set fast path window base address for the cs */
+			reg = (((SDRAM_CS_SIZE + 1) * cs) & 0xFFFF0000);
+			/* Set base address */
+			reg_write(REG_FASTPATH_WIN_BASE_ADDR(cs), reg);
+		}
+	}
+#else
+	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 void ddr3_save_and_set_training_windows(u32 *win_backup)
+{
+	u32 cs_ena = ddr3_get_cs_ena_from_reg();
+	u32 reg, tmp_count, cs, ui;
+	u32 win_ctrl_reg, win_base_reg, win_remap_reg;
+	u32 num_of_win_regs, win_jump_index;
+
+#if defined(MV88F672X)
+	/* Disable L2 filtering */
+	reg_write(0x8c04, 0);
+
+	win_ctrl_reg = REG_XBAR_WIN_16_CTRL_ADDR;
+	win_base_reg = REG_XBAR_WIN_16_BASE_ADDR;
+	win_remap_reg = REG_XBAR_WIN_16_REMAP_ADDR;
+	win_jump_index = 0x8;
+	num_of_win_regs = 8;
+#else
+	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;
+#endif
+
+	/* 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_backup[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++;
+		}
+	}
+}
+#endif /*  !defined(STATIC_TRAINING) */
+
+/*
+ * 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)
+{
+	unsigned int status;
+
+	ddr3_set_pbs(DDR3_PBS);
+	ddr3_set_sw_wl_rl_debug(DDR3_RUN_SW_WHEN_HW_FAIL);
+
+	status = ddr3_init_main();
+	if (status == MV_DDR3_TRAINING_ERR_BAD_SAR)
+		DEBUG_INIT_S("DDR3 Training Error: Bad sample at reset");
+	if (status == MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP)
+		DEBUG_INIT_S("DDR3 Training Error: Bad DIMM setup");
+	if (status == MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT)
+		DEBUG_INIT_S("DDR3 Training Error: Max CS limit");
+	if (status == MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT)
+		DEBUG_INIT_S("DDR3 Training Error: Max enable CS limit");
+	if (status == MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP)
+		DEBUG_INIT_S("DDR3 Training Error: Bad R-DIMM setup");
+	if (status == MV_DDR3_TRAINING_ERR_TWSI_FAIL)
+		DEBUG_INIT_S("DDR3 Training Error: TWSI failure");
+	if (status == MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH)
+		DEBUG_INIT_S("DDR3 Training Error: DIMM type no match");
+	if (status == MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE)
+		DEBUG_INIT_S("DDR3 Training Error: TWSI bad type");
+	if (status == MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH)
+		DEBUG_INIT_S("DDR3 Training Error: bus width no match");
+	if (status > MV_DDR3_TRAINING_ERR_HW_FAIL_BASE)
+		DEBUG_INIT_C("DDR3 Training Error: HW Failure 0x", status, 8);
+
+	return status;
+}
+
+static void print_ddr_target_freq(u32 cpu_freq, u32 fab_opt)
+{
+	puts("\nDDR3 Training Sequence - Run DDR3 at ");
+
+	switch (cpu_freq) {
+#if defined(MV88F672X)
+	case 21:
+		puts("533 Mhz\n");
+		break;
+#else
+	case 1:
+		puts("533 Mhz\n");
+		break;
+	case 2:
+		if (fab_opt == 5)
+			puts("600 Mhz\n");
+		if (fab_opt == 9)
+			puts("400 Mhz\n");
+		break;
+	case 3:
+		puts("667 Mhz\n");
+		break;
+	case 4:
+		if (fab_opt == 5)
+			puts("750 Mhz\n");
+		if (fab_opt == 9)
+			puts("500 Mhz\n");
+		break;
+	case 0xa:
+		puts("400 Mhz\n");
+		break;
+	case 0xb:
+		if (fab_opt == 5)
+			puts("800 Mhz\n");
+		if (fab_opt == 9)
+			puts("553 Mhz\n");
+		if (fab_opt == 0xA)
+			puts("640 Mhz\n");
+		break;
+#endif
+	default:
+		puts("NOT DEFINED FREQ\n");
+	}
+}
+
+static u32 ddr3_init_main(void)
+{
+	u32 target_freq;
+	u32 reg = 0;
+	u32 cpu_freq, fab_opt, hclk_time_ps, soc_num;
+	__maybe_unused u32 ecc = DRAM_ECC;
+	__maybe_unused int dqs_clk_aligned = 0;
+	__maybe_unused u32 scrub_offs, scrub_size;
+	__maybe_unused u32 ddr_width = BUS_WIDTH;
+	__maybe_unused int status;
+	__maybe_unused u32 win_backup[16];
+
+	/* SoC/Board special Initializtions */
+	fab_opt = ddr3_get_fab_opt();
+
+#ifdef CONFIG_SPD_EEPROM
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+
+	ddr3_print_version();
+	DEBUG_INIT_S("4\n");
+	/* Lib version 5.5.4 */
+
+	fab_opt = ddr3_get_fab_opt();
+
+	/* 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;
+	}
+
+	/* Power down deskew PLL */
+#if !defined(MV88F672X)
+	/* 0x18780 [25] */
+	reg = (reg_read(REG_DDRPHY_APLL_CTRL_ADDR) & ~(1 << 25));
+	reg_write(REG_DDRPHY_APLL_CTRL_ADDR, reg);
+#endif
+
+	/*
+	 * Stage 0 - Set board configuration
+	 */
+	cpu_freq = ddr3_get_cpu_freq();
+	if (fab_opt > FAB_OPT)
+		fab_opt = FAB_OPT - 1;
+
+	if (ddr3_get_log_level() > 0)
+		print_ddr_target_freq(cpu_freq, fab_opt);
+
+#if defined(MV88F672X)
+	get_target_freq(cpu_freq, &target_freq, &hclk_time_ps);
+#else
+	target_freq = cpu_ddr_ratios[fab_opt][cpu_freq];
+	hclk_time_ps = cpu_fab_clk_to_hclk[fab_opt][cpu_freq];
+#endif
+	if ((target_freq == 0) || (hclk_time_ps == 0)) {
+		DEBUG_INIT_S("DDR3 Training Sequence - FAILED - Wrong Sample at Reset Configurations\n");
+		if (target_freq == 0) {
+			DEBUG_INIT_C("target_freq", target_freq, 2);
+			DEBUG_INIT_C("fab_opt", fab_opt, 2);
+			DEBUG_INIT_C("cpu_freq", cpu_freq, 2);
+		} else if (hclk_time_ps == 0) {
+			DEBUG_INIT_C("hclk_time_ps", hclk_time_ps, 2);
+			DEBUG_INIT_C("fab_opt", fab_opt, 2);
+			DEBUG_INIT_C("cpu_freq", cpu_freq, 2);
+		}
+
+		return MV_DDR3_TRAINING_ERR_BAD_SAR;
+	}
+
+#if defined(ECC_SUPPORT)
+	scrub_offs = U_BOOT_START_ADDR;
+	scrub_size = U_BOOT_SCRUB_SIZE;
+#else
+	scrub_offs = 0;
+	scrub_size = 0;
+#endif
+
+#if defined(ECC_SUPPORT) && defined(AUTO_DETECTION_SUPPORT)
+	ecc = DRAM_ECC;
+#endif
+
+#if defined(ECC_SUPPORT) && defined(AUTO_DETECTION_SUPPORT)
+	ecc = 0;
+	if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_ECC))
+		ecc = 1;
+#endif
+
+#ifdef DQS_CLK_ALIGNED
+	dqs_clk_aligned = 1;
+#endif
+
+	/* Check if DRAM is already initialized  */
+	if (reg_read(REG_BOOTROM_ROUTINE_ADDR) &
+	    (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) {
+		DEBUG_INIT_S("DDR3 Training Sequence - 2nd boot - Skip\n");
+		return MV_OK;
+	}
+
+	/*
+	 * Stage 1 - Dunit Setup
+	 */
+
+#ifdef DUNIT_STATIC
+	/*
+	 * For Static D-Unit Setup use must set the correct static values
+	 * at the ddr3_*soc*_vars.h file
+	 */
+	DEBUG_INIT_FULL_S("DDR3 Training Sequence - Static MC Init\n");
+	ddr3_static_mc_init();
+
+#ifdef ECC_SUPPORT
+	ecc = DRAM_ECC;
+	if (ecc) {
+		reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+		reg |= (1 << REG_SDRAM_CONFIG_ECC_OFFS);
+		reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+	}
+#endif
+#endif
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+#if defined(AUTO_DETECTION_SUPPORT)
+	/*
+	 * Configurations for both static and dynamic MC setups
+	 *
+	 * Dynamically Set 32Bit and ECC for AXP (Relevant only for
+	 * Marvell DB boards)
+	 */
+	if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_BUS_WIDTH)) {
+		ddr_width = 32;
+		DEBUG_INIT_S("DDR3 Training Sequence - DRAM bus width 32Bit\n");
+	}
+#endif
+
+#if defined(MV88F672X)
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+	if ((reg >> 15) & 1)
+		ddr_width = 32;
+	else
+		ddr_width = 16;
+#endif
+#endif
+
+#ifdef DUNIT_SPD
+	status = ddr3_dunit_setup(ecc, hclk_time_ps, &ddr_width);
+	if (MV_OK != status) {
+		DEBUG_INIT_S("DDR3 Training Sequence - FAILED (ddr3 Dunit Setup)\n");
+		return status;
+	}
+#endif
+
+	/* 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);
+
+#if defined(MV88F672X)
+	/*
+	 * AxiBrespMode[8] = Compliant,
+	 * AxiAddrDecodeCntrl[11] = Internal,
+	 * AxiDataBusWidth[0] = 128bit
+	 */
+	/* 0x14A8 - AXI Control Register */
+	reg_write(REG_DRAM_AXI_CTRL_ADDR, 0);
+#else
+	/* 0x14A8 - AXI Control Register */
+	reg_write(REG_DRAM_AXI_CTRL_ADDR, 0x00000100);
+	reg_write(REG_CDI_CONFIG_ADDR, 0x00000006);
+
+	if ((ddr_width == 64) && (reg_read(REG_DDR_IO_ADDR) &
+				  (1 << REG_DDR_IO_CLK_RATIO_OFFS))) {
+		/* 0x14A8 - AXI Control Register */
+		reg_write(REG_DRAM_AXI_CTRL_ADDR, 0x00000101);
+		reg_write(REG_CDI_CONFIG_ADDR, 0x00000007);
+	}
+#endif
+
+#if !defined(MV88F67XX)
+	/*
+	 * ARMADA-370 activate DLB later at the u-boot,
+	 * Armada38x - No DLB activation at this time
+	 */
+	reg_write(DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x18C01E);
+
+#if defined(MV88F78X60)
+	/* WA according to eratta GL-8672902*/
+	if (mv_ctrl_rev_get() == MV_78XX0_B0_REV)
+		reg_write(DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0xc19e);
+#endif
+
+	reg_write(DLB_AGING_REGISTER, 0x0f7f007f);
+	reg_write(DLB_EVICTION_CONTROL_REG, 0x0);
+	reg_write(DLB_EVICTION_TIMERS_REGISTER_REG, 0x00FF3C1F);
+
+	reg_write(MBUS_UNITS_PRIORITY_CONTROL_REG, 0x55555555);
+	reg_write(FABRIC_UNITS_PRIORITY_CONTROL_REG, 0xAA);
+	reg_write(MBUS_UNITS_PREFETCH_CONTROL_REG, 0xffff);
+	reg_write(FABRIC_UNITS_PREFETCH_CONTROL_REG, 0xf0f);
+
+#if defined(MV88F78X60)
+	/* WA according to eratta GL-8672902 */
+	if (mv_ctrl_rev_get() == MV_78XX0_B0_REV) {
+		reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+		reg |= DLB_ENABLE;
+		reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+	}
+#endif /* end defined(MV88F78X60) */
+#endif /* end !defined(MV88F67XX) */
+
+	if (ddr3_get_log_level() >= MV_LOG_LEVEL_1)
+		print_dunit_setup();
+
+	/*
+	 * Stage 2 - Training Values Setup
+	 */
+#ifdef STATIC_TRAINING
+	/*
+	 * DRAM Init - After all the D-unit values are set, its time to init
+	 * the D-unit
+	 */
+	/* Wait for '0' */
+	reg_write(REG_SDRAM_INIT_CTRL_ADDR, 0x1);
+	do {
+		reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+			(1 << REG_SDRAM_INIT_CTRL_OFFS);
+	} while (reg);
+
+	/* ddr3 init using static parameters - HW training is disabled */
+	DEBUG_INIT_FULL_S("DDR3 Training Sequence - Static Training Parameters\n");
+	ddr3_static_training_init();
+
+#if defined(MV88F78X60)
+	/*
+	 * If ECC is enabled, need to scrub the U-Boot area memory region -
+	 * Run training function with Xor bypass just to scrub the memory
+	 */
+	status = ddr3_hw_training(target_freq, ddr_width,
+				  1, scrub_offs, scrub_size,
+				  dqs_clk_aligned, DDR3_TRAINING_DEBUG,
+				  REG_DIMM_SKIP_WL);
+	if (MV_OK != status) {
+		DEBUG_INIT_FULL_S("DDR3 Training Sequence - FAILED\n");
+		return status;
+	}
+#endif
+#else
+	/* Set X-BAR windows for the training sequence */
+	ddr3_save_and_set_training_windows(win_backup);
+
+	/* Run DDR3 Training Sequence */
+	/* DRAM Init */
+	reg_write(REG_SDRAM_INIT_CTRL_ADDR, 0x1);
+	do {
+		reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+			(1 << REG_SDRAM_INIT_CTRL_OFFS);
+	} while (reg);		/* Wait for '0' */
+
+	/* ddr3 init using DDR3 HW training procedure */
+	DEBUG_INIT_FULL_S("DDR3 Training Sequence - HW Training Procedure\n");
+	status = ddr3_hw_training(target_freq, ddr_width,
+				  0, scrub_offs, scrub_size,
+				  dqs_clk_aligned, DDR3_TRAINING_DEBUG,
+				  REG_DIMM_SKIP_WL);
+	if (MV_OK != status) {
+		DEBUG_INIT_FULL_S("DDR3 Training Sequence - FAILED\n");
+		return status;
+	}
+#endif
+
+	/*
+	 * Stage 3 - Finish
+	 */
+#if defined(MV88F78X60) || defined(MV88F672X)
+	/* Disable ECC Ignore bit */
+	reg = reg_read(REG_SDRAM_CONFIG_ADDR) &
+		~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
+	reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+#endif
+
+#if !defined(STATIC_TRAINING)
+	/* Restore and set windows */
+	ddr3_restore_and_set_final_windows(win_backup);
+#endif
+
+	/* 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));
+
+#if !defined(MV88F67XX)
+#if defined(MV88F78X60)
+	if (mv_ctrl_rev_get() == MV_78XX0_B0_REV) {
+		reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+		if (ecc == 0)
+			reg_write(REG_SDRAM_CONFIG_ADDR, reg | (1 << 19));
+	}
+#endif /* end defined(MV88F78X60) */
+
+	reg_write(DLB_EVICTION_CONTROL_REG, 0x9);
+
+	reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+	reg |= (DLB_ENABLE | DLB_WRITE_COALESING | DLB_AXI_PREFETCH_EN |
+		DLB_MBUS_PREFETCH_EN | PREFETCH_NLNSZTR);
+	reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+#endif /* end !defined(MV88F67XX) */
+
+#ifdef STATIC_TRAINING
+	DEBUG_INIT_S("DDR3 Training Sequence - Ended Successfully (S)\n");
+#else
+	DEBUG_INIT_S("DDR3 Training Sequence - Ended Successfully\n");
+#endif
+
+	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)
+{
+	u32 reg, cpu_freq;
+
+#if defined(MV88F672X)
+	/* Read sample at reset setting */
+	reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR);	/* 0xE8200 */
+	cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+		REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+#else
+	/* Read sample at reset setting */
+	reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR);	/* 0x18230 [23:21] */
+#if defined(MV88F78X60)
+	cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+		REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+	reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR);	/* 0x18234 [20] */
+	cpu_freq |= (((reg >> REG_SAMPLE_RESET_HIGH_CPU_FREQ_OFFS) & 0x1) << 3);
+#elif defined(MV88F67XX)
+	cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+		REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+#endif
+#endif
+
+	return cpu_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)
+{
+	__maybe_unused u32 reg, fab_opt;
+
+#if defined(MV88F672X)
+	return 0;		/* No fabric */
+#else
+	/* Read sample at reset setting */
+	reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR);
+	fab_opt = (reg & REG_SAMPLE_RESET_FAB_MASK) >>
+		REG_SAMPLE_RESET_FAB_OFFS;
+
+#if defined(MV88F78X60)
+	reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR);
+	fab_opt |= (((reg >> 19) & 0x1) << 4);
+#endif
+
+	return fab_opt;
+#endif
+}
+
+/*
+ * Name:     ddr3_get_vco_freq
+ * Desc:     read S@R and return VCO frequency
+ * Args:
+ * Notes:
+ * Returns:  required value
+ */
+u32 ddr3_get_vco_freq(void)
+{
+	u32 fab, cpu_freq, ui_vco_freq;
+
+	fab = ddr3_get_fab_opt();
+	cpu_freq = ddr3_get_cpu_freq();
+
+	if (fab == 2 || fab == 3 || fab == 7 || fab == 8 || fab == 10 ||
+	    fab == 15 || fab == 17 || fab == 20)
+		ui_vco_freq = cpu_freq + CLK_CPU;
+	else
+		ui_vco_freq = cpu_freq;
+
+	return ui_vco_freq;
+}
+
+#ifdef STATIC_TRAINING
+/*
+ * Name:     ddr3_static_training_init - Init DDR3 Training 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.
+ */
+void ddr3_static_training_init(void)
+{
+	MV_DRAM_MODES *ddr_mode;
+	u32 reg;
+	int j;
+
+	ddr_mode = ddr3_get_static_ddr_mode();
+
+	j = 0;
+	while (ddr_mode->vals[j].reg_addr != 0) {
+		udelay(10);	/* haim want to delay each write */
+		reg_write(ddr_mode->vals[j].reg_addr,
+			  ddr_mode->vals[j].reg_value);
+
+		if (ddr_mode->vals[j].reg_addr ==
+		    REG_PHY_REGISTRY_FILE_ACCESS_ADDR)
+			do {
+				reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+					REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+			} while (reg);
+		j++;
+	}
+}
+#endif
+
+/*
+ * Name:     ddr3_get_static_mc_value - 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, tmp;
+
+	reg = reg_read(reg_addr);
+
+	tmp = (reg >> offset1) & mask1;
+	if (mask2)
+		tmp |= (reg >> offset2) & mask2;
+
+	return tmp;
+}
+
+/*
+ * 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.
+ */
+__weak MV_DRAM_MODES *ddr3_get_static_ddr_mode(void)
+{
+	u32 chip_board_rev, i;
+	u32 size;
+
+	/* Do not modify this code. relevant only for marvell Boards */
+#if defined(DB_78X60_PCAC)
+	chip_board_rev = Z1_PCAC;
+#elif defined(DB_78X60_AMC)
+	chip_board_rev = A0_AMC;
+#elif defined(DB_88F6710_PCAC)
+	chip_board_rev = A0_PCAC;
+#elif defined(RD_88F6710)
+	chip_board_rev = A0_RD;
+#elif defined(MV88F672X)
+	chip_board_rev = mv_board_id_get();
+#else
+	chip_board_rev = A0;
+#endif
+
+	size = sizeof(ddr_modes) / sizeof(MV_DRAM_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 &ddr_modes[i];
+	}
+
+	return &ddr_modes[0];
+}
+
+#ifdef DUNIT_STATIC
+/*
+ * Name:     ddr3_static_mc_init - 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.
+ */
+void ddr3_static_mc_init(void)
+{
+	MV_DRAM_MODES *ddr_mode;
+	u32 reg;
+	int j;
+
+	ddr_mode = ddr3_get_static_ddr_mode();
+	j = 0;
+	while (ddr_mode->regs[j].reg_addr != 0) {
+		reg_write(ddr_mode->regs[j].reg_addr,
+			  ddr_mode->regs[j].reg_value);
+		if (ddr_mode->regs[j].reg_addr ==
+		    REG_PHY_REGISTRY_FILE_ACCESS_ADDR)
+			do {
+				reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+					REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+			} while (reg);
+		j++;
+	}
+}
+#endif
+
+/*
+ * Name:     ddr3_check_config - Check user configurations: ECC/MultiCS
+ * Desc:
+ * Args:     twsi Address
+ * Notes:    Only Available for ArmadaXP/Armada 370 DB boards
+ * Returns:  None.
+ */
+int ddr3_check_config(u32 twsi_addr, MV_CONFIG_TYPE config_type)
+{
+#ifdef AUTO_DETECTION_SUPPORT
+	u8 data = 0;
+	int ret;
+	int offset;
+
+	if ((config_type == CONFIG_ECC) || (config_type == CONFIG_BUS_WIDTH))
+		offset = 1;
+	else
+		offset = 0;
+
+	ret = i2c_read(twsi_addr, offset, 1, (u8 *)&data, 1);
+	if (!ret) {
+		switch (config_type) {
+		case CONFIG_ECC:
+			if (data & 0x2)
+				return 1;
+			break;
+		case CONFIG_BUS_WIDTH:
+			if (data & 0x1)
+				return 1;
+			break;
+#ifdef DB_88F6710
+		case CONFIG_MULTI_CS:
+			if (CFG_MULTI_CS_MODE(data))
+				return 1;
+			break;
+#else
+		case CONFIG_MULTI_CS:
+			break;
+#endif
+		}
+	}
+#endif
+
+	return 0;
+}
+
+#if defined(DB_88F78X60_REV2)
+/*
+ * Name:     ddr3_get_eprom_fabric - Get Fabric configuration from EPROM
+ * Desc:
+ * Args:     twsi Address
+ * Notes:    Only Available for ArmadaXP DB Rev2 boards
+ * Returns:  None.
+ */
+u8 ddr3_get_eprom_fabric(void)
+{
+#ifdef AUTO_DETECTION_SUPPORT
+	u8 data = 0;
+	int ret;
+
+	ret = i2c_read(NEW_FABRIC_TWSI_ADDR, 1, 1, (u8 *)&data, 1);
+	if (!ret)
+		return data & 0x1F;
+#endif
+
+	return 0;
+}
+
+#endif
+
+/*
+ * Name:     ddr3_cl_to_valid_cl - this return register matching CL value
+ * Desc:
+ * Args:     clValue - the value
+
+ * Notes:
+ * Returns:  required CL value
+ */
+u32 ddr3_cl_to_valid_cl(u32 cl)
+{
+	switch (cl) {
+	case 5:
+		return 2;
+		break;
+	case 6:
+		return 4;
+		break;
+	case 7:
+		return 6;
+		break;
+	case 8:
+		return 8;
+		break;
+	case 9:
+		return 10;
+		break;
+	case 10:
+		return 12;
+		break;
+	case 11:
+		return 14;
+		break;
+	case 12:
+		return 1;
+		break;
+	case 13:
+		return 3;
+		break;
+	case 14:
+		return 5;
+		break;
+	default:
+		return 2;
+	}
+}
+
+/*
+ * Name:     ddr3_cl_to_valid_cl - this return register matching CL value
+ * Desc:
+ * Args:     clValue - the value
+ * Notes:
+ * Returns:  required CL value
+ */
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl)
+{
+	switch (ui_valid_cl) {
+	case 1:
+		return 12;
+		break;
+	case 2:
+		return 5;
+		break;
+	case 3:
+		return 13;
+		break;
+	case 4:
+		return 6;
+		break;
+	case 5:
+		return 14;
+		break;
+	case 6:
+		return 7;
+		break;
+	case 8:
+		return 8;
+		break;
+	case 10:
+		return 9;
+		break;
+	case 12:
+		return 10;
+		break;
+	case 14:
+		return 11;
+		break;
+	default:
+		return 0;
+	}
+}
+
+/*
+ * Name:     ddr3_get_cs_num_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_num_from_reg(void)
+{
+	u32 cs_ena = ddr3_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_get_cs_ena_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_ena_from_reg(void)
+{
+	return reg_read(REG_DDR3_RANK_CTRL_ADDR) &
+		REG_DDR3_RANK_CTRL_CS_ENA_MASK;
+}
+
+/*
+ * mv_ctrl_rev_get - Get Marvell controller device revision number
+ *
+ * DESCRIPTION:
+ *       This function returns 8bit describing the device revision as defined
+ *       in PCI Express Class Code and Revision ID Register.
+ *
+ * INPUT:
+ *       None.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       8bit desscribing Marvell controller revision number
+ *
+ */
+#if !defined(MV88F672X)
+u8 mv_ctrl_rev_get(void)
+{
+	u8 rev_num;
+
+#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
+	/* Check pex power state */
+	u32 pex_power;
+	pex_power = mv_ctrl_pwr_clck_get(PEX_UNIT_ID, 0);
+	if (pex_power == 0)
+		mv_ctrl_pwr_clck_set(PEX_UNIT_ID, 0, 1);
+#endif
+	rev_num = (u8)reg_read(PEX_CFG_DIRECT_ACCESS(0,
+			PCI_CLASS_CODE_AND_REVISION_ID));
+
+#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
+	/* Return to power off state */
+	if (pex_power == 0)
+		mv_ctrl_pwr_clck_set(PEX_UNIT_ID, 0, 0);
+#endif
+
+	return (rev_num & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS;
+}
+
+#endif
+
+#if defined(MV88F672X)
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps)
+{
+	u32 tmp, hclk;
+
+	switch (freq_mode) {
+	case CPU_333MHz_DDR_167MHz_L2_167MHz:
+		hclk = 84;
+		tmp = DDR_100;
+		break;
+	case CPU_266MHz_DDR_266MHz_L2_133MHz:
+	case CPU_333MHz_DDR_222MHz_L2_167MHz:
+	case CPU_400MHz_DDR_200MHz_L2_200MHz:
+	case CPU_400MHz_DDR_267MHz_L2_200MHz:
+	case CPU_533MHz_DDR_267MHz_L2_267MHz:
+	case CPU_500MHz_DDR_250MHz_L2_250MHz:
+	case CPU_600MHz_DDR_300MHz_L2_300MHz:
+	case CPU_800MHz_DDR_267MHz_L2_400MHz:
+	case CPU_900MHz_DDR_300MHz_L2_450MHz:
+		tmp = DDR_300;
+		hclk = 150;
+		break;
+	case CPU_333MHz_DDR_333MHz_L2_167MHz:
+	case CPU_500MHz_DDR_334MHz_L2_250MHz:
+	case CPU_666MHz_DDR_333MHz_L2_333MHz:
+		tmp = DDR_333;
+		hclk = 165;
+		break;
+	case CPU_533MHz_DDR_356MHz_L2_267MHz:
+		tmp = DDR_360;
+		hclk = 180;
+		break;
+	case CPU_400MHz_DDR_400MHz_L2_200MHz:
+	case CPU_600MHz_DDR_400MHz_L2_300MHz:
+	case CPU_800MHz_DDR_400MHz_L2_400MHz:
+	case CPU_400MHz_DDR_400MHz_L2_400MHz:
+		tmp = DDR_400;
+		hclk = 200;
+		break;
+	case CPU_666MHz_DDR_444MHz_L2_333MHz:
+	case CPU_900MHz_DDR_450MHz_L2_450MHz:
+		tmp = DDR_444;
+		hclk = 222;
+		break;
+	case CPU_500MHz_DDR_500MHz_L2_250MHz:
+	case CPU_1000MHz_DDR_500MHz_L2_500MHz:
+	case CPU_1000MHz_DDR_500MHz_L2_333MHz:
+		tmp = DDR_500;
+		hclk = 250;
+		break;
+	case CPU_533MHz_DDR_533MHz_L2_267MHz:
+	case CPU_800MHz_DDR_534MHz_L2_400MHz:
+	case CPU_1100MHz_DDR_550MHz_L2_550MHz:
+		tmp = DDR_533;
+		hclk = 267;
+		break;
+	case CPU_600MHz_DDR_600MHz_L2_300MHz:
+	case CPU_900MHz_DDR_600MHz_L2_450MHz:
+	case CPU_1200MHz_DDR_600MHz_L2_600MHz:
+		tmp = DDR_600;
+		hclk = 300;
+		break;
+	case CPU_666MHz_DDR_666MHz_L2_333MHz:
+	case CPU_1000MHz_DDR_667MHz_L2_500MHz:
+		tmp = DDR_666;
+		hclk = 333;
+		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;
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_init.h b/drivers/ddr/mvebu/ddr3_init.h
new file mode 100644
index 0000000..b259e09
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_init.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __DDR3_INIT_H
+#define __DDR3_INIT_H
+
+/*
+ * Debug
+ */
+
+/*
+ * MV_DEBUG_INIT need to be defines, otherwise the output of the
+ * DDR2 training code is not complete and misleading
+ */
+#define MV_DEBUG_INIT
+
+#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"); }
+
+#define MV_MBUS_REGS_OFFSET                 (0x20000)
+
+#include "ddr3_hw_training.h"
+
+#define MAX_DIMM_NUM			2
+#define SPD_SIZE			128
+
+#ifdef MV88F78X60
+#include "ddr3_axp.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375.h"
+#endif
+
+/* DRR training Error codes */
+/* Stage 0 errors */
+#define MV_DDR3_TRAINING_ERR_BAD_SAR			0xDD300001
+/* Stage 1 errors */
+#define MV_DDR3_TRAINING_ERR_TWSI_FAIL			0xDD301001
+#define MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH		0xDD301001
+#define MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE		0xDD301003
+#define MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH	0xDD301004
+#define MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP		0xDD301005
+#define MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT		0xDD301006
+#define MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT		0xDD301007
+#define MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP		0xDD301008
+/* Stage 2 errors */
+#define MV_DDR3_TRAINING_ERR_HW_FAIL_BASE		0xDD302000
+
+typedef enum config_type {
+	CONFIG_ECC,
+	CONFIG_MULTI_CS,
+	CONFIG_BUS_WIDTH
+} MV_CONFIG_TYPE;
+
+enum log_level  {
+	MV_LOG_LEVEL_0,
+	MV_LOG_LEVEL_1,
+	MV_LOG_LEVEL_2,
+	MV_LOG_LEVEL_3
+};
+
+int ddr3_hw_training(u32 target_freq, u32 ddr_width,
+		     int xor_bypass, u32 scrub_offs, u32 scrub_size,
+		     int dqs_clk_aligned, int debug_mode, int reg_dimm_skip_wl);
+
+void ddr3_print_version(void);
+void fix_pll_val(u8 target_fab);
+u8 ddr3_get_eprom_fabric(void);
+u32 ddr3_get_fab_opt(void);
+u32 ddr3_get_cpu_freq(void);
+u32 ddr3_get_vco_freq(void);
+int ddr3_check_config(u32 addr, MV_CONFIG_TYPE config_type);
+u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1, u32 offset2,
+			     u32 mask2);
+u32 ddr3_cl_to_valid_cl(u32 cl);
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl);
+u32 ddr3_get_cs_num_from_reg(void);
+u32 ddr3_get_cs_ena_from_reg(void);
+u8 mv_ctrl_rev_get(void);
+
+u32 ddr3_get_log_level(void);
+
+/* SPD */
+int ddr3_dunit_setup(u32 ecc_ena, u32 hclk_time, u32 *ddr_width);
+
+/*
+ * 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/mvebu/ddr3_patterns_64bit.h b/drivers/ddr/mvebu/ddr3_patterns_64bit.h
new file mode 100644
index 0000000..1b57328
--- /dev/null
+++ b/drivers/ddr/mvebu/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/mvebu/ddr3_pbs.c b/drivers/ddr/mvebu/ddr3_pbs.c
new file mode 100644
index 0000000..00ea3fd
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_pbs.c
@@ -0,0 +1,1592 @@
+/*
+ * 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_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_PBS_FULL_C(s, d, l) \
+	DEBUG_PBS_FULL_S(s); DEBUG_PBS_FULL_D(d, l); DEBUG_PBS_FULL_S("\n")
+#define DEBUG_PBS_C(s, d, l) \
+	DEBUG_PBS_S(s); DEBUG_PBS_D(d, l); DEBUG_PBS_S("\n")
+
+#ifdef MV_DEBUG_PBS
+#define DEBUG_PBS_S(s)			puts(s)
+#define DEBUG_PBS_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_PBS_S(s)
+#define DEBUG_PBS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_FULL_PBS
+#define DEBUG_PBS_FULL_S(s)		puts(s)
+#define DEBUG_PBS_FULL_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_PBS_FULL_S(s)
+#define DEBUG_PBS_FULL_D(d, l)
+#endif
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+
+/* Temp array for skew data storage */
+static u32 skew_array[(MAX_PUP_NUM) * DQ_NUM] = { 0 };
+
+/* PBS locked dq (per pup) */
+extern u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM];
+extern u32 pbs_locked_dm[MAX_PUP_NUM];
+extern u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM];
+
+#if defined(MV88F672X)
+extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+#else
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
+#endif
+
+extern u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM];
+
+static int ddr3_tx_shift_dqs_adll_step_before_fail(MV_DRAM_INFO *dram_info,
+		u32 cur_pup, u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_rx_shift_dqs_to_first_fail(MV_DRAM_INFO *dram_info, u32 cur_pup,
+		u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_pbs_per_bit(MV_DRAM_INFO *dram_info, int *start_over, int is_tx,
+		u32 *pcur_pup, u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_set_pbs_results(MV_DRAM_INFO *dram_info, int is_tx);
+static void ddr3_pbs_write_pup_dqs_reg(u32 cs, u32 pup, u32 dqs_delay);
+
+/*
+ * Name:     ddr3_pbs_tx
+ * Desc:     Execute the PBS TX phase.
+ * Args:     dram_info   ddr3 training information struct
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_pbs_tx(MV_DRAM_INFO *dram_info)
+{
+	/* Array of Deskew results */
+
+	/*
+	 * Array to hold the total sum of skew from all iterations
+	 * (for average purpose)
+	 */
+	u32 skew_sum_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+	/*
+	 * Array to hold the total average skew from both patterns
+	 * (for average purpose)
+	 */
+	u32 pattern_skew_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+	u32 pbs_rep_time = 0;	/* counts number of loop in case of fail */
+	/* bit array for unlock pups - used to repeat on the RX operation */
+	u32 cur_pup;
+	u32 max_pup;
+	u32 pbs_retry;
+	u32 pup, dq, pups, cur_max_pup, valid_pup, reg;
+	u32 pattern_idx;
+	u32 ecc;
+	/* indicates whether we need to start the loop again */
+	int start_over;
+
+	DEBUG_PBS_S("DDR3 - PBS TX - Starting PBS TX procedure\n");
+
+	pups = dram_info->num_of_total_pups;
+	max_pup = dram_info->num_of_total_pups;
+
+	/* Enable SW override */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	DEBUG_PBS_S("DDR3 - PBS RX - SW Override Enabled\n");
+
+	reg = 1 << REG_DRAM_TRAINING_AUTO_OFFS;
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	/* Running twice for 2 different patterns. each patterns - 3 times */
+	for (pattern_idx = 0; pattern_idx < COUNT_PBS_PATTERN; pattern_idx++) {
+		DEBUG_PBS_C("DDR3 - PBS TX - Working with pattern - ",
+			    pattern_idx, 1);
+
+		/* Reset sum array */
+		for (pup = 0; pup < pups; pup++) {
+			for (dq = 0; dq < DQ_NUM; dq++)
+				skew_sum_array[pup][dq] = 0;
+		}
+
+		/*
+		 * Perform PBS several of times (3 for each pattern).
+		 * At the end, we'll use the average
+		 */
+		/* If there is ECC, do each PBS again with mux change */
+		for (pbs_retry = 0; pbs_retry < COUNT_PBS_REPEAT; pbs_retry++) {
+			for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+
+				/*
+				 * This parameter stores the current PUP
+				 * num - ecc mode dependent - 4-8 / 1 pups
+				 */
+				cur_max_pup = (1 - ecc) *
+					dram_info->num_of_std_pups + ecc;
+
+				if (ecc) {
+					/* Only 1 pup in this case */
+					valid_pup = 0x1;
+				} else if (cur_max_pup > 4) {
+					/* 64 bit - 8 pups */
+					valid_pup = 0xFF;
+				} else if (cur_max_pup == 4) {
+					/* 32 bit - 4 pups */
+					valid_pup = 0xF;
+				} else {
+					/* 16 bit - 2 pups */
+					valid_pup = 0x3;
+				}
+
+				/* ECC Support - Switch ECC Mux on ecc=1 */
+				reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+					~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg |= (dram_info->ecc_ena * ecc <<
+					REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+				if (ecc)
+					DEBUG_PBS_S("DDR3 - PBS Tx - ECC Mux Enabled\n");
+				else
+					DEBUG_PBS_S("DDR3 - PBS Tx - ECC Mux Disabled\n");
+
+				/* Init iteration values */
+				/* Clear the locked DQs */
+				for (pup = 0; pup < cur_max_pup; pup++) {
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						pbs_locked_dq[
+							pup + ecc *
+							(max_pup - 1)][dq] =
+							0;
+					}
+				}
+
+				pbs_rep_time = 0;
+				cur_pup = valid_pup;
+				start_over = 0;
+
+				/*
+				 * Run loop On current Pattern and current
+				 * pattern iteration (just to cover the false
+				 * fail problem)
+				 */
+				do {
+					DEBUG_PBS_S("DDR3 - PBS Tx - Pbs Rep Loop is ");
+					DEBUG_PBS_D(pbs_rep_time, 1);
+					DEBUG_PBS_S(", for Retry No.");
+					DEBUG_PBS_D(pbs_retry, 1);
+					DEBUG_PBS_S("\n");
+
+					/* Set all PBS values to MIN (0) */
+					DEBUG_PBS_S("DDR3 - PBS Tx - Set all PBS values to MIN\n");
+
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						ddr3_write_pup_reg(
+							PUP_PBS_TX +
+							pbs_dq_mapping[pup *
+								(1 - ecc) +
+								ecc * ECC_PUP]
+							[dq], CS0, (1 - ecc) *
+							PUP_BC + ecc * ECC_PUP, 0,
+							0);
+					}
+
+					/*
+					 * Shift DQ ADLL right, One step before
+					 * fail
+					 */
+					DEBUG_PBS_S("DDR3 - PBS Tx - ADLL shift right one phase before fail\n");
+
+					if (MV_OK != ddr3_tx_shift_dqs_adll_step_before_fail
+					    (dram_info, cur_pup, pattern_idx,
+					     ecc))
+						return MV_DDR3_TRAINING_ERR_PBS_ADLL_SHR_1PHASE;
+
+					/* PBS For each bit */
+					DEBUG_PBS_S("DDR3 - PBS Tx - perform PBS for each bit\n");
+
+					/*
+					 * In this stage - start_over = 0
+					 */
+					if (MV_OK != ddr3_pbs_per_bit(
+						    dram_info, &start_over, 1,
+						    &cur_pup, pattern_idx, ecc))
+						return MV_DDR3_TRAINING_ERR_PBS_TX_PER_BIT;
+
+				} while ((start_over == 1) &&
+					 (++pbs_rep_time < COUNT_PBS_STARTOVER));
+
+				if (pbs_rep_time == COUNT_PBS_STARTOVER &&
+				    start_over == 1) {
+					DEBUG_PBS_S("DDR3 - PBS Tx - FAIL - Adll reach max value\n");
+					return MV_DDR3_TRAINING_ERR_PBS_TX_MAX_VAL;
+				}
+
+				DEBUG_PBS_FULL_C("DDR3 - PBS TX - values for iteration - ",
+						 pbs_retry, 1);
+				for (pup = 0; pup < cur_max_pup; pup++) {
+					/*
+					 * To minimize delay elements, inc
+					 * from pbs value the min pbs val
+					 */
+					DEBUG_PBS_S("DDR3 - PBS - PUP");
+					DEBUG_PBS_D((pup + (ecc * ECC_PUP)), 1);
+					DEBUG_PBS_S(": ");
+
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						/* Set skew value for all dq */
+						/*
+						 * Bit# Deskew <- Bit# Deskew -
+						 * last / first  failing bit
+						 * Deskew For all bits (per PUP)
+						 * (minimize delay elements)
+						 */
+						DEBUG_PBS_S("DQ");
+						DEBUG_PBS_D(dq, 1);
+						DEBUG_PBS_S("-");
+						DEBUG_PBS_D(skew_array
+							    [((pup) * DQ_NUM) +
+							     dq], 2);
+						DEBUG_PBS_S(", ");
+					}
+					DEBUG_PBS_S("\n");
+				}
+
+				/*
+				 * Collect the results we got on this trial
+				 * of PBS
+				 */
+				for (pup = 0; pup < cur_max_pup; pup++) {
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						skew_sum_array[pup + (ecc * (max_pup - 1))]
+							[dq] += skew_array
+							[((pup) * DQ_NUM) + dq];
+					}
+				}
+
+				/* ECC Support - Disable ECC MUX */
+				reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+					~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+			}
+		}
+
+		DEBUG_PBS_C("DDR3 - PBS TX - values for current pattern - ",
+			    pattern_idx, 1);
+		for (pup = 0; pup < max_pup; pup++) {
+			/*
+			 * To minimize delay elements, inc from pbs value the
+			 * min pbs val
+			 */
+			DEBUG_PBS_S("DDR3 - PBS - PUP");
+			DEBUG_PBS_D(pup, 1);
+			DEBUG_PBS_S(": ");
+
+			for (dq = 0; dq < DQ_NUM; dq++) {
+				/* set skew value for all dq */
+				/* Bit# Deskew <- Bit# Deskew - last / first  failing bit Deskew For all bits (per PUP) (minimize delay elements) */
+				DEBUG_PBS_S("DQ");
+				DEBUG_PBS_D(dq, 1);
+				DEBUG_PBS_S("-");
+				DEBUG_PBS_D(skew_sum_array[pup][dq] /
+					    COUNT_PBS_REPEAT, 2);
+				DEBUG_PBS_S(", ");
+			}
+			DEBUG_PBS_S("\n");
+		}
+
+		/*
+		 * Calculate the average skew for current pattern for each
+		 * pup and each bit
+		 */
+		DEBUG_PBS_C("DDR3 - PBS TX - Average for pattern - ",
+			    pattern_idx, 1);
+
+		for (pup = 0; pup < max_pup; pup++) {
+			/*
+			 * FOR ECC only :: found min and max value for current
+			 * pattern skew array
+			 */
+			/* Loop for all dqs */
+			for (dq = 0; dq < DQ_NUM; dq++) {
+				pattern_skew_array[pup][dq] +=
+					(skew_sum_array[pup][dq] /
+					 COUNT_PBS_REPEAT);
+			}
+		}
+	}
+
+	/* Calculate the average skew */
+	for (pup = 0; pup < max_pup; pup++) {
+		for (dq = 0; dq < DQ_NUM; dq++)
+			skew_array[((pup) * DQ_NUM) + dq] =
+				pattern_skew_array[pup][dq] / COUNT_PBS_PATTERN;
+	}
+
+	DEBUG_PBS_S("DDR3 - PBS TX - Average for all patterns:\n");
+	for (pup = 0; pup < max_pup; pup++) {
+		/*
+		 * To minimize delay elements, inc from pbs value the min
+		 * pbs val
+		 */
+		DEBUG_PBS_S("DDR3 - PBS - PUP");
+		DEBUG_PBS_D(pup, 1);
+		DEBUG_PBS_S(": ");
+
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			/* Set skew value for all dq */
+			/*
+			 * Bit# Deskew <- Bit# Deskew - last / first
+			 * failing bit Deskew For all bits (per PUP)
+			 * (minimize delay elements)
+			 */
+			DEBUG_PBS_S("DQ");
+			DEBUG_PBS_D(dq, 1);
+			DEBUG_PBS_S("-");
+			DEBUG_PBS_D(skew_array[(pup * DQ_NUM) + dq], 2);
+			DEBUG_PBS_S(", ");
+		}
+		DEBUG_PBS_S("\n");
+	}
+
+	/* Return ADLL to default value */
+	for (pup = 0; pup < max_pup; pup++) {
+		if (pup == (max_pup - 1) && dram_info->ecc_ena)
+			pup = ECC_PUP;
+		ddr3_pbs_write_pup_dqs_reg(CS0, pup, INIT_WL_DELAY);
+	}
+
+	/* Set averaged PBS results */
+	ddr3_set_pbs_results(dram_info, 1);
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+		(1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+	reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+	DEBUG_PBS_S("DDR3 - PBS Tx - PBS TX ended successfuly\n");
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_tx_shift_dqs_adll_step_before_fail
+ * Desc:     Execute the Tx shift DQ phase.
+ * Args:     dram_info            ddr3 training information struct
+ *           cur_pup              bit array of the function active pups.
+ *           pbs_pattern_idx      Index of PBS pattern
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+static int ddr3_tx_shift_dqs_adll_step_before_fail(MV_DRAM_INFO *dram_info,
+						   u32 cur_pup,
+						   u32 pbs_pattern_idx, u32 ecc)
+{
+	u32 unlock_pup;		/* bit array of unlock pups  */
+	u32 new_lockup_pup;	/* bit array of compare failed pups */
+	u32 adll_val = 4;	/* INIT_WL_DELAY */
+	u32 cur_max_pup, pup;
+	u32 dqs_dly_set[MAX_PUP_NUM] = { 0 };
+	u32 *pattern_ptr;
+
+	/* Choose pattern */
+	switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+	case 16:
+		pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+		break;
+#endif
+	case 32:
+		pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+		break;
+#if defined(MV88F78X60)
+	case 64:
+		pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+		break;
+#endif
+	default:
+		return MV_FAIL;
+	}
+
+	/* Set current pup number */
+	if (cur_pup == 0x1)	/* Ecc mode */
+		cur_max_pup = 1;
+	else
+		cur_max_pup = dram_info->num_of_std_pups;
+
+	unlock_pup = cur_pup;	/* '1' for each unlocked pup */
+
+	/* Loop on all ADLL Vaules */
+	do {
+		/* Loop until found first fail */
+		adll_val++;
+
+		/*
+		 * Increment (Move to right - ADLL) DQ TX delay
+		 * (broadcast to all Data PUPs)
+		 */
+		for (pup = 0; pup < cur_max_pup; pup++)
+			ddr3_pbs_write_pup_dqs_reg(CS0,
+						   pup * (1 - ecc) +
+						   ECC_PUP * ecc, adll_val);
+
+		/*
+		 * Write and Read, compare results (read was already verified)
+		 */
+		/* 0 - all locked */
+		new_lockup_pup = 0;
+
+		if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup,
+						&new_lockup_pup,
+						pattern_ptr, LEN_PBS_PATTERN,
+						SDRAM_PBS_TX_OFFS, 1, 0,
+						NULL,
+						0))
+			return MV_FAIL;
+
+		unlock_pup &= ~new_lockup_pup;
+
+		DEBUG_PBS_FULL_S("Shift DQS by 2 steps for PUPs: ");
+		DEBUG_PBS_FULL_D(unlock_pup, 2);
+		DEBUG_PBS_FULL_C(", Set ADLL value = ", adll_val, 2);
+
+		/* If any PUP failed there is '1' to mark the PUP */
+		if (new_lockup_pup != 0) {
+			/*
+			 * Decrement (Move Back to Left two steps - ADLL)
+			 * DQ TX delay for current failed pups and save
+			 */
+			for (pup = 0; pup < cur_max_pup; pup++) {
+				if (((new_lockup_pup >> pup) & 0x1) &&
+				    dqs_dly_set[pup] == 0)
+					dqs_dly_set[pup] = adll_val - 1;
+			}
+		}
+	} while ((unlock_pup != 0) && (adll_val != ADLL_MAX));
+
+	if (unlock_pup != 0) {
+		DEBUG_PBS_FULL_S("DDR3 - PBS Tx - Shift DQ - Adll value reached maximum\n");
+
+		for (pup = 0; pup < cur_max_pup; pup++) {
+			if (((unlock_pup >> pup) & 0x1) &&
+			    dqs_dly_set[pup] == 0)
+				dqs_dly_set[pup] = adll_val - 1;
+		}
+	}
+
+	DEBUG_PBS_FULL_C("PBS TX one step before fail last pups locked Adll ",
+			 adll_val - 2, 2);
+
+	/* Set the PUP DQS DLY Values */
+	for (pup = 0; pup < cur_max_pup; pup++)
+		ddr3_pbs_write_pup_dqs_reg(CS0, pup * (1 - ecc) + ECC_PUP * ecc,
+					   dqs_dly_set[pup]);
+
+	/* Found one phase before fail */
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_pbs_rx
+ * Desc:     Execute the PBS RX phase.
+ * Args:     dram_info   ddr3 training information struct
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_pbs_rx(MV_DRAM_INFO *dram_info)
+{
+	/*
+	 * Array to hold the total sum of skew from all iterations
+	 * (for average purpose)
+	 */
+	u32 skew_sum_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+	/*
+	 * Array to hold the total average skew from both patterns
+	 * (for average purpose)
+	 */
+	u32 pattern_skew_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+	u32 pbs_rep_time = 0;	/* counts number of loop in case of fail */
+	/* bit array for unlock pups - used to repeat on the RX operation */
+	u32 cur_pup;
+	u32 max_pup;
+	u32 pbs_retry;
+	u32 pup, dq, pups, cur_max_pup, valid_pup, reg;
+	u32 pattern_idx;
+	u32 ecc;
+	/* indicates whether we need to start the loop again */
+	int start_over;
+	int status;
+
+	DEBUG_PBS_S("DDR3 - PBS RX - Starting PBS RX procedure\n");
+
+	pups = dram_info->num_of_total_pups;
+	max_pup = dram_info->num_of_total_pups;
+
+	/* Enable SW override */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	DEBUG_PBS_FULL_S("DDR3 - PBS RX - SW Override Enabled\n");
+
+	reg = 1 << REG_DRAM_TRAINING_AUTO_OFFS;
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	/* Running twice for 2 different patterns. each patterns - 3 times */
+	for (pattern_idx = 0; pattern_idx < COUNT_PBS_PATTERN; pattern_idx++) {
+		DEBUG_PBS_FULL_C("DDR3 - PBS RX - Working with pattern - ",
+				 pattern_idx, 1);
+
+		/* Reset sum array */
+		for (pup = 0; pup < pups; pup++) {
+			for (dq = 0; dq < DQ_NUM; dq++)
+				skew_sum_array[pup][dq] = 0;
+		}
+
+		/*
+		 * Perform PBS several of times (3 for each pattern).
+		 * At the end, we'll use the average
+		 */
+		/* If there is ECC, do each PBS again with mux change */
+		for (pbs_retry = 0; pbs_retry < COUNT_PBS_REPEAT; pbs_retry++) {
+			for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+				/*
+				 * This parameter stores the current PUP
+				 * num - ecc mode dependent - 4-8 / 1 pups
+				 */
+				cur_max_pup = (1 - ecc) *
+					dram_info->num_of_std_pups + ecc;
+
+				if (ecc) {
+					/* Only 1 pup in this case */
+					valid_pup = 0x1;
+				} else if (cur_max_pup > 4) {
+					/* 64 bit - 8 pups */
+					valid_pup = 0xFF;
+				} else if (cur_max_pup == 4) {
+					/* 32 bit - 4 pups */
+					valid_pup = 0xF;
+				} else {
+					/* 16 bit - 2 pups */
+					valid_pup = 0x3;
+				}
+
+				/* ECC Support - Switch ECC Mux on ecc=1 */
+				reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+					~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg |= (dram_info->ecc_ena * ecc <<
+					REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+				if (ecc)
+					DEBUG_PBS_FULL_S("DDR3 - PBS Rx - ECC Mux Enabled\n");
+				else
+					DEBUG_PBS_FULL_S("DDR3 - PBS Rx - ECC Mux Disabled\n");
+
+				/* Init iteration values */
+				/* Clear the locked DQs */
+				for (pup = 0; pup < cur_max_pup; pup++) {
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						pbs_locked_dq[
+							pup + ecc * (max_pup - 1)][dq] =
+							0;
+					}
+				}
+
+				pbs_rep_time = 0;
+				cur_pup = valid_pup;
+				start_over = 0;
+
+				/*
+				 * Run loop On current Pattern and current
+				 * pattern iteration (just to cover the false
+				 * fail problem
+				 */
+				do {
+					DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Pbs Rep Loop is ");
+					DEBUG_PBS_FULL_D(pbs_rep_time, 1);
+					DEBUG_PBS_FULL_S(", for Retry No.");
+					DEBUG_PBS_FULL_D(pbs_retry, 1);
+					DEBUG_PBS_FULL_S("\n");
+
+					/* Set all PBS values to MAX (31) */
+					for (pup = 0; pup < cur_max_pup; pup++) {
+						for (dq = 0; dq < DQ_NUM; dq++)
+							ddr3_write_pup_reg(
+								PUP_PBS_RX +
+								pbs_dq_mapping[
+								pup * (1 - ecc)
+								+ ecc * ECC_PUP]
+								[dq], CS0,
+								pup + ecc * ECC_PUP,
+								0, MAX_PBS);
+					}
+
+					/* Set all DQS PBS values to MIN (0) */
+					for (pup = 0; pup < cur_max_pup; pup++) {
+						ddr3_write_pup_reg(PUP_PBS_RX +
+								   DQ_NUM, CS0,
+								   pup +
+								   ecc *
+								   ECC_PUP, 0,
+								   0);
+					}
+
+					/* Shift DQS, To first Fail */
+					DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Shift RX DQS to first fail\n");
+
+					status = ddr3_rx_shift_dqs_to_first_fail
+						(dram_info, cur_pup,
+						 pattern_idx, ecc);
+					if (MV_OK != status) {
+						DEBUG_PBS_S("DDR3 - PBS Rx - ddr3_rx_shift_dqs_to_first_fail failed.\n");
+						DEBUG_PBS_D(status, 8);
+						DEBUG_PBS_S("\nDDR3 - PBS Rx - SKIP.\n");
+
+						/* Reset read FIFO */
+						reg = reg_read(REG_DRAM_TRAINING_ADDR);
+						/* Start Auto Read Leveling procedure */
+						reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+						/* 0x15B0 - Training Register */
+						reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+						reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+						reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS)
+							+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+						/* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset  */
+						/* 0x15B8 - Training SW 2 Register */
+						reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+						do {
+							reg = (reg_read(REG_DRAM_TRAINING_2_ADDR))
+								& (1 <<	REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+						} while (reg);	/* Wait for '0' */
+
+						reg = reg_read(REG_DRAM_TRAINING_ADDR);
+						/* Clear Auto Read Leveling procedure */
+						reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+						/* 0x15B0 - Training Register */
+						reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+						/* Set ADLL to 15 */
+						for (pup = 0; pup < max_pup;
+						     pup++) {
+							ddr3_write_pup_reg
+							    (PUP_DQS_RD, CS0,
+							     pup +
+							     (ecc * ECC_PUP), 0,
+							     15);
+						}
+
+						/* Set all PBS values to MIN (0) */
+						for (pup = 0; pup < cur_max_pup;
+						     pup++) {
+							for (dq = 0;
+							     dq < DQ_NUM; dq++)
+								ddr3_write_pup_reg
+								    (PUP_PBS_RX +
+								     pbs_dq_mapping
+								     [pup * (1 - ecc) +
+								      ecc * ECC_PUP]
+								     [dq], CS0,
+								     pup + ecc * ECC_PUP,
+								     0, MIN_PBS);
+						}
+
+						return MV_OK;
+					}
+
+					/* PBS For each bit */
+					DEBUG_PBS_FULL_S("DDR3 - PBS Rx - perform PBS for each bit\n");
+					/* in this stage - start_over = 0; */
+					if (MV_OK != ddr3_pbs_per_bit(
+						    dram_info, &start_over,
+						    0, &cur_pup,
+						    pattern_idx, ecc)) {
+						DEBUG_PBS_S("DDR3 - PBS Rx - ddr3_pbs_per_bit failed.");
+						return MV_DDR3_TRAINING_ERR_PBS_RX_PER_BIT;
+					}
+
+				} while ((start_over == 1) &&
+					 (++pbs_rep_time < COUNT_PBS_STARTOVER));
+
+				if (pbs_rep_time == COUNT_PBS_STARTOVER &&
+				    start_over == 1) {
+					DEBUG_PBS_FULL_S("DDR3 - PBS Rx - FAIL - Algorithm failed doing RX PBS\n");
+					return MV_DDR3_TRAINING_ERR_PBS_RX_MAX_VAL;
+				}
+
+				/* Return DQS ADLL to default value - 15 */
+				/* Set all DQS PBS values to MIN (0) */
+				for (pup = 0; pup < cur_max_pup; pup++)
+					ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+							   pup + ecc * ECC_PUP,
+							   0, INIT_RL_DELAY);
+
+				DEBUG_PBS_FULL_C("DDR3 - PBS RX - values for iteration - ",
+						 pbs_retry, 1);
+				for (pup = 0; pup < cur_max_pup; pup++) {
+					/*
+					 * To minimize delay elements, inc from
+					 * pbs value the min pbs val
+					 */
+					DEBUG_PBS_FULL_S("DDR3 - PBS - PUP");
+					DEBUG_PBS_FULL_D((pup +
+							  (ecc * ECC_PUP)), 1);
+					DEBUG_PBS_FULL_S(": ");
+
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						/* Set skew value for all dq */
+						/*
+						 * Bit# Deskew <- Bit# Deskew -
+						 * last / first  failing bit
+						 * Deskew For all bits (per PUP)
+						 * (minimize delay elements)
+						 */
+						DEBUG_PBS_FULL_S("DQ");
+						DEBUG_PBS_FULL_D(dq, 1);
+						DEBUG_PBS_FULL_S("-");
+						DEBUG_PBS_FULL_D(skew_array
+								 [((pup) *
+								   DQ_NUM) +
+								  dq], 2);
+						DEBUG_PBS_FULL_S(", ");
+					}
+					DEBUG_PBS_FULL_S("\n");
+				}
+
+				/*
+				 * Collect the results we got on this trial
+				 * of PBS
+				 */
+				for (pup = 0; pup < cur_max_pup; pup++) {
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						skew_sum_array
+							[pup + (ecc * (max_pup - 1))]
+							[dq] +=
+							skew_array[((pup) * DQ_NUM) + dq];
+					}
+				}
+
+				/* ECC Support - Disable ECC MUX */
+				reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+					~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+				reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+			}
+		}
+
+		/*
+		 * Calculate the average skew for current pattern for each
+		 * pup and each bit
+		 */
+		DEBUG_PBS_FULL_C("DDR3 - PBS RX - Average for pattern - ",
+				 pattern_idx, 1);
+		for (pup = 0; pup < max_pup; pup++) {
+			/*
+			 * FOR ECC only :: found min and max value for
+			 * current pattern skew array
+			 */
+			/* Loop for all dqs */
+			for (dq = 0; dq < DQ_NUM; dq++) {
+				pattern_skew_array[pup][dq] +=
+					(skew_sum_array[pup][dq] /
+					 COUNT_PBS_REPEAT);
+			}
+		}
+
+		DEBUG_PBS_C("DDR3 - PBS RX - values for current pattern - ",
+			    pattern_idx, 1);
+		for (pup = 0; pup < max_pup; pup++) {
+			/*
+			 * To minimize delay elements, inc from pbs value the
+			 * min pbs val
+			 */
+			DEBUG_PBS_S("DDR3 - PBS RX - PUP");
+			DEBUG_PBS_D(pup, 1);
+			DEBUG_PBS_S(": ");
+
+			for (dq = 0; dq < DQ_NUM; dq++) {
+				/* Set skew value for all dq */
+				/*
+				 * Bit# Deskew <- Bit# Deskew - last / first
+				 * failing bit Deskew For all bits (per PUP)
+				 * (minimize delay elements)
+				 */
+				DEBUG_PBS_S("DQ");
+				DEBUG_PBS_D(dq, 1);
+				DEBUG_PBS_S("-");
+				DEBUG_PBS_D(skew_sum_array[pup][dq] /
+					    COUNT_PBS_REPEAT, 2);
+				DEBUG_PBS_S(", ");
+			}
+			DEBUG_PBS_S("\n");
+		}
+	}
+
+	/* Calculate the average skew */
+	for (pup = 0; pup < max_pup; pup++) {
+		for (dq = 0; dq < DQ_NUM; dq++)
+			skew_array[((pup) * DQ_NUM) + dq] =
+				pattern_skew_array[pup][dq] / COUNT_PBS_PATTERN;
+	}
+
+	DEBUG_PBS_S("DDR3 - PBS RX - Average for all patterns:\n");
+	for (pup = 0; pup < max_pup; pup++) {
+		/*
+		 * To minimize delay elements, inc from pbs value the
+		 * min pbs val
+		 */
+		DEBUG_PBS_S("DDR3 - PBS - PUP");
+		DEBUG_PBS_D(pup, 1);
+		DEBUG_PBS_S(": ");
+
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			/* Set skew value for all dq */
+			/*
+			 * Bit# Deskew <- Bit# Deskew - last / first
+			 * failing bit Deskew For all bits (per PUP)
+			 * (minimize delay elements)
+			 */
+			DEBUG_PBS_S("DQ");
+			DEBUG_PBS_D(dq, 1);
+			DEBUG_PBS_S("-");
+			DEBUG_PBS_D(skew_array[(pup * DQ_NUM) + dq], 2);
+			DEBUG_PBS_S(", ");
+		}
+		DEBUG_PBS_S("\n");
+	}
+
+	/* Return ADLL to default value */
+	ddr3_write_pup_reg(PUP_DQS_RD, CS0, PUP_BC, 0, INIT_RL_DELAY);
+
+	/* Set averaged PBS results */
+	ddr3_set_pbs_results(dram_info, 0);
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+		(1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+	reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+	DEBUG_PBS_FULL_S("DDR3 - PBS RX - ended successfuly\n");
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_rx_shift_dqs_to_first_fail
+ * Desc:     Execute the Rx shift DQ phase.
+ * Args:     dram_info           ddr3 training information struct
+ *           cur_pup             bit array of the function active pups.
+ *           pbs_pattern_idx     Index of PBS pattern
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+static int ddr3_rx_shift_dqs_to_first_fail(MV_DRAM_INFO *dram_info, u32 cur_pup,
+					   u32 pbs_pattern_idx, u32 ecc)
+{
+	u32 unlock_pup;		/* bit array of unlock pups  */
+	u32 new_lockup_pup;	/* bit array of compare failed pups */
+	u32 adll_val = MAX_DELAY;
+	u32 dqs_deskew_val = 0;	/* current value of DQS PBS deskew */
+	u32 cur_max_pup, pup, pass_pup;
+	u32 *pattern_ptr;
+
+	/* Choose pattern */
+	switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+	case 16:
+		pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+		break;
+#endif
+	case 32:
+		pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+		break;
+#if defined(MV88F78X60)
+	case 64:
+		pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+		break;
+#endif
+	default:
+		return MV_FAIL;
+	}
+
+	/* Set current pup number */
+	if (cur_pup == 0x1)	/* Ecc mode */
+		cur_max_pup = 1;
+	else
+		cur_max_pup = dram_info->num_of_std_pups;
+
+	unlock_pup = cur_pup;	/* '1' for each unlocked pup */
+
+	DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Starting...\n");
+
+	/* Set DQS ADLL to MAX */
+	DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Set DQS ADLL to Max for all PUPs\n");
+	for (pup = 0; pup < cur_max_pup; pup++)
+		ddr3_write_pup_reg(PUP_DQS_RD, CS0, pup + ecc * ECC_PUP, 0,
+				   MAX_DELAY);
+
+	/* Loop on all ADLL Vaules */
+	do {
+		/* Loop until found fail for all pups */
+		new_lockup_pup = 0;
+		if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup,
+						&new_lockup_pup,
+						pattern_ptr, LEN_PBS_PATTERN,
+						SDRAM_PBS_I_OFFS +
+						pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS,
+						0, 0, NULL, 0)) {
+			DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP(ddr3_sdram_compare)\n");
+			return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+		}
+
+		if ((new_lockup_pup != 0) && (dqs_deskew_val <= 1)) {
+			/* Fail on start with first deskew value */
+			/* Decrement DQS ADLL */
+			--adll_val;
+			if (adll_val == ADLL_MIN) {
+				DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - fail on start with first deskew value\n");
+				return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+			}
+			ddr3_write_pup_reg(PUP_DQS_RD, CS0, pup + ecc * ECC_PUP,
+					   0, adll_val);
+			continue;
+		}
+
+		/* Update all new locked pups */
+		unlock_pup &= ~new_lockup_pup;
+
+		if ((unlock_pup == 0) || (dqs_deskew_val == MAX_PBS)) {
+			if (dqs_deskew_val == MAX_PBS) {
+				/*
+				 * Reach max value of dqs deskew or get fail
+				 * for all pups
+				 */
+				DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - DQS deskew reached maximum value\n");
+			}
+			break;
+		}
+
+		DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Inc DQS deskew for PUPs: ");
+		DEBUG_PBS_FULL_D(unlock_pup, 2);
+		DEBUG_PBS_FULL_C(", deskew = ", dqs_deskew_val, 2);
+
+		/* Increment DQS deskew elements - Only for unlocked pups */
+		dqs_deskew_val++;
+		for (pup = 0; pup < cur_max_pup; pup++) {
+			if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+				ddr3_write_pup_reg(PUP_PBS_RX + DQS_DQ_NUM, CS0,
+						   pup + ecc * ECC_PUP, 0,
+						   dqs_deskew_val);
+			}
+		}
+	} while (1);
+
+	DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - ADLL shift one step before fail\n");
+	/* Continue to ADLL shift one step before fail */
+	unlock_pup = cur_pup;
+	do {
+		/* Loop until pass compare for all pups */
+		new_lockup_pup = 0;
+		/* Read and compare results  */
+		if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup, &new_lockup_pup,
+						pattern_ptr, LEN_PBS_PATTERN,
+						SDRAM_PBS_I_OFFS +
+						pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS,
+						1, 0, NULL, 0)) {
+			DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP(ddr3_sdram_compare)\n");
+			return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+		}
+
+		/*
+		 * Get mask for pup which passed so their adll will be
+		 * changed to 2 steps before fails
+		 */
+		pass_pup = unlock_pup & ~new_lockup_pup;
+
+		DEBUG_PBS_FULL_S("Shift DQS by 2 steps for PUPs: ");
+		DEBUG_PBS_FULL_D(pass_pup, 2);
+		DEBUG_PBS_FULL_C(", Set ADLL value = ", (adll_val - 2), 2);
+
+		/* Only for pass pups   */
+		for (pup = 0; pup < cur_max_pup; pup++) {
+			if (IS_PUP_ACTIVE(pass_pup, pup) == 1) {
+				ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+						   pup + ecc * ECC_PUP, 0,
+						   (adll_val - 2));
+			}
+		}
+
+		/* Locked pups that compare success  */
+		unlock_pup &= new_lockup_pup;
+
+		if (unlock_pup == 0) {
+			/* All pups locked */
+			break;
+		}
+
+		/* Found error */
+		if (adll_val == 0) {
+			DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Shift DQS - Adll reach min value\n");
+			return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_MAX_VAL;
+		}
+
+		/*
+		 * Decrement (Move Back to Left one phase - ADLL) dqs RX delay
+		 */
+		adll_val--;
+		for (pup = 0; pup < cur_max_pup; pup++) {
+			if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+				ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+						   pup + ecc * ECC_PUP, 0,
+						   adll_val);
+			}
+		}
+	} while (1);
+
+	return MV_OK;
+}
+
+/*
+ * lock_pups() extracted from ddr3_pbs_per_bit(). This just got too
+ * much indented making it hard to read / edit.
+ */
+static void lock_pups(u32 pup, u32 *pup_locked, u8 *unlock_pup_dq_array,
+		      u32 pbs_curr_val, u32 start_pbs, u32 ecc, int is_tx)
+{
+	u32 dq;
+	int idx;
+
+	/* Lock PBS value for all remaining PUPs bits */
+	DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Lock PBS value for all remaining PUPs bits, pup ");
+	DEBUG_PBS_FULL_D(pup, 1);
+	DEBUG_PBS_FULL_C(" pbs value ", pbs_curr_val, 2);
+
+	idx = pup * (1 - ecc) + ecc * ECC_PUP;
+	*pup_locked &= ~(1 << pup);
+
+	for (dq = 0; dq < DQ_NUM; dq++) {
+		if (IS_PUP_ACTIVE(unlock_pup_dq_array[dq], pup) == 1) {
+			int offs;
+
+			/* Lock current dq */
+			unlock_pup_dq_array[dq] &= ~(1 << pup);
+			skew_array[(pup * DQ_NUM) + dq] = pbs_curr_val;
+
+			if (is_tx == 1)
+				offs = PUP_PBS_TX;
+			else
+				offs = PUP_PBS_RX;
+
+			ddr3_write_pup_reg(offs +
+					   pbs_dq_mapping[idx][dq], CS0,
+					   idx, 0, start_pbs);
+		}
+	}
+}
+
+/*
+ * Name:     ddr3_pbs_per_bit
+ * Desc:     Execute the Per Bit Skew phase.
+ * Args:     start_over      Return whether need to start over the algorithm
+ *           is_tx           Indicate whether Rx or Tx
+ *           pcur_pup        bit array of the function active pups. return the
+ *                           pups that need to repeat on the PBS
+ *           pbs_pattern_idx Index of PBS pattern
+ *
+ * Notes:    Current implementation supports double activation of this function.
+ *           i.e. in order to activate this function (using start_over) more than
+ *           twice, the implementation should change.
+ *           imlementation limitation are marked using
+ *           ' CHIP-ONLY! - Implementation Limitation '
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+static int ddr3_pbs_per_bit(MV_DRAM_INFO *dram_info, int *start_over, int is_tx,
+			    u32 *pcur_pup, u32 pbs_pattern_idx, u32 ecc)
+{
+	/*
+	 * Bit array to indicate if we already get fail on bit per pup & dq bit
+	 */
+	u8 unlock_pup_dq_array[DQ_NUM] = {
+		*pcur_pup, *pcur_pup, *pcur_pup, *pcur_pup, *pcur_pup,
+		*pcur_pup, *pcur_pup, *pcur_pup
+	};
+
+	u8 cmp_unlock_pup_dq_array[COUNT_PBS_COMP_RETRY_NUM][DQ_NUM];
+	u32 pup, dq;
+	/* value of pbs is according to RX or TX */
+	u32 start_pbs, last_pbs;
+	u32 pbs_curr_val;
+	/* bit array that indicates all dq of the pup locked */
+	u32 pup_locked;
+	u32 first_fail[MAX_PUP_NUM] = { 0 };	/* count first fail per pup */
+	/* indicates whether we get first fail per pup */
+	int first_failed[MAX_PUP_NUM] = { 0 };
+	/* bit array that indicates pup already get fail */
+	u32 sum_pup_fail;
+	/* use to calculate diff between curr pbs to first fail pbs */
+	u32 calc_pbs_diff;
+	u32 pbs_cmp_retry;
+	u32 max_pup;
+
+	/* Set init values for retry array - 8 retry */
+	for (pbs_cmp_retry = 0; pbs_cmp_retry < COUNT_PBS_COMP_RETRY_NUM;
+	     pbs_cmp_retry++) {
+		for (dq = 0; dq < DQ_NUM; dq++)
+			cmp_unlock_pup_dq_array[pbs_cmp_retry][dq] = *pcur_pup;
+	}
+
+	memset(&skew_array, 0, MAX_PUP_NUM * DQ_NUM * sizeof(u32));
+
+	DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Started\n");
+
+	/* The pbs value depends if rx or tx */
+	if (is_tx == 1) {
+		start_pbs = MIN_PBS;
+		last_pbs = MAX_PBS;
+	} else {
+		start_pbs = MAX_PBS;
+		last_pbs = MIN_PBS;
+	}
+
+	pbs_curr_val = start_pbs;
+	pup_locked = *pcur_pup;
+
+	/* Set current pup number */
+	if (pup_locked == 0x1)	/* Ecc mode */
+		max_pup = 1;
+	else
+		max_pup = dram_info->num_of_std_pups;
+
+	do {
+		/* Increment/ decrement PBS for un-lock bits only */
+		if (is_tx == 1)
+			pbs_curr_val++;
+		else
+			pbs_curr_val--;
+
+		/* Set Current PBS delay  */
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			/* Check DQ bits to see if locked in all pups */
+			if (unlock_pup_dq_array[dq] == 0) {
+				DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - All pups are locked for DQ ");
+				DEBUG_PBS_FULL_D(dq, 1);
+				DEBUG_PBS_FULL_S("\n");
+				continue;
+			}
+
+			for (pup = 0; pup < max_pup; pup++) {
+				int idx;
+
+				idx = pup * (1 - ecc) + ecc * ECC_PUP;
+
+				if (IS_PUP_ACTIVE(unlock_pup_dq_array[dq], pup)
+				    == 0)
+					continue;
+
+				if (is_tx == 1)
+					ddr3_write_pup_reg(
+						PUP_PBS_TX + pbs_dq_mapping[idx][dq],
+						CS0, idx, 0, pbs_curr_val);
+				else
+					ddr3_write_pup_reg(
+						PUP_PBS_RX + pbs_dq_mapping[idx][dq],
+						CS0, idx, 0, pbs_curr_val);
+			}
+		}
+
+		/*
+		 * Write Read and compare results - run the test
+		 * DDR_PBS_COMP_RETRY_NUM times
+		 */
+		/* Run number of read and write to verify */
+		for (pbs_cmp_retry = 0;
+		     pbs_cmp_retry < COUNT_PBS_COMP_RETRY_NUM;
+		     pbs_cmp_retry++) {
+
+			if (MV_OK !=
+			    ddr3_sdram_pbs_compare(dram_info, pup_locked, is_tx,
+						   pbs_pattern_idx,
+						   pbs_curr_val, start_pbs,
+						   skew_array,
+						   cmp_unlock_pup_dq_array
+						   [pbs_cmp_retry], ecc))
+				return MV_FAIL;
+
+			for (pup = 0; pup < max_pup; pup++) {
+				for (dq = 0; dq < DQ_NUM; dq++) {
+					if ((IS_PUP_ACTIVE(unlock_pup_dq_array[dq],
+							   pup) == 1)
+					    && (IS_PUP_ACTIVE(cmp_unlock_pup_dq_array
+					      [pbs_cmp_retry][dq],
+					      pup) == 0)) {
+						DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - PbsCurrVal: ");
+						DEBUG_PBS_FULL_D(pbs_curr_val, 2);
+						DEBUG_PBS_FULL_S(" PUP: ");
+						DEBUG_PBS_FULL_D(pup, 1);
+						DEBUG_PBS_FULL_S(" DQ: ");
+						DEBUG_PBS_FULL_D(dq, 1);
+						DEBUG_PBS_FULL_S(" - failed\n");
+					}
+				}
+			}
+
+			for (dq = 0; dq < DQ_NUM; dq++) {
+				unlock_pup_dq_array[dq] &=
+				    cmp_unlock_pup_dq_array[pbs_cmp_retry][dq];
+			}
+		}
+
+		pup_locked = 0;
+		sum_pup_fail = *pcur_pup;
+
+		/* Check which DQ is failed */
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			/* Summarize the locked pup */
+			pup_locked |= unlock_pup_dq_array[dq];
+
+			/* Check if get fail */
+			sum_pup_fail &= unlock_pup_dq_array[dq];
+		}
+
+		/* If all PUPS are locked in all DQ - Break */
+		if (pup_locked == 0) {
+			/* All pups are locked */
+			*start_over = 0;
+			DEBUG_PBS_FULL_S("DDR3 - PBS Per bit -  All bit in all pups are successfully locked\n");
+			break;
+		}
+
+		/* PBS deskew elements reach max ? */
+		if (pbs_curr_val == last_pbs) {
+			DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - PBS deskew elements reach max\n");
+			/* CHIP-ONLY! - Implementation Limitation */
+			*start_over = (sum_pup_fail != 0) && (!(*start_over));
+			*pcur_pup = pup_locked;
+
+			DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - StartOver: ");
+			DEBUG_PBS_FULL_D(*start_over, 1);
+			DEBUG_PBS_FULL_S("  pup_locked: ");
+			DEBUG_PBS_FULL_D(pup_locked, 2);
+			DEBUG_PBS_FULL_S("  sum_pup_fail: ");
+			DEBUG_PBS_FULL_D(sum_pup_fail, 2);
+			DEBUG_PBS_FULL_S("\n");
+
+			/* Lock PBS value for all remaining  bits */
+			for (pup = 0; pup < max_pup; pup++) {
+				/* Check if current pup already received error */
+				if (IS_PUP_ACTIVE(pup_locked, pup) == 1) {
+					/* Valid pup for current function */
+					if (IS_PUP_ACTIVE(sum_pup_fail, pup) ==
+					    1 && (*start_over == 1)) {
+						DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - skipping lock of pup (first loop of pbs)",
+								 pup, 1);
+						continue;
+					} else
+					    if (IS_PUP_ACTIVE(sum_pup_fail, pup)
+						== 1) {
+						DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - Locking pup %d (even though it wasn't supposed to be locked)",
+								 pup, 1);
+					}
+
+					/* Already got fail on the PUP */
+					/* Lock PBS value for all remaining bits */
+					DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Locking remaning DQs for pup - ");
+					DEBUG_PBS_FULL_D(pup, 1);
+					DEBUG_PBS_FULL_S(": ");
+
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						if (IS_PUP_ACTIVE
+						    (unlock_pup_dq_array[dq],
+						     pup) == 1) {
+							DEBUG_PBS_FULL_D(dq, 1);
+							DEBUG_PBS_FULL_S(",");
+							/* set current PBS */
+							skew_array[((pup) *
+								    DQ_NUM) +
+								   dq] =
+							    pbs_curr_val;
+						}
+					}
+
+					if (*start_over == 1) {
+						/*
+						 * Reset this pup bit - when
+						 * restart the PBS, ignore this
+						 * pup
+						 */
+						*pcur_pup &= ~(1 << pup);
+					}
+					DEBUG_PBS_FULL_S("\n");
+				} else {
+					DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Pup ");
+					DEBUG_PBS_FULL_D(pup, 1);
+					DEBUG_PBS_FULL_C(" is not set in puplocked - ",
+							 pup_locked, 1);
+				}
+			}
+
+			/* Need to start the PBS again */
+			if (*start_over == 1) {
+				DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - false fail - returning to start\n");
+				return MV_OK;
+			}
+			break;
+		}
+
+		/* Diff Check */
+		for (pup = 0; pup < max_pup; pup++) {
+			if (IS_PUP_ACTIVE(pup_locked, pup) == 1) {
+				/* pup is not locked */
+				if (first_failed[pup] == 0) {
+					/* No first fail until now */
+					if (IS_PUP_ACTIVE(sum_pup_fail, pup) ==
+					    0) {
+						/* Get first fail */
+						DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - First fail in pup ",
+								 pup, 1);
+						first_failed[pup] = 1;
+						first_fail[pup] = pbs_curr_val;
+					}
+				} else {
+					/* Already got first fail */
+					if (is_tx == 1) {
+						/* TX - inc pbs */
+						calc_pbs_diff =	pbs_curr_val -
+							first_fail[pup];
+					} else {
+						/* RX - dec pbs */
+						calc_pbs_diff = first_fail[pup] -
+							pbs_curr_val;
+					}
+
+					if (calc_pbs_diff >= PBS_DIFF_LIMIT) {
+						lock_pups(pup, &pup_locked,
+							  unlock_pup_dq_array,
+							  pbs_curr_val,
+							  start_pbs, ecc, is_tx);
+					}
+				}
+			}
+		}
+	} while (1);
+
+	return MV_OK;
+}
+
+/*
+ * Name:         ddr3_set_pbs_results
+ * Desc:         Set to HW the PBS phase results.
+ * Args:         is_tx       Indicates whether to set Tx or RX results
+ * Notes:
+ * Returns:      MV_OK if success, other error code if fail.
+ */
+static int ddr3_set_pbs_results(MV_DRAM_INFO *dram_info, int is_tx)
+{
+	u32 pup, phys_pup, dq;
+	u32 max_pup;		/* number of valid pups */
+	u32 pbs_min;		/* minimal pbs val per pup */
+	u32 pbs_max;		/* maximum pbs val per pup */
+	u32 val[9];
+
+	max_pup = dram_info->num_of_total_pups;
+	DEBUG_PBS_FULL_S("DDR3 - PBS - ddr3_set_pbs_results:\n");
+
+	/* Loop for all dqs & pups */
+	for (pup = 0; pup < max_pup; pup++) {
+		if (pup == (max_pup - 1) && dram_info->ecc_ena)
+			phys_pup = ECC_PUP;
+		else
+			phys_pup = pup;
+
+		/*
+		 * To minimize delay elements, inc from pbs value the min
+		 * pbs val
+		 */
+		pbs_min = MAX_PBS;
+		pbs_max = 0;
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			if (pbs_min > skew_array[(pup * DQ_NUM) + dq])
+				pbs_min = skew_array[(pup * DQ_NUM) + dq];
+
+			if (pbs_max < skew_array[(pup * DQ_NUM) + dq])
+				pbs_max = skew_array[(pup * DQ_NUM) + dq];
+		}
+
+		pbs_max -= pbs_min;
+
+		DEBUG_PBS_FULL_S("DDR3 - PBS - PUP");
+		DEBUG_PBS_FULL_D(phys_pup, 1);
+		DEBUG_PBS_FULL_S(": Min Val = ");
+		DEBUG_PBS_FULL_D(pbs_min, 2);
+		DEBUG_PBS_FULL_C(", Max Val = ", pbs_max, 2);
+
+		val[pup] = 0;
+
+		for (dq = 0; dq < DQ_NUM; dq++) {
+			int idx;
+			int offs;
+
+			/* Set skew value for all dq */
+			/*
+			 * Bit# Deskew <- Bit# Deskew - last / first
+			 * failing bit Deskew For all bits (per PUP)
+			 * (minimize delay elements)
+			 */
+
+			DEBUG_PBS_FULL_S("DQ");
+			DEBUG_PBS_FULL_D(dq, 1);
+			DEBUG_PBS_FULL_S("-");
+			DEBUG_PBS_FULL_D((skew_array[(pup * DQ_NUM) + dq] -
+					  pbs_min), 2);
+			DEBUG_PBS_FULL_S(", ");
+
+			idx = (pup * DQ_NUM) + dq;
+
+			if (is_tx == 1)
+				offs = PUP_PBS_TX;
+			else
+				offs = PUP_PBS_RX;
+
+			ddr3_write_pup_reg(offs + pbs_dq_mapping[phys_pup][dq],
+					   CS0, phys_pup, 0,
+					   skew_array[idx] - pbs_min);
+
+			if (is_tx == 1)
+				val[pup] += skew_array[idx] - pbs_min;
+		}
+
+		DEBUG_PBS_FULL_S("\n");
+
+		/* Set the DQS the half of the Max PBS of the DQs  */
+		if (is_tx == 1) {
+			ddr3_write_pup_reg(PUP_PBS_TX + 8, CS0, phys_pup, 0,
+					   pbs_max / 2);
+			ddr3_write_pup_reg(PUP_PBS_TX + 0xa, CS0, phys_pup, 0,
+					   val[pup] / 8);
+		} else
+			ddr3_write_pup_reg(PUP_PBS_RX + 8, CS0, phys_pup, 0,
+					   pbs_max / 2);
+	}
+
+	return MV_OK;
+}
+
+static void ddr3_pbs_write_pup_dqs_reg(u32 cs, u32 pup, u32 dqs_delay)
+{
+	u32 reg, delay;
+
+	reg = (ddr3_read_pup_reg(PUP_WL_MODE, cs, pup) & 0x3FF);
+	delay = reg & PUP_DELAY_MASK;
+	reg |= ((dqs_delay + delay) << REG_PHY_DQS_REF_DLY_OFFS);
+	reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+	reg |= (pup << REG_PHY_PUP_OFFS);
+	reg |= ((0x4 * cs + PUP_WL_MODE) << REG_PHY_CS_OFFS);
+
+	reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg);	/* 0x16A0 */
+	do {
+		reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+			REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+	} while (reg);	/* Wait for '0' to mark the end of the transaction */
+
+	udelay(10);
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_pbs_patterns(MV_DRAM_INFO *dram_info)
+{
+	u32 cs, cs_count, cs_tmp;
+	u32 sdram_addr;
+	u32 *pattern_ptr0, *pattern_ptr1;
+
+	/* Choose pattern */
+	switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+	case 16:
+		pattern_ptr0 = (u32 *)&pbs_pattern[0];
+		pattern_ptr1 = (u32 *)&pbs_pattern[1];
+		break;
+#endif
+	case 32:
+		pattern_ptr0 = (u32 *)&pbs_pattern_32b[0];
+		pattern_ptr1 = (u32 *)&pbs_pattern_32b[1];
+		break;
+#if defined(MV88F78X60)
+	case 64:
+		pattern_ptr0 = (u32 *)&pbs_pattern_64b[0];
+		pattern_ptr1 = (u32 *)&pbs_pattern_64b[1];
+		break;
+#endif
+	default:
+		return MV_FAIL;
+	}
+
+	/* Loop for each CS */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			cs_count = 0;
+			for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+				if (dram_info->cs_ena & (1 << cs_tmp))
+					cs_count++;
+			}
+
+			/* Init PBS I pattern */
+			sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+				      SDRAM_PBS_I_OFFS);
+			if (MV_OK !=
+			    ddr3_sdram_compare(dram_info, (u32) NULL, NULL,
+					       pattern_ptr0, LEN_STD_PATTERN,
+					       sdram_addr, 1, 0, NULL,
+					       0))
+				return MV_FAIL;
+
+			/* Init PBS II pattern */
+			sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+				      SDRAM_PBS_II_OFFS);
+			if (MV_OK !=
+			    ddr3_sdram_compare(dram_info, (u32) NULL, NULL,
+					       pattern_ptr1, LEN_STD_PATTERN,
+					       sdram_addr, 1, 0, NULL,
+					       0))
+				return MV_FAIL;
+		}
+	}
+
+	return MV_OK;
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_read_leveling.c b/drivers/ddr/mvebu/ddr3_read_leveling.c
new file mode 100644
index 0000000..4662bde
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_read_leveling.c
@@ -0,0 +1,1214 @@
+/*
+ * 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_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_RL_C(s, d, l) \
+	DEBUG_RL_S(s); DEBUG_RL_D(d, l); DEBUG_RL_S("\n")
+#define DEBUG_RL_FULL_C(s, d, l) \
+	DEBUG_RL_FULL_S(s); DEBUG_RL_FULL_D(d, l); DEBUG_RL_FULL_S("\n")
+
+#ifdef MV_DEBUG_RL
+#define DEBUG_RL_S(s) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_RL_D(d, l) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+#else
+#define DEBUG_RL_S(s)
+#define DEBUG_RL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_RL_FULL
+#define DEBUG_RL_FULL_S(s)		puts(s)
+#define DEBUG_RL_FULL_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_RL_FULL_S(s)
+#define DEBUG_RL_FULL_D(d, l)
+#endif
+
+extern u32 rl_pattern[LEN_STD_PATTERN];
+
+#ifdef RL_MODE
+static int ddr3_read_leveling_single_cs_rl_mode(u32 cs, u32 freq,
+						int ratio_2to1, u32 ecc,
+						MV_DRAM_INFO *dram_info);
+#else
+static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
+						    int ratio_2to1, u32 ecc,
+						    MV_DRAM_INFO *dram_info);
+#endif
+
+/*
+ * Name:     ddr3_read_leveling_hw
+ * Desc:     Execute the Read leveling phase by HW
+ * Args:     dram_info - main struct
+ *           freq      - current sequence frequency
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_read_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info)
+{
+	u32 reg;
+
+	/* Debug message - Start Read leveling procedure */
+	DEBUG_RL_S("DDR3 - Read Leveling - Starting HW RL procedure\n");
+
+	/* Start Auto Read Leveling procedure */
+	reg = 1 << REG_DRAM_TRAINING_RL_OFFS;
+	/* Config the retest number */
+	reg |= (COUNT_HW_RL << REG_DRAM_TRAINING_RETEST_OFFS);
+
+	/* Enable CS in the automatic process */
+	reg |= (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS);
+
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+		(1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+	/* Wait */
+	do {
+		reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+			(1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	} while (reg);		/* Wait for '0' */
+
+	/* Check if Successful */
+	if (reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+	    (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+		u32 delay, phase, pup, cs;
+
+		dram_info->rl_max_phase = 0;
+		dram_info->rl_min_phase = 10;
+
+		/* Read results to arrays */
+		for (cs = 0; cs < MAX_CS; cs++) {
+			if (dram_info->cs_ena & (1 << cs)) {
+				for (pup = 0;
+				     pup < dram_info->num_of_total_pups;
+				     pup++) {
+					if (pup == dram_info->num_of_std_pups
+					    && dram_info->ecc_ena)
+						pup = ECC_PUP;
+					reg =
+					    ddr3_read_pup_reg(PUP_RL_MODE, cs,
+							      pup);
+					phase = (reg >> REG_PHY_PHASE_OFFS) &
+						PUP_PHASE_MASK;
+					delay = reg & PUP_DELAY_MASK;
+					dram_info->rl_val[cs][pup][P] = phase;
+					if (phase > dram_info->rl_max_phase)
+						dram_info->rl_max_phase = phase;
+					if (phase < dram_info->rl_min_phase)
+						dram_info->rl_min_phase = phase;
+					dram_info->rl_val[cs][pup][D] = delay;
+					dram_info->rl_val[cs][pup][S] =
+					    RL_FINAL_STATE;
+					reg =
+					    ddr3_read_pup_reg(PUP_RL_MODE + 0x1,
+							      cs, pup);
+					dram_info->rl_val[cs][pup][DQS] =
+					    (reg & 0x3F);
+				}
+#ifdef MV_DEBUG_RL
+				/* Print results */
+				DEBUG_RL_C("DDR3 - Read Leveling - Results for CS - ",
+					   (u32) cs, 1);
+
+				for (pup = 0;
+				     pup < (dram_info->num_of_total_pups);
+				     pup++) {
+					if (pup == dram_info->num_of_std_pups
+					    && dram_info->ecc_ena)
+						pup = ECC_PUP;
+					DEBUG_RL_S("DDR3 - Read Leveling - PUP: ");
+					DEBUG_RL_D((u32) pup, 1);
+					DEBUG_RL_S(", Phase: ");
+					DEBUG_RL_D((u32) dram_info->
+						   rl_val[cs][pup][P], 1);
+					DEBUG_RL_S(", Delay: ");
+					DEBUG_RL_D((u32) dram_info->
+						   rl_val[cs][pup][D], 2);
+					DEBUG_RL_S("\n");
+				}
+#endif
+			}
+		}
+
+		dram_info->rd_rdy_dly =
+			reg_read(REG_READ_DATA_READY_DELAYS_ADDR) &
+			REG_READ_DATA_SAMPLE_DELAYS_MASK;
+		dram_info->rd_smpl_dly =
+			reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR) &
+			REG_READ_DATA_READY_DELAYS_MASK;
+#ifdef MV_DEBUG_RL
+		DEBUG_RL_C("DDR3 - Read Leveling - Read Sample Delay: ",
+			   dram_info->rd_smpl_dly, 2);
+		DEBUG_RL_C("DDR3 - Read Leveling - Read Ready Delay: ",
+			   dram_info->rd_rdy_dly, 2);
+		DEBUG_RL_S("DDR3 - Read Leveling - HW RL Ended Successfully\n");
+#endif
+		return MV_OK;
+
+	} else {
+		DEBUG_RL_S("DDR3 - Read Leveling - HW RL Error\n");
+		return MV_FAIL;
+	}
+}
+
+/*
+ * Name:     ddr3_read_leveling_sw
+ * Desc:     Execute the Read leveling phase by SW
+ * Args:     dram_info - main struct
+ *           freq      - current sequence frequency
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_read_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+	u32 reg, cs, ecc, pup_num, phase, delay, pup;
+	int status;
+
+	/* Debug message - Start Read leveling procedure */
+	DEBUG_RL_S("DDR3 - Read Leveling - Starting SW RL procedure\n");
+
+	/* Enable SW Read Leveling */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_RL_MODE_OFFS);
+	/* [0]=1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+#ifdef RL_MODE
+	reg = (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS) |
+		(1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+#endif
+
+	/* Loop for each CS */
+	for (cs = 0; cs < dram_info->num_cs; cs++) {
+		DEBUG_RL_C("DDR3 - Read Leveling - CS - ", (u32) cs, 1);
+
+		for (ecc = 0; ecc <= (dram_info->ecc_ena); ecc++) {
+			/* ECC Support - Switch ECC Mux on ecc=1 */
+			reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+				~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+			reg |= (dram_info->ecc_ena *
+				ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+			reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+			if (ecc)
+				DEBUG_RL_S("DDR3 - Read Leveling - ECC Mux Enabled\n");
+			else
+				DEBUG_RL_S("DDR3 - Read Leveling - ECC Mux Disabled\n");
+
+			/* Set current sample delays */
+			reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+			reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+				 (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+			reg |= (dram_info->cl <<
+				(REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+			reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+			/* Set current Ready delay */
+			reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+			reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+				 (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+			if (!ratio_2to1) {
+				/* 1:1 mode */
+				reg |= ((dram_info->cl + 1) <<
+					(REG_READ_DATA_READY_DELAYS_OFFS * cs));
+			} else {
+				/* 2:1 mode */
+				reg |= ((dram_info->cl + 2) <<
+					(REG_READ_DATA_READY_DELAYS_OFFS * cs));
+			}
+			reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+
+			/* Read leveling Single CS[cs] */
+#ifdef RL_MODE
+			status =
+			    ddr3_read_leveling_single_cs_rl_mode(cs, freq,
+								 ratio_2to1,
+								 ecc,
+								 dram_info);
+			if (MV_OK != status)
+				return status;
+#else
+			status =
+			    ddr3_read_leveling_single_cs_window_mode(cs, freq,
+								     ratio_2to1,
+								     ecc,
+								     dram_info)
+			    if (MV_OK != status)
+				return status;
+#endif
+		}
+
+		/* Print results */
+		DEBUG_RL_C("DDR3 - Read Leveling - Results for CS - ", (u32) cs,
+			   1);
+
+		for (pup = 0;
+		     pup < (dram_info->num_of_std_pups + dram_info->ecc_ena);
+		     pup++) {
+			DEBUG_RL_S("DDR3 - Read Leveling - PUP: ");
+			DEBUG_RL_D((u32) pup, 1);
+			DEBUG_RL_S(", Phase: ");
+			DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][P], 1);
+			DEBUG_RL_S(", Delay: ");
+			DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][D], 2);
+			DEBUG_RL_S("\n");
+		}
+
+		DEBUG_RL_C("DDR3 - Read Leveling - Read Sample Delay: ",
+			   dram_info->rd_smpl_dly, 2);
+		DEBUG_RL_C("DDR3 - Read Leveling - Read Ready Delay: ",
+			   dram_info->rd_rdy_dly, 2);
+
+		/* Configure PHY with average of 3 locked leveling settings */
+		for (pup = 0;
+		     pup < (dram_info->num_of_std_pups + dram_info->ecc_ena);
+		     pup++) {
+			/* ECC support - bit 8 */
+			pup_num = (pup == dram_info->num_of_std_pups) ? ECC_BIT : pup;
+
+			/* For now, set last cnt result */
+			phase = dram_info->rl_val[cs][pup][P];
+			delay = dram_info->rl_val[cs][pup][D];
+			ddr3_write_pup_reg(PUP_RL_MODE, cs, pup_num, phase,
+					   delay);
+		}
+	}
+
+	/* Reset PHY read FIFO */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	do {
+		reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+			(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+	} while (reg);		/* Wait for '0' */
+
+	/* ECC Support - Switch ECC Mux off ecc=0 */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+		~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+#ifdef RL_MODE
+	reg_write(REG_DRAM_TRAINING_ADDR, 0);	/* 0x15B0 - Training Register */
+#endif
+
+	/* Disable SW Read Leveling */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+		~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* [0] = 0 - Disable SW override  */
+	reg = (reg | (0x1 << REG_DRAM_TRAINING_2_RL_MODE_OFFS));
+	/* [3] = 1 - Disable RL MODE */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	DEBUG_RL_S("DDR3 - Read Leveling - Finished RL procedure for all CS\n");
+	return MV_OK;
+}
+
+#ifdef RL_MODE
+/*
+ * overrun() extracted from ddr3_read_leveling_single_cs_rl_mode().
+ * This just got too much indented making it hard to read / edit.
+ */
+static void overrun(u32 cs, MV_DRAM_INFO *info, u32 pup, u32 locked_pups,
+		    u32 *locked_sum, u32 ecc, int *first_octet_locked,
+		    int *counter_in_progress, int final_delay, u32 delay,
+		    u32 phase)
+{
+	/* If no OverRun */
+	if (((~locked_pups >> pup) & 0x1) && (final_delay == 0)) {
+		int idx;
+
+		idx = pup + ecc * ECC_BIT;
+
+		/* PUP passed, start examining */
+		if (info->rl_val[cs][idx][S] == RL_UNLOCK_STATE) {
+			/* Must be RL_UNLOCK_STATE */
+			/* Match expected value ? - Update State Machine */
+			if (info->rl_val[cs][idx][C] < RL_RETRY_COUNT) {
+				DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have no overrun and a match on pup: ",
+						(u32)pup, 1);
+				info->rl_val[cs][idx][C]++;
+
+				/* If pup got to last state - lock the delays */
+				if (info->rl_val[cs][idx][C] == RL_RETRY_COUNT) {
+					info->rl_val[cs][idx][C] = 0;
+					info->rl_val[cs][idx][DS] = delay;
+					info->rl_val[cs][idx][PS] = phase;
+
+					/* Go to Final State */
+					info->rl_val[cs][idx][S] = RL_FINAL_STATE;
+					*locked_sum = *locked_sum + 1;
+					DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have locked pup: ",
+							(u32)pup, 1);
+
+					/*
+					 * If first lock - need to lock delays
+					 */
+					if (*first_octet_locked == 0) {
+						DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got first lock on pup: ",
+								(u32)pup, 1);
+						*first_octet_locked = 1;
+					}
+
+					/*
+					 * If pup is in not in final state but
+					 * there was match - dont increment
+					 * counter
+					 */
+				} else {
+					*counter_in_progress = 1;
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Name:     ddr3_read_leveling_single_cs_rl_mode
+ * Desc:     Execute Read leveling for single Chip select
+ * Args:     cs        - current chip select
+ *           freq      - current sequence frequency
+ *           ecc       - ecc iteration indication
+ *           dram_info - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_read_leveling_single_cs_rl_mode(u32 cs, u32 freq,
+						int ratio_2to1, u32 ecc,
+						MV_DRAM_INFO *dram_info)
+{
+	u32 reg, delay, phase, pup, rd_sample_delay, add, locked_pups,
+		repeat_max_cnt, sdram_offset, locked_sum;
+	u32 phase_min, ui_max_delay;
+	int all_locked, first_octet_locked, counter_in_progress;
+	int final_delay = 0;
+
+	DEBUG_RL_FULL_C("DDR3 - Read Leveling - Single CS - ", (u32) cs, 1);
+
+	/* Init values */
+	phase = 0;
+	delay = 0;
+	rd_sample_delay = dram_info->cl;
+	all_locked = 0;
+	first_octet_locked = 0;
+	repeat_max_cnt = 0;
+	locked_sum = 0;
+
+	for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+	     pup++)
+		dram_info->rl_val[cs][pup + ecc * ECC_BIT][S] = 0;
+
+	/* Main loop */
+	while (!all_locked) {
+		counter_in_progress = 0;
+
+		DEBUG_RL_FULL_S("DDR3 - Read Leveling - RdSmplDly = ");
+		DEBUG_RL_FULL_D(rd_sample_delay, 2);
+		DEBUG_RL_FULL_S(", RdRdyDly = ");
+		DEBUG_RL_FULL_D(dram_info->rd_rdy_dly, 2);
+		DEBUG_RL_FULL_S(", Phase = ");
+		DEBUG_RL_FULL_D(phase, 1);
+		DEBUG_RL_FULL_S(", Delay = ");
+		DEBUG_RL_FULL_D(delay, 2);
+		DEBUG_RL_FULL_S("\n");
+
+		/*
+		 * Broadcast to all PUPs current RL delays: DQS phase,
+		 * leveling delay
+		 */
+		ddr3_write_pup_reg(PUP_RL_MODE, cs, PUP_BC, phase, delay);
+
+		/* Reset PHY read FIFO */
+		reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+			(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+		/* 0x15B8 - Training SW 2 Register */
+		reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+		do {
+			reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+				(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+		} while (reg);	/* Wait for '0' */
+
+		/* Read pattern from SDRAM */
+		sdram_offset = cs * (SDRAM_CS_SIZE + 1) + SDRAM_RL_OFFS;
+		locked_pups = 0;
+		if (MV_OK !=
+		    ddr3_sdram_compare(dram_info, 0xFF, &locked_pups,
+				       rl_pattern, LEN_STD_PATTERN,
+				       sdram_offset, 0, 0, NULL, 0))
+			return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PATTERN;
+
+		/* Octet evaluation */
+		/* pup_num = Q or 1 for ECC */
+		for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+			/* Check Overrun */
+			if (!((reg_read(REG_DRAM_TRAINING_2_ADDR) >>
+			       (REG_DRAM_TRAINING_2_OVERRUN_OFFS + pup)) & 0x1)) {
+				overrun(cs, dram_info, pup, locked_pups,
+					&locked_sum, ecc, &first_octet_locked,
+					&counter_in_progress, final_delay,
+					delay, phase);
+			} else {
+				DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got overrun on pup: ",
+						(u32)pup, 1);
+			}
+		}
+
+		if (locked_sum == (dram_info->num_of_std_pups *
+				   (1 - ecc) + ecc)) {
+			all_locked = 1;
+			DEBUG_RL_FULL_S("DDR3 - Read Leveling - Single Cs - All pups locked\n");
+		}
+
+		/*
+		 * This is a fix for unstable condition where pups are
+		 * toggling between match and no match
+		 */
+		/*
+		 * If some of the pups is >1 <3, check if we did it too
+		 * many times
+		 */
+		if (counter_in_progress == 1) {
+			/* Notify at least one Counter is >=1 and < 3 */
+			if (repeat_max_cnt < RL_RETRY_COUNT) {
+				repeat_max_cnt++;
+				counter_in_progress = 1;
+				DEBUG_RL_FULL_S("DDR3 - Read Leveling - Counter is >=1 and <3\n");
+				DEBUG_RL_FULL_S("DDR3 - Read Leveling - So we will not increment the delay to see if locked again\n");
+			} else {
+				DEBUG_RL_FULL_S("DDR3 - Read Leveling - repeat_max_cnt reached max so now we will increment the delay\n");
+				counter_in_progress = 0;
+			}
+		}
+
+		/*
+		 * Check some of the pups are in the middle of state machine
+		 * and don't increment the delays
+		 */
+		if (!counter_in_progress && !all_locked) {
+			int idx;
+
+			idx = pup + ecc * ECC_BIT;
+
+			repeat_max_cnt = 0;
+			/* if 1:1 mode */
+			if ((!ratio_2to1) && ((phase == 0) || (phase == 4)))
+				ui_max_delay = MAX_DELAY_INV;
+			else
+				ui_max_delay = MAX_DELAY;
+
+			/* Increment Delay */
+			if (delay < ui_max_delay) {
+				delay++;
+				/*
+				 * Mark the last delay/pahse place for
+				 * window final place
+				 */
+				if (delay == ui_max_delay) {
+					if ((!ratio_2to1 && phase ==
+					     MAX_PHASE_RL_L_1TO1)
+					    || (ratio_2to1 && phase ==
+						MAX_PHASE_RL_L_2TO1))
+						final_delay = 1;
+				}
+			} else {
+				/* Phase+CL Incrementation */
+				delay = 0;
+
+				if (!ratio_2to1) {
+					/* 1:1 mode */
+					if (first_octet_locked) {
+						/* some Pup was Locked */
+						if (phase < MAX_PHASE_RL_L_1TO1) {
+							if (phase == 1) {
+								phase = 4;
+							} else {
+								phase++;
+								delay = MIN_DELAY_PHASE_1_LIMIT;
+							}
+						} else {
+							DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+							DEBUG_RL_S("1)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked n");
+							return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK;
+						}
+					} else {
+						/* NO Pup was Locked */
+						if (phase < MAX_PHASE_RL_UL_1TO1) {
+							phase++;
+							delay =
+							    MIN_DELAY_PHASE_1_LIMIT;
+						} else {
+							phase = 0;
+						}
+					}
+				} else {
+					/* 2:1 mode */
+					if (first_octet_locked) {
+						/* some Pup was Locked */
+						if (phase < MAX_PHASE_RL_L_2TO1) {
+							phase++;
+						} else {
+							DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+							DEBUG_RL_S("2)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+							for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+								/* pup_num = Q or 1 for ECC */
+								if (dram_info->rl_val[cs][idx][S]
+								    == 0) {
+									DEBUG_RL_C("Failed byte is = ",
+										   pup, 1);
+								}
+							}
+							return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK;
+						}
+					} else {
+						/* No Pup was Locked */
+						if (phase < MAX_PHASE_RL_UL_2TO1)
+							phase++;
+						else
+							phase = 0;
+					}
+				}
+
+				/*
+				 * If we finished a full Phases cycle (so now
+				 * phase = 0, need to increment rd_sample_dly
+				 */
+				if (phase == 0 && first_octet_locked == 0) {
+					rd_sample_delay++;
+					if (rd_sample_delay == 0x10) {
+						DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+						DEBUG_RL_S("3)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+						for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+							/* pup_num = Q or 1 for ECC */
+							if (dram_info->
+							    rl_val[cs][idx][S] == 0) {
+								DEBUG_RL_C("Failed byte is = ",
+									   pup, 1);
+							}
+						}
+						return MV_DDR3_TRAINING_ERR_RD_LVL_PUP_UNLOCK;
+					}
+
+					/* Set current rd_sample_delay  */
+					reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+					reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK
+					      << (REG_READ_DATA_SAMPLE_DELAYS_OFFS
+						  * cs));
+					reg |= (rd_sample_delay <<
+						(REG_READ_DATA_SAMPLE_DELAYS_OFFS *
+						 cs));
+					reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR,
+						  reg);
+				}
+
+				/*
+				 * Set current rdReadyDelay according to the
+				 * hash table (Need to do this in every phase
+				 * change)
+				 */
+				if (!ratio_2to1) {
+					/* 1:1 mode */
+					add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+					switch (phase) {
+					case 0:
+						add = (add >>
+						       REG_TRAINING_DEBUG_2_OFFS);
+						break;
+					case 1:
+						add = (add >>
+						       (REG_TRAINING_DEBUG_2_OFFS
+							+ 3));
+						break;
+					case 4:
+						add = (add >>
+						       (REG_TRAINING_DEBUG_2_OFFS
+							+ 6));
+						break;
+					case 5:
+						add = (add >>
+						       (REG_TRAINING_DEBUG_2_OFFS
+							+ 9));
+						break;
+					}
+					add &= REG_TRAINING_DEBUG_2_MASK;
+				} else {
+					/* 2:1 mode */
+					add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+					add = (add >>
+					       (phase *
+						REG_TRAINING_DEBUG_3_OFFS));
+					add &= REG_TRAINING_DEBUG_3_MASK;
+				}
+
+				reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+				reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+					 (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+				reg |= ((rd_sample_delay + add) <<
+					(REG_READ_DATA_READY_DELAYS_OFFS * cs));
+				reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+				dram_info->rd_smpl_dly = rd_sample_delay;
+				dram_info->rd_rdy_dly = rd_sample_delay + add;
+			}
+
+			/* Reset counters for pups with states<RD_STATE_COUNT */
+			for (pup = 0; pup <
+				     (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+			     pup++) {
+				if (dram_info->rl_val[cs][idx][C] < RL_RETRY_COUNT)
+					dram_info->rl_val[cs][idx][C] = 0;
+			}
+		}
+	}
+
+	phase_min = 10;
+
+	for (pup = 0; pup < (dram_info->num_of_std_pups); pup++) {
+		if (dram_info->rl_val[cs][pup][PS] < phase_min)
+			phase_min = dram_info->rl_val[cs][pup][PS];
+	}
+
+	/*
+	 * Set current rdReadyDelay according to the hash table (Need to
+	 * do this in every phase change)
+	 */
+	if (!ratio_2to1) {
+		/* 1:1 mode */
+		add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+		switch (phase_min) {
+		case 0:
+			add = (add >> REG_TRAINING_DEBUG_2_OFFS);
+			break;
+		case 1:
+			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 3));
+			break;
+		case 4:
+			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 6));
+			break;
+		case 5:
+			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 9));
+			break;
+		}
+		add &= REG_TRAINING_DEBUG_2_MASK;
+	} else {
+		/* 2:1 mode */
+		add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+		add = (add >> (phase_min * REG_TRAINING_DEBUG_3_OFFS));
+		add &= REG_TRAINING_DEBUG_3_MASK;
+	}
+
+	reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+	reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+		 (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+	reg |= ((rd_sample_delay + add) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+	reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+	dram_info->rd_rdy_dly = rd_sample_delay + add;
+
+	for (cs = 0; cs < dram_info->num_cs; cs++) {
+		for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+			reg = ddr3_read_pup_reg(PUP_RL_MODE + 0x1, cs, pup);
+			dram_info->rl_val[cs][pup][DQS] = (reg & 0x3F);
+		}
+	}
+
+	return MV_OK;
+}
+
+#else
+
+/*
+ * Name:     ddr3_read_leveling_single_cs_window_mode
+ * Desc:     Execute Read leveling for single Chip select
+ * Args:     cs        - current chip select
+ *           freq      - current sequence frequency
+ *           ecc       - ecc iteration indication
+ *           dram_info - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
+						    int ratio_2to1, u32 ecc,
+						    MV_DRAM_INFO *dram_info)
+{
+	u32 reg, delay, phase, sum, pup, rd_sample_delay, add, locked_pups,
+	    repeat_max_cnt, sdram_offset, final_sum, locked_sum;
+	u32 delay_s, delay_e, tmp, phase_min, ui_max_delay;
+	int all_locked, first_octet_locked, counter_in_progress;
+	int final_delay = 0;
+
+	DEBUG_RL_FULL_C("DDR3 - Read Leveling - Single CS - ", (u32) cs, 1);
+
+	/* Init values */
+	phase = 0;
+	delay = 0;
+	rd_sample_delay = dram_info->cl;
+	all_locked = 0;
+	first_octet_locked = 0;
+	repeat_max_cnt = 0;
+	sum = 0;
+	final_sum = 0;
+	locked_sum = 0;
+
+	for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+	     pup++)
+		dram_info->rl_val[cs][pup + ecc * ECC_BIT][S] = 0;
+
+	/* Main loop */
+	while (!all_locked) {
+		counter_in_progress = 0;
+
+		DEBUG_RL_FULL_S("DDR3 - Read Leveling - RdSmplDly = ");
+		DEBUG_RL_FULL_D(rd_sample_delay, 2);
+		DEBUG_RL_FULL_S(", RdRdyDly = ");
+		DEBUG_RL_FULL_D(dram_info->rd_rdy_dly, 2);
+		DEBUG_RL_FULL_S(", Phase = ");
+		DEBUG_RL_FULL_D(phase, 1);
+		DEBUG_RL_FULL_S(", Delay = ");
+		DEBUG_RL_FULL_D(delay, 2);
+		DEBUG_RL_FULL_S("\n");
+
+		/*
+		 * Broadcast to all PUPs current RL delays: DQS phase,leveling
+		 * delay
+		 */
+		ddr3_write_pup_reg(PUP_RL_MODE, cs, PUP_BC, phase, delay);
+
+		/* Reset PHY read FIFO */
+		reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+			(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+		/* 0x15B8 - Training SW 2 Register */
+		reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+		do {
+			reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+				(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+		} while (reg);	/* Wait for '0' */
+
+		/* Read pattern from SDRAM */
+		sdram_offset = cs * (SDRAM_CS_SIZE + 1) + SDRAM_RL_OFFS;
+		locked_pups = 0;
+		if (MV_OK !=
+		    ddr3_sdram_compare(dram_info, 0xFF, &locked_pups,
+				       rl_pattern, LEN_STD_PATTERN,
+				       sdram_offset, 0, 0, NULL, 0))
+			return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PATTERN;
+
+		/* Octet evaluation */
+		for (pup = 0; pup < (dram_info->num_of_std_pups *
+				     (1 - ecc) + ecc); pup++) {
+			/* pup_num = Q or 1 for ECC */
+			int idx;
+
+			idx = pup + ecc * ECC_BIT;
+
+			/* Check Overrun */
+			if (!((reg_read(REG_DRAM_TRAINING_2_ADDR) >>
+			      (REG_DRAM_TRAINING_2_OVERRUN_OFFS +
+			       pup)) & 0x1)) {
+				/* If no OverRun */
+
+				/* Inside the window */
+				if (dram_info->rl_val[cs][idx][S] == RL_WINDOW_STATE) {
+					/*
+					 * Match expected value ? - Update
+					 * State Machine
+					 */
+					if (((~locked_pups >> pup) & 0x1)
+					    && (final_delay == 0)) {
+						/* Match - Still inside the Window */
+						DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got another match inside the window  for pup: ",
+								(u32)pup, 1);
+
+					} else {
+						/* We got fail -> this is the end of the window */
+						dram_info->rl_val[cs][idx][DE] = delay;
+						dram_info->rl_val[cs][idx][PE] = phase;
+						/* Go to Final State */
+						dram_info->rl_val[cs][idx][S]++;
+						final_sum++;
+						DEBUG_RL_FULL_C("DDR3 - Read Leveling - We finished the window for pup: ",
+								(u32)pup, 1);
+					}
+
+					/* Before the start of the window */
+				} else if (dram_info->rl_val[cs][idx][S] ==
+					   RL_UNLOCK_STATE) {
+					/* Must be RL_UNLOCK_STATE */
+					/*
+					 * Match expected value ? - Update
+					 * State Machine
+					 */
+					if (dram_info->rl_val[cs][idx][C] <
+					    RL_RETRY_COUNT) {
+						if (((~locked_pups >> pup) & 0x1)) {
+							/* Match */
+							DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have no overrun and a match on pup: ",
+									(u32)pup, 1);
+							dram_info->rl_val[cs][idx][C]++;
+
+							/* If pup got to last state - lock the delays */
+							if (dram_info->rl_val[cs][idx][C] ==
+							    RL_RETRY_COUNT) {
+								dram_info->rl_val[cs][idx][C] = 0;
+								dram_info->rl_val[cs][idx][DS] =
+									delay;
+								dram_info->rl_val[cs][idx][PS] =
+									phase;
+								dram_info->rl_val[cs][idx][S]++;	/* Go to Window State */
+								locked_sum++;
+								/* Will count the pups that got locked */
+
+								/* IF First lock - need to lock delays */
+								if (first_octet_locked == 0) {
+									DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got first lock on pup: ",
+											(u32)pup, 1);
+									first_octet_locked
+									    =
+									    1;
+								}
+							}
+
+							/* if pup is in not in final state but there was match - dont increment counter */
+							else {
+								counter_in_progress
+								    = 1;
+							}
+						}
+					}
+				}
+			} else {
+				DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got overrun on pup: ",
+						(u32)pup, 1);
+				counter_in_progress = 1;
+			}
+		}
+
+		if (final_sum == (dram_info->num_of_std_pups * (1 - ecc) + ecc)) {
+			all_locked = 1;
+			DEBUG_RL_FULL_S("DDR3 - Read Leveling - Single Cs - All pups locked\n");
+		}
+
+		/*
+		 * This is a fix for unstable condition where pups are
+		 * toggling between match and no match
+		 */
+		/*
+		 * If some of the pups is >1 <3, check if we did it too many
+		 * times
+		 */
+		if (counter_in_progress == 1) {
+			if (repeat_max_cnt < RL_RETRY_COUNT) {
+				/* Notify at least one Counter is >=1 and < 3 */
+				repeat_max_cnt++;
+				counter_in_progress = 1;
+				DEBUG_RL_FULL_S("DDR3 - Read Leveling - Counter is >=1 and <3\n");
+				DEBUG_RL_FULL_S("DDR3 - Read Leveling - So we will not increment the delay to see if locked again\n");
+			} else {
+				DEBUG_RL_FULL_S("DDR3 - Read Leveling - repeat_max_cnt reached max so now we will increment the delay\n");
+				counter_in_progress = 0;
+			}
+		}
+
+		/*
+		 * Check some of the pups are in the middle of state machine
+		 * and don't increment the delays
+		 */
+		if (!counter_in_progress && !all_locked) {
+			repeat_max_cnt = 0;
+			if (!ratio_2to1)
+				ui_max_delay = MAX_DELAY_INV;
+			else
+				ui_max_delay = MAX_DELAY;
+
+			/* Increment Delay */
+			if (delay < ui_max_delay) {
+				/* Delay Incrementation */
+				delay++;
+				if (delay == ui_max_delay) {
+					/*
+					 * Mark the last delay/pahse place
+					 * for window final place
+					 */
+					if ((!ratio_2to1
+					     && phase == MAX_PHASE_RL_L_1TO1)
+					    || (ratio_2to1
+						&& phase ==
+						MAX_PHASE_RL_L_2TO1))
+						final_delay = 1;
+				}
+			} else {
+				/* Phase+CL Incrementation */
+				delay = 0;
+				if (!ratio_2to1) {
+					/* 1:1 mode */
+					if (first_octet_locked) {
+						/* some pupet was Locked */
+						if (phase < MAX_PHASE_RL_L_1TO1) {
+#ifdef RL_WINDOW_WA
+							if (phase == 0)
+#else
+							if (phase == 1)
+#endif
+								phase = 4;
+							else
+								phase++;
+						} else {
+							DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+							return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
+						}
+					} else {
+						/* No Pup was Locked */
+						if (phase < MAX_PHASE_RL_UL_1TO1) {
+#ifdef RL_WINDOW_WA
+							if (phase == 0)
+								phase = 4;
+#else
+							phase++;
+#endif
+						} else
+							phase = 0;
+					}
+				} else {
+					/* 2:1 mode */
+					if (first_octet_locked) {
+						/* Some Pup was Locked */
+						if (phase < MAX_PHASE_RL_L_2TO1) {
+							phase++;
+						} else {
+							DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+							return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
+						}
+					} else {
+						/* No Pup was Locked */
+						if (phase < MAX_PHASE_RL_UL_2TO1)
+							phase++;
+						else
+							phase = 0;
+					}
+				}
+
+				/*
+				 * If we finished a full Phases cycle (so
+				 * now phase = 0, need to increment
+				 * rd_sample_dly
+				 */
+				if (phase == 0 && first_octet_locked == 0) {
+					rd_sample_delay++;
+
+					/* Set current rd_sample_delay  */
+					reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+					reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+						 (REG_READ_DATA_SAMPLE_DELAYS_OFFS
+						  * cs));
+					reg |= (rd_sample_delay <<
+						(REG_READ_DATA_SAMPLE_DELAYS_OFFS *
+						 cs));
+					reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR,
+						  reg);
+				}
+
+				/*
+				 * Set current rdReadyDelay according to the
+				 * hash table (Need to do this in every phase
+				 * change)
+				 */
+				if (!ratio_2to1) {
+					/* 1:1 mode */
+					add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+					switch (phase) {
+					case 0:
+						add = add >>
+							REG_TRAINING_DEBUG_2_OFFS;
+						break;
+					case 1:
+						add = add >>
+							(REG_TRAINING_DEBUG_2_OFFS
+							 + 3);
+						break;
+					case 4:
+						add = add >>
+							(REG_TRAINING_DEBUG_2_OFFS
+							 + 6);
+						break;
+					case 5:
+						add = add >>
+							(REG_TRAINING_DEBUG_2_OFFS
+							 + 9);
+						break;
+					}
+				} else {
+					/* 2:1 mode */
+					add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+					add = (add >> phase *
+					       REG_TRAINING_DEBUG_3_OFFS);
+				}
+				add &= REG_TRAINING_DEBUG_2_MASK;
+				reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+				reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+					 (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+				reg |= ((rd_sample_delay + add) <<
+					(REG_READ_DATA_READY_DELAYS_OFFS * cs));
+				reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+				dram_info->rd_smpl_dly = rd_sample_delay;
+				dram_info->rd_rdy_dly = rd_sample_delay + add;
+			}
+
+			/* Reset counters for pups with states<RD_STATE_COUNT */
+			for (pup = 0;
+			     pup <
+			     (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+			     pup++) {
+				if (dram_info->rl_val[cs][idx][C] < RL_RETRY_COUNT)
+					dram_info->rl_val[cs][idx][C] = 0;
+			}
+		}
+	}
+
+	phase_min = 10;
+
+	for (pup = 0; pup < (dram_info->num_of_std_pups); pup++) {
+		DEBUG_RL_S("DDR3 - Read Leveling - Window info - PUP: ");
+		DEBUG_RL_D((u32) pup, 1);
+		DEBUG_RL_S(", PS: ");
+		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PS], 1);
+		DEBUG_RL_S(", DS: ");
+		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DS], 2);
+		DEBUG_RL_S(", PE: ");
+		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PE], 1);
+		DEBUG_RL_S(", DE: ");
+		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DE], 2);
+		DEBUG_RL_S("\n");
+	}
+
+	/* Find center of the window procedure */
+	for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+	     pup++) {
+#ifdef RL_WINDOW_WA
+		if (!ratio_2to1) {	/* 1:1 mode */
+			if (dram_info->rl_val[cs][idx][PS] == 4)
+				dram_info->rl_val[cs][idx][PS] = 1;
+			if (dram_info->rl_val[cs][idx][PE] == 4)
+				dram_info->rl_val[cs][idx][PE] = 1;
+
+			delay_s = dram_info->rl_val[cs][idx][PS] *
+				MAX_DELAY_INV + dram_info->rl_val[cs][idx][DS];
+			delay_e = dram_info->rl_val[cs][idx][PE] *
+				MAX_DELAY_INV + dram_info->rl_val[cs][idx][DE];
+
+			tmp = (delay_e - delay_s) / 2 + delay_s;
+			phase = tmp / MAX_DELAY_INV;
+			if (phase == 1)	/* 1:1 mode */
+				phase = 4;
+
+			if (phase < phase_min)	/* for the read ready delay */
+				phase_min = phase;
+
+			dram_info->rl_val[cs][idx][P] = phase;
+			dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY_INV;
+
+		} else {
+			delay_s = dram_info->rl_val[cs][idx][PS] *
+				MAX_DELAY + dram_info->rl_val[cs][idx][DS];
+			delay_e = dram_info->rl_val[cs][idx][PE] *
+				MAX_DELAY + dram_info->rl_val[cs][idx][DE];
+
+			tmp = (delay_e - delay_s) / 2 + delay_s;
+			phase = tmp / MAX_DELAY;
+
+			if (phase < phase_min)	/* for the read ready delay */
+				phase_min = phase;
+
+			dram_info->rl_val[cs][idx][P] = phase;
+			dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
+		}
+#else
+		if (!ratio_2to1) {	/* 1:1 mode */
+			if (dram_info->rl_val[cs][idx][PS] > 1)
+				dram_info->rl_val[cs][idx][PS] -= 2;
+			if (dram_info->rl_val[cs][idx][PE] > 1)
+				dram_info->rl_val[cs][idx][PE] -= 2;
+		}
+
+		delay_s = dram_info->rl_val[cs][idx][PS] * MAX_DELAY +
+			dram_info->rl_val[cs][idx][DS];
+		delay_e = dram_info->rl_val[cs][idx][PE] * MAX_DELAY +
+			dram_info->rl_val[cs][idx][DE];
+
+		tmp = (delay_e - delay_s) / 2 + delay_s;
+		phase = tmp / MAX_DELAY;
+		if (!ratio_2to1 && phase > 1)	/* 1:1 mode */
+			phase += 2;
+
+		if (phase < phase_min)	/* for the read ready delay */
+			phase_min = phase;
+
+		dram_info->rl_val[cs][idx][P] = phase;
+		dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
+#endif
+	}
+
+	/* Set current rdReadyDelay according to the hash table (Need to do this in every phase change) */
+	if (!ratio_2to1) {	/* 1:1 mode */
+		add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+		switch (phase_min) {
+		case 0:
+			add = (add >> REG_TRAINING_DEBUG_2_OFFS);
+			break;
+		case 1:
+			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 3));
+			break;
+		case 4:
+			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 6));
+			break;
+		case 5:
+			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 9));
+			break;
+		}
+	} else {		/* 2:1 mode */
+		add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+		add = (add >> phase_min * REG_TRAINING_DEBUG_3_OFFS);
+	}
+
+	add &= REG_TRAINING_DEBUG_2_MASK;
+	reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+	reg &=
+	    ~(REG_READ_DATA_READY_DELAYS_MASK <<
+	      (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+	reg |=
+	    ((rd_sample_delay + add) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+	reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+	dram_info->rd_rdy_dly = rd_sample_delay + add;
+
+	for (cs = 0; cs < dram_info->num_cs; cs++) {
+		for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+			reg = ddr3_read_pup_reg(PUP_RL_MODE + 0x1, cs, pup);
+			dram_info->rl_val[cs][pup][DQS] = (reg & 0x3F);
+		}
+	}
+
+	return MV_OK;
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_sdram.c b/drivers/ddr/mvebu/ddr3_sdram.c
new file mode 100644
index 0000000..50c1bf8
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_sdram.c
@@ -0,0 +1,669 @@
+/*
+ * 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_hw_training.h"
+#include "xor.h"
+#include "xor_regs.h"
+
+static void ddr3_flush_l1_line(u32 line);
+
+extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+#if defined(MV88F78X60)
+extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
+#endif
+extern u32 pbs_dq_mapping[PUP_NUM_64BIT][DQ_NUM];
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+/* PBS locked dq (per pup) */
+u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
+u32 pbs_locked_dm[MAX_PUP_NUM] = { 0 };
+u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
+
+int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#endif
+
+static u32 sdram_data[LEN_KILLER_PATTERN] __aligned(32) = { 0 };
+
+static struct crc_dma_desc dma_desc __aligned(32) = { 0 };
+
+#define XOR_TIMEOUT 0x8000000
+
+struct xor_channel_t {
+	struct crc_dma_desc *desc;
+	unsigned long desc_phys_addr;
+};
+
+#define XOR_CAUSE_DONE_MASK(chan)	((0x1 | 0x2) << (chan * 16))
+
+void xor_waiton_eng(int chan)
+{
+	int timeout;
+
+	timeout = 0;
+	while (!(reg_read(XOR_CAUSE_REG(XOR_UNIT(chan))) &
+		 XOR_CAUSE_DONE_MASK(XOR_CHAN(chan)))) {
+		if (timeout > XOR_TIMEOUT)
+			goto timeout;
+
+		timeout++;
+	}
+
+	timeout = 0;
+	while (mv_xor_state_get(chan) != MV_IDLE) {
+		if (timeout > XOR_TIMEOUT)
+			goto timeout;
+
+		timeout++;
+	}
+
+	/* Clear int */
+	reg_write(XOR_CAUSE_REG(XOR_UNIT(chan)),
+		  ~(XOR_CAUSE_DONE_MASK(XOR_CHAN(chan))));
+
+timeout:
+	return;
+}
+
+static int special_compare_pattern(u32 uj)
+{
+	if ((uj == 30) || (uj == 31) || (uj == 61) || (uj == 62) ||
+	    (uj == 93) || (uj == 94) || (uj == 126) || (uj == 127))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Compare code extracted as its used by multiple functions. This
+ * reduces code-size and makes it easier to maintain it. Additionally
+ * the code is not indented that much and therefore easier to read.
+ */
+static void compare_pattern_v1(u32 uj, u32 *pup, u32 *pattern,
+			       u32 pup_groups, int debug_dqs)
+{
+	u32 val;
+	u32 uk;
+	u32 var1;
+	u32 var2;
+	__maybe_unused u32 dq;
+
+	if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0xFF)) {
+		for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+			val = CMP_BYTE_SHIFT * uk;
+			var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
+			var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
+
+			if (var1 != var2) {
+				*pup |= (1 << (uk + (PUP_NUM_32BIT *
+						     (uj % pup_groups))));
+
+#ifdef MV_DEBUG_DQS
+				if (!debug_dqs)
+					continue;
+
+				for (dq = 0; dq < DQ_NUM; dq++) {
+					val = uk + (PUP_NUM_32BIT *
+						    (uj % pup_groups));
+					if (((var1 >> dq) & 0x1) !=
+					    ((var2 >> dq) & 0x1))
+						per_bit_data[val][dq] = 1;
+					else
+						per_bit_data[val][dq] = 0;
+				}
+#endif
+			}
+		}
+	}
+}
+
+static void compare_pattern_v2(u32 uj, u32 *pup, u32 *pattern)
+{
+	u32 val;
+	u32 uk;
+	u32 var1;
+	u32 var2;
+
+	if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0x3)) {
+		/* Found error */
+		for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+			val = CMP_BYTE_SHIFT * uk;
+			var1 = (sdram_data[uj] >> val) & CMP_BYTE_MASK;
+			var2 = (pattern[uj] >> val) & CMP_BYTE_MASK;
+			if (var1 != var2)
+				*pup |= (1 << (uk % PUP_NUM_16BIT));
+		}
+	}
+}
+
+/*
+ * Name:     ddr3_sdram_compare
+ * Desc:     Execute compare per PUP
+ * Args:     unlock_pup      Bit array of the unlock pups
+ *           new_locked_pup  Output  bit array of the pups with failed compare
+ *           pattern         Pattern to compare
+ *           pattern_len     Length of pattern (in bytes)
+ *           sdram_offset    offset address to the SDRAM
+ *           write           write to the SDRAM before read
+ *           mask            compare pattern with mask;
+ *           mask_pattern    Mask to compare pattern
+ *
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+		       u32 *new_locked_pup, u32 *pattern,
+		       u32 pattern_len, u32 sdram_offset, int write,
+		       int mask, u32 *mask_pattern,
+		       int special_compare)
+{
+	u32 uj;
+	__maybe_unused u32 pup_groups;
+	__maybe_unused u32 dq;
+
+#if !defined(MV88F67XX)
+	if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+		pup_groups = 2;
+	else
+		pup_groups = 1;
+#endif
+
+	ddr3_reset_phy_read_fifo();
+
+	/* Check if need to write to sdram before read */
+	if (write == 1)
+		ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
+
+	ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
+
+	/* Compare read result to write */
+	for (uj = 0; uj < pattern_len; uj++) {
+		if (special_compare && special_compare_pattern(uj))
+			continue;
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+		compare_pattern_v1(uj, new_locked_pup, pattern, pup_groups, 1);
+#elif defined(MV88F67XX)
+		compare_pattern_v2(uj, new_locked_pup, pattern);
+#endif
+	}
+
+	return MV_OK;
+}
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+/*
+ * Name:     ddr3_sdram_dm_compare
+ * Desc:     Execute compare per PUP
+ * Args:     unlock_pup      Bit array of the unlock pups
+ *           new_locked_pup  Output  bit array of the pups with failed compare
+ *           pattern         Pattern to compare
+ *           pattern_len     Length of pattern (in bytes)
+ *           sdram_offset    offset address to the SDRAM
+ *           write           write to the SDRAM before read
+ *           mask            compare pattern with mask;
+ *           mask_pattern    Mask to compare pattern
+ *
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+			  u32 *new_locked_pup, u32 *pattern,
+			  u32 sdram_offset)
+{
+	u32 uj, uk, var1, var2, pup_groups;
+	u32 val;
+	u32 pup = 0;
+
+	if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+		pup_groups = 2;
+	else
+		pup_groups = 1;
+
+	ddr3_dram_sram_burst((u32)pattern, SDRAM_PBS_TX_OFFS,
+			     LEN_PBS_PATTERN);
+	ddr3_dram_sram_burst(SDRAM_PBS_TX_OFFS, (u32)sdram_data,
+			     LEN_PBS_PATTERN);
+
+	/* Validate the correctness of the results */
+	for (uj = 0; uj < LEN_PBS_PATTERN; uj++)
+		compare_pattern_v1(uj, &pup, pattern, pup_groups, 0);
+
+	/* Test the DM Signals */
+	*(u32 *)(SDRAM_PBS_TX_OFFS + 0x10) = 0x12345678;
+	*(u32 *)(SDRAM_PBS_TX_OFFS + 0x14) = 0x12345678;
+
+	sdram_data[0] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10);
+	sdram_data[1] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14);
+
+	for (uj = 0; uj < 2; uj++) {
+		if (((sdram_data[uj]) != (pattern[uj])) &&
+		    (*new_locked_pup != 0xFF)) {
+			for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+				val = CMP_BYTE_SHIFT * uk;
+				var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
+				var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
+				if (var1 != var2) {
+					*new_locked_pup |= (1 << (uk +
+						(PUP_NUM_32BIT * (uj % pup_groups))));
+					*new_locked_pup |= pup;
+				}
+			}
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_sdram_pbs_compare
+ * Desc:     Execute SRAM compare per PUP and DQ.
+ * Args:     pup_locked             bit array of locked pups
+ *           is_tx                  Indicate whether Rx or Tx
+ *           pbs_pattern_idx        Index of PBS pattern
+ *           pbs_curr_val           The PBS value
+ *           pbs_lock_val           The value to set to locked PBS
+ *           skew_array             Global array to update with the compare results
+ *           ai_unlock_pup_dq_array bit array of the locked / unlocked pups per dq.
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked,
+			   int is_tx, u32 pbs_pattern_idx,
+			   u32 pbs_curr_val, u32 pbs_lock_val,
+			   u32 *skew_array, u8 *unlock_pup_dq_array,
+			   u32 ecc)
+{
+	/* bit array failed dq per pup for current compare */
+	u32 pbs_write_pup[DQ_NUM] = { 0 };
+	u32 update_pup;	/* pup as HW convention */
+	u32 max_pup;	/* maximal pup index */
+	u32 pup_addr;
+	u32 ui, dq, pup;
+	int var1, var2;
+	u32 sdram_offset, pup_groups, tmp_pup;
+	u32 *pattern_ptr;
+	u32 val;
+
+	/* Choose pattern */
+	switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+	case 16:
+		pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+		break;
+#endif
+	case 32:
+		pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+		break;
+#if defined(MV88F78X60)
+	case 64:
+		pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+		break;
+#endif
+	default:
+		return MV_FAIL;
+	}
+
+	max_pup = dram_info->num_of_std_pups;
+
+	sdram_offset = SDRAM_PBS_I_OFFS + pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS;
+
+	if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+		pup_groups = 2;
+	else
+		pup_groups = 1;
+
+	ddr3_reset_phy_read_fifo();
+
+	/* Check if need to write to sdram before read */
+	if (is_tx == 1) {
+		ddr3_dram_sram_burst((u32)pattern_ptr, sdram_offset,
+				     LEN_PBS_PATTERN);
+	}
+
+	ddr3_dram_sram_read(sdram_offset, (u32)sdram_data, LEN_PBS_PATTERN);
+
+	/* Compare read result to write */
+	for (ui = 0; ui < LEN_PBS_PATTERN; ui++) {
+		if ((sdram_data[ui]) != (pattern_ptr[ui])) {
+			/* found error */
+			/* error in low pup group */
+			for (pup = 0; pup < PUP_NUM_32BIT; pup++) {
+				val = CMP_BYTE_SHIFT * pup;
+				var1 = ((sdram_data[ui] >> val) &
+					CMP_BYTE_MASK);
+				var2 = ((pattern_ptr[ui] >> val) &
+					CMP_BYTE_MASK);
+
+				if (var1 != var2) {
+					if (dram_info->ddr_width > 16) {
+						tmp_pup = (pup + PUP_NUM_32BIT *
+							   (ui % pup_groups));
+					} else {
+						tmp_pup = (pup % PUP_NUM_16BIT);
+					}
+
+					update_pup = (1 << tmp_pup);
+					if (ecc && (update_pup != 0x1))
+						continue;
+
+					/*
+					 * Pup is failed - Go over all DQs and
+					 * look for failures
+					 */
+					for (dq = 0; dq < DQ_NUM; dq++) {
+						val = tmp_pup * (1 - ecc) +
+							ecc * ECC_PUP;
+						if (((var1 >> dq) & 0x1) !=
+						    ((var2 >> dq) & 0x1)) {
+							if (pbs_locked_dq[val][dq] == 1 &&
+							    pbs_locked_value[val][dq] != pbs_curr_val)
+								continue;
+
+							/*
+							 * Activate write to
+							 * update PBS to
+							 * pbs_lock_val
+							 */
+							pbs_write_pup[dq] |=
+								update_pup;
+
+							/*
+							 * Update the
+							 * unlock_pup_dq_array
+							 */
+							unlock_pup_dq_array[dq] &=
+								~update_pup;
+
+							/*
+							 * Lock PBS value for
+							 * failed bits in
+							 * compare operation
+							 */
+							skew_array[tmp_pup * DQ_NUM + dq] =
+								pbs_curr_val;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	pup_addr = (is_tx == 1) ? PUP_PBS_TX : PUP_PBS_RX;
+
+	/* Set last failed bits PBS to min / max pbs value */
+	for (dq = 0; dq < DQ_NUM; dq++) {
+		for (pup = 0; pup < max_pup; pup++) {
+			if (pbs_write_pup[dq] & (1 << pup)) {
+				val = pup * (1 - ecc) + ecc * ECC_PUP;
+				if (pbs_locked_dq[val][dq] == 1 &&
+				    pbs_locked_value[val][dq] != pbs_curr_val)
+					continue;
+
+				/* Mark the dq as locked */
+				pbs_locked_dq[val][dq] = 1;
+				pbs_locked_value[val][dq] = pbs_curr_val;
+				ddr3_write_pup_reg(pup_addr +
+						   pbs_dq_mapping[val][dq],
+						   CS0, val, 0, pbs_lock_val);
+			}
+		}
+	}
+
+	return MV_OK;
+}
+#endif
+
+/*
+ * Name:     ddr3_sdram_direct_compare
+ * Desc:     Execute compare  per PUP without DMA (no burst mode)
+ * Args:     unlock_pup       Bit array of the unlock pups
+ *           new_locked_pup   Output  bit array of the pups with failed compare
+ *           pattern          Pattern to compare
+ *           pattern_len      Length of pattern (in bytes)
+ *           sdram_offset     offset address to the SDRAM
+ *           write            write to the SDRAM before read
+ *           mask             compare pattern with mask;
+ *           auiMaskPatter    Mask to compare pattern
+ *
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+			      u32 *new_locked_pup, u32 *pattern,
+			      u32 pattern_len, u32 sdram_offset,
+			      int write, int mask, u32 *mask_pattern)
+{
+	u32 uj, uk, pup_groups;
+	u32 *sdram_addr;	/* used to read from SDRAM */
+
+	sdram_addr = (u32 *)sdram_offset;
+
+	if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+		pup_groups = 2;
+	else
+		pup_groups = 1;
+
+	/* Check if need to write before read */
+	if (write == 1) {
+		for (uk = 0; uk < pattern_len; uk++) {
+			*sdram_addr = pattern[uk];
+			sdram_addr++;
+		}
+	}
+
+	sdram_addr = (u32 *)sdram_offset;
+
+	for (uk = 0; uk < pattern_len; uk++) {
+		sdram_data[uk] = *sdram_addr;
+		sdram_addr++;
+	}
+
+	/* Compare read result to write */
+	for (uj = 0; uj < pattern_len; uj++) {
+		if (dram_info->ddr_width > 16) {
+			compare_pattern_v1(uj, new_locked_pup, pattern,
+					   pup_groups, 0);
+		} else {
+			compare_pattern_v2(uj, new_locked_pup, pattern);
+		}
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_dram_sram_burst
+ * Desc:     Read from the SDRAM in burst of 64 bytes
+ * Args:     src
+ *           dst
+ * Notes:    Using the XOR mechanism
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len)
+{
+	u32 chan, byte_count, cs_num, byte;
+	struct xor_channel_t channel;
+
+	chan = 0;
+	byte_count = len * 4;
+
+	/* Wait for previous transfer completion */
+	while (mv_xor_state_get(chan) != MV_IDLE)
+		;
+
+	/* Build the channel descriptor */
+	channel.desc = &dma_desc;
+
+	/* Enable Address Override and set correct src and dst */
+	if (src < SRAM_BASE) {
+		/* src is DRAM CS, dst is SRAM */
+		cs_num = (src / (1 + SDRAM_CS_SIZE));
+		reg_write(XOR_ADDR_OVRD_REG(0, 0),
+			  ((cs_num << 1) | (1 << 0)));
+		channel.desc->src_addr0 = (src % (1 + SDRAM_CS_SIZE));
+		channel.desc->dst_addr = dst;
+	} else {
+		/* src is SRAM, dst is DRAM CS */
+		cs_num = (dst / (1 + SDRAM_CS_SIZE));
+		reg_write(XOR_ADDR_OVRD_REG(0, 0),
+			  ((cs_num << 25) | (1 << 24)));
+		channel.desc->src_addr0 = (src);
+		channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
+		channel.desc->src_addr0 = src;
+		channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
+	}
+
+	channel.desc->src_addr1 = 0;
+	channel.desc->byte_cnt = byte_count;
+	channel.desc->next_desc_ptr = 0;
+	channel.desc->status = 1 << 31;
+	channel.desc->desc_cmd = 0x0;
+	channel.desc_phys_addr = (unsigned long)&dma_desc;
+
+	ddr3_flush_l1_line((u32)&dma_desc);
+
+	/* Issue the transfer */
+	if (mv_xor_transfer(chan, MV_DMA, channel.desc_phys_addr) != MV_OK)
+		return MV_FAIL;
+
+	/* Wait for completion */
+	xor_waiton_eng(chan);
+
+	if (dst > SRAM_BASE) {
+		for (byte = 0; byte < byte_count; byte += 0x20)
+			cache_inv(dst + byte);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_flush_l1_line
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:  MV_OK if success, other error code if fail.
+ */
+static void ddr3_flush_l1_line(u32 line)
+{
+	u32 reg;
+
+#if defined(MV88F672X)
+	reg = 1;
+#else
+	reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR) &
+		(1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
+#ifdef MV88F67XX
+	reg = ~reg & (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
+#endif
+#endif
+
+	if (reg) {
+		/* V7 Arch mode */
+		flush_l1_v7(line);
+		flush_l1_v7(line + CACHE_LINE_SIZE);
+	} else {
+		/* V6 Arch mode */
+		flush_l1_v6(line);
+		flush_l1_v6(line + CACHE_LINE_SIZE);
+	}
+}
+
+int ddr3_dram_sram_read(u32 src, u32 dst, u32 len)
+{
+	u32 ui;
+	u32 *dst_ptr, *src_ptr;
+
+	dst_ptr = (u32 *)dst;
+	src_ptr = (u32 *)src;
+
+	for (ui = 0; ui < len; ui++) {
+		*dst_ptr = *src_ptr;
+		dst_ptr++;
+		src_ptr++;
+	}
+
+	return MV_OK;
+}
+
+int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+			   u32 *new_locked_pup, u32 *pattern,
+			   u32 pattern_len, u32 sdram_offset, int write,
+			   int mask, u32 *mask_pattern,
+			   int special_compare)
+{
+	u32 uj, pup_groups;
+
+	if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+		pup_groups = 2;
+	else
+		pup_groups = 1;
+
+	ddr3_reset_phy_read_fifo();
+
+	/* Check if need to write to sdram before read */
+	if (write == 1)
+		ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
+
+	ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
+
+	/* Compare read result to write */
+	for (uj = 0; uj < pattern_len; uj++) {
+		if (special_compare && special_compare_pattern(uj))
+			continue;
+
+		if (dram_info->ddr_width > 16) {
+			compare_pattern_v1(uj, new_locked_pup, pattern,
+					   pup_groups, 1);
+		} else {
+			compare_pattern_v2(uj, new_locked_pup, pattern);
+		}
+	}
+
+	return MV_OK;
+}
+
+void ddr3_reset_phy_read_fifo(void)
+{
+	u32 reg;
+
+	/* reset read FIFO */
+	reg = reg_read(REG_DRAM_TRAINING_ADDR);
+	/* Start Auto Read Leveling procedure */
+	reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+
+	/* 0x15B0 - Training Register */
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+
+	/* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	do {
+		reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+			(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+	} while (reg);	/* Wait for '0' */
+
+	reg = reg_read(REG_DRAM_TRAINING_ADDR);
+
+	/* Clear Auto Read Leveling procedure */
+	reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+
+	/* 0x15B0 - Training Register */
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);
+}
diff --git a/drivers/ddr/mvebu/ddr3_spd.c b/drivers/ddr/mvebu/ddr3_spd.c
new file mode 100644
index 0000000..f4f94c5
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_spd.c
@@ -0,0 +1,1300 @@
+/*
+ * 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"
+
+#if defined(MV88F78X60)
+#include "ddr3_axp_config.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370_config.h"
+#endif
+
+#if defined(MV88F672X)
+#include "ddr3_a375_config.h"
+#endif
+
+#ifdef DUNIT_SPD
+
+/* DIMM SPD offsets */
+#define SPD_DEV_TYPE_BYTE		2
+
+#define SPD_MODULE_TYPE_BYTE		3
+#define SPD_MODULE_MASK			0xf
+#define SPD_MODULE_TYPE_RDIMM		1
+#define SPD_MODULE_TYPE_UDIMM		2
+
+#define SPD_DEV_DENSITY_BYTE		4
+#define SPD_DEV_DENSITY_MASK		0xf
+
+#define SPD_ROW_NUM_BYTE		5
+#define SPD_ROW_NUM_MIN			12
+#define SPD_ROW_NUM_OFF			3
+#define SPD_ROW_NUM_MASK		(7 << SPD_ROW_NUM_OFF)
+
+#define SPD_COL_NUM_BYTE		5
+#define SPD_COL_NUM_MIN			9
+#define SPD_COL_NUM_OFF			0
+#define SPD_COL_NUM_MASK		(7 << SPD_COL_NUM_OFF)
+
+#define SPD_MODULE_ORG_BYTE		7
+#define SPD_MODULE_SDRAM_DEV_WIDTH_OFF 	0
+#define SPD_MODULE_SDRAM_DEV_WIDTH_MASK	(7 << SPD_MODULE_SDRAM_DEV_WIDTH_OFF)
+#define SPD_MODULE_BANK_NUM_MIN		1
+#define SPD_MODULE_BANK_NUM_OFF		3
+#define SPD_MODULE_BANK_NUM_MASK	(7 << SPD_MODULE_BANK_NUM_OFF)
+
+#define SPD_BUS_WIDTH_BYTE		8
+#define SPD_BUS_WIDTH_OFF		0
+#define SPD_BUS_WIDTH_MASK		(7 << SPD_BUS_WIDTH_OFF)
+#define SPD_BUS_ECC_OFF			3
+#define SPD_BUS_ECC_MASK		(3 << SPD_BUS_ECC_OFF)
+
+#define SPD_MTB_DIVIDEND_BYTE		10
+#define SPD_MTB_DIVISOR_BYTE		11
+#define SPD_TCK_BYTE			12
+#define SPD_SUP_CAS_LAT_LSB_BYTE	14
+#define SPD_SUP_CAS_LAT_MSB_BYTE	15
+#define SPD_TAA_BYTE			16
+#define SPD_TWR_BYTE			17
+#define SPD_TRCD_BYTE			18
+#define SPD_TRRD_BYTE			19
+#define SPD_TRP_BYTE			20
+
+#define SPD_TRAS_MSB_BYTE		21
+#define SPD_TRAS_MSB_MASK		0xf
+
+#define SPD_TRC_MSB_BYTE		21
+#define SPD_TRC_MSB_MASK		0xf0
+
+#define SPD_TRAS_LSB_BYTE		22
+#define SPD_TRC_LSB_BYTE		23
+#define SPD_TRFC_LSB_BYTE		24
+#define SPD_TRFC_MSB_BYTE		25
+#define SPD_TWTR_BYTE			26
+#define SPD_TRTP_BYTE			27
+
+#define SPD_TFAW_MSB_BYTE		28
+#define SPD_TFAW_MSB_MASK		0xf
+
+#define SPD_TFAW_LSB_BYTE		29
+#define SPD_OPT_FEATURES_BYTE		30
+#define SPD_THERMAL_REFRESH_OPT_BYTE	31
+
+#define SPD_ADDR_MAP_BYTE		63
+#define SPD_ADDR_MAP_MIRROR_OFFS	0
+
+#define SPD_RDIMM_RC_BYTE		69
+#define SPD_RDIMM_RC_NIBBLE_MASK	0xF
+#define SPD_RDIMM_RC_NUM		16
+
+/* Dimm Memory Type values */
+#define SPD_MEM_TYPE_SDRAM		0x4
+#define SPD_MEM_TYPE_DDR1		0x7
+#define SPD_MEM_TYPE_DDR2		0x8
+#define SPD_MEM_TYPE_DDR3		0xB
+
+#define DIMM_MODULE_MANU_OFFS		64
+#define DIMM_MODULE_MANU_SIZE		8
+#define DIMM_MODULE_VEN_OFFS		73
+#define DIMM_MODULE_VEN_SIZE		25
+#define DIMM_MODULE_ID_OFFS		99
+#define DIMM_MODULE_ID_SIZE		18
+
+/* enumeration for voltage levels. */
+enum dimm_volt_if {
+	TTL_5V_TOLERANT,
+	LVTTL,
+	HSTL_1_5V,
+	SSTL_3_3V,
+	SSTL_2_5V,
+	VOLTAGE_UNKNOWN,
+};
+
+/* enumaration for SDRAM CAS Latencies. */
+enum dimm_sdram_cas {
+	SD_CL_1 = 1,
+	SD_CL_2,
+	SD_CL_3,
+	SD_CL_4,
+	SD_CL_5,
+	SD_CL_6,
+	SD_CL_7,
+	SD_FAULT
+};
+
+/* enumeration for memory types */
+enum memory_type {
+	MEM_TYPE_SDRAM,
+	MEM_TYPE_DDR1,
+	MEM_TYPE_DDR2,
+	MEM_TYPE_DDR3
+};
+
+/* DIMM information structure */
+typedef struct dimm_info {
+	/* DIMM dimensions */
+	u32 num_of_module_ranks;
+	u32 data_width;
+	u32 rank_capacity;
+	u32 num_of_devices;
+
+	u32 sdram_width;
+	u32 num_of_banks_on_each_device;
+	u32 sdram_capacity;
+
+	u32 num_of_row_addr;
+	u32 num_of_col_addr;
+
+	u32 addr_mirroring;
+
+	u32 err_check_type;			/* ECC , PARITY.. */
+	u32 type_info;				/* DDR2 only */
+
+	/* DIMM timing parameters */
+	u32 supported_cas_latencies;
+	u32 refresh_interval;
+	u32 min_cycle_time;
+	u32 min_row_precharge_time;
+	u32 min_row_active_to_row_active;
+	u32 min_ras_to_cas_delay;
+	u32 min_write_recovery_time;		/* DDR3/2 only */
+	u32 min_write_to_read_cmd_delay;	/* DDR3/2 only */
+	u32 min_read_to_prech_cmd_delay;	/* DDR3/2 only */
+	u32 min_active_to_precharge;
+	u32 min_refresh_recovery;		/* DDR3/2 only */
+	u32 min_cas_lat_time;
+	u32 min_four_active_win_delay;
+	u8 dimm_rc[SPD_RDIMM_RC_NUM];
+
+	/* DIMM vendor ID */
+	u32 vendor;
+} MV_DIMM_INFO;
+
+static int ddr3_spd_sum_init(MV_DIMM_INFO *info, MV_DIMM_INFO *sum_info,
+			     u32 dimm);
+static u32 ddr3_get_max_val(u32 spd_val, u32 dimm_num, u32 static_val);
+static u32 ddr3_get_min_val(u32 spd_val, u32 dimm_num, u32 static_val);
+static int ddr3_spd_init(MV_DIMM_INFO *info, u32 dimm_addr, u32 dimm_width);
+static u32 ddr3_div(u32 val, u32 divider, u32 sub);
+
+extern u8 spd_data[SPD_SIZE];
+extern u32 odt_config[ODT_OPT];
+extern u16 odt_static[ODT_OPT][MAX_CS];
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+
+#if !(defined(DB_88F6710) || defined(DB_88F6710_PCAC) || defined(RD_88F6710))
+/*
+ * Name:     ddr3_get_dimm_num - Find number of dimms and their addresses
+ * Desc:
+ * Args:     dimm_addr - array of dimm addresses
+ * Notes:
+ * Returns:  None.
+ */
+static u32 ddr3_get_dimm_num(u32 *dimm_addr)
+{
+	u32 dimm_cur_addr;
+	u8 data[3];
+	u32 dimm_num = 0;
+	int ret;
+
+	/* Read the dimm eeprom */
+	for (dimm_cur_addr = MAX_DIMM_ADDR; dimm_cur_addr > MIN_DIMM_ADDR;
+	     dimm_cur_addr--) {
+		data[SPD_DEV_TYPE_BYTE] = 0;
+
+		/* Far-End DIMM must be connected */
+		if ((dimm_num == 0) && (dimm_cur_addr < FAR_END_DIMM_ADDR))
+			return 0;
+
+		ret = i2c_read(dimm_cur_addr, 0, 1, (uchar *)data, 3);
+		if (!ret) {
+			if (data[SPD_DEV_TYPE_BYTE] == SPD_MEM_TYPE_DDR3) {
+				dimm_addr[dimm_num] = dimm_cur_addr;
+				dimm_num++;
+			}
+		}
+	}
+
+	return dimm_num;
+}
+#endif
+
+/*
+ * Name:     dimmSpdInit - Get the SPD parameters.
+ * Desc:     Read the DIMM SPD parameters into given struct parameter.
+ * Args:     dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
+ *           info - DIMM information structure.
+ * Notes:
+ * Returns:  MV_OK if function could read DIMM parameters, 0 otherwise.
+ */
+int ddr3_spd_init(MV_DIMM_INFO *info, u32 dimm_addr, u32 dimm_width)
+{
+	u32 tmp;
+	u32 time_base;
+	int ret;
+	__maybe_unused u32 rc;
+	__maybe_unused u8 vendor_high, vendor_low;
+
+	if (dimm_addr != 0) {
+		memset(spd_data, 0, SPD_SIZE * sizeof(u8));
+
+		ret = i2c_read(dimm_addr, 0, 1, (uchar *)spd_data, SPD_SIZE);
+		if (ret)
+			return MV_DDR3_TRAINING_ERR_TWSI_FAIL;
+	}
+
+	/* Check if DDR3 */
+	if (spd_data[SPD_DEV_TYPE_BYTE] != SPD_MEM_TYPE_DDR3)
+		return MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE;
+
+	/* Error Check Type */
+	/* No byte for error check in DDR3 SPD, use DDR2 convention */
+	info->err_check_type = 0;
+
+	/* Check if ECC */
+	if ((spd_data[SPD_BUS_WIDTH_BYTE] & 0x18) >> 3)
+		info->err_check_type = 1;
+
+	DEBUG_INIT_FULL_C("DRAM err_check_type ", info->err_check_type, 1);
+	switch (spd_data[SPD_MODULE_TYPE_BYTE]) {
+	case 1:
+		/* support RDIMM */
+		info->type_info = SPD_MODULE_TYPE_RDIMM;
+		break;
+	case 2:
+		/* support UDIMM */
+		info->type_info = SPD_MODULE_TYPE_UDIMM;
+		break;
+	case 11:		/* LRDIMM current not supported */
+	default:
+		info->type_info = (spd_data[SPD_MODULE_TYPE_BYTE]);
+		break;
+	}
+
+	/* Size Calculations: */
+
+	/* Number Of Row Addresses - 12/13/14/15/16 */
+	info->num_of_row_addr =
+		(spd_data[SPD_ROW_NUM_BYTE] & SPD_ROW_NUM_MASK) >>
+		SPD_ROW_NUM_OFF;
+	info->num_of_row_addr += SPD_ROW_NUM_MIN;
+	DEBUG_INIT_FULL_C("DRAM num_of_row_addr ", info->num_of_row_addr, 2);
+
+	/* Number Of Column Addresses - 9/10/11/12 */
+	info->num_of_col_addr =
+		(spd_data[SPD_COL_NUM_BYTE] & SPD_COL_NUM_MASK) >>
+		SPD_COL_NUM_OFF;
+	info->num_of_col_addr += SPD_COL_NUM_MIN;
+	DEBUG_INIT_FULL_C("DRAM num_of_col_addr ", info->num_of_col_addr, 1);
+
+	/* Number Of Ranks = number of CS on Dimm - 1/2/3/4 Ranks */
+	info->num_of_module_ranks =
+		(spd_data[SPD_MODULE_ORG_BYTE] & SPD_MODULE_BANK_NUM_MASK) >>
+		SPD_MODULE_BANK_NUM_OFF;
+	info->num_of_module_ranks += SPD_MODULE_BANK_NUM_MIN;
+	DEBUG_INIT_FULL_C("DRAM numOfModuleBanks ", info->num_of_module_ranks,
+			  1);
+
+	/* Data Width - 8/16/32/64 bits */
+	info->data_width =
+		1 << (3 + (spd_data[SPD_BUS_WIDTH_BYTE] & SPD_BUS_WIDTH_MASK));
+	DEBUG_INIT_FULL_C("DRAM data_width ", info->data_width, 1);
+
+	/* Number Of Banks On Each Device - 8/16/32/64 banks */
+	info->num_of_banks_on_each_device =
+		1 << (3 + ((spd_data[SPD_DEV_DENSITY_BYTE] >> 4) & 0x7));
+	DEBUG_INIT_FULL_C("DRAM num_of_banks_on_each_device ",
+			  info->num_of_banks_on_each_device, 1);
+
+	/* Total SDRAM capacity - 256Mb/512Mb/1Gb/2Gb/4Gb/8Gb/16Gb - MegaBits */
+	info->sdram_capacity =
+		spd_data[SPD_DEV_DENSITY_BYTE] & SPD_DEV_DENSITY_MASK;
+
+	/* Sdram Width - 4/8/16/32 bits */
+	info->sdram_width = 1 << (2 + (spd_data[SPD_MODULE_ORG_BYTE] &
+				       SPD_MODULE_SDRAM_DEV_WIDTH_MASK));
+	DEBUG_INIT_FULL_C("DRAM sdram_width ", info->sdram_width, 1);
+
+	/* CS (Rank) Capacity - MB */
+	/*
+	 * DDR3 device uiDensity val are: (device capacity/8) *
+	 * (Module_width/Device_width)
+	 */
+	/* Jedec SPD DDR3 - page 7, Save spd_data in Mb  - 2048=2GB */
+	if (dimm_width == 32) {
+		info->rank_capacity =
+			((1 << info->sdram_capacity) * 256 *
+			 (info->data_width / info->sdram_width)) << 16;
+		/* CS size = CS size / 2  */
+	} else {
+		info->rank_capacity =
+			((1 << info->sdram_capacity) * 256 *
+			 (info->data_width / info->sdram_width) * 0x2) << 16;
+		/* 0x2 =>  0x100000-1Mbit / 8-bit->byte / 0x10000  */
+	}
+	DEBUG_INIT_FULL_C("DRAM rank_capacity[31] ", info->rank_capacity, 1);
+
+	/* Number of devices includeing Error correction */
+	info->num_of_devices =
+		((info->data_width / info->sdram_width) *
+		 info->num_of_module_ranks) + info->err_check_type;
+	DEBUG_INIT_FULL_C("DRAM num_of_devices  ", info->num_of_devices, 1);
+
+	/* Address Mapping from Edge connector to DRAM - mirroring option */
+	info->addr_mirroring =
+		spd_data[SPD_ADDR_MAP_BYTE] & (1 << SPD_ADDR_MAP_MIRROR_OFFS);
+
+	/* Timings - All in ps */
+
+	time_base = (1000 * spd_data[SPD_MTB_DIVIDEND_BYTE]) /
+		spd_data[SPD_MTB_DIVISOR_BYTE];
+
+	/* Minimum Cycle Time At Max CasLatancy */
+	info->min_cycle_time = spd_data[SPD_TCK_BYTE] * time_base;
+	DEBUG_INIT_FULL_C("DRAM tCKmin ", info->min_cycle_time, 1);
+
+	/* Refresh Interval */
+	/* No byte for refresh interval in DDR3 SPD, use DDR2 convention */
+	/*
+	 * JEDEC param are 0 <= Tcase <= 85: 7.8uSec, 85 <= Tcase
+	 * <= 95: 3.9uSec
+	 */
+	info->refresh_interval = 7800000;	/* Set to 7.8uSec */
+	DEBUG_INIT_FULL_C("DRAM refresh_interval ", info->refresh_interval, 1);
+
+	/* Suported Cas Latencies -  DDR 3: */
+
+	/*
+	 *         bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
+	 *******-******-******-******-******-******-******-*******-*******
+	 CAS =      11  |  10  |  9   |  8   |  7   |  6   |  5   |  4   *
+	 *********************************************************-*******
+	 *******-******-******-******-******-******-******-*******-*******
+	 *        bit15 |bit14 |bit13 |bit12 |bit11 |bit10 | bit9 | bit8 *
+	 *******-******-******-******-******-******-******-*******-*******
+	 CAS =     TBD  |  18  |  17  |  16  |  15  |  14  |  13  |  12  *
+	*/
+
+	/* DDR3 include 2 byte of CAS support */
+	info->supported_cas_latencies =
+		(spd_data[SPD_SUP_CAS_LAT_MSB_BYTE] << 8) |
+		spd_data[SPD_SUP_CAS_LAT_LSB_BYTE];
+	DEBUG_INIT_FULL_C("DRAM supported_cas_latencies ",
+			  info->supported_cas_latencies, 1);
+
+	/* Minimum Cycle Time At Max CasLatancy */
+	info->min_cas_lat_time = (spd_data[SPD_TAA_BYTE] * time_base);
+	/*
+	 * This field divided by the cycleTime will give us the CAS latency
+	 * to config
+	 */
+
+	/*
+	 * For DDR3 and DDR2 includes Write Recovery Time field.
+	 * Other SDRAM ignore
+	 */
+	info->min_write_recovery_time = spd_data[SPD_TWR_BYTE] * time_base;
+	DEBUG_INIT_FULL_C("DRAM min_write_recovery_time ",
+			  info->min_write_recovery_time, 1);
+
+	/* Mininmum Ras to Cas Delay */
+	info->min_ras_to_cas_delay = spd_data[SPD_TRCD_BYTE] * time_base;
+	DEBUG_INIT_FULL_C("DRAM min_ras_to_cas_delay ",
+			  info->min_ras_to_cas_delay, 1);
+
+	/* Minimum Row Active to Row Active Time */
+	info->min_row_active_to_row_active =
+	    spd_data[SPD_TRRD_BYTE] * time_base;
+	DEBUG_INIT_FULL_C("DRAM min_row_active_to_row_active ",
+			  info->min_row_active_to_row_active, 1);
+
+	/* Minimum Row Precharge Delay Time */
+	info->min_row_precharge_time = spd_data[SPD_TRP_BYTE] * time_base;
+	DEBUG_INIT_FULL_C("DRAM min_row_precharge_time ",
+			  info->min_row_precharge_time, 1);
+
+	/* Minimum Active to Precharge Delay Time - tRAS   ps */
+	info->min_active_to_precharge =
+		(spd_data[SPD_TRAS_MSB_BYTE] & SPD_TRAS_MSB_MASK) << 8;
+	info->min_active_to_precharge |= spd_data[SPD_TRAS_LSB_BYTE];
+	info->min_active_to_precharge *= time_base;
+	DEBUG_INIT_FULL_C("DRAM min_active_to_precharge ",
+			  info->min_active_to_precharge, 1);
+
+	/* Minimum Refresh Recovery Delay Time - tRFC  ps */
+	info->min_refresh_recovery = spd_data[SPD_TRFC_MSB_BYTE] << 8;
+	info->min_refresh_recovery |= spd_data[SPD_TRFC_LSB_BYTE];
+	info->min_refresh_recovery *= time_base;
+	DEBUG_INIT_FULL_C("DRAM min_refresh_recovery ",
+			  info->min_refresh_recovery, 1);
+
+	/*
+	 * For DDR3 and DDR2 includes Internal Write To Read Command Delay
+	 * field.
+	 */
+	info->min_write_to_read_cmd_delay = spd_data[SPD_TWTR_BYTE] * time_base;
+	DEBUG_INIT_FULL_C("DRAM min_write_to_read_cmd_delay ",
+			  info->min_write_to_read_cmd_delay, 1);
+
+	/*
+	 * For DDR3 and DDR2 includes Internal Read To Precharge Command Delay
+	 * field.
+	 */
+	info->min_read_to_prech_cmd_delay = spd_data[SPD_TRTP_BYTE] * time_base;
+	DEBUG_INIT_FULL_C("DRAM min_read_to_prech_cmd_delay ",
+			  info->min_read_to_prech_cmd_delay, 1);
+
+	/*
+	 * For DDR3 includes Minimum Activate to Activate/Refresh Command
+	 * field
+	 */
+	tmp = ((spd_data[SPD_TFAW_MSB_BYTE] & SPD_TFAW_MSB_MASK) << 8) |
+		spd_data[SPD_TFAW_LSB_BYTE];
+	info->min_four_active_win_delay = tmp * time_base;
+	DEBUG_INIT_FULL_C("DRAM min_four_active_win_delay ",
+			  info->min_four_active_win_delay, 1);
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+	/* Registered DIMM support */
+	if (info->type_info == SPD_MODULE_TYPE_RDIMM) {
+		for (rc = 2; rc < 6; rc += 2) {
+			tmp = spd_data[SPD_RDIMM_RC_BYTE + rc / 2];
+			info->dimm_rc[rc] =
+				spd_data[SPD_RDIMM_RC_BYTE + rc / 2] &
+				SPD_RDIMM_RC_NIBBLE_MASK;
+			info->dimm_rc[rc + 1] =
+				(spd_data[SPD_RDIMM_RC_BYTE + rc / 2] >> 4) &
+				SPD_RDIMM_RC_NIBBLE_MASK;
+		}
+
+		vendor_low = spd_data[66];
+		vendor_high = spd_data[65];
+		info->vendor = (vendor_high << 8) + vendor_low;
+		DEBUG_INIT_C("DDR3 Training Sequence - Registered DIMM vendor ID 0x",
+			     info->vendor, 4);
+
+		info->dimm_rc[0] = RDIMM_RC0;
+		info->dimm_rc[1] = RDIMM_RC1;
+		info->dimm_rc[2] = RDIMM_RC2;
+		info->dimm_rc[8] = RDIMM_RC8;
+		info->dimm_rc[9] = RDIMM_RC9;
+		info->dimm_rc[10] = RDIMM_RC10;
+		info->dimm_rc[11] = RDIMM_RC11;
+	}
+#endif
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_spd_sum_init - Get the SPD parameters.
+ * Desc:     Read the DIMM SPD parameters into given struct parameter.
+ * Args:     dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
+ *           info - DIMM information structure.
+ * Notes:
+ * Returns:  MV_OK if function could read DIMM parameters, 0 otherwise.
+ */
+int ddr3_spd_sum_init(MV_DIMM_INFO *info, MV_DIMM_INFO *sum_info, u32 dimm)
+{
+	if (dimm == 0) {
+		memcpy(sum_info, info, sizeof(MV_DIMM_INFO));
+		return MV_OK;
+	}
+	if (sum_info->type_info != info->type_info) {
+		DEBUG_INIT_S("DDR3 Dimm Compare - DIMM type does not match - FAIL\n");
+		return MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH;
+	}
+	if (sum_info->err_check_type > info->err_check_type) {
+		sum_info->err_check_type = info->err_check_type;
+		DEBUG_INIT_S("DDR3 Dimm Compare - ECC does not match. ECC is disabled\n");
+	}
+	if (sum_info->data_width != info->data_width) {
+		DEBUG_INIT_S("DDR3 Dimm Compare - DRAM bus width does not match - FAIL\n");
+		return MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH;
+	}
+	if (sum_info->min_cycle_time < info->min_cycle_time)
+		sum_info->min_cycle_time = info->min_cycle_time;
+	if (sum_info->refresh_interval < info->refresh_interval)
+		sum_info->refresh_interval = info->refresh_interval;
+	sum_info->supported_cas_latencies &= info->supported_cas_latencies;
+	if (sum_info->min_cas_lat_time < info->min_cas_lat_time)
+		sum_info->min_cas_lat_time = info->min_cas_lat_time;
+	if (sum_info->min_write_recovery_time < info->min_write_recovery_time)
+		sum_info->min_write_recovery_time =
+		    info->min_write_recovery_time;
+	if (sum_info->min_ras_to_cas_delay < info->min_ras_to_cas_delay)
+		sum_info->min_ras_to_cas_delay = info->min_ras_to_cas_delay;
+	if (sum_info->min_row_active_to_row_active <
+	    info->min_row_active_to_row_active)
+		sum_info->min_row_active_to_row_active =
+		    info->min_row_active_to_row_active;
+	if (sum_info->min_row_precharge_time < info->min_row_precharge_time)
+		sum_info->min_row_precharge_time = info->min_row_precharge_time;
+	if (sum_info->min_active_to_precharge < info->min_active_to_precharge)
+		sum_info->min_active_to_precharge =
+		    info->min_active_to_precharge;
+	if (sum_info->min_refresh_recovery < info->min_refresh_recovery)
+		sum_info->min_refresh_recovery = info->min_refresh_recovery;
+	if (sum_info->min_write_to_read_cmd_delay <
+	    info->min_write_to_read_cmd_delay)
+		sum_info->min_write_to_read_cmd_delay =
+		    info->min_write_to_read_cmd_delay;
+	if (sum_info->min_read_to_prech_cmd_delay <
+	    info->min_read_to_prech_cmd_delay)
+		sum_info->min_read_to_prech_cmd_delay =
+		    info->min_read_to_prech_cmd_delay;
+	if (sum_info->min_four_active_win_delay <
+	    info->min_four_active_win_delay)
+		sum_info->min_four_active_win_delay =
+		    info->min_four_active_win_delay;
+	if (sum_info->min_write_to_read_cmd_delay <
+	    info->min_write_to_read_cmd_delay)
+		sum_info->min_write_to_read_cmd_delay =
+			info->min_write_to_read_cmd_delay;
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_dunit_setup
+ * Desc:     Set the controller with the timing values.
+ * Args:     ecc_ena - User ECC setup
+ * Notes:
+ * Returns:
+ */
+int ddr3_dunit_setup(u32 ecc_ena, u32 hclk_time, u32 *ddr_width)
+{
+	u32 reg, tmp, cwl;
+	u32 ddr_clk_time;
+	MV_DIMM_INFO dimm_info[2];
+	MV_DIMM_INFO sum_info;
+	u32 stat_val, spd_val;
+	u32 cs, cl, cs_num, cs_ena;
+	u32 dimm_num = 0;
+	int status;
+	u32 rc;
+	__maybe_unused u32 dimm_cnt, cs_count, dimm;
+	__maybe_unused u32 dimm_addr[2] = { 0, 0 };
+
+#if defined(DB_88F6710) || defined(DB_88F6710_PCAC) || defined(RD_88F6710)
+	/* Armada 370 - SPD is not available on DIMM */
+	/*
+	 * Set MC registers according to Static SPD values Values -
+	 * must be set manually
+	 */
+	/*
+	 * We only have one optional DIMM for the DB and we already got the
+	 * SPD matching values
+	 */
+	status = ddr3_spd_init(&dimm_info[0], 0, *ddr_width);
+	if (MV_OK != status)
+		return status;
+
+	dimm_num = 1;
+	/* Use JP8 to enable multiCS support for Armada 370 DB */
+	if (!ddr3_check_config(EEPROM_MODULE_ADDR, CONFIG_MULTI_CS))
+		dimm_info[0].num_of_module_ranks = 1;
+	status = ddr3_spd_sum_init(&dimm_info[0], &sum_info, 0);
+	if (MV_OK != status)
+		return status;
+#else
+	/* Dynamic D-Unit Setup - Read SPD values */
+#ifdef DUNIT_SPD
+	dimm_num = ddr3_get_dimm_num(dimm_addr);
+	if (dimm_num == 0) {
+#ifdef MIXED_DIMM_STATIC
+		DEBUG_INIT_S("DDR3 Training Sequence - No DIMMs detected\n");
+#else
+		DEBUG_INIT_S("DDR3 Training Sequence - FAILED (Wrong DIMMs Setup)\n");
+		return MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP;
+#endif
+	} else {
+		DEBUG_INIT_C("DDR3 Training Sequence - Number of DIMMs detected: ",
+			     dimm_num, 1);
+	}
+
+	for (dimm = 0; dimm < dimm_num; dimm++) {
+		status = ddr3_spd_init(&dimm_info[dimm], dimm_addr[dimm],
+				       *ddr_width);
+		if (MV_OK != status)
+			return status;
+		status = ddr3_spd_sum_init(&dimm_info[dimm], &sum_info, dimm);
+		if (MV_OK != status)
+			return status;
+	}
+#endif
+#endif
+
+	/* Set number of enabled CS */
+	cs_num = 0;
+#ifdef DUNIT_STATIC
+	cs_num = ddr3_get_cs_num_from_reg();
+#endif
+#ifdef DUNIT_SPD
+	for (dimm = 0; dimm < dimm_num; dimm++)
+		cs_num += dimm_info[dimm].num_of_module_ranks;
+#endif
+	if (cs_num > MAX_CS) {
+		DEBUG_INIT_C("DDR3 Training Sequence - Number of CS exceed limit -  ",
+			     MAX_CS, 1);
+		return MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT;
+	}
+
+	/* Set bitmap of enabled CS */
+	cs_ena = 0;
+#ifdef DUNIT_STATIC
+	cs_ena = ddr3_get_cs_ena_from_reg();
+#endif
+#ifdef DUNIT_SPD
+	dimm = 0;
+
+	if (dimm_num) {
+		for (cs = 0; cs < MAX_CS; cs += 2) {
+			if (((1 << cs) & DIMM_CS_BITMAP) &&
+			    !(cs_ena & (1 << cs))) {
+				if (dimm_info[dimm].num_of_module_ranks == 1)
+					cs_ena |= (0x1 << cs);
+				else if (dimm_info[dimm].num_of_module_ranks == 2)
+					cs_ena |= (0x3 << cs);
+				else if (dimm_info[dimm].num_of_module_ranks == 3)
+					cs_ena |= (0x7 << cs);
+				else if (dimm_info[dimm].num_of_module_ranks == 4)
+					cs_ena |= (0xF << cs);
+
+				dimm++;
+				if (dimm == dimm_num)
+					break;
+			}
+		}
+	}
+#endif
+
+	if (cs_ena > 0xF) {
+		DEBUG_INIT_C("DDR3 Training Sequence - Number of enabled CS exceed limit -  ",
+			     MAX_CS, 1);
+		return MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT;
+	}
+
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - Number of CS = ", cs_num, 1);
+
+	/* Check Ratio - '1' - 2:1, '0' - 1:1 */
+	if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+		ddr_clk_time = hclk_time / 2;
+	else
+		ddr_clk_time = hclk_time;
+
+#ifdef DUNIT_STATIC
+	/* Get target CL value from set register */
+	reg = (reg_read(REG_DDR3_MR0_ADDR) >> 2);
+	reg = ((((reg >> 1) & 0xE)) | (reg & 0x1)) & 0xF;
+
+	cl = ddr3_get_max_val(ddr3_div(sum_info.min_cas_lat_time,
+				       ddr_clk_time, 0),
+			      dimm_num, ddr3_valid_cl_to_cl(reg));
+#else
+	cl = ddr3_div(sum_info.min_cas_lat_time, ddr_clk_time, 0);
+#endif
+	if (cl < 5)
+		cl = 5;
+
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - Cas Latency = ", cl, 1);
+
+	/* {0x00001400} -   DDR SDRAM Configuration Register */
+	reg = 0x73004000;
+	stat_val = ddr3_get_static_mc_value(
+		REG_SDRAM_CONFIG_ADDR, REG_SDRAM_CONFIG_ECC_OFFS, 0x1, 0, 0);
+	if (ecc_ena && ddr3_get_min_val(sum_info.err_check_type, dimm_num,
+					stat_val)) {
+		reg |= (1 << REG_SDRAM_CONFIG_ECC_OFFS);
+		reg |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - ECC Enabled\n");
+	} else {
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - ECC Disabled\n");
+	}
+
+	if (sum_info.type_info == SPD_MODULE_TYPE_RDIMM) {
+#ifdef DUNIT_STATIC
+		DEBUG_INIT_S("DDR3 Training Sequence - FAIL - Illegal R-DIMM setup\n");
+		return MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP;
+#endif
+		reg |= (1 << REG_SDRAM_CONFIG_REGDIMM_OFFS);
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - R-DIMM\n");
+	} else {
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - U-DIMM\n");
+	}
+
+#ifndef MV88F67XX
+#ifdef DUNIT_STATIC
+	if (ddr3_get_min_val(sum_info.data_width, dimm_num, BUS_WIDTH) == 64) {
+#else
+	if (*ddr_width == 64) {
+#endif
+		reg |= (1 << REG_SDRAM_CONFIG_WIDTH_OFFS);
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 64Bits\n");
+	} else {
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 32Bits\n");
+	}
+#else
+	DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 16Bits\n");
+#endif
+
+#if defined(MV88F672X)
+	if (*ddr_width == 32) {
+		reg |= (1 << REG_SDRAM_CONFIG_WIDTH_OFFS);
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 32Bits\n");
+	} else {
+		DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 16Bits\n");
+	}
+#endif
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_CONFIG_ADDR, 0,
+					       REG_SDRAM_CONFIG_RFRS_MASK, 0, 0);
+	tmp = ddr3_get_min_val(sum_info.refresh_interval / hclk_time,
+			       dimm_num, stat_val);
+
+#ifdef TREFI_USER_EN
+	tmp = min(TREFI_USER / hclk_time, tmp);
+#endif
+
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - RefreshInterval/Hclk = ", tmp, 4);
+	reg |= tmp;
+
+	if (cl != 3)
+		reg |= (1 << 16);	/*  If 2:1 need to set P2DWr */
+
+#if defined(MV88F672X)
+	reg |= (1 << 27);	/* PhyRfRST = Disable */
+#endif
+	reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+	/*{0x00001404}  -   DDR SDRAM Configuration Register */
+	reg = 0x3630B800;
+#ifdef DUNIT_SPD
+	reg |= (DRAM_2T << REG_DUNIT_CTRL_LOW_2T_OFFS);
+#endif
+	reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+	/* {0x00001408}  -   DDR SDRAM Timing (Low) Register */
+	reg = 0x0;
+
+	/* tRAS - (0:3,20) */
+	spd_val = ddr3_div(sum_info.min_active_to_precharge,
+			    ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+					    0, 0xF, 16, 0x10);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRAS-1 = ", tmp, 1);
+	reg |= (tmp & 0xF);
+	reg |= ((tmp & 0x10) << 16);	/* to bit 20 */
+
+	/* tRCD - (4:7) */
+	spd_val = ddr3_div(sum_info.min_ras_to_cas_delay, ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+					    4, 0xF, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRCD-1 = ", tmp, 1);
+	reg |= ((tmp & 0xF) << 4);
+
+	/* tRP - (8:11) */
+	spd_val = ddr3_div(sum_info.min_row_precharge_time, ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+					    8, 0xF, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRP-1 = ", tmp, 1);
+	reg |= ((tmp & 0xF) << 8);
+
+	/* tWR - (12:15) */
+	spd_val = ddr3_div(sum_info.min_write_recovery_time, ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+					    12, 0xF, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tWR-1 = ", tmp, 1);
+	reg |= ((tmp & 0xF) << 12);
+
+	/* tWTR - (16:19) */
+	spd_val = ddr3_div(sum_info.min_write_to_read_cmd_delay, ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+					    16, 0xF, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tWTR-1 = ", tmp, 1);
+	reg |= ((tmp & 0xF) << 16);
+
+	/* tRRD - (24:27) */
+	spd_val = ddr3_div(sum_info.min_row_active_to_row_active, ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+					    24, 0xF, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRRD-1 = ", tmp, 1);
+	reg |= ((tmp & 0xF) << 24);
+
+	/* tRTP - (28:31) */
+	spd_val = ddr3_div(sum_info.min_read_to_prech_cmd_delay, ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+					    28, 0xF, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRTP-1 = ", tmp, 1);
+	reg |= ((tmp & 0xF) << 28);
+
+	if (cl < 7)
+		reg = 0x33137663;
+
+	reg_write(REG_SDRAM_TIMING_LOW_ADDR, reg);
+
+	/*{0x0000140C}  -   DDR SDRAM Timing (High) Register */
+	/* Add cycles to R2R W2W */
+	reg = 0x39F8FF80;
+
+	/* tRFC - (0:6,16:18) */
+	spd_val = ddr3_div(sum_info.min_refresh_recovery, ddr_clk_time, 1);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_HIGH_ADDR,
+					    0, 0x7F, 9, 0x380);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRFC-1 = ", tmp, 1);
+	reg |= (tmp & 0x7F);
+	reg |= ((tmp & 0x380) << 9);	/* to bit 16 */
+	reg_write(REG_SDRAM_TIMING_HIGH_ADDR, reg);
+
+	/*{0x00001410}  -   DDR SDRAM Address Control Register */
+	reg = 0x000F0000;
+
+	/* tFAW - (24:28)  */
+#if (defined(MV88F78X60) || defined(MV88F672X))
+	tmp = sum_info.min_four_active_win_delay;
+	spd_val = ddr3_div(tmp, ddr_clk_time, 0);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_ADDRESS_CTRL_ADDR,
+					    24, 0x3F, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tFAW = ", tmp, 1);
+	reg |= ((tmp & 0x3F) << 24);
+#else
+	tmp = sum_info.min_four_active_win_delay -
+		4 * (sum_info.min_row_active_to_row_active);
+	spd_val = ddr3_div(tmp, ddr_clk_time, 0);
+	stat_val = ddr3_get_static_mc_value(REG_SDRAM_ADDRESS_CTRL_ADDR,
+					    24, 0x1F, 0, 0);
+	tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+	DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tFAW-4*tRRD = ", tmp, 1);
+	reg |= ((tmp & 0x1F) << 24);
+#endif
+
+	/* SDRAM device capacity */
+#ifdef DUNIT_STATIC
+	reg |= (reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR) & 0xF0FFFF);
+#endif
+
+#ifdef DUNIT_SPD
+	cs_count = 0;
+	dimm_cnt = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+			if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+				dimm_cnt++;
+				cs_count = 0;
+			}
+			cs_count++;
+			if (dimm_info[dimm_cnt].sdram_capacity < 0x3) {
+				reg |= ((dimm_info[dimm_cnt].sdram_capacity + 1) <<
+					(REG_SDRAM_ADDRESS_SIZE_OFFS +
+					 (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs)));
+			} else if (dimm_info[dimm_cnt].sdram_capacity > 0x3) {
+				reg |= ((dimm_info[dimm_cnt].sdram_capacity & 0x3) <<
+					(REG_SDRAM_ADDRESS_SIZE_OFFS +
+					 (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs)));
+				reg |= ((dimm_info[dimm_cnt].sdram_capacity & 0x4) <<
+					(REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS + cs));
+			}
+		}
+	}
+
+	/* SDRAM device structure */
+	cs_count = 0;
+	dimm_cnt = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+			if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+				dimm_cnt++;
+				cs_count = 0;
+			}
+			cs_count++;
+			if (dimm_info[dimm_cnt].sdram_width == 16)
+				reg |= (1 << (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs));
+		}
+	}
+#endif
+	reg_write(REG_SDRAM_ADDRESS_CTRL_ADDR, reg);
+
+	/*{0x00001418}  -   DDR SDRAM Operation Register */
+	reg = 0xF00;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs))
+			reg &= ~(1 << (cs + REG_SDRAM_OPERATION_CS_OFFS));
+	}
+	reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+	/*{0x00001420}  -   DDR SDRAM Extended Mode Register */
+	reg = 0x00000004;
+	reg_write(REG_SDRAM_EXT_MODE_ADDR, reg);
+
+	/*{0x00001424}  -   DDR Controller Control (High) Register */
+#if (defined(MV88F78X60) || defined(MV88F672X))
+	reg = 0x0000D3FF;
+#else
+	reg = 0x0100D1FF;
+#endif
+	reg_write(REG_DDR_CONT_HIGH_ADDR, reg);
+
+	/*{0x0000142C}  -   DDR3 Timing Register */
+	reg = 0x014C2F38;
+#if defined(MV88F78X60) || defined(MV88F672X)
+	reg = 0x1FEC2F38;
+#endif
+	reg_write(0x142C, reg);
+
+	/*{0x00001484}  - MBus CPU Block Register */
+#ifdef MV88F67XX
+	if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+		reg_write(REG_MBUS_CPU_BLOCK_ADDR, 0x0000E907);
+#endif
+
+	/*
+	 * In case of mixed dimm and on-board devices setup paramters will
+	 * be taken statically
+	 */
+	/*{0x00001494}  -   DDR SDRAM ODT Control (Low) Register */
+	reg = odt_config[cs_ena];
+	reg_write(REG_SDRAM_ODT_CTRL_LOW_ADDR, reg);
+
+	/*{0x00001498}  -   DDR SDRAM ODT Control (High) Register */
+	reg = 0x00000000;
+	reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+	/*{0x0000149C}  -   DDR Dunit ODT Control Register */
+	reg = cs_ena;
+	reg_write(REG_DUNIT_ODT_CTRL_ADDR, reg);
+
+	/*{0x000014A0}  -   DDR Dunit ODT Control Register */
+#if defined(MV88F672X)
+	reg = 0x000006A9;
+	reg_write(REG_DRAM_FIFO_CTRL_ADDR, reg);
+#endif
+
+	/*{0x000014C0}  -   DRAM address and Control Driving Strenght */
+	reg_write(REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR, 0x192435e9);
+
+	/*{0x000014C4}  -   DRAM Data and DQS Driving Strenght */
+	reg_write(REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR, 0xB2C35E9);
+
+#if (defined(MV88F78X60) || defined(MV88F672X))
+	/*{0x000014CC}  -   DRAM Main Pads Calibration Machine Control Register */
+	reg = reg_read(REG_DRAM_MAIN_PADS_CAL_ADDR);
+	reg_write(REG_DRAM_MAIN_PADS_CAL_ADDR, reg | (1 << 0));
+#endif
+
+#if defined(MV88F672X)
+	/* DRAM Main Pads Calibration Machine Control Register */
+	/* 0x14CC[4:3] - CalUpdateControl = IntOnly */
+	reg = reg_read(REG_DRAM_MAIN_PADS_CAL_ADDR);
+	reg &= 0xFFFFFFE7;
+	reg |= (1 << 3);
+	reg_write(REG_DRAM_MAIN_PADS_CAL_ADDR, reg);
+#endif
+
+#ifdef DUNIT_SPD
+	cs_count = 0;
+	dimm_cnt = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if ((1 << cs) & DIMM_CS_BITMAP) {
+			if ((1 << cs) & cs_ena) {
+				if (dimm_info[dimm_cnt].num_of_module_ranks ==
+				    cs_count) {
+					dimm_cnt++;
+					cs_count = 0;
+				}
+				cs_count++;
+				reg_write(REG_CS_SIZE_SCRATCH_ADDR + (cs * 0x8),
+					  dimm_info[dimm_cnt].rank_capacity - 1);
+			} else {
+				reg_write(REG_CS_SIZE_SCRATCH_ADDR + (cs * 0x8), 0);
+			}
+		}
+	}
+#endif
+
+	/*{0x00020184}  -   Close FastPath - 2G */
+	reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, 0);
+
+	/*{0x00001538}  -    Read Data Sample Delays Register */
+	reg = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs))
+			reg |= (cl << (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+	}
+
+	reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+	DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Read Data Sample Delays = ", reg,
+			  1);
+
+	/*{0x0000153C}  -   Read Data Ready Delay Register */
+	reg = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			reg |= ((cl + 2) <<
+				(REG_READ_DATA_READY_DELAYS_OFFS * cs));
+		}
+	}
+	reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+	DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Read Data Ready Delays = ", reg, 1);
+
+	/* Set MR registers */
+	/* MR0 */
+	reg = 0x00000600;
+	tmp = ddr3_cl_to_valid_cl(cl);
+	reg |= ((tmp & 0x1) << 2);
+	reg |= ((tmp & 0xE) << 3);	/* to bit 4 */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			reg_write(REG_DDR3_MR0_CS_ADDR +
+				  (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	/* MR1 */
+	reg = 0x00000044 & REG_DDR3_MR1_ODT_MASK;
+	if (cs_num > 1)
+		reg = 0x00000046 & REG_DDR3_MR1_ODT_MASK;
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			reg |= odt_static[cs_ena][cs];
+			reg_write(REG_DDR3_MR1_CS_ADDR +
+				  (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	/* MR2 */
+	if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+		tmp = hclk_time / 2;
+	else
+		tmp = hclk_time;
+
+	if (tmp >= 2500)
+		cwl = 5;	/* CWL = 5 */
+	else if (tmp >= 1875 && tmp < 2500)
+		cwl = 6;	/* CWL = 6 */
+	else if (tmp >= 1500 && tmp < 1875)
+		cwl = 7;	/* CWL = 7 */
+	else if (tmp >= 1250 && tmp < 1500)
+		cwl = 8;	/* CWL = 8 */
+	else if (tmp >= 1070 && tmp < 1250)
+		cwl = 9;	/* CWL = 9 */
+	else if (tmp >= 935 && tmp < 1070)
+		cwl = 10;	/* CWL = 10 */
+	else if (tmp >= 833 && tmp < 935)
+		cwl = 11;	/* CWL = 11 */
+	else if (tmp >= 750 && tmp < 833)
+		cwl = 12;	/* CWL = 12 */
+	else {
+		cwl = 12;	/* CWL = 12 */
+		printf("Unsupported hclk %d MHz\n", tmp);
+	}
+
+	reg = ((cwl - 5) << REG_DDR3_MR2_CWL_OFFS);
+
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			reg &= REG_DDR3_MR2_ODT_MASK;
+			reg |= odt_dynamic[cs_ena][cs];
+			reg_write(REG_DDR3_MR2_CS_ADDR +
+				  (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	/* MR3 */
+	reg = 0x00000000;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs)) {
+			reg_write(REG_DDR3_MR3_CS_ADDR +
+				  (cs << MR_CS_ADDR_OFFS), reg);
+		}
+	}
+
+	/* {0x00001428}  -   DDR ODT Timing (Low) Register */
+	reg = 0;
+	reg |= (((cl - cwl + 1) & 0xF) << 4);
+	reg |= (((cl - cwl + 6) & 0xF) << 8);
+	reg |= ((((cl - cwl + 6) >> 4) & 0x1) << 21);
+	reg |= (((cl - 1) & 0xF) << 12);
+	reg |= (((cl + 6) & 0x1F) << 16);
+	reg_write(REG_ODT_TIME_LOW_ADDR, reg);
+
+	/* {0x0000147C}  -   DDR ODT Timing (High) Register */
+	reg = 0x00000071;
+	reg |= ((cwl - 1) << 8);
+	reg |= ((cwl + 5) << 12);
+	reg_write(REG_ODT_TIME_HIGH_ADDR, reg);
+
+#ifdef DUNIT_SPD
+	/*{0x000015E0} - DDR3 Rank Control Register */
+	reg = cs_ena;
+	cs_count = 0;
+	dimm_cnt = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+			if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+				dimm_cnt++;
+				cs_count = 0;
+			}
+			cs_count++;
+
+			if (dimm_info[dimm_cnt].addr_mirroring &&
+			    (cs == 1 || cs == 3) &&
+			    (sum_info.type_info != SPD_MODULE_TYPE_RDIMM)) {
+				reg |= (1 << (REG_DDR3_RANK_CTRL_MIRROR_OFFS + cs));
+				DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Setting Address Mirroring for CS = ",
+						  cs, 1);
+			}
+		}
+	}
+	reg_write(REG_DDR3_RANK_CTRL_ADDR, reg);
+#endif
+
+	/*{0xD00015E4}  -   ZQDS Configuration Register */
+	reg = 0x00203c18;
+	reg_write(REG_ZQC_CONF_ADDR, reg);
+
+	/* {0x00015EC}  -   DDR PHY */
+#if defined(MV88F78X60)
+	reg = 0xF800AAA5;
+	if (mv_ctrl_rev_get() == MV_78XX0_B0_REV)
+		reg = 0xF800A225;
+#else
+	reg = 0xDE000025;
+#if defined(MV88F672X)
+	reg = 0xF800A225;
+#endif
+#endif
+	reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+#if (defined(MV88F78X60) || defined(MV88F672X))
+	/* Registered DIMM support - supported only in AXP A0 devices */
+	/* Currently supported for SPD detection only */
+	/*
+	 * Flow is according to the Registered DIMM chapter in the
+	 * Functional Spec
+	 */
+	if (sum_info.type_info == SPD_MODULE_TYPE_RDIMM) {
+		DEBUG_INIT_S("DDR3 Training Sequence - Registered DIMM detected\n");
+
+		/* Set commands parity completion */
+		reg = reg_read(REG_REGISTERED_DRAM_CTRL_ADDR);
+		reg &= ~REG_REGISTERED_DRAM_CTRL_PARITY_MASK;
+		reg |= 0x8;
+		reg_write(REG_REGISTERED_DRAM_CTRL_ADDR, reg);
+
+		/* De-assert M_RESETn and assert M_CKE */
+		reg_write(REG_SDRAM_INIT_CTRL_ADDR,
+			  1 << REG_SDRAM_INIT_CKE_ASSERT_OFFS);
+		do {
+			reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+				(1 << REG_SDRAM_INIT_CKE_ASSERT_OFFS);
+		} while (reg);
+
+		for (rc = 0; rc < SPD_RDIMM_RC_NUM; rc++) {
+			if (rc != 6 && rc != 7) {
+				/* Set CWA Command */
+				reg = (REG_SDRAM_OPERATION_CMD_CWA &
+				       ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+				reg |= ((dimm_info[0].dimm_rc[rc] &
+					 REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+					REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+				reg |= rc << REG_SDRAM_OPERATION_CWA_RC_OFFS;
+				/* Configure - Set Delay - tSTAB/tMRD */
+				if (rc == 2 || rc == 10)
+					reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+				/* 0x1418 - SDRAM Operation Register */
+				reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+				/*
+				 * Poll the "cmd" field in the SDRAM OP
+				 * register for 0x0
+				 */
+				do {
+					reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+						(REG_SDRAM_OPERATION_CMD_MASK);
+				} while (reg);
+			}
+		}
+	}
+#endif
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_div - this function divides integers
+ * Desc:
+ * Args:     val - the value
+ *           divider - the divider
+ *           sub - substruction value
+ * Notes:
+ * Returns:  required value
+ */
+u32 ddr3_div(u32 val, u32 divider, u32 sub)
+{
+	return val / divider + (val % divider > 0 ? 1 : 0) - sub;
+}
+
+/*
+ * Name:     ddr3_get_max_val
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_max_val(u32 spd_val, u32 dimm_num, u32 static_val)
+{
+#ifdef DUNIT_STATIC
+	if (dimm_num > 0) {
+		if (spd_val >= static_val)
+			return spd_val;
+		else
+			return static_val;
+	} else {
+		return static_val;
+	}
+#else
+	return spd_val;
+#endif
+}
+
+/*
+ * Name:     ddr3_get_min_val
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_min_val(u32 spd_val, u32 dimm_num, u32 static_val)
+{
+#ifdef DUNIT_STATIC
+	if (dimm_num > 0) {
+		if (spd_val <= static_val)
+			return spd_val;
+		else
+			return static_val;
+	} else
+		return static_val;
+#else
+	return spd_val;
+#endif
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_write_leveling.c b/drivers/ddr/mvebu/ddr3_write_leveling.c
new file mode 100644
index 0000000..df3a3df
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_write_leveling.c
@@ -0,0 +1,1366 @@
+/*
+ * 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_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_WL_C(s, d, l) \
+	DEBUG_WL_S(s); DEBUG_WL_D(d, l); DEBUG_WL_S("\n")
+#define DEBUG_WL_FULL_C(s, d, l) \
+	DEBUG_WL_FULL_S(s); DEBUG_WL_FULL_D(d, l); DEBUG_WL_FULL_S("\n")
+
+#ifdef MV_DEBUG_WL
+#define DEBUG_RL_S(s) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_RL_D(d, l) \
+	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+#else
+#define DEBUG_WL_S(s)
+#define DEBUG_WL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_WL_FULL
+#define DEBUG_WL_FULL_S(s)		puts(s)
+#define DEBUG_WL_FULL_D(d, l)		printf("%x", d)
+#else
+#define DEBUG_WL_FULL_S(s)
+#define DEBUG_WL_FULL_D(d, l)
+#endif
+
+#define WL_SUP_EXPECTED_DATA		0x21
+#define WL_SUP_READ_DRAM_ENTRY		0x8
+
+static int ddr3_write_leveling_single_cs(u32 cs, u32 freq, int ratio_2to1,
+					 u32 *result,
+					 MV_DRAM_INFO *dram_info);
+static void ddr3_write_ctrl_pup_reg(int bc_acc, u32 pup, u32 reg_addr,
+				    u32 data);
+
+extern u16 odt_static[ODT_OPT][MAX_CS];
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+extern u32 wl_sup_pattern[LEN_WL_SUP_PATTERN];
+
+/*
+ * Name:     ddr3_write_leveling_hw
+ * Desc:     Execute Write leveling phase by HW
+ * Args:     freq      - current sequence frequency
+ *           dram_info   - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info)
+{
+	u32 reg, phase, delay, cs, pup;
+#ifdef MV88F67XX
+	int dpde_flag = 0;
+#endif
+	/* Debug message - Start Read leveling procedure */
+	DEBUG_WL_S("DDR3 - Write Leveling - Starting HW WL procedure\n");
+
+#ifdef MV88F67XX
+	/* Dynamic pad issue (BTS669) during WL */
+	reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+	if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+		dpde_flag = 1;
+		reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+			  reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+	}
+#endif
+
+	reg = 1 << REG_DRAM_TRAINING_WL_OFFS;
+	/* Config the retest number */
+	reg |= (COUNT_HW_WL << REG_DRAM_TRAINING_RETEST_OFFS);
+	reg |= (dram_info->cs_ena << (REG_DRAM_TRAINING_CS_OFFS));
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	reg =  reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+		(1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+	/* Wait */
+	do {
+		reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+			(1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	} while (reg);		/* Wait for '0' */
+
+	reg = reg_read(REG_DRAM_TRAINING_ADDR);
+	/* Check if Successful */
+	if (reg & (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+		/*
+		 * Read results to arrays - Results are required for WL
+		 * High freq Supplement and DQS Centralization
+		 */
+		for (cs = 0; cs < MAX_CS; cs++) {
+			if (dram_info->cs_ena & (1 << cs)) {
+				for (pup = 0;
+				     pup < dram_info->num_of_total_pups;
+				     pup++) {
+					if (pup == dram_info->num_of_std_pups
+					    && dram_info->ecc_ena)
+						pup = ECC_PUP;
+					reg =
+					    ddr3_read_pup_reg(PUP_WL_MODE, cs,
+							      pup);
+					phase =
+					    (reg >> REG_PHY_PHASE_OFFS) &
+					    PUP_PHASE_MASK;
+					delay = reg & PUP_DELAY_MASK;
+					dram_info->wl_val[cs][pup][P] = phase;
+					dram_info->wl_val[cs][pup][D] = delay;
+					dram_info->wl_val[cs][pup][S] =
+					    WL_HI_FREQ_STATE - 1;
+					reg =
+					    ddr3_read_pup_reg(PUP_WL_MODE + 0x1,
+							      cs, pup);
+					dram_info->wl_val[cs][pup][DQS] =
+					    (reg & 0x3F);
+				}
+
+#ifdef MV_DEBUG_WL
+				/* Debug message - Print res for cs[i]: cs,PUP,Phase,Delay */
+				DEBUG_WL_S("DDR3 - Write Leveling - Write Leveling Cs - ");
+				DEBUG_WL_D((u32) cs, 1);
+				DEBUG_WL_S(" Results:\n");
+				for (pup = 0;
+				     pup < dram_info->num_of_total_pups;
+				     pup++) {
+					if (pup == dram_info->num_of_std_pups
+					    && dram_info->ecc_ena)
+						pup = ECC_PUP;
+					DEBUG_WL_S("DDR3 - Write Leveling - PUP: ");
+					DEBUG_WL_D((u32) pup, 1);
+					DEBUG_WL_S(", Phase: ");
+					DEBUG_WL_D((u32)
+						   dram_info->wl_val[cs][pup]
+						   [P], 1);
+					DEBUG_WL_S(", Delay: ");
+					DEBUG_WL_D((u32)
+						   dram_info->wl_val[cs][pup]
+						   [D], 2);
+					DEBUG_WL_S("\n");
+				}
+#endif
+			}
+		}
+
+		/* Dynamic pad issue (BTS669) during WL */
+#ifdef MV88F67XX
+		if (dpde_flag) {
+			reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+				(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+			reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+		}
+#endif
+
+		DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+
+		return MV_OK;
+	} else {
+		DEBUG_WL_S("DDR3 - Write Leveling - HW WL Error\n");
+		return MV_FAIL;
+	}
+}
+
+/*
+ * Name:     ddr3_wl_supplement
+ * Desc:     Write Leveling Supplement
+ * Args:     dram_info   - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_wl_supplement(MV_DRAM_INFO *dram_info)
+{
+	u32 cs, cnt, pup_num, sum, phase, delay, max_pup_num, pup, sdram_offset;
+	u32 tmp_count, ecc, reg;
+	u32 ddr_width, tmp_pup, idx;
+	u32 sdram_pup_val, uj;
+	u32 one_clk_err = 0, align_err = 0, no_err = 0, err = 0, err_n = 0;
+	u32 sdram_data[LEN_WL_SUP_PATTERN] __aligned(32) = { 0 };
+
+	ddr_width = dram_info->ddr_width;
+	no_err = 0;
+
+	DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - Starting\n");
+
+	switch (ddr_width) {
+		/* Data error from pos-adge to pos-adge */
+	case 16:
+		one_clk_err = 4;
+		align_err = 4;
+		break;
+	case 32:
+		one_clk_err = 8;
+		align_err = 8;
+		break;
+	case 64:
+		one_clk_err = 0x10;
+		align_err = 0x10;
+		break;
+	default:
+		DEBUG_WL_S("Error - bus width!!!\n");
+		return MV_FAIL;
+	}
+
+	/* Enable SW override */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - SW Override Enabled\n");
+	reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+	tmp_count = 0;
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			sum = 0;
+			/*
+			 * 2 iterations loop: 1)actual WL results 2) fix WL
+			 * if needed
+			 */
+			for (cnt = 0; cnt < COUNT_WL_HI_FREQ; cnt++) {
+				DEBUG_WL_C("COUNT = ", cnt, 1);
+				for (ecc = 0; ecc < (dram_info->ecc_ena + 1);
+				     ecc++) {
+					if (ecc) {
+						DEBUG_WL_S("ECC PUP:\n");
+					} else {
+						DEBUG_WL_S("DATA PUP:\n");
+					}
+
+					max_pup_num =
+					    dram_info->num_of_std_pups * (1 -
+									  ecc) +
+					    ecc;
+					/* ECC Support - Switch ECC Mux on ecc=1 */
+					reg =
+					    (reg_read(REG_DRAM_TRAINING_2_ADDR)
+					     & ~(1 <<
+						 REG_DRAM_TRAINING_2_ECC_MUX_OFFS));
+					reg |=
+					    (dram_info->ecc_ena *
+					     ecc <<
+					     REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+					reg_write(REG_DRAM_TRAINING_2_ADDR,
+						  reg);
+					ddr3_reset_phy_read_fifo();
+
+					/* Write to memory */
+					sdram_offset =
+					    tmp_count * (SDRAM_CS_SIZE + 1) +
+					    0x200;
+					if (MV_OK != ddr3_dram_sram_burst((u32)
+									  wl_sup_pattern,
+									  sdram_offset,
+									  LEN_WL_SUP_PATTERN))
+						return MV_FAIL;
+
+					/* Read from memory */
+					if (MV_OK !=
+					    ddr3_dram_sram_burst(sdram_offset,
+								 (u32)
+								 sdram_data,
+								 LEN_WL_SUP_PATTERN))
+						return MV_FAIL;
+
+					/* Print the buffer */
+					for (uj = 0; uj < LEN_WL_SUP_PATTERN;
+					     uj++) {
+						if ((uj % 4 == 0) && (uj != 0)) {
+							DEBUG_WL_S("\n");
+						}
+						DEBUG_WL_D(sdram_data[uj],
+							   8);
+						DEBUG_WL_S(" ");
+					}
+
+					/* Check pup which DQS/DATA is error */
+					for (pup = 0; pup < max_pup_num; pup++) {
+						/* ECC support - bit 8 */
+						pup_num = (ecc) ? ECC_PUP : pup;
+						if (pup < 4) {	/* lower 32 bit */
+							tmp_pup = pup;
+							idx =
+							    WL_SUP_READ_DRAM_ENTRY;
+						} else {	/* higher 32 bit */
+							tmp_pup = pup - 4;
+							idx =
+							    WL_SUP_READ_DRAM_ENTRY
+							    + 1;
+						}
+						DEBUG_WL_S("\nCS: ");
+						DEBUG_WL_D((u32) cs, 1);
+						DEBUG_WL_S(" PUP: ");
+						DEBUG_WL_D((u32) pup_num, 1);
+						DEBUG_WL_S("\n");
+						sdram_pup_val =
+						    ((sdram_data[idx] >>
+						      ((tmp_pup) * 8)) & 0xFF);
+						DEBUG_WL_C("Actual Data = ",
+							   sdram_pup_val, 2);
+						DEBUG_WL_C("Expected Data = ",
+							   (WL_SUP_EXPECTED_DATA
+							    + pup), 2);
+						/*
+						 * ALINGHMENT: calculate
+						 * expected data vs actual data
+						 */
+						err =
+						    (WL_SUP_EXPECTED_DATA +
+						     pup) - sdram_pup_val;
+						/*
+						 * CLOCK LONG: calculate
+						 * expected data vs actual data
+						 */
+						err_n =
+						    sdram_pup_val -
+						    (WL_SUP_EXPECTED_DATA +
+						     pup);
+						DEBUG_WL_C("err = ", err, 2);
+						DEBUG_WL_C("err_n = ", err_n,
+							   2);
+						if (err == no_err) {
+							/* PUP is correct - increment State */
+							dram_info->wl_val[cs]
+							    [pup_num]
+							    [S] = 1;
+						} else if (err_n == one_clk_err) {
+							/* clock is longer than DQS */
+							phase =
+							    ((dram_info->wl_val
+							      [cs]
+							      [pup_num][P] +
+							      WL_HI_FREQ_SHIFT)
+							     % MAX_PHASE_2TO1);
+							dram_info->wl_val[cs]
+							    [pup_num]
+							    [P] = phase;
+							delay =
+							    dram_info->wl_val
+							    [cs][pup_num]
+							    [D];
+							DEBUG_WL_S("#### Clock is longer than DQS more than one clk cycle ####\n");
+							ddr3_write_pup_reg
+							    (PUP_WL_MODE, cs,
+							     pup * (1 - ecc) +
+							     ECC_PUP * ecc,
+							     phase, delay);
+						} else if (err == align_err) {
+							/* clock is align to DQS */
+							phase =
+							    dram_info->wl_val
+							    [cs][pup_num]
+							    [P];
+							delay =
+							    dram_info->wl_val
+							    [cs][pup_num]
+							    [D];
+							DEBUG_WL_S("#### Alignment PUPS problem ####\n");
+							if ((phase == 0)
+							    || ((phase == 1)
+								&& (delay <=
+								    0x10))) {
+								DEBUG_WL_S("#### Warning - Possible Layout Violation (DQS is longer than CLK)####\n");
+							}
+
+							phase = 0x0;
+							delay = 0x0;
+							dram_info->wl_val[cs]
+							    [pup_num]
+							    [P] = phase;
+							dram_info->wl_val[cs]
+							    [pup_num]
+							    [D] = delay;
+							ddr3_write_pup_reg
+							    (PUP_WL_MODE, cs,
+							     pup * (1 - ecc) +
+							     ECC_PUP * ecc,
+							     phase, delay);
+						}
+						/* Stop condition for ECC phase */
+						pup = (ecc) ? max_pup_num : pup;
+					}
+
+					/* ECC Support - Disable ECC MUX */
+					reg =
+					    (reg_read(REG_DRAM_TRAINING_2_ADDR)
+					     & ~(1 <<
+						 REG_DRAM_TRAINING_2_ECC_MUX_OFFS));
+					reg_write(REG_DRAM_TRAINING_2_ADDR,
+						  reg);
+				}
+			}
+
+			for (pup = 0; pup < dram_info->num_of_std_pups; pup++)
+				sum += dram_info->wl_val[cs][pup][S];
+
+			if (dram_info->ecc_ena)
+				sum += dram_info->wl_val[cs][ECC_PUP][S];
+
+			/* Checks if any pup is not locked after the change */
+			if (sum < (WL_HI_FREQ_STATE * (dram_info->num_of_total_pups))) {
+				DEBUG_WL_C("DDR3 - Write Leveling Hi-Freq Supplement - didn't work for Cs - ",
+					   (u32) cs, 1);
+				return MV_FAIL;
+			}
+			tmp_count++;
+		}
+	}
+
+	dram_info->wl_max_phase = 0;
+	dram_info->wl_min_phase = 10;
+
+	/*
+	 * Read results to arrays - Results are required for DQS Centralization
+	 */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+				if (pup == dram_info->num_of_std_pups
+				    && dram_info->ecc_ena)
+					pup = ECC_PUP;
+				reg = ddr3_read_pup_reg(PUP_WL_MODE, cs, pup);
+				phase =
+				    (reg >> REG_PHY_PHASE_OFFS) &
+				    PUP_PHASE_MASK;
+				if (phase > dram_info->wl_max_phase)
+					dram_info->wl_max_phase = phase;
+				if (phase < dram_info->wl_min_phase)
+					dram_info->wl_min_phase = phase;
+			}
+		}
+	}
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+		(1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+	reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+	DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - Ended Successfully\n");
+
+	return MV_OK;
+}
+
+/*
+ * Name:     ddr3_write_leveling_hw_reg_dimm
+ * Desc:     Execute Write leveling phase by HW
+ * Args:     freq      - current sequence frequency
+ *           dram_info   - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_hw_reg_dimm(u32 freq, MV_DRAM_INFO *dram_info)
+{
+	u32 reg, phase, delay, cs, pup, pup_num;
+	__maybe_unused int dpde_flag = 0;
+
+	/* Debug message - Start Read leveling procedure */
+	DEBUG_WL_S("DDR3 - Write Leveling - Starting HW WL procedure\n");
+
+	if (dram_info->num_cs > 2) {
+		DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+		return MV_NO_CHANGE;
+	}
+
+	/* If target freq = 400 move clock start point */
+	/* Write to control PUP to Control Deskew Regs */
+	if (freq <= DDR_400) {
+		for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+			/* PUP_DELAY_MASK 0x1F */
+			/* reg = 0x0C10001F + (uj << 16); */
+			ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+						0x1F);
+		}
+	}
+
+#ifdef MV88F67XX
+	/* Dynamic pad issue (BTS669) during WL */
+	reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+	if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+		dpde_flag = 1;
+		reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+			  reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+	}
+#endif
+
+	reg = (1 << REG_DRAM_TRAINING_WL_OFFS);
+	/* Config the retest number */
+	reg |= (COUNT_HW_WL << REG_DRAM_TRAINING_RETEST_OFFS);
+	reg |= (dram_info->cs_ena << (REG_DRAM_TRAINING_CS_OFFS));
+	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
+
+	reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+		(1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+	/* Wait */
+	do {
+		reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+			(1 << REG_DRAM_TRAINING_AUTO_OFFS);
+	} while (reg);		/* Wait for '0' */
+
+	reg = reg_read(REG_DRAM_TRAINING_ADDR);
+	/* Check if Successful */
+	if (reg & (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+		/*
+		 * Read results to arrays - Results are required for WL High
+		 * freq Supplement and DQS Centralization
+		 */
+		for (cs = 0; cs < MAX_CS; cs++) {
+			if (dram_info->cs_ena & (1 << cs)) {
+				for (pup = 0;
+				     pup < dram_info->num_of_total_pups;
+				     pup++) {
+					if (pup == dram_info->num_of_std_pups
+					    && dram_info->ecc_ena)
+						pup = ECC_BIT;
+					reg =
+					    ddr3_read_pup_reg(PUP_WL_MODE, cs,
+							      pup);
+					phase =
+					    (reg >> REG_PHY_PHASE_OFFS) &
+					    PUP_PHASE_MASK;
+					delay = reg & PUP_DELAY_MASK;
+					dram_info->wl_val[cs][pup][P] = phase;
+					dram_info->wl_val[cs][pup][D] = delay;
+					if ((phase == 1) && (delay >= 0x1D)) {
+						/*
+						 * Need to do it here for
+						 * uncorrect WL values
+						 */
+						ddr3_write_pup_reg(PUP_WL_MODE,
+								   cs, pup, 0,
+								   0);
+						dram_info->wl_val[cs][pup][P] =
+						    0;
+						dram_info->wl_val[cs][pup][D] =
+						    0;
+					}
+					dram_info->wl_val[cs][pup][S] =
+					    WL_HI_FREQ_STATE - 1;
+					reg =
+					    ddr3_read_pup_reg(PUP_WL_MODE + 0x1,
+							      cs, pup);
+					dram_info->wl_val[cs][pup][DQS] =
+					    (reg & 0x3F);
+				}
+#ifdef MV_DEBUG_WL
+				/*
+				 * Debug message - Print res for cs[i]:
+				 * cs,PUP,Phase,Delay
+				 */
+				DEBUG_WL_S("DDR3 - Write Leveling - Write Leveling Cs - ");
+				DEBUG_WL_D((u32) cs, 1);
+				DEBUG_WL_S(" Results:\n");
+				for (pup = 0;
+				     pup < dram_info->num_of_total_pups;
+				     pup++) {
+					DEBUG_WL_S
+					    ("DDR3 - Write Leveling - PUP: ");
+					DEBUG_WL_D((u32) pup, 1);
+					DEBUG_WL_S(", Phase: ");
+					DEBUG_WL_D((u32)
+						   dram_info->wl_val[cs][pup]
+						   [P], 1);
+					DEBUG_WL_S(", Delay: ");
+					DEBUG_WL_D((u32)
+						   dram_info->wl_val[cs][pup]
+						   [D], 2);
+					DEBUG_WL_S("\n");
+				}
+#endif
+			}
+		}
+
+#ifdef MV88F67XX
+		/* Dynamic pad issue (BTS669) during WL */
+		if (dpde_flag) {
+			reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+				(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+			reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+		}
+#endif
+		DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+
+		/* If target freq = 400 move clock back */
+		/* Write to control PUP to Control Deskew Regs */
+		if (freq <= DDR_400) {
+			for (pup = 0; pup <= dram_info->num_of_total_pups;
+			     pup++) {
+				ddr3_write_ctrl_pup_reg(1, pup,
+							CNTRL_PUP_DESKEW + pup, 0);
+			}
+		}
+
+		return MV_OK;
+	} else {
+		/* Configure Each PUP with locked leveling settings */
+		for (cs = 0; cs < MAX_CS; cs++) {
+			if (dram_info->cs_ena & (1 << cs)) {
+				for (pup = 0;
+				     pup < dram_info->num_of_total_pups;
+				     pup++) {
+					/* ECC support - bit 8 */
+					pup_num = (pup == dram_info->num_of_std_pups) ?
+						ECC_BIT : pup;
+					ddr3_write_pup_reg(PUP_WL_MODE, cs,
+							   pup_num, 0, 0);
+				}
+			}
+		}
+
+		reg_write(REG_DRAM_TRAINING_ADDR, 0);
+
+		/* If target freq = 400 move clock back */
+		/* Write to control PUP to Control Deskew Regs */
+		if (freq <= DDR_400) {
+			for (pup = 0; pup <= dram_info->num_of_total_pups;
+			     pup++) {
+				ddr3_write_ctrl_pup_reg(1, pup,
+							CNTRL_PUP_DESKEW + pup, 0);
+			}
+		}
+
+		DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+		return MV_NO_CHANGE;
+	}
+}
+
+/*
+ * Name:     ddr3_write_leveling_sw
+ * Desc:     Execute Write leveling phase by SW
+ * Args:     freq      - current sequence frequency
+ *           dram_info   - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+	u32 reg, cs, cnt, pup, max_pup_num;
+	u32 res[MAX_CS];
+	max_pup_num = dram_info->num_of_total_pups;
+	__maybe_unused int dpde_flag = 0;
+
+	/* Debug message - Start Write leveling procedure */
+	DEBUG_WL_S("DDR3 - Write Leveling - Starting SW WL procedure\n");
+
+#ifdef MV88F67XX
+	/* Dynamic pad issue (BTS669) during WL */
+	reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+	if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+		dpde_flag = 1;
+		reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+			  reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+	}
+#endif
+
+	/* Set Output buffer-off to all CS and correct ODT values */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_ODT_MASK;
+			reg |= odt_static[dram_info->cs_ena][cs];
+			reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+
+			/* 0x15D0 - DDR3 MR0 Register */
+			reg_write(REG_DDR3_MR1_ADDR, reg);
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+		}
+	}
+
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling - Qoff and RTT Values are set for all Cs\n");
+
+	/* Enable SW override */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling - SW Override Enabled\n");
+
+	/* Enable PHY write leveling mode */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+		~(1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+	/* [2] = 0 - TrnWLMode - Enable */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	/* Reset WL results arry */
+	memset(dram_info->wl_val, 0, sizeof(u32) * MAX_CS * MAX_PUP_NUM * 7);
+
+	/* Loop for each cs */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			DEBUG_WL_FULL_C("DDR3 - Write Leveling - Starting working with Cs - ",
+					(u32) cs, 1);
+			/* Refresh X9 current cs */
+			DEBUG_WL_FULL_S("DDR3 - Write Leveling - Refresh X9\n");
+			for (cnt = 0; cnt < COUNT_WL_RFRS; cnt++) {
+				reg =
+				    REG_SDRAM_OPERATION_CMD_RFRS & ~(1 <<
+								     (REG_SDRAM_OPERATION_CS_OFFS
+								      + cs));
+				/* [3-0] = 0x2 - refresh, [11-8] - enable current cs */
+				reg_write(REG_SDRAM_OPERATION_ADDR, reg);	/* 0x1418 - SDRAM Operation Register */
+
+				do {
+					reg =
+					    ((reg_read
+					      (REG_SDRAM_OPERATION_ADDR)) &
+					     REG_SDRAM_OPERATION_CMD_RFRS_DONE);
+				} while (reg);	/* Wait for '0' */
+			}
+
+			/* Configure MR1 in Cs[CsNum] - write leveling on, output buffer on */
+			DEBUG_WL_FULL_S("DDR3 - Write Leveling - Configure MR1 for current Cs: WL-on,OB-on\n");
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_OUTBUF_WL_MASK;
+			/* Set ODT Values */
+			reg &= REG_DDR3_MR1_ODT_MASK;
+			reg |= odt_static[dram_info->cs_ena][cs];
+			/* Enable WL MODE */
+			reg |= (1 << REG_DDR3_MR1_WL_ENA_OFFS);
+			/* [7]=1, [12]=0 - Output Buffer and write leveling enabled */
+			reg_write(REG_DDR3_MR1_ADDR, reg);	/* 0x15D4 - DDR3 MR1 Register */
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+
+			/* Write leveling  cs[cs] */
+			if (MV_OK !=
+			    ddr3_write_leveling_single_cs(cs, freq, ratio_2to1,
+							  (u32 *)(res + cs),
+							  dram_info)) {
+				DEBUG_WL_FULL_C("DDR3 - Write Leveling single Cs - FAILED -  Cs - ",
+						(u32) cs, 1);
+				for (pup = 0; pup < max_pup_num; pup++) {
+					if (((res[cs] >> pup) & 0x1) == 0) {
+						DEBUG_WL_C("Failed Byte : ",
+							   pup, 1);
+					}
+				}
+				return MV_FAIL;
+			}
+
+			/* Set TrnWLDeUpd - After each CS is done */
+			reg = reg_read(REG_TRAINING_WL_ADDR) |
+				(1 << REG_TRAINING_WL_CS_DONE_OFFS);
+			/* 0x16AC - Training Write leveling register */
+			reg_write(REG_TRAINING_WL_ADDR, reg);
+
+			/*
+			 * Debug message - Finished Write leveling cs[cs] -
+			 * each PUP Fail/Success
+			 */
+			DEBUG_WL_FULL_C("DDR3 - Write Leveling - Finished Cs - ", (u32) cs,
+					1);
+			DEBUG_WL_FULL_C("DDR3 - Write Leveling - The Results: 1-PUP locked, 0-PUP failed -",
+					(u32) res[cs], 3);
+
+			/*
+			 * Configure MR1 in cs[cs] - write leveling off (0),
+			 * output buffer off (1)
+			 */
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_OUTBUF_WL_MASK;
+			reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+			/* No need to sort ODT since it is same CS */
+			/* 0x15D4 - DDR3 MR1 Register */
+			reg_write(REG_DDR3_MR1_ADDR, reg);
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+		}
+	}
+
+	/* Disable WL Mode */
+	/* [2]=1 - TrnWLMode - Disable */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg |= (1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	/* Set Output buffer-on to all CS and correct ODT values */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_ODT_MASK;
+			reg &= REG_DDR3_MR1_OUTBUF_WL_MASK;
+			reg |= odt_static[dram_info->cs_ena][cs];
+
+			/* 0x15D0 - DDR3 MR1 Register */
+			reg_write(REG_DDR3_MR1_ADDR, reg);
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+		}
+	}
+
+#ifdef MV88F67XX
+	/* Dynamic pad issue (BTS669) during WL */
+	if (dpde_flag) {
+		reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+			(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+		reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+	}
+#endif
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling - Finished WL procedure for all Cs\n");
+
+	return MV_OK;
+}
+
+#if !defined(MV88F672X)
+/*
+ * Name:     ddr3_write_leveling_sw
+ * Desc:     Execute Write leveling phase by SW
+ * Args:     freq        - current sequence frequency
+ *           dram_info   - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_sw_reg_dimm(u32 freq, int ratio_2to1,
+				    MV_DRAM_INFO *dram_info)
+{
+	u32 reg, cs, cnt, pup;
+	u32 res[MAX_CS];
+	__maybe_unused int dpde_flag = 0;
+
+	/* Debug message - Start Write leveling procedure */
+	DEBUG_WL_S("DDR3 - Write Leveling - Starting SW WL procedure\n");
+
+#ifdef MV88F67XX
+	/* Dynamic pad issue (BTS669) during WL */
+	reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+	if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+		dpde_flag = 1;
+		reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+			  reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+	}
+#endif
+
+	/* If target freq = 400 move clock start point */
+	/* Write to control PUP to Control Deskew Regs */
+	if (freq <= DDR_400) {
+		for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+			/* PUP_DELAY_MASK 0x1F */
+			/* reg = 0x0C10001F + (uj << 16); */
+			ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+						0x1F);
+		}
+	}
+
+	/* Set Output buffer-off to all CS and correct ODT values */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_ODT_MASK;
+			reg |= odt_static[dram_info->cs_ena][cs];
+			reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+
+			/* 0x15D0 - DDR3 MR0 Register */
+			reg_write(REG_DDR3_MR1_ADDR, reg);
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+		}
+	}
+
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling - Qoff and RTT Values are set for all Cs\n");
+
+	/* Enable SW override */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* [0] = 1 - Enable SW override  */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling - SW Override Enabled\n");
+
+	/* Enable PHY write leveling mode */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+		~(1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+	/* [2] = 0 - TrnWLMode - Enable */
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	/* Loop for each cs */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			DEBUG_WL_FULL_C("DDR3 - Write Leveling - Starting working with Cs - ",
+					(u32) cs, 1);
+
+			/* Refresh X9 current cs */
+			DEBUG_WL_FULL_S("DDR3 - Write Leveling - Refresh X9\n");
+			for (cnt = 0; cnt < COUNT_WL_RFRS; cnt++) {
+				reg =
+				    REG_SDRAM_OPERATION_CMD_RFRS & ~(1 <<
+								     (REG_SDRAM_OPERATION_CS_OFFS
+								      + cs));
+				/* [3-0] = 0x2 - refresh, [11-8] - enable current cs */
+				reg_write(REG_SDRAM_OPERATION_ADDR, reg);	/* 0x1418 - SDRAM Operation Register */
+
+				do {
+					reg =
+					    ((reg_read
+					      (REG_SDRAM_OPERATION_ADDR)) &
+					     REG_SDRAM_OPERATION_CMD_RFRS_DONE);
+				} while (reg);	/* Wait for '0' */
+			}
+
+			/*
+			 * Configure MR1 in Cs[CsNum] - write leveling on,
+			 * output buffer on
+			 */
+			DEBUG_WL_FULL_S("DDR3 - Write Leveling - Configure MR1 for current Cs: WL-on,OB-on\n");
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_OUTBUF_WL_MASK;
+			/* Set ODT Values */
+			reg &= REG_DDR3_MR1_ODT_MASK;
+			reg |= odt_static[dram_info->cs_ena][cs];
+			/* Enable WL MODE */
+			reg |= (1 << REG_DDR3_MR1_WL_ENA_OFFS);
+			/*
+			 * [7]=1, [12]=0 - Output Buffer and write leveling
+			 * enabled
+			 */
+			/* 0x15D4 - DDR3 MR1 Register */
+			reg_write(REG_DDR3_MR1_ADDR, reg);
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+
+			/* Write leveling  cs[cs] */
+			if (MV_OK !=
+			    ddr3_write_leveling_single_cs(cs, freq, ratio_2to1,
+							  (u32 *)(res + cs),
+							  dram_info)) {
+				DEBUG_WL_FULL_C("DDR3 - Write Leveling single Cs - FAILED -  Cs - ",
+						(u32) cs, 1);
+				return MV_FAIL;
+			}
+
+			/* Set TrnWLDeUpd - After each CS is done */
+			reg = reg_read(REG_TRAINING_WL_ADDR) |
+				(1 << REG_TRAINING_WL_CS_DONE_OFFS);
+			/* 0x16AC - Training Write leveling register */
+			reg_write(REG_TRAINING_WL_ADDR, reg);
+
+			/*
+			 * Debug message - Finished Write leveling cs[cs] -
+			 * each PUP Fail/Success
+			 */
+			DEBUG_WL_FULL_C("DDR3 - Write Leveling - Finished Cs - ", (u32) cs,
+					1);
+			DEBUG_WL_FULL_C("DDR3 - Write Leveling - The Results: 1-PUP locked, 0-PUP failed -",
+					(u32) res[cs], 3);
+
+			/* Configure MR1 in cs[cs] - write leveling off (0), output buffer off (1) */
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_OUTBUF_WL_MASK;
+			reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+			/* No need to sort ODT since it is same CS */
+			/* 0x15D4 - DDR3 MR1 Register */
+			reg_write(REG_DDR3_MR1_ADDR, reg);
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+		}
+	}
+
+	/* Disable WL Mode */
+	/* [2]=1 - TrnWLMode - Disable */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg |= (1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	/* Disable SW override - Must be in a different stage */
+	/* [0]=0 - Enable SW override  */
+	reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+	reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+	/* 0x15B8 - Training SW 2 Register */
+	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+	/* Set Output buffer-on to all CS and correct ODT values */
+	for (cs = 0; cs < MAX_CS; cs++) {
+		if (dram_info->cs_ena & (1 << cs)) {
+			reg = reg_read(REG_DDR3_MR1_ADDR) &
+				REG_DDR3_MR1_ODT_MASK;
+			reg &= REG_DDR3_MR1_OUTBUF_WL_MASK;
+			reg |= odt_static[dram_info->cs_ena][cs];
+
+			/* 0x15D0 - DDR3 MR1 Register */
+			reg_write(REG_DDR3_MR1_ADDR, reg);
+			/* Issue MRS Command to current cs */
+			reg = REG_SDRAM_OPERATION_CMD_MR1 &
+				~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+			/*
+			 * [3-0] = 0x4 - MR1 Command, [11-8] -
+			 * enable current cs
+			 */
+			/* 0x1418 - SDRAM Operation Register */
+			reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+			udelay(MRS_DELAY);
+		}
+	}
+
+#ifdef MV88F67XX
+	/* Dynamic pad issue (BTS669) during WL */
+	if (dpde_flag) {
+		reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+			(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+		reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+	}
+#endif
+
+	/* If target freq = 400 move clock back */
+	/* Write to control PUP to Control Deskew Regs */
+	if (freq <= DDR_400) {
+		for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+			ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+						0);
+		}
+	}
+
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling - Finished WL procedure for all Cs\n");
+	return MV_OK;
+}
+#endif
+
+/*
+ * Name:     ddr3_write_leveling_single_cs
+ * Desc:     Execute Write leveling for single Chip select
+ * Args:     cs          - current chip select
+ *           freq        - current sequence frequency
+ *           result      - res array
+ *           dram_info   - main struct
+ * Notes:
+ * Returns:  MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_write_leveling_single_cs(u32 cs, u32 freq, int ratio_2to1,
+					 u32 *result, MV_DRAM_INFO *dram_info)
+{
+	u32 reg, pup_num, delay, phase, phaseMax, max_pup_num, pup,
+		max_pup_mask;
+
+	max_pup_num = dram_info->num_of_total_pups;
+	*result = 0;
+	u32 flag[MAX_PUP_NUM] = { 0 };
+
+	DEBUG_WL_FULL_C("DDR3 - Write Leveling Single Cs - WL for Cs - ",
+			(u32) cs, 1);
+
+	switch (max_pup_num) {
+	case 2:
+		max_pup_mask = 0x3;
+		break;
+	case 4:
+		max_pup_mask = 0xf;
+		DEBUG_WL_C("max_pup_mask =  ", max_pup_mask, 3);
+		break;
+	case 5:
+		max_pup_mask = 0x1f;
+		DEBUG_WL_C("max_pup_mask =  ", max_pup_mask, 3);
+		break;
+	case 8:
+		max_pup_mask = 0xff;
+		DEBUG_WL_C("max_pup_mask =  ", max_pup_mask, 3);
+		break;
+	case 9:
+		max_pup_mask = 0x1ff;
+		DEBUG_WL_C("max_pup_mask =  ", max_pup_mask, 3);
+		break;
+	default:
+		DEBUG_WL_C("ddr3_write_leveling_single_cs wrong max_pup_num =  ",
+			   max_pup_num, 3);
+		return MV_FAIL;
+	}
+
+	/* CS ODT Override */
+	reg = reg_read(REG_SDRAM_ODT_CTRL_HIGH_ADDR) &
+		REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK;
+	reg |= (REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA << (2 * cs));
+	/* Set 0x3 - Enable ODT on the curent cs and disable on other cs */
+	/* 0x1498 - SDRAM ODT Control high */
+	reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - ODT Asserted for current Cs\n");
+
+	/* tWLMRD Delay */
+	/* Delay of minimum 40 Dram clock cycles - 20 Tclk cycles */
+	udelay(1);
+
+	/* [1:0] - current cs number */
+	reg = (reg_read(REG_TRAINING_WL_ADDR) & REG_TRAINING_WL_CS_MASK) | cs;
+	reg |= (1 << REG_TRAINING_WL_UPD_OFFS);	/* [2] - trnWLCsUpd */
+	/* 0x16AC - Training Write leveling register */
+	reg_write(REG_TRAINING_WL_ADDR, reg);
+
+	/* Broadcast to all PUPs: Reset DQS phase, reset leveling delay */
+	ddr3_write_pup_reg(PUP_WL_MODE, cs, PUP_BC, 0, 0);
+
+	/* Seek Edge */
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Current Cs\n");
+
+	/* Drive DQS high for one cycle - All data PUPs */
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Driving DQS high for one cycle\n");
+	if (!ratio_2to1) {
+		reg = (reg_read(REG_TRAINING_WL_ADDR) &
+		       REG_TRAINING_WL_RATIO_MASK) | REG_TRAINING_WL_1TO1;
+	} else {
+		reg = (reg_read(REG_TRAINING_WL_ADDR) &
+		       REG_TRAINING_WL_RATIO_MASK) | REG_TRAINING_WL_2TO1;
+	}
+	/* 0x16AC - Training Write leveling register */
+	reg_write(REG_TRAINING_WL_ADDR, reg);
+
+	/* Wait tWLdelay */
+	do {
+		/* [29] - trnWLDelayExp */
+		reg = (reg_read(REG_TRAINING_WL_ADDR)) &
+			REG_TRAINING_WL_DELAYEXP_MASK;
+	} while (reg == 0x0);	/* Wait for '1' */
+
+	/* Read WL res */
+	reg = (reg_read(REG_TRAINING_WL_ADDR) >> REG_TRAINING_WL_RESULTS_OFFS) &
+		REG_TRAINING_WL_RESULTS_MASK;
+	/* [28:20] - TrnWLResult */
+
+	if (!ratio_2to1) /* Different phase options for 2:1 or 1:1 modes */
+		phaseMax = MAX_PHASE_1TO1;
+	else
+		phaseMax = MAX_PHASE_2TO1;
+
+	DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Shift DQS + Octet Leveling\n");
+
+	/* Shift DQS + Octet leveling */
+	for (phase = 0; phase < phaseMax; phase++) {
+		for (delay = 0; delay < MAX_DELAY; delay++) {
+			/*  Broadcast to all PUPs: DQS phase,leveling delay */
+			ddr3_write_pup_reg(PUP_WL_MODE, cs, PUP_BC, phase,
+					   delay);
+
+			udelay(1);	/* Delay of  3 Tclk cycles */
+
+			DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge: Phase = ");
+			DEBUG_WL_FULL_D((u32) phase, 1);
+			DEBUG_WL_FULL_S(", Delay = ");
+			DEBUG_WL_FULL_D((u32) delay, 1);
+			DEBUG_WL_FULL_S(", Counter = ");
+			DEBUG_WL_FULL_D((u32) i, 1);
+			DEBUG_WL_FULL_S("\n");
+
+			/* Drive DQS high for one cycle - All data PUPs */
+			if (!ratio_2to1) {
+				reg = (reg_read(REG_TRAINING_WL_ADDR) &
+				       REG_TRAINING_WL_RATIO_MASK) |
+					REG_TRAINING_WL_1TO1;
+			} else {
+				reg = (reg_read(REG_TRAINING_WL_ADDR) &
+				       REG_TRAINING_WL_RATIO_MASK) |
+					REG_TRAINING_WL_2TO1;
+			}
+			reg_write(REG_TRAINING_WL_ADDR, reg);	/* 0x16AC  */
+
+			/* Wait tWLdelay */
+			do {
+				reg = (reg_read(REG_TRAINING_WL_ADDR)) &
+					REG_TRAINING_WL_DELAYEXP_MASK;
+			} while (reg == 0x0);	/* [29] Wait for '1' */
+
+			/* Read WL res */
+			reg = reg_read(REG_TRAINING_WL_ADDR);
+			reg = (reg >> REG_TRAINING_WL_RESULTS_OFFS) &
+				REG_TRAINING_WL_RESULTS_MASK;	/* [28:20] */
+
+			DEBUG_WL_FULL_C("DDR3 - Write Leveling Single Cs - Seek Edge: Results =  ",
+					(u32) reg, 3);
+
+			/* Update State machine */
+			for (pup = 0; pup < (max_pup_num); pup++) {
+				/* ECC support - bit 8 */
+				pup_num = (pup == dram_info->num_of_std_pups) ?
+					ECC_BIT : pup;
+				if (dram_info->wl_val[cs][pup][S] == 0) {
+					/* Update phase to PUP */
+					dram_info->wl_val[cs][pup][P] = phase;
+					/* Update delay to PUP */
+					dram_info->wl_val[cs][pup][D] = delay;
+				}
+
+				if (((reg >> pup_num) & 0x1) == 0)
+					flag[pup_num] = 1;
+
+				if (((reg >> pup_num) & 0x1)
+				    && (flag[pup_num] == 1)
+				    && (dram_info->wl_val[cs][pup][S] == 0)) {
+					/*
+					 * If the PUP is locked now and in last
+					 * counter states
+					 */
+					/* Go to next state */
+					dram_info->wl_val[cs][pup][S] = 1;
+					/* Set res */
+					*result = *result | (1 << pup_num);
+				}
+			}
+
+			/* If all locked - Break the loops - Finished */
+			if (*result == max_pup_mask) {
+				phase = phaseMax;
+				delay = MAX_DELAY;
+				DEBUG_WL_S("DDR3 - Write Leveling Single Cs - Seek Edge: All Locked\n");
+			}
+		}
+	}
+
+	/* Debug message - Print res for cs[i]: cs,PUP,Phase,Delay */
+	DEBUG_WL_C("DDR3 - Write Leveling - Results for CS - ", (u32) cs, 1);
+	for (pup = 0; pup < (max_pup_num); pup++) {
+		DEBUG_WL_S("DDR3 - Write Leveling - PUP: ");
+		DEBUG_WL_D((u32) pup, 1);
+		DEBUG_WL_S(", Phase: ");
+		DEBUG_WL_D((u32) dram_info->wl_val[cs][pup][P], 1);
+		DEBUG_WL_S(", Delay: ");
+		DEBUG_WL_D((u32) dram_info->wl_val[cs][pup][D], 2);
+		DEBUG_WL_S("\n");
+	}
+
+	/* Check if some not locked and return error */
+	if (*result != max_pup_mask) {
+		DEBUG_WL_S("DDR3 - Write Leveling - ERROR - not all PUPS were locked\n");
+		return MV_FAIL;
+	}
+
+	/* Configure Each PUP with locked leveling settings */
+	for (pup = 0; pup < (max_pup_num); pup++) {
+		/* ECC support - bit 8 */
+		pup_num = (pup == dram_info->num_of_std_pups) ? ECC_BIT : pup;
+		phase = dram_info->wl_val[cs][pup][P];
+		delay = dram_info->wl_val[cs][pup][D];
+		ddr3_write_pup_reg(PUP_WL_MODE, cs, pup_num, phase, delay);
+	}
+
+	/* CS ODT Override */
+	reg =  reg_read(REG_SDRAM_ODT_CTRL_HIGH_ADDR) &
+		REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK;
+	/* 0x1498 - SDRAM ODT Control high */
+	reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+	return MV_OK;
+}
+
+/*
+ * Perform DDR3 Control PUP Indirect Write
+ */
+static void ddr3_write_ctrl_pup_reg(int bc_acc, u32 pup, u32 reg_addr, u32 data)
+{
+	u32 reg = 0;
+
+	/* Store value for write */
+	reg = (data & 0xFFFF);
+
+	/* Set bit 26 for control PHY access */
+	reg |= (1 << REG_PHY_CNTRL_OFFS);
+
+	/* Configure BC or UC access to PHYs */
+	if (bc_acc == 1)
+		reg |= (1 << REG_PHY_BC_OFFS);
+	else
+		reg |= (pup << REG_PHY_PUP_OFFS);
+
+	/* Set PHY register address to write to */
+	reg |= (reg_addr << REG_PHY_CS_OFFS);
+
+	reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg);	/* 0x16A0 */
+	reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+	reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg);	/* 0x16A0 */
+
+	do {
+		reg = (reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR)) &
+			REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+	} while (reg);		/* Wait for '0' to mark the end of the transaction */
+}
diff --git a/drivers/ddr/mvebu/xor.c b/drivers/ddr/mvebu/xor.c
new file mode 100644
index 0000000..66c96ae
--- /dev/null
+++ b/drivers/ddr/mvebu/xor.c
@@ -0,0 +1,436 @@
+/*
+ * 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 "xor.h"
+#include "xor_regs.h"
+
+static u32 xor_regs_ctrl_backup;
+static u32 xor_regs_base_backup[MAX_CS];
+static u32 xor_regs_mask_backup[MAX_CS];
+
+static void mv_xor_hal_init(u32 chan_num);
+static int mv_xor_cmd_set(u32 chan, int command);
+static int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl);
+
+void mv_sys_xor_init(MV_DRAM_INFO *dram_info)
+{
+	u32 reg, ui, base, cs_count;
+
+	xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
+	for (ui = 0; ui < MAX_CS; ui++)
+		xor_regs_base_backup[ui] = reg_read(XOR_BASE_ADDR_REG(0, ui));
+	for (ui = 0; ui < MAX_CS; ui++)
+		xor_regs_mask_backup[ui] = reg_read(XOR_SIZE_MASK_REG(0, ui));
+
+	reg = 0;
+	for (ui = 0; ui < (dram_info->num_cs + 1); 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);
+
+	/* Last window - Base - 0x40000000, Attribute 0x1E - SRAM */
+	base = (SRAM_BASE & 0xFFFF0000) | 0x1E00;
+	reg_write(XOR_BASE_ADDR_REG(0, dram_info->num_cs), base);
+	/* Last window - Size - 64 MB */
+	reg_write(XOR_SIZE_MASK_REG(0, dram_info->num_cs), 0x03FF0000);
+
+	cs_count = 0;
+	for (ui = 0; ui < MAX_CS; ui++) {
+		if (dram_info->cs_ena & (1 << ui)) {
+			/*
+			 * Window x - Base - 0x00000000, Attribute 0x0E - DRAM
+			 */
+			base = 0;
+			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 - 256 MB */
+			reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x0FFF0000);
+			cs_count++;
+		}
+	}
+
+	mv_xor_hal_init(1);
+
+	return;
+}
+
+void mv_sys_xor_finish(void)
+{
+	u32 ui;
+
+	reg_write(XOR_WINDOW_CTRL_REG(0, 0), xor_regs_ctrl_backup);
+	for (ui = 0; ui < MAX_CS; ui++)
+		reg_write(XOR_BASE_ADDR_REG(0, ui), xor_regs_base_backup[ui]);
+	for (ui = 0; ui < MAX_CS; ui++)
+		reg_write(XOR_SIZE_MASK_REG(0, 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.
+ */
+static void mv_xor_hal_init(u32 chan_num)
+{
+	u32 i;
+
+	/* Abort any XOR activity & set default configuration */
+	for (i = 0; i < chan_num; i++) {
+		mv_xor_cmd_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 OperationMode field of control register.
+ *
+ */
+static int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
+{
+	u32 val;
+
+	/* Update the XOR Engine [0..1] Configuration Registers (XExCR) */
+	val = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)))
+	    & XEXCR_OPERATION_MODE_MASK;
+	xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
+	xor_ctrl |= val;
+	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 tmp;
+
+	/* 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 */
+	tmp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+	tmp &= ~XEXCR_OPERATION_MODE_MASK;
+	tmp |= XEXCR_OPERATION_MODE_MEM_INIT;
+	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), tmp);
+
+	/*
+	 * Update the start_ptr field in XOR Engine [0..1] Destination Pointer
+	 * Register (XExDPR0)
+	 */
+	reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
+
+	/*
+	 * Update the BlockSize field in the XOR Engine[0..1] Block Size
+	 * Registers (XExBSR)
+	 */
+	reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+		  block_size);
+
+	/*
+	 * Update the field InitValL 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 InitValH 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_transfer - Transfer data from source to destination on one of
+ *                 three modes (XOR,CRC32,DMA)
+ *
+ * DESCRIPTION:
+ *       This function initiates XOR channel, according to function parameters,
+ *       in order to perform XOR or CRC32 or DMA transaction.
+ *       To gain maximum performance the user is asked to keep the following
+ *       restrictions:
+ *       1) Selected engine is available (not busy).
+ *       1) This module does not take into consideration CPU MMU issues.
+ *          In order for the XOR engine to access the appropreate source
+ *          and destination, address parameters must be given in system
+ *          physical mode.
+ *       2) This API does not take care of cache coherency issues. The source,
+ *          destination and in case of chain the descriptor list are assumed
+ *          to be cache coherent.
+ *       4) Parameters validity. For example, does size parameter exceeds
+ *          maximum byte count of descriptor mode (16M or 64K).
+ *
+ * INPUT:
+ *       chan          - XOR channel number. See MV_XOR_CHANNEL enumerator.
+ *       xor_type      - One of three: XOR, CRC32 and DMA operations.
+ *       xor_chain_ptr - address of chain pointer
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURS:
+ *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ *
+ */
+int mv_xor_transfer(u32 chan, int xor_type, u32 xor_chain_ptr)
+{
+	u32 tmp;
+
+	/* Parameter checking */
+	if (chan >= MV_XOR_MAX_CHAN) {
+		debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+		return MV_BAD_PARAM;
+	}
+
+	if (MV_ACTIVE == mv_xor_state_get(chan)) {
+		debug("%s: ERR. Channel is already active\n", __func__);
+		return MV_BUSY;
+	}
+
+	if (0x0 == xor_chain_ptr) {
+		debug("%s: ERR. xor_chain_ptr is NULL pointer\n", __func__);
+		return MV_BAD_PARAM;
+	}
+
+	/* Read configuration register and mask the operation mode field */
+	tmp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+	tmp &= ~XEXCR_OPERATION_MODE_MASK;
+
+	switch (xor_type) {
+	case MV_XOR:
+		if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_XOR_MASK)) {
+			debug("%s: ERR. Invalid chain pointer (bits [5:0] must be cleared)\n",
+			      __func__);
+			return MV_BAD_PARAM;
+		}
+
+		/* Set the operation mode to XOR */
+		tmp |= XEXCR_OPERATION_MODE_XOR;
+		break;
+
+	case MV_DMA:
+		if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_DMA_MASK)) {
+			debug("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
+			      __func__);
+			return MV_BAD_PARAM;
+		}
+
+		/* Set the operation mode to DMA */
+		tmp |= XEXCR_OPERATION_MODE_DMA;
+		break;
+
+	case MV_CRC32:
+		if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_CRC_MASK)) {
+			debug("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
+			      __func__);
+			return MV_BAD_PARAM;
+		}
+
+		/* Set the operation mode to CRC32 */
+		tmp |= XEXCR_OPERATION_MODE_CRC;
+		break;
+
+	default:
+		return MV_BAD_PARAM;
+	}
+
+	/* Write the operation mode to the register */
+	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), tmp);
+
+	/*
+	 * Update the NextDescPtr field in the XOR Engine [0..1] Next Descriptor
+	 * Pointer Register (XExNDPR)
+	 */
+	reg_write(XOR_NEXT_DESC_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+		  xor_chain_ptr);
+
+	/* 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
+ *
+ */
+int mv_xor_state_get(u32 chan)
+{
+	u32 state;
+
+	/* Parameter checking */
+	if (chan >= MV_XOR_MAX_CHAN) {
+		debug("%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_cmd_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
+ *
+ */
+static int mv_xor_cmd_set(u32 chan, int command)
+{
+	int state;
+
+	/* Parameter checking */
+	if (chan >= MV_XOR_MAX_CHAN) {
+		debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+		return MV_BAD_PARAM;
+	}
+
+	/* Get the current state */
+	state = mv_xor_state_get(chan);
+
+	/* Command is start and current state is idle */
+	if ((command == MV_START) && (state == MV_IDLE)) {
+		reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XESTART_MASK);
+		return MV_OK;
+	}
+	/* Command is stop and current state is active */
+	else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
+		reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XESTOP_MASK);
+		return MV_OK;
+	}
+	/* Command is paused and current state is active */
+	else if ((command == MV_PAUSED) && (state == MV_ACTIVE)) {
+		reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XEPAUSE_MASK);
+		return MV_OK;
+	}
+	/* Command is restart and current state is paused */
+	else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
+		reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+			    XEXACTR_XERESTART_MASK);
+		return MV_OK;
+	}
+	/* Command is stop and current state is active */
+	else if ((command == MV_STOP) && (state == MV_IDLE))
+		return MV_OK;
+
+	/* Illegal command */
+	debug("%s: ERR. Illegal command\n", __func__);
+
+	return MV_BAD_PARAM;
+}
diff --git a/drivers/ddr/mvebu/xor.h b/drivers/ddr/mvebu/xor.h
new file mode 100644
index 0000000..3536487
--- /dev/null
+++ b/drivers/ddr/mvebu/xor.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __XOR_H
+#define __XOR_H
+
+#include "ddr3_hw_training.h"
+
+#define MV_XOR_MAX_CHAN         4 /* total channels for all units together */
+
+/*
+ * 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   */
+};
+
+/*
+ * 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  */
+};
+
+/*
+ * This enumerator describes the set of state conditions.
+ * Moving from one state to other is stricted.
+ */
+enum mv_state {
+	MV_IDLE,
+	MV_ACTIVE,
+	MV_PAUSED,
+	MV_UNDEFINED_STATE
+};
+
+/* XOR descriptor structure for CRC and DMA descriptor */
+struct crc_dma_desc {
+	u32 status;		/* Successful descriptor execution indication */
+	u32 crc32_result;	/* Result of CRC-32 calculation */
+	u32 desc_cmd;		/* type of operation to be carried out on the data */
+	u32 next_desc_ptr;	/* Next descriptor address pointer */
+	u32 byte_cnt;		/* Size of source block part represented by the descriptor */
+	u32 dst_addr;		/* Destination Block address pointer (not used in CRC32 */
+	u32 src_addr0;		/* Mode: Source Block address pointer */
+	u32 src_addr1;		/* Mode: Source Block address pointer */
+} __packed;
+
+int mv_xor_state_get(u32 chan);
+void mv_sys_xor_init(MV_DRAM_INFO *dram_info);
+void mv_sys_xor_finish(void);
+int mv_xor_transfer(u32 chan, int xor_type, u32 xor_chain_ptr);
+int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size, u32 init_val_high,
+		    u32 init_val_low);
+
+#endif /* __XOR_H */
diff --git a/drivers/ddr/mvebu/xor_regs.h b/drivers/ddr/mvebu/xor_regs.h
new file mode 100644
index 0000000..884aa15
--- /dev/null
+++ b/drivers/ddr/mvebu/xor_regs.h
@@ -0,0 +1,103 @@
+/*
+ * 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)))
+
+#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 register fileds */
+
+/* XOR Engine [0..1] Configuration Registers (XExCR) */
+#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 (XExACTR) */
+#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 [0..1] Destination Pointer Register (XExDPR0) */
+#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 (XExBSR) */
+#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 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)	(MV_XOR_REGS_BASE(unit) + (0x250 + ((win) * 4)))
+#define XOR_SIZE_MASK_REG(unit, win)	(MV_XOR_REGS_BASE(unit) + (0x270 + ((win) * 4)))
+#define XOR_HIGH_ADDR_REMAP_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x290 + ((win) * 4)))
+#define XOR_ADDR_OVRD_REG(unit, win)	(MV_XOR_REGS_BASE(unit) + (0x2A0 + ((win) * 4)))
+
+#endif /* __XOR_REGS_H */
diff --git a/include/configs/db-mv784mp-gp.h b/include/configs/db-mv784mp-gp.h
index cb03e33..1683a15 100644
--- a/include/configs/db-mv784mp-gp.h
+++ b/include/configs/db-mv784mp-gp.h
@@ -11,6 +11,8 @@
  * High Level Configuration Options (easy to change)
  */
 #define CONFIG_ARMADA_XP		/* SOC Family Name */
+#define CONFIG_DB_784MP_GP		/* Board target name for DDR training */
+
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
 #define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO_LATE
@@ -65,4 +67,51 @@
  */
 #include "mv-common.h"
 
+/*
+ * Memory layout while starting into the bin_hdr via the
+ * BootROM:
+ *
+ * 0x4000.4000 - 0x4003.4000	headers space (192KiB)
+ * 0x4000.4030			bin_hdr start address
+ * 0x4003.4000 - 0x4004.7c00	BootROM memory allocations (15KiB)
+ * 0x4007.fffc			BootROM stack top
+ *
+ * The address space between 0x4007.fffc and 0x400f.fff is not locked in
+ * L2 cache thus cannot be used.
+ */
+
+/* SPL */
+/* Defines for SPL */
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_TEXT_BASE		0x40004030
+#define CONFIG_SPL_MAX_SIZE		((128 << 10) - 0x4030)
+
+#define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + (128 << 10))
+#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
+#define CONFIG_SPL_LDSCRIPT		"arch/arm/mvebu-common/u-boot-spl.lds"
+
+/* 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
+
+/* Enable DDR support in SPL (DDR3 training from Marvell bin_hdr) */
+#define CONFIG_SYS_MVEBU_DDR
+#define CONFIG_SPD_EEPROM		0x4e
+
 #endif /* _CONFIG_DB_MV7846MP_GP_H */
diff --git a/include/configs/maxbcm.h b/include/configs/maxbcm.h
index 72217bd..5999d60 100644
--- a/include/configs/maxbcm.h
+++ b/include/configs/maxbcm.h
@@ -43,6 +43,8 @@
 #define CONFIG_SF_DEFAULT_SPEED		1000000
 #define CONFIG_SF_DEFAULT_MODE		SPI_MODE_3
 #define CONFIG_SPI_FLASH_STMICRO
+#define CONFIG_SPI_FLASH_SPANSION
+#define CONFIG_SPI_FLASH_BAR
 
 /* Environment in SPI NOR flash */
 #define CONFIG_ENV_IS_IN_SPI_FLASH
@@ -65,4 +67,51 @@
  */
 #include "mv-common.h"
 
+/*
+ * Memory layout while starting into the bin_hdr via the
+ * BootROM:
+ *
+ * 0x4000.4000 - 0x4003.4000	headers space (192KiB)
+ * 0x4000.4030			bin_hdr start address
+ * 0x4003.4000 - 0x4004.7c00	BootROM memory allocations (15KiB)
+ * 0x4007.fffc			BootROM stack top
+ *
+ * The address space between 0x4007.fffc and 0x400f.fff is not locked in
+ * L2 cache thus cannot be used.
+ */
+
+/* SPL */
+/* Defines for SPL */
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_TEXT_BASE		0x40004030
+#define CONFIG_SPL_MAX_SIZE		((128 << 10) - 0x4030)
+
+#define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + (128 << 10))
+#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
+#define CONFIG_SPL_LDSCRIPT		"arch/arm/mvebu-common/u-boot-spl.lds"
+
+/* 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
+
+/* Enable DDR support in SPL (DDR3 training from Marvell bin_hdr) */
+#define CONFIG_SYS_MVEBU_DDR
+#define CONFIG_DDR_FIXED_SIZE		(1 << 20)	/* 1GiB */
+
 #endif /* _CONFIG_DB_MV7846MP_GP_H */
diff --git a/include/configs/sheevaplug.h b/include/configs/sheevaplug.h
index 21c8bda..84029cb 100644
--- a/include/configs/sheevaplug.h
+++ b/include/configs/sheevaplug.h
@@ -33,6 +33,11 @@
 #define CONFIG_LZO
 
 /*
+ * Enable device tree support
+ */
+#define CONFIG_OF_LIBFDT
+
+/*
  * Miscellaneous configurable options
  */
 #define CONFIG_SYS_HUSH_PARSER		/* use "hush" command parser */
@@ -51,6 +56,7 @@
 #define CONFIG_CMD_NAND
 #define CONFIG_CMD_PING
 #define CONFIG_CMD_USB
+
 /*
  * mv-common.h should be defined after CMD configs since it used them
  * to enable certain macros
@@ -141,6 +147,5 @@
 #define CONFIG_MTD_DEVICE               /* needed for mtdparts commands */
 #define CONFIG_MTD_PARTITIONS
 #define CONFIG_CMD_MTDPARTS
-#define CONFIG_LZO
 
 #endif /* _CONFIG_SHEEVAPLUG_H */
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index ecf3037..e4b9881 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -57,6 +57,7 @@
 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_SPL_SERIAL_SUPPORT) += drivers/serial/
 libs-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/
 libs-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/
diff --git a/tools/kwbimage.c b/tools/kwbimage.c
index 66f459a..28ce1e4 100644
--- a/tools/kwbimage.c
+++ b/tools/kwbimage.c
@@ -16,6 +16,7 @@
 #include <image.h>
 #include <stdint.h>
 #include "kwbimage.h"
+#include <config.h>
 
 #define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
 
@@ -868,6 +869,16 @@
 			sizeof(struct ext_hdr_v0);
 	} else {
 		alloc_len = image_headersz_v1(params, NULL);
+#if defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
+		if (alloc_len > CONFIG_SYS_SPI_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",
+				alloc_len, CONFIG_SYS_SPI_U_BOOT_OFFS);
+			fprintf(stderr, "Increase CONFIG_SYS_SPI_U_BOOT_OFFS!\n");
+		} else {
+			alloc_len = CONFIG_SYS_SPI_U_BOOT_OFFS;
+		}
+#endif
 	}
 
 	hdr = malloc(alloc_len);