[PATCH phy-next 10/13] phy: lynx-28g: add support for big endian register maps

From: Vladimir Oltean

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


Some 10G Lynx SerDes blocks are big endian and require byte swapping
because the CPUs are little endian armv8 (LS1046A). Parse the
"big-endian" device tree property, and modify the base lynx_read() and
lynx_write() accessors to test this property before issuing either the
ioread32() or ioread32be() variants (as per
Documentation/driver-api/device-io.rst).

All other accessors - lynx_rmw(), lynx_lane_read(), lynx_lane_write(),
lynx_lane_rmw(), lynx_pll_read() - need to go through these endian-aware
helpers.

Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx>
---
drivers/phy/freescale/phy-fsl-lynx-core.c | 1 +
drivers/phy/freescale/phy-fsl-lynx-core.h | 36 ++++++++++++++++-------
2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c
index bd1cd78e80bb..ca523e59b167 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.c
@@ -292,6 +292,7 @@ int lynx_probe(struct platform_device *pdev, const struct lynx_info *info,

priv->dev = dev;
priv->info = info;
+ priv->big_endian = device_property_read_bool(dev, "big-endian");
dev_set_drvdata(dev, priv);
spin_lock_init(&priv->pcc_lock);
INIT_DELAYED_WORK(&priv->cdr_check, lynx_cdr_lock_check);
diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h
index e8b280cc9b38..d82e529fa65a 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.h
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.h
@@ -58,36 +58,52 @@ struct lynx_priv {
* like PCCn
*/
spinlock_t pcc_lock;
+ bool big_endian;
struct lynx_pll pll[LYNX_NUM_PLL];
struct lynx_lane *lane;

struct delayed_work cdr_check;
};

+static inline u32 lynx_read(struct lynx_priv *priv, unsigned long off)
+{
+ void __iomem *reg = priv->base + off;
+
+ if (priv->big_endian)
+ return ioread32be(reg);
+
+ return ioread32(reg);
+}
+
+static inline void lynx_write(struct lynx_priv *priv, unsigned long off, u32 val)
+{
+ void __iomem *reg = priv->base + off;
+
+ if (priv->big_endian)
+ return iowrite32be(val, reg);
+
+ return iowrite32(val, reg);
+}
+
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);
+ orig = lynx_read(priv, off);
tmp = orig & ~mask;
tmp |= val;
- iowrite32(tmp, reg);
+ lynx_write(priv, off, tmp);
}

-#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))
+ lynx_read((lane)->priv, reg((lane)->id))
#define lynx_lane_write(lane, reg, val) \
- iowrite32(val, (lane)->priv->base + reg((lane)->id))
+ lynx_write((lane)->priv, reg((lane)->id), val)
#define lynx_pll_read(pll, reg) \
- ioread32((pll)->priv->base + reg((pll)->id))
+ lynx_read((pll)->priv, reg((pll)->id))

int lynx_probe(struct platform_device *pdev, const struct lynx_info *info,
const struct phy_ops *phy_ops);
--
2.34.1