netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/4] microchip: add support for ksz88x3 driver family
@ 2019-11-07 11:00 Michael Grzeschik
  2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw)
  To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel

This series adds support for the ksz88x3 driver family to the 
dsa based ksz drivers. For now the ksz8863 and 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

Michael Grzeschik (4):
  mdio-bitbang: add SMI0 mode support
  net: tag: ksz: Add KSZ8863 tag code
  ksz: Add Microchip KSZ8863 SMI-DSA driver
  dt-bindings: net: dsa: document additional Microchip KSZ8863/8873
    switch

 .../devicetree/bindings/net/dsa/ksz.txt       |    2 +
 drivers/net/dsa/microchip/Kconfig             |   16 +
 drivers/net/dsa/microchip/Makefile            |    2 +
 drivers/net/dsa/microchip/ksz8863.c           | 1038 +++++++++++++++++
 drivers/net/dsa/microchip/ksz8863_reg.h       |  605 ++++++++++
 drivers/net/dsa/microchip/ksz8863_smi.c       |  166 +++
 drivers/net/dsa/microchip/ksz_common.h        |    1 +
 drivers/net/phy/mdio-bitbang.c                |   21 +
 include/linux/phy.h                           |    2 +
 include/net/dsa.h                             |    2 +
 net/dsa/tag_ksz.c                             |   60 +
 11 files changed, 1915 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.24.0.rc1


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

* [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support
  2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
@ 2019-11-07 11:00 ` Michael Grzeschik
  2019-11-07 15:42   ` Andrew Lunn
  2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw)
  To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel

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 available 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>
---
RFC -> v1: - moved the Protocol description to mdio-bitbang
           - renamed the protocol to SMI_KSZ88X3...

 drivers/net/phy/mdio-bitbang.c | 21 +++++++++++++++++++++
 include/linux/phy.h            |  2 ++
 2 files changed, 23 insertions(+)

diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index 5136275c8e739..9f6fb84f92f60 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -22,6 +22,21 @@
 #define MDIO_READ 2
 #define MDIO_WRITE 1
 
+/* KSZ8863 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 SMI_KSZ88X3_RW_OPCODE	0
+#define SMI_KSZ88X3_READ_PHY	(1 << 4)
+#define SMI_KSZ88X3_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 +172,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_SMI_KSZ88X3) {
+		mdiobb_cmd(ctrl, SMI_KSZ88X3_RW_OPCODE,
+			   (reg & 0xE0) >> 5 | SMI_KSZ88X3_READ_PHY, reg);
 	} else
 		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
 
@@ -188,6 +206,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_SMI_KSZ88X3) {
+		mdiobb_cmd(ctrl, SMI_KSZ88X3_RW_OPCODE,
+			   (reg & 0xE0) >> 5 | SMI_KSZ88X3_WRITE_PHY, reg);
 	} else
 		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
 
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 78436d58ce7ce..e569aa92ac6c8 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -201,6 +201,8 @@ static inline const char *phy_modes(phy_interface_t interface)
 #define MII_DEVADDR_C45_SHIFT	16
 #define MII_REGADDR_C45_MASK	GENMASK(15, 0)
 
+#define MII_ADDR_SMI_KSZ88X3 (1<<31)
+
 struct device;
 struct phylink;
 struct sk_buff;
-- 
2.24.0.rc1


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

* [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code
  2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
  2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik
@ 2019-11-07 11:00 ` Michael Grzeschik
  2019-11-07 15:44   ` Andrew Lunn
  2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw)
  To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel

Add DSA tag code for the Microchip KSZ8863 switch.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
---
 include/net/dsa.h |  2 ++
 net/dsa/tag_ksz.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 9507611a41f07..911f07ec40e3a 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -42,6 +42,7 @@ struct phylink_link_state;
 #define DSA_TAG_PROTO_8021Q_VALUE		12
 #define DSA_TAG_PROTO_SJA1105_VALUE		13
 #define DSA_TAG_PROTO_KSZ8795_VALUE		14
+#define DSA_TAG_PROTO_KSZ8863_VALUE		15
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -59,6 +60,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_8021Q		= DSA_TAG_PROTO_8021Q_VALUE,
 	DSA_TAG_PROTO_SJA1105		= DSA_TAG_PROTO_SJA1105_VALUE,
 	DSA_TAG_PROTO_KSZ8795		= DSA_TAG_PROTO_KSZ8795_VALUE,
+	DSA_TAG_PROTO_KSZ8863		= DSA_TAG_PROTO_KSZ8863_VALUE,
 };
 
 struct packet_type;
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index 73605bcbb3851..08ea996af3c34 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -243,8 +243,68 @@ static const struct dsa_device_ops ksz9893_netdev_ops = {
 DSA_TAG_DRIVER(ksz9893_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893);
 
+/* For ingress (Host -> KSZ8863), 1 byte is added before FCS.
+ * ---------------------------------------------------------------------------
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes)
+ * ---------------------------------------------------------------------------
+ * tag0[1,0] : represents port
+ *             (e.g. 0b00=addr-lookup 0b01=port1, 0b10=port2, 0b11=port1+port2)
+ * tag0[3,2] : bits two and three represent prioritization
+ *             (e.g. 0b00xx=prio0, 0b01xx=prio1, 0b10xx=prio2, 0b11xx=prio3)
+ *
+ * For egress (KSZ8873 -> Host), 1 byte is added before FCS.
+ * ---------------------------------------------------------------------------
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes)
+ * ---------------------------------------------------------------------------
+ * tag0[0]   : zero-based value represents port
+ *             (eg, 0b0=port1, 0b1=port2)
+ */
+
+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, KSZ_INGRESS_TAG_LEN);
+	if (!nskb)
+		return NULL;
+
+	/* Tag encoding */
+	tag = skb_put(nskb, KSZ_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 = KSZ_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(ksz8795_netdev_ops),
+	&DSA_TAG_DRIVER_NAME(ksz8863_netdev_ops),
 	&DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops),
 	&DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops),
 };
-- 
2.24.0.rc1


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

