]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
phy: lynx-28g: move data structures to core
authorVladimir Oltean <vladimir.oltean@nxp.com>
Wed, 10 Jun 2026 15:19:40 +0000 (18:19 +0300)
committerVinod Koul <vkoul@kernel.org>
Thu, 11 Jun 2026 07:09:46 +0000 (12:39 +0530)
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@nxp.com>
Link: https://patch.msgid.link/20260610151952.2141019-5-vladimir.oltean@nxp.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/freescale/phy-fsl-lynx-28g.c
drivers/phy/freescale/phy-fsl-lynx-core.c
drivers/phy/freescale/phy-fsl-lynx-core.h

index d3f49d96340fd749173f6024ee43db72e59feb09..570fa74daba0889f97efd9adfabf654506ea9623 100644 (file)
@@ -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)
 #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);
index d56f189c162dcb0221668d698f150a903f8e6475..de45b14d3fb60ae7c3a08960a9a390d5b392084f 100644 (file)
@@ -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");
index fe15986482b0e1be3316b1f24aa9348a6903471a..f0cb3e80523507dc89b370a03c85604cc1e375b1 100644 (file)
@@ -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