From: Vladimir Oltean Date: Wed, 10 Jun 2026 15:19:40 +0000 (+0300) Subject: phy: lynx-28g: move data structures to core X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=b7021a4d3129aeb0e25c3edcaf3a36199e73f652;p=thirdparty%2Fkernel%2Flinux.git phy: lynx-28g: move data structures to core 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 Link: https://patch.msgid.link/20260610151952.2141019-5-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index d3f49d96340fd..570fa74daba08 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 */ @@ -1440,6 +1384,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 d56f189c162dc..de45b14d3fb60 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 fe15986482b0e..f0cb3e8052350 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -7,18 +7,82 @@ #include #include +#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