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);