* [PATCH phy-next 0/5] Lynx 28G SerDes: 25GbE support
@ 2026-05-11 15:00 Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 1/5] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Vladimir Oltean @ 2026-05-11 15:00 UTC (permalink / raw)
To: linux-phy
Cc: netdev, Ioana Ciornei, Vinod Koul, Neil Armstrong, Josua Mayer,
linux-kernel
This is the remainder of "Lynx 28G improvements part 2", previously
submitted here:
https://lore.kernel.org/linux-phy/176850672122.1082429.444623229961712368.robh@kernel.org/
but split up into smaller portions (merged separately):
- https://lore.kernel.org/linux-phy/20260226182853.1103616-1-vladimir.oltean@nxp.com/
- https://lore.kernel.org/linux-phy/20260321011451.1557091-1-vladimir.oltean@nxp.com/
What remains is the highlight feature (patch 5/5): support for dynamic
protocol changes to/from 25GBase-R, required by SFP28 modules. These are
used with the NXP LX2160A and the (Ethernet) dpaa2-mac consumer.
Patches 1-4 handle the following situation: with current device trees,
the driver will think 25GBase-R will work on a lane, but it may work or
may not. This is because not all lanes support this protocol. So we
modify the SerDes compatible strings to identify them, and we use a
driver-internal database to figure out on which lanes does each SerDes
instance support this protocol.
On current device trees, 25GbE is not supported.
Detailed change log in patches. Summary:
- reworded commit messages
- change match condition from dt-bindings change 2/5
- patch 3/5 is new (reject probing on devices with no OF node)
Ioana Ciornei (1):
phy: lynx-28g: add support for 25GBASER
Vladimir Oltean (4):
dt-bindings: phy: lynx-28g: add compatible strings per SerDes and
instantiation
dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices
phy: lynx-28g: require an OF node to probe
phy: lynx-28g: probe on per-SoC and per-instance compatible strings
.../devicetree/bindings/phy/fsl,lynx-28g.yaml | 48 +++-
drivers/phy/freescale/phy-fsl-lynx-28g.c | 221 +++++++++++++++++-
2 files changed, 254 insertions(+), 15 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH phy-next 1/5] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation
2026-05-11 15:00 [PATCH phy-next 0/5] Lynx 28G SerDes: 25GbE support Vladimir Oltean
@ 2026-05-11 15:00 ` Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 2/5] dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices Vladimir Oltean
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Vladimir Oltean @ 2026-05-11 15:00 UTC (permalink / raw)
To: linux-phy
Cc: netdev, Ioana Ciornei, Vinod Koul, Neil Armstrong, Josua Mayer,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree
The 28G Lynx SerDes is instantiated 3 times in the NXP LX2160A SoC and
twice in the NXP LX2162A. All these instances share the same register
map, but the number of lanes and the protocols supported by each lane
differs in a way that isn't detectable by the programming model.
For example, not all lanes of all SerDes block instantiations support
25GbE.
So, using a generic "fsl,lynx-28g" compatible string and expecting all
SerDes instantiations to use it was a mistake that needs to be fixed.
The option chosen is to encode the SoC and the SerDes instance in the
compatible string, with everything else being the responsibility of the
driver to derive.
An alternative considered but dismissed was to add sufficient device
tree properties to describe the per-lane differences (implying:
supported protocols), as well as the different lane count.
Any decision made for the 28G Lynx should be consistent with the
decisions taken for the yet-to-be-introduced 10G Lynx SerDes (older
generation for older SoCs), because of how similar they are.
I've seen the alternative at play in this unmerged patch set for the 10G
Lynx here, and I didn't like it:
https://lore.kernel.org/linux-phy/20230413160607.4128315-3-sean.anderson@seco.com/
This is because there, we have a higher degree of variability in the
PCCR register values that need to be written per protocol. This makes
that approach more drawn-out and more prone to errors, compared to the
compatible strings which are more succinct and obviously correct.
NXP SoC reference manuals clearly document the SerDes instantiations as
not identical, and refers to them as such (SerDes 1, 2, etc).
The per-SoC compatible string is prepended to the "fsl,lynx-28g" generic
compatible, which is left there for compatibility with old kernels. An
exception would be LX2160A SerDes #3, which at the time of writing is
not described in fsl-lx2160a.dtsi. As "fsl,lx2160a-serdes3" implies it
is a 28G Lynx SerDes, it makes "fsl,lynx-28g" redundant so we don't
accept it.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Previously submitted here:
https://lore.kernel.org/linux-phy/20260114152111.625350-3-vladimir.oltean@nxp.com/
Changes:
- Update commit message to remove leftover information stating that we
use the per-SoC compatible strings to impose constraints
- Add review tag from Rob Herring
---
.../devicetree/bindings/phy/fsl,lynx-28g.yaml | 33 +++++++++++++++++--
1 file changed, 30 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
index e96229c2f8fb..8375bca810cc 100644
--- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
+++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
@@ -9,10 +9,37 @@ title: Freescale Lynx 28G SerDes PHY
maintainers:
- Ioana Ciornei <ioana.ciornei@nxp.com>
+description:
+ The Lynx 28G is a multi-lane, multi-protocol SerDes (PCIe, SATA, Ethernet)
+ present in multiple instances on NXP LX2160A and LX2162A SoCs. All instances
+ share a common register map and programming model, however they differ in
+ supported protocols per lane in a way that is not detectable by said
+ programming model without prior knowledge. The distinction is made through
+ the compatible string.
+
properties:
compatible:
- enum:
- - fsl,lynx-28g
+ oneOf:
+ - const: fsl,lynx-28g
+ deprecated: true
+ description:
+ Legacy compatibility string for Lynx 28G SerDes. Any assumption
+ regarding whether a certain lane supports a certain protocol may
+ be incorrect. Deprecated except when used as a fallback. Use
+ device-specific strings instead.
+ - items:
+ - const: fsl,lx2160a-serdes1
+ - const: fsl,lynx-28g
+ - items:
+ - const: fsl,lx2160a-serdes2
+ - const: fsl,lynx-28g
+ - items:
+ - const: fsl,lx2162a-serdes1
+ - const: fsl,lynx-28g
+ - items:
+ - const: fsl,lx2162a-serdes2
+ - const: fsl,lynx-28g
+ - const: fsl,lx2160a-serdes3
reg:
maxItems: 1
@@ -60,7 +87,7 @@ examples:
#size-cells = <2>;
serdes@1ea0000 {
- compatible = "fsl,lynx-28g";
+ compatible = "fsl,lx2160a-serdes1", "fsl,lynx-28g";
reg = <0x0 0x1ea0000 0x0 0x1e30>;
#address-cells = <1>;
#size-cells = <0>;
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH phy-next 2/5] dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices
2026-05-11 15:00 [PATCH phy-next 0/5] Lynx 28G SerDes: 25GbE support Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 1/5] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
@ 2026-05-11 15:00 ` Vladimir Oltean
2026-05-11 16:30 ` Conor Dooley
2026-05-11 15:00 ` [PATCH phy-next 3/5] phy: lynx-28g: require an OF node to probe Vladimir Oltean
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Vladimir Oltean @ 2026-05-11 15:00 UTC (permalink / raw)
To: linux-phy
Cc: netdev, Ioana Ciornei, Vinod Koul, Neil Armstrong, Josua Mayer,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree
The SerDes 1 of LX2162A has fewer lanes than all other instances, and
strangely, their indices are not 0-3, but 4-7.
This is a best-effort constraint, since we can only impose it when using
per-SoC compatible string and per-lane OF nodes.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Patch previously submitted at:
https://lore.kernel.org/linux-phy/20260114152111.625350-4-vladimir.oltean@nxp.com/
Changes:
- remove redundant patternProperties: "^phy@[0-7]$": true from the
match; having it makes no difference
- clarify that the constraint is best effort
---
.../devicetree/bindings/phy/fsl,lynx-28g.yaml | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
index 8375bca810cc..d73591315d4b 100644
--- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
+++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
@@ -78,6 +78,21 @@ required:
- reg
- "#phy-cells"
+allOf:
+ # LX2162A SerDes 1 has fewer lanes than the others
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: fsl,lx2162a-serdes1
+ then:
+ patternProperties:
+ "^phy@[0-7]$":
+ properties:
+ reg:
+ minimum: 4
+ maximum: 7
+
additionalProperties: false
examples:
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH phy-next 3/5] phy: lynx-28g: require an OF node to probe
2026-05-11 15:00 [PATCH phy-next 0/5] Lynx 28G SerDes: 25GbE support Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 1/5] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 2/5] dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices Vladimir Oltean
@ 2026-05-11 15:00 ` Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 4/5] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 5/5] phy: lynx-28g: add support for 25GBASER Vladimir Oltean
4 siblings, 0 replies; 7+ messages in thread
From: Vladimir Oltean @ 2026-05-11 15:00 UTC (permalink / raw)
To: linux-phy
Cc: netdev, Ioana Ciornei, Vinod Koul, Neil Armstrong, Josua Mayer,
linux-kernel
The driver will gain support for variants in an upcoming change, and
will use of_device_get_match_data() to deduce the running variant from
the compatible string.
Currently, the driver expects the schema at phy/fsl,lynx-28g.yaml, and
OF-based consumers, but doesn't enforce this. And it is possible for
user space to force-bind the driver to a device without OF node using
the driver_override sysfs.
To avoid future surprise crashes for an unsupported configuration,
explicitly test for the presence of an OF node and fail probing if
found.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Change is new.
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 4ec3fb7a0d69..6d0c395d20e5 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1286,6 +1286,12 @@ static int lynx_28g_probe(struct platform_device *pdev)
struct device_node *dn;
int err;
+ dn = dev_of_node(dev);
+ if (!dn) {
+ dev_err(dev, "Device requires an OF node\n");
+ return -EINVAL;
+ }
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1301,7 +1307,6 @@ static int lynx_28g_probe(struct platform_device *pdev)
lynx_28g_pll_read_configuration(priv);
- dn = dev_of_node(dev);
if (of_get_child_count(dn)) {
struct device_node *child;
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH phy-next 4/5] phy: lynx-28g: probe on per-SoC and per-instance compatible strings
2026-05-11 15:00 [PATCH phy-next 0/5] Lynx 28G SerDes: 25GbE support Vladimir Oltean
` (2 preceding siblings ...)
2026-05-11 15:00 ` [PATCH phy-next 3/5] phy: lynx-28g: require an OF node to probe Vladimir Oltean
@ 2026-05-11 15:00 ` Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 5/5] phy: lynx-28g: add support for 25GBASER Vladimir Oltean
4 siblings, 0 replies; 7+ messages in thread
From: Vladimir Oltean @ 2026-05-11 15:00 UTC (permalink / raw)
To: linux-phy
Cc: netdev, Ioana Ciornei, Vinod Koul, Neil Armstrong, Josua Mayer,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree
Add driver support for probing on the new, per-instance and per-SoC
bindings, which provide the main benefit that they allow rejecting
unsupported protocols per lane (10GbE on SerDes 2 lanes 0-5), but they
also allow avoiding the creation of PHYs for lanes that don't exist
(LX2162A lanes 0-3).
For old device trees with just "fsl,lynx-28g", the only things that
change are:
- a probe time warning/encouragement to update the device tree. This is
warranted by the fact that using "fsl,lynx-28g" may already provide
incorrect behaviour (undetected absent 10GbE support on LX2160A
SerDes 2 lanes 0-5). But we retain bug compatibility nonetheless.
- the feature set is frozen in time (e.g. no 25GbE). Since we cannot
guarantee that this protocol will work on a lane, just err on the safe
side and don't offer it (and require a device tree update to get it).
In terms of code, the lynx_28g_supports_lane_mode() function prototype
changes. It was a SerDes-global function and now becomes per lane, to
reflect the specific capabilities each instance may have. The
implementation goes through priv->info->lane_supports_mode().
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Change previously submitted at:
https://lore.kernel.org/linux-phy/20260114152111.625350-5-vladimir.oltean@nxp.com/
Changes:
- reword commit message
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 126 +++++++++++++++++++++--
1 file changed, 116 insertions(+), 10 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 6d0c395d20e5..5eddc2723e78 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -446,9 +446,15 @@ 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;
+ const struct lynx_info *info;
/* Serialize concurrent access to registers shared between lanes,
* like PCCn
*/
@@ -513,11 +519,18 @@ static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
}
}
-static bool lynx_28g_supports_lane_mode(struct lynx_28g_priv *priv,
+/* 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;
@@ -783,6 +796,87 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
}
}
+static bool lx2160a_serdes1_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return true;
+}
+
+static bool lx2160a_serdes2_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return true;
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ return lane == 6 || lane == 7;
+ default:
+ return false;
+ }
+}
+
+static bool lx2160a_serdes3_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ /*
+ * Non-networking SerDes, and this driver supports only
+ * networking protocols
+ */
+ return false;
+}
+
+static bool lx2162a_serdes1_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return true;
+}
+
+static bool lx2162a_serdes2_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return lx2160a_serdes2_lane_supports_mode(lane, mode);
+}
+
+/* Feature set is not expected to grow for the deprecated compatible string */
+static bool lynx_28g_compat_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct lynx_info lynx_info_compat = {
+ .lane_supports_mode = lynx_28g_compat_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2160a_serdes1 = {
+ .lane_supports_mode = lx2160a_serdes1_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2160a_serdes2 = {
+ .lane_supports_mode = lx2160a_serdes2_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2160a_serdes3 = {
+ .lane_supports_mode = lx2160a_serdes3_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2162a_serdes1 = {
+ .lane_supports_mode = lx2162a_serdes1_lane_supports_mode,
+ .first_lane = 4,
+};
+
+static const struct lynx_info lynx_info_lx2162a_serdes2 = {
+ .lane_supports_mode = lx2162a_serdes2_lane_supports_mode,
+};
+
static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode,
u32 *val)
{
@@ -1035,7 +1129,6 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
- struct lynx_28g_priv *priv = lane->priv;
int powered_up = lane->powered_up;
enum lynx_lane_mode lane_mode;
int err = 0;
@@ -1047,7 +1140,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(priv, lane_mode))
+ if (!lynx_28g_supports_lane_mode(lane, lane_mode))
return -EOPNOTSUPP;
if (lane_mode == lane->mode)
@@ -1083,14 +1176,13 @@ static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
union phy_configure_opts *opts __always_unused)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
- struct lynx_28g_priv *priv = lane->priv;
enum lynx_lane_mode lane_mode;
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
lane_mode = phy_interface_to_lane_mode(submode);
- if (!lynx_28g_supports_lane_mode(priv, lane_mode))
+ if (!lynx_28g_supports_lane_mode(lane, lane_mode))
return -EOPNOTSUPP;
return 0;
@@ -1183,7 +1275,7 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
u32 rrstctl;
int err, i;
- for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
lane = &priv->lane[i];
if (!lane->phy)
continue;
@@ -1253,7 +1345,8 @@ static struct phy *lynx_28g_xlate(struct device *dev,
idx = args->args[0];
- if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
+ if (WARN_ON(idx >= LYNX_28G_NUM_LANE ||
+ idx < priv->info->first_lane))
return ERR_PTR(-EINVAL);
return priv->lane[idx].phy;
@@ -1297,10 +1390,18 @@ static int lynx_28g_probe(struct platform_device *pdev)
return -ENOMEM;
priv->dev = dev;
+ priv->info = of_device_get_match_data(dev);
dev_set_drvdata(dev, priv);
spin_lock_init(&priv->pcc_lock);
INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
+ /*
+ * If we get here it means we probed on a device tree where
+ * "fsl,lynx-28g" wasn't the fallback, but the sole compatible string.
+ */
+ if (priv->info == &lynx_info_compat)
+ dev_warn(dev, "Please update device tree to use per-device compatible strings\n");
+
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
@@ -1323,7 +1424,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (reg >= LYNX_28G_NUM_LANE) {
+ if (reg < priv->info->first_lane || reg >= LYNX_28G_NUM_LANE) {
dev_err(dev, "\"reg\" property out of range for %pOF\n", child);
of_node_put(child);
return -EINVAL;
@@ -1336,7 +1437,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
}
}
} else {
- for (int i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ for (int i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
err = lynx_28g_probe_lane(priv, i, NULL);
if (err)
return err;
@@ -1362,7 +1463,12 @@ static void lynx_28g_remove(struct platform_device *pdev)
}
static const struct of_device_id lynx_28g_of_match_table[] = {
- { .compatible = "fsl,lynx-28g" },
+ { .compatible = "fsl,lx2160a-serdes1", .data = &lynx_info_lx2160a_serdes1 },
+ { .compatible = "fsl,lx2160a-serdes2", .data = &lynx_info_lx2160a_serdes2 },
+ { .compatible = "fsl,lx2160a-serdes3", .data = &lynx_info_lx2160a_serdes3 },
+ { .compatible = "fsl,lx2162a-serdes1", .data = &lynx_info_lx2162a_serdes1 },
+ { .compatible = "fsl,lx2162a-serdes2", .data = &lynx_info_lx2162a_serdes2 },
+ { .compatible = "fsl,lynx-28g", .data = &lynx_info_compat }, /* fallback, keep last */
{ },
};
MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH phy-next 5/5] phy: lynx-28g: add support for 25GBASER
2026-05-11 15:00 [PATCH phy-next 0/5] Lynx 28G SerDes: 25GbE support Vladimir Oltean
` (3 preceding siblings ...)
2026-05-11 15:00 ` [PATCH phy-next 4/5] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Vladimir Oltean
@ 2026-05-11 15:00 ` Vladimir Oltean
4 siblings, 0 replies; 7+ messages in thread
From: Vladimir Oltean @ 2026-05-11 15:00 UTC (permalink / raw)
To: linux-phy
Cc: netdev, Ioana Ciornei, Vinod Koul, Neil Armstrong, Josua Mayer,
linux-kernel
From: Ioana Ciornei <ioana.ciornei@nxp.com>
Add support for 25GBASE-R in the Lynx 28G SerDes PHY driver. This will
be used by the dpaa2-mac consumer on LX2160A with:
- phy_validate(phy, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_25GBASER) to
detect support.
- phy_set_mode_ext(phy, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_25GBASER)
to reconfigure the lane for this protocol.
The intended use case for dynamic protocol switching to 25GBase-R is
with SFP28 modules, and protocol switching is triggered by the SFP
module insertion. There also exists a 25GBase-KR use case, where the
protocol switching is covered by IEEE 802.3 clause 73 auto-negotiation.
However, that is not handled here; it merely needs the support added
here as basic ground work.
The lane frequency for 25GbE is sourced from a clock net frequency of
12.890625 GHz, as produced by PLLF or PLLS, further multiplied by the
lane by 2. The clock net frequencies produced by the PLLs are treated as
read-only by the driver, so the absence of a PLL provisioned for the
right clock net frequency implies absence of 25GbE support, even though
a lane might have the appropriate protocol converter for it.
In terms of implementation, the change consists of:
- determining at probe time if any PLL was preconfigured for the
required clock net frequency for 25GbE
- adding the default lane parameters for reconfiguring a lane to 25GbE
irrespective of the original protocol
- allowing this operating mode only on supported lanes, i.e. all lanes
of LX2162A SerDes #1, and LX2160A SerDes lanes 0-1, 4-7.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Change previously submitted at:
https://lore.kernel.org/linux-phy/20260114152111.625350-6-vladimir.oltean@nxp.com/
Changes:
- reword commit message
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 90 +++++++++++++++++++++++-
1 file changed, 88 insertions(+), 2 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 5eddc2723e78..92bfc5f65e0b 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -57,6 +57,7 @@
#define PLLnCR1_FRATE_5G_10GVCO 0x0
#define PLLnCR1_FRATE_5G_25GVCO 0x10
#define PLLnCR1_FRATE_10G_20GVCO 0x6
+#define PLLnCR1_FRATE_12G_25GVCO 0x16
/* Per SerDes lane registers */
/* Lane a General Control Register */
@@ -64,9 +65,11 @@
#define LNaGCR0_PROTO_SEL GENMASK(7, 3)
#define LNaGCR0_PROTO_SEL_SGMII 0x1
#define LNaGCR0_PROTO_SEL_XFI 0xa
+#define LNaGCR0_PROTO_SEL_25G 0x1a
#define LNaGCR0_IF_WIDTH GENMASK(2, 0)
#define LNaGCR0_IF_WIDTH_10_BIT 0x0
#define LNaGCR0_IF_WIDTH_20_BIT 0x2
+#define LNaGCR0_IF_WIDTH_40_BIT 0x4
/* Lane a Tx Reset Control Register */
#define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
@@ -85,6 +88,7 @@
#define LNaTGCR0_N_RATE_FULL 0x0
#define LNaTGCR0_N_RATE_HALF 0x1
#define LNaTGCR0_N_RATE_QUARTER 0x2
+#define LNaTGCR0_N_RATE_DOUBLE 0x3
#define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
#define LNaTECR0_EQ_TYPE GENMASK(30, 28)
@@ -116,6 +120,7 @@
#define LNaRGCR0_N_RATE_FULL 0x0
#define LNaRGCR0_N_RATE_HALF 0x1
#define LNaRGCR0_N_RATE_QUARTER 0x2
+#define LNaRGCR0_N_RATE_DOUBLE 0x3
#define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
#define LNaRGCR1_RX_ORD_ELECIDLE BIT(31)
@@ -282,6 +287,7 @@ enum lynx_lane_mode {
LANE_MODE_1000BASEX_SGMII,
LANE_MODE_10GBASER,
LANE_MODE_USXGMII,
+ LANE_MODE_25GBASER,
LANE_MODE_MAX,
};
@@ -420,6 +426,41 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
.ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
LNaTTLCR0_DATA_IN_SSC,
},
+ [LANE_MODE_25GBASER] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_25G,
+ .if_width = LNaGCR0_IF_WIDTH_40_BIT,
+ .teq_type = EQ_TYPE_3TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 2,
+ .sgn_post1q = 1,
+ .ratio_post1q = 7,
+ .amp_red = 0,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 5,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 1,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 2,
+ .spare_in = 3,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 2,
+ .rccr0 = LNaRCCR0_CAL_EN |
+ LNaRCCR0_CAL_DC3_DIS |
+ LNaRCCR0_CAL_DC2_DIS |
+ LNaRCCR0_CAL_DC1_DIS |
+ LNaRCCR0_CAL_DC0_DIS,
+ .ttlcr0 = LNaTTLCR0_DATA_IN_SSC |
+ FIELD_PREP_CONST(LNaTTLCR0_CDR_MIN_SMP_ON, 1),
+ },
};
struct lynx_pccr {
@@ -499,6 +540,8 @@ static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
return "10GBase-R";
case LANE_MODE_USXGMII:
return "USXGMII";
+ case LANE_MODE_25GBASER:
+ return "25GBase-R";
default:
return "unknown";
}
@@ -514,6 +557,8 @@ static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
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;
}
@@ -601,6 +646,20 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
break;
}
break;
+ case PLLnCR1_FRATE_12G_25GVCO:
+ switch (lane_mode) {
+ case LANE_MODE_25GBASER:
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_DOUBLE),
+ LNaTGCR0_N_RATE);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_DOUBLE),
+ LNaRGCR0_N_RATE);
+ break;
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -761,6 +820,11 @@ static int lynx_28g_power_on(struct phy *phy)
return 0;
}
+static int lynx_28g_e25g_pcvt(int lane)
+{
+ return 7 - lane;
+}
+
static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
struct lynx_pccr *pccr)
{
@@ -776,6 +840,11 @@ static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
pccr->width = 4;
pccr->shift = SXGMII_CFG(lane);
break;
+ case LANE_MODE_25GBASER:
+ pccr->offset = PCCD;
+ pccr->width = 4;
+ pccr->shift = E25G_CFG(lynx_28g_e25g_pcvt(lane));
+ break;
default:
return -EOPNOTSUPP;
}
@@ -791,6 +860,8 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
case LANE_MODE_USXGMII:
case LANE_MODE_10GBASER:
return SXGMIIaCR0(lane);
+ case LANE_MODE_25GBASER:
+ return E25GaCR0(lynx_28g_e25g_pcvt(lane));
default:
return -EOPNOTSUPP;
}
@@ -799,7 +870,12 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
static bool lx2160a_serdes1_lane_supports_mode(int lane,
enum lynx_lane_mode mode)
{
- return true;
+ switch (mode) {
+ case LANE_MODE_25GBASER:
+ return lane != 2 && lane != 3;
+ default:
+ return true;
+ }
}
static bool lx2160a_serdes2_lane_supports_mode(int lane,
@@ -1115,6 +1191,9 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
case LANE_MODE_USXGMII:
val |= PCCC_SXGMIIn_CFG;
break;
+ case LANE_MODE_25GBASER:
+ val |= PCCD_E25Gn_CFG;
+ break;
default:
break;
}
@@ -1259,8 +1338,12 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
__set_bit(LANE_MODE_10GBASER, pll->supported);
__set_bit(LANE_MODE_USXGMII, pll->supported);
break;
+ case PLLnCR1_FRATE_12G_25GVCO:
+ /* 12.890625GHz clock net */
+ __set_bit(LANE_MODE_25GBASER, pll->supported);
+ break;
default:
- /* 6GHz, 12.890625GHz, 8GHz */
+ /* 6GHz, 8GHz */
break;
}
}
@@ -1327,6 +1410,9 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
else
lane->mode = LANE_MODE_USXGMII;
break;
+ case LNaPSS_TYPE_25G:
+ lane->mode = LANE_MODE_25GBASER;
+ break;
default:
lane->mode = LANE_MODE_UNKNOWN;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH phy-next 2/5] dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices
2026-05-11 15:00 ` [PATCH phy-next 2/5] dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices Vladimir Oltean
@ 2026-05-11 16:30 ` Conor Dooley
0 siblings, 0 replies; 7+ messages in thread
From: Conor Dooley @ 2026-05-11 16:30 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, netdev, Ioana Ciornei, Vinod Koul, Neil Armstrong,
Josua Mayer, linux-kernel, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, devicetree
[-- Attachment #1: Type: text/plain, Size: 440 bytes --]
On Mon, May 11, 2026 at 06:00:20PM +0300, Vladimir Oltean wrote:
> The SerDes 1 of LX2162A has fewer lanes than all other instances, and
> strangely, their indices are not 0-3, but 4-7.
>
> This is a best-effort constraint, since we can only impose it when using
> per-SoC compatible string and per-lane OF nodes.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-11 16:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11 15:00 [PATCH phy-next 0/5] Lynx 28G SerDes: 25GbE support Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 1/5] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 2/5] dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices Vladimir Oltean
2026-05-11 16:30 ` Conor Dooley
2026-05-11 15:00 ` [PATCH phy-next 3/5] phy: lynx-28g: require an OF node to probe Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 4/5] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Vladimir Oltean
2026-05-11 15:00 ` [PATCH phy-next 5/5] phy: lynx-28g: add support for 25GBASER Vladimir Oltean
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox