Skip to contentSkip to conversation

net: dsa: lantiq_gswip: Add support for MaxLinear GSW1xx switch family

PATCH Superseded Daniel Golle 3 participants 19 messages Oct 25, 2025 – Oct 27, 2025

Subsystems (5)

v2 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v2 cover net: dsa: lantiq_gswip: Add support for MaxLinear GSW1xx switch family

This patch series extends the existing lantiq_gswip DSA driver to support the MaxLinear GSW1xx family of dedicated Ethernet switch ICs. These switches are based on the same IP as the Lantiq/Intel GSWIP found in VR9 and xRX MIPS router SoCs, but are connected via MDIO instead of memory-mapped I/O.

The series includes several improvements and refactoring to prepare for the new hardware support.

The GSW1xx family includes several variants:
- GSW120: 4 ports, 2 PHYs, RGMII & SGMII/2500Base-X
- GSW125: 4 ports, 2 PHYs, RGMII & SGMII/2500Base-X, industrial temperature
- GSW140: 6 ports, 4 PHYs, RGMII & SGMII/2500Base-X
- GSW141: 6 ports, 4 PHYs, RGMII & SGMII
- GSW145: 6 ports, 4 PHYs, RGMII & SGMII/2500Base-X, industrial temperature

Key features implemented:
- MDIO-based register access using regmap
- Support for SGMII/1000Base-X/2500Base-X SerDes interfaces
- Configurable RGMII delays via device tree properties
- Configurable RMII clock direction
- Energy Efficient Ethernet (EEE) support
- enabling/disabling learning

Daniel Golle (13):
net: dsa: lantiq_gswip: split into common and MMIO parts
net: dsa: lantiq_gswip: support enable/disable learning
net: dsa: lantiq_gswip: support Energy Efficient Ethernet
net: dsa: lantiq_gswip: set link parameters also for CPU port
net: dsa: lantiq_gswip: define and use
GSWIP_TABLE_MAC_BRIDGE_VAL1_VALID
dt-bindings: net: dsa: lantiq,gswip: add support for MII delay
properties
net: dsa: lantiq_gswip: allow adjusting MII delays
dt-bindings: net: dsa: lantiq,gswip: add MaxLinear RMII refclk output
property
net: dsa: lantiq_gswip: add vendor property to setup MII refclk output
dt-bindings: net: dsa: lantiq,gswip: add support for MaxLinear GSW1xx
switches
net: dsa: add tagging driver for MaxLinear GSW1xx switch family
net: dsa: lantiq_gswip: add registers specific for MaxLinear GSW1xx
net: dsa: add driver for MaxLinear GSW1xx switch family

 .../bindings/net/dsa/lantiq,gswip.yaml        |  291 ++-
 MAINTAINERS                                   |    3 +-
 drivers/net/dsa/lantiq/Kconfig                |   18 +-
 drivers/net/dsa/lantiq/Makefile               |    2 +
 drivers/net/dsa/lantiq/lantiq_gswip.c         | 1617 +--------------
 drivers/net/dsa/lantiq/lantiq_gswip.h         |  128 ++
 drivers/net/dsa/lantiq/lantiq_gswip_common.c  | 1748 +++++++++++++++++
 drivers/net/dsa/lantiq/mxl-gsw1xx.c           |  680 +++++++
 drivers/net/dsa/lantiq/mxl-gsw1xx_pce.h       |  154 ++
 include/net/dsa.h                             |    2 +
 net/dsa/Kconfig                               |    8 +
 net/dsa/Makefile                              |    1 +
 net/dsa/tag_mxl-gsw1xx.c                      |  141 ++
 13 files changed, 3127 insertions(+), 1666 deletions(-)
 create mode 100644 drivers/net/dsa/lantiq/lantiq_gswip_common.c
 create mode 100644 drivers/net/dsa/lantiq/mxl-gsw1xx.c
 create mode 100644 drivers/net/dsa/lantiq/mxl-gsw1xx_pce.h
 create mode 100644 net/dsa/tag_mxl-gsw1xx.c
Signature · 1 line
2.51.0
#1 lore raw

PATCH v2 1/13 net: dsa: lantiq_gswip: split into common and MMIO parts

Move all parts specific for the MMIO/SoC driver into a module of its own to prepare for supporting MDIO-connected switch ICs.
Modify gswip_probe() functions by splitting it into a common function gswip_probe_common() which covers allocating, initializing and registering the DSA switch, while keeping transport-specific regmap initialization as well as PHY firmware loading in the new MMIO/SoC-specific gswip_probe() function.

---
 drivers/net/dsa/lantiq/Kconfig               |    6 +-
 drivers/net/dsa/lantiq/Makefile              |    1 +
 drivers/net/dsa/lantiq/lantiq_gswip.c        | 1617 +----------------
 drivers/net/dsa/lantiq/lantiq_gswip.h        |    4 +
 drivers/net/dsa/lantiq/lantiq_gswip_common.c | 1622 ++++++++++++++++++
 5 files changed, 1658 insertions(+), 1592 deletions(-)
 create mode 100644 drivers/net/dsa/lantiq/lantiq_gswip_common.c
drivers/net/dsa/lantiq/Kconfig +5 -1
index 3cfa16840cf5..78db82a47d09 100644
@@ -1,8 +1,12 @@
+config NET_DSA_LANTIQ_COMMON
+	tristate
+	select REGMAP
+
 config NET_DSA_LANTIQ_GSWIP
 	tristate "Lantiq / Intel GSWIP"
 	depends on HAS_IOMEM
 	select NET_DSA_TAG_GSWIP
-	select REGMAP
+	select NET_DSA_LANTIQ_COMMON
 	help
 	  This enables support for the Lantiq / Intel GSWIP 2.1 found in
 	  the xrx200 / VR9 SoC.
drivers/net/dsa/lantiq/Makefile +1 -0
index 849f85ebebd6..65ffa7bb71aa 100644
@@ -1 +1,2 @@
 obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
+obj-$(CONFIG_NET_DSA_LANTIQ_COMMON) += lantiq_gswip_common.o
drivers/net/dsa/lantiq/lantiq_gswip.c +26 -1591

1,665 lines not on this page · raw message

drivers/net/dsa/lantiq/lantiq_gswip.h +4 -0
index 24d759e06e15..d86290db19b4 100644
@@ -278,4 +278,8 @@ struct gswip_priv {
 	u16 version;
 };
 
+void gswip_disable_switch(struct gswip_priv *priv);
+
+int gswip_probe_common(struct gswip_priv *priv, u32 version);
+
 #endif /* __LANTIQ_GSWIP_H */
drivers/net/dsa/lantiq/lantiq_gswip_common.c new file +1622 -0

1,312 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.51.0

Part of the diff is not shown here. View the raw message.

#2 lore raw

PATCH v2 2/13 net: dsa: lantiq_gswip: support enable/disable learning

In reply to Daniel Golle

Switch API 2.2 or later supports enabling or disabling learning on each port. Implement support for BR_LEARNING bridge flag and announce support for BR_LEARNING on GSWIP 2.2 or later.

---
v2: initialize supported flags with 0

 drivers/net/dsa/lantiq/lantiq_gswip.h        |  3 ++
 drivers/net/dsa/lantiq/lantiq_gswip_common.c | 43 ++++++++++++++++++++
 2 files changed, 46 insertions(+)
drivers/net/dsa/lantiq/lantiq_gswip.h +3 -0
index d86290db19b4..fb7d2c02bde9 100644
@@ -157,6 +157,9 @@
 #define  GSWIP_PCE_PCTRL_0_PSTATE_LEARNING	0x3
 #define  GSWIP_PCE_PCTRL_0_PSTATE_FORWARDING	0x7
 #define  GSWIP_PCE_PCTRL_0_PSTATE_MASK	GENMASK(2, 0)
+/* Ethernet Switch PCE Port Control Register 3 */
+#define GSWIP_PCE_PCTRL_3p(p)		(0x483 + ((p) * 0xA))
+#define  GSWIP_PCE_PCTRL_3_LNDIS	BIT(15)  /* Learning Disable */
 #define GSWIP_PCE_VCTRL(p)		(0x485 + ((p) * 0xA))
 #define  GSWIP_PCE_VCTRL_UVR		BIT(0)	/* Unknown VLAN Rule */
 #define  GSWIP_PCE_VCTRL_VINR		GENMASK(2, 1) /* VLAN Ingress Tag Rule */
drivers/net/dsa/lantiq/lantiq_gswip_common.c +43 -0

55 lines not on this page · raw message

Signature · 1 line
2.51.0
#3 lore raw

PATCH v2 3/13 net: dsa: lantiq_gswip: support Energy Efficient Ethernet

In reply to Daniel Golle

Introduce support for Energy Efficient Ethernet (EEE) on hardware version 2.2 or later.

---
 drivers/net/dsa/lantiq/lantiq_gswip.h        |  7 +++
 drivers/net/dsa/lantiq/lantiq_gswip_common.c | 47 ++++++++++++++++++++
 2 files changed, 54 insertions(+)
drivers/net/dsa/lantiq/lantiq_gswip.h +7 -0
index fb7d2c02bde9..56de869fc472 100644
@@ -2,6 +2,7 @@
 #ifndef __LANTIQ_GSWIP_H
 #define __LANTIQ_GSWIP_H
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/mutex.h>
 #include <linux/phylink.h>
@@ -193,6 +194,12 @@
 #define GSWIP_MAC_CTRL_2p(p)		(0x905 + ((p) * 0xC))
 #define GSWIP_MAC_CTRL_2_LCHKL		BIT(2) /* Frame Length Check Long Enable */
 #define GSWIP_MAC_CTRL_2_MLEN		BIT(3) /* Maximum Untagged Frame Lnegth */
+#define GSWIP_MAC_CTRL_4p(p)		(0x907 + ((p) * 0xC))
+#define  GSWIP_MAC_CTRL_4_LPIEN		BIT(7) /* LPI Mode Enable */
+#define  GSWIP_MAC_CTRL_4_GWAIT_MASK	GENMASK(14, 8) /* LPI Wait Time 1G */
+#define  GSWIP_MAC_CTRL_4_GWAIT(t)	u16_encode_bits((t), GSWIP_MAC_CTRL_4_GWAIT_MASK)
+#define  GSWIP_MAC_CTRL_4_WAIT_MASK	GENMASK(6, 0) /* LPI Wait Time 100M */
+#define  GSWIP_MAC_CTRL_4_WAIT(t)	u16_encode_bits((t), GSWIP_MAC_CTRL_4_WAIT_MASK)
 
 /* Ethernet Switch Fetch DMA Port Control Register */
 #define GSWIP_FDMA_PCTRLp(p)		(0xA80 + ((p) * 0x6))
drivers/net/dsa/lantiq/lantiq_gswip_common.c +47 -0

65 lines not on this page · raw message

Signature · 1 line
2.51.0
Reviewed-by on v2 3/13
#4 lore raw

Re: [PATCH net-next v2 03/13] net: dsa: lantiq_gswip: support Energy Efficient Ethernet

Quoted 4 lines · Daniel Golle

Introduce support for Energy Efficient Ethernet (EEE) on hardware version 2.2 or later.

Thanks!

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
#5 lore raw

PATCH v2 4/13 net: dsa: lantiq_gswip: set link parameters also for CPU port

In reply to Daniel Golle

On standalone switch ICs the link parameters of the CPU port need to be setup just like user ports. The destinction in the driver to not carry out link parameter setup for the CPU port does make sense for in-SoC switches on which the CPU port is internally connected to the SoC's Ethernet MAC.
Set link parameters also for the CPU port unless it is an internal interface.

---
 drivers/net/dsa/lantiq/lantiq_gswip_common.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/lantiq/lantiq_gswip_common.c +1 -1
index 092187603dea..0ac87eb23bb5 100644
@@ -1459,7 +1459,7 @@ static void gswip_phylink_mac_link_up(struct phylink_config *config,
 	struct gswip_priv *priv = dp->ds->priv;
 	int port = dp->index;
 
-	if (!dsa_port_is_cpu(dp)) {
+	if (!dsa_port_is_cpu(dp) || interface != PHY_INTERFACE_MODE_INTERNAL) {
 		gswip_port_set_link(priv, port, true);
 		gswip_port_set_speed(priv, port, speed, interface);
 		gswip_port_set_duplex(priv, port, duplex);
Signature · 1 line
2.51.0
#6 lore raw

PATCH v2 5/13 net: dsa: lantiq_gswip: define and use GSWIP_TABLE_MAC_BRIDGE_VAL1_VALID

In reply to Daniel Golle

When adding FDB entries to the MAC bridge table it is needed to set an (undocumented) bit to mark the entry as valid. If this bit isn't set for entries in the MAC bridge table, then those entries won't be considered as valid MAC addresses.

---
 drivers/net/dsa/lantiq/lantiq_gswip.h        | 1 +
 drivers/net/dsa/lantiq/lantiq_gswip_common.c | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/net/dsa/lantiq/lantiq_gswip.h +1 -0
index 56de869fc472..42000954d842 100644
@@ -224,6 +224,7 @@
 #define  GSWIP_TABLE_MAC_BRIDGE_KEY3_FID	GENMASK(5, 0)	/* Filtering identifier */
 #define  GSWIP_TABLE_MAC_BRIDGE_VAL0_PORT	GENMASK(7, 4)	/* Port on learned entries */
 #define  GSWIP_TABLE_MAC_BRIDGE_VAL1_STATIC	BIT(0)		/* Static, non-aging entry */
+#define  GSWIP_TABLE_MAC_BRIDGE_VAL1_VALID	BIT(1)		/* Valid bit */
 
 #define XRX200_GPHY_FW_ALIGN	(16 * 1024)
 
drivers/net/dsa/lantiq/lantiq_gswip_common.c +2 -1
index 0ac87eb23bb5..94b187899db6 100644
@@ -1149,7 +1149,8 @@ static int gswip_port_fdb(struct dsa_switch *ds, int port,
 	mac_bridge.key[2] = addr[1] | (addr[0] << 8);
 	mac_bridge.key[3] = FIELD_PREP(GSWIP_TABLE_MAC_BRIDGE_KEY3_FID, fid);
 	mac_bridge.val[0] = add ? BIT(port) : 0; /* port map */
-	mac_bridge.val[1] = GSWIP_TABLE_MAC_BRIDGE_VAL1_STATIC;
+	mac_bridge.val[1] = add ? (GSWIP_TABLE_MAC_BRIDGE_VAL1_STATIC |
+				   GSWIP_TABLE_MAC_BRIDGE_VAL1_VALID) : 0;
 	mac_bridge.valid = add;
 
 	err = gswip_pce_table_entry_write(priv, &mac_bridge);
Signature · 1 line
2.51.0
#7 lore raw

PATCH v2 6/13 dt-bindings: net: dsa: lantiq,gswip: add support for MII delay properties

In reply to Daniel Golle

Add support for standard tx-internal-delay-ps and rx-internal-delay-ps properties on port nodes to allow fine-tuning of RGMII clock delays.

The GSWIP switch hardware supports delay values in 500 picosecond increments from 0 to 3500 picoseconds, with a default of 2000 picoseconds for both TX and RX delays.

This corresponds to the driver changes that allow adjusting MII delays using Device Tree properties instead of relying solely on the PHY interface mode.

---
 .../bindings/net/dsa/lantiq,gswip.yaml        | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +20 -0
index f3154b19af78..ed274bfb8d49 100644
@@ -8,6 +8,24 @@ title: Lantiq GSWIP Ethernet switches
 
 allOf:
   - $ref: dsa.yaml#/$defs/ethernet-ports
+  - properties:
+      ports:
+        patternProperties:
+          "^port@[0-6]$":
+            type: object
+            properties:
+              tx-internal-delay-ps:
+                enum: [0, 500, 1000, 1500, 2000, 2500, 3000, 3500]
+                default: 2000
+                description:
+                  RGMII TX Clock Delay defined in pico seconds.
+                  The delay lines adjust the MII clock vs. data timing.
+              rx-internal-delay-ps:
+                enum: [0, 500, 1000, 1500, 2000, 2500, 3000, 3500]
+                default: 2000
+                description:
+                  RGMII RX Clock Delay defined in pico seconds.
+                  The delay lines adjust the MII clock vs. data timing.
 
 maintainers:
   - Hauke Mehrtens <[email protected]>
@@ -115,6 +133,8 @@ examples:
                             label = "lan3";
                             phy-mode = "rgmii";
                             phy-handle = <&phy0>;
+                            tx-internal-delay-ps = <2000>;
+                            rx-internal-delay-ps = <2000>;
                     };
 
                     port@1 {
Signature · 1 line
2.51.0
#8 lore raw

Re: [PATCH net-next v2 06/13] dt-bindings: net: dsa: lantiq,gswip: add support for MII delay properties

Hi Daniel,

Quoted 46 lines · Daniel Golle

Add support for standard tx-internal-delay-ps and rx-internal-delay-ps properties on port nodes to allow fine-tuning of RGMII clock delays.

The GSWIP switch hardware supports delay values in 500 picosecond increments from 0 to 3500 picoseconds, with a default of 2000 picoseconds for both TX and RX delays.

This corresponds to the driver changes that allow adjusting MII delays using Device Tree properties instead of relying solely on the PHY interface mode.

---
 .../bindings/net/dsa/lantiq,gswip.yaml        | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +18 -0
index f3154b19af78..ed274bfb8d49 100644
@@ -8,6 +8,24 @@ title: Lantiq GSWIP Ethernet switches
 
 allOf:
   - $ref: dsa.yaml#/$defs/ethernet-ports
+  - properties:
+      ports:
+        patternProperties:
+          "^port@[0-6]$":
+            type: object
+            properties:
+              tx-internal-delay-ps:
+                enum: [0, 500, 1000, 1500, 2000, 2500, 3000, 3500]
+                default: 2000
+                description:
+                  RGMII TX Clock Delay defined in pico seconds.
+                  The delay lines adjust the MII clock vs. data timing.
+              rx-internal-delay-ps:
+                enum: [0, 500, 1000, 1500, 2000, 2500, 3000, 3500]
+                default: 2000
+                description:
+                  RGMII RX Clock Delay defined in pico seconds.
+                  The delay lines adjust the MII clock vs. data timing.
 
 maintainers:
   - Hauke Mehrtens <[email protected]>

Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml examples: · line 137

Quoted 5 lines
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +2 -0
@@ -115,6 +133,8 @@ examples:
                             label = "lan3";
                             phy-mode = "rgmii";
                             phy-handle = <&phy0>;
+                            tx-internal-delay-ps = <2000>;
+                            rx-internal-delay-ps = <2000>;

I guess that in this example, with a 2ns delay, this is no longer "rgmii" but "rgmii-id", as delays are inserted by the switch. It would make sense to update the phy-mode.

Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml examples: · line 140

Quoted 3 lines
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +0 -0
                     };
 
                     port@1 {

Maxime

#9 lore raw

PATCH v2 7/13 net: dsa: lantiq_gswip: allow adjusting MII delays

In reply to Daniel Golle

Currently the MII clk vs. data delay is configured based on the PHY interface mode.

In addition to that add support for setting up MII delays using the standard Device Tree properties 'tx-internal-delay-ps' and 'rx-internal-delay-ps' and only fall back to using the PHY interface mode in case both properties are unused.

---
 drivers/net/dsa/lantiq/lantiq_gswip.h        |  4 +++
 drivers/net/dsa/lantiq/lantiq_gswip_common.c | 31 ++++++++++++++++++++
 2 files changed, 35 insertions(+)
drivers/net/dsa/lantiq/lantiq_gswip.h +4 -0
index 42000954d842..0c32ec85e127 100644
@@ -82,6 +82,10 @@
 #define GSWIP_MII_PCDU5			0x05
 #define  GSWIP_MII_PCDU_TXDLY_MASK	GENMASK(2, 0)
 #define  GSWIP_MII_PCDU_RXDLY_MASK	GENMASK(9, 7)
+#define  GSWIP_MII_PCDU_TXDLY(x)	u16_encode_bits(((x) / 500), GSWIP_MII_PCDU_TXDLY_MASK)
+#define  GSWIP_MII_PCDU_RXDLY(x)	u16_encode_bits(((x) / 500), GSWIP_MII_PCDU_RXDLY_MASK)
+#define GSWIP_MII_PCDU_RXDLY_DEFAULT	2000 /* picoseconds */
+#define GSWIP_MII_PCDU_TXDLY_DEFAULT	2000 /* picoseconds */
 
 /* GSWIP Core Registers */
 #define GSWIP_SWRES			0x000
drivers/net/dsa/lantiq/lantiq_gswip_common.c +31 -0
index 94b187899db6..60a83093cd10 100644
@@ -622,6 +622,34 @@ static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port,
 	return 0;
 }
 
+static bool gswip_mii_delay_setup(struct gswip_priv *priv, struct dsa_port *dp)
+{
+	u32 tx_delay = GSWIP_MII_PCDU_TXDLY_DEFAULT;
+	u32 rx_delay = GSWIP_MII_PCDU_RXDLY_DEFAULT;
+	struct device_node *port_dn = dp->dn;
+	bool used;
+	int ret;
+
+	ret = of_property_read_u32(port_dn, "tx-internal-delay-ps", &tx_delay);
+	if (ret && ret != -EINVAL)
+		return ret;
+	used = !ret;
+
+	ret = of_property_read_u32(port_dn, "rx-internal-delay-ps", &rx_delay);
+	if (ret && ret != -EINVAL)
+		return ret;
+	used |= !ret;
+
+	if (used)
+		gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK |
+					  GSWIP_MII_PCDU_RXDLY_MASK,
+					  GSWIP_MII_PCDU_TXDLY(tx_delay) |
+					  GSWIP_MII_PCDU_RXDLY(rx_delay),
+					  dp->index);
+
+	return used;
+}
+
 static int gswip_setup(struct dsa_switch *ds)
 {
 	unsigned int cpu_ports = dsa_cpu_ports(ds);
@@ -1419,6 +1447,9 @@ static void gswip_phylink_mac_config(struct phylink_config *config,
 			   GSWIP_MII_CFG_RGMII_IBS | GSWIP_MII_CFG_LDCLKDIS,
 			   miicfg, port);
 
+	if (gswip_mii_delay_setup(priv, dp))
+		return;
+
 	switch (state->interface) {
 	case PHY_INTERFACE_MODE_RGMII_ID:
 		gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK |
Signature · 1 line
2.51.0
#10 lore raw

PATCH v2 8/13 dt-bindings: net: dsa: lantiq,gswip: add MaxLinear RMII refclk output property

In reply to Daniel Golle

Add support for the maxlinear,rmii-refclk-out boolean property on port nodes to configure the RMII reference clock to be an output rather than an input.

This property is only applicable for non-RGMII ports and allows the switch to provide the reference clock for RMII-connected PHYs instead of requiring an external clock source.

This corresponds to the driver changes that read this Device Tree property to configure the RMII clock direction.

---
 .../devicetree/bindings/net/dsa/lantiq,gswip.yaml          | 7 +++++++
 1 file changed, 7 insertions(+)
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +7 -0
index ed274bfb8d49..48641c27da10 100644
@@ -13,6 +13,8 @@ allOf:
         patternProperties:
           "^port@[0-6]$":
             type: object
+            allOf:
+              - $ref: /schemas/net/dsa/dsa-port.yaml#
             properties:
               tx-internal-delay-ps:
                 enum: [0, 500, 1000, 1500, 2000, 2500, 3000, 3500]
@@ -26,6 +28,11 @@ allOf:
                 description:
                   RGMII RX Clock Delay defined in pico seconds.
                   The delay lines adjust the MII clock vs. data timing.
+              maxlinear,rmii-refclk-out:
+                type: boolean
+                description:
+                  Configure the RMII reference clock to be a clock output
+                  rather than an input. Only applicable for RMII mode.
 
 maintainers:
   - Hauke Mehrtens <[email protected]>
Signature · 1 line
2.51.0
#11 lore raw

PATCH v2 9/13 net: dsa: lantiq_gswip: add vendor property to setup MII refclk output

In reply to Daniel Golle

Read boolean Device Tree property "maxlinear,rmii-refclk-out" and switch the RMII reference clock to be a clock output rather than an input if it is set.

---
 drivers/net/dsa/lantiq/lantiq_gswip_common.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/net/dsa/lantiq/lantiq_gswip_common.c +4 -0
index 60a83093cd10..bf38ecc13f76 100644
@@ -1442,6 +1442,10 @@ static void gswip_phylink_mac_config(struct phylink_config *config,
 		return;
 	}
 
+	if (of_property_read_bool(dp->dn, "maxlinear,rmii-refclk-out") &&
+	    !(miicfg & GSWIP_MII_CFG_MODE_RGMII))
+		miicfg |= GSWIP_MII_CFG_RMII_CLK;
+
 	gswip_mii_mask_cfg(priv,
 			   GSWIP_MII_CFG_MODE_MASK | GSWIP_MII_CFG_RMII_CLK |
 			   GSWIP_MII_CFG_RGMII_IBS | GSWIP_MII_CFG_LDCLKDIS,
Signature · 1 line
2.51.0
#12 lore raw

PATCH v2 10/13 dt-bindings: net: dsa: lantiq,gswip: add support for MaxLinear GSW1xx switches

In reply to Daniel Golle

Extend the Lantiq GSWIP device tree binding to also cover MaxLinear GSW1xx switches which are based on the same hardware IP but connected via MDIO instead of being memory-mapped.

Add compatible strings for MaxLinear GSW120, GSW125, GSW140, GSW141, and GSW145 switches and adjust the schema to handle the different connection methods with conditional properties.

Add MaxLinear GSW125 example showing MDIO-connected configuration.

---
v2:
* remove git conflict left-overs which somehow creeped in
* indent example with 4 spaces instead of tabs

 .../bindings/net/dsa/lantiq,gswip.yaml        | 264 +++++++++++++-----
 1 file changed, 191 insertions(+), 73 deletions(-)
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +191 -73
index 48641c27da10..017021d3b511 100644
@@ -4,7 +4,12 @@
 $id: http://devicetree.org/schemas/net/dsa/lantiq,gswip.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Lantiq GSWIP Ethernet switches
+title: Lantiq GSWIP and MaxLinear GSW1xx Ethernet switches
+
+description:
+  Lantiq GSWIP and MaxLinear GSW1xx switches share the same hardware IP.
+  Lantiq switches are embedded in SoCs and accessed via memory-mapped I/O,
+  while MaxLinear switches are standalone ICs connected via MDIO.
 
 allOf:
   - $ref: dsa.yaml#/$defs/ethernet-ports
@@ -33,6 +38,98 @@ allOf:
                 description:
                   Configure the RMII reference clock to be a clock output
                   rather than an input. Only applicable for RMII mode.
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - lantiq,xrx200-gswip
+              - lantiq,xrx300-gswip
+              - lantiq,xrx330-gswip
+    then:
+      properties:
+        reg:
+          minItems: 3
+          maxItems: 3
+          description: Memory-mapped register regions (switch, mdio, mii)
+        reg-names:
+          items:
+            - const: switch
+            - const: mdio
+            - const: mii
+        mdio:
+          $ref: /schemas/net/mdio.yaml#
+          unevaluatedProperties: false
+
+          properties:
+            compatible:
+              const: lantiq,xrx200-mdio
+
+          required:
+            - compatible
+        gphy-fw:
+          type: object
+          properties:
+            '#address-cells':
+              const: 1
+
+            '#size-cells':
+              const: 0
+
+            compatible:
+              items:
+                - enum:
+                    - lantiq,xrx200-gphy-fw
+                    - lantiq,xrx300-gphy-fw
+                    - lantiq,xrx330-gphy-fw
+                - const: lantiq,gphy-fw
+
+            lantiq,rcu:
+              $ref: /schemas/types.yaml#/definitions/phandle
+              description: phandle to the RCU syscon
+
+          patternProperties:
+            "^gphy@[0-9a-f]{1,2}$":
+              type: object
+
+              additionalProperties: false
+
+              properties:
+                reg:
+                  minimum: 0
+                  maximum: 255
+                  description:
+                    Offset of the GPHY firmware register in the RCU register
+                    range
+
+                resets:
+                  items:
+                    - description: GPHY reset line
+
+                reset-names:
+                  items:
+                    - const: gphy
+
+              required:
+                - reg
+
+          required:
+            - compatible
+            - lantiq,rcu
+
+          additionalProperties: false
+      required:
+        - reg-names
+    else:
+      properties:
+        reg:
+          maxItems: 1
+          description: MDIO bus address
+        reg-names: false
+        gphy-fw: false
+        mdio:
+          $ref: /schemas/net/mdio.yaml#
+          unevaluatedProperties: false
 
 maintainers:
   - Hauke Mehrtens <[email protected]>
@@ -43,78 +140,11 @@ properties:
       - lantiq,xrx200-gswip
       - lantiq,xrx300-gswip
       - lantiq,xrx330-gswip
-
-  reg:
-    minItems: 3
-    maxItems: 3
-
-  reg-names:
-    items:
-      - const: switch
-      - const: mdio
-      - const: mii
-
-  mdio:
-    $ref: /schemas/net/mdio.yaml#
-    unevaluatedProperties: false
-
-    properties:
-      compatible:
-        const: lantiq,xrx200-mdio
-
-    required:
-      - compatible
-
-  gphy-fw:
-    type: object
-    properties:
-      '#address-cells':
-        const: 1
-
-      '#size-cells':
-        const: 0
-
-      compatible:
-        items:
-          - enum:
-              - lantiq,xrx200-gphy-fw
-              - lantiq,xrx300-gphy-fw
-              - lantiq,xrx330-gphy-fw
-          - const: lantiq,gphy-fw
-
-      lantiq,rcu:
-        $ref: /schemas/types.yaml#/definitions/phandle
-        description: phandle to the RCU syscon
-
-    patternProperties:
-      "^gphy@[0-9a-f]{1,2}$":
-        type: object
-
-        additionalProperties: false
-
-        properties:
-          reg:
-            minimum: 0
-            maximum: 255
-            description:
-              Offset of the GPHY firmware register in the RCU register range
-
-          resets:
-            items:
-              - description: GPHY reset line
-
-          reset-names:
-            items:
-              - const: gphy
-
-        required:
-          - reg
-
-    required:
-      - compatible
-      - lantiq,rcu
-
-    additionalProperties: false
+      - maxlinear,gsw120
+      - maxlinear,gsw125
+      - maxlinear,gsw140
+      - maxlinear,gsw141
+      - maxlinear,gsw145
 
 required:
   - compatible
@@ -129,6 +159,7 @@ examples:
             reg = <0xe108000 0x3100>,  /* switch */
                   <0xe10b100 0xd8>,    /* mdio */
                   <0xe10b1d8 0x130>;   /* mii */
+            reg-names = "switch", "mdio", "mii";
             dsa,member = <0 0>;
 
             ports {
@@ -227,3 +258,90 @@ examples:
                     };
             };
     };
+
+  - |
+    #include <dt-bindings/leds/common.h>
+
+    mdio {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        switch@1f {
+            compatible = "maxlinear,gsw125";
+            reg = <0x1f>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    label = "lan0";
+                    phy-handle = <&switchphy0>;
+                    phy-mode = "internal";
+                };
+
+                port@1 {
+                    reg = <1>;
+                    label = "lan1";
+                    phy-handle = <&switchphy1>;
+                    phy-mode = "internal";
+                };
+
+                port@4 {
+                    reg = <4>;
+                    label = "wan";
+                    phy-mode = "sgmii";
+                    managed = "in-band-status";
+                };
+
+                port@5 {
+                    reg = <5>;
+                    phy-mode = "rgmii-id";
+                    tx-internal-delay-ps = <2000>;
+                    rx-internal-delay-ps = <2000>;
+                    ethernet = <&eth0>;
+
+                    fixed-link {
+                        speed = <1000>;
+                        full-duplex;
+                    };
+                };
+            };
+
+            mdio {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                switchphy0: switchphy@0 {
+                    reg = <0>;
+
+                    leds {
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+
+                        led@0 {
+                            reg = <0>;
+                            color = <LED_COLOR_ID_GREEN>;
+                            function = LED_FUNCTION_LAN;
+                        };
+                    };
+                };
+
+                switchphy1: switchphy@1 {
+                    reg = <1>;
+
+                    leds {
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+
+                        led@0 {
+                            reg = <0>;
+                            color = <LED_COLOR_ID_GREEN>;
+                            function = LED_FUNCTION_LAN;
+                        };
+                    };
+                };
+            };
+        };
+    };
Signature · 1 line
2.51.0
#13 lore raw

PATCH v2 11/13 net: dsa: add tagging driver for MaxLinear GSW1xx switch family

In reply to Daniel Golle

Add support for a new DSA tagging protocol driver for the MaxLinear GSW1xx switch family. The GSW1xx switches use a proprietary 8-byte special tag inserted between the source MAC address and the EtherType field to indicate the source and destination ports for frames traversing the CPU port.

Implement the tag handling logic to insert the special tag on transmit and parse it on receive.

---
since RFC:
* use dsa etype header macros instead of open coding them
* maintain alphabetic order in Kconfig and Makefile

 MAINTAINERS              |   3 +-
 include/net/dsa.h        |   2 +
 net/dsa/Kconfig          |   8 +++
 net/dsa/Makefile         |   1 +
 net/dsa/tag_mxl-gsw1xx.c | 141 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+), 1 deletion(-)
 create mode 100644 net/dsa/tag_mxl-gsw1xx.c
MAINTAINERS +2 -1
index 3ed59823f7a4..1db770b7274d 100644
@@ -14037,7 +14037,7 @@ F:	tools/testing/selftests/landlock/
 K:	landlock
 K:	LANDLOCK
 
-LANTIQ / INTEL Ethernet drivers
+LANTIQ / MAXLINEAR / INTEL Ethernet DSA drivers
 M:	Hauke Mehrtens <[email protected]>
 L:	[email protected]
 S:	Maintained
@@ -14045,6 +14045,7 @@ F:	Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml
 F:	drivers/net/dsa/lantiq/*
 F:	drivers/net/ethernet/lantiq_xrx200.c
 F:	net/dsa/tag_gswip.c
+F:	net/dsa/tag_mxl-gsw1xx.c
 
 LANTIQ MIPS ARCHITECTURE
 M:	John Crispin <[email protected]>
include/net/dsa.h +2 -0
index 67762fdaf3c7..2df2e2ead9a8 100644
@@ -56,6 +56,7 @@ struct tc_action;
 #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE	28
 #define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE	29
 #define DSA_TAG_PROTO_YT921X_VALUE		30
+#define DSA_TAG_PROTO_MXL_GSW1XX_VALUE		31
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -89,6 +90,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_LAN937X		= DSA_TAG_PROTO_LAN937X_VALUE,
 	DSA_TAG_PROTO_VSC73XX_8021Q	= DSA_TAG_PROTO_VSC73XX_8021Q_VALUE,
 	DSA_TAG_PROTO_YT921X		= DSA_TAG_PROTO_YT921X_VALUE,
+	DSA_TAG_PROTO_MXL_GSW1XX	= DSA_TAG_PROTO_MXL_GSW1XX_VALUE,
 };
 
 struct dsa_switch;
net/dsa/Kconfig +8 -0
index 6b94028b1fcc..f86b30742122 100644
@@ -104,6 +104,14 @@ config NET_DSA_TAG_MTK
 	  Say Y or M if you want to enable support for tagging frames for
 	  Mediatek switches.
 
+config NET_DSA_TAG_MXL_GSW1XX
+	tristate "Tag driver for MaxLinear GSW1xx switches"
+	help
+	  The GSW1xx family of switches supports an 8-byte special tag which
+	  can be used on the CPU port of the switch.
+	  Say Y or M if you want to enable support for tagging frames for
+	  MaxLinear GSW1xx switches.
+
 config NET_DSA_TAG_KSZ
 	tristate "Tag driver for Microchip 8795/937x/9477/9893 families of switches"
 	help
net/dsa/Makefile +1 -0
index 4b011a1d5c87..42d173f5a701 100644
@@ -28,6 +28,7 @@ obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
 obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
 obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
 obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
+obj-$(CONFIG_NET_DSA_TAG_MXL_GSW1XX) += tag_mxl-gsw1xx.o
 obj-$(CONFIG_NET_DSA_TAG_NONE) += tag_none.o
 obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o
 obj-$(CONFIG_NET_DSA_TAG_OCELOT_8021Q) += tag_ocelot_8021q.o
net/dsa/tag_mxl-gsw1xx.c new file +141 -0

141 lines not on this page · raw message

Signature · 1 line
2.51.0
#14 lore raw

PATCH v2 12/13 net: dsa: lantiq_gswip: add registers specific for MaxLinear GSW1xx

In reply to Daniel Golle

Add all registers needed for MaxLinear GSW1xx family of dedicated switch ICs connected via MDIO or SPI.

---
 drivers/net/dsa/lantiq/lantiq_gswip.h | 109 ++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)
drivers/net/dsa/lantiq/lantiq_gswip.h +109 -0
index 0c32ec85e127..bc8cd118a474 100644
@@ -232,6 +232,114 @@
 
 #define XRX200_GPHY_FW_ALIGN	(16 * 1024)
 
+#define GSW1XX_PORTS				6
+/* Port used for RGMII or optional RMII */
+#define GSW1XX_MII_PORT				0x5
+/* Port used for SGMII */
+#define GSW1XX_SGMII_PORT			0x4
+
+#define GSW1XX_SYS_CLK_FREQ			340000000
+
+/* SMDIO switch register base address */
+#define GSW1XX_SMDIO_BADR			0x1f
+#define  GSW1XX_SMDIO_BADR_UNKNOWN		-1
+
+/* GSW1XX SGMII PCS */
+#define GSW1XX_SGMII_BASE			0xd000
+#define GSW1XX_SGMII_PHY_HWBU_CTRL		0x009
+#define  GSW1XX_SGMII_PHY_HWBU_CTRL_EN_HWBU_FSM	BIT(0)
+#define  GSW1XX_SGMII_PHY_HWBU_CTRL_HW_FSM_EN	BIT(3)
+#define GSW1XX_SGMII_TBI_TXANEGH		0x300
+#define GSW1XX_SGMII_TBI_TXANEGL		0x301
+#define GSW1XX_SGMII_TBI_ANEGCTL		0x304
+#define  GSW1XX_SGMII_TBI_ANEGCTL_LT		GENMASK(1, 0)
+#define   GSW1XX_SGMII_TBI_ANEGCTL_LT_10US	0
+#define   GSW1XX_SGMII_TBI_ANEGCTL_LT_1_6MS	1
+#define   GSW1XX_SGMII_TBI_ANEGCTL_LT_5MS	2
+#define   GSW1XX_SGMII_TBI_ANEGCTL_LT_10MS	3
+#define  GSW1XX_SGMII_TBI_ANEGCTL_ANEGEN	BIT(2)
+#define  GSW1XX_SGMII_TBI_ANEGCTL_RANEG		BIT(3)
+#define  GSW1XX_SGMII_TBI_ANEGCTL_OVRABL	BIT(4)
+#define  GSW1XX_SGMII_TBI_ANEGCTL_OVRANEG	BIT(5)
+#define  GSW1XX_SGMII_TBI_ANEGCTL_ANMODE	GENMASK(7, 6)
+#define   GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_1000BASEX	1
+#define   GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_SGMII_PHY	2
+#define   GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_SGMII_MAC	3
+#define  GSW1XX_SGMII_TBI_ANEGCTL_BCOMP		BIT(15)
+
+#define GSW1XX_SGMII_TBI_TBICTL			0x305
+#define  GSW1XX_SGMII_TBI_TBICTL_INITTBI	BIT(0)
+#define  GSW1XX_SGMII_TBI_TBICTL_ENTBI		BIT(1)
+#define  GSW1XX_SGMII_TBI_TBICTL_CRSTRR		BIT(4)
+#define  GSW1XX_SGMII_TBI_TBICTL_CRSOFF		BIT(5)
+#define GSW1XX_SGMII_TBI_TBISTAT		0x309
+#define  GSW1XX_SGMII_TBI_TBISTAT_LINK		BIT(0)
+#define  GSW1XX_SGMII_TBI_TBISTAT_AN_COMPLETE	BIT(1)
+#define GSW1XX_SGMII_TBI_LPSTAT			0x30a
+#define  GSW1XX_SGMII_TBI_LPSTAT_DUPLEX		BIT(0)
+#define  GSW1XX_SGMII_TBI_LPSTAT_PAUSE_RX	BIT(1)
+#define  GSW1XX_SGMII_TBI_LPSTAT_PAUSE_TX	BIT(2)
+#define  GSW1XX_SGMII_TBI_LPSTAT_SPEED		GENMASK(6, 5)
+#define   GSW1XX_SGMII_TBI_LPSTAT_SPEED_10	0
+#define   GSW1XX_SGMII_TBI_LPSTAT_SPEED_100	1
+#define   GSW1XX_SGMII_TBI_LPSTAT_SPEED_1000	2
+#define   GSW1XX_SGMII_TBI_LPSTAT_SPEED_NOSGMII	3
+#define GSW1XX_SGMII_PHY_D			0x100
+#define GSW1XX_SGMII_PHY_A			0x101
+#define GSW1XX_SGMII_PHY_C			0x102
+#define  GSW1XX_SGMII_PHY_STATUS		BIT(0)
+#define  GSW1XX_SGMII_PHY_READ			BIT(4)
+#define  GSW1XX_SGMII_PHY_WRITE			BIT(8)
+#define  GSW1XX_SGMII_PHY_RESET_N		BIT(12)
+#define GSW1XX_SGMII_PCS_RXB_CTL		0x401
+#define  GSW1XX_SGMII_PCS_RXB_CTL_INIT_RX_RXB	BIT(1)
+#define GSW1XX_SGMII_PCS_TXB_CTL		0x404
+#define  GSW1XX_SGMII_PCS_TXB_CTL_INIT_TX_TXB	BIT(1)
+
+#define GSW1XX_SGMII_PHY_RX0_CFG2		0x004
+#define  GSW1XX_SGMII_PHY_RX0_CFG2_EQ		GENMASK(2, 0)
+#define   GSW1XX_SGMII_PHY_RX0_CFG2_EQ_DEF	2
+#define  GSW1XX_SGMII_PHY_RX0_CFG2_INVERT	BIT(3)
+#define  GSW1XX_SGMII_PHY_RX0_CFG2_LOS_EN	BIT(4)
+#define  GSW1XX_SGMII_PHY_RX0_CFG2_TERM_EN	BIT(5)
+#define  GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT	GENMASK(12, 6)
+#define   GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT_DEF	20
+
+/* GSW1XX PDI Registers */
+#define GSW1XX_SWITCH_BASE			0xe000
+
+/* GSW1XX MII Registers */
+#define GSW1XX_RGMII_BASE			0xf100
+
+/* GSW1XX GPIO Registers */
+#define GSW1XX_GPIO_BASE			0xf300
+#define GPIO_ALTSEL0				0x83
+#define GPIO_ALTSEL0_EXTPHY_MUX_VAL		0x03c3
+#define GPIO_ALTSEL1				0x84
+#define GPIO_ALTSEL1_EXTPHY_MUX_VAL		0x003f
+
+/* MDIO bus controller */
+#define GSW1XX_MMDIO_BASE			0xf400
+
+/* generic IC registers */
+#define GSW1XX_SHELL_BASE			0xfa00
+#define  GSW1XX_SHELL_RST_REQ			0x01
+#define   GSW1XX_RST_REQ_SGMII_SHELL		BIT(5)
+/* RGMII PAD Slew Control Register */
+#define  GSW1XX_SHELL_RGMII_SLEW_CFG		0x78
+#define   RGMII_SLEW_CFG_RX_2_5_V		BIT(4)
+#define   RGMII_SLEW_CFG_TX_2_5_V		BIT(5)
+
+/* SGMII clock related settings */
+#define GSW1XX_CLK_BASE				0xf900
+#define  GSW1XX_CLK_NCO_CTRL			0x68
+#define   GSW1XX_SGMII_HSP_MASK			GENMASK(3, 2)
+#define   GSW1XX_SGMII_SEL			BIT(1)
+#define   GSW1XX_SGMII_1G			0x0
+#define   GSW1XX_SGMII_2G5			0xc
+#define   GSW1XX_SGMII_1G_NCO1			0x0
+#define   GSW1XX_SGMII_2G5_NCO2			0x2
+
 /* Maximum packet size supported by the switch. In theory this should be 10240,
  * but long packets currently cause lock-ups with an MTU of over 2526. Medium
  * packets are sometimes dropped (e.g. TCP over 2477, UDP over 2516-2519, ICMP
@@ -255,6 +363,7 @@ struct gswip_hw_info {
 	unsigned int allowed_cpu_ports;
 	unsigned int mii_ports;
 	int mii_port_reg_offset;
+	bool supports_2500m;
 	const struct gswip_pce_microcode (*pce_microcode)[];
 	size_t pce_microcode_size;
 	enum dsa_tag_protocol tag_protocol;
Signature · 1 line
2.51.0
#15 lore raw

PATCH v2 13/13 net: dsa: add driver for MaxLinear GSW1xx switch family

In reply to Daniel Golle

Add driver for the MaxLinear GSW1xx family of Ethernet switch ICs which are based on the same IP as the Lantiq/Intel GSWIP found in the Lantiq VR9 and Intel GRX MIPS router SoCs. The main difference is that instead of using memory-mapped I/O to communicate with the host CPU these ICs are connected via MDIO (or SPI, which isn't supported by this driver). Implement the regmap API to access the switch registers over MDIO to allow reusing lantiq_gswip_common for all core functionality.

The GSW1xx also comes with a SerDes port capable of 1000Base-X, SGMII and 2500Base-X, which can either be used to connect an external PHY or SFP cage, or as the CPU port. Support for the SerDes interface is implemented in this driver using the phylink_pcs interface.

---
v2: remove left-overs of 4k VLAN support (will be added in future)

 drivers/net/dsa/lantiq/Kconfig          |  12 +
 drivers/net/dsa/lantiq/Makefile         |   1 +
 drivers/net/dsa/lantiq/mxl-gsw1xx.c     | 680 ++++++++++++++++++++++++
 drivers/net/dsa/lantiq/mxl-gsw1xx_pce.h | 154 ++++++
 4 files changed, 847 insertions(+)
 create mode 100644 drivers/net/dsa/lantiq/mxl-gsw1xx.c
 create mode 100644 drivers/net/dsa/lantiq/mxl-gsw1xx_pce.h
drivers/net/dsa/lantiq/Kconfig +12 -0
index 78db82a47d09..4a9771be5d58 100644
@@ -10,3 +10,15 @@ config NET_DSA_LANTIQ_GSWIP
 	help
 	  This enables support for the Lantiq / Intel GSWIP 2.1 found in
 	  the xrx200 / VR9 SoC.
+
+config NET_DSA_MXL_GSW1XX
+	tristate "MaxLinear GSW1xx Ethernet switch support"
+	select NET_DSA_TAG_MXL_GSW1XX
+	select NET_DSA_LANTIQ_COMMON
+	help
+	  This enables support for the MaxLinear GSW1xx family of 1GE switches
+	    GSW120 4 port, 2 PHYs, RGMII & SGMII/2500Base-X
+	    GSW125 4 port, 2 PHYs, RGMII & SGMII/2500Base-X, industrial temperature
+	    GSW140 6 port, 4 PHYs, RGMII & SGMII/2500Base-X
+	    GSW141 6 port, 4 PHYs, RGMII & SGMII
+	    GSW145 6 port, 4 PHYs, RGMII & SGMII/2500Base-X, industrial temperature
drivers/net/dsa/lantiq/Makefile +1 -0
index 65ffa7bb71aa..85fce605310b 100644
@@ -1,2 +1,3 @@
 obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
 obj-$(CONFIG_NET_DSA_LANTIQ_COMMON) += lantiq_gswip_common.o
+obj-$(CONFIG_NET_DSA_MXL_GSW1XX) += mxl-gsw1xx.o
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +680 -0

680 lines not on this page · raw message

drivers/net/dsa/lantiq/mxl-gsw1xx_pce.h new file +154 -0

154 lines not on this page · raw message

Signature · 1 line
2.51.0
#16 lore raw

Re: [PATCH net-next v2 13/13] net: dsa: add driver for MaxLinear GSW1xx switch family

Hi Daniel,

Quoted 15 lines · Daniel Golle

Add driver for the MaxLinear GSW1xx family of Ethernet switch ICs which are based on the same IP as the Lantiq/Intel GSWIP found in the Lantiq VR9 and Intel GRX MIPS router SoCs. The main difference is that instead of using memory-mapped I/O to communicate with the host CPU these ICs are connected via MDIO (or SPI, which isn't supported by this driver). Implement the regmap API to access the switch registers over MDIO to allow reusing lantiq_gswip_common for all core functionality.

The GSW1xx also comes with a SerDes port capable of 1000Base-X, SGMII and 2500Base-X, which can either be used to connect an external PHY or SFP cage, or as the CPU port. Support for the SerDes interface is implemented in this driver using the phylink_pcs interface.

---

[...]

Quoted 29 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +29 -0
+static int gsw1xx_sgmii_pcs_config(struct phylink_pcs *pcs,
+				   unsigned int neg_mode,
+				   phy_interface_t interface,
+				   const unsigned long *advertising,
+				   bool permit_pause_to_mac)
+{
+	struct gsw1xx_priv *priv = sgmii_pcs_to_gsw1xx(pcs);
+	bool sgmii_mac_mode = dsa_is_user_port(priv->gswip.ds, GSW1XX_SGMII_PORT);
+	u16 txaneg, anegctl, val, nco_ctrl;
+	int ret;
+
+	/* Assert and deassert SGMII shell reset */
+	ret = regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
+			      GSW1XX_RST_REQ_SGMII_SHELL);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_clear_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
+				GSW1XX_RST_REQ_SGMII_SHELL);
+	if (ret < 0)
+		return ret;
+
+	/* Hardware Bringup FSM Enable  */
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_PHY_HWBU_CTRL,
+			   GSW1XX_SGMII_PHY_HWBU_CTRL_EN_HWBU_FSM |
+			   GSW1XX_SGMII_PHY_HWBU_CTRL_HW_FSM_EN);
+	if (ret < 0)
+		return ret;
+

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 190

Quoted 10 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+	/* Configure SGMII PHY Receiver */
+	val = FIELD_PREP(GSW1XX_SGMII_PHY_RX0_CFG2_EQ,
+			 GSW1XX_SGMII_PHY_RX0_CFG2_EQ_DEF) |
+	      GSW1XX_SGMII_PHY_RX0_CFG2_LOS_EN |
+	      GSW1XX_SGMII_PHY_RX0_CFG2_TERM_EN |
+	      FIELD_PREP(GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT,
+			 GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT_DEF);
+
+	// if (!priv->dts.sgmii_rx_invert)
+		val |= GSW1XX_SGMII_PHY_RX0_CFG2_INVERT;

There's a leftover commented-out line here :)

Maxime

#17 lore raw

Re: [PATCH net-next v2 13/13] net: dsa: add driver for MaxLinear GSW1xx switch family

In reply to Daniel Golle
Quoted 11 lines · Daniel Golle
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +11 -0
+static int gsw1xx_sgmii_pcs_config(struct phylink_pcs *pcs,
+				   unsigned int neg_mode,
+				   phy_interface_t interface,
+				   const unsigned long *advertising,
+				   bool permit_pause_to_mac)
+{
+	struct gsw1xx_priv *priv = sgmii_pcs_to_gsw1xx(pcs);
+	bool sgmii_mac_mode = dsa_is_user_port(priv->gswip.ds, GSW1XX_SGMII_PORT);
+	u16 txaneg, anegctl, val, nco_ctrl;
+	int ret;
+

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 172

Quoted 10 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+	/* Assert and deassert SGMII shell reset */
+	ret = regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
+			      GSW1XX_RST_REQ_SGMII_SHELL);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_clear_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
+				GSW1XX_RST_REQ_SGMII_SHELL);
+	if (ret < 0)
+		return ret;

