[U-Boot] [PATCH v1 09/12] arm: mvebu: Add Armada 38x SERDES / PHY init code from Marvell bin_hdr

Stefan Roese sr at denx.de
Wed Jun 3 11:18:28 CEST 2015


This code is ported from the Marvell bin_hdr code into mainline
SPL U-Boot. It needs to be executed very early so that the devices
connected to the serdes PHY are configured correctly.

Signed-off-by: Stefan Roese <sr at denx.de>
---

 arch/arm/mach-mvebu/Makefile                       |    1 +
 arch/arm/mach-mvebu/serdes/a38x/Makefile           |   10 +
 arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c         |  347 +++
 arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h         |   82 +
 .../serdes/a38x/high_speed_env_spec-38x.c          |  158 ++
 .../mach-mvebu/serdes/a38x/high_speed_env_spec.c   | 2228 ++++++++++++++++++++
 .../mach-mvebu/serdes/a38x/high_speed_env_spec.h   |  251 +++
 .../serdes/a38x/high_speed_topology_spec-38x.c     | 1009 +++++++++
 .../serdes/a38x/high_speed_topology_spec.h         |  124 ++
 arch/arm/mach-mvebu/serdes/a38x/seq_exec.c         |  170 ++
 arch/arm/mach-mvebu/serdes/a38x/seq_exec.h         |   65 +
 arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c      |  388 ++++
 arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h      |  372 ++++
 13 files changed, 5205 insertions(+)
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/Makefile
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/seq_exec.h
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
 create mode 100644 arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h

diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 9cdbefd..446ce04 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -20,6 +20,7 @@ obj-y	+= timer.o
 obj-$(CONFIG_SPL_BUILD) += spl.o
 obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o
 
+obj-$(CONFIG_SYS_MVEBU_DDR_A38X) += serdes/a38x/
 obj-$(CONFIG_SYS_MVEBU_DDR_AXP)	+= serdes/axp/
 
 endif
