realtek: Add driver for auxiliary MDIO busses
authorSander Vanheule <sander@svanheule.net>
Fri, 27 Dec 2024 14:53:23 +0000 (15:53 +0100)
committerSander Vanheule <sander@svanheule.net>
Tue, 7 Jan 2025 13:36:34 +0000 (14:36 +0100)
Add a driver that exposes the auxiliary busses, used for the RTL8231
expanders, as a proper MDIO controller. The device must be instantiated
under an MFD device, so the driver should also be compatible with SoC
managed by an external CPU via SPI.

Leave the driver disabled in builds until required.

Signed-off-by: Sander Vanheule <sander@svanheule.net>
target/linux/realtek/patches-6.6/723-net-mdio-Add-Realtek-Otto-auxiliary-controller.patch [new file with mode: 0644]
target/linux/realtek/rtl838x/config-6.6
target/linux/realtek/rtl839x/config-6.6
target/linux/realtek/rtl930x/config-6.6
target/linux/realtek/rtl931x/config-6.6

diff --git a/target/linux/realtek/patches-6.6/723-net-mdio-Add-Realtek-Otto-auxiliary-controller.patch b/target/linux/realtek/patches-6.6/723-net-mdio-Add-Realtek-Otto-auxiliary-controller.patch
new file mode 100644 (file)
index 0000000..430f8f5
--- /dev/null
@@ -0,0 +1,193 @@
+From c7ddb74c981c1a29bad82d555d08724aca93b687 Mon Sep 17 00:00:00 2001
+From: Sander Vanheule <sander@svanheule.net>
+Date: Fri, 27 Dec 2024 14:55:31 +0100
+Subject: [PATCH] net: mdio: Add Realtek Otto auxiliary controller
+
+SoCs in Realtek's Otto platform such as the RTL8380 and RTL8391 have a
+simple auxiliary MDIO controller that is commonly used to manage RTL8231
+GPIO expanders on switch devices.
+
+Add a new MDIO controller driver supporting the RTL838x (maple) and
+RTL839x (cypress) SoCs.
+
+Signed-off-by: Sander Vanheule <sander@svanheule.net>
+---
+ drivers/net/mdio/Kconfig                 |  10 ++
+ drivers/net/mdio/Makefile                |   1 +
+ drivers/net/mdio/mdio-realtek-otto-aux.c | 129 +++++++++++++++++++++++
+ 3 files changed, 140 insertions(+)
+ create mode 100644 drivers/net/mdio/mdio-realtek-otto-aux.c
+
+--- a/drivers/net/mdio/Kconfig
++++ b/drivers/net/mdio/Kconfig
+@@ -207,6 +207,16 @@ config MDIO_REGMAP
+         regmap. Users willing to use this driver must explicitly select
+         REGMAP.
++config MDIO_REALTEK_OTTO_AUX
++      tristate "Realtek Otto auxiliary MDIO interface support"
++      default MACH_REALTEK_RTL
++      depends on MACH_REALTEK_RTL
++      depends on MFD_SYSCON
++      select MDIO_DEVRES
++      help
++        This driver supports the auxilairy MDIO bus on RTL838x SoCs. This bus
++        is typically used to attach RTL8231 GPIO extenders.
++
+ config MDIO_THUNDER
+       tristate "ThunderX SOCs MDIO buses"
+       depends on 64BIT
+--- a/drivers/net/mdio/Makefile
++++ b/drivers/net/mdio/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_MDIO_MSCC_MIIM)         += mdio-ms
+ obj-$(CONFIG_MDIO_MVUSB)              += mdio-mvusb.o
+ obj-$(CONFIG_MDIO_OCTEON)             += mdio-octeon.o
+ obj-$(CONFIG_MDIO_REGMAP)             += mdio-regmap.o
++obj-$(CONFIG_MDIO_REALTEK_OTTO_AUX)   += mdio-realtek-otto-aux.o
+ obj-$(CONFIG_MDIO_SMBUS)              += mdio-smbus.o
+ obj-$(CONFIG_MDIO_SUN4I)              += mdio-sun4i.o
+ obj-$(CONFIG_MDIO_THUNDER)            += mdio-thunder.o
+--- /dev/null
++++ b/drivers/net/mdio/mdio-realtek-otto-aux.c
+@@ -0,0 +1,141 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++
++#include <linux/mfd/core.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_mdio.h>
++#include <linux/of_platform.h>
++#include <linux/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++
++#define RTL8380_EXT_GPIO_INDIRECT_ACCESS      0xA09C
++#define RTL8390_EXT_GPIO_INDIRECT_ACCESS      0x0224
++
++#define RTL83XX_AUX_MDIO_DATA                 GENMASK(31, 16)
++#define RTL83XX_AUX_MDIO_REG                  GENMASK(11, 7)
++#define RTL83XX_AUX_MDIO_PHY_ADDR             GENMASK(6, 2)
++#define RTL83XX_AUX_MDIO_WRITE                        BIT(1)
++#define RTL83XX_AUX_MDIO_READ                 0
++#define RTL83XX_AUX_MDIO_EXEC                 BIT(0)
++
++struct realtek_aux_mdio_ctrl {
++      struct device *dev;
++      struct regmap *map;
++      unsigned int cmd_reg;
++};
++
++#define mii_bus_to_ctrl(bus)  ((struct realtek_aux_mdio_ctrl *) bus->priv)
++
++static int rtl83xx_aux_mdio_cmd(struct realtek_aux_mdio_ctrl *ctrl, int addr, int regnum,
++              u32 rw_bit, u16 *data)
++{
++      unsigned int mask_volatile;
++      unsigned int cmd;
++      unsigned int run;
++      int err;
++
++      cmd = rw_bit | RTL83XX_AUX_MDIO_EXEC;
++      cmd |= FIELD_PREP(RTL83XX_AUX_MDIO_PHY_ADDR, addr);
++      cmd |= FIELD_PREP(RTL83XX_AUX_MDIO_REG, regnum);
++
++      mask_volatile = RTL83XX_AUX_MDIO_EXEC;
++
++      if (rw_bit == RTL83XX_AUX_MDIO_WRITE)
++              cmd |= FIELD_PREP(RTL83XX_AUX_MDIO_DATA, *data);
++      else
++              mask_volatile |= RTL83XX_AUX_MDIO_DATA;
++
++      err = regmap_write(ctrl->map, ctrl->cmd_reg, cmd);
++      if (err)
++              return err;
++
++      err = regmap_read_poll_timeout(ctrl->map, ctrl->cmd_reg, run, (run != cmd), 3, 100);
++
++      if ((run & ~mask_volatile) != (cmd & ~mask_volatile)) {
++              dev_err(ctrl->dev, "Command modified. Is offloading still active?");
++              return -EIO;
++      }
++
++      if (!err && (rw_bit == RTL83XX_AUX_MDIO_READ))
++              *data = FIELD_GET(RTL83XX_AUX_MDIO_DATA, run);
++
++      return err;
++}
++
++static int rtl83xx_aux_mdio_read(struct mii_bus *bus, int addr, int regnum)
++{
++      struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
++      u16 data;
++      int err;
++
++      err = rtl83xx_aux_mdio_cmd(ctrl, addr, regnum, RTL83XX_AUX_MDIO_READ, &data);
++
++      if (err)
++              return err;
++      else
++              return data;
++}
++
++static int rtl83xx_aux_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
++{
++      struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
++
++      return rtl83xx_aux_mdio_cmd(ctrl, addr, regnum, RTL83XX_AUX_MDIO_WRITE, &val);
++}
++
++static int realtek_aux_mdio_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct realtek_aux_mdio_ctrl *ctrl;
++      struct mii_bus *bus;
++
++      bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*ctrl));
++      if (!bus)
++              return -ENOMEM;
++
++      ctrl = bus->priv;
++      ctrl->dev = &pdev->dev;
++      ctrl->cmd_reg = (unsigned int) device_get_match_data(ctrl->dev);
++      ctrl->map = syscon_node_to_regmap(np->parent);
++      if (IS_ERR(ctrl->map))
++              return PTR_ERR(ctrl->map);
++
++      bus->name = "RTL83xx auxiliary MDIO bus";
++      snprintf(bus->id, MII_BUS_ID_SIZE, "rtl83xx-aux-mdio") ;
++      bus->parent = ctrl->dev;
++      bus->read = rtl83xx_aux_mdio_read;
++      bus->write = rtl83xx_aux_mdio_write;
++      /* Don't have interrupts */
++      for (unsigned int i = 0; i < PHY_MAX_ADDR; i++)
++              bus->irq[i] = PHY_POLL;
++
++      return devm_of_mdiobus_register(ctrl->dev, bus, np);
++}
++
++static const struct of_device_id realtek_aux_mdio_of_match[] = {
++      {
++              .compatible = "realtek,rtl8380-aux-mdio",
++              .data = (void *) RTL8380_EXT_GPIO_INDIRECT_ACCESS,
++      },
++      {
++              .compatible = "realtek,rtl8390-aux-mdio",
++              .data = (void *) RTL8390_EXT_GPIO_INDIRECT_ACCESS,
++      },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, realtek_aux_mdio_of_match);
++
++static struct platform_driver realtek_aux_mdio_driver = {
++      .driver = {
++              .name = "realtek-otto-aux-mdio",
++              .of_match_table = realtek_aux_mdio_of_match
++      },
++      .probe = realtek_aux_mdio_probe,
++};
++module_platform_driver(realtek_aux_mdio_driver);
++
++MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
++MODULE_DESCRIPTION("Realtek RTL83xx auxiliary MDIO bus");
++MODULE_LICENSE("GPL v2");
index a190a69ec66c6b7de8f7260e5a12f73b95de5917..6cceded5af55de667dac279d5f5fe20a75ac667f 100644 (file)
@@ -130,6 +130,7 @@ CONFIG_MDIO_BUS=y
 CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
+# CONFIG_MDIO_REALTEK_OTTO_AUX is not set
 CONFIG_MDIO_SMBUS=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
index 53a167e8f70e11eaaa295143c38053b10f561361..ebf473db61c814d2293528e88408f15f94702310 100644 (file)
@@ -130,6 +130,7 @@ CONFIG_MDIO_BUS=y
 CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
+# CONFIG_MDIO_REALTEK_OTTO_AUX is not set
 CONFIG_MDIO_SMBUS=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
index a6a23ebcffc9bf584546eee31017a5e8736bdbb1..35d088fe08984db0d5743e8f5d48db43713720cf 100644 (file)
@@ -112,6 +112,7 @@ CONFIG_MDIO_BUS=y
 CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
+# CONFIG_MDIO_REALTEK_OTTO_AUX is not set
 CONFIG_MDIO_SMBUS=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
index 9d332cee27ac0be093f2b9094ce113b8b13508b5..d843382f515448ec929dc9ecf4864de7590c07a0 100644 (file)
@@ -120,6 +120,7 @@ CONFIG_MDIO_BUS=y
 CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
+# CONFIG_MDIO_REALTEK_OTTO_AUX is not set
 CONFIG_MDIO_SMBUS=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y