netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/3] microchip: add support for ksz8863 driver family
@ 2019-05-08 21:13 Michael Grzeschik
  2019-05-08 21:13 ` [RFC 1/3] mdio-bitbang: add SMI0 mode support Michael Grzeschik
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Michael Grzeschik @ 2019-05-08 21:13 UTC (permalink / raw)
  To: Tristram.Ha; +Cc: kernel, UNGLinuxDriver, netdev

This series adds support for the ksz8863 driver family to the
dsa based ksz drivers. For now the ksz8863 nad ksz8873 are compatible.

The driver is based on the ksz8895 RFC patch from Tristam Ha:

https://patchwork.ozlabs.org/patch/822712/

And the latest version of the ksz8863.h from Microchip:

https://raw.githubusercontent.com/Microchip-Ethernet/UNG8071_old_1.10/master/KSZ/linux-drivers/ksz8863/linux-3.14/drivers/net/ethernet/micrel/ksz8863.h

The driver works as expected on the machine including the switch. The
clients on the other hand behind the switch see some bandwidth issues
after the stack was bootet and configured appropriate via:

ip link add name br0 type bridge

ip link set dev eth1 master br0
ip link set dev eth2 master br0

@Tristam: Could you have a look if something obious was misconfigured?

Michael Grzeschik (3):
  mdio-bitbang: add SMI0 mode support
  ksz: Add Microchip KSZ8873 SMI-DSA driver
  dt-bindings: net: dsa: document additional Microchip KSZ8863 family
    switches

 .../devicetree/bindings/net/dsa/ksz.txt       |   44 +
 drivers/net/dsa/microchip/Kconfig             |   16 +
 drivers/net/dsa/microchip/Makefile            |    2 +
 drivers/net/dsa/microchip/ksz8863.c           | 1026 +++++++++++++++++
 drivers/net/dsa/microchip/ksz8863_reg.h       |  605 ++++++++++
 drivers/net/dsa/microchip/ksz8863_smi.c       |  105 ++
 drivers/net/dsa/microchip/ksz_priv.h          |    3 +
 drivers/net/phy/mdio-bitbang.c                |   10 +
 include/linux/phy.h                           |   12 +
 include/net/dsa.h                             |    2 +
 net/dsa/Kconfig                               |    7 +
 net/dsa/tag_ksz.c                             |   45 +
 12 files changed, 1877 insertions(+)
 create mode 100644 drivers/net/dsa/microchip/ksz8863.c
 create mode 100644 drivers/net/dsa/microchip/ksz8863_reg.h
 create mode 100644 drivers/net/dsa/microchip/ksz8863_smi.c

-- 
2.20.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC 1/3] mdio-bitbang: add SMI0 mode support
  2019-05-08 21:13 [RFC 0/3] microchip: add support for ksz8863 driver family Michael Grzeschik
@ 2019-05-08 21:13 ` Michael Grzeschik
  2019-05-09 14:29   ` Andrew Lunn
  2019-05-08 21:13 ` [RFC 2/3] ksz: Add Microchip KSZ8873 SMI-DSA driver Michael Grzeschik
  2019-05-08 21:13 ` [RFC 3/3] dt-bindings: net: dsa: document additional Microchip KSZ8863 family switches Michael Grzeschik
  2 siblings, 1 reply; 10+ messages in thread
From: Michael Grzeschik @ 2019-05-08 21:13 UTC (permalink / raw)
  To: Tristram.Ha; +Cc: kernel, UNGLinuxDriver, netdev

Some microchip phys support the Serial Management Interface Protocol
(SMI) for the configuration of the extended register set. We add
MII_ADDR_SMI0 as an availabe interface to the mdiobb write and read
functions, as this interface can be easy realized using the bitbang mdio
driver.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
---
 drivers/net/phy/mdio-bitbang.c | 10 ++++++++++
 include/linux/phy.h            | 12 ++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index 5136275c8e739..a978f8a9a172b 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -22,6 +22,10 @@
 #define MDIO_READ 2
 #define MDIO_WRITE 1
 
+#define SMI0_RW_OPCODE	0
+#define SMI0_READ_PHY	(1 << 4)
+#define SMI0_WRITE_PHY	(0 << 4)
+
 #define MDIO_C45 (1<<15)
 #define MDIO_C45_ADDR (MDIO_C45 | 0)
 #define MDIO_C45_READ (MDIO_C45 | 3)
@@ -157,6 +161,9 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
 	if (reg & MII_ADDR_C45) {
 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
 		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
+	} else if (reg & MII_ADDR_SMI0) {
+		mdiobb_cmd(ctrl, SMI0_RW_OPCODE,
+			   (reg & 0xE0) >> 5 | SMI0_READ_PHY, reg);
 	} else
 		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
 
@@ -188,6 +195,9 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
 	if (reg & MII_ADDR_C45) {
 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
 		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
+	} else if (reg & MII_ADDR_SMI0) {
+		mdiobb_cmd(ctrl, SMI0_RW_OPCODE,
+			   (reg & 0xE0) >> 5 | SMI0_WRITE_PHY, reg);
 	} else
 		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
 
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 073fb151b5a99..f011722fbd5c2 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -199,6 +199,18 @@ static inline const char *phy_modes(phy_interface_t interface)
    IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
 #define MII_ADDR_C45 (1<<30)
 
+/* Serial Management Interface (SMI) uses the following frame format:
+ *
+ *       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
+ *               |frame| OP code  |address |address|  |                  |
+ * read | 32x1´s | 01  |    00    | 1xRRR  | RRRRR |Z0| 00000000DDDDDDDD |  Z
+ * write| 32x1´s | 01  |    00    | 0xRRR  | RRRRR |10| xxxxxxxxDDDDDDDD |  Z
+ *
+ * The register number is encoded with the 5 least significant bits in REG
+ * and the 3 most significant bits in PHY
+ */
+#define MII_ADDR_SMI0 (1<<31)
+
 struct device;
 struct phylink;
 struct sk_buff;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [RFC 2/3] ksz: Add Microchip KSZ8873 SMI-DSA driver
  2019-05-08 21:13 [RFC 0/3] microchip: add support for ksz8863 driver family Michael Grzeschik
  2019-05-08 21:13 ` [RFC 1/3] mdio-bitbang: add SMI0 mode support Michael Grzeschik
