net: dsa: microchip: rename ksz8 series files
authorPieter Van Trappen <pieter.van.trappen@cern.ch>
Wed, 4 Sep 2024 06:27:40 +0000 (08:27 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 6 Sep 2024 07:41:35 +0000 (08:41 +0100)
The first KSZ8 series implementation was done for a KSZ8795 device but
since several other KSZ8 devices have been added. Rename these files
to adhere to the ksz8 naming convention as already used in most
functions and the existing ksz8.h; add an explanatory note.

Signed-off-by: Pieter Van Trappen <pieter.van.trappen@cern.ch>
Acked-by: Arun Ramadoss <arun.ramadoss@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/microchip/Kconfig
drivers/net/dsa/microchip/Makefile
drivers/net/dsa/microchip/ksz8.c [new file with mode: 0644]
drivers/net/dsa/microchip/ksz8795.c [deleted file]
drivers/net/dsa/microchip/ksz8795_reg.h [deleted file]
drivers/net/dsa/microchip/ksz8_reg.h [new file with mode: 0644]

index c1b906c05a025cbf3ed3f0b1b0f793a0c6997fdf..12a86585a77fdb8b9a120a127bcc350dd93e4712 100644 (file)
@@ -1,14 +1,17 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menuconfig NET_DSA_MICROCHIP_KSZ_COMMON
-       tristate "Microchip KSZ8795/KSZ9477/LAN937x series switch support"
+       tristate "Microchip KSZ8XXX/KSZ9XXX/LAN937X series switch support"
        depends on NET_DSA
        select NET_DSA_TAG_KSZ
        select NET_DSA_TAG_NONE
        select NET_IEEE8021Q_HELPERS
        select DCB
        help
-         This driver adds support for Microchip KSZ9477 series switch and
-         KSZ8795/KSZ88x3 switch chips.
+         This driver adds support for Microchip KSZ8, KSZ9 and
+         LAN937X series switch chips, being KSZ8863/8873,
+         KSZ8895/8864, KSZ8794/8795/8765,
+         KSZ9477/9897/9896/9567/8567, KSZ9893/9563/8563 and
+         LAN9370/9371/9372/9373/9374.
 
 config NET_DSA_MICROCHIP_KSZ9477_I2C
        tristate "KSZ series I2C connected switch driver"
index 1cfba1ec9355a35b7e9caa26897f98b348e78b3c..9347cfb3d0b5e75335a2a0edb20d4b1daa66b583 100644 (file)
@@ -2,7 +2,7 @@
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)     += ksz_switch.o
 ksz_switch-objs := ksz_common.o ksz_dcb.o
 ksz_switch-objs += ksz9477.o ksz9477_acl.o ksz9477_tc_flower.o
