[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260122105654.105600-16-vladimir.oltean@nxp.com>
Date: Thu, 22 Jan 2026 12:56:54 +0200
From: Vladimir Oltean <vladimir.oltean@....com>
To: netdev@...r.kernel.org
Cc: Andrew Lunn <andrew@...n.ch>,
Heiner Kallweit <hkallweit1@...il.com>,
Russell King <linux@...linux.org.uk>,
"David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>,
linux-kernel@...r.kernel.org,
Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
Herve Codina <herve.codina@...tlin.com>,
Mark Brown <broonie@...nel.org>,
Serge Semin <fancer.lancer@...il.com>,
Maxime Chevallier <maxime.chevallier@...tlin.com>,
Lee Jones <lee@...nel.org>,
Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
devicetree@...r.kernel.org,
Choong Yong Liang <yong.liang.choong@...ux.intel.com>,
Jiawen Wu <jiawenwu@...stnetic.com>
Subject: [PATCH v2 net-next 15/15] net: pcs: xpcs: allow generic polarity inversion
Using the linux/phy/phy-common-props.h helpers, get the 'rx-polarity'
and 'tx-polarity' device tree properties, and apply them to hardware in
the newly introduced xpcs_pma_config(), called from phylink_pcs_ops ::
pcs_config().
This is the right place to do it, as the generic PHY helpers require
knowing the phy_interface_t for which we want the polarity known, and
that comes from phylink.
By using the "manual" helpers, we default to PHY_POL_NORMAL, and support
normal and inverted polarities in the RX and TX directions.
Note that for NXP SJA1105, to get a functional data path with
non-inverted signals at the device pins, we have to apply TX polarity
inversion in the PCS, due to its integration with a custom PMA.
Since the SJA1105 was only recently made to describe the XPCS in the
device tree, we can require that this hardware quirk is described there,
and this avoids having custom handling for it in the driver.
Signed-off-by: Vladimir Oltean <vladimir.oltean@....com>
---
v1->v2:
- use phy_get_manual_rx_polarity() and phy_get_manual_tx_polarity(),
which are simpler helpers that assume the default polarity is
PHY_POL_NORMAL. There is a slight regression risk if some XPCS
integrations rely on custom polarity set in the bootloader.
- drop custom handling for SJA1105.
drivers/net/pcs/Kconfig | 1 +
drivers/net/pcs/pcs-xpcs-nxp.c | 11 --------
drivers/net/pcs/pcs-xpcs.c | 46 ++++++++++++++++++++++++++++------
drivers/net/pcs/pcs-xpcs.h | 1 -
4 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig
index e417fd66f660..c95e24c895df 100644
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig
@@ -8,6 +8,7 @@ menu "PCS device drivers"
config PCS_XPCS
tristate "Synopsys DesignWare Ethernet XPCS"
select PHYLINK
+ select PHY_COMMON_PROPS
help
This module provides a driver and helper functions for Synopsys
DesignWare XPCS controllers.
diff --git a/drivers/net/pcs/pcs-xpcs-nxp.c b/drivers/net/pcs/pcs-xpcs-nxp.c
index e8efe94cf4ec..37708b28a7aa 100644
--- a/drivers/net/pcs/pcs-xpcs-nxp.c
+++ b/drivers/net/pcs/pcs-xpcs-nxp.c
@@ -64,17 +64,6 @@
/* RX_CDR_CTLE register */
#define SJA1110_RX_CDR_CTLE 0x8042
-/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane
- * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain
- * normal non-inverted behavior, the TX lane polarity must be inverted in the
- * PCS, via the DIGITAL_CONTROL_2 register.
- */
-int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs)
-{
- return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2,
- DW_VR_MII_DIG_CTRL2_TX_POL_INV);
-}
-
static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs,
u16 txpll_fbdiv, u16 txpll_refdiv,
u16 rxpll_fbdiv, u16 rxpll_refdiv,
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 910fd8b23d41..eeddd0b1f3da 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -11,6 +11,7 @@
#include <linux/pcs/pcs-xpcs.h>
#include <linux/mdio.h>
#include <linux/phy.h>
+#include <linux/phy/phy-common-props.h>
#include <linux/phylink.h>
#include <linux/property.h>
@@ -908,6 +909,42 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
BMCR_SPEED1000);
}
+static int xpcs_pma_config(struct dw_xpcs *xpcs, const struct dw_xpcs_compat *compat)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(&xpcs->mdiodev->dev);
+ u32 val = 0, mask;
+ unsigned int pol;
+ int ret;
+
+ mask = DW_VR_MII_DIG_CTRL2_TX_POL_INV | DW_VR_MII_DIG_CTRL2_RX_POL_INV;
+
+ ret = phy_get_manual_rx_polarity(fwnode, phy_modes(compat->interface),
+ &pol);
+ if (ret)
+ return ret;
+ if (pol == PHY_POL_INVERT)
+ val |= DW_VR_MII_DIG_CTRL2_RX_POL_INV;
+
+ ret = phy_get_manual_tx_polarity(fwnode, phy_modes(compat->interface),
+ &pol);
+ if (ret)
+ return ret;
+ if (pol == PHY_POL_INVERT)
+ val |= DW_VR_MII_DIG_CTRL2_TX_POL_INV;
+
+ ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2, mask, val);
+ if (ret < 0)
+ return ret;
+
+ if (compat->pma_config) {
+ ret = compat->pma_config(xpcs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
const unsigned long *advertising,
unsigned int neg_mode)
@@ -959,13 +996,7 @@ static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
return -EINVAL;
}
- if (compat->pma_config) {
- ret = compat->pma_config(xpcs);
- if (ret)
- return ret;
- }
-
- return 0;
+ return xpcs_pma_config(xpcs, compat);
}
static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
@@ -1456,7 +1487,6 @@ static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[] = {
.interface = PHY_INTERFACE_MODE_SGMII,
.supported = xpcs_sgmii_features,
.an_mode = DW_AN_C37_SGMII,
- .pma_config = nxp_sja1105_sgmii_pma_config,
}, {
}
};
diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h
index 929fa238445e..56fd170a8736 100644
--- a/drivers/net/pcs/pcs-xpcs.h
+++ b/drivers/net/pcs/pcs-xpcs.h
@@ -121,7 +121,6 @@ int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
int xpcs_modify(struct dw_xpcs *xpcs, int dev, u32 reg, u16 mask, u16 set);
int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg);
int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val);
-int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs);
int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
--
2.34.1
Powered by blists - more mailing lists