So this is disruptive. Overall, at this point, having added every other comment below, this code has me wondering whether you are aware of the documentation I have written in phylink.h for pcs_config(). This code goes against this paragraph in that documentation:

"
* pcs_config() will be called when configuration of the PCS is required
* or when the advertisement is possibly updated. It must not unnecessarily
* disrupt an established link.
"

Low quality implementations lead to poor user experiences.

Quoted 47 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +47 -0
+
+	/* Hardware Bringup FSM Enable  */
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_PHY_HWBU_CTRL,
+			   GSW1XX_SGMII_PHY_HWBU_CTRL_EN_HWBU_FSM |
+			   GSW1XX_SGMII_PHY_HWBU_CTRL_HW_FSM_EN);
+	if (ret < 0)
+		return ret;
+
+	/* Configure SGMII PHY Receiver */
+	val = FIELD_PREP(GSW1XX_SGMII_PHY_RX0_CFG2_EQ,
+			 GSW1XX_SGMII_PHY_RX0_CFG2_EQ_DEF) |
+	      GSW1XX_SGMII_PHY_RX0_CFG2_LOS_EN |
+	      GSW1XX_SGMII_PHY_RX0_CFG2_TERM_EN |
+	      FIELD_PREP(GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT,
+			 GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT_DEF);
+
+	// if (!priv->dts.sgmii_rx_invert)
+		val |= GSW1XX_SGMII_PHY_RX0_CFG2_INVERT;
+
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_PHY_RX0_CFG2, val);
+	if (ret < 0)
+		return ret;
+
+	/* Reset and Release TBI */
+	val = GSW1XX_SGMII_TBI_TBICTL_INITTBI | GSW1XX_SGMII_TBI_TBICTL_ENTBI |
+	      GSW1XX_SGMII_TBI_TBICTL_CRSTRR | GSW1XX_SGMII_TBI_TBICTL_CRSOFF;
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_TBI_TBICTL, val);
+	if (ret < 0)
+		return ret;
+	val &= ~GSW1XX_SGMII_TBI_TBICTL_INITTBI;
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_TBI_TBICTL, val);
+	if (ret < 0)
+		return ret;
+
+	/* Release Tx Data Buffers */
+	ret = regmap_set_bits(priv->sgmii, GSW1XX_SGMII_PCS_TXB_CTL,
+			      GSW1XX_SGMII_PCS_TXB_CTL_INIT_TX_TXB);
+	if (ret < 0)
+		return ret;
+	ret = regmap_clear_bits(priv->sgmii, GSW1XX_SGMII_PCS_TXB_CTL,
+				GSW1XX_SGMII_PCS_TXB_CTL_INIT_TX_TXB);
+	if (ret < 0)
+		return ret;
+
+	/* Release Rx Data Buffers */
+	ret = regmap_set_bits(priv->sgmii, GSW1XX_SGMII_PCS_RXB_CTL,
+			      GSW1XX_SGMII_PCS_RXB_CTL_INIT_RX_RXB);

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 229

Quoted 10 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+	if (ret < 0)
+		return ret;
+	ret = regmap_clear_bits(priv->sgmii, GSW1XX_SGMII_PCS_RXB_CTL,
+				GSW1XX_SGMII_PCS_RXB_CTL_INIT_RX_RXB);
+	if (ret < 0)
+		return ret;
+
+	anegctl = GSW1XX_SGMII_TBI_ANEGCTL_OVRANEG;
+	if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED)
+		anegctl |= GSW1XX_SGMII_TBI_ANEGCTL_OVRABL;

override aneg and override able? What's this doing?

Quoted 16 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +16 -0
+
+	switch (phylink_get_link_timer_ns(interface)) {
+	case 10000:
+		anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_LT,
+				      GSW1XX_SGMII_TBI_ANEGCTL_LT_10US);
+		break;
+	case 1600000:
+		anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_LT,
+				      GSW1XX_SGMII_TBI_ANEGCTL_LT_1_6MS);
+		break;
+	case 5000000:
+		anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_LT,
+				      GSW1XX_SGMII_TBI_ANEGCTL_LT_5MS);
+		break;
+	case 10000000:
+		anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_LT,

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 255