diff --git a/arch/arm/mach-mvebu/serdes/a38x/Makefile b/arch/arm/mach-mvebu/serdes/a38x/Makefile
new file mode 100644
index 0000000..1503da8
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/Makefile
@@ -0,0 +1,10 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD)	= ctrl_pex.o
+obj-$(CONFIG_SPL_BUILD)	+= high_speed_env_spec.o
+obj-$(CONFIG_SPL_BUILD)	+= high_speed_env_spec-38x.o
+obj-$(CONFIG_SPL_BUILD)	+= high_speed_topology_spec-38x.o
+obj-$(CONFIG_SPL_BUILD)	+= seq_exec.o
+obj-$(CONFIG_SPL_BUILD)	+= sys_env_lib.o
diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
new file mode 100644
index 0000000..5f223f9
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ctrl_pex.h"
+#include "sys_env_lib.h"
+
+int hws_pex_config(struct serdes_map *serdes_map)
+{
+	u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg,
+	    temp_reg, addr, dev_id, ctrl_mode;
+	enum serdes_type serdes_type;
+	u32 idx, max_lane_num;
+
+	DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
+
+	max_lane_num = hws_serdes_get_max_lane();
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		/* configuration for PEX only */
+		if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
+		    (serdes_type != PEX2) && (serdes_type != PEX3))
+			continue;
+
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		pex_idx = serdes_type - PEX0;
+		tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx));
+		tmp &= ~(0xf << 20);
+		tmp |= (0x4 << 20);
+		reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp);
+	}
+
+	tmp = reg_read(SOC_CTRL_REG);
+	tmp &= ~0x03;
+
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		switch (serdes_type) {
+		case PEX0:
+			tmp |= 0x1 << PCIE0_ENABLE_OFFS;
+			break;
+		case PEX1:
+			tmp |= 0x1 << PCIE1_ENABLE_OFFS;
+			break;
+		case PEX2:
+			tmp |= 0x1 << PCIE2_ENABLE_OFFS;
+			break;
+		case PEX3:
+			tmp |= 0x1 << PCIE3_ENABLE_OFFS;
+			break;
+		default:
+			break;
+		}
+	}
+
+	reg_write(SOC_CTRL_REG, tmp);
+
+	/* Support gen1/gen2 */
+	DEBUG_INIT_FULL_S("Support gen1/gen2\n");
+	next_busno = 0;
+	mdelay(150);
+
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		DEBUG_INIT_FULL_S(" serdes_type=0x");
+		DEBUG_INIT_FULL_D(serdes_type, 8);
+		DEBUG_INIT_FULL_S("\n");
+		DEBUG_INIT_FULL_S(" idx=0x");
+		DEBUG_INIT_FULL_D(idx, 8);
+		DEBUG_INIT_FULL_S("\n");
+
+		/* Configuration for PEX only */
+		if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
+		    (serdes_type != PEX2) && (serdes_type != PEX3))
+			continue;
+
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		pex_idx = serdes_type - PEX0;
+		tmp = reg_read(PEX_DBG_STATUS_REG(pex_idx));
+
+		first_busno = next_busno;
+		if ((tmp & 0x7f) != 0x7e) {
+			DEBUG_INIT_S("PCIe, Idx ");
+			DEBUG_INIT_D(pex_idx, 1);
+			DEBUG_INIT_S(": detected no link\n");
+			continue;
+		}
+
+		next_busno++;
+		temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS
+					 (pex_idx, PEX_LINK_CAPABILITY_REG)));
+		temp_pex_reg &= 0xf;
+		if (temp_pex_reg != 0x2)
+			continue;
+
+		temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS(
+					     pex_idx,
+					     PEX_LINK_CTRL_STAT_REG)) &
+			    0xf0000) >> 16;
+
+		/* Check if the link established is GEN1 */
+		DEBUG_INIT_FULL_S
+			("Checking if the link established is gen1\n");
+		if (temp_reg != 0x1)
+			continue;
+
+		pex_local_bus_num_set(pex_idx, first_busno);
+		pex_local_dev_num_set(pex_idx, 1);
+		DEBUG_INIT_FULL_S("PCIe, Idx ");
+		DEBUG_INIT_FULL_D(pex_idx, 1);
+
+		DEBUG_INIT_S(":** Link is Gen1, check the EP capability\n");
+		/* link is Gen1, check the EP capability */
+		addr = pex_config_read(pex_idx, first_busno, 0, 0, 0x34) & 0xff;
+		DEBUG_INIT_FULL_C("pex_config_read: return addr=0x%x", addr, 4);
+		if (addr == 0xff) {
+			DEBUG_INIT_FULL_C
+				("pex_config_read: return 0xff -->PCIe (%d): Detected No Link.",
+				 pex_idx, 1);
+			continue;
+		}
+
+		while ((pex_config_read(pex_idx, first_busno, 0, 0, addr)
+			& 0xff) != 0x10) {
+			addr = (pex_config_read(pex_idx, first_busno, 0,
+						0, addr) & 0xff00) >> 8;
+		}
+
+		/* Check for Gen2 and above */
+		if ((pex_config_read(pex_idx, first_busno, 0, 0,
+				     addr + 0xc) & 0xf) < 0x2) {
+			DEBUG_INIT_S("PCIe, Idx ");
+			DEBUG_INIT_D(pex_idx, 1);
+			DEBUG_INIT_S(": remains Gen1\n");
+			continue;
+		}
+
+		tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx));
+		DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
+		tmp &= ~(BIT(0) | BIT(1));
+		tmp |= BIT(1);
+		tmp |= BIT(6);	/* Select Deemphasize (-3.5d_b) */
+		reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
+		DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
+
+		tmp = reg_read(PEX_CTRL_REG(pex_idx));
+		DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp);
+		tmp |= BIT(10);
+		reg_write(PEX_CTRL_REG(pex_idx), tmp);
+		DEBUG_WR_REG(PEX_CTRL_REG(pex_idx), tmp);
+
+		/*
+		 * We need to wait 10ms before reading the PEX_DBG_STATUS_REG
+		 * in order not to read the status of the former state
+		 */
+		mdelay(10);
+
+		DEBUG_INIT_S("PCIe, Idx ");
+		DEBUG_INIT_D(pex_idx, 1);
+		DEBUG_INIT_S
+			(": Link upgraded to Gen2 based on client cpabilities\n");
+	}
+
+	/* Update pex DEVICE ID */
+	ctrl_mode = sys_env_model_get();
+
+	for (idx = 0; idx < max_lane_num; idx++) {
+		serdes_type = serdes_map[idx].serdes_type;
+		/* configuration for PEX only */
+		if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
+		    (serdes_type != PEX2) && (serdes_type != PEX3))
+			continue;
+
+		if ((serdes_type != PEX0) &&
+		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
+			/* for PEX by4 - relevant for the first port only */
+			continue;
+		}
+
+		pex_idx = serdes_type - PEX0;
+		dev_id = reg_read(PEX_CFG_DIRECT_ACCESS
+				  (pex_idx, PEX_DEVICE_AND_VENDOR_ID));
+		dev_id &= 0xffff;
+		dev_id |= ((ctrl_mode << 16) & 0xffff0000);
+		reg_write(PEX_CFG_DIRECT_ACCESS
+			  (pex_idx, PEX_DEVICE_AND_VENDOR_ID), dev_id);
+	}
+	DEBUG_INIT_FULL_C("Update PEX Device ID ", ctrl_mode, 4);
+
+	return MV_OK;
+}
+
+int pex_local_bus_num_set(u32 pex_if, u32 bus_num)
+{
+	u32 pex_status;
+
+	DEBUG_INIT_FULL_S("\n### pex_local_bus_num_set ###\n");
+
+	if (bus_num >= MAX_PEX_BUSSES) {
+		DEBUG_INIT_C("pex_local_bus_num_set: Illegal bus number %d\n",
+			     bus_num, 4);
+		return MV_BAD_PARAM;
+	}
+
+	pex_status = reg_read(PEX_STATUS_REG(pex_if));
+	pex_status &= ~PXSR_PEX_BUS_NUM_MASK;
+	pex_status |=
+	    (bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK;
+	reg_write(PEX_STATUS_REG(pex_if), pex_status);
+
+	return MV_OK;
+}
+
+int pex_local_dev_num_set(u32 pex_if, u32 dev_num)
+{
+	u32 pex_status;
+
+	DEBUG_INIT_FULL_S("\n### pex_local_dev_num_set ###\n");
+
+	pex_status = reg_read(PEX_STATUS_REG(pex_if));
+	pex_status &= ~PXSR_PEX_DEV_NUM_MASK;
+	pex_status |=
+	    (dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK;
+	reg_write(PEX_STATUS_REG(pex_if), pex_status);
+
+	return MV_OK;
+}
+
+/*
+ * pex_config_read - Read from configuration space
+ *
+ * DESCRIPTION:
+ *       This function performs a 32 bit read from PEX configuration space.
+ *       It supports both type 0 and type 1 of Configuration Transactions
+ *       (local and over bridge). In order to read from local bus segment, use
+ *       bus number retrieved from pex_local_bus_num_get(). Other bus numbers
+ *       will result configuration transaction of type 1 (over bridge).
+ *
+ * INPUT:
+ *       pex_if   - PEX interface number.
+ *       bus      - PEX segment bus number.
+ *       dev      - PEX device number.
+ *       func     - Function number.
+ *       reg_offs - Register offset.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       32bit register data, 0xffffffff on error
+ */
+u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off)
+{
+	u32 pex_data = 0;
+	u32 local_dev, local_bus;
+	u32 pex_status;
+
+	pex_status = reg_read(PEX_STATUS_REG(pex_if));
+	local_dev =
+	    ((pex_status & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS);
+	local_bus =
+	    ((pex_status & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS);
+
+	/*
+	 * In PCI Express we have only one device number
+	 * and this number is the first number we encounter
+	 * else that the local_dev
+	 * spec pex define return on config read/write on any device
+	 */
+	if (bus == local_bus) {
+		if (local_dev == 0) {
+			/*
+			 * if local dev is 0 then the first number we encounter
+			 * after 0 is 1
+			 */
+			if ((dev != 1) && (dev != local_dev))
+				return MV_ERROR;
+		} else {
+			/*
+			 * if local dev is not 0 then the first number we
+			 * encounter is 0
+			 */
+			if ((dev != 0) && (dev != local_dev))
+				return MV_ERROR;
+		}
+	}
+
+	/* Creating PEX address to be passed */
+	pex_data = (bus << PXCAR_BUS_NUM_OFFS);
+	pex_data |= (dev << PXCAR_DEVICE_NUM_OFFS);
+	pex_data |= (func << PXCAR_FUNC_NUM_OFFS);
+	/* Legacy register space */
+	pex_data |= (reg_off & PXCAR_REG_NUM_MASK);
+	/* Extended register space */
+	pex_data |= (((reg_off & PXCAR_REAL_EXT_REG_NUM_MASK) >>
+		      PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS);
+	pex_data |= PXCAR_CONFIG_EN;
+
+	/* Write the address to the PEX configuration address register */
+	reg_write(PEX_CFG_ADDR_REG(pex_if), pex_data);
+
+	/*
+	 * In order to let the PEX controller absorbed the address
+	 * of the read transaction we perform a validity check that
+	 * the address was written
+	 */
+	if (pex_data != reg_read(PEX_CFG_ADDR_REG(pex_if)))
+		return MV_ERROR;
+
+	/* Cleaning Master Abort */
+	reg_bit_set(PEX_CFG_DIRECT_ACCESS(pex_if, PEX_STATUS_AND_COMMAND),
+		    PXSAC_MABORT);
+	/* Read the Data returned in the PEX Data register */
+	pex_data = reg_read(PEX_CFG_DATA_REG(pex_if));
+
+	DEBUG_INIT_FULL_C(" --> ", pex_data, 4);
+
+	return pex_data;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
new file mode 100644
index 0000000..5032759
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _CTRL_PEX_H
+#define _CTRL_PEX_H
+
+#include "high_speed_env_spec.h"
+
+/* Sample at Reset */
+#define MPP_SAMPLE_AT_RESET(id)		(0xe4200 + (id * 4))
+
+/* PCI Express Control and Status Registers */
+#define MAX_PEX_BUSSES			256
+
+#define MISC_REGS_OFFSET		0x18200
+#define MV_MISC_REGS_BASE		MISC_REGS_OFFSET
+#define SOC_CTRL_REG			(MV_MISC_REGS_BASE + 0x4)
+
+#define PEX_CAPABILITIES_REG(if)	((PEX_IF_REGS_BASE(if)) + 0x60)
+#define PEX_LINK_CTRL_STATUS2_REG(if)	((PEX_IF_REGS_BASE(if)) + 0x90)
+#define PEX_CTRL_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x1a00)
+#define PEX_STATUS_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x1a04)
+#define PEX_DBG_STATUS_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x1a64)
+#define PEX_LINK_CAPABILITY_REG		0x6c
+#define PEX_LINK_CTRL_STAT_REG		0x70
+#define PXSR_PEX_DEV_NUM_OFFS		16  /* Device Number Indication */
+#define PXSR_PEX_DEV_NUM_MASK		(0x1f << PXSR_PEX_DEV_NUM_OFFS)
+#define PXSR_PEX_BUS_NUM_OFFS		8 /* Bus Number Indication */
+#define PXSR_PEX_BUS_NUM_MASK		(0xff << PXSR_PEX_BUS_NUM_OFFS)
+
+/* PEX_CAPABILITIES_REG fields */
+#define PCIE0_ENABLE_OFFS		0
+#define PCIE0_ENABLE_MASK		(0x1 << PCIE0_ENABLE_OFFS)
+#define PCIE1_ENABLE_OFFS		1
+#define PCIE1_ENABLE_MASK		(0x1 << PCIE1_ENABLE_OFFS)
+#define PCIE2_ENABLE_OFFS		2
+#define PCIE2_ENABLE_MASK		(0x1 << PCIE2_ENABLE_OFFS)
+#define PCIE3_ENABLE_OFFS		3
+#define PCIE4_ENABLE_MASK		(0x1 << PCIE3_ENABLE_OFFS)
+
+/* Controller revision info */
+#define PEX_DEVICE_AND_VENDOR_ID	0x000
+
+/* PCI Express Configuration Address Register */
+#define PXCAR_REG_NUM_OFFS		2
+#define PXCAR_REG_NUM_MAX		0x3f
+#define PXCAR_REG_NUM_MASK		(PXCAR_REG_NUM_MAX << \
+					 PXCAR_REG_NUM_OFFS)
+#define PXCAR_FUNC_NUM_OFFS		8
+#define PXCAR_FUNC_NUM_MAX		0x7
+#define PXCAR_FUNC_NUM_MASK		(PXCAR_FUNC_NUM_MAX << \
+					 PXCAR_FUNC_NUM_OFFS)
+#define PXCAR_DEVICE_NUM_OFFS		11
+#define PXCAR_DEVICE_NUM_MAX		0x1f
+#define PXCAR_DEVICE_NUM_MASK		(PXCAR_DEVICE_NUM_MAX << \
+					 PXCAR_DEVICE_NUM_OFFS)
+#define PXCAR_BUS_NUM_OFFS		16
+#define PXCAR_BUS_NUM_MAX		0xff
+#define PXCAR_BUS_NUM_MASK		(PXCAR_BUS_NUM_MAX << \
+					 PXCAR_BUS_NUM_OFFS)
+#define PXCAR_EXT_REG_NUM_OFFS		24
+#define PXCAR_EXT_REG_NUM_MAX		0xf
+
+#define PEX_CFG_ADDR_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x18f8)
+#define PEX_CFG_DATA_REG(if)		((PEX_IF_REGS_BASE(if)) + 0x18fc)
+
+#define PXCAR_REAL_EXT_REG_NUM_OFFS	8
+#define PXCAR_REAL_EXT_REG_NUM_MASK	(0xf << PXCAR_REAL_EXT_REG_NUM_OFFS)
+
+#define PXCAR_CONFIG_EN			BIT(31)
+#define PEX_STATUS_AND_COMMAND		0x004
+#define PXSAC_MABORT			BIT(29) /* Recieved Master Abort */
+
+int hws_pex_config(struct serdes_map *serdes_map);
+int pex_local_bus_num_set(u32 pex_if, u32 bus_num);
+int pex_local_dev_num_set(u32 pex_if, u32 dev_num);
+u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off);
+
+#endif
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c
new file mode 100644
index 0000000..5ff8567
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_env_spec.h"
+#include "sys_env_lib.h"
+
+#define SERDES_VERION	"2.0"
+
+u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = {
+	/* 0  1    2    3    4    5 */
+	{0x1, 0x1, NA,  NA,  NA,  NA},		/* PEX0 */
+	{NA,  0x2, 0x1, NA,  0x1, NA},		/* PEX1 */
+	{NA,  NA,  0x2, NA,  NA,  0x1},		/* PEX2 */
+	{NA,  NA,  NA,  0x1, NA,  NA},		/* PEX3 */
+	{0x2, 0x3, NA,  NA,  NA,  NA},		/* SATA0 */
+	{NA,  NA,  0x3, NA,  0x2, NA},		/* SATA1 */
+	{NA,  NA,  NA,  NA,  0x6, 0x2},		/* SATA2 */
+	{NA,  NA,  NA,  0x3, NA,  NA},		/* SATA3 */
+	{0x3, 0x4, NA,  NA,  NA,  NA},		/* SGMII0 */
+	{NA,  0x5, 0x4, NA,  0x3, NA},		/* SGMII1 */
+	{NA,  NA,  NA,  0x4, NA,  0x3},		/* SGMII2 */
+	{NA,  0x7, NA,  NA,  NA,  NA},		/* QSGMII */
+	{NA,  0x6, NA,  NA,  0x4, NA},		/* USB3_HOST0 */
+	{NA,  NA,  NA,  0x5, NA,  0x4},		/* USB3_HOST1 */
+	{NA,  NA,  NA,  0x6, 0x5, 0x5},		/* USB3_DEVICE */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}		/* DEFAULT_SERDES */
+};
+
+int hws_serdes_seq_init(void)
+{
+	DEBUG_INIT_FULL_S("\n### serdes_seq_init ###\n");
+
+	if (hws_serdes_seq_db_init() != MV_OK) {
+		printf("hws_serdes_seq_init: Error: Serdes initialization fail\n");
+		return MV_FAIL;
+	}
+
+	return MV_OK;
+}
+
+int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up,
+			     enum serdes_type serdes_type,
+			     enum serdes_speed baud_rate,
+			     enum serdes_mode serdes_mode,
+			     enum ref_clock ref_clock)
+{
+	return MV_NOT_SUPPORTED;
+}
+
+u32 hws_serdes_silicon_ref_clock_get(void)
+{
+	DEBUG_INIT_FULL_S("\n### hws_serdes_silicon_ref_clock_get ###\n");
+
+	return REF_CLOCK_25MHZ;
+}
+
+u32 hws_serdes_get_max_lane(void)
+{
+	switch (sys_env_device_id_get()) {
+	case MV_6811:		/* A381/A3282: 6811/6821: single/dual cpu */
+		return 4;
+	case MV_6810:
+		return 5;
+	case MV_6820:
+	case MV_6828:
+		return 6;
+	default:		/* not the right module */
+		printf("%s: Device ID Error, using 4 SerDes lanes\n",
+		       __func__);
+		return 4;
+	}
+	return 6;
+}
+
+int hws_is_serdes_active(u8 lane_num)
+{
+	int ret = 1;
+
+	/* Maximum lane count for A388 (6828) is 6 */
+	if (lane_num > 6)
+		ret = 0;
+
+	/* 4th Lane (#4 on Device 6810 is not Active */
+	if (sys_env_device_id_get() == MV_6810 && lane_num == 4) {
+		printf("%s: Error: Lane#4 on Device 6810 is not Active.\n",
+		       __func__);
+		return 0;
+	}
+
+	/*
+	 * 6th Lane (#5) on Device 6810 is Active, even though 6810
+	 * has only 5 lanes
+	 */
+	if (sys_env_device_id_get() == MV_6810 && lane_num == 5)
+		return 1;
+
+	if (lane_num >= hws_serdes_get_max_lane())
+		ret = 0;
+
+	return ret;
+}
+
+int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset,
+			  u32 *unit_base_reg, u32 *unit_offset)
+{
+	*unit_base_reg = base_addr;
+	*unit_offset = unit_base_offset;
+
+	return MV_OK;
+}
+
+/*
+ * hws_serdes_get_phy_selector_val
+ *
+ * DESCRIPTION: Get the mapping of Serdes Selector values according to the
+ *              Serdes revision number
+ * INPUT:    serdes_num - Serdes number
+ *           serdes_type - Serdes type
+ * OUTPUT: None
+ * RETURN:
+ *       Mapping of Serdes Selector values
+ */
+u32 hws_serdes_get_phy_selector_val(int serdes_num,
+				    enum serdes_type serdes_type)
+{
+	if (serdes_type >= LAST_SERDES_TYPE)
+		return 0xff;
+
+	if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+		return selectors_serdes_rev1_map
+			[serdes_type][serdes_num];
+	} else
+		return selectors_serdes_rev2_map
+			[serdes_type][serdes_num];
+}
+
+u32 hws_get_physical_serdes_num(u32 serdes_num)
+{
+	if ((serdes_num == 4) && (sys_env_device_id_get() == MV_6810)) {
+		/*
+		 * For 6810, there are 5 Serdes and Serdes Num 4 doesn't
+		 * exist. Instead Serdes Num 5 is connected.
+		 */
+		return 5;
+	} else {
+		return serdes_num;
+	}
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
new file mode 100644
index 0000000..23af769
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
@@ -0,0 +1,2228 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_env_spec.h"
+#include "high_speed_topology_spec.h"
+#include "sys_env_lib.h"
+#include "ctrl_pex.h"
+
+#if defined(CONFIG_ARMADA_38X)
+#elif defined(CONFIG_ARMADA_39X)
+#else
+#error "No device is defined"
+#endif
+
+/*
+ * The board topology map, initialized in the beginning of
+ * ctrl_high_speed_serdes_phy_config
+ */
+struct serdes_map serdes_configuration_map[MAX_SERDES_LANES];
+
+/*
+ * serdes_seq_db - holds all serdes sequences, their size and the
+ * relevant index in the data array initialized in serdes_seq_init
+ */
+struct cfg_seq serdes_seq_db[SERDES_LAST_SEQ];
+
+#define	SERDES_VERION		"2.0"
+#define ENDED_OK		"High speed PHY - Ended Successfully\n"
+
+#define LINK_WAIT_CNTR		100
+#define LINK_WAIT_SLEEP		100
+
+#define MAX_UNIT_NUMB		4
+#define TOPOLOGY_TEST_OK	0
+#define WRONG_NUMBER_OF_UNITS	1
+#define SERDES_ALREADY_IN_USE	2
+#define UNIT_NUMBER_VIOLATION	3
+
+/*
+ * serdes_lane_in_use_count contains the exact amount of serdes lanes
+ * needed per type
+ */
+u8 serdes_lane_in_use_count[MAX_UNITS_ID][MAX_UNIT_NUMB] = {
+	/* 0  1  2  3  */
+	{  1, 1, 1, 1 },	/* PEX     */
+	{  1, 1, 1, 1 },	/* ETH_GIG */
+	{  1, 1, 0, 0 },	/* USB3H   */
+	{  1, 1, 1, 0 },	/* USB3D   */
+	{  1, 1, 1, 1 },	/* SATA    */
+	{  1, 0, 0, 0 },	/* QSGMII  */
+	{  4, 0, 0, 0 },	/* XAUI    */
+	{  2, 0, 0, 0 }		/* RXAUI   */
+};
+
+/*
+ * serdes_unit_count count unit number.
+ * (i.e a single XAUI is counted as 1 unit)
+ */
+u8 serdes_unit_count[MAX_UNITS_ID] = { 0 };
+
+/* Selector mapping for A380-A0 and A390-Z1 */
+u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = {
+	/* 0      1      2       3       4       5       6 */
+	{ 0x1,   0x1,    NA,	 NA,	 NA,	 NA,     NA  }, /* PEX0 */
+	{ NA,    NA,     0x1,	 NA,	 0x1,	 NA,     0x1 }, /* PEX1 */
+	{ NA,    NA,     NA,	 NA,	 0x7,	 0x1,    NA  }, /* PEX2 */
+	{ NA,    NA,     NA,	 0x1,	 NA,	 NA,     NA  }, /* PEX3 */
+	{ 0x2,   0x3,    NA,	 NA,	 NA,	 NA,     NA  }, /* SATA0 */
+	{ NA,    NA,     0x3,	 NA,	 NA,	 NA,     NA  }, /* SATA1 */
+	{ NA,    NA,     NA,	 NA,	 0x6,	 0x2,    NA  }, /* SATA2 */
+	{ NA,	 NA,     NA,	 0x3,	 NA,	 NA,     NA  }, /* SATA3 */
+	{ 0x3,   0x4,    NA,     NA,	 NA,	 NA,     NA  }, /* SGMII0 */
+	{ NA,    0x5,    0x4,    NA,	 0x3,	 NA,     NA  }, /* SGMII1 */
+	{ NA,    NA,     NA,	 0x4,	 NA,	 0x3,    NA  }, /* SGMII2 */
+	{ NA,    0x7,    NA,	 NA,	 NA,	 NA,     NA  }, /* QSGMII */
+	{ NA,    0x6,    NA,	 NA,	 0x4,	 NA,     NA  }, /* USB3_HOST0 */
+	{ NA,    NA,     NA,	 0x5,	 NA,	 0x4,    NA  }, /* USB3_HOST1 */
+	{ NA,    NA,     NA,	 0x6,	 0x5,	 0x5,    NA  }, /* USB3_DEVICE */
+#ifdef CONFIG_ARMADA_39X
+	{ NA,    NA,     0x5,	 NA,	 0x8,	 NA,     0x2 }, /* SGMII3 */
+	{ NA,    NA,     NA,	 0x8,	 0x9,	 0x8,    0x4 }, /* XAUI */
+	{ NA,    NA,     NA,	 NA,	 NA,	 0x8,    0x4 }, /* RXAUI */
+#endif
+	{ 0x0,   0x0,    0x0,	 0x0,	 0x0,	 0x0,    NA  }  /* DEFAULT_SERDES */
+};
+
+/* Selector mapping for PEX by 4 confiuration */
+u8 common_phys_selectors_pex_by4_lanes[] = { 0x1, 0x2, 0x2, 0x2 };
+
+static const char *const serdes_type_to_string[] = {
+	"PCIe0",
+	"PCIe1",
+	"PCIe2",
+	"PCIe3",
+	"SATA0",
+	"SATA1",
+	"SATA2",
+	"SATA3",
+	"SGMII0",
+	"SGMII1",
+	"SGMII2",
+	"QSGMII",
+	"USB3 HOST0",
+	"USB3 HOST1",
+	"USB3 DEVICE",
+	"SGMII3",
+	"XAUI",
+	"RXAUI",
+	"DEFAULT SERDES",
+	"LAST_SERDES_TYPE"
+};
+
+struct serdes_unit_data {
+	u8 serdes_unit_id;
+	u8 serdes_unit_num;
+};
+
+static struct serdes_unit_data serdes_type_to_unit_info[] = {
+	{PEX_UNIT_ID, 0,},
+	{PEX_UNIT_ID, 1,},
+	{PEX_UNIT_ID, 2,},
+	{PEX_UNIT_ID, 3,},
+	{SATA_UNIT_ID, 0,},
+	{SATA_UNIT_ID, 1,},
+	{SATA_UNIT_ID, 2,},
+	{SATA_UNIT_ID, 3,},
+	{ETH_GIG_UNIT_ID, 0,},
+	{ETH_GIG_UNIT_ID, 1,},
+	{ETH_GIG_UNIT_ID, 2,},
+	{QSGMII_UNIT_ID, 0,},
+	{USB3H_UNIT_ID, 0,},
+	{USB3H_UNIT_ID, 1,},
+	{USB3D_UNIT_ID, 0,},
+	{ETH_GIG_UNIT_ID, 3,},
+	{XAUI_UNIT_ID, 0,},
+	{RXAUI_UNIT_ID, 0,},
+};
+
+/* Sequences DB */
+
+/*
+ * SATA and SGMII
+ */
+
+struct op_params sata_port0_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Access to reg 0x48(OOB param 1) */
+	{SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0},
+	/* OOB Com_wake and Com_reset spacing upper limit data */
+	{SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0},
+	/* Access to reg 0xa(PHY Control) */
+	{SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0},
+	/* Rx clk and Tx clk select non-inverted mode */
+	{SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0},
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0},
+	/* Power Down Sata Port 0 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40040,}, 0, 0},
+};
+
+struct op_params sata_port1_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Access to reg 0x48(OOB param 1) */
+	{SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0},
+	/* OOB Com_wake and Com_reset spacing upper limit data */
+	{SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0},
+	/* Access to reg 0xa(PHY Control) */
+	{SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0},
+	/* Rx clk and Tx clk select non-inverted mode */
+	{SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0},
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0},
+	/* Power Down Sata Port 1 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc44000,}, 0, 0},
+};
+
+/* SATA and SGMII - power up seq */
+struct op_params sata_and_sgmii_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	/* Power Up */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x90006, {0x80002, 0x80002},
+	 0, 0},
+	/* Unreset */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0x6000}, 0, 0},
+	/* Phy Selector */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x0e0, {0x0, 0x80}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x440, {0x440, 0x400}, 0, 0}
+};
+
+/* SATA and SGMII - speed config seq */
+struct op_params sata_and_sgmii_speed_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data,
+	 * SGMII (1.25G), SGMII (3.125G), wait_time, num_of_loops
+	 */
+	/* Baud Rate */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000,
+	 {0x8800000, 0x19800000, 0x22000000}, 0, 0},
+	/* Select Baud Rate for SATA only */
+	{INTERFACE_REG, 0x800, 0xc00, {0x800, NO_DATA, NO_DATA}, 0, 0},
+	/* Phy Gen RX and TX */
+	{ISOLATE_REG, 0x800, 0xff, {NO_DATA, 0x66, 0x66}, 0, 0},
+	/* Bus Width */
+	{LOOPBACK_REG, 0x800, 0xe, {0x4, 0x2, 0x2}, 0, 0}
+};
+
+/* SATA and SGMII - TX config seq */
+struct op_params sata_and_sgmii_tx_config_params1[] = {
+	/*
+	 * unitunit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	{GLUE_REG, 0x800, 0x1800, {NO_DATA, 0x800}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0},
+	/* Power up PLL, RX and TX */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0000, {0x70000, 0x70000},
+	 0, 0}
+};
+
+struct op_params sata_port0_tx_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0},
+	/* Power Down Sata  Port 0 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40000}, 0, 0},
+	/* Regret bit addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0},
+	/* Regret bit data */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0}
+};
+
+struct op_params sata_port1_tx_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* Power Down Sata addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0},
+	/* Power Down Sata Port 1 */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc40000}, 0, 0},
+	/* Regret bit addr */
+	{SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0},
+	/* Regret bit data */
+	{SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0}
+};
+
+struct op_params sata_and_sgmii_tx_config_serdes_rev1_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000},
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000}
+};
+
+struct op_params sata_and_sgmii_tx_config_serdes_rev2_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, SGMII data,
+	 * wait_time, num_of_loops
+	 */
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000},
+	/* Assert Rx Init for SGMII */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x40000000},
+	 0, 0},
+	/* Assert Rx Init for SATA */
+	{ISOLATE_REG, 0x800, 0x400, {0x400, NA}, 0, 0},
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000},
+	/* De-assert Rx Init for SGMII */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x0}, 0, 0},
+	/* De-assert Rx Init for SATA */
+	{ISOLATE_REG, 0x800, 0x400, {0x0, NA}, 0, 0},
+	/* os_ph_offset_force (align 90) */
+	{RX_REG3, 0x800, 0xff, {0xde, NO_DATA}, 0, 0},
+	/* Set os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0},
+	/* Unset os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0},
+};
+
+struct op_params sata_electrical_config_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* enable SSC and DFE update enable */
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000,}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000,}, 0, 0},
+	/* SQ_THRESH and FFE Setting */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x6cf,}, 0, 0},
+	/* G1_TX SLEW, EMPH1 and AMP */
+	{G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32,}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9,}, 0, 0},
+	/* G2_TX SLEW, EMPH1 and AMP */
+	{G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c,}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0},
+	/* G3_TX SLEW, EMPH1 and AMP */
+	{G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e,}, 0, 0},
+	/* G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G3_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0},
+	/* Cal rxclkalign90 ext enable and Cal os ph ext */
+	{CAL_REG6, 0x800, 0xff00, {0xdd00,}, 0, 0},
+	/* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0},
+};
+
+struct op_params sata_electrical_config_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SATA data, wait_time,
+	 * num_of_loops
+	 */
+	/* SQ_THRESH and FFE Setting */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xf00, {0x600}, 0, 0},
+	/* enable SSC and DFE update enable */
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000}, 0, 0},
+	/* G1_TX SLEW, EMPH1 and AMP */
+	{G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G2_TX SLEW, EMPH1 and AMP */
+	{G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0},
+	/* G3_TX SLEW, EMPH1 and AMP */
+	{G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e}, 0, 0},
+	/*
+	 * G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI & DFE_En Gen3,
+	 * DC wander calibration dis
+	 */
+	{G3_SETTINGS_1_REG, 0x800, 0x47ff, {0x7d2}, 0, 0},
+	/* Bit[12]=0x0 idle_sync_en */
+	{PCIE_REG0, 0x800, 0x1000, {0x0}, 0, 0},
+	/* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0},
+	/* DFE_STEP_FINE_FX[3:0] =0xa */
+	{DFE_REG0, 0x800, 0xa00f, {0x800a}, 0, 0},
+	/* DFE_EN and Dis Update control from pin disable */
+	{DFE_REG3, 0x800, 0xc000, {0x0}, 0, 0},
+	/* FFE Force FFE_REs and cap settings for Gen1 */
+	{G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0},
+	/* FFE Force FFE_REs and cap settings for Gen2 */
+	{G2_SETTINGS_3_REG, 0x800, 0xff, {0xbf}, 0, 0},
+	/* FE Force FFE_REs=4 and cap settings for Gen3n */
+	{G3_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0},
+	/* Set DFE Gen 3 Resolution to 3 */
+	{G3_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0},
+};
+
+struct op_params sgmii_electrical_config_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G),
+	 * wait_time, num_of_loops
+	 */
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0},
+	/* SQ_THRESH and FFE Setting */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x8f, 0xbf}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000, 0x4000}, 0, 0},
+};
+
+struct op_params sgmii_electrical_config_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G),
+	 * wait_time, num_of_loops
+	 */
+	/* Set Slew_rate, Emph and Amp */
+	{G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8fa, 0x8fa}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0},
+	/* DTL_FLOOP_EN */
+	{RX_REG2, 0x800, 0x4, {0x0, 0x0}, 0, 0},
+	/* G1 FFE Setting Force, RES and CAP */
+	{G1_SETTINGS_3_REG, 0x800, 0xff, {0x8f, 0xbf}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000, 0x3000}, 0, 0},
+};
+
+/*
+ * PEX and USB3
+ */
+
+/* PEX and USB3 - power up seq for Serdes Rev 1.2 */
+struct op_params pex_and_usb3_power_up_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806,
+	 {0x4471804, 0x4479804}, 0, 0},
+	{COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0},
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0},
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0},
+	{GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0}
+};
+
+/* PEX and USB3 - power up seq for Serdes Rev 2.1 */
+struct op_params pex_and_usb3_power_up_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806,
+	 {0x4471804, 0x4479804}, 0, 0},
+	{COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0},
+	{COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0},
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0},
+	{GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0},
+	{GLOBAL_MISC_CTRL, 0x800, 0xc0, {0x0, NO_DATA}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0}
+};
+
+/* PEX and USB3 - speed config seq */
+struct op_params pex_and_usb3_speed_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	/* Maximal PHY Generation Setting */
+	{INTERFACE_REG, 0x800, 0xc00, {0x400, 0x400, 0x400, 0x400, 0x400},
+	 0, 0},
+};
+
+struct op_params usb3_electrical_config_serdes_rev1_params[] = {
+	/* Spread Spectrum Clock Enable */
+	{LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0},
+	/* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */
+	{G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0},
+	/* FFE Setting Force, RES and CAP */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xef}, 0, 0},
+	/* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70}, 0, 0},
+	/* cal_rxclkalign90_ext_en and cal_os_ph_ext */
+	{CAL_REG6, 0x800, 0xff00, {0xd500}, 0, 0},
+	/* vco_cal_vth_sel */
+	{REF_REG0, 0x800, 0x38, {0x20}, 0, 0},
+};
+
+struct op_params usb3_electrical_config_serdes_rev2_params[] = {
+	/* Spread Spectrum Clock Enable */
+	{LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0},
+	/* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */
+	{G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0},
+	/* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */
+	{RX_REG2, 0x800, 0xf0, {0x70}, 0, 0},
+	/* vco_cal_vth_sel */
+	{REF_REG0, 0x800, 0x38, {0x20}, 0, 0},
+	/* Spread Spectrum Clock Enable */
+	{LANE_CFG5_REG, 0x800, 0x4, {0x4}, 0, 0},
+};
+
+/* PEX and USB3 - TX config seq */
+
+/*
+ * For PEXx1: the pex_and_usb3_tx_config_params1/2/3 configurations should run
+ *            one by one on the lane.
+ * For PEXx4: the pex_and_usb3_tx_config_params1/2/3 configurations should run
+ *            by setting each sequence for all 4 lanes.
+ */
+struct op_params pex_and_usb3_tx_config_params1[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	{GLOBAL_CLK_CTRL, 0x800, 0x1, {0x0, 0x0}, 0, 0},
+	/* 10ms delay */
+	{0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0},
+	/* os_ph_offset_force (align 90) */
+	{RX_REG3, 0x800, 0xff, {0xdc, NO_DATA}, 0, 0},
+	/* Set os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0},
+	/* Unset os_ph_valid */
+	{RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0},
+};
+
+struct op_params pex_and_usb3_tx_config_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0},
+};
+
+struct op_params pex_and_usb3_tx_config_params3[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, USB3 data,
+	 * wait_time, num_of_loops
+	 */
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0},
+	/* 10ms delay */
+	{0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0}
+};
+
+/* PEX by 4 config seq */
+struct op_params pex_by4_config_params[] = {
+	/* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */
+	{GLOBAL_CLK_SRC_HI, 0x800, 0x7, {0x5, 0x0, 0x0, 0x2}, 0, 0},
+	/* Lane Alignement enable */
+	{LANE_ALIGN_REG0, 0x800, 0x1000, {0x0, 0x0, 0x0, 0x0}, 0, 0},
+	/* Max PLL phy config */
+	{CALIBRATION_CTRL_REG, 0x800, 0x1000, {0x1000, 0x1000, 0x1000, 0x1000},
+	 0, 0},
+	/* Max PLL pipe config */
+	{LANE_CFG1_REG, 0x800, 0x600, {0x600, 0x600, 0x600, 0x600}, 0, 0},
+};
+
+/* USB3 device donfig seq */
+struct op_params usb3_device_config_params[] = {
+	/* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */
+	{LANE_CFG4_REG, 0x800, 0x200, {0x200}, 0, 0}
+};
+
+/* PEX - electrical configuration seq Rev 1.2 */
+struct op_params pex_electrical_config_serdes_rev1_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */
+	{G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* CFG_DFE_EN_SEL */
+	{LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0},
+	/* FFE Setting Force, RES and CAP */
+	{SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xaf}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0},
+	/* cal_rxclkalign90_ext_en and cal_os_ph_ext */
+	{CAL_REG6, 0x800, 0xff00, {0xdc00}, 0, 0},
+};
+
+/* PEX - electrical configuration seq Rev 2.1 */
+struct op_params pex_electrical_config_serdes_rev2_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */
+	{G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0},
+	/* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G1 FFE Setting Force, RES and CAP */
+	{G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0},
+	/* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */
+	{G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0},
+	/* G2 FFE Setting Force, RES and CAP */
+	{G2_SETTINGS_3_REG, 0x800, 0xff, {0xaf}, 0, 0},
+	/* G2 DFE resolution value */
+	{G2_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0},
+	/* DFE resolution force */
+	{DFE_REG0, 0x800, 0x8000, {0x8000}, 0, 0},
+	/* Tx amplitude for Tx Margin 0 */
+	{PCIE_REG1, 0x800, 0xf80, {0xd00}, 0, 0},
+	/* Tx_Emph value for -3.5d_b and -6d_b */
+	{PCIE_REG3, 0x800, 0xff00, {0xaf00}, 0, 0},
+	/* CFG_DFE_EN_SEL */
+	{LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0},
+	/* tximpcal_th and rximpcal_th */
+	{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0},
+};
+
+/* PEX - configuration seq for REF_CLOCK_25MHz */
+struct op_params pex_config_ref_clock25_m_hz[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* Bits[4:0]=0x2 - REF_FREF_SEL */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x2}, 0, 0},
+	/* Bit[10]=0x1   - REFCLK_SEL */
+	{MISC_REG, 0x800, 0x400, {0x400}, 0, 0},
+	/* Bits[7:0]=0x7 - CFG_PM_RXDLOZ_WAIT */
+	{GLOBAL_PM_CTRL, 0x800, 0xff, {0x7}, 0, 0},
+};
+
+/* PEX - configuration seq for REF_CLOCK_40MHz */
+struct op_params pex_config_ref_clock40_m_hz[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* Bits[4:0]=0x3 - REF_FREF_SEL */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x3}, 0, 0},
+	/* Bits[10]=0x1  - REFCLK_SEL */
+	{MISC_REG, 0x800, 0x400, {0x400}, 0, 0},
+	/* Bits[7:0]=0xc - CFG_PM_RXDLOZ_WAIT */
+	{GLOBAL_PM_CTRL, 0x800, 0xff, {0xc}, 0, 0},
+};
+
+/* PEX - configuration seq for REF_CLOCK_100MHz */
+struct op_params pex_config_ref_clock100_m_hz[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, PEX data, wait_time,
+	 * num_of_loops
+	 */
+	/* Bits[4:0]=0x0  - REF_FREF_SEL */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x0}, 0, 0},
+	/* Bit[10]=0x0    - REFCLK_SEL */
+	{MISC_REG, 0x800, 0x400, {0x0}, 0, 0},
+	/* Bits[7:0]=0x1e - CFG_PM_RXDLOZ_WAIT */
+	{GLOBAL_PM_CTRL, 0x800, 0xff, {0x1e}, 0, 0},
+};
+
+/*
+ *    USB2
+ */
+
+struct op_params usb2_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, USB2 data, wait_time,
+	 * num_of_loops
+	 */
+	/* Init phy 0 */
+	{0x18440, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0},
+	/* Init phy 1 */
+	{0x18444, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0},
+	/* Init phy 2 */
+	{0x18448, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0},
+	/* Phy offset 0x0 - PLL_CONTROL0  */
+	{0xc0000, 0x0 /*NA*/, 0xffffffff, {0x40605205}, 0, 0},
+	{0xc001c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0},
+	{0xc201c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0},
+	{0xc401c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0},
+	/* Phy offset 0x1 - PLL_CONTROL1 */
+	{0xc0004, 0x0 /*NA*/, 0x1, {0x1}, 0, 0},
+	/* Phy0 register 3  - TX Channel control 0 */
+	{0xc000c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
+	/* Phy0 register 3  - TX Channel control 0 */
+	{0xc200c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
+	/* Phy0 register 3  - TX Channel control 0 */
+	{0xc400c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
+	/* check PLLCAL_DONE is set and IMPCAL_DONE is set */
+	{0xc0008, 0x0 /*NA*/, 0x80800000, {0x80800000}, 1, 1000},
+	/* check REG_SQCAL_DONE  is set */
+	{0xc0018, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000},
+	/* check PLL_READY  is set */
+	{0xc0000, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000}
+};
+
+/*
+ *    QSGMII
+ */
+
+/* QSGMII - power up seq */
+struct op_params qsgmii_port_power_up_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Connect the QSGMII to Gigabit Ethernet units */
+	{QSGMII_CONTROL_REG1, 0x0, 0x40000000, {0x40000000}, 0, 0},
+	/* Power Up */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0006, {0x80002}, 0, 0},
+	/* Unreset */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000}, 0, 0},
+	/* Phy Selector */
+	{POWER_AND_PLL_CTRL_REG, 0x800, 0xff, {0xfc81}, 0, 0},
+	/* Ref clock source select */
+	{MISC_REG, 0x800, 0x4c0, {0x480}, 0, 0}
+};
+
+/* QSGMII - speed config seq */
+struct op_params qsgmii_port_speed_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Baud Rate */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000, {0xcc00000}, 0, 0},
+	/* Phy Gen RX and TX */
+	{ISOLATE_REG, 0x800, 0xff, {0x33}, 0, 0},
+	/* Bus Width */
+	{LOOPBACK_REG, 0x800, 0xe, {0x2}, 0, 0}
+};
+
+/* QSGMII - Select electrical param seq */
+struct op_params qsgmii_port_electrical_config_params[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Slew rate and emphasis */
+	{G1_SETTINGS_0_REG, 0x800, 0x8000, {0x0}, 0, 0}
+};
+
+/* QSGMII - TX config seq */
+struct op_params qsgmii_port_tx_config_params1[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	{GLUE_REG, 0x800, 0x1800, {0x800}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x401}, 0, 0},
+	/* Sft Reset pulse */
+	{RESET_DFE_REG, 0x800, 0x401, {0x0}, 0, 0},
+	/* Lane align */
+	{LANE_ALIGN_REG0, 0x800, 0x1000, {0x1000}, 0, 0},
+	/* Power up PLL, RX and TX */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x70000, {0x70000}, 0, 0},
+	/* Tx driver output idle */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x80000, {0x80000}, 0, 0}
+};
+
+struct op_params qsgmii_port_tx_config_params2[] = {
+	/*
+	 * unit_base_reg, unit_offset, mask, QSGMII data, wait_time,
+	 * num_of_loops
+	 */
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc}, 10, 1000},
+	/* Assert Rx Init and Tx driver output valid */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40080000, {0x40000000}, 0, 0},
+	/* Wait for PHY power up sequence to finish */
+	{COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1}, 1, 1000},
+	/* De-assert Rx Init */
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {0x0}, 0, 0}
+};
+
+/* SERDES_POWER_DOWN */
+struct op_params serdes_power_down_params[] = {
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, (0xf << 11), {(0x3 << 11)},
+	 0, 0},
+	{COMMON_PHY_CONFIGURATION1_REG, 0x28, (0x7 << 16), {0}, 0, 0}
+};
+
+/*
+ * hws_ctrl_serdes_rev_get
+ *
+ * DESCRIPTION: Get the Serdes revision number
+ *
+ * INPUT: config_field - Field description enum
+ *
+ * OUTPUT: None
+ *
+ * RETURN:
+ *		8bit Serdes revision number
+ */
+u8 hws_ctrl_serdes_rev_get(void)
+{
+#ifdef CONFIG_ARMADA_38X
+	/* for A38x-Z1 */
+	if (sys_env_device_rev_get() == MV_88F68XX_Z1_ID)
+		return MV_SERDES_REV_1_2;
+#endif
+
+	/* for A39x-Z1, A38x-A0 */
+	return MV_SERDES_REV_2_1;
+}
+
+u32 hws_serdes_topology_verify(enum serdes_type serdes_type, u32 serdes_id,
+			       enum serdes_mode serdes_mode)
+{
+	u32 test_result = 0;
+	u8 serd_max_num, unit_numb;
+	enum unit_id unit_id;
+
+	if (serdes_type > RXAUI) {
+		printf("%s: Warning: Wrong serdes type %s serdes#%d\n",
+		       __func__, serdes_type_to_string[serdes_type], serdes_id);
+		return MV_FAIL;
+	}
+
+	unit_id = serdes_type_to_unit_info[serdes_type].serdes_unit_id;
+	unit_numb = serdes_type_to_unit_info[serdes_type].serdes_unit_num;
+	serd_max_num = sys_env_unit_max_num_get(unit_id);
+
+	/* if didn't exceed amount of required Serdes lanes for current type */
+	if (serdes_lane_in_use_count[unit_id][unit_numb] != 0) {
+		/* update amount of required Serdes lanes for current type */
+		serdes_lane_in_use_count[unit_id][unit_numb]--;
+
+		/*
+		 * If reached the exact amount of required Serdes lanes for
+		 * current type
+		 */
+		if (serdes_lane_in_use_count[unit_id][unit_numb] == 0) {
+			if (((serdes_type <= PEX3)) &&
+			    ((serdes_mode == PEX_END_POINT_X4) ||
+			     (serdes_mode == PEX_ROOT_COMPLEX_X4))) {
+				/* PCiex4 uses 2 SerDes */
+				serdes_unit_count[PEX_UNIT_ID] += 2;
+			} else {
+				serdes_unit_count[unit_id]++;
+			}
+
+			/* test SoC unit count limitation */
+			if (serdes_unit_count[unit_id] > serd_max_num) {
+				test_result = WRONG_NUMBER_OF_UNITS;
+			} else if (unit_numb >= serd_max_num) {
+				/* test SoC unit number limitation */
+				test_result = UNIT_NUMBER_VIOLATION;
+			}
+		}
+	} else {
+		test_result = SERDES_ALREADY_IN_USE;
+		if (test_result == SERDES_ALREADY_IN_USE) {
+			printf("%s: Error: serdes lane %d is configured to type %s: type already in use\n",
+			       __func__, serdes_id,
+			       serdes_type_to_string[serdes_type]);
+			return MV_FAIL;
+		} else if (test_result == WRONG_NUMBER_OF_UNITS) {
+			printf("%s: Warning: serdes lane %d is set to type %s.\n",
+			       __func__, serdes_id,
+			       serdes_type_to_string[serdes_type]);
+			printf("%s: Maximum supported lanes are already set to this type (limit = %d)\n",
+			       __func__, serd_max_num);
+			return MV_FAIL;
+		} else if (test_result == UNIT_NUMBER_VIOLATION) {
+			printf("%s: Warning: serdes lane %d type is %s: current device support only %d units of this type.\n",
+			       __func__, serdes_id,
+			       serdes_type_to_string[serdes_type],
+			       serd_max_num);
+			return MV_FAIL;
+		}
+	}
+
+	return MV_OK;
+}
+
+void hws_serdes_xaui_topology_verify(void)
+{
+	/*
+	 * If XAUI is in use - serdes_lane_in_use_count has to be = 0;
+	 * if it is not in use hast be = 4
+	 */
+	if ((serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 0) &&
+	    (serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 4)) {
+		printf("%s: Warning: wrong number of lanes is set to XAUI - %d\n",
+		       __func__, serdes_lane_in_use_count[XAUI_UNIT_ID][0]);
+		printf("%s: XAUI has to be defined on 4 lanes\n", __func__);
+	}
+
+	/*
+	 * If RXAUI is in use - serdes_lane_in_use_count has to be = 0;
+	 * if it is not in use hast be = 2
+	 */
+	if ((serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 0) &&
+	    (serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 2)) {
+		printf("%s: Warning: wrong number of lanes is set to RXAUI - %d\n",
+		       __func__, serdes_lane_in_use_count[RXAUI_UNIT_ID][0]);
+		printf("%s: RXAUI has to be defined on 2 lanes\n", __func__);
+	}
+}
+
+int hws_serdes_seq_db_init(void)
+{
+	u8 serdes_rev = hws_ctrl_serdes_rev_get();
+
+	DEBUG_INIT_FULL_S("\n### serdes_seq38x_init ###\n");
+
+	if (serdes_rev == MV_SERDES_REV_NA) {
+		printf("hws_serdes_seq_db_init: serdes revision number is not supported\n");
+		return MV_NOT_SUPPORTED;
+	}
+
+	/* SATA_PORT_0_ONLY_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].op_params_ptr =
+	    sata_port0_power_up_params;
+	serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_port0_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].data_arr_idx = SATA;
+
+	/* SATA_PORT_1_ONLY_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].op_params_ptr =
+	    sata_port1_power_up_params;
+	serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_port1_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].data_arr_idx = SATA;
+
+	/* SATA_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SATA_POWER_UP_SEQ].op_params_ptr =
+	    sata_and_sgmii_power_up_params;
+	serdes_seq_db[SATA_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_POWER_UP_SEQ].data_arr_idx = SATA;
+
+	/* SATA_1_5_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_3_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_6_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sata_electrical_config_serdes_rev1_params;
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sata_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sata_electrical_config_serdes_rev2_params;
+		serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sata_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_TX_CONFIG_SEQ1].op_params_ptr =
+	    sata_and_sgmii_tx_config_params1;
+	serdes_seq_db[SATA_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[SATA_TX_CONFIG_SEQ1].data_arr_idx = SATA;
+
+	/* SATA_PORT_0_ONLY_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].op_params_ptr =
+	    sata_port0_tx_config_params;
+	serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_port0_tx_config_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_PORT_1_ONLY_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].op_params_ptr =
+	    sata_port1_tx_config_params;
+	serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_port1_tx_config_params) / sizeof(struct op_params);
+	serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA;
+
+	/* SATA_TX_CONFIG_SEQ2 sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev1_params2;
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev2_params2;
+		serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SATA_TX_CONFIG_SEQ2].data_arr_idx = SATA;
+
+	/* SGMII_POWER_UP_SEQ sequence init */
+	serdes_seq_db[SGMII_POWER_UP_SEQ].op_params_ptr =
+	    sata_and_sgmii_power_up_params;
+	serdes_seq_db[SGMII_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[SGMII_POWER_UP_SEQ].data_arr_idx = SGMII;
+
+	/* SGMII_1_25_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].data_arr_idx = SGMII;
+
+	/* SGMII_3_125_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].op_params_ptr =
+	    sata_and_sgmii_speed_config_params;
+	serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(sata_and_sgmii_speed_config_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].data_arr_idx = SGMII_3_125;
+
+	/* SGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sgmii_electrical_config_serdes_rev1_params;
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sgmii_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    sgmii_electrical_config_serdes_rev2_params;
+		serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(sgmii_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SGMII;
+
+	/* SGMII_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ1].op_params_ptr =
+	    sata_and_sgmii_tx_config_params1;
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ1].data_arr_idx = SGMII;
+
+	/* SGMII_TX_CONFIG_SEQ sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev1_params2;
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr =
+		    sata_and_sgmii_tx_config_serdes_rev2_params2;
+		serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[SGMII_TX_CONFIG_SEQ2].data_arr_idx = SGMII;
+
+	/* PEX_POWER_UP_SEQ sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev1_params;
+		serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev2_params;
+		serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[PEX_POWER_UP_SEQ].data_arr_idx = PEX;
+
+	/* PEX_2_5_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].data_arr_idx =
+		PEXSERDES_SPEED_2_5_GBPS;
+
+	/* PEX_5_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].data_arr_idx =
+		PEXSERDES_SPEED_5_GBPS;
+
+	/* PEX_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    pex_electrical_config_serdes_rev1_params;
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(pex_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    pex_electrical_config_serdes_rev2_params;
+		serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(pex_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].data_arr_idx = PEX;
+
+	/* PEX_TX_CONFIG_SEQ1 sequence init */
+	serdes_seq_db[PEX_TX_CONFIG_SEQ1].op_params_ptr =
+	    pex_and_usb3_tx_config_params1;
+	serdes_seq_db[PEX_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[PEX_TX_CONFIG_SEQ1].data_arr_idx = PEX;
+
+	/* PEX_TX_CONFIG_SEQ2 sequence init */
+	serdes_seq_db[PEX_TX_CONFIG_SEQ2].op_params_ptr =
+	    pex_and_usb3_tx_config_params2;
+	serdes_seq_db[PEX_TX_CONFIG_SEQ2].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params);
+	serdes_seq_db[PEX_TX_CONFIG_SEQ2].data_arr_idx = PEX;
+
+	/* PEX_TX_CONFIG_SEQ3 sequence init */
+	serdes_seq_db[PEX_TX_CONFIG_SEQ3].op_params_ptr =
+	    pex_and_usb3_tx_config_params3;
+	serdes_seq_db[PEX_TX_CONFIG_SEQ3].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params);
+	serdes_seq_db[PEX_TX_CONFIG_SEQ3].data_arr_idx = PEX;
+
+	/* PEX_BY_4_CONFIG_SEQ sequence init */
+	serdes_seq_db[PEX_BY_4_CONFIG_SEQ].op_params_ptr =
+	    pex_by4_config_params;
+	serdes_seq_db[PEX_BY_4_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_by4_config_params) / sizeof(struct op_params);
+	serdes_seq_db[PEX_BY_4_CONFIG_SEQ].data_arr_idx = PEX;
+
+	/* PEX_CONFIG_REF_CLOCK_25MHZ_SEQ sequence init */
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].op_params_ptr =
+	    pex_config_ref_clock25_m_hz;
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].cfg_seq_size =
+	    sizeof(pex_config_ref_clock25_m_hz) / sizeof(struct op_params);
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].data_arr_idx = PEX;
+
+	/* PEX_ELECTRICAL_CONFIG_REF_CLOCK_40MHZ_SEQ sequence init */
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].op_params_ptr =
+	    pex_config_ref_clock40_m_hz;
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].cfg_seq_size =
+	    sizeof(pex_config_ref_clock40_m_hz) / sizeof(struct op_params);
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].data_arr_idx = PEX;
+
+	/* PEX_CONFIG_REF_CLOCK_100MHZ_SEQ sequence init */
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].op_params_ptr =
+	    pex_config_ref_clock100_m_hz;
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].cfg_seq_size =
+	    sizeof(pex_config_ref_clock100_m_hz) / sizeof(struct op_params);
+	serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].data_arr_idx = PEX;
+
+	/* USB3_POWER_UP_SEQ sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev1_params;
+		serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr =
+		    pex_and_usb3_power_up_serdes_rev2_params;
+		serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(pex_and_usb3_power_up_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[USB3_POWER_UP_SEQ].data_arr_idx = USB3;
+
+	/* USB3_HOST_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].data_arr_idx =
+	    USB3SERDES_SPEED_5_GBPS_HOST;
+
+	/* USB3_DEVICE_SPEED_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].op_params_ptr =
+	    pex_and_usb3_speed_config_params;
+	serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params);
+	serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].data_arr_idx =
+	    USB3SERDES_SPEED_5_GBPS_DEVICE;
+
+	/* USB3_ELECTRICAL_CONFIG_SEQ seq sequence init */
+	if (serdes_rev == MV_SERDES_REV_1_2) {
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    usb3_electrical_config_serdes_rev1_params;
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(usb3_electrical_config_serdes_rev1_params) /
+		    sizeof(struct op_params);
+	} else {
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    usb3_electrical_config_serdes_rev2_params;
+		serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(usb3_electrical_config_serdes_rev2_params) /
+		    sizeof(struct op_params);
+	}
+	serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].data_arr_idx = USB3;
+
+	/* USB3_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_TX_CONFIG_SEQ1].op_params_ptr =
+	    pex_and_usb3_tx_config_params1;
+	serdes_seq_db[USB3_TX_CONFIG_SEQ1].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params);
+	serdes_seq_db[USB3_TX_CONFIG_SEQ1].data_arr_idx = USB3;
+
+	/* USB3_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_TX_CONFIG_SEQ2].op_params_ptr =
+	    pex_and_usb3_tx_config_params2;
+	serdes_seq_db[USB3_TX_CONFIG_SEQ2].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params);
+	serdes_seq_db[USB3_TX_CONFIG_SEQ2].data_arr_idx = USB3;
+
+	/* USB3_TX_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_TX_CONFIG_SEQ3].op_params_ptr =
+	    pex_and_usb3_tx_config_params3;
+	serdes_seq_db[USB3_TX_CONFIG_SEQ3].cfg_seq_size =
+	    sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params);
+	serdes_seq_db[USB3_TX_CONFIG_SEQ3].data_arr_idx = USB3;
+
+	/* USB2_POWER_UP_SEQ sequence init */
+	serdes_seq_db[USB2_POWER_UP_SEQ].op_params_ptr = usb2_power_up_params;
+	serdes_seq_db[USB2_POWER_UP_SEQ].cfg_seq_size =
+	    sizeof(usb2_power_up_params) / sizeof(struct op_params);
+	serdes_seq_db[USB2_POWER_UP_SEQ].data_arr_idx = 0;
+
+	/* USB3_DEVICE_CONFIG_SEQ sequence init */
+	serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].op_params_ptr =
+	    usb3_device_config_params;
+	serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].cfg_seq_size =
+	    sizeof(usb3_device_config_params) / sizeof(struct op_params);
+	serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].data_arr_idx = 0;	/* Not relevant */
+
+	/* SERDES_POWER_DOWN_SEQ sequence init */
+	serdes_seq_db[SERDES_POWER_DOWN_SEQ].op_params_ptr =
+	    serdes_power_down_params;
+	serdes_seq_db[SERDES_POWER_DOWN_SEQ].cfg_seq_size =
+	    sizeof(serdes_power_down_params) /
+		sizeof(struct op_params);
+	serdes_seq_db[SERDES_POWER_DOWN_SEQ].data_arr_idx = FIRST_CELL;
+
+	if (serdes_rev == MV_SERDES_REV_2_1) {
+		/* QSGMII_POWER_UP_SEQ sequence init */
+		serdes_seq_db[QSGMII_POWER_UP_SEQ].op_params_ptr =
+		    qsgmii_port_power_up_params;
+		serdes_seq_db[QSGMII_POWER_UP_SEQ].cfg_seq_size =
+		    sizeof(qsgmii_port_power_up_params) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_POWER_UP_SEQ].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_5_SPEED_CONFIG_SEQ sequence init */
+		serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].op_params_ptr =
+		    qsgmii_port_speed_config_params;
+		serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(qsgmii_port_speed_config_params) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */
+		serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr =
+		    qsgmii_port_electrical_config_params;
+		serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size =
+		    sizeof(qsgmii_port_electrical_config_params) /
+		    sizeof(struct op_params);
+		serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_TX_CONFIG_SEQ sequence init */
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].op_params_ptr =
+		    qsgmii_port_tx_config_params1;
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].cfg_seq_size =
+		    sizeof(qsgmii_port_tx_config_params1) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+
+		/* QSGMII_TX_CONFIG_SEQ sequence init */
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].op_params_ptr =
+		    qsgmii_port_tx_config_params2;
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].cfg_seq_size =
+		    sizeof(qsgmii_port_tx_config_params2) /
+			sizeof(struct op_params);
+		serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].data_arr_idx =
+		    QSGMII_SEQ_IDX;
+	}
+
+	return MV_OK;
+}
+
+enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type,
+					      enum serdes_speed baud_rate)
+{
+	enum serdes_seq seq_id = SERDES_LAST_SEQ;
+
+	DEBUG_INIT_FULL_S("\n### serdes_type_and_speed_to_speed_seq ###\n");
+	switch (serdes_type) {
+	case PEX0:
+	case PEX1:
+	case PEX2:
+	case PEX3:
+		if (baud_rate == SERDES_SPEED_2_5_GBPS)
+			seq_id = PEX_2_5_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_5_GBPS)
+			seq_id = PEX_5_SPEED_CONFIG_SEQ;
+		break;
+	case USB3_HOST0:
+	case USB3_HOST1:
+		if (baud_rate == SERDES_SPEED_5_GBPS)
+			seq_id = USB3_HOST_SPEED_CONFIG_SEQ;
+		break;
+	case USB3_DEVICE:
+		if (baud_rate == SERDES_SPEED_5_GBPS)
+			seq_id = USB3_DEVICE_SPEED_CONFIG_SEQ;
+		break;
+	case SATA0:
+	case SATA1:
+	case SATA2:
+	case SATA3:
+		if (baud_rate == SERDES_SPEED_1_5_GBPS)
+			seq_id = SATA_1_5_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_3_GBPS)
+			seq_id = SATA_3_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_6_GBPS)
+			seq_id = SATA_6_SPEED_CONFIG_SEQ;
+		break;
+	case SGMII0:
+	case SGMII1:
+	case SGMII2:
+#ifdef CONFIG_ARMADA_39X
+	case SGMII3:
+#endif
+		if (baud_rate == SERDES_SPEED_1_25_GBPS)
+			seq_id = SGMII_1_25_SPEED_CONFIG_SEQ;
+		else if (baud_rate == SERDES_SPEED_3_125_GBPS)
+			seq_id = SGMII_3_125_SPEED_CONFIG_SEQ;
+		break;
+	case QSGMII:
+		seq_id = QSGMII_5_SPEED_CONFIG_SEQ;
+		break;
+#ifdef CONFIG_ARMADA_39X
+	case XAUI:
+		seq_id = XAUI_3_125_SPEED_CONFIG_SEQ;
+		break;
+	case RXAUI:
+		seq_id = RXAUI_6_25_SPEED_CONFIG_SEQ;
+		break;
+#endif
+	default:
+		return SERDES_LAST_SEQ;
+	}
+
+	return seq_id;
+}
+
+/*
+ * This is the weak default function for the Marvell evaluation or
+ * development boarrds. Like the DB-88F6820-GP and others.
+ * Custom boards should define this function in their board
+ * code (board directory). And overwrite this default function
+ * with this custom specific code.
+ */
+__weak int hws_board_topology_load(struct serdes_map *serdes_map_array)
+{
+	u32 board_id = mv_board_id_get();
+	u32 board_id_index = mv_board_id_index_get(board_id);
+
+	DEBUG_INIT_FULL_S("\n### hws_board_topology_load ###\n");
+	/* getting board topology according to the board id */
+	DEBUG_INIT_FULL_S("Getting board topology according to the board id\n");
+
+	CHECK_STATUS(load_topology_func_arr[board_id_index] (serdes_map_array));
+
+	return MV_OK;
+}
+
+void print_topology_details(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+
+	DEBUG_INIT_S("board SerDes lanes topology details:\n");
+
+	DEBUG_INIT_S(" | Lane #  | Speed |  Type       |\n");
+	DEBUG_INIT_S(" --------------------------------\n");
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		if (serdes_map_array[lane_num].serdes_type == DEFAULT_SERDES)
+			continue;
+		DEBUG_INIT_S(" |   ");
+		DEBUG_INIT_D(hws_get_physical_serdes_num(lane_num), 1);
+		DEBUG_INIT_S("    |  ");
+		DEBUG_INIT_D(serdes_map_array[lane_num].serdes_speed, 2);
+		DEBUG_INIT_S("   |  ");
+		DEBUG_INIT_S((char *)
+			     serdes_type_to_string[serdes_map_array[lane_num].
+						   serdes_type]);
+		DEBUG_INIT_S("\t|\n");
+	}
+	DEBUG_INIT_S(" --------------------------------\n");
+}
+
+int hws_pre_serdes_init_config(void)
+{
+	u32 data;
+
+	/*
+	 * Configure Core PLL
+	 */
+	/*
+	 * set PLL parameters
+	 * bits[2:0]  =0x3 (Core-PLL Kdiv)
+	 * bits[20:12]=0x9f (Core-PLL Ndiv)
+	 * bits[24:21]=0x7(Core-PLL VCO Band)
+	 * bits[28:25]=0x1(Core-PLL Rlf)
+	 * bits[31:29]=0x2(Core-PLL charge-pump adjust)
+	 */
+	reg_write(CORE_PLL_PARAMETERS_REG, 0x42e9f003);
+
+	/* Enable PLL Configuration */
+	data = reg_read(CORE_PLL_CONFIG_REG);
+	data = SET_BIT(data, 9);
+	reg_write(CORE_PLL_CONFIG_REG, data);
+
+	return MV_OK;
+}
+
+int serdes_phy_config(void)
+{
+	DEBUG_INIT_FULL_S("\n### ctrl_high_speed_serdes_phy_config ###\n");
+
+	DEBUG_INIT_S("High speed PHY - Version: ");
+	DEBUG_INIT_S(SERDES_VERION);
+	DEBUG_INIT_S("\n");
+
+	/* Init serdes sequences DB */
+	if (hws_serdes_seq_init() != MV_OK) {
+		printf("hws_ctrl_high_speed_serdes_phy_config: Error: Serdes initialization fail\n");
+		return MV_FAIL;
+	}
+
+	/* I2C init */
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	/* Board topology load */
+	DEBUG_INIT_FULL_S
+	    ("ctrl_high_speed_serdes_phy_config: Loading board topology..\n");
+	CHECK_STATUS(hws_board_topology_load(serdes_configuration_map));
+
+	/* print topology */
+	print_topology_details(serdes_configuration_map);
+	CHECK_STATUS(hws_pre_serdes_init_config());
+
+	/* Power-Up sequence */
+	DEBUG_INIT_FULL_S
+		("ctrl_high_speed_serdes_phy_config: Starting serdes power up sequence\n");
+
+	CHECK_STATUS(hws_power_up_serdes_lanes(serdes_configuration_map));
+
+	DEBUG_INIT_FULL_S
+		("\n### ctrl_high_speed_serdes_phy_config ended successfully ###\n");
+
+	DEBUG_INIT_S(ENDED_OK);
+
+	return MV_OK;
+}
+
+int serdes_polarity_config(u32 serdes_num, int is_rx)
+{
+	u32 data;
+	u32 reg_addr;
+	u8 bit_off = (is_rx) ? 11 : 10;
+
+	reg_addr = SERDES_REGS_LANE_BASE_OFFSET(serdes_num) + SYNC_PATTERN_REG;
+	data = reg_read(reg_addr);
+	data = SET_BIT(data, bit_off);
+	reg_write(reg_addr, data);
+
+	return MV_OK;
+}
+
+int hws_power_up_serdes_lanes(struct serdes_map *serdes_config_map)
+{
+	u32 serdes_id, serdes_lane_num;
+	enum ref_clock ref_clock;
+	enum serdes_type serdes_type;
+	enum serdes_speed serdes_speed;
+	enum serdes_mode serdes_mode;
+	int serdes_rx_polarity_swap;
+	int serdes_tx_polarity_swap;
+	int is_pex_enabled = 0;
+
+	/*
+	 * is_pex_enabled:
+	 * Flag which indicates that one of the Serdes is of PEX.
+	 * In this case, PEX unit will be initialized after Serdes power-up
+	 */
+
+	DEBUG_INIT_FULL_S("\n### hws_power_up_serdes_lanes ###\n");
+
+	/* COMMON PHYS SELECTORS register configuration */
+	DEBUG_INIT_FULL_S
+	    ("hws_power_up_serdes_lanes: Updating COMMON PHYS SELECTORS reg\n");
+	CHECK_STATUS(hws_update_serdes_phy_selectors(serdes_configuration_map));
+
+	/* per Serdes Power Up */
+	for (serdes_id = 0; serdes_id < hws_serdes_get_max_lane();
+	     serdes_id++) {
+		DEBUG_INIT_FULL_S
+		    ("calling serdes_power_up_ctrl: serdes lane number ");
+		DEBUG_INIT_FULL_D_10(serdes_lane_num, 1);
+		DEBUG_INIT_FULL_S("\n");
+
+		serdes_lane_num = hws_get_physical_serdes_num(serdes_id);
+		serdes_type = serdes_config_map[serdes_id].serdes_type;
+		serdes_speed = serdes_config_map[serdes_id].serdes_speed;
+		serdes_mode = serdes_config_map[serdes_id].serdes_mode;
+		serdes_rx_polarity_swap = serdes_config_map[serdes_id].swap_rx;
+		serdes_tx_polarity_swap = serdes_config_map[serdes_id].swap_tx;
+
+		/* serdes lane is not in use */
+		if (serdes_type == DEFAULT_SERDES)
+			continue;
+		else if (serdes_type <= PEX3)	/* PEX type */
+			is_pex_enabled = 1;
+
+		ref_clock = hws_serdes_get_ref_clock_val(serdes_type);
+		if (ref_clock == REF_CLOCK_UNSUPPORTED) {
+			DEBUG_INIT_S
+			    ("hws_power_up_serdes_lanes: unsupported ref clock\n");
+			return MV_NOT_SUPPORTED;
+		}
+		CHECK_STATUS(serdes_power_up_ctrl(serdes_lane_num,
+						  1,
+						  serdes_type,
+						  serdes_speed,
+						  serdes_mode, ref_clock));
+
+		/* RX Polarity config */
+		if (serdes_rx_polarity_swap)
+			CHECK_STATUS(serdes_polarity_config
+				     (serdes_lane_num, 1));
+
+		/* TX Polarity config */
+		if (serdes_tx_polarity_swap)
+			CHECK_STATUS(serdes_polarity_config
+				     (serdes_lane_num, 0));
+	}
+
+	if (is_pex_enabled) {
+		/* Set PEX_TX_CONFIG_SEQ sequence for PEXx4 mode.
+		   After finish the Power_up sequence for all lanes,
+		   the lanes should be released from reset state.       */
+		CHECK_STATUS(hws_pex_tx_config_seq(serdes_config_map));
+
+		/* PEX configuration */
+		CHECK_STATUS(hws_pex_config(serdes_config_map));
+	}
+
+	/* USB2 configuration */
+	DEBUG_INIT_FULL_S("hws_power_up_serdes_lanes: init USB2 Phys\n");
+	CHECK_STATUS(mv_seq_exec(0 /* not relevant */ , USB2_POWER_UP_SEQ));
+
+	DEBUG_INIT_FULL_S
+	    ("### hws_power_up_serdes_lanes ended successfully ###\n");
+
+	return MV_OK;
+}
+
+int ctrl_high_speed_serdes_phy_config(void)
+{
+	return hws_ctrl_high_speed_serdes_phy_config();
+}
+
+static int serdes_pex_usb3_pipe_delay_w_a(u32 serdes_num, u8 serdes_type)
+{
+	u32 reg_data;
+
+	/* WA for A380 Z1 relevant for lanes 3,4,5 only */
+	if (serdes_num >= 3) {
+		reg_data = reg_read(GENERAL_PURPOSE_RESERVED0_REG);
+		/* set delay on pipe -
+		 * When lane 3 is connected to a MAC of Pex -> set bit 7 to 1.
+		 * When lane 3 is connected to a MAC of USB3 -> set bit 7 to 0.
+		 * When lane 4 is connected to a MAC of Pex -> set bit 8 to 1.
+		 * When lane 4 is connected to a MAC of USB3 -> set bit 8 to 0.
+		 * When lane 5 is connected to a MAC of Pex -> set bit 8 to 1.
+		 * When lane 5 is connected to a MAC of USB3 -> set bit 8 to 0.
+		 */
+		if (serdes_type == PEX)
+			reg_data |= 1 << (7 + (serdes_num - 3));
+		if (serdes_type == USB3) {
+			/* USB3 */
+			reg_data &= ~(1 << (7 + (serdes_num - 3)));
+		}
+		reg_write(GENERAL_PURPOSE_RESERVED0_REG, reg_data);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * hws_serdes_pex_ref_clock_satr_get -
+ *
+ * DESCRIPTION: Get the reference clock value from DEVICE_SAMPLE_AT_RESET1_REG
+ *              and check:
+ *              bit[2] for PEX#0, bit[3] for PEX#1, bit[30] for PEX#2, bit[31]
+ *              for PEX#3.
+ *              If bit=0 --> REF_CLOCK_100MHz
+ *              If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=0
+ *              --> REF_CLOCK_25MHz
+ *              If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=1
+ *              --> REF_CLOCK_40MHz
+ *
+ * INPUT:        serdes_type - Type of Serdes
+ *
+ * OUTPUT:       pex_satr   -  Return the REF_CLOCK value:
+ *                            REF_CLOCK_25MHz, REF_CLOCK_40MHz or REF_CLOCK_100MHz
+ *
+ * RETURNS:      MV_OK        - for success
+ *               MV_BAD_PARAM - for fail
+ */
+int hws_serdes_pex_ref_clock_satr_get(enum serdes_type serdes_type, u32 *pex_satr)
+{
+	u32 data, reg_satr1;
+
+	reg_satr1 = reg_read(DEVICE_SAMPLE_AT_RESET1_REG);
+
+	switch (serdes_type) {
+	case PEX0:
+		data = REF_CLK_SELECTOR_VAL_PEX0(reg_satr1);
+		break;
+	case PEX1:
+		data = REF_CLK_SELECTOR_VAL_PEX1(reg_satr1);
+		break;
+	case PEX2:
+		data = REF_CLK_SELECTOR_VAL_PEX2(reg_satr1);
+		break;
+	case PEX3:
+		data = REF_CLK_SELECTOR_VAL_PEX3(reg_satr1);
+		break;
+	default:
+		printf("%s: Error: SerDes type %d is not supported\n",
+		       __func__, serdes_type);
+		return MV_BAD_PARAM;
+	}
+
+	*pex_satr = data;
+
+	return MV_OK;
+}
+
+u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type)
+{
+	u32 pex_satr;
+	enum ref_clock ref_clock;
+
+	DEBUG_INIT_FULL_S("\n### hws_serdes_get_ref_clock_val ###\n");
+
+	if (serdes_type >= LAST_SERDES_TYPE)
+		return REF_CLOCK_UNSUPPORTED;
+
+	/* read ref clock from S at 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 at R */
+	CHECK_STATUS(hws_serdes_pex_ref_clock_satr_get
+		     (serdes_type, &pex_satr));
+
+	if (pex_satr == 0) {
+		return REF_CLOCK_100MHZ;
+	} else if (pex_satr == 1) {
+		/* value of 1 means we can use ref clock from SoC (as other Serdes types) */
+		return ref_clock;
+	} else {
+		printf
+		    ("%s: Error: REF_CLK_SELECTOR_VAL for SerDes type %d is wrong\n",
+		     __func__, serdes_type);
+		return REF_CLOCK_UNSUPPORTED;
+	}
+}
+
+int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up,
+			 enum serdes_type serdes_type,
+			 enum serdes_speed baud_rate,
+			 enum serdes_mode serdes_mode, enum ref_clock ref_clock)
+{
+	u32 sata_idx, pex_idx, sata_port;
+	enum serdes_seq speed_seq_id;
+	u32 reg_data;
+	int is_pex_by1;
+
+	DEBUG_INIT_FULL_S("\n### serdes_power_up_ctrl ###\n");
+
+	if (serdes_power_up == 1) {	/* Serdes power up */
+		DEBUG_INIT_FULL_S
+		    ("serdes_power_up_ctrl: executing power up.. ");
+		DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 2);
+		DEBUG_INIT_FULL_C("serdes type = ", serdes_type, 2);
+
+		DEBUG_INIT_FULL_S("Going access 1");
+
+		/* Getting the Speed Select sequence id */
+		speed_seq_id =
+			serdes_type_and_speed_to_speed_seq(serdes_type,
+							   baud_rate);
+		if (speed_seq_id == SERDES_LAST_SEQ) {
+			printf
+			    ("serdes_power_up_ctrl: serdes type %d and speed %d are not supported together\n",
+			     serdes_type, baud_rate);
+
+			return MV_BAD_PARAM;
+		}
+
+		/* Executing power up, ref clock set, speed config and TX config */
+		switch (serdes_type) {
+		case PEX0:
+		case PEX1:
+		case PEX2:
+		case PEX3:
+			if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+				CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a
+					     (serdes_num, PEX));
+			}
+
+			is_pex_by1 = (serdes_mode == PEX_ROOT_COMPLEX_X1) ||
+				(serdes_mode == PEX_END_POINT_X1);
+			pex_idx = serdes_type - PEX0;
+
+			if ((is_pex_by1 == 1) || (serdes_type == PEX0)) {
+				/* For PEX by 4, init only the PEX 0 */
+				reg_data = reg_read(SOC_CONTROL_REG1);
+				if (is_pex_by1 == 1)
+					reg_data |= 0x4000;
+				else
+					reg_data &= ~0x4000;
+				reg_write(SOC_CONTROL_REG1, reg_data);
+
+				reg_data =
+				    reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+					      0x6c));
+				reg_data &= ~0x3f0;
+				if (is_pex_by1 == 1)
+					reg_data |= 0x10;
+				else
+					reg_data |= 0x40;
+				reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c),
+					  reg_data);
+
+				reg_data =
+				    reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+					      0x6c));
+				reg_data &= ~0xf;
+				reg_data |= 0x2;
+				reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c),
+					  reg_data);
+
+				reg_data =
+				    reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+					      0x70));
+				reg_data &= ~0x40;
+				reg_data |= 0x40;
+				reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x70),
+					  reg_data);
+			}
+
+			CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ));
+			if (is_pex_by1 == 0) {
+				/*
+				 * for PEX by 4 - use the PEX index as the
+				 * seq array index
+				 */
+				serdes_seq_db[PEX_BY_4_CONFIG_SEQ].
+				    data_arr_idx = pex_idx;
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_BY_4_CONFIG_SEQ));
+			}
+
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, PEX_ELECTRICAL_CONFIG_SEQ));
+
+			if (is_pex_by1 == 1) {
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_TX_CONFIG_SEQ2));
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_TX_CONFIG_SEQ3));
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num, PEX_TX_CONFIG_SEQ1));
+			}
+			udelay(20);
+
+			break;
+		case USB3_HOST0:
+		case USB3_HOST1:
+		case USB3_DEVICE:
+			if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+				CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a
+					     (serdes_num, USB3));
+			}
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			if (serdes_type == USB3_DEVICE) {
+				CHECK_STATUS(mv_seq_exec
+					     (serdes_num,
+					      USB3_DEVICE_CONFIG_SEQ));
+			}
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_TX_CONFIG_SEQ2));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, USB3_TX_CONFIG_SEQ3));
+
+			udelay(10000);
+			break;
+		case SATA0:
+		case SATA1:
+		case SATA2:
+		case SATA3:
+			sata_idx = ((serdes_type == SATA0) ||
+				    (serdes_type == SATA1)) ? 0 : 1;
+			sata_port = ((serdes_type == SATA0) ||
+				     (serdes_type == SATA2)) ? 0 : 1;
+
+			CHECK_STATUS(mv_seq_exec
+				     (sata_idx, (sata_port == 0) ?
+				      SATA_PORT_0_ONLY_POWER_UP_SEQ :
+				      SATA_PORT_1_ONLY_POWER_UP_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (sata_idx, (sata_port == 0) ?
+				      SATA_PORT_0_ONLY_TX_CONFIG_SEQ :
+				      SATA_PORT_1_ONLY_TX_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SATA_TX_CONFIG_SEQ2));
+
+			udelay(10000);
+			break;
+		case SGMII0:
+		case SGMII1:
+		case SGMII2:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, SGMII_TX_CONFIG_SEQ2));
+
+			/* GBE configuration */
+			reg_data = reg_read(GBE_CONFIGURATION_REG);
+			/* write the SGMII index */
+			reg_data |= 0x1 << (serdes_type - SGMII0);
+			reg_write(GBE_CONFIGURATION_REG, reg_data);
+
+			break;
+		case QSGMII:
+			if (hws_ctrl_serdes_rev_get() < MV_SERDES_REV_2_1)
+				return MV_NOT_SUPPORTED;
+
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, QSGMII_POWER_UP_SEQ));
+			CHECK_STATUS(hws_ref_clock_set
+				     (serdes_num, serdes_type, ref_clock));
+			CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      QSGMII_ELECTRICAL_CONFIG_SEQ));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, QSGMII_TX_CONFIG_SEQ1));
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num, QSGMII_TX_CONFIG_SEQ2));
+			break;
+		case SGMII3:
+		case XAUI:
+		case RXAUI:
+			CHECK_STATUS(serdes_power_up_ctrl_ext
+				     (serdes_num, serdes_power_up, serdes_type,
+				      baud_rate, serdes_mode, ref_clock));
+			break;
+		default:
+			DEBUG_INIT_S
+			    ("serdes_power_up_ctrl: bad serdes_type parameter\n");
+			return MV_BAD_PARAM;
+		}
+	} else {		/* Serdes power down */
+		DEBUG_INIT_FULL_S("serdes_power_up: executing power down.. ");
+		DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 1);
+
+		CHECK_STATUS(mv_seq_exec(serdes_num, SERDES_POWER_DOWN_SEQ));
+	}
+
+	DEBUG_INIT_FULL_C(
+		"serdes_power_up_ctrl ended successfully for serdes ",
+		serdes_num, 2);
+
+	return MV_OK;
+}
+
+int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map)
+{
+	u32 lane_data, idx, serdes_lane_hw_num, reg_data = 0;
+	enum serdes_type serdes_type;
+	enum serdes_mode serdes_mode;
+	u8 select_bit_off;
+	int is_pex_x4 = 0;
+	int updated_topology_print = 0;
+
+	DEBUG_INIT_FULL_S("\n### hws_update_serdes_phy_selectors ###\n");
+	DEBUG_INIT_FULL_S
+	    ("Updating the COMMON PHYS SELECTORS register with the serdes types\n");
+
+	if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2)
+		select_bit_off = 3;
+	else
+		select_bit_off = 4;
+
+	/*
+	 * Updating bits 0-17 in the COMMON PHYS SELECTORS register
+	 * according to the serdes types
+	 */
+	for (idx = 0; idx < hws_serdes_get_max_lane();
+	     idx++) {
+		serdes_type = serdes_config_map[idx].serdes_type;
+		serdes_mode = serdes_config_map[idx].serdes_mode;
+		serdes_lane_hw_num = hws_get_physical_serdes_num(idx);
+
+		lane_data =
+		    hws_serdes_get_phy_selector_val(serdes_lane_hw_num,
+						    serdes_type);
+
+		if (serdes_type == DEFAULT_SERDES)
+			continue;
+
+		if (hws_serdes_topology_verify
+		    (serdes_type, idx, serdes_mode) != MV_OK) {
+			serdes_config_map[idx].serdes_type =
+			    DEFAULT_SERDES;
+			printf("%s: SerDes lane #%d is  disabled\n", __func__,
+			       serdes_lane_hw_num);
+			updated_topology_print = 1;
+			continue;
+		}
+
+		/*
+		 * Checking if the board topology configuration includes
+		 * PEXx4 - for the next step
+		 */
+		if ((serdes_mode == PEX_END_POINT_X4) ||
+		    (serdes_mode == PEX_ROOT_COMPLEX_X4)) {
+			/* update lane data to the 3 next SERDES lanes */
+			lane_data =
+			    common_phys_selectors_pex_by4_lanes
+			    [serdes_lane_hw_num];
+			if (serdes_type == PEX0)
+				is_pex_x4 = 1;
+		}
+
+		if (lane_data == NA) {
+			printf
+			    ("%s: Warning: SerDes lane #%d and type %d are not supported together\n",
+			     __func__, serdes_lane_hw_num, serdes_mode);
+			serdes_config_map[idx].serdes_type =
+				DEFAULT_SERDES;
+			printf("%s: SerDes lane #%d is  disabled\n", __func__,
+			       serdes_lane_hw_num);
+			continue;
+		}
+
+		/*
+		 * Updating the data that will be written to
+		 * COMMON_PHYS_SELECTORS_REG
+		 */
+		reg_data |= (lane_data <<
+			     (select_bit_off * serdes_lane_hw_num));
+	}
+
+	/*
+	 * Check that number of used lanes for XAUI and RXAUI
+	 * (if used) is right
+	 */
+	hws_serdes_xaui_topology_verify();
+
+	/* Print topology */
+	if (updated_topology_print)
+		print_topology_details(serdes_config_map);
+
+	/*
+	 * Updating the PEXx4 Enable bit in the COMMON PHYS SELECTORS
+	 * register for PEXx4 mode
+	 */
+	reg_data |= (is_pex_x4 == 1) ? (0x1 << PEX_X4_ENABLE_OFFS) : 0;
+
+	/* Updating the COMMON PHYS SELECTORS register */
+	reg_write(COMMON_PHYS_SELECTORS_REG, reg_data);
+
+	return MV_OK;
+}
+
+int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type,
+		      enum ref_clock ref_clock)
+{
+	u32 data1 = 0, data2 = 0, data3 = 0, reg_data;
+
+	DEBUG_INIT_FULL_S("\n### hws_ref_clock_set ###\n");
+
+	if (hws_is_serdes_active(serdes_num) != 1) {
+		printf("%s: SerDes lane #%d is not Active\n", __func__,
+		       serdes_num);
+		return MV_BAD_PARAM;
+	}
+
+	switch (serdes_type) {
+	case PEX0:
+	case PEX1:
+	case PEX2:
+	case PEX3:
+		switch (ref_clock) {
+		case REF_CLOCK_25MHZ:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      PEX_CONFIG_REF_CLOCK_25MHZ_SEQ));
+			return MV_OK;
+		case REF_CLOCK_100MHZ:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      PEX_CONFIG_REF_CLOCK_100MHZ_SEQ));
+			return MV_OK;
+#ifdef CONFIG_ARMADA_39X
+		case REF_CLOCK_40MHZ:
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_num,
+				      PEX_CONFIG_REF_CLOCK_40MHZ_SEQ));
+			return MV_OK;
+#endif
+		default:
+			printf
+			    ("%s: Error: ref_clock %d for SerDes lane #%d, type %d is not supported\n",
+			     __func__, ref_clock, serdes_num, serdes_type);
+			return MV_BAD_PARAM;
+		}
+	case USB3_HOST0:
+	case USB3_HOST1:
+	case USB3_DEVICE:
+		if (ref_clock == REF_CLOCK_25MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2;
+			data2 = GLOBAL_PM_CTRL_REG_25MHZ_VAL;
+			data3 = LANE_CFG4_REG_25MHZ_VAL;
+		} else if (ref_clock == REF_CLOCK_40MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+			data2 = GLOBAL_PM_CTRL_REG_40MHZ_VAL;
+			data3 = LANE_CFG4_REG_40MHZ_VAL;
+		} else {
+			printf
+			    ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+			     serdes_type);
+			return MV_BAD_PARAM;
+		}
+		break;
+	case SATA0:
+	case SATA1:
+	case SATA2:
+	case SATA3:
+	case SGMII0:
+	case SGMII1:
+	case SGMII2:
+	case QSGMII:
+		if (ref_clock == REF_CLOCK_25MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1;
+		} else if (ref_clock == REF_CLOCK_40MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+		} else {
+			printf
+			    ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+			     serdes_type);
+			return MV_BAD_PARAM;
+		}
+		break;
+#ifdef CONFIG_ARMADA_39X
+	case SGMII3:
+	case XAUI:
+	case RXAUI:
+		if (ref_clock == REF_CLOCK_25MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1;
+		} else if (ref_clock == REF_CLOCK_40MHZ) {
+			data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+		} else {
+			printf
+			    ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+			     serdes_type);
+			return MV_BAD_PARAM;
+		}
+		break;
+#endif
+	default:
+		DEBUG_INIT_S("hws_ref_clock_set: not supported serdes type\n");
+		return MV_BAD_PARAM;
+	}
+
+	/*
+	 * Write the ref_clock to relevant SELECT_REF_CLOCK_REG bits and
+	 * offset
+	 */
+	reg_data = reg_read(POWER_AND_PLL_CTRL_REG +
+			    SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+	reg_data &= POWER_AND_PLL_CTRL_REG_MASK;
+	reg_data |= data1;
+	reg_write(POWER_AND_PLL_CTRL_REG +
+		  SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+
+	if ((serdes_type == USB3_HOST0) || (serdes_type == USB3_HOST1) ||
+	    (serdes_type == USB3_DEVICE)) {
+		reg_data = reg_read(GLOBAL_PM_CTRL +
+				    SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+		reg_data &= GLOBAL_PM_CTRL_REG_MASK;
+		reg_data |= data2;
+		reg_write(GLOBAL_PM_CTRL +
+			  SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+
+		reg_data = reg_read(LANE_CFG4_REG +
+				    SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+		reg_data &= LANE_CFG4_REG_MASK;
+		reg_data |= data3;
+		reg_write(LANE_CFG4_REG +
+			  SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+	}
+
+	return MV_OK;
+}
+
+/*
+ * hws_pex_tx_config_seq -
+ *
+ * DESCRIPTION:          Set PEX_TX_CONFIG_SEQ sequence init for PEXx4 mode
+ * INPUT:                serdes_map       - The board topology map
+ * OUTPUT:               None
+ * RETURNS:              MV_OK           - for success
+ *                       MV_BAD_PARAM    - for fail
+ */
+int hws_pex_tx_config_seq(struct serdes_map *serdes_map)
+{
+	enum serdes_mode serdes_mode;
+	u32 serdes_lane_id, serdes_lane_hw_num;
+
+	DEBUG_INIT_FULL_S("\n### hws_pex_tx_config_seq ###\n");
+
+	/*
+	 * For PEXx4: the pex_and_usb3_tx_config_params1/2/3
+	 * configurations should run by setting each sequence for
+	 * all 4 lanes.
+	 */
+
+	/* relese pipe soft reset for all lanes */
+	for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+	     serdes_lane_id++) {
+		serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+		serdes_lane_hw_num =
+		    hws_get_physical_serdes_num(serdes_lane_id);
+
+		if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		    (serdes_mode == PEX_END_POINT_X4)) {
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ1));
+		}
+	}
+
+	/* set phy soft reset for all lanes */
+	for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+	     serdes_lane_id++) {
+		serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+		serdes_lane_hw_num =
+		    hws_get_physical_serdes_num(serdes_lane_id);
+		if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		    (serdes_mode == PEX_END_POINT_X4)) {
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ2));
+		}
+	}
+
+	/* set phy soft reset for all lanes */
+	for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+	     serdes_lane_id++) {
+		serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+		serdes_lane_hw_num =
+		    hws_get_physical_serdes_num(serdes_lane_id);
+		if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+		    (serdes_mode == PEX_END_POINT_X4)) {
+			CHECK_STATUS(mv_seq_exec
+				     (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ3));
+		}
+	}
+
+	return MV_OK;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
new file mode 100644
index 0000000..2508721
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _HIGH_SPEED_ENV_SPEC_H
+#define _HIGH_SPEED_ENV_SPEC_H
+
+#include "seq_exec.h"
+
+/*
+ * For setting or clearing a certain bit (bit is a number between 0 and 31)
+ * in the data
+ */
+#define SET_BIT(data, bit)		((data) | (0x1 << (bit)))
+#define CLEAR_BIT(data, bit)		((data) & (~(0x1 << (bit))))
+
+#define MAX_SERDES_LANES		7	/* as in a39x */
+
+/* Serdes revision */
+/* Serdes revision 1.2 (for A38x-Z1) */
+#define MV_SERDES_REV_1_2		0x0
+/* Serdes revision 2.1 (for A39x-Z1, A38x-A0) */
+#define MV_SERDES_REV_2_1		0x1
+#define MV_SERDES_REV_NA		0xff
+
+#define	SERDES_REGS_LANE_BASE_OFFSET(lane)	(0x800 * (lane))
+
+#define PEX_X4_ENABLE_OFFS						\
+	(hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2 ? 18 : 31)
+
+/* Serdes lane types */
+enum serdes_type {
+	PEX0,
+	PEX1,
+	PEX2,
+	PEX3,
+	SATA0,
+	SATA1,
+	SATA2,
+	SATA3,
+	SGMII0,
+	SGMII1,
+	SGMII2,
+	QSGMII,
+	USB3_HOST0,
+	USB3_HOST1,
+	USB3_DEVICE,
+	SGMII3,
+	XAUI,
+	RXAUI,
+	DEFAULT_SERDES,
+	LAST_SERDES_TYPE
+};
+
+/* Serdes baud rates */
+enum serdes_speed {
+	SERDES_SPEED_1_25_GBPS,
+	SERDES_SPEED_1_5_GBPS,
+	SERDES_SPEED_2_5_GBPS,
+	SERDES_SPEED_3_GBPS,
+	SERDES_SPEED_3_125_GBPS,
+	SERDES_SPEED_5_GBPS,
+	SERDES_SPEED_6_GBPS,
+	SERDES_SPEED_6_25_GBPS,
+	LAST_SERDES_SPEED
+};
+
+/* Serdes modes */
+enum serdes_mode {
+	PEX_ROOT_COMPLEX_X1,
+	PEX_ROOT_COMPLEX_X4,
+	PEX_END_POINT_X1,
+	PEX_END_POINT_X4,
+
+	SERDES_DEFAULT_MODE, /* not pex */
+
+	SERDES_LAST_MODE
+};
+
+struct serdes_map {
+	enum serdes_type	serdes_type;
+	enum serdes_speed	serdes_speed;
+	enum serdes_mode	serdes_mode;
+	int			swap_rx;
+	int			swap_tx;
+};
+
+/* Serdes ref clock options */
+enum ref_clock {
+	REF_CLOCK_25MHZ,
+	REF_CLOCK_100MHZ,
+	REF_CLOCK_40MHZ,
+	REF_CLOCK_UNSUPPORTED
+};
+
+/* Serdes sequences */
+enum serdes_seq {
+	SATA_PORT_0_ONLY_POWER_UP_SEQ,
+	SATA_PORT_1_ONLY_POWER_UP_SEQ,
+	SATA_POWER_UP_SEQ,
+	SATA_1_5_SPEED_CONFIG_SEQ,
+	SATA_3_SPEED_CONFIG_SEQ,
+	SATA_6_SPEED_CONFIG_SEQ,
+	SATA_ELECTRICAL_CONFIG_SEQ,
+	SATA_TX_CONFIG_SEQ1,
+	SATA_PORT_0_ONLY_TX_CONFIG_SEQ,
+	SATA_PORT_1_ONLY_TX_CONFIG_SEQ,
+	SATA_TX_CONFIG_SEQ2,
+
+	SGMII_POWER_UP_SEQ,
+	SGMII_1_25_SPEED_CONFIG_SEQ,
+	SGMII_3_125_SPEED_CONFIG_SEQ,
+	SGMII_ELECTRICAL_CONFIG_SEQ,
+	SGMII_TX_CONFIG_SEQ1,
+	SGMII_TX_CONFIG_SEQ2,
+
+	PEX_POWER_UP_SEQ,
+	PEX_2_5_SPEED_CONFIG_SEQ,
+	PEX_5_SPEED_CONFIG_SEQ,
+	PEX_ELECTRICAL_CONFIG_SEQ,
+	PEX_TX_CONFIG_SEQ1,
+	PEX_TX_CONFIG_SEQ2,
+	PEX_TX_CONFIG_SEQ3,
+	PEX_BY_4_CONFIG_SEQ,
+	PEX_CONFIG_REF_CLOCK_25MHZ_SEQ,
+	PEX_CONFIG_REF_CLOCK_100MHZ_SEQ,
+	PEX_CONFIG_REF_CLOCK_40MHZ_SEQ,
+
+	USB3_POWER_UP_SEQ,
+	USB3_HOST_SPEED_CONFIG_SEQ,
+	USB3_DEVICE_SPEED_CONFIG_SEQ,
+	USB3_ELECTRICAL_CONFIG_SEQ,
+	USB3_TX_CONFIG_SEQ1,
+	USB3_TX_CONFIG_SEQ2,
+	USB3_TX_CONFIG_SEQ3,
+	USB3_DEVICE_CONFIG_SEQ,
+
+	USB2_POWER_UP_SEQ,
+
+	SERDES_POWER_DOWN_SEQ,
+
+	SGMII3_POWER_UP_SEQ,
+	SGMII3_1_25_SPEED_CONFIG_SEQ,
+	SGMII3_TX_CONFIG_SEQ1,
+	SGMII3_TX_CONFIG_SEQ2,
+
+	QSGMII_POWER_UP_SEQ,
+	QSGMII_5_SPEED_CONFIG_SEQ,
+	QSGMII_ELECTRICAL_CONFIG_SEQ,
+	QSGMII_TX_CONFIG_SEQ1,
+	QSGMII_TX_CONFIG_SEQ2,
+
+	XAUI_POWER_UP_SEQ,
+	XAUI_3_125_SPEED_CONFIG_SEQ,
+	XAUI_ELECTRICAL_CONFIG_SEQ,
+	XAUI_TX_CONFIG_SEQ1,
+	XAUI_TX_CONFIG_SEQ2,
+
+	RXAUI_POWER_UP_SEQ,
+	RXAUI_6_25_SPEED_CONFIG_SEQ,
+	RXAUI_ELECTRICAL_CONFIG_SEQ,
+	RXAUI_TX_CONFIG_SEQ1,
+	RXAUI_TX_CONFIG_SEQ2,
+
+	SERDES_LAST_SEQ
+};
+
+/* The different sequence types for PEX and USB3 */
+enum {
+	PEX,
+	USB3,
+	LAST_PEX_USB_SEQ_TYPE
+};
+
+enum {
+	PEXSERDES_SPEED_2_5_GBPS,
+	PEXSERDES_SPEED_5_GBPS,
+	USB3SERDES_SPEED_5_GBPS_HOST,
+	USB3SERDES_SPEED_5_GBPS_DEVICE,
+	LAST_PEX_USB_SPEED_SEQ_TYPE
+};
+
+/* The different sequence types for SATA and SGMII */
+enum {
+	SATA,
+	SGMII,
+	SGMII_3_125,
+	LAST_SATA_SGMII_SEQ_TYPE
+};
+
+enum {
+	QSGMII_SEQ_IDX,
+	LAST_QSGMII_SEQ_TYPE
+};
+
+enum {
+	XAUI_SEQ_IDX,
+	RXAUI_SEQ_IDX,
+	LAST_XAUI_RXAUI_SEQ_TYPE
+};
+
+enum {
+	SATASERDES_SPEED_1_5_GBPS,
+	SATASERDES_SPEED_3_GBPS,
+	SATASERDES_SPEED_6_GBPS,
+	SGMIISERDES_SPEED_1_25_GBPS,
+	SGMIISERDES_SPEED_3_125_GBPS,
+	LAST_SATA_SGMII_SPEED_SEQ_TYPE
+};
+
+extern u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES];
+extern u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES];
+
+u8 hws_ctrl_serdes_rev_get(void);
+int mv_update_serdes_select_phy_mode_seq(void);
+int hws_board_topology_load(struct serdes_map *serdes_map_array);
+enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type,
+						   enum serdes_speed baud_rate);
+int hws_serdes_seq_init(void);
+int hws_serdes_seq_db_init(void);
+int hws_power_up_serdes_lanes(struct serdes_map *serdes_config_map);
+int hws_ctrl_high_speed_serdes_phy_config(void);
+int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up,
+			 enum serdes_type serdes_type,
+			 enum serdes_speed baud_rate,
+			 enum serdes_mode serdes_mode,
+			 enum ref_clock ref_clock);
+int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up,
+			     enum serdes_type serdes_type,
+			     enum serdes_speed baud_rate,
+			     enum serdes_mode serdes_mode,
+			     enum ref_clock ref_clock);
+u32 hws_serdes_silicon_ref_clock_get(void);
+int hws_serdes_pex_ref_clock_get(enum serdes_type serdes_type,
+				 enum ref_clock *ref_clock);
+int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type,
+		      enum ref_clock ref_clock);
+int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map);
+u32 hws_serdes_get_phy_selector_val(int serdes_num,
+				    enum serdes_type serdes_type);
+u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type);
+u32 hws_serdes_get_max_lane(void);
+int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset,
+			  u32 *unit_base_reg, u32 *unit_offset);
+int hws_pex_tx_config_seq(struct serdes_map *serdes_map);
+u32 hws_get_physical_serdes_num(u32 serdes_num);
+int hws_is_serdes_active(u8 lane_num);
+
+#endif /* _HIGH_SPEED_ENV_SPEC_H */
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c
new file mode 100644
index 0000000..5f2c3eb
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "high_speed_topology_spec.h"
+#include "sys_env_lib.h"
+
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+/*
+ * This is an example implementation for this custom board
+ * specific function
+ */
+static struct serdes_map custom_board_topology_config[] = {
+	/* Customer Board Topology - reference from Marvell DB-GP board */
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+int hws_board_topology_load(struct serdes_map *serdes_map_array)
+{
+	serdes_map_array = custom_board_topology_config;
+}
+#endif
+
+load_topology_func_ptr load_topology_func_arr[] = {
+	load_topology_rd,	/* RD NAS */
+	load_topology_db,	/* 6820 DB-BP (A38x) */
+	load_topology_rd,	/* RD AP */
+	load_topology_db_ap,	/* DB AP */
+	load_topology_db_gp,	/* DB GP */
+	load_topology_db_381,	/* 6821 DB-BP (A381) */
+	load_topology_db_amc,	/* DB-AMC */
+};
+
+/*****************************************/
+/** Load topology - Marvell 380 DB - BP **/
+/*****************************************/
+/* Configuration options */
+struct serdes_map db_config_default[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1363_c[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+};
+
+struct serdes_map db_config_slm1363_d[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1363_e[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1363_f[MAX_SERDES_LANES] = {
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1364_d[MAX_SERDES_LANES] = {
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1364_e[MAX_SERDES_LANES] = {
+	{SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}
+};
+
+struct serdes_map db_config_slm1364_f[MAX_SERDES_LANES] = {
+	{SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	{DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0, 0},
+	{PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}
+};
+
+/*************************************************************************/
+/** The following structs are mapping for DB board 'SatR' configuration **/
+/*************************************************************************/
+struct serdes_map db_satr_config_lane1[SATR_DB_LANE1_MAX_OPTIONS] = {
+	/* 0 */ {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 1 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 2 */ {SATA0, SERDES_SPEED_3_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 3 */ {SGMII0, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 4 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 5 */ {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 6 */ {QSGMII, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_satr_config_lane2[SATR_DB_LANE2_MAX_OPTIONS] = {
+	/* 0 */ {DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 1 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 2 */ {SATA1, SERDES_SPEED_3_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 3 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0}
+};
+
+/*******************************************************/
+/* Configuration options DB ****************************/
+/* mapping from TWSI address data to configuration map */
+/*******************************************************/
+struct serdes_map *topology_config_db[] = {
+	db_config_slm1363_c,
+	db_config_slm1363_d,
+	db_config_slm1363_e,
+	db_config_slm1363_f,
+	db_config_slm1364_d,
+	db_config_slm1364_e,
+	db_config_slm1364_f,
+	db_config_default
+};
+
+/*************************************/
+/** Load topology - Marvell DB - AP **/
+/*************************************/
+struct serdes_map db_ap_config_default[MAX_SERDES_LANES] = {
+	/* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 1 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 2 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 3 */ {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 4 */ {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 5 */ {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}
+};
+
+/*************************************/
+/** Load topology - Marvell DB - GP **/
+/*************************************/
+struct serdes_map db_gp_config_default[MAX_SERDES_LANES] = {
+	/* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	/* 1 */ {SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 2 */ {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 3 */ {SATA3, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 4 */ {SATA2, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0},
+	/* 5 */ {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0}
+};
+
+struct serdes_map db_amc_config_default[MAX_SERDES_LANES] = {
+	/* 0 */ {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 1 */ {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 2 */ {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 3 */ {PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X4, 0, 0},
+	/* 4 */ {SGMII1, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+	/* 5 */ {SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 0,
+		 0},
+};
+
+/*****************************************/
+/** Load topology - Marvell 381 DB - BP **/
+/*****************************************/
+/* Configuration options */
+struct serdes_map db381_config_default[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}
+};
+
+struct serdes_map db_config_slm1427[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 1, 1},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 1, 1}
+};
+
+struct serdes_map db_config_slm1426[MAX_SERDES_LANES] = {
+	{SATA0, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 1, 1},
+	{SGMII2, SERDES_SPEED_3_125_GBPS, SERDES_DEFAULT_MODE, 1, 1}
+};
+
+/*
+ * this array must be aligned with enum topology_config_db381 enum,
+ * every update to this array requires update to enum topology_config_db381
+ * enum
+ */
+struct serdes_map *topology_config_db_381[] = {
+	db_config_slm1427,
+	db_config_slm1426,
+	db381_config_default,
+};
+
+u8 topology_config_db_mode_get(void)
+{
+	u8 mode;
+
+	DEBUG_INIT_FULL_S("\n### topology_config_db_mode_get ###\n");
+
+	/* Default - return DB_CONFIG_DEFAULT */
+
+	if (!i2c_read(DB_GET_MODE_SLM1363_ADDR, 0, 1, &mode, 1)) {
+		switch (mode & 0xf) {
+		case 0xc:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 C topology\n");
+			return DB_CONFIG_SLM1363_C;
+		case 0xd:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 D topology\n");
+			return DB_CONFIG_SLM1363_D;
+		case 0xe:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 E topology\n");
+			return DB_CONFIG_SLM1363_E;
+		case 0xf:
+			DEBUG_INIT_S("\nInit DB board SLM 1363 F topology\n");
+			return DB_CONFIG_SLM1363_F;
+		default:	/* not the right module */
+			break;
+		}
+	}
+
+	/* SLM1364 Module */
+	if (i2c_read(DB_GET_MODE_SLM1364_ADDR, 0, 1, &mode, 1)) {
+		DEBUG_INIT_S("\nInit DB board default topology\n");
+		return DB_CONFIG_DEFAULT;
+	}
+
+	switch (mode & 0xf) {
+	case 0xd:
+		DEBUG_INIT_S("\nInit DB board SLM 1364 D topology\n");
+		return DB_CONFIG_SLM1364_D;
+	case 0xe:
+		DEBUG_INIT_S("\nInit DB board SLM 1364 E topology\n");
+		return DB_CONFIG_SLM1364_E;
+	case 0xf:
+		DEBUG_INIT_S("\nInit DB board SLM 1364 F topology\n");
+		return DB_CONFIG_SLM1364_F;
+	default:		/* Default configuration */
+		DEBUG_INIT_S("\nInit DB board default topology\n");
+		return DB_CONFIG_DEFAULT;
+	}
+}
+
+u8 topology_config_db_381_mode_get(void)
+{
+	u8 mode;
+
+	DEBUG_INIT_FULL_S("\n### topology_config_db_381_mode_get ###\n");
+
+	if (!i2c_read(DB381_GET_MODE_SLM1426_1427_ADDR, 0, 2, &mode, 1)) {
+		switch (mode & 0xf) {
+		case 0x1:
+			DEBUG_INIT_S("\nInit DB-381 board SLM 1427 topology\n");
+			return DB_CONFIG_SLM1427;
+		case 0x2:
+			DEBUG_INIT_S("\nInit DB-381 board SLM 1426 topology\n");
+			return DB_CONFIG_SLM1426;
+		default:	/* not the right module */
+			break;
+		}
+	}
+
+	/* in case not detected any supported module, use default topology */
+	DEBUG_INIT_S("\nInit DB-381 board default topology\n");
+	return DB_381_CONFIG_DEFAULT;
+}
+
+/*
+ * Read SatR field 'sgmiispeed' and update lane topology SGMII entries
+ * speed setup
+ */
+int update_topology_sgmii_speed(struct serdes_map *serdes_map_array)
+{
+	u32 serdes_type, lane_num;
+	u8 config_val;
+
+	/* Update SGMII speed settings by 'sgmiispeed' SatR value */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_type = serdes_map_array[lane_num].serdes_type;
+		/*Read SatR configuration for SGMII speed */
+		if ((serdes_type == SGMII0) || (serdes_type == SGMII1) ||
+		    (serdes_type == SGMII2)) {
+			/* Read SatR 'sgmiispeed' value */
+			if (i2c_read(EEPROM_I2C_ADDR, 0, 2, &config_val, 1)) {
+				printf("%s: TWSI Read of 'sgmiispeed' failed\n",
+				       __func__);
+				return MV_FAIL;
+			}
+
+			if (0 == (config_val & 0x40)) {
+				serdes_map_array[lane_num].serdes_speed =
+					SERDES_SPEED_1_25_GBPS;
+			} else {
+				serdes_map_array[lane_num].serdes_speed =
+					SERDES_SPEED_3_125_GBPS;
+			}
+		}
+	}
+	return MV_OK;
+}
+
+struct serdes_map default_lane = {
+	DEFAULT_SERDES, LAST_SERDES_SPEED, SERDES_DEFAULT_MODE
+};
+int is_custom_topology = 0;	/* indicate user of non-default topology */
+
+/*
+ * Read SatR fields (dbserdes1/2 , gpserdes1/2/5) and update lane
+ * topology accordingly
+ */
+int update_topology_satr(struct serdes_map *serdes_map_array)
+{
+	u8 config_val, lane_select, i;
+	u32 board_id = mv_board_id_get();
+
+	switch (board_id) {
+	case DB_68XX_ID:	/* read 'dbserdes1' & 'dbserdes2' */
+	case DB_BP_6821_ID:
+		if (i2c_read(EEPROM_I2C_ADDR, 1, 2, &config_val, 1)) {
+			printf("%s: TWSI Read of 'dbserdes1/2' failed\n",
+			       __func__);
+			return MV_FAIL;
+		}
+
+		/* Lane #1 */
+		lane_select = (config_val & SATR_DB_LANE1_CFG_MASK) >>
+			SATR_DB_LANE1_CFG_OFFSET;
+		if (lane_select >= SATR_DB_LANE1_MAX_OPTIONS) {
+			printf("\n\%s: Error: invalid value for SatR field 'dbserdes1' (%x)\n",
+			       __func__, lane_select);
+			printf("\t_skipping Topology update (run 'SatR write default')\n");
+			return MV_FAIL;
+		}
+
+		/*
+		 * If modified default serdes_type for lane#1, update
+		 * topology and mark it as custom
+		 */
+		if (serdes_map_array[1].serdes_type !=
+		    db_satr_config_lane1[lane_select].serdes_type) {
+			serdes_map_array[1] = db_satr_config_lane1[lane_select];
+			is_custom_topology = 1;
+			/* DB 381/2 board has inverted SerDes polarity */
+			if (board_id == DB_BP_6821_ID)
+				serdes_map_array[1].swap_rx =
+					serdes_map_array[1].swap_tx = 1;
+		}
+
+		/* Lane #2 */
+		lane_select = (config_val & SATR_DB_LANE2_CFG_MASK) >>
+			SATR_DB_LANE2_CFG_OFFSET;
+		if (lane_select >= SATR_DB_LANE2_MAX_OPTIONS) {
+			printf("\n\%s: Error: invalid value for SatR field 'dbserdes2' (%x)\n",
+			       __func__, lane_select);
+			printf("\t_skipping Topology update (run 'SatR write default')\n");
+			return MV_FAIL;
+		}
+
+		/*
+		 * If modified default serdes_type for lane at 2, update
+		 * topology and mark it as custom
+		 */
+		if (serdes_map_array[2].serdes_type !=
+		    db_satr_config_lane2[lane_select].serdes_type) {
+			serdes_map_array[2] = db_satr_config_lane2[lane_select];
+			is_custom_topology = 1;
+			/* DB 381/2 board has inverted SerDes polarity */
+			if (board_id == DB_BP_6821_ID)
+				serdes_map_array[2].swap_rx =
+					serdes_map_array[2].swap_tx = 1;
+		}
+
+		if (is_custom_topology == 1) {
+			/*
+			 * Check for conflicts with detected lane #1 and
+			 * lane #2 (Disable conflicted lanes)
+			 */
+			for (i = 0; i < hws_serdes_get_max_lane(); i++) {
+				if (i != 1 && serdes_map_array[1].serdes_type ==
+				    serdes_map_array[i].serdes_type) {
+					printf("\t_lane #%d Type conflicts with Lane #1 (Lane #%d disabled)\n",
+					       i, i);
+					serdes_map_array[i] =
+						db_satr_config_lane1[0];
+				}
+
+				if (i != 2 &&
+				    serdes_map_array[2].serdes_type ==
+				    serdes_map_array[i].serdes_type) {
+					printf("\t_lane #%d Type conflicts with Lane #2 (Lane #%d disabled)\n",
+					       i, i);
+					serdes_map_array[i] =
+						db_satr_config_lane1[0];
+				}
+			}
+		}
+
+		break;		/* case DB_68XX_ID */
+	case DB_GP_68XX_ID:	/* read 'gpserdes1' & 'gpserdes2' */
+		if (i2c_read(EEPROM_I2C_ADDR, 2, 2, &config_val, 1)) {
+			printf("%s: TWSI Read of 'gpserdes1/2' failed\n",
+			       __func__);
+			return MV_FAIL;
+		}
+
+		/*
+		 * Lane #1:
+		 * lane_select = 0 --> SATA0,
+		 * lane_select = 1 --> PCIe0 (mini PCIe)
+		 */
+		lane_select = (config_val & SATR_GP_LANE1_CFG_MASK) >>
+			SATR_GP_LANE1_CFG_OFFSET;
+		if (lane_select == 1) {
+			serdes_map_array[1].serdes_mode = PEX0;
+			serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS;
+			serdes_map_array[1].serdes_type = PEX_ROOT_COMPLEX_X1;
+			/*
+			 * If lane 1 is set to PCIe0 --> disable PCIe0
+			 * on lane 0
+			 */
+			serdes_map_array[0] = default_lane;
+			/* indicate user of non-default topology */
+			is_custom_topology = 1;
+		}
+		printf("Lane 1 detection: %s\n",
+		       lane_select ? "PCIe0 (mini PCIe)" : "SATA0");
+
+		/*
+		 * Lane #2:
+		 * lane_select = 0 --> SATA1,
+		 * lane_select = 1 --> PCIe1 (mini PCIe)
+		 */
+		lane_select = (config_val & SATR_GP_LANE2_CFG_MASK) >>
+			SATR_GP_LANE2_CFG_OFFSET;
+		if (lane_select == 1) {
+			serdes_map_array[2].serdes_type = PEX1;
+			serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS;
+			serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1;
+			/* indicate user of non-default topology */
+			is_custom_topology = 1;
+		}
+		printf("Lane 2 detection: %s\n",
+		       lane_select ? "PCIe1 (mini PCIe)" : "SATA1");
+		break;		/* case DB_GP_68XX_ID */
+	}
+
+	if (is_custom_topology)
+		printf("\nDetected custom SerDes topology (to restore default run 'SatR write default')\n\n");
+
+	return MV_OK;
+}
+
+/*
+ * hws_update_device_toplogy
+ * DESCRIPTION: Update the default board topology for specific device Id
+ * INPUT:
+ *	topology_config_ptr - pointer to the Serdes mapping
+ *	topology_mode - topology mode (index)
+ * OUTPUT: None
+ * RRETURNS:
+ *	MV_OK - if updating the board topology success
+ *	MV_BAD_PARAM - if the input parameter is wrong
+ */
+int hws_update_device_toplogy(struct serdes_map *topology_config_ptr,
+			      enum topology_config_db topology_mode)
+{
+	u32 dev_id = sys_env_device_id_get();
+	u32 board_id = mv_board_id_get();
+
+	switch (topology_mode) {
+	case DB_CONFIG_DEFAULT:
+		switch (dev_id) {
+		case MV_6810:
+			/*
+			 * DB-AP : default for Lane3=SGMII2 -->
+			 * 6810 supports only 2 SGMII interfaces:
+			 * lane 3 disabled
+			 */
+			if (board_id == DB_AP_68XX_ID) {
+				printf("Device 6810 supports only 2 SGMII interfaces: SGMII-2 @ lane3 disabled\n");
+				topology_config_ptr[3] = default_lane;
+			}
+
+			/*
+			 * 6810 has only 4 SerDes and the forth one is
+			 * Serdes number 5 (i.e. Serdes 4 is not connected),
+			 * therefore we need to copy SerDes 5 configuration
+			 * to SerDes 4
+			 */
+			printf("Device 6810 does not supports SerDes Lane #4: replaced topology entry with lane #5\n");
+			topology_config_ptr[4] = topology_config_ptr[5];
+
+			/*
+			 * No break between cases since the 1st
+			 * 6820 limitation apply on 6810
+			 */
+		case MV_6820:
+			/*
+			 * DB-GP & DB-BP: default for Lane3=SATA3 -->
+			 * 6810/20 supports only 2 SATA interfaces:
+			 * lane 3 disabled
+			 */
+			if ((board_id == DB_68XX_ID) ||
+			    (board_id == DB_GP_68XX_ID)) {
+				printf("Device 6810/20 supports only 2 SATA interfaces: SATA Port 3 @ lane3 disabled\n");
+				topology_config_ptr[3] = default_lane;
+			}
+			/*
+			 * DB-GP on 6820 only: default for Lane4=SATA2
+			 * --> 6820 supports only 2 SATA interfaces:
+			 * lane 3 disabled
+			 */
+			if (board_id == DB_GP_68XX_ID && dev_id == MV_6820) {
+				printf("Device 6820 supports only 2 SATA interfaces: SATA Port 2 @ lane4 disabled\n");
+				topology_config_ptr[4] = default_lane;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+
+	default:
+		printf("sys_env_update_device_toplogy: selected topology is not supported by this routine\n");
+		break;
+	}
+
+	return MV_OK;
+}
+
+int load_topology_db_381(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	u8 topology_mode;
+	struct serdes_map *topology_config_ptr;
+	u8 twsi_data;
+	u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0;
+
+	printf("\nInitialize DB-88F6821-BP board topology\n");
+
+	/* Getting the relevant topology mode (index) */
+	topology_mode = topology_config_db_381_mode_get();
+	topology_config_ptr = topology_config_db_381[topology_mode];
+
+	/* Read USB3.0 mode: HOST/DEVICE */
+	if (load_topology_usb_mode_get(&twsi_data) == MV_OK) {
+		usb3_host0_or_device = (twsi_data & 0x1);
+		/* Only one USB3 device is enabled */
+		if (usb3_host0_or_device == 0)
+			usb3_host1_or_device = ((twsi_data >> 1) & 0x1);
+	}
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+
+		/* Update USB3 device if needed */
+		if (usb3_host0_or_device == 1 &&
+		    serdes_map_array[lane_num].serdes_type == USB3_HOST0)
+			serdes_map_array[lane_num].serdes_type = USB3_DEVICE;
+
+		if (usb3_host1_or_device == 1 &&
+		    serdes_map_array[lane_num].serdes_type == USB3_HOST1)
+			serdes_map_array[lane_num].serdes_type = USB3_DEVICE;
+	}
+
+	/* If not detected any SerDes Site module, read 'SatR' lane setup */
+	if (topology_mode == DB_381_CONFIG_DEFAULT)
+		update_topology_satr(serdes_map_array);
+
+	/* update 'sgmiispeed' settings */
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	u8 topology_mode;
+	struct serdes_map *topology_config_ptr;
+	u8 twsi_data;
+	u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0;
+
+	printf("\nInitialize DB-88F6820-BP board topology\n");
+
+	/* Getting the relevant topology mode (index) */
+	topology_mode = topology_config_db_mode_get();
+
+	if (topology_mode == DB_NO_TOPOLOGY)
+		topology_mode = DB_CONFIG_DEFAULT;
+
+	topology_config_ptr = topology_config_db[topology_mode];
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, topology_mode));
+
+	/* Read USB3.0 mode: HOST/DEVICE */
+	if (load_topology_usb_mode_get(&twsi_data) == MV_OK) {
+		usb3_host0_or_device = (twsi_data & 0x1);
+		/* Only one USB3 device is enabled */
+		if (usb3_host0_or_device == 0)
+			usb3_host1_or_device = ((twsi_data >> 1) & 0x1);
+	}
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+
+		/*
+		 * Update USB3 device if needed - relevant for
+		 * lane 3,4,5 only
+		 */
+		if (lane_num >= 3) {
+			if ((serdes_map_array[lane_num].serdes_type ==
+			     USB3_HOST0) && (usb3_host0_or_device == 1))
+				serdes_map_array[lane_num].serdes_type =
+					USB3_DEVICE;
+
+			if ((serdes_map_array[lane_num].serdes_type ==
+			     USB3_HOST1) && (usb3_host1_or_device == 1))
+				serdes_map_array[lane_num].serdes_type =
+					USB3_DEVICE;
+		}
+	}
+
+	/* If not detected any SerDes Site module, read 'SatR' lane setup */
+	if (topology_mode == DB_CONFIG_DEFAULT)
+		update_topology_satr(serdes_map_array);
+
+	/* update 'sgmiispeed' settings */
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db_ap(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	struct serdes_map *topology_config_ptr;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_db_ap ###\n");
+
+	printf("\nInitialize DB-AP board topology\n");
+	topology_config_ptr = db_ap_config_default;
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+	}
+
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db_gp(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	struct serdes_map *topology_config_ptr;
+	int is_sgmii = 0;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_db_gp ###\n");
+
+	topology_config_ptr = db_gp_config_default;
+
+	printf("\nInitialize DB-GP board topology\n");
+
+	/* check S at R: if lane 5 is USB3 or SGMII */
+	if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK)
+		printf("%s: TWSI Read failed - Loading Default Topology\n",
+		       __func__);
+	else {
+		topology_config_ptr[5].serdes_type =
+			is_sgmii ? SGMII2 : USB3_HOST1;
+		topology_config_ptr[5].serdes_speed = is_sgmii ?
+			SERDES_SPEED_3_125_GBPS : SERDES_SPEED_5_GBPS;
+		topology_config_ptr[5].serdes_mode = SERDES_DEFAULT_MODE;
+	}
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+	}
+
+	/*
+	 * Update 'gpserdes1/2/3' lane configuration , and 'sgmiispeed'
+	 * for SGMII lanes
+	 */
+	update_topology_satr(serdes_map_array);
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_db_amc(struct serdes_map *serdes_map_array)
+{
+	u32 lane_num;
+	struct serdes_map *topology_config_ptr;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_db_amc ###\n");
+
+	printf("\nInitialize DB-AMC board topology\n");
+	topology_config_ptr = db_amc_config_default;
+
+	/* Update the default board topology device flavours */
+	CHECK_STATUS(hws_update_device_toplogy
+		     (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+	/* Updating the topology map */
+	for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+		serdes_map_array[lane_num].serdes_mode =
+			topology_config_ptr[lane_num].serdes_mode;
+		serdes_map_array[lane_num].serdes_speed =
+			topology_config_ptr[lane_num].serdes_speed;
+		serdes_map_array[lane_num].serdes_type =
+			topology_config_ptr[lane_num].serdes_type;
+		serdes_map_array[lane_num].swap_rx =
+			topology_config_ptr[lane_num].swap_rx;
+		serdes_map_array[lane_num].swap_tx =
+			topology_config_ptr[lane_num].swap_tx;
+	}
+
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_rd(struct serdes_map *serdes_map_array)
+{
+	u8 mode;
+
+	DEBUG_INIT_FULL_S("\n### load_topology_rd ###\n");
+
+	DEBUG_INIT_S("\nInit RD board ");
+
+	/* Reading mode */
+	DEBUG_INIT_FULL_S("load_topology_rd: getting mode\n");
+	if (i2c_read(EEPROM_I2C_ADDR, 0, 2, &mode, 1)) {
+		DEBUG_INIT_S("load_topology_rd: TWSI Read failed\n");
+		return MV_FAIL;
+	}
+
+	/* Updating the topology map */
+	DEBUG_INIT_FULL_S("load_topology_rd: Loading board topology details\n");
+
+	/* RD mode: 0 = NAS, 1 = AP */
+	if (((mode >> 1) & 0x1) == 0) {
+		CHECK_STATUS(load_topology_rd_nas(serdes_map_array));
+	} else {
+		CHECK_STATUS(load_topology_rd_ap(serdes_map_array));
+	}
+
+	update_topology_sgmii_speed(serdes_map_array);
+
+	return MV_OK;
+}
+
+int load_topology_rd_nas(struct serdes_map *serdes_map_array)
+{
+	int is_sgmii = 0;
+	u32 i;
+
+	DEBUG_INIT_S("\nInit RD NAS topology ");
+
+	/* check if lane 4 is USB3 or SGMII */
+	if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) {
+		DEBUG_INIT_S("load_topology_rd NAS: TWSI Read failed\n");
+		return MV_FAIL;
+	}
+
+	/* Lane 0 */
+	serdes_map_array[0].serdes_type = PEX0;
+	serdes_map_array[0].serdes_speed = SERDES_SPEED_5_GBPS;
+	serdes_map_array[0].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+	/* Lane 1 */
+	serdes_map_array[1].serdes_type = SATA0;
+	serdes_map_array[1].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[1].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 2 */
+	serdes_map_array[2].serdes_type = SATA1;
+	serdes_map_array[2].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[2].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 3 */
+	serdes_map_array[3].serdes_type = SATA3;
+	serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 4 */
+	if (is_sgmii == 1) {
+		DEBUG_INIT_S("Serdes Lane 4 is SGMII\n");
+		serdes_map_array[4].serdes_type = SGMII1;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	} else {
+		DEBUG_INIT_S("Serdes Lane 4 is USB3\n");
+		serdes_map_array[4].serdes_type = USB3_HOST0;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	}
+
+	/* Lane 5 */
+	serdes_map_array[5].serdes_type = SATA2;
+	serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* init swap configuration */
+	for (i = 0; i <= 5; i++) {
+		serdes_map_array[i].swap_rx = 0;
+		serdes_map_array[i].swap_tx = 0;
+	}
+
+	return MV_OK;
+}
+
+int load_topology_rd_ap(struct serdes_map *serdes_map_array)
+{
+	int is_sgmii = 0;
+	u32 i;
+
+	DEBUG_INIT_S("\nInit RD AP topology ");
+
+	/* check if lane 4 is USB3 or SGMII */
+	if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) {
+		DEBUG_INIT_S("load_topology_rd AP: TWSI Read failed\n");
+		return MV_FAIL;
+	}
+
+	/* Lane 0 */
+	serdes_map_array[0].serdes_type = DEFAULT_SERDES;
+	serdes_map_array[0].serdes_speed = LAST_SERDES_SPEED;
+	serdes_map_array[0].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 1 */
+	serdes_map_array[1].serdes_type = PEX0;
+	serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS;
+	serdes_map_array[1].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+	/* Lane 2 */
+	serdes_map_array[2].serdes_type = PEX1;
+	serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS;
+	serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+	/* Lane 3 */
+	serdes_map_array[3].serdes_type = SATA3;
+	serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* Lane 4 */
+	if (is_sgmii == 1) {
+		DEBUG_INIT_S("Serdes Lane 4 is SGMII\n");
+		serdes_map_array[4].serdes_type = SGMII1;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	} else {
+		DEBUG_INIT_S("Serdes Lane 4 is USB3\n");
+		serdes_map_array[4].serdes_type = USB3_HOST0;
+		serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS;
+		serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+	}
+
+	/* Lane 5 */
+	serdes_map_array[5].serdes_type = SATA2;
+	serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS;
+	serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE;
+
+	/* init swap configuration */
+	for (i = 0; i <= 5; i++) {
+		serdes_map_array[i].swap_rx = 0;
+		serdes_map_array[i].swap_tx = 0;
+	}
+
+	return MV_OK;
+}
+
+int load_topology_rd_sgmii_usb(int *is_sgmii)
+{
+	u8 mode;
+
+	/*
+	 * DB-GP board: Device 6810 supports only 2 GbE ports:
+	 * SGMII2 not supported (USE USB3 Host instead)
+	 */
+	if (sys_env_device_id_get() == MV_6810) {
+		printf("Device 6810 supports only 2 GbE ports: SGMII-2 @ lane5 disabled (setting USB3.0 H1 instead)\n");
+		*is_sgmii = 0;
+		return MV_OK;
+	}
+
+	if (!i2c_read(RD_GET_MODE_ADDR, 1, 2, &mode, 1)) {
+		*is_sgmii = ((mode >> 2) & 0x1);
+	} else {
+		/* else use the default - USB3 */
+		*is_sgmii = 0;
+	}
+
+	if (*is_sgmii)
+		is_custom_topology = 1;
+
+	printf("Lane 5 detection: %s\n",
+	       *is_sgmii ? "SGMII2" : "USB3.0 Host Port 1");
+
+	return MV_OK;
+}
+
+/*
+ * 'usb3port0'/'usb3port1' fields are located in EEPROM,
+ * at 3rd byte(offset=2), bit 0:1 (respectively)
+ */
+int load_topology_usb_mode_get(u8 *twsi_data)
+{
+	if (!i2c_read(EEPROM_I2C_ADDR, 2, 2, twsi_data, 1))
+		return MV_OK;
+
+	return MV_ERROR;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h
new file mode 100644
index 0000000..3cfb1c7
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _HIGHSPEED_TOPOLOGY_SPEC_H
+#define _HIGHSPEED_TOPOLOGY_SPEC_H
+
+#include "high_speed_env_spec.h"
+
+/* Topology map options for the DB_A38X_BP board */
+enum topology_config_db {
+	DB_CONFIG_SLM1363_C,
+	DB_CONFIG_SLM1363_D,
+	DB_CONFIG_SLM1363_E,
+	DB_CONFIG_SLM1363_F,
+	DB_CONFIG_SLM1364_D,
+	DB_CONFIG_SLM1364_E,
+	DB_CONFIG_SLM1364_F,
+	DB_CONFIG_DEFAULT,
+	DB_NO_TOPOLOGY
+};
+
+/*
+ * this enum must be aligned with topology_config_db_381 array,
+ * every update to this enum requires update to topology_config_db_381
+ * array
+ */
+enum topology_config_db381 {
+	DB_CONFIG_SLM1427,	/* enum for db_config_slm1427 */
+	DB_CONFIG_SLM1426,	/* enum for db_config_slm1426 */
+	DB_381_CONFIG_DEFAULT,
+	DB_381_NO_TOPOLOGY
+};
+
+/* A generic function pointer for loading the board topology map */
+typedef int (*load_topology_func_ptr)(struct serdes_map *serdes_map_array);
+
+extern load_topology_func_ptr load_topology_func_arr[];
+
+/*
+ * topology_config_db_mode_get -
+ *
+ * DESCRIPTION:		Gets the relevant topology mode (index).
+ *			for load_topology_db use only.
+ * INPUT:		None.
+ * OUTPUT:		None.
+ * RETURNS:		the topology mode
+ */
+u8 topology_config_db_mode_get(void);
+
+/*
+ * load_topology_xxx -
+ *
+ * DESCRIPTION:		Loads the board topology for the XXX board
+ * INPUT:		serdes_map_array - The struct that will contain
+ *			the board topology map
+ * OUTPUT:		The board topology map.
+ * RETURNS:		MV_OK   for success
+ *			MV_FAIL	for failure (a wrong topology mode was read
+ *			from the board)
+ */
+
+/* load_topology_db - Loads the board topology for DB Board */
+int load_topology_db(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd - Loads the board topology for RD Board */
+int load_topology_rd(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd_nas - Loads the board topology for RD NAS Board */
+int load_topology_rd_nas(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd_ap - Loads the board topology for RD Ap Board */
+int load_topology_rd_ap(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_ap - Loads the board topology for DB-AP Board */
+int load_topology_db_ap(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_gp - Loads the board topology for DB GP Board */
+int load_topology_db_gp(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_381 - Loads the board topology for 381 DB-BP Board */
+int load_topology_db_381(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_amc - Loads the board topology for DB-AMC Board */
+int load_topology_db_amc(struct serdes_map *serdes_map_array);
+
+/*
+ * hws_update_device_toplogy
+ * DESCRIPTION: Update the default board topology for specific device Id
+ * INPUT:
+ *	topology_config_ptr - pointer to the Serdes mapping
+ *	topology_mode - topology mode (index)
+ * OUTPUT: None
+ * RRETURNS:
+ *	MV_OK - if updating the board topology success
+ *	MV_BAD_PARAM - if the input parameter is wrong
+ */
+int hws_update_device_toplogy(struct serdes_map *topology_config_ptr,
+			      enum topology_config_db topology_mode);
+
+/*
+ * load_topology_rd_sgmii_usb -
+ *
+ * DESCRIPTION:			For RD board check if lane 4 is USB3 or SGMII
+ * INPUT:			None
+ * OUTPUT:			is_sgmii - return 1 if lane 4 is SGMII
+ *				return 0 if lane 4 is USB.
+ * RETURNS:			MV_OK for success
+ */
+int load_topology_rd_sgmii_usb(int *is_sgmii);
+
+/*
+ * load_topology_usb_mode_get -
+ *
+ * DESCRIPTION:			For DB board check if USB3.0 mode
+ * INPUT:			None
+ * OUTPUT:			twsi_data - return data read from S at R via I2C
+ * RETURNS:			MV_OK for success
+ */
+int load_topology_usb_mode_get(u8 *twsi_data);
+
+#endif /* _HIGHSPEED_TOPOLOGY_SPEC_H */
diff --git a/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
new file mode 100644
index 0000000..ee2305b
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "seq_exec.h"
+#include "high_speed_env_spec.h"
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
+
+#if defined(MV_DEBUG_INIT_FULL) || defined(MV_DEBUG)
+#define DB(x)	x
+#else
+#define DB(x)
+#endif
+
+/* Array for mapping the operation (write, poll or delay) functions */
+op_execute_func_ptr op_execute_func_arr[] = {
+	write_op_execute,
+	delay_op_execute,
+	poll_op_execute
+};
+
+int write_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+	u32 unit_base_reg, unit_offset, data, mask, reg_data, reg_addr;
+
+	/* Getting write op params from the input parameter */
+	data = params->data[data_arr_idx];
+	mask = params->mask;
+
+	/* an empty operation */
+	if (data == NO_DATA)
+		return MV_OK;
+
+	/* get updated base address since it can be different between Serdes */
+	CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
+					   params->unit_offset,
+					   &unit_base_reg, &unit_offset));
+
+	/* Address calculation */
+	reg_addr = unit_base_reg + unit_offset * serdes_num;
+
+#ifdef SEQ_DEBUG
+	printf("Write: 0x%x: 0x%x (mask 0x%x) - ", reg_addr, data, mask);
+#endif
+	/* Reading old value */
+	reg_data = reg_read(reg_addr);
+	reg_data &= (~mask);
+
+	/* Writing new data */
+	data &= mask;
+	reg_data |= data;
+	reg_write(reg_addr, reg_data);
+
+#ifdef SEQ_DEBUG
+	printf(" - 0x%x\n", reg_data);
+#endif
+
+	return MV_OK;
+}
+
+int delay_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+	u32 delay;
+
+	/* Getting delay op params from the input parameter */
+	delay = params->wait_time;
+#ifdef SEQ_DEBUG
+	printf("Delay: %d\n", delay);
+#endif
+	mdelay(delay);
+
+	return MV_OK;
+}
+
+int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
+{
+	u32 unit_base_reg, unit_offset, data, mask, num_of_loops, wait_time;
+	u32 poll_counter = 0;
+	u32 reg_addr, reg_data;
+
+	/* Getting poll op params from the input parameter */
+	data = params->data[data_arr_idx];
+	mask = params->mask;
+	num_of_loops = params->num_of_loops;
+	wait_time = params->wait_time;
+
+	/* an empty operation */
+	if (data == NO_DATA)
+		return MV_OK;
+
+	/* get updated base address since it can be different between Serdes */
+	CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
+					   params->unit_offset,
+					   &unit_base_reg, &unit_offset));
+
+	/* Address calculation */
+	reg_addr = unit_base_reg + unit_offset * serdes_num;
+
+	/* Polling */
+#ifdef SEQ_DEBUG
+	printf("Poll:  0x%x: 0x%x (mask 0x%x)\n", reg_addr, data, mask);
+#endif
+
+	do {
+		reg_data = reg_read(reg_addr) & mask;
+		poll_counter++;
+		udelay(wait_time);
+	} while ((reg_data != data) && (poll_counter < num_of_loops));
+
+	if ((poll_counter >= num_of_loops) && (reg_data != data)) {
+		DEBUG_INIT_S("poll_op_execute: TIMEOUT\n");
+		return MV_TIMEOUT;
+	}
+
+	return MV_OK;
+}
+
+enum mv_op get_cfg_seq_op(struct op_params *params)
+{
+	if (params->wait_time == 0)
+		return WRITE_OP;
+	else if (params->num_of_loops == 0)
+		return DELAY_OP;
+
+	return POLL_OP;
+}
+
+int mv_seq_exec(u32 serdes_num, u32 seq_id)
+{
+	u32 seq_idx;
+	struct op_params *seq_arr;
+	u32 seq_size;
+	u32 data_arr_idx;
+	enum mv_op curr_op;
+
+	DB(printf("\n### mv_seq_exec ###\n"));
+	DB(printf("seq id: %d\n", seq_id));
+
+	if (hws_is_serdes_active(serdes_num) != 1) {
+		printf("mv_seq_exec_ext:Error: SerDes lane %d is not valid\n",
+		       serdes_num);
+		return MV_BAD_PARAM;
+	}
+
+	seq_arr = serdes_seq_db[seq_id].op_params_ptr;
+	seq_size = serdes_seq_db[seq_id].cfg_seq_size;
+	data_arr_idx = serdes_seq_db[seq_id].data_arr_idx;
+
+	DB(printf("seq_size: %d\n", seq_size));
+	DB(printf("data_arr_idx: %d\n", data_arr_idx));
+
+	/* Executing the sequence operations */
+	for (seq_idx = 0; seq_idx < seq_size; seq_idx++) {
+		curr_op = get_cfg_seq_op(&seq_arr[seq_idx]);
+		op_execute_func_arr[curr_op](serdes_num, &seq_arr[seq_idx],
+					     data_arr_idx);
+	}
+
+	return MV_OK;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h
new file mode 100644
index 0000000..14f406a
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _SEQ_EXEC_H
+#define _SEQ_EXEC_H
+
+#define NA			0xff
+#define DEFAULT_PARAM		0
+#define MV_BOARD_TCLK_ERROR	0xffffffff
+
+#define NO_DATA			0xffffffff
+#define MAX_DATA_ARRAY		5
+#define FIRST_CELL		0
+
+/* Operation types */
+enum mv_op {
+	WRITE_OP,
+	DELAY_OP,
+	POLL_OP,
+};
+
+/* Operation parameters */
+struct op_params {
+	u32 unit_base_reg;
+	u32 unit_offset;
+	u32 mask;
+	u32 data[MAX_DATA_ARRAY];	/* data array */
+	u8 wait_time;			/* msec */
+	u16 num_of_loops;		/* for polling only */
+};
+
+/*
+ * Sequence parameters. Each sequence contains:
+ * 1. Sequence id.
+ * 2. Sequence size (total amount of operations during the sequence)
+ * 3. a series of operations. operations can be write, poll or delay
+ * 4. index in the data array (the entry where the relevant data sits)
+ */
+struct cfg_seq {
+	struct op_params *op_params_ptr;
+	u8 cfg_seq_size;
+	u8 data_arr_idx;
+};
+
+extern struct cfg_seq serdes_seq_db[];
+
+/*
+ * A generic function type for executing an operation (write, poll or delay)
+ */
+typedef int (*op_execute_func_ptr)(u32 serdes_num, struct op_params *params,
+				   u32 data_arr_idx);
+
+/* Specific functions for executing each operation */
+int write_op_execute(u32 serdes_num, struct op_params *params,
+		     u32 data_arr_idx);
+int delay_op_execute(u32 serdes_num, struct op_params *params,
+		     u32 data_arr_idx);
+int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx);
+enum mv_op get_cfg_seq_op(struct op_params *params);
+int mv_seq_exec(u32 serdes_num, u32 seq_id);
+
+#endif /*_SEQ_EXEC_H*/
diff --git a/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
new file mode 100644
index 0000000..efd3873
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "seq_exec.h"
+#include "sys_env_lib.h"
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_a38x.h"
+
+#ifdef CONFIG_ARMADA_38X
+enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
+/*                     6820    6810     6811     6828     */
+/* PEX_UNIT_ID      */ { 4,     3,       3,       4},
+/* ETH_GIG_UNIT_ID  */ { 3,	2,       3,       3},
+/* USB3H_UNIT_ID    */ { 2,     2,       2,       2},
+/* USB3D_UNIT_ID    */ { 1,     1,       1,       1},
+/* SATA_UNIT_ID     */ { 2,     2,       2,       4},
+/* QSGMII_UNIT_ID   */ { 1,     0,       0,       1},
+/* XAUI_UNIT_ID     */ { 0,     0,       0,       0},
+/* RXAUI_UNIT_ID    */ { 0,     0,       0,       0}
+};
+#else  /* if (CONFIG_ARMADA_39X) */
+enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
+/*                      6920     6928     */
+/* PEX_UNIT_ID      */ { 4,       4},
+/* ETH_GIG_UNIT_ID  */ { 3,       4},
+/* USB3H_UNIT_ID    */ { 1,       2},
+/* USB3D_UNIT_ID    */ { 0,       1},
+/* SATA_UNIT_ID     */ { 0,       4},
+/* QSGMII_UNIT_ID   */ { 0,       1},
+/* XAUI_UNIT_ID     */ { 1,       1},
+/* RXAUI_UNIT_ID    */ { 1,	  1}
+};
+#endif
+
+u32 g_dev_id = -1;
+
+u32 mv_board_id_get(void)
+{
+#if defined(CONFIG_DB_88F6820_GP)
+	return DB_GP_68XX_ID;
+#else
+	/*
+	 * Return 0 here for custom board as this should not be used
+	 * for custom boards.
+	 */
+	return 0;
+#endif
+}
+
+u32 mv_board_tclk_get(void)
+{
+	u32 value;
+
+	value = (reg_read(DEVICE_SAMPLE_AT_RESET1_REG) >> 15) & 0x1;
+
+	switch (value) {
+	case (0x0):
+		return 250000000;
+	case (0x1):
+		return 200000000;
+	default:
+		return 0xffffffff;
+	}
+}
+
+u32 mv_board_id_index_get(u32 board_id)
+{
+	/*
+	 * Marvell Boards use 0x10 as base for Board ID:
+	 * mask MSB to receive index for board ID
+	 */
+	return board_id & (MARVELL_BOARD_ID_MASK - 1);
+}
+
+/*
+ * sys_env_suspend_wakeup_check
+ * DESCRIPTION:		Reads GPIO input for suspend-wakeup indication.
+ * INPUT:		None.
+ * OUTPUT:
+ * RETURNS:		u32 indicating suspend wakeup status:
+ * 0 - Not supported,
+ * 1 - supported: read magic word detect wakeup,
+ * 2 - detected wakeup from GPIO.
+ */
+enum suspend_wakeup_status sys_env_suspend_wakeup_check(void)
+{
+	u32 reg, board_id_index, gpio;
+	struct board_wakeup_gpio board_gpio[] = MV_BOARD_WAKEUP_GPIO_INFO;
+
+	board_id_index = mv_board_id_index_get(mv_board_id_get());
+	if (!(sizeof(board_gpio) / sizeof(struct board_wakeup_gpio) >
+	      board_id_index)) {
+		printf("\n_failed loading Suspend-Wakeup information (invalid board ID)\n");
+		return SUSPEND_WAKEUP_DISABLED;
+	}
+
+	/*
+	 * - Detect if Suspend-Wakeup is supported on current board
+	 * - Fetch the GPIO number for wakeup status input indication
+	 */
+	if (board_gpio[board_id_index].gpio_num == -1) {
+		/* Suspend to RAM is not supported */
+		return SUSPEND_WAKEUP_DISABLED;
+	} else if (board_gpio[board_id_index].gpio_num == -2) {
+		/*
+		 * Suspend to RAM is supported but GPIO indication is
+		 * not implemented - Skip
+		 */
+		return SUSPEND_WAKEUP_ENABLED;
+	} else {
+		gpio = board_gpio[board_id_index].gpio_num;
+	}
+
+	/* Initialize MPP for GPIO (set MPP = 0x0) */
+	reg = reg_read(MPP_CONTROL_REG(MPP_REG_NUM(gpio)));
+	/* reset MPP21 to 0x0, keep rest of MPP settings*/
+	reg &= ~MPP_MASK(gpio);
+	reg_write(MPP_CONTROL_REG(MPP_REG_NUM(gpio)), reg);
+
+	/* Initialize GPIO as input */
+	reg = reg_read(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)));
+	reg |= GPP_MASK(gpio);
+	reg_write(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)), reg);
+
+	/*
+	 * Check GPP for input status from PIC: 0 - regular init,
+	 * 1 - suspend wakeup
+	 */
+	reg = reg_read(GPP_DATA_IN_REG(GPP_REG_NUM(gpio)));
+
+	/* if GPIO is ON: wakeup from S2RAM indication detected */
+	return (reg & GPP_MASK(gpio)) ? SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED :
+		SUSPEND_WAKEUP_DISABLED;
+}
+
+/*
+ * mv_ctrl_dev_id_index_get
+ *
+ * DESCRIPTION: return SOC device index
+ * INPUT: None
+ * OUTPUT: None
+ * RETURN:
+ *        return SOC device index
+ */
+u32 sys_env_id_index_get(u32 ctrl_model)
+{
+	switch (ctrl_model) {
+	case MV_6820_DEV_ID:
+		return MV_6820_INDEX;
+	case MV_6810_DEV_ID:
+		return MV_6810_INDEX;
+	case MV_6811_DEV_ID:
+		return MV_6811_INDEX;
+	case MV_6828_DEV_ID:
+		return MV_6828_INDEX;
+	case MV_6920_DEV_ID:
+		return MV_6920_INDEX;
+	case MV_6928_DEV_ID:
+		return MV_6928_INDEX;
+	default:
+		return MV_6820_INDEX;
+	}
+}
+
+u32 sys_env_unit_max_num_get(enum unit_id unit)
+{
+	u32 dev_id_index;
+
+	if (unit >= MAX_UNITS_ID) {
+		printf("%s: Error: Wrong unit type (%u)\n", __func__, unit);
+		return 0;
+	}
+
+	dev_id_index = sys_env_id_index_get(sys_env_model_get());
+	return sys_env_soc_unit_nums[unit][dev_id_index];
+}
+
+/*
+ * sys_env_model_get
+ * DESCRIPTION:	Returns 16bit describing the device model (ID) as defined
+ *		in Vendor ID configuration register
+ */
+u16 sys_env_model_get(void)
+{
+	u32 default_ctrl_id, ctrl_id = reg_read(DEV_ID_REG);
+	ctrl_id = (ctrl_id & (DEV_ID_REG_DEVICE_ID_MASK)) >>
+		DEV_ID_REG_DEVICE_ID_OFFS;
+
+	switch (ctrl_id) {
+	case MV_6820_DEV_ID:
+	case MV_6810_DEV_ID:
+	case MV_6811_DEV_ID:
+	case MV_6828_DEV_ID:
+	case MV_6920_DEV_ID:
+	case MV_6928_DEV_ID:
+		return ctrl_id;
+	default:
+		/* Device ID Default for A38x: 6820 , for A39x: 6920 */
+	#ifdef CONFIG_ARMADA_38X
+		default_ctrl_id =  MV_6820_DEV_ID;
+	#else
+		default_ctrl_id = MV_6920_DEV_ID;
+	#endif
+		printf("%s: Error retrieving device ID (%x), using default ID = %x\n",
+		       __func__, ctrl_id, default_ctrl_id);
+		return default_ctrl_id;
+	}
+}
+
+/*
+ * sys_env_device_id_get
+ * DESCRIPTION:	Returns enum (0..7) index of the device model (ID)
+ */
+u32 sys_env_device_id_get(void)
+{
+	char *device_id_str[7] = {
+		"6810", "6820", "6811", "6828", "NONE", "6920", "6928"
+	};
+
+	if (g_dev_id != -1)
+		return g_dev_id;
+
+	g_dev_id = reg_read(DEVICE_SAMPLE_AT_RESET1_REG);
+	g_dev_id = g_dev_id >> SAR_DEV_ID_OFFS & SAR_DEV_ID_MASK;
+	printf("Detected Device ID %s\n", device_id_str[g_dev_id]);
+
+	return g_dev_id;
+}
+
+#ifdef MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI
+/*
+* sys_env_get_topology_update_info
+* DESCRIPTION: Read TWSI fields to update DDR topology structure
+* INPUT: None
+* OUTPUT: None, 0 means no topology update
+* RETURN:
+*       Bit mask of changes topology features
+*/
+#ifdef CONFIG_ARMADA_39X
+u32 sys_env_get_topology_update_info(
+	struct topology_update_info *tui)
+{
+	/* Set 16/32 bit configuration*/
+	tui->update_width = 1;
+	tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+
+#ifdef CONFIG_DDR3
+	if (1 == sys_env_config_get(MV_CONFIG_DDR_BUSWIDTH)) {
+		/* 16bit */
+		tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+	} else {
+		/* 32bit */
+		tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+	}
+#endif
+
+	/* Set ECC/no ECC bit configuration */
+	tui->update_ecc = 1;
+	if (0 == sys_env_config_get(MV_CONFIG_DDR_ECC_EN)) {
+		/* NO ECC */
+		tui->ecc = TOPOLOGY_UPDATE_ECC_OFF;
+	} else {
+		/* ECC */
+		tui->ecc = TOPOLOGY_UPDATE_ECC_ON;
+	}
+
+	tui->update_ecc_pup3_mode = 1;
+	tui->ecc_pup_mode_offset = TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+
+	return MV_OK;
+}
+#else /*CONFIG_ARMADA_38X*/
+u32 sys_env_get_topology_update_info(
+	struct topology_update_info *tui)
+{
+	u8 config_val;
+	u8 ecc_mode[A38X_MV_MAX_MARVELL_BOARD_ID -
+		    A38X_MARVELL_BOARD_ID_BASE][5] = TOPOLOGY_UPDATE;
+	u8 board_id = mv_board_id_get();
+	int ret;
+
+	board_id = mv_board_id_index_get(board_id);
+	ret = i2c_read(EEPROM_I2C_ADDR, 0, 2, &config_val, 1);
+	if (ret) {
+		DEBUG_INIT_S("sys_env_get_topology_update_info: TWSI Read failed\n");
+		return 0;
+	}
+
+	/* Set 16/32 bit configuration */
+	if ((0 == (config_val & DDR_SATR_CONFIG_MASK_WIDTH)) ||
+	    (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] == 0)) {
+		/* 16bit by SatR of 32bit mode not supported for the board */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT] != 0)) {
+			tui->update_width = 1;
+			tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+		}
+	} else {
+		/* 32bit */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] != 0)) {
+			tui->update_width = 1;
+			tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+		}
+	}
+
+	/* Set ECC/no ECC bit configuration */
+	if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC)) {
+		/* NO ECC */
+		tui->update_ecc = 1;
+		tui->ecc = TOPOLOGY_UPDATE_ECC_OFF;
+	} else {
+		/* ECC */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) ||
+		    (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0) ||
+		    (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) {
+			tui->update_ecc = 1;
+			tui->ecc = TOPOLOGY_UPDATE_ECC_ON;
+		}
+	}
+
+	/* Set ECC pup bit configuration */
+	if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC_PUP)) {
+		/* PUP3 */
+		/*
+		 * Check if PUP3 configuration allowed, if not -
+		 * force Pup4 with warning message
+		 */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) {
+			if (tui->width == TOPOLOGY_UPDATE_WIDTH_16BIT) {
+				tui->update_ecc_pup3_mode = 1;
+				tui->ecc_pup_mode_offset =
+					TOPOLOGY_UPDATE_ECC_OFFSET_PUP3;
+			} else {
+				if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0)) {
+					printf("DDR Topology Update: ECC PUP3 not valid for 32bit mode, force ECC in PUP4\n");
+					tui->update_ecc_pup3_mode = 1;
+					tui->ecc_pup_mode_offset =
+						TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+				}
+			}
+		} else {
+			if (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] !=
+			    0) {
+				printf("DDR Topology Update: ECC on PUP3 not supported, force ECC on PUP4\n");
+				tui->update_ecc_pup3_mode = 1;
+				tui->ecc_pup_mode_offset =
+					TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+			}
+		}
+	} else {
+		/* PUP4 */
+		if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) ||
+		    (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0)) {
+			tui->update_ecc_pup3_mode = 1;
+			tui->ecc_pup_mode_offset =
+				TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+		}
+	}
+
+	/*
+	 * Check for forbidden ECC mode,
+	 * if by default width and pup selection set 32bit ECC mode and this
+	 * mode not supported for the board - config 16bit with ECC on PUP3
+	 */
+	if ((tui->ecc == TOPOLOGY_UPDATE_ECC_ON) &&
+	    (tui->width == TOPOLOGY_UPDATE_WIDTH_32BIT)) {
+		if (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] == 0) {
+			printf("DDR Topology Update: 32bit mode with ECC not allowed on this board, forced  16bit with ECC on PUP3\n");
+			tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+			tui->update_ecc_pup3_mode = 1;
+			tui->ecc_pup_mode_offset =
+				TOPOLOGY_UPDATE_ECC_OFFSET_PUP3;
+		}
+	}
+
+	return MV_OK;
+}
+#endif /* CONFIG_ARMADA_38X */
+#endif /* MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI */
diff --git a/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h
new file mode 100644
index 0000000..6b5bcb9
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _SYS_ENV_LIB_H
+#define _SYS_ENV_LIB_H
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
+#include "../../../drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h"
+
+/* Serdes definitions */
+#define COMMON_PHY_BASE_ADDR		0x18300
+
+#define DEVICE_CONFIGURATION_REG0	0x18284
+#define DEVICE_CONFIGURATION_REG1	0x18288
+#define COMMON_PHY_CONFIGURATION1_REG	0x18300
+#define COMMON_PHY_CONFIGURATION2_REG	0x18304
+#define COMMON_PHY_CONFIGURATION4_REG	0x1830c
+#define COMMON_PHY_STATUS1_REG		0x18318
+#define COMMON_PHYS_SELECTORS_REG	0x183fc
+#define SOC_CONTROL_REG1		0x18204
+#define GENERAL_PURPOSE_RESERVED0_REG	0x182e0
+#define GBE_CONFIGURATION_REG		0x18460
+#define DEVICE_SAMPLE_AT_RESET1_REG	0x18600
+#define DEVICE_SAMPLE_AT_RESET2_REG	0x18604
+#define DEV_ID_REG			0x18238
+
+#define CORE_PLL_PARAMETERS_REG		0xe42e0
+#define CORE_PLL_CONFIG_REG		0xe42e4
+
+#define QSGMII_CONTROL_REG1		0x18494
+
+#define DEV_ID_REG_DEVICE_ID_OFFS	16
+#define DEV_ID_REG_DEVICE_ID_MASK	0xffff0000
+
+#define SAR_DEV_ID_OFFS			27
+#define SAR_DEV_ID_MASK			0x7
+
+#define POWER_AND_PLL_CTRL_REG		0xa0004
+#define CALIBRATION_CTRL_REG		0xa0008
+#define DFE_REG0			0xa001c
+#define DFE_REG3			0xa0028
+#define RESET_DFE_REG			0xa0148
+#define LOOPBACK_REG			0xa008c
+#define SYNC_PATTERN_REG		0xa0090
+#define INTERFACE_REG			0xa0094
+#define ISOLATE_REG			0xa0098
+#define MISC_REG			0xa013c
+#define GLUE_REG			0xa0140
+#define GENERATION_DIVIDER_FORCE_REG	0xa0144
+#define PCIE_REG0			0xa0120
+#define LANE_ALIGN_REG0			0xa0124
+#define SQUELCH_FFE_SETTING_REG		0xa0018
+#define G1_SETTINGS_0_REG		0xa0034
+#define G1_SETTINGS_1_REG		0xa0038
+#define G1_SETTINGS_3_REG		0xa0440
+#define G1_SETTINGS_4_REG		0xa0444
+#define G2_SETTINGS_0_REG		0xa003c
+#define G2_SETTINGS_1_REG		0xa0040
+#define G2_SETTINGS_2_REG		0xa00f8
+#define G2_SETTINGS_3_REG		0xa0448
+#define G2_SETTINGS_4_REG		0xa044c
+#define G3_SETTINGS_0_REG		0xa0044
+#define G3_SETTINGS_1_REG		0xa0048
+#define G3_SETTINGS_3_REG		0xa0450
+#define G3_SETTINGS_4_REG		0xa0454
+#define VTHIMPCAL_CTRL_REG		0xa0104
+#define REF_REG0			0xa0134
+#define CAL_REG6			0xa0168
+#define RX_REG2				0xa0184
+#define RX_REG3				0xa0188
+#define PCIE_REG1			0xa0288
+#define PCIE_REG3			0xa0290
+#define LANE_CFG1_REG			0xa0604
+#define LANE_CFG4_REG			0xa0620
+#define LANE_CFG5_REG			0xa0624
+#define GLOBAL_CLK_CTRL			0xa0704
+#define GLOBAL_MISC_CTRL		0xa0718
+#define GLOBAL_CLK_SRC_HI		0xa0710
+
+#define GLOBAL_CLK_CTRL			0xa0704
+#define GLOBAL_MISC_CTRL		0xa0718
+#define GLOBAL_PM_CTRL			0xa0740
+
+/* SATA registers */
+#define SATA_CTRL_REG_IND_ADDR		0xa80a0
+#define SATA_CTRL_REG_IND_DATA		0xa80a4
+
+#define SATA_VENDOR_PORT_0_REG_ADDR	0xa8178
+#define SATA_VENDOR_PORT_1_REG_ADDR	0xa81f8
+#define SATA_VENDOR_PORT_0_REG_DATA	0xa817c
+#define SATA_VENDOR_PORT_1_REG_DATA	0xa81fc
+
+/* Reference clock values and mask */
+#define POWER_AND_PLL_CTRL_REG_100MHZ_VAL	0x0
+#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1	0x1
+#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2	0x2
+#define POWER_AND_PLL_CTRL_REG_40MHZ_VAL	0x3
+#define GLOBAL_PM_CTRL_REG_25MHZ_VAL		0x7
+#define GLOBAL_PM_CTRL_REG_40MHZ_VAL		0xc
+#define LANE_CFG4_REG_25MHZ_VAL			0x200
+#define LANE_CFG4_REG_40MHZ_VAL			0x300
+
+#define POWER_AND_PLL_CTRL_REG_MASK		(~(0x1f))
+#define GLOBAL_PM_CTRL_REG_MASK			(~(0xff))
+#define LANE_CFG4_REG_MASK			(~(0x1f00))
+
+#define REF_CLK_SELECTOR_VAL_PEX0(reg_val)	(reg_val >> 2) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX1(reg_val)	(reg_val >> 3) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX2(reg_val)	(reg_val >> 30) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX3(reg_val)	(reg_val >> 31) & 0x1
+#define REF_CLK_SELECTOR_VAL(reg_val)		(reg_val & 0x1)
+
+#define MAX_SELECTOR_VAL			10
+
+/* TWSI addresses */
+/* starting from A38x A0, i2c address of EEPROM is 0x57 */
+#ifdef CONFIG_ARMADA_39X
+#define EEPROM_I2C_ADDR			0x50
+#else
+#define EEPROM_I2C_ADDR			(sys_env_device_rev_get() == \
+					 MV_88F68XX_Z1_ID ? 0x50 : 0x57)
+#endif
+#define RD_GET_MODE_ADDR		0x4c
+#define DB_GET_MODE_SLM1363_ADDR	0x25
+#define DB_GET_MODE_SLM1364_ADDR	0x24
+#define DB381_GET_MODE_SLM1426_1427_ADDR 0x56
+
+/* DB-BP Board 'SatR' mapping */
+#define SATR_DB_LANE1_MAX_OPTIONS	7
+#define SATR_DB_LANE1_CFG_MASK		0x7
+#define SATR_DB_LANE1_CFG_OFFSET	0
+#define SATR_DB_LANE2_MAX_OPTIONS	4
+#define SATR_DB_LANE2_CFG_MASK		0x38
+#define SATR_DB_LANE2_CFG_OFFSET	3
+
+/* GP Board 'SatR' mapping */
+#define SATR_GP_LANE1_CFG_MASK		0x4
+#define SATR_GP_LANE1_CFG_OFFSET	2
+#define SATR_GP_LANE2_CFG_MASK		0x8
+#define SATR_GP_LANE2_CFG_OFFSET	3
+
+/* For setting MPP2 and MPP3 to be TWSI mode and MPP 0,1 to UART mode */
+#define MPP_CTRL_REG			0x18000
+#define MPP_SET_MASK			(~(0xffff))
+#define MPP_SET_DATA			(0x1111)
+#define MPP_UART1_SET_MASK		(~(0xff000))
+#define MPP_UART1_SET_DATA		(0x66000)
+
+#define AVS_DEBUG_CNTR_REG		0xe4124
+#define AVS_DEBUG_CNTR_DEFAULT_VALUE	0x08008073
+
+#define AVS_ENABLED_CONTROL		0xe4130
+#define AVS_LOW_VDD_LIMIT_OFFS		4
+#define AVS_LOW_VDD_LIMIT_MASK		(0xff << AVS_LOW_VDD_LIMIT_OFFS)
+#define AVS_LOW_VDD_LIMIT_VAL		(0x27 << AVS_LOW_VDD_LIMIT_OFFS)
+
+#define AVS_HIGH_VDD_LIMIT_OFFS		12
+#define AVS_HIGH_VDD_LIMIT_MASK		(0xff << AVS_HIGH_VDD_LIMIT_OFFS)
+#define AVS_HIGH_VDD_LIMIT_VAL		(0x27 << AVS_HIGH_VDD_LIMIT_OFFS)
+
+/* Board ID numbers */
+#define MARVELL_BOARD_ID_MASK		0x10
+/* Customer boards for A38x */
+#define A38X_CUSTOMER_BOARD_ID_BASE	0x0
+#define A38X_CUSTOMER_BOARD_ID0		(A38X_CUSTOMER_BOARD_ID_BASE + 0)
+#define A38X_CUSTOMER_BOARD_ID1		(A38X_CUSTOMER_BOARD_ID_BASE + 1)
+#define A38X_MV_MAX_CUSTOMER_BOARD_ID	(A38X_CUSTOMER_BOARD_ID_BASE + 2)
+#define A38X_MV_CUSTOMER_BOARD_NUM	(A38X_MV_MAX_CUSTOMER_BOARD_ID - \
+					 A38X_CUSTOMER_BOARD_ID_BASE)
+
+/* Marvell boards for A38x */
+#define A38X_MARVELL_BOARD_ID_BASE	0x10
+#define RD_NAS_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 0)
+#define DB_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 1)
+#define RD_AP_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 2)
+#define DB_AP_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 3)
+#define DB_GP_68XX_ID			(A38X_MARVELL_BOARD_ID_BASE + 4)
+#define DB_BP_6821_ID			(A38X_MARVELL_BOARD_ID_BASE + 5)
+#define DB_AMC_6820_ID			(A38X_MARVELL_BOARD_ID_BASE + 6)
+#define A38X_MV_MAX_MARVELL_BOARD_ID	(A38X_MARVELL_BOARD_ID_BASE + 7)
+#define A38X_MV_MARVELL_BOARD_NUM	(A38X_MV_MAX_MARVELL_BOARD_ID - \
+					 A38X_MARVELL_BOARD_ID_BASE)
+
+/* Customer boards for A39x */
+#define A39X_CUSTOMER_BOARD_ID_BASE	0x20
+#define A39X_CUSTOMER_BOARD_ID0		(A39X_CUSTOMER_BOARD_ID_BASE + 0)
+#define A39X_CUSTOMER_BOARD_ID1		(A39X_CUSTOMER_BOARD_ID_BASE + 1)
+#define A39X_MV_MAX_CUSTOMER_BOARD_ID	(A39X_CUSTOMER_BOARD_ID_BASE + 2)
+#define A39X_MV_CUSTOMER_BOARD_NUM	(A39X_MV_MAX_CUSTOMER_BOARD_ID - \
+					 A39X_CUSTOMER_BOARD_ID_BASE)
+
+/* Marvell boards for A39x */
+#define A39X_MARVELL_BOARD_ID_BASE	0x30
+#define A39X_DB_69XX_ID			(A39X_MARVELL_BOARD_ID_BASE + 0)
+#define A39X_RD_69XX_ID			(A39X_MARVELL_BOARD_ID_BASE + 1)
+#define A39X_MV_MAX_MARVELL_BOARD_ID	(A39X_MARVELL_BOARD_ID_BASE + 2)
+#define A39X_MV_MARVELL_BOARD_NUM	(A39X_MV_MAX_MARVELL_BOARD_ID - \
+					 A39X_MARVELL_BOARD_ID_BASE)
+
+#ifdef CONFIG_ARMADA_38X
+#define CUTOMER_BOARD_ID_BASE		A38X_CUSTOMER_BOARD_ID_BASE
+#define CUSTOMER_BOARD_ID0		A38X_CUSTOMER_BOARD_ID0
+#define CUSTOMER_BOARD_ID1		A38X_CUSTOMER_BOARD_ID1
+#define MV_MAX_CUSTOMER_BOARD_ID	A38X_MV_MAX_CUSTOMER_BOARD_ID
+#define MV_CUSTOMER_BOARD_NUM		A38X_MV_CUSTOMER_BOARD_NUM
+#define MARVELL_BOARD_ID_BASE		A38X_MARVELL_BOARD_ID_BASE
+#define MV_MAX_MARVELL_BOARD_ID		A38X_MV_MAX_MARVELL_BOARD_ID
+#define MV_MARVELL_BOARD_NUM		A38X_MV_MARVELL_BOARD_NUM
+#define MV_DEFAULT_BOARD_ID		DB_68XX_ID
+#define MV_DEFAULT_DEVICE_ID		MV_6811
+#elif defined(CONFIG_ARMADA_39X)
+#define CUTOMER_BOARD_ID_BASE		A39X_CUSTOMER_BOARD_ID_BASE
+#define CUSTOMER_BOARD_ID0		A39X_CUSTOMER_BOARD_ID0
+#define CUSTOMER_BOARD_ID1		A39X_CUSTOMER_BOARD_ID1
+#define MV_MAX_CUSTOMER_BOARD_ID	A39X_MV_MAX_CUSTOMER_BOARD_ID
+#define MV_CUSTOMER_BOARD_NUM		A39X_MV_CUSTOMER_BOARD_NUM
+#define MARVELL_BOARD_ID_BASE		A39X_MARVELL_BOARD_ID_BASE
+#define MV_MAX_MARVELL_BOARD_ID		A39X_MV_MAX_MARVELL_BOARD_ID
+#define MV_MARVELL_BOARD_NUM		A39X_MV_MARVELL_BOARD_NUM
+#define MV_DEFAULT_BOARD_ID		A39X_DB_69XX_ID
+#define MV_DEFAULT_DEVICE_ID		MV_6920
+#endif
+
+#define MV_INVALID_BOARD_ID		0xffffffff
+
+/* device revesion */
+#define DEV_VERSION_ID_REG		0x1823c
+#define REVISON_ID_OFFS			8
+#define REVISON_ID_MASK			0xf00
+
+/* A38x revisions */
+#define MV_88F68XX_Z1_ID		0x0
+#define MV_88F68XX_A0_ID		0x4
+/* A39x revisions */
+#define MV_88F69XX_Z1_ID		0x2
+
+#define MPP_CONTROL_REG(id)		(0x18000 + (id * 4))
+#define GPP_DATA_OUT_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x00)
+#define GPP_DATA_OUT_EN_REG(grp)	(MV_GPP_REGS_BASE(grp) + 0x04)
+#define GPP_DATA_IN_REG(grp)		(MV_GPP_REGS_BASE(grp) + 0x10)
+#define MV_GPP_REGS_BASE(unit)		(0x18100 + ((unit) * 0x40))
+
+#define MPP_REG_NUM(GPIO_NUM)		(GPIO_NUM / 8)
+#define MPP_MASK(GPIO_NUM)		(0xf << 4 * (GPIO_NUM - \
+					(MPP_REG_NUM(GPIO_NUM) * 8)));
+#define GPP_REG_NUM(GPIO_NUM)		(GPIO_NUM / 32)
+#define GPP_MASK(GPIO_NUM)		(1 << GPIO_NUM % 32)
+
+/* device ID */
+/* Armada 38x Family */
+#define MV_6810_DEV_ID		0x6810
+#define MV_6811_DEV_ID		0x6811
+#define MV_6820_DEV_ID		0x6820
+#define MV_6828_DEV_ID		0x6828
+/* Armada 39x Family */
+#define MV_6920_DEV_ID		0x6920
+#define MV_6928_DEV_ID		0x6928
+
+enum {
+	MV_6810,
+	MV_6820,
+	MV_6811,
+	MV_6828,
+	MV_NONE,
+	MV_6920,
+	MV_6928,
+	MV_MAX_DEV_ID,
+};
+
+#define MV_6820_INDEX			0
+#define MV_6810_INDEX			1
+#define MV_6811_INDEX			2
+#define MV_6828_INDEX			3
+
+#define MV_6920_INDEX			0
+#define MV_6928_INDEX			1
+
+#ifdef CONFIG_ARMADA_38X
+#define MAX_DEV_ID_NUM			4
+#else
+#define MAX_DEV_ID_NUM			2
+#endif
+
+#define MV_6820_INDEX			0
+#define MV_6810_INDEX			1
+#define MV_6811_INDEX			2
+#define MV_6828_INDEX			3
+#define MV_6920_INDEX			0
+#define MV_6928_INDEX			1
+
+enum unit_id {
+	PEX_UNIT_ID,
+	ETH_GIG_UNIT_ID,
+	USB3H_UNIT_ID,
+	USB3D_UNIT_ID,
+	SATA_UNIT_ID,
+	QSGMII_UNIT_ID,
+	XAUI_UNIT_ID,
+	RXAUI_UNIT_ID,
+	MAX_UNITS_ID
+};
+
+struct board_wakeup_gpio {
+	u32 board_id;
+	int gpio_num;
+};
+
+enum suspend_wakeup_status {
+	SUSPEND_WAKEUP_DISABLED,
+	SUSPEND_WAKEUP_ENABLED,
+	SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED,
+};
+
+/*
+ * GPIO status indication for Suspend Wakeup:
+ * If suspend to RAM is supported and GPIO inidcation is implemented,
+ * set the gpio number
+ * If suspend to RAM is supported but GPIO indication is not implemented
+ * set '-2'
+ * If suspend to RAM is not supported set '-1'
+ */
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+#ifdef CONFIG_ARMADA_38X
+#define MV_BOARD_WAKEUP_GPIO_INFO {		\
+	{A38X_CUSTOMER_BOARD_ID0,	-1 },	\
+	{A38X_CUSTOMER_BOARD_ID0,	-1 },	\
+};
+#else
+#define MV_BOARD_WAKEUP_GPIO_INFO {		\
+	{A39X_CUSTOMER_BOARD_ID0,	-1 },	\
+	{A39X_CUSTOMER_BOARD_ID0,	-1 },	\
+};
+#endif /* CONFIG_ARMADA_38X */
+
+#else
+
+#ifdef CONFIG_ARMADA_38X
+#define MV_BOARD_WAKEUP_GPIO_INFO {	\
+	{RD_NAS_68XX_ID, -2 },		\
+	{DB_68XX_ID,	 -1 },		\
+	{RD_AP_68XX_ID,	 -2 },		\
+	{DB_AP_68XX_ID,	 -2 },		\
+	{DB_GP_68XX_ID,	 -2 },		\
+	{DB_BP_6821_ID,	 -2 },		\
+	{DB_AMC_6820_ID, -2 },		\
+};
+#else
+#define MV_BOARD_WAKEUP_GPIO_INFO {	\
+	{A39X_RD_69XX_ID, -1 },		\
+	{A39X_DB_69XX_ID, -1 },		\
+};
+#endif /* CONFIG_ARMADA_38X */
+#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */
+
+u32 mv_board_tclk_get(void);
+u32 mv_board_id_get(void);
+u32 mv_board_id_index_get(u32 board_id);
+u32 sys_env_unit_max_num_get(enum unit_id unit);
+enum suspend_wakeup_status sys_env_suspend_wakeup_check(void);
+u8 sys_env_device_rev_get(void);
+u32 sys_env_device_id_get(void);
+u16 sys_env_model_get(void);
+struct dlb_config *sys_env_dlb_config_ptr_get(void);
+u32 sys_env_get_topology_update_info(
+	struct topology_update_info *topology_update_info);
+u32 sys_env_get_cs_ena_from_reg(void);
+
+#endif /* _SYS_ENV_LIB_H */
+
-- 
2.4.2



More information about the U-Boot mailing list