@ 2019-05-08 21:13 ` Michael Grzeschik
  2019-05-09 14:48   ` Andrew Lunn
  2019-05-08 21:13 ` [RFC 3/3] dt-bindings: net: dsa: document additional Microchip KSZ8863 family switches Michael Grzeschik
  2 siblings, 1 reply; 10+ messages in thread
From: Michael Grzeschik @ 2019-05-08 21:13 UTC (permalink / raw)
  To: Tristram.Ha; +Cc: kernel, UNGLinuxDriver, netdev

Cc: Tristram.Ha@microchip.com
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
---
 drivers/net/dsa/microchip/Kconfig       |   16 +
 drivers/net/dsa/microchip/Makefile      |    2 +
 drivers/net/dsa/microchip/ksz8863.c     | 1026 +++++++++++++++++++++++
 drivers/net/dsa/microchip/ksz8863_reg.h |  605 +++++++++++++
 drivers/net/dsa/microchip/ksz8863_smi.c |  105 +++
 drivers/net/dsa/microchip/ksz_priv.h    |    3 +
 include/net/dsa.h                       |    2 +
 net/dsa/Kconfig                         |    7 +
 net/dsa/tag_ksz.c                       |   45 +
 9 files changed, 1811 insertions(+)
 create mode 100644 drivers/net/dsa/microchip/ksz8863.c
 create mode 100644 drivers/net/dsa/microchip/ksz8863_reg.h
 create mode 100644 drivers/net/dsa/microchip/ksz8863_smi.c

diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
index bea29fde9f3d1..a6fa6ae972951 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -14,3 +14,19 @@ config NET_DSA_MICROCHIP_KSZ9477_SPI
 	depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
 	help
 	  Select to enable support for registering switches configured through SPI.
+
+menuconfig NET_DSA_MICROCHIP_KSZ8863
+	tristate "Microchip KSZ8863 series switch support"
+	depends on NET_DSA
+	select NET_DSA_TAG_KSZ8863
+	select NET_DSA_MICROCHIP_KSZ_COMMON
+	help
+	  This driver adds support for Microchip KSZ8863 switch chips.
+
+config NET_DSA_MICROCHIP_KSZ8863_SMI
+	tristate "KSZ series SMI connected switch driver"
+	depends on NET_DSA_MICROCHIP_KSZ8863
+	default y
+	help
+	  Select to enable support for registering switches configured through SMI.
+	  Supports the KSZ8863 Switch.
diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
index 3142c18b8f573..73fd58052a9d6 100644
--- a/drivers/net/dsa/microchip/Makefile
+++ b/drivers/net/dsa/microchip/Makefile
@@ -1,3 +1,5 @@
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)	+= ksz_common.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)		+= ksz9477.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)	+= ksz9477_spi.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863)	        += ksz8863.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI)	+= ksz8863_smi.o
diff --git a/drivers/net/dsa/microchip/ksz8863.c b/drivers/net/dsa/microchip/ksz8863.c
new file mode 100644
index 0000000000000..ed1a775eb5ab7
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz8863.c
@@ -0,0 +1,1026 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip KSZ8863 switch driver main logic
+ *
+ * Copyright (C) 2017-2019 Microchip Technology Inc.
+ * Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>
+ */
+
+#include <linux/delay.h>
+#include <linux/export.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 <net/dsa.h>
+#include <net/switchdev.h>
+
+#include "ksz_priv.h"
+#include "ksz_common.h"
+#include "ksz8863_reg.h"
+
+static const struct {
+	char string[ETH_GSTRING_LEN];
+} mib_names[TOTAL_SWITCH_COUNTER_NUM] = {
+	{ "rx" },
+	{ "rx_hi" },
+	{ "rx_undersize" },
+	{ "rx_fragments" },
+	{ "rx_oversize" },
+	{ "rx_jabbers" },
+	{ "rx_symbol_err" },
+	{ "rx_crc_err" },
+	{ "rx_align_err" },
+	{ "rx_mac_ctrl" },
+	{ "rx_pause" },
+	{ "rx_bcast" },
+	{ "rx_mcast" },
+	{ "rx_ucast" },
+	{ "rx_64_or_less" },
+	{ "rx_65_127" },
+	{ "rx_128_255" },
+	{ "rx_256_511" },
+	{ "rx_512_1023" },
+	{ "rx_1024_1522" },
+	{ "tx" },
+	{ "tx_hi" },
+	{ "tx_late_col" },
+	{ "tx_pause" },
+	{ "tx_bcast" },
+	{ "tx_mcast" },
+	{ "tx_ucast" },
+	{ "tx_deferred" },
+	{ "tx_total_col" },
+	{ "tx_exc_col" },
+	{ "tx_single_col" },
+	{ "tx_mult_col" },
+	{ "rx_discards" },
+	{ "tx_discards" },
+};
+
+static int ksz8863_reset_switch(struct ksz_device *dev)
+{
+	/* reset switch */
+	ksz_cfg(dev, REG_SWITCH_RESET, GLOBAL_SOFTWARE_RESET | PCS_RESET, true);
+
+	ksz_cfg(dev, REG_POWER_MANAGEMENT, SWITCH_SOFTWARE_POWER_DOWN, true);
+	ksz_cfg(dev, REG_POWER_MANAGEMENT, SWITCH_SOFTWARE_POWER_DOWN, false);
+
+	return 0;
+}
+
+static void ksz8863_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
+			      u64 *cnt)
+{
+	u32 data;
+	u16 ctrl_addr;
+	u8 check;
+	int loop;
+
+	ctrl_addr = addr + SWITCH_COUNTER_NUM * port;
+	ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
+
+	mutex_lock(&dev->alu_mutex);
+	ksz_write16(dev, 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, REG_IND_MIB_CHECK, &check);
+
+		if (check & MIB_COUNTER_VALID) {
+			ksz_read32(dev, REG_IND_DATA_LO, &data);
+			if (check & MIB_COUNTER_OVERFLOW)
+				*cnt += MIB_COUNTER_VALUE + 1;
+			*cnt += data & MIB_COUNTER_VALUE;
+			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 cur;
+	u32 data;
+	u16 ctrl_addr;
+	u32 *last = (u32 *)dropped;
+
+	addr -= SWITCH_COUNTER_NUM;
+	ctrl_addr = addr ? KS_MIB_PACKET_DROPPED_TX_0 :
+			   KS_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, REG_IND_CTRL_0, ctrl_addr);
+	ksz_read32(dev, 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;
+	}
+}
+
+static void ksz8863_port_init_cnt(struct ksz_device *dev, int port)
+{
+	struct ksz_port_mib *mib = &dev->ports[port].mib;
+	u64 *dropped;
+
+	mib->cnt_ptr = 0;
+
+	/* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
+	while (mib->cnt_ptr < dev->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->mib_cnt];
+
+	/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
+	while (mib->cnt_ptr < dev->mib_cnt) {
+		dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
+					dropped, &mib->counters[mib->cnt_ptr]);
+		++mib->cnt_ptr;
+	}
+	mib->cnt_ptr = 0;
+	memset(mib->counters, 0, dev->mib_cnt * sizeof(u64));
+}
+
+static void ksz8863_r_table(struct ksz_device *dev, int table, u16 addr,
+			    u64 *data)
+{
+	u16 ctrl_addr;
+
+	ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
+
+	mutex_lock(&dev->alu_mutex);
+	ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
+	ksz_get(dev, REG_IND_DATA_HI, data, sizeof(u64));
+	mutex_unlock(&dev->alu_mutex);
+	*data = be64_to_cpu(*data);
+}
+
+static void ksz8863_w_table(struct ksz_device *dev, int table, u16 addr,
+			    u64 data)
+{
+	u16 ctrl_addr;
+
+	ctrl_addr = IND_ACC_TABLE(table) | addr;
+	data = cpu_to_be64(data);
+
+	mutex_lock(&dev->alu_mutex);
+	ksz_set(dev, REG_IND_DATA_HI, &data, sizeof(u64));
+	ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
+	mutex_unlock(&dev->alu_mutex);
+}
+
+static int ksz8863_valid_dyn_entry(struct ksz_device *dev, u8 *data)
+{
+	int timeout = 100;
+
+	do {
+		ksz_read8(dev, REG_IND_DATA_CHECK, data);
+		timeout--;
+	} while ((*data & DYNAMIC_MAC_TABLE_NOT_READY) && timeout);
+
+	/* Entry is not ready for accessing. */
+	if (*data & DYNAMIC_MAC_TABLE_NOT_READY) {
+		return -EAGAIN;
+	/* Entry is ready for accessing. */
+	} else {
+		ksz_read8(dev, REG_IND_DATA_8, data);
+
+		/* There is no valid entry in the table. */
+		if (*data & DYNAMIC_MAC_TABLE_MAC_EMPTY)
+			return -ENXIO;
+	}
+	return 0;
+}
+
+static int ksz8863_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
+				   u8 *mac_addr, u8 *fid, u8 *src_port,
+				   u8 *timestamp, u16 *entries)
+{
+	u32 data_hi;
+	u32 data_lo;
+	u16 ctrl_addr;
+	int rc;
+	u8 data;
+
+	ctrl_addr = IND_ACC_TABLE(TABLE_DYNAMIC_MAC | TABLE_READ) | addr;
+
+	mutex_lock(&dev->alu_mutex);
+	ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
+
+	rc = ksz8863_valid_dyn_entry(dev, &data);
+	if (rc == -EAGAIN) {
+		if (addr == 0)
+			*entries = 0;
+	} else if (rc == -ENXIO) {
+		*entries = 0;
+	/* At least one valid entry in the table. */
+	} else {
+		u64 buf;
+		int cnt;
+
+		ksz_get(dev, REG_IND_DATA_HI, &buf, sizeof(buf));
+		buf = be64_to_cpu(buf);
+		data_hi = (u32)(buf >> 32);
+		data_lo = (u32)buf;
+
+		/* Check out how many valid entry in the table. */
+		cnt = data & DYNAMIC_MAC_TABLE_ENTRIES_H;
+		cnt <<= DYNAMIC_MAC_ENTRIES_H_S;
+		cnt |= (data_hi & DYNAMIC_MAC_TABLE_ENTRIES) >>
+			DYNAMIC_MAC_ENTRIES_S;
+		*entries = cnt + 1;
+
+		*fid = (data_hi & DYNAMIC_MAC_TABLE_FID) >>
+			DYNAMIC_MAC_FID_S;
+		*src_port = (data_hi & DYNAMIC_MAC_TABLE_SRC_PORT) >>
+			DYNAMIC_MAC_SRC_PORT_S;
+		*timestamp = (data_hi & DYNAMIC_MAC_TABLE_TIMESTAMP) >>
+			DYNAMIC_MAC_TIMESTAMP_S;
+
+		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);
+		rc = 0;
+	}
+	mutex_unlock(&dev->alu_mutex);
+
+	return rc;
+}
+
+static int ksz8863_r_sta_mac_table(struct ksz_device *dev, u16 addr,
+				   struct alu_struct *alu)
+{
+	u64 data;
+	u32 data_hi;
+	u32 data_lo;
+
+	ksz8863_r_table(dev, TABLE_STATIC_MAC, addr, &data);
+
+	data_hi = data >> 32;
+	data_lo = (u32)data;
+
+	if (data_hi & (STATIC_MAC_TABLE_VALID | STATIC_MAC_TABLE_OVERRIDE)) {
+		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 & STATIC_MAC_TABLE_FWD_PORTS) >>
+			STATIC_MAC_FWD_PORTS_S;
+		alu->is_override =
+			(data_hi & STATIC_MAC_TABLE_OVERRIDE) ? 1 : 0;
+		data_hi >>= 1;
+		alu->is_static = true;
+		alu->is_use_fid = (data_hi & STATIC_MAC_TABLE_USE_FID) ? 1 : 0;
+		alu->fid = (data_hi & STATIC_MAC_TABLE_FID) >>
+			STATIC_MAC_FID_S;
+
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+static void ksz8863_w_sta_mac_table(struct ksz_device *dev, u16 addr,
+				    struct alu_struct *alu)
+{
+	u64 data;
+	u32 data_hi;
+	u32 data_lo;
+
+	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 << STATIC_MAC_FWD_PORTS_S;
+
+	if (alu->is_override)
+		data_hi |= STATIC_MAC_TABLE_OVERRIDE;
+
+	if (alu->is_use_fid) {
+		data_hi |= STATIC_MAC_TABLE_USE_FID;
+		data_hi |= (u32)alu->fid << STATIC_MAC_FID_S;
+	}
+
+	if (alu->is_static)
+		data_hi |= STATIC_MAC_TABLE_VALID;
+	else
+		data_hi &= ~STATIC_MAC_TABLE_OVERRIDE;
+
+	data = (u64)data_hi << 32 | data_lo;
+	ksz8863_w_table(dev, TABLE_STATIC_MAC, addr, data);
+}
+
+static inline void ksz8863_from_vlan(u16 vlan, u8 *fid, u8 *member, u8 *valid)
+{
+	*fid = vlan & VLAN_TABLE_FID;
+	*member = (vlan & VLAN_TABLE_MEMBERSHIP) >> VLAN_TABLE_MEMBERSHIP_S;
+	*valid = !!(vlan & VLAN_TABLE_VALID);
+}
+
+static inline void ksz8863_to_vlan(u8 fid, u8 member, u8 valid, u16 *vlan)
+{
+	*vlan = fid;
+	*vlan |= (u16)member << VLAN_TABLE_MEMBERSHIP_S;
+	if (valid)
+		*vlan |= VLAN_TABLE_VALID;
+}
+
+static void ksz8863_r_vlan_entries(struct ksz_device *dev, u16 addr)
+{
+	u64 data;
+	int i;
+
+	ksz8863_r_table(dev, TABLE_VLAN, addr, &data);
+	addr *= 2;
+	for (i = 0; i < 2; i++) {
+		dev->vlan_cache[addr + i].table[0] = data & VLAN_TABLE_M;
+		data >>= VLAN_TABLE_S;
+	}
+}
+
+static void ksz8863_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan)
+{
+	u64 buf;
+	u16 addr;
+	int index;
+
+	addr = vid / 2;
+	index = vid & 3;
+	ksz8863_r_table(dev, TABLE_VLAN, addr, &buf);
+	buf >>= VLAN_TABLE_S * index;
+	*vlan = buf & VLAN_TABLE_M;
+}
+
+static void ksz8863_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
+{
+	u64 buf;
+	u16 addr;
+	int index;
+
+	addr = vid / 2;
+	index = vid & 3;
+	ksz8863_r_table(dev, TABLE_VLAN, addr, &buf);
+	index *= VLAN_TABLE_S;
+	buf &= ~(VLAN_TABLE_M << index);
+	buf |= (u64)vlan << index;
+	dev->vlan_cache[vid].table[0] = vlan;
+	ksz8863_w_table(dev, TABLE_VLAN, addr, buf);
+}
+
+static enum dsa_tag_protocol ksz8863_get_tag_protocol(struct dsa_switch *ds,
+						      int port)
+{
+	/* Use KSZ8795 tail tagging code. */
+	return DSA_TAG_PROTO_KSZ8863;
+}
+
+static void ksz8863_get_strings(struct dsa_switch *ds, int port,
+				u32 stringset, uint8_t *buf)
+{
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) {
+			memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string,
+			       ETH_GSTRING_LEN);
+		}
+		break;
+	}
+}
+
+static const u8 stp_multicast_addr[] = {
+	0x01, 0x80, 0xC2, 0x00, 0x00, 0x00
+};
+
+static void ksz8863_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);
+	dev->ports[port].member = member;
+}
+
+static void ksz8863_port_stp_state_set(struct dsa_switch *ds, int port,
+				       u8 state)
+{
+	struct ksz_device *dev = ds->priv;
+	struct ksz_port *p = &dev->ports[port];
+	u8 data;
+	int member = -1;
+
+	ksz_pread8(dev, port, P_STP_CTRL, &data);
+	data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
+
+	switch (state) {
+	case BR_STATE_DISABLED:
+		data |= PORT_LEARN_DISABLE;
+		if (port < SWITCH_PORT_NUM)
+			member = 0;
+		break;
+	case BR_STATE_LISTENING:
+		data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
+		if (port < SWITCH_PORT_NUM &&
+		    p->stp_state == BR_STATE_DISABLED)
+			member = dev->host_mask | p->vid_member;
+		break;
+	case BR_STATE_LEARNING:
+		data |= PORT_RX_ENABLE;
+		break;
+	case BR_STATE_FORWARDING:
+		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
+
+		/* This function is also used internally. */
+		if (port == dev->cpu_port)
+			break;
+
+		/* Port is a member of a bridge. */
+		if (dev->br_member & (1 << port)) {
+			dev->member |= (1 << port);
+			member = dev->member;
+		} else {
+			member = dev->host_mask | p->vid_member;
+		}
+		break;
+	case BR_STATE_BLOCKING:
+		data |= PORT_LEARN_DISABLE;
+		if (port < SWITCH_PORT_NUM &&
+		    p->stp_state == BR_STATE_DISABLED)
+			member = dev->host_mask | p->vid_member;
+		break;
+	default:
+		dev_err(ds->dev, "invalid STP state: %d\n", state);
+		return;
+	}
+
+	ksz_pwrite8(dev, port, P_STP_CTRL, data);
+	p->stp_state = state;
+	if (data & PORT_RX_ENABLE)
+		dev->rx_ports |= (1 << port);
+	else
+		dev->rx_ports &= ~(1 << port);
+	if (data & PORT_TX_ENABLE)
+		dev->tx_ports |= (1 << port);
+	else
+		dev->tx_ports &= ~(1 << port);
+
+	/* Port membership may share register with STP state. */
+	if (member >= 0 && member != p->member)
+		ksz8863_cfg_port_member(dev, port, (u8)member);
+
+	/* Check if forwarding needs to be updated. */
+	if (state != BR_STATE_FORWARDING) {
+		if (dev->br_member & (1 << port))
+			dev->member &= ~(1 << port);
+	}
+
+	/* When topology has changed the function ksz_update_port_member
+	 * should be called to modify port forwarding behavior.  However
+	 * as the offload_fwd_mark indication cannot be reported here
+	 * the switch forwarding function is not enabled.
+	 */
+}
+
+static void ksz8863_flush_dyn_mac_table(struct ksz_device *dev, int port)
+{
+	int cnt;
+	int first;
+	int index;
+	u8 learn[TOTAL_PORT_NUM];
+
+	if ((uint)port < TOTAL_PORT_NUM) {
+		first = port;
+		cnt = port + 1;
+	} else {
+		/* Flush all ports. */
+		first = 0;
+		cnt = dev->mib_port_cnt;
+	}
+	for (index = first; index < cnt; index++) {
+		ksz_pread8(dev, index, P_STP_CTRL, &learn[index]);
+		if (!(learn[index] & PORT_LEARN_DISABLE))
+			ksz_pwrite8(dev, index, P_STP_CTRL,
+				    learn[index] | PORT_LEARN_DISABLE);
+	}
+	ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SWITCH_FLUSH_DYN_MAC_TABLE, true);
+	for (index = first; index < cnt; index++) {
+		if (!(learn[index] & PORT_LEARN_DISABLE))
+			ksz_pwrite8(dev, index, P_STP_CTRL, learn[index]);
+	}
+}
+
+static int ksz8863_port_vlan_filtering(struct dsa_switch *ds, int port,
+				       bool flag)
+{
+	struct ksz_device *dev = ds->priv;
+
+	ksz_cfg(dev, S_MIRROR_CTRL, SWITCH_VLAN_ENABLE, flag);
+
+	return 0;
+}
+
+static void ksz8863_port_vlan_add(struct dsa_switch *ds, int port,
+				  const struct switchdev_obj_port_vlan *vlan)
+{
+	struct ksz_device *dev = ds->priv;
+	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+	u16 data;
+	u16 vid;
+	u8 fid;
+	u8 member;
+	u8 valid;
+	u16 new_pvid = 0;
+
+	mutex_lock(&dev->vlan_mutex);
+
+	ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
+
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+		ksz8863_r_vlan_table(dev, vid, &data);
+		ksz8863_from_vlan(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);
+
+		ksz8863_to_vlan(fid, member, valid, &data);
+		ksz8863_w_vlan_table(dev, vid, data);
+
+		/* change PVID */
+		if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
+			new_pvid = vid;
+	}
+
+	if (new_pvid) {
+		ksz_pread16(dev, port, REG_PORT_CTRL_VID, &vid);
+		vid &= 0xfff;
+		vid |= new_pvid;
+		ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, vid);
+	}
+
+	mutex_unlock(&dev->vlan_mutex);
+}
+
+static int ksz8863_port_vlan_del(struct dsa_switch *ds, int port,
+				 const struct switchdev_obj_port_vlan *vlan)
+{
+	struct ksz_device *dev = ds->priv;
+	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+	u16 data;
+	u16 vid;
+	u16 pvid;
+	u8 fid;
+	u8 member;
+	u8 valid;
+	u16 new_pvid = 0;
+
+	mutex_lock(&dev->vlan_mutex);
+
+	ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid);
+	pvid = pvid & 0xFFF;
+
+	ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
+
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+		ksz8863_r_vlan_table(dev, vid, &data);
+		ksz8863_from_vlan(data, &fid, &member, &valid);
+
+		member &= ~BIT(port);
+
+		/* Invalidate the entry if no more member. */
+		if (!member) {
+			fid = 0;
+			valid = 0;
+		}
+
+		if (pvid == vid)
+			new_pvid = 1;
+
+		ksz8863_to_vlan(fid, member, valid, &data);
+		ksz8863_w_vlan_table(dev, vid, data);
+	}
+
+	if (new_pvid != pvid)
+		ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, pvid);
+
+	mutex_unlock(&dev->vlan_mutex);
+
+	return 0;
+}
+
+static int ksz8863_port_mirror_add(struct dsa_switch *ds, int port,
+				   struct dsa_mall_mirror_tc_entry *mirror,
+				   bool ingress)
+{
+	struct ksz_device *dev = ds->priv;
+
+	if (ingress) {
+		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
+		dev->mirror_rx |= (1 << port);
+	} else {
+		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
+		dev->mirror_tx |= (1 << 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;
+}
+
+static void ksz8863_port_mirror_del(struct dsa_switch *ds, int port,
+				    struct dsa_mall_mirror_tc_entry *mirror)
+{
+	struct ksz_device *dev = ds->priv;
+	u8 data;
+
+	if (mirror->ingress) {
+		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
+		dev->mirror_rx &= ~(1 << port);
+	} else {
+		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
+		dev->mirror_tx &= ~(1 << 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 ksz8863_phy_setup(struct ksz_device *dev, int port,
+			      struct phy_device *phy)
+{
+	/* SUPPORTED_Pause can be removed to disable flow control when
+	 * rate limiting is used.
+	 */
+	linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phy->supported);
+	linkmode_copy(phy->advertising, phy->supported);
+}
+
+static void ksz8863_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+{
+	u8 member;
+	struct ksz_port *p = &dev->ports[port];
+
+	/* enable broadcast storm limit */
+	ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
+
+	/* disable DiffServ priority */
+	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false);
+
+	/* replace priority */
+	ksz_port_cfg(dev, port, P_802_1P_CTRL, PORT_802_1P_REMAPPING, false);
+
+	/* enable 802.1p priority */
+	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true);
+
+	if (cpu_port) {
+		member = dev->port_mask;
+		dev->on_ports = dev->host_mask;
+		dev->live_ports = dev->host_mask;
+	} else {
+		member = dev->host_mask | p->vid_member;
+		dev->on_ports |= (1 << port);
+
+		/* Link was detected before port is enabled. */
+		if (p->phydev.link)
+			dev->live_ports |= (1 << port);
+	}
+	ksz8863_cfg_port_member(dev, port, member);
+}
+
+static void ksz8863_config_cpu_port(struct dsa_switch *ds)
+{
+	struct ksz_device *dev = ds->priv;
+	struct ksz_port *p;
+	int i;
+
+	ds->num_ports = dev->port_cnt + 1;
+
+	ksz_cfg(dev, S_TAIL_TAG_CTRL, SWITCH_TAIL_TAG_ENABLE, true);
+
+	p = &dev->ports[dev->cpu_port];
+	p->vid_member = dev->port_mask;
+	p->on = 1;
+
+	ksz8863_port_setup(dev, dev->cpu_port, true);
+	dev->member = dev->host_mask;
+
+	for (i = 0; i < SWITCH_PORT_NUM; i++) {
+		p = &dev->ports[i];
+
+		/* Initialize to non-zero so that ksz_cfg_port_member() will
+		 * be called.
+		 */
+		p->vid_member = (1 << i);
+		p->member = dev->port_mask;
+		ksz8863_port_stp_state_set(ds, i, BR_STATE_DISABLED);
+
+		p->on = 1;
+		p->phy = 1;
+	}
+
+	for (i = 0; i < dev->phy_port_cnt; i++) {
+		p = &dev->ports[i];
+		if (!p->on)
+			continue;
+		ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL,
+			     false);
+	}
+}
+
+static int ksz8863_setup(struct dsa_switch *ds)
+{
+	u8 data8;
+	u16 data16;
+	u32 value;
+	int i;
+	struct alu_struct alu;
+	struct ksz_device *dev = ds->priv;
+	int ret = 0;
+
+	dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
+				       dev->num_vlans, GFP_KERNEL);
+	if (!dev->vlan_cache)
+		return -ENOMEM;
+
+	ret = ksz8863_reset_switch(dev);
+	if (ret) {
+		dev_err(ds->dev, "failed to reset switch\n");
+		return ret;
+	}
+
+	ksz_cfg(dev, S_REPLACE_VID_CTRL, SWITCH_FLOW_CTRL, true);
+
+	/* Enable automatic fast aging when link changed detected. */
+	ksz_cfg(dev, S_LINK_AGING_CTRL, SWITCH_LINK_AUTO_AGING, true);
+
+	ksz_read8(dev, REG_SWITCH_CTRL_1, &data8);
+
+	/* Enable aggressive back off algorithm in half duplex mode. */
+	data8 |= SWITCH_AGGR_BACKOFF;
+	ksz_write8(dev, REG_SWITCH_CTRL_1, data8);
+
+	ksz_read8(dev, REG_SWITCH_CTRL_2, &data8);
+
+	/* Make sure unicast VLAN boundary is set as default. */
+	data8 |= UNICAST_VLAN_BOUNDARY;
+
+	/* Enable no excessive collision drop. */
+	data8 |= NO_EXC_COLLISION_DROP;
+	ksz_write8(dev, REG_SWITCH_CTRL_2, data8);
+
+	ksz8863_config_cpu_port(ds);
+
+	ksz_cfg(dev, REG_SWITCH_CTRL_2, MULTICAST_STORM_DISABLE, true);
+
+	ksz_cfg(dev, S_REPLACE_VID_CTRL, SWITCH_REPLACE_VID, false);
+
+	ksz_cfg(dev, S_MIRROR_CTRL, SWITCH_MIRROR_RX_TX, false);
+
+	/* set broadcast storm protection 10% rate */
+	data8 = BROADCAST_STORM_PROT_RATE;
+	value = ((u32)BROADCAST_STORM_VALUE * data8) / 100;
+	if (value > BROADCAST_STORM_RATE)
+		value = BROADCAST_STORM_RATE;
+	ksz_read16(dev, S_REPLACE_VID_CTRL, &data16);
+	data16 &= ~BROADCAST_STORM_RATE;
+	data16 |= value;
+	ksz_write16(dev, S_REPLACE_VID_CTRL, data16);
+
+	for (i = 0; i < VLAN_TABLE_ENTRIES; i++)
+		ksz8863_r_vlan_entries(dev, i);
+
+	/* Setup STP address for STP operation. */
+	memset(&alu, 0, sizeof(alu));
+	memcpy(alu.mac, stp_multicast_addr, ETH_ALEN);
+	alu.is_static = true;
+	alu.is_override = true;
+	alu.port_forward = dev->host_mask;
+
+	ksz8863_w_sta_mac_table(dev, 0, &alu);
+
+	ksz_write8(dev, REG_CHIP_ID1, SWITCH_START);
+
+	ksz_init_mib_timer(dev);
+
+	return 0;
+}
+
+static const struct dsa_switch_ops ksz8863_switch_ops = {
+	.get_tag_protocol	= ksz8863_get_tag_protocol,
+	.setup			= ksz8863_setup,
+	.adjust_link		= ksz_adjust_link,
+	.port_enable		= ksz_enable_port,
+	.port_disable		= ksz_disable_port,
+	.get_strings		= ksz8863_get_strings,
+	.get_ethtool_stats	= ksz_get_ethtool_stats,
+	.get_sset_count		= ksz_sset_count,
+	.port_bridge_join	= ksz_port_bridge_join,
+	.port_bridge_leave	= ksz_port_bridge_leave,
+	.port_stp_state_set	= ksz8863_port_stp_state_set,
+	.port_fast_age		= ksz_port_fast_age,
+	.port_vlan_filtering	= ksz8863_port_vlan_filtering,
+	.port_vlan_prepare	= ksz_port_vlan_prepare,
+	.port_vlan_add		= ksz8863_port_vlan_add,
+	.port_vlan_del		= ksz8863_port_vlan_del,
+	.port_fdb_dump		= ksz_port_fdb_dump,
+	.port_mdb_prepare       = ksz_port_mdb_prepare,
+	.port_mdb_add           = ksz_port_mdb_add,
+	.port_mdb_del           = ksz_port_mdb_del,
+	.port_mirror_add	= ksz8863_port_mirror_add,
+	.port_mirror_del	= ksz8863_port_mirror_del,
+};
+
+static u32 ksz8863_get_port_addr(int port, int reg)
+{
+	int offset;
+
+	PORT_CTRL_ADDR(port, offset);
+
+	return reg + offset;
+}
+
+static int ksz8863_switch_detect(struct ksz_device *dev)
+{
+	u16 id16;
+	u8 id1;
+	u8 id2;
+	int ret;
+
+	/* read chip id */
+	ret = ksz_read16(dev, REG_CHIP_ID0, &id16);
+	if (ret)
+		return ret;
+
+	id1 = id16 >> 8;
+	id2 = id16 & SW_CHIP_ID_M;
+	if (id1 != FAMILY_ID ||
+	    id2 != CHIP_ID_63)
+		return -ENODEV;
+
+	dev->mib_port_cnt = TOTAL_PORT_NUM;
+	dev->phy_port_cnt = SWITCH_PORT_NUM;
+
+	id16 = 0x8800;
+	id16 |= 0x73;
+	dev->chip_id = id16;
+
+	dev->cpu_port = dev->mib_port_cnt - 1;
+	dev->host_mask = (1 << dev->cpu_port);
+
+	return 0;
+}
+
+struct ksz_chip_data {
+	u16 chip_id;
+	const char *dev_name;
+	int num_vlans;
+	int num_alus;
+	int num_statics;
+	int cpu_ports;
+	int port_cnt;
+};
+
+static const struct ksz_chip_data ksz8863_switch_chips[] = {
+	{
+		.chip_id = 0x8863,
+		.dev_name = "KSZ8863",
+		.num_vlans = 16,
+		.num_alus = 0,
+		.num_statics = 8,
+		.cpu_ports = 0x4,	/* can be configured as cpu port */
+		.port_cnt = 2,		/* total physical port count */
+	},
+	{
+		.chip_id = 0x8873,
+		.dev_name = "KSZ8873",
+		.num_vlans = 16,
+		.num_alus = 0,
+		.num_statics = 8,
+		.cpu_ports = 0x4,	/* can be configured as cpu port */
+		.port_cnt = 2,		/* total physical port count */
+	},
+};
+
+static int ksz8863_switch_init(struct ksz_device *dev)
+{
+	int i;
+
+	dev->ds->ops = &ksz8863_switch_ops;
+
+	for (i = 0; i < ARRAY_SIZE(ksz8863_switch_chips); i++) {
+		const struct ksz_chip_data *chip = &ksz8863_switch_chips[i];
+
+		if (dev->chip_id == chip->chip_id) {
+			dev->name = chip->dev_name;
+			dev->num_vlans = chip->num_vlans;
+			dev->num_alus = chip->num_alus;
+			dev->num_statics = chip->num_statics;
+			dev->port_cnt = chip->port_cnt;
+			dev->cpu_ports = chip->cpu_ports;
+
+			break;
+		}
+	}
+
+	/* no switch found */
+	if (!dev->cpu_ports)
+		return -ENODEV;
+
+	dev->port_mask = (1 << dev->port_cnt) - 1;
+	dev->port_mask |= dev->host_mask;
+
+	dev->reg_mib_cnt = SWITCH_COUNTER_NUM;
+	dev->mib_cnt = TOTAL_SWITCH_COUNTER_NUM;
+
+	i = dev->mib_port_cnt;
+	dev->ports = devm_kzalloc(dev->dev, sizeof(struct ksz_port) * i,
+				  GFP_KERNEL);
+	if (!dev->ports)
+		return -ENOMEM;
+	for (i = 0; i < dev->mib_port_cnt; i++) {
+		mutex_init(&dev->ports[i].mib.cnt_mutex);
+		dev->ports[i].mib.counters =
+			devm_kzalloc(dev->dev,
+				     sizeof(u64) *
+				     (TOTAL_SWITCH_COUNTER_NUM + 1),
+				     GFP_KERNEL);
+		if (!dev->ports[i].mib.counters)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void ksz8863_switch_exit(struct ksz_device *dev)
+{
+	ksz8863_reset_switch(dev);
+	ksz_write8(dev, REG_CHIP_ID1, SWITCH_START);
+}
+
+static const struct ksz_dev_ops ksz8863_dev_ops = {
+	.get_port_addr = ksz8863_get_port_addr,
+	.cfg_port_member = ksz8863_cfg_port_member,
+	.flush_dyn_mac_table = ksz8863_flush_dyn_mac_table,
+	.phy_setup = ksz8863_phy_setup,
+	.port_setup = ksz8863_port_setup,
+	.r_dyn_mac_table = ksz8863_r_dyn_mac_table,
+	.r_sta_mac_table = ksz8863_r_sta_mac_table,
+	.w_sta_mac_table = ksz8863_w_sta_mac_table,
+	.r_mib_cnt = ksz8863_r_mib_cnt,
+	.r_mib_pkt = ksz8863_r_mib_pkt,
+	.port_init_cnt = ksz8863_port_init_cnt,
+	.shutdown = ksz8863_reset_switch,
+	.detect = ksz8863_switch_detect,
+	.init = ksz8863_switch_init,
+	.exit = ksz8863_switch_exit,
+};
+
+int ksz8863_switch_register(struct ksz_device *dev)
+{
+	return ksz_switch_register(dev, &ksz8863_dev_ops);
+}
+EXPORT_SYMBOL(ksz8863_switch_register);
+
+MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>");
+MODULE_DESCRIPTION("Micrel KSZ8863 SMI Switch driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/microchip/ksz8863_reg.h b/drivers/net/dsa/microchip/ksz8863_reg.h
new file mode 100644
index 0000000000000..6921890ae5509
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz8863_reg.h
@@ -0,0 +1,605 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Microchip KSZ8863 definition file
+ *
+ * Copyright (c) 2015-2016 Microchip Technology Inc.
+ */
+
+#ifndef __KSZ8863_REGS_H
+#define __KSZ8863_REGS_H
+
+#define REG_CHIP_ID0			0x00
+
+#define FAMILY_ID			0x88
+
+#define REG_CHIP_ID1			0x01
+#define SW_CHIP_ID_M			0xF0
+
+#define SWITCH_CHIP_ID_MASK		0xF0
+#define SWITCH_CHIP_ID_SHIFT		4
+#define SWITCH_REVISION_MASK		0x0E
+#define SWITCH_REVISION_SHIFT		1
+#define SWITCH_START			0x01
+
+#define CHIP_ID_63			0x30
+
+#define REG_SWITCH_CTRL_0		0x02
+
+#define SWITCH_NEW_BACKOFF		BIT(7)
+#define SWITCH_FLUSH_DYN_MAC_TABLE	BIT(5)
+#define SWITCH_FLUSH_STA_MAC_TABLE	BIT(4)
+#define SWITCH_PASS_PAUSE		BIT(3)
+#define SWITCH_LINK_AUTO_AGING		BIT(0)
+
+#define REG_SWITCH_CTRL_1		0x03
+
+#define SWITCH_PASS_ALL			BIT(7)
+#define SWITCH_TAIL_TAG_ENABLE		BIT(6)
+#define SWITCH_TX_FLOW_CTRL		BIT(5)
+#define SWITCH_RX_FLOW_CTRL		BIT(4)
+#define SWITCH_CHECK_LENGTH		BIT(3)
+#define SWITCH_AGING_ENABLE		BIT(2)
+#define SWITCH_FAST_AGING		BIT(1)
+#define SWITCH_AGGR_BACKOFF		BIT(0)
+
+#define REG_SWITCH_CTRL_2		0x04
+
+#define UNICAST_VLAN_BOUNDARY		BIT(7)
+#define MULTICAST_STORM_DISABLE		BIT(6)
+#define SWITCH_BACK_PRESSURE		BIT(5)
+#define FAIR_FLOW_CTRL			BIT(4)
+#define NO_EXC_COLLISION_DROP		BIT(3)
+#define SWITCH_HUGE_PACKET		BIT(2)
+#define SWITCH_LEGAL_PACKET		BIT(1)
+
+#define REG_SWITCH_CTRL_3		0x05
+
+#define SWITCH_VLAN_ENABLE		BIT(7)
+#define SWITCH_IGMP_SNOOP		BIT(6)
+#define WEIGHTED_FAIR_QUEUE_ENABLE	BIT(3)
+#define SWITCH_MIRROR_RX_TX		BIT(0)
+
+#define REG_SWITCH_CTRL_4		0x06
+
+#define SWITCH_HALF_DUPLEX		BIT(6)
+#define SWITCH_FLOW_CTRL		BIT(5)
+#define SWITCH_10_MBIT			BIT(4)
+#define SWITCH_REPLACE_VID		BIT(3)
+#define BROADCAST_STORM_RATE_HI		0x07
+
+#define REG_SWITCH_CTRL_5		0x07
+
+#define BROADCAST_STORM_RATE_LO		0xFF
+#define BROADCAST_STORM_RATE		0x07FF
+
+#define REG_SWITCH_CTRL_9		0x0B
+
+#define SPI_CLK_125_MHZ			0x80
+#define SPI_CLK_62_5_MHZ		0x40
+#define SPI_CLK_31_25_MHZ		0x00
+
+#define REG_SWITCH_CTRL_10		0x0C
+#define REG_SWITCH_CTRL_11		0x0D
+
+#define SWITCH_802_1P_MASK		3
+#define SWITCH_802_1P_BASE		3
+#define SWITCH_802_1P_SHIFT		2
+
+#define SWITCH_802_1P_MAP_MASK		3
+#define SWITCH_802_1P_MAP_SHIFT		2
+
+#define REG_SWITCH_CTRL_12		0x0E
+
+#define SWITCH_UNKNOWN_DA_ENABLE	BIT(7)
+#define SWITCH_DRIVER_16MA		BIT(6)
+#define SWITCH_UNKNOWN_DA_2_PORT3	BIT(2)
+#define SWITCH_UNKNOWN_DA_2_PORT2	BIT(1)
+#define SWITCH_UNKNOWN_DA_2_PORT1	BIT(0)
+
+#define REG_SWITCH_CTRL_13		0x0F
+
+#define SWITCH_PORT_PHY_ADDR_MASK	0x1F
+#define SWITCH_PORT_PHY_ADDR_SHIFT	3
+
+#define REG_PORT_1_CTRL_0		0x10
+#define REG_PORT_2_CTRL_0		0x20
+#define REG_PORT_3_CTRL_0		0x30
+
+#define PORT_BROADCAST_STORM		BIT(7)
+#define PORT_DIFFSERV_ENABLE		BIT(6)
+#define PORT_802_1P_ENABLE		BIT(5)
+#define PORT_BASED_PRIORITY_MASK	0x18
+#define PORT_BASED_PRIORITY_BASE	0x03
+#define PORT_BASED_PRIORITY_SHIFT	3
+#define PORT_PORT_PRIO_0		0x00
+#define PORT_PORT_PRIO_1		0x08
+#define PORT_PORT_PRIO_2		0x10
+#define PORT_PORT_PRIO_3		0x18
+#define PORT_INSERT_TAG			BIT(2)
+#define PORT_REMOVE_TAG			BIT(1)
+#define PORT_4_QUEUES_ENABLE		BIT(0)
+
+#define REG_PORT_1_CTRL_1		0x11
+#define REG_PORT_2_CTRL_1		0x21
+#define REG_PORT_3_CTRL_1		0x31
+
+#define PORT_MIRROR_SNIFFER		BIT(7)
+#define PORT_MIRROR_RX			BIT(6)
+#define PORT_MIRROR_TX			BIT(5)
+#define PORT_DOUBLE_TAG			BIT(4)
+#define PORT_802_1P_REMAPPING		BIT(3)
+#define PORT_VLAN_MEMBERSHIP		0x07
+
+#define REG_PORT_1_CTRL_2		0x12
+#define REG_PORT_2_CTRL_2		0x22
+#define REG_PORT_3_CTRL_2		0x32
+
+#define PORT_2_QUEUES_ENABLE		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 PORT_TX_ENABLE			BIT(2)
+#define PORT_RX_ENABLE			BIT(1)
+#define PORT_LEARN_DISABLE		BIT(0)
+
+#define REG_PORT_1_CTRL_3		0x13
+#define REG_PORT_2_CTRL_3		0x23
+#define REG_PORT_3_CTRL_3		0x33
+#define REG_PORT_1_CTRL_4		0x14
+#define REG_PORT_2_CTRL_4		0x24
+#define REG_PORT_3_CTRL_4		0x34
+
+#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 PORT_3_MII_MAC_MODE		BIT(7)
+#define PORT_SA_MAC2			BIT(6)
+#define PORT_SA_MAC1			BIT(5)
+#define PORT_DROP_TAG			BIT(4)
+#define PORT_INGRESS_LIMIT_MODE		0x0C
+#define PORT_INGRESS_ALL		0x00
+#define PORT_INGRESS_UNICAST		0x04
+#define PORT_INGRESS_MULTICAST		0x08
+#define PORT_INGRESS_BROADCAST		0x0C
+#define PORT_COUNT_IFG			BIT(1)
+#define PORT_COUNT_PREAMBLE		BIT(0)
+
+#define REG_PORT_1_IN_RATE_0		0x16
+#define REG_PORT_2_IN_RATE_0		0x26
+#define REG_PORT_3_IN_RATE_0		0x36
+
+#define PORT_3_INVERTED_REFCLK		BIT(7)
+
+#define REG_PORT_1_IN_RATE_1		0x17
+#define REG_PORT_2_IN_RATE_1		0x27
+#define REG_PORT_3_IN_RATE_1		0x37
+#define REG_PORT_1_IN_RATE_2		0x18
+#define REG_PORT_2_IN_RATE_2		0x28
+#define REG_PORT_3_IN_RATE_2		0x38
+#define REG_PORT_1_IN_RATE_3		0x19
+#define REG_PORT_2_IN_RATE_3		0x29
+#define REG_PORT_3_IN_RATE_3		0x39
+
+#define PORT_PRIO_RATE			0x0F
+#define PORT_PRIO_RATE_SHIFT		4
+
+#define REG_PORT_1_LINK_MD_CTRL		0x1A
+#define REG_PORT_2_LINK_MD_CTRL		0x2A
+
+#define PORT_CABLE_10M_SHORT		BIT(7)
+#define PORT_CABLE_DIAG_RESULT		0x60
+#define PORT_CABLE_STAT_NORMAL		0x00
+#define PORT_CABLE_STAT_OPEN		0x20
+#define PORT_CABLE_STAT_SHORT		0x40
+#define PORT_CABLE_STAT_FAILED		0x60
+#define PORT_START_CABLE_DIAG		BIT(4)
+#define PORT_FORCE_LINK			BIT(3)
+#define PORT_POWER_SAVING		0x04
+#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 PORT_CABLE_FAULT_COUNTER_L	0xFF
+#define PORT_CABLE_FAULT_COUNTER	0x1FF
+
+#define REG_PORT_1_CTRL_12		0x1C
+#define REG_PORT_2_CTRL_12		0x2C
+
+#define PORT_AUTO_NEG_ENABLE		BIT(7)
+#define PORT_FORCE_100_MBIT		BIT(6)
+#define PORT_FORCE_FULL_DUPLEX		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_CTRL_13		0x1D
+#define REG_PORT_2_CTRL_13		0x2D
+
+#define PORT_LED_OFF			BIT(7)
+#define PORT_TX_DISABLE			BIT(6)
+#define PORT_AUTO_NEG_RESTART		BIT(5)
+#define PORT_REMOTE_FAULT_DISABLE	BIT(4)
+#define PORT_POWER_DOWN			BIT(3)
+#define PORT_AUTO_MDIX_DISABLE		BIT(2)
+#define PORT_FORCE_MDIX			BIT(1)
+#define PORT_LOOPBACK			BIT(0)
+
+#define REG_PORT_1_STATUS_0		0x1E
+#define REG_PORT_2_STATUS_0		0x2E
+
+#define PORT_MDIX_STATUS		BIT(7)
+#define PORT_AUTO_NEG_COMPLETE		BIT(6)
+#define PORT_STATUS_LINK_GOOD		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		0x1F
+#define REG_PORT_2_STATUS_1		0x2F
+#define REG_PORT_3_STATUS_1		0x3F
+
+#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_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_IN_RATE_0		0x06
+#define REG_PORT_IN_RATE_1		0x07
+#define REG_PORT_IN_RATE_2		0x08
+#define REG_PORT_IN_RATE_3		0x09
+#define REG_PORT_LINK_MD_CTRL		0x0A
+#define REG_PORT_LINK_MD_RESULT		0x0B
+#define REG_PORT_CTRL_12		0x0C
+#define REG_PORT_CTRL_13		0x0D
+#define REG_PORT_STATUS_0		0x0E
+#define REG_PORT_STATUS_1		0x0F
+
+#define PORT_CTRL_ADDR(port, addr)		\
+	(addr = REG_PORT_1_CTRL_0 + (port) *	\
+		(REG_PORT_2_CTRL_0 - REG_PORT_1_CTRL_0))
+
+#define REG_SWITCH_RESET		0x43
+
+#define GLOBAL_SOFTWARE_RESET		BIT(4)
+#define PCS_RESET			BIT(0)
+
+#define REG_TOS_PRIO_CTRL_0		0x60
+#define REG_TOS_PRIO_CTRL_1		0x61
+#define REG_TOS_PRIO_CTRL_2		0x62
+#define REG_TOS_PRIO_CTRL_3		0x63
+#define REG_TOS_PRIO_CTRL_4		0x64
+#define REG_TOS_PRIO_CTRL_5		0x65
+#define REG_TOS_PRIO_CTRL_6		0x66
+#define REG_TOS_PRIO_CTRL_7		0x67
+#define REG_TOS_PRIO_CTRL_8		0x68
+#define REG_TOS_PRIO_CTRL_9		0x69
+#define REG_TOS_PRIO_CTRL_10		0x6A
+#define REG_TOS_PRIO_CTRL_11		0x6B
+#define REG_TOS_PRIO_CTRL_12		0x6C
+#define REG_TOS_PRIO_CTRL_13		0x6D
+#define REG_TOS_PRIO_CTRL_14		0x6E
+#define REG_TOS_PRIO_CTRL_15		0x6F
+
+#define TOS_PRIO_M			3
+#define TOS_PRIO_S			2
+
+#define REG_SWITCH_MAC_ADDR_0		0x70
+#define REG_SWITCH_MAC_ADDR_1		0x71
+#define REG_SWITCH_MAC_ADDR_2		0x72
+#define REG_SWITCH_MAC_ADDR_3		0x73
+#define REG_SWITCH_MAC_ADDR_4		0x74
+#define REG_SWITCH_MAC_ADDR_5		0x75
+
+#define REG_USER_DEFINED_1		0x76
+#define REG_USER_DEFINED_2		0x77
+#define REG_USER_DEFINED_3		0x78
+
+#define REG_IND_CTRL_0			0x79
+
+#define TABLE_READ			BIT(4)
+#define TABLE_STATIC_MAC		BIT(2)
+#define TABLE_VLAN			BIT(2)
+#define TABLE_DYNAMIC_MAC		BIT(2)
+#define TABLE_MIB			BIT(2)
+
+#define REG_IND_CTRL_1			0x7A
+
+#define TABLE_ENTRY_MASK		0x03FF
+
+#define REG_IND_DATA_8			0x7B
+#define REG_IND_DATA_7			0x7C
+#define REG_IND_DATA_6			0x7D
+#define REG_IND_DATA_5			0x7E
+#define REG_IND_DATA_4			0x7F
+#define REG_IND_DATA_3			0x80
+#define REG_IND_DATA_2			0x81
+#define REG_IND_DATA_1			0x82
+#define REG_IND_DATA_0			0x83
+
+#define REG_IND_DATA_CHECK		REG_IND_DATA_8
+#define REG_IND_MIB_CHECK		REG_IND_DATA_3
+#define REG_IND_DATA_HI			REG_IND_DATA_7
+#define REG_IND_DATA_LO			REG_IND_DATA_3
+
+#define REG_PORT_0_MAC_ADDR_0		0x8E
+#define REG_PORT_0_MAC_ADDR_1		0x8F
+#define REG_PORT_0_MAC_ADDR_2		0x90
+#define REG_PORT_0_MAC_ADDR_3		0x91
+#define REG_PORT_0_MAC_ADDR_4		0x92
+#define REG_PORT_0_MAC_ADDR_5		0x93
+#define REG_PORT_1_MAC_ADDR_0		0x94
+#define REG_PORT_1_MAC_ADDR_1		0x95
+#define REG_PORT_1_MAC_ADDR_2		0x96
+#define REG_PORT_1_MAC_ADDR_3		0x97
+#define REG_PORT_1_MAC_ADDR_4		0x98
+#define REG_PORT_1_MAC_ADDR_5		0x99
+
+#define REG_PORT_1_OUT_RATE_0		0x9A
+#define REG_PORT_2_OUT_RATE_0		0x9E
+#define REG_PORT_3_OUT_RATE_0		0xA2
+
+#define SWITCH_OUT_RATE_ENABLE		BIT(7)
+
+#define REG_PORT_1_OUT_RATE_1		0x9B
+#define REG_PORT_2_OUT_RATE_1		0x9F
+#define REG_PORT_3_OUT_RATE_1		0xA3
+#define REG_PORT_1_OUT_RATE_2		0x9C
+#define REG_PORT_2_OUT_RATE_2		0xA0
+#define REG_PORT_3_OUT_RATE_2		0xA4
+#define REG_PORT_1_OUT_RATE_3		0x9D
+#define REG_PORT_2_OUT_RATE_3		0xA1
+#define REG_PORT_3_OUT_RATE_3		0xA5
+
+#define REG_PORT_OUT_RATE_0		0x00
+#define REG_PORT_OUT_RATE_1		0x01
+#define REG_PORT_OUT_RATE_2		0x02
+#define REG_PORT_OUT_RATE_3		0x03
+
+#define REG_MODE_INDICATOR		0xA6
+
+#define MODE_2_MII			BIT(7)
+#define MODE_2_PHY			BIT(6)
+#define PORT_1_RMII			BIT(5)
+#define PORT_3_RMII			BIT(4)
+#define PORT_1_MAC_MII			BIT(3)
+#define PORT_3_MAC_MII			BIT(2)
+#define PORT_1_FIBER			BIT(1)
+#define PORT_2_FIBER			BIT(0)
+
+#define MODE_MLL			0x03
+#define MODE_RLL			0x13
+#define MODE_FLL			0x01
+
+#define REG_BUF_RESERVED_Q3		0xA7
+#define REG_BUF_RESERVED_Q2		0xA8
+#define REG_BUF_RESERVED_Q1		0xA9
+#define REG_BUF_RESERVED_Q0		0xAA
+#define REG_PM_FLOW_CTRL_SELECT_1	0xAB
+#define REG_PM_FLOW_CTRL_SELECT_2	0xAC
+#define REG_PM_FLOW_CTRL_SELECT_3	0xAD
+#define REG_PM_FLOW_CTRL_SELECT_4	0xAE
+
+#define REG_PORT1_TXQ3_RATE_CTRL	0xAF
+#define REG_PORT1_TXQ2_RATE_CTRL	0xB0
+#define REG_PORT1_TXQ1_RATE_CTRL	0xB1
+#define REG_PORT1_TXQ0_RATE_CTRL	0xB2
+#define REG_PORT2_TXQ3_RATE_CTRL	0xB3
+#define REG_PORT2_TXQ2_RATE_CTRL	0xB4
+#define REG_PORT2_TXQ1_RATE_CTRL	0xB5
+#define REG_PORT2_TXQ0_RATE_CTRL	0xB6
+#define REG_PORT3_TXQ3_RATE_CTRL	0xB7
+#define REG_PORT3_TXQ2_RATE_CTRL	0xB8
+#define REG_PORT3_TXQ1_RATE_CTRL	0xB9
+#define REG_PORT3_TXQ0_RATE_CTRL	0xBA
+
+#define RATE_CTRL_ENABLE		BIT(7)
+
+#define REG_INT_ENABLE			0xBB
+
+#define REG_INT_STATUS			0xBC
+
+#define INT_PORT_1_2_LINK_CHANGE	BIT(7)
+#define INT_PORT_3_LINK_CHANGE		BIT(2)
+#define INT_PORT_2_LINK_CHANGE		BIT(1)
+#define INT_PORT_1_LINK_CHANGE		BIT(0)
+
+#define REG_PAUSE_ITERATION_LIMIT	0xBD
+
+#define REG_INSERT_SRC_PVID		0xC2
+
+#define SWITCH_INS_TAG_1_PORT_2		BIT(5)
+#define SWITCH_INS_TAG_1_PORT_3		BIT(4)
+#define SWITCH_INS_TAG_2_PORT_1		BIT(3)
+#define SWITCH_INS_TAG_2_PORT_3		BIT(2)
+#define SWITCH_INS_TAG_3_PORT_1		BIT(1)
+#define SWITCH_INS_TAG_3_PORT_2		BIT(0)
+
+#define REG_POWER_MANAGEMENT		0xC3
+
+#define SWITCH_CPU_CLK_POWER_DOWN	BIT(7)
+#define SWITCH_CLK_POWER_DOWN		BIT(6)
+#define SWITCH_LED_SELECTION		0x30
+#define SWITCH_LED_LINK_ACT_SPEED	0x00
+#define SWITCH_LED_LINK_ACT		0x20
+#define SWITCH_LED_LINK_ACT_DUPLEX	0x10
+#define SWITCH_LED_LINK_DUPLEX		0x30
+#define SWITCH_LED_OUTPUT_MODE		BIT(3)
+#define SWITCH_PLL_POWER_DOWN		BIT(2)
+#define SWITCH_POWER_MANAGEMENT_MODE	0x03
+#define SWITCH_NORMAL			0x00
+#define SWITCH_ENERGY_DETECTION		0x01
+#define SWITCH_SOFTWARE_POWER_DOWN	0x02
+#define SWITCH_POWER_SAVING		0x03
+
+#define REG_FORWARD_INVALID_VID		0xC6
+
+#define SWITCH_FORWARD_INVALID_PORTS	0x70
+#define FORWARD_INVALID_PORT_SHIFT	4
+#define PORT_3_RMII_CLOCK_SELECTION	BIT(3)
+#define PORT_1_RMII_CLOCK_SELECTION	BIT(2)
+#define SWITCH_HOST_INTERFACE_MODE	0x03
+#define SWITCH_I2C_MASTER		0x00
+#define SWITCH_I2C_SLAVE		0x01
+#define SWITCH_SPI_SLAVE		0x02
+#define SWITCH_SMII			0x03
+
+#define KSZ8863_ID_HI			0x0022
+#define KSZ8863_ID_LO			0x1430
+
+#define PHY_REG_LINK_MD			29
+
+#define PHY_START_CABLE_DIAG		BIT(15)
+#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		0x01FF
+
+#define PHY_REG_PHY_CTRL		30
+
+#define PHY_STAT_REVERSED_POLARITY	BIT(5)
+#define PHY_STAT_MDIX			BIT(4)
+#define PHY_FORCE_LINK			BIT(3)
+#define PHY_POWER_SAVING_DISABLE	BIT(2)
+#define PHY_REMOTE_LOOPBACK		BIT(1)
+
+/* Default values are used in ksz_sw.h if these are not defined. */
+#define PRIO_QUEUES			4
+
+#define KS_PRIO_IN_REG			4
+
+#define TOTAL_PORT_NUM			3
+
+/* Host port can only be last of them. */
+#define SWITCH_PORT_NUM			(TOTAL_PORT_NUM - 1)
+
+#define KSZ8863_COUNTER_NUM		0x20
+#define TOTAL_KSZ8863_COUNTER_NUM	(KSZ8863_COUNTER_NUM + 2)
+
+#define SWITCH_COUNTER_NUM		KSZ8863_COUNTER_NUM
+#define TOTAL_SWITCH_COUNTER_NUM	TOTAL_KSZ8863_COUNTER_NUM
+
+#define P_802_1P_CTRL			REG_PORT_CTRL_2
+#define P_LOCAL_CTRL			REG_PORT_CTRL_5
+#define P_REMOTE_STATUS			REG_PORT_STATUS_1
+#define P_INS_SRC_PVID_CTRL		REG_PORT_CTRL_8
+#define P_DROP_TAG_CTRL			REG_PORT_CTRL_9
+
+#define S_HUGE_PACKET_CTRL		REG_SW_CTRL_2
+#define S_PASS_PAUSE_CTRL		REG_SW_CTRL_10
+#define S_IPV6_MLD_CTRL			REG_SW_CTRL_21
+
+#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_STP_CTRL			REG_PORT_CTRL_2
+#define P_PHY_CTRL			REG_PORT_CTRL_12
+#define P_FORCE_CTRL			REG_PORT_CTRL_12
+#define P_NEG_RESTART_CTRL		REG_PORT_CTRL_13
+#define P_LINK_STATUS			REG_PORT_STATUS_0
+#define P_SPEED_STATUS			REG_PORT_STATUS_1
+#define P_RATE_LIMIT_CTRL		REG_PORT_CTRL_5
+#define P_SA_MAC_CTRL			REG_PORT_CTRL_5
+#define P_4_QUEUE_CTRL			REG_PORT_CTRL_0
+#define P_2_QUEUE_CTRL			REG_PORT_CTRL_2
+
+#define S_LINK_AGING_CTRL		REG_SWITCH_CTRL_0
+#define S_MIRROR_CTRL			REG_SWITCH_CTRL_3
+#define S_REPLACE_VID_CTRL		REG_SWITCH_CTRL_4
+#define S_802_1P_PRIO_CTRL		REG_SWITCH_CTRL_10
+#define S_UNKNOWN_DA_CTRL		REG_SWITCH_CTRL_12
+#define S_TOS_PRIO_CTRL			REG_TOS_PRIO_CTRL_0
+#define S_FLUSH_TABLE_CTRL		REG_SWITCH_CTRL_0
+#define S_TAIL_TAG_CTRL			REG_SWITCH_CTRL_1
+#define S_FORWARD_INVALID_VID_CTRL	REG_FORWARD_INVALID_VID
+#define S_INS_SRC_PVID_CTRL		REG_INSERT_SRC_PVID
+
+#define IND_ACC_TABLE(table)		((table) << 8)
+
+/* Driver set switch broadcast storm protection at 10% rate. */
+#define BROADCAST_STORM_PROT_RATE	10
+
+/* 148,800 frames * 67 ms / 100 */
+#define BROADCAST_STORM_VALUE		9969
+
+#define STATIC_MAC_TABLE_ADDR		0x0000FFFF
+#define STATIC_MAC_TABLE_FWD_PORTS	0x001F0000
+#define STATIC_MAC_TABLE_VALID		0x00200000
+#define STATIC_MAC_TABLE_OVERRIDE	0x00400000
+#define STATIC_MAC_TABLE_USE_FID	0x00800000
+#define STATIC_MAC_TABLE_FID		0x7F000000
+
+#define STATIC_MAC_FWD_PORTS_S		16
+#define STATIC_MAC_FID_S		24
+
+#define VLAN_TABLE_FID			0x007F
+#define VLAN_TABLE_MEMBERSHIP		0x0F80
+#define VLAN_TABLE_VALID		0x1000
+
+#define VLAN_TABLE_MEMBERSHIP_S		7
+#define VLAN_TABLE_S			13
+#define VLAN_TABLE_M			(BIT(VLAN_TABLE_S) - 1)
+
+#define DYNAMIC_MAC_TABLE_ADDR		0x0000FFFF
+#define DYNAMIC_MAC_TABLE_FID		0x007F0000
+#define DYNAMIC_MAC_TABLE_SRC_PORT	0x07000000
+#define DYNAMIC_MAC_TABLE_TIMESTAMP	0x18000000
+#define DYNAMIC_MAC_TABLE_ENTRIES	0xE0000000
+
+#define DYNAMIC_MAC_TABLE_NOT_READY	0x80
+
+#define DYNAMIC_MAC_TABLE_ENTRIES_H	0x7F
+#define DYNAMIC_MAC_TABLE_MAC_EMPTY	0x80
+
+#define DYNAMIC_MAC_FID_S		16
+#define DYNAMIC_MAC_SRC_PORT_S		24
+#define DYNAMIC_MAC_TIMESTAMP_S		27
+#define DYNAMIC_MAC_ENTRIES_S		29
+#define DYNAMIC_MAC_ENTRIES_H_S		3
+
+#define MIB_COUNTER_OVERFLOW		BIT(7)
+#define MIB_COUNTER_VALID		BIT(6)
+
+#define MIB_COUNTER_VALUE		0x3FFFFFFF
+
+#define KS_MIB_PACKET_DROPPED_TX_0	0x100
+#define KS_MIB_PACKET_DROPPED_TX_1	0x101
+#define KS_MIB_PACKET_DROPPED_TX_2	0x102
+#define KS_MIB_PACKET_DROPPED_TX_3	0x103
+#define KS_MIB_PACKET_DROPPED_TX_4	0x104
+#define KS_MIB_PACKET_DROPPED_RX_0	0x105
+#define KS_MIB_PACKET_DROPPED_RX_1	0x106
+#define KS_MIB_PACKET_DROPPED_RX_2	0x107
+#define KS_MIB_PACKET_DROPPED_RX_3	0x108
+#define KS_MIB_PACKET_DROPPED_RX_4	0x109
+
+#define MIB_PACKET_DROPPED		0x0000FFFF
+
+#define TAIL_TAG_OVERRIDE		BIT(6)
+#define TAIL_TAG_LOOKUP			BIT(7)
+
+#define VLAN_TABLE_ENTRIES		(16 / 2)
+#define FID_ENTRIES			16
+
+#endif
diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c
new file mode 100644
index 0000000000000..d9fa069ecfa37
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz8863_smi.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip KSZ8863 series register access through SMI
+ *
+ * Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>
+ */
+
+#include "ksz_priv.h"
+#include "ksz_spi.h"
+
+static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data,
+			unsigned int len)
+{
+	int i = 0;
+
+	for (i = 0; i < len; i++)
+		data[i] = (u8)mdiobus_read(dev->bus, 0,
+					    (reg + i) | MII_ADDR_SMI0);
+
+	return 0;
+}
+
+static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data,
+			 unsigned int len)
+{
+	int i = 0;
+	int ret = 0;
+
+	u8 *val = data;
+
+	for (i = 0; i < len; i++) {
+		ret = mdiobus_write(dev->bus, 0,
+				    (reg + i) | MII_ADDR_SMI0, val[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct ksz_io_ops ksz8863_smi_ops = {
+	.read8 = ksz_spi_read8,
+	.read16 = ksz_spi_read16,
+	.read32 = ksz_spi_read32,
+	.write8 = ksz_spi_write8,
+	.write16 = ksz_spi_write16,
+	.write32 = ksz_spi_write32,
+	.get = ksz_spi_get,
+	.set = ksz_spi_set,
+};
+
+static int ksz8863_smi_probe(struct mdio_device *mdiodev)
+{
+	struct ksz_device *dev;
+	int ret;
+
+	dev = ksz_switch_alloc(&mdiodev->dev, &ksz8863_smi_ops, mdiodev);
+	if (!dev)
+		return -EINVAL;
+
+	if (mdiodev->dev.platform_data)
+		dev->pdata = mdiodev->dev.platform_data;
+
+	dev->bus = mdiodev->bus;
+
+	ret = ksz8863_switch_register(dev);
+
+	/* Main DSA driver may not be started yet. */
+	if (ret)
+		return ret;
+
+	dev_set_drvdata(&mdiodev->dev, dev);
+
+	return 0;
+}
+
+static void ksz8863_smi_remove(struct mdio_device *mdiodev)
+{
+	struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev);
+
+	if (dev)
+		ksz_switch_remove(dev);
+}
+
+static const struct of_device_id ksz8863_dt_ids[] = {
+	{ .compatible = "microchip,ksz8863" },
+	{ .compatible = "microchip,ksz8873" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ksz8863_dt_ids);
+
+static struct mdio_driver ksz8863_driver = {
+	.probe	= ksz8863_smi_probe,
+	.remove	= ksz8863_smi_remove,
+	.mdiodrv.driver = {
+		.name	= "ksz8863-switch",
+		.of_match_table = ksz8863_dt_ids,
+	},
+};
+
+mdio_module_driver(ksz8863_driver);
+
+MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>");
+MODULE_DESCRIPTION("Microchip KSZ8863 SMI Switch driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h
index b52e5ca17ab49..4c7c43d694554 100644
--- a/drivers/net/dsa/microchip/ksz_priv.h
+++ b/drivers/net/dsa/microchip/ksz_priv.h
@@ -56,6 +56,8 @@ struct ksz_device {
 	const struct ksz_io_ops *ops;
 	const struct ksz_dev_ops *dev_ops;
 
+	struct mii_bus *bus;
+
 	struct device *dev;
 
 	void *priv;
@@ -167,6 +169,7 @@ int ksz_switch_register(struct ksz_device *dev,
 			const struct ksz_dev_ops *ops);
 void ksz_switch_remove(struct ksz_device *dev);
 
+int ksz8863_switch_register(struct ksz_device *dev);
 int ksz9477_switch_register(struct ksz_device *dev);
 
 #endif
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6aaaadd6a413c..57fbf3e722362 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -44,6 +44,7 @@ struct phylink_link_state;
 #define DSA_TAG_PROTO_TRAILER_VALUE		11
 #define DSA_TAG_PROTO_8021Q_VALUE		12
 #define DSA_TAG_PROTO_SJA1105_VALUE		13
+#define DSA_TAG_PROTO_KSZ8863_VALUE		14
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -60,6 +61,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_TRAILER		= DSA_TAG_PROTO_TRAILER_VALUE,
 	DSA_TAG_PROTO_8021Q		= DSA_TAG_PROTO_8021Q_VALUE,
 	DSA_TAG_PROTO_SJA1105		= DSA_TAG_PROTO_SJA1105_VALUE,
+	DSA_TAG_PROTO_KSZ8863		= DSA_TAG_PROTO_KSZ8863_VALUE,
 };
 
 struct packet_type;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index cf855352a440e..de641a62b814b 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -83,6 +83,13 @@ config NET_DSA_TAG_KSZ
 	  Say Y if you want to enable support for tagging frames for the
 	  Microchip 9893 family of switches.
 
+config NET_DSA_TAG_KSZ8863
+	tristate "Tag driver for Microchip 8863 family of switches"
+	select NET_DSA_TAG_KSZ_COMMON
+	help
+	  Say Y if you want to enable support for tagging frames for the
+	  Microchip 8863 family of switches.
+
 config NET_DSA_TAG_KSZ9477
 	tristate "Tag driver for Microchip 9477 family of switches"
 	select NET_DSA_TAG_KSZ_COMMON
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index b4872b87d4a6b..3ef7c3945f0a4 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -182,9 +182,54 @@ static const struct dsa_device_ops ksz9893_netdev_ops = {
 DSA_TAG_DRIVER(ksz9893_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893);
 
+#define	KSZ8863_INGRESS_TAG_LEN	1
+
+static struct sk_buff *ksz8863_xmit(struct sk_buff *skb,
+				    struct net_device *dev)
+{
+	struct dsa_port *dp = dsa_slave_to_port(dev);
+	struct sk_buff *nskb;
+	u16 *tag;
+
+	nskb = ksz_common_xmit(skb, dev, KSZ8863_INGRESS_TAG_LEN);
+	if (!nskb)
+		return NULL;
+
+	/* Tag encoding */
+	tag = skb_put(nskb, KSZ8863_INGRESS_TAG_LEN);
+
+	*tag = 1 << (dp->index); /* destination port */
+	*tag = cpu_to_be16(*tag);
+
+	return nskb;
+}
+
+static struct sk_buff *ksz8863_rcv(struct sk_buff *skb, struct net_device *dev,
+				   struct packet_type *pt)
+{
+	/* Tag decoding */
+	u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
+	unsigned int port = tag[0] & 1;
+	unsigned int len = KSZ_EGRESS_TAG_LEN;
+
+	return ksz_common_rcv(skb, dev, port, len);
+}
+
+static const struct dsa_device_ops ksz8863_netdev_ops = {
+	.name	= "ksz8863",
+	.proto	= DSA_TAG_PROTO_KSZ8863,
+	.xmit	= ksz8863_xmit,
+	.rcv	= ksz8863_rcv,
+	.overhead = KSZ8863_INGRESS_TAG_LEN,
+};
+
+DSA_TAG_DRIVER(ksz8863_netdev_ops);
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8863);
+
 static struct dsa_tag_driver *dsa_tag_driver_array[] = {
 	&DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops),
 	&DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops),
+	&DSA_TAG_DRIVER_NAME(ksz8863_netdev_ops),
 };
 
 module_dsa_tag_drivers(dsa_tag_driver_array);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [RFC 3/3] dt-bindings: net: dsa: document additional Microchip KSZ8863 family switches
  2019-05-08 21:13 [RFC 0/3] microchip: add support for ksz8863 driver family Michael Grzeschik
  2019-05-08 21:13 ` [RFC 1/3] mdio-bitbang: add SMI0 mode support Michael Grzeschik
  2019-05-08 21:13 ` [RFC 2/3] ksz: Add Microchip KSZ8873 SMI-DSA driver Michael Grzeschik
@ 2019-05-08 21:13 ` Michael Grzeschik
  2019-06-13 20:09   ` Rob Herring
  2 siblings, 1 reply; 10+ messages in thread
From: Michael Grzeschik @ 2019-05-08 21:13 UTC (permalink / raw)
  To: Tristram.Ha; +Cc: kernel, UNGLinuxDriver, netdev, devicetree

Document additional Microchip KSZ8863 family switches.

Show how KSZ8863 switch should be configured as the host port is port 3.

Cc: devicetree@vger.kernel.org
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
---
 .../devicetree/bindings/net/dsa/ksz.txt       | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt
index e7db7268fd0fd..4ac576e1cc34e 100644
--- a/Documentation/devicetree/bindings/net/dsa/ksz.txt
+++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt
@@ -5,6 +5,8 @@ Required properties:
 
 - compatible: For external switch chips, compatible string must be exactly one
   of the following:
+  - "microchip,ksz8863"
+  - "microchip,ksz8873"
   - "microchip,ksz9477"
   - "microchip,ksz9897"
   - "microchip,ksz9896"
@@ -31,6 +33,48 @@ Ethernet switch connected via SPI to the host, CPU port wired to eth0:
 		};
 	};
 
+	mdio0: mdio-gpio {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mdio_1>;
+		compatible = "virtual,mdio-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&gpio1 31 0 &gpio1 22 0>;
+
+		ksz8863@3 {
+			compatible = "microchip,ksz8863";
+			interrupt-parrent = <&gpio3>;
+			interrupt = <30 IRQ_TYPE_LEVEL_HIGH>;
+			reg = <0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				ports@0 {
+					reg = <0>;
+					label = "lan1";
+				};
+
+				ports@1 {
+					reg = <1>;
+					label = "lan2";
+				};
+
+				ports@2 {
+					reg = <2>;
+					label = "cpu";
+					ethernet = <&eth0>;
+
+					fixed-link {
+						speed = <100>;
+						full-duplex;
+					};
+				};
+			};
+		};
+	};
+
 	spi1: spi@f8008000 {
 		pinctrl-0 = <&pinctrl_spi_ksz>;
 		cs-gpios = <&pioC 25 0>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC 1/3] mdio-bitbang: add SMI0 mode support
  2019-05-08 21:13 ` [RFC 1/3] mdio-bitbang: add SMI0 mode support Michael Grzeschik