Quoted 10 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+				      GSW1XX_SGMII_TBI_ANEGCTL_LT_10MS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (interface == PHY_INTERFACE_MODE_SGMII) {
+		txaneg = ADVERTISE_SGMII;
+		if (sgmii_mac_mode) {
+			txaneg |= BIT(14); /* MAC should always send BIT 14 */

Bit 14 is ADVERTISE_LPACK.

I think I'd prefer:

			txaneg = ADVERTISE_SGMII | ADVERTISE_LPACK;

and...

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 259

Quoted 4 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +4 -0
+			anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_ANMODE,
+					      GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_SGMII_MAC);
+		} else {
+			txaneg |= LPA_SGMII_1000FULL;
			txaneg = LPA_SGMII | LPA_SGMII_1000FULL;

here.

Review

Quoted 2 lines
(quoted diff) +2 -0
+			anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_ANMODE,
+					      GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_SGMII_PHY);

So this seems to be yet another case of reverse SGMII. Andrew, please can we get to a conclusion on PHY_INTERFACE_MODE_REVSGMII before we end up with a crapshow of drivers doing their own stuff *exactly* like we see here?

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 265

Quoted 2 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +2 -0
+		if (neg_mode & PHYLINK_PCS_NEG_INBAND)
+			anegctl |= GSW1XX_SGMII_TBI_ANEGCTL_ANEGEN;

Please add a comment describing what is going on here. What does this register bit do...

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 268

Quoted 3 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +3 -0
+	} else if (interface == PHY_INTERFACE_MODE_1000BASEX ||
+		   interface == PHY_INTERFACE_MODE_2500BASEX) {
+		txaneg = BIT(5) | BIT(7);

ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE ?

Quoted 144 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +144 -0
+		anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_ANMODE,
+				      GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_1000BASEX);
+	} else {
+		dev_err(priv->gswip.dev, "%s: SGMII wrong interface mode %s\n",
+			__func__, phy_modes(interface));
+		return -EINVAL;
+	}
+
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_TBI_TXANEGH,
+			   FIELD_GET(GENMASK(15, 8), txaneg));
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_TBI_TXANEGL,
+			   FIELD_GET(GENMASK(7, 0), txaneg));
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL, anegctl);
+	if (ret < 0)
+		return ret;
+
+	/* setup SerDes clock speed */
+	if (interface == PHY_INTERFACE_MODE_2500BASEX)
+		nco_ctrl = GSW1XX_SGMII_2G5 | GSW1XX_SGMII_2G5_NCO2;
+	else
+		nco_ctrl = GSW1XX_SGMII_1G | GSW1XX_SGMII_1G_NCO1;
+
+	ret = regmap_update_bits(priv->clk, GSW1XX_CLK_NCO_CTRL,
+				 GSW1XX_SGMII_HSP_MASK | GSW1XX_SGMII_SEL,
+				 nco_ctrl);
+	if (ret)
+		return ret;
+
+	ret = gsw1xx_sgmii_phy_xaui_write(priv, 0x30, 0x80);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void gsw1xx_sgmii_pcs_link_up(struct phylink_pcs *pcs,
+				     unsigned int neg_mode,
+				     phy_interface_t interface, int speed,
+				     int duplex)
+{
+	struct gsw1xx_priv *priv = sgmii_pcs_to_gsw1xx(pcs);
+	u16 lpstat;
+
+	/* When in-band AN is enabled hardware will set lpstat */
+	if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+		return;
+
+	/* Force speed and duplex settings */
+	if (interface == PHY_INTERFACE_MODE_SGMII) {
+		if (speed == SPEED_10)
+			lpstat = FIELD_PREP(GSW1XX_SGMII_TBI_LPSTAT_SPEED,
+					    GSW1XX_SGMII_TBI_LPSTAT_SPEED_10);
+		else if (speed == SPEED_100)
+			lpstat = FIELD_PREP(GSW1XX_SGMII_TBI_LPSTAT_SPEED,
+					    GSW1XX_SGMII_TBI_LPSTAT_SPEED_100);
+		else
+			lpstat = FIELD_PREP(GSW1XX_SGMII_TBI_LPSTAT_SPEED,
+					    GSW1XX_SGMII_TBI_LPSTAT_SPEED_1000);
+	} else {
+		lpstat = FIELD_PREP(GSW1XX_SGMII_TBI_LPSTAT_SPEED,
+				    GSW1XX_SGMII_TBI_LPSTAT_SPEED_NOSGMII);
+	}
+
+	if (duplex == DUPLEX_FULL)
+		lpstat |= GSW1XX_SGMII_TBI_LPSTAT_DUPLEX;
+
+	regmap_write(priv->sgmii, GSW1XX_SGMII_TBI_LPSTAT, lpstat);
+}
+
+static void gsw1xx_sgmii_pcs_get_state(struct phylink_pcs *pcs,
+				       unsigned int neg_mode,
+				       struct phylink_link_state *state)
+{
+	struct gsw1xx_priv *priv = sgmii_pcs_to_gsw1xx(pcs);
+	int ret;
+	u32 val;
+
+	ret = regmap_read(priv->sgmii, GSW1XX_SGMII_TBI_TBISTAT, &val);
+	if (ret < 0)
+		return;
+
+	state->link = !!(val & GSW1XX_SGMII_TBI_TBISTAT_LINK);
+	state->an_complete = !!(val & GSW1XX_SGMII_TBI_TBISTAT_AN_COMPLETE);
+
+	ret = regmap_read(priv->sgmii, GSW1XX_SGMII_TBI_LPSTAT, &val);
+	if (ret < 0)
+		return;
+
+	state->duplex = (val & GSW1XX_SGMII_TBI_LPSTAT_DUPLEX) ?
+			 DUPLEX_FULL : DUPLEX_HALF;
+	if (val & GSW1XX_SGMII_TBI_LPSTAT_PAUSE_RX)
+		state->pause |= MLO_PAUSE_RX;
+
+	if (val & GSW1XX_SGMII_TBI_LPSTAT_PAUSE_TX)
+		state->pause |= MLO_PAUSE_TX;
+
+	switch (FIELD_GET(GSW1XX_SGMII_TBI_LPSTAT_SPEED, val)) {
+	case GSW1XX_SGMII_TBI_LPSTAT_SPEED_10:
+		state->speed = SPEED_10;
+		break;
+	case GSW1XX_SGMII_TBI_LPSTAT_SPEED_100:
+		state->speed = SPEED_100;
+		break;
+	case GSW1XX_SGMII_TBI_LPSTAT_SPEED_1000:
+		state->speed = SPEED_1000;
+		break;
+	case GSW1XX_SGMII_TBI_LPSTAT_SPEED_NOSGMII:
+		if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
+			state->speed = SPEED_1000;
+		else if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
+			state->speed = SPEED_2500;
+		else
+			state->speed = SPEED_UNKNOWN;
+		break;
+	}
+}
+
+static void gsw1xx_sgmii_pcs_an_restart(struct phylink_pcs *pcs)
+{
+	struct gsw1xx_priv *priv = sgmii_pcs_to_gsw1xx(pcs);
+
+	regmap_set_bits(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL,
+			GSW1XX_SGMII_TBI_ANEGCTL_RANEG);
+}
+
+static int gsw1xx_sgmii_pcs_enable(struct phylink_pcs *pcs)
+{
+	struct gsw1xx_priv *priv = sgmii_pcs_to_gsw1xx(pcs);
+
+	/* Deassert SGMII shell reset */
+	return regmap_clear_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
+				 GSW1XX_RST_REQ_SGMII_SHELL);
+}
+
+static void gsw1xx_sgmii_pcs_disable(struct phylink_pcs *pcs)
+{
+	struct gsw1xx_priv *priv = sgmii_pcs_to_gsw1xx(pcs);
+
+	/* Assert SGMII shell reset */
+	regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ,

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 422

Quoted 10 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+			GSW1XX_RST_REQ_SGMII_SHELL);
+}
+
+static const struct phylink_pcs_ops gsw1xx_sgmii_pcs_ops = {
+	.pcs_an_restart = gsw1xx_sgmii_pcs_an_restart,
+	.pcs_config = gsw1xx_sgmii_pcs_config,
+	.pcs_disable = gsw1xx_sgmii_pcs_disable,
+	.pcs_enable = gsw1xx_sgmii_pcs_enable,
+	.pcs_get_state = gsw1xx_sgmii_pcs_get_state,
+	.pcs_link_up = gsw1xx_sgmii_pcs_link_up,

Please order these in the same order as they appear in the struct, and please order your functions above in the same order. This makes it easier in future if new methods need to be added.

Also, please add the .pcs_inband_caps method to describe the capabilities of the PCS.

It seems to me that this is not just a Cisco SGMII PCS, but also supports IEEE 802.3 1000BASE-X. "SGMII" is an ambiguous term. Please avoid propagating this ambigutiy to the kernel. I think in this case merely "gsw1xx_pcs_xyz" will do.

Quoted 40 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +40 -0
+};
+
+static void gsw1xx_phylink_get_caps(struct dsa_switch *ds, int port,
+				    struct phylink_config *config)
+{
+	struct gswip_priv *priv = ds->priv;
+
+	config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+				   MAC_10 | MAC_100 | MAC_1000;
+
+	switch (port) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
+			  config->supported_interfaces);
+		break;
+	case 4: /* port 4: SGMII */
+		__set_bit(PHY_INTERFACE_MODE_SGMII,
+			  config->supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_1000BASEX,
+			  config->supported_interfaces);
+		if (priv->hw_info->supports_2500m) {
+			__set_bit(PHY_INTERFACE_MODE_2500BASEX,
+				  config->supported_interfaces);
+			config->mac_capabilities |= MAC_2500FD;
+		}
+		return; /* no support for EEE on SGMII port */
+	case 5: /* port 5: RGMII or RMII */
+		__set_bit(PHY_INTERFACE_MODE_RMII,
+			  config->supported_interfaces);
+		phy_interface_set_rgmii(config->supported_interfaces);
+		break;
+	}
+
+	config->lpi_capabilities = MAC_100FD | MAC_1000FD;
+	config->lpi_timer_default = 20;
+	memcpy(config->lpi_interfaces, config->supported_interfaces,
+	       sizeof(config->lpi_interfaces));

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 472

