aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/net/mscc_eswitch
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/net/mscc_eswitch
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/net/mscc_eswitch')
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/Kconfig46
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/Makefile7
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/felix_switch.c414
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/jr2_switch.c1000
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/luton_switch.c739
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.c75
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.h19
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.c103
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.h24
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.c142
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.h20
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/ocelot_switch.c654
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/serval_switch.c607
-rw-r--r--roms/u-boot/drivers/net/mscc_eswitch/servalt_switch.c526
14 files changed, 4376 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/Kconfig b/roms/u-boot/drivers/net/mscc_eswitch/Kconfig
new file mode 100644
index 000000000..ccf7822db
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/Kconfig
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2019 Microsemi Corporation
+
+config MSCC_OCELOT_SWITCH
+ bool "Ocelot switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Ocelot network switch device.
+
+config MSCC_LUTON_SWITCH
+ bool "Luton switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Luton network switch device.
+
+config MSCC_JR2_SWITCH
+ bool "Jaguar2 switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Jaguar2 network switch device.
+
+config MSCC_SERVALT_SWITCH
+ bool "Servalt switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Servalt network switch device.
+
+config MSCC_SERVAL_SWITCH
+ bool "Serval switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Serval network switch device.
+
+config MSCC_FELIX_SWITCH
+ bool "Felix switch driver"
+ depends on DM_DSA && DM_PCI
+ select FSL_ENETC
+ help
+ This driver supports the Ethernet switch integrated in the
+ NXP LS1028A SoC.
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/Makefile b/roms/u-boot/drivers/net/mscc_eswitch/Makefile
new file mode 100644
index 000000000..22342ed11
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/Makefile
@@ -0,0 +1,7 @@
+
+obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o
+obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o
+obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o mscc_miim.o
+obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o mscc_miim.o
+obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o
+obj-$(CONFIG_MSCC_FELIX_SWITCH) += felix_switch.o
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/felix_switch.c b/roms/u-boot/drivers/net/mscc_eswitch/felix_switch.c
new file mode 100644
index 000000000..f20e84e0f
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/felix_switch.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Felix (VSC9959) Ethernet switch driver
+ * Copyright 2018-2021 NXP Semiconductors
+ */
+
+/*
+ * This driver is used for the Ethernet switch integrated into NXP LS1028A.
+ * Felix switch is derived from Microsemi Ocelot but there are several NXP
+ * adaptations that makes the two U-Boot drivers largely incompatible.
+ *
+ * Felix on LS1028A has 4 front panel ports and two internal ports, connected
+ * to ENETC interfaces. We're using one of the ENETC interfaces to push traffic
+ * into the switch. Injection/extraction headers are used to identify
+ * egress/ingress ports in the switch for Tx/Rx.
+ */
+
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <net/dsa.h>
+#include <asm/io.h>
+#include <miiphy.h>
+#include <pci.h>
+
+/* defines especially around PCS are reused from enetc */
+#include "../fsl_enetc.h"
+
+#define PCI_DEVICE_ID_FELIX_ETHSW 0xEEF0
+
+/* Felix has in fact 6 ports, but we don't use the last internal one */
+#define FELIX_PORT_COUNT 5
+/* Front panel port mask */
+#define FELIX_FP_PORT_MASK 0xf
+
+/* Register map for BAR4 */
+#define FELIX_SYS 0x010000
+#define FELIX_ES0 0x040000
+#define FELIX_IS1 0x050000
+#define FELIX_IS2 0x060000
+#define FELIX_GMII(port) (0x100000 + (port) * 0x10000)
+#define FELIX_QSYS 0x200000
+
+#define FELIX_SYS_SYSTEM (FELIX_SYS + 0x00000E00)
+#define FELIX_SYS_SYSTEM_EN BIT(0)
+#define FELIX_SYS_RAM_CTRL (FELIX_SYS + 0x00000F24)
+#define FELIX_SYS_RAM_CTRL_INIT BIT(1)
+#define FELIX_SYS_SYSTEM_PORT_MODE(a) (FELIX_SYS_SYSTEM + 0xC + (a) * 4)
+#define FELIX_SYS_SYSTEM_PORT_MODE_CPU 0x0000001e
+
+#define FELIX_ES0_TCAM_CTRL (FELIX_ES0 + 0x000003C0)
+#define FELIX_ES0_TCAM_CTRL_EN BIT(0)
+#define FELIX_IS1_TCAM_CTRL (FELIX_IS1 + 0x000003C0)
+#define FELIX_IS1_TCAM_CTRL_EN BIT(0)
+#define FELIX_IS2_TCAM_CTRL (FELIX_IS2 + 0x000003C0)
+#define FELIX_IS2_TCAM_CTRL_EN BIT(0)
+
+#define FELIX_GMII_CLOCK_CFG(port) (FELIX_GMII(port) + 0x00000000)
+#define FELIX_GMII_CLOCK_CFG_LINK_1G 1
+#define FELIX_GMII_CLOCK_CFG_LINK_100M 2
+#define FELIX_GMII_CLOCK_CFG_LINK_10M 3
+#define FELIX_GMII_MAC_ENA_CFG(port) (FELIX_GMII(port) + 0x0000001C)
+#define FELIX_GMII_MAX_ENA_CFG_TX BIT(0)
+#define FELIX_GMII_MAX_ENA_CFG_RX BIT(4)
+#define FELIX_GMII_MAC_IFG_CFG(port) (FELIX_GMII(port) + 0x0000001C + 0x14)
+#define FELIX_GMII_MAC_IFG_CFG_DEF 0x515
+
+#define FELIX_QSYS_SYSTEM (FELIX_QSYS + 0x0000F460)
+#define FELIX_QSYS_SYSTEM_SW_PORT_MODE(a) \
+ (FELIX_QSYS_SYSTEM + 0x20 + (a) * 4)
+#define FELIX_QSYS_SYSTEM_SW_PORT_ENA BIT(14)
+#define FELIX_QSYS_SYSTEM_SW_PORT_LOSSY BIT(9)
+#define FELIX_QSYS_SYSTEM_SW_PORT_SCH(a) (((a) & 0x3800) << 11)
+#define FELIX_QSYS_SYSTEM_EXT_CPU_CFG (FELIX_QSYS_SYSTEM + 0x80)
+#define FELIX_QSYS_SYSTEM_EXT_CPU_PORT(a) (((a) & 0xf) << 8 | 0xff)
+
+/* internal MDIO in BAR0 */
+#define FELIX_PM_IMDIO_BASE 0x8030
+
+/* Serdes block on LS1028A */
+#define FELIX_SERDES_BASE 0x1ea0000L
+#define FELIX_SERDES_LNATECR0(lane) (FELIX_SERDES_BASE + 0x818 + \
+ (lane) * 0x40)
+#define FELIX_SERDES_LNATECR0_ADPT_EQ 0x00003000
+#define FELIX_SERDES_SGMIICR1(lane) (FELIX_SERDES_BASE + 0x1804 + \
+ (lane) * 0x10)
+#define FELIX_SERDES_SGMIICR1_SGPCS BIT(11)
+#define FELIX_SERDES_SGMIICR1_MDEV(a) (((a) & 0x1f) << 27)
+
+#define FELIX_PCS_CTRL 0
+#define FELIX_PCS_CTRL_RST BIT(15)
+
+/*
+ * The long prefix format used here contains two dummy MAC addresses, a magic
+ * value in place of a VLAN tag followed by the extraction/injection header and
+ * the original L2 frame. Out of all this we only use the port ID.
+ */
+#define FELIX_DSA_TAG_LEN sizeof(struct felix_dsa_tag)
+#define FELIX_DSA_TAG_MAGIC 0x0a008088
+#define FELIX_DSA_TAG_INJ_PORT 7
+#define FELIX_DSA_TAG_INJ_PORT_SET(a) (0x1 << ((a) & FELIX_FP_PORT_MASK))
+#define FELIX_DSA_TAG_EXT_PORT 10
+#define FELIX_DSA_TAG_EXT_PORT_GET(a) ((a) >> 3)
+
+struct felix_dsa_tag {
+ uchar d_mac[6];
+ uchar s_mac[6];
+ u32 magic;
+ uchar meta[16];
+};
+
+struct felix_priv {
+ void *regs_base;
+ void *imdio_base;
+ struct mii_dev imdio;
+};
+
+/* MDIO wrappers, we're using these to drive internal MDIO to get to serdes */
+static int felix_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct enetc_mdio_priv priv;
+
+ priv.regs_base = bus->priv;
+ return enetc_mdio_read_priv(&priv, addr, devad, reg);
+}
+
+static int felix_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct enetc_mdio_priv priv;
+
+ priv.regs_base = bus->priv;
+ return enetc_mdio_write_priv(&priv, addr, devad, reg, val);
+}
+
+/* set up serdes for SGMII */
+static void felix_init_sgmii(struct mii_dev *imdio, int pidx, bool an)
+{
+ u16 reg;
+
+ /* set up PCS lane address */
+ out_le32(FELIX_SERDES_SGMIICR1(pidx), FELIX_SERDES_SGMIICR1_SGPCS |
+ FELIX_SERDES_SGMIICR1_MDEV(pidx));
+
+ /*
+ * Set to SGMII mode, for 1Gbps enable AN, for 2.5Gbps set fixed speed.
+ * Although fixed speed is 1Gbps, we could be running at 2.5Gbps based
+ * on PLL configuration. Setting 1G for 2.5G here is counter intuitive
+ * but intentional.
+ */
+ reg = ENETC_PCS_IF_MODE_SGMII;
+ reg |= an ? ENETC_PCS_IF_MODE_SGMII_AN : ENETC_PCS_IF_MODE_SPEED_1G;
+ felix_mdio_write(imdio, pidx, MDIO_DEVAD_NONE,
+ ENETC_PCS_IF_MODE, reg);
+
+ /* Dev ability - SGMII */
+ felix_mdio_write(imdio, pidx, MDIO_DEVAD_NONE,
+ ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SGMII);
+
+ /* Adjust link timer for SGMII */
+ felix_mdio_write(imdio, pidx, MDIO_DEVAD_NONE,
+ ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
+ felix_mdio_write(imdio, pidx, MDIO_DEVAD_NONE,
+ ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
+
+ reg = ENETC_PCS_CR_DEF_VAL;
+ reg |= an ? ENETC_PCS_CR_RESET_AN : ENETC_PCS_CR_RST;
+ /* restart PCS AN */
+ felix_mdio_write(imdio, pidx, MDIO_DEVAD_NONE,
+ ENETC_PCS_CR, reg);
+}
+
+/* set up MAC and serdes for (Q)SXGMII */
+static int felix_init_sxgmii(struct mii_dev *imdio, int pidx)
+{
+ int timeout = 1000;
+
+ /* set up transit equalization control on serdes lane */
+ out_le32(FELIX_SERDES_LNATECR0(1), FELIX_SERDES_LNATECR0_ADPT_EQ);
+
+ /*reset lane */
+ felix_mdio_write(imdio, pidx, MDIO_MMD_PCS, FELIX_PCS_CTRL,
+ FELIX_PCS_CTRL_RST);
+ while (felix_mdio_read(imdio, pidx, MDIO_MMD_PCS,
+ FELIX_PCS_CTRL) & FELIX_PCS_CTRL_RST &&
+ --timeout) {
+ mdelay(10);
+ }
+ if (felix_mdio_read(imdio, pidx, MDIO_MMD_PCS,
+ FELIX_PCS_CTRL) & FELIX_PCS_CTRL_RST)
+ return -ETIME;
+
+ /* Dev ability - SXGMII */
+ felix_mdio_write(imdio, pidx, ENETC_PCS_DEVAD_REPL,
+ ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII);
+
+ /* Restart PCS AN */
+ felix_mdio_write(imdio, pidx, ENETC_PCS_DEVAD_REPL, ENETC_PCS_CR,
+ ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN);
+ felix_mdio_write(imdio, pidx, ENETC_PCS_DEVAD_REPL,
+ ENETC_PCS_REPL_LINK_TIMER_1,
+ ENETC_PCS_REPL_LINK_TIMER_1_DEF);
+ felix_mdio_write(imdio, pidx, ENETC_PCS_DEVAD_REPL,
+ ENETC_PCS_REPL_LINK_TIMER_2,
+ ENETC_PCS_REPL_LINK_TIMER_2_DEF);
+
+ return 0;
+}
+
+/* Apply protocol specific configuration to MAC, serdes as needed */
+static void felix_start_pcs(struct udevice *dev, int port,
+ struct phy_device *phy, struct mii_dev *imdio)
+{
+ bool autoneg = true;
+
+ if (phy->phy_id == PHY_FIXED_ID ||
+ phy->interface == PHY_INTERFACE_MODE_SGMII_2500)
+ autoneg = false;
+
+ switch (phy->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_SGMII_2500:
+ case PHY_INTERFACE_MODE_QSGMII:
+ felix_init_sgmii(imdio, port, autoneg);
+ break;
+ case PHY_INTERFACE_MODE_XGMII:
+ case PHY_INTERFACE_MODE_XFI:
+ case PHY_INTERFACE_MODE_USXGMII:
+ if (felix_init_sxgmii(imdio, port))
+ dev_err(dev, "PCS reset timeout on port %d\n", port);
+ break;
+ default:
+ break;
+ }
+}
+
+void felix_init(struct udevice *dev)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
+ struct felix_priv *priv = dev_get_priv(dev);
+ void *base = priv->regs_base;
+ int timeout = 100;
+
+ /* Init core memories */
+ out_le32(base + FELIX_SYS_RAM_CTRL, FELIX_SYS_RAM_CTRL_INIT);
+ while (in_le32(base + FELIX_SYS_RAM_CTRL) & FELIX_SYS_RAM_CTRL_INIT &&
+ --timeout)
+ udelay(10);
+ if (in_le32(base + FELIX_SYS_RAM_CTRL) & FELIX_SYS_RAM_CTRL_INIT)
+ dev_err(dev, "Timeout waiting for switch memories\n");
+
+ /* Start switch core, set up ES0, IS1, IS2 */
+ out_le32(base + FELIX_SYS_SYSTEM, FELIX_SYS_SYSTEM_EN);
+ out_le32(base + FELIX_ES0_TCAM_CTRL, FELIX_ES0_TCAM_CTRL_EN);
+ out_le32(base + FELIX_IS1_TCAM_CTRL, FELIX_IS1_TCAM_CTRL_EN);
+ out_le32(base + FELIX_IS2_TCAM_CTRL, FELIX_IS2_TCAM_CTRL_EN);
+ udelay(20);
+
+ priv->imdio.read = felix_mdio_read;
+ priv->imdio.write = felix_mdio_write;
+ priv->imdio.priv = priv->imdio_base + FELIX_PM_IMDIO_BASE;
+ strncpy(priv->imdio.name, dev->name, MDIO_NAME_LEN);
+
+ /* set up CPU port */
+ out_le32(base + FELIX_QSYS_SYSTEM_EXT_CPU_CFG,
+ FELIX_QSYS_SYSTEM_EXT_CPU_PORT(pdata->cpu_port));
+ out_le32(base + FELIX_SYS_SYSTEM_PORT_MODE(pdata->cpu_port),
+ FELIX_SYS_SYSTEM_PORT_MODE_CPU);
+}
+
+/*
+ * Probe Felix:
+ * - enable the PCI function
+ * - map BAR 4
+ * - init switch core and port registers
+ */
+static int felix_probe(struct udevice *dev)
+{
+ struct felix_priv *priv = dev_get_priv(dev);
+
+ if (ofnode_valid(dev_ofnode(dev)) &&
+ !ofnode_is_available(dev_ofnode(dev))) {
+ dev_dbg(dev, "switch disabled\n");
+ return -ENODEV;
+ }
+
+ priv->imdio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ if (!priv->imdio_base) {
+ dev_err(dev, "failed to map BAR0\n");
+ return -EINVAL;
+ }
+
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4, 0);
+ if (!priv->regs_base) {
+ dev_err(dev, "failed to map BAR4\n");
+ return -EINVAL;
+ }
+
+ /* register internal MDIO for debug */
+ if (!miiphy_get_dev_by_name(dev->name)) {
+ struct mii_dev *mii_bus;
+
+ mii_bus = mdio_alloc();
+ mii_bus->read = felix_mdio_read;
+ mii_bus->write = felix_mdio_write;
+ mii_bus->priv = priv->imdio_base + FELIX_PM_IMDIO_BASE;
+ strncpy(mii_bus->name, dev->name, MDIO_NAME_LEN);
+ mdio_register(mii_bus);
+ }
+
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+
+ dsa_set_tagging(dev, FELIX_DSA_TAG_LEN, 0);
+
+ /* set up registers */
+ felix_init(dev);
+
+ return 0;
+}
+
+static int felix_port_enable(struct udevice *dev, int port,
+ struct phy_device *phy)
+{
+ int supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full;
+ struct felix_priv *priv = dev_get_priv(dev);
+ void *base = priv->regs_base;
+
+ /* Set up MAC registers */
+ out_le32(base + FELIX_GMII_CLOCK_CFG(port),
+ FELIX_GMII_CLOCK_CFG_LINK_1G);
+
+ out_le32(base + FELIX_GMII_MAC_IFG_CFG(port),
+ FELIX_GMII_MAC_IFG_CFG_DEF);
+
+ out_le32(base + FELIX_GMII_MAC_ENA_CFG(port),
+ FELIX_GMII_MAX_ENA_CFG_TX | FELIX_GMII_MAX_ENA_CFG_RX);
+
+ out_le32(base + FELIX_QSYS_SYSTEM_SW_PORT_MODE(port),
+ FELIX_QSYS_SYSTEM_SW_PORT_ENA |
+ FELIX_QSYS_SYSTEM_SW_PORT_LOSSY |
+ FELIX_QSYS_SYSTEM_SW_PORT_SCH(1));
+
+ felix_start_pcs(dev, port, phy, &priv->imdio);
+
+ phy->supported &= supported;
+ phy->advertising &= supported;
+ phy_config(phy);
+
+ phy_startup(phy);
+
+ return 0;
+}
+
+static void felix_port_disable(struct udevice *dev, int pidx,
+ struct phy_device *phy)
+{
+ struct felix_priv *priv = dev_get_priv(dev);
+ void *base = priv->regs_base;
+
+ out_le32(base + FELIX_GMII_MAC_ENA_CFG(pidx), 0);
+
+ out_le32(base + FELIX_QSYS_SYSTEM_SW_PORT_MODE(pidx),
+ FELIX_QSYS_SYSTEM_SW_PORT_LOSSY |
+ FELIX_QSYS_SYSTEM_SW_PORT_SCH(1));
+
+ /*
+ * we don't call phy_shutdown here to avoid waiting next time we use
+ * the port, but the downside is that remote side will think we're
+ * actively processing traffic although we are not.
+ */
+}
+
+static int felix_xmit(struct udevice *dev, int pidx, void *packet, int length)
+{
+ struct felix_dsa_tag *tag = packet;
+
+ tag->magic = FELIX_DSA_TAG_MAGIC;
+ tag->meta[FELIX_DSA_TAG_INJ_PORT] = FELIX_DSA_TAG_INJ_PORT_SET(pidx);
+
+ return 0;
+}
+
+static int felix_rcv(struct udevice *dev, int *pidx, void *packet, int length)
+{
+ struct felix_dsa_tag *tag = packet;
+
+ if (tag->magic != FELIX_DSA_TAG_MAGIC)
+ return -EINVAL;
+
+ *pidx = FELIX_DSA_TAG_EXT_PORT_GET(tag->meta[FELIX_DSA_TAG_EXT_PORT]);
+
+ return 0;
+}
+
+static const struct dsa_ops felix_dsa_ops = {
+ .port_enable = felix_port_enable,
+ .port_disable = felix_port_disable,
+ .xmit = felix_xmit,
+ .rcv = felix_rcv,
+};
+
+U_BOOT_DRIVER(felix_ethsw) = {
+ .name = "felix-switch",
+ .id = UCLASS_DSA,
+ .probe = felix_probe,
+ .ops = &felix_dsa_ops,
+ .priv_auto = sizeof(struct felix_priv),
+};
+
+static struct pci_device_id felix_ethsw_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_FELIX_ETHSW) },
+ {}
+};
+
+U_BOOT_PCI_DEVICE(felix_ethsw, felix_ethsw_ids);
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/jr2_switch.c b/roms/u-boot/drivers/net/mscc_eswitch/jr2_switch.c
new file mode 100644
index 000000000..d1e5b61ea
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/jr2_switch.c
@@ -0,0 +1,1000 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <malloc.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include <dt-bindings/mscc/jr2_data.h>
+#include "mscc_xfer.h"
+#include "mscc_miim.h"
+
+#define ANA_AC_RAM_CTRL_RAM_INIT 0x94358
+#define ANA_AC_STAT_GLOBAL_CFG_PORT_RESET 0x94370
+
+#define ANA_CL_PORT_VLAN_CFG(x) (0x24018 + 0xc8 * (x))
+#define ANA_CL_PORT_VLAN_CFG_AWARE_ENA BIT(19)
+#define ANA_CL_PORT_VLAN_CFG_POP_CNT(x) ((x) << 17)
+
+#define ANA_L2_COMMON_FWD_CFG 0x8a2a8
+#define ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA BIT(6)
+
+#define ASM_CFG_STAT_CFG 0x3508
+#define ASM_CFG_PORT(x) (0x36c4 + 0x4 * (x))
+#define ASM_CFG_PORT_NO_PREAMBLE_ENA BIT(8)
+#define ASM_CFG_PORT_INJ_FORMAT_CFG(x) ((x) << 1)
+#define ASM_RAM_CTRL_RAM_INIT 0x39b8
+
+#define DEV_DEV_CFG_DEV_RST_CTRL 0x0
+#define DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(x) ((x) << 20)
+#define DEV_MAC_CFG_MAC_ENA 0x1c
+#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
+#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
+#define DEV_MAC_CFG_MAC_IFG 0x34
+#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
+#define DEV_PCS1G_CFG_PCS1G_CFG 0x40
+#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
+#define DEV_PCS1G_CFG_PCS1G_MODE 0x44
+#define DEV_PCS1G_CFG_PCS1G_SD 0x48
+#define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c
+#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
+
+#define DSM_RAM_CTRL_RAM_INIT 0x8
+
+#define HSIO_ANA_SERDES1G_DES_CFG 0xac
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
+#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG 0xb0
+#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
+#define HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x) ((x) << 19)
+#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG 0xb4
+#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
+#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG 0xb8
+#define HSIO_ANA_SERDES1G_COMMON_CFG 0xbc
+#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG 0xc0
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0 0xc8
+#define HSIO_DIG_SERDES1G_TP_CFG 0xd4
+#define HSIO_DIG_SERDES1G_MISC_CFG 0xdc
+#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES1G_CFG 0xe8
+#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
+
+#define HSIO_ANA_SERDES6G_DES_CFG 0x11c
+#define HSIO_ANA_SERDES6G_DES_CFG_SWAP_ANA BIT(0)
+#define HSIO_ANA_SERDES6G_DES_CFG_BW_ANA(x) ((x) << 1)
+#define HSIO_ANA_SERDES6G_DES_CFG_SWAP_HYST BIT(4)
+#define HSIO_ANA_SERDES6G_DES_CFG_BW_HYST(x) ((x) << 5)
+#define HSIO_ANA_SERDES6G_DES_CFG_CPMD_SEL(x) ((x) << 8)
+#define HSIO_ANA_SERDES6G_DES_CFG_MBTR_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES6G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES6G_IB_CFG 0x120
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_ENA BIT(0)
+#define HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA BIT(1)
+#define HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA BIT(2)
+#define HSIO_ANA_SERDES6G_IB_CFG_CAL_ENA(x) ((x) << 3)
+#define HSIO_ANA_SERDES6G_IB_CFG_CONCUR BIT(4)
+#define HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA BIT(5)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(x) ((x) << 7)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(x) ((x) << 9)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(x) ((x) << 11)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(x) ((x) << 13)
+#define HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(x) ((x) << 15)
+#define HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(x) ((x) << 20)
+#define HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(x) ((x) << 24)
+#define HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL BIT(28)
+#define HSIO_ANA_SERDES6G_IB_CFG_SOFSI(x) ((x) << 29)
+#define HSIO_ANA_SERDES6G_IB_CFG1 0x124
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET BIT(4)
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP BIT(5)
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID BIT(6)
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP BIT(7)
+#define HSIO_ANA_SERDES6G_IB_CFG1_SCALY(x) ((x) << 8)
+#define HSIO_ANA_SERDES6G_IB_CFG1_TSDET(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(x) ((x) << 17)
+#define HSIO_ANA_SERDES6G_IB_CFG2 0x128
+#define HSIO_ANA_SERDES6G_IB_CFG2_UREG(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG2_UMAX(x) ((x) << 3)
+#define HSIO_ANA_SERDES6G_IB_CFG2_TCALV(x) ((x) << 5)
+#define HSIO_ANA_SERDES6G_IB_CFG2_OCALS(x) ((x) << 10)
+#define HSIO_ANA_SERDES6G_IB_CFG2_OINFS(x) ((x) << 16)
+#define HSIO_ANA_SERDES6G_IB_CFG2_OINFI(x) ((x) << 22)
+#define HSIO_ANA_SERDES6G_IB_CFG2_TINFV(x) ((x) << 27)
+#define HSIO_ANA_SERDES6G_IB_CFG3 0x12c
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_OFFSET(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_LP(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_MID(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_HP(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_IB_CFG4 0x130
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_OFFSET(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_LP(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_MID(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_HP(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_IB_CFG5 0x134
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_OFFSET(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_LP(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_MID(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_HP(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_OB_CFG 0x138
+#define HSIO_ANA_SERDES6G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES6G_OB_CFG_SR(x) ((x) << 4)
+#define HSIO_ANA_SERDES6G_OB_CFG_SR_H BIT(8)
+#define HSIO_ANA_SERDES6G_OB_CFG_SEL_RCTRL BIT(9)
+#define HSIO_ANA_SERDES6G_OB_CFG_R_COR BIT(10)
+#define HSIO_ANA_SERDES6G_OB_CFG_POST1(x) ((x) << 11)
+#define HSIO_ANA_SERDES6G_OB_CFG_R_ADJ_PDR BIT(16)
+#define HSIO_ANA_SERDES6G_OB_CFG_R_ADJ_MUX BIT(17)
+#define HSIO_ANA_SERDES6G_OB_CFG_PREC(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_OB_CFG_POST0(x) ((x) << 23)
+#define HSIO_ANA_SERDES6G_OB_CFG_POL BIT(29)
+#define HSIO_ANA_SERDES6G_OB_CFG_ENA1V_MODE(x) ((x) << 30)
+#define HSIO_ANA_SERDES6G_OB_CFG_IDLE BIT(31)
+#define HSIO_ANA_SERDES6G_OB_CFG1 0x13c
+#define HSIO_ANA_SERDES6G_OB_CFG1_LEV(x) (x)
+#define HSIO_ANA_SERDES6G_OB_CFG1_ENA_CAS(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_SER_CFG 0x140
+#define HSIO_ANA_SERDES6G_COMMON_CFG 0x144
+#define HSIO_ANA_SERDES6G_COMMON_CFG_IF_MODE(x) (x)
+#define HSIO_ANA_SERDES6G_COMMON_CFG_QRATE(x) (x << 2)
+#define HSIO_ANA_SERDES6G_COMMON_CFG_ENA_LANE BIT(14)
+#define HSIO_ANA_SERDES6G_COMMON_CFG_SYS_RST BIT(16)
+#define HSIO_ANA_SERDES6G_PLL_CFG 0x148
+#define HSIO_ANA_SERDES6G_PLL_CFG_ROT_FRQ BIT(0)
+#define HSIO_ANA_SERDES6G_PLL_CFG_ROT_DIR BIT(1)
+#define HSIO_ANA_SERDES6G_PLL_CFG_RB_DATA_SEL BIT(2)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_OOR_RECAL_ENA BIT(3)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_FORCE_SET_ENA BIT(4)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_ENA BIT(5)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_PLL_CFG_ENA_ROT BIT(14)
+#define HSIO_ANA_SERDES6G_PLL_CFG_DIV4 BIT(15)
+#define HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(x) ((x) << 16)
+#define HSIO_DIG_SERDES6G_MISC_CFG 0x108
+#define HSIO_DIG_SERDES6G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES6G_CFG 0x168
+#define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x)
+#define HSIO_HW_CFGSTAT_HW_CFG 0x16c
+
+#define LRN_COMMON_ACCESS_CTRL 0x0
+#define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT BIT(0)
+#define LRN_COMMON_MAC_ACCESS_CFG0 0x4
+#define LRN_COMMON_MAC_ACCESS_CFG1 0x8
+#define LRN_COMMON_MAC_ACCESS_CFG2 0xc
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(x) (x)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(x) ((x) << 12)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD BIT(15)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED BIT(16)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY BIT(23)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(x) ((x) << 24)
+
+#define QFWD_SYSTEM_SWITCH_PORT_MODE(x) (0x4 * (x))
+#define QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA BIT(17)
+
+#define QS_XTR_GRP_CFG(x) (0x0 + 4 * (x))
+#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
+
+#define QSYS_SYSTEM_RESET_CFG 0xf0
+#define QSYS_CALCFG_CAL_AUTO(x) (0x3d4 + 4 * (x))
+#define QSYS_CALCFG_CAL_CTRL 0x3e8
+#define QSYS_CALCFG_CAL_CTRL_CAL_MODE(x) ((x) << 11)
+#define QSYS_RAM_CTRL_RAM_INIT 0x3ec
+
+#define REW_RAM_CTRL_RAM_INIT 0x53528
+
+#define VOP_RAM_CTRL_RAM_INIT 0x43638
+
+#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
+#define MAC_VID 0
+#define CPU_PORT 53
+#define IFH_LEN 7
+#define JR2_BUF_CELL_SZ 60
+#define ETH_ALEN 6
+#define PGID_BROADCAST 510
+#define PGID_UNICAST 511
+
+static const char * const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+ "port8", "port9", "port10", "port11", "port12", "port13", "port14",
+ "port15", "port16", "port17", "port18", "port19", "port20", "port21",
+ "port22", "port23", "port24", "port25", "port26", "port27", "port28",
+ "port29", "port30", "port31", "port32", "port33", "port34", "port35",
+ "port36", "port37", "port38", "port39", "port40", "port41", "port42",
+ "port43", "port44", "port45", "port46", "port47",
+ "ana_ac", "ana_cl", "ana_l2", "asm", "hsio", "lrn",
+ "qfwd", "qs", "qsys", "rew", "gcb", "icpu",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 48
+
+enum jr2_ctrl_regs {
+ ANA_AC = MAX_PORT,
+ ANA_CL,
+ ANA_L2,
+ ASM,
+ HSIO,
+ LRN,
+ QFWD,
+ QS,
+ QSYS,
+ REW,
+ GCB,
+ ICPU,
+};
+
+#define JR2_MIIM_BUS_COUNT 3
+
+struct jr2_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
+};
+
+struct jr2_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[JR2_MIIM_BUS_COUNT];
+ struct jr2_phy_port_t ports[MAX_PORT];
+};
+
+static const unsigned long jr2_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x8,
+ [MSCC_QS_XTR_FLUSH] = 0x18,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+ [MSCC_QS_INJ_WR] = 0x2c,
+ [MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static struct mscc_miim_dev miim[JR2_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static void jr2_cpu_capture_setup(struct jr2_private *priv)
+{
+ /* ASM: No preamble and IFH prefix on CPU injected frames */
+ writel(ASM_CFG_PORT_NO_PREAMBLE_ENA |
+ ASM_CFG_PORT_INJ_FORMAT_CFG(1),
+ priv->regs[ASM] + ASM_CFG_PORT(CPU_PORT));
+
+ /* Set Manual injection via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x5, priv->regs[QS] + QS_INJ_GRP_CFG(0));
+
+ /* Set Manual extraction via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x7, priv->regs[QS] + QS_XTR_GRP_CFG(0));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(CPU_PORT),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+
+ /* Send a copy to CPU when found as forwarding entry */
+ setbits_le32(priv->regs[ANA_L2] + ANA_L2_COMMON_FWD_CFG,
+ ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA);
+}
+
+static void jr2_port_init(struct jr2_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
+ regs + DEV_PCS1G_CFG_PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+ DEV_MAC_CFG_MAC_ENA_TX_ENA,
+ regs + DEV_MAC_CFG_MAC_ENA);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
+ regs + DEV_PCS1G_CFG_PCS1G_ANEG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(4) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG1(5) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG2(1),
+ regs + DEV_MAC_CFG_MAC_IFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(2),
+ regs + DEV_DEV_CFG_DEV_RST_CTRL);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_CL_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_CL_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA_CL] + ANA_CL_PORT_VLAN_CFG(port));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(port),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes6g_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES6G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES6G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES6G_CFG);
+ } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes6g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ u32 ib_if_mode = 0;
+ u32 ib_qrate = 0;
+ u32 ib1_tsdet = 0;
+ u32 ob_lev = 0;
+ u32 ob_ena_cas = 0;
+ u32 ob_ena1v_mode = 0;
+ u32 des_bw_ana = 0;
+ u32 pll_fsm_ctrl_data = 0;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ib_if_mode = 1;
+ ib_qrate = 1;
+ ib1_tsdet = 3;
+ ob_lev = 48;
+ ob_ena_cas = 2;
+ ob_ena1v_mode = 1;
+ des_bw_ana = 3;
+ pll_fsm_ctrl_data = 60;
+ break;
+ case PHY_INTERFACE_MODE_QSGMII:
+ ib_if_mode = 3;
+ ib1_tsdet = 16;
+ ob_lev = 24;
+ des_bw_ana = 5;
+ pll_fsm_ctrl_data = 120;
+ break;
+ default:
+ pr_err("Interface not supported\n");
+ return;
+ }
+
+ if (interface == PHY_INTERFACE_MODE_QSGMII)
+ writel(0xfff, base + HSIO_HW_CFGSTAT_HW_CFG);
+
+ writel(HSIO_ANA_SERDES6G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES6G_OB_CFG_SR(7) |
+ HSIO_ANA_SERDES6G_OB_CFG_SR_H |
+ HSIO_ANA_SERDES6G_OB_CFG_ENA1V_MODE(ob_ena1v_mode) |
+ HSIO_ANA_SERDES6G_OB_CFG_POL, base + HSIO_ANA_SERDES6G_OB_CFG);
+
+ writel(HSIO_ANA_SERDES6G_COMMON_CFG_IF_MODE(3),
+ base + HSIO_ANA_SERDES6G_COMMON_CFG);
+ writel(HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(120) |
+ HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(3),
+ base + HSIO_ANA_SERDES6G_PLL_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(7) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP |
+ HSIO_ANA_SERDES6G_IB_CFG1_SCALY(15) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TSDET(3) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(8),
+ base + HSIO_ANA_SERDES6G_IB_CFG1);
+
+ writel(HSIO_ANA_SERDES6G_IB_CFG2_UREG(4) |
+ HSIO_ANA_SERDES6G_IB_CFG2_UMAX(2) |
+ HSIO_ANA_SERDES6G_IB_CFG2_TCALV(12) |
+ HSIO_ANA_SERDES6G_IB_CFG2_OCALS(32) |
+ HSIO_ANA_SERDES6G_IB_CFG2_OINFS(7) |
+ HSIO_ANA_SERDES6G_IB_CFG2_OINFI(0x1f) |
+ HSIO_ANA_SERDES6G_IB_CFG2_TINFV(3),
+ base + HSIO_ANA_SERDES6G_IB_CFG2);
+
+ writel(HSIO_ANA_SERDES6G_IB_CFG3_INI_OFFSET(0x1f) |
+ HSIO_ANA_SERDES6G_IB_CFG3_INI_LP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG3_INI_MID(0x1f),
+ base + HSIO_ANA_SERDES6G_IB_CFG3);
+
+ writel(HSIO_DIG_SERDES6G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES6G_MISC_CFG);
+
+ serdes6g_write(base, addr);
+
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP |
+ HSIO_ANA_SERDES6G_IB_CFG1_SCALY(15) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TSDET(16) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(8),
+ base + HSIO_ANA_SERDES6G_IB_CFG1);
+
+ writel(0x0, base + HSIO_ANA_SERDES6G_SER_CFG);
+ writel(HSIO_ANA_SERDES6G_COMMON_CFG_IF_MODE(ib_if_mode) |
+ HSIO_ANA_SERDES6G_COMMON_CFG_QRATE(ib_qrate) |
+ HSIO_ANA_SERDES6G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES6G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES6G_COMMON_CFG);
+ writel(HSIO_DIG_SERDES6G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES6G_MISC_CFG);
+
+ writel(HSIO_ANA_SERDES6G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES6G_OB_CFG_SR(7) |
+ HSIO_ANA_SERDES6G_OB_CFG_SR_H |
+ HSIO_ANA_SERDES6G_OB_CFG_ENA1V_MODE(ob_ena1v_mode) |
+ HSIO_ANA_SERDES6G_OB_CFG_POL, base + HSIO_ANA_SERDES6G_OB_CFG);
+ writel(HSIO_ANA_SERDES6G_OB_CFG1_LEV(ob_lev) |
+ HSIO_ANA_SERDES6G_OB_CFG1_ENA_CAS(ob_ena_cas),
+ base + HSIO_ANA_SERDES6G_OB_CFG1);
+
+ writel(HSIO_ANA_SERDES6G_DES_CFG_BW_ANA(des_bw_ana) |
+ HSIO_ANA_SERDES6G_DES_CFG_BW_HYST(5) |
+ HSIO_ANA_SERDES6G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES6G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES6G_DES_CFG);
+ writel(HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(pll_fsm_ctrl_data) |
+ HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(3),
+ base + HSIO_ANA_SERDES6G_PLL_CFG);
+
+ serdes6g_write(base, addr);
+
+ /* set pll_fsm_ena = 1 */
+ writel(HSIO_ANA_SERDES6G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(pll_fsm_ctrl_data) |
+ HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(3),
+ base + HSIO_ANA_SERDES6G_PLL_CFG);
+
+ serdes6g_write(base, addr);
+
+ /* wait 20ms for pll bringup */
+ mdelay(20);
+
+ /* start IB calibration by setting ib_cal_ena and clearing lane_rst */
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CAL_ENA(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES6G_MISC_CFG);
+
+ serdes6g_write(base, addr);
+
+ /* wait 60 for calibration */
+ mdelay(60);
+
+ /* set ib_tsdet and ib_reg_pat_sel_offset back to correct values */
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CAL_ENA(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(7) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP |
+ HSIO_ANA_SERDES6G_IB_CFG1_SCALY(15) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TSDET(ib1_tsdet) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(8),
+ base + HSIO_ANA_SERDES6G_IB_CFG1);
+
+ serdes6g_write(base, addr);
+}
+
+static void serdes1g_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES1G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES1G_CFG);
+ } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_TP_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+ writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+ HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+ HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+ HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+ base + HSIO_ANA_SERDES1G_OB_CFG);
+ writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(13) |
+ HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(2) |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+ HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(3) |
+ HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+ base + HSIO_ANA_SERDES1G_IB_CFG);
+ writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+ HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+ HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES1G_DES_CFG);
+ writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES1G_MISC_CFG);
+ writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(0xc8) |
+ HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+ base + HSIO_ANA_SERDES1G_PLL_CFG);
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+
+ serdes1g_write(base, addr);
+
+ setbits_le32(base + HSIO_ANA_SERDES1G_COMMON_CFG,
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST);
+
+ serdes1g_write(base, addr);
+
+ clrbits_le32(base + HSIO_DIG_SERDES1G_MISC_CFG,
+ HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST);
+
+ serdes1g_write(base, addr);
+}
+
+static int ram_init(u32 val, void __iomem *addr)
+{
+ writel(val, addr);
+
+ if (wait_for_bit_le32(addr, BIT(1), false, 2000, false)) {
+ printf("Timeout in memory reset, reg = 0x%08x\n", val);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int jr2_switch_init(struct jr2_private *priv)
+{
+ /* Initialize memories */
+ ram_init(0x3, priv->regs[QSYS] + QSYS_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ASM] + ASM_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ANA_AC] + ANA_AC_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[REW] + REW_RAM_CTRL_RAM_INIT);
+
+ /* Reset counters */
+ writel(0x1, priv->regs[ANA_AC] + ANA_AC_STAT_GLOBAL_CFG_PORT_RESET);
+ writel(0x1, priv->regs[ASM] + ASM_CFG_STAT_CFG);
+
+ /* Enable switch-core and queue system */
+ writel(0x1, priv->regs[QSYS] + QSYS_SYSTEM_RESET_CFG);
+
+ return 0;
+}
+
+static void jr2_switch_config(struct jr2_private *priv)
+{
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(0));
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(1));
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(2));
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(3));
+
+ writel(readl(priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL) |
+ QSYS_CALCFG_CAL_CTRL_CAL_MODE(8),
+ priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL);
+}
+
+static int jr2_initialize(struct jr2_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = jr2_switch_init(priv);
+ if (ret)
+ return ret;
+
+ jr2_switch_config(priv);
+
+ for (i = 0; i < MAX_PORT; i++)
+ jr2_port_init(priv, i);
+
+ jr2_cpu_capture_setup(priv);
+
+ return 0;
+}
+
+static inline int jr2_vlant_wait_for_completion(struct jr2_private *priv)
+{
+ if (wait_for_bit_le32(priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL,
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ false, 2000, false))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int jr2_mac_table_add(struct jr2_private *priv,
+ const unsigned char mac[ETH_ALEN], int pgid)
+{
+ u32 macl = 0, mach = 0;
+
+ /*
+ * Set the MAC address to handle and the vlan associated in a format
+ * understood by the hardware.
+ */
+ mach |= MAC_VID << 16;
+ mach |= ((u32)mac[0]) << 8;
+ mach |= ((u32)mac[1]) << 0;
+ macl |= ((u32)mac[2]) << 24;
+ macl |= ((u32)mac[3]) << 16;
+ macl |= ((u32)mac[4]) << 8;
+ macl |= ((u32)mac[5]) << 0;
+
+ writel(mach, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG0);
+ writel(macl, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG1);
+
+ writel(LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(pgid) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(0x3) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(0) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED,
+ priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG2);
+
+ writel(LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL);
+
+ return jr2_vlant_wait_for_completion(priv);
+}
+
+static int jr2_write_hwaddr(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+
+ return jr2_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+}
+
+static void serdes_setup(struct jr2_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ if (priv->ports[i].serdes_index < SERDES1G_MAX) {
+ serdes1g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ } else {
+ mask >>= SERDES6G(0);
+ serdes6g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ }
+ }
+}
+
+static int jr2_start(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ const unsigned char mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = jr2_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ ret = jr2_mac_table_add(priv, mac, PGID_BROADCAST);
+ if (ret)
+ return ret;
+
+ ret = jr2_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+ if (ret)
+ return ret;
+
+ serdes_setup(priv);
+
+ return 0;
+}
+
+static void jr2_stop(struct udevice *dev)
+{
+}
+
+static int jr2_send(struct udevice *dev, void *packet, int length)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ u32 *buf = packet;
+
+ memset(ifh, '\0', IFH_LEN);
+
+ /* Set DST PORT_MASK */
+ ifh[0] = htonl(0);
+ ifh[1] = htonl(0x1FFFFF);
+ ifh[2] = htonl(~0);
+ /* Set DST_MODE to INJECT and UPDATE_FCS */
+ ifh[5] = htonl(0x4c0);
+
+ return mscc_send(priv->regs[QS], jr2_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int jr2_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt = 0;
+
+ byte_cnt = mscc_recv(priv->regs[QS], jr2_regs_qs, rxbuf, IFH_LEN,
+ false);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < JR2_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct jr2_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
+static int jr2_probe(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ int i;
+ int ret;
+ struct resource res;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
+ u32 val;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ val = readl(priv->regs[ICPU] + ICPU_RESET);
+ val |= ICPU_RESET_CORE_RST_PROTECT;
+ writel(val, priv->regs[ICPU] + ICPU_RESET);
+
+ val = readl(priv->regs[GCB] + PERF_SOFT_RST);
+ val |= PERF_SOFT_RST_SOFT_SWC_RST;
+ writel(val, priv->regs[GCB] + PERF_SOFT_RST);
+
+ while (readl(priv->regs[GCB] + PERF_SOFT_RST) & PERF_SOFT_RST_SOFT_SWC_RST)
+ ;
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(struct mscc_miim_dev) * JR2_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+ 0, 0, &phandle);
+ if (ret)
+ continue;
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+
+ addr_base = res.start;
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ mscc_mdiobus_init(miim, &miim_count, addr_base,
+ addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ return -ENOMEM;
+
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy)
+ board_phy_config(phy);
+ }
+
+ return 0;
+}
+
+static int jr2_remove(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < JR2_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops jr2_ops = {
+ .start = jr2_start,
+ .stop = jr2_stop,
+ .send = jr2_send,
+ .recv = jr2_recv,
+ .write_hwaddr = jr2_write_hwaddr,
+};
+
+static const struct udevice_id mscc_jr2_ids[] = {
+ {.compatible = "mscc,vsc7454-switch" },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(jr2) = {
+ .name = "jr2-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_jr2_ids,
+ .probe = jr2_probe,
+ .remove = jr2_remove,
+ .ops = &jr2_ops,
+ .priv_auto = sizeof(struct jr2_private),
+ .plat_auto = sizeof(struct eth_pdata),
+};
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/luton_switch.c b/roms/u-boot/drivers/net/mscc_eswitch/luton_switch.c
new file mode 100644
index 000000000..73c950d11
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/luton_switch.c
@@ -0,0 +1,739 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <malloc.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include "mscc_xfer.h"
+#include "mscc_mac_table.h"
+#include "mscc_miim.h"
+
+#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
+#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
+#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
+#define ANA_PORT_CPU_FWD_CFG(x) (0x50 + 0x80 * (x))
+#define ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA BIT(1)
+#define ANA_PORT_PORT_CFG(x) (0x60 + 0x80 * (x))
+#define ANA_PORT_PORT_CFG_RECV_ENA BIT(5)
+#define ANA_PGID(x) (0x1000 + 4 * (x))
+
+#define SYS_FRM_AGING 0x8300
+
+#define SYS_SYSTEM_RST_CFG 0x81b0
+#define SYS_SYSTEM_RST_MEM_INIT BIT(0)
+#define SYS_SYSTEM_RST_MEM_ENA BIT(1)
+#define SYS_SYSTEM_RST_CORE_ENA BIT(2)
+#define SYS_PORT_MODE(x) (0x81bc + 0x4 * (x))
+#define SYS_PORT_MODE_INCL_INJ_HDR BIT(0)
+#define SYS_SWITCH_PORT_MODE(x) (0x8294 + 0x4 * (x))
+#define SYS_SWITCH_PORT_MODE_PORT_ENA BIT(3)
+#define SYS_EGR_NO_SHARING 0x8378
+#define SYS_SCH_CPU 0x85a0
+
+#define REW_PORT_CFG(x) (0x8 + 0x80 * (x))
+#define REW_PORT_CFG_IFH_INSERT_ENA BIT(7)
+
+#define GCB_DEVCPU_RST_SOFT_CHIP_RST 0x90
+#define GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY BIT(1)
+#define GCB_MISC_STAT 0x11c
+#define GCB_MISC_STAT_PHY_READY BIT(3)
+
+#define QS_XTR_MAP(x) (0x10 + 4 * (x))
+#define QS_XTR_MAP_GRP BIT(4)
+#define QS_XTR_MAP_ENA BIT(0)
+
+#define HSIO_PLL5G_CFG_PLL5G_CFG2 0x8
+
+#define HSIO_RCOMP_CFG_CFG0 0x20
+#define HSIO_RCOMP_CFG_CFG0_MODE_SEL(x) ((x) << 8)
+#define HSIO_RCOMP_CFG_CFG0_RUN_CAL BIT(12)
+#define HSIO_RCOMP_STATUS 0x24
+#define HSIO_RCOMP_STATUS_BUSY BIT(12)
+#define HSIO_RCOMP_STATUS_RCOMP_M GENMASK(3, 0)
+#define HSIO_SERDES6G_ANA_CFG_DES_CFG 0x64
+#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x) ((x) << 1)
+#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x) ((x) << 5)
+#define HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x) ((x) << 10)
+#define HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG 0x68
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x) ((x) << 4)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x) ((x) << 7)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x) ((x) << 9)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x) ((x) << 14)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1 0x6c
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST BIT(0)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC BIT(2)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC BIT(3)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE BIT(6)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF BIT(7)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x) ((x) << 8)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG 0x70
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x) ((x) << 4)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H BIT(8)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x) ((x) << 23)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POL BIT(29)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE BIT(30)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG1 0x74
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x) (x)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x) ((x) << 6)
+#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
+#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x) (x)
+#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE BIT(18)
+#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST BIT(31)
+#define HSIO_SERDES6G_ANA_CFG_PLL_CFG 0x80
+#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA BIT(7)
+#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
+#define HSIO_SERDES6G_ANA_CFG_SER_CFG 0x84
+#define HSIO_SERDES6G_DIG_CFG_MISC_CFG 0x88
+#define HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES6G_CFG 0xac
+#define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x)
+
+#define DEV_GMII_PORT_MODE_CLK 0x0
+#define DEV_GMII_PORT_MODE_CLK_PHY_RST BIT(0)
+#define DEV_GMII_MAC_CFG_MAC_ENA 0xc
+#define DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
+#define DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
+
+#define DEV_PORT_MODE_CLK 0x4
+#define DEV_PORT_MODE_CLK_PHY_RST BIT(2)
+#define DEV_PORT_MODE_CLK_LINK_SPEED_1000 1
+#define DEV_MAC_CFG_MAC_ENA 0x10
+#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
+#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
+#define DEV_MAC_CFG_MAC_IFG 0x24
+#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
+#define DEV_PCS1G_CFG_PCS1G_CFG 0x40
+#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
+#define DEV_PCS1G_CFG_PCS1G_MODE 0x44
+#define DEV_PCS1G_CFG_PCS1G_SD 0x48
+#define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c
+#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
+
+#define IFH_INJ_BYPASS BIT(31)
+#define IFH_TAG_TYPE_C 0
+#define MAC_VID 1
+#define CPU_PORT 26
+#define INTERNAL_PORT_MSK 0xFFFFFF
+#define IFH_LEN 2
+#define ETH_ALEN 6
+#define PGID_BROADCAST 28
+#define PGID_UNICAST 29
+#define PGID_SRC 80
+
+static const char * const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+ "port8", "port9", "port10", "port11", "port12", "port13", "port14",
+ "port15", "port16", "port17", "port18", "port19", "port20", "port21",
+ "port22", "port23",
+ "sys", "ana", "rew", "gcb", "qs", "hsio",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 24
+
+enum luton_ctrl_regs {
+ SYS = MAX_PORT,
+ ANA,
+ REW,
+ GCB,
+ QS,
+ HSIO
+};
+
+#define MIN_INT_PORT 0
+#define PORT10 10
+#define PORT11 11
+#define MAX_INT_PORT 12
+#define MIN_EXT_PORT MAX_INT_PORT
+#define MAX_EXT_PORT MAX_PORT
+
+#define LUTON_MIIM_BUS_COUNT 2
+
+struct luton_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
+};
+
+struct luton_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
+ struct luton_phy_port_t ports[MAX_PORT];
+};
+
+static const unsigned long luton_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x18,
+ [MSCC_QS_XTR_FLUSH] = 0x28,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x2c,
+ [MSCC_QS_INJ_WR] = 0x3c,
+ [MSCC_QS_INJ_CTRL] = 0x44,
+};
+
+static const unsigned long luton_regs_ana_table[] = {
+ [MSCC_ANA_TABLES_MACHDATA] = 0x11b0,
+ [MSCC_ANA_TABLES_MACLDATA] = 0x11b4,
+ [MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
+};
+
+static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static void luton_stop(struct udevice *dev)
+{
+ struct luton_private *priv = dev_get_priv(dev);
+
+ /*
+ * Switch core only reset affects VCORE-III bus and MIPS frequency
+ * and thereby also the DDR SDRAM controller. The workaround is to
+ * not to redirect any trafic to the CPU after the data transfer.
+ */
+ writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
+}
+
+static void luton_cpu_capture_setup(struct luton_private *priv)
+{
+ int i;
+
+ /* map the 8 CPU extraction queues to CPU port 26 */
+ writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
+
+ for (i = 0; i <= 1; i++) {
+ /*
+ * One to one mapping from CPU Queue number to Group extraction
+ * number
+ */
+ writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
+ priv->regs[QS] + QS_XTR_MAP(i));
+
+ /* Enable IFH insertion/parsing on CPU ports */
+ setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
+ REW_PORT_CFG_IFH_INSERT_ENA);
+
+ /* Enable IFH parsing on CPU port 0 and 1 */
+ setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
+ SYS_PORT_MODE_INCL_INJ_HDR);
+ }
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
+
+ /* Disable learning (only RECV_ENA must be set) */
+ writel(ANA_PORT_PORT_CFG_RECV_ENA,
+ priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
+
+ /* Enable switching to/from cpu port */
+ setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
+ SYS_SWITCH_PORT_MODE_PORT_ENA);
+
+ setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
+}
+
+static void luton_gmii_port_init(struct luton_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ writel(0, regs + DEV_GMII_PORT_MODE_CLK);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
+ DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
+ regs + DEV_GMII_MAC_CFG_MAC_ENA);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
+
+ /* Enable switching to/from port */
+ setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
+ SYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void luton_port_init(struct luton_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ writel(0, regs + DEV_PORT_MODE_CLK);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+ DEV_MAC_CFG_MAC_ENA_TX_ENA,
+ regs + DEV_MAC_CFG_MAC_ENA);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
+
+ /* Enable switching to/from port */
+ setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
+ SYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void luton_ext_port_init(struct luton_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
+ regs + DEV_PCS1G_CFG_PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+ DEV_MAC_CFG_MAC_ENA_TX_ENA,
+ regs + DEV_MAC_CFG_MAC_ENA);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
+ regs + DEV_PCS1G_CFG_PCS1G_ANEG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
+ regs + DEV_MAC_CFG_MAC_IFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
+ regs + DEV_PORT_MODE_CLK);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
+
+ /* Enable switching to/from port */
+ setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
+ SYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes6g_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES6G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES6G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES6G_CFG);
+ } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes6g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
+ HSIO_RCOMP_CFG_CFG0_RUN_CAL,
+ base + HSIO_RCOMP_CFG_CFG0);
+
+ while (readl(base + HSIO_RCOMP_STATUS) &
+ HSIO_RCOMP_STATUS_BUSY)
+ ;
+
+ writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
+ HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
+ HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
+ HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
+ HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
+ base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
+ writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
+ HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
+ base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
+ writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
+ base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
+ writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
+ HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
+ base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
+ writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
+ HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
+ HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
+ HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
+ base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
+ writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
+ HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
+ base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
+ writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
+ HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
+ base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+ /*
+ * There are 4 serdes6g, configure all except serdes6g0, therefore
+ * the address is b1110
+ */
+ serdes6g_write(base, addr);
+
+ writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
+ HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
+ base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+ serdes6g_write(base, addr);
+
+ clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
+ HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
+ writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
+ base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
+ serdes6g_write(base, addr);
+}
+
+static void serdes_setup(struct luton_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
+ }
+}
+
+static int luton_switch_init(struct luton_private *priv)
+{
+ setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
+ clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
+
+ /* Reset switch & memories */
+ writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
+ priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
+
+ /* Wait to complete */
+ if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
+ printf("Timeout in memory reset\n");
+ }
+
+ /* Enable switch core */
+ setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_CORE_ENA);
+
+ /* Setup the Serdes macros */
+ serdes_setup(priv);
+
+ return 0;
+}
+
+static int luton_initialize(struct luton_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = luton_switch_init(priv);
+ if (ret)
+ return ret;
+
+ /*
+ * Disable port-to-port by switching
+ * Put front ports in "port isolation modes" - i.e. they can't send
+ * to other ports - via the PGID sorce masks.
+ */
+ for (i = 0; i < MAX_PORT; i++)
+ writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
+
+ /* Flush queues */
+ mscc_flush(priv->regs[QS], luton_regs_qs);
+
+ /* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
+ writel(2000000000 / 4,
+ priv->regs[SYS] + SYS_FRM_AGING);
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (i < PORT10)
+ luton_gmii_port_init(priv, i);
+ else
+ if (i == PORT10 || i == PORT11)
+ luton_port_init(priv, i);
+ else
+ luton_ext_port_init(priv, i);
+ }
+
+ luton_cpu_capture_setup(priv);
+
+ return 0;
+}
+
+static int luton_write_hwaddr(struct udevice *dev)
+{
+ struct luton_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+
+ mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+ return 0;
+}
+
+static int luton_start(struct udevice *dev)
+{
+ struct luton_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = luton_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
+ mac, PGID_BROADCAST);
+
+ writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
+ priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
+
+ mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+ return 0;
+}
+
+static int luton_send(struct udevice *dev, void *packet, int length)
+{
+ struct luton_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ int port = BIT(0); /* use port 0 */
+ u32 *buf = packet;
+
+ ifh[0] = IFH_INJ_BYPASS | port;
+ ifh[1] = (IFH_TAG_TYPE_C << 16);
+
+ return mscc_send(priv->regs[QS], luton_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct luton_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt = 0;
+
+ byte_cnt = mscc_recv(priv->regs[QS], luton_regs_qs, rxbuf, IFH_LEN,
+ true);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct luton_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
+static int luton_probe(struct udevice *dev)
+{
+ struct luton_private *priv = dev_get_priv(dev);
+ int i, ret;
+ struct resource res;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ /* Release reset in the CU-PHY */
+ writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
+
+ /* Ports with ext phy don't need to reset clk */
+ for (i = 0; i < MAX_INT_PORT; i++) {
+ if (i < PORT10)
+ clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
+ DEV_GMII_PORT_MODE_CLK_PHY_RST);
+ else
+ clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK,
+ DEV_PORT_MODE_CLK_PHY_RST);
+ }
+
+ /* Wait for internal PHY to be ready */
+ if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT,
+ GCB_MISC_STAT_PHY_READY, true, 500, false))
+ return -EACCES;
+
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+ 0, 0, &phandle);
+ if (ret)
+ continue;
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+ addr_base = res.start;
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ mscc_mdiobus_init(miim, &miim_count, addr_base,
+ addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
+ else
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy && i >= MAX_INT_PORT)
+ board_phy_config(phy);
+ }
+
+ /*
+ * coma_mode is need on only one phy, because all the other phys
+ * will be affected.
+ */
+ mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
+ mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
+ mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
+
+ return 0;
+}
+
+static int luton_remove(struct udevice *dev)
+{
+ struct luton_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops luton_ops = {
+ .start = luton_start,
+ .stop = luton_stop,
+ .send = luton_send,
+ .recv = luton_recv,
+ .write_hwaddr = luton_write_hwaddr,
+};
+
+static const struct udevice_id mscc_luton_ids[] = {
+ {.compatible = "mscc,vsc7527-switch", },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(luton) = {
+ .name = "luton-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_luton_ids,
+ .probe = luton_probe,
+ .remove = luton_remove,
+ .ops = &luton_ops,
+ .priv_auto = sizeof(struct luton_private),
+ .plat_auto = sizeof(struct eth_pdata),
+};
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.c b/roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.c
new file mode 100644
index 000000000..25b9cad42
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include "mscc_mac_table.h"
+
+#define ANA_TABLES_MACACCESS_VALID BIT(11)
+#define ANA_TABLES_MACACCESS_ENTRYTYPE(x) ((x) << 9)
+#define ANA_TABLES_MACACCESS_DEST_IDX(x) ((x) << 3)
+#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x) (x)
+#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M GENMASK(2, 0)
+#define MACACCESS_CMD_IDLE 0
+#define MACACCESS_CMD_LEARN 1
+
+/* MAC table entry types.
+ * ENTRYTYPE_NORMAL is subject to aging.
+ * ENTRYTYPE_LOCKED is not subject to aging.
+ */
+enum macaccess_entry_type {
+ ENTRYTYPE_NORMAL = 0,
+ ENTRYTYPE_LOCKED,
+};
+
+static int vlan_wait_for_completion(void __iomem *regs,
+ const unsigned long *mscc_mac_table_offset)
+{
+ unsigned int val, timeout = 10;
+
+ /* Wait for the issued mac table command to be completed, or timeout.
+ * When the command read from ANA_TABLES_MACACCESS is
+ * MACACCESS_CMD_IDLE, the issued command completed successfully.
+ */
+ do {
+ val = readl(regs +
+ mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]);
+ val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
+ } while (val != MACACCESS_CMD_IDLE && timeout--);
+
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+int mscc_mac_table_add(void __iomem *regs,
+ const unsigned long *mscc_mac_table_offset,
+ const unsigned char mac[ETH_LEN], int pgid)
+{
+ u32 macl = 0, mach = 0;
+
+ /* Set the MAC address to handle and the vlan associated in a format
+ * understood by the hardware.
+ */
+ mach |= MAC_VID << 16;
+ mach |= ((u32)mac[0]) << 8;
+ mach |= ((u32)mac[1]) << 0;
+ macl |= ((u32)mac[2]) << 24;
+ macl |= ((u32)mac[3]) << 16;
+ macl |= ((u32)mac[4]) << 8;
+ macl |= ((u32)mac[5]) << 0;
+
+ writel(macl, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACLDATA]);
+ writel(mach, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACHDATA]);
+
+ writel(ANA_TABLES_MACACCESS_VALID |
+ ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
+ ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
+ regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]);
+
+ return vlan_wait_for_completion(regs, mscc_mac_table_offset);
+}
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.h b/roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.h
new file mode 100644
index 000000000..17fed2e79
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/mscc_mac_table.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+
+#define ETH_LEN 6
+#define MAC_VID 1
+
+enum mscc_regs_ana_table {
+ MSCC_ANA_TABLES_MACHDATA,
+ MSCC_ANA_TABLES_MACLDATA,
+ MSCC_ANA_TABLES_MACACCESS,
+};
+
+int mscc_mac_table_add(void __iomem *regs,
+ const unsigned long *mscc_mac_table_offset,
+ const unsigned char mac[ETH_LEN], int pgid);
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.c b/roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.c
new file mode 100644
index 000000000..6687787b1
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <miiphy.h>
+#include <wait_bit.h>
+#include <linux/bitops.h>
+#include "mscc_miim.h"
+
+#define MIIM_STATUS 0x0
+#define MIIM_STAT_BUSY BIT(3)
+#define MIIM_CMD 0x8
+#define MIIM_CMD_SCAN BIT(0)
+#define MIIM_CMD_OPR_WRITE BIT(1)
+#define MIIM_CMD_OPR_READ BIT(2)
+#define MIIM_CMD_SINGLE_SCAN BIT(3)
+#define MIIM_CMD_WRDATA(x) ((x) << 4)
+#define MIIM_CMD_REGAD(x) ((x) << 20)
+#define MIIM_CMD_PHYAD(x) ((x) << 25)
+#define MIIM_CMD_VLD BIT(31)
+#define MIIM_DATA 0xC
+#define MIIM_DATA_ERROR (0x2 << 16)
+
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+ return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY,
+ false, 250, false);
+}
+
+int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ u32 val;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
+ MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
+ miim->regs + MIIM_CMD);
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ val = readl(miim->regs + MIIM_DATA);
+ if (val & MIIM_DATA_ERROR) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = val & 0xFFFF;
+ out:
+ return ret;
+}
+
+int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret < 0)
+ goto out;
+
+ writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
+ MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
+ MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
+ out:
+ return ret;
+}
+
+struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count,
+ phys_addr_t miim_base,
+ unsigned long miim_size)
+{
+ struct mii_dev *bus;
+
+ bus = mdio_alloc();
+
+ if (!bus)
+ return NULL;
+
+ *miim_count += 1;
+ sprintf(bus->name, "miim-bus%d", *miim_count);
+
+ miim[*miim_count].regs = ioremap(miim_base, miim_size);
+ miim[*miim_count].miim_base = miim_base;
+ miim[*miim_count].miim_size = miim_size;
+ bus->priv = &miim[*miim_count];
+ bus->read = mscc_miim_read;
+ bus->write = mscc_miim_write;
+
+ if (mdio_register(bus))
+ return NULL;
+
+ miim[*miim_count].bus = bus;
+ return bus;
+}
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.h b/roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.h
new file mode 100644
index 000000000..feb1f40ae
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/mscc_miim.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_MIIM_H_
+#define _MSCC_MIIM_H_
+
+struct mscc_miim_dev {
+ void __iomem *regs;
+ phys_addr_t miim_base;
+ unsigned long miim_size;
+ struct mii_dev *bus;
+};
+
+int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg);
+int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val);
+
+struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count,
+ phys_addr_t miim_base,
+ unsigned long miim_size);
+
+
+#endif /* _MSCC_MIIM_H_ */
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.c b/roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.c
new file mode 100644
index 000000000..6f7474645
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <log.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include "mscc_xfer.h"
+
+#define QS_XTR_FLUSH_FLUSH GENMASK(1, 0)
+#define QS_INJ_CTRL_GAP_SIZE(x) ((x) << 21)
+#define QS_INJ_CTRL_EOF BIT(19)
+#define QS_INJ_CTRL_SOF BIT(18)
+#define QS_INJ_CTRL_VLD_BYTES(x) ((x) << 16)
+
+#define XTR_EOF_0 ntohl(0x80000000u)
+#define XTR_EOF_1 ntohl(0x80000001u)
+#define XTR_EOF_2 ntohl(0x80000002u)
+#define XTR_EOF_3 ntohl(0x80000003u)
+#define XTR_PRUNED ntohl(0x80000004u)
+#define XTR_ABORT ntohl(0x80000005u)
+#define XTR_ESCAPE ntohl(0x80000006u)
+#define XTR_NOT_READY ntohl(0x80000007u)
+
+#define BUF_CELL_SZ 60
+#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
+
+int mscc_send(void __iomem *regs, const unsigned long *mscc_qs_offset,
+ u32 *ifh, size_t ifh_len, u32 *buff, size_t buff_len)
+{
+ int i, count = (buff_len + 3) / 4, last = buff_len % 4;
+
+ writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
+ regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
+
+ for (i = 0; i < ifh_len; i++)
+ writel(ifh[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
+
+ for (i = 0; i < count; i++)
+ writel(buff[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
+
+ /* Add padding */
+ while (i < (BUF_CELL_SZ / 4)) {
+ writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
+ i++;
+ }
+
+ /* Indicate EOF and valid bytes in last word */
+ writel(QS_INJ_CTRL_GAP_SIZE(1) |
+ QS_INJ_CTRL_VLD_BYTES(buff_len < BUF_CELL_SZ ? 0 : last) |
+ QS_INJ_CTRL_EOF, regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
+
+ /* Add dummy CRC */
+ writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
+
+ return 0;
+}
+
+int mscc_recv(void __iomem *regs, const unsigned long *mscc_qs_offset,
+ u32 *rxbuf, size_t ifh_len, bool byte_swap)
+{
+ u8 grp = 0; /* Recv everything on CPU group 0 */
+ int i, byte_cnt = 0;
+ bool eof_flag = false, pruned_flag = false, abort_flag = false;
+
+ if (!(readl(regs + mscc_qs_offset[MSCC_QS_XTR_DATA_PRESENT]) &
+ BIT(grp)))
+ return -EAGAIN;
+
+ /* skip IFH */
+ for (i = 0; i < ifh_len; i++)
+ readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
+
+ while (!eof_flag) {
+ u32 val = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
+ u32 cmp = val;
+
+ if (byte_swap)
+ cmp = ntohl(val);
+
+ switch (cmp) {
+ case XTR_NOT_READY:
+ debug("%d NOT_READY...?\n", byte_cnt);
+ break;
+ case XTR_ABORT:
+ *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
+ abort_flag = true;
+ eof_flag = true;
+ debug("XTR_ABORT\n");
+ break;
+ case XTR_EOF_0:
+ case XTR_EOF_1:
+ case XTR_EOF_2:
+ case XTR_EOF_3:
+ byte_cnt += XTR_VALID_BYTES(val);
+ *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
+ eof_flag = true;
+ debug("EOF\n");
+ break;
+ case XTR_PRUNED:
+ /* But get the last 4 bytes as well */
+ eof_flag = true;
+ pruned_flag = true;
+ debug("PRUNED\n");
+ /* fallthrough */
+ case XTR_ESCAPE:
+ *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
+ byte_cnt += 4;
+ rxbuf++;
+ debug("ESCAPED\n");
+ break;
+ default:
+ *rxbuf = val;
+ byte_cnt += 4;
+ rxbuf++;
+ }
+ }
+
+ if (abort_flag || pruned_flag || !eof_flag) {
+ debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
+ abort_flag, pruned_flag, eof_flag);
+ return -EAGAIN;
+ }
+
+ return byte_cnt;
+}
+
+void mscc_flush(void __iomem *regs, const unsigned long *mscc_qs_offset)
+{
+ /* All Queues flush */
+ setbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
+ QS_XTR_FLUSH_FLUSH);
+
+ /* Allow to drain */
+ mdelay(1);
+
+ /* All Queues normal */
+ clrbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
+ QS_XTR_FLUSH_FLUSH);
+}
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.h b/roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.h
new file mode 100644
index 000000000..c880a4e7e
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/mscc_xfer.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+
+enum mscc_regs_qs {
+ MSCC_QS_XTR_RD,
+ MSCC_QS_XTR_FLUSH,
+ MSCC_QS_XTR_DATA_PRESENT,
+ MSCC_QS_INJ_WR,
+ MSCC_QS_INJ_CTRL,
+};
+
+int mscc_send(void __iomem *regs, const unsigned long *mscc_qs_offset,
+ u32 *ifh, size_t ifh_len, u32 *buff, size_t buff_len);
+int mscc_recv(void __iomem *regs, const unsigned long *mscc_qs_offset,
+ u32 *rxbuf, size_t ifh_len, bool byte_swap);
+void mscc_flush(void __iomem *regs, const unsigned long *mscc_qs_offset);
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/ocelot_switch.c b/roms/u-boot/drivers/net/mscc_eswitch/ocelot_switch.c
new file mode 100644
index 000000000..d1d0a489a
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/ocelot_switch.c
@@ -0,0 +1,654 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include "mscc_xfer.h"
+#include "mscc_mac_table.h"
+#include "mscc_miim.h"
+
+#define PHY_CFG 0x0
+#define PHY_CFG_ENA 0xF
+#define PHY_CFG_COMMON_RST BIT(4)
+#define PHY_CFG_RST (0xF << 5)
+#define PHY_STAT 0x4
+#define PHY_STAT_SUPERVISOR_COMPLETE BIT(0)
+
+#define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x))
+#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
+#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
+#define ANA_PORT_PORT_CFG(x) (0x7070 + 0x100 * (x))
+#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
+#define ANA_PGID(x) (0x8c00 + 4 * (x))
+
+#define HSIO_ANA_SERDES1G_DES_CFG 0x4c
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
+#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG 0x50
+#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
+#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG 0x54
+#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
+#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG 0x58
+#define HSIO_ANA_SERDES1G_COMMON_CFG 0x5c
+#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG 0x60
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0 0x68
+#define HSIO_DIG_SERDES1G_MISC_CFG 0x7c
+#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES1G_CFG 0x88
+#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
+#define HSIO_HW_CFGSTAT_HW_CFG 0x10c
+
+#define SYS_FRM_AGING 0x574
+#define SYS_FRM_AGING_ENA BIT(20)
+
+#define SYS_SYSTEM_RST_CFG 0x508
+#define SYS_SYSTEM_RST_MEM_INIT BIT(0)
+#define SYS_SYSTEM_RST_MEM_ENA BIT(1)
+#define SYS_SYSTEM_RST_CORE_ENA BIT(2)
+#define SYS_PORT_MODE(x) (0x514 + 0x4 * (x))
+#define SYS_PORT_MODE_INCL_INJ_HDR(x) ((x) << 3)
+#define SYS_PORT_MODE_INCL_INJ_HDR_M GENMASK(4, 3)
+#define SYS_PORT_MODE_INCL_XTR_HDR(x) ((x) << 1)
+#define SYS_PORT_MODE_INCL_XTR_HDR_M GENMASK(2, 1)
+#define SYS_PAUSE_CFG(x) (0x608 + 0x4 * (x))
+#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0)
+
+#define QSYS_SWITCH_PORT_MODE(x) (0x11234 + 0x4 * (x))
+#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(14)
+#define QSYS_QMAP 0x112d8
+#define QSYS_EGR_NO_SHARING 0x1129c
+
+/* Port registers */
+#define DEV_CLOCK_CFG 0x0
+#define DEV_CLOCK_CFG_LINK_SPEED_1000 1
+#define DEV_MAC_ENA_CFG 0x1c
+#define DEV_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV_MAC_ENA_CFG_TX_ENA BIT(0)
+
+#define DEV_MAC_IFG_CFG 0x30
+#define DEV_MAC_IFG_CFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_IFG_CFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_IFG_CFG_RX_IFG1(x) (x)
+
+#define PCS1G_CFG 0x48
+#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
+#define PCS1G_MODE_CFG 0x4c
+#define PCS1G_MODE_CFG_UNIDIR_MODE_ENA BIT(4)
+#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
+#define PCS1G_SD_CFG 0x50
+#define PCS1G_ANEG_CFG 0x54
+#define PCS1G_ANEG_CFG_ADV_ABILITY(x) ((x) << 16)
+
+#define QS_XTR_GRP_CFG(x) (4 * (x))
+#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2)
+#define QS_XTR_GRP_CFG_STATUS_WORD_POS BIT(1)
+#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0)
+#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
+#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2)
+#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
+
+#define IFH_INJ_BYPASS BIT(31)
+#define IFH_TAG_TYPE_C 0
+#define MAC_VID 1
+#define CPU_PORT 11
+#define INTERNAL_PORT_MSK 0x2FF
+#define IFH_LEN 4
+#define ETH_ALEN 6
+#define PGID_BROADCAST 13
+#define PGID_UNICAST 14
+#define PGID_SRC 80
+
+static const char * const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+ "port8", "port9", "port10", "sys", "rew", "qs", "hsio", "qsys", "ana",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 11
+
+enum ocelot_ctrl_regs {
+ SYS = MAX_PORT,
+ REW,
+ QS,
+ HSIO,
+ QSYS,
+ ANA,
+};
+
+#define OCELOT_MIIM_BUS_COUNT 2
+
+struct ocelot_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
+};
+
+struct ocelot_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[OCELOT_MIIM_BUS_COUNT];
+ struct ocelot_phy_port_t ports[MAX_PORT];
+};
+
+static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static const unsigned long ocelot_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x8,
+ [MSCC_QS_XTR_FLUSH] = 0x18,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+ [MSCC_QS_INJ_WR] = 0x2c,
+ [MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static const unsigned long ocelot_regs_ana_table[] = {
+ [MSCC_ANA_TABLES_MACHDATA] = 0x8b34,
+ [MSCC_ANA_TABLES_MACLDATA] = 0x8b38,
+ [MSCC_ANA_TABLES_MACACCESS] = 0x8b3c,
+};
+
+static void mscc_phy_reset(void)
+{
+ writel(0, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
+ writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
+ | PHY_CFG_ENA, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
+ if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + PERF_PHY_CFG) +
+ PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE,
+ true, 2000, false)) {
+ pr_err("Timeout in phy reset\n");
+ }
+}
+
+__weak void mscc_switch_reset(void)
+{
+}
+
+static void ocelot_stop(struct udevice *dev)
+{
+ mscc_switch_reset();
+ mscc_phy_reset();
+}
+
+static void ocelot_cpu_capture_setup(struct ocelot_private *priv)
+{
+ int i;
+
+ /* map the 8 CPU extraction queues to CPU port 11 */
+ writel(0, priv->regs[QSYS] + QSYS_QMAP);
+
+ for (i = 0; i <= 1; i++) {
+ /*
+ * Do byte-swap and expect status after last data word
+ * Extraction: Mode: manual extraction) | Byte_swap
+ */
+ writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
+ priv->regs[QS] + QS_XTR_GRP_CFG(i));
+ /*
+ * Injection: Mode: manual extraction | Byte_swap
+ */
+ writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
+ priv->regs[QS] + QS_INJ_GRP_CFG(i));
+ }
+
+ for (i = 0; i <= 1; i++)
+ /* Enable IFH insertion/parsing on CPU ports */
+ writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
+ SYS_PORT_MODE_INCL_XTR_HDR(1),
+ priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
+ /*
+ * Setup the CPU port as VLAN aware to support switching frames
+ * based on tags
+ */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
+
+ /* Disable learning (only RECV_ENA must be set) */
+ writel(ANA_PORT_PORT_CFG_RECV_ENA,
+ priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
+
+ /* Enable switching to/from cpu port */
+ setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
+ QSYS_SWITCH_PORT_MODE_PORT_ENA);
+
+ /* No pause on CPU port - not needed (off by default) */
+ clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
+ SYS_PAUSE_CFG_PAUSE_ENA);
+
+ setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
+}
+
+static void ocelot_port_init(struct ocelot_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + PCS1G_SD_CFG);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
+ regs + DEV_MAC_ENA_CFG);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + PCS1G_MODE_CFG);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
+ DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
+
+ /* Enable the port in the core */
+ setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
+ QSYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes1g_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES1G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES1G_CFG);
+ } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ writel(0x34, base + HSIO_HW_CFGSTAT_HW_CFG);
+
+ writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+ writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
+ HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+ HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+ base + HSIO_ANA_SERDES1G_IB_CFG);
+ writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+ HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+ HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES1G_DES_CFG);
+ writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+ HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+ HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+ HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+ base + HSIO_ANA_SERDES1G_OB_CFG);
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
+ HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+ base + HSIO_ANA_SERDES1G_PLL_CFG);
+ writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES1G_MISC_CFG);
+
+ serdes1g_write(base, addr);
+
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ serdes1g_write(base, addr);
+
+ writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
+ serdes1g_write(base, addr);
+}
+
+static void serdes_setup(struct ocelot_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ serdes1g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ }
+}
+
+static int ocelot_switch_init(struct ocelot_private *priv)
+{
+ /* Reset switch & memories */
+ writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
+ priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
+
+ /* Wait to complete */
+ if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
+ pr_err("Timeout in memory reset\n");
+ return -EIO;
+ }
+
+ /* Enable switch core */
+ setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_CORE_ENA);
+
+ serdes_setup(priv);
+ return 0;
+}
+
+static int ocelot_initialize(struct ocelot_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = ocelot_switch_init(priv);
+ if (ret)
+ return ret;
+ /*
+ * Disable port-to-port by switching
+ * Put fron ports in "port isolation modes" - i.e. they cant send
+ * to other ports - via the PGID sorce masks.
+ */
+ for (i = 0; i < MAX_PORT; i++)
+ writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
+
+ /* Flush queues */
+ mscc_flush(priv->regs[QS], ocelot_regs_qs);
+
+ /* Setup frame ageing - "2 sec" - The unit is 6.5us on Ocelot */
+ writel(SYS_FRM_AGING_ENA | (20000000 / 65),
+ priv->regs[SYS] + SYS_FRM_AGING);
+
+ for (i = 0; i < MAX_PORT; i++)
+ ocelot_port_init(priv, i);
+
+ ocelot_cpu_capture_setup(priv);
+
+ debug("Ports enabled\n");
+
+ return 0;
+}
+
+static int ocelot_write_hwaddr(struct udevice *dev)
+{
+ struct ocelot_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+
+ mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+ return 0;
+}
+
+static int ocelot_start(struct udevice *dev)
+{
+ struct ocelot_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = ocelot_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table, mac,
+ PGID_BROADCAST);
+
+ writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
+ priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
+
+ /* It should be setup latter in ocelot_write_hwaddr */
+ mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+ return 0;
+}
+
+static int ocelot_send(struct udevice *dev, void *packet, int length)
+{
+ struct ocelot_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ int port = BIT(0); /* use port 0 */
+ u32 *buf = packet;
+
+ /*
+ * Generate the IFH for frame injection
+ *
+ * The IFH is a 128bit-value
+ * bit 127: bypass the analyzer processing
+ * bit 56-67: destination mask
+ * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
+ * bit 20-27: cpu extraction queue mask
+ * bit 16: tag type 0: C-tag, 1: S-tag
+ * bit 0-11: VID
+ */
+ ifh[0] = IFH_INJ_BYPASS;
+ ifh[1] = (0xf00 & port) >> 8;
+ ifh[2] = (0xff & port) << 24;
+ ifh[3] = (IFH_TAG_TYPE_C << 16);
+
+ return mscc_send(priv->regs[QS], ocelot_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct ocelot_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt;
+
+ byte_cnt = mscc_recv(priv->regs[QS], ocelot_regs_qs, rxbuf, IFH_LEN,
+ false);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < OCELOT_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct ocelot_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
+static int external_bus(struct ocelot_private *priv, size_t port_index)
+{
+ return priv->ports[port_index].serdes_index != 0xff;
+}
+
+static int ocelot_probe(struct udevice *dev)
+{
+ struct ocelot_private *priv = dev_get_priv(dev);
+ int i, ret;
+ struct resource res;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
+
+ if (!priv)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(struct mscc_miim_dev) *
+ OCELOT_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node); ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
+ &phandle);
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+
+ addr_base = res.start;
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ mscc_mdiobus_init(miim, &miim_count, addr_base,
+ addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
+ else
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
+ mscc_phy_reset();
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy && external_bus(priv, i))
+ board_phy_config(phy);
+ }
+
+ return 0;
+}
+
+static int ocelot_remove(struct udevice *dev)
+{
+ struct ocelot_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < OCELOT_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops ocelot_ops = {
+ .start = ocelot_start,
+ .stop = ocelot_stop,
+ .send = ocelot_send,
+ .recv = ocelot_recv,
+ .write_hwaddr = ocelot_write_hwaddr,
+};
+
+static const struct udevice_id mscc_ocelot_ids[] = {
+ {.compatible = "mscc,vsc7514-switch"},
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(ocelot) = {
+ .name = "ocelot-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_ocelot_ids,
+ .probe = ocelot_probe,
+ .remove = ocelot_remove,
+ .ops = &ocelot_ops,
+ .priv_auto = sizeof(struct ocelot_private),
+ .plat_auto = sizeof(struct eth_pdata),
+};
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/serval_switch.c b/roms/u-boot/drivers/net/mscc_eswitch/serval_switch.c
new file mode 100644
index 000000000..c4b81f752
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/serval_switch.c
@@ -0,0 +1,607 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include "mscc_xfer.h"
+#include "mscc_mac_table.h"
+#include "mscc_miim.h"
+
+#define ANA_PORT_VLAN_CFG(x) (0xc000 + 0x100 * (x))
+#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
+#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
+#define ANA_PORT_PORT_CFG(x) (0xc070 + 0x100 * (x))
+#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
+#define ANA_PGID(x) (0x9c00 + 4 * (x))
+
+#define HSIO_ANA_SERDES1G_DES_CFG 0x3c
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
+#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG 0x40
+#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
+#define HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x) ((x) << 19)
+#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG 0x44
+#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
+#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG 0x48
+#define HSIO_ANA_SERDES1G_COMMON_CFG 0x4c
+#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG 0x50
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0 0x58
+#define HSIO_DIG_SERDES1G_MISC_CFG 0x6c
+#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES1G_CFG 0x74
+#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
+
+#define SYS_FRM_AGING 0x584
+#define SYS_FRM_AGING_ENA BIT(20)
+#define SYS_SYSTEM_RST_CFG 0x518
+#define SYS_SYSTEM_RST_MEM_INIT BIT(5)
+#define SYS_SYSTEM_RST_MEM_ENA BIT(6)
+#define SYS_SYSTEM_RST_CORE_ENA BIT(7)
+#define SYS_PORT_MODE(x) (0x524 + 0x4 * (x))
+#define SYS_PORT_MODE_INCL_INJ_HDR(x) ((x) << 4)
+#define SYS_PORT_MODE_INCL_XTR_HDR(x) ((x) << 2)
+#define SYS_PAUSE_CFG(x) (0x65c + 0x4 * (x))
+#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0)
+
+#define QSYS_SWITCH_PORT_MODE(x) (0x15a34 + 0x4 * (x))
+#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(13)
+#define QSYS_EGR_NO_SHARING 0x15a9c
+#define QSYS_QMAP 0x15adc
+
+/* Port registers */
+#define DEV_CLOCK_CFG 0x0
+#define DEV_CLOCK_CFG_LINK_SPEED_1000 1
+#define DEV_MAC_ENA_CFG 0x10
+#define DEV_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV_MAC_ENA_CFG_TX_ENA BIT(0)
+#define DEV_MAC_IFG_CFG 0x24
+#define DEV_MAC_IFG_CFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_IFG_CFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_IFG_CFG_RX_IFG1(x) (x)
+#define PCS1G_CFG 0x3c
+#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
+#define PCS1G_MODE_CFG 0x40
+#define PCS1G_SD_CFG 0x44
+#define PCS1G_ANEG_CFG 0x48
+#define PCS1G_ANEG_CFG_ADV_ABILITY(x) ((x) << 16)
+
+#define QS_XTR_GRP_CFG(x) (4 * (x))
+#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2)
+#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0)
+#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
+#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2)
+#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
+
+#define IFH_INJ_BYPASS BIT(31)
+#define IFH_TAG_TYPE_C 0
+#define MAC_VID 1
+#define CPU_PORT 11
+#define INTERNAL_PORT_MSK 0xFF
+#define IFH_LEN 4
+#define ETH_ALEN 6
+#define PGID_BROADCAST 13
+#define PGID_UNICAST 14
+
+static const char *const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6",
+ "port7", "port8", "port9", "port10",
+ "ana", "qs", "qsys", "rew", "sys", "hsio",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 11
+
+enum serval_ctrl_regs {
+ ANA = MAX_PORT,
+ QS,
+ QSYS,
+ REW,
+ SYS,
+ HSIO,
+};
+
+#define SERVAL_MIIM_BUS_COUNT 2
+
+struct serval_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
+};
+
+struct serval_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[SERVAL_MIIM_BUS_COUNT];
+ struct serval_phy_port_t ports[MAX_PORT];
+};
+
+static const unsigned long serval_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x8,
+ [MSCC_QS_XTR_FLUSH] = 0x18,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+ [MSCC_QS_INJ_WR] = 0x2c,
+ [MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static const unsigned long serval_regs_ana_table[] = {
+ [MSCC_ANA_TABLES_MACHDATA] = 0x9b34,
+ [MSCC_ANA_TABLES_MACLDATA] = 0x9b38,
+ [MSCC_ANA_TABLES_MACACCESS] = 0x9b3c,
+};
+
+static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static void serval_cpu_capture_setup(struct serval_private *priv)
+{
+ int i;
+
+ /* map the 8 CPU extraction queues to CPU port 11 */
+ writel(0, priv->regs[QSYS] + QSYS_QMAP);
+
+ for (i = 0; i <= 1; i++) {
+ /*
+ * Do byte-swap and expect status after last data word
+ * Extraction: Mode: manual extraction) | Byte_swap
+ */
+ writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
+ priv->regs[QS] + QS_XTR_GRP_CFG(i));
+ /*
+ * Injection: Mode: manual extraction | Byte_swap
+ */
+ writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
+ priv->regs[QS] + QS_INJ_GRP_CFG(i));
+ }
+
+ for (i = 0; i <= 1; i++)
+ /* Enable IFH insertion/parsing on CPU ports */
+ writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
+ SYS_PORT_MODE_INCL_XTR_HDR(1),
+ priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
+ /*
+ * Setup the CPU port as VLAN aware to support switching frames
+ * based on tags
+ */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
+
+ /* Disable learning (only RECV_ENA must be set) */
+ writel(ANA_PORT_PORT_CFG_RECV_ENA,
+ priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
+
+ /* Enable switching to/from cpu port */
+ setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
+ QSYS_SWITCH_PORT_MODE_PORT_ENA);
+
+ /* No pause on CPU port - not needed (off by default) */
+ clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
+ SYS_PAUSE_CFG_PAUSE_ENA);
+
+ setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
+}
+
+static void serval_port_init(struct serval_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + PCS1G_SD_CFG);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
+ regs + DEV_MAC_ENA_CFG);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + PCS1G_MODE_CFG);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
+ DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
+
+ /* Enable the port in the core */
+ setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
+ QSYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES1G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES1G_CFG);
+ } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+ writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
+ HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+ HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+ base + HSIO_ANA_SERDES1G_IB_CFG);
+ writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+ HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+ HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES1G_DES_CFG);
+ writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+ HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+ HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+ HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+ base + HSIO_ANA_SERDES1G_OB_CFG);
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
+ HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+ base + HSIO_ANA_SERDES1G_PLL_CFG);
+ writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES1G_MISC_CFG);
+ serdes_write(base, addr);
+
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ serdes_write(base, addr);
+
+ writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
+ serdes_write(base, addr);
+}
+
+static void serdes_setup(struct serval_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ serdes1g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ }
+}
+
+static int serval_switch_init(struct serval_private *priv)
+{
+ /* Reset switch & memories */
+ writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
+ priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
+
+ if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
+ pr_err("Timeout in memory reset\n");
+ return -EIO;
+ }
+
+ /* Enable switch core */
+ setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_CORE_ENA);
+
+ serdes_setup(priv);
+
+ return 0;
+}
+
+static int serval_initialize(struct serval_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = serval_switch_init(priv);
+ if (ret)
+ return ret;
+
+ /* Flush queues */
+ mscc_flush(priv->regs[QS], serval_regs_qs);
+
+ /* Setup frame ageing - "2 sec" - The unit is 6.5us on serval */
+ writel(SYS_FRM_AGING_ENA | (20000000 / 65),
+ priv->regs[SYS] + SYS_FRM_AGING);
+
+ for (i = 0; i < MAX_PORT; i++)
+ serval_port_init(priv, i);
+
+ serval_cpu_capture_setup(priv);
+
+ debug("Ports enabled\n");
+
+ return 0;
+}
+
+static int serval_write_hwaddr(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+
+ mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+ return 0;
+}
+
+static int serval_start(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = serval_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, mac,
+ PGID_BROADCAST);
+
+ writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
+ priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
+
+ /* It should be setup latter in serval_write_hwaddr */
+ mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+ return 0;
+}
+
+static void serval_stop(struct udevice *dev)
+{
+ writel(ICPU_RESET_CORE_RST_PROTECT, BASE_CFG + ICPU_RESET);
+ writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST);
+}
+
+static int serval_send(struct udevice *dev, void *packet, int length)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ u32 *buf = packet;
+
+ /*
+ * Generate the IFH for frame injection
+ *
+ * The IFH is a 128bit-value
+ * bit 127: bypass the analyzer processing
+ * bit 57-67: destination mask
+ * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
+ * bit 20-27: cpu extraction queue mask
+ * bit 16: tag type 0: C-tag, 1: S-tag
+ * bit 0-11: VID
+ */
+ ifh[0] = IFH_INJ_BYPASS;
+ ifh[1] = (0x07);
+ ifh[2] = (0x7f) << 25;
+ ifh[3] = (IFH_TAG_TYPE_C << 16);
+
+ return mscc_send(priv->regs[QS], serval_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int serval_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt = 0;
+
+ byte_cnt = mscc_recv(priv->regs[QS], serval_regs_qs, rxbuf, IFH_LEN,
+ false);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < SERVAL_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct serval_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
+static int serval_probe(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ int i, ret;
+ struct resource res;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(miim) * SERVAL_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+ 0, 0, &phandle);
+ if (ret)
+ continue;
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+
+ addr_base = res.start;
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ mscc_mdiobus_init(miim, &miim_count, addr_base,
+ addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ return -ENOMEM;
+
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy)
+ board_phy_config(phy);
+ }
+
+ return 0;
+}
+
+static int serval_remove(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < SERVAL_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops serval_ops = {
+ .start = serval_start,
+ .stop = serval_stop,
+ .send = serval_send,
+ .recv = serval_recv,
+ .write_hwaddr = serval_write_hwaddr,
+};
+
+static const struct udevice_id mscc_serval_ids[] = {
+ {.compatible = "mscc,vsc7418-switch"},
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(serval) = {
+ .name = "serval-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_serval_ids,
+ .probe = serval_probe,
+ .remove = serval_remove,
+ .ops = &serval_ops,
+ .priv_auto = sizeof(struct serval_private),
+ .plat_auto = sizeof(struct eth_pdata),
+};
diff --git a/roms/u-boot/drivers/net/mscc_eswitch/servalt_switch.c b/roms/u-boot/drivers/net/mscc_eswitch/servalt_switch.c
new file mode 100644
index 000000000..f114086ec
--- /dev/null
+++ b/roms/u-boot/drivers/net/mscc_eswitch/servalt_switch.c
@@ -0,0 +1,526 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <malloc.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include "mscc_xfer.h"
+#include "mscc_miim.h"
+
+#define PHY_CFG 0x0
+#define PHY_CFG_ENA 0x3
+#define PHY_CFG_COMMON_RST BIT(2)
+#define PHY_CFG_RST (0x3 << 3)
+#define PHY_STAT 0x4
+#define PHY_STAT_SUPERVISOR_COMPLETE BIT(0)
+
+#define ANA_AC_RAM_CTRL_RAM_INIT 0x14fdc
+#define ANA_AC_STAT_GLOBAL_CFG_PORT_RESET 0x15474
+
+#define ANA_CL_PORT_VLAN_CFG(x) (0xa018 + 0xc8 * (x))
+#define ANA_CL_PORT_VLAN_CFG_AWARE_ENA BIT(19)
+#define ANA_CL_PORT_VLAN_CFG_POP_CNT(x) ((x) << 17)
+
+#define ANA_L2_COMMON_FWD_CFG 0x18498
+#define ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA BIT(6)
+
+#define ASM_CFG_STAT_CFG 0xb08
+#define ASM_CFG_PORT(x) (0xb74 + 0x4 * (x))
+#define ASM_CFG_PORT_NO_PREAMBLE_ENA BIT(8)
+#define ASM_CFG_PORT_INJ_FORMAT_CFG(x) ((x) << 1)
+#define ASM_RAM_CTRL_RAM_INIT 0xbfc
+
+#define DEV_DEV_CFG_DEV_RST_CTRL 0x0
+#define DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(x) ((x) << 20)
+#define DEV_MAC_CFG_MAC_ENA 0x24
+#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
+#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
+#define DEV_MAC_CFG_MAC_IFG 0x3c
+#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
+#define DEV_PCS1G_CFG_PCS1G_CFG 0x48
+#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
+#define DEV_PCS1G_CFG_PCS1G_MODE 0x4c
+#define DEV_PCS1G_CFG_PCS1G_SD 0x50
+#define DEV_PCS1G_CFG_PCS1G_ANEG 0x54
+#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
+
+#define LRN_COMMON_ACCESS_CTRL 0x0
+#define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT BIT(0)
+#define LRN_COMMON_MAC_ACCESS_CFG0 0x4
+#define LRN_COMMON_MAC_ACCESS_CFG1 0x8
+#define LRN_COMMON_MAC_ACCESS_CFG2 0xc
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(x) (x)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(x) ((x) << 12)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD BIT(15)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED BIT(16)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY BIT(23)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(x) ((x) << 24)
+
+#define QFWD_SYSTEM_SWITCH_PORT_MODE(x) (0x4400 + 0x4 * (x))
+#define QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA BIT(17)
+
+#define QS_XTR_GRP_CFG(x) (4 * (x))
+#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
+
+#define QSYS_SYSTEM_RESET_CFG 0x1048
+#define QSYS_CALCFG_CAL_AUTO 0x1134
+#define QSYS_CALCFG_CAL_CTRL 0x113c
+#define QSYS_CALCFG_CAL_CTRL_CAL_MODE(x) ((x) << 11)
+#define QSYS_RAM_CTRL_RAM_INIT 0x1140
+
+#define REW_RAM_CTRL_RAM_INIT 0xFFF4
+
+#define MAC_VID 0
+#define CPU_PORT 11
+#define IFH_LEN 7
+#define ETH_ALEN 6
+#define PGID_BROADCAST 50
+#define PGID_UNICAST 51
+
+static const char * const regs_names[] = {
+ "port0", "port1",
+ "ana_ac", "ana_cl", "ana_l2", "asm", "lrn", "qfwd", "qs", "qsys", "rew",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 2
+
+enum servalt_ctrl_regs {
+ ANA_AC = MAX_PORT,
+ ANA_CL,
+ ANA_L2,
+ ASM,
+ LRN,
+ QFWD,
+ QS,
+ QSYS,
+ REW,
+};
+
+#define SERVALT_MIIM_BUS_COUNT 2
+
+struct servalt_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+};
+
+struct servalt_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[SERVALT_MIIM_BUS_COUNT];
+ struct servalt_phy_port_t ports[MAX_PORT];
+};
+
+static const unsigned long servalt_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x8,
+ [MSCC_QS_XTR_FLUSH] = 0x18,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+ [MSCC_QS_INJ_WR] = 0x2c,
+ [MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static struct mscc_miim_dev miim[SERVALT_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static void mscc_phy_reset(void)
+{
+ writel(0, BASE_DEVCPU_GCB + GCB_PHY_CFG + PHY_CFG);
+ writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
+ | PHY_CFG_ENA, BASE_DEVCPU_GCB + GCB_PHY_CFG + PHY_CFG);
+ if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + GCB_PHY_CFG) +
+ PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE,
+ true, 2000, false)) {
+ pr_err("Timeout in phy reset\n");
+ }
+}
+
+static void servalt_cpu_capture_setup(struct servalt_private *priv)
+{
+ /* ASM: No preamble and IFH prefix on CPU injected frames */
+ writel(ASM_CFG_PORT_NO_PREAMBLE_ENA |
+ ASM_CFG_PORT_INJ_FORMAT_CFG(1),
+ priv->regs[ASM] + ASM_CFG_PORT(CPU_PORT));
+
+ /* Set Manual injection via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x5, priv->regs[QS] + QS_INJ_GRP_CFG(0));
+
+ /* Set Manual extraction via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x7, priv->regs[QS] + QS_XTR_GRP_CFG(0));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(CPU_PORT),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+
+ /* Send a copy to CPU when found as forwarding entry */
+ setbits_le32(priv->regs[ANA_L2] + ANA_L2_COMMON_FWD_CFG,
+ ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA);
+}
+
+static void servalt_port_init(struct servalt_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
+ regs + DEV_PCS1G_CFG_PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+ DEV_MAC_CFG_MAC_ENA_TX_ENA,
+ regs + DEV_MAC_CFG_MAC_ENA);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
+ regs + DEV_PCS1G_CFG_PCS1G_ANEG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(4) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG1(5) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG2(1),
+ regs + DEV_MAC_CFG_MAC_IFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(2),
+ regs + DEV_DEV_CFG_DEV_RST_CTRL);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_CL_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_CL_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA_CL] + ANA_CL_PORT_VLAN_CFG(port));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(port),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static int ram_init(u32 val, void __iomem *addr)
+{
+ writel(val, addr);
+
+ if (wait_for_bit_le32(addr, BIT(1), false, 2000, false)) {
+ printf("Timeout in memory reset, reg = 0x%08x\n", val);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int servalt_switch_init(struct servalt_private *priv)
+{
+ /* Initialize memories */
+ ram_init(0x3, priv->regs[QSYS] + QSYS_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ASM] + ASM_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ANA_AC] + ANA_AC_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[REW] + REW_RAM_CTRL_RAM_INIT);
+
+ /* Reset counters */
+ writel(0x1, priv->regs[ANA_AC] + ANA_AC_STAT_GLOBAL_CFG_PORT_RESET);
+ writel(0x1, priv->regs[ASM] + ASM_CFG_STAT_CFG);
+
+ /* Enable switch-core and queue system */
+ writel(0x1, priv->regs[QSYS] + QSYS_SYSTEM_RESET_CFG);
+
+ return 0;
+}
+
+static void servalt_switch_config(struct servalt_private *priv)
+{
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO);
+
+ writel(readl(priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL) |
+ QSYS_CALCFG_CAL_CTRL_CAL_MODE(8),
+ priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL);
+}
+
+static int servalt_initialize(struct servalt_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = servalt_switch_init(priv);
+ if (ret)
+ return ret;
+
+ servalt_switch_config(priv);
+
+ for (i = 0; i < MAX_PORT; i++)
+ servalt_port_init(priv, i);
+
+ servalt_cpu_capture_setup(priv);
+
+ return 0;
+}
+
+static inline
+int servalt_vlant_wait_for_completion(struct servalt_private *priv)
+{
+ if (wait_for_bit_le32(priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL,
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ false, 2000, false))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int servalt_mac_table_add(struct servalt_private *priv,
+ const unsigned char mac[ETH_ALEN], int pgid)
+{
+ u32 macl = 0, mach = 0;
+
+ /*
+ * Set the MAC address to handle and the vlan associated in a format
+ * understood by the hardware.
+ */
+ mach |= MAC_VID << 16;
+ mach |= ((u32)mac[0]) << 8;
+ mach |= ((u32)mac[1]) << 0;
+ macl |= ((u32)mac[2]) << 24;
+ macl |= ((u32)mac[3]) << 16;
+ macl |= ((u32)mac[4]) << 8;
+ macl |= ((u32)mac[5]) << 0;
+
+ writel(mach, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG0);
+ writel(macl, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG1);
+
+ writel(LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(pgid) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(0x3) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(0) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED,
+ priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG2);
+
+ writel(LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL);
+
+ return servalt_vlant_wait_for_completion(priv);
+}
+
+static int servalt_write_hwaddr(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+
+ return servalt_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+}
+
+static int servalt_start(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ const unsigned char mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = servalt_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ ret = servalt_mac_table_add(priv, mac, PGID_BROADCAST);
+ if (ret)
+ return ret;
+
+ ret = servalt_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void servalt_stop(struct udevice *dev)
+{
+}
+
+static int servalt_send(struct udevice *dev, void *packet, int length)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ u32 *buf = packet;
+
+ memset(ifh, '\0', IFH_LEN * 4);
+
+ /* Set DST PORT_MASK */
+ ifh[0] = htonl(0);
+ ifh[1] = htonl(0x1FFFFF);
+ ifh[2] = htonl(~0);
+ /* Set DST_MODE to INJECT and UPDATE_FCS */
+ ifh[5] = htonl(0x4c0);
+
+ return mscc_send(priv->regs[QS], servalt_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int servalt_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt = 0;
+
+ byte_cnt = mscc_recv(priv->regs[QS], servalt_regs_qs, rxbuf, IFH_LEN,
+ false);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < SERVALT_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct servalt_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+}
+
+static int servalt_probe(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ int i;
+ struct resource res;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(struct mscc_miim_dev) *
+ SERVALT_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
+ &phandle);
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+
+ addr_base = res.start;
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ mscc_mdiobus_init(miim, &miim_count, addr_base,
+ addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+ add_port_entry(priv, i, phy_addr, bus);
+ }
+
+ mscc_phy_reset();
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy_connect(priv->ports[i].bus, priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ }
+
+ return 0;
+}
+
+static int servalt_remove(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < SERVALT_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops servalt_ops = {
+ .start = servalt_start,
+ .stop = servalt_stop,
+ .send = servalt_send,
+ .recv = servalt_recv,
+ .write_hwaddr = servalt_write_hwaddr,
+};
+
+static const struct udevice_id mscc_servalt_ids[] = {
+ {.compatible = "mscc,vsc7437-switch" },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(servalt) = {
+ .name = "servalt-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_servalt_ids,
+ .probe = servalt_probe,
+ .remove = servalt_remove,
+ .ops = &servalt_ops,
+ .priv_auto = sizeof(struct servalt_private),
+ .plat_auto = sizeof(struct eth_pdata),
+};