@ 2019-05-09 14:29   ` Andrew Lunn
  2019-05-10  7:32     ` Michael Grzeschik
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Lunn @ 2019-05-09 14:29 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: Tristram.Ha, kernel, UNGLinuxDriver, netdev

On Wed, May 08, 2019 at 11:13:28PM +0200, Michael Grzeschik wrote:
> Some microchip phys support the Serial Management Interface Protocol
> (SMI) for the configuration of the extended register set. We add
> MII_ADDR_SMI0 as an availabe interface to the mdiobb write and read
> functions, as this interface can be easy realized using the bitbang mdio
> driver.
> 
> Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> ---
>  drivers/net/phy/mdio-bitbang.c | 10 ++++++++++
>  include/linux/phy.h            | 12 ++++++++++++
>  2 files changed, 22 insertions(+)
> 
> diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
> index 5136275c8e739..a978f8a9a172b 100644
> --- a/drivers/net/phy/mdio-bitbang.c
> +++ b/drivers/net/phy/mdio-bitbang.c
> @@ -22,6 +22,10 @@
>  #define MDIO_READ 2
>  #define MDIO_WRITE 1
>  
> +#define SMI0_RW_OPCODE	0
> +#define SMI0_READ_PHY	(1 << 4)
> +#define SMI0_WRITE_PHY	(0 << 4)
> +
>  #define MDIO_C45 (1<<15)
>  #define MDIO_C45_ADDR (MDIO_C45 | 0)
>  #define MDIO_C45_READ (MDIO_C45 | 3)
> @@ -157,6 +161,9 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
>  	if (reg & MII_ADDR_C45) {
>  		reg = mdiobb_cmd_addr(ctrl, phy, reg);
>  		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
> +	} else if (reg & MII_ADDR_SMI0) {
> +		mdiobb_cmd(ctrl, SMI0_RW_OPCODE,
> +			   (reg & 0xE0) >> 5 | SMI0_READ_PHY, reg);
>  	} else
>  		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
>  
> @@ -188,6 +195,9 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
>  	if (reg & MII_ADDR_C45) {
>  		reg = mdiobb_cmd_addr(ctrl, phy, reg);
>  		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
> +	} else if (reg & MII_ADDR_SMI0) {
> +		mdiobb_cmd(ctrl, SMI0_RW_OPCODE,
> +			   (reg & 0xE0) >> 5 | SMI0_WRITE_PHY, reg);
>  	} else
>  		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
>  
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index 073fb151b5a99..f011722fbd5c2 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -199,6 +199,18 @@ static inline const char *phy_modes(phy_interface_t interface)
>     IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
>  #define MII_ADDR_C45 (1<<30)
>  
> +/* Serial Management Interface (SMI) uses the following frame format:
> + *
> + *       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
> + *               |frame| OP code  |address |address|  |                  |
> + * read | 32x1´s | 01  |    00    | 1xRRR  | RRRRR |Z0| 00000000DDDDDDDD |  Z
> + * write| 32x1´s | 01  |    00    | 0xRRR  | RRRRR |10| xxxxxxxxDDDDDDDD |  Z
> + *
> + * The register number is encoded with the 5 least significant bits in REG
> + * and the 3 most significant bits in PHY
> + */
> +#define MII_ADDR_SMI0 (1<<31)
> +

