[PATCH v2 phy-next 02/15] phy: lynx-28g: move lane mode helpers to new core module

From: Vladimir Oltean

Date: Fri May 29 2026 - 13:17:06 EST


Do some preparation work for the introduction of the lynx-10g driver,
which will share a common backbone with the 28G Lynx SerDes.

This is just trivial stuff which can be moved without any surgery, and
is easy to follow but otherwise pollutes more serious changes.

The lane modes themselves are exported to a public header, because on
the 10G Lynx, the hardware requires implementing a procedure called
"RCW override". This requires coordination with drivers/soc/fsl/guts.c
to tell it that a SerDes lane needs to be switched to a different
protocol (enum lynx_lane_mode).

Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx>
---
v1->v2: none
---
drivers/phy/freescale/Kconfig | 7 +++
drivers/phy/freescale/Makefile | 1 +
drivers/phy/freescale/phy-fsl-lynx-28g.c | 56 ++---------------------
drivers/phy/freescale/phy-fsl-lynx-core.c | 44 ++++++++++++++++++
drivers/phy/freescale/phy-fsl-lynx-core.h | 24 ++++++++++
include/soc/fsl/phy-fsl-lynx.h | 16 +++++++
6 files changed, 95 insertions(+), 53 deletions(-)
create mode 100644 drivers/phy/freescale/phy-fsl-lynx-core.c
create mode 100644 drivers/phy/freescale/phy-fsl-lynx-core.h
create mode 100644 include/soc/fsl/phy-fsl-lynx.h

diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index 81f53564ee15..a87429f634ea 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -51,11 +51,18 @@ config PHY_FSL_SAMSUNG_HDMI_PHY
Enable this to add support for the Samsung HDMI PHY in i.MX8MP.
endif

+config PHY_FSL_LYNX_CORE
+ tristate
+ help
+ Enable this to add common support code for NXP Lynx 10G and Lynx 28G
+ SerDes blocks.
+
config PHY_FSL_LYNX_28G
tristate "Freescale Layerscape Lynx 28G SerDes PHY support"
depends on OF
depends on ARCH_LAYERSCAPE || COMPILE_TEST
select GENERIC_PHY
+ select PHY_FSL_LYNX_CORE
help
Enable this to add support for the Lynx SerDes 28G PHY as
found on NXP's Layerscape platforms such as LX2160A.
diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
index 658eac7d0a62..d7aa62cdeb39 100644
--- a/drivers/phy/freescale/Makefile
+++ b/drivers/phy/freescale/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o
obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o
obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o
obj-$(CONFIG_PHY_FSL_IMX8QM_HSIO) += phy-fsl-imx8qm-hsio.o
+obj-$(CONFIG_PHY_FSL_LYNX_CORE) += phy-fsl-lynx-core.o
obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o
obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 4461b47a16ad..27587ad87f22 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -9,6 +9,8 @@
#include <linux/platform_device.h>
#include <linux/workqueue.h>

+#include "phy-fsl-lynx-core.h"
+
#define LYNX_28G_NUM_LANE 8
#define LYNX_28G_NUM_PLL 2

@@ -282,15 +284,6 @@ enum lynx_28g_proto_sel {
PROTO_SEL_25G_50G_100G = 0x1a,
};

-enum lynx_lane_mode {
- LANE_MODE_UNKNOWN,
- LANE_MODE_1000BASEX_SGMII,
- LANE_MODE_10GBASER,
- LANE_MODE_USXGMII,
- LANE_MODE_25GBASER,
- LANE_MODE_MAX,
-};
-
struct lynx_28g_proto_conf {
/* LNaGCR0 */
int proto_sel;
@@ -463,12 +456,6 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
},
};

-struct lynx_pccr {
- int offset;
- int width;
- int shift;
-};
-
struct lynx_28g_priv;

