* [PATCH phy 01/14] phy: lynx-28g: remove LYNX_28G_ prefix from register names
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 02/14] phy: lynx-28g: don't concatenate lynx_28g_lane_rmw() argument "reg" with "val" and "mask" Vladimir Oltean
` (12 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
Currently, in macros such as lynx_28g_lane_rmw(), the driver has
macros which concatenate the LYNX_28G_ prefix with the "val" and "mask"
arguments. This is done to shorten function calls and not have to spell
out LYNX_28G_ everywhere.
But outside of lynx_28g_lane_rmw(), lynx_28g_lane_read() and
lynx_28g_pll_read(), this is not done, leading to an inconsistency in
the code.
Also, the concatenation itself has the disadvantage that searching the
arguments of these functions as full words (like N_RATE_QUARTER) leads
us nowhere, since the real macro definition is LNaTGCR0_N_RATE_QUARTER.
Some maintainers want register definitions in drivers to contain the
driver name as a prefix, but here, this has the disadvantages listed
above, so just remove that prefix.
The only change made here is the removal of LYNX_28G_.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 248 +++++++++++------------
1 file changed, 124 insertions(+), 124 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index c20d2636c5e9..4e8d2c56d702 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -12,99 +12,99 @@
#define LYNX_28G_NUM_PLL 2
/* General registers per SerDes block */
-#define LYNX_28G_PCC8 0x10a0
-#define LYNX_28G_PCC8_SGMII 0x1
-#define LYNX_28G_PCC8_SGMII_DIS 0x0
+#define PCC8 0x10a0
+#define PCC8_SGMII 0x1
+#define PCC8_SGMII_DIS 0x0
-#define LYNX_28G_PCCC 0x10b0
-#define LYNX_28G_PCCC_10GBASER 0x9
-#define LYNX_28G_PCCC_USXGMII 0x1
-#define LYNX_28G_PCCC_SXGMII_DIS 0x0
+#define PCCC 0x10b0
+#define PCCC_10GBASER 0x9
+#define PCCC_USXGMII 0x1
+#define PCCC_SXGMII_DIS 0x0
-#define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
+#define LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
/* Per PLL registers */
-#define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
-#define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
-#define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
-
-#define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
-#define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x0
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x10000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x20000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x30000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x40000
-
-#define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
-#define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))
-#define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x0
-#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x10000000
-#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x6000000
+#define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
+#define PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
+#define PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
+
+#define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
+#define PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))
+#define PLLnCR0_REFCLK_SEL_100MHZ 0x0
+#define PLLnCR0_REFCLK_SEL_125MHZ 0x10000
+#define PLLnCR0_REFCLK_SEL_156MHZ 0x20000
+#define PLLnCR0_REFCLK_SEL_150MHZ 0x30000
+#define PLLnCR0_REFCLK_SEL_161MHZ 0x40000
+
+#define PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
+#define PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))
+#define PLLnCR1_FRATE_5G_10GVCO 0x0
+#define PLLnCR1_FRATE_5G_25GVCO 0x10000000
+#define PLLnCR1_FRATE_10G_20GVCO 0x6000000
/* Per SerDes lane registers */
/* Lane a General Control Register */
-#define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
-#define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)
-#define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x8
-#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x50
-#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)
-#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x0
-#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x2
+#define LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
+#define LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)
+#define LNaGCR0_PROTO_SEL_SGMII 0x8
+#define LNaGCR0_PROTO_SEL_XFI 0x50
+#define LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)
+#define LNaGCR0_IF_WIDTH_10_BIT 0x0
+#define LNaGCR0_IF_WIDTH_20_BIT 0x2
/* Lane a Tx Reset Control Register */
-#define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
-#define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27)
-#define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30)
-#define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31)
+#define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
+#define LNaTRSTCTL_HLT_REQ BIT(27)
+#define LNaTRSTCTL_RST_DONE BIT(30)
+#define LNaTRSTCTL_RST_REQ BIT(31)
/* Lane a Tx General Control Register */
-#define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
-#define LYNX_28G_LNaTGCR0_USE_PLLF 0x0
-#define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28)
-#define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28)
-#define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x0
-#define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x1000000
-#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x2000000
-#define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24)
+#define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
+#define LNaTGCR0_USE_PLLF 0x0
+#define LNaTGCR0_USE_PLLS BIT(28)
+#define LNaTGCR0_USE_PLL_MSK BIT(28)
+#define LNaTGCR0_N_RATE_FULL 0x0
+#define LNaTGCR0_N_RATE_HALF 0x1000000
+#define LNaTGCR0_N_RATE_QUARTER 0x2000000
+#define LNaTGCR0_N_RATE_MSK GENMASK(26, 24)
-#define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
+#define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
/* Lane a Rx Reset Control Register */
-#define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
-#define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27)
-#define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30)
-#define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31)
-#define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12)
+#define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
+#define LNaRRSTCTL_HLT_REQ BIT(27)
+#define LNaRRSTCTL_RST_DONE BIT(30)
+#define LNaRRSTCTL_RST_REQ BIT(31)
+#define LNaRRSTCTL_CDR_LOCK BIT(12)
/* Lane a Rx General Control Register */
-#define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
-#define LYNX_28G_LNaRGCR0_USE_PLLF 0x0
-#define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28)
-#define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28)
-#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
-#define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x0
-#define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x1000000
-#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x2000000
-#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
-
-#define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
-
-#define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
-#define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
-#define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
-
-#define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
-
-#define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4)
-#define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)
-#define LYNX_28G_LNaPSS_TYPE_SGMII 0x4
-#define LYNX_28G_LNaPSS_TYPE_XFI 0x28
-
-#define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
-#define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11)
-#define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0
-#define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11)
+#define LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
+#define LNaRGCR0_USE_PLLF 0x0
+#define LNaRGCR0_USE_PLLS BIT(28)
+#define LNaRGCR0_USE_PLL_MSK BIT(28)
+#define LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
+#define LNaRGCR0_N_RATE_FULL 0x0
+#define LNaRGCR0_N_RATE_HALF 0x1000000
+#define LNaRGCR0_N_RATE_QUARTER 0x2000000
+#define LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
+
+#define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
+
+#define LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
+#define LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
+#define LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
+
+#define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
+
+#define LNaPSS(lane) (0x1000 + (lane) * 0x4)
+#define LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)
+#define LNaPSS_TYPE_SGMII 0x4
+#define LNaPSS_TYPE_XFI 0x28
+
+#define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
+#define SGMIIaCR1_SGPCS_EN BIT(11)
+#define SGMIIaCR1_SGPCS_DIS 0x0
+#define SGMIIaCR1_SGPCS_MSK BIT(11)
struct lynx_28g_priv;
@@ -150,19 +150,19 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
}
#define lynx_28g_lane_rmw(lane, reg, val, mask) \
- lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \
- LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)
+ lynx_28g_rmw((lane)->priv, reg(lane->id), \
+ reg##_##val, reg##_##mask)
#define lynx_28g_lane_read(lane, reg) \
- ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))
+ ioread32((lane)->priv->base + reg((lane)->id))
#define lynx_28g_pll_read(pll, reg) \
- ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))
+ ioread32((pll)->priv->base + reg((pll)->id))
static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
{
int i;
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
- if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))
+ if (PLLnRSTCTL_DIS(priv->pll[i].rstctl))
continue;
if (test_bit(intf, priv->pll[i].supported))
@@ -181,7 +181,7 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
pll = &priv->pll[i];
- if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
+ if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
if (test_bit(intf, pll->supported))
@@ -199,9 +199,9 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll,
phy_interface_t intf)
{
- switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
- case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
- case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
+ switch (PLLnCR1_FRATE_SEL(pll->cr1)) {
+ case PLLnCR1_FRATE_5G_10GVCO:
+ case PLLnCR1_FRATE_5G_25GVCO:
switch (intf) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
@@ -212,7 +212,7 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
break;
}
break;
- case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
+ case PLLnCR1_FRATE_10G_20GVCO:
switch (intf) {
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_USXGMII:
@@ -242,20 +242,20 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
+ u32 lane_offset = LNa_PCC_OFFSET(lane);
/* Cleanup the protocol configuration registers of the current protocol */
switch (lane->interface) {
case PHY_INTERFACE_MODE_10GBASER:
- lynx_28g_rmw(priv, LYNX_28G_PCCC,
- LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
+ lynx_28g_rmw(priv, PCCC,
+ PCCC_SXGMII_DIS << lane_offset,
GENMASK(3, 0) << lane_offset);
break;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_rmw(priv, LYNX_28G_PCC8,
- LYNX_28G_PCC8_SGMII_DIS << lane_offset,
+ lynx_28g_rmw(priv, PCC8,
+ PCC8_SGMII_DIS << lane_offset,
GENMASK(3, 0) << lane_offset);
break;
default:
@@ -265,15 +265,15 @@ static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
+ u32 lane_offset = LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
struct lynx_28g_pll *pll;
lynx_28g_cleanup_lane(lane);
/* Setup the lane to run in SGMII */
- lynx_28g_rmw(priv, LYNX_28G_PCC8,
- LYNX_28G_PCC8_SGMII << lane_offset,
+ lynx_28g_rmw(priv, PCC8,
+ PCC8_SGMII << lane_offset,
GENMASK(3, 0) << lane_offset);
/* Setup the protocol select and SerDes parallel interface width */
@@ -295,25 +295,25 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
/* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
- iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
- iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
+ iowrite32(0x00808006, priv->base + LNaTECR0(lane->id));
+ iowrite32(0x04310000, priv->base + LNaRGCR1(lane->id));
+ iowrite32(0x9f800000, priv->base + LNaRECR0(lane->id));
+ iowrite32(0x001f0000, priv->base + LNaRECR1(lane->id));
+ iowrite32(0x00000000, priv->base + LNaRECR2(lane->id));
+ iowrite32(0x00000000, priv->base + LNaRSCCR0(lane->id));
}
static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
+ u32 lane_offset = LNa_PCC_OFFSET(lane);
struct lynx_28g_pll *pll;
lynx_28g_cleanup_lane(lane);
/* Enable the SXGMII lane */
- lynx_28g_rmw(priv, LYNX_28G_PCCC,
- LYNX_28G_PCCC_10GBASER << lane_offset,
+ lynx_28g_rmw(priv, PCCC,
+ PCCC_10GBASER << lane_offset,
GENMASK(3, 0) << lane_offset);
/* Setup the protocol select and SerDes parallel interface width */
@@ -335,12 +335,12 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
/* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
- iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
- iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
- iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
+ iowrite32(0x10808307, priv->base + LNaTECR0(lane->id));
+ iowrite32(0x10000000, priv->base + LNaRGCR1(lane->id));
+ iowrite32(0x00000000, priv->base + LNaRECR0(lane->id));
+ iowrite32(0x001f0000, priv->base + LNaRECR1(lane->id));
+ iowrite32(0x81000020, priv->base + LNaRECR2(lane->id));
+ iowrite32(0x00002000, priv->base + LNaRSCCR0(lane->id));
}
static int lynx_28g_power_off(struct phy *phy)
@@ -359,8 +359,8 @@ static int lynx_28g_power_off(struct phy *phy)
do {
trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
- (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
+ } while ((trstctl & LNaTRSTCTL_HLT_REQ) ||
+ (rrstctl & LNaRRSTCTL_HLT_REQ));
lane->powered_up = false;
@@ -383,8 +383,8 @@ static int lynx_28g_power_on(struct phy *phy)
do {
trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
- !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
+ } while (!(trstctl & LNaTRSTCTL_RST_DONE) ||
+ !(rrstctl & LNaRRSTCTL_RST_DONE));
lane->powered_up = true;
@@ -495,17 +495,17 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
- if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
+ if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
- switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
- case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
- case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
+ switch (PLLnCR1_FRATE_SEL(pll->cr1)) {
+ case PLLnCR1_FRATE_5G_10GVCO:
+ case PLLnCR1_FRATE_5G_25GVCO:
/* 5GHz clock net */
__set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
__set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
break;
- case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
+ case PLLnCR1_FRATE_10G_20GVCO:
/* 10.3125GHz clock net */
__set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
break;
@@ -536,11 +536,11 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
}
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
+ if (!(rrstctl & LNaRRSTCTL_CDR_LOCK)) {
lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
do {
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
+ } while (!(rrstctl & LNaRRSTCTL_RST_DONE));
}
mutex_unlock(&lane->phy->mutex);
@@ -554,12 +554,12 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
u32 pss, protocol;
pss = lynx_28g_lane_read(lane, LNaPSS);
- protocol = LYNX_28G_LNaPSS_TYPE(pss);
+ protocol = LNaPSS_TYPE(pss);
switch (protocol) {
- case LYNX_28G_LNaPSS_TYPE_SGMII:
+ case LNaPSS_TYPE_SGMII:
lane->interface = PHY_INTERFACE_MODE_SGMII;
break;
- case LYNX_28G_LNaPSS_TYPE_XFI:
+ case LNaPSS_TYPE_XFI:
lane->interface = PHY_INTERFACE_MODE_10GBASER;
break;
default:
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 02/14] phy: lynx-28g: don't concatenate lynx_28g_lane_rmw() argument "reg" with "val" and "mask"
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 01/14] phy: lynx-28g: remove LYNX_28G_ prefix from register names Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 03/14] phy: lynx-28g: use FIELD_GET() and FIELD_PREP() Vladimir Oltean
` (11 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
The last step in having lynx_28g_lane_rmw() arguments that fully point
to their definitions is the removal of the current concatenation logic,
by which e.g. "LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK" is expanded to
"LNaTGCR0, LNaTGCR0_N_RATE_QUARTER, LNaTGCR0_N_RATE_MSK".
There are pros and cons to the above. An advantage is the impossibility
to mix up fields of one register with fields of another. For example
both LNaTGCR0 and LNaRGCR0 contain an N_RATE_QUARTER field (one for the
lane RX direction, one for the lane TX).
But the two notable disadvantages are:
1. the impossibility to write expressions such as logical OR between
multiple fields. Practically, this forces us to perform more accesses
to hardware registers than would otherwise be needed. See the LNaGCR0
access for example.
2. the necessity to invent fields that don't exist, like SGMIIaCR1_SGPCS_DIS,
in order to clear SGMIIaCR1_SGPCS_EN (the real field name). This is
confusing, because sometimes, fields that end with _DIS really exist,
and it's best to not invent new field names.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 60 +++++++++++++++---------
1 file changed, 38 insertions(+), 22 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 4e8d2c56d702..732ba65950f3 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -103,7 +103,6 @@
#define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
#define SGMIIaCR1_SGPCS_EN BIT(11)
-#define SGMIIaCR1_SGPCS_DIS 0x0
#define SGMIIaCR1_SGPCS_MSK BIT(11)
struct lynx_28g_priv;
@@ -150,8 +149,7 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
}
#define lynx_28g_lane_rmw(lane, reg, val, mask) \
- lynx_28g_rmw((lane)->priv, reg(lane->id), \
- reg##_##val, reg##_##mask)
+ lynx_28g_rmw((lane)->priv, reg(lane->id), val, mask)
#define lynx_28g_lane_read(lane, reg) \
ioread32((lane)->priv->base + reg((lane)->id))
#define lynx_28g_pll_read(pll, reg) \
@@ -205,8 +203,12 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
switch (intf) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ LNaTGCR0_N_RATE_QUARTER,
+ LNaTGCR0_N_RATE_MSK);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ LNaRGCR0_N_RATE_QUARTER,
+ LNaRGCR0_N_RATE_MSK);
break;
default:
break;
@@ -216,8 +218,10 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
switch (intf) {
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_USXGMII:
- lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0, LNaTGCR0_N_RATE_FULL,
+ LNaTGCR0_N_RATE_MSK);
+ lynx_28g_lane_rmw(lane, LNaRGCR0, LNaRGCR0_N_RATE_FULL,
+ LNaRGCR0_N_RATE_MSK);
break;
default:
break;
@@ -232,11 +236,15 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll)
{
if (pll->id == 0) {
- lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0, LNaTGCR0_USE_PLLF,
+ LNaTGCR0_USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaRGCR0, LNaRGCR0_USE_PLLF,
+ LNaRGCR0_USE_PLL_MSK);
} else {
- lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0, LNaTGCR0_USE_PLLS,
+ LNaTGCR0_USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaRGCR0, LNaRGCR0_USE_PLLS,
+ LNaRGCR0_USE_PLL_MSK);
}
}
@@ -277,8 +285,9 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
GENMASK(3, 0) << lane_offset);
/* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
- lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
+ lynx_28g_lane_rmw(lane, LNaGCR0,
+ LNaGCR0_PROTO_SEL_SGMII | LNaGCR0_IF_WIDTH_10_BIT,
+ LNaGCR0_PROTO_SEL_MSK | LNaGCR0_IF_WIDTH_MSK);
/* Find the PLL that works with this interface type */
pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
@@ -292,7 +301,8 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
/* Enable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
+ lynx_28g_lane_rmw(lane, SGMIIaCR1, SGMIIaCR1_SGPCS_EN,
+ SGMIIaCR1_SGPCS_MSK);
/* Configure the appropriate equalization parameters for the protocol */
iowrite32(0x00808006, priv->base + LNaTECR0(lane->id));
@@ -317,8 +327,9 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
GENMASK(3, 0) << lane_offset);
/* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
- lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
+ lynx_28g_lane_rmw(lane, LNaGCR0,
+ LNaGCR0_PROTO_SEL_XFI | LNaGCR0_IF_WIDTH_20_BIT,
+ LNaGCR0_PROTO_SEL_MSK | LNaGCR0_IF_WIDTH_MSK);
/* Find the PLL that works with this interface type */
pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
@@ -332,7 +343,7 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
/* Disable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
+ lynx_28g_lane_rmw(lane, SGMIIaCR1, 0, SGMIIaCR1_SGPCS_MSK);
/* Configure the appropriate equalization parameters for the protocol */
iowrite32(0x10808307, priv->base + LNaTECR0(lane->id));
@@ -352,8 +363,10 @@ static int lynx_28g_power_off(struct phy *phy)
return 0;
/* Issue a halt request */
- lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ,
+ LNaTRSTCTL_HLT_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_HLT_REQ,
+ LNaRRSTCTL_HLT_REQ);
/* Wait until the halting process is complete */
do {
@@ -376,8 +389,10 @@ static int lynx_28g_power_on(struct phy *phy)
return 0;
/* Issue a reset request on the lane */
- lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ,
+ LNaTRSTCTL_RST_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
+ LNaRRSTCTL_RST_REQ);
/* Wait until the reset sequence is completed */
do {
@@ -537,7 +552,8 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
if (!(rrstctl & LNaRRSTCTL_CDR_LOCK)) {
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
+ LNaRRSTCTL_RST_REQ);
do {
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
} while (!(rrstctl & LNaRRSTCTL_RST_DONE));
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 03/14] phy: lynx-28g: use FIELD_GET() and FIELD_PREP()
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 01/14] phy: lynx-28g: remove LYNX_28G_ prefix from register names Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 02/14] phy: lynx-28g: don't concatenate lynx_28g_lane_rmw() argument "reg" with "val" and "mask" Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 04/14] phy: lynx-28g: convert iowrite32() calls with magic values to macros Vladimir Oltean
` (10 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
Reduce the number of bit field definitions required in this driver (in
the worst case, a read form and a write form), by defining just the
mask, and using the FIELD_GET() and FIELD_PREP() API from
<linux/bitfield.h> with that.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 107 ++++++++++++-----------
1 file changed, 57 insertions(+), 50 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 732ba65950f3..414d9a4bcbb7 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021-2022 NXP. */
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
@@ -29,26 +30,26 @@
#define PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
#define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
-#define PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))
+#define PLLnCR0_REFCLK_SEL GENMASK(20, 16)
#define PLLnCR0_REFCLK_SEL_100MHZ 0x0
-#define PLLnCR0_REFCLK_SEL_125MHZ 0x10000
-#define PLLnCR0_REFCLK_SEL_156MHZ 0x20000
-#define PLLnCR0_REFCLK_SEL_150MHZ 0x30000
-#define PLLnCR0_REFCLK_SEL_161MHZ 0x40000
+#define PLLnCR0_REFCLK_SEL_125MHZ 0x1
+#define PLLnCR0_REFCLK_SEL_156MHZ 0x2
+#define PLLnCR0_REFCLK_SEL_150MHZ 0x3
+#define PLLnCR0_REFCLK_SEL_161MHZ 0x4
#define PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
-#define PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))
+#define PLLnCR1_FRATE_SEL GENMASK(28, 24)
#define PLLnCR1_FRATE_5G_10GVCO 0x0
-#define PLLnCR1_FRATE_5G_25GVCO 0x10000000
-#define PLLnCR1_FRATE_10G_20GVCO 0x6000000
+#define PLLnCR1_FRATE_5G_25GVCO 0x10
+#define PLLnCR1_FRATE_10G_20GVCO 0x6
/* Per SerDes lane registers */
/* Lane a General Control Register */
#define LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
-#define LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)
-#define LNaGCR0_PROTO_SEL_SGMII 0x8
-#define LNaGCR0_PROTO_SEL_XFI 0x50
-#define LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)
+#define LNaGCR0_PROTO_SEL GENMASK(7, 3)
+#define LNaGCR0_PROTO_SEL_SGMII 0x1
+#define LNaGCR0_PROTO_SEL_XFI 0xa
+#define LNaGCR0_IF_WIDTH GENMASK(2, 0)
#define LNaGCR0_IF_WIDTH_10_BIT 0x0
#define LNaGCR0_IF_WIDTH_20_BIT 0x2
@@ -60,13 +61,13 @@
/* Lane a Tx General Control Register */
#define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
+#define LNaTGCR0_USE_PLL BIT(28)
#define LNaTGCR0_USE_PLLF 0x0
-#define LNaTGCR0_USE_PLLS BIT(28)
-#define LNaTGCR0_USE_PLL_MSK BIT(28)
+#define LNaTGCR0_USE_PLLS 0x1
+#define LNaTGCR0_N_RATE GENMASK(26, 24)
#define LNaTGCR0_N_RATE_FULL 0x0
-#define LNaTGCR0_N_RATE_HALF 0x1000000
-#define LNaTGCR0_N_RATE_QUARTER 0x2000000
-#define LNaTGCR0_N_RATE_MSK GENMASK(26, 24)
+#define LNaTGCR0_N_RATE_HALF 0x1
+#define LNaTGCR0_N_RATE_QUARTER 0x2
#define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
@@ -79,14 +80,13 @@
/* Lane a Rx General Control Register */
#define LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
+#define LNaRGCR0_USE_PLL BIT(28)
#define LNaRGCR0_USE_PLLF 0x0
-#define LNaRGCR0_USE_PLLS BIT(28)
-#define LNaRGCR0_USE_PLL_MSK BIT(28)
-#define LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
+#define LNaRGCR0_USE_PLLS 0x1
+#define LNaRGCR0_N_RATE GENMASK(26, 24)
#define LNaRGCR0_N_RATE_FULL 0x0
-#define LNaRGCR0_N_RATE_HALF 0x1000000
-#define LNaRGCR0_N_RATE_QUARTER 0x2000000
-#define LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
+#define LNaRGCR0_N_RATE_HALF 0x1
+#define LNaRGCR0_N_RATE_QUARTER 0x2
#define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
@@ -97,13 +97,12 @@
#define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
#define LNaPSS(lane) (0x1000 + (lane) * 0x4)
-#define LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)
+#define LNaPSS_TYPE GENMASK(30, 24)
#define LNaPSS_TYPE_SGMII 0x4
#define LNaPSS_TYPE_XFI 0x28
#define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
#define SGMIIaCR1_SGPCS_EN BIT(11)
-#define SGMIIaCR1_SGPCS_MSK BIT(11)
struct lynx_28g_priv;
@@ -197,18 +196,18 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll,
phy_interface_t intf)
{
- switch (PLLnCR1_FRATE_SEL(pll->cr1)) {
+ switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
switch (intf) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
lynx_28g_lane_rmw(lane, LNaTGCR0,
- LNaTGCR0_N_RATE_QUARTER,
- LNaTGCR0_N_RATE_MSK);
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_QUARTER),
+ LNaTGCR0_N_RATE);
lynx_28g_lane_rmw(lane, LNaRGCR0,
- LNaRGCR0_N_RATE_QUARTER,
- LNaRGCR0_N_RATE_MSK);
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_QUARTER),
+ LNaRGCR0_N_RATE);
break;
default:
break;
@@ -218,10 +217,12 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
switch (intf) {
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_USXGMII:
- lynx_28g_lane_rmw(lane, LNaTGCR0, LNaTGCR0_N_RATE_FULL,
- LNaTGCR0_N_RATE_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, LNaRGCR0_N_RATE_FULL,
- LNaRGCR0_N_RATE_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_FULL),
+ LNaTGCR0_N_RATE);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_FULL),
+ LNaRGCR0_N_RATE);
break;
default:
break;
@@ -236,15 +237,19 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll)
{
if (pll->id == 0) {
- lynx_28g_lane_rmw(lane, LNaTGCR0, LNaTGCR0_USE_PLLF,
- LNaTGCR0_USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, LNaRGCR0_USE_PLLF,
- LNaRGCR0_USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLF),
+ LNaTGCR0_USE_PLL);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLF),
+ LNaRGCR0_USE_PLL);
} else {
- lynx_28g_lane_rmw(lane, LNaTGCR0, LNaTGCR0_USE_PLLS,
- LNaTGCR0_USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, LNaRGCR0_USE_PLLS,
- LNaRGCR0_USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLS),
+ LNaTGCR0_USE_PLL);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLS),
+ LNaRGCR0_USE_PLL);
}
}
@@ -286,8 +291,9 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
/* Setup the protocol select and SerDes parallel interface width */
lynx_28g_lane_rmw(lane, LNaGCR0,
- LNaGCR0_PROTO_SEL_SGMII | LNaGCR0_IF_WIDTH_10_BIT,
- LNaGCR0_PROTO_SEL_MSK | LNaGCR0_IF_WIDTH_MSK);
+ FIELD_PREP(LNaGCR0_PROTO_SEL, LNaGCR0_PROTO_SEL_SGMII) |
+ FIELD_PREP(LNaGCR0_IF_WIDTH, LNaGCR0_IF_WIDTH_10_BIT),
+ LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
/* Find the PLL that works with this interface type */
pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
@@ -302,7 +308,7 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
/* Enable the SGMII PCS */
lynx_28g_lane_rmw(lane, SGMIIaCR1, SGMIIaCR1_SGPCS_EN,
- SGMIIaCR1_SGPCS_MSK);
+ SGMIIaCR1_SGPCS_EN);
/* Configure the appropriate equalization parameters for the protocol */
iowrite32(0x00808006, priv->base + LNaTECR0(lane->id));
@@ -328,8 +334,9 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
/* Setup the protocol select and SerDes parallel interface width */
lynx_28g_lane_rmw(lane, LNaGCR0,
- LNaGCR0_PROTO_SEL_XFI | LNaGCR0_IF_WIDTH_20_BIT,
- LNaGCR0_PROTO_SEL_MSK | LNaGCR0_IF_WIDTH_MSK);
+ FIELD_PREP(LNaGCR0_PROTO_SEL, LNaGCR0_PROTO_SEL_XFI) |
+ FIELD_PREP(LNaGCR0_IF_WIDTH, LNaGCR0_IF_WIDTH_20_BIT),
+ LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
/* Find the PLL that works with this interface type */
pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
@@ -343,7 +350,7 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
/* Disable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, 0, SGMIIaCR1_SGPCS_MSK);
+ lynx_28g_lane_rmw(lane, SGMIIaCR1, 0, SGMIIaCR1_SGPCS_EN);
/* Configure the appropriate equalization parameters for the protocol */
iowrite32(0x10808307, priv->base + LNaTECR0(lane->id));
@@ -513,7 +520,7 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
- switch (PLLnCR1_FRATE_SEL(pll->cr1)) {
+ switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
/* 5GHz clock net */
@@ -570,7 +577,7 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
u32 pss, protocol;
pss = lynx_28g_lane_read(lane, LNaPSS);
- protocol = LNaPSS_TYPE(pss);
+ protocol = FIELD_GET(LNaPSS_TYPE, pss);
switch (protocol) {
case LNaPSS_TYPE_SGMII:
lane->interface = PHY_INTERFACE_MODE_SGMII;
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 04/14] phy: lynx-28g: convert iowrite32() calls with magic values to macros
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (2 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 03/14] phy: lynx-28g: use FIELD_GET() and FIELD_PREP() Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 05/14] phy: lynx-28g: restructure protocol configuration register accesses Vladimir Oltean
` (9 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
The driver will need to become more careful with the values it writes to
the TX and RX equalization registers. As a preliminary step, convert the
magic numbers to macros defining the register field meanings.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 103 ++++++++++++++++++++---
1 file changed, 91 insertions(+), 12 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 414d9a4bcbb7..60a7d1a63dd7 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -70,6 +70,12 @@
#define LNaTGCR0_N_RATE_QUARTER 0x2
#define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
+#define LNaTECR0_EQ_TYPE GENMASK(30, 28)
+#define LNaTECR0_EQ_SGN_PREQ BIT(23)
+#define LNaTECR0_EQ_PREQ GENMASK(19, 16)
+#define LNaTECR0_EQ_SGN_POST1Q BIT(15)
+#define LNaTECR0_EQ_POST1Q GENMASK(12, 8)
+#define LNaTECR0_EQ_AMP_RED GENMASK(5, 0)
/* Lane a Rx Reset Control Register */
#define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
@@ -89,12 +95,57 @@
#define LNaRGCR0_N_RATE_QUARTER 0x2
#define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
+#define LNaRGCR1_RX_ORD_ELECIDLE BIT(31)
+#define LNaRGCR1_DATA_LOST_FLT BIT(30)
+#define LNaRGCR1_DATA_LOST BIT(29)
+#define LNaRGCR1_IDLE_CONFIG BIT(28)
+#define LNaRGCR1_ENTER_IDLE_FLT_SEL GENMASK(26, 24)
+#define LNaRGCR1_EXIT_IDLE_FLT_SEL GENMASK(22, 20)
+#define LNaRGCR1_DATA_LOST_TH_SEL GENMASK(18, 16)
+#define LNaRGCR1_EXT_REC_CLK_SEL GENMASK(10, 8)
+#define LNaRGCR1_WAKE_TX_DIS BIT(5)
+#define LNaRGCR1_PHY_RDY BIT(4)
+#define LNaRGCR1_CHANGE_RX_CLK BIT(3)
+#define LNaRGCR1_PWR_MGT GENMASK(2, 0)
#define LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
+#define LNaRECR0_EQ_GAINK2_HF_OV_EN BIT(31)
+#define LNaRECR0_EQ_GAINK2_HF_OV GENMASK(28, 24)
+#define LNaRECR0_EQ_GAINK3_MF_OV_EN BIT(23)
+#define LNaRECR0_EQ_GAINK3_MF_OV GENMASK(20, 16)
+#define LNaRECR0_EQ_GAINK4_LF_OV_EN BIT(7)
+#define LNaRECR0_EQ_GAINK4_LF_DIS BIT(6)
+#define LNaRECR0_EQ_GAINK4_LF_OV GENMASK(4, 0)
+
#define LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
+#define LNaRECR1_EQ_BLW_OV_EN BIT(31)
+#define LNaRECR1_EQ_BLW_OV GENMASK(28, 24)
+#define LNaRECR1_EQ_OFFSET_OV_EN BIT(23)
+#define LNaRECR1_EQ_OFFSET_OV GENMASK(21, 16)
+
#define LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
+#define LNaRECR2_EQ_OFFSET_RNG_DBL BIT(31)
+#define LNaRECR2_EQ_BOOST GENMASK(29, 28)
+#define LNaRECR2_EQ_BLW_SEL GENMASK(25, 24)
+#define LNaRECR2_EQ_ZERO GENMASK(17, 16)
+#define LNaRECR2_EQ_IND GENMASK(13, 12)
+#define LNaRECR2_EQ_BIN_DATA_AVG_TC GENMASK(5, 4)
+#define LNaRECR2_SPARE_IN GENMASK(1, 0)
#define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
+#define LNaRSCCR0_SMP_OFF_EN BIT(31)
+#define LNaRSCCR0_SMP_OFF_OV_EN BIT(30)
+#define LNaRSCCR0_SMP_MAN_OFF_EN BIT(29)
+#define LNaRSCCR0_SMP_OFF_RNG_OV_EN BIT(27)
+#define LNaRSCCR0_SMP_OFF_RNG_4X_OV BIT(25)
+#define LNaRSCCR0_SMP_OFF_RNG_2X_OV BIT(24)
+#define LNaRSCCR0_SMP_AUTOZ_PD BIT(23)
+#define LNaRSCCR0_SMP_AUTOZ_CTRL GENMASK(19, 16)
+#define LNaRSCCR0_SMP_AUTOZ_D1R GENMASK(13, 12)
+#define LNaRSCCR0_SMP_AUTOZ_D1F GENMASK(9, 8)
+#define LNaRSCCR0_SMP_AUTOZ_D1F GENMASK(9, 8)
+#define LNaRSCCR0_SMP_AUTOZ_EG1R GENMASK(5, 4)
+#define LNaRSCCR0_SMP_AUTOZ_EG1F GENMASK(1, 0)
#define LNaPSS(lane) (0x1000 + (lane) * 0x4)
#define LNaPSS_TYPE GENMASK(30, 24)
@@ -104,6 +155,12 @@
#define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
#define SGMIIaCR1_SGPCS_EN BIT(11)
+enum lynx_28g_eq_type {
+ EQ_TYPE_NO_EQ = 0,
+ EQ_TYPE_2TAP = 1,
+ EQ_TYPE_3TAP = 2,
+};
+
struct lynx_28g_priv;
struct lynx_28g_pll {
@@ -151,6 +208,8 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
lynx_28g_rmw((lane)->priv, reg(lane->id), val, mask)
#define lynx_28g_lane_read(lane, reg) \
ioread32((lane)->priv->base + reg((lane)->id))
+#define lynx_28g_lane_write(lane, reg, val) \
+ iowrite32(val, (lane)->priv->base + reg((lane)->id))
#define lynx_28g_pll_read(pll, reg) \
ioread32((pll)->priv->base + reg((pll)->id))
@@ -311,12 +370,22 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
SGMIIaCR1_SGPCS_EN);
/* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x00808006, priv->base + LNaTECR0(lane->id));
- iowrite32(0x04310000, priv->base + LNaRGCR1(lane->id));
- iowrite32(0x9f800000, priv->base + LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LNaRECR1(lane->id));
- iowrite32(0x00000000, priv->base + LNaRECR2(lane->id));
- iowrite32(0x00000000, priv->base + LNaRSCCR0(lane->id));
+ lynx_28g_lane_write(lane, LNaTECR0,
+ LNaTECR0_EQ_SGN_PREQ | LNaTECR0_EQ_SGN_POST1Q |
+ FIELD_PREP(LNaTECR0_EQ_AMP_RED, 6));
+ lynx_28g_lane_write(lane, LNaRGCR1,
+ FIELD_PREP(LNaRGCR1_ENTER_IDLE_FLT_SEL, 4) |
+ FIELD_PREP(LNaRGCR1_EXIT_IDLE_FLT_SEL, 3) |
+ LNaRGCR1_DATA_LOST_FLT);
+ lynx_28g_lane_write(lane, LNaRECR0,
+ LNaRECR0_EQ_GAINK2_HF_OV_EN |
+ FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV, 31) |
+ LNaRECR0_EQ_GAINK3_MF_OV_EN |
+ FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV, 0));
+ lynx_28g_lane_write(lane, LNaRECR1,
+ FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, 31));
+ lynx_28g_lane_write(lane, LNaRECR2, 0);
+ lynx_28g_lane_write(lane, LNaRSCCR0, 0);
}
static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
@@ -353,12 +422,22 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
lynx_28g_lane_rmw(lane, SGMIIaCR1, 0, SGMIIaCR1_SGPCS_EN);
/* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x10808307, priv->base + LNaTECR0(lane->id));
- iowrite32(0x10000000, priv->base + LNaRGCR1(lane->id));
- iowrite32(0x00000000, priv->base + LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LNaRECR1(lane->id));
- iowrite32(0x81000020, priv->base + LNaRECR2(lane->id));
- iowrite32(0x00002000, priv->base + LNaRSCCR0(lane->id));
+ lynx_28g_lane_write(lane, LNaTECR0,
+ FIELD_PREP(LNaTECR0_EQ_TYPE, EQ_TYPE_2TAP) |
+ LNaTECR0_EQ_SGN_PREQ |
+ FIELD_PREP(LNaTECR0_EQ_PREQ, 0) |
+ LNaTECR0_EQ_SGN_POST1Q |
+ FIELD_PREP(LNaTECR0_EQ_POST1Q, 3) |
+ FIELD_PREP(LNaTECR0_EQ_AMP_RED, 7));
+ lynx_28g_lane_write(lane, LNaRGCR1, LNaRGCR1_IDLE_CONFIG);
+ lynx_28g_lane_write(lane, LNaRECR0, 0);
+ lynx_28g_lane_write(lane, LNaRECR1, FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, 31));
+ lynx_28g_lane_write(lane, LNaRECR2,
+ LNaRECR2_EQ_OFFSET_RNG_DBL |
+ FIELD_PREP(LNaRECR2_EQ_BLW_SEL, 1) |
+ FIELD_PREP(LNaRECR2_EQ_BIN_DATA_AVG_TC, 2));
+ lynx_28g_lane_write(lane, LNaRSCCR0,
+ FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_D1R, 2));
}
static int lynx_28g_power_off(struct phy *phy)
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 05/14] phy: lynx-28g: restructure protocol configuration register accesses
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (3 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 04/14] phy: lynx-28g: convert iowrite32() calls with magic values to macros Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 06/14] phy: lynx-28g: make lynx_28g_set_lane_mode() more systematic Vladimir Oltean
` (8 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
Eliminate the need to calculate a lane_offset manually, and generate
some macros which access the protocol converter corresponding to the
correct lane in the PCC* registers.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 55 ++++++++++++++----------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 60a7d1a63dd7..911c975040a3 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -12,17 +12,32 @@
#define LYNX_28G_NUM_LANE 8
#define LYNX_28G_NUM_PLL 2
+#define LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
+
/* General registers per SerDes block */
#define PCC8 0x10a0
-#define PCC8_SGMII 0x1
-#define PCC8_SGMII_DIS 0x0
+#define PCC8_SGMIInCFG(lane, x) (((x) & GENMASK(2, 0)) << LNa_PCC_OFFSET(lane))
+#define PCC8_SGMIInCFG_EN(lane) PCC8_SGMIInCFG(lane, 1)
+#define PCC8_SGMIInCFG_MSK(lane) PCC8_SGMIInCFG(lane, GENMASK(2, 0))
+#define PCC8_SGMIIn_KX(lane, x) ((((x) << 3) & BIT(3)) << LNa_PCC_OFFSET(lane))
+#define PCC8_SGMIIn_KX_MSK(lane) PCC8_SGMIIn_KX(lane, 1)
+#define PCC8_MSK(lane) PCC8_SGMIInCFG_MSK(lane) | \
+ PCC8_SGMIIn_KX_MSK(lane)
#define PCCC 0x10b0
-#define PCCC_10GBASER 0x9
-#define PCCC_USXGMII 0x1
-#define PCCC_SXGMII_DIS 0x0
-
-#define LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
+#define PCCC_SXGMIInCFG(lane, x) (((x) & GENMASK(2, 0)) << LNa_PCC_OFFSET(lane))
+#define PCCC_SXGMIInCFG_EN(lane) PCCC_SXGMIInCFG(lane, 1)
+#define PCCC_SXGMIInCFG_MSK(lane) PCCC_SXGMIInCFG(lane, GENMASK(2, 0))
+#define PCCC_SXGMIInCFG_XFI(lane, x) ((((x) << 3) & BIT(3)) << LNa_PCC_OFFSET(lane))
+#define PCCC_SXGMIInCFG_XFI_MSK(lane) PCCC_SXGMIInCFG_XFI(lane, 1)
+#define PCCC_MSK(lane) PCCC_SXGMIInCFG_MSK(lane) | \
+ PCCC_SXGMIInCFG_XFI_MSK(lane)
+
+#define PCCD 0x10b4
+#define PCCD_E25GnCFG(lane, x) (((x) & GENMASK(2, 0)) << LNa_PCCD_OFFSET(lane))
+#define PCCD_E25GnCFG_EN(lane) PCCD_E25GnCFG(lane, 1)
+#define PCCD_E25GnCFG_MSK(lane) PCCD_E25GnCFG(lane, GENMASK(2, 0))
+#define PCCD_MSK(lane) PCCD_E25GnCFG_MSK(lane)
/* Per PLL registers */
#define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
@@ -315,20 +330,21 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
{
struct lynx_28g_priv *priv = lane->priv;
- u32 lane_offset = LNa_PCC_OFFSET(lane);
/* Cleanup the protocol configuration registers of the current protocol */
switch (lane->interface) {
case PHY_INTERFACE_MODE_10GBASER:
- lynx_28g_rmw(priv, PCCC,
- PCCC_SXGMII_DIS << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ /* Cleanup the protocol configuration registers */
+ lynx_28g_rmw(priv, PCCC, 0, PCCC_MSK(lane));
break;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_rmw(priv, PCC8,
- PCC8_SGMII_DIS << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ /* Cleanup the protocol configuration registers */
+ lynx_28g_rmw(priv, PCC8, 0, PCC8_MSK(lane));
+
+ /* Disable the SGMII PCS */
+ lynx_28g_lane_rmw(lane, SGMIIaCR1, 0, SGMIIaCR1_SGPCS_EN);
+
break;
default:
break;
@@ -337,16 +353,13 @@ static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
{
- u32 lane_offset = LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
struct lynx_28g_pll *pll;
lynx_28g_cleanup_lane(lane);
/* Setup the lane to run in SGMII */
- lynx_28g_rmw(priv, PCC8,
- PCC8_SGMII << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ lynx_28g_rmw(priv, PCC8, PCC8_SGMIInCFG_EN(lane), PCC8_MSK(lane));
/* Setup the protocol select and SerDes parallel interface width */
lynx_28g_lane_rmw(lane, LNaGCR0,
@@ -391,15 +404,13 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
{
struct lynx_28g_priv *priv = lane->priv;
- u32 lane_offset = LNa_PCC_OFFSET(lane);
struct lynx_28g_pll *pll;
lynx_28g_cleanup_lane(lane);
/* Enable the SXGMII lane */
- lynx_28g_rmw(priv, PCCC,
- PCCC_10GBASER << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ lynx_28g_rmw(priv, PCCC, PCCC_SXGMIInCFG_EN(lane) |
+ PCCC_SXGMIInCFG_XFI(lane, 1), PCCC_MSK(lane));
/* Setup the protocol select and SerDes parallel interface width */
lynx_28g_lane_rmw(lane, LNaGCR0,
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 06/14] phy: lynx-28g: make lynx_28g_set_lane_mode() more systematic
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (4 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 05/14] phy: lynx-28g: restructure protocol configuration register accesses Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 07/14] phy: lynx-28g: refactor lane->interface to lane->mode Vladimir Oltean
` (7 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
The current approach of transitioning from one SerDes protocol to
another in lynx_28g_set_lane_mode() is too poetic.
Because the driver only supports 1GbE and 10GbE, it only modifies those
registers which it knows are different between these two modes. However,
that is hardly extensible for 25GbE, 40GbE, backplane modes, etc.
We need something more systematic to make sure that all lane and
protocol converter registers are written to consistent values, no matter
what was the source lane mode.
For that, we need to introduce tables with register field values, for
each supported lane mode.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 657 +++++++++++++++++------
1 file changed, 494 insertions(+), 163 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 911c975040a3..c483c2a80a77 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -12,32 +12,32 @@
#define LYNX_28G_NUM_LANE 8
#define LYNX_28G_NUM_PLL 2
-#define LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
-
-/* General registers per SerDes block */
+/* SoC IP wrapper for protocol converters */
#define PCC8 0x10a0
-#define PCC8_SGMIInCFG(lane, x) (((x) & GENMASK(2, 0)) << LNa_PCC_OFFSET(lane))
-#define PCC8_SGMIInCFG_EN(lane) PCC8_SGMIInCFG(lane, 1)
-#define PCC8_SGMIInCFG_MSK(lane) PCC8_SGMIInCFG(lane, GENMASK(2, 0))
-#define PCC8_SGMIIn_KX(lane, x) ((((x) << 3) & BIT(3)) << LNa_PCC_OFFSET(lane))
-#define PCC8_SGMIIn_KX_MSK(lane) PCC8_SGMIIn_KX(lane, 1)
-#define PCC8_MSK(lane) PCC8_SGMIInCFG_MSK(lane) | \
- PCC8_SGMIIn_KX_MSK(lane)
+#define PCC8_SGMIIa_KX BIT(3)
+#define PCC8_SGMIIa_CFG BIT(0)
#define PCCC 0x10b0
-#define PCCC_SXGMIInCFG(lane, x) (((x) & GENMASK(2, 0)) << LNa_PCC_OFFSET(lane))
-#define PCCC_SXGMIInCFG_EN(lane) PCCC_SXGMIInCFG(lane, 1)
-#define PCCC_SXGMIInCFG_MSK(lane) PCCC_SXGMIInCFG(lane, GENMASK(2, 0))
-#define PCCC_SXGMIInCFG_XFI(lane, x) ((((x) << 3) & BIT(3)) << LNa_PCC_OFFSET(lane))
-#define PCCC_SXGMIInCFG_XFI_MSK(lane) PCCC_SXGMIInCFG_XFI(lane, 1)
-#define PCCC_MSK(lane) PCCC_SXGMIInCFG_MSK(lane) | \
- PCCC_SXGMIInCFG_XFI_MSK(lane)
+#define PCCC_SXGMIIn_XFI BIT(3)
+#define PCCC_SXGMIIn_CFG BIT(0)
#define PCCD 0x10b4
-#define PCCD_E25GnCFG(lane, x) (((x) & GENMASK(2, 0)) << LNa_PCCD_OFFSET(lane))
-#define PCCD_E25GnCFG_EN(lane) PCCD_E25GnCFG(lane, 1)
-#define PCCD_E25GnCFG_MSK(lane) PCCD_E25GnCFG(lane, GENMASK(2, 0))
-#define PCCD_MSK(lane) PCCD_E25GnCFG_MSK(lane)
+#define PCCD_E25Gn_CFG BIT(0)
+
+#define PCCE 0x10b8
+#define PCCE_E40Gn_LRV BIT(3)
+#define PCCE_E40Gn_CFG BIT(0)
+#define PCCE_E50Gn_LRV BIT(3)
+#define PCCE_E50GnCFG BIT(0)
+#define PCCE_E100Gn_LRV BIT(3)
+#define PCCE_E100Gn_CFG BIT(0)
+
+#define SGMII_CFG(id) (28 - (id) * 4) /* Offset into PCC8 */
+#define SXGMII_CFG(id) (28 - (id) * 4) /* Offset into PCCC */
+#define E25G_CFG(id) (28 - (id) * 4) /* Offset into PCCD */
+#define E40G_CFG(id) (28 - (id) * 4) /* Offset into PCCE */
+#define E50G_CFG(id) (20 - (id) * 4) /* Offset into PCCE */
+#define E100G_CFG(id) (12 - (id) * 4) /* Offset into PCCE */
/* Per PLL registers */
#define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
@@ -92,6 +92,10 @@
#define LNaTECR0_EQ_POST1Q GENMASK(12, 8)
#define LNaTECR0_EQ_AMP_RED GENMASK(5, 0)
+#define LNaTECR1(lane) (0x800 + (lane) * 0x100 + 0x34)
+#define LNaTECR1_EQ_ADPT_EQ_DRVR_DIS BIT(31)
+#define LNaTECR1_EQ_ADPT_EQ GENMASK(29, 24)
+
/* Lane a Rx Reset Control Register */
#define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
#define LNaRRSTCTL_HLT_REQ BIT(27)
@@ -147,6 +151,21 @@
#define LNaRECR2_EQ_BIN_DATA_AVG_TC GENMASK(5, 4)
#define LNaRECR2_SPARE_IN GENMASK(1, 0)
+#define LNaRECR3(lane) (0x800 + (lane) * 0x100 + 0x5c)
+#define LNaRECR3_EQ_SNAP_START BIT(31)
+#define LNaRECR3_EQ_SNAP_DONE BIT(30)
+#define LNaRECR3_EQ_GAINK2_HF_STAT GENMASK(28, 24)
+#define LNaRECR3_EQ_GAINK3_MF_STAT GENMASK(20, 16)
+#define LNaRECR3_SPARE_OUT GENMASK(13, 12)
+#define LNaRECR3_EQ_GAINK4_LF_STAT GENMASK(4, 0)
+
+#define LNaRECR4(lane) (0x800 + (lane) * 0x100 + 0x60)
+#define LNaRECR4_BLW_STAT GENMASK(28, 24)
+#define LNaRECR4_EQ_OFFSET_STAT GENMASK(21, 16)
+#define LNaRECR4_EQ_BIN_DATA_SEL GENMASK(15, 12)
+#define LNaRECR4_EQ_BIN_DATA GENMASK(8, 0) /* bit 9 is reserved */
+#define LNaRECR4_EQ_BIN_DATA_SGN BIT(8)
+
#define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
#define LNaRSCCR0_SMP_OFF_EN BIT(31)
#define LNaRSCCR0_SMP_OFF_OV_EN BIT(30)
@@ -162,20 +181,199 @@
#define LNaRSCCR0_SMP_AUTOZ_EG1R GENMASK(5, 4)
#define LNaRSCCR0_SMP_AUTOZ_EG1F GENMASK(1, 0)
+#define LNaTCSR0(lane) (0x800 + (lane) * 0x100 + 0xa0)
+#define LNaTCSR0_SD_STAT_OBS_EN BIT(31)
+#define LNaTCSR0_SD_LPBK_SEL GENMASK(29, 28)
+
#define LNaPSS(lane) (0x1000 + (lane) * 0x4)
#define LNaPSS_TYPE GENMASK(30, 24)
-#define LNaPSS_TYPE_SGMII 0x4
-#define LNaPSS_TYPE_XFI 0x28
+#define LNaPSS_TYPE_SGMII (PROTO_SEL_SGMII_BASEX_KX << 2)
+#define LNaPSS_TYPE_XFI (PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2)
+#define LNaPSS_TYPE_40G ((PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2) | 3)
+#define LNaPSS_TYPE_25G (PROTO_SEL_25G_50G_100G << 2)
+#define LNaPSS_TYPE_100G ((PROTO_SEL_25G_50G_100G << 2) | 2)
+/* MDEV_PORT is at the same bitfield address for all protocol converters */
+#define MDEV_PORT GENMASK(31, 27)
+
+#define SGMIIaCR0(lane) (0x1800 + (lane) * 0x10)
#define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
#define SGMIIaCR1_SGPCS_EN BIT(11)
+#define ANLTaCR0(lane) (0x1a00 + (lane) * 0x10)
+#define ANLTaCR1(lane) (0x1a04 + (lane) * 0x10)
+
+#define SXGMIIaCR0(lane) (0x1a80 + (lane) * 0x10)
+#define SXGMIIaCR0_RST BIT(31)
+#define SXGMIIaCR0_PD BIT(30)
+
+#define SXGMIIaCR1(lane) (0x1a84 + (lane) * 0x10)
+
+#define E25GaCR0(lane) (0x1b00 + (lane) * 0x10)
+#define E25GaCR0_RST BIT(31)
+#define E25GaCR0_PD BIT(30)
+
+#define E25GaCR1(lane) (0x1b04 + (lane) * 0x10)
+
+#define E25GaCR2(lane) (0x1b08 + (lane) * 0x10)
+#define E25GaCR2_FEC_ENA BIT(23)
+#define E25GaCR2_FEC_ERR_ENA BIT(22)
+#define E25GaCR2_FEC91_ENA BIT(20)
+
+#define E40GaCR0(pcvt) (0x1b40 + (pcvt) * 0x20)
+#define E40GaCR1(pcvt) (0x1b44 + (pcvt) * 0x20)
+
+#define E50GaCR1(pcvt) (0x1b84 + (pcvt) * 0x10)
+
+#define E100GaCR1(pcvt) (0x1c04 + (pcvt) * 0x20)
+
+#define CR(x) ((x) * 4)
+
enum lynx_28g_eq_type {
EQ_TYPE_NO_EQ = 0,
EQ_TYPE_2TAP = 1,
EQ_TYPE_3TAP = 2,
};
+enum lynx_28g_proto_sel {
+ PROTO_SEL_PCIE = 0,
+ PROTO_SEL_SGMII_BASEX_KX = 1,
+ PROTO_SEL_SATA = 2,
+ PROTO_SEL_XAUI = 4,
+ PROTO_SEL_XFI_10GBASER_KR_SXGMII = 0xa,
+ PROTO_SEL_25G_50G_100G = 0x1a,
+};
+
+struct lynx_28g_proto_conf {
+ /* LNaGCR0 */
+ int proto_sel;
+ int if_width;
+ /* LNaTECR0 */
+ int teq_type;
+ int sgn_preq;
+ int ratio_preq;
+ int sgn_post1q;
+ int ratio_post1q;
+ int amp_red;
+ /* LNaTECR1 */
+ int adpt_eq;
+ /* LNaRGCR1 */
+ int enter_idle_flt_sel;
+ int exit_idle_flt_sel;
+ int data_lost_th_sel;
+ /* LNaRECR0 */
+ int gk2ovd;
+ int gk3ovd;
+ int gk4ovd;
+ int gk2ovd_en;
+ int gk3ovd_en;
+ int gk4ovd_en;
+ /* LNaRECR1 ? */
+ int eq_offset_ovd;
+ int eq_offset_ovd_en;
+ /* LNaRECR2 */
+ int eq_offset_rng_dbl;
+ int eq_blw_sel;
+ int eq_boost;
+ int spare_in;
+ /* LNaRSCCR0 */
+ int smp_autoz_d1r;
+ int smp_autoz_eg1r;
+};
+
+static const struct lynx_28g_proto_conf lynx_28g_proto_conf[PHY_INTERFACE_MODE_MAX] = {
+ [PHY_INTERFACE_MODE_SGMII] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_SGMII,
+ .if_width = LNaGCR0_IF_WIDTH_10_BIT,
+ .teq_type = EQ_TYPE_NO_EQ,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 0,
+ .amp_red = 6,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 4,
+ .exit_idle_flt_sel = 3,
+ .data_lost_th_sel = 1,
+ .gk2ovd = 0x1f,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 1,
+ .gk3ovd_en = 1,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 0,
+ .eq_blw_sel = 0,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 0,
+ .smp_autoz_eg1r = 0,
+ },
+ [PHY_INTERFACE_MODE_1000BASEX] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_SGMII,
+ .if_width = LNaGCR0_IF_WIDTH_10_BIT,
+ .teq_type = EQ_TYPE_NO_EQ,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 0,
+ .amp_red = 6,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 4,
+ .exit_idle_flt_sel = 3,
+ .data_lost_th_sel = 1,
+ .gk2ovd = 0x1f,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 1,
+ .gk3ovd_en = 1,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 0,
+ .eq_blw_sel = 0,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 0,
+ .smp_autoz_eg1r = 0,
+ },
+ [PHY_INTERFACE_MODE_10GBASER] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_XFI,
+ .if_width = LNaGCR0_IF_WIDTH_20_BIT,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 3,
+ .amp_red = 7,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 0,
+ },
+};
+
+struct lynx_pccr {
+ int offset;
+ int width;
+ int shift;
+};
+
struct lynx_28g_priv;
struct lynx_28g_pll {
@@ -219,6 +417,10 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
iowrite32(tmp, reg);
}
+#define lynx_28g_read(priv, off) \
+ ioread32((priv)->base + (off))
+#define lynx_28g_write(priv, off, val) \
+ iowrite32(val, (priv)->base + (off))
#define lynx_28g_lane_rmw(lane, reg, val, mask) \
lynx_28g_rmw((lane)->priv, reg(lane->id), val, mask)
#define lynx_28g_lane_read(lane, reg) \
@@ -327,130 +529,6 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
}
}
-static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
-{
- struct lynx_28g_priv *priv = lane->priv;
-
- /* Cleanup the protocol configuration registers of the current protocol */
- switch (lane->interface) {
- case PHY_INTERFACE_MODE_10GBASER:
- /* Cleanup the protocol configuration registers */
- lynx_28g_rmw(priv, PCCC, 0, PCCC_MSK(lane));
- break;
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- /* Cleanup the protocol configuration registers */
- lynx_28g_rmw(priv, PCC8, 0, PCC8_MSK(lane));
-
- /* Disable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, 0, SGMIIaCR1_SGPCS_EN);
-
- break;
- default:
- break;
- }
-}
-
-static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
-{
- struct lynx_28g_priv *priv = lane->priv;
- struct lynx_28g_pll *pll;
-
- lynx_28g_cleanup_lane(lane);
-
- /* Setup the lane to run in SGMII */
- lynx_28g_rmw(priv, PCC8, PCC8_SGMIInCFG_EN(lane), PCC8_MSK(lane));
-
- /* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0,
- FIELD_PREP(LNaGCR0_PROTO_SEL, LNaGCR0_PROTO_SEL_SGMII) |
- FIELD_PREP(LNaGCR0_IF_WIDTH, LNaGCR0_IF_WIDTH_10_BIT),
- LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
-
- /* Find the PLL that works with this interface type */
- pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
- if (unlikely(pll == NULL))
- return;
-
- /* Switch to the PLL that works with this interface type */
- lynx_28g_lane_set_pll(lane, pll);
-
- /* Choose the portion of clock net to be used on this lane */
- lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
-
- /* Enable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, SGMIIaCR1_SGPCS_EN,
- SGMIIaCR1_SGPCS_EN);
-
- /* Configure the appropriate equalization parameters for the protocol */
- lynx_28g_lane_write(lane, LNaTECR0,
- LNaTECR0_EQ_SGN_PREQ | LNaTECR0_EQ_SGN_POST1Q |
- FIELD_PREP(LNaTECR0_EQ_AMP_RED, 6));
- lynx_28g_lane_write(lane, LNaRGCR1,
- FIELD_PREP(LNaRGCR1_ENTER_IDLE_FLT_SEL, 4) |
- FIELD_PREP(LNaRGCR1_EXIT_IDLE_FLT_SEL, 3) |
- LNaRGCR1_DATA_LOST_FLT);
- lynx_28g_lane_write(lane, LNaRECR0,
- LNaRECR0_EQ_GAINK2_HF_OV_EN |
- FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV, 31) |
- LNaRECR0_EQ_GAINK3_MF_OV_EN |
- FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV, 0));
- lynx_28g_lane_write(lane, LNaRECR1,
- FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, 31));
- lynx_28g_lane_write(lane, LNaRECR2, 0);
- lynx_28g_lane_write(lane, LNaRSCCR0, 0);
-}
-
-static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
-{
- struct lynx_28g_priv *priv = lane->priv;
- struct lynx_28g_pll *pll;
-
- lynx_28g_cleanup_lane(lane);
-
- /* Enable the SXGMII lane */
- lynx_28g_rmw(priv, PCCC, PCCC_SXGMIInCFG_EN(lane) |
- PCCC_SXGMIInCFG_XFI(lane, 1), PCCC_MSK(lane));
-
- /* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0,
- FIELD_PREP(LNaGCR0_PROTO_SEL, LNaGCR0_PROTO_SEL_XFI) |
- FIELD_PREP(LNaGCR0_IF_WIDTH, LNaGCR0_IF_WIDTH_20_BIT),
- LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
-
- /* Find the PLL that works with this interface type */
- pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
- if (unlikely(pll == NULL))
- return;
-
- /* Switch to the PLL that works with this interface type */
- lynx_28g_lane_set_pll(lane, pll);
-
- /* Choose the portion of clock net to be used on this lane */
- lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
-
- /* Disable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, 0, SGMIIaCR1_SGPCS_EN);
-
- /* Configure the appropriate equalization parameters for the protocol */
- lynx_28g_lane_write(lane, LNaTECR0,
- FIELD_PREP(LNaTECR0_EQ_TYPE, EQ_TYPE_2TAP) |
- LNaTECR0_EQ_SGN_PREQ |
- FIELD_PREP(LNaTECR0_EQ_PREQ, 0) |
- LNaTECR0_EQ_SGN_POST1Q |
- FIELD_PREP(LNaTECR0_EQ_POST1Q, 3) |
- FIELD_PREP(LNaTECR0_EQ_AMP_RED, 7));
- lynx_28g_lane_write(lane, LNaRGCR1, LNaRGCR1_IDLE_CONFIG);
- lynx_28g_lane_write(lane, LNaRECR0, 0);
- lynx_28g_lane_write(lane, LNaRECR1, FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, 31));
- lynx_28g_lane_write(lane, LNaRECR2,
- LNaRECR2_EQ_OFFSET_RNG_DBL |
- FIELD_PREP(LNaRECR2_EQ_BLW_SEL, 1) |
- FIELD_PREP(LNaRECR2_EQ_BIN_DATA_AVG_TC, 2));
- lynx_28g_lane_write(lane, LNaRSCCR0,
- FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_D1R, 2));
-}
-
static int lynx_28g_power_off(struct phy *phy)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
@@ -503,6 +581,266 @@ static int lynx_28g_power_on(struct phy *phy)
return 0;
}
+static int lynx_28g_get_pccr(phy_interface_t interface, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ pccr->offset = PCC8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ pccr->offset = PCCC;
+ pccr->width = 4;
+ pccr->shift = SXGMII_CFG(lane);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int lynx_28g_get_pcvt_offset(int lane, phy_interface_t interface)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return SGMIIaCR0(lane);
+ case PHY_INTERFACE_MODE_10GBASER:
+ return SXGMIIaCR0(lane);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lynx_pccr_write(struct lynx_28g_lane *lane,
+ phy_interface_t interface, u32 val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_pccr pccr;
+ u32 old, tmp, mask;
+ int err;
+
+ err = lynx_28g_get_pccr(interface, lane->id, &pccr);
+ if (err)
+ return err;
+
+ old = lynx_28g_read(priv, pccr.offset);
+ mask = GENMASK(pccr.width - 1, 0) << pccr.shift;
+ tmp = (old & ~mask) | (val << pccr.shift);
+ lynx_28g_write(priv, pccr.offset, tmp);
+
+ dev_dbg(&lane->phy->dev, "PCCR@0x%x: 0x%x -> 0x%x\n",
+ pccr.offset, old, tmp);
+
+ return 0;
+}
+
+static int lynx_pcvt_read(struct lynx_28g_lane *lane, phy_interface_t interface,
+ int cr, u32 *val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ int offset;
+
+ offset = lynx_28g_get_pcvt_offset(lane->id, interface);
+ if (offset < 0)
+ return offset;
+
+ *val = lynx_28g_read(priv, offset + cr);
+
+ return 0;
+}
+
+static int lynx_pcvt_write(struct lynx_28g_lane *lane, phy_interface_t interface,
+ int cr, u32 val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ int offset;
+
+ offset = lynx_28g_get_pcvt_offset(lane->id, interface);
+ if (offset < 0)
+ return offset;
+
+ lynx_28g_write(priv, offset + cr, val);
+
+ return 0;
+}
+
+static int lynx_pcvt_rmw(struct lynx_28g_lane *lane, phy_interface_t interface,
+ int cr, u32 val, u32 mask)
+{
+ int err;
+ u32 tmp;
+
+ err = lynx_pcvt_read(lane, interface, cr, &tmp);
+ if (err)
+ return err;
+
+ tmp &= ~mask;
+ tmp |= val;
+
+ return lynx_pcvt_write(lane, interface, cr, tmp);
+}
+
+static void lynx_28g_lane_remap_pll(struct lynx_28g_lane *lane,
+ phy_interface_t interface)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_28g_pll *pll;
+
+ /* Switch to the PLL that works with this interface type */
+ pll = lynx_28g_pll_get(priv, interface);
+ if (unlikely(pll == NULL))
+ return;
+
+ lynx_28g_lane_set_pll(lane, pll);
+
+ /* Choose the portion of clock net to be used on this lane */
+ lynx_28g_lane_set_nrate(lane, pll, interface);
+}
+
+static void lynx_28g_lane_change_proto_conf(struct lynx_28g_lane *lane,
+ phy_interface_t interface)
+{
+ const struct lynx_28g_proto_conf *conf = &lynx_28g_proto_conf[interface];
+
+ lynx_28g_lane_rmw(lane, LNaGCR0, conf->proto_sel | conf->if_width,
+ LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
+
+ lynx_28g_lane_rmw(lane, LNaTECR0,
+ FIELD_PREP(LNaTECR0_EQ_TYPE, conf->teq_type) |
+ FIELD_PREP(LNaTECR0_EQ_SGN_PREQ, conf->sgn_preq) |
+ FIELD_PREP(LNaTECR0_EQ_PREQ, conf->ratio_preq) |
+ FIELD_PREP(LNaTECR0_EQ_SGN_POST1Q, conf->sgn_post1q) |
+ FIELD_PREP(LNaTECR0_EQ_POST1Q, conf->ratio_post1q) |
+ FIELD_PREP(LNaTECR0_EQ_AMP_RED, conf->amp_red),
+ LNaTECR0_EQ_TYPE |
+ LNaTECR0_EQ_SGN_PREQ |
+ LNaTECR0_EQ_PREQ |
+ LNaTECR0_EQ_SGN_POST1Q |
+ LNaTECR0_EQ_POST1Q |
+ LNaTECR0_EQ_AMP_RED);
+
+ lynx_28g_lane_rmw(lane, LNaTECR1,
+ FIELD_PREP(LNaTECR1_EQ_ADPT_EQ, conf->adpt_eq),
+ LNaTECR1_EQ_ADPT_EQ);
+
+ lynx_28g_lane_rmw(lane, LNaRGCR1,
+ FIELD_PREP(LNaRGCR1_ENTER_IDLE_FLT_SEL, conf->enter_idle_flt_sel) |
+ FIELD_PREP(LNaRGCR1_EXIT_IDLE_FLT_SEL, conf->exit_idle_flt_sel) |
+ FIELD_PREP(LNaRGCR1_DATA_LOST_TH_SEL, conf->data_lost_th_sel),
+ LNaRGCR1_ENTER_IDLE_FLT_SEL |
+ LNaRGCR1_EXIT_IDLE_FLT_SEL |
+ LNaRGCR1_DATA_LOST_TH_SEL);
+
+ lynx_28g_lane_rmw(lane, LNaRECR0,
+ FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV_EN, conf->gk2ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV_EN, conf->gk3ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV_EN, conf->gk4ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV, conf->gk2ovd) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV, conf->gk3ovd) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV, conf->gk4ovd),
+ LNaRECR0_EQ_GAINK2_HF_OV |
+ LNaRECR0_EQ_GAINK3_MF_OV |
+ LNaRECR0_EQ_GAINK4_LF_OV |
+ LNaRECR0_EQ_GAINK2_HF_OV_EN |
+ LNaRECR0_EQ_GAINK3_MF_OV_EN |
+ LNaRECR0_EQ_GAINK4_LF_OV_EN);
+
+ lynx_28g_lane_rmw(lane, LNaRECR1,
+ FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, conf->eq_offset_ovd) |
+ FIELD_PREP(LNaRECR1_EQ_OFFSET_OV_EN, conf->eq_offset_ovd_en),
+ LNaRECR1_EQ_OFFSET_OV |
+ LNaRECR1_EQ_OFFSET_OV_EN);
+
+ lynx_28g_lane_rmw(lane, LNaRECR2,
+ FIELD_PREP(LNaRECR2_EQ_OFFSET_RNG_DBL, conf->eq_offset_rng_dbl) |
+ FIELD_PREP(LNaRECR2_EQ_BLW_SEL, conf->eq_blw_sel) |
+ FIELD_PREP(LNaRECR2_EQ_BOOST, conf->eq_boost) |
+ FIELD_PREP(LNaRECR2_SPARE_IN, conf->spare_in),
+ LNaRECR2_EQ_OFFSET_RNG_DBL |
+ LNaRECR2_EQ_BLW_SEL |
+ LNaRECR2_EQ_BOOST |
+ LNaRECR2_SPARE_IN);
+
+ lynx_28g_lane_rmw(lane, LNaRSCCR0,
+ FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_D1R, conf->smp_autoz_d1r) |
+ FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_EG1R, conf->smp_autoz_eg1r),
+ LNaRSCCR0_SMP_AUTOZ_D1R |
+ LNaRSCCR0_SMP_AUTOZ_EG1R);
+}
+
+static int lynx_28g_lane_disable_pcvt(struct lynx_28g_lane *lane,
+ phy_interface_t interface)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ int err;
+
+ spin_lock(&priv->pcc_lock);
+
+ err = lynx_pccr_write(lane, interface, 0);
+ if (err)
+ goto out;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ err = lynx_pcvt_rmw(lane, interface, CR(1), 0,
+ SGMIIaCR1_SGPCS_EN);
+ break;
+ default:
+ err = 0;
+ }
+
+out:
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
+}
+
+static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
+ phy_interface_t interface)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ u32 val;
+ int err;
+
+ spin_lock(&priv->pcc_lock);
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ err = lynx_pcvt_rmw(lane, interface, CR(1), SGMIIaCR1_SGPCS_EN,
+ SGMIIaCR1_SGPCS_EN);
+ break;
+ default:
+ err = 0;
+ }
+
+ val = 0;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ val |= PCC8_SGMIIa_CFG;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ val |= PCCC_SXGMIIn_CFG | PCCC_SXGMIIn_XFI;
+ break;
+ default:
+ break;
+ }
+
+ err = lynx_pccr_write(lane, interface, val);
+
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
+}
+
static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
@@ -519,33 +857,26 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
if (!lynx_28g_supports_interface(priv, submode))
return -EOPNOTSUPP;
+ if (submode == lane->interface)
+ return 0;
+
/* If the lane is powered up, put the lane into the halt state while
* the reconfiguration is being done.
*/
if (powered_up)
lynx_28g_power_off(phy);
- spin_lock(&priv->pcc_lock);
-
- switch (submode) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_lane_set_sgmii(lane);
- break;
- case PHY_INTERFACE_MODE_10GBASER:
- lynx_28g_lane_set_10gbaser(lane);
- break;
- default:
- err = -EOPNOTSUPP;
+ err = lynx_28g_lane_disable_pcvt(lane, lane->interface);
+ if (err)
goto out;
- }
+
+ lynx_28g_lane_change_proto_conf(lane, submode);
+ lynx_28g_lane_remap_pll(lane, submode);
+ WARN_ON(lynx_28g_lane_enable_pcvt(lane, submode));
lane->interface = submode;
out:
- spin_unlock(&priv->pcc_lock);
-
- /* Power up the lane if necessary */
if (powered_up)
lynx_28g_power_on(phy);
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 07/14] phy: lynx-28g: refactor lane->interface to lane->mode
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (5 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 06/14] phy: lynx-28g: make lynx_28g_set_lane_mode() more systematic Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 08/14] phy: lynx-28g: distinguish between 10GBASE-R and USXGMII Vladimir Oltean
` (6 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
Lynx 28G is a multi-protocol SerDes - it handles serial Ethernet, PCIe,
SATA.
The driver should not use the phylib-specific phy_interface_t as an
internal data representation, but something specific to its internal
capabilities, and only convert to phy_interface_t when PHY_MODE_ETHERNET
is selected and used.
Otherwise it has no way of representing the non-Ethernet lanes (which
was not a short-term goal when the driver was introduced, and is not a
goal per se right now either, but should nonetheless be possible).
Prefer the "enum lynx_lane_mode" name over "lynx_28g_lane_mode", in
preparation of future Lynx 10G SerDes support. This SerDes is part of
the same IP family and has similar capabilities, and will reuse some
code, hence the common data type.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 202 ++++++++++++-----------
1 file changed, 103 insertions(+), 99 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index c483c2a80a77..5f1af4fdcb49 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -244,6 +244,13 @@ enum lynx_28g_proto_sel {
PROTO_SEL_25G_50G_100G = 0x1a,
};
+enum lynx_lane_mode {
+ LANE_MODE_UNKNOWN,
+ LANE_MODE_1000BASEX_SGMII,
+ LANE_MODE_10GBASER_USXGMII,
+ LANE_MODE_MAX,
+};
+
struct lynx_28g_proto_conf {
/* LNaGCR0 */
int proto_sel;
@@ -281,36 +288,8 @@ struct lynx_28g_proto_conf {
int smp_autoz_eg1r;
};
-static const struct lynx_28g_proto_conf lynx_28g_proto_conf[PHY_INTERFACE_MODE_MAX] = {
- [PHY_INTERFACE_MODE_SGMII] = {
- .proto_sel = LNaGCR0_PROTO_SEL_SGMII,
- .if_width = LNaGCR0_IF_WIDTH_10_BIT,
- .teq_type = EQ_TYPE_NO_EQ,
- .sgn_preq = 1,
- .ratio_preq = 0,
- .sgn_post1q = 1,
- .ratio_post1q = 0,
- .amp_red = 6,
- .adpt_eq = 48,
- .enter_idle_flt_sel = 4,
- .exit_idle_flt_sel = 3,
- .data_lost_th_sel = 1,
- .gk2ovd = 0x1f,
- .gk3ovd = 0,
- .gk4ovd = 0,
- .gk2ovd_en = 1,
- .gk3ovd_en = 1,
- .gk4ovd_en = 0,
- .eq_offset_ovd = 0x1f,
- .eq_offset_ovd_en = 0,
- .eq_offset_rng_dbl = 0,
- .eq_blw_sel = 0,
- .eq_boost = 0,
- .spare_in = 0,
- .smp_autoz_d1r = 0,
- .smp_autoz_eg1r = 0,
- },
- [PHY_INTERFACE_MODE_1000BASEX] = {
+static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
+ [LANE_MODE_1000BASEX_SGMII] = {
.proto_sel = LNaGCR0_PROTO_SEL_SGMII,
.if_width = LNaGCR0_IF_WIDTH_10_BIT,
.teq_type = EQ_TYPE_NO_EQ,
@@ -338,7 +317,7 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[PHY_INTERFACE_MODE_M
.smp_autoz_d1r = 0,
.smp_autoz_eg1r = 0,
},
- [PHY_INTERFACE_MODE_10GBASER] = {
+ [LANE_MODE_10GBASER_USXGMII] = {
.proto_sel = LNaGCR0_PROTO_SEL_XFI,
.if_width = LNaGCR0_IF_WIDTH_20_BIT,
.teq_type = EQ_TYPE_2TAP,
@@ -380,7 +359,7 @@ struct lynx_28g_pll {
struct lynx_28g_priv *priv;
u32 rstctl, cr0, cr1;
int id;
- DECLARE_PHY_INTERFACE_MASK(supported);
+ DECLARE_BITMAP(supported, LANE_MODE_MAX);
};
struct lynx_28g_lane {
@@ -389,7 +368,7 @@ struct lynx_28g_lane {
bool powered_up;
bool init;
unsigned int id;
- phy_interface_t interface;
+ enum lynx_lane_mode mode;
};
struct lynx_28g_priv {
@@ -430,7 +409,34 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
#define lynx_28g_pll_read(pll, reg) \
ioread32((pll)->priv->base + reg((pll)->id))
-static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
+static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return "1000Base-X/SGMII";
+ case LANE_MODE_10GBASER_USXGMII:
+ return "10GBase-R/USXGMII";
+ default:
+ return "unknown";
+ }
+}
+
+static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
+{
+ switch (intf) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LANE_MODE_1000BASEX_SGMII;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LANE_MODE_10GBASER_USXGMII;
+ default:
+ return LANE_MODE_UNKNOWN;
+ }
+}
+
+static bool lynx_28g_supports_lane_mode(struct lynx_28g_priv *priv,
+ enum lynx_lane_mode mode)
{
int i;
@@ -438,7 +444,7 @@ static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
if (PLLnRSTCTL_DIS(priv->pll[i].rstctl))
continue;
- if (test_bit(intf, priv->pll[i].supported))
+ if (test_bit(mode, priv->pll[i].supported))
return true;
}
@@ -446,7 +452,7 @@ static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
}
static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
- phy_interface_t intf)
+ enum lynx_lane_mode mode)
{
struct lynx_28g_pll *pll;
int i;
@@ -457,27 +463,27 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
- if (test_bit(intf, pll->supported))
+ if (test_bit(mode, pll->supported))
return pll;
}
/* no pll supports requested mode, either caller forgot to check
* lynx_28g_supports_lane_mode, or this is a bug.
*/
- dev_WARN_ONCE(priv->dev, 1, "no pll for interface %s\n", phy_modes(intf));
+ dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n",
+ lynx_lane_mode_str(mode));
return NULL;
}
static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll,
- phy_interface_t intf)
+ enum lynx_lane_mode lane_mode)
{
switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
- switch (intf) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
lynx_28g_lane_rmw(lane, LNaTGCR0,
FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_QUARTER),
LNaTGCR0_N_RATE);
@@ -490,9 +496,8 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
}
break;
case PLLnCR1_FRATE_10G_20GVCO:
- switch (intf) {
- case PHY_INTERFACE_MODE_10GBASER:
- case PHY_INTERFACE_MODE_USXGMII:
+ switch (lane_mode) {
+ case LANE_MODE_10GBASER_USXGMII:
lynx_28g_lane_rmw(lane, LNaTGCR0,
FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_FULL),
LNaTGCR0_N_RATE);
@@ -581,17 +586,16 @@ static int lynx_28g_power_on(struct phy *phy)
return 0;
}
-static int lynx_28g_get_pccr(phy_interface_t interface, int lane,
+static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
struct lynx_pccr *pccr)
{
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
pccr->offset = PCC8;
pccr->width = 4;
pccr->shift = SGMII_CFG(lane);
break;
- case PHY_INTERFACE_MODE_10GBASER:
+ case LANE_MODE_10GBASER_USXGMII:
pccr->offset = PCCC;
pccr->width = 4;
pccr->shift = SXGMII_CFG(lane);
@@ -603,13 +607,12 @@ static int lynx_28g_get_pccr(phy_interface_t interface, int lane,
return 0;
}
-static int lynx_28g_get_pcvt_offset(int lane, phy_interface_t interface)
+static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
{
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
return SGMIIaCR0(lane);
- case PHY_INTERFACE_MODE_10GBASER:
+ case LANE_MODE_10GBASER_USXGMII:
return SXGMIIaCR0(lane);
default:
return -EOPNOTSUPP;
@@ -617,14 +620,14 @@ static int lynx_28g_get_pcvt_offset(int lane, phy_interface_t interface)
}
static int lynx_pccr_write(struct lynx_28g_lane *lane,
- phy_interface_t interface, u32 val)
+ enum lynx_lane_mode lane_mode, u32 val)
{
struct lynx_28g_priv *priv = lane->priv;
struct lynx_pccr pccr;
u32 old, tmp, mask;
int err;
- err = lynx_28g_get_pccr(interface, lane->id, &pccr);
+ err = lynx_28g_get_pccr(lane_mode, lane->id, &pccr);
if (err)
return err;
@@ -639,13 +642,13 @@ static int lynx_pccr_write(struct lynx_28g_lane *lane,
return 0;
}
-static int lynx_pcvt_read(struct lynx_28g_lane *lane, phy_interface_t interface,
- int cr, u32 *val)
+static int lynx_pcvt_read(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, int cr, u32 *val)
{
struct lynx_28g_priv *priv = lane->priv;
int offset;
- offset = lynx_28g_get_pcvt_offset(lane->id, interface);
+ offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode);
if (offset < 0)
return offset;
@@ -654,13 +657,13 @@ static int lynx_pcvt_read(struct lynx_28g_lane *lane, phy_interface_t interface,
return 0;
}
-static int lynx_pcvt_write(struct lynx_28g_lane *lane, phy_interface_t interface,
- int cr, u32 val)
+static int lynx_pcvt_write(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, int cr, u32 val)
{
struct lynx_28g_priv *priv = lane->priv;
int offset;
- offset = lynx_28g_get_pcvt_offset(lane->id, interface);
+ offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode);
if (offset < 0)
return offset;
@@ -669,43 +672,44 @@ static int lynx_pcvt_write(struct lynx_28g_lane *lane, phy_interface_t interface
return 0;
}
-static int lynx_pcvt_rmw(struct lynx_28g_lane *lane, phy_interface_t interface,
+static int lynx_pcvt_rmw(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode,
int cr, u32 val, u32 mask)
{
int err;
u32 tmp;
- err = lynx_pcvt_read(lane, interface, cr, &tmp);
+ err = lynx_pcvt_read(lane, lane_mode, cr, &tmp);
if (err)
return err;
tmp &= ~mask;
tmp |= val;
- return lynx_pcvt_write(lane, interface, cr, tmp);
+ return lynx_pcvt_write(lane, lane_mode, cr, tmp);
}
static void lynx_28g_lane_remap_pll(struct lynx_28g_lane *lane,
- phy_interface_t interface)
+ enum lynx_lane_mode lane_mode)
{
struct lynx_28g_priv *priv = lane->priv;
struct lynx_28g_pll *pll;
/* Switch to the PLL that works with this interface type */
- pll = lynx_28g_pll_get(priv, interface);
+ pll = lynx_28g_pll_get(priv, lane_mode);
if (unlikely(pll == NULL))
return;
lynx_28g_lane_set_pll(lane, pll);
/* Choose the portion of clock net to be used on this lane */
- lynx_28g_lane_set_nrate(lane, pll, interface);
+ lynx_28g_lane_set_nrate(lane, pll, lane_mode);
}
static void lynx_28g_lane_change_proto_conf(struct lynx_28g_lane *lane,
- phy_interface_t interface)
+ enum lynx_lane_mode lane_mode)
{
- const struct lynx_28g_proto_conf *conf = &lynx_28g_proto_conf[interface];
+ const struct lynx_28g_proto_conf *conf = &lynx_28g_proto_conf[lane_mode];
lynx_28g_lane_rmw(lane, LNaGCR0, conf->proto_sel | conf->if_width,
LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
@@ -774,21 +778,20 @@ static void lynx_28g_lane_change_proto_conf(struct lynx_28g_lane *lane,
}
static int lynx_28g_lane_disable_pcvt(struct lynx_28g_lane *lane,
- phy_interface_t interface)
+ enum lynx_lane_mode lane_mode)
{
struct lynx_28g_priv *priv = lane->priv;
int err;
spin_lock(&priv->pcc_lock);
- err = lynx_pccr_write(lane, interface, 0);
+ err = lynx_pccr_write(lane, lane_mode, 0);
if (err)
goto out;
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- err = lynx_pcvt_rmw(lane, interface, CR(1), 0,
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ err = lynx_pcvt_rmw(lane, lane_mode, CR(1), 0,
SGMIIaCR1_SGPCS_EN);
break;
default:
@@ -802,7 +805,7 @@ static int lynx_28g_lane_disable_pcvt(struct lynx_28g_lane *lane,
}
static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
- phy_interface_t interface)
+ enum lynx_lane_mode lane_mode)
{
struct lynx_28g_priv *priv = lane->priv;
u32 val;
@@ -810,10 +813,9 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
spin_lock(&priv->pcc_lock);
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- err = lynx_pcvt_rmw(lane, interface, CR(1), SGMIIaCR1_SGPCS_EN,
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ err = lynx_pcvt_rmw(lane, lane_mode, CR(1), SGMIIaCR1_SGPCS_EN,
SGMIIaCR1_SGPCS_EN);
break;
default:
@@ -822,19 +824,18 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
val = 0;
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
val |= PCC8_SGMIIa_CFG;
break;
- case PHY_INTERFACE_MODE_10GBASER:
+ case LANE_MODE_10GBASER_USXGMII:
val |= PCCC_SXGMIIn_CFG | PCCC_SXGMIIn_XFI;
break;
default:
break;
}
- err = lynx_pccr_write(lane, interface, val);
+ err = lynx_pccr_write(lane, lane_mode, val);
spin_unlock(&priv->pcc_lock);
@@ -846,18 +847,21 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
struct lynx_28g_priv *priv = lane->priv;
int powered_up = lane->powered_up;
+ enum lynx_lane_mode lane_mode;
int err = 0;
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
- if (lane->interface == PHY_INTERFACE_MODE_NA)
+ if (lane->mode == LANE_MODE_UNKNOWN)
return -EOPNOTSUPP;
- if (!lynx_28g_supports_interface(priv, submode))
+ lane_mode = phy_interface_to_lane_mode(submode);
+
+ if (!lynx_28g_supports_lane_mode(priv, lane_mode))
return -EOPNOTSUPP;
- if (submode == lane->interface)
+ if (submode == lane->mode)
return 0;
/* If the lane is powered up, put the lane into the halt state while
@@ -866,7 +870,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
if (powered_up)
lynx_28g_power_off(phy);
- err = lynx_28g_lane_disable_pcvt(lane, lane->interface);
+ err = lynx_28g_lane_disable_pcvt(lane, lane->mode);
if (err)
goto out;
@@ -874,7 +878,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
lynx_28g_lane_remap_pll(lane, submode);
WARN_ON(lynx_28g_lane_enable_pcvt(lane, submode));
- lane->interface = submode;
+ lane->mode = lane_mode;
out:
if (powered_up)
@@ -892,7 +896,8 @@ static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
- if (!lynx_28g_supports_interface(priv, submode))
+ if (!lynx_28g_supports_lane_mode(priv,
+ phy_interface_to_lane_mode(submode)))
return -EOPNOTSUPP;
return 0;
@@ -945,12 +950,11 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
/* 5GHz clock net */
- __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
- __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
+ __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported);
break;
case PLLnCR1_FRATE_10G_20GVCO:
/* 10.3125GHz clock net */
- __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
+ __set_bit(LANE_MODE_10GBASER_USXGMII, pll->supported);
break;
default:
/* 6GHz, 12.890625GHz, 8GHz */
@@ -1001,13 +1005,13 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
protocol = FIELD_GET(LNaPSS_TYPE, pss);
switch (protocol) {
case LNaPSS_TYPE_SGMII:
- lane->interface = PHY_INTERFACE_MODE_SGMII;
+ lane->mode = LANE_MODE_1000BASEX_SGMII;
break;
case LNaPSS_TYPE_XFI:
- lane->interface = PHY_INTERFACE_MODE_10GBASER;
+ lane->mode = LANE_MODE_10GBASER_USXGMII;
break;
default:
- lane->interface = PHY_INTERFACE_MODE_NA;
+ lane->mode = LANE_MODE_UNKNOWN;
}
}
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 08/14] phy: lynx-28g: distinguish between 10GBASE-R and USXGMII
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (6 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 07/14] phy: lynx-28g: refactor lane->interface to lane->mode Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 09/14] phy: lynx-28g: configure more equalization params for 1GbE and 10GbE Vladimir Oltean
` (5 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
The driver does not handle well protocol switching to or from USXGMII,
because it conflates it with 10GBase-R.
In the expected USXGMII use case, that isn't a problem, because SerDes
protocol switching performed by the lynx-28g driver is not necessary,
because USXGMII natively supports multiple speeds, as opposed to SFP
modules using 1000Base-X or 10GBase-R which require switching between
the 2.
That being said, let's be explicit, and in case someone requests a
protocol change which involves USXGMII, let's do the right thing.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 87 ++++++++++++++++++++----
1 file changed, 74 insertions(+), 13 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 5f1af4fdcb49..49e9ea82106f 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -247,7 +247,8 @@ enum lynx_28g_proto_sel {
enum lynx_lane_mode {
LANE_MODE_UNKNOWN,
LANE_MODE_1000BASEX_SGMII,
- LANE_MODE_10GBASER_USXGMII,
+ LANE_MODE_10GBASER,
+ LANE_MODE_USXGMII,
LANE_MODE_MAX,
};
@@ -317,7 +318,35 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
.smp_autoz_d1r = 0,
.smp_autoz_eg1r = 0,
},
- [LANE_MODE_10GBASER_USXGMII] = {
+ [LANE_MODE_USXGMII] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_XFI,
+ .if_width = LNaGCR0_IF_WIDTH_20_BIT,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 3,
+ .amp_red = 7,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 0,
+ },
+ [LANE_MODE_10GBASER] = {
.proto_sel = LNaGCR0_PROTO_SEL_XFI,
.if_width = LNaGCR0_IF_WIDTH_20_BIT,
.teq_type = EQ_TYPE_2TAP,
@@ -414,8 +443,10 @@ static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
switch (lane_mode) {
case LANE_MODE_1000BASEX_SGMII:
return "1000Base-X/SGMII";
- case LANE_MODE_10GBASER_USXGMII:
- return "10GBase-R/USXGMII";
+ case LANE_MODE_10GBASER:
+ return "10GBase-R";
+ case LANE_MODE_USXGMII:
+ return "USXGMII";
default:
return "unknown";
}
@@ -428,8 +459,9 @@ static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
case PHY_INTERFACE_MODE_1000BASEX:
return LANE_MODE_1000BASEX_SGMII;
case PHY_INTERFACE_MODE_10GBASER:
+ return LANE_MODE_10GBASER;
case PHY_INTERFACE_MODE_USXGMII:
- return LANE_MODE_10GBASER_USXGMII;
+ return LANE_MODE_USXGMII;
default:
return LANE_MODE_UNKNOWN;
}
@@ -497,7 +529,8 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
break;
case PLLnCR1_FRATE_10G_20GVCO:
switch (lane_mode) {
- case LANE_MODE_10GBASER_USXGMII:
+ case LANE_MODE_10GBASER:
+ case LANE_MODE_USXGMII:
lynx_28g_lane_rmw(lane, LNaTGCR0,
FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_FULL),
LNaTGCR0_N_RATE);
@@ -595,7 +628,8 @@ static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
pccr->width = 4;
pccr->shift = SGMII_CFG(lane);
break;
- case LANE_MODE_10GBASER_USXGMII:
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
pccr->offset = PCCC;
pccr->width = 4;
pccr->shift = SXGMII_CFG(lane);
@@ -612,13 +646,32 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
switch (lane_mode) {
case LANE_MODE_1000BASEX_SGMII:
return SGMIIaCR0(lane);
- case LANE_MODE_10GBASER_USXGMII:
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
return SXGMIIaCR0(lane);
default:
return -EOPNOTSUPP;
}
}
+static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode,
+ u32 *val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_pccr pccr;
+ u32 tmp;
+ int err;
+
+ err = lynx_28g_get_pccr(mode, lane->id, &pccr);
+ if (err)
+ return err;
+
+ tmp = lynx_28g_read(priv, pccr.offset);
+ *val = (tmp >> pccr.shift) & GENMASK(pccr.width - 1, 0);
+
+ return 0;
+}
+
static int lynx_pccr_write(struct lynx_28g_lane *lane,
enum lynx_lane_mode lane_mode, u32 val)
{
@@ -828,8 +881,11 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
case LANE_MODE_1000BASEX_SGMII:
val |= PCC8_SGMIIa_CFG;
break;
- case LANE_MODE_10GBASER_USXGMII:
- val |= PCCC_SXGMIIn_CFG | PCCC_SXGMIIn_XFI;
+ case LANE_MODE_10GBASER:
+ val |= PCCC_SXGMIIn_XFI;
+ fallthrough;
+ case LANE_MODE_USXGMII:
+ val |= PCCC_SXGMIIn_CFG;
break;
default:
break;
@@ -954,7 +1010,8 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
break;
case PLLnCR1_FRATE_10G_20GVCO:
/* 10.3125GHz clock net */
- __set_bit(LANE_MODE_10GBASER_USXGMII, pll->supported);
+ __set_bit(LANE_MODE_10GBASER, pll->supported);
+ __set_bit(LANE_MODE_USXGMII, pll->supported);
break;
default:
/* 6GHz, 12.890625GHz, 8GHz */
@@ -999,7 +1056,7 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
{
- u32 pss, protocol;
+ u32 pccr, pss, protocol;
pss = lynx_28g_lane_read(lane, LNaPSS);
protocol = FIELD_GET(LNaPSS_TYPE, pss);
@@ -1008,7 +1065,11 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
lane->mode = LANE_MODE_1000BASEX_SGMII;
break;
case LNaPSS_TYPE_XFI:
- lane->mode = LANE_MODE_10GBASER_USXGMII;
+ lynx_pccr_read(lane, LANE_MODE_10GBASER, &pccr);
+ if (pccr & PCCC_SXGMIIn_XFI)
+ lane->mode = LANE_MODE_10GBASER;
+ else
+ lane->mode = LANE_MODE_USXGMII;
break;
default:
lane->mode = LANE_MODE_UNKNOWN;
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 09/14] phy: lynx-28g: configure more equalization params for 1GbE and 10GbE
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (7 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 08/14] phy: lynx-28g: distinguish between 10GBASE-R and USXGMII Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 10/14] phy: lynx-28g: add support for 25GBASER Vladimir Oltean
` (4 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
From: Ioana Ciornei <ioana.ciornei@nxp.com>
While adding support for 25GbE, it was noticed that the RCCR0 and TTLCR0
registers have different values for this protocol than the 10GbE and
1GbE modes.
Expand the lynx_28g_proto_conf[] array with the expected values for the
currently supported protocols. These were dumped from a live system, and
are the out-of-reset values. It will ensure that the lane is configured
with these values when transitioning from 25GbE back into one of these
modes.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 37 ++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 49e9ea82106f..1a8751e79898 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -166,6 +166,18 @@
#define LNaRECR4_EQ_BIN_DATA GENMASK(8, 0) /* bit 9 is reserved */
#define LNaRECR4_EQ_BIN_DATA_SGN BIT(8)
+#define LNaRCCR0(lane) (0x800 + (lane) * 0x100 + 0x68)
+#define LNaRCCR0_CAL_EN BIT(31)
+#define LNaRCCR0_MEAS_EN BIT(30)
+#define LNaRCCR0_CAL_BIN_SEL BIT(28)
+#define LNaRCCR0_CAL_DC3_DIS BIT(27)
+#define LNaRCCR0_CAL_DC2_DIS BIT(26)
+#define LNaRCCR0_CAL_DC1_DIS BIT(25)
+#define LNaRCCR0_CAL_DC0_DIS BIT(24)
+#define LNaRCCR0_CAL_AC3_OV_EN BIT(15)
+#define LNaRCCR0_CAL_AC3_OV GENMASK(11, 8)
+#define LNaRCCR0_CAL_AC2_OV_EN BIT(7)
+
#define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
#define LNaRSCCR0_SMP_OFF_EN BIT(31)
#define LNaRSCCR0_SMP_OFF_OV_EN BIT(30)
@@ -181,6 +193,15 @@
#define LNaRSCCR0_SMP_AUTOZ_EG1R GENMASK(5, 4)
#define LNaRSCCR0_SMP_AUTOZ_EG1F GENMASK(1, 0)
+#define LNaTTLCR0(lane) (0x800 + (lane) * 0x100 + 0x80)
+#define LNaTTLCR0_TTL_FLT_SEL GENMASK(29, 24)
+#define LNaTTLCR0_TTL_SLO_PM_BYP BIT(22)
+#define LNaTTLCR0_STALL_DET_DIS BIT(21)
+#define LNaTTLCR0_INACT_MON_DIS BIT(20)
+#define LNaTTLCR0_CDR_OV GENMASK(18, 16)
+#define LNaTTLCR0_DATA_IN_SSC BIT(15)
+#define LNaTTLCR0_CDR_MIN_SMP_ON GENMASK(1, 0)
+
#define LNaTCSR0(lane) (0x800 + (lane) * 0x100 + 0xa0)
#define LNaTCSR0_SD_STAT_OBS_EN BIT(31)
#define LNaTCSR0_SD_LPBK_SEL GENMASK(29, 28)
@@ -287,6 +308,10 @@ struct lynx_28g_proto_conf {
/* LNaRSCCR0 */
int smp_autoz_d1r;
int smp_autoz_eg1r;
+ /* LNaRCCR0 */
+ int rccr0;
+ /* LNaTTLCR0 */
+ int ttlcr0;
};
static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
@@ -317,6 +342,9 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
.spare_in = 0,
.smp_autoz_d1r = 0,
.smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
},
[LANE_MODE_USXGMII] = {
.proto_sel = LNaGCR0_PROTO_SEL_XFI,
@@ -345,6 +373,9 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
.spare_in = 0,
.smp_autoz_d1r = 2,
.smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
},
[LANE_MODE_10GBASER] = {
.proto_sel = LNaGCR0_PROTO_SEL_XFI,
@@ -373,6 +404,9 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
.spare_in = 0,
.smp_autoz_d1r = 2,
.smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
},
};
@@ -828,6 +862,9 @@ static void lynx_28g_lane_change_proto_conf(struct lynx_28g_lane *lane,
FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_EG1R, conf->smp_autoz_eg1r),
LNaRSCCR0_SMP_AUTOZ_D1R |
LNaRSCCR0_SMP_AUTOZ_EG1R);
+
+ lynx_28g_lane_write(lane, LNaRCCR0, conf->rccr0);
+ lynx_28g_lane_write(lane, LNaTTLCR0, conf->ttlcr0);
}
static int lynx_28g_lane_disable_pcvt(struct lynx_28g_lane *lane,
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 10/14] phy: lynx-28g: add support for 25GBASER
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (8 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 09/14] phy: lynx-28g: configure more equalization params for 1GbE and 10GbE Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 11/14] phy: lynx-28g: truly power the lanes up or down Vladimir Oltean
` (3 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
From: Ioana Ciornei <ioana.ciornei@nxp.com>
Add support for 25GBASE-R in the Lynx 28G SerDes PHY driver.
This mainly means being able to determine if a PLL is able to support
the new interface type, to determine at probe time if a lane is
configured from the Reset Configuration Word (RCW) with this interface
type and to be able to reconfigure a lane.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 83 +++++++++++++++++++++++-
1 file changed, 82 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 1a8751e79898..08553ffe273f 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -57,6 +57,7 @@
#define PLLnCR1_FRATE_5G_10GVCO 0x0
#define PLLnCR1_FRATE_5G_25GVCO 0x10
#define PLLnCR1_FRATE_10G_20GVCO 0x6
+#define PLLnCR1_FRATE_12G_25GVCO 0x16
/* Per SerDes lane registers */
/* Lane a General Control Register */
@@ -64,9 +65,11 @@
#define LNaGCR0_PROTO_SEL GENMASK(7, 3)
#define LNaGCR0_PROTO_SEL_SGMII 0x1
#define LNaGCR0_PROTO_SEL_XFI 0xa
+#define LNaGCR0_PROTO_SEL_25G 0x1a
#define LNaGCR0_IF_WIDTH GENMASK(2, 0)
#define LNaGCR0_IF_WIDTH_10_BIT 0x0
#define LNaGCR0_IF_WIDTH_20_BIT 0x2
+#define LNaGCR0_IF_WIDTH_40_BIT 0x4
/* Lane a Tx Reset Control Register */
#define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
@@ -83,6 +86,7 @@
#define LNaTGCR0_N_RATE_FULL 0x0
#define LNaTGCR0_N_RATE_HALF 0x1
#define LNaTGCR0_N_RATE_QUARTER 0x2
+#define LNaTGCR0_N_RATE_DOUBLE 0x3
#define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
#define LNaTECR0_EQ_TYPE GENMASK(30, 28)
@@ -112,6 +116,7 @@
#define LNaRGCR0_N_RATE_FULL 0x0
#define LNaRGCR0_N_RATE_HALF 0x1
#define LNaRGCR0_N_RATE_QUARTER 0x2
+#define LNaRGCR0_N_RATE_DOUBLE 0x3
#define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
#define LNaRGCR1_RX_ORD_ELECIDLE BIT(31)
@@ -270,6 +275,7 @@ enum lynx_lane_mode {
LANE_MODE_1000BASEX_SGMII,
LANE_MODE_10GBASER,
LANE_MODE_USXGMII,
+ LANE_MODE_25GBASER,
LANE_MODE_MAX,
};
@@ -408,6 +414,41 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
.ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
LNaTTLCR0_DATA_IN_SSC,
},
+ [LANE_MODE_25GBASER] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_25G,
+ .if_width = LNaGCR0_IF_WIDTH_40_BIT,
+ .teq_type = EQ_TYPE_3TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 2,
+ .sgn_post1q = 1,
+ .ratio_post1q = 7,
+ .amp_red = 0,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 5,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 1,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 2,
+ .spare_in = 3,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 2,
+ .rccr0 = LNaRCCR0_CAL_EN |
+ LNaRCCR0_CAL_DC3_DIS |
+ LNaRCCR0_CAL_DC2_DIS |
+ LNaRCCR0_CAL_DC1_DIS |
+ LNaRCCR0_CAL_DC0_DIS,
+ .ttlcr0 = LNaTTLCR0_DATA_IN_SSC |
+ FIELD_PREP_CONST(LNaTTLCR0_CDR_MIN_SMP_ON, 1),
+ },
};
struct lynx_pccr {
@@ -481,6 +522,8 @@ static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
return "10GBase-R";
case LANE_MODE_USXGMII:
return "USXGMII";
+ case LANE_MODE_25GBASER:
+ return "25GBase-R";
default:
return "unknown";
}
@@ -496,6 +539,8 @@ static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
return LANE_MODE_10GBASER;
case PHY_INTERFACE_MODE_USXGMII:
return LANE_MODE_USXGMII;
+ case PHY_INTERFACE_MODE_25GBASER:
+ return LANE_MODE_25GBASER;
default:
return LANE_MODE_UNKNOWN;
}
@@ -576,6 +621,20 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
break;
}
break;
+ case PLLnCR1_FRATE_12G_25GVCO:
+ switch (lane_mode) {
+ case LANE_MODE_25GBASER:
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_DOUBLE),
+ LNaTGCR0_N_RATE);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_DOUBLE),
+ LNaRGCR0_N_RATE);
+ break;
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -653,6 +712,11 @@ static int lynx_28g_power_on(struct phy *phy)
return 0;
}
+static int lynx_28g_e25g_pcvt(int lane)
+{
+ return 7 - lane;
+}
+
static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
struct lynx_pccr *pccr)
{
@@ -668,6 +732,11 @@ static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
pccr->width = 4;
pccr->shift = SXGMII_CFG(lane);
break;
+ case LANE_MODE_25GBASER:
+ pccr->offset = PCCD;
+ pccr->width = 4;
+ pccr->shift = E25G_CFG(lynx_28g_e25g_pcvt(lane));
+ break;
default:
return -EOPNOTSUPP;
}
@@ -683,6 +752,8 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
case LANE_MODE_USXGMII:
case LANE_MODE_10GBASER:
return SXGMIIaCR0(lane);
+ case LANE_MODE_25GBASER:
+ return E25GaCR0(lynx_28g_e25g_pcvt(lane));
default:
return -EOPNOTSUPP;
}
@@ -924,6 +995,9 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
case LANE_MODE_USXGMII:
val |= PCCC_SXGMIIn_CFG;
break;
+ case LANE_MODE_25GBASER:
+ val |= PCCD_E25Gn_CFG;
+ break;
default:
break;
}
@@ -1050,8 +1124,12 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
__set_bit(LANE_MODE_10GBASER, pll->supported);
__set_bit(LANE_MODE_USXGMII, pll->supported);
break;
+ case PLLnCR1_FRATE_12G_25GVCO:
+ /* 12.890625GHz clock net */
+ __set_bit(LANE_MODE_25GBASER, pll->supported);
+ break;
default:
- /* 6GHz, 12.890625GHz, 8GHz */
+ /* 6GHz, 8GHz */
break;
}
}
@@ -1108,6 +1186,9 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
else
lane->mode = LANE_MODE_USXGMII;
break;
+ case LNaPSS_TYPE_25G:
+ lane->mode = LANE_MODE_25GBASER;
+ break;
default:
lane->mode = LANE_MODE_UNKNOWN;
}
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 11/14] phy: lynx-28g: truly power the lanes up or down
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (9 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 10/14] phy: lynx-28g: add support for 25GBASER Vladimir Oltean
@ 2025-09-04 15:43 ` Vladimir Oltean
2025-09-04 15:44 ` [PATCH phy 12/14] phy: lynx-28g: implement phy_exit() operation Vladimir Oltean
` (2 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:43 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
The current procedure for power_off() and power_on() is the same as the
one used for major lane reconfiguration, aka halting. But one can
observe that a halted lane does not cause, for example, the CDR loop of
the link partner to lose lock on its RX stream.
Implement the procedure mentioned in the block guide for powering down
a lane, and then back on.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 78 ++++++++++++++++++------
1 file changed, 60 insertions(+), 18 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 08553ffe273f..5055ddba0363 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -73,9 +73,11 @@
/* Lane a Tx Reset Control Register */
#define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
-#define LNaTRSTCTL_HLT_REQ BIT(27)
-#define LNaTRSTCTL_RST_DONE BIT(30)
#define LNaTRSTCTL_RST_REQ BIT(31)
+#define LNaTRSTCTL_RST_DONE BIT(30)
+#define LNaTRSTCTL_HLT_REQ BIT(27)
+#define LNaTRSTCTL_STP_REQ BIT(26)
+#define LNaTRSTCTL_DIS BIT(24)
/* Lane a Tx General Control Register */
#define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
@@ -102,9 +104,11 @@
/* Lane a Rx Reset Control Register */
#define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
-#define LNaRRSTCTL_HLT_REQ BIT(27)
-#define LNaRRSTCTL_RST_DONE BIT(30)
#define LNaRRSTCTL_RST_REQ BIT(31)
+#define LNaRRSTCTL_RST_DONE BIT(30)
+#define LNaRRSTCTL_HLT_REQ BIT(27)
+#define LNaRRSTCTL_STP_REQ BIT(26)
+#define LNaRRSTCTL_DIS BIT(24)
#define LNaRRSTCTL_CDR_LOCK BIT(12)
/* Lane a Rx General Control Register */
@@ -660,14 +664,12 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
}
}
-static int lynx_28g_power_off(struct phy *phy)
+/* Halting puts the lane in a mode in which it can be reconfigured */
+static void lynx_28g_lane_halt(struct phy *phy)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
u32 trstctl, rrstctl;
- if (!lane->powered_up)
- return 0;
-
/* Issue a halt request */
lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ,
LNaTRSTCTL_HLT_REQ);
@@ -680,20 +682,13 @@ static int lynx_28g_power_off(struct phy *phy)
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
} while ((trstctl & LNaTRSTCTL_HLT_REQ) ||
(rrstctl & LNaRRSTCTL_HLT_REQ));
-
- lane->powered_up = false;
-
- return 0;
}
-static int lynx_28g_power_on(struct phy *phy)
+static void lynx_28g_lane_reset(struct phy *phy)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
u32 trstctl, rrstctl;
- if (lane->powered_up)
- return 0;
-
/* Issue a reset request on the lane */
lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ,
LNaTRSTCTL_RST_REQ);
@@ -706,6 +701,52 @@ static int lynx_28g_power_on(struct phy *phy)
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
} while (!(trstctl & LNaTRSTCTL_RST_DONE) ||
!(rrstctl & LNaRRSTCTL_RST_DONE));
+}
+
+static int lynx_28g_power_off(struct phy *phy)
+{
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+ u32 trstctl, rrstctl;
+
+ if (!lane->powered_up)
+ return 0;
+
+ /* Issue a stop request */
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_STP_REQ,
+ LNaTRSTCTL_STP_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_STP_REQ,
+ LNaRRSTCTL_STP_REQ);
+
+ /* Wait until the stop process is complete */
+ do {
+ trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
+ rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
+ } while ((trstctl & LNaTRSTCTL_STP_REQ) ||
+ (rrstctl & LNaRRSTCTL_STP_REQ));
+
+ /* Power down the RX and TX portions of the lane */
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_DIS,
+ LNaRRSTCTL_DIS);
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_DIS,
+ LNaTRSTCTL_DIS);
+
+ lane->powered_up = false;
+
+ return 0;
+}
+
+static int lynx_28g_power_on(struct phy *phy)
+{
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+
+ if (lane->powered_up)
+ return 0;
+
+ /* Power up the RX and TX portions of the lane */
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, 0, LNaRRSTCTL_DIS);
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, 0, LNaTRSTCTL_DIS);
+
+ lynx_28g_lane_reset(phy);
lane->powered_up = true;
@@ -1035,7 +1076,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
* the reconfiguration is being done.
*/
if (powered_up)
- lynx_28g_power_off(phy);
+ lynx_28g_lane_halt(phy);
err = lynx_28g_lane_disable_pcvt(lane, lane->mode);
if (err)
@@ -1048,8 +1089,9 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
lane->mode = lane_mode;
out:
+ /* Reset the lane if necessary */
if (powered_up)
- lynx_28g_power_on(phy);
+ lynx_28g_lane_reset(phy);
return err;
}
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 12/14] phy: lynx-28g: implement phy_exit() operation
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (10 preceding siblings ...)
2025-09-04 15:43 ` [PATCH phy 11/14] phy: lynx-28g: truly power the lanes up or down Vladimir Oltean
@ 2025-09-04 15:44 ` Vladimir Oltean
2025-09-04 15:44 ` [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
2025-09-04 15:44 ` [PATCH phy 14/14] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Vladimir Oltean
13 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:44 UTC (permalink / raw)
To: linux-phy; +Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel
Managed lanes are supposed to have power management through
phy_power_on() and phy_power_off().
Unmanaged lanes are supposed to be always powered on, because they might
have a consumer which doesn't use this SerDes driver, and we don't want
to break it.
A lane is initially unmanaged, and becomes managed when phy_init() is
called on it.
It is normal for consumer drivers to call both phy_init() and
phy_exit(), in a balanced way. This ensures the phy->init_count from the
phy core is brought back to zero, for example during -EPROBE_DEFER in
the consumer, the lane temporarily becomes unmanaged and then managed
again.
Given the above requirement for consumers, it also imposes a requirement
for the SerDes driver to implement the exit() operation. Otherwise, a
balanced set of phy_init() and phy_exit() calls from the consumer will
effectively result in multiple lynx_28g_init() calls as seen by the
SerDes and nothing else. That actually doesn't work - the driver can't
power down a SerDes lane which is actually powered down, so such a call
sequence would hang the kernel.
No consumer driver currently uses phy_exit(), so the above problem does
not yet trigger, but in preparation for its introduction, it is
necessary to add lynx_28g_exit() as the mirror of lynx_28g_init().
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 5055ddba0363..91a3b3928ab4 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1129,8 +1129,24 @@ static int lynx_28g_init(struct phy *phy)
return 0;
}
+static int lynx_28g_exit(struct phy *phy)
+{
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+
+ /* The lane returns to the state where it isn't managed by the
+ * consumer, so we must treat is as if it isn't initialized, and always
+ * powered on.
+ */
+ lane->init = false;
+ lane->powered_up = false;
+ lynx_28g_power_on(phy);
+
+ return 0;
+}
+
static const struct phy_ops lynx_28g_ops = {
.init = lynx_28g_init,
+ .exit = lynx_28g_exit,
.power_on = lynx_28g_power_on,
.power_off = lynx_28g_power_off,
.set_mode = lynx_28g_set_mode,
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (11 preceding siblings ...)
2025-09-04 15:44 ` [PATCH phy 12/14] phy: lynx-28g: implement phy_exit() operation Vladimir Oltean
@ 2025-09-04 15:44 ` Vladimir Oltean
2025-09-04 19:22 ` Conor Dooley
2025-09-05 8:29 ` Krzysztof Kozlowski
2025-09-04 15:44 ` [PATCH phy 14/14] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Vladimir Oltean
13 siblings, 2 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:44 UTC (permalink / raw)
To: linux-phy
Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree
Going by the generic "fsl,lynx-28g" compatible string and expecting all
SerDes instantiations on all SoCs to use it was a mistake.
They all share the same register map, sure, but the number of protocol
converters and lanes which are instantiated differs in a way that isn't
detectable by software. So distinguish them by compatible strings.
At the same time, keep "fsl,lynx-28g" as backup.
Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
.../devicetree/bindings/phy/fsl,lynx-28g.yaml | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
index ff9f9ca0f19c..55d773c8d0e4 100644
--- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
+++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
@@ -11,8 +11,17 @@ maintainers:
properties:
compatible:
- enum:
- - fsl,lynx-28g
+ oneOf:
+ - items:
+ - const: fsl,lynx-28g
+ - items:
+ - enum:
+ - fsl,lx2160a-serdes1
+ - fsl,lx2160a-serdes2
+ - fsl,lx2160a-serdes3
+ - fsl,lx2162a-serdes1
+ - fsl,lx2162a-serdes2
+ - const: fsl,lynx-28g
reg:
maxItems: 1
@@ -33,7 +42,7 @@ examples:
#address-cells = <2>;
#size-cells = <2>;
serdes_1: phy@1ea0000 {
- compatible = "fsl,lynx-28g";
+ compatible = "fsl,lx2160a-serdes1", "fsl,lynx-28g";
reg = <0x0 0x1ea0000 0x0 0x1e30>;
#phy-cells = <1>;
};
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-04 15:44 ` [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
@ 2025-09-04 19:22 ` Conor Dooley
2025-09-05 10:49 ` Vladimir Oltean
2025-09-05 8:29 ` Krzysztof Kozlowski
1 sibling, 1 reply; 40+ messages in thread
From: Conor Dooley @ 2025-09-04 19:22 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree
[-- Attachment #1.1: Type: text/plain, Size: 2218 bytes --]
On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
> Going by the generic "fsl,lynx-28g" compatible string and expecting all
> SerDes instantiations on all SoCs to use it was a mistake.
>
> They all share the same register map, sure, but the number of protocol
> converters and lanes which are instantiated differs in a way that isn't
> detectable by software. So distinguish them by compatible strings.
> At the same time, keep "fsl,lynx-28g" as backup.
Why keep the backup? Doesn't sound like you can use it for anything,
unless there's some minimum set of capabilities that all devices
support. If that's not the case, should it not just be marked deprecated
or removed entirely?
>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> .../devicetree/bindings/phy/fsl,lynx-28g.yaml | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> index ff9f9ca0f19c..55d773c8d0e4 100644
> --- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> +++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> @@ -11,8 +11,17 @@ maintainers:
>
> properties:
> compatible:
> - enum:
> - - fsl,lynx-28g
> + oneOf:
> + - items:
> + - const: fsl,lynx-28g
> + - items:
> + - enum:
> + - fsl,lx2160a-serdes1
> + - fsl,lx2160a-serdes2
> + - fsl,lx2160a-serdes3
> + - fsl,lx2162a-serdes1
> + - fsl,lx2162a-serdes2
> + - const: fsl,lynx-28g
>
> reg:
> maxItems: 1
> @@ -33,7 +42,7 @@ examples:
> #address-cells = <2>;
> #size-cells = <2>;
> serdes_1: phy@1ea0000 {
> - compatible = "fsl,lynx-28g";
> + compatible = "fsl,lx2160a-serdes1", "fsl,lynx-28g";
> reg = <0x0 0x1ea0000 0x0 0x1e30>;
> #phy-cells = <1>;
> };
> --
> 2.34.1
>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-04 19:22 ` Conor Dooley
@ 2025-09-05 10:49 ` Vladimir Oltean
2025-09-05 11:10 ` Josua Mayer
2025-09-05 18:58 ` Conor Dooley
0 siblings, 2 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-05 10:49 UTC (permalink / raw)
To: Conor Dooley
Cc: linux-phy, Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree, Josua Mayer
On Thu, Sep 04, 2025 at 08:22:16PM +0100, Conor Dooley wrote:
> On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
> > Going by the generic "fsl,lynx-28g" compatible string and expecting all
> > SerDes instantiations on all SoCs to use it was a mistake.
> >
> > They all share the same register map, sure, but the number of protocol
> > converters and lanes which are instantiated differs in a way that isn't
> > detectable by software. So distinguish them by compatible strings.
> > At the same time, keep "fsl,lynx-28g" as backup.
>
> Why keep the backup? Doesn't sound like you can use it for anything,
> unless there's some minimum set of capabilities that all devices
> support. If that's not the case, should it not just be marked deprecated
> or removed entirely?
To be honest, I could use some guidance on the best way to handle this.
When I had written this patch downstream, lx2160a.dtsi only had serdes_1
defined, as "fsl,lynx-28g", and this patch made more sense. Keep
"fsl,lynx-28g" as a synonym for "fsl,lx2160a-serdes1", so that new
device trees still work with old kernels (as is sometimes needed during
'git bisect', etc), for some definition of the word "work" (more often
than not, unsatisfactory - for example, fw_devlink blocks probing the PHY
consumer driver if the PHY driver doesn't exist, but the 'phys' property
exists in the device tree).
Unbeknownst to me, commit 2f2900176b44 ("arm64: dts: lx2160a: describe
the SerDes block #2") came and defined the second SerDes also with
"fsl,lynx-28g".
The second SerDes is less capable than the first one, so the same
developer then started battling with the fact that the driver doesn't
know that serdes_2 doesn't support some protocols, and wrote some
patches like 9bef84d30f1f ("phy: lynx-28g: check return value when
calling lynx_28g_pll_get"), which in all likelihood could have been
avoided using a specific compatible string. The lynx_info ::
lane_supports_mode() method from patch 14/14 is supposed to say what is
supported per SerDes and what not.
In terms of implementation, what does "deprecating" the "fsl,lynx-28g"
compatible string mean, compared to removing it entirely? Would there be
any remaining driver support for it? Should I compute the common set of
capabilities between SerDes #1 and #2, and only support that? What
impact would this have upon old device trees? Is it acceptable to just
remove support for them?
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 10:49 ` Vladimir Oltean
@ 2025-09-05 11:10 ` Josua Mayer
2025-09-05 11:37 ` Vladimir Oltean
2025-09-05 18:58 ` Conor Dooley
1 sibling, 1 reply; 40+ messages in thread
From: Josua Mayer @ 2025-09-05 11:10 UTC (permalink / raw)
To: Vladimir Oltean, Conor Dooley
Cc: linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, devicetree@vger.kernel.org
Hi Vladimir,
Thanks for adding me in CC!
Am 05.09.25 um 12:49 schrieb Vladimir Oltean:
> On Thu, Sep 04, 2025 at 08:22:16PM +0100, Conor Dooley wrote:
>> On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
>>> Going by the generic "fsl,lynx-28g" compatible string and expecting all
>>> SerDes instantiations on all SoCs to use it was a mistake.
>>>
>>> They all share the same register map, sure, but the number of protocol
>>> converters and lanes which are instantiated differs in a way that isn't
>>> detectable by software.
If the serdes node had a phy sub-node for each lane, then software
could describe each lane individually / omit 4 lanes on lx2162 sd1 e.g..
This comes with added benefit that perhaps in the future we can use
them to describe board-specific equalization parameters.
The current driver uses hardcoded defaults that may be appropriate
for some nxp evaluation boards only.
>>> So distinguish them by compatible strings.
>>> At the same time, keep "fsl,lynx-28g" as backup.
>> Why keep the backup? Doesn't sound like you can use it for anything,
>> unless there's some minimum set of capabilities that all devices
>> support. If that's not the case, should it not just be marked deprecated
>> or removed entirely?
> To be honest, I could use some guidance on the best way to handle this.
>
> When I had written this patch downstream, lx2160a.dtsi only had serdes_1
> defined, as "fsl,lynx-28g", and this patch made more sense. Keep
> "fsl,lynx-28g" as a synonym for "fsl,lx2160a-serdes1", so that new
> device trees still work with old kernels (as is sometimes needed during
> 'git bisect', etc), for some definition of the word "work" (more often
> than not, unsatisfactory - for example, fw_devlink blocks probing the PHY
> consumer driver if the PHY driver doesn't exist, but the 'phys' property
> exists in the device tree).
>
> Unbeknownst to me, commit 2f2900176b44 ("arm64: dts: lx2160a: describe
> the SerDes block #2") came and defined the second SerDes also with
> "fsl,lynx-28g".
>
> The second SerDes is less capable than the first one, so the same
> developer then started battling with the fact that the driver doesn't
> know that serdes_2 doesn't support some protocols, and wrote some
> patches like 9bef84d30f1f ("phy: lynx-28g: check return value when
> calling lynx_28g_pll_get"), which in all likelihood could have been
> avoided using a specific compatible string.
> The lynx_info ::
In upstream my patch fixes nothing, it added a return value check
for a function call that can indeed return NULL.
My battle was a different one, unrelated to varying serdes block features
(I claim it can also happen with same phy on serdes block 1):
I found that the combination of Marvell 10G phy driver, pcs, serdes and dpaa2
did not strictly adhere to phy-connection-type set in device-tree, or the initial
mode negoitated between phy and mac.
Once phy negotiated a 2.5Gbps, the kernel would then try switching
all 3 drivers to a 2.5g mode, when it should have stuck with 10gbase-r,
or reported an error knowing that the serdes did not advertise support for 2.5g.
Due to massive downstream refactoring in the vendor kernel serdes driver,
there existed a code-path leading to null pointer dereference.
But that was also a consequence of other mistakes.
> lane_supports_mode() method from patch 14/14 is supposed to say what is
> supported per SerDes and what not.
Indeed, and upstream properly gates all reconfiguration attempts using it.
>
> In terms of implementation, what does "deprecating" the "fsl,lynx-28g"
> compatible string mean, compared to removing it entirely? Would there be
> any remaining driver support for it?Should I compute the common set of
> capabilities between SerDes #1 and #2, and only support that? What
> impact would this have upon old device trees? Is it acceptable to just
> remove support for them?
When you remove the old compatible string, the driver should still keep
supporting old DTBs.
I personally believe it correct to keep dual compatible strings,
reflecting that the serdes blocks share a common programming model.
sincerely
Josua Mayer
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 11:10 ` Josua Mayer
@ 2025-09-05 11:37 ` Vladimir Oltean
2025-09-05 14:23 ` Josua Mayer
0 siblings, 1 reply; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-05 11:37 UTC (permalink / raw)
To: Josua Mayer
Cc: Conor Dooley, linux-phy@lists.infradead.org, Ioana Ciornei,
Vinod Koul, Kishon Vijay Abraham I, linux-kernel@vger.kernel.org,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree@vger.kernel.org
On Fri, Sep 05, 2025 at 11:10:53AM +0000, Josua Mayer wrote:
> Hi Vladimir,
>
> Thanks for adding me in CC!
>
> Am 05.09.25 um 12:49 schrieb Vladimir Oltean:
> > On Thu, Sep 04, 2025 at 08:22:16PM +0100, Conor Dooley wrote:
> >> On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
> >>> Going by the generic "fsl,lynx-28g" compatible string and expecting all
> >>> SerDes instantiations on all SoCs to use it was a mistake.
> >>>
> >>> They all share the same register map, sure, but the number of protocol
> >>> converters and lanes which are instantiated differs in a way that isn't
> >>> detectable by software.
> If the serdes node had a phy sub-node for each lane, then software
> could describe each lane individually / omit 4 lanes on lx2162 sd1 e.g..
>
> This comes with added benefit that perhaps in the future we can use
> them to describe board-specific equalization parameters.
>
> The current driver uses hardcoded defaults that may be appropriate
> for some nxp evaluation boards only.
Yeah.
Given the fact that the SerDes can change between protocols, I suspect
you want to go one level further, and describe default equalization
parameters for each protocol. The equalization for 10G won't be good for
25G and vice versa.
Do you have a specific format in mind?
> >>> So distinguish them by compatible strings.
> >>> At the same time, keep "fsl,lynx-28g" as backup.
> >> Why keep the backup? Doesn't sound like you can use it for anything,
> >> unless there's some minimum set of capabilities that all devices
> >> support. If that's not the case, should it not just be marked deprecated
> >> or removed entirely?
> > To be honest, I could use some guidance on the best way to handle this.
> >
> > When I had written this patch downstream, lx2160a.dtsi only had serdes_1
> > defined, as "fsl,lynx-28g", and this patch made more sense. Keep
> > "fsl,lynx-28g" as a synonym for "fsl,lx2160a-serdes1", so that new
> > device trees still work with old kernels (as is sometimes needed during
> > 'git bisect', etc), for some definition of the word "work" (more often
> > than not, unsatisfactory - for example, fw_devlink blocks probing the PHY
> > consumer driver if the PHY driver doesn't exist, but the 'phys' property
> > exists in the device tree).
> >
> > Unbeknownst to me, commit 2f2900176b44 ("arm64: dts: lx2160a: describe
> > the SerDes block #2") came and defined the second SerDes also with
> > "fsl,lynx-28g".
> >
> > The second SerDes is less capable than the first one, so the same
> > developer then started battling with the fact that the driver doesn't
> > know that serdes_2 doesn't support some protocols, and wrote some
> > patches like 9bef84d30f1f ("phy: lynx-28g: check return value when
> > calling lynx_28g_pll_get"), which in all likelihood could have been
> > avoided using a specific compatible string.
> > The lynx_info ::
> In upstream my patch fixes nothing, it added a return value check
> for a function call that can indeed return NULL.
>
> My battle was a different one, unrelated to varying serdes block features
> (I claim it can also happen with same phy on serdes block 1):
>
> I found that the combination of Marvell 10G phy driver, pcs, serdes and dpaa2
> did not strictly adhere to phy-connection-type set in device-tree, or the initial
> mode negoitated between phy and mac.
Yes, it doesn't have to.
> Once phy negotiated a 2.5Gbps, the kernel would then try switching
> all 3 drivers to a 2.5g mode, when it should have stuck with 10gbase-r,
> or reported an error knowing that the serdes did not advertise support for 2.5g.
>
> Due to massive downstream refactoring in the vendor kernel serdes driver,
> there existed a code-path leading to null pointer dereference.
> But that was also a consequence of other mistakes.
Sorry, I interpreted your patch in the only way that could have made any
sense.
In the circumstance you describe, isn't your fix just "code after return"?
How would have lynx_28g_set_mode(PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_2500BASEX)
gotten past the lynx_28g_supports_interface() test without being rejected?
The driver would have needed to suffer some pretty serious modifications
to allow this to happen, and I'm not happy with the fact that it's changed
to handle incorrect downstream changes, without at least a complete
description.
> > lane_supports_mode() method from patch 14/14 is supposed to say what is
> > supported per SerDes and what not.
> Indeed, and upstream properly gates all reconfiguration attempts using it.
> >
> > In terms of implementation, what does "deprecating" the "fsl,lynx-28g"
> > compatible string mean, compared to removing it entirely? Would there be
> > any remaining driver support for it?Should I compute the common set of
> > capabilities between SerDes #1 and #2, and only support that? What
> > impact would this have upon old device trees? Is it acceptable to just
> > remove support for them?
> When you remove the old compatible string, the driver should still keep
> supporting old DTBs.
Thus thinking SerDes #2 supports all features of SerDes #1?
> I personally believe it correct to keep dual compatible strings,
> reflecting that the serdes blocks share a common programming model.
Thanks for the input.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 11:37 ` Vladimir Oltean
@ 2025-09-05 14:23 ` Josua Mayer
2025-09-05 14:44 ` Josua Mayer
0 siblings, 1 reply; 40+ messages in thread
From: Josua Mayer @ 2025-09-05 14:23 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Conor Dooley, linux-phy@lists.infradead.org, Ioana Ciornei,
Vinod Koul, Kishon Vijay Abraham I, linux-kernel@vger.kernel.org,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree@vger.kernel.org
Am 05.09.25 um 13:37 schrieb Vladimir Oltean:
> On Fri, Sep 05, 2025 at 11:10:53AM +0000, Josua Mayer wrote:
>> Hi Vladimir,
>>
>> Thanks for adding me in CC!
>>
>> Am 05.09.25 um 12:49 schrieb Vladimir Oltean:
>>> On Thu, Sep 04, 2025 at 08:22:16PM +0100, Conor Dooley wrote:
>>>> On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
>>>>> Going by the generic "fsl,lynx-28g" compatible string and expecting all
>>>>> SerDes instantiations on all SoCs to use it was a mistake.
>>>>>
>>>>> They all share the same register map, sure, but the number of protocol
>>>>> converters and lanes which are instantiated differs in a way that isn't
>>>>> detectable by software.
>> If the serdes node had a phy sub-node for each lane, then software
>> could describe each lane individually / omit 4 lanes on lx2162 sd1 e.g..
>>
>> This comes with added benefit that perhaps in the future we can use
>> them to describe board-specific equalization parameters.
>>
>> The current driver uses hardcoded defaults that may be appropriate
>> for some nxp evaluation boards only.
> Yeah.
>
> Given the fact that the SerDes can change between protocols, I suspect
> you want to go one level further, and describe default equalization
> parameters for each protocol. The equalization for 10G won't be good for
> 25G and vice versa.
>
> Do you have a specific format in mind?
I have a prototype implementation based on v5.15 using properties as below
(I am not sure this is the best format though, DT maintainers may have opinions):
serdes_1_lane_g: phy@6 {
reg = <6>;
#phy-cells = <0>;
fsl,eq-names = "10gbase-r", "25gbase-r";
fsl,eq-type = "3-tap", "3-tap";
fsl,eq-preq-sign = "positive", "positive";
fsl,eq-preq-rate = "1.33", "1.33";
fsl,eq-post1q-sign = "negative", "negative";
fsl,eq-post1q-rate = "1.26", "1.26";
fsl,eq-amp-red = "1.000", "1.000";
fsl,eq-adaptive = <32>, <32>;
};
I imagine a parameters sub-node per protocol may be more readable.
The best description would be generic enough to cover pci and sata, too.
Perhaps:
serdes_1_lane_g: phy@6 {
reg = <6>;
#phy-cells = <0>;
fsl,eq-params = <&serdes_1_lane_g_eq_10g>, <&serdes_1_lane_g_eq_sata>;
serdes_1_lane_g_eq_10g: eq-params-0 {
/* compare downstream enum lynx_28g_lane_mode */
fsl,lane-protocol = "xfi";
fsl,eq-type = "3-tap";
fsl,eq-preq-sign = "positive";
fsl,eq-preq-rate = "1.33";
fsl,eq-post1q-sign = "negative";
fsl,eq-post1q-rate = "1.26";
fsl,eq-amp-red = "1.000";
fsl,eq-adaptive = <32>;
};
serdes_1_lane_g_eq_sata: eq-1 {
/* compare downstream enum lynx_28g_lane_mode */
/* example parameters, do not use for sata */
fsl,lane-mode = "pci";
fsl,eq-type = "3-tap";
fsl,eq-preq-sign = "positive";
fsl,eq-preq-rate = "1.33";
fsl,eq-post1q-sign = "negative";
fsl,eq-post1q-rate = "1.26";
fsl,eq-amp-red = "1.000";
fsl,eq-adaptive = <32>;
};
};
>
>>>>> So distinguish them by compatible strings.
>>>>> At the same time, keep "fsl,lynx-28g" as backup.
>>>> Why keep the backup? Doesn't sound like you can use it for anything,
>>>> unless there's some minimum set of capabilities that all devices
>>>> support. If that's not the case, should it not just be marked deprecated
>>>> or removed entirely?
>>> To be honest, I could use some guidance on the best way to handle this.
>>>
>>> When I had written this patch downstream, lx2160a.dtsi only had serdes_1
>>> defined, as "fsl,lynx-28g", and this patch made more sense. Keep
>>> "fsl,lynx-28g" as a synonym for "fsl,lx2160a-serdes1", so that new
>>> device trees still work with old kernels (as is sometimes needed during
>>> 'git bisect', etc), for some definition of the word "work" (more often
>>> than not, unsatisfactory - for example, fw_devlink blocks probing the PHY
>>> consumer driver if the PHY driver doesn't exist, but the 'phys' property
>>> exists in the device tree).
>>>
>>> Unbeknownst to me, commit 2f2900176b44 ("arm64: dts: lx2160a: describe
>>> the SerDes block #2") came and defined the second SerDes also with
>>> "fsl,lynx-28g".
>>>
>>> The second SerDes is less capable than the first one, so the same
>>> developer then started battling with the fact that the driver doesn't
>>> know that serdes_2 doesn't support some protocols, and wrote some
>>> patches like 9bef84d30f1f ("phy: lynx-28g: check return value when
>>> calling lynx_28g_pll_get"), which in all likelihood could have been
>>> avoided using a specific compatible string.
>>> The lynx_info ::
>> In upstream my patch fixes nothing, it added a return value check
>> for a function call that can indeed return NULL.
>>
>> My battle was a different one, unrelated to varying serdes block features
>> (I claim it can also happen with same phy on serdes block 1):
>>
>> I found that the combination of Marvell 10G phy driver, pcs, serdes and dpaa2
>> did not strictly adhere to phy-connection-type set in device-tree, or the initial
>> mode negoitated between phy and mac.
> Yes, it doesn't have to.
>
>> Once phy negotiated a 2.5Gbps, the kernel would then try switching
>> all 3 drivers to a 2.5g mode, when it should have stuck with 10gbase-r,
>> or reported an error knowing that the serdes did not advertise support for 2.5g.
>>
>> Due to massive downstream refactoring in the vendor kernel serdes driver,
>> there existed a code-path leading to null pointer dereference.
>> But that was also a consequence of other mistakes.
> Sorry, I interpreted your patch in the only way that could have made any
> sense.
>
> In the circumstance you describe, isn't your fix just "code after return"?
> How would have lynx_28g_set_mode(PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_2500BASEX)
> gotten past the lynx_28g_supports_interface() test without being rejected?
v6.6.6.52-2.2.0 release, .set_mode:
lynx_28g_set_mode->lynx_28g_set_link_mode->lynx_28g_set_lane_mode->lynx_28g_pll_get
does not check lynx_28g_supports_interface.
> The driver would have needed to suffer some pretty serious modifications
> to allow this to happen, and I'm not happy with the fact that it's changed
> to handle incorrect downstream changes, without at least a complete
> description.
Point of my submitted patch was merely to guard an unchecked pointer,
generating appropriate error with enough explanation for non-maintainers.
I debated using BUG_ON instead of warn.
>
>>> lane_supports_mode() method from patch 14/14 is supposed to say what is
>>> supported per SerDes and what not.
>> Indeed, and upstream properly gates all reconfiguration attempts using it.
>>> In terms of implementation, what does "deprecating" the "fsl,lynx-28g"
>>> compatible string mean, compared to removing it entirely? Would there be
>>> any remaining driver support for it?Should I compute the common set of
>>> capabilities between SerDes #1 and #2, and only support that? What
>>> impact would this have upon old device trees? Is it acceptable to just
>>> remove support for them?
>> When you remove the old compatible string, the driver should still keep
>> supporting old DTBs.
> Thus thinking SerDes #2 supports all features of SerDes #1?
Yes.
This will not be a problem for those users who configure all lanes to SGMII,
or just the two special lanes for XFI.
I don't think you need to fix a downstream dtb via the driver.
If downstream user can update the kernel, they can update the dtb also,
to resolve their own bugs.
>
>> I personally believe it correct to keep dual compatible strings,
>> reflecting that the serdes blocks share a common programming model.
> Thanks for the input.
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 14:23 ` Josua Mayer
@ 2025-09-05 14:44 ` Josua Mayer
2025-09-05 15:29 ` Vladimir Oltean
0 siblings, 1 reply; 40+ messages in thread
From: Josua Mayer @ 2025-09-05 14:44 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Conor Dooley, linux-phy@lists.infradead.org, Ioana Ciornei,
Vinod Koul, Kishon Vijay Abraham I, linux-kernel@vger.kernel.org,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree@vger.kernel.org
Am 05.09.25 um 16:23 schrieb Josua Mayer:
> Am 05.09.25 um 13:37 schrieb Vladimir Oltean:
>> On Fri, Sep 05, 2025 at 11:10:53AM +0000, Josua Mayer wrote:
>>> Hi Vladimir,
>>>
>>> Thanks for adding me in CC!
>>>
>>> Am 05.09.25 um 12:49 schrieb Vladimir Oltean:
>>>> On Thu, Sep 04, 2025 at 08:22:16PM +0100, Conor Dooley wrote:
>>>>> On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
>>>>>> Going by the generic "fsl,lynx-28g" compatible string and expecting all
>>>>>> SerDes instantiations on all SoCs to use it was a mistake.
>>>>>>
>>>>>> They all share the same register map, sure, but the number of protocol
>>>>>> converters and lanes which are instantiated differs in a way that isn't
>>>>>> detectable by software.
>>> If the serdes node had a phy sub-node for each lane, then software
>>> could describe each lane individually / omit 4 lanes on lx2162 sd1 e.g..
>>>
>>> This comes with added benefit that perhaps in the future we can use
>>> them to describe board-specific equalization parameters.
>>>
>>> The current driver uses hardcoded defaults that may be appropriate
>>> for some nxp evaluation boards only.
>> Yeah.
>>
>> Given the fact that the SerDes can change between protocols, I suspect
>> you want to go one level further, and describe default equalization
>> parameters for each protocol. The equalization for 10G won't be good for
>> 25G and vice versa.
>>
>> Do you have a specific format in mind?
> I have a prototype implementation based on v5.15 using properties as below
> (I am not sure this is the best format though, DT maintainers may have opinions):
>
> serdes_1_lane_g: phy@6 {
> reg = <6>;
> #phy-cells = <0>;
> fsl,eq-names = "10gbase-r", "25gbase-r";
> fsl,eq-type = "3-tap", "3-tap";
> fsl,eq-preq-sign = "positive", "positive";
> fsl,eq-preq-rate = "1.33", "1.33";
> fsl,eq-post1q-sign = "negative", "negative";
> fsl,eq-post1q-rate = "1.26", "1.26";
> fsl,eq-amp-red = "1.000", "1.000";
> fsl,eq-adaptive = <32>, <32>;
> };
>
> I imagine a parameters sub-node per protocol may be more readable.
>
> The best description would be generic enough to cover pci and sata, too.
>
> Perhaps:
>
> serdes_1_lane_g: phy@6 {
> reg = <6>;
> #phy-cells = <0>;
> fsl,eq-params = <&serdes_1_lane_g_eq_10g>, <&serdes_1_lane_g_eq_sata>;
fsl,lane-modes = "xfi", "sata";
^^ Would be mroe elegant, as it can at the same time explain which modes
a specific lane supports generally.
Then eq-params is an optional list with specific parameters, some of
which can be shared between different modes (40g/10g)
> serdes_1_lane_g_eq_10g: eq-params-0 {
> /* compare downstream enum lynx_28g_lane_mode */
> fsl,lane-protocol = "xfi";
> fsl,eq-type = "3-tap";
> fsl,eq-preq-sign = "positive";
> fsl,eq-preq-rate = "1.33";
> fsl,eq-post1q-sign = "negative";
> fsl,eq-post1q-rate = "1.26";
> fsl,eq-amp-red = "1.000";
> fsl,eq-adaptive = <32>;
> };
>
> serdes_1_lane_g_eq_sata: eq-1 {
> /* compare downstream enum lynx_28g_lane_mode */
> /* example parameters, do not use for sata */
> fsl,lane-mode = "pci";
> fsl,eq-type = "3-tap";
> fsl,eq-preq-sign = "positive";
> fsl,eq-preq-rate = "1.33";
> fsl,eq-post1q-sign = "negative";
> fsl,eq-post1q-rate = "1.26";
> fsl,eq-amp-red = "1.000";
> fsl,eq-adaptive = <32>;
> };
> };
>
>>>>>> So distinguish them by compatible strings.
>>>>>> At the same time, keep "fsl,lynx-28g" as backup.
>>>>> Why keep the backup? Doesn't sound like you can use it for anything,
>>>>> unless there's some minimum set of capabilities that all devices
>>>>> support. If that's not the case, should it not just be marked deprecated
>>>>> or removed entirely?
>>>> To be honest, I could use some guidance on the best way to handle this.
>>>>
>>>> When I had written this patch downstream, lx2160a.dtsi only had serdes_1
>>>> defined, as "fsl,lynx-28g", and this patch made more sense. Keep
>>>> "fsl,lynx-28g" as a synonym for "fsl,lx2160a-serdes1", so that new
>>>> device trees still work with old kernels (as is sometimes needed during
>>>> 'git bisect', etc), for some definition of the word "work" (more often
>>>> than not, unsatisfactory - for example, fw_devlink blocks probing the PHY
>>>> consumer driver if the PHY driver doesn't exist, but the 'phys' property
>>>> exists in the device tree).
>>>>
>>>> Unbeknownst to me, commit 2f2900176b44 ("arm64: dts: lx2160a: describe
>>>> the SerDes block #2") came and defined the second SerDes also with
>>>> "fsl,lynx-28g".
>>>>
>>>> The second SerDes is less capable than the first one, so the same
>>>> developer then started battling with the fact that the driver doesn't
>>>> know that serdes_2 doesn't support some protocols, and wrote some
>>>> patches like 9bef84d30f1f ("phy: lynx-28g: check return value when
>>>> calling lynx_28g_pll_get"), which in all likelihood could have been
>>>> avoided using a specific compatible string.
>>>> The lynx_info ::
>>> In upstream my patch fixes nothing, it added a return value check
>>> for a function call that can indeed return NULL.
>>>
>>> My battle was a different one, unrelated to varying serdes block features
>>> (I claim it can also happen with same phy on serdes block 1):
>>>
>>> I found that the combination of Marvell 10G phy driver, pcs, serdes and dpaa2
>>> did not strictly adhere to phy-connection-type set in device-tree, or the initial
>>> mode negoitated between phy and mac.
>> Yes, it doesn't have to.
>>
>>> Once phy negotiated a 2.5Gbps, the kernel would then try switching
>>> all 3 drivers to a 2.5g mode, when it should have stuck with 10gbase-r,
>>> or reported an error knowing that the serdes did not advertise support for 2.5g.
>>>
>>> Due to massive downstream refactoring in the vendor kernel serdes driver,
>>> there existed a code-path leading to null pointer dereference.
>>> But that was also a consequence of other mistakes.
>> Sorry, I interpreted your patch in the only way that could have made any
>> sense.
>>
>> In the circumstance you describe, isn't your fix just "code after return"?
>> How would have lynx_28g_set_mode(PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_2500BASEX)
>> gotten past the lynx_28g_supports_interface() test without being rejected?
> v6.6.6.52-2.2.0 release, .set_mode:
>
> lynx_28g_set_mode->lynx_28g_set_link_mode->lynx_28g_set_lane_mode->lynx_28g_pll_get
>
> does not check lynx_28g_supports_interface.
>
>> The driver would have needed to suffer some pretty serious modifications
>> to allow this to happen, and I'm not happy with the fact that it's changed
>> to handle incorrect downstream changes, without at least a complete
>> description.
> Point of my submitted patch was merely to guard an unchecked pointer,
> generating appropriate error with enough explanation for non-maintainers.
>
> I debated using BUG_ON instead of warn.
>
>>>> lane_supports_mode() method from patch 14/14 is supposed to say what is
>>>> supported per SerDes and what not.
>>> Indeed, and upstream properly gates all reconfiguration attempts using it.
>>>> In terms of implementation, what does "deprecating" the "fsl,lynx-28g"
>>>> compatible string mean, compared to removing it entirely? Would there be
>>>> any remaining driver support for it?Should I compute the common set of
>>>> capabilities between SerDes #1 and #2, and only support that? What
>>>> impact would this have upon old device trees? Is it acceptable to just
>>>> remove support for them?
>>> When you remove the old compatible string, the driver should still keep
>>> supporting old DTBs.
>> Thus thinking SerDes #2 supports all features of SerDes #1?
> Yes.
> This will not be a problem for those users who configure all lanes to SGMII,
> or just the two special lanes for XFI.
>
> I don't think you need to fix a downstream dtb via the driver.
> If downstream user can update the kernel, they can update the dtb also,
> to resolve their own bugs.
>
>>> I personally believe it correct to keep dual compatible strings,
>>> reflecting that the serdes blocks share a common programming model.
>> Thanks for the input.
>>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 14:44 ` Josua Mayer
@ 2025-09-05 15:29 ` Vladimir Oltean
2025-09-05 15:50 ` Josua Mayer
0 siblings, 1 reply; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-05 15:29 UTC (permalink / raw)
To: Josua Mayer
Cc: Conor Dooley, linux-phy@lists.infradead.org, Ioana Ciornei,
Vinod Koul, Kishon Vijay Abraham I, linux-kernel@vger.kernel.org,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree@vger.kernel.org
On Fri, Sep 05, 2025 at 02:44:33PM +0000, Josua Mayer wrote:
> >> Do you have a specific format in mind?
> > I have a prototype implementation based on v5.15 using properties as below
> > (I am not sure this is the best format though, DT maintainers may have opinions):
> >
> > serdes_1_lane_g: phy@6 {
> > reg = <6>;
> > #phy-cells = <0>;
> > fsl,eq-names = "10gbase-r", "25gbase-r";
> > fsl,eq-type = "3-tap", "3-tap";
> > fsl,eq-preq-sign = "positive", "positive";
> > fsl,eq-preq-rate = "1.33", "1.33";
> > fsl,eq-post1q-sign = "negative", "negative";
> > fsl,eq-post1q-rate = "1.26", "1.26";
> > fsl,eq-amp-red = "1.000", "1.000";
> > fsl,eq-adaptive = <32>, <32>;
> > };
> >
> > I imagine a parameters sub-node per protocol may be more readable.
> >
> > The best description would be generic enough to cover pci and sata, too.
> >
> > Perhaps:
> >
> > serdes_1_lane_g: phy@6 {
> > reg = <6>;
> > #phy-cells = <0>;
> > fsl,eq-params = <&serdes_1_lane_g_eq_10g>, <&serdes_1_lane_g_eq_sata>;
>
> fsl,lane-modes = "xfi", "sata";
>
> ^^ Would be mroe elegant, as it can at the same time explain which modes
> a specific lane supports generally.
>
> Then eq-params is an optional list with specific parameters, some of
> which can be shared between different modes (40g/10g)
>
> > serdes_1_lane_g_eq_10g: eq-params-0 {
> > /* compare downstream enum lynx_28g_lane_mode */
> > fsl,lane-protocol = "xfi";
> > fsl,eq-type = "3-tap";
> > fsl,eq-preq-sign = "positive";
> > fsl,eq-preq-rate = "1.33";
> > fsl,eq-post1q-sign = "negative";
> > fsl,eq-post1q-rate = "1.26";
> > fsl,eq-amp-red = "1.000";
> > fsl,eq-adaptive = <32>;
> > };
> >
> > serdes_1_lane_g_eq_sata: eq-1 {
> > /* compare downstream enum lynx_28g_lane_mode */
> > /* example parameters, do not use for sata */
> > fsl,lane-mode = "pci";
> > fsl,eq-type = "3-tap";
> > fsl,eq-preq-sign = "positive";
> > fsl,eq-preq-rate = "1.33";
> > fsl,eq-post1q-sign = "negative";
> > fsl,eq-post1q-rate = "1.26";
> > fsl,eq-amp-red = "1.000";
> > fsl,eq-adaptive = <32>;
> > };
> > };
Why stop the eq-params reuse at "per lane"? Why not make these global
nodes, like SFP cages? It's imaginable your pre-emphasis settings might
be the same across the board, for both SerDes #1 and #2 lanes.
Also, let's take what is upstream now as a starting point. Currently the
driver has #phy-cells = <1> (i.e. the "phys" phandle is to the SerDes,
not to individual lanes). Wouldn't we want to keep it that way, and make
the SerDes lane sub-nodes optional, only in case they have phandles to
custom pre-emphasis settings? If they don't, use the driver default
pre-emphasis.
> >> In the circumstance you describe, isn't your fix just "code after return"?
> >> How would have lynx_28g_set_mode(PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_2500BASEX)
> >> gotten past the lynx_28g_supports_interface() test without being rejected?
> > v6.6.6.52-2.2.0 release, .set_mode:
> >
> > lynx_28g_set_mode->lynx_28g_set_link_mode->lynx_28g_set_lane_mode->lynx_28g_pll_get
> >
> > does not check lynx_28g_supports_interface.
> >
> >> The driver would have needed to suffer some pretty serious modifications
> >> to allow this to happen, and I'm not happy with the fact that it's changed
> >> to handle incorrect downstream changes, without at least a complete
> >> description.
> > Point of my submitted patch was merely to guard an unchecked pointer,
> > generating appropriate error with enough explanation for non-maintainers.
> >
> > I debated using BUG_ON instead of warn.
Sorry for maybe being obtuse. You're saying you added code in mainline
to check for a condition that exists only in downstream lf-6.6.52-2.2.0?
Why?
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 15:29 ` Vladimir Oltean
@ 2025-09-05 15:50 ` Josua Mayer
2025-09-09 11:37 ` Vladimir Oltean
0 siblings, 1 reply; 40+ messages in thread
From: Josua Mayer @ 2025-09-05 15:50 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Conor Dooley, linux-phy@lists.infradead.org, Ioana Ciornei,
Vinod Koul, Kishon Vijay Abraham I, linux-kernel@vger.kernel.org,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree@vger.kernel.org
Am 05.09.25 um 17:29 schrieb Vladimir Oltean:
> On Fri, Sep 05, 2025 at 02:44:33PM +0000, Josua Mayer wrote:
>>>> Do you have a specific format in mind?
>>> I have a prototype implementation based on v5.15 using properties as below
>>> (I am not sure this is the best format though, DT maintainers may have opinions):
>>>
>>> serdes_1_lane_g: phy@6 {
>>> reg = <6>;
>>> #phy-cells = <0>;
>>> fsl,eq-names = "10gbase-r", "25gbase-r";
>>> fsl,eq-type = "3-tap", "3-tap";
>>> fsl,eq-preq-sign = "positive", "positive";
>>> fsl,eq-preq-rate = "1.33", "1.33";
>>> fsl,eq-post1q-sign = "negative", "negative";
>>> fsl,eq-post1q-rate = "1.26", "1.26";
>>> fsl,eq-amp-red = "1.000", "1.000";
>>> fsl,eq-adaptive = <32>, <32>;
>>> };
>>>
>>> I imagine a parameters sub-node per protocol may be more readable.
>>>
>>> The best description would be generic enough to cover pci and sata, too.
>>>
>>> Perhaps:
>>>
>>> serdes_1_lane_g: phy@6 {
>>> reg = <6>;
>>> #phy-cells = <0>;
>>> fsl,eq-params = <&serdes_1_lane_g_eq_10g>, <&serdes_1_lane_g_eq_sata>;
>> fsl,lane-modes = "xfi", "sata";
>>
>> ^^ Would be mroe elegant, as it can at the same time explain which modes
>> a specific lane supports generally.
>>
>> Then eq-params is an optional list with specific parameters, some of
>> which can be shared between different modes (40g/10g)
>>
>>> serdes_1_lane_g_eq_10g: eq-params-0 {
>>> /* compare downstream enum lynx_28g_lane_mode */
>>> fsl,lane-protocol = "xfi";
>>> fsl,eq-type = "3-tap";
>>> fsl,eq-preq-sign = "positive";
>>> fsl,eq-preq-rate = "1.33";
>>> fsl,eq-post1q-sign = "negative";
>>> fsl,eq-post1q-rate = "1.26";
>>> fsl,eq-amp-red = "1.000";
>>> fsl,eq-adaptive = <32>;
>>> };
>>>
>>> serdes_1_lane_g_eq_sata: eq-1 {
>>> /* compare downstream enum lynx_28g_lane_mode */
>>> /* example parameters, do not use for sata */
>>> fsl,lane-mode = "pci";
>>> fsl,eq-type = "3-tap";
>>> fsl,eq-preq-sign = "positive";
>>> fsl,eq-preq-rate = "1.33";
>>> fsl,eq-post1q-sign = "negative";
>>> fsl,eq-post1q-rate = "1.26";
>>> fsl,eq-amp-red = "1.000";
>>> fsl,eq-adaptive = <32>;
>>> };
>>> };
> Why stop the eq-params reuse at "per lane"? Why not make these global
> nodes, like SFP cages? It's imaginable your pre-emphasis settings might
> be the same across the board, for both SerDes #1 and #2 lanes.
No special reason, I think you got the right idea.
>
> Also, let's take what is upstream now as a starting point. Currently the
> driver has #phy-cells = <1> (i.e. the "phys" phandle is to the SerDes,
> not to individual lanes).
Yes. And all serdes blocks are considered equal.
> Wouldn't we want to keep it that way, and make
> the SerDes lane sub-nodes optional, only in case they have phandles to
> custom pre-emphasis settings? If they don't, use the driver default
> pre-emphasis.
That depends on whether or not you want to use those sub-nodes also
to differentiate between the special characteristics of each serdes block,
and each lane.
Each lane could by itself declare which modes it supports, then the driver
wouldn't need to know about serdes-1/2/3.
Presence (or status) of a lane node can indicate whether the lane is usable.
No strong opinion, either approach can work out.
>
>>>> In the circumstance you describe, isn't your fix just "code after return"?
>>>> How would have lynx_28g_set_mode(PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_2500BASEX)
>>>> gotten past the lynx_28g_supports_interface() test without being rejected?
>>> v6.6.6.52-2.2.0 release, .set_mode:
>>>
>>> lynx_28g_set_mode->lynx_28g_set_link_mode->lynx_28g_set_lane_mode->lynx_28g_pll_get
>>>
>>> does not check lynx_28g_supports_interface.
>>>
>>>> The driver would have needed to suffer some pretty serious modifications
>>>> to allow this to happen, and I'm not happy with the fact that it's changed
>>>> to handle incorrect downstream changes, without at least a complete
>>>> description.
>>> Point of my submitted patch was merely to guard an unchecked pointer,
>>> generating appropriate error with enough explanation for non-maintainers.
>>>
>>> I debated using BUG_ON instead of warn.
> Sorry for maybe being obtuse. You're saying you added code in mainline
> to check for a condition that exists only in downstream lf-6.6.52-2.2.0?
> Why?
I consider it good practice to check the return value of functions, especially
when they can return NULL.
The downstream code merely shows that an original author's assumptions
on how a function is called do not necessarily hold true into the future.
It is not a bug-fix and I didn't intend it to be backported into older releases.
However I actually anticipated a discussion - which started late, here.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 15:50 ` Josua Mayer
@ 2025-09-09 11:37 ` Vladimir Oltean
0 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-09 11:37 UTC (permalink / raw)
To: Josua Mayer
Cc: Conor Dooley, linux-phy@lists.infradead.org, Ioana Ciornei,
Vinod Koul, Kishon Vijay Abraham I, linux-kernel@vger.kernel.org,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree@vger.kernel.org
On Fri, Sep 05, 2025 at 03:50:52PM +0000, Josua Mayer wrote:
> > Why stop the eq-params reuse at "per lane"? Why not make these global
> > nodes, like SFP cages? It's imaginable your pre-emphasis settings might
> > be the same across the board, for both SerDes #1 and #2 lanes.
> No special reason, I think you got the right idea.
Well, there is a reason why. You wouldn't put "fsl,blabla" vendor device
tree properties in a root device tree node, where it isn't namespaced by
the "fsl,lynx-28g" device. You'd only put them under the root node if
they were vendor-agnostic.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 10:49 ` Vladimir Oltean
2025-09-05 11:10 ` Josua Mayer
@ 2025-09-05 18:58 ` Conor Dooley
1 sibling, 0 replies; 40+ messages in thread
From: Conor Dooley @ 2025-09-05 18:58 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree, Josua Mayer
[-- Attachment #1.1: Type: text/plain, Size: 3751 bytes --]
On Fri, Sep 05, 2025 at 01:49:21PM +0300, Vladimir Oltean wrote:
> On Thu, Sep 04, 2025 at 08:22:16PM +0100, Conor Dooley wrote:
> > On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
> > > Going by the generic "fsl,lynx-28g" compatible string and expecting all
> > > SerDes instantiations on all SoCs to use it was a mistake.
> > >
> > > They all share the same register map, sure, but the number of protocol
> > > converters and lanes which are instantiated differs in a way that isn't
> > > detectable by software. So distinguish them by compatible strings.
> > > At the same time, keep "fsl,lynx-28g" as backup.
> >
> > Why keep the backup? Doesn't sound like you can use it for anything,
> > unless there's some minimum set of capabilities that all devices
> > support. If that's not the case, should it not just be marked deprecated
> > or removed entirely?
>
> To be honest, I could use some guidance on the best way to handle this.
>
> When I had written this patch downstream, lx2160a.dtsi only had serdes_1
> defined, as "fsl,lynx-28g", and this patch made more sense. Keep
> "fsl,lynx-28g" as a synonym for "fsl,lx2160a-serdes1", so that new
> device trees still work with old kernels (as is sometimes needed during
> 'git bisect', etc), for some definition of the word "work" (more often
> than not, unsatisfactory - for example, fw_devlink blocks probing the PHY
> consumer driver if the PHY driver doesn't exist, but the 'phys' property
> exists in the device tree).
>
> Unbeknownst to me, commit 2f2900176b44 ("arm64: dts: lx2160a: describe
> the SerDes block #2") came and defined the second SerDes also with
> "fsl,lynx-28g".
>
> The second SerDes is less capable than the first one, so the same
> developer then started battling with the fact that the driver doesn't
> know that serdes_2 doesn't support some protocols, and wrote some
> patches like 9bef84d30f1f ("phy: lynx-28g: check return value when
> calling lynx_28g_pll_get"), which in all likelihood could have been
> avoided using a specific compatible string. The lynx_info ::
> lane_supports_mode() method from patch 14/14 is supposed to say what is
> supported per SerDes and what not.
> In terms of implementation, what does "deprecating" the "fsl,lynx-28g"
> compatible string mean, compared to removing it entirely? Would there be
> any remaining driver support for it?
Really it does nothing much. The difference is that removing it entirely
from the binding will cause existing dts users to create warnings
whereas marking it deprecated is more of an attempt to stop
proliferation since it doesn't generate any warnings at the moment but
people using the binding will see that it's not ideal. I personally use
deprecated when using the old binding is only ill-advised because
there's missing features etc and I opt for removal when the old binding
is wrong and actively harmful. In both cases, I'd keep the old
compatible in the driver for compatibility reasons.
> Should I compute the common set of
> capabilities between SerDes #1 and #2, and only support that? What
> impact would this have upon old device trees? Is it acceptable to just
> remove support for them?
Up to you really, if there is a common set between the two, that's
probably the ideal thing to do for the generic compatible. If there
isn't, and shit just ain't working properly at all for either then yeah,
it might be for the better to remove support for it entirely from the
driver too. Just make sure that you're clear about the fact that it just
cannot work at all, and that's why you're axing it. Breaking
compatibility is allowed, when there's justification for doing so, it's
not a complete no-no.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-04 15:44 ` [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
2025-09-04 19:22 ` Conor Dooley
@ 2025-09-05 8:29 ` Krzysztof Kozlowski
2025-09-05 11:02 ` Vladimir Oltean
2025-09-05 15:41 ` Vladimir Oltean
1 sibling, 2 replies; 40+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-05 8:29 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree
On Thu, Sep 04, 2025 at 06:44:01PM +0300, Vladimir Oltean wrote:
> Going by the generic "fsl,lynx-28g" compatible string and expecting all
> SerDes instantiations on all SoCs to use it was a mistake.
>
> They all share the same register map, sure, but the number of protocol
> converters and lanes which are instantiated differs in a way that isn't
> detectable by software. So distinguish them by compatible strings.
> At the same time, keep "fsl,lynx-28g" as backup.
>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> .../devicetree/bindings/phy/fsl,lynx-28g.yaml | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> index ff9f9ca0f19c..55d773c8d0e4 100644
> --- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> +++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> @@ -11,8 +11,17 @@ maintainers:
>
> properties:
> compatible:
> - enum:
> - - fsl,lynx-28g
> + oneOf:
> + - items:
> + - const: fsl,lynx-28g
Don't change that part. Previous enum was correct. You want oneOf and
enum.
> + - items:
> + - enum:
> + - fsl,lx2160a-serdes1
> + - fsl,lx2160a-serdes2
> + - fsl,lx2160a-serdes3
What are the differences? number of lanes? For this you can take
num-lanes property.
> + - fsl,lx2162a-serdes1
> + - fsl,lx2162a-serdes2
> + - const: fsl,lynx-28g
Best regards,
Krzysztof
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 8:29 ` Krzysztof Kozlowski
@ 2025-09-05 11:02 ` Vladimir Oltean
2025-09-05 15:41 ` Vladimir Oltean
1 sibling, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-05 11:02 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: linux-phy, Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree
On Fri, Sep 05, 2025 at 10:29:33AM +0200, Krzysztof Kozlowski wrote:
> > diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> > index ff9f9ca0f19c..55d773c8d0e4 100644
> > --- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> > +++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
> > @@ -11,8 +11,17 @@ maintainers:
> >
> > properties:
> > compatible:
> > - enum:
> > - - fsl,lynx-28g
> > + oneOf:
> > + - items:
> > + - const: fsl,lynx-28g
>
> Don't change that part. Previous enum was correct. You want oneOf and
> enum.
>
> > + - items:
> > + - enum:
> > + - fsl,lx2160a-serdes1
> > + - fsl,lx2160a-serdes2
> > + - fsl,lx2160a-serdes3
>
> What are the differences? number of lanes? For this you can take
> num-lanes property.
Number of lanes, but on LX2162A it's a bit weird. It supports 4 lanes
but they are numbered 4, 5, 6, 7.
Also supported protocols for each lane. Just one example: lane 0 of
fsl,lx2160a-serdes1 supports PCIe, SGMII, USXGMII, 40GbE, whereas lane 0
of fsl,lx2160a-serdes2 supports PCIe, SGMII.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 8:29 ` Krzysztof Kozlowski
2025-09-05 11:02 ` Vladimir Oltean
@ 2025-09-05 15:41 ` Vladimir Oltean
2025-09-05 19:02 ` Conor Dooley
1 sibling, 1 reply; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-05 15:41 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: linux-phy, Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree, Josua Mayer
On Fri, Sep 05, 2025 at 10:29:33AM +0200, Krzysztof Kozlowski wrote:
> > properties:
> > compatible:
> > - enum:
> > - - fsl,lynx-28g
> > + oneOf:
> > + - items:
> > + - const: fsl,lynx-28g
>
> Don't change that part. Previous enum was correct. You want oneOf and
> enum.
Combining the feedback from Conor and Josua, I should only be permitting
the use of "fsl,lynx-28g" as a fallback to "fsl,lx216{0,2}a-serdes{1,2}",
or standalone. The description below achieves just that. Does it look ok
to you?
properties:
compatible:
oneOf:
- enum:
- fsl,lx2160a-serdes1
- fsl,lx2160a-serdes2
- fsl,lx2160a-serdes3
- fsl,lx2162a-serdes1
- fsl,lx2162a-serdes2
- const: fsl,lynx-28g
deprecated: true
- items:
- const: fsl,lx2160a-serdes1
- const: fsl,lynx-28g
deprecated: true
- items:
- const: fsl,lx2160a-serdes2
- const: fsl,lynx-28g
deprecated: true
- items:
- const: fsl,lx2162a-serdes1
- const: fsl,lynx-28g
deprecated: true
- items:
- const: fsl,lx2162a-serdes2
- const: fsl,lynx-28g
deprecated: true
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 15:41 ` Vladimir Oltean
@ 2025-09-05 19:02 ` Conor Dooley
2025-09-08 9:37 ` Vladimir Oltean
0 siblings, 1 reply; 40+ messages in thread
From: Conor Dooley @ 2025-09-05 19:02 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Krzysztof Kozlowski, linux-phy, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, devicetree, Josua Mayer
[-- Attachment #1.1: Type: text/plain, Size: 2040 bytes --]
On Fri, Sep 05, 2025 at 06:41:50PM +0300, Vladimir Oltean wrote:
> On Fri, Sep 05, 2025 at 10:29:33AM +0200, Krzysztof Kozlowski wrote:
> > > properties:
> > > compatible:
> > > - enum:
> > > - - fsl,lynx-28g
> > > + oneOf:
> > > + - items:
> > > + - const: fsl,lynx-28g
> >
> > Don't change that part. Previous enum was correct. You want oneOf and
> > enum.
>
> Combining the feedback from Conor and Josua, I should only be permitting
> the use of "fsl,lynx-28g" as a fallback to "fsl,lx216{0,2}a-serdes{1,2}",
> or standalone. The description below achieves just that. Does it look ok
> to you?
>
> properties:
> compatible:
> oneOf:
> - enum:
> - fsl,lx2160a-serdes1
> - fsl,lx2160a-serdes2
> - fsl,lx2160a-serdes3
> - fsl,lx2162a-serdes1
> - fsl,lx2162a-serdes2
> - const: fsl,lynx-28g
> deprecated: true
> - items:
> - const: fsl,lx2160a-serdes1
> - const: fsl,lynx-28g
> deprecated: true
> - items:
> - const: fsl,lx2160a-serdes2
> - const: fsl,lynx-28g
> deprecated: true
> - items:
> - const: fsl,lx2162a-serdes1
> - const: fsl,lynx-28g
> deprecated: true
> - items:
> - const: fsl,lx2162a-serdes2
> - const: fsl,lynx-28g
> deprecated: true
This doesn't really make sense, none of these are currently in use
right? Everything is just using fsl,lynx-28g right?
Adding new stuff and immediately marking it deprecated is a
contradiction, just don't add it at all if you don't want people using
it. Any users of it would be something you're going to retrofit in now,
so you may as well just retrofit to use what you want people to use
going forward, which has no fallbacks.
I didn't read the back and forth with Josua (sorry!) but is the fallback
even valid? Do those devices have a common minimum set of features that
they share?
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-05 19:02 ` Conor Dooley
@ 2025-09-08 9:37 ` Vladimir Oltean
2025-09-08 14:02 ` Josua Mayer
0 siblings, 1 reply; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-08 9:37 UTC (permalink / raw)
To: Conor Dooley, Josua Mayer, Krzysztof Kozlowski
Cc: Krzysztof Kozlowski, linux-phy, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel, Rob Herring, Conor Dooley,
devicetree
On Fri, Sep 05, 2025 at 08:02:59PM +0100, Conor Dooley wrote:
> On Fri, Sep 05, 2025 at 06:41:50PM +0300, Vladimir Oltean wrote:
> > On Fri, Sep 05, 2025 at 10:29:33AM +0200, Krzysztof Kozlowski wrote:
> > > > properties:
> > > > compatible:
> > > > - enum:
> > > > - - fsl,lynx-28g
> > > > + oneOf:
> > > > + - items:
> > > > + - const: fsl,lynx-28g
> > >
> > > Don't change that part. Previous enum was correct. You want oneOf and
> > > enum.
> >
> > Combining the feedback from Conor and Josua, I should only be permitting
> > the use of "fsl,lynx-28g" as a fallback to "fsl,lx216{0,2}a-serdes{1,2}",
> > or standalone. The description below achieves just that. Does it look ok
> > to you?
> >
> > properties:
> > compatible:
> > oneOf:
> > - enum:
> > - fsl,lx2160a-serdes1
> > - fsl,lx2160a-serdes2
> > - fsl,lx2160a-serdes3
> > - fsl,lx2162a-serdes1
> > - fsl,lx2162a-serdes2
> > - const: fsl,lynx-28g
> > deprecated: true
>
> > - items:
> > - const: fsl,lx2160a-serdes1
> > - const: fsl,lynx-28g
> > deprecated: true
> > - items:
> > - const: fsl,lx2160a-serdes2
> > - const: fsl,lynx-28g
> > deprecated: true
> > - items:
> > - const: fsl,lx2162a-serdes1
> > - const: fsl,lynx-28g
> > deprecated: true
> > - items:
> > - const: fsl,lx2162a-serdes2
> > - const: fsl,lynx-28g
> > deprecated: true
>
> This doesn't really make sense, none of these are currently in use
> right? Everything is just using fsl,lynx-28g right?
> Adding new stuff and immediately marking it deprecated is a
> contradiction, just don't add it at all if you don't want people using
> it. Any users of it would be something you're going to retrofit in now,
> so you may as well just retrofit to use what you want people to use
> going forward, which has no fallbacks.
You're right that it doesn't make sense to deprecate a newly introduced
compatible string pair - my mistake for misunderstanding "deprecated".
> I didn't read the back and forth with Josua (sorry!) but is the fallback
> even valid? Do those devices have a common minimum set of features that
> they share?
I'll try to make an argument based on the facts presented below.
The current Linux driver, which recognizes only "fsl,lynx-28g", supports
only 1GbE and 10GbE. There are other SerDes protocols supported by the
SerDes, but they are irrelevant for the purpose of discussing
compatibility. Also, LX2160A SerDes #3 is also irrelevant, because it is
not currently described in the device tree.
1GbE compatibility table
SerDes Lane 0 Lane 1 Lane 2 Lane 3 Lane 4 Lane 5 Lane 6 Lane 7 Comments
LX2160A SerDes #1 y y y y y y y y
LX2160A SerDes #2 y y y y y y y y
LX2162A SerDes #1 n/a n/a n/a n/a y y y y LX2162A currently uses lx2160a.dtsi
LX2162A SerDes #2 y y y y y y y y LX2162A currently uses lx2160a.dtsi
10GbE compatibility table
SerDes Lane 0 Lane 1 Lane 2 Lane 3 Lane 4 Lane 5 Lane 6 Lane 7 Comments
LX2160A SerDes #1 y y y y y y y y
LX2160A SerDes #2 n n n n n n y y
LX2162A SerDes #1 n/a n/a n/a n/a y y y y LX2162A currently uses lx2160a.dtsi
LX2162A SerDes #2 n n n n n n y y LX2162A currently uses lx2160a.dtsi
As LX2160A SerDes #2 is treated like #1, the device tree is telling the
driver that all lanes support 10GbE (which is false for lanes 0-5).
If one of the SerDes PLLs happens to be provisioned for the 10GbE clock
net frequency, as for example with the RCW[SRDS_PRTCL_S2]=6 setting,
this will make the driver think that it can reconfigure lanes 0-5 as
10GbE.
This will directly affect upper layers (phylink), which will advertise
10GbE modes to its link partner on ports which support only 1GbE, and
the non-functional link mode might be resolved through negotiation, when
a lower speed but functional link could have been established.
You mention a common minimum feature set. That would be supporting 10GbE
only on lanes 6-7, which would be disadvantageous to existing uses of
10GbE on lanes 0-5 of SerDes #1. In some cases, the change might also be
breaking - there might be a PHY attached to these lanes whose firmware
is hardcoded to expect 10GbE, so there won't be a graceful degradation
to 1GbE in all cases.
With Josua's permission, I would consider commit 2f2900176b44 ("arm64:
dts: lx2160a: describe the SerDes block #2") as broken, for being an
incorrect description of hardware - it is presented as identical to
another device, which has a different supported feature set. I will not
try to keep SerDes #2 compatible with "fsl,lynx-28g". This will remain
synonymous only with SerDes #1. The users of the fsl-lx2162a-clearfog.dts
will need updating if the "undetected lack of support for 10GbE" becomes
an issue.
My updated plan is to describe the schema rules for the compatible as
follows. Is that ok with everyone?
properties:
compatible:
oneOf:
- const: fsl,lynx-28g
deprecated: true
- items:
- const: fsl,lx2160a-serdes1
- const: fsl,lynx-28g
- enum:
- fsl,lx2160a-serdes2
- fsl,lx2160a-serdes3
- fsl,lx2162a-serdes1
- fsl,lx2162a-serdes2
Also, I will limit the driver support for the "fsl,lynx-28g" compatible
to just 1GbE and 10GbE. The 25GbE feature introduced by this series will
require a more precise compatible string.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-08 9:37 ` Vladimir Oltean
@ 2025-09-08 14:02 ` Josua Mayer
2025-09-08 15:37 ` Vladimir Oltean
2025-09-08 18:39 ` Conor Dooley
0 siblings, 2 replies; 40+ messages in thread
From: Josua Mayer @ 2025-09-08 14:02 UTC (permalink / raw)
To: Vladimir Oltean, Conor Dooley, Krzysztof Kozlowski
Cc: Krzysztof Kozlowski, linux-phy@lists.infradead.org, Ioana Ciornei,
Vinod Koul, Kishon Vijay Abraham I, linux-kernel@vger.kernel.org,
Rob Herring, Conor Dooley, devicetree@vger.kernel.org
Am 08.09.25 um 11:37 schrieb Vladimir Oltean:
> On Fri, Sep 05, 2025 at 08:02:59PM +0100, Conor Dooley wrote:
>> On Fri, Sep 05, 2025 at 06:41:50PM +0300, Vladimir Oltean wrote:
>>> On Fri, Sep 05, 2025 at 10:29:33AM +0200, Krzysztof Kozlowski wrote:
>>>>> properties:
>>>>> compatible:
>>>>> - enum:
>>>>> - - fsl,lynx-28g
>>>>> + oneOf:
>>>>> + - items:
>>>>> + - const: fsl,lynx-28g
>>>> Don't change that part. Previous enum was correct. You want oneOf and
>>>> enum.
>>> Combining the feedback from Conor and Josua, I should only be permitting
>>> the use of "fsl,lynx-28g" as a fallback to "fsl,lx216{0,2}a-serdes{1,2}",
>>> or standalone. The description below achieves just that. Does it look ok
>>> to you?
>>>
>>> properties:
>>> compatible:
>>> oneOf:
>>> - enum:
>>> - fsl,lx2160a-serdes1
>>> - fsl,lx2160a-serdes2
>>> - fsl,lx2160a-serdes3
>>> - fsl,lx2162a-serdes1
>>> - fsl,lx2162a-serdes2
>>> - const: fsl,lynx-28g
>>> deprecated: true
>>> - items:
>>> - const: fsl,lx2160a-serdes1
>>> - const: fsl,lynx-28g
>>> deprecated: true
>>> - items:
>>> - const: fsl,lx2160a-serdes2
>>> - const: fsl,lynx-28g
>>> deprecated: true
>>> - items:
>>> - const: fsl,lx2162a-serdes1
>>> - const: fsl,lynx-28g
>>> deprecated: true
>>> - items:
>>> - const: fsl,lx2162a-serdes2
>>> - const: fsl,lynx-28g
>>> deprecated: true
>> This doesn't really make sense, none of these are currently in use
>> right? Everything is just using fsl,lynx-28g right?
>> Adding new stuff and immediately marking it deprecated is a
>> contradiction, just don't add it at all if you don't want people using
>> it. Any users of it would be something you're going to retrofit in now,
>> so you may as well just retrofit to use what you want people to use
>> going forward, which has no fallbacks.
> You're right that it doesn't make sense to deprecate a newly introduced
> compatible string pair - my mistake for misunderstanding "deprecated".
>
>> I didn't read the back and forth with Josua (sorry!) but is the fallback
>> even valid? Do those devices have a common minimum set of features that
>> they share?
> I'll try to make an argument based on the facts presented below.
>
> The current Linux driver, which recognizes only "fsl,lynx-28g", supports
> only 1GbE and 10GbE. There are other SerDes protocols supported by the
> SerDes, but they are irrelevant for the purpose of discussing
> compatibility. Also, LX2160A SerDes #3 is also irrelevant, because it is
> not currently described in the device tree.
>
> 1GbE compatibility table
>
> SerDes Lane 0 Lane 1 Lane 2 Lane 3 Lane 4 Lane 5 Lane 6 Lane 7 Comments
> LX2160A SerDes #1 y y y y y y y y
> LX2160A SerDes #2 y y y y y y y y
> LX2162A SerDes #1 n/a n/a n/a n/a y y y y LX2162A currently uses lx2160a.dtsi
> LX2162A SerDes #2 y y y y y y y y LX2162A currently uses lx2160a.dtsi
>
> 10GbE compatibility table
>
> SerDes Lane 0 Lane 1 Lane 2 Lane 3 Lane 4 Lane 5 Lane 6 Lane 7 Comments
> LX2160A SerDes #1 y y y y y y y y
> LX2160A SerDes #2 n n n n n n y y
> LX2162A SerDes #1 n/a n/a n/a n/a y y y y LX2162A currently uses lx2160a.dtsi
> LX2162A SerDes #2 n n n n n n y y LX2162A currently uses lx2160a.dtsi
>
> As LX2160A SerDes #2 is treated like #1, the device tree is telling the
> driver that all lanes support 10GbE (which is false for lanes 0-5).
>
> If one of the SerDes PLLs happens to be provisioned for the 10GbE clock
> net frequency, as for example with the RCW[SRDS_PRTCL_S2]=6 setting,
> this will make the driver think that it can reconfigure lanes 0-5 as
> 10GbE.
>
> This will directly affect upper layers (phylink), which will advertise
> 10GbE modes to its link partner on ports which support only 1GbE, and
> the non-functional link mode might be resolved through negotiation, when
> a lower speed but functional link could have been established.
>
> You mention a common minimum feature set. That would be supporting 10GbE
> only on lanes 6-7, which would be disadvantageous to existing uses of
> 10GbE on lanes 0-5 of SerDes #1. In some cases, the change might also be
> breaking - there might be a PHY attached to these lanes whose firmware
> is hardcoded to expect 10GbE, so there won't be a graceful degradation
> to 1GbE in all cases.
>
> With Josua's permission, I would consider commit 2f2900176b44 ("arm64:
> dts: lx2160a: describe the SerDes block #2") as broken, for being an
> incorrect description of hardware - it is presented as identical to
> another device, which has a different supported feature set. I will not
> try to keep SerDes #2 compatible with "fsl,lynx-28g". This will remain
> synonymous only with SerDes #1. The users of the fsl-lx2162a-clearfog.dts
> will need updating if the "undetected lack of support for 10GbE" becomes
> an issue.
>
> My updated plan is to describe the schema rules for the compatible as
> follows. Is that ok with everyone?
>
> properties:
> compatible:
> oneOf:
> - const: fsl,lynx-28g
> deprecated: true
> - items:
> - const: fsl,lx2160a-serdes1
> - const: fsl,lynx-28g
> - enum:
> - fsl,lx2160a-serdes2
> - fsl,lx2160a-serdes3
> - fsl,lx2162a-serdes1
> - fsl,lx2162a-serdes2
Weak objection, I think this is more complex than it should be.
Perhaps it was discussed before to keep two compatible strings ...:
properties:
compatible:
items:
- enum:
- fsl,lx2160a-serdes2
- fsl,lx2160a-serdes3
- fsl,lx2162a-serdes1
- fsl,lx2162a-serdes2
- const: fsl,lynx-28g
This will cause the dtbs_check to complain about anyone in the future
using it wrong.
The driver can still probe on fsl,lynx-28g alone for backwards compatibility,
and you can limit the feature-set as you see fit in such case.
Main argument for always specifying lynx-28g is that the serdes blocks
do share a common programming model and register definitions.
>
> Also, I will limit the driver support for the "fsl,lynx-28g" compatible
> to just 1GbE and 10GbE. The 25GbE feature introduced by this series will
> require a more precise compatible string.
Okay
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-08 14:02 ` Josua Mayer
@ 2025-09-08 15:37 ` Vladimir Oltean
2025-09-08 16:04 ` Josua Mayer
2025-09-08 18:39 ` Conor Dooley
1 sibling, 1 reply; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-08 15:37 UTC (permalink / raw)
To: Josua Mayer
Cc: Conor Dooley, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
On Mon, Sep 08, 2025 at 02:02:35PM +0000, Josua Mayer wrote:
> > My updated plan is to describe the schema rules for the compatible as
> > follows. Is that ok with everyone?
> >
> > properties:
> > compatible:
> > oneOf:
> > - const: fsl,lynx-28g
> > deprecated: true
> > - items:
> > - const: fsl,lx2160a-serdes1
> > - const: fsl,lynx-28g
> > - enum:
> > - fsl,lx2160a-serdes2
> > - fsl,lx2160a-serdes3
> > - fsl,lx2162a-serdes1
> > - fsl,lx2162a-serdes2
> Weak objection, I think this is more complex than it should be.
> Perhaps it was discussed before to keep two compatible strings ...:
>
> properties:
> compatible:
> items:
> - enum:
> - fsl,lx2160a-serdes2
> - fsl,lx2160a-serdes3
> - fsl,lx2162a-serdes1
> - fsl,lx2162a-serdes2
> - const: fsl,lynx-28g
>
> This will cause the dtbs_check to complain about anyone in the future
> using it wrong.
So just that we stay on track, this is what the submitted patch
originally proposed:
properties:
compatible:
oneOf:
- items:
- const: fsl,lynx-28g
- items:
- enum:
- fsl,lx2160a-serdes1
- fsl,lx2160a-serdes2
- fsl,lx2160a-serdes3
- fsl,lx2162a-serdes1
- fsl,lx2162a-serdes2
- const: fsl,lynx-28g
Your proposal is different in the following ways:
- Just compatible = "fsl,lynx-28g" will produce a schema validation error, BUT
- There is no compatible = "fsl,lx2160a-serdes1". I don't understand how
you propose to describe that SerDes.
I realize I've CCed you late on the patches. They are here:
https://lore.kernel.org/lkml/20250904154402.300032-1-vladimir.oltean@nxp.com/
One of Conor's objections was that keeping "fsl,lynx-28g" as a fallback
compatible string may not make sense, and indeed I tried to highlight in
my previous reply that it can lead to incorrect behaviour if SerDes #2
is described in this way.
Further trying to argue that SerDes #2 should have "fsl,lynx-28g" as a
fallback without directly addressing the fact it results in incorrect
behaviour is... strange.
Also, SerDes #3 is not described at all, it's not necessary to introduce
a fallback when it can be described precisely from the start.
> The driver can still probe on fsl,lynx-28g alone for backwards compatibility,
> and you can limit the feature-set as you see fit in such case.
>
> Main argument for always specifying lynx-28g is that the serdes blocks
> do share a common programming model and register definitions.
I think this is the sticking point. The blocks do share a common
programming model, but that model does not give us a way to identify the
supported protocols. You can try to enable a protocol converter that
doesn't exist, and read back the enablement status, and you'll find the
hardware reports it to be enabled (for example PCCC[SXGMIIA_CFG]).
The snippet below is something you can try out and see for yourself (it
will need adaptation depending on kernel revision).
static void lynx_28g_lane_probe_supported(struct lynx_28g_lane *lane)
{
enum lynx_lane_mode lane_mode;
unsigned long supported = 0;
int err;
for (lane_mode = LANE_MODE_UNKNOWN + 1; lane_mode < LANE_MODE_MAX; lane_mode++) {
u32 orig_val, val;
err = lynx_pccr_read(lane, lane_mode, &orig_val);
if (err)
continue;
val = orig_val;
switch (lane_mode) {
case LANE_MODE_1000BASEKX:
val |= PCC8_SGMIIa_KX;
fallthrough;
case LANE_MODE_1000BASEX_SGMII:
val |= PCC8_SGMIIa_CFG;
break;
case LANE_MODE_10GBASER:
case LANE_MODE_10GBASEKR:
val |= PCCC_SXGMIIn_XFI;
fallthrough;
case LANE_MODE_USXGMII:
val |= PCCC_SXGMIIn_CFG;
break;
case LANE_MODE_25GBASER:
case LANE_MODE_25GBASEKR:
val |= PCCD_E25Gn_CFG;
break;
case LANE_MODE_40GBASER_XLAUI:
case LANE_MODE_40GBASEKR4:
val |= PCCE_E40Gn_CFG;
break;
default:
break;
}
err = lynx_pccr_write(lane, lane_mode, val);
if (err)
continue;
err = lynx_pccr_read(lane, lane_mode, &val);
if (err)
continue;
dev_info(&lane->phy->dev, "Protocol %d: PCCR was 0x%x, is 0x%x\n",
lane_mode, orig_val, val);
switch (lane_mode) {
case LANE_MODE_1000BASEKX:
if (val & PCC8_SGMIIa_KX)
supported |= BIT(lane_mode);
fallthrough;
case LANE_MODE_1000BASEX_SGMII:
if (val & PCC8_SGMIIa_CFG)
supported |= BIT(lane_mode);
break;
case LANE_MODE_10GBASER:
case LANE_MODE_10GBASEKR:
if (val & PCCC_SXGMIIn_XFI)
supported |= BIT(lane_mode);
fallthrough;
case LANE_MODE_USXGMII:
if (val & PCCC_SXGMIIn_CFG)
supported |= BIT(lane_mode);
break;
case LANE_MODE_25GBASER:
case LANE_MODE_25GBASEKR:
if (val & PCCD_E25Gn_CFG)
supported |= BIT(lane_mode);
break;
case LANE_MODE_40GBASER_XLAUI:
case LANE_MODE_40GBASEKR4:
if (val & PCCE_E40Gn_CFG)
supported |= BIT(lane_mode);
break;
default:
break;
}
WARN_ON(lynx_pccr_write(lane, lane_mode, orig_val));
}
dev_info(&lane->phy->dev, "Lane supported modes: 0x%lx\n", supported);
}
The fact that SerDes #2 works on the fsl-lx2162a-clearfog.dts is
accidental and doesn't change the fact that describing it as
"fsl,lynx-28g" is wrong. (of course, I stand corrected if someone finds
a way to determine that 10GbE is unsupported on some lanes based on just
the programming model, but I doubt it.)
The only 3 ways to find the list of supported protocols, that are known
to me to work, are:
#1: list them all in the device tree (talking about tens, and the list
is ever-expanding as the driver gets more development). This is by
far the most complex and difficult to maintain solution and my least
preferred.
#2: hardcode them in the driver, based on SerDes compatible string (the
current patch, or variations). This is my preferred variant for
keeping the dt-bindings simple and the
#3: like #2, but distinguish between two "fsl,lynx-28g" instances based
on the "reg" value. This should work fine, as every SerDes block
index is instatiated at a fixed physical address in every SoC (block
#1: 0x1ea0000, #2: 0x1eb0000, #3: 0x1ec0000). It should directly
address your objection, but:
- it also requires dt-bindings maintainers buy-in.
- this method can distinguish features of SerDes i from j, but not
from SoC A vs B. There is an upcoming Lynx 10G driver where we
need the per-SoC capabilities as well, and it would be good to
have the same overall driver and dt-binding structure for both.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-08 15:37 ` Vladimir Oltean
@ 2025-09-08 16:04 ` Josua Mayer
2025-09-09 11:35 ` Vladimir Oltean
0 siblings, 1 reply; 40+ messages in thread
From: Josua Mayer @ 2025-09-08 16:04 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Conor Dooley, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
Am 08.09.25 um 17:37 schrieb Vladimir Oltean:
> On Mon, Sep 08, 2025 at 02:02:35PM +0000, Josua Mayer wrote:
>>> My updated plan is to describe the schema rules for the compatible as
>>> follows. Is that ok with everyone?
>>>
>>> properties:
>>> compatible:
>>> oneOf:
>>> - const: fsl,lynx-28g
>>> deprecated: true
>>> - items:
>>> - const: fsl,lx2160a-serdes1
>>> - const: fsl,lynx-28g
>>> - enum:
missed fsl,lx2160a-serdes1
>>> - fsl,lx2160a-serdes2
>>> - fsl,lx2160a-serdes3
>>> - fsl,lx2162a-serdes1
>>> - fsl,lx2162a-serdes2
>> Weak objection, I think this is more complex than it should be.
>> Perhaps it was discussed before to keep two compatible strings ...:
>>
>> properties:
>> compatible:
>> items:
>> - enum:
>> - fsl,lx2160a-serdes2
>> - fsl,lx2160a-serdes3
>> - fsl,lx2162a-serdes1
>> - fsl,lx2162a-serdes2
>> - const: fsl,lynx-28g
>>
>> This will cause the dtbs_check to complain about anyone in the future
>> using it wrong.
My proposal requires two compatible strings always, or the schema will fail
to validate. Examples:
compatible = "fsl,lynx-28g";
// fails validation but driver can keep supporting it for backwards compatibility
compatible = "fsl,lx2160a-serdes1", "fsl,lynx-28g";
// valid per my proposal, functional with existing driver and future changes.
// this is how you will know it is SD #1
compatible = "fsl,lx2160a-serdes2", "fsl,lynx-28g";
// valid per my proposal, and driver can use it in the future to identify SD #2
The kernel looks in compatible strings for the *first match*.
> So just that we stay on track, this is what the submitted patch
> originally proposed:
>
> properties:
> compatible:
> oneOf:
> - items:
> - const: fsl,lynx-28g
> - items:
> - enum:
> - fsl,lx2160a-serdes1
> - fsl,lx2160a-serdes2
> - fsl,lx2160a-serdes3
> - fsl,lx2162a-serdes1
> - fsl,lx2162a-serdes2
> - const: fsl,lynx-28g
>
> Your proposal is different in the following ways:
- always require 2 compatible strings specified in combination,.
validation fails when fsl,lynx-28g string specified alone.
> - Just compatible = "fsl,lynx-28g" will produce a schema validation error, BUT
>
> - There is no compatible = "fsl,lx2160a-serdes1". I don't understand how
> you propose to describe that SerDes.
copy-paste failure, I intended to list them all, including sd1.
>
> I realize I've CCed you late on the patches. They are here:
> https://lore.kernel.org/lkml/20250904154402.300032-1-vladimir.oltean@nxp.com/
>
> One of Conor's objections was that keeping "fsl,lynx-28g" as a fallback
> compatible string may not make sense, and indeed I tried to highlight in
> my previous reply that it can lead to incorrect behaviour if SerDes #2
> is described in this way.
>
> Further trying to argue that SerDes #2 should have "fsl,lynx-28g" as a
> fallback without directly addressing the fact it results in incorrect
> behaviour is... strange.
>
> Also, SerDes #3 is not described at all, it's not necessary to introduce
> a fallback when it can be described precisely from the start.
>
>> The driver can still probe on fsl,lynx-28g alone for backwards compatibility,
>> and you can limit the feature-set as you see fit in such case.
>>
>> Main argument for always specifying lynx-28g is that the serdes blocks
>> do share a common programming model and register definitions.
> I think this is the sticking point. The blocks do share a common
> programming model, but that model does not give us a way to identify the
> supported protocols. You can try to enable a protocol converter that
> doesn't exist, and read back the enablement status, and you'll find the
> hardware reports it to be enabled (for example PCCC[SXGMIIA_CFG]).
Indeed.
>
> The snippet below is something you can try out and see for yourself (it
> will need adaptation depending on kernel revision).
>
> static void lynx_28g_lane_probe_supported(struct lynx_28g_lane *lane)
> {
> enum lynx_lane_mode lane_mode;
> unsigned long supported = 0;
> int err;
>
> for (lane_mode = LANE_MODE_UNKNOWN + 1; lane_mode < LANE_MODE_MAX; lane_mode++) {
> u32 orig_val, val;
>
> err = lynx_pccr_read(lane, lane_mode, &orig_val);
> if (err)
> continue;
>
> val = orig_val;
>
> switch (lane_mode) {
> case LANE_MODE_1000BASEKX:
> val |= PCC8_SGMIIa_KX;
> fallthrough;
> case LANE_MODE_1000BASEX_SGMII:
> val |= PCC8_SGMIIa_CFG;
> break;
> case LANE_MODE_10GBASER:
> case LANE_MODE_10GBASEKR:
> val |= PCCC_SXGMIIn_XFI;
> fallthrough;
> case LANE_MODE_USXGMII:
> val |= PCCC_SXGMIIn_CFG;
> break;
> case LANE_MODE_25GBASER:
> case LANE_MODE_25GBASEKR:
> val |= PCCD_E25Gn_CFG;
> break;
> case LANE_MODE_40GBASER_XLAUI:
> case LANE_MODE_40GBASEKR4:
> val |= PCCE_E40Gn_CFG;
> break;
> default:
> break;
> }
>
> err = lynx_pccr_write(lane, lane_mode, val);
> if (err)
> continue;
>
> err = lynx_pccr_read(lane, lane_mode, &val);
> if (err)
> continue;
>
> dev_info(&lane->phy->dev, "Protocol %d: PCCR was 0x%x, is 0x%x\n",
> lane_mode, orig_val, val);
>
> switch (lane_mode) {
> case LANE_MODE_1000BASEKX:
> if (val & PCC8_SGMIIa_KX)
> supported |= BIT(lane_mode);
> fallthrough;
> case LANE_MODE_1000BASEX_SGMII:
> if (val & PCC8_SGMIIa_CFG)
> supported |= BIT(lane_mode);
> break;
> case LANE_MODE_10GBASER:
> case LANE_MODE_10GBASEKR:
> if (val & PCCC_SXGMIIn_XFI)
> supported |= BIT(lane_mode);
> fallthrough;
> case LANE_MODE_USXGMII:
> if (val & PCCC_SXGMIIn_CFG)
> supported |= BIT(lane_mode);
> break;
> case LANE_MODE_25GBASER:
> case LANE_MODE_25GBASEKR:
> if (val & PCCD_E25Gn_CFG)
> supported |= BIT(lane_mode);
> break;
> case LANE_MODE_40GBASER_XLAUI:
> case LANE_MODE_40GBASEKR4:
> if (val & PCCE_E40Gn_CFG)
> supported |= BIT(lane_mode);
> break;
> default:
> break;
> }
>
> WARN_ON(lynx_pccr_write(lane, lane_mode, orig_val));
> }
>
> dev_info(&lane->phy->dev, "Lane supported modes: 0x%lx\n", supported);
> }
I did play with those in u-boot trying to derive dt dpmac node status from
protocol converter registers ... ... ...
> The fact that SerDes #2 works on the fsl-lx2162a-clearfog.dts is
> accidental and doesn't change the fact that describing it as
> "fsl,lynx-28g" is wrong.
It works because only the SGMII modes are used on that board.
You can however use this argument to drop driver support for the
lone fsl,lynx-28g compatible string.
> (of course, I stand corrected if someone finds
> a way to determine that 10GbE is unsupported on some lanes based on just
> the programming model, but I doubt it.)
>
> The only 3 ways to find the list of supported protocols, that are known
> to me to work, are:
> #1: list them all in the device tree (talking about tens, and the list
> is ever-expanding as the driver gets more development). This is by
> far the most complex and difficult to maintain solution and my least
> preferred.
> #2: hardcode them in the driver, based on SerDes compatible string (the
> current patch, or variations). This is my preferred variant for
> keeping the dt-bindings simple and the
> #3: like #2, but distinguish between two "fsl,lynx-28g" instances based
> on the "reg" value. This should work fine, as every SerDes block
> index is instatiated at a fixed physical address in every SoC (block
> #1: 0x1ea0000, #2: 0x1eb0000, #3: 0x1ec0000). It should directly
> address your objection, but:
> - it also requires dt-bindings maintainers buy-in.
> - this method can distinguish features of SerDes i from j, but not
> from SoC A vs B. There is an upcoming Lynx 10G driver where we
> need the per-SoC capabilities as well, and it would be good to
> have the same overall driver and dt-binding structure for both.
#4: by listing descriptive phy sub-nodes under the serdes blocks root node.
Presence indicates whether or not a lane is available,
while each node can specify the modes it supports.
Obviously this allows the device-tree author to describe invalid configurations.
But it avoids describing each combination in the driver.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-08 16:04 ` Josua Mayer
@ 2025-09-09 11:35 ` Vladimir Oltean
2025-09-09 18:35 ` Conor Dooley
` (2 more replies)
0 siblings, 3 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-09 11:35 UTC (permalink / raw)
To: Josua Mayer
Cc: Conor Dooley, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
On Mon, Sep 08, 2025 at 04:04:45PM +0000, Josua Mayer wrote:
> Am 08.09.25 um 17:37 schrieb Vladimir Oltean:
> > On Mon, Sep 08, 2025 at 02:02:35PM +0000, Josua Mayer wrote:
> >>> My updated plan is to describe the schema rules for the compatible as
> >>> follows. Is that ok with everyone?
> >>>
> >>> properties:
> >>> compatible:
> >>> oneOf:
> >>> - const: fsl,lynx-28g
> >>> deprecated: true
> >>> - items:
> >>> - const: fsl,lx2160a-serdes1
> >>> - const: fsl,lynx-28g
> >>> - enum:
> missed fsl,lx2160a-serdes1
I didn't miss anything. "fsl,lx2160a-serdes1" is deliberately not in
"enum" because there's no point specifying this compatible as
standalone, if for backwards compatibility reasons it will always have
to be "fsl,lx2160a-serdes1", "fsl,lynx-28g" (it was described as
"fsl,lynx-28g" before), which is already covered by "items".
> >>> - fsl,lx2160a-serdes2
> >>> - fsl,lx2160a-serdes3
> >>> - fsl,lx2162a-serdes1
> >>> - fsl,lx2162a-serdes2
> >> Weak objection, I think this is more complex than it should be.
> >> Perhaps it was discussed before to keep two compatible strings ...:
> >>
> >> properties:
> >> compatible:
> >> items:
> >> - enum:
> >> - fsl,lx2160a-serdes2
> >> - fsl,lx2160a-serdes3
> >> - fsl,lx2162a-serdes1
> >> - fsl,lx2162a-serdes2
> >> - const: fsl,lynx-28g
> >>
> >> This will cause the dtbs_check to complain about anyone in the future
> >> using it wrong.
> My proposal requires two compatible strings always, or the schema will fail
> to validate. Examples:
>
> compatible = "fsl,lynx-28g";
> // fails validation but driver can keep supporting it for backwards compatibility
>
> compatible = "fsl,lx2160a-serdes1", "fsl,lynx-28g";
> // valid per my proposal, functional with existing driver and future changes.
No, not valid per your proposal, there is no "fsl,lx2160a-serdes1" in it.
But verbally I got the point. What you propose is only different from
the patch that I submitted in that you're saying let's drop schema
support for the lone "fsl,lynx-28g".
Our proposals are fundamentally different in this aspect: to you,
"fsl,lynx-28g" means the general register layout and programming model.
To me, it specifically means LX2160A SerDes #1. We have to agree which
one is it.
So, generally I do agree that either one of:
- compatible = "fsl,lx2160a-serdes1" or
- compatible = "fsl,lynx-28g" + explicit protocol listing for each lane
are sufficient hardware descriptions, but as a matter of practicality I
prefer to keep only obviously correct information in the device tree,
which is only sufficient for the expert level details to go in the
driver, where they are much easier to fix if wrong.
The current "fsl,lynx-28g" definition and use does _not_ have explicit
protocol listing per lane, so unless it is interpreted as meaning a
synonym for one particular SerDes instance, it becomes even more
meaningless with current device trees.
> // this is how you will know it is SD #1
>
> compatible = "fsl,lx2160a-serdes2", "fsl,lynx-28g";
> // valid per my proposal, and driver can use it in the future to identify SD #2
>
> The kernel looks in compatible strings for the *first match*.
>
> > So just that we stay on track, this is what the submitted patch
> > originally proposed:
> >
> > properties:
> > compatible:
> > oneOf:
> > - items:
> > - const: fsl,lynx-28g
> > - items:
> > - enum:
> > - fsl,lx2160a-serdes1
> > - fsl,lx2160a-serdes2
> > - fsl,lx2160a-serdes3
> > - fsl,lx2162a-serdes1
> > - fsl,lx2162a-serdes2
> > - const: fsl,lynx-28g
> >
> > Your proposal is different in the following ways:
> - always require 2 compatible strings specified in combination,.
> validation fails when fsl,lynx-28g string specified alone.
> > - Just compatible = "fsl,lynx-28g" will produce a schema validation error, BUT
> >
> > - There is no compatible = "fsl,lx2160a-serdes1". I don't understand how
> > you propose to describe that SerDes.
> copy-paste failure, I intended to list them all, including sd1.
ok.
> > The fact that SerDes #2 works on the fsl-lx2162a-clearfog.dts is
> > accidental and doesn't change the fact that describing it as
> > "fsl,lynx-28g" is wrong.
>
> It works because only the SGMII modes are used on that board.
Yes, which qualifies as "accidental", considering that the SoC dtsi
describes two non-identical blocks as identical.
> You can however use this argument to drop driver support for the
> lone fsl,lynx-28g compatible string.
I'm not going to do that. There is a big difference in the two uses,
which is that "fsl,lynx-28g" is problematic for SerDes #2 but isn't so
for SerDes #1.
Accepting "fsl,lx216*a-serdes2", "fsl,lynx-28g" in the schema would mean
the two are compatible, which they are not.
Keeping driver support for the lone "fsl,lynx-28g" (treating it as
SerDes #1) would mean newer kernels would continue to work on
non-updated fsl-lx2162a-clearfog.dts, but updating the device tree would
require updating the kernel. I think you implicitly gave an ack for that
here:
https://lore.kernel.org/lkml/02270f62-9334-400c-b7b9-7e6a44dbbfc9@solid-run.com/
|I don't think you need to fix a downstream dtb via the driver.
|If downstream user can update the kernel, they can update the dtb also,
|to resolve their own bugs.
> > (of course, I stand corrected if someone finds
> > a way to determine that 10GbE is unsupported on some lanes based on just
> > the programming model, but I doubt it.)
> >
> > The only 3 ways to find the list of supported protocols, that are known
> > to me to work, are:
> > #1: list them all in the device tree (talking about tens, and the list
> > is ever-expanding as the driver gets more development). This is by
> > far the most complex and difficult to maintain solution and my least
> > preferred.
> > #2: hardcode them in the driver, based on SerDes compatible string (the
> > current patch, or variations). This is my preferred variant for
> > keeping the dt-bindings simple and the
> > #3: like #2, but distinguish between two "fsl,lynx-28g" instances based
> > on the "reg" value. This should work fine, as every SerDes block
> > index is instatiated at a fixed physical address in every SoC (block
> > #1: 0x1ea0000, #2: 0x1eb0000, #3: 0x1ec0000). It should directly
> > address your objection, but:
> > - it also requires dt-bindings maintainers buy-in.
> > - this method can distinguish features of SerDes i from j, but not
> > from SoC A vs B. There is an upcoming Lynx 10G driver where we
> > need the per-SoC capabilities as well, and it would be good to
> > have the same overall driver and dt-binding structure for both.
> #4: by listing descriptive phy sub-nodes under the serdes blocks root node.
So in which way is #4 fundamentally different than #1, other than
slightly different organization of information?
Generally I disagree with requiring board device tree authors to
maintain the protocol list - it should rather reside in the SoC dtsi,
because the driver is able to automatically further restrict to the
valid set of each board, through lynx_28g_pll_read_configuration().
So I'm only ever going to consider this if the protocol listing is done
only once, in the SoC dtsi.
> Presence indicates whether or not a lane is available,
> while each node can specify the modes it supports.
You mean "lane is available" as in "LX2162A SerDes #1 only has lanes 4-7
available as an SoC parameterisation option", or as in "this board only
uses SerDes lanes A and B"?
If the former, then yes, maybe. If the latter - I don't think this is
compatible with my idea of describing SerDes lanes in the SoC dtsi.
> Obviously this allows the device-tree author to describe invalid configurations.
> But it avoids describing each combination in the driver.
I see "describing each combination in the driver" as literally the
smallest of problems. It is just a little bit of extra code and a few
tables, located a few tens of lines above the code that implements those
same features in the same driver.
Compare that to listing protocols in the device tree, which may be
distributed through entirely different channels than the kernel, so it
involves an ABI contract to obey.
It's really a matter of humbly admitting that I don't know what I don't
know - I would very much want to avoid the logistical nightmare of
having to update device trees again when new things are discovered.
I've seen your proposal map out on the Lynx 10G SerDes, and it would
look like this:
https://lore.kernel.org/linux-phy/20230413160607.4128315-3-sean.anderson@seco.com/
You can hardly consider it "KISS" when the device tree specifies what
value should be written to what PCCR register for what protocol.
What you seem to want (customize electrical parameters per lane) doesn't
seem to need what you're asking for (listing supported protocols in the
device tree per lane).
This is mostly because we're _not_ going to add "fsl,eq-amp-red",
"fsl,eq-adaptive" etc as you seem to imply here:
https://lore.kernel.org/lkml/02270f62-9334-400c-b7b9-7e6a44dbbfc9@solid-run.com/
- i.e. shoving device tree values into hardware registers. We will
instead define a vendor-agnostic method of specifying equalizer
attenuations in decibels for each tap, and somehow translate that in the
driver into LNaTECR0/ LNaTECR1 register values. See for instance how
Documentation/devicetree/bindings/phy/transmit-amplitude.yaml defines
"tx-p2p-microvolt", and which is a starting point for programming the
AMP_RED field. That property already has "tx-p2p-microvolt-names" per
SerDes protocol (or so it should be - no idea what's with "xgmii"), so
there should be no reason to link this with custom "fsl,lane-protocol"
values or whatever.
It's completely fair to say that currently I have no idea how to
translate standard measurement units into register values, and I'd have
to ask the hardware validation team for formulas. But if you were to
imagine yourself as a user rather than as a developer, I think it's
pretty clear which option you would choose.
Anyway, I don't see why the above can be future extensions, and aren't
my main preoccupation right now. For now we just need to sort out the
lane capability detection per SerDes.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-09 11:35 ` Vladimir Oltean
@ 2025-09-09 18:35 ` Conor Dooley
2025-09-09 18:58 ` Vladimir Oltean
2025-09-16 17:07 ` Vladimir Oltean
2025-09-17 10:47 ` Josua Mayer
2 siblings, 1 reply; 40+ messages in thread
From: Conor Dooley @ 2025-09-09 18:35 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Josua Mayer, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
[-- Attachment #1.1: Type: text/plain, Size: 1256 bytes --]
On Tue, Sep 09, 2025 at 02:35:43PM +0300, Vladimir Oltean wrote:
> On Mon, Sep 08, 2025 at 04:04:45PM +0000, Josua Mayer wrote:
> > Am 08.09.25 um 17:37 schrieb Vladimir Oltean:
> > > On Mon, Sep 08, 2025 at 02:02:35PM +0000, Josua Mayer wrote:
> > >>> My updated plan is to describe the schema rules for the compatible as
> > >>> follows. Is that ok with everyone?
> > >>>
> > >>> properties:
> > >>> compatible:
> > >>> oneOf:
> > >>> - const: fsl,lynx-28g
> > >>> deprecated: true
> > >>> - items:
> > >>> - const: fsl,lx2160a-serdes1
> > >>> - const: fsl,lynx-28g
> > >>> - enum:
> > missed fsl,lx2160a-serdes1
>
> I didn't miss anything. "fsl,lx2160a-serdes1" is deliberately not in
> "enum" because there's no point specifying this compatible as
> standalone, if for backwards compatibility reasons it will always have
> to be "fsl,lx2160a-serdes1", "fsl,lynx-28g" (it was described as
> "fsl,lynx-28g" before), which is already covered by "items".
I think Josua was pointing out their own omission here.
> > >>> - fsl,lx2160a-serdes2
> > >>> - fsl,lx2160a-serdes3
> > >>> - fsl,lx2162a-serdes1
> > >>> - fsl,lx2162a-serdes2
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-09 18:35 ` Conor Dooley
@ 2025-09-09 18:58 ` Vladimir Oltean
0 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-09 18:58 UTC (permalink / raw)
To: Conor Dooley
Cc: Josua Mayer, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
On Tue, Sep 09, 2025 at 07:35:43PM +0100, Conor Dooley wrote:
> On Tue, Sep 09, 2025 at 02:35:43PM +0300, Vladimir Oltean wrote:
> > On Mon, Sep 08, 2025 at 04:04:45PM +0000, Josua Mayer wrote:
> > > Am 08.09.25 um 17:37 schrieb Vladimir Oltean:
> > > > On Mon, Sep 08, 2025 at 02:02:35PM +0000, Josua Mayer wrote:
> > > >>> My updated plan is to describe the schema rules for the compatible as
> > > >>> follows. Is that ok with everyone?
> > > >>>
> > > >>> properties:
> > > >>> compatible:
> > > >>> oneOf:
> > > >>> - const: fsl,lynx-28g
> > > >>> deprecated: true
> > > >>> - items:
> > > >>> - const: fsl,lx2160a-serdes1
> > > >>> - const: fsl,lynx-28g
> > > >>> - enum:
> > > missed fsl,lx2160a-serdes1
> >
> > I didn't miss anything. "fsl,lx2160a-serdes1" is deliberately not in
> > "enum" because there's no point specifying this compatible as
> > standalone, if for backwards compatibility reasons it will always have
> > to be "fsl,lx2160a-serdes1", "fsl,lynx-28g" (it was described as
> > "fsl,lynx-28g" before), which is already covered by "items".
>
> I think Josua was pointing out their own omission here.
Maybe, but the quoted text was my proposal.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-09 11:35 ` Vladimir Oltean
2025-09-09 18:35 ` Conor Dooley
@ 2025-09-16 17:07 ` Vladimir Oltean
2025-09-17 10:47 ` Josua Mayer
2 siblings, 0 replies; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-16 17:07 UTC (permalink / raw)
To: Josua Mayer
Cc: Conor Dooley, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
Hi Josua,
On Tue, Sep 09, 2025 at 02:35:43PM +0300, Vladimir Oltean wrote:
> I've seen your proposal map out on the Lynx 10G SerDes, and it would
> look like this:
> https://lore.kernel.org/linux-phy/20230413160607.4128315-3-sean.anderson@seco.com/
> You can hardly consider it "KISS" when the device tree specifies what
> value should be written to what PCCR register for what protocol.
...
> Anyway, I don't see why the above can be future extensions, and aren't
> my main preoccupation right now. For now we just need to sort out the
> lane capability detection per SerDes.
Do you have any further feedback? I would like to keep the ball rolling
and submit a new version. One thing I could do is I could require
#phy-cells to be 0 when using one of the new compatibles like
"fsl,lx2160a-serdes1", and 1 when "fsl,lynx-28g" is found.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-09 11:35 ` Vladimir Oltean
2025-09-09 18:35 ` Conor Dooley
2025-09-16 17:07 ` Vladimir Oltean
@ 2025-09-17 10:47 ` Josua Mayer
2 siblings, 0 replies; 40+ messages in thread
From: Josua Mayer @ 2025-09-17 10:47 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Conor Dooley, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
Am 09.09.25 um 13:35 schrieb Vladimir Oltean:
> On Mon, Sep 08, 2025 at 04:04:45PM +0000, Josua Mayer wrote:
>> Am 08.09.25 um 17:37 schrieb Vladimir Oltean:
>>> On Mon, Sep 08, 2025 at 02:02:35PM +0000, Josua Mayer wrote:
>>>>> My updated plan is to describe the schema rules for the compatible as
>>>>> follows. Is that ok with everyone?
>>>>>
>>>>> properties:
>>>>> compatible:
>>>>> oneOf:
>>>>> - const: fsl,lynx-28g
>>>>> deprecated: true
>>>>> - items:
>>>>> - const: fsl,lx2160a-serdes1
>>>>> - const: fsl,lynx-28g
>>>>> - enum:
>> missed fsl,lx2160a-serdes1
> I didn't miss anything. "fsl,lx2160a-serdes1" is deliberately not in
> "enum" because there's no point specifying this compatible as
> standalone, if for backwards compatibility reasons it will always have
> to be "fsl,lx2160a-serdes1", "fsl,lynx-28g" (it was described as
> "fsl,lynx-28g" before), which is already covered by "items".
>
>>>>> - fsl,lx2160a-serdes2
>>>>> - fsl,lx2160a-serdes3
>>>>> - fsl,lx2162a-serdes1
>>>>> - fsl,lx2162a-serdes2
>>>> Weak objection, I think this is more complex than it should be.
>>>> Perhaps it was discussed before to keep two compatible strings ...:
>>>>
>>>> properties:
>>>> compatible:
>>>> items:
>>>> - enum:
>>>> - fsl,lx2160a-serdes2
>>>> - fsl,lx2160a-serdes3
>>>> - fsl,lx2162a-serdes1
>>>> - fsl,lx2162a-serdes2
>>>> - const: fsl,lynx-28g
>>>>
>>>> This will cause the dtbs_check to complain about anyone in the future
>>>> using it wrong.
>> My proposal requires two compatible strings always, or the schema will fail
>> to validate. Examples:
>>
>> compatible = "fsl,lynx-28g";
>> // fails validation but driver can keep supporting it for backwards compatibility
>>
>> compatible = "fsl,lx2160a-serdes1", "fsl,lynx-28g";
>> // valid per my proposal, functional with existing driver and future changes.
> No, not valid per your proposal, there is no "fsl,lx2160a-serdes1" in it.
> But verbally I got the point. What you propose is only different from
> the patch that I submitted in that you're saying let's drop schema
> support for the lone "fsl,lynx-28g".
>
> Our proposals are fundamentally different in this aspect: to you,
> "fsl,lynx-28g" means the general register layout and programming model.
> To me, it specifically means LX2160A SerDes #1. We have to agree which
> one is it.
>
> So, generally I do agree that either one of:
> - compatible = "fsl,lx2160a-serdes1" or
> - compatible = "fsl,lynx-28g" + explicit protocol listing for each lane
> are sufficient hardware descriptions, but as a matter of practicality I
> prefer to keep only obviously correct information in the device tree,
> which is only sufficient for the expert level details to go in the
> driver, where they are much easier to fix if wrong.
>
> The current "fsl,lynx-28g" definition and use does _not_ have explicit
> protocol listing per lane, so unless it is interpreted as meaning a
> synonym for one particular SerDes instance, it becomes even more
> meaningless with current device trees.
>
>> // this is how you will know it is SD #1
>>
>> compatible = "fsl,lx2160a-serdes2", "fsl,lynx-28g";
>> // valid per my proposal, and driver can use it in the future to identify SD #2
>>
>> The kernel looks in compatible strings for the *first match*.
>>
>>> So just that we stay on track, this is what the submitted patch
>>> originally proposed:
>>>
>>> properties:
>>> compatible:
>>> oneOf:
>>> - items:
>>> - const: fsl,lynx-28g
>>> - items:
>>> - enum:
>>> - fsl,lx2160a-serdes1
>>> - fsl,lx2160a-serdes2
>>> - fsl,lx2160a-serdes3
>>> - fsl,lx2162a-serdes1
>>> - fsl,lx2162a-serdes2
>>> - const: fsl,lynx-28g
>>>
>>> Your proposal is different in the following ways:
>> - always require 2 compatible strings specified in combination,.
>> validation fails when fsl,lynx-28g string specified alone.
>>> - Just compatible = "fsl,lynx-28g" will produce a schema validation error, BUT
>>>
>>> - There is no compatible = "fsl,lx2160a-serdes1". I don't understand how
>>> you propose to describe that SerDes.
>> copy-paste failure, I intended to list them all, including sd1.
> ok.
>
>>> The fact that SerDes #2 works on the fsl-lx2162a-clearfog.dts is
>>> accidental and doesn't change the fact that describing it as
>>> "fsl,lynx-28g" is wrong.
>> It works because only the SGMII modes are used on that board.
> Yes, which qualifies as "accidental", considering that the SoC dtsi
> describes two non-identical blocks as identical.
>
>> You can however use this argument to drop driver support for the
>> lone fsl,lynx-28g compatible string.
> I'm not going to do that. There is a big difference in the two uses,
> which is that "fsl,lynx-28g" is problematic for SerDes #2 but isn't so
> for SerDes #1.
>
> Accepting "fsl,lx216*a-serdes2", "fsl,lynx-28g" in the schema would mean
> the two are compatible
No, it means they share a programming model and are compatible to a degree.
> , which they are
absolutely (by register map), and partially as implemented in LX2 SoCs.
> not.
>
> Keeping driver support for the lone "fsl,lynx-28g" (treating it as
> SerDes #1) would mean newer kernels would continue to work on
> non-updated fsl-lx2162a-clearfog.dts, but updating the device tree would
> require updating the kernel. I think you implicitly gave an ack for that
> here:
> https://lore.kernel.org/lkml/02270f62-9334-400c-b7b9-7e6a44dbbfc9@solid-run.com/
>
> |I don't think you need to fix a downstream dtb via the driver.
> |If downstream user can update the kernel, they can update the dtb also,
> |to resolve their own bugs.
Correct.
As far as solidrun layerscape boards, it is currently fine to require dtb upgrade with kernel.
>
>>> (of course, I stand corrected if someone finds
>>> a way to determine that 10GbE is unsupported on some lanes based on just
>>> the programming model, but I doubt it.)
>>>
>>> The only 3 ways to find the list of supported protocols, that are known
>>> to me to work, are:
>>> #1: list them all in the device tree (talking about tens, and the list
>>> is ever-expanding as the driver gets more development). This is by
>>> far the most complex and difficult to maintain solution and my least
>>> preferred.
>>> #2: hardcode them in the driver, based on SerDes compatible string (the
>>> current patch, or variations). This is my preferred variant for
>>> keeping the dt-bindings simple and the
>>> #3: like #2, but distinguish between two "fsl,lynx-28g" instances based
>>> on the "reg" value. This should work fine, as every SerDes block
>>> index is instatiated at a fixed physical address in every SoC (block
>>> #1: 0x1ea0000, #2: 0x1eb0000, #3: 0x1ec0000). It should directly
>>> address your objection, but:
>>> - it also requires dt-bindings maintainers buy-in.
>>> - this method can distinguish features of SerDes i from j, but not
>>> from SoC A vs B. There is an upcoming Lynx 10G driver where we
>>> need the per-SoC capabilities as well, and it would be good to
>>> have the same overall driver and dt-binding structure for both.
>> #4: by listing descriptive phy sub-nodes under the serdes blocks root node.
> So in which way is #4 fundamentally different than #1, other than
> slightly different organization of information?
That is the difference exactly.
> Generally I disagree with requiring board device tree authors to
> maintain the protocol list
> - it should rather reside in the SoC dtsi,
agree.
> because the driver is able to automatically further restrict to the
> valid set of each board, through lynx_28g_pll_read_configuration().
correct. The Soc dtsi may however spell out the full list in dts.
> So I'm only ever going to consider this if the protocol listing is done
> only once, in the SoC dtsi.
fair.
>> Presence indicates whether or not a lane is available,
>> while each node can specify the modes it supports.
> You mean "lane is available" as in "LX2162A SerDes #1 only has lanes 4-7
> available as an SoC parameterisation option", or as in "this board only
> uses SerDes lanes A and B"?
The former.
>
> If the former, then yes, maybe. If the latter - I don't think this is
> compatible with my idea of describing SerDes lanes in the SoC dtsi.
>
>> Obviously this allows the device-tree author to describe invalid configurations.
>> But it avoids describing each combination in the driver.
> I see "describing each combination in the driver" as literally the
> smallest of problems. It is just a little bit of extra code and a few
> tables, located a few tens of lines above the code that implements those
> same features in the same driver.
>
> Compare that to listing protocols in the device tree, which may be
> distributed through entirely different channels than the kernel, so it
> involves an ABI contract to obey.
>
> It's really a matter of humbly admitting that I don't know what I don't
> know - I would very much want to avoid the logistical nightmare of
> having to update device trees again when new things are discovered.
>
> I've seen your proposal map out on the Lynx 10G SerDes, and it would
> look like this:
> https://lore.kernel.org/linux-phy/20230413160607.4128315-3-sean.anderson@seco.com/
> You can hardly consider it "KISS" when the device tree specifies what
> value should be written to what PCCR register for what protocol.
>
> What you seem to want (customize electrical parameters per lane) doesn't
> seem to need what you're asking for (listing supported protocols in the
> device tree per lane).
>
> This is mostly because we're _not_ going to add "fsl,eq-amp-red",
> "fsl,eq-adaptive" etc as you seem to imply here:
> https://lore.kernel.org/lkml/02270f62-9334-400c-b7b9-7e6a44dbbfc9@solid-run.com/
> - i.e. shoving device tree values into hardware registers. We will
> instead define a vendor-agnostic method of specifying equalizer
> attenuations in decibels for each tap, and somehow translate that in the
> driver into LNaTECR0/ LNaTECR1 register values. See for instance how
> Documentation/devicetree/bindings/phy/transmit-amplitude.yaml defines
> "tx-p2p-microvolt", and which is a starting point for programming the
> AMP_RED field. That property already has "tx-p2p-microvolt-names" per
> SerDes protocol (or so it should be - no idea what's with "xgmii"), so
> there should be no reason to link this with custom "fsl,lane-protocol"
> values or whatever.
You are correct, I anticipated putting the equalization parameters
as described by NXP documentation as magic (commented) numbers
in device-tree.
And the tuning process to derive those per docs I had seen involves
testing all combinations against test patterns to find the optimal combination(s).
Very often we can't create an accurate description for the electrical properties
of a board, so it is more natural to specify the compensation parameters.
>
> It's completely fair to say that currently I have no idea how to
> translate standard measurement units into register values, and I'd have
> to ask the hardware validation team for formulas. But if you were to
> imagine yourself as a user rather than as a developer, I think it's
> pretty clear which option you would choose.
>
> Anyway, I don't see why the above can be future extensions, and aren't
> my main preoccupation right now. For now we just need to sort out the
> lane capability detection per SerDes.
As Conor would accept either model, it is your choice.
I do not have any strong objection - the outcomes are workable either way.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2025-09-08 14:02 ` Josua Mayer
2025-09-08 15:37 ` Vladimir Oltean
@ 2025-09-08 18:39 ` Conor Dooley
1 sibling, 0 replies; 40+ messages in thread
From: Conor Dooley @ 2025-09-08 18:39 UTC (permalink / raw)
To: Josua Mayer
Cc: Vladimir Oltean, Krzysztof Kozlowski, Krzysztof Kozlowski,
linux-phy@lists.infradead.org, Ioana Ciornei, Vinod Koul,
Kishon Vijay Abraham I, linux-kernel@vger.kernel.org, Rob Herring,
Conor Dooley, devicetree@vger.kernel.org
[-- Attachment #1.1: Type: text/plain, Size: 7223 bytes --]
On Mon, Sep 08, 2025 at 02:02:35PM +0000, Josua Mayer wrote:
>
> Am 08.09.25 um 11:37 schrieb Vladimir Oltean:
> > On Fri, Sep 05, 2025 at 08:02:59PM +0100, Conor Dooley wrote:
> >> On Fri, Sep 05, 2025 at 06:41:50PM +0300, Vladimir Oltean wrote:
> >>> On Fri, Sep 05, 2025 at 10:29:33AM +0200, Krzysztof Kozlowski wrote:
> >>>>> properties:
> >>>>> compatible:
> >>>>> - enum:
> >>>>> - - fsl,lynx-28g
> >>>>> + oneOf:
> >>>>> + - items:
> >>>>> + - const: fsl,lynx-28g
> >>>> Don't change that part. Previous enum was correct. You want oneOf and
> >>>> enum.
> >>> Combining the feedback from Conor and Josua, I should only be permitting
> >>> the use of "fsl,lynx-28g" as a fallback to "fsl,lx216{0,2}a-serdes{1,2}",
> >>> or standalone. The description below achieves just that. Does it look ok
> >>> to you?
> >>>
> >>> properties:
> >>> compatible:
> >>> oneOf:
> >>> - enum:
> >>> - fsl,lx2160a-serdes1
> >>> - fsl,lx2160a-serdes2
> >>> - fsl,lx2160a-serdes3
> >>> - fsl,lx2162a-serdes1
> >>> - fsl,lx2162a-serdes2
> >>> - const: fsl,lynx-28g
> >>> deprecated: true
> >>> - items:
> >>> - const: fsl,lx2160a-serdes1
> >>> - const: fsl,lynx-28g
> >>> deprecated: true
> >>> - items:
> >>> - const: fsl,lx2160a-serdes2
> >>> - const: fsl,lynx-28g
> >>> deprecated: true
> >>> - items:
> >>> - const: fsl,lx2162a-serdes1
> >>> - const: fsl,lynx-28g
> >>> deprecated: true
> >>> - items:
> >>> - const: fsl,lx2162a-serdes2
> >>> - const: fsl,lynx-28g
> >>> deprecated: true
> >> This doesn't really make sense, none of these are currently in use
> >> right? Everything is just using fsl,lynx-28g right?
> >> Adding new stuff and immediately marking it deprecated is a
> >> contradiction, just don't add it at all if you don't want people using
> >> it. Any users of it would be something you're going to retrofit in now,
> >> so you may as well just retrofit to use what you want people to use
> >> going forward, which has no fallbacks.
> > You're right that it doesn't make sense to deprecate a newly introduced
> > compatible string pair - my mistake for misunderstanding "deprecated".
> >
> >> I didn't read the back and forth with Josua (sorry!) but is the fallback
> >> even valid? Do those devices have a common minimum set of features that
> >> they share?
> > I'll try to make an argument based on the facts presented below.
> >
> > The current Linux driver, which recognizes only "fsl,lynx-28g", supports
> > only 1GbE and 10GbE. There are other SerDes protocols supported by the
> > SerDes, but they are irrelevant for the purpose of discussing
> > compatibility. Also, LX2160A SerDes #3 is also irrelevant, because it is
> > not currently described in the device tree.
> >
> > 1GbE compatibility table
> >
> > SerDes Lane 0 Lane 1 Lane 2 Lane 3 Lane 4 Lane 5 Lane 6 Lane 7 Comments
> > LX2160A SerDes #1 y y y y y y y y
> > LX2160A SerDes #2 y y y y y y y y
> > LX2162A SerDes #1 n/a n/a n/a n/a y y y y LX2162A currently uses lx2160a.dtsi
> > LX2162A SerDes #2 y y y y y y y y LX2162A currently uses lx2160a.dtsi
> >
> > 10GbE compatibility table
> >
> > SerDes Lane 0 Lane 1 Lane 2 Lane 3 Lane 4 Lane 5 Lane 6 Lane 7 Comments
> > LX2160A SerDes #1 y y y y y y y y
> > LX2160A SerDes #2 n n n n n n y y
> > LX2162A SerDes #1 n/a n/a n/a n/a y y y y LX2162A currently uses lx2160a.dtsi
> > LX2162A SerDes #2 n n n n n n y y LX2162A currently uses lx2160a.dtsi
> >
> > As LX2160A SerDes #2 is treated like #1, the device tree is telling the
> > driver that all lanes support 10GbE (which is false for lanes 0-5).
> >
> > If one of the SerDes PLLs happens to be provisioned for the 10GbE clock
> > net frequency, as for example with the RCW[SRDS_PRTCL_S2]=6 setting,
> > this will make the driver think that it can reconfigure lanes 0-5 as
> > 10GbE.
> >
> > This will directly affect upper layers (phylink), which will advertise
> > 10GbE modes to its link partner on ports which support only 1GbE, and
> > the non-functional link mode might be resolved through negotiation, when
> > a lower speed but functional link could have been established.
> >
> > You mention a common minimum feature set. That would be supporting 10GbE
> > only on lanes 6-7, which would be disadvantageous to existing uses of
> > 10GbE on lanes 0-5 of SerDes #1. In some cases, the change might also be
> > breaking - there might be a PHY attached to these lanes whose firmware
> > is hardcoded to expect 10GbE, so there won't be a graceful degradation
> > to 1GbE in all cases.
> >
> > With Josua's permission, I would consider commit 2f2900176b44 ("arm64:
> > dts: lx2160a: describe the SerDes block #2") as broken, for being an
> > incorrect description of hardware - it is presented as identical to
> > another device, which has a different supported feature set. I will not
> > try to keep SerDes #2 compatible with "fsl,lynx-28g". This will remain
> > synonymous only with SerDes #1. The users of the fsl-lx2162a-clearfog.dts
> > will need updating if the "undetected lack of support for 10GbE" becomes
> > an issue.
> >
> > My updated plan is to describe the schema rules for the compatible as
> > follows. Is that ok with everyone?
> >
> > properties:
> > compatible:
> > oneOf:
> > - const: fsl,lynx-28g
> > deprecated: true
> > - items:
> > - const: fsl,lx2160a-serdes1
> > - const: fsl,lynx-28g
> > - enum:
> > - fsl,lx2160a-serdes2
> > - fsl,lx2160a-serdes3
> > - fsl,lx2162a-serdes1
> > - fsl,lx2162a-serdes2
> Weak objection, I think this is more complex than it should be.
> Perhaps it was discussed before to keep two compatible strings ...:
>
> properties:
> compatible:
> items:
> - enum:
> - fsl,lx2160a-serdes2
> - fsl,lx2160a-serdes3
> - fsl,lx2162a-serdes1
> - fsl,lx2162a-serdes2
> - const: fsl,lynx-28g
>
> This will cause the dtbs_check to complain about anyone in the future
> using it wrong.
>
> The driver can still probe on fsl,lynx-28g alone for backwards compatibility,
> and you can limit the feature-set as you see fit in such case.
>
> Main argument for always specifying lynx-28g is that the serdes blocks
> do share a common programming model and register definitions.
FWIW, I'd accept both of what's been proposed here with the
justifications being provided. Up to you guys that understand the
hardware to decide what's more suitable.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH phy 14/14] phy: lynx-28g: probe on per-SoC and per-instance compatible strings
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
` (12 preceding siblings ...)
2025-09-04 15:44 ` [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
@ 2025-09-04 15:44 ` Vladimir Oltean
2025-09-05 10:41 ` Ioana Ciornei
13 siblings, 1 reply; 40+ messages in thread
From: Vladimir Oltean @ 2025-09-04 15:44 UTC (permalink / raw)
To: linux-phy
Cc: Ioana Ciornei, Vinod Koul, Kishon Vijay Abraham I, linux-kernel,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree
There are 3 SerDes blocks on LX2160A and 2 on LX2162A, and they differ
in some aspects, namely in the number of lanes per SerDes and in the
protocol converters instantiated per lane.
All of this justifies introducing compatible strings for each SerDes and
some driver structures for figuring out the differences. The
"fsl,lynx-28g" compatible string is kind of the "maximal configuration".
It corresponds to SerDes 1 of LX2160A. If we were to treat all SerDes
blocks like this one, we would access lanes which do not exist (0-3) and
we would fail to reject lane modes which don't work.
Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 97 +++++++++++++++++++++++-
1 file changed, 93 insertions(+), 4 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 91a3b3928ab4..991587c453df 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -479,9 +479,18 @@ struct lynx_28g_lane {
enum lynx_lane_mode mode;
};
+struct lynx_info {
+ int (*get_pccr)(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr);
+ int (*get_pcvt_offset)(int lane, enum lynx_lane_mode mode);
+ bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
+ int first_lane;
+};
+
struct lynx_28g_priv {
void __iomem *base;
struct device *dev;
+ const struct lynx_info *info;
/* Serialize concurrent access to registers shared between lanes,
* like PCCn
*/
@@ -800,6 +809,79 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
}
}
+static bool lx2160a_serdes1_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return true;
+}
+
+static bool lx2160a_serdes2_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return true;
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ return lane == 6 || lane == 7;
+ default:
+ return false;
+ }
+}
+
+static bool lx2160a_serdes3_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ /*
+ * Non-networking SerDes, and this driver supports only
+ * networking protocols
+ */
+ return false;
+}
+
+static bool lx2162a_serdes1_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return true;
+}
+
+static bool lx2162a_serdes2_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return lx2160a_serdes2_lane_supports_mode(lane, mode);
+}
+
+static const struct lynx_info lynx_info_lx2160a_serdes1 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2160a_serdes1_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2160a_serdes2 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2160a_serdes2_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2160a_serdes3 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2160a_serdes3_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2162a_serdes1 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2162a_serdes1_lane_supports_mode,
+ .first_lane = 4,
+};
+
+static const struct lynx_info lynx_info_lx2162a_serdes2 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2162a_serdes2_lane_supports_mode,
+};
+
static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode,
u32 *val)
{
@@ -1202,7 +1284,7 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
u32 rrstctl;
int i;
- for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
lane = &priv->lane[i];
mutex_lock(&lane->phy->mutex);
@@ -1258,7 +1340,8 @@ static struct phy *lynx_28g_xlate(struct device *dev,
struct lynx_28g_priv *priv = dev_get_drvdata(dev);
int idx = args->args[0];
- if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
+ if (WARN_ON(idx >= LYNX_28G_NUM_LANE ||
+ idx < priv->info->first_lane))
return ERR_PTR(-EINVAL);
return priv->lane[idx].phy;
@@ -1275,6 +1358,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->dev = &pdev->dev;
+ priv->info = of_device_get_match_data(dev);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
@@ -1282,7 +1366,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
lynx_28g_pll_read_configuration(priv);
- for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
struct lynx_28g_lane *lane = &priv->lane[i];
struct phy *phy;
@@ -1322,7 +1406,12 @@ static void lynx_28g_remove(struct platform_device *pdev)
}
static const struct of_device_id lynx_28g_of_match_table[] = {
- { .compatible = "fsl,lynx-28g" },
+ { .compatible = "fsl,lx2160a-serdes1", .data = &lynx_info_lx2160a_serdes1 },
+ { .compatible = "fsl,lx2160a-serdes2", .data = &lynx_info_lx2160a_serdes2 },
+ { .compatible = "fsl,lx2160a-serdes3", .data = &lynx_info_lx2160a_serdes3 },
+ { .compatible = "fsl,lx2162a-serdes1", .data = &lynx_info_lx2162a_serdes1 },
+ { .compatible = "fsl,lx2162a-serdes2", .data = &lynx_info_lx2162a_serdes2 },
+ { .compatible = "fsl,lynx-28g", .data = &lynx_info_lx2160a_serdes1 }, /* fallback */
{ },
};
MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 40+ messages in thread* Re: [PATCH phy 14/14] phy: lynx-28g: probe on per-SoC and per-instance compatible strings
2025-09-04 15:44 ` [PATCH phy 14/14] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Vladimir Oltean
@ 2025-09-05 10:41 ` Ioana Ciornei
0 siblings, 0 replies; 40+ messages in thread
From: Ioana Ciornei @ 2025-09-05 10:41 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, Vinod Koul, Kishon Vijay Abraham I, linux-kernel,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree
On Thu, Sep 04, 2025 at 06:44:02PM +0300, Vladimir Oltean wrote:
> There are 3 SerDes blocks on LX2160A and 2 on LX2162A, and they differ
> in some aspects, namely in the number of lanes per SerDes and in the
> protocol converters instantiated per lane.
>
> All of this justifies introducing compatible strings for each SerDes and
> some driver structures for figuring out the differences. The
> "fsl,lynx-28g" compatible string is kind of the "maximal configuration".
> It corresponds to SerDes 1 of LX2160A. If we were to treat all SerDes
> blocks like this one, we would access lanes which do not exist (0-3) and
> we would fail to reject lane modes which don't work.
>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> drivers/phy/freescale/phy-fsl-lynx-28g.c | 97 +++++++++++++++++++++++-
> 1 file changed, 93 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
> index 91a3b3928ab4..991587c453df 100644
> --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
> +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
> @@ -479,9 +479,18 @@ struct lynx_28g_lane {
> enum lynx_lane_mode mode;
> };
>
> +struct lynx_info {
> + int (*get_pccr)(enum lynx_lane_mode lane_mode, int lane,
> + struct lynx_pccr *pccr);
> + int (*get_pcvt_offset)(int lane, enum lynx_lane_mode mode);
> + bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
> + int first_lane;
> +};
> +
> struct lynx_28g_priv {
> void __iomem *base;
> struct device *dev;
> + const struct lynx_info *info;
> /* Serialize concurrent access to registers shared between lanes,
> * like PCCn
> */
> @@ -800,6 +809,79 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
> }
> }
>
> +static bool lx2160a_serdes1_lane_supports_mode(int lane,
> + enum lynx_lane_mode mode)
> +{
> + return true;
> +}
The SerDes block#1 does have one limitations - 25G is supported on all
lanes except 2 and 3.
This is the only restriction that I discovered looking through the list
of supported SerDes 1 protocol combinations.
Ioana
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 40+ messages in thread