Michael

This is a Micrel Proprietary protocol. So we should reflect this in
the name. MII_ADDR_MICREL_SMI? Why the 0? Are there different
versions? Maybe replace all SMI0 with MICREL_SMI in mdio-bitbang.c

When i look at this, i don't see how a normal MDIO bus driver is going
to support this. Only the bit banging driver, or maybe a Micrel MDIO
bus master hardware driver. So i think the diagram should be placed
into mdio-bitbang.c, and it would be nice to add a diagram of standard
SMI.

	Andrew

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC 2/3] ksz: Add Microchip KSZ8873 SMI-DSA driver
  2019-05-08 21:13 ` [RFC 2/3] ksz: Add Microchip KSZ8873 SMI-DSA driver Michael Grzeschik
@ 2019-05-09 14:48   ` Andrew Lunn
  2019-05-10  7:37     ` Michael Grzeschik
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Lunn @ 2019-05-09 14:48 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: Tristram.Ha, kernel, UNGLinuxDriver, netdev

On Wed, May 08, 2019 at 11:13:29PM +0200, Michael Grzeschik wrote:
> Cc: Tristram.Ha@microchip.com
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> ---
>  drivers/net/dsa/microchip/Kconfig       |   16 +
>  drivers/net/dsa/microchip/Makefile      |    2 +
>  drivers/net/dsa/microchip/ksz8863.c     | 1026 +++++++++++++++++++++++
>  drivers/net/dsa/microchip/ksz8863_reg.h |  605 +++++++++++++
>  drivers/net/dsa/microchip/ksz8863_smi.c |  105 +++
>  drivers/net/dsa/microchip/ksz_priv.h    |    3 +
>  include/net/dsa.h                       |    2 +
>  net/dsa/Kconfig                         |    7 +
>  net/dsa/tag_ksz.c                       |   45 +
>  9 files changed, 1811 insertions(+)
>  create mode 100644 drivers/net/dsa/microchip/ksz8863.c
>  create mode 100644 drivers/net/dsa/microchip/ksz8863_reg.h
>  create mode 100644 drivers/net/dsa/microchip/ksz8863_smi.c
> 
> diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
> index bea29fde9f3d1..a6fa6ae972951 100644
> --- a/drivers/net/dsa/microchip/Kconfig
> +++ b/drivers/net/dsa/microchip/Kconfig
> @@ -14,3 +14,19 @@ config NET_DSA_MICROCHIP_KSZ9477_SPI
>  	depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
>  	help
>  	  Select to enable support for registering switches configured through SPI.
> +
> +menuconfig NET_DSA_MICROCHIP_KSZ8863
> +	tristate "Microchip KSZ8863 series switch support"
> +	depends on NET_DSA
> +	select NET_DSA_TAG_KSZ8863
> +	select NET_DSA_MICROCHIP_KSZ_COMMON
> +	help
> +	  This driver adds support for Microchip KSZ8863 switch chips.
> +
> +config NET_DSA_MICROCHIP_KSZ8863_SMI

> +	tristate "KSZ series SMI connected switch driver"
> +	depends on NET_DSA_MICROCHIP_KSZ8863
> +	default y
> +	help
> +	  Select to enable support for registering switches configured through SMI.

SMI is a synonym for MDIO. So we should make it clear, this is a
proprietary version. "... through Microchip SMI".

You might also want to either depend on or select mdio-bitbang, since
that is the other driver which supports Microchip SMI.

> +static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data,
> +			unsigned int len)
> +{
> +	int i = 0;
> +
> +	for (i = 0; i < len; i++)
> +		data[i] = (u8)mdiobus_read(dev->bus, 0,
> +					    (reg + i) | MII_ADDR_SMI0);

mdiobus_read() and mdiobus_write() can return an error, which is why
is returns an int. Please check for the error and return it.

> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index 6aaaadd6a413c..57fbf3e722362 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -44,6 +44,7 @@ struct phylink_link_state;
>  #define DSA_TAG_PROTO_TRAILER_VALUE		11
>  #define DSA_TAG_PROTO_8021Q_VALUE		12
>  #define DSA_TAG_PROTO_SJA1105_VALUE		13
> +#define DSA_TAG_PROTO_KSZ8863_VALUE		14
>  
>  enum dsa_tag_protocol {
>  	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
> @@ -60,6 +61,7 @@ enum dsa_tag_protocol {
>  	DSA_TAG_PROTO_TRAILER		= DSA_TAG_PROTO_TRAILER_VALUE,
>  	DSA_TAG_PROTO_8021Q		= DSA_TAG_PROTO_8021Q_VALUE,
>  	DSA_TAG_PROTO_SJA1105		= DSA_TAG_PROTO_SJA1105_VALUE,
> +	DSA_TAG_PROTO_KSZ8863		= DSA_TAG_PROTO_KSZ8863_VALUE,
>  };

Please put all the tag driver changes into a separate patch.

> +static struct sk_buff *ksz8863_rcv(struct sk_buff *skb, struct net_device *dev,
> +				   struct packet_type *pt)
> +{
> +	/* Tag decoding */
> +	u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
> +	unsigned int port = tag[0] & 1;

Does this device only have 2 ports, 0 and 1?

> +	unsigned int len = KSZ_EGRESS_TAG_LEN;
> +
> +	return ksz_common_rcv(skb, dev, port, len);
> +}

  Andrew

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC 1/3] mdio-bitbang: add SMI0 mode support
  2019-05-09 14:29   ` Andrew Lunn