* [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver
  2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
  2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik
  2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik
@ 2019-11-07 11:00 ` Michael Grzeschik
  2019-11-07 15:56   ` Andrew Lunn
  2019-11-09  8:08   ` kbuild test robot
  2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik
  2019-11-07 15:36 ` [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
  4 siblings, 2 replies; 20+ messages in thread
From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw)
  To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel

Add KSZ88X3 driver support. The code ksz8863.c and ksz8863_smi.c add
support for the three port switches ksz8863 and ksz8873 using the
Microchip SMI Interface. They are currently only supported using the
MDIO-Bitbang Interface.

Cc: Tristram.Ha@microchip.com
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
---
RFC -> v1: - added Microchip SMI to description
	   - added select MDIO_BITBANG
	   - added return error code handling in mdiobus_read/write
	   - fixed the stp state handling
	   - moved tag handling code to seperate patch

 drivers/net/dsa/microchip/Kconfig       |   16 +
 drivers/net/dsa/microchip/Makefile      |    2 +
 drivers/net/dsa/microchip/ksz8863.c     | 1038 +++++++++++++++++++++++
 drivers/net/dsa/microchip/ksz8863_reg.h |  605 +++++++++++++
 drivers/net/dsa/microchip/ksz8863_smi.c |  166 ++++
 drivers/net/dsa/microchip/ksz_common.h  |    1 +
 6 files changed, 1828 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 1d7870c6df3ce..5bd5d4a8d875e 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -39,3 +39,19 @@ config NET_DSA_MICROCHIP_KSZ8795_SPI
 
 	  It is required to use the KSZ8795 switch driver as the only access
 	  is through SPI.
+
+menuconfig NET_DSA_MICROCHIP_KSZ8863
+	tristate "Microchip KSZ8863 series switch support"
+	depends on NET_DSA
+	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
+	select MDIO_BITBANG
+	default y
+	help
+	  Select to enable support for registering switches configured through
+	  Microchip SMI. It Supports the KSZ8863 and KSZ8873 Switch.
diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
index 929caa81e782e..694c2e2eea228 100644
--- a/drivers/net/dsa/microchip/Makefile
+++ b/drivers/net/dsa/microchip/Makefile
@@ -5,3 +5,5 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)	+= ksz9477_i2c.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)	+= ksz9477_spi.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795)		+= ksz8795.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI)	+= ksz8795_spi.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_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..c299a3f41eef7
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz8863.c
@@ -0,0 +1,1038 @@
+// 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_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 void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
+{
+	regmap_update_bits(dev->regmap[0], 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(dev->regmap[0], PORT_CTRL_ADDR(port, offset),
+			   bits, set ? bits : 0);
+}
+
+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_read64(dev, REG_IND_DATA_HI, data);
+	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_write64(dev, REG_IND_DATA_HI, data);
+	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;
+
+		regmap_bulk_read(dev->regmap[0], 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..742955c85d859
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz8863_smi.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip KSZ8863 series register access through SMI
+ *
+ * Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>
+ */
+
+#include "ksz_common.h"
+
+static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
+			     void *val_buf, size_t val_len)
+{
+	struct ksz_device *dev = (struct ksz_device *)ctx;
+	struct mdio_device *mdev = (struct mdio_device *)dev->priv;
+	u8 reg = *(u8 *)reg_buf;
+	u8 *val = val_buf;
+	int ret;
+	int i;
+
+	for (i = 0; i < val_len; i++) {
+		ret = mdiobus_read(mdev->bus, 0, (reg + i) |
+				   MII_ADDR_SMI_KSZ88X3);
+		if (ret < 0)
+			return ret;
+
+		val[i] = ret;
+	}
+
+	return 0;
+}
+
+static int ksz8863_mdio_write(void *ctx, const void *data, size_t count)
+{
+	struct ksz_device *dev = (struct ksz_device *)ctx;
+	struct mdio_device *mdev = (struct mdio_device *)dev->priv;
+	u32 reg = *(u32 *)data;
+	u8 *val = (u8 *)(data + 4);
+	int ret;
+	int i;
+
+	for (i = 0; i < (count - 4); i++) {
+		ret = mdiobus_write(mdev->bus, 0, (reg + i) |
+				    MII_ADDR_SMI_KSZ88X3, val[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct regmap_bus regmap_smi[] = {
+	{
+		.read = ksz8863_mdio_read,
+		.write = ksz8863_mdio_write,
+		.max_raw_read = 1,
+		.max_raw_write = 1,
+	},
+	{
+		.read = ksz8863_mdio_read,
+		.write = ksz8863_mdio_write,
+		.val_format_endian_default = REGMAP_ENDIAN_BIG,
+		.max_raw_read = 2,
+		.max_raw_write = 2,
+	},
+	{
+		.read = ksz8863_mdio_read,
+		.write = ksz8863_mdio_write,
+		.val_format_endian_default = REGMAP_ENDIAN_BIG,
+		.max_raw_read = 4,
+		.max_raw_write = 4,
+	}
+};
+
+static const struct regmap_config ksz8863_regmap_config[] = {
+	{
+		.name = "#8",
+		.reg_bits = 8,
+		.pad_bits = 24,
+		.val_bits = 8,
+		.cache_type = REGCACHE_NONE,
+		.use_single_read = 1,
+	},
+	{
+		.name = "#16",
+		.reg_bits = 8,
+		.pad_bits = 24,
+		.val_bits = 16,
+		.cache_type = REGCACHE_NONE,
+		.use_single_read = 1,
+	},
+	{
+		.name = "#32",
+		.reg_bits = 8,
+		.pad_bits = 24,
+		.val_bits = 32,
+		.cache_type = REGCACHE_NONE,
+		.use_single_read = 1,
+	}
+};
+
+static int ksz8863_smi_probe(struct mdio_device *mdiodev)
+{
+	struct ksz_device *dev;
+	int ret;
+	int i;
+
+	dev = ksz_switch_alloc(&mdiodev->dev, mdiodev);
+	if (!dev)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(ksz8863_regmap_config); i++) {
+		dev->regmap[i] = devm_regmap_init(&mdiodev->dev,
+						  &regmap_smi[i], dev,
+						  &ksz8863_regmap_config[i]);
+		if (IS_ERR(dev->regmap[i])) {
+			ret = PTR_ERR(dev->regmap[i]);
+			dev_err(&mdiodev->dev,
+				"Failed to initialize regmap%i: %d\n",
+				ksz8863_regmap_config[i].val_bits, ret);
+			return ret;
+		}
+	}
+
+	if (mdiodev->dev.platform_data)
+		dev->pdata = mdiodev->dev.platform_data;
+
+	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_common.h b/drivers/net/dsa/microchip/ksz_common.h
index a20ebb749377c..dd2bd645a3125 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -151,6 +151,7 @@ int ksz_switch_register(struct ksz_device *dev,
 void ksz_switch_remove(struct ksz_device *dev);
 
 int ksz8795_switch_register(struct ksz_device *dev);
+int ksz8863_switch_register(struct ksz_device *dev);
 int ksz9477_switch_register(struct ksz_device *dev);
 
 void ksz_update_port_member(struct ksz_device *dev, int port);
-- 
2.24.0.rc1


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

* [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch
  2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
                   ` (2 preceding siblings ...)
  2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik
@ 2019-11-07 11:00 ` Michael Grzeschik
  2019-11-13 13:34   ` Rob Herring
  2019-11-07 15:36 ` [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
  4 siblings, 1 reply; 20+ messages in thread
From: Michael Grzeschik @ 2019-11-07 11:00 UTC (permalink / raw)
  To: netdev; +Cc: Tristram.Ha, UNGLinuxDriver, kernel, devicetree

It is a 3-Port 10/100 Ethernet Switch. One CPU-Port and two
Switch-Ports.

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

diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt
index 95e91e84151c3..a5d71862f53cb 100644
--- a/Documentation/devicetree/bindings/net/dsa/ksz.txt
+++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt
@@ -8,6 +8,8 @@ Required properties:
   - "microchip,ksz8765"
   - "microchip,ksz8794"
   - "microchip,ksz8795"
+  - "microchip,ksz8863"
+  - "microchip,ksz8873"
   - "microchip,ksz9477"
   - "microchip,ksz9897"
   - "microchip,ksz9896"
-- 
2.24.0.rc1


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

* Re: [PATCH v1 0/4] microchip: add support for ksz88x3 driver family
  2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
                   ` (3 preceding siblings ...)
  2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik
@ 2019-11-07 15:36 ` Michael Grzeschik
  4 siblings, 0 replies; 20+ messages in thread
From: Michael Grzeschik @ 2019-11-07 15:36 UTC (permalink / raw)
  To: netdev; +Cc: UNGLinuxDriver, kernel, Tristram.Ha

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

On Thu, Nov 07, 2019 at 12:00:26PM +0100, Michael Grzeschik wrote:
> This series adds support for the ksz88x3 driver family to the 
> dsa based ksz drivers. For now the ksz8863 and 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

After reviewing the code with my colleague, we found out this core is
not very different to the already mainlined ksz8795. So it will be
easier to port the ksz8863 specific changes into that driver.

I will give it a try.

> Michael Grzeschik (4):
>   mdio-bitbang: add SMI0 mode support
>   net: tag: ksz: Add KSZ8863 tag code
>   ksz: Add Microchip KSZ8863 SMI-DSA driver
>   dt-bindings: net: dsa: document additional Microchip KSZ8863/8873
>     switch
> 
>  .../devicetree/bindings/net/dsa/ksz.txt       |    2 +
>  drivers/net/dsa/microchip/Kconfig             |   16 +
>  drivers/net/dsa/microchip/Makefile            |    2 +
>  drivers/net/dsa/microchip/ksz8863.c           | 1038 +++++++++++++++++
>  drivers/net/dsa/microchip/ksz8863_reg.h       |  605 ++++++++++
>  drivers/net/dsa/microchip/ksz8863_smi.c       |  166 +++
>  drivers/net/dsa/microchip/ksz_common.h        |    1 +
>  drivers/net/phy/mdio-bitbang.c                |   21 +
>  include/linux/phy.h                           |    2 +
>  include/net/dsa.h                             |    2 +
>  net/dsa/tag_ksz.c                             |   60 +
>  11 files changed, 1915 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.24.0.rc1
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
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] 20+ messages in thread

* Re: [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support
  2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik
@ 2019-11-07 15:42   ` Andrew Lunn
  2019-12-18 16:29     ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik
  0 siblings, 1 reply; 20+ messages in thread
From: Andrew Lunn @ 2019-11-07 15:42 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel

On Thu, Nov 07, 2019 at 12:00:27PM +0100, 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 available 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>

Hi Michael

I don't like adding vendor proprietary stuff to generic code like
this. Please could you see if you can make use of mdiobb_ops in some
way? Move all this junk out into a mdio-kzs88x3.c?

Thanks
	Andrew

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

* Re: [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code
  2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik
@ 2019-11-07 15:44   ` Andrew Lunn
  0 siblings, 0 replies; 20+ messages in thread
From: Andrew Lunn @ 2019-11-07 15:44 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel

On Thu, Nov 07, 2019 at 12:00:28PM +0100, Michael Grzeschik wrote:
> Add DSA tag code for the Microchip KSZ8863 switch.
> 
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

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

* Re: [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver
  2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik
@ 2019-11-07 15:56   ` Andrew Lunn
  2019-11-09  8:08   ` kbuild test robot
  1 sibling, 0 replies; 20+ messages in thread
From: Andrew Lunn @ 2019-11-07 15:56 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel

> +static const u8 stp_multicast_addr[] = {
> +	0x01, 0x80, 0xC2, 0x00, 0x00, 0x00
> +};

This probably exists already. Please go looking in include/linux and
include/net.

> +static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
> +			     void *val_buf, size_t val_len)
> +{
> +	struct ksz_device *dev = (struct ksz_device *)ctx;

ctx is a void *, so you don't need the cast.

> +	struct mdio_device *mdev = (struct mdio_device *)dev->priv;

and priv is also probably a void *.

And please fix the reverse christmas tree.

Thanks
	Andrew

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

* Re: [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver
  2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik
  2019-11-07 15:56   ` Andrew Lunn
@ 2019-11-09  8:08   ` kbuild test robot
  1 sibling, 0 replies; 20+ messages in thread
From: kbuild test robot @ 2019-11-09  8:08 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: kbuild-all, netdev, Tristram.Ha, UNGLinuxDriver, kernel

Hi Michael,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net/master]
[also build test WARNING on v5.4-rc6 next-20191108]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Michael-Grzeschik/microchip-add-support-for-ksz88x3-driver-family/20191109-122140
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git a2582cdc32f071422e0197a6c59bd1235b426ce2
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-21-gb31adac-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:184:17: sparse: sparse: cast to restricted __be64
>> drivers/net/dsa/microchip/ksz8863.c:193:14: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned long long [usertype] data @@    got nsigned long long [usertype] data @@
>> drivers/net/dsa/microchip/ksz8863.c:193:14: sparse:    expected unsigned long long [usertype] data
>> drivers/net/dsa/microchip/ksz8863.c:193:14: sparse:    got restricted __be64 [usertype]
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64
   drivers/net/dsa/microchip/ksz8863.c:252:23: sparse: sparse: cast to restricted __be64

vim +184 drivers/net/dsa/microchip/ksz8863.c

   172	
   173	static void ksz8863_r_table(struct ksz_device *dev, int table, u16 addr,
   174				    u64 *data)
   175	{
   176		u16 ctrl_addr;
   177	
   178		ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
   179	
   180		mutex_lock(&dev->alu_mutex);
   181		ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
   182		ksz_read64(dev, REG_IND_DATA_HI, data);
   183		mutex_unlock(&dev->alu_mutex);
 > 184		*data = be64_to_cpu(*data);
   185	}
   186	
   187	static void ksz8863_w_table(struct ksz_device *dev, int table, u16 addr,
   188				    u64 data)
   189	{
   190		u16 ctrl_addr;
   191	
   192		ctrl_addr = IND_ACC_TABLE(table) | addr;
 > 193		data = cpu_to_be64(data);
   194	
   195		mutex_lock(&dev->alu_mutex);
   196		ksz_write64(dev, REG_IND_DATA_HI, data);
   197		ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
   198		mutex_unlock(&dev->alu_mutex);
   199	}
   200	

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation

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

* Re: [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch
  2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik
@ 2019-11-13 13:34   ` Rob Herring
  0 siblings, 0 replies; 20+ messages in thread
From: Rob Herring @ 2019-11-13 13:34 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: netdev, Tristram.Ha, UNGLinuxDriver, kernel, devicetree

On Thu,  7 Nov 2019 12:00:30 +0100, Michael Grzeschik wrote:
> It is a 3-Port 10/100 Ethernet Switch. One CPU-Port and two
> Switch-Ports.
> 
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> ---
>  Documentation/devicetree/bindings/net/dsa/ksz.txt | 2 ++
>  1 file changed, 2 insertions(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

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

* [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2019-11-07 15:42   ` Andrew Lunn
@ 2019-12-18 16:29     ` Michael Grzeschik
  2019-12-19 20:39       ` Andrew Lunn
                         ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Michael Grzeschik @ 2019-12-18 16:29 UTC (permalink / raw)
  To: andrew; +Cc: f.fainelli, netdev, davem, kernel

Some phys support special opcode handling when communicating via mdio.
This patch introduces mdio_ll_read/write which makes it possible to set
the opcode. It implements these functions in the gpio-bitbang driver,
which is capable of setting the opcode on read and write.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
---
Hi Andrew,

I worked on your suggestion moving the proprietary call to
mdio-ksz88x3.c which does not seem to work out very well.
I still end up having an MII_ADDR_SMI???? define in linux/phy.h.

Instead of having to support this special case in one extra file
what do you think of adding mdiobus_lowlevel_write/read to mdio_bus.
This way it would be possible to add the opcode directly as user.

Other controllers which have the possibility to set the op code in hardware
will also profit from that and can implement these functions.

Regards,
Michael

 drivers/net/phy/mdio-bitbang.c |  41 +++++++++---
 drivers/net/phy/mdio_bus.c     | 110 +++++++++++++++++++++++++++++++++
 include/linux/mdio.h           |   6 ++
 include/linux/phy.h            |   3 +
 4 files changed, 150 insertions(+), 10 deletions(-)

diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index 5136275c8e739..77fbc7eaadf51 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -149,16 +149,12 @@ static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr)
 	return dev_addr;
 }
 
-static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+static int mdiobb_ll_read(struct mii_bus *bus, int op, int phy, int reg)
 {
 	struct mdiobb_ctrl *ctrl = bus->priv;
 	int ret, i;
 
-	if (reg & MII_ADDR_C45) {
-		reg = mdiobb_cmd_addr(ctrl, phy, reg);
-		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
-	} else
-		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+	mdiobb_cmd(ctrl, op, phy, reg);
 
 	ctrl->ops->set_mdio_dir(ctrl, 0);
 
@@ -181,15 +177,25 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
 	return ret;
 }
 
-static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
 {
 	struct mdiobb_ctrl *ctrl = bus->priv;
+	int op = MDIO_READ;
 
 	if (reg & MII_ADDR_C45) {
 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
-		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
-	} else
-		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+		op = MDIO_C45_READ;
+	}
+
+	return mdiobb_ll_read(bus, op, phy, reg);
+}
+
+static int mdiobb_ll_write(struct mii_bus *bus, int op, int phy,
+			   int reg, u16 val)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+
+	mdiobb_cmd(ctrl, op, phy, reg);
 
 	/* send the turnaround (10) */
 	mdiobb_send_bit(ctrl, 1);
@@ -202,6 +208,19 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
 	return 0;
 }
 
+static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+	int op = MDIO_WRITE;
+
+	if (reg & MII_ADDR_C45) {
+		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+		op = MDIO_C45_WRITE;
+	}
+
+	return mdiobb_ll_write(bus, op, phy, reg, val);
+}
+
 struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 {
 	struct mii_bus *bus;
@@ -213,7 +232,9 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 	__module_get(ctrl->ops->owner);
 
 	bus->read = mdiobb_read;
+	bus->ll_read = mdiobb_ll_read;
 	bus->write = mdiobb_write;
+	bus->ll_write = mdiobb_ll_write;
 	bus->priv = ctrl;
 
 	return bus;
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 229e480179ff1..57f4b7b9ce39a 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -560,6 +560,34 @@ int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
 }
 EXPORT_SYMBOL(__mdiobus_read);
 
+/**
+ * __mdiobus_ll_read - Unlocked version of the mdiobus_read function
+ * @bus: the mii_bus struct
+ * @op: opcode to use on transfer
+ * @addr: the phy address
+ * @regnum: register number to read
+ *
+ * Read a MDIO bus register. Caller must hold the mdio bus lock.
+ *
+ * NOTE: MUST NOT be called from interrupt context.
+ */
+int __mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum)
+{
+	int retval;
+
+	if (!bus->ll_write)
+		return -ENODEV;
+
+	WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
+
+	retval = bus->ll_read(bus, op, addr, regnum);
+
+	trace_mdio_access(bus, 1, addr, regnum, retval, retval);
+
+	return retval;
+}
+EXPORT_SYMBOL(__mdiobus_ll_read);
+
 /**
  * __mdiobus_write - Unlocked version of the mdiobus_write function
  * @bus: the mii_bus struct
@@ -585,6 +613,36 @@ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
 }
 EXPORT_SYMBOL(__mdiobus_write);
 
+/**
+ * __mdiobus_ll_write - Unlocked version of the mdiobus_write function
+ * @bus: the mii_bus struct
+ * @op: opcode to use on transfer
+ * @addr: the phy address
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * Write a MDIO bus register. Caller must hold the mdio bus lock.
+ *
+ * NOTE: MUST NOT be called from interrupt context.
+ */
+int __mdiobus_ll_write(struct mii_bus *bus, int op, int addr,
+		       u32 regnum, u16 val)
+{
+	int err;
+
+	if (!bus->ll_write)
+		return -ENODEV;
+
+	WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
+
+	err = bus->ll_write(bus, op, addr, regnum, val);
+
+	trace_mdio_access(bus, 0, addr, regnum, val, err);
+
+	return err;
+}
+EXPORT_SYMBOL(__mdiobus_ll_write);
+
 /**
  * mdiobus_read_nested - Nested version of the mdiobus_read function
  * @bus: the mii_bus struct
@@ -636,6 +694,31 @@ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
 }
 EXPORT_SYMBOL(mdiobus_read);
 
+/**
+ * mdiobus_ll_read - Convenience function for reading a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @op: opcode to use on transfer
+ * @addr: the phy address
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+int mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum)
+{
+	int retval;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&bus->mdio_lock);
+	retval = __mdiobus_ll_read(bus, op, addr, regnum);
+	mutex_unlock(&bus->mdio_lock);
+
+	return retval;
+}
+EXPORT_SYMBOL(mdiobus_ll_read);
+
 /**
  * mdiobus_write_nested - Nested version of the mdiobus_write function
  * @bus: the mii_bus struct
@@ -689,6 +772,33 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
 }
 EXPORT_SYMBOL(mdiobus_write);
 
+/**
+ * mdiobus_ll_write - Convenience function for writing a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @op: opcode to use on transfer
+ * @addr: the phy address
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+int mdiobus_ll_write(struct mii_bus *bus, int op, int addr,
+		     u32 regnum, u16 val)
+{
+	int err;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&bus->mdio_lock);
+	err = __mdiobus_ll_write(bus, op, addr, regnum, val);
+	mutex_unlock(&bus->mdio_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(mdiobus_ll_write);
+
 /**
  * mdio_bus_match - determine if given MDIO driver supports the given
  *		    MDIO device
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index a7604248777b7..aafd24eb6d393 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -315,11 +315,17 @@ static inline void mii_10gbt_stat_mod_linkmode_lpa_t(unsigned long *advertising,
 }
 
 int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
+int __mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum);
 int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+int __mdiobus_ll_write(struct mii_bus *bus, int op, int addr,
+		       u32 regnum, u16 val);
 
 int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
+int mdiobus_ll_read(struct mii_bus *bus, int op, int addr, u32 regnum);
 int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
 int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+int mdiobus_ll_write(struct mii_bus *bus, int op, int addr,
+		     u32 regnum, u16 val);
 int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val);
 
 int mdiobus_register_device(struct mdio_device *mdiodev);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 5032d453ac66a..3bb802cb03a8a 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -218,6 +218,9 @@ struct mii_bus {
 	void *priv;
 	int (*read)(struct mii_bus *bus, int addr, int regnum);
 	int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
+	int (*ll_read)(struct mii_bus *bus, int op, int addr, int regnum);
+	int (*ll_write)(struct mii_bus *bus, int op, int addr,
+			int regnum, u16 val);
 	int (*reset)(struct mii_bus *bus);
 
 	/*
-- 
2.24.0


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

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2019-12-18 16:29     ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik
@ 2019-12-19 20:39       ` Andrew Lunn
  2019-12-19 22:01         ` Michael Grzeschik
  2019-12-19 22:05       ` Florian Fainelli
  2019-12-21 16:41       ` Andrew Lunn
  2 siblings, 1 reply; 20+ messages in thread
From: Andrew Lunn @ 2019-12-19 20:39 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: f.fainelli, netdev, davem, kernel

On Wed, Dec 18, 2019 at 05:29:19PM +0100, Michael Grzeschik wrote:
> Some phys support special opcode handling when communicating via mdio.
> This patch introduces mdio_ll_read/write which makes it possible to set
> the opcode. It implements these functions in the gpio-bitbang driver,
> which is capable of setting the opcode on read and write.
> 
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

Hi Michael

It is normal to post the user of a new API at the same time as a new
API. I'm having trouble working out how this is supposed to be used.

     Andrew

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

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2019-12-19 20:39       ` Andrew Lunn
@ 2019-12-19 22:01         ` Michael Grzeschik
  0 siblings, 0 replies; 20+ messages in thread
From: Michael Grzeschik @ 2019-12-19 22:01 UTC (permalink / raw)
  To: Andrew Lunn, g; +Cc: f.fainelli, netdev, davem, kernel

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

On Thu, Dec 19, 2019 at 09:39:31PM +0100, Andrew Lunn wrote:
> On Wed, Dec 18, 2019 at 05:29:19PM +0100, Michael Grzeschik wrote:
> > Some phys support special opcode handling when communicating via mdio.
> > This patch introduces mdio_ll_read/write which makes it possible to set
> > the opcode. It implements these functions in the gpio-bitbang driver,
> > which is capable of setting the opcode on read and write.
> > 
> > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> 
> Hi Michael
> 
> It is normal to post the user of a new API at the same time as a new
> API. I'm having trouble working out how this is supposed to be used.

Hi Andrew,

so this patch should have been in the series with the ksz8863 driver,
which is using the API. I will send the series again as v3 including
this patch, so it will be clear how this is ment.

Thanks,
Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
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] 20+ messages in thread

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2019-12-18 16:29     ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik
  2019-12-19 20:39       ` Andrew Lunn
@ 2019-12-19 22:05       ` Florian Fainelli
  2019-12-21 16:41       ` Andrew Lunn
  2 siblings, 0 replies; 20+ messages in thread
From: Florian Fainelli @ 2019-12-19 22:05 UTC (permalink / raw)
  To: Michael Grzeschik, andrew; +Cc: netdev, davem, kernel

On 12/18/19 8:29 AM, Michael Grzeschik wrote:
> Some phys support special opcode handling when communicating via mdio.
> This patch introduces mdio_ll_read/write which makes it possible to set
> the opcode. It implements these functions in the gpio-bitbang driver,
> which is capable of setting the opcode on read and write.
> 
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> ---
> Hi Andrew,
> 
> I worked on your suggestion moving the proprietary call to
> mdio-ksz88x3.c which does not seem to work out very well.
> I still end up having an MII_ADDR_SMI???? define in linux/phy.h.
> 
> Instead of having to support this special case in one extra file
> what do you think of adding mdiobus_lowlevel_write/read to mdio_bus.
> This way it would be possible to add the opcode directly as user.
> 
> Other controllers which have the possibility to set the op code in hardware
> will also profit from that and can implement these functions.

I am not sure it makes sense for the entire struct mii_bus to gain two
new pointers, when you could just exported the mdiobb_ll_read() and
mdiobb_ll_write() to the kernel modules that needs those, and wrap them
however you need them to implement the mdiobus->read() and
mdiobus->write() operations?
-- 
Florian

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

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2019-12-18 16:29     ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik
  2019-12-19 20:39       ` Andrew Lunn
  2019-12-19 22:05       ` Florian Fainelli
@ 2019-12-21 16:41       ` Andrew Lunn
  2020-01-29 15:42         ` Michael Grzeschik
  2 siblings, 1 reply; 20+ messages in thread
From: Andrew Lunn @ 2019-12-21 16:41 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: f.fainelli, netdev, davem, kernel

Hi Michael

In your V1 patch, you had this diagram.

+/* 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
+ *
+ */

I just compared this to plain MDIO:

+ *       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
+ *               |frame| OP code  |address |address|  |                  |
+ * read | 32x1´s | 01  |    10    | AAAA   | RRRRR |Z0| DDDDDDDDDDDDDDDD |  Z
+ * write| 32x1´s | 01  |    01    | AAAA   | RRRRR |10| DDDDDDDDDDDDDDDD |  Z

So the only real issue here is the OP code? The rest you can do with a
layer on top of the standard API.

How about something like this. Totally untested, probably does not
even compile.....

     Andrew

From 6051479b218fd19942d702e3e051c6355fe2a11f Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Sat, 21 Dec 2019 10:31:19 -0600
Subject: [PATCH] net: phy: Add support for microchip SMI0 MDIO bus.

SMI0 is a mangled version of MDIO. The main low level difference is
the MDIO C22 OP code is always 0, not 0x2 or 0x1 for Read/Write. The
read/write information is instead encoded in the PHY address.

Extend the bit-bang code to allow the op code to be overridden, but
default to normal C22 values. Add an extra compatible to the mdio-gpio
driver, and when this compatible is present, set the op codes to 0.

A higher level driver, sitting on top of the basic MDIO bus driver can
then implement the rest of the microchip SMI0 odderties.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/phy/mdio-bitbang.c | 7 +++++--
 drivers/net/phy/mdio-gpio.c    | 7 +++++++
 include/linux/mdio-bitbang.h   | 2 ++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index 5136275c8e73..01f620889c78 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -158,7 +158,7 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
 		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
 	} else
-		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+		mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg);
 
 	ctrl->ops->set_mdio_dir(ctrl, 0);
 
@@ -189,7 +189,7 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
 		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
 	} else
-		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+		mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg);
 
 	/* send the turnaround (10) */
 	mdiobb_send_bit(ctrl, 1);
