diff options
| author | Paolo Abeni <pabeni@redhat.com> | 2026-01-27 11:52:46 +0100 |
|---|---|---|
| committer | Paolo Abeni <pabeni@redhat.com> | 2026-01-27 11:52:46 +0100 |
| commit | 4c17c01c317a432382393b34cc9f65bf4ca310aa (patch) | |
| tree | 5d5ce920b4ac4fe8b25f23f306d4c4c5aafae6e8 | |
| parent | 099ca4121ea747acc8a0d36852f2f477943f306d (diff) | |
| parent | afe813fd89ecde068a5f972714c4abf896715167 (diff) | |
Merge branch 'net-dsa-lantiq-add-support-for-intel-gsw150'
Daniel Golle says:
====================
net: dsa: lantiq: add support for Intel GSW150
The Intel GSW150 Ethernet Switch (aka. Lantiq PEB7084) is the predecessor of
MaxLinear's GSW1xx series of switches. It shares most features, but has a
slightly different port layout and different MII interfaces.
Adding support for this switch to the mxl-gsw1xx driver is quite trivial.
====================
Link: https://patch.msgid.link/cover.1769099517.git.daniel@makrotopia.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
| -rw-r--r-- | Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml | 6 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/lantiq_gswip.c | 46 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/lantiq_gswip.h | 6 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/lantiq_gswip_common.c | 27 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/mxl-gsw1xx.c | 151 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/mxl-gsw1xx.h | 2 |
7 files changed, 168 insertions, 74 deletions
diff --git a/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml b/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml index 37d64b8a76ac..f601e5f9fa6a 100644 --- a/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +++ b/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml @@ -19,6 +19,8 @@ maintainers: properties: compatible: enum: + - intel,gsw150 + - lantiq,peb7084 - lantiq,xrx200-gswip - lantiq,xrx300-gswip - lantiq,xrx330-gswip @@ -338,7 +340,7 @@ examples: #address-cells = <1>; #size-cells = <0>; - switchphy0: switchphy@0 { + switchphy0: ethernet-phy@0 { reg = <0>; leds { @@ -353,7 +355,7 @@ examples: }; }; - switchphy1: switchphy@1 { + switchphy1: ethernet-phy@1 { reg = <1>; leds { diff --git a/drivers/net/dsa/lantiq/Kconfig b/drivers/net/dsa/lantiq/Kconfig index 4a9771be5d58..bad13817af25 100644 --- a/drivers/net/dsa/lantiq/Kconfig +++ b/drivers/net/dsa/lantiq/Kconfig @@ -16,9 +16,11 @@ config NET_DSA_MXL_GSW1XX select NET_DSA_TAG_MXL_GSW1XX select NET_DSA_LANTIQ_COMMON help - This enables support for the MaxLinear GSW1xx family of 1GE switches + This enables support for the Intel/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 + GSW150 7 port, 5 PHYs, 1x GMII/RGMII, 1x RGMII diff --git a/drivers/net/dsa/lantiq/lantiq_gswip.c b/drivers/net/dsa/lantiq/lantiq_gswip.c index b094001a7c80..4d699d8c16f9 100644 --- a/drivers/net/dsa/lantiq/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq/lantiq_gswip.c @@ -33,8 +33,7 @@ static void gswip_xrx200_phylink_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { switch (port) { - case 0: - case 1: + case 0 ... 1: phy_interface_set_rgmii(config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); @@ -44,9 +43,7 @@ static void gswip_xrx200_phylink_get_caps(struct dsa_switch *ds, int port, config->supported_interfaces); break; - case 2: - case 3: - case 4: + case 2 ... 4: case 6: __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); @@ -75,10 +72,7 @@ static void gswip_xrx300_phylink_get_caps(struct dsa_switch *ds, int port, config->supported_interfaces); break; - case 1: - case 2: - case 3: - case 4: + case 1 ... 4: case 6: __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); @@ -463,10 +457,22 @@ static void gswip_shutdown(struct platform_device *pdev) } static const struct gswip_hw_info gswip_xrx200 = { - .max_ports = 7, + .max_ports = GSWIP_MAX_PORTS, .allowed_cpu_ports = BIT(6), - .mii_ports = BIT(0) | BIT(1) | BIT(5), - .mii_port_reg_offset = 0, + .mii_cfg = { + [0] = GSWIP_MII_CFGp(0), + [1] = GSWIP_MII_CFGp(1), + [2 ... 4] = -1, + [5] = GSWIP_MII_CFGp(5), + [6] = -1, + }, + .mii_pcdu = { + [0] = GSWIP_MII_PCDU0, + [1] = GSWIP_MII_PCDU1, + [2 ... 4] = -1, + [5] = GSWIP_MII_PCDU5, + [6] = -1, + }, .phylink_get_caps = gswip_xrx200_phylink_get_caps, .pce_microcode = &gswip_pce_microcode, .pce_microcode_size = ARRAY_SIZE(gswip_pce_microcode), @@ -474,10 +480,20 @@ static const struct gswip_hw_info gswip_xrx200 = { }; static const struct gswip_hw_info gswip_xrx300 = { - .max_ports = 7, + .max_ports = GSWIP_MAX_PORTS, .allowed_cpu_ports = BIT(6), - .mii_ports = BIT(0) | BIT(5), - .mii_port_reg_offset = 0, + .mii_cfg = { + [0] = GSWIP_MII_CFGp(0), + [1 ... 4] = -1, + [5] = GSWIP_MII_CFGp(5), + [6] = -1, + }, + .mii_pcdu = { + [0] = GSWIP_MII_PCDU0, + [1 ... 4] = -1, + [5] = GSWIP_MII_PCDU5, + [6] = -1, + }, .phylink_get_caps = gswip_xrx300_phylink_get_caps, .pce_microcode = &gswip_pce_microcode, .pce_microcode_size = ARRAY_SIZE(gswip_pce_microcode), diff --git a/drivers/net/dsa/lantiq/lantiq_gswip.h b/drivers/net/dsa/lantiq/lantiq_gswip.h index 8fc4c7cc5283..bc3686faad0d 100644 --- a/drivers/net/dsa/lantiq/lantiq_gswip.h +++ b/drivers/net/dsa/lantiq/lantiq_gswip.h @@ -243,6 +243,8 @@ #define GSWIP_VLAN_UNAWARE_PVID 0 +#define GSWIP_MAX_PORTS 7 + struct gswip_pce_microcode { u16 val_3; u16 val_2; @@ -253,8 +255,8 @@ struct gswip_pce_microcode { struct gswip_hw_info { int max_ports; unsigned int allowed_cpu_ports; - unsigned int mii_ports; - int mii_port_reg_offset; + s16 mii_cfg[GSWIP_MAX_PORTS]; + s16 mii_pcdu[GSWIP_MAX_PORTS]; bool supports_2500m; const struct gswip_pce_microcode (*pce_microcode)[]; size_t pce_microcode_size; diff --git a/drivers/net/dsa/lantiq/lantiq_gswip_common.c b/drivers/net/dsa/lantiq/lantiq_gswip_common.c index 17a61e445f00..0e8eedf64d3a 100644 --- a/drivers/net/dsa/lantiq/lantiq_gswip_common.c +++ b/drivers/net/dsa/lantiq/lantiq_gswip_common.c @@ -118,15 +118,11 @@ static u32 gswip_switch_r_timeout(struct gswip_priv *priv, u32 offset, static void gswip_mii_mask_cfg(struct gswip_priv *priv, u32 mask, u32 set, int port) { - int reg_port; - /* MII_CFG register only exists for MII ports */ - if (!(priv->hw_info->mii_ports & BIT(port))) + if (priv->hw_info->mii_cfg[port] == -1) return; - reg_port = port + priv->hw_info->mii_port_reg_offset; - - regmap_write_bits(priv->mii, GSWIP_MII_CFGp(reg_port), mask, + regmap_write_bits(priv->mii, priv->hw_info->mii_cfg[port], mask, set); } @@ -610,28 +606,13 @@ static void 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; - u16 mii_pcdu_reg; /* As MII_PCDU registers only exist for MII ports, silently return * unless the port is an MII port */ - if (!(priv->hw_info->mii_ports & BIT(dp->index))) + if (priv->hw_info->mii_pcdu[dp->index] == -1) return; - switch (dp->index + priv->hw_info->mii_port_reg_offset) { - case 0: - mii_pcdu_reg = GSWIP_MII_PCDU0; - break; - case 1: - mii_pcdu_reg = GSWIP_MII_PCDU1; - break; - case 5: - mii_pcdu_reg = GSWIP_MII_PCDU5; - break; - default: - return; - } - /* legacy code to set default delays according to the interface mode */ switch (interface) { case PHY_INTERFACE_MODE_RGMII_ID: @@ -652,7 +633,7 @@ static void gswip_mii_delay_setup(struct gswip_priv *priv, struct dsa_port *dp, of_property_read_u32(port_dn, "rx-internal-delay-ps", &rx_delay); of_property_read_u32(port_dn, "tx-internal-delay-ps", &tx_delay); - regmap_write_bits(priv->mii, mii_pcdu_reg, + regmap_write_bits(priv->mii, priv->hw_info->mii_pcdu[dp->index], GSWIP_MII_PCDU_TXDLY_MASK | GSWIP_MII_PCDU_RXDLY_MASK, GSWIP_MII_PCDU_TXDLY(tx_delay) | diff --git a/drivers/net/dsa/lantiq/mxl-gsw1xx.c b/drivers/net/dsa/lantiq/mxl-gsw1xx.c index 6afc7539fefb..79cf72cc77be 100644 --- a/drivers/net/dsa/lantiq/mxl-gsw1xx.c +++ b/drivers/net/dsa/lantiq/mxl-gsw1xx.c @@ -502,6 +502,14 @@ static const struct phylink_pcs_ops gsw1xx_pcs_ops = { .pcs_link_up = gsw1xx_pcs_link_up, }; +static void gsw1xx_phylink_get_lpi_caps(struct phylink_config *config) +{ + config->lpi_capabilities = MAC_100FD | MAC_1000FD; + config->lpi_timer_default = 20; + memcpy(config->lpi_interfaces, config->supported_interfaces, + sizeof(config->lpi_interfaces)); +} + static void gsw1xx_phylink_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { @@ -511,14 +519,12 @@ static void gsw1xx_phylink_get_caps(struct dsa_switch *ds, int port, MAC_10 | MAC_100 | MAC_1000; switch (port) { - case 0: - case 1: - case 2: - case 3: + case 0 ... 3: /* built-in PHYs */ __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); break; - case 4: /* port 4: SGMII */ + + case 4: /* SGMII */ __set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_1000BASEX, @@ -529,17 +535,40 @@ static void gsw1xx_phylink_get_caps(struct dsa_switch *ds, int port, config->mac_capabilities |= MAC_2500FD; } return; /* no support for EEE on SGMII port */ - case 5: /* port 5: RGMII or RMII */ + + case 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)); + gsw1xx_phylink_get_lpi_caps(config); +} + +static void gsw150_phylink_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) +{ + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000; + + switch (port) { + case 0 ... 4: /* built-in PHYs */ + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + config->supported_interfaces); + break; + + case 5: /* GMII or RGMII */ + __set_bit(PHY_INTERFACE_MODE_GMII, + config->supported_interfaces); + fallthrough; + + case 6: /* RGMII */ + phy_interface_set_rgmii(config->supported_interfaces); + break; + } + + gsw1xx_phylink_get_lpi_caps(config); } static struct phylink_pcs *gsw1xx_phylink_mac_select_pcs(struct phylink_config *config, @@ -616,6 +645,28 @@ static struct regmap *gsw1xx_regmap_init(struct gsw1xx_priv *priv, priv, &config); } +static int gsw1xx_serdes_pcs_init(struct gsw1xx_priv *priv) +{ + /* do nothing if the chip doesn't have a SerDes PCS */ + if (!priv->gswip.hw_info->mac_select_pcs) + return 0; + + priv->pcs.ops = &gsw1xx_pcs_ops; + priv->pcs.poll = true; + __set_bit(PHY_INTERFACE_MODE_SGMII, + priv->pcs.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, + priv->pcs.supported_interfaces); + if (priv->gswip.hw_info->supports_2500m) + __set_bit(PHY_INTERFACE_MODE_2500BASEX, + priv->pcs.supported_interfaces); + priv->tbi_interface = PHY_INTERFACE_MODE_NA; + + /* assert SGMII reset to power down SGMII unit */ + return regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ, + GSW1XX_RST_REQ_SGMII_SHELL); +} + static int gsw1xx_probe(struct mdio_device *mdiodev) { struct device *dev = &mdiodev->dev; @@ -668,20 +719,7 @@ static int gsw1xx_probe(struct mdio_device *mdiodev) if (IS_ERR(priv->shell)) return PTR_ERR(priv->shell); - priv->pcs.ops = &gsw1xx_pcs_ops; - priv->pcs.poll = true; - __set_bit(PHY_INTERFACE_MODE_SGMII, - priv->pcs.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_1000BASEX, - priv->pcs.supported_interfaces); - if (priv->gswip.hw_info->supports_2500m) - __set_bit(PHY_INTERFACE_MODE_2500BASEX, - priv->pcs.supported_interfaces); - priv->tbi_interface = PHY_INTERFACE_MODE_NA; - - /* assert SGMII reset to power down SGMII unit */ - ret = regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ, - GSW1XX_RST_REQ_SGMII_SHELL); + ret = gsw1xx_serdes_pcs_init(priv); if (ret < 0) return ret; @@ -739,8 +777,16 @@ static void gsw1xx_shutdown(struct mdio_device *mdiodev) static const struct gswip_hw_info gsw12x_data = { .max_ports = GSW1XX_PORTS, .allowed_cpu_ports = BIT(GSW1XX_MII_PORT) | BIT(GSW1XX_SGMII_PORT), - .mii_ports = BIT(GSW1XX_MII_PORT), - .mii_port_reg_offset = -GSW1XX_MII_PORT, + .mii_cfg = { + [0 ... GSW1XX_MII_PORT - 1] = -1, + [GSW1XX_MII_PORT] = GSWIP_MII_CFGp(0), + [GSW1XX_MII_PORT + 1 ... GSWIP_MAX_PORTS - 1] = -1, + }, + .mii_pcdu = { + [0 ... GSW1XX_MII_PORT - 1] = -1, + [GSW1XX_MII_PORT] = GSWIP_MII_PCDU0, + [GSW1XX_MII_PORT + 1 ... GSWIP_MAX_PORTS - 1] = -1, + }, .mac_select_pcs = gsw1xx_phylink_mac_select_pcs, .phylink_get_caps = &gsw1xx_phylink_get_caps, .supports_2500m = true, @@ -753,8 +799,16 @@ static const struct gswip_hw_info gsw12x_data = { static const struct gswip_hw_info gsw140_data = { .max_ports = GSW1XX_PORTS, .allowed_cpu_ports = BIT(GSW1XX_MII_PORT) | BIT(GSW1XX_SGMII_PORT), - .mii_ports = BIT(GSW1XX_MII_PORT), - .mii_port_reg_offset = -GSW1XX_MII_PORT, + .mii_cfg = { + [0 ... GSW1XX_MII_PORT - 1] = -1, + [GSW1XX_MII_PORT] = GSWIP_MII_CFGp(0), + [GSW1XX_MII_PORT + 1 ... GSWIP_MAX_PORTS - 1] = -1, + }, + .mii_pcdu = { + [0 ... GSW1XX_MII_PORT - 1] = -1, + [GSW1XX_MII_PORT] = GSWIP_MII_PCDU0, + [GSW1XX_MII_PORT + 1 ... GSWIP_MAX_PORTS - 1] = -1, + }, .mac_select_pcs = gsw1xx_phylink_mac_select_pcs, .phylink_get_caps = &gsw1xx_phylink_get_caps, .supports_2500m = true, @@ -767,8 +821,16 @@ static const struct gswip_hw_info gsw140_data = { static const struct gswip_hw_info gsw141_data = { .max_ports = GSW1XX_PORTS, .allowed_cpu_ports = BIT(GSW1XX_MII_PORT) | BIT(GSW1XX_SGMII_PORT), - .mii_ports = BIT(GSW1XX_MII_PORT), - .mii_port_reg_offset = -GSW1XX_MII_PORT, + .mii_cfg = { + [0 ... GSW1XX_MII_PORT - 1] = -1, + [GSW1XX_MII_PORT] = GSWIP_MII_CFGp(0), + [GSW1XX_MII_PORT + 1 ... GSWIP_MAX_PORTS - 1] = -1, + }, + .mii_pcdu = { + [0 ... GSW1XX_MII_PORT - 1] = -1, + [GSW1XX_MII_PORT] = GSWIP_MII_PCDU0, + [GSW1XX_MII_PORT + 1 ... GSWIP_MAX_PORTS - 1] = -1, + }, .mac_select_pcs = gsw1xx_phylink_mac_select_pcs, .phylink_get_caps = gsw1xx_phylink_get_caps, .port_setup = gsw1xx_port_setup, @@ -777,11 +839,38 @@ static const struct gswip_hw_info gsw141_data = { .tag_protocol = DSA_TAG_PROTO_MXL_GSW1XX, }; +static const struct gswip_hw_info gsw150_data = { + .max_ports = GSW150_PORTS, + .allowed_cpu_ports = BIT(5) | BIT(6), + .mii_cfg = { + [0 ... 4] = -1, + [5] = 0, + [6] = 10, + }, + .mii_pcdu = { + [0 ... 4] = -1, + [5] = 1, + [6] = 11, + }, + .phylink_get_caps = gsw150_phylink_get_caps, + /* There is only a single RGMII_SLEW_CFG register in GSW150 and it is + * unknown if RGMII slew configuration affects both RGMII ports + * or only port 5. Use .port_setup which assumes it affects port 5 + * for now. + */ + .port_setup = gsw1xx_port_setup, + .pce_microcode = &gsw1xx_pce_microcode, + .pce_microcode_size = ARRAY_SIZE(gsw1xx_pce_microcode), + .tag_protocol = DSA_TAG_PROTO_MXL_GSW1XX, +}; + /* * GSW125 is the industrial temperature version of GSW120. * GSW145 is the industrial temperature version of GSW140. */ static const struct of_device_id gsw1xx_of_match[] = { + { .compatible = "intel,gsw150", .data = &gsw150_data }, + { .compatible = "lantiq,peb7084", .data = &gsw150_data }, { .compatible = "maxlinear,gsw120", .data = &gsw12x_data }, { .compatible = "maxlinear,gsw125", .data = &gsw12x_data }, { .compatible = "maxlinear,gsw140", .data = &gsw140_data }, @@ -805,5 +894,5 @@ static struct mdio_driver gsw1xx_driver = { mdio_module_driver(gsw1xx_driver); MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>"); -MODULE_DESCRIPTION("Driver for MaxLinear GSW1xx ethernet switch"); +MODULE_DESCRIPTION("Driver for Intel/MaxLinear GSW1xx Ethernet switch"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/lantiq/mxl-gsw1xx.h b/drivers/net/dsa/lantiq/mxl-gsw1xx.h index 8c0298b2b766..d1fded56e967 100644 --- a/drivers/net/dsa/lantiq/mxl-gsw1xx.h +++ b/drivers/net/dsa/lantiq/mxl-gsw1xx.h @@ -10,6 +10,8 @@ #include <linux/bitfield.h> #define GSW1XX_PORTS 6 +#define GSW150_PORTS 7 + /* Port used for RGMII or optional RMII */ #define GSW1XX_MII_PORT 5 /* Port used for SGMII */ |