@ 2019-05-10  7:32     ` Michael Grzeschik
  2019-05-10 12:36       ` Andrew Lunn
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Grzeschik @ 2019-05-10  7:32 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: Tristram.Ha, kernel, UNGLinuxDriver, netdev

[-- Attachment #1: Type: text/plain, Size: 4808 bytes --]

On Thu, May 09, 2019 at 04:29:25PM +0200, Andrew Lunn wrote:
> On Wed, May 08, 2019 at 11:13:28PM +0200, Michael Grzeschik wrote:
> > Some microchip phys support the Serial Management Interface Protocol
> > (SMI) for the configuration of the extended register set. We add
> > MII_ADDR_SMI0 as an availabe interface to the mdiobb write and read
> > functions, as this interface can be easy realized using the bitbang mdio
> > driver.
> > 
> > Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
> > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> > ---
> >  drivers/net/phy/mdio-bitbang.c | 10 ++++++++++
> >  include/linux/phy.h            | 12 ++++++++++++
> >  2 files changed, 22 insertions(+)
> > 
> > diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
> > index 5136275c8e739..a978f8a9a172b 100644
> > --- a/drivers/net/phy/mdio-bitbang.c
> > +++ b/drivers/net/phy/mdio-bitbang.c
> > @@ -22,6 +22,10 @@
> >  #define MDIO_READ 2
> >  #define MDIO_WRITE 1
> >  
> > +#define SMI0_RW_OPCODE	0
> > +#define SMI0_READ_PHY	(1 << 4)
> > +#define SMI0_WRITE_PHY	(0 << 4)
> > +
> >  #define MDIO_C45 (1<<15)
> >  #define MDIO_C45_ADDR (MDIO_C45 | 0)
> >  #define MDIO_C45_READ (MDIO_C45 | 3)
> > @@ -157,6 +161,9 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
> >  	if (reg & MII_ADDR_C45) {
> >  		reg = mdiobb_cmd_addr(ctrl, phy, reg);
> >  		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
> > +	} else if (reg & MII_ADDR_SMI0) {
> > +		mdiobb_cmd(ctrl, SMI0_RW_OPCODE,
> > +			   (reg & 0xE0) >> 5 | SMI0_READ_PHY, reg);
> >  	} else
> >  		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
> >  
> > @@ -188,6 +195,9 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
> >  	if (reg & MII_ADDR_C45) {
> >  		reg = mdiobb_cmd_addr(ctrl, phy, reg);
> >  		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
> > +	} else if (reg & MII_ADDR_SMI0) {
> > +		mdiobb_cmd(ctrl, SMI0_RW_OPCODE,
> > +			   (reg & 0xE0) >> 5 | SMI0_WRITE_PHY, reg);
> >  	} else
> >  		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
> >  
> > diff --git a/include/linux/phy.h b/include/linux/phy.h
> > index 073fb151b5a99..f011722fbd5c2 100644
> > --- a/include/linux/phy.h
> > +++ b/include/linux/phy.h
> > @@ -199,6 +199,18 @@ static inline const char *phy_modes(phy_interface_t interface)
> >     IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
> >  #define MII_ADDR_C45 (1<<30)
> >  
> > +/* Serial Management Interface (SMI) uses the following frame format:
> > + *
> > + *       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
> > + *               |frame| OP code  |address |address|  |                  |
> > + * read | 32x1´s | 01  |    00    | 1xRRR  | RRRRR |Z0| 00000000DDDDDDDD |  Z
> > + * write| 32x1´s | 01  |    00    | 0xRRR  | RRRRR |10| xxxxxxxxDDDDDDDD |  Z
> > + *
> > + * The register number is encoded with the 5 least significant bits in REG
> > + * and the 3 most significant bits in PHY
> > + */
> > +#define MII_ADDR_SMI0 (1<<31)
> > +
> 
> Michael
> 
> This is a Micrel Proprietary protocol. So we should reflect this in
> the name. MII_ADDR_MICREL_SMI? Why the 0? Are there different
> versions? Maybe replace all SMI0 with MICREL_SMI in mdio-bitbang.c

There are two variants of the SMI interface.

The KSZ8863/73/93 Products use the above Variant described as "SMI0".

The KSZ8864/95 Products use another layout:

      preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
              |frame| OP code  |address |address|  |                  |
read | 32x1´s | 01  |    10    | RR11R  | RRRRR |Z0| 00000000DDDDDDDD |  Z
write| 32x1´s | 01  |    01    | RR11R  | RRRRR |10| xxxxxxxxDDDDDDDD |  Z

So they describe their write/read operation in the OP code rather then
the PHY address.

We could change the SMI index to SMI_KSZ88X3 for the current SMI0 to
give it a more descriptive name. Beside we never know if Microchip
will add the same protocol to other numbered switches. What naming
would you prefer?

> When i look at this, i don't see how a normal MDIO bus driver is going
> to support this. Only the bit banging driver, or maybe a Micrel MDIO
> bus master hardware driver. So i think the diagram should be placed
> into mdio-bitbang.c, and it would be nice to add a diagram of standard
> SMI.

Right. I will move the description to mdio-bitbang.c.

Thanks,
Michael

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC 2/3] ksz: Add Microchip KSZ8873 SMI-DSA driver
  2019-05-09 14:48   ` Andrew Lunn
@ 2019-05-10  7:37     ` Michael Grzeschik
  0 siblings, 0 replies; 10+ messages in thread
