]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
arm: mvebu: Add Armada 38x SERDES / PHY init code from Marvell bin_hdr
authorStefan Roese <sr@denx.de>
Mon, 20 Apr 2015 07:31:27 +0000 (09:31 +0200)
committerLothar Waßmann <LW@KARO-electronics.de>
Wed, 9 Sep 2015 11:49:02 +0000 (13:49 +0200)
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@denx.de>
13 files changed:
arch/arm/mach-mvebu/Makefile
arch/arm/mach-mvebu/serdes/a38x/Makefile [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec-38x.c [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec-38x.c [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/seq_exec.c [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/seq_exec.h [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c [new file with mode: 0644]
arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.h [new file with mode: 0644]

index 9cdbefd24b1a2a008188158c463e4bd5369474dd..446ce04109740cb47c57becab6e9f6c1ce557f79 100644 (file)
@@ -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 (file)
index 0000000..1503da8
--- /dev/null
@@ -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 (file)
index 0000000..5f223f9
--- /dev/null
@@ -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 (file)
index 0000000..5032759
--- /dev/null
@@ -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 (file)
index 0000000..5ff8567
--- /dev/null
@@ -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 (file)
index 0000000..23af769
--- /dev/null
@@ -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@R */
+       ref_clock = hws_serdes_silicon_ref_clock_get();
+
+       if (serdes_type > PEX3) {
+               /* for all Serdes types but PCIe */
+               return ref_clock;
+       }
+
+       /* for PCIe, need also to check PCIe S@R */
+       CHECK_STATUS(hws_serdes_pex_ref_clock_satr_get
+                    (serdes_type, &pex_satr));
+
+       if (pex_satr == 0) {
+               return REF_CLOCK_100MHZ;
+       } else if (pex_satr == 1) {
+               /* value of 1 means we can use ref clock from SoC (as other Serdes types) */
+               return ref_clock;
+       } else {
+               printf
+                   ("%s: Error: REF_CLK_SELECTOR_VAL for SerDes type %d is wrong\n",
+                    __func__, serdes_type);
+               return REF_CLOCK_UNSUPPORTED;
+       }
+}
+
+int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up,
+                        enum serdes_type serdes_type,
+                        enum serdes_speed baud_rate,
+                        enum serdes_mode serdes_mode, enum ref_clock ref_clock)
+{
+       u32 sata_idx, pex_idx, sata_port;
+       enum serdes_seq speed_seq_id;
+       u32 reg_data;
+       int is_pex_by1;
+
+       DEBUG_INIT_FULL_S("\n### serdes_power_up_ctrl ###\n");
+
+       if (serdes_power_up == 1) {     /* Serdes power up */
+               DEBUG_INIT_FULL_S
+                   ("serdes_power_up_ctrl: executing power up.. ");
+               DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 2);
+               DEBUG_INIT_FULL_C("serdes type = ", serdes_type, 2);
+
+               DEBUG_INIT_FULL_S("Going access 1");
+
+               /* Getting the Speed Select sequence id */
+               speed_seq_id =
+                       serdes_type_and_speed_to_speed_seq(serdes_type,
+                                                          baud_rate);
+               if (speed_seq_id == SERDES_LAST_SEQ) {
+                       printf
+                           ("serdes_power_up_ctrl: serdes type %d and speed %d are not supported together\n",
+                            serdes_type, baud_rate);
+
+                       return MV_BAD_PARAM;
+               }
+
+               /* Executing power up, ref clock set, speed config and TX config */
+               switch (serdes_type) {
+               case PEX0:
+               case PEX1:
+               case PEX2:
+               case PEX3:
+                       if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+                               CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a
+                                            (serdes_num, PEX));
+                       }
+
+                       is_pex_by1 = (serdes_mode == PEX_ROOT_COMPLEX_X1) ||
+                               (serdes_mode == PEX_END_POINT_X1);
+                       pex_idx = serdes_type - PEX0;
+
+                       if ((is_pex_by1 == 1) || (serdes_type == PEX0)) {
+                               /* For PEX by 4, init only the PEX 0 */
+                               reg_data = reg_read(SOC_CONTROL_REG1);
+                               if (is_pex_by1 == 1)
+                                       reg_data |= 0x4000;
+                               else
+                                       reg_data &= ~0x4000;
+                               reg_write(SOC_CONTROL_REG1, reg_data);
+
+                               reg_data =
+                                   reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+                                             0x6c));
+                               reg_data &= ~0x3f0;
+                               if (is_pex_by1 == 1)
+                                       reg_data |= 0x10;
+                               else
+                                       reg_data |= 0x40;
+                               reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c),
+                                         reg_data);
+
+                               reg_data =
+                                   reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+                                             0x6c));
+                               reg_data &= ~0xf;
+                               reg_data |= 0x2;
+                               reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c),
+                                         reg_data);
+
+                               reg_data =
+                                   reg_read(((PEX_IF_REGS_BASE(pex_idx)) +
+                                             0x70));
+                               reg_data &= ~0x40;
+                               reg_data |= 0x40;
+                               reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x70),
+                                         reg_data);
+                       }
+
+                       CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ));
+                       if (is_pex_by1 == 0) {
+                               /*
+                                * for PEX by 4 - use the PEX index as the
+                                * seq array index
+                                */
+                               serdes_seq_db[PEX_BY_4_CONFIG_SEQ].
+                                   data_arr_idx = pex_idx;
+                               CHECK_STATUS(mv_seq_exec
+                                            (serdes_num, PEX_BY_4_CONFIG_SEQ));
+                       }
+
+                       CHECK_STATUS(hws_ref_clock_set
+                                    (serdes_num, serdes_type, ref_clock));
+                       CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, PEX_ELECTRICAL_CONFIG_SEQ));
+
+                       if (is_pex_by1 == 1) {
+                               CHECK_STATUS(mv_seq_exec
+                                            (serdes_num, PEX_TX_CONFIG_SEQ2));
+                               CHECK_STATUS(mv_seq_exec
+                                            (serdes_num, PEX_TX_CONFIG_SEQ3));
+                               CHECK_STATUS(mv_seq_exec
+                                            (serdes_num, PEX_TX_CONFIG_SEQ1));
+                       }
+                       udelay(20);
+
+                       break;
+               case USB3_HOST0:
+               case USB3_HOST1:
+               case USB3_DEVICE:
+                       if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
+                               CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a
+                                            (serdes_num, USB3));
+                       }
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, USB3_POWER_UP_SEQ));
+                       CHECK_STATUS(hws_ref_clock_set
+                                    (serdes_num, serdes_type, ref_clock));
+                       CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+                       if (serdes_type == USB3_DEVICE) {
+                               CHECK_STATUS(mv_seq_exec
+                                            (serdes_num,
+                                             USB3_DEVICE_CONFIG_SEQ));
+                       }
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, USB3_ELECTRICAL_CONFIG_SEQ));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, USB3_TX_CONFIG_SEQ1));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, USB3_TX_CONFIG_SEQ2));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, USB3_TX_CONFIG_SEQ3));
+
+                       udelay(10000);
+                       break;
+               case SATA0:
+               case SATA1:
+               case SATA2:
+               case SATA3:
+                       sata_idx = ((serdes_type == SATA0) ||
+                                   (serdes_type == SATA1)) ? 0 : 1;
+                       sata_port = ((serdes_type == SATA0) ||
+                                    (serdes_type == SATA2)) ? 0 : 1;
+
+                       CHECK_STATUS(mv_seq_exec
+                                    (sata_idx, (sata_port == 0) ?
+                                     SATA_PORT_0_ONLY_POWER_UP_SEQ :
+                                     SATA_PORT_1_ONLY_POWER_UP_SEQ));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SATA_POWER_UP_SEQ));
+                       CHECK_STATUS(hws_ref_clock_set
+                                    (serdes_num, serdes_type, ref_clock));
+                       CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SATA_ELECTRICAL_CONFIG_SEQ));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SATA_TX_CONFIG_SEQ1));
+                       CHECK_STATUS(mv_seq_exec
+                                    (sata_idx, (sata_port == 0) ?
+                                     SATA_PORT_0_ONLY_TX_CONFIG_SEQ :
+                                     SATA_PORT_1_ONLY_TX_CONFIG_SEQ));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SATA_TX_CONFIG_SEQ2));
+
+                       udelay(10000);
+                       break;
+               case SGMII0:
+               case SGMII1:
+               case SGMII2:
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SGMII_POWER_UP_SEQ));
+                       CHECK_STATUS(hws_ref_clock_set
+                                    (serdes_num, serdes_type, ref_clock));
+                       CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SGMII_ELECTRICAL_CONFIG_SEQ));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SGMII_TX_CONFIG_SEQ1));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, SGMII_TX_CONFIG_SEQ2));
+
+                       /* GBE configuration */
+                       reg_data = reg_read(GBE_CONFIGURATION_REG);
+                       /* write the SGMII index */
+                       reg_data |= 0x1 << (serdes_type - SGMII0);
+                       reg_write(GBE_CONFIGURATION_REG, reg_data);
+
+                       break;
+               case QSGMII:
+                       if (hws_ctrl_serdes_rev_get() < MV_SERDES_REV_2_1)
+                               return MV_NOT_SUPPORTED;
+
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, QSGMII_POWER_UP_SEQ));
+                       CHECK_STATUS(hws_ref_clock_set
+                                    (serdes_num, serdes_type, ref_clock));
+                       CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num,
+                                     QSGMII_ELECTRICAL_CONFIG_SEQ));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, QSGMII_TX_CONFIG_SEQ1));
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num, QSGMII_TX_CONFIG_SEQ2));
+                       break;
+               case SGMII3:
+               case XAUI:
+               case RXAUI:
+                       CHECK_STATUS(serdes_power_up_ctrl_ext
+                                    (serdes_num, serdes_power_up, serdes_type,
+                                     baud_rate, serdes_mode, ref_clock));
+                       break;
+               default:
+                       DEBUG_INIT_S
+                           ("serdes_power_up_ctrl: bad serdes_type parameter\n");
+                       return MV_BAD_PARAM;
+               }
+       } else {                /* Serdes power down */
+               DEBUG_INIT_FULL_S("serdes_power_up: executing power down.. ");
+               DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 1);
+
+               CHECK_STATUS(mv_seq_exec(serdes_num, SERDES_POWER_DOWN_SEQ));
+       }
+
+       DEBUG_INIT_FULL_C(
+               "serdes_power_up_ctrl ended successfully for serdes ",
+               serdes_num, 2);
+
+       return MV_OK;
+}
+
+int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map)
+{
+       u32 lane_data, idx, serdes_lane_hw_num, reg_data = 0;
+       enum serdes_type serdes_type;
+       enum serdes_mode serdes_mode;
+       u8 select_bit_off;
+       int is_pex_x4 = 0;
+       int updated_topology_print = 0;
+
+       DEBUG_INIT_FULL_S("\n### hws_update_serdes_phy_selectors ###\n");
+       DEBUG_INIT_FULL_S
+           ("Updating the COMMON PHYS SELECTORS register with the serdes types\n");
+
+       if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2)
+               select_bit_off = 3;
+       else
+               select_bit_off = 4;
+
+       /*
+        * Updating bits 0-17 in the COMMON PHYS SELECTORS register
+        * according to the serdes types
+        */
+       for (idx = 0; idx < hws_serdes_get_max_lane();
+            idx++) {
+               serdes_type = serdes_config_map[idx].serdes_type;
+               serdes_mode = serdes_config_map[idx].serdes_mode;
+               serdes_lane_hw_num = hws_get_physical_serdes_num(idx);
+
+               lane_data =
+                   hws_serdes_get_phy_selector_val(serdes_lane_hw_num,
+                                                   serdes_type);
+
+               if (serdes_type == DEFAULT_SERDES)
+                       continue;
+
+               if (hws_serdes_topology_verify
+                   (serdes_type, idx, serdes_mode) != MV_OK) {
+                       serdes_config_map[idx].serdes_type =
+                           DEFAULT_SERDES;
+                       printf("%s: SerDes lane #%d is  disabled\n", __func__,
+                              serdes_lane_hw_num);
+                       updated_topology_print = 1;
+                       continue;
+               }
+
+               /*
+                * Checking if the board topology configuration includes
+                * PEXx4 - for the next step
+                */
+               if ((serdes_mode == PEX_END_POINT_X4) ||
+                   (serdes_mode == PEX_ROOT_COMPLEX_X4)) {
+                       /* update lane data to the 3 next SERDES lanes */
+                       lane_data =
+                           common_phys_selectors_pex_by4_lanes
+                           [serdes_lane_hw_num];
+                       if (serdes_type == PEX0)
+                               is_pex_x4 = 1;
+               }
+
+               if (lane_data == NA) {
+                       printf
+                           ("%s: Warning: SerDes lane #%d and type %d are not supported together\n",
+                            __func__, serdes_lane_hw_num, serdes_mode);
+                       serdes_config_map[idx].serdes_type =
+                               DEFAULT_SERDES;
+                       printf("%s: SerDes lane #%d is  disabled\n", __func__,
+                              serdes_lane_hw_num);
+                       continue;
+               }
+
+               /*
+                * Updating the data that will be written to
+                * COMMON_PHYS_SELECTORS_REG
+                */
+               reg_data |= (lane_data <<
+                            (select_bit_off * serdes_lane_hw_num));
+       }
+
+       /*
+        * Check that number of used lanes for XAUI and RXAUI
+        * (if used) is right
+        */
+       hws_serdes_xaui_topology_verify();
+
+       /* Print topology */
+       if (updated_topology_print)
+               print_topology_details(serdes_config_map);
+
+       /*
+        * Updating the PEXx4 Enable bit in the COMMON PHYS SELECTORS
+        * register for PEXx4 mode
+        */
+       reg_data |= (is_pex_x4 == 1) ? (0x1 << PEX_X4_ENABLE_OFFS) : 0;
+
+       /* Updating the COMMON PHYS SELECTORS register */
+       reg_write(COMMON_PHYS_SELECTORS_REG, reg_data);
+
+       return MV_OK;
+}
+
+int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type,
+                     enum ref_clock ref_clock)
+{
+       u32 data1 = 0, data2 = 0, data3 = 0, reg_data;
+
+       DEBUG_INIT_FULL_S("\n### hws_ref_clock_set ###\n");
+
+       if (hws_is_serdes_active(serdes_num) != 1) {
+               printf("%s: SerDes lane #%d is not Active\n", __func__,
+                      serdes_num);
+               return MV_BAD_PARAM;
+       }
+
+       switch (serdes_type) {
+       case PEX0:
+       case PEX1:
+       case PEX2:
+       case PEX3:
+               switch (ref_clock) {
+               case REF_CLOCK_25MHZ:
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num,
+                                     PEX_CONFIG_REF_CLOCK_25MHZ_SEQ));
+                       return MV_OK;
+               case REF_CLOCK_100MHZ:
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num,
+                                     PEX_CONFIG_REF_CLOCK_100MHZ_SEQ));
+                       return MV_OK;
+#ifdef CONFIG_ARMADA_39X
+               case REF_CLOCK_40MHZ:
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_num,
+                                     PEX_CONFIG_REF_CLOCK_40MHZ_SEQ));
+                       return MV_OK;
+#endif
+               default:
+                       printf
+                           ("%s: Error: ref_clock %d for SerDes lane #%d, type %d is not supported\n",
+                            __func__, ref_clock, serdes_num, serdes_type);
+                       return MV_BAD_PARAM;
+               }
+       case USB3_HOST0:
+       case USB3_HOST1:
+       case USB3_DEVICE:
+               if (ref_clock == REF_CLOCK_25MHZ) {
+                       data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2;
+                       data2 = GLOBAL_PM_CTRL_REG_25MHZ_VAL;
+                       data3 = LANE_CFG4_REG_25MHZ_VAL;
+               } else if (ref_clock == REF_CLOCK_40MHZ) {
+                       data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+                       data2 = GLOBAL_PM_CTRL_REG_40MHZ_VAL;
+                       data3 = LANE_CFG4_REG_40MHZ_VAL;
+               } else {
+                       printf
+                           ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+                            serdes_type);
+                       return MV_BAD_PARAM;
+               }
+               break;
+       case SATA0:
+       case SATA1:
+       case SATA2:
+       case SATA3:
+       case SGMII0:
+       case SGMII1:
+       case SGMII2:
+       case QSGMII:
+               if (ref_clock == REF_CLOCK_25MHZ) {
+                       data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1;
+               } else if (ref_clock == REF_CLOCK_40MHZ) {
+                       data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+               } else {
+                       printf
+                           ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+                            serdes_type);
+                       return MV_BAD_PARAM;
+               }
+               break;
+#ifdef CONFIG_ARMADA_39X
+       case SGMII3:
+       case XAUI:
+       case RXAUI:
+               if (ref_clock == REF_CLOCK_25MHZ) {
+                       data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1;
+               } else if (ref_clock == REF_CLOCK_40MHZ) {
+                       data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL;
+               } else {
+                       printf
+                           ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n",
+                            serdes_type);
+                       return MV_BAD_PARAM;
+               }
+               break;
+#endif
+       default:
+               DEBUG_INIT_S("hws_ref_clock_set: not supported serdes type\n");
+               return MV_BAD_PARAM;
+       }
+
+       /*
+        * Write the ref_clock to relevant SELECT_REF_CLOCK_REG bits and
+        * offset
+        */
+       reg_data = reg_read(POWER_AND_PLL_CTRL_REG +
+                           SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+       reg_data &= POWER_AND_PLL_CTRL_REG_MASK;
+       reg_data |= data1;
+       reg_write(POWER_AND_PLL_CTRL_REG +
+                 SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+
+       if ((serdes_type == USB3_HOST0) || (serdes_type == USB3_HOST1) ||
+           (serdes_type == USB3_DEVICE)) {
+               reg_data = reg_read(GLOBAL_PM_CTRL +
+                                   SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+               reg_data &= GLOBAL_PM_CTRL_REG_MASK;
+               reg_data |= data2;
+               reg_write(GLOBAL_PM_CTRL +
+                         SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+
+               reg_data = reg_read(LANE_CFG4_REG +
+                                   SERDES_REGS_LANE_BASE_OFFSET(serdes_num));
+               reg_data &= LANE_CFG4_REG_MASK;
+               reg_data |= data3;
+               reg_write(LANE_CFG4_REG +
+                         SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data);
+       }
+
+       return MV_OK;
+}
+
+/*
+ * hws_pex_tx_config_seq -
+ *
+ * DESCRIPTION:          Set PEX_TX_CONFIG_SEQ sequence init for PEXx4 mode
+ * INPUT:                serdes_map       - The board topology map
+ * OUTPUT:               None
+ * RETURNS:              MV_OK           - for success
+ *                       MV_BAD_PARAM    - for fail
+ */
+int hws_pex_tx_config_seq(struct serdes_map *serdes_map)
+{
+       enum serdes_mode serdes_mode;
+       u32 serdes_lane_id, serdes_lane_hw_num;
+
+       DEBUG_INIT_FULL_S("\n### hws_pex_tx_config_seq ###\n");
+
+       /*
+        * For PEXx4: the pex_and_usb3_tx_config_params1/2/3
+        * configurations should run by setting each sequence for
+        * all 4 lanes.
+        */
+
+       /* relese pipe soft reset for all lanes */
+       for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+            serdes_lane_id++) {
+               serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+               serdes_lane_hw_num =
+                   hws_get_physical_serdes_num(serdes_lane_id);
+
+               if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+                   (serdes_mode == PEX_END_POINT_X4)) {
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ1));
+               }
+       }
+
+       /* set phy soft reset for all lanes */
+       for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+            serdes_lane_id++) {
+               serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+               serdes_lane_hw_num =
+                   hws_get_physical_serdes_num(serdes_lane_id);
+               if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+                   (serdes_mode == PEX_END_POINT_X4)) {
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ2));
+               }
+       }
+
+       /* set phy soft reset for all lanes */
+       for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
+            serdes_lane_id++) {
+               serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
+               serdes_lane_hw_num =
+                   hws_get_physical_serdes_num(serdes_lane_id);
+               if ((serdes_mode == PEX_ROOT_COMPLEX_X4) ||
+                   (serdes_mode == PEX_END_POINT_X4)) {
+                       CHECK_STATUS(mv_seq_exec
+                                    (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ3));
+               }
+       }
+
+       return MV_OK;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h
new file mode 100644 (file)
index 0000000..2508721
--- /dev/null
@@ -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 (file)
index 0000000..5f2c3eb
--- /dev/null
@@ -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@2, update
+                * topology and mark it as custom
+                */
+               if (serdes_map_array[2].serdes_type !=
+                   db_satr_config_lane2[lane_select].serdes_type) {
+                       serdes_map_array[2] = db_satr_config_lane2[lane_select];
+                       is_custom_topology = 1;
+                       /* DB 381/2 board has inverted SerDes polarity */
+                       if (board_id == DB_BP_6821_ID)
+                               serdes_map_array[2].swap_rx =
+                                       serdes_map_array[2].swap_tx = 1;
+               }
+
+               if (is_custom_topology == 1) {
+                       /*
+                        * Check for conflicts with detected lane #1 and
+                        * lane #2 (Disable conflicted lanes)
+                        */
+                       for (i = 0; i < hws_serdes_get_max_lane(); i++) {
+                               if (i != 1 && serdes_map_array[1].serdes_type ==
+                                   serdes_map_array[i].serdes_type) {
+                                       printf("\t_lane #%d Type conflicts with Lane #1 (Lane #%d disabled)\n",
+                                              i, i);
+                                       serdes_map_array[i] =
+                                               db_satr_config_lane1[0];
+                               }
+
+                               if (i != 2 &&
+                                   serdes_map_array[2].serdes_type ==
+                                   serdes_map_array[i].serdes_type) {
+                                       printf("\t_lane #%d Type conflicts with Lane #2 (Lane #%d disabled)\n",
+                                              i, i);
+                                       serdes_map_array[i] =
+                                               db_satr_config_lane1[0];
+                               }
+                       }
+               }
+
+               break;          /* case DB_68XX_ID */
+       case DB_GP_68XX_ID:     /* read 'gpserdes1' & 'gpserdes2' */
+               if (i2c_read(EEPROM_I2C_ADDR, 2, 2, &config_val, 1)) {
+                       printf("%s: TWSI Read of 'gpserdes1/2' failed\n",
+                              __func__);
+                       return MV_FAIL;
+               }
+
+               /*
+                * Lane #1:
+                * lane_select = 0 --> SATA0,
+                * lane_select = 1 --> PCIe0 (mini PCIe)
+                */
+               lane_select = (config_val & SATR_GP_LANE1_CFG_MASK) >>
+                       SATR_GP_LANE1_CFG_OFFSET;
+               if (lane_select == 1) {
+                       serdes_map_array[1].serdes_mode = PEX0;
+                       serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS;
+                       serdes_map_array[1].serdes_type = PEX_ROOT_COMPLEX_X1;
+                       /*
+                        * If lane 1 is set to PCIe0 --> disable PCIe0
+                        * on lane 0
+                        */
+                       serdes_map_array[0] = default_lane;
+                       /* indicate user of non-default topology */
+                       is_custom_topology = 1;
+               }
+               printf("Lane 1 detection: %s\n",
+                      lane_select ? "PCIe0 (mini PCIe)" : "SATA0");
+
+               /*
+                * Lane #2:
+                * lane_select = 0 --> SATA1,
+                * lane_select = 1 --> PCIe1 (mini PCIe)
+                */
+               lane_select = (config_val & SATR_GP_LANE2_CFG_MASK) >>
+                       SATR_GP_LANE2_CFG_OFFSET;
+               if (lane_select == 1) {
+                       serdes_map_array[2].serdes_type = PEX1;
+                       serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS;
+                       serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1;
+                       /* indicate user of non-default topology */
+                       is_custom_topology = 1;
+               }
+               printf("Lane 2 detection: %s\n",
+                      lane_select ? "PCIe1 (mini PCIe)" : "SATA1");
+               break;          /* case DB_GP_68XX_ID */
+       }
+
+       if (is_custom_topology)
+               printf("\nDetected custom SerDes topology (to restore default run 'SatR write default')\n\n");
+
+       return MV_OK;
+}
+
+/*
+ * hws_update_device_toplogy
+ * DESCRIPTION: Update the default board topology for specific device Id
+ * INPUT:
+ *     topology_config_ptr - pointer to the Serdes mapping
+ *     topology_mode - topology mode (index)
+ * OUTPUT: None
+ * RRETURNS:
+ *     MV_OK - if updating the board topology success
+ *     MV_BAD_PARAM - if the input parameter is wrong
+ */
+int hws_update_device_toplogy(struct serdes_map *topology_config_ptr,
+                             enum topology_config_db topology_mode)
+{
+       u32 dev_id = sys_env_device_id_get();
+       u32 board_id = mv_board_id_get();
+
+       switch (topology_mode) {
+       case DB_CONFIG_DEFAULT:
+               switch (dev_id) {
+               case MV_6810:
+                       /*
+                        * DB-AP : default for Lane3=SGMII2 -->
+                        * 6810 supports only 2 SGMII interfaces:
+                        * lane 3 disabled
+                        */
+                       if (board_id == DB_AP_68XX_ID) {
+                               printf("Device 6810 supports only 2 SGMII interfaces: SGMII-2 @ lane3 disabled\n");
+                               topology_config_ptr[3] = default_lane;
+                       }
+
+                       /*
+                        * 6810 has only 4 SerDes and the forth one is
+                        * Serdes number 5 (i.e. Serdes 4 is not connected),
+                        * therefore we need to copy SerDes 5 configuration
+                        * to SerDes 4
+                        */
+                       printf("Device 6810 does not supports SerDes Lane #4: replaced topology entry with lane #5\n");
+                       topology_config_ptr[4] = topology_config_ptr[5];
+
+                       /*
+                        * No break between cases since the 1st
+                        * 6820 limitation apply on 6810
+                        */
+               case MV_6820:
+                       /*
+                        * DB-GP & DB-BP: default for Lane3=SATA3 -->
+                        * 6810/20 supports only 2 SATA interfaces:
+                        * lane 3 disabled
+                        */
+                       if ((board_id == DB_68XX_ID) ||
+                           (board_id == DB_GP_68XX_ID)) {
+                               printf("Device 6810/20 supports only 2 SATA interfaces: SATA Port 3 @ lane3 disabled\n");
+                               topology_config_ptr[3] = default_lane;
+                       }
+                       /*
+                        * DB-GP on 6820 only: default for Lane4=SATA2
+                        * --> 6820 supports only 2 SATA interfaces:
+                        * lane 3 disabled
+                        */
+                       if (board_id == DB_GP_68XX_ID && dev_id == MV_6820) {
+                               printf("Device 6820 supports only 2 SATA interfaces: SATA Port 2 @ lane4 disabled\n");
+                               topology_config_ptr[4] = default_lane;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               printf("sys_env_update_device_toplogy: selected topology is not supported by this routine\n");
+               break;
+       }
+
+       return MV_OK;
+}
+
+int load_topology_db_381(struct serdes_map *serdes_map_array)
+{
+       u32 lane_num;
+       u8 topology_mode;
+       struct serdes_map *topology_config_ptr;
+       u8 twsi_data;
+       u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0;
+
+       printf("\nInitialize DB-88F6821-BP board topology\n");
+
+       /* Getting the relevant topology mode (index) */
+       topology_mode = topology_config_db_381_mode_get();
+       topology_config_ptr = topology_config_db_381[topology_mode];
+
+       /* Read USB3.0 mode: HOST/DEVICE */
+       if (load_topology_usb_mode_get(&twsi_data) == MV_OK) {
+               usb3_host0_or_device = (twsi_data & 0x1);
+               /* Only one USB3 device is enabled */
+               if (usb3_host0_or_device == 0)
+                       usb3_host1_or_device = ((twsi_data >> 1) & 0x1);
+       }
+
+       /* Updating the topology map */
+       for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+               serdes_map_array[lane_num].serdes_mode =
+                       topology_config_ptr[lane_num].serdes_mode;
+               serdes_map_array[lane_num].serdes_speed =
+                       topology_config_ptr[lane_num].serdes_speed;
+               serdes_map_array[lane_num].serdes_type =
+                       topology_config_ptr[lane_num].serdes_type;
+               serdes_map_array[lane_num].swap_rx =
+                       topology_config_ptr[lane_num].swap_rx;
+               serdes_map_array[lane_num].swap_tx =
+                       topology_config_ptr[lane_num].swap_tx;
+
+               /* Update USB3 device if needed */
+               if (usb3_host0_or_device == 1 &&
+                   serdes_map_array[lane_num].serdes_type == USB3_HOST0)
+                       serdes_map_array[lane_num].serdes_type = USB3_DEVICE;
+
+               if (usb3_host1_or_device == 1 &&
+                   serdes_map_array[lane_num].serdes_type == USB3_HOST1)
+                       serdes_map_array[lane_num].serdes_type = USB3_DEVICE;
+       }
+
+       /* If not detected any SerDes Site module, read 'SatR' lane setup */
+       if (topology_mode == DB_381_CONFIG_DEFAULT)
+               update_topology_satr(serdes_map_array);
+
+       /* update 'sgmiispeed' settings */
+       update_topology_sgmii_speed(serdes_map_array);
+
+       return MV_OK;
+}
+
+int load_topology_db(struct serdes_map *serdes_map_array)
+{
+       u32 lane_num;
+       u8 topology_mode;
+       struct serdes_map *topology_config_ptr;
+       u8 twsi_data;
+       u8 usb3_host0_or_device = 0, usb3_host1_or_device = 0;
+
+       printf("\nInitialize DB-88F6820-BP board topology\n");
+
+       /* Getting the relevant topology mode (index) */
+       topology_mode = topology_config_db_mode_get();
+
+       if (topology_mode == DB_NO_TOPOLOGY)
+               topology_mode = DB_CONFIG_DEFAULT;
+
+       topology_config_ptr = topology_config_db[topology_mode];
+
+       /* Update the default board topology device flavours */
+       CHECK_STATUS(hws_update_device_toplogy
+                    (topology_config_ptr, topology_mode));
+
+       /* Read USB3.0 mode: HOST/DEVICE */
+       if (load_topology_usb_mode_get(&twsi_data) == MV_OK) {
+               usb3_host0_or_device = (twsi_data & 0x1);
+               /* Only one USB3 device is enabled */
+               if (usb3_host0_or_device == 0)
+                       usb3_host1_or_device = ((twsi_data >> 1) & 0x1);
+       }
+
+       /* Updating the topology map */
+       for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+               serdes_map_array[lane_num].serdes_mode =
+                       topology_config_ptr[lane_num].serdes_mode;
+               serdes_map_array[lane_num].serdes_speed =
+                       topology_config_ptr[lane_num].serdes_speed;
+               serdes_map_array[lane_num].serdes_type =
+                       topology_config_ptr[lane_num].serdes_type;
+               serdes_map_array[lane_num].swap_rx =
+                       topology_config_ptr[lane_num].swap_rx;
+               serdes_map_array[lane_num].swap_tx =
+                       topology_config_ptr[lane_num].swap_tx;
+
+               /*
+                * Update USB3 device if needed - relevant for
+                * lane 3,4,5 only
+                */
+               if (lane_num >= 3) {
+                       if ((serdes_map_array[lane_num].serdes_type ==
+                            USB3_HOST0) && (usb3_host0_or_device == 1))
+                               serdes_map_array[lane_num].serdes_type =
+                                       USB3_DEVICE;
+
+                       if ((serdes_map_array[lane_num].serdes_type ==
+                            USB3_HOST1) && (usb3_host1_or_device == 1))
+                               serdes_map_array[lane_num].serdes_type =
+                                       USB3_DEVICE;
+               }
+       }
+
+       /* If not detected any SerDes Site module, read 'SatR' lane setup */
+       if (topology_mode == DB_CONFIG_DEFAULT)
+               update_topology_satr(serdes_map_array);
+
+       /* update 'sgmiispeed' settings */
+       update_topology_sgmii_speed(serdes_map_array);
+
+       return MV_OK;
+}
+
+int load_topology_db_ap(struct serdes_map *serdes_map_array)
+{
+       u32 lane_num;
+       struct serdes_map *topology_config_ptr;
+
+       DEBUG_INIT_FULL_S("\n### load_topology_db_ap ###\n");
+
+       printf("\nInitialize DB-AP board topology\n");
+       topology_config_ptr = db_ap_config_default;
+
+       /* Update the default board topology device flavours */
+       CHECK_STATUS(hws_update_device_toplogy
+                    (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+       /* Updating the topology map */
+       for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+               serdes_map_array[lane_num].serdes_mode =
+                       topology_config_ptr[lane_num].serdes_mode;
+               serdes_map_array[lane_num].serdes_speed =
+                       topology_config_ptr[lane_num].serdes_speed;
+               serdes_map_array[lane_num].serdes_type =
+                       topology_config_ptr[lane_num].serdes_type;
+               serdes_map_array[lane_num].swap_rx =
+                       topology_config_ptr[lane_num].swap_rx;
+               serdes_map_array[lane_num].swap_tx =
+                       topology_config_ptr[lane_num].swap_tx;
+       }
+
+       update_topology_sgmii_speed(serdes_map_array);
+
+       return MV_OK;
+}
+
+int load_topology_db_gp(struct serdes_map *serdes_map_array)
+{
+       u32 lane_num;
+       struct serdes_map *topology_config_ptr;
+       int is_sgmii = 0;
+
+       DEBUG_INIT_FULL_S("\n### load_topology_db_gp ###\n");
+
+       topology_config_ptr = db_gp_config_default;
+
+       printf("\nInitialize DB-GP board topology\n");
+
+       /* check S@R: if lane 5 is USB3 or SGMII */
+       if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK)
+               printf("%s: TWSI Read failed - Loading Default Topology\n",
+                      __func__);
+       else {
+               topology_config_ptr[5].serdes_type =
+                       is_sgmii ? SGMII2 : USB3_HOST1;
+               topology_config_ptr[5].serdes_speed = is_sgmii ?
+                       SERDES_SPEED_3_125_GBPS : SERDES_SPEED_5_GBPS;
+               topology_config_ptr[5].serdes_mode = SERDES_DEFAULT_MODE;
+       }
+
+       /* Update the default board topology device flavours */
+       CHECK_STATUS(hws_update_device_toplogy
+                    (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+       /* Updating the topology map */
+       for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+               serdes_map_array[lane_num].serdes_mode =
+                       topology_config_ptr[lane_num].serdes_mode;
+               serdes_map_array[lane_num].serdes_speed =
+                       topology_config_ptr[lane_num].serdes_speed;
+               serdes_map_array[lane_num].serdes_type =
+                       topology_config_ptr[lane_num].serdes_type;
+               serdes_map_array[lane_num].swap_rx =
+                       topology_config_ptr[lane_num].swap_rx;
+               serdes_map_array[lane_num].swap_tx =
+                       topology_config_ptr[lane_num].swap_tx;
+       }
+
+       /*
+        * Update 'gpserdes1/2/3' lane configuration , and 'sgmiispeed'
+        * for SGMII lanes
+        */
+       update_topology_satr(serdes_map_array);
+       update_topology_sgmii_speed(serdes_map_array);
+
+       return MV_OK;
+}
+
+int load_topology_db_amc(struct serdes_map *serdes_map_array)
+{
+       u32 lane_num;
+       struct serdes_map *topology_config_ptr;
+
+       DEBUG_INIT_FULL_S("\n### load_topology_db_amc ###\n");
+
+       printf("\nInitialize DB-AMC board topology\n");
+       topology_config_ptr = db_amc_config_default;
+
+       /* Update the default board topology device flavours */
+       CHECK_STATUS(hws_update_device_toplogy
+                    (topology_config_ptr, DB_CONFIG_DEFAULT));
+
+       /* Updating the topology map */
+       for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
+               serdes_map_array[lane_num].serdes_mode =
+                       topology_config_ptr[lane_num].serdes_mode;
+               serdes_map_array[lane_num].serdes_speed =
+                       topology_config_ptr[lane_num].serdes_speed;
+               serdes_map_array[lane_num].serdes_type =
+                       topology_config_ptr[lane_num].serdes_type;
+               serdes_map_array[lane_num].swap_rx =
+                       topology_config_ptr[lane_num].swap_rx;
+               serdes_map_array[lane_num].swap_tx =
+                       topology_config_ptr[lane_num].swap_tx;
+       }
+
+       update_topology_sgmii_speed(serdes_map_array);
+
+       return MV_OK;
+}
+
+int load_topology_rd(struct serdes_map *serdes_map_array)
+{
+       u8 mode;
+
+       DEBUG_INIT_FULL_S("\n### load_topology_rd ###\n");
+
+       DEBUG_INIT_S("\nInit RD board ");
+
+       /* Reading mode */
+       DEBUG_INIT_FULL_S("load_topology_rd: getting mode\n");
+       if (i2c_read(EEPROM_I2C_ADDR, 0, 2, &mode, 1)) {
+               DEBUG_INIT_S("load_topology_rd: TWSI Read failed\n");
+               return MV_FAIL;
+       }
+
+       /* Updating the topology map */
+       DEBUG_INIT_FULL_S("load_topology_rd: Loading board topology details\n");
+
+       /* RD mode: 0 = NAS, 1 = AP */
+       if (((mode >> 1) & 0x1) == 0) {
+               CHECK_STATUS(load_topology_rd_nas(serdes_map_array));
+       } else {
+               CHECK_STATUS(load_topology_rd_ap(serdes_map_array));
+       }
+
+       update_topology_sgmii_speed(serdes_map_array);
+
+       return MV_OK;
+}
+
+int load_topology_rd_nas(struct serdes_map *serdes_map_array)
+{
+       int is_sgmii = 0;
+       u32 i;
+
+       DEBUG_INIT_S("\nInit RD NAS topology ");
+
+       /* check if lane 4 is USB3 or SGMII */
+       if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) {
+               DEBUG_INIT_S("load_topology_rd NAS: TWSI Read failed\n");
+               return MV_FAIL;
+       }
+
+       /* Lane 0 */
+       serdes_map_array[0].serdes_type = PEX0;
+       serdes_map_array[0].serdes_speed = SERDES_SPEED_5_GBPS;
+       serdes_map_array[0].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+       /* Lane 1 */
+       serdes_map_array[1].serdes_type = SATA0;
+       serdes_map_array[1].serdes_speed = SERDES_SPEED_3_GBPS;
+       serdes_map_array[1].serdes_mode = SERDES_DEFAULT_MODE;
+
+       /* Lane 2 */
+       serdes_map_array[2].serdes_type = SATA1;
+       serdes_map_array[2].serdes_speed = SERDES_SPEED_3_GBPS;
+       serdes_map_array[2].serdes_mode = SERDES_DEFAULT_MODE;
+
+       /* Lane 3 */
+       serdes_map_array[3].serdes_type = SATA3;
+       serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS;
+       serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE;
+
+       /* Lane 4 */
+       if (is_sgmii == 1) {
+               DEBUG_INIT_S("Serdes Lane 4 is SGMII\n");
+               serdes_map_array[4].serdes_type = SGMII1;
+               serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS;
+               serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+       } else {
+               DEBUG_INIT_S("Serdes Lane 4 is USB3\n");
+               serdes_map_array[4].serdes_type = USB3_HOST0;
+               serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS;
+               serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+       }
+
+       /* Lane 5 */
+       serdes_map_array[5].serdes_type = SATA2;
+       serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS;
+       serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE;
+
+       /* init swap configuration */
+       for (i = 0; i <= 5; i++) {
+               serdes_map_array[i].swap_rx = 0;
+               serdes_map_array[i].swap_tx = 0;
+       }
+
+       return MV_OK;
+}
+
+int load_topology_rd_ap(struct serdes_map *serdes_map_array)
+{
+       int is_sgmii = 0;
+       u32 i;
+
+       DEBUG_INIT_S("\nInit RD AP topology ");
+
+       /* check if lane 4 is USB3 or SGMII */
+       if (load_topology_rd_sgmii_usb(&is_sgmii) != MV_OK) {
+               DEBUG_INIT_S("load_topology_rd AP: TWSI Read failed\n");
+               return MV_FAIL;
+       }
+
+       /* Lane 0 */
+       serdes_map_array[0].serdes_type = DEFAULT_SERDES;
+       serdes_map_array[0].serdes_speed = LAST_SERDES_SPEED;
+       serdes_map_array[0].serdes_mode = SERDES_DEFAULT_MODE;
+
+       /* Lane 1 */
+       serdes_map_array[1].serdes_type = PEX0;
+       serdes_map_array[1].serdes_speed = SERDES_SPEED_5_GBPS;
+       serdes_map_array[1].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+       /* Lane 2 */
+       serdes_map_array[2].serdes_type = PEX1;
+       serdes_map_array[2].serdes_speed = SERDES_SPEED_5_GBPS;
+       serdes_map_array[2].serdes_mode = PEX_ROOT_COMPLEX_X1;
+
+       /* Lane 3 */
+       serdes_map_array[3].serdes_type = SATA3;
+       serdes_map_array[3].serdes_speed = SERDES_SPEED_3_GBPS;
+       serdes_map_array[3].serdes_mode = SERDES_DEFAULT_MODE;
+
+       /* Lane 4 */
+       if (is_sgmii == 1) {
+               DEBUG_INIT_S("Serdes Lane 4 is SGMII\n");
+               serdes_map_array[4].serdes_type = SGMII1;
+               serdes_map_array[4].serdes_speed = SERDES_SPEED_3_125_GBPS;
+               serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+       } else {
+               DEBUG_INIT_S("Serdes Lane 4 is USB3\n");
+               serdes_map_array[4].serdes_type = USB3_HOST0;
+               serdes_map_array[4].serdes_speed = SERDES_SPEED_5_GBPS;
+               serdes_map_array[4].serdes_mode = SERDES_DEFAULT_MODE;
+       }
+
+       /* Lane 5 */
+       serdes_map_array[5].serdes_type = SATA2;
+       serdes_map_array[5].serdes_speed = SERDES_SPEED_3_GBPS;
+       serdes_map_array[5].serdes_mode = SERDES_DEFAULT_MODE;
+
+       /* init swap configuration */
+       for (i = 0; i <= 5; i++) {
+               serdes_map_array[i].swap_rx = 0;
+               serdes_map_array[i].swap_tx = 0;
+       }
+
+       return MV_OK;
+}
+
+int load_topology_rd_sgmii_usb(int *is_sgmii)
+{
+       u8 mode;
+
+       /*
+        * DB-GP board: Device 6810 supports only 2 GbE ports:
+        * SGMII2 not supported (USE USB3 Host instead)
+        */
+       if (sys_env_device_id_get() == MV_6810) {
+               printf("Device 6810 supports only 2 GbE ports: SGMII-2 @ lane5 disabled (setting USB3.0 H1 instead)\n");
+               *is_sgmii = 0;
+               return MV_OK;
+       }
+
+       if (!i2c_read(RD_GET_MODE_ADDR, 1, 2, &mode, 1)) {
+               *is_sgmii = ((mode >> 2) & 0x1);
+       } else {
+               /* else use the default - USB3 */
+               *is_sgmii = 0;
+       }
+
+       if (*is_sgmii)
+               is_custom_topology = 1;
+
+       printf("Lane 5 detection: %s\n",
+              *is_sgmii ? "SGMII2" : "USB3.0 Host Port 1");
+
+       return MV_OK;
+}
+
+/*
+ * 'usb3port0'/'usb3port1' fields are located in EEPROM,
+ * at 3rd byte(offset=2), bit 0:1 (respectively)
+ */
+int load_topology_usb_mode_get(u8 *twsi_data)
+{
+       if (!i2c_read(EEPROM_I2C_ADDR, 2, 2, twsi_data, 1))
+               return MV_OK;
+
+       return MV_ERROR;
+}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h b/arch/arm/mach-mvebu/serdes/a38x/high_speed_topology_spec.h
new file mode 100644 (file)
index 0000000..3cfb1c7
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef _HIGHSPEED_TOPOLOGY_SPEC_H
+#define _HIGHSPEED_TOPOLOGY_SPEC_H
+
+#include "high_speed_env_spec.h"
+
+/* Topology map options for the DB_A38X_BP board */
+enum topology_config_db {
+       DB_CONFIG_SLM1363_C,
+       DB_CONFIG_SLM1363_D,
+       DB_CONFIG_SLM1363_E,
+       DB_CONFIG_SLM1363_F,
+       DB_CONFIG_SLM1364_D,
+       DB_CONFIG_SLM1364_E,
+       DB_CONFIG_SLM1364_F,
+       DB_CONFIG_DEFAULT,
+       DB_NO_TOPOLOGY
+};
+
+/*
+ * this enum must be aligned with topology_config_db_381 array,
+ * every update to this enum requires update to topology_config_db_381
+ * array
+ */
+enum topology_config_db381 {
+       DB_CONFIG_SLM1427,      /* enum for db_config_slm1427 */
+       DB_CONFIG_SLM1426,      /* enum for db_config_slm1426 */
+       DB_381_CONFIG_DEFAULT,
+       DB_381_NO_TOPOLOGY
+};
+
+/* A generic function pointer for loading the board topology map */
+typedef int (*load_topology_func_ptr)(struct serdes_map *serdes_map_array);
+
+extern load_topology_func_ptr load_topology_func_arr[];
+
+/*
+ * topology_config_db_mode_get -
+ *
+ * DESCRIPTION:                Gets the relevant topology mode (index).
+ *                     for load_topology_db use only.
+ * INPUT:              None.
+ * OUTPUT:             None.
+ * RETURNS:            the topology mode
+ */
+u8 topology_config_db_mode_get(void);
+
+/*
+ * load_topology_xxx -
+ *
+ * DESCRIPTION:                Loads the board topology for the XXX board
+ * INPUT:              serdes_map_array - The struct that will contain
+ *                     the board topology map
+ * OUTPUT:             The board topology map.
+ * RETURNS:            MV_OK   for success
+ *                     MV_FAIL for failure (a wrong topology mode was read
+ *                     from the board)
+ */
+
+/* load_topology_db - Loads the board topology for DB Board */
+int load_topology_db(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd - Loads the board topology for RD Board */
+int load_topology_rd(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd_nas - Loads the board topology for RD NAS Board */
+int load_topology_rd_nas(struct serdes_map *serdes_map_array);
+
+/* load_topology_rd_ap - Loads the board topology for RD Ap Board */
+int load_topology_rd_ap(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_ap - Loads the board topology for DB-AP Board */
+int load_topology_db_ap(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_gp - Loads the board topology for DB GP Board */
+int load_topology_db_gp(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_381 - Loads the board topology for 381 DB-BP Board */
+int load_topology_db_381(struct serdes_map *serdes_map_array);
+
+/* load_topology_db_amc - Loads the board topology for DB-AMC Board */
+int load_topology_db_amc(struct serdes_map *serdes_map_array);
+
+/*
+ * hws_update_device_toplogy
+ * DESCRIPTION: Update the default board topology for specific device Id
+ * INPUT:
+ *     topology_config_ptr - pointer to the Serdes mapping
+ *     topology_mode - topology mode (index)
+ * OUTPUT: None
+ * RRETURNS:
+ *     MV_OK - if updating the board topology success
+ *     MV_BAD_PARAM - if the input parameter is wrong
+ */
+int hws_update_device_toplogy(struct serdes_map *topology_config_ptr,
+                             enum topology_config_db topology_mode);
+
+/*
+ * load_topology_rd_sgmii_usb -
+ *
+ * DESCRIPTION:                        For RD board check if lane 4 is USB3 or SGMII
+ * INPUT:                      None
+ * OUTPUT:                     is_sgmii - return 1 if lane 4 is SGMII
+ *                             return 0 if lane 4 is USB.
+ * RETURNS:                    MV_OK for success
+ */
+int load_topology_rd_sgmii_usb(int *is_sgmii);
+
+/*
+ * load_topology_usb_mode_get -
+ *
+ * DESCRIPTION:                        For DB board check if USB3.0 mode
+ * INPUT:                      None
+ * OUTPUT:                     twsi_data - return data read from S@R via I2C
+ * RETURNS:                    MV_OK for success
+ */
+int load_topology_usb_mode_get(u8 *twsi_data);
+
+#endif /* _HIGHSPEED_TOPOLOGY_SPEC_H */
diff --git a/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c b/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
new file mode 100644 (file)
index 0000000..ee2305b
--- /dev/null
@@ -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 (file)
index 0000000..14f406a
--- /dev/null
@@ -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 (file)
index 0000000..efd3873
--- /dev/null
@@ -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 (file)
index 0000000..3e5373c
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef _SYS_ENV_LIB_H
+#define _SYS_ENV_LIB_H
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
+#include "../../../drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h"
+
+/* Serdes definitions */
+#define COMMON_PHY_BASE_ADDR           0x18300
+
+#define DEVICE_CONFIGURATION_REG0      0x18284
+#define DEVICE_CONFIGURATION_REG1      0x18288
+#define COMMON_PHY_CONFIGURATION1_REG  0x18300
+#define COMMON_PHY_CONFIGURATION2_REG  0x18304
+#define COMMON_PHY_CONFIGURATION4_REG  0x1830c
+#define COMMON_PHY_STATUS1_REG         0x18318
+#define COMMON_PHYS_SELECTORS_REG      0x183fc
+#define SOC_CONTROL_REG1               0x18204
+#define GENERAL_PURPOSE_RESERVED0_REG  0x182e0
+#define GBE_CONFIGURATION_REG          0x18460
+#define DEVICE_SAMPLE_AT_RESET1_REG    0x18600
+#define DEVICE_SAMPLE_AT_RESET2_REG    0x18604
+#define DEV_ID_REG                     0x18238
+
+#define CORE_PLL_PARAMETERS_REG                0xe42e0
+#define CORE_PLL_CONFIG_REG            0xe42e4
+
+#define QSGMII_CONTROL_REG1            0x18494
+
+#define DEV_ID_REG_DEVICE_ID_OFFS      16
+#define DEV_ID_REG_DEVICE_ID_MASK      0xffff0000
+
+#define SAR_DEV_ID_OFFS                        27
+#define SAR_DEV_ID_MASK                        0x7
+
+#define POWER_AND_PLL_CTRL_REG         0xa0004
+#define CALIBRATION_CTRL_REG           0xa0008
+#define DFE_REG0                       0xa001c
+#define DFE_REG3                       0xa0028
+#define RESET_DFE_REG                  0xa0148
+#define LOOPBACK_REG                   0xa008c
+#define SYNC_PATTERN_REG               0xa0090
+#define INTERFACE_REG                  0xa0094
+#define ISOLATE_REG                    0xa0098
+#define MISC_REG                       0xa013c
+#define GLUE_REG                       0xa0140
+#define GENERATION_DIVIDER_FORCE_REG   0xa0144
+#define PCIE_REG0                      0xa0120
+#define LANE_ALIGN_REG0                        0xa0124
+#define SQUELCH_FFE_SETTING_REG                0xa0018
+#define G1_SETTINGS_0_REG              0xa0034
+#define G1_SETTINGS_1_REG              0xa0038
+#define G1_SETTINGS_3_REG              0xa0440
+#define G1_SETTINGS_4_REG              0xa0444
+#define G2_SETTINGS_0_REG              0xa003c
+#define G2_SETTINGS_1_REG              0xa0040
+#define G2_SETTINGS_2_REG              0xa00f8
+#define G2_SETTINGS_3_REG              0xa0448
+#define G2_SETTINGS_4_REG              0xa044c
+#define G3_SETTINGS_0_REG              0xa0044
+#define G3_SETTINGS_1_REG              0xa0048
+#define G3_SETTINGS_3_REG              0xa0450
+#define G3_SETTINGS_4_REG              0xa0454
+#define VTHIMPCAL_CTRL_REG             0xa0104
+#define REF_REG0                       0xa0134
+#define CAL_REG6                       0xa0168
+#define RX_REG2                                0xa0184
+#define RX_REG3                                0xa0188
+#define PCIE_REG1                      0xa0288
+#define PCIE_REG3                      0xa0290
+#define LANE_CFG1_REG                  0xa0604
+#define LANE_CFG4_REG                  0xa0620
+#define LANE_CFG5_REG                  0xa0624
+#define GLOBAL_CLK_CTRL                        0xa0704
+#define GLOBAL_MISC_CTRL               0xa0718
+#define GLOBAL_CLK_SRC_HI              0xa0710
+
+#define GLOBAL_CLK_CTRL                        0xa0704
+#define GLOBAL_MISC_CTRL               0xa0718
+#define GLOBAL_PM_CTRL                 0xa0740
+
+/* SATA registers */
+#define SATA_CTRL_REG_IND_ADDR         0xa80a0
+#define SATA_CTRL_REG_IND_DATA         0xa80a4
+
+#define SATA_VENDOR_PORT_0_REG_ADDR    0xa8178
+#define SATA_VENDOR_PORT_1_REG_ADDR    0xa81f8
+#define SATA_VENDOR_PORT_0_REG_DATA    0xa817c
+#define SATA_VENDOR_PORT_1_REG_DATA    0xa81fc
+
+/* Reference clock values and mask */
+#define POWER_AND_PLL_CTRL_REG_100MHZ_VAL      0x0
+#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1     0x1
+#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2     0x2
+#define POWER_AND_PLL_CTRL_REG_40MHZ_VAL       0x3
+#define GLOBAL_PM_CTRL_REG_25MHZ_VAL           0x7
+#define GLOBAL_PM_CTRL_REG_40MHZ_VAL           0xc
+#define LANE_CFG4_REG_25MHZ_VAL                        0x200
+#define LANE_CFG4_REG_40MHZ_VAL                        0x300
+
+#define POWER_AND_PLL_CTRL_REG_MASK            (~(0x1f))
+#define GLOBAL_PM_CTRL_REG_MASK                        (~(0xff))
+#define LANE_CFG4_REG_MASK                     (~(0x1f00))
+
+#define REF_CLK_SELECTOR_VAL_PEX0(reg_val)     (reg_val >> 2) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX1(reg_val)     (reg_val >> 3) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX2(reg_val)     (reg_val >> 30) & 0x1
+#define REF_CLK_SELECTOR_VAL_PEX3(reg_val)     (reg_val >> 31) & 0x1
+#define REF_CLK_SELECTOR_VAL(reg_val)          (reg_val & 0x1)
+
+#define MAX_SELECTOR_VAL                       10
+
+/* TWSI addresses */
+/* starting from A38x A0, i2c address of EEPROM is 0x57 */
+#ifdef CONFIG_ARMADA_39X
+#define EEPROM_I2C_ADDR                        0x50
+#else
+#define EEPROM_I2C_ADDR                        (sys_env_device_rev_get() == \
+                                        MV_88F68XX_Z1_ID ? 0x50 : 0x57)
+#endif
+#define RD_GET_MODE_ADDR               0x4c
+#define DB_GET_MODE_SLM1363_ADDR       0x25
+#define DB_GET_MODE_SLM1364_ADDR       0x24
+#define DB381_GET_MODE_SLM1426_1427_ADDR 0x56
+
+/* DB-BP Board 'SatR' mapping */
+#define SATR_DB_LANE1_MAX_OPTIONS      7
+#define SATR_DB_LANE1_CFG_MASK         0x7
+#define SATR_DB_LANE1_CFG_OFFSET       0
+#define SATR_DB_LANE2_MAX_OPTIONS      4
+#define SATR_DB_LANE2_CFG_MASK         0x38
+#define SATR_DB_LANE2_CFG_OFFSET       3
+
+/* GP Board 'SatR' mapping */
+#define SATR_GP_LANE1_CFG_MASK         0x4
+#define SATR_GP_LANE1_CFG_OFFSET       2
+#define SATR_GP_LANE2_CFG_MASK         0x8
+#define SATR_GP_LANE2_CFG_OFFSET       3
+
+/* For setting MPP2 and MPP3 to be TWSI mode and MPP 0,1 to UART mode */
+#define MPP_CTRL_REG                   0x18000
+#define MPP_SET_MASK                   (~(0xffff))
+#define MPP_SET_DATA                   (0x1111)
+#define MPP_UART1_SET_MASK             (~(0xff000))
+#define MPP_UART1_SET_DATA             (0x66000)
+
+#define AVS_DEBUG_CNTR_REG             0xe4124
+#define AVS_DEBUG_CNTR_DEFAULT_VALUE   0x08008073
+
+#define AVS_ENABLED_CONTROL            0xe4130
+#define AVS_LOW_VDD_LIMIT_OFFS         4
+#define AVS_LOW_VDD_LIMIT_MASK         (0xff << AVS_LOW_VDD_LIMIT_OFFS)
+#define AVS_LOW_VDD_LIMIT_VAL          (0x27 << AVS_LOW_VDD_LIMIT_OFFS)
+
+#define AVS_HIGH_VDD_LIMIT_OFFS                12
+#define AVS_HIGH_VDD_LIMIT_MASK                (0xff << AVS_HIGH_VDD_LIMIT_OFFS)
+#define AVS_HIGH_VDD_LIMIT_VAL         (0x27 << AVS_HIGH_VDD_LIMIT_OFFS)
+
+/* Board ID numbers */
+#define MARVELL_BOARD_ID_MASK          0x10
+/* Customer boards for A38x */
+#define A38X_CUSTOMER_BOARD_ID_BASE    0x0
+#define A38X_CUSTOMER_BOARD_ID0                (A38X_CUSTOMER_BOARD_ID_BASE + 0)
+#define A38X_CUSTOMER_BOARD_ID1                (A38X_CUSTOMER_BOARD_ID_BASE + 1)
+#define A38X_MV_MAX_CUSTOMER_BOARD_ID  (A38X_CUSTOMER_BOARD_ID_BASE + 2)
+#define A38X_MV_CUSTOMER_BOARD_NUM     (A38X_MV_MAX_CUSTOMER_BOARD_ID - \
+                                        A38X_CUSTOMER_BOARD_ID_BASE)
+
+/* Marvell boards for A38x */
+#define A38X_MARVELL_BOARD_ID_BASE     0x10
+#define RD_NAS_68XX_ID                 (A38X_MARVELL_BOARD_ID_BASE + 0)
+#define DB_68XX_ID                     (A38X_MARVELL_BOARD_ID_BASE + 1)
+#define RD_AP_68XX_ID                  (A38X_MARVELL_BOARD_ID_BASE + 2)
+#define DB_AP_68XX_ID                  (A38X_MARVELL_BOARD_ID_BASE + 3)
+#define DB_GP_68XX_ID                  (A38X_MARVELL_BOARD_ID_BASE + 4)
+#define DB_BP_6821_ID                  (A38X_MARVELL_BOARD_ID_BASE + 5)
+#define DB_AMC_6820_ID                 (A38X_MARVELL_BOARD_ID_BASE + 6)
+#define A38X_MV_MAX_MARVELL_BOARD_ID   (A38X_MARVELL_BOARD_ID_BASE + 7)
+#define A38X_MV_MARVELL_BOARD_NUM      (A38X_MV_MAX_MARVELL_BOARD_ID - \
+                                        A38X_MARVELL_BOARD_ID_BASE)
+
+/* Customer boards for A39x */
+#define A39X_CUSTOMER_BOARD_ID_BASE    0x20
+#define A39X_CUSTOMER_BOARD_ID0                (A39X_CUSTOMER_BOARD_ID_BASE + 0)
+#define A39X_CUSTOMER_BOARD_ID1                (A39X_CUSTOMER_BOARD_ID_BASE + 1)
+#define A39X_MV_MAX_CUSTOMER_BOARD_ID  (A39X_CUSTOMER_BOARD_ID_BASE + 2)
+#define A39X_MV_CUSTOMER_BOARD_NUM     (A39X_MV_MAX_CUSTOMER_BOARD_ID - \
+                                        A39X_CUSTOMER_BOARD_ID_BASE)
+
+/* Marvell boards for A39x */
+#define A39X_MARVELL_BOARD_ID_BASE     0x30
+#define A39X_DB_69XX_ID                        (A39X_MARVELL_BOARD_ID_BASE + 0)
+#define A39X_RD_69XX_ID                        (A39X_MARVELL_BOARD_ID_BASE + 1)
+#define A39X_MV_MAX_MARVELL_BOARD_ID   (A39X_MARVELL_BOARD_ID_BASE + 2)
+#define A39X_MV_MARVELL_BOARD_NUM      (A39X_MV_MAX_MARVELL_BOARD_ID - \
+                                        A39X_MARVELL_BOARD_ID_BASE)
+
+#ifdef CONFIG_ARMADA_38X
+#define CUTOMER_BOARD_ID_BASE          A38X_CUSTOMER_BOARD_ID_BASE
+#define CUSTOMER_BOARD_ID0             A38X_CUSTOMER_BOARD_ID0
+#define CUSTOMER_BOARD_ID1             A38X_CUSTOMER_BOARD_ID1
+#define MV_MAX_CUSTOMER_BOARD_ID       A38X_MV_MAX_CUSTOMER_BOARD_ID
+#define MV_CUSTOMER_BOARD_NUM          A38X_MV_CUSTOMER_BOARD_NUM
+#define MARVELL_BOARD_ID_BASE          A38X_MARVELL_BOARD_ID_BASE
+#define MV_MAX_MARVELL_BOARD_ID                A38X_MV_MAX_MARVELL_BOARD_ID
+#define MV_MARVELL_BOARD_NUM           A38X_MV_MARVELL_BOARD_NUM
+#define MV_DEFAULT_BOARD_ID            DB_68XX_ID
+#define MV_DEFAULT_DEVICE_ID           MV_6811
+#elif defined(CONFIG_ARMADA_39X)
+#define CUTOMER_BOARD_ID_BASE          A39X_CUSTOMER_BOARD_ID_BASE
+#define CUSTOMER_BOARD_ID0             A39X_CUSTOMER_BOARD_ID0
+#define CUSTOMER_BOARD_ID1             A39X_CUSTOMER_BOARD_ID1
+#define MV_MAX_CUSTOMER_BOARD_ID       A39X_MV_MAX_CUSTOMER_BOARD_ID
+#define MV_CUSTOMER_BOARD_NUM          A39X_MV_CUSTOMER_BOARD_NUM
+#define MARVELL_BOARD_ID_BASE          A39X_MARVELL_BOARD_ID_BASE
+#define MV_MAX_MARVELL_BOARD_ID                A39X_MV_MAX_MARVELL_BOARD_ID
+#define MV_MARVELL_BOARD_NUM           A39X_MV_MARVELL_BOARD_NUM
+#define MV_DEFAULT_BOARD_ID            A39X_DB_69XX_ID
+#define MV_DEFAULT_DEVICE_ID           MV_6920
+#endif
+
+#define MV_INVALID_BOARD_ID            0xffffffff
+
+/* device revesion */
+#define DEV_VERSION_ID_REG             0x1823c
+#define REVISON_ID_OFFS                        8
+#define REVISON_ID_MASK                        0xf00
+
+/* A38x revisions */
+#define MV_88F68XX_Z1_ID               0x0
+#define MV_88F68XX_A0_ID               0x4
+/* A39x revisions */
+#define MV_88F69XX_Z1_ID               0x2
+
+#define MPP_CONTROL_REG(id)            (0x18000 + (id * 4))
+#define GPP_DATA_OUT_REG(grp)          (MV_GPP_REGS_BASE(grp) + 0x00)
+#define GPP_DATA_OUT_EN_REG(grp)       (MV_GPP_REGS_BASE(grp) + 0x04)
+#define GPP_DATA_IN_REG(grp)           (MV_GPP_REGS_BASE(grp) + 0x10)
+#define MV_GPP_REGS_BASE(unit)         (0x18100 + ((unit) * 0x40))
+
+#define MPP_REG_NUM(GPIO_NUM)          (GPIO_NUM / 8)
+#define MPP_MASK(GPIO_NUM)             (0xf << 4 * (GPIO_NUM - \
+                                       (MPP_REG_NUM(GPIO_NUM) * 8)));
+#define GPP_REG_NUM(GPIO_NUM)          (GPIO_NUM / 32)
+#define GPP_MASK(GPIO_NUM)             (1 << GPIO_NUM % 32)
+
+/* device ID */
+/* Armada 38x Family */
+#define MV_6810_DEV_ID         0x6810
+#define MV_6811_DEV_ID         0x6811
+#define MV_6820_DEV_ID         0x6820
+#define MV_6828_DEV_ID         0x6828
+/* Armada 39x Family */
+#define MV_6920_DEV_ID         0x6920
+#define MV_6928_DEV_ID         0x6928
+
+enum {
+       MV_6810,
+       MV_6820,
+       MV_6811,
+       MV_6828,
+       MV_NONE,
+       MV_6920,
+       MV_6928,
+       MV_MAX_DEV_ID,
+};
+
+#define MV_6820_INDEX                  0
+#define MV_6810_INDEX                  1
+#define MV_6811_INDEX                  2
+#define MV_6828_INDEX                  3
+
+#define MV_6920_INDEX                  0
+#define MV_6928_INDEX                  1
+
+#ifdef CONFIG_ARMADA_38X
+#define MAX_DEV_ID_NUM                 4
+#else
+#define MAX_DEV_ID_NUM                 2
+#endif
+
+#define MV_6820_INDEX                  0
+#define MV_6810_INDEX                  1
+#define MV_6811_INDEX                  2
+#define MV_6828_INDEX                  3
+#define MV_6920_INDEX                  0
+#define MV_6928_INDEX                  1
+
+enum unit_id {
+       PEX_UNIT_ID,
+       ETH_GIG_UNIT_ID,
+       USB3H_UNIT_ID,
+       USB3D_UNIT_ID,
+       SATA_UNIT_ID,
+       QSGMII_UNIT_ID,
+       XAUI_UNIT_ID,
+       RXAUI_UNIT_ID,
+       MAX_UNITS_ID
+};
+
+struct board_wakeup_gpio {
+       u32 board_id;
+       int gpio_num;
+};
+
+enum suspend_wakeup_status {
+       SUSPEND_WAKEUP_DISABLED,
+       SUSPEND_WAKEUP_ENABLED,
+       SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED,
+};
+
+/*
+ * GPIO status indication for Suspend Wakeup:
+ * If suspend to RAM is supported and GPIO inidcation is implemented,
+ * set the gpio number
+ * If suspend to RAM is supported but GPIO indication is not implemented
+ * set '-2'
+ * If suspend to RAM is not supported set '-1'
+ */
+#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
+#ifdef CONFIG_ARMADA_38X
+#define MV_BOARD_WAKEUP_GPIO_INFO {            \
+       {A38X_CUSTOMER_BOARD_ID0,       -1 },   \
+       {A38X_CUSTOMER_BOARD_ID0,       -1 },   \
+};
+#else
+#define MV_BOARD_WAKEUP_GPIO_INFO {            \
+       {A39X_CUSTOMER_BOARD_ID0,       -1 },   \
+       {A39X_CUSTOMER_BOARD_ID0,       -1 },   \
+};
+#endif /* CONFIG_ARMADA_38X */
+
+#else
+
+#ifdef CONFIG_ARMADA_38X
+#define MV_BOARD_WAKEUP_GPIO_INFO {    \
+       {RD_NAS_68XX_ID, -2 },          \
+       {DB_68XX_ID,     -1 },          \
+       {RD_AP_68XX_ID,  -2 },          \
+       {DB_AP_68XX_ID,  -2 },          \
+       {DB_GP_68XX_ID,  -2 },          \
+       {DB_BP_6821_ID,  -2 },          \
+       {DB_AMC_6820_ID, -2 },          \
+};
+#else
+#define MV_BOARD_WAKEUP_GPIO_INFO {    \
+       {A39X_RD_69XX_ID, -1 },         \
+       {A39X_DB_69XX_ID, -1 },         \
+};
+#endif /* CONFIG_ARMADA_38X */
+#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */
+
+u32 mv_board_tclk_get(void);
+u32 mv_board_id_get(void);
+u32 mv_board_id_index_get(u32 board_id);
+u32 sys_env_unit_max_num_get(enum unit_id unit);
+enum suspend_wakeup_status sys_env_suspend_wakeup_check(void);
+u8 sys_env_device_rev_get(void);
+u32 sys_env_device_id_get(void);
+u16 sys_env_model_get(void);
+struct dlb_config *sys_env_dlb_config_ptr_get(void);
+u32 sys_env_get_topology_update_info(
+       struct topology_update_info *topology_update_info);
+u32 sys_env_get_cs_ena_from_reg(void);
+
+#endif /* _SYS_ENV_LIB_H */