-ksz_switch-objs += ksz8795.o
+ksz_switch-objs += ksz8.o
 ksz_switch-objs += lan937x_main.o
 
 ifdef CONFIG_NET_DSA_MICROCHIP_KSZ_PTP
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
new file mode 100644 (file)
index 0000000..7af3c08
--- /dev/null
@@ -0,0 +1,1975 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip KSZ8XXX series switch driver
+ *
+ * It supports the following switches:
+ * - KSZ8863, KSZ8873 aka KSZ88X3
+ * - KSZ8895, KSZ8864 aka KSZ8895 family
+ * - KSZ8794, KSZ8795, KSZ8765 aka KSZ87XX
+ * Note that it does NOT support:
+ * - KSZ8563, KSZ8567 - see KSZ9477 driver
+ *
+ * Copyright (C) 2017 Microchip Technology Inc.
+ *     Tristram Ha <Tristram.Ha@microchip.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/if_vlan.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_data/microchip-ksz.h>
+#include <linux/phy.h>
+#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/micrel_phy.h>
+#include <net/dsa.h>
+#include <net/switchdev.h>
+#include <linux/phylink.h>
+
+#include "ksz_common.h"
+#include "ksz8_reg.h"
+#include "ksz8.h"
+
+static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
+{
+       regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0);
+}
+
+static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
+                        bool set)
+{
+       regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset),
+                          bits, set ? bits : 0);
+}
+
+/**
+ * ksz8_ind_write8 - EEE/ACL/PME indirect register write
+ * @dev: The device structure.
+ * @table: Function & table select, register 110.
+ * @addr: Indirect access control, register 111.
+ * @data: The data to be written.
+ *
+ * This function performs an indirect register write for EEE, ACL or
+ * PME switch functionalities. Both 8-bit registers 110 and 111 are
+ * written at once with ksz_write16, using the serial multiple write
+ * functionality.
+ *
+ * Return: 0 on success, or an error code on failure.
+ */
+static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
+{
+       const u16 *regs;
+       u16 ctrl_addr;
+       int ret = 0;
+
+       regs = dev->info->regs;
+
+       mutex_lock(&dev->alu_mutex);
+
+       ctrl_addr = IND_ACC_TABLE(table) | addr;
+       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+       if (!ret)
+               ret = ksz_write8(dev, regs[REG_IND_BYTE], data);
+
+       mutex_unlock(&dev->alu_mutex);
+
+       return ret;
+}
+
+/**
+ * ksz8_ind_read8 - EEE/ACL/PME indirect register read
+ * @dev: The device structure.
+ * @table: Function & table select, register 110.
+ * @addr: Indirect access control, register 111.
+ * @val: The value read.
+ *
+ * This function performs an indirect register read for EEE, ACL or
+ * PME switch functionalities. Both 8-bit registers 110 and 111 are
+ * written at once with ksz_write16, using the serial multiple write
+ * functionality.
+ *
+ * Return: 0 on success, or an error code on failure.
+ */
+static int ksz8_ind_read8(struct ksz_device *dev, u8 table, u16 addr, u8 *val)
+{
+       const u16 *regs;
+       u16 ctrl_addr;
+       int ret = 0;
+
+       regs = dev->info->regs;
+
+       mutex_lock(&dev->alu_mutex);
+
+       ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
+       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+       if (!ret)
+               ret = ksz_read8(dev, regs[REG_IND_BYTE], val);
+
+       mutex_unlock(&dev->alu_mutex);
+
+       return ret;
+}
+
+int ksz8_pme_write8(struct ksz_device *dev, u32 reg, u8 value)
+{
+       return ksz8_ind_write8(dev, (u8)(reg >> 8), (u8)(reg), value);
+}
+
+int ksz8_pme_pread8(struct ksz_device *dev, int port, int offset, u8 *data)
+{
+       u8 table = (u8)(offset >> 8 | (port + 1));
+
+       return ksz8_ind_read8(dev, table, (u8)(offset), data);
+}
+
+int ksz8_pme_pwrite8(struct ksz_device *dev, int port, int offset, u8 data)
+{
+       u8 table = (u8)(offset >> 8 | (port + 1));
+
+       return ksz8_ind_write8(dev, table, (u8)(offset), data);
+}
+
+int ksz8_reset_switch(struct ksz_device *dev)
+{
+       if (ksz_is_ksz88x3(dev)) {
+               /* reset switch */
+               ksz_cfg(dev, KSZ8863_REG_SW_RESET,
+                       KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true);
+               ksz_cfg(dev, KSZ8863_REG_SW_RESET,
+                       KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, false);
+       } else {
+               /* reset switch */
+               ksz_write8(dev, REG_POWER_MANAGEMENT_1,
+                          SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S);
+               ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0);
+       }
+
+       return 0;
+}
+
+static int ksz8863_change_mtu(struct ksz_device *dev, int frame_size)
+{
+       u8 ctrl2 = 0;
+
+       if (frame_size <= KSZ8_LEGAL_PACKET_SIZE)
+               ctrl2 |= KSZ8863_LEGAL_PACKET_ENABLE;
+       else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE)
+               ctrl2 |= KSZ8863_HUGE_PACKET_ENABLE;
+
+       return ksz_rmw8(dev, REG_SW_CTRL_2, KSZ8863_LEGAL_PACKET_ENABLE |
+                       KSZ8863_HUGE_PACKET_ENABLE, ctrl2);
+}
+
+static int ksz8795_change_mtu(struct ksz_device *dev, int frame_size)
+{
+       u8 ctrl1 = 0, ctrl2 = 0;
+       int ret;
+
+       if (frame_size > KSZ8_LEGAL_PACKET_SIZE)
+               ctrl2 |= SW_LEGAL_PACKET_DISABLE;
+       if (frame_size > KSZ8863_NORMAL_PACKET_SIZE)
+               ctrl1 |= SW_HUGE_PACKET;
+
+       ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_HUGE_PACKET, ctrl1);
+       if (ret)
+               return ret;
+
+       return ksz_rmw8(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, ctrl2);
+}
+
+int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu)
+{
+       u16 frame_size;
+
+       if (!dsa_is_cpu_port(dev->ds, port))
+               return 0;
+
+       frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
+
+       switch (dev->chip_id) {
+       case KSZ8795_CHIP_ID:
+       case KSZ8794_CHIP_ID:
+       case KSZ8765_CHIP_ID:
+               return ksz8795_change_mtu(dev, frame_size);
+       case KSZ8830_CHIP_ID:
+       case KSZ8864_CHIP_ID:
+       case KSZ8895_CHIP_ID:
+               return ksz8863_change_mtu(dev, frame_size);
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)
+{
+       u8 mask_4q, mask_2q;
+       u8 reg_4q, reg_2q;
+       u8 data_4q = 0;
+       u8 data_2q = 0;
+       int ret;
+
+       if (ksz_is_ksz88x3(dev)) {
+               mask_4q = KSZ8873_PORT_4QUEUE_SPLIT_EN;
+               mask_2q = KSZ8873_PORT_2QUEUE_SPLIT_EN;
+               reg_4q = REG_PORT_CTRL_0;
+               reg_2q = REG_PORT_CTRL_2;
+
+               /* KSZ8795 family switches have Weighted Fair Queueing (WFQ)
+                * enabled by default. Enable it for KSZ8873 family switches
+                * too. Default value for KSZ8873 family is strict priority,
+                * which should be enabled by using TC_SETUP_QDISC_ETS, not
+                * by default.
+                */
+               ret = ksz_rmw8(dev, REG_SW_CTRL_3, WEIGHTED_FAIR_QUEUE_ENABLE,
+                              WEIGHTED_FAIR_QUEUE_ENABLE);
+               if (ret)
+                       return ret;
+       } else {
+               mask_4q = KSZ8795_PORT_4QUEUE_SPLIT_EN;
+               mask_2q = KSZ8795_PORT_2QUEUE_SPLIT_EN;
+               reg_4q = REG_PORT_CTRL_13;
+               reg_2q = REG_PORT_CTRL_0;
+
+               /* TODO: this is legacy from initial KSZ8795 driver, should be
+                * moved to appropriate place in the future.
+                */
+               ret = ksz_rmw8(dev, REG_SW_CTRL_19,
+                              SW_OUT_RATE_LIMIT_QUEUE_BASED,
+                              SW_OUT_RATE_LIMIT_QUEUE_BASED);
+               if (ret)
+                       return ret;
+       }
+
+       if (queues == 4)
+               data_4q = mask_4q;
+       else if (queues == 2)
+               data_2q = mask_2q;
+
+       ret = ksz_prmw8(dev, port, reg_4q, mask_4q, data_4q);
+       if (ret)
+               return ret;
+
+       return ksz_prmw8(dev, port, reg_2q, mask_2q, data_2q);
+}
+
+int ksz8_all_queues_split(struct ksz_device *dev, int queues)
+{
+       struct dsa_switch *ds = dev->ds;
+       const struct dsa_port *dp;
+
+       dsa_switch_for_each_port(dp, ds) {
+               int ret = ksz8_port_queue_split(dev, dp->index, queues);
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
+{
+       const u32 *masks;
+       const u16 *regs;
+       u16 ctrl_addr;
+       u32 data;
+       u8 check;
+       int loop;
+
+       masks = dev->info->masks;
+       regs = dev->info->regs;
+
+       ctrl_addr = addr + dev->info->reg_mib_cnt * port;
+       ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
+
+       mutex_lock(&dev->alu_mutex);
+       ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+
+       /* It is almost guaranteed to always read the valid bit because of
+        * slow SPI speed.
+        */
+       for (loop = 2; loop > 0; loop--) {
+               ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
+
+               if (check & masks[MIB_COUNTER_VALID]) {
+                       ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
+                       if (check & masks[MIB_COUNTER_OVERFLOW])
+                               *cnt += MIB_COUNTER_VALUE + 1;
+                       *cnt += data & MIB_COUNTER_VALUE;
+                       break;
+               }
+       }
+       mutex_unlock(&dev->alu_mutex);
+}
+
+static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+                             u64 *dropped, u64 *cnt)
+{
+       const u32 *masks;
+       const u16 *regs;
+       u16 ctrl_addr;
+       u32 data;
+       u8 check;
+       int loop;
+
+       masks = dev->info->masks;
+       regs = dev->info->regs;
+
+       addr -= dev->info->reg_mib_cnt;
+       ctrl_addr = (KSZ8795_MIB_TOTAL_RX_1 - KSZ8795_MIB_TOTAL_RX_0) * port;
+       ctrl_addr += addr + KSZ8795_MIB_TOTAL_RX_0;
+       ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
+
+       mutex_lock(&dev->alu_mutex);
+       ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+
+       /* It is almost guaranteed to always read the valid bit because of
+        * slow SPI speed.
+        */
+       for (loop = 2; loop > 0; loop--) {
+               ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
+
+               if (check & masks[MIB_COUNTER_VALID]) {
+                       ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
+                       if (addr < 2) {
+                               u64 total;
+
+                               total = check & MIB_TOTAL_BYTES_H;
+                               total <<= 32;
+                               *cnt += total;
+                               *cnt += data;
+                               if (check & masks[MIB_COUNTER_OVERFLOW]) {
+                                       total = MIB_TOTAL_BYTES_H + 1;
+                                       total <<= 32;
+                                       *cnt += total;
+                               }
+                       } else {
+                               if (check & masks[MIB_COUNTER_OVERFLOW])
+                                       *cnt += MIB_PACKET_DROPPED + 1;
+                               *cnt += data & MIB_PACKET_DROPPED;
+                       }
+                       break;
+               }
+       }
+       mutex_unlock(&dev->alu_mutex);
+}
+
+static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+                             u64 *dropped, u64 *cnt)
+{
+       u32 *last = (u32 *)dropped;
+       const u16 *regs;
+       u16 ctrl_addr;
+       u32 data;
+       u32 cur;
+
+       regs = dev->info->regs;
+
+       addr -= dev->info->reg_mib_cnt;
+       ctrl_addr = addr ? KSZ8863_MIB_PACKET_DROPPED_TX_0 :
+                          KSZ8863_MIB_PACKET_DROPPED_RX_0;
+       ctrl_addr += port;
+       ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
+
+       mutex_lock(&dev->alu_mutex);
+       ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+       ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
+       mutex_unlock(&dev->alu_mutex);
+
+       data &= MIB_PACKET_DROPPED;
+       cur = last[addr];
+       if (data != cur) {
+               last[addr] = data;
+               if (data < cur)
+                       data += MIB_PACKET_DROPPED + 1;
+               data -= cur;
+               *cnt += data;
+       }
+}
+
+void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+                   u64 *dropped, u64 *cnt)
+{
+       if (is_ksz88xx(dev))
+               ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
+       else
+               ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
+}
+
+void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
+{
+       if (is_ksz88xx(dev))
+               return;
+
+       /* enable the port for flush/freeze function */
+       if (freeze)
+               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
+       ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FREEZE, freeze);
+
+       /* disable the port after freeze is done */
+       if (!freeze)
+               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
+}
+
+void ksz8_port_init_cnt(struct ksz_device *dev, int port)
+{
+       struct ksz_port_mib *mib = &dev->ports[port].mib;
+       u64 *dropped;
+
+       /* For KSZ8795 family. */
+       if (ksz_is_ksz87xx(dev)) {
+               /* flush all enabled port MIB counters */
+               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
+               ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true);
+               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
+       }
+
+       mib->cnt_ptr = 0;
+
+       /* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
+       while (mib->cnt_ptr < dev->info->reg_mib_cnt) {
+               dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
+                                       &mib->counters[mib->cnt_ptr]);
+               ++mib->cnt_ptr;
+       }
+
+       /* last one in storage */
+       dropped = &mib->counters[dev->info->mib_cnt];
+
+       /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
+       while (mib->cnt_ptr < dev->info->mib_cnt) {
+               dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
+                                       dropped, &mib->counters[mib->cnt_ptr]);
+               ++mib->cnt_ptr;
+       }
+}
+
+static int ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)
+{
+       const u16 *regs;
+       u16 ctrl_addr;
+       int ret;
+
+       regs = dev->info->regs;
+
+       ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
+
+       mutex_lock(&dev->alu_mutex);
+       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+       if (ret)
+               goto unlock_alu;
+
+       ret = ksz_read64(dev, regs[REG_IND_DATA_HI], data);
+unlock_alu:
+       mutex_unlock(&dev->alu_mutex);
+
+       return ret;
+}
+
+static int ksz8_w_table(struct ksz_device *dev, int table, u16 addr, u64 data)
+{
+       const u16 *regs;
+       u16 ctrl_addr;
+       int ret;
+
+       regs = dev->info->regs;
+
+       ctrl_addr = IND_ACC_TABLE(table) | addr;
+
+       mutex_lock(&dev->alu_mutex);
+       ret = ksz_write64(dev, regs[REG_IND_DATA_HI], data);
+       if (ret)
+               goto unlock_alu;
+
+       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+unlock_alu:
+       mutex_unlock(&dev->alu_mutex);
+
+       return ret;
+}
+
+static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data)
+{
+       int timeout = 100;
+       const u32 *masks;
+       const u16 *regs;
+       int ret;
+
+       masks = dev->info->masks;
+       regs = dev->info->regs;
+
+       do {
+               ret = ksz_read8(dev, regs[REG_IND_DATA_CHECK], data);
+               if (ret)
+                       return ret;
+
+               timeout--;
+       } while ((*data & masks[DYNAMIC_MAC_TABLE_NOT_READY]) && timeout);
+
+       /* Entry is not ready for accessing. */
+       if (*data & masks[DYNAMIC_MAC_TABLE_NOT_READY])
+               return -ETIMEDOUT;
+
+       /* Entry is ready for accessing. */
+       return ksz_read8(dev, regs[REG_IND_DATA_8], data);
+}
+
+static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,
+                               u8 *fid, u8 *src_port, u16 *entries)
+{
+       u32 data_hi, data_lo;
+       const u8 *shifts;
+       const u32 *masks;
+       const u16 *regs;
+       u16 ctrl_addr;
+       u64 buf = 0;
+       u8 data;
+       int cnt;
+       int ret;
+
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+       regs = dev->info->regs;
+
+       ctrl_addr = IND_ACC_TABLE(TABLE_DYNAMIC_MAC | TABLE_READ) | addr;
+
+       mutex_lock(&dev->alu_mutex);
+       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+       if (ret)
+               goto unlock_alu;
+
+       ret = ksz8_valid_dyn_entry(dev, &data);
+       if (ret)
+               goto unlock_alu;
+
+       if (data & masks[DYNAMIC_MAC_TABLE_MAC_EMPTY]) {
+               *entries = 0;
+               goto unlock_alu;
+       }
+
+       ret = ksz_read64(dev, regs[REG_IND_DATA_HI], &buf);
+       if (ret)
+               goto unlock_alu;
+
+       data_hi = (u32)(buf >> 32);
+       data_lo = (u32)buf;
+
+       /* Check out how many valid entry in the table. */
+       cnt = data & masks[DYNAMIC_MAC_TABLE_ENTRIES_H];
+       cnt <<= shifts[DYNAMIC_MAC_ENTRIES_H];
+       cnt |= (data_hi & masks[DYNAMIC_MAC_TABLE_ENTRIES]) >>
+               shifts[DYNAMIC_MAC_ENTRIES];
+       *entries = cnt + 1;
+
+       *fid = (data_hi & masks[DYNAMIC_MAC_TABLE_FID]) >>
+               shifts[DYNAMIC_MAC_FID];
+       *src_port = (data_hi & masks[DYNAMIC_MAC_TABLE_SRC_PORT]) >>
+               shifts[DYNAMIC_MAC_SRC_PORT];
+
+       mac_addr[5] = (u8)data_lo;
+       mac_addr[4] = (u8)(data_lo >> 8);
+       mac_addr[3] = (u8)(data_lo >> 16);
+       mac_addr[2] = (u8)(data_lo >> 24);
+
+       mac_addr[1] = (u8)data_hi;
+       mac_addr[0] = (u8)(data_hi >> 8);
+
+unlock_alu:
+       mutex_unlock(&dev->alu_mutex);
+
+       return ret;
+}
+
+static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
+                               struct alu_struct *alu, bool *valid)
+{
+       u32 data_hi, data_lo;
+       const u8 *shifts;
+       const u32 *masks;
+       u64 data;
+       int ret;
+
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+
+       ret = ksz8_r_table(dev, TABLE_STATIC_MAC, addr, &data);
+       if (ret)
+               return ret;
+
+       data_hi = data >> 32;
+       data_lo = (u32)data;
+
+       if (!(data_hi & (masks[STATIC_MAC_TABLE_VALID] |
+                        masks[STATIC_MAC_TABLE_OVERRIDE]))) {
+               *valid = false;
+               return 0;
+       }
+
+       alu->mac[5] = (u8)data_lo;
+       alu->mac[4] = (u8)(data_lo >> 8);
+       alu->mac[3] = (u8)(data_lo >> 16);
+       alu->mac[2] = (u8)(data_lo >> 24);
+       alu->mac[1] = (u8)data_hi;
+       alu->mac[0] = (u8)(data_hi >> 8);
+       alu->port_forward =
+               (data_hi & masks[STATIC_MAC_TABLE_FWD_PORTS]) >>
+                       shifts[STATIC_MAC_FWD_PORTS];
+       alu->is_override = (data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0;
+
+       /* KSZ8795/KSZ8895 family switches have STATIC_MAC_TABLE_USE_FID and
+        * STATIC_MAC_TABLE_FID definitions off by 1 when doing read on the
+        * static MAC table compared to doing write.
+        */
+       if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev))
+               data_hi >>= 1;
+       alu->is_static = true;
+       alu->is_use_fid = (data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0;
+       alu->fid = (data_hi & masks[STATIC_MAC_TABLE_FID]) >>
+               shifts[STATIC_MAC_FID];
+
+       *valid = true;
+
+       return 0;
+}
+
+static int ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
+                               struct alu_struct *alu)
+{
+       u32 data_hi, data_lo;
+       const u8 *shifts;
+       const u32 *masks;
+       u64 data;
+
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+
+       data_lo = ((u32)alu->mac[2] << 24) |
+               ((u32)alu->mac[3] << 16) |
+               ((u32)alu->mac[4] << 8) | alu->mac[5];
+       data_hi = ((u32)alu->mac[0] << 8) | alu->mac[1];
+       data_hi |= (u32)alu->port_forward << shifts[STATIC_MAC_FWD_PORTS];
+
+       if (alu->is_override)
+               data_hi |= masks[STATIC_MAC_TABLE_OVERRIDE];
+       if (alu->is_use_fid) {
+               data_hi |= masks[STATIC_MAC_TABLE_USE_FID];
+               data_hi |= (u32)alu->fid << shifts[STATIC_MAC_FID];
+       }
+       if (alu->is_static)
+               data_hi |= masks[STATIC_MAC_TABLE_VALID];
+       else
+               data_hi &= ~masks[STATIC_MAC_TABLE_OVERRIDE];
+
+       data = (u64)data_hi << 32 | data_lo;
+
+       return ksz8_w_table(dev, TABLE_STATIC_MAC, addr, data);
+}
+
+static void ksz8_from_vlan(struct ksz_device *dev, u32 vlan, u8 *fid,
+                          u8 *member, u8 *valid)
+{
+       const u8 *shifts;
+       const u32 *masks;
+
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+
+       *fid = vlan & masks[VLAN_TABLE_FID];
+       *member = (vlan & masks[VLAN_TABLE_MEMBERSHIP]) >>
+                       shifts[VLAN_TABLE_MEMBERSHIP_S];
+       *valid = !!(vlan & masks[VLAN_TABLE_VALID]);
+}
+
+static void ksz8_to_vlan(struct ksz_device *dev, u8 fid, u8 member, u8 valid,
+                        u16 *vlan)
+{
+       const u8 *shifts;
+       const u32 *masks;
+
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+
+       *vlan = fid;
+       *vlan |= (u16)member << shifts[VLAN_TABLE_MEMBERSHIP_S];
+       if (valid)
+               *vlan |= masks[VLAN_TABLE_VALID];
+}
+
+static void ksz8_r_vlan_entries(struct ksz_device *dev, u16 addr)
+{
+       const u8 *shifts;
+       u64 data;
+       int i;
+
+       shifts = dev->info->shifts;
+
+       ksz8_r_table(dev, TABLE_VLAN, addr, &data);
+       addr *= 4;
+       for (i = 0; i < 4; i++) {
+               dev->vlan_cache[addr + i].table[0] = (u16)data;
+               data >>= shifts[VLAN_TABLE];
+       }
+}
+
+static void ksz8_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan)
+{
+       int index;
+       u16 *data;
+       u16 addr;
+       u64 buf;
+
+       data = (u16 *)&buf;
+       addr = vid / 4;
+       index = vid & 3;
+       ksz8_r_table(dev, TABLE_VLAN, addr, &buf);
+       *vlan = data[index];
+}
+
+static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
+{
+       int index;
+       u16 *data;
+       u16 addr;
+       u64 buf;
+
+       data = (u16 *)&buf;
+       addr = vid / 4;
+       index = vid & 3;
+       ksz8_r_table(dev, TABLE_VLAN, addr, &buf);
+       data[index] = vlan;
+       dev->vlan_cache[vid].table[0] = vlan;
+       ksz8_w_table(dev, TABLE_VLAN, addr, buf);
+}
+
+/**
+ * ksz879x_get_loopback - KSZ879x specific function to get loopback
+ *                        configuration status for a specific port
+ * @dev: Pointer to the device structure
+ * @port: Port number to query
+ * @val: Pointer to store the result
+ *
+ * This function reads the SMI registers to determine whether loopback mode
+ * is enabled for a specific port.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz879x_get_loopback(struct ksz_device *dev, u16 port,
+                               u16 *val)
+{
+       u8 stat3;
+       int ret;
+
+       ret = ksz_pread8(dev, port, REG_PORT_STATUS_3, &stat3);
+       if (ret)
+               return ret;
+
+       if (stat3 & PORT_PHY_LOOPBACK)
+               *val |= BMCR_LOOPBACK;
+
+       return 0;
+}
+
+/**
+ * ksz879x_set_loopback - KSZ879x specific function  to set loopback mode for
+ *                       a specific port
+ * @dev: Pointer to the device structure.
+ * @port: Port number to modify.
+ * @val: Value indicating whether to enable or disable loopback mode.
+ *
+ * This function translates loopback bit of the BMCR register into the
+ * corresponding hardware register bit value and writes it to the SMI interface.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz879x_set_loopback(struct ksz_device *dev, u16 port, u16 val)
+{
+       u8 stat3 = 0;
+
+       if (val & BMCR_LOOPBACK)
+               stat3 |= PORT_PHY_LOOPBACK;
+
+       return ksz_prmw8(dev, port, REG_PORT_STATUS_3, PORT_PHY_LOOPBACK,
+                        stat3);
+}
+
+/**
+ * ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY
+ *                  Control register (Reg. 31).
+ * @dev: The KSZ device instance.
+ * @port: The port number to be read.
+ * @val: The value read from the SMI interface.
+ *
+ * This function reads the SMI interface and translates the hardware register
+ * bit values into their corresponding control settings for a MIIM PHY Control
+ * register.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val)
+{
+       const u16 *regs = dev->info->regs;
+       u8 reg_val;
+       int ret;
+
+       *val = 0;
+
+       ret = ksz_pread8(dev, port, regs[P_LINK_STATUS], &reg_val);
+       if (ret < 0)
+               return ret;
+
+       if (reg_val & PORT_MDIX_STATUS)
+               *val |= KSZ886X_CTRL_MDIX_STAT;
+
+       ret = ksz_pread8(dev, port, REG_PORT_LINK_MD_CTRL, &reg_val);
+       if (ret < 0)
+               return ret;
+
+       if (reg_val & PORT_FORCE_LINK)
+               *val |= KSZ886X_CTRL_FORCE_LINK;
+
+       if (reg_val & PORT_POWER_SAVING)
+               *val |= KSZ886X_CTRL_PWRSAVE;
+
+       if (reg_val & PORT_PHY_REMOTE_LOOPBACK)
+               *val |= KSZ886X_CTRL_REMOTE_LOOPBACK;
+
+       return 0;
+}
+
+/**
+ * ksz8_r_phy_bmcr - Translates and reads from the SMI interface to a MIIM PHY
+ *                  Basic mode control register (Reg. 0).
+ * @dev: The KSZ device instance.
+ * @port: The port number to be read.
+ * @val: The value read from the SMI interface.
+ *
+ * This function reads the SMI interface and translates the hardware register
+ * bit values into their corresponding control settings for a MIIM PHY Basic
+ * mode control register.
+ *
+ * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873
+ * -------------------------------------------------------------------
+ * MIIM Bit                    | KSZ8794 Reg/Bit             | KSZ8873 Reg/Bit
+ * ----------------------------+-----------------------------+----------------
+ * Bit 15 - Soft Reset         | 0xF/4                       | Not supported
+ * Bit 14 - Loopback           | 0xD/0 (MAC), 0xF/7 (PHY)    ~ 0xD/0 (PHY)
+ * Bit 13 - Force 100          | 0xC/6                       = 0xC/6
+ * Bit 12 - AN Enable          | 0xC/7 (reverse logic)       ~ 0xC/7
+ * Bit 11 - Power Down         | 0xD/3                       = 0xD/3
+ * Bit 10 - PHY Isolate        | 0xF/5                       | Not supported
+ * Bit 9 - Restart AN          | 0xD/5                       = 0xD/5
+ * Bit 8 - Force Full-Duplex   | 0xC/5                       = 0xC/5
+ * Bit 7 - Collision Test/Res. | Not supported               | Not supported
+ * Bit 6 - Reserved            | Not supported               | Not supported
+ * Bit 5 - Hp_mdix             | 0x9/7                       ~ 0xF/7
+ * Bit 4 - Force MDI           | 0xD/1                       = 0xD/1
+ * Bit 3 - Disable MDIX        | 0xD/2                       = 0xD/2
+ * Bit 2 - Disable Far-End F.  | ????                        | 0xD/4
+ * Bit 1 - Disable Transmit    | 0xD/6                       = 0xD/6
+ * Bit 0 - Disable LED         | 0xD/7                       = 0xD/7
+ * -------------------------------------------------------------------
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val)
+{
+       const u16 *regs = dev->info->regs;
+       u8 restart, speed, ctrl;
+       int ret;
+
+       *val = 0;
+
+       ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart);
+       if (ret)
+               return ret;
+
+       ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed);
+       if (ret)
+               return ret;
+
+       ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl);
+       if (ret)
+               return ret;
+
+       if (ctrl & PORT_FORCE_100_MBIT)
+               *val |= BMCR_SPEED100;
+
+       if (ksz_is_ksz88x3(dev)) {
+               if (restart & KSZ8873_PORT_PHY_LOOPBACK)
+                       *val |= BMCR_LOOPBACK;
+
+               if ((ctrl & PORT_AUTO_NEG_ENABLE))
+                       *val |= BMCR_ANENABLE;
+       } else {
+               ret = ksz879x_get_loopback(dev, port, val);
+               if (ret)
+                       return ret;
+
+               if (!(ctrl & PORT_AUTO_NEG_DISABLE))
+                       *val |= BMCR_ANENABLE;
+       }
+
+       if (restart & PORT_POWER_DOWN)
+               *val |= BMCR_PDOWN;
+
+       if (restart & PORT_AUTO_NEG_RESTART)
+               *val |= BMCR_ANRESTART;
+
+       if (ctrl & PORT_FORCE_FULL_DUPLEX)
+               *val |= BMCR_FULLDPLX;
+
+       if (speed & PORT_HP_MDIX)
+               *val |= KSZ886X_BMCR_HP_MDIX;
+
+       if (restart & PORT_FORCE_MDIX)
+               *val |= KSZ886X_BMCR_FORCE_MDI;
+
+       if (restart & PORT_AUTO_MDIX_DISABLE)
+               *val |= KSZ886X_BMCR_DISABLE_AUTO_MDIX;
+
+       if (restart & PORT_TX_DISABLE)
+               *val |= KSZ886X_BMCR_DISABLE_TRANSMIT;
+
+       if (restart & PORT_LED_OFF)
+               *val |= KSZ886X_BMCR_DISABLE_LED;
+
+       return 0;
+}
+
+int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
+{
+       u8 ctrl, link, val1, val2;
+       int processed = true;
+       const u16 *regs;
+       u16 data = 0;
+       u16 p = phy;
+       int ret;
+
+       regs = dev->info->regs;
+
+       switch (reg) {
+       case MII_BMCR:
+               ret = ksz8_r_phy_bmcr(dev, p, &data);
+               if (ret)
+                       return ret;
+               break;
+       case MII_BMSR:
+               ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
+               if (ret)
+                       return ret;
+
+               data = BMSR_100FULL |
+                      BMSR_100HALF |
+                      BMSR_10FULL |
+                      BMSR_10HALF |
+                      BMSR_ANEGCAPABLE;
+               if (link & PORT_AUTO_NEG_COMPLETE)
+                       data |= BMSR_ANEGCOMPLETE;
+               if (link & PORT_STAT_LINK_GOOD)
+                       data |= BMSR_LSTATUS;
+               break;
+       case MII_PHYSID1:
+               data = KSZ8795_ID_HI;
+               break;
+       case MII_PHYSID2:
+               if (ksz_is_ksz88x3(dev))
+                       data = KSZ8863_ID_LO;
+               else
+                       data = KSZ8795_ID_LO;
+               break;
+       case MII_ADVERTISE:
+               ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
+               if (ret)
+                       return ret;
+
+               data = ADVERTISE_CSMA;
+               if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
+                       data |= ADVERTISE_PAUSE_CAP;
+               if (ctrl & PORT_AUTO_NEG_100BTX_FD)
+                       data |= ADVERTISE_100FULL;
+               if (ctrl & PORT_AUTO_NEG_100BTX)
+                       data |= ADVERTISE_100HALF;
+               if (ctrl & PORT_AUTO_NEG_10BT_FD)
+                       data |= ADVERTISE_10FULL;
+               if (ctrl & PORT_AUTO_NEG_10BT)
+                       data |= ADVERTISE_10HALF;
+               break;
+       case MII_LPA:
+               ret = ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link);
+               if (ret)
+                       return ret;
+
+               data = LPA_SLCT;
+               if (link & PORT_REMOTE_SYM_PAUSE)
+                       data |= LPA_PAUSE_CAP;
+               if (link & PORT_REMOTE_100BTX_FD)
+                       data |= LPA_100FULL;
+               if (link & PORT_REMOTE_100BTX)
+                       data |= LPA_100HALF;
+               if (link & PORT_REMOTE_10BT_FD)
+                       data |= LPA_10FULL;
+               if (link & PORT_REMOTE_10BT)
+                       data |= LPA_10HALF;
+               if (data & ~LPA_SLCT)
+                       data |= LPA_LPACK;
+               break;
+       case PHY_REG_LINK_MD:
+               ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1);
+               if (ret)
+                       return ret;
+
+               ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2);
+               if (ret)
+                       return ret;
+
+               if (val1 & PORT_START_CABLE_DIAG)
+                       data |= PHY_START_CABLE_DIAG;
+
+               if (val1 & PORT_CABLE_10M_SHORT)
+                       data |= PHY_CABLE_10M_SHORT;
+
+               data |= FIELD_PREP(PHY_CABLE_DIAG_RESULT_M,
+                               FIELD_GET(PORT_CABLE_DIAG_RESULT_M, val1));
+
+               data |= FIELD_PREP(PHY_CABLE_FAULT_COUNTER_M,
+                               (FIELD_GET(PORT_CABLE_FAULT_COUNTER_H, val1) << 8) |
+                               FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2));
+               break;
+       case PHY_REG_PHY_CTRL:
+               ret = ksz8_r_phy_ctrl(dev, p, &data);
+               if (ret)
+                       return ret;
+
+               break;
+       default:
+               processed = false;
+               break;
+       }
+       if (processed)
+               *val = data;
+
+       return 0;
+}
+
+/**
+ * ksz8_w_phy_ctrl - Translates and writes to the SMI interface from a MIIM PHY
+ *                  Control register (Reg. 31).
+ * @dev: The KSZ device instance.
+ * @port: The port number to be configured.
+ * @val: The register value to be written.
+ *
+ * This function translates control settings from a MIIM PHY Control register
+ * into their corresponding hardware register bit values for the SMI
+ * interface.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz8_w_phy_ctrl(struct ksz_device *dev, int port, u16 val)
+{
+       u8 reg_val = 0;
+       int ret;
+
+       if (val & KSZ886X_CTRL_FORCE_LINK)
+               reg_val |= PORT_FORCE_LINK;
+
+       if (val & KSZ886X_CTRL_PWRSAVE)
+               reg_val |= PORT_POWER_SAVING;
+
+       if (val & KSZ886X_CTRL_REMOTE_LOOPBACK)
+               reg_val |= PORT_PHY_REMOTE_LOOPBACK;
+
+       ret = ksz_prmw8(dev, port, REG_PORT_LINK_MD_CTRL, PORT_FORCE_LINK |
+                       PORT_POWER_SAVING | PORT_PHY_REMOTE_LOOPBACK, reg_val);
+       return ret;
+}
+
+/**
+ * ksz8_w_phy_bmcr - Translates and writes to the SMI interface from a MIIM PHY
+ *                  Basic mode control register (Reg. 0).
+ * @dev: The KSZ device instance.
+ * @port: The port number to be configured.
+ * @val: The register value to be written.
+ *
+ * This function translates control settings from a MIIM PHY Basic mode control
+ * register into their corresponding hardware register bit values for the SMI
+ * interface.
+ *
+ * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873
+ * -------------------------------------------------------------------
+ * MIIM Bit                    | KSZ8794 Reg/Bit             | KSZ8873 Reg/Bit
+ * ----------------------------+-----------------------------+----------------
+ * Bit 15 - Soft Reset         | 0xF/4                       | Not supported
+ * Bit 14 - Loopback           | 0xD/0 (MAC), 0xF/7 (PHY)    ~ 0xD/0 (PHY)
+ * Bit 13 - Force 100          | 0xC/6                       = 0xC/6
+ * Bit 12 - AN Enable          | 0xC/7 (reverse logic)       ~ 0xC/7
+ * Bit 11 - Power Down         | 0xD/3                       = 0xD/3
+ * Bit 10 - PHY Isolate        | 0xF/5                       | Not supported
+ * Bit 9 - Restart AN          | 0xD/5                       = 0xD/5
+ * Bit 8 - Force Full-Duplex   | 0xC/5                       = 0xC/5
+ * Bit 7 - Collision Test/Res. | Not supported               | Not supported
+ * Bit 6 - Reserved            | Not supported               | Not supported
+ * Bit 5 - Hp_mdix             | 0x9/7                       ~ 0xF/7
+ * Bit 4 - Force MDI           | 0xD/1                       = 0xD/1
+ * Bit 3 - Disable MDIX        | 0xD/2                       = 0xD/2
+ * Bit 2 - Disable Far-End F.  | ????                        | 0xD/4
+ * Bit 1 - Disable Transmit    | 0xD/6                       = 0xD/6
+ * Bit 0 - Disable LED         | 0xD/7                       = 0xD/7
+ * -------------------------------------------------------------------
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val)
+{
+       u8 restart, speed, ctrl, restart_mask;
+       const u16 *regs = dev->info->regs;
+       int ret;
+
+       /* Do not support PHY reset function. */
+       if (val & BMCR_RESET)
+               return 0;
+
+       speed = 0;
+       if (val & KSZ886X_BMCR_HP_MDIX)
+               speed |= PORT_HP_MDIX;
+
+       ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed);
+       if (ret)
+               return ret;
+
+       ctrl = 0;
+       if (ksz_is_ksz88x3(dev)) {
+               if ((val & BMCR_ANENABLE))
+                       ctrl |= PORT_AUTO_NEG_ENABLE;
+       } else {
+               if (!(val & BMCR_ANENABLE))
+                       ctrl |= PORT_AUTO_NEG_DISABLE;
+
+               /* Fiber port does not support auto-negotiation. */
+               if (dev->ports[port].fiber)
+                       ctrl |= PORT_AUTO_NEG_DISABLE;
+       }
+
+       if (val & BMCR_SPEED100)
+               ctrl |= PORT_FORCE_100_MBIT;
+
+       if (val & BMCR_FULLDPLX)
+               ctrl |= PORT_FORCE_FULL_DUPLEX;
+
+       ret = ksz_prmw8(dev, port, regs[P_FORCE_CTRL], PORT_FORCE_100_MBIT |
+                /* PORT_AUTO_NEG_ENABLE and PORT_AUTO_NEG_DISABLE are the same
+                 * bits
+                 */
+                PORT_FORCE_FULL_DUPLEX | PORT_AUTO_NEG_ENABLE, ctrl);
+       if (ret)
+               return ret;
+
+       restart = 0;
+       restart_mask = PORT_LED_OFF | PORT_TX_DISABLE | PORT_AUTO_NEG_RESTART |
+               PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX;
+
+       if (val & KSZ886X_BMCR_DISABLE_LED)
+               restart |= PORT_LED_OFF;
+
+       if (val & KSZ886X_BMCR_DISABLE_TRANSMIT)
+               restart |= PORT_TX_DISABLE;
+
+       if (val & BMCR_ANRESTART)
+               restart |= PORT_AUTO_NEG_RESTART;
+
+       if (val & BMCR_PDOWN)
+               restart |= PORT_POWER_DOWN;
+
+       if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX)
+               restart |= PORT_AUTO_MDIX_DISABLE;
+
+       if (val & KSZ886X_BMCR_FORCE_MDI)
+               restart |= PORT_FORCE_MDIX;
+
+       if (ksz_is_ksz88x3(dev)) {
+               restart_mask |= KSZ8873_PORT_PHY_LOOPBACK;
+
+               if (val & BMCR_LOOPBACK)
+                       restart |= KSZ8873_PORT_PHY_LOOPBACK;
+       } else {
+               ret = ksz879x_set_loopback(dev, port, val);
+               if (ret)
+                       return ret;
+       }
+
+       return ksz_prmw8(dev, port, regs[P_NEG_RESTART_CTRL], restart_mask,
+                        restart);
+}
+
+int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
+{
+       const u16 *regs;
+       u8 ctrl, data;
+       u16 p = phy;
+       int ret;
+
+       regs = dev->info->regs;
+
+       switch (reg) {
+       case MII_BMCR:
+               ret = ksz8_w_phy_bmcr(dev, p, val);
+               if (ret)
+                       return ret;
+               break;
+       case MII_ADVERTISE:
+               ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
+               if (ret)
+                       return ret;
+
+               data = ctrl;
+               data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
+                         PORT_AUTO_NEG_100BTX_FD |
+                         PORT_AUTO_NEG_100BTX |
+                         PORT_AUTO_NEG_10BT_FD |
+                         PORT_AUTO_NEG_10BT);
+               if (val & ADVERTISE_PAUSE_CAP)
+                       data |= PORT_AUTO_NEG_SYM_PAUSE;
+               if (val & ADVERTISE_100FULL)
+                       data |= PORT_AUTO_NEG_100BTX_FD;
+               if (val & ADVERTISE_100HALF)
+                       data |= PORT_AUTO_NEG_100BTX;
+               if (val & ADVERTISE_10FULL)
+                       data |= PORT_AUTO_NEG_10BT_FD;
+               if (val & ADVERTISE_10HALF)
+                       data |= PORT_AUTO_NEG_10BT;
+
+               if (data != ctrl) {
+                       ret = ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case PHY_REG_LINK_MD:
+               if (val & PHY_START_CABLE_DIAG)
+                       ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);
+               break;
+
+       case PHY_REG_PHY_CTRL:
+               ret = ksz8_w_phy_ctrl(dev, p, val);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
+{
+       u8 data;
+
+       ksz_pread8(dev, port, P_MIRROR_CTRL, &data);
+       data &= ~PORT_VLAN_MEMBERSHIP;
+       data |= (member & dev->port_mask);
+       ksz_pwrite8(dev, port, P_MIRROR_CTRL, data);
+}
+
+void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
+{
+       u8 learn[DSA_MAX_PORTS];
+       int first, index, cnt;
+       const u16 *regs;
+
+       regs = dev->info->regs;
+
+       if ((uint)port < dev->info->port_cnt) {
+               first = port;
+               cnt = port + 1;
+       } else {
+               /* Flush all ports. */
+               first = 0;
+               cnt = dev->info->port_cnt;
+       }
+       for (index = first; index < cnt; index++) {
+               ksz_pread8(dev, index, regs[P_STP_CTRL], &learn[index]);
+               if (!(learn[index] & PORT_LEARN_DISABLE))
+                       ksz_pwrite8(dev, index, regs[P_STP_CTRL],
+                                   learn[index] | PORT_LEARN_DISABLE);
+       }
+       ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true);
+       for (index = first; index < cnt; index++) {
+               if (!(learn[index] & PORT_LEARN_DISABLE))
+                       ksz_pwrite8(dev, index, regs[P_STP_CTRL], learn[index]);
+       }
+}
+
+int ksz8_fdb_dump(struct ksz_device *dev, int port,
+                 dsa_fdb_dump_cb_t *cb, void *data)
+{
+       u8 mac[ETH_ALEN];
+       u8 src_port, fid;
+       u16 entries = 0;
+       int ret, i;
+
+       for (i = 0; i < KSZ8_DYN_MAC_ENTRIES; i++) {
+               ret = ksz8_r_dyn_mac_table(dev, i, mac, &fid, &src_port,
+                                          &entries);
+               if (ret)
+                       return ret;
+
+               if (i >= entries)
+                       return 0;
+
+               if (port == src_port) {
+                       ret = cb(mac, fid, false, data);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int ksz8_add_sta_mac(struct ksz_device *dev, int port,
+                           const unsigned char *addr, u16 vid)
+{
+       struct alu_struct alu;
+       int index, ret;
+       int empty = 0;
+
+       alu.port_forward = 0;
+       for (index = 0; index < dev->info->num_statics; index++) {
+               bool valid;
+
+               ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid);
+               if (ret)
+                       return ret;
+               if (!valid) {
+                       /* Remember the first empty entry. */
+                       if (!empty)
+                               empty = index + 1;
+                       continue;
+               }
+
+               if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid)
+                       break;
+       }
+
+       /* no available entry */
+       if (index == dev->info->num_statics && !empty)
+               return -ENOSPC;
+
+       /* add entry */
+       if (index == dev->info->num_statics) {
+               index = empty - 1;
+               memset(&alu, 0, sizeof(alu));
+               memcpy(alu.mac, addr, ETH_ALEN);
+               alu.is_static = true;
+       }
+       alu.port_forward |= BIT(port);
+       if (vid) {
+               alu.is_use_fid = true;
+
+               /* Need a way to map VID to FID. */
+               alu.fid = vid;
+       }
+
+       return ksz8_w_sta_mac_table(dev, index, &alu);
+}
+
+static int ksz8_del_sta_mac(struct ksz_device *dev, int port,
+                           const unsigned char *addr, u16 vid)
+{
+       struct alu_struct alu;
+       int index, ret;
+
+       for (index = 0; index < dev->info->num_statics; index++) {
+               bool valid;
+
+               ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid);
+               if (ret)
+                       return ret;
+               if (!valid)
+                       continue;
+
+               if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid)
+                       break;
+       }
+
+       /* no available entry */
+       if (index == dev->info->num_statics)
+               return 0;
+
+       /* clear port */
+       alu.port_forward &= ~BIT(port);
+       if (!alu.port_forward)
+               alu.is_static = false;
+
+       return ksz8_w_sta_mac_table(dev, index, &alu);
+}
+
+int ksz8_mdb_add(struct ksz_device *dev, int port,
+                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
+{
+       return ksz8_add_sta_mac(dev, port, mdb->addr, mdb->vid);
+}
+
+int ksz8_mdb_del(struct ksz_device *dev, int port,
+                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
+{
+       return ksz8_del_sta_mac(dev, port, mdb->addr, mdb->vid);
+}
+
+int ksz8_fdb_add(struct ksz_device *dev, int port, const unsigned char *addr,
+                u16 vid, struct dsa_db db)
+{
+       return ksz8_add_sta_mac(dev, port, addr, vid);
+}
+
+int ksz8_fdb_del(struct ksz_device *dev, int port, const unsigned char *addr,
+                u16 vid, struct dsa_db db)
+{
+       return ksz8_del_sta_mac(dev, port, addr, vid);
+}
+
+int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag,
+                            struct netlink_ext_ack *extack)
+{
+       if (ksz_is_ksz88x3(dev))
+               return -ENOTSUPP;
+
+       /* Discard packets with VID not enabled on the switch */
+       ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
+
+       /* Discard packets with VID not enabled on the ingress port */
+       for (port = 0; port < dev->phy_port_cnt; ++port)
+               ksz_port_cfg(dev, port, REG_PORT_CTRL_2, PORT_INGRESS_FILTER,
+                            flag);
+
+       return 0;
+}
+
+static void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool state)
+{
+       if (ksz_is_ksz88x3(dev)) {
+               ksz_cfg(dev, REG_SW_INSERT_SRC_PVID,
+                       0x03 << (4 - 2 * port), state);
+       } else {
+               ksz_pwrite8(dev, port, REG_PORT_CTRL_12, state ? 0x0f : 0x00);
+       }
+}
+
+int ksz8_port_vlan_add(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_vlan *vlan,
+                      struct netlink_ext_ack *extack)
+{
+       bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+       struct ksz_port *p = &dev->ports[port];
+       u16 data, new_pvid = 0;
+       u8 fid, member, valid;
+
+       if (ksz_is_ksz88x3(dev))
+               return -ENOTSUPP;
+
+       /* If a VLAN is added with untagged flag different from the
+        * port's Remove Tag flag, we need to change the latter.
+        * Ignore VID 0, which is always untagged.
+        * Ignore CPU port, which will always be tagged.
+        */
+       if (untagged != p->remove_tag && vlan->vid != 0 &&
+           port != dev->cpu_port) {
+               unsigned int vid;
+
+               /* Reject attempts to add a VLAN that requires the
+                * Remove Tag flag to be changed, unless there are no
+                * other VLANs currently configured.
+                */
+               for (vid = 1; vid < dev->info->num_vlans; ++vid) {
+                       /* Skip the VID we are going to add or reconfigure */
+                       if (vid == vlan->vid)
+                               continue;
+
+                       ksz8_from_vlan(dev, dev->vlan_cache[vid].table[0],
+                                      &fid, &member, &valid);
+                       if (valid && (member & BIT(port)))
+                               return -EINVAL;
+               }
+
+               ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
+               p->remove_tag = untagged;
+       }
+
+       ksz8_r_vlan_table(dev, vlan->vid, &data);
+       ksz8_from_vlan(dev, data, &fid, &member, &valid);
+
+       /* First time to setup the VLAN entry. */
+       if (!valid) {
+               /* Need to find a way to map VID to FID. */
+               fid = 1;
+               valid = 1;
+       }
+       member |= BIT(port);
+
+       ksz8_to_vlan(dev, fid, member, valid, &data);
+       ksz8_w_vlan_table(dev, vlan->vid, data);
+
+       /* change PVID */
+       if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
+               new_pvid = vlan->vid;
+
+       if (new_pvid) {
+               u16 vid;
+
+               ksz_pread16(dev, port, REG_PORT_CTRL_VID, &vid);
+               vid &= ~VLAN_VID_MASK;
+               vid |= new_pvid;
+               ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, vid);
+
+               ksz8_port_enable_pvid(dev, port, true);
+       }
+
+       return 0;
+}
+
+int ksz8_port_vlan_del(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_vlan *vlan)
+{
+       u16 data, pvid;
+       u8 fid, member, valid;
+
+       if (ksz_is_ksz88x3(dev))
+               return -ENOTSUPP;
+
+       ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid);
+       pvid = pvid & 0xFFF;
+
+       ksz8_r_vlan_table(dev, vlan->vid, &data);
+       ksz8_from_vlan(dev, data, &fid, &member, &valid);
+
+       member &= ~BIT(port);
+
+       /* Invalidate the entry if no more member. */
+       if (!member) {
+               fid = 0;
+               valid = 0;
+       }
+
+       ksz8_to_vlan(dev, fid, member, valid, &data);
+       ksz8_w_vlan_table(dev, vlan->vid, data);
+
+       if (pvid == vlan->vid)
+               ksz8_port_enable_pvid(dev, port, false);
+
+       return 0;
+}
+
+int ksz8_port_mirror_add(struct ksz_device *dev, int port,
+                        struct dsa_mall_mirror_tc_entry *mirror,
+                        bool ingress, struct netlink_ext_ack *extack)
+{
+       if (ingress) {
+               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
+               dev->mirror_rx |= BIT(port);
+       } else {
+               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
+               dev->mirror_tx |= BIT(port);
+       }
+
+       ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false);
+
+       /* configure mirror port */
+       if (dev->mirror_rx || dev->mirror_tx)
+               ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
+                            PORT_MIRROR_SNIFFER, true);
+
+       return 0;
+}
+
+void ksz8_port_mirror_del(struct ksz_device *dev, int port,
+                         struct dsa_mall_mirror_tc_entry *mirror)
+{
+       u8 data;
+
+       if (mirror->ingress) {
+               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
+               dev->mirror_rx &= ~BIT(port);
+       } else {
+               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
+               dev->mirror_tx &= ~BIT(port);
+       }
+
+       ksz_pread8(dev, port, P_MIRROR_CTRL, &data);
+
+       if (!dev->mirror_rx && !dev->mirror_tx)
+               ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
+                            PORT_MIRROR_SNIFFER, false);
+}
+
+static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
+{
+       struct ksz_port *p = &dev->ports[port];
+
+       if (!ksz_is_ksz87xx(dev))
+               return;
+
+       if (!p->interface && 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",
+                        port);
+               p->interface = dev->compat_interface;
+       }
+}
+
+void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+{
+       const u16 *regs = dev->info->regs;
+       struct dsa_switch *ds = dev->ds;
+       const u32 *masks;
+       int queues;
+       u8 member;
+
+       masks = dev->info->masks;
+
+       /* enable broadcast storm limit */
+       ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
+
+       /* For KSZ88x3 enable only one queue by default, otherwise we won't
+        * be able to get rid of PCP prios on Port 2.
+        */
+       if (ksz_is_ksz88x3(dev))
+               queues = 1;
+       else
+               queues = dev->info->num_tx_queues;
+
+       ksz8_port_queue_split(dev, port, queues);
+
+       /* replace priority */
+       ksz_port_cfg(dev, port, P_802_1P_CTRL,
+                    masks[PORT_802_1P_REMAPPING], false);
+
+       if (cpu_port)
+               member = dsa_user_ports(ds);
+       else
+               member = BIT(dsa_upstream_port(ds, port));
+
+       ksz8_cfg_port_member(dev, port, member);
+
+       /* Disable all WoL options by default. Otherwise
+        * ksz_switch_macaddr_get/put logic will not work properly.
+        * CPU port 4 has no WoL functionality.
+        */
+       if (ksz_is_ksz87xx(dev) && !cpu_port)
+               ksz8_pme_pwrite8(dev, port, regs[REG_PORT_PME_CTRL], 0);
+}
+
+static void ksz88x3_config_rmii_clk(struct ksz_device *dev)
+{
+       struct dsa_port *cpu_dp = dsa_to_port(dev->ds, dev->cpu_port);
+       bool rmii_clk_internal;
+
+       if (!ksz_is_ksz88x3(dev))
+               return;
+
+       rmii_clk_internal = of_property_read_bool(cpu_dp->dn,
+                                                 "microchip,rmii-clk-internal");
+
+       ksz_cfg(dev, KSZ88X3_REG_FVID_AND_HOST_MODE,
+               KSZ88X3_PORT3_RMII_CLK_INTERNAL, rmii_clk_internal);
+}
+
+void ksz8_config_cpu_port(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       struct ksz_port *p;
+       const u32 *masks;
+       const u16 *regs;
+       u8 remote;
+       int i;
+
+       masks = dev->info->masks;
+       regs = dev->info->regs;
+
+       ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);
+
+       ksz8_port_setup(dev, dev->cpu_port, true);
+
+       ksz8795_cpu_interface_select(dev, dev->cpu_port);
+       ksz88x3_config_rmii_clk(dev);
+
+       for (i = 0; i < dev->phy_port_cnt; i++) {
+               ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
+       }
+       for (i = 0; i < dev->phy_port_cnt; i++) {
+               p = &dev->ports[i];
+
+               /* For KSZ8795 family. */
+               if (ksz_is_ksz87xx(dev)) {
+                       ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote);
+                       if (remote & KSZ8_PORT_FIBER_MODE)
+                               p->fiber = 1;
+               }
+               if (p->fiber)
+                       ksz_port_cfg(dev, i, regs[P_STP_CTRL],
+                                    PORT_FORCE_FLOW_CTRL, true);
+               else
+                       ksz_port_cfg(dev, i, regs[P_STP_CTRL],
+                                    PORT_FORCE_FLOW_CTRL, false);
+       }
+}
+
+/**
+ * ksz8_phy_port_link_up - Configures ports with integrated PHYs
+ * @dev: The KSZ device instance.
+ * @port: The port number to configure.
+ * @duplex: The desired duplex mode.
+ * @tx_pause: If true, enables transmit pause.
+ * @rx_pause: If true, enables receive pause.
+ *
+ * Description:
+ * The function configures flow control settings for a given port based on the
+ * desired settings and current duplex mode.
+ *
+ * According to the KSZ8873 datasheet, the PORT_FORCE_FLOW_CTRL bit in the
+ * Port Control 2 register (0x1A for Port 1, 0x22 for Port 2, 0x32 for Port 3)
+ * determines how flow control is handled on the port:
+ *    "1 = will always enable full-duplex flow control on the port, regardless
+ *         of AN result.
+ *     0 = full-duplex flow control is enabled based on AN result."
+ *
+ * This means that the flow control behavior depends on the state of this bit:
+ * - If PORT_FORCE_FLOW_CTRL is set to 1, the switch will ignore AN results and
+ *   force flow control on the port.
+ * - If PORT_FORCE_FLOW_CTRL is set to 0, the switch will enable or disable
+ *   flow control based on the AN results.
+ *
+ * However, there is a potential limitation in this configuration. It is
+ * currently not possible to force disable flow control on a port if we still
+ * advertise pause support. While such a configuration is not currently
+ * supported by Linux, and may not make practical sense, it's important to be
+ * aware of this limitation when working with the KSZ8873 and similar devices.
+ */
+static void ksz8_phy_port_link_up(struct ksz_device *dev, int port, int duplex,
+                                 bool tx_pause, bool rx_pause)
+{
+       const u16 *regs = dev->info->regs;
+       u8 sctrl = 0;
+
+       /* The KSZ8795 switch differs from the KSZ8873 by supporting
+        * asymmetric pause control. However, since a single bit is used to
+        * control both RX and TX pause, we can't enforce asymmetric pause
+        * control - both TX and RX pause will be either enabled or disabled
+        * together.
+        *
+        * If auto-negotiation is enabled, we usually allow the flow control to
+        * be determined by the auto-negotiation process based on the
+        * capabilities of both link partners. However, for KSZ8873, the
+        * PORT_FORCE_FLOW_CTRL bit may be set by the hardware bootstrap,
+        * ignoring the auto-negotiation result. Thus, even in auto-negotiation
+        * mode, we need to ensure that the PORT_FORCE_FLOW_CTRL bit is
+        * properly cleared.
+        *
+        * In the absence of pause auto-negotiation, we will enforce symmetric
+        * pause control for both variants of switches - KSZ8873 and KSZ8795.
+        *
+        * Autoneg Pause Autoneg      rx,tx     PORT_FORCE_FLOW_CTRL
+        * 1            1               x       0
+        * 0            1               x       0 (flow control probably disabled)
+        * x            0               1       1 (flow control force enabled)
+        * 1            0               0       0 (flow control still depends on
+        *                                         aneg result due to hardware)
+        * 0            0               0       0 (flow control probably disabled)
+        */
+       if (dev->ports[port].manual_flow && tx_pause)
+               sctrl |= PORT_FORCE_FLOW_CTRL;
+
+       ksz_prmw8(dev, port, regs[P_STP_CTRL], PORT_FORCE_FLOW_CTRL, sctrl);
+}
+
+/**
+ * ksz8_cpu_port_link_up - Configures the CPU port of the switch.
+ * @dev: The KSZ device instance.
+ * @speed: The desired link speed.
+ * @duplex: The desired duplex mode.
+ * @tx_pause: If true, enables transmit pause.
+ * @rx_pause: If true, enables receive pause.
+ *
+ * Description:
+ * The function configures flow control and speed settings for the CPU
+ * port of the switch based on the desired settings, current duplex mode, and
+ * speed.
+ */
+static void ksz8_cpu_port_link_up(struct ksz_device *dev, int speed, int duplex,
+                                 bool tx_pause, bool rx_pause)
+{
+       const u16 *regs = dev->info->regs;
+       u8 ctrl = 0;
+
+       /* SW_FLOW_CTRL, SW_HALF_DUPLEX, and SW_10_MBIT bits are bootstrappable
+        * at least on KSZ8873. They can have different values depending on your
+        * board setup.
+        */
+       if (tx_pause || rx_pause)
+               ctrl |= SW_FLOW_CTRL;
+
+       if (duplex == DUPLEX_HALF)
+               ctrl |= SW_HALF_DUPLEX;
+
+       /* This hardware only supports SPEED_10 and SPEED_100. For SPEED_10
+        * we need to set the SW_10_MBIT bit. Otherwise, we can leave it 0.
+        */
+       if (speed == SPEED_10)
+               ctrl |= SW_10_MBIT;
+
+       ksz_rmw8(dev, regs[S_BROADCAST_CTRL], SW_HALF_DUPLEX | SW_FLOW_CTRL |
+                SW_10_MBIT, ctrl);
+}
+
+void ksz8_phylink_mac_link_up(struct phylink_config *config,
+                             struct phy_device *phydev, unsigned int mode,
+                             phy_interface_t interface, int speed, int duplex,
+                             bool tx_pause, bool rx_pause)
+{
+       struct dsa_port *dp = dsa_phylink_to_port(config);
+       struct ksz_device *dev = dp->ds->priv;
+       int port = dp->index;
+
+       /* If the port is the CPU port, apply special handling. Only the CPU
+        * port is configured via global registers.
+        */
+       if (dev->cpu_port == port)
+               ksz8_cpu_port_link_up(dev, speed, duplex, tx_pause, rx_pause);
+       else if (dev->info->internal_phy[port])
+               ksz8_phy_port_link_up(dev, port, duplex, tx_pause, rx_pause);
+}
+
+static int ksz8_handle_global_errata(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       int ret = 0;
+
+       /* KSZ87xx Errata DS80000687C.
+        * Module 2: Link drops with some EEE link partners.
+        *   An issue with the EEE next page exchange between the
+        *   KSZ879x/KSZ877x/KSZ876x and some EEE link partners may result in
+        *   the link dropping.
+        */
+       if (dev->info->ksz87xx_eee_link_erratum)
+               ret = ksz8_ind_write8(dev, TABLE_EEE, REG_IND_EEE_GLOB2_HI, 0);
+
+       return ret;
+}
+
+int ksz8_enable_stp_addr(struct ksz_device *dev)
+{
+       struct alu_struct alu;
+
+       /* Setup STP address for STP operation. */
+       memset(&alu, 0, sizeof(alu));
+       ether_addr_copy(alu.mac, eth_stp_addr);
+       alu.is_static = true;
+       alu.is_override = true;
+       alu.port_forward = dev->info->cpu_ports;
+
+       return ksz8_w_sta_mac_table(dev, 0, &alu);
+}
+
+int ksz8_setup(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       const u16 *regs = dev->info->regs;
+       int i, ret = 0;
+
+       ds->mtu_enforcement_ingress = true;
+
+       /* We rely on software untagging on the CPU port, so that we
+        * can support both tagged and untagged VLANs
+        */
+       ds->untag_bridge_pvid = true;
+
+       /* VLAN filtering is partly controlled by the global VLAN
+        * Enable flag
+        */
+       ds->vlan_filtering_is_global = true;
+
+       /* Enable automatic fast aging when link changed detected. */
+       ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true);
+
+       /* Enable aggressive back off algorithm in half duplex mode. */
+       regmap_update_bits(ksz_regmap_8(dev), REG_SW_CTRL_1,
+                          SW_AGGR_BACKOFF, SW_AGGR_BACKOFF);
+
+       /*
+        * Make sure unicast VLAN boundary is set as default and
+        * enable no excessive collision drop.
+        */
+       regmap_update_bits(ksz_regmap_8(dev), REG_SW_CTRL_2,
+                          UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,
+                          UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP);
+
+       ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_REPLACE_VID, false);
+
+       ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
+
+       if (!ksz_is_ksz88x3(dev))
+               ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true);
+
+       for (i = 0; i < (dev->info->num_vlans / 4); i++)
+               ksz8_r_vlan_entries(dev, i);
+
+       /* Make sure PME (WoL) is not enabled. If requested, it will
+        * be enabled by ksz_wol_pre_shutdown(). Otherwise, some PMICs
+        * do not like PME events changes before shutdown. PME only
+        * available on KSZ87xx family.
+        */
+       if (ksz_is_ksz87xx(dev)) {
+               ret = ksz8_pme_write8(dev, regs[REG_SW_PME_CTRL], 0);
+               if (!ret)
+                       ret = ksz_rmw8(dev, REG_INT_ENABLE, INT_PME, 0);
+       }
+
+       if (!ret)
+               return ksz8_handle_global_errata(ds);
+       else
+               return ret;
+}
+
+void ksz8_get_caps(struct ksz_device *dev, int port,
+                  struct phylink_config *config)
+{
+       config->mac_capabilities = MAC_10 | MAC_100;
+
+       /* Silicon Errata Sheet (DS80000830A):
+        * "Port 1 does not respond to received flow control PAUSE frames"
+        * So, disable Pause support on "Port 1" (port == 0) for all ksz88x3
+        * switches.
+        */
+       if (!ksz_is_ksz88x3(dev) || port)
+               config->mac_capabilities |= MAC_SYM_PAUSE;
+
+       /* Asym pause is not supported on KSZ8863 and KSZ8873 */
+       if (!ksz_is_ksz88x3(dev))
+               config->mac_capabilities |= MAC_ASYM_PAUSE;
+}
+
+u32 ksz8_get_port_addr(int port, int offset)
+{
+       return PORT_CTRL_ADDR(port, offset);
+}
+
+int ksz8_switch_init(struct ksz_device *dev)
+{
+       dev->cpu_port = fls(dev->info->cpu_ports) - 1;
+       dev->phy_port_cnt = dev->info->port_cnt - 1;
+       dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports;
+
+       return 0;
+}
+
+void ksz8_switch_exit(struct ksz_device *dev)
+{
+       ksz8_reset_switch(dev);
+}
+
+MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
+MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch DSA Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
deleted file mode 100644 (file)
index aa09d89..0000000
+++ /dev/null
@@ -1,1968 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Microchip KSZ8795 switch driver
- *
- * Copyright (C) 2017 Microchip Technology Inc.
- *     Tristram Ha <Tristram.Ha@microchip.com>
- */
-
-#include <linux/bitfield.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/gpio.h>
-#include <linux/if_vlan.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_data/microchip-ksz.h>
-#include <linux/phy.h>
-#include <linux/etherdevice.h>
-#include <linux/if_bridge.h>
-#include <linux/micrel_phy.h>
-#include <net/dsa.h>
-#include <net/switchdev.h>
-#include <linux/phylink.h>
-
-#include "ksz_common.h"
-#include "ksz8795_reg.h"
-#include "ksz8.h"
-
-static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
-{
-       regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0);
-}
-
-static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
-                        bool set)
-{
-       regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset),
-                          bits, set ? bits : 0);
-}
-
-/**
- * ksz8_ind_write8 - EEE/ACL/PME indirect register write
- * @dev: The device structure.
- * @table: Function & table select, register 110.
- * @addr: Indirect access control, register 111.
- * @data: The data to be written.
- *
- * This function performs an indirect register write for EEE, ACL or
- * PME switch functionalities. Both 8-bit registers 110 and 111 are
- * written at once with ksz_write16, using the serial multiple write
- * functionality.
- *
- * Return: 0 on success, or an error code on failure.
- */
-static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
-{
-       const u16 *regs;
-       u16 ctrl_addr;
-       int ret = 0;
-
-       regs = dev->info->regs;
-
-       mutex_lock(&dev->alu_mutex);
-
-       ctrl_addr = IND_ACC_TABLE(table) | addr;
-       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-       if (!ret)
-               ret = ksz_write8(dev, regs[REG_IND_BYTE], data);
-
-       mutex_unlock(&dev->alu_mutex);
-
-       return ret;
-}
-
-/**
- * ksz8_ind_read8 - EEE/ACL/PME indirect register read
- * @dev: The device structure.
- * @table: Function & table select, register 110.
- * @addr: Indirect access control, register 111.
- * @val: The value read.
- *
- * This function performs an indirect register read for EEE, ACL or
- * PME switch functionalities. Both 8-bit registers 110 and 111 are
- * written at once with ksz_write16, using the serial multiple write
- * functionality.
- *
- * Return: 0 on success, or an error code on failure.
- */
-static int ksz8_ind_read8(struct ksz_device *dev, u8 table, u16 addr, u8 *val)
-{
-       const u16 *regs;
-       u16 ctrl_addr;
-       int ret = 0;
-
-       regs = dev->info->regs;
-
-       mutex_lock(&dev->alu_mutex);
-
-       ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
-       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-       if (!ret)
-               ret = ksz_read8(dev, regs[REG_IND_BYTE], val);
-
-       mutex_unlock(&dev->alu_mutex);
-
-       return ret;
-}
-
-int ksz8_pme_write8(struct ksz_device *dev, u32 reg, u8 value)
-{
-       return ksz8_ind_write8(dev, (u8)(reg >> 8), (u8)(reg), value);
-}
-
-int ksz8_pme_pread8(struct ksz_device *dev, int port, int offset, u8 *data)
-{
-       u8 table = (u8)(offset >> 8 | (port + 1));
-
-       return ksz8_ind_read8(dev, table, (u8)(offset), data);
-}
-
-int ksz8_pme_pwrite8(struct ksz_device *dev, int port, int offset, u8 data)
-{
-       u8 table = (u8)(offset >> 8 | (port + 1));
-
-       return ksz8_ind_write8(dev, table, (u8)(offset), data);
-}
-
-int ksz8_reset_switch(struct ksz_device *dev)
-{
-       if (ksz_is_ksz88x3(dev)) {
-               /* reset switch */
-               ksz_cfg(dev, KSZ8863_REG_SW_RESET,
-                       KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true);
-               ksz_cfg(dev, KSZ8863_REG_SW_RESET,
-                       KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, false);
-       } else {
-               /* reset switch */
-               ksz_write8(dev, REG_POWER_MANAGEMENT_1,
-                          SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S);
-               ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0);
-       }
-
-       return 0;
-}
-
-static int ksz8863_change_mtu(struct ksz_device *dev, int frame_size)
-{
-       u8 ctrl2 = 0;
-
-       if (frame_size <= KSZ8_LEGAL_PACKET_SIZE)
-               ctrl2 |= KSZ8863_LEGAL_PACKET_ENABLE;
-       else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE)
-               ctrl2 |= KSZ8863_HUGE_PACKET_ENABLE;
-
-       return ksz_rmw8(dev, REG_SW_CTRL_2, KSZ8863_LEGAL_PACKET_ENABLE |
-                       KSZ8863_HUGE_PACKET_ENABLE, ctrl2);
-}
-
-static int ksz8795_change_mtu(struct ksz_device *dev, int frame_size)
-{
-       u8 ctrl1 = 0, ctrl2 = 0;
-       int ret;
-
-       if (frame_size > KSZ8_LEGAL_PACKET_SIZE)
-               ctrl2 |= SW_LEGAL_PACKET_DISABLE;
-       if (frame_size > KSZ8863_NORMAL_PACKET_SIZE)
-               ctrl1 |= SW_HUGE_PACKET;
-
-       ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_HUGE_PACKET, ctrl1);
-       if (ret)
-               return ret;
-
-       return ksz_rmw8(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, ctrl2);
-}
-
-int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu)
-{
-       u16 frame_size;
-
-       if (!dsa_is_cpu_port(dev->ds, port))
-               return 0;
-
-       frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
-
-       switch (dev->chip_id) {
-       case KSZ8795_CHIP_ID:
-       case KSZ8794_CHIP_ID:
-       case KSZ8765_CHIP_ID:
-               return ksz8795_change_mtu(dev, frame_size);
-       case KSZ8830_CHIP_ID:
-       case KSZ8864_CHIP_ID:
-       case KSZ8895_CHIP_ID:
-               return ksz8863_change_mtu(dev, frame_size);
-       }
-
-       return -EOPNOTSUPP;
-}
-
-static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)
-{
-       u8 mask_4q, mask_2q;
-       u8 reg_4q, reg_2q;
-       u8 data_4q = 0;
-       u8 data_2q = 0;
-       int ret;
-
-       if (ksz_is_ksz88x3(dev)) {
-               mask_4q = KSZ8873_PORT_4QUEUE_SPLIT_EN;
-               mask_2q = KSZ8873_PORT_2QUEUE_SPLIT_EN;
-               reg_4q = REG_PORT_CTRL_0;
-               reg_2q = REG_PORT_CTRL_2;
-
-               /* KSZ8795 family switches have Weighted Fair Queueing (WFQ)
-                * enabled by default. Enable it for KSZ8873 family switches
-                * too. Default value for KSZ8873 family is strict priority,
-                * which should be enabled by using TC_SETUP_QDISC_ETS, not
-                * by default.
-                */
-               ret = ksz_rmw8(dev, REG_SW_CTRL_3, WEIGHTED_FAIR_QUEUE_ENABLE,
-                              WEIGHTED_FAIR_QUEUE_ENABLE);
-               if (ret)
-                       return ret;
-       } else {
-               mask_4q = KSZ8795_PORT_4QUEUE_SPLIT_EN;
-               mask_2q = KSZ8795_PORT_2QUEUE_SPLIT_EN;
-               reg_4q = REG_PORT_CTRL_13;
-               reg_2q = REG_PORT_CTRL_0;
-
-               /* TODO: this is legacy from initial KSZ8795 driver, should be
-                * moved to appropriate place in the future.
-                */
-               ret = ksz_rmw8(dev, REG_SW_CTRL_19,
-                              SW_OUT_RATE_LIMIT_QUEUE_BASED,
-                              SW_OUT_RATE_LIMIT_QUEUE_BASED);
-               if (ret)
-                       return ret;
-       }
-
-       if (queues == 4)
-               data_4q = mask_4q;
-       else if (queues == 2)
-               data_2q = mask_2q;
-
-       ret = ksz_prmw8(dev, port, reg_4q, mask_4q, data_4q);
-       if (ret)
-               return ret;
-
-       return ksz_prmw8(dev, port, reg_2q, mask_2q, data_2q);
-}
-
-int ksz8_all_queues_split(struct ksz_device *dev, int queues)
-{
-       struct dsa_switch *ds = dev->ds;
-       const struct dsa_port *dp;
-
-       dsa_switch_for_each_port(dp, ds) {
-               int ret = ksz8_port_queue_split(dev, dp->index, queues);
-
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
-{
-       const u32 *masks;
-       const u16 *regs;
-       u16 ctrl_addr;
-       u32 data;
-       u8 check;
-       int loop;
-
-       masks = dev->info->masks;
-       regs = dev->info->regs;
-
-       ctrl_addr = addr + dev->info->reg_mib_cnt * port;
-       ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
-
-       mutex_lock(&dev->alu_mutex);
-       ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-
-       /* It is almost guaranteed to always read the valid bit because of
-        * slow SPI speed.
-        */
-       for (loop = 2; loop > 0; loop--) {
-               ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
-
-               if (check & masks[MIB_COUNTER_VALID]) {
-                       ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
-                       if (check & masks[MIB_COUNTER_OVERFLOW])
-                               *cnt += MIB_COUNTER_VALUE + 1;
-                       *cnt += data & MIB_COUNTER_VALUE;
-                       break;
-               }
-       }
-       mutex_unlock(&dev->alu_mutex);
-}
-
-static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
-                             u64 *dropped, u64 *cnt)
-{
-       const u32 *masks;
-       const u16 *regs;
-       u16 ctrl_addr;
-       u32 data;
-       u8 check;
-       int loop;
-
-       masks = dev->info->masks;
-       regs = dev->info->regs;
-
-       addr -= dev->info->reg_mib_cnt;
-       ctrl_addr = (KSZ8795_MIB_TOTAL_RX_1 - KSZ8795_MIB_TOTAL_RX_0) * port;
-       ctrl_addr += addr + KSZ8795_MIB_TOTAL_RX_0;
-       ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
-
-       mutex_lock(&dev->alu_mutex);
-       ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-
-       /* It is almost guaranteed to always read the valid bit because of
-        * slow SPI speed.
-        */
-       for (loop = 2; loop > 0; loop--) {
-               ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
-
-               if (check & masks[MIB_COUNTER_VALID]) {
-                       ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
-                       if (addr < 2) {
-                               u64 total;
-
-                               total = check & MIB_TOTAL_BYTES_H;
-                               total <<= 32;
-                               *cnt += total;
-                               *cnt += data;
-                               if (check & masks[MIB_COUNTER_OVERFLOW]) {
-                                       total = MIB_TOTAL_BYTES_H + 1;
-                                       total <<= 32;
-                                       *cnt += total;
-                               }
-                       } else {
-                               if (check & masks[MIB_COUNTER_OVERFLOW])
-                                       *cnt += MIB_PACKET_DROPPED + 1;
-                               *cnt += data & MIB_PACKET_DROPPED;
-                       }
-                       break;
-               }
-       }
-       mutex_unlock(&dev->alu_mutex);
-}
-
-static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
-                             u64 *dropped, u64 *cnt)
-{
-       u32 *last = (u32 *)dropped;
-       const u16 *regs;
-       u16 ctrl_addr;
-       u32 data;
-       u32 cur;
-
-       regs = dev->info->regs;
-
-       addr -= dev->info->reg_mib_cnt;
-       ctrl_addr = addr ? KSZ8863_MIB_PACKET_DROPPED_TX_0 :
-                          KSZ8863_MIB_PACKET_DROPPED_RX_0;
-       ctrl_addr += port;
-       ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
-
-       mutex_lock(&dev->alu_mutex);
-       ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-       ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
-       mutex_unlock(&dev->alu_mutex);
-
-       data &= MIB_PACKET_DROPPED;
-       cur = last[addr];
-       if (data != cur) {
-               last[addr] = data;
-               if (data < cur)
-                       data += MIB_PACKET_DROPPED + 1;
-               data -= cur;
-               *cnt += data;
-       }
-}
-
-void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
-                   u64 *dropped, u64 *cnt)
-{
-       if (is_ksz88xx(dev))
-               ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
-       else
-               ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
-}
-
-void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
-{
-       if (is_ksz88xx(dev))
-               return;
-
-       /* enable the port for flush/freeze function */
-       if (freeze)
-               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
-       ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FREEZE, freeze);
-
-       /* disable the port after freeze is done */
-       if (!freeze)
-               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
-}
-
-void ksz8_port_init_cnt(struct ksz_device *dev, int port)
-{
-       struct ksz_port_mib *mib = &dev->ports[port].mib;
-       u64 *dropped;
-
-       /* For KSZ8795 family. */
-       if (ksz_is_ksz87xx(dev)) {
-               /* flush all enabled port MIB counters */
-               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
-               ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true);
-               ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
-       }
-
-       mib->cnt_ptr = 0;
-
-       /* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
-       while (mib->cnt_ptr < dev->info->reg_mib_cnt) {
-               dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
-                                       &mib->counters[mib->cnt_ptr]);
-               ++mib->cnt_ptr;
-       }
-
-       /* last one in storage */
-       dropped = &mib->counters[dev->info->mib_cnt];
-
-       /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
-       while (mib->cnt_ptr < dev->info->mib_cnt) {
-               dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
-                                       dropped, &mib->counters[mib->cnt_ptr]);
-               ++mib->cnt_ptr;
-       }
-}
-
-static int ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)
-{
-       const u16 *regs;
-       u16 ctrl_addr;
-       int ret;
-
-       regs = dev->info->regs;
-
-       ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
-
-       mutex_lock(&dev->alu_mutex);
-       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-       if (ret)
-               goto unlock_alu;
-
-       ret = ksz_read64(dev, regs[REG_IND_DATA_HI], data);
-unlock_alu:
-       mutex_unlock(&dev->alu_mutex);
-
-       return ret;
-}
-
-static int ksz8_w_table(struct ksz_device *dev, int table, u16 addr, u64 data)
-{
-       const u16 *regs;
-       u16 ctrl_addr;
-       int ret;
-
-       regs = dev->info->regs;
-
-       ctrl_addr = IND_ACC_TABLE(table) | addr;
-
-       mutex_lock(&dev->alu_mutex);
-       ret = ksz_write64(dev, regs[REG_IND_DATA_HI], data);
-       if (ret)
-               goto unlock_alu;
-
-       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-unlock_alu:
-       mutex_unlock(&dev->alu_mutex);
-
-       return ret;
-}
-
-static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data)
-{
-       int timeout = 100;
-       const u32 *masks;
-       const u16 *regs;
-       int ret;
-
-       masks = dev->info->masks;
-       regs = dev->info->regs;
-
-       do {
-               ret = ksz_read8(dev, regs[REG_IND_DATA_CHECK], data);
-               if (ret)
-                       return ret;
-
-               timeout--;
-       } while ((*data & masks[DYNAMIC_MAC_TABLE_NOT_READY]) && timeout);
-
-       /* Entry is not ready for accessing. */
-       if (*data & masks[DYNAMIC_MAC_TABLE_NOT_READY])
-               return -ETIMEDOUT;
-
-       /* Entry is ready for accessing. */
-       return ksz_read8(dev, regs[REG_IND_DATA_8], data);
-}
-
-static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,
-                               u8 *fid, u8 *src_port, u16 *entries)
-{
-       u32 data_hi, data_lo;
-       const u8 *shifts;
-       const u32 *masks;
-       const u16 *regs;
-       u16 ctrl_addr;
-       u64 buf = 0;
-       u8 data;
-       int cnt;
-       int ret;
-
-       shifts = dev->info->shifts;
-       masks = dev->info->masks;
-       regs = dev->info->regs;
-
-       ctrl_addr = IND_ACC_TABLE(TABLE_DYNAMIC_MAC | TABLE_READ) | addr;
-
-       mutex_lock(&dev->alu_mutex);
-       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
-       if (ret)
-               goto unlock_alu;
-
-       ret = ksz8_valid_dyn_entry(dev, &data);
-       if (ret)
-               goto unlock_alu;
-
-       if (data & masks[DYNAMIC_MAC_TABLE_MAC_EMPTY]) {
-               *entries = 0;
-               goto unlock_alu;
-       }
-
-       ret = ksz_read64(dev, regs[REG_IND_DATA_HI], &buf);
-       if (ret)
-               goto unlock_alu;
-
-       data_hi = (u32)(buf >> 32);
-       data_lo = (u32)buf;
-
-       /* Check out how many valid entry in the table. */
-       cnt = data & masks[DYNAMIC_MAC_TABLE_ENTRIES_H];
-       cnt <<= shifts[DYNAMIC_MAC_ENTRIES_H];
-       cnt |= (data_hi & masks[DYNAMIC_MAC_TABLE_ENTRIES]) >>
-               shifts[DYNAMIC_MAC_ENTRIES];
-       *entries = cnt + 1;
-
-       *fid = (data_hi & masks[DYNAMIC_MAC_TABLE_FID]) >>
-               shifts[DYNAMIC_MAC_FID];
-       *src_port = (data_hi & masks[DYNAMIC_MAC_TABLE_SRC_PORT]) >>
-               shifts[DYNAMIC_MAC_SRC_PORT];
-
-       mac_addr[5] = (u8)data_lo;
-       mac_addr[4] = (u8)(data_lo >> 8);
-       mac_addr[3] = (u8)(data_lo >> 16);
-       mac_addr[2] = (u8)(data_lo >> 24);
-
-       mac_addr[1] = (u8)data_hi;
-       mac_addr[0] = (u8)(data_hi >> 8);
-
-unlock_alu:
-       mutex_unlock(&dev->alu_mutex);
-
-       return ret;
-}
-
-static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
-                               struct alu_struct *alu, bool *valid)
-{
-       u32 data_hi, data_lo;
-       const u8 *shifts;
-       const u32 *masks;
-       u64 data;
-       int ret;
-
-       shifts = dev->info->shifts;
-       masks = dev->info->masks;
-
-       ret = ksz8_r_table(dev, TABLE_STATIC_MAC, addr, &data);
-       if (ret)
-               return ret;
-
-       data_hi = data >> 32;
-       data_lo = (u32)data;
-
-       if (!(data_hi & (masks[STATIC_MAC_TABLE_VALID] |
-                        masks[STATIC_MAC_TABLE_OVERRIDE]))) {
-               *valid = false;
-               return 0;
-       }
-
-       alu->mac[5] = (u8)data_lo;
-       alu->mac[4] = (u8)(data_lo >> 8);
-       alu->mac[3] = (u8)(data_lo >> 16);
-       alu->mac[2] = (u8)(data_lo >> 24);
-       alu->mac[1] = (u8)data_hi;
-       alu->mac[0] = (u8)(data_hi >> 8);
-       alu->port_forward =
-               (data_hi & masks[STATIC_MAC_TABLE_FWD_PORTS]) >>
-                       shifts[STATIC_MAC_FWD_PORTS];
-       alu->is_override = (data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0;
-
-       /* KSZ8795/KSZ8895 family switches have STATIC_MAC_TABLE_USE_FID and
-        * STATIC_MAC_TABLE_FID definitions off by 1 when doing read on the
-        * static MAC table compared to doing write.
-        */
-       if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev))
-               data_hi >>= 1;
-       alu->is_static = true;
-       alu->is_use_fid = (data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0;
-       alu->fid = (data_hi & masks[STATIC_MAC_TABLE_FID]) >>
-               shifts[STATIC_MAC_FID];
-
-       *valid = true;
-
-       return 0;
-}
-
-static int ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
-                               struct alu_struct *alu)
-{
-       u32 data_hi, data_lo;
-       const u8 *shifts;
-       const u32 *masks;
-       u64 data;
-
-       shifts = dev->info->shifts;
-       masks = dev->info->masks;
-
-       data_lo = ((u32)alu->mac[2] << 24) |
-               ((u32)alu->mac[3] << 16) |
-               ((u32)alu->mac[4] << 8) | alu->mac[5];
-       data_hi = ((u32)alu->mac[0] << 8) | alu->mac[1];
-       data_hi |= (u32)alu->port_forward << shifts[STATIC_MAC_FWD_PORTS];
-
-       if (alu->is_override)
-               data_hi |= masks[STATIC_MAC_TABLE_OVERRIDE];
-       if (alu->is_use_fid) {
-               data_hi |= masks[STATIC_MAC_TABLE_USE_FID];
-               data_hi |= (u32)alu->fid << shifts[STATIC_MAC_FID];
-       }
-       if (alu->is_static)
-               data_hi |= masks[STATIC_MAC_TABLE_VALID];
-       else
-               data_hi &= ~masks[STATIC_MAC_TABLE_OVERRIDE];
-
-       data = (u64)data_hi << 32 | data_lo;
-
-       return ksz8_w_table(dev, TABLE_STATIC_MAC, addr, data);
-}
-
-static void ksz8_from_vlan(struct ksz_device *dev, u32 vlan, u8 *fid,
-                          u8 *member, u8 *valid)
-{
-       const u8 *shifts;
-       const u32 *masks;
-
-       shifts = dev->info->shifts;
-       masks = dev->info->masks;
-
-       *fid = vlan & masks[VLAN_TABLE_FID];
-       *member = (vlan & masks[VLAN_TABLE_MEMBERSHIP]) >>
-                       shifts[VLAN_TABLE_MEMBERSHIP_S];
-       *valid = !!(vlan & masks[VLAN_TABLE_VALID]);
-}
-
-static void ksz8_to_vlan(struct ksz_device *dev, u8 fid, u8 member, u8 valid,
-                        u16 *vlan)
-{
-       const u8 *shifts;
-       const u32 *masks;
-
-       shifts = dev->info->shifts;
-       masks = dev->info->masks;
-
-       *vlan = fid;
-       *vlan |= (u16)member << shifts[VLAN_TABLE_MEMBERSHIP_S];
-       if (valid)
-               *vlan |= masks[VLAN_TABLE_VALID];
-}
-
-static void ksz8_r_vlan_entries(struct ksz_device *dev, u16 addr)
-{
-       const u8 *shifts;
-       u64 data;
-       int i;
-
-       shifts = dev->info->shifts;
-
-       ksz8_r_table(dev, TABLE_VLAN, addr, &data);
-       addr *= 4;
-       for (i = 0; i < 4; i++) {
-               dev->vlan_cache[addr + i].table[0] = (u16)data;
-               data >>= shifts[VLAN_TABLE];
-       }
-}
-
-static void ksz8_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan)
-{
-       int index;
-       u16 *data;
-       u16 addr;
-       u64 buf;
-
-       data = (u16 *)&buf;
-       addr = vid / 4;
-       index = vid & 3;
-       ksz8_r_table(dev, TABLE_VLAN, addr, &buf);
-       *vlan = data[index];
-}
-
-static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
-{
-       int index;
-       u16 *data;
-       u16 addr;
-       u64 buf;
-
-       data = (u16 *)&buf;
-       addr = vid / 4;
-       index = vid & 3;
-       ksz8_r_table(dev, TABLE_VLAN, addr, &buf);
-       data[index] = vlan;
-       dev->vlan_cache[vid].table[0] = vlan;
-       ksz8_w_table(dev, TABLE_VLAN, addr, buf);
-}
-
-/**
- * ksz879x_get_loopback - KSZ879x specific function to get loopback
- *                        configuration status for a specific port
- * @dev: Pointer to the device structure
- * @port: Port number to query
- * @val: Pointer to store the result
- *
- * This function reads the SMI registers to determine whether loopback mode
- * is enabled for a specific port.
- *
- * Return: 0 on success, error code on failure.
- */
-static int ksz879x_get_loopback(struct ksz_device *dev, u16 port,
-                               u16 *val)
-{
-       u8 stat3;
-       int ret;
-
-       ret = ksz_pread8(dev, port, REG_PORT_STATUS_3, &stat3);
-       if (ret)
-               return ret;
-
-       if (stat3 & PORT_PHY_LOOPBACK)
-               *val |= BMCR_LOOPBACK;
-
-       return 0;
-}
-
-/**
- * ksz879x_set_loopback - KSZ879x specific function  to set loopback mode for
- *                       a specific port
- * @dev: Pointer to the device structure.
- * @port: Port number to modify.
- * @val: Value indicating whether to enable or disable loopback mode.
- *
- * This function translates loopback bit of the BMCR register into the
- * corresponding hardware register bit value and writes it to the SMI interface.
- *
- * Return: 0 on success, error code on failure.
- */
-static int ksz879x_set_loopback(struct ksz_device *dev, u16 port, u16 val)
-{
-       u8 stat3 = 0;
-
-       if (val & BMCR_LOOPBACK)
-               stat3 |= PORT_PHY_LOOPBACK;
-
-       return ksz_prmw8(dev, port, REG_PORT_STATUS_3, PORT_PHY_LOOPBACK,
-                        stat3);
-}
-
-/**
- * ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY
- *                  Control register (Reg. 31).
- * @dev: The KSZ device instance.
- * @port: The port number to be read.
- * @val: The value read from the SMI interface.
- *
- * This function reads the SMI interface and translates the hardware register
- * bit values into their corresponding control settings for a MIIM PHY Control
- * register.
- *
- * Return: 0 on success, error code on failure.
- */
-static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val)
-{
-       const u16 *regs = dev->info->regs;
-       u8 reg_val;
-       int ret;
-
-       *val = 0;
-
-       ret = ksz_pread8(dev, port, regs[P_LINK_STATUS], &reg_val);
-       if (ret < 0)
-               return ret;
-
-       if (reg_val & PORT_MDIX_STATUS)
-               *val |= KSZ886X_CTRL_MDIX_STAT;
-
-       ret = ksz_pread8(dev, port, REG_PORT_LINK_MD_CTRL, &reg_val);
-       if (ret < 0)
-               return ret;
-
-       if (reg_val & PORT_FORCE_LINK)
-               *val |= KSZ886X_CTRL_FORCE_LINK;
-
-       if (reg_val & PORT_POWER_SAVING)
-               *val |= KSZ886X_CTRL_PWRSAVE;
-
-       if (reg_val & PORT_PHY_REMOTE_LOOPBACK)
-               *val |= KSZ886X_CTRL_REMOTE_LOOPBACK;
-
-       return 0;
-}
-
-/**
- * ksz8_r_phy_bmcr - Translates and reads from the SMI interface to a MIIM PHY
- *                  Basic mode control register (Reg. 0).
- * @dev: The KSZ device instance.
- * @port: The port number to be read.
- * @val: The value read from the SMI interface.
- *
- * This function reads the SMI interface and translates the hardware register
- * bit values into their corresponding control settings for a MIIM PHY Basic
- * mode control register.
- *
- * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873
- * -------------------------------------------------------------------
- * MIIM Bit                    | KSZ8794 Reg/Bit             | KSZ8873 Reg/Bit
- * ----------------------------+-----------------------------+----------------
- * Bit 15 - Soft Reset         | 0xF/4                       | Not supported
- * Bit 14 - Loopback           | 0xD/0 (MAC), 0xF/7 (PHY)    ~ 0xD/0 (PHY)
- * Bit 13 - Force 100          | 0xC/6                       = 0xC/6
- * Bit 12 - AN Enable          | 0xC/7 (reverse logic)       ~ 0xC/7
- * Bit 11 - Power Down         | 0xD/3                       = 0xD/3
- * Bit 10 - PHY Isolate        | 0xF/5                       | Not supported
- * Bit 9 - Restart AN          | 0xD/5                       = 0xD/5
- * Bit 8 - Force Full-Duplex   | 0xC/5                       = 0xC/5
- * Bit 7 - Collision Test/Res. | Not supported               | Not supported
- * Bit 6 - Reserved            | Not supported               | Not supported
- * Bit 5 - Hp_mdix             | 0x9/7                       ~ 0xF/7
- * Bit 4 - Force MDI           | 0xD/1                       = 0xD/1
- * Bit 3 - Disable MDIX        | 0xD/2                       = 0xD/2
- * Bit 2 - Disable Far-End F.  | ????                        | 0xD/4
- * Bit 1 - Disable Transmit    | 0xD/6                       = 0xD/6
- * Bit 0 - Disable LED         | 0xD/7                       = 0xD/7
- * -------------------------------------------------------------------
- *
- * Return: 0 on success, error code on failure.
- */
-static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val)
-{
-       const u16 *regs = dev->info->regs;
-       u8 restart, speed, ctrl;
-       int ret;
-
-       *val = 0;
-
-       ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart);
-       if (ret)
-               return ret;
-
-       ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed);
-       if (ret)
-               return ret;
-
-       ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl);
-       if (ret)
-               return ret;
-
-       if (ctrl & PORT_FORCE_100_MBIT)
-               *val |= BMCR_SPEED100;
-
-       if (ksz_is_ksz88x3(dev)) {
-               if (restart & KSZ8873_PORT_PHY_LOOPBACK)
-                       *val |= BMCR_LOOPBACK;
-
-               if ((ctrl & PORT_AUTO_NEG_ENABLE))
-                       *val |= BMCR_ANENABLE;
-       } else {
-               ret = ksz879x_get_loopback(dev, port, val);
-               if (ret)
-                       return ret;
-
-               if (!(ctrl & PORT_AUTO_NEG_DISABLE))
-                       *val |= BMCR_ANENABLE;
-       }
-
-       if (restart & PORT_POWER_DOWN)
-               *val |= BMCR_PDOWN;
-
-       if (restart & PORT_AUTO_NEG_RESTART)
-               *val |= BMCR_ANRESTART;
-
-       if (ctrl & PORT_FORCE_FULL_DUPLEX)
-               *val |= BMCR_FULLDPLX;
-
-       if (speed & PORT_HP_MDIX)
-               *val |= KSZ886X_BMCR_HP_MDIX;
-
-       if (restart & PORT_FORCE_MDIX)
-               *val |= KSZ886X_BMCR_FORCE_MDI;
-
-       if (restart & PORT_AUTO_MDIX_DISABLE)
-               *val |= KSZ886X_BMCR_DISABLE_AUTO_MDIX;
-
-       if (restart & PORT_TX_DISABLE)
-               *val |= KSZ886X_BMCR_DISABLE_TRANSMIT;
-
-       if (restart & PORT_LED_OFF)
-               *val |= KSZ886X_BMCR_DISABLE_LED;
-
-       return 0;
-}
-
-int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
-{
-       u8 ctrl, link, val1, val2;
-       int processed = true;
-       const u16 *regs;
-       u16 data = 0;
-       u16 p = phy;
-       int ret;
-
-       regs = dev->info->regs;
-
-       switch (reg) {
-       case MII_BMCR:
-               ret = ksz8_r_phy_bmcr(dev, p, &data);
-               if (ret)
-                       return ret;
-               break;
-       case MII_BMSR:
-               ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
-               if (ret)
-                       return ret;
-
-               data = BMSR_100FULL |
-                      BMSR_100HALF |
-                      BMSR_10FULL |
-                      BMSR_10HALF |
-                      BMSR_ANEGCAPABLE;
-               if (link & PORT_AUTO_NEG_COMPLETE)
-                       data |= BMSR_ANEGCOMPLETE;
-               if (link & PORT_STAT_LINK_GOOD)
-                       data |= BMSR_LSTATUS;
-               break;
-       case MII_PHYSID1:
-               data = KSZ8795_ID_HI;
-               break;
-       case MII_PHYSID2:
-               if (ksz_is_ksz88x3(dev))
-                       data = KSZ8863_ID_LO;
-               else
-                       data = KSZ8795_ID_LO;
-               break;
-       case MII_ADVERTISE:
-               ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
-               if (ret)
-                       return ret;
-
-               data = ADVERTISE_CSMA;
-               if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
-                       data |= ADVERTISE_PAUSE_CAP;
-               if (ctrl & PORT_AUTO_NEG_100BTX_FD)
-                       data |= ADVERTISE_100FULL;
-               if (ctrl & PORT_AUTO_NEG_100BTX)
-                       data |= ADVERTISE_100HALF;
-               if (ctrl & PORT_AUTO_NEG_10BT_FD)
-                       data |= ADVERTISE_10FULL;
-               if (ctrl & PORT_AUTO_NEG_10BT)
-                       data |= ADVERTISE_10HALF;
-               break;
-       case MII_LPA:
-               ret = ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link);
-               if (ret)
-                       return ret;
-
-               data = LPA_SLCT;
-               if (link & PORT_REMOTE_SYM_PAUSE)
-                       data |= LPA_PAUSE_CAP;
-               if (link & PORT_REMOTE_100BTX_FD)
-                       data |= LPA_100FULL;
-               if (link & PORT_REMOTE_100BTX)
-                       data |= LPA_100HALF;
-               if (link & PORT_REMOTE_10BT_FD)
-                       data |= LPA_10FULL;
-               if (link & PORT_REMOTE_10BT)
-                       data |= LPA_10HALF;
-               if (data & ~LPA_SLCT)
-                       data |= LPA_LPACK;
-               break;
-       case PHY_REG_LINK_MD:
-               ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1);
-               if (ret)
-                       return ret;
-
-               ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2);
-               if (ret)
-                       return ret;
-
-               if (val1 & PORT_START_CABLE_DIAG)
-                       data |= PHY_START_CABLE_DIAG;
-
-               if (val1 & PORT_CABLE_10M_SHORT)
-                       data |= PHY_CABLE_10M_SHORT;
-
-               data |= FIELD_PREP(PHY_CABLE_DIAG_RESULT_M,
-                               FIELD_GET(PORT_CABLE_DIAG_RESULT_M, val1));
-
-               data |= FIELD_PREP(PHY_CABLE_FAULT_COUNTER_M,
-                               (FIELD_GET(PORT_CABLE_FAULT_COUNTER_H, val1) << 8) |
-                               FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2));
-               break;
-       case PHY_REG_PHY_CTRL:
-               ret = ksz8_r_phy_ctrl(dev, p, &data);
-               if (ret)
-                       return ret;
-
-               break;
-       default:
-               processed = false;
-               break;
-       }
-       if (processed)
-               *val = data;
-
-       return 0;
-}
-
-/**
- * ksz8_w_phy_ctrl - Translates and writes to the SMI interface from a MIIM PHY
- *                  Control register (Reg. 31).
- * @dev: The KSZ device instance.
- * @port: The port number to be configured.
- * @val: The register value to be written.
- *
- * This function translates control settings from a MIIM PHY Control register
- * into their corresponding hardware register bit values for the SMI
- * interface.
- *
- * Return: 0 on success, error code on failure.
- */
-static int ksz8_w_phy_ctrl(struct ksz_device *dev, int port, u16 val)
-{
-       u8 reg_val = 0;
-       int ret;
-
-       if (val & KSZ886X_CTRL_FORCE_LINK)
-               reg_val |= PORT_FORCE_LINK;
-
-       if (val & KSZ886X_CTRL_PWRSAVE)
-               reg_val |= PORT_POWER_SAVING;
-
-       if (val & KSZ886X_CTRL_REMOTE_LOOPBACK)
-               reg_val |= PORT_PHY_REMOTE_LOOPBACK;
-
-       ret = ksz_prmw8(dev, port, REG_PORT_LINK_MD_CTRL, PORT_FORCE_LINK |
-                       PORT_POWER_SAVING | PORT_PHY_REMOTE_LOOPBACK, reg_val);
-       return ret;
-}
-
-/**
- * ksz8_w_phy_bmcr - Translates and writes to the SMI interface from a MIIM PHY
- *                  Basic mode control register (Reg. 0).
- * @dev: The KSZ device instance.
- * @port: The port number to be configured.
- * @val: The register value to be written.
- *
- * This function translates control settings from a MIIM PHY Basic mode control
- * register into their corresponding hardware register bit values for the SMI
- * interface.
- *
- * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873
- * -------------------------------------------------------------------
- * MIIM Bit                    | KSZ8794 Reg/Bit             | KSZ8873 Reg/Bit
- * ----------------------------+-----------------------------+----------------
- * Bit 15 - Soft Reset         | 0xF/4                       | Not supported
- * Bit 14 - Loopback           | 0xD/0 (MAC), 0xF/7 (PHY)    ~ 0xD/0 (PHY)
- * Bit 13 - Force 100          | 0xC/6                       = 0xC/6
- * Bit 12 - AN Enable          | 0xC/7 (reverse logic)       ~ 0xC/7
- * Bit 11 - Power Down         | 0xD/3                       = 0xD/3
- * Bit 10 - PHY Isolate        | 0xF/5                       | Not supported
- * Bit 9 - Restart AN          | 0xD/5                       = 0xD/5
- * Bit 8 - Force Full-Duplex   | 0xC/5                       = 0xC/5
- * Bit 7 - Collision Test/Res. | Not supported               | Not supported
- * Bit 6 - Reserved            | Not supported               | Not supported
- * Bit 5 - Hp_mdix             | 0x9/7                       ~ 0xF/7
- * Bit 4 - Force MDI           | 0xD/1                       = 0xD/1
- * Bit 3 - Disable MDIX        | 0xD/2                       = 0xD/2
- * Bit 2 - Disable Far-End F.  | ????                        | 0xD/4
- * Bit 1 - Disable Transmit    | 0xD/6                       = 0xD/6
- * Bit 0 - Disable LED         | 0xD/7                       = 0xD/7
- * -------------------------------------------------------------------
- *
- * Return: 0 on success, error code on failure.
- */
-static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val)
-{
-       u8 restart, speed, ctrl, restart_mask;
-       const u16 *regs = dev->info->regs;
-       int ret;
-
-       /* Do not support PHY reset function. */
-       if (val & BMCR_RESET)
-               return 0;
-
-       speed = 0;
-       if (val & KSZ886X_BMCR_HP_MDIX)
-               speed |= PORT_HP_MDIX;
-
-       ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed);
-       if (ret)
-               return ret;
-
-       ctrl = 0;
-       if (ksz_is_ksz88x3(dev)) {
-               if ((val & BMCR_ANENABLE))
-                       ctrl |= PORT_AUTO_NEG_ENABLE;
-       } else {
-               if (!(val & BMCR_ANENABLE))
-                       ctrl |= PORT_AUTO_NEG_DISABLE;
-
-               /* Fiber port does not support auto-negotiation. */
-               if (dev->ports[port].fiber)
-                       ctrl |= PORT_AUTO_NEG_DISABLE;
-       }
-
-       if (val & BMCR_SPEED100)
-               ctrl |= PORT_FORCE_100_MBIT;
-
-       if (val & BMCR_FULLDPLX)
-               ctrl |= PORT_FORCE_FULL_DUPLEX;
-
-       ret = ksz_prmw8(dev, port, regs[P_FORCE_CTRL], PORT_FORCE_100_MBIT |
-                /* PORT_AUTO_NEG_ENABLE and PORT_AUTO_NEG_DISABLE are the same
-                 * bits
-                 */
-                PORT_FORCE_FULL_DUPLEX | PORT_AUTO_NEG_ENABLE, ctrl);
-       if (ret)
-               return ret;
-
-       restart = 0;
-       restart_mask = PORT_LED_OFF | PORT_TX_DISABLE | PORT_AUTO_NEG_RESTART |
-               PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX;
-
-       if (val & KSZ886X_BMCR_DISABLE_LED)
-               restart |= PORT_LED_OFF;
-
-       if (val & KSZ886X_BMCR_DISABLE_TRANSMIT)
-               restart |= PORT_TX_DISABLE;
-
-       if (val & BMCR_ANRESTART)
-               restart |= PORT_AUTO_NEG_RESTART;
-
-       if (val & BMCR_PDOWN)
-               restart |= PORT_POWER_DOWN;
-
-       if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX)
-               restart |= PORT_AUTO_MDIX_DISABLE;
-
-       if (val & KSZ886X_BMCR_FORCE_MDI)
-               restart |= PORT_FORCE_MDIX;
-
-       if (ksz_is_ksz88x3(dev)) {
-               restart_mask |= KSZ8873_PORT_PHY_LOOPBACK;
-
-               if (val & BMCR_LOOPBACK)
-                       restart |= KSZ8873_PORT_PHY_LOOPBACK;
-       } else {
-               ret = ksz879x_set_loopback(dev, port, val);
-               if (ret)
-                       return ret;
-       }
-
-       return ksz_prmw8(dev, port, regs[P_NEG_RESTART_CTRL], restart_mask,
-                        restart);
-}
-
-int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
-{
-       const u16 *regs;
-       u8 ctrl, data;
-       u16 p = phy;
-       int ret;
-
-       regs = dev->info->regs;
-
-       switch (reg) {
-       case MII_BMCR:
-               ret = ksz8_w_phy_bmcr(dev, p, val);
-               if (ret)
-                       return ret;
-               break;
-       case MII_ADVERTISE:
-               ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
-               if (ret)
-                       return ret;
-
-               data = ctrl;
-               data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
-                         PORT_AUTO_NEG_100BTX_FD |
-                         PORT_AUTO_NEG_100BTX |
-                         PORT_AUTO_NEG_10BT_FD |
-                         PORT_AUTO_NEG_10BT);
-               if (val & ADVERTISE_PAUSE_CAP)
-                       data |= PORT_AUTO_NEG_SYM_PAUSE;
-               if (val & ADVERTISE_100FULL)
-                       data |= PORT_AUTO_NEG_100BTX_FD;
-               if (val & ADVERTISE_100HALF)
-                       data |= PORT_AUTO_NEG_100BTX;
-               if (val & ADVERTISE_10FULL)
-                       data |= PORT_AUTO_NEG_10BT_FD;
-               if (val & ADVERTISE_10HALF)
-                       data |= PORT_AUTO_NEG_10BT;
-
-               if (data != ctrl) {
-                       ret = ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case PHY_REG_LINK_MD:
-               if (val & PHY_START_CABLE_DIAG)
-                       ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);
-               break;
-
-       case PHY_REG_PHY_CTRL:
-               ret = ksz8_w_phy_ctrl(dev, p, val);
-               if (ret)
-                       return ret;
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
-{
-       u8 data;
-
-       ksz_pread8(dev, port, P_MIRROR_CTRL, &data);
-       data &= ~PORT_VLAN_MEMBERSHIP;
-       data |= (member & dev->port_mask);
-       ksz_pwrite8(dev, port, P_MIRROR_CTRL, data);
-}
-
-void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
-{
-       u8 learn[DSA_MAX_PORTS];
-       int first, index, cnt;
-       const u16 *regs;
-
-       regs = dev->info->regs;
-
-       if ((uint)port < dev->info->port_cnt) {
-               first = port;
-               cnt = port + 1;
-       } else {
-               /* Flush all ports. */
-               first = 0;
-               cnt = dev->info->port_cnt;
-       }
-       for (index = first; index < cnt; index++) {
-               ksz_pread8(dev, index, regs[P_STP_CTRL], &learn[index]);
-               if (!(learn[index] & PORT_LEARN_DISABLE))
-                       ksz_pwrite8(dev, index, regs[P_STP_CTRL],
-                                   learn[index] | PORT_LEARN_DISABLE);
-       }
-       ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true);
-       for (index = first; index < cnt; index++) {
-               if (!(learn[index] & PORT_LEARN_DISABLE))
-                       ksz_pwrite8(dev, index, regs[P_STP_CTRL], learn[index]);
-       }
-}
-
-int ksz8_fdb_dump(struct ksz_device *dev, int port,
-                 dsa_fdb_dump_cb_t *cb, void *data)
-{
-       u8 mac[ETH_ALEN];
-       u8 src_port, fid;
-       u16 entries = 0;
-       int ret, i;
-
-       for (i = 0; i < KSZ8_DYN_MAC_ENTRIES; i++) {
-               ret = ksz8_r_dyn_mac_table(dev, i, mac, &fid, &src_port,
-                                          &entries);
-               if (ret)
-                       return ret;
-
-               if (i >= entries)
-                       return 0;
-
-               if (port == src_port) {
-                       ret = cb(mac, fid, false, data);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       return 0;
-}
-
-static int ksz8_add_sta_mac(struct ksz_device *dev, int port,
-                           const unsigned char *addr, u16 vid)
-{
-       struct alu_struct alu;
-       int index, ret;
-       int empty = 0;
-
-       alu.port_forward = 0;
-       for (index = 0; index < dev->info->num_statics; index++) {
-               bool valid;
-
-               ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid);
-               if (ret)
-                       return ret;
-               if (!valid) {
-                       /* Remember the first empty entry. */
-                       if (!empty)
-                               empty = index + 1;
-                       continue;
-               }
-
-               if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid)
-                       break;
-       }
-
-       /* no available entry */
-       if (index == dev->info->num_statics && !empty)
-               return -ENOSPC;
-
-       /* add entry */
-       if (index == dev->info->num_statics) {
-               index = empty - 1;
-               memset(&alu, 0, sizeof(alu));
-               memcpy(alu.mac, addr, ETH_ALEN);
-               alu.is_static = true;
-       }
-       alu.port_forward |= BIT(port);
-       if (vid) {
-               alu.is_use_fid = true;
-
-               /* Need a way to map VID to FID. */
-               alu.fid = vid;
-       }
-
-       return ksz8_w_sta_mac_table(dev, index, &alu);
-}
-
-static int ksz8_del_sta_mac(struct ksz_device *dev, int port,
-                           const unsigned char *addr, u16 vid)
-{
-       struct alu_struct alu;
-       int index, ret;
-
-       for (index = 0; index < dev->info->num_statics; index++) {
-               bool valid;
-
-               ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid);
-               if (ret)
-                       return ret;
-               if (!valid)
-                       continue;
-
-               if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid)
-                       break;
-       }
-
-       /* no available entry */
-       if (index == dev->info->num_statics)
-               return 0;
-
-       /* clear port */
-       alu.port_forward &= ~BIT(port);
-       if (!alu.port_forward)
-               alu.is_static = false;
-
-       return ksz8_w_sta_mac_table(dev, index, &alu);
-}
-
-int ksz8_mdb_add(struct ksz_device *dev, int port,
-                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
-{
-       return ksz8_add_sta_mac(dev, port, mdb->addr, mdb->vid);
-}
-
-int ksz8_mdb_del(struct ksz_device *dev, int port,
-                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
-{
-       return ksz8_del_sta_mac(dev, port, mdb->addr, mdb->vid);
-}
-
-int ksz8_fdb_add(struct ksz_device *dev, int port, const unsigned char *addr,
-                u16 vid, struct dsa_db db)
-{
-       return ksz8_add_sta_mac(dev, port, addr, vid);
-}
-
-int ksz8_fdb_del(struct ksz_device *dev, int port, const unsigned char *addr,
-                u16 vid, struct dsa_db db)
-{
-       return ksz8_del_sta_mac(dev, port, addr, vid);
-}
-
-int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag,
-                            struct netlink_ext_ack *extack)
-{
-       if (ksz_is_ksz88x3(dev))
-               return -ENOTSUPP;
-
-       /* Discard packets with VID not enabled on the switch */
-       ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
-
-       /* Discard packets with VID not enabled on the ingress port */
-       for (port = 0; port < dev->phy_port_cnt; ++port)
-               ksz_port_cfg(dev, port, REG_PORT_CTRL_2, PORT_INGRESS_FILTER,
-                            flag);
-
-       return 0;
-}
-
-static void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool state)
-{
-       if (ksz_is_ksz88x3(dev)) {
-               ksz_cfg(dev, REG_SW_INSERT_SRC_PVID,
-                       0x03 << (4 - 2 * port), state);
-       } else {
-               ksz_pwrite8(dev, port, REG_PORT_CTRL_12, state ? 0x0f : 0x00);
-       }
-}
-
-int ksz8_port_vlan_add(struct ksz_device *dev, int port,
-                      const struct switchdev_obj_port_vlan *vlan,
-                      struct netlink_ext_ack *extack)
-{
-       bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
-       struct ksz_port *p = &dev->ports[port];
-       u16 data, new_pvid = 0;
-       u8 fid, member, valid;
-
-       if (ksz_is_ksz88x3(dev))
-               return -ENOTSUPP;
-
-       /* If a VLAN is added with untagged flag different from the
-        * port's Remove Tag flag, we need to change the latter.
-        * Ignore VID 0, which is always untagged.
-        * Ignore CPU port, which will always be tagged.
-        */
-       if (untagged != p->remove_tag && vlan->vid != 0 &&
-           port != dev->cpu_port) {
-               unsigned int vid;
-
-               /* Reject attempts to add a VLAN that requires the
-                * Remove Tag flag to be changed, unless there are no
-                * other VLANs currently configured.
-                */
-               for (vid = 1; vid < dev->info->num_vlans; ++vid) {
-                       /* Skip the VID we are going to add or reconfigure */
-                       if (vid == vlan->vid)
-                               continue;
-
-                       ksz8_from_vlan(dev, dev->vlan_cache[vid].table[0],
-                                      &fid, &member, &valid);
-                       if (valid && (member & BIT(port)))
-                               return -EINVAL;
-               }
-
-               ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
-               p->remove_tag = untagged;
-       }
-
-       ksz8_r_vlan_table(dev, vlan->vid, &data);
-       ksz8_from_vlan(dev, data, &fid, &member, &valid);
-
-       /* First time to setup the VLAN entry. */
-       if (!valid) {
-               /* Need to find a way to map VID to FID. */
-               fid = 1;
-               valid = 1;
-       }
-       member |= BIT(port);
-
-       ksz8_to_vlan(dev, fid, member, valid, &data);
-       ksz8_w_vlan_table(dev, vlan->vid, data);
-
-       /* change PVID */
-       if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
-               new_pvid = vlan->vid;
-
-       if (new_pvid) {
-               u16 vid;
-
-               ksz_pread16(dev, port, REG_PORT_CTRL_VID, &vid);
-               vid &= ~VLAN_VID_MASK;
-               vid |= new_pvid;
-               ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, vid);
-
-               ksz8_port_enable_pvid(dev, port, true);
-       }
-
-       return 0;
-}
-
-int ksz8_port_vlan_del(struct ksz_device *dev, int port,
-                      const struct switchdev_obj_port_vlan *vlan)
-{
-       u16 data, pvid;
-       u8 fid, member, valid;
-
-       if (ksz_is_ksz88x3(dev))
-               return -ENOTSUPP;
-
-       ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid);
-       pvid = pvid & 0xFFF;
-
-       ksz8_r_vlan_table(dev, vlan->vid, &data);
-       ksz8_from_vlan(dev, data, &fid, &member, &valid);
-
-       member &= ~BIT(port);
-
-       /* Invalidate the entry if no more member. */
-       if (!member) {
-               fid = 0;
-               valid = 0;
-       }
-
-       ksz8_to_vlan(dev, fid, member, valid, &data);
-       ksz8_w_vlan_table(dev, vlan->vid, data);
-
-       if (pvid == vlan->vid)
-               ksz8_port_enable_pvid(dev, port, false);
-
-       return 0;
-}
-
-int ksz8_port_mirror_add(struct ksz_device *dev, int port,
-                        struct dsa_mall_mirror_tc_entry *mirror,
-                        bool ingress, struct netlink_ext_ack *extack)
-{
-       if (ingress) {
-               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
-               dev->mirror_rx |= BIT(port);
-       } else {
-               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
-               dev->mirror_tx |= BIT(port);
-       }
-
-       ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false);
-
-       /* configure mirror port */
-       if (dev->mirror_rx || dev->mirror_tx)
-               ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
-                            PORT_MIRROR_SNIFFER, true);
-
-       return 0;
-}
-
-void ksz8_port_mirror_del(struct ksz_device *dev, int port,
-                         struct dsa_mall_mirror_tc_entry *mirror)
-{
-       u8 data;
-
-       if (mirror->ingress) {
-               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
-               dev->mirror_rx &= ~BIT(port);
-       } else {
-               ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
-               dev->mirror_tx &= ~BIT(port);
-       }
-
-       ksz_pread8(dev, port, P_MIRROR_CTRL, &data);
-
-       if (!dev->mirror_rx && !dev->mirror_tx)
-               ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
-                            PORT_MIRROR_SNIFFER, false);
-}
-
-static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
-{
-       struct ksz_port *p = &dev->ports[port];
-
-       if (!ksz_is_ksz87xx(dev))
-               return;
-
-       if (!p->interface && 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",
-                        port);
-               p->interface = dev->compat_interface;
-       }
-}
-
-void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
-{
-       const u16 *regs = dev->info->regs;
-       struct dsa_switch *ds = dev->ds;
-       const u32 *masks;
-       int queues;
-       u8 member;
-
-       masks = dev->info->masks;
-
-       /* enable broadcast storm limit */
-       ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
-
-       /* For KSZ88x3 enable only one queue by default, otherwise we won't
-        * be able to get rid of PCP prios on Port 2.
-        */
-       if (ksz_is_ksz88x3(dev))
-               queues = 1;
-       else
-               queues = dev->info->num_tx_queues;
-
-       ksz8_port_queue_split(dev, port, queues);
-
-       /* replace priority */
-       ksz_port_cfg(dev, port, P_802_1P_CTRL,
-                    masks[PORT_802_1P_REMAPPING], false);
-
-       if (cpu_port)
-               member = dsa_user_ports(ds);
-       else
-               member = BIT(dsa_upstream_port(ds, port));
-
-       ksz8_cfg_port_member(dev, port, member);
-
-       /* Disable all WoL options by default. Otherwise
-        * ksz_switch_macaddr_get/put logic will not work properly.
-        * CPU port 4 has no WoL functionality.
-        */
-       if (ksz_is_ksz87xx(dev) && !cpu_port)
-               ksz8_pme_pwrite8(dev, port, regs[REG_PORT_PME_CTRL], 0);
-}
-
-static void ksz88x3_config_rmii_clk(struct ksz_device *dev)
-{
-       struct dsa_port *cpu_dp = dsa_to_port(dev->ds, dev->cpu_port);
-       bool rmii_clk_internal;
-
-       if (!ksz_is_ksz88x3(dev))
-               return;
-
-       rmii_clk_internal = of_property_read_bool(cpu_dp->dn,
-                                                 "microchip,rmii-clk-internal");
-
-       ksz_cfg(dev, KSZ88X3_REG_FVID_AND_HOST_MODE,
-               KSZ88X3_PORT3_RMII_CLK_INTERNAL, rmii_clk_internal);
-}
-
-void ksz8_config_cpu_port(struct dsa_switch *ds)
-{
-       struct ksz_device *dev = ds->priv;
-       struct ksz_port *p;
-       const u32 *masks;
-       const u16 *regs;
-       u8 remote;
-       int i;
-
-       masks = dev->info->masks;
-       regs = dev->info->regs;
-
-       ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);
-
-       ksz8_port_setup(dev, dev->cpu_port, true);
-
-       ksz8795_cpu_interface_select(dev, dev->cpu_port);
-       ksz88x3_config_rmii_clk(dev);
-
-       for (i = 0; i < dev->phy_port_cnt; i++) {
-               ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
-       }
-       for (i = 0; i < dev->phy_port_cnt; i++) {
-               p = &dev->ports[i];
-
-               /* For KSZ8795 family. */
-               if (ksz_is_ksz87xx(dev)) {
-                       ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote);
-                       if (remote & KSZ8_PORT_FIBER_MODE)
-                               p->fiber = 1;
-               }
-               if (p->fiber)
-                       ksz_port_cfg(dev, i, regs[P_STP_CTRL],
-                                    PORT_FORCE_FLOW_CTRL, true);
-               else
-                       ksz_port_cfg(dev, i, regs[P_STP_CTRL],
-                                    PORT_FORCE_FLOW_CTRL, false);
-       }
-}
-
-/**
- * ksz8_phy_port_link_up - Configures ports with integrated PHYs
- * @dev: The KSZ device instance.
- * @port: The port number to configure.
- * @duplex: The desired duplex mode.
- * @tx_pause: If true, enables transmit pause.
- * @rx_pause: If true, enables receive pause.
- *
- * Description:
- * The function configures flow control settings for a given port based on the
- * desired settings and current duplex mode.
- *
- * According to the KSZ8873 datasheet, the PORT_FORCE_FLOW_CTRL bit in the
- * Port Control 2 register (0x1A for Port 1, 0x22 for Port 2, 0x32 for Port 3)
- * determines how flow control is handled on the port:
- *    "1 = will always enable full-duplex flow control on the port, regardless
- *         of AN result.
- *     0 = full-duplex flow control is enabled based on AN result."
- *
- * This means that the flow control behavior depends on the state of this bit:
- * - If PORT_FORCE_FLOW_CTRL is set to 1, the switch will ignore AN results and
- *   force flow control on the port.
- * - If PORT_FORCE_FLOW_CTRL is set to 0, the switch will enable or disable
- *   flow control based on the AN results.
- *
- * However, there is a potential limitation in this configuration. It is
- * currently not possible to force disable flow control on a port if we still
- * advertise pause support. While such a configuration is not currently
- * supported by Linux, and may not make practical sense, it's important to be
- * aware of this limitation when working with the KSZ8873 and similar devices.
- */
-static void ksz8_phy_port_link_up(struct ksz_device *dev, int port, int duplex,
-                                 bool tx_pause, bool rx_pause)
-{
-       const u16 *regs = dev->info->regs;
-       u8 sctrl = 0;
-
-       /* The KSZ8795 switch differs from the KSZ8873 by supporting
-        * asymmetric pause control. However, since a single bit is used to
-        * control both RX and TX pause, we can't enforce asymmetric pause
-        * control - both TX and RX pause will be either enabled or disabled
-        * together.
-        *
-        * If auto-negotiation is enabled, we usually allow the flow control to
-        * be determined by the auto-negotiation process based on the
-        * capabilities of both link partners. However, for KSZ8873, the
-        * PORT_FORCE_FLOW_CTRL bit may be set by the hardware bootstrap,
-        * ignoring the auto-negotiation result. Thus, even in auto-negotiation
-        * mode, we need to ensure that the PORT_FORCE_FLOW_CTRL bit is
-        * properly cleared.
-        *
-        * In the absence of pause auto-negotiation, we will enforce symmetric
-        * pause control for both variants of switches - KSZ8873 and KSZ8795.
-        *
-        * Autoneg Pause Autoneg      rx,tx     PORT_FORCE_FLOW_CTRL
-        * 1            1               x       0
-        * 0            1               x       0 (flow control probably disabled)
-        * x            0               1       1 (flow control force enabled)
-        * 1            0               0       0 (flow control still depends on
-        *                                         aneg result due to hardware)
-        * 0            0               0       0 (flow control probably disabled)
-        */
-       if (dev->ports[port].manual_flow && tx_pause)
-               sctrl |= PORT_FORCE_FLOW_CTRL;
-
-       ksz_prmw8(dev, port, regs[P_STP_CTRL], PORT_FORCE_FLOW_CTRL, sctrl);
-}
-
-/**
- * ksz8_cpu_port_link_up - Configures the CPU port of the switch.
- * @dev: The KSZ device instance.
- * @speed: The desired link speed.
- * @duplex: The desired duplex mode.
- * @tx_pause: If true, enables transmit pause.
- * @rx_pause: If true, enables receive pause.
- *
- * Description:
- * The function configures flow control and speed settings for the CPU
- * port of the switch based on the desired settings, current duplex mode, and
- * speed.
- */
-static void ksz8_cpu_port_link_up(struct ksz_device *dev, int speed, int duplex,
-                                 bool tx_pause, bool rx_pause)
-{
-       const u16 *regs = dev->info->regs;
-       u8 ctrl = 0;
-
-       /* SW_FLOW_CTRL, SW_HALF_DUPLEX, and SW_10_MBIT bits are bootstrappable
-        * at least on KSZ8873. They can have different values depending on your
-        * board setup.
-        */
-       if (tx_pause || rx_pause)
-               ctrl |= SW_FLOW_CTRL;
-
-       if (duplex == DUPLEX_HALF)
-               ctrl |= SW_HALF_DUPLEX;
-
-       /* This hardware only supports SPEED_10 and SPEED_100. For SPEED_10
-        * we need to set the SW_10_MBIT bit. Otherwise, we can leave it 0.
-        */
-       if (speed == SPEED_10)
-               ctrl |= SW_10_MBIT;
-
-       ksz_rmw8(dev, regs[S_BROADCAST_CTRL], SW_HALF_DUPLEX | SW_FLOW_CTRL |
-                SW_10_MBIT, ctrl);
-}
-
-void ksz8_phylink_mac_link_up(struct phylink_config *config,
-                             struct phy_device *phydev, unsigned int mode,
-                             phy_interface_t interface, int speed, int duplex,
-                             bool tx_pause, bool rx_pause)
-{
-       struct dsa_port *dp = dsa_phylink_to_port(config);
-       struct ksz_device *dev = dp->ds->priv;
-       int port = dp->index;
-
-       /* If the port is the CPU port, apply special handling. Only the CPU
-        * port is configured via global registers.
-        */
-       if (dev->cpu_port == port)
-               ksz8_cpu_port_link_up(dev, speed, duplex, tx_pause, rx_pause);
-       else if (dev->info->internal_phy[port])
-               ksz8_phy_port_link_up(dev, port, duplex, tx_pause, rx_pause);
-}
-
-static int ksz8_handle_global_errata(struct dsa_switch *ds)
-{
-       struct ksz_device *dev = ds->priv;
-       int ret = 0;
-
-       /* KSZ87xx Errata DS80000687C.
-        * Module 2: Link drops with some EEE link partners.
-        *   An issue with the EEE next page exchange between the
-        *   KSZ879x/KSZ877x/KSZ876x and some EEE link partners may result in
-        *   the link dropping.
-        */
-       if (dev->info->ksz87xx_eee_link_erratum)
-               ret = ksz8_ind_write8(dev, TABLE_EEE, REG_IND_EEE_GLOB2_HI, 0);
-
-       return ret;
-}
-
-int ksz8_enable_stp_addr(struct ksz_device *dev)
-{
-       struct alu_struct alu;
-
-       /* Setup STP address for STP operation. */
-       memset(&alu, 0, sizeof(alu));
-       ether_addr_copy(alu.mac, eth_stp_addr);
-       alu.is_static = true;
-       alu.is_override = true;
-       alu.port_forward = dev->info->cpu_ports;
-
-       return ksz8_w_sta_mac_table(dev, 0, &alu);
-}
-
-int ksz8_setup(struct dsa_switch *ds)
-{
-       struct ksz_device *dev = ds->priv;
-       const u16 *regs = dev->info->regs;
-       int i, ret = 0;
-
-       ds->mtu_enforcement_ingress = true;
-
-       /* We rely on software untagging on the CPU port, so that we
-        * can support both tagged and untagged VLANs
-        */
-       ds->untag_bridge_pvid = true;
-
-       /* VLAN filtering is partly controlled by the global VLAN
-        * Enable flag
-        */
-       ds->vlan_filtering_is_global = true;
-
-       /* Enable automatic fast aging when link changed detected. */
-       ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true);
-
-       /* Enable aggressive back off algorithm in half duplex mode. */
-       regmap_update_bits(ksz_regmap_8(dev), REG_SW_CTRL_1,
-                          SW_AGGR_BACKOFF, SW_AGGR_BACKOFF);
-
-       /*
-        * Make sure unicast VLAN boundary is set as default and
-        * enable no excessive collision drop.
-        */
-       regmap_update_bits(ksz_regmap_8(dev), REG_SW_CTRL_2,
-                          UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,
-                          UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP);
-
-       ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_REPLACE_VID, false);
-
-       ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
-
-       if (!ksz_is_ksz88x3(dev))
-               ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true);
-
-       for (i = 0; i < (dev->info->num_vlans / 4); i++)
-               ksz8_r_vlan_entries(dev, i);
-
-       /* Make sure PME (WoL) is not enabled. If requested, it will
-        * be enabled by ksz_wol_pre_shutdown(). Otherwise, some PMICs
-        * do not like PME events changes before shutdown. PME only
-        * available on KSZ87xx family.
-        */
-       if (ksz_is_ksz87xx(dev)) {
-               ret = ksz8_pme_write8(dev, regs[REG_SW_PME_CTRL], 0);
-               if (!ret)
-                       ret = ksz_rmw8(dev, REG_INT_ENABLE, INT_PME, 0);
-       }
-
-       if (!ret)
-               return ksz8_handle_global_errata(ds);
-       else
-               return ret;
-}
-
-void ksz8_get_caps(struct ksz_device *dev, int port,
-                  struct phylink_config *config)
-{
-       config->mac_capabilities = MAC_10 | MAC_100;
-
-       /* Silicon Errata Sheet (DS80000830A):
-        * "Port 1 does not respond to received flow control PAUSE frames"
-        * So, disable Pause support on "Port 1" (port == 0) for all ksz88x3
-        * switches.
-        */
-       if (!ksz_is_ksz88x3(dev) || port)
-               config->mac_capabilities |= MAC_SYM_PAUSE;
-
-       /* Asym pause is not supported on KSZ8863 and KSZ8873 */
-       if (!ksz_is_ksz88x3(dev))
-               config->mac_capabilities |= MAC_ASYM_PAUSE;
-}
-
-u32 ksz8_get_port_addr(int port, int offset)
-{
-       return PORT_CTRL_ADDR(port, offset);
-}
-
-int ksz8_switch_init(struct ksz_device *dev)
-{
-       dev->cpu_port = fls(dev->info->cpu_ports) - 1;
-       dev->phy_port_cnt = dev->info->port_cnt - 1;
-       dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports;
-
-       return 0;
-}
-
-void ksz8_switch_exit(struct ksz_device *dev)
-{
-       ksz8_reset_switch(dev);
-}
-
-MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
-MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch DSA Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h
deleted file mode 100644 (file)
index 69566a5..0000000
+++ /dev/null
@@ -1,798 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Microchip KSZ8795 register definitions
- *
- * Copyright (c) 2017 Microchip Technology Inc.
- *     Tristram Ha <Tristram.Ha@microchip.com>
- */
-
-#ifndef __KSZ8795_REG_H
-#define __KSZ8795_REG_H
-
-#define KS_PORT_M                      0x1F
-
-#define KS_PRIO_M                      0x3
-#define KS_PRIO_S                      2
-
-#define SW_REVISION_M                  0x0E
-#define SW_REVISION_S                  1
-
-#define KSZ8863_REG_SW_RESET           0x43
-
-#define KSZ8863_GLOBAL_SOFTWARE_RESET  BIT(4)
-#define KSZ8863_PCS_RESET              BIT(0)
-
-#define KSZ88X3_REG_FVID_AND_HOST_MODE  0xC6
-#define KSZ88X3_PORT3_RMII_CLK_INTERNAL BIT(3)
-
-#define REG_SW_CTRL_0                  0x02
-
-#define SW_NEW_BACKOFF                 BIT(7)
-#define SW_GLOBAL_RESET                        BIT(6)
-#define SW_FLUSH_DYN_MAC_TABLE         BIT(5)
-#define SW_FLUSH_STA_MAC_TABLE         BIT(4)
-#define SW_LINK_AUTO_AGING             BIT(0)
-
-#define REG_SW_CTRL_1                  0x03
-
-#define SW_HUGE_PACKET                 BIT(6)
-#define SW_TX_FLOW_CTRL_DISABLE                BIT(5)
-#define SW_RX_FLOW_CTRL_DISABLE                BIT(4)
-#define SW_CHECK_LENGTH                        BIT(3)
-#define SW_AGING_ENABLE                        BIT(2)
-#define SW_FAST_AGING                  BIT(1)
-#define SW_AGGR_BACKOFF                        BIT(0)
-
-#define REG_SW_CTRL_2                  0x04
-
-#define UNICAST_VLAN_BOUNDARY          BIT(7)
-#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 KSZ8863_HUGE_PACKET_ENABLE     BIT(2)
-#define KSZ8863_LEGAL_PACKET_ENABLE    BIT(1)
-
-#define REG_SW_CTRL_3                  0x05
- #define WEIGHTED_FAIR_QUEUE_ENABLE    BIT(3)
-
-#define SW_VLAN_ENABLE                 BIT(7)
-#define SW_IGMP_SNOOP                  BIT(6)
-#define SW_MIRROR_RX_TX                        BIT(0)
-
-#define REG_SW_CTRL_4                  0x06
-
-#define SW_HALF_DUPLEX_FLOW_CTRL       BIT(7)
-#define SW_HALF_DUPLEX                 BIT(6)
-#define SW_FLOW_CTRL                   BIT(5)
-#define SW_10_MBIT                     BIT(4)
-#define SW_REPLACE_VID                 BIT(3)
-
-#define REG_SW_CTRL_5                  0x07
-
-#define REG_SW_CTRL_6                  0x08
-
-#define SW_MIB_COUNTER_FLUSH           BIT(7)
-#define SW_MIB_COUNTER_FREEZE          BIT(6)
-#define SW_MIB_COUNTER_CTRL_ENABLE     KS_PORT_M
-
-#define REG_SW_CTRL_9                  0x0B
-
-#define SPI_CLK_125_MHZ                        0x80
-#define SPI_CLK_62_5_MHZ               0x40
-#define SPI_CLK_31_25_MHZ              0x00
-
-#define SW_LED_MODE_M                  0x3
-#define SW_LED_MODE_S                  4
-#define SW_LED_LINK_ACT_SPEED          0
-#define SW_LED_LINK_ACT                        1
-#define SW_LED_LINK_ACT_DUPLEX         2
-#define SW_LED_LINK_DUPLEX             3
-
-#define REG_SW_CTRL_10                 0x0C
-
-#define SW_PASS_PAUSE                  BIT(0)
-
-#define REG_SW_CTRL_11                 0x0D
-
-#define REG_POWER_MANAGEMENT_1         0x0E
-
-#define SW_PLL_POWER_DOWN              BIT(5)
-#define SW_POWER_MANAGEMENT_MODE_M     0x3
-#define SW_POWER_MANAGEMENT_MODE_S     3
-#define SW_POWER_NORMAL                        0
-#define SW_ENERGY_DETECTION            1
-#define SW_SOFTWARE_POWER_DOWN         2
-
-#define REG_POWER_MANAGEMENT_2         0x0F
-
-#define REG_PORT_1_CTRL_0              0x10
-#define REG_PORT_2_CTRL_0              0x20
-#define REG_PORT_3_CTRL_0              0x30
-#define REG_PORT_4_CTRL_0              0x40
-#define REG_PORT_5_CTRL_0              0x50
-
-#define PORT_BROADCAST_STORM           BIT(7)
-#define PORT_DIFFSERV_ENABLE           BIT(6)
-#define PORT_802_1P_ENABLE             BIT(5)
-#define PORT_BASED_PRIO_S              3
-#define PORT_BASED_PRIO_M              KS_PRIO_M
-#define PORT_BASED_PRIO_0              0
-#define PORT_BASED_PRIO_1              1
-#define PORT_BASED_PRIO_2              2
-#define PORT_BASED_PRIO_3              3
-#define PORT_INSERT_TAG                        BIT(2)
-#define PORT_REMOVE_TAG                        BIT(1)
-#define KSZ8795_PORT_2QUEUE_SPLIT_EN   BIT(0)
-#define KSZ8873_PORT_4QUEUE_SPLIT_EN   BIT(0)
-
-#define REG_PORT_1_CTRL_1              0x11
-#define REG_PORT_2_CTRL_1              0x21
-#define REG_PORT_3_CTRL_1              0x31
-#define REG_PORT_4_CTRL_1              0x41
-#define REG_PORT_5_CTRL_1              0x51
-
-#define PORT_MIRROR_SNIFFER            BIT(7)
-#define PORT_MIRROR_RX                 BIT(6)
-#define PORT_MIRROR_TX                 BIT(5)
-#define PORT_VLAN_MEMBERSHIP           KS_PORT_M
-
-#define REG_PORT_1_CTRL_2              0x12
-#define REG_PORT_2_CTRL_2              0x22
-#define REG_PORT_3_CTRL_2              0x32
-#define REG_PORT_4_CTRL_2              0x42
-#define REG_PORT_5_CTRL_2              0x52
-
-#define KSZ8873_PORT_2QUEUE_SPLIT_EN   BIT(7)
-#define PORT_INGRESS_FILTER            BIT(6)
-#define PORT_DISCARD_NON_VID           BIT(5)
-#define PORT_FORCE_FLOW_CTRL           BIT(4)
-#define PORT_BACK_PRESSURE             BIT(3)
-
-#define REG_PORT_1_CTRL_3              0x13
-#define REG_PORT_2_CTRL_3              0x23
-#define REG_PORT_3_CTRL_3              0x33
-#define REG_PORT_4_CTRL_3              0x43
-#define REG_PORT_5_CTRL_3              0x53
-#define REG_PORT_1_CTRL_4              0x14
-#define REG_PORT_2_CTRL_4              0x24
-#define REG_PORT_3_CTRL_4              0x34
-#define REG_PORT_4_CTRL_4              0x44
-#define REG_PORT_5_CTRL_4              0x54
-
-#define PORT_DEFAULT_VID               0x0001
-
-#define REG_PORT_1_CTRL_5              0x15
-#define REG_PORT_2_CTRL_5              0x25
-#define REG_PORT_3_CTRL_5              0x35
-#define REG_PORT_4_CTRL_5              0x45
-#define REG_PORT_5_CTRL_5              0x55
-
-#define PORT_ACL_ENABLE                        BIT(2)
-#define PORT_AUTHEN_MODE               0x3
-#define PORT_AUTHEN_PASS               0
-#define PORT_AUTHEN_BLOCK              1
-#define PORT_AUTHEN_TRAP               2
-
-#define REG_PORT_5_CTRL_6              0x56
-
-#define PORT_MII_INTERNAL_CLOCK                BIT(7)
-#define PORT_GMII_MAC_MODE             BIT(2)
-
-#define REG_PORT_1_CTRL_7              0x17
-#define REG_PORT_2_CTRL_7              0x27
-#define REG_PORT_3_CTRL_7              0x37
-#define REG_PORT_4_CTRL_7              0x47
-
-#define PORT_AUTO_NEG_ASYM_PAUSE       BIT(5)
-#define PORT_AUTO_NEG_SYM_PAUSE                BIT(4)
-#define PORT_AUTO_NEG_100BTX_FD                BIT(3)
-#define PORT_AUTO_NEG_100BTX           BIT(2)
-#define PORT_AUTO_NEG_10BT_FD          BIT(1)
-#define PORT_AUTO_NEG_10BT             BIT(0)
-
-#define REG_PORT_1_STATUS_0            0x18
-#define REG_PORT_2_STATUS_0            0x28
-#define REG_PORT_3_STATUS_0            0x38
-#define REG_PORT_4_STATUS_0            0x48
-
-/* For KSZ8765. */
-#define PORT_REMOTE_ASYM_PAUSE         BIT(5)
-#define PORT_REMOTE_SYM_PAUSE          BIT(4)
-#define PORT_REMOTE_100BTX_FD          BIT(3)
-#define PORT_REMOTE_100BTX             BIT(2)
-#define PORT_REMOTE_10BT_FD            BIT(1)
-#define PORT_REMOTE_10BT               BIT(0)
-
-#define REG_PORT_1_STATUS_1            0x19
-#define REG_PORT_2_STATUS_1            0x29
-#define REG_PORT_3_STATUS_1            0x39
-#define REG_PORT_4_STATUS_1            0x49
-
-#define PORT_HP_MDIX                   BIT(7)
-#define PORT_REVERSED_POLARITY         BIT(5)
-#define PORT_TX_FLOW_CTRL              BIT(4)
-#define PORT_RX_FLOW_CTRL              BIT(3)
-#define PORT_STAT_SPEED_100MBIT                BIT(2)
-#define PORT_STAT_FULL_DUPLEX          BIT(1)
-
-#define PORT_REMOTE_FAULT              BIT(0)
-
-#define REG_PORT_1_LINK_MD_CTRL                0x1A
-#define REG_PORT_2_LINK_MD_CTRL                0x2A
-#define REG_PORT_3_LINK_MD_CTRL                0x3A
-#define REG_PORT_4_LINK_MD_CTRL                0x4A
-
-#define PORT_CABLE_10M_SHORT           BIT(7)
-#define PORT_CABLE_DIAG_RESULT_M       GENMASK(6, 5)
-#define PORT_CABLE_DIAG_RESULT_S       5
-#define PORT_CABLE_STAT_NORMAL         0
-#define PORT_CABLE_STAT_OPEN           1
-#define PORT_CABLE_STAT_SHORT          2
-#define PORT_CABLE_STAT_FAILED         3
-#define PORT_START_CABLE_DIAG          BIT(4)
-#define PORT_FORCE_LINK                        BIT(3)
-#define PORT_POWER_SAVING              BIT(2)
-#define PORT_PHY_REMOTE_LOOPBACK       BIT(1)
-#define PORT_CABLE_FAULT_COUNTER_H     0x01
-
-#define REG_PORT_1_LINK_MD_RESULT      0x1B
-#define REG_PORT_2_LINK_MD_RESULT      0x2B
-#define REG_PORT_3_LINK_MD_RESULT      0x3B
-#define REG_PORT_4_LINK_MD_RESULT      0x4B
-
-#define PORT_CABLE_FAULT_COUNTER_L     0xFF
-#define PORT_CABLE_FAULT_COUNTER       0x1FF
-
-#define REG_PORT_1_CTRL_9              0x1C
-#define REG_PORT_2_CTRL_9              0x2C
-#define REG_PORT_3_CTRL_9              0x3C
-#define REG_PORT_4_CTRL_9              0x4C
-
-#define PORT_AUTO_NEG_ENABLE           BIT(7)
-#define PORT_AUTO_NEG_DISABLE          BIT(7)
-#define PORT_FORCE_100_MBIT            BIT(6)
-#define PORT_FORCE_FULL_DUPLEX         BIT(5)
-
-#define REG_PORT_1_CTRL_10             0x1D
-#define REG_PORT_2_CTRL_10             0x2D
-#define REG_PORT_3_CTRL_10             0x3D
-#define REG_PORT_4_CTRL_10             0x4D
-
-#define PORT_LED_OFF                   BIT(7)
-#define PORT_TX_DISABLE                        BIT(6)
-#define PORT_AUTO_NEG_RESTART          BIT(5)
-#define PORT_POWER_DOWN                        BIT(3)
-#define PORT_AUTO_MDIX_DISABLE         BIT(2)
-#define PORT_FORCE_MDIX                        BIT(1)
-#define PORT_MAC_LOOPBACK              BIT(0)
-#define KSZ8873_PORT_PHY_LOOPBACK      BIT(0)
-
-#define REG_PORT_1_STATUS_2            0x1E
-#define REG_PORT_2_STATUS_2            0x2E
-#define REG_PORT_3_STATUS_2            0x3E
-#define REG_PORT_4_STATUS_2            0x4E
-
-#define PORT_MDIX_STATUS               BIT(7)
-#define PORT_AUTO_NEG_COMPLETE         BIT(6)
-#define PORT_STAT_LINK_GOOD            BIT(5)
-
-#define REG_PORT_1_STATUS_3            0x1F
-#define REG_PORT_2_STATUS_3            0x2F
-#define REG_PORT_3_STATUS_3            0x3F
-#define REG_PORT_4_STATUS_3            0x4F
-
-#define PORT_PHY_LOOPBACK              BIT(7)
-#define PORT_PHY_ISOLATE               BIT(5)
-#define PORT_PHY_SOFT_RESET            BIT(4)
-#define PORT_PHY_FORCE_LINK            BIT(3)
-#define PORT_PHY_MODE_M                        0x7
-#define PHY_MODE_IN_AUTO_NEG           1
-#define PHY_MODE_10BT_HALF             2
-#define PHY_MODE_100BT_HALF            3
-#define PHY_MODE_10BT_FULL             5
-#define PHY_MODE_100BT_FULL            6
-#define PHY_MODE_ISOLDATE              7
-
-#define REG_PORT_CTRL_0                        0x00
-#define REG_PORT_CTRL_1                        0x01
-#define REG_PORT_CTRL_2                        0x02
-#define REG_PORT_CTRL_VID              0x03
-
-#define REG_PORT_CTRL_5                        0x05
-
-#define REG_PORT_STATUS_1              0x09
-#define REG_PORT_LINK_MD_CTRL          0x0A
-#define REG_PORT_LINK_MD_RESULT                0x0B
-#define REG_PORT_CTRL_9                        0x0C
-#define REG_PORT_CTRL_10               0x0D
-#define REG_PORT_STATUS_3              0x0F
-
-#define REG_PORT_CTRL_12               0xA0
-#define REG_PORT_CTRL_13               0xA1
-#define REG_PORT_RATE_CTRL_3           0xA2
-#define REG_PORT_RATE_CTRL_2           0xA3
-#define REG_PORT_RATE_CTRL_1           0xA4
-#define REG_PORT_RATE_CTRL_0           0xA5
-#define REG_PORT_RATE_LIMIT            0xA6
-#define REG_PORT_IN_RATE_0             0xA7
-#define REG_PORT_IN_RATE_1             0xA8
-#define REG_PORT_IN_RATE_2             0xA9
-#define REG_PORT_IN_RATE_3             0xAA
-#define REG_PORT_OUT_RATE_0            0xAB
-#define REG_PORT_OUT_RATE_1            0xAC
-#define REG_PORT_OUT_RATE_2            0xAD
-#define REG_PORT_OUT_RATE_3            0xAE
-
-#define PORT_CTRL_ADDR(port, addr)             \
-       ((addr) + REG_PORT_1_CTRL_0 + (port) *  \
-               (REG_PORT_2_CTRL_0 - REG_PORT_1_CTRL_0))
-
-#define TABLE_EXT_SELECT_S             5
-#define TABLE_EEE_V                    1
-#define TABLE_ACL_V                    2
-#define TABLE_PME_V                    4
-#define TABLE_LINK_MD_V                        5
-#define TABLE_EEE                      (TABLE_EEE_V << TABLE_EXT_SELECT_S)
-#define TABLE_ACL                      (TABLE_ACL_V << TABLE_EXT_SELECT_S)
-#define TABLE_PME                      (TABLE_PME_V << TABLE_EXT_SELECT_S)
-#define TABLE_LINK_MD                  (TABLE_LINK_MD << TABLE_EXT_SELECT_S)
-#define TABLE_READ                     BIT(4)
-#define TABLE_SELECT_S                 2
-#define TABLE_STATIC_MAC_V             0
-#define TABLE_VLAN_V                   1
-#define TABLE_DYNAMIC_MAC_V            2
-#define TABLE_MIB_V                    3
-#define TABLE_STATIC_MAC               (TABLE_STATIC_MAC_V << TABLE_SELECT_S)
-#define TABLE_VLAN                     (TABLE_VLAN_V << TABLE_SELECT_S)
-#define TABLE_DYNAMIC_MAC              (TABLE_DYNAMIC_MAC_V << TABLE_SELECT_S)
-#define TABLE_MIB                      (TABLE_MIB_V << TABLE_SELECT_S)
-
-#define REG_IND_CTRL_1                 0x6F
-
-#define TABLE_ENTRY_MASK               0x03FF
-#define TABLE_EXT_ENTRY_MASK           0x0FFF
-
-#define REG_IND_DATA_5                 0x73
-#define REG_IND_DATA_2                 0x76
-#define REG_IND_DATA_1                 0x77
-#define REG_IND_DATA_0                 0x78
-
-#define REG_IND_DATA_PME_EEE_ACL       0xA0
-
-#define REG_INT_STATUS                 0x7C
-#define REG_INT_ENABLE                 0x7D
-
-#define INT_PME                                BIT(4)
-
-#define REG_ACL_INT_STATUS             0x7E
-#define REG_ACL_INT_ENABLE             0x7F
-
-#define INT_PORT_5                     BIT(4)
-#define INT_PORT_4                     BIT(3)
-#define INT_PORT_3                     BIT(2)
-#define INT_PORT_2                     BIT(1)
-#define INT_PORT_1                     BIT(0)
-
-#define INT_PORT_ALL                   \
-       (INT_PORT_5 | INT_PORT_4 | INT_PORT_3 | INT_PORT_2 | INT_PORT_1)
-
-#define REG_SW_CTRL_12                 0x80
-#define REG_SW_CTRL_13                 0x81
-
-#define SWITCH_802_1P_MASK             3
-#define SWITCH_802_1P_BASE             3
-#define SWITCH_802_1P_SHIFT            2
-
-#define SW_802_1P_MAP_M                        KS_PRIO_M
-#define SW_802_1P_MAP_S                        KS_PRIO_S
-
-#define REG_SWITCH_CTRL_14             0x82
-
-#define SW_PRIO_MAPPING_M              KS_PRIO_M
-#define SW_PRIO_MAPPING_S              6
-#define SW_PRIO_MAP_3_HI               0
-#define SW_PRIO_MAP_2_HI               2
-#define SW_PRIO_MAP_0_LO               3
-
-#define REG_SW_CTRL_15                 0x83
-#define REG_SW_CTRL_16                 0x84
-#define REG_SW_CTRL_17                 0x85
-#define REG_SW_CTRL_18                 0x86
-
-#define SW_SELF_ADDR_FILTER_ENABLE     BIT(6)
-
-#define REG_SW_UNK_UCAST_CTRL          0x83
-#define REG_SW_UNK_MCAST_CTRL          0x84
-#define REG_SW_UNK_VID_CTRL            0x85
-#define REG_SW_UNK_IP_MCAST_CTRL       0x86
-
-#define SW_UNK_FWD_ENABLE              BIT(5)
-#define SW_UNK_FWD_MAP                 KS_PORT_M
-
-#define REG_SW_CTRL_19                 0x87
-
-#define SW_IN_RATE_LIMIT_PERIOD_M      0x3
-#define SW_IN_RATE_LIMIT_PERIOD_S      4
-#define SW_IN_RATE_LIMIT_16_MS         0
-#define SW_IN_RATE_LIMIT_64_MS         1
-#define SW_IN_RATE_LIMIT_256_MS                2
-#define SW_OUT_RATE_LIMIT_QUEUE_BASED  BIT(3)
-#define SW_INS_TAG_ENABLE              BIT(2)
-
-#define REG_TOS_PRIO_CTRL_0            0x90
-#define REG_TOS_PRIO_CTRL_1            0x91
-#define REG_TOS_PRIO_CTRL_2            0x92
-#define REG_TOS_PRIO_CTRL_3            0x93
-#define REG_TOS_PRIO_CTRL_4            0x94
-#define REG_TOS_PRIO_CTRL_5            0x95
-#define REG_TOS_PRIO_CTRL_6            0x96
-#define REG_TOS_PRIO_CTRL_7            0x97
-#define REG_TOS_PRIO_CTRL_8            0x98
-#define REG_TOS_PRIO_CTRL_9            0x99
-#define REG_TOS_PRIO_CTRL_10           0x9A
-#define REG_TOS_PRIO_CTRL_11           0x9B
-#define REG_TOS_PRIO_CTRL_12           0x9C
-#define REG_TOS_PRIO_CTRL_13           0x9D
-#define REG_TOS_PRIO_CTRL_14           0x9E
-#define REG_TOS_PRIO_CTRL_15           0x9F
-
-#define TOS_PRIO_M                     KS_PRIO_M
-#define TOS_PRIO_S                     KS_PRIO_S
-
-#define REG_SW_CTRL_21                 0xA4
-
-#define SW_IPV6_MLD_OPTION             BIT(3)
-#define SW_IPV6_MLD_SNOOP              BIT(2)
-
-#define REG_PORT_1_CTRL_12             0xB0
-#define REG_PORT_2_CTRL_12             0xC0
-#define REG_PORT_3_CTRL_12             0xD0
-#define REG_PORT_4_CTRL_12             0xE0
-#define REG_PORT_5_CTRL_12             0xF0
-
-#define PORT_PASS_ALL                  BIT(6)
-#define PORT_INS_TAG_FOR_PORT_5_S      3
-#define PORT_INS_TAG_FOR_PORT_5                BIT(3)
-#define PORT_INS_TAG_FOR_PORT_4                BIT(2)
-#define PORT_INS_TAG_FOR_PORT_3                BIT(1)
-#define PORT_INS_TAG_FOR_PORT_2                BIT(0)
-
-#define REG_PORT_1_CTRL_13             0xB1
-#define REG_PORT_2_CTRL_13             0xC1
-#define REG_PORT_3_CTRL_13             0xD1
-#define REG_PORT_4_CTRL_13             0xE1
-#define REG_PORT_5_CTRL_13             0xF1
-
-#define KSZ8795_PORT_4QUEUE_SPLIT_EN   BIT(1)
-#define PORT_DROP_TAG                  BIT(0)
-
-#define REG_PORT_1_CTRL_14             0xB2
-#define REG_PORT_2_CTRL_14             0xC2
-#define REG_PORT_3_CTRL_14             0xD2
-#define REG_PORT_4_CTRL_14             0xE2
-#define REG_PORT_5_CTRL_14             0xF2
-#define REG_PORT_1_CTRL_15             0xB3
-#define REG_PORT_2_CTRL_15             0xC3
-#define REG_PORT_3_CTRL_15             0xD3
-#define REG_PORT_4_CTRL_15             0xE3
-#define REG_PORT_5_CTRL_15             0xF3
-#define REG_PORT_1_CTRL_16             0xB4
-#define REG_PORT_2_CTRL_16             0xC4
-#define REG_PORT_3_CTRL_16             0xD4
-#define REG_PORT_4_CTRL_16             0xE4
-#define REG_PORT_5_CTRL_16             0xF4
-#define REG_PORT_1_CTRL_17             0xB5
-#define REG_PORT_2_CTRL_17             0xC5
-#define REG_PORT_3_CTRL_17             0xD5
-#define REG_PORT_4_CTRL_17             0xE5
-#define REG_PORT_5_CTRL_17             0xF5
-
-#define REG_PORT_1_RATE_CTRL_3         0xB2
-#define REG_PORT_1_RATE_CTRL_2         0xB3
-#define REG_PORT_1_RATE_CTRL_1         0xB4
-#define REG_PORT_1_RATE_CTRL_0         0xB5
-#define REG_PORT_2_RATE_CTRL_3         0xC2
-#define REG_PORT_2_RATE_CTRL_2         0xC3
-#define REG_PORT_2_RATE_CTRL_1         0xC4
-#define REG_PORT_2_RATE_CTRL_0         0xC5
-#define REG_PORT_3_RATE_CTRL_3         0xD2
-#define REG_PORT_3_RATE_CTRL_2         0xD3
-#define REG_PORT_3_RATE_CTRL_1         0xD4
-#define REG_PORT_3_RATE_CTRL_0         0xD5
-#define REG_PORT_4_RATE_CTRL_3         0xE2
-#define REG_PORT_4_RATE_CTRL_2         0xE3
-#define REG_PORT_4_RATE_CTRL_1         0xE4
-#define REG_PORT_4_RATE_CTRL_0         0xE5
-#define REG_PORT_5_RATE_CTRL_3         0xF2
-#define REG_PORT_5_RATE_CTRL_2         0xF3
-#define REG_PORT_5_RATE_CTRL_1         0xF4
-#define REG_PORT_5_RATE_CTRL_0         0xF5
-
-#define RATE_CTRL_ENABLE               BIT(7)
-#define RATE_RATIO_M                   (BIT(7) - 1)
-
-#define PORT_OUT_RATE_ENABLE           BIT(7)
-
-#define REG_PORT_1_RATE_LIMIT          0xB6
-#define REG_PORT_2_RATE_LIMIT          0xC6
-#define REG_PORT_3_RATE_LIMIT          0xD6
-#define REG_PORT_4_RATE_LIMIT          0xE6
-#define REG_PORT_5_RATE_LIMIT          0xF6
-
-#define PORT_IN_PORT_BASED_S           6
-#define PORT_RATE_PACKET_BASED_S       5
-#define PORT_IN_FLOW_CTRL_S            4
-#define PORT_IN_LIMIT_MODE_M           0x3
-#define PORT_IN_LIMIT_MODE_S           2
-#define PORT_COUNT_IFG_S               1
-#define PORT_COUNT_PREAMBLE_S          0
-#define PORT_IN_PORT_BASED             BIT(PORT_IN_PORT_BASED_S)
-#define PORT_RATE_PACKET_BASED         BIT(PORT_RATE_PACKET_BASED_S)
-#define PORT_IN_FLOW_CTRL              BIT(PORT_IN_FLOW_CTRL_S)
-#define PORT_IN_ALL                    0
-#define PORT_IN_UNICAST                        1
-#define PORT_IN_MULTICAST              2
-#define PORT_IN_BROADCAST              3
-#define PORT_COUNT_IFG                 BIT(PORT_COUNT_IFG_S)
-#define PORT_COUNT_PREAMBLE            BIT(PORT_COUNT_PREAMBLE_S)
-
-#define REG_PORT_1_IN_RATE_0           0xB7
-#define REG_PORT_2_IN_RATE_0           0xC7
-#define REG_PORT_3_IN_RATE_0           0xD7
-#define REG_PORT_4_IN_RATE_0           0xE7
-#define REG_PORT_5_IN_RATE_0           0xF7
-#define REG_PORT_1_IN_RATE_1           0xB8
-#define REG_PORT_2_IN_RATE_1           0xC8
-#define REG_PORT_3_IN_RATE_1           0xD8
-#define REG_PORT_4_IN_RATE_1           0xE8
-#define REG_PORT_5_IN_RATE_1           0xF8
-#define REG_PORT_1_IN_RATE_2           0xB9
-#define REG_PORT_2_IN_RATE_2           0xC9
-#define REG_PORT_3_IN_RATE_2           0xD9
-#define REG_PORT_4_IN_RATE_2           0xE9
-#define REG_PORT_5_IN_RATE_2           0xF9
-#define REG_PORT_1_IN_RATE_3           0xBA
-#define REG_PORT_2_IN_RATE_3           0xCA
-#define REG_PORT_3_IN_RATE_3           0xDA
-#define REG_PORT_4_IN_RATE_3           0xEA
-#define REG_PORT_5_IN_RATE_3           0xFA
-
-#define PORT_IN_RATE_ENABLE            BIT(7)
-#define PORT_RATE_LIMIT_M              (BIT(7) - 1)
-
-#define REG_PORT_1_OUT_RATE_0          0xBB
-#define REG_PORT_2_OUT_RATE_0          0xCB
-#define REG_PORT_3_OUT_RATE_0          0xDB
-#define REG_PORT_4_OUT_RATE_0          0xEB
-#define REG_PORT_5_OUT_RATE_0          0xFB
-#define REG_PORT_1_OUT_RATE_1          0xBC
-#define REG_PORT_2_OUT_RATE_1          0xCC
-#define REG_PORT_3_OUT_RATE_1          0xDC
-#define REG_PORT_4_OUT_RATE_1          0xEC
-#define REG_PORT_5_OUT_RATE_1          0xFC
-#define REG_PORT_1_OUT_RATE_2          0xBD
-#define REG_PORT_2_OUT_RATE_2          0xCD
-#define REG_PORT_3_OUT_RATE_2          0xDD
-#define REG_PORT_4_OUT_RATE_2          0xED
-#define REG_PORT_5_OUT_RATE_2          0xFD
-#define REG_PORT_1_OUT_RATE_3          0xBE
-#define REG_PORT_2_OUT_RATE_3          0xCE
-#define REG_PORT_3_OUT_RATE_3          0xDE
-#define REG_PORT_4_OUT_RATE_3          0xEE
-#define REG_PORT_5_OUT_RATE_3          0xFE
-
-/* 88x3 specific */
-
-#define REG_SW_INSERT_SRC_PVID         0xC2
-
-/* PME */
-
-#define SW_PME_OUTPUT_ENABLE           BIT(1)
-#define SW_PME_ACTIVE_HIGH             BIT(0)
-
-#define PORT_MAGIC_PACKET_DETECT       BIT(2)
-#define PORT_LINK_UP_DETECT            BIT(1)
-#define PORT_ENERGY_DETECT             BIT(0)
-
-/* ACL */
-
-#define ACL_FIRST_RULE_M               0xF
-
-#define ACL_MODE_M                     0x3
-#define ACL_MODE_S                     4
-#define ACL_MODE_DISABLE               0
-#define ACL_MODE_LAYER_2               1
-#define ACL_MODE_LAYER_3               2
-#define ACL_MODE_LAYER_4               3
-#define ACL_ENABLE_M                   0x3
-#define ACL_ENABLE_S                   2
-#define ACL_ENABLE_2_COUNT             0
-#define ACL_ENABLE_2_TYPE              1
-#define ACL_ENABLE_2_MAC               2
-#define ACL_ENABLE_2_BOTH              3
-#define ACL_ENABLE_3_IP                        1
-#define ACL_ENABLE_3_SRC_DST_COMP      2
-#define ACL_ENABLE_4_PROTOCOL          0
-#define ACL_ENABLE_4_TCP_PORT_COMP     1
-#define ACL_ENABLE_4_UDP_PORT_COMP     2
-#define ACL_ENABLE_4_TCP_SEQN_COMP     3
-#define ACL_SRC                                BIT(1)
-#define ACL_EQUAL                      BIT(0)
-
-#define ACL_MAX_PORT                   0xFFFF
-
-#define ACL_MIN_PORT                   0xFFFF
-#define ACL_IP_ADDR                    0xFFFFFFFF
-#define ACL_TCP_SEQNUM                 0xFFFFFFFF
-
-#define ACL_RESERVED                   0xF8
-#define ACL_PORT_MODE_M                        0x3
-#define ACL_PORT_MODE_S                        1
-#define ACL_PORT_MODE_DISABLE          0
-#define ACL_PORT_MODE_EITHER           1
-#define ACL_PORT_MODE_IN_RANGE         2
-#define ACL_PORT_MODE_OUT_OF_RANGE     3
-
-#define ACL_TCP_FLAG_ENABLE            BIT(0)
-
-#define ACL_TCP_FLAG_M                 0xFF
-
-#define ACL_TCP_FLAG                   0xFF
-#define ACL_ETH_TYPE                   0xFFFF
-#define ACL_IP_M                       0xFFFFFFFF
-
-#define ACL_PRIO_MODE_M                        0x3
-#define ACL_PRIO_MODE_S                        6
-#define ACL_PRIO_MODE_DISABLE          0
-#define ACL_PRIO_MODE_HIGHER           1
-#define ACL_PRIO_MODE_LOWER            2
-#define ACL_PRIO_MODE_REPLACE          3
-#define ACL_PRIO_M                     0x7
-#define ACL_PRIO_S                     3
-#define ACL_VLAN_PRIO_REPLACE          BIT(2)
-#define ACL_VLAN_PRIO_M                        0x7
-#define ACL_VLAN_PRIO_HI_M             0x3
-
-#define ACL_VLAN_PRIO_LO_M             0x8
-#define ACL_VLAN_PRIO_S                        7
-#define ACL_MAP_MODE_M                 0x3
-#define ACL_MAP_MODE_S                 5
-#define ACL_MAP_MODE_DISABLE           0
-#define ACL_MAP_MODE_OR                        1
-#define ACL_MAP_MODE_AND               2
-#define ACL_MAP_MODE_REPLACE           3
-#define ACL_MAP_PORT_M                 0x1F
-
-#define ACL_CNT_M                      (BIT(11) - 1)
-#define ACL_CNT_S                      5
-#define ACL_MSEC_UNIT                  BIT(4)
-#define ACL_INTR_MODE                  BIT(3)
-
-#define REG_PORT_ACL_BYTE_EN_MSB       0x10
-
-#define ACL_BYTE_EN_MSB_M              0x3F
-
-#define REG_PORT_ACL_BYTE_EN_LSB       0x11
-
-#define ACL_ACTION_START               0xA
-#define ACL_ACTION_LEN                 2
-#define ACL_INTR_CNT_START             0xB
-#define ACL_RULESET_START              0xC
-#define ACL_RULESET_LEN                        2
-#define ACL_TABLE_LEN                  14
-
-#define ACL_ACTION_ENABLE              0x000C
-#define ACL_MATCH_ENABLE               0x1FF0
-#define ACL_RULESET_ENABLE             0x2003
-#define ACL_BYTE_ENABLE                        ((ACL_BYTE_EN_MSB_M << 8) | 0xFF)
-#define ACL_MODE_ENABLE                        (0x10 << 8)
-
-#define REG_PORT_ACL_CTRL_0            0x12
-
-#define PORT_ACL_WRITE_DONE            BIT(6)
-#define PORT_ACL_READ_DONE             BIT(5)
-#define PORT_ACL_WRITE                 BIT(4)
-#define PORT_ACL_INDEX_M               0xF
-
-#define REG_PORT_ACL_CTRL_1            0x13
-
-#define PORT_ACL_FORCE_DLR_MISS                BIT(0)
-
-#define KSZ8795_ID_HI                  0x0022
-#define KSZ8795_ID_LO                  0x1550
-#define KSZ8863_ID_LO                  0x1430
-
-#define KSZ8795_SW_ID                  0x8795
-
-#define PHY_REG_LINK_MD                        0x1D
-
-#define PHY_START_CABLE_DIAG           BIT(15)
-#define PHY_CABLE_DIAG_RESULT_M                GENMASK(14, 13)
-#define PHY_CABLE_DIAG_RESULT          0x6000
-#define PHY_CABLE_STAT_NORMAL          0x0000
-#define PHY_CABLE_STAT_OPEN            0x2000
-#define PHY_CABLE_STAT_SHORT           0x4000
-#define PHY_CABLE_STAT_FAILED          0x6000
-#define PHY_CABLE_10M_SHORT            BIT(12)
-#define PHY_CABLE_FAULT_COUNTER_M      GENMASK(8, 0)
-
-#define PHY_REG_PHY_CTRL               0x1F
-
-#define PHY_MODE_M                     0x7
-#define PHY_MODE_S                     8
-#define PHY_STAT_REVERSED_POLARITY     BIT(5)
-#define PHY_STAT_MDIX                  BIT(4)
-#define PHY_FORCE_LINK                 BIT(3)
-#define PHY_POWER_SAVING_ENABLE                BIT(2)
-#define PHY_REMOTE_LOOPBACK            BIT(1)
-
-/* Chip resource */
-
-#define PRIO_QUEUES                    4
-
-#define KS_PRIO_IN_REG                 4
-
-#define MIB_COUNTER_NUM                0x20
-
-/* Common names used by other drivers */
-
-#define P_BCAST_STORM_CTRL             REG_PORT_CTRL_0
-#define P_PRIO_CTRL                    REG_PORT_CTRL_0
-#define P_TAG_CTRL                     REG_PORT_CTRL_0
-#define P_MIRROR_CTRL                  REG_PORT_CTRL_1
-#define P_802_1P_CTRL                  REG_PORT_CTRL_2
-#define P_PASS_ALL_CTRL                        REG_PORT_CTRL_12
-#define P_INS_SRC_PVID_CTRL            REG_PORT_CTRL_12
-#define P_DROP_TAG_CTRL                        REG_PORT_CTRL_13
-#define P_RATE_LIMIT_CTRL              REG_PORT_RATE_LIMIT
-
-#define S_UNKNOWN_DA_CTRL              REG_SWITCH_CTRL_12
-#define S_FORWARD_INVALID_VID_CTRL     REG_FORWARD_INVALID_VID
-
-#define S_FLUSH_TABLE_CTRL             REG_SW_CTRL_0
-#define S_LINK_AGING_CTRL              REG_SW_CTRL_0
-#define S_HUGE_PACKET_CTRL             REG_SW_CTRL_1
-#define S_MIRROR_CTRL                  REG_SW_CTRL_3
-#define S_REPLACE_VID_CTRL             REG_SW_CTRL_4
-#define S_PASS_PAUSE_CTRL              REG_SW_CTRL_10
-#define S_802_1P_PRIO_CTRL             REG_SW_CTRL_12
-#define S_TOS_PRIO_CTRL                        REG_TOS_PRIO_CTRL_0
-#define S_IPV6_MLD_CTRL                        REG_SW_CTRL_21
-
-#define IND_ACC_TABLE(table)           ((table) << 8)
-
-/* */
-#define REG_IND_EEE_GLOB2_LO           0x34
-#define REG_IND_EEE_GLOB2_HI           0x35
-
-/**
- * MIB_COUNTER_VALUE                   00-00000000-3FFFFFFF
- * MIB_TOTAL_BYTES                     00-0000000F-FFFFFFFF
- * MIB_PACKET_DROPPED                  00-00000000-0000FFFF
- * MIB_COUNTER_VALID                   00-00000020-00000000
- * MIB_COUNTER_OVERFLOW                        00-00000040-00000000
- */
-
-#define MIB_COUNTER_VALUE              0x3FFFFFFF
-
-#define KSZ8795_MIB_TOTAL_RX_0         0x100
-#define KSZ8795_MIB_TOTAL_TX_0         0x101
-#define KSZ8795_MIB_TOTAL_RX_1         0x104
-#define KSZ8795_MIB_TOTAL_TX_1         0x105
-
-#define KSZ8863_MIB_PACKET_DROPPED_TX_0 0x100
-#define KSZ8863_MIB_PACKET_DROPPED_RX_0 0x105
-
-#define MIB_PACKET_DROPPED             0x0000FFFF
-
-#define MIB_TOTAL_BYTES_H              0x0000000F
-
-#define TAIL_TAG_OVERRIDE              BIT(6)
-#define TAIL_TAG_LOOKUP                        BIT(7)
-
-#define FID_ENTRIES                    128
-#define KSZ8_DYN_MAC_ENTRIES           1024
-
-#endif
diff --git a/drivers/net/dsa/microchip/ksz8_reg.h b/drivers/net/dsa/microchip/ksz8_reg.h
new file mode 100644 (file)
index 0000000..ff264d5
--- /dev/null
@@ -0,0 +1,803 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Microchip KSZ8XXX series register definitions
+ *
+ * The base for these definitions is KSZ8795 but unless indicated
+ * differently by their prefix, they apply to all KSZ8 series
+ * devices. Registers and masks that do change are defined in
+ * dedicated structures in ksz_common.c.
+ *
+ * Copyright (c) 2017 Microchip Technology Inc.
+ *     Tristram Ha <Tristram.Ha@microchip.com>
+ */
+
+#ifndef __KSZ8_REG_H
+#define __KSZ8_REG_H
+
+#define KS_PORT_M                      0x1F
+
+#define KS_PRIO_M                      0x3
+#define KS_PRIO_S                      2
+
+#define SW_REVISION_M                  0x0E
+#define SW_REVISION_S                  1
+
+#define KSZ8863_REG_SW_RESET           0x43
+
+#define KSZ8863_GLOBAL_SOFTWARE_RESET  BIT(4)
+#define KSZ8863_PCS_RESET              BIT(0)
+
+#define KSZ88X3_REG_FVID_AND_HOST_MODE  0xC6
+#define KSZ88X3_PORT3_RMII_CLK_INTERNAL BIT(3)
+
+#define REG_SW_CTRL_0                  0x02
+
+#define SW_NEW_BACKOFF                 BIT(7)
+#define SW_GLOBAL_RESET                        BIT(6)
+#define SW_FLUSH_DYN_MAC_TABLE         BIT(5)
+#define SW_FLUSH_STA_MAC_TABLE         BIT(4)
+#define SW_LINK_AUTO_AGING             BIT(0)
+
+#define REG_SW_CTRL_1                  0x03
+
+#define SW_HUGE_PACKET                 BIT(6)
+#define SW_TX_FLOW_CTRL_DISABLE                BIT(5)
+#define SW_RX_FLOW_CTRL_DISABLE                BIT(4)
+#define SW_CHECK_LENGTH                        BIT(3)
+#define SW_AGING_ENABLE                        BIT(2)
+#define SW_FAST_AGING                  BIT(1)
+#define SW_AGGR_BACKOFF                        BIT(0)
+
+#define REG_SW_CTRL_2                  0x04
+
+#define UNICAST_VLAN_BOUNDARY          BIT(7)
+#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 KSZ8863_HUGE_PACKET_ENABLE     BIT(2)
+#define KSZ8863_LEGAL_PACKET_ENABLE    BIT(1)
+
+#define REG_SW_CTRL_3                  0x05
+ #define WEIGHTED_FAIR_QUEUE_ENABLE    BIT(3)
+
+#define SW_VLAN_ENABLE                 BIT(7)
+#define SW_IGMP_SNOOP                  BIT(6)
+#define SW_MIRROR_RX_TX                        BIT(0)
+
+#define REG_SW_CTRL_4                  0x06
+
+#define SW_HALF_DUPLEX_FLOW_CTRL       BIT(7)
+#define SW_HALF_DUPLEX                 BIT(6)
+#define SW_FLOW_CTRL                   BIT(5)
+#define SW_10_MBIT                     BIT(4)
+#define SW_REPLACE_VID                 BIT(3)
+
+#define REG_SW_CTRL_5                  0x07
+
+#define REG_SW_CTRL_6                  0x08
+
+#define SW_MIB_COUNTER_FLUSH           BIT(7)
+#define SW_MIB_COUNTER_FREEZE          BIT(6)
+#define SW_MIB_COUNTER_CTRL_ENABLE     KS_PORT_M
+
+#define REG_SW_CTRL_9                  0x0B
+
+#define SPI_CLK_125_MHZ                        0x80
+#define SPI_CLK_62_5_MHZ               0x40
+#define SPI_CLK_31_25_MHZ              0x00
+
+#define SW_LED_MODE_M                  0x3
+#define SW_LED_MODE_S                  4
+#define SW_LED_LINK_ACT_SPEED          0
+#define SW_LED_LINK_ACT                        1
+#define SW_LED_LINK_ACT_DUPLEX         2
+#define SW_LED_LINK_DUPLEX             3
+
+#define REG_SW_CTRL_10                 0x0C
+
+#define SW_PASS_PAUSE                  BIT(0)
+
+#define REG_SW_CTRL_11                 0x0D
+
+#define REG_POWER_MANAGEMENT_1         0x0E
+
+#define SW_PLL_POWER_DOWN              BIT(5)
+#define SW_POWER_MANAGEMENT_MODE_M     0x3
+#define SW_POWER_MANAGEMENT_MODE_S     3
+#define SW_POWER_NORMAL                        0
+#define SW_ENERGY_DETECTION            1
+#define SW_SOFTWARE_POWER_DOWN         2
+
+#define REG_POWER_MANAGEMENT_2         0x0F
+
+#define REG_PORT_1_CTRL_0              0x10
+#define REG_PORT_2_CTRL_0              0x20
+#define REG_PORT_3_CTRL_0              0x30
+#define REG_PORT_4_CTRL_0              0x40
+#define REG_PORT_5_CTRL_0              0x50
+
+#define PORT_BROADCAST_STORM           BIT(7)
+#define PORT_DIFFSERV_ENABLE           BIT(6)
+#define PORT_802_1P_ENABLE             BIT(5)
+#define PORT_BASED_PRIO_S              3
+#define PORT_BASED_PRIO_M              KS_PRIO_M
+#define PORT_BASED_PRIO_0              0
+#define PORT_BASED_PRIO_1              1
+#define PORT_BASED_PRIO_2              2
+#define PORT_BASED_PRIO_3              3
+#define PORT_INSERT_TAG                        BIT(2)
+#define PORT_REMOVE_TAG                        BIT(1)
+#define KSZ8795_PORT_2QUEUE_SPLIT_EN   BIT(0)
+#define KSZ8873_PORT_4QUEUE_SPLIT_EN   BIT(0)
+
+#define REG_PORT_1_CTRL_1              0x11
+#define REG_PORT_2_CTRL_1              0x21
+#define REG_PORT_3_CTRL_1              0x31
+#define REG_PORT_4_CTRL_1              0x41
+#define REG_PORT_5_CTRL_1              0x51
+
+#define PORT_MIRROR_SNIFFER            BIT(7)
+#define PORT_MIRROR_RX                 BIT(6)
+#define PORT_MIRROR_TX                 BIT(5)
+#define PORT_VLAN_MEMBERSHIP           KS_PORT_M
+
+#define REG_PORT_1_CTRL_2              0x12
+#define REG_PORT_2_CTRL_2              0x22
+#define REG_PORT_3_CTRL_2              0x32
+#define REG_PORT_4_CTRL_2              0x42
+#define REG_PORT_5_CTRL_2              0x52
+
+#define KSZ8873_PORT_2QUEUE_SPLIT_EN   BIT(7)
+#define PORT_INGRESS_FILTER            BIT(6)
+#define PORT_DISCARD_NON_VID           BIT(5)
+#define PORT_FORCE_FLOW_CTRL           BIT(4)
+#define PORT_BACK_PRESSURE             BIT(3)
+
+#define REG_PORT_1_CTRL_3              0x13
+#define REG_PORT_2_CTRL_3              0x23
+#define REG_PORT_3_CTRL_3              0x33
+#define REG_PORT_4_CTRL_3              0x43
+#define REG_PORT_5_CTRL_3              0x53
+#define REG_PORT_1_CTRL_4              0x14
+#define REG_PORT_2_CTRL_4              0x24
+#define REG_PORT_3_CTRL_4              0x34
+#define REG_PORT_4_CTRL_4              0x44
+#define REG_PORT_5_CTRL_4              0x54
+
+#define PORT_DEFAULT_VID               0x0001
+
+#define REG_PORT_1_CTRL_5              0x15
+#define REG_PORT_2_CTRL_5              0x25
+#define REG_PORT_3_CTRL_5              0x35
+#define REG_PORT_4_CTRL_5              0x45
+#define REG_PORT_5_CTRL_5              0x55
+
+#define PORT_ACL_ENABLE                        BIT(2)
+#define PORT_AUTHEN_MODE               0x3
+#define PORT_AUTHEN_PASS               0
+#define PORT_AUTHEN_BLOCK              1
+#define PORT_AUTHEN_TRAP               2
+
+#define REG_PORT_5_CTRL_6              0x56
+
+#define PORT_MII_INTERNAL_CLOCK                BIT(7)
+#define PORT_GMII_MAC_MODE             BIT(2)
+
+#define REG_PORT_1_CTRL_7              0x17
+#define REG_PORT_2_CTRL_7              0x27
+#define REG_PORT_3_CTRL_7              0x37
+#define REG_PORT_4_CTRL_7              0x47
+
+#define PORT_AUTO_NEG_ASYM_PAUSE       BIT(5)
+#define PORT_AUTO_NEG_SYM_PAUSE                BIT(4)
+#define PORT_AUTO_NEG_100BTX_FD                BIT(3)
+#define PORT_AUTO_NEG_100BTX           BIT(2)
+#define PORT_AUTO_NEG_10BT_FD          BIT(1)
+#define PORT_AUTO_NEG_10BT             BIT(0)
+
+#define REG_PORT_1_STATUS_0            0x18
+#define REG_PORT_2_STATUS_0            0x28
+#define REG_PORT_3_STATUS_0            0x38
+#define REG_PORT_4_STATUS_0            0x48
+
+/* For KSZ8765. */
+#define PORT_REMOTE_ASYM_PAUSE         BIT(5)
+#define PORT_REMOTE_SYM_PAUSE          BIT(4)
+#define PORT_REMOTE_100BTX_FD          BIT(3)
+#define PORT_REMOTE_100BTX             BIT(2)
+#define PORT_REMOTE_10BT_FD            BIT(1)
+#define PORT_REMOTE_10BT               BIT(0)
+
+#define REG_PORT_1_STATUS_1            0x19
+#define REG_PORT_2_STATUS_1            0x29
+#define REG_PORT_3_STATUS_1            0x39
+#define REG_PORT_4_STATUS_1            0x49
+
+#define PORT_HP_MDIX                   BIT(7)
+#define PORT_REVERSED_POLARITY         BIT(5)
+#define PORT_TX_FLOW_CTRL              BIT(4)
+#define PORT_RX_FLOW_CTRL              BIT(3)
+#define PORT_STAT_SPEED_100MBIT                BIT(2)
+#define PORT_STAT_FULL_DUPLEX          BIT(1)
+
+#define PORT_REMOTE_FAULT              BIT(0)
+
+#define REG_PORT_1_LINK_MD_CTRL                0x1A
+#define REG_PORT_2_LINK_MD_CTRL                0x2A
+#define REG_PORT_3_LINK_MD_CTRL                0x3A
+#define REG_PORT_4_LINK_MD_CTRL                0x4A
+
+#define PORT_CABLE_10M_SHORT           BIT(7)
+#define PORT_CABLE_DIAG_RESULT_M       GENMASK(6, 5)
+#define PORT_CABLE_DIAG_RESULT_S       5
+#define PORT_CABLE_STAT_NORMAL         0
+#define PORT_CABLE_STAT_OPEN           1
+#define PORT_CABLE_STAT_SHORT          2
+#define PORT_CABLE_STAT_FAILED         3
+#define PORT_START_CABLE_DIAG          BIT(4)
+#define PORT_FORCE_LINK                        BIT(3)
+#define PORT_POWER_SAVING              BIT(2)
+#define PORT_PHY_REMOTE_LOOPBACK       BIT(1)
+#define PORT_CABLE_FAULT_COUNTER_H     0x01
+
+#define REG_PORT_1_LINK_MD_RESULT      0x1B
+#define REG_PORT_2_LINK_MD_RESULT      0x2B
+#define REG_PORT_3_LINK_MD_RESULT      0x3B
+#define REG_PORT_4_LINK_MD_RESULT      0x4B
+
+#define PORT_CABLE_FAULT_COUNTER_L     0xFF
+#define PORT_CABLE_FAULT_COUNTER       0x1FF
+
+#define REG_PORT_1_CTRL_9              0x1C
+#define REG_PORT_2_CTRL_9              0x2C
+#define REG_PORT_3_CTRL_9              0x3C
+#define REG_PORT_4_CTRL_9              0x4C
+
+#define PORT_AUTO_NEG_ENABLE           BIT(7)
+#define PORT_AUTO_NEG_DISABLE          BIT(7)
+#define PORT_FORCE_100_MBIT            BIT(6)
+#define PORT_FORCE_FULL_DUPLEX         BIT(5)
+
+#define REG_PORT_1_CTRL_10             0x1D
+#define REG_PORT_2_CTRL_10             0x2D
+#define REG_PORT_3_CTRL_10             0x3D
+#define REG_PORT_4_CTRL_10             0x4D
+
+#define PORT_LED_OFF                   BIT(7)
+#define PORT_TX_DISABLE                        BIT(6)
+#define PORT_AUTO_NEG_RESTART          BIT(5)
+#define PORT_POWER_DOWN                        BIT(3)
+#define PORT_AUTO_MDIX_DISABLE         BIT(2)
+#define PORT_FORCE_MDIX                        BIT(1)
+#define PORT_MAC_LOOPBACK              BIT(0)
+#define KSZ8873_PORT_PHY_LOOPBACK      BIT(0)
+
+#define REG_PORT_1_STATUS_2            0x1E
+#define REG_PORT_2_STATUS_2            0x2E
+#define REG_PORT_3_STATUS_2            0x3E
+#define REG_PORT_4_STATUS_2            0x4E
+
+#define PORT_MDIX_STATUS               BIT(7)
+#define PORT_AUTO_NEG_COMPLETE         BIT(6)
+#define PORT_STAT_LINK_GOOD            BIT(5)
+
+#define REG_PORT_1_STATUS_3            0x1F
+#define REG_PORT_2_STATUS_3            0x2F
+#define REG_PORT_3_STATUS_3            0x3F
+#define REG_PORT_4_STATUS_3            0x4F
+
+#define PORT_PHY_LOOPBACK              BIT(7)
+#define PORT_PHY_ISOLATE               BIT(5)
+#define PORT_PHY_SOFT_RESET            BIT(4)
+#define PORT_PHY_FORCE_LINK            BIT(3)
+#define PORT_PHY_MODE_M                        0x7
+#define PHY_MODE_IN_AUTO_NEG           1
+#define PHY_MODE_10BT_HALF             2
+#define PHY_MODE_100BT_HALF            3
+#define PHY_MODE_10BT_FULL             5
+#define PHY_MODE_100BT_FULL            6
+#define PHY_MODE_ISOLDATE              7
+
+#define REG_PORT_CTRL_0                        0x00
+#define REG_PORT_CTRL_1                        0x01
+#define REG_PORT_CTRL_2                        0x02
+#define REG_PORT_CTRL_VID              0x03
+
+#define REG_PORT_CTRL_5                        0x05
+
+#define REG_PORT_STATUS_1              0x09
+#define REG_PORT_LINK_MD_CTRL          0x0A
+#define REG_PORT_LINK_MD_RESULT                0x0B
+#define REG_PORT_CTRL_9                        0x0C
+#define REG_PORT_CTRL_10               0x0D
+#define REG_PORT_STATUS_3              0x0F
+
+#define REG_PORT_CTRL_12               0xA0
+#define REG_PORT_CTRL_13               0xA1
+#define REG_PORT_RATE_CTRL_3           0xA2
+#define REG_PORT_RATE_CTRL_2           0xA3
+#define REG_PORT_RATE_CTRL_1           0xA4
+#define REG_PORT_RATE_CTRL_0           0xA5
+#define REG_PORT_RATE_LIMIT            0xA6
+#define REG_PORT_IN_RATE_0             0xA7
+#define REG_PORT_IN_RATE_1             0xA8
+#define REG_PORT_IN_RATE_2             0xA9
+#define REG_PORT_IN_RATE_3             0xAA
+#define REG_PORT_OUT_RATE_0            0xAB
+#define REG_PORT_OUT_RATE_1            0xAC
+#define REG_PORT_OUT_RATE_2            0xAD
+#define REG_PORT_OUT_RATE_3            0xAE
+
+#define PORT_CTRL_ADDR(port, addr)             \
+       ((addr) + REG_PORT_1_CTRL_0 + (port) *  \
+               (REG_PORT_2_CTRL_0 - REG_PORT_1_CTRL_0))
+
+#define TABLE_EXT_SELECT_S             5
+#define TABLE_EEE_V                    1
+#define TABLE_ACL_V                    2
+#define TABLE_PME_V                    4
+#define TABLE_LINK_MD_V                        5
+#define TABLE_EEE                      (TABLE_EEE_V << TABLE_EXT_SELECT_S)
+#define TABLE_ACL                      (TABLE_ACL_V << TABLE_EXT_SELECT_S)
+#define TABLE_PME                      (TABLE_PME_V << TABLE_EXT_SELECT_S)
+#define TABLE_LINK_MD                  (TABLE_LINK_MD << TABLE_EXT_SELECT_S)
+#define TABLE_READ                     BIT(4)
+#define TABLE_SELECT_S                 2
+#define TABLE_STATIC_MAC_V             0
+#define TABLE_VLAN_V                   1
+#define TABLE_DYNAMIC_MAC_V            2
+#define TABLE_MIB_V                    3
+#define TABLE_STATIC_MAC               (TABLE_STATIC_MAC_V << TABLE_SELECT_S)
+#define TABLE_VLAN                     (TABLE_VLAN_V << TABLE_SELECT_S)
+#define TABLE_DYNAMIC_MAC              (TABLE_DYNAMIC_MAC_V << TABLE_SELECT_S)
+#define TABLE_MIB                      (TABLE_MIB_V << TABLE_SELECT_S)
+
+#define REG_IND_CTRL_1                 0x6F
+
+#define TABLE_ENTRY_MASK               0x03FF
+#define TABLE_EXT_ENTRY_MASK           0x0FFF
+
+#define REG_IND_DATA_5                 0x73
+#define REG_IND_DATA_2                 0x76
+#define REG_IND_DATA_1                 0x77
+#define REG_IND_DATA_0                 0x78
+
+#define REG_IND_DATA_PME_EEE_ACL       0xA0
+
+#define REG_INT_STATUS                 0x7C
+#define REG_INT_ENABLE                 0x7D
+
+#define INT_PME                                BIT(4)
+
+#define REG_ACL_INT_STATUS             0x7E
+#define REG_ACL_INT_ENABLE             0x7F
+
+#define INT_PORT_5                     BIT(4)
+#define INT_PORT_4                     BIT(3)
+#define INT_PORT_3                     BIT(2)
+#define INT_PORT_2                     BIT(1)
+#define INT_PORT_1                     BIT(0)
+
+#define INT_PORT_ALL                   \
+       (INT_PORT_5 | INT_PORT_4 | INT_PORT_3 | INT_PORT_2 | INT_PORT_1)
+
+#define REG_SW_CTRL_12                 0x80
+#define REG_SW_CTRL_13                 0x81
+
+#define SWITCH_802_1P_MASK             3
+#define SWITCH_802_1P_BASE             3
+#define SWITCH_802_1P_SHIFT            2
+
+#define SW_802_1P_MAP_M                        KS_PRIO_M
+#define SW_802_1P_MAP_S                        KS_PRIO_S
+
+#define REG_SWITCH_CTRL_14             0x82
+
+#define SW_PRIO_MAPPING_M              KS_PRIO_M
+#define SW_PRIO_MAPPING_S              6
+#define SW_PRIO_MAP_3_HI               0
+#define SW_PRIO_MAP_2_HI               2
+#define SW_PRIO_MAP_0_LO               3
+
+#define REG_SW_CTRL_15                 0x83
+#define REG_SW_CTRL_16                 0x84
+#define REG_SW_CTRL_17                 0x85
+#define REG_SW_CTRL_18                 0x86
+
+#define SW_SELF_ADDR_FILTER_ENABLE     BIT(6)
+
+#define REG_SW_UNK_UCAST_CTRL          0x83
+#define REG_SW_UNK_MCAST_CTRL          0x84
+#define REG_SW_UNK_VID_CTRL            0x85
+#define REG_SW_UNK_IP_MCAST_CTRL       0x86
+
+#define SW_UNK_FWD_ENABLE              BIT(5)
+#define SW_UNK_FWD_MAP                 KS_PORT_M
+
+#define REG_SW_CTRL_19                 0x87
+
+#define SW_IN_RATE_LIMIT_PERIOD_M      0x3
+#define SW_IN_RATE_LIMIT_PERIOD_S      4
+#define SW_IN_RATE_LIMIT_16_MS         0
+#define SW_IN_RATE_LIMIT_64_MS         1
+#define SW_IN_RATE_LIMIT_256_MS                2
+#define SW_OUT_RATE_LIMIT_QUEUE_BASED  BIT(3)
+#define SW_INS_TAG_ENABLE              BIT(2)
+
+#define REG_TOS_PRIO_CTRL_0            0x90
+#define REG_TOS_PRIO_CTRL_1            0x91
+#define REG_TOS_PRIO_CTRL_2            0x92
+#define REG_TOS_PRIO_CTRL_3            0x93
+#define REG_TOS_PRIO_CTRL_4            0x94
+#define REG_TOS_PRIO_CTRL_5            0x95
+#define REG_TOS_PRIO_CTRL_6            0x96
+#define REG_TOS_PRIO_CTRL_7            0x97
+#define REG_TOS_PRIO_CTRL_8            0x98
+#define REG_TOS_PRIO_CTRL_9            0x99
+#define REG_TOS_PRIO_CTRL_10           0x9A
+#define REG_TOS_PRIO_CTRL_11           0x9B
+#define REG_TOS_PRIO_CTRL_12           0x9C
+#define REG_TOS_PRIO_CTRL_13           0x9D
+#define REG_TOS_PRIO_CTRL_14           0x9E
+#define REG_TOS_PRIO_CTRL_15           0x9F
+
+#define TOS_PRIO_M                     KS_PRIO_M
+#define TOS_PRIO_S                     KS_PRIO_S
+
+#define REG_SW_CTRL_21                 0xA4
+
+#define SW_IPV6_MLD_OPTION             BIT(3)
+#define SW_IPV6_MLD_SNOOP              BIT(2)
+
+#define REG_PORT_1_CTRL_12             0xB0
+#define REG_PORT_2_CTRL_12             0xC0
+#define REG_PORT_3_CTRL_12             0xD0
+#define REG_PORT_4_CTRL_12             0xE0
+#define REG_PORT_5_CTRL_12             0xF0
+
+#define PORT_PASS_ALL                  BIT(6)
+#define PORT_INS_TAG_FOR_PORT_5_S      3
+#define PORT_INS_TAG_FOR_PORT_5                BIT(3)
+#define PORT_INS_TAG_FOR_PORT_4                BIT(2)
+#define PORT_INS_TAG_FOR_PORT_3                BIT(1)
+#define PORT_INS_TAG_FOR_PORT_2                BIT(0)
+
+#define REG_PORT_1_CTRL_13             0xB1
+#define REG_PORT_2_CTRL_13             0xC1
+#define REG_PORT_3_CTRL_13             0xD1
+#define REG_PORT_4_CTRL_13             0xE1
+#define REG_PORT_5_CTRL_13             0xF1
+
+#define KSZ8795_PORT_4QUEUE_SPLIT_EN   BIT(1)
+#define PORT_DROP_TAG                  BIT(0)
+
+#define REG_PORT_1_CTRL_14             0xB2
+#define REG_PORT_2_CTRL_14             0xC2
+#define REG_PORT_3_CTRL_14             0xD2
+#define REG_PORT_4_CTRL_14             0xE2
+#define REG_PORT_5_CTRL_14             0xF2
+#define REG_PORT_1_CTRL_15             0xB3
+#define REG_PORT_2_CTRL_15             0xC3
+#define REG_PORT_3_CTRL_15             0xD3
+#define REG_PORT_4_CTRL_15             0xE3
+#define REG_PORT_5_CTRL_15             0xF3
+#define REG_PORT_1_CTRL_16             0xB4
+#define REG_PORT_2_CTRL_16             0xC4
+#define REG_PORT_3_CTRL_16             0xD4
+#define REG_PORT_4_CTRL_16             0xE4
+#define REG_PORT_5_CTRL_16             0xF4
+#define REG_PORT_1_CTRL_17             0xB5
+#define REG_PORT_2_CTRL_17             0xC5
+#define REG_PORT_3_CTRL_17             0xD5
+#define REG_PORT_4_CTRL_17             0xE5
+#define REG_PORT_5_CTRL_17             0xF5
+
+#define REG_PORT_1_RATE_CTRL_3         0xB2
+#define REG_PORT_1_RATE_CTRL_2         0xB3
+#define REG_PORT_1_RATE_CTRL_1         0xB4
+#define REG_PORT_1_RATE_CTRL_0         0xB5
+#define REG_PORT_2_RATE_CTRL_3         0xC2
+#define REG_PORT_2_RATE_CTRL_2         0xC3
+#define REG_PORT_2_RATE_CTRL_1         0xC4
+#define REG_PORT_2_RATE_CTRL_0         0xC5
+#define REG_PORT_3_RATE_CTRL_3         0xD2
+#define REG_PORT_3_RATE_CTRL_2         0xD3
+#define REG_PORT_3_RATE_CTRL_1         0xD4
+#define REG_PORT_3_RATE_CTRL_0         0xD5
+#define REG_PORT_4_RATE_CTRL_3         0xE2
+#define REG_PORT_4_RATE_CTRL_2         0xE3
+#define REG_PORT_4_RATE_CTRL_1         0xE4
+#define REG_PORT_4_RATE_CTRL_0         0xE5
+#define REG_PORT_5_RATE_CTRL_3         0xF2
+#define REG_PORT_5_RATE_CTRL_2         0xF3
+#define REG_PORT_5_RATE_CTRL_1         0xF4
+#define REG_PORT_5_RATE_CTRL_0         0xF5
+
+#define RATE_CTRL_ENABLE               BIT(7)
+#define RATE_RATIO_M                   (BIT(7) - 1)
+
+#define PORT_OUT_RATE_ENABLE           BIT(7)
+
+#define REG_PORT_1_RATE_LIMIT          0xB6
+#define REG_PORT_2_RATE_LIMIT          0xC6
+#define REG_PORT_3_RATE_LIMIT          0xD6
+#define REG_PORT_4_RATE_LIMIT          0xE6
+#define REG_PORT_5_RATE_LIMIT          0xF6
+
+#define PORT_IN_PORT_BASED_S           6
+#define PORT_RATE_PACKET_BASED_S       5
+#define PORT_IN_FLOW_CTRL_S            4
+#define PORT_IN_LIMIT_MODE_M           0x3
+#define PORT_IN_LIMIT_MODE_S           2
+#define PORT_COUNT_IFG_S               1
+#define PORT_COUNT_PREAMBLE_S          0
+#define PORT_IN_PORT_BASED             BIT(PORT_IN_PORT_BASED_S)
+#define PORT_RATE_PACKET_BASED         BIT(PORT_RATE_PACKET_BASED_S)
+#define PORT_IN_FLOW_CTRL              BIT(PORT_IN_FLOW_CTRL_S)
+#define PORT_IN_ALL                    0
+#define PORT_IN_UNICAST                        1
+#define PORT_IN_MULTICAST              2
+#define PORT_IN_BROADCAST              3
+#define PORT_COUNT_IFG                 BIT(PORT_COUNT_IFG_S)
+#define PORT_COUNT_PREAMBLE            BIT(PORT_COUNT_PREAMBLE_S)
+
+#define REG_PORT_1_IN_RATE_0           0xB7
+#define REG_PORT_2_IN_RATE_0           0xC7
+#define REG_PORT_3_IN_RATE_0           0xD7
+#define REG_PORT_4_IN_RATE_0           0xE7
+#define REG_PORT_5_IN_RATE_0           0xF7
+#define REG_PORT_1_IN_RATE_1           0xB8
+#define REG_PORT_2_IN_RATE_1           0xC8
+#define REG_PORT_3_IN_RATE_1           0xD8
+#define REG_PORT_4_IN_RATE_1           0xE8
+#define REG_PORT_5_IN_RATE_1           0xF8
+#define REG_PORT_1_IN_RATE_2           0xB9
+#define REG_PORT_2_IN_RATE_2           0xC9
+#define REG_PORT_3_IN_RATE_2           0xD9
+#define REG_PORT_4_IN_RATE_2           0xE9
+#define REG_PORT_5_IN_RATE_2           0xF9
+#define REG_PORT_1_IN_RATE_3           0xBA
+#define REG_PORT_2_IN_RATE_3           0xCA
+#define REG_PORT_3_IN_RATE_3           0xDA
+#define REG_PORT_4_IN_RATE_3           0xEA
+#define REG_PORT_5_IN_RATE_3           0xFA
+
+#define PORT_IN_RATE_ENABLE            BIT(7)
+#define PORT_RATE_LIMIT_M              (BIT(7) - 1)
+
+#define REG_PORT_1_OUT_RATE_0          0xBB
+#define REG_PORT_2_OUT_RATE_0          0xCB
+#define REG_PORT_3_OUT_RATE_0          0xDB
+#define REG_PORT_4_OUT_RATE_0          0xEB
+#define REG_PORT_5_OUT_RATE_0          0xFB
+#define REG_PORT_1_OUT_RATE_1          0xBC
+#define REG_PORT_2_OUT_RATE_1          0xCC
+#define REG_PORT_3_OUT_RATE_1          0xDC
+#define REG_PORT_4_OUT_RATE_1          0xEC
+#define REG_PORT_5_OUT_RATE_1          0xFC
+#define REG_PORT_1_OUT_RATE_2          0xBD
+#define REG_PORT_2_OUT_RATE_2          0xCD
+#define REG_PORT_3_OUT_RATE_2          0xDD
+#define REG_PORT_4_OUT_RATE_2          0xED
+#define REG_PORT_5_OUT_RATE_2          0xFD
+#define REG_PORT_1_OUT_RATE_3          0xBE
+#define REG_PORT_2_OUT_RATE_3          0xCE
+#define REG_PORT_3_OUT_RATE_3          0xDE
+#define REG_PORT_4_OUT_RATE_3          0xEE
+#define REG_PORT_5_OUT_RATE_3          0xFE
+
+/* 88x3 specific */
+
+#define REG_SW_INSERT_SRC_PVID         0xC2
+
+/* PME */
+
+#define SW_PME_OUTPUT_ENABLE           BIT(1)
+#define SW_PME_ACTIVE_HIGH             BIT(0)
+
+#define PORT_MAGIC_PACKET_DETECT       BIT(2)
+#define PORT_LINK_UP_DETECT            BIT(1)
+#define PORT_ENERGY_DETECT             BIT(0)
+
+/* ACL */
+
+#define ACL_FIRST_RULE_M               0xF
+
+#define ACL_MODE_M                     0x3
+#define ACL_MODE_S                     4
+#define ACL_MODE_DISABLE               0
+#define ACL_MODE_LAYER_2               1
+#define ACL_MODE_LAYER_3               2
+#define ACL_MODE_LAYER_4               3
+#define ACL_ENABLE_M                   0x3
+#define ACL_ENABLE_S                   2
+#define ACL_ENABLE_2_COUNT             0
+#define ACL_ENABLE_2_TYPE              1
+#define ACL_ENABLE_2_MAC               2
+#define ACL_ENABLE_2_BOTH              3
+#define ACL_ENABLE_3_IP                        1
+#define ACL_ENABLE_3_SRC_DST_COMP      2
+#define ACL_ENABLE_4_PROTOCOL          0
+#define ACL_ENABLE_4_TCP_PORT_COMP     1
+#define ACL_ENABLE_4_UDP_PORT_COMP     2
+#define ACL_ENABLE_4_TCP_SEQN_COMP     3
+#define ACL_SRC                                BIT(1)
+#define ACL_EQUAL                      BIT(0)
+
+#define ACL_MAX_PORT                   0xFFFF
+
+#define ACL_MIN_PORT                   0xFFFF
+#define ACL_IP_ADDR                    0xFFFFFFFF
+#define ACL_TCP_SEQNUM                 0xFFFFFFFF
+
+#define ACL_RESERVED                   0xF8
+#define ACL_PORT_MODE_M                        0x3
+#define ACL_PORT_MODE_S                        1
+#define ACL_PORT_MODE_DISABLE          0
+#define ACL_PORT_MODE_EITHER           1
+#define ACL_PORT_MODE_IN_RANGE         2
+#define ACL_PORT_MODE_OUT_OF_RANGE     3
+
+#define ACL_TCP_FLAG_ENABLE            BIT(0)
+
+#define ACL_TCP_FLAG_M                 0xFF
+
+#define ACL_TCP_FLAG                   0xFF
+#define ACL_ETH_TYPE                   0xFFFF
+#define ACL_IP_M                       0xFFFFFFFF
+
+#define ACL_PRIO_MODE_M                        0x3
+#define ACL_PRIO_MODE_S                        6
+#define ACL_PRIO_MODE_DISABLE          0
+#define ACL_PRIO_MODE_HIGHER           1
+#define ACL_PRIO_MODE_LOWER            2
+#define ACL_PRIO_MODE_REPLACE          3
+#define ACL_PRIO_M                     0x7
+#define ACL_PRIO_S                     3
+#define ACL_VLAN_PRIO_REPLACE          BIT(2)
+#define ACL_VLAN_PRIO_M                        0x7
+#define ACL_VLAN_PRIO_HI_M             0x3
+
+#define ACL_VLAN_PRIO_LO_M             0x8
+#define ACL_VLAN_PRIO_S                        7
+#define ACL_MAP_MODE_M                 0x3
+#define ACL_MAP_MODE_S                 5
+#define ACL_MAP_MODE_DISABLE           0
+#define ACL_MAP_MODE_OR                        1
+#define ACL_MAP_MODE_AND               2
+#define ACL_MAP_MODE_REPLACE           3
+#define ACL_MAP_PORT_M                 0x1F
+
+#define ACL_CNT_M                      (BIT(11) - 1)
+#define ACL_CNT_S                      5
+#define ACL_MSEC_UNIT                  BIT(4)
+#define ACL_INTR_MODE                  BIT(3)
+
+#define REG_PORT_ACL_BYTE_EN_MSB       0x10
+
+#define ACL_BYTE_EN_MSB_M              0x3F
+
+#define REG_PORT_ACL_BYTE_EN_LSB       0x11
+
+#define ACL_ACTION_START               0xA
+#define ACL_ACTION_LEN                 2
+#define ACL_INTR_CNT_START             0xB
+#define ACL_RULESET_START              0xC
+#define ACL_RULESET_LEN                        2
+#define ACL_TABLE_LEN                  14
+
+#define ACL_ACTION_ENABLE              0x000C
+#define ACL_MATCH_ENABLE               0x1FF0
+#define ACL_RULESET_ENABLE             0x2003
+#define ACL_BYTE_ENABLE                        ((ACL_BYTE_EN_MSB_M << 8) | 0xFF)
+#define ACL_MODE_ENABLE                        (0x10 << 8)
+
+#define REG_PORT_ACL_CTRL_0            0x12
+
+#define PORT_ACL_WRITE_DONE            BIT(6)
+#define PORT_ACL_READ_DONE             BIT(5)
+#define PORT_ACL_WRITE                 BIT(4)
+#define PORT_ACL_INDEX_M               0xF
+
+#define REG_PORT_ACL_CTRL_1            0x13
+
+#define PORT_ACL_FORCE_DLR_MISS                BIT(0)
+
+#define KSZ8795_ID_HI                  0x0022
+#define KSZ8795_ID_LO                  0x1550
+#define KSZ8863_ID_LO                  0x1430
+
+#define KSZ8795_SW_ID                  0x8795
+
+#define PHY_REG_LINK_MD                        0x1D
+
+#define PHY_START_CABLE_DIAG           BIT(15)
+#define PHY_CABLE_DIAG_RESULT_M                GENMASK(14, 13)
+#define PHY_CABLE_DIAG_RESULT          0x6000
+#define PHY_CABLE_STAT_NORMAL          0x0000
+#define PHY_CABLE_STAT_OPEN            0x2000
+#define PHY_CABLE_STAT_SHORT           0x4000
+#define PHY_CABLE_STAT_FAILED          0x6000
+#define PHY_CABLE_10M_SHORT            BIT(12)
+#define PHY_CABLE_FAULT_COUNTER_M      GENMASK(8, 0)
+
+#define PHY_REG_PHY_CTRL               0x1F
+
+#define PHY_MODE_M                     0x7
+#define PHY_MODE_S                     8
+#define PHY_STAT_REVERSED_POLARITY     BIT(5)
+#define PHY_STAT_MDIX                  BIT(4)
+#define PHY_FORCE_LINK                 BIT(3)
+#define PHY_POWER_SAVING_ENABLE                BIT(2)
+#define PHY_REMOTE_LOOPBACK            BIT(1)
+
+/* Chip resource */
+
+#define PRIO_QUEUES                    4
+
+#define KS_PRIO_IN_REG                 4
+
+#define MIB_COUNTER_NUM                0x20
+
+/* Common names used by other drivers */
+
+#define P_BCAST_STORM_CTRL             REG_PORT_CTRL_0
+#define P_PRIO_CTRL                    REG_PORT_CTRL_0
+#define P_TAG_CTRL                     REG_PORT_CTRL_0
+#define P_MIRROR_CTRL                  REG_PORT_CTRL_1
+#define P_802_1P_CTRL                  REG_PORT_CTRL_2
+#define P_PASS_ALL_CTRL                        REG_PORT_CTRL_12
+#define P_INS_SRC_PVID_CTRL            REG_PORT_CTRL_12
+#define P_DROP_TAG_CTRL                        REG_PORT_CTRL_13
+#define P_RATE_LIMIT_CTRL              REG_PORT_RATE_LIMIT
+
+#define S_UNKNOWN_DA_CTRL              REG_SWITCH_CTRL_12
+#define S_FORWARD_INVALID_VID_CTRL     REG_FORWARD_INVALID_VID
+
+#define S_FLUSH_TABLE_CTRL             REG_SW_CTRL_0
+#define S_LINK_AGING_CTRL              REG_SW_CTRL_0
+#define S_HUGE_PACKET_CTRL             REG_SW_CTRL_1
+#define S_MIRROR_CTRL                  REG_SW_CTRL_3
+#define S_REPLACE_VID_CTRL             REG_SW_CTRL_4
+#define S_PASS_PAUSE_CTRL              REG_SW_CTRL_10
+#define S_802_1P_PRIO_CTRL             REG_SW_CTRL_12
+#define S_TOS_PRIO_CTRL                        REG_TOS_PRIO_CTRL_0
+#define S_IPV6_MLD_CTRL                        REG_SW_CTRL_21
+
+#define IND_ACC_TABLE(table)           ((table) << 8)
+
+/* */
+#define REG_IND_EEE_GLOB2_LO           0x34
+#define REG_IND_EEE_GLOB2_HI           0x35
+
+/**
+ * MIB_COUNTER_VALUE                   00-00000000-3FFFFFFF
+ * MIB_TOTAL_BYTES                     00-0000000F-FFFFFFFF
+ * MIB_PACKET_DROPPED                  00-00000000-0000FFFF
+ * MIB_COUNTER_VALID                   00-00000020-00000000
+ * MIB_COUNTER_OVERFLOW                        00-00000040-00000000
+ */
+
+#define MIB_COUNTER_VALUE              0x3FFFFFFF
+
+#define KSZ8795_MIB_TOTAL_RX_0         0x100
+#define KSZ8795_MIB_TOTAL_TX_0         0x101
+#define KSZ8795_MIB_TOTAL_RX_1         0x104
+#define KSZ8795_MIB_TOTAL_TX_1         0x105
+
+#define KSZ8863_MIB_PACKET_DROPPED_TX_0 0x100
+#define KSZ8863_MIB_PACKET_DROPPED_RX_0 0x105
+
+#define MIB_PACKET_DROPPED             0x0000FFFF
+
+#define MIB_TOTAL_BYTES_H              0x0000000F
+
+#define TAIL_TAG_OVERRIDE              BIT(6)
+#define TAIL_TAG_LOOKUP                        BIT(7)
+
+#define FID_ENTRIES                    128
+#define KSZ8_DYN_MAC_ENTRIES           1024
+
+#endif