From: Michael Grzeschik @ 2019-05-10  7:37 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: Tristram.Ha, kernel, UNGLinuxDriver, netdev

[-- Attachment #1: Type: text/plain, Size: 4664 bytes --]

On Thu, May 09, 2019 at 04:48:44PM +0200, Andrew Lunn wrote:
> On Wed, May 08, 2019 at 11:13:29PM +0200, Michael Grzeschik wrote:
> > Cc: Tristram.Ha@microchip.com
> > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> > ---
> >  drivers/net/dsa/microchip/Kconfig       |   16 +
> >  drivers/net/dsa/microchip/Makefile      |    2 +
> >  drivers/net/dsa/microchip/ksz8863.c     | 1026 +++++++++++++++++++++++
> >  drivers/net/dsa/microchip/ksz8863_reg.h |  605 +++++++++++++
> >  drivers/net/dsa/microchip/ksz8863_smi.c |  105 +++
> >  drivers/net/dsa/microchip/ksz_priv.h    |    3 +
> >  include/net/dsa.h                       |    2 +
> >  net/dsa/Kconfig                         |    7 +
> >  net/dsa/tag_ksz.c                       |   45 +
> >  9 files changed, 1811 insertions(+)
> >  create mode 100644 drivers/net/dsa/microchip/ksz8863.c
> >  create mode 100644 drivers/net/dsa/microchip/ksz8863_reg.h
> >  create mode 100644 drivers/net/dsa/microchip/ksz8863_smi.c
> > 
> > diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
> > index bea29fde9f3d1..a6fa6ae972951 100644
> > --- a/drivers/net/dsa/microchip/Kconfig
> > +++ b/drivers/net/dsa/microchip/Kconfig
> > @@ -14,3 +14,19 @@ config NET_DSA_MICROCHIP_KSZ9477_SPI
> >  	depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
> >  	help
> >  	  Select to enable support for registering switches configured through SPI.
> > +
> > +menuconfig NET_DSA_MICROCHIP_KSZ8863
> > +	tristate "Microchip KSZ8863 series switch support"
> > +	depends on NET_DSA
> > +	select NET_DSA_TAG_KSZ8863
> > +	select NET_DSA_MICROCHIP_KSZ_COMMON
> > +	help
> > +	  This driver adds support for Microchip KSZ8863 switch chips.
> > +
> > +config NET_DSA_MICROCHIP_KSZ8863_SMI
> 
> > +	tristate "KSZ series SMI connected switch driver"
> > +	depends on NET_DSA_MICROCHIP_KSZ8863
> > +	default y
> > +	help
> > +	  Select to enable support for registering switches configured through SMI.
> 
> SMI is a synonym for MDIO. So we should make it clear, this is a
> proprietary version. "... through Microchip SMI".
> 
> You might also want to either depend on or select mdio-bitbang, since
> that is the other driver which supports Microchip SMI.

Right, I will add the comment and include the depend to mdio-bitbang.

> > +static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data,
> > +			unsigned int len)
> > +{
> > +	int i = 0;
> > +
> > +	for (i = 0; i < len; i++)
> > +		data[i] = (u8)mdiobus_read(dev->bus, 0,
> > +					    (reg + i) | MII_ADDR_SMI0);
> 
> mdiobus_read() and mdiobus_write() can return an error, which is why
> is returns an int. Please check for the error and return it.

Thanks for pointing this out. I will fix it!

> > diff --git a/include/net/dsa.h b/include/net/dsa.h
> > index 6aaaadd6a413c..57fbf3e722362 100644
> > --- a/include/net/dsa.h
> > +++ b/include/net/dsa.h
> > @@ -44,6 +44,7 @@ struct phylink_link_state;
> >  #define DSA_TAG_PROTO_TRAILER_VALUE		11
> >  #define DSA_TAG_PROTO_8021Q_VALUE		12
> >  #define DSA_TAG_PROTO_SJA1105_VALUE		13
> > +#define DSA_TAG_PROTO_KSZ8863_VALUE		14
> >  
> >  enum dsa_tag_protocol {
> >  	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
> > @@ -60,6 +61,7 @@ enum dsa_tag_protocol {
> >  	DSA_TAG_PROTO_TRAILER		= DSA_TAG_PROTO_TRAILER_VALUE,
> >  	DSA_TAG_PROTO_8021Q		= DSA_TAG_PROTO_8021Q_VALUE,
> >  	DSA_TAG_PROTO_SJA1105		= DSA_TAG_PROTO_SJA1105_VALUE,
> > +	DSA_TAG_PROTO_KSZ8863		= DSA_TAG_PROTO_KSZ8863_VALUE,
> >  };
> 
> Please put all the tag driver changes into a separate patch.

Right, I will ad that to another patch.

> > +static struct sk_buff *ksz8863_rcv(struct sk_buff *skb, struct net_device *dev,
> > +				   struct packet_type *pt)
> > +{
> > +	/* Tag decoding */
> > +	u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
> > +	unsigned int port = tag[0] & 1;
> 
> Does this device only have 2 ports, 0 and 1?
> 

Yes this is a very basic "switch" only managing two physical ports.

Refer Page 28 Chapter 3.7 "Tail Tagging Mode"
in the Reference Manual of the switch:

http://ww1.microchip.com/downloads/en/DeviceDoc/00002335B.pdf

> > +	unsigned int len = KSZ_EGRESS_TAG_LEN;
> > +
> > +	return ksz_common_rcv(skb, dev, port, len);
> > +}
> 
>   Andrew
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC 1/3] mdio-bitbang: add SMI0 mode support
  2019-05-10  7:32     ` Michael Grzeschik
@ 2019-05-10 12:36       ` Andrew Lunn
  0 siblings, 0 replies; 10+ messages in thread
From: Andrew Lunn @ 2019-05-10 12:36 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: Tristram.Ha, kernel, UNGLinuxDriver, netdev

> > > +/* Serial Management Interface (SMI) uses the following frame format:
> > > + *
> > > + *       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
> > > + *               |frame| OP code  |address |address|  |                  |
> > > + * read | 32x1´s | 01  |    00    | 1xRRR  | RRRRR |Z0| 00000000DDDDDDDD |  Z
> > > + * write| 32x1´s | 01  |    00    | 0xRRR  | RRRRR |10| xxxxxxxxDDDDDDDD |  Z
> > > + *
> > > + * The register number is encoded with the 5 least significant bits in REG
> > > + * and the 3 most significant bits in PHY
> > > + */
> > > +#define MII_ADDR_SMI0 (1<<31)
> > > +
> > 
> > Michael
> > 
> > This is a Micrel Proprietary protocol. So we should reflect this in
> > the name. MII_ADDR_MICREL_SMI? Why the 0? Are there different
> > versions? Maybe replace all SMI0 with MICREL_SMI in mdio-bitbang.c
> 
> There are two variants of the SMI interface.

Hi Michael

O.K, that explains the 0.

> 
> The KSZ8863/73/93 Products use the above Variant described as "SMI0".
> 
> The KSZ8864/95 Products use another layout:
> 
>       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
>               |frame| OP code  |address |address|  |                  |
> read | 32x1´s | 01  |    10    | RR11R  | RRRRR |Z0| 00000000DDDDDDDD |  Z
> write| 32x1´s | 01  |    01    | RR11R  | RRRRR |10| xxxxxxxxDDDDDDDD |  Z
> 
> So they describe their write/read operation in the OP code rather then
> the PHY address.

At a first look, i think a standard MDIO bus controller can do this?
If so, we don't need a second define, just some code in the switch
driver which shuffles bits around.

> 
> We could change the SMI index to SMI_KSZ88X3 for the current SMI0 to
> give it a more descriptive name.

That seems sensible. In the mv88e6xxx driver, we name things based on
the first device to introduce the feature.

    Andrew

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC 3/3] dt-bindings: net: dsa: document additional Microchip KSZ8863 family switches
  2019-05-08 21:13 ` [RFC 3/3] dt-bindings: net: dsa: document additional Microchip KSZ8863 family switches Michael Grzeschik
@ 2019-06-13 20:09   ` Rob Herring
  0 siblings, 0 replies; 10+ messages in thread