Quoted 10 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+}
+
+static struct phylink_pcs *gsw1xx_phylink_mac_select_pcs(struct phylink_config *config,
+							 phy_interface_t interface)
+{
+	struct dsa_port *dp = dsa_phylink_to_port(config);
+	struct gswip_priv *gswip_priv = dp->ds->priv;
+	struct gsw1xx_priv *gsw1xx_priv = container_of(gswip_priv,
+						       struct gsw1xx_priv,
+						       gswip);

Reverse christmas tree?

Quoted 44 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +44 -0
+static int gsw1xx_probe(struct mdio_device *mdiodev)
+{
+	struct device *dev = &mdiodev->dev;
+	struct gsw1xx_priv *priv;
+	u32 version;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->mdio_dev = mdiodev;
+	priv->smdio_badr = GSW1XX_SMDIO_BADR_UNKNOWN;
+
+	priv->gswip.dev = dev;
+	priv->gswip.hw_info = of_device_get_match_data(dev);
+	if (!priv->gswip.hw_info)
+		return -EINVAL;
+
+	priv->gswip.gswip = gsw1xx_regmap_init(priv, "switch",
+					       GSW1XX_SWITCH_BASE, 0xfff);
+	if (IS_ERR(priv->gswip.gswip))
+		return PTR_ERR(priv->gswip.gswip);
+
+	priv->gswip.mdio = gsw1xx_regmap_init(priv, "mdio", GSW1XX_MMDIO_BASE,
+					      0xff);
+	if (IS_ERR(priv->gswip.mdio))
+		return PTR_ERR(priv->gswip.mdio);
+
+	priv->gswip.mii = gsw1xx_regmap_init(priv, "mii", GSW1XX_RGMII_BASE,
+					     0xff);
+	if (IS_ERR(priv->gswip.mii))
+		return PTR_ERR(priv->gswip.mii);
+
+	priv->sgmii = gsw1xx_regmap_init(priv, "sgmii", GSW1XX_SGMII_BASE,
+					 0xfff);
+	if (IS_ERR(priv->sgmii))
+		return PTR_ERR(priv->sgmii);
+
+	priv->gpio = gsw1xx_regmap_init(priv, "gpio", GSW1XX_GPIO_BASE, 0xff);
+	if (IS_ERR(priv->gpio))
+		return PTR_ERR(priv->gpio);
+
+	priv->clk = gsw1xx_regmap_init(priv, "clk", GSW1XX_CLK_BASE, 0xff);

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 555

Quoted 10 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	priv->shell = gsw1xx_regmap_init(priv, "shell", GSW1XX_SHELL_BASE,
+					 0xff);
+	if (IS_ERR(priv->shell))
+		return PTR_ERR(priv->shell);
+
+	priv->sgmii_pcs.ops = &gsw1xx_sgmii_pcs_ops;
+	priv->sgmii_pcs.poll = 1;

This is declared as a C99 'bool'. It takes true/false values in preference to 0/1.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
#18 lore raw

Re: [PATCH net-next v2 13/13] net: dsa: add driver for MaxLinear GSW1xx switch family

Hi Russell,

thank you for the review and for not getting tired to teach me ;)

Quoted 18 lines · Russell King (Oracle)

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 172

Quoted 11 lines · Daniel Golle

[...]

drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +10 -0
+	/* Assert and deassert SGMII shell reset */
+	ret = regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
+			      GSW1XX_RST_REQ_SGMII_SHELL);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_clear_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
+				GSW1XX_RST_REQ_SGMII_SHELL);
+	if (ret < 0)
+		return ret;

So this is disruptive. Overall, at this point, having added every other comment below, this code has me wondering whether you are aware of the documentation I have written in phylink.h for pcs_config(). This code goes against this paragraph in that documentation:

Quoted 7 lines

"
* pcs_config() will be called when configuration of the PCS is required
* or when the advertisement is possibly updated. It must not unnecessarily
* disrupt an established link.
"

Low quality implementations lead to poor user experiences.

I've improved this in v3 which I have just sent, unless the TBI block came out of reset or the interface mode had changed since the previous call to .pcs_config() I'm now avoiding any disruptive operations.

Quoted 7 lines

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 255

Quoted 5 lines

[...]

drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +4 -0
+	if (interface == PHY_INTERFACE_MODE_SGMII) {
+		txaneg = ADVERTISE_SGMII;
+		if (sgmii_mac_mode) {
+			txaneg |= BIT(14); /* MAC should always send BIT 14 */

Bit 14 is ADVERTISE_LPACK.

Thanks for that, always learning ;)

Quoted 7 lines

I think I'd prefer:

			txaneg = ADVERTISE_SGMII | ADVERTISE_LPACK;

and...

Quoted 8 lines

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 259

Quoted 4 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +4 -0
+			anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_ANMODE,
+					      GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_SGMII_MAC);
+		} else {
+			txaneg |= LPA_SGMII_1000FULL;
			txaneg = LPA_SGMII | LPA_SGMII_1000FULL;

here.

Ack.

Quoted 8 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+			anegctl |= FIELD_PREP(GSW1XX_SGMII_TBI_ANEGCTL_ANMODE,
+					      GSW1XX_SGMII_TBI_ANEGCTL_ANMODE_SGMII_PHY);

So this seems to be yet another case of reverse SGMII. Andrew, please can we get to a conclusion on PHY_INTERFACE_MODE_REVSGMII before we end up with a crapshow of drivers doing their own stuff *exactly* like we see here?

I agree that PHY_INTERFACE_MODE_REVSGMII would make sense, and I have now at least added a comment indicating that.
As on DSA switches it is very common for the same SerDes interface being potentially used to connect a PHY or SFP cage, but be used as CPU port, it will be important to clearly state which end of such links is described as SGMII or REVSGMII, as one side is always MAC side and the other side is PHY side, so its a bit ambigous to use the 'foward' (aka. 'normal') vs. 'reverse' language...

Quoted 4 lines
Quoted 2 lines

[...] (regarding GSW1XX_SGMII_TBI_ANEGCTL_OVRANEG and
GSW1XX_SGMII_TBI_ANEGCTL_OVRABL bits)

Please add a comment describing what is going on here. What does this register bit do...

I've added a comment describing the override bits in detail and it also turned out that it makes most sense to always set both override bits.

Quoted 6 lines

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 268

Quoted 4 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +3 -0
+	} else if (interface == PHY_INTERFACE_MODE_1000BASEX ||
+		   interface == PHY_INTERFACE_MODE_2500BASEX) {
+		txaneg = BIT(5) | BIT(7);

ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE ?

Actually phylink_mii_c22_pcs_encode_advertisement() seemed like a good match here and I've used that for the Base-X modes.

Quoted 5 lines
Quoted 5 lines

[...]

drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +4 -0
+
+static const struct phylink_pcs_ops gsw1xx_sgmii_pcs_ops = {
+	.pcs_an_restart = gsw1xx_sgmii_pcs_an_restart,
+	.pcs_config = gsw1xx_sgmii_pcs_config,
Quoted 8 lines

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 422

Quoted 4 lines
drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +4 -0
+	.pcs_disable = gsw1xx_sgmii_pcs_disable,
+	.pcs_enable = gsw1xx_sgmii_pcs_enable,
+	.pcs_get_state = gsw1xx_sgmii_pcs_get_state,
+	.pcs_link_up = gsw1xx_sgmii_pcs_link_up,

Please order these in the same order as they appear in the struct, and please order your functions above in the same order. This makes it easier in future if new methods need to be added.

Ack, done.

Quoted 3 lines

Also, please add the .pcs_inband_caps method to describe the capabilities of the PCS.

Ack.

Quoted 5 lines

It seems to me that this is not just a Cisco SGMII PCS, but also supports IEEE 802.3 1000BASE-X. "SGMII" is an ambiguous term. Please avoid propagating this ambigutiy to the kernel. I think in this case merely "gsw1xx_pcs_xyz" will do.

I've renamed all functions according to your suggestions, but kept register names as-is to still match how they are called in the (btw public) datasheet.

Quoted 11 lines

drivers/net/dsa/lantiq/mxl-gsw1xx.c line 472

Quoted 9 lines

[...]

drivers/net/dsa/lantiq/mxl-gsw1xx.c new file +8 -0
+static struct phylink_pcs *gsw1xx_phylink_mac_select_pcs(struct phylink_config *config,
+							 phy_interface_t interface)
+{
+	struct dsa_port *dp = dsa_phylink_to_port(config);
+	struct gswip_priv *gswip_priv = dp->ds->priv;
+	struct gsw1xx_priv *gsw1xx_priv = container_of(gswip_priv,
+						       struct gsw1xx_priv,
+						       gswip);

Reverse christmas tree?

Not possible as each declaration uses the previously declared variable in its initializer.

Cheers

Daniel