aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/arch/arm/mach-mvebu
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/arch/arm/mach-mvebu
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/arch/arm/mach-mvebu')
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/.gitignore1
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/Kconfig314
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/Makefile77
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/arm64-common.c113
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/armada3700/Makefile5
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/armada3700/cpu.c386
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/armada8k/Makefile5
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/armada8k/cache_llc.S37
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/armada8k/cpu.c114
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/armada8k/dram.c54
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/cpu.c688
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/dram.c346
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/efuse.c265
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/gpio.c29
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/include/mach/config.h75
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/include/mach/cpu.h194
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/include/mach/efuse.h68
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/include/mach/fw_info.h18
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/include/mach/gpio.h8
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/include/mach/soc.h210
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/kwbimage.cfg.in12
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/lowlevel_spl.S69
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/mbus.c531
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/Makefile7
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c355
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h88
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c154
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c2173
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h250
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c169
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h64
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c277
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h351
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/axp/Makefile4
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/axp/board_env_spec.h261
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c1611
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c183
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h86
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/spl.c160
-rw-r--r--roms/u-boot/arch/arm/mach-mvebu/timer.c41
40 files changed, 9853 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/mach-mvebu/.gitignore b/roms/u-boot/arch/arm/mach-mvebu/.gitignore
new file mode 100644
index 000000000..775b9346b
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/.gitignore
@@ -0,0 +1 @@
+kwbimage.cfg
diff --git a/roms/u-boot/arch/arm/mach-mvebu/Kconfig b/roms/u-boot/arch/arm/mach-mvebu/Kconfig
new file mode 100644
index 000000000..cda65f747
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/Kconfig
@@ -0,0 +1,314 @@
+if ARCH_MVEBU
+
+config HAVE_MVEBU_EFUSE
+ bool
+ default n
+
+config ARMADA_32BIT
+ bool
+ select ARCH_MISC_INIT
+ select BOARD_EARLY_INIT_F
+ select CPU_V7A
+ select SPL_DM if SPL
+ select SPL_DM_SEQ_ALIAS if SPL
+ select SPL_OF_CONTROL if SPL
+ select SPL_SIMPLE_BUS if SPL
+ select SUPPORT_SPL
+ select TRANSLATION_OFFSET
+
+config ARMADA_64BIT
+ bool
+ select ARM64
+
+# ARMv7 SoCs...
+config ARMADA_375
+ bool
+ select ARMADA_32BIT
+
+config ARMADA_38X
+ bool
+ select ARMADA_32BIT
+ select HAVE_MVEBU_EFUSE
+
+config ARMADA_38X_HS_IMPEDANCE_THRESH
+ hex "Armada 38x USB 2.0 High-Speed Impedance Threshold (0x0 - 0x7)"
+ depends on ARMADA_38X
+ default 0x6
+ range 0x0 0x7
+
+config ARMADA_XP
+ bool
+ select ARMADA_32BIT
+
+# ARMv8 SoCs...
+config ARMADA_3700
+ bool
+ select ARM64
+
+# Armada 7K and 8K are very similar - use only one Kconfig symbol for both
+config ARMADA_8K
+ bool
+ select ARM64
+
+# Armada PLL frequency (used for NAND clock generation)
+config SYS_MVEBU_PLL_CLOCK
+ int
+ default "2000000000" if ARMADA_XP || ARMADA_3700 || ARMADA_8K || ARMADA_MSYS
+ default "1000000000" if ARMADA_38X || ARMADA_375
+
+# Armada XP/38x SoC types...
+config MV78230
+ bool
+ select ARMADA_XP
+
+config MV78260
+ bool
+ select ARMADA_XP
+ imply CMD_SATA
+
+config MV78460
+ bool
+ select ARMADA_XP
+
+config ARMADA_MSYS
+ bool
+ select ARMADA_32BIT
+
+config 98DX4251
+ bool
+ select ARMADA_MSYS
+
+config 98DX3336
+ bool
+ select ARMADA_MSYS
+
+config 98DX3236
+ bool
+ select ARMADA_MSYS
+
+config 88F6820
+ bool
+ select ARMADA_38X
+
+choice
+ prompt "Armada XP/375/38x/3700/7K/8K board select"
+ optional
+
+config TARGET_CLEARFOG
+ bool "Support ClearFog"
+ select 88F6820
+ select BOARD_LATE_INIT
+
+config TARGET_HELIOS4
+ bool "Support Helios4"
+ select 88F6820
+
+config TARGET_MVEBU_ARMADA_37XX
+ bool "Support Armada 37xx platforms"
+ select ARMADA_3700
+ imply SCSI
+
+config TARGET_DB_88F6720
+ bool "Support DB-88F6720 Armada 375"
+ select ARMADA_375
+
+config TARGET_DB_88F6820_GP
+ bool "Support DB-88F6820-GP"
+ select 88F6820
+
+config TARGET_DB_88F6820_AMC
+ bool "Support DB-88F6820-AMC"
+ select 88F6820
+
+config TARGET_TURRIS_OMNIA
+ bool "Support Turris Omnia"
+ select 88F6820
+ select BOARD_LATE_INIT
+ select DM_I2C
+ select I2C_MUX
+ select I2C_MUX_PCA954x
+ select SPL_I2C_MUX
+ select SYS_I2C_MVTWSI
+ select ATSHA204A
+
+config TARGET_TURRIS_MOX
+ bool "Support Turris Mox"
+ select ARMADA_3700
+
+config TARGET_MVEBU_ARMADA_8K
+ bool "Support Armada 7k/8k platforms"
+ select ARMADA_8K
+ select BOARD_LATE_INIT
+ imply SCSI
+
+config TARGET_OCTEONTX2_CN913x
+ bool "Support CN913x platforms"
+ select ARMADA_8K
+ imply BOARD_EARLY_INIT_R
+ select BOARD_LATE_INIT
+ imply SCSI
+
+config TARGET_DB_MV784MP_GP
+ bool "Support db-mv784mp-gp"
+ select MV78460
+
+config TARGET_DS414
+ bool "Support Synology DS414"
+ select MV78230
+
+config TARGET_MAXBCM
+ bool "Support maxbcm"
+ select MV78460
+
+config TARGET_THEADORABLE
+ bool "Support theadorable Armada XP"
+ select BOARD_LATE_INIT if USB
+ select MV78260
+ imply CMD_SATA
+
+config TARGET_CONTROLCENTERDC
+ bool "Support CONTROLCENTERDC"
+ select 88F6820
+
+config TARGET_X530
+ bool "Support Allied Telesis x530"
+ select 88F6820
+
+config TARGET_DB_XC3_24G4XG
+ bool "Support DB-XC3-24G4XG"
+ select 98DX3336
+
+config TARGET_CRS3XX_98DX3236
+ bool "Support CRS3XX-98DX3236"
+ select 98DX3236
+
+endchoice
+
+config SYS_BOARD
+ default "clearfog" if TARGET_CLEARFOG
+ default "helios4" if TARGET_HELIOS4
+ default "mvebu_armada-37xx" if TARGET_MVEBU_ARMADA_37XX
+ default "db-88f6720" if TARGET_DB_88F6720
+ default "db-88f6820-gp" if TARGET_DB_88F6820_GP
+ default "db-88f6820-amc" if TARGET_DB_88F6820_AMC
+ default "turris_omnia" if TARGET_TURRIS_OMNIA
+ default "turris_mox" if TARGET_TURRIS_MOX
+ default "mvebu_armada-8k" if TARGET_MVEBU_ARMADA_8K
+ default "octeontx2_cn913x" if TARGET_OCTEONTX2_CN913x
+ default "db-mv784mp-gp" if TARGET_DB_MV784MP_GP
+ default "ds414" if TARGET_DS414
+ default "maxbcm" if TARGET_MAXBCM
+ default "theadorable" if TARGET_THEADORABLE
+ default "a38x" if TARGET_CONTROLCENTERDC
+ default "x530" if TARGET_X530
+ default "db-xc3-24g4xg" if TARGET_DB_XC3_24G4XG
+ default "crs3xx-98dx3236" if TARGET_CRS3XX_98DX3236
+
+config SYS_CONFIG_NAME
+ default "clearfog" if TARGET_CLEARFOG
+ default "helios4" if TARGET_HELIOS4
+ default "mvebu_armada-37xx" if TARGET_MVEBU_ARMADA_37XX
+ default "db-88f6720" if TARGET_DB_88F6720
+ default "db-88f6820-gp" if TARGET_DB_88F6820_GP
+ default "db-88f6820-amc" if TARGET_DB_88F6820_AMC
+ default "mvebu_armada-8k" if TARGET_MVEBU_ARMADA_8K
+ default "mvebu_armada-8k" if TARGET_OCTEONTX2_CN913x
+ default "db-mv784mp-gp" if TARGET_DB_MV784MP_GP
+ default "ds414" if TARGET_DS414
+ default "maxbcm" if TARGET_MAXBCM
+ default "theadorable" if TARGET_THEADORABLE
+ default "turris_omnia" if TARGET_TURRIS_OMNIA
+ default "turris_mox" if TARGET_TURRIS_MOX
+ default "controlcenterdc" if TARGET_CONTROLCENTERDC
+ default "x530" if TARGET_X530
+ default "db-xc3-24g4xg" if TARGET_DB_XC3_24G4XG
+ default "crs3xx-98dx3236" if TARGET_CRS3XX_98DX3236
+
+config SYS_VENDOR
+ default "Marvell" if TARGET_DB_MV784MP_GP
+ default "Marvell" if TARGET_MVEBU_ARMADA_37XX
+ default "Marvell" if TARGET_DB_88F6720
+ default "Marvell" if TARGET_DB_88F6820_GP
+ default "Marvell" if TARGET_DB_88F6820_AMC
+ default "Marvell" if TARGET_MVEBU_ARMADA_8K
+ default "Marvell" if TARGET_OCTEONTX2_CN913x
+ default "Marvell" if TARGET_DB_XC3_24G4XG
+ default "Marvell" if TARGET_MVEBU_DB_88F7040
+ default "solidrun" if TARGET_CLEARFOG
+ default "kobol" if TARGET_HELIOS4
+ default "Synology" if TARGET_DS414
+ default "CZ.NIC" if TARGET_TURRIS_OMNIA
+ default "CZ.NIC" if TARGET_TURRIS_MOX
+ default "gdsys" if TARGET_CONTROLCENTERDC
+ default "alliedtelesis" if TARGET_X530
+ default "mikrotik" if TARGET_CRS3XX_98DX3236
+
+config SYS_SOC
+ default "mvebu"
+
+choice
+ prompt "Boot method"
+ depends on SPL
+
+config MVEBU_SPL_BOOT_DEVICE_SPI
+ bool "SPI NOR flash"
+ imply ENV_IS_IN_SPI_FLASH
+ select SPL_DM_SPI
+ select SPL_SPI_FLASH_SUPPORT
+ select SPL_SPI_LOAD
+ select SPL_SPI_SUPPORT
+
+config MVEBU_SPL_BOOT_DEVICE_MMC
+ bool "SDIO/MMC card"
+ imply ENV_IS_IN_MMC
+ # GPIO needed for eMMC/SD card presence detection
+ select SPL_DM_GPIO
+ select SPL_DM_MMC
+ select SPL_GPIO_SUPPORT
+ select SPL_LIBDISK_SUPPORT
+ select SPL_MMC_SUPPORT
+
+config MVEBU_SPL_BOOT_DEVICE_SATA
+ bool "SATA"
+ select SPL_SATA_SUPPORT
+ select SPL_LIBDISK_SUPPORT
+
+config MVEBU_SPL_BOOT_DEVICE_UART
+ bool "UART"
+
+endchoice
+
+config MVEBU_EFUSE
+ bool "Enable eFuse support"
+ default n
+ depends on HAVE_MVEBU_EFUSE
+ help
+ Enable support for reading and writing eFuses on mvebu SoCs.
+
+config MVEBU_EFUSE_FAKE
+ bool "Fake eFuse access (dry run)"
+ default n
+ depends on MVEBU_EFUSE
+ help
+ This enables a "dry run" mode where eFuses are not really programmed.
+ Instead the eFuse accesses are emulated by writing to and reading
+ from a memory block.
+ This is can be used for testing prog scripts.
+
+config SECURED_MODE_IMAGE
+ bool "Build image for trusted boot"
+ default false
+ depends on 88F6820
+ help
+ Build an image that employs the ARMADA SoC's trusted boot framework
+ for securely booting images.
+
+config SECURED_MODE_CSK_INDEX
+ int "Index of active CSK"
+ default 0
+ depends on SECURED_MODE_IMAGE
+
+source "board/solidrun/clearfog/Kconfig"
+source "board/kobol/helios4/Kconfig"
+
+endif
diff --git a/roms/u-boot/arch/arm/mach-mvebu/Makefile b/roms/u-boot/arch/arm/mach-mvebu/Makefile
new file mode 100644
index 000000000..7e9c206ed
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/Makefile
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2014-2016 Stefan Roese <sr@denx.de>
+
+ifdef CONFIG_ARM64
+
+obj-$(CONFIG_ARMADA_3700) += armada3700/
+obj-$(CONFIG_ARMADA_8K) += armada8k/
+obj-y += arm64-common.o
+
+else # CONFIG_ARM64
+
+ifdef CONFIG_ARCH_KIRKWOOD
+
+obj-y = dram.o
+obj-y += gpio.o
+obj-y += mbus.o
+obj-y += timer.o
+
+else # CONFIG_ARCH_KIRKWOOD
+
+obj-y = cpu.o
+obj-y += dram.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o
+obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o
+obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o
+obj-$(CONFIG_ARMADA_MSYS) += ../../../drivers/ddr/marvell/axp/xor.o
+obj-$(CONFIG_MVEBU_EFUSE) += efuse.o
+
+extra-y += kwbimage.cfg
+
+KWB_REPLACE += BOOT_FROM
+ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI),)
+ KWB_CFG_BOOT_FROM=spi
+endif
+ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_MMC),)
+ KWB_CFG_BOOT_FROM=sdio
+endif
+ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_SATA),)
+ KWB_CFG_BOOT_FROM=sata
+endif
+ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_UART),)
+ KWB_CFG_BOOT_FROM=uart
+endif
+
+ifneq ($(CONFIG_SECURED_MODE_IMAGE),)
+KWB_REPLACE += CSK_INDEX
+KWB_CFG_CSK_INDEX = $(CONFIG_SECURED_MODE_CSK_INDEX)
+
+KWB_REPLACE += SEC_BOOT_DEV
+KWB_CFG_SEC_BOOT_DEV=$(patsubst "%",%, \
+ $(if $(findstring BOOT_SPI_NOR_FLASH,$(CONFIG_SPL_BOOT_DEVICE)),0x34) \
+ $(if $(findstring BOOT_SDIO_MMC_CARD,$(CONFIG_SPL_BOOT_DEVICE)),0x31) \
+ )
+
+KWB_REPLACE += SEC_FUSE_DUMP
+KWB_CFG_SEC_FUSE_DUMP = a38x
+endif
+
+$(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
+ include/config/auto.conf
+ $(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \
+ <$< >$(dir $@)$(@F)
+
+endif # CONFIG_SPL_BUILD
+obj-y += gpio.o
+obj-y += mbus.o
+obj-y += timer.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
+obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o
+
+obj-$(CONFIG_ARMADA_38X) += serdes/a38x/
+obj-$(CONFIG_ARMADA_XP) += serdes/axp/
+
+endif # CONFIG_ARCH_KIRKWOOD
+endif # CONFIG_ARM64
diff --git a/roms/u-boot/arch/arm/mach-mvebu/arm64-common.c b/roms/u-boot/arch/arm/mach-mvebu/arm64-common.c
new file mode 100644
index 000000000..fa687d8ab
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/arm64-common.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <init.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/ptrace.h>
+#include <linux/libfdt.h>
+#include <linux/sizes.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <asm/armv8/mmu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Not all memory is mapped in the MMU. So we need to restrict the
+ * memory size so that U-Boot does not try to access it. Also, the
+ * internal registers are located at 0xf000.0000 - 0xffff.ffff.
+ * Currently only 2GiB are mapped for system memory. This is what
+ * we pass to the U-Boot subsystem here.
+ */
+#define USABLE_RAM_SIZE 0x80000000
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+ if (gd->ram_size > USABLE_RAM_SIZE)
+ return USABLE_RAM_SIZE;
+
+ return gd->ram_size;
+}
+
+/*
+ * On ARMv8, MBus is not configured in U-Boot. To enable compilation
+ * of the already implemented drivers, lets add a dummy version of
+ * this function so that linking does not fail.
+ */
+const struct mbus_dram_target_info *mvebu_mbus_dram_info(void)
+{
+ return NULL;
+}
+
+__weak int dram_init_banksize(void)
+{
+ if (CONFIG_IS_ENABLED(ARMADA_8K))
+ return a8k_dram_init_banksize();
+ else if (CONFIG_IS_ENABLED(ARMADA_3700))
+ return a3700_dram_init_banksize();
+ else
+ return fdtdec_setup_memory_banksize();
+}
+
+__weak int dram_init(void)
+{
+ if (CONFIG_IS_ENABLED(ARMADA_8K)) {
+ gd->ram_size = a8k_dram_scan_ap_sz();
+ if (gd->ram_size != 0)
+ return 0;
+ }
+
+ if (CONFIG_IS_ENABLED(ARMADA_3700))
+ return a3700_dram_init();
+
+ if (fdtdec_setup_mem_size_base() != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+int arch_cpu_init(void)
+{
+ /* Nothing to do (yet) */
+ return 0;
+}
+
+int arch_early_init_r(void)
+{
+ struct udevice *dev;
+ int ret;
+ int i;
+
+ /*
+ * Loop over all MISC uclass drivers to call the comphy code
+ * and init all CP110 devices enabled in the DT
+ */
+ i = 0;
+ while (1) {
+ /* Call the comphy code via the MISC uclass driver */
+ ret = uclass_get_device(UCLASS_MISC, i++, &dev);
+
+ /* We're done, once no further CP110 device is found */
+ if (ret)
+ break;
+ }
+
+ /* Cause the SATA device to do its early init */
+ uclass_first_device(UCLASS_AHCI, &dev);
+
+#ifdef CONFIG_DM_PCI
+ /* Trigger PCIe devices detection */
+ pci_init();
+#endif
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/armada3700/Makefile b/roms/u-boot/arch/arm/mach-mvebu/armada3700/Makefile
new file mode 100644
index 000000000..031b3e854
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/armada3700/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2016 Stefan Roese <sr@denx.de>
+
+obj-y = cpu.o
diff --git a/roms/u-boot/arch/arm/mach-mvebu/armada3700/cpu.c b/roms/u-boot/arch/arm/mach-mvebu/armada3700/cpu.c
new file mode 100644
index 000000000..9aec0ce9a
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/armada3700/cpu.c
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ * Copyright (C) 2020 Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <linux/bitops.h>
+#include <linux/libfdt.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <asm/armv8/mmu.h>
+#include <sort.h>
+
+/* Armada 3700 */
+#define MVEBU_GPIO_NB_REG_BASE (MVEBU_REGISTER(0x13800))
+
+#define MVEBU_TEST_PIN_LATCH_N (MVEBU_GPIO_NB_REG_BASE + 0x8)
+#define MVEBU_XTAL_MODE_MASK BIT(9)
+#define MVEBU_XTAL_MODE_OFFS 9
+#define MVEBU_XTAL_CLOCK_25MHZ 0x0
+#define MVEBU_XTAL_CLOCK_40MHZ 0x1
+
+#define MVEBU_NB_WARM_RST_REG (MVEBU_GPIO_NB_REG_BASE + 0x40)
+#define MVEBU_NB_WARM_RST_MAGIC_NUM 0x1d1e
+
+/* Armada 3700 CPU Address Decoder registers */
+#define MVEBU_CPU_DEC_WIN_REG_BASE (size_t)(MVEBU_REGISTER(0xcf00))
+#define MVEBU_CPU_DEC_WIN_CTRL(w) \
+ (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
+#define MVEBU_CPU_DEC_WIN_CTRL_EN BIT(0)
+#define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
+#define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
+#define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
+#define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
+#define MVEBU_CPU_DEC_WIN_SIZE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
+#define MVEBU_CPU_DEC_WIN_BASE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
+#define MVEBU_CPU_DEC_WIN_REMAP(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
+#define MVEBU_CPU_DEC_WIN_GRANULARITY 16
+#define MVEBU_CPU_DEC_WINS 5
+
+#define MAX_MEM_MAP_REGIONS (MVEBU_CPU_DEC_WINS + 2)
+
+#define A3700_PTE_BLOCK_NORMAL \
+ (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
+#define A3700_PTE_BLOCK_DEVICE \
+ (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
+ {
+ /*
+ * SRAM, MMIO regions
+ * Don't remove this, a3700_build_mem_map needs it.
+ */
+ .phys = SOC_REGS_PHY_BASE,
+ .virt = SOC_REGS_PHY_BASE,
+ .size = 0x02000000UL, /* 32MiB internal registers */
+ .attrs = A3700_PTE_BLOCK_DEVICE
+ },
+};
+
+struct mm_region *mem_map = mvebu_mem_map;
+
+static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
+{
+ u32 reg;
+
+ reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
+ if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
+ return -1;
+
+ if (tgt) {
+ reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
+ reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
+ *tgt = reg;
+ }
+
+ if (base) {
+ reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
+ *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
+ }
+
+ if (size) {
+ /*
+ * Window size is encoded as the number of 1s from LSB to MSB,
+ * followed by 0s. The number of 1s specifies the size in 64 KiB
+ * granularity.
+ */
+ reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
+ *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
+ }
+
+ return 0;
+}
+
+/*
+ * Builds mem_map according to CPU Address Decoder settings, which were set by
+ * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
+ */
+static void build_mem_map(void)
+{
+ int win, region;
+
+ region = 1;
+ for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
+ u32 base, tgt, size;
+ u64 attrs;
+
+ /* skip disabled windows */
+ if (get_cpu_dec_win(win, &tgt, &base, &size))
+ continue;
+
+ if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
+ attrs = A3700_PTE_BLOCK_NORMAL;
+ else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
+ attrs = A3700_PTE_BLOCK_DEVICE;
+ else
+ /* skip windows with other targets */
+ continue;
+
+ mvebu_mem_map[region].phys = base;
+ mvebu_mem_map[region].virt = base;
+ mvebu_mem_map[region].size = size;
+ mvebu_mem_map[region].attrs = attrs;
+ ++region;
+ }
+
+ /* add list terminator */
+ mvebu_mem_map[region].size = 0;
+ mvebu_mem_map[region].attrs = 0;
+}
+
+void enable_caches(void)
+{
+ build_mem_map();
+
+ icache_enable();
+ dcache_enable();
+}
+
+int a3700_dram_init(void)
+{
+ int win;
+
+ gd->ram_size = 0;
+ for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
+ u32 base, tgt, size;
+
+ /* skip disabled windows */
+ if (get_cpu_dec_win(win, &tgt, &base, &size))
+ continue;
+
+ /* skip non-DRAM windows */
+ if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
+ continue;
+
+ /*
+ * It is possible that one image was built for boards with
+ * different RAM sizes, for example 512 MiB and 1 GiB.
+ * We therefore try to determine the actual RAM size in the
+ * window with get_ram_size.
+ */
+ gd->ram_size += get_ram_size((void *)(size_t)base, size);
+ }
+
+ return 0;
+}
+
+struct a3700_dram_window {
+ size_t base, size;
+};
+
+static int dram_win_cmp(const void *a, const void *b)
+{
+ size_t ab, bb;
+
+ ab = ((const struct a3700_dram_window *)a)->base;
+ bb = ((const struct a3700_dram_window *)b)->base;
+
+ if (ab < bb)
+ return -1;
+ else if (ab > bb)
+ return 1;
+ else
+ return 0;
+}
+
+int a3700_dram_init_banksize(void)
+{
+ struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
+ int bank, win, ndram_wins;
+ u32 last_end;
+ size_t size;
+
+ ndram_wins = 0;
+ for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
+ u32 base, tgt, size;
+
+ /* skip disabled windows */
+ if (get_cpu_dec_win(win, &tgt, &base, &size))
+ continue;
+
+ /* skip non-DRAM windows */
+ if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
+ continue;
+
+ dram_wins[win].base = base;
+ dram_wins[win].size = size;
+ ++ndram_wins;
+ }
+
+ qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
+
+ bank = 0;
+ last_end = -1;
+
+ for (win = 0; win < ndram_wins; ++win) {
+ /* again determining actual RAM size as in a3700_dram_init */
+ size = get_ram_size((void *)dram_wins[win].base,
+ dram_wins[win].size);
+
+ /*
+ * Check if previous window ends as the current starts. If yes,
+ * merge these windows into one "bank". This is possible by this
+ * simple check thanks to mem_map regions being qsorted in
+ * build_mem_map.
+ */
+ if (last_end == dram_wins[win].base) {
+ gd->bd->bi_dram[bank - 1].size += size;
+ last_end += size;
+ } else {
+ if (bank == CONFIG_NR_DRAM_BANKS) {
+ printf("Need more CONFIG_NR_DRAM_BANKS\n");
+ return -ENOBUFS;
+ }
+
+ gd->bd->bi_dram[bank].start = dram_wins[win].base;
+ gd->bd->bi_dram[bank].size = size;
+ last_end = dram_wins[win].base + size;
+ ++bank;
+ }
+ }
+
+ /*
+ * If there is more place for DRAM BANKS definitions than needed, fill
+ * the rest with zeros.
+ */
+ for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
+ gd->bd->bi_dram[bank].start = 0;
+ gd->bd->bi_dram[bank].size = 0;
+ }
+
+ return 0;
+}
+
+static u32 find_pcie_window_base(void)
+{
+ int win;
+
+ for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
+ u32 base, tgt;
+
+ /* skip disabled windows */
+ if (get_cpu_dec_win(win, &tgt, &base, NULL))
+ continue;
+
+ if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
+ return base;
+ }
+
+ return -1;
+}
+
+static int fdt_setprop_inplace_u32_partial(void *blob, int node,
+ const char *name,
+ u32 idx, u32 val)
+{
+ val = cpu_to_fdt32(val);
+
+ return fdt_setprop_inplace_namelen_partial(blob, node, name,
+ strlen(name),
+ idx * sizeof(u32),
+ &val, sizeof(u32));
+}
+
+int a3700_fdt_fix_pcie_regions(void *blob)
+{
+ int acells, pacells, scells;
+ u32 base, fix_offset;
+ const u32 *ranges;
+ int node, pnode;
+ int ret, i, len;
+
+ base = find_pcie_window_base();
+ if (base == -1)
+ return -ENOENT;
+
+ node = fdt_node_offset_by_compatible(blob, -1, "marvell,armada-3700-pcie");
+ if (node < 0)
+ return node;
+
+ ranges = fdt_getprop(blob, node, "ranges", &len);
+ if (!ranges || len % sizeof(u32))
+ return -ENOENT;
+
+ /*
+ * The "ranges" property is an array of
+ * { <child address> <parent address> <size in child address space> }
+ *
+ * All 3 elements can span a diffent number of cells. Fetch their sizes.
+ */
+ pnode = fdt_parent_offset(blob, node);
+ acells = fdt_address_cells(blob, node);
+ pacells = fdt_address_cells(blob, pnode);
+ scells = fdt_size_cells(blob, node);
+
+ /* Child PCI addresses always use 3 cells */
+ if (acells != 3)
+ return -ENOENT;
+
+ /* Calculate fixup offset from first child address (in last cell) */
+ fix_offset = base - fdt32_to_cpu(ranges[2]);
+
+ /*
+ * Fix address (last cell) of each child address and each parent
+ * address
+ */
+ for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) {
+ int idx;
+
+ /* fix child address */
+ idx = i + acells - 1;
+ ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
+ fdt32_to_cpu(ranges[idx]) +
+ fix_offset);
+ if (ret)
+ return ret;
+
+ /* fix parent address */
+ idx = i + acells + pacells - 1;
+ ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
+ fdt32_to_cpu(ranges[idx]) +
+ fix_offset);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void reset_cpu(void)
+{
+ /*
+ * Write magic number of 0x1d1e to North Bridge Warm Reset register
+ * to trigger warm reset
+ */
+ writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
+}
+
+/*
+ * get_ref_clk
+ *
+ * return: reference clock in MHz (25 or 40)
+ */
+u32 get_ref_clk(void)
+{
+ u32 regval;
+
+ regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
+ MVEBU_XTAL_MODE_OFFS;
+
+ if (regval == MVEBU_XTAL_CLOCK_25MHZ)
+ return 25;
+ else
+ return 40;
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/armada8k/Makefile b/roms/u-boot/arch/arm/mach-mvebu/armada8k/Makefile
new file mode 100644
index 000000000..0a4756717
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/armada8k/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2016 Stefan Roese <sr@denx.de>
+
+obj-y = cpu.o cache_llc.o dram.o
diff --git a/roms/u-boot/arch/arm/mach-mvebu/armada8k/cache_llc.S b/roms/u-boot/arch/arm/mach-mvebu/armada8k/cache_llc.S
new file mode 100644
index 000000000..d78b33cbf
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/armada8k/cache_llc.S
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ */
+
+#include <asm/arch-armada8k/cache_llc.h>
+#include <linux/linkage.h>
+
+/*
+ * int __asm_flush_l3_dcache
+ *
+ * flush Armada-8K last level cache.
+ *
+ */
+ENTRY(__asm_flush_l3_dcache)
+ /* flush cache */
+ mov x0, #LLC_BASE_ADDR
+ add x0, x0, #LLC_FLUSH_BY_WAY
+ movk x0, #MVEBU_A8K_REGS_BASE_MSB, lsl #16
+ mov w1, #LLC_WAY_MASK
+ str w1, [x0]
+ /* sync cache */
+ mov x0, #LLC_BASE_ADDR
+ add x0, x0, #LLC_CACHE_SYNC
+ movk x0, #MVEBU_A8K_REGS_BASE_MSB, lsl #16
+ str wzr, [x0]
+ /* check that cache sync completed */
+ mov x0, #LLC_BASE_ADDR
+ add x0, x0, #LLC_CACHE_SYNC_COMPLETE
+ movk x0, #MVEBU_A8K_REGS_BASE_MSB, lsl #16
+1: ldr w1, [x0]
+ and w1, w1, #LLC_CACHE_SYNC_MASK
+ cbnz w1, 1b
+ /* return success */
+ mov x0, #0
+ ret
+ENDPROC(__asm_flush_l3_dcache)
diff --git a/roms/u-boot/arch/arm/mach-mvebu/armada8k/cpu.c b/roms/u-boot/arch/arm/mach-mvebu/armada8k/cpu.c
new file mode 100644
index 000000000..939abce00
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/armada8k/cpu.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <linux/libfdt.h>
+#include <linux/sizes.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <asm/armv8/mmu.h>
+#include <mach/fw_info.h>
+
+/* Armada 7k/8k */
+#define MVEBU_RFU_BASE (MVEBU_REGISTER(0x6f0000))
+#define RFU_GLOBAL_SW_RST (MVEBU_RFU_BASE + 0x84)
+#define RFU_SW_RESET_OFFSET 0
+
+#define SAR0_REG (MVEBU_REGISTER(0x2400200))
+#define BOOT_MODE_MASK 0x3f
+#define BOOT_MODE_OFFSET 4
+
+static struct mm_region mvebu_mem_map[] = {
+ /* Armada 80x0 memory regions include the CP1 (slave) units */
+ {
+ /* RAM 0-64MB */
+ .phys = 0x0UL,
+ .virt = 0x0UL,
+ .size = ATF_REGION_START,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ },
+ /* ATF and TEE region 0x4000000-0x5400000 not mapped */
+ {
+ /* RAM 66MB-2GB */
+ .phys = ATF_REGION_END,
+ .virt = ATF_REGION_END,
+ .size = SZ_2G,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ },
+ {
+ /* MMIO regions */
+ .phys = MMIO_REGS_PHY_BASE,
+ .virt = MMIO_REGS_PHY_BASE,
+ .size = SZ_1G,
+
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE
+ },
+ {
+ 0,
+ }
+};
+
+struct mm_region *mem_map = mvebu_mem_map;
+
+void enable_caches(void)
+{
+ icache_enable();
+ dcache_enable();
+}
+
+void reset_cpu(void)
+{
+ u32 reg;
+
+ reg = readl(RFU_GLOBAL_SW_RST);
+ reg &= ~(1 << RFU_SW_RESET_OFFSET);
+ writel(reg, RFU_GLOBAL_SW_RST);
+}
+
+/*
+ * TODO - implement this functionality using platform
+ * clock driver once it gets available
+ * Return NAND clock in Hz
+ */
+u32 mvebu_get_nand_clock(void)
+{
+ unsigned long NAND_FLASH_CLK_CTRL = 0xF2440700UL;
+ unsigned long NF_CLOCK_SEL_MASK = 0x1;
+ u32 reg;
+
+ reg = readl(NAND_FLASH_CLK_CTRL);
+ if (reg & NF_CLOCK_SEL_MASK)
+ return 400 * 1000000;
+ else
+ return 250 * 1000000;
+}
+
+int mmc_get_env_dev(void)
+{
+ u32 reg;
+ unsigned int boot_mode;
+
+ reg = readl(SAR0_REG);
+ boot_mode = (reg >> BOOT_MODE_OFFSET) & BOOT_MODE_MASK;
+
+ switch (boot_mode) {
+ case 0x28:
+ case 0x2a:
+ return 0;
+ case 0x29:
+ case 0x2b:
+ return 1;
+ }
+
+ return CONFIG_SYS_MMC_ENV_DEV;
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/armada8k/dram.c b/roms/u-boot/arch/arm/mach-mvebu/armada8k/dram.c
new file mode 100644
index 000000000..bab375e18
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/armada8k/dram.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <asm/global_data.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MV_SIP_DRAM_SIZE 0x82000010
+
+u64 a8k_dram_scan_ap_sz(void)
+{
+ struct pt_regs pregs;
+
+ pregs.regs[0] = MV_SIP_DRAM_SIZE;
+ pregs.regs[1] = SOC_REGS_PHY_BASE;
+ smc_call(&pregs);
+
+ return pregs.regs[0];
+}
+
+int a8k_dram_init_banksize(void)
+{
+ /*
+ * The firmware (ATF) leaves a 1G whole above the 3G mark for IO
+ * devices. Higher RAM is mapped at 4G.
+ *
+ * Config 2 DRAM banks:
+ * Bank 0 - max size 4G - 1G
+ * Bank 1 - ram size - 4G + 1G
+ */
+ phys_size_t max_bank0_size = SZ_4G - SZ_1G;
+
+ gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+ if (gd->ram_size <= max_bank0_size) {
+ gd->bd->bi_dram[0].size = gd->ram_size;
+ return 0;
+ }
+
+ gd->bd->bi_dram[0].size = max_bank0_size;
+ if (CONFIG_NR_DRAM_BANKS > 1) {
+ gd->bd->bi_dram[1].start = SZ_4G;
+ gd->bd->bi_dram[1].size = gd->ram_size - max_bank0_size;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/cpu.c b/roms/u-boot/arch/arm/mach-mvebu/cpu.c
new file mode 100644
index 000000000..0b935c46f
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/cpu.c
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014-2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <ahci.h>
+#include <cpu_func.h>
+#include <init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/mbus.h>
+#include <asm/io.h>
+#include <asm/pl310.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <sdhci.h>
+
+#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3))
+#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
+
+static struct mbus_win windows[] = {
+ /* SPI */
+ { MBUS_SPI_BASE, MBUS_SPI_SIZE,
+ CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPIFLASH },
+
+ /* NOR */
+ { MBUS_BOOTROM_BASE, MBUS_BOOTROM_SIZE,
+ CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_BOOTROM },
+
+#ifdef CONFIG_ARMADA_MSYS
+ /* DFX */
+ { MBUS_DFX_BASE, MBUS_DFX_SIZE, CPU_TARGET_DFX, 0 },
+#endif
+};
+
+void lowlevel_init(void)
+{
+ /*
+ * Dummy implementation, we only need LOWLEVEL_INIT
+ * on Armada to configure CP15 in start.S / cpu_init_cp15()
+ */
+}
+
+void reset_cpu(void)
+{
+ struct mvebu_system_registers *reg =
+ (struct mvebu_system_registers *)MVEBU_SYSTEM_REG_BASE;
+
+ writel(readl(&reg->rstoutn_mask) | 1, &reg->rstoutn_mask);
+ writel(readl(&reg->sys_soft_rst) | 1, &reg->sys_soft_rst);
+ while (1)
+ ;
+}
+
+int mvebu_soc_family(void)
+{
+ u16 devid = (readl(MVEBU_REG_PCIE_DEVID) >> 16) & 0xffff;
+
+ switch (devid) {
+ case SOC_MV78230_ID:
+ case SOC_MV78260_ID:
+ case SOC_MV78460_ID:
+ return MVEBU_SOC_AXP;
+
+ case SOC_88F6720_ID:
+ return MVEBU_SOC_A375;
+
+ case SOC_88F6810_ID:
+ case SOC_88F6820_ID:
+ case SOC_88F6828_ID:
+ return MVEBU_SOC_A38X;
+
+ case SOC_98DX3236_ID:
+ case SOC_98DX3336_ID:
+ case SOC_98DX4251_ID:
+ return MVEBU_SOC_MSYS;
+ }
+
+ return MVEBU_SOC_UNKNOWN;
+}
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+
+#if defined(CONFIG_ARMADA_375)
+/* SAR frequency values for Armada 375 */
+static const struct sar_freq_modes sar_freq_tab[] = {
+ { 0, 0x0, 266, 133, 266 },
+ { 1, 0x0, 333, 167, 167 },
+ { 2, 0x0, 333, 167, 222 },
+ { 3, 0x0, 333, 167, 333 },
+ { 4, 0x0, 400, 200, 200 },
+ { 5, 0x0, 400, 200, 267 },
+ { 6, 0x0, 400, 200, 400 },
+ { 7, 0x0, 500, 250, 250 },
+ { 8, 0x0, 500, 250, 334 },
+ { 9, 0x0, 500, 250, 500 },
+ { 10, 0x0, 533, 267, 267 },
+ { 11, 0x0, 533, 267, 356 },
+ { 12, 0x0, 533, 267, 533 },
+ { 13, 0x0, 600, 300, 300 },
+ { 14, 0x0, 600, 300, 400 },
+ { 15, 0x0, 600, 300, 600 },
+ { 16, 0x0, 666, 333, 333 },
+ { 17, 0x0, 666, 333, 444 },
+ { 18, 0x0, 666, 333, 666 },
+ { 19, 0x0, 800, 400, 267 },
+ { 20, 0x0, 800, 400, 400 },
+ { 21, 0x0, 800, 400, 534 },
+ { 22, 0x0, 900, 450, 300 },
+ { 23, 0x0, 900, 450, 450 },
+ { 24, 0x0, 900, 450, 600 },
+ { 25, 0x0, 1000, 500, 500 },
+ { 26, 0x0, 1000, 500, 667 },
+ { 27, 0x0, 1000, 333, 500 },
+ { 28, 0x0, 400, 400, 400 },
+ { 29, 0x0, 1100, 550, 550 },
+ { 0xff, 0xff, 0, 0, 0 } /* 0xff marks end of array */
+};
+#elif defined(CONFIG_ARMADA_38X)
+/* SAR frequency values for Armada 38x */
+static const struct sar_freq_modes sar_freq_tab[] = {
+ { 0x0, 0x0, 666, 333, 333 },
+ { 0x2, 0x0, 800, 400, 400 },
+ { 0x4, 0x0, 1066, 533, 533 },
+ { 0x6, 0x0, 1200, 600, 600 },
+ { 0x8, 0x0, 1332, 666, 666 },
+ { 0xc, 0x0, 1600, 800, 800 },
+ { 0x10, 0x0, 1866, 933, 933 },
+ { 0x13, 0x0, 2000, 1000, 933 },
+ { 0xff, 0xff, 0, 0, 0 } /* 0xff marks end of array */
+};
+#elif defined(CONFIG_ARMADA_MSYS)
+static const struct sar_freq_modes sar_freq_tab[] = {
+ { 0x0, 0x0, 400, 400, 400 },
+ { 0x2, 0x0, 667, 333, 667 },
+ { 0x3, 0x0, 800, 400, 800 },
+ { 0x5, 0x0, 800, 400, 800 },
+ { 0xff, 0xff, 0, 0, 0 } /* 0xff marks end of array */
+};
+#else
+/* SAR frequency values for Armada XP */
+static const struct sar_freq_modes sar_freq_tab[] = {
+ { 0xa, 0x5, 800, 400, 400 },
+ { 0x1, 0x5, 1066, 533, 533 },
+ { 0x2, 0x5, 1200, 600, 600 },
+ { 0x2, 0x9, 1200, 600, 400 },
+ { 0x3, 0x5, 1333, 667, 667 },
+ { 0x4, 0x5, 1500, 750, 750 },
+ { 0x4, 0x9, 1500, 750, 500 },
+ { 0xb, 0x9, 1600, 800, 533 },
+ { 0xb, 0xa, 1600, 800, 640 },
+ { 0xb, 0x5, 1600, 800, 800 },
+ { 0xff, 0xff, 0, 0, 0 } /* 0xff marks end of array */
+};
+#endif
+
+void get_sar_freq(struct sar_freq_modes *sar_freq)
+{
+ u32 val;
+ u32 freq;
+ int i;
+
+#if defined(CONFIG_ARMADA_375) || defined(CONFIG_ARMADA_MSYS)
+ val = readl(CONFIG_SAR2_REG); /* SAR - Sample At Reset */
+#else
+ val = readl(CONFIG_SAR_REG); /* SAR - Sample At Reset */
+#endif
+ freq = (val & SAR_CPU_FREQ_MASK) >> SAR_CPU_FREQ_OFFS;
+#if defined(SAR2_CPU_FREQ_MASK)
+ /*
+ * Shift CPU0 clock frequency select bit from SAR2 register
+ * into correct position
+ */
+ freq |= ((readl(CONFIG_SAR2_REG) & SAR2_CPU_FREQ_MASK)
+ >> SAR2_CPU_FREQ_OFFS) << 3;
+#endif
+ for (i = 0; sar_freq_tab[i].val != 0xff; i++) {
+ if (sar_freq_tab[i].val == freq) {
+#if defined(CONFIG_ARMADA_375) || defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_MSYS)
+ *sar_freq = sar_freq_tab[i];
+ return;
+#else
+ int k;
+ u8 ffc;
+
+ ffc = (val & SAR_FFC_FREQ_MASK) >>
+ SAR_FFC_FREQ_OFFS;
+ for (k = i; sar_freq_tab[k].ffc != 0xff; k++) {
+ if (sar_freq_tab[k].ffc == ffc) {
+ *sar_freq = sar_freq_tab[k];
+ return;
+ }
+ }
+ i = k;
+#endif
+ }
+ }
+
+ /* SAR value not found, return 0 for frequencies */
+ *sar_freq = sar_freq_tab[i - 1];
+}
+
+int print_cpuinfo(void)
+{
+ u16 devid = (readl(MVEBU_REG_PCIE_DEVID) >> 16) & 0xffff;
+ u8 revid = readl(MVEBU_REG_PCIE_REVID) & 0xff;
+ struct sar_freq_modes sar_freq;
+
+ puts("SoC: ");
+
+ switch (devid) {
+ case SOC_MV78230_ID:
+ puts("MV78230-");
+ break;
+ case SOC_MV78260_ID:
+ puts("MV78260-");
+ break;
+ case SOC_MV78460_ID:
+ puts("MV78460-");
+ break;
+ case SOC_88F6720_ID:
+ puts("MV88F6720-");
+ break;
+ case SOC_88F6810_ID:
+ puts("MV88F6810-");
+ break;
+ case SOC_88F6820_ID:
+ puts("MV88F6820-");
+ break;
+ case SOC_88F6828_ID:
+ puts("MV88F6828-");
+ break;
+ case SOC_98DX3236_ID:
+ puts("98DX3236-");
+ break;
+ case SOC_98DX3336_ID:
+ puts("98DX3336-");
+ break;
+ case SOC_98DX4251_ID:
+ puts("98DX4251-");
+ break;
+ default:
+ puts("Unknown-");
+ break;
+ }
+
+ if (mvebu_soc_family() == MVEBU_SOC_AXP) {
+ switch (revid) {
+ case 1:
+ puts("A0");
+ break;
+ case 2:
+ puts("B0");
+ break;
+ default:
+ printf("?? (%x)", revid);
+ break;
+ }
+ }
+
+ if (mvebu_soc_family() == MVEBU_SOC_A375) {
+ switch (revid) {
+ case MV_88F67XX_A0_ID:
+ puts("A0");
+ break;
+ default:
+ printf("?? (%x)", revid);
+ break;
+ }
+ }
+
+ if (mvebu_soc_family() == MVEBU_SOC_A38X) {
+ switch (revid) {
+ case MV_88F68XX_Z1_ID:
+ puts("Z1");
+ break;
+ case MV_88F68XX_A0_ID:
+ puts("A0");
+ break;
+ case MV_88F68XX_B0_ID:
+ puts("B0");
+ break;
+ default:
+ printf("?? (%x)", revid);
+ break;
+ }
+ }
+
+ if (mvebu_soc_family() == MVEBU_SOC_MSYS) {
+ switch (revid) {
+ case 3:
+ puts("A0");
+ break;
+ case 4:
+ puts("A1");
+ break;
+ default:
+ printf("?? (%x)", revid);
+ break;
+ }
+ }
+
+ get_sar_freq(&sar_freq);
+ printf(" at %d MHz\n", sar_freq.p_clk);
+
+ return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+/*
+ * This function initialize Controller DRAM Fastpath windows.
+ * It takes the CS size information from the 0x1500 scratch registers
+ * and sets the correct windows sizes and base addresses accordingly.
+ *
+ * These values are set in the scratch registers by the Marvell
+ * DDR3 training code, which is executed by the SPL before the
+ * main payload (U-Boot) is executed.
+ */
+static void update_sdram_window_sizes(void)
+{
+ u64 base = 0;
+ u32 size, temp;
+ int i;
+
+ for (i = 0; i < SDRAM_MAX_CS; i++) {
+ size = readl((MVEBU_SDRAM_SCRATCH + (i * 8))) & SDRAM_ADDR_MASK;
+ if (size != 0) {
+ size |= ~(SDRAM_ADDR_MASK);
+
+ /* Set Base Address */
+ temp = (base & 0xFF000000ll) | ((base >> 32) & 0xF);
+ writel(temp, MVEBU_SDRAM_BASE + DDR_BASE_CS_OFF(i));
+
+ /*
+ * Check if out of max window size and resize
+ * the window
+ */
+ temp = (readl(MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i)) &
+ ~(SDRAM_ADDR_MASK)) | 1;
+ temp |= (size & SDRAM_ADDR_MASK);
+ writel(temp, MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i));
+
+ base += ((u64)size + 1);
+ } else {
+ /*
+ * Disable window if not used, otherwise this
+ * leads to overlapping enabled windows with
+ * pretty strange results
+ */
+ clrbits_le32(MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i), 1);
+ }
+ }
+}
+
+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)
+{
+ asm("mcr p15, 4, %0, c15, c0" : : "r" (addr));
+}
+
+#define MV_USB_PHY_BASE (MVEBU_AXP_USB_BASE + 0x800)
+#define MV_USB_PHY_PLL_REG(reg) (MV_USB_PHY_BASE | (((reg) & 0xF) << 2))
+#define MV_USB_X3_BASE(addr) (MVEBU_AXP_USB_BASE | BIT(11) | \
+ (((addr) & 0xF) << 6))
+#define MV_USB_X3_PHY_CHANNEL(dev, reg) (MV_USB_X3_BASE((dev) + 1) | \
+ (((reg) & 0xF) << 2))
+
+static void setup_usb_phys(void)
+{
+ int dev;
+
+ /*
+ * USB PLL init
+ */
+
+ /* Setup PLL frequency */
+ /* USB REF frequency = 25 MHz */
+ clrsetbits_le32(MV_USB_PHY_PLL_REG(1), 0x3ff, 0x605);
+
+ /* Power up PLL and PHY channel */
+ setbits_le32(MV_USB_PHY_PLL_REG(2), BIT(9));
+
+ /* Assert VCOCAL_START */
+ setbits_le32(MV_USB_PHY_PLL_REG(1), BIT(21));
+
+ mdelay(1);
+
+ /*
+ * USB PHY init (change from defaults) specific for 40nm (78X30 78X60)
+ */
+
+ for (dev = 0; dev < 3; dev++) {
+ setbits_le32(MV_USB_X3_PHY_CHANNEL(dev, 3), BIT(15));
+
+ /* Assert REG_RCAL_START in channel REG 1 */
+ setbits_le32(MV_USB_X3_PHY_CHANNEL(dev, 1), BIT(12));
+ udelay(40);
+ clrbits_le32(MV_USB_X3_PHY_CHANNEL(dev, 1), BIT(12));
+ }
+}
+
+/*
+ * This function is not called from the SPL U-Boot version
+ */
+int arch_cpu_init(void)
+{
+ struct pl310_regs *const pl310 =
+ (struct pl310_regs *)CONFIG_SYS_PL310_BASE;
+
+ /*
+ * 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();
+
+ /* 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);
+
+ /*
+ * From this stage on, the SoC detection is working. As we have
+ * configured the internal register base to the value used
+ * in the macros / defines in the U-Boot header (soc.h).
+ */
+
+ if (mvebu_soc_family() == MVEBU_SOC_A38X) {
+ /*
+ * To fully release / unlock this area from cache, we need
+ * to flush all caches and disable the L2 cache.
+ */
+ icache_disable();
+ dcache_disable();
+ clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN);
+ }
+
+ /*
+ * We need to call mvebu_mbus_probe() before calling
+ * update_sdram_window_sizes() as it disables all previously
+ * configured mbus windows and then configures them as
+ * required for U-Boot. Calling update_sdram_window_sizes()
+ * without this configuration will not work, as the internal
+ * registers can't be accessed reliably because of potenial
+ * double mapping.
+ * After updating the SDRAM access windows we need to call
+ * mvebu_mbus_probe() again, as this now correctly configures
+ * the SDRAM areas that are later used by the MVEBU drivers
+ * (e.g. USB, NETA).
+ */
+
+ /*
+ * First disable all windows
+ */
+ mvebu_mbus_probe(NULL, 0);
+
+ if (mvebu_soc_family() == MVEBU_SOC_AXP) {
+ /*
+ * Now the SDRAM access windows can be reconfigured using
+ * the information in the SDRAM scratch pad registers
+ */
+ update_sdram_window_sizes();
+ }
+
+ /*
+ * Finally the mbus windows can be configured with the
+ * updated SDRAM sizes
+ */
+ mvebu_mbus_probe(windows, ARRAY_SIZE(windows));
+
+ if (mvebu_soc_family() == MVEBU_SOC_AXP) {
+ /* Enable GBE0, GBE1, LCD and NFC PUP */
+ clrsetbits_le32(ARMADA_XP_PUP_ENABLE, 0,
+ GE0_PUP_EN | GE1_PUP_EN | LCD_PUP_EN |
+ NAND_PUP_EN | SPI_PUP_EN);
+
+ /* Configure USB PLL and PHYs on AXP */
+ setup_usb_phys();
+ }
+
+ /* Enable NAND and NAND arbiter */
+ clrsetbits_le32(MVEBU_SOC_DEV_MUX_REG, 0, NAND_EN | NAND_ARBITER_EN);
+
+ /* Disable MBUS error propagation */
+ clrsetbits_le32(SOC_COHERENCY_FABRIC_CTRL_REG, MBUS_ERR_PROP_EN, 0);
+
+ return 0;
+}
+#endif /* CONFIG_ARCH_CPU_INIT */
+
+u32 mvebu_get_nand_clock(void)
+{
+ u32 reg;
+
+ if (mvebu_soc_family() == MVEBU_SOC_A38X)
+ reg = MVEBU_DFX_DIV_CLK_CTRL(1);
+ else if (mvebu_soc_family() == MVEBU_SOC_MSYS)
+ reg = MVEBU_DFX_DIV_CLK_CTRL(8);
+ else
+ reg = MVEBU_CORE_DIV_CLK_CTRL(1);
+
+ return CONFIG_SYS_MVEBU_PLL_CLOCK /
+ ((readl(reg) &
+ NAND_ECC_DIVCKL_RATIO_MASK) >> NAND_ECC_DIVCKL_RATIO_OFFS);
+}
+
+/*
+ * SOC specific misc init
+ */
+#if defined(CONFIG_ARCH_MISC_INIT)
+int arch_misc_init(void)
+{
+ /* Nothing yet, perhaps we need something here later */
+ return 0;
+}
+#endif /* CONFIG_ARCH_MISC_INIT */
+
+#if defined(CONFIG_MMC_SDHCI_MV) && !defined(CONFIG_DM_MMC)
+int board_mmc_init(struct bd_info *bis)
+{
+ mv_sdh_init(MVEBU_SDIO_BASE, 0, 0,
+ SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD);
+
+ return 0;
+}
+#endif
+
+#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0
+#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4
+
+#define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4))
+#define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4))
+#define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4))
+
+static void ahci_mvebu_mbus_config(void __iomem *base)
+{
+ const struct mbus_dram_target_info *dram;
+ int i;
+
+ /* mbus is not initialized in SPL; keep the ROM settings */
+ if (IS_ENABLED(CONFIG_SPL_BUILD))
+ return;
+
+ dram = mvebu_mbus_dram_info();
+
+ for (i = 0; i < 4; i++) {
+ writel(0, base + AHCI_WINDOW_CTRL(i));
+ writel(0, base + AHCI_WINDOW_BASE(i));
+ writel(0, base + AHCI_WINDOW_SIZE(i));
+ }
+
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ writel((cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ base + AHCI_WINDOW_CTRL(i));
+ writel(cs->base >> 16, base + AHCI_WINDOW_BASE(i));
+ writel(((cs->size - 1) & 0xffff0000),
+ base + AHCI_WINDOW_SIZE(i));
+ }
+}
+
+static void ahci_mvebu_regret_option(void __iomem *base)
+{
+ /*
+ * Enable the regret bit to allow the SATA unit to regret a
+ * request that didn't receive an acknowlegde and avoid a
+ * deadlock
+ */
+ writel(0x4, base + AHCI_VENDOR_SPECIFIC_0_ADDR);
+ writel(0x80, base + AHCI_VENDOR_SPECIFIC_0_DATA);
+}
+
+int board_ahci_enable(void)
+{
+ ahci_mvebu_mbus_config((void __iomem *)MVEBU_SATA0_BASE);
+ ahci_mvebu_regret_option((void __iomem *)MVEBU_SATA0_BASE);
+
+ return 0;
+}
+
+#ifdef CONFIG_SCSI_AHCI_PLAT
+void scsi_init(void)
+{
+ printf("MVEBU SATA INIT\n");
+ board_ahci_enable();
+ ahci_init((void __iomem *)MVEBU_SATA0_BASE);
+}
+#endif
+
+#ifdef CONFIG_USB_XHCI_MVEBU
+#define USB3_MAX_WINDOWS 4
+#define USB3_WIN_CTRL(w) (0x0 + ((w) * 8))
+#define USB3_WIN_BASE(w) (0x4 + ((w) * 8))
+
+static void xhci_mvebu_mbus_config(void __iomem *base,
+ const struct mbus_dram_target_info *dram)
+{
+ int i;
+
+ for (i = 0; i < USB3_MAX_WINDOWS; i++) {
+ writel(0, base + USB3_WIN_CTRL(i));
+ writel(0, base + USB3_WIN_BASE(i));
+ }
+
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ /* Write size, attributes and target id to control register */
+ writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ base + USB3_WIN_CTRL(i));
+
+ /* Write base address to base register */
+ writel((cs->base & 0xffff0000), base + USB3_WIN_BASE(i));
+ }
+}
+
+int board_xhci_enable(fdt_addr_t base)
+{
+ const struct mbus_dram_target_info *dram;
+
+ printf("MVEBU XHCI INIT controller @ 0x%lx\n", base);
+
+ dram = mvebu_mbus_dram_info();
+ xhci_mvebu_mbus_config((void __iomem *)base, dram);
+
+ return 0;
+}
+#endif
+
+void enable_caches(void)
+{
+ /* Avoid problem with e.g. neta ethernet driver */
+ invalidate_dcache_all();
+
+ /*
+ * Armada 375 still has some problems with d-cache enabled in the
+ * ethernet driver (mvpp2). So lets keep the d-cache disabled
+ * until this is solved.
+ */
+ if (mvebu_soc_family() != MVEBU_SOC_A375) {
+ /* Enable D-cache. I-cache is already enabled in start.S */
+ dcache_enable();
+ }
+}
+
+void v7_outer_cache_enable(void)
+{
+ if (mvebu_soc_family() == MVEBU_SOC_AXP) {
+ struct pl310_regs *const pl310 =
+ (struct pl310_regs *)CONFIG_SYS_PL310_BASE;
+ u32 u;
+
+ /* The L2 cache is already disabled at this point */
+
+ /*
+ * For Aurora cache in no outer mode, enable via the CP15
+ * coprocessor broadcasting of cache commands to L2.
+ */
+ asm volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (u));
+ u |= BIT(8); /* Set the FW bit */
+ asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u));
+
+ isb();
+
+ /* Enable the L2 cache */
+ setbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN);
+ }
+}
+
+void v7_outer_cache_disable(void)
+{
+ struct pl310_regs *const pl310 =
+ (struct pl310_regs *)CONFIG_SYS_PL310_BASE;
+
+ clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN);
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/dram.c b/roms/u-boot/arch/arm/mach-mvebu/dram.c
new file mode 100644
index 000000000..349e0cc4c
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/dram.c
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#if defined(CONFIG_ARCH_MVEBU)
+/* Use common XOR definitions for A3x and AXP */
+#include "../../../drivers/ddr/marvell/axp/xor.h"
+#include "../../../drivers/ddr/marvell/axp/xor_regs.h"
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sdram_bank {
+ u32 win_bar;
+ u32 win_sz;
+};
+
+struct sdram_addr_dec {
+ struct sdram_bank sdram_bank[4];
+};
+
+#define REG_CPUCS_WIN_ENABLE (1 << 0)
+#define REG_CPUCS_WIN_WR_PROTECT (1 << 1)
+#define REG_CPUCS_WIN_WIN0_CS(x) (((x) & 0x3) << 2)
+#define REG_CPUCS_WIN_SIZE(x) (((x) & 0xff) << 24)
+
+#ifndef MVEBU_SDRAM_SIZE_MAX
+#define MVEBU_SDRAM_SIZE_MAX 0xc0000000
+#endif
+
+#define SCRUB_MAGIC 0xbeefdead
+
+#define SCRB_XOR_UNIT 0
+#define SCRB_XOR_CHAN 1
+#define SCRB_XOR_WIN 0
+
+#define XEBARX_BASE_OFFS 16
+
+/*
+ * mvebu_sdram_bar - reads SDRAM Base Address Register
+ */
+u32 mvebu_sdram_bar(enum memory_bank bank)
+{
+ struct sdram_addr_dec *base =
+ (struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
+ u32 result = 0;
+ u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
+
+ if ((!enable) || (bank > BANK3))
+ return 0;
+
+ result = readl(&base->sdram_bank[bank].win_bar);
+ return result;
+}
+
+/*
+ * mvebu_sdram_bs_set - writes SDRAM Bank size
+ */
+static void mvebu_sdram_bs_set(enum memory_bank bank, u32 size)
+{
+ struct sdram_addr_dec *base =
+ (struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
+ /* Read current register value */
+ u32 reg = readl(&base->sdram_bank[bank].win_sz);
+
+ /* Clear window size */
+ reg &= ~REG_CPUCS_WIN_SIZE(0xFF);
+
+ /* Set new window size */
+ reg |= REG_CPUCS_WIN_SIZE((size - 1) >> 24);
+
+ writel(reg, &base->sdram_bank[bank].win_sz);
+}
+
+/*
+ * mvebu_sdram_bs - reads SDRAM Bank size
+ */
+u32 mvebu_sdram_bs(enum memory_bank bank)
+{
+ struct sdram_addr_dec *base =
+ (struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
+ u32 result = 0;
+ u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
+
+ if ((!enable) || (bank > BANK3))
+ return 0;
+ result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz);
+ result += 0x01000000;
+ return result;
+}
+
+void mvebu_sdram_size_adjust(enum memory_bank bank)
+{
+ u32 size;
+
+ /* probe currently equipped RAM size */
+ size = get_ram_size((void *)mvebu_sdram_bar(bank),
+ mvebu_sdram_bs(bank));
+
+ /* adjust SDRAM window size accordingly */
+ mvebu_sdram_bs_set(bank, size);
+}
+
+#if defined(CONFIG_ARCH_MVEBU)
+static u32 xor_ctrl_save;
+static u32 xor_base_save;
+static u32 xor_mask_save;
+
+static void mv_xor_init2(u32 cs)
+{
+ u32 reg, base, size, base2;
+ u32 bank_attr[4] = { 0xe00, 0xd00, 0xb00, 0x700 };
+
+ xor_ctrl_save = reg_read(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT,
+ SCRB_XOR_CHAN));
+ xor_base_save = reg_read(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT,
+ SCRB_XOR_WIN));
+ xor_mask_save = reg_read(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT,
+ SCRB_XOR_WIN));
+
+ /* Enable Window x for each CS */
+ reg = 0x1;
+ reg |= (0x3 << 16);
+ reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), reg);
+
+ base = 0;
+ size = mvebu_sdram_bs(cs) - 1;
+ if (size) {
+ base2 = ((base / (64 << 10)) << XEBARX_BASE_OFFS) |
+ bank_attr[cs];
+ reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
+ base2);
+
+ base += size + 1;
+ size = (size / (64 << 10)) << 16;
+ /* Window x - size - 256 MB */
+ reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), size);
+ }
+
+ mv_xor_hal_init(0);
+
+ return;
+}
+
+static void mv_xor_finish2(void)
+{
+ reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN),
+ xor_ctrl_save);
+ reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
+ xor_base_save);
+ reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
+ xor_mask_save);
+}
+
+static void dram_ecc_scrubbing(void)
+{
+ int cs;
+ u32 size, temp;
+ u32 total_mem = 0;
+ u64 total;
+ u32 start_addr;
+
+ /*
+ * The DDR training code from the bin_hdr / SPL already
+ * scrubbed the DDR till 0x1000000. And the main U-Boot
+ * is loaded to an address < 0x1000000. So we need to
+ * skip this range to not re-scrub this area again.
+ */
+ temp = reg_read(REG_SDRAM_CONFIG_ADDR);
+ temp |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, temp);
+
+ for (cs = 0; cs < CONFIG_NR_DRAM_BANKS; cs++) {
+ size = mvebu_sdram_bs(cs);
+ if (size == 0)
+ continue;
+
+ total = (u64)size;
+ total_mem += (u32)(total / (1 << 30));
+ start_addr = 0;
+ mv_xor_init2(cs);
+
+ /* Skip first 16 MiB */
+ if (0 == cs) {
+ start_addr = 0x1000000;
+ size -= start_addr;
+ }
+
+ mv_xor_mem_init(SCRB_XOR_CHAN, start_addr, size - 1,
+ SCRUB_MAGIC, SCRUB_MAGIC);
+
+ /* Wait for previous transfer completion */
+ while (mv_xor_state_get(SCRB_XOR_CHAN) != MV_IDLE)
+ ;
+
+ mv_xor_finish2();
+ }
+
+ temp = reg_read(REG_SDRAM_CONFIG_ADDR);
+ temp &= ~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, temp);
+}
+
+static int ecc_enabled(void)
+{
+ if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_ECC_OFFS))
+ return 1;
+
+ return 0;
+}
+
+/* Return the width of the DRAM bus, or 0 for unknown. */
+static int bus_width(void)
+{
+ int full_width = 0;
+
+ if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_WIDTH_OFFS))
+ full_width = 1;
+
+ switch (mvebu_soc_family()) {
+ case MVEBU_SOC_AXP:
+ return full_width ? 64 : 32;
+ break;
+ case MVEBU_SOC_A375:
+ case MVEBU_SOC_A38X:
+ case MVEBU_SOC_MSYS:
+ return full_width ? 32 : 16;
+ default:
+ return 0;
+ }
+}
+
+static int cycle_mode(void)
+{
+ int val = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+
+ return (val >> REG_DUNIT_CTRL_LOW_2T_OFFS) & REG_DUNIT_CTRL_LOW_2T_MASK;
+}
+
+#else
+static void dram_ecc_scrubbing(void)
+{
+}
+
+static int ecc_enabled(void)
+{
+ return 0;
+}
+#endif
+
+int dram_init(void)
+{
+ u64 size = 0;
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ /*
+ * It is assumed that all memory banks are consecutive
+ * and without gaps.
+ * If the gap is found, ram_size will be reported for
+ * consecutive memory only
+ */
+ if (mvebu_sdram_bar(i) != size)
+ break;
+
+ /*
+ * Don't report more than 3GiB of SDRAM, otherwise there is no
+ * address space left for the internal registers etc.
+ */
+ size += mvebu_sdram_bs(i);
+ if (size > MVEBU_SDRAM_SIZE_MAX)
+ size = MVEBU_SDRAM_SIZE_MAX;
+ }
+
+ if (ecc_enabled())
+ dram_ecc_scrubbing();
+
+ gd->ram_size = size;
+
+ return 0;
+}
+
+/*
+ * If this function is not defined here,
+ * board.c alters dram bank zero configuration defined above.
+ */
+int dram_init_banksize(void)
+{
+ u64 size = 0;
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ gd->bd->bi_dram[i].start = mvebu_sdram_bar(i);
+ gd->bd->bi_dram[i].size = mvebu_sdram_bs(i);
+
+ /* Clip the banksize to 1GiB if it exceeds the max size */
+ size += gd->bd->bi_dram[i].size;
+ if (size > MVEBU_SDRAM_SIZE_MAX)
+ mvebu_sdram_bs_set(i, 0x40000000);
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_ARCH_MVEBU)
+void board_add_ram_info(int use_default)
+{
+ struct sar_freq_modes sar_freq;
+ int mode;
+ int width;
+
+ get_sar_freq(&sar_freq);
+ printf(" (%d MHz, ", sar_freq.d_clk);
+
+ width = bus_width();
+ if (width)
+ printf("%d-bit, ", width);
+
+ mode = cycle_mode();
+ /* Mode 0 = Single cycle
+ * Mode 1 = Two cycles (2T)
+ * Mode 2 = Three cycles (3T)
+ */
+ if (mode == 1)
+ printf("2T, ");
+ if (mode == 2)
+ printf("3T, ");
+
+ if (ecc_enabled())
+ printf("ECC");
+ else
+ printf("ECC not");
+ printf(" enabled)");
+}
+#endif
diff --git a/roms/u-boot/arch/arm/mach-mvebu/efuse.c b/roms/u-boot/arch/arm/mach-mvebu/efuse.c
new file mode 100644
index 000000000..c79eee98f
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/efuse.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015-2016 Reinhard Pfau <reinhard.pfau@gdsys.cc>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/efuse.h>
+#include <asm/arch/soc.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/mbus.h>
+
+#if defined(CONFIG_MVEBU_EFUSE_FAKE)
+#define DRY_RUN
+#else
+#undef DRY_RUN
+#endif
+
+#define MBUS_EFUSE_BASE 0xF6000000
+#define MBUS_EFUSE_SIZE BIT(20)
+
+#define MVEBU_EFUSE_CONTROL (MVEBU_REGISTER(0xE4008))
+
+enum {
+ MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 << 31),
+};
+
+struct mvebu_hd_efuse {
+ u32 bits_31_0;
+ u32 bits_63_32;
+ u32 bit64;
+ u32 reserved0;
+};
+
+#ifndef DRY_RUN
+static struct mvebu_hd_efuse *efuses =
+ (struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE + 0xF9000);
+#else
+static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX + 1];
+#endif
+
+static int efuse_initialised;
+
+static struct mvebu_hd_efuse *get_efuse_line(int nr)
+{
+ if (nr < 0 || nr > 63 || !efuse_initialised)
+ return NULL;
+
+ return efuses + nr;
+}
+
+static void enable_efuse_program(void)
+{
+#ifndef DRY_RUN
+ setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
+#endif
+}
+
+static void disable_efuse_program(void)
+{
+#ifndef DRY_RUN
+ clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
+#endif
+}
+
+static int do_prog_efuse(struct mvebu_hd_efuse *efuse,
+ struct efuse_val *new_val, u32 mask0, u32 mask1)
+{
+ struct efuse_val val;
+
+ val.dwords.d[0] = readl(&efuse->bits_31_0);
+ val.dwords.d[1] = readl(&efuse->bits_63_32);
+ val.lock = readl(&efuse->bit64);
+
+ if (val.lock & 1)
+ return -EPERM;
+
+ val.dwords.d[0] |= (new_val->dwords.d[0] & mask0);
+ val.dwords.d[1] |= (new_val->dwords.d[1] & mask1);
+ val.lock |= new_val->lock;
+
+ writel(val.dwords.d[0], &efuse->bits_31_0);
+ mdelay(1);
+ writel(val.dwords.d[1], &efuse->bits_63_32);
+ mdelay(1);
+ writel(val.lock, &efuse->bit64);
+ mdelay(5);
+
+ return 0;
+}
+
+static int prog_efuse(int nr, struct efuse_val *new_val, u32 mask0, u32 mask1)
+{
+ struct mvebu_hd_efuse *efuse;
+ int res = 0;
+
+ res = mvebu_efuse_init_hw();
+ if (res)
+ return res;
+
+ efuse = get_efuse_line(nr);
+ if (!efuse)
+ return -ENODEV;
+
+ if (!new_val)
+ return -EINVAL;
+
+ /* only write a fuse line with lock bit */
+ if (!new_val->lock)
+ return -EINVAL;
+
+ /* according to specs ECC protection bits must be 0 on write */
+ if (new_val->bytes.d[7] & 0xFE)
+ return -EINVAL;
+
+ if (!new_val->dwords.d[0] && !new_val->dwords.d[1] && (mask0 | mask1))
+ return 0;
+
+ enable_efuse_program();
+
+ res = do_prog_efuse(efuse, new_val, mask0, mask1);
+
+ disable_efuse_program();
+
+ return res;
+}
+
+int mvebu_efuse_init_hw(void)
+{
+ int ret;
+
+ if (efuse_initialised)
+ return 0;
+
+ ret = mvebu_mbus_add_window_by_id(
+ CPU_TARGET_SATA23_DFX, 0xA, MBUS_EFUSE_BASE, MBUS_EFUSE_SIZE);
+
+ if (ret)
+ return ret;
+
+ efuse_initialised = 1;
+
+ return 0;
+}
+
+int mvebu_read_efuse(int nr, struct efuse_val *val)
+{
+ struct mvebu_hd_efuse *efuse;
+ int res;
+
+ res = mvebu_efuse_init_hw();
+ if (res)
+ return res;
+
+ efuse = get_efuse_line(nr);
+ if (!efuse)
+ return -ENODEV;
+
+ if (!val)
+ return -EINVAL;
+
+ val->dwords.d[0] = readl(&efuse->bits_31_0);
+ val->dwords.d[1] = readl(&efuse->bits_63_32);
+ val->lock = readl(&efuse->bit64);
+ return 0;
+}
+
+int mvebu_write_efuse(int nr, struct efuse_val *val)
+{
+ return prog_efuse(nr, val, ~0, ~0);
+}
+
+int mvebu_lock_efuse(int nr)
+{
+ struct efuse_val val = {
+ .lock = 1,
+ };
+
+ return prog_efuse(nr, &val, 0, 0);
+}
+
+/*
+ * wrapper funcs providing the fuse API
+ *
+ * we use the following mapping:
+ * "bank" -> eFuse line
+ * "word" -> 0: bits 0-31
+ * 1: bits 32-63
+ * 2: bit 64 (lock)
+ */
+
+static struct efuse_val prog_val;
+static int valid_prog_words;
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ struct efuse_val fuse_line;
+ int res;
+
+ if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2)
+ return -EINVAL;
+
+ res = mvebu_read_efuse(bank, &fuse_line);
+ if (res)
+ return res;
+
+ if (word < 2)
+ *val = fuse_line.dwords.d[word];
+ else
+ *val = fuse_line.lock;
+
+ return res;
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ /* not supported */
+ return -ENOSYS;
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ int res = 0;
+
+ /*
+ * NOTE: Fuse line should be written as whole.
+ * So how can we do that with this API?
+ * For now: remember values for word == 0 and word == 1 and write the
+ * whole line when word == 2.
+ * This implies that we always require all 3 fuse prog cmds (one for
+ * for each word) to write a single fuse line.
+ * Exception is a single write to word 2 which will lock the fuse line.
+ *
+ * Hope that will be OK.
+ */
+
+ if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2)
+ return -EINVAL;
+
+ if (word < 2) {
+ prog_val.dwords.d[word] = val;
+ valid_prog_words |= (1 << word);
+ } else if ((valid_prog_words & 3) == 0 && val) {
+ res = mvebu_lock_efuse(bank);
+ valid_prog_words = 0;
+ } else if ((valid_prog_words & 3) != 3 || !val) {
+ res = -EINVAL;
+ } else {
+ prog_val.lock = val != 0;
+ res = mvebu_write_efuse(bank, &prog_val);
+ valid_prog_words = 0;
+ }
+
+ return res;
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ /* not supported */
+ return -ENOSYS;
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/gpio.c b/roms/u-boot/arch/arm/mach-mvebu/gpio.c
new file mode 100644
index 000000000..1d1e3df8b
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/gpio.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+/*
+ * mvebu_config_gpio - GPIO configuration
+ */
+void mvebu_config_gpio(u32 gpp0_oe_val, u32 gpp1_oe_val,
+ u32 gpp0_oe, u32 gpp1_oe)
+{
+ struct kwgpio_registers *gpio0reg =
+ (struct kwgpio_registers *)MVEBU_GPIO0_BASE;
+ struct kwgpio_registers *gpio1reg =
+ (struct kwgpio_registers *)MVEBU_GPIO1_BASE;
+
+ /* Init GPIOS to default values as per board requirement */
+ writel(gpp0_oe_val, &gpio0reg->dout);
+ writel(gpp1_oe_val, &gpio1reg->dout);
+ writel(gpp0_oe, &gpio0reg->oe);
+ writel(gpp1_oe, &gpio1reg->oe);
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/include/mach/config.h b/roms/u-boot/arch/arm/mach-mvebu/include/mach/config.h
new file mode 100644
index 000000000..02a5b8801
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/include/mach/config.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2011
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Lei Wen <leiwen@marvell.com>
+ */
+
+/*
+ * This file should be included in board config header file.
+ *
+ * It supports common definitions for MVEBU platforms
+ */
+
+#ifndef _MVEBU_CONFIG_H
+#define _MVEBU_CONFIG_H
+
+#include <asm/arch/soc.h>
+
+#if defined(CONFIG_ARMADA_XP) || defined(CONFIG_ARMADA_375) \
+ || defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_MSYS)
+/*
+ * Set this for the common xor register definitions needed in dram.c
+ * for A38x as well here.
+ */
+#define MV88F78X60 /* for the DDR training bin_hdr code */
+#endif
+
+#define CONFIG_SYS_L2_PL310
+
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_SKIP_LOWLEVEL_INIT /* disable board lowlevel_init */
+#endif
+
+/*
+ * By default the generated mvebu kwbimage.cfg is used
+ * If for some board, different configuration file need to be used,
+ * CONFIG_SYS_KWD_CONFIG should be defined in board specific header file
+ */
+#ifndef CONFIG_SYS_KWD_CONFIG
+#define CONFIG_SYS_KWD_CONFIG arch/arm/mach-mvebu/kwbimage.cfg
+#endif /* CONFIG_SYS_KWD_CONFIG */
+
+/* end of 16M scrubbed by training in bootrom */
+#define CONFIG_SYS_INIT_SP_ADDR 0x00FF0000
+
+#define MV_UART_CONSOLE_BASE MVEBU_UART0_BASE
+
+/* Needed for SPI NOR booting in SPL */
+#define CONFIG_DM_SEQ_ALIAS 1
+
+/*
+ * Ethernet Driver configuration
+ */
+#ifdef CONFIG_CMD_NET
+#define CONFIG_ARP_TIMEOUT 200
+#define CONFIG_NET_RETRY_COUNT 50
+#endif /* CONFIG_CMD_NET */
+
+/*
+ * I2C related stuff
+ */
+#ifdef CONFIG_CMD_I2C
+#ifndef CONFIG_SYS_I2C_SOFT
+#define CONFIG_I2C_MVTWSI
+#endif
+#define CONFIG_SYS_I2C_SLAVE 0x0
+#define CONFIG_SYS_I2C_SPEED 100000
+#endif
+
+/* Use common timer */
+#define CONFIG_SYS_TIMER_COUNTS_DOWN
+#define CONFIG_SYS_TIMER_COUNTER (MVEBU_TIMER_BASE + 0x14)
+#define CONFIG_SYS_TIMER_RATE 25000000
+
+#endif /* __MVEBU_CONFIG_H */
diff --git a/roms/u-boot/arch/arm/mach-mvebu/include/mach/cpu.h b/roms/u-boot/arch/arm/mach-mvebu/include/mach/cpu.h
new file mode 100644
index 000000000..52473ade7
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/include/mach/cpu.h
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ */
+
+#ifndef _MVEBU_CPU_H
+#define _MVEBU_CPU_H
+
+#include <asm/system.h>
+
+#ifndef __ASSEMBLY__
+
+#define MVEBU_REG_PCIE_DEVID (MVEBU_REG_PCIE_BASE + 0x00)
+#define MVEBU_REG_PCIE_REVID (MVEBU_REG_PCIE_BASE + 0x08)
+
+enum memory_bank {
+ BANK0,
+ BANK1,
+ BANK2,
+ BANK3
+};
+
+enum cpu_winen {
+ CPU_WIN_DISABLE,
+ CPU_WIN_ENABLE
+};
+
+enum cpu_target {
+ CPU_TARGET_DRAM = 0x0,
+ CPU_TARGET_DEVICEBUS_BOOTROM_SPI = 0x1,
+ CPU_TARGET_ETH23 = 0x3,
+ CPU_TARGET_PCIE02 = 0x4,
+ CPU_TARGET_ETH01 = 0x7,
+ CPU_TARGET_PCIE13 = 0x8,
+ CPU_TARGET_DFX = 0x8,
+ CPU_TARGET_SASRAM = 0x9,
+ CPU_TARGET_SATA01 = 0xa, /* A38X */
+ CPU_TARGET_NAND = 0xd,
+ CPU_TARGET_SATA23_DFX = 0xe, /* A38X */
+};
+
+enum cpu_attrib {
+ CPU_ATTR_SASRAM = 0x01,
+ CPU_ATTR_DRAM_CS0 = 0x0e,
+ CPU_ATTR_DRAM_CS1 = 0x0d,
+ CPU_ATTR_DRAM_CS2 = 0x0b,
+ CPU_ATTR_DRAM_CS3 = 0x07,
+ CPU_ATTR_NANDFLASH = 0x2f,
+ CPU_ATTR_SPIFLASH = 0x1e,
+ CPU_ATTR_SPI0_CS0 = 0x1e,
+ CPU_ATTR_SPI0_CS1 = 0x5e,
+ CPU_ATTR_SPI1_CS2 = 0x9a,
+ CPU_ATTR_BOOTROM = 0x1d,
+ CPU_ATTR_PCIE_IO = 0xe0,
+ CPU_ATTR_PCIE_MEM = 0xe8,
+ CPU_ATTR_DEV_CS0 = 0x3e,
+ CPU_ATTR_DEV_CS1 = 0x3d,
+ CPU_ATTR_DEV_CS2 = 0x3b,
+ CPU_ATTR_DEV_CS3 = 0x37,
+};
+
+enum {
+ MVEBU_SOC_AXP,
+ MVEBU_SOC_A375,
+ MVEBU_SOC_A38X,
+ MVEBU_SOC_MSYS,
+ MVEBU_SOC_UNKNOWN,
+};
+
+#define MVEBU_SDRAM_SIZE_MAX 0xc0000000
+
+/*
+ * Default Device Address MAP BAR values
+ */
+#define MBUS_PCI_MEM_BASE MVEBU_SDRAM_SIZE_MAX
+#define MBUS_PCI_MEM_SIZE (128 << 20)
+#define MBUS_PCI_IO_BASE 0xF1100000
+#define MBUS_PCI_IO_SIZE (64 << 10)
+#define MBUS_SPI_BASE 0xF4000000
+#define MBUS_SPI_SIZE (8 << 20)
+#define MBUS_DFX_BASE 0xF6000000
+#define MBUS_DFX_SIZE (1 << 20)
+#define MBUS_BOOTROM_BASE 0xF8000000
+#define MBUS_BOOTROM_SIZE (8 << 20)
+
+struct mbus_win {
+ u32 base;
+ u32 size;
+ u8 target;
+ u8 attr;
+};
+
+/*
+ * System registers
+ * Ref: Datasheet sec:A.28
+ */
+struct mvebu_system_registers {
+#if defined(CONFIG_ARMADA_375)
+ u8 pad1[0x54];
+#else
+ u8 pad1[0x60];
+#endif
+ u32 rstoutn_mask; /* 0x60 */
+ u32 sys_soft_rst; /* 0x64 */
+};
+
+/*
+ * GPIO Registers
+ * Ref: Datasheet sec:A.19
+ */
+struct kwgpio_registers {
+ u32 dout;
+ u32 oe;
+ u32 blink_en;
+ u32 din_pol;
+ u32 din;
+ u32 irq_cause;
+ u32 irq_mask;
+ u32 irq_level;
+};
+
+struct sar_freq_modes {
+ u8 val;
+ u8 ffc; /* Fabric Frequency Configuration */
+ u32 p_clk;
+ u32 nb_clk;
+ u32 d_clk;
+};
+
+/* Needed for dynamic (board-specific) mbus configuration */
+extern struct mvebu_mbus_state mbus_state;
+
+/*
+ * functions
+ */
+unsigned int mvebu_sdram_bar(enum memory_bank bank);
+unsigned int mvebu_sdram_bs(enum memory_bank bank);
+void mvebu_sdram_size_adjust(enum memory_bank bank);
+int mvebu_mbus_probe(struct mbus_win windows[], int count);
+int mvebu_soc_family(void);
+u32 mvebu_get_nand_clock(void);
+
+void return_to_bootrom(void);
+
+#ifndef CONFIG_DM_MMC
+int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks);
+#endif
+
+void get_sar_freq(struct sar_freq_modes *sar_freq);
+
+/*
+ * Highspeed SERDES PHY config init, ported from bin_hdr
+ * to mainline U-Boot
+ */
+int serdes_phy_config(void);
+
+/*
+ * DDR3 init / training code ported from Marvell bin_hdr. Now
+ * available in mainline U-Boot in:
+ * drivers/ddr/marvell
+ */
+int ddr3_init(void);
+
+/* Auto Voltage Scaling */
+#if defined(CONFIG_ARMADA_38X)
+void mv_avs_init(void);
+void mv_rtc_config(void);
+#else
+static inline void mv_avs_init(void) {}
+static inline void mv_rtc_config(void) {}
+#endif
+
+/* A8K dram functions */
+u64 a8k_dram_scan_ap_sz(void);
+int a8k_dram_init_banksize(void);
+
+/* A3700 dram functions */
+int a3700_dram_init(void);
+int a3700_dram_init_banksize(void);
+
+/* A3700 PCIe regions fixer for device tree */
+int a3700_fdt_fix_pcie_regions(void *blob);
+
+/*
+ * get_ref_clk
+ *
+ * return: reference clock in MHz (25 or 40)
+ */
+u32 get_ref_clk(void);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _MVEBU_CPU_H */
diff --git a/roms/u-boot/arch/arm/mach-mvebu/include/mach/efuse.h b/roms/u-boot/arch/arm/mach-mvebu/include/mach/efuse.h
new file mode 100644
index 000000000..bbc5844d8
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/include/mach/efuse.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015 Reinhard Pfau <reinhard.pfau@gdsys.cc>
+ */
+
+#ifndef _MVEBU_EFUSE_H
+#define _MVEBU_EFUSE_H
+
+#include <common.h>
+
+struct efuse_val {
+ union {
+ struct {
+ u8 d[8];
+ } bytes;
+ struct {
+ u16 d[4];
+ } words;
+ struct {
+ u32 d[2];
+ } dwords;
+ };
+ u32 lock;
+};
+
+#if defined(CONFIG_ARMADA_38X)
+
+enum efuse_line {
+ EFUSE_LINE_SECURE_BOOT = 24,
+ EFUSE_LINE_PUBKEY_DIGEST_0 = 26,
+ EFUSE_LINE_PUBKEY_DIGEST_1 = 27,
+ EFUSE_LINE_PUBKEY_DIGEST_2 = 28,
+ EFUSE_LINE_PUBKEY_DIGEST_3 = 29,
+ EFUSE_LINE_PUBKEY_DIGEST_4 = 30,
+ EFUSE_LINE_CSK_0_VALID = 31,
+ EFUSE_LINE_CSK_1_VALID = 32,
+ EFUSE_LINE_CSK_2_VALID = 33,
+ EFUSE_LINE_CSK_3_VALID = 34,
+ EFUSE_LINE_CSK_4_VALID = 35,
+ EFUSE_LINE_CSK_5_VALID = 36,
+ EFUSE_LINE_CSK_6_VALID = 37,
+ EFUSE_LINE_CSK_7_VALID = 38,
+ EFUSE_LINE_CSK_8_VALID = 39,
+ EFUSE_LINE_CSK_9_VALID = 40,
+ EFUSE_LINE_CSK_10_VALID = 41,
+ EFUSE_LINE_CSK_11_VALID = 42,
+ EFUSE_LINE_CSK_12_VALID = 43,
+ EFUSE_LINE_CSK_13_VALID = 44,
+ EFUSE_LINE_CSK_14_VALID = 45,
+ EFUSE_LINE_CSK_15_VALID = 46,
+ EFUSE_LINE_FLASH_ID = 47,
+ EFUSE_LINE_BOX_ID = 48,
+
+ EFUSE_LINE_MIN = 0,
+ EFUSE_LINE_MAX = 63,
+};
+
+#endif
+
+int mvebu_efuse_init_hw(void);
+
+int mvebu_read_efuse(int nr, struct efuse_val *val);
+
+int mvebu_write_efuse(int nr, struct efuse_val *val);
+
+int mvebu_lock_efuse(int nr);
+
+#endif
diff --git a/roms/u-boot/arch/arm/mach-mvebu/include/mach/fw_info.h b/roms/u-boot/arch/arm/mach-mvebu/include/mach/fw_info.h
new file mode 100644
index 000000000..1382438e3
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/include/mach/fw_info.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ */
+
+#ifndef _FW_INFO_H_
+#define _FW_INFO_H_
+
+/* Protected ATF and TEE region */
+#define ATF_REGION_START 0x4000000
+#define ATF_REGION_END 0x5400000
+
+/* Firmware related definition used for SMC calls */
+#define MV_SIP_DRAM_SIZE 0x82000010
+
+#define MMIO_REGS_PHY_BASE 0xc0000000
+
+#endif /* _FW_INFO_H_ */
diff --git a/roms/u-boot/arch/arm/mach-mvebu/include/mach/gpio.h b/roms/u-boot/arch/arm/mach-mvebu/include/mach/gpio.h
new file mode 100644
index 000000000..b0c95db7f
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/include/mach/gpio.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __MACH_MVEBU_GPIO_H
+#define __MACH_MVEBU_GPIO_H
+
+/* Empty file - sdhci requires this. */
+
+#endif
diff --git a/roms/u-boot/arch/arm/mach-mvebu/include/mach/soc.h b/roms/u-boot/arch/arm/mach-mvebu/include/mach/soc.h
new file mode 100644
index 000000000..3f3b15aa8
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/include/mach/soc.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * Header file for the Marvell's Feroceon CPU core.
+ */
+
+#ifndef _MVEBU_SOC_H
+#define _MVEBU_SOC_H
+
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#endif
+
+#define SOC_MV78230_ID 0x7823
+#define SOC_MV78260_ID 0x7826
+#define SOC_MV78460_ID 0x7846
+#define SOC_88F6720_ID 0x6720
+#define SOC_88F6810_ID 0x6810
+#define SOC_88F6820_ID 0x6820
+#define SOC_88F6828_ID 0x6828
+#define SOC_98DX3236_ID 0xf410
+#define SOC_98DX3336_ID 0xf400
+#define SOC_98DX4251_ID 0xfc00
+
+/* A375 revisions */
+#define MV_88F67XX_A0_ID 0x3
+
+/* A38x revisions */
+#define MV_88F68XX_Z1_ID 0x0
+#define MV_88F68XX_A0_ID 0x4
+#define MV_88F68XX_B0_ID 0xa
+
+/* TCLK Core Clock definition */
+#ifndef CONFIG_SYS_TCLK
+#define CONFIG_SYS_TCLK 250000000 /* 250MHz */
+#endif
+
+/* SOC specific definations */
+#define INTREG_BASE 0xd0000000
+#define INTREG_BASE_ADDR_REG (INTREG_BASE + 0x20080)
+#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_ARMADA_3700)
+/*
+ * The SPL U-Boot version still runs with the default
+ * address for the internal registers, configured by
+ * the BootROM. Only the main U-Boot version uses the
+ * new internal register base address, that also is
+ * required for the Linux kernel.
+ */
+#define SOC_REGS_PHY_BASE 0xd0000000
+#elif defined(CONFIG_ARMADA_8K)
+#define SOC_REGS_PHY_BASE 0xf0000000
+#else
+#define SOC_REGS_PHY_BASE 0xf1000000
+#endif
+#define MVEBU_REGISTER(x) (SOC_REGS_PHY_BASE + x)
+
+#define MVEBU_SDRAM_SCRATCH (MVEBU_REGISTER(0x01504))
+#define MVEBU_L2_CACHE_BASE (MVEBU_REGISTER(0x08000))
+#define CONFIG_SYS_PL310_BASE MVEBU_L2_CACHE_BASE
+#define MVEBU_TWSI_BASE (MVEBU_REGISTER(0x11000))
+#define MVEBU_TWSI1_BASE (MVEBU_REGISTER(0x11100))
+#define MVEBU_MPP_BASE (MVEBU_REGISTER(0x18000))
+#define MVEBU_GPIO0_BASE (MVEBU_REGISTER(0x18100))
+#define MVEBU_GPIO1_BASE (MVEBU_REGISTER(0x18140))
+#define MVEBU_GPIO2_BASE (MVEBU_REGISTER(0x18180))
+#define MVEBU_SYSTEM_REG_BASE (MVEBU_REGISTER(0x18200))
+#define MVEBU_CLOCK_BASE (MVEBU_REGISTER(0x18700))
+#define MVEBU_CPU_WIN_BASE (MVEBU_REGISTER(0x20000))
+#define MVEBU_SDRAM_BASE (MVEBU_REGISTER(0x20180))
+#define MVEBU_TIMER_BASE (MVEBU_REGISTER(0x20300))
+#define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000))
+#define MVEBU_AXP_USB_BASE (MVEBU_REGISTER(0x50000))
+#define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000))
+#define MVEBU_REG_PCIE0_BASE (MVEBU_REGISTER(0x80000))
+#define MVEBU_AXP_SATA_BASE (MVEBU_REGISTER(0xa0000))
+#define MVEBU_SATA0_BASE (MVEBU_REGISTER(0xa8000))
+#define MVEBU_NAND_BASE (MVEBU_REGISTER(0xd0000))
+#define MVEBU_SDIO_BASE (MVEBU_REGISTER(0xd8000))
+#define MVEBU_LCD_BASE (MVEBU_REGISTER(0xe0000))
+#ifdef CONFIG_ARMADA_MSYS
+#define MVEBU_DFX_BASE (MBUS_DFX_BASE)
+#else
+#define MVEBU_DFX_BASE (MVEBU_REGISTER(0xe4000))
+#endif
+
+#define SOC_COHERENCY_FABRIC_CTRL_REG (MVEBU_REGISTER(0x20200))
+#define MBUS_ERR_PROP_EN (1 << 8)
+
+#define MBUS_BRIDGE_WIN_CTRL_REG (MVEBU_REGISTER(0x20250))
+#define MBUS_BRIDGE_WIN_BASE_REG (MVEBU_REGISTER(0x20254))
+
+#define MVEBU_SOC_DEV_MUX_REG (MVEBU_SYSTEM_REG_BASE + 0x08)
+#define NAND_EN BIT(0)
+#define NAND_ARBITER_EN BIT(27)
+
+#define ARMADA_XP_PUP_ENABLE (MVEBU_SYSTEM_REG_BASE + 0x44c)
+#define GE0_PUP_EN BIT(0)
+#define GE1_PUP_EN BIT(1)
+#define LCD_PUP_EN BIT(2)
+#define NAND_PUP_EN BIT(4)
+#define SPI_PUP_EN BIT(5)
+
+#define MVEBU_CORE_DIV_CLK_CTRL(i) (MVEBU_CLOCK_BASE + ((i) * 0x8))
+#ifdef CONFIG_ARMADA_MSYS
+#define MVEBU_DFX_DIV_CLK_CTRL(i) (MVEBU_DFX_BASE + 0xf8000 + 0x250 + ((i) * 0x4))
+#define NAND_ECC_DIVCKL_RATIO_OFFS 6
+#define NAND_ECC_DIVCKL_RATIO_MASK (0xF << NAND_ECC_DIVCKL_RATIO_OFFS)
+#else
+#define MVEBU_DFX_DIV_CLK_CTRL(i) (MVEBU_DFX_BASE + 0x250 + ((i) * 0x4))
+#endif
+#ifdef CONFIG_ARMADA_MSYS
+#define NAND_ECC_DIVCKL_RATIO_OFFS 6
+#define NAND_ECC_DIVCKL_RATIO_MASK (0xF << NAND_ECC_DIVCKL_RATIO_OFFS)
+#else
+#define NAND_ECC_DIVCKL_RATIO_OFFS 8
+#define NAND_ECC_DIVCKL_RATIO_MASK (0x3F << NAND_ECC_DIVCKL_RATIO_OFFS)
+#endif
+
+#define SDRAM_MAX_CS 4
+#define SDRAM_ADDR_MASK 0xFF000000
+
+/* MVEBU CPU memory windows */
+#define MVCPU_WIN_CTRL_DATA CPU_WIN_CTRL_DATA
+#define MVCPU_WIN_ENABLE CPU_WIN_ENABLE
+#define MVCPU_WIN_DISABLE CPU_WIN_DISABLE
+
+#define COMPHY_REFCLK_ALIGNMENT (MVEBU_REGISTER(0x182f8))
+
+/* BootROM error register (also includes some status infos) */
+#define CONFIG_BOOTROM_ERR_REG (MVEBU_REGISTER(0x182d0))
+#define BOOTROM_ERR_MODE_OFFS 28
+#define BOOTROM_ERR_MODE_MASK (0xf << BOOTROM_ERR_MODE_OFFS)
+#define BOOTROM_ERR_MODE_UART 0x6
+#define BOOTROM_ERR_CODE_OFFS 0
+#define BOOTROM_ERR_CODE_MASK (0xf << BOOTROM_ERR_CODE_OFFS)
+
+#if defined(CONFIG_ARMADA_375)
+/* SAR values for Armada 375 */
+#define CONFIG_SAR_REG (MVEBU_REGISTER(0xe8200))
+#define CONFIG_SAR2_REG (MVEBU_REGISTER(0xe8204))
+
+#define SAR_CPU_FREQ_OFFS 17
+#define SAR_CPU_FREQ_MASK (0x1f << SAR_CPU_FREQ_OFFS)
+
+#define BOOT_DEV_SEL_OFFS 3
+#define BOOT_DEV_SEL_MASK (0x3f << BOOT_DEV_SEL_OFFS)
+
+#define BOOT_FROM_UART 0x30
+#define BOOT_FROM_SPI 0x38
+#elif defined(CONFIG_ARMADA_38X)
+/* SAR values for Armada 38x */
+#define CONFIG_SAR_REG (MVEBU_REGISTER(0x18600))
+
+#define SAR_CPU_FREQ_OFFS 10
+#define SAR_CPU_FREQ_MASK (0x1f << SAR_CPU_FREQ_OFFS)
+#define SAR_BOOT_DEVICE_OFFS 4
+#define SAR_BOOT_DEVICE_MASK (0x1f << SAR_BOOT_DEVICE_OFFS)
+
+#define BOOT_DEV_SEL_OFFS 4
+#define BOOT_DEV_SEL_MASK (0x3f << BOOT_DEV_SEL_OFFS)
+
+#define BOOT_FROM_NAND 0x0A
+#define BOOT_FROM_SATA 0x22
+#define BOOT_FROM_UART 0x28
+#define BOOT_FROM_SATA_ALT 0x2A
+#define BOOT_FROM_UART_ALT 0x3f
+#define BOOT_FROM_SPI 0x32
+#define BOOT_FROM_MMC 0x30
+#define BOOT_FROM_MMC_ALT 0x31
+#elif defined(CONFIG_ARMADA_MSYS)
+/* SAR values for MSYS */
+#define CONFIG_SAR_REG (MBUS_DFX_BASE + 0xf8200)
+#define CONFIG_SAR2_REG (MBUS_DFX_BASE + 0xf8204)
+
+#define SAR_CPU_FREQ_OFFS 18
+#define SAR_CPU_FREQ_MASK (0x7 << SAR_CPU_FREQ_OFFS)
+#define SAR_BOOT_DEVICE_OFFS 11
+#define SAR_BOOT_DEVICE_MASK (0x7 << SAR_BOOT_DEVICE_OFFS)
+
+#define BOOT_DEV_SEL_OFFS 11
+#define BOOT_DEV_SEL_MASK (0x7 << BOOT_DEV_SEL_OFFS)
+
+#define BOOT_FROM_NAND 0x1
+#define BOOT_FROM_UART 0x2
+#define BOOT_FROM_SPI 0x3
+#else
+/* SAR values for Armada XP */
+#define CONFIG_SAR_REG (MVEBU_REGISTER(0x18230))
+#define CONFIG_SAR2_REG (MVEBU_REGISTER(0x18234))
+
+#define SAR_CPU_FREQ_OFFS 21
+#define SAR_CPU_FREQ_MASK (0x7 << SAR_CPU_FREQ_OFFS)
+#define SAR_FFC_FREQ_OFFS 24
+#define SAR_FFC_FREQ_MASK (0xf << SAR_FFC_FREQ_OFFS)
+#define SAR2_CPU_FREQ_OFFS 20
+#define SAR2_CPU_FREQ_MASK (0x1 << SAR2_CPU_FREQ_OFFS)
+#define SAR_BOOT_DEVICE_OFFS 5
+#define SAR_BOOT_DEVICE_MASK (0xf << SAR_BOOT_DEVICE_OFFS)
+
+#define BOOT_DEV_SEL_OFFS 5
+#define BOOT_DEV_SEL_MASK (0xf << BOOT_DEV_SEL_OFFS)
+
+#define BOOT_FROM_UART 0x2
+#define BOOT_FROM_SPI 0x3
+#endif
+
+#endif /* _MVEBU_SOC_H */
diff --git a/roms/u-boot/arch/arm/mach-mvebu/kwbimage.cfg.in b/roms/u-boot/arch/arm/mach-mvebu/kwbimage.cfg.in
new file mode 100644
index 000000000..72e67d75c
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/kwbimage.cfg.in
@@ -0,0 +1,12 @@
+#
+# Copyright (C) 2014 Stefan Roese <sr@denx.de>
+#
+
+# Armada 38x uses version 1 image format
+VERSION 1
+
+# Boot Media configurations
+#@BOOT_FROM
+
+# Binary Header (bin_hdr) with DDR3 training code
+BINARY spl/u-boot-spl.bin 0000005b 00000068
diff --git a/roms/u-boot/arch/arm/mach-mvebu/lowlevel_spl.S b/roms/u-boot/arch/arm/mach-mvebu/lowlevel_spl.S
new file mode 100644
index 000000000..8718d7a43
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/lowlevel_spl.S
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+
+ENTRY(save_boot_params)
+ stmfd sp!, {r0 - r12, lr} /* @ save registers on stack */
+ ldr r12, =CONFIG_SPL_BOOTROM_SAVE
+ str sp, [r12]
+ b save_boot_params_ret
+ENDPROC(save_boot_params)
+
+ENTRY(return_to_bootrom)
+ ldr r12, =CONFIG_SPL_BOOTROM_SAVE
+ ldr sp, [r12]
+ mov r0, #0x0 /* @ return value: 0x0 NO_ERR */
+ ldmfd sp!, {r0 - r12, pc} /* @ restore regs and return */
+ENDPROC(return_to_bootrom)
+
+/*
+ * cache_inv - invalidate Cache line
+ * r0 - dest
+ */
+ .global cache_inv
+ .type cache_inv, %function
+ cache_inv:
+
+ stmfd sp!, {r1-r12}
+
+ mcr p15, 0, r0, c7, c6, 1
+
+ ldmfd sp!, {r1-r12}
+ bx lr
+
+
+/*
+ * flush_l1_v6 - l1 cache clean invalidate
+ * r0 - dest
+ */
+ .global flush_l1_v6
+ .type flush_l1_v6, %function
+ flush_l1_v6:
+
+ stmfd sp!, {r1-r12}
+
+ mcr p15, 0, r0, c7, c10, 5 /* @ data memory barrier */
+ mcr p15, 0, r0, c7, c14, 1 /* @ clean & invalidate D line */
+ mcr p15, 0, r0, c7, c10, 4 /* @ data sync barrier */
+
+ ldmfd sp!, {r1-r12}
+ bx lr
+
+
+/*
+ * flush_l1_v7 - l1 cache clean invalidate
+ * r0 - dest
+ */
+ .global flush_l1_v7
+ .type flush_l1_v7, %function
+ flush_l1_v7:
+
+ stmfd sp!, {r1-r12}
+
+ dmb /* @data memory barrier */
+ mcr p15, 0, r0, c7, c14, 1 /* @ clean & invalidate D line */
+ dsb /* @data sync barrier */
+
+ ldmfd sp!, {r1-r12}
+ bx lr
diff --git a/roms/u-boot/arch/arm/mach-mvebu/mbus.c b/roms/u-boot/arch/arm/mach-mvebu/mbus.c
new file mode 100644
index 000000000..3b1b9f73e
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/mbus.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Address map functions for Marvell EBU SoCs (Kirkwood, Armada
+ * 370/XP, Dove, Orion5x and MV78xx0)
+ *
+ * Ported from the Barebox version to U-Boot by:
+ * Stefan Roese <sr@denx.de>
+ *
+ * The Barebox version is:
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * based on mbus driver from Linux
+ * (C) Copyright 2008 Marvell Semiconductor
+ *
+ * The Marvell EBU SoCs have a configurable physical address space:
+ * the physical address at which certain devices (PCIe, NOR, NAND,
+ * etc.) sit can be configured. The configuration takes place through
+ * two sets of registers:
+ *
+ * - One to configure the access of the CPU to the devices. Depending
+ * on the families, there are between 8 and 20 configurable windows,
+ * each can be use to create a physical memory window that maps to a
+ * specific device. Devices are identified by a tuple (target,
+ * attribute).
+ *
+ * - One to configure the access to the CPU to the SDRAM. There are
+ * either 2 (for Dove) or 4 (for other families) windows to map the
+ * SDRAM into the physical address space.
+ *
+ * This driver:
+ *
+ * - Reads out the SDRAM address decoding windows at initialization
+ * time, and fills the mbus_dram_info structure with these
+ * informations. The exported function mv_mbus_dram_info() allow
+ * device drivers to get those informations related to the SDRAM
+ * address decoding windows. This is because devices also have their
+ * own windows (configured through registers that are part of each
+ * device register space), and therefore the drivers for Marvell
+ * devices have to configure those device -> SDRAM windows to ensure
+ * that DMA works properly.
+ *
+ * - Provides an API for platform code or device drivers to
+ * dynamically add or remove address decoding windows for the CPU ->
+ * device accesses. This API is mvebu_mbus_add_window_by_id(),
+ * mvebu_mbus_add_window_remap_by_id() and
+ * mvebu_mbus_del_window().
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/log2.h>
+#include <linux/mbus.h>
+
+/* DDR target is the same on all platforms */
+#define TARGET_DDR 0
+
+/* CPU Address Decode Windows registers */
+#define WIN_CTRL_OFF 0x0000
+#define WIN_CTRL_ENABLE BIT(0)
+#define WIN_CTRL_TGT_MASK 0xf0
+#define WIN_CTRL_TGT_SHIFT 4
+#define WIN_CTRL_ATTR_MASK 0xff00
+#define WIN_CTRL_ATTR_SHIFT 8
+#define WIN_CTRL_SIZE_MASK 0xffff0000
+#define WIN_CTRL_SIZE_SHIFT 16
+#define WIN_BASE_OFF 0x0004
+#define WIN_BASE_LOW 0xffff0000
+#define WIN_BASE_HIGH 0xf
+#define WIN_REMAP_LO_OFF 0x0008
+#define WIN_REMAP_LOW 0xffff0000
+#define WIN_REMAP_HI_OFF 0x000c
+
+#define ATTR_HW_COHERENCY (0x1 << 4)
+
+#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3))
+#define DDR_BASE_CS_HIGH_MASK 0xf
+#define DDR_BASE_CS_LOW_MASK 0xff000000
+#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
+#define DDR_SIZE_ENABLED BIT(0)
+#define DDR_SIZE_CS_MASK 0x1c
+#define DDR_SIZE_CS_SHIFT 2
+#define DDR_SIZE_MASK 0xff000000
+
+#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
+
+struct mvebu_mbus_state;
+
+struct mvebu_mbus_soc_data {
+ unsigned int num_wins;
+ unsigned int num_remappable_wins;
+ unsigned int (*win_cfg_offset)(const int win);
+ void (*setup_cpu_target)(struct mvebu_mbus_state *s);
+};
+
+struct mvebu_mbus_state mbus_state
+ __section(".data");
+static struct mbus_dram_target_info mbus_dram_info
+ __section(".data");
+
+/*
+ * Functions to manipulate the address decoding windows
+ */
+
+static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
+ int win, int *enabled, u64 *base,
+ u32 *size, u8 *target, u8 *attr,
+ u64 *remap)
+{
+ void __iomem *addr = mbus->mbuswins_base +
+ mbus->soc->win_cfg_offset(win);
+ u32 basereg = readl(addr + WIN_BASE_OFF);
+ u32 ctrlreg = readl(addr + WIN_CTRL_OFF);
+
+ if (!(ctrlreg & WIN_CTRL_ENABLE)) {
+ *enabled = 0;
+ return;
+ }
+
+ *enabled = 1;
+ *base = ((u64)basereg & WIN_BASE_HIGH) << 32;
+ *base |= (basereg & WIN_BASE_LOW);
+ *size = (ctrlreg | ~WIN_CTRL_SIZE_MASK) + 1;
+
+ if (target)
+ *target = (ctrlreg & WIN_CTRL_TGT_MASK) >> WIN_CTRL_TGT_SHIFT;
+
+ if (attr)
+ *attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT;
+
+ if (remap) {
+ if (win < mbus->soc->num_remappable_wins) {
+ u32 remap_low = readl(addr + WIN_REMAP_LO_OFF);
+ u32 remap_hi = readl(addr + WIN_REMAP_HI_OFF);
+ *remap = ((u64)remap_hi << 32) | remap_low;
+ } else {
+ *remap = 0;
+ }
+ }
+}
+
+static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
+ int win)
+{
+ void __iomem *addr;
+
+ addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win);
+
+ writel(0, addr + WIN_BASE_OFF);
+ writel(0, addr + WIN_CTRL_OFF);
+ if (win < mbus->soc->num_remappable_wins) {
+ writel(0, addr + WIN_REMAP_LO_OFF);
+ writel(0, addr + WIN_REMAP_HI_OFF);
+ }
+}
+
+/* Checks whether the given window number is available */
+static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
+ const int win)
+{
+ void __iomem *addr = mbus->mbuswins_base +
+ mbus->soc->win_cfg_offset(win);
+ u32 ctrl = readl(addr + WIN_CTRL_OFF);
+ return !(ctrl & WIN_CTRL_ENABLE);
+}
+
+/*
+ * Checks whether the given (base, base+size) area doesn't overlap an
+ * existing region
+ */
+static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
+ phys_addr_t base, size_t size,
+ u8 target, u8 attr)
+{
+ u64 end = (u64)base + size;
+ int win;
+
+ for (win = 0; win < mbus->soc->num_wins; win++) {
+ u64 wbase, wend;
+ u32 wsize;
+ u8 wtarget, wattr;
+ int enabled;
+
+ mvebu_mbus_read_window(mbus, win,
+ &enabled, &wbase, &wsize,
+ &wtarget, &wattr, NULL);
+
+ if (!enabled)
+ continue;
+
+ wend = wbase + wsize;
+
+ /*
+ * Check if the current window overlaps with the
+ * proposed physical range
+ */
+ if ((u64)base < wend && end > wbase)
+ return 0;
+
+ /*
+ * Check if target/attribute conflicts
+ */
+ if (target == wtarget && attr == wattr)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int mvebu_mbus_find_window(struct mvebu_mbus_state *mbus,
+ phys_addr_t base, size_t size)
+{
+ int win;
+
+ for (win = 0; win < mbus->soc->num_wins; win++) {
+ u64 wbase;
+ u32 wsize;
+ int enabled;
+
+ mvebu_mbus_read_window(mbus, win,
+ &enabled, &wbase, &wsize,
+ NULL, NULL, NULL);
+
+ if (!enabled)
+ continue;
+
+ if (base == wbase && size == wsize)
+ return win;
+ }
+
+ return -ENODEV;
+}
+
+static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
+ int win, phys_addr_t base, size_t size,
+ phys_addr_t remap, u8 target,
+ u8 attr)
+{
+ void __iomem *addr = mbus->mbuswins_base +
+ mbus->soc->win_cfg_offset(win);
+ u32 ctrl, remap_addr;
+
+ ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
+ (attr << WIN_CTRL_ATTR_SHIFT) |
+ (target << WIN_CTRL_TGT_SHIFT) |
+ WIN_CTRL_ENABLE;
+
+ writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
+ writel(ctrl, addr + WIN_CTRL_OFF);
+ if (win < mbus->soc->num_remappable_wins) {
+ if (remap == MVEBU_MBUS_NO_REMAP)
+ remap_addr = base;
+ else
+ remap_addr = remap;
+ writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF);
+ writel(0, addr + WIN_REMAP_HI_OFF);
+ }
+
+ return 0;
+}
+
+static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus,
+ phys_addr_t base, size_t size,
+ phys_addr_t remap, u8 target,
+ u8 attr)
+{
+ int win;
+
+ if (remap == MVEBU_MBUS_NO_REMAP) {
+ for (win = mbus->soc->num_remappable_wins;
+ win < mbus->soc->num_wins; win++)
+ if (mvebu_mbus_window_is_free(mbus, win))
+ return mvebu_mbus_setup_window(mbus, win, base,
+ size, remap,
+ target, attr);
+ }
+
+
+ for (win = 0; win < mbus->soc->num_wins; win++)
+ if (mvebu_mbus_window_is_free(mbus, win))
+ return mvebu_mbus_setup_window(mbus, win, base, size,
+ remap, target, attr);
+
+ return -ENOMEM;
+}
+
+/*
+ * SoC-specific functions and definitions
+ */
+
+static unsigned int armada_370_xp_mbus_win_offset(int win)
+{
+ /* The register layout is a bit annoying and the below code
+ * tries to cope with it.
+ * - At offset 0x0, there are the registers for the first 8
+ * windows, with 4 registers of 32 bits per window (ctrl,
+ * base, remap low, remap high)
+ * - Then at offset 0x80, there is a hole of 0x10 bytes for
+ * the internal registers base address and internal units
+ * sync barrier register.
+ * - Then at offset 0x90, there the registers for 12
+ * windows, with only 2 registers of 32 bits per window
+ * (ctrl, base).
+ */
+ if (win < 8)
+ return win << 4;
+ else
+ return 0x90 + ((win - 8) << 3);
+}
+
+static unsigned int orion5x_mbus_win_offset(int win)
+{
+ return win << 4;
+}
+
+static void mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
+{
+ int i;
+ int cs;
+
+ mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
+
+ for (i = 0, cs = 0; i < 4; i++) {
+ u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
+ u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
+
+ /*
+ * We only take care of entries for which the chip
+ * select is enabled, and that don't have high base
+ * address bits set (devices can only access the first
+ * 32 bits of the memory).
+ */
+ if ((size & DDR_SIZE_ENABLED) &&
+ !(base & DDR_BASE_CS_HIGH_MASK)) {
+ struct mbus_dram_window *w;
+
+ w = &mbus_dram_info.cs[cs++];
+ w->cs_index = i;
+ w->mbus_attr = 0xf & ~(1 << i);
+ w->base = base & DDR_BASE_CS_LOW_MASK;
+ w->size = (size | ~DDR_SIZE_MASK) + 1;
+ }
+ }
+ mbus_dram_info.num_cs = cs;
+
+#if defined(CONFIG_ARMADA_MSYS)
+ /* Disable MBUS Err Prop - in order to avoid data aborts */
+ clrbits_le32(mbus->mbuswins_base + 0x200, BIT(8));
+#endif
+}
+
+static const struct mvebu_mbus_soc_data
+armada_370_xp_mbus_data __maybe_unused = {
+ .num_wins = 20,
+ .num_remappable_wins = 8,
+ .win_cfg_offset = armada_370_xp_mbus_win_offset,
+ .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
+};
+
+static const struct mvebu_mbus_soc_data
+kirkwood_mbus_data __maybe_unused = {
+ .num_wins = 8,
+ .num_remappable_wins = 4,
+ .win_cfg_offset = orion5x_mbus_win_offset,
+ .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
+};
+
+/*
+ * Public API of the driver
+ */
+const struct mbus_dram_target_info *mvebu_mbus_dram_info(void)
+{
+ return &mbus_dram_info;
+}
+
+int mvebu_mbus_add_window_remap_by_id(unsigned int target,
+ unsigned int attribute,
+ phys_addr_t base, size_t size,
+ phys_addr_t remap)
+{
+ struct mvebu_mbus_state *s = &mbus_state;
+
+ if (!mvebu_mbus_window_conflicts(s, base, size, target, attribute)) {
+ printf("Cannot add window '%x:%x', conflicts with another window\n",
+ target, attribute);
+ return -EINVAL;
+ }
+
+ return mvebu_mbus_alloc_window(s, base, size, remap, target, attribute);
+}
+
+int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute,
+ phys_addr_t base, size_t size)
+{
+ return mvebu_mbus_add_window_remap_by_id(target, attribute, base,
+ size, MVEBU_MBUS_NO_REMAP);
+}
+
+int mvebu_mbus_del_window(phys_addr_t base, size_t size)
+{
+ int win;
+
+ win = mvebu_mbus_find_window(&mbus_state, base, size);
+ if (win < 0)
+ return win;
+
+ mvebu_mbus_disable_window(&mbus_state, win);
+ return 0;
+}
+
+#ifndef CONFIG_ARCH_KIRKWOOD
+static void mvebu_mbus_get_lowest_base(struct mvebu_mbus_state *mbus,
+ phys_addr_t *base)
+{
+ int win;
+ *base = 0xffffffff;
+
+ for (win = 0; win < mbus->soc->num_wins; win++) {
+ u64 wbase;
+ u32 wsize;
+ u8 wtarget, wattr;
+ int enabled;
+
+ mvebu_mbus_read_window(mbus, win,
+ &enabled, &wbase, &wsize,
+ &wtarget, &wattr, NULL);
+
+ if (!enabled)
+ continue;
+
+ if (wbase < *base)
+ *base = wbase;
+ }
+}
+
+static void mvebu_config_mbus_bridge(struct mvebu_mbus_state *mbus)
+{
+ phys_addr_t base;
+ u32 val;
+ u32 size;
+
+ /* Set MBUS bridge base/ctrl */
+ mvebu_mbus_get_lowest_base(&mbus_state, &base);
+
+ size = 0xffffffff - base + 1;
+ if (!is_power_of_2(size)) {
+ /* Round up to next power of 2 */
+ size = 1 << (ffs(base) + 1);
+ base = 0xffffffff - size + 1;
+ }
+
+ /* Now write base and size */
+ writel(base, MBUS_BRIDGE_WIN_BASE_REG);
+ /* Align window size to 64KiB */
+ val = (size / (64 << 10)) - 1;
+ writel((val << 16) | 0x1, MBUS_BRIDGE_WIN_CTRL_REG);
+}
+#endif
+
+int mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
+ u32 base, u32 size, u8 target, u8 attr)
+{
+ if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
+ printf("Cannot add window '%04x:%04x', conflicts with another window\n",
+ target, attr);
+ return -EBUSY;
+ }
+
+ /*
+ * In U-Boot we first try to add the mbus window to the remap windows.
+ * If this fails, lets try to add the windows to the non-remap windows.
+ */
+ if (mvebu_mbus_alloc_window(mbus, base, size, base, target, attr)) {
+ if (mvebu_mbus_alloc_window(mbus, base, size,
+ MVEBU_MBUS_NO_REMAP, target, attr))
+ return -ENOMEM;
+ }
+
+#ifndef CONFIG_ARCH_KIRKWOOD
+ /*
+ * Re-configure the mbus bridge registers each time this function
+ * is called. Since it may get called from the board code in
+ * later boot stages as well.
+ */
+ mvebu_config_mbus_bridge(mbus);
+#endif
+
+ return 0;
+}
+
+int mvebu_mbus_probe(struct mbus_win windows[], int count)
+{
+ int win;
+ int ret;
+ int i;
+
+#if defined(CONFIG_ARCH_KIRKWOOD)
+ mbus_state.soc = &kirkwood_mbus_data;
+#endif
+#if defined(CONFIG_ARCH_MVEBU)
+ mbus_state.soc = &armada_370_xp_mbus_data;
+#endif
+
+ mbus_state.mbuswins_base = (void __iomem *)MVEBU_CPU_WIN_BASE;
+ mbus_state.sdramwins_base = (void __iomem *)MVEBU_SDRAM_BASE;
+
+ for (win = 0; win < mbus_state.soc->num_wins; win++)
+ mvebu_mbus_disable_window(&mbus_state, win);
+
+ mbus_state.soc->setup_cpu_target(&mbus_state);
+
+ /* Setup statically declared windows in the DT */
+ for (i = 0; i < count; i++) {
+ u32 base, size;
+ u8 target, attr;
+
+ target = windows[i].target;
+ attr = windows[i].attr;
+ base = windows[i].base;
+ size = windows[i].size;
+ ret = mbus_dt_setup_win(&mbus_state, base, size, target, attr);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/Makefile b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/Makefile
new file mode 100644
index 000000000..917fc1350
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/Makefile
@@ -0,0 +1,7 @@
+# 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) += seq_exec.o
+obj-$(CONFIG_SPL_BUILD) += sys_env_lib.o
diff --git a/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
new file mode 100644
index 000000000..adef3331a
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#include "ctrl_pex.h"
+#include "sys_env_lib.h"
+
+__weak void board_pex_config(void)
+{
+ /* nothing in this weak default implementation */
+}
+
+int hws_pex_config(const struct serdes_map *serdes_map, u8 count)
+{
+ 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;
+
+ DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
+
+ for (idx = 0; idx < count; 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 < count; 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");
+
+ board_pex_config();
+
+ next_busno = 0;
+ mdelay(150);
+
+ for (idx = 0; idx < count; 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 capabilities\n");
+ }
+
+ /* Update pex DEVICE ID */
+ ctrl_mode = sys_env_model_get();
+
+ for (idx = 0; idx < count; 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/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
new file mode 100644
index 000000000..3f30b6bf9
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#ifndef _CTRL_PEX_H
+#define _CTRL_PEX_H
+
+#include "high_speed_env_spec.h"
+
+/* Sample at Reset */
+#define MPP_SAMPLE_AT_RESET(id) (0xe4200 + (id * 4))
+
+/* PCI Express Control and Status Registers */
+#define MAX_PEX_BUSSES 256
+
+#define MISC_REGS_OFFSET 0x18200
+#define MV_MISC_REGS_BASE MISC_REGS_OFFSET
+#define SOC_CTRL_REG (MV_MISC_REGS_BASE + 0x4)
+
+#define PEX_IF_REGS_OFFSET(if) ((if) > 0 ? \
+ (0x40000 + ((if) - 1) * 0x4000) : \
+ 0x80000)
+#define PEX_IF_REGS_BASE(if) (PEX_IF_REGS_OFFSET(if))
+#define PEX_CAPABILITIES_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x60)
+#define PEX_LINK_CTRL_STATUS2_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x90)
+#define PEX_CTRL_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a00)
+#define PEX_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a04)
+#define PEX_DBG_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a64)
+#define PEX_LINK_CAPABILITY_REG 0x6c
+#define PEX_LINK_CTRL_STAT_REG 0x70
+#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */
+#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS)
+#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */
+#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS)
+
+/* PEX_CAPABILITIES_REG fields */
+#define PCIE0_ENABLE_OFFS 0
+#define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS)
+#define PCIE1_ENABLE_OFFS 1
+#define PCIE1_ENABLE_MASK (0x1 << PCIE1_ENABLE_OFFS)
+#define PCIE2_ENABLE_OFFS 2
+#define PCIE2_ENABLE_MASK (0x1 << PCIE2_ENABLE_OFFS)
+#define PCIE3_ENABLE_OFFS 3
+#define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS)
+
+/* Controller revision info */
+#define PEX_DEVICE_AND_VENDOR_ID 0x000
+#define PEX_CFG_DIRECT_ACCESS(if, reg) (PEX_IF_REGS_BASE(if) + (reg))
+
+/* 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(const struct serdes_map *serdes_map, u8 count);
+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);
+
+void board_pex_config(void);
+
+#endif
diff --git a/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c
new file mode 100644
index 000000000..12596ec2d
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_env_spec.h"
+#include "sys_env_lib.h"
+
+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/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
new file mode 100644
index 000000000..3b41c7d49
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
@@ -0,0 +1,2173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/delay.h>
+
+#include "high_speed_env_spec.h"
+#include "sys_env_lib.h"
+#include "ctrl_pex.h"
+
+
+
+/*
+ * 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_VERSION "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 */
+ { 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 Alignment 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},
+ /* Force receiver detected */
+ {LANE_CFG0_REG, 0x800, 0x8000, {0x8000}, 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},
+ /* Decrease the amplitude of the low speed eye to meet the spec */
+ {0xc000c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+ {0xc200c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+ {0xc400c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+ /* Change the High speed impedance threshold */
+ {0xc0008, 0x0 /*NA*/, 0x700, {CONFIG_ARMADA_38X_HS_IMPEDANCE_THRESH << 8}, 0, 0},
+ {0xc2008, 0x0 /*NA*/, 0x700, {CONFIG_ARMADA_38X_HS_IMPEDANCE_THRESH << 8}, 0, 0},
+ {0xc4008, 0x0 /*NA*/, 0x700, {CONFIG_ARMADA_38X_HS_IMPEDANCE_THRESH << 8}, 0, 0},
+ /* Change the squelch level of the receiver to meet the receiver electrical measurements (squelch and receiver sensitivity tests) */
+ {0xc0014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+ {0xc2014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+ {0xc4014, 0x0 /*NA*/, 0xf, {0x8}, 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},
+ /* Start calibrate of high seed impedance */
+ {0xc0008, 0x0 /*NA*/, 0x2000, {0x2000}, 0, 0},
+ {0x0, 0x0 /*NA*/, 0x0, {0x0}, 10, 0},
+ /* De-assert the calibration signal */
+ {0xc0008, 0x0 /*NA*/, 0x2000, {0x0}, 0, 0},
+};
+
+/*
+ * 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)
+{
+ /* for A38x-Z1 */
+ if (sys_env_device_rev_get() == MV_88F68XX_Z1_ID)
+ return MV_SERDES_REV_1_2;
+
+ /* 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:
+ 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;
+ default:
+ return SERDES_LAST_SEQ;
+ }
+
+ return seq_id;
+}
+
+static void print_topology_details(const struct serdes_map *serdes_map,
+ u8 count)
+{
+ 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 < count; lane_num++) {
+ if (serdes_map[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[lane_num].serdes_speed, 2);
+ DEBUG_INIT_S(" | ");
+ DEBUG_INIT_S((char *)
+ serdes_type_to_string[serdes_map[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)
+{
+ struct serdes_map *serdes_map;
+ u8 serdes_count;
+
+ DEBUG_INIT_FULL_S("\n### ctrl_high_speed_serdes_phy_config ###\n");
+
+ DEBUG_INIT_S("High speed PHY - Version: ");
+ DEBUG_INIT_S(SERDES_VERSION);
+ 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;
+ }
+
+ /* Board topology load */
+ DEBUG_INIT_FULL_S
+ ("ctrl_high_speed_serdes_phy_config: Loading board topology..\n");
+ CHECK_STATUS(hws_board_topology_load(&serdes_map, &serdes_count));
+ if (serdes_count > hws_serdes_get_max_lane()) {
+ printf("Error: too many serdes lanes specified by board\n");
+ return MV_FAIL;
+ }
+
+ /* print topology */
+ print_topology_details(serdes_map, serdes_count);
+ 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_map, serdes_count));
+
+ 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_map, u8 count)
+{
+ 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_map, count));
+
+ /* per Serdes Power Up */
+ for (serdes_id = 0; serdes_id < count; 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_map[serdes_id].serdes_type;
+ serdes_speed = serdes_map[serdes_id].serdes_speed;
+ serdes_mode = serdes_map[serdes_id].serdes_mode;
+ serdes_rx_polarity_swap = serdes_map[serdes_id].swap_rx;
+ serdes_tx_polarity_swap = serdes_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_map, count));
+
+ /* PEX configuration */
+ CHECK_STATUS(hws_pex_config(serdes_map, count));
+ }
+
+ /* 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_map, u8 count)
+{
+ 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 < count; idx++) {
+ serdes_type = serdes_map[idx].serdes_type;
+ serdes_mode = serdes_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_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_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_map, count);
+
+ /*
+ * 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;
+ 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;
+ 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(const struct serdes_map *serdes_map, u8 count)
+{
+ 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 < count; 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 < count; 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 < count; 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/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
new file mode 100644
index 000000000..dd229e1a4
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#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, u8 *count);
+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_map, u8 count);
+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_map, u8 count);
+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(const struct serdes_map *serdes_map, u8 count);
+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/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
new file mode 100644
index 000000000..2a51b7113
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/delay.h>
+
+#include "seq_exec.h"
+#include "high_speed_env_spec.h"
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
+
+#if defined(MV_DEBUG_INIT_FULL) || defined(MV_DEBUG)
+#define DB(x) x
+#else
+#define DB(x)
+#endif
+
+/* Array for mapping the operation (write, poll or delay) functions */
+op_execute_func_ptr op_execute_func_arr[] = {
+ write_op_execute,
+ delay_op_execute,
+ poll_op_execute
+};
+
+int write_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+ u32 unit_base_reg, unit_offset, data, mask, reg_data, reg_addr;
+
+ /* Getting write op params from the input parameter */
+ data = params->data[data_arr_idx];
+ mask = params->mask;
+
+ /* an empty operation */
+ if (data == NO_DATA)
+ return MV_OK;
+
+ /* get updated base address since it can be different between Serdes */
+ CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
+ params->unit_offset,
+ &unit_base_reg, &unit_offset));
+
+ /* Address calculation */
+ reg_addr = unit_base_reg + unit_offset * serdes_num;
+
+#ifdef SEQ_DEBUG
+ printf("Write: 0x%x: 0x%x (mask 0x%x) - ", reg_addr, data, mask);
+#endif
+ /* Reading old value */
+ reg_data = reg_read(reg_addr);
+ reg_data &= (~mask);
+
+ /* Writing new data */
+ data &= mask;
+ reg_data |= data;
+ reg_write(reg_addr, reg_data);
+
+#ifdef SEQ_DEBUG
+ printf(" - 0x%x\n", reg_data);
+#endif
+
+ return MV_OK;
+}
+
+int delay_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+ u32 delay;
+
+ /* Getting delay op params from the input parameter */
+ delay = params->wait_time;
+#ifdef SEQ_DEBUG
+ printf("Delay: %d\n", delay);
+#endif
+ mdelay(delay);
+
+ return MV_OK;
+}
+
+int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+ u32 unit_base_reg, unit_offset, data, mask, num_of_loops, wait_time;
+ u32 poll_counter = 0;
+ u32 reg_addr, reg_data;
+
+ /* Getting poll op params from the input parameter */
+ data = params->data[data_arr_idx];
+ mask = params->mask;
+ num_of_loops = params->num_of_loops;
+ wait_time = params->wait_time;
+
+ /* an empty operation */
+ if (data == NO_DATA)
+ return MV_OK;
+
+ /* get updated base address since it can be different between Serdes */
+ CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
+ params->unit_offset,
+ &unit_base_reg, &unit_offset));
+
+ /* Address calculation */
+ reg_addr = unit_base_reg + unit_offset * serdes_num;
+
+ /* Polling */
+#ifdef SEQ_DEBUG
+ printf("Poll: 0x%x: 0x%x (mask 0x%x)\n", reg_addr, data, mask);
+#endif
+
+ do {
+ reg_data = reg_read(reg_addr) & mask;
+ poll_counter++;
+ udelay(wait_time);
+ } while ((reg_data != data) && (poll_counter < num_of_loops));
+
+ if ((poll_counter >= num_of_loops) && (reg_data != data)) {
+ DEBUG_INIT_S("poll_op_execute: TIMEOUT\n");
+ return MV_TIMEOUT;
+ }
+
+ return MV_OK;
+}
+
+enum mv_op get_cfg_seq_op(struct op_params *params)
+{
+ if (params->wait_time == 0)
+ return WRITE_OP;
+ else if (params->num_of_loops == 0)
+ return DELAY_OP;
+
+ return POLL_OP;
+}
+
+int mv_seq_exec(u32 serdes_num, u32 seq_id)
+{
+ u32 seq_idx;
+ struct op_params *seq_arr;
+ u32 seq_size;
+ u32 data_arr_idx;
+ enum mv_op curr_op;
+
+ DB(printf("\n### mv_seq_exec ###\n"));
+ DB(printf("seq id: %d\n", seq_id));
+
+ if (hws_is_serdes_active(serdes_num) != 1) {
+ printf("mv_seq_exec_ext:Error: SerDes lane %d is not valid\n",
+ serdes_num);
+ return MV_BAD_PARAM;
+ }
+
+ seq_arr = serdes_seq_db[seq_id].op_params_ptr;
+ seq_size = serdes_seq_db[seq_id].cfg_seq_size;
+ data_arr_idx = serdes_seq_db[seq_id].data_arr_idx;
+
+ DB(printf("seq_size: %d\n", seq_size));
+ DB(printf("data_arr_idx: %d\n", data_arr_idx));
+
+ /* Executing the sequence operations */
+ for (seq_idx = 0; seq_idx < seq_size; seq_idx++) {
+ curr_op = get_cfg_seq_op(&seq_arr[seq_idx]);
+ op_execute_func_arr[curr_op](serdes_num, &seq_arr[seq_idx],
+ data_arr_idx);
+ }
+
+ return MV_OK;
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h
new file mode 100644
index 000000000..fe0cb8f75
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#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/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
new file mode 100644
index 000000000..950680a58
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "seq_exec.h"
+#include "sys_env_lib.h"
+
+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}
+};
+
+u32 g_dev_id = -1;
+
+u32 mv_board_id_get(void)
+{
+#if defined(CONFIG_TARGET_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 */
+ default_ctrl_id = MV_6820_DEV_ID;
+ 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;
+}
+
+/*
+ * 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;
+}
+
+void mv_rtc_config(void)
+{
+ u32 i, val;
+
+ /* Activate pipe0 for read/write transaction, and set XBAR client number #1 */
+ val = 0x1 << DFX_PIPE_SELECT_PIPE0_ACTIVE_OFFS |
+ 0x1 << DFX_PIPE_SELECT_XBAR_CLIENT_SEL_OFFS;
+ writel(val, MVEBU_DFX_BASE);
+
+ /* Set new RTC value for all memory wrappers */
+ for (i = 0; i < RTC_MEMORY_WRAPPER_COUNT; i++)
+ reg_write(RTC_MEMORY_WRAPPER_REG(i), RTC_MEMORY_WRAPPER_CTRL_VAL);
+}
+
+void mv_avs_init(void)
+{
+ u32 sar_freq;
+
+ reg_write(AVS_DEBUG_CNTR_REG, AVS_DEBUG_CNTR_DEFAULT_VALUE);
+ reg_write(AVS_DEBUG_CNTR_REG, AVS_DEBUG_CNTR_DEFAULT_VALUE);
+
+ sar_freq = reg_read(DEVICE_SAMPLE_AT_RESET1_REG);
+ sar_freq = sar_freq >> SAR_FREQ_OFFSET & SAR_FREQ_MASK;
+
+ /* Set AVS value only for core frequency of 1600MHz or less.
+ * For higher frequency leave the default value.
+ */
+ if (sar_freq <= 0xd) {
+ u32 avs_reg_data = reg_read(AVS_ENABLED_CONTROL);
+
+ avs_reg_data &= ~(AVS_LOW_VDD_LIMIT_MASK
+ | AVS_HIGH_VDD_LIMIT_MASK);
+ avs_reg_data |= AVS_LOW_VDD_SLOW_VAL | AVS_HIGH_VDD_SLOW_VAL;
+ reg_write(AVS_ENABLED_CONTROL, avs_reg_data);
+ }
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h
new file mode 100644
index 000000000..118bf5660
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h
@@ -0,0 +1,351 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#ifndef _SYS_ENV_LIB_H
+#define _SYS_ENV_LIB_H
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_init.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_FREQ_OFFSET 10
+#define SAR_FREQ_MASK 0x1f
+#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_CFG0_REG 0xa0600
+#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 */
+#define EEPROM_I2C_ADDR (sys_env_device_rev_get() == \
+ MV_88F68XX_Z1_ID ? 0x50 : 0x57)
+#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 DFX_PIPE_SELECT_PIPE0_ACTIVE_OFFS 0
+/* DFX_PIPE_SELECT_XBAR_CLIENT_SEL_OFFS: Since address completion in 14bit
+ * address mode, and given that [14:8] => [19:13], the 2 lower bits [9:8] =>
+ * [14:13] are dismissed. hence field offset is also shifted to 10
+ */
+#define DFX_PIPE_SELECT_XBAR_CLIENT_SEL_OFFS 10
+
+#define RTC_MEMORY_CTRL_REG_BASE 0xE6000
+#define RTC_MEMORY_WRAPPER_COUNT 8
+#define RTC_MEMORY_WRAPPER_REG(i) (RTC_MEMORY_CTRL_REG_BASE + ((i) * 0x40))
+#define RTC_MEMORY_CTRL_PDLVMC_FIELD_OFFS 6
+#define RTC_MEMORY_WRAPPER_CTRL_VAL (0x1 << RTC_MEMORY_CTRL_PDLVMC_FIELD_OFFS)
+
+#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_LOW_VDD_SLOW_VAL (0x23 << 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)
+#define AVS_HIGH_VDD_SLOW_VAL (0x23 << 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)
+
+#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
+
+#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
+#define MV_88F68XX_B0_ID 0xa
+/* 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
+
+#define MAX_DEV_ID_NUM 4
+
+#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
+#define MV_BOARD_WAKEUP_GPIO_INFO { \
+ {A38X_CUSTOMER_BOARD_ID0, -1 }, \
+ {A38X_CUSTOMER_BOARD_ID0, -1 }, \
+};
+
+#else
+
+#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 }, \
+};
+#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_cs_ena_from_reg(void);
+
+#endif /* _SYS_ENV_LIB_H */
diff --git a/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/Makefile b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/Makefile
new file mode 100644
index 000000000..897afb703
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/Makefile
@@ -0,0 +1,4 @@
+# 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/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/board_env_spec.h b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/board_env_spec.h
new file mode 100644
index 000000000..9c3e7c082
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/board_env_spec.h
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#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 + 1)
+#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_BOARD_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/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c
new file mode 100644
index 000000000..ea3b4c7d5
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_lib.c
@@ -0,0 +1,1611 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/delay.h>
+
+#include "high_speed_env_spec.h"
+#include "board_env_spec.h"
+
+#define SERDES_VERSION "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, port) ((satr >> port) & 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
+}
+
+__weak u8 board_sat_r_get(u8 dev_num, u8 reg)
+{
+ u8 data;
+ u8 *dev;
+ u32 board_id = board_id_get();
+ int ret;
+
+ 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:
+ return (0x1 << 1) | 1;
+ case FPGA_88F78XX0_ID:
+ case RD_78460_NAS_ID:
+ return (0x0 << 1) | 1;
+ 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;
+
+ default:
+ return 0;
+ }
+
+ /* Read MPP module ID */
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+ 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(void)
+{
+ 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)
+{
+ /*
+ * SoC version can't be autodetected. So we need to rely on a define
+ * from the config system here.
+ */
+#if defined(CONFIG_MV78230)
+ return MV_78230_DEV_ID;
+#elif defined(CONFIG_MV78260)
+ return MV_78260_DEV_ID;
+#else
+ return MV_78460_DEV_ID;
+#endif
+}
+
+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;
+}
+
+static int serdes_max_lines_get(void)
+{
+ switch (ctrl_model_get()) {
+ case MV_78230_DEV_ID:
+ return 7;
+ case MV_78260_DEV_ID:
+ return 12;
+ case MV_78460_DEV_ID:
+ return 16;
+ }
+
+ return 0;
+}
+
+/*
+ * Tests have shown that on some boards the default width of the
+ * configuration pulse for the PEX link detection might lead to
+ * non-established PCIe links (link down). Especially under certain
+ * conditions (higher temperature) and with specific PCIe devices.
+ * To enable a board-specific detection pulse width this weak
+ * array "serdes_pex_pulse_width[4]" is introduced which can be
+ * overwritten if needed by a board-specific version. If the board
+ * code does not provide a non-weak version of this variable, the
+ * default value will be used. So nothing is changed from the
+ * current setup on the supported board.
+ */
+__weak u8 serdes_pex_pulse_width[4] = { 2, 2, 2, 2 };
+
+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 pex_if;
+ u32 pex_if_num;
+
+ /*
+ * Get max. serdes lines count
+ */
+ max_serdes_lines = serdes_max_lines_get();
+ if (max_serdes_lines == 0)
+ return MV_OK;
+
+ satr11 = board_sat_r_get(1, 1);
+ if ((u8) MV_ERROR == (u8) satr11)
+ return MV_ERROR;
+
+ 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_VERSION);
+ DEBUG_INIT_S(" - 2nd boot - Skip\n");
+ return MV_OK;
+ }
+ DEBUG_INIT_S("High speed PHY - Version: ");
+ DEBUG_INIT_S(SERDES_VERSION);
+ 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();
+
+ if (info == NULL) {
+ DEBUG_INIT_S("Hight speed PHY Error #1\n");
+ return MV_ERROR;
+ }
+ 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 (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, pex_unit))
+ 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) {
+ /*
+ * Configure the detection pulse with before
+ * the reset is deasserted
+ */
+
+ /* Read the old value (indirect access) */
+ reg_write(PEX_PHY_ACCESS_REG(pex_unit),
+ (0x48 << 16) | (1 << 31) |
+ (pex_line_num << 24));
+ tmp = reg_read(PEX_PHY_ACCESS_REG(pex_unit));
+ tmp &= ~(1 << 31); /* Clear read */
+ tmp &= ~(3 << 6); /* Mask width */
+ /* Insert new detection pulse width */
+ tmp |= serdes_pex_pulse_width[pex_unit] << 6;
+ /* Write value back */
+ reg_write(PEX_PHY_ACCESS_REG(pex_unit), tmp);
+
+ 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_FULL_S("Update Device ID PEX");
+ DEBUG_INIT_FULL_D(pex_if, 1);
+ DEBUG_INIT_FULL_D(devId, 8);
+ DEBUG_INIT_FULL_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_FULL_S("Update PEX Device ID 0x");
+ DEBUG_INIT_FULL_D(ctrl_mode, 4);
+ DEBUG_INIT_FULL_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/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c
new file mode 100644
index 000000000..539d23762
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_env_spec.h"
+
+MV_SERDES_CHANGE_M_PHY serdes_change_m_phy[] = {
+ /* SERDES TYPE, Low REG OFFS, Low REG VALUE, Hi REG OFS, Hi REG VALUE */
+ {
+ /* PEX: Change of Slew Rate port0 */
+ SERDES_UNIT_PEX, 0x0,
+ (0x0F << 16) | 0x2a21, 0x0, (0x0F << 16) | 0x2a21
+ }, {
+ /* PEX: Change PLL BW port0 */
+ SERDES_UNIT_PEX, 0x0,
+ (0x4F << 16) | 0x6219, 0x0, (0x4F << 16) | 0x6219
+ }, {
+ /* SATA: Slew rate change port 0 */
+ SERDES_UNIT_SATA, 0x0083C, 0x8a31, 0x0083C, 0x8a31
+ }, {
+ /* SATA: Slew rate change port 0 */
+ SERDES_UNIT_SATA, 0x00834, 0xc928, 0x00834, 0xc928
+ }, {
+ /* SATA: Slew rate change port 0 */
+ SERDES_UNIT_SATA, 0x00838, 0x30f0, 0x00838, 0x30f0
+ }, {
+ /* SATA: Slew rate change port 0 */
+ SERDES_UNIT_SATA, 0x00840, 0x30f5, 0x00840, 0x30f5
+ }, {
+ /* SGMII: FFE setting Port0 */
+ SERDES_UNIT_SGMII0, 0x00E18, 0x989F, 0x00E18, 0x989F
+ }, {
+ /* SGMII: SELMUP and SELMUF Port0 */
+ SERDES_UNIT_SGMII0, 0x00E38, 0x10FA, 0x00E38, 0x10FA
+ }, {
+ /* SGMII: Amplitude new setting gen2 Port3 */
+ SERDES_UNIT_SGMII0, 0x00E34, 0xC968, 0x00E34, 0xC66C
+ }, {
+ /* QSGMII: Amplitude and slew rate change */
+ SERDES_UNIT_QSGMII, 0x72E34, 0xaa58, 0x72E34, 0xaa58
+ }, {
+ /* QSGMII: SELMUP and SELMUF */
+ SERDES_UNIT_QSGMII, 0x72e38, 0x10aF, 0x72e38, 0x10aF
+ }, {
+ /* QSGMII: 0x72e18 */
+ SERDES_UNIT_QSGMII, 0x72e18, 0x98AC, 0x72e18, 0x98AC
+ }, {
+ /* Null terminated */
+ SERDES_UNIT_UNCONNECTED, 0, 0
+ }
+};
+
+MV_BIN_SERDES_CFG db88f78xx0_serdes_cfg[] = {
+ /* Z1B */
+ {MV_PEX_ROOT_COMPLEX, 0x32221111, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* Default */
+ {MV_PEX_ROOT_COMPLEX, 0x31211111, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* PEX module */
+ /* Z1A */
+ {MV_PEX_ROOT_COMPLEX, 0x32220000, 0x00000000,
+ {PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED,
+ PEX_BUS_DISABLED}, 0x0030, serdes_change_m_phy}, /* Default - Z1A */
+ {MV_PEX_ROOT_COMPLEX, 0x31210000, 0x00000000,
+ {PEX_BUS_DISABLED, PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0030, serdes_change_m_phy} /* PEX module - Z1A */
+};
+
+MV_BIN_SERDES_CFG db88f78xx0rev2_serdes_cfg[] = {
+ /* A0 */
+ {MV_PEX_ROOT_COMPLEX, 0x33221111, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* Default: No Pex module, PEX0 x1, disabled */
+ {MV_PEX_ROOT_COMPLEX, 0x33211111, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x1, PEX1 x1 */
+ {MV_PEX_ROOT_COMPLEX, 0x33221111, 0x11111111,
+ {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* no Pex module, PEX0 x4, PEX1 disabled */
+ {MV_PEX_ROOT_COMPLEX, 0x33211111, 0x11111111,
+ {PEX_BUS_MODE_X4, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x4, PEX1 x1 */
+ {MV_PEX_ROOT_COMPLEX, 0x11111111, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x1, PEX1 x4 */
+ {MV_PEX_ROOT_COMPLEX, 0x11111111, 0x11111111,
+ {PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x4, PEX1 x4 */
+};
+
+MV_BIN_SERDES_CFG rd78460nas_serdes_cfg[] = {
+ {MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy}, /* Default */
+ {MV_PEX_ROOT_COMPLEX, 0x33320201, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x00f4, serdes_change_m_phy}, /* Switch module */
+};
+
+MV_BIN_SERDES_CFG rd78460_serdes_cfg[] = {
+ {MV_PEX_ROOT_COMPLEX, 0x22321111, 0x00000000,
+ {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0010, serdes_change_m_phy}, /* CPU0 */
+ {MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
+ {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0010, serdes_change_m_phy} /* CPU1-3 */
+};
+
+MV_BIN_SERDES_CFG rd78460server_rev2_serdes_cfg[] = {
+ {MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
+ {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0010, serdes_change_m_phy}, /* CPU0 */
+ {MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
+ {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0010, serdes_change_m_phy} /* CPU1-3 */
+};
+
+MV_BIN_SERDES_CFG db78X60pcac_serdes_cfg[] = {
+ {MV_PEX_END_POINT, 0x22321111, 0x00000000,
+ {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0010, serdes_change_m_phy} /* Default */
+};
+
+MV_BIN_SERDES_CFG db78X60pcacrev2_serdes_cfg[] = {
+ {MV_PEX_END_POINT, 0x23321111, 0x00000000,
+ {PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0010, serdes_change_m_phy} /* Default */
+};
+
+MV_BIN_SERDES_CFG fpga88f78xx0_serdes_cfg[] = {
+ {MV_PEX_ROOT_COMPLEX, 0x00000000, 0x00000000,
+ {PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
+ 0x0000, serdes_change_m_phy} /* No PEX in FPGA */
+};
+
+MV_BIN_SERDES_CFG db78X60amc_serdes_cfg[] = {
+ {MV_PEX_ROOT_COMPLEX, 0x33111111, 0x00010001,
+ {PEX_BUS_MODE_X4, PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X1},
+ 0x0030, serdes_change_m_phy} /* Default */
+};
+
+/*
+ * ARMADA-XP CUSTOMER BOARD
+ */
+MV_BIN_SERDES_CFG rd78460customer_serdes_cfg[] = {
+ {MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x00000030, serdes_change_m_phy}, /* Default */
+ {MV_PEX_ROOT_COMPLEX, 0x33320201, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x00000030, serdes_change_m_phy}, /* Switch module */
+};
+
+MV_BIN_SERDES_CFG rd78460AXP_GP_serdes_cfg[] = {
+ {MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
+ {PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
+ 0x0030, serdes_change_m_phy} /* Default */
+};
+
+MV_BIN_SERDES_CFG *serdes_info_tbl[] = {
+ db88f78xx0_serdes_cfg,
+ rd78460_serdes_cfg,
+ db78X60pcac_serdes_cfg,
+ fpga88f78xx0_serdes_cfg,
+ db88f78xx0rev2_serdes_cfg,
+ rd78460nas_serdes_cfg,
+ db78X60amc_serdes_cfg,
+ db78X60pcacrev2_serdes_cfg,
+ rd78460server_rev2_serdes_cfg,
+ rd78460AXP_GP_serdes_cfg,
+ rd78460customer_serdes_cfg
+};
+
+u8 rd78460gp_twsi_dev[] = { 0x4C, 0x4D, 0x4E };
+u8 db88f78xx0rev2_twsi_dev[] = { 0x4C, 0x4D, 0x4E, 0x4F };
diff --git a/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h
new file mode 100644
index 000000000..b920f5ef0
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ */
+
+#ifndef __HIGHSPEED_ENV_SPEC_H
+#define __HIGHSPEED_ENV_SPEC_H
+
+#include "../../../drivers/ddr/marvell/axp/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/roms/u-boot/arch/arm/mach-mvebu/spl.c b/roms/u-boot/arch/arm/mach-mvebu/spl.c
new file mode 100644
index 000000000..16ebb7a59
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/spl.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014-2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <debug_uart.h>
+#include <fdtdec.h>
+#include <hang.h>
+#include <init.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+static u32 get_boot_device(void)
+{
+ u32 val;
+ u32 boot_device;
+
+ /*
+ * First check, if UART boot-mode is active. This can only
+ * be done, via the bootrom error register. Here the
+ * MSB marks if the UART mode is active.
+ */
+ val = readl(CONFIG_BOOTROM_ERR_REG);
+ boot_device = (val & BOOTROM_ERR_MODE_MASK) >> BOOTROM_ERR_MODE_OFFS;
+ debug("BOOTROM_REG=0x%08x boot_device=0x%x\n", val, boot_device);
+ if (boot_device == BOOTROM_ERR_MODE_UART)
+ return BOOT_DEVICE_UART;
+
+#ifdef CONFIG_ARMADA_38X
+ /*
+ * If the bootrom error code contains any other than zeros it's an
+ * error condition and the bootROM has fallen back to UART boot
+ */
+ boot_device = (val & BOOTROM_ERR_CODE_MASK) >> BOOTROM_ERR_CODE_OFFS;
+ if (boot_device)
+ return BOOT_DEVICE_UART;
+#endif
+
+ /*
+ * Now check the SAR register for the strapped boot-device
+ */
+ val = readl(CONFIG_SAR_REG); /* SAR - Sample At Reset */
+ boot_device = (val & BOOT_DEV_SEL_MASK) >> BOOT_DEV_SEL_OFFS;
+ debug("SAR_REG=0x%08x boot_device=0x%x\n", val, boot_device);
+ switch (boot_device) {
+#if defined(CONFIG_ARMADA_38X)
+ case BOOT_FROM_NAND:
+ return BOOT_DEVICE_NAND;
+#endif
+#ifdef CONFIG_SPL_MMC_SUPPORT
+ case BOOT_FROM_MMC:
+ case BOOT_FROM_MMC_ALT:
+ return BOOT_DEVICE_MMC1;
+#endif
+ case BOOT_FROM_UART:
+#ifdef BOOT_FROM_UART_ALT
+ case BOOT_FROM_UART_ALT:
+#endif
+ return BOOT_DEVICE_UART;
+#ifdef BOOT_FROM_SATA
+ case BOOT_FROM_SATA:
+ case BOOT_FROM_SATA_ALT:
+ return BOOT_DEVICE_SATA;
+#endif
+ case BOOT_FROM_SPI:
+ default:
+ return BOOT_DEVICE_SPI;
+ };
+}
+
+u32 spl_boot_device(void)
+{
+ return get_boot_device();
+}
+
+void board_init_f(ulong dummy)
+{
+ int ret;
+
+ /*
+ * 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();
+
+ /* Example code showing how to enable the debug UART on MVEBU */
+#ifdef EARLY_UART
+ /*
+ * Debug UART can be used from here if required:
+ *
+ * debug_uart_init();
+ * printch('a');
+ * printhex8(0x1234);
+ * printascii("string");
+ */
+#endif
+
+ /*
+ * Use special translation offset for SPL. This needs to be
+ * configured *before* spl_init() is called as this function
+ * calls dm_init() which calls the bind functions of the
+ * device drivers. Here the base address needs to be configured
+ * (translated) correctly.
+ */
+ gd->translation_offset = 0xd0000000 - 0xf1000000;
+
+ ret = spl_init();
+ if (ret) {
+ debug("spl_init() failed: %d\n", ret);
+ hang();
+ }
+
+ preloader_console_init();
+
+ timer_init();
+
+ /* Armada 375 does not support SerDes and DDR3 init yet */
+#if !defined(CONFIG_ARMADA_375)
+ /* First init the serdes PHY's */
+ serdes_phy_config();
+
+ /* Setup DDR */
+ ddr3_init();
+#endif
+
+ /* Initialize Auto Voltage Scaling */
+ mv_avs_init();
+
+ /* Update read timing control for PCIe */
+ mv_rtc_config();
+
+ /*
+ * Return to the BootROM to continue the Marvell xmodem
+ * UART boot protocol. As initiated by the kwboot tool.
+ *
+ * This can only be done by the BootROM and not by the
+ * U-Boot SPL infrastructure, since the beginning of the
+ * image is already read and interpreted by the BootROM.
+ * SPL has no chance to receive this information. So we
+ * need to return to the BootROM to enable this xmodem
+ * UART download.
+ *
+ * If booting from NAND lets let the BootROM load the
+ * rest of the bootloader.
+ */
+ switch (get_boot_device()) {
+ case BOOT_DEVICE_UART:
+#if defined(CONFIG_ARMADA_38X)
+ case BOOT_DEVICE_NAND:
+#endif
+ return_to_bootrom();
+ }
+}
diff --git a/roms/u-boot/arch/arm/mach-mvebu/timer.c b/roms/u-boot/arch/arm/mach-mvebu/timer.c
new file mode 100644
index 000000000..557a37877
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-mvebu/timer.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * Copyright (C) 2015 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/io.h>
+#include <asm/arch/soc.h>
+#include <linux/bitops.h>
+
+#define TIMER_LOAD_VAL 0xffffffff
+
+static int init_done __section(".data") = 0;
+
+/*
+ * Timer initialization
+ */
+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, MVEBU_TIMER_BASE + 0x10);
+ writel(TIMER_LOAD_VAL, MVEBU_TIMER_BASE + 0x14);
+
+#if defined(CONFIG_ARCH_MVEBU)
+ /* On Armada XP / 38x ..., the 25MHz clock source needs to be enabled */
+ setbits_le32(MVEBU_TIMER_BASE + 0x00, BIT(11));
+#endif
+ /* enable timer in auto reload mode */
+ setbits_le32(MVEBU_TIMER_BASE + 0x00, 0x3);
+
+ return 0;
+}