linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/4] RTL9300 MDIO driver
@ 2025-01-31  1:01 Chris Packham
  2025-01-31  1:01 ` [PATCH v5 1/4] dt-bindings: net: Add Realtek MDIO controller Chris Packham
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Chris Packham @ 2025-01-31  1:01 UTC (permalink / raw)
  To: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen
  Cc: devicetree, linux-kernel, netdev, linux-mips, Chris Packham

This series adds a driver for the MDIO controller on the RTL9300 family
of devices. The controller is a little unique in that we can't access the SMI
interfaces directly. This means we need to use the hardware description from
the DTS to compute a mapping of switch port to mdio bus/address.

Note that the dt-bindings: mfd patch is dependent on the dt-bindings: net patch.

Gmail seems to have decided to throttle mail coming from our domain so there
has been some things I've responded to that have hit lore.kernel.org but may
not have been delivered directly. So sorry if it looks like I've ignored
something. That's also why I haven't send this round out earlier as hopefully
we've done enough to get of Google's naughty list.

Chris Packham (4):
  dt-bindings: net: Add Realtek MDIO controller
  dt-bindings: mfd: Add MDIO interface to rtl9301-switch
  mips: dts: realtek: Add MDIO controller
  net: mdio: Add RTL9300 MDIO driver

 .../bindings/mfd/realtek,rtl9301-switch.yaml  |  29 ++
 .../bindings/net/realtek,rtl9301-mdio.yaml    |  98 ++++
 arch/mips/boot/dts/realtek/rtl930x.dtsi       |  33 ++
 drivers/net/mdio/Kconfig                      |   7 +
 drivers/net/mdio/Makefile                     |   1 +
 drivers/net/mdio/mdio-realtek-rtl9300.c       | 436 ++++++++++++++++++
 6 files changed, 604 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl9301-mdio.yaml
 create mode 100644 drivers/net/mdio/mdio-realtek-rtl9300.c

-- 
2.48.1


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

* [PATCH v5 1/4] dt-bindings: net: Add Realtek MDIO controller
  2025-01-31  1:01 [PATCH v5 0/4] RTL9300 MDIO driver Chris Packham
@ 2025-01-31  1:01 ` Chris Packham
  2025-01-31  7:31   ` Krzysztof Kozlowski
  2025-01-31  1:01 ` [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch Chris Packham
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Chris Packham @ 2025-01-31  1:01 UTC (permalink / raw)
  To: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen
  Cc: devicetree, linux-kernel, netdev, linux-mips, Chris Packham

Add dtschema for the MDIO controller found in the RTL9300 SoCs. The
controller is slightly unusual in that direct MDIO communication is not
possible. We model the MDIO controller with the MDIO buses as child
nodes and the PHYs as children of the buses. Because we do need the
switch port number to actually communicate over the MDIO bus this needs
to be supplied via the "realtek,port" property.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---

Notes:
    Changes in v5:
    - Add back reg property to mdio-controller node
    - Make unit address in the node name required
    - Andrew suggested perhaps doing away with the realtek,port property and
      providing the overall mapping via an array of phandles. I've explored
      this a little, it is doable but I'm not sure it actually makes things
      any clearer when the portmap has gaps so I haven't made this change.
    Changes in v4:
    - Model the MDIO controller with the buses as child nodes. We still need
      to deal with the switch port number so this is represented with the
      "realtek,port" property which needs to be added to the MDIO bus
      children (i.e. the PHYs)
    - Because the above is quite a departure from earlier I've dropped the
      r-by
    Changes in v3:
    - Add r-by from Connor
    Changes in v2:
    - None

 .../bindings/net/realtek,rtl9301-mdio.yaml    | 98 +++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl9301-mdio.yaml

diff --git a/Documentation/devicetree/bindings/net/realtek,rtl9301-mdio.yaml b/Documentation/devicetree/bindings/net/realtek,rtl9301-mdio.yaml
new file mode 100644
index 000000000000..80456dc791eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/realtek,rtl9301-mdio.yaml
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/realtek,rtl9301-mdio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Realtek RTL9300 MDIO Controller
+
+maintainers:
+  - Chris Packham <chris.packham@alliedtelesis.co.nz>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - realtek,rtl9302b-mdio
+              - realtek,rtl9302c-mdio
+              - realtek,rtl9303-mdio
+          - const: realtek,rtl9301-mdio
+      - const: realtek,rtl9301-mdio
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  reg:
+    maxItems: 1
+
+patternProperties:
+  '^mdio-bus@[0-4]$':
+    $ref: mdio.yaml#
+
+    properties:
+      reg:
+        maxItems: 1
+
+    required:
+      - reg
+
+    patternProperties:
+      '^ethernet-phy@[a-f0-9]+$':
+        type: object
+        $ref: ethernet-phy.yaml#
+
+        properties:
+          realtek,port:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description:
+              The MDIO communication on the RTL9300 is abstracted by the switch. At
+              the software level communication uses the switch port to address the
+              PHY with the actual MDIO bus and address having been setup via the
+              parent mdio-bus and reg property.
+
+        unevaluatedProperties: false
+
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    mdio-controller@ca00 {
+      compatible = "realtek,rtl9301-mdio";
+      reg = <0xca00 0x200>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      mdio-bus@0 {
+        reg = <0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ethernet-phy@0 {
+          compatible = "ethernet-phy-ieee802.3-c45";
+          reg = <0>;
+          realtek,port = <0>;
+        };
+      };
+
+      mdio-bus@1 {
+        reg = <1>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ethernet-phy@0 {
+          compatible = "ethernet-phy-ieee802.3-c45";
+          reg = <0>;
+          realtek,port = <8>;
+        };
+      };
+    };
-- 
2.48.1


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

* [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch
  2025-01-31  1:01 [PATCH v5 0/4] RTL9300 MDIO driver Chris Packham
  2025-01-31  1:01 ` [PATCH v5 1/4] dt-bindings: net: Add Realtek MDIO controller Chris Packham
@ 2025-01-31  1:01 ` Chris Packham
  2025-01-31  6:35   ` Daniel Golle
  2025-01-31  7:33   ` Krzysztof Kozlowski
  2025-01-31  1:01 ` [PATCH v5 3/4] mips: dts: realtek: Add MDIO controller Chris Packham
  2025-01-31  1:01 ` [PATCH v5 4/4] net: mdio: Add RTL9300 MDIO driver Chris Packham
  3 siblings, 2 replies; 10+ messages in thread
From: Chris Packham @ 2025-01-31  1:01 UTC (permalink / raw)
  To: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen
  Cc: devicetree, linux-kernel, netdev, linux-mips, Chris Packham

The MDIO controller is part of the switch on the RTL9300 family of
devices. Add a $ref to the mfd binding for these devices.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---

Notes:
    This patch is dependent on "dt-bindings: net: Add Realtek MDIO
    controller" which adds the realtek,rtl9301-mdio.yaml binding.
    
    Changes in v5:
    - Note dependency on realtek,rtl9301-mdio.yaml patch
    - Add back reg property to the mdio-controller node.
    Changes in v4:
    - There is a single MDIO controller that has MDIO buses as children
    Changes in v3:
    - None
    Changes in v2:
    - None

 .../bindings/mfd/realtek,rtl9301-switch.yaml  | 29 +++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
index f053303ab1e6..89e10213a4ee 100644
--- a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
+++ b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
@@ -28,6 +28,9 @@ properties:
   reg:
     maxItems: 1
 
+  mdio-controller:
+    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
+
   '#address-cells':
     const: 1
 
@@ -41,6 +44,10 @@ patternProperties:
   'i2c@[0-9a-f]+$':
     $ref: /schemas/i2c/realtek,rtl9301-i2c.yaml#
 
+  'mdio-controller@[0-9a-f]+$':
+    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
+
+
 required:
   - compatible
   - reg
@@ -110,5 +117,27 @@ examples:
           };
         };
       };
+
+      mdio-controller@ca00 {
+        compatible = "realtek,rtl9301-mdio";
+        reg = <0xca00 0x200>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        mdio-bus@0 {
+          reg = <0>;
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          ethernet-phy@0 {
+            reg = <0>;
+            realtek,port = <1>;
+          };
+          ethernet-phy@1 {
+            reg = <1>;
+            realtek,port = <0>;
+          };
+        };
+      };
     };
 
-- 
2.48.1


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

* [PATCH v5 3/4] mips: dts: realtek: Add MDIO controller
  2025-01-31  1:01 [PATCH v5 0/4] RTL9300 MDIO driver Chris Packham
  2025-01-31  1:01 ` [PATCH v5 1/4] dt-bindings: net: Add Realtek MDIO controller Chris Packham
  2025-01-31  1:01 ` [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch Chris Packham
@ 2025-01-31  1:01 ` Chris Packham
  2025-01-31  1:01 ` [PATCH v5 4/4] net: mdio: Add RTL9300 MDIO driver Chris Packham
  3 siblings, 0 replies; 10+ messages in thread
From: Chris Packham @ 2025-01-31  1:01 UTC (permalink / raw)
  To: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen
  Cc: devicetree, linux-kernel, netdev, linux-mips, Chris Packham

Add a device tree node for the MDIO controller on the RTL9300 chips.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---

Notes:
    Changes in v5:
    - Add reg property to mdio-controller
    Changes in v4:
    - Have a single mdio-controller with the individual buses as child
      nodes
    Changes in v3:
    - None
    Changes in v2:
    - None

 arch/mips/boot/dts/realtek/rtl930x.dtsi | 33 +++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/arch/mips/boot/dts/realtek/rtl930x.dtsi b/arch/mips/boot/dts/realtek/rtl930x.dtsi
index f2e57ea3a60c..101bab72a95f 100644
--- a/arch/mips/boot/dts/realtek/rtl930x.dtsi
+++ b/arch/mips/boot/dts/realtek/rtl930x.dtsi
@@ -69,6 +69,39 @@ i2c1: i2c@388 {
 			#size-cells = <0>;
 			status = "disabled";
 		};
+
+		mdio_controller: mdio-controller@ca00 {
+			compatible = "realtek,rtl9301-mdio";
+			reg = <0xca00 0x200>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			mdio0: mdio-bus@0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+			mdio1: mdio-bus@1 {
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+			mdio2: mdio-bus@2 {
+				reg = <2>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+			mdio3: mdio-bus@3 {
+				reg = <3>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
 	};
 
 	soc: soc@18000000 {
-- 
2.48.1


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

* [PATCH v5 4/4] net: mdio: Add RTL9300 MDIO driver
  2025-01-31  1:01 [PATCH v5 0/4] RTL9300 MDIO driver Chris Packham
                   ` (2 preceding siblings ...)
  2025-01-31  1:01 ` [PATCH v5 3/4] mips: dts: realtek: Add MDIO controller Chris Packham
@ 2025-01-31  1:01 ` Chris Packham
  2025-01-31  1:16   ` Chris Packham
  3 siblings, 1 reply; 10+ messages in thread
From: Chris Packham @ 2025-01-31  1:01 UTC (permalink / raw)
  To: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen
  Cc: devicetree, linux-kernel, netdev, linux-mips, Chris Packham

Add a driver for the MDIO controller on the RTL9300 family of Ethernet
switches with integrated SoC. There are 4 physical SMI interfaces on the
RTL9300 however access is done using the switch ports. The driver takes
the MDIO bus hierarchy from the DTS and uses this to configure the
switch ports so they are associated with the correct PHY. This mapping
is also used when dealing with software requests from phylib.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---

Notes:
    Changes in v5:
    - Reword out of date comment
    - Use GENMASK/FIELD_PREP where appropriate
    - Introduce port validity bitmap.
    - Use more obvious names for PHY_CTRL_READ/WRITE and
      PHY_CTRL_TYPE_C45/C22
    Changes in v4:
    - rename to realtek-rtl9300
    - s/realtek_/rtl9300_/
    - add locking to support concurrent access
    - The dtbinding now represents the MDIO bus hierarchy so we consume this
      information and use it to configure the switch port to MDIO bus+addr.
    Changes in v3:
    - Fix (another) off-by-one error
    Changes in v2:
    - Add clause 22 support
    - Remove commented out code
    - Formatting cleanup
    - Set MAX_PORTS correctly for MDIO interface
    - Fix off-by-one error in pn check

 drivers/net/mdio/Kconfig                |   7 +
 drivers/net/mdio/Makefile               |   1 +
 drivers/net/mdio/mdio-realtek-rtl9300.c | 436 ++++++++++++++++++++++++
 3 files changed, 444 insertions(+)
 create mode 100644 drivers/net/mdio/mdio-realtek-rtl9300.c

diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
index 4a7a303be2f7..058fcdaf6c18 100644
--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -185,6 +185,13 @@ config MDIO_IPQ8064
 	  This driver supports the MDIO interface found in the network
 	  interface units of the IPQ8064 SoC
 
+config MDIO_REALTEK_RTL9300
+	tristate "Realtek RTL9300 MDIO interface support"
+	depends on MACH_REALTEK_RTL || COMPILE_TEST
+	help
+	  This driver supports the MDIO interface found in the Realtek
+	  RTL9300 family of Ethernet switches with integrated SoC.
+
 config MDIO_REGMAP
 	tristate
 	help
diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile
index 1015f0db4531..c23778e73890 100644
--- a/drivers/net/mdio/Makefile
+++ b/drivers/net/mdio/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MDIO_MOXART)		+= mdio-moxart.o
 obj-$(CONFIG_MDIO_MSCC_MIIM)		+= mdio-mscc-miim.o
 obj-$(CONFIG_MDIO_MVUSB)		+= mdio-mvusb.o
 obj-$(CONFIG_MDIO_OCTEON)		+= mdio-octeon.o
+obj-$(CONFIG_MDIO_REALTEK_RTL9300)	+= mdio-realtek-rtl9300.o
 obj-$(CONFIG_MDIO_REGMAP)		+= mdio-regmap.o
 obj-$(CONFIG_MDIO_SUN4I)		+= mdio-sun4i.o
 obj-$(CONFIG_MDIO_THUNDER)		+= mdio-thunder.o
diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c
new file mode 100644
index 000000000000..d2ee66890caf
--- /dev/null
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MDIO controller for RTL9300 switches with integrated SoC.
+ *
+ * The MDIO communication is abstracted by the switch. At the software level
+ * communication uses the switch port to address the PHY. We work out the
+ * mapping based on the MDIO bus described in device tree and the realtek,port
+ * property.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/find.h>
+#include <linux/mdio.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#define SMI_GLB_CTRL			0xca00
+#define   GLB_CTRL_INTF_SEL(intf)	BIT(16 + (intf))
+#define SMI_PORT0_15_POLLING_SEL	0xca08
+#define SMI_POLL_CTRL			0xca90
+#define SMI_ACCESS_PHY_CTRL_0		0xcb70
+#define SMI_ACCESS_PHY_CTRL_1		0xcb74
+#define   PHY_CTRL_WRITE		BIT(2)
+#define   PHY_CTRL_READ			0
+#define   PHY_CTRL_TYPE_C45		BIT(1)
+#define   PHY_CTRL_TYPE_C22		0
+#define   PHY_CTRL_CMD			BIT(0)
+#define   PHY_CTRL_FAIL			BIT(25)
+#define SMI_ACCESS_PHY_CTRL_2		0xcb78
+#define SMI_ACCESS_PHY_CTRL_3		0xcb7c
+#define SMI_PORT0_5_ADDR_CTRL		0xcb80
+
+#define MAX_PORTS       28
+#define MAX_SMI_BUSSES  4
+#define MAX_SMI_ADDR	0x1f
+
+struct rtl9300_mdio_priv {
+	struct regmap *regmap;
+	struct mutex lock; /* protect HW access */
+	DECLARE_BITMAP(valid_ports, MAX_PORTS);
+	u8 smi_bus[MAX_PORTS];
+	u8 smi_addr[MAX_PORTS];
+	bool smi_bus_is_c45[MAX_SMI_BUSSES];
+	struct mii_bus *bus[MAX_SMI_BUSSES];
+};
+
+struct rtl9300_mdio_chan {
+	struct rtl9300_mdio_priv *priv;
+	u8 mdio_bus;
+};
+
+static int rtl9300_mdio_phy_to_port(struct mii_bus *bus, int phy_id)
+{
+	struct rtl9300_mdio_chan *chan = bus->priv;
+	struct rtl9300_mdio_priv *priv = chan->priv;
+	int i;
+
+	for (i = find_first_bit(priv->valid_ports, MAX_PORTS);
+	     i < MAX_PORTS;
+	     i = find_next_bit(priv->valid_ports, MAX_PORTS, i + 1))
+		if (priv->smi_bus[i] == chan->mdio_bus &&
+		    priv->smi_addr[i] == phy_id)
+			return i;
+
+	return -ENOENT;
+}
+
+static int rtl9300_mdio_wait_ready(struct rtl9300_mdio_priv *priv)
+{
+	struct regmap *regmap = priv->regmap;
+	u32 val;
+
+	lockdep_assert_held(&priv->lock);
+
+	return regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1,
+					val, !(val & PHY_CTRL_CMD), 10, 1000);
+}
+
+static int rtl9300_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
+{
+	struct rtl9300_mdio_chan *chan = bus->priv;
+	struct rtl9300_mdio_priv *priv = chan->priv;
+	struct regmap *regmap = priv->regmap;
+	int port;
+	u32 val;
+	int err;
+
+	guard(mutex)(&priv->lock);
+
+	port = rtl9300_mdio_phy_to_port(bus, phy_id);
+	if (port < 0)
+		return port;
+
+	err = rtl9300_mdio_wait_ready(priv);
+	if (err)
+		return err;
+
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, port << 16);
+	if (err)
+		return err;
+
+	val = FIELD_PREP(GENMASK(24, 20), regnum) |
+	      FIELD_PREP(GENMASK(19, 15), 0x1f) |
+	      FIELD_PREP(GENMASK(14, 3), 0xfff) |
+	      PHY_CTRL_READ | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD;
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val);
+	if (err)
+		return err;
+
+	err = rtl9300_mdio_wait_ready(priv);
+	if (err)
+		return err;
+
+	err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val);
+	if (err)
+		return err;
+
+	return FIELD_GET(GENMASK(15, 0), val);
+}
+
+static int rtl9300_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, u16 value)
+{
+	struct rtl9300_mdio_chan *chan = bus->priv;
+	struct rtl9300_mdio_priv *priv = chan->priv;
+	struct regmap *regmap = priv->regmap;
+	int port;
+	u32 val;
+	int err;
+
+	guard(mutex)(&priv->lock);
+
+	port = rtl9300_mdio_phy_to_port(bus, phy_id);
+	if (port < 0)
+		return port;
+
+	err = rtl9300_mdio_wait_ready(priv);
+	if (err)
+		return err;
+
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port));
+	if (err)
+		return err;
+
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, value << 16);
+	if (err)
+		return err;
+
+	val = FIELD_PREP(GENMASK(24, 20), regnum) |
+	      FIELD_PREP(GENMASK(19, 15), 0x1f) |
+	      FIELD_PREP(GENMASK(14, 3), 0xfff) |
+	      PHY_CTRL_WRITE | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD;
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val);
+	if (err)
+		return err;
+
+	err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1,
+				       val, !(val & PHY_CTRL_CMD), 10, 100);
+	if (err)
+		return err;
+
+	if (val & PHY_CTRL_FAIL)
+		return -ENXIO;
+
+	return 0;
+}
+
+static int rtl9300_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum)
+{
+	struct rtl9300_mdio_chan *chan = bus->priv;
+	struct rtl9300_mdio_priv *priv = chan->priv;
+	struct regmap *regmap = priv->regmap;
+	int port;
+	u32 val;
+	int err;
+
+	guard(mutex)(&priv->lock);
+
+	port = rtl9300_mdio_phy_to_port(bus, phy_id);
+	if (port < 0)
+		return port;
+
+	err = rtl9300_mdio_wait_ready(priv);
+	if (err)
+		return err;
+
+	val = FIELD_PREP(GENMASK(31, 16), port);
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val);
+	if (err)
+		return err;
+
+	val = FIELD_PREP(GENMASK(20, 16), dev_addr) |
+	      FIELD_PREP(GENMASK(15, 0), regnum);
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val);
+	if (err)
+		return err;
+
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1,
+			   PHY_CTRL_READ | PHY_CTRL_TYPE_C45 | PHY_CTRL_CMD);
+	if (err)
+		return err;
+
+	err = rtl9300_mdio_wait_ready(priv);
+	if (err)
+		return err;
+
+	err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val);
+	if (err)
+		return err;
+
+	return FIELD_GET(GENMASK(15, 0), val);
+}
+
+static int rtl9300_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
+				  int regnum, u16 value)
+{
+	struct rtl9300_mdio_chan *chan = bus->priv;
+	struct rtl9300_mdio_priv *priv = chan->priv;
+	struct regmap *regmap = priv->regmap;
+	int port;
+	u32 val;
+	int err;
+
+	guard(mutex)(&priv->lock);
+
+	port = rtl9300_mdio_phy_to_port(bus, phy_id);
+	if (port < 0)
+		return port;
+
+	err = rtl9300_mdio_wait_ready(priv);
+	if (err)
+		return err;
+
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port));
+	if (err)
+		return err;
+
+	val = FIELD_PREP(GENMASK(31, 16), value);
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val);
+	if (err)
+		return err;
+
+	val = FIELD_PREP(GENMASK(20, 16), dev_addr) |
+	      FIELD_PREP(GENMASK(15, 0), regnum);
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val);
+	if (err)
+		return err;
+
+	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1,
+			   PHY_CTRL_TYPE_C45 | PHY_CTRL_WRITE | PHY_CTRL_CMD);
+	if (err)
+		return err;
+
+	err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1,
+				       val, !(val & PHY_CTRL_CMD), 10, 100);
+	if (err)
+		return err;
+
+	if (val & PHY_CTRL_FAIL)
+		return -ENXIO;
+
+	return 0;
+}
+
+static int rtl9300_mdiobus_init(struct rtl9300_mdio_priv *priv)
+{
+	u32 glb_ctrl_mask = 0, glb_ctrl_val = 0;
+	struct regmap *regmap = priv->regmap;
+	u32 port_addr[5] = { 0 };
+	u32 poll_sel[2] = { 0 };
+	int i, err;
+
+	/* Associate the port with the SMI interface and PHY */
+	for (i = find_first_bit(priv->valid_ports, MAX_PORTS);
+	     i < MAX_PORTS;
+	     i = find_next_bit(priv->valid_ports, MAX_PORTS, i + 1)) {
+		int pos;
+
+		pos = (i % 6) * 5;
+		port_addr[i / 6] |= (priv->smi_addr[i] & 0x1f) << pos;
+
+		pos = (i % 16) * 2;
+		poll_sel[i / 16] |= (priv->smi_bus[i] & 0x3) << pos;
+	}
+
+	/* Stop the PPU from interfering */
+	err = regmap_update_bits(regmap, SMI_POLL_CTRL, priv->valid_ports, 0);
+	if (err)
+		return err;
+
+	/* Put the interfaces into C45 mode if required */
+	glb_ctrl_mask = GENMASK(19, 16);
+	for (i = 0; i < MAX_SMI_BUSSES; i++)
+		if (priv->smi_bus_is_c45[i])
+			glb_ctrl_val |= GLB_CTRL_INTF_SEL(i);
+
+	err = regmap_bulk_write(regmap, SMI_PORT0_5_ADDR_CTRL,
+				port_addr, 5);
+	if (err)
+		return err;
+
+	err = regmap_bulk_write(regmap, SMI_PORT0_15_POLLING_SEL,
+				poll_sel, 2);
+	if (err)
+		return err;
+
+	err = regmap_update_bits(regmap, SMI_GLB_CTRL,
+				 glb_ctrl_mask, glb_ctrl_val);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_priv *priv,
+				     struct fwnode_handle *node)
+{
+	struct rtl9300_mdio_chan *chan;
+	struct fwnode_handle *child;
+	struct mii_bus *bus;
+	u32 mdio_bus;
+	int err;
+
+	err = fwnode_property_read_u32(node, "reg", &mdio_bus);
+	if (err)
+		return err;
+
+	if (mdio_bus >= MAX_SMI_BUSSES)
+		return dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", mdio_bus);
+
+	fwnode_for_each_child_node(node, child) {
+		u32 addr;
+		u32 pn;
+
+		err = fwnode_property_read_u32(child, "reg", &addr);
+		if (err)
+			return err;
+
+		err = fwnode_property_read_u32(child, "realtek,port", &pn);
+		if (err)
+			return err;
+
+		if (pn >= MAX_PORTS)
+			return dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn);
+
+		if (fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"))
+			priv->smi_bus_is_c45[mdio_bus] = true;
+
+		bitmap_set(priv->valid_ports, pn, 1);
+		priv->smi_bus[pn] = mdio_bus;
+		priv->smi_addr[pn] = addr;
+	}
+
+	bus = devm_mdiobus_alloc_size(dev, sizeof(*chan));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "Reaktek Switch MDIO Bus";
+	bus->read = rtl9300_mdio_read_c22;
+	bus->write = rtl9300_mdio_write_c22;
+	bus->read_c45 = rtl9300_mdio_read_c45;
+	bus->write_c45 =  rtl9300_mdio_write_c45;
+	bus->parent = dev;
+	chan = bus->priv;
+	chan->mdio_bus = mdio_bus;
+	chan->priv = priv;
+
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", dev_name(dev), mdio_bus);
+
+	err = devm_of_mdiobus_register(dev, bus, to_of_node(node));
+	if (err)
+		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
+
+	return 0;
+}
+
+static int rtl9300_mdiobus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rtl9300_mdio_priv *priv;
+	struct fwnode_handle *child;
+	int err;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	err = devm_mutex_init(dev, &priv->lock);
+	if (err)
+		return err;
+
+	priv->regmap = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	platform_set_drvdata(pdev, priv);
+
+	device_for_each_child_node(dev, child) {
+		err = rtl9300_mdiobus_probe_one(dev, priv, child);
+		if (err)
+			return err;
+	}
+
+	err = rtl9300_mdiobus_init(priv);
+	if (err)
+		return dev_err_probe(dev, err, "failed to initialise MDIO bus controller\n");
+
+	return 0;
+}
+
+static const struct of_device_id rtl9300_mdio_ids[] = {
+	{ .compatible = "realtek,rtl9301-mdio" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rtl9300_mdio_ids);
+
+static struct platform_driver rtl9300_mdio_driver = {
+	.probe = rtl9300_mdiobus_probe,
+	.driver = {
+		.name = "mdio-rtl9300",
+		.of_match_table = rtl9300_mdio_ids,
+	},
+};
+
+module_platform_driver(rtl9300_mdio_driver);
+
+MODULE_DESCRIPTION("RTL9300 MDIO driver");
+MODULE_LICENSE("GPL");
-- 
2.48.1


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

* Re: [PATCH v5 4/4] net: mdio: Add RTL9300 MDIO driver
  2025-01-31  1:01 ` [PATCH v5 4/4] net: mdio: Add RTL9300 MDIO driver Chris Packham
@ 2025-01-31  1:16   ` Chris Packham
  0 siblings, 0 replies; 10+ messages in thread
From: Chris Packham @ 2025-01-31  1:16 UTC (permalink / raw)
  To: lee@kernel.org, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	tsbogend@alpha.franken.de, hkallweit1@gmail.com,
	linux@armlinux.org.uk, sander@svanheule.net,
	markus.stockhausen@gmx.de
  Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	netdev@vger.kernel.org, linux-mips@vger.kernel.org


On 31/01/2025 14:01, Chris Packham wrote:
> Add a driver for the MDIO controller on the RTL9300 family of Ethernet
> switches with integrated SoC. There are 4 physical SMI interfaces on the
> RTL9300 however access is done using the switch ports. The driver takes
> the MDIO bus hierarchy from the DTS and uses this to configure the
> switch ports so they are associated with the correct PHY. This mapping
> is also used when dealing with software requests from phylib.
>
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
>
> Notes:
>      Changes in v5:
>      - Reword out of date comment
>      - Use GENMASK/FIELD_PREP where appropriate
>      - Introduce port validity bitmap.
>      - Use more obvious names for PHY_CTRL_READ/WRITE and
>        PHY_CTRL_TYPE_C45/C22
>      Changes in v4:
>      - rename to realtek-rtl9300
>      - s/realtek_/rtl9300_/
>      - add locking to support concurrent access
>      - The dtbinding now represents the MDIO bus hierarchy so we consume this
>        information and use it to configure the switch port to MDIO bus+addr.
>      Changes in v3:
>      - Fix (another) off-by-one error
>      Changes in v2:
>      - Add clause 22 support
>      - Remove commented out code
>      - Formatting cleanup
>      - Set MAX_PORTS correctly for MDIO interface
>      - Fix off-by-one error in pn check
>
>   drivers/net/mdio/Kconfig                |   7 +
>   drivers/net/mdio/Makefile               |   1 +
>   drivers/net/mdio/mdio-realtek-rtl9300.c | 436 ++++++++++++++++++++++++
>   3 files changed, 444 insertions(+)
>   create mode 100644 drivers/net/mdio/mdio-realtek-rtl9300.c
>
> diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
> index 4a7a303be2f7..058fcdaf6c18 100644
> --- a/drivers/net/mdio/Kconfig
> +++ b/drivers/net/mdio/Kconfig
> @@ -185,6 +185,13 @@ config MDIO_IPQ8064
>   	  This driver supports the MDIO interface found in the network
>   	  interface units of the IPQ8064 SoC
>   
> +config MDIO_REALTEK_RTL9300
> +	tristate "Realtek RTL9300 MDIO interface support"
> +	depends on MACH_REALTEK_RTL || COMPILE_TEST
> +	help
> +	  This driver supports the MDIO interface found in the Realtek
> +	  RTL9300 family of Ethernet switches with integrated SoC.
> +
>   config MDIO_REGMAP
>   	tristate
>   	help
> diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile
> index 1015f0db4531..c23778e73890 100644
> --- a/drivers/net/mdio/Makefile
> +++ b/drivers/net/mdio/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_MDIO_MOXART)		+= mdio-moxart.o
>   obj-$(CONFIG_MDIO_MSCC_MIIM)		+= mdio-mscc-miim.o
>   obj-$(CONFIG_MDIO_MVUSB)		+= mdio-mvusb.o
>   obj-$(CONFIG_MDIO_OCTEON)		+= mdio-octeon.o
> +obj-$(CONFIG_MDIO_REALTEK_RTL9300)	+= mdio-realtek-rtl9300.o
>   obj-$(CONFIG_MDIO_REGMAP)		+= mdio-regmap.o
>   obj-$(CONFIG_MDIO_SUN4I)		+= mdio-sun4i.o
>   obj-$(CONFIG_MDIO_THUNDER)		+= mdio-thunder.o
> diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c
> new file mode 100644
> index 000000000000..d2ee66890caf
> --- /dev/null
> +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
> @@ -0,0 +1,436 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * MDIO controller for RTL9300 switches with integrated SoC.
> + *
> + * The MDIO communication is abstracted by the switch. At the software level
> + * communication uses the switch port to address the PHY. We work out the
> + * mapping based on the MDIO bus described in device tree and the realtek,port
> + * property.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bitmap.h>
> +#include <linux/bits.h>
> +#include <linux/cleanup.h>
> +#include <linux/find.h>
> +#include <linux/mdio.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/mutex.h>
> +#include <linux/of_mdio.h>
> +#include <linux/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +#define SMI_GLB_CTRL			0xca00
> +#define   GLB_CTRL_INTF_SEL(intf)	BIT(16 + (intf))
> +#define SMI_PORT0_15_POLLING_SEL	0xca08
> +#define SMI_POLL_CTRL			0xca90
> +#define SMI_ACCESS_PHY_CTRL_0		0xcb70
> +#define SMI_ACCESS_PHY_CTRL_1		0xcb74
> +#define   PHY_CTRL_WRITE		BIT(2)
> +#define   PHY_CTRL_READ			0
> +#define   PHY_CTRL_TYPE_C45		BIT(1)
> +#define   PHY_CTRL_TYPE_C22		0
> +#define   PHY_CTRL_CMD			BIT(0)
> +#define   PHY_CTRL_FAIL			BIT(25)
> +#define SMI_ACCESS_PHY_CTRL_2		0xcb78
> +#define SMI_ACCESS_PHY_CTRL_3		0xcb7c
> +#define SMI_PORT0_5_ADDR_CTRL		0xcb80
> +
> +#define MAX_PORTS       28
> +#define MAX_SMI_BUSSES  4
> +#define MAX_SMI_ADDR	0x1f
> +
> +struct rtl9300_mdio_priv {
> +	struct regmap *regmap;
> +	struct mutex lock; /* protect HW access */
> +	DECLARE_BITMAP(valid_ports, MAX_PORTS);
> +	u8 smi_bus[MAX_PORTS];
> +	u8 smi_addr[MAX_PORTS];
> +	bool smi_bus_is_c45[MAX_SMI_BUSSES];
> +	struct mii_bus *bus[MAX_SMI_BUSSES];
> +};
> +
> +struct rtl9300_mdio_chan {
> +	struct rtl9300_mdio_priv *priv;
> +	u8 mdio_bus;
> +};
> +
> +static int rtl9300_mdio_phy_to_port(struct mii_bus *bus, int phy_id)
> +{
> +	struct rtl9300_mdio_chan *chan = bus->priv;
> +	struct rtl9300_mdio_priv *priv = chan->priv;
> +	int i;
> +
> +	for (i = find_first_bit(priv->valid_ports, MAX_PORTS);
> +	     i < MAX_PORTS;
> +	     i = find_next_bit(priv->valid_ports, MAX_PORTS, i + 1))
> +		if (priv->smi_bus[i] == chan->mdio_bus &&
> +		    priv->smi_addr[i] == phy_id)
> +			return i;
> +
> +	return -ENOENT;
> +}
> +
> +static int rtl9300_mdio_wait_ready(struct rtl9300_mdio_priv *priv)
> +{
> +	struct regmap *regmap = priv->regmap;
> +	u32 val;
> +
> +	lockdep_assert_held(&priv->lock);
> +
> +	return regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1,
> +					val, !(val & PHY_CTRL_CMD), 10, 1000);
> +}
> +
> +static int rtl9300_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
> +{
> +	struct rtl9300_mdio_chan *chan = bus->priv;
> +	struct rtl9300_mdio_priv *priv = chan->priv;
> +	struct regmap *regmap = priv->regmap;
> +	int port;
> +	u32 val;
> +	int err;
> +
> +	guard(mutex)(&priv->lock);
> +
> +	port = rtl9300_mdio_phy_to_port(bus, phy_id);
> +	if (port < 0)
> +		return port;
> +
> +	err = rtl9300_mdio_wait_ready(priv);
> +	if (err)
> +		return err;
> +
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, port << 16);
> +	if (err)
> +		return err;
> +
> +	val = FIELD_PREP(GENMASK(24, 20), regnum) |
> +	      FIELD_PREP(GENMASK(19, 15), 0x1f) |
> +	      FIELD_PREP(GENMASK(14, 3), 0xfff) |
> +	      PHY_CTRL_READ | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD;
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val);
> +	if (err)
> +		return err;
> +
> +	err = rtl9300_mdio_wait_ready(priv);
> +	if (err)
> +		return err;
> +
> +	err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val);
> +	if (err)
> +		return err;
> +
> +	return FIELD_GET(GENMASK(15, 0), val);
> +}
> +
> +static int rtl9300_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, u16 value)
> +{
> +	struct rtl9300_mdio_chan *chan = bus->priv;
> +	struct rtl9300_mdio_priv *priv = chan->priv;
> +	struct regmap *regmap = priv->regmap;
> +	int port;
> +	u32 val;
> +	int err;
> +
> +	guard(mutex)(&priv->lock);
> +
> +	port = rtl9300_mdio_phy_to_port(bus, phy_id);
> +	if (port < 0)
> +		return port;
> +
> +	err = rtl9300_mdio_wait_ready(priv);
> +	if (err)
> +		return err;
> +
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port));
> +	if (err)
> +		return err;
> +
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, value << 16);
> +	if (err)
> +		return err;
> +
> +	val = FIELD_PREP(GENMASK(24, 20), regnum) |
> +	      FIELD_PREP(GENMASK(19, 15), 0x1f) |
> +	      FIELD_PREP(GENMASK(14, 3), 0xfff) |
> +	      PHY_CTRL_WRITE | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD;
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val);
> +	if (err)
> +		return err;
> +
> +	err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1,
> +				       val, !(val & PHY_CTRL_CMD), 10, 100);
> +	if (err)
> +		return err;
> +
> +	if (val & PHY_CTRL_FAIL)
> +		return -ENXIO;
> +
> +	return 0;
> +}
> +
> +static int rtl9300_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum)
> +{
> +	struct rtl9300_mdio_chan *chan = bus->priv;
> +	struct rtl9300_mdio_priv *priv = chan->priv;
> +	struct regmap *regmap = priv->regmap;
> +	int port;
> +	u32 val;
> +	int err;
> +
> +	guard(mutex)(&priv->lock);
> +
> +	port = rtl9300_mdio_phy_to_port(bus, phy_id);
> +	if (port < 0)
> +		return port;
> +
> +	err = rtl9300_mdio_wait_ready(priv);
> +	if (err)
> +		return err;
> +
> +	val = FIELD_PREP(GENMASK(31, 16), port);
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val);
> +	if (err)
> +		return err;
> +
> +	val = FIELD_PREP(GENMASK(20, 16), dev_addr) |
> +	      FIELD_PREP(GENMASK(15, 0), regnum);
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val);
> +	if (err)
> +		return err;
> +
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1,
> +			   PHY_CTRL_READ | PHY_CTRL_TYPE_C45 | PHY_CTRL_CMD);
> +	if (err)
> +		return err;
> +
> +	err = rtl9300_mdio_wait_ready(priv);
> +	if (err)
> +		return err;
> +
> +	err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val);
> +	if (err)
> +		return err;
> +
> +	return FIELD_GET(GENMASK(15, 0), val);
> +}
> +
> +static int rtl9300_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
> +				  int regnum, u16 value)
> +{
> +	struct rtl9300_mdio_chan *chan = bus->priv;
> +	struct rtl9300_mdio_priv *priv = chan->priv;
> +	struct regmap *regmap = priv->regmap;
> +	int port;
> +	u32 val;
> +	int err;
> +
> +	guard(mutex)(&priv->lock);
> +
> +	port = rtl9300_mdio_phy_to_port(bus, phy_id);
> +	if (port < 0)
> +		return port;
> +
> +	err = rtl9300_mdio_wait_ready(priv);
> +	if (err)
> +		return err;
> +
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port));
> +	if (err)
> +		return err;
> +
> +	val = FIELD_PREP(GENMASK(31, 16), value);
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val);
> +	if (err)
> +		return err;
> +
> +	val = FIELD_PREP(GENMASK(20, 16), dev_addr) |
> +	      FIELD_PREP(GENMASK(15, 0), regnum);
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val);
> +	if (err)
> +		return err;
> +
> +	err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1,
> +			   PHY_CTRL_TYPE_C45 | PHY_CTRL_WRITE | PHY_CTRL_CMD);
> +	if (err)
> +		return err;
> +
> +	err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1,
> +				       val, !(val & PHY_CTRL_CMD), 10, 100);
> +	if (err)
> +		return err;
> +
> +	if (val & PHY_CTRL_FAIL)
> +		return -ENXIO;
> +
> +	return 0;
> +}
> +
> +static int rtl9300_mdiobus_init(struct rtl9300_mdio_priv *priv)
> +{
> +	u32 glb_ctrl_mask = 0, glb_ctrl_val = 0;
> +	struct regmap *regmap = priv->regmap;
> +	u32 port_addr[5] = { 0 };
> +	u32 poll_sel[2] = { 0 };
> +	int i, err;
> +
> +	/* Associate the port with the SMI interface and PHY */
> +	for (i = find_first_bit(priv->valid_ports, MAX_PORTS);
> +	     i < MAX_PORTS;
> +	     i = find_next_bit(priv->valid_ports, MAX_PORTS, i + 1)) {
> +		int pos;
> +
> +		pos = (i % 6) * 5;
> +		port_addr[i / 6] |= (priv->smi_addr[i] & 0x1f) << pos;
> +
> +		pos = (i % 16) * 2;
> +		poll_sel[i / 16] |= (priv->smi_bus[i] & 0x3) << pos;
> +	}
> +
> +	/* Stop the PPU from interfering */
> +	err = regmap_update_bits(regmap, SMI_POLL_CTRL, priv->valid_ports, 0);
> +	if (err)
> +		return err;
drivers/net/mdio/mdio-realtek-rtl9300.c:295:61: warning: passing 
argument 3 of 'regmap_update_bits' makes integer from pointer without a 
cast [-Wint-conversion]
   295 |         err = regmap_update_bits(regmap, SMI_POLL_CTRL, 
priv->valid_ports, 0);
       | ~~~~^~~~~~~~~~~~~
       | |
       | long unsigned int *

darn not sure how I missed that.

> +
> +	/* Put the interfaces into C45 mode if required */
> +	glb_ctrl_mask = GENMASK(19, 16);
> +	for (i = 0; i < MAX_SMI_BUSSES; i++)
> +		if (priv->smi_bus_is_c45[i])
> +			glb_ctrl_val |= GLB_CTRL_INTF_SEL(i);
> +
> +	err = regmap_bulk_write(regmap, SMI_PORT0_5_ADDR_CTRL,
> +				port_addr, 5);
> +	if (err)
> +		return err;
> +
> +	err = regmap_bulk_write(regmap, SMI_PORT0_15_POLLING_SEL,
> +				poll_sel, 2);
> +	if (err)
> +		return err;
> +
> +	err = regmap_update_bits(regmap, SMI_GLB_CTRL,
> +				 glb_ctrl_mask, glb_ctrl_val);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_priv *priv,
> +				     struct fwnode_handle *node)
> +{
> +	struct rtl9300_mdio_chan *chan;
> +	struct fwnode_handle *child;
> +	struct mii_bus *bus;
> +	u32 mdio_bus;
> +	int err;
> +
> +	err = fwnode_property_read_u32(node, "reg", &mdio_bus);
> +	if (err)
> +		return err;
> +
> +	if (mdio_bus >= MAX_SMI_BUSSES)
> +		return dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", mdio_bus);
> +
> +	fwnode_for_each_child_node(node, child) {
> +		u32 addr;
> +		u32 pn;
> +
> +		err = fwnode_property_read_u32(child, "reg", &addr);
> +		if (err)
> +			return err;
> +
> +		err = fwnode_property_read_u32(child, "realtek,port", &pn);
> +		if (err)
> +			return err;
> +
> +		if (pn >= MAX_PORTS)
> +			return dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn);
> +
> +		if (fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"))
> +			priv->smi_bus_is_c45[mdio_bus] = true;
> +
> +		bitmap_set(priv->valid_ports, pn, 1);
> +		priv->smi_bus[pn] = mdio_bus;
> +		priv->smi_addr[pn] = addr;
> +	}
> +
> +	bus = devm_mdiobus_alloc_size(dev, sizeof(*chan));
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	bus->name = "Reaktek Switch MDIO Bus";
> +	bus->read = rtl9300_mdio_read_c22;
> +	bus->write = rtl9300_mdio_write_c22;
> +	bus->read_c45 = rtl9300_mdio_read_c45;
> +	bus->write_c45 =  rtl9300_mdio_write_c45;
> +	bus->parent = dev;
> +	chan = bus->priv;
> +	chan->mdio_bus = mdio_bus;
> +	chan->priv = priv;
> +
> +	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", dev_name(dev), mdio_bus);
> +
> +	err = devm_of_mdiobus_register(dev, bus, to_of_node(node));
> +	if (err)
> +		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
> +
> +	return 0;
> +}
> +
> +static int rtl9300_mdiobus_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct rtl9300_mdio_priv *priv;
> +	struct fwnode_handle *child;
> +	int err;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	err = devm_mutex_init(dev, &priv->lock);
> +	if (err)
> +		return err;
> +
> +	priv->regmap = syscon_node_to_regmap(dev->parent->of_node);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	device_for_each_child_node(dev, child) {
> +		err = rtl9300_mdiobus_probe_one(dev, priv, child);
> +		if (err)
> +			return err;
> +	}
> +
> +	err = rtl9300_mdiobus_init(priv);
> +	if (err)
> +		return dev_err_probe(dev, err, "failed to initialise MDIO bus controller\n");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id rtl9300_mdio_ids[] = {
> +	{ .compatible = "realtek,rtl9301-mdio" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, rtl9300_mdio_ids);
> +
> +static struct platform_driver rtl9300_mdio_driver = {
> +	.probe = rtl9300_mdiobus_probe,
> +	.driver = {
> +		.name = "mdio-rtl9300",
> +		.of_match_table = rtl9300_mdio_ids,
> +	},
> +};
> +
> +module_platform_driver(rtl9300_mdio_driver);
> +
> +MODULE_DESCRIPTION("RTL9300 MDIO driver");
> +MODULE_LICENSE("GPL");

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

* Re: [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch
  2025-01-31  1:01 ` [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch Chris Packham
@ 2025-01-31  6:35   ` Daniel Golle
  2025-02-02 20:14     ` Chris Packham
  2025-01-31  7:33   ` Krzysztof Kozlowski
  1 sibling, 1 reply; 10+ messages in thread
From: Daniel Golle @ 2025-01-31  6:35 UTC (permalink / raw)
  To: Chris Packham
  Cc: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen, devicetree, linux-kernel, netdev, linux-mips

Hi Chris,

afaik net-next is still closed right now, but lets discuss the series as RFC
in the meantime maybe, right?

On Fri, Jan 31, 2025 at 02:01:49PM +1300, Chris Packham wrote:
> The MDIO controller is part of the switch on the RTL9300 family of
> devices. Add a $ref to the mfd binding for these devices.
> 
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
> 
> Notes:
>     This patch is dependent on "dt-bindings: net: Add Realtek MDIO
>     controller" which adds the realtek,rtl9301-mdio.yaml binding.
>     
>     Changes in v5:
>     - Note dependency on realtek,rtl9301-mdio.yaml patch
>     - Add back reg property to the mdio-controller node.
>     Changes in v4:
>     - There is a single MDIO controller that has MDIO buses as children
>     Changes in v3:
>     - None
>     Changes in v2:
>     - None
> 
>  .../bindings/mfd/realtek,rtl9301-switch.yaml  | 29 +++++++++++++++++++
>  1 file changed, 29 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
> index f053303ab1e6..89e10213a4ee 100644
> --- a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
> +++ b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
> @@ -28,6 +28,9 @@ properties:
>    reg:
>      maxItems: 1
>  
> +  mdio-controller:
> +    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
> +
>    '#address-cells':
>      const: 1
>  
> @@ -41,6 +44,10 @@ patternProperties:
>    'i2c@[0-9a-f]+$':
>      $ref: /schemas/i2c/realtek,rtl9301-i2c.yaml#
>  
> +  'mdio-controller@[0-9a-f]+$':
> +    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
> +
> +
>  required:
>    - compatible
>    - reg
> @@ -110,5 +117,27 @@ examples:
>            };
>          };
>        };
> +
> +      mdio-controller@ca00 {
> +        compatible = "realtek,rtl9301-mdio";
> +        reg = <0xca00 0x200>;
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        mdio-bus@0 {
> +          reg = <0>;
> +          #address-cells = <1>;
> +          #size-cells = <0>;
> +
> +          ethernet-phy@0 {
> +            reg = <0>;
> +            realtek,port = <1>;

Aren't all those PHYs referenced as phandles by DSA switch ports?

Imho it would be better to not introduce a new property but instead
let the driver of the mdio-controller parse the DSA switch description
and follow the existing 'phy-handle' properties in order to infer the
mapping of all ports to all PHYs, and by that then be able to also
know the reverse mapping.
You could reference the switch node in the mdio-controller node.

That would avoid redundant information in the device tree, as we
would then only have one mapping instead of having it two times
(once by the usual 'phy-handle' property of the DSA user port and
another time reverse using your newly introduce 'realtek,port'
property of each ethernet-phy).


> +          };
> +          ethernet-phy@1 {
> +            reg = <1>;
> +            realtek,port = <0>;
> +          };
> +        };
> +      };
>      };
>  
> -- 
> 2.48.1
> 
> 

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

