summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2026-01-27 11:52:46 +0100
committerPaolo Abeni <pabeni@redhat.com>2026-01-27 11:52:46 +0100
commit4c17c01c317a432382393b34cc9f65bf4ca310aa (patch)
tree5d5ce920b4ac4fe8b25f23f306d4c4c5aafae6e8
parent099ca4121ea747acc8a0d36852f2f477943f306d (diff)
parentafe813fd89ecde068a5f972714c4abf896715167 (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.yaml6
-rw-r--r--drivers/net/dsa/lantiq/Kconfig4
-rw-r--r--drivers/net/dsa/lantiq/lantiq_gswip.c46
-rw-r--r--drivers/net/dsa/lantiq/lantiq_gswip.h6
-rw-r--r--drivers/net/dsa/lantiq/lantiq_gswip_common.c27
-rw-r--r--drivers/net/dsa/lantiq/mxl-gsw1xx.c151
-rw-r--r--drivers/net/dsa/lantiq/mxl-gsw1xx.h2
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 */