Basic DSA driver support for lan937x and the device will be
configured through SPI interface.

drivers/net/dsa/microchip/ path is already part of MAINTAINERS &
the new files come under this path. Hence no update needed to the
MAINTAINERS

Reused KSZ APIs for port_bridge_join() & port_bridge_leave() and
added support for port_stp_state_set() & port_fast_age().

lan937x_flush_dyn_mac_table() which gets called from
port_fast_age() of KSZ common layer, hence added support for it.

Signed-off-by: Prasanna Vengateshan <prasanna.vengates...@microchip.com>
---
 drivers/net/dsa/microchip/Kconfig        |  12 +
 drivers/net/dsa/microchip/Makefile       |   5 +
 drivers/net/dsa/microchip/ksz_common.h   |   1 +
 drivers/net/dsa/microchip/lan937x_dev.c  | 859 ++++++++++++++++++++
 drivers/net/dsa/microchip/lan937x_dev.h  |  79 ++
 drivers/net/dsa/microchip/lan937x_main.c | 352 +++++++++
 drivers/net/dsa/microchip/lan937x_reg.h  | 955 +++++++++++++++++++++++
 drivers/net/dsa/microchip/lan937x_spi.c  | 104 +++
 8 files changed, 2367 insertions(+)
 create mode 100644 drivers/net/dsa/microchip/lan937x_dev.c
 create mode 100644 drivers/net/dsa/microchip/lan937x_dev.h
 create mode 100644 drivers/net/dsa/microchip/lan937x_main.c
 create mode 100644 drivers/net/dsa/microchip/lan937x_reg.h
 create mode 100644 drivers/net/dsa/microchip/lan937x_spi.c

diff --git a/drivers/net/dsa/microchip/Kconfig 
b/drivers/net/dsa/microchip/Kconfig
index 4ec6a47b7f72..ae2484e3759b 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -3,6 +3,18 @@ config NET_DSA_MICROCHIP_KSZ_COMMON
        select NET_DSA_TAG_KSZ
        tristate
 
+config NET_DSA_MICROCHIP_LAN937X
+       tristate "Microchip LAN937X series SPI connected switch support"
+       depends on NET_DSA && SPI
+       select NET_DSA_MICROCHIP_KSZ_COMMON
+       select REGMAP_SPI
+       help
+         This driver adds support for Microchip LAN937X series
+         switch chips.
+
+         Select to enable support for registering switches configured
+         through SPI.
+
 menuconfig NET_DSA_MICROCHIP_KSZ9477
        tristate "Microchip KSZ9477 series switch support"
        depends on NET_DSA
diff --git a/drivers/net/dsa/microchip/Makefile 
b/drivers/net/dsa/microchip/Makefile
index 929caa81e782..13f38efdadf0 100644
--- a/drivers/net/dsa/microchip/Makefile
+++ b/drivers/net/dsa/microchip/Makefile
@@ -5,3 +5,8 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)     += ksz9477_i2c.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)    += ksz9477_spi.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795)                += ksz8795.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI)    += ksz8795_spi.o
+
+obj-$(CONFIG_NET_DSA_MICROCHIP_LAN937X)                += lan937x.o
+lan937x-objs := lan937x_dev.o
+lan937x-objs += lan937x_main.o
+lan937x-objs += lan937x_spi.o
diff --git a/drivers/net/dsa/microchip/ksz_common.h 
b/drivers/net/dsa/microchip/ksz_common.h
index f212775372ce..7cc14b72ad39 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -144,6 +144,7 @@ void ksz_switch_remove(struct ksz_device *dev);
 
 int ksz8795_switch_register(struct ksz_device *dev);
 int ksz9477_switch_register(struct ksz_device *dev);
+int lan937x_switch_register(struct ksz_device *dev);
 
 void ksz_update_port_member(struct ksz_device *dev, int port);
 void ksz_init_mib_timer(struct ksz_device *dev);