* Re: [PATCH v5 1/4] dt-bindings: net: Add Realtek MDIO controller
  2025-01-31  1:01 ` [PATCH v5 1/4] dt-bindings: net: Add Realtek MDIO controller Chris Packham
@ 2025-01-31  7:31   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 10+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-31  7:31 UTC (permalink / raw)
  To: Chris Packham
  Cc: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen, devicetree, linux-kernel, netdev, linux-mips

On Fri, Jan 31, 2025 at 02:01:48PM +1300, Chris Packham wrote:
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +  reg:
> +    maxItems: 1
> +
> +patternProperties:
> +  '^mdio-bus@[0-4]$':

4 or 5 buses?

> +    $ref: mdio.yaml#
> +
> +    properties:
> +      reg:
> +        maxItems: 1
> +
> +    required:
> +      - reg
> +
> +    patternProperties:
> +      '^ethernet-phy@[a-f0-9]+$':
> +        type: object
> +        $ref: ethernet-phy.yaml#
> +
> +        properties:
> +          realtek,port:
> +            $ref: /schemas/types.yaml#/definitions/uint32
> +            description:
> +              The MDIO communication on the RTL9300 is abstracted by the switch. At
> +              the software level communication uses the switch port to address the
> +              PHY with the actual MDIO bus and address having been setup via the
> +              parent mdio-bus and reg property.

maximum: 8 ?

also property should be required or you miss here default.

Best regards,
Krzysztof


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

* Re: [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch
  2025-01-31  1:01 ` [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch Chris Packham
  2025-01-31  6:35   ` Daniel Golle
@ 2025-01-31  7:33   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 10+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-31  7:33 UTC (permalink / raw)
  To: Chris Packham
  Cc: lee, robh, krzk+dt, conor+dt, andrew+netdev, davem, edumazet,
	kuba, pabeni, tsbogend, hkallweit1, linux, sander,
	markus.stockhausen, devicetree, linux-kernel, netdev, linux-mips

On Fri, Jan 31, 2025 at 02:01:49PM +1300, Chris Packham wrote:
>  .../bindings/mfd/realtek,rtl9301-switch.yaml  | 29 +++++++++++++++++++
>  1 file changed, 29 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
> index f053303ab1e6..89e10213a4ee 100644
> --- a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
> +++ b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
> @@ -28,6 +28,9 @@ properties:
>    reg:
>      maxItems: 1
>  
> +  mdio-controller:
> +    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
> +

So this mdio-controller looks duplicated now. Why is it needed?

>    '#address-cells':
>      const: 1
>  
> @@ -41,6 +44,10 @@ patternProperties:
>    'i2c@[0-9a-f]+$':
>      $ref: /schemas/i2c/realtek,rtl9301-i2c.yaml#
>  
> +  'mdio-controller@[0-9a-f]+$':
> +    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
> +
> +

Just one blank line.


Best regards,
Krzysztof


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

* Re: [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch
  2025-01-31  6:35   ` Daniel Golle
@ 2025-02-02 20:14     ` Chris Packham
  0 siblings, 0 replies; 10+ messages in thread
From: Chris Packham @ 2025-02-02 20:14 UTC (permalink / raw)
  To: Daniel Golle
  Cc: lee@kernel.org, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	tsbogend@alpha.franken.de, hkallweit1@gmail.com,
	linux@armlinux.org.uk, sander@svanheule.net,
	markus.stockhausen@gmx.de, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	linux-mips@vger.kernel.org


On 31/01/2025 19:35, Daniel Golle wrote:
> Hi Chris,
>
> afaik net-next is still closed right now, but lets discuss the series as RFC
> in the meantime maybe, right?

Yes sure. I probably should have tagged these as net-next even with or 
without RFC.

> On Fri, Jan 31, 2025 at 02:01:49PM +1300, Chris Packham wrote:
>> The MDIO controller is part of the switch on the RTL9300 family of
>> devices. Add a $ref to the mfd binding for these devices.
>>
>> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
>> ---
>>
>> Notes:
>>      This patch is dependent on "dt-bindings: net: Add Realtek MDIO
>>      controller" which adds the realtek,rtl9301-mdio.yaml binding.
>>      
>>      Changes in v5:
>>      - Note dependency on realtek,rtl9301-mdio.yaml patch
>>      - Add back reg property to the mdio-controller node.
>>      Changes in v4:
>>      - There is a single MDIO controller that has MDIO buses as children
>>      Changes in v3:
>>      - None
>>      Changes in v2:
>>      - None
>>
>>   .../bindings/mfd/realtek,rtl9301-switch.yaml  | 29 +++++++++++++++++++
>>   1 file changed, 29 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
>> index f053303ab1e6..89e10213a4ee 100644
>> --- a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
>> +++ b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml
>> @@ -28,6 +28,9 @@ properties:
>>     reg:
>>       maxItems: 1
>>   
>> +  mdio-controller:
>> +    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
>> +
>>     '#address-cells':
>>       const: 1
>>   
>> @@ -41,6 +44,10 @@ patternProperties:
>>     'i2c@[0-9a-f]+$':
>>       $ref: /schemas/i2c/realtek,rtl9301-i2c.yaml#
>>   
>> +  'mdio-controller@[0-9a-f]+$':
>> +    $ref: /schemas/net/realtek,rtl9301-mdio.yaml#
>> +
>> +
>>   required:
>>     - compatible
>>     - reg
>> @@ -110,5 +117,27 @@ examples:
>>             };
>>           };
>>         };
>> +
>> +      mdio-controller@ca00 {
>> +        compatible = "realtek,rtl9301-mdio";
>> +        reg = <0xca00 0x200>;
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        mdio-bus@0 {
>> +          reg = <0>;
>> +          #address-cells = <1>;
>> +          #size-cells = <0>;
>> +
>> +          ethernet-phy@0 {
>> +            reg = <0>;
>> +            realtek,port = <1>;
> Aren't all those PHYs referenced as phandles by DSA switch ports?

I'm still tiptoeing around whether this thing will be DSA or 
switchdev[1]. In theory the RTL9300 could be either although the 
specific design I'm working uses the internal CPU core so it's more 
switchdev like. Binding wise the mdio-bus arrangement would be fairly 
similar in either case.

> Imho it would be better to not introduce a new property but instead
> let the driver of the mdio-controller parse the DSA switch description
> and follow the existing 'phy-handle' properties in order to infer the
> mapping of all ports to all PHYs, and by that then be able to also
> know the reverse mapping.
> You could reference the switch node in the mdio-controller node.

As it stands the switch node is the parent of the mdio-controller (that 
may actually help as presumably I can go via the parent rather than a 
phandle). I've kind of avoided doing anything involving too much of the 
switch because I was hoping to land the mdio driver independently. Maybe 
I still can as long as I define the binding for the switch block now. Is 
is the done thing for one node in the dts to parse information from a 
second?

>
> That would avoid redundant information in the device tree, as we
> would then only have one mapping instead of having it two times
> (once by the usual 'phy-handle' property of the DSA user port and
> another time reverse using your newly introduce 'realtek,port'
> property of each ethernet-phy).

Yes that makes sense. It does mean I need to start defining the binding 
for the actual switch portion which I've been putting off. Time to roll 
up those sleeves.

>
>> +          };
>> +          ethernet-phy@1 {
>> +            reg = <1>;
>> +            realtek,port = <0>;
>> +          };
>> +        };
>> +      };
>>       };
>>   
>> -- 
>> 2.48.1
>>
>>
[1] - 
https://lore.kernel.org/lkml/b15b15ce-ae24-4e04-83ab-87017226f558@alliedtelesis.co.nz/ 

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

end of thread, other threads:[~2025-02-02 20:14 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-31  1:01 [PATCH v5 0/4] RTL9300 MDIO driver Chris Packham
2025-01-31  1:01 ` [PATCH v5 1/4] dt-bindings: net: Add Realtek MDIO controller Chris Packham
2025-01-31  7:31   ` Krzysztof Kozlowski
2025-01-31  1:01 ` [PATCH v5 2/4] dt-bindings: mfd: Add MDIO interface to rtl9301-switch Chris Packham
2025-01-31  6:35   ` Daniel Golle
2025-02-02 20:14     ` Chris Packham
2025-01-31  7:33   ` Krzysztof Kozlowski
2025-01-31  1:01 ` [PATCH v5 3/4] mips: dts: realtek: Add MDIO controller Chris Packham
2025-01-31  1:01 ` [PATCH v5 4/4] net: mdio: Add RTL9300 MDIO driver Chris Packham
2025-01-31  1:16   ` Chris Packham

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