mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus
@ 2022-09-20 12:55 Oleksij Rempel
  2022-09-20 12:55 ` [PATCH v1 2/3] net: add support for MDIO devices Oleksij Rempel
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Oleksij Rempel @ 2022-09-20 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

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.

This code was ported from the kernel v6.0-rc2.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/net/phy/mdio-bitbang.c | 8 ++++++--
 drivers/net/phy/mdio-gpio.c    | 8 ++++++++
 include/linux/mdio-bitbang.h   | 3 +++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index 839a7d1eb8..656557589d 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);
 
@@ -188,7 +188,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);
@@ -219,6 +219,10 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 	bus->write = mdiobb_write;
 	bus->reset = mdiobb_reset;
 	bus->priv = ctrl;
+	if (!ctrl->override_op_c22) {
+		ctrl->op_c22_read = MDIO_READ;
+		ctrl->op_c22_write = MDIO_WRITE;
+	}
 
 	return bus;
 }
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 80d2394f4b..c64f2b3925 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -193,6 +193,13 @@ static int mdio_gpio_probe(struct device_d *dev)
 		goto free_mdo;
 	}
 
+	if (np &&
+	    of_device_is_compatible(np, "microchip,mdio-smi0")) {
+		info->ctrl.op_c22_read = 0;
+		info->ctrl.op_c22_write = 0;
+		info->ctrl.override_op_c22 = 1;
+	}
+
 	bus = alloc_mdio_bitbang(&info->ctrl);
 	bus->parent = dev;
 	bus->dev.device_node = np;
@@ -217,6 +224,7 @@ free_info:
 
 static const struct of_device_id gpio_mdio_dt_ids[] = {
 	{ .compatible = "virtual,mdio-gpio", },
+	{ .compatible = "microchip,mdio-smi0" },
 	{ /* sentinel */ }
 };
 
diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h
index a6e6057886..49fe435429 100644
--- a/include/linux/mdio-bitbang.h
+++ b/include/linux/mdio-bitbang.h
@@ -36,6 +36,9 @@ struct mdiobb_ctrl {
 	const struct mdiobb_ops *ops;
 	/* reset callback */
 	int (*reset)(struct mii_bus *bus);
+	unsigned int override_op_c22;
+	u8 op_c22_read;
+	u8 op_c22_write;
 };
 
 /* The returned bus is not yet registered with the phy layer. */
-- 
2.30.2




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

* [PATCH v1 2/3] net: add support for MDIO devices
  2022-09-20 12:55 [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus Oleksij Rempel
@ 2022-09-20 12:55 ` Oleksij Rempel
  2022-09-20 12:55 ` [PATCH v1 3/3] net: add ksz8873 switch support Oleksij Rempel
  2022-09-22  9:29 ` [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Oleksij Rempel @ 2022-09-20 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

On the MDIO bus we can have PHYs and some other type of devices.
Typical not_PHY MDIO devices do not have easy detectable ID and can't be
used as-is by the PHY framework. So, add additional handler to register
MDIO devices and drivers alongside with the PHY devices/drivers.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/net/phy/mdio_bus.c | 101 ++++++++++++++++++++++++++++++-------
 drivers/net/phy/phy.c      |   2 +
 include/linux/mdio.h       |  14 +++++
 include/linux/phy.h        |   1 +
 4 files changed, 101 insertions(+), 17 deletions(-)

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index e37ab79f3e..f06ab68f50 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -19,6 +19,7 @@
 #include <clock.h>
 #include <net.h>
 #include <errno.h>
+#include <linux/mdio.h>
 #include <linux/phy.h>
 #include <linux/err.h>
 #include <of_device.h>
@@ -29,6 +30,56 @@
 
 LIST_HEAD(mii_bus_list);
 
+static struct phy_device *mdio_device_create(struct mii_bus *bus, int addr)
+{
+	struct phy_device *phydev;
+
+	phydev = xzalloc(sizeof(*phydev));
+
+	phydev->addr = addr;
+	phydev->bus = bus;
+	phydev->dev.bus = &mdio_bus_type;
+
+	dev_set_name(&phydev->dev, "mdio%d-dev%02x", phydev->bus->dev.id,
+		     phydev->addr);
+	phydev->dev.id = DEVICE_ID_SINGLE;
+
+	return phydev;
+}
+
+static int mdio_register_device(struct phy_device *phydev)
+{
+	int ret;
+
+	if (phydev->registered)
+		return -EBUSY;
+
+	if (!phydev->dev.parent)
+		phydev->dev.parent = &phydev->bus->dev;
+
+	ret = register_device(&phydev->dev);
+	if (ret)
+		return ret;
+
+	if (phydev->bus)
+		phydev->bus->phy_map[phydev->addr] = phydev;
+
+	phydev->registered = 1;
+
+	if (phydev->dev.driver)
+		return 0;
+
+	return ret;
+}
+
+int mdio_driver_register(struct phy_driver *phydrv)
+{
+	phydrv->drv.bus = &mdio_bus_type;
+	phydrv->is_phy = false;
+
+	return register_driver(&phydrv->drv);
+}
+
 int mdiobus_detect(struct device_d *dev)
 {
 	struct mii_bus *mii = to_mii_bus(dev);
@@ -84,6 +135,28 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
 	return 0;
 }
 
+static int of_mdiobus_register_device(struct mii_bus *mdio,
+				      struct device_node *child, u32 addr)
+{
+	struct phy_device *mdiodev;
+	int ret;
+
+	mdiodev = mdio_device_create(mdio, addr);
+	if (IS_ERR(mdiodev))
+		return PTR_ERR(mdiodev);
+
+	mdiodev->dev.device_node = child;
+
+	ret = mdio_register_device(mdiodev);
+	if (ret)
+		return ret;
+
+	dev_dbg(&mdio->dev, "registered mdio device %s at address %i\n",
+		child->name, addr);
+
+	return 0;
+}
+
 /*
  * Node is considered a PHY node if:
  * o Compatible string of "ethernet-phy-idX.X"
@@ -176,20 +249,6 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
 
 	/* Loop over the child nodes and register a phy_device for each one */
 	for_each_available_child_of_node(np, child) {
-		if (!of_mdiobus_child_is_phy(child)) {
-			if (of_get_property(child, "compatible", NULL)) {
-				if (!of_platform_device_create(child,
-							       &mdio->dev)) {
-					dev_err(&mdio->dev,
-						"Failed to create device "
-						"for %s\n",
-						child->full_name);
-				}
-			}
-
-			continue;
-		}
-
 		ret = of_property_read_u32(child, "reg", &addr);
 		if (ret) {
 			dev_dbg(&mdio->dev, "%s has invalid PHY address\n",
@@ -205,7 +264,11 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
 
 		of_pinctrl_select_state_default(child);
 		of_mdiobus_reset_phy(mdio, child);
-		of_mdiobus_register_phy(mdio, child, addr);
+
+		if (of_mdiobus_child_is_phy(child))
+			of_mdiobus_register_phy(mdio, child, addr);
+		else
+			of_mdiobus_register_device(mdio, child, addr);
 	}
 
 	return 0;
@@ -356,9 +419,13 @@ static int mdio_bus_match(struct device_d *dev, struct driver_d *drv)
 	struct phy_device *phydev = to_phy_device(dev);
 	struct phy_driver *phydrv = to_phy_driver(drv);
 
-	if ((phydrv->phy_id & phydrv->phy_id_mask) ==
-	    (phydev->phy_id & phydrv->phy_id_mask))
+	if (phydrv->is_phy) {
+		if ((phydrv->phy_id & phydrv->phy_id_mask) ==
+		    (phydev->phy_id & phydrv->phy_id_mask))
 		return 0;
+	} else {
+		return device_match(dev, drv);
+	}
 
 	return 1;
 }
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 60b5839b40..56ec8a28df 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -933,6 +933,8 @@ int phy_driver_register(struct phy_driver *phydrv)
 {
 	phydrv->drv.bus = &mdio_bus_type;
 
+	phydrv->is_phy = true;
+
 	if (!phydrv->config_init)
 		phydrv->config_init = genphy_config_init;
 
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index b910b05cec..a4aee49d8d 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -326,4 +326,18 @@ static inline __u16 mdio_phy_id_c45(int prtad, int devad)
 
 #define MDIO_DEVAD_NONE			(-1)
 
+struct phy_driver;
+
+int mdio_driver_register(struct phy_driver *drv);
+
+#define mdio_register_driver_macro(level, drv)		\
+        static int __init drv##_register(void)		\
+        {						\
+                return mdio_driver_register(&drv);	\
+        }						\
+        level##_initcall(drv##_register)
+
+#define device_mdio_driver(drv)	\
+        mdio_register_driver_macro(device, drv)
+
 #endif /* _UAPI__LINUX_MDIO_H__ */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index a4c3f43c06..ba1740ff55 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -223,6 +223,7 @@ struct phy_driver {
 	unsigned int phy_id_mask;
 	u32 features;
 	const void *driver_data;
+	bool is_phy;
 
 	/*
 	 * Called to initialize the PHY,
-- 
2.30.2




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

* [PATCH v1 3/3] net: add ksz8873 switch support
  2022-09-20 12:55 [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus Oleksij Rempel
  2022-09-20 12:55 ` [PATCH v1 2/3] net: add support for MDIO devices Oleksij Rempel
@ 2022-09-20 12:55 ` Oleksij Rempel
  2022-09-22  9:29 ` [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Oleksij Rempel @ 2022-09-20 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

Add minimal DSA driver for the KSZ8873 switches

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/net/Kconfig   |   6 +
 drivers/net/Makefile  |   1 +
 drivers/net/ksz8873.c | 424 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 431 insertions(+)
 create mode 100644 drivers/net/ksz8873.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 84a01c5328..2dafd9c7a8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -300,6 +300,12 @@ menuconfig DSA
 
 if DSA
 
+config DRIVER_NET_KSZ8873
+	bool "KSZ8873 switch driver"
+	help
+	  This option enables support for the Microchip KSZ8873
+	  switch chip.
+
 config DRIVER_NET_KSZ9477
 	bool "KSZ9477 switch driver"
 	depends on SPI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 47ad749943..7ff330a2bf 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_DRIVER_NET_FEC_IMX)	+= fec_imx.o
 obj-$(CONFIG_DRIVER_NET_FSL_FMAN)	+= fsl-fman.o
 obj-$(CONFIG_DRIVER_NET_GIANFAR)	+= gianfar.o
 obj-$(CONFIG_DRIVER_NET_KS8851_MLL)	+= ks8851_mll.o
+obj-$(CONFIG_DRIVER_NET_KSZ8873)	+= ksz8873.o
 obj-$(CONFIG_DRIVER_NET_KSZ9477)	+= ksz9477.o
 obj-$(CONFIG_DRIVER_NET_MACB)		+= macb.o
 obj-$(CONFIG_DRIVER_NET_MICREL)		+= ksz8864rmn.o
diff --git a/drivers/net/ksz8873.c b/drivers/net/ksz8873.c
new file mode 100644
index 0000000000..bd8071b872
--- /dev/null
+++ b/drivers/net/ksz8873.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <common.h>
+#include <complete.h>
+#include <dsa.h>
+#include <gpiod.h>
+#include <linux/mii.h>
+#include <linux/mdio.h>
+#include <net.h>
+#include <of_device.h>
+#include <regmap.h>
+
+#define KSZ8873_GLOBAL_CTRL_1		0x03
+#define KSZ8873_PASS_ALL_FRAMES		BIT(7)
+#define KSZ8873_P3_TAIL_TAG_EN		BIT(6)
+
+/*
+ * port specific registers. Should be used with ksz_pwrite/ksz_pread functions
+ */
+#define KSZ8873_PORTx_CTRL_1		0x01
+#define KSZ8873_PORTx_CTRL_12		0x0c
+
+#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_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 KSZ8873_PORTx_CTRL_13		0x0d
+
+#define PORT_AUTO_NEG_RESTART		BIT(5)
+#define PORT_POWER_DOWN			BIT(3)
+
+#define KSZ8873_PORTx_STATUS_0		0x0e
+
+#define PORT_AUTO_NEG_COMPLETE		BIT(6)
+#define PORT_STAT_LINK_GOOD		BIT(5)
+#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 KSZ8873_PORTx_STATUS_1		0x0f
+
+#define KSZ8795_ID_HI			0x0022
+#define KSZ8863_ID_LO			0x1430
+
+#define PORT_CTRL_ADDR(port, addr)	((addr) + 0x10 + (port) * 0x10)
+
+struct ksz8873_dcfg {
+	unsigned int num_ports;
+	unsigned int phy_port_cnt;
+};
+
+struct ksz8873_switch {
+	struct phy_device *mdiodev;
+	struct dsa_switch ds;
+	struct device_d *dev;
+	const struct ksz8873_dcfg *dcfg;
+	struct regmap *regmap;
+};
+
+/* 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
+ *
+ */
+
+#define SMI_KSZ88XX_READ_PHY	BIT(4)
+
+static int ksz8873_mdio_read(void *ctx, unsigned int reg, unsigned int *val)
+{
+	struct ksz8873_switch *priv = ctx;
+	struct phy_device *mdiodev = priv->mdiodev;
+	int ret;
+
+	ret = mdiobus_read(mdiodev->bus, ((reg & 0xE0) >> 5) |
+			     SMI_KSZ88XX_READ_PHY, reg);
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+
+	return 0;
+}
+
+static ssize_t ksz8873_mdio_write(void *ctx, unsigned int reg, unsigned int val)
+{
+	struct ksz8873_switch *priv = ctx;
+	struct phy_device *mdiodev = priv->mdiodev;
+
+	return mdiobus_write(mdiodev->bus, ((reg & 0xE0) >> 5), reg, val);
+}
+
+static const struct regmap_bus ksz8873_regmap_smi = {
+	.reg_read = ksz8873_mdio_read,
+	.reg_write = ksz8873_mdio_write,
+};
+
+static const struct regmap_config ksz8873_regmap_config = {
+	.name = "#8",
+	.reg_bits = 8,
+	.pad_bits = 24,
+	.val_bits = 8,
+};
+
+static int ksz_read8(struct ksz8873_switch *priv, u32 reg, u8 *val)
+{
+	unsigned int value;
+	int ret = regmap_read(priv->regmap, reg, &value);
+
+	*val = value & 0xff;
+
+	return ret;
+}
+
+static int ksz_write8(struct ksz8873_switch *priv, u32 reg, u8 value)
+{
+	return regmap_write(priv->regmap, reg, value);
+}
+
+static int ksz_pread8(struct ksz8873_switch *priv, int port, int reg, u8 *val)
+{
+	return ksz_read8(priv, PORT_CTRL_ADDR(port, reg), val);
+}
+
+static int ksz_pwrite8(struct ksz8873_switch *priv, int port, int reg, u8 val)
+{
+	return ksz_write8(priv, PORT_CTRL_ADDR(port, reg), val);
+}
+
+static void ksz8_r_phy(struct ksz8873_switch *priv, u16 phy, u16 reg, u16 *val)
+{
+	u8 restart, ctrl, link;
+	int processed = true;
+	u16 data = 0;
+	u8 p = phy;
+
+	switch (reg) {
+	case MII_BMCR:
+		ksz_pread8(priv, p, KSZ8873_PORTx_CTRL_13, &restart);
+		ksz_pread8(priv, p, KSZ8873_PORTx_CTRL_12, &ctrl);
+		if (ctrl & PORT_FORCE_100_MBIT)
+			data |= BMCR_SPEED100;
+		if ((ctrl & PORT_AUTO_NEG_ENABLE))
+			data |= BMCR_ANENABLE;
+		if (restart & PORT_POWER_DOWN)
+			data |= BMCR_PDOWN;
+		if (restart & PORT_AUTO_NEG_RESTART)
+			data |= BMCR_ANRESTART;
+		if (ctrl & PORT_FORCE_FULL_DUPLEX)
+			data |= BMCR_FULLDPLX;
+		break;
+	case MII_BMSR:
+		ksz_pread8(priv, p, KSZ8873_PORTx_STATUS_0, &link);
+		data = BMSR_100FULL |
+		       BMSR_100HALF |
+		       BMSR_10FULL |
+		       BMSR_10HALF |
+		       BMSR_ANEGCAPABLE;
+		if (link & PORT_AUTO_NEG_COMPLETE)
+			data |= BMSR_ANEGCOMPLETE;
+		if (link & PORT_STAT_LINK_GOOD)
+			data |= BMSR_LSTATUS;
+		break;
+	case MII_PHYSID1:
+		data = KSZ8795_ID_HI;
+		break;
+	case MII_PHYSID2:
+		data = KSZ8863_ID_LO;
+		break;
+	case MII_ADVERTISE:
+		ksz_pread8(priv, p, KSZ8873_PORTx_CTRL_12, &ctrl);
+		data = ADVERTISE_CSMA;
+		if (ctrl & PORT_AUTO_NEG_100BTX_FD)
+			data |= ADVERTISE_100FULL;
+		if (ctrl & PORT_AUTO_NEG_100BTX)
+			data |= ADVERTISE_100HALF;
+		if (ctrl & PORT_AUTO_NEG_10BT_FD)
+			data |= ADVERTISE_10FULL;
+		if (ctrl & PORT_AUTO_NEG_10BT)
+			data |= ADVERTISE_10HALF;
+		break;
+	case MII_LPA:
+		ksz_pread8(priv, p, KSZ8873_PORTx_STATUS_0, &link);
+		data = LPA_SLCT;
+		if (link & PORT_REMOTE_100BTX_FD)
+			data |= LPA_100FULL;
+		if (link & PORT_REMOTE_100BTX)
+			data |= LPA_100HALF;
+		if (link & PORT_REMOTE_10BT_FD)
+			data |= LPA_10FULL;
+		if (link & PORT_REMOTE_10BT)
+			data |= LPA_10HALF;
+		if (data & ~LPA_SLCT)
+			data |= LPA_LPACK;
+		break;
+	default:
+		processed = false;
+		break;
+	}
+	if (processed)
+		*val = data;
+}
+
+static void ksz8_w_phy(struct ksz8873_switch *priv, u16 phy, u16 reg, u16 val)
+{
+	u8 restart, ctrl, data;
+	u8 p = phy;
+
+	switch (reg) {
+	case MII_BMCR:
+		ksz_pread8(priv, p, KSZ8873_PORTx_CTRL_12, &ctrl);
+		data = ctrl;
+		if ((val & BMCR_ANENABLE))
+			data |= PORT_AUTO_NEG_ENABLE;
+		else
+			data &= ~PORT_AUTO_NEG_ENABLE;
+
+		if (val & BMCR_SPEED100)
+			data |= PORT_FORCE_100_MBIT;
+		else
+			data &= ~PORT_FORCE_100_MBIT;
+		if (val & BMCR_FULLDPLX)
+			data |= PORT_FORCE_FULL_DUPLEX;
+		else
+			data &= ~PORT_FORCE_FULL_DUPLEX;
+		if (data != ctrl)
+			ksz_pwrite8(priv, p, KSZ8873_PORTx_CTRL_12, data);
+		ksz_pread8(priv, p, KSZ8873_PORTx_CTRL_13, &restart);
+		data = restart;
+		if (val & BMCR_ANRESTART)
+			data |= PORT_AUTO_NEG_RESTART;
+		else
+			data &= ~(PORT_AUTO_NEG_RESTART);
+		if (val & BMCR_PDOWN)
+			data |= PORT_POWER_DOWN;
+		else
+			data &= ~PORT_POWER_DOWN;
+		if (data != restart)
+			ksz_pwrite8(priv, p, KSZ8873_PORTx_CTRL_13, data);
+		break;
+	case MII_ADVERTISE:
+		ksz_pread8(priv, p, KSZ8873_PORTx_CTRL_12, &ctrl);
+		data = ctrl;
+		data &= ~(PORT_AUTO_NEG_100BTX_FD |
+			  PORT_AUTO_NEG_100BTX |
+			  PORT_AUTO_NEG_10BT_FD |
+			  PORT_AUTO_NEG_10BT);
+		if (val & ADVERTISE_100FULL)
+			data |= PORT_AUTO_NEG_100BTX_FD;
+		if (val & ADVERTISE_100HALF)
+			data |= PORT_AUTO_NEG_100BTX;
+		if (val & ADVERTISE_10FULL)
+			data |= PORT_AUTO_NEG_10BT_FD;
+		if (val & ADVERTISE_10HALF)
+			data |= PORT_AUTO_NEG_10BT;
+		if (data != ctrl)
+			ksz_pwrite8(priv, p, KSZ8873_PORTx_CTRL_12, data);
+		break;
+	default:
+		break;
+	}
+}
+
+static int ksz8873_phy_read16(struct dsa_switch *ds, int addr, int reg)
+{
+	struct device_d *dev = ds->dev;
+	struct ksz8873_switch *priv = dev_get_priv(dev);
+	u16 val = 0xffff;
+
+	if (addr >= priv->dcfg->phy_port_cnt)
+		return val;
+
+	ksz8_r_phy(priv, addr, reg, &val);
+
+	return val;
+}
+
+static int ksz8873_phy_write16(struct dsa_switch *ds, int addr, int reg,
+			       u16 val)
+{
+	struct device_d *dev = ds->dev;
+	struct ksz8873_switch *priv = dev_get_priv(dev);
+
+	/* No real PHY after this. */
+	if (addr >= priv->dcfg->phy_port_cnt)
+		return 0;
+
+	ksz8_w_phy(priv, addr, reg, val);
+
+	return 0;
+}
+
+static void ksz8873_cfg_port_member(struct ksz8873_switch *priv, int port,
+				    u8 member)
+{
+	ksz_pwrite8(priv, port, KSZ8873_PORTx_CTRL_1, member);
+}
+
+static int ksz8873_port_enable(struct dsa_port *dp, int port,
+			   struct phy_device *phy)
+{
+	return 0;
+}
+
+static int ksz8873_xmit(struct dsa_port *dp, int port, void *packet, int length)
+{
+	u8 *tag = packet + length - dp->ds->needed_tx_tailroom;
+
+	*tag = BIT(dp->index);
+
+	return 0;
+}
+
+static int ksz8873_recv(struct dsa_switch *ds, int *port, void *packet,
+			int length)
+{
+	u8 *tag = packet + length - ds->needed_rx_tailroom;
+
+	*port = *tag & 7;
+
+	return 0;
+};
+
+static const struct dsa_ops ksz8873_dsa_ops = {
+	.port_enable = ksz8873_port_enable,
+	.xmit = ksz8873_xmit,
+	.rcv = ksz8873_recv,
+	.phy_read = ksz8873_phy_read16,
+	.phy_write = ksz8873_phy_write16,
+};
+
+static int ksz8873_default_setup(struct ksz8873_switch *priv)
+{
+	int i;
+
+	ksz_write8(priv, KSZ8873_GLOBAL_CTRL_1, KSZ8873_PASS_ALL_FRAMES |
+		   KSZ8873_P3_TAIL_TAG_EN);
+
+	for (i = 0; i < priv->ds.num_ports; i++) {
+		u8 member;
+		/* isolate all ports by default */
+		member = BIT(priv->ds.cpu_port);
+		ksz8873_cfg_port_member(priv, i, member);
+
+		member = dsa_user_ports(&priv->ds);
+		ksz8873_cfg_port_member(priv, priv->ds.cpu_port, member);
+	}
+
+	return 0;
+}
+
+static int ksz8873_probe_mdio(struct phy_device *mdiodev)
+{
+	struct device_d *dev = &mdiodev->dev;
+	const struct ksz8873_dcfg *dcfg;
+	struct ksz8873_switch *priv;
+	struct dsa_switch *ds;
+	int ret, gpio;
+
+	priv = xzalloc(sizeof(*priv));
+
+	dcfg = of_device_get_match_data(dev);
+	if (!dcfg)
+		return -EINVAL;
+
+	dev->priv = priv;
+	priv->dev = dev;
+	priv->dcfg = dcfg;
+	priv->mdiodev = mdiodev;
+
+	priv->regmap = regmap_init(dev, &ksz8873_regmap_smi, priv,
+				   &ksz8873_regmap_config);
+	if (IS_ERR(priv->regmap))
+		return dev_err_probe(dev, PTR_ERR(priv->regmap),
+				     "Failed to initialize regmap.\n");
+
+	gpio = gpiod_get(dev, "reset", GPIOF_OUT_INIT_ACTIVE);
+	if (gpio_is_valid(gpio)) {
+		mdelay(1);
+		gpio_set_active(gpio, false);
+	}
+
+	ds = &priv->ds;
+	ds->dev = dev;
+	ds->num_ports = dcfg->num_ports;
+	ds->ops = &ksz8873_dsa_ops;
+	ds->needed_rx_tailroom = 1;
+	ds->needed_tx_tailroom = 1;
+	ds->phys_mii_mask = 0x3;
+
+	ret = dsa_register_switch(ds);
+	if (ret)
+		return ret;
+
+	ksz8873_default_setup(priv);
+
+	return 0;
+}
+
+static const struct ksz8873_dcfg ksz8873_dcfg = {
+	.num_ports = 3,
+	.phy_port_cnt = 2,
+};
+
+static const struct of_device_id ksz8873_dt_ids[] = {
+	{ .compatible = "microchip,ksz8873", .data = &ksz8873_dcfg },
+	{ }
+};
+
+static struct phy_driver ksz8873_driver_mdio = {
+	.drv = {
+		.name = "KSZ8873 MDIO",
+		.of_compatible = DRV_OF_COMPAT(ksz8873_dt_ids),
+	},
+	.probe = ksz8873_probe_mdio,
+};
+device_mdio_driver(ksz8873_driver_mdio);
-- 
2.30.2




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

* Re: [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus
  2022-09-20 12:55 [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus Oleksij Rempel
  2022-09-20 12:55 ` [PATCH v1 2/3] net: add support for MDIO devices Oleksij Rempel
  2022-09-20 12:55 ` [PATCH v1 3/3] net: add ksz8873 switch support Oleksij Rempel
@ 2022-09-22  9:29 ` Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2022-09-22  9:29 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox

On Tue, Sep 20, 2022 at 02:55:31PM +0200, Oleksij Rempel wrote:
> 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.
> 
> This code was ported from the kernel v6.0-rc2.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/net/phy/mdio-bitbang.c | 8 ++++++--
>  drivers/net/phy/mdio-gpio.c    | 8 ++++++++
>  include/linux/mdio-bitbang.h   | 3 +++
>  3 files changed, 17 insertions(+), 2 deletions(-)

Applied, thanks

Sascha

> 
> diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
> index 839a7d1eb8..656557589d 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);
>  
> @@ -188,7 +188,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);
> @@ -219,6 +219,10 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
>  	bus->write = mdiobb_write;
>  	bus->reset = mdiobb_reset;
>  	bus->priv = ctrl;
> +	if (!ctrl->override_op_c22) {
> +		ctrl->op_c22_read = MDIO_READ;
> +		ctrl->op_c22_write = MDIO_WRITE;
> +	}
>  
>  	return bus;
>  }
> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
> index 80d2394f4b..c64f2b3925 100644
> --- a/drivers/net/phy/mdio-gpio.c
> +++ b/drivers/net/phy/mdio-gpio.c
> @@ -193,6 +193,13 @@ static int mdio_gpio_probe(struct device_d *dev)
>  		goto free_mdo;
>  	}
>  
> +	if (np &&
> +	    of_device_is_compatible(np, "microchip,mdio-smi0")) {
> +		info->ctrl.op_c22_read = 0;
> +		info->ctrl.op_c22_write = 0;
> +		info->ctrl.override_op_c22 = 1;
> +	}
> +
>  	bus = alloc_mdio_bitbang(&info->ctrl);
>  	bus->parent = dev;
>  	bus->dev.device_node = np;
> @@ -217,6 +224,7 @@ free_info:
>  
>  static const struct of_device_id gpio_mdio_dt_ids[] = {
>  	{ .compatible = "virtual,mdio-gpio", },
> +	{ .compatible = "microchip,mdio-smi0" },
>  	{ /* sentinel */ }
>  };
>  
> diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h
> index a6e6057886..49fe435429 100644
> --- a/include/linux/mdio-bitbang.h
> +++ b/include/linux/mdio-bitbang.h
> @@ -36,6 +36,9 @@ struct mdiobb_ctrl {
>  	const struct mdiobb_ops *ops;
>  	/* reset callback */
>  	int (*reset)(struct mii_bus *bus);
> +	unsigned int override_op_c22;
> +	u8 op_c22_read;
> +	u8 op_c22_write;
>  };
>  
>  /* The returned bus is not yet registered with the phy layer. */
> -- 
> 2.30.2
> 
> 
> 

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



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

end of thread, other threads:[~2022-09-22  9:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-20 12:55 [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus Oleksij Rempel
2022-09-20 12:55 ` [PATCH v1 2/3] net: add support for MDIO devices Oleksij Rempel
2022-09-20 12:55 ` [PATCH v1 3/3] net: add ksz8873 switch support Oleksij Rempel
2022-09-22  9:29 ` [PATCH v1 1/3] net: port support for microchip SMI0 MDIO bus Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox