[PATCH phy-next 03/13] phy: lynx-28g: move data structures to core
From: Vladimir Oltean
Date: Thu May 28 2026 - 13:30:20 EST
The goal is to avoid duplicating the core data structures when
introducing the new lynx-10g driver.
We move the following to phy-fsl-lynx-core:
- struct lynx_28g_pll -> struct lynx_pll. This has some
hardware-specific register fields which need to become hardware
agnostic (the PLL register layout is different for Lynx 10G), So:
- PLLnRSTCTL_DIS(pll->rstctl) becomes !pll->enabled
- PLLnRSTCTL_LOCK(pll->rstctl) becomes pll->locked
- FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1) becomes pll->frate_sel
- FIELD_GET(PLLnCR0_REFCLK_SEL, pll->cr0) becomes pll->refclk_sel
- struct lynx_28g_lane -> struct lynx_lane
- struct lynx_28g_priv -> struct lynx_priv
- field lane[LYNX_28G_NUM_LANE] has to be dynamically allocated. Not
all Lynx 10G SerDes blocks have 8 lanes.
- LYNX_28G_NUM_PLL -> LYNX_NUM_PLL. This is an architectural constant
which is the same for Lynx 10G as well.
To avoid major noise in the lynx-28g driver, we keep compatibility shims
(for now) where the old lynx_28g names are preserved, but translate to
the common data structures.
Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 135 +++++++---------------
drivers/phy/freescale/phy-fsl-lynx-core.c | 23 ++++
drivers/phy/freescale/phy-fsl-lynx-core.h | 64 ++++++++++
3 files changed, 129 insertions(+), 93 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 0f7814b7224c..bca0db162a95 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -12,7 +12,7 @@
#include "phy-fsl-lynx-core.h"
#define LYNX_28G_NUM_LANE 8
-#define LYNX_28G_NUM_PLL 2
+#define LYNX_28G_NUM_PLL LYNX_NUM_PLL
/* SoC IP wrapper for protocol converters */
#define PCC8 0x10a0
@@ -43,8 +43,8 @@
/* Per PLL registers */
#define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
-#define PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
-#define PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
+#define PLLnRSTCTL_DIS BIT(24)
+#define PLLnRSTCTL_LOCK BIT(23)
#define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
#define PLLnCR0_REFCLK_SEL GENMASK(20, 16)
@@ -269,6 +269,17 @@
#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
+#define lynx_28g_pll_read lynx_pll_read
+
+#define lynx_28g_priv lynx_priv
+#define lynx_28g_lane lynx_lane
+#define lynx_28g_pll lynx_pll
+
enum lynx_28g_eq_type {
EQ_TYPE_NO_EQ = 0,
EQ_TYPE_2TAP = 1,
@@ -456,86 +467,6 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
},
};
-struct lynx_28g_priv;
-
-struct lynx_28g_pll {
- struct lynx_28g_priv *priv;
- u32 rstctl, cr0, cr1;
- int id;
- DECLARE_BITMAP(supported, LANE_MODE_MAX);
-};
-
-struct lynx_28g_lane {
- struct lynx_28g_priv *priv;
- struct phy *phy;
- bool powered_up;
- bool init;
- unsigned int id;
- enum lynx_lane_mode mode;
-};
-
-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
- */
- spinlock_t pcc_lock;
- struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];
- struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];
-
- struct delayed_work cdr_check;
-};
-
-static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
- u32 val, u32 mask)
-{
- void __iomem *reg = priv->base + off;
- u32 orig, tmp;
-
- orig = ioread32(reg);
- tmp = orig & ~mask;
- tmp |= val;
- 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) \
- 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))
-
-/* A lane mode is supported if we have a PLL that can provide its required
- * clock net, and if there is a protocol converter for that mode on that lane.
- */
-static bool lynx_28g_supports_lane_mode(struct lynx_28g_lane *lane,
- enum lynx_lane_mode mode)
-{
- struct lynx_28g_priv *priv = lane->priv;
- int i;
-
- if (!priv->info->lane_supports_mode(lane->id, mode))
- return false;
-
- for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
- if (PLLnRSTCTL_DIS(priv->pll[i].rstctl))
- continue;
-
- if (test_bit(mode, priv->pll[i].supported))
- return true;
- }
-
- return false;
-}
-
static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
enum lynx_lane_mode mode)
{
@@ -545,7 +476,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 (PLLnRSTCTL_DIS(pll->rstctl))
+ if (!pll->enabled)
continue;
if (test_bit(mode, pll->supported))
@@ -553,7 +484,7 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
}
/* no pll supports requested mode, either caller forgot to check
- * lynx_28g_supports_lane_mode, or this is a bug.
+ * lynx_lane_supports_mode(), or this is a bug.
*/
dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n",
lynx_lane_mode_str(mode));
@@ -564,7 +495,7 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll,
enum lynx_lane_mode lane_mode)
{
- switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ switch (pll->frate_sel) {
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
switch (lane_mode) {
@@ -879,27 +810,33 @@ static bool lynx_28g_compat_lane_supports_mode(int lane,
static const struct lynx_info lynx_info_compat = {
.lane_supports_mode = lynx_28g_compat_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2160a_serdes1 = {
.lane_supports_mode = lx2160a_serdes1_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2160a_serdes2 = {
.lane_supports_mode = lx2160a_serdes2_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2160a_serdes3 = {
.lane_supports_mode = lx2160a_serdes3_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2162a_serdes1 = {
.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 = {
.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,
@@ -1168,7 +1105,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
return -EOPNOTSUPP;
lane_mode = phy_interface_to_lane_mode(submode);
- if (!lynx_28g_supports_lane_mode(lane, lane_mode))
+ if (!lynx_lane_supports_mode(lane, lane_mode))
return -EOPNOTSUPP;
if (lane_mode == lane->mode)
@@ -1210,7 +1147,7 @@ static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
return -EOPNOTSUPP;
lane_mode = phy_interface_to_lane_mode(submode);
- if (!lynx_28g_supports_lane_mode(lane, lane_mode))
+ if (!lynx_lane_supports_mode(lane, lane_mode))
return -EOPNOTSUPP;
return 0;
@@ -1262,6 +1199,7 @@ static const struct phy_ops lynx_28g_ops = {
static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
{
struct lynx_28g_pll *pll;
+ u32 val;
int i;
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
@@ -1269,14 +1207,20 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
pll->priv = priv;
pll->id = i;
- pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);
- pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
- pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
+ val = lynx_28g_pll_read(pll, PLLnRSTCTL);
+ pll->enabled = !(val & PLLnRSTCTL_DIS);
+ pll->locked = !!(val & PLLnRSTCTL_LOCK);
- if (PLLnRSTCTL_DIS(pll->rstctl))
+ val = lynx_28g_pll_read(pll, PLLnCR0);
+ pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val);
+
+ val = lynx_28g_pll_read(pll, PLLnCR1);
+ pll->frate_sel = FIELD_GET(PLLnCR1_FRATE_SEL, val);
+
+ if (!pll->enabled)
continue;
- switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ switch (pll->frate_sel) {
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
/* 5GHz clock net */
@@ -1437,6 +1381,11 @@ static int lynx_28g_probe(struct platform_device *pdev)
if (priv->info == &lynx_info_compat)
dev_warn(dev, "Please update device tree to use per-device compatible strings\n");
+ priv->lane = devm_kcalloc(dev, priv->info->num_lanes,
+ sizeof(*priv->lane), GFP_KERNEL);
+ if (!priv->lane)
+ return -ENOMEM;
+
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c
index d56f189c162d..de45b14d3fb6 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.c
@@ -40,5 +40,28 @@ enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
}
EXPORT_SYMBOL_NS_GPL(phy_interface_to_lane_mode, "PHY_FSL_LYNX");
+/* A lane mode is supported if we have a PLL that can provide its required
+ * clock net, and if there is a protocol converter for that mode on that lane.
+ */
+bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode)
+{
+ struct lynx_priv *priv = lane->priv;
+ int i;
+
+ if (!priv->info->lane_supports_mode(lane->id, mode))
+ return false;
+
+ for (i = 0; i < LYNX_NUM_PLL; i++) {
+ if (!priv->pll[i].enabled)
+ continue;
+
+ if (test_bit(mode, priv->pll[i].supported))
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_NS_GPL(lynx_lane_supports_mode, "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 fe15986482b0..f0cb3e805235 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.h
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.h
@@ -7,18 +7,82 @@
#include <linux/phy.h>
#include <soc/fsl/phy-fsl-lynx.h>
+#define LYNX_NUM_PLL 2
+
struct lynx_pccr {
int offset;
int width;
int shift;
};
+struct lynx_priv;
+
+struct lynx_pll {
+ struct lynx_priv *priv;
+ int id;
+ int refclk_sel;
+ int frate_sel;
+ bool enabled;
+ bool locked;
+ DECLARE_BITMAP(supported, LANE_MODE_MAX);
+};
+
+struct lynx_lane {
+ struct lynx_priv *priv;
+ struct phy *phy;
+ bool powered_up;
+ bool init;
+ unsigned int id;
+ enum lynx_lane_mode mode;
+};
+
struct lynx_info {
bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
int first_lane;
+ int num_lanes;
};
+struct lynx_priv {
+ void __iomem *base;
+ struct device *dev;
+ const struct lynx_info *info;
+ /* Serialize concurrent access to registers shared between lanes,
+ * like PCCn
+ */
+ spinlock_t pcc_lock;
+ struct lynx_pll pll[LYNX_NUM_PLL];
+ struct lynx_lane *lane;
+
+ struct delayed_work cdr_check;
+};
+
+static inline void lynx_rmw(struct lynx_priv *priv, unsigned long off, u32 val,
+ u32 mask)
+{
+ void __iomem *reg = priv->base + off;
+ u32 orig, tmp;
+
+ orig = ioread32(reg);
+ tmp = orig & ~mask;
+ tmp |= val;
+ iowrite32(tmp, reg);
+}
+
+#define lynx_read(priv, off) \
+ ioread32((priv)->base + (off))
+#define lynx_write(priv, off, val) \
+ iowrite32(val, (priv)->base + (off))
+#define lynx_lane_rmw(lane, reg, val, mask) \
+ lynx_rmw((lane)->priv, reg(lane->id), val, mask)
+#define lynx_lane_read(lane, reg) \
+ ioread32((lane)->priv->base + reg((lane)->id))
+#define lynx_lane_write(lane, reg, val) \
+ iowrite32(val, (lane)->priv->base + reg((lane)->id))
+#define lynx_pll_read(pll, reg) \
+ ioread32((pll)->priv->base + reg((pll)->id))
+
const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode);
enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf);
+bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode);
#endif
--
2.34.1