diff options
| author | Paolo Abeni <pabeni@redhat.com> | 2026-02-10 09:09:31 +0100 |
|---|---|---|
| committer | Paolo Abeni <pabeni@redhat.com> | 2026-02-10 09:09:32 +0100 |
| commit | 30827969b03e7745dd199dca48847604d99b70b3 (patch) | |
| tree | 710b2d9c7ad848c0cde2817d5043a32470ad3c96 | |
| parent | 71e1eab8d246c27b6e7e2917e8d0e6866977a627 (diff) | |
| parent | a046d6fc54d46168f69cf4d4a35f714594d205b8 (diff) | |
Merge branch 'net-dsa-mxl-gsw1xx-setup-polarities-and-validate-chip'
Daniel Golle says:
====================
net: dsa: mxl-gsw1xx: setup polarities and validate chip
Now that common PHY properties make it easy to configure the SerDes RX
and TX polarities, use that for the SGMII/1000Base-X/2500Base-X port of
the MaxLinear GSW1xx switches.
Also, validate hardware in probe() function to make sure the switch is
actually present and MDIO communication works properly.
====================
Link: https://patch.msgid.link/cover.1769916962.git.daniel@makrotopia.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
| -rw-r--r-- | Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml | 4 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/mxl-gsw1xx.c | 66 | ||||
| -rw-r--r-- | drivers/net/dsa/lantiq/mxl-gsw1xx.h | 9 |
4 files changed, 68 insertions, 12 deletions
diff --git a/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml b/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml index f601e5f9fa6a..49af5573e452 100644 --- a/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml +++ b/Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml @@ -105,6 +105,8 @@ patternProperties: patternProperties: "^(ethernet-)?port@[0-6]$": $ref: dsa-port.yaml# + allOf: + - $ref: /schemas/phy/phy-common-props.yaml# unevaluatedProperties: false properties: @@ -288,6 +290,7 @@ examples: - | #include <dt-bindings/leds/common.h> + #include <dt-bindings/phy/phy.h> mdio { #address-cells = <1>; @@ -320,6 +323,7 @@ examples: label = "wan"; phy-mode = "1000base-x"; managed = "in-band-status"; + tx-polarity = <PHY_POL_INVERT>; }; port@5 { diff --git a/drivers/net/dsa/lantiq/Kconfig b/drivers/net/dsa/lantiq/Kconfig index bad13817af25..98efeef2661b 100644 --- a/drivers/net/dsa/lantiq/Kconfig +++ b/drivers/net/dsa/lantiq/Kconfig @@ -15,6 +15,7 @@ config NET_DSA_MXL_GSW1XX tristate "MaxLinear GSW1xx Ethernet switch support" select NET_DSA_TAG_MXL_GSW1XX select NET_DSA_LANTIQ_COMMON + select PHY_COMMON_PROPS help This enables support for the Intel/MaxLinear GSW1xx family of 1GE switches. diff --git a/drivers/net/dsa/lantiq/mxl-gsw1xx.c b/drivers/net/dsa/lantiq/mxl-gsw1xx.c index 79cf72cc77be..a1104b2f92a9 100644 --- a/drivers/net/dsa/lantiq/mxl-gsw1xx.c +++ b/drivers/net/dsa/lantiq/mxl-gsw1xx.c @@ -15,6 +15,8 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/of_mdio.h> +#include <linux/phy/phy-common-props.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/workqueue.h> #include <net/dsa.h> @@ -229,11 +231,17 @@ static int gsw1xx_pcs_phy_xaui_write(struct gsw1xx_priv *priv, u16 addr, 1000, 100000); } -static int gsw1xx_pcs_reset(struct gsw1xx_priv *priv) +static int gsw1xx_pcs_reset(struct gsw1xx_priv *priv, phy_interface_t interface) { + struct dsa_port *sgmii_port; + unsigned int pol; int ret; u16 val; + sgmii_port = dsa_to_port(priv->gswip.ds, GSW1XX_SGMII_PORT); + if (!sgmii_port) + return -EINVAL; + /* Assert and deassert SGMII shell reset */ ret = regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ, GSW1XX_RST_REQ_SGMII_SHELL); @@ -260,15 +268,20 @@ static int gsw1xx_pcs_reset(struct gsw1xx_priv *priv) FIELD_PREP(GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT, GSW1XX_SGMII_PHY_RX0_CFG2_FILT_CNT_DEF); + ret = phy_get_manual_rx_polarity(of_fwnode_handle(sgmii_port->dn), + phy_modes(interface), &pol); + if (ret) + return ret; + /* RX lane seems to be inverted internally, so bit * GSW1XX_SGMII_PHY_RX0_CFG2_INVERT needs to be set for normal - * (ie. non-inverted) operation. - * - * TODO: Take care of inverted RX pair once generic property is - * available + * (ie. non-inverted) operation matching the chips external pins as + * described in datasheets dated 2023-11-08, ie. pin B20 (RX0_P) being + * the positive signal and pin B21 (RX0_M) being the negative signal of + * the differential input pair. */ - - val |= GSW1XX_SGMII_PHY_RX0_CFG2_INVERT; + if (pol == PHY_POL_NORMAL) + val |= GSW1XX_SGMII_PHY_RX0_CFG2_INVERT; ret = regmap_write(priv->sgmii, GSW1XX_SGMII_PHY_RX0_CFG2, val); if (ret < 0) @@ -277,9 +290,13 @@ static int gsw1xx_pcs_reset(struct gsw1xx_priv *priv) val = FIELD_PREP(GSW1XX_SGMII_PHY_TX0_CFG3_VBOOST_LEVEL, GSW1XX_SGMII_PHY_TX0_CFG3_VBOOST_LEVEL_DEF); - /* TODO: Take care of inverted TX pair once generic property is - * available - */ + ret = phy_get_manual_tx_polarity(of_fwnode_handle(sgmii_port->dn), + phy_modes(interface), &pol); + if (ret) + return ret; + + if (pol == PHY_POL_INVERT) + val |= GSW1XX_SGMII_PHY_TX0_CFG3_INVERT; ret = regmap_write(priv->sgmii, GSW1XX_SGMII_PHY_TX0_CFG3, val); if (ret < 0) @@ -336,7 +353,7 @@ static int gsw1xx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, priv->tbi_interface = PHY_INTERFACE_MODE_NA; if (!reconf) - ret = gsw1xx_pcs_reset(priv); + ret = gsw1xx_pcs_reset(priv, interface); if (ret) return ret; @@ -671,7 +688,9 @@ static int gsw1xx_probe(struct mdio_device *mdiodev) { struct device *dev = &mdiodev->dev; struct gsw1xx_priv *priv; - u32 version; + u32 version, val; + u8 shellver; + u16 pnum; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -719,6 +738,27 @@ static int gsw1xx_probe(struct mdio_device *mdiodev) if (IS_ERR(priv->shell)) return PTR_ERR(priv->shell); + ret = regmap_read(priv->shell, GSW1XX_SHELL_MANU_ID, &val); + if (ret < 0) + return ret; + + /* validate chip ID */ + if (FIELD_GET(GSW1XX_SHELL_MANU_ID_FIX1, val) != 1) + return -ENODEV; + + if (FIELD_GET(GSW1XX_SHELL_MANU_ID_MANID, val) != + GSW1XX_SHELL_MANU_ID_MANID_VAL) + return -ENODEV; + + pnum = FIELD_GET(GSW1XX_SHELL_MANU_ID_PNUML, val); + + ret = regmap_read(priv->shell, GSW1XX_SHELL_PNUM_ID, &val); + if (ret < 0) + return ret; + + pnum |= FIELD_GET(GSW1XX_SHELL_PNUM_ID_PNUMM, val) << 4; + shellver = FIELD_GET(GSW1XX_SHELL_PNUM_ID_VER, val); + ret = gsw1xx_serdes_pcs_init(priv); if (ret < 0) return ret; @@ -739,6 +779,8 @@ static int gsw1xx_probe(struct mdio_device *mdiodev) if (ret) return ret; + dev_info(dev, "standalone switch part number 0x%x v1.%u\n", pnum, shellver); + dev_set_drvdata(dev, &priv->gswip); return 0; diff --git a/drivers/net/dsa/lantiq/mxl-gsw1xx.h b/drivers/net/dsa/lantiq/mxl-gsw1xx.h index d1fded56e967..caa8f1008587 100644 --- a/drivers/net/dsa/lantiq/mxl-gsw1xx.h +++ b/drivers/net/dsa/lantiq/mxl-gsw1xx.h @@ -110,6 +110,15 @@ #define GSW1XX_SHELL_BASE 0xfa00 #define GSW1XX_SHELL_RST_REQ 0x01 #define GSW1XX_RST_REQ_SGMII_SHELL BIT(5) +#define GSW1XX_SHELL_MANU_ID 0x10 +#define GSW1XX_SHELL_MANU_ID_PNUML GENMASK(15, 12) +#define GSW1XX_SHELL_MANU_ID_MANID GENMASK(11, 1) +#define GSW1XX_SHELL_MANU_ID_MANID_VAL 0x389 +#define GSW1XX_SHELL_MANU_ID_FIX1 BIT(0) +#define GSW1XX_SHELL_PNUM_ID 0x11 +#define GSW1XX_SHELL_PNUM_ID_VER GENMASK(15, 12) +#define GSW1XX_SHELL_PNUM_ID_PNUMM GENMASK(11, 0) + /* RGMII PAD Slew Control Register */ #define GSW1XX_SHELL_RGMII_SLEW_CFG 0x78 #define RGMII_SLEW_CFG_DRV_TXC BIT(2) |