@@ -216,6 +216,9 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 	bus->write = mdiobb_write;
 	bus->priv = ctrl;
 
+	ctrl->op_c22_read = MDIO_READ;
+	ctrl->op_c22_write = MDIO_WRITE;
+
 	return bus;
 }
 EXPORT_SYMBOL(alloc_mdio_bitbang);
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 1b00235d7dc5..282bc38331d7 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -132,6 +132,12 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
 		new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
 	}
 
+	if (dev->of_node &&
+	    of_device_is_compatible(dev->of_node, "microchip,mdio-smi0")) {
+		bitbang->ctrl->op_c22_read = 0;
+		bitbang->ctrl->op_c22_write = 0;
+	}
+
 	dev_set_drvdata(dev, new_bus);
 
 	return new_bus;
@@ -196,6 +202,7 @@ static int mdio_gpio_remove(struct platform_device *pdev)
 
 static const struct of_device_id mdio_gpio_of_match[] = {
 	{ .compatible = "virtual,mdio-gpio", },
+	{ .compatible = "microchip,mdio-smi0" },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mdio_gpio_of_match);
diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h
index 5d71e8a8500f..8ae0b3835233 100644
--- a/include/linux/mdio-bitbang.h
+++ b/include/linux/mdio-bitbang.h
@@ -33,6 +33,8 @@ struct mdiobb_ops {
 
 struct mdiobb_ctrl {
 	const struct mdiobb_ops *ops;
+	u8 op_c22_read;
+	u8 op_c22_write;
 };
 
 /* The returned bus is not yet registered with the phy layer. */
-- 
2.24.0


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

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2019-12-21 16:41       ` Andrew Lunn
@ 2020-01-29 15:42         ` Michael Grzeschik
  2020-01-29 15:53           ` Andrew Lunn
  0 siblings, 1 reply; 20+ messages in thread
From: Michael Grzeschik @ 2020-01-29 15:42 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: f.fainelli, netdev, davem, kernel

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

Hi Andrew!

I tested your patch. But it works only partially. For the case that
the upper driver is directly communicating in SMI mode with the phy,
this works fine. But the regular MDIO connection does not work anymore
afterwards.

The normals MDIO communication still needs to work, as mdio-gpio is
calling of_mdiobus_register that on the other end calls get_phy_device
and tries to communicate via regular MDIO to the device.

Fixing the whole bus to the SMI opcode breaks the regular commands.

Do you have any ideas how to fix that?

Regards,
Michael

On Sat, Dec 21, 2019 at 05:41:10PM +0100, Andrew Lunn wrote:
> Hi Michael
> 
> In your V1 patch, you had this diagram.
> 
> +/* 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
> + *
> + */
> 
> I just compared this to plain MDIO:
> 
> + *       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle
> + *               |frame| OP code  |address |address|  |                  |
> + * read | 32x1´s | 01  |    10    | AAAA   | RRRRR |Z0| DDDDDDDDDDDDDDDD |  Z
> + * write| 32x1´s | 01  |    01    | AAAA   | RRRRR |10| DDDDDDDDDDDDDDDD |  Z
> 
> So the only real issue here is the OP code? The rest you can do with a
> layer on top of the standard API.
> 
> How about something like this. Totally untested, probably does not
> even compile.....
> 
>      Andrew
> 
> From 6051479b218fd19942d702e3e051c6355fe2a11f Mon Sep 17 00:00:00 2001
> From: Andrew Lunn <andrew@lunn.ch>
> Date: Sat, 21 Dec 2019 10:31:19 -0600
> Subject: [PATCH] net: phy: Add support for microchip SMI0 MDIO bus.
> 
> SMI0 is a mangled version of MDIO. The main low level difference is
> the MDIO C22 OP code is always 0, not 0x2 or 0x1 for Read/Write. The
> read/write information is instead encoded in the PHY address.
> 
> Extend the bit-bang code to allow the op code to be overridden, but
> default to normal C22 values. Add an extra compatible to the mdio-gpio
> driver, and when this compatible is present, set the op codes to 0.
> 
> A higher level driver, sitting on top of the basic MDIO bus driver can
> then implement the rest of the microchip SMI0 odderties.
> 
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
> ---
>  drivers/net/phy/mdio-bitbang.c | 7 +++++--
>  drivers/net/phy/mdio-gpio.c    | 7 +++++++
>  include/linux/mdio-bitbang.h   | 2 ++
>  3 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
> index 5136275c8e73..01f620889c78 100644
> --- a/drivers/net/phy/mdio-bitbang.c
> +++ b/drivers/net/phy/mdio-bitbang.c
> @@ -158,7 +158,7 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
>  		reg = mdiobb_cmd_addr(ctrl, phy, reg);
>  		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
>  	} else
> -		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
> +		mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg);
>  
>  	ctrl->ops->set_mdio_dir(ctrl, 0);
>  
> @@ -189,7 +189,7 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
>  		reg = mdiobb_cmd_addr(ctrl, phy, reg);
>  		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
>  	} else
> -		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
> +		mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg);
>  
>  	/* send the turnaround (10) */
>  	mdiobb_send_bit(ctrl, 1);
> @@ -216,6 +216,9 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
>  	bus->write = mdiobb_write;
>  	bus->priv = ctrl;
>  
> +	ctrl->op_c22_read = MDIO_READ;
> +	ctrl->op_c22_write = MDIO_WRITE;
> +
>  	return bus;
>  }
>  EXPORT_SYMBOL(alloc_mdio_bitbang);
> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
> index 1b00235d7dc5..282bc38331d7 100644
> --- a/drivers/net/phy/mdio-gpio.c
> +++ b/drivers/net/phy/mdio-gpio.c
> @@ -132,6 +132,12 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
>  		new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
>  	}
>  
> +	if (dev->of_node &&
> +	    of_device_is_compatible(dev->of_node, "microchip,mdio-smi0")) {
> +		bitbang->ctrl->op_c22_read = 0;
> +		bitbang->ctrl->op_c22_write = 0;
> +	}
> +
>  	dev_set_drvdata(dev, new_bus);
>  
>  	return new_bus;
> @@ -196,6 +202,7 @@ static int mdio_gpio_remove(struct platform_device *pdev)
>  
>  static const struct of_device_id mdio_gpio_of_match[] = {
>  	{ .compatible = "virtual,mdio-gpio", },
> +	{ .compatible = "microchip,mdio-smi0" },
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, mdio_gpio_of_match);
> diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h
> index 5d71e8a8500f..8ae0b3835233 100644
> --- a/include/linux/mdio-bitbang.h
> +++ b/include/linux/mdio-bitbang.h
> @@ -33,6 +33,8 @@ struct mdiobb_ops {
>  
>  struct mdiobb_ctrl {
>  	const struct mdiobb_ops *ops;
> +	u8 op_c22_read;
> +	u8 op_c22_write;
>  };
>  
>  /* The returned bus is not yet registered with the phy layer. */
> -- 
> 2.24.0
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
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] 20+ messages in thread

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2020-01-29 15:42         ` Michael Grzeschik
@ 2020-01-29 15:53           ` Andrew Lunn
  2020-01-29 21:48             ` Michael Grzeschik
  0 siblings, 1 reply; 20+ messages in thread
From: Andrew Lunn @ 2020-01-29 15:53 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: f.fainelli, netdev, davem, kernel

On Wed, Jan 29, 2020 at 04:42:01PM +0100, Michael Grzeschik wrote:
> Hi Andrew!
> 
> I tested your patch. But it works only partially. For the case that
> the upper driver is directly communicating in SMI mode with the phy,
> this works fine. But the regular MDIO connection does not work anymore
> afterwards.
> 
> The normals MDIO communication still needs to work, as mdio-gpio is
> calling of_mdiobus_register that on the other end calls get_phy_device
> and tries to communicate via regular MDIO to the device.

Do you mean you have a mix of devices on the bus, some standards
comformant, and others using this hacked up SMI0 mode?
You need to specify per device if SMI0 should be used?

    Andrew

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

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2020-01-29 15:53           ` Andrew Lunn
@ 2020-01-29 21:48             ` Michael Grzeschik
  2020-04-21 14:31               ` Michael Grzeschik
  0 siblings, 1 reply; 20+ messages in thread
From: Michael Grzeschik @ 2020-01-29 21:48 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: f.fainelli, netdev, davem, kernel

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

On Wed, Jan 29, 2020 at 04:53:46PM +0100, Andrew Lunn wrote:
> On Wed, Jan 29, 2020 at 04:42:01PM +0100, Michael Grzeschik wrote:
> > Hi Andrew!
> > 
> > I tested your patch. But it works only partially. For the case that
> > the upper driver is directly communicating in SMI mode with the phy,
> > this works fine. But the regular MDIO connection does not work anymore
> > afterwards.
> > 
> > The normals MDIO communication still needs to work, as mdio-gpio is
> > calling of_mdiobus_register that on the other end calls get_phy_device
> > and tries to communicate via regular MDIO to the device.
> 
> Do you mean you have a mix of devices on the bus, some standards
> comformant, and others using this hacked up SMI0 mode?

Actually it is the same device used in both modes. The SMI0
mode is used by the switch driver to address the extended switch
functions. But on the same bus we have the fec connected to
the cpu bound fixed-phy (microchip,ks8863) via MDIO.

> You need to specify per device if SMI0 should be used?

Yes, we have to use the same bus fot both modes SMI0 and MDIO.

 Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
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] 20+ messages in thread

* Re: [PATCH] mdio-bitbang: add support for lowlevel mdio read/write
  2020-01-29 21:48             ` Michael Grzeschik
@ 2020-04-21 14:31               ` Michael Grzeschik
  0 siblings, 0 replies; 20+ messages in thread
From: Michael Grzeschik @ 2020-04-21 14:31 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: netdev, f.fainelli, davem, kernel

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

Hi Andrew,

I want to refresh this thread.

On Wed, Jan 29, 2020 at 10:48:05PM +0100, Michael Grzeschik wrote:
>On Wed, Jan 29, 2020 at 04:53:46PM +0100, Andrew Lunn wrote:
>> On Wed, Jan 29, 2020 at 04:42:01PM +0100, Michael Grzeschik wrote:
>> > Hi Andrew!
>> >
>> > I tested your patch. But it works only partially. For the case that
>> > the upper driver is directly communicating in SMI mode with the phy,
>> > this works fine. But the regular MDIO connection does not work anymore
>> > afterwards.
>> >
>> > The normals MDIO communication still needs to work, as mdio-gpio is
>> > calling of_mdiobus_register that on the other end calls get_phy_device
>> > and tries to communicate via regular MDIO to the device.
>>
>> Do you mean you have a mix of devices on the bus, some standards
>> comformant, and others using this hacked up SMI0 mode?
>
>Actually it is the same device used in both modes. The SMI0
>mode is used by the switch driver to address the extended switch
>functions. But on the same bus we have the fec connected to
>the cpu bound fixed-phy (microchip,ks8863) via MDIO.
>
>> You need to specify per device if SMI0 should be used?
>
>Yes, we have to use the same bus fot both modes SMI0 and MDIO.

In fact I for now used the cpu bound port with phy-handle to the fec.
This way it still used mdio for the initial probe.

But it should also work to use fixed-phy for it don't run into mdio
communication on the same bus. This way your patch should work.

In case you did not think of anything else, I will send the series
including your patch after I tested it with master.

Regards,
Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
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] 20+ messages in thread

end of thread, other threads:[~2020-04-21 14:32 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-07 11:00 [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik
2019-11-07 11:00 ` [PATCH v1 1/4] mdio-bitbang: add SMI0 mode support Michael Grzeschik
2019-11-07 15:42   ` Andrew Lunn
2019-12-18 16:29     ` [PATCH] mdio-bitbang: add support for lowlevel mdio read/write Michael Grzeschik
2019-12-19 20:39       ` Andrew Lunn
2019-12-19 22:01         ` Michael Grzeschik
2019-12-19 22:05       ` Florian Fainelli
2019-12-21 16:41       ` Andrew Lunn
2020-01-29 15:42         ` Michael Grzeschik
2020-01-29 15:53           ` Andrew Lunn
2020-01-29 21:48             ` Michael Grzeschik
2020-04-21 14:31               ` Michael Grzeschik
2019-11-07 11:00 ` [PATCH v1 2/4] net: tag: ksz: Add KSZ8863 tag code Michael Grzeschik
2019-11-07 15:44   ` Andrew Lunn
2019-11-07 11:00 ` [PATCH v1 3/4] ksz: Add Microchip KSZ8863 SMI-DSA driver Michael Grzeschik
2019-11-07 15:56   ` Andrew Lunn
2019-11-09  8:08   ` kbuild test robot
2019-11-07 11:00 ` [PATCH v1 4/4] dt-bindings: net: dsa: document additional Microchip KSZ8863/8873 switch Michael Grzeschik
2019-11-13 13:34   ` Rob Herring
2019-11-07 15:36 ` [PATCH v1 0/4] microchip: add support for ksz88x3 driver family Michael Grzeschik

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).