diff --git a/drivers/net/dsa/microchip/lan937x_dev.c 
b/drivers/net/dsa/microchip/lan937x_dev.c
new file mode 100644
index 000000000000..84540180ff2f
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan937x_dev.c
@@ -0,0 +1,859 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Microchip lan937x dev ops functions
+ * Copyright (C) 2019-2020 Microchip Technology Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/platform_data/microchip-ksz.h>
+#include <linux/phy.h>
+#include <linux/if_bridge.h>
+#include <net/dsa.h>
+#include <net/switchdev.h>
+
+#include "lan937x_reg.h"
+#include "ksz_common.h"
+#include "lan937x_dev.h"
+
+const struct mib_names lan937x_mib_names[] = {
+       { 0x00, "rx_hi" },
+       { 0x01, "rx_undersize" },
+       { 0x02, "rx_fragments" },
+       { 0x03, "rx_oversize" },
+       { 0x04, "rx_jabbers" },
+       { 0x05, "rx_symbol_err" },
+       { 0x06, "rx_crc_err" },
+       { 0x07, "rx_align_err" },
+       { 0x08, "rx_mac_ctrl" },
+       { 0x09, "rx_pause" },
+       { 0x0A, "rx_bcast" },
+       { 0x0B, "rx_mcast" },
+       { 0x0C, "rx_ucast" },
+       { 0x0D, "rx_64_or_less" },
+       { 0x0E, "rx_65_127" },
+       { 0x0F, "rx_128_255" },
+       { 0x10, "rx_256_511" },
+       { 0x11, "rx_512_1023" },
+       { 0x12, "rx_1024_1522" },
+       { 0x13, "rx_1523_2000" },
+       { 0x14, "rx_2001" },
+       { 0x15, "tx_hi" },
+       { 0x16, "tx_late_col" },
+       { 0x17, "tx_pause" },
+       { 0x18, "tx_bcast" },
+       { 0x19, "tx_mcast" },
+       { 0x1A, "tx_ucast" },
+       { 0x1B, "tx_deferred" },
+       { 0x1C, "tx_total_col" },
+       { 0x1D, "tx_exc_col" },
+       { 0x1E, "tx_single_col" },
+       { 0x1F, "tx_mult_col" },
+       { 0x80, "rx_total" },
+       { 0x81, "tx_total" },
+       { 0x82, "rx_discards" },
+       { 0x83, "tx_discards" },
+};
+
+static const struct lan937x_chip_data lan937x_switch_chips[] = {
+       {
+               .chip_id = 0x00937000,
+               .dev_name = "LAN9370",
+               .num_vlans = 4096,
+               .num_alus = 1024,
+               .num_statics = 256,
+               /* can be configured as cpu port */
+               .cpu_ports = 0x10,
+               /* total port count */
+               .port_cnt = 5,
+       },
+       {
+               .chip_id = 0x00937100,
+               .dev_name = "LAN9371",
+               .num_vlans = 4096,
+               .num_alus = 1024,
+               .num_statics = 256,
+               /* can be configured as cpu port */
+               .cpu_ports = 0x30,
+               /* total port count */
+               .port_cnt = 6,
+       },
+       {
+               .chip_id = 0x00937200,
+               .dev_name = "LAN9372",
+               .num_vlans = 4096,
+               .num_alus = 1024,
+               .num_statics = 256,
+               /* can be configured as cpu port */
+               .cpu_ports = 0x30,
+               /* total port count */
+               .port_cnt = 8,
+       },
+       {
+               .chip_id = 0x00937300,
+               .dev_name = "LAN9373",
+               .num_vlans = 4096,
+               .num_alus = 1024,
+               .num_statics = 256,
+               /* can be configured as cpu port */
+               .cpu_ports = 0x38,
+               /* total port count */
+               .port_cnt = 5,
+       },
+       {
+               .chip_id = 0x00937400,
+               .dev_name = "LAN9374",
+               .num_vlans = 4096,
+               .num_alus = 1024,
+               .num_statics = 256,
+               /* can be configured as cpu port */
+               .cpu_ports = 0x30,
+               /* total port count */
+               .port_cnt = 8,
+       },
+
+};
+
+void lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
+{
+       regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
+}
+
+void lan937x_port_cfg(struct ksz_device *dev, int port, int offset,
+                     u8 bits, bool set)
+{
+       regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset),
+                          bits, set ? bits : 0);
+}
+
+void lan937x_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set)
+{
+       regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0);
+}
+
+void lan937x_pread8(struct ksz_device *dev, int port, int offset,
+                   u8 *data)
+{
+       ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data);
+}
+
+void lan937x_pread16(struct ksz_device *dev, int port, int offset,
+                    u16 *data)
+{
+       ksz_read16(dev, PORT_CTRL_ADDR(port, offset), data);
+}
+
+void lan937x_pread32(struct ksz_device *dev, int port, int offset,
+                    u32 *data)
+{
+       ksz_read32(dev, PORT_CTRL_ADDR(port, offset), data);
+}
+
+void lan937x_pwrite8(struct ksz_device *dev, int port,
+                    int offset, u8 data)
+{
+       ksz_write8(dev, PORT_CTRL_ADDR(port, offset), data);
+}
+
+void lan937x_pwrite16(struct ksz_device *dev, int port,
+                     int offset, u16 data)
+{
+       ksz_write16(dev, PORT_CTRL_ADDR(port, offset), data);
+}
+
+void lan937x_pwrite32(struct ksz_device *dev, int port,
+                     int offset, u32 data)
+{
+       ksz_write32(dev, PORT_CTRL_ADDR(port, offset), data);
+}
+
+void lan937x_port_cfg32(struct ksz_device *dev, int port, int offset,
+                       u32 bits, bool set)
+{
+       regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset),
+                          bits, set ? bits : 0);
+}
+
+void lan937x_cfg_port_member(struct ksz_device *dev, int port,
+                            u8 member)
+{
+       lan937x_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member);
+
+       dev->ports[port].member = member;
+}
+
+static void lan937x_flush_dyn_mac_table(struct ksz_device *dev, int port)
+{
+       unsigned int value;
+       u8 data;
+
+       regmap_update_bits(dev->regmap[0], REG_SW_LUE_CTRL_2,
+                          SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S,
+                          SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S);
+
+       if (port < dev->port_cnt) {
+               /* flush individual port */
+               lan937x_pread8(dev, port, P_STP_CTRL, &data);
+               if (!(data & PORT_LEARN_DISABLE))
+                       lan937x_pwrite8(dev, port, P_STP_CTRL,
+                                       data | PORT_LEARN_DISABLE);
+               lan937x_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, 
true);
+
+               regmap_read_poll_timeout(dev->regmap[0],
+                                        S_FLUSH_TABLE_CTRL,
+                               value, !(value & SW_FLUSH_DYN_MAC_TABLE), 10, 
1000);
+
+               lan937x_pwrite8(dev, port, P_STP_CTRL, data);
+       } else {
+               /* flush all */
+               lan937x_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_STP_TABLE, true);
+       }
+}
+
+static void lan937x_port_init_cnt(struct ksz_device *dev, int port)
+{
+       struct ksz_port_mib *mib = &dev->ports[port].mib;
+
+       /* flush all enabled port MIB counters */
+       mutex_lock(&mib->cnt_mutex);
+       lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4,
+                        MIB_COUNTER_FLUSH_FREEZE);
+       ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH);
+       lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0);
+       mutex_unlock(&mib->cnt_mutex);
+
+       mib->cnt_ptr = 0;
+       memset(mib->counters, 0, dev->mib_cnt * sizeof(u64));
+}
+
+int lan937x_reset_switch(struct ksz_device *dev)
+{
+       u32 data32;
+       u8 data8;
+
+       /* reset switch */
+       lan937x_cfg(dev, REG_SW_OPERATION, SW_RESET, true);
+
+       /* default configuration */
+       ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8);
+       data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING |
+             SW_SRC_ADDR_FILTER;
+       ksz_write8(dev, REG_SW_LUE_CTRL_1, data8);
+
+       /* disable interrupts */
+       ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK);
+       ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF);
+       ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
+
+       /* set broadcast storm protection 10% rate */
+       regmap_update_bits(dev->regmap[1], REG_SW_MAC_CTRL_2,
+                          BROADCAST_STORM_RATE,
+                          (BROADCAST_STORM_VALUE *
+                          BROADCAST_STORM_PROT_RATE) / 100);
+
+       return 0;
+}
+
+static int lan937x_switch_detect(struct ksz_device *dev)
+{
+       u32 id32;
+       int ret;
+
+       /* Read Chip ID */
+       ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32);
+
+       if (ret)
+               return ret;
+
+       if (id32 != 0) {
+               dev->chip_id = id32;
+               dev_info(dev->dev, "Chip ID: 0x%x", id32);
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static void lan937x_switch_exit(struct ksz_device *dev)
+{
+       lan937x_reset_switch(dev);
+}
+
+void lan937x_enable_spi_indirect_access(struct ksz_device *dev)
+{
+       u16 data16;
+       u8 data8;
+
+       ksz_read8(dev, REG_GLOBAL_CTRL_0, &data8);
+
+       /* Check if PHY register is blocked */
+       if (data8 & SW_PHY_REG_BLOCK) {
+               /* Enable Phy access through SPI*/
+               data8 &= ~SW_PHY_REG_BLOCK;
+               ksz_write8(dev, REG_GLOBAL_CTRL_0, data8);
+       }
+
+       ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16);
+
+       /* If already the access is not enabled go ahead and allow SPI access */
+       if (!(data16 & VPHY_SPI_INDIRECT_ENABLE)) {
+               data16 |= VPHY_SPI_INDIRECT_ENABLE;
+               ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16);
+       }
+}
+
+bool lan937x_is_internal_phy_port(struct ksz_device *dev, int port)
+{
+       /* Check if the port is RGMII */
+       if (port == LAN937X_RGMII_1_PORT || port == LAN937X_RGMII_2_PORT)
+               return false;
+
+       /* Check if the port is SGMII */
+       if (port == LAN937X_SGMII_PORT &&
+           GET_CHIP_ID_LSB(dev->chip_id) == CHIP_ID_73)
+               return false;
+
+       return true;
+}
+
+static u32 lan937x_get_port_addr(int port, int offset)
+{
+       return PORT_CTRL_ADDR(port, offset);
+}
+
+bool lan937x_is_internal_tx_phy_port(struct ksz_device *dev, int port)
+{
+       /* Check if the port is internal tx phy port */
+       if (lan937x_is_internal_phy_port(dev, port) && port == 
LAN937X_TXPHY_PORT)
+               if ((GET_CHIP_ID_LSB(dev->chip_id) == CHIP_ID_71) ||
+                   (GET_CHIP_ID_LSB(dev->chip_id) == CHIP_ID_72))
+                       return true;
+
+       return false;
+}
+
+bool lan937x_is_internal_t1_phy_port(struct ksz_device *dev, int port)
+{
+       /* Check if the port is internal t1 phy port */
+       if (lan937x_is_internal_phy_port(dev, port) &&
+           !lan937x_is_internal_tx_phy_port(dev, port))
+               return true;
+
+       return false;
+}
+
+int lan937x_t1_tx_phy_write(struct ksz_device *dev, int addr,
+                           int reg, u16 val)
+{
+       u16 temp, addr_base;
+       unsigned int value;
+       int ret;
+
+       /* Check for internal phy port */
+       if (!lan937x_is_internal_phy_port(dev, addr))
+               return 0;
+
+       if (lan937x_is_internal_tx_phy_port(dev, addr))
+               addr_base = REG_PORT_TX_PHY_CTRL_BASE;
+       else
+               addr_base = REG_PORT_T1_PHY_CTRL_BASE;
+
+       temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2)));
+
+       ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp);
+
+       /* Write the data to be written to the VPHY reg */
+       ksz_write16(dev, REG_VPHY_IND_DATA__2, val);
+
+       /* Write the Write En and Busy bit */
+       ksz_write16(dev, REG_VPHY_IND_CTRL__2, (VPHY_IND_WRITE
+                               | VPHY_IND_BUSY));
+
+       ret = regmap_read_poll_timeout(dev->regmap[1],
+                                      REG_VPHY_IND_CTRL__2,
+                               value, !(value & VPHY_IND_BUSY), 10, 1000);
+
+       /* failed to write phy register. get out of loop */
+       if (ret) {
+               dev_err(dev->dev, "Failed to write phy register\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int lan937x_t1_tx_phy_read(struct ksz_device *dev, int addr,
+                          int reg, u16 *val)
+{
+       u16 temp, addr_base;
+       unsigned int value;
+       int ret;
+
+       if (lan937x_is_internal_phy_port(dev, addr)) {
+               if (lan937x_is_internal_tx_phy_port(dev, addr))
+                       addr_base = REG_PORT_TX_PHY_CTRL_BASE;
+               else
+                       addr_base = REG_PORT_T1_PHY_CTRL_BASE;
+
+               /* get register address based on the logical port */
+               temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2)));
+
+               ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp);
+               /* Write Read and Busy bit to start the transaction*/
+               ksz_write16(dev, REG_VPHY_IND_CTRL__2, VPHY_IND_BUSY);
+
+               ret = regmap_read_poll_timeout(dev->regmap[1],
+                                              REG_VPHY_IND_CTRL__2,
+                                       value, !(value & VPHY_IND_BUSY), 10, 
1000);
+
+               /*  failed to read phy register. get out of loop */
+               if (ret) {
+                       dev_err(dev->dev, "Failed to read phy register\n");
+                       return ret;
+               }
+               /* Read the VPHY register which has the PHY data*/
+               ksz_read16(dev, REG_VPHY_IND_DATA__2, val);
+       }
+
+       return 0;
+}
+
+static void lan937x_t1_tx_phy_mod_bits(struct ksz_device *dev, int port,
+                                      int reg, u16 val, bool set)
+{
+       u16 data;
+
+       /* read phy register */
+       lan937x_t1_tx_phy_read(dev, port, reg, &data);
+
+       /* set/clear the data */
+       if (set)
+               data |= val;
+       else
+               data &= ~val;
+
+       /* write phy register */
+       lan937x_t1_tx_phy_write(dev, port, reg, data);
+}
+
+static u32 lan937x_tx_phy_bank_read(struct ksz_device *dev, int port,
+                                   u8 bank, u8 reg)
+{
+       u16 data_hi;
+       u16 data_lo;
+       u16 ctrl;
+
+       ctrl = ((u16)bank & TX_REG_BANK_SEL_M) << TX_REG_BANK_SEL_S;
+       ctrl |= ((u16)reg & TX_READ_ADDR_M) << TX_READ_ADDR_S;
+
+       /* write ctrl register with appropriate value */
+       ctrl |= TX_IND_DATA_READ;
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, ctrl);
+
+       /* if bank is WOL value to be written again to reflect correct bank */
+       if (bank == TX_REG_BANK_SEL_WOL)
+               lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, ctrl);
+
+       /* read data hi & low value */
+       lan937x_t1_tx_phy_read(dev, port, REG_PORT_TX_READ_DATA_LO, &data_lo);
+       lan937x_t1_tx_phy_read(dev, port, REG_PORT_TX_READ_DATA_HI, &data_hi);
+
+       return ((u32)data_hi << 16) | data_lo;
+}
+
+static void lan937x_tx_phy_bank_write(struct ksz_device *dev, int port,
+                                     u8 bank, u8 reg, u16 val)
+{
+       u16 ctrl;
+
+       /* write the value */
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_WRITE_DATA, val);
+       ctrl = ((u16)bank & TX_REG_BANK_SEL_M) << TX_REG_BANK_SEL_S;
+       ctrl |= (reg & TX_WRITE_ADDR_M);
+
+       if (bank == TX_REG_BANK_SEL_DSP || bank == TX_REG_BANK_SEL_BIST)
+               ctrl |= TX_TEST_MODE;
+       /* write ctrl register with write operation bit set */
+       ctrl |= TX_IND_DATA_WRITE;
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, ctrl);
+}
+
+static void tx_phy_setup(struct ksz_device *dev, int port)
+{
+       u16 data_lo;
+
+       lan937x_t1_tx_phy_read(dev, port, REG_PORT_TX_SPECIAL_MODES, &data_lo);
+       /* Need to change configuration from 6 to other value. */
+       data_lo &= TX_PHYADDR_M;
+
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_SPECIAL_MODES, data_lo);
+
+       /* Need to toggle test_mode bit to enable DSP access. */
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, TX_TEST_MODE);
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, 0);
+
+       /* Note TX_TEST_MODE is then always enabled so this is not required. */
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, TX_TEST_MODE);
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, 0);
+}
+
+static void tx_phy_port_init(struct ksz_device *dev, int port)
+{
+       u32 data;
+
+       /* Software reset. */
+       lan937x_t1_tx_phy_mod_bits(dev, port, MII_BMCR, BMCR_RESET, true);
+
+       /* tx phy setup */
+       tx_phy_setup(dev, port);
+
+       /* tx phy init sequence */
+       data = lan937x_tx_phy_bank_read(dev, port, TX_REG_BANK_SEL_VMDAC,
+                                       TX_VMDAC_ZQ_CAL_CTRL);
+       data |= TX_START_ZQ_CAL;
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC,
+                                 TX_VMDAC_ZQ_CAL_CTRL, data);
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC, 
TX_VMDAC_CTRL0,
+                                 TX_VMDAC_CTRL0_VAL);
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC, 
TX_VMDAC_CTRL1,
+                                 TX_VMDAC_CTRL1_VAL);
+       data = lan937x_tx_phy_bank_read(dev, port, TX_REG_BANK_SEL_VMDAC,
+                                       TX_VMDAC_MISC_PCS_CTRL0);
+       data |= TX_MISC_PCS_CTRL0_13;
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC,
+                                 TX_VMDAC_MISC_PCS_CTRL0, data);
+
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_DSP, TX_DSP_DCBLW,
+                                 TX_DSP_DCBLW_VAL);
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_DSP, 
TX_DSP_A11_CONFIG,
+                                 TX_DSP_A11_CONFIG_VAL);
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_DSP, 
TX_DSP_A10_CONFIG,
+                                 TX_DSP_A10_CONFIG_VAL);
+       data = lan937x_tx_phy_bank_read(dev, port, TX_REG_BANK_SEL_DSP,
+                                       TX_DSP_A5_CONFIG);
+       data &= ~(TX_A5_TXCLKPHSEL_M << TX_A5_TXCLKPHSEL_S);
+       data |= (TX_A5_TXCLK_2_NS << TX_A5_TXCLKPHSEL_S);
+       lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC,
+                                 TX_DSP_A5_CONFIG, data);
+}
+
+static void lan937x_t1_phy_bank_sel(struct ksz_device *dev, int port,
+                                   u8 bank, u8 addr, u16 oper)
+{
+       u16 data, ctrl;
+       u8 prev_bank;
+
+       lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_EXT_REG_CTRL, &ctrl);
+       prev_bank = (ctrl >> T1_REG_BANK_SEL_S) & T1_REG_BANK_SEL_M;
+       ctrl &= T1_PCS_STS_CNT_RESET;
+
+       data = ((u16)bank & T1_REG_BANK_SEL_M) << T1_REG_BANK_SEL_S;
+       data |= (addr & T1_REG_ADDR_M);
+       data |= oper;
+       data |= ctrl;
+
+       /* if the bank is DSP need to write twice */
+       if (bank != prev_bank && bank == T1_REG_BANK_SEL_DSP) {
+               u16 t = data & ~T1_REG_ADDR_M;
+
+               t &= ~oper;
+               t |= T1_IND_DATA_READ;
+
+               /* Need to write twice to access correct register. */
+               lan937x_t1_tx_phy_write(dev, port, REG_PORT_T1_EXT_REG_CTRL, t);
+       }
+
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_T1_EXT_REG_CTRL, data);
+}
+
+static void lan937x_t1_phy_bank_read(struct ksz_device *dev, int port,
+                                    u8 bank, u8 addr, u16 *val)
+{
+       /* select the bank for read operation */
+       lan937x_t1_phy_bank_sel(dev, port, bank, addr, T1_IND_DATA_READ);
+
+       /* read bank */
+       lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_EXT_REG_RD_DATA, val);
+}
+
+static void lan937x_t1_phy_bank_write(struct ksz_device *dev, int port,
+                                     u8 bank, u8 addr, u16 val)
+{
+       /* write the data to be written into the bank */
+       lan937x_t1_tx_phy_write(dev, port, REG_PORT_T1_EXT_REG_WR_DATA, val);
+       /* select the bank for write operation */
+       lan937x_t1_phy_bank_sel(dev, port, bank, addr, T1_IND_DATA_WRITE);
+}
+
+static void t1_phy_port_init(struct ksz_device *dev, int port)
+{
+       u16 val;
+
+       /* Power down the PHY. */
+       lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_BASIC_CTRL,
+                                  PORT_T1_POWER_DOWN, true);
+
+       /* Make sure software initialization sequence is used. */
+       lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_POWER_DOWN_CTRL,
+                                  T1_HW_INIT_SEQ_ENABLE, false);
+
+       /* Configure T1 phy role */
+       lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_M_CTRL,
+                                  PORT_T1_M_CFG, true);
+
+       /* Software reset. */
+       lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_BASIC_CTRL,
+                                  PORT_T1_PHY_RESET, true);
+
+       /* cdr mode */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x34, 0x0001);
+
+       /* setting lock 3 mufac */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x1B, 0x0B6A);
+
+       /* setting pos lock mufac */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x1C, 0x0B6B);
+
+       /* setting lock1 win config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x11, 0x2A74);
+
+       /* setting lock2 win config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x12, 0x2B70);
+
+       /* setting lock3 win config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x13, 0x2B6C);
+
+       /* setting plock */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x14, 0x2974);
+
+       /* setting lock threshold config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x16, 0xC803);
+
+       /* slv fd stg bmp */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x24, 0x0002);
+
+       /* Blw BW config lock stage 3 */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x2A, 0x003C);
+
+       /* Blw BW config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x56, 0x3CAA);
+
+       /* Blw BW config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x57, 0x1E47);
+
+       /* Blw BW config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x58, 0x1E4E);
+
+       /* Blw BW config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x59, 0x1E56);
+
+       /* disable scrambler lock timeout 0-disable 1- enable */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x32, 0x00F6);
+
+       /* reducing energy detect partial timeout */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x3C, 0x64CC);
+
+       lan937x_t1_tx_phy_read(dev, port, 0x0A, &val);
+
+       if ((val & 0x4000) == 0)
+               lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_PCS, 0x26, 
0x1770);
+
+       /* pwr dn Config */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x04, 0x16D7);
+
+       /* scrambler lock hysterisis */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_PCS, 0x00, 0x7FFF);
+
+       /* eq status timer control */
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_PCS, 0x02, 0x07FF);
+
+       /* MANUAL STD POLARITY */
+       lan937x_t1_tx_phy_write(dev, port, 0x17, 0x0080);
+
+       /* disable master mode energy detect */
+       lan937x_t1_tx_phy_mod_bits(dev, port, 0x10, 0x0040, false);
+
+       lan937x_t1_phy_bank_read(dev, port, T1_REG_BANK_SEL_AFE, 0x0B, &val);
+
+       val &= ~0x001E;
+       /* increase tx amp to 0b0101 */
+       val |= 0x000A;
+
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_AFE, 0x0B, val);
+
+       lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x25, 0x23E0);
+
+       /* Set HW_INIT */
+       lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_POWER_DOWN_CTRL,
+                                  T1_HW_INIT_SEQ_ENABLE, true);
+
+       /* Power up the PHY. */
+       lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_BASIC_CTRL,
+                                  PORT_T1_POWER_DOWN, false);
+}
+
+static void lan937x_set_gbit(struct ksz_device *dev, bool gbit, u8 *data)
+{
+       if (gbit)
+               *data &= ~PORT_MII_NOT_1GBIT;
+       else
+               *data |= PORT_MII_NOT_1GBIT;
+}
+
+void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+{
+       struct ksz_port *p = &dev->ports[port];
+       u8 data8, member;
+
+       /* enable tag tail for host port */
+       if (cpu_port) {
+               lan937x_port_cfg(dev, port, REG_PORT_CTRL_0, 
PORT_TAIL_TAG_ENABLE,
+                                true);
+               /* Enable jumbo packet in host port so that frames are not
+                * counted as oversized.
+                */
+               lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, 
PORT_JUMBO_PACKET,
+                                true);
+               lan937x_pwrite16(dev, port, REG_PORT_MTU__2, FR_SIZE_CPU_PORT);
+       }
+
+       lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_FR_CHK_LENGTH,
+                        false);
+
+       lan937x_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false);
+
+       /* set back pressure */
+       lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, 
true);
+
+       /* enable broadcast storm limit */
+       lan937x_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, 
true);
+
+       /* disable DiffServ priority */
+       lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, 
false);
+
+       /* replace priority */
+       lan937x_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, 
PORT_USER_PRIO_CEILING,
+                        false);
+       lan937x_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4,
+                          MTI_PVID_REPLACE, false);
+
+       /* enable 802.1p priority */
+       lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true);
+
+       /* phy init for internal ports */
+       if (lan937x_is_internal_phy_port(dev, port)) {
+               if (lan937x_is_internal_tx_phy_port(dev, port))
+                       tx_phy_port_init(dev, port);
+               else
+                       t1_phy_port_init(dev, port);
+
+       } else {
+               /* force flow control off*/
+               lan937x_port_cfg(dev, port, REG_PORT_XMII_CTRL_0,
+                                PORT_FORCE_TX_FLOW_CTRL | 
PORT_FORCE_RX_FLOW_CTRL,
+                            false);
+
+               lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8);
+
+               /* clear MII selection & set it based on interface later */
+               data8 &= ~PORT_MII_SEL_M;
+
+               /* configure MAC based on p->interface */
+               switch (p->interface) {
+               case PHY_INTERFACE_MODE_MII:
+                       lan937x_set_gbit(dev, false, &data8);
+                       data8 |= PORT_MII_SEL;
+                       break;
+               case PHY_INTERFACE_MODE_RMII:
+                       lan937x_set_gbit(dev, false, &data8);
+                       data8 |= PORT_RMII_SEL;
+                       break;
+               default:
+                       lan937x_set_gbit(dev, true, &data8);
+                       data8 |= PORT_RGMII_SEL;
+
+                       data8 &= ~PORT_RGMII_ID_IG_ENABLE;
+                       data8 &= ~PORT_RGMII_ID_EG_ENABLE;
+
+                       if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+                           p->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+                               data8 |= PORT_RGMII_ID_IG_ENABLE;
+
+                       if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+                           p->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+                               data8 |= PORT_RGMII_ID_EG_ENABLE;
+                       break;
+               }
+               lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8);
+       }
+
+       if (cpu_port)
+               member = dev->port_mask;
+       else
+               member = dev->host_mask | p->vid_member;
+
+       lan937x_cfg_port_member(dev, port, member);
+}
+
+static int lan937x_switch_init(struct ksz_device *dev)
+{
+       int i;
+
+       dev->ds->ops = &lan937x_switch_ops;
+
+       for (i = 0; i < ARRAY_SIZE(lan937x_switch_chips); i++) {
+               const struct lan937x_chip_data *chip = &lan937x_switch_chips[i];
+
+               if (dev->chip_id == chip->chip_id) {
+                       dev->name = chip->dev_name;
+                       dev->num_vlans = chip->num_vlans;
+                       dev->num_alus = chip->num_alus;
+                       dev->num_statics = chip->num_statics;
+                       dev->port_cnt = chip->port_cnt;
+                       dev->cpu_ports = chip->cpu_ports;
+                       break;
+               }
+       }
+
+       /* no switch found */
+       if (!dev->port_cnt)
+               return -ENODEV;
+
+       dev->port_mask = (1 << dev->port_cnt) - 1;
+
+       dev->reg_mib_cnt = SWITCH_COUNTER_NUM;
+       dev->mib_cnt = ARRAY_SIZE(lan937x_mib_names);
+
+       dev->ports = devm_kzalloc(dev->dev,
+                                 dev->port_cnt * sizeof(struct ksz_port),
+                                 GFP_KERNEL);
+       if (!dev->ports)
+               return -ENOMEM;
+
+       for (i = 0; i < dev->port_cnt; i++) {
+               mutex_init(&dev->ports[i].mib.cnt_mutex);
+               dev->ports[i].mib.counters =
+                       devm_kzalloc(dev->dev,
+                                    sizeof(u64) *
+                                    (dev->mib_cnt + 1),
+                                    GFP_KERNEL);
+               if (!dev->ports[i].mib.counters)
+                       return -ENOMEM;
+       }
+
+       /* set the real number of ports */
+       dev->ds->num_ports = dev->port_cnt;
+       return 0;
+}
+
+const struct ksz_dev_ops lan937x_dev_ops = {
+       .get_port_addr = lan937x_get_port_addr,
+       .cfg_port_member = lan937x_cfg_port_member,
+       .flush_dyn_mac_table = lan937x_flush_dyn_mac_table,
+       .port_setup = lan937x_port_setup,
+       .port_init_cnt = lan937x_port_init_cnt,
+       .shutdown = lan937x_reset_switch,
+       .detect = lan937x_switch_detect,
+       .init = lan937x_switch_init,
+       .exit = lan937x_switch_exit,
+};
diff --git a/drivers/net/dsa/microchip/lan937x_dev.h 
b/drivers/net/dsa/microchip/lan937x_dev.h
new file mode 100644
index 000000000000..e78483793642
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan937x_dev.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Microchip lan937x dev ops headers
+ * Copyright (C) 2019-2020 Microchip Technology Inc.
+ */
+
+#ifndef __LAN937X_CFG_H
+#define __LAN937X_CFG_H
+
+void lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set);
+void lan937x_port_cfg(struct ksz_device *dev, int port, int offset,
+                     u8 bits, bool set);
+void lan937x_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set);
+void lan937x_pread8(struct ksz_device *dev, int port, int offset,
+                   u8 *data);
+void lan937x_pread16(struct ksz_device *dev, int port, int offset,
+                    u16 *data);
+void lan937x_pread32(struct ksz_device *dev, int port, int offset,
+                    u32 *data);
+void lan937x_pwrite8(struct ksz_device *dev, int port,
+                    int offset, u8 data);
+void lan937x_pwrite16(struct ksz_device *dev, int port,
+                     int offset, u16 data);
+void lan937x_pwrite32(struct ksz_device *dev, int port,
+                     int offset, u32 data);
+void lan937x_port_cfg32(struct ksz_device *dev, int port, int offset,
+                       u32 bits, bool set);
+int lan937x_t1_tx_phy_write(struct ksz_device *dev, int addr,
+                           int reg, u16 val);
+int lan937x_t1_tx_phy_read(struct ksz_device *dev, int addr,
+                          int reg, u16 *val);
+bool lan937x_is_internal_tx_phy_port(struct ksz_device *dev, int port);
+bool lan937x_is_internal_t1_phy_port(struct ksz_device *dev, int port);
+bool lan937x_is_internal_phy_port(struct ksz_device *dev, int port);
+int lan937x_reset_switch(struct ksz_device *dev);
+void lan937x_cfg_port_member(struct ksz_device *dev, int port,
+                            u8 member);
+void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port);
+int lan937x_sw_register(struct ksz_device *dev);
+void lan937x_enable_spi_indirect_access(struct ksz_device *dev);
+
+struct mib_names {
+       int index;
+       char string[ETH_GSTRING_LEN];
+};
+
+struct lan937x_chip_data {
+       u32 chip_id;
+       const char *dev_name;
+       int num_vlans;
+       int num_alus;
+       int num_statics;
+       int cpu_ports;
+       int port_cnt;
+};
+
+struct lan_alu_struct {
+       /* entry 1 */
+       u8      is_static:1;
+       u8      is_src_filter:1;
+       u8      is_dst_filter:1;
+       u8      prio_age:3;
+       u32     _reserv_0_1:23;
+       u8      mstp:3;
+       /* entry 2 */
+       u8      is_override:1;
+       u8      is_use_fid:1;
+       u32     _reserv_1_1:22;
+       u8      port_forward:8;
+       /* entry 3 & 4*/
+       u32     _reserv_2_1:9;
+       u8      fid:7;
+       u8      mac[ETH_ALEN];
+};
+
+extern const struct dsa_switch_ops lan937x_switch_ops;
+extern const struct ksz_dev_ops lan937x_dev_ops;
+extern const struct mib_names lan937x_mib_names[];
+
+#endif
diff --git a/drivers/net/dsa/microchip/lan937x_main.c 
b/drivers/net/dsa/microchip/lan937x_main.c
new file mode 100644
index 000000000000..41f7f5f8f435
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan937x_main.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Microchip LAN937X switch driver main logic
+ * Copyright (C) 2019-2020 Microchip Technology Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/phy.h>
+#include <linux/if_bridge.h>
+#include <net/dsa.h>
+#include <net/switchdev.h>
+
+#include "lan937x_reg.h"
+#include "ksz_common.h"
+#include "lan937x_dev.h"
+
+static enum dsa_tag_protocol lan937x_get_tag_protocol(struct dsa_switch *ds,
+                                                     int port,
+                                                     enum dsa_tag_protocol mp)
+{
+       return DSA_TAG_PROTO_LAN937X_VALUE;
+}
+
+static int lan937x_get_link_status(struct ksz_device *dev, int port)
+{
+       u16 val1, val2;
+
+       lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_PHY_M_STATUS,
+                              &val1);
+
+       lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_MODE_STAT, &val2);
+
+       if (val1 & (PORT_T1_LOCAL_RX_OK | PORT_T1_REMOTE_RX_OK) &&
+           val2 & (T1_PORT_DSCR_LOCK_STATUS_MSK | T1_PORT_LINK_UP_MSK))
+               return PHY_LINK_UP;
+
+       return PHY_LINK_DOWN;
+}
+
+static int lan937x_phy_read16(struct dsa_switch *ds, int addr, int reg)
+{
+       struct ksz_device *dev = ds->priv;
+       u16 val;
+
+       lan937x_t1_tx_phy_read(dev, addr, reg, &val);
+
+       if (reg == MII_BMSR && lan937x_is_internal_t1_phy_port(dev, addr)) {
+               /* T1 PHY supports only 100 Mb FD, report through BMSR_100FULL 
bit*/
+               val |= BMSR_100FULL;
+
+               /* T1 Phy link is based on REG_PORT_T1_PHY_M_STATUS & 
REG_PORT_T1
+                * _MODE_STAT registers for LAN937x, get the link status
+                * and report through BMSR_LSTATUS bit
+                */
+               if (lan937x_get_link_status(dev, addr) == PHY_LINK_UP)
+                       val |= BMSR_LSTATUS;
+               else
+                       val &= ~BMSR_LSTATUS;
+       }
+
+       return val;
+}
+
+static int lan937x_phy_write16(struct dsa_switch *ds, int addr, int reg,
+                              u16 val)
+{
+       struct ksz_device *dev = ds->priv;
+
+       return lan937x_t1_tx_phy_write(dev, addr, reg, val);
+}
+
+static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port,
+                                      u8 state)
+{
+       struct ksz_device *dev = ds->priv;
+       struct ksz_port *p = &dev->ports[port];
+       int forward = dev->member;
+       int member = -1;
+       u8 data;
+
+       lan937x_pread8(dev, port, P_STP_CTRL, &data);
+       data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
+
+       switch (state) {
+       case BR_STATE_DISABLED:
+               data |= PORT_LEARN_DISABLE;
+               if (port != dev->cpu_port)
+                       member = 0;
+               break;
+       case BR_STATE_LISTENING:
+               data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
+               if (port != dev->cpu_port &&
+                   p->stp_state == BR_STATE_DISABLED)
+                       member = dev->host_mask | p->vid_member;
+               break;
+       case BR_STATE_LEARNING:
+               data |= PORT_RX_ENABLE;
+               break;
+       case BR_STATE_FORWARDING:
+               data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
+
+               /* This function is also used internally. */
+               if (port == dev->cpu_port)
+                       break;
+
+               member = dev->host_mask | p->vid_member;
+               mutex_lock(&dev->dev_mutex);
+
+               /* Port is a member of a bridge. */
+               if (dev->br_member & (1 << port)) {
+                       dev->member |= (1 << port);
+                       member = dev->member;
+               }
+               mutex_unlock(&dev->dev_mutex);
+               break;
+       case BR_STATE_BLOCKING:
+               data |= PORT_LEARN_DISABLE;
+               if (port != dev->cpu_port &&
+                   p->stp_state == BR_STATE_DISABLED)
+                       member = dev->host_mask | p->vid_member;
+               break;
+       default:
+               dev_err(ds->dev, "invalid STP state: %d\n", state);
+               return;
+       }
+
+       lan937x_pwrite8(dev, port, P_STP_CTRL, data);
+
+       p->stp_state = state;
+       mutex_lock(&dev->dev_mutex);
+
+       /* Port membership may share register with STP state. */
+       if (member >= 0 && member != p->member)
+               lan937x_cfg_port_member(dev, port, (u8)member);
+
+       /* Check if forwarding needs to be updated. */
+       if (state != BR_STATE_FORWARDING) {
+               if (dev->br_member & (1 << port))
+                       dev->member &= ~(1 << port);
+       }
+
+       /* When topology has changed the function ksz_update_port_member
+        * should be called to modify port forwarding behavior.
+        */
+       if (forward != dev->member)
+               ksz_update_port_member(dev, port);
+       mutex_unlock(&dev->dev_mutex);
+}
+
+static phy_interface_t lan937x_get_interface(struct ksz_device *dev, int port)
+{
+       phy_interface_t interface;
+       u8 data8;
+
+       if (lan937x_is_internal_phy_port(dev, port))
+               return PHY_INTERFACE_MODE_NA;
+
+       /* read interface from REG_PORT_XMII_CTRL_1 register */
+       lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8);
+
+       switch (data8 & PORT_MII_SEL_M) {
+       case PORT_RMII_SEL:
+               interface = PHY_INTERFACE_MODE_RMII;
+               break;
+       case PORT_RGMII_SEL:
+               interface = PHY_INTERFACE_MODE_RGMII;
+               if (data8 & PORT_RGMII_ID_EG_ENABLE)
+                       interface = PHY_INTERFACE_MODE_RGMII_TXID;
+               if (data8 & PORT_RGMII_ID_IG_ENABLE) {
+                       interface = PHY_INTERFACE_MODE_RGMII_RXID;
+                       if (data8 & PORT_RGMII_ID_EG_ENABLE)
+                               interface = PHY_INTERFACE_MODE_RGMII_ID;
+               }
+               break;
+       case PORT_MII_SEL:
+       default:
+               /* Interface is MII */
+               interface = PHY_INTERFACE_MODE_MII;
+               break;
+       }
+       return interface;
+}
+
+static void lan937x_config_cpu_port(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       struct ksz_port *p;
+       int i;
+
+       ds->num_ports = dev->port_cnt;
+
+       for (i = 0; i < dev->port_cnt; i++) {
+               if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) {
+                       phy_interface_t interface;
+                       const char *prev_msg;
+                       const char *prev_mode;
+
+                       dev->cpu_port = i;
+                       dev->host_mask = (1 << dev->cpu_port);
+                       dev->port_mask |= dev->host_mask;
+                       p = &dev->ports[i];
+
+                       /* Read from XMII register to determine host port
+                        * interface.  If set specifically in device tree
+                        * note the difference to help debugging.
+                        */
+                       interface = lan937x_get_interface(dev, i);
+                       if (!p->interface) {
+                               if (dev->compat_interface) {
+                                       dev_warn(dev->dev,
+                                                "Using legacy switch 
\"phy-mode\" property, because it is missing on port %d node. Please update 
your device tree.\n",
+                                                i);
+                                       p->interface = dev->compat_interface;
+                               } else {
+                                       p->interface = interface;
+                               }
+                       }
+                       if (interface && interface != p->interface) {
+                               prev_msg = " instead of ";
+                               prev_mode = phy_modes(interface);
+                       } else {
+                               prev_msg = "";
+                               prev_mode = "";
+                       }
+                       dev_info(dev->dev,
+                                "Port%d: using phy mode %s%s%s\n",
+                                i,
+                                phy_modes(p->interface),
+                                prev_msg,
+                                prev_mode);
+
+                       /* enable cpu port */
+                       lan937x_port_setup(dev, i, true);
+                       p->vid_member = dev->port_mask;
+               }
+       }
+
+       dev->member = dev->host_mask;
+
+       for (i = 0; i < dev->port_cnt; i++) {
+               if (i == dev->cpu_port)
+                       continue;
+               p = &dev->ports[i];
+
+               /* Initialize to non-zero so that lan937x_cfg_port_member() will
+                * be called.
+                */
+               p->vid_member = (1 << i);
+               p->member = dev->port_mask;
+               lan937x_port_stp_state_set(ds, i, BR_STATE_DISABLED);
+       }
+}
+
+static int lan937x_setup(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       int ret = 0;
+
+       dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
+                                      dev->num_vlans, GFP_KERNEL);
+       if (!dev->vlan_cache)
+               return -ENOMEM;
+
+       ret = lan937x_reset_switch(dev);
+       if (ret) {
+               dev_err(ds->dev, "failed to reset switch\n");
+               return ret;
+       }
+
+       /* Required for port partitioning. */
+       lan937x_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY,
+                     true);
+
+       lan937x_config_cpu_port(ds);
+
+       ds->configure_vlan_while_not_filtering = true;
+
+       /* Enable aggressive back off & UNH */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_0, SW_PAUSE_UNH_MODE | SW_NEW_BACKOFF |
+                                               SW_AGGR_BACKOFF, true);
+
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_1, (MULTICAST_STORM_DISABLE
+                                                       | 
NO_EXC_COLLISION_DROP), true);
+
+       /* queue based egress rate limit */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, 
true);
+
+       lan937x_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true);
+
+       /* enable global MIB counter freeze function */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
+
+       /* enable Indirect Access from SPI to the VPHY registers */
+       lan937x_enable_spi_indirect_access(dev);
+
+       /* start switch */
+       lan937x_cfg(dev, REG_SW_OPERATION, SW_START, true);
+
+       ksz_init_mib_timer(dev);
+
+       return 0;
+}
+
+static int lan937x_change_mtu(struct dsa_switch *ds, int port, int mtu)
+{
+       struct ksz_device *dev = ds->priv;
+       u16 max_size;
+
+       if (mtu >= FR_MIN_SIZE) {
+               lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_JUMBO_EN, 
true);
+               max_size = FR_MAX_SIZE;
+       } else {
+               lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_JUMBO_EN, 
false);
+               max_size = FR_MIN_SIZE;
+       }
+       /* Write the frame size in PORT_MAX_FR_SIZE register */
+       lan937x_pwrite16(dev, port, PORT_MAX_FR_SIZE, max_size);
+       return 0;
+}
+
+static int lan937x_get_max_mtu(struct dsa_switch *ds, int port)
+{
+       /* Frame size is 9000 (= 0x2328) if
+        * jumbo frame support is enabled, PORT_JUMBO_EN bit will be enabled
+        * based on mtu in lan937x_change_mtu() API
+        */
+       return FR_MAX_SIZE;
+}
+
+const struct dsa_switch_ops lan937x_switch_ops = {
+       .get_tag_protocol       = lan937x_get_tag_protocol,
+       .setup                  = lan937x_setup,
+       .phy_read               = lan937x_phy_read16,
+       .phy_write              = lan937x_phy_write16,
+       .port_enable            = ksz_enable_port,
+       .port_bridge_join       = ksz_port_bridge_join,
+       .port_bridge_leave      = ksz_port_bridge_leave,
+       .port_stp_state_set     = lan937x_port_stp_state_set,
+       .port_fast_age          = ksz_port_fast_age,
+       .port_max_mtu           = lan937x_get_max_mtu,
+       .port_change_mtu        = lan937x_change_mtu,
+};
+
+int lan937x_switch_register(struct ksz_device *dev)
+{
+       return ksz_switch_register(dev, &lan937x_dev_ops);
+}
+EXPORT_SYMBOL(lan937x_switch_register);
+
+MODULE_AUTHOR("Prasanna Vengateshan Varadharajan 
<prasanna.vengates...@microchip.com>");
+MODULE_DESCRIPTION("Microchip LAN937x Series Switch DSA Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/lan937x_reg.h 
b/drivers/net/dsa/microchip/lan937x_reg.h
new file mode 100644
index 000000000000..d899a43f4d8e
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan937x_reg.h
@@ -0,0 +1,955 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Microchip LAN937X switch register definitions
+ * Copyright (C) 2019-2020 Microchip Technology Inc.
+ */
+#ifndef __LAN937X_REG_H
+#define __LAN937X_REG_H
+
+/* 0 - Operation */
+#define REG_CHIP_ID0__1                        0x0000
+#define REG_CHIP_ID1__1                        0x0001
+#define REG_CHIP_ID2__1                        0x0002
+
+#define CHIP_ID_74                     0x74
+#define CHIP_ID_73                     0x73
+#define CHIP_ID_72                     0x72
+#define CHIP_ID_71                     0x71
+#define CHIP_ID_70                     0x70
+
+#define REG_CHIP_ID3__1                        0x0003
+
+#define REG_GLOBAL_CTRL_0              0x0007
+
+#define SW_PHY_REG_BLOCK               BIT(7)
+#define SW_FAST_MODE                   BIT(3)
+#define SW_FAST_MODE_OVERRIDE          BIT(2)
+
+#define REG_GLOBAL_OPTIONS             0x000F
+
+#define REG_SW_INT_STATUS__4           0x0010
+#define REG_SW_INT_MASK__4             0x0014
+
+#define LUE_INT                                BIT(31)
+#define TRIG_TS_INT                    BIT(30)
+#define APB_TIMEOUT_INT                        BIT(29)
+#define OVER_TEMP_INT                  BIT(28)
+#define HSR_INT                                BIT(27)
+#define PIO_INT                                BIT(26)
+#define POR_READY_INT                  BIT(25)
+
+#define SWITCH_INT_MASK                        \
+       (LUE_INT | TRIG_TS_INT | APB_TIMEOUT_INT | OVER_TEMP_INT | HSR_INT | \
+        PIO_INT | POR_READY_INT)
+
+#define REG_SW_PORT_INT_STATUS__4      0x0018
+#define REG_SW_PORT_INT_MASK__4                0x001C
+
+/* 1 - Global */
+#define REG_SW_GLOBAL_SERIAL_CTRL_0    0x0100
+
+#define SW_LITTLE_ENDIAN               BIT(4)
+#define SPI_AUTO_EDGE_DETECTION                BIT(1)
+#define SPI_CLOCK_OUT_RISING_EDGE      BIT(0)
+
+#define REG_SW_GLOBAL_OUTPUT_CTRL__1   0x0103
+#define SW_ENABLE_REFCLKO              BIT(1)
+#define SW_REFCLKO_IS_125MHZ           BIT(0)
+
+/* 2 - PHY */
+#define REG_SW_POWER_MANAGEMENT_CTRL   0x0201
+
+/* 3 - Operation Control */
+#define REG_SW_OPERATION               0x0300
+
+#define SW_DOUBLE_TAG                  BIT(7)
+#define SW_OVER_TEMP_ENABLE            BIT(2)
+#define SW_RESET                       BIT(1)
+#define SW_START                       BIT(0)
+
+#define REG_SW_LUE_CTRL_0              0x0310
+#define SW_VLAN_ENABLE                 BIT(7)
+#define SW_DROP_INVALID_VID            BIT(6)
+#define SW_AGE_CNT_M                   0x7
+#define SW_AGE_CNT_S                   3
+#define SW_RESV_MCAST_ENABLE           BIT(2)
+
+#define REG_SW_LUE_CTRL_1              0x0311
+
+#define UNICAST_LEARN_DISABLE          BIT(7)
+#define SW_SRC_ADDR_FILTER             BIT(6)
+#define SW_FLUSH_STP_TABLE             BIT(5)
+#define SW_FLUSH_MSTP_TABLE            BIT(4)
+#define SW_FWD_MCAST_SRC_ADDR          BIT(3)
+#define SW_AGING_ENABLE                        BIT(2)
+#define SW_FAST_AGING                  BIT(1)
+#define SW_LINK_AUTO_AGING             BIT(0)
+
+#define REG_SW_LUE_CTRL_2              0x0312
+
+#define SW_MID_RANGE_AGE               BIT(7)
+#define SW_LINK_DOWN_FLUSH             BIT(6)
+#define SW_EGRESS_VLAN_FILTER_DYN      BIT(5)
+#define SW_EGRESS_VLAN_FILTER_STA      BIT(4)
+#define SW_FLUSH_OPTION_M              0x3
+#define SW_FLUSH_OPTION_S              2
+#define SW_FLUSH_OPTION_DYN_MAC                1
+#define SW_FLUSH_OPTION_STA_MAC                2
+#define SW_FLUSH_OPTION_BOTH           3
+
+#define REG_SW_LUE_CTRL_3              0x0313
+#define REG_SW_AGE_PERIOD__1           0x0313
+
+#define REG_SW_LUE_INT_STATUS__1       0x0314
+#define REG_SW_LUE_INT_MASK__1         0x0315
+
+#define LEARN_FAIL_INT                 BIT(2)
+#define WRITE_FAIL_INT                 BIT(0)
+
+#define LUE_INT_MASK                   (LEARN_FAIL_INT | WRITE_FAIL_INT)
+
+#define REG_SW_LUE_INDEX_0__2          0x0316
+
+#define ENTRY_INDEX_M                  0x0FFF
+
+#define REG_SW_LUE_INDEX_1__2          0x0318
+
+#define FAIL_INDEX_M                   0x03FF
+
+#define REG_SW_LUE_INDEX_2__2          0x031A
+
+#define REG_SW_STATIC_AVAIL_ENTRY__4   0x031C
+
+#define SW_INGRESS_FILTERING_NO_LEARN  BIT(15)
+#define SW_STATIC_AVAIL_CNT            0x1FF
+
+#define REG_SW_AGE_PERIOD__2           0x0320
+#define SW_AGE_PERIOD_M                        0xFFF
+
+#define REG_SW_LUE_UNK_UCAST_CTRL__2   0x0322
+#define REG_SW_LUE_UNK_CTRL_0__4       0x0322
+
+#define SW_UNK_UCAST_ENABLE            BIT(15)
+#define SW_UNK_PORTS_M                 0xFF
+
+#define REG_SW_LUE_UNK_MCAST_CTRL__2   0x0324
+#define SW_UNK_MCAST_ENABLE            BIT(15)
+
+#define REG_SW_LUE_UNK_VID_CTRL__2     0x0326
+#define SW_UNK_VID_ENABLE              BIT(15)
+
+#define SW_VLAN_FLUSH_PORTS_M          0xFF
+
+#define REG_SW_STATIC_ENTRY_LIMIT__4   0x032C
+
+#define REG_SW_MAC_CTRL_0                      0x0330
+#define SW_NEW_BACKOFF                 BIT(7)
+#define SW_PAUSE_UNH_MODE              BIT(1)
+#define SW_AGGR_BACKOFF                        BIT(0)
+
+#define REG_SW_MAC_CTRL_1              0x0331
+#define SW_SHORT_IFG                   BIT(7)
+#define MULTICAST_STORM_DISABLE                BIT(6)
+#define SW_BACK_PRESSURE               BIT(5)
+#define FAIR_FLOW_CTRL                 BIT(4)
+#define NO_EXC_COLLISION_DROP          BIT(3)
+#define SW_LEGAL_PACKET_DISABLE                BIT(1)
+#define SW_PASS_SHORT_FRAME            BIT(0)
+
+#define REG_SW_MAC_CTRL_2              0x0332
+#define SW_REPLACE_VID                 BIT(3)
+#define BROADCAST_STORM_RATE_HI                0x07
+
+#define REG_SW_MAC_CTRL_3              0x0333
+#define BROADCAST_STORM_RATE_LO                0xFF
+#define BROADCAST_STORM_RATE           0x07FF
+
+#define REG_SW_MAC_CTRL_4              0x0334
+#define SW_PASS_PAUSE                  BIT(3)
+
+#define REG_SW_MAC_CTRL_5              0x0335
+#define SW_OUT_RATE_LIMIT_QUEUE_BASED  BIT(3)
+
+#define REG_SW_MAC_CTRL_6              0x0336
+#define SW_MIB_COUNTER_FLUSH           BIT(7)
+#define SW_MIB_COUNTER_FREEZE          BIT(6)
+
+#define REG_SW_MRI_CTRL_0              0x0370
+#define SW_IGMP_SNOOP                  BIT(6)
+#define SW_IPV6_MLD_OPTION             BIT(3)
+#define SW_IPV6_MLD_SNOOP              BIT(2)
+#define SW_MIRROR_RX_TX                        BIT(0)
+
+#define REG_SW_MRI_CTRL_1__4           0x0374
+#define REG_SW_MRI_CTRL_2__4           0x0378
+#define REG_SW_CLASS_D_IP_CTRL__4      0x0374
+
+#define SW_CLASS_D_IP_ENABLE           BIT(31)
+
+#define REG_SW_MRI_CTRL_8              0x0378
+#define SW_RED_COLOR_S                 4
+#define SW_YELLOW_COLOR_S              2
+#define SW_GREEN_COLOR_S               0
+#define SW_COLOR_M                     0x3
+
+#define REG_PTP_EVENT_PRIO_CTRL                0x037C
+#define REG_PTP_GENERAL_PRIO_CTRL      0x037D
+#define PTP_PRIO_ENABLE                        BIT(7)
+
+#define REG_SW_QM_CTRL__4              0x0390
+#define PRIO_SCHEME_SELECT_M           KS_PRIO_M
+#define PRIO_SCHEME_SELECT_S           6
+#define PRIO_MAP_3_HI                  0
+#define PRIO_MAP_2_HI                  2
+#define PRIO_MAP_0_LO                  3
+#define UNICAST_VLAN_BOUNDARY          BIT(1)
+
+#define REG_SW_EEE_QM_CTRL__2          0x03C0
+#define REG_SW_EEE_TXQ_WAIT_TIME__2    0x03C2
+
+/* 4 - */
+#define REG_SW_VLAN_ENTRY__4           0x0400
+#define VLAN_VALID                     BIT(31)
+#define VLAN_FORWARD_OPTION            BIT(27)
+#define VLAN_PRIO_M                    KS_PRIO_M
+#define VLAN_PRIO_S                    24
+#define VLAN_MSTP_M                    0x7
+#define VLAN_MSTP_S                    12
+#define VLAN_FID_M                     0x7F
+
+#define REG_SW_VLAN_ENTRY_UNTAG__4     0x0404
+#define REG_SW_VLAN_ENTRY_PORTS__4     0x0408
+#define REG_SW_VLAN_ENTRY_INDEX__2     0x040C
+
+#define VLAN_INDEX_M                   0x0FFF
+
+#define REG_SW_VLAN_CTRL               0x040E
+#define VLAN_START                     BIT(7)
+#define VLAN_ACTION                    0x3
+#define VLAN_WRITE                     1
+#define VLAN_READ                      2
+#define VLAN_CLEAR                     3
+
+#define REG_SW_ALU_INDEX_0             0x0410
+#define ALU_FID_INDEX_S                        16
+#define ALU_FID_SIZE                   127
+#define ALU_MAC_ADDR_HI                        0xFFFF
+
+#define REG_SW_ALU_INDEX_1             0x0414
+#define ALU_DIRECT_INDEX_M             (BIT(12) - 1)
+
+#define REG_SW_ALU_CTRL__4             0x0418
+#define REG_SW_ALU_CTRL(num)   (REG_SW_ALU_CTRL__4 + ((num) * 4))
+
+#define ALU_STA_DYN_CNT                        2
+#define ALU_VALID_CNT_M                        (BIT(14) - 1)
+#define ALU_VALID_CNT_S                        16
+#define ALU_START                      BIT(7)
+#define ALU_VALID                      BIT(6)
+#define ALU_VALID_OR_STOP              BIT(5)
+#define ALU_DIRECT                     BIT(2)
+#define ALU_ACTION                     0x3
+#define ALU_WRITE                      1
+#define ALU_READ                       2
+#define ALU_SEARCH                     3
+
+#define REG_SW_ALU_STAT_CTRL__4                0x041C
+#define ALU_STAT_VALID_CNT_M           (BIT(9) - 1)
+#define ALU_STAT_VALID_CNT_S           20
+#define ALU_STAT_INDEX_M               (BIT(8) - 1)
+#define ALU_STAT_INDEX_S               8
+#define ALU_RESV_MCAST_INDEX_M         (BIT(6) - 1)
+#define ALU_STAT_START                 BIT(7)
+#define ALU_STAT_VALID                 BIT(6)
+#define ALU_STAT_VALID_OR_STOP         BIT(5)
+#define ALU_STAT_USE_FID               BIT(4)
+#define ALU_STAT_DIRECT                        BIT(3)
+#define ALU_RESV_MCAST_ADDR            BIT(2)
+#define ALU_STAT_ACTION                        0x3
+#define ALU_STAT_WRITE                 1
+#define ALU_STAT_READ                  2
+#define ALU_STAT_SEARCH                        3
+
+#define REG_SW_ALU_VAL_A               0x0420
+#define ALU_V_STATIC_VALID             BIT(31)
+#define ALU_V_SRC_FILTER               BIT(30)
+#define ALU_V_DST_FILTER               BIT(29)
+#define ALU_V_PRIO_AGE_CNT_M           (BIT(3) - 1)
+#define ALU_V_PRIO_AGE_CNT_S           26
+#define ALU_V_MSTP_M                   0x7
+
+#define REG_SW_ALU_VAL_B               0x0424
+#define ALU_V_OVERRIDE                 BIT(31)
+#define ALU_V_USE_FID                  BIT(30)
+#define ALU_V_PORT_MAP                 0xFF
+
+#define REG_SW_ALU_VAL_C               0x0428
+#define ALU_V_FID_M                    (BIT(16) - 1)
+#define ALU_V_FID_S                    16
+#define ALU_V_MAC_ADDR_HI              0xFFFF
+
+#define REG_SW_ALU_VAL_D               0x042C
+
+#define PORT_CTRL_ADDR(port, addr)     ((addr) | (((port) + 1)  << 12))
+
+#define REG_GLOBAL_RR_INDEX__1         0x0600
+
+/* VPHY */
+#define REG_VPHY_CTRL__2               0x0700
+#define REG_VPHY_STAT__2               0x0704
+#define REG_VPHY_ID_HI__2              0x0708
+#define REG_VPHY_ID_LO__2              0x070C
+#define REG_VPHY_AUTO_NEG__2           0x0710
+#define REG_VPHY_REMOTE_CAP__2         0x0714
+
+#define REG_VPHY_EXPANSION__2          0x0718
+
+#define REG_VPHY_M_CTRL__2             0x0724
+#define REG_VPHY_M_STAT__2             0x0728
+
+#define REG_VPHY_EXT_STAT__2           0x073C
+#define VPHY_EXT_1000_X_FULL           BIT(15)
+#define VPHY_EXT_1000_X_HALF           BIT(14)
+#define VPHY_EXT_1000_T_FULL           BIT(13)
+#define VPHY_EXT_1000_T_HALF           BIT(12)
+
+#define REG_VPHY_DEVAD_0__2            0x0740
+#define REG_VPHY_DEVAD_1__2            0x0744
+#define REG_VPHY_DEVAD_2__2            0x0748
+#define REG_VPHY_DEVAD_3__2            0x074C
+
+#define VPHY_DEVAD_UPDATE              BIT(7)
+#define VPHY_DEVAD_M                   0x1F
+#define VPHY_DEVAD_S                   8
+
+#define REG_VPHY_SMI_ADDR__2           0x0750
+#define REG_VPHY_SMI_DATA_LO__2                0x0754
+#define REG_VPHY_SMI_DATA_HI__2                0x0758
+
+#define REG_VPHY_IND_ADDR__2           0x075C
+#define REG_VPHY_IND_DATA__2           0x0760
+#define REG_VPHY_IND_CTRL__2           0x0768
+
+#define VPHY_IND_WRITE                 BIT(1)
+#define VPHY_IND_BUSY                  BIT(0)
+
+#define REG_VPHY_SPECIAL_CTRL__2       0x077C
+#define VPHY_SMI_INDIRECT_ENABLE       BIT(15)
+#define VPHY_SW_LOOPBACK               BIT(14)
+#define VPHY_MDIO_INTERNAL_ENABLE      BIT(13)
+#define VPHY_SPI_INDIRECT_ENABLE       BIT(12)
+#define VPHY_PORT_MODE_M               0x3
+#define VPHY_PORT_MODE_S               8
+#define VPHY_MODE_RGMII                        0
+#define VPHY_MODE_MII_PHY              1
+#define VPHY_MODE_SGMII                        2
+#define VPHY_MODE_RMII_PHY             3
+#define VPHY_SW_COLLISION_TEST         BIT(7)
+#define VPHY_SPEED_DUPLEX_STAT_M       0x7
+#define VPHY_SPEED_DUPLEX_STAT_S       2
+#define VPHY_SPEED_1000                        BIT(4)
+#define VPHY_SPEED_100                 BIT(3)
+#define VPHY_FULL_DUPLEX               BIT(2)
+
+/* 0 - Operation */
+#define REG_PORT_DEFAULT_VID           0x0000
+
+#define REG_PORT_CUSTOM_VID            0x0002
+#define REG_PORT_PME_STATUS            0x0013
+
+#define REG_PORT_PME_CTRL              0x0017
+#define PME_WOL_MAGICPKT               BIT(2)
+#define PME_WOL_LINKUP                 BIT(1)
+#define PME_WOL_ENERGY                 BIT(0)
+
+#define REG_PORT_INT_STATUS            0x001B
+#define REG_PORT_INT_MASK              0x001F
+
+#define PORT_TAS_INT                   BIT(5)
+#define PORT_SGMII_INT                 BIT(3)
+#define PORT_PTP_INT                   BIT(2)
+#define PORT_PHY_INT                   BIT(1)
+#define PORT_ACL_INT                   BIT(0)
+
+#define PORT_INT_MASK                  \
+       (                               \
+       PORT_TAS_INT |                  \
+       PORT_SGMII_INT | PORT_PTP_INT | PORT_PHY_INT | PORT_ACL_INT)
+
+#define REG_PORT_CTRL_0                        0x0020
+
+#define PORT_MAC_LOOPBACK              BIT(7)
+#define PORT_MAC_REMOTE_LOOPBACK       BIT(6)
+#define PORT_K2L_INSERT_ENABLE         BIT(5)
+#define PORT_K2L_DEBUG_ENABLE          BIT(4)
+#define PORT_TAIL_TAG_ENABLE           BIT(2)
+#define PORT_QUEUE_SPLIT_ENABLE                0x3
+
+#define REG_PORT_CTRL_1                        0x0021
+#define PORT_SRP_ENABLE                        0x3
+
+#define REG_PORT_STATUS_0              0x0030
+#define PORT_INTF_SPEED_M              0x3
+#define PORT_INTF_SPEED_S              3
+#define PORT_INTF_FULL_DUPLEX          BIT(2)
+#define PORT_TX_FLOW_CTRL              BIT(1)
+#define PORT_RX_FLOW_CTRL              BIT(0)
+
+#define REG_PORT_STATUS_1              0x0034
+
+/* 1 - PHY */
+#define REG_VPHY_SMI_ADDR              0x14
+#define REG_VPHY_SMI_DATA_LO           0x15
+#define REG_VPHY_SMI_DATA_HI           0x16
+
+#define REG_VPHY_SPECIAL_CTRL_STAT     0x1F
+
+#define REG_PORT_T1_PHY_BASIC_CTRL     0x00
+
+#define PORT_T1_PHY_RESET              BIT(15)
+#define PORT_T1_PHY_LOOPBACK           BIT(14)
+#define PORT_T1_SPEED_100MBIT          BIT(13)
+#define PORT_T1_POWER_DOWN             BIT(11)
+#define PORT_T1_ISOLATE                        BIT(10)
+#define PORT_T1_FULL_DUPLEX            BIT(8)
+
+#define REG_PORT_T1_PHY_BASIC_STATUS   0x01
+
+#define PORT_T1_MII_SUPPRESS_CAPABLE   BIT(6)
+#define PORT_T1_LINK_STATUS            BIT(2)
+#define PORT_T1_EXTENDED_CAPABILITY    BIT(0)
+
+#define REG_PORT_T1_PHY_ID_HI          0x02
+#define REG_PORT_T1_PHY_ID_LO          0x03
+
+#define LAN937X_T1_ID_HI               0x0007
+#define LAN937X_T1_ID_LO               0xC150
+
+#define REG_PORT_T1_PHY_M_CTRL 0x09
+
+#define PORT_T1_MANUAL_CFG             BIT(12)
+#define PORT_T1_M_CFG          BIT(11)
+
+#define REG_PORT_T1_PHY_M_STATUS       0x0A
+
+#define PORT_T1_LOCAL_M                BIT(14)
+#define PORT_T1_LOCAL_RX_OK            BIT(13)
+#define PORT_T1_REMOTE_RX_OK           BIT(12)
+#define PORT_T1_IDLE_ERR_CNT_M         0xFF
+
+#define REG_PORT_T1_MDIO_CTRL_1                0x0F
+
+#define T1_MDIO_WAKE_OUT_PIN_REQ       BIT(0)
+
+#define REG_PORT_T1_MDIO_CTRL_2                0x10
+
+#define T1_MDIO_MDPREBP                        BIT(15)
+#define T1_MDIO_PHYADBP                        BIT(14)
+#define T1_MDIO_WAKE_REQ               BIT(13)
+#define T1_MDIO_SLEEP_REQ              BIT(12)
+#define TI_MDIO_CTRL_CLOCK_SKEW                0x0C00
+#define T1_MDIO_TX_TERNARY_SYM                 0x0300
+#define T1_MDIO_PCS_SC_RESET                   BIT(7)
+#define T1_MDIO_ENERGY_DETECT_M        BIT(6)
+#define T1_MDIO_IGNORE_IDLE                    BIT(5)
+#define T1_MDIO_TIME_OUT_CNT                   0x001E
+#define T1_MDIO_TIME_OUT_ENABLE                BIT(0)
+
+#define REG_PORT_T1_MODE_STAT                  0x11
+#define T1_PORT_DSCR_LOCK_STATUS_MSK   BIT(3)
+#define T1_PORT_LINK_UP_MSK                            BIT(0)
+
+#define REG_PORT_T1_LOOPBACK_CTRL      0x12
+
+#define REG_PORT_T1_RESET_CTRL         0x13
+
+#define T1_PHYADDR_S                   11
+
+#define REG_PORT_T1_EXT_REG_CTRL       0x14
+
+#define T1_PCS_STS_CNT_RESET           BIT(15)
+#define T1_IND_DATA_READ               BIT(12)
+#define T1_IND_DATA_WRITE              BIT(11)
+#define T1_REG_BANK_SEL_M              0x7
+#define T1_REG_BANK_SEL_S              8
+#define T1_REG_BANK_SEL_INST           5
+#define T1_REG_BANK_SEL_DSP            4
+#define T1_REG_BANK_SEL_AFE            3
+#define T1_REG_BANK_SEL_PCS            2
+#define T1_REG_BANK_SEL_MISC           1
+#define T1_REG_ADDR_M                  0xFF
+
+#define REG_PORT_T1_EXT_REG_RD_DATA    0x15
+#define REG_PORT_T1_EXT_REG_WR_DATA    0x16
+
+#define REG_PORT_T1_PCS_CTRL           0x17
+
+#define REG_PORT_T1_PHY_INT_STATUS     0x18
+#define REG_PORT_T1_PHY_INT_ENABLE     0x19
+
+#define T1_PHY_CTRL_MAXWAIT_TIMER_INT  BIT(8)
+#define T1_ZERO_TIMER_INT              BIT(7)
+#define T1_ENERGY_OFF_INT              BIT(6)
+#define T1_IDLE_ERR_THRESH_DET_INT     BIT(4)
+#define T1_LINK_UP_INT                 BIT(2)
+#define T1_LINK_DOWN_INT               BIT(1)
+#define T1_ENERGY_ON_INT               BIT(0)
+
+#define REG_PORT_T1_POWER_DOWN_CTRL    0x1A
+
+#define T1_BIST_LINK_UP                        BIT(15)
+#define T1_EMERGENCY_STOP              BIT(14)
+#define T1_PTP_ENABLE                  BIT(13)
+#define T1_PCS_LINK_CTRL_ENABLE                BIT(12)
+#define T1_DSP_START_EQUALIZER         BIT(11)
+#define T1_START_ZQ_CAL                        BIT(10)
+#define T1_FORCE_TX_ENABLE             BIT(9)
+#define T1_HW_INIT_SEQ_ENABLE          BIT(8)
+#define T1_WAKE_ENABLE                 BIT(7)
+#define T1_LINK_UP_REQ                 BIT(6)
+#define T1_AUTO_CLR_EPDWRDOWN          BIT(5)
+#define T1_ENERGY_DETECT_POWER_DOWN    BIT(4)
+#define T1_FORCE_ENERGY_DETECT         BIT(3)
+#define T1_AUTO_SLEEP_WAKEUP           BIT(2)
+#define T1_ENERGY_DETECT_HW_ENABLE     BIT(1)
+#define T1_ENERGY_DETECT_ENABLE                BIT(0)
+
+#define REG_PORT_T1_BIST_CTRL          0x1B
+#define REG_PORT_T1_BIST_STAT          0x1C
+#define REG_PORT_T1_BIST_ERR_CNT_STS   0x1D
+#define REG_PORT_T1_PCS_RX_ERR_CNT_STS 0x1E
+#define REG_PORT_T1_TS_CTRL_STAT       0x1F
+
+#define REG_PORT_T1_PCS_DESCRM_CTRL_0  0x00
+
+#define T1_PCS_SEND_IDLE_LOC_RCV_STS   BIT(15)
+#define T1_PCS_DESCR_RELOCK_ON_IDLE    BIT(14)
+#define T1_PCS_DESCR_RELOCK_ON_RCV     BIT(13)
+#define T1_PCS_DESCR_RELOCK_ON_EQ      BIT(12)
+#define T1_PCS_DESCR_LOCK_SYM_CNT      0x0FC0
+#define T1_PCS_DESCR_LOCK_CHK_WIN      0x003F
+
+#define REG_PORT_T1_PCS_DESCRM_CTRL_1  0x01
+
+#define T1_PCS_DESCR_PIPE_DELAY                0x0700
+#define T1_PCS_FEED_DESCR_LFSR_WIN     0x003F
+
+#define REG_PORT_T1_PCS_EQ_TIMER_CTRL  0x02
+
+#define REG_PORT_T1_PCS_RX_ERR_CNT     0x0E
+
+#define REG_PORT_T1_PCS_ED_STABILITY   0x26
+
+#define REG_PORT_TX_PHY_CTRL           0x00
+#define REG_PORT_TX_PHY_STATUS         0x01
+#define REG_PORT_TX_PHY_ID_HI          0x02
+#define REG_PORT_TX_PHY_ID_LO          0x03
+#define REG_PORT_TX_PHY_AUTO_NEG       0x04
+#define REG_PORT_TX_PHY_REMOTE_CAP     0x05
+
+#define REG_PORT_TX_6                  0x06
+#define REG_PORT_TX_7                  0x07
+#define REG_PORT_TX_10                 0x10
+#define REG_PORT_TX_11                 0x11
+
+#define REG_PORT_TX_SPECIAL_MODES      0x12
+
+#define TX_SPECIAL_CFG_M               0x7
+#define TX_SPECIAL_CFG_S               5
+#define TX_PHYADDR_M                   0x1F
+
+#define REG_PORT_TX_13                 0x13
+
+#define REG_PORT_TX_IND_CTRL           0x14
+
+#define TX_IND_DATA_READ               BIT(15)
+#define TX_IND_DATA_WRITE              BIT(14)
+#define TX_REG_BANK_SEL_M              0x7
+#define TX_REG_BANK_SEL_S              11
+#define TX_REG_BANK_SEL_VMDAC          7
+#define TX_REG_BANK_SEL_BIST           3
+#define TX_REG_BANK_SEL_WOL            1
+#define TX_REG_BANK_SEL_DSP            0
+#define TX_TEST_MODE                   BIT(10)
+#define TX_READ_ADDR_M                 0x1F
+#define TX_READ_ADDR_S                 5
+#define TX_WRITE_ADDR_M                        0x1F
+
+#define REG_PORT_TX_READ_DATA_LO       0x15
+#define REG_PORT_TX_READ_DATA_HI       0x16
+#define REG_PORT_TX_WRITE_DATA         0x17
+
+#define REG_PORT_TX_PHY_INT_STATUS     0x1D
+#define REG_PORT_TX_PHY_INT_ENABLE     0x1E
+
+#define TX_ENERGY_ON_INT               BIT(7)
+#define TX_AUTO_NEG_COMPLETE_INT       BIT(6)
+#define TX_LINK_DOWN_INT               BIT(4)
+#define TX_AUTO_NEG_ACK_INT            BIT(3)
+#define TX_AUTO_NEG_PAGE_RCV_INT       BIT(1)
+
+#define REG_PORT_TX_1F                 0x1F
+
+#define TX_DSP_DCBLW                   0x00
+
+#define TX_DSP_DCBLW_VAL               0x9aa2
+
+#define TX_DSP_A5_CONFIG               0x16
+
+#define TX_A5_TXCLKPHSEL_M             0x7
+#define TX_A5_TXCLKPHSEL_S             12
+#define TX_A5_TXCLK_0_NS               0
+#define TX_A5_TXCLK_1_NS               1
+#define TX_A5_TXCLK_2_NS               2
+#define TX_A5_TXCLK_3_NS               3
+#define TX_A5_TXCLK_4_NS               4
+#define TX_A5_TXCLK_5_NS               5
+#define TX_A5_TXCLK_6_NS               6
+#define TX_A5_TXCLK_7_NS               7
+
+#define TX_DSP_A10_CONFIG              0x1C
+
+#define TX_DSP_A10_CONFIG_VAL          0x9000
+
+#define TX_DSP_A11_CONFIG              0x1D
+
+#define TX_DSP_A11_CONFIG_VAL          0x7600
+
+#define TX_BIST_FR_PLL_DIV0            0x1C
+#define TX_BIST_FR_PLL_DIV1            0x1D
+
+#define TX_FR_PLL_DIV0                 0x0
+#define TX_FR_PLL_DIV1                 0x1280
+
+#define TX_VMDAC_ZQ_CAL_CTRL           0x00
+
+#define TX_START_ZQ_CAL                        BIT(0)
+#define TX_BYPASS_ZQ_CAL               BIT(1)
+
+#define TX_VMDAC_ZQ_CAL_STAT           0x01
+
+#define TX_VMDAC_CTRL0                 0x02
+#define TX_VDVREF_EN                   BIT(0)
+#define TX_VDVEXT_EN                   BIT(1)
+#define TX_A_ZEN                       BIT(11)
+#define TX_A_RXZEN                     BIT(12)
+#define TX_VD_INTIR_EN                 BIT(15)
+
+#define TX_VMDAC_CTRL0_VAL             0x9783
+#define TX_VMDAC_CTRL1                 0x03
+
+#define TX_10BT_VD_EN                  BIT(0)
+#define TX_B_ZEN                       BIT(11)
+#define TX_B_RXZEN                     BIT(12)
+#define TX_VD_PD                       BIT(15)
+
+#define TX_VMDAC_CTRL1_VAL             0x7784
+#define TX_VMDAC_MISC_PCS_CTRL0                0x05
+
+#define TX_MISC_PCS_CTRL0_13           BIT(13)
+#define TX_VMDAC_MISC_PCS_CTRL1                0x06
+
+#define REG_PORT_T1_PHY_CTRL_BASE      0x0100
+#define REG_PORT_TX_PHY_CTRL_BASE      0x0280
+#define REG_TX_PHY_CTRL_BASE           0x0980
+
+#define REG_PORT_PHY_CTRL              0x0100
+
+#define PORT_PHY_RESET                 BIT(15)
+#define PORT_PHY_LOOPBACK              BIT(14)
+#define PORT_SPEED_100MBIT             BIT(13)
+#define PORT_AUTO_NEG_ENABLE           BIT(12)
+#define PORT_POWER_DOWN                        BIT(11)
+#define PORT_ISOLATE                   BIT(10)
+#define PORT_AUTO_NEG_RESTART          BIT(9)
+#define PORT_FULL_DUPLEX               BIT(8)
+#define PORT_COLLISION_TEST            BIT(7)
+#define PORT_SPEED_1000MBIT            BIT(6)
+
+#define REG_PORT_PHY_STATUS            0x0102
+
+#define PORT_100BT4_CAPABLE            BIT(15)
+#define PORT_100BTX_FD_CAPABLE         BIT(14)
+#define PORT_100BTX_CAPABLE            BIT(13)
+#define PORT_10BT_FD_CAPABLE           BIT(12)
+#define PORT_10BT_CAPABLE              BIT(11)
+#define PORT_EXTENDED_STATUS           BIT(8)
+#define PORT_MII_SUPPRESS_CAPABLE      BIT(6)
+#define PORT_AUTO_NEG_ACKNOWLEDGE      BIT(5)
+#define PORT_REMOTE_FAULT              BIT(4)
+#define PORT_AUTO_NEG_CAPABLE          BIT(3)
+#define PORT_LINK_STATUS               BIT(2)
+#define PORT_JABBER_DETECT             BIT(1)
+#define PORT_EXTENDED_CAPABILITY       BIT(0)
+
+#define REG_PORT_PHY_ID_HI             0x0104
+#define REG_PORT_PHY_ID_LO             0x0106
+
+#define LAN937X_ID_HI                  0x0007
+#define LAN937X_ID_LO                  0x1951
+
+#define REG_PORT_PHY_1000_CTRL         0x0112
+#define PORT_AUTO_NEG_MANUAL                   BIT(12)
+#define PORT_AUTO_NEG_M                BIT(11)
+#define PORT_AUTO_NEG_M_PREFERRED      BIT(10)
+#define PORT_AUTO_NEG_1000BT_FD                BIT(9)
+#define PORT_AUTO_NEG_1000BT                   BIT(8)
+
+#define REG_PORT_PHY_1000_STATUS       0x0114
+
+#define REG_PORT_PHY_RXER_COUNTER      0x012A
+#define REG_PORT_PHY_INT_ENABLE                0x0136
+#define REG_PORT_PHY_INT_STATUS                0x0137
+
+/* Same as PORT_PHY_LOOPBACK */
+#define PORT_PHY_PCS_LOOPBACK          BIT(0)
+
+#define REG_PORT_PHY_DIGITAL_DEBUG_2   0x013A
+
+#define REG_PORT_PHY_DIGITAL_DEBUG_3   0x013C
+#define PORT_100BT_FIXED_LATENCY       BIT(15)
+
+#define REG_PORT_PHY_PHY_CTRL          0x013E
+#define PORT_INT_PIN_HIGH              BIT(14)
+#define PORT_ENABLE_JABBER             BIT(9)
+#define PORT_STAT_SPEED_1000MBIT       BIT(6)
+#define PORT_STAT_SPEED_100MBIT                BIT(5)
+#define PORT_STAT_SPEED_10MBIT         BIT(4)
+#define PORT_STAT_FULL_DUPLEX          BIT(3)
+
+/* Same as PORT_PHY_STAT_M */
+#define PORT_STAT_M            BIT(2)
+#define PORT_RESET                     BIT(1)
+#define PORT_LINK_STATUS_FAIL          BIT(0)
+
+/* 3 - xMII */
+#define REG_PORT_XMII_CTRL_0           0x0300
+#define PORT_SGMII_SEL                 BIT(7)
+#define PORT_MII_FULL_DUPLEX           BIT(6)
+#define PORT_MII_TX_FLOW_CTRL          BIT(5)
+#define PORT_MII_100MBIT               BIT(4)
+#define PORT_MII_RX_FLOW_CTRL          BIT(3)
+#define PORT_GRXC_ENABLE               BIT(0)
+
+#define REG_PORT_XMII_CTRL_1           0x0301
+#define PORT_MII_NOT_1GBIT             BIT(6)
+#define PORT_MII_SEL_EDGE              BIT(5)
+#define PORT_RGMII_ID_IG_ENABLE                BIT(4)
+#define PORT_RGMII_ID_EG_ENABLE                BIT(3)
+#define PORT_MII_MAC_MODE              BIT(2)
+#define PORT_MII_SEL_M                 0x3
+#define PORT_RGMII_SEL                 0x0
+#define PORT_RMII_SEL                  0x1
+#define PORT_MII_SEL                   0x2
+
+#define REG_PORT_XMII_CTRL_2           0x0302
+#define PORT_RGMII_RX_STS_ENABLE       BIT(0)
+
+#define REG_PORT_XMII_CTRL_4           0x0304
+#define REG_PORT_XMII_CTRL_5           0x0305
+
+/* 4 - MAC */
+#define REG_PORT_MAC_CTRL_0            0x0400
+#define PORT_CHECK_LENGTH              BIT(2)
+#define PORT_BROADCAST_STORM           BIT(1)
+#define PORT_JUMBO_PACKET              BIT(0)
+
+#define REG_PORT_MAC_CTRL_1            0x0401
+#define PORT_BACK_PRESSURE             BIT(3)
+#define PORT_PASS_ALL                  BIT(0)
+
+#define REG_PORT_MAC_CTRL_2            0x0402
+#define PORT_100BT_EEE_DISABLE         BIT(7)
+#define PORT_1000BT_EEE_DISABLE                BIT(6)
+
+#define REG_PORT_MAC_IN_RATE_LIMIT     0x0403
+
+#define REG_PORT_MTU__2                        0x0404
+#define PORT_RATE_LIMIT_M              (BIT(7) - 1)
+
+/* 5 - MIB Counters */
+#define REG_PORT_MIB_CTRL_STAT__4      0x0500
+#define MIB_COUNTER_OVERFLOW           BIT(31)
+#define MIB_COUNTER_VALID              BIT(30)
+#define MIB_COUNTER_READ               BIT(25)
+#define MIB_COUNTER_FLUSH_FREEZE       BIT(24)
+#define MIB_COUNTER_INDEX_M            (BIT(8) - 1)
+#define MIB_COUNTER_INDEX_S            16
+#define MIB_COUNTER_DATA_HI_M          0xF
+
+#define REG_PORT_MIB_DATA              0x0504
+
+/* 8 - Classification and Policing */
+#define REG_PORT_MRI_MIRROR_CTRL       0x0800
+#define PORT_MIRROR_RX                 BIT(6)
+#define PORT_MIRROR_TX                 BIT(5)
+#define PORT_MIRROR_SNIFFER            BIT(1)
+
+#define REG_PORT_MRI_PRIO_CTRL         0x0801
+#define PORT_HIGHEST_PRIO              BIT(7)
+#define PORT_OR_PRIO                   BIT(6)
+#define PORT_MAC_PRIO_ENABLE           BIT(4)
+#define PORT_VLAN_PRIO_ENABLE          BIT(3)
+#define PORT_802_1P_PRIO_ENABLE                BIT(2)
+#define PORT_DIFFSERV_PRIO_ENABLE      BIT(1)
+#define PORT_ACL_PRIO_ENABLE           BIT(0)
+
+#define REG_PORT_MRI_MAC_CTRL          0x0802
+#define PORT_USER_PRIO_CEILING         BIT(7)
+#define PORT_DROP_NON_VLAN             BIT(4)
+#define PORT_DROP_TAG                  BIT(3)
+#define PORT_BASED_PRIO_M              KS_PRIO_M
+#define PORT_BASED_PRIO_S              0
+
+#define REG_PORT_MRI_TC_MAP__4         0x0808
+
+/* 9 - Shaping */
+#define REG_PORT_MTI_QUEUE_INDEX__4    0x0900
+
+#define REG_PORT_MTI_QUEUE_CTRL_0__4   0x0904
+#define MTI_PVID_REPLACE               BIT(0)
+
+#define REG_PORT_MTI_QUEUE_CTRL_0      0x0914
+
+/* A - QM */
+#define REG_PORT_QM_CTRL__4            0x0A00
+#define PORT_QM_DROP_PRIO_M            0x3
+
+#define REG_PORT_VLAN_MEMBERSHIP__4    0x0A04
+
+#define REG_PORT_QM_QUEUE_INDEX__4     0x0A08
+#define PORT_QM_QUEUE_INDEX_S          24
+#define PORT_QM_BURST_SIZE_S           16
+#define PORT_QM_MIN_RESV_SPACE_M       (BIT(11) - 1)
+
+#define REG_PORT_QM_WATER_MARK__4      0x0A0C
+#define PORT_QM_HI_WATER_MARK_S                16
+#define PORT_QM_LO_WATER_MARK_S                0
+#define PORT_QM_WATER_MARK_M           (BIT(11) - 1)
+
+#define REG_PORT_QM_TX_CNT_0__4                0x0A10
+#define PORT_QM_TX_CNT_USED_S          0
+#define PORT_QM_TX_CNT_M               (BIT(11) - 1)
+
+#define REG_PORT_QM_TX_CNT_1__4                0x0A14
+#define PORT_QM_TX_CNT_CALCULATED_S    16
+#define PORT_QM_TX_CNT_AVAIL_S         0
+
+/* B - LUE */
+#define REG_PORT_LUE_CTRL              0x0B00
+
+#define PORT_VLAN_LOOKUP_VID_0         BIT(7)
+#define PORT_INGRESS_FILTER            BIT(6)
+#define PORT_DISCARD_NON_VID           BIT(5)
+#define PORT_MAC_BASED_802_1X          BIT(4)
+#define PORT_SRC_ADDR_FILTER           BIT(3)
+
+#define REG_PORT_LUE_MSTP_INDEX                0x0B01
+
+#define REG_PORT_LUE_MSTP_STATE                0x0B04
+
+#define PORT_TX_ENABLE                 BIT(2)
+#define PORT_RX_ENABLE                 BIT(1)
+#define PORT_LEARN_DISABLE             BIT(0)
+
+#define REG_PORT_LUE_LEARN_CNT__2      0x0B08
+
+#define REG_PORT_LUE_UNK_UCAST_CTRL__2 0x0B0E
+#define REG_PORT_LUE_UNK_MCAST_CTRL__2 0x0B10
+#define REG_PORT_LUE_UNK_VID_CTRL__2   0x0B12
+
+#define PORT_UNK_UCAST_ENABLE          BIT(15)
+#define PORT_UNK_MCAST_ENABLE          BIT(15)
+#define PORT_UNK_VID_ENABLE            BIT(15)
+
+#define PRIO_QUEUES                    8
+#define RX_PRIO_QUEUES                 8
+#define KS_PRIO_IN_REG                 2
+#define TOTAL_PORT_NUM                 8
+
+#define LAN937X_COUNTER_NUM            0x20
+#define TOTAL_LAN937X_COUNTER_NUM      (LAN937X_COUNTER_NUM + 2 + 2)
+
+#define SWITCH_COUNTER_NUM             LAN937X_COUNTER_NUM
+
+#define P_BCAST_STORM_CTRL             REG_PORT_MAC_CTRL_0
+#define P_PRIO_CTRL                    REG_PORT_MRI_PRIO_CTRL
+#define P_MIRROR_CTRL                  REG_PORT_MRI_MIRROR_CTRL
+#define P_STP_CTRL                     REG_PORT_LUE_MSTP_STATE
+#define P_PHY_CTRL                     REG_PORT_PHY_CTRL
+#define P_NEG_RESTART_CTRL             REG_PORT_PHY_CTRL
+#define P_LINK_STATUS                  REG_PORT_PHY_STATUS
+#define P_SPEED_STATUS                 REG_PORT_PHY_PHY_CTRL
+#define P_RATE_LIMIT_CTRL              REG_PORT_MAC_IN_RATE_LIMIT
+
+#define S_LINK_AGING_CTRL              REG_SW_LUE_CTRL_1
+#define S_MIRROR_CTRL                  REG_SW_MRI_CTRL_0
+#define S_REPLACE_VID_CTRL             REG_SW_MAC_CTRL_2
+#define S_802_1P_PRIO_CTRL             REG_SW_MAC_802_1P_MAP_0
+#define S_TOS_PRIO_CTRL                        REG_SW_MAC_TOS_PRIO_0
+#define S_FLUSH_TABLE_CTRL             REG_SW_LUE_CTRL_1
+
+#define REG_SWITCH_RESET               REG_RESET_CTRL
+
+#define SW_FLUSH_DYN_MAC_TABLE         SW_FLUSH_MSTP_TABLE
+
+#define MAX_TIMESTAMP_UNIT             2
+#define MAX_TRIG_UNIT                  3
+#define MAX_TIMESTAMP_EVENT_UNIT       8
+#define MAX_GPIO                       2
+#define MAX_CLOCK                      2
+
+#define PTP_TRIG_UNIT_M                        (BIT(MAX_TRIG_UNIT) - 1)
+#define PTP_TS_UNIT_M                  (BIT(MAX_TIMESTAMP_UNIT) - 1)
+
+#define TAIL_TAG_PTP                   BIT(7)
+#define TAIL_TAG_NEXT_CHIP             BIT(6)
+#define TAIL_TAG_K2L                   BIT(5)
+#define TAIL_TAG_PTP_1_STEP            BIT(4)
+#define TAIL_TAG_PTP_P2P               BIT(3)
+#define TAIL_TAG_RX_PORTS_M            0x7
+
+/* 148,800 frames * 67 ms / 100 */
+#define BROADCAST_STORM_VALUE          9969
+
+#define SW_CHECK_LENGTH                        BIT(3)
+
+#define FR_MIN_SIZE            1522
+#define FR_MAX_SIZE            9000
+
+#define PORT_JUMBO_EN                  BIT(0)
+#define PORT_FR_CHK_LENGTH             BIT(2)
+#define PORT_MAX_FR_SIZE               0x404
+
+#define FR_SIZE_CPU_PORT               1540
+
+#define REG_PORT_CTRL_0                                0x0020
+#define PORT_MAC_LOOPBACK                      BIT(7)
+#define PORT_FORCE_TX_FLOW_CTRL                BIT(5)
+#define PORT_FORCE_RX_FLOW_CTRL                BIT(3)
+
+#define PORT_QUEUE_SPLIT_ENABLE                0x3
+
+/* Get fid from vid, fid 0 is not used if vid is greater than 127 */
+#define LAN937X_GET_FID(vid)   (((vid) % ALU_FID_SIZE) + 1)
+
+/* Driver set switch broadcast storm protection at 10% rate. */
+#define BROADCAST_STORM_PROT_RATE      10
+
+#define MII_BMSR_100BASE_TX_FD         BIT(14)
+
+#define PHY_LINK_UP                                    1
+#define PHY_LINK_DOWN                          0
+
+/*The port number as per the datasheet*/
+#define RGMII_2_PORT_NUM               5
+#define RGMII_1_PORT_NUM               6
+#define SGMII_PORT_NUM                 4
+#define TXPHY_PORT_NUM                 4
+
+#define GET_CHIP_ID_LSB(chip_id)       (((chip_id) >> 8) & 0xff)
+#define LAN937X_RGMII_2_PORT           (RGMII_2_PORT_NUM - 1)
+#define LAN937X_RGMII_1_PORT           (RGMII_1_PORT_NUM - 1)
+#define LAN937X_SGMII_PORT                     (SGMII_PORT_NUM - 1)
+#define LAN937X_TXPHY_PORT                     (TXPHY_PORT_NUM - 1)
+
+#endif
diff --git a/drivers/net/dsa/microchip/lan937x_spi.c 
b/drivers/net/dsa/microchip/lan937x_spi.c
new file mode 100644
index 000000000000..20ee931c448d
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan937x_spi.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Microchip LAN937X switch driver register access through SPI
+ * Copyright (C) 2019-2020 Microchip Technology Inc.
+ */
+#include <asm/unaligned.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "ksz_common.h"
+
+#define SPI_ADDR_SHIFT                         24
+#define SPI_ADDR_ALIGN                         3
+#define SPI_TURNAROUND_SHIFT           5
+
+KSZ_REGMAP_TABLE(lan937x, 32, SPI_ADDR_SHIFT,
+                SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);
+
+static int lan937x_spi_probe(struct spi_device *spi)
+{
+       struct regmap_config rc;
+       struct ksz_device *dev;
+       int i, ret;
+
+       dev = ksz_switch_alloc(&spi->dev, spi);
+       if (!dev)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(lan937x_regmap_config); i++) {
+               rc = lan937x_regmap_config[i];
+               rc.lock_arg = &dev->regmap_mutex;
+               dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
+               if (IS_ERR(dev->regmap[i])) {
+                       ret = PTR_ERR(dev->regmap[i]);
+                       dev_err(&spi->dev,
+                               "Failed to initialize regmap%i: %d\n",
+                               lan937x_regmap_config[i].val_bits, ret);
+                       return ret;
+               }
+       }
+
+       if (spi->dev.platform_data)
+               dev->pdata = spi->dev.platform_data;
+
+       ret = lan937x_switch_register(dev);
+
+       /* Main DSA driver may not be started yet. */
+       if (ret)
+               return ret;
+
+       spi_set_drvdata(spi, dev);
+
+       return 0;
+}
+
+static int lan937x_spi_remove(struct spi_device *spi)
+{
+       struct ksz_device *dev = spi_get_drvdata(spi);
+
+       if (dev)
+               ksz_switch_remove(dev);
+
+       return 0;
+}
+
+static void lan937x_spi_shutdown(struct spi_device *spi)
+{
+       struct ksz_device *dev = spi_get_drvdata(spi);
+
+       if (dev && dev->dev_ops->shutdown)
+               dev->dev_ops->shutdown(dev);
+}
+
+static const struct of_device_id lan937x_dt_ids[] = {
+       { .compatible = "microchip,lan9370"},
+       { .compatible = "microchip,lan9371"},
+       { .compatible = "microchip,lan9372"},
+       { .compatible = "microchip,lan9373"},
+       { .compatible = "microchip,lan9374"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, lan937x_dt_ids);
+
+static struct spi_driver lan937x_spi_driver = {
+       .driver = {
+               .name   = "lan937x-switch",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(lan937x_dt_ids),
+       },
+       .probe  = lan937x_spi_probe,
+       .remove = lan937x_spi_remove,
+       .shutdown = lan937x_spi_shutdown,
+};
+
+module_spi_driver(lan937x_spi_driver);
+
+MODULE_ALIAS("spi:lan937x");
+
+MODULE_AUTHOR("Prasanna Vengateshan Varadharajan 
<prasanna.vengates...@microchip.com>");
+MODULE_DESCRIPTION("Microchip LAN937x Series Switch SPI access Driver");
+MODULE_LICENSE("GPL");
-- 
2.25.1

Reply via email to