struct lynx_28g_pll {
@@ -487,11 +474,6 @@ struct lynx_28g_lane {
enum lynx_lane_mode mode;
};

-struct lynx_info {
- bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
- int first_lane;
-};
-
struct lynx_28g_priv {
void __iomem *base;
struct device *dev;
@@ -531,39 +513,6 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
#define lynx_28g_pll_read(pll, reg) \
ioread32((pll)->priv->base + reg((pll)->id))

-static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
-{
- switch (lane_mode) {
- case LANE_MODE_1000BASEX_SGMII:
- return "1000Base-X/SGMII";
- case LANE_MODE_10GBASER:
- return "10GBase-R";
- case LANE_MODE_USXGMII:
- return "USXGMII";
- case LANE_MODE_25GBASER:
- return "25GBase-R";
- default:
- return "unknown";
- }
-}
-
-static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
-{
- switch (intf) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- return LANE_MODE_1000BASEX_SGMII;
- case PHY_INTERFACE_MODE_10GBASER:
- return LANE_MODE_10GBASER;
- case PHY_INTERFACE_MODE_USXGMII:
- return LANE_MODE_USXGMII;
- case PHY_INTERFACE_MODE_25GBASER:
- return LANE_MODE_25GBASER;
- default:
- return LANE_MODE_UNKNOWN;
- }
-}
-
/* 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.
*/
@@ -1572,6 +1521,7 @@ static struct platform_driver lynx_28g_driver = {
};
module_platform_driver(lynx_28g_driver);

+MODULE_IMPORT_NS("PHY_FSL_LYNX");
MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@xxxxxxx>");
MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c
new file mode 100644
index 000000000000..d56f189c162d
--- /dev/null
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright 2025-2026 NXP */
+
+#include <linux/module.h>
+
+#include "phy-fsl-lynx-core.h"
+
+const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return "1000Base-X/SGMII";
+ case LANE_MODE_10GBASER:
+ return "10GBase-R";
+ case LANE_MODE_USXGMII:
+ return "USXGMII";
+ case LANE_MODE_25GBASER:
+ return "25GBase-R";
+ default:
+ return "unknown";
+ }
+}
+EXPORT_SYMBOL_NS_GPL(lynx_lane_mode_str, "PHY_FSL_LYNX");
+
+enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
+{
+ switch (intf) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LANE_MODE_1000BASEX_SGMII;
+ case PHY_INTERFACE_MODE_10GBASER:
+ return LANE_MODE_10GBASER;
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LANE_MODE_USXGMII;
+ case PHY_INTERFACE_MODE_25GBASER:
+ return LANE_MODE_25GBASER;
+ default:
+ return LANE_MODE_UNKNOWN;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(phy_interface_to_lane_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
new file mode 100644
index 000000000000..fe15986482b0
--- /dev/null
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright 2025-2026 NXP */
+
+#ifndef _PHY_FSL_LYNX_CORE_H
+#define _PHY_FSL_LYNX_CORE_H
+
+#include <linux/phy.h>
+#include <soc/fsl/phy-fsl-lynx.h>
+
+struct lynx_pccr {
+ int offset;
+ int width;
+ int shift;
+};
+
+struct lynx_info {
+ bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
+ int first_lane;
+};
+
+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);
+
+#endif
diff --git a/include/soc/fsl/phy-fsl-lynx.h b/include/soc/fsl/phy-fsl-lynx.h
new file mode 100644
index 000000000000..92e8272d5ae1
--- /dev/null
+++ b/include/soc/fsl/phy-fsl-lynx.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright 2023-2026 NXP */
+
+#ifndef __PHY_FSL_LYNX_H_
+#define __PHY_FSL_LYNX_H_
+
+enum lynx_lane_mode {
+ LANE_MODE_UNKNOWN,
+ LANE_MODE_1000BASEX_SGMII,
+ LANE_MODE_10GBASER,
+ LANE_MODE_USXGMII,
+ LANE_MODE_25GBASER,
+ LANE_MODE_MAX,
+};
+
+#endif /* __PHY_FSL_LYNX_H_ */
--
2.34.1