From: Rob Herring @ 2019-06-13 20:09 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: Tristram.Ha, kernel, UNGLinuxDriver, netdev, devicetree

On Wed, May 08, 2019 at 11:13:30PM +0200, Michael Grzeschik wrote:
> Document additional Microchip KSZ8863 family switches.
> 
> Show how KSZ8863 switch should be configured as the host port is port 3.
> 
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> ---
>  .../devicetree/bindings/net/dsa/ksz.txt       | 44 +++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt
> index e7db7268fd0fd..4ac576e1cc34e 100644
> --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt
> +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt
> @@ -5,6 +5,8 @@ Required properties:
>  
>  - compatible: For external switch chips, compatible string must be exactly one
>    of the following:
> +  - "microchip,ksz8863"
> +  - "microchip,ksz8873"
>    - "microchip,ksz9477"
>    - "microchip,ksz9897"
>    - "microchip,ksz9896"
> @@ -31,6 +33,48 @@ Ethernet switch connected via SPI to the host, CPU port wired to eth0:
>  		};
>  	};
>  
> +	mdio0: mdio-gpio {

Does this example show something new? Examples don't need to instantiate 
every possible option.

> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_mdio_1>;
> +		compatible = "virtual,mdio-gpio";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		gpios = <&gpio1 31 0 &gpio1 22 0>;
> +
> +		ksz8863@3 {
> +			compatible = "microchip,ksz8863";
> +			interrupt-parrent = <&gpio3>;
> +			interrupt = <30 IRQ_TYPE_LEVEL_HIGH>;
> +			reg = <0>;
> +
> +			ports {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				ports@0 {
> +					reg = <0>;
> +					label = "lan1";
> +				};
> +
> +				ports@1 {
> +					reg = <1>;
> +					label = "lan2";
> +				};
> +
> +				ports@2 {
> +					reg = <2>;
> +					label = "cpu";
> +					ethernet = <&eth0>;
> +
> +					fixed-link {
> +						speed = <100>;
> +						full-duplex;
> +					};
> +				};
> +			};
> +		};
> +	};
> +
>  	spi1: spi@f8008000 {
>  		pinctrl-0 = <&pinctrl_spi_ksz>;
>  		cs-gpios = <&pioC 25 0>;
> -- 
> 2.20.1
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-06-13 20:09 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-05-08 21:13 [RFC 0/3] microchip: add support for ksz8863 driver family Michael Grzeschik
2019-05-08 21:13 ` [RFC 1/3] mdio-bitbang: add SMI0 mode support Michael Grzeschik
2019-05-09 14:29   ` Andrew Lunn
2019-05-10  7:32     ` Michael Grzeschik
2019-05-10 12:36       ` Andrew Lunn
2019-05-08 21:13 ` [RFC 2/3] ksz: Add Microchip KSZ8873 SMI-DSA driver Michael Grzeschik
2019-05-09 14:48   ` Andrew Lunn
2019-05-10  7:37     ` Michael Grzeschik
2019-05-08 21:13 ` [RFC 3/3] dt-bindings: net: dsa: document additional Microchip KSZ8863 family switches Michael Grzeschik
2019-06-13 20:09   ` Rob Herring

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).