[PATCH phy-next 05/13] phy: lynx-28g: generalize protocol converter accessors

From: Vladimir Oltean

Date: Thu May 28 2026 - 13:24:41 EST


The protocol converters on the 10G Lynx are architecturally similar, but
different in layout from the 28G Lynx ones.

Move lynx_pccr_read(), lynx_pccr_write(), lynx_pcvt_read() and
lynx_pcvt_write() from the 28G Lynx driver to the common module, and
permit each SerDes driver to provide just its own bits in order to use
this common API.

Currently, that just means that the direct calls to
lynx_28g_get_pcvt_offset() are modified to go through the
lynx->info->get_pcvt_offset() indirect function call, and similarly,
lynx_28g_get_pccr() through lynx->info->get_pccr().

Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 102 +++-------------------
drivers/phy/freescale/phy-fsl-lynx-core.c | 90 +++++++++++++++++++
drivers/phy/freescale/phy-fsl-lynx-core.h | 13 +++
3 files changed, 115 insertions(+), 90 deletions(-)

diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index ab36df000804..84dce3026efc 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -269,8 +269,6 @@
#define LYNX_28G_LANE_STOP_SLEEP_US 100
#define LYNX_28G_LANE_STOP_TIMEOUT_US 1000000

-#define lynx_28g_read lynx_read
-#define lynx_28g_write lynx_write
#define lynx_28g_lane_rmw lynx_lane_rmw
#define lynx_28g_lane_read lynx_lane_read
#define lynx_28g_lane_write lynx_lane_write
@@ -785,124 +783,48 @@ static bool lynx_28g_compat_lane_supports_mode(int lane,
}

static const struct lynx_info lynx_info_compat = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
.lane_supports_mode = lynx_28g_compat_lane_supports_mode,
.num_lanes = LYNX_28G_NUM_LANE,
};

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,
.num_lanes = LYNX_28G_NUM_LANE,
};

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,
.num_lanes = LYNX_28G_NUM_LANE,
};

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,
.num_lanes = LYNX_28G_NUM_LANE,
};

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,
.num_lanes = LYNX_28G_NUM_LANE,
};

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,
.num_lanes = LYNX_28G_NUM_LANE,
};

-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)
-{
- struct lynx_28g_priv *priv = lane->priv;
- struct lynx_pccr pccr;
- u32 old, tmp, mask;
- int err;
-
- err = lynx_28g_get_pccr(lane_mode, 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,
- 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, lane_mode);
- if (offset < 0)
- return offset;
-
- *val = lynx_28g_read(priv, offset + cr);
-
- return 0;
-}
-
-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, lane_mode);
- if (offset < 0)
- return offset;
-
- lynx_28g_write(priv, offset + cr, val);
-
- return 0;
-}
-
-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, lane_mode, cr, &tmp);
- if (err)
- return err;
-
- tmp &= ~mask;
- tmp |= val;
-
- return lynx_pcvt_write(lane, lane_mode, cr, tmp);
-}
-
static void lynx_28g_lane_remap_pll(struct lynx_28g_lane *lane,
enum lynx_lane_mode lane_mode)
{
diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c
index 5e5bcaa54d09..f49d594622cb 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.c
@@ -87,5 +87,95 @@ struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode)
}
EXPORT_SYMBOL_NS_GPL(lynx_pll_get, "PHY_FSL_LYNX");

+int lynx_pccr_read(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 *val)
+{
+ struct lynx_priv *priv = lane->priv;
+ struct lynx_pccr pccr;
+ u32 tmp;
+ int err;
+
+ err = priv->info->get_pccr(mode, lane->id, &pccr);
+ if (err)
+ return err;
+
+ tmp = lynx_read(priv, pccr.offset);
+ *val = (tmp >> pccr.shift) & GENMASK(pccr.width - 1, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(lynx_pccr_read, "PHY_FSL_LYNX");
+
+int lynx_pccr_write(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 val)
+{
+ struct lynx_priv *priv = lane->priv;
+ struct lynx_pccr pccr;
+ u32 old, tmp, mask;
+ int err;
+
+ err = priv->info->get_pccr(mode, lane->id, &pccr);
+ if (err)
+ return err;
+
+ old = lynx_read(priv, pccr.offset);
+ mask = GENMASK(pccr.width - 1, 0) << pccr.shift;
+ tmp = (old & ~mask) | (val << pccr.shift);
+ lynx_write(priv, pccr.offset, tmp);
+
+ dev_dbg(&lane->phy->dev, "PCCR@0x%x: 0x%x -> 0x%x\n",
+ pccr.offset, old, tmp);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(lynx_pccr_write, "PHY_FSL_LYNX");
+
+int lynx_pcvt_read(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr,
+ u32 *val)
+{
+ struct lynx_priv *priv = lane->priv;
+ int offset;
+
+ offset = priv->info->get_pcvt_offset(lane->id, mode);
+ if (offset < 0)
+ return offset;
+
+ *val = lynx_read(priv, offset + cr);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(lynx_pcvt_read, "PHY_FSL_LYNX");
+
+int lynx_pcvt_write(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr,
+ u32 val)
+{
+ struct lynx_priv *priv = lane->priv;
+ int offset;
+
+ offset = priv->info->get_pcvt_offset(lane->id, mode);
+ if (offset < 0)
+ return offset;
+
+ lynx_write(priv, offset + cr, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(lynx_pcvt_write, "PHY_FSL_LYNX");
+
+int lynx_pcvt_rmw(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr,
+ u32 val, u32 mask)
+{
+ int err;
+ u32 tmp;
+
+ err = lynx_pcvt_read(lane, mode, cr, &tmp);
+ if (err)
+ return err;
+
+ tmp &= ~mask;
+ tmp |= val;
+
+ return lynx_pcvt_write(lane, mode, cr, tmp);
+}
+EXPORT_SYMBOL_NS_GPL(lynx_pcvt_rmw, "PHY_FSL_LYNX");
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality");
diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h
index b726ff21972b..5cd86c9543cb 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.h
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.h
@@ -4,6 +4,7 @@
#ifndef _PHY_FSL_LYNX_CORE_H
#define _PHY_FSL_LYNX_CORE_H

+#include <linux/phy/phy.h>
#include <linux/phy.h>
#include <soc/fsl/phy-fsl-lynx.h>

@@ -37,6 +38,9 @@ struct lynx_lane {
};

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;
int num_lanes;
@@ -87,4 +91,13 @@ bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode);

struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode);

+int lynx_pccr_read(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 *val);
+int lynx_pccr_write(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 val);
+int lynx_pcvt_read(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr,
+ u32 *val);
+int lynx_pcvt_write(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr,
+ u32 val);
+int lynx_pcvt_rmw(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr,
+ u32 val, u32 mask);
+
#endif
--
2.34.1