From e863f7f051687b682b948bf5c5493c8b60463113 Mon Sep 17 00:00:00 2001 From: Anton Schubert Date: Wed, 15 Jul 2015 14:50:05 +0200 Subject: arm: mvebu: add Armada XP SATA support This patch initializes the SATA address windows on Armada XP and allows it to work with the existing mvsata_ide driver. It also adds the necessary configuration for the db-mv784mp-gp board. Signed-off-by: Anton Schubert Tested-by: Stefan Roese Cc: Luka Perkov diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 1aaea67..619bc7e 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -52,6 +52,7 @@ #define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000)) #define MVEBU_EGIGA0_BASE (MVEBU_REGISTER(0x70000)) #define MVEBU_EGIGA1_BASE (MVEBU_REGISTER(0x74000)) +#define MVEBU_AXP_SATA_BASE (MVEBU_REGISTER(0xa0000)) #define MVEBU_SATA0_BASE (MVEBU_REGISTER(0xa8000)) #define MVEBU_SDIO_BASE (MVEBU_REGISTER(0xd8000)) diff --git a/drivers/block/mvsata_ide.c b/drivers/block/mvsata_ide.c index e54d564..52c1602 100644 --- a/drivers/block/mvsata_ide.c +++ b/drivers/block/mvsata_ide.c @@ -13,6 +13,8 @@ #include #elif defined(CONFIG_KIRKWOOD) #include +#elif defined(CONFIG_ARMADA_XP) +#include #endif /* SATA port registers */ @@ -90,6 +92,41 @@ struct mvsata_port_registers { #define MVSATA_STATUS_TIMEOUT -1 /* + * Registers for SATA MBUS memory windows + */ + +#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) +#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) + +/* + * Initialize SATA memory windows for Armada XP + */ + +#ifdef CONFIG_ARMADA_XP +static void mvsata_ide_conf_mbus_windows(void) +{ + const struct mbus_dram_target_info *dram; + int i; + + dram = mvebu_mbus_dram_info(); + + /* Disable windows, Set Size/Base to 0 */ + for (i = 0; i < 4; i++) { + writel(0, MVSATA_WIN_CONTROL(i)); + writel(0, MVSATA_WIN_BASE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + MVSATA_WIN_CONTROL(i)); + writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); + } +} +#endif + +/* * Initialize one MVSATAHC port: set SControl's IPM to "always active" * and DET to "reset", then wait for SStatus's DET to become "device and * comm ok" (or time out after 50 us if no device), then set SControl's @@ -137,6 +174,10 @@ int ide_preinit(void) int ret = MVSATA_STATUS_TIMEOUT; int status; +#ifdef CONFIG_ARMADA_XP + mvsata_ide_conf_mbus_windows(); +#endif + /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */ #if defined(CONFIG_SYS_ATA_IDE0_OFFSET) status = mvsata_ide_initialize_port( diff --git a/include/configs/db-mv784mp-gp.h b/include/configs/db-mv784mp-gp.h index c33a588..aeddbf9 100644 --- a/include/configs/db-mv784mp-gp.h +++ b/include/configs/db-mv784mp-gp.h @@ -27,6 +27,7 @@ #define CONFIG_CMD_DHCP #define CONFIG_CMD_ENV #define CONFIG_CMD_I2C +#define CONFIG_CMD_IDE #define CONFIG_CMD_PING #define CONFIG_CMD_SF #define CONFIG_CMD_SPI @@ -60,6 +61,34 @@ #define CONFIG_SYS_CONSOLE_INFO_QUIET /* don't print console @ startup */ #define CONFIG_SYS_ALT_MEMTEST +/* SATA support */ +#ifdef CONFIG_CMD_IDE +#define __io +#define CONFIG_IDE_PREINIT +#define CONFIG_MVSATA_IDE + +/* Needs byte-swapping for ATA data register */ +#define CONFIG_IDE_SWAP_IO + +#define CONFIG_SYS_ATA_REG_OFFSET 0x0100 /* Offset for register access */ +#define CONFIG_SYS_ATA_DATA_OFFSET 0x0100 /* Offset for data I/O */ +#define CONFIG_SYS_ATA_ALT_OFFSET 0x0100 + +/* Each 8-bit ATA register is aligned to a 4-bytes address */ +#define CONFIG_SYS_ATA_STRIDE 4 + +/* CONFIG_CMD_IDE requires some #defines for ATA registers */ +#define CONFIG_SYS_IDE_MAXBUS 2 +#define CONFIG_SYS_IDE_MAXDEVICE CONFIG_SYS_IDE_MAXBUS + +/* ATA registers base is at SATA controller base */ +#define CONFIG_SYS_ATA_BASE_ADDR MVEBU_AXP_SATA_BASE +#define CONFIG_SYS_ATA_IDE0_OFFSET 0x2000 +#define CONFIG_SYS_ATA_IDE1_OFFSET 0x4000 + +#define CONFIG_DOS_PARTITION +#endif /* CONFIG_CMD_IDE */ + /* * mv-common.h should be defined after CMD configs since it used them * to enable certain macros -- cgit v0.10.2 From ade741b3896b1a3872ff74437f04b50762d05849 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 15 Jul 2015 15:36:52 +0200 Subject: arm: mvebu: Call timer_init early before PHY and DDR init Without calling timer_init(), the xdelay() functions return immediately. We need to call timer_init() early, so that these functions work and the PHY and DDR init code works correctly. Signed-off-by: Stefan Roese Cc: Anton Schubert Cc: Luka Perkov diff --git a/arch/arm/mach-mvebu/spl.c b/arch/arm/mach-mvebu/spl.c index 402e520..ab045b0 100644 --- a/arch/arm/mach-mvebu/spl.c +++ b/arch/arm/mach-mvebu/spl.c @@ -28,6 +28,8 @@ void board_init_f(ulong dummy) preloader_console_init(); + timer_init(); + /* First init the serdes PHY's */ serdes_phy_config(); diff --git a/arch/arm/mach-mvebu/timer.c b/arch/arm/mach-mvebu/timer.c index 40c4bc2..c516c41 100644 --- a/arch/arm/mach-mvebu/timer.c +++ b/arch/arm/mach-mvebu/timer.c @@ -41,6 +41,8 @@ #define timestamp gd->arch.tbl #define lastdec gd->arch.lastinc +static int init_done; + /* Timer reload and current value registers */ struct kwtmr_val { u32 reload; /* Timer reload reg */ @@ -112,6 +114,11 @@ void __udelay(unsigned long usec) */ int timer_init(void) { + /* Only init the timer once */ + if (init_done) + return 0; + init_done = 1; + /* load value into timer */ writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR)); writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR)); -- cgit v0.10.2 From 21427708a654ca7b0af0a2a95bdd6391226b276c Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 17 Apr 2015 18:12:41 +0200 Subject: arm: mvebu: Use default reg base address for SPL on A38x On A38x switching the regs base address without running from SDRAM doesn't seem to work. So let the SPL still use the default base address and switch to the new address in the mail u-boot later. Signed-off-by: Stefan Roese diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 619bc7e..125b5f2 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -28,7 +28,17 @@ /* SOC specific definations */ #define INTREG_BASE 0xd0000000 #define INTREG_BASE_ADDR_REG (INTREG_BASE + 0x20080) +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYS_MVEBU_DDR_A38X) +/* + * On A38x switching the regs base address without running from + * SDRAM doesn't seem to work. So let the SPL still use the + * default base address and switch to the new address in the + * main u-boot later. + */ +#define SOC_REGS_PHY_BASE 0xd0000000 +#else #define SOC_REGS_PHY_BASE 0xf1000000 +#endif #define MVEBU_REGISTER(x) (SOC_REGS_PHY_BASE + x) #define MVEBU_SDRAM_SCRATCH (MVEBU_REGISTER(0x01504)) -- cgit v0.10.2 From e3cccf9eb2ed6e25d603272719bf0cad5561826c Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 17 Apr 2015 18:13:06 +0200 Subject: arm: mvebu: spl.c: Add call to board_early_init_f() Pin muxing needs to be done before UART output, since on A38x the UART pins need some re-muxing for output to work. Signed-off-by: Stefan Roese diff --git a/arch/arm/mach-mvebu/spl.c b/arch/arm/mach-mvebu/spl.c index ab045b0..e65f6ca 100644 --- a/arch/arm/mach-mvebu/spl.c +++ b/arch/arm/mach-mvebu/spl.c @@ -26,6 +26,13 @@ void board_init_f(ulong dummy) /* Linux expects the internal registers to be at 0xf1000000 */ arch_cpu_init(); + /* + * Pin muxing needs to be done before UART output, since + * on A38x the UART pins need some re-muxing for output + * to work. + */ + board_early_init_f(); + preloader_console_init(); timer_init(); -- cgit v0.10.2 From 9f62b44ec7afabd2eea7d3bde14b6542739be249 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 24 Apr 2015 10:49:11 +0200 Subject: arm: mvebu: Disable MMU before changing register base address Only with disabled MMU its possible to switch the base register address on Armada 38x. Without this the SDRAM located at >= 0x4000.0000 is also not accessible, as its still locked to cache. Signed-off-by: Stefan Roese diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 9bc9f00..9496d5f 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -163,6 +163,14 @@ static void update_sdram_window_sizes(void) } } +void mmu_disable(void) +{ + asm volatile( + "mrc p15, 0, r0, c1, c0, 0\n" + "bic r0, #1\n" + "mcr p15, 0, r0, c1, c0, 0\n"); +} + #ifdef CONFIG_ARCH_CPU_INIT static void set_cbar(u32 addr) { @@ -172,6 +180,16 @@ static void set_cbar(u32 addr) int arch_cpu_init(void) { +#ifndef CONFIG_SPL_BUILD + /* + * Only with disabled MMU its possible to switch the base + * register address on Armada 38x. Without this the SDRAM + * located at >= 0x4000.0000 is also not accessible, as its + * still locked to cache. + */ + mmu_disable(); +#endif + /* Linux expects the internal registers to be at 0xf1000000 */ writel(SOC_REGS_PHY_BASE, INTREG_BASE_ADDR_REG); set_cbar(SOC_REGS_PHY_BASE + 0xC000); -- cgit v0.10.2 From c25012b9af1e217958ee74dc8d26742cec613860 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 20 Apr 2015 11:17:16 +0200 Subject: Makefile: Fix mvebu build target to use SPL load and exe-address The u-boot-spl.kwb build target needs the SPL text-base (CONFIG_SPL_TEXT_BASE) as load and execution address. Signed-off-by: Stefan Roese diff --git a/Makefile b/Makefile index b6f83a5..9ca0a56 100644 --- a/Makefile +++ b/Makefile @@ -887,7 +887,7 @@ 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) + -T kwbimage -a $(CONFIG_SPL_TEXT_BASE) -e $(CONFIG_SPL_TEXT_BASE) MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \ -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage -- cgit v0.10.2 From 29b103c733f6c17ecf8ee8d66140254788e2bdda Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 20 Apr 2015 09:28:12 +0200 Subject: arm: mvebu: serdes: Move Armada XP SERDES / PHY init code into new directory With the upcoming addition of the Armada 38x SPL support, which is not compatible to the Armada XP SERDES init code, we need to introduce a new directory infrastructure. So lets move the AXP serdes init code into a new directory. This way the A38x code can be added in a clean way. Signed-off-by: Stefan Roese diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 4f477cd..9cdbefd 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -20,5 +20,6 @@ obj-y += timer.o obj-$(CONFIG_SPL_BUILD) += spl.o obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o -obj-y += serdes/ +obj-$(CONFIG_SYS_MVEBU_DDR_AXP) += serdes/axp/ + endif diff --git a/arch/arm/mach-mvebu/serdes/Makefile b/arch/arm/mach-mvebu/serdes/Makefile deleted file mode 100644 index a380fee..0000000 --- a/arch/arm/mach-mvebu/serdes/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# 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/mach-mvebu/serdes/axp/Makefile b/arch/arm/mach-mvebu/serdes/axp/Makefile new file mode 100644 index 0000000..a380fee --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/axp/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/mach-mvebu/serdes/axp/board_env_spec.h b/arch/arm/mach-mvebu/serdes/axp/board_env_spec.h new file mode 100644 index 0000000..36e0ed8 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/axp/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/mach-mvebu/serdes/axp/high_speed_env_lib.c b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c new file mode 100644 index 0000000..702273a --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c @@ -0,0 +1,1572 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/mach-mvebu/serdes/axp/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c new file mode 100644 index 0000000..115ec2c --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/mach-mvebu/serdes/axp/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h new file mode 100644 index 0000000..e5aa1b0 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/axp/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/mach-mvebu/serdes/board_env_spec.h b/arch/arm/mach-mvebu/serdes/board_env_spec.h deleted file mode 100644 index 36e0ed8..0000000 --- a/arch/arm/mach-mvebu/serdes/board_env_spec.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * 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/mach-mvebu/serdes/high_speed_env_lib.c b/arch/arm/mach-mvebu/serdes/high_speed_env_lib.c deleted file mode 100644 index 702273a..0000000 --- a/arch/arm/mach-mvebu/serdes/high_speed_env_lib.c +++ /dev/null @@ -1,1572 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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/mach-mvebu/serdes/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/high_speed_env_spec.c deleted file mode 100644 index 115ec2c..0000000 --- a/arch/arm/mach-mvebu/serdes/high_speed_env_spec.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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/mach-mvebu/serdes/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/high_speed_env_spec.h deleted file mode 100644 index e5aa1b0..0000000 --- a/arch/arm/mach-mvebu/serdes/high_speed_env_spec.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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/board/maxbcm/maxbcm.c b/board/maxbcm/maxbcm.c index 2fbb90c..119ba4c 100644 --- a/board/maxbcm/maxbcm.c +++ b/board/maxbcm/maxbcm.c @@ -11,8 +11,8 @@ #include #include -#include "../drivers/ddr/mvebu/ddr3_hw_training.h" -#include "../arch/arm/mach-mvebu/serdes/high_speed_env_spec.h" +#include "../drivers/ddr/marvell/axp/ddr3_hw_training.h" +#include "../arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h" DECLARE_GLOBAL_DATA_PTR; -- cgit v0.10.2 From edb470253346f4a882ba9e891c8b102ce388b9cc Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 20 Apr 2015 09:31:27 +0200 Subject: arm: mvebu: Add Armada 38x SERDES / PHY init code from Marvell bin_hdr This code is ported from the Marvell bin_hdr code into mainline SPL U-Boot. It needs to be executed very early so that the devices connected to the serdes PHY are configured correctly. Signed-off-by: Stefan Roese diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 9cdbefd..446ce04 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -20,6 +20,7 @@ obj-y += timer.o obj-$(CONFIG_SPL_BUILD) += spl.o obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o +obj-$(CONFIG_SYS_MVEBU_DDR_A38X) += serdes/a38x/ obj-$(CONFIG_SYS_MVEBU_DDR_AXP) += serdes/axp/ endif diff --git a/arch/arm/mach-mvebu/serdes/a38x/Makefile b/arch/arm/mach-mvebu/serdes/a38x/Makefile new file mode 100644 index 0000000..1503da8 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/Makefile @@ -0,0 +1,10 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_SPL_BUILD) = ctrl_pex.o +obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec.o +obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec-38x.o +obj-$(CONFIG_SPL_BUILD) += high_speed_topology_spec-38x.o +obj-$(CONFIG_SPL_BUILD) += seq_exec.o +obj-$(CONFIG_SPL_BUILD) += sys_env_lib.o diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c new file mode 100644 index 0000000..5f223f9 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ctrl_pex.h" +#include "sys_env_lib.h" + +int hws_pex_config(struct serdes_map *serdes_map) +{ + u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg, + temp_reg, addr, dev_id, ctrl_mode; + enum serdes_type serdes_type; + u32 idx, max_lane_num; + + DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n"); + + max_lane_num = hws_serdes_get_max_lane(); + for (idx = 0; idx < max_lane_num; idx++) { + serdes_type = serdes_map[idx].serdes_type; + /* configuration for PEX only */ + if ((serdes_type != PEX0) && (serdes_type != PEX1) && + (serdes_type != PEX2) && (serdes_type != PEX3)) + continue; + + if ((serdes_type != PEX0) && + ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || + (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { + /* for PEX by4 - relevant for the first port only */ + continue; + } + + pex_idx = serdes_type - PEX0; + tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx)); + tmp &= ~(0xf << 20); + tmp |= (0x4 << 20); + reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp); + } + + tmp = reg_read(SOC_CTRL_REG); + tmp &= ~0x03; + + for (idx = 0; idx < max_lane_num; idx++) { + serdes_type = serdes_map[idx].serdes_type; + if ((serdes_type != PEX0) && + ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || + (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { + /* for PEX by4 - relevant for the first port only */ + continue; + } + + switch (serdes_type) { + case PEX0: + tmp |= 0x1 << PCIE0_ENABLE_OFFS; + break; + case PEX1: + tmp |= 0x1 << PCIE1_ENABLE_OFFS; + break; + case PEX2: + tmp |= 0x1 << PCIE2_ENABLE_OFFS; + break; + case PEX3: + tmp |= 0x1 << PCIE3_ENABLE_OFFS; + break; + default: + break; + } + } + + reg_write(SOC_CTRL_REG, tmp); + + /* Support gen1/gen2 */ + DEBUG_INIT_FULL_S("Support gen1/gen2\n"); + next_busno = 0; + mdelay(150); + + for (idx = 0; idx < max_lane_num; idx++) { + serdes_type = serdes_map[idx].serdes_type; + DEBUG_INIT_FULL_S(" serdes_type=0x"); + DEBUG_INIT_FULL_D(serdes_type, 8); + DEBUG_INIT_FULL_S("\n"); + DEBUG_INIT_FULL_S(" idx=0x"); + DEBUG_INIT_FULL_D(idx, 8); + DEBUG_INIT_FULL_S("\n"); + + /* Configuration for PEX only */ + if ((serdes_type != PEX0) && (serdes_type != PEX1) && + (serdes_type != PEX2) && (serdes_type != PEX3)) + continue; + + if ((serdes_type != PEX0) && + ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || + (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { + /* for PEX by4 - relevant for the first port only */ + continue; + } + + pex_idx = serdes_type - PEX0; + tmp = reg_read(PEX_DBG_STATUS_REG(pex_idx)); + + first_busno = next_busno; + if ((tmp & 0x7f) != 0x7e) { + DEBUG_INIT_S("PCIe, Idx "); + DEBUG_INIT_D(pex_idx, 1); + DEBUG_INIT_S(": detected no link\n"); + continue; + } + + next_busno++; + temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS + (pex_idx, PEX_LINK_CAPABILITY_REG))); + temp_pex_reg &= 0xf; + if (temp_pex_reg != 0x2) + continue; + + temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS( + pex_idx, + PEX_LINK_CTRL_STAT_REG)) & + 0xf0000) >> 16; + + /* Check if the link established is GEN1 */ + DEBUG_INIT_FULL_S + ("Checking if the link established is gen1\n"); + if (temp_reg != 0x1) + continue; + + pex_local_bus_num_set(pex_idx, first_busno); + pex_local_dev_num_set(pex_idx, 1); + DEBUG_INIT_FULL_S("PCIe, Idx "); + DEBUG_INIT_FULL_D(pex_idx, 1); + + DEBUG_INIT_S(":** Link is Gen1, check the EP capability\n"); + /* link is Gen1, check the EP capability */ + addr = pex_config_read(pex_idx, first_busno, 0, 0, 0x34) & 0xff; + DEBUG_INIT_FULL_C("pex_config_read: return addr=0x%x", addr, 4); + if (addr == 0xff) { + DEBUG_INIT_FULL_C + ("pex_config_read: return 0xff -->PCIe (%d): Detected No Link.", + pex_idx, 1); + continue; + } + + while ((pex_config_read(pex_idx, first_busno, 0, 0, addr) + & 0xff) != 0x10) { + addr = (pex_config_read(pex_idx, first_busno, 0, + 0, addr) & 0xff00) >> 8; + } + + /* Check for Gen2 and above */ + if ((pex_config_read(pex_idx, first_busno, 0, 0, + addr + 0xc) & 0xf) < 0x2) { + DEBUG_INIT_S("PCIe, Idx "); + DEBUG_INIT_D(pex_idx, 1); + DEBUG_INIT_S(": remains Gen1\n"); + continue; + } + + tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx)); + DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); + tmp &= ~(BIT(0) | BIT(1)); + tmp |= BIT(1); + tmp |= BIT(6); /* Select Deemphasize (-3.5d_b) */ + reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); + DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); + + tmp = reg_read(PEX_CTRL_REG(pex_idx)); + DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp); + tmp |= BIT(10); + reg_write(PEX_CTRL_REG(pex_idx), tmp); + DEBUG_WR_REG(PEX_CTRL_REG(pex_idx), tmp); + + /* + * We need to wait 10ms before reading the PEX_DBG_STATUS_REG + * in order not to read the status of the former state + */ + mdelay(10); + + DEBUG_INIT_S("PCIe, Idx "); + DEBUG_INIT_D(pex_idx, 1); + DEBUG_INIT_S + (": Link upgraded to Gen2 based on client cpabilities\n"); + } + + /* Update pex DEVICE ID */ + ctrl_mode = sys_env_model_get(); + + for (idx = 0; idx < max_lane_num; idx++) { + serdes_type = serdes_map[idx].serdes_type; + /* configuration for PEX only */ + if ((serdes_type != PEX0) && (serdes_type != PEX1) && + (serdes_type != PEX2) && (serdes_type != PEX3)) + continue; + + if ((serdes_type != PEX0) && + ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || + (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { + /* for PEX by4 - relevant for the first port only */ + continue; + } + + pex_idx = serdes_type - PEX0; + dev_id = reg_read(PEX_CFG_DIRECT_ACCESS + (pex_idx, PEX_DEVICE_AND_VENDOR_ID)); + dev_id &= 0xffff; + dev_id |= ((ctrl_mode << 16) & 0xffff0000); + reg_write(PEX_CFG_DIRECT_ACCESS + (pex_idx, PEX_DEVICE_AND_VENDOR_ID), dev_id); + } + DEBUG_INIT_FULL_C("Update PEX Device ID ", ctrl_mode, 4); + + return MV_OK; +} + +int pex_local_bus_num_set(u32 pex_if, u32 bus_num) +{ + u32 pex_status; + + DEBUG_INIT_FULL_S("\n### pex_local_bus_num_set ###\n"); + + if (bus_num >= MAX_PEX_BUSSES) { + DEBUG_INIT_C("pex_local_bus_num_set: Illegal bus number %d\n", + bus_num, 4); + return MV_BAD_PARAM; + } + + pex_status = reg_read(PEX_STATUS_REG(pex_if)); + pex_status &= ~PXSR_PEX_BUS_NUM_MASK; + pex_status |= + (bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK; + reg_write(PEX_STATUS_REG(pex_if), pex_status); + + return MV_OK; +} + +int pex_local_dev_num_set(u32 pex_if, u32 dev_num) +{ + u32 pex_status; + + DEBUG_INIT_FULL_S("\n### pex_local_dev_num_set ###\n"); + + pex_status = reg_read(PEX_STATUS_REG(pex_if)); + pex_status &= ~PXSR_PEX_DEV_NUM_MASK; + pex_status |= + (dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK; + reg_write(PEX_STATUS_REG(pex_if), pex_status); + + return MV_OK; +} + +/* + * pex_config_read - Read from configuration space + * + * DESCRIPTION: + * This function performs a 32 bit read from PEX configuration space. + * It supports both type 0 and type 1 of Configuration Transactions + * (local and over bridge). In order to read from local bus segment, use + * bus number retrieved from pex_local_bus_num_get(). Other bus numbers + * will result configuration transaction of type 1 (over bridge). + * + * INPUT: + * pex_if - PEX interface number. + * bus - PEX segment bus number. + * dev - PEX device number. + * func - Function number. + * reg_offs - Register offset. + * + * OUTPUT: + * None. + * + * RETURN: + * 32bit register data, 0xffffffff on error + */ +u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off) +{ + u32 pex_data = 0; + u32 local_dev, local_bus; + u32 pex_status; + + pex_status = reg_read(PEX_STATUS_REG(pex_if)); + local_dev = + ((pex_status & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS); + local_bus = + ((pex_status & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS); + + /* + * In PCI Express we have only one device number + * and this number is the first number we encounter + * else that the local_dev + * spec pex define return on config read/write on any device + */ + if (bus == local_bus) { + if (local_dev == 0) { + /* + * if local dev is 0 then the first number we encounter + * after 0 is 1 + */ + if ((dev != 1) && (dev != local_dev)) + return MV_ERROR; + } else { + /* + * if local dev is not 0 then the first number we + * encounter is 0 + */ + if ((dev != 0) && (dev != local_dev)) + return MV_ERROR; + } + } + + /* Creating PEX address to be passed */ + pex_data = (bus << PXCAR_BUS_NUM_OFFS); + pex_data |= (dev << PXCAR_DEVICE_NUM_OFFS); + pex_data |= (func << PXCAR_FUNC_NUM_OFFS); + /* Legacy register space */ + pex_data |= (reg_off & PXCAR_REG_NUM_MASK); + /* Extended register space */ + pex_data |= (((reg_off & PXCAR_REAL_EXT_REG_NUM_MASK) >> + PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS); + pex_data |= PXCAR_CONFIG_EN; + + /* Write the address to the PEX configuration address register */ + reg_write(PEX_CFG_ADDR_REG(pex_if), pex_data); + + /* + * In order to let the PEX controller absorbed the address + * of the read transaction we perform a validity check that + * the address was written + */ + if (pex_data != reg_read(PEX_CFG_ADDR_REG(pex_if))) + return MV_ERROR; + + /* Cleaning Master Abort */ + reg_bit_set(PEX_CFG_DIRECT_ACCESS(pex_if, PEX_STATUS_AND_COMMAND), + PXSAC_MABORT); + /* Read the Data returned in the PEX Data register */ + pex_data = reg_read(PEX_CFG_DATA_REG(pex_if)); + + DEBUG_INIT_FULL_C(" --> ", pex_data, 4); + + return pex_data; +} diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h new file mode 100644 index 0000000..5032759 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _CTRL_PEX_H +#define _CTRL_PEX_H + +#include "high_speed_env_spec.h" + +/* Sample at Reset */ +#define MPP_SAMPLE_AT_RESET(id) (0xe4200 + (id * 4)) + +/* PCI Express Control and Status Registers */ +#define MAX_PEX_BUSSES 256 + +#define MISC_REGS_OFFSET 0x18200 +#define MV_MISC_REGS_BASE MISC_REGS_OFFSET +#define SOC_CTRL_REG (MV_MISC_REGS_BASE + 0x4) + +#define PEX_CAPABILITIES_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x60) +#define PEX_LINK_CTRL_STATUS2_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x90) +#define PEX_CTRL_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a00) +#define PEX_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a04) +#define PEX_DBG_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a64) +#define PEX_LINK_CAPABILITY_REG 0x6c +#define PEX_LINK_CTRL_STAT_REG 0x70 +#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */ +#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS) +#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */ +#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS) + +/* PEX_CAPABILITIES_REG fields */ +#define PCIE0_ENABLE_OFFS 0 +#define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS) +#define PCIE1_ENABLE_OFFS 1 +#define PCIE1_ENABLE_MASK (0x1 << PCIE1_ENABLE_OFFS) +#define PCIE2_ENABLE_OFFS 2 +#define PCIE2_ENABLE_MASK (0x1 << PCIE2_ENABLE_OFFS) +#define PCIE3_ENABLE_OFFS 3 +#define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS) + +/* Controller revision info */ +#define PEX_DEVICE_AND_VENDOR_ID 0x000 + +/* PCI Express Configuration Address Register */ +#define PXCAR_REG_NUM_OFFS 2 +#define PXCAR_REG_NUM_MAX 0x3f +#define PXCAR_REG_NUM_MASK (PXCAR_REG_NUM_MAX << \ + PXCAR_REG_NUM_OFFS) +#define PXCAR_FUNC_NUM_OFFS 8 +#define PXCAR_FUNC_NUM_MAX 0x7 +#define PXCAR_FUNC_NUM_MASK (PXCAR_FUNC_NUM_MAX << \ + PXCAR_FUNC_NUM_OFFS) +#define PXCAR_DEVICE_NUM_OFFS 11 +#define PXCAR_DEVICE_NUM_MAX 0x1f +#define PXCAR_DEVICE_NUM_MASK (PXCAR_DEVICE_NUM_MAX << \ + PXCAR_DEVICE_NUM_OFFS) +#define PXCAR_BUS_NUM_OFFS 16 +#define PXCAR_BUS_NUM_MAX 0xff +#define PXCAR_BUS_NUM_MASK (PXCAR_BUS_NUM_MAX << \ + PXCAR_BUS_NUM_OFFS) +#define PXCAR_EXT_REG_NUM_OFFS 24 +#define PXCAR_EXT_REG_NUM_MAX 0xf + +#define PEX_CFG_ADDR_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18f8) +#define PEX_CFG_DATA_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18fc) + +#define PXCAR_REAL_EXT_REG_NUM_OFFS 8 +#define PXCAR_REAL_EXT_REG_NUM_MASK (0xf << PXCAR_REAL_EXT_REG_NUM_OFFS) + +#define PXCAR_CONFIG_EN BIT(31) +#define PEX_STATUS_AND_COMMAND 0x004 +#define PXSAC_MABORT BIT(29) /* Recieved Master Abort */ + +int hws_pex_config(struct serdes_map *serdes_map); +int pex_local_bus_num_set(u32 pex_if, u32 bus_num); +int pex_local_dev_num_set(u32 pex_if, u32 dev_num); +u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off); + +#endif diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c new file mode 100644 index 0000000..5ff8567 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "high_speed_env_spec.h" +#include "sys_env_lib.h" + +#define SERDES_VERION "2.0" + +u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = { + /* 0 1 2 3 4 5 */ + {0x1, 0x1, NA, NA, NA, NA}, /* PEX0 */ + {NA, 0x2, 0x1, NA, 0x1, NA}, /* PEX1 */ + {NA, NA, 0x2, NA, NA, 0x1}, /* PEX2 */ + {NA, NA, NA, 0x1, NA, NA}, /* PEX3 */ + {0x2, 0x3, NA, NA, NA, NA}, /* SATA0 */ + {NA, NA, 0x3, NA, 0x2, NA}, /* SATA1 */ + {NA, NA, NA, NA, 0x6, 0x2}, /* SATA2 */ + {NA, NA, NA, 0x3, NA, NA}, /* SATA3 */ + {0x3, 0x4, NA, NA, NA, NA}, /* SGMII0 */ + {NA, 0x5, 0x4, NA, 0x3, NA}, /* SGMII1 */ + {NA, NA, NA, 0x4, NA, 0x3}, /* SGMII2 */ + {NA, 0x7, NA, NA, NA, NA}, /* QSGMII */ + {NA, 0x6, NA, NA, 0x4, NA}, /* USB3_HOST0 */ + {NA, NA, NA, 0x5, NA, 0x4}, /* USB3_HOST1 */ + {NA, NA, NA, 0x6, 0x5, 0x5}, /* USB3_DEVICE */ + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0} /* DEFAULT_SERDES */ +}; + +int hws_serdes_seq_init(void) +{ + DEBUG_INIT_FULL_S("\n### serdes_seq_init ###\n"); + + if (hws_serdes_seq_db_init() != MV_OK) { + printf("hws_serdes_seq_init: Error: Serdes initialization fail\n"); + return MV_FAIL; + } + + return MV_OK; +} + +int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up, + enum serdes_type serdes_type, + enum serdes_speed baud_rate, + enum serdes_mode serdes_mode, + enum ref_clock ref_clock) +{ + return MV_NOT_SUPPORTED; +} + +u32 hws_serdes_silicon_ref_clock_get(void) +{ + DEBUG_INIT_FULL_S("\n### hws_serdes_silicon_ref_clock_get ###\n"); + + return REF_CLOCK_25MHZ; +} + +u32 hws_serdes_get_max_lane(void) +{ + switch (sys_env_device_id_get()) { + case MV_6811: /* A381/A3282: 6811/6821: single/dual cpu */ + return 4; + case MV_6810: + return 5; + case MV_6820: + case MV_6828: + return 6; + default: /* not the right module */ + printf("%s: Device ID Error, using 4 SerDes lanes\n", + __func__); + return 4; + } + return 6; +} + +int hws_is_serdes_active(u8 lane_num) +{ + int ret = 1; + + /* Maximum lane count for A388 (6828) is 6 */ + if (lane_num > 6) + ret = 0; + + /* 4th Lane (#4 on Device 6810 is not Active */ + if (sys_env_device_id_get() == MV_6810 && lane_num == 4) { + printf("%s: Error: Lane#4 on Device 6810 is not Active.\n", + __func__); + return 0; + } + + /* + * 6th Lane (#5) on Device 6810 is Active, even though 6810 + * has only 5 lanes + */ + if (sys_env_device_id_get() == MV_6810 && lane_num == 5) + return 1; + + if (lane_num >= hws_serdes_get_max_lane()) + ret = 0; + + return ret; +} + +int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset, + u32 *unit_base_reg, u32 *unit_offset) +{ + *unit_base_reg = base_addr; + *unit_offset = unit_base_offset; + + return MV_OK; +} + +/* + * hws_serdes_get_phy_selector_val + * + * DESCRIPTION: Get the mapping of Serdes Selector values according to the + * Serdes revision number + * INPUT: serdes_num - Serdes number + * serdes_type - Serdes type + * OUTPUT: None + * RETURN: + * Mapping of Serdes Selector values + */ +u32 hws_serdes_get_phy_selector_val(int serdes_num, + enum serdes_type serdes_type) +{ + if (serdes_type >= LAST_SERDES_TYPE) + return 0xff; + + if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) { + return selectors_serdes_rev1_map + [serdes_type][serdes_num]; + } else + return selectors_serdes_rev2_map + [serdes_type][serdes_num]; +} + +u32 hws_get_physical_serdes_num(u32 serdes_num) +{ + if ((serdes_num == 4) && (sys_env_device_id_get() == MV_6810)) { + /* + * For 6810, there are 5 Serdes and Serdes Num 4 doesn't + * exist. Instead Serdes Num 5 is connected. + */ + return 5; + } else { + return serdes_num; + } +} diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c new file mode 100644 index 0000000..23af769 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c @@ -0,0 +1,2228 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "high_speed_env_spec.h" +#include "high_speed_topology_spec.h" +#include "sys_env_lib.h" +#include "ctrl_pex.h" + +#if defined(CONFIG_ARMADA_38X) +#elif defined(CONFIG_ARMADA_39X) +#else +#error "No device is defined" +#endif + +/* + * The board topology map, initialized in the beginning of + * ctrl_high_speed_serdes_phy_config + */ +struct serdes_map serdes_configuration_map[MAX_SERDES_LANES]; + +/* + * serdes_seq_db - holds all serdes sequences, their size and the + * relevant index in the data array initialized in serdes_seq_init + */ +struct cfg_seq serdes_seq_db[SERDES_LAST_SEQ]; + +#define SERDES_VERION "2.0" +#define ENDED_OK "High speed PHY - Ended Successfully\n" + +#define LINK_WAIT_CNTR 100 +#define LINK_WAIT_SLEEP 100 + +#define MAX_UNIT_NUMB 4 +#define TOPOLOGY_TEST_OK 0 +#define WRONG_NUMBER_OF_UNITS 1 +#define SERDES_ALREADY_IN_USE 2 +#define UNIT_NUMBER_VIOLATION 3 + +/* + * serdes_lane_in_use_count contains the exact amount of serdes lanes + * needed per type + */ +u8 serdes_lane_in_use_count[MAX_UNITS_ID][MAX_UNIT_NUMB] = { + /* 0 1 2 3 */ + { 1, 1, 1, 1 }, /* PEX */ + { 1, 1, 1, 1 }, /* ETH_GIG */ + { 1, 1, 0, 0 }, /* USB3H */ + { 1, 1, 1, 0 }, /* USB3D */ + { 1, 1, 1, 1 }, /* SATA */ + { 1, 0, 0, 0 }, /* QSGMII */ + { 4, 0, 0, 0 }, /* XAUI */ + { 2, 0, 0, 0 } /* RXAUI */ +}; + +/* + * serdes_unit_count count unit number. + * (i.e a single XAUI is counted as 1 unit) + */ +u8 serdes_unit_count[MAX_UNITS_ID] = { 0 }; + +/* Selector mapping for A380-A0 and A390-Z1 */ +u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = { + /* 0 1 2 3 4 5 6 */ + { 0x1, 0x1, NA, NA, NA, NA, NA }, /* PEX0 */ + { NA, NA, 0x1, NA, 0x1, NA, 0x1 }, /* PEX1 */ + { NA, NA, NA, NA, 0x7, 0x1, NA }, /* PEX2 */ + { NA, NA, NA, 0x1, NA, NA, NA }, /* PEX3 */ + { 0x2, 0x3, NA, NA, NA, NA, NA }, /* SATA0 */ + { NA, NA, 0x3, NA, NA, NA, NA }, /* SATA1 */ + { NA, NA, NA, NA, 0x6, 0x2, NA }, /* SATA2 */ + { NA, NA, NA, 0x3, NA, NA, NA }, /* SATA3 */ + { 0x3, 0x4, NA, NA, NA, NA, NA }, /* SGMII0 */ + { NA, 0x5, 0x4, NA, 0x3, NA, NA }, /* SGMII1 */ + { NA, NA, NA, 0x4, NA, 0x3, NA }, /* SGMII2 */ + { NA, 0x7, NA, NA, NA, NA, NA }, /* QSGMII */ + { NA, 0x6, NA, NA, 0x4, NA, NA }, /* USB3_HOST0 */ + { NA, NA, NA, 0x5, NA, 0x4, NA }, /* USB3_HOST1 */ + { NA, NA, NA, 0x6, 0x5, 0x5, NA }, /* USB3_DEVICE */ +#ifdef CONFIG_ARMADA_39X + { NA, NA, 0x5, NA, 0x8, NA, 0x2 }, /* SGMII3 */ + { NA, NA, NA, 0x8, 0x9, 0x8, 0x4 }, /* XAUI */ + { NA, NA, NA, NA, NA, 0x8, 0x4 }, /* RXAUI */ +#endif + { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, NA } /* DEFAULT_SERDES */ +}; + +/* Selector mapping for PEX by 4 confiuration */ +u8 common_phys_selectors_pex_by4_lanes[] = { 0x1, 0x2, 0x2, 0x2 }; + +static const char *const serdes_type_to_string[] = { + "PCIe0", + "PCIe1", + "PCIe2", + "PCIe3", + "SATA0", + "SATA1", + "SATA2", + "SATA3", + "SGMII0", + "SGMII1", + "SGMII2", + "QSGMII", + "USB3 HOST0", + "USB3 HOST1", + "USB3 DEVICE", + "SGMII3", + "XAUI", + "RXAUI", + "DEFAULT SERDES", + "LAST_SERDES_TYPE" +}; + +struct serdes_unit_data { + u8 serdes_unit_id; + u8 serdes_unit_num; +}; + +static struct serdes_unit_data serdes_type_to_unit_info[] = { + {PEX_UNIT_ID, 0,}, + {PEX_UNIT_ID, 1,}, + {PEX_UNIT_ID, 2,}, + {PEX_UNIT_ID, 3,}, + {SATA_UNIT_ID, 0,}, + {SATA_UNIT_ID, 1,}, + {SATA_UNIT_ID, 2,}, + {SATA_UNIT_ID, 3,}, + {ETH_GIG_UNIT_ID, 0,}, + {ETH_GIG_UNIT_ID, 1,}, + {ETH_GIG_UNIT_ID, 2,}, + {QSGMII_UNIT_ID, 0,}, + {USB3H_UNIT_ID, 0,}, + {USB3H_UNIT_ID, 1,}, + {USB3D_UNIT_ID, 0,}, + {ETH_GIG_UNIT_ID, 3,}, + {XAUI_UNIT_ID, 0,}, + {RXAUI_UNIT_ID, 0,}, +}; + +/* Sequences DB */ + +/* + * SATA and SGMII + */ + +struct op_params sata_port0_power_up_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, wait_time, + * num_of_loops + */ + /* Access to reg 0x48(OOB param 1) */ + {SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0}, + /* OOB Com_wake and Com_reset spacing upper limit data */ + {SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0}, + /* Access to reg 0xa(PHY Control) */ + {SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0}, + /* Rx clk and Tx clk select non-inverted mode */ + {SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0}, + /* Power Down Sata addr */ + {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0}, + /* Power Down Sata Port 0 */ + {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40040,}, 0, 0}, +}; + +struct op_params sata_port1_power_up_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, wait_time, + * num_of_loops + */ + /* Access to reg 0x48(OOB param 1) */ + {SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0}, + /* OOB Com_wake and Com_reset spacing upper limit data */ + {SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0}, + /* Access to reg 0xa(PHY Control) */ + {SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0}, + /* Rx clk and Tx clk select non-inverted mode */ + {SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0}, + /* Power Down Sata addr */ + {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0}, + /* Power Down Sata Port 1 */ + {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc44000,}, 0, 0}, +}; + +/* SATA and SGMII - power up seq */ +struct op_params sata_and_sgmii_power_up_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, SGMII data, + * wait_time, num_of_loops + */ + /* Power Up */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x90006, {0x80002, 0x80002}, + 0, 0}, + /* Unreset */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0x6000}, 0, 0}, + /* Phy Selector */ + {POWER_AND_PLL_CTRL_REG, 0x800, 0x0e0, {0x0, 0x80}, 0, 0}, + /* Ref clock source select */ + {MISC_REG, 0x800, 0x440, {0x440, 0x400}, 0, 0} +}; + +/* SATA and SGMII - speed config seq */ +struct op_params sata_and_sgmii_speed_config_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, + * SGMII (1.25G), SGMII (3.125G), wait_time, num_of_loops + */ + /* Baud Rate */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000, + {0x8800000, 0x19800000, 0x22000000}, 0, 0}, + /* Select Baud Rate for SATA only */ + {INTERFACE_REG, 0x800, 0xc00, {0x800, NO_DATA, NO_DATA}, 0, 0}, + /* Phy Gen RX and TX */ + {ISOLATE_REG, 0x800, 0xff, {NO_DATA, 0x66, 0x66}, 0, 0}, + /* Bus Width */ + {LOOPBACK_REG, 0x800, 0xe, {0x4, 0x2, 0x2}, 0, 0} +}; + +/* SATA and SGMII - TX config seq */ +struct op_params sata_and_sgmii_tx_config_params1[] = { + /* + * unitunit_base_reg, unit_offset, mask, SATA data, SGMII data, + * wait_time, num_of_loops + */ + {GLUE_REG, 0x800, 0x1800, {NO_DATA, 0x800}, 0, 0}, + /* Sft Reset pulse */ + {RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0}, + /* Sft Reset pulse */ + {RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0}, + /* Power up PLL, RX and TX */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0000, {0x70000, 0x70000}, + 0, 0} +}; + +struct op_params sata_port0_tx_config_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, wait_time, + * num_of_loops + */ + /* Power Down Sata addr */ + {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0}, + /* Power Down Sata Port 0 */ + {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40000}, 0, 0}, + /* Regret bit addr */ + {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0}, + /* Regret bit data */ + {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0} +}; + +struct op_params sata_port1_tx_config_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, wait_time, + * num_of_loops + */ + /* Power Down Sata addr */ + {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0}, + /* Power Down Sata Port 1 */ + {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc40000}, 0, 0}, + /* Regret bit addr */ + {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0}, + /* Regret bit data */ + {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0} +}; + +struct op_params sata_and_sgmii_tx_config_serdes_rev1_params2[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, SGMII data, + * wait_time, num_of_loops + */ + /* Wait for PHY power up sequence to finish */ + {COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000}, + /* Wait for PHY power up sequence to finish */ + {COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000} +}; + +struct op_params sata_and_sgmii_tx_config_serdes_rev2_params2[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, SGMII data, + * wait_time, num_of_loops + */ + /* Wait for PHY power up sequence to finish */ + {COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000}, + /* Assert Rx Init for SGMII */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x40000000}, + 0, 0}, + /* Assert Rx Init for SATA */ + {ISOLATE_REG, 0x800, 0x400, {0x400, NA}, 0, 0}, + /* Wait for PHY power up sequence to finish */ + {COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000}, + /* De-assert Rx Init for SGMII */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x0}, 0, 0}, + /* De-assert Rx Init for SATA */ + {ISOLATE_REG, 0x800, 0x400, {0x0, NA}, 0, 0}, + /* os_ph_offset_force (align 90) */ + {RX_REG3, 0x800, 0xff, {0xde, NO_DATA}, 0, 0}, + /* Set os_ph_valid */ + {RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0}, + /* Unset os_ph_valid */ + {RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0}, +}; + +struct op_params sata_electrical_config_serdes_rev1_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, wait_time, + * num_of_loops + */ + /* enable SSC and DFE update enable */ + {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000,}, 0, 0}, + /* tximpcal_th and rximpcal_th */ + {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000,}, 0, 0}, + /* SQ_THRESH and FFE Setting */ + {SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x6cf,}, 0, 0}, + /* G1_TX SLEW, EMPH1 and AMP */ + {G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32,}, 0, 0}, + /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9,}, 0, 0}, + /* G2_TX SLEW, EMPH1 and AMP */ + {G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c,}, 0, 0}, + /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0}, + /* G3_TX SLEW, EMPH1 and AMP */ + {G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e,}, 0, 0}, + /* G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G3_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0}, + /* Cal rxclkalign90 ext enable and Cal os ph ext */ + {CAL_REG6, 0x800, 0xff00, {0xdd00,}, 0, 0}, + /* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */ + {RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0}, +}; + +struct op_params sata_electrical_config_serdes_rev2_params[] = { + /* + * unit_base_reg, unit_offset, mask, SATA data, wait_time, + * num_of_loops + */ + /* SQ_THRESH and FFE Setting */ + {SQUELCH_FFE_SETTING_REG, 0x800, 0xf00, {0x600}, 0, 0}, + /* enable SSC and DFE update enable */ + {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000}, 0, 0}, + /* G1_TX SLEW, EMPH1 and AMP */ + {G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32}, 0, 0}, + /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, + /* G2_TX SLEW, EMPH1 and AMP */ + {G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c}, 0, 0}, + /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0}, + /* G3_TX SLEW, EMPH1 and AMP */ + {G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e}, 0, 0}, + /* + * G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI & DFE_En Gen3, + * DC wander calibration dis + */ + {G3_SETTINGS_1_REG, 0x800, 0x47ff, {0x7d2}, 0, 0}, + /* Bit[12]=0x0 idle_sync_en */ + {PCIE_REG0, 0x800, 0x1000, {0x0}, 0, 0}, + /* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */ + {RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0}, + /* tximpcal_th and rximpcal_th */ + {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0}, + /* DFE_STEP_FINE_FX[3:0] =0xa */ + {DFE_REG0, 0x800, 0xa00f, {0x800a}, 0, 0}, + /* DFE_EN and Dis Update control from pin disable */ + {DFE_REG3, 0x800, 0xc000, {0x0}, 0, 0}, + /* FFE Force FFE_REs and cap settings for Gen1 */ + {G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0}, + /* FFE Force FFE_REs and cap settings for Gen2 */ + {G2_SETTINGS_3_REG, 0x800, 0xff, {0xbf}, 0, 0}, + /* FE Force FFE_REs=4 and cap settings for Gen3n */ + {G3_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0}, + /* Set DFE Gen 3 Resolution to 3 */ + {G3_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0}, +}; + +struct op_params sgmii_electrical_config_serdes_rev1_params[] = { + /* + * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G), + * wait_time, num_of_loops + */ + /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0}, + /* SQ_THRESH and FFE Setting */ + {SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x8f, 0xbf}, 0, 0}, + /* tximpcal_th and rximpcal_th */ + {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000, 0x4000}, 0, 0}, +}; + +struct op_params sgmii_electrical_config_serdes_rev2_params[] = { + /* + * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G), + * wait_time, num_of_loops + */ + /* Set Slew_rate, Emph and Amp */ + {G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8fa, 0x8fa}, 0, 0}, + /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0}, + /* DTL_FLOOP_EN */ + {RX_REG2, 0x800, 0x4, {0x0, 0x0}, 0, 0}, + /* G1 FFE Setting Force, RES and CAP */ + {G1_SETTINGS_3_REG, 0x800, 0xff, {0x8f, 0xbf}, 0, 0}, + /* tximpcal_th and rximpcal_th */ + {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000, 0x3000}, 0, 0}, +}; + +/* + * PEX and USB3 + */ + +/* PEX and USB3 - power up seq for Serdes Rev 1.2 */ +struct op_params pex_and_usb3_power_up_serdes_rev1_params[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, USB3 data, + * wait_time, num_of_loops + */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806, + {0x4471804, 0x4479804}, 0, 0}, + {COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0}, + {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0}, + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0}, + {GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0}, + /* Ref clock source select */ + {MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0} +}; + +/* PEX and USB3 - power up seq for Serdes Rev 2.1 */ +struct op_params pex_and_usb3_power_up_serdes_rev2_params[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, USB3 data, + * wait_time, num_of_loops + */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806, + {0x4471804, 0x4479804}, 0, 0}, + {COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0}, + {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0}, + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0}, + {GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0}, + {GLOBAL_MISC_CTRL, 0x800, 0xc0, {0x0, NO_DATA}, 0, 0}, + /* Ref clock source select */ + {MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0} +}; + +/* PEX and USB3 - speed config seq */ +struct op_params pex_and_usb3_speed_config_params[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, USB3 data, + * wait_time, num_of_loops + */ + /* Maximal PHY Generation Setting */ + {INTERFACE_REG, 0x800, 0xc00, {0x400, 0x400, 0x400, 0x400, 0x400}, + 0, 0}, +}; + +struct op_params usb3_electrical_config_serdes_rev1_params[] = { + /* Spread Spectrum Clock Enable */ + {LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0}, + /* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */ + {G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0}, + /* tximpcal_th and rximpcal_th */ + {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000}, 0, 0}, + /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0}, + /* FFE Setting Force, RES and CAP */ + {SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xef}, 0, 0}, + /* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */ + {RX_REG2, 0x800, 0xf0, {0x70}, 0, 0}, + /* cal_rxclkalign90_ext_en and cal_os_ph_ext */ + {CAL_REG6, 0x800, 0xff00, {0xd500}, 0, 0}, + /* vco_cal_vth_sel */ + {REF_REG0, 0x800, 0x38, {0x20}, 0, 0}, +}; + +struct op_params usb3_electrical_config_serdes_rev2_params[] = { + /* Spread Spectrum Clock Enable */ + {LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0}, + /* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */ + {G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0}, + /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0}, + /* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */ + {RX_REG2, 0x800, 0xf0, {0x70}, 0, 0}, + /* vco_cal_vth_sel */ + {REF_REG0, 0x800, 0x38, {0x20}, 0, 0}, + /* Spread Spectrum Clock Enable */ + {LANE_CFG5_REG, 0x800, 0x4, {0x4}, 0, 0}, +}; + +/* PEX and USB3 - TX config seq */ + +/* + * For PEXx1: the pex_and_usb3_tx_config_params1/2/3 configurations should run + * one by one on the lane. + * For PEXx4: the pex_and_usb3_tx_config_params1/2/3 configurations should run + * by setting each sequence for all 4 lanes. + */ +struct op_params pex_and_usb3_tx_config_params1[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, USB3 data, + * wait_time, num_of_loops + */ + {GLOBAL_CLK_CTRL, 0x800, 0x1, {0x0, 0x0}, 0, 0}, + /* 10ms delay */ + {0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0}, + /* os_ph_offset_force (align 90) */ + {RX_REG3, 0x800, 0xff, {0xdc, NO_DATA}, 0, 0}, + /* Set os_ph_valid */ + {RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0}, + /* Unset os_ph_valid */ + {RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0}, +}; + +struct op_params pex_and_usb3_tx_config_params2[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, USB3 data, + * wait_time, num_of_loops + */ + /* Sft Reset pulse */ + {RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0}, +}; + +struct op_params pex_and_usb3_tx_config_params3[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, USB3 data, + * wait_time, num_of_loops + */ + /* Sft Reset pulse */ + {RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0}, + /* 10ms delay */ + {0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0} +}; + +/* PEX by 4 config seq */ +struct op_params pex_by4_config_params[] = { + /* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */ + {GLOBAL_CLK_SRC_HI, 0x800, 0x7, {0x5, 0x0, 0x0, 0x2}, 0, 0}, + /* Lane Alignement enable */ + {LANE_ALIGN_REG0, 0x800, 0x1000, {0x0, 0x0, 0x0, 0x0}, 0, 0}, + /* Max PLL phy config */ + {CALIBRATION_CTRL_REG, 0x800, 0x1000, {0x1000, 0x1000, 0x1000, 0x1000}, + 0, 0}, + /* Max PLL pipe config */ + {LANE_CFG1_REG, 0x800, 0x600, {0x600, 0x600, 0x600, 0x600}, 0, 0}, +}; + +/* USB3 device donfig seq */ +struct op_params usb3_device_config_params[] = { + /* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */ + {LANE_CFG4_REG, 0x800, 0x200, {0x200}, 0, 0} +}; + +/* PEX - electrical configuration seq Rev 1.2 */ +struct op_params pex_electrical_config_serdes_rev1_params[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, wait_time, + * num_of_loops + */ + /* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */ + {G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0}, + /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, + /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, + /* CFG_DFE_EN_SEL */ + {LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0}, + /* FFE Setting Force, RES and CAP */ + {SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xaf}, 0, 0}, + /* tximpcal_th and rximpcal_th */ + {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0}, + /* cal_rxclkalign90_ext_en and cal_os_ph_ext */ + {CAL_REG6, 0x800, 0xff00, {0xdc00}, 0, 0}, +}; + +/* PEX - electrical configuration seq Rev 2.1 */ +struct op_params pex_electrical_config_serdes_rev2_params[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, wait_time, + * num_of_loops + */ + /* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */ + {G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0}, + /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, + /* G1 FFE Setting Force, RES and CAP */ + {G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0}, + /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ + {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, + /* G2 FFE Setting Force, RES and CAP */ + {G2_SETTINGS_3_REG, 0x800, 0xff, {0xaf}, 0, 0}, + /* G2 DFE resolution value */ + {G2_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0}, + /* DFE resolution force */ + {DFE_REG0, 0x800, 0x8000, {0x8000}, 0, 0}, + /* Tx amplitude for Tx Margin 0 */ + {PCIE_REG1, 0x800, 0xf80, {0xd00}, 0, 0}, + /* Tx_Emph value for -3.5d_b and -6d_b */ + {PCIE_REG3, 0x800, 0xff00, {0xaf00}, 0, 0}, + /* CFG_DFE_EN_SEL */ + {LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0}, + /* tximpcal_th and rximpcal_th */ + {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0}, +}; + +/* PEX - configuration seq for REF_CLOCK_25MHz */ +struct op_params pex_config_ref_clock25_m_hz[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, wait_time, + * num_of_loops + */ + /* Bits[4:0]=0x2 - REF_FREF_SEL */ + {POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x2}, 0, 0}, + /* Bit[10]=0x1 - REFCLK_SEL */ + {MISC_REG, 0x800, 0x400, {0x400}, 0, 0}, + /* Bits[7:0]=0x7 - CFG_PM_RXDLOZ_WAIT */ + {GLOBAL_PM_CTRL, 0x800, 0xff, {0x7}, 0, 0}, +}; + +/* PEX - configuration seq for REF_CLOCK_40MHz */ +struct op_params pex_config_ref_clock40_m_hz[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, wait_time, + * num_of_loops + */ + /* Bits[4:0]=0x3 - REF_FREF_SEL */ + {POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x3}, 0, 0}, + /* Bits[10]=0x1 - REFCLK_SEL */ + {MISC_REG, 0x800, 0x400, {0x400}, 0, 0}, + /* Bits[7:0]=0xc - CFG_PM_RXDLOZ_WAIT */ + {GLOBAL_PM_CTRL, 0x800, 0xff, {0xc}, 0, 0}, +}; + +/* PEX - configuration seq for REF_CLOCK_100MHz */ +struct op_params pex_config_ref_clock100_m_hz[] = { + /* + * unit_base_reg, unit_offset, mask, PEX data, wait_time, + * num_of_loops + */ + /* Bits[4:0]=0x0 - REF_FREF_SEL */ + {POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x0}, 0, 0}, + /* Bit[10]=0x0 - REFCLK_SEL */ + {MISC_REG, 0x800, 0x400, {0x0}, 0, 0}, + /* Bits[7:0]=0x1e - CFG_PM_RXDLOZ_WAIT */ + {GLOBAL_PM_CTRL, 0x800, 0xff, {0x1e}, 0, 0}, +}; + +/* + * USB2 + */ + +struct op_params usb2_power_up_params[] = { + /* + * unit_base_reg, unit_offset, mask, USB2 data, wait_time, + * num_of_loops + */ + /* Init phy 0 */ + {0x18440, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0}, + /* Init phy 1 */ + {0x18444, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0}, + /* Init phy 2 */ + {0x18448, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0}, + /* Phy offset 0x0 - PLL_CONTROL0 */ + {0xc0000, 0x0 /*NA*/, 0xffffffff, {0x40605205}, 0, 0}, + {0xc001c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0}, + {0xc201c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0}, + {0xc401c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0}, + /* Phy offset 0x1 - PLL_CONTROL1 */ + {0xc0004, 0x0 /*NA*/, 0x1, {0x1}, 0, 0}, + /* Phy0 register 3 - TX Channel control 0 */ + {0xc000c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0}, + /* Phy0 register 3 - TX Channel control 0 */ + {0xc200c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0}, + /* Phy0 register 3 - TX Channel control 0 */ + {0xc400c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0}, + /* check PLLCAL_DONE is set and IMPCAL_DONE is set */ + {0xc0008, 0x0 /*NA*/, 0x80800000, {0x80800000}, 1, 1000}, + /* check REG_SQCAL_DONE is set */ + {0xc0018, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000}, + /* check PLL_READY is set */ + {0xc0000, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000} +}; + +/* + * QSGMII + */ + +/* QSGMII - power up seq */ +struct op_params qsgmii_port_power_up_params[] = { + /* + * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, + * num_of_loops + */ + /* Connect the QSGMII to Gigabit Ethernet units */ + {QSGMII_CONTROL_REG1, 0x0, 0x40000000, {0x40000000}, 0, 0}, + /* Power Up */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0006, {0x80002}, 0, 0}, + /* Unreset */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000}, 0, 0}, + /* Phy Selector */ + {POWER_AND_PLL_CTRL_REG, 0x800, 0xff, {0xfc81}, 0, 0}, + /* Ref clock source select */ + {MISC_REG, 0x800, 0x4c0, {0x480}, 0, 0} +}; + +/* QSGMII - speed config seq */ +struct op_params qsgmii_port_speed_config_params[] = { + /* + * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, + * num_of_loops + */ + /* Baud Rate */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000, {0xcc00000}, 0, 0}, + /* Phy Gen RX and TX */ + {ISOLATE_REG, 0x800, 0xff, {0x33}, 0, 0}, + /* Bus Width */ + {LOOPBACK_REG, 0x800, 0xe, {0x2}, 0, 0} +}; + +/* QSGMII - Select electrical param seq */ +struct op_params qsgmii_port_electrical_config_params[] = { + /* + * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, + * num_of_loops + */ + /* Slew rate and emphasis */ + {G1_SETTINGS_0_REG, 0x800, 0x8000, {0x0}, 0, 0} +}; + +/* QSGMII - TX config seq */ +struct op_params qsgmii_port_tx_config_params1[] = { + /* + * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, + * num_of_loops + */ + {GLUE_REG, 0x800, 0x1800, {0x800}, 0, 0}, + /* Sft Reset pulse */ + {RESET_DFE_REG, 0x800, 0x401, {0x401}, 0, 0}, + /* Sft Reset pulse */ + {RESET_DFE_REG, 0x800, 0x401, {0x0}, 0, 0}, + /* Lane align */ + {LANE_ALIGN_REG0, 0x800, 0x1000, {0x1000}, 0, 0}, + /* Power up PLL, RX and TX */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x70000, {0x70000}, 0, 0}, + /* Tx driver output idle */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x80000, {0x80000}, 0, 0} +}; + +struct op_params qsgmii_port_tx_config_params2[] = { + /* + * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, + * num_of_loops + */ + /* Wait for PHY power up sequence to finish */ + {COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc}, 10, 1000}, + /* Assert Rx Init and Tx driver output valid */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40080000, {0x40000000}, 0, 0}, + /* Wait for PHY power up sequence to finish */ + {COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1}, 1, 1000}, + /* De-assert Rx Init */ + {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {0x0}, 0, 0} +}; + +/* SERDES_POWER_DOWN */ +struct op_params serdes_power_down_params[] = { + {COMMON_PHY_CONFIGURATION1_REG, 0x28, (0xf << 11), {(0x3 << 11)}, + 0, 0}, + {COMMON_PHY_CONFIGURATION1_REG, 0x28, (0x7 << 16), {0}, 0, 0} +}; + +/* + * hws_ctrl_serdes_rev_get + * + * DESCRIPTION: Get the Serdes revision number + * + * INPUT: config_field - Field description enum + * + * OUTPUT: None + * + * RETURN: + * 8bit Serdes revision number + */ +u8 hws_ctrl_serdes_rev_get(void) +{ +#ifdef CONFIG_ARMADA_38X + /* for A38x-Z1 */ + if (sys_env_device_rev_get() == MV_88F68XX_Z1_ID) + return MV_SERDES_REV_1_2; +#endif + + /* for A39x-Z1, A38x-A0 */ + return MV_SERDES_REV_2_1; +} + +u32 hws_serdes_topology_verify(enum serdes_type serdes_type, u32 serdes_id, + enum serdes_mode serdes_mode) +{ + u32 test_result = 0; + u8 serd_max_num, unit_numb; + enum unit_id unit_id; + + if (serdes_type > RXAUI) { + printf("%s: Warning: Wrong serdes type %s serdes#%d\n", + __func__, serdes_type_to_string[serdes_type], serdes_id); + return MV_FAIL; + } + + unit_id = serdes_type_to_unit_info[serdes_type].serdes_unit_id; + unit_numb = serdes_type_to_unit_info[serdes_type].serdes_unit_num; + serd_max_num = sys_env_unit_max_num_get(unit_id); + + /* if didn't exceed amount of required Serdes lanes for current type */ + if (serdes_lane_in_use_count[unit_id][unit_numb] != 0) { + /* update amount of required Serdes lanes for current type */ + serdes_lane_in_use_count[unit_id][unit_numb]--; + + /* + * If reached the exact amount of required Serdes lanes for + * current type + */ + if (serdes_lane_in_use_count[unit_id][unit_numb] == 0) { + if (((serdes_type <= PEX3)) && + ((serdes_mode == PEX_END_POINT_X4) || + (serdes_mode == PEX_ROOT_COMPLEX_X4))) { + /* PCiex4 uses 2 SerDes */ + serdes_unit_count[PEX_UNIT_ID] += 2; + } else { + serdes_unit_count[unit_id]++; + } + + /* test SoC unit count limitation */ + if (serdes_unit_count[unit_id] > serd_max_num) { + test_result = WRONG_NUMBER_OF_UNITS; + } else if (unit_numb >= serd_max_num) { + /* test SoC unit number limitation */ + test_result = UNIT_NUMBER_VIOLATION; + } + } + } else { + test_result = SERDES_ALREADY_IN_USE; + if (test_result == SERDES_ALREADY_IN_USE) { + printf("%s: Error: serdes lane %d is configured to type %s: type already in use\n", + __func__, serdes_id, + serdes_type_to_string[serdes_type]); + return MV_FAIL; + } else if (test_result == WRONG_NUMBER_OF_UNITS) { + printf("%s: Warning: serdes lane %d is set to type %s.\n", + __func__, serdes_id, + serdes_type_to_string[serdes_type]); + printf("%s: Maximum supported lanes are already set to this type (limit = %d)\n", + __func__, serd_max_num); + return MV_FAIL; + } else if (test_result == UNIT_NUMBER_VIOLATION) { + printf("%s: Warning: serdes lane %d type is %s: current device support only %d units of this type.\n", + __func__, serdes_id, + serdes_type_to_string[serdes_type], + serd_max_num); + return MV_FAIL; + } + } + + return MV_OK; +} + +void hws_serdes_xaui_topology_verify(void) +{ + /* + * If XAUI is in use - serdes_lane_in_use_count has to be = 0; + * if it is not in use hast be = 4 + */ + if ((serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 0) && + (serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 4)) { + printf("%s: Warning: wrong number of lanes is set to XAUI - %d\n", + __func__, serdes_lane_in_use_count[XAUI_UNIT_ID][0]); + printf("%s: XAUI has to be defined on 4 lanes\n", __func__); + } + + /* + * If RXAUI is in use - serdes_lane_in_use_count has to be = 0; + * if it is not in use hast be = 2 + */ + if ((serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 0) && + (serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 2)) { + printf("%s: Warning: wrong number of lanes is set to RXAUI - %d\n", + __func__, serdes_lane_in_use_count[RXAUI_UNIT_ID][0]); + printf("%s: RXAUI has to be defined on 2 lanes\n", __func__); + } +} + +int hws_serdes_seq_db_init(void) +{ + u8 serdes_rev = hws_ctrl_serdes_rev_get(); + + DEBUG_INIT_FULL_S("\n### serdes_seq38x_init ###\n"); + + if (serdes_rev == MV_SERDES_REV_NA) { + printf("hws_serdes_seq_db_init: serdes revision number is not supported\n"); + return MV_NOT_SUPPORTED; + } + + /* SATA_PORT_0_ONLY_POWER_UP_SEQ sequence init */ + serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].op_params_ptr = + sata_port0_power_up_params; + serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].cfg_seq_size = + sizeof(sata_port0_power_up_params) / sizeof(struct op_params); + serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].data_arr_idx = SATA; + + /* SATA_PORT_1_ONLY_POWER_UP_SEQ sequence init */ + serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].op_params_ptr = + sata_port1_power_up_params; + serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].cfg_seq_size = + sizeof(sata_port1_power_up_params) / sizeof(struct op_params); + serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].data_arr_idx = SATA; + + /* SATA_POWER_UP_SEQ sequence init */ + serdes_seq_db[SATA_POWER_UP_SEQ].op_params_ptr = + sata_and_sgmii_power_up_params; + serdes_seq_db[SATA_POWER_UP_SEQ].cfg_seq_size = + sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params); + serdes_seq_db[SATA_POWER_UP_SEQ].data_arr_idx = SATA; + + /* SATA_1_5_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].op_params_ptr = + sata_and_sgmii_speed_config_params; + serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_and_sgmii_speed_config_params) / + sizeof(struct op_params); + serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].data_arr_idx = SATA; + + /* SATA_3_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].op_params_ptr = + sata_and_sgmii_speed_config_params; + serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_and_sgmii_speed_config_params) / + sizeof(struct op_params); + serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].data_arr_idx = SATA; + + /* SATA_6_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].op_params_ptr = + sata_and_sgmii_speed_config_params; + serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_and_sgmii_speed_config_params) / + sizeof(struct op_params); + serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].data_arr_idx = SATA; + + /* SATA_ELECTRICAL_CONFIG_SEQ seq sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + sata_electrical_config_serdes_rev1_params; + serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_electrical_config_serdes_rev1_params) / + sizeof(struct op_params); + } else { + serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + sata_electrical_config_serdes_rev2_params; + serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_electrical_config_serdes_rev2_params) / + sizeof(struct op_params); + } + serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SATA; + + /* SATA_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[SATA_TX_CONFIG_SEQ1].op_params_ptr = + sata_and_sgmii_tx_config_params1; + serdes_seq_db[SATA_TX_CONFIG_SEQ1].cfg_seq_size = + sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params); + serdes_seq_db[SATA_TX_CONFIG_SEQ1].data_arr_idx = SATA; + + /* SATA_PORT_0_ONLY_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].op_params_ptr = + sata_port0_tx_config_params; + serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_port0_tx_config_params) / sizeof(struct op_params); + serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA; + + /* SATA_PORT_1_ONLY_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].op_params_ptr = + sata_port1_tx_config_params; + serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_port1_tx_config_params) / sizeof(struct op_params); + serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA; + + /* SATA_TX_CONFIG_SEQ2 sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr = + sata_and_sgmii_tx_config_serdes_rev1_params2; + serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size = + sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) / + sizeof(struct op_params); + } else { + serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr = + sata_and_sgmii_tx_config_serdes_rev2_params2; + serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size = + sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) / + sizeof(struct op_params); + } + serdes_seq_db[SATA_TX_CONFIG_SEQ2].data_arr_idx = SATA; + + /* SGMII_POWER_UP_SEQ sequence init */ + serdes_seq_db[SGMII_POWER_UP_SEQ].op_params_ptr = + sata_and_sgmii_power_up_params; + serdes_seq_db[SGMII_POWER_UP_SEQ].cfg_seq_size = + sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params); + serdes_seq_db[SGMII_POWER_UP_SEQ].data_arr_idx = SGMII; + + /* SGMII_1_25_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].op_params_ptr = + sata_and_sgmii_speed_config_params; + serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_and_sgmii_speed_config_params) / + sizeof(struct op_params); + serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].data_arr_idx = SGMII; + + /* SGMII_3_125_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].op_params_ptr = + sata_and_sgmii_speed_config_params; + serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(sata_and_sgmii_speed_config_params) / + sizeof(struct op_params); + serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].data_arr_idx = SGMII_3_125; + + /* SGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + sgmii_electrical_config_serdes_rev1_params; + serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(sgmii_electrical_config_serdes_rev1_params) / + sizeof(struct op_params); + } else { + serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + sgmii_electrical_config_serdes_rev2_params; + serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(sgmii_electrical_config_serdes_rev2_params) / + sizeof(struct op_params); + } + serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SGMII; + + /* SGMII_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[SGMII_TX_CONFIG_SEQ1].op_params_ptr = + sata_and_sgmii_tx_config_params1; + serdes_seq_db[SGMII_TX_CONFIG_SEQ1].cfg_seq_size = + sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params); + serdes_seq_db[SGMII_TX_CONFIG_SEQ1].data_arr_idx = SGMII; + + /* SGMII_TX_CONFIG_SEQ sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr = + sata_and_sgmii_tx_config_serdes_rev1_params2; + serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size = + sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) / + sizeof(struct op_params); + } else { + serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr = + sata_and_sgmii_tx_config_serdes_rev2_params2; + serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size = + sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) / + sizeof(struct op_params); + } + serdes_seq_db[SGMII_TX_CONFIG_SEQ2].data_arr_idx = SGMII; + + /* PEX_POWER_UP_SEQ sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr = + pex_and_usb3_power_up_serdes_rev1_params; + serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_power_up_serdes_rev1_params) / + sizeof(struct op_params); + } else { + serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr = + pex_and_usb3_power_up_serdes_rev2_params; + serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_power_up_serdes_rev2_params) / + sizeof(struct op_params); + } + serdes_seq_db[PEX_POWER_UP_SEQ].data_arr_idx = PEX; + + /* PEX_2_5_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].op_params_ptr = + pex_and_usb3_speed_config_params; + serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); + serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].data_arr_idx = + PEXSERDES_SPEED_2_5_GBPS; + + /* PEX_5_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].op_params_ptr = + pex_and_usb3_speed_config_params; + serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); + serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].data_arr_idx = + PEXSERDES_SPEED_5_GBPS; + + /* PEX_ELECTRICAL_CONFIG_SEQ seq sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + pex_electrical_config_serdes_rev1_params; + serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(pex_electrical_config_serdes_rev1_params) / + sizeof(struct op_params); + } else { + serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + pex_electrical_config_serdes_rev2_params; + serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(pex_electrical_config_serdes_rev2_params) / + sizeof(struct op_params); + } + serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].data_arr_idx = PEX; + + /* PEX_TX_CONFIG_SEQ1 sequence init */ + serdes_seq_db[PEX_TX_CONFIG_SEQ1].op_params_ptr = + pex_and_usb3_tx_config_params1; + serdes_seq_db[PEX_TX_CONFIG_SEQ1].cfg_seq_size = + sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params); + serdes_seq_db[PEX_TX_CONFIG_SEQ1].data_arr_idx = PEX; + + /* PEX_TX_CONFIG_SEQ2 sequence init */ + serdes_seq_db[PEX_TX_CONFIG_SEQ2].op_params_ptr = + pex_and_usb3_tx_config_params2; + serdes_seq_db[PEX_TX_CONFIG_SEQ2].cfg_seq_size = + sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params); + serdes_seq_db[PEX_TX_CONFIG_SEQ2].data_arr_idx = PEX; + + /* PEX_TX_CONFIG_SEQ3 sequence init */ + serdes_seq_db[PEX_TX_CONFIG_SEQ3].op_params_ptr = + pex_and_usb3_tx_config_params3; + serdes_seq_db[PEX_TX_CONFIG_SEQ3].cfg_seq_size = + sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params); + serdes_seq_db[PEX_TX_CONFIG_SEQ3].data_arr_idx = PEX; + + /* PEX_BY_4_CONFIG_SEQ sequence init */ + serdes_seq_db[PEX_BY_4_CONFIG_SEQ].op_params_ptr = + pex_by4_config_params; + serdes_seq_db[PEX_BY_4_CONFIG_SEQ].cfg_seq_size = + sizeof(pex_by4_config_params) / sizeof(struct op_params); + serdes_seq_db[PEX_BY_4_CONFIG_SEQ].data_arr_idx = PEX; + + /* PEX_CONFIG_REF_CLOCK_25MHZ_SEQ sequence init */ + serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].op_params_ptr = + pex_config_ref_clock25_m_hz; + serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].cfg_seq_size = + sizeof(pex_config_ref_clock25_m_hz) / sizeof(struct op_params); + serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].data_arr_idx = PEX; + + /* PEX_ELECTRICAL_CONFIG_REF_CLOCK_40MHZ_SEQ sequence init */ + serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].op_params_ptr = + pex_config_ref_clock40_m_hz; + serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].cfg_seq_size = + sizeof(pex_config_ref_clock40_m_hz) / sizeof(struct op_params); + serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].data_arr_idx = PEX; + + /* PEX_CONFIG_REF_CLOCK_100MHZ_SEQ sequence init */ + serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].op_params_ptr = + pex_config_ref_clock100_m_hz; + serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].cfg_seq_size = + sizeof(pex_config_ref_clock100_m_hz) / sizeof(struct op_params); + serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].data_arr_idx = PEX; + + /* USB3_POWER_UP_SEQ sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr = + pex_and_usb3_power_up_serdes_rev1_params; + serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_power_up_serdes_rev1_params) / + sizeof(struct op_params); + } else { + serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr = + pex_and_usb3_power_up_serdes_rev2_params; + serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_power_up_serdes_rev2_params) / + sizeof(struct op_params); + } + serdes_seq_db[USB3_POWER_UP_SEQ].data_arr_idx = USB3; + + /* USB3_HOST_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].op_params_ptr = + pex_and_usb3_speed_config_params; + serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); + serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].data_arr_idx = + USB3SERDES_SPEED_5_GBPS_HOST; + + /* USB3_DEVICE_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].op_params_ptr = + pex_and_usb3_speed_config_params; + serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); + serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].data_arr_idx = + USB3SERDES_SPEED_5_GBPS_DEVICE; + + /* USB3_ELECTRICAL_CONFIG_SEQ seq sequence init */ + if (serdes_rev == MV_SERDES_REV_1_2) { + serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + usb3_electrical_config_serdes_rev1_params; + serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(usb3_electrical_config_serdes_rev1_params) / + sizeof(struct op_params); + } else { + serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + usb3_electrical_config_serdes_rev2_params; + serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(usb3_electrical_config_serdes_rev2_params) / + sizeof(struct op_params); + } + serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].data_arr_idx = USB3; + + /* USB3_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[USB3_TX_CONFIG_SEQ1].op_params_ptr = + pex_and_usb3_tx_config_params1; + serdes_seq_db[USB3_TX_CONFIG_SEQ1].cfg_seq_size = + sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params); + serdes_seq_db[USB3_TX_CONFIG_SEQ1].data_arr_idx = USB3; + + /* USB3_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[USB3_TX_CONFIG_SEQ2].op_params_ptr = + pex_and_usb3_tx_config_params2; + serdes_seq_db[USB3_TX_CONFIG_SEQ2].cfg_seq_size = + sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params); + serdes_seq_db[USB3_TX_CONFIG_SEQ2].data_arr_idx = USB3; + + /* USB3_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[USB3_TX_CONFIG_SEQ3].op_params_ptr = + pex_and_usb3_tx_config_params3; + serdes_seq_db[USB3_TX_CONFIG_SEQ3].cfg_seq_size = + sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params); + serdes_seq_db[USB3_TX_CONFIG_SEQ3].data_arr_idx = USB3; + + /* USB2_POWER_UP_SEQ sequence init */ + serdes_seq_db[USB2_POWER_UP_SEQ].op_params_ptr = usb2_power_up_params; + serdes_seq_db[USB2_POWER_UP_SEQ].cfg_seq_size = + sizeof(usb2_power_up_params) / sizeof(struct op_params); + serdes_seq_db[USB2_POWER_UP_SEQ].data_arr_idx = 0; + + /* USB3_DEVICE_CONFIG_SEQ sequence init */ + serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].op_params_ptr = + usb3_device_config_params; + serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].cfg_seq_size = + sizeof(usb3_device_config_params) / sizeof(struct op_params); + serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].data_arr_idx = 0; /* Not relevant */ + + /* SERDES_POWER_DOWN_SEQ sequence init */ + serdes_seq_db[SERDES_POWER_DOWN_SEQ].op_params_ptr = + serdes_power_down_params; + serdes_seq_db[SERDES_POWER_DOWN_SEQ].cfg_seq_size = + sizeof(serdes_power_down_params) / + sizeof(struct op_params); + serdes_seq_db[SERDES_POWER_DOWN_SEQ].data_arr_idx = FIRST_CELL; + + if (serdes_rev == MV_SERDES_REV_2_1) { + /* QSGMII_POWER_UP_SEQ sequence init */ + serdes_seq_db[QSGMII_POWER_UP_SEQ].op_params_ptr = + qsgmii_port_power_up_params; + serdes_seq_db[QSGMII_POWER_UP_SEQ].cfg_seq_size = + sizeof(qsgmii_port_power_up_params) / + sizeof(struct op_params); + serdes_seq_db[QSGMII_POWER_UP_SEQ].data_arr_idx = + QSGMII_SEQ_IDX; + + /* QSGMII_5_SPEED_CONFIG_SEQ sequence init */ + serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].op_params_ptr = + qsgmii_port_speed_config_params; + serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].cfg_seq_size = + sizeof(qsgmii_port_speed_config_params) / + sizeof(struct op_params); + serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].data_arr_idx = + QSGMII_SEQ_IDX; + + /* QSGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */ + serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr = + qsgmii_port_electrical_config_params; + serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = + sizeof(qsgmii_port_electrical_config_params) / + sizeof(struct op_params); + serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx = + QSGMII_SEQ_IDX; + + /* QSGMII_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].op_params_ptr = + qsgmii_port_tx_config_params1; + serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].cfg_seq_size = + sizeof(qsgmii_port_tx_config_params1) / + sizeof(struct op_params); + serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].data_arr_idx = + QSGMII_SEQ_IDX; + + /* QSGMII_TX_CONFIG_SEQ sequence init */ + serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].op_params_ptr = + qsgmii_port_tx_config_params2; + serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].cfg_seq_size = + sizeof(qsgmii_port_tx_config_params2) / + sizeof(struct op_params); + serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].data_arr_idx = + QSGMII_SEQ_IDX; + } + + return MV_OK; +} + +enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type, + enum serdes_speed baud_rate) +{ + enum serdes_seq seq_id = SERDES_LAST_SEQ; + + DEBUG_INIT_FULL_S("\n### serdes_type_and_speed_to_speed_seq ###\n"); + switch (serdes_type) { + case PEX0: + case PEX1: + case PEX2: + case PEX3: + if (baud_rate == SERDES_SPEED_2_5_GBPS) + seq_id = PEX_2_5_SPEED_CONFIG_SEQ; + else if (baud_rate == SERDES_SPEED_5_GBPS) + seq_id = PEX_5_SPEED_CONFIG_SEQ; + break; + case USB3_HOST0: + case USB3_HOST1: + if (baud_rate == SERDES_SPEED_5_GBPS) + seq_id = USB3_HOST_SPEED_CONFIG_SEQ; + break; + case USB3_DEVICE: + if (baud_rate == SERDES_SPEED_5_GBPS) + seq_id = USB3_DEVICE_SPEED_CONFIG_SEQ; + break; + case SATA0: + case SATA1: + case SATA2: + case SATA3: + if (baud_rate == SERDES_SPEED_1_5_GBPS) + seq_id = SATA_1_5_SPEED_CONFIG_SEQ; + else if (baud_rate == SERDES_SPEED_3_GBPS) + seq_id = SATA_3_SPEED_CONFIG_SEQ; + else if (baud_rate == SERDES_SPEED_6_GBPS) + seq_id = SATA_6_SPEED_CONFIG_SEQ; + break; + case SGMII0: + case SGMII1: + case SGMII2: +#ifdef CONFIG_ARMADA_39X + case SGMII3: +#endif + if (baud_rate == SERDES_SPEED_1_25_GBPS) + seq_id = SGMII_1_25_SPEED_CONFIG_SEQ; + else if (baud_rate == SERDES_SPEED_3_125_GBPS) + seq_id = SGMII_3_125_SPEED_CONFIG_SEQ; + break; + case QSGMII: + seq_id = QSGMII_5_SPEED_CONFIG_SEQ; + break; +#ifdef CONFIG_ARMADA_39X + case XAUI: + seq_id = XAUI_3_125_SPEED_CONFIG_SEQ; + break; + case RXAUI: + seq_id = RXAUI_6_25_SPEED_CONFIG_SEQ; + break; +#endif + default: + return SERDES_LAST_SEQ; + } + + return seq_id; +} + +/* + * This is the weak default function for the Marvell evaluation or + * development boarrds. Like the DB-88F6820-GP and others. + * Custom boards should define this function in their board + * code (board directory). And overwrite this default function + * with this custom specific code. + */ +__weak int hws_board_topology_load(struct serdes_map *serdes_map_array) +{ + u32 board_id = mv_board_id_get(); + u32 board_id_index = mv_board_id_index_get(board_id); + + DEBUG_INIT_FULL_S("\n### hws_board_topology_load ###\n"); + /* getting board topology according to the board id */ + DEBUG_INIT_FULL_S("Getting board topology according to the board id\n"); + + CHECK_STATUS(load_topology_func_arr[board_id_index] (serdes_map_array)); + + return MV_OK; +} + +void print_topology_details(struct serdes_map *serdes_map_array) +{ + u32 lane_num; + + DEBUG_INIT_S("board SerDes lanes topology details:\n"); + + DEBUG_INIT_S(" | Lane # | Speed | Type |\n"); + DEBUG_INIT_S(" --------------------------------\n"); + for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) { + if (serdes_map_array[lane_num].serdes_type == DEFAULT_SERDES) + continue; + DEBUG_INIT_S(" | "); + DEBUG_INIT_D(hws_get_physical_serdes_num(lane_num), 1); + DEBUG_INIT_S(" | "); + DEBUG_INIT_D(serdes_map_array[lane_num].serdes_speed, 2); + DEBUG_INIT_S(" | "); + DEBUG_INIT_S((char *) + serdes_type_to_string[serdes_map_array[lane_num]. + serdes_type]); + DEBUG_INIT_S("\t|\n"); + } + DEBUG_INIT_S(" --------------------------------\n"); +} + +int hws_pre_serdes_init_config(void) +{ + u32 data; + + /* + * Configure Core PLL + */ + /* + * set PLL parameters + * bits[2:0] =0x3 (Core-PLL Kdiv) + * bits[20:12]=0x9f (Core-PLL Ndiv) + * bits[24:21]=0x7(Core-PLL VCO Band) + * bits[28:25]=0x1(Core-PLL Rlf) + * bits[31:29]=0x2(Core-PLL charge-pump adjust) + */ + reg_write(CORE_PLL_PARAMETERS_REG, 0x42e9f003); + + /* Enable PLL Configuration */ + data = reg_read(CORE_PLL_CONFIG_REG); + data = SET_BIT(data, 9); + reg_write(CORE_PLL_CONFIG_REG, data); + + return MV_OK; +} + +int serdes_phy_config(void) +{ + DEBUG_INIT_FULL_S("\n### ctrl_high_speed_serdes_phy_config ###\n"); + + DEBUG_INIT_S("High speed PHY - Version: "); + DEBUG_INIT_S(SERDES_VERION); + DEBUG_INIT_S("\n"); + + /* Init serdes sequences DB */ + if (hws_serdes_seq_init() != MV_OK) { + printf("hws_ctrl_high_speed_serdes_phy_config: Error: Serdes initialization fail\n"); + return MV_FAIL; + } + + /* I2C init */ + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + /* Board topology load */ + DEBUG_INIT_FULL_S + ("ctrl_high_speed_serdes_phy_config: Loading board topology..\n"); + CHECK_STATUS(hws_board_topology_load(serdes_configuration_map)); + + /* print topology */ + print_topology_details(serdes_configuration_map); + CHECK_STATUS(hws_pre_serdes_init_config()); + + /* Power-Up sequence */ + DEBUG_INIT_FULL_S + ("ctrl_high_speed_serdes_phy_config: Starting serdes power up sequence\n"); + + CHECK_STATUS(hws_power_up_serdes_lanes(serdes_configuration_map)); + + DEBUG_INIT_FULL_S + ("\n### ctrl_high_speed_serdes_phy_config ended successfully ###\n"); + + DEBUG_INIT_S(ENDED_OK); + + return MV_OK; +} + +int serdes_polarity_config(u32 serdes_num, int is_rx) +{ + u32 data; + u32 reg_addr; + u8 bit_off = (is_rx) ? 11 : 10; + + reg_addr = SERDES_REGS_LANE_BASE_OFFSET(serdes_num) + SYNC_PATTERN_REG; + data = reg_read(reg_addr); + data = SET_BIT(data, bit_off); + reg_write(reg_addr, data); + + return MV_OK; +} + +int hws_power_up_serdes_lanes(struct serdes_map *serdes_config_map) +{ + u32 serdes_id, serdes_lane_num; + enum ref_clock ref_clock; + enum serdes_type serdes_type; + enum serdes_speed serdes_speed; + enum serdes_mode serdes_mode; + int serdes_rx_polarity_swap; + int serdes_tx_polarity_swap; + int is_pex_enabled = 0; + + /* + * is_pex_enabled: + * Flag which indicates that one of the Serdes is of PEX. + * In this case, PEX unit will be initialized after Serdes power-up + */ + + DEBUG_INIT_FULL_S("\n### hws_power_up_serdes_lanes ###\n"); + + /* COMMON PHYS SELECTORS register configuration */ + DEBUG_INIT_FULL_S + ("hws_power_up_serdes_lanes: Updating COMMON PHYS SELECTORS reg\n"); + CHECK_STATUS(hws_update_serdes_phy_selectors(serdes_configuration_map)); + + /* per Serdes Power Up */ + for (serdes_id = 0; serdes_id < hws_serdes_get_max_lane(); + serdes_id++) { + DEBUG_INIT_FULL_S + ("calling serdes_power_up_ctrl: serdes lane number "); + DEBUG_INIT_FULL_D_10(serdes_lane_num, 1); + DEBUG_INIT_FULL_S("\n"); + + serdes_lane_num = hws_get_physical_serdes_num(serdes_id); + serdes_type = serdes_config_map[serdes_id].serdes_type; + serdes_speed = serdes_config_map[serdes_id].serdes_speed; + serdes_mode = serdes_config_map[serdes_id].serdes_mode; + serdes_rx_polarity_swap = serdes_config_map[serdes_id].swap_rx; + serdes_tx_polarity_swap = serdes_config_map[serdes_id].swap_tx; + + /* serdes lane is not in use */ + if (serdes_type == DEFAULT_SERDES) + continue; + else if (serdes_type <= PEX3) /* PEX type */ + is_pex_enabled = 1; + + ref_clock = hws_serdes_get_ref_clock_val(serdes_type); + if (ref_clock == REF_CLOCK_UNSUPPORTED) { + DEBUG_INIT_S + ("hws_power_up_serdes_lanes: unsupported ref clock\n"); + return MV_NOT_SUPPORTED; + } + CHECK_STATUS(serdes_power_up_ctrl(serdes_lane_num, + 1, + serdes_type, + serdes_speed, + serdes_mode, ref_clock)); + + /* RX Polarity config */ + if (serdes_rx_polarity_swap) + CHECK_STATUS(serdes_polarity_config + (serdes_lane_num, 1)); + + /* TX Polarity config */ + if (serdes_tx_polarity_swap) + CHECK_STATUS(serdes_polarity_config + (serdes_lane_num, 0)); + } + + if (is_pex_enabled) { + /* Set PEX_TX_CONFIG_SEQ sequence for PEXx4 mode. + After finish the Power_up sequence for all lanes, + the lanes should be released from reset state. */ + CHECK_STATUS(hws_pex_tx_config_seq(serdes_config_map)); + + /* PEX configuration */ + CHECK_STATUS(hws_pex_config(serdes_config_map)); + } + + /* USB2 configuration */ + DEBUG_INIT_FULL_S("hws_power_up_serdes_lanes: init USB2 Phys\n"); + CHECK_STATUS(mv_seq_exec(0 /* not relevant */ , USB2_POWER_UP_SEQ)); + + DEBUG_INIT_FULL_S + ("### hws_power_up_serdes_lanes ended successfully ###\n"); + + return MV_OK; +} + +int ctrl_high_speed_serdes_phy_config(void) +{ + return hws_ctrl_high_speed_serdes_phy_config(); +} + +static int serdes_pex_usb3_pipe_delay_w_a(u32 serdes_num, u8 serdes_type) +{ + u32 reg_data; + + /* WA for A380 Z1 relevant for lanes 3,4,5 only */ + if (serdes_num >= 3) { + reg_data = reg_read(GENERAL_PURPOSE_RESERVED0_REG); + /* set delay on pipe - + * When lane 3 is connected to a MAC of Pex -> set bit 7 to 1. + * When lane 3 is connected to a MAC of USB3 -> set bit 7 to 0. + * When lane 4 is connected to a MAC of Pex -> set bit 8 to 1. + * When lane 4 is connected to a MAC of USB3 -> set bit 8 to 0. + * When lane 5 is connected to a MAC of Pex -> set bit 8 to 1. + * When lane 5 is connected to a MAC of USB3 -> set bit 8 to 0. + */ + if (serdes_type == PEX) + reg_data |= 1 << (7 + (serdes_num - 3)); + if (serdes_type == USB3) { + /* USB3 */ + reg_data &= ~(1 << (7 + (serdes_num - 3))); + } + reg_write(GENERAL_PURPOSE_RESERVED0_REG, reg_data); + } + + return MV_OK; +} + +/* + * hws_serdes_pex_ref_clock_satr_get - + * + * DESCRIPTION: Get the reference clock value from DEVICE_SAMPLE_AT_RESET1_REG + * and check: + * bit[2] for PEX#0, bit[3] for PEX#1, bit[30] for PEX#2, bit[31] + * for PEX#3. + * If bit=0 --> REF_CLOCK_100MHz + * If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=0 + * --> REF_CLOCK_25MHz + * If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=1 + * --> REF_CLOCK_40MHz + * + * INPUT: serdes_type - Type of Serdes + * + * OUTPUT: pex_satr - Return the REF_CLOCK value: + * REF_CLOCK_25MHz, REF_CLOCK_40MHz or REF_CLOCK_100MHz + * + * RETURNS: MV_OK - for success + * MV_BAD_PARAM - for fail + */ +int hws_serdes_pex_ref_clock_satr_get(enum serdes_type serdes_type, u32 *pex_satr) +{ + u32 data, reg_satr1; + + reg_satr1 = reg_read(DEVICE_SAMPLE_AT_RESET1_REG); + + switch (serdes_type) { + case PEX0: + data = REF_CLK_SELECTOR_VAL_PEX0(reg_satr1); + break; + case PEX1: + data = REF_CLK_SELECTOR_VAL_PEX1(reg_satr1); + break; + case PEX2: + data = REF_CLK_SELECTOR_VAL_PEX2(reg_satr1); + break; + case PEX3: + data = REF_CLK_SELECTOR_VAL_PEX3(reg_satr1); + break; + default: + printf("%s: Error: SerDes type %d is not supported\n", + __func__, serdes_type); + return MV_BAD_PARAM; + } + + *pex_satr = data; + + return MV_OK; +} + +u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type) +{ + u32 pex_satr; + enum ref_clock ref_clock; + + DEBUG_INIT_FULL_S("\n### hws_serdes_get_ref_clock_val ###\n"); + + if (serdes_type >= LAST_SERDES_TYPE) + return REF_CLOCK_UNSUPPORTED; + + /* read ref clock from S@R */ + ref_clock = hws_serdes_silicon_ref_clock_get(); + + if (serdes_type > PEX3) { + /* for all Serdes types but PCIe */ + return ref_clock; + } + + /* for PCIe, need also to check PCIe S@R */ + CHECK_STATUS(hws_serdes_pex_ref_clock_satr_get + (serdes_type, &pex_satr)); + + if (pex_satr == 0) { + return REF_CLOCK_100MHZ; + } else if (pex_satr == 1) { + /* value of 1 means we can use ref clock from SoC (as other Serdes types) */ + return ref_clock; + } else { + printf + ("%s: Error: REF_CLK_SELECTOR_VAL for SerDes type %d is wrong\n", + __func__, serdes_type); + return REF_CLOCK_UNSUPPORTED; + } +} + +int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, + enum serdes_type serdes_type, + enum serdes_speed baud_rate, + enum serdes_mode serdes_mode, enum ref_clock ref_clock) +{ + u32 sata_idx, pex_idx, sata_port; + enum serdes_seq speed_seq_id; + u32 reg_data; + int is_pex_by1; + + DEBUG_INIT_FULL_S("\n### serdes_power_up_ctrl ###\n"); + + if (serdes_power_up == 1) { /* Serdes power up */ + DEBUG_INIT_FULL_S + ("serdes_power_up_ctrl: executing power up.. "); + DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 2); + DEBUG_INIT_FULL_C("serdes type = ", serdes_type, 2); + + DEBUG_INIT_FULL_S("Going access 1"); + + /* Getting the Speed Select sequence id */ + speed_seq_id = + serdes_type_and_speed_to_speed_seq(serdes_type, + baud_rate); + if (speed_seq_id == SERDES_LAST_SEQ) { + printf + ("serdes_power_up_ctrl: serdes type %d and speed %d are not supported together\n", + serdes_type, baud_rate); + + return MV_BAD_PARAM; + } + + /* Executing power up, ref clock set, speed config and TX config */ + switch (serdes_type) { + case PEX0: + case PEX1: + case PEX2: + case PEX3: + if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) { + CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a + (serdes_num, PEX)); + } + + is_pex_by1 = (serdes_mode == PEX_ROOT_COMPLEX_X1) || + (serdes_mode == PEX_END_POINT_X1); + pex_idx = serdes_type - PEX0; + + if ((is_pex_by1 == 1) || (serdes_type == PEX0)) { + /* For PEX by 4, init only the PEX 0 */ + reg_data = reg_read(SOC_CONTROL_REG1); + if (is_pex_by1 == 1) + reg_data |= 0x4000; + else + reg_data &= ~0x4000; + reg_write(SOC_CONTROL_REG1, reg_data); + + reg_data = + reg_read(((PEX_IF_REGS_BASE(pex_idx)) + + 0x6c)); + reg_data &= ~0x3f0; + if (is_pex_by1 == 1) + reg_data |= 0x10; + else + reg_data |= 0x40; + reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c), + reg_data); + + reg_data = + reg_read(((PEX_IF_REGS_BASE(pex_idx)) + + 0x6c)); + reg_data &= ~0xf; + reg_data |= 0x2; + reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c), + reg_data); + + reg_data = + reg_read(((PEX_IF_REGS_BASE(pex_idx)) + + 0x70)); + reg_data &= ~0x40; + reg_data |= 0x40; + reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x70), + reg_data); + } + + CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ)); + if (is_pex_by1 == 0) { + /* + * for PEX by 4 - use the PEX index as the + * seq array index + */ + serdes_seq_db[PEX_BY_4_CONFIG_SEQ]. + data_arr_idx = pex_idx; + CHECK_STATUS(mv_seq_exec + (serdes_num, PEX_BY_4_CONFIG_SEQ)); + } + + CHECK_STATUS(hws_ref_clock_set + (serdes_num, serdes_type, ref_clock)); + CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); + CHECK_STATUS(mv_seq_exec + (serdes_num, PEX_ELECTRICAL_CONFIG_SEQ)); + + if (is_pex_by1 == 1) { + CHECK_STATUS(mv_seq_exec + (serdes_num, PEX_TX_CONFIG_SEQ2)); + CHECK_STATUS(mv_seq_exec + (serdes_num, PEX_TX_CONFIG_SEQ3)); + CHECK_STATUS(mv_seq_exec + (serdes_num, PEX_TX_CONFIG_SEQ1)); + } + udelay(20); + + break; + case USB3_HOST0: + case USB3_HOST1: + case USB3_DEVICE: + if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) { + CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a + (serdes_num, USB3)); + } + CHECK_STATUS(mv_seq_exec + (serdes_num, USB3_POWER_UP_SEQ)); + CHECK_STATUS(hws_ref_clock_set + (serdes_num, serdes_type, ref_clock)); + CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); + if (serdes_type == USB3_DEVICE) { + CHECK_STATUS(mv_seq_exec + (serdes_num, + USB3_DEVICE_CONFIG_SEQ)); + } + CHECK_STATUS(mv_seq_exec + (serdes_num, USB3_ELECTRICAL_CONFIG_SEQ)); + CHECK_STATUS(mv_seq_exec + (serdes_num, USB3_TX_CONFIG_SEQ1)); + CHECK_STATUS(mv_seq_exec + (serdes_num, USB3_TX_CONFIG_SEQ2)); + CHECK_STATUS(mv_seq_exec + (serdes_num, USB3_TX_CONFIG_SEQ3)); + + udelay(10000); + break; + case SATA0: + case SATA1: + case SATA2: + case SATA3: + sata_idx = ((serdes_type == SATA0) || + (serdes_type == SATA1)) ? 0 : 1; + sata_port = ((serdes_type == SATA0) || + (serdes_type == SATA2)) ? 0 : 1; + + CHECK_STATUS(mv_seq_exec + (sata_idx, (sata_port == 0) ? + SATA_PORT_0_ONLY_POWER_UP_SEQ : + SATA_PORT_1_ONLY_POWER_UP_SEQ)); + CHECK_STATUS(mv_seq_exec + (serdes_num, SATA_POWER_UP_SEQ)); + CHECK_STATUS(hws_ref_clock_set + (serdes_num, serdes_type, ref_clock)); + CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); + CHECK_STATUS(mv_seq_exec + (serdes_num, SATA_ELECTRICAL_CONFIG_SEQ)); + CHECK_STATUS(mv_seq_exec + (serdes_num, SATA_TX_CONFIG_SEQ1)); + CHECK_STATUS(mv_seq_exec + (sata_idx, (sata_port == 0) ? + SATA_PORT_0_ONLY_TX_CONFIG_SEQ : + SATA_PORT_1_ONLY_TX_CONFIG_SEQ)); + CHECK_STATUS(mv_seq_exec + (serdes_num, SATA_TX_CONFIG_SEQ2)); + + udelay(10000); + break; + case SGMII0: + case SGMII1: + case SGMII2: + CHECK_STATUS(mv_seq_exec + (serdes_num, SGMII_POWER_UP_SEQ)); + CHECK_STATUS(hws_ref_clock_set + (serdes_num, serdes_type, ref_clock)); + CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); + CHECK_STATUS(mv_seq_exec + (serdes_num, SGMII_ELECTRICAL_CONFIG_SEQ)); + CHECK_STATUS(mv_seq_exec + (serdes_num, SGMII_TX_CONFIG_SEQ1)); + CHECK_STATUS(mv_seq_exec + (serdes_num, SGMII_TX_CONFIG_SEQ2)); + + /* GBE configuration */ + reg_data = reg_read(GBE_CONFIGURATION_REG); + /* write the SGMII index */ + reg_data |= 0x1 << (serdes_type - SGMII0); + reg_write(GBE_CONFIGURATION_REG, reg_data); + + break; + case QSGMII: + if (hws_ctrl_serdes_rev_get() < MV_SERDES_REV_2_1) + return MV_NOT_SUPPORTED; + + CHECK_STATUS(mv_seq_exec + (serdes_num, QSGMII_POWER_UP_SEQ)); + CHECK_STATUS(hws_ref_clock_set + (serdes_num, serdes_type, ref_clock)); + CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); + CHECK_STATUS(mv_seq_exec + (serdes_num, + QSGMII_ELECTRICAL_CONFIG_SEQ)); + CHECK_STATUS(mv_seq_exec + (serdes_num, QSGMII_TX_CONFIG_SEQ1)); + CHECK_STATUS(mv_seq_exec + (serdes_num, QSGMII_TX_CONFIG_SEQ2)); + break; + case SGMII3: + case XAUI: + case RXAUI: + CHECK_STATUS(serdes_power_up_ctrl_ext + (serdes_num, serdes_power_up, serdes_type, + baud_rate, serdes_mode, ref_clock)); + break; + default: + DEBUG_INIT_S + ("serdes_power_up_ctrl: bad serdes_type parameter\n"); + return MV_BAD_PARAM; + } + } else { /* Serdes power down */ + DEBUG_INIT_FULL_S("serdes_power_up: executing power down.. "); + DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 1); + + CHECK_STATUS(mv_seq_exec(serdes_num, SERDES_POWER_DOWN_SEQ)); + } + + DEBUG_INIT_FULL_C( + "serdes_power_up_ctrl ended successfully for serdes ", + serdes_num, 2); + + return MV_OK; +} + +int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map) +{ + u32 lane_data, idx, serdes_lane_hw_num, reg_data = 0; + enum serdes_type serdes_type; + enum serdes_mode serdes_mode; + u8 select_bit_off; + int is_pex_x4 = 0; + int updated_topology_print = 0; + + DEBUG_INIT_FULL_S("\n### hws_update_serdes_phy_selectors ###\n"); + DEBUG_INIT_FULL_S + ("Updating the COMMON PHYS SELECTORS register with the serdes types\n"); + + if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) + select_bit_off = 3; + else + select_bit_off = 4; + + /* + * Updating bits 0-17 in the COMMON PHYS SELECTORS register + * according to the serdes types + */ + for (idx = 0; idx < hws_serdes_get_max_lane(); + idx++) { + serdes_type = serdes_config_map[idx].serdes_type; + serdes_mode = serdes_config_map[idx].serdes_mode; + serdes_lane_hw_num = hws_get_physical_serdes_num(idx); + + lane_data = + hws_serdes_get_phy_selector_val(serdes_lane_hw_num, + serdes_type); + + if (serdes_type == DEFAULT_SERDES) + continue; + + if (hws_serdes_topology_verify + (serdes_type, idx, serdes_mode) != MV_OK) { + serdes_config_map[idx].serdes_type = + DEFAULT_SERDES; + printf("%s: SerDes lane #%d is disabled\n", __func__, + serdes_lane_hw_num); + updated_topology_print = 1; + continue; + } + + /* + * Checking if the board topology configuration includes + * PEXx4 - for the next step + */ + if ((serdes_mode == PEX_END_POINT_X4) || + (serdes_mode == PEX_ROOT_COMPLEX_X4)) { + /* update lane data to the 3 next SERDES lanes */ + lane_data = + common_phys_selectors_pex_by4_lanes + [serdes_lane_hw_num]; + if (serdes_type == PEX0) + is_pex_x4 = 1; + } + + if (lane_data == NA) { + printf + ("%s: Warning: SerDes lane #%d and type %d are not supported together\n", + __func__, serdes_lane_hw_num, serdes_mode); + serdes_config_map[idx].serdes_type = + DEFAULT_SERDES; + printf("%s: SerDes lane #%d is disabled\n", __func__, + serdes_lane_hw_num); + continue; + } + + /* + * Updating the data that will be written to + * COMMON_PHYS_SELECTORS_REG + */ + reg_data |= (lane_data << + (select_bit_off * serdes_lane_hw_num)); + } + + /* + * Check that number of used lanes for XAUI and RXAUI + * (if used) is right + */ + hws_serdes_xaui_topology_verify(); + + /* Print topology */ + if (updated_topology_print) + print_topology_details(serdes_config_map); + + /* + * Updating the PEXx4 Enable bit in the COMMON PHYS SELECTORS + * register for PEXx4 mode + */ + reg_data |= (is_pex_x4 == 1) ? (0x1 << PEX_X4_ENABLE_OFFS) : 0; + + /* Updating the COMMON PHYS SELECTORS register */ + reg_write(COMMON_PHYS_SELECTORS_REG, reg_data); + + return MV_OK; +} + +int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type, + enum ref_clock ref_clock) +{ + u32 data1 = 0, data2 = 0, data3 = 0, reg_data; + + DEBUG_INIT_FULL_S("\n### hws_ref_clock_set ###\n"); + + if (hws_is_serdes_active(serdes_num) != 1) { + printf("%s: SerDes lane #%d is not Active\n", __func__, + serdes_num); + return MV_BAD_PARAM; + } + + switch (serdes_type) { + case PEX0: + case PEX1: + case PEX2: + case PEX3: + switch (ref_clock) { + case REF_CLOCK_25MHZ: + CHECK_STATUS(mv_seq_exec + (serdes_num, + PEX_CONFIG_REF_CLOCK_25MHZ_SEQ)); + return MV_OK; + case REF_CLOCK_100MHZ: + CHECK_STATUS(mv_seq_exec + (serdes_num, + PEX_CONFIG_REF_CLOCK_100MHZ_SEQ)); + return MV_OK; +#ifdef CONFIG_ARMADA_39X + case REF_CLOCK_40MHZ: + CHECK_STATUS(mv_seq_exec + (serdes_num, + PEX_CONFIG_REF_CLOCK_40MHZ_SEQ)); + return MV_OK; +#endif + default: + printf + ("%s: Error: ref_clock %d for SerDes lane #%d, type %d is not supported\n", + __func__, ref_clock, serdes_num, serdes_type); + return MV_BAD_PARAM; + } + case USB3_HOST0: + case USB3_HOST1: + case USB3_DEVICE: + if (ref_clock == REF_CLOCK_25MHZ) { + data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2; + data2 = GLOBAL_PM_CTRL_REG_25MHZ_VAL; + data3 = LANE_CFG4_REG_25MHZ_VAL; + } else if (ref_clock == REF_CLOCK_40MHZ) { + data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL; + data2 = GLOBAL_PM_CTRL_REG_40MHZ_VAL; + data3 = LANE_CFG4_REG_40MHZ_VAL; + } else { + printf + ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n", + serdes_type); + return MV_BAD_PARAM; + } + break; + case SATA0: + case SATA1: + case SATA2: + case SATA3: + case SGMII0: + case SGMII1: + case SGMII2: + case QSGMII: + if (ref_clock == REF_CLOCK_25MHZ) { + data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1; + } else if (ref_clock == REF_CLOCK_40MHZ) { + data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL; + } else { + printf + ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n", + serdes_type); + return MV_BAD_PARAM; + } + break; +#ifdef CONFIG_ARMADA_39X + case SGMII3: + case XAUI: + case RXAUI: + if (ref_clock == REF_CLOCK_25MHZ) { + data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1; + } else if (ref_clock == REF_CLOCK_40MHZ) { + data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL; + } else { + printf + ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n", + serdes_type); + return MV_BAD_PARAM; + } + break; +#endif + default: + DEBUG_INIT_S("hws_ref_clock_set: not supported serdes type\n"); + return MV_BAD_PARAM; + } + + /* + * Write the ref_clock to relevant SELECT_REF_CLOCK_REG bits and + * offset + */ + reg_data = reg_read(POWER_AND_PLL_CTRL_REG + + SERDES_REGS_LANE_BASE_OFFSET(serdes_num)); + reg_data &= POWER_AND_PLL_CTRL_REG_MASK; + reg_data |= data1; + reg_write(POWER_AND_PLL_CTRL_REG + + SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data); + + if ((serdes_type == USB3_HOST0) || (serdes_type == USB3_HOST1) || + (serdes_type == USB3_DEVICE)) { + reg_data = reg_read(GLOBAL_PM_CTRL + + SERDES_REGS_LANE_BASE_OFFSET(serdes_num)); + reg_data &= GLOBAL_PM_CTRL_REG_MASK; + reg_data |= data2; + reg_write(GLOBAL_PM_CTRL + + SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data); + + reg_data = reg_read(LANE_CFG4_REG + + SERDES_REGS_LANE_BASE_OFFSET(serdes_num)); + reg_data &= LANE_CFG4_REG_MASK; + reg_data |= data3; + reg_write(LANE_CFG4_REG + + SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data); + } + + return MV_OK; +} + +/* + * hws_pex_tx_config_seq - + * + * DESCRIPTION: Set PEX_TX_CONFIG_SEQ sequence init for PEXx4 mode + * INPUT: serdes_map - The board topology map + * OUTPUT: None + * RETURNS: MV_OK - for success + * MV_BAD_PARAM - for fail + */ +int hws_pex_tx_config_seq(struct serdes_map *serdes_map) +{ + enum serdes_mode serdes_mode; + u32 serdes_lane_id, serdes_lane_hw_num; + + DEBUG_INIT_FULL_S("\n### hws_pex_tx_config_seq ###\n"); + + /* + * For PEXx4: the pex_and_usb3_tx_config_params1/2/3 + * configurations should run by setting each sequence for + * all 4 lanes. + */ + + /* relese pipe soft reset for all lanes */ + for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane(); + serdes_lane_id++) { + serdes_mode = serdes_map[serdes_lane_id].serdes_mode; + serdes_lane_hw_num = + hws_get_physical_serdes_num(serdes_lane_id); + + if ((serdes_mode == PEX_ROOT_COMPLEX_X4) || + (serdes_mode == PEX_END_POINT_X4)) { + CHECK_STATUS(mv_seq_exec + (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ1)); + } + } + + /* set phy soft reset for all lanes */ + for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane(); + serdes_lane_id++) { + serdes_mode = serdes_map[serdes_lane_id].serdes_mode; + serdes_lane_hw_num = + hws_get_physical_serdes_num(serdes_lane_id); + if ((serdes_mode == PEX_ROOT_COMPLEX_X4) || + (serdes_mode == PEX_END_POINT_X4)) { + CHECK_STATUS(mv_seq_exec + (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ2)); + } + } + + /* set phy soft reset for all lanes */ + for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane(); + serdes_lane_id++) { + serdes_mode = serdes_map[serdes_lane_id].serdes_mode; + serdes_lane_hw_num = + hws_get_physical_serdes_num(serdes_lane_id); + if ((serdes_mode == PEX_ROOT_COMPLEX_X4) || + (serdes_mode == PEX_END_POINT_X4)) { + CHECK_STATUS(mv_seq_exec + (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ3)); + } + } + + return MV_OK; +} diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h new file mode 100644 index 0000000..2508721 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _HIGH_SPEED_ENV_SPEC_H +#define _HIGH_SPEED_ENV_SPEC_H + +#include "seq_exec.h" + +/* + * For setting or clearing a certain bit (bit is a number between 0 and 31) + * in the data + */ +#define SET_BIT(data, bit) ((data) | (0x1 << (bit))) +#define CLEAR_BIT(data, bit) ((data) & (~(0x1 << (bit)))) + +#define MAX_SERDES_LANES 7 /* as in a39x */ + +/* Serdes revision */ +/* Serdes revision 1.2 (for A38x-Z1) */ +#define MV_SERDES_REV_1_2 0x0 +/* Serdes revision 2.1 (for A39x-Z1, A38x-A0) */ +#define MV_SERDES_REV_2_1 0x1 +#define MV_SERDES_REV_NA 0xff + +#define SERDES_REGS_LANE_BASE_OFFSET(lane) (0x800 * (lane)) + +#define PEX_X4_ENABLE_OFFS \ + (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2 ? 18 : 31) + +/* Serdes lane types */ +enum serdes_type { + PEX0, + PEX1, + PEX2, + PEX3, + SATA0, + SATA1, + SATA2, + SATA3, + SGMII0, + SGMII1, + SGMII2, + QSGMII, + USB3_HOST0, + USB3_HOST1, + USB3_DEVICE, + SGMII3, + XAUI, + RXAUI, + DEFAULT_SERDES, + LAST_SERDES_TYPE +}; + +/* Serdes baud rates */ +enum serdes_speed { + SERDES_SPEED_1_25_GBPS, + SERDES_SPEED_1_5_GBPS, + SERDES_SPEED_2_5_GBPS, + SERDES_SPEED_3_GBPS, + SERDES_SPEED_3_125_GBPS, + SERDES_SPEED_5_GBPS, + SERDES_SPEED_6_GBPS, + SERDES_SPEED_6_25_GBPS, + LAST_SERDES_SPEED +}; + +/* Serdes modes */ +enum serdes_mode { + PEX_ROOT_COMPLEX_X1, + PEX_ROOT_COMPLEX_X4, + PEX_END_POINT_X1, + PEX_END_POINT_X4, + + SERDES_DEFAULT_MODE, /* not pex */ + + SERDES_LAST_MODE +}; + +struct serdes_map { + enum serdes_type serdes_type; + enum serdes_speed serdes_speed; + enum serdes_mode serdes_mode; + int swap_rx; + int swap_tx; +}; + +/* Serdes ref clock options */ +enum ref_clock { + REF_CLOCK_25MHZ, + REF_CLOCK_100MHZ, + REF_CLOCK_40MHZ, + REF_CLOCK_UNSUPPORTED +}; + +/* Serdes sequences */ +enum serdes_seq { + SATA_PORT_0_ONLY_POWER_UP_SEQ, + SATA_PORT_1_ONLY_POWER_UP_SEQ, + SATA_POWER_UP_SEQ, + SATA_1_5_SPEED_CONFIG_SEQ, + SATA_3_SPEED_CONFIG_SEQ, + SATA_6_SPEED_CONFIG_SEQ, + SATA_ELECTRICAL_CONFIG_SEQ, + SATA_TX_CONFIG_SEQ1, + SATA_PORT_0_ONLY_TX_CONFIG_SEQ, + SATA_PORT_1_ONLY_TX_CONFIG_SEQ, + SATA_TX_CONFIG_SEQ2, + + SGMII_POWER_UP_SEQ, + SGMII_1_25_SPEED_CONFIG_SEQ, + SGMII_3_125_SPEED_CONFIG_SEQ, + SGMII_ELECTRICAL_CONFIG_SEQ, + SGMII_TX_CONFIG_SEQ1, + SGMII_TX_CONFIG_SEQ2, + + PEX_POWER_UP_SEQ, + PEX_2_5_SPEED_CONFIG_SEQ, + PEX_5_SPEED_CONFIG_SEQ, + PEX_ELECTRICAL_CONFIG_SEQ, + PEX_TX_CONFIG_SEQ1, + PEX_TX_CONFIG_SEQ2, + PEX_TX_CONFIG_SEQ3, + PEX_BY_4_CONFIG_SEQ, + PEX_CONFIG_REF_CLOCK_25MHZ_SEQ, + PEX_CONFIG_REF_CLOCK_100MHZ_SEQ, + PEX_CONFIG_REF_CLOCK_40MHZ_SEQ, + + USB3_POWER_UP_SEQ, + USB3_HOST_SPEED_CONFIG_SEQ, + USB3_DEVICE_SPEED_CONFIG_SEQ, + USB3_ELECTRICAL_CONFIG_SEQ, + USB3_TX_CONFIG_SEQ1, + USB3_TX_CONFIG_SEQ2, + USB3_TX_CONFIG_SEQ3, + USB3_DEVICE_CONFIG_SEQ, + + USB2_POWER_UP_SEQ, + + SERDES_POWER_DOWN_SEQ, + + SGMII3_POWER_UP_SEQ, + SGMII3_1_25_SPEED_CONFIG_SEQ, + SGMII3_TX_CONFIG_SEQ1, + SGMII3_TX_CONFIG_SEQ2, + + QSGMII_POWER_UP_SEQ, + QSGMII_5_SPEED_CONFIG_SEQ, + QSGMII_ELECTRICAL_CONFIG_SEQ, + QSGMII_TX_CONFIG_SEQ1, + QSGMII_TX_CONFIG_SEQ2, + + XAUI_POWER_UP_SEQ, + XAUI_3_125_SPEED_CONFIG_SEQ, + XAUI_ELECTRICAL_CONFIG_SEQ, + XAUI_TX_CONFIG_SEQ1, + XAUI_TX_CONFIG_SEQ2, + + RXAUI_POWER_UP_SEQ, + RXAUI_6_25_SPEED_CONFIG_SEQ, + RXAUI_ELECTRICAL_CONFIG_SEQ, + RXAUI_TX_CONFIG_SEQ1, + RXAUI_TX_CONFIG_SEQ2, + + SERDES_LAST_SEQ +}; + +/* The different sequence types for PEX and USB3 */ +enum { + PEX, + USB3, + LAST_PEX_USB_SEQ_TYPE +}; + +enum { + PEXSERDES_SPEED_2_5_GBPS, + PEXSERDES_SPEED_5_GBPS, + USB3SERDES_SPEED_5_GBPS_HOST, + USB3SERDES_SPEED_5_GBPS_DEVICE, + LAST_PEX_USB_SPEED_SEQ_TYPE +}; + +/* The different sequence types for SATA and SGMII */ +enum { + SATA, + SGMII, + SGMII_3_125, + LAST_SATA_SGMII_SEQ_TYPE +}; + +enum { + QSGMII_SEQ_IDX, + LAST_QSGMII_SEQ_TYPE +}; + +enum { + XAUI_SEQ_IDX, + RXAUI_SEQ_IDX, + LAST_XAUI_RXAUI_SEQ_TYPE +}; + +enum { + SATASERDES_SPEED_1_5_GBPS, + SATASERDES_SPEED_3_GBPS, + SATASERDES_SPEED_6_GBPS, + SGMIISERDES_SPEED_1_25_GBPS, + SGMIISERDES_SPEED_3_125_GBPS, + LAST_SATA_SGMII_SPEED_SEQ_TYPE +}; + +extern u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES]; +extern u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES]; + +u8 hws_ctrl_serdes_rev_get(void); +int mv_update_serdes_select_phy_mode_seq(void); +int hws_board_topology_load(struct serdes_map *serdes_map_array); +enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type, + enum serdes_speed baud_rate); +int hws_serdes_seq_init(void); +int hws_serdes_seq_db_init(void); +int hws_power_up_serdes_lanes(struct serdes_map *serdes_config_map); +int hws_ctrl_high_speed_serdes_phy_config(void); +int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, + enum serdes_type serdes_type, + enum serdes_speed baud_rate, + enum serdes_mode serdes_mode, + enum ref_clock ref_clock); +int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up, + enum serdes_type serdes_type, + enum serdes_speed baud_rate, + enum serdes_mode serdes_mode, + enum ref_clock ref_clock); +u32 hws_serdes_silicon_ref_clock_get(void); +int hws_serdes_pex_ref_clock_get(enum serdes_type serdes_type, + enum ref_clock *ref_clock); +int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type, + enum ref_clock ref_clock); +int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map); +u32 hws_serdes_get_phy_selector_val(int serdes_num, + enum serdes_type serdes_type); +u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type); +u32 hws_serdes_get_max_lane(void); +int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset, + u32 *unit_base_reg, u32 *unit_offset); +int hws_pex_tx_config_seq(struct serdes_map *serdes_map); +u32 hws_get_physical_serdes_num(u32 serdes_num); +int hws_is_serdes_active(u8 lane_num); + +#endif /* _HIGH_SPEED_ENV_SPEC_H */ diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c new file mode 100644 index 0000000..5f2c3eb --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c @@ -0,0 +1,1009 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "high_speed_topology_spec.h" +#include "sys_env_lib.h" + +#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT +/* + * This is an example implementation for this custom board + * specific function + */ +static struct serdes_map custom_board_topology_config[] = { + /* Customer Board Topology - reference from Marvell DB-GP board */ + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +int hws_board_topology_load(struct serdes_map *serdes_map_array) +{ + serdes_map_array = custom_board_topology_config; +} +#endif + +load_topology_func_ptr load_topology_func_arr[] = { + load_topology_rd, /* RD NAS */ + load_topology_db, /* 6820 DB-BP (A38x) */ + load_topology_rd, /* RD AP */ + load_topology_db_ap, /* DB AP */ + load_topology_db_gp, /* DB GP */ + load_topology_db_381, /* 6821 DB-BP (A381) */ + load_topology_db_amc, /* DB-AMC */ +}; + +/*****************************************/ +/** Load topology - Marvell 380 DB - BP **/ +/*****************************************/ +/* Configuration options */ +struct serdes_map db_config_default[MAX_SERDES_LANES] = { + {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +struct serdes_map db_config_slm1363_c[MAX_SERDES_LANES] = { + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, +}; + +struct serdes_map db_config_slm1363_d[MAX_SERDES_LANES] = { + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + {PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +struct serdes_map db_config_slm1363_e[MAX_SERDES_LANES] = { + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +struct serdes_map db_config_slm1363_f[MAX_SERDES_LANES] = { + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +struct serdes_map db_config_slm1364_d[MAX_SERDES_LANES] = { + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +struct serdes_map db_config_slm1364_e[MAX_SERDES_LANES] = { + {SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0} +}; + +struct serdes_map db_config_slm1364_f[MAX_SERDES_LANES] = { + {SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0}, + {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0} +}; + +/*************************************************************************/ +/** The following structs are mapping for DB board 'SatR' configuration **/ +/*************************************************************************/ +struct serdes_map db_satr_config_lane1[SATR_DB_LANE1_MAX_OPTIONS] = { + /* 0 */ {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, + 0}, + /* 1 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + /* 2 */ {SATA0, SERDES_SPEED_3_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + /* 3 */ {SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, + /* 4 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, + /* 5 */ {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, + /* 6 */ {QSGMII, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +struct serdes_map db_satr_config_lane2[SATR_DB_LANE2_MAX_OPTIONS] = { + /* 0 */ {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, + 0}, + /* 1 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + /* 2 */ {SATA1, SERDES_SPEED_3_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + /* 3 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, + 0} +}; + +/*******************************************************/ +/* Configuration options DB ****************************/ +/* mapping from TWSI address data to configuration map */ +/*******************************************************/ +struct serdes_map *topology_config_db[] = { + db_config_slm1363_c, + db_config_slm1363_d, + db_config_slm1363_e, + db_config_slm1363_f, + db_config_slm1364_d, + db_config_slm1364_e, + db_config_slm1364_f, + db_config_default +}; + +/*************************************/ +/** Load topology - Marvell DB - AP **/ +/*************************************/ +struct serdes_map db_ap_config_default[MAX_SERDES_LANES] = { + /* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + /* 1 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, + /* 2 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + /* 3 */ {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, + /* 4 */ {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, + /* 5 */ {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0} +}; + +/*************************************/ +/** Load topology - Marvell DB - GP **/ +/*************************************/ +struct serdes_map db_gp_config_default[MAX_SERDES_LANES] = { + /* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + /* 1 */ {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + /* 2 */ {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + /* 3 */ {SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + /* 4 */ {SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + /* 5 */ {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, + 0} +}; + +struct serdes_map db_amc_config_default[MAX_SERDES_LANES] = { + /* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + /* 1 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + /* 2 */ {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + /* 3 */ {PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0}, + /* 4 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, + /* 5 */ {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, + 0}, +}; + +/*****************************************/ +/** Load topology - Marvell 381 DB - BP **/ +/*****************************************/ +/* Configuration options */ +struct serdes_map db381_config_default[MAX_SERDES_LANES] = { + {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1}, + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, + {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0} +}; + +struct serdes_map db_config_slm1427[MAX_SERDES_LANES] = { + {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1}, + {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 1, 1}, + {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1}, + {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 1, 1} +}; + +struct serdes_map db_config_slm1426[MAX_SERDES_LANES] = { + {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1}, + {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 1, 1}, + {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1}, + {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 1, 1} +}; + +/* + * this array must be aligned with enum topology_config_db381 enum, + * every update to this array requires update to enum topology_config_db381 + * enum + */ +struct serdes_map *topology_config_db_381[] = { + db_config_slm1427, + db_config_slm1426, + db381_config_default, +}; + +u8 topology_config_db_mode_get(void) +{ + u8 mode; + + DEBUG_INIT_FULL_S("\n### topology_config_db_mode_get ###\n"); + + /* Default - return DB_CONFIG_DEFAULT */ + + if (!i2c_read(DB_GET_MODE_SLM1363_ADDR, 0, 1, &mode, 1)) { + switch (mode & 0xf) { + case 0xc: + DEBUG_INIT_S("\nInit DB board SLM 1363 C topology\n"); + return DB_CONFIG_SLM1363_C; + case 0xd: + DEBUG_INIT_S("\nInit DB board SLM 1363 D topology\n"); + return DB_CONFIG_SLM1363_D; + case 0xe: + DEBUG_INIT_S("\nInit DB board SLM 1363 E topology\n"); + return DB_CONFIG_SLM1363_E; + case 0xf: + DEBUG_INIT_S("\nInit DB board SLM 1363 F topology\n"); + return DB_CONFIG_SLM1363_F; + default: /* not the right module */ + break; + } + } + + /* SLM1364 Module */ + if (i2c_read(DB_GET_MODE_SLM1364_ADDR, 0, 1, &mode, 1)) { + DEBUG_INIT_S("\nInit DB board default topology\n"); + return DB_CONFIG_DEFAULT; + } + + switch (mode & 0xf) { + case 0xd: + DEBUG_INIT_S("\nInit DB board SLM 1364 D topology\n"); + return DB_CONFIG_SLM1364_D; + case 0xe: + DEBUG_INIT_S("\nInit DB board SLM 1364 E topology\n"); + return DB_CONFIG_SLM1364_E; + case 0xf: + DEBUG_INIT_S("\nInit DB board SLM 1364 F topology\n"); + return DB_CONFIG_SLM1364_F; + default: /* Default configuration */ + DEBUG_INIT_S("\nInit DB board default topology\n"); + return DB_CONFIG_DEFAULT; + } +} + +u8 topology_config_db_381_mode_get(void) +{ + u8 mode; + + DEBUG_INIT_FULL_S("\n### topology_config_db_381_mode_get ###\n"); + + if (!i2c_read(DB381_GET_MODE_SLM1426_1427_ADDR, 0, 2, &mode, 1)) { + switch (mode & 0xf) { + case 0x1: + DEBUG_INIT_S("\nInit DB-381 board SLM 1427 topology\n"); + return DB_CONFIG_SLM1427; + case 0x2: + DEBUG_INIT_S("\nInit DB-381 board SLM 1426 topology\n"); + return DB_CONFIG_SLM1426; + default: /* not the right module */ + break; + } + } + + /* in case not detected any supported module, use default topology */ + DEBUG_INIT_S("\nInit DB-381 board default topology\n"); + return DB_381_CONFIG_DEFAULT; +} + +/* + * Read SatR field 'sgmiispeed' and update lane topology SGMII entries + * speed setup + */ +int update_topology_sgmii_speed(struct serdes_map *serdes_map_array) +{ + u32 serdes_type, lane_num; + u8 config_val; + + /* Update SGMII speed settings by 'sgmiispeed' SatR value */ + for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) { + serdes_type = serdes_map_array[lane_num].serdes_type; + /*Read SatR configuration for SGMII speed */ + if ((serdes_type == SGMII0) || (serdes_type == SGMII1) || + (serdes_type == SGMII2)) { + /* Read SatR 'sgmiispeed' value */ + if (i2c_read(EEPROM_I2C_ADDR, 0, 2, &config_val, 1)) { + printf("%s: TWSI Read of 'sgmiispeed' failed\n", + __func__); + return MV_FAIL; + } + + if (0 == (config_val & 0x40)) { + serdes_map_array[lane_num].serdes_speed = + SERDES_SPEED_1_25_GBPS; + } else { + serdes_map_array[lane_num].serdes_speed = + SERDES_SPEED_3_125_GBPS; + } + } + } + return MV_OK; +} + +struct serdes_map default_lane = { + DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE +}; +int is_custom_topology = 0; /* indicate user of non-default topology */ + +/* + * Read SatR fields (dbserdes1/2 , gpserdes1/2/5) and update lane + * topology accordingly + */ +int update_topology_satr(struct serdes_map *serdes_map_array) +{ + u8 config_val, lane_select, i; + u32 board_id = mv_board_id_get(); + + switch (board_id) { + case DB_68XX_ID: /* read 'dbserdes1' & 'dbserdes2' */ + case DB_BP_6821_ID: + if (i2c_read(EEPROM_I2C_ADDR, 1, 2, &config_val, 1)) { + printf("%s: TWSI Read of 'dbserdes1/2' failed\n", + __func__); + return MV_FAIL; + } + + /* Lane #1 */ + lane_select = (config_val & SATR_DB_LANE1_CFG_MASK) >> + SATR_DB_LANE1_CFG_OFFSET; + if (lane_select >= SATR_DB_LANE1_MAX_OPTIONS) { + printf("\n\%s: Error: invalid value for SatR field 'dbserdes1' (%x)\n", + __func__, lane_select); + printf("\t_skipping Topology update (run 'SatR write default')\n"); + return MV_FAIL; + } + + /* + * If modified default serdes_type for lane#1, update + * topology and mark it as custom + */ + if (serdes_map_array[1].serdes_type != + db_satr_config_lane1[lane_select].serdes_type) { + serdes_map_array[1] = db_satr_config_lane1[lane_select]; + is_custom_topology = 1; + /* DB 381/2 board has inverted SerDes polarity */ + if (board_id == DB_BP_6821_ID) + serdes_map_array[1].swap_rx = + serdes_map_array[1].swap_tx = 1; + } + + /* Lane #2 */ + lane_select = (config_val & SATR_DB_LANE2_CFG_MASK) >> + SATR_DB_LANE2_CFG_OFFSET; + if (lane_select >= SATR_DB_LANE2_MAX_OPTIONS) { + printf("\n\%s: Error: invalid value for SatR field 'dbserdes2' (%x)\n", + __func__, lane_select); + printf("\t_skipping Topology update (run 'SatR write default')\n"); + return MV_FAIL; + } + + /* + * If modified default serdes_type for lane@2, update + * topology and mark it as custom + */ + if (serdes_map_array[2].serdes_type != + db_satr_config_lane2[lane_select].serdes_type) { + serdes_map_array[2] = db_satr_config_lane2[lane_select]; + is_custom_topology = 1; + /* DB 381/2 board has inverted SerDes polarity */ + if (board_id == DB_BP_6821_ID) + serdes_map_array[2].swap_rx = + serdes_map_array[2].swap_tx = 1; + } + + if (is_custom_topology == 1) { + /* + * Check for conflicts with detected lane #1 and + * lane #2 (Disable conflicted lanes) + */ + for (i = 0; i < hws_serdes_get_max_lane(); i++) { + if (i != 1 && serdes_map_array[1].serdes_type == + serdes_map_array[i].serdes_type) { + printf("\t_lane #%d Type conflicts with Lane #1 (Lane #%d disabled)\n", + i, i); + serdes_map_array[i] = + db_satr_config_lane1[0]; + } + + if (i != 2 && + serdes_map_array[2].serdes_type == + serdes_map_array[i].serdes_type) { + printf("\t_lane #%d Type conflicts with Lane #2 (Lane #%d disabled)\n", + i, i); + serdes_map_array[i] = + db_satr_config_lane1[0]; + } + } + } + + break; /* case DB_68XX_ID */ + case DB_GP_68XX_ID: /* read 'gpserdes1' & 'gpserdes2' */ + if (i2c_read(EEPROM_I2C_ADDR, 2, 2, &config_val, 1)) { + printf("%s: TWSI Read of 'gpserdes1/2' failed\n", + __func__); + return MV_FAIL; + } + + /* + * Lane #1: + * lane_select = 0 --> SATA0, + * lane_select = 1 --> PCIe0 (mini PCIe) + */ + lane_select = (config_val & SATR_GP_LANE1_CFG_MASK) >> + SATR_GP_LANE1_CFG_OFFSET; + if (lane_select == 1) { + serdes_map_array[1].serdes_mode = PEX0; + serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS; + serdes_map_array[1].serdes_type = PEX_ROOT_COMPLEX_X1; + /* + * If lane 1 is set to PCIe0 --> disable PCIe0 + * on lane 0 + */ + serdes_map_array[0] = default_lane; + /* indicate user of non-default topology */ + is_custom_topology = 1; + } + printf("Lane 1 detection: %s\n", + lane_select ? "PCIe0 (mini PCIe)" : "SATA0"); + + /* + * Lane #2: + * lane_select = 0 --> SATA1, + * lane_select = 1 --> PCIe1 (mini PCIe) + */ + lane_select = (config_val & SATR_GP_LANE2_CFG_MASK) >> + SATR_GP_LANE2_CFG_OFFSET; + if (lane_select == 1) { + serdes_map_array[2].serdes_type = PEX1; + serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS; + serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1; + /* indicate user of non-default topology */ + is_custom_topology = 1; + } + printf("Lane 2 detection: %s\n", + lane_select ? "PCIe1 (mini PCIe)" : "SATA1"); + break; /* case DB_GP_68XX_ID */ + } + + if (is_custom_topology) + printf("\nDetected custom SerDes topology (to restore default run 'SatR write default')\n\n"); + + return MV_OK; +} + +/* + * hws_update_device_toplogy + * DESCRIPTION: Update the default board topology for specific device Id + * INPUT: + * topology_config_ptr - pointer to the Serdes mapping + * topology_mode - topology mode (index) + * OUTPUT: None + * RRETURNS: + * MV_OK - if updating the board topology success + * MV_BAD_PARAM - if the input parameter is wrong + */ +int hws_update_device_toplogy(struct serdes_map *topology_config_ptr, + enum topology_config_db topology_mode) +{ + u32 dev_id = sys_env_device_id_get(); + u32 board_id = mv_board_id_get(); + + switch (topology_mode) { + case DB_CONFIG_DEFAULT: + switch (dev_id) { + case MV_6810: + /* + * DB-AP : default for Lane3=SGMII2 --> + * 6810 supports only 2 SGMII interfaces: + * lane 3 disabled + */ + if (board_id == DB_AP_68XX_ID) { + printf("Device 6810 supports only 2 SGMII interfaces: SGMII-2 @ lane3 disabled\n"); + topology_config_ptr[3] = default_lane; + } + + /* + * 6810 has only 4 SerDes and the forth one is + * Serdes number 5 (i.e. Serdes 4 is not connected), + * therefore we need to copy SerDes 5 configuration + * to SerDes 4 + */ + printf("Device 6810 does not supports SerDes Lane #4: replaced topology entry with lane #5\n"); + topology_config_ptr[4] = topology_config_ptr[5]; + + /* + * No break between cases since the 1st + * 6820 limitation apply on 6810 + */ + case MV_6820: + /* + * DB-GP & DB-BP: default for Lane3=SATA3 --> + * 6810/20 supports only 2 SATA interfaces: + * lane 3 disabled + */ + if ((board_id == DB_68XX_ID) || + (board_id == DB_GP_68XX_ID)) { + printf("Device 6810/20 supports only 2 SATA interfaces: SATA Port 3 @ lane3 disabled\n"); + topology_config_ptr[3] = default_lane; + } + /* + * DB-GP on 6820 only: default for Lane4=SATA2 + * --> 6820 supports only 2 SATA interfaces: + * lane 3 disabled + */ + if (board_id == DB_GP_68XX_ID && dev_id == MV_6820) { + printf("Device 6820 supports only 2 SATA interfaces: SATA Port 2 @ lane4 disabled\n"); + topology_config_ptr[4] = default_lane; + } + break; + default: + break; + } + break; + + default: + printf("sys_env_update_device_toplogy: selected topology is not supported by this routine\n"); + break; + } + + return MV_OK; +} + +int load_topology_db_381(struct serdes_map *serdes_map_array) +{ + u32 lane_num; + u8 topology_mode; + struct serdes_map *topology_config_ptr; + u8 twsi_data; + u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0; + + printf("\nInitialize DB-88F6821-BP board topology\n"); + + /* Getting the relevant topology mode (index) */ + topology_mode = topology_config_db_381_mode_get(); + topology_config_ptr = topology_config_db_381[topology_mode]; + + /* Read USB3.0 mode: HOST/DEVICE */ + if (load_topology_usb_mode_get(&twsi_data) == MV_OK) { + usb3_host0_or_device = (twsi_data & 0x1); + /* Only one USB3 device is enabled */ + if (usb3_host0_or_device == 0) + usb3_host1_or_device = ((twsi_data >> 1) & 0x1); + } + + /* Updating the topology map */ + for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) { + serdes_map_array[lane_num].serdes_mode = + topology_config_ptr[lane_num].serdes_mode; + serdes_map_array[lane_num].serdes_speed = + topology_config_ptr[lane_num].serdes_speed; + serdes_map_array[lane_num].serdes_type = + topology_config_ptr[lane_num].serdes_type; + serdes_map_array[lane_num].swap_rx = + topology_config_ptr[lane_num].swap_rx; + serdes_map_array[lane_num].swap_tx = + topology_config_ptr[lane_num].swap_tx; + + /* Update USB3 device if needed */ + if (usb3_host0_or_device == 1 && + serdes_map_array[lane_num].serdes_type == USB3_HOST0) + serdes_map_array[lane_num].serdes_type = USB3_DEVICE; + + if (usb3_host1_or_device == 1 && + serdes_map_array[lane_num].serdes_type == USB3_HOST1) + serdes_map_array[lane_num].serdes_type = USB3_DEVICE; + } + + /* If not detected any SerDes Site module, read 'SatR' lane setup */ + if (topology_mode == DB_381_CONFIG_DEFAULT) + update_topology_satr(serdes_map_array); + + /* update 'sgmiispeed' settings */ + update_topology_sgmii_speed(serdes_map_array); + + return MV_OK; +} + +int load_topology_db(struct serdes_map *serdes_map_array) +{ + u32 lane_num; + u8 topology_mode; + struct serdes_map *topology_config_ptr; + u8 twsi_data; + u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0; + + printf("\nInitialize DB-88F6820-BP board topology\n"); + + /* Getting the relevant topology mode (index) */ + topology_mode = topology_config_db_mode_get(); + + if (topology_mode == DB_NO_TOPOLOGY) + topology_mode = DB_CONFIG_DEFAULT; + + topology_config_ptr = topology_config_db[topology_mode]; + + /* Update the default board topology device flavours */ + CHECK_STATUS(hws_update_device_toplogy + (topology_config_ptr, topology_mode)); + + /* Read USB3.0 mode: HOST/DEVICE */ + if (load_topology_usb_mode_get(&twsi_data) == MV_OK) { + usb3_host0_or_device = (twsi_data & 0x1); + /* Only one USB3 device is enabled */ + if (usb3_host0_or_device == 0) + usb3_host1_or_device = ((twsi_data >> 1) & 0x1); + } + + /* Updating the topology map */ + for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) { + serdes_map_array[lane_num].serdes_mode = + topology_config_ptr[lane_num].serdes_mode; + serdes_map_array[lane_num].serdes_speed = + topology_config_ptr[lane_num].serdes_speed; + serdes_map_array[lane_num].serdes_type = + topology_config_ptr[lane_num].serdes_type; + serdes_map_array[lane_num].swap_rx = + topology_config_ptr[lane_num].swap_rx; + serdes_map_array[lane_num].swap_tx = + topology_config_ptr[lane_num].swap_tx; + + /* + * Update USB3 device if needed - relevant for + * lane 3,4,5 only + */ + if (lane_num >= 3) { + if ((serdes_map_array[lane_num].serdes_type == + USB3_HOST0) && (usb3_host0_or_device == 1)) + serdes_map_array[lane_num].serdes_type = + USB3_DEVICE; + + if ((serdes_map_array[lane_num].serdes_type == + USB3_HOST1) && (usb3_host1_or_device == 1)) + serdes_map_array[lane_num].serdes_type = + USB3_DEVICE; + } + } + + /* If not detected any SerDes Site module, read 'SatR' lane setup */ + if (topology_mode == DB_CONFIG_DEFAULT) + update_topology_satr(serdes_map_array); + + /* update 'sgmiispeed' settings */ + update_topology_sgmii_speed(serdes_map_array); + + return MV_OK; +} + +int load_topology_db_ap(struct serdes_map *serdes_map_array) +{ + u32 lane_num; + struct serdes_map *topology_config_ptr; + + DEBUG_INIT_FULL_S("\n### load_topology_db_ap ###\n"); + + printf("\nInitialize DB-AP board topology\n"); + topology_config_ptr = db_ap_config_default; + + /* Update the default board topology device flavours */ + CHECK_STATUS(hws_update_device_toplogy + (topology_config_ptr, DB_CONFIG_DEFAULT)); + + /* Updating the topology map */ + for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) { + serdes_map_array[lane_num].serdes_mode = + topology_config_ptr[lane_num].serdes_mode; + serdes_map_array[lane_num].serdes_speed = + topology_config_ptr[lane_num].serdes_speed; + serdes_map_array[lane_num].serdes_type = + topology_config_ptr[lane_num].serdes_type; + serdes_map_array[lane_num].swap_rx = + topology_config_ptr[lane_num].swap_rx; + serdes_map_array[lane_num].swap_tx = + topology_config_ptr[lane_num].swap_tx; + } + + update_topology_sgmii_speed(serdes_map_array); + + return MV_OK; +} + +int load_topology_db_gp(struct serdes_map *serdes_map_array) +{ + u32 lane_num; + struct serdes_map *topology_config_ptr; + int is_sgmii = 0; + + DEBUG_INIT_FULL_S("\n### load_topology_db_gp ###\n"); + + topology_config_ptr = db_gp_config_default; + + printf("\nInitialize DB-GP board topology\n"); + + /* check S@R: if lane 5 is USB3 or SGMII */ + if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) + printf("%s: TWSI Read failed - Loading Default Topology\n", + __func__); + else { + topology_config_ptr[5].serdes_type = + is_sgmii ? SGMII2 : USB3_HOST1; + topology_config_ptr[5].serdes_speed = is_sgmii ? + SERDES_SPEED_3_125_GBPS : SERDES_SPEED_5_GBPS; + topology_config_ptr[5].serdes_mode = SERDES_DEFAULT_MODE; + } + + /* Update the default board topology device flavours */ + CHECK_STATUS(hws_update_device_toplogy + (topology_config_ptr, DB_CONFIG_DEFAULT)); + + /* Updating the topology map */ + for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) { + serdes_map_array[lane_num].serdes_mode = + topology_config_ptr[lane_num].serdes_mode; + serdes_map_array[lane_num].serdes_speed = + topology_config_ptr[lane_num].serdes_speed; + serdes_map_array[lane_num].serdes_type = + topology_config_ptr[lane_num].serdes_type; + serdes_map_array[lane_num].swap_rx = + topology_config_ptr[lane_num].swap_rx; + serdes_map_array[lane_num].swap_tx = + topology_config_ptr[lane_num].swap_tx; + } + + /* + * Update 'gpserdes1/2/3' lane configuration , and 'sgmiispeed' + * for SGMII lanes + */ + update_topology_satr(serdes_map_array); + update_topology_sgmii_speed(serdes_map_array); + + return MV_OK; +} + +int load_topology_db_amc(struct serdes_map *serdes_map_array) +{ + u32 lane_num; + struct serdes_map *topology_config_ptr; + + DEBUG_INIT_FULL_S("\n### load_topology_db_amc ###\n"); + + printf("\nInitialize DB-AMC board topology\n"); + topology_config_ptr = db_amc_config_default; + + /* Update the default board topology device flavours */ + CHECK_STATUS(hws_update_device_toplogy + (topology_config_ptr, DB_CONFIG_DEFAULT)); + + /* Updating the topology map */ + for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) { + serdes_map_array[lane_num].serdes_mode = + topology_config_ptr[lane_num].serdes_mode; + serdes_map_array[lane_num].serdes_speed = + topology_config_ptr[lane_num].serdes_speed; + serdes_map_array[lane_num].serdes_type = + topology_config_ptr[lane_num].serdes_type; + serdes_map_array[lane_num].swap_rx = + topology_config_ptr[lane_num].swap_rx; + serdes_map_array[lane_num].swap_tx = + topology_config_ptr[lane_num].swap_tx; + } + + update_topology_sgmii_speed(serdes_map_array); + + return MV_OK; +} + +int load_topology_rd(struct serdes_map *serdes_map_array) +{ + u8 mode; + + DEBUG_INIT_FULL_S("\n### load_topology_rd ###\n"); + + DEBUG_INIT_S("\nInit RD board "); + + /* Reading mode */ + DEBUG_INIT_FULL_S("load_topology_rd: getting mode\n"); + if (i2c_read(EEPROM_I2C_ADDR, 0, 2, &mode, 1)) { + DEBUG_INIT_S("load_topology_rd: TWSI Read failed\n"); + return MV_FAIL; + } + + /* Updating the topology map */ + DEBUG_INIT_FULL_S("load_topology_rd: Loading board topology details\n"); + + /* RD mode: 0 = NAS, 1 = AP */ + if (((mode >> 1) & 0x1) == 0) { + CHECK_STATUS(load_topology_rd_nas(serdes_map_array)); + } else { + CHECK_STATUS(load_topology_rd_ap(serdes_map_array)); + } + + update_topology_sgmii_speed(serdes_map_array); + + return MV_OK; +} + +int load_topology_rd_nas(struct serdes_map *serdes_map_array) +{ + int is_sgmii = 0; + u32 i; + + DEBUG_INIT_S("\nInit RD NAS topology "); + + /* check if lane 4 is USB3 or SGMII */ + if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) { + DEBUG_INIT_S("load_topology_rd NAS: TWSI Read failed\n"); + return MV_FAIL; + } + + /* Lane 0 */ + serdes_map_array[0].serdes_type = PEX0; + serdes_map_array[0].serdes_speed = SERDES_SPEED_5_GBPS; + serdes_map_array[0].serdes_mode = PEX_ROOT_COMPLEX_X1; + + /* Lane 1 */ + serdes_map_array[1].serdes_type = SATA0; + serdes_map_array[1].serdes_speed = SERDES_SPEED_3_GBPS; + serdes_map_array[1].serdes_mode = SERDES_DEFAULT_MODE; + + /* Lane 2 */ + serdes_map_array[2].serdes_type = SATA1; + serdes_map_array[2].serdes_speed = SERDES_SPEED_3_GBPS; + serdes_map_array[2].serdes_mode = SERDES_DEFAULT_MODE; + + /* Lane 3 */ + serdes_map_array[3].serdes_type = SATA3; + serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS; + serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE; + + /* Lane 4 */ + if (is_sgmii == 1) { + DEBUG_INIT_S("Serdes Lane 4 is SGMII\n"); + serdes_map_array[4].serdes_type = SGMII1; + serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS; + serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE; + } else { + DEBUG_INIT_S("Serdes Lane 4 is USB3\n"); + serdes_map_array[4].serdes_type = USB3_HOST0; + serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS; + serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE; + } + + /* Lane 5 */ + serdes_map_array[5].serdes_type = SATA2; + serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS; + serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE; + + /* init swap configuration */ + for (i = 0; i <= 5; i++) { + serdes_map_array[i].swap_rx = 0; + serdes_map_array[i].swap_tx = 0; + } + + return MV_OK; +} + +int load_topology_rd_ap(struct serdes_map *serdes_map_array) +{ + int is_sgmii = 0; + u32 i; + + DEBUG_INIT_S("\nInit RD AP topology "); + + /* check if lane 4 is USB3 or SGMII */ + if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) { + DEBUG_INIT_S("load_topology_rd AP: TWSI Read failed\n"); + return MV_FAIL; + } + + /* Lane 0 */ + serdes_map_array[0].serdes_type = DEFAULT_SERDES; + serdes_map_array[0].serdes_speed = LAST_SERDES_SPEED; + serdes_map_array[0].serdes_mode = SERDES_DEFAULT_MODE; + + /* Lane 1 */ + serdes_map_array[1].serdes_type = PEX0; + serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS; + serdes_map_array[1].serdes_mode = PEX_ROOT_COMPLEX_X1; + + /* Lane 2 */ + serdes_map_array[2].serdes_type = PEX1; + serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS; + serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1; + + /* Lane 3 */ + serdes_map_array[3].serdes_type = SATA3; + serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS; + serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE; + + /* Lane 4 */ + if (is_sgmii == 1) { + DEBUG_INIT_S("Serdes Lane 4 is SGMII\n"); + serdes_map_array[4].serdes_type = SGMII1; + serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS; + serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE; + } else { + DEBUG_INIT_S("Serdes Lane 4 is USB3\n"); + serdes_map_array[4].serdes_type = USB3_HOST0; + serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS; + serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE; + } + + /* Lane 5 */ + serdes_map_array[5].serdes_type = SATA2; + serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS; + serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE; + + /* init swap configuration */ + for (i = 0; i <= 5; i++) { + serdes_map_array[i].swap_rx = 0; + serdes_map_array[i].swap_tx = 0; + } + + return MV_OK; +} + +int load_topology_rd_sgmii_usb(int *is_sgmii) +{ + u8 mode; + + /* + * DB-GP board: Device 6810 supports only 2 GbE ports: + * SGMII2 not supported (USE USB3 Host instead) + */ + if (sys_env_device_id_get() == MV_6810) { + printf("Device 6810 supports only 2 GbE ports: SGMII-2 @ lane5 disabled (setting USB3.0 H1 instead)\n"); + *is_sgmii = 0; + return MV_OK; + } + + if (!i2c_read(RD_GET_MODE_ADDR, 1, 2, &mode, 1)) { + *is_sgmii = ((mode >> 2) & 0x1); + } else { + /* else use the default - USB3 */ + *is_sgmii = 0; + } + + if (*is_sgmii) + is_custom_topology = 1; + + printf("Lane 5 detection: %s\n", + *is_sgmii ? "SGMII2" : "USB3.0 Host Port 1"); + + return MV_OK; +} + +/* + * 'usb3port0'/'usb3port1' fields are located in EEPROM, + * at 3rd byte(offset=2), bit 0:1 (respectively) + */ +int load_topology_usb_mode_get(u8 *twsi_data) +{ + if (!i2c_read(EEPROM_I2C_ADDR, 2, 2, twsi_data, 1)) + return MV_OK; + + return MV_ERROR; +} diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h new file mode 100644 index 0000000..3cfb1c7 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _HIGHSPEED_TOPOLOGY_SPEC_H +#define _HIGHSPEED_TOPOLOGY_SPEC_H + +#include "high_speed_env_spec.h" + +/* Topology map options for the DB_A38X_BP board */ +enum topology_config_db { + DB_CONFIG_SLM1363_C, + DB_CONFIG_SLM1363_D, + DB_CONFIG_SLM1363_E, + DB_CONFIG_SLM1363_F, + DB_CONFIG_SLM1364_D, + DB_CONFIG_SLM1364_E, + DB_CONFIG_SLM1364_F, + DB_CONFIG_DEFAULT, + DB_NO_TOPOLOGY +}; + +/* + * this enum must be aligned with topology_config_db_381 array, + * every update to this enum requires update to topology_config_db_381 + * array + */ +enum topology_config_db381 { + DB_CONFIG_SLM1427, /* enum for db_config_slm1427 */ + DB_CONFIG_SLM1426, /* enum for db_config_slm1426 */ + DB_381_CONFIG_DEFAULT, + DB_381_NO_TOPOLOGY +}; + +/* A generic function pointer for loading the board topology map */ +typedef int (*load_topology_func_ptr)(struct serdes_map *serdes_map_array); + +extern load_topology_func_ptr load_topology_func_arr[]; + +/* + * topology_config_db_mode_get - + * + * DESCRIPTION: Gets the relevant topology mode (index). + * for load_topology_db use only. + * INPUT: None. + * OUTPUT: None. + * RETURNS: the topology mode + */ +u8 topology_config_db_mode_get(void); + +/* + * load_topology_xxx - + * + * DESCRIPTION: Loads the board topology for the XXX board + * INPUT: serdes_map_array - The struct that will contain + * the board topology map + * OUTPUT: The board topology map. + * RETURNS: MV_OK for success + * MV_FAIL for failure (a wrong topology mode was read + * from the board) + */ + +/* load_topology_db - Loads the board topology for DB Board */ +int load_topology_db(struct serdes_map *serdes_map_array); + +/* load_topology_rd - Loads the board topology for RD Board */ +int load_topology_rd(struct serdes_map *serdes_map_array); + +/* load_topology_rd_nas - Loads the board topology for RD NAS Board */ +int load_topology_rd_nas(struct serdes_map *serdes_map_array); + +/* load_topology_rd_ap - Loads the board topology for RD Ap Board */ +int load_topology_rd_ap(struct serdes_map *serdes_map_array); + +/* load_topology_db_ap - Loads the board topology for DB-AP Board */ +int load_topology_db_ap(struct serdes_map *serdes_map_array); + +/* load_topology_db_gp - Loads the board topology for DB GP Board */ +int load_topology_db_gp(struct serdes_map *serdes_map_array); + +/* load_topology_db_381 - Loads the board topology for 381 DB-BP Board */ +int load_topology_db_381(struct serdes_map *serdes_map_array); + +/* load_topology_db_amc - Loads the board topology for DB-AMC Board */ +int load_topology_db_amc(struct serdes_map *serdes_map_array); + +/* + * hws_update_device_toplogy + * DESCRIPTION: Update the default board topology for specific device Id + * INPUT: + * topology_config_ptr - pointer to the Serdes mapping + * topology_mode - topology mode (index) + * OUTPUT: None + * RRETURNS: + * MV_OK - if updating the board topology success + * MV_BAD_PARAM - if the input parameter is wrong + */ +int hws_update_device_toplogy(struct serdes_map *topology_config_ptr, + enum topology_config_db topology_mode); + +/* + * load_topology_rd_sgmii_usb - + * + * DESCRIPTION: For RD board check if lane 4 is USB3 or SGMII + * INPUT: None + * OUTPUT: is_sgmii - return 1 if lane 4 is SGMII + * return 0 if lane 4 is USB. + * RETURNS: MV_OK for success + */ +int load_topology_rd_sgmii_usb(int *is_sgmii); + +/* + * load_topology_usb_mode_get - + * + * DESCRIPTION: For DB board check if USB3.0 mode + * INPUT: None + * OUTPUT: twsi_data - return data read from S@R via I2C + * RETURNS: MV_OK for success + */ +int load_topology_usb_mode_get(u8 *twsi_data); + +#endif /* _HIGHSPEED_TOPOLOGY_SPEC_H */ diff --git a/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c new file mode 100644 index 0000000..ee2305b --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "seq_exec.h" +#include "high_speed_env_spec.h" + +#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h" + +#if defined(MV_DEBUG_INIT_FULL) || defined(MV_DEBUG) +#define DB(x) x +#else +#define DB(x) +#endif + +/* Array for mapping the operation (write, poll or delay) functions */ +op_execute_func_ptr op_execute_func_arr[] = { + write_op_execute, + delay_op_execute, + poll_op_execute +}; + +int write_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx) +{ + u32 unit_base_reg, unit_offset, data, mask, reg_data, reg_addr; + + /* Getting write op params from the input parameter */ + data = params->data[data_arr_idx]; + mask = params->mask; + + /* an empty operation */ + if (data == NO_DATA) + return MV_OK; + + /* get updated base address since it can be different between Serdes */ + CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg, + params->unit_offset, + &unit_base_reg, &unit_offset)); + + /* Address calculation */ + reg_addr = unit_base_reg + unit_offset * serdes_num; + +#ifdef SEQ_DEBUG + printf("Write: 0x%x: 0x%x (mask 0x%x) - ", reg_addr, data, mask); +#endif + /* Reading old value */ + reg_data = reg_read(reg_addr); + reg_data &= (~mask); + + /* Writing new data */ + data &= mask; + reg_data |= data; + reg_write(reg_addr, reg_data); + +#ifdef SEQ_DEBUG + printf(" - 0x%x\n", reg_data); +#endif + + return MV_OK; +} + +int delay_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx) +{ + u32 delay; + + /* Getting delay op params from the input parameter */ + delay = params->wait_time; +#ifdef SEQ_DEBUG + printf("Delay: %d\n", delay); +#endif + mdelay(delay); + + return MV_OK; +} + +int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx) +{ + u32 unit_base_reg, unit_offset, data, mask, num_of_loops, wait_time; + u32 poll_counter = 0; + u32 reg_addr, reg_data; + + /* Getting poll op params from the input parameter */ + data = params->data[data_arr_idx]; + mask = params->mask; + num_of_loops = params->num_of_loops; + wait_time = params->wait_time; + + /* an empty operation */ + if (data == NO_DATA) + return MV_OK; + + /* get updated base address since it can be different between Serdes */ + CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg, + params->unit_offset, + &unit_base_reg, &unit_offset)); + + /* Address calculation */ + reg_addr = unit_base_reg + unit_offset * serdes_num; + + /* Polling */ +#ifdef SEQ_DEBUG + printf("Poll: 0x%x: 0x%x (mask 0x%x)\n", reg_addr, data, mask); +#endif + + do { + reg_data = reg_read(reg_addr) & mask; + poll_counter++; + udelay(wait_time); + } while ((reg_data != data) && (poll_counter < num_of_loops)); + + if ((poll_counter >= num_of_loops) && (reg_data != data)) { + DEBUG_INIT_S("poll_op_execute: TIMEOUT\n"); + return MV_TIMEOUT; + } + + return MV_OK; +} + +enum mv_op get_cfg_seq_op(struct op_params *params) +{ + if (params->wait_time == 0) + return WRITE_OP; + else if (params->num_of_loops == 0) + return DELAY_OP; + + return POLL_OP; +} + +int mv_seq_exec(u32 serdes_num, u32 seq_id) +{ + u32 seq_idx; + struct op_params *seq_arr; + u32 seq_size; + u32 data_arr_idx; + enum mv_op curr_op; + + DB(printf("\n### mv_seq_exec ###\n")); + DB(printf("seq id: %d\n", seq_id)); + + if (hws_is_serdes_active(serdes_num) != 1) { + printf("mv_seq_exec_ext:Error: SerDes lane %d is not valid\n", + serdes_num); + return MV_BAD_PARAM; + } + + seq_arr = serdes_seq_db[seq_id].op_params_ptr; + seq_size = serdes_seq_db[seq_id].cfg_seq_size; + data_arr_idx = serdes_seq_db[seq_id].data_arr_idx; + + DB(printf("seq_size: %d\n", seq_size)); + DB(printf("data_arr_idx: %d\n", data_arr_idx)); + + /* Executing the sequence operations */ + for (seq_idx = 0; seq_idx < seq_size; seq_idx++) { + curr_op = get_cfg_seq_op(&seq_arr[seq_idx]); + op_execute_func_arr[curr_op](serdes_num, &seq_arr[seq_idx], + data_arr_idx); + } + + return MV_OK; +} diff --git a/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h new file mode 100644 index 0000000..14f406a --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _SEQ_EXEC_H +#define _SEQ_EXEC_H + +#define NA 0xff +#define DEFAULT_PARAM 0 +#define MV_BOARD_TCLK_ERROR 0xffffffff + +#define NO_DATA 0xffffffff +#define MAX_DATA_ARRAY 5 +#define FIRST_CELL 0 + +/* Operation types */ +enum mv_op { + WRITE_OP, + DELAY_OP, + POLL_OP, +}; + +/* Operation parameters */ +struct op_params { + u32 unit_base_reg; + u32 unit_offset; + u32 mask; + u32 data[MAX_DATA_ARRAY]; /* data array */ + u8 wait_time; /* msec */ + u16 num_of_loops; /* for polling only */ +}; + +/* + * Sequence parameters. Each sequence contains: + * 1. Sequence id. + * 2. Sequence size (total amount of operations during the sequence) + * 3. a series of operations. operations can be write, poll or delay + * 4. index in the data array (the entry where the relevant data sits) + */ +struct cfg_seq { + struct op_params *op_params_ptr; + u8 cfg_seq_size; + u8 data_arr_idx; +}; + +extern struct cfg_seq serdes_seq_db[]; + +/* + * A generic function type for executing an operation (write, poll or delay) + */ +typedef int (*op_execute_func_ptr)(u32 serdes_num, struct op_params *params, + u32 data_arr_idx); + +/* Specific functions for executing each operation */ +int write_op_execute(u32 serdes_num, struct op_params *params, + u32 data_arr_idx); +int delay_op_execute(u32 serdes_num, struct op_params *params, + u32 data_arr_idx); +int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx); +enum mv_op get_cfg_seq_op(struct op_params *params); +int mv_seq_exec(u32 serdes_num, u32 seq_id); + +#endif /*_SEQ_EXEC_H*/ diff --git a/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c new file mode 100644 index 0000000..efd3873 --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "seq_exec.h" +#include "sys_env_lib.h" + +#include "../../../drivers/ddr/marvell/a38x/ddr3_a38x.h" + +#ifdef CONFIG_ARMADA_38X +enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = { +/* 6820 6810 6811 6828 */ +/* PEX_UNIT_ID */ { 4, 3, 3, 4}, +/* ETH_GIG_UNIT_ID */ { 3, 2, 3, 3}, +/* USB3H_UNIT_ID */ { 2, 2, 2, 2}, +/* USB3D_UNIT_ID */ { 1, 1, 1, 1}, +/* SATA_UNIT_ID */ { 2, 2, 2, 4}, +/* QSGMII_UNIT_ID */ { 1, 0, 0, 1}, +/* XAUI_UNIT_ID */ { 0, 0, 0, 0}, +/* RXAUI_UNIT_ID */ { 0, 0, 0, 0} +}; +#else /* if (CONFIG_ARMADA_39X) */ +enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = { +/* 6920 6928 */ +/* PEX_UNIT_ID */ { 4, 4}, +/* ETH_GIG_UNIT_ID */ { 3, 4}, +/* USB3H_UNIT_ID */ { 1, 2}, +/* USB3D_UNIT_ID */ { 0, 1}, +/* SATA_UNIT_ID */ { 0, 4}, +/* QSGMII_UNIT_ID */ { 0, 1}, +/* XAUI_UNIT_ID */ { 1, 1}, +/* RXAUI_UNIT_ID */ { 1, 1} +}; +#endif + +u32 g_dev_id = -1; + +u32 mv_board_id_get(void) +{ +#if defined(CONFIG_DB_88F6820_GP) + return DB_GP_68XX_ID; +#else + /* + * Return 0 here for custom board as this should not be used + * for custom boards. + */ + return 0; +#endif +} + +u32 mv_board_tclk_get(void) +{ + u32 value; + + value = (reg_read(DEVICE_SAMPLE_AT_RESET1_REG) >> 15) & 0x1; + + switch (value) { + case (0x0): + return 250000000; + case (0x1): + return 200000000; + default: + return 0xffffffff; + } +} + +u32 mv_board_id_index_get(u32 board_id) +{ + /* + * Marvell Boards use 0x10 as base for Board ID: + * mask MSB to receive index for board ID + */ + return board_id & (MARVELL_BOARD_ID_MASK - 1); +} + +/* + * sys_env_suspend_wakeup_check + * DESCRIPTION: Reads GPIO input for suspend-wakeup indication. + * INPUT: None. + * OUTPUT: + * RETURNS: u32 indicating suspend wakeup status: + * 0 - Not supported, + * 1 - supported: read magic word detect wakeup, + * 2 - detected wakeup from GPIO. + */ +enum suspend_wakeup_status sys_env_suspend_wakeup_check(void) +{ + u32 reg, board_id_index, gpio; + struct board_wakeup_gpio board_gpio[] = MV_BOARD_WAKEUP_GPIO_INFO; + + board_id_index = mv_board_id_index_get(mv_board_id_get()); + if (!(sizeof(board_gpio) / sizeof(struct board_wakeup_gpio) > + board_id_index)) { + printf("\n_failed loading Suspend-Wakeup information (invalid board ID)\n"); + return SUSPEND_WAKEUP_DISABLED; + } + + /* + * - Detect if Suspend-Wakeup is supported on current board + * - Fetch the GPIO number for wakeup status input indication + */ + if (board_gpio[board_id_index].gpio_num == -1) { + /* Suspend to RAM is not supported */ + return SUSPEND_WAKEUP_DISABLED; + } else if (board_gpio[board_id_index].gpio_num == -2) { + /* + * Suspend to RAM is supported but GPIO indication is + * not implemented - Skip + */ + return SUSPEND_WAKEUP_ENABLED; + } else { + gpio = board_gpio[board_id_index].gpio_num; + } + + /* Initialize MPP for GPIO (set MPP = 0x0) */ + reg = reg_read(MPP_CONTROL_REG(MPP_REG_NUM(gpio))); + /* reset MPP21 to 0x0, keep rest of MPP settings*/ + reg &= ~MPP_MASK(gpio); + reg_write(MPP_CONTROL_REG(MPP_REG_NUM(gpio)), reg); + + /* Initialize GPIO as input */ + reg = reg_read(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio))); + reg |= GPP_MASK(gpio); + reg_write(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)), reg); + + /* + * Check GPP for input status from PIC: 0 - regular init, + * 1 - suspend wakeup + */ + reg = reg_read(GPP_DATA_IN_REG(GPP_REG_NUM(gpio))); + + /* if GPIO is ON: wakeup from S2RAM indication detected */ + return (reg & GPP_MASK(gpio)) ? SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED : + SUSPEND_WAKEUP_DISABLED; +} + +/* + * mv_ctrl_dev_id_index_get + * + * DESCRIPTION: return SOC device index + * INPUT: None + * OUTPUT: None + * RETURN: + * return SOC device index + */ +u32 sys_env_id_index_get(u32 ctrl_model) +{ + switch (ctrl_model) { + case MV_6820_DEV_ID: + return MV_6820_INDEX; + case MV_6810_DEV_ID: + return MV_6810_INDEX; + case MV_6811_DEV_ID: + return MV_6811_INDEX; + case MV_6828_DEV_ID: + return MV_6828_INDEX; + case MV_6920_DEV_ID: + return MV_6920_INDEX; + case MV_6928_DEV_ID: + return MV_6928_INDEX; + default: + return MV_6820_INDEX; + } +} + +u32 sys_env_unit_max_num_get(enum unit_id unit) +{ + u32 dev_id_index; + + if (unit >= MAX_UNITS_ID) { + printf("%s: Error: Wrong unit type (%u)\n", __func__, unit); + return 0; + } + + dev_id_index = sys_env_id_index_get(sys_env_model_get()); + return sys_env_soc_unit_nums[unit][dev_id_index]; +} + +/* + * sys_env_model_get + * DESCRIPTION: Returns 16bit describing the device model (ID) as defined + * in Vendor ID configuration register + */ +u16 sys_env_model_get(void) +{ + u32 default_ctrl_id, ctrl_id = reg_read(DEV_ID_REG); + ctrl_id = (ctrl_id & (DEV_ID_REG_DEVICE_ID_MASK)) >> + DEV_ID_REG_DEVICE_ID_OFFS; + + switch (ctrl_id) { + case MV_6820_DEV_ID: + case MV_6810_DEV_ID: + case MV_6811_DEV_ID: + case MV_6828_DEV_ID: + case MV_6920_DEV_ID: + case MV_6928_DEV_ID: + return ctrl_id; + default: + /* Device ID Default for A38x: 6820 , for A39x: 6920 */ + #ifdef CONFIG_ARMADA_38X + default_ctrl_id = MV_6820_DEV_ID; + #else + default_ctrl_id = MV_6920_DEV_ID; + #endif + printf("%s: Error retrieving device ID (%x), using default ID = %x\n", + __func__, ctrl_id, default_ctrl_id); + return default_ctrl_id; + } +} + +/* + * sys_env_device_id_get + * DESCRIPTION: Returns enum (0..7) index of the device model (ID) + */ +u32 sys_env_device_id_get(void) +{ + char *device_id_str[7] = { + "6810", "6820", "6811", "6828", "NONE", "6920", "6928" + }; + + if (g_dev_id != -1) + return g_dev_id; + + g_dev_id = reg_read(DEVICE_SAMPLE_AT_RESET1_REG); + g_dev_id = g_dev_id >> SAR_DEV_ID_OFFS & SAR_DEV_ID_MASK; + printf("Detected Device ID %s\n", device_id_str[g_dev_id]); + + return g_dev_id; +} + +#ifdef MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI +/* +* sys_env_get_topology_update_info +* DESCRIPTION: Read TWSI fields to update DDR topology structure +* INPUT: None +* OUTPUT: None, 0 means no topology update +* RETURN: +* Bit mask of changes topology features +*/ +#ifdef CONFIG_ARMADA_39X +u32 sys_env_get_topology_update_info( + struct topology_update_info *tui) +{ + /* Set 16/32 bit configuration*/ + tui->update_width = 1; + tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT; + +#ifdef CONFIG_DDR3 + if (1 == sys_env_config_get(MV_CONFIG_DDR_BUSWIDTH)) { + /* 16bit */ + tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT; + } else { + /* 32bit */ + tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT; + } +#endif + + /* Set ECC/no ECC bit configuration */ + tui->update_ecc = 1; + if (0 == sys_env_config_get(MV_CONFIG_DDR_ECC_EN)) { + /* NO ECC */ + tui->ecc = TOPOLOGY_UPDATE_ECC_OFF; + } else { + /* ECC */ + tui->ecc = TOPOLOGY_UPDATE_ECC_ON; + } + + tui->update_ecc_pup3_mode = 1; + tui->ecc_pup_mode_offset = TOPOLOGY_UPDATE_ECC_OFFSET_PUP4; + + return MV_OK; +} +#else /*CONFIG_ARMADA_38X*/ +u32 sys_env_get_topology_update_info( + struct topology_update_info *tui) +{ + u8 config_val; + u8 ecc_mode[A38X_MV_MAX_MARVELL_BOARD_ID - + A38X_MARVELL_BOARD_ID_BASE][5] = TOPOLOGY_UPDATE; + u8 board_id = mv_board_id_get(); + int ret; + + board_id = mv_board_id_index_get(board_id); + ret = i2c_read(EEPROM_I2C_ADDR, 0, 2, &config_val, 1); + if (ret) { + DEBUG_INIT_S("sys_env_get_topology_update_info: TWSI Read failed\n"); + return 0; + } + + /* Set 16/32 bit configuration */ + if ((0 == (config_val & DDR_SATR_CONFIG_MASK_WIDTH)) || + (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] == 0)) { + /* 16bit by SatR of 32bit mode not supported for the board */ + if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT] != 0)) { + tui->update_width = 1; + tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT; + } + } else { + /* 32bit */ + if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] != 0)) { + tui->update_width = 1; + tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT; + } + } + + /* Set ECC/no ECC bit configuration */ + if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC)) { + /* NO ECC */ + tui->update_ecc = 1; + tui->ecc = TOPOLOGY_UPDATE_ECC_OFF; + } else { + /* ECC */ + if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) || + (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0) || + (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) { + tui->update_ecc = 1; + tui->ecc = TOPOLOGY_UPDATE_ECC_ON; + } + } + + /* Set ECC pup bit configuration */ + if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC_PUP)) { + /* PUP3 */ + /* + * Check if PUP3 configuration allowed, if not - + * force Pup4 with warning message + */ + if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) { + if (tui->width == TOPOLOGY_UPDATE_WIDTH_16BIT) { + tui->update_ecc_pup3_mode = 1; + tui->ecc_pup_mode_offset = + TOPOLOGY_UPDATE_ECC_OFFSET_PUP3; + } else { + if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0)) { + printf("DDR Topology Update: ECC PUP3 not valid for 32bit mode, force ECC in PUP4\n"); + tui->update_ecc_pup3_mode = 1; + tui->ecc_pup_mode_offset = + TOPOLOGY_UPDATE_ECC_OFFSET_PUP4; + } + } + } else { + if (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != + 0) { + printf("DDR Topology Update: ECC on PUP3 not supported, force ECC on PUP4\n"); + tui->update_ecc_pup3_mode = 1; + tui->ecc_pup_mode_offset = + TOPOLOGY_UPDATE_ECC_OFFSET_PUP4; + } + } + } else { + /* PUP4 */ + if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) || + (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0)) { + tui->update_ecc_pup3_mode = 1; + tui->ecc_pup_mode_offset = + TOPOLOGY_UPDATE_ECC_OFFSET_PUP4; + } + } + + /* + * Check for forbidden ECC mode, + * if by default width and pup selection set 32bit ECC mode and this + * mode not supported for the board - config 16bit with ECC on PUP3 + */ + if ((tui->ecc == TOPOLOGY_UPDATE_ECC_ON) && + (tui->width == TOPOLOGY_UPDATE_WIDTH_32BIT)) { + if (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] == 0) { + printf("DDR Topology Update: 32bit mode with ECC not allowed on this board, forced 16bit with ECC on PUP3\n"); + tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT; + tui->update_ecc_pup3_mode = 1; + tui->ecc_pup_mode_offset = + TOPOLOGY_UPDATE_ECC_OFFSET_PUP3; + } + } + + return MV_OK; +} +#endif /* CONFIG_ARMADA_38X */ +#endif /* MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI */ diff --git a/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h new file mode 100644 index 0000000..3e5373c --- /dev/null +++ b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h @@ -0,0 +1,371 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _SYS_ENV_LIB_H +#define _SYS_ENV_LIB_H + +#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h" +#include "../../../drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h" + +/* Serdes definitions */ +#define COMMON_PHY_BASE_ADDR 0x18300 + +#define DEVICE_CONFIGURATION_REG0 0x18284 +#define DEVICE_CONFIGURATION_REG1 0x18288 +#define COMMON_PHY_CONFIGURATION1_REG 0x18300 +#define COMMON_PHY_CONFIGURATION2_REG 0x18304 +#define COMMON_PHY_CONFIGURATION4_REG 0x1830c +#define COMMON_PHY_STATUS1_REG 0x18318 +#define COMMON_PHYS_SELECTORS_REG 0x183fc +#define SOC_CONTROL_REG1 0x18204 +#define GENERAL_PURPOSE_RESERVED0_REG 0x182e0 +#define GBE_CONFIGURATION_REG 0x18460 +#define DEVICE_SAMPLE_AT_RESET1_REG 0x18600 +#define DEVICE_SAMPLE_AT_RESET2_REG 0x18604 +#define DEV_ID_REG 0x18238 + +#define CORE_PLL_PARAMETERS_REG 0xe42e0 +#define CORE_PLL_CONFIG_REG 0xe42e4 + +#define QSGMII_CONTROL_REG1 0x18494 + +#define DEV_ID_REG_DEVICE_ID_OFFS 16 +#define DEV_ID_REG_DEVICE_ID_MASK 0xffff0000 + +#define SAR_DEV_ID_OFFS 27 +#define SAR_DEV_ID_MASK 0x7 + +#define POWER_AND_PLL_CTRL_REG 0xa0004 +#define CALIBRATION_CTRL_REG 0xa0008 +#define DFE_REG0 0xa001c +#define DFE_REG3 0xa0028 +#define RESET_DFE_REG 0xa0148 +#define LOOPBACK_REG 0xa008c +#define SYNC_PATTERN_REG 0xa0090 +#define INTERFACE_REG 0xa0094 +#define ISOLATE_REG 0xa0098 +#define MISC_REG 0xa013c +#define GLUE_REG 0xa0140 +#define GENERATION_DIVIDER_FORCE_REG 0xa0144 +#define PCIE_REG0 0xa0120 +#define LANE_ALIGN_REG0 0xa0124 +#define SQUELCH_FFE_SETTING_REG 0xa0018 +#define G1_SETTINGS_0_REG 0xa0034 +#define G1_SETTINGS_1_REG 0xa0038 +#define G1_SETTINGS_3_REG 0xa0440 +#define G1_SETTINGS_4_REG 0xa0444 +#define G2_SETTINGS_0_REG 0xa003c +#define G2_SETTINGS_1_REG 0xa0040 +#define G2_SETTINGS_2_REG 0xa00f8 +#define G2_SETTINGS_3_REG 0xa0448 +#define G2_SETTINGS_4_REG 0xa044c +#define G3_SETTINGS_0_REG 0xa0044 +#define G3_SETTINGS_1_REG 0xa0048 +#define G3_SETTINGS_3_REG 0xa0450 +#define G3_SETTINGS_4_REG 0xa0454 +#define VTHIMPCAL_CTRL_REG 0xa0104 +#define REF_REG0 0xa0134 +#define CAL_REG6 0xa0168 +#define RX_REG2 0xa0184 +#define RX_REG3 0xa0188 +#define PCIE_REG1 0xa0288 +#define PCIE_REG3 0xa0290 +#define LANE_CFG1_REG 0xa0604 +#define LANE_CFG4_REG 0xa0620 +#define LANE_CFG5_REG 0xa0624 +#define GLOBAL_CLK_CTRL 0xa0704 +#define GLOBAL_MISC_CTRL 0xa0718 +#define GLOBAL_CLK_SRC_HI 0xa0710 + +#define GLOBAL_CLK_CTRL 0xa0704 +#define GLOBAL_MISC_CTRL 0xa0718 +#define GLOBAL_PM_CTRL 0xa0740 + +/* SATA registers */ +#define SATA_CTRL_REG_IND_ADDR 0xa80a0 +#define SATA_CTRL_REG_IND_DATA 0xa80a4 + +#define SATA_VENDOR_PORT_0_REG_ADDR 0xa8178 +#define SATA_VENDOR_PORT_1_REG_ADDR 0xa81f8 +#define SATA_VENDOR_PORT_0_REG_DATA 0xa817c +#define SATA_VENDOR_PORT_1_REG_DATA 0xa81fc + +/* Reference clock values and mask */ +#define POWER_AND_PLL_CTRL_REG_100MHZ_VAL 0x0 +#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1 0x1 +#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2 0x2 +#define POWER_AND_PLL_CTRL_REG_40MHZ_VAL 0x3 +#define GLOBAL_PM_CTRL_REG_25MHZ_VAL 0x7 +#define GLOBAL_PM_CTRL_REG_40MHZ_VAL 0xc +#define LANE_CFG4_REG_25MHZ_VAL 0x200 +#define LANE_CFG4_REG_40MHZ_VAL 0x300 + +#define POWER_AND_PLL_CTRL_REG_MASK (~(0x1f)) +#define GLOBAL_PM_CTRL_REG_MASK (~(0xff)) +#define LANE_CFG4_REG_MASK (~(0x1f00)) + +#define REF_CLK_SELECTOR_VAL_PEX0(reg_val) (reg_val >> 2) & 0x1 +#define REF_CLK_SELECTOR_VAL_PEX1(reg_val) (reg_val >> 3) & 0x1 +#define REF_CLK_SELECTOR_VAL_PEX2(reg_val) (reg_val >> 30) & 0x1 +#define REF_CLK_SELECTOR_VAL_PEX3(reg_val) (reg_val >> 31) & 0x1 +#define REF_CLK_SELECTOR_VAL(reg_val) (reg_val & 0x1) + +#define MAX_SELECTOR_VAL 10 + +/* TWSI addresses */ +/* starting from A38x A0, i2c address of EEPROM is 0x57 */ +#ifdef CONFIG_ARMADA_39X +#define EEPROM_I2C_ADDR 0x50 +#else +#define EEPROM_I2C_ADDR (sys_env_device_rev_get() == \ + MV_88F68XX_Z1_ID ? 0x50 : 0x57) +#endif +#define RD_GET_MODE_ADDR 0x4c +#define DB_GET_MODE_SLM1363_ADDR 0x25 +#define DB_GET_MODE_SLM1364_ADDR 0x24 +#define DB381_GET_MODE_SLM1426_1427_ADDR 0x56 + +/* DB-BP Board 'SatR' mapping */ +#define SATR_DB_LANE1_MAX_OPTIONS 7 +#define SATR_DB_LANE1_CFG_MASK 0x7 +#define SATR_DB_LANE1_CFG_OFFSET 0 +#define SATR_DB_LANE2_MAX_OPTIONS 4 +#define SATR_DB_LANE2_CFG_MASK 0x38 +#define SATR_DB_LANE2_CFG_OFFSET 3 + +/* GP Board 'SatR' mapping */ +#define SATR_GP_LANE1_CFG_MASK 0x4 +#define SATR_GP_LANE1_CFG_OFFSET 2 +#define SATR_GP_LANE2_CFG_MASK 0x8 +#define SATR_GP_LANE2_CFG_OFFSET 3 + +/* For setting MPP2 and MPP3 to be TWSI mode and MPP 0,1 to UART mode */ +#define MPP_CTRL_REG 0x18000 +#define MPP_SET_MASK (~(0xffff)) +#define MPP_SET_DATA (0x1111) +#define MPP_UART1_SET_MASK (~(0xff000)) +#define MPP_UART1_SET_DATA (0x66000) + +#define AVS_DEBUG_CNTR_REG 0xe4124 +#define AVS_DEBUG_CNTR_DEFAULT_VALUE 0x08008073 + +#define AVS_ENABLED_CONTROL 0xe4130 +#define AVS_LOW_VDD_LIMIT_OFFS 4 +#define AVS_LOW_VDD_LIMIT_MASK (0xff << AVS_LOW_VDD_LIMIT_OFFS) +#define AVS_LOW_VDD_LIMIT_VAL (0x27 << AVS_LOW_VDD_LIMIT_OFFS) + +#define AVS_HIGH_VDD_LIMIT_OFFS 12 +#define AVS_HIGH_VDD_LIMIT_MASK (0xff << AVS_HIGH_VDD_LIMIT_OFFS) +#define AVS_HIGH_VDD_LIMIT_VAL (0x27 << AVS_HIGH_VDD_LIMIT_OFFS) + +/* Board ID numbers */ +#define MARVELL_BOARD_ID_MASK 0x10 +/* Customer boards for A38x */ +#define A38X_CUSTOMER_BOARD_ID_BASE 0x0 +#define A38X_CUSTOMER_BOARD_ID0 (A38X_CUSTOMER_BOARD_ID_BASE + 0) +#define A38X_CUSTOMER_BOARD_ID1 (A38X_CUSTOMER_BOARD_ID_BASE + 1) +#define A38X_MV_MAX_CUSTOMER_BOARD_ID (A38X_CUSTOMER_BOARD_ID_BASE + 2) +#define A38X_MV_CUSTOMER_BOARD_NUM (A38X_MV_MAX_CUSTOMER_BOARD_ID - \ + A38X_CUSTOMER_BOARD_ID_BASE) + +/* Marvell boards for A38x */ +#define A38X_MARVELL_BOARD_ID_BASE 0x10 +#define RD_NAS_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 0) +#define DB_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 1) +#define RD_AP_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 2) +#define DB_AP_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 3) +#define DB_GP_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 4) +#define DB_BP_6821_ID (A38X_MARVELL_BOARD_ID_BASE + 5) +#define DB_AMC_6820_ID (A38X_MARVELL_BOARD_ID_BASE + 6) +#define A38X_MV_MAX_MARVELL_BOARD_ID (A38X_MARVELL_BOARD_ID_BASE + 7) +#define A38X_MV_MARVELL_BOARD_NUM (A38X_MV_MAX_MARVELL_BOARD_ID - \ + A38X_MARVELL_BOARD_ID_BASE) + +/* Customer boards for A39x */ +#define A39X_CUSTOMER_BOARD_ID_BASE 0x20 +#define A39X_CUSTOMER_BOARD_ID0 (A39X_CUSTOMER_BOARD_ID_BASE + 0) +#define A39X_CUSTOMER_BOARD_ID1 (A39X_CUSTOMER_BOARD_ID_BASE + 1) +#define A39X_MV_MAX_CUSTOMER_BOARD_ID (A39X_CUSTOMER_BOARD_ID_BASE + 2) +#define A39X_MV_CUSTOMER_BOARD_NUM (A39X_MV_MAX_CUSTOMER_BOARD_ID - \ + A39X_CUSTOMER_BOARD_ID_BASE) + +/* Marvell boards for A39x */ +#define A39X_MARVELL_BOARD_ID_BASE 0x30 +#define A39X_DB_69XX_ID (A39X_MARVELL_BOARD_ID_BASE + 0) +#define A39X_RD_69XX_ID (A39X_MARVELL_BOARD_ID_BASE + 1) +#define A39X_MV_MAX_MARVELL_BOARD_ID (A39X_MARVELL_BOARD_ID_BASE + 2) +#define A39X_MV_MARVELL_BOARD_NUM (A39X_MV_MAX_MARVELL_BOARD_ID - \ + A39X_MARVELL_BOARD_ID_BASE) + +#ifdef CONFIG_ARMADA_38X +#define CUTOMER_BOARD_ID_BASE A38X_CUSTOMER_BOARD_ID_BASE +#define CUSTOMER_BOARD_ID0 A38X_CUSTOMER_BOARD_ID0 +#define CUSTOMER_BOARD_ID1 A38X_CUSTOMER_BOARD_ID1 +#define MV_MAX_CUSTOMER_BOARD_ID A38X_MV_MAX_CUSTOMER_BOARD_ID +#define MV_CUSTOMER_BOARD_NUM A38X_MV_CUSTOMER_BOARD_NUM +#define MARVELL_BOARD_ID_BASE A38X_MARVELL_BOARD_ID_BASE +#define MV_MAX_MARVELL_BOARD_ID A38X_MV_MAX_MARVELL_BOARD_ID +#define MV_MARVELL_BOARD_NUM A38X_MV_MARVELL_BOARD_NUM +#define MV_DEFAULT_BOARD_ID DB_68XX_ID +#define MV_DEFAULT_DEVICE_ID MV_6811 +#elif defined(CONFIG_ARMADA_39X) +#define CUTOMER_BOARD_ID_BASE A39X_CUSTOMER_BOARD_ID_BASE +#define CUSTOMER_BOARD_ID0 A39X_CUSTOMER_BOARD_ID0 +#define CUSTOMER_BOARD_ID1 A39X_CUSTOMER_BOARD_ID1 +#define MV_MAX_CUSTOMER_BOARD_ID A39X_MV_MAX_CUSTOMER_BOARD_ID +#define MV_CUSTOMER_BOARD_NUM A39X_MV_CUSTOMER_BOARD_NUM +#define MARVELL_BOARD_ID_BASE A39X_MARVELL_BOARD_ID_BASE +#define MV_MAX_MARVELL_BOARD_ID A39X_MV_MAX_MARVELL_BOARD_ID +#define MV_MARVELL_BOARD_NUM A39X_MV_MARVELL_BOARD_NUM +#define MV_DEFAULT_BOARD_ID A39X_DB_69XX_ID +#define MV_DEFAULT_DEVICE_ID MV_6920 +#endif + +#define MV_INVALID_BOARD_ID 0xffffffff + +/* device revesion */ +#define DEV_VERSION_ID_REG 0x1823c +#define REVISON_ID_OFFS 8 +#define REVISON_ID_MASK 0xf00 + +/* A38x revisions */ +#define MV_88F68XX_Z1_ID 0x0 +#define MV_88F68XX_A0_ID 0x4 +/* A39x revisions */ +#define MV_88F69XX_Z1_ID 0x2 + +#define MPP_CONTROL_REG(id) (0x18000 + (id * 4)) +#define GPP_DATA_OUT_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x00) +#define GPP_DATA_OUT_EN_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x04) +#define GPP_DATA_IN_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x10) +#define MV_GPP_REGS_BASE(unit) (0x18100 + ((unit) * 0x40)) + +#define MPP_REG_NUM(GPIO_NUM) (GPIO_NUM / 8) +#define MPP_MASK(GPIO_NUM) (0xf << 4 * (GPIO_NUM - \ + (MPP_REG_NUM(GPIO_NUM) * 8))); +#define GPP_REG_NUM(GPIO_NUM) (GPIO_NUM / 32) +#define GPP_MASK(GPIO_NUM) (1 << GPIO_NUM % 32) + +/* device ID */ +/* Armada 38x Family */ +#define MV_6810_DEV_ID 0x6810 +#define MV_6811_DEV_ID 0x6811 +#define MV_6820_DEV_ID 0x6820 +#define MV_6828_DEV_ID 0x6828 +/* Armada 39x Family */ +#define MV_6920_DEV_ID 0x6920 +#define MV_6928_DEV_ID 0x6928 + +enum { + MV_6810, + MV_6820, + MV_6811, + MV_6828, + MV_NONE, + MV_6920, + MV_6928, + MV_MAX_DEV_ID, +}; + +#define MV_6820_INDEX 0 +#define MV_6810_INDEX 1 +#define MV_6811_INDEX 2 +#define MV_6828_INDEX 3 + +#define MV_6920_INDEX 0 +#define MV_6928_INDEX 1 + +#ifdef CONFIG_ARMADA_38X +#define MAX_DEV_ID_NUM 4 +#else +#define MAX_DEV_ID_NUM 2 +#endif + +#define MV_6820_INDEX 0 +#define MV_6810_INDEX 1 +#define MV_6811_INDEX 2 +#define MV_6828_INDEX 3 +#define MV_6920_INDEX 0 +#define MV_6928_INDEX 1 + +enum unit_id { + PEX_UNIT_ID, + ETH_GIG_UNIT_ID, + USB3H_UNIT_ID, + USB3D_UNIT_ID, + SATA_UNIT_ID, + QSGMII_UNIT_ID, + XAUI_UNIT_ID, + RXAUI_UNIT_ID, + MAX_UNITS_ID +}; + +struct board_wakeup_gpio { + u32 board_id; + int gpio_num; +}; + +enum suspend_wakeup_status { + SUSPEND_WAKEUP_DISABLED, + SUSPEND_WAKEUP_ENABLED, + SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED, +}; + +/* + * GPIO status indication for Suspend Wakeup: + * If suspend to RAM is supported and GPIO inidcation is implemented, + * set the gpio number + * If suspend to RAM is supported but GPIO indication is not implemented + * set '-2' + * If suspend to RAM is not supported set '-1' + */ +#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT +#ifdef CONFIG_ARMADA_38X +#define MV_BOARD_WAKEUP_GPIO_INFO { \ + {A38X_CUSTOMER_BOARD_ID0, -1 }, \ + {A38X_CUSTOMER_BOARD_ID0, -1 }, \ +}; +#else +#define MV_BOARD_WAKEUP_GPIO_INFO { \ + {A39X_CUSTOMER_BOARD_ID0, -1 }, \ + {A39X_CUSTOMER_BOARD_ID0, -1 }, \ +}; +#endif /* CONFIG_ARMADA_38X */ + +#else + +#ifdef CONFIG_ARMADA_38X +#define MV_BOARD_WAKEUP_GPIO_INFO { \ + {RD_NAS_68XX_ID, -2 }, \ + {DB_68XX_ID, -1 }, \ + {RD_AP_68XX_ID, -2 }, \ + {DB_AP_68XX_ID, -2 }, \ + {DB_GP_68XX_ID, -2 }, \ + {DB_BP_6821_ID, -2 }, \ + {DB_AMC_6820_ID, -2 }, \ +}; +#else +#define MV_BOARD_WAKEUP_GPIO_INFO { \ + {A39X_RD_69XX_ID, -1 }, \ + {A39X_DB_69XX_ID, -1 }, \ +}; +#endif /* CONFIG_ARMADA_38X */ +#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */ + +u32 mv_board_tclk_get(void); +u32 mv_board_id_get(void); +u32 mv_board_id_index_get(u32 board_id); +u32 sys_env_unit_max_num_get(enum unit_id unit); +enum suspend_wakeup_status sys_env_suspend_wakeup_check(void); +u8 sys_env_device_rev_get(void); +u32 sys_env_device_id_get(void); +u16 sys_env_model_get(void); +struct dlb_config *sys_env_dlb_config_ptr_get(void); +u32 sys_env_get_topology_update_info( + struct topology_update_info *topology_update_info); +u32 sys_env_get_cs_ena_from_reg(void); + +#endif /* _SYS_ENV_LIB_H */ -- cgit v0.10.2 From ff9112df8b643ad989e8673452c75e073f3c9ff3 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 25 Mar 2015 12:51:18 +0100 Subject: arm: mvebu: drivers/ddr: Move Armada XP DDR init code into new directory With the upcoming addition of the Armada 38x DDR support, which is not compatible to the Armada XP DDR init code, we need to introduce a new directory infrastructure. To support multiple Marvell DDR controller. This will be the new structure: drivers/ddr/marvell/axp Supporting Armada XP (AXP) devices (and perhaps Armada 370) drivers/ddr/marvell/a38x Supporting Armada 38x devices (and perhaps Armada 39x) Signed-off-by: Stefan Roese diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h index 4bdb633..8bcdef6 100644 --- a/arch/arm/mach-mvebu/include/mach/cpu.h +++ b/arch/arm/mach-mvebu/include/mach/cpu.h @@ -125,7 +125,7 @@ int serdes_phy_config(void); /* * DDR3 init / training code ported from Marvell bin_hdr. Now * available in mainline U-Boot in: - * drivers/ddr/mvebu/ + * drivers/ddr/marvell */ int ddr3_init(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h index e5aa1b0..e10574e 100644 --- a/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h +++ b/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h @@ -7,7 +7,7 @@ #ifndef __HIGHSPEED_ENV_SPEC_H #define __HIGHSPEED_ENV_SPEC_H -#include "../../../drivers/ddr/mvebu/ddr3_hw_training.h" +#include "../../../drivers/ddr/marvell/axp/ddr3_hw_training.h" typedef enum { SERDES_UNIT_UNCONNECTED = 0x0, diff --git a/drivers/ddr/marvell/axp/Makefile b/drivers/ddr/marvell/axp/Makefile new file mode 100644 index 0000000..50a69ea --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/ddr3_axp.h b/drivers/ddr/marvell/axp/ddr3_axp.h new file mode 100644 index 0000000..d9e33f7 --- /dev/null +++ b/drivers/ddr/marvell/axp/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 CONFIG_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/marvell/axp/ddr3_axp_config.h b/drivers/ddr/marvell/axp/ddr3_axp_config.h new file mode 100644 index 0000000..800d2d1 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/ddr3_axp_mc_static.h b/drivers/ddr/marvell/axp/ddr3_axp_mc_static.h new file mode 100644 index 0000000..2c0e9075 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/ddr3_axp_training_static.h b/drivers/ddr/marvell/axp/ddr3_axp_training_static.h new file mode 100644 index 0000000..4e61547 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/ddr3_axp_vars.h b/drivers/ddr/marvell/axp/ddr3_axp_vars.h new file mode 100644 index 0000000..1b0ab56 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/ddr3_dfs.c b/drivers/ddr/marvell/axp/ddr3_dfs.c new file mode 100644 index 0000000..9347773 --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_dfs.c @@ -0,0 +1,1552 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/ddr3_dqs.c b/drivers/ddr/marvell/axp/ddr3_dqs.c new file mode 100644 index 0000000..71a986d --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_dqs.c @@ -0,0 +1,1374 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/ddr3_hw_training.c b/drivers/ddr/marvell/axp/ddr3_hw_training.c new file mode 100644 index 0000000..a8c5e6a --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_hw_training.c @@ -0,0 +1,1115 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/ddr3_hw_training.h b/drivers/ddr/marvell/axp/ddr3_hw_training.h new file mode 100644 index 0000000..cffa7c4 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/ddr3_init.c b/drivers/ddr/marvell/axp/ddr3_init.c new file mode 100644 index 0000000..11b8591 --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_init.c @@ -0,0 +1,1219 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/ddr3_init.h b/drivers/ddr/marvell/axp/ddr3_init.h new file mode 100644 index 0000000..b259e09 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/ddr3_patterns_64bit.h b/drivers/ddr/marvell/axp/ddr3_patterns_64bit.h new file mode 100644 index 0000000..1b57328 --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_patterns_64bit.h @@ -0,0 +1,924 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __DDR3_PATTERNS_64_H +#define __DDR3_PATTERNS_64_H + +/* + * Patterns Declerations + */ + +u32 wl_sup_pattern[LEN_WL_SUP_PATTERN] __aligned(32) = { + 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, + 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d, + 0x24232221, 0x28272625, 0x2c2b2a29, 0x302f2e2d, + 0x34333231, 0x38373635, 0x3c3b3a39, 0x403f3e3d, + 0x44434241, 0x48474645, 0x4c4b4a49, 0x504f4e4d, + 0x54535251, 0x58575655, 0x5c5b5a59, 0x605f5e5d, + 0x64636261, 0x68676665, 0x6c6b6a69, 0x706f6e6d, + 0x74737271, 0x78777675, 0x7c7b7a79, 0x807f7e7d +}; + +u32 pbs_pattern_32b[2][LEN_PBS_PATTERN] __aligned(32) = { + { + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555 + }, + { + 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, + 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, + 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, + 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA + } +}; + +u32 pbs_pattern_64b[2][LEN_PBS_PATTERN] __aligned(32) = { + { + 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, + 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, + 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, + 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555 + }, + { + 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, + 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, + 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, + 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA + } +}; + +u32 rl_pattern[LEN_STD_PATTERN] __aligned(32) = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x01010101, 0x01010101, 0x01010101, 0x01010101 +}; + +u32 killer_pattern_32b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = { + { + 0x01010101, 0x00000000, 0x01010101, 0xFFFFFFFF, + 0x01010101, 0x00000000, 0x01010101, 0xFFFFFFFF, + 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, + 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, + 0x01010101, 0xFEFEFEFE, 0x01010101, 0x01010101, + 0x01010101, 0xFEFEFEFE, 0x01010101, 0x01010101, + 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, 0x00000000, + 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x01010101, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x01010101, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0xFEFEFEFE, + 0x00000000, 0x00000000, 0x00000000, 0xFEFEFEFE, + 0xFEFEFEFE, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFEFEFEFE, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFEFEFEFE, 0x00000000, 0xFEFEFEFE, 0x00000000, + 0xFEFEFEFE, 0x00000000, 0xFEFEFEFE, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, + 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x00000000, + 0x01010101, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE, + 0x01010101, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE + }, + { + 0x02020202, 0x00000000, 0x02020202, 0xFFFFFFFF, + 0x02020202, 0x00000000, 0x02020202, 0xFFFFFFFF, + 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, + 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, + 0x02020202, 0xFDFDFDFD, 0x02020202, 0x02020202, + 0x02020202, 0xFDFDFDFD, 0x02020202, 0x02020202, + 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, 0x00000000, + 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x02020202, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x02020202, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0xFDFDFDFD, + 0x00000000, 0x00000000, 0x00000000, 0xFDFDFDFD, + 0xFDFDFDFD, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFDFDFDFD, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFDFDFDFD, 0x00000000, 0xFDFDFDFD, 0x00000000, + 0xFDFDFDFD, 0x00000000, 0xFDFDFDFD, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, + 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x00000000, + 0x02020202, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD, + 0x02020202, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD + }, + { + 0x04040404, 0x00000000, 0x04040404, 0xFFFFFFFF, + 0x04040404, 0x00000000, 0x04040404, 0xFFFFFFFF, + 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, + 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, + 0x04040404, 0xFBFBFBFB, 0x04040404, 0x04040404, + 0x04040404, 0xFBFBFBFB, 0x04040404, 0x04040404, + 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, 0x00000000, + 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x04040404, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x04040404, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0xFBFBFBFB, + 0x00000000, 0x00000000, 0x00000000, 0xFBFBFBFB, + 0xFBFBFBFB, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFBFBFBFB, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFBFBFBFB, 0x00000000, 0xFBFBFBFB, 0x00000000, + 0xFBFBFBFB, 0x00000000, 0xFBFBFBFB, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, + 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x00000000, + 0x04040404, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB, + 0x04040404, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB + }, + { + 0x08080808, 0x00000000, 0x08080808, 0xFFFFFFFF, + 0x08080808, 0x00000000, 0x08080808, 0xFFFFFFFF, + 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, + 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, + 0x08080808, 0xF7F7F7F7, 0x08080808, 0x08080808, + 0x08080808, 0xF7F7F7F7, 0x08080808, 0x08080808, + 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, 0x00000000, + 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x08080808, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x08080808, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0xF7F7F7F7, + 0x00000000, 0x00000000, 0x00000000, 0xF7F7F7F7, + 0xF7F7F7F7, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xF7F7F7F7, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xF7F7F7F7, 0x00000000, 0xF7F7F7F7, 0x00000000, + 0xF7F7F7F7, 0x00000000, 0xF7F7F7F7, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, + 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x00000000, + 0x08080808, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7, + 0x08080808, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7 + }, + { + 0x10101010, 0x00000000, 0x10101010, 0xFFFFFFFF, + 0x10101010, 0x00000000, 0x10101010, 0xFFFFFFFF, + 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, + 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, + 0x10101010, 0xEFEFEFEF, 0x10101010, 0x10101010, + 0x10101010, 0xEFEFEFEF, 0x10101010, 0x10101010, + 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, 0x00000000, + 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x10101010, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x10101010, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0xEFEFEFEF, + 0x00000000, 0x00000000, 0x00000000, 0xEFEFEFEF, + 0xEFEFEFEF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xEFEFEFEF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xEFEFEFEF, 0x00000000, 0xEFEFEFEF, 0x00000000, + 0xEFEFEFEF, 0x00000000, 0xEFEFEFEF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, + 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x00000000, + 0x10101010, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF, + 0x10101010, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF + }, + { + 0x20202020, 0x00000000, 0x20202020, 0xFFFFFFFF, + 0x20202020, 0x00000000, 0x20202020, 0xFFFFFFFF, + 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, + 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, + 0x20202020, 0xDFDFDFDF, 0x20202020, 0x20202020, + 0x20202020, 0xDFDFDFDF, 0x20202020, 0x20202020, + 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, 0x00000000, + 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x20202020, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x20202020, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0xDFDFDFDF, + 0x00000000, 0x00000000, 0x00000000, 0xDFDFDFDF, + 0xDFDFDFDF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xDFDFDFDF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xDFDFDFDF, 0x00000000, 0xDFDFDFDF, 0x00000000, + 0xDFDFDFDF, 0x00000000, 0xDFDFDFDF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, + 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x00000000, + 0x20202020, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF, + 0x20202020, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF + }, + { + 0x40404040, 0x00000000, 0x40404040, 0xFFFFFFFF, + 0x40404040, 0x00000000, 0x40404040, 0xFFFFFFFF, + 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, + 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, + 0x40404040, 0xBFBFBFBF, 0x40404040, 0x40404040, + 0x40404040, 0xBFBFBFBF, 0x40404040, 0x40404040, + 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, 0x00000000, + 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x40404040, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x40404040, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0xBFBFBFBF, + 0x00000000, 0x00000000, 0x00000000, 0xBFBFBFBF, + 0xBFBFBFBF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xBFBFBFBF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xBFBFBFBF, 0x00000000, 0xBFBFBFBF, 0x00000000, + 0xBFBFBFBF, 0x00000000, 0xBFBFBFBF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, + 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x00000000, + 0x40404040, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF, + 0x40404040, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF + }, + { + 0x80808080, 0x00000000, 0x80808080, 0xFFFFFFFF, + 0x80808080, 0x00000000, 0x80808080, 0xFFFFFFFF, + 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, + 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, + 0x80808080, 0x7F7F7F7F, 0x80808080, 0x80808080, + 0x80808080, 0x7F7F7F7F, 0x80808080, 0x80808080, + 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, 0x00000000, + 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x80808080, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x80808080, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x7F7F7F7F, + 0x00000000, 0x00000000, 0x00000000, 0x7F7F7F7F, + 0x7F7F7F7F, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x7F7F7F7F, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0x7F7F7F7F, 0x00000000, 0x7F7F7F7F, 0x00000000, + 0x7F7F7F7F, 0x00000000, 0x7F7F7F7F, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, + 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x00000000, + 0x80808080, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F, + 0x80808080, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F + } +}; + +u32 killer_pattern_64b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = { + { + 0x01010101, 0x01010101, 0x00000000, 0x00000000, + 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, + 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE, + 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE, + 0x01010101, 0x01010101, 0x01010101, 0x01010101, + 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101, + 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFEFEFEFE, 0xFEFEFEFE, + 0xFEFEFEFE, 0xFEFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000, + 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x01010101, 0x01010101, 0x00000000, 0x00000000, + 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE + }, + { + 0x02020202, 0x02020202, 0x00000000, 0x00000000, + 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, + 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD, + 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD, + 0x02020202, 0x02020202, 0x02020202, 0x02020202, + 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202, + 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFDFDFDFD, 0xFDFDFDFD, + 0xFDFDFDFD, 0xFDFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000, + 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x02020202, 0x02020202, 0x00000000, 0x00000000, + 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD + }, + { + 0x04040404, 0x04040404, 0x00000000, 0x00000000, + 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, + 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB, + 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB, + 0x04040404, 0x04040404, 0x04040404, 0x04040404, + 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404, + 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFBFBFBFB, 0xFBFBFBFB, + 0xFBFBFBFB, 0xFBFBFBFB, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000, + 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x04040404, 0x04040404, 0x00000000, 0x00000000, + 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB + }, + { + 0x08080808, 0x08080808, 0x00000000, 0x00000000, + 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF, + 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, + 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7, + 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7, + 0x08080808, 0x08080808, 0x08080808, 0x08080808, + 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808, + 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xF7F7F7F7, 0xF7F7F7F7, + 0xF7F7F7F7, 0xF7F7F7F7, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000, + 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x08080808, 0x08080808, 0x00000000, 0x00000000, + 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF, + 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7 + }, + { + 0x10101010, 0x10101010, 0x00000000, 0x00000000, + 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF, + 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, + 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF, + 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010, + 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xEFEFEFEF, 0xEFEFEFEF, + 0xEFEFEFEF, 0xEFEFEFEF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000, + 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x10101010, 0x10101010, 0x00000000, 0x00000000, + 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF, + 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF + }, + { + 0x20202020, 0x20202020, 0x00000000, 0x00000000, + 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF, + 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, + 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF, + 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF, + 0x20202020, 0x20202020, 0x20202020, 0x20202020, + 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020, + 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xDFDFDFDF, 0xDFDFDFDF, + 0xDFDFDFDF, 0xDFDFDFDF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000, + 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x20202020, 0x20202020, 0x00000000, 0x00000000, + 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF, + 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF + }, + { + 0x40404040, 0x40404040, 0x00000000, 0x00000000, + 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF, + 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, + 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF, + 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF, + 0x40404040, 0x40404040, 0x40404040, 0x40404040, + 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040, + 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xBFBFBFBF, 0xBFBFBFBF, + 0xBFBFBFBF, 0xBFBFBFBF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000, + 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x40404040, 0x40404040, 0x00000000, 0x00000000, + 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF, + 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF + }, + { + 0x80808080, 0x80808080, 0x00000000, 0x00000000, + 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF, + 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, + 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F, + 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F, + 0x80808080, 0x80808080, 0x80808080, 0x80808080, + 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080, + 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x7F7F7F7F, 0x7F7F7F7F, + 0x7F7F7F7F, 0x7F7F7F7F, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000, + 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x80808080, 0x80808080, 0x00000000, 0x00000000, + 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF, + 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F + } +}; + +u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN] __aligned(32) = { + { + 0x00000000, 0x00000000, 0x01010101, 0x01010101, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE, + 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101, + 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101, + 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101, + 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE, + 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x01010101, 0x01010101, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE, + 0x00000000, 0x00000000, 0xFEFEFEFE, 0xFEFEFEFE, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101, + 0x00000000, 0x00000000, 0x01010101, 0x01010101, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE, + 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x02020202, 0x02020202, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD, + 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202, + 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202, + 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202, + 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD, + 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x02020202, 0x02020202, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD, + 0x00000000, 0x00000000, 0xFDFDFDFD, 0xFDFDFDFD, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202, + 0x00000000, 0x00000000, 0x02020202, 0x02020202, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD, + 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x04040404, 0x04040404, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB, + 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404, + 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404, + 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404, + 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB, + 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x04040404, 0x04040404, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB, + 0x00000000, 0x00000000, 0xFBFBFBFB, 0xFBFBFBFB, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404, + 0x00000000, 0x00000000, 0x04040404, 0x04040404, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB, + 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x08080808, 0x08080808, + 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7, + 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808, + 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808, + 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808, + 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7, + 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x08080808, 0x08080808, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7, + 0x00000000, 0x00000000, 0xF7F7F7F7, 0xF7F7F7F7, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808, + 0x00000000, 0x00000000, 0x08080808, 0x08080808, + 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7, + 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x10101010, 0x10101010, + 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF, + 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010, + 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010, + 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF, + 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x10101010, 0x10101010, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF, + 0x00000000, 0x00000000, 0xEFEFEFEF, 0xEFEFEFEF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010, + 0x00000000, 0x00000000, 0x10101010, 0x10101010, + 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF, + 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x20202020, 0x20202020, + 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF, + 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020, + 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020, + 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020, + 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF, + 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x20202020, 0x20202020, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF, + 0x00000000, 0x00000000, 0xDFDFDFDF, 0xDFDFDFDF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020, + 0x00000000, 0x00000000, 0x20202020, 0x20202020, + 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF, + 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x40404040, 0x40404040, + 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF, + 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040, + 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040, + 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040, + 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF, + 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x40404040, 0x40404040, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF, + 0x00000000, 0x00000000, 0xBFBFBFBF, 0xBFBFBFBF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040, + 0x00000000, 0x00000000, 0x40404040, 0x40404040, + 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF, + 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x80808080, 0x80808080, + 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F, + 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080, + 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080, + 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080, + 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F, + 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x80808080, 0x80808080, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F, + 0x00000000, 0x00000000, 0x7F7F7F7F, 0x7F7F7F7F, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080, + 0x00000000, 0x00000000, 0x80808080, 0x80808080, + 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F, + 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000 + } +}; + +/* Fabric ratios table */ +u32 fabric_ratio[FAB_OPT] = { + 0x04010204, + 0x04020202, + 0x08020306, + 0x08020303, + 0x04020303, + 0x04020204, + 0x04010202, + 0x08030606, + 0x08030505, + 0x04020306, + 0x0804050A, + 0x04030606, + 0x04020404, + 0x04030306, + 0x04020505, + 0x08020505, + 0x04010303, + 0x08050A0A, + 0x04030408, + 0x04010102, + 0x08030306 +}; + +u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM] = { + {3, 2, 5, 7, 1, 0, 6, 4}, + {2, 3, 6, 7, 1, 0, 4, 5}, + {1, 3, 5, 6, 0, 2, 4, 7}, + {0, 2, 4, 7, 1, 3, 5, 6}, + {3, 0, 4, 6, 1, 2, 5, 7}, + {0, 3, 5, 7, 1, 2, 4, 6}, + {2, 3, 5, 7, 1, 0, 4, 6}, + {0, 2, 5, 4, 1, 3, 6, 7}, + {2, 3, 4, 7, 0, 1, 5, 6} +}; + +#endif /* __DDR3_PATTERNS_64_H */ diff --git a/drivers/ddr/marvell/axp/ddr3_pbs.c b/drivers/ddr/marvell/axp/ddr3_pbs.c new file mode 100644 index 0000000..00ea3fd --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_pbs.c @@ -0,0 +1,1592 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/ddr3_read_leveling.c b/drivers/ddr/marvell/axp/ddr3_read_leveling.c new file mode 100644 index 0000000..4662bde --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_read_leveling.c @@ -0,0 +1,1214 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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 statesnum_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 statesnum_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/marvell/axp/ddr3_sdram.c b/drivers/ddr/marvell/axp/ddr3_sdram.c new file mode 100644 index 0000000..50c1bf8 --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_sdram.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/ddr3_spd.c b/drivers/ddr/marvell/axp/ddr3_spd.c new file mode 100644 index 0000000..f4f94c5 --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_spd.c @@ -0,0 +1,1300 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/ddr3_write_leveling.c b/drivers/ddr/marvell/axp/ddr3_write_leveling.c new file mode 100644 index 0000000..df3a3df --- /dev/null +++ b/drivers/ddr/marvell/axp/ddr3_write_leveling.c @@ -0,0 +1,1366 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/xor.c b/drivers/ddr/marvell/axp/xor.c new file mode 100644 index 0000000..66c96ae --- /dev/null +++ b/drivers/ddr/marvell/axp/xor.c @@ -0,0 +1,436 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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/marvell/axp/xor.h b/drivers/ddr/marvell/axp/xor.h new file mode 100644 index 0000000..3536487 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/marvell/axp/xor_regs.h b/drivers/ddr/marvell/axp/xor_regs.h new file mode 100644 index 0000000..884aa15 --- /dev/null +++ b/drivers/ddr/marvell/axp/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/drivers/ddr/mvebu/Makefile b/drivers/ddr/mvebu/Makefile deleted file mode 100644 index 50a69ea..0000000 --- a/drivers/ddr/mvebu/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# 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 deleted file mode 100644 index d9e33f7..0000000 --- a/drivers/ddr/mvebu/ddr3_axp.h +++ /dev/null @@ -1,510 +0,0 @@ -/* - * 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 CONFIG_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 deleted file mode 100644 index 800d2d1..0000000 --- a/drivers/ddr/mvebu/ddr3_axp_config.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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 deleted file mode 100644 index 2c0e9075..0000000 --- a/drivers/ddr/mvebu/ddr3_axp_mc_static.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * 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 deleted file mode 100644 index 4e61547..0000000 --- a/drivers/ddr/mvebu/ddr3_axp_training_static.h +++ /dev/null @@ -1,770 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1b0ab56..0000000 --- a/drivers/ddr/mvebu/ddr3_axp_vars.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9347773..0000000 --- a/drivers/ddr/mvebu/ddr3_dfs.c +++ /dev/null @@ -1,1552 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index 71a986d..0000000 --- a/drivers/ddr/mvebu/ddr3_dqs.c +++ /dev/null @@ -1,1374 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index a8c5e6a..0000000 --- a/drivers/ddr/mvebu/ddr3_hw_training.c +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index cffa7c4..0000000 --- a/drivers/ddr/mvebu/ddr3_hw_training.h +++ /dev/null @@ -1,392 +0,0 @@ -/* - * 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 deleted file mode 100644 index 11b8591..0000000 --- a/drivers/ddr/mvebu/ddr3_init.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index b259e09..0000000 --- a/drivers/ddr/mvebu/ddr3_init.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1b57328..0000000 --- a/drivers/ddr/mvebu/ddr3_patterns_64bit.h +++ /dev/null @@ -1,924 +0,0 @@ -/* - * 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 deleted file mode 100644 index 00ea3fd..0000000 --- a/drivers/ddr/mvebu/ddr3_pbs.c +++ /dev/null @@ -1,1592 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index 4662bde..0000000 --- a/drivers/ddr/mvebu/ddr3_read_leveling.c +++ /dev/null @@ -1,1214 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 statesnum_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 statesnum_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 deleted file mode 100644 index 50c1bf8..0000000 --- a/drivers/ddr/mvebu/ddr3_sdram.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index f4f94c5..0000000 --- a/drivers/ddr/mvebu/ddr3_spd.c +++ /dev/null @@ -1,1300 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index df3a3df..0000000 --- a/drivers/ddr/mvebu/ddr3_write_leveling.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index 66c96ae..0000000 --- a/drivers/ddr/mvebu/xor.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index 3536487..0000000 --- a/drivers/ddr/mvebu/xor.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 deleted file mode 100644 index 884aa15..0000000 --- a/drivers/ddr/mvebu/xor_regs.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 aeddbf9..41e6fdc 100644 --- a/include/configs/db-mv784mp-gp.h +++ b/include/configs/db-mv784mp-gp.h @@ -138,7 +138,7 @@ #define CONFIG_SYS_SPI_U_BOOT_OFFS 0x20000 /* Enable DDR support in SPL (DDR3 training from Marvell bin_hdr) */ -#define CONFIG_SYS_MVEBU_DDR +#define CONFIG_SYS_MVEBU_DDR_AXP #define CONFIG_SPD_EEPROM 0x4e #endif /* _CONFIG_DB_MV7846MP_GP_H */ diff --git a/include/configs/maxbcm.h b/include/configs/maxbcm.h index 4826044..0fb117f 100644 --- a/include/configs/maxbcm.h +++ b/include/configs/maxbcm.h @@ -108,7 +108,7 @@ #define CONFIG_SYS_SPI_U_BOOT_OFFS 0x20000 /* Enable DDR support in SPL (DDR3 training from Marvell bin_hdr) */ -#define CONFIG_SYS_MVEBU_DDR +#define CONFIG_SYS_MVEBU_DDR_AXP #define CONFIG_DDR_FIXED_SIZE (1 << 20) /* 1GiB */ #endif /* _CONFIG_DB_MV7846MP_GP_H */ diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index fd572f4..3c9a9a0 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -59,7 +59,7 @@ libs-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/ libs-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/ libs-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/ libs-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += drivers/ddr/fsl/ -libs-$(CONFIG_SYS_MVEBU_DDR) += drivers/ddr/mvebu/ +libs-$(CONFIG_SYS_MVEBU_DDR_AXP) += drivers/ddr/marvell/axp/ libs-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/ libs-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/ libs-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/ -- cgit v0.10.2 From f1df9364459425abba75488a148ddd98fabf40d7 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 26 Mar 2015 15:36:56 +0100 Subject: arm: mvebu: Add Armada 38x DDR3 training code from Marvell bin_hdr This patch adds the DDR3 setup and training code taken from the Marvell U-Boot repository. This code used to be included as a binary (bin_hdr) into the Armada A38x boot image. Not linked with the main U-Boot. With this code addition and the serdes/PHY setup code, the Armada A38x support in mainline U-Boot is finally self-contained. So the complete image for booting can be built from mainline U-Boot. Without any additional external inclusion. Note: This code has undergone many hours (days!) of coding-style cleanup and refactoring. It still is not checkpatch clean though, I'm afraid. As the factoring of the code has so many levels of indentation that many lines are longer than 80 chars. Signed-off-by: Stefan Roese diff --git a/drivers/ddr/marvell/a38x/Makefile b/drivers/ddr/marvell/a38x/Makefile new file mode 100644 index 0000000..bf6ea49 --- /dev/null +++ b/drivers/ddr/marvell/a38x/Makefile @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_SPL_BUILD) += ddr3_a38x.o +obj-$(CONFIG_SPL_BUILD) += ddr3_a38x_training.o +obj-$(CONFIG_SPL_BUILD) += ddr3_debug.o +obj-$(CONFIG_SPL_BUILD) += ddr3_hws_hw_training.o +obj-$(CONFIG_SPL_BUILD) += ddr3_init.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_bist.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_centralization.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_db.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_hw_algo.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_ip_engine.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_leveling.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_pbs.o +obj-$(CONFIG_SPL_BUILD) += ddr3_training_static.o +obj-$(CONFIG_SPL_BUILD) += xor.o diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x.c b/drivers/ddr/marvell/a38x/ddr3_a38x.c new file mode 100644 index 0000000..f469907 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_a38x.c @@ -0,0 +1,741 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define A38X_NUMBER_OF_INTERFACES 5 + +#define SAR_DEV_ID_OFFS 27 +#define SAR_DEV_ID_MASK 0x7 + +/* Termal Sensor Registers */ +#define TSEN_STATE_REG 0xe4070 +#define TSEN_STATE_OFFSET 31 +#define TSEN_STATE_MASK (0x1 << TSEN_STATE_OFFSET) +#define TSEN_CONF_REG 0xe4074 +#define TSEN_CONF_RST_OFFSET 8 +#define TSEN_CONF_RST_MASK (0x1 << TSEN_CONF_RST_OFFSET) +#define TSEN_STATUS_REG 0xe4078 +#define TSEN_STATUS_READOUT_VALID_OFFSET 10 +#define TSEN_STATUS_READOUT_VALID_MASK (0x1 << \ + TSEN_STATUS_READOUT_VALID_OFFSET) +#define TSEN_STATUS_TEMP_OUT_OFFSET 0 +#define TSEN_STATUS_TEMP_OUT_MASK (0x3ff << TSEN_STATUS_TEMP_OUT_OFFSET) + +static struct dfx_access interface_map[] = { + /* Pipe Client */ + { 0, 17 }, + { 1, 7 }, + { 1, 11 }, + { 0, 3 }, + { 1, 25 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 } +}; + +/* This array hold the board round trip delay (DQ and CK) per */ +struct trip_delay_element a38x_board_round_trip_delay_array[] = { + /* 1st board */ + /* Interface bus DQS-delay CK-delay */ + { 3952, 5060 }, + { 3192, 4493 }, + { 4785, 6677 }, + { 3413, 7267 }, + { 4282, 6086 }, /* ECC PUP */ + { 3952, 5134 }, + { 3192, 4567 }, + { 4785, 6751 }, + { 3413, 7341 }, + { 4282, 6160 }, /* ECC PUP */ + + /* 2nd board */ + /* Interface bus DQS-delay CK-delay */ + { 3952, 5060 }, + { 3192, 4493 }, + { 4785, 6677 }, + { 3413, 7267 }, + { 4282, 6086 }, /* ECC PUP */ + { 3952, 5134 }, + { 3192, 4567 }, + { 4785, 6751 }, + { 3413, 7341 }, + { 4282, 6160 } /* ECC PUP */ +}; + +#ifdef STATIC_ALGO_SUPPORT +/* package trace */ +static struct trip_delay_element a38x_package_round_trip_delay_array[] = { + /* IF BUS DQ_DELAY CK_DELAY */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 } +}; + +static int a38x_silicon_delay_offset[] = { + /* board 0 */ + 0, + /* board 1 */ + 0, + /* board 2 */ + 0 +}; +#endif + +static u8 a38x_bw_per_freq[DDR_FREQ_LIMIT] = { + 0x3, /* DDR_FREQ_100 */ + 0x4, /* DDR_FREQ_400 */ + 0x4, /* DDR_FREQ_533 */ + 0x5, /* DDR_FREQ_667 */ + 0x5, /* DDR_FREQ_800 */ + 0x5, /* DDR_FREQ_933 */ + 0x5, /* DDR_FREQ_1066 */ + 0x3, /* DDR_FREQ_311 */ + 0x3, /* DDR_FREQ_333 */ + 0x4, /* DDR_FREQ_467 */ + 0x5, /* DDR_FREQ_850 */ + 0x5, /* DDR_FREQ_600 */ + 0x3, /* DDR_FREQ_300 */ + 0x5, /* DDR_FREQ_900 */ + 0x3, /* DDR_FREQ_360 */ + 0x5 /* DDR_FREQ_1000 */ +}; + +static u8 a38x_rate_per_freq[DDR_FREQ_LIMIT] = { + /*TBD*/ 0x1, /* DDR_FREQ_100 */ + 0x2, /* DDR_FREQ_400 */ + 0x2, /* DDR_FREQ_533 */ + 0x2, /* DDR_FREQ_667 */ + 0x2, /* DDR_FREQ_800 */ + 0x3, /* DDR_FREQ_933 */ + 0x3, /* DDR_FREQ_1066 */ + 0x1, /* DDR_FREQ_311 */ + 0x1, /* DDR_FREQ_333 */ + 0x2, /* DDR_FREQ_467 */ + 0x2, /* DDR_FREQ_850 */ + 0x2, /* DDR_FREQ_600 */ + 0x1, /* DDR_FREQ_300 */ + 0x2, /* DDR_FREQ_900 */ + 0x1, /* DDR_FREQ_360 */ + 0x2 /* DDR_FREQ_1000 */ +}; + +static u16 a38x_vco_freq_per_sar[] = { + 666, /* 0 */ + 1332, + 800, + 1600, + 1066, + 2132, + 1200, + 2400, + 1332, + 1332, + 1500, + 1500, + 1600, /* 12 */ + 1600, + 1700, + 1700, + 1866, + 1866, + 1800, /* 18 */ + 2000, + 2000, + 4000, + 2132, + 2132, + 2300, + 2300, + 2400, + 2400, + 2500, + 2500, + 800 +}; + +u32 pipe_multicast_mask; + +u32 dq_bit_map_2_phy_pin[] = { + 1, 0, 2, 6, 9, 8, 3, 7, /* 0 */ + 8, 9, 1, 7, 2, 6, 3, 0, /* 1 */ + 3, 9, 7, 8, 1, 0, 2, 6, /* 2 */ + 1, 0, 6, 2, 8, 3, 7, 9, /* 3 */ + 0, 1, 2, 9, 7, 8, 3, 6, /* 4 */ +}; + +static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, + enum hws_ddr_freq freq); + +/* + * Read temperature TJ value + */ +u32 ddr3_ctrl_get_junc_temp(u8 dev_num) +{ + int reg = 0; + + /* Initiates TSEN hardware reset once */ + if ((reg_read(TSEN_CONF_REG) & TSEN_CONF_RST_MASK) == 0) + reg_bit_set(TSEN_CONF_REG, TSEN_CONF_RST_MASK); + mdelay(10); + + /* Check if the readout field is valid */ + if ((reg_read(TSEN_STATUS_REG) & TSEN_STATUS_READOUT_VALID_MASK) == 0) { + printf("%s: TSEN not ready\n", __func__); + return 0; + } + + reg = reg_read(TSEN_STATUS_REG); + reg = (reg & TSEN_STATUS_TEMP_OUT_MASK) >> TSEN_STATUS_TEMP_OUT_OFFSET; + + return ((((10000 * reg) / 21445) * 1000) - 272674) / 1000; +} + +/* + * Name: ddr3_tip_a38x_get_freq_config. + * Desc: + * Args: + * Notes: + * Returns: MV_OK if success, other error code if fail. + */ +int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum hws_ddr_freq freq, + struct hws_tip_freq_config_info + *freq_config_info) +{ + if (a38x_bw_per_freq[freq] == 0xff) + return MV_NOT_SUPPORTED; + + if (freq_config_info == NULL) + return MV_BAD_PARAM; + + freq_config_info->bw_per_freq = a38x_bw_per_freq[freq]; + freq_config_info->rate_per_freq = a38x_rate_per_freq[freq]; + freq_config_info->is_supported = 1; + + return MV_OK; +} + +/* + * Name: ddr3_tip_a38x_pipe_enable. + * Desc: + * Args: + * Notes: + * Returns: MV_OK if success, other error code if fail. + */ +int ddr3_tip_a38x_pipe_enable(u8 dev_num, enum hws_access_type interface_access, + u32 if_id, int enable) +{ + u32 data_value, pipe_enable_mask = 0; + + if (enable == 0) { + pipe_enable_mask = 0; + } else { + if (interface_access == ACCESS_TYPE_MULTICAST) + pipe_enable_mask = pipe_multicast_mask; + else + pipe_enable_mask = (1 << interface_map[if_id].pipe); + } + + CHECK_STATUS(ddr3_tip_reg_read + (dev_num, PIPE_ENABLE_ADDR, &data_value, MASK_ALL_BITS)); + data_value = (data_value & (~0xff)) | pipe_enable_mask; + CHECK_STATUS(ddr3_tip_reg_write(dev_num, PIPE_ENABLE_ADDR, data_value)); + + return MV_OK; +} + +/* + * Name: ddr3_tip_a38x_if_write. + * Desc: + * Args: + * Notes: + * Returns: MV_OK if success, other error code if fail. + */ +int ddr3_tip_a38x_if_write(u8 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 data_value, + u32 mask) +{ + u32 ui_data_read; + + if (mask != MASK_ALL_BITS) { + CHECK_STATUS(ddr3_tip_a38x_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, reg_addr, + &ui_data_read, MASK_ALL_BITS)); + data_value = (ui_data_read & (~mask)) | (data_value & mask); + } + + reg_write(reg_addr, data_value); + + return MV_OK; +} + +/* + * Name: ddr3_tip_a38x_if_read. + * Desc: + * Args: + * Notes: + * Returns: MV_OK if success, other error code if fail. + */ +int ddr3_tip_a38x_if_read(u8 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 *data, u32 mask) +{ + *data = reg_read(reg_addr) & mask; + + return MV_OK; +} + +/* + * Name: ddr3_tip_a38x_select_ddr_controller. + * Desc: Enable/Disable access to Marvell's server. + * Args: dev_num - device number + * enable - whether to enable or disable the server + * Notes: + * Returns: MV_OK if success, other error code if fail. + */ +int ddr3_tip_a38x_select_ddr_controller(u8 dev_num, int enable) +{ + u32 reg; + + reg = reg_read(CS_ENABLE_REG); + + if (enable) + reg |= (1 << 6); + else + reg &= ~(1 << 6); + + reg_write(CS_ENABLE_REG, reg); + + return MV_OK; +} + +/* + * Name: ddr3_tip_init_a38x_silicon. + * Desc: init Training SW DB. + * Args: + * Notes: + * Returns: MV_OK if success, other error code if fail. + */ +static int ddr3_tip_init_a38x_silicon(u32 dev_num, u32 board_id) +{ + struct hws_tip_config_func_db config_func; + enum hws_ddr_freq ddr_freq; + int status; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* new read leveling version */ + config_func.tip_dunit_read_func = ddr3_tip_a38x_if_read; + config_func.tip_dunit_write_func = ddr3_tip_a38x_if_write; + config_func.tip_dunit_mux_select_func = + ddr3_tip_a38x_select_ddr_controller; + config_func.tip_get_freq_config_info_func = + ddr3_tip_a38x_get_freq_config; + config_func.tip_set_freq_divider_func = ddr3_tip_a38x_set_divider; + config_func.tip_get_device_info_func = ddr3_tip_a38x_get_device_info; + config_func.tip_get_temperature = ddr3_ctrl_get_junc_temp; + + ddr3_tip_init_config_func(dev_num, &config_func); + + ddr3_tip_register_dq_table(dev_num, dq_bit_map_2_phy_pin); + +#ifdef STATIC_ALGO_SUPPORT + { + struct hws_tip_static_config_info static_config; + u32 board_offset = + board_id * A38X_NUMBER_OF_INTERFACES * + tm->num_of_bus_per_interface; + + static_config.silicon_delay = + a38x_silicon_delay_offset[board_id]; + static_config.package_trace_arr = + a38x_package_round_trip_delay_array; + static_config.board_trace_arr = + &a38x_board_round_trip_delay_array[board_offset]; + ddr3_tip_init_static_config_db(dev_num, &static_config); + } +#endif + status = ddr3_tip_a38x_get_init_freq(dev_num, &ddr_freq); + if (MV_OK != status) { + DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, + ("DDR3 silicon get target frequency - FAILED 0x%x\n", + status)); + return status; + } + + rl_version = 1; + mask_tune_func = (SET_LOW_FREQ_MASK_BIT | + LOAD_PATTERN_MASK_BIT | + SET_MEDIUM_FREQ_MASK_BIT | WRITE_LEVELING_MASK_BIT | + /* LOAD_PATTERN_2_MASK_BIT | */ + WRITE_LEVELING_SUPP_MASK_BIT | + READ_LEVELING_MASK_BIT | + PBS_RX_MASK_BIT | + PBS_TX_MASK_BIT | + SET_TARGET_FREQ_MASK_BIT | + WRITE_LEVELING_TF_MASK_BIT | + WRITE_LEVELING_SUPP_TF_MASK_BIT | + READ_LEVELING_TF_MASK_BIT | + CENTRALIZATION_RX_MASK_BIT | + CENTRALIZATION_TX_MASK_BIT); + rl_mid_freq_wa = 1; + + if ((ddr_freq == DDR_FREQ_333) || (ddr_freq == DDR_FREQ_400)) { + mask_tune_func = (WRITE_LEVELING_MASK_BIT | + LOAD_PATTERN_2_MASK_BIT | + WRITE_LEVELING_SUPP_MASK_BIT | + READ_LEVELING_MASK_BIT | + PBS_RX_MASK_BIT | + PBS_TX_MASK_BIT | + CENTRALIZATION_RX_MASK_BIT | + CENTRALIZATION_TX_MASK_BIT); + rl_mid_freq_wa = 0; /* WA not needed if 333/400 is TF */ + } + + /* Supplementary not supported for ECC modes */ + if (1 == ddr3_if_ecc_enabled()) { + mask_tune_func &= ~WRITE_LEVELING_SUPP_TF_MASK_BIT; + mask_tune_func &= ~WRITE_LEVELING_SUPP_MASK_BIT; + mask_tune_func &= ~PBS_TX_MASK_BIT; + mask_tune_func &= ~PBS_RX_MASK_BIT; + } + + if (ck_delay == -1) + ck_delay = 160; + if (ck_delay_16 == -1) + ck_delay_16 = 160; + ca_delay = 0; + delay_enable = 1; + + calibration_update_control = 1; + + init_freq = tm->interface_params[first_active_if].memory_freq; + + ddr3_tip_a38x_get_medium_freq(dev_num, &medium_freq); + + return MV_OK; +} + +int ddr3_a38x_update_topology_map(u32 dev_num, struct hws_topology_map *tm) +{ + u32 if_id = 0; + enum hws_ddr_freq freq; + + ddr3_tip_a38x_get_init_freq(dev_num, &freq); + tm->interface_params[if_id].memory_freq = freq; + + /* + * re-calc topology parameters according to topology updates + * (if needed) + */ + CHECK_STATUS(hws_ddr3_tip_load_topology_map(dev_num, tm)); + + return MV_OK; +} + +int ddr3_tip_init_a38x(u32 dev_num, u32 board_id) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (NULL == tm) + return MV_FAIL; + + ddr3_a38x_update_topology_map(dev_num, tm); + ddr3_tip_init_a38x_silicon(dev_num, board_id); + + return MV_OK; +} + +int ddr3_tip_a38x_get_init_freq(int dev_num, enum hws_ddr_freq *freq) +{ + u32 reg; + + /* Read sample at reset setting */ + reg = (reg_read(REG_DEVICE_SAR1_ADDR) >> + RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) & + RST2_CPU_DDR_CLOCK_SELECT_IN_MASK; + switch (reg) { + case 0x0: + case 0x1: + *freq = DDR_FREQ_333; + break; + case 0x2: + case 0x3: + *freq = DDR_FREQ_400; + break; + case 0x4: + case 0xd: + *freq = DDR_FREQ_533; + break; + case 0x6: + *freq = DDR_FREQ_600; + break; + case 0x8: + case 0x11: + case 0x14: + *freq = DDR_FREQ_667; + break; + case 0xc: + case 0x15: + case 0x1b: + *freq = DDR_FREQ_800; + break; + case 0x10: + *freq = DDR_FREQ_933; + break; + case 0x12: + *freq = DDR_FREQ_900; + break; + case 0x13: + *freq = DDR_FREQ_900; + break; + default: + *freq = 0; + return MV_NOT_SUPPORTED; + } + + return MV_OK; +} + +int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq) +{ + u32 reg; + + /* Read sample at reset setting */ + reg = (reg_read(REG_DEVICE_SAR1_ADDR) >> + RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) & + RST2_CPU_DDR_CLOCK_SELECT_IN_MASK; + switch (reg) { + case 0x0: + case 0x1: + /* Medium is same as TF to run PBS in this freq */ + *freq = DDR_FREQ_333; + break; + case 0x2: + case 0x3: + /* Medium is same as TF to run PBS in this freq */ + *freq = DDR_FREQ_400; + break; + case 0x4: + case 0xd: + *freq = DDR_FREQ_533; + break; + case 0x8: + case 0x11: + case 0x14: + *freq = DDR_FREQ_333; + break; + case 0xc: + case 0x15: + case 0x1b: + *freq = DDR_FREQ_400; + break; + case 0x6: + *freq = DDR_FREQ_300; + break; + case 0x12: + *freq = DDR_FREQ_360; + break; + case 0x13: + *freq = DDR_FREQ_400; + break; + default: + *freq = 0; + return MV_NOT_SUPPORTED; + } + + return MV_OK; +} + +u32 ddr3_tip_get_init_freq(void) +{ + enum hws_ddr_freq freq; + + ddr3_tip_a38x_get_init_freq(0, &freq); + + return freq; +} + +static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, + enum hws_ddr_freq frequency) +{ + u32 divider = 0; + u32 sar_val; + + if (if_id != 0) { + DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, + ("A38x does not support interface 0x%x\n", + if_id)); + return MV_BAD_PARAM; + } + + /* get VCO freq index */ + sar_val = (reg_read(REG_DEVICE_SAR1_ADDR) >> + RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET) & + RST2_CPU_DDR_CLOCK_SELECT_IN_MASK; + divider = a38x_vco_freq_per_sar[sar_val] / freq_val[frequency]; + + /* Set Sync mode */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x20220, 0x0, + 0x1000)); + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe42f4, 0x0, + 0x200)); + + /* cpupll_clkdiv_reset_mask */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0x1f, + 0xff)); + + /* cpupll_clkdiv_reload_smooth */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, + (0x2 << 8), (0xff << 8))); + + /* cpupll_clkdiv_relax_en */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, + (0x2 << 24), (0xff << 24))); + + /* write the divider */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4268, + (divider << 8), (0x3f << 8))); + + /* set cpupll_clkdiv_reload_ratio */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, + (1 << 8), (1 << 8))); + + /* undet cpupll_clkdiv_reload_ratio */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0, + (1 << 8))); + + /* clear cpupll_clkdiv_reload_force */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, 0, + (0xff << 8))); + + /* clear cpupll_clkdiv_relax_en */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4260, 0, + (0xff << 24))); + + /* clear cpupll_clkdiv_reset_mask */ + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0xe4264, 0, + 0xff)); + + /* Dunit training clock + 1:1 mode */ + if ((frequency == DDR_FREQ_LOW_FREQ) || (freq_val[frequency] <= 400)) { + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x18488, + (1 << 16), (1 << 16))); + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1524, + (0 << 15), (1 << 15))); + } else { + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x18488, + 0, (1 << 16))); + CHECK_STATUS(ddr3_tip_a38x_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1524, + (1 << 15), (1 << 15))); + } + + return MV_OK; +} + +/* + * external read from memory + */ +int ddr3_tip_ext_read(u32 dev_num, u32 if_id, u32 reg_addr, + u32 num_of_bursts, u32 *data) +{ + u32 burst_num; + + for (burst_num = 0; burst_num < num_of_bursts * 8; burst_num++) + data[burst_num] = readl(reg_addr + 4 * burst_num); + + return MV_OK; +} + +/* + * external write to memory + */ +int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr, + u32 num_of_bursts, u32 *data) { + u32 burst_num; + + for (burst_num = 0; burst_num < num_of_bursts * 8; burst_num++) + writel(data[burst_num], reg_addr + 4 * burst_num); + + return MV_OK; +} + +int ddr3_silicon_pre_init(void) +{ + int result; + + result = ddr3_silicon_init(); + + return result; +} + +int ddr3_post_run_alg(void) +{ + return MV_OK; +} + +int ddr3_silicon_post_init(void) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* Set half bus width */ + if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask)) { + CHECK_STATUS(ddr3_tip_if_write + (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE, + REG_SDRAM_CONFIG_ADDR, 0x0, 0x8000)); + } + + return MV_OK; +} + +int ddr3_tip_a38x_get_device_info(u8 dev_num, struct ddr3_device_info *info_ptr) +{ + info_ptr->device_id = 0x6800; + info_ptr->ck_delay = ck_delay; + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x.h b/drivers/ddr/marvell/a38x/ddr3_a38x.h new file mode 100644 index 0000000..49621bc --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_a38x.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_A38X_H +#define _DDR3_A38X_H + +#define MAX_INTERFACE_NUM 1 +#define MAX_BUS_NUM 5 + +#include "ddr3_hws_hw_training_def.h" + +/* Allow topolgy update from board TWSI device*/ +#if !defined(CONFIG_CUSTOMER_BOARD_SUPPORT) +#define MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI +#endif + +#define ECC_SUPPORT + +/* right now, we're not supporting this in mainline */ +#undef SUPPORT_STATIC_DUNIT_CONFIG + +/* Controler bus divider 1 for 32 bit, 2 for 64 bit */ +#define DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER 1 + +/* Tune internal training params values */ +#define TUNE_TRAINING_PARAMS_CK_DELAY 160 +#define TUNE_TRAINING_PARAMS_CK_DELAY_16 160 +#define TUNE_TRAINING_PARAMS_PFINGER 41 +#define TUNE_TRAINING_PARAMS_NFINGER 43 +#define TUNE_TRAINING_PARAMS_PHYREG3VAL 0xa + +#define MARVELL_BOARD MARVELL_BOARD_ID_BASE + + +#define REG_DEVICE_SAR1_ADDR 0xe4204 +#define RST2_CPU_DDR_CLOCK_SELECT_IN_OFFSET 17 +#define RST2_CPU_DDR_CLOCK_SELECT_IN_MASK 0x1f + +/* DRAM Windows */ +#define REG_XBAR_WIN_5_CTRL_ADDR 0x20050 +#define REG_XBAR_WIN_5_BASE_ADDR 0x20054 + +/* DRAM Windows */ +#define REG_XBAR_WIN_4_CTRL_ADDR 0x20040 +#define REG_XBAR_WIN_4_BASE_ADDR 0x20044 +#define REG_XBAR_WIN_4_REMAP_ADDR 0x20048 +#define REG_XBAR_WIN_7_REMAP_ADDR 0x20078 +#define REG_XBAR_WIN_16_CTRL_ADDR 0x200d0 +#define REG_XBAR_WIN_16_BASE_ADDR 0x200d4 +#define REG_XBAR_WIN_16_REMAP_ADDR 0x200dc +#define REG_XBAR_WIN_19_CTRL_ADDR 0x200e8 + +#define REG_FASTPATH_WIN_BASE_ADDR(win) (0x20180 + (0x8 * win)) +#define REG_FASTPATH_WIN_CTRL_ADDR(win) (0x20184 + (0x8 * win)) + +/* SatR defined too change topology busWidth and ECC configuration */ +#define DDR_SATR_CONFIG_MASK_WIDTH 0x8 +#define DDR_SATR_CONFIG_MASK_ECC 0x10 +#define DDR_SATR_CONFIG_MASK_ECC_PUP 0x20 + +#define REG_SAMPLE_RESET_HIGH_ADDR 0x18600 + +#define MV_BOARD_REFCLK MV_BOARD_REFCLK_25MHZ + +/* Matrix enables DRAM modes (bus width/ECC) per boardId */ +#define TOPOLOGY_UPDATE_32BIT 0 +#define TOPOLOGY_UPDATE_32BIT_ECC 1 +#define TOPOLOGY_UPDATE_16BIT 2 +#define TOPOLOGY_UPDATE_16BIT_ECC 3 +#define TOPOLOGY_UPDATE_16BIT_ECC_PUP3 4 +#define TOPOLOGY_UPDATE { \ + /* 32Bit, 32bit ECC, 16bit, 16bit ECC PUP4, 16bit ECC PUP3 */ \ + {1, 1, 1, 1, 1}, /* RD_NAS_68XX_ID */ \ + {1, 1, 1, 1, 1}, /* DB_68XX_ID */ \ + {1, 0, 1, 0, 1}, /* RD_AP_68XX_ID */ \ + {1, 0, 1, 0, 1}, /* DB_AP_68XX_ID */ \ + {1, 0, 1, 0, 1}, /* DB_GP_68XX_ID */ \ + {0, 0, 1, 1, 0}, /* DB_BP_6821_ID */ \ + {1, 1, 1, 1, 1} /* DB_AMC_6820_ID */ \ + }; + +enum { + CPU_1066MHZ_DDR_400MHZ, + CPU_RESERVED_DDR_RESERVED0, + CPU_667MHZ_DDR_667MHZ, + CPU_800MHZ_DDR_800MHZ, + CPU_RESERVED_DDR_RESERVED1, + CPU_RESERVED_DDR_RESERVED2, + CPU_RESERVED_DDR_RESERVED3, + LAST_FREQ +}; + +#define ACTIVE_INTERFACE_MASK 0x1 + +#endif /* _DDR3_A38X_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h b/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h new file mode 100644 index 0000000..b879a01 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_a38x_mc_static.h @@ -0,0 +1,226 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_A38X_MC_STATIC_H +#define _DDR3_A38X_MC_STATIC_H + +#include "ddr3_a38x.h" + +#ifdef SUPPORT_STATIC_DUNIT_CONFIG + +#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT +static struct reg_data ddr3_customer_800[] = { + /* parameters for customer board (based on 800MHZ) */ + {0x1400, 0x7b00cc30, 0xffffffff}, + {0x1404, 0x36301820, 0xffffffff}, + {0x1408, 0x5415baab, 0xffffffff}, + {0x140c, 0x38411def, 0xffffffff}, + {0x1410, 0x18300000, 0xffffffff}, + {0x1414, 0x00000700, 0xffffffff}, + {0x1424, 0x0060f3ff, 0xffffffff}, + {0x1428, 0x0011a940, 0xffffffff}, + {0x142c, 0x28c5134, 0xffffffff}, + {0x1474, 0x00000000, 0xffffffff}, + {0x147c, 0x0000d771, 0xffffffff}, + {0x1494, 0x00030000, 0xffffffff}, + {0x149c, 0x00000300, 0xffffffff}, + {0x14a8, 0x00000000, 0xffffffff}, + {0x14cc, 0xbd09000d, 0xffffffff}, + {0x1504, 0xfffffff1, 0xffffffff}, + {0x150c, 0xffffffe5, 0xffffffff}, + {0x1514, 0x00000000, 0xffffffff}, + {0x151c, 0x00000000, 0xffffffff}, + {0x1538, 0x00000b0b, 0xffffffff}, + {0x153c, 0x00000c0c, 0xffffffff}, + {0x15d0, 0x00000670, 0xffffffff}, + {0x15d4, 0x00000046, 0xffffffff}, + {0x15d8, 0x00000010, 0xffffffff}, + {0x15dc, 0x00000000, 0xffffffff}, + {0x15e0, 0x00000023, 0xffffffff}, + {0x15e4, 0x00203c18, 0xffffffff}, + {0x15ec, 0xf8000019, 0xffffffff}, + {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */ + {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */ + {0, 0, 0} +}; + +#else /* CONFIG_CUSTOMER_BOARD_SUPPORT */ + +struct reg_data ddr3_a38x_933[MV_MAX_DDR3_STATIC_SIZE] = { + /* parameters for 933MHZ */ + {0x1400, 0x7b00ce3a, 0xffffffff}, + {0x1404, 0x36301820, 0xffffffff}, + {0x1408, 0x7417eccf, 0xffffffff}, + {0x140c, 0x3e421f98, 0xffffffff}, + {0x1410, 0x1a300000, 0xffffffff}, + {0x1414, 0x00000700, 0xffffffff}, + {0x1424, 0x0060f3ff, 0xffffffff}, + {0x1428, 0x0013ca50, 0xffffffff}, + {0x142c, 0x028c5165, 0xffffffff}, + {0x1474, 0x00000000, 0xffffffff}, + {0x147c, 0x0000e871, 0xffffffff}, + {0x1494, 0x00010000, 0xffffffff}, + {0x149c, 0x00000001, 0xffffffff}, + {0x14a8, 0x00000000, 0xffffffff}, + {0x14cc, 0xbd09000d, 0xffffffff}, + {0x1504, 0xffffffe1, 0xffffffff}, + {0x150c, 0xffffffe5, 0xffffffff}, + {0x1514, 0x00000000, 0xffffffff}, + {0x151c, 0x00000000, 0xffffffff}, + {0x1538, 0x00000d0d, 0xffffffff}, + {0x153c, 0x00000d0d, 0xffffffff}, + {0x15d0, 0x00000608, 0xffffffff}, + {0x15d4, 0x00000044, 0xffffffff}, + {0x15d8, 0x00000020, 0xffffffff}, + {0x15dc, 0x00000000, 0xffffffff}, + {0x15e0, 0x00000021, 0xffffffff}, + {0x15e4, 0x00203c18, 0xffffffff}, + {0x15ec, 0xf8000019, 0xffffffff}, + {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */ + {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */ + {0, 0, 0} +}; + +static struct reg_data ddr3_a38x_800[] = { + /* parameters for 800MHZ */ + {0x1400, 0x7b00cc30, 0xffffffff}, + {0x1404, 0x36301820, 0xffffffff}, + {0x1408, 0x5415baab, 0xffffffff}, + {0x140c, 0x38411def, 0xffffffff}, + {0x1410, 0x18300000, 0xffffffff}, + {0x1414, 0x00000700, 0xffffffff}, + {0x1424, 0x0060f3ff, 0xffffffff}, + {0x1428, 0x0011a940, 0xffffffff}, + {0x142c, 0x28c5134, 0xffffffff}, + {0x1474, 0x00000000, 0xffffffff}, + {0x147c, 0x0000d771, 0xffffffff}, + {0x1494, 0x00030000, 0xffffffff}, + {0x149c, 0x00000300, 0xffffffff}, + {0x14a8, 0x00000000, 0xffffffff}, + {0x14cc, 0xbd09000d, 0xffffffff}, + {0x1504, 0xfffffff1, 0xffffffff}, + {0x150c, 0xffffffe5, 0xffffffff}, + {0x1514, 0x00000000, 0xffffffff}, + {0x151c, 0x00000000, 0xffffffff}, + {0x1538, 0x00000b0b, 0xffffffff}, + {0x153c, 0x00000c0c, 0xffffffff}, + {0x15d0, 0x00000670, 0xffffffff}, + {0x15d4, 0x00000046, 0xffffffff}, + {0x15d8, 0x00000010, 0xffffffff}, + {0x15dc, 0x00000000, 0xffffffff}, + {0x15e0, 0x00000023, 0xffffffff}, + {0x15e4, 0x00203c18, 0xffffffff}, + {0x15ec, 0xf8000019, 0xffffffff}, + {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */ + {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */ + {0, 0, 0} +}; + +static struct reg_data ddr3_a38x_667[] = { + /* parameters for 667MHZ */ + /* DDR SDRAM Configuration Register */ + {0x1400, 0x7b00ca28, 0xffffffff}, + /* Dunit Control Low Register - kw28 bit12 low (disable CLK1) */ + {0x1404, 0x36301820, 0xffffffff}, + /* DDR SDRAM Timing (Low) Register */ + {0x1408, 0x43149997, 0xffffffff}, + /* DDR SDRAM Timing (High) Register */ + {0x140c, 0x38411bc7, 0xffffffff}, + /* DDR SDRAM Address Control Register */ + {0x1410, 0x14330000, 0xffffffff}, + /* DDR SDRAM Open Pages Control Register */ + {0x1414, 0x00000700, 0xffffffff}, + /* Dunit Control High Register (2 :1 - bits 15:12 = 0xd) */ + {0x1424, 0x0060f3ff, 0xffffffff}, + /* Dunit Control High Register */ + {0x1428, 0x000f8830, 0xffffffff}, + /* Dunit Control High Register (2:1 - bit 29 = '1') */ + {0x142c, 0x28c50f8, 0xffffffff}, + {0x147c, 0x0000c671, 0xffffffff}, + /* DDR SDRAM ODT Control (Low) Register */ + {0x1494, 0x00030000, 0xffffffff}, + /* DDR SDRAM ODT Control (High) Register, will be configured at WL */ + {0x1498, 0x00000000, 0xffffffff}, + /* DDR Dunit ODT Control Register */ + {0x149c, 0x00000300, 0xffffffff}, + {0x14a8, 0x00000000, 0xffffffff}, /* */ + {0x14cc, 0xbd09000d, 0xffffffff}, /* */ + {0x1474, 0x00000000, 0xffffffff}, + /* Read Data Sample Delays Register */ + {0x1538, 0x00000009, 0xffffffff}, + /* Read Data Ready Delay Register */ + {0x153c, 0x0000000c, 0xffffffff}, + {0x1504, 0xfffffff1, 0xffffffff}, /* */ + {0x150c, 0xffffffe5, 0xffffffff}, /* */ + {0x1514, 0x00000000, 0xffffffff}, /* */ + {0x151c, 0x0, 0xffffffff}, /* */ + {0x15d0, 0x00000650, 0xffffffff}, /* MR0 */ + {0x15d4, 0x00000046, 0xffffffff}, /* MR1 */ + {0x15d8, 0x00000010, 0xffffffff}, /* MR2 */ + {0x15dc, 0x00000000, 0xffffffff}, /* MR3 */ + {0x15e0, 0x23, 0xffffffff}, /* */ + {0x15e4, 0x00203c18, 0xffffffff}, /* ZQC Configuration Register */ + {0x15ec, 0xf8000019, 0xffffffff}, /* DDR PHY */ + {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */ + {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */ + {0, 0, 0} +}; + +static struct reg_data ddr3_a38x_533[] = { + /* parameters for 533MHZ */ + /* DDR SDRAM Configuration Register */ + {0x1400, 0x7b00d040, 0xffffffff}, + /* Dunit Control Low Register - kw28 bit12 low (disable CLK1) */ + {0x1404, 0x36301820, 0xffffffff}, + /* DDR SDRAM Timing (Low) Register */ + {0x1408, 0x33137772, 0xffffffff}, + /* DDR SDRAM Timing (High) Register */ + {0x140c, 0x3841199f, 0xffffffff}, + /* DDR SDRAM Address Control Register */ + {0x1410, 0x10330000, 0xffffffff}, + /* DDR SDRAM Open Pages Control Register */ + {0x1414, 0x00000700, 0xffffffff}, + /* Dunit Control High Register (2 :1 - bits 15:12 = 0xd) */ + {0x1424, 0x0060f3ff, 0xffffffff}, + /* Dunit Control High Register */ + {0x1428, 0x000d6720, 0xffffffff}, + /* Dunit Control High Register (2:1 - bit 29 = '1') */ + {0x142c, 0x028c50c3, 0xffffffff}, + {0x147c, 0x0000b571, 0xffffffff}, + /* DDR SDRAM ODT Control (Low) Register */ + {0x1494, 0x00030000, 0xffffffff}, + /* DDR SDRAM ODT Control (High) Register, will be configured at WL */ + {0x1498, 0x00000000, 0xffffffff}, + /* DDR Dunit ODT Control Register */ + {0x149c, 0x00000003, 0xffffffff}, + {0x14a8, 0x00000000, 0xffffffff}, /* */ + {0x14cc, 0xbd09000d, 0xffffffff}, /* */ + {0x1474, 0x00000000, 0xffffffff}, + /* Read Data Sample Delays Register */ + {0x1538, 0x00000707, 0xffffffff}, + /* Read Data Ready Delay Register */ + {0x153c, 0x00000707, 0xffffffff}, + {0x1504, 0xffffffe1, 0xffffffff}, /* */ + {0x150c, 0xffffffe5, 0xffffffff}, /* */ + {0x1514, 0x00000000, 0xffffffff}, /* */ + {0x151c, 0x00000000, 0xffffffff}, /* */ + {0x15d0, 0x00000630, 0xffffffff}, /* MR0 */ + {0x15d4, 0x00000046, 0xffffffff}, /* MR1 */ + {0x15d8, 0x00000008, 0xffffffff}, /* MR2 */ + {0x15dc, 0x00000000, 0xffffffff}, /* MR3 */ + {0x15e0, 0x00000023, 0xffffffff}, /* */ + {0x15e4, 0x00203c18, 0xffffffff}, /* ZQC Configuration Register */ + {0x15ec, 0xf8000019, 0xffffffff}, /* DDR PHY */ + {0x16a0, 0xcc000006, 0xffffffff}, /* Clock Delay */ + {0xe4124, 0x08008073, 0xffffffff}, /* AVS BG default */ + {0, 0, 0} +}; + +#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */ + +#endif /* SUPPORT_STATIC_DUNIT_CONFIG */ + +#endif /* _DDR3_A38X_MC_STATIC_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h b/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h new file mode 100644 index 0000000..f27bbff --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_a38x_topology.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_A38X_TOPOLOGY_H +#define _DDR3_A38X_TOPOLOGY_H + +#include "ddr_topology_def.h" + +/* Bus mask variants */ +#define BUS_MASK_32BIT 0xf +#define BUS_MASK_32BIT_ECC 0x1f +#define BUS_MASK_16BIT 0x3 +#define BUS_MASK_16BIT_ECC 0x13 +#define BUS_MASK_16BIT_ECC_PUP3 0xb + +#define DYNAMIC_CS_SIZE_CONFIG +#define DISABLE_L2_FILTERING_DURING_DDR_TRAINING + +#endif /* _DDR3_A38X_TOPOLOGY_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_a38x_training.c b/drivers/ddr/marvell/a38x/ddr3_a38x_training.c new file mode 100644 index 0000000..52c43f7 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_a38x_training.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +/* + * Name: ddr3_tip_init_silicon + * Desc: initiate silicon parameters + * Args: + * Notes: + * Returns: required value + */ +int ddr3_silicon_init(void) +{ + int status; + static int init_done; + + if (init_done == 1) + return MV_OK; + + status = ddr3_tip_init_a38x(0, 0); + if (MV_OK != status) { + printf("DDR3 A38x silicon init - FAILED 0x%x\n", status); + return status; + } + + init_done = 1; + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_debug.c b/drivers/ddr/marvell/a38x/ddr3_debug.c new file mode 100644 index 0000000..1d72bc5 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_debug.c @@ -0,0 +1,1551 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +u8 is_reg_dump = 0; +u8 debug_pbs = DEBUG_LEVEL_ERROR; + +/* + * API to change flags outside of the lib + */ +#ifndef SILENT_LIB +/* Debug flags for other Training modules */ +u8 debug_training_static = DEBUG_LEVEL_ERROR; +u8 debug_training = DEBUG_LEVEL_ERROR; +u8 debug_leveling = DEBUG_LEVEL_ERROR; +u8 debug_centralization = DEBUG_LEVEL_ERROR; +u8 debug_training_ip = DEBUG_LEVEL_ERROR; +u8 debug_training_bist = DEBUG_LEVEL_ERROR; +u8 debug_training_hw_alg = DEBUG_LEVEL_ERROR; +u8 debug_training_access = DEBUG_LEVEL_ERROR; +u8 debug_training_a38x = DEBUG_LEVEL_ERROR; + +void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level) +{ + switch (block) { + case DEBUG_BLOCK_STATIC: + debug_training_static = level; + break; + case DEBUG_BLOCK_TRAINING_MAIN: + debug_training = level; + break; + case DEBUG_BLOCK_LEVELING: + debug_leveling = level; + break; + case DEBUG_BLOCK_CENTRALIZATION: + debug_centralization = level; + break; + case DEBUG_BLOCK_PBS: + debug_pbs = level; + break; + case DEBUG_BLOCK_ALG: + debug_training_hw_alg = level; + break; + case DEBUG_BLOCK_DEVICE: + debug_training_a38x = level; + break; + case DEBUG_BLOCK_ACCESS: + debug_training_access = level; + break; + case DEBUG_STAGES_REG_DUMP: + if (level == DEBUG_LEVEL_TRACE) + is_reg_dump = 1; + else + is_reg_dump = 0; + break; + case DEBUG_BLOCK_ALL: + default: + debug_training_static = level; + debug_training = level; + debug_leveling = level; + debug_centralization = level; + debug_pbs = level; + debug_training_hw_alg = level; + debug_training_access = level; + debug_training_a38x = level; + } +} +#else +void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level) +{ + return; +} +#endif + +struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM]; +u8 is_default_centralization = 0; +u8 is_tune_result = 0; +u8 is_validate_window_per_if = 0; +u8 is_validate_window_per_pup = 0; +u8 sweep_cnt = 1; +u32 is_bist_reset_bit = 1; +static struct hws_xsb_info xsb_info[HWS_MAX_DEVICE_NUM]; + +/* + * Dump Dunit & Phy registers + */ +int ddr3_tip_reg_dump(u32 dev_num) +{ + u32 if_id, reg_addr, data_value, bus_id; + u32 read_data[MAX_INTERFACE_NUM]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + printf("-- dunit registers --\n"); + for (reg_addr = 0x1400; reg_addr < 0x19f0; reg_addr += 4) { + printf("0x%x ", reg_addr); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + if_id, reg_addr, read_data, + MASK_ALL_BITS)); + printf("0x%x ", read_data[if_id]); + } + printf("\n"); + } + + printf("-- Phy registers --\n"); + for (reg_addr = 0; reg_addr <= 0xff; reg_addr++) { + printf("0x%x ", reg_addr); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; + bus_id < tm->num_of_bus_per_interface; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_DATA, reg_addr, + &data_value)); + printf("0x%x ", data_value); + } + for (bus_id = 0; + bus_id < tm->num_of_bus_per_interface; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_CONTROL, reg_addr, + &data_value)); + printf("0x%x ", data_value); + } + } + printf("\n"); + } + + return MV_OK; +} + +/* + * Register access func registration + */ +int ddr3_tip_init_config_func(u32 dev_num, + struct hws_tip_config_func_db *config_func) +{ + if (config_func == NULL) + return MV_BAD_PARAM; + + memcpy(&config_func_info[dev_num], config_func, + sizeof(struct hws_tip_config_func_db)); + + return MV_OK; +} + +/* + * Read training result table + */ +int hws_ddr3_tip_read_training_result( + u32 dev_num, enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]) +{ + dev_num = dev_num; + + if (result == NULL) + return MV_BAD_PARAM; + memcpy(result, training_result, sizeof(result)); + + return MV_OK; +} + +/* + * Get training result info pointer + */ +enum hws_result *ddr3_tip_get_result_ptr(u32 stage) +{ + return training_result[stage]; +} + +/* + * Device info read + */ +int ddr3_tip_get_device_info(u32 dev_num, struct ddr3_device_info *info_ptr) +{ + if (config_func_info[dev_num].tip_get_device_info_func != NULL) { + return config_func_info[dev_num]. + tip_get_device_info_func((u8) dev_num, info_ptr); + } + + return MV_FAIL; +} + +#ifndef EXCLUDE_SWITCH_DEBUG +/* + * Convert freq to character string + */ +static char *convert_freq(enum hws_ddr_freq freq) +{ + switch (freq) { + case DDR_FREQ_LOW_FREQ: + return "DDR_FREQ_LOW_FREQ"; + case DDR_FREQ_400: + return "400"; + + case DDR_FREQ_533: + return "533"; + case DDR_FREQ_667: + return "667"; + + case DDR_FREQ_800: + return "800"; + + case DDR_FREQ_933: + return "933"; + + case DDR_FREQ_1066: + return "1066"; + case DDR_FREQ_311: + return "311"; + + case DDR_FREQ_333: + return "333"; + + case DDR_FREQ_467: + return "467"; + + case DDR_FREQ_850: + return "850"; + + case DDR_FREQ_900: + return "900"; + + case DDR_FREQ_360: + return "DDR_FREQ_360"; + + case DDR_FREQ_1000: + return "DDR_FREQ_1000"; + default: + return "Unknown Frequency"; + } +} + +/* + * Convert device ID to character string + */ +static char *convert_dev_id(u32 dev_id) +{ + switch (dev_id) { + case 0x6800: + return "A38xx"; + case 0x6900: + return "A39XX"; + case 0xf400: + return "AC3"; + case 0xfc00: + return "BC2"; + + default: + return "Unknown Device"; + } +} + +/* + * Convert device ID to character string + */ +static char *convert_mem_size(u32 dev_id) +{ + switch (dev_id) { + case 0: + return "512 MB"; + case 1: + return "1 GB"; + case 2: + return "2 GB"; + case 3: + return "4 GB"; + case 4: + return "8 GB"; + + default: + return "wrong mem size"; + } +} + +int print_device_info(u8 dev_num) +{ + struct ddr3_device_info info_ptr; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + CHECK_STATUS(ddr3_tip_get_device_info(dev_num, &info_ptr)); + printf("=== DDR setup START===\n"); + printf("\tDevice ID: %s\n", convert_dev_id(info_ptr.device_id)); + printf("\tDDR3 CK delay: %d\n", info_ptr.ck_delay); + print_topology(tm); + printf("=== DDR setup END===\n"); + + return MV_OK; +} + +void hws_ddr3_tip_sweep_test(int enable) +{ + if (enable) { + is_validate_window_per_if = 1; + is_validate_window_per_pup = 1; + debug_training = DEBUG_LEVEL_TRACE; + } else { + is_validate_window_per_if = 0; + is_validate_window_per_pup = 0; + } +} +#endif + +char *ddr3_tip_convert_tune_result(enum hws_result tune_result) +{ + switch (tune_result) { + case TEST_FAILED: + return "FAILED"; + case TEST_SUCCESS: + return "PASS"; + case NO_TEST_DONE: + return "NOT COMPLETED"; + default: + return "Un-KNOWN"; + } +} + +/* + * Print log info + */ +int ddr3_tip_print_log(u32 dev_num, u32 mem_addr) +{ + u32 if_id = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + mem_addr = mem_addr; + +#ifndef EXCLUDE_SWITCH_DEBUG + if ((is_validate_window_per_if != 0) || + (is_validate_window_per_pup != 0)) { + u32 is_pup_log = 0; + enum hws_ddr_freq freq; + + freq = tm->interface_params[first_active_if].memory_freq; + + is_pup_log = (is_validate_window_per_pup != 0) ? 1 : 0; + printf("===VALIDATE WINDOW LOG START===\n"); + printf("DDR Frequency: %s ======\n", convert_freq(freq)); + /* print sweep windows */ + ddr3_tip_run_sweep_test(dev_num, sweep_cnt, 1, is_pup_log); + ddr3_tip_run_sweep_test(dev_num, sweep_cnt, 0, is_pup_log); + ddr3_tip_print_all_pbs_result(dev_num); + ddr3_tip_print_wl_supp_result(dev_num); + printf("===VALIDATE WINDOW LOG END ===\n"); + CHECK_STATUS(ddr3_tip_restore_dunit_regs(dev_num)); + ddr3_tip_reg_dump(dev_num); + } +#endif + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("IF %d Status:\n", if_id)); + + if (mask_tune_func & INIT_CONTROLLER_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tInit Controller: %s\n", + ddr3_tip_convert_tune_result + (training_result[INIT_CONTROLLER] + [if_id]))); + } + if (mask_tune_func & SET_LOW_FREQ_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tLow freq Config: %s\n", + ddr3_tip_convert_tune_result + (training_result[SET_LOW_FREQ] + [if_id]))); + } + if (mask_tune_func & LOAD_PATTERN_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tLoad Pattern: %s\n", + ddr3_tip_convert_tune_result + (training_result[LOAD_PATTERN] + [if_id]))); + } + if (mask_tune_func & SET_MEDIUM_FREQ_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tMedium freq Config: %s\n", + ddr3_tip_convert_tune_result + (training_result[SET_MEDIUM_FREQ] + [if_id]))); + } + if (mask_tune_func & WRITE_LEVELING_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tWL: %s\n", + ddr3_tip_convert_tune_result + (training_result[WRITE_LEVELING] + [if_id]))); + } + if (mask_tune_func & LOAD_PATTERN_2_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tLoad Pattern: %s\n", + ddr3_tip_convert_tune_result + (training_result[LOAD_PATTERN_2] + [if_id]))); + } + if (mask_tune_func & READ_LEVELING_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tRL: %s\n", + ddr3_tip_convert_tune_result + (training_result[READ_LEVELING] + [if_id]))); + } + if (mask_tune_func & WRITE_LEVELING_SUPP_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tWL Supp: %s\n", + ddr3_tip_convert_tune_result + (training_result[WRITE_LEVELING_SUPP] + [if_id]))); + } + if (mask_tune_func & PBS_RX_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tPBS RX: %s\n", + ddr3_tip_convert_tune_result + (training_result[PBS_RX] + [if_id]))); + } + if (mask_tune_func & PBS_TX_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tPBS TX: %s\n", + ddr3_tip_convert_tune_result + (training_result[PBS_TX] + [if_id]))); + } + if (mask_tune_func & SET_TARGET_FREQ_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tTarget freq Config: %s\n", + ddr3_tip_convert_tune_result + (training_result[SET_TARGET_FREQ] + [if_id]))); + } + if (mask_tune_func & WRITE_LEVELING_TF_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tWL TF: %s\n", + ddr3_tip_convert_tune_result + (training_result[WRITE_LEVELING_TF] + [if_id]))); + } + if (mask_tune_func & READ_LEVELING_TF_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tRL TF: %s\n", + ddr3_tip_convert_tune_result + (training_result[READ_LEVELING_TF] + [if_id]))); + } + if (mask_tune_func & WRITE_LEVELING_SUPP_TF_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tWL TF Supp: %s\n", + ddr3_tip_convert_tune_result + (training_result + [WRITE_LEVELING_SUPP_TF] + [if_id]))); + } + if (mask_tune_func & CENTRALIZATION_RX_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tCentr RX: %s\n", + ddr3_tip_convert_tune_result + (training_result[CENTRALIZATION_RX] + [if_id]))); + } + if (mask_tune_func & VREF_CALIBRATION_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tVREF_CALIBRATION: %s\n", + ddr3_tip_convert_tune_result + (training_result[VREF_CALIBRATION] + [if_id]))); + } + if (mask_tune_func & CENTRALIZATION_TX_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("\tCentr TX: %s\n", + ddr3_tip_convert_tune_result + (training_result[CENTRALIZATION_TX] + [if_id]))); + } + } + + return MV_OK; +} + +/* + * Print stability log info + */ +int ddr3_tip_print_stability_log(u32 dev_num) +{ + u8 if_id = 0, csindex = 0, bus_id = 0, idx = 0; + u32 reg_data; + u32 read_data[MAX_INTERFACE_NUM]; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* Title print */ + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + printf("Title: I/F# , Tj, Calibration_n0, Calibration_p0, Calibration_n1, Calibration_p1, Calibration_n2, Calibration_p2,"); + for (csindex = 0; csindex < max_cs; csindex++) { + printf("CS%d , ", csindex); + printf("\n"); + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + printf("VWTx, VWRx, WL_tot, WL_ADLL, WL_PH, RL_Tot, RL_ADLL, RL_PH, RL_Smp, Cen_tx, Cen_rx, Vref, DQVref,"); + printf("\t\t"); + for (idx = 0; idx < 11; idx++) + printf("PBSTx-Pad%d,", idx); + printf("\t\t"); + for (idx = 0; idx < 11; idx++) + printf("PBSRx-Pad%d,", idx); + } + } + printf("\n"); + + /* Data print */ + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + printf("Data: %d,%d,", if_id, + (config_func_info[dev_num].tip_get_temperature != NULL) + ? (config_func_info[dev_num]. + tip_get_temperature(dev_num)) : (0)); + + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x14c8, + read_data, MASK_ALL_BITS)); + printf("%d,%d,", ((read_data[if_id] & 0x3f0) >> 4), + ((read_data[if_id] & 0xfc00) >> 10)); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x17c8, + read_data, MASK_ALL_BITS)); + printf("%d,%d,", ((read_data[if_id] & 0x3f0) >> 4), + ((read_data[if_id] & 0xfc00) >> 10)); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1dc8, + read_data, MASK_ALL_BITS)); + printf("%d,%d,", ((read_data[if_id] & 0x3f0000) >> 16), + ((read_data[if_id] & 0xfc00000) >> 22)); + + for (csindex = 0; csindex < max_cs; csindex++) { + printf("CS%d , ", csindex); + for (bus_id = 0; bus_id < MAX_BUS_NUM; bus_id++) { + printf("\n"); + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + RESULT_DB_PHY_REG_ADDR + + csindex, ®_data); + printf("%d,%d,", (reg_data & 0x1f), + ((reg_data & 0x3e0) >> 5)); + /* WL */ + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + WL_PHY_REG + + csindex * 4, ®_data); + printf("%d,%d,%d,", + (reg_data & 0x1f) + + ((reg_data & 0x1c0) >> 6) * 32, + (reg_data & 0x1f), + (reg_data & 0x1c0) >> 6); + /* RL */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + if_id, + READ_DATA_SAMPLE_DELAY, + read_data, MASK_ALL_BITS)); + read_data[if_id] = + (read_data[if_id] & + (0xf << (4 * csindex))) >> + (4 * csindex); + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_DATA, + RL_PHY_REG + csindex * 4, + ®_data); + printf("%d,%d,%d,%d,", + (reg_data & 0x1f) + + ((reg_data & 0x1c0) >> 6) * 32 + + read_data[if_id] * 64, + (reg_data & 0x1f), + ((reg_data & 0x1c0) >> 6), + read_data[if_id]); + /* Centralization */ + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + csindex * 4, ®_data); + printf("%d,", (reg_data & 0x3f)); + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_DATA, + READ_CENTRALIZATION_PHY_REG + + csindex * 4, ®_data); + printf("%d,", (reg_data & 0x1f)); + /* Vref */ + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_DATA, + PAD_CONFIG_PHY_REG, + ®_data); + printf("%d,", (reg_data & 0x7)); + /* DQVref */ + /* Need to add the Read Function from device */ + printf("%d,", 0); + printf("\t\t"); + for (idx = 0; idx < 11; idx++) { + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + 0xd0 + + 12 * csindex + + idx, ®_data); + printf("%d,", (reg_data & 0x3f)); + } + printf("\t\t"); + for (idx = 0; idx < 11; idx++) { + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + 0x10 + + 16 * csindex + + idx, ®_data); + printf("%d,", (reg_data & 0x3f)); + } + printf("\t\t"); + for (idx = 0; idx < 11; idx++) { + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + 0x50 + + 16 * csindex + + idx, ®_data); + printf("%d,", (reg_data & 0x3f)); + } + } + } + } + printf("\n"); + + return MV_OK; +} + +/* + * Register XSB information + */ +int ddr3_tip_register_xsb_info(u32 dev_num, struct hws_xsb_info *xsb_info_table) +{ + memcpy(&xsb_info[dev_num], xsb_info_table, sizeof(struct hws_xsb_info)); + return MV_OK; +} + +/* + * Read ADLL Value + */ +int read_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], + int reg_addr, u32 mask) +{ + u32 data_value; + u32 if_id = 0, bus_id = 0; + u32 dev_num = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* + * multi CS support - reg_addr is calucalated in calling function + * with CS offset + */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, + bus_id, + DDR_PHY_DATA, reg_addr, + &data_value)); + pup_values[if_id * + tm->num_of_bus_per_interface + bus_id] = + data_value & mask; + } + } + + return 0; +} + +/* + * Write ADLL Value + */ +int write_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], + int reg_addr) +{ + u32 if_id = 0, bus_id = 0; + u32 dev_num = 0, data; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* + * multi CS support - reg_addr is calucalated in calling function + * with CS offset + */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + data = pup_values[if_id * + tm->num_of_bus_per_interface + + bus_id]; + CHECK_STATUS(ddr3_tip_bus_write(dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + reg_addr, data)); + } + } + + return 0; +} + +#ifndef EXCLUDE_SWITCH_DEBUG +u32 rl_version = 1; /* 0 - old RL machine */ +struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM]; +u32 start_xsb_offset = 0; +u8 is_rl_old = 0; +u8 is_freq_old = 0; +u8 is_dfs_disabled = 0; +u32 default_centrlization_value = 0x12; +u32 vref = 0x4; +u32 activate_select_before_run_alg = 1, activate_deselect_after_run_alg = 1, + rl_test = 0, reset_read_fifo = 0; +int debug_acc = 0; +u32 ctrl_sweepres[ADLL_LENGTH][MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u32 ctrl_adll[MAX_CS_NUM * MAX_INTERFACE_NUM * MAX_BUS_NUM]; +u8 cs_mask_reg[] = { + 0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +u32 xsb_test_table[][8] = { + {0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, + 0x66666666, 0x77777777}, + {0x88888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd, + 0xeeeeeeee, 0xffffffff}, + {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff}, + {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff}, + {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff}, + {0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff}, + {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff}, + {0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000}, + {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff} +}; + +static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr); + +int ddr3_tip_print_adll(void) +{ + u32 bus_cnt = 0, if_id, data_p1, data_p2, ui_data3, dev_num = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_cnt, + DDR_PHY_DATA, 0x1, &data_p1)); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_cnt, DDR_PHY_DATA, 0x2, &data_p2)); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_cnt, DDR_PHY_DATA, 0x3, &ui_data3)); + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + (" IF %d bus_cnt %d phy_reg_1_data 0x%x phy_reg_2_data 0x%x phy_reg_3_data 0x%x\n", + if_id, bus_cnt, data_p1, data_p2, + ui_data3)); + } + } + + return MV_OK; +} + +/* + * Set attribute value + */ +int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value) +{ + int ret; + u32 *ptr_flag = NULL; + + ret = ddr3_tip_access_atr(dev_num, flag_id, value, &ptr_flag); + if (ptr_flag != NULL) { + printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x (was 0x%x)\n", + flag_id, value, *ptr_flag); + *ptr_flag = value; + } else { + printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x\n", + flag_id, value); + } + + return ret; +} + +/* + * Access attribute + */ +static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr) +{ + u32 tmp_val = 0, if_id = 0, pup_id = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + dev_num = dev_num; + *ptr = NULL; + + switch (flag_id) { + case 0: + *ptr = (u32 *)&(tm->if_act_mask); + break; + + case 0x1: + *ptr = (u32 *)&mask_tune_func; + break; + + case 0x2: + *ptr = (u32 *)&low_freq; + break; + + case 0x3: + *ptr = (u32 *)&medium_freq; + break; + + case 0x4: + *ptr = (u32 *)&generic_init_controller; + break; + + case 0x5: + *ptr = (u32 *)&rl_version; + break; + + case 0x8: + *ptr = (u32 *)&start_xsb_offset; + break; + + case 0x20: + *ptr = (u32 *)&is_rl_old; + break; + + case 0x21: + *ptr = (u32 *)&is_freq_old; + break; + + case 0x23: + *ptr = (u32 *)&is_dfs_disabled; + break; + + case 0x24: + *ptr = (u32 *)&is_pll_before_init; + break; + + case 0x25: + *ptr = (u32 *)&is_adll_calib_before_init; + break; +#ifdef STATIC_ALGO_SUPPORT + case 0x26: + *ptr = (u32 *)&(silicon_delay[0]); + break; + + case 0x27: + *ptr = (u32 *)&wl_debug_delay; + break; +#endif + case 0x28: + *ptr = (u32 *)&is_tune_result; + break; + + case 0x29: + *ptr = (u32 *)&is_validate_window_per_if; + break; + + case 0x2a: + *ptr = (u32 *)&is_validate_window_per_pup; + break; + + case 0x30: + *ptr = (u32 *)&sweep_cnt; + break; + + case 0x31: + *ptr = (u32 *)&is_bist_reset_bit; + break; + + case 0x32: + *ptr = (u32 *)&is_dfs_in_init; + break; + + case 0x33: + *ptr = (u32 *)&p_finger; + break; + + case 0x34: + *ptr = (u32 *)&n_finger; + break; + + case 0x35: + *ptr = (u32 *)&init_freq; + break; + + case 0x36: + *ptr = (u32 *)&(freq_val[DDR_FREQ_LOW_FREQ]); + break; + + case 0x37: + *ptr = (u32 *)&start_pattern; + break; + + case 0x38: + *ptr = (u32 *)&end_pattern; + break; + + case 0x39: + *ptr = (u32 *)&phy_reg0_val; + break; + + case 0x4a: + *ptr = (u32 *)&phy_reg1_val; + break; + + case 0x4b: + *ptr = (u32 *)&phy_reg2_val; + break; + + case 0x4c: + *ptr = (u32 *)&phy_reg3_val; + break; + + case 0x4e: + *ptr = (u32 *)&sweep_pattern; + break; + + case 0x50: + *ptr = (u32 *)&is_rzq6; + break; + + case 0x51: + *ptr = (u32 *)&znri_data_phy_val; + break; + + case 0x52: + *ptr = (u32 *)&zpri_data_phy_val; + break; + + case 0x53: + *ptr = (u32 *)&finger_test; + break; + + case 0x54: + *ptr = (u32 *)&n_finger_start; + break; + + case 0x55: + *ptr = (u32 *)&n_finger_end; + break; + + case 0x56: + *ptr = (u32 *)&p_finger_start; + break; + + case 0x57: + *ptr = (u32 *)&p_finger_end; + break; + + case 0x58: + *ptr = (u32 *)&p_finger_step; + break; + + case 0x59: + *ptr = (u32 *)&n_finger_step; + break; + + case 0x5a: + *ptr = (u32 *)&znri_ctrl_phy_val; + break; + + case 0x5b: + *ptr = (u32 *)&zpri_ctrl_phy_val; + break; + + case 0x5c: + *ptr = (u32 *)&is_reg_dump; + break; + + case 0x5d: + *ptr = (u32 *)&vref; + break; + + case 0x5e: + *ptr = (u32 *)&mode2_t; + break; + + case 0x5f: + *ptr = (u32 *)&xsb_validate_type; + break; + + case 0x60: + *ptr = (u32 *)&xsb_validation_base_address; + break; + + case 0x67: + *ptr = (u32 *)&activate_select_before_run_alg; + break; + + case 0x68: + *ptr = (u32 *)&activate_deselect_after_run_alg; + break; + + case 0x69: + *ptr = (u32 *)&odt_additional; + break; + + case 0x70: + *ptr = (u32 *)&debug_mode; + break; + + case 0x71: + *ptr = (u32 *)&pbs_pattern; + break; + + case 0x72: + *ptr = (u32 *)&delay_enable; + break; + + case 0x73: + *ptr = (u32 *)&ck_delay; + break; + + case 0x74: + *ptr = (u32 *)&ck_delay_16; + break; + + case 0x75: + *ptr = (u32 *)&ca_delay; + break; + + case 0x100: + *ptr = (u32 *)&debug_dunit; + break; + + case 0x101: + debug_acc = (int)value; + break; + + case 0x102: + debug_training = (u8)value; + break; + + case 0x103: + debug_training_bist = (u8)value; + break; + + case 0x104: + debug_centralization = (u8)value; + break; + + case 0x105: + debug_training_ip = (u8)value; + break; + + case 0x106: + debug_leveling = (u8)value; + break; + + case 0x107: + debug_pbs = (u8)value; + break; + + case 0x108: + debug_training_static = (u8)value; + break; + + case 0x109: + debug_training_access = (u8)value; + break; + + case 0x112: + *ptr = &start_pattern; + break; + + case 0x113: + *ptr = &end_pattern; + break; + + default: + if ((flag_id >= 0x200) && (flag_id < 0x210)) { + if_id = flag_id - 0x200; + *ptr = (u32 *)&(tm->interface_params + [if_id].memory_freq); + } else if ((flag_id >= 0x210) && (flag_id < 0x220)) { + if_id = flag_id - 0x210; + *ptr = (u32 *)&(tm->interface_params + [if_id].speed_bin_index); + } else if ((flag_id >= 0x220) && (flag_id < 0x230)) { + if_id = flag_id - 0x220; + *ptr = (u32 *)&(tm->interface_params + [if_id].bus_width); + } else if ((flag_id >= 0x230) && (flag_id < 0x240)) { + if_id = flag_id - 0x230; + *ptr = (u32 *)&(tm->interface_params + [if_id].memory_size); + } else if ((flag_id >= 0x240) && (flag_id < 0x250)) { + if_id = flag_id - 0x240; + *ptr = (u32 *)&(tm->interface_params + [if_id].cas_l); + } else if ((flag_id >= 0x250) && (flag_id < 0x260)) { + if_id = flag_id - 0x250; + *ptr = (u32 *)&(tm->interface_params + [if_id].cas_wl); + } else if ((flag_id >= 0x270) && (flag_id < 0x2cf)) { + if_id = (flag_id - 0x270) / MAX_BUS_NUM; + pup_id = (flag_id - 0x270) % MAX_BUS_NUM; + *ptr = (u32 *)&(tm->interface_params[if_id]. + as_bus_params[pup_id].is_ck_swap); + } else if ((flag_id >= 0x2d0) && (flag_id < 0x32f)) { + if_id = (flag_id - 0x2d0) / MAX_BUS_NUM; + pup_id = (flag_id - 0x2d0) % MAX_BUS_NUM; + *ptr = (u32 *)&(tm->interface_params[if_id]. + as_bus_params[pup_id].is_dqs_swap); + } else if ((flag_id >= 0x330) && (flag_id < 0x38f)) { + if_id = (flag_id - 0x330) / MAX_BUS_NUM; + pup_id = (flag_id - 0x330) % MAX_BUS_NUM; + *ptr = (u32 *)&(tm->interface_params[if_id]. + as_bus_params[pup_id].cs_bitmask); + } else if ((flag_id >= 0x390) && (flag_id < 0x3ef)) { + if_id = (flag_id - 0x390) / MAX_BUS_NUM; + pup_id = (flag_id - 0x390) % MAX_BUS_NUM; + *ptr = (u32 *)&(tm->interface_params + [if_id].as_bus_params + [pup_id].mirror_enable_bitmask); + } else if ((flag_id >= 0x500) && (flag_id <= 0x50f)) { + tmp_val = flag_id - 0x320; + *ptr = (u32 *)&(clamp_tbl[tmp_val]); + } else { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("flag_id out of boundary %d\n", + flag_id)); + return MV_BAD_PARAM; + } + } + + return MV_OK; +} + +#ifndef EXCLUDE_SWITCH_DEBUG +/* + * Print ADLL + */ +int print_adll(u32 dev_num, u32 adll[MAX_INTERFACE_NUM * MAX_BUS_NUM]) +{ + u32 i, j; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + dev_num = dev_num; + + for (j = 0; j < tm->num_of_bus_per_interface; j++) { + VALIDATE_ACTIVE(tm->bus_act_mask, j); + for (i = 0; i < MAX_INTERFACE_NUM; i++) { + printf("%d ,", + adll[i * tm->num_of_bus_per_interface + j]); + } + } + printf("\n"); + + return MV_OK; +} +#endif + +/* byte_index - only byte 0, 1, 2, or 3, oxff - test all bytes */ +static u32 ddr3_tip_compare(u32 if_id, u32 *p_src, u32 *p_dst, + u32 byte_index) +{ + u32 burst_cnt = 0, addr_offset, i_id; + int b_is_fail = 0; + + addr_offset = + (byte_index == + 0xff) ? (u32) 0xffffffff : (u32) (0xff << (byte_index * 8)); + for (burst_cnt = 0; burst_cnt < EXT_ACCESS_BURST_LENGTH; burst_cnt++) { + if ((p_src[burst_cnt] & addr_offset) != + (p_dst[burst_cnt] & addr_offset)) + b_is_fail = 1; + } + + if (b_is_fail == 1) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("IF %d exp: ", if_id)); + for (i_id = 0; i_id <= MAX_INTERFACE_NUM - 1; i_id++) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("0x%8x ", p_src[i_id])); + } + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("\n_i_f %d rcv: ", if_id)); + for (i_id = 0; i_id <= MAX_INTERFACE_NUM - 1; i_id++) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("(0x%8x ", p_dst[i_id])); + } + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("\n ")); + } + + return b_is_fail; +} + +/* test_type = 0-tx , 1-rx */ +int ddr3_tip_sweep_test(u32 dev_num, u32 test_type, + u32 mem_addr, u32 is_modify_adll, + u32 start_if, u32 end_if, u32 startpup, u32 endpup) +{ + u32 bus_cnt = 0, adll_val = 0, if_id, ui_prev_adll, ui_mask_bit, + end_adll, start_adll; + u32 reg_addr = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + mem_addr = mem_addr; + + if (test_type == 0) { + reg_addr = 1; + ui_mask_bit = 0x3f; + start_adll = 0; + end_adll = ui_mask_bit; + } else { + reg_addr = 3; + ui_mask_bit = 0x1f; + start_adll = 0; + end_adll = ui_mask_bit; + } + + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("==============================\n")); + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("Test type %d (0-tx, 1-rx)\n", test_type)); + + for (if_id = start_if; if_id <= end_if; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_cnt = startpup; bus_cnt < endpup; bus_cnt++) { + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_cnt, DDR_PHY_DATA, reg_addr, + &ui_prev_adll)); + + for (adll_val = start_adll; adll_val <= end_adll; + adll_val++) { + if (is_modify_adll == 1) { + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, bus_cnt, + DDR_PHY_DATA, reg_addr, + adll_val, ui_mask_bit)); + } + } + if (is_modify_adll == 1) { + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + bus_cnt, DDR_PHY_DATA, reg_addr, + ui_prev_adll)); + } + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("\n")); + } + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("\n")); + } + + return MV_OK; +} + +#ifndef EXCLUDE_SWITCH_DEBUG +/* + * Sweep validation + */ +int ddr3_tip_run_sweep_test(int dev_num, u32 repeat_num, u32 direction, + u32 mode) +{ + u32 pup = 0, start_pup = 0, end_pup = 0; + u32 adll = 0; + u32 res[MAX_INTERFACE_NUM] = { 0 }; + int if_id = 0; + u32 adll_value = 0; + int reg = (direction == 0) ? WRITE_CENTRALIZATION_PHY_REG : + READ_CENTRALIZATION_PHY_REG; + enum hws_access_type pup_access; + u32 cs; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + repeat_num = repeat_num; + + if (mode == 1) { + /* per pup */ + start_pup = 0; + end_pup = tm->num_of_bus_per_interface - 1; + pup_access = ACCESS_TYPE_UNICAST; + } else { + start_pup = 0; + end_pup = 0; + pup_access = ACCESS_TYPE_MULTICAST; + } + + for (cs = 0; cs < max_cs; cs++) { + for (adll = 0; adll < ADLL_LENGTH; adll++) { + for (if_id = 0; + if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE + (tm->if_act_mask, + if_id); + for (pup = start_pup; pup <= end_pup; pup++) { + ctrl_sweepres[adll][if_id][pup] = + 0; + } + } + } + + for (adll = 0; adll < (MAX_INTERFACE_NUM * MAX_BUS_NUM); adll++) + ctrl_adll[adll] = 0; + /* Save DQS value(after algorithm run) */ + read_adll_value(ctrl_adll, + (reg + (cs * CS_REGISTER_ADDR_OFFSET)), + MASK_ALL_BITS); + + /* + * Sweep ADLL from 0:31 on all I/F on all Pup and perform + * BIST on each stage. + */ + for (pup = start_pup; pup <= end_pup; pup++) { + for (adll = 0; adll < ADLL_LENGTH; adll++) { + adll_value = + (direction == 0) ? (adll * 2) : adll; + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, 0, + pup_access, pup, DDR_PHY_DATA, + reg + CS_REG_VALUE(cs), + adll_value)); + hws_ddr3_run_bist(dev_num, sweep_pattern, res, + cs); + /* ddr3_tip_reset_fifo_ptr(dev_num); */ + for (if_id = 0; + if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE + (tm->if_act_mask, + if_id); + ctrl_sweepres[adll][if_id][pup] + = res[if_id]; + if (mode == 1) { + CHECK_STATUS + (ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + pup, + DDR_PHY_DATA, + reg + CS_REG_VALUE(cs), + ctrl_adll[if_id * + cs * + tm->num_of_bus_per_interface + + pup])); + } + } + } + } + printf("Final, CS %d,%s, Sweep, Result, Adll,", cs, + ((direction == 0) ? "TX" : "RX")); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (mode == 1) { + for (pup = start_pup; pup <= end_pup; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + printf("I/F%d-PHY%d , ", if_id, pup); + } + } else { + printf("I/F%d , ", if_id); + } + } + printf("\n"); + + for (adll = 0; adll < ADLL_LENGTH; adll++) { + adll_value = (direction == 0) ? (adll * 2) : adll; + printf("Final,%s, Sweep, Result, %d ,", + ((direction == 0) ? "TX" : "RX"), adll_value); + + for (if_id = 0; + if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup = start_pup; pup <= end_pup; pup++) { + printf("%d , ", + ctrl_sweepres[adll][if_id] + [pup]); + } + } + printf("\n"); + } + + /* + * Write back to the phy the Rx DQS value, we store in + * the beginning. + */ + write_adll_value(ctrl_adll, + (reg + cs * CS_REGISTER_ADDR_OFFSET)); + /* print adll results */ + read_adll_value(ctrl_adll, (reg + cs * CS_REGISTER_ADDR_OFFSET), + MASK_ALL_BITS); + printf("%s, DQS, ADLL,,,", (direction == 0) ? "Tx" : "Rx"); + print_adll(dev_num, ctrl_adll); + } + ddr3_tip_reset_fifo_ptr(dev_num); + + return 0; +} + +void print_topology(struct hws_topology_map *topology_db) +{ + u32 ui, uj; + + printf("\tinterface_mask: 0x%x\n", topology_db->if_act_mask); + printf("\tNum Bus: %d\n", topology_db->num_of_bus_per_interface); + printf("\tbus_act_mask: 0x%x\n", topology_db->bus_act_mask); + + for (ui = 0; ui < MAX_INTERFACE_NUM; ui++) { + VALIDATE_ACTIVE(topology_db->if_act_mask, ui); + printf("\n\tInterface ID: %d\n", ui); + printf("\t\tDDR Frequency: %s\n", + convert_freq(topology_db-> + interface_params[ui].memory_freq)); + printf("\t\tSpeed_bin: %d\n", + topology_db->interface_params[ui].speed_bin_index); + printf("\t\tBus_width: %d\n", + (4 << topology_db->interface_params[ui].bus_width)); + printf("\t\tMem_size: %s\n", + convert_mem_size(topology_db-> + interface_params[ui].memory_size)); + printf("\t\tCAS-WL: %d\n", + topology_db->interface_params[ui].cas_wl); + printf("\t\tCAS-L: %d\n", + topology_db->interface_params[ui].cas_l); + printf("\t\tTemperature: %d\n", + topology_db->interface_params[ui].interface_temp); + printf("\n"); + for (uj = 0; uj < 4; uj++) { + printf("\t\tBus %d parameters- CS Mask: 0x%x\t", uj, + topology_db->interface_params[ui]. + as_bus_params[uj].cs_bitmask); + printf("Mirror: 0x%x\t", + topology_db->interface_params[ui]. + as_bus_params[uj].mirror_enable_bitmask); + printf("DQS Swap is %s \t", + (topology_db-> + interface_params[ui].as_bus_params[uj]. + is_dqs_swap == 1) ? "enabled" : "disabled"); + printf("Ck Swap:%s\t", + (topology_db-> + interface_params[ui].as_bus_params[uj]. + is_ck_swap == 1) ? "enabled" : "disabled"); + printf("\n"); + } + } +} +#endif + +/* + * Execute XSB Test transaction (rd/wr/both) + */ +int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type, + u32 read_type, u32 burst_length) +{ + u32 seq = 0, if_id = 0, addr, cnt; + int ret = MV_OK, ret_tmp; + u32 data_read[MAX_INTERFACE_NUM]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + addr = mem_addr; + for (cnt = 0; cnt <= burst_length; cnt++) { + seq = (seq + 1) % 8; + if (write_type != 0) { + CHECK_STATUS(ddr3_tip_ext_write + (dev_num, if_id, addr, 1, + xsb_test_table[seq])); + } + if (read_type != 0) { + CHECK_STATUS(ddr3_tip_ext_read + (dev_num, if_id, addr, 1, + data_read)); + } + if ((read_type != 0) && (write_type != 0)) { + ret_tmp = + ddr3_tip_compare(if_id, + xsb_test_table[seq], + data_read, + 0xff); + addr += (EXT_ACCESS_BURST_LENGTH * 4); + ret = (ret != MV_OK) ? ret : ret_tmp; + } + } + } + + return ret; +} + +#else /*EXCLUDE_SWITCH_DEBUG */ + +u32 rl_version = 1; /* 0 - old RL machine */ +u32 vref = 0x4; +u32 start_xsb_offset = 0; +u8 cs_mask_reg[] = { + 0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type, + u32 read_type, u32 burst_length) +{ + return MV_OK; +} + +#endif diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c new file mode 100644 index 0000000..560da7e --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define REG_READ_DATA_SAMPLE_DELAYS_ADDR 0x1538 +#define REG_READ_DATA_SAMPLE_DELAYS_MASK 0x1f +#define REG_READ_DATA_SAMPLE_DELAYS_OFFS 8 + +#define REG_READ_DATA_READY_DELAYS_ADDR 0x153c +#define REG_READ_DATA_READY_DELAYS_MASK 0x1f +#define REG_READ_DATA_READY_DELAYS_OFFS 8 + +int ddr3_if_ecc_enabled(void) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask) || + DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask)) + return 1; + else + return 0; +} + +int ddr3_pre_algo_config(void) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* Set Bus3 ECC training mode */ + if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask)) { + /* Set Bus3 ECC MUX */ + CHECK_STATUS(ddr3_tip_if_write + (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE, + REG_SDRAM_PINS_MUX, 0x100, 0x100)); + } + + /* Set regular ECC training mode (bus4 and bus 3) */ + if ((DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask)) || + (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))) { + /* Enable ECC Write MUX */ + CHECK_STATUS(ddr3_tip_if_write + (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x100, 0x100)); + /* General ECC enable */ + CHECK_STATUS(ddr3_tip_if_write + (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE, + REG_SDRAM_CONFIG_ADDR, 0x40000, 0x40000)); + /* Disable Read Data ECC MUX */ + CHECK_STATUS(ddr3_tip_if_write + (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x0, 0x2)); + } + + return MV_OK; +} + +int ddr3_post_algo_config(void) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + int status; + + status = ddr3_post_run_alg(); + if (MV_OK != status) { + printf("DDR3 Post Run Alg - FAILED 0x%x\n", status); + return status; + } + + /* Un_set ECC training mode */ + if ((DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask)) || + (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask))) { + /* Disable ECC Write MUX */ + CHECK_STATUS(ddr3_tip_if_write + (0, ACCESS_TYPE_UNICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x0, 0x100)); + /* General ECC and Bus3 ECC MUX remains enabled */ + } + + return MV_OK; +} + +int ddr3_hws_hw_training(void) +{ + enum hws_algo_type algo_mode = ALGO_TYPE_DYNAMIC; + int status; + struct init_cntr_param init_param; + + status = ddr3_silicon_pre_init(); + if (MV_OK != status) { + printf("DDR3 Pre silicon Config - FAILED 0x%x\n", status); + return status; + } + + init_param.do_mrs_phy = 1; +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X) + init_param.is_ctrl64_bit = 0; +#else + init_param.is_ctrl64_bit = 1; +#endif +#if defined(CONFIG_ALLEYCAT3) || defined(CONFIG_ARMADA_38X) || \ + defined(CONFIG_ARMADA_39X) + init_param.init_phy = 1; +#else + init_param.init_phy = 0; +#endif + init_param.msys_init = 1; + status = hws_ddr3_tip_init_controller(0, &init_param); + if (MV_OK != status) { + printf("DDR3 init controller - FAILED 0x%x\n", status); + return status; + } + + status = ddr3_silicon_post_init(); + if (MV_OK != status) { + printf("DDR3 Post Init - FAILED 0x%x\n", status); + return status; + } + + status = ddr3_pre_algo_config(); + if (MV_OK != status) { + printf("DDR3 Pre Algo Config - FAILED 0x%x\n", status); + return status; + } + + /* run algorithm in order to configure the PHY */ + status = hws_ddr3_tip_run_alg(0, algo_mode); + if (MV_OK != status) { + printf("DDR3 run algorithm - FAILED 0x%x\n", status); + return status; + } + + status = ddr3_post_algo_config(); + if (MV_OK != status) { + printf("DDR3 Post Algo Config - FAILED 0x%x\n", status); + return status; + } + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h new file mode 100644 index 0000000..17a0953 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_HWS_HW_TRAINING_H +#define _DDR3_HWS_HW_TRAINING_H + +/* struct used for DLB configuration array */ +struct dlb_config { + u32 reg_addr; + u32 reg_data; +}; + +/* Topology update structure */ +struct topology_update_info { + int update_ecc; + u8 ecc; + int update_width; + u8 width; + int update_ecc_pup3_mode; + u8 ecc_pup_mode_offset; +}; + +/* Topology update defines */ +#define TOPOLOGY_UPDATE_WIDTH_16BIT 1 +#define TOPOLOGY_UPDATE_WIDTH_32BIT 0 +#define TOPOLOGY_UPDATE_WIDTH_32BIT_MASK 0xf +#define TOPOLOGY_UPDATE_WIDTH_16BIT_MASK 0x3 + +#define TOPOLOGY_UPDATE_ECC_ON 1 +#define TOPOLOGY_UPDATE_ECC_OFF 0 +#define TOPOLOGY_UPDATE_ECC_OFFSET_PUP4 4 +#define TOPOLOGY_UPDATE_ECC_OFFSET_PUP3 3 + +/* + * 1. L2 filter should be set at binary header to 0xd000000, + * to avoid conflict with internal register IO. + * 2. U-Boot modifies internal registers base to 0xf100000, + * and than should update L2 filter accordingly to 0xf000000 (3.75 GB) + */ +/* temporary limit l2 filter to 3GiB (LSP issue) */ +#define L2_FILTER_FOR_MAX_MEMORY_SIZE 0xc0000000 +#define ADDRESS_FILTERING_END_REGISTER 0x8c04 + +#define SUB_VERSION 0 + +#endif /* _DDR3_HWS_HW_TRAINING_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h new file mode 100644 index 0000000..02d8c61 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h @@ -0,0 +1,472 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_HWS_HW_TRAINING_DEF_H +#define _DDR3_HWS_HW_TRAINING_DEF_H + +#define SAR_DDR3_FREQ_MASK 0xfe00000 +#define SAR_CPU_FAB_GET(cpu, fab) (((cpu & 0x7) << 21) | \ + ((fab & 0xf) << 24)) + +#define MAX_CS 4 + +#define MIN_DIMM_ADDR 0x50 +#define FAR_END_DIMM_ADDR 0x50 +#define MAX_DIMM_ADDR 0x60 + +#define SDRAM_CS_SIZE 0xfffffff +#define SDRAM_CS_BASE 0x0 +#define SDRAM_DIMM_SIZE 0x80000000 + +#define CPU_CONFIGURATION_REG(id) (0x21800 + (id * 0x100)) +#define CPU_MRVL_ID_OFFSET 0x10 +#define SAR1_CPU_CORE_MASK 0x00000018 +#define SAR1_CPU_CORE_OFFSET 3 + +#define NEW_FABRIC_TWSI_ADDR 0x4e +#ifdef DB_784MP_GP +#define BUS_WIDTH_ECC_TWSI_ADDR 0x4e +#else +#define BUS_WIDTH_ECC_TWSI_ADDR 0x4f +#endif +#define MV_MAX_DDR3_STATIC_SIZE 50 +#define MV_DDR3_MODES_NUMBER 30 + +#define RESUME_RL_PATTERNS_ADDR 0xfe0000 +#define RESUME_RL_PATTERNS_SIZE 0x100 +#define RESUME_TRAINING_VALUES_ADDR (RESUME_RL_PATTERNS_ADDR + \ + RESUME_RL_PATTERNS_SIZE) +#define RESUME_TRAINING_VALUES_MAX 0xcd0 +#define BOOT_INFO_ADDR (RESUME_RL_PATTERNS_ADDR + 0x1000) +#define CHECKSUM_RESULT_ADDR (BOOT_INFO_ADDR + 0x1000) +#define NUM_OF_REGISTER_ADDR (CHECKSUM_RESULT_ADDR + 4) +#define SUSPEND_MAGIC_WORD 0xdeadb002 +#define REGISTER_LIST_END 0xffffffff + +/* MISC */ +#define INTER_REGS_BASE SOC_REGS_PHY_BASE + +/* DDR */ +#define REG_SDRAM_CONFIG_ADDR 0x1400 +#define REG_SDRAM_CONFIG_MASK 0x9fffffff +#define REG_SDRAM_CONFIG_RFRS_MASK 0x3fff +#define REG_SDRAM_CONFIG_WIDTH_OFFS 15 +#define REG_SDRAM_CONFIG_REGDIMM_OFFS 17 +#define REG_SDRAM_CONFIG_ECC_OFFS 18 +#define REG_SDRAM_CONFIG_IERR_OFFS 19 +#define REG_SDRAM_CONFIG_PUPRSTDIV_OFFS 28 +#define REG_SDRAM_CONFIG_RSTRD_OFFS 30 + +#define REG_SDRAM_PINS_MUX 0x19d4 + +#define REG_DUNIT_CTRL_LOW_ADDR 0x1404 +#define REG_DUNIT_CTRL_LOW_2T_OFFS 3 +#define REG_DUNIT_CTRL_LOW_2T_MASK 0x3 +#define REG_DUNIT_CTRL_LOW_DPDE_OFFS 14 + +#define REG_SDRAM_TIMING_LOW_ADDR 0x1408 +#define REG_SDRAM_TIMING_HIGH_ADDR 0x140c +#define REG_SDRAM_TIMING_H_R2R_OFFS 7 +#define REG_SDRAM_TIMING_H_R2R_MASK 0x3 +#define REG_SDRAM_TIMING_H_R2W_W2R_OFFS 9 +#define REG_SDRAM_TIMING_H_R2W_W2R_MASK 0x3 +#define REG_SDRAM_TIMING_H_W2W_OFFS 11 +#define REG_SDRAM_TIMING_H_W2W_MASK 0x1f +#define REG_SDRAM_TIMING_H_R2R_H_OFFS 19 +#define REG_SDRAM_TIMING_H_R2R_H_MASK 0x7 +#define REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS 22 +#define REG_SDRAM_TIMING_H_R2W_W2R_H_MASK 0x7 + +#define REG_SDRAM_ADDRESS_CTRL_ADDR 0x1410 +#define REG_SDRAM_ADDRESS_SIZE_OFFS 2 +#define REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS 18 +#define REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS 4 + +#define REG_SDRAM_OPEN_PAGES_ADDR 0x1414 +#define REG_SDRAM_OPERATION_CS_OFFS 8 + +#define REG_SDRAM_OPERATION_ADDR 0x1418 +#define REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS 24 +#define REG_SDRAM_OPERATION_CWA_DATA_OFFS 20 +#define REG_SDRAM_OPERATION_CWA_DATA_MASK 0xf +#define REG_SDRAM_OPERATION_CWA_RC_OFFS 16 +#define REG_SDRAM_OPERATION_CWA_RC_MASK 0xf +#define REG_SDRAM_OPERATION_CMD_MR0 0xf03 +#define REG_SDRAM_OPERATION_CMD_MR1 0xf04 +#define REG_SDRAM_OPERATION_CMD_MR2 0xf08 +#define REG_SDRAM_OPERATION_CMD_MR3 0xf09 +#define REG_SDRAM_OPERATION_CMD_RFRS 0xf02 +#define REG_SDRAM_OPERATION_CMD_CWA 0xf0e +#define REG_SDRAM_OPERATION_CMD_RFRS_DONE 0xf +#define REG_SDRAM_OPERATION_CMD_MASK 0xf +#define REG_SDRAM_OPERATION_CS_OFFS 8 + +#define REG_OUDDR3_TIMING_ADDR 0x142c + +#define REG_SDRAM_MODE_ADDR 0x141c + +#define REG_SDRAM_EXT_MODE_ADDR 0x1420 + +#define REG_DDR_CONT_HIGH_ADDR 0x1424 + +#define REG_ODT_TIME_LOW_ADDR 0x1428 +#define REG_ODT_ON_CTL_RD_OFFS 12 +#define REG_ODT_OFF_CTL_RD_OFFS 16 +#define REG_SDRAM_ERROR_ADDR 0x1454 +#define REG_SDRAM_AUTO_PWR_SAVE_ADDR 0x1474 +#define REG_ODT_TIME_HIGH_ADDR 0x147c + +#define REG_SDRAM_INIT_CTRL_ADDR 0x1480 +#define REG_SDRAM_INIT_CTRL_OFFS 0 +#define REG_SDRAM_INIT_CKE_ASSERT_OFFS 2 +#define REG_SDRAM_INIT_RESET_DEASSERT_OFFS 3 +#define REG_SDRAM_INIT_RESET_MASK_OFFS 1 + +#define REG_SDRAM_ODT_CTRL_LOW_ADDR 0x1494 + +#define REG_SDRAM_ODT_CTRL_HIGH_ADDR 0x1498 +#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK 0x0 +#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA 0x3 + +#define REG_DUNIT_ODT_CTRL_ADDR 0x149c +#define REG_DUNIT_ODT_CTRL_OVRD_OFFS 8 +#define REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS 9 + +#define REG_DRAM_FIFO_CTRL_ADDR 0x14a0 + +#define REG_DRAM_AXI_CTRL_ADDR 0x14a8 +#define REG_DRAM_AXI_CTRL_AXIDATABUSWIDTH_OFFS 0 + +#define REG_METAL_MASK_ADDR 0x14b0 +#define REG_METAL_MASK_MASK 0xdfffffff +#define REG_METAL_MASK_RETRY_OFFS 0 + +#define REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR 0x14c0 + +#define REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR 0x14c4 +#define REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR 0x14c8 +#define REG_DRAM_MAIN_PADS_CAL_ADDR 0x14cc + +#define REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR 0x17c8 + +#define REG_CS_SIZE_SCRATCH_ADDR 0x1504 +#define REG_DYNAMIC_POWER_SAVE_ADDR 0x1520 +#define REG_DDR_IO_ADDR 0x1524 +#define REG_DDR_IO_CLK_RATIO_OFFS 15 + +#define REG_DFS_ADDR 0x1528 +#define REG_DFS_DLLNEXTSTATE_OFFS 0 +#define REG_DFS_BLOCK_OFFS 1 +#define REG_DFS_SR_OFFS 2 +#define REG_DFS_ATSR_OFFS 3 +#define REG_DFS_RECONF_OFFS 4 +#define REG_DFS_CL_NEXT_STATE_OFFS 8 +#define REG_DFS_CL_NEXT_STATE_MASK 0xf +#define REG_DFS_CWL_NEXT_STATE_OFFS 12 +#define REG_DFS_CWL_NEXT_STATE_MASK 0x7 + +#define REG_READ_DATA_SAMPLE_DELAYS_ADDR 0x1538 +#define REG_READ_DATA_SAMPLE_DELAYS_MASK 0x1f +#define REG_READ_DATA_SAMPLE_DELAYS_OFFS 8 + +#define REG_READ_DATA_READY_DELAYS_ADDR 0x153c +#define REG_READ_DATA_READY_DELAYS_MASK 0x1f +#define REG_READ_DATA_READY_DELAYS_OFFS 8 + +#define START_BURST_IN_ADDR 1 + +#define REG_DRAM_TRAINING_SHADOW_ADDR 0x18488 +#define REG_DRAM_TRAINING_ADDR 0x15b0 +#define REG_DRAM_TRAINING_LOW_FREQ_OFFS 0 +#define REG_DRAM_TRAINING_PATTERNS_OFFS 4 +#define REG_DRAM_TRAINING_MED_FREQ_OFFS 2 +#define REG_DRAM_TRAINING_WL_OFFS 3 +#define REG_DRAM_TRAINING_RL_OFFS 6 +#define REG_DRAM_TRAINING_DQS_RX_OFFS 15 +#define REG_DRAM_TRAINING_DQS_TX_OFFS 16 +#define REG_DRAM_TRAINING_CS_OFFS 20 +#define REG_DRAM_TRAINING_RETEST_OFFS 24 +#define REG_DRAM_TRAINING_DFS_FREQ_OFFS 27 +#define REG_DRAM_TRAINING_DFS_REQ_OFFS 29 +#define REG_DRAM_TRAINING_ERROR_OFFS 30 +#define REG_DRAM_TRAINING_AUTO_OFFS 31 +#define REG_DRAM_TRAINING_RETEST_PAR 0x3 +#define REG_DRAM_TRAINING_RETEST_MASK 0xf8ffffff +#define REG_DRAM_TRAINING_CS_MASK 0xff0fffff +#define REG_DRAM_TRAINING_PATTERNS_MASK 0xff0f0000 + +#define REG_DRAM_TRAINING_1_ADDR 0x15b4 +#define REG_DRAM_TRAINING_1_TRNBPOINT_OFFS 16 + +#define REG_DRAM_TRAINING_2_ADDR 0x15b8 +#define REG_DRAM_TRAINING_2_OVERRUN_OFFS 17 +#define REG_DRAM_TRAINING_2_FIFO_RST_OFFS 4 +#define REG_DRAM_TRAINING_2_RL_MODE_OFFS 3 +#define REG_DRAM_TRAINING_2_WL_MODE_OFFS 2 +#define REG_DRAM_TRAINING_2_ECC_MUX_OFFS 1 +#define REG_DRAM_TRAINING_2_SW_OVRD_OFFS 0 + +#define REG_DRAM_TRAINING_PATTERN_BASE_ADDR 0x15bc +#define REG_DRAM_TRAINING_PATTERN_BASE_OFFS 3 + +#define REG_TRAINING_DEBUG_2_ADDR 0x15c4 +#define REG_TRAINING_DEBUG_2_OFFS 16 +#define REG_TRAINING_DEBUG_2_MASK 0x3 + +#define REG_TRAINING_DEBUG_3_ADDR 0x15c8 +#define REG_TRAINING_DEBUG_3_OFFS 3 +#define REG_TRAINING_DEBUG_3_MASK 0x7 + +#define MR_CS_ADDR_OFFS 4 + +#define REG_DDR3_MR0_ADDR 0x15d0 +#define REG_DDR3_MR0_CS_ADDR 0x1870 +#define REG_DDR3_MR0_CL_MASK 0x74 +#define REG_DDR3_MR0_CL_OFFS 2 +#define REG_DDR3_MR0_CL_HIGH_OFFS 3 +#define CL_MASK 0xf + +#define REG_DDR3_MR1_ADDR 0x15d4 +#define REG_DDR3_MR1_CS_ADDR 0x1874 +#define REG_DDR3_MR1_RTT_MASK 0xfffffdbb +#define REG_DDR3_MR1_DLL_ENA_OFFS 0 +#define REG_DDR3_MR1_RTT_DISABLED 0x0 +#define REG_DDR3_MR1_RTT_RZQ2 0x40 +#define REG_DDR3_MR1_RTT_RZQ4 0x2 +#define REG_DDR3_MR1_RTT_RZQ6 0x42 +#define REG_DDR3_MR1_RTT_RZQ8 0x202 +#define REG_DDR3_MR1_RTT_RZQ12 0x4 +/* WL-disabled, OB-enabled */ +#define REG_DDR3_MR1_OUTBUF_WL_MASK 0xffffef7f +/* Output Buffer Disabled */ +#define REG_DDR3_MR1_OUTBUF_DIS_OFFS 12 +#define REG_DDR3_MR1_WL_ENA_OFFS 7 +#define REG_DDR3_MR1_WL_ENA 0x80 /* WL Enabled */ +#define REG_DDR3_MR1_ODT_MASK 0xfffffdbb + +#define REG_DDR3_MR2_ADDR 0x15d8 +#define REG_DDR3_MR2_CS_ADDR 0x1878 +#define REG_DDR3_MR2_CWL_OFFS 3 +#define REG_DDR3_MR2_CWL_MASK 0x7 +#define REG_DDR3_MR2_ODT_MASK 0xfffff9ff +#define REG_DDR3_MR3_ADDR 0x15dc +#define REG_DDR3_MR3_CS_ADDR 0x187c + +#define REG_DDR3_RANK_CTRL_ADDR 0x15e0 +#define REG_DDR3_RANK_CTRL_CS_ENA_MASK 0xf +#define REG_DDR3_RANK_CTRL_MIRROR_OFFS 4 + +#define REG_ZQC_CONF_ADDR 0x15e4 + +#define REG_DRAM_PHY_CONFIG_ADDR 0x15ec +#define REG_DRAM_PHY_CONFIG_MASK 0x3fffffff + +#define REG_ODPG_CNTRL_ADDR 0x1600 +#define REG_ODPG_CNTRL_OFFS 21 + +#define REG_PHY_LOCK_MASK_ADDR 0x1670 +#define REG_PHY_LOCK_MASK_MASK 0xfffff000 + +#define REG_PHY_LOCK_STATUS_ADDR 0x1674 +#define REG_PHY_LOCK_STATUS_LOCK_OFFS 9 +#define REG_PHY_LOCK_STATUS_LOCK_MASK 0xfff +#define REG_PHY_LOCK_APLL_ADLL_STATUS_MASK 0x7ff + +#define REG_PHY_REGISTRY_FILE_ACCESS_ADDR 0x16a0 +#define REG_PHY_REGISTRY_FILE_ACCESS_OP_WR 0xc0000000 +#define REG_PHY_REGISTRY_FILE_ACCESS_OP_RD 0x80000000 +#define REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE 0x80000000 +#define REG_PHY_BC_OFFS 27 +#define REG_PHY_CNTRL_OFFS 26 +#define REG_PHY_CS_OFFS 16 +#define REG_PHY_DQS_REF_DLY_OFFS 10 +#define REG_PHY_PHASE_OFFS 8 +#define REG_PHY_PUP_OFFS 22 + +#define REG_TRAINING_WL_ADDR 0x16ac +#define REG_TRAINING_WL_CS_MASK 0xfffffffc +#define REG_TRAINING_WL_UPD_OFFS 2 +#define REG_TRAINING_WL_CS_DONE_OFFS 3 +#define REG_TRAINING_WL_RATIO_MASK 0xffffff0f +#define REG_TRAINING_WL_1TO1 0x50 +#define REG_TRAINING_WL_2TO1 0x10 +#define REG_TRAINING_WL_DELAYEXP_MASK 0x20000000 +#define REG_TRAINING_WL_RESULTS_MASK 0x000001ff +#define REG_TRAINING_WL_RESULTS_OFFS 20 + +#define REG_REGISTERED_DRAM_CTRL_ADDR 0x16d0 +#define REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS 15 +#define REG_REGISTERED_DRAM_CTRL_PARITY_MASK 0x3f + +/* DLB */ +#define REG_STATIC_DRAM_DLB_CONTROL 0x1700 +#define DLB_BUS_OPTIMIZATION_WEIGHTS_REG 0x1704 +#define DLB_AGING_REGISTER 0x1708 +#define DLB_EVICTION_CONTROL_REG 0x170c +#define DLB_EVICTION_TIMERS_REGISTER_REG 0x1710 +#define DLB_USER_COMMAND_REG 0x1714 +#define DLB_BUS_WEIGHTS_DIFF_CS 0x1770 +#define DLB_BUS_WEIGHTS_DIFF_BG 0x1774 +#define DLB_BUS_WEIGHTS_SAME_BG 0x1778 +#define DLB_BUS_WEIGHTS_RD_WR 0x177c +#define DLB_BUS_WEIGHTS_ATTR_SYS_PRIO 0x1780 +#define DLB_MAIN_QUEUE_MAP 0x1784 +#define DLB_LINE_SPLIT 0x1788 + +#define DLB_ENABLE 0x1 +#define DLB_WRITE_COALESING (0x1 << 2) +#define DLB_AXI_PREFETCH_EN (0x1 << 3) +#define DLB_MBUS_PREFETCH_EN (0x1 << 4) +#define PREFETCH_N_LN_SZ_TR (0x1 << 6) +#define DLB_INTERJECTION_ENABLE (0x1 << 3) + +/* CPU */ +#define REG_BOOTROM_ROUTINE_ADDR 0x182d0 +#define REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS 12 + +#define REG_DRAM_INIT_CTRL_STATUS_ADDR 0x18488 +#define REG_DRAM_INIT_CTRL_TRN_CLK_OFFS 16 +#define REG_CPU_DIV_CLK_CTRL_0_NEW_RATIO 0x000200ff +#define REG_DRAM_INIT_CTRL_STATUS_2_ADDR 0x1488 + +#define REG_CPU_DIV_CLK_CTRL_0_ADDR 0x18700 + +#define REG_CPU_DIV_CLK_CTRL_1_ADDR 0x18704 +#define REG_CPU_DIV_CLK_CTRL_2_ADDR 0x18708 + +#define REG_CPU_DIV_CLK_CTRL_3_ADDR 0x1870c +#define REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK 0xffffc0ff +#define REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS 8 + +#define REG_CPU_DIV_CLK_CTRL_4_ADDR 0x18710 + +#define REG_CPU_DIV_CLK_STATUS_0_ADDR 0x18718 +#define REG_CPU_DIV_CLK_ALL_STABLE_OFFS 8 + +#define REG_CPU_PLL_CTRL_0_ADDR 0x1871c +#define REG_CPU_PLL_STATUS_0_ADDR 0x18724 +#define REG_CORE_DIV_CLK_CTRL_ADDR 0x18740 +#define REG_CORE_DIV_CLK_STATUS_ADDR 0x18744 +#define REG_DDRPHY_APLL_CTRL_ADDR 0x18780 + +#define REG_DDRPHY_APLL_CTRL_2_ADDR 0x18784 +#define REG_SFABRIC_CLK_CTRL_ADDR 0x20858 +#define REG_SFABRIC_CLK_CTRL_SMPL_OFFS 8 + +/* DRAM Windows */ +#define REG_XBAR_WIN_19_CTRL_ADDR 0x200e8 +#define REG_XBAR_WIN_4_CTRL_ADDR 0x20040 +#define REG_XBAR_WIN_4_BASE_ADDR 0x20044 +#define REG_XBAR_WIN_4_REMAP_ADDR 0x20048 +#define REG_FASTPATH_WIN_0_CTRL_ADDR 0x20184 +#define REG_XBAR_WIN_7_REMAP_ADDR 0x20078 + +/* SRAM */ +#define REG_CDI_CONFIG_ADDR 0x20220 +#define REG_SRAM_WINDOW_0_ADDR 0x20240 +#define REG_SRAM_WINDOW_0_ENA_OFFS 0 +#define REG_SRAM_WINDOW_1_ADDR 0x20244 +#define REG_SRAM_L2_ENA_ADDR 0x8500 +#define REG_SRAM_CLEAN_BY_WAY_ADDR 0x87bc + +/* Timers */ +#define REG_TIMERS_CTRL_ADDR 0x20300 +#define REG_TIMERS_EVENTS_ADDR 0x20304 +#define REG_TIMER0_VALUE_ADDR 0x20314 +#define REG_TIMER1_VALUE_ADDR 0x2031c +#define REG_TIMER0_ENABLE_MASK 0x1 + +#define MV_BOARD_REFCLK_25MHZ 25000000 +#define CNTMR_RELOAD_REG(tmr) (REG_TIMERS_CTRL_ADDR + 0x10 + (tmr * 8)) +#define CNTMR_VAL_REG(tmr) (REG_TIMERS_CTRL_ADDR + 0x14 + (tmr * 8)) +#define CNTMR_CTRL_REG(tmr) (REG_TIMERS_CTRL_ADDR) +#define CTCR_ARM_TIMER_EN_OFFS(timer) (timer * 2) +#define CTCR_ARM_TIMER_EN_MASK(timer) (1 << CTCR_ARM_TIMER_EN_OFFS(timer)) +#define CTCR_ARM_TIMER_EN(timer) (1 << CTCR_ARM_TIMER_EN_OFFS(timer)) + +#define CTCR_ARM_TIMER_AUTO_OFFS(timer) (1 + (timer * 2)) +#define CTCR_ARM_TIMER_AUTO_MASK(timer) (1 << CTCR_ARM_TIMER_EN_OFFS(timer)) +#define CTCR_ARM_TIMER_AUTO_EN(timer) (1 << CTCR_ARM_TIMER_AUTO_OFFS(timer)) + +/* PMU */ +#define REG_PMU_I_F_CTRL_ADDR 0x1c090 +#define REG_PMU_DUNIT_BLK_OFFS 16 +#define REG_PMU_DUNIT_RFRS_OFFS 20 +#define REG_PMU_DUNIT_ACK_OFFS 24 + +/* MBUS */ +#define MBUS_UNITS_PRIORITY_CONTROL_REG (MBUS_REGS_OFFSET + 0x420) +#define FABRIC_UNITS_PRIORITY_CONTROL_REG (MBUS_REGS_OFFSET + 0x424) +#define MBUS_UNITS_PREFETCH_CONTROL_REG (MBUS_REGS_OFFSET + 0x428) +#define FABRIC_UNITS_PREFETCH_CONTROL_REG (MBUS_REGS_OFFSET + 0x42c) + +#define REG_PM_STAT_MASK_ADDR 0x2210c +#define REG_PM_STAT_MASK_CPU0_IDLE_MASK_OFFS 16 + +#define REG_PM_EVENT_STAT_MASK_ADDR 0x22120 +#define REG_PM_EVENT_STAT_MASK_DFS_DONE_OFFS 17 + +#define REG_PM_CTRL_CONFIG_ADDR 0x22104 +#define REG_PM_CTRL_CONFIG_DFS_REQ_OFFS 18 + +#define REG_FABRIC_LOCAL_IRQ_MASK_ADDR 0x218c4 +#define REG_FABRIC_LOCAL_IRQ_PMU_MASK_OFFS 18 + +/* Controller revision info */ +#define PCI_CLASS_CODE_AND_REVISION_ID 0x008 +#define PCCRIR_REVID_OFFS 0 /* Revision ID */ +#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS) + +/* Power Management Clock Gating Control Register */ +#define MV_PEX_IF_REGS_OFFSET(pex_if) \ + (pex_if < 8 ? (0x40000 + ((pex_if) / 4) * 0x40000 + \ + ((pex_if) % 4) * 0x4000) : \ + (0x42000 + ((pex_if) % 8) * 0x40000)) +#define 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) (PEX_IF_REGS_BASE(if) + (reg)) +#define PMC_PEXSTOPCLOCK_OFFS(p) ((p) < 8 ? (5 + (p)) : (18 + (p))) +#define PMC_PEXSTOPCLOCK_MASK(p) (1 << PMC_PEXSTOPCLOCK_OFFS(p)) +#define PMC_PEXSTOPCLOCK_EN(p) (1 << PMC_PEXSTOPCLOCK_OFFS(p)) +#define PMC_PEXSTOPCLOCK_STOP(p) (0 << PMC_PEXSTOPCLOCK_OFFS(p)) + +/* TWSI */ +#define TWSI_DATA_ADDR_MASK 0x7 +#define TWSI_DATA_ADDR_OFFS 1 + +/* General */ +#define MAX_CS 4 + +/* Frequencies */ +#define FAB_OPT 21 +#define CLK_CPU 12 +#define CLK_VCO (2 * CLK_CPU) +#define CLK_DDR 12 + +/* CPU Frequencies: */ +#define CLK_CPU_1000 0 +#define CLK_CPU_1066 1 +#define CLK_CPU_1200 2 +#define CLK_CPU_1333 3 +#define CLK_CPU_1500 4 +#define CLK_CPU_1666 5 +#define CLK_CPU_1800 6 +#define CLK_CPU_2000 7 +#define CLK_CPU_600 8 +#define CLK_CPU_667 9 +#define CLK_CPU_800 0xa + +/* Extra Cpu Frequencies: */ +#define CLK_CPU_1600 11 +#define CLK_CPU_2133 12 +#define CLK_CPU_2200 13 +#define CLK_CPU_2400 14 + +#define SAR1_CPU_CORE_MASK 0x00000018 +#define SAR1_CPU_CORE_OFFSET 3 + +#endif /* _DDR3_HWS_HW_TRAINING_DEF_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h b/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h new file mode 100644 index 0000000..544237a --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_hws_sil_training.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_HWS_SIL_TRAINING_H +#define _DDR3_HWS_SIL_TRAINING_H + +#include "ddr3_training_ip.h" +#include "ddr3_training_ip_prv_if.h" + +int ddr3_silicon_pre_config(void); +int ddr3_silicon_init(void); +int ddr3_silicon_get_ddr_target_freq(u32 *ddr_freq); + +#endif /* _DDR3_HWS_SIL_TRAINING_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_init.c b/drivers/ddr/marvell/a38x/ddr3_init.c new file mode 100644 index 0000000..d6ed8e0 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_init.c @@ -0,0 +1,852 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#include "../../../../arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h" + +static struct dlb_config ddr3_dlb_config_table[] = { + {REG_STATIC_DRAM_DLB_CONTROL, 0x2000005c}, + {DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x00880000}, + {DLB_AGING_REGISTER, 0x0f7f007f}, + {DLB_EVICTION_CONTROL_REG, 0x0000129f}, + {DLB_EVICTION_TIMERS_REGISTER_REG, 0x00ff0000}, + {DLB_BUS_WEIGHTS_DIFF_CS, 0x04030802}, + {DLB_BUS_WEIGHTS_DIFF_BG, 0x00000a02}, + {DLB_BUS_WEIGHTS_SAME_BG, 0x09000a01}, + {DLB_BUS_WEIGHTS_RD_WR, 0x00020005}, + {DLB_BUS_WEIGHTS_ATTR_SYS_PRIO, 0x00060f10}, + {DLB_MAIN_QUEUE_MAP, 0x00000543}, + {DLB_LINE_SPLIT, 0x00000000}, + {DLB_USER_COMMAND_REG, 0x00000000}, + {0x0, 0x0} +}; + +static struct dlb_config ddr3_dlb_config_table_a0[] = { + {REG_STATIC_DRAM_DLB_CONTROL, 0x2000005c}, + {DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x00880000}, + {DLB_AGING_REGISTER, 0x0f7f007f}, + {DLB_EVICTION_CONTROL_REG, 0x0000129f}, + {DLB_EVICTION_TIMERS_REGISTER_REG, 0x00ff0000}, + {DLB_BUS_WEIGHTS_DIFF_CS, 0x04030802}, + {DLB_BUS_WEIGHTS_DIFF_BG, 0x00000a02}, + {DLB_BUS_WEIGHTS_SAME_BG, 0x09000a01}, + {DLB_BUS_WEIGHTS_RD_WR, 0x00020005}, + {DLB_BUS_WEIGHTS_ATTR_SYS_PRIO, 0x00060f10}, + {DLB_MAIN_QUEUE_MAP, 0x00000543}, + {DLB_LINE_SPLIT, 0x00000000}, + {DLB_USER_COMMAND_REG, 0x00000000}, + {0x0, 0x0} +}; + +#if defined(CONFIG_ARMADA_38X) +struct dram_modes { + char *mode_name; + u8 cpu_freq; + u8 fab_freq; + u8 chip_id; + u8 chip_board_rev; + struct reg_data *regs; +}; + +struct dram_modes ddr_modes[] = { +#ifdef SUPPORT_STATIC_DUNIT_CONFIG + /* Conf name, CPUFreq, Fab_freq, Chip ID, Chip/Board, MC regs*/ +#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT + {"a38x_customer_0_800", DDR_FREQ_800, 0, 0x0, A38X_CUSTOMER_BOARD_ID0, + ddr3_customer_800}, + {"a38x_customer_1_800", DDR_FREQ_800, 0, 0x0, A38X_CUSTOMER_BOARD_ID1, + ddr3_customer_800}, +#else + {"a38x_533", DDR_FREQ_533, 0, 0x0, MARVELL_BOARD, ddr3_a38x_533}, + {"a38x_667", DDR_FREQ_667, 0, 0x0, MARVELL_BOARD, ddr3_a38x_667}, + {"a38x_800", DDR_FREQ_800, 0, 0x0, MARVELL_BOARD, ddr3_a38x_800}, + {"a38x_933", DDR_FREQ_933, 0, 0x0, MARVELL_BOARD, ddr3_a38x_933}, +#endif +#endif +}; +#endif /* defined(CONFIG_ARMADA_38X) */ + +/* Translates topology map definitions to real memory size in bits */ +u32 mem_size[] = { + ADDR_SIZE_512MB, ADDR_SIZE_1GB, ADDR_SIZE_2GB, ADDR_SIZE_4GB, + ADDR_SIZE_8GB +}; + +static char *ddr_type = "DDR3"; + +/* + * Set 1 to use dynamic DUNIT configuration, + * set 0 (supported for A380 and AC3) to configure DUNIT in values set by + * ddr3_tip_init_specific_reg_config + */ +u8 generic_init_controller = 1; + +#ifdef SUPPORT_STATIC_DUNIT_CONFIG +static u32 ddr3_get_static_ddr_mode(void); +#endif +static int ddr3_hws_tune_training_params(u8 dev_num); +static int ddr3_update_topology_map(struct hws_topology_map *topology_map); + +/* device revision */ +#define DEV_VERSION_ID_REG 0x1823c +#define REVISON_ID_OFFS 8 +#define REVISON_ID_MASK 0xf00 + +/* A38x revisions */ +#define MV_88F68XX_Z1_ID 0x0 +#define MV_88F68XX_A0_ID 0x4 +/* A39x revisions */ +#define MV_88F69XX_Z1_ID 0x2 + +/* + * sys_env_device_rev_get - Get Marvell controller device revision number + * + * DESCRIPTION: + * This function returns 8bit describing the device revision as defined + * Revision ID Register. + * + * INPUT: + * None. + * + * OUTPUT: + * None. + * + * RETURN: + * 8bit desscribing Marvell controller revision number + */ +u8 sys_env_device_rev_get(void) +{ + u32 value; + + value = reg_read(DEV_VERSION_ID_REG); + return (value & (REVISON_ID_MASK)) >> REVISON_ID_OFFS; +} + +/* + * sys_env_dlb_config_ptr_get + * + * DESCRIPTION: defines pointer to to DLB COnfiguration table + * + * INPUT: none + * + * OUTPUT: pointer to DLB COnfiguration table + * + * RETURN: + * returns pointer to DLB COnfiguration table + */ +struct dlb_config *sys_env_dlb_config_ptr_get(void) +{ +#ifdef CONFIG_ARMADA_39X + return &ddr3_dlb_config_table_a0[0]; +#else + if (sys_env_device_rev_get() == MV_88F68XX_A0_ID) + return &ddr3_dlb_config_table_a0[0]; + else + return &ddr3_dlb_config_table[0]; +#endif +} + +/* + * sys_env_get_cs_ena_from_reg + * + * DESCRIPTION: Get bit mask of enabled CS + * + * INPUT: None + * + * OUTPUT: None + * + * RETURN: + * Bit mask of enabled CS, 1 if only CS0 enabled, + * 3 if both CS0 and CS1 enabled + */ +u32 sys_env_get_cs_ena_from_reg(void) +{ + return reg_read(REG_DDR3_RANK_CTRL_ADDR) & + REG_DDR3_RANK_CTRL_CS_ENA_MASK; +} + +static void ddr3_restore_and_set_final_windows(u32 *win) +{ + u32 win_ctrl_reg, num_of_win_regs; + u32 cs_ena = sys_env_get_cs_ena_from_reg(); + u32 ui; + + win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR; + num_of_win_regs = 16; + + /* Return XBAR windows 4-7 or 16-19 init configuration */ + for (ui = 0; ui < num_of_win_regs; ui++) + reg_write((win_ctrl_reg + 0x4 * ui), win[ui]); + + printf("%s Training Sequence - Switching XBAR Window to FastPath Window\n", + ddr_type); + +#if defined DYNAMIC_CS_SIZE_CONFIG + if (ddr3_fast_path_dynamic_cs_size_config(cs_ena) != MV_OK) + printf("ddr3_fast_path_dynamic_cs_size_config FAILED\n"); +#else + u32 reg, cs; + reg = 0x1fffffe1; + for (cs = 0; cs < MAX_CS; cs++) { + if (cs_ena & (1 << cs)) { + reg |= (cs << 2); + break; + } + } + /* Open fast path Window to - 0.5G */ + reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, reg); +#endif +} + +static int ddr3_save_and_set_training_windows(u32 *win) +{ + u32 cs_ena; + u32 reg, tmp_count, cs, ui; + u32 win_ctrl_reg, win_base_reg, win_remap_reg; + u32 num_of_win_regs, win_jump_index; + win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR; + win_base_reg = REG_XBAR_WIN_4_BASE_ADDR; + win_remap_reg = REG_XBAR_WIN_4_REMAP_ADDR; + win_jump_index = 0x10; + num_of_win_regs = 16; + struct hws_topology_map *tm = ddr3_get_topology_map(); + +#ifdef DISABLE_L2_FILTERING_DURING_DDR_TRAINING + /* + * Disable L2 filtering during DDR training + * (when Cross Bar window is open) + */ + reg_write(ADDRESS_FILTERING_END_REGISTER, 0); +#endif + + cs_ena = tm->interface_params[0].as_bus_params[0].cs_bitmask; + + /* Close XBAR Window 19 - Not needed */ + /* {0x000200e8} - Open Mbus Window - 2G */ + reg_write(REG_XBAR_WIN_19_CTRL_ADDR, 0); + + /* Save XBAR Windows 4-19 init configurations */ + for (ui = 0; ui < num_of_win_regs; ui++) + win[ui] = reg_read(win_ctrl_reg + 0x4 * ui); + + /* Open XBAR Windows 4-7 or 16-19 for other CS */ + reg = 0; + tmp_count = 0; + for (cs = 0; cs < MAX_CS; cs++) { + if (cs_ena & (1 << cs)) { + switch (cs) { + case 0: + reg = 0x0e00; + break; + case 1: + reg = 0x0d00; + break; + case 2: + reg = 0x0b00; + break; + case 3: + reg = 0x0700; + break; + } + reg |= (1 << 0); + reg |= (SDRAM_CS_SIZE & 0xffff0000); + + reg_write(win_ctrl_reg + win_jump_index * tmp_count, + reg); + reg = (((SDRAM_CS_SIZE + 1) * (tmp_count)) & + 0xffff0000); + reg_write(win_base_reg + win_jump_index * tmp_count, + reg); + + if (win_remap_reg <= REG_XBAR_WIN_7_REMAP_ADDR) + reg_write(win_remap_reg + + win_jump_index * tmp_count, 0); + + tmp_count++; + } + } + + return MV_OK; +} + +/* + * Name: ddr3_init - Main DDR3 Init function + * Desc: This routine initialize the DDR3 MC and runs HW training. + * Args: None. + * Notes: + * Returns: None. + */ +int ddr3_init(void) +{ + u32 reg = 0; + u32 soc_num; + int status; + u32 win[16]; + + /* SoC/Board special Initializtions */ + /* Get version from internal library */ + ddr3_print_version(); + + /*Add sub_version string */ + DEBUG_INIT_C("", SUB_VERSION, 1); + + /* Switching CPU to MRVL ID */ + soc_num = (reg_read(REG_SAMPLE_RESET_HIGH_ADDR) & SAR1_CPU_CORE_MASK) >> + SAR1_CPU_CORE_OFFSET; + switch (soc_num) { + case 0x3: + reg_bit_set(CPU_CONFIGURATION_REG(3), CPU_MRVL_ID_OFFSET); + reg_bit_set(CPU_CONFIGURATION_REG(2), CPU_MRVL_ID_OFFSET); + case 0x1: + reg_bit_set(CPU_CONFIGURATION_REG(1), CPU_MRVL_ID_OFFSET); + case 0x0: + reg_bit_set(CPU_CONFIGURATION_REG(0), CPU_MRVL_ID_OFFSET); + default: + break; + } + + /* + * Set DRAM Reset Mask in case detected GPIO indication of wakeup from + * suspend i.e the DRAM values will not be overwritten / reset when + * waking from suspend + */ + if (sys_env_suspend_wakeup_check() == + SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED) { + reg_bit_set(REG_SDRAM_INIT_CTRL_ADDR, + 1 << REG_SDRAM_INIT_RESET_MASK_OFFS); + } + + /* + * Stage 0 - Set board configuration + */ + + /* Check if DRAM is already initialized */ + if (reg_read(REG_BOOTROM_ROUTINE_ADDR) & + (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) { + printf("%s Training Sequence - 2nd boot - Skip\n", ddr_type); + return MV_OK; + } + + /* + * Stage 1 - Dunit Setup + */ + + /* Fix read ready phases for all SOC in reg 0x15c8 */ + reg = reg_read(REG_TRAINING_DEBUG_3_ADDR); + reg &= ~(REG_TRAINING_DEBUG_3_MASK); + reg |= 0x4; /* Phase 0 */ + reg &= ~(REG_TRAINING_DEBUG_3_MASK << REG_TRAINING_DEBUG_3_OFFS); + reg |= (0x4 << (1 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 1 */ + reg &= ~(REG_TRAINING_DEBUG_3_MASK << (3 * REG_TRAINING_DEBUG_3_OFFS)); + reg |= (0x6 << (3 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 3 */ + reg &= ~(REG_TRAINING_DEBUG_3_MASK << (4 * REG_TRAINING_DEBUG_3_OFFS)); + reg |= (0x6 << (4 * REG_TRAINING_DEBUG_3_OFFS)); + reg &= ~(REG_TRAINING_DEBUG_3_MASK << (5 * REG_TRAINING_DEBUG_3_OFFS)); + reg |= (0x6 << (5 * REG_TRAINING_DEBUG_3_OFFS)); + reg_write(REG_TRAINING_DEBUG_3_ADDR, reg); + + /* + * Axi_bresp_mode[8] = Compliant, + * Axi_addr_decode_cntrl[11] = Internal, + * Axi_data_bus_width[0] = 128bit + * */ + /* 0x14a8 - AXI Control Register */ + reg_write(REG_DRAM_AXI_CTRL_ADDR, 0); + + /* + * Stage 2 - Training Values Setup + */ + /* Set X-BAR windows for the training sequence */ + ddr3_save_and_set_training_windows(win); + +#ifdef SUPPORT_STATIC_DUNIT_CONFIG + /* + * Load static controller configuration (in case dynamic/generic init + * is not enabled + */ + if (generic_init_controller == 0) { + ddr3_tip_init_specific_reg_config(0, + ddr_modes + [ddr3_get_static_ddr_mode + ()].regs); + } +#endif + + /* Load topology for New Training IP */ + status = ddr3_load_topology_map(); + if (MV_OK != status) { + printf("%s Training Sequence topology load - FAILED\n", + ddr_type); + return status; + } + + /* Tune training algo paramteres */ + status = ddr3_hws_tune_training_params(0); + if (MV_OK != status) + return status; + + /* Set log level for training lib */ + ddr3_hws_set_log_level(DEBUG_BLOCK_ALL, DEBUG_LEVEL_ERROR); + + /* Start New Training IP */ + status = ddr3_hws_hw_training(); + if (MV_OK != status) { + printf("%s Training Sequence - FAILED\n", ddr_type); + return status; + } + + /* + * Stage 3 - Finish + */ + /* Restore and set windows */ + ddr3_restore_and_set_final_windows(win); + + /* Update DRAM init indication in bootROM register */ + reg = reg_read(REG_BOOTROM_ROUTINE_ADDR); + reg_write(REG_BOOTROM_ROUTINE_ADDR, + reg | (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)); + + /* DLB config */ + ddr3_new_tip_dlb_config(); + +#if defined(ECC_SUPPORT) + if (ddr3_if_ecc_enabled()) + ddr3_new_tip_ecc_scrub(); +#endif + + printf("%s Training Sequence - Ended Successfully\n", ddr_type); + + return MV_OK; +} + +/* + * Name: ddr3_get_cpu_freq + * Desc: read S@R and return CPU frequency + * Args: + * Notes: + * Returns: required value + */ +u32 ddr3_get_cpu_freq(void) +{ + return ddr3_tip_get_init_freq(); +} + +/* + * Name: ddr3_get_fab_opt + * Desc: read S@R and return CPU frequency + * Args: + * Notes: + * Returns: required value + */ +u32 ddr3_get_fab_opt(void) +{ + return 0; /* No fabric */ +} + +/* + * Name: ddr3_get_static_m_cValue - Init Memory controller with + * static parameters + * Desc: Use this routine to init the controller without the HW training + * procedure. + * User must provide compatible header file with registers data. + * Args: None. + * Notes: + * Returns: None. + */ +u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1, + u32 offset2, u32 mask2) +{ + u32 reg, temp; + + reg = reg_read(reg_addr); + + temp = (reg >> offset1) & mask1; + if (mask2) + temp |= (reg >> offset2) & mask2; + + return temp; +} + +/* + * Name: ddr3_get_static_ddr_mode - Init Memory controller with + * static parameters + * Desc: Use this routine to init the controller without the HW training + * procedure. + * User must provide compatible header file with registers data. + * Args: None. + * Notes: + * Returns: None. + */ +u32 ddr3_get_static_ddr_mode(void) +{ + u32 chip_board_rev, i; + u32 size; + + /* Valid only for A380 only, MSYS using dynamic controller config */ +#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT + /* + * Customer boards select DDR mode according to + * board ID & Sample@Reset + */ + chip_board_rev = mv_board_id_get(); +#else + /* Marvell boards select DDR mode according to Sample@Reset only */ + chip_board_rev = MARVELL_BOARD; +#endif + + size = ARRAY_SIZE(ddr_modes); + for (i = 0; i < size; i++) { + if ((ddr3_get_cpu_freq() == ddr_modes[i].cpu_freq) && + (ddr3_get_fab_opt() == ddr_modes[i].fab_freq) && + (chip_board_rev == ddr_modes[i].chip_board_rev)) + return i; + } + + DEBUG_INIT_S("\n*** Error: ddr3_get_static_ddr_mode: No match for requested DDR mode. ***\n\n"); + + return 0; +} + +/****************************************************************************** + * Name: ddr3_get_cs_num_from_reg + * Desc: + * Args: + * Notes: + * Returns: + */ +u32 ddr3_get_cs_num_from_reg(void) +{ + u32 cs_ena = sys_env_get_cs_ena_from_reg(); + u32 cs_count = 0; + u32 cs; + + for (cs = 0; cs < MAX_CS; cs++) { + if (cs_ena & (1 << cs)) + cs_count++; + } + + return cs_count; +} + +/* + * Name: ddr3_load_topology_map + * Desc: + * Args: + * Notes: + * Returns: + */ +int ddr3_load_topology_map(void) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + +#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI) + /* Update topology data */ + if (MV_OK != ddr3_update_topology_map(tm)) { + DEBUG_INIT_FULL_S("Failed update of DDR3 Topology map\n"); + } +#endif + + return MV_OK; +} + +void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps) +{ + u32 tmp, hclk = 200; + + switch (freq_mode) { + case 4: + tmp = 1; /* DDR_400; */ + hclk = 200; + break; + case 0x8: + tmp = 1; /* DDR_666; */ + hclk = 333; + break; + case 0xc: + tmp = 1; /* DDR_800; */ + hclk = 400; + break; + default: + *ddr_freq = 0; + *hclk_ps = 0; + break; + } + + *ddr_freq = tmp; /* DDR freq define */ + *hclk_ps = 1000000 / hclk; /* values are 1/HCLK in ps */ + + return; +} + +void ddr3_new_tip_dlb_config(void) +{ + u32 reg, i = 0; + struct dlb_config *config_table_ptr = sys_env_dlb_config_ptr_get(); + + /* Write the configuration */ + while (config_table_ptr[i].reg_addr != 0) { + reg_write(config_table_ptr[i].reg_addr, + config_table_ptr[i].reg_data); + i++; + } + + /* Enable DLB */ + reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL); + reg |= DLB_ENABLE | DLB_WRITE_COALESING | DLB_AXI_PREFETCH_EN | + DLB_MBUS_PREFETCH_EN | PREFETCH_N_LN_SZ_TR; + reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg); +} + +int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena) +{ + u32 reg, cs; + u32 mem_total_size = 0; + u32 cs_mem_size = 0; + u32 mem_total_size_c, cs_mem_size_c; + +#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE + u32 physical_mem_size; + u32 max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE; + struct hws_topology_map *tm = ddr3_get_topology_map(); +#endif + + /* Open fast path windows */ + for (cs = 0; cs < MAX_CS; cs++) { + if (cs_ena & (1 << cs)) { + /* get CS size */ + if (ddr3_calc_mem_cs_size(cs, &cs_mem_size) != MV_OK) + return MV_FAIL; + +#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE + /* + * if number of address pins doesn't allow to use max + * mem size that is defined in topology + * mem size is defined by DEVICE_MAX_DRAM_ADDRESS_SIZE + */ + physical_mem_size = mem_size + [tm->interface_params[0].memory_size]; + + if (ddr3_get_device_width(cs) == 16) { + /* + * 16bit mem device can be twice more - no need + * in less significant pin + */ + max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE * 2; + } + + if (physical_mem_size > max_mem_size) { + cs_mem_size = max_mem_size * + (ddr3_get_bus_width() / + ddr3_get_device_width(cs)); + printf("Updated Physical Mem size is from 0x%x to %x\n", + physical_mem_size, + DEVICE_MAX_DRAM_ADDRESS_SIZE); + } +#endif + + /* set fast path window control for the cs */ + reg = 0xffffe1; + reg |= (cs << 2); + reg |= (cs_mem_size - 1) & 0xffff0000; + /*Open fast path Window */ + reg_write(REG_FASTPATH_WIN_CTRL_ADDR(cs), reg); + + /* Set fast path window base address for the cs */ + reg = ((cs_mem_size) * cs) & 0xffff0000; + /* Set base address */ + reg_write(REG_FASTPATH_WIN_BASE_ADDR(cs), reg); + + /* + * Since memory size may be bigger than 4G the summ may + * be more than 32 bit word, + * so to estimate the result divide mem_total_size and + * cs_mem_size by 0x10000 (it is equal to >> 16) + */ + mem_total_size_c = mem_total_size >> 16; + cs_mem_size_c = cs_mem_size >> 16; + /* if the sum less than 2 G - calculate the value */ + if (mem_total_size_c + cs_mem_size_c < 0x10000) + mem_total_size += cs_mem_size; + else /* put max possible size */ + mem_total_size = L2_FILTER_FOR_MAX_MEMORY_SIZE; + } + } + + /* Set L2 filtering to Max Memory size */ + reg_write(ADDRESS_FILTERING_END_REGISTER, mem_total_size); + + return MV_OK; +} + +u32 ddr3_get_bus_width(void) +{ + u32 bus_width; + + bus_width = (reg_read(REG_SDRAM_CONFIG_ADDR) & 0x8000) >> + REG_SDRAM_CONFIG_WIDTH_OFFS; + + return (bus_width == 0) ? 16 : 32; +} + +u32 ddr3_get_device_width(u32 cs) +{ + u32 device_width; + + device_width = (reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR) & + (0x3 << (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs))) >> + (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs); + + return (device_width == 0) ? 8 : 16; +} + +float ddr3_get_device_size(u32 cs) +{ + u32 device_size_low, device_size_high, device_size; + u32 data, cs_low_offset, cs_high_offset; + + cs_low_offset = REG_SDRAM_ADDRESS_SIZE_OFFS + cs * 4; + cs_high_offset = REG_SDRAM_ADDRESS_SIZE_OFFS + + REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS + cs; + + data = reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR); + device_size_low = (data >> cs_low_offset) & 0x3; + device_size_high = (data >> cs_high_offset) & 0x1; + + device_size = device_size_low | (device_size_high << 2); + + switch (device_size) { + case 0: + return 2; + case 2: + return 0.5; + case 3: + return 1; + case 4: + return 4; + case 5: + return 8; + case 1: + default: + DEBUG_INIT_C("Error: Wrong device size of Cs: ", cs, 1); + /* + * Small value will give wrong emem size in + * ddr3_calc_mem_cs_size + */ + return 0.01; + } +} + +int ddr3_calc_mem_cs_size(u32 cs, u32 *cs_size) +{ + float cs_mem_size; + + /* Calculate in GiB */ + cs_mem_size = ((ddr3_get_bus_width() / ddr3_get_device_width(cs)) * + ddr3_get_device_size(cs)) / 8; + + /* + * Multiple controller bus width, 2x for 64 bit + * (SoC controller may be 32 or 64 bit, + * so bit 15 in 0x1400, that means if whole bus used or only half, + * have a differnt meaning + */ + cs_mem_size *= DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER; + + if (cs_mem_size == 0.125) { + *cs_size = 128 << 20; + } else if (cs_mem_size == 0.25) { + *cs_size = 256 << 20; + } else if (cs_mem_size == 0.5) { + *cs_size = 512 << 20; + } else if (cs_mem_size == 1) { + *cs_size = 1 << 30; + } else if (cs_mem_size == 2) { + *cs_size = 2 << 30; + } else { + DEBUG_INIT_C("Error: Wrong Memory size of Cs: ", cs, 1); + return MV_BAD_VALUE; + } + + return MV_OK; +} + +#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI) +/* + * Name: ddr3_update_topology_map + * Desc: + * Args: + * Notes: Update topology map by Sat_r values + * Returns: + */ +static int ddr3_update_topology_map(struct hws_topology_map *tm) +{ + struct topology_update_info topology_update_info; + + topology_update_info.update_width = 0; + topology_update_info.update_ecc = 0; + topology_update_info.update_ecc_pup3_mode = 0; + sys_env_get_topology_update_info(&topology_update_info); + if (topology_update_info.update_width) { + tm->bus_act_mask &= + ~(TOPOLOGY_UPDATE_WIDTH_32BIT_MASK); + if (topology_update_info.width == TOPOLOGY_UPDATE_WIDTH_16BIT) + tm->bus_act_mask = + TOPOLOGY_UPDATE_WIDTH_16BIT_MASK; + else + tm->bus_act_mask = + TOPOLOGY_UPDATE_WIDTH_32BIT_MASK; + } + + if (topology_update_info.update_ecc) { + if (topology_update_info.ecc == TOPOLOGY_UPDATE_ECC_OFF) { + tm->bus_act_mask &= + ~(1 << topology_update_info.ecc_pup_mode_offset); + } else { + tm->bus_act_mask |= + topology_update_info. + ecc << topology_update_info.ecc_pup_mode_offset; + } + } + + return MV_OK; +} +#endif + +/* + * Name: ddr3_hws_tune_training_params + * Desc: + * Args: + * Notes: Tune internal training params + * Returns: + */ +static int ddr3_hws_tune_training_params(u8 dev_num) +{ + struct tune_train_params params; + int status; + + /* NOTE: do not remove any field initilization */ + params.ck_delay = TUNE_TRAINING_PARAMS_CK_DELAY; + params.ck_delay_16 = TUNE_TRAINING_PARAMS_CK_DELAY_16; + params.p_finger = TUNE_TRAINING_PARAMS_PFINGER; + params.n_finger = TUNE_TRAINING_PARAMS_NFINGER; + params.phy_reg3_val = TUNE_TRAINING_PARAMS_PHYREG3VAL; + + status = ddr3_tip_tune_training_params(dev_num, ¶ms); + if (MV_OK != status) { + printf("%s Training Sequence - FAILED\n", ddr_type); + return status; + } + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_init.h b/drivers/ddr/marvell/a38x/ddr3_init.h new file mode 100644 index 0000000..e2ff040 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_init.h @@ -0,0 +1,395 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_INIT_H +#define _DDR3_INIT_H + +#if defined(CONFIG_ARMADA_38X) +#include "ddr3_a38x.h" +#include "ddr3_a38x_mc_static.h" +#include "ddr3_a38x_topology.h" +#endif +#include "ddr3_hws_hw_training.h" +#include "ddr3_hws_sil_training.h" +#include "ddr3_logging_def.h" +#include "ddr3_training_hw_algo.h" +#include "ddr3_training_ip.h" +#include "ddr3_training_ip_centralization.h" +#include "ddr3_training_ip_engine.h" +#include "ddr3_training_ip_flow.h" +#include "ddr3_training_ip_pbs.h" +#include "ddr3_training_ip_prv_if.h" +#include "ddr3_training_ip_static.h" +#include "ddr3_training_leveling.h" +#include "xor.h" + +/* + * MV_DEBUG_INIT need to be defines, otherwise the output of the + * DDR2 training code is not complete and misleading + */ +#define MV_DEBUG_INIT + +#define BIT(x) (1 << (x)) + +#ifdef MV_DEBUG_INIT +#define DEBUG_INIT_S(s) puts(s) +#define DEBUG_INIT_D(d, l) printf("%x", d) +#define DEBUG_INIT_D_10(d, l) printf("%d", d) +#else +#define DEBUG_INIT_S(s) +#define DEBUG_INIT_D(d, l) +#define DEBUG_INIT_D_10(d, l) +#endif + +#ifdef MV_DEBUG_INIT_FULL +#define DEBUG_INIT_FULL_S(s) puts(s) +#define DEBUG_INIT_FULL_D(d, l) printf("%x", d) +#define DEBUG_INIT_FULL_D_10(d, l) printf("%d", d) +#define DEBUG_WR_REG(reg, val) \ + { DEBUG_INIT_S("Write Reg: 0x"); DEBUG_INIT_D((reg), 8); \ + DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); } +#define DEBUG_RD_REG(reg, val) \ + { DEBUG_INIT_S("Read Reg: 0x"); DEBUG_INIT_D((reg), 8); \ + DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); } +#else +#define DEBUG_INIT_FULL_S(s) +#define DEBUG_INIT_FULL_D(d, l) +#define DEBUG_INIT_FULL_D_10(d, l) +#define DEBUG_WR_REG(reg, val) +#define DEBUG_RD_REG(reg, val) +#endif + +#define DEBUG_INIT_FULL_C(s, d, l) \ + { DEBUG_INIT_FULL_S(s); \ + DEBUG_INIT_FULL_D(d, l); \ + DEBUG_INIT_FULL_S("\n"); } +#define DEBUG_INIT_C(s, d, l) \ + { DEBUG_INIT_S(s); DEBUG_INIT_D(d, l); DEBUG_INIT_S("\n"); } + +/* + * Debug (Enable/Disable modules) and Error report + */ + +#ifdef BASIC_DEBUG +#define MV_DEBUG_WL +#define MV_DEBUG_RL +#define MV_DEBUG_DQS_RESULTS +#endif + +#ifdef FULL_DEBUG +#define MV_DEBUG_WL +#define MV_DEBUG_RL +#define MV_DEBUG_DQS + +#define MV_DEBUG_PBS +#define MV_DEBUG_DFS +#define MV_DEBUG_MAIN_FULL +#define MV_DEBUG_DFS_FULL +#define MV_DEBUG_DQS_FULL +#define MV_DEBUG_RL_FULL +#define MV_DEBUG_WL_FULL +#endif + +#if defined(CONFIG_ARMADA_38X) +#include "ddr3_a38x.h" +#include "ddr3_a38x_topology.h" +#endif + +/* The following is a list of Marvell status */ +#define MV_ERROR (-1) +#define MV_OK (0x00) /* Operation succeeded */ +#define MV_FAIL (0x01) /* Operation failed */ +#define MV_BAD_VALUE (0x02) /* Illegal value (general) */ +#define MV_OUT_OF_RANGE (0x03) /* The value is out of range */ +#define MV_BAD_PARAM (0x04) /* Illegal parameter in function called */ +#define MV_BAD_PTR (0x05) /* Illegal pointer value */ +#define MV_BAD_SIZE (0x06) /* Illegal size */ +#define MV_BAD_STATE (0x07) /* Illegal state of state machine */ +#define MV_SET_ERROR (0x08) /* Set operation failed */ +#define MV_GET_ERROR (0x09) /* Get operation failed */ +#define MV_CREATE_ERROR (0x0a) /* Fail while creating an item */ +#define MV_NOT_FOUND (0x0b) /* Item not found */ +#define MV_NO_MORE (0x0c) /* No more items found */ +#define MV_NO_SUCH (0x0d) /* No such item */ +#define MV_TIMEOUT (0x0e) /* Time Out */ +#define MV_NO_CHANGE (0x0f) /* Parameter(s) is already in this value */ +#define MV_NOT_SUPPORTED (0x10) /* This request is not support */ +#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented*/ +#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized */ +#define MV_NO_RESOURCE (0x13) /* Resource not available (memory ...) */ +#define MV_FULL (0x14) /* Item is full (Queue or table etc...) */ +#define MV_EMPTY (0x15) /* Item is empty (Queue or table etc...) */ +#define MV_INIT_ERROR (0x16) /* Error occured while INIT process */ +#define MV_HW_ERROR (0x17) /* Hardware error */ +#define MV_TX_ERROR (0x18) /* Transmit operation not succeeded */ +#define MV_RX_ERROR (0x19) /* Recieve operation not succeeded */ +#define MV_NOT_READY (0x1a) /* The other side is not ready yet */ +#define MV_ALREADY_EXIST (0x1b) /* Tried to create existing item */ +#define MV_OUT_OF_CPU_MEM (0x1c) /* Cpu memory allocation failed. */ +#define MV_NOT_STARTED (0x1d) /* Not started yet */ +#define MV_BUSY (0x1e) /* Item is busy. */ +#define MV_TERMINATE (0x1f) /* Item terminates it's work. */ +#define MV_NOT_ALIGNED (0x20) /* Wrong alignment */ +#define MV_NOT_ALLOWED (0x21) /* Operation NOT allowed */ +#define MV_WRITE_PROTECT (0x22) /* Write protected */ +#define MV_INVALID (int)(-1) + +/* For checking function return values */ +#define CHECK_STATUS(orig_func) \ + { \ + int status; \ + status = orig_func; \ + if (MV_OK != status) \ + return status; \ + } + +enum log_level { + MV_LOG_LEVEL_0, + MV_LOG_LEVEL_1, + MV_LOG_LEVEL_2, + MV_LOG_LEVEL_3 +}; + +/* Globals */ +extern u8 debug_training; +extern u8 is_reg_dump; +extern u8 generic_init_controller; +extern u32 freq_val[]; +extern u32 is_pll_old; +extern struct cl_val_per_freq cas_latency_table[]; +extern struct pattern_info pattern_table[]; +extern struct cl_val_per_freq cas_write_latency_table[]; +extern u8 debug_training; +extern u8 debug_centralization, debug_training_ip, debug_training_bist, + debug_pbs, debug_training_static, debug_leveling; +extern u32 pipe_multicast_mask; +extern struct hws_tip_config_func_db config_func_info[]; +extern u8 cs_mask_reg[]; +extern u8 twr_mask_table[]; +extern u8 cl_mask_table[]; +extern u8 cwl_mask_table[]; +extern u16 rfc_table[]; +extern u32 speed_bin_table_t_rc[]; +extern u32 speed_bin_table_t_rcd_t_rp[]; +extern u32 ck_delay, ck_delay_16; + +extern u32 g_zpri_data; +extern u32 g_znri_data; +extern u32 g_zpri_ctrl; +extern u32 g_znri_ctrl; +extern u32 g_zpodt_data; +extern u32 g_znodt_data; +extern u32 g_zpodt_ctrl; +extern u32 g_znodt_ctrl; +extern u32 g_dic; +extern u32 g_odt_config; +extern u32 g_rtt_nom; + +extern u8 debug_training_access; +extern u8 debug_training_a38x; +extern u32 first_active_if; +extern enum hws_ddr_freq init_freq; +extern u32 delay_enable, ck_delay, ck_delay_16, ca_delay; +extern u32 mask_tune_func; +extern u32 rl_version; +extern int rl_mid_freq_wa; +extern u8 calibration_update_control; /* 2 external only, 1 is internal only */ +extern enum hws_ddr_freq medium_freq; + +extern u32 ck_delay, ck_delay_16; +extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]; +extern u32 first_active_if; +extern u32 mask_tune_func; +extern u32 freq_val[]; +extern enum hws_ddr_freq init_freq; +extern enum hws_ddr_freq low_freq; +extern enum hws_ddr_freq medium_freq; +extern u8 generic_init_controller; +extern enum auto_tune_stage training_stage; +extern u32 is_pll_before_init; +extern u32 is_adll_calib_before_init; +extern u32 is_dfs_in_init; +extern int wl_debug_delay; +extern u32 silicon_delay[HWS_MAX_DEVICE_NUM]; +extern u32 p_finger; +extern u32 n_finger; +extern u32 freq_val[DDR_FREQ_LIMIT]; +extern u32 start_pattern, end_pattern; +extern u32 phy_reg0_val; +extern u32 phy_reg1_val; +extern u32 phy_reg2_val; +extern u32 phy_reg3_val; +extern enum hws_pattern sweep_pattern; +extern enum hws_pattern pbs_pattern; +extern u8 is_rzq6; +extern u32 znri_data_phy_val; +extern u32 zpri_data_phy_val; +extern u32 znri_ctrl_phy_val; +extern u32 zpri_ctrl_phy_val; +extern u8 debug_training_access; +extern u32 finger_test, p_finger_start, p_finger_end, n_finger_start, + n_finger_end, p_finger_step, n_finger_step; +extern u32 mode2_t; +extern u32 xsb_validate_type; +extern u32 xsb_validation_base_address; +extern u32 odt_additional; +extern u32 debug_mode; +extern u32 delay_enable; +extern u32 ca_delay; +extern u32 debug_dunit; +extern u32 clamp_tbl[]; +extern u32 freq_mask[HWS_MAX_DEVICE_NUM][DDR_FREQ_LIMIT]; +extern u32 start_pattern, end_pattern; + +extern u32 maxt_poll_tries; +extern u32 is_bist_reset_bit; +extern u8 debug_training_bist; + +extern u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +extern u32 debug_mode; +extern u32 effective_cs; +extern int ddr3_tip_centr_skip_min_win_check; +extern u32 *dq_map_table; +extern enum auto_tune_stage training_stage; +extern u8 debug_centralization; + +extern u32 delay_enable; +extern u32 start_pattern, end_pattern; +extern u32 freq_val[DDR_FREQ_LIMIT]; +extern u8 debug_training_hw_alg; +extern enum auto_tune_stage training_stage; + +extern u8 debug_training_ip; +extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]; +extern enum auto_tune_stage training_stage; +extern u32 effective_cs; + +extern u8 debug_leveling; +extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]; +extern enum auto_tune_stage training_stage; +extern u32 rl_version; +extern struct cl_val_per_freq cas_latency_table[]; +extern u32 start_xsb_offset; +extern u32 debug_mode; +extern u32 odt_config; +extern u32 effective_cs; +extern u32 phy_reg1_val; + +extern u8 debug_pbs; +extern u32 effective_cs; +extern u16 mask_results_dq_reg_map[]; +extern enum hws_ddr_freq medium_freq; +extern u32 freq_val[]; +extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]; +extern enum auto_tune_stage training_stage; +extern u32 debug_mode; +extern u32 *dq_map_table; + +extern u32 vref; +extern struct cl_val_per_freq cas_latency_table[]; +extern u32 target_freq; +extern struct hws_tip_config_func_db config_func_info[HWS_MAX_DEVICE_NUM]; +extern u32 clamp_tbl[]; +extern u32 init_freq; +/* list of allowed frequency listed in order of enum hws_ddr_freq */ +extern u32 freq_val[]; +extern u8 debug_training_static; +extern u32 first_active_if; + +/* Prototypes */ +int ddr3_tip_enable_init_sequence(u32 dev_num); + +int ddr3_tip_init_a38x(u32 dev_num, u32 board_id); + +int ddr3_hws_hw_training(void); +int ddr3_silicon_pre_init(void); +int ddr3_silicon_post_init(void); +int ddr3_post_run_alg(void); +int ddr3_if_ecc_enabled(void); +void ddr3_new_tip_ecc_scrub(void); + +void ddr3_print_version(void); +void ddr3_new_tip_dlb_config(void); +struct hws_topology_map *ddr3_get_topology_map(void); + +int ddr3_if_ecc_enabled(void); +int ddr3_tip_reg_write(u32 dev_num, u32 reg_addr, u32 data); +int ddr3_tip_reg_read(u32 dev_num, u32 reg_addr, u32 *data, u32 reg_mask); +int ddr3_silicon_get_ddr_target_freq(u32 *ddr_freq); +int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum hws_ddr_freq freq, + struct hws_tip_freq_config_info + *freq_config_info); +int ddr3_a38x_update_topology_map(u32 dev_num, + struct hws_topology_map *topology_map); +int ddr3_tip_a38x_get_init_freq(int dev_num, enum hws_ddr_freq *freq); +int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq); +int ddr3_tip_a38x_if_read(u8 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 *data, u32 mask); +int ddr3_tip_a38x_if_write(u8 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 data, u32 mask); +int ddr3_tip_a38x_get_device_info(u8 dev_num, + struct ddr3_device_info *info_ptr); + +int ddr3_tip_init_a38x(u32 dev_num, u32 board_id); + +int print_adll(u32 dev_num, u32 adll[MAX_INTERFACE_NUM * MAX_BUS_NUM]); +int ddr3_tip_restore_dunit_regs(u32 dev_num); +void print_topology(struct hws_topology_map *topology_db); + +u32 mv_board_id_get(void); + +int ddr3_load_topology_map(void); +int ddr3_tip_init_specific_reg_config(u32 dev_num, + struct reg_data *reg_config_arr); +u32 ddr3_tip_get_init_freq(void); +void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level); +int ddr3_tip_tune_training_params(u32 dev_num, + struct tune_train_params *params); +void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps); +int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena); +void ddr3_fast_path_static_cs_size_config(u32 cs_ena); +u32 ddr3_get_device_width(u32 cs); +u32 mv_board_id_index_get(u32 board_id); +u32 mv_board_id_get(void); +u32 ddr3_get_bus_width(void); +void ddr3_set_log_level(u32 n_log_level); +int ddr3_calc_mem_cs_size(u32 cs, u32 *cs_size); + +int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr); + +int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode); +int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode); + +int ddr3_tip_static_round_trip_arr_build(u32 dev_num, + struct trip_delay_element *table_ptr, + int is_wl, u32 *round_trip_delay_arr); + +u32 hws_ddr3_tip_max_cs_get(void); + +/* + * Accessor functions for the registers + */ +static inline void reg_write(u32 addr, u32 val) +{ + writel(val, INTER_REGS_BASE + addr); +} + +static inline u32 reg_read(u32 addr) +{ + return readl(INTER_REGS_BASE + addr); +} + +static inline void reg_bit_set(u32 addr, u32 mask) +{ + setbits_le32(INTER_REGS_BASE + addr, mask); +} + +static inline void reg_bit_clr(u32 addr, u32 mask) +{ + clrbits_le32(INTER_REGS_BASE + addr, mask); +} + +#endif /* _DDR3_INIT_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_logging_def.h b/drivers/ddr/marvell/a38x/ddr3_logging_def.h new file mode 100644 index 0000000..2de7c4f --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_logging_def.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_LOGGING_CONFIG_H +#define _DDR3_LOGGING_CONFIG_H + +#ifdef SILENT_LIB +#define DEBUG_TRAINING_BIST_ENGINE(level, s) +#define DEBUG_TRAINING_IP(level, s) +#define DEBUG_CENTRALIZATION_ENGINE(level, s) +#define DEBUG_TRAINING_HW_ALG(level, s) +#define DEBUG_TRAINING_IP_ENGINE(level, s) +#define DEBUG_LEVELING(level, s) +#define DEBUG_PBS_ENGINE(level, s) +#define DEBUG_TRAINING_STATIC_IP(level, s) +#define DEBUG_TRAINING_ACCESS(level, s) +#else +#ifdef LIB_FUNCTIONAL_DEBUG_ONLY +#define DEBUG_TRAINING_BIST_ENGINE(level, s) +#define DEBUG_TRAINING_IP_ENGINE(level, s) +#define DEBUG_TRAINING_IP(level, s) \ + if (level >= debug_training) \ + printf s +#define DEBUG_CENTRALIZATION_ENGINE(level, s) \ + if (level >= debug_centralization) \ + printf s +#define DEBUG_TRAINING_HW_ALG(level, s) \ + if (level >= debug_training_hw_alg) \ + printf s +#define DEBUG_LEVELING(level, s) \ + if (level >= debug_leveling) \ + printf s +#define DEBUG_PBS_ENGINE(level, s) \ + if (level >= debug_pbs) \ + printf s +#define DEBUG_TRAINING_STATIC_IP(level, s) \ + if (level >= debug_training_static) \ + printf s +#define DEBUG_TRAINING_ACCESS(level, s) \ + if (level >= debug_training_access) \ + printf s +#else +#define DEBUG_TRAINING_BIST_ENGINE(level, s) \ + if (level >= debug_training_bist) \ + printf s + +#define DEBUG_TRAINING_IP_ENGINE(level, s) \ + if (level >= debug_training_ip) \ + printf s +#define DEBUG_TRAINING_IP(level, s) \ + if (level >= debug_training) \ + printf s +#define DEBUG_CENTRALIZATION_ENGINE(level, s) \ + if (level >= debug_centralization) \ + printf s +#define DEBUG_TRAINING_HW_ALG(level, s) \ + if (level >= debug_training_hw_alg) \ + printf s +#define DEBUG_LEVELING(level, s) \ + if (level >= debug_leveling) \ + printf s +#define DEBUG_PBS_ENGINE(level, s) \ + if (level >= debug_pbs) \ + printf s +#define DEBUG_TRAINING_STATIC_IP(level, s) \ + if (level >= debug_training_static) \ + printf s +#define DEBUG_TRAINING_ACCESS(level, s) \ + if (level >= debug_training_access) \ + printf s +#endif +#endif + +/* Logging defines */ +#define DEBUG_LEVEL_TRACE 1 +#define DEBUG_LEVEL_INFO 2 +#define DEBUG_LEVEL_ERROR 3 + +enum ddr_lib_debug_block { + DEBUG_BLOCK_STATIC, + DEBUG_BLOCK_TRAINING_MAIN, + DEBUG_BLOCK_LEVELING, + DEBUG_BLOCK_CENTRALIZATION, + DEBUG_BLOCK_PBS, + DEBUG_BLOCK_IP, + DEBUG_BLOCK_BIST, + DEBUG_BLOCK_ALG, + DEBUG_BLOCK_DEVICE, + DEBUG_BLOCK_ACCESS, + DEBUG_STAGES_REG_DUMP, + /* All excluding IP and REG_DUMP, should be enabled separatelly */ + DEBUG_BLOCK_ALL +}; + +int ddr3_tip_print_log(u32 dev_num, u32 mem_addr); +int ddr3_tip_print_stability_log(u32 dev_num); + +#endif /* _DDR3_LOGGING_CONFIG_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h b/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h new file mode 100644 index 0000000..0ce0479 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_patterns_64bit.h @@ -0,0 +1,924 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __DDR3_PATTERNS_64_H +#define __DDR3_PATTERNS_64_H + +/* + * Patterns Declerations + */ + +u32 wl_sup_pattern[LEN_WL_SUP_PATTERN] __aligned(32) = { + 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, + 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d, + 0x24232221, 0x28272625, 0x2c2b2a29, 0x302f2e2d, + 0x34333231, 0x38373635, 0x3c3b3a39, 0x403f3e3d, + 0x44434241, 0x48474645, 0x4c4b4a49, 0x504f4e4d, + 0x54535251, 0x58575655, 0x5c5b5a59, 0x605f5e5d, + 0x64636261, 0x68676665, 0x6c6b6a69, 0x706f6e6d, + 0x74737271, 0x78777675, 0x7c7b7a79, 0x807f7e7d +}; + +u32 pbs_pattern_32b[2][LEN_PBS_PATTERN] __aligned(32) = { + { + 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555 + }, + { + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa + } +}; + +u32 pbs_pattern_64b[2][LEN_PBS_PATTERN] __aligned(32) = { + { + 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555, + 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555, + 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555, + 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555 + }, + { + 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa, + 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa, + 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa, + 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa + } +}; + +u32 rl_pattern[LEN_STD_PATTERN] __aligned(32) = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x01010101, 0x01010101, 0x01010101, 0x01010101 +}; + +u32 killer_pattern_32b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = { + { + 0x01010101, 0x00000000, 0x01010101, 0xffffffff, + 0x01010101, 0x00000000, 0x01010101, 0xffffffff, + 0xfefefefe, 0xfefefefe, 0x01010101, 0xfefefefe, + 0xfefefefe, 0xfefefefe, 0x01010101, 0xfefefefe, + 0x01010101, 0xfefefefe, 0x01010101, 0x01010101, + 0x01010101, 0xfefefefe, 0x01010101, 0x01010101, + 0xfefefefe, 0x01010101, 0xfefefefe, 0x00000000, + 0xfefefefe, 0x01010101, 0xfefefefe, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x01010101, + 0xffffffff, 0x00000000, 0xffffffff, 0x01010101, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xfefefefe, + 0x00000000, 0x00000000, 0x00000000, 0xfefefefe, + 0xfefefefe, 0xffffffff, 0x00000000, 0x00000000, + 0xfefefefe, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xfefefefe, 0x00000000, 0xfefefefe, 0x00000000, + 0xfefefefe, 0x00000000, 0xfefefefe, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x01010101, + 0x00000000, 0xffffffff, 0xffffffff, 0x01010101, + 0xffffffff, 0xffffffff, 0x01010101, 0x00000000, + 0xffffffff, 0xffffffff, 0x01010101, 0x00000000, + 0x01010101, 0xffffffff, 0xfefefefe, 0xfefefefe, + 0x01010101, 0xffffffff, 0xfefefefe, 0xfefefefe + }, + { + 0x02020202, 0x00000000, 0x02020202, 0xffffffff, + 0x02020202, 0x00000000, 0x02020202, 0xffffffff, + 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, + 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, + 0x02020202, 0xfdfdfdfd, 0x02020202, 0x02020202, + 0x02020202, 0xfdfdfdfd, 0x02020202, 0x02020202, + 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, 0x00000000, + 0xfdfdfdfd, 0x02020202, 0xfdfdfdfd, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x02020202, + 0xffffffff, 0x00000000, 0xffffffff, 0x02020202, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xfdfdfdfd, + 0x00000000, 0x00000000, 0x00000000, 0xfdfdfdfd, + 0xfdfdfdfd, 0xffffffff, 0x00000000, 0x00000000, + 0xfdfdfdfd, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xfdfdfdfd, 0x00000000, 0xfdfdfdfd, 0x00000000, + 0xfdfdfdfd, 0x00000000, 0xfdfdfdfd, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x02020202, + 0x00000000, 0xffffffff, 0xffffffff, 0x02020202, + 0xffffffff, 0xffffffff, 0x02020202, 0x00000000, + 0xffffffff, 0xffffffff, 0x02020202, 0x00000000, + 0x02020202, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd, + 0x02020202, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd + }, + { + 0x04040404, 0x00000000, 0x04040404, 0xffffffff, + 0x04040404, 0x00000000, 0x04040404, 0xffffffff, + 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, + 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, + 0x04040404, 0xfbfbfbfb, 0x04040404, 0x04040404, + 0x04040404, 0xfbfbfbfb, 0x04040404, 0x04040404, + 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, 0x00000000, + 0xfbfbfbfb, 0x04040404, 0xfbfbfbfb, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x04040404, + 0xffffffff, 0x00000000, 0xffffffff, 0x04040404, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xfbfbfbfb, + 0x00000000, 0x00000000, 0x00000000, 0xfbfbfbfb, + 0xfbfbfbfb, 0xffffffff, 0x00000000, 0x00000000, + 0xfbfbfbfb, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xfbfbfbfb, 0x00000000, 0xfbfbfbfb, 0x00000000, + 0xfbfbfbfb, 0x00000000, 0xfbfbfbfb, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x04040404, + 0x00000000, 0xffffffff, 0xffffffff, 0x04040404, + 0xffffffff, 0xffffffff, 0x04040404, 0x00000000, + 0xffffffff, 0xffffffff, 0x04040404, 0x00000000, + 0x04040404, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb, + 0x04040404, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb + }, + { + 0x08080808, 0x00000000, 0x08080808, 0xffffffff, + 0x08080808, 0x00000000, 0x08080808, 0xffffffff, + 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, + 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, + 0x08080808, 0xf7f7f7f7, 0x08080808, 0x08080808, + 0x08080808, 0xf7f7f7f7, 0x08080808, 0x08080808, + 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, 0x00000000, + 0xf7f7f7f7, 0x08080808, 0xf7f7f7f7, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x08080808, + 0xffffffff, 0x00000000, 0xffffffff, 0x08080808, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xf7f7f7f7, + 0x00000000, 0x00000000, 0x00000000, 0xf7f7f7f7, + 0xf7f7f7f7, 0xffffffff, 0x00000000, 0x00000000, + 0xf7f7f7f7, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xf7f7f7f7, 0x00000000, 0xf7f7f7f7, 0x00000000, + 0xf7f7f7f7, 0x00000000, 0xf7f7f7f7, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x08080808, + 0x00000000, 0xffffffff, 0xffffffff, 0x08080808, + 0xffffffff, 0xffffffff, 0x08080808, 0x00000000, + 0xffffffff, 0xffffffff, 0x08080808, 0x00000000, + 0x08080808, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7, + 0x08080808, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7 + }, + { + 0x10101010, 0x00000000, 0x10101010, 0xffffffff, + 0x10101010, 0x00000000, 0x10101010, 0xffffffff, + 0xefefefef, 0xefefefef, 0x10101010, 0xefefefef, + 0xefefefef, 0xefefefef, 0x10101010, 0xefefefef, + 0x10101010, 0xefefefef, 0x10101010, 0x10101010, + 0x10101010, 0xefefefef, 0x10101010, 0x10101010, + 0xefefefef, 0x10101010, 0xefefefef, 0x00000000, + 0xefefefef, 0x10101010, 0xefefefef, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x10101010, + 0xffffffff, 0x00000000, 0xffffffff, 0x10101010, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xefefefef, + 0x00000000, 0x00000000, 0x00000000, 0xefefefef, + 0xefefefef, 0xffffffff, 0x00000000, 0x00000000, + 0xefefefef, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xefefefef, 0x00000000, 0xefefefef, 0x00000000, + 0xefefefef, 0x00000000, 0xefefefef, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x10101010, + 0x00000000, 0xffffffff, 0xffffffff, 0x10101010, + 0xffffffff, 0xffffffff, 0x10101010, 0x00000000, + 0xffffffff, 0xffffffff, 0x10101010, 0x00000000, + 0x10101010, 0xffffffff, 0xefefefef, 0xefefefef, + 0x10101010, 0xffffffff, 0xefefefef, 0xefefefef + }, + { + 0x20202020, 0x00000000, 0x20202020, 0xffffffff, + 0x20202020, 0x00000000, 0x20202020, 0xffffffff, + 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, + 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, + 0x20202020, 0xdfdfdfdf, 0x20202020, 0x20202020, + 0x20202020, 0xdfdfdfdf, 0x20202020, 0x20202020, + 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, 0x00000000, + 0xdfdfdfdf, 0x20202020, 0xdfdfdfdf, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x20202020, + 0xffffffff, 0x00000000, 0xffffffff, 0x20202020, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xdfdfdfdf, + 0x00000000, 0x00000000, 0x00000000, 0xdfdfdfdf, + 0xdfdfdfdf, 0xffffffff, 0x00000000, 0x00000000, + 0xdfdfdfdf, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xdfdfdfdf, 0x00000000, 0xdfdfdfdf, 0x00000000, + 0xdfdfdfdf, 0x00000000, 0xdfdfdfdf, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x20202020, + 0x00000000, 0xffffffff, 0xffffffff, 0x20202020, + 0xffffffff, 0xffffffff, 0x20202020, 0x00000000, + 0xffffffff, 0xffffffff, 0x20202020, 0x00000000, + 0x20202020, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf, + 0x20202020, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf + }, + { + 0x40404040, 0x00000000, 0x40404040, 0xffffffff, + 0x40404040, 0x00000000, 0x40404040, 0xffffffff, + 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, + 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, + 0x40404040, 0xbfbfbfbf, 0x40404040, 0x40404040, + 0x40404040, 0xbfbfbfbf, 0x40404040, 0x40404040, + 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, 0x00000000, + 0xbfbfbfbf, 0x40404040, 0xbfbfbfbf, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x40404040, + 0xffffffff, 0x00000000, 0xffffffff, 0x40404040, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xbfbfbfbf, + 0x00000000, 0x00000000, 0x00000000, 0xbfbfbfbf, + 0xbfbfbfbf, 0xffffffff, 0x00000000, 0x00000000, + 0xbfbfbfbf, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xbfbfbfbf, 0x00000000, 0xbfbfbfbf, 0x00000000, + 0xbfbfbfbf, 0x00000000, 0xbfbfbfbf, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x40404040, + 0x00000000, 0xffffffff, 0xffffffff, 0x40404040, + 0xffffffff, 0xffffffff, 0x40404040, 0x00000000, + 0xffffffff, 0xffffffff, 0x40404040, 0x00000000, + 0x40404040, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf, + 0x40404040, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf + }, + { + 0x80808080, 0x00000000, 0x80808080, 0xffffffff, + 0x80808080, 0x00000000, 0x80808080, 0xffffffff, + 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, + 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, + 0x80808080, 0x7f7f7f7f, 0x80808080, 0x80808080, + 0x80808080, 0x7f7f7f7f, 0x80808080, 0x80808080, + 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, 0x00000000, + 0x7f7f7f7f, 0x80808080, 0x7f7f7f7f, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x80808080, + 0xffffffff, 0x00000000, 0xffffffff, 0x80808080, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x7f7f7f7f, + 0x00000000, 0x00000000, 0x00000000, 0x7f7f7f7f, + 0x7f7f7f7f, 0xffffffff, 0x00000000, 0x00000000, + 0x7f7f7f7f, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x7f7f7f7f, 0x00000000, 0x7f7f7f7f, 0x00000000, + 0x7f7f7f7f, 0x00000000, 0x7f7f7f7f, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x80808080, + 0x00000000, 0xffffffff, 0xffffffff, 0x80808080, + 0xffffffff, 0xffffffff, 0x80808080, 0x00000000, + 0xffffffff, 0xffffffff, 0x80808080, 0x00000000, + 0x80808080, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f, + 0x80808080, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f + } +}; + +u32 killer_pattern_64b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = { + { + 0x01010101, 0x01010101, 0x00000000, 0x00000000, + 0x01010101, 0x01010101, 0xffffffff, 0xffffffff, + 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe, + 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe, + 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe, + 0x01010101, 0x01010101, 0x01010101, 0x01010101, + 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101, + 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x01010101, 0x01010101, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xfefefefe, 0xfefefefe, + 0xfefefefe, 0xfefefefe, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000, + 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x01010101, 0x01010101, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x01010101, 0x01010101, 0x00000000, 0x00000000, + 0x01010101, 0x01010101, 0xffffffff, 0xffffffff, + 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe + }, + { + 0x02020202, 0x02020202, 0x00000000, 0x00000000, + 0x02020202, 0x02020202, 0xffffffff, 0xffffffff, + 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, + 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd, + 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd, + 0x02020202, 0x02020202, 0x02020202, 0x02020202, + 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202, + 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x02020202, 0x02020202, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xfdfdfdfd, 0xfdfdfdfd, + 0xfdfdfdfd, 0xfdfdfdfd, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000, + 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x02020202, 0x02020202, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x02020202, 0x02020202, 0x00000000, 0x00000000, + 0x02020202, 0x02020202, 0xffffffff, 0xffffffff, + 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd + }, + { + 0x04040404, 0x04040404, 0x00000000, 0x00000000, + 0x04040404, 0x04040404, 0xffffffff, 0xffffffff, + 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, + 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb, + 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb, + 0x04040404, 0x04040404, 0x04040404, 0x04040404, + 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404, + 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x04040404, 0x04040404, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xfbfbfbfb, 0xfbfbfbfb, + 0xfbfbfbfb, 0xfbfbfbfb, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000, + 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x04040404, 0x04040404, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x04040404, 0x04040404, 0x00000000, 0x00000000, + 0x04040404, 0x04040404, 0xffffffff, 0xffffffff, + 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb + }, + { + 0x08080808, 0x08080808, 0x00000000, 0x00000000, + 0x08080808, 0x08080808, 0xffffffff, 0xffffffff, + 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, + 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7, + 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7, + 0x08080808, 0x08080808, 0x08080808, 0x08080808, + 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808, + 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x08080808, 0x08080808, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xf7f7f7f7, 0xf7f7f7f7, + 0xf7f7f7f7, 0xf7f7f7f7, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000, + 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x08080808, 0x08080808, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x08080808, 0x08080808, 0x00000000, 0x00000000, + 0x08080808, 0x08080808, 0xffffffff, 0xffffffff, + 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7 + }, + { + 0x10101010, 0x10101010, 0x00000000, 0x00000000, + 0x10101010, 0x10101010, 0xffffffff, 0xffffffff, + 0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef, + 0x10101010, 0x10101010, 0xefefefef, 0xefefefef, + 0x10101010, 0x10101010, 0xefefefef, 0xefefefef, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0xefefefef, 0xefefefef, 0x10101010, 0x10101010, + 0xefefefef, 0xefefefef, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x10101010, 0x10101010, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xefefefef, 0xefefefef, + 0xefefefef, 0xefefefef, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xefefefef, 0xefefefef, 0x00000000, 0x00000000, + 0xefefefef, 0xefefefef, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x10101010, 0x10101010, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x10101010, 0x10101010, 0x00000000, 0x00000000, + 0x10101010, 0x10101010, 0xffffffff, 0xffffffff, + 0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef + }, + { + 0x20202020, 0x20202020, 0x00000000, 0x00000000, + 0x20202020, 0x20202020, 0xffffffff, 0xffffffff, + 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, + 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf, + 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf, + 0x20202020, 0x20202020, 0x20202020, 0x20202020, + 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020, + 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x20202020, 0x20202020, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xdfdfdfdf, 0xdfdfdfdf, + 0xdfdfdfdf, 0xdfdfdfdf, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000, + 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x20202020, 0x20202020, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x20202020, 0x20202020, 0x00000000, 0x00000000, + 0x20202020, 0x20202020, 0xffffffff, 0xffffffff, + 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf + }, + { + 0x40404040, 0x40404040, 0x00000000, 0x00000000, + 0x40404040, 0x40404040, 0xffffffff, 0xffffffff, + 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, + 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf, + 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf, + 0x40404040, 0x40404040, 0x40404040, 0x40404040, + 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040, + 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x40404040, 0x40404040, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xbfbfbfbf, 0xbfbfbfbf, + 0xbfbfbfbf, 0xbfbfbfbf, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000, + 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x40404040, 0x40404040, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x40404040, 0x40404040, 0x00000000, 0x00000000, + 0x40404040, 0x40404040, 0xffffffff, 0xffffffff, + 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf + }, + { + 0x80808080, 0x80808080, 0x00000000, 0x00000000, + 0x80808080, 0x80808080, 0xffffffff, 0xffffffff, + 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, + 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f, + 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f, + 0x80808080, 0x80808080, 0x80808080, 0x80808080, + 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080, + 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x80808080, 0x80808080, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x7f7f7f7f, 0x7f7f7f7f, + 0x7f7f7f7f, 0x7f7f7f7f, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000, + 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x80808080, 0x80808080, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x80808080, 0x80808080, 0x00000000, 0x00000000, + 0x80808080, 0x80808080, 0xffffffff, 0xffffffff, + 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f + } +}; + +u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN] __aligned(32) = { + { + 0x00000000, 0x00000000, 0x01010101, 0x01010101, + 0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe, + 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101, + 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101, + 0xfefefefe, 0xfefefefe, 0x01010101, 0x01010101, + 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe, + 0x01010101, 0x01010101, 0xfefefefe, 0xfefefefe, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x01010101, 0x01010101, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe, + 0x00000000, 0x00000000, 0xfefefefe, 0xfefefefe, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x01010101, 0x01010101, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x01010101, 0x01010101, + 0x00000000, 0x00000000, 0x01010101, 0x01010101, + 0xffffffff, 0xffffffff, 0xfefefefe, 0xfefefefe, + 0xfefefefe, 0xfefefefe, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x02020202, 0x02020202, + 0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd, + 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202, + 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202, + 0xfdfdfdfd, 0xfdfdfdfd, 0x02020202, 0x02020202, + 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd, + 0x02020202, 0x02020202, 0xfdfdfdfd, 0xfdfdfdfd, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x02020202, 0x02020202, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd, + 0x00000000, 0x00000000, 0xfdfdfdfd, 0xfdfdfdfd, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x02020202, 0x02020202, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x02020202, 0x02020202, + 0x00000000, 0x00000000, 0x02020202, 0x02020202, + 0xffffffff, 0xffffffff, 0xfdfdfdfd, 0xfdfdfdfd, + 0xfdfdfdfd, 0xfdfdfdfd, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x04040404, 0x04040404, + 0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb, + 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404, + 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404, + 0xfbfbfbfb, 0xfbfbfbfb, 0x04040404, 0x04040404, + 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb, + 0x04040404, 0x04040404, 0xfbfbfbfb, 0xfbfbfbfb, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x04040404, 0x04040404, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, 0xfbfbfbfb, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb, + 0x00000000, 0x00000000, 0xfbfbfbfb, 0xfbfbfbfb, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x04040404, 0x04040404, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x04040404, 0x04040404, + 0x00000000, 0x00000000, 0x04040404, 0x04040404, + 0xffffffff, 0xffffffff, 0xfbfbfbfb, 0xfbfbfbfb, + 0xfbfbfbfb, 0xfbfbfbfb, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x08080808, 0x08080808, + 0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7, + 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808, + 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808, + 0xf7f7f7f7, 0xf7f7f7f7, 0x08080808, 0x08080808, + 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7, + 0x08080808, 0x08080808, 0xf7f7f7f7, 0xf7f7f7f7, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x08080808, 0x08080808, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, 0xf7f7f7f7, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7, + 0x00000000, 0x00000000, 0xf7f7f7f7, 0xf7f7f7f7, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x08080808, 0x08080808, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x08080808, 0x08080808, + 0x00000000, 0x00000000, 0x08080808, 0x08080808, + 0xffffffff, 0xffffffff, 0xf7f7f7f7, 0xf7f7f7f7, + 0xf7f7f7f7, 0xf7f7f7f7, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x10101010, 0x10101010, + 0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef, + 0xefefefef, 0xefefefef, 0x10101010, 0x10101010, + 0xefefefef, 0xefefefef, 0x10101010, 0x10101010, + 0xefefefef, 0xefefefef, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0xefefefef, 0xefefefef, + 0x10101010, 0x10101010, 0xefefefef, 0xefefefef, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x10101010, 0x10101010, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef, + 0x00000000, 0x00000000, 0xefefefef, 0xefefefef, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x10101010, 0x10101010, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x10101010, 0x10101010, + 0x00000000, 0x00000000, 0x10101010, 0x10101010, + 0xffffffff, 0xffffffff, 0xefefefef, 0xefefefef, + 0xefefefef, 0xefefefef, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x20202020, 0x20202020, + 0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf, + 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020, + 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020, + 0xdfdfdfdf, 0xdfdfdfdf, 0x20202020, 0x20202020, + 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf, + 0x20202020, 0x20202020, 0xdfdfdfdf, 0xdfdfdfdf, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x20202020, 0x20202020, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, 0xdfdfdfdf, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf, + 0x00000000, 0x00000000, 0xdfdfdfdf, 0xdfdfdfdf, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x20202020, 0x20202020, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x20202020, 0x20202020, + 0x00000000, 0x00000000, 0x20202020, 0x20202020, + 0xffffffff, 0xffffffff, 0xdfdfdfdf, 0xdfdfdfdf, + 0xdfdfdfdf, 0xdfdfdfdf, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x40404040, 0x40404040, + 0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf, + 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040, + 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040, + 0xbfbfbfbf, 0xbfbfbfbf, 0x40404040, 0x40404040, + 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf, + 0x40404040, 0x40404040, 0xbfbfbfbf, 0xbfbfbfbf, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x40404040, 0x40404040, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, 0xbfbfbfbf, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf, + 0x00000000, 0x00000000, 0xbfbfbfbf, 0xbfbfbfbf, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x40404040, 0x40404040, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x40404040, 0x40404040, + 0x00000000, 0x00000000, 0x40404040, 0x40404040, + 0xffffffff, 0xffffffff, 0xbfbfbfbf, 0xbfbfbfbf, + 0xbfbfbfbf, 0xbfbfbfbf, 0x00000000, 0x00000000 + }, + { + 0x00000000, 0x00000000, 0x80808080, 0x80808080, + 0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f, + 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080, + 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080, + 0x7f7f7f7f, 0x7f7f7f7f, 0x80808080, 0x80808080, + 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f, + 0x80808080, 0x80808080, 0x7f7f7f7f, 0x7f7f7f7f, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x80808080, 0x80808080, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f, + 0x00000000, 0x00000000, 0x7f7f7f7f, 0x7f7f7f7f, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x80808080, 0x80808080, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x80808080, 0x80808080, + 0x00000000, 0x00000000, 0x80808080, 0x80808080, + 0xffffffff, 0xffffffff, 0x7f7f7f7f, 0x7f7f7f7f, + 0x7f7f7f7f, 0x7f7f7f7f, 0x00000000, 0x00000000 + } +}; + +/* Fabric ratios table */ +u32 fabric_ratio[FAB_OPT] = { + 0x04010204, + 0x04020202, + 0x08020306, + 0x08020303, + 0x04020303, + 0x04020204, + 0x04010202, + 0x08030606, + 0x08030505, + 0x04020306, + 0x0804050a, + 0x04030606, + 0x04020404, + 0x04030306, + 0x04020505, + 0x08020505, + 0x04010303, + 0x08050a0a, + 0x04030408, + 0x04010102, + 0x08030306 +}; + +u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM] = { + {3, 2, 5, 7, 1, 0, 6, 4}, + {2, 3, 6, 7, 1, 0, 4, 5}, + {1, 3, 5, 6, 0, 2, 4, 7}, + {0, 2, 4, 7, 1, 3, 5, 6}, + {3, 0, 4, 6, 1, 2, 5, 7}, + {0, 3, 5, 7, 1, 2, 4, 6}, + {2, 3, 5, 7, 1, 0, 4, 6}, + {0, 2, 5, 4, 1, 3, 6, 7}, + {2, 3, 4, 7, 0, 1, 5, 6} +}; + +#endif /* __DDR3_PATTERNS_64_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_topology_def.h b/drivers/ddr/marvell/a38x/ddr3_topology_def.h new file mode 100644 index 0000000..64a0447 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_topology_def.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TOPOLOGY_DEF_H +#define _DDR3_TOPOLOGY_DEF_H + +/* TOPOLOGY */ + +enum hws_speed_bin { + SPEED_BIN_DDR_800D, + SPEED_BIN_DDR_800E, + SPEED_BIN_DDR_1066E, + SPEED_BIN_DDR_1066F, + SPEED_BIN_DDR_1066G, + SPEED_BIN_DDR_1333F, + SPEED_BIN_DDR_1333G, + SPEED_BIN_DDR_1333H, + SPEED_BIN_DDR_1333J, + SPEED_BIN_DDR_1600G, + SPEED_BIN_DDR_1600H, + SPEED_BIN_DDR_1600J, + SPEED_BIN_DDR_1600K, + SPEED_BIN_DDR_1866J, + SPEED_BIN_DDR_1866K, + SPEED_BIN_DDR_1866L, + SPEED_BIN_DDR_1866M, + SPEED_BIN_DDR_2133K, + SPEED_BIN_DDR_2133L, + SPEED_BIN_DDR_2133M, + SPEED_BIN_DDR_2133N, + + SPEED_BIN_DDR_1333H_EXT, + SPEED_BIN_DDR_1600K_EXT, + SPEED_BIN_DDR_1866M_EXT +}; + +enum hws_ddr_freq { + DDR_FREQ_LOW_FREQ, + DDR_FREQ_400, + DDR_FREQ_533, + DDR_FREQ_667, + DDR_FREQ_800, + DDR_FREQ_933, + DDR_FREQ_1066, + DDR_FREQ_311, + DDR_FREQ_333, + DDR_FREQ_467, + DDR_FREQ_850, + DDR_FREQ_600, + DDR_FREQ_300, + DDR_FREQ_900, + DDR_FREQ_360, + DDR_FREQ_1000, + DDR_FREQ_LIMIT +}; + +enum speed_bin_table_elements { + SPEED_BIN_TRCD, + SPEED_BIN_TRP, + SPEED_BIN_TRAS, + SPEED_BIN_TRC, + SPEED_BIN_TRRD1K, + SPEED_BIN_TRRD2K, + SPEED_BIN_TPD, + SPEED_BIN_TFAW1K, + SPEED_BIN_TFAW2K, + SPEED_BIN_TWTR, + SPEED_BIN_TRTP, + SPEED_BIN_TWR, + SPEED_BIN_TMOD +}; + +#endif /* _DDR3_TOPOLOGY_DEF_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c new file mode 100644 index 0000000..80ef050 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training.c @@ -0,0 +1,2644 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define GET_MAX_VALUE(x, y) \ + ((x) > (y)) ? (x) : (y) +#define CEIL_DIVIDE(x, y) \ + ((x - (x / y) * y) == 0) ? ((x / y) - 1) : (x / y) + +#define TIME_2_CLOCK_CYCLES CEIL_DIVIDE + +#define GET_CS_FROM_MASK(mask) (cs_mask2_num[mask]) +#define CS_CBE_VALUE(cs_num) (cs_cbe_reg[cs_num]) + +u32 window_mem_addr = 0; +u32 phy_reg0_val = 0; +u32 phy_reg1_val = 8; +u32 phy_reg2_val = 0; +u32 phy_reg3_val = 0xa; +enum hws_ddr_freq init_freq = DDR_FREQ_667; +enum hws_ddr_freq low_freq = DDR_FREQ_LOW_FREQ; +enum hws_ddr_freq medium_freq; +u32 debug_dunit = 0; +u32 odt_additional = 1; +u32 *dq_map_table = NULL; +u32 odt_config = 1; + +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ALLEYCAT3) || \ + defined(CONFIG_ARMADA_39X) +u32 is_pll_before_init = 0, is_adll_calib_before_init = 0, is_dfs_in_init = 0; +u32 dfs_low_freq = 130; +#else +u32 is_pll_before_init = 0, is_adll_calib_before_init = 1, is_dfs_in_init = 0; +u32 dfs_low_freq = 100; +#endif +u32 g_rtt_nom_c_s0, g_rtt_nom_c_s1; +u8 calibration_update_control; /* 2 external only, 1 is internal only */ + +enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]; +enum auto_tune_stage training_stage = INIT_CONTROLLER; +u32 finger_test = 0, p_finger_start = 11, p_finger_end = 64, + n_finger_start = 11, n_finger_end = 64, + p_finger_step = 3, n_finger_step = 3; +u32 clamp_tbl[] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; + +/* Initiate to 0xff, this variable is define by user in debug mode */ +u32 mode2_t = 0xff; +u32 xsb_validate_type = 0; +u32 xsb_validation_base_address = 0xf000; +u32 first_active_if = 0; +u32 dfs_low_phy1 = 0x1f; +u32 multicast_id = 0; +int use_broadcast = 0; +struct hws_tip_freq_config_info *freq_info_table = NULL; +u8 is_cbe_required = 0; +u32 debug_mode = 0; +u32 delay_enable = 0; +int rl_mid_freq_wa = 0; + +u32 effective_cs = 0; + +u32 mask_tune_func = (SET_MEDIUM_FREQ_MASK_BIT | + WRITE_LEVELING_MASK_BIT | + LOAD_PATTERN_2_MASK_BIT | + READ_LEVELING_MASK_BIT | + SET_TARGET_FREQ_MASK_BIT | WRITE_LEVELING_TF_MASK_BIT | + READ_LEVELING_TF_MASK_BIT | + CENTRALIZATION_RX_MASK_BIT | CENTRALIZATION_TX_MASK_BIT); + +void ddr3_print_version(void) +{ + printf(DDR3_TIP_VERSION_STRING); +} + +static int ddr3_tip_ddr3_training_main_flow(u32 dev_num); +static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type, + u32 if_id, u32 cl_value, u32 cwl_value); +static int ddr3_tip_ddr3_auto_tune(u32 dev_num); +static int is_bus_access_done(u32 dev_num, u32 if_id, + u32 dunit_reg_adrr, u32 bit); +#ifdef ODT_TEST_SUPPORT +static int odt_test(u32 dev_num, enum hws_algo_type algo_type); +#endif + +int adll_calibration(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_ddr_freq frequency); +static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_ddr_freq frequency); + +static struct page_element page_param[] = { + /* + * 8bits 16 bits + * page-size(K) page-size(K) mask + */ + { 1, 2, 2}, + /* 512M */ + { 1, 2, 3}, + /* 1G */ + { 1, 2, 0}, + /* 2G */ + { 1, 2, 4}, + /* 4G */ + { 2, 2, 5} + /* 8G */ +}; + +static u8 mem_size_config[MEM_SIZE_LAST] = { + 0x2, /* 512Mbit */ + 0x3, /* 1Gbit */ + 0x0, /* 2Gbit */ + 0x4, /* 4Gbit */ + 0x5 /* 8Gbit */ +}; + +static u8 cs_mask2_num[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; + +static struct reg_data odpg_default_value[] = { + {0x1034, 0x38000, MASK_ALL_BITS}, + {0x1038, 0x0, MASK_ALL_BITS}, + {0x10b0, 0x0, MASK_ALL_BITS}, + {0x10b8, 0x0, MASK_ALL_BITS}, + {0x10c0, 0x0, MASK_ALL_BITS}, + {0x10f0, 0x0, MASK_ALL_BITS}, + {0x10f4, 0x0, MASK_ALL_BITS}, + {0x10f8, 0xff, MASK_ALL_BITS}, + {0x10fc, 0xffff, MASK_ALL_BITS}, + {0x1130, 0x0, MASK_ALL_BITS}, + {0x1830, 0x2000000, MASK_ALL_BITS}, + {0x14d0, 0x0, MASK_ALL_BITS}, + {0x14d4, 0x0, MASK_ALL_BITS}, + {0x14d8, 0x0, MASK_ALL_BITS}, + {0x14dc, 0x0, MASK_ALL_BITS}, + {0x1454, 0x0, MASK_ALL_BITS}, + {0x1594, 0x0, MASK_ALL_BITS}, + {0x1598, 0x0, MASK_ALL_BITS}, + {0x159c, 0x0, MASK_ALL_BITS}, + {0x15a0, 0x0, MASK_ALL_BITS}, + {0x15a4, 0x0, MASK_ALL_BITS}, + {0x15a8, 0x0, MASK_ALL_BITS}, + {0x15ac, 0x0, MASK_ALL_BITS}, + {0x1604, 0x0, MASK_ALL_BITS}, + {0x1608, 0x0, MASK_ALL_BITS}, + {0x160c, 0x0, MASK_ALL_BITS}, + {0x1610, 0x0, MASK_ALL_BITS}, + {0x1614, 0x0, MASK_ALL_BITS}, + {0x1618, 0x0, MASK_ALL_BITS}, + {0x1624, 0x0, MASK_ALL_BITS}, + {0x1690, 0x0, MASK_ALL_BITS}, + {0x1694, 0x0, MASK_ALL_BITS}, + {0x1698, 0x0, MASK_ALL_BITS}, + {0x169c, 0x0, MASK_ALL_BITS}, + {0x14b8, 0x6f67, MASK_ALL_BITS}, + {0x1630, 0x0, MASK_ALL_BITS}, + {0x1634, 0x0, MASK_ALL_BITS}, + {0x1638, 0x0, MASK_ALL_BITS}, + {0x163c, 0x0, MASK_ALL_BITS}, + {0x16b0, 0x0, MASK_ALL_BITS}, + {0x16b4, 0x0, MASK_ALL_BITS}, + {0x16b8, 0x0, MASK_ALL_BITS}, + {0x16bc, 0x0, MASK_ALL_BITS}, + {0x16c0, 0x0, MASK_ALL_BITS}, + {0x16c4, 0x0, MASK_ALL_BITS}, + {0x16c8, 0x0, MASK_ALL_BITS}, + {0x16cc, 0x1, MASK_ALL_BITS}, + {0x16f0, 0x1, MASK_ALL_BITS}, + {0x16f4, 0x0, MASK_ALL_BITS}, + {0x16f8, 0x0, MASK_ALL_BITS}, + {0x16fc, 0x0, MASK_ALL_BITS} +}; + +static int ddr3_tip_bus_access(u32 dev_num, enum hws_access_type interface_access, + u32 if_id, enum hws_access_type phy_access, + u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr, + u32 data_value, enum hws_operation oper_type); +static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id); +static int ddr3_tip_rank_control(u32 dev_num, u32 if_id); + +/* + * Update global training parameters by data from user + */ +int ddr3_tip_tune_training_params(u32 dev_num, + struct tune_train_params *params) +{ + if (params->ck_delay != -1) + ck_delay = params->ck_delay; + if (params->ck_delay_16 != -1) + ck_delay_16 = params->ck_delay_16; + if (params->phy_reg3_val != -1) + phy_reg3_val = params->phy_reg3_val; + + return MV_OK; +} + +/* + * Configure CS + */ +int ddr3_tip_configure_cs(u32 dev_num, u32 if_id, u32 cs_num, u32 enable) +{ + u32 data, addr_hi, data_high; + u32 mem_index; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (enable == 1) { + data = (tm->interface_params[if_id].bus_width == + BUS_WIDTH_8) ? 0 : 1; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + SDRAM_ACCESS_CONTROL_REG, (data << (cs_num * 4)), + 0x3 << (cs_num * 4))); + mem_index = tm->interface_params[if_id].memory_size; + + addr_hi = mem_size_config[mem_index] & 0x3; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + SDRAM_ACCESS_CONTROL_REG, + (addr_hi << (2 + cs_num * 4)), + 0x3 << (2 + cs_num * 4))); + + data_high = (mem_size_config[mem_index] & 0x4) >> 2; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + SDRAM_ACCESS_CONTROL_REG, + data_high << (20 + cs_num), 1 << (20 + cs_num))); + + /* Enable Address Select Mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + SDRAM_ACCESS_CONTROL_REG, 1 << (16 + cs_num), + 1 << (16 + cs_num))); + } + switch (cs_num) { + case 0: + case 1: + case 2: + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + DDR_CONTROL_LOW_REG, (enable << (cs_num + 11)), + 1 << (cs_num + 11))); + break; + case 3: + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + DDR_CONTROL_LOW_REG, (enable << 15), 1 << 15)); + break; + } + + return MV_OK; +} + +/* + * Calculate number of CS + */ +static int calc_cs_num(u32 dev_num, u32 if_id, u32 *cs_num) +{ + u32 cs; + u32 bus_cnt; + u32 cs_count; + u32 cs_bitmask; + u32 curr_cs_num = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + cs_count = 0; + cs_bitmask = tm->interface_params[if_id]. + as_bus_params[bus_cnt].cs_bitmask; + for (cs = 0; cs < MAX_CS_NUM; cs++) { + if ((cs_bitmask >> cs) & 1) + cs_count++; + } + + if (curr_cs_num == 0) { + curr_cs_num = cs_count; + } else if (cs_count != curr_cs_num) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("CS number is different per bus (IF %d BUS %d cs_num %d curr_cs_num %d)\n", + if_id, bus_cnt, cs_count, + curr_cs_num)); + return MV_NOT_SUPPORTED; + } + } + *cs_num = curr_cs_num; + + return MV_OK; +} + +/* + * Init Controller Flow + */ +int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_prm) +{ + u32 if_id; + u32 cs_num; + u32 t_refi = 0, t_hclk = 0, t_ckclk = 0, t_faw = 0, t_pd = 0, + t_wr = 0, t2t = 0, txpdll = 0; + u32 data_value = 0, bus_width = 0, page_size = 0, cs_cnt = 0, + mem_mask = 0, bus_index = 0; + enum hws_speed_bin speed_bin_index = SPEED_BIN_DDR_2133N; + enum hws_mem_size memory_size = MEM_2G; + enum hws_ddr_freq freq = init_freq; + u32 cs_mask = 0; + u32 cl_value = 0, cwl_val = 0; + u32 refresh_interval_cnt = 0, bus_cnt = 0, adll_tap = 0; + enum hws_access_type access_type = ACCESS_TYPE_UNICAST; + u32 data_read[MAX_INTERFACE_NUM]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("Init_controller, do_mrs_phy=%d, is_ctrl64_bit=%d\n", + init_cntr_prm->do_mrs_phy, + init_cntr_prm->is_ctrl64_bit)); + + if (init_cntr_prm->init_phy == 1) { + CHECK_STATUS(ddr3_tip_configure_phy(dev_num)); + } + + if (generic_init_controller == 1) { + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("active IF %d\n", if_id)); + mem_mask = 0; + for (bus_index = 0; + bus_index < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_index++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + mem_mask |= + tm->interface_params[if_id]. + as_bus_params[bus_index].mirror_enable_bitmask; + } + + if (mem_mask != 0) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, + if_id, CS_ENABLE_REG, 0, + 0x8)); + } + + memory_size = + tm->interface_params[if_id]. + memory_size; + speed_bin_index = + tm->interface_params[if_id]. + speed_bin_index; + freq = init_freq; + t_refi = + (tm->interface_params[if_id]. + interface_temp == + HWS_TEMP_HIGH) ? TREFI_HIGH : TREFI_LOW; + t_refi *= 1000; /* psec */ + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("memy_size %d speed_bin_ind %d freq %d t_refi %d\n", + memory_size, speed_bin_index, freq, + t_refi)); + /* HCLK & CK CLK in 2:1[ps] */ + /* t_ckclk is external clock */ + t_ckclk = (MEGA / freq_val[freq]); + /* t_hclk is internal clock */ + t_hclk = 2 * t_ckclk; + refresh_interval_cnt = t_refi / t_hclk; /* no units */ + bus_width = + (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) + == 1) ? (16) : (32); + + if (init_cntr_prm->is_ctrl64_bit) + bus_width = 64; + + data_value = + (refresh_interval_cnt | 0x4000 | + ((bus_width == + 32) ? 0x8000 : 0) | 0x1000000) & ~(1 << 26); + + /* Interface Bus Width */ + /* SRMode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_CONFIGURATION_REG, data_value, + 0x100ffff)); + + /* Interleave first command pre-charge enable (TBD) */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_OPEN_PAGE_CONTROL_REG, (1 << 10), + (1 << 10))); + + /* PHY configuration */ + /* + * Postamble Length = 1.5cc, Addresscntl to clk skew + * \BD, Preamble length normal, parralal ADLL enable + */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DRAM_PHY_CONFIGURATION, 0x28, 0x3e)); + if (init_cntr_prm->is_ctrl64_bit) { + /* positive edge */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DRAM_PHY_CONFIGURATION, 0x0, + 0xff80)); + } + + /* calibration block disable */ + /* Xbar Read buffer select (for Internal access) */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + CALIB_MACHINE_CTRL_REG, 0x1200c, + 0x7dffe01c)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + CALIB_MACHINE_CTRL_REG, + calibration_update_control << 3, 0x3 << 3)); + + /* Pad calibration control - enable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + CALIB_MACHINE_CTRL_REG, 0x1, 0x1)); + + cs_mask = 0; + data_value = 0x7; + /* + * Address ctrl \96 Part of the Generic code + * The next configuration is done: + * 1) Memory Size + * 2) Bus_width + * 3) CS# + * 4) Page Number + * 5) t_faw + * Per Dunit get from the Map_topology the parameters: + * Bus_width + * t_faw is per Dunit not per CS + */ + page_size = + (tm->interface_params[if_id]. + bus_width == + BUS_WIDTH_8) ? page_param[memory_size]. + page_size_8bit : page_param[memory_size]. + page_size_16bit; + + t_faw = + (page_size == 1) ? speed_bin_table(speed_bin_index, + SPEED_BIN_TFAW1K) + : speed_bin_table(speed_bin_index, + SPEED_BIN_TFAW2K); + + data_value = TIME_2_CLOCK_CYCLES(t_faw, t_ckclk); + data_value = data_value << 24; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_ACCESS_CONTROL_REG, data_value, + 0x7f000000)); + + data_value = + (tm->interface_params[if_id]. + bus_width == BUS_WIDTH_8) ? 0 : 1; + + /* create merge cs mask for all cs available in dunit */ + for (bus_cnt = 0; + bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + cs_mask |= + tm->interface_params[if_id]. + as_bus_params[bus_cnt].cs_bitmask; + } + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("Init_controller IF %d cs_mask %d\n", + if_id, cs_mask)); + /* + * Configure the next upon the Map Topology \96 If the + * Dunit is CS0 Configure CS0 if it is multi CS + * configure them both: The Bust_width it\92s the + * Memory Bus width \96 x8 or x16 + */ + for (cs_cnt = 0; cs_cnt < NUM_OF_CS; cs_cnt++) { + ddr3_tip_configure_cs(dev_num, if_id, cs_cnt, + ((cs_mask & (1 << cs_cnt)) ? 1 + : 0)); + } + + if (init_cntr_prm->do_mrs_phy) { + /* + * MR0 \96 Part of the Generic code + * The next configuration is done: + * 1) Burst Length + * 2) CAS Latency + * get for each dunit what is it Speed_bin & + * Target Frequency. From those both parameters + * get the appropriate Cas_l from the CL table + */ + cl_value = + tm->interface_params[if_id]. + cas_l; + cwl_val = + tm->interface_params[if_id]. + cas_wl; + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("cl_value 0x%x cwl_val 0x%x\n", + cl_value, cwl_val)); + + data_value = + ((cl_mask_table[cl_value] & 0x1) << 2) | + ((cl_mask_table[cl_value] & 0xe) << 3); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + MR0_REG, data_value, + (0x7 << 4) | (1 << 2))); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + MR0_REG, twr_mask_table[t_wr + 1], + 0xe00)); + + /* + * MR1: Set RTT and DIC Design GL values + * configured by user + */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, MR1_REG, + g_dic | g_rtt_nom, 0x266)); + + /* MR2 - Part of the Generic code */ + /* + * The next configuration is done: + * 1) SRT + * 2) CAS Write Latency + */ + data_value = (cwl_mask_table[cwl_val] << 3); + data_value |= + ((tm->interface_params[if_id]. + interface_temp == + HWS_TEMP_HIGH) ? (1 << 7) : 0); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + MR2_REG, data_value, + (0x7 << 3) | (0x1 << 7) | (0x3 << + 9))); + } + + ddr3_tip_write_odt(dev_num, access_type, if_id, + cl_value, cwl_val); + ddr3_tip_set_timing(dev_num, access_type, if_id, freq); + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DUNIT_CONTROL_HIGH_REG, 0x177, + 0x1000177)); + + if (init_cntr_prm->is_ctrl64_bit) { + /* disable 0.25 cc delay */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DUNIT_CONTROL_HIGH_REG, 0x0, + 0x800)); + } + + /* reset bit 7 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DUNIT_CONTROL_HIGH_REG, + (init_cntr_prm->msys_init << 7), (1 << 7))); + + if (mode2_t != 0xff) { + t2t = mode2_t; + } else { + /* calculate number of CS (per interface) */ + CHECK_STATUS(calc_cs_num + (dev_num, if_id, &cs_num)); + t2t = (cs_num == 1) ? 0 : 1; + } + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DDR_CONTROL_LOW_REG, t2t << 3, + 0x3 << 3)); + /* move the block to ddr3_tip_set_timing - start */ + t_pd = GET_MAX_VALUE(t_ckclk * 3, + speed_bin_table(speed_bin_index, + SPEED_BIN_TPD)); + t_pd = TIME_2_CLOCK_CYCLES(t_pd, t_ckclk); + txpdll = GET_MAX_VALUE(t_ckclk * 10, 24); + txpdll = CEIL_DIVIDE((txpdll - 1), t_ckclk); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DDR_TIMING_REG, txpdll << 4, + 0x1f << 4)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DDR_TIMING_REG, 0x28 << 9, 0x3f << 9)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DDR_TIMING_REG, 0xa << 21, 0xff << 21)); + + /* move the block to ddr3_tip_set_timing - end */ + /* AUTO_ZQC_TIMING */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + TIMING_REG, (AUTO_ZQC_TIMING | (2 << 20)), + 0x3fffff)); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, access_type, if_id, + DRAM_PHY_CONFIGURATION, data_read, 0x30)); + data_value = + (data_read[if_id] == 0) ? (1 << 11) : 0; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DUNIT_CONTROL_HIGH_REG, data_value, + (1 << 11))); + + /* Set Active control for ODT write transactions */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, 0x1494, g_odt_config, + MASK_ALL_BITS)); + } + } else { +#ifdef STATIC_ALGO_SUPPORT + CHECK_STATUS(ddr3_tip_static_init_controller(dev_num)); +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X) + CHECK_STATUS(ddr3_tip_static_phy_init_controller(dev_num)); +#endif +#endif /* STATIC_ALGO_SUPPORT */ + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_rank_control(dev_num, if_id)); + + if (init_cntr_prm->do_mrs_phy) { + CHECK_STATUS(ddr3_tip_pad_inv(dev_num, if_id)); + } + + /* Pad calibration control - disable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + CALIB_MACHINE_CTRL_REG, 0x0, 0x1)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + CALIB_MACHINE_CTRL_REG, + calibration_update_control << 3, 0x3 << 3)); + } + + CHECK_STATUS(ddr3_tip_enable_init_sequence(dev_num)); + + if (delay_enable != 0) { + adll_tap = MEGA / (freq_val[freq] * 64); + ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap); + } + + return MV_OK; +} + +/* + * Load Topology map + */ +int hws_ddr3_tip_load_topology_map(u32 dev_num, struct hws_topology_map *tm) +{ + enum hws_speed_bin speed_bin_index; + enum hws_ddr_freq freq = DDR_FREQ_LIMIT; + u32 if_id; + + freq_val[DDR_FREQ_LOW_FREQ] = dfs_low_freq; + tm = ddr3_get_topology_map(); + CHECK_STATUS(ddr3_tip_get_first_active_if + ((u8)dev_num, tm->if_act_mask, + &first_active_if)); + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("board IF_Mask=0x%x num_of_bus_per_interface=0x%x\n", + tm->if_act_mask, + tm->num_of_bus_per_interface)); + + /* + * if CL, CWL values are missing in topology map, then fill them + * according to speedbin tables + */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + speed_bin_index = + tm->interface_params[if_id].speed_bin_index; + /* TBD memory frequency of interface 0 only is used ! */ + freq = tm->interface_params[first_active_if].memory_freq; + + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("speed_bin_index =%d freq=%d cl=%d cwl=%d\n", + speed_bin_index, freq_val[freq], + tm->interface_params[if_id]. + cas_l, + tm->interface_params[if_id]. + cas_wl)); + + if (tm->interface_params[if_id].cas_l == 0) { + tm->interface_params[if_id].cas_l = + cas_latency_table[speed_bin_index].cl_val[freq]; + } + + if (tm->interface_params[if_id].cas_wl == 0) { + tm->interface_params[if_id].cas_wl = + cas_write_latency_table[speed_bin_index].cl_val[freq]; + } + } + + return MV_OK; +} + +/* + * RANK Control Flow + */ +static int ddr3_tip_rank_control(u32 dev_num, u32 if_id) +{ + u32 data_value = 0, bus_cnt; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (bus_cnt = 1; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + if ((tm->interface_params[if_id]. + as_bus_params[0].cs_bitmask != + tm->interface_params[if_id]. + as_bus_params[bus_cnt].cs_bitmask) || + (tm->interface_params[if_id]. + as_bus_params[0].mirror_enable_bitmask != + tm->interface_params[if_id]. + as_bus_params[bus_cnt].mirror_enable_bitmask)) + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("WARNING:Wrong configuration for pup #%d CS mask and CS mirroring for all pups should be the same\n", + bus_cnt)); + } + + data_value |= tm->interface_params[if_id]. + as_bus_params[0].cs_bitmask; + data_value |= tm->interface_params[if_id]. + as_bus_params[0].mirror_enable_bitmask << 4; + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, RANK_CTRL_REG, + data_value, 0xff)); + + return MV_OK; +} + +/* + * PAD Inverse Flow + */ +static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id) +{ + u32 bus_cnt, data_value, ck_swap_pup_ctrl; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + if (tm->interface_params[if_id]. + as_bus_params[bus_cnt].is_dqs_swap == 1) { + /* dqs swap */ + ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST, + if_id, bus_cnt, + DDR_PHY_DATA, + PHY_CONTROL_PHY_REG, 0xc0, + 0xc0); + } + + if (tm->interface_params[if_id]. + as_bus_params[bus_cnt].is_ck_swap == 1) { + if (bus_cnt <= 1) + data_value = 0x5 << 2; + else + data_value = 0xa << 2; + + /* mask equals data */ + /* ck swap pup is only control pup #0 ! */ + ck_swap_pup_ctrl = 0; + ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST, + if_id, ck_swap_pup_ctrl, + DDR_PHY_CONTROL, + PHY_CONTROL_PHY_REG, + data_value, data_value); + } + } + + return MV_OK; +} + +/* + * Run Training Flow + */ +int hws_ddr3_tip_run_alg(u32 dev_num, enum hws_algo_type algo_type) +{ + int ret = MV_OK, ret_tune = MV_OK; + +#ifdef ODT_TEST_SUPPORT + if (finger_test == 1) + return odt_test(dev_num, algo_type); +#endif + + if (algo_type == ALGO_TYPE_DYNAMIC) { + ret = ddr3_tip_ddr3_auto_tune(dev_num); + } else { +#ifdef STATIC_ALGO_SUPPORT + { + enum hws_ddr_freq freq; + freq = init_freq; + + /* add to mask */ + if (is_adll_calib_before_init != 0) { + printf("with adll calib before init\n"); + adll_calibration(dev_num, ACCESS_TYPE_MULTICAST, + 0, freq); + } + /* + * Frequency per interface is not relevant, + * only interface 0 + */ + ret = ddr3_tip_run_static_alg(dev_num, + freq); + } +#endif + } + + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Run_alg: tuning failed %d\n", ret_tune)); + } + + return ret; +} + +#ifdef ODT_TEST_SUPPORT +/* + * ODT Test + */ +static int odt_test(u32 dev_num, enum hws_algo_type algo_type) +{ + int ret = MV_OK, ret_tune = MV_OK; + int pfinger_val = 0, nfinger_val; + + for (pfinger_val = p_finger_start; pfinger_val <= p_finger_end; + pfinger_val += p_finger_step) { + for (nfinger_val = n_finger_start; nfinger_val <= n_finger_end; + nfinger_val += n_finger_step) { + if (finger_test != 0) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("pfinger_val %d nfinger_val %d\n", + pfinger_val, nfinger_val)); + p_finger = pfinger_val; + n_finger = nfinger_val; + } + + if (algo_type == ALGO_TYPE_DYNAMIC) { + ret = ddr3_tip_ddr3_auto_tune(dev_num); + } else { + /* + * Frequency per interface is not relevant, + * only interface 0 + */ + ret = ddr3_tip_run_static_alg(dev_num, + init_freq); + } + } + } + + if (ret_tune != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Run_alg: tuning failed %d\n", ret_tune)); + ret = (ret == MV_OK) ? ret_tune : ret; + } + + return ret; +} +#endif + +/* + * Select Controller + */ +int hws_ddr3_tip_select_ddr_controller(u32 dev_num, int enable) +{ + if (config_func_info[dev_num].tip_dunit_mux_select_func != NULL) { + return config_func_info[dev_num]. + tip_dunit_mux_select_func((u8)dev_num, enable); + } + + return MV_FAIL; +} + +/* + * Dunit Register Write + */ +int ddr3_tip_if_write(u32 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 data_value, u32 mask) +{ + if (config_func_info[dev_num].tip_dunit_write_func != NULL) { + return config_func_info[dev_num]. + tip_dunit_write_func((u8)dev_num, interface_access, + if_id, reg_addr, + data_value, mask); + } + + return MV_FAIL; +} + +/* + * Dunit Register Read + */ +int ddr3_tip_if_read(u32 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 *data, u32 mask) +{ + if (config_func_info[dev_num].tip_dunit_read_func != NULL) { + return config_func_info[dev_num]. + tip_dunit_read_func((u8)dev_num, interface_access, + if_id, reg_addr, + data, mask); + } + + return MV_FAIL; +} + +/* + * Dunit Register Polling + */ +int ddr3_tip_if_polling(u32 dev_num, enum hws_access_type access_type, + u32 if_id, u32 exp_value, u32 mask, u32 offset, + u32 poll_tries) +{ + u32 poll_cnt = 0, interface_num = 0, start_if, end_if; + u32 read_data[MAX_INTERFACE_NUM]; + int ret; + int is_fail = 0, is_if_fail; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (access_type == ACCESS_TYPE_MULTICAST) { + start_if = 0; + end_if = MAX_INTERFACE_NUM - 1; + } else { + start_if = if_id; + end_if = if_id; + } + + for (interface_num = start_if; interface_num <= end_if; interface_num++) { + /* polling bit 3 for n times */ + VALIDATE_ACTIVE(tm->if_act_mask, interface_num); + + is_if_fail = 0; + for (poll_cnt = 0; poll_cnt < poll_tries; poll_cnt++) { + ret = + ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, + interface_num, offset, read_data, + mask); + if (ret != MV_OK) + return ret; + + if (read_data[interface_num] == exp_value) + break; + } + + if (poll_cnt >= poll_tries) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("max poll IF #%d\n", interface_num)); + is_fail = 1; + is_if_fail = 1; + } + + training_result[training_stage][interface_num] = + (is_if_fail == 1) ? TEST_FAILED : TEST_SUCCESS; + } + + return (is_fail == 0) ? MV_OK : MV_FAIL; +} + +/* + * Bus read access + */ +int ddr3_tip_bus_read(u32 dev_num, u32 if_id, + enum hws_access_type phy_access, u32 phy_id, + enum hws_ddr_phy phy_type, u32 reg_addr, u32 *data) +{ + u32 bus_index = 0; + u32 data_read[MAX_INTERFACE_NUM]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (phy_access == ACCESS_TYPE_MULTICAST) { + for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_index++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + CHECK_STATUS(ddr3_tip_bus_access + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + bus_index, phy_type, reg_addr, 0, + OPERATION_READ)); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + PHY_REG_FILE_ACCESS, data_read, + MASK_ALL_BITS)); + data[bus_index] = (data_read[if_id] & 0xffff); + } + } else { + CHECK_STATUS(ddr3_tip_bus_access + (dev_num, ACCESS_TYPE_UNICAST, if_id, + phy_access, phy_id, phy_type, reg_addr, 0, + OPERATION_READ)); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + PHY_REG_FILE_ACCESS, data_read, MASK_ALL_BITS)); + + /* + * only 16 lsb bit are valid in Phy (each register is different, + * some can actually be less than 16 bits) + */ + *data = (data_read[if_id] & 0xffff); + } + + return MV_OK; +} + +/* + * Bus write access + */ +int ddr3_tip_bus_write(u32 dev_num, enum hws_access_type interface_access, + u32 if_id, enum hws_access_type phy_access, + u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr, + u32 data_value) +{ + CHECK_STATUS(ddr3_tip_bus_access + (dev_num, interface_access, if_id, phy_access, + phy_id, phy_type, reg_addr, data_value, OPERATION_WRITE)); + + return MV_OK; +} + +/* + * Bus access routine (relevant for both read & write) + */ +static int ddr3_tip_bus_access(u32 dev_num, enum hws_access_type interface_access, + u32 if_id, enum hws_access_type phy_access, + u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr, + u32 data_value, enum hws_operation oper_type) +{ + u32 addr_low = 0x3f & reg_addr; + u32 addr_hi = ((0xc0 & reg_addr) >> 6); + u32 data_p1 = + (oper_type << 30) + (addr_hi << 28) + (phy_access << 27) + + (phy_type << 26) + (phy_id << 22) + (addr_low << 16) + + (data_value & 0xffff); + u32 data_p2 = data_p1 + (1 << 31); + u32 start_if, end_if; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, interface_access, if_id, PHY_REG_FILE_ACCESS, + data_p1, MASK_ALL_BITS)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, interface_access, if_id, PHY_REG_FILE_ACCESS, + data_p2, MASK_ALL_BITS)); + + if (interface_access == ACCESS_TYPE_UNICAST) { + start_if = if_id; + end_if = if_id; + } else { + start_if = 0; + end_if = MAX_INTERFACE_NUM - 1; + } + + /* polling for read/write execution done */ + for (if_id = start_if; if_id <= end_if; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(is_bus_access_done + (dev_num, if_id, PHY_REG_FILE_ACCESS, 31)); + } + + return MV_OK; +} + +/* + * Check bus access done + */ +static int is_bus_access_done(u32 dev_num, u32 if_id, u32 dunit_reg_adrr, + u32 bit) +{ + u32 rd_data = 1; + u32 cnt = 0; + u32 data_read[MAX_INTERFACE_NUM]; + + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, dunit_reg_adrr, + data_read, MASK_ALL_BITS)); + rd_data = data_read[if_id]; + rd_data &= (1 << bit); + + while (rd_data != 0) { + if (cnt++ >= MAX_POLLING_ITERATIONS) + break; + + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + dunit_reg_adrr, data_read, MASK_ALL_BITS)); + rd_data = data_read[if_id]; + rd_data &= (1 << bit); + } + + if (cnt < MAX_POLLING_ITERATIONS) + return MV_OK; + else + return MV_FAIL; +} + +/* + * Phy read-modify-write + */ +int ddr3_tip_bus_read_modify_write(u32 dev_num, enum hws_access_type access_type, + u32 interface_id, u32 phy_id, + enum hws_ddr_phy phy_type, u32 reg_addr, + u32 data_value, u32 reg_mask) +{ + u32 data_val = 0, if_id, start_if, end_if; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (access_type == ACCESS_TYPE_MULTICAST) { + start_if = 0; + end_if = MAX_INTERFACE_NUM - 1; + } else { + start_if = interface_id; + end_if = interface_id; + } + + for (if_id = start_if; if_id <= end_if; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, phy_id, + phy_type, reg_addr, &data_val)); + data_value = (data_val & (~reg_mask)) | (data_value & reg_mask); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, phy_id, phy_type, reg_addr, + data_value)); + } + + return MV_OK; +} + +/* + * ADLL Calibration + */ +int adll_calibration(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_ddr_freq frequency) +{ + struct hws_tip_freq_config_info freq_config_info; + u32 bus_cnt = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* Reset Diver_b assert -> de-assert */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG, + 0, 0x10000000)); + mdelay(10); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG, + 0x10000000, 0x10000000)); + + if (config_func_info[dev_num].tip_get_freq_config_info_func != NULL) { + CHECK_STATUS(config_func_info[dev_num]. + tip_get_freq_config_info_func((u8)dev_num, frequency, + &freq_config_info)); + } else { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("tip_get_freq_config_info_func is NULL")); + return MV_NOT_INITIALIZED; + } + + for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, access_type, if_id, bus_cnt, + DDR_PHY_DATA, BW_PHY_REG, + freq_config_info.bw_per_freq << 8, 0x700)); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, access_type, if_id, bus_cnt, + DDR_PHY_DATA, RATE_PHY_REG, + freq_config_info.rate_per_freq, 0x7)); + } + + /* DUnit to Phy drive post edge, ADLL reset assert de-assert */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DRAM_PHY_CONFIGURATION, + 0, (0x80000000 | 0x40000000))); + mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ])); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DRAM_PHY_CONFIGURATION, + (0x80000000 | 0x40000000), (0x80000000 | 0x40000000))); + + /* polling for ADLL Done */ + if (ddr3_tip_if_polling(dev_num, access_type, if_id, + 0x3ff03ff, 0x3ff03ff, PHY_LOCK_STATUS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Freq_set: DDR3 poll failed(1)")); + } + + /* pup data_pup reset assert-> deassert */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG, + 0, 0x60000000)); + mdelay(10); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, SDRAM_CONFIGURATION_REG, + 0x60000000, 0x60000000)); + + return MV_OK; +} + +int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_ddr_freq frequency) +{ + u32 cl_value = 0, cwl_value = 0, mem_mask = 0, val = 0, + bus_cnt = 0, t_hclk = 0, t_wr = 0, + refresh_interval_cnt = 0, cnt_id; + u32 t_refi = 0, end_if, start_if; + u32 bus_index = 0; + int is_dll_off = 0; + enum hws_speed_bin speed_bin_index = 0; + struct hws_tip_freq_config_info freq_config_info; + enum hws_result *flow_result = training_result[training_stage]; + u32 adll_tap = 0; + u32 cs_mask[MAX_INTERFACE_NUM]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("dev %d access %d IF %d freq %d\n", dev_num, + access_type, if_id, frequency)); + + if (frequency == DDR_FREQ_LOW_FREQ) + is_dll_off = 1; + if (access_type == ACCESS_TYPE_MULTICAST) { + start_if = 0; + end_if = MAX_INTERFACE_NUM - 1; + } else { + start_if = if_id; + end_if = if_id; + } + + /* calculate interface cs mask - Oferb 4/11 */ + /* speed bin can be different for each interface */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + /* cs enable is active low */ + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + cs_mask[if_id] = CS_BIT_MASK; + training_result[training_stage][if_id] = TEST_SUCCESS; + ddr3_tip_calc_cs_mask(dev_num, if_id, effective_cs, + &cs_mask[if_id]); + } + + /* speed bin can be different for each interface */ + /* + * moti b - need to remove the loop for multicas access functions + * and loop the unicast access functions + */ + for (if_id = start_if; if_id <= end_if; if_id++) { + if (IS_ACTIVE(tm->if_act_mask, if_id) == 0) + continue; + + flow_result[if_id] = TEST_SUCCESS; + speed_bin_index = + tm->interface_params[if_id].speed_bin_index; + if (tm->interface_params[if_id].memory_freq == + frequency) { + cl_value = + tm->interface_params[if_id].cas_l; + cwl_value = + tm->interface_params[if_id].cas_wl; + } else { + cl_value = + cas_latency_table[speed_bin_index].cl_val[frequency]; + cwl_value = + cas_write_latency_table[speed_bin_index]. + cl_val[frequency]; + } + + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("Freq_set dev 0x%x access 0x%x if 0x%x freq 0x%x speed %d:\n\t", + dev_num, access_type, if_id, + frequency, speed_bin_index)); + + for (cnt_id = 0; cnt_id < DDR_FREQ_LIMIT; cnt_id++) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, + ("%d ", + cas_latency_table[speed_bin_index]. + cl_val[cnt_id])); + } + + DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("\n")); + mem_mask = 0; + for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_index++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + mem_mask |= + tm->interface_params[if_id]. + as_bus_params[bus_index].mirror_enable_bitmask; + } + + if (mem_mask != 0) { + /* motib redundent in KW28 */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, + if_id, + CS_ENABLE_REG, 0, 0x8)); + } + + /* dll state after exiting SR */ + if (is_dll_off == 1) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DFS_REG, 0x1, 0x1)); + } else { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DFS_REG, 0, 0x1)); + } + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DUNIT_MMASK_REG, 0, 0x1)); + /* DFS - block transactions */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DFS_REG, 0x2, 0x2)); + + /* disable ODT in case of dll off */ + if (is_dll_off == 1) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + 0x1874, 0, 0x244)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + 0x1884, 0, 0x244)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + 0x1894, 0, 0x244)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + 0x18a4, 0, 0x244)); + } + + /* DFS - Enter Self-Refresh */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DFS_REG, 0x4, + 0x4)); + /* polling on self refresh entry */ + if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, + if_id, 0x8, 0x8, DFS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Freq_set: DDR3 poll failed on SR entry\n")); + } + + /* PLL configuration */ + if (config_func_info[dev_num].tip_set_freq_divider_func != NULL) { + config_func_info[dev_num]. + tip_set_freq_divider_func(dev_num, if_id, + frequency); + } + + /* PLL configuration End */ + + /* adjust t_refi to new frequency */ + t_refi = (tm->interface_params[if_id].interface_temp == + HWS_TEMP_HIGH) ? TREFI_LOW : TREFI_HIGH; + t_refi *= 1000; /*psec */ + + /* HCLK in[ps] */ + t_hclk = MEGA / (freq_val[frequency] / 2); + refresh_interval_cnt = t_refi / t_hclk; /* no units */ + val = 0x4000 | refresh_interval_cnt; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_CONFIGURATION_REG, val, 0x7fff)); + + /* DFS - CL/CWL/WR parameters after exiting SR */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DFS_REG, + (cl_mask_table[cl_value] << 8), 0xf00)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DFS_REG, + (cwl_mask_table[cwl_value] << 12), 0x7000)); + t_wr = speed_bin_table(speed_bin_index, SPEED_BIN_TWR); + t_wr = (t_wr / 1000); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DFS_REG, + (twr_mask_table[t_wr + 1] << 16), 0x70000)); + + /* Restore original RTT values if returning from DLL OFF mode */ + if (is_dll_off == 1) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, 0x1874, + g_dic | g_rtt_nom, 0x266)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, 0x1884, + g_dic | g_rtt_nom, 0x266)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, 0x1894, + g_dic | g_rtt_nom, 0x266)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, 0x18a4, + g_dic | g_rtt_nom, 0x266)); + } + + /* Reset Diver_b assert -> de-assert */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_CONFIGURATION_REG, 0, 0x10000000)); + mdelay(10); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_CONFIGURATION_REG, 0x10000000, 0x10000000)); + + /* Adll configuration function of process and Frequency */ + if (config_func_info[dev_num].tip_get_freq_config_info_func != NULL) { + CHECK_STATUS(config_func_info[dev_num]. + tip_get_freq_config_info_func(dev_num, frequency, + &freq_config_info)); + } + /* TBD check milo5 using device ID ? */ + for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, bus_cnt, DDR_PHY_DATA, + 0x92, + freq_config_info. + bw_per_freq << 8 + /*freq_mask[dev_num][frequency] << 8 */ + , 0x700)); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + bus_cnt, DDR_PHY_DATA, 0x94, + freq_config_info.rate_per_freq, 0x7)); + } + + /* DUnit to Phy drive post edge, ADLL reset assert de-assert */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DRAM_PHY_CONFIGURATION, 0, + (0x80000000 | 0x40000000))); + mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ])); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + DRAM_PHY_CONFIGURATION, (0x80000000 | 0x40000000), + (0x80000000 | 0x40000000))); + + /* polling for ADLL Done */ + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x3ff03ff, + 0x3ff03ff, PHY_LOCK_STATUS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Freq_set: DDR3 poll failed(1)\n")); + } + + /* pup data_pup reset assert-> deassert */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_CONFIGURATION_REG, 0, 0x60000000)); + mdelay(10); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_CONFIGURATION_REG, 0x60000000, 0x60000000)); + + /* Set proper timing params before existing Self-Refresh */ + ddr3_tip_set_timing(dev_num, access_type, if_id, frequency); + if (delay_enable != 0) { + adll_tap = MEGA / (freq_val[frequency] * 64); + ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap); + } + + /* Exit SR */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DFS_REG, 0, + 0x4)); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x8, DFS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Freq_set: DDR3 poll failed(2)")); + } + + /* Refresh Command */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + SDRAM_OPERATION_REG, 0x2, 0xf1f)); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f, + SDRAM_OPERATION_REG, MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Freq_set: DDR3 poll failed(3)")); + } + + /* Release DFS Block */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DFS_REG, 0, + 0x2)); + /* Controller to MBUS Retry - normal */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, DUNIT_MMASK_REG, + 0x1, 0x1)); + + /* MRO: Burst Length 8, CL , Auto_precharge 0x16cc */ + val = + ((cl_mask_table[cl_value] & 0x1) << 2) | + ((cl_mask_table[cl_value] & 0xe) << 3); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, MR0_REG, + val, (0x7 << 4) | (1 << 2))); + /* MR2: CWL = 10 , Auto Self-Refresh - disable */ + val = (cwl_mask_table[cwl_value] << 3); + /* + * nklein 24.10.13 - should not be here - leave value as set in + * the init configuration val |= (1 << 9); + * val |= ((tm->interface_params[if_id]. + * interface_temp == HWS_TEMP_HIGH) ? (1 << 7) : 0); + */ + /* nklein 24.10.13 - see above comment */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, + if_id, MR2_REG, + val, (0x7 << 3))); + + /* ODT TIMING */ + val = ((cl_value - cwl_value + 1) << 4) | + ((cl_value - cwl_value + 6) << 8) | + ((cl_value - 1) << 12) | ((cl_value + 6) << 16); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, + if_id, ODT_TIMING_LOW, + val, 0xffff0)); + val = 0x71 | ((cwl_value - 1) << 8) | ((cwl_value + 5) << 12); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, + if_id, ODT_TIMING_HI_REG, + val, 0xffff)); + + /* ODT Active */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, + if_id, + DUNIT_ODT_CONTROL_REG, + 0xf, 0xf)); + + /* re-write CL */ + val = ((cl_mask_table[cl_value] & 0x1) << 2) | + ((cl_mask_table[cl_value] & 0xe) << 3); + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + 0, MR0_REG, val, + (0x7 << 4) | (1 << 2))); + + /* re-write CWL */ + val = (cwl_mask_table[cwl_value] << 3); + CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask, MRS2_CMD, + val, (0x7 << 3))); + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + 0, MR2_REG, val, (0x7 << 3))); + + if (mem_mask != 0) { + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, + if_id, + CS_ENABLE_REG, + 1 << 3, 0x8)); + } + } + + return MV_OK; +} + +/* + * Set ODT values + */ +static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type, + u32 if_id, u32 cl_value, u32 cwl_value) +{ + /* ODT TIMING */ + u32 val = (cl_value - cwl_value + 6); + + val = ((cl_value - cwl_value + 1) << 4) | ((val & 0xf) << 8) | + (((cl_value - 1) & 0xf) << 12) | + (((cl_value + 6) & 0xf) << 16) | (((val & 0x10) >> 4) << 21); + val |= (((cl_value - 1) >> 4) << 22) | (((cl_value + 6) >> 4) << 23); + + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + ODT_TIMING_LOW, val, 0xffff0)); + val = 0x71 | ((cwl_value - 1) << 8) | ((cwl_value + 5) << 12); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + ODT_TIMING_HI_REG, val, 0xffff)); + if (odt_additional == 1) { + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, + if_id, + SDRAM_ODT_CONTROL_HIGH_REG, + 0xf, 0xf)); + } + + /* ODT Active */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + DUNIT_ODT_CONTROL_REG, 0xf, 0xf)); + + return MV_OK; +} + +/* + * Set Timing values for training + */ +static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_ddr_freq frequency) +{ + u32 t_ckclk = 0, t_ras = 0; + u32 t_rcd = 0, t_rp = 0, t_wr = 0, t_wtr = 0, t_rrd = 0, t_rtp = 0, + t_rfc = 0, t_mod = 0; + u32 val = 0, page_size = 0; + enum hws_speed_bin speed_bin_index; + enum hws_mem_size memory_size = MEM_2G; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + speed_bin_index = tm->interface_params[if_id].speed_bin_index; + memory_size = tm->interface_params[if_id].memory_size; + page_size = + (tm->interface_params[if_id].bus_width == + BUS_WIDTH_8) ? page_param[memory_size]. + page_size_8bit : page_param[memory_size].page_size_16bit; + t_ckclk = (MEGA / freq_val[frequency]); + t_rrd = (page_size == 1) ? speed_bin_table(speed_bin_index, + SPEED_BIN_TRRD1K) : + speed_bin_table(speed_bin_index, SPEED_BIN_TRRD2K); + t_rrd = GET_MAX_VALUE(t_ckclk * 4, t_rrd); + t_rtp = GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index, + SPEED_BIN_TRTP)); + t_wtr = GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index, + SPEED_BIN_TWTR)); + t_ras = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index, + SPEED_BIN_TRAS), + t_ckclk); + t_rcd = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index, + SPEED_BIN_TRCD), + t_ckclk); + t_rp = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index, + SPEED_BIN_TRP), + t_ckclk); + t_wr = TIME_2_CLOCK_CYCLES(speed_bin_table(speed_bin_index, + SPEED_BIN_TWR), + t_ckclk); + t_wtr = TIME_2_CLOCK_CYCLES(t_wtr, t_ckclk); + t_rrd = TIME_2_CLOCK_CYCLES(t_rrd, t_ckclk); + t_rtp = TIME_2_CLOCK_CYCLES(t_rtp, t_ckclk); + t_rfc = TIME_2_CLOCK_CYCLES(rfc_table[memory_size] * 1000, t_ckclk); + t_mod = GET_MAX_VALUE(t_ckclk * 24, 15000); + t_mod = TIME_2_CLOCK_CYCLES(t_mod, t_ckclk); + + /* SDRAM Timing Low */ + val = (t_ras & 0xf) | (t_rcd << 4) | (t_rp << 8) | (t_wr << 12) | + (t_wtr << 16) | (((t_ras & 0x30) >> 4) << 20) | (t_rrd << 24) | + (t_rtp << 28); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_LOW_REG, val, 0xff3fffff)); + + /* SDRAM Timing High */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + t_rfc & 0x7f, 0x7f)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + 0x180, 0x180)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + 0x600, 0x600)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + 0x1800, 0xf800)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + ((t_rfc & 0x380) >> 7) << 16, 0x70000)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, 0, + 0x380000)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + (t_mod & 0xf) << 25, 0x1e00000)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + (t_mod >> 4) << 30, 0xc0000000)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + 0x16000000, 0x1e000000)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + SDRAM_TIMING_HIGH_REG, + 0x40000000, 0xc0000000)); + + return MV_OK; +} + +/* + * Mode Read + */ +int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info) +{ + u32 ret; + + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + MR0_REG, mode_info->reg_mr0, MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + MR1_REG, mode_info->reg_mr1, MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + MR2_REG, mode_info->reg_mr2, MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + MR3_REG, mode_info->reg_mr2, MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + READ_DATA_SAMPLE_DELAY, mode_info->read_data_sample, + MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + READ_DATA_READY_DELAY, mode_info->read_data_ready, + MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + + return MV_OK; +} + +/* + * Get first active IF + */ +int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask, + u32 *interface_id) +{ + u32 if_id; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (interface_mask & (1 << if_id)) { + *interface_id = if_id; + break; + } + } + + return MV_OK; +} + +/* + * Write CS Result + */ +int ddr3_tip_write_cs_result(u32 dev_num, u32 offset) +{ + u32 if_id, bus_num, cs_bitmask, data_val, cs_num; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_num = 0; bus_num < tm->num_of_bus_per_interface; + bus_num++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_num); + cs_bitmask = + tm->interface_params[if_id]. + as_bus_params[bus_num].cs_bitmask; + if (cs_bitmask != effective_cs) { + cs_num = GET_CS_FROM_MASK(cs_bitmask); + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_num, + DDR_PHY_DATA, + offset + + CS_REG_VALUE(effective_cs), + &data_val); + ddr3_tip_bus_write(dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + bus_num, DDR_PHY_DATA, + offset + + CS_REG_VALUE(cs_num), + data_val); + } + } + } + + return MV_OK; +} + +/* + * Write MRS + */ +int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, u32 cmd, + u32 data, u32 mask) +{ + u32 if_id, reg; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + reg = (cmd == MRS1_CMD) ? MR1_REG : MR2_REG; + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, reg, data, mask)); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + SDRAM_OPERATION_REG, + (cs_mask_arr[if_id] << 8) | cmd, 0xf1f)); + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0, + 0x1f, SDRAM_OPERATION_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("write_mrs_cmd: Poll cmd fail")); + } + } + + return MV_OK; +} + +/* + * Reset XSB Read FIFO + */ +int ddr3_tip_reset_fifo_ptr(u32 dev_num) +{ + u32 if_id = 0; + + /* Configure PHY reset value to 0 in order to "clean" the FIFO */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + if_id, 0x15c8, 0, 0xff000000)); + /* + * Move PHY to RL mode (only in RL mode the PHY overrides FIFO values + * during FIFO reset) + */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + if_id, TRAINING_SW_2_REG, + 0x1, 0x9)); + /* In order that above configuration will influence the PHY */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + if_id, 0x15b0, + 0x80000000, 0x80000000)); + /* Reset read fifo assertion */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + if_id, 0x1400, 0, 0x40000000)); + /* Reset read fifo deassertion */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + if_id, 0x1400, + 0x40000000, 0x40000000)); + /* Move PHY back to functional mode */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + if_id, TRAINING_SW_2_REG, + 0x8, 0x9)); + /* Stop training machine */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + if_id, 0x15b4, 0x10000, 0x10000)); + + return MV_OK; +} + +/* + * Reset Phy registers + */ +int ddr3_tip_ddr3_reset_phy_regs(u32 dev_num) +{ + u32 if_id, phy_id, cs; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (phy_id = 0; phy_id < tm->num_of_bus_per_interface; + phy_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, phy_id); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + phy_id, DDR_PHY_DATA, + WL_PHY_REG + + CS_REG_VALUE(effective_cs), + phy_reg0_val)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA, + RL_PHY_REG + CS_REG_VALUE(effective_cs), + phy_reg2_val)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA, + READ_CENTRALIZATION_PHY_REG + + CS_REG_VALUE(effective_cs), phy_reg3_val)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, phy_id, DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + CS_REG_VALUE(effective_cs), phy_reg3_val)); + } + } + + /* Set Receiver Calibration value */ + for (cs = 0; cs < MAX_CS_NUM; cs++) { + /* PHY register 0xdb bits[5:0] - configure to 63 */ + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + DDR_PHY_DATA, CSN_IOB_VREF_REG(cs), 63)); + } + + return MV_OK; +} + +/* + * Restore Dunit registers + */ +int ddr3_tip_restore_dunit_regs(u32 dev_num) +{ + u32 index_cnt; + + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, CALIB_MACHINE_CTRL_REG, + 0x1, 0x1)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, CALIB_MACHINE_CTRL_REG, + calibration_update_control << 3, + 0x3 << 3)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + ODPG_WRITE_READ_MODE_ENABLE_REG, + 0xffff, MASK_ALL_BITS)); + + for (index_cnt = 0; index_cnt < ARRAY_SIZE(odpg_default_value); + index_cnt++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + odpg_default_value[index_cnt].reg_addr, + odpg_default_value[index_cnt].reg_data, + odpg_default_value[index_cnt].reg_mask)); + } + + return MV_OK; +} + +/* + * Auto tune main flow + */ +static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) +{ + enum hws_ddr_freq freq = init_freq; + struct init_cntr_param init_cntr_prm; + int ret = MV_OK; + u32 if_id; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + +#ifndef EXCLUDE_SWITCH_DEBUG + if (debug_training == DEBUG_LEVEL_TRACE) { + CHECK_STATUS(print_device_info((u8)dev_num)); + } +#endif + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + CHECK_STATUS(ddr3_tip_ddr3_reset_phy_regs(dev_num)); + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + freq = init_freq; + if (is_pll_before_init != 0) { + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + config_func_info[dev_num].tip_set_freq_divider_func( + (u8)dev_num, if_id, freq); + } + } + + if (is_adll_calib_before_init != 0) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("with adll calib before init\n")); + adll_calibration(dev_num, ACCESS_TYPE_MULTICAST, 0, freq); + } + + if (is_reg_dump != 0) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("Dump before init controller\n")); + ddr3_tip_reg_dump(dev_num); + } + + if (mask_tune_func & INIT_CONTROLLER_MASK_BIT) { + training_stage = INIT_CONTROLLER; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("INIT_CONTROLLER_MASK_BIT\n")); + init_cntr_prm.do_mrs_phy = 1; + init_cntr_prm.is_ctrl64_bit = 0; + init_cntr_prm.init_phy = 1; + init_cntr_prm.msys_init = 0; + ret = hws_ddr3_tip_init_controller(dev_num, &init_cntr_prm); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("hws_ddr3_tip_init_controller failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + +#ifdef STATIC_ALGO_SUPPORT + if (mask_tune_func & STATIC_LEVELING_MASK_BIT) { + training_stage = STATIC_LEVELING; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("STATIC_LEVELING_MASK_BIT\n")); + ret = ddr3_tip_run_static_alg(dev_num, freq); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_run_static_alg failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } +#endif + + if (mask_tune_func & SET_LOW_FREQ_MASK_BIT) { + training_stage = SET_LOW_FREQ; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("SET_LOW_FREQ_MASK_BIT %d\n", + freq_val[low_freq])); + ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, low_freq); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_freq_set failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & LOAD_PATTERN_MASK_BIT) { + training_stage = LOAD_PATTERN; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("LOAD_PATTERN_MASK_BIT #%d\n", + effective_cs)); + ret = ddr3_tip_load_all_pattern_to_mem(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_load_all_pattern_to_mem failure CS #%d\n", + effective_cs)); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + if (mask_tune_func & SET_MEDIUM_FREQ_MASK_BIT) { + training_stage = SET_MEDIUM_FREQ; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("SET_MEDIUM_FREQ_MASK_BIT %d\n", + freq_val[medium_freq])); + ret = + ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, medium_freq); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_freq_set failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + if (mask_tune_func & WRITE_LEVELING_MASK_BIT) { + training_stage = WRITE_LEVELING; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("WRITE_LEVELING_MASK_BIT\n")); + if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) { + ret = ddr3_tip_dynamic_write_leveling(dev_num); + } else { + /* Use old WL */ + ret = ddr3_tip_legacy_dynamic_write_leveling(dev_num); + } + + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_dynamic_write_leveling failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & LOAD_PATTERN_2_MASK_BIT) { + training_stage = LOAD_PATTERN_2; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("LOAD_PATTERN_2_MASK_BIT CS #%d\n", + effective_cs)); + ret = ddr3_tip_load_all_pattern_to_mem(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_load_all_pattern_to_mem failure CS #%d\n", + effective_cs)); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + if (mask_tune_func & READ_LEVELING_MASK_BIT) { + training_stage = READ_LEVELING; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("READ_LEVELING_MASK_BIT\n")); + if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) { + ret = ddr3_tip_dynamic_read_leveling(dev_num, medium_freq); + } else { + /* Use old RL */ + ret = ddr3_tip_legacy_dynamic_read_leveling(dev_num); + } + + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_dynamic_read_leveling failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + if (mask_tune_func & WRITE_LEVELING_SUPP_MASK_BIT) { + training_stage = WRITE_LEVELING_SUPP; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("WRITE_LEVELING_SUPP_MASK_BIT\n")); + ret = ddr3_tip_dynamic_write_leveling_supp(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_dynamic_write_leveling_supp failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & PBS_RX_MASK_BIT) { + training_stage = PBS_RX; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("PBS_RX_MASK_BIT CS #%d\n", + effective_cs)); + ret = ddr3_tip_pbs_rx(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_pbs_rx failure CS #%d\n", + effective_cs)); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & PBS_TX_MASK_BIT) { + training_stage = PBS_TX; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("PBS_TX_MASK_BIT CS #%d\n", + effective_cs)); + ret = ddr3_tip_pbs_tx(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_pbs_tx failure CS #%d\n", + effective_cs)); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + if (mask_tune_func & SET_TARGET_FREQ_MASK_BIT) { + training_stage = SET_TARGET_FREQ; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("SET_TARGET_FREQ_MASK_BIT %d\n", + freq_val[tm-> + interface_params[first_active_if]. + memory_freq])); + ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + tm->interface_params[first_active_if]. + memory_freq); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_freq_set failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + if (mask_tune_func & WRITE_LEVELING_TF_MASK_BIT) { + training_stage = WRITE_LEVELING_TF; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("WRITE_LEVELING_TF_MASK_BIT\n")); + ret = ddr3_tip_dynamic_write_leveling(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_dynamic_write_leveling TF failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + if (mask_tune_func & LOAD_PATTERN_HIGH_MASK_BIT) { + training_stage = LOAD_PATTERN_HIGH; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("LOAD_PATTERN_HIGH\n")); + ret = ddr3_tip_load_all_pattern_to_mem(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_load_all_pattern_to_mem failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + if (mask_tune_func & READ_LEVELING_TF_MASK_BIT) { + training_stage = READ_LEVELING_TF; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("READ_LEVELING_TF_MASK_BIT\n")); + ret = ddr3_tip_dynamic_read_leveling(dev_num, tm-> + interface_params[first_active_if]. + memory_freq); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_dynamic_read_leveling TF failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + + if (mask_tune_func & DM_PBS_TX_MASK_BIT) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("DM_PBS_TX_MASK_BIT\n")); + } + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & VREF_CALIBRATION_MASK_BIT) { + training_stage = VREF_CALIBRATION; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("VREF\n")); + ret = ddr3_tip_vref(dev_num); + if (is_reg_dump != 0) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("VREF Dump\n")); + ddr3_tip_reg_dump(dev_num); + } + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_vref failure\n")); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & CENTRALIZATION_RX_MASK_BIT) { + training_stage = CENTRALIZATION_RX; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("CENTRALIZATION_RX_MASK_BIT CS #%d\n", + effective_cs)); + ret = ddr3_tip_centralization_rx(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_centralization_rx failure CS #%d\n", + effective_cs)); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & WRITE_LEVELING_SUPP_TF_MASK_BIT) { + training_stage = WRITE_LEVELING_SUPP_TF; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("WRITE_LEVELING_SUPP_TF_MASK_BIT CS #%d\n", + effective_cs)); + ret = ddr3_tip_dynamic_write_leveling_supp(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_dynamic_write_leveling_supp TF failure CS #%d\n", + effective_cs)); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + if (mask_tune_func & CENTRALIZATION_TX_MASK_BIT) { + training_stage = CENTRALIZATION_TX; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("CENTRALIZATION_TX_MASK_BIT CS #%d\n", + effective_cs)); + ret = ddr3_tip_centralization_tx(dev_num); + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + if (ret != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("ddr3_tip_centralization_tx failure CS #%d\n", + effective_cs)); + if (debug_mode == 0) + return MV_FAIL; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("restore registers to default\n")); + /* restore register values */ + CHECK_STATUS(ddr3_tip_restore_dunit_regs(dev_num)); + + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + + return MV_OK; +} + +/* + * DDR3 Dynamic training flow + */ +static int ddr3_tip_ddr3_auto_tune(u32 dev_num) +{ + u32 if_id, stage, ret; + int is_if_fail = 0, is_auto_tune_fail = 0; + + training_stage = INIT_CONTROLLER; + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + for (stage = 0; stage < MAX_STAGE_LIMIT; stage++) + training_result[stage][if_id] = NO_TEST_DONE; + } + + ret = ddr3_tip_ddr3_training_main_flow(dev_num); + + /* activate XSB test */ + if (xsb_validate_type != 0) { + run_xsb_test(dev_num, xsb_validation_base_address, 1, 1, + 0x1024); + } + + if (is_reg_dump != 0) + ddr3_tip_reg_dump(dev_num); + + /* print log */ + CHECK_STATUS(ddr3_tip_print_log(dev_num, window_mem_addr)); + + if (ret != MV_OK) { + CHECK_STATUS(ddr3_tip_print_stability_log(dev_num)); + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + is_if_fail = 0; + for (stage = 0; stage < MAX_STAGE_LIMIT; stage++) { + if (training_result[stage][if_id] == TEST_FAILED) + is_if_fail = 1; + } + if (is_if_fail == 1) { + is_auto_tune_fail = 1; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, + ("Auto Tune failed for IF %d\n", + if_id)); + } + } + + if ((ret == MV_FAIL) || (is_auto_tune_fail == 1)) + return MV_FAIL; + else + return MV_OK; +} + +/* + * Enable init sequence + */ +int ddr3_tip_enable_init_sequence(u32 dev_num) +{ + int is_fail = 0; + u32 if_id = 0, mem_mask = 0, bus_index = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* Enable init sequence */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, 0, + SDRAM_INIT_CONTROL_REG, 0x1, 0x1)); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1, + SDRAM_INIT_CONTROL_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("polling failed IF %d\n", + if_id)); + is_fail = 1; + continue; + } + + mem_mask = 0; + for (bus_index = 0; bus_index < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_index++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + mem_mask |= + tm->interface_params[if_id]. + as_bus_params[bus_index].mirror_enable_bitmask; + } + + if (mem_mask != 0) { + /* Disable Multi CS */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, + if_id, CS_ENABLE_REG, 1 << 3, + 1 << 3)); + } + } + + return (is_fail == 0) ? MV_OK : MV_FAIL; +} + +int ddr3_tip_register_dq_table(u32 dev_num, u32 *table) +{ + dq_map_table = table; + + return MV_OK; +} + +/* + * Check if pup search is locked + */ +int ddr3_tip_is_pup_lock(u32 *pup_buf, enum hws_training_result read_mode) +{ + u32 bit_start = 0, bit_end = 0, bit_id; + + if (read_mode == RESULT_PER_BIT) { + bit_start = 0; + bit_end = BUS_WIDTH_IN_BITS - 1; + } else { + bit_start = 0; + bit_end = 0; + } + + for (bit_id = bit_start; bit_id <= bit_end; bit_id++) { + if (GET_LOCK_RESULT(pup_buf[bit_id]) == 0) + return 0; + } + + return 1; +} + +/* + * Get minimum buffer value + */ +u8 ddr3_tip_get_buf_min(u8 *buf_ptr) +{ + u8 min_val = 0xff; + u8 cnt = 0; + + for (cnt = 0; cnt < BUS_WIDTH_IN_BITS; cnt++) { + if (buf_ptr[cnt] < min_val) + min_val = buf_ptr[cnt]; + } + + return min_val; +} + +/* + * Get maximum buffer value + */ +u8 ddr3_tip_get_buf_max(u8 *buf_ptr) +{ + u8 max_val = 0; + u8 cnt = 0; + + for (cnt = 0; cnt < BUS_WIDTH_IN_BITS; cnt++) { + if (buf_ptr[cnt] > max_val) + max_val = buf_ptr[cnt]; + } + + return max_val; +} + +/* + * The following functions return memory parameters: + * bus and device width, device size + */ + +u32 hws_ddr3_get_bus_width(void) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + return (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == + 1) ? 16 : 32; +} + +u32 hws_ddr3_get_device_width(u32 if_id) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + return (tm->interface_params[if_id].bus_width == + BUS_WIDTH_8) ? 8 : 16; +} + +u32 hws_ddr3_get_device_size(u32 if_id) +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (tm->interface_params[if_id].memory_size >= + MEM_SIZE_LAST) { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Error: Wrong device size of Cs: %d", + tm->interface_params[if_id].memory_size)); + return 0; + } else { + return 1 << tm->interface_params[if_id].memory_size; + } +} + +int hws_ddr3_calc_mem_cs_size(u32 if_id, u32 cs, u32 *cs_size) +{ + u32 cs_mem_size, dev_size; + + dev_size = hws_ddr3_get_device_size(if_id); + if (dev_size != 0) { + cs_mem_size = ((hws_ddr3_get_bus_width() / + hws_ddr3_get_device_width(if_id)) * dev_size); + + /* the calculated result in Gbytex16 to avoid float using */ + + if (cs_mem_size == 2) { + *cs_size = _128M; + } else if (cs_mem_size == 4) { + *cs_size = _256M; + } else if (cs_mem_size == 8) { + *cs_size = _512M; + } else if (cs_mem_size == 16) { + *cs_size = _1G; + } else if (cs_mem_size == 32) { + *cs_size = _2G; + } else { + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Error: Wrong Memory size of Cs: %d", cs)); + return MV_FAIL; + } + return MV_OK; + } else { + return MV_FAIL; + } +} + +int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr) +{ + u32 cs_mem_size = 0; +#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE + u32 physical_mem_size; + u32 max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE; +#endif + + if (hws_ddr3_calc_mem_cs_size(if_id, cs, &cs_mem_size) != MV_OK) + return MV_FAIL; + +#ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE + struct hws_topology_map *tm = ddr3_get_topology_map(); + /* + * if number of address pins doesn't allow to use max mem size that + * is defined in topology mem size is defined by + * DEVICE_MAX_DRAM_ADDRESS_SIZE + */ + physical_mem_size = + mv_hwsmem_size[tm->interface_params[0].memory_size]; + + if (hws_ddr3_get_device_width(cs) == 16) { + /* + * 16bit mem device can be twice more - no need in less + * significant pin + */ + max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE * 2; + } + + if (physical_mem_size > max_mem_size) { + cs_mem_size = max_mem_size * + (hws_ddr3_get_bus_width() / + hws_ddr3_get_device_width(if_id)); + DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, + ("Updated Physical Mem size is from 0x%x to %x\n", + physical_mem_size, + DEVICE_MAX_DRAM_ADDRESS_SIZE)); + } +#endif + + /* calculate CS base addr */ + *cs_base_addr = ((cs_mem_size) * cs) & 0xffff0000; + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_bist.c b/drivers/ddr/marvell/a38x/ddr3_training_bist.c new file mode 100644 index 0000000..bd0e260 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_bist.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +static u32 bist_offset = 32; +enum hws_pattern sweep_pattern = PATTERN_KILLER_DQ0; + +static int ddr3_tip_bist_operation(u32 dev_num, + enum hws_access_type access_type, + u32 if_id, + enum hws_bist_operation oper_type); + +/* + * BIST activate + */ +int ddr3_tip_bist_activate(u32 dev_num, enum hws_pattern pattern, + enum hws_access_type access_type, u32 if_num, + enum hws_dir direction, + enum hws_stress_jump addr_stress_jump, + enum hws_pattern_duration duration, + enum hws_bist_operation oper_type, + u32 offset, u32 cs_num, u32 pattern_addr_length) +{ + u32 tx_burst_size; + u32 delay_between_burst; + u32 rd_mode, val; + u32 poll_cnt = 0, max_poll = 1000, i, start_if, end_if; + struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); + u32 read_data[MAX_INTERFACE_NUM]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* ODPG Write enable from BIST */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num, + ODPG_DATA_CONTROL_REG, 0x1, 0x1)); + /* ODPG Read enable/disable from BIST */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num, + ODPG_DATA_CONTROL_REG, + (direction == OPER_READ) ? + 0x2 : 0, 0x2)); + CHECK_STATUS(ddr3_tip_load_pattern_to_odpg(dev_num, access_type, if_num, + pattern, offset)); + + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num, + ODPG_DATA_BUF_SIZE_REG, + pattern_addr_length, MASK_ALL_BITS)); + tx_burst_size = (direction == OPER_WRITE) ? + pattern_table[pattern].tx_burst_size : 0; + delay_between_burst = (direction == OPER_WRITE) ? 2 : 0; + rd_mode = (direction == OPER_WRITE) ? 1 : 0; + CHECK_STATUS(ddr3_tip_configure_odpg + (dev_num, access_type, if_num, direction, + pattern_table[pattern].num_of_phases_tx, tx_burst_size, + pattern_table[pattern].num_of_phases_rx, + delay_between_burst, + rd_mode, cs_num, addr_stress_jump, duration)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num, + ODPG_PATTERN_ADDR_OFFSET_REG, + offset, MASK_ALL_BITS)); + if (oper_type == BIST_STOP) { + CHECK_STATUS(ddr3_tip_bist_operation(dev_num, access_type, + if_num, BIST_STOP)); + } else { + CHECK_STATUS(ddr3_tip_bist_operation(dev_num, access_type, + if_num, BIST_START)); + if (duration != DURATION_CONT) { + /* + * This pdelay is a WA, becuase polling fives "done" + * also the odpg did nmot finish its task + */ + if (access_type == ACCESS_TYPE_MULTICAST) { + start_if = 0; + end_if = MAX_INTERFACE_NUM - 1; + } else { + start_if = if_num; + end_if = if_num; + } + + for (i = start_if; i <= end_if; i++) { + VALIDATE_ACTIVE(tm-> + if_act_mask, i); + + for (poll_cnt = 0; poll_cnt < max_poll; + poll_cnt++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_UNICAST, + if_num, ODPG_BIST_DONE, + read_data, + MASK_ALL_BITS)); + val = read_data[i]; + if ((val & 0x1) == 0x0) { + /* + * In SOC type devices this bit + * is self clear so, if it was + * cleared all good + */ + break; + } + } + + if (poll_cnt >= max_poll) { + DEBUG_TRAINING_BIST_ENGINE + (DEBUG_LEVEL_ERROR, + ("Bist poll failure 2\n")); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_num, + ODPG_DATA_CONTROL_REG, 0, + MASK_ALL_BITS)); + return MV_FAIL; + } + } + + CHECK_STATUS(ddr3_tip_bist_operation + (dev_num, access_type, if_num, BIST_STOP)); + } + } + + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_num, + ODPG_DATA_CONTROL_REG, 0, + MASK_ALL_BITS)); + + return MV_OK; +} + +/* + * BIST read result + */ +int ddr3_tip_bist_read_result(u32 dev_num, u32 if_id, + struct bist_result *pst_bist_result) +{ + int ret; + u32 read_data[MAX_INTERFACE_NUM]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (IS_ACTIVE(tm->if_act_mask, if_id) == 0) + return MV_NOT_SUPPORTED; + DEBUG_TRAINING_BIST_ENGINE(DEBUG_LEVEL_TRACE, + ("ddr3_tip_bist_read_result if_id %d\n", + if_id)); + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_BIST_FAILED_DATA_HI_REG, read_data, + MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + pst_bist_result->bist_fail_high = read_data[if_id]; + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_BIST_FAILED_DATA_LOW_REG, read_data, + MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + pst_bist_result->bist_fail_low = read_data[if_id]; + + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_BIST_LAST_FAIL_ADDR_REG, read_data, + MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + pst_bist_result->bist_last_fail_addr = read_data[if_id]; + ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_BIST_DATA_ERROR_COUNTER_REG, read_data, + MASK_ALL_BITS); + if (ret != MV_OK) + return ret; + pst_bist_result->bist_error_cnt = read_data[if_id]; + + return MV_OK; +} + +/* + * BIST flow - Activate & read result + */ +int hws_ddr3_run_bist(u32 dev_num, enum hws_pattern pattern, u32 *result, + u32 cs_num) +{ + int ret; + u32 i = 0; + u32 win_base; + struct bist_result st_bist_result; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (i = 0; i < MAX_INTERFACE_NUM; i++) { + VALIDATE_ACTIVE(tm->if_act_mask, i); + hws_ddr3_cs_base_adr_calc(i, cs_num, &win_base); + ret = ddr3_tip_bist_activate(dev_num, pattern, + ACCESS_TYPE_UNICAST, + i, OPER_WRITE, STRESS_NONE, + DURATION_SINGLE, BIST_START, + bist_offset + win_base, + cs_num, 15); + if (ret != MV_OK) { + printf("ddr3_tip_bist_activate failed (0x%x)\n", ret); + return ret; + } + + ret = ddr3_tip_bist_activate(dev_num, pattern, + ACCESS_TYPE_UNICAST, + i, OPER_READ, STRESS_NONE, + DURATION_SINGLE, BIST_START, + bist_offset + win_base, + cs_num, 15); + if (ret != MV_OK) { + printf("ddr3_tip_bist_activate failed (0x%x)\n", ret); + return ret; + } + + ret = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result); + if (ret != MV_OK) { + printf("ddr3_tip_bist_read_result failed\n"); + return ret; + } + result[i] = st_bist_result.bist_error_cnt; + } + + return MV_OK; +} + +/* + * Set BIST Operation + */ + +static int ddr3_tip_bist_operation(u32 dev_num, + enum hws_access_type access_type, + u32 if_id, enum hws_bist_operation oper_type) +{ + if (oper_type == BIST_STOP) { + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + ODPG_BIST_DONE, 1 << 8, 1 << 8)); + } else { + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + ODPG_BIST_DONE, 1, 1)); + } + + return MV_OK; +} + +/* + * Print BIST result + */ +void ddr3_tip_print_bist_res(void) +{ + u32 dev_num = 0; + u32 i; + struct bist_result st_bist_result[MAX_INTERFACE_NUM]; + int res; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (i = 0; i < MAX_INTERFACE_NUM; i++) { + if (IS_ACTIVE(tm->if_act_mask, i) == 0) + continue; + + res = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result[i]); + if (res != MV_OK) { + DEBUG_TRAINING_BIST_ENGINE( + DEBUG_LEVEL_ERROR, + ("ddr3_tip_bist_read_result failed\n")); + return; + } + } + + DEBUG_TRAINING_BIST_ENGINE( + DEBUG_LEVEL_INFO, + ("interface | error_cnt | fail_low | fail_high | fail_addr\n")); + + for (i = 0; i < MAX_INTERFACE_NUM; i++) { + if (IS_ACTIVE(tm->if_act_mask, i) == + 0) + continue; + + DEBUG_TRAINING_BIST_ENGINE( + DEBUG_LEVEL_INFO, + ("%d | 0x%08x | 0x%08x | 0x%08x | 0x%08x\n", + i, st_bist_result[i].bist_error_cnt, + st_bist_result[i].bist_fail_low, + st_bist_result[i].bist_fail_high, + st_bist_result[i].bist_last_fail_addr)); + } +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c new file mode 100644 index 0000000..9d216da --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c @@ -0,0 +1,714 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define VALIDATE_WIN_LENGTH(e1, e2, maxsize) \ + (((e2) + 1 > (e1) + (u8)MIN_WINDOW_SIZE) && \ + ((e2) + 1 < (e1) + (u8)maxsize)) +#define IS_WINDOW_OUT_BOUNDARY(e1, e2, maxsize) \ + (((e1) == 0 && (e2) != 0) || \ + ((e1) != (maxsize - 1) && (e2) == (maxsize - 1))) +#define CENTRAL_TX 0 +#define CENTRAL_RX 1 +#define NUM_OF_CENTRAL_TYPES 2 + +u32 start_pattern = PATTERN_KILLER_DQ0, end_pattern = PATTERN_KILLER_DQ7; +u32 start_if = 0, end_if = (MAX_INTERFACE_NUM - 1); +u8 bus_end_window[NUM_OF_CENTRAL_TYPES][MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 bus_start_window[NUM_OF_CENTRAL_TYPES][MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 centralization_state[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +static u8 ddr3_tip_special_rx_run_once_flag; + +static int ddr3_tip_centralization(u32 dev_num, u32 mode); + +/* + * Centralization RX Flow + */ +int ddr3_tip_centralization_rx(u32 dev_num) +{ + CHECK_STATUS(ddr3_tip_special_rx(dev_num)); + CHECK_STATUS(ddr3_tip_centralization(dev_num, CENTRAL_RX)); + + return MV_OK; +} + +/* + * Centralization TX Flow + */ +int ddr3_tip_centralization_tx(u32 dev_num) +{ + CHECK_STATUS(ddr3_tip_centralization(dev_num, CENTRAL_TX)); + + return MV_OK; +} + +/* + * Centralization Flow + */ +static int ddr3_tip_centralization(u32 dev_num, u32 mode) +{ + enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM]; + u32 if_id, pattern_id, bit_id; + u8 bus_id; + u8 cur_start_win[BUS_WIDTH_IN_BITS]; + u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS]; + u8 cur_end_win[BUS_WIDTH_IN_BITS]; + u8 current_window[BUS_WIDTH_IN_BITS]; + u8 opt_window, waste_window, start_window_skew, end_window_skew; + u8 final_pup_window[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + enum hws_training_result result_type = RESULT_PER_BIT; + enum hws_dir direction; + u32 *result[HWS_SEARCH_DIR_LIMIT]; + u32 reg_phy_off, reg; + u8 max_win_size; + int lock_success = 1; + u8 cur_end_win_min, cur_start_win_max; + u32 cs_enable_reg_val[MAX_INTERFACE_NUM]; + int is_if_fail = 0; + enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage); + u32 pup_win_length = 0; + enum hws_search_dir search_dir_id; + u8 cons_tap = (mode == CENTRAL_TX) ? (64) : (0); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* save current cs enable reg val */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS)); + /* enable single cs */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, (1 << 3), (1 << 3))); + } + + if (mode == CENTRAL_TX) { + max_win_size = MAX_WINDOW_SIZE_TX; + reg_phy_off = WRITE_CENTRALIZATION_PHY_REG + (effective_cs * 4); + direction = OPER_WRITE; + } else { + max_win_size = MAX_WINDOW_SIZE_RX; + reg_phy_off = READ_CENTRALIZATION_PHY_REG + (effective_cs * 4); + direction = OPER_READ; + } + + /* DB initialization */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; + bus_id < tm->num_of_bus_per_interface; bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + centralization_state[if_id][bus_id] = 0; + bus_end_window[mode][if_id][bus_id] = + (max_win_size - 1) + cons_tap; + bus_start_window[mode][if_id][bus_id] = 0; + centralization_result[if_id][bus_id] = 0; + } + } + + /* start flow */ + for (pattern_id = start_pattern; pattern_id <= end_pattern; + pattern_id++) { + ddr3_tip_ip_training_wrapper(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, result_type, + HWS_CONTROL_ELEMENT_ADLL, + PARAM_NOT_CARE, direction, + tm-> + if_act_mask, 0x0, + max_win_size - 1, + max_win_size - 1, + pattern_id, EDGE_FPF, CS_SINGLE, + PARAM_NOT_CARE, training_result); + + for (if_id = start_if; if_id <= end_if; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; + bus_id <= tm->num_of_bus_per_interface - 1; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + + for (search_dir_id = HWS_LOW2HIGH; + search_dir_id <= HWS_HIGH2LOW; + search_dir_id++) { + CHECK_STATUS + (ddr3_tip_read_training_result + (dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + ALL_BITS_PER_PUP, + search_dir_id, + direction, result_type, + TRAINING_LOAD_OPERATION_UNLOAD, + CS_SINGLE, + &result[search_dir_id], + 1, 0, 0)); + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("%s pat %d IF %d pup %d Regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + ((mode == + CENTRAL_TX) ? "TX" : "RX"), + pattern_id, if_id, bus_id, + result[search_dir_id][0], + result[search_dir_id][1], + result[search_dir_id][2], + result[search_dir_id][3], + result[search_dir_id][4], + result[search_dir_id][5], + result[search_dir_id][6], + result[search_dir_id][7])); + } + + for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; + bit_id++) { + /* check if this code is valid for 2 edge, probably not :( */ + cur_start_win[bit_id] = + GET_TAP_RESULT(result + [HWS_LOW2HIGH] + [bit_id], + EDGE_1); + cur_end_win[bit_id] = + GET_TAP_RESULT(result + [HWS_HIGH2LOW] + [bit_id], + EDGE_1); + /* window length */ + current_window[bit_id] = + cur_end_win[bit_id] - + cur_start_win[bit_id] + 1; + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_TRACE, + ("cs %x patern %d IF %d pup %d cur_start_win %d cur_end_win %d current_window %d\n", + effective_cs, pattern_id, + if_id, bus_id, + cur_start_win[bit_id], + cur_end_win[bit_id], + current_window[bit_id])); + } + + if ((ddr3_tip_is_pup_lock + (result[HWS_LOW2HIGH], result_type)) && + (ddr3_tip_is_pup_lock + (result[HWS_HIGH2LOW], result_type))) { + /* read result success */ + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("Pup locked, pat %d IF %d pup %d\n", + pattern_id, if_id, bus_id)); + } else { + /* read result failure */ + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("fail Lock, pat %d IF %d pup %d\n", + pattern_id, if_id, bus_id)); + if (centralization_state[if_id][bus_id] + == 1) { + /* continue with next pup */ + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_TRACE, + ("continue to next pup %d %d\n", + if_id, bus_id)); + continue; + } + + for (bit_id = 0; + bit_id < BUS_WIDTH_IN_BITS; + bit_id++) { + /* + * the next check is relevant + * only when using search + * machine 2 edges + */ + if (cur_start_win[bit_id] > 0 && + cur_end_win[bit_id] == 0) { + cur_end_win + [bit_id] = + max_win_size - 1; + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_TRACE, + ("fail, IF %d pup %d bit %d fail #1\n", + if_id, bus_id, + bit_id)); + /* the next bit */ + continue; + } else { + centralization_state + [if_id][bus_id] = 1; + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_TRACE, + ("fail, IF %d pup %d bit %d fail #2\n", + if_id, bus_id, + bit_id)); + } + } + + if (centralization_state[if_id][bus_id] + == 1) { + /* going to next pup */ + continue; + } + } /*bit */ + + opt_window = + ddr3_tip_get_buf_min(current_window); + /* final pup window length */ + final_pup_window[if_id][bus_id] = + ddr3_tip_get_buf_min(cur_end_win) - + ddr3_tip_get_buf_max(cur_start_win) + + 1; + waste_window = + opt_window - + final_pup_window[if_id][bus_id]; + start_window_skew = + ddr3_tip_get_buf_max(cur_start_win) - + ddr3_tip_get_buf_min( + cur_start_win); + end_window_skew = + ddr3_tip_get_buf_max( + cur_end_win) - + ddr3_tip_get_buf_min( + cur_end_win); + /* min/max updated with pattern change */ + cur_end_win_min = + ddr3_tip_get_buf_min( + cur_end_win); + cur_start_win_max = + ddr3_tip_get_buf_max( + cur_start_win); + bus_end_window[mode][if_id][bus_id] = + GET_MIN(bus_end_window[mode][if_id] + [bus_id], + cur_end_win_min); + bus_start_window[mode][if_id][bus_id] = + GET_MAX(bus_start_window[mode][if_id] + [bus_id], + cur_start_win_max); + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_INFO, + ("pat %d IF %d pup %d opt_win %d final_win %d waste_win %d st_win_skew %d end_win_skew %d cur_st_win_max %d cur_end_win_min %d bus_st_win %d bus_end_win %d\n", + pattern_id, if_id, bus_id, opt_window, + final_pup_window[if_id][bus_id], + waste_window, start_window_skew, + end_window_skew, + cur_start_win_max, + cur_end_win_min, + bus_start_window[mode][if_id][bus_id], + bus_end_window[mode][if_id][bus_id])); + + /* check if window is valid */ + if (ddr3_tip_centr_skip_min_win_check == 0) { + if ((VALIDATE_WIN_LENGTH + (bus_start_window[mode][if_id] + [bus_id], + bus_end_window[mode][if_id] + [bus_id], + max_win_size) == 1) || + (IS_WINDOW_OUT_BOUNDARY + (bus_start_window[mode][if_id] + [bus_id], + bus_end_window[mode][if_id] + [bus_id], + max_win_size) == 1)) { + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("win valid, pat %d IF %d pup %d\n", + pattern_id, if_id, + bus_id)); + /* window is valid */ + } else { + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("fail win, pat %d IF %d pup %d bus_st_win %d bus_end_win %d\n", + pattern_id, if_id, bus_id, + bus_start_window[mode] + [if_id][bus_id], + bus_end_window[mode] + [if_id][bus_id])); + centralization_state[if_id] + [bus_id] = 1; + if (debug_mode == 0) + return MV_FAIL; + } + } /* ddr3_tip_centr_skip_min_win_check */ + } /* pup */ + } /* interface */ + } /* pattern */ + + for (if_id = start_if; if_id <= end_if; if_id++) { + if (IS_ACTIVE(tm->if_act_mask, if_id) == 0) + continue; + + is_if_fail = 0; + flow_result[if_id] = TEST_SUCCESS; + + for (bus_id = 0; + bus_id <= (tm->num_of_bus_per_interface - 1); bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + + /* continue only if lock */ + if (centralization_state[if_id][bus_id] != 1) { + if (ddr3_tip_centr_skip_min_win_check == 0) { + if ((bus_end_window + [mode][if_id][bus_id] == + (max_win_size - 1)) && + ((bus_end_window + [mode][if_id][bus_id] - + bus_start_window[mode][if_id] + [bus_id]) < MIN_WINDOW_SIZE) && + ((bus_end_window[mode][if_id] + [bus_id] - bus_start_window + [mode][if_id][bus_id]) > 2)) { + /* prevent false lock */ + /* TBD change to enum */ + centralization_state + [if_id][bus_id] = 2; + } + + if ((bus_end_window[mode][if_id][bus_id] + == 0) && + ((bus_end_window[mode][if_id] + [bus_id] - + bus_start_window[mode][if_id] + [bus_id]) < MIN_WINDOW_SIZE) && + ((bus_end_window[mode][if_id] + [bus_id] - + bus_start_window[mode][if_id] + [bus_id]) > 2)) + /*prevent false lock */ + centralization_state[if_id] + [bus_id] = 3; + } + + if ((bus_end_window[mode][if_id][bus_id] > + (max_win_size - 1)) && direction == + OPER_WRITE) { + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("Tx special pattern\n")); + cons_tap = 64; + } + } + + /* check states */ + if (centralization_state[if_id][bus_id] == 3) { + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_INFO, + ("SSW - TBD IF %d pup %d\n", + if_id, bus_id)); + lock_success = 1; + } else if (centralization_state[if_id][bus_id] == 2) { + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_INFO, + ("SEW - TBD IF %d pup %d\n", + if_id, bus_id)); + lock_success = 1; + } else if (centralization_state[if_id][bus_id] == 0) { + lock_success = 1; + } else { + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_ERROR, + ("fail, IF %d pup %d\n", + if_id, bus_id)); + lock_success = 0; + } + + if (lock_success == 1) { + centralization_result[if_id][bus_id] = + (bus_end_window[mode][if_id][bus_id] + + bus_start_window[mode][if_id][bus_id]) + / 2 - cons_tap; + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_TRACE, + (" bus_id %d Res= %d\n", bus_id, + centralization_result[if_id][bus_id])); + /* copy results to registers */ + pup_win_length = + bus_end_window[mode][if_id][bus_id] - + bus_start_window[mode][if_id][bus_id] + + 1; + + ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_DATA, + RESULT_DB_PHY_REG_ADDR + + effective_cs, ®); + reg = (reg & (~0x1f << + ((mode == CENTRAL_TX) ? + (RESULT_DB_PHY_REG_TX_OFFSET) : + (RESULT_DB_PHY_REG_RX_OFFSET)))) + | pup_win_length << + ((mode == CENTRAL_TX) ? + (RESULT_DB_PHY_REG_TX_OFFSET) : + (RESULT_DB_PHY_REG_RX_OFFSET)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + RESULT_DB_PHY_REG_ADDR + + effective_cs, reg)); + + /* offset per CS is calculated earlier */ + CHECK_STATUS( + ddr3_tip_bus_write(dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + bus_id, + DDR_PHY_DATA, + reg_phy_off, + centralization_result + [if_id] + [bus_id])); + } else { + is_if_fail = 1; + } + } + + if (is_if_fail == 1) + flow_result[if_id] = TEST_FAILED; + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + /* restore cs enable value */ + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, + if_id, CS_ENABLE_REG, + cs_enable_reg_val[if_id], + MASK_ALL_BITS)); + } + + return is_if_fail; +} + +/* + * Centralization Flow + */ +int ddr3_tip_special_rx(u32 dev_num) +{ + enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM]; + u32 if_id, pup_id, pattern_id, bit_id; + u8 cur_start_win[BUS_WIDTH_IN_BITS]; + u8 cur_end_win[BUS_WIDTH_IN_BITS]; + enum hws_training_result result_type = RESULT_PER_BIT; + enum hws_dir direction; + enum hws_search_dir search_dir_id; + u32 *result[HWS_SEARCH_DIR_LIMIT]; + u32 max_win_size; + u8 cur_end_win_min, cur_start_win_max; + u32 cs_enable_reg_val[MAX_INTERFACE_NUM]; + u32 temp = 0; + int pad_num = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (ddr3_tip_special_rx_run_once_flag != 0) + return MV_OK; + + ddr3_tip_special_rx_run_once_flag = 1; + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* save current cs enable reg val */ + CHECK_STATUS(ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, + if_id, CS_ENABLE_REG, + cs_enable_reg_val, + MASK_ALL_BITS)); + /* enable single cs */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, + if_id, CS_ENABLE_REG, + (1 << 3), (1 << 3))); + } + + max_win_size = MAX_WINDOW_SIZE_RX; + direction = OPER_READ; + pattern_id = PATTERN_VREF; + + /* start flow */ + ddr3_tip_ip_training_wrapper(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, result_type, + HWS_CONTROL_ELEMENT_ADLL, + PARAM_NOT_CARE, direction, + tm->if_act_mask, 0x0, + max_win_size - 1, max_win_size - 1, + pattern_id, EDGE_FPF, CS_SINGLE, + PARAM_NOT_CARE, training_result); + + for (if_id = start_if; if_id <= end_if; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup_id = 0; + pup_id <= tm->num_of_bus_per_interface; pup_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup_id); + + for (search_dir_id = HWS_LOW2HIGH; + search_dir_id <= HWS_HIGH2LOW; + search_dir_id++) { + CHECK_STATUS(ddr3_tip_read_training_result + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup_id, + ALL_BITS_PER_PUP, search_dir_id, + direction, result_type, + TRAINING_LOAD_OPERATION_UNLOAD, + CS_SINGLE, &result[search_dir_id], + 1, 0, 0)); + DEBUG_CENTRALIZATION_ENGINE(DEBUG_LEVEL_INFO, + ("Special: pat %d IF %d pup %d Regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pattern_id, if_id, + pup_id, + result + [search_dir_id][0], + result + [search_dir_id][1], + result + [search_dir_id][2], + result + [search_dir_id][3], + result + [search_dir_id][4], + result + [search_dir_id][5], + result + [search_dir_id][6], + result + [search_dir_id] + [7])); + } + + for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; bit_id++) { + /* + * check if this code is valid for 2 edge, + * probably not :( + */ + cur_start_win[bit_id] = + GET_TAP_RESULT(result[HWS_LOW2HIGH] + [bit_id], EDGE_1); + cur_end_win[bit_id] = + GET_TAP_RESULT(result[HWS_HIGH2LOW] + [bit_id], EDGE_1); + } + if (!((ddr3_tip_is_pup_lock + (result[HWS_LOW2HIGH], result_type)) && + (ddr3_tip_is_pup_lock + (result[HWS_HIGH2LOW], result_type)))) { + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_ERROR, + ("Special: Pup lock fail, pat %d IF %d pup %d\n", + pattern_id, if_id, pup_id)); + return MV_FAIL; + } + + cur_end_win_min = + ddr3_tip_get_buf_min(cur_end_win); + cur_start_win_max = + ddr3_tip_get_buf_max(cur_start_win); + + if (cur_start_win_max <= 1) { /* Align left */ + for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; + bit_id++) { + pad_num = + dq_map_table[bit_id + + pup_id * + BUS_WIDTH_IN_BITS + + if_id * + BUS_WIDTH_IN_BITS * + tm-> + num_of_bus_per_interface]; + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, + pup_id, DDR_PHY_DATA, + PBS_RX_PHY_REG + pad_num, + &temp)); + temp = (temp + 0xa > 31) ? + (31) : (temp + 0xa); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + pup_id, DDR_PHY_DATA, + PBS_RX_PHY_REG + pad_num, + temp)); + } + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_INFO, + ("Special: PBS:: I/F# %d , Bus# %d fix align to the Left\n", + if_id, pup_id)); + } + + if (cur_end_win_min > 30) { /* Align right */ + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup_id, + DDR_PHY_DATA, PBS_RX_PHY_REG + 4, + &temp)); + temp += 0xa; + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + pup_id, DDR_PHY_DATA, + PBS_RX_PHY_REG + 4, temp)); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup_id, + DDR_PHY_DATA, PBS_RX_PHY_REG + 5, + &temp)); + temp += 0xa; + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + pup_id, DDR_PHY_DATA, + PBS_RX_PHY_REG + 5, temp)); + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_INFO, + ("Special: PBS:: I/F# %d , Bus# %d fix align to the right\n", + if_id, pup_id)); + } + + vref_window_size[if_id][pup_id] = + cur_end_win_min - + cur_start_win_max + 1; + DEBUG_CENTRALIZATION_ENGINE( + DEBUG_LEVEL_INFO, + ("Special: Winsize I/F# %d , Bus# %d is %d\n", + if_id, pup_id, vref_window_size + [if_id][pup_id])); + } /* pup */ + } /* end of interface */ + + return MV_OK; +} + +/* + * Print Centralization Result + */ +int ddr3_tip_print_centralization_result(u32 dev_num) +{ + u32 if_id = 0, bus_id = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + dev_num = dev_num; + + printf("Centralization Results\n"); + printf("I/F0 Result[0 - success 1-fail 2 - state_2 3 - state_3] ...\n"); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + printf("%d ,\n", centralization_state[if_id][bus_id]); + } + } + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_db.c b/drivers/ddr/marvell/a38x/ddr3_training_db.c new file mode 100644 index 0000000..861dfb1 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_db.c @@ -0,0 +1,652 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +/* List of allowed frequency listed in order of enum hws_ddr_freq */ +u32 freq_val[DDR_FREQ_LIMIT] = { + 0, /*DDR_FREQ_LOW_FREQ */ + 400, /*DDR_FREQ_400, */ + 533, /*DDR_FREQ_533, */ + 666, /*DDR_FREQ_667, */ + 800, /*DDR_FREQ_800, */ + 933, /*DDR_FREQ_933, */ + 1066, /*DDR_FREQ_1066, */ + 311, /*DDR_FREQ_311, */ + 333, /*DDR_FREQ_333, */ + 467, /*DDR_FREQ_467, */ + 850, /*DDR_FREQ_850, */ + 600, /*DDR_FREQ_600 */ + 300, /*DDR_FREQ_300 */ + 900, /*DDR_FREQ_900 */ + 360, /*DDR_FREQ_360 */ + 1000 /*DDR_FREQ_1000 */ +}; + +/* Table for CL values per frequency for each speed bin index */ +struct cl_val_per_freq cas_latency_table[] = { + /* + * 400M 667M 933M 311M 467M 600M 360 + * 100M 533M 800M 1066M 333M 850M 900 + * 1000 (the order is 100, 400, 533 etc.) + */ + /* DDR3-800D */ + { {6, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} }, + /* DDR3-800E */ + { {6, 6, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 6, 0, 6, 0} }, + /* DDR3-1066E */ + { {6, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 0, 5, 0, 5, 0} }, + /* DDR3-1066F */ + { {6, 6, 7, 0, 0, 0, 0, 6, 6, 7, 0, 0, 6, 0, 6, 0} }, + /* DDR3-1066G */ + { {6, 6, 8, 0, 0, 0, 0, 6, 6, 8, 0, 0, 6, 0, 6, 0} }, + /* DDR3-1333F* */ + { {6, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1333G */ + { {6, 5, 7, 8, 0, 0, 0, 5, 5, 7, 0, 8, 5, 0, 5, 0} }, + /* DDR3-1333H */ + { {6, 6, 8, 9, 0, 0, 0, 6, 6, 8, 0, 9, 6, 0, 6, 0} }, + /* DDR3-1333J* */ + { {6, 6, 8, 10, 0, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6, 0} + /* DDR3-1600G* */}, + { {6, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1600H */ + { {6, 5, 6, 8, 9, 0, 0, 5, 5, 6, 0, 8, 5, 0, 5, 0} }, + /* DDR3-1600J */ + { {6, 5, 7, 9, 10, 0, 0, 5, 5, 7, 0, 9, 5, 0, 5, 0} }, + /* DDR3-1600K */ + { {6, 6, 8, 10, 11, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6, 0 } }, + /* DDR3-1866J* */ + { {6, 5, 6, 8, 9, 11, 0, 5, 5, 6, 11, 8, 5, 0, 5, 0} }, + /* DDR3-1866K */ + { {6, 5, 7, 8, 10, 11, 0, 5, 5, 7, 11, 8, 5, 11, 5, 11} }, + /* DDR3-1866L */ + { {6, 6, 7, 9, 11, 12, 0, 6, 6, 7, 12, 9, 6, 12, 6, 12} }, + /* DDR3-1866M* */ + { {6, 6, 8, 10, 11, 13, 0, 6, 6, 8, 13, 10, 6, 13, 6, 13} }, + /* DDR3-2133K* */ + { {6, 5, 6, 7, 9, 10, 11, 5, 5, 6, 10, 7, 5, 11, 5, 11} }, + /* DDR3-2133L */ + { {6, 5, 6, 8, 9, 11, 12, 5, 5, 6, 11, 8, 5, 12, 5, 12} }, + /* DDR3-2133M */ + { {6, 5, 7, 9, 10, 12, 13, 5, 5, 7, 12, 9, 5, 13, 5, 13} }, + /* DDR3-2133N* */ + { {6, 6, 7, 9, 11, 13, 14, 6, 6, 7, 13, 9, 6, 14, 6, 14} }, + /* DDR3-1333H-ext */ + { {6, 6, 7, 9, 0, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} }, + /* DDR3-1600K-ext */ + { {6, 6, 7, 9, 11, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} }, + /* DDR3-1866M-ext */ + { {6, 6, 7, 9, 11, 13, 0, 6, 6, 7, 13, 9, 6, 13, 6, 13} }, +}; + +/* Table for CWL values per speedbin index */ +struct cl_val_per_freq cas_write_latency_table[] = { + /* + * 400M 667M 933M 311M 467M 600M 360 + * 100M 533M 800M 1066M 333M 850M 900 + * (the order is 100, 400, 533 etc.) + */ + /* DDR3-800D */ + { {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} }, + /* DDR3-800E */ + { {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} }, + /* DDR3-1066E */ + { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1066F */ + { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1066G */ + { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1333F* */ + { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1333G */ + { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1333H */ + { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1333J* */ + { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1600G* */ + { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1600H */ + { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1600J */ + { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1600K */ + { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1866J* */ + { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} }, + /* DDR3-1866K */ + { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} }, + /* DDR3-1866L */ + { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} }, + /* DDR3-1866M* */ + { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} }, + /* DDR3-2133K* */ + { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} }, + /* DDR3-2133L */ + { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} }, + /* DDR3-2133M */ + { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} }, + /* DDR3-2133N* */ + { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} }, + /* DDR3-1333H-ext */ + { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1600K-ext */ + { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} }, + /* DDR3-1866M-ext */ + { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} }, +}; + +u8 twr_mask_table[] = { + 10, + 10, + 10, + 10, + 10, + 1, /*5 */ + 2, /*6 */ + 3, /*7 */ + 10, + 10, + 5, /*10 */ + 10, + 6, /*12 */ + 10, + 7, /*14 */ + 10, + 0 /*16 */ +}; + +u8 cl_mask_table[] = { + 0, + 0, + 0, + 0, + 0, + 0x2, + 0x4, + 0x6, + 0x8, + 0xa, + 0xc, + 0xe, + 0x1, + 0x3, + 0x5, + 0x5 +}; + +u8 cwl_mask_table[] = { + 0, + 0, + 0, + 0, + 0, + 0, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0x9 +}; + +/* RFC values (in ns) */ +u16 rfc_table[] = { + 90, /* 512M */ + 110, /* 1G */ + 160, /* 2G */ + 260, /* 4G */ + 350 /* 8G */ +}; + +u32 speed_bin_table_t_rc[] = { + 50000, + 52500, + 48750, + 50625, + 52500, + 46500, + 48000, + 49500, + 51000, + 45000, + 46250, + 47500, + 48750, + 44700, + 45770, + 46840, + 47910, + 43285, + 44220, + 45155, + 46900 +}; + +u32 speed_bin_table_t_rcd_t_rp[] = { + 12500, + 15000, + 11250, + 13125, + 15000, + 10500, + 12000, + 13500, + 15000, + 10000, + 11250, + 12500, + 13750, + 10700, + 11770, + 12840, + 13910, + 10285, + 11022, + 12155, + 13090, +}; + +enum { + PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR = 0, + PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM +}; + +static u8 pattern_killer_pattern_table_map[KILLER_PATTERN_LENGTH * 2][2] = { + /*Aggressor / Victim */ + {1, 0}, + {0, 0}, + {1, 0}, + {1, 1}, + {0, 1}, + {0, 1}, + {1, 0}, + {0, 1}, + {1, 0}, + {0, 1}, + {1, 0}, + {1, 0}, + {0, 1}, + {1, 0}, + {0, 1}, + {0, 0}, + {1, 1}, + {0, 0}, + {1, 1}, + {0, 0}, + {1, 1}, + {0, 0}, + {1, 1}, + {1, 0}, + {0, 0}, + {1, 1}, + {0, 0}, + {1, 1}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 1}, + {0, 1}, + {1, 1}, + {0, 0}, + {0, 0}, + {1, 1}, + {1, 1}, + {0, 0}, + {1, 1}, + {0, 0}, + {1, 1}, + {1, 1}, + {0, 0}, + {0, 0}, + {1, 1}, + {0, 0}, + {1, 1}, + {0, 1}, + {0, 0}, + {0, 1}, + {0, 1}, + {0, 0}, + {1, 1}, + {1, 1}, + {1, 0}, + {1, 0}, + {1, 1}, + {1, 1}, + {1, 1}, + {1, 1}, + {1, 1}, + {1, 1}, + {1, 1} +}; + +static u8 pattern_vref_pattern_table_map[] = { + /* 1 means 0xffffffff, 0 is 0x0 */ + 0xb8, + 0x52, + 0x55, + 0x8a, + 0x33, + 0xa6, + 0x6d, + 0xfe +}; + +/* Return speed Bin value for selected index and t* element */ +u32 speed_bin_table(u8 index, enum speed_bin_table_elements element) +{ + u32 result = 0; + + switch (element) { + case SPEED_BIN_TRCD: + case SPEED_BIN_TRP: + result = speed_bin_table_t_rcd_t_rp[index]; + break; + case SPEED_BIN_TRAS: + if (index < 6) + result = 37500; + else if (index < 10) + result = 36000; + else if (index < 14) + result = 35000; + else if (index < 18) + result = 34000; + else + result = 33000; + break; + case SPEED_BIN_TRC: + result = speed_bin_table_t_rc[index]; + break; + case SPEED_BIN_TRRD1K: + if (index < 3) + result = 10000; + else if (index < 6) + result = 7005; + else if (index < 14) + result = 6000; + else + result = 5000; + break; + case SPEED_BIN_TRRD2K: + if (index < 6) + result = 10000; + else if (index < 14) + result = 7005; + else + result = 6000; + break; + case SPEED_BIN_TPD: + if (index < 3) + result = 7500; + else if (index < 10) + result = 5625; + else + result = 5000; + break; + case SPEED_BIN_TFAW1K: + if (index < 3) + result = 40000; + else if (index < 6) + result = 37500; + else if (index < 14) + result = 30000; + else if (index < 18) + result = 27000; + else + result = 25000; + break; + case SPEED_BIN_TFAW2K: + if (index < 6) + result = 50000; + else if (index < 10) + result = 45000; + else if (index < 14) + result = 40000; + else + result = 35000; + break; + case SPEED_BIN_TWTR: + result = 7500; + break; + case SPEED_BIN_TRTP: + result = 7500; + break; + case SPEED_BIN_TWR: + result = 15000; + break; + case SPEED_BIN_TMOD: + result = 15000; + break; + default: + break; + } + + return result; +} + +static inline u32 pattern_table_get_killer_word(u8 dqs, u8 index) +{ + u8 i, byte = 0; + u8 role; + + for (i = 0; i < 8; i++) { + role = (i == dqs) ? + (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) : + (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM); + byte |= pattern_killer_pattern_table_map[index][role] << i; + } + + return byte | (byte << 8) | (byte << 16) | (byte << 24); +} + +static inline u32 pattern_table_get_killer_word16(u8 dqs, u8 index) +{ + u8 i, byte0 = 0, byte1 = 0; + u8 role; + + for (i = 0; i < 8; i++) { + role = (i == dqs) ? + (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) : + (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM); + byte0 |= pattern_killer_pattern_table_map[index * 2][role] << i; + } + + for (i = 0; i < 8; i++) { + role = (i == dqs) ? + (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) : + (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM); + byte1 |= pattern_killer_pattern_table_map + [index * 2 + 1][role] << i; + } + + return byte0 | (byte0 << 8) | (byte1 << 16) | (byte1 << 24); +} + +static inline u32 pattern_table_get_sso_word(u8 sso, u8 index) +{ + u8 step = sso + 1; + + if (0 == ((index / step) & 1)) + return 0x0; + else + return 0xffffffff; +} + +static inline u32 pattern_table_get_vref_word(u8 index) +{ + if (0 == ((pattern_vref_pattern_table_map[index / 8] >> + (index % 8)) & 1)) + return 0x0; + else + return 0xffffffff; +} + +static inline u32 pattern_table_get_vref_word16(u8 index) +{ + if (0 == pattern_killer_pattern_table_map + [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] && + 0 == pattern_killer_pattern_table_map + [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1]) + return 0x00000000; + else if (1 == pattern_killer_pattern_table_map + [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] && + 0 == pattern_killer_pattern_table_map + [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1]) + return 0xffff0000; + else if (0 == pattern_killer_pattern_table_map + [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] && + 1 == pattern_killer_pattern_table_map + [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1]) + return 0x0000ffff; + else + return 0xffffffff; +} + +static inline u32 pattern_table_get_static_pbs_word(u8 index) +{ + u16 temp; + + temp = ((0x00ff << (index / 3)) & 0xff00) >> 8; + + return temp | (temp << 8) | (temp << 16) | (temp << 24); +} + +inline u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index) +{ + u32 pattern; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0) { + /* 32bit patterns */ + switch (type) { + case PATTERN_PBS1: + case PATTERN_PBS2: + if (index == 0 || index == 2 || index == 5 || + index == 7) + pattern = PATTERN_55; + else + pattern = PATTERN_AA; + break; + case PATTERN_PBS3: + if (0 == (index & 1)) + pattern = PATTERN_55; + else + pattern = PATTERN_AA; + break; + case PATTERN_RL: + if (index < 6) + pattern = PATTERN_00; + else + pattern = PATTERN_80; + break; + case PATTERN_STATIC_PBS: + pattern = pattern_table_get_static_pbs_word(index); + break; + case PATTERN_KILLER_DQ0: + case PATTERN_KILLER_DQ1: + case PATTERN_KILLER_DQ2: + case PATTERN_KILLER_DQ3: + case PATTERN_KILLER_DQ4: + case PATTERN_KILLER_DQ5: + case PATTERN_KILLER_DQ6: + case PATTERN_KILLER_DQ7: + pattern = pattern_table_get_killer_word( + (u8)(type - PATTERN_KILLER_DQ0), index); + break; + case PATTERN_RL2: + if (index < 6) + pattern = PATTERN_00; + else + pattern = PATTERN_01; + break; + case PATTERN_TEST: + if (index > 1 && index < 6) + pattern = PATTERN_20; + else + pattern = PATTERN_00; + break; + case PATTERN_FULL_SSO0: + case PATTERN_FULL_SSO1: + case PATTERN_FULL_SSO2: + case PATTERN_FULL_SSO3: + pattern = pattern_table_get_sso_word( + (u8)(type - PATTERN_FULL_SSO0), index); + break; + case PATTERN_VREF: + pattern = pattern_table_get_vref_word(index); + break; + default: + pattern = 0; + break; + } + } else { + /* 16bit patterns */ + switch (type) { + case PATTERN_PBS1: + case PATTERN_PBS2: + case PATTERN_PBS3: + pattern = PATTERN_55AA; + break; + case PATTERN_RL: + if (index < 3) + pattern = PATTERN_00; + else + pattern = PATTERN_80; + break; + case PATTERN_STATIC_PBS: + pattern = PATTERN_00FF; + break; + case PATTERN_KILLER_DQ0: + case PATTERN_KILLER_DQ1: + case PATTERN_KILLER_DQ2: + case PATTERN_KILLER_DQ3: + case PATTERN_KILLER_DQ4: + case PATTERN_KILLER_DQ5: + case PATTERN_KILLER_DQ6: + case PATTERN_KILLER_DQ7: + pattern = pattern_table_get_killer_word16( + (u8)(type - PATTERN_KILLER_DQ0), index); + break; + case PATTERN_RL2: + if (index < 3) + pattern = PATTERN_00; + else + pattern = PATTERN_01; + break; + case PATTERN_TEST: + pattern = PATTERN_0080; + break; + case PATTERN_FULL_SSO0: + pattern = 0x0000ffff; + break; + case PATTERN_FULL_SSO1: + case PATTERN_FULL_SSO2: + case PATTERN_FULL_SSO3: + pattern = pattern_table_get_sso_word( + (u8)(type - PATTERN_FULL_SSO1), index); + break; + case PATTERN_VREF: + pattern = pattern_table_get_vref_word16(index); + break; + default: + pattern = 0; + break; + } + } + + return pattern; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c new file mode 100644 index 0000000..56fce17 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c @@ -0,0 +1,686 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define VREF_INITIAL_STEP 3 +#define VREF_SECOND_STEP 1 +#define VREF_MAX_INDEX 7 +#define MAX_VALUE (1024 - 1) +#define MIN_VALUE (-MAX_VALUE) +#define GET_RD_SAMPLE_DELAY(data, cs) ((data >> rd_sample_mask[cs]) & 0xf) + +u32 ck_delay = (u32)-1, ck_delay_16 = (u32)-1; +u32 ca_delay; +int ddr3_tip_centr_skip_min_win_check = 0; +u8 current_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM]; +u8 last_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM]; +u16 current_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM]; +u16 last_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM]; +u8 lim_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM]; +u8 interface_state[MAX_INTERFACE_NUM]; +u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 vref_window_size_th = 12; + +static u8 pup_st[MAX_BUS_NUM][MAX_INTERFACE_NUM]; + +static u32 rd_sample_mask[] = { + 0, + 8, + 16, + 24 +}; + +#define VREF_STEP_1 0 +#define VREF_STEP_2 1 +#define VREF_CONVERGE 2 + +/* + * ODT additional timing + */ +int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id) +{ + u32 cs_num = 0, max_read_sample = 0, min_read_sample = 0; + u32 data_read[MAX_INTERFACE_NUM] = { 0 }; + u32 read_sample[MAX_CS_NUM]; + u32 val; + u32 pup_index; + int max_phase = MIN_VALUE, current_phase; + enum hws_access_type access_type = ACCESS_TYPE_UNICAST; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + DUNIT_ODT_CONTROL_REG, + 0 << 8, 0x3 << 8)); + CHECK_STATUS(ddr3_tip_if_read(dev_num, access_type, if_id, + READ_DATA_SAMPLE_DELAY, + data_read, MASK_ALL_BITS)); + val = data_read[if_id]; + + for (cs_num = 0; cs_num < MAX_CS_NUM; cs_num++) { + read_sample[cs_num] = GET_RD_SAMPLE_DELAY(val, cs_num); + + /* find maximum of read_samples */ + if (read_sample[cs_num] >= max_read_sample) { + if (read_sample[cs_num] == max_read_sample) + max_phase = MIN_VALUE; + else + max_read_sample = read_sample[cs_num]; + + for (pup_index = 0; + pup_index < tm->num_of_bus_per_interface; + pup_index++) { + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup_index, + DDR_PHY_DATA, + RL_PHY_REG + CS_REG_VALUE(cs_num), + &val)); + + current_phase = ((int)val & 0xe0) >> 6; + if (current_phase >= max_phase) + max_phase = current_phase; + } + } + + /* find minimum */ + if (read_sample[cs_num] < min_read_sample) + min_read_sample = read_sample[cs_num]; + } + + min_read_sample = min_read_sample - 1; + max_read_sample = max_read_sample + 4 + (max_phase + 1) / 2 + 1; + if (min_read_sample >= 0xf) + min_read_sample = 0xf; + if (max_read_sample >= 0x1f) + max_read_sample = 0x1f; + + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + ODT_TIMING_LOW, + ((min_read_sample - 1) << 12), + 0xf << 12)); + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id, + ODT_TIMING_LOW, + (max_read_sample << 16), + 0x1f << 16)); + + return MV_OK; +} + +int get_valid_win_rx(u32 dev_num, u32 if_id, u8 res[4]) +{ + u32 reg_pup = RESULT_DB_PHY_REG_ADDR; + u32 reg_data; + u32 cs_num; + int i; + + cs_num = 0; + + /* TBD */ + reg_pup += cs_num; + + for (i = 0; i < 4; i++) { + CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id, + ACCESS_TYPE_UNICAST, i, + DDR_PHY_DATA, reg_pup, + ®_data)); + res[i] = (reg_data >> RESULT_DB_PHY_REG_RX_OFFSET) & 0x1f; + } + + return 0; +} + +/* + * This algorithm deals with the vertical optimum from Voltage point of view + * of the sample signal. + * Voltage sample point can improve the Eye / window size of the bit and the + * pup. + * The problem is that it is tune for all DQ the same so there isn't any + * PBS like code. + * It is more like centralization. + * But because we don't have The training SM support we do it a bit more + * smart search to save time. + */ +int ddr3_tip_vref(u32 dev_num) +{ + /* + * The Vref register have non linear order. Need to check what will be + * in future projects. + */ + u32 vref_map[8] = { + 1, 2, 3, 4, 5, 6, 7, 0 + }; + /* State and parameter definitions */ + u32 initial_step = VREF_INITIAL_STEP; + /* need to be assign with minus ????? */ + u32 second_step = VREF_SECOND_STEP; + u32 algo_run_flag = 0, currrent_vref = 0; + u32 while_count = 0; + u32 pup = 0, if_id = 0, num_pup = 0, rep = 0; + u32 val = 0; + u32 reg_addr = 0xa8; + u32 copy_start_pattern, copy_end_pattern; + enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage); + u8 res[4]; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + CHECK_STATUS(ddr3_tip_special_rx(dev_num)); + + /* save start/end pattern */ + copy_start_pattern = start_pattern; + copy_end_pattern = end_pattern; + + /* set vref as centralization pattern */ + start_pattern = PATTERN_VREF; + end_pattern = PATTERN_VREF; + + /* init params */ + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup = 0; + pup < tm->num_of_bus_per_interface; pup++) { + current_vref[pup][if_id] = 0; + last_vref[pup][if_id] = 0; + lim_vref[pup][if_id] = 0; + current_valid_window[pup][if_id] = 0; + last_valid_window[pup][if_id] = 0; + if (vref_window_size[if_id][pup] > + vref_window_size_th) { + pup_st[pup][if_id] = VREF_CONVERGE; + DEBUG_TRAINING_HW_ALG( + DEBUG_LEVEL_INFO, + ("VREF config, IF[ %d ]pup[ %d ] - Vref tune not requered (%d)\n", + if_id, pup, __LINE__)); + } else { + pup_st[pup][if_id] = VREF_STEP_1; + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, &val)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + pup, DDR_PHY_DATA, reg_addr, + (val & (~0xf)) | vref_map[0])); + DEBUG_TRAINING_HW_ALG( + DEBUG_LEVEL_INFO, + ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n", + if_id, pup, + (val & (~0xf)) | vref_map[0], + __LINE__)); + } + } + interface_state[if_id] = 0; + } + + /* TODO: Set number of active interfaces */ + num_pup = tm->num_of_bus_per_interface * MAX_INTERFACE_NUM; + + while ((algo_run_flag <= num_pup) & (while_count < 10)) { + while_count++; + for (rep = 1; rep < 4; rep++) { + ddr3_tip_centr_skip_min_win_check = 1; + ddr3_tip_centralization_rx(dev_num); + ddr3_tip_centr_skip_min_win_check = 0; + + /* Read Valid window results only for non converge pups */ + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (interface_state[if_id] != 4) { + get_valid_win_rx(dev_num, if_id, res); + for (pup = 0; + pup < tm->num_of_bus_per_interface; + pup++) { + VALIDATE_ACTIVE + (tm->bus_act_mask, pup); + if (pup_st[pup] + [if_id] == + VREF_CONVERGE) + continue; + + current_valid_window[pup] + [if_id] = + (current_valid_window[pup] + [if_id] * (rep - 1) + + 1000 * res[pup]) / rep; + } + } + } + } + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + DEBUG_TRAINING_HW_ALG( + DEBUG_LEVEL_TRACE, + ("current_valid_window: IF[ %d ] - ", if_id)); + + for (pup = 0; + pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, + ("%d ", + current_valid_window + [pup][if_id])); + } + DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, ("\n")); + } + + /* Compare results and respond as function of state */ + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup = 0; + pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, + ("I/F[ %d ], pup[ %d ] STATE #%d (%d)\n", + if_id, pup, + pup_st[pup] + [if_id], __LINE__)); + + if (pup_st[pup][if_id] == VREF_CONVERGE) + continue; + + DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, + ("I/F[ %d ], pup[ %d ] CHECK progress - Current %d Last %d, limit VREF %d (%d)\n", + if_id, pup, + current_valid_window[pup] + [if_id], + last_valid_window[pup] + [if_id], lim_vref[pup] + [if_id], __LINE__)); + + /* + * The -1 is for solution resolution +/- 1 tap + * of ADLL + */ + if (current_valid_window[pup][if_id] + 200 >= + (last_valid_window[pup][if_id])) { + if (pup_st[pup][if_id] == VREF_STEP_1) { + /* + * We stay in the same state and + * step just update the window + * size (take the max) and Vref + */ + if (current_vref[pup] + [if_id] == VREF_MAX_INDEX) { + /* + * If we step to the end + * and didn't converge + * to some particular + * better Vref value + * define the pup as + * converge and step + * back to nominal + * Vref. + */ + pup_st[pup] + [if_id] = + VREF_CONVERGE; + algo_run_flag++; + interface_state + [if_id]++; + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n", + if_id, pup, + current_vref[pup] + [if_id], + __LINE__)); + } else { + /* continue to update the Vref index */ + current_vref[pup] + [if_id] = + ((current_vref[pup] + [if_id] + + initial_step) > + VREF_MAX_INDEX) ? + VREF_MAX_INDEX + : (current_vref[pup] + [if_id] + + initial_step); + if (current_vref[pup] + [if_id] == + VREF_MAX_INDEX) { + pup_st[pup] + [if_id] + = + VREF_STEP_2; + } + lim_vref[pup] + [if_id] = + last_vref[pup] + [if_id] = + current_vref[pup] + [if_id]; + } + + last_valid_window[pup] + [if_id] = + GET_MAX(current_valid_window + [pup][if_id], + last_valid_window + [pup] + [if_id]); + + /* update the Vref for next stage */ + currrent_vref = + current_vref[pup] + [if_id]; + CHECK_STATUS + (ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + &val)); + CHECK_STATUS + (ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + (val & (~0xf)) | + vref_map[currrent_vref])); + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n", + if_id, pup, + (val & (~0xf)) | + vref_map[currrent_vref], + __LINE__)); + } else if (pup_st[pup][if_id] + == VREF_STEP_2) { + /* + * We keep on search back with + * the same step size. + */ + last_valid_window[pup] + [if_id] = + GET_MAX(current_valid_window + [pup][if_id], + last_valid_window + [pup] + [if_id]); + last_vref[pup][if_id] = + current_vref[pup] + [if_id]; + + /* we finish all search space */ + if ((current_vref[pup] + [if_id] - second_step) == lim_vref[pup][if_id]) { + /* + * If we step to the end + * and didn't converge + * to some particular + * better Vref value + * define the pup as + * converge and step + * back to nominal + * Vref. + */ + pup_st[pup] + [if_id] = + VREF_CONVERGE; + algo_run_flag++; + + interface_state + [if_id]++; + + current_vref[pup] + [if_id] = + (current_vref[pup] + [if_id] - + second_step); + + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n", + if_id, pup, + current_vref[pup] + [if_id], + __LINE__)); + } else + /* we finish all search space */ + if (current_vref[pup] + [if_id] == + lim_vref[pup] + [if_id]) { + /* + * If we step to the end + * and didn't converge + * to some particular + * better Vref value + * define the pup as + * converge and step + * back to nominal + * Vref. + */ + pup_st[pup] + [if_id] = + VREF_CONVERGE; + + algo_run_flag++; + interface_state + [if_id]++; + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n", + if_id, pup, + current_vref[pup] + [if_id], + __LINE__)); + } else { + current_vref[pup] + [if_id] = + current_vref[pup] + [if_id] - + second_step; + } + + /* Update the Vref for next stage */ + currrent_vref = + current_vref[pup] + [if_id]; + CHECK_STATUS + (ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + &val)); + CHECK_STATUS + (ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + (val & (~0xf)) | + vref_map[currrent_vref])); + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n", + if_id, pup, + (val & (~0xf)) | + vref_map[currrent_vref], + __LINE__)); + } + } else { + /* we change state and change step */ + if (pup_st[pup][if_id] == VREF_STEP_1) { + pup_st[pup][if_id] = + VREF_STEP_2; + lim_vref[pup][if_id] = + current_vref[pup] + [if_id] - initial_step; + last_valid_window[pup] + [if_id] = + current_valid_window[pup] + [if_id]; + last_vref[pup][if_id] = + current_vref[pup] + [if_id]; + current_vref[pup][if_id] = + last_vref[pup][if_id] - + second_step; + + /* Update the Vref for next stage */ + CHECK_STATUS + (ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + &val)); + CHECK_STATUS + (ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + (val & (~0xf)) | + vref_map[current_vref[pup] + [if_id]])); + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n", + if_id, pup, + (val & (~0xf)) | + vref_map[current_vref[pup] + [if_id]], + __LINE__)); + + } else if (pup_st[pup][if_id] == VREF_STEP_2) { + /* + * The last search was the max + * point set value and exit + */ + CHECK_STATUS + (ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + &val)); + CHECK_STATUS + (ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + (val & (~0xf)) | + vref_map[last_vref[pup] + [if_id]])); + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n", + if_id, pup, + (val & (~0xf)) | + vref_map[last_vref[pup] + [if_id]], + __LINE__)); + pup_st[pup][if_id] = + VREF_CONVERGE; + algo_run_flag++; + interface_state[if_id]++; + DEBUG_TRAINING_HW_ALG + (DEBUG_LEVEL_TRACE, + ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n", + if_id, pup, + current_vref[pup] + [if_id], __LINE__)); + } + } + } + } + } + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup = 0; + pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, &val)); + DEBUG_TRAINING_HW_ALG( + DEBUG_LEVEL_INFO, + ("FINAL values: I/F[ %d ], pup[ %d ] - Vref = %X (%d)\n", + if_id, pup, val, __LINE__)); + } + } + + flow_result[if_id] = TEST_SUCCESS; + + /* restore start/end pattern */ + start_pattern = copy_start_pattern; + end_pattern = copy_end_pattern; + + return 0; +} + +/* + * CK/CA Delay + */ +int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap) +{ + u32 if_id = 0; + u32 ck_num_adll_tap = 0, ca_num_adll_tap = 0, data = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* + * ck_delay_table is delaying the of the clock signal only. + * (to overcome timing issues between_c_k & command/address signals) + */ + /* + * ca_delay is delaying the of the entire command & Address signals + * (include Clock signal to overcome DGL error on the Clock versus + * the DQS). + */ + + /* Calc ADLL Tap */ + if ((ck_delay == -1) || (ck_delay_16 == -1)) { + DEBUG_TRAINING_HW_ALG( + DEBUG_LEVEL_ERROR, + ("ERROR: One of ck_delay values not initialized!!!\n")); + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* Calc delay ps in ADLL tap */ + if (tm->interface_params[if_id].bus_width == + BUS_WIDTH_16) + ck_num_adll_tap = ck_delay_16 / adll_tap; + else + ck_num_adll_tap = ck_delay / adll_tap; + + ca_num_adll_tap = ca_delay / adll_tap; + data = (ck_num_adll_tap & 0x3f) + + ((ca_num_adll_tap & 0x3f) << 10); + + /* + * Set the ADLL number to the CK ADLL for Interfaces for + * all Pup + */ + DEBUG_TRAINING_HW_ALG( + DEBUG_LEVEL_TRACE, + ("ck_num_adll_tap %d ca_num_adll_tap %d adll_tap %d\n", + ck_num_adll_tap, ca_num_adll_tap, adll_tap)); + + CHECK_STATUS(ddr3_tip_bus_write(dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, DDR_PHY_CONTROL, + 0x0, data)); + } + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h new file mode 100644 index 0000000..6e1bab2 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_HW_ALGO_H_ +#define _DDR3_TRAINING_HW_ALGO_H_ + +int ddr3_tip_vref(u32 dev_num); +int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id); +int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap); + +#endif /* _DDR3_TRAINING_HW_ALGO_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip.h b/drivers/ddr/marvell/a38x/ddr3_training_ip.h new file mode 100644 index 0000000..76a1b6a0 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_H_ +#define _DDR3_TRAINING_IP_H_ + +#include "ddr3_training_ip_def.h" +#include "ddr_topology_def.h" +#include "ddr_training_ip_db.h" + +#define DDR3_TIP_VERSION_STRING "DDR3 Training Sequence - Ver TIP-1.29." + +#define MAX_CS_NUM 4 +#define MAX_TOTAL_BUS_NUM (MAX_INTERFACE_NUM * MAX_BUS_NUM) +#define MAX_DQ_NUM 40 + +#define GET_MIN(arg1, arg2) ((arg1) < (arg2)) ? (arg1) : (arg2) +#define GET_MAX(arg1, arg2) ((arg1) < (arg2)) ? (arg2) : (arg1) + +#define INIT_CONTROLLER_MASK_BIT 0x00000001 +#define STATIC_LEVELING_MASK_BIT 0x00000002 +#define SET_LOW_FREQ_MASK_BIT 0x00000004 +#define LOAD_PATTERN_MASK_BIT 0x00000008 +#define SET_MEDIUM_FREQ_MASK_BIT 0x00000010 +#define WRITE_LEVELING_MASK_BIT 0x00000020 +#define LOAD_PATTERN_2_MASK_BIT 0x00000040 +#define READ_LEVELING_MASK_BIT 0x00000080 +#define SW_READ_LEVELING_MASK_BIT 0x00000100 +#define WRITE_LEVELING_SUPP_MASK_BIT 0x00000200 +#define PBS_RX_MASK_BIT 0x00000400 +#define PBS_TX_MASK_BIT 0x00000800 +#define SET_TARGET_FREQ_MASK_BIT 0x00001000 +#define ADJUST_DQS_MASK_BIT 0x00002000 +#define WRITE_LEVELING_TF_MASK_BIT 0x00004000 +#define LOAD_PATTERN_HIGH_MASK_BIT 0x00008000 +#define READ_LEVELING_TF_MASK_BIT 0x00010000 +#define WRITE_LEVELING_SUPP_TF_MASK_BIT 0x00020000 +#define DM_PBS_TX_MASK_BIT 0x00040000 +#define CENTRALIZATION_RX_MASK_BIT 0x00100000 +#define CENTRALIZATION_TX_MASK_BIT 0x00200000 +#define TX_EMPHASIS_MASK_BIT 0x00400000 +#define PER_BIT_READ_LEVELING_TF_MASK_BIT 0x00800000 +#define VREF_CALIBRATION_MASK_BIT 0x01000000 + +enum hws_result { + TEST_FAILED = 0, + TEST_SUCCESS = 1, + NO_TEST_DONE = 2 +}; + +enum hws_training_result { + RESULT_PER_BIT, + RESULT_PER_BYTE +}; + +enum auto_tune_stage { + INIT_CONTROLLER, + STATIC_LEVELING, + SET_LOW_FREQ, + LOAD_PATTERN, + SET_MEDIUM_FREQ, + WRITE_LEVELING, + LOAD_PATTERN_2, + READ_LEVELING, + WRITE_LEVELING_SUPP, + PBS_RX, + PBS_TX, + SET_TARGET_FREQ, + ADJUST_DQS, + WRITE_LEVELING_TF, + READ_LEVELING_TF, + WRITE_LEVELING_SUPP_TF, + DM_PBS_TX, + VREF_CALIBRATION, + CENTRALIZATION_RX, + CENTRALIZATION_TX, + TX_EMPHASIS, + LOAD_PATTERN_HIGH, + PER_BIT_READ_LEVELING_TF, + MAX_STAGE_LIMIT +}; + +enum hws_access_type { + ACCESS_TYPE_UNICAST = 0, + ACCESS_TYPE_MULTICAST = 1 +}; + +enum hws_algo_type { + ALGO_TYPE_DYNAMIC, + ALGO_TYPE_STATIC +}; + +struct init_cntr_param { + int is_ctrl64_bit; + int do_mrs_phy; + int init_phy; + int msys_init; +}; + +struct pattern_info { + u8 num_of_phases_tx; + u8 tx_burst_size; + u8 delay_between_bursts; + u8 num_of_phases_rx; + u32 start_addr; + u8 pattern_len; +}; + +/* CL value for each frequency */ +struct cl_val_per_freq { + u8 cl_val[DDR_FREQ_LIMIT]; +}; + +struct cs_element { + u8 cs_num; + u8 num_of_cs; +}; + +struct mode_info { + /* 32 bits representing MRS bits */ + u32 reg_mr0[MAX_INTERFACE_NUM]; + u32 reg_mr1[MAX_INTERFACE_NUM]; + u32 reg_mr2[MAX_INTERFACE_NUM]; + u32 reg_m_r3[MAX_INTERFACE_NUM]; + /* + * Each element in array represent read_data_sample register delay for + * a specific interface. + * Each register, 4 bits[0+CS*8 to 4+CS*8] represent Number of DDR + * cycles from read command until data is ready to be fetched from + * the PHY, when accessing CS. + */ + u32 read_data_sample[MAX_INTERFACE_NUM]; + /* + * Each element in array represent read_data_sample register delay for + * a specific interface. + * Each register, 4 bits[0+CS*8 to 4+CS*8] represent the total delay + * from read command until opening the read mask, when accessing CS. + * This field defines the delay in DDR cycles granularity. + */ + u32 read_data_ready[MAX_INTERFACE_NUM]; +}; + +struct hws_tip_freq_config_info { + u8 is_supported; + u8 bw_per_freq; + u8 rate_per_freq; +}; + +struct hws_cs_config_info { + u32 cs_reg_value; + u32 cs_cbe_value; +}; + +struct dfx_access { + u8 pipe; + u8 client; +}; + +struct hws_xsb_info { + struct dfx_access *dfx_table; +}; + +int ddr3_tip_register_dq_table(u32 dev_num, u32 *table); +int hws_ddr3_tip_select_ddr_controller(u32 dev_num, int enable); +int hws_ddr3_tip_init_controller(u32 dev_num, + struct init_cntr_param *init_cntr_prm); +int hws_ddr3_tip_load_topology_map(u32 dev_num, + struct hws_topology_map *topology); +int hws_ddr3_tip_run_alg(u32 dev_num, enum hws_algo_type algo_type); +int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info); +int hws_ddr3_tip_read_training_result(u32 dev_num, + enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]); +int ddr3_tip_is_pup_lock(u32 *pup_buf, enum hws_training_result read_mode); +u8 ddr3_tip_get_buf_min(u8 *buf_ptr); +u8 ddr3_tip_get_buf_max(u8 *buf_ptr); + +#endif /* _DDR3_TRAINING_IP_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h new file mode 100644 index 0000000..5c9bfe9 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_bist.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_BIST_H_ +#define _DDR3_TRAINING_IP_BIST_H_ + +#include "ddr3_training_ip.h" + +enum hws_bist_operation { + BIST_STOP = 0, + BIST_START = 1 +}; + +enum hws_stress_jump { + STRESS_NONE = 0, + STRESS_ENABLE = 1 +}; + +enum hws_pattern_duration { + DURATION_SINGLE = 0, + DURATION_STOP_AT_FAIL = 1, + DURATION_ADDRESS = 2, + DURATION_CONT = 4 +}; + +struct bist_result { + u32 bist_error_cnt; + u32 bist_fail_low; + u32 bist_fail_high; + u32 bist_last_fail_addr; +}; + +int ddr3_tip_bist_read_result(u32 dev_num, u32 if_id, + struct bist_result *pst_bist_result); +int ddr3_tip_bist_activate(u32 dev_num, enum hws_pattern pattern, + enum hws_access_type access_type, + u32 if_num, enum hws_dir direction, + enum hws_stress_jump addr_stress_jump, + enum hws_pattern_duration duration, + enum hws_bist_operation oper_type, + u32 offset, u32 cs_num, u32 pattern_addr_length); +int hws_ddr3_run_bist(u32 dev_num, enum hws_pattern pattern, u32 *result, + u32 cs_num); +int ddr3_tip_run_sweep_test(int dev_num, u32 repeat_num, u32 direction, + u32 mode); +int ddr3_tip_print_regs(u32 dev_num); +int ddr3_tip_reg_dump(u32 dev_num); +int run_xsb_test(u32 dev_num, u32 mem_addr, u32 write_type, u32 read_type, + u32 burst_length); + +#endif /* _DDR3_TRAINING_IP_BIST_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h new file mode 100644 index 0000000..7c57603 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_centralization.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_CENTRALIZATION_H +#define _DDR3_TRAINING_IP_CENTRALIZATION_H + +int ddr3_tip_centralization_tx(u32 dev_num); +int ddr3_tip_centralization_rx(u32 dev_num); +int ddr3_tip_print_centralization_result(u32 dev_num); +int ddr3_tip_special_rx(u32 dev_num); + +#endif /* _DDR3_TRAINING_IP_CENTRALIZATION_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h new file mode 100644 index 0000000..c0afa77 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_db.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_DB_H_ +#define _DDR3_TRAINING_IP_DB_H_ + +enum hws_pattern { + PATTERN_PBS1, + PATTERN_PBS2, + PATTERN_RL, + PATTERN_STATIC_PBS, + PATTERN_KILLER_DQ0, + PATTERN_KILLER_DQ1, + PATTERN_KILLER_DQ2, + PATTERN_KILLER_DQ3, + PATTERN_KILLER_DQ4, + PATTERN_KILLER_DQ5, + PATTERN_KILLER_DQ6, + PATTERN_KILLER_DQ7, + PATTERN_PBS3, + PATTERN_RL2, + PATTERN_TEST, + PATTERN_FULL_SSO0, + PATTERN_FULL_SSO1, + PATTERN_FULL_SSO2, + PATTERN_FULL_SSO3, + PATTERN_VREF, + PATTERN_LIMIT +}; + +#endif /* _DDR3_TRAINING_IP_DB_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h new file mode 100644 index 0000000..51a66d8 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_DEF_H +#define _DDR3_TRAINING_IP_DEF_H + +#include "silicon_if.h" + +#define PATTERN_55 0x55555555 +#define PATTERN_AA 0xaaaaaaaa +#define PATTERN_80 0x80808080 +#define PATTERN_20 0x20202020 +#define PATTERN_01 0x01010101 +#define PATTERN_FF 0xffffffff +#define PATTERN_00 0x00000000 + +/* 16bit bus width patterns */ +#define PATTERN_55AA 0x5555aaaa +#define PATTERN_00FF 0x0000ffff +#define PATTERN_0080 0x00008080 + +#define INVALID_VALUE 0xffffffff +#define MAX_NUM_OF_DUNITS 32 +/* + * length *2 = length in words of pattern, first low address, + * second high address + */ +#define TEST_PATTERN_LENGTH 4 +#define KILLER_PATTERN_DQ_NUMBER 8 +#define SSO_DQ_NUMBER 4 +#define PATTERN_MAXIMUM_LENGTH 64 +#define ADLL_TX_LENGTH 64 +#define ADLL_RX_LENGTH 32 + +#define PARAM_NOT_CARE 0 + +#define READ_LEVELING_PHY_OFFSET 2 +#define WRITE_LEVELING_PHY_OFFSET 0 + +#define MASK_ALL_BITS 0xffffffff + +#define CS_BIT_MASK 0xf + +/* DFX access */ +#define BROADCAST_ID 28 +#define MULTICAST_ID 29 + +#define XSB_BASE_ADDR 0x00004000 +#define XSB_CTRL_0_REG 0x00000000 +#define XSB_CTRL_1_REG 0x00000004 +#define XSB_CMD_REG 0x00000008 +#define XSB_ADDRESS_REG 0x0000000c +#define XSB_DATA_REG 0x00000010 +#define PIPE_ENABLE_ADDR 0x000f8000 +#define ENABLE_DDR_TUNING_ADDR 0x000f829c + +#define CLIENT_BASE_ADDR 0x00002000 +#define CLIENT_CTRL_REG 0x00000000 + +#define TARGET_INT 0x1801 +#define TARGET_EXT 0x180e +#define BYTE_EN 0 +#define CMD_READ 0 +#define CMD_WRITE 1 + +#define INTERNAL_ACCESS_PORT 1 +#define EXECUTING 1 +#define ACCESS_EXT 1 +#define CS2_EXIST_BIT 2 +#define TRAINING_ID 0xf +#define EXT_TRAINING_ID 1 +#define EXT_MODE 0x4 + +#define GET_RESULT_STATE(res) (res) +#define SET_RESULT_STATE(res, state) (res = state) + +#define _1K 0x00000400 +#define _4K 0x00001000 +#define _8K 0x00002000 +#define _16K 0x00004000 +#define _32K 0x00008000 +#define _64K 0x00010000 +#define _128K 0x00020000 +#define _256K 0x00040000 +#define _512K 0x00080000 + +#define _1M 0x00100000 +#define _2M 0x00200000 +#define _4M 0x00400000 +#define _8M 0x00800000 +#define _16M 0x01000000 +#define _32M 0x02000000 +#define _64M 0x04000000 +#define _128M 0x08000000 +#define _256M 0x10000000 +#define _512M 0x20000000 + +#define _1G 0x40000000 +#define _2G 0x80000000 + +#define ADDR_SIZE_512MB 0x04000000 +#define ADDR_SIZE_1GB 0x08000000 +#define ADDR_SIZE_2GB 0x10000000 +#define ADDR_SIZE_4GB 0x20000000 +#define ADDR_SIZE_8GB 0x40000000 + +enum hws_edge_compare { + EDGE_PF, + EDGE_FP, + EDGE_FPF, + EDGE_PFP +}; + +enum hws_control_element { + HWS_CONTROL_ELEMENT_ADLL, /* per bit 1 edge */ + HWS_CONTROL_ELEMENT_DQ_SKEW, + HWS_CONTROL_ELEMENT_DQS_SKEW +}; + +enum hws_search_dir { + HWS_LOW2HIGH, + HWS_HIGH2LOW, + HWS_SEARCH_DIR_LIMIT +}; + +enum hws_page_size { + PAGE_SIZE_1K, + PAGE_SIZE_2K +}; + +enum hws_operation { + OPERATION_READ = 0, + OPERATION_WRITE = 1 +}; + +enum hws_training_ip_stat { + HWS_TRAINING_IP_STATUS_FAIL, + HWS_TRAINING_IP_STATUS_SUCCESS, + HWS_TRAINING_IP_STATUS_TIMEOUT +}; + +enum hws_ddr_cs { + CS_SINGLE, + CS_NON_SINGLE +}; + +enum hws_ddr_phy { + DDR_PHY_DATA = 0, + DDR_PHY_CONTROL = 1 +}; + +enum hws_dir { + OPER_WRITE, + OPER_READ, + OPER_WRITE_AND_READ +}; + +enum hws_wl_supp { + PHASE_SHIFT, + CLOCK_SHIFT, + ALIGN_SHIFT +}; + +struct reg_data { + u32 reg_addr; + u32 reg_data; + u32 reg_mask; +}; + +#endif /* _DDR3_TRAINING_IP_DEF_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c new file mode 100644 index 0000000..011824a --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c @@ -0,0 +1,1354 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define PATTERN_1 0x55555555 +#define PATTERN_2 0xaaaaaaaa + +#define VALIDATE_TRAINING_LIMIT(e1, e2) \ + ((((e2) - (e1) + 1) > 33) && ((e1) < 67)) + +u32 phy_reg_bk[MAX_INTERFACE_NUM][MAX_BUS_NUM][BUS_WIDTH_IN_BITS]; + +u32 training_res[MAX_INTERFACE_NUM * MAX_BUS_NUM * BUS_WIDTH_IN_BITS * + HWS_SEARCH_DIR_LIMIT]; + +u16 mask_results_dq_reg_map[] = { + RESULT_CONTROL_PUP_0_BIT_0_REG, RESULT_CONTROL_PUP_0_BIT_1_REG, + RESULT_CONTROL_PUP_0_BIT_2_REG, RESULT_CONTROL_PUP_0_BIT_3_REG, + RESULT_CONTROL_PUP_0_BIT_4_REG, RESULT_CONTROL_PUP_0_BIT_5_REG, + RESULT_CONTROL_PUP_0_BIT_6_REG, RESULT_CONTROL_PUP_0_BIT_7_REG, + RESULT_CONTROL_PUP_1_BIT_0_REG, RESULT_CONTROL_PUP_1_BIT_1_REG, + RESULT_CONTROL_PUP_1_BIT_2_REG, RESULT_CONTROL_PUP_1_BIT_3_REG, + RESULT_CONTROL_PUP_1_BIT_4_REG, RESULT_CONTROL_PUP_1_BIT_5_REG, + RESULT_CONTROL_PUP_1_BIT_6_REG, RESULT_CONTROL_PUP_1_BIT_7_REG, + RESULT_CONTROL_PUP_2_BIT_0_REG, RESULT_CONTROL_PUP_2_BIT_1_REG, + RESULT_CONTROL_PUP_2_BIT_2_REG, RESULT_CONTROL_PUP_2_BIT_3_REG, + RESULT_CONTROL_PUP_2_BIT_4_REG, RESULT_CONTROL_PUP_2_BIT_5_REG, + RESULT_CONTROL_PUP_2_BIT_6_REG, RESULT_CONTROL_PUP_2_BIT_7_REG, + RESULT_CONTROL_PUP_3_BIT_0_REG, RESULT_CONTROL_PUP_3_BIT_1_REG, + RESULT_CONTROL_PUP_3_BIT_2_REG, RESULT_CONTROL_PUP_3_BIT_3_REG, + RESULT_CONTROL_PUP_3_BIT_4_REG, RESULT_CONTROL_PUP_3_BIT_5_REG, + RESULT_CONTROL_PUP_3_BIT_6_REG, RESULT_CONTROL_PUP_3_BIT_7_REG, + RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG, + RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG, + RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG, + RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG, +}; + +u16 mask_results_pup_reg_map[] = { + RESULT_CONTROL_BYTE_PUP_0_REG, RESULT_CONTROL_BYTE_PUP_1_REG, + RESULT_CONTROL_BYTE_PUP_2_REG, RESULT_CONTROL_BYTE_PUP_3_REG, + RESULT_CONTROL_BYTE_PUP_4_REG +}; + +u16 mask_results_dq_reg_map_pup3_ecc[] = { + RESULT_CONTROL_PUP_0_BIT_0_REG, RESULT_CONTROL_PUP_0_BIT_1_REG, + RESULT_CONTROL_PUP_0_BIT_2_REG, RESULT_CONTROL_PUP_0_BIT_3_REG, + RESULT_CONTROL_PUP_0_BIT_4_REG, RESULT_CONTROL_PUP_0_BIT_5_REG, + RESULT_CONTROL_PUP_0_BIT_6_REG, RESULT_CONTROL_PUP_0_BIT_7_REG, + RESULT_CONTROL_PUP_1_BIT_0_REG, RESULT_CONTROL_PUP_1_BIT_1_REG, + RESULT_CONTROL_PUP_1_BIT_2_REG, RESULT_CONTROL_PUP_1_BIT_3_REG, + RESULT_CONTROL_PUP_1_BIT_4_REG, RESULT_CONTROL_PUP_1_BIT_5_REG, + RESULT_CONTROL_PUP_1_BIT_6_REG, RESULT_CONTROL_PUP_1_BIT_7_REG, + RESULT_CONTROL_PUP_2_BIT_0_REG, RESULT_CONTROL_PUP_2_BIT_1_REG, + RESULT_CONTROL_PUP_2_BIT_2_REG, RESULT_CONTROL_PUP_2_BIT_3_REG, + RESULT_CONTROL_PUP_2_BIT_4_REG, RESULT_CONTROL_PUP_2_BIT_5_REG, + RESULT_CONTROL_PUP_2_BIT_6_REG, RESULT_CONTROL_PUP_2_BIT_7_REG, + RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG, + RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG, + RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG, + RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG, + RESULT_CONTROL_PUP_4_BIT_0_REG, RESULT_CONTROL_PUP_4_BIT_1_REG, + RESULT_CONTROL_PUP_4_BIT_2_REG, RESULT_CONTROL_PUP_4_BIT_3_REG, + RESULT_CONTROL_PUP_4_BIT_4_REG, RESULT_CONTROL_PUP_4_BIT_5_REG, + RESULT_CONTROL_PUP_4_BIT_6_REG, RESULT_CONTROL_PUP_4_BIT_7_REG, +}; + +u16 mask_results_pup_reg_map_pup3_ecc[] = { + RESULT_CONTROL_BYTE_PUP_0_REG, RESULT_CONTROL_BYTE_PUP_1_REG, + RESULT_CONTROL_BYTE_PUP_2_REG, RESULT_CONTROL_BYTE_PUP_4_REG, + RESULT_CONTROL_BYTE_PUP_4_REG +}; + +struct pattern_info pattern_table_16[] = { + /* + * num tx phases, tx burst, delay between, rx pattern, + * start_address, pattern_len + */ + {1, 1, 2, 1, 0x0080, 2}, /* PATTERN_PBS1 */ + {1, 1, 2, 1, 0x00c0, 2}, /* PATTERN_PBS2 */ + {1, 1, 2, 1, 0x0100, 2}, /* PATTERN_RL */ + {0xf, 0x7, 2, 0x7, 0x0140, 16}, /* PATTERN_STATIC_PBS */ + {0xf, 0x7, 2, 0x7, 0x0190, 16}, /* PATTERN_KILLER_DQ0 */ + {0xf, 0x7, 2, 0x7, 0x01d0, 16}, /* PATTERN_KILLER_DQ1 */ + {0xf, 0x7, 2, 0x7, 0x0210, 16}, /* PATTERN_KILLER_DQ2 */ + {0xf, 0x7, 2, 0x7, 0x0250, 16}, /* PATTERN_KILLER_DQ3 */ + {0xf, 0x7, 2, 0x7, 0x0290, 16}, /* PATTERN_KILLER_DQ4 */ + {0xf, 0x7, 2, 0x7, 0x02d0, 16}, /* PATTERN_KILLER_DQ5 */ + {0xf, 0x7, 2, 0x7, 0x0310, 16}, /* PATTERN_KILLER_DQ6 */ + {0xf, 0x7, 2, 0x7, 0x0350, 16}, /* PATTERN_KILLER_DQ7 */ + {1, 1, 2, 1, 0x0380, 2}, /* PATTERN_PBS3 */ + {1, 1, 2, 1, 0x0000, 2}, /* PATTERN_RL2 */ + {1, 1, 2, 1, 0x0040, 2}, /* PATTERN_TEST */ + {0xf, 0x7, 2, 0x7, 0x03c0, 16}, /* PATTERN_FULL_SSO_1T */ + {0xf, 0x7, 2, 0x7, 0x0400, 16}, /* PATTERN_FULL_SSO_2T */ + {0xf, 0x7, 2, 0x7, 0x0440, 16}, /* PATTERN_FULL_SSO_3T */ + {0xf, 0x7, 2, 0x7, 0x0480, 16}, /* PATTERN_FULL_SSO_4T */ + {0xf, 0x7, 2, 0x7, 0x04c0, 16} /* PATTERN_VREF */ + /*Note: actual start_address is <<3 of defined addess */ +}; + +struct pattern_info pattern_table_32[] = { + /* + * num tx phases, tx burst, delay between, rx pattern, + * start_address, pattern_len + */ + {3, 3, 2, 3, 0x0080, 4}, /* PATTERN_PBS1 */ + {3, 3, 2, 3, 0x00c0, 4}, /* PATTERN_PBS2 */ + {3, 3, 2, 3, 0x0100, 4}, /* PATTERN_RL */ + {0x1f, 0xf, 2, 0xf, 0x0140, 32}, /* PATTERN_STATIC_PBS */ + {0x1f, 0xf, 2, 0xf, 0x0190, 32}, /* PATTERN_KILLER_DQ0 */ + {0x1f, 0xf, 2, 0xf, 0x01d0, 32}, /* PATTERN_KILLER_DQ1 */ + {0x1f, 0xf, 2, 0xf, 0x0210, 32}, /* PATTERN_KILLER_DQ2 */ + {0x1f, 0xf, 2, 0xf, 0x0250, 32}, /* PATTERN_KILLER_DQ3 */ + {0x1f, 0xf, 2, 0xf, 0x0290, 32}, /* PATTERN_KILLER_DQ4 */ + {0x1f, 0xf, 2, 0xf, 0x02d0, 32}, /* PATTERN_KILLER_DQ5 */ + {0x1f, 0xf, 2, 0xf, 0x0310, 32}, /* PATTERN_KILLER_DQ6 */ + {0x1f, 0xf, 2, 0xf, 0x0350, 32}, /* PATTERN_KILLER_DQ7 */ + {3, 3, 2, 3, 0x0380, 4}, /* PATTERN_PBS3 */ + {3, 3, 2, 3, 0x0000, 4}, /* PATTERN_RL2 */ + {3, 3, 2, 3, 0x0040, 4}, /* PATTERN_TEST */ + {0x1f, 0xf, 2, 0xf, 0x03c0, 32}, /* PATTERN_FULL_SSO_1T */ + {0x1f, 0xf, 2, 0xf, 0x0400, 32}, /* PATTERN_FULL_SSO_2T */ + {0x1f, 0xf, 2, 0xf, 0x0440, 32}, /* PATTERN_FULL_SSO_3T */ + {0x1f, 0xf, 2, 0xf, 0x0480, 32}, /* PATTERN_FULL_SSO_4T */ + {0x1f, 0xf, 2, 0xf, 0x04c0, 32} /* PATTERN_VREF */ + /*Note: actual start_address is <<3 of defined addess */ +}; + +u32 train_dev_num; +enum hws_ddr_cs traintrain_cs_type; +u32 train_pup_num; +enum hws_training_result train_result_type; +enum hws_control_element train_control_element; +enum hws_search_dir traine_search_dir; +enum hws_dir train_direction; +u32 train_if_select; +u32 train_init_value; +u32 train_number_iterations; +enum hws_pattern train_pattern; +enum hws_edge_compare train_edge_compare; +u32 train_cs_num; +u32 train_if_acess, train_if_id, train_pup_access; +u32 max_polling_for_done = 1000000; + +u32 *ddr3_tip_get_buf_ptr(u32 dev_num, enum hws_search_dir search, + enum hws_training_result result_type, + u32 interface_num) +{ + u32 *buf_ptr = NULL; + + buf_ptr = &training_res + [MAX_INTERFACE_NUM * MAX_BUS_NUM * BUS_WIDTH_IN_BITS * search + + interface_num * MAX_BUS_NUM * BUS_WIDTH_IN_BITS]; + + return buf_ptr; +} + +/* + * IP Training search + * Note: for one edge search only from fail to pass, else jitter can + * be be entered into solution. + */ +int ddr3_tip_ip_training(u32 dev_num, enum hws_access_type access_type, + u32 interface_num, + enum hws_access_type pup_access_type, + u32 pup_num, enum hws_training_result result_type, + enum hws_control_element control_element, + enum hws_search_dir search_dir, enum hws_dir direction, + u32 interface_mask, u32 init_value, u32 num_iter, + enum hws_pattern pattern, + enum hws_edge_compare edge_comp, + enum hws_ddr_cs cs_type, u32 cs_num, + enum hws_training_ip_stat *train_status) +{ + u32 mask_dq_num_of_regs, mask_pup_num_of_regs, index_cnt, poll_cnt, + reg_data, pup_id; + u32 tx_burst_size; + u32 delay_between_burst; + u32 rd_mode; + u32 read_data[MAX_INTERFACE_NUM]; + struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); + u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); + u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (pup_num >= tm->num_of_bus_per_interface) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("pup_num %d not valid\n", pup_num)); + } + if (interface_num >= MAX_INTERFACE_NUM) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("if_id %d not valid\n", + interface_num)); + } + if (train_status == NULL) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("error param 4\n")); + return MV_BAD_PARAM; + } + + /* load pattern */ + if (cs_type == CS_SINGLE) { + /* All CSs to CS0 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + CS_ENABLE_REG, 1 << 3, 1 << 3)); + /* All CSs to CS0 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + ODPG_DATA_CONTROL_REG, + (0x3 | (effective_cs << 26)), 0xc000003)); + } else { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + CS_ENABLE_REG, 0, 1 << 3)); + /* CS select */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + ODPG_DATA_CONTROL_REG, 0x3 | cs_num << 26, + 0x3 | 3 << 26)); + } + + /* load pattern to ODPG */ + ddr3_tip_load_pattern_to_odpg(dev_num, access_type, interface_num, + pattern, + pattern_table[pattern].start_addr); + tx_burst_size = (direction == OPER_WRITE) ? + pattern_table[pattern].tx_burst_size : 0; + delay_between_burst = (direction == OPER_WRITE) ? 2 : 0; + rd_mode = (direction == OPER_WRITE) ? 1 : 0; + CHECK_STATUS(ddr3_tip_configure_odpg + (dev_num, access_type, interface_num, direction, + pattern_table[pattern].num_of_phases_tx, tx_burst_size, + pattern_table[pattern].num_of_phases_rx, + delay_between_burst, rd_mode, effective_cs, STRESS_NONE, + DURATION_SINGLE)); + reg_data = (direction == OPER_READ) ? 0 : (0x3 << 30); + reg_data |= (direction == OPER_READ) ? 0x60 : 0xfa; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + ODPG_WRITE_READ_MODE_ENABLE_REG, reg_data, + MASK_ALL_BITS)); + reg_data = (edge_comp == EDGE_PF || edge_comp == EDGE_FP) ? 0 : 1 << 6; + reg_data |= (edge_comp == EDGE_PF || edge_comp == EDGE_PFP) ? + (1 << 7) : 0; + + /* change from Pass to Fail will lock the result */ + if (pup_access_type == ACCESS_TYPE_MULTICAST) + reg_data |= 0xe << 14; + else + reg_data |= pup_num << 14; + + if (edge_comp == EDGE_FP) { + /* don't search for readl edge change, only the state */ + reg_data |= (0 << 20); + } else if (edge_comp == EDGE_FPF) { + reg_data |= (0 << 20); + } else { + reg_data |= (3 << 20); + } + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + ODPG_TRAINING_CONTROL_REG, + reg_data | (0x7 << 8) | (0x7 << 11), + (0x3 | (0x3 << 2) | (0x3 << 6) | (1 << 5) | (0x7 << 8) | + (0x7 << 11) | (0xf << 14) | (0x3 << 18) | (3 << 20)))); + reg_data = (search_dir == HWS_LOW2HIGH) ? 0 : (1 << 8); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, ODPG_OBJ1_OPCODE_REG, + 1 | reg_data | init_value << 9 | (1 << 25) | (1 << 26), + 0xff | (1 << 8) | (0xffff << 9) | (1 << 25) | (1 << 26))); + + /* + * Write2_dunit(0x10b4, Number_iteration , [15:0]) + * Max number of iterations + */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, interface_num, + ODPG_OBJ1_ITER_CNT_REG, num_iter, + 0xffff)); + if (control_element == HWS_CONTROL_ELEMENT_DQ_SKEW && + direction == OPER_READ) { + /* + * Write2_dunit(0x10c0, 0x5f , [7:0]) + * MC PBS Reg Address at DDR PHY + */ + reg_data = 0x5f + + effective_cs * CALIBRATED_OBJECTS_REG_ADDR_OFFSET; + } else if (control_element == HWS_CONTROL_ELEMENT_DQ_SKEW && + direction == OPER_WRITE) { + reg_data = 0x1f + + effective_cs * CALIBRATED_OBJECTS_REG_ADDR_OFFSET; + } else if (control_element == HWS_CONTROL_ELEMENT_ADLL && + direction == OPER_WRITE) { + /* + * LOOP 0x00000001 + 4*n: + * where n (0-3) represents M_CS number + */ + /* + * Write2_dunit(0x10c0, 0x1 , [7:0]) + * ADLL WR Reg Address at DDR PHY + */ + reg_data = 1 + effective_cs * CS_REGISTER_ADDR_OFFSET; + } else if (control_element == HWS_CONTROL_ELEMENT_ADLL && + direction == OPER_READ) { + /* ADLL RD Reg Address at DDR PHY */ + reg_data = 3 + effective_cs * CS_REGISTER_ADDR_OFFSET; + } else if (control_element == HWS_CONTROL_ELEMENT_DQS_SKEW && + direction == OPER_WRITE) { + /* TBD not defined in 0.5.0 requirement */ + } else if (control_element == HWS_CONTROL_ELEMENT_DQS_SKEW && + direction == OPER_READ) { + /* TBD not defined in 0.5.0 requirement */ + } + + reg_data |= (0x6 << 28); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, CALIB_OBJ_PRFA_REG, + reg_data | (init_value << 8), + 0xff | (0xffff << 8) | (0xf << 24) | (u32) (0xf << 28))); + + mask_dq_num_of_regs = tm->num_of_bus_per_interface * BUS_WIDTH_IN_BITS; + mask_pup_num_of_regs = tm->num_of_bus_per_interface; + + if (result_type == RESULT_PER_BIT) { + for (index_cnt = 0; index_cnt < mask_dq_num_of_regs; + index_cnt++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + mask_results_dq_reg_map[index_cnt], 0, + 1 << 24)); + } + + /* Mask disabled buses */ + for (pup_id = 0; pup_id < tm->num_of_bus_per_interface; + pup_id++) { + if (IS_ACTIVE(tm->bus_act_mask, pup_id) == 1) + continue; + + for (index_cnt = (mask_dq_num_of_regs - pup_id * 8); + index_cnt < + (mask_dq_num_of_regs - (pup_id + 1) * 8); + index_cnt++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, + interface_num, + mask_results_dq_reg_map + [index_cnt], (1 << 24), 1 << 24)); + } + } + + for (index_cnt = 0; index_cnt < mask_pup_num_of_regs; + index_cnt++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + mask_results_pup_reg_map[index_cnt], + (1 << 24), 1 << 24)); + } + } else if (result_type == RESULT_PER_BYTE) { + /* write to adll */ + for (index_cnt = 0; index_cnt < mask_pup_num_of_regs; + index_cnt++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + mask_results_pup_reg_map[index_cnt], 0, + 1 << 24)); + } + for (index_cnt = 0; index_cnt < mask_dq_num_of_regs; + index_cnt++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, interface_num, + mask_results_dq_reg_map[index_cnt], + (1 << 24), (1 << 24))); + } + } + + /* Start Training Trigger */ + CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, interface_num, + ODPG_TRAINING_TRIGGER_REG, 1, 1)); + /* wait for all RFU tests to finish (or timeout) */ + /* WA for 16 bit mode, more investigation needed */ + mdelay(1); + + /* Training "Done ?" */ + for (index_cnt = 0; index_cnt < MAX_INTERFACE_NUM; index_cnt++) { + if (IS_ACTIVE(tm->if_act_mask, index_cnt) == 0) + continue; + + if (interface_mask & (1 << index_cnt)) { + /* need to check results for this Dunit */ + for (poll_cnt = 0; poll_cnt < max_polling_for_done; + poll_cnt++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + index_cnt, + ODPG_TRAINING_STATUS_REG, + ®_data, MASK_ALL_BITS)); + if ((reg_data & 0x2) != 0) { + /*done */ + train_status[index_cnt] = + HWS_TRAINING_IP_STATUS_SUCCESS; + break; + } + } + + if (poll_cnt == max_polling_for_done) { + train_status[index_cnt] = + HWS_TRAINING_IP_STATUS_TIMEOUT; + } + } + /* Be sure that ODPG done */ + CHECK_STATUS(is_odpg_access_done(dev_num, index_cnt)); + } + + /* Write ODPG done in Dunit */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_STATUS_DONE_REG, 0, 0x1)); + + /* wait for all Dunit tests to finish (or timeout) */ + /* Training "Done ?" */ + /* Training "Pass ?" */ + for (index_cnt = 0; index_cnt < MAX_INTERFACE_NUM; index_cnt++) { + if (IS_ACTIVE(tm->if_act_mask, index_cnt) == 0) + continue; + + if (interface_mask & (1 << index_cnt)) { + /* need to check results for this Dunit */ + for (poll_cnt = 0; poll_cnt < max_polling_for_done; + poll_cnt++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + index_cnt, + ODPG_TRAINING_TRIGGER_REG, + read_data, MASK_ALL_BITS)); + reg_data = read_data[index_cnt]; + if ((reg_data & 0x2) != 0) { + /* done */ + if ((reg_data & 0x4) == 0) { + train_status[index_cnt] = + HWS_TRAINING_IP_STATUS_SUCCESS; + } else { + train_status[index_cnt] = + HWS_TRAINING_IP_STATUS_FAIL; + } + break; + } + } + + if (poll_cnt == max_polling_for_done) { + train_status[index_cnt] = + HWS_TRAINING_IP_STATUS_TIMEOUT; + } + } + } + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS)); + + return MV_OK; +} + +/* + * Load expected Pattern to ODPG + */ +int ddr3_tip_load_pattern_to_odpg(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_pattern pattern, + u32 load_addr) +{ + u32 pattern_length_cnt = 0; + struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); + + for (pattern_length_cnt = 0; + pattern_length_cnt < pattern_table[pattern].pattern_len; + pattern_length_cnt++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + ODPG_PATTERN_DATA_LOW_REG, + pattern_table_get_word(dev_num, pattern, + (u8) (pattern_length_cnt * + 2)), MASK_ALL_BITS)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + ODPG_PATTERN_DATA_HI_REG, + pattern_table_get_word(dev_num, pattern, + (u8) (pattern_length_cnt * + 2 + 1)), + MASK_ALL_BITS)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + ODPG_PATTERN_ADDR_REG, pattern_length_cnt, + MASK_ALL_BITS)); + } + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, access_type, if_id, + ODPG_PATTERN_ADDR_OFFSET_REG, load_addr, MASK_ALL_BITS)); + + return MV_OK; +} + +/* + * Configure ODPG + */ +int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_dir direction, u32 tx_phases, + u32 tx_burst_size, u32 rx_phases, + u32 delay_between_burst, u32 rd_mode, u32 cs_num, + u32 addr_stress_jump, u32 single_pattern) +{ + u32 data_value = 0; + int ret; + + data_value = ((single_pattern << 2) | (tx_phases << 5) | + (tx_burst_size << 11) | (delay_between_burst << 15) | + (rx_phases << 21) | (rd_mode << 25) | (cs_num << 26) | + (addr_stress_jump << 29)); + ret = ddr3_tip_if_write(dev_num, access_type, if_id, + ODPG_DATA_CONTROL_REG, data_value, 0xaffffffc); + if (ret != MV_OK) + return ret; + + return MV_OK; +} + +int ddr3_tip_process_result(u32 *ar_result, enum hws_edge e_edge, + enum hws_edge_search e_edge_search, + u32 *edge_result) +{ + u32 i, res; + int tap_val, max_val = -10000, min_val = 10000; + int lock_success = 1; + + for (i = 0; i < BUS_WIDTH_IN_BITS; i++) { + res = GET_LOCK_RESULT(ar_result[i]); + if (res == 0) { + lock_success = 0; + break; + } + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("lock failed for bit %d\n", i)); + } + + if (lock_success == 1) { + for (i = 0; i < BUS_WIDTH_IN_BITS; i++) { + tap_val = GET_TAP_RESULT(ar_result[i], e_edge); + if (tap_val > max_val) + max_val = tap_val; + if (tap_val < min_val) + min_val = tap_val; + if (e_edge_search == TRAINING_EDGE_MAX) + *edge_result = (u32) max_val; + else + *edge_result = (u32) min_val; + + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("i %d ar_result[i] 0x%x tap_val %d max_val %d min_val %d Edge_result %d\n", + i, ar_result[i], tap_val, + max_val, min_val, + *edge_result)); + } + } else { + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Read training search result + */ +int ddr3_tip_read_training_result(u32 dev_num, u32 if_id, + enum hws_access_type pup_access_type, + u32 pup_num, u32 bit_num, + enum hws_search_dir search, + enum hws_dir direction, + enum hws_training_result result_type, + enum hws_training_load_op operation, + u32 cs_num_type, u32 **load_res, + int is_read_from_db, u8 cons_tap, + int is_check_result_validity) +{ + u32 reg_offset, pup_cnt, start_pup, end_pup, start_reg, end_reg; + u32 *interface_train_res = NULL; + u16 *reg_addr = NULL; + u32 read_data[MAX_INTERFACE_NUM]; + u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); + u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* + * Agreed assumption: all CS mask contain same number of bits, + * i.e. in multi CS, the number of CS per memory is the same for + * all pups + */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, CS_ENABLE_REG, + (cs_num_type == 0) ? 1 << 3 : 0, (1 << 3))); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_DATA_CONTROL_REG, (cs_num_type << 26), (3 << 26))); + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_TRACE, + ("Read_from_d_b %d cs_type %d oper %d result_type %d direction %d search %d pup_num %d if_id %d pup_access_type %d\n", + is_read_from_db, cs_num_type, operation, + result_type, direction, search, pup_num, + if_id, pup_access_type)); + + if ((load_res == NULL) && (is_read_from_db == 1)) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("ddr3_tip_read_training_result load_res = NULL")); + return MV_FAIL; + } + if (pup_num >= tm->num_of_bus_per_interface) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("pup_num %d not valid\n", pup_num)); + } + if (if_id >= MAX_INTERFACE_NUM) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("if_id %d not valid\n", if_id)); + } + if (result_type == RESULT_PER_BIT) + reg_addr = mask_results_dq_reg_map; + else + reg_addr = mask_results_pup_reg_map; + if (pup_access_type == ACCESS_TYPE_UNICAST) { + start_pup = pup_num; + end_pup = pup_num; + } else { /*pup_access_type == ACCESS_TYPE_MULTICAST) */ + + start_pup = 0; + end_pup = tm->num_of_bus_per_interface - 1; + } + + for (pup_cnt = start_pup; pup_cnt <= end_pup; pup_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup_cnt); + DEBUG_TRAINING_IP_ENGINE( + DEBUG_LEVEL_TRACE, + ("if_id %d start_pup %d end_pup %d pup_cnt %d\n", + if_id, start_pup, end_pup, pup_cnt)); + if (result_type == RESULT_PER_BIT) { + if (bit_num == ALL_BITS_PER_PUP) { + start_reg = pup_cnt * BUS_WIDTH_IN_BITS; + end_reg = (pup_cnt + 1) * BUS_WIDTH_IN_BITS - 1; + } else { + start_reg = + pup_cnt * BUS_WIDTH_IN_BITS + bit_num; + end_reg = pup_cnt * BUS_WIDTH_IN_BITS + bit_num; + } + } else { + start_reg = pup_cnt; + end_reg = pup_cnt; + } + + interface_train_res = + ddr3_tip_get_buf_ptr(dev_num, search, result_type, + if_id); + DEBUG_TRAINING_IP_ENGINE( + DEBUG_LEVEL_TRACE, + ("start_reg %d end_reg %d interface %p\n", + start_reg, end_reg, interface_train_res)); + if (interface_train_res == NULL) { + DEBUG_TRAINING_IP_ENGINE( + DEBUG_LEVEL_ERROR, + ("interface_train_res is NULL\n")); + return MV_FAIL; + } + + for (reg_offset = start_reg; reg_offset <= end_reg; + reg_offset++) { + if (operation == TRAINING_LOAD_OPERATION_UNLOAD) { + if (is_read_from_db == 0) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + reg_addr[reg_offset], + read_data, + MASK_ALL_BITS)); + if (is_check_result_validity == 1) { + if ((read_data[if_id] & + 0x02000000) == 0) { + interface_train_res + [reg_offset] = + 0x02000000 + + 64 + cons_tap; + } else { + interface_train_res + [reg_offset] = + read_data + [if_id] + + cons_tap; + } + } else { + interface_train_res[reg_offset] + = read_data[if_id] + + cons_tap; + } + DEBUG_TRAINING_IP_ENGINE + (DEBUG_LEVEL_TRACE, + ("reg_offset %d value 0x%x addr %p\n", + reg_offset, + interface_train_res + [reg_offset], + &interface_train_res + [reg_offset])); + } else { + *load_res = + &interface_train_res[start_reg]; + DEBUG_TRAINING_IP_ENGINE + (DEBUG_LEVEL_TRACE, + ("*load_res %p\n", *load_res)); + } + } else { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_TRACE, + ("not supported\n")); + } + } + } + + return MV_OK; +} + +/* + * Load all pattern to memory using ODPG + */ +int ddr3_tip_load_all_pattern_to_mem(u32 dev_num) +{ + u32 pattern = 0, if_id; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + training_result[training_stage][if_id] = TEST_SUCCESS; + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* enable single cs */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, (1 << 3), (1 << 3))); + } + + for (pattern = 0; pattern < PATTERN_LIMIT; pattern++) + ddr3_tip_load_pattern_to_mem(dev_num, pattern); + + return MV_OK; +} + +/* + * Wait till ODPG access is ready + */ +int is_odpg_access_done(u32 dev_num, u32 if_id) +{ + u32 poll_cnt = 0, data_value; + u32 read_data[MAX_INTERFACE_NUM]; + + for (poll_cnt = 0; poll_cnt < MAX_POLLING_ITERATIONS; poll_cnt++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_BIST_DONE, read_data, MASK_ALL_BITS)); + data_value = read_data[if_id]; + if (((data_value >> ODPG_BIST_DONE_BIT_OFFS) & 0x1) == + ODPG_BIST_DONE_BIT_VALUE) { + data_value = data_value & 0xfffffffe; + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ODPG_BIST_DONE, data_value, + MASK_ALL_BITS)); + break; + } + } + + if (poll_cnt >= MAX_POLLING_ITERATIONS) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("Bist Activate: poll failure 2\n")); + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Load specific pattern to memory using ODPG + */ +int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern pattern) +{ + u32 reg_data, if_id; + struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* load pattern to memory */ + /* + * Write Tx mode, CS0, phases, Tx burst size, delay between burst, + * rx pattern phases + */ + reg_data = + 0x1 | (pattern_table[pattern].num_of_phases_tx << 5) | + (pattern_table[pattern].tx_burst_size << 11) | + (pattern_table[pattern].delay_between_bursts << 15) | + (pattern_table[pattern].num_of_phases_rx << 21) | (0x1 << 25) | + (effective_cs << 26); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, reg_data, MASK_ALL_BITS)); + /* ODPG Write enable from BIST */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, (0x1 | (effective_cs << 26)), + 0xc000003)); + /* disable error injection */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_WRITE_DATA_ERROR_REG, 0, 0x1)); + /* load pattern to ODPG */ + ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, pattern, + pattern_table[pattern].start_addr); + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + if (IS_ACTIVE(tm->if_act_mask, if_id) == 0) + continue; + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0x1498, + 0x3, 0xf)); + } + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_ENABLE_REG, 0x1 << ODPG_ENABLE_OFFS, + (0x1 << ODPG_ENABLE_OFFS))); + + mdelay(1); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(is_odpg_access_done(dev_num, if_id)); + } + + /* Disable ODPG and stop write to memory */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, (0x1 << 30), (u32) (0x3 << 30))); + + /* return to default */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS)); + + /* Disable odt0 for CS0 training - need to adjust for multy CS */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x1498, + 0x0, 0xf)); + + /* temporary added */ + mdelay(1); + + return MV_OK; +} + +/* + * Load specific pattern to memory using CPU + */ +int ddr3_tip_load_pattern_to_mem_by_cpu(u32 dev_num, enum hws_pattern pattern, + u32 offset) +{ + /* eranba - TBD */ + return MV_OK; +} + +/* + * Training search routine + */ +int ddr3_tip_ip_training_wrapper_int(u32 dev_num, + enum hws_access_type access_type, + u32 if_id, + enum hws_access_type pup_access_type, + u32 pup_num, u32 bit_num, + enum hws_training_result result_type, + enum hws_control_element control_element, + enum hws_search_dir search_dir, + enum hws_dir direction, + u32 interface_mask, u32 init_value_l2h, + u32 init_value_h2l, u32 num_iter, + enum hws_pattern pattern, + enum hws_edge_compare edge_comp, + enum hws_ddr_cs train_cs_type, u32 cs_num, + enum hws_training_ip_stat *train_status) +{ + u32 interface_num = 0, start_if, end_if, init_value_used; + enum hws_search_dir search_dir_id, start_search, end_search; + enum hws_edge_compare edge_comp_used; + u8 cons_tap = (direction == OPER_WRITE) ? (64) : (0); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (train_status == NULL) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("train_status is NULL\n")); + return MV_FAIL; + } + + if ((train_cs_type > CS_NON_SINGLE) || + (edge_comp >= EDGE_PFP) || + (pattern >= PATTERN_LIMIT) || + (direction > OPER_WRITE_AND_READ) || + (search_dir > HWS_HIGH2LOW) || + (control_element > HWS_CONTROL_ELEMENT_DQS_SKEW) || + (result_type > RESULT_PER_BYTE) || + (pup_num >= tm->num_of_bus_per_interface) || + (pup_access_type > ACCESS_TYPE_MULTICAST) || + (if_id > 11) || (access_type > ACCESS_TYPE_MULTICAST)) { + DEBUG_TRAINING_IP_ENGINE( + DEBUG_LEVEL_ERROR, + ("wrong parameter train_cs_type %d edge_comp %d pattern %d direction %d search_dir %d control_element %d result_type %d pup_num %d pup_access_type %d if_id %d access_type %d\n", + train_cs_type, edge_comp, pattern, direction, + search_dir, control_element, result_type, pup_num, + pup_access_type, if_id, access_type)); + return MV_FAIL; + } + + if (edge_comp == EDGE_FPF) { + start_search = HWS_LOW2HIGH; + end_search = HWS_HIGH2LOW; + edge_comp_used = EDGE_FP; + } else { + start_search = search_dir; + end_search = search_dir; + edge_comp_used = edge_comp; + } + + for (search_dir_id = start_search; search_dir_id <= end_search; + search_dir_id++) { + init_value_used = (search_dir_id == HWS_LOW2HIGH) ? + init_value_l2h : init_value_h2l; + DEBUG_TRAINING_IP_ENGINE( + DEBUG_LEVEL_TRACE, + ("dev_num %d, access_type %d, if_id %d, pup_access_type %d,pup_num %d, result_type %d, control_element %d search_dir_id %d, direction %d, interface_mask %d,init_value_used %d, num_iter %d, pattern %d, edge_comp_used %d, train_cs_type %d, cs_num %d\n", + dev_num, access_type, if_id, pup_access_type, pup_num, + result_type, control_element, search_dir_id, + direction, interface_mask, init_value_used, num_iter, + pattern, edge_comp_used, train_cs_type, cs_num)); + + ddr3_tip_ip_training(dev_num, access_type, if_id, + pup_access_type, pup_num, result_type, + control_element, search_dir_id, direction, + interface_mask, init_value_used, num_iter, + pattern, edge_comp_used, train_cs_type, + cs_num, train_status); + if (access_type == ACCESS_TYPE_MULTICAST) { + start_if = 0; + end_if = MAX_INTERFACE_NUM - 1; + } else { + start_if = if_id; + end_if = if_id; + } + + for (interface_num = start_if; interface_num <= end_if; + interface_num++) { + VALIDATE_ACTIVE(tm->if_act_mask, interface_num); + cs_num = 0; + CHECK_STATUS(ddr3_tip_read_training_result + (dev_num, interface_num, pup_access_type, + pup_num, bit_num, search_dir_id, + direction, result_type, + TRAINING_LOAD_OPERATION_UNLOAD, + train_cs_type, NULL, 0, cons_tap, + 0)); + } + } + + return MV_OK; +} + +/* + * Training search & read result routine + */ +int ddr3_tip_ip_training_wrapper(u32 dev_num, enum hws_access_type access_type, + u32 if_id, + enum hws_access_type pup_access_type, + u32 pup_num, + enum hws_training_result result_type, + enum hws_control_element control_element, + enum hws_search_dir search_dir, + enum hws_dir direction, u32 interface_mask, + u32 init_value_l2h, u32 init_value_h2l, + u32 num_iter, enum hws_pattern pattern, + enum hws_edge_compare edge_comp, + enum hws_ddr_cs train_cs_type, u32 cs_num, + enum hws_training_ip_stat *train_status) +{ + u8 e1, e2; + u32 interface_cnt, bit_id, start_if, end_if, bit_end = 0; + u32 *result[HWS_SEARCH_DIR_LIMIT] = { 0 }; + u8 cons_tap = (direction == OPER_WRITE) ? (64) : (0); + u8 bit_bit_mask[MAX_BUS_NUM] = { 0 }, bit_bit_mask_active = 0; + u8 pup_id; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (pup_num >= tm->num_of_bus_per_interface) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("pup_num %d not valid\n", pup_num)); + } + + if (if_id >= MAX_INTERFACE_NUM) { + DEBUG_TRAINING_IP_ENGINE(DEBUG_LEVEL_ERROR, + ("if_id %d not valid\n", if_id)); + } + + CHECK_STATUS(ddr3_tip_ip_training_wrapper_int + (dev_num, access_type, if_id, pup_access_type, pup_num, + ALL_BITS_PER_PUP, result_type, control_element, + search_dir, direction, interface_mask, init_value_l2h, + init_value_h2l, num_iter, pattern, edge_comp, + train_cs_type, cs_num, train_status)); + + if (access_type == ACCESS_TYPE_MULTICAST) { + start_if = 0; + end_if = MAX_INTERFACE_NUM - 1; + } else { + start_if = if_id; + end_if = if_id; + } + + for (interface_cnt = start_if; interface_cnt <= end_if; + interface_cnt++) { + VALIDATE_ACTIVE(tm->if_act_mask, interface_cnt); + for (pup_id = 0; + pup_id <= (tm->num_of_bus_per_interface - 1); pup_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup_id); + if (result_type == RESULT_PER_BIT) + bit_end = BUS_WIDTH_IN_BITS - 1; + else + bit_end = 0; + + bit_bit_mask[pup_id] = 0; + for (bit_id = 0; bit_id <= bit_end; bit_id++) { + enum hws_search_dir search_dir_id; + for (search_dir_id = HWS_LOW2HIGH; + search_dir_id <= HWS_HIGH2LOW; + search_dir_id++) { + CHECK_STATUS + (ddr3_tip_read_training_result + (dev_num, interface_cnt, + ACCESS_TYPE_UNICAST, pup_id, + bit_id, search_dir_id, + direction, result_type, + TRAINING_LOAD_OPERATION_UNLOAD, + CS_SINGLE, + &result[search_dir_id], + 1, 0, 0)); + } + e1 = GET_TAP_RESULT(result[HWS_LOW2HIGH][0], + EDGE_1); + e2 = GET_TAP_RESULT(result[HWS_HIGH2LOW][0], + EDGE_1); + DEBUG_TRAINING_IP_ENGINE( + DEBUG_LEVEL_INFO, + ("wrapper if_id %d pup_id %d bit %d l2h 0x%x (e1 0x%x) h2l 0x%x (e2 0x%x)\n", + interface_cnt, pup_id, bit_id, + result[HWS_LOW2HIGH][0], e1, + result[HWS_HIGH2LOW][0], e2)); + /* TBD validate is valid only for tx */ + if (VALIDATE_TRAINING_LIMIT(e1, e2) == 1 && + GET_LOCK_RESULT(result[HWS_LOW2HIGH][0]) && + GET_LOCK_RESULT(result[HWS_LOW2HIGH][0])) { + /* Mark problem bits */ + bit_bit_mask[pup_id] |= 1 << bit_id; + bit_bit_mask_active = 1; + } + } /* For all bits */ + } /* For all PUPs */ + + /* Fix problem bits */ + if (bit_bit_mask_active != 0) { + u32 *l2h_if_train_res = NULL; + u32 *h2l_if_train_res = NULL; + l2h_if_train_res = + ddr3_tip_get_buf_ptr(dev_num, HWS_LOW2HIGH, + result_type, + interface_cnt); + h2l_if_train_res = + ddr3_tip_get_buf_ptr(dev_num, HWS_HIGH2LOW, + result_type, + interface_cnt); + + ddr3_tip_ip_training(dev_num, ACCESS_TYPE_UNICAST, + interface_cnt, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, result_type, + control_element, HWS_LOW2HIGH, + direction, interface_mask, + num_iter / 2, num_iter / 2, + pattern, EDGE_FP, train_cs_type, + cs_num, train_status); + + for (pup_id = 0; + pup_id <= (tm->num_of_bus_per_interface - 1); + pup_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup_id); + + if (bit_bit_mask[pup_id] == 0) + continue; + + for (bit_id = 0; bit_id <= bit_end; bit_id++) { + if ((bit_bit_mask[pup_id] & + (1 << bit_id)) == 0) + continue; + CHECK_STATUS + (ddr3_tip_read_training_result + (dev_num, interface_cnt, + ACCESS_TYPE_UNICAST, pup_id, + bit_id, HWS_LOW2HIGH, + direction, + result_type, + TRAINING_LOAD_OPERATION_UNLOAD, + CS_SINGLE, &l2h_if_train_res, + 0, 0, 1)); + } + } + + ddr3_tip_ip_training(dev_num, ACCESS_TYPE_UNICAST, + interface_cnt, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, result_type, + control_element, HWS_HIGH2LOW, + direction, interface_mask, + num_iter / 2, num_iter / 2, + pattern, EDGE_FP, train_cs_type, + cs_num, train_status); + + for (pup_id = 0; + pup_id <= (tm->num_of_bus_per_interface - 1); + pup_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup_id); + + if (bit_bit_mask[pup_id] == 0) + continue; + + for (bit_id = 0; bit_id <= bit_end; bit_id++) { + if ((bit_bit_mask[pup_id] & + (1 << bit_id)) == 0) + continue; + CHECK_STATUS + (ddr3_tip_read_training_result + (dev_num, interface_cnt, + ACCESS_TYPE_UNICAST, pup_id, + bit_id, HWS_HIGH2LOW, direction, + result_type, + TRAINING_LOAD_OPERATION_UNLOAD, + CS_SINGLE, &h2l_if_train_res, + 0, cons_tap, 1)); + } + } + } /* if bit_bit_mask_active */ + } /* For all Interfacess */ + + return MV_OK; +} + +/* + * Load phy values + */ +int ddr3_tip_load_phy_values(int b_load) +{ + u32 bus_cnt = 0, if_id, dev_num = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_cnt = 0; bus_cnt < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + if (b_load == 1) { + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_cnt, + DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + (effective_cs * + CS_REGISTER_ADDR_OFFSET), + &phy_reg_bk[if_id][bus_cnt] + [0])); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_cnt, + DDR_PHY_DATA, + RL_PHY_REG + + (effective_cs * + CS_REGISTER_ADDR_OFFSET), + &phy_reg_bk[if_id][bus_cnt] + [1])); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, bus_cnt, + DDR_PHY_DATA, + READ_CENTRALIZATION_PHY_REG + + (effective_cs * + CS_REGISTER_ADDR_OFFSET), + &phy_reg_bk[if_id][bus_cnt] + [2])); + } else { + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + bus_cnt, DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + (effective_cs * + CS_REGISTER_ADDR_OFFSET), + phy_reg_bk[if_id][bus_cnt] + [0])); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + bus_cnt, DDR_PHY_DATA, + RL_PHY_REG + + (effective_cs * + CS_REGISTER_ADDR_OFFSET), + phy_reg_bk[if_id][bus_cnt] + [1])); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, + bus_cnt, DDR_PHY_DATA, + READ_CENTRALIZATION_PHY_REG + + (effective_cs * + CS_REGISTER_ADDR_OFFSET), + phy_reg_bk[if_id][bus_cnt] + [2])); + } + } + } + + return MV_OK; +} + +int ddr3_tip_training_ip_test(u32 dev_num, enum hws_training_result result_type, + enum hws_search_dir search_dir, + enum hws_dir direction, + enum hws_edge_compare edge, + u32 init_val1, u32 init_val2, + u32 num_of_iterations, + u32 start_pattern, u32 end_pattern) +{ + u32 pattern, if_id, pup_id; + enum hws_training_ip_stat train_status[MAX_INTERFACE_NUM]; + u32 *res = NULL; + u32 search_state = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + ddr3_tip_load_phy_values(1); + + for (pattern = start_pattern; pattern <= end_pattern; pattern++) { + for (search_state = 0; search_state < HWS_SEARCH_DIR_LIMIT; + search_state++) { + ddr3_tip_ip_training_wrapper(dev_num, + ACCESS_TYPE_MULTICAST, 0, + ACCESS_TYPE_MULTICAST, 0, + result_type, + HWS_CONTROL_ELEMENT_ADLL, + search_dir, direction, + 0xfff, init_val1, + init_val2, + num_of_iterations, pattern, + edge, CS_SINGLE, + PARAM_NOT_CARE, + train_status); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup_id = 0; pup_id < + tm->num_of_bus_per_interface; + pup_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, + pup_id); + CHECK_STATUS + (ddr3_tip_read_training_result + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup_id, + ALL_BITS_PER_PUP, + search_state, + direction, result_type, + TRAINING_LOAD_OPERATION_UNLOAD, + CS_SINGLE, &res, 1, 0, + 0)); + if (result_type == RESULT_PER_BYTE) { + DEBUG_TRAINING_IP_ENGINE + (DEBUG_LEVEL_INFO, + ("search_state %d if_id %d pup_id %d 0x%x\n", + search_state, if_id, + pup_id, res[0])); + } else { + DEBUG_TRAINING_IP_ENGINE + (DEBUG_LEVEL_INFO, + ("search_state %d if_id %d pup_id %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + search_state, if_id, + pup_id, res[0], + res[1], res[2], + res[3], res[4], + res[5], res[6], + res[7])); + } + } + } /* interface */ + } /* search */ + } /* pattern */ + + ddr3_tip_load_phy_values(0); + + return MV_OK; +} + +struct pattern_info *ddr3_tip_get_pattern_table() +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0) + return pattern_table_32; + else + return pattern_table_16; +} + +u16 *ddr3_tip_get_mask_results_dq_reg() +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask)) + return mask_results_dq_reg_map_pup3_ecc; + else + return mask_results_dq_reg_map; +} + +u16 *ddr3_tip_get_mask_results_pup_reg_map() +{ + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask)) + return mask_results_pup_reg_map_pup3_ecc; + else + return mask_results_pup_reg_map; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h new file mode 100644 index 0000000..25b1462 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_ENGINE_H_ +#define _DDR3_TRAINING_IP_ENGINE_H_ + +#include "ddr3_training_ip_def.h" +#include "ddr3_training_ip_flow.h" + +#define EDGE_1 0 +#define EDGE_2 1 +#define ALL_PUP_TRAINING 0xe +#define PUP_RESULT_EDGE_1_MASK 0xff +#define PUP_RESULT_EDGE_2_MASK (0xff << 8) +#define PUP_LOCK_RESULT_BIT 25 + +#define GET_TAP_RESULT(reg, edge) \ + (((edge) == EDGE_1) ? ((reg) & PUP_RESULT_EDGE_1_MASK) : \ + (((reg) & PUP_RESULT_EDGE_2_MASK) >> 8)); +#define GET_LOCK_RESULT(reg) \ + (((reg) & (1<> PUP_LOCK_RESULT_BIT) + +#define EDGE_FAILURE 128 +#define ALL_BITS_PER_PUP 128 + +#define MIN_WINDOW_SIZE 6 +#define MAX_WINDOW_SIZE_RX 32 +#define MAX_WINDOW_SIZE_TX 64 + +int ddr3_tip_training_ip_test(u32 dev_num, enum hws_training_result result_type, + enum hws_search_dir search_dir, + enum hws_dir direction, + enum hws_edge_compare edge, + u32 init_val1, u32 init_val2, + u32 num_of_iterations, u32 start_pattern, + u32 end_pattern); +int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern pattern); +int ddr3_tip_load_pattern_to_mem_by_cpu(u32 dev_num, enum hws_pattern pattern, + u32 offset); +int ddr3_tip_load_all_pattern_to_mem(u32 dev_num); +int ddr3_tip_read_training_result(u32 dev_num, u32 if_id, + enum hws_access_type pup_access_type, + u32 pup_num, u32 bit_num, + enum hws_search_dir search, + enum hws_dir direction, + enum hws_training_result result_type, + enum hws_training_load_op operation, + u32 cs_num_type, u32 **load_res, + int is_read_from_db, u8 cons_tap, + int is_check_result_validity); +int ddr3_tip_ip_training(u32 dev_num, enum hws_access_type access_type, + u32 interface_num, + enum hws_access_type pup_access_type, + u32 pup_num, enum hws_training_result result_type, + enum hws_control_element control_element, + enum hws_search_dir search_dir, enum hws_dir direction, + u32 interface_mask, u32 init_value, u32 num_iter, + enum hws_pattern pattern, + enum hws_edge_compare edge_comp, + enum hws_ddr_cs cs_type, u32 cs_num, + enum hws_training_ip_stat *train_status); +int ddr3_tip_ip_training_wrapper(u32 dev_num, enum hws_access_type access_type, + u32 if_id, + enum hws_access_type pup_access_type, + u32 pup_num, + enum hws_training_result result_type, + enum hws_control_element control_element, + enum hws_search_dir search_dir, + enum hws_dir direction, + u32 interface_mask, u32 init_value1, + u32 init_value2, u32 num_iter, + enum hws_pattern pattern, + enum hws_edge_compare edge_comp, + enum hws_ddr_cs train_cs_type, u32 cs_num, + enum hws_training_ip_stat *train_status); +int is_odpg_access_done(u32 dev_num, u32 if_id); +void ddr3_tip_print_bist_res(void); +struct pattern_info *ddr3_tip_get_pattern_table(void); +u16 *ddr3_tip_get_mask_results_dq_reg(void); +u16 *ddr3_tip_get_mask_results_pup_reg_map(void); + +#endif /* _DDR3_TRAINING_IP_ENGINE_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h new file mode 100644 index 0000000..22d7ce2 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h @@ -0,0 +1,349 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_FLOW_H_ +#define _DDR3_TRAINING_IP_FLOW_H_ + +#include "ddr3_training_ip.h" +#include "ddr3_training_ip_pbs.h" + +#define MRS0_CMD 0x3 +#define MRS1_CMD 0x4 +#define MRS2_CMD 0x8 +#define MRS3_CMD 0x9 + +/* + * Definitions of INTERFACE registers + */ + +#define READ_BUFFER_SELECT 0x14a4 + +/* + * Definitions of PHY registers + */ + +#define KILLER_PATTERN_LENGTH 32 +#define EXT_ACCESS_BURST_LENGTH 8 + +#define IS_ACTIVE(if_mask , if_id) \ + ((if_mask) & (1 << (if_id))) +#define VALIDATE_ACTIVE(mask, id) \ + { \ + if (IS_ACTIVE(mask, id) == 0) \ + continue; \ + } + +#define GET_TOPOLOGY_NUM_OF_BUSES() \ + (ddr3_get_topology_map()->num_of_bus_per_interface) + +#define DDR3_IS_ECC_PUP3_MODE(if_mask) \ + (((if_mask) == 0xb) ? 1 : 0) +#define DDR3_IS_ECC_PUP4_MODE(if_mask) \ + (((((if_mask) & 0x10) == 0)) ? 0 : 1) +#define DDR3_IS_16BIT_DRAM_MODE(mask) \ + (((((mask) & 0x4) == 0)) ? 1 : 0) + +#define MEGA 1000000 +#define BUS_WIDTH_IN_BITS 8 + +/* + * DFX address Space + * Table 2: DFX address space + * Address Bits Value Description + * [31 : 20] 0x? DFX base address bases PCIe mapping + * [19 : 15] 0...Number_of_client-1 Client Index inside pipe. + * See also Table 1 Multi_cast = 29 Broadcast = 28 + * [14 : 13] 2'b01 Access to Client Internal Register + * [12 : 0] Client Internal Register offset See related Client Registers + * [14 : 13] 2'b00 Access to Ram Wrappers Internal Register + * [12 : 6] 0 Number_of_rams-1 Ram Index inside Client + * [5 : 0] Ram Wrapper Internal Register offset See related Ram Wrappers + * Registers + */ + +/* nsec */ +#define TREFI_LOW 7800 +#define TREFI_HIGH 3900 + +#define TR2R_VALUE_REG 0x180 +#define TR2R_MASK_REG 0x180 +#define TRFC_MASK_REG 0x7f +#define TR2W_MASK_REG 0x600 +#define TW2W_HIGH_VALUE_REG 0x1800 +#define TW2W_HIGH_MASK_REG 0xf800 +#define TRFC_HIGH_VALUE_REG 0x20000 +#define TRFC_HIGH_MASK_REG 0x70000 +#define TR2R_HIGH_VALUE_REG 0x0 +#define TR2R_HIGH_MASK_REG 0x380000 +#define TMOD_VALUE_REG 0x16000000 +#define TMOD_MASK_REG 0x1e000000 +#define T_VALUE_REG 0x40000000 +#define T_MASK_REG 0xc0000000 +#define AUTO_ZQC_TIMING 15384 +#define WRITE_XBAR_PORT1 0xc03f8077 +#define READ_XBAR_PORT1 0xc03f8073 +#define DISABLE_DDR_TUNING_DATA 0x02294285 +#define ENABLE_DDR_TUNING_DATA 0x12294285 + +#define ODPG_TRAINING_STATUS_REG 0x18488 +#define ODPG_TRAINING_TRIGGER_REG 0x1030 +#define ODPG_STATUS_DONE_REG 0x16fc +#define ODPG_ENABLE_REG 0x186d4 +#define ODPG_ENABLE_OFFS 0 +#define ODPG_DISABLE_OFFS 8 + +#define ODPG_TRAINING_CONTROL_REG 0x1034 +#define ODPG_OBJ1_OPCODE_REG 0x103c +#define ODPG_OBJ1_ITER_CNT_REG 0x10b4 +#define CALIB_OBJ_PRFA_REG 0x10c4 +#define ODPG_WRITE_LEVELING_DONE_CNTR_REG 0x10f8 +#define ODPG_WRITE_READ_MODE_ENABLE_REG 0x10fc +#define TRAINING_OPCODE_1_REG 0x10b4 +#define SDRAM_CONFIGURATION_REG 0x1400 +#define DDR_CONTROL_LOW_REG 0x1404 +#define SDRAM_TIMING_LOW_REG 0x1408 +#define SDRAM_TIMING_HIGH_REG 0x140c +#define SDRAM_ACCESS_CONTROL_REG 0x1410 +#define SDRAM_OPEN_PAGE_CONTROL_REG 0x1414 +#define SDRAM_OPERATION_REG 0x1418 +#define DUNIT_CONTROL_HIGH_REG 0x1424 +#define ODT_TIMING_LOW 0x1428 +#define DDR_TIMING_REG 0x142c +#define ODT_TIMING_HI_REG 0x147c +#define SDRAM_INIT_CONTROL_REG 0x1480 +#define SDRAM_ODT_CONTROL_HIGH_REG 0x1498 +#define DUNIT_ODT_CONTROL_REG 0x149c +#define READ_BUFFER_SELECT_REG 0x14a4 +#define DUNIT_MMASK_REG 0x14b0 +#define CALIB_MACHINE_CTRL_REG 0x14cc +#define DRAM_DLL_TIMING_REG 0x14e0 +#define DRAM_ZQ_INIT_TIMIMG_REG 0x14e4 +#define DRAM_ZQ_TIMING_REG 0x14e8 +#define DFS_REG 0x1528 +#define READ_DATA_SAMPLE_DELAY 0x1538 +#define READ_DATA_READY_DELAY 0x153c +#define TRAINING_REG 0x15b0 +#define TRAINING_SW_1_REG 0x15b4 +#define TRAINING_SW_2_REG 0x15b8 +#define TRAINING_PATTERN_BASE_ADDRESS_REG 0x15bc +#define TRAINING_DBG_1_REG 0x15c0 +#define TRAINING_DBG_2_REG 0x15c4 +#define TRAINING_DBG_3_REG 0x15c8 +#define RANK_CTRL_REG 0x15e0 +#define TIMING_REG 0x15e4 +#define DRAM_PHY_CONFIGURATION 0x15ec +#define MR0_REG 0x15d0 +#define MR1_REG 0x15d4 +#define MR2_REG 0x15d8 +#define MR3_REG 0x15dc +#define TIMING_REG 0x15e4 +#define ODPG_CTRL_CONTROL_REG 0x1600 +#define ODPG_DATA_CONTROL_REG 0x1630 +#define ODPG_PATTERN_ADDR_OFFSET_REG 0x1638 +#define ODPG_DATA_BUF_SIZE_REG 0x163c +#define PHY_LOCK_STATUS_REG 0x1674 +#define PHY_REG_FILE_ACCESS 0x16a0 +#define TRAINING_WRITE_LEVELING_REG 0x16ac +#define ODPG_PATTERN_ADDR_REG 0x16b0 +#define ODPG_PATTERN_DATA_HI_REG 0x16b4 +#define ODPG_PATTERN_DATA_LOW_REG 0x16b8 +#define ODPG_BIST_LAST_FAIL_ADDR_REG 0x16bc +#define ODPG_BIST_DATA_ERROR_COUNTER_REG 0x16c0 +#define ODPG_BIST_FAILED_DATA_HI_REG 0x16c4 +#define ODPG_BIST_FAILED_DATA_LOW_REG 0x16c8 +#define ODPG_WRITE_DATA_ERROR_REG 0x16cc +#define CS_ENABLE_REG 0x16d8 +#define WR_LEVELING_DQS_PATTERN_REG 0x16dc + +#define ODPG_BIST_DONE 0x186d4 +#define ODPG_BIST_DONE_BIT_OFFS 0 +#define ODPG_BIST_DONE_BIT_VALUE 0 + +#define RESULT_CONTROL_BYTE_PUP_0_REG 0x1830 +#define RESULT_CONTROL_BYTE_PUP_1_REG 0x1834 +#define RESULT_CONTROL_BYTE_PUP_2_REG 0x1838 +#define RESULT_CONTROL_BYTE_PUP_3_REG 0x183c +#define RESULT_CONTROL_BYTE_PUP_4_REG 0x18b0 + +#define RESULT_CONTROL_PUP_0_BIT_0_REG 0x18b4 +#define RESULT_CONTROL_PUP_0_BIT_1_REG 0x18b8 +#define RESULT_CONTROL_PUP_0_BIT_2_REG 0x18bc +#define RESULT_CONTROL_PUP_0_BIT_3_REG 0x18c0 +#define RESULT_CONTROL_PUP_0_BIT_4_REG 0x18c4 +#define RESULT_CONTROL_PUP_0_BIT_5_REG 0x18c8 +#define RESULT_CONTROL_PUP_0_BIT_6_REG 0x18cc +#define RESULT_CONTROL_PUP_0_BIT_7_REG 0x18f0 +#define RESULT_CONTROL_PUP_1_BIT_0_REG 0x18f4 +#define RESULT_CONTROL_PUP_1_BIT_1_REG 0x18f8 +#define RESULT_CONTROL_PUP_1_BIT_2_REG 0x18fc +#define RESULT_CONTROL_PUP_1_BIT_3_REG 0x1930 +#define RESULT_CONTROL_PUP_1_BIT_4_REG 0x1934 +#define RESULT_CONTROL_PUP_1_BIT_5_REG 0x1938 +#define RESULT_CONTROL_PUP_1_BIT_6_REG 0x193c +#define RESULT_CONTROL_PUP_1_BIT_7_REG 0x19b0 +#define RESULT_CONTROL_PUP_2_BIT_0_REG 0x19b4 +#define RESULT_CONTROL_PUP_2_BIT_1_REG 0x19b8 +#define RESULT_CONTROL_PUP_2_BIT_2_REG 0x19bc +#define RESULT_CONTROL_PUP_2_BIT_3_REG 0x19c0 +#define RESULT_CONTROL_PUP_2_BIT_4_REG 0x19c4 +#define RESULT_CONTROL_PUP_2_BIT_5_REG 0x19c8 +#define RESULT_CONTROL_PUP_2_BIT_6_REG 0x19cc +#define RESULT_CONTROL_PUP_2_BIT_7_REG 0x19f0 +#define RESULT_CONTROL_PUP_3_BIT_0_REG 0x19f4 +#define RESULT_CONTROL_PUP_3_BIT_1_REG 0x19f8 +#define RESULT_CONTROL_PUP_3_BIT_2_REG 0x19fc +#define RESULT_CONTROL_PUP_3_BIT_3_REG 0x1a30 +#define RESULT_CONTROL_PUP_3_BIT_4_REG 0x1a34 +#define RESULT_CONTROL_PUP_3_BIT_5_REG 0x1a38 +#define RESULT_CONTROL_PUP_3_BIT_6_REG 0x1a3c +#define RESULT_CONTROL_PUP_3_BIT_7_REG 0x1ab0 +#define RESULT_CONTROL_PUP_4_BIT_0_REG 0x1ab4 +#define RESULT_CONTROL_PUP_4_BIT_1_REG 0x1ab8 +#define RESULT_CONTROL_PUP_4_BIT_2_REG 0x1abc +#define RESULT_CONTROL_PUP_4_BIT_3_REG 0x1ac0 +#define RESULT_CONTROL_PUP_4_BIT_4_REG 0x1ac4 +#define RESULT_CONTROL_PUP_4_BIT_5_REG 0x1ac8 +#define RESULT_CONTROL_PUP_4_BIT_6_REG 0x1acc +#define RESULT_CONTROL_PUP_4_BIT_7_REG 0x1af0 + +#define WL_PHY_REG 0x0 +#define WRITE_CENTRALIZATION_PHY_REG 0x1 +#define RL_PHY_REG 0x2 +#define READ_CENTRALIZATION_PHY_REG 0x3 +#define PBS_RX_PHY_REG 0x50 +#define PBS_TX_PHY_REG 0x10 +#define PHY_CONTROL_PHY_REG 0x90 +#define BW_PHY_REG 0x92 +#define RATE_PHY_REG 0x94 +#define CMOS_CONFIG_PHY_REG 0xa2 +#define PAD_ZRI_CALIB_PHY_REG 0xa4 +#define PAD_ODT_CALIB_PHY_REG 0xa6 +#define PAD_CONFIG_PHY_REG 0xa8 +#define PAD_PRE_DISABLE_PHY_REG 0xa9 +#define TEST_ADLL_REG 0xbf +#define CSN_IOB_VREF_REG(cs) (0xdb + (cs * 12)) +#define CSN_IO_BASE_VREF_REG(cs) (0xd0 + (cs * 12)) + +#define RESULT_DB_PHY_REG_ADDR 0xc0 +#define RESULT_DB_PHY_REG_RX_OFFSET 5 +#define RESULT_DB_PHY_REG_TX_OFFSET 0 + +/* TBD - for NP5 use only CS 0 */ +#define PHY_WRITE_DELAY(cs) WL_PHY_REG +/*( ( _cs_ == 0 ) ? 0x0 : 0x4 )*/ +/* TBD - for NP5 use only CS 0 */ +#define PHY_READ_DELAY(cs) RL_PHY_REG + +#define DDR0_ADDR_1 0xf8258 +#define DDR0_ADDR_2 0xf8254 +#define DDR1_ADDR_1 0xf8270 +#define DDR1_ADDR_2 0xf8270 +#define DDR2_ADDR_1 0xf825c +#define DDR2_ADDR_2 0xf825c +#define DDR3_ADDR_1 0xf8264 +#define DDR3_ADDR_2 0xf8260 +#define DDR4_ADDR_1 0xf8274 +#define DDR4_ADDR_2 0xf8274 + +#define GENERAL_PURPOSE_RESERVED0_REG 0x182e0 + +#define GET_BLOCK_ID_MAX_FREQ(dev_num, block_id) 800000 +#define CS0_RD_LVL_REF_DLY_OFFS 0 +#define CS0_RD_LVL_REF_DLY_LEN 0 +#define CS0_RD_LVL_PH_SEL_OFFS 0 +#define CS0_RD_LVL_PH_SEL_LEN 0 + +#define CS_REGISTER_ADDR_OFFSET 4 +#define CALIBRATED_OBJECTS_REG_ADDR_OFFSET 0x10 + +#define MAX_POLLING_ITERATIONS 100000 + +#define PHASE_REG_OFFSET 32 +#define NUM_BYTES_IN_BURST 31 +#define NUM_OF_CS 4 +#define CS_REG_VALUE(cs_num) (cs_mask_reg[cs_num]) +#define ADLL_LENGTH 32 + +struct write_supp_result { + enum hws_wl_supp stage; + int is_pup_fail; +}; + +struct page_element { + enum hws_page_size page_size_8bit; + /* page size in 8 bits bus width */ + enum hws_page_size page_size_16bit; + /* page size in 16 bits bus width */ + u32 ui_page_mask; + /* Mask used in register */ +}; + +int ddr3_tip_write_leveling_static_config(u32 dev_num, u32 if_id, + enum hws_ddr_freq frequency, + u32 *round_trip_delay_arr); +int ddr3_tip_read_leveling_static_config(u32 dev_num, u32 if_id, + enum hws_ddr_freq frequency, + u32 *total_round_trip_delay_arr); +int ddr3_tip_if_write(u32 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 data_value, u32 mask); +int ddr3_tip_if_polling(u32 dev_num, enum hws_access_type access_type, + u32 if_id, u32 exp_value, u32 mask, u32 offset, + u32 poll_tries); +int ddr3_tip_if_read(u32 dev_num, enum hws_access_type interface_access, + u32 if_id, u32 reg_addr, u32 *data, u32 mask); +int ddr3_tip_bus_read_modify_write(u32 dev_num, + enum hws_access_type access_type, + u32 if_id, u32 phy_id, + enum hws_ddr_phy phy_type, + u32 reg_addr, u32 data_value, u32 reg_mask); +int ddr3_tip_bus_read(u32 dev_num, u32 if_id, enum hws_access_type phy_access, + u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr, + u32 *data); +int ddr3_tip_bus_write(u32 dev_num, enum hws_access_type e_interface_access, + u32 if_id, enum hws_access_type e_phy_access, u32 phy_id, + enum hws_ddr_phy e_phy_type, u32 reg_addr, + u32 data_value); +int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type e_access, u32 if_id, + enum hws_ddr_freq memory_freq); +int ddr3_tip_adjust_dqs(u32 dev_num); +int ddr3_tip_init_controller(u32 dev_num); +int ddr3_tip_ext_read(u32 dev_num, u32 if_id, u32 reg_addr, + u32 num_of_bursts, u32 *addr); +int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr, + u32 num_of_bursts, u32 *addr); +int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 ui_freq); +int ddr3_tip_legacy_dynamic_read_leveling(u32 dev_num); +int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 ui_freq); +int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num); +int ddr3_tip_dynamic_write_leveling(u32 dev_num); +int ddr3_tip_dynamic_write_leveling_supp(u32 dev_num); +int ddr3_tip_static_init_controller(u32 dev_num); +int ddr3_tip_configure_phy(u32 dev_num); +int ddr3_tip_load_pattern_to_odpg(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_pattern pattern, + u32 load_addr); +int ddr3_tip_load_pattern_to_mem(u32 dev_num, enum hws_pattern e_pattern); +int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type, + u32 if_id, enum hws_dir direction, u32 tx_phases, + u32 tx_burst_size, u32 rx_phases, + u32 delay_between_burst, u32 rd_mode, u32 cs_num, + u32 addr_stress_jump, u32 single_pattern); +int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value); +int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, u32 cmd, u32 data, + u32 mask); +int ddr3_tip_write_cs_result(u32 dev_num, u32 offset); +int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask, u32 *if_id); +int ddr3_tip_reset_fifo_ptr(u32 dev_num); +int read_pup_value(int pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], + int reg_addr, u32 mask); +int read_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], + int reg_addr, u32 mask); +int write_adll_value(u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], + int reg_addr); +int ddr3_tip_tune_training_params(u32 dev_num, + struct tune_train_params *params); + +#endif /* _DDR3_TRAINING_IP_FLOW_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h new file mode 100644 index 0000000..c6be67c --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_pbs.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_PBS_H_ +#define _DDR3_TRAINING_IP_PBS_H_ + +enum { + EBA_CONFIG, + EEBA_CONFIG, + SBA_CONFIG +}; + +enum hws_training_load_op { + TRAINING_LOAD_OPERATION_UNLOAD, + TRAINING_LOAD_OPERATION_LOAD +}; + +enum hws_edge { + TRAINING_EDGE_1, + TRAINING_EDGE_2 +}; + +enum hws_edge_search { + TRAINING_EDGE_MAX, + TRAINING_EDGE_MIN +}; + +enum pbs_dir { + PBS_TX_MODE = 0, + PBS_RX_MODE, + NUM_OF_PBS_MODES +}; + +int ddr3_tip_pbs_rx(u32 dev_num); +int ddr3_tip_print_all_pbs_result(u32 dev_num); +int ddr3_tip_pbs_tx(u32 dev_num); + +#endif /* _DDR3_TRAINING_IP_PBS_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h new file mode 100644 index 0000000..724b106 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_PRV_IF_H +#define _DDR3_TRAINING_IP_PRV_IF_H + +#include "ddr3_training_ip.h" +#include "ddr3_training_ip_flow.h" +#include "ddr3_training_ip_bist.h" + +enum hws_static_config_type { + WRITE_LEVELING_STATIC, + READ_LEVELING_STATIC +}; + +struct ddr3_device_info { + u32 device_id; + u32 ck_delay; +}; + +typedef int (*HWS_TIP_DUNIT_MUX_SELECT_FUNC_PTR)(u8 dev_num, int enable); +typedef int (*HWS_TIP_DUNIT_REG_READ_FUNC_PTR)( + u8 dev_num, enum hws_access_type interface_access, u32 if_id, + u32 offset, u32 *data, u32 mask); +typedef int (*HWS_TIP_DUNIT_REG_WRITE_FUNC_PTR)( + u8 dev_num, enum hws_access_type interface_access, u32 if_id, + u32 offset, u32 data, u32 mask); +typedef int (*HWS_TIP_GET_FREQ_CONFIG_INFO)( + u8 dev_num, enum hws_ddr_freq freq, + struct hws_tip_freq_config_info *freq_config_info); +typedef int (*HWS_TIP_GET_DEVICE_INFO)( + u8 dev_num, struct ddr3_device_info *info_ptr); +typedef int (*HWS_GET_CS_CONFIG_FUNC_PTR)( + u8 dev_num, u32 cs_mask, struct hws_cs_config_info *cs_info); +typedef int (*HWS_SET_FREQ_DIVIDER_FUNC_PTR)( + u8 dev_num, u32 if_id, enum hws_ddr_freq freq); +typedef int (*HWS_GET_INIT_FREQ)(u8 dev_num, enum hws_ddr_freq *freq); +typedef int (*HWS_TRAINING_IP_IF_WRITE_FUNC_PTR)( + u32 dev_num, enum hws_access_type access_type, u32 dunit_id, + u32 reg_addr, u32 data, u32 mask); +typedef int (*HWS_TRAINING_IP_IF_READ_FUNC_PTR)( + u32 dev_num, enum hws_access_type access_type, u32 dunit_id, + u32 reg_addr, u32 *data, u32 mask); +typedef int (*HWS_TRAINING_IP_BUS_WRITE_FUNC_PTR)( + u32 dev_num, enum hws_access_type dunit_access_type, u32 if_id, + enum hws_access_type phy_access_type, u32 phy_id, + enum hws_ddr_phy phy_type, u32 reg_addr, u32 data); +typedef int (*HWS_TRAINING_IP_BUS_READ_FUNC_PTR)( + u32 dev_num, u32 if_id, enum hws_access_type phy_access_type, + u32 phy_id, enum hws_ddr_phy phy_type, u32 reg_addr, u32 *data); +typedef int (*HWS_TRAINING_IP_ALGO_RUN_FUNC_PTR)( + u32 dev_num, enum hws_algo_type algo_type); +typedef int (*HWS_TRAINING_IP_SET_FREQ_FUNC_PTR)( + u32 dev_num, enum hws_access_type access_type, u32 if_id, + enum hws_ddr_freq frequency); +typedef int (*HWS_TRAINING_IP_INIT_CONTROLLER_FUNC_PTR)( + u32 dev_num, struct init_cntr_param *init_cntr_prm); +typedef int (*HWS_TRAINING_IP_PBS_RX_FUNC_PTR)(u32 dev_num); +typedef int (*HWS_TRAINING_IP_PBS_TX_FUNC_PTR)(u32 dev_num); +typedef int (*HWS_TRAINING_IP_SELECT_CONTROLLER_FUNC_PTR)( + u32 dev_num, int enable); +typedef int (*HWS_TRAINING_IP_TOPOLOGY_MAP_LOAD_FUNC_PTR)( + u32 dev_num, struct hws_topology_map *topology_map); +typedef int (*HWS_TRAINING_IP_STATIC_CONFIG_FUNC_PTR)( + u32 dev_num, enum hws_ddr_freq frequency, + enum hws_static_config_type static_config_type, u32 if_id); +typedef int (*HWS_TRAINING_IP_EXTERNAL_READ_PTR)( + u32 dev_num, u32 if_id, u32 ddr_addr, u32 num_bursts, u32 *data); +typedef int (*HWS_TRAINING_IP_EXTERNAL_WRITE_PTR)( + u32 dev_num, u32 if_id, u32 ddr_addr, u32 num_bursts, u32 *data); +typedef int (*HWS_TRAINING_IP_BIST_ACTIVATE)( + u32 dev_num, enum hws_pattern pattern, enum hws_access_type access_type, + u32 if_num, enum hws_dir direction, + enum hws_stress_jump addr_stress_jump, + enum hws_pattern_duration duration, + enum hws_bist_operation oper_type, u32 offset, u32 cs_num, + u32 pattern_addr_length); +typedef int (*HWS_TRAINING_IP_BIST_READ_RESULT)( + u32 dev_num, u32 if_id, struct bist_result *pst_bist_result); +typedef int (*HWS_TRAINING_IP_LOAD_TOPOLOGY)(u32 dev_num, u32 config_num); +typedef int (*HWS_TRAINING_IP_READ_LEVELING)(u32 dev_num, u32 config_num); +typedef int (*HWS_TRAINING_IP_WRITE_LEVELING)(u32 dev_num, u32 config_num); +typedef u32 (*HWS_TRAINING_IP_GET_TEMP)(u8 dev_num); + +struct hws_tip_config_func_db { + HWS_TIP_DUNIT_MUX_SELECT_FUNC_PTR tip_dunit_mux_select_func; + HWS_TIP_DUNIT_REG_READ_FUNC_PTR tip_dunit_read_func; + HWS_TIP_DUNIT_REG_WRITE_FUNC_PTR tip_dunit_write_func; + HWS_TIP_GET_FREQ_CONFIG_INFO tip_get_freq_config_info_func; + HWS_TIP_GET_DEVICE_INFO tip_get_device_info_func; + HWS_SET_FREQ_DIVIDER_FUNC_PTR tip_set_freq_divider_func; + HWS_GET_CS_CONFIG_FUNC_PTR tip_get_cs_config_info; + HWS_TRAINING_IP_GET_TEMP tip_get_temperature; +}; + +int ddr3_tip_init_config_func(u32 dev_num, + struct hws_tip_config_func_db *config_func); +int ddr3_tip_register_xsb_info(u32 dev_num, + struct hws_xsb_info *xsb_info_table); +enum hws_result *ddr3_tip_get_result_ptr(u32 stage); +int ddr3_set_freq_config_info(struct hws_tip_freq_config_info *table); +int print_device_info(u8 dev_num); + +#endif /* _DDR3_TRAINING_IP_PRV_IF_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h new file mode 100644 index 0000000..878068b --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_static.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_IP_STATIC_H_ +#define _DDR3_TRAINING_IP_STATIC_H_ + +#include "ddr3_training_ip_def.h" +#include "ddr3_training_ip.h" + +struct trip_delay_element { + u32 dqs_delay; /* DQS delay (m_sec) */ + u32 ck_delay; /* CK Delay (m_sec) */ +}; + +struct hws_tip_static_config_info { + u32 silicon_delay; + struct trip_delay_element *package_trace_arr; + struct trip_delay_element *board_trace_arr; +}; + +int ddr3_tip_run_static_alg(u32 dev_num, enum hws_ddr_freq freq); +int ddr3_tip_init_static_config_db( + u32 dev_num, struct hws_tip_static_config_info *static_config_info); +int ddr3_tip_init_specific_reg_config(u32 dev_num, + struct reg_data *reg_config_arr); +int ddr3_tip_static_phy_init_controller(u32 dev_num); + +#endif /* _DDR3_TRAINING_IP_STATIC_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.c b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c new file mode 100644 index 0000000..3c40f19 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c @@ -0,0 +1,1836 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define WL_ITERATION_NUM 10 +#define ONE_CLOCK_ERROR_SHIFT 2 +#define ALIGN_ERROR_SHIFT -2 + +static u32 pup_mask_table[] = { + 0x000000ff, + 0x0000ff00, + 0x00ff0000, + 0xff000000 +}; + +static struct write_supp_result wr_supp_res[MAX_INTERFACE_NUM][MAX_BUS_NUM]; + +static int ddr3_tip_dynamic_write_leveling_seq(u32 dev_num); +static int ddr3_tip_dynamic_read_leveling_seq(u32 dev_num); +static int ddr3_tip_dynamic_per_bit_read_leveling_seq(u32 dev_num); +static int ddr3_tip_wl_supp_align_err_shift(u32 dev_num, u32 if_id, u32 bus_id, + u32 bus_id_delta); +static int ddr3_tip_wl_supp_align_phase_shift(u32 dev_num, u32 if_id, + u32 bus_id, u32 offset, + u32 bus_id_delta); +static int ddr3_tip_xsb_compare_test(u32 dev_num, u32 if_id, u32 bus_id, + u32 edge_offset, u32 bus_id_delta); +static int ddr3_tip_wl_supp_one_clk_err_shift(u32 dev_num, u32 if_id, + u32 bus_id, u32 bus_id_delta); + +u32 hws_ddr3_tip_max_cs_get(void) +{ + u32 c_cs; + static u32 max_cs; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (!max_cs) { + for (c_cs = 0; c_cs < NUM_OF_CS; c_cs++) { + VALIDATE_ACTIVE(tm-> + interface_params[0].as_bus_params[0]. + cs_bitmask, c_cs); + max_cs++; + } + } + + return max_cs; +} + +/***************************************************************************** +Dynamic read leveling +******************************************************************************/ +int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 freq) +{ + u32 data, mask; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + u32 bus_num, if_id, cl_val; + enum hws_speed_bin speed_bin_index; + /* save current CS value */ + u32 cs_enable_reg_val[MAX_INTERFACE_NUM] = { 0 }; + int is_any_pup_fail = 0; + u32 data_read[MAX_INTERFACE_NUM + 1] = { 0 }; + u8 rl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM]; + struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); + u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + if (rl_version == 0) { + /* OLD RL machine */ + data = 0x40; + data |= (1 << 20); + + /* TBD multi CS */ + CHECK_STATUS(ddr3_tip_if_write( + dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, TRAINING_REG, + data, 0x11ffff)); + CHECK_STATUS(ddr3_tip_if_write( + dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + TRAINING_PATTERN_BASE_ADDRESS_REG, + 0, 0xfffffff8)); + CHECK_STATUS(ddr3_tip_if_write( + dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, TRAINING_REG, + (u32)(1 << 31), (u32)(1 << 31))); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + training_result[training_stage][if_id] = TEST_SUCCESS; + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, + (u32)(1 << 31), TRAINING_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("RL: DDR3 poll failed(1) IF %d\n", + if_id)); + training_result[training_stage][if_id] = + TEST_FAILED; + + if (debug_mode == 0) + return MV_FAIL; + } + } + + /* read read-leveling result */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_REG, data_read, 1 << 30)); + /* exit read leveling mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x8, 0x9)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_1_REG, 1 << 16, 1 << 16)); + + /* disable RL machine all Trn_CS[3:0] , [16:0] */ + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_REG, 0, 0xf1ffff)); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if ((data_read[if_id] & (1 << 30)) == 0) { + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("\n_read Leveling failed for IF %d\n", + if_id)); + training_result[training_stage][if_id] = + TEST_FAILED; + if (debug_mode == 0) + return MV_FAIL; + } + } + return MV_OK; + } + + /* NEW RL machine */ + for (effective_cs = 0; effective_cs < NUM_OF_CS; effective_cs++) + for (bus_num = 0; bus_num < MAX_BUS_NUM; bus_num++) + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) + rl_values[effective_cs][bus_num][if_id] = 0; + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + training_result[training_stage][if_id] = TEST_SUCCESS; + + /* save current cs enable reg val */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val, + MASK_ALL_BITS)); + /* enable single cs */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, (1 << 3), (1 << 3))); + } + + ddr3_tip_reset_fifo_ptr(dev_num); + + /* + * Phase 1: Load pattern (using ODPG) + * + * enter Read Leveling mode + * only 27 bits are masked + * assuming non multi-CS configuration + * write to CS = 0 for the non multi CS configuration, note + * that the results shall be read back to the required CS !!! + */ + + /* BUS count is 0 shifted 26 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0x3, 0x3)); + CHECK_STATUS(ddr3_tip_configure_odpg + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0, + pattern_table[PATTERN_RL].num_of_phases_tx, 0, + pattern_table[PATTERN_RL].num_of_phases_rx, 0, 0, + effective_cs, STRESS_NONE, DURATION_SINGLE)); + + /* load pattern to ODPG */ + ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, PATTERN_RL, + pattern_table[PATTERN_RL]. + start_addr); + + /* + * Phase 2: ODPG to Read Leveling mode + */ + + /* General Training Opcode register */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_WRITE_READ_MODE_ENABLE_REG, 0, + MASK_ALL_BITS)); + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_CONTROL_REG, + (0x301b01 | effective_cs << 2), 0x3c3fef)); + + /* Object1 opcode register 0 & 1 */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + speed_bin_index = + tm->interface_params[if_id].speed_bin_index; + cl_val = + cas_latency_table[speed_bin_index].cl_val[freq]; + data = (cl_val << 17) | (0x3 << 25); + mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_OBJ1_OPCODE_REG, data, mask)); + } + + /* Set iteration count to max value */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_OPCODE_1_REG, 0xd00, 0xd00)); + + /* + * Phase 2: Mask config + */ + + ddr3_tip_dynamic_read_leveling_seq(dev_num); + + /* + * Phase 3: Read Leveling execution + */ + + /* temporary jira dunit=14751 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_DBG_1_REG, 0, (u32)(1 << 31))); + /* configure phy reset value */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_DBG_3_REG, (0x7f << 24), + (u32)(0xff << 24))); + /* data pup rd reset enable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + SDRAM_CONFIGURATION_REG, 0, (1 << 30))); + /* data pup rd reset disable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + SDRAM_CONFIGURATION_REG, (1 << 30), (1 << 30))); + /* training SW override & training RL mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x1, 0x9)); + /* training enable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_REG, (1 << 24) | (1 << 20), + (1 << 24) | (1 << 20))); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_REG, (u32)(1 << 31), (u32)(1 << 31))); + + /********* trigger training *******************/ + /* Trigger, poll on status and disable ODPG */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_STATUS_REG, 0x1, 0x1)); + + /* check for training done + results pass */ + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x2, 0x2, + ODPG_TRAINING_STATUS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("Training Done Failed\n")); + return MV_FAIL; + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + if_id, + ODPG_TRAINING_TRIGGER_REG, data_read, + 0x4)); + data = data_read[if_id]; + if (data != 0x0) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("Training Result Failed\n")); + } + } + + /*disable ODPG - Back to functional mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_ENABLE_REG, 0x1 << ODPG_DISABLE_OFFS, + (0x1 << ODPG_DISABLE_OFFS))); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x0, 0x1, + ODPG_ENABLE_REG, MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("ODPG disable failed ")); + return MV_FAIL; + } + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS)); + + /* double loop on bus, pup */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* check training done */ + is_any_pup_fail = 0; + for (bus_num = 0; + bus_num < tm->num_of_bus_per_interface; + bus_num++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_num); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, + if_id, (1 << 25), (1 << 25), + mask_results_pup_reg_map[bus_num], + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("\n_r_l: DDR3 poll failed(2) for bus %d", + bus_num)); + is_any_pup_fail = 1; + } else { + /* read result per pup */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + mask_results_pup_reg_map + [bus_num], data_read, + 0xff)); + rl_values[effective_cs][bus_num] + [if_id] = (u8)data_read[if_id]; + } + } + + if (is_any_pup_fail == 1) { + training_result[training_stage][if_id] = + TEST_FAILED; + if (debug_mode == 0) + return MV_FAIL; + } + } + + DEBUG_LEVELING(DEBUG_LEVEL_INFO, ("RL exit read leveling\n")); + + /* + * Phase 3: Exit Read Leveling + */ + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, (1 << 3), (1 << 3))); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_1_REG, (1 << 16), (1 << 16))); + /* set ODPG to functional */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS)); + + /* + * Copy the result from the effective CS search to the + * real Functional CS + */ + /*ddr3_tip_write_cs_result(dev_num, RL_PHY_REG); */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS)); + } + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + /* double loop on bus, pup */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_num = 0; + bus_num < tm->num_of_bus_per_interface; + bus_num++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_num); + /* read result per pup from arry */ + data = rl_values[effective_cs][bus_num][if_id]; + data = (data & 0x1f) | + (((data & 0xe0) >> 5) << 6); + ddr3_tip_bus_write(dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + bus_num, DDR_PHY_DATA, + RL_PHY_REG + + ((effective_cs == + 0) ? 0x0 : 0x4), data); + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* restore cs enable value */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val[if_id], + MASK_ALL_BITS)); + if (odt_config != 0) { + CHECK_STATUS(ddr3_tip_write_additional_odt_setting + (dev_num, if_id)); + } + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (training_result[training_stage][if_id] == TEST_FAILED) + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Legacy Dynamic write leveling + */ +int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num) +{ + u32 c_cs, if_id, cs_mask = 0; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* + * In TRAINIUNG reg (0x15b0) write 0x80000008 | cs_mask: + * Trn_start + * cs_mask = 0x1 <<20 Trn_CS0 - CS0 is included in the DDR3 training + * cs_mask = 0x1 <<21 Trn_CS1 - CS1 is included in the DDR3 training + * cs_mask = 0x1 <<22 Trn_CS2 - CS2 is included in the DDR3 training + * cs_mask = 0x1 <<23 Trn_CS3 - CS3 is included in the DDR3 training + * Trn_auto_seq = write leveling + */ + for (c_cs = 0; c_cs < max_cs; c_cs++) + cs_mask = cs_mask | 1 << (20 + c_cs); + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, 0, + TRAINING_REG, (0x80000008 | cs_mask), + 0xffffffff)); + mdelay(20); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, + (u32)0x80000000, TRAINING_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("polling failed for Old WL result\n")); + return MV_FAIL; + } + } + + return MV_OK; +} + +/* + * Legacy Dynamic read leveling + */ +int ddr3_tip_legacy_dynamic_read_leveling(u32 dev_num) +{ + u32 c_cs, if_id, cs_mask = 0; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* + * In TRAINIUNG reg (0x15b0) write 0x80000040 | cs_mask: + * Trn_start + * cs_mask = 0x1 <<20 Trn_CS0 - CS0 is included in the DDR3 training + * cs_mask = 0x1 <<21 Trn_CS1 - CS1 is included in the DDR3 training + * cs_mask = 0x1 <<22 Trn_CS2 - CS2 is included in the DDR3 training + * cs_mask = 0x1 <<23 Trn_CS3 - CS3 is included in the DDR3 training + * Trn_auto_seq = Read Leveling using training pattern + */ + for (c_cs = 0; c_cs < max_cs; c_cs++) + cs_mask = cs_mask | 1 << (20 + c_cs); + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, 0, TRAINING_REG, + (0x80000040 | cs_mask), 0xffffffff)); + mdelay(100); + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, + (u32)0x80000000, TRAINING_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("polling failed for Old RL result\n")); + return MV_FAIL; + } + } + + return MV_OK; +} + +/* + * Dynamic per bit read leveling + */ +int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 freq) +{ + u32 data, mask; + u32 bus_num, if_id, cl_val, bit_num; + u32 curr_numb, curr_min_delay; + int adll_array[3] = { 0, -0xa, 0x14 }; + u32 phyreg3_arr[MAX_INTERFACE_NUM][MAX_BUS_NUM]; + enum hws_speed_bin speed_bin_index; + int is_any_pup_fail = 0; + int break_loop = 0; + u32 cs_enable_reg_val[MAX_INTERFACE_NUM]; /* save current CS value */ + u32 data_read[MAX_INTERFACE_NUM]; + int per_bit_rl_pup_status[MAX_INTERFACE_NUM][MAX_BUS_NUM]; + u32 data2_write[MAX_INTERFACE_NUM][MAX_BUS_NUM]; + struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); + u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_num = 0; + bus_num <= tm->num_of_bus_per_interface; bus_num++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_num); + per_bit_rl_pup_status[if_id][bus_num] = 0; + data2_write[if_id][bus_num] = 0; + /* read current value of phy register 0x3 */ + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_num, DDR_PHY_DATA, + READ_CENTRALIZATION_PHY_REG, + &phyreg3_arr[if_id][bus_num])); + } + } + + /* NEW RL machine */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + training_result[training_stage][if_id] = TEST_SUCCESS; + + /* save current cs enable reg val */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, &cs_enable_reg_val[if_id], + MASK_ALL_BITS)); + /* enable single cs */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, (1 << 3), (1 << 3))); + } + + ddr3_tip_reset_fifo_ptr(dev_num); + for (curr_numb = 0; curr_numb < 3; curr_numb++) { + /* + * Phase 1: Load pattern (using ODPG) + * + * enter Read Leveling mode + * only 27 bits are masked + * assuming non multi-CS configuration + * write to CS = 0 for the non multi CS configuration, note that + * the results shall be read back to the required CS !!! + */ + + /* BUS count is 0 shifted 26 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0x3, 0x3)); + CHECK_STATUS(ddr3_tip_configure_odpg + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0, + pattern_table[PATTERN_TEST].num_of_phases_tx, 0, + pattern_table[PATTERN_TEST].num_of_phases_rx, 0, + 0, 0, STRESS_NONE, DURATION_SINGLE)); + + /* load pattern to ODPG */ + ddr3_tip_load_pattern_to_odpg(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, PATTERN_TEST, + pattern_table[PATTERN_TEST]. + start_addr); + + /* + * Phase 2: ODPG to Read Leveling mode + */ + + /* General Training Opcode register */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_WRITE_READ_MODE_ENABLE_REG, 0, + MASK_ALL_BITS)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_CONTROL_REG, 0x301b01, 0x3c3fef)); + + /* Object1 opcode register 0 & 1 */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + speed_bin_index = + tm->interface_params[if_id].speed_bin_index; + cl_val = + cas_latency_table[speed_bin_index].cl_val[freq]; + data = (cl_val << 17) | (0x3 << 25); + mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ODPG_OBJ1_OPCODE_REG, data, mask)); + } + + /* Set iteration count to max value */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_OPCODE_1_REG, 0xd00, 0xd00)); + + /* + * Phase 2: Mask config + */ + + ddr3_tip_dynamic_per_bit_read_leveling_seq(dev_num); + + /* + * Phase 3: Read Leveling execution + */ + + /* temporary jira dunit=14751 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_DBG_1_REG, 0, (u32)(1 << 31))); + /* configure phy reset value */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_DBG_3_REG, (0x7f << 24), + (u32)(0xff << 24))); + /* data pup rd reset enable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + SDRAM_CONFIGURATION_REG, 0, (1 << 30))); + /* data pup rd reset disable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + SDRAM_CONFIGURATION_REG, (1 << 30), (1 << 30))); + /* training SW override & training RL mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x1, 0x9)); + /* training enable */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_REG, (1 << 24) | (1 << 20), + (1 << 24) | (1 << 20))); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_REG, (u32)(1 << 31), (u32)(1 << 31))); + + /********* trigger training *******************/ + /* Trigger, poll on status and disable ODPG */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_STATUS_REG, 0x1, 0x1)); + + /*check for training done + results pass */ + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x2, 0x2, + ODPG_TRAINING_STATUS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("Training Done Failed\n")); + return MV_FAIL; + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + if_id, + ODPG_TRAINING_TRIGGER_REG, data_read, + 0x4)); + data = data_read[if_id]; + if (data != 0x0) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("Training Result Failed\n")); + } + } + + /*disable ODPG - Back to functional mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_ENABLE_REG, 0x1 << ODPG_DISABLE_OFFS, + (0x1 << ODPG_DISABLE_OFFS))); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x0, 0x1, + ODPG_ENABLE_REG, MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("ODPG disable failed ")); + return MV_FAIL; + } + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0, MASK_ALL_BITS)); + + /* double loop on bus, pup */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* check training done */ + for (bus_num = 0; + bus_num < tm->num_of_bus_per_interface; + bus_num++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_num); + + if (per_bit_rl_pup_status[if_id][bus_num] + == 0) { + curr_min_delay = 0; + for (bit_num = 0; bit_num < 8; + bit_num++) { + if (ddr3_tip_if_polling + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, (1 << 25), + (1 << 25), + mask_results_dq_reg_map + [bus_num * 8 + bit_num], + MAX_POLLING_ITERATIONS) != + MV_OK) { + DEBUG_LEVELING + (DEBUG_LEVEL_ERROR, + ("\n_r_l: DDR3 poll failed(2) for bus %d bit %d\n", + bus_num, + bit_num)); + } else { + /* read result per pup */ + CHECK_STATUS + (ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + mask_results_dq_reg_map + [bus_num * 8 + + bit_num], + data_read, + MASK_ALL_BITS)); + data = + (data_read + [if_id] & + 0x1f) | + ((data_read + [if_id] & + 0xe0) << 1); + if (curr_min_delay == 0) + curr_min_delay = + data; + else if (data < + curr_min_delay) + curr_min_delay = + data; + if (data > data2_write[if_id][bus_num]) + data2_write + [if_id] + [bus_num] = + data; + } + } + + if (data2_write[if_id][bus_num] <= + (curr_min_delay + + MAX_DQ_READ_LEVELING_DELAY)) { + per_bit_rl_pup_status[if_id] + [bus_num] = 1; + } + } + } + } + + /* check if there is need to search new phyreg3 value */ + if (curr_numb < 2) { + /* if there is DLL that is not checked yet */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_num = 0; + bus_num < tm->num_of_bus_per_interface; + bus_num++) { + VALIDATE_ACTIVE(tm->bus_act_mask, + bus_num); + if (per_bit_rl_pup_status[if_id] + [bus_num] != 1) { + /* go to next ADLL value */ + CHECK_STATUS + (ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + bus_num, DDR_PHY_DATA, + READ_CENTRALIZATION_PHY_REG, + (phyreg3_arr[if_id] + [bus_num] + + adll_array[curr_numb]))); + break_loop = 1; + break; + } + } + if (break_loop) + break; + } + } /* if (curr_numb < 2) */ + if (!break_loop) + break; + } /* for ( curr_numb = 0; curr_numb <3; curr_numb++) */ + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_num = 0; bus_num < tm->num_of_bus_per_interface; + bus_num++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_num); + if (per_bit_rl_pup_status[if_id][bus_num] == 1) + ddr3_tip_bus_write(dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + bus_num, DDR_PHY_DATA, + RL_PHY_REG + + CS_REG_VALUE(effective_cs), + data2_write[if_id] + [bus_num]); + else + is_any_pup_fail = 1; + } + + /* TBD flow does not support multi CS */ + /* + * cs_bitmask = tm->interface_params[if_id]. + * as_bus_params[bus_num].cs_bitmask; + */ + /* divide by 4 is used for retrieving the CS number */ + /* + * TBD BC2 - what is the PHY address for other + * CS ddr3_tip_write_cs_result() ??? + */ + /* + * find what should be written to PHY + * - max delay that is less than threshold + */ + if (is_any_pup_fail == 1) { + training_result[training_stage][if_id] = TEST_FAILED; + if (debug_mode == 0) + return MV_FAIL; + } + } + DEBUG_LEVELING(DEBUG_LEVEL_INFO, ("RL exit read leveling\n")); + + /* + * Phase 3: Exit Read Leveling + */ + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, (1 << 3), (1 << 3))); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_1_REG, (1 << 16), (1 << 16))); + /* set ODPG to functional */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS)); + /* + * Copy the result from the effective CS search to the real + * Functional CS + */ + ddr3_tip_write_cs_result(dev_num, RL_PHY_REG); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_DATA_CONTROL_REG, 0x0, MASK_ALL_BITS)); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* restore cs enable value */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val[if_id], + MASK_ALL_BITS)); + if (odt_config != 0) { + CHECK_STATUS(ddr3_tip_write_additional_odt_setting + (dev_num, if_id)); + } + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (training_result[training_stage][if_id] == TEST_FAILED) + return MV_FAIL; + } + + return MV_OK; +} + +int ddr3_tip_calc_cs_mask(u32 dev_num, u32 if_id, u32 effective_cs, + u32 *cs_mask) +{ + u32 all_bus_cs = 0, same_bus_cs; + u32 bus_cnt; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + *cs_mask = same_bus_cs = CS_BIT_MASK; + + /* + * In some of the devices (such as BC2), the CS is per pup and there + * for mixed mode is valid on like other devices where CS configuration + * is per interface. + * In order to know that, we do 'Or' and 'And' operation between all + * CS (of the pups). + * If they are they are not the same then it's mixed mode so all CS + * should be configured (when configuring the MRS) + */ + for (bus_cnt = 0; bus_cnt < tm->num_of_bus_per_interface; bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + + all_bus_cs |= tm->interface_params[if_id]. + as_bus_params[bus_cnt].cs_bitmask; + same_bus_cs &= tm->interface_params[if_id]. + as_bus_params[bus_cnt].cs_bitmask; + + /* cs enable is active low */ + *cs_mask &= ~tm->interface_params[if_id]. + as_bus_params[bus_cnt].cs_bitmask; + } + + if (all_bus_cs == same_bus_cs) + *cs_mask = (*cs_mask | (~(1 << effective_cs))) & CS_BIT_MASK; + + return MV_OK; +} + +/* + * Dynamic write leveling + */ +int ddr3_tip_dynamic_write_leveling(u32 dev_num) +{ + u32 reg_data = 0, iter, if_id, bus_cnt; + u32 cs_enable_reg_val[MAX_INTERFACE_NUM] = { 0 }; + u32 cs_mask[MAX_INTERFACE_NUM]; + u32 read_data_sample_delay_vals[MAX_INTERFACE_NUM] = { 0 }; + u32 read_data_ready_delay_vals[MAX_INTERFACE_NUM] = { 0 }; + /* 0 for failure */ + u32 res_values[MAX_INTERFACE_NUM * MAX_BUS_NUM] = { 0 }; + u32 test_res = 0; /* 0 - success for all pup */ + u32 data_read[MAX_INTERFACE_NUM]; + u8 wl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM]; + u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); + u32 cs_mask0[MAX_INTERFACE_NUM] = { 0 }; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + training_result[training_stage][if_id] = TEST_SUCCESS; + + /* save Read Data Sample Delay */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + READ_DATA_SAMPLE_DELAY, + read_data_sample_delay_vals, MASK_ALL_BITS)); + /* save Read Data Ready Delay */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + READ_DATA_READY_DELAY, read_data_ready_delay_vals, + MASK_ALL_BITS)); + /* save current cs reg val */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS)); + } + + /* + * Phase 1: DRAM 2 Write Leveling mode + */ + + /*Assert 10 refresh commands to DRAM to all CS */ + for (iter = 0; iter < WL_ITERATION_NUM; iter++) { + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, SDRAM_OPERATION_REG, + (u32)((~(0xf) << 8) | 0x2), 0xf1f)); + } + } + /* check controller back to normal */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f, + SDRAM_OPERATION_REG, MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("WL: DDR3 poll failed(3)")); + } + } + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + /*enable write leveling to all cs - Q off , WL n */ + /* calculate interface cs mask */ + CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask0, MRS1_CMD, + 0x1000, 0x1080)); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* cs enable is active low */ + ddr3_tip_calc_cs_mask(dev_num, if_id, effective_cs, + &cs_mask[if_id]); + } + + /* Enable Output buffer to relevant CS - Q on , WL on */ + CHECK_STATUS(ddr3_tip_write_mrs_cmd + (dev_num, cs_mask, MRS1_CMD, 0x80, 0x1080)); + + /*enable odt for relevant CS */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + 0x1498, (0x3 << (effective_cs * 2)), 0xf)); + + /* + * Phase 2: Set training IP to write leveling mode + */ + + CHECK_STATUS(ddr3_tip_dynamic_write_leveling_seq(dev_num)); + + /* + * Phase 3: Trigger training + */ + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_TRIGGER_REG, 0x1, 0x1)); + + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + /* training done */ + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, + (1 << 1), (1 << 1), ODPG_TRAINING_STATUS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("WL: DDR3 poll (4) failed (Data: 0x%x)\n", + reg_data)); + } +#if !defined(CONFIG_ARMADA_38X) /*Disabled. JIRA #1498 */ + else { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + if_id, + ODPG_TRAINING_TRIGGER_REG, + ®_data, (1 << 2))); + if (reg_data != 0) { + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("WL: WL failed IF %d reg_data=0x%x\n", + if_id, reg_data)); + } + } +#endif + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* training done */ + if (ddr3_tip_if_polling + (dev_num, ACCESS_TYPE_UNICAST, if_id, + (1 << 1), (1 << 1), ODPG_TRAINING_STATUS_REG, + MAX_POLLING_ITERATIONS) != MV_OK) { + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("WL: DDR3 poll (4) failed (Data: 0x%x)\n", + reg_data)); + } else { +#if !defined(CONFIG_ARMADA_38X) /*Disabled. JIRA #1498 */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, + if_id, + ODPG_TRAINING_STATUS_REG, + data_read, (1 << 2))); + reg_data = data_read[if_id]; + if (reg_data != 0) { + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("WL: WL failed IF %d reg_data=0x%x\n", + if_id, reg_data)); + } +#endif + + /* check for training completion per bus */ + for (bus_cnt = 0; + bus_cnt < tm->num_of_bus_per_interface; + bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, + bus_cnt); + /* training status */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + mask_results_pup_reg_map + [bus_cnt], data_read, + (1 << 25))); + reg_data = data_read[if_id]; + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("WL: IF %d BUS %d reg 0x%x\n", + if_id, bus_cnt, reg_data)); + if (reg_data == 0) { + res_values[ + (if_id * + tm->num_of_bus_per_interface) + + bus_cnt] = 1; + } + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + mask_results_pup_reg_map + [bus_cnt], data_read, + 0xff)); + /* + * Save the read value that should be + * write to PHY register + */ + wl_values[effective_cs] + [bus_cnt][if_id] = + (u8)data_read[if_id]; + } + } + } + + /* + * Phase 4: Exit write leveling mode + */ + + /* disable DQs toggling */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + WR_LEVELING_DQS_PATTERN_REG, 0x0, 0x1)); + + /* Update MRS 1 (WL off) */ + CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask0, MRS1_CMD, + 0x1000, 0x1080)); + + /* Update MRS 1 (return to functional mode - Q on , WL off) */ + CHECK_STATUS(ddr3_tip_write_mrs_cmd + (dev_num, cs_mask0, MRS1_CMD, 0x0, 0x1080)); + + /* set phy to normal mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x5, 0x7)); + + /* exit sw override mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x4, 0x7)); + } + + /* + * Phase 5: Load WL values to each PHY + */ + + for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + test_res = 0; + for (bus_cnt = 0; + bus_cnt < tm->num_of_bus_per_interface; + bus_cnt++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_cnt); + /* check if result == pass */ + if (res_values + [(if_id * + tm->num_of_bus_per_interface) + + bus_cnt] == 0) { + /* + * read result control register + * according to pup + */ + reg_data = + wl_values[effective_cs][bus_cnt] + [if_id]; + /* + * Write into write leveling register + * ([4:0] ADLL, [8:6] Phase, [15:10] + * (centralization) ADLL + 0x10) + */ + reg_data = + (reg_data & 0x1f) | + (((reg_data & 0xe0) >> 5) << 6) | + (((reg_data & 0x1f) + + phy_reg1_val) << 10); + ddr3_tip_bus_write( + dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, + bus_cnt, + DDR_PHY_DATA, + WL_PHY_REG + + effective_cs * + CS_REGISTER_ADDR_OFFSET, + reg_data); + } else { + test_res = 1; + /* + * read result control register + * according to pup + */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + mask_results_pup_reg_map + [bus_cnt], data_read, + 0xff)); + reg_data = data_read[if_id]; + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("WL: IF %d BUS %d failed, reg 0x%x\n", + if_id, bus_cnt, reg_data)); + } + } + + if (test_res != 0) { + training_result[training_stage][if_id] = + TEST_FAILED; + } + } + } + /* Set to 0 after each loop to avoid illegal value may be used */ + effective_cs = 0; + + /* + * Copy the result from the effective CS search to the real + * Functional CS + */ + /* ddr3_tip_write_cs_result(dev_num, WL_PHY_REG); */ + /* restore saved values */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* restore Read Data Sample Delay */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + READ_DATA_SAMPLE_DELAY, + read_data_sample_delay_vals[if_id], + MASK_ALL_BITS)); + + /* restore Read Data Ready Delay */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + READ_DATA_READY_DELAY, + read_data_ready_delay_vals[if_id], + MASK_ALL_BITS)); + + /* enable multi cs */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val[if_id], + MASK_ALL_BITS)); + } + + /* Disable modt0 for CS0 training - need to adjust for multy CS */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, 0x1498, + 0x0, 0xf)); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (training_result[training_stage][if_id] == TEST_FAILED) + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Dynamic write leveling supplementary + */ +int ddr3_tip_dynamic_write_leveling_supp(u32 dev_num) +{ + int adll_offset; + u32 if_id, bus_id, data, data_tmp; + int is_if_fail = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + is_if_fail = 0; + + for (bus_id = 0; bus_id < GET_TOPOLOGY_NUM_OF_BUSES(); + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + wr_supp_res[if_id][bus_id].is_pup_fail = 1; + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + effective_cs * CS_REGISTER_ADDR_OFFSET, + &data)); + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("WL Supp: adll_offset=0 data delay = %d\n", + data)); + if (ddr3_tip_wl_supp_align_phase_shift + (dev_num, if_id, bus_id, 0, 0) == MV_OK) { + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("WL Supp: IF %d bus_id %d adll_offset=0 Success !\n", + if_id, bus_id)); + continue; + } + + /* change adll */ + adll_offset = 5; + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, bus_id, DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + effective_cs * CS_REGISTER_ADDR_OFFSET, + data + adll_offset)); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + effective_cs * CS_REGISTER_ADDR_OFFSET, + &data_tmp)); + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("WL Supp: adll_offset= %d data delay = %d\n", + adll_offset, data_tmp)); + + if (ddr3_tip_wl_supp_align_phase_shift + (dev_num, if_id, bus_id, adll_offset, 0) == MV_OK) { + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("WL Supp: IF %d bus_id %d adll_offset= %d Success !\n", + if_id, bus_id, adll_offset)); + continue; + } + + /* change adll */ + adll_offset = -5; + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, bus_id, DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + effective_cs * CS_REGISTER_ADDR_OFFSET, + data + adll_offset)); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, + WRITE_CENTRALIZATION_PHY_REG + + effective_cs * CS_REGISTER_ADDR_OFFSET, + &data_tmp)); + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("WL Supp: adll_offset= %d data delay = %d\n", + adll_offset, data_tmp)); + if (ddr3_tip_wl_supp_align_phase_shift + (dev_num, if_id, bus_id, adll_offset, 0) == MV_OK) { + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("WL Supp: IF %d bus_id %d adll_offset= %d Success !\n", + if_id, bus_id, adll_offset)); + continue; + } else { + DEBUG_LEVELING( + DEBUG_LEVEL_ERROR, + ("WL Supp: IF %d bus_id %d Failed !\n", + if_id, bus_id)); + is_if_fail = 1; + } + } + DEBUG_LEVELING(DEBUG_LEVEL_TRACE, + ("WL Supp: IF %d bus_id %d is_pup_fail %d\n", + if_id, bus_id, is_if_fail)); + + if (is_if_fail == 1) { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("WL Supp: IF %d failed\n", if_id)); + training_result[training_stage][if_id] = TEST_FAILED; + } else { + training_result[training_stage][if_id] = TEST_SUCCESS; + } + } + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (training_result[training_stage][if_id] == TEST_FAILED) + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Phase Shift + */ +static int ddr3_tip_wl_supp_align_phase_shift(u32 dev_num, u32 if_id, + u32 bus_id, u32 offset, + u32 bus_id_delta) +{ + wr_supp_res[if_id][bus_id].stage = PHASE_SHIFT; + if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id, + 0, bus_id_delta) == MV_OK) { + wr_supp_res[if_id][bus_id].is_pup_fail = 0; + return MV_OK; + } else if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id, + ONE_CLOCK_ERROR_SHIFT, + bus_id_delta) == MV_OK) { + /* 1 clock error */ + wr_supp_res[if_id][bus_id].stage = CLOCK_SHIFT; + DEBUG_LEVELING(DEBUG_LEVEL_TRACE, + ("Supp: 1 error clock for if %d pup %d with ofsset %d success\n", + if_id, bus_id, offset)); + ddr3_tip_wl_supp_one_clk_err_shift(dev_num, if_id, bus_id, 0); + wr_supp_res[if_id][bus_id].is_pup_fail = 0; + return MV_OK; + } else if (ddr3_tip_xsb_compare_test(dev_num, if_id, bus_id, + ALIGN_ERROR_SHIFT, + bus_id_delta) == MV_OK) { + /* align error */ + DEBUG_LEVELING(DEBUG_LEVEL_TRACE, + ("Supp: align error for if %d pup %d with ofsset %d success\n", + if_id, bus_id, offset)); + wr_supp_res[if_id][bus_id].stage = ALIGN_SHIFT; + ddr3_tip_wl_supp_align_err_shift(dev_num, if_id, bus_id, 0); + wr_supp_res[if_id][bus_id].is_pup_fail = 0; + return MV_OK; + } else { + wr_supp_res[if_id][bus_id].is_pup_fail = 1; + return MV_FAIL; + } +} + +/* + * Compare Test + */ +static int ddr3_tip_xsb_compare_test(u32 dev_num, u32 if_id, u32 bus_id, + u32 edge_offset, u32 bus_id_delta) +{ + u32 num_of_succ_byte_compare, word_in_pattern, abs_offset; + u32 word_offset, i; + u32 read_pattern[TEST_PATTERN_LENGTH * 2]; + struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); + u32 pattern_test_pattern_table[8]; + + for (i = 0; i < 8; i++) { + pattern_test_pattern_table[i] = + pattern_table_get_word(dev_num, PATTERN_TEST, (u8)i); + } + + /* extern write, than read and compare */ + CHECK_STATUS(ddr3_tip_ext_write + (dev_num, if_id, + (pattern_table[PATTERN_TEST].start_addr + + ((SDRAM_CS_SIZE + 1) * effective_cs)), 1, + pattern_test_pattern_table)); + + CHECK_STATUS(ddr3_tip_reset_fifo_ptr(dev_num)); + + CHECK_STATUS(ddr3_tip_ext_read + (dev_num, if_id, + (pattern_table[PATTERN_TEST].start_addr + + ((SDRAM_CS_SIZE + 1) * effective_cs)), 1, read_pattern)); + + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("XSB-compt: IF %d bus_id %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + if_id, bus_id, read_pattern[0], read_pattern[1], + read_pattern[2], read_pattern[3], read_pattern[4], + read_pattern[5], read_pattern[6], read_pattern[7])); + + /* compare byte per pup */ + num_of_succ_byte_compare = 0; + for (word_in_pattern = start_xsb_offset; + word_in_pattern < (TEST_PATTERN_LENGTH * 2); word_in_pattern++) { + word_offset = word_in_pattern + edge_offset; + if ((word_offset > (TEST_PATTERN_LENGTH * 2 - 1)) || + (word_offset < 0)) + continue; + + if ((read_pattern[word_in_pattern] & pup_mask_table[bus_id]) == + (pattern_test_pattern_table[word_offset] & + pup_mask_table[bus_id])) + num_of_succ_byte_compare++; + } + + abs_offset = (edge_offset > 0) ? edge_offset : -edge_offset; + if (num_of_succ_byte_compare == ((TEST_PATTERN_LENGTH * 2) - + abs_offset - start_xsb_offset)) { + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Success\n", + if_id, bus_id, num_of_succ_byte_compare)); + return MV_OK; + } else { + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Fail !\n", + if_id, bus_id, num_of_succ_byte_compare)); + + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("XSB-compt: expected 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pattern_test_pattern_table[0], + pattern_test_pattern_table[1], + pattern_test_pattern_table[2], + pattern_test_pattern_table[3], + pattern_test_pattern_table[4], + pattern_test_pattern_table[5], + pattern_test_pattern_table[6], + pattern_test_pattern_table[7])); + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("XSB-compt: recieved 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + read_pattern[0], read_pattern[1], + read_pattern[2], read_pattern[3], + read_pattern[4], read_pattern[5], + read_pattern[6], read_pattern[7])); + + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("XSB-compt: IF %d bus_id %d num_of_succ_byte_compare %d - Fail !\n", + if_id, bus_id, num_of_succ_byte_compare)); + + return MV_FAIL; + } +} + +/* + * Clock error shift - function moves the write leveling delay 1cc forward + */ +static int ddr3_tip_wl_supp_one_clk_err_shift(u32 dev_num, u32 if_id, + u32 bus_id, u32 bus_id_delta) +{ + int phase, adll; + u32 data; + DEBUG_LEVELING(DEBUG_LEVEL_TRACE, ("One_clk_err_shift\n")); + + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, ACCESS_TYPE_UNICAST, bus_id, + DDR_PHY_DATA, WL_PHY_REG, &data)); + phase = ((data >> 6) & 0x7); + adll = data & 0x1f; + DEBUG_LEVELING(DEBUG_LEVEL_TRACE, + ("One_clk_err_shift: IF %d bus_id %d phase %d adll %d\n", + if_id, bus_id, phase, adll)); + + if ((phase == 0) || (phase == 1)) { + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, bus_id, + DDR_PHY_DATA, 0, (phase + 2), 0x1f)); + } else if (phase == 2) { + if (adll < 6) { + data = (3 << 6) + (0x1f); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + bus_id, DDR_PHY_DATA, 0, data, + (0x7 << 6 | 0x1f))); + data = 0x2f; + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + bus_id, DDR_PHY_DATA, 1, data, 0x3f)); + } + } else { + /* phase 3 */ + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Align error shift + */ +static int ddr3_tip_wl_supp_align_err_shift(u32 dev_num, u32 if_id, + u32 bus_id, u32 bus_id_delta) +{ + int phase, adll; + u32 data; + + /* Shift WL result 1 phase back */ + CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id, ACCESS_TYPE_UNICAST, + bus_id, DDR_PHY_DATA, WL_PHY_REG, + &data)); + phase = ((data >> 6) & 0x7); + adll = data & 0x1f; + DEBUG_LEVELING( + DEBUG_LEVEL_TRACE, + ("Wl_supp_align_err_shift: IF %d bus_id %d phase %d adll %d\n", + if_id, bus_id, phase, adll)); + + if (phase < 2) { + if (adll > 0x1a) { + if (phase == 0) + return MV_FAIL; + + if (phase == 1) { + data = 0; + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, bus_id, DDR_PHY_DATA, + 0, data, (0x7 << 6 | 0x1f))); + data = 0xf; + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, bus_id, DDR_PHY_DATA, + 1, data, 0x1f)); + return MV_OK; + } + } else { + return MV_FAIL; + } + } else if ((phase == 2) || (phase == 3)) { + phase = phase - 2; + data = (phase << 6) + (adll & 0x1f); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, bus_id, + DDR_PHY_DATA, 0, data, (0x7 << 6 | 0x1f))); + return MV_OK; + } else { + DEBUG_LEVELING(DEBUG_LEVEL_ERROR, + ("Wl_supp_align_err_shift: unexpected phase\n")); + + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Dynamic write leveling sequence + */ +static int ddr3_tip_dynamic_write_leveling_seq(u32 dev_num) +{ + u32 bus_id, dq_id; + u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); + u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_SW_2_REG, 0x1, 0x5)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_WRITE_LEVELING_REG, 0x50, 0xff)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_WRITE_LEVELING_REG, 0x5c, 0xff)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_TRAINING_CONTROL_REG, 0x381b82, 0x3c3faf)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_OBJ1_OPCODE_REG, (0x3 << 25), (0x3ffff << 9))); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_OBJ1_ITER_CNT_REG, 0x80, 0xffff)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_WRITE_LEVELING_DONE_CNTR_REG, 0x14, 0xff)); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + TRAINING_WRITE_LEVELING_REG, 0xff5c, 0xffff)); + + /* mask PBS */ + for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_dq_reg_map[dq_id], 0x1 << 24, + 0x1 << 24)); + } + + /* Mask all results */ + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_pup_reg_map[bus_id], 0x1 << 24, + 0x1 << 24)); + } + + /* Unmask only wanted */ + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_pup_reg_map[bus_id], 0, 0x1 << 24)); + } + + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + WR_LEVELING_DQS_PATTERN_REG, 0x1, 0x1)); + + return MV_OK; +} + +/* + * Dynamic read leveling sequence + */ +static int ddr3_tip_dynamic_read_leveling_seq(u32 dev_num) +{ + u32 bus_id, dq_id; + u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); + u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* mask PBS */ + for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_dq_reg_map[dq_id], 0x1 << 24, + 0x1 << 24)); + } + + /* Mask all results */ + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_pup_reg_map[bus_id], 0x1 << 24, + 0x1 << 24)); + } + + /* Unmask only wanted */ + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_pup_reg_map[bus_id], 0, 0x1 << 24)); + } + + return MV_OK; +} + +/* + * Dynamic read leveling sequence + */ +static int ddr3_tip_dynamic_per_bit_read_leveling_seq(u32 dev_num) +{ + u32 bus_id, dq_id; + u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); + u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* mask PBS */ + for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_dq_reg_map[dq_id], 0x1 << 24, + 0x1 << 24)); + } + + /* Mask all results */ + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; bus_id++) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_pup_reg_map[bus_id], 0x1 << 24, + 0x1 << 24)); + } + + /* Unmask only wanted */ + for (dq_id = 0; dq_id < MAX_DQ_NUM; dq_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, dq_id / 8); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + mask_results_dq_reg_map[dq_id], 0x0 << 24, + 0x1 << 24)); + } + + return MV_OK; +} + +/* + * Print write leveling supplementary results + */ +int ddr3_tip_print_wl_supp_result(u32 dev_num) +{ + u32 bus_id = 0, if_id = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + DEBUG_LEVELING(DEBUG_LEVEL_INFO, + ("I/F0 PUP0 Result[0 - success, 1-fail] ...\n")); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + DEBUG_LEVELING(DEBUG_LEVEL_INFO, + ("%d ,", wr_supp_res[if_id] + [bus_id].is_pup_fail)); + } + } + DEBUG_LEVELING( + DEBUG_LEVEL_INFO, + ("I/F0 PUP0 Stage[0-phase_shift, 1-clock_shift, 2-align_shift] ...\n")); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_id = 0; bus_id < tm->num_of_bus_per_interface; + bus_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_id); + DEBUG_LEVELING(DEBUG_LEVEL_INFO, + ("%d ,", wr_supp_res[if_id] + [bus_id].stage)); + } + } + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.h b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h new file mode 100644 index 0000000..f2b4177 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR3_TRAINING_LEVELING_H_ +#define _DDR3_TRAINING_LEVELING_H_ + +#define MAX_DQ_READ_LEVELING_DELAY 15 + +int ddr3_tip_print_wl_supp_result(u32 dev_num); +int ddr3_tip_calc_cs_mask(u32 dev_num, u32 if_id, u32 effective_cs, + u32 *cs_mask); +u32 hws_ddr3_tip_max_cs_get(void); + +#endif /* _DDR3_TRAINING_LEVELING_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_pbs.c b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c new file mode 100644 index 0000000..2b4a58f --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c @@ -0,0 +1,995 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +#define TYPICAL_PBS_VALUE 12 + +u32 nominal_adll[MAX_INTERFACE_NUM * MAX_BUS_NUM]; +enum hws_training_ip_stat train_status[MAX_INTERFACE_NUM]; +u8 result_mat[MAX_INTERFACE_NUM][MAX_BUS_NUM][BUS_WIDTH_IN_BITS]; +u8 result_mat_rx_dqs[MAX_INTERFACE_NUM][MAX_BUS_NUM][MAX_CS_NUM]; +/* 4-EEWA, 3-EWA, 2-SWA, 1-Fail, 0-Pass */ +u8 result_all_bit[MAX_BUS_NUM * BUS_WIDTH_IN_BITS * MAX_INTERFACE_NUM]; +u8 max_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 min_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 max_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 min_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u32 pbsdelay_per_pup[NUM_OF_PBS_MODES][MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 adll_shift_lock[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +u8 adll_shift_val[MAX_INTERFACE_NUM][MAX_BUS_NUM]; +enum hws_pattern pbs_pattern = PATTERN_VREF; +static u8 pup_state[MAX_INTERFACE_NUM][MAX_BUS_NUM]; + +/* + * Name: ddr3_tip_pbs + * Desc: PBS + * Args: TBD + * Notes: + * Returns: OK if success, other error code if fail. + */ +int ddr3_tip_pbs(u32 dev_num, enum pbs_dir pbs_mode) +{ + u32 res0[MAX_INTERFACE_NUM]; + int adll_tap = MEGA / freq_val[medium_freq] / 64; + int pad_num = 0; + enum hws_search_dir search_dir = + (pbs_mode == PBS_RX_MODE) ? HWS_HIGH2LOW : HWS_LOW2HIGH; + enum hws_dir dir = (pbs_mode == PBS_RX_MODE) ? OPER_READ : OPER_WRITE; + int iterations = (pbs_mode == PBS_RX_MODE) ? 31 : 63; + u32 res_valid_mask = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f; + int init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations; + enum hws_edge_compare search_edge = EDGE_FP; + u32 pup = 0, bit = 0, if_id = 0, all_lock = 0, cs_num = 0; + int reg_addr = 0; + u32 validation_val = 0; + u32 cs_enable_reg_val[MAX_INTERFACE_NUM]; + u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg(); + u8 temp = 0; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* save current cs enable reg val */ + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + /* save current cs enable reg val */ + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val, MASK_ALL_BITS)); + + /* enable single cs */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, (1 << 3), (1 << 3))); + } + + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (READ_CENTRALIZATION_PHY_REG + + (effective_cs * CS_REGISTER_ADDR_OFFSET)) : + (WRITE_CENTRALIZATION_PHY_REG + + (effective_cs * CS_REGISTER_ADDR_OFFSET)); + read_adll_value(nominal_adll, reg_addr, MASK_ALL_BITS); + + /* stage 1 shift ADLL */ + ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, RESULT_PER_BIT, + HWS_CONTROL_ELEMENT_ADLL, search_dir, dir, + tm->if_act_mask, init_val, iterations, + pbs_pattern, search_edge, CS_SINGLE, cs_num, + train_status); + validation_val = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0; + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + min_adll_per_pup[if_id][pup] = + (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f; + pup_state[if_id][pup] = 0x3; + adll_shift_lock[if_id][pup] = 1; + max_adll_per_pup[if_id][pup] = 0x0; + } + } + + /* EBA */ + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + mask_results_dq_reg_map[ + bit + pup * BUS_WIDTH_IN_BITS], + res0, MASK_ALL_BITS)); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n", + if_id, bit, pup, + res0[if_id])); + if (pup_state[if_id][pup] != 3) + continue; + /* if not EBA state than move to next pup */ + + if ((res0[if_id] & 0x2000000) == 0) { + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("-- Fail Training IP\n")); + /* training machine failed */ + pup_state[if_id][pup] = 1; + adll_shift_lock[if_id][pup] = 0; + continue; + } + + else if ((res0[if_id] & res_valid_mask) == + validation_val) { + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("-- FAIL EBA %d %d %d %d\n", + if_id, bit, pup, + res0[if_id])); + pup_state[if_id][pup] = 4; + /* this pup move to EEBA */ + adll_shift_lock[if_id][pup] = 0; + continue; + } else { + /* + * The search ended in Pass we need + * Fail + */ + res0[if_id] = + (pbs_mode == PBS_RX_MODE) ? + ((res0[if_id] & + res_valid_mask) + 1) : + ((res0[if_id] & + res_valid_mask) - 1); + max_adll_per_pup[if_id][pup] = + (max_adll_per_pup[if_id][pup] < + res0[if_id]) ? + (u8)res0[if_id] : + max_adll_per_pup[if_id][pup]; + min_adll_per_pup[if_id][pup] = + (res0[if_id] > + min_adll_per_pup[if_id][pup]) ? + min_adll_per_pup[if_id][pup] : + (u8) + res0[if_id]; + /* + * vs the Rx we are searching for the + * smallest value of DQ shift so all + * Bus would fail + */ + adll_shift_val[if_id][pup] = + (pbs_mode == PBS_RX_MODE) ? + max_adll_per_pup[if_id][pup] : + min_adll_per_pup[if_id][pup]; + } + } + } + } + + /* EEBA */ + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + if (pup_state[if_id][pup] != 4) + continue; + /* + * if pup state different from EEBA than move to + * next pup + */ + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x54 + effective_cs * 0x10) : + (0x14 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA, + reg_addr, 0x1f)); + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x55 + effective_cs * 0x10) : + (0x15 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA, + reg_addr, 0x1f)); + /* initialize the Edge2 Max. */ + adll_shift_val[if_id][pup] = 0; + min_adll_per_pup[if_id][pup] = + (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f; + max_adll_per_pup[if_id][pup] = 0x0; + + ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, RESULT_PER_BIT, + HWS_CONTROL_ELEMENT_ADLL, + search_dir, dir, + tm->if_act_mask, init_val, + iterations, pbs_pattern, + search_edge, CS_SINGLE, cs_num, + train_status); + DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO, + ("ADLL shift results:\n")); + + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + mask_results_dq_reg_map[ + bit + pup * + BUS_WIDTH_IN_BITS], + res0, MASK_ALL_BITS)); + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n", + if_id, bit, pup, + res0[if_id])); + + if ((res0[if_id] & 0x2000000) == 0) { + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + (" -- EEBA Fail\n")); + bit = BUS_WIDTH_IN_BITS; + /* exit bit loop */ + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("-- EEBA Fail Training IP\n")); + /* + * training machine failed but pass + * before in the EBA so maybe the DQS + * shift change env. + */ + pup_state[if_id][pup] = 2; + adll_shift_lock[if_id][pup] = 0; + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x54 + effective_cs * 0x10) : + (0x14 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + 0x0)); + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x55 + effective_cs * 0x10) : + (0x15 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + 0x0)); + continue; + } else if ((res0[if_id] & res_valid_mask) == + validation_val) { + /* exit bit loop */ + bit = BUS_WIDTH_IN_BITS; + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("-- FAIL EEBA\n")); + /* this pup move to SBA */ + pup_state[if_id][pup] = 2; + adll_shift_lock[if_id][pup] = 0; + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x54 + effective_cs * 0x10) : + (0x14 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + 0x0)); + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x55 + effective_cs * 0x10) : + (0x15 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, + ACCESS_TYPE_UNICAST, + if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + 0x0)); + continue; + } else { + adll_shift_lock[if_id][pup] = 1; + /* + * The search ended in Pass we need + * Fail + */ + res0[if_id] = + (pbs_mode == PBS_RX_MODE) ? + ((res0[if_id] & + res_valid_mask) + 1) : + ((res0[if_id] & + res_valid_mask) - 1); + max_adll_per_pup[if_id][pup] = + (max_adll_per_pup[if_id][pup] < + res0[if_id]) ? + (u8)res0[if_id] : + max_adll_per_pup[if_id][pup]; + min_adll_per_pup[if_id][pup] = + (res0[if_id] > + min_adll_per_pup[if_id][pup]) ? + min_adll_per_pup[if_id][pup] : + (u8)res0[if_id]; + /* + * vs the Rx we are searching for the + * smallest value of DQ shift so all Bus + * would fail + */ + adll_shift_val[if_id][pup] = + (pbs_mode == PBS_RX_MODE) ? + max_adll_per_pup[if_id][pup] : + min_adll_per_pup[if_id][pup]; + } + } + } + } + + /* Print Stage result */ + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("FP I/F %d, ADLL Shift for EBA: pup[%d] Lock status = %d Lock Val = %d,%d\n", + if_id, pup, + adll_shift_lock[if_id][pup], + max_adll_per_pup[if_id][pup], + min_adll_per_pup[if_id][pup])); + } + } + DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO, + ("Update ADLL Shift of all pups:\n")); + + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (adll_shift_lock[if_id][pup] != 1) + continue; + /* if pup not locked continue to next pup */ + + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x3 + effective_cs * 4) : + (0x1 + effective_cs * 4); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA, + reg_addr, adll_shift_val[if_id][pup])); + DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE, + ("FP I/F %d, Pup[%d] = %d\n", if_id, + pup, adll_shift_val[if_id][pup])); + } + } + + /* PBS EEBA&EBA */ + /* Start the Per Bit Skew search */ + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + max_pbs_per_pup[if_id][pup] = 0x0; + min_pbs_per_pup[if_id][pup] = 0x1f; + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + /* reset result for PBS */ + result_all_bit[bit + pup * BUS_WIDTH_IN_BITS + + if_id * MAX_BUS_NUM * + BUS_WIDTH_IN_BITS] = 0; + } + } + } + + iterations = 31; + search_dir = HWS_LOW2HIGH; + /* !!!!! ran sh (search_dir == HWS_LOW2HIGH)?0:iterations; */ + init_val = 0; + + ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + RESULT_PER_BIT, HWS_CONTROL_ELEMENT_DQ_SKEW, + search_dir, dir, tm->if_act_mask, init_val, + iterations, pbs_pattern, search_edge, + CS_SINGLE, cs_num, train_status); + + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (adll_shift_lock[if_id][pup] != 1) { + /* if pup not lock continue to next pup */ + continue; + } + + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + mask_results_dq_reg_map[ + bit + + pup * BUS_WIDTH_IN_BITS], + res0, MASK_ALL_BITS)); + DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO, + ("Per Bit Skew search, FP I/F %d, bit:%d, pup:%d res0 0x%x\n", + if_id, bit, pup, + res0[if_id])); + if ((res0[if_id] & 0x2000000) == 0) { + DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO, + ("--EBA PBS Fail - Training IP machine\n")); + /* exit the bit loop */ + bit = BUS_WIDTH_IN_BITS; + /* + * ADLL is no long in lock need new + * search + */ + adll_shift_lock[if_id][pup] = 0; + /* Move to SBA */ + pup_state[if_id][pup] = 2; + max_pbs_per_pup[if_id][pup] = 0x0; + min_pbs_per_pup[if_id][pup] = 0x1f; + continue; + } else { + temp = (u8)(res0[if_id] & + res_valid_mask); + max_pbs_per_pup[if_id][pup] = + (temp > + max_pbs_per_pup[if_id][pup]) ? + temp : + max_pbs_per_pup[if_id][pup]; + min_pbs_per_pup[if_id][pup] = + (temp < + min_pbs_per_pup[if_id][pup]) ? + temp : + min_pbs_per_pup[if_id][pup]; + result_all_bit[bit + + pup * BUS_WIDTH_IN_BITS + + if_id * MAX_BUS_NUM * + BUS_WIDTH_IN_BITS] = + temp; + } + } + } + } + + /* Check all Pup lock */ + all_lock = 1; + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + all_lock = all_lock * adll_shift_lock[if_id][pup]; + } + } + + /* Only if not all Pups Lock */ + if (all_lock == 0) { + DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO, + ("##########ADLL shift for SBA###########\n")); + + /* ADLL shift for SBA */ + search_dir = (pbs_mode == PBS_RX_MODE) ? HWS_LOW2HIGH : + HWS_HIGH2LOW; + init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations; + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + if (adll_shift_lock[if_id][pup] == 1) { + /*if pup lock continue to next pup */ + continue; + } + /*init the var altogth init before */ + adll_shift_lock[if_id][pup] = 0; + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x54 + effective_cs * 0x10) : + (0x14 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, 0)); + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x55 + effective_cs * 0x10) : + (0x15 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, 0)); + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x5f + effective_cs * 0x10) : + (0x1f + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, 0)); + /* initilaze the Edge2 Max. */ + adll_shift_val[if_id][pup] = 0; + min_adll_per_pup[if_id][pup] = 0x1f; + max_adll_per_pup[if_id][pup] = 0x0; + + ddr3_tip_ip_training(dev_num, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + RESULT_PER_BIT, + HWS_CONTROL_ELEMENT_ADLL, + search_dir, dir, + tm->if_act_mask, + init_val, iterations, + pbs_pattern, + search_edge, CS_SINGLE, + cs_num, train_status); + + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + mask_results_dq_reg_map + [bit + + pup * + BUS_WIDTH_IN_BITS], + res0, MASK_ALL_BITS)); + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_INFO, + ("FP I/F %d, bit:%d, pup:%d res0 0x%x\n", + if_id, bit, pup, res0[if_id])); + if ((res0[if_id] & 0x2000000) == 0) { + /* exit the bit loop */ + bit = BUS_WIDTH_IN_BITS; + /* Fail SBA --> Fail PBS */ + pup_state[if_id][pup] = 1; + DEBUG_PBS_ENGINE + (DEBUG_LEVEL_INFO, + (" SBA Fail\n")); + continue; + } else { + /* + * - increment to get all + * 8 bit lock. + */ + adll_shift_lock[if_id][pup]++; + /* + * The search ended in Pass + * we need Fail + */ + res0[if_id] = + (pbs_mode == PBS_RX_MODE) ? + ((res0[if_id] & res_valid_mask) + 1) : + ((res0[if_id] & res_valid_mask) - 1); + max_adll_per_pup[if_id][pup] = + (max_adll_per_pup[if_id] + [pup] < res0[if_id]) ? + (u8)res0[if_id] : + max_adll_per_pup[if_id][pup]; + min_adll_per_pup[if_id][pup] = + (res0[if_id] > + min_adll_per_pup[if_id] + [pup]) ? + min_adll_per_pup[if_id][pup] : + (u8)res0[if_id]; + /* + * vs the Rx we are searching for + * the smallest value of DQ shift + * so all Bus would fail + */ + adll_shift_val[if_id][pup] = + (pbs_mode == PBS_RX_MODE) ? + max_adll_per_pup[if_id][pup] : + min_adll_per_pup[if_id][pup]; + } + } + /* 1 is lock */ + adll_shift_lock[if_id][pup] = + (adll_shift_lock[if_id][pup] == 8) ? + 1 : 0; + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x3 + effective_cs * 4) : + (0x1 + effective_cs * 4); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + adll_shift_val[if_id][pup])); + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_INFO, + ("adll_shift_lock[%x][%x] = %x\n", + if_id, pup, + adll_shift_lock[if_id][pup])); + } + } + + /* End ADLL Shift for SBA */ + /* Start the Per Bit Skew search */ + /* The ADLL shift finished with a Pass */ + search_edge = (pbs_mode == PBS_RX_MODE) ? EDGE_PF : EDGE_FP; + search_dir = (pbs_mode == PBS_RX_MODE) ? + HWS_LOW2HIGH : HWS_HIGH2LOW; + iterations = 0x1f; + /* - The initial value is different in Rx and Tx mode */ + init_val = (pbs_mode == PBS_RX_MODE) ? 0 : iterations; + + ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, RESULT_PER_BIT, + HWS_CONTROL_ELEMENT_DQ_SKEW, + search_dir, dir, tm->if_act_mask, + init_val, iterations, pbs_pattern, + search_edge, CS_SINGLE, cs_num, + train_status); + + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + CHECK_STATUS(ddr3_tip_if_read + (dev_num, + ACCESS_TYPE_MULTICAST, + PARAM_NOT_CARE, + mask_results_dq_reg_map + [bit + + pup * + BUS_WIDTH_IN_BITS], + res0, MASK_ALL_BITS)); + if (pup_state[if_id][pup] != 2) { + /* + * if pup is not SBA continue + * to next pup + */ + bit = BUS_WIDTH_IN_BITS; + continue; + } + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_INFO, + ("Per Bit Skew search, PF I/F %d, bit:%d, pup:%d res0 0x%x\n", + if_id, bit, pup, res0[if_id])); + if ((res0[if_id] & 0x2000000) == 0) { + DEBUG_PBS_ENGINE + (DEBUG_LEVEL_INFO, + ("SBA Fail\n")); + + max_pbs_per_pup[if_id][pup] = + 0x1f; + result_all_bit[ + bit + pup * + BUS_WIDTH_IN_BITS + + if_id * MAX_BUS_NUM * + BUS_WIDTH_IN_BITS] = + 0x1f; + } else { + temp = (u8)(res0[if_id] & + res_valid_mask); + max_pbs_per_pup[if_id][pup] = + (temp > + max_pbs_per_pup[if_id] + [pup]) ? temp : + max_pbs_per_pup + [if_id][pup]; + min_pbs_per_pup[if_id][pup] = + (temp < + min_pbs_per_pup[if_id] + [pup]) ? temp : + min_pbs_per_pup + [if_id][pup]; + result_all_bit[ + bit + pup * + BUS_WIDTH_IN_BITS + + if_id * MAX_BUS_NUM * + BUS_WIDTH_IN_BITS] = + temp; + adll_shift_lock[if_id][pup] = 1; + } + } + } + } + + /* Check all Pup state */ + all_lock = 1; + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + /* + * DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO, + * ("pup_state[%d][%d] = %d\n",if_id,pup,pup_state + * [if_id][pup])); + */ + } + } + + /* END OF SBA */ + /* Norm */ + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; + if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* if pup not lock continue to next pup */ + if (adll_shift_lock[if_id][pup] != 1) { + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_ERROR, + ("PBS failed for IF #%d\n", + if_id)); + training_result[training_stage][if_id] + = TEST_FAILED; + + result_mat[if_id][pup][bit] = 0; + max_pbs_per_pup[if_id][pup] = 0; + min_pbs_per_pup[if_id][pup] = 0; + } else { + training_result[ + training_stage][if_id] = + (training_result[training_stage] + [if_id] == TEST_FAILED) ? + TEST_FAILED : TEST_SUCCESS; + result_mat[if_id][pup][bit] = + result_all_bit[ + bit + pup * + BUS_WIDTH_IN_BITS + + if_id * MAX_BUS_NUM * + BUS_WIDTH_IN_BITS] - + min_pbs_per_pup[if_id][pup]; + } + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_INFO, + ("The abs min_pbs[%d][%d] = %d\n", + if_id, pup, + min_pbs_per_pup[if_id][pup])); + } + } + } + + /* Clean all results */ + ddr3_tip_clean_pbs_result(dev_num, pbs_mode); + + /* DQ PBS register update with the final result */ + for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup = 0; pup < tm->num_of_bus_per_interface; pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_INFO, + ("Final Results: if_id %d, pup %d, Pup State: %d\n", + if_id, pup, pup_state[if_id][pup])); + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + if (dq_map_table == NULL) { + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_ERROR, + ("dq_map_table not initialized\n")); + return MV_FAIL; + } + pad_num = dq_map_table[ + bit + pup * BUS_WIDTH_IN_BITS + + if_id * BUS_WIDTH_IN_BITS * + tm->num_of_bus_per_interface]; + DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO, + ("result_mat: %d ", + result_mat[if_id][pup] + [bit])); + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (PBS_RX_PHY_REG + effective_cs * 0x10) : + (PBS_TX_PHY_REG + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr + pad_num, + result_mat[if_id][pup][bit])); + } + pbsdelay_per_pup[pbs_mode][if_id][pup] = + (max_pbs_per_pup[if_id][pup] == + min_pbs_per_pup[if_id][pup]) ? + TYPICAL_PBS_VALUE : + ((max_adll_per_pup[if_id][pup] - + min_adll_per_pup[if_id][pup]) * adll_tap / + (max_pbs_per_pup[if_id][pup] - + min_pbs_per_pup[if_id][pup])); + + /* RX results ready, write RX also */ + if (pbs_mode == PBS_TX_MODE) { + /* Write TX results */ + reg_addr = (0x14 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + (max_pbs_per_pup[if_id][pup] - + min_pbs_per_pup[if_id][pup]) / + 2)); + reg_addr = (0x15 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + (max_pbs_per_pup[if_id][pup] - + min_pbs_per_pup[if_id][pup]) / + 2)); + + /* Write previously stored RX results */ + reg_addr = (0x54 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + result_mat_rx_dqs[if_id][pup] + [effective_cs])); + reg_addr = (0x55 + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr, + result_mat_rx_dqs[if_id][pup] + [effective_cs])); + } else { + /* + * RX results may affect RL results correctess, + * so just store the results that will written + * in TX stage + */ + result_mat_rx_dqs[if_id][pup][effective_cs] = + (max_pbs_per_pup[if_id][pup] - + min_pbs_per_pup[if_id][pup]) / 2; + } + DEBUG_PBS_ENGINE( + DEBUG_LEVEL_INFO, + (", PBS tap=%d [psec] ==> skew observed = %d\n", + pbsdelay_per_pup[pbs_mode][if_id][pup], + ((max_pbs_per_pup[if_id][pup] - + min_pbs_per_pup[if_id][pup]) * + pbsdelay_per_pup[pbs_mode][if_id][pup]))); + } + } + + /* Write back to the phy the default values */ + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (READ_CENTRALIZATION_PHY_REG + effective_cs * 4) : + (WRITE_CENTRALIZATION_PHY_REG + effective_cs * 4); + write_adll_value(nominal_adll, reg_addr); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + reg_addr = (pbs_mode == PBS_RX_MODE) ? + (0x5a + effective_cs * 0x10) : + (0x1a + effective_cs * 0x10); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA, reg_addr, + 0)); + + /* restore cs enable value */ + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + CS_ENABLE_REG, cs_enable_reg_val[if_id], + MASK_ALL_BITS)); + } + + /* exit test mode */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ODPG_WRITE_READ_MODE_ENABLE_REG, 0xffff, MASK_ALL_BITS)); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + /* + * meaning that there is no VW exist at all (No lock at + * the EBA ADLL shift at EBS) + */ + if (pup_state[if_id][pup] == 1) + return MV_FAIL; + } + + return MV_OK; +} + +/* + * Name: ddr3_tip_pbs_rx. + * Desc: PBS TX + * Args: TBD + * Notes: + * Returns: OK if success, other error code if fail. + */ +int ddr3_tip_pbs_rx(u32 uidev_num) +{ + return ddr3_tip_pbs(uidev_num, PBS_RX_MODE); +} + +/* + * Name: ddr3_tip_pbs_tx. + * Desc: PBS TX + * Args: TBD + * Notes: + * Returns: OK if success, other error code if fail. + */ +int ddr3_tip_pbs_tx(u32 uidev_num) +{ + return ddr3_tip_pbs(uidev_num, PBS_TX_MODE); +} + +#ifndef EXCLUDE_SWITCH_DEBUG +/* + * Print PBS Result + */ +int ddr3_tip_print_all_pbs_result(u32 dev_num) +{ + u32 curr_cs; + u32 max_cs = hws_ddr3_tip_max_cs_get(); + + for (curr_cs = 0; curr_cs < max_cs; curr_cs++) { + ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_RX_MODE); + ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_TX_MODE); + } + + return MV_OK; +} + +/* + * Print PBS Result + */ +int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode) +{ + u32 data_value = 0, bit = 0, if_id = 0, pup = 0; + u32 reg_addr = (pbs_mode == PBS_RX_MODE) ? + (PBS_RX_PHY_REG + cs_num * 0x10) : + (PBS_TX_PHY_REG + cs_num * 0x10); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + printf("CS%d, %s ,PBS\n", cs_num, + (pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx"); + + for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) { + printf("%s, DQ", (pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx"); + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + printf("%d ,PBS,,, ", bit); + for (pup = 0; pup <= tm->num_of_bus_per_interface; + pup++) { + VALIDATE_ACTIVE(tm->bus_act_mask, pup); + CHECK_STATUS(ddr3_tip_bus_read + (dev_num, if_id, + ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr + bit, + &data_value)); + printf("%d , ", data_value); + } + } + printf("\n"); + } + printf("\n"); + + return MV_OK; +} +#endif + +/* + * Fixup PBS Result + */ +int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode) +{ + u32 if_id, pup, bit; + u32 reg_addr = (pbs_mode == PBS_RX_MODE) ? + (PBS_RX_PHY_REG + effective_cs * 0x10) : + (PBS_TX_PHY_REG + effective_cs * 0x10); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (pup = 0; pup <= tm->num_of_bus_per_interface; pup++) { + for (bit = 0; bit <= BUS_WIDTH_IN_BITS + 3; bit++) { + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, ACCESS_TYPE_UNICAST, pup, + DDR_PHY_DATA, reg_addr + bit, 0)); + } + } + } + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_static.c b/drivers/ddr/marvell/a38x/ddr3_training_static.c new file mode 100644 index 0000000..5101f3f --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr3_training_static.c @@ -0,0 +1,538 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#include "ddr3_init.h" + +/* Design Guidelines parameters */ +u32 g_zpri_data = 123; /* controller data - P drive strength */ +u32 g_znri_data = 123; /* controller data - N drive strength */ +u32 g_zpri_ctrl = 74; /* controller C/A - P drive strength */ +u32 g_znri_ctrl = 74; /* controller C/A - N drive strength */ +u32 g_zpodt_data = 45; /* controller data - P ODT */ +u32 g_znodt_data = 45; /* controller data - N ODT */ +u32 g_zpodt_ctrl = 45; /* controller data - P ODT */ +u32 g_znodt_ctrl = 45; /* controller data - N ODT */ +u32 g_odt_config = 0x120012; +u32 g_rtt_nom = 0x44; +u32 g_dic = 0x2; + +#ifdef STATIC_ALGO_SUPPORT + +#define PARAM_NOT_CARE 0 +#define MAX_STATIC_SEQ 48 + +u32 silicon_delay[HWS_MAX_DEVICE_NUM]; +struct hws_tip_static_config_info static_config[HWS_MAX_DEVICE_NUM]; +static reg_data *static_init_controller_config[HWS_MAX_DEVICE_NUM]; + +/* debug delay in write leveling */ +int wl_debug_delay = 0; +/* pup register #3 for functional board */ +int function_reg_value = 8; +u32 silicon; + +u32 read_ready_delay_phase_offset[] = { 4, 4, 4, 4, 6, 6, 6, 6 }; + +static struct cs_element chip_select_map[] = { + /* CS Value (single only) Num_CS */ + {0, 0}, + {0, 1}, + {1, 1}, + {0, 2}, + {2, 1}, + {0, 2}, + {0, 2}, + {0, 3}, + {3, 1}, + {0, 2}, + {0, 2}, + {0, 3}, + {0, 2}, + {0, 3}, + {0, 3}, + {0, 4} +}; + +/* + * Register static init controller DB + */ +int ddr3_tip_init_specific_reg_config(u32 dev_num, reg_data *reg_config_arr) +{ + static_init_controller_config[dev_num] = reg_config_arr; + return MV_OK; +} + +/* + * Register static info DB + */ +int ddr3_tip_init_static_config_db( + u32 dev_num, struct hws_tip_static_config_info *static_config_info) +{ + static_config[dev_num].board_trace_arr = + static_config_info->board_trace_arr; + static_config[dev_num].package_trace_arr = + static_config_info->package_trace_arr; + silicon_delay[dev_num] = static_config_info->silicon_delay; + + return MV_OK; +} + +/* + * Static round trip flow - Calculates the total round trip delay. + */ +int ddr3_tip_static_round_trip_arr_build(u32 dev_num, + struct trip_delay_element *table_ptr, + int is_wl, u32 *round_trip_delay_arr) +{ + u32 bus_index, global_bus; + u32 if_id; + u32 bus_per_interface; + int sign; + u32 temp; + u32 board_trace; + struct trip_delay_element *pkg_delay_ptr; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + /* + * In WL we calc the diff between Clock to DQs in RL we sum the round + * trip of Clock and DQs + */ + sign = (is_wl) ? -1 : 1; + + bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES(); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + for (bus_index = 0; bus_index < bus_per_interface; + bus_index++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + global_bus = (if_id * bus_per_interface) + bus_index; + + /* calculate total trip delay (package and board) */ + board_trace = (table_ptr[global_bus].dqs_delay * sign) + + table_ptr[global_bus].ck_delay; + temp = (board_trace * 163) / 1000; + + /* Convert the length to delay in psec units */ + pkg_delay_ptr = + static_config[dev_num].package_trace_arr; + round_trip_delay_arr[global_bus] = temp + + (int)(pkg_delay_ptr[global_bus].dqs_delay * + sign) + + (int)pkg_delay_ptr[global_bus].ck_delay + + (int)((is_wl == 1) ? wl_debug_delay : + (int)silicon_delay[dev_num]); + DEBUG_TRAINING_STATIC_IP( + DEBUG_LEVEL_TRACE, + ("Round Trip Build round_trip_delay_arr[0x%x]: 0x%x temp 0x%x\n", + global_bus, round_trip_delay_arr[global_bus], + temp)); + } + } + + return MV_OK; +} + +/* + * Write leveling for static flow - calculating the round trip delay of the + * DQS signal. + */ +int ddr3_tip_write_leveling_static_config(u32 dev_num, u32 if_id, + enum hws_ddr_freq frequency, + u32 *round_trip_delay_arr) +{ + u32 bus_index; /* index to the bus loop */ + u32 bus_start_index; + u32 bus_per_interface; + u32 phase = 0; + u32 adll = 0, adll_cen, adll_inv, adll_final; + u32 adll_period = MEGA / freq_val[frequency] / 64; + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("ddr3_tip_write_leveling_static_config\n")); + DEBUG_TRAINING_STATIC_IP( + DEBUG_LEVEL_TRACE, + ("dev_num 0x%x IF 0x%x freq %d (adll_period 0x%x)\n", + dev_num, if_id, frequency, adll_period)); + + bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES(); + bus_start_index = if_id * bus_per_interface; + for (bus_index = bus_start_index; + bus_index < (bus_start_index + bus_per_interface); bus_index++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + phase = round_trip_delay_arr[bus_index] / (32 * adll_period); + adll = (round_trip_delay_arr[bus_index] - + (phase * 32 * adll_period)) / adll_period; + adll = (adll > 31) ? 31 : adll; + adll_cen = 16 + adll; + adll_inv = adll_cen / 32; + adll_final = adll_cen - (adll_inv * 32); + adll_final = (adll_final > 31) ? 31 : adll_final; + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("\t%d - phase 0x%x adll 0x%x\n", + bus_index, phase, adll)); + /* + * Writing to all 4 phy of Interface number, + * bit 0 \96 4 \96 ADLL, bit 6-8 phase + */ + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + (bus_index % 4), DDR_PHY_DATA, + PHY_WRITE_DELAY(cs), + ((phase << 6) + (adll & 0x1f)), 0x1df)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ACCESS_TYPE_UNICAST, (bus_index % 4), + DDR_PHY_DATA, WRITE_CENTRALIZATION_PHY_REG, + ((adll_inv & 0x1) << 5) + adll_final)); + } + + return MV_OK; +} + +/* + * Read leveling for static flow + */ +int ddr3_tip_read_leveling_static_config(u32 dev_num, + u32 if_id, + enum hws_ddr_freq frequency, + u32 *total_round_trip_delay_arr) +{ + u32 cs, data0, data1, data3 = 0; + u32 bus_index; /* index to the bus loop */ + u32 bus_start_index; + u32 phase0, phase1, max_phase; + u32 adll0, adll1; + u32 cl_value; + u32 min_delay; + u32 sdr_period = MEGA / freq_val[frequency]; + u32 ddr_period = MEGA / freq_val[frequency] / 2; + u32 adll_period = MEGA / freq_val[frequency] / 64; + enum hws_speed_bin speed_bin_index; + u32 rd_sample_dly[MAX_CS_NUM] = { 0 }; + u32 rd_ready_del[MAX_CS_NUM] = { 0 }; + u32 bus_per_interface = GET_TOPOLOGY_NUM_OF_BUSES(); + struct hws_topology_map *tm = ddr3_get_topology_map(); + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("ddr3_tip_read_leveling_static_config\n")); + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("dev_num 0x%x ifc 0x%x freq %d\n", dev_num, + if_id, frequency)); + DEBUG_TRAINING_STATIC_IP( + DEBUG_LEVEL_TRACE, + ("Sdr_period 0x%x Ddr_period 0x%x adll_period 0x%x\n", + sdr_period, ddr_period, adll_period)); + + if (tm->interface_params[first_active_if].memory_freq == + frequency) { + cl_value = tm->interface_params[first_active_if].cas_l; + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("cl_value 0x%x\n", cl_value)); + } else { + speed_bin_index = tm->interface_params[if_id].speed_bin_index; + cl_value = cas_latency_table[speed_bin_index].cl_val[frequency]; + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("cl_value 0x%x speed_bin_index %d\n", + cl_value, speed_bin_index)); + } + + bus_start_index = if_id * bus_per_interface; + + for (bus_index = bus_start_index; + bus_index < (bus_start_index + bus_per_interface); + bus_index += 2) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + cs = chip_select_map[ + tm->interface_params[if_id].as_bus_params[ + (bus_index % 4)].cs_bitmask].cs_num; + + /* read sample delay calculation */ + min_delay = (total_round_trip_delay_arr[bus_index] < + total_round_trip_delay_arr[bus_index + 1]) ? + total_round_trip_delay_arr[bus_index] : + total_round_trip_delay_arr[bus_index + 1]; + /* round down */ + rd_sample_dly[cs] = 2 * (min_delay / (sdr_period * 2)); + DEBUG_TRAINING_STATIC_IP( + DEBUG_LEVEL_TRACE, + ("\t%d - min_delay 0x%x cs 0x%x rd_sample_dly[cs] 0x%x\n", + bus_index, min_delay, cs, rd_sample_dly[cs])); + + /* phase calculation */ + phase0 = (total_round_trip_delay_arr[bus_index] - + (sdr_period * rd_sample_dly[cs])) / (ddr_period); + phase1 = (total_round_trip_delay_arr[bus_index + 1] - + (sdr_period * rd_sample_dly[cs])) / (ddr_period); + max_phase = (phase0 > phase1) ? phase0 : phase1; + DEBUG_TRAINING_STATIC_IP( + DEBUG_LEVEL_TRACE, + ("\tphase0 0x%x phase1 0x%x max_phase 0x%x\n", + phase0, phase1, max_phase)); + + /* ADLL calculation */ + adll0 = (u32)((total_round_trip_delay_arr[bus_index] - + (sdr_period * rd_sample_dly[cs]) - + (ddr_period * phase0)) / adll_period); + adll0 = (adll0 > 31) ? 31 : adll0; + adll1 = (u32)((total_round_trip_delay_arr[bus_index + 1] - + (sdr_period * rd_sample_dly[cs]) - + (ddr_period * phase1)) / adll_period); + adll1 = (adll1 > 31) ? 31 : adll1; + + /* The Read delay close the Read FIFO */ + rd_ready_del[cs] = rd_sample_dly[cs] + + read_ready_delay_phase_offset[max_phase]; + DEBUG_TRAINING_STATIC_IP( + DEBUG_LEVEL_TRACE, + ("\tadll0 0x%x adll1 0x%x rd_ready_del[cs] 0x%x\n", + adll0, adll1, rd_ready_del[cs])); + + /* + * Write to the phy of Interface (bit 0 \96 4 \96 ADLL, + * bit 6-8 phase) + */ + data0 = ((phase0 << 6) + (adll0 & 0x1f)); + data1 = ((phase1 << 6) + (adll1 & 0x1f)); + + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + (bus_index % 4), DDR_PHY_DATA, PHY_READ_DELAY(cs), + data0, 0x1df)); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + ((bus_index + 1) % 4), DDR_PHY_DATA, + PHY_READ_DELAY(cs), data1, 0x1df)); + } + + for (bus_index = 0; bus_index < bus_per_interface; bus_index++) { + VALIDATE_ACTIVE(tm->bus_act_mask, bus_index); + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + bus_index, DDR_PHY_DATA, 0x3, data3, 0x1f)); + } + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + READ_DATA_SAMPLE_DELAY, + (rd_sample_dly[0] + cl_value) + (rd_sample_dly[1] << 8), + MASK_ALL_BITS)); + + /* Read_ready_del0 bit 0-4 , CS bits 8-12 */ + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_UNICAST, if_id, + READ_DATA_READY_DELAY, + rd_ready_del[0] + (rd_ready_del[1] << 8) + cl_value, + MASK_ALL_BITS)); + + return MV_OK; +} + +/* + * DDR3 Static flow + */ +int ddr3_tip_run_static_alg(u32 dev_num, enum hws_ddr_freq freq) +{ + u32 if_id = 0; + struct trip_delay_element *table_ptr; + u32 wl_total_round_trip_delay_arr[MAX_TOTAL_BUS_NUM]; + u32 rl_total_round_trip_delay_arr[MAX_TOTAL_BUS_NUM]; + struct init_cntr_param init_cntr_prm; + int ret; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("ddr3_tip_run_static_alg")); + + init_cntr_prm.do_mrs_phy = 1; + init_cntr_prm.is_ctrl64_bit = 0; + init_cntr_prm.init_phy = 1; + ret = hws_ddr3_tip_init_controller(dev_num, &init_cntr_prm); + if (ret != MV_OK) { + DEBUG_TRAINING_STATIC_IP( + DEBUG_LEVEL_ERROR, + ("hws_ddr3_tip_init_controller failure\n")); + } + + /* calculate the round trip delay for Write Leveling */ + table_ptr = static_config[dev_num].board_trace_arr; + CHECK_STATUS(ddr3_tip_static_round_trip_arr_build + (dev_num, table_ptr, 1, + wl_total_round_trip_delay_arr)); + /* calculate the round trip delay for Read Leveling */ + CHECK_STATUS(ddr3_tip_static_round_trip_arr_build + (dev_num, table_ptr, 0, + rl_total_round_trip_delay_arr)); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + /* check if the interface is enabled */ + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + /* + * Static frequency is defined according to init-frequency + * (not target) + */ + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("Static IF %d freq %d\n", + if_id, freq)); + CHECK_STATUS(ddr3_tip_write_leveling_static_config + (dev_num, if_id, freq, + wl_total_round_trip_delay_arr)); + CHECK_STATUS(ddr3_tip_read_leveling_static_config + (dev_num, if_id, freq, + rl_total_round_trip_delay_arr)); + } + + return MV_OK; +} + +/* + * Init controller for static flow + */ +int ddr3_tip_static_init_controller(u32 dev_num) +{ + u32 index_cnt = 0; + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("ddr3_tip_static_init_controller\n")); + while (static_init_controller_config[dev_num][index_cnt].reg_addr != + 0) { + CHECK_STATUS(ddr3_tip_if_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + static_init_controller_config[dev_num][index_cnt]. + reg_addr, + static_init_controller_config[dev_num][index_cnt]. + reg_data, + static_init_controller_config[dev_num][index_cnt]. + reg_mask)); + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("Init_controller index_cnt %d\n", + index_cnt)); + index_cnt++; + } + + return MV_OK; +} + +int ddr3_tip_static_phy_init_controller(u32 dev_num) +{ + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("Phy Init Controller 2\n")); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa4, + 0x3dfe)); + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("Phy Init Controller 3\n")); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa6, + 0xcb2)); + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("Phy Init Controller 4\n")); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa9, + 0)); + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("Static Receiver Calibration\n")); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xd0, + 0x1f)); + + DEBUG_TRAINING_STATIC_IP(DEBUG_LEVEL_TRACE, + ("Static V-REF Calibration\n")); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0xa8, + 0x434)); + + return MV_OK; +} +#endif + +/* + * Configure phy (called by static init controller) for static flow + */ +int ddr3_tip_configure_phy(u32 dev_num) +{ + u32 if_id, phy_id; + struct hws_topology_map *tm = ddr3_get_topology_map(); + + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, + PAD_ZRI_CALIB_PHY_REG, + ((0x7f & g_zpri_data) << 7 | (0x7f & g_znri_data)))); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL, + PAD_ZRI_CALIB_PHY_REG, + ((0x7f & g_zpri_ctrl) << 7 | (0x7f & g_znri_ctrl)))); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, + PAD_ODT_CALIB_PHY_REG, + ((0x3f & g_zpodt_data) << 6 | (0x3f & g_znodt_data)))); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL, + PAD_ODT_CALIB_PHY_REG, + ((0x3f & g_zpodt_ctrl) << 6 | (0x3f & g_znodt_ctrl)))); + + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, + PAD_PRE_DISABLE_PHY_REG, 0)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, + CMOS_CONFIG_PHY_REG, 0)); + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_CONTROL, + CMOS_CONFIG_PHY_REG, 0)); + + for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { + /* check if the interface is enabled */ + VALIDATE_ACTIVE(tm->if_act_mask, if_id); + + for (phy_id = 0; + phy_id < tm->num_of_bus_per_interface; + phy_id++) { + VALIDATE_ACTIVE(tm->bus_act_mask, phy_id); + /* Vref & clamp */ + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, phy_id, DDR_PHY_DATA, + PAD_CONFIG_PHY_REG, + ((clamp_tbl[if_id] << 4) | vref), + ((0x7 << 4) | 0x7))); + /* clamp not relevant for control */ + CHECK_STATUS(ddr3_tip_bus_read_modify_write + (dev_num, ACCESS_TYPE_UNICAST, + if_id, phy_id, DDR_PHY_CONTROL, + PAD_CONFIG_PHY_REG, 0x4, 0x7)); + } + } + + CHECK_STATUS(ddr3_tip_bus_write + (dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, + ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, DDR_PHY_DATA, 0x90, + 0x6002)); + + return MV_OK; +} diff --git a/drivers/ddr/marvell/a38x/ddr_topology_def.h b/drivers/ddr/marvell/a38x/ddr_topology_def.h new file mode 100644 index 0000000..f8894e8 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr_topology_def.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR_TOPOLOGY_DEF_H +#define _DDR_TOPOLOGY_DEF_H + +#include "ddr3_training_ip_def.h" +#include "ddr3_topology_def.h" + +#if defined(CONFIG_ARMADA_38X) +#include "ddr3_a38x.h" +#endif + +/* bus width in bits */ +enum hws_bus_width { + BUS_WIDTH_4, + BUS_WIDTH_8, + BUS_WIDTH_16, + BUS_WIDTH_32 +}; + +enum hws_temperature { + HWS_TEMP_LOW, + HWS_TEMP_NORMAL, + HWS_TEMP_HIGH +}; + +enum hws_mem_size { + MEM_512M, + MEM_1G, + MEM_2G, + MEM_4G, + MEM_8G, + MEM_SIZE_LAST +}; + +struct bus_params { + /* Chip Select (CS) bitmask (bits 0-CS0, bit 1- CS1 ...) */ + u8 cs_bitmask; + + /* + * mirror enable/disable + * (bits 0-CS0 mirroring, bit 1- CS1 mirroring ...) + */ + int mirror_enable_bitmask; + + /* DQS Swap (polarity) - true if enable */ + int is_dqs_swap; + + /* CK swap (polarity) - true if enable */ + int is_ck_swap; +}; + +struct if_params { + /* bus configuration */ + struct bus_params as_bus_params[MAX_BUS_NUM]; + + /* Speed Bin Table */ + enum hws_speed_bin speed_bin_index; + + /* bus width of memory */ + enum hws_bus_width bus_width; + + /* Bus memory size (MBit) */ + enum hws_mem_size memory_size; + + /* The DDR frequency for each interfaces */ + enum hws_ddr_freq memory_freq; + + /* + * delay CAS Write Latency + * - 0 for using default value (jedec suggested) + */ + u8 cas_wl; + + /* + * delay CAS Latency + * - 0 for using default value (jedec suggested) + */ + u8 cas_l; + + /* operation temperature */ + enum hws_temperature interface_temp; +}; + +struct hws_topology_map { + /* Number of interfaces (default is 12) */ + u8 if_act_mask; + + /* Controller configuration per interface */ + struct if_params interface_params[MAX_INTERFACE_NUM]; + + /* BUS per interface (default is 4) */ + u8 num_of_bus_per_interface; + + /* Bit mask for active buses */ + u8 bus_act_mask; +}; + +/* DDR3 training global configuration parameters */ +struct tune_train_params { + u32 ck_delay; + u32 ck_delay_16; + u32 p_finger; + u32 n_finger; + u32 phy_reg3_val; +}; + +#endif /* _DDR_TOPOLOGY_DEF_H */ diff --git a/drivers/ddr/marvell/a38x/ddr_training_ip_db.h b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h new file mode 100644 index 0000000..ff5f817 --- /dev/null +++ b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _DDR_TRAINING_IP_DB_H_ +#define _DDR_TRAINING_IP_DB_H_ + +#include "ddr_topology_def.h" +#include "ddr3_training_ip_db.h" + +u32 speed_bin_table(u8 index, enum speed_bin_table_elements element); +u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index); + +#endif /* _DDR3_TRAINING_IP_DB_H_ */ diff --git a/drivers/ddr/marvell/a38x/silicon_if.h b/drivers/ddr/marvell/a38x/silicon_if.h new file mode 100644 index 0000000..7fce27d --- /dev/null +++ b/drivers/ddr/marvell/a38x/silicon_if.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __silicon_if_H +#define __silicon_if_H + +/* max number of devices supported by driver */ +#ifdef CO_CPU_RUN +#define HWS_MAX_DEVICE_NUM (1) +#else +#define HWS_MAX_DEVICE_NUM (16) +#endif + +#endif /* __silicon_if_H */ diff --git a/drivers/ddr/marvell/a38x/xor.c b/drivers/ddr/marvell/a38x/xor.c new file mode 100644 index 0000000..9c73c54 --- /dev/null +++ b/drivers/ddr/marvell/a38x/xor.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "ddr3_init.h" +#include "xor_regs.h" + +/* defines */ +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + +static u32 ui_xor_regs_ctrl_backup; +static u32 ui_xor_regs_base_backup[MAX_CS]; +static u32 ui_xor_regs_mask_backup[MAX_CS]; + +void mv_sys_xor_init(u32 num_of_cs, u32 cs_ena, u32 cs_size, u32 base_delta) +{ + u32 reg, ui, base, cs_count; + + ui_xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0)); + for (ui = 0; ui < MAX_CS; ui++) + ui_xor_regs_base_backup[ui] = + reg_read(XOR_BASE_ADDR_REG(0, ui)); + for (ui = 0; ui < MAX_CS; ui++) + ui_xor_regs_mask_backup[ui] = + reg_read(XOR_SIZE_MASK_REG(0, ui)); + + reg = 0; + for (ui = 0; ui < (num_of_cs); ui++) { + /* Enable Window x for each CS */ + reg |= (0x1 << (ui)); + /* Enable Window x for each CS */ + reg |= (0x3 << ((ui * 2) + 16)); + } + + reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg); + + cs_count = 0; + for (ui = 0; ui < num_of_cs; ui++) { + if (cs_ena & (1 << ui)) { + /* + * window x - Base - 0x00000000, + * Attribute 0x0e - DRAM + */ + base = cs_size * ui + base_delta; + switch (ui) { + case 0: + base |= 0xe00; + break; + case 1: + base |= 0xd00; + break; + case 2: + base |= 0xb00; + break; + case 3: + base |= 0x700; + break; + } + + reg_write(XOR_BASE_ADDR_REG(0, cs_count), base); + + /* window x - Size */ + reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x7fff0000); + cs_count++; + } + } + + mv_xor_hal_init(1); + + return; +} + +void mv_sys_xor_finish(void) +{ + u32 ui; + + reg_write(XOR_WINDOW_CTRL_REG(0, 0), ui_xor_regs_ctrl_backup); + for (ui = 0; ui < MAX_CS; ui++) + reg_write(XOR_BASE_ADDR_REG(0, ui), + ui_xor_regs_base_backup[ui]); + for (ui = 0; ui < MAX_CS; ui++) + reg_write(XOR_SIZE_MASK_REG(0, ui), + ui_xor_regs_mask_backup[ui]); + + reg_write(XOR_ADDR_OVRD_REG(0, 0), 0); +} + +/* + * mv_xor_hal_init - Initialize XOR engine + * + * DESCRIPTION: + * This function initialize XOR unit. + * INPUT: + * None. + * + * OUTPUT: + * None. + * + * RETURN: + * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. + */ +void mv_xor_hal_init(u32 xor_chan_num) +{ + u32 i; + + /* Abort any XOR activity & set default configuration */ + for (i = 0; i < xor_chan_num; i++) { + mv_xor_command_set(i, MV_STOP); + mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) | + (4 << XEXCR_DST_BURST_LIMIT_OFFS) | + (4 << XEXCR_SRC_BURST_LIMIT_OFFS)); + } +} + +/* + * mv_xor_ctrl_set - Set XOR channel control registers + * + * DESCRIPTION: + * + * INPUT: + * + * OUTPUT: + * None. + * + * RETURN: + * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. + * NOTE: + * This function does not modify the Operation_mode field of control register. + */ +int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl) +{ + u32 old_value; + + /* update the XOR Engine [0..1] Configuration Registers (XEx_c_r) */ + old_value = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))) & + XEXCR_OPERATION_MODE_MASK; + xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK; + xor_ctrl |= old_value; + reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl); + + return MV_OK; +} + +int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size, + u32 init_val_high, u32 init_val_low) +{ + u32 temp; + + /* Parameter checking */ + if (chan >= MV_XOR_MAX_CHAN) + return MV_BAD_PARAM; + + if (MV_ACTIVE == mv_xor_state_get(chan)) + return MV_BUSY; + + if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) || + (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE)) + return MV_BAD_PARAM; + + /* set the operation mode to Memory Init */ + temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))); + temp &= ~XEXCR_OPERATION_MODE_MASK; + temp |= XEXCR_OPERATION_MODE_MEM_INIT; + reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp); + + /* + * update the start_ptr field in XOR Engine [0..1] Destination Pointer + * Register + */ + reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr); + + /* + * update the Block_size field in the XOR Engine[0..1] Block Size + * Registers + */ + reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)), + block_size); + + /* + * update the field Init_val_l in the XOR Engine Initial Value Register + * Low (XEIVRL) + */ + reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low); + + /* + * update the field Init_val_h in the XOR Engine Initial Value Register + * High (XEIVRH) + */ + reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high); + + /* start transfer */ + reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)), + XEXACTR_XESTART_MASK); + + return MV_OK; +} + +/* + * mv_xor_state_get - Get XOR channel state. + * + * DESCRIPTION: + * XOR channel activity state can be active, idle, paused. + * This function retrunes the channel activity state. + * + * INPUT: + * chan - the channel number + * + * OUTPUT: + * None. + * + * RETURN: + * XOR_CHANNEL_IDLE - If the engine is idle. + * XOR_CHANNEL_ACTIVE - If the engine is busy. + * XOR_CHANNEL_PAUSED - If the engine is paused. + * MV_UNDEFINED_STATE - If the engine state is undefind or there is no + * such engine + */ +enum mv_state mv_xor_state_get(u32 chan) +{ + u32 state; + + /* Parameter checking */ + if (chan >= MV_XOR_MAX_CHAN) { + DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan)); + return MV_UNDEFINED_STATE; + } + + /* read the current state */ + state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan))); + state &= XEXACTR_XESTATUS_MASK; + + /* return the state */ + switch (state) { + case XEXACTR_XESTATUS_IDLE: + return MV_IDLE; + case XEXACTR_XESTATUS_ACTIVE: + return MV_ACTIVE; + case XEXACTR_XESTATUS_PAUSED: + return MV_PAUSED; + } + + return MV_UNDEFINED_STATE; +} + +/* + * mv_xor_command_set - Set command of XOR channel + * + * DESCRIPTION: + * XOR channel can be started, idle, paused and restarted. + * Paused can be set only if channel is active. + * Start can be set only if channel is idle or paused. + * Restart can be set only if channel is paused. + * Stop can be set only if channel is active. + * + * INPUT: + * chan - The channel number + * command - The command type (start, stop, restart, pause) + * + * OUTPUT: + * None. + * + * RETURN: + * MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on + * undefind XOR engine mode + */ +int mv_xor_command_set(u32 chan, enum mv_command command) +{ + enum mv_state state; + + /* Parameter checking */ + if (chan >= MV_XOR_MAX_CHAN) { + DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan)); + return MV_BAD_PARAM; + } + + /* get the current state */ + state = mv_xor_state_get(chan); + + if ((command == MV_START) && (state == MV_IDLE)) { + /* command is start and current state is idle */ + reg_bit_set(XOR_ACTIVATION_REG + (XOR_UNIT(chan), XOR_CHAN(chan)), + XEXACTR_XESTART_MASK); + return MV_OK; + } else if ((command == MV_STOP) && (state == MV_ACTIVE)) { + /* command is stop and current state is active */ + reg_bit_set(XOR_ACTIVATION_REG + (XOR_UNIT(chan), XOR_CHAN(chan)), + XEXACTR_XESTOP_MASK); + return MV_OK; + } else if (((enum mv_state)command == MV_PAUSED) && + (state == MV_ACTIVE)) { + /* command is paused and current state is active */ + reg_bit_set(XOR_ACTIVATION_REG + (XOR_UNIT(chan), XOR_CHAN(chan)), + XEXACTR_XEPAUSE_MASK); + return MV_OK; + } else if ((command == MV_RESTART) && (state == MV_PAUSED)) { + /* command is restart and current state is paused */ + reg_bit_set(XOR_ACTIVATION_REG + (XOR_UNIT(chan), XOR_CHAN(chan)), + XEXACTR_XERESTART_MASK); + return MV_OK; + } else if ((command == MV_STOP) && (state == MV_IDLE)) { + /* command is stop and current state is active */ + return MV_OK; + } + + /* illegal command */ + DB(printf("%s: ERR. Illegal command\n", __func__)); + + return MV_BAD_PARAM; +} + +void ddr3_new_tip_ecc_scrub(void) +{ + u32 cs_c, max_cs; + u32 cs_ena = 0; + + printf("DDR3 Training Sequence - Start scrubbing\n"); + + max_cs = hws_ddr3_tip_max_cs_get(); + for (cs_c = 0; cs_c < max_cs; cs_c++) + cs_ena |= 1 << cs_c; + + mv_sys_xor_init(max_cs, cs_ena, 0x80000000, 0); + + mv_xor_mem_init(0, 0x00000000, 0x80000000, 0xdeadbeef, 0xdeadbeef); + /* wait for previous transfer completion */ + while (mv_xor_state_get(0) != MV_IDLE) + ; + + mv_xor_mem_init(0, 0x80000000, 0x40000000, 0xdeadbeef, 0xdeadbeef); + + /* wait for previous transfer completion */ + while (mv_xor_state_get(0) != MV_IDLE) + ; + + /* Return XOR State */ + mv_sys_xor_finish(); + + printf("DDR3 Training Sequence - End scrubbing\n"); +} diff --git a/drivers/ddr/marvell/a38x/xor.h b/drivers/ddr/marvell/a38x/xor.h new file mode 100644 index 0000000..7b1e316 --- /dev/null +++ b/drivers/ddr/marvell/a38x/xor.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _XOR_H +#define _XOR_H + +#define SRAM_BASE 0x40000000 + +#include "ddr3_hws_hw_training_def.h" + +#define MV_XOR_MAX_UNIT 2 /* XOR unit == XOR engine */ +#define MV_XOR_MAX_CHAN 4 /* total channels for all units */ +#define MV_XOR_MAX_CHAN_PER_UNIT 2 /* channels for units */ + +#define MV_IS_POWER_OF_2(num) (((num) != 0) && (((num) & ((num) - 1)) == 0)) + +/* + * This structure describes address space window. Window base can be + * 64 bit, window size up to 4GB + */ +struct addr_win { + u32 base_low; /* 32bit base low */ + u32 base_high; /* 32bit base high */ + u32 size; /* 32bit size */ +}; + +/* This structure describes SoC units address decode window */ +struct unit_win_info { + struct addr_win addr_win; /* An address window */ + int enable; /* Address decode window is enabled/disabled */ + u8 attrib; /* chip select attributes */ + u8 target_id; /* Target Id of this MV_TARGET */ +}; + +/* + * This enumerator describes the type of functionality the XOR channel + * can have while using the same data structures. + */ +enum xor_type { + MV_XOR, /* XOR channel functions as XOR accelerator */ + MV_DMA, /* XOR channel functions as IDMA channel */ + MV_CRC32 /* XOR channel functions as CRC 32 calculator */ +}; + +enum mv_state { + MV_IDLE, + MV_ACTIVE, + MV_PAUSED, + MV_UNDEFINED_STATE +}; + +/* + * This enumerator describes the set of commands that can be applied on + * an engine (e.g. IDMA, XOR). Appling a comman depends on the current + * status (see MV_STATE enumerator) + * + * Start can be applied only when status is IDLE + * Stop can be applied only when status is IDLE, ACTIVE or PAUSED + * Pause can be applied only when status is ACTIVE + * Restart can be applied only when status is PAUSED + */ +enum mv_command { + MV_START, /* Start */ + MV_STOP, /* Stop */ + MV_PAUSE, /* Pause */ + MV_RESTART /* Restart */ +}; + +enum xor_override_target { + SRC_ADDR0, /* Source Address #0 Control */ + SRC_ADDR1, /* Source Address #1 Control */ + SRC_ADDR2, /* Source Address #2 Control */ + SRC_ADDR3, /* Source Address #3 Control */ + SRC_ADDR4, /* Source Address #4 Control */ + SRC_ADDR5, /* Source Address #5 Control */ + SRC_ADDR6, /* Source Address #6 Control */ + SRC_ADDR7, /* Source Address #7 Control */ + XOR_DST_ADDR, /* Destination Address Control */ + XOR_NEXT_DESC /* Next Descriptor Address Control */ +}; + +enum mv_state mv_xor_state_get(u32 chan); +void mv_xor_hal_init(u32 xor_chan_num); +int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl); +int mv_xor_command_set(u32 chan, enum mv_command command); +int mv_xor_override_set(u32 chan, enum xor_override_target target, u32 win_num, + int enable); + +#endif diff --git a/drivers/ddr/marvell/a38x/xor_regs.h b/drivers/ddr/marvell/a38x/xor_regs.h new file mode 100644 index 0000000..cc1546e --- /dev/null +++ b/drivers/ddr/marvell/a38x/xor_regs.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _XOR_REGS_h +#define _XOR_REGS_h + +/* + * For controllers that have two XOR units, then chans 2 & 3 will be + * mapped to channels 0 & 1 of unit 1 + */ +#define XOR_UNIT(chan) ((chan) >> 1) +#define XOR_CHAN(chan) ((chan) & 1) + +#define MV_XOR_REGS_OFFSET(unit) (0x60900) +#define MV_XOR_REGS_BASE(unit) (MV_XOR_REGS_OFFSET(unit)) + +/* XOR Engine Control Register Map */ +#define XOR_CHANNEL_ARBITER_REG(unit) (MV_XOR_REGS_BASE(unit)) +#define XOR_CONFIG_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x10 + ((chan) * 4))) +#define XOR_ACTIVATION_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x20 + ((chan) * 4))) + +/* XOR Engine Interrupt Register Map */ +#define XOR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x30)) +#define XOR_MASK_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x40)) +#define XOR_ERROR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x50)) +#define XOR_ERROR_ADDR_REG(unit) (MV_XOR_REGS_BASE(unit)+(0x60)) + +/* XOR Engine Descriptor Register Map */ +#define XOR_NEXT_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x200 + ((chan) * 4))) +#define XOR_CURR_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x210 + ((chan) * 4))) +#define XOR_BYTE_COUNT_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x220 + ((chan) * 4))) + +/* XOR Engine ECC/Mem_init Register Map */ +#define XOR_DST_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x2b0 + ((chan) * 4))) +#define XOR_BLOCK_SIZE_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x2c0 + ((chan) * 4))) +#define XOR_TIMER_MODE_CTRL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d0)) +#define XOR_TIMER_MODE_INIT_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d4)) +#define XOR_TIMER_MODE_CURR_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2d8)) +#define XOR_INIT_VAL_LOW_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2e0)) +#define XOR_INIT_VAL_HIGH_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x2e4)) + +/* XOR Engine Debug Register Map */ +#define XOR_DEBUG_REG(unit) (MV_XOR_REGS_BASE(unit) + (0x70)) + +/* XOR register fileds */ + +/* XOR Engine Channel Arbiter Register */ +#define XECAR_SLICE_OFFS(slice_num) (slice_num) +#define XECAR_SLICE_MASK(slice_num) (1 << (XECAR_SLICE_OFFS(slice_num))) + +/* XOR Engine [0..1] Configuration Registers */ +#define XEXCR_OPERATION_MODE_OFFS (0) +#define XEXCR_OPERATION_MODE_MASK (7 << XEXCR_OPERATION_MODE_OFFS) +#define XEXCR_OPERATION_MODE_XOR (0 << XEXCR_OPERATION_MODE_OFFS) +#define XEXCR_OPERATION_MODE_CRC (1 << XEXCR_OPERATION_MODE_OFFS) +#define XEXCR_OPERATION_MODE_DMA (2 << XEXCR_OPERATION_MODE_OFFS) +#define XEXCR_OPERATION_MODE_ECC (3 << XEXCR_OPERATION_MODE_OFFS) +#define XEXCR_OPERATION_MODE_MEM_INIT (4 << XEXCR_OPERATION_MODE_OFFS) + +#define XEXCR_SRC_BURST_LIMIT_OFFS (4) +#define XEXCR_SRC_BURST_LIMIT_MASK (7 << XEXCR_SRC_BURST_LIMIT_OFFS) +#define XEXCR_DST_BURST_LIMIT_OFFS (8) +#define XEXCR_DST_BURST_LIMIT_MASK (7 << XEXCR_DST_BURST_LIMIT_OFFS) +#define XEXCR_DRD_RES_SWP_OFFS (12) +#define XEXCR_DRD_RES_SWP_MASK (1 << XEXCR_DRD_RES_SWP_OFFS) +#define XEXCR_DWR_REQ_SWP_OFFS (13) +#define XEXCR_DWR_REQ_SWP_MASK (1 << XEXCR_DWR_REQ_SWP_OFFS) +#define XEXCR_DES_SWP_OFFS (14) +#define XEXCR_DES_SWP_MASK (1 << XEXCR_DES_SWP_OFFS) +#define XEXCR_REG_ACC_PROTECT_OFFS (15) +#define XEXCR_REG_ACC_PROTECT_MASK (1 << XEXCR_REG_ACC_PROTECT_OFFS) + +/* XOR Engine [0..1] Activation Registers */ +#define XEXACTR_XESTART_OFFS (0) +#define XEXACTR_XESTART_MASK (1 << XEXACTR_XESTART_OFFS) +#define XEXACTR_XESTOP_OFFS (1) +#define XEXACTR_XESTOP_MASK (1 << XEXACTR_XESTOP_OFFS) +#define XEXACTR_XEPAUSE_OFFS (2) +#define XEXACTR_XEPAUSE_MASK (1 << XEXACTR_XEPAUSE_OFFS) +#define XEXACTR_XERESTART_OFFS (3) +#define XEXACTR_XERESTART_MASK (1 << XEXACTR_XERESTART_OFFS) +#define XEXACTR_XESTATUS_OFFS (4) +#define XEXACTR_XESTATUS_MASK (3 << XEXACTR_XESTATUS_OFFS) +#define XEXACTR_XESTATUS_IDLE (0 << XEXACTR_XESTATUS_OFFS) +#define XEXACTR_XESTATUS_ACTIVE (1 << XEXACTR_XESTATUS_OFFS) +#define XEXACTR_XESTATUS_PAUSED (2 << XEXACTR_XESTATUS_OFFS) + +/* XOR Engine Interrupt Cause Register (XEICR) */ +#define XEICR_CHAN_OFFS 16 +#define XEICR_CAUSE_OFFS(chan) (chan * XEICR_CHAN_OFFS) +#define XEICR_CAUSE_MASK(chan, cause) (1 << (cause + XEICR_CAUSE_OFFS(chan))) +#define XEICR_COMP_MASK_ALL 0x000f000f +#define XEICR_COMP_MASK(chan) (0x000f << XEICR_CAUSE_OFFS(chan)) +#define XEICR_ERR_MASK 0x03800380 + +/* XOR Engine Error Cause Register (XEECR) */ +#define XEECR_ERR_TYPE_OFFS 0 +#define XEECR_ERR_TYPE_MASK (0x1f << XEECR_ERR_TYPE_OFFS) + +/* XOR Engine Error Address Register (XEEAR) */ +#define XEEAR_ERR_ADDR_OFFS (0) +#define XEEAR_ERR_ADDR_MASK (0xffffffff << XEEAR_ERR_ADDR_OFFS) + +/* XOR Engine [0..1] Next Descriptor Pointer Register */ +#define XEXNDPR_NEXT_DESC_PTR_OFFS (0) +#define XEXNDPR_NEXT_DESC_PTR_MASK (0xffffffff << \ + XEXNDPR_NEXT_DESC_PTR_OFFS) + +/* XOR Engine [0..1] Current Descriptor Pointer Register */ +#define XEXCDPR_CURRENT_DESC_PTR_OFFS (0) +#define XEXCDPR_CURRENT_DESC_PTR_MASK (0xffffffff << \ + XEXCDPR_CURRENT_DESC_PTR_OFFS) + +/* XOR Engine [0..1] Byte Count Register */ +#define XEXBCR_BYTE_CNT_OFFS (0) +#define XEXBCR_BYTE_CNT_MASK (0xffffffff << XEXBCR_BYTE_CNT_OFFS) + +/* XOR Engine [0..1] Destination Pointer Register */ +#define XEXDPR_DST_PTR_OFFS (0) +#define XEXDPR_DST_PTR_MASK (0xffffffff << XEXDPR_DST_PTR_OFFS) +#define XEXDPR_DST_PTR_XOR_MASK (0x3f) +#define XEXDPR_DST_PTR_DMA_MASK (0x1f) +#define XEXDPR_DST_PTR_CRC_MASK (0x1f) + +/* XOR Engine[0..1] Block Size Registers */ +#define XEXBSR_BLOCK_SIZE_OFFS (0) +#define XEXBSR_BLOCK_SIZE_MASK (0xffffffff << XEXBSR_BLOCK_SIZE_OFFS) +#define XEXBSR_BLOCK_SIZE_MIN_VALUE (128) +#define XEXBSR_BLOCK_SIZE_MAX_VALUE (0xffffffff) + +/* XOR Engine Timer Mode Control Register (XETMCR) */ +#define XETMCR_TIMER_EN_OFFS (0) +#define XETMCR_TIMER_EN_MASK (1 << XETMCR_TIMER_EN_OFFS) +#define XETMCR_TIMER_EN_ENABLE (1 << XETMCR_TIMER_EN_OFFS) +#define XETMCR_TIMER_EN_DISABLE (0 << XETMCR_TIMER_EN_OFFS) +#define XETMCR_SECTION_SIZE_CTRL_OFFS (8) +#define XETMCR_SECTION_SIZE_CTRL_MASK (0x1f << XETMCR_SECTION_SIZE_CTRL_OFFS) +#define XETMCR_SECTION_SIZE_MIN_VALUE (7) +#define XETMCR_SECTION_SIZE_MAX_VALUE (31) + +/* XOR Engine Timer Mode Initial Value Register (XETMIVR) */ +#define XETMIVR_TIMER_INIT_VAL_OFFS (0) +#define XETMIVR_TIMER_INIT_VAL_MASK (0xffffffff << \ + XETMIVR_TIMER_INIT_VAL_OFFS) + +/* XOR Engine Timer Mode Current Value Register (XETMCVR) */ +#define XETMCVR_TIMER_CRNT_VAL_OFFS (0) +#define XETMCVR_TIMER_CRNT_VAL_MASK (0xffffffff << \ + XETMCVR_TIMER_CRNT_VAL_OFFS) + +/* XOR Engine Initial Value Register Low (XEIVRL) */ +#define XEIVRL_INIT_VAL_L_OFFS (0) +#define XEIVRL_INIT_VAL_L_MASK (0xffffffff << XEIVRL_INIT_VAL_L_OFFS) + +/* XOR Engine Initial Value Register High (XEIVRH) */ +#define XEIVRH_INIT_VAL_H_OFFS (0) +#define XEIVRH_INIT_VAL_H_MASK (0xffffffff << XEIVRH_INIT_VAL_H_OFFS) + +/* XOR Engine Debug Register (XEDBR) */ +#define XEDBR_PARITY_ERR_INSR_OFFS (0) +#define XEDBR_PARITY_ERR_INSR_MASK (1 << XEDBR_PARITY_ERR_INSR_OFFS) +#define XEDBR_XBAR_ERR_INSR_OFFS (1) +#define XEDBR_XBAR_ERR_INSR_MASK (1 << XEDBR_XBAR_ERR_INSR_OFFS) + +/* XOR Engine address decode registers. */ +/* Maximum address decode windows */ +#define XOR_MAX_ADDR_DEC_WIN 8 +/* Maximum address arbiter windows */ +#define XOR_MAX_REMAP_WIN 4 + +/* XOR Engine Address Decoding Register Map */ +#define XOR_WINDOW_CTRL_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + \ + (0x240 + ((chan) * 4))) +#define XOR_BASE_ADDR_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \ + (0x250 + ((win_num) * 4))) +#define XOR_SIZE_MASK_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \ + (0x270 + ((win_num) * 4))) +#define XOR_HIGH_ADDR_REMAP_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \ + (0x290 + ((win_num) * 4))) +#define XOR_ADDR_OVRD_REG(unit, win_num) (MV_XOR_REGS_BASE(unit) + \ + (0x2a0 + ((win_num) * 4))) + +/* XOR Engine [0..1] Window Control Registers */ +#define XEXWCR_WIN_EN_OFFS(win_num) (win_num) +#define XEXWCR_WIN_EN_MASK(win_num) (1 << (XEXWCR_WIN_EN_OFFS(win_num))) +#define XEXWCR_WIN_EN_ENABLE(win_num) (1 << (XEXWCR_WIN_EN_OFFS(win_num))) +#define XEXWCR_WIN_EN_DISABLE(win_num) (0 << (XEXWCR_WIN_EN_OFFS(win_num))) + +#define XEXWCR_WIN_ACC_OFFS(win_num) ((2 * win_num) + 16) +#define XEXWCR_WIN_ACC_MASK(win_num) (3 << (XEXWCR_WIN_ACC_OFFS(win_num))) +#define XEXWCR_WIN_ACC_NO_ACC(win_num) (0 << (XEXWCR_WIN_ACC_OFFS(win_num))) +#define XEXWCR_WIN_ACC_RO(win_num) (1 << (XEXWCR_WIN_ACC_OFFS(win_num))) +#define XEXWCR_WIN_ACC_RW(win_num) (3 << (XEXWCR_WIN_ACC_OFFS(win_num))) + +/* XOR Engine Base Address Registers (XEBARx) */ +#define XEBARX_TARGET_OFFS (0) +#define XEBARX_TARGET_MASK (0xf << XEBARX_TARGET_OFFS) +#define XEBARX_ATTR_OFFS (8) +#define XEBARX_ATTR_MASK (0xff << XEBARX_ATTR_OFFS) +#define XEBARX_BASE_OFFS (16) +#define XEBARX_BASE_MASK (0xffff << XEBARX_BASE_OFFS) + +/* XOR Engine Size Mask Registers (XESMRx) */ +#define XESMRX_SIZE_MASK_OFFS (16) +#define XESMRX_SIZE_MASK_MASK (0xffff << XESMRX_SIZE_MASK_OFFS) +#define XOR_WIN_SIZE_ALIGN _64K + +/* XOR Engine High Address Remap Register (XEHARRx1) */ +#define XEHARRX_REMAP_OFFS (0) +#define XEHARRX_REMAP_MASK (0xffffffff << XEHARRX_REMAP_OFFS) + +#define XOR_OVERRIDE_CTRL_REG(chan) (MV_XOR_REGS_BASE(XOR_UNIT(chan)) + \ + (0x2a0 + ((XOR_CHAN(chan)) * 4))) + +/* XOR Engine [0..1] Address Override Control Register */ +#define XEXAOCR_OVR_EN_OFFS(target) (3 * target) +#define XEXAOCR_OVR_EN_MASK(target) (1 << (XEXAOCR_OVR_EN_OFFS(target))) +#define XEXAOCR_OVR_PTR_OFFS(target) ((3 * target) + 1) +#define XEXAOCR_OVR_PTR_MASK(target) (3 << (XEXAOCR_OVR_PTR_OFFS(target))) +#define XEXAOCR_OVR_BAR(win_num, target) (win_num << \ + (XEXAOCR_OVR_PTR_OFFS(target))) + +/* Maximum address override windows */ +#define XOR_MAX_OVERRIDE_WIN 4 + +#endif /* _XOR_REGS_h */ diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 3c9a9a0..481ee5e 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -59,6 +59,7 @@ libs-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/ libs-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/ libs-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/ libs-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += drivers/ddr/fsl/ +libs-$(CONFIG_SYS_MVEBU_DDR_A38X) += drivers/ddr/marvell/a38x/ libs-$(CONFIG_SYS_MVEBU_DDR_AXP) += drivers/ddr/marvell/axp/ libs-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/ libs-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/ -- cgit v0.10.2 From ad6ac7aa0002915bf2a285c85a8e96a0f8c2b6aa Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 8 Jun 2015 17:01:26 +0200 Subject: arm: mvebu: a38x: Use correct PEX register access macros Remove the incorrect PEX macros from the DDR header. And insert the correct ones in ctrl_pex.h instead. Signed-off-by: Stefan Roese diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h index 5032759..df395bf 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h @@ -19,6 +19,10 @@ #define MV_MISC_REGS_BASE MISC_REGS_OFFSET #define SOC_CTRL_REG (MV_MISC_REGS_BASE + 0x4) +#define PEX_IF_REGS_OFFSET(if) ((if) > 0 ? \ + (0x40000 + ((if) - 1) * 0x4000) : \ + 0x80000) +#define PEX_IF_REGS_BASE(if) (PEX_IF_REGS_OFFSET(if)) #define PEX_CAPABILITIES_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x60) #define PEX_LINK_CTRL_STATUS2_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x90) #define PEX_CTRL_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a00) diff --git a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h index 02d8c61..7500a72 100644 --- a/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h +++ b/drivers/ddr/marvell/a38x/ddr3_hws_hw_training_def.h @@ -421,11 +421,6 @@ #define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS) /* Power Management Clock Gating Control Register */ -#define MV_PEX_IF_REGS_OFFSET(pex_if) \ - (pex_if < 8 ? (0x40000 + ((pex_if) / 4) * 0x40000 + \ - ((pex_if) % 4) * 0x4000) : \ - (0x42000 + ((pex_if) % 8) * 0x40000)) -#define 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) (PEX_IF_REGS_BASE(if) + (reg)) -- cgit v0.10.2 From 9e30b31d20f0b793465d07f056b3d9885f578c0d Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 25 Mar 2015 13:35:15 +0100 Subject: arm: mvebu: db-88f6820: Add SPL support with DDR init code This patch adds SPL support for the Marvell DB-88F6820-GP board. With this change, the bin_hdr from the original Marvell U-boot is not needed any more on this board. The sources from bin_hdr (SERDES/PHY and DDR setup) are now integrated in mainline U-Boot. And this patch enables them for this board. Signed-off-by: Stefan Roese diff --git a/board/Marvell/db-88f6820-gp/README b/board/Marvell/db-88f6820-gp/README new file mode 100644 index 0000000..9bea5b3 --- /dev/null +++ b/board/Marvell/db-88f6820-gp/README @@ -0,0 +1,18 @@ +Update from original Marvell U-Boot to mainline U-Boot: +------------------------------------------------------- + +The resulting image including the SPL binary with the +full DDR setup is "u-boot-spl.kwb". + +To update the SPI NOR flash, please use the following +command: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf update 2000000 0 60000 + +Note that the original Marvell U-Boot seems to have +problems with the "sf update" command. This does not +work reliable. So here this command should be used: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf erase 0 60000;sf write 2000000 0 60000 diff --git a/board/Marvell/db-88f6820-gp/db-88f6820-gp.c b/board/Marvell/db-88f6820-gp/db-88f6820-gp.c index 51ac495..e661fa1 100644 --- a/board/Marvell/db-88f6820-gp/db-88f6820-gp.c +++ b/board/Marvell/db-88f6820-gp/db-88f6820-gp.c @@ -11,6 +11,8 @@ #include #include +#include "../drivers/ddr/marvell/a38x/ddr3_a38x_topology.h" + DECLARE_GLOBAL_DATA_PTR; #define BIT(nr) (1UL << (nr)) @@ -54,6 +56,35 @@ static struct marvell_io_exp io_exp[] = { { 0x21, 3, 0xC0 } /* Output Data, register#1 */ }; +/* + * Define the DDR layout / topology here in the board file. This will + * be used by the DDR3 init code in the SPL U-Boot version to configure + * the DDR3 controller. + */ +static struct hws_topology_map board_topology_map = { + 0x1, /* active interfaces */ + /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */ + { { { {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0} }, + SPEED_BIN_DDR_1866L, /* speed_bin */ + BUS_WIDTH_8, /* memory_width */ + MEM_4G, /* mem_size */ + DDR_FREQ_800, /* frequency */ + 0, 0, /* cas_l cas_wl */ + HWS_TEMP_LOW} }, /* temperature */ + 5, /* Num Of Bus Per Interface*/ + BUS_MASK_32BIT /* Busses mask */ +}; + +struct hws_topology_map *ddr3_get_topology_map(void) +{ + /* Return the board topology as defined in the board code */ + return &board_topology_map; +} + int board_early_init_f(void) { /* Configure MPP */ diff --git a/board/Marvell/db-88f6820-gp/kwbimage.cfg b/board/Marvell/db-88f6820-gp/kwbimage.cfg index e812454..cc05792 100644 --- a/board/Marvell/db-88f6820-gp/kwbimage.cfg +++ b/board/Marvell/db-88f6820-gp/kwbimage.cfg @@ -9,4 +9,4 @@ VERSION 1 BOOT_FROM spi # Binary Header (bin_hdr) with DDR3 training code -BINARY board/Marvell/db-88f6820-gp/binary.0 0000005b 00000068 +BINARY spl/u-boot-spl.bin 0000005b 00000068 diff --git a/configs/db-88f6820-gp_defconfig b/configs/db-88f6820-gp_defconfig index 569ddfd..0ff6706 100644 --- a/configs/db-88f6820-gp_defconfig +++ b/configs/db-88f6820-gp_defconfig @@ -1,3 +1,4 @@ +CONFIG_SPL=y CONFIG_ARM=y CONFIG_TARGET_DB_88F6820_GP=y # CONFIG_CMD_IMLS is not set diff --git a/include/configs/db-88f6820-gp.h b/include/configs/db-88f6820-gp.h index a429107..73b3236 100644 --- a/include/configs/db-88f6820-gp.h +++ b/include/configs/db-88f6820-gp.h @@ -11,6 +11,7 @@ * High Level Configuration Options (easy to change) */ #define CONFIG_ARMADA_XP /* SOC Family Name */ +#define CONFIG_ARMADA_38X #define CONFIG_DB_88F6820_GP /* Board target name for DDR training */ #define CONFIG_SYS_L2_PL310 @@ -108,6 +109,40 @@ "fdt_high=0x10000000\0" \ "initrd_high=0x10000000\0" +/* SPL */ +/* Defines for SPL */ +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_SIZE (140 << 10) +#define CONFIG_SPL_TEXT_BASE 0x40000030 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) + +#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) +#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) + +#define CONFIG_SYS_SPL_MALLOC_START (CONFIG_SPL_BSS_START_ADDR + \ + CONFIG_SPL_BSS_MAX_SIZE) +#define CONFIG_SYS_SPL_MALLOC_SIZE (16 << 10) + +#define CONFIG_SPL_STACK (0x40000000 + ((192 - 16) << 10)) +#define CONFIG_SPL_BOOTROM_SAVE (CONFIG_SPL_STACK + 4) + +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT + +/* 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_A38X +#define CONFIG_DDR3 + /* * mv-common.h should be defined after CMD configs since it used them * to enable certain macros -- cgit v0.10.2