* [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards
@ 2026-10-01 20:47 Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 01/13] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
` (12 more replies)
0 siblings, 13 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
The 1x100GE + 4x25G split of SerDes 1 is in next since v1, commit
035d68fc36b5 ("lx2160: add lx2160_serdes split and management").
This series builds on it with incremental patches to ease reviews,
but with many reworks:
- No more command that re-groups the lanes at the prompt: the MC has
already started. Use hwconfig
- hwconfig values are named based on needed cases:
serdes1:split becomes serdes1:100g4x25g (patch 2)
- Use a table (patches 3 to 5), and enter a mode through the one it
starts from (patch 9)
- One patch per new mode: 2x40GE, 1x40GE + 4x10G and 1x100GE + 4x10G
- Rewrite documentation
- Add and apply to nbxv3
It is now mainly tested on a Nodebox v3
setenv hwconfig serdes1:<mode>
saveenv
reset
- print checks using lx2160_serdes status 1
- in Linux, with the matching MC DPC, DPL: each case has its netdevices
As agreed with Tom on v4, the conversion of README.soc and
README.fsl-hwconfig to rST will be a separate series, after this one.
v5: https://lore.kernel.org/u-boot/20260929175947.1379710-1-vjardin@free.fr/
v4: https://lore.kernel.org/u-boot/20260928101330.881662-1-vjardin@free.fr/
v3: https://lore.kernel.org/u-boot/20260916211549.3432913-1-vjardin@free.fr/
v2: https://lore.kernel.org/u-boot/20260914170417.3052423-1-vjardin@free.fr/
Changes in v6:
- 3/13, 4/13, 5/13, 6/13, 11/13: Reviewed-by from Vladimir
- 8/13: 40GE needs PLLS, only 161.1328125 MHz PLLS reference clock is supported (Vladimir)
- 12/13: same for the PLLS reference clock (Vladimir)
Changes in v5:
- 1/13, 2/13, 7/13, 13/13: Reviewed-by from Vladimir
- 3/13 (new): rename SPLIT_POLL_US to SRDS_POLL_US
- 4/13 (new): halt and reset of SD1 become helpers
- 5/13: the table only
- 6/13: report an unknown serdes1 value
- 9/13 (new): enter a mode through the one it starts from
- 10/13: skip logic of the reset added
- 12/13: reworded, PLLS reference clock, no list of boards
Changes in v4:
- rebased on next, incremental over v1 instead of replacing it
- 1/10 (new): drop `lx2160_serdes split`
- 2/10 (new): rename serdes1:split to serdes1:100g4x25g
- 3/10 (new): use a table to set SD1
- 4/10 (new): report invalid serdes1 names
- 5/10 (new): refuse once the MC runs
- 6/10, 7/10, 8/10: resp. v3 2/5, 3/5, 4/5: add other modes
- 9/10: v3 5/5, rewritten doc
- 10/10 (new): apply sd1 for the nbxv3
Vincent Jardin (13):
board: lx2160a: serdes: drop the split subcommand
board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g
board: lx2160a: serdes: rename SPLIT_POLL_US to SRDS_POLL_US
board: lx2160a: serdes: move the SD1 halt and reset into helpers
board: lx2160a: serdes: set SD1 with a table
board: lx2160a: serdes: report unknown SD1 cases
board: lx2160a: serdes: no SD1 config once MC runs
board: lx2160a: serdes: add serdes1:2x40g
board: lx2160a: serdes: enter a SD1 mode through the mode it starts
from
board: lx2160a: serdes: add serdes1:40g4x10g
board: lx2160a: serdes: add serdes1:100g4x10g
doc: lx2160a: document the sd1 hwconfig option
board: nbxv3: apply sd1 hwconfig before MC starts
.../cpu/armv8/fsl-layerscape/doc/README.soc | 7 +
board/nxp/lx2160a/eth_lx2160aqds.c | 4 +-
board/nxp/lx2160a/nbxv3/eth_nbxv3.c | 3 +
board/nxp/lx2160a/serdes_split.c | 548 +++++++++++++++---
board/nxp/lx2160a/serdes_split.h | 16 +-
doc/README.fsl-hwconfig | 64 ++
6 files changed, 531 insertions(+), 111 deletions(-)
---
base-commit: 2b8902913c19eb581fb0d567201c09b8fa46ac74
branch: for-upstream/lx2160a-serdes1-v6
--
2.43.0
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v6 01/13] board: lx2160a: serdes: drop the split subcommand
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 02/13] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g Vincent Jardin
` (11 subsequent siblings)
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
lx2160_serdes split command configure SD1 lanes from the U-Boot prompt.
But the MC firmware has very likely normally been started already.
The split must be before the MC starts. That is the purpose of
hwconfig=serdes1:split
Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v4)
Changes in v4:
- New patch
board/nxp/lx2160a/serdes_split.c | 28 ----------------------------
1 file changed, 28 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index ca3d7228977..6d9743a28dc 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -449,23 +449,6 @@ static int do_lx2160_serdes(struct cmd_tbl *cmdtp, int flag,
if (argc < 2)
return CMD_RET_USAGE;
- if (!strcmp(argv[1], "split")) {
-#if !defined(CONFIG_ARCH_LX2160A)
- printf("no 100GE on SerDes 1 to split on this SoC\n");
- return CMD_RET_FAILURE;
-#else
- if (argc != 2)
- return CMD_RET_USAGE;
- if (lx2160a_serdes1_is_split()) {
- printf("SD1 is already split, nothing to do\n");
- return CMD_RET_SUCCESS;
- }
- if (lx2160a_serdes1_split())
- return CMD_RET_FAILURE;
- return CMD_RET_SUCCESS;
-#endif
- }
-
if (strcmp(argv[1], "status"))
return CMD_RET_USAGE;
@@ -487,16 +470,6 @@ static int do_lx2160_serdes(struct cmd_tbl *cmdtp, int flag,
return do_serdes_status(sd);
}
-#if defined(CONFIG_ARCH_LX2160A)
-#define SPLIT_CMD_HELP \
- "lx2160_serdes split\n" \
- " - split Lynx 28G SD1 100GE.1 (lanes LNE-LNH) into 4x 25G.\n" \
- " Runs before the MC starts. To make it permanent on a board\n" \
- " that needs it: setenv hwconfig serdes1:split && saveenv"
-#else
-#define SPLIT_CMD_HELP ""
-#endif
-
U_BOOT_CMD(
lx2160_serdes, 3, 0, do_lx2160_serdes,
"inspect the LX2160A 28G-Lynx SerDes protocol configuration",
@@ -505,5 +478,4 @@ U_BOOT_CMD(
" per-lane port grouping and protocol (LNmGCR0), next to the\n"
" protocol number the RCW latched.\n"
" No argument prints all three SerDes."
- SPLIT_CMD_HELP
);
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 02/13] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 01/13] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 03/13] board: lx2160a: serdes: rename SPLIT_POLL_US to SRDS_POLL_US Vincent Jardin
` (10 subsequent siblings)
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
The following patches will be adding other cases for SD1 lanes:
2x 40GE, 1x 40GE + 4x 10G and 1x 100GE + 4x 10G.
So "split" is no longer meaningful.
Let's name each hwconfig value based on the SD1's lanes settings:
1x 100GE + 4x 25G.
note: serdes1:split has only been in next, never in a release, so
we should not need a compatibility alias.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v5)
Changes in v5:
- Fix typos in the commit message
Changes in v4:
- New patch
board/nxp/lx2160a/eth_lx2160aqds.c | 4 ++--
board/nxp/lx2160a/serdes_split.c | 4 ++--
board/nxp/lx2160a/serdes_split.h | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/board/nxp/lx2160a/eth_lx2160aqds.c b/board/nxp/lx2160a/eth_lx2160aqds.c
index c1a060877cd..8f48b14c0e3 100644
--- a/board/nxp/lx2160a/eth_lx2160aqds.c
+++ b/board/nxp/lx2160a/eth_lx2160aqds.c
@@ -18,8 +18,8 @@ void reset_phy(void)
{
/*
* Before the MC boots: it latches the live protocol-converter
- * configuration when it starts, so `hwconfig=serdes1:split` has to
- * be applied here and not later.
+ * configuration when it starts, so `hwconfig=serdes1:<mode>` has
+ * to be applied here and not later.
*/
lx2160a_serdes_apply_hwconfig();
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 6d9743a28dc..1a5c44e7740 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -409,13 +409,13 @@ int lx2160a_serdes1_split(void)
}
/*
- * setenv hwconfig serdes1:split
+ * setenv hwconfig serdes1:100g4x25g
*
* Idempotent: a board whose PBI already split SD1 skip it too.
*/
void lx2160a_serdes_apply_hwconfig(void)
{
- if (!hwconfig_sub("serdes1", "split"))
+ if (!hwconfig_sub("serdes1", "100g4x25g"))
return;
if (lx2160a_serdes1_is_split())
diff --git a/board/nxp/lx2160a/serdes_split.h b/board/nxp/lx2160a/serdes_split.h
index 67e8c4873a7..8dce9ddf97a 100644
--- a/board/nxp/lx2160a/serdes_split.h
+++ b/board/nxp/lx2160a/serdes_split.h
@@ -25,7 +25,7 @@ bool lx2160a_serdes1_is_split(void);
int lx2160a_serdes1_split(void);
/*
- * Apply `hwconfig=serdes1:split` if the board's environment asks for it.
+ * Apply `hwconfig=serdes1:100g4x25g` if the board's environment asks for it.
* Boards call this from reset_phy(), before mc_env_boot().
*/
void lx2160a_serdes_apply_hwconfig(void);
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 03/13] board: lx2160a: serdes: rename SPLIT_POLL_US to SRDS_POLL_US
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 01/13] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 02/13] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 04/13] board: lx2160a: serdes: move the SD1 halt and reset into helpers Vincent Jardin
` (9 subsequent siblings)
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
The poll bound is not specific to the split.
No functional change.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v5)
Changes in v5:
- New patch, split out of "set SD1 with a table"
board/nxp/lx2160a/serdes_split.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 1a5c44e7740..aeae8fbb340 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -264,7 +264,7 @@ static void print_rcw_view(int sd)
#define SPLIT_PCCE 0x00000100 /* E100Ga off, E100Gb on */
#define SPLIT_PCCD 0x11110000 /* E25Ga..E25Gd on */
-#define SPLIT_POLL_US 10000 /* NXP waits ~100 cycles */
+#define SRDS_POLL_US 10000 /* NXP waits ~100 cycles */
static bool srds1_split_state(unsigned long base)
{
@@ -298,7 +298,7 @@ static bool srds1_is_unsplit(unsigned long base)
*/
static int poll_clear(unsigned long reg, u32 bit)
{
- int us = SPLIT_POLL_US;
+ int us = SRDS_POLL_US;
while (us--) {
if (!(in_le32((void __iomem *)reg) & bit))
@@ -352,7 +352,7 @@ int lx2160a_serdes1_split(void)
if (poll_clear(SRDS_LNmTRSTCTL(base, master), RSTCTL_HLT_REQ) ||
poll_clear(SRDS_LNmRRSTCTL(base, master), RSTCTL_HLT_REQ)) {
printf("lx2160a serdes: LN%c did not halt within %d us, continuing\n",
- 'A' + master, SPLIT_POLL_US);
+ 'A' + master, SRDS_POLL_US);
ret = -ETIMEDOUT;
}
@@ -381,7 +381,7 @@ int lx2160a_serdes1_split(void)
if (poll_clear(SRDS_LNmTRSTCTL(base, m), RSTCTL_RST_REQ) ||
poll_clear(SRDS_LNmRRSTCTL(base, m), RSTCTL_RST_REQ)) {
printf("lx2160a serdes: LN%c reset did not complete within %d us\n",
- 'A' + m, SPLIT_POLL_US);
+ 'A' + m, SRDS_POLL_US);
ret = -ETIMEDOUT;
continue;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 04/13] board: lx2160a: serdes: move the SD1 halt and reset into helpers
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (2 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 03/13] board: lx2160a: serdes: rename SPLIT_POLL_US to SRDS_POLL_US Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 05/13] board: lx2160a: serdes: set SD1 with a table Vincent Jardin
` (8 subsequent siblings)
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
The split halts the 100GE port on LNE-LNH, reconfigures its lanes,
then resets. The following patches do the same halt and reset on
other lanes, for the other SD1 modes.
Move them into helpers.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v5)
Changes in v5:
- New patch, split out of "set SD1 with a table"
board/nxp/lx2160a/serdes_split.c | 132 ++++++++++++++++++++-----------
1 file changed, 88 insertions(+), 44 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index aeae8fbb340..5dcdeff5898 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -12,6 +12,7 @@
#include <asm/arch/fsl_serdes.h>
#include <asm/arch/immap_lsch3.h>
#include <asm/arch/soc.h> /* gur_in32() picks the GUR endianness */
+#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/delay.h>
@@ -251,8 +252,7 @@ static void print_rcw_view(int sd)
* This is NXP's e100g1_split.rcw sequence, moved from the PBI into
* U-Boot.
*/
-#define SPLIT_FIRST_LANE 4 /* LNE */
-#define SPLIT_LAST_LANE 7 /* LNH */
+#define SD1_LNE_LNH GENMASK(7, 4)
/*
* PROTO_SEL=11010b (25G/50G/100G, shared) + IF_WIDTH=100b (40-bit),
@@ -309,73 +309,74 @@ static int poll_clear(unsigned long reg, u32 bit)
return -ETIMEDOUT;
}
-int lx2160a_serdes1_split(void)
+static int sd1_port_master(unsigned long base, unsigned long lanes)
{
- unsigned long base = srds_base(FSL_SRDS_1);
- int m, master = -1, ret = 0;
-
- if (srds1_split_state(base)) {
- debug("lx2160a serdes: SD1 already split, nothing to do\n");
- return 0;
- }
-
- if (!srds1_is_unsplit(base)) {
- printf("lx2160a serdes: SD1 is in neither the split nor the unsplit state (PCCD=%08x PCCE=%08x), refusing\n",
- in_le32((void __iomem *)SRDS_PCCD(base)),
- in_le32((void __iomem *)SRDS_PCCE(base)));
- return -EINVAL;
- }
+ int m, master = -1;
- /*
- * Halt. "Halt only has meaning on the master source
- * clock lane of a port (LNmGCR0[PORT_LN0_B]=0)". Lanes E-H are one
- * 100G port at this point, so exactly one of them is the master and
- * the other three requests are ignored. Issue all four anyway
- * (that is what NXP's sequence does) but only wait on the lane
- * where the bit can actually clear.
- */
- for (m = SPLIT_FIRST_LANE; m <= SPLIT_LAST_LANE; m++) {
+ for_each_set_bit(m, &lanes, SRDS_LANES)
if (!(in_le32((void __iomem *)SRDS_LNmGCR0(base, m)) &
GCR0_PORT_LN0_B))
master = m;
+
+ if (master < 0)
+ printf("lx2160a serdes: no master lane among LN%c-LN%c, refusing\n",
+ 'A' + (int)__ffs(lanes), 'A' + (int)__fls(lanes));
+
+ return master;
+}
+
+/*
+ * Halt the port made of @lanes.
+ *
+ * "Halt only has meaning on the master source clock lane of a port
+ * (LNmGCR0[PORT_LN0_B]=0)", so the request goes to every lane, as
+ * NXP's sequence does, and only the master is waited on:
+ * it is the one lane where the bit can clear.
+ *
+ * -EINVAL means nothing was touched
+ * -ETIMEDOUT is only a warning
+ */
+static int sd1_halt_port(unsigned long base, unsigned long lanes)
+{
+ int m, master = sd1_port_master(base, lanes);
+
+ if (master < 0)
+ return -EINVAL;
+
+ for_each_set_bit(m, &lanes, SRDS_LANES) {
out_le32((void __iomem *)SRDS_LNmTRSTCTL(base, m),
RSTCTL_HLT_REQ);
out_le32((void __iomem *)SRDS_LNmRRSTCTL(base, m),
RSTCTL_HLT_REQ);
}
- if (master < 0) {
- printf("lx2160a serdes: no master lane among LNE-LNH, refusing\n");
- return -EINVAL;
- }
-
if (poll_clear(SRDS_LNmTRSTCTL(base, master), RSTCTL_HLT_REQ) ||
poll_clear(SRDS_LNmRRSTCTL(base, master), RSTCTL_HLT_REQ)) {
printf("lx2160a serdes: LN%c did not halt within %d us, continuing\n",
'A' + master, SRDS_POLL_US);
- ret = -ETIMEDOUT;
+ return -ETIMEDOUT;
}
- /*
- * Reconfigure while halted: four one-lane ports instead of one
- * four-lane port. Everything else about the lane is unchanged.
- */
- for (m = SPLIT_FIRST_LANE; m <= SPLIT_LAST_LANE; m++)
- out_le32((void __iomem *)SRDS_LNmGCR0(base, m), SPLIT_GCR0);
+ return 0;
+}
- /* Re-point the protocol converters. */
- out_le32((void __iomem *)SRDS_PCCE(base), SPLIT_PCCE);
- out_le32((void __iomem *)SRDS_PCCD(base), SPLIT_PCCD);
+static void sd1_reset_req(unsigned long base, unsigned long lanes)
+{
+ int m;
- /* Reset. Every lane is its own master now, so all four count. */
- for (m = SPLIT_FIRST_LANE; m <= SPLIT_LAST_LANE; m++) {
+ for_each_set_bit(m, &lanes, SRDS_LANES) {
out_le32((void __iomem *)SRDS_LNmTRSTCTL(base, m),
RSTCTL_RST_REQ);
out_le32((void __iomem *)SRDS_LNmRRSTCTL(base, m),
RSTCTL_RST_REQ);
}
+}
- for (m = SPLIT_FIRST_LANE; m <= SPLIT_LAST_LANE; m++) {
+static int sd1_reset_wait(unsigned long base, unsigned long lanes)
+{
+ int m, ret = 0;
+
+ for_each_set_bit(m, &lanes, SRDS_LANES) {
u32 t, r;
if (poll_clear(SRDS_LNmTRSTCTL(base, m), RSTCTL_RST_REQ) ||
@@ -395,6 +396,49 @@ int lx2160a_serdes1_split(void)
}
}
+ return ret;
+}
+
+int lx2160a_serdes1_split(void)
+{
+ unsigned long base = srds_base(FSL_SRDS_1);
+ unsigned long lanes = SD1_LNE_LNH;
+ int m, ret, err;
+
+ if (srds1_split_state(base)) {
+ debug("lx2160a serdes: SD1 already split, nothing to do\n");
+ return 0;
+ }
+
+ if (!srds1_is_unsplit(base)) {
+ printf("lx2160a serdes: SD1 is in neither the split nor the unsplit state (PCCD=%08x PCCE=%08x), refusing\n",
+ in_le32((void __iomem *)SRDS_PCCD(base)),
+ in_le32((void __iomem *)SRDS_PCCE(base)));
+ return -EINVAL;
+ }
+
+ /* Lanes E-H are one 100G port at this point. */
+ ret = sd1_halt_port(base, lanes);
+ if (ret == -EINVAL)
+ return ret;
+
+ /*
+ * Reconfigure while halted: four one-lane ports instead of one
+ * four-lane port. Everything else about the lane is unchanged.
+ */
+ for_each_set_bit(m, &lanes, SRDS_LANES)
+ out_le32((void __iomem *)SRDS_LNmGCR0(base, m), SPLIT_GCR0);
+
+ /* Re-point the protocol converters. */
+ out_le32((void __iomem *)SRDS_PCCE(base), SPLIT_PCCE);
+ out_le32((void __iomem *)SRDS_PCCD(base), SPLIT_PCCD);
+
+ /* Reset. Every lane is its own master now, so all four count. */
+ sd1_reset_req(base, lanes);
+ err = sd1_reset_wait(base, lanes);
+ if (err)
+ ret = err;
+
if (!srds1_split_state(base)) {
printf("lx2160a serdes: split did not take (PCCD=%08x PCCE=%08x)\n",
in_le32((void __iomem *)SRDS_PCCD(base)),
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 05/13] board: lx2160a: serdes: set SD1 with a table
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (3 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 04/13] board: lx2160a: serdes: move the SD1 halt and reset into helpers Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 06/13] board: lx2160a: serdes: report unknown SD1 cases Vincent Jardin
` (7 subsequent siblings)
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
The SD1 lanes can be set in more cases than the 1x100GE + 4x25G
split. Describe each case as a mode, an entry of a table:
- its hwconfig name
- how to tell SD1 is in it
- the mode it is entered from
- the sequence that enters it
The two existing states become the first two modes, under their
serdes1 names:
- the "split" state, 1x100GE + 4x25G, is 100g4x25g
- the "unsplit" state, 2x100GE, is 2x100g
A mode is entered only when SD1 is in the mode it starts from, as
the split required the unsplit state. The serdes1 value is a single
mode name, read with hwconfig_arg().
Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v5)
Changes in v5:
- SPLIT_POLL_US and the halt and reset helpers are separate patches
- Keep the order of the state checks, tell old state is which mode
- sd1_mode_find(): use a name and its length from the start
- The serdes1 value is one mode name, read with hwconfig_arg()
- No skip logic yet, entering a mode through another one is another
topic
Changes in v4:
- New patch
board/nxp/lx2160a/serdes_split.c | 127 ++++++++++++++++++++++---------
board/nxp/lx2160a/serdes_split.h | 16 +---
2 files changed, 92 insertions(+), 51 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 5dcdeff5898..1cc9c7e5509 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -246,8 +246,16 @@ static void print_rcw_view(int sd)
#if defined(CONFIG_ARCH_LX2160A)
+struct sd1_mode {
+ const char *name; /* hwconfig serdes1:<name> */
+ const char *desc;
+ const char *from;
+ bool (*is_active)(unsigned long base);
+ int (*enter)(unsigned long base);
+};
+
/*
- * The split itself.
+ * 1x100GE + 4x25G
*
* This is NXP's e100g1_split.rcw sequence, moved from the PBI into
* U-Boot.
@@ -266,7 +274,7 @@ static void print_rcw_view(int sd)
#define SRDS_POLL_US 10000 /* NXP waits ~100 cycles */
-static bool srds1_split_state(unsigned long base)
+static bool sd1_is_100g4x25g(unsigned long base)
{
u32 pccd = in_le32((void __iomem *)SRDS_PCCD(base));
u32 pcce = in_le32((void __iomem *)SRDS_PCCE(base));
@@ -276,12 +284,7 @@ static bool srds1_split_state(unsigned long base)
PCCD_E25G_CFG(pccd, 2) && PCCD_E25G_CFG(pccd, 3);
}
-bool lx2160a_serdes1_is_split(void)
-{
- return srds1_split_state(srds_base(FSL_SRDS_1));
-}
-
-static bool srds1_is_unsplit(unsigned long base)
+static bool sd1_is_2x100g(unsigned long base)
{
u32 pccd = in_le32((void __iomem *)SRDS_PCCD(base));
u32 pcce = in_le32((void __iomem *)SRDS_PCCE(base));
@@ -399,24 +402,11 @@ static int sd1_reset_wait(unsigned long base, unsigned long lanes)
return ret;
}
-int lx2160a_serdes1_split(void)
+static int sd1_enter_100g4x25g(unsigned long base)
{
- unsigned long base = srds_base(FSL_SRDS_1);
unsigned long lanes = SD1_LNE_LNH;
int m, ret, err;
- if (srds1_split_state(base)) {
- debug("lx2160a serdes: SD1 already split, nothing to do\n");
- return 0;
- }
-
- if (!srds1_is_unsplit(base)) {
- printf("lx2160a serdes: SD1 is in neither the split nor the unsplit state (PCCD=%08x PCCE=%08x), refusing\n",
- in_le32((void __iomem *)SRDS_PCCD(base)),
- in_le32((void __iomem *)SRDS_PCCE(base)));
- return -EINVAL;
- }
-
/* Lanes E-H are one 100G port at this point. */
ret = sd1_halt_port(base, lanes);
if (ret == -EINVAL)
@@ -436,36 +426,99 @@ int lx2160a_serdes1_split(void)
/* Reset. Every lane is its own master now, so all four count. */
sd1_reset_req(base, lanes);
err = sd1_reset_wait(base, lanes);
- if (err)
- ret = err;
-
- if (!srds1_split_state(base)) {
- printf("lx2160a serdes: split did not take (PCCD=%08x PCCE=%08x)\n",
- in_le32((void __iomem *)SRDS_PCCD(base)),
- in_le32((void __iomem *)SRDS_PCCE(base)));
- return -EIO;
+
+ return err ? err : ret;
+}
+
+static const struct sd1_mode sd1_modes[] = {
+ {
+ .name = "2x100g",
+ .desc = "2x 100GE",
+ .is_active = sd1_is_2x100g,
+ },
+ {
+ .name = "100g4x25g",
+ .desc = "1x 100GE + 4x 25G",
+ .from = "2x100g",
+ .is_active = sd1_is_100g4x25g,
+ .enter = sd1_enter_100g4x25g,
+ },
+};
+
+static const struct sd1_mode *sd1_mode_find(const char *name, size_t len)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sd1_modes); i++)
+ if (strlen(sd1_modes[i].name) == len &&
+ !strncmp(sd1_modes[i].name, name, len))
+ return &sd1_modes[i];
+
+ return NULL;
+}
+
+static void sd1_print_pcc(unsigned long base)
+{
+ printf("PCCC=%08x PCCD=%08x PCCE=%08x",
+ in_le32((void __iomem *)SRDS_PCCC(base)),
+ in_le32((void __iomem *)SRDS_PCCD(base)),
+ in_le32((void __iomem *)SRDS_PCCE(base)));
+}
+
+static int sd1_enter(const struct sd1_mode *mode)
+{
+ unsigned long base = srds_base(FSL_SRDS_1);
+ const struct sd1_mode *from = NULL;
+ int ret;
+
+ if (mode->is_active(base))
+ return 0;
+
+ if (mode->from)
+ from = sd1_mode_find(mode->from, strlen(mode->from));
+
+ if (!mode->enter || !from || !from->is_active(base)) {
+ printf("lx2160a serdes: serdes1:%s needs SD1 to be %s, it is not (",
+ mode->name, from ? from->desc : mode->desc);
+ sd1_print_pcc(base);
+ printf("), refusing\n");
+ return -EINVAL;
+ }
+
+ ret = mode->enter(base);
+ if (!mode->is_active(base)) {
+ printf("lx2160a serdes: SD1 is not %s (", mode->desc);
+ sd1_print_pcc(base);
+ printf("), stopping\n");
+ return ret ? ret : -EIO;
}
- printf("lx2160a serdes: SD1 100GE.1 split into 4x 25G%s\n",
+ printf("lx2160a serdes: SD1 now %s%s\n", mode->desc,
ret ? " (with warnings above)" : "");
- return ret;
+ return 0;
}
/*
- * setenv hwconfig serdes1:100g4x25g
+ * setenv hwconfig serdes1:<mode>
*
- * Idempotent: a board whose PBI already split SD1 skip it too.
+ * Idempotent: a board whose PBI already configured SD1 skips it.
*/
void lx2160a_serdes_apply_hwconfig(void)
{
- if (!hwconfig_sub("serdes1", "100g4x25g"))
+ const struct sd1_mode *mode;
+ const char *arg;
+ size_t len;
+
+ arg = hwconfig_arg("serdes1", &len);
+ if (!arg)
return;
- if (lx2160a_serdes1_is_split())
+ mode = sd1_mode_find(arg, len);
+ if (!mode || mode->is_active(srds_base(FSL_SRDS_1)))
return;
- lx2160a_serdes1_split();
+ sd1_enter(mode);
}
#endif /* CONFIG_ARCH_LX2160A */
diff --git a/board/nxp/lx2160a/serdes_split.h b/board/nxp/lx2160a/serdes_split.h
index 8dce9ddf97a..5a820c8c5d8 100644
--- a/board/nxp/lx2160a/serdes_split.h
+++ b/board/nxp/lx2160a/serdes_split.h
@@ -7,25 +7,13 @@
#define __LX2160A_SERDES_SPLIT_H
/*
- * The split is LX2160A only: LX2162A's SerDes 1 is four lanes with no
+ * SD1 modes are for LX2160A only: LX2162A's SD 1 is four lanes with no
* 100GE in its protocol table.
*/
#if defined(CONFIG_ARCH_LX2160A)
-/* Is SerDes 1 already 1x 100G + 4x 25G? */
-bool lx2160a_serdes1_is_split(void);
-
-/*
- * Split SerDes 1's 100GE.1 (lanes LNE-LNH) into 4x 25G.
- *
- * Refuses unless SD1 is in the unsplit state, and must be called before
- * the Management Complex starts: MC latches the live protocol-converter
- * configuration when it boots.
- */
-int lx2160a_serdes1_split(void);
-
/*
- * Apply `hwconfig=serdes1:100g4x25g` if the board's environment asks for it.
+ * Apply `hwconfig=serdes1:<mode>` if the board's environment asks for it.
* Boards call this from reset_phy(), before mc_env_boot().
*/
void lx2160a_serdes_apply_hwconfig(void);
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 06/13] board: lx2160a: serdes: report unknown SD1 cases
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (4 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 05/13] board: lx2160a: serdes: set SD1 with a table Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 07/13] board: lx2160a: serdes: no SD1 config once MC runs Vincent Jardin
` (6 subsequent siblings)
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
Check and if unknown display:
lx2160a serdes: unknown hwconfig serdes1:split, ignored
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v5)
Changes in v5:
- Print the serdes1 value as hwconfig_arg() returns it, no sub-option
Changes in v4:
- New patch
board/nxp/lx2160a/serdes_split.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 1cc9c7e5509..57504a2327c 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -515,7 +515,13 @@ void lx2160a_serdes_apply_hwconfig(void)
return;
mode = sd1_mode_find(arg, len);
- if (!mode || mode->is_active(srds_base(FSL_SRDS_1)))
+ if (!mode) {
+ printf("lx2160a serdes: unknown hwconfig serdes1:%.*s, ignored\n",
+ (int)len, arg);
+ return;
+ }
+
+ if (mode->is_active(srds_base(FSL_SRDS_1)))
return;
sd1_enter(mode);
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 07/13] board: lx2160a: serdes: no SD1 config once MC runs
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (5 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 06/13] board: lx2160a: serdes: report unknown SD1 cases Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 08/13] board: lx2160a: serdes: add serdes1:2x40g Vincent Jardin
` (5 subsequent siblings)
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
The MC reads the SD1 lane grouping once, when it boots.
lx2160a_serdes_apply_hwconfig() has to run before.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v4)
Changes in v4:
- New patch
board/nxp/lx2160a/serdes_split.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 57504a2327c..ba3be4bc0d7 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -12,6 +12,7 @@
#include <asm/arch/fsl_serdes.h>
#include <asm/arch/immap_lsch3.h>
#include <asm/arch/soc.h> /* gur_in32() picks the GUR endianness */
+#include <fsl-mc/fsl_mc.h>
#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -524,6 +525,12 @@ void lx2160a_serdes_apply_hwconfig(void)
if (mode->is_active(srds_base(FSL_SRDS_1)))
return;
+ if (IS_ENABLED(CONFIG_FSL_MC_ENET) && get_mc_boot_status() != -1) {
+ printf("lx2160a serdes: the MC is already running, serdes1:%s not applied\n",
+ mode->name);
+ return;
+ }
+
sd1_enter(mode);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 08/13] board: lx2160a: serdes: add serdes1:2x40g
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (6 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 07/13] board: lx2160a: serdes: no SD1 config once MC runs Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-02 14:07 ` Vladimir Oltean
2026-10-01 20:47 ` [PATCH v6 09/13] board: lx2160a: serdes: enter a SD1 mode through the mode it starts from Vincent Jardin
` (4 subsequent siblings)
12 siblings, 1 reply; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
Add a SD1 mode that makes the two 100GE ports of protocol 13
two 40GE (XLAUI-4) ports, dpmac.2 on LNA-LND and dpmac.1 on LNE-LNH,
as protocol 20 would have built them.
Sequence:
- bring PLLS up and wait for its lock
- halt PLLF, which puts all eight lanes in reset
- make them 2x 4-lane ports on PLLS with their master lanes kept
- switch PCCE from E100G to E40G
- reset PLLS which restarts every lane
Signed-off-by: Vincent Jardin <vjardin@free.fr>
---
Changes in v6:
- Better explain the move to PLLS by the clock net, not BY_N_RATE_SEL (Vladimir)
- Only 161.1328125 MHz PLLS reference clock is supported,
from the PLLS input or through SRDS_INTRA_REF_CLK_S1
Changes in v4:
- was on v3 2/5, now it is an entry of the mode table
board/nxp/lx2160a/serdes_split.c | 148 +++++++++++++++++++++++++++++++
1 file changed, 148 insertions(+)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index ba3be4bc0d7..0107e8636a6 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -29,10 +29,17 @@
#define SRDS_LANES 8
#define SRDS_BLOCK_STRIDE 0x10000
#define SRDS_LANE_STRIDE 0x100
+#define SRDS_PLL_STRIDE 0x100
+#define SRDS_PLLnRSTCTL(b, n) ((b) + 0x400 + (n) * SRDS_PLL_STRIDE)
+#define SRDS_PLLnCR0(b, n) ((b) + 0x404 + (n) * SRDS_PLL_STRIDE)
+#define SRDS_PLLnCR1(b, n) ((b) + 0x408 + (n) * SRDS_PLL_STRIDE)
+#define SRDS_PLLnCR5(b, n) ((b) + 0x414 + (n) * SRDS_PLL_STRIDE)
#define SRDS_LNmGCR0(b, m) ((b) + 0x800 + (m) * SRDS_LANE_STRIDE)
#define SRDS_LNmTRSTCTL(b, m) ((b) + 0x820 + (m) * SRDS_LANE_STRIDE)
+#define SRDS_LNmTGCR0(b, m) ((b) + 0x824 + (m) * SRDS_LANE_STRIDE)
#define SRDS_LNmRRSTCTL(b, m) ((b) + 0x840 + (m) * SRDS_LANE_STRIDE)
+#define SRDS_LNmRGCR0(b, m) ((b) + 0x844 + (m) * SRDS_LANE_STRIDE)
#define SRDS_PCCC(b) ((b) + 0x10B0)
#define SRDS_PCCD(b) ((b) + 0x10B4)
#define SRDS_PCCE(b) ((b) + 0x10B8)
@@ -51,6 +58,14 @@
#define RSTCTL_STP_REQ BIT(26)
#define RSTCTL_DIS BIT(24)
+/* PLLnRSTCTL adds two status bits the lane RSTCTLs do not have */
+#define PLLRSTCTL_RST_ERR BIT(29) /* no lock before time-out */
+#define PLLRSTCTL_LOCK BIT(23) /* PLL calibrated + locked */
+
+/* PCCE: E40Ga at 30-28 (LRV 31), E40Gb at 26-24 (LRV 27) */
+#define PCCE_E40GA_CFG(v) (((v) >> 28) & 0x7)
+#define PCCE_E40GB_CFG(v) (((v) >> 24) & 0x7)
+
/* PCCE: E100Ga at 14-12 (LRV 15), E100Gb at 10-8 (LRV 11) */
#define PCCE_E100GA_CFG(v) (((v) >> 12) & 0x7)
#define PCCE_E100GA_LRV(v) (((v) >> 15) & 0x1)
@@ -261,6 +276,7 @@ struct sd1_mode {
* This is NXP's e100g1_split.rcw sequence, moved from the PBI into
* U-Boot.
*/
+#define SD1_LNA_LND GENMASK(3, 0)
#define SD1_LNE_LNH GENMASK(7, 4)
/*
@@ -431,6 +447,131 @@ static int sd1_enter_100g4x25g(unsigned long base)
return err ? err : ret;
}
+/*
+ * 2x40GE (XLAUI-4), dpmac.2 on LNA-LND and dpmac.1 on LNE-LNH,
+ * protocol 20 builds the same.
+ *
+ * A PLL makes one clock net, and each lane takes its rate from the
+ * clock net of one PLL, through its own BY_N_RATE_SEL. 25GE and 100GE
+ * lanes run at 25.78125 Gbaud, twice the 12.890625 GHz clock net of
+ * PLLF. 40GE lanes run at 10.3125 Gbaud, which no ratio of 12.890625
+ * GHz gives: they need the 10.3125 GHz clock net, which only PLLS
+ * makes (PLLnCR1[FRATE_SEL]=00110b). So the lanes move to PLLS.
+ *
+ * Protocol 13 does not use PLLS, and NXP's RCWs for it power it down
+ * (SRDS_PLL_PD_PLL2=1), which leaves PLLSRSTCTL[DIS] set: software can
+ * clear it. PLLS then gets the PLLSCR0/CR1/CR5 values the SoC loads
+ * for protocol 20 when SRDS_PLL_REF_CLK_SEL_S1 selects 161.1328125 MHz
+ * for PLLS.
+ *
+ * Only a 161.1328125 MHz PLLS reference clock is supported. It comes
+ * from the SD1 PLLS reference clock input, or from the PLLF one when
+ * the RCW sets SRDS_INTRA_REF_CLK_S1=1, as 25GE and 100GE already need
+ * 161.1328125 MHz on PLLF. 156.25 MHz, also valid for a 10.3125 GHz
+ * clock net, would need PLLSCR0[REFCLK_SEL]=00010b and is not handled.
+ * Nothing here can check the reference clock: PLLSRSTCTL[LOCK] does
+ * not tell its frequency.
+ */
+#define SRDS_PLLF 0
+#define SRDS_PLLS 1
+#define SLOW_PLLS_CR0 0x00040000 /* REFCLK_SEL=00100b, 161.1328125 MHz */
+#define SLOW_PLLS_CR1 0x86100008 /* 10.3125 GHz clock net */
+#define SLOW_PLLS_CR5 0x00001000
+/* PROTO_SEL=01010b (XFI/10GBase-R/40GBase-R) + IF_WIDTH=010b (20-bit) */
+#define F40G_GCR0_MASTER 0x00000052
+#define F40G_GCR0_SLAVE 0x00010052
+/* LNmTGCR0/LNmRGCR0: USE_SLOW_PLL=1 (bit 28), BY_N_RATE_SEL=000b full */
+#define SLOW_LANE_GCR 0x10000000
+#define F40G_PCCE 0x11000000 /* E40Ga+E40Gb on, E100G off */
+
+static bool sd1_is_2x40g(unsigned long base)
+{
+ u32 pcce = in_le32((void __iomem *)SRDS_PCCE(base));
+
+ return PCCE_E40GA_CFG(pcce) != 0 && PCCE_E40GB_CFG(pcce) != 0 &&
+ PCCE_E100GA_CFG(pcce) == 0 && PCCE_E100GB_CFG(pcce) == 0;
+}
+
+/* Program PLLS (Slow) for 10.3125 GHz, and wait for its lock */
+static int sd1_plls_up(unsigned long base)
+{
+ unsigned long rstctl = SRDS_PLLnRSTCTL(base, SRDS_PLLS);
+ u32 v;
+
+ out_le32((void __iomem *)SRDS_PLLnCR0(base, SRDS_PLLS), SLOW_PLLS_CR0);
+ out_le32((void __iomem *)SRDS_PLLnCR1(base, SRDS_PLLS), SLOW_PLLS_CR1);
+ out_le32((void __iomem *)SRDS_PLLnCR5(base, SRDS_PLLS), SLOW_PLLS_CR5);
+
+ out_le32((void __iomem *)rstctl, 0); /* clears DIS */
+ out_le32((void __iomem *)rstctl, RSTCTL_RST_REQ);
+
+ if (poll_clear(rstctl, RSTCTL_RST_REQ)) {
+ printf("lx2160a serdes: SD1 PLLS reset did not complete within %d us\n",
+ SRDS_POLL_US);
+ return -ETIMEDOUT;
+ }
+
+ v = in_le32((void __iomem *)rstctl);
+ if ((v & PLLRSTCTL_RST_ERR) || !(v & PLLRSTCTL_LOCK) ||
+ !(v & RSTCTL_RST_DONE)) {
+ printf("lx2160a serdes: SD1 PLLS did not lock (PLLSRSTCTL=%08x)\n",
+ v);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int sd1_enter_2x40g(unsigned long base)
+{
+ unsigned long pllf = SRDS_PLLnRSTCTL(base, SRDS_PLLF);
+ unsigned long plls = SRDS_PLLnRSTCTL(base, SRDS_PLLS);
+ unsigned long lanes = SD1_LNA_LND | SD1_LNE_LNH;
+ int m, lo, hi, ret, err;
+
+ /* The two ports keep their master lanes. */
+ lo = sd1_port_master(base, SD1_LNA_LND);
+ hi = sd1_port_master(base, SD1_LNE_LNH);
+ if (lo < 0 || hi < 0)
+ return -EINVAL;
+
+ ret = sd1_plls_up(base);
+ if (ret)
+ return ret;
+
+ /*
+ * Halt PLLF, which puts every lane using it, all eight, in reset
+ * "to allow reconfiguration".
+ */
+ out_le32((void __iomem *)pllf, RSTCTL_HLT_REQ);
+ if (poll_clear(pllf, RSTCTL_HLT_REQ)) {
+ printf("lx2160a serdes: SD1 PLLF did not halt within %d us, continuing\n",
+ SRDS_POLL_US);
+ ret = -ETIMEDOUT;
+ }
+
+ for_each_set_bit(m, &lanes, SRDS_LANES) {
+ out_le32((void __iomem *)SRDS_LNmGCR0(base, m),
+ m == lo || m == hi ? F40G_GCR0_MASTER : F40G_GCR0_SLAVE);
+ out_le32((void __iomem *)SRDS_LNmTGCR0(base, m), SLOW_LANE_GCR);
+ out_le32((void __iomem *)SRDS_LNmRGCR0(base, m), SLOW_LANE_GCR);
+ }
+
+ out_le32((void __iomem *)SRDS_PCCE(base), F40G_PCCE);
+
+ /* Every lane now selects PLLS, so one PLL reset restarts them all. */
+ out_le32((void __iomem *)plls, RSTCTL_RST_REQ);
+ if (poll_clear(plls, RSTCTL_RST_REQ)) {
+ printf("lx2160a serdes: SD1 PLLS reset did not complete within %d us\n",
+ SRDS_POLL_US);
+ ret = -ETIMEDOUT;
+ }
+
+ err = sd1_reset_wait(base, lanes);
+
+ return err ? err : ret;
+}
+
static const struct sd1_mode sd1_modes[] = {
{
.name = "2x100g",
@@ -444,6 +585,13 @@ static const struct sd1_mode sd1_modes[] = {
.is_active = sd1_is_100g4x25g,
.enter = sd1_enter_100g4x25g,
},
+ {
+ .name = "2x40g",
+ .desc = "2x 40GE",
+ .from = "2x100g",
+ .is_active = sd1_is_2x40g,
+ .enter = sd1_enter_2x40g,
+ },
};
static const struct sd1_mode *sd1_mode_find(const char *name, size_t len)
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 09/13] board: lx2160a: serdes: enter a SD1 mode through the mode it starts from
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (7 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 08/13] board: lx2160a: serdes: add serdes1:2x40g Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-02 14:08 ` Vladimir Oltean
2026-10-01 20:47 ` [PATCH v6 10/13] board: lx2160a: serdes: add serdes1:40g4x10g Vincent Jardin
` (3 subsequent siblings)
12 siblings, 1 reply; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
So far a mode is entered only when SD1 already is in the mode it
starts from.
The next mode, 40g4x10g, splits the second 40GE port into 4x XFI:
it starts from 2x40g.
Protocol 20 boots in 2x40g, but protocol 13 boots in 2x100g, which has
to be made 2x40g first.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
---
(no changes since v5)
Changes in v5:
- New patch, split out of "set SD1 with a table"
board/nxp/lx2160a/serdes_split.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 0107e8636a6..41208ca79ab 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -614,7 +614,8 @@ static void sd1_print_pcc(unsigned long base)
in_le32((void __iomem *)SRDS_PCCE(base)));
}
-static int sd1_enter(const struct sd1_mode *mode)
+static int sd1_enter(const struct sd1_mode *mode,
+ const struct sd1_mode *target, int depth)
{
unsigned long base = srds_base(FSL_SRDS_1);
const struct sd1_mode *from = NULL;
@@ -623,17 +624,23 @@ static int sd1_enter(const struct sd1_mode *mode)
if (mode->is_active(base))
return 0;
- if (mode->from)
- from = sd1_mode_find(mode->from, strlen(mode->from));
-
- if (!mode->enter || !from || !from->is_active(base)) {
+ if (!mode->enter) {
printf("lx2160a serdes: serdes1:%s needs SD1 to be %s, it is not (",
- mode->name, from ? from->desc : mode->desc);
+ target->name, mode->desc);
sd1_print_pcc(base);
printf("), refusing\n");
return -EINVAL;
}
+ if (mode->from)
+ from = sd1_mode_find(mode->from, strlen(mode->from));
+ if (!from || depth >= ARRAY_SIZE(sd1_modes))
+ return -EINVAL;
+
+ ret = sd1_enter(from, target, depth + 1);
+ if (ret)
+ return ret;
+
ret = mode->enter(base);
if (!mode->is_active(base)) {
printf("lx2160a serdes: SD1 is not %s (", mode->desc);
@@ -679,7 +686,7 @@ void lx2160a_serdes_apply_hwconfig(void)
return;
}
- sd1_enter(mode);
+ sd1_enter(mode, mode, 0);
}
#endif /* CONFIG_ARCH_LX2160A */
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 10/13] board: lx2160a: serdes: add serdes1:40g4x10g
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (8 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 09/13] board: lx2160a: serdes: enter a SD1 mode through the mode it starts from Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-07 11:27 ` Vladimir Oltean
2026-10-01 20:47 ` [PATCH v6 11/13] board: lx2160a: serdes: add serdes1:100g4x10g Vincent Jardin
` (2 subsequent siblings)
12 siblings, 1 reply; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
Add a SD1 mode that keeps dpmac.2 as 40GE on LNA-LND and that changes
the LNE-LNH 40GE port 4xXFI ports, dpmac.3-6.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
---
(no changes since v5)
Changes in v5:
- sd1_reset_req()
Changes in v4:
- was on v3 3/5, now let's add an entry of the mode table
board/nxp/lx2160a/serdes_split.c | 69 +++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 2 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 41208ca79ab..479e4789eaf 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -380,11 +380,13 @@ static int sd1_halt_port(unsigned long base, unsigned long lanes)
return 0;
}
-static void sd1_reset_req(unsigned long base, unsigned long lanes)
+static void sd1_reset_req(unsigned long base, unsigned long lanes, int skip)
{
int m;
for_each_set_bit(m, &lanes, SRDS_LANES) {
+ if (m == skip)
+ continue;
out_le32((void __iomem *)SRDS_LNmTRSTCTL(base, m),
RSTCTL_RST_REQ);
out_le32((void __iomem *)SRDS_LNmRRSTCTL(base, m),
@@ -441,7 +443,7 @@ static int sd1_enter_100g4x25g(unsigned long base)
out_le32((void __iomem *)SRDS_PCCD(base), SPLIT_PCCD);
/* Reset. Every lane is its own master now, so all four count. */
- sd1_reset_req(base, lanes);
+ sd1_reset_req(base, lanes, -1);
err = sd1_reset_wait(base, lanes);
return err ? err : ret;
@@ -572,6 +574,62 @@ static int sd1_enter_2x40g(unsigned long base)
return err ? err : ret;
}
+/*
+ * 1x40GE + 4x10G: dpmac.2 stays 40GE on LNA-LND, LNE-LNH become
+ * 4xXFI ports, dpmac.3-6.
+ * An XFI lane is a 40GE lane that is its own port master:
+ * same PROTO_SEL and width, same PLLS and rate.
+ *
+ * XFI LNmGCR0 = 0x00000052 LNmTGCR0 = 0x10000000
+ * 40GE LNmGCR0 = 0x00010052 LNmTGCR0 = 0x10000000 (but its master)
+ * ^ PORT_LN0_B
+ */
+#define XFI_GCR0 0x00000052 /* as 40GE, but own port master */
+#define X10G_PCCE 0x01000000 /* E40Gb kept (lanes 0-3) */
+#define XFI_PCCC 0x88889999 /* XFI converters for lanes 4-7 */
+
+static bool sd1_is_40g4x10g(unsigned long base)
+{
+ u32 pccc = in_le32((void __iomem *)SRDS_PCCC(base));
+ u32 pcce = in_le32((void __iomem *)SRDS_PCCE(base));
+
+ return PCCE_E40GB_CFG(pcce) != 0 && PCCE_E40GA_CFG(pcce) == 0 &&
+ (pccc & 0xffff) == 0x9999;
+}
+
+static int sd1_reset_both(unsigned long base, int keep)
+{
+ sd1_reset_req(base, SD1_LNE_LNH, -1);
+ sd1_reset_req(base, SD1_LNA_LND, keep);
+ sd1_reset_req(base, BIT(keep), -1);
+
+ return sd1_reset_wait(base, SD1_LNA_LND | SD1_LNE_LNH);
+}
+
+static int sd1_enter_40g4x10g(unsigned long base)
+{
+ unsigned long lanes = SD1_LNE_LNH;
+ int m, keep, ret, err;
+
+ keep = sd1_port_master(base, SD1_LNA_LND);
+ if (keep < 0)
+ return -EINVAL;
+
+ ret = sd1_halt_port(base, lanes);
+ if (ret == -EINVAL)
+ return ret;
+
+ for_each_set_bit(m, &lanes, SRDS_LANES)
+ out_le32((void __iomem *)SRDS_LNmGCR0(base, m), XFI_GCR0);
+
+ out_le32((void __iomem *)SRDS_PCCE(base), X10G_PCCE);
+ out_le32((void __iomem *)SRDS_PCCC(base), XFI_PCCC);
+
+ err = sd1_reset_both(base, keep);
+
+ return err ? err : ret;
+}
+
static const struct sd1_mode sd1_modes[] = {
{
.name = "2x100g",
@@ -592,6 +650,13 @@ static const struct sd1_mode sd1_modes[] = {
.is_active = sd1_is_2x40g,
.enter = sd1_enter_2x40g,
},
+ {
+ .name = "40g4x10g",
+ .desc = "1x 40GE + 4x 10G",
+ .from = "2x40g",
+ .is_active = sd1_is_40g4x10g,
+ .enter = sd1_enter_40g4x10g,
+ },
};
static const struct sd1_mode *sd1_mode_find(const char *name, size_t len)
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 11/13] board: lx2160a: serdes: add serdes1:100g4x10g
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (9 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 10/13] board: lx2160a: serdes: add serdes1:40g4x10g Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 12/13] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 13/13] board: nbxv3: apply sd1 hwconfig before MC starts Vincent Jardin
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
Add the SD1 mode that keeps dpmac.2 as 100GE on LNA-LND and makes
LNE-LNH four XFI ports, dpmac.3-6.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v4)
Changes in v4:
- Was on v3 with 4/5, now let's add an entry of the mode table
board/nxp/lx2160a/serdes_split.c | 56 ++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 479e4789eaf..ea7a745c31b 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -630,6 +630,55 @@ static int sd1_enter_40g4x10g(unsigned long base)
return err ? err : ret;
}
+/*
+ * 1x100GE + 4x10G: dpmac.2 stays 100GE on LNA-LND at 25.78125 Gbaud on PLLF,
+ * and LNE-LNH become four XFI ports, dpmac.3-6, at 10.3125 Gbaud on PLLS.
+ *
+ * Note: it is the only mode that runs SD1 on both PLLs Slow and Fast !
+ */
+#define M100G_PCCE SPLIT_PCCE /* E100Gb kept (lanes 0-3) */
+
+static bool sd1_is_100g4x10g(unsigned long base)
+{
+ u32 pccc = in_le32((void __iomem *)SRDS_PCCC(base));
+ u32 pcce = in_le32((void __iomem *)SRDS_PCCE(base));
+
+ return PCCE_E100GB_CFG(pcce) != 0 && PCCE_E100GA_CFG(pcce) == 0 &&
+ (pccc & 0xffff) == 0x9999;
+}
+
+static int sd1_enter_100g4x10g(unsigned long base)
+{
+ unsigned long lanes = SD1_LNE_LNH;
+ int m, keep, ret, err;
+
+ keep = sd1_port_master(base, SD1_LNA_LND);
+ if (keep < 0)
+ return -EINVAL;
+
+ ret = sd1_plls_up(base);
+ if (ret)
+ return ret;
+
+ /* Halt only the port that moves. */
+ ret = sd1_halt_port(base, lanes);
+ if (ret == -EINVAL)
+ return ret;
+
+ for_each_set_bit(m, &lanes, SRDS_LANES) {
+ out_le32((void __iomem *)SRDS_LNmGCR0(base, m), XFI_GCR0);
+ out_le32((void __iomem *)SRDS_LNmTGCR0(base, m), SLOW_LANE_GCR);
+ out_le32((void __iomem *)SRDS_LNmRGCR0(base, m), SLOW_LANE_GCR);
+ }
+
+ out_le32((void __iomem *)SRDS_PCCE(base), M100G_PCCE);
+ out_le32((void __iomem *)SRDS_PCCC(base), XFI_PCCC);
+
+ err = sd1_reset_both(base, keep);
+
+ return err ? err : ret;
+}
+
static const struct sd1_mode sd1_modes[] = {
{
.name = "2x100g",
@@ -657,6 +706,13 @@ static const struct sd1_mode sd1_modes[] = {
.is_active = sd1_is_40g4x10g,
.enter = sd1_enter_40g4x10g,
},
+ {
+ .name = "100g4x10g",
+ .desc = "1x 100GE + 4x 10G",
+ .from = "2x100g",
+ .is_active = sd1_is_100g4x10g,
+ .enter = sd1_enter_100g4x10g,
+ },
};
static const struct sd1_mode *sd1_mode_find(const char *name, size_t len)
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 12/13] doc: lx2160a: document the sd1 hwconfig option
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (10 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 11/13] board: lx2160a: serdes: add serdes1:100g4x10g Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
2026-10-07 10:47 ` Vladimir Oltean
2026-10-01 20:47 ` [PATCH v6 13/13] board: nbxv3: apply sd1 hwconfig before MC starts Vincent Jardin
12 siblings, 1 reply; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
Enrich README.fsl-hwconfig with this sd1 reconfiguration scenarios.
Add a reference to the Layerscape README.soc.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
---
Changes in v6:
- Only 161.1328125 MHz PLLS reference clock is supported,
from the PLLS input or through SRDS_INTRA_REF_CLK_S1 (Vladimir)
Changes in v5:
- Reword the grouping sentence, suggested by Vladimir
- PLLS reference clock as an initial condition
- Drop the MC bullet, and the list of boards
Changes in v4:
- was v3 5/5, rewritten using a table
.../cpu/armv8/fsl-layerscape/doc/README.soc | 7 ++
doc/README.fsl-hwconfig | 64 +++++++++++++++++++
2 files changed, 71 insertions(+)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
index f2efd4cc1d7..a641e4978aa 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
+++ b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
@@ -331,6 +331,13 @@ LX2160A SoC has 2 more similar SoC personalities
2)LX2080A, few difference w.r.t. LX2160A:
a) Eight 64-bit ARM v8 Cortex-A72 CPUs
+SerDes 1 lane grouping
+ SRDS_PRTCL_S1 is latched at reset. U-Boot can still configure SD1 before
+ the MC starts:
+ 1x100GE + 4x25G, 2x40GE, 1x40GE + 4x10G or 1x100GE + 4x10G.
+ See 'serdes1' in doc/README.fsl-hwconfig, and the 'lx2160_serdes status'
+ command.
+
LS1028A
--------
diff --git a/doc/README.fsl-hwconfig b/doc/README.fsl-hwconfig
index e752505da49..91bc39d7238 100644
--- a/doc/README.fsl-hwconfig
+++ b/doc/README.fsl-hwconfig
@@ -44,3 +44,67 @@ usb
usb1:dr_mode=host;usb2:dr_mode=peripheral'
usb1:dr_mode=host,phy_type=utmi;usb2:dr_mode=host'
+
+serdes1
+ Specific to the LX2160A boards whose reset_phy() calls
+ lx2160a_serdes_apply_hwconfig() before mc_env_boot().
+
+ SRDS_PRTCL_S1 is latched at reset, but the eight SD1 (SerDes) lanes
+ can still be configured before the DPAA2 management complex (MC) starts.
+ This option alters the Ethernet MAC-to-lane grouping after the fact
+ (RCWSR29 keeps reporting the initial protocol).
+
+ 'serdes1:2x100g'
+ 2x 100GE (CAUI-4), what protocol 13 builds: nothing to do
+
+ 'serdes1:100g4x25g'
+ 1x 100GE + 4x 25G
+
+ 'serdes1:2x40g'
+ 2x 40GE (XLAUI-4)
+
+ 'serdes1:40g4x10g'
+ 1x 40GE + 4x 10G (XFI)
+
+ 'serdes1:100g4x10g'
+ 1x 100GE + 4x 10G (XFI)
+
+ Each mode starts from the one in the 'from' column, which is
+ entered first when SD1 is not in it yet, and so on down to what
+ SRDS_PRTCL_S1 built:
+
+ mode from SRDS_PRTCL_S1 lanes run on
+ 2x100g - 13 PLLF
+ 100g4x25g 2x100g 13 PLLF
+ 2x40g 2x100g 13 PLLS
+ 40g4x10g 2x40g 13 or 20 PLLS
+ 100g4x10g 2x100g 13 PLLF and PLLS
+
+ What each mode makes of the two four-lane ports of protocol 13:
+
+ mode dpmac.2 port dpmac.1 port
+ 2x100g 100GE 100GE
+ 100g4x25g 100GE 4x 25G: dpmac.3 to dpmac.6
+ 2x40g 40GE 40GE
+ 40g4x10g 40GE 4x XFI: dpmac.3 to dpmac.6
+ 100g4x10g 100GE 4x XFI: dpmac.3 to dpmac.6
+
+ Initial conditions:
+
+ - PLLS needs a 161.1328125 MHz reference clock, for which 2x40g,
+ 40g4x10g and 100g4x10g program it. It can come from the SD1
+ PLLS reference clock input, or from the PLLF one with
+ SRDS_INTRA_REF_CLK_S1=1. A 156.25 MHz PLLS reference clock is
+ not supported. With protocol 13 PLLS is not in use, so nothing
+ checks that clock before these modes start it.
+ - The MC DPC must set follow_hw_pssr in board_info/serdes, for the
+ MC to read the lanes rather than look at protocol, and the DPL
+ must use the dpmacs of the new grouping.
+
+ 'lx2160_serdes status 1' shows the resulting lane grouping and
+ protocol converters.
+
+ Example:
+ setenv hwconfig serdes1:100g4x25g
+ saveenv
+ reset
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v6 13/13] board: nbxv3: apply sd1 hwconfig before MC starts
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (11 preceding siblings ...)
2026-10-01 20:47 ` [PATCH v6 12/13] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
@ 2026-10-01 20:47 ` Vincent Jardin
12 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-01 20:47 UTC (permalink / raw)
To: u-boot
Cc: Priyanka Jain, Wasim Khan, Tom Rini, Vladimir Oltean, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal, Vincent Jardin
Apply this feature to the nbxv3 board too.
Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
(no changes since v5)
Changes in v5:
- No doc change: the doc no longer lists the boards
Changes in v4:
- New patch
board/nxp/lx2160a/nbxv3/eth_nbxv3.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/board/nxp/lx2160a/nbxv3/eth_nbxv3.c b/board/nxp/lx2160a/nbxv3/eth_nbxv3.c
index a8d249c5cac..69873909733 100644
--- a/board/nxp/lx2160a/nbxv3/eth_nbxv3.c
+++ b/board/nxp/lx2160a/nbxv3/eth_nbxv3.c
@@ -15,6 +15,7 @@
#include <fsl-mc/fsl_mc.h>
#include "carrier.h"
+#include "../serdes_split.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -34,6 +35,8 @@ void reset_phy(void)
*/
nbxv3_carrier_env_init();
+ lx2160a_serdes_apply_hwconfig();
+
if (IS_ENABLED(CONFIG_FSL_MC_ENET))
mc_env_boot();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v6 08/13] board: lx2160a: serdes: add serdes1:2x40g
2026-10-01 20:47 ` [PATCH v6 08/13] board: lx2160a: serdes: add serdes1:2x40g Vincent Jardin
@ 2026-10-02 14:07 ` Vladimir Oltean
2026-10-06 14:10 ` Vincent Jardin
0 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-10-02 14:07 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Priyanka Jain, Wasim Khan, Tom Rini, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal
On Thu, Oct 01, 2026 at 10:47:25PM +0200, Vincent Jardin wrote:
> Add a SD1 mode that makes the two 100GE ports of protocol 13
> two 40GE (XLAUI-4) ports, dpmac.2 on LNA-LND and dpmac.1 on LNE-LNH,
> as protocol 20 would have built them.
>
> Sequence:
> - bring PLLS up and wait for its lock
> - halt PLLF, which puts all eight lanes in reset
> - make them 2x 4-lane ports on PLLS with their master lanes kept
> - switch PCCE from E100G to E40G
> - reset PLLS which restarts every lane
>
> Signed-off-by: Vincent Jardin <vjardin@free.fr>
>
> ---
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v6 09/13] board: lx2160a: serdes: enter a SD1 mode through the mode it starts from
2026-10-01 20:47 ` [PATCH v6 09/13] board: lx2160a: serdes: enter a SD1 mode through the mode it starts from Vincent Jardin
@ 2026-10-02 14:08 ` Vladimir Oltean
0 siblings, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-10-02 14:08 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Priyanka Jain, Wasim Khan, Tom Rini, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal
On Thu, Oct 01, 2026 at 10:47:26PM +0200, Vincent Jardin wrote:
> So far a mode is entered only when SD1 already is in the mode it
> starts from.
>
> The next mode, 40g4x10g, splits the second 40GE port into 4x XFI:
> it starts from 2x40g.
>
> Protocol 20 boots in 2x40g, but protocol 13 boots in 2x100g, which has
> to be made 2x40g first.
>
> Signed-off-by: Vincent Jardin <vjardin@free.fr>
>
> ---
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v6 08/13] board: lx2160a: serdes: add serdes1:2x40g
2026-10-02 14:07 ` Vladimir Oltean
@ 2026-10-06 14:10 ` Vincent Jardin
0 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-06 14:10 UTC (permalink / raw)
To: Vladimir Oltean
Cc: u-boot, Priyanka Jain, Wasim Khan, Tom Rini, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal
Thanks Vladimir
If I am correct, there are 2 missing patch that do not have a review yet:
https://patchwork.ozlabs.org/project/uboot/list/?series=526189
- [v6,10/13] board: lx2160a: serdes: add serdes1:40g4x10g
- [v6,12/13] doc: lx2160a: document the sd1 hwconfig option
thank you,
Vincent
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v6 12/13] doc: lx2160a: document the sd1 hwconfig option
2026-10-01 20:47 ` [PATCH v6 12/13] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
@ 2026-10-07 10:47 ` Vladimir Oltean
2026-10-08 22:36 ` Vincent Jardin
0 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-10-07 10:47 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Priyanka Jain, Wasim Khan, Tom Rini, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal
On Thu, Oct 01, 2026 at 10:47:29PM +0200, Vincent Jardin wrote:
> Enrich README.fsl-hwconfig with this sd1 reconfiguration scenarios.
> Add a reference to the Layerscape README.soc.
>
> Signed-off-by: Vincent Jardin <vjardin@free.fr>
>
> ---
>
> Changes in v6:
> - Only 161.1328125 MHz PLLS reference clock is supported,
> from the PLLS input or through SRDS_INTRA_REF_CLK_S1 (Vladimir)
>
> Changes in v5:
> - Reword the grouping sentence, suggested by Vladimir
> - PLLS reference clock as an initial condition
> - Drop the MC bullet, and the list of boards
>
> Changes in v4:
> - was v3 5/5, rewritten using a table
>
> .../cpu/armv8/fsl-layerscape/doc/README.soc | 7 ++
> doc/README.fsl-hwconfig | 64 +++++++++++++++++++
> 2 files changed, 71 insertions(+)
>
> diff --git a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
> index f2efd4cc1d7..a641e4978aa 100644
> --- a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
> +++ b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
> @@ -331,6 +331,13 @@ LX2160A SoC has 2 more similar SoC personalities
> 2)LX2080A, few difference w.r.t. LX2160A:
> a) Eight 64-bit ARM v8 Cortex-A72 CPUs
>
> +SerDes 1 lane grouping
> + SRDS_PRTCL_S1 is latched at reset. U-Boot can still configure SD1 before
> + the MC starts:
> + 1x100GE + 4x25G, 2x40GE, 1x40GE + 4x10G or 1x100GE + 4x10G.
> + See 'serdes1' in doc/README.fsl-hwconfig, and the 'lx2160_serdes status'
> + command.
> +
>
> LS1028A
> --------
> diff --git a/doc/README.fsl-hwconfig b/doc/README.fsl-hwconfig
> index e752505da49..91bc39d7238 100644
> --- a/doc/README.fsl-hwconfig
> +++ b/doc/README.fsl-hwconfig
> @@ -44,3 +44,67 @@ usb
> usb1:dr_mode=host;usb2:dr_mode=peripheral'
>
> usb1:dr_mode=host,phy_type=utmi;usb2:dr_mode=host'
> +
> +serdes1
> + Specific to the LX2160A boards whose reset_phy() calls
> + lx2160a_serdes_apply_hwconfig() before mc_env_boot().
> +
> + SRDS_PRTCL_S1 is latched at reset, but the eight SD1 (SerDes) lanes
> + can still be configured before the DPAA2 management complex (MC) starts.
> + This option alters the Ethernet MAC-to-lane grouping after the fact
> + (RCWSR29 keeps reporting the initial protocol).
> +
> + 'serdes1:2x100g'
> + 2x 100GE (CAUI-4), what protocol 13 builds: nothing to do
> +
> + 'serdes1:100g4x25g'
> + 1x 100GE + 4x 25G
> +
> + 'serdes1:2x40g'
> + 2x 40GE (XLAUI-4)
> +
> + 'serdes1:40g4x10g'
> + 1x 40GE + 4x 10G (XFI)
> +
> + 'serdes1:100g4x10g'
> + 1x 100GE + 4x 10G (XFI)
> +
> + Each mode starts from the one in the 'from' column, which is
> + entered first when SD1 is not in it yet, and so on down to what
> + SRDS_PRTCL_S1 built:
> +
> + mode from SRDS_PRTCL_S1 lanes run on
> + 2x100g - 13 PLLF
> + 100g4x25g 2x100g 13 PLLF
> + 2x40g 2x100g 13 PLLS
2x40g should have the "SRDS_PRTCL_S1" field as "13 or 20" as well, no?
Because protocol 20 is literally 2x40g.
> + 40g4x10g 2x40g 13 or 20 PLLS
> + 100g4x10g 2x100g 13 PLLF and PLLS
> +
> + What each mode makes of the two four-lane ports of protocol 13:
Why "of protocol 13"? You could simply say "Active DPMACs for each mode:"
> +
> + mode dpmac.2 port dpmac.1 port
> + 2x100g 100GE 100GE
> + 100g4x25g 100GE 4x 25G: dpmac.3 to dpmac.6
> + 2x40g 40GE 40GE
> + 40g4x10g 40GE 4x XFI: dpmac.3 to dpmac.6
> + 100g4x10g 100GE 4x XFI: dpmac.3 to dpmac.6
For clarity, I would recommend one more column
mode dpmac.1 dpmac.2 dpmac.3 ... dpmac.6
2x100g 100GE 100GE -
100g4x25g - 100GE 4x 25G
2x40g 40GE 40GE -
40g4x10g - 40GE 4x XFI
100g4x10g - 100GE 4x XFI
Also, I think a clarification is in order, that your SerDes1 protocol
naming convention needs to be read from right to left, compared to the
SRDS_PRTCL_S1 table from the hardware RM.
> +
> + Initial conditions:
> +
> + - PLLS needs a 161.1328125 MHz reference clock, for which 2x40g,
> + 40g4x10g and 100g4x10g program it. It can come from the SD1
> + PLLS reference clock input, or from the PLLF one with
> + SRDS_INTRA_REF_CLK_S1=1. A 156.25 MHz PLLS reference clock is
> + not supported. With protocol 13 PLLS is not in use, so nothing
> + checks that clock before these modes start it.
> + - The MC DPC must set follow_hw_pssr in board_info/serdes, for the
> + MC to read the lanes rather than look at protocol, and the DPL
> + must use the dpmacs of the new grouping.
> +
> + 'lx2160_serdes status 1' shows the resulting lane grouping and
> + protocol converters.
> +
> + Example:
> + setenv hwconfig serdes1:100g4x25g
> + saveenv
> + reset
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v6 10/13] board: lx2160a: serdes: add serdes1:40g4x10g
2026-10-01 20:47 ` [PATCH v6 10/13] board: lx2160a: serdes: add serdes1:40g4x10g Vincent Jardin
@ 2026-10-07 11:27 ` Vladimir Oltean
2026-10-08 22:32 ` Vincent Jardin
0 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-10-07 11:27 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Priyanka Jain, Wasim Khan, Tom Rini, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal
On Thu, Oct 01, 2026 at 10:47:27PM +0200, Vincent Jardin wrote:
> +static int sd1_enter_40g4x10g(unsigned long base)
> +{
> + unsigned long lanes = SD1_LNE_LNH;
> + int m, keep, ret, err;
> +
> + keep = sd1_port_master(base, SD1_LNA_LND);
> + if (keep < 0)
> + return -EINVAL;
> +
> + ret = sd1_halt_port(base, lanes);
> + if (ret == -EINVAL)
> + return ret;
> +
> + for_each_set_bit(m, &lanes, SRDS_LANES)
> + out_le32((void __iomem *)SRDS_LNmGCR0(base, m), XFI_GCR0);
> +
> + out_le32((void __iomem *)SRDS_PCCE(base), X10G_PCCE);
> + out_le32((void __iomem *)SRDS_PCCC(base), XFI_PCCC);
> +
> + err = sd1_reset_both(base, keep);
When entering 40g4x10g from 2x40g, why do you need to reset both lane
groups rather than just lanes E-H?
> +
> + return err ? err : ret;
> +}
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v6 10/13] board: lx2160a: serdes: add serdes1:40g4x10g
2026-10-07 11:27 ` Vladimir Oltean
@ 2026-10-08 22:32 ` Vincent Jardin
0 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-08 22:32 UTC (permalink / raw)
To: Vladimir Oltean
Cc: u-boot, Priyanka Jain, Wasim Khan, Tom Rini, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal
Hi Vladimir,
> > + out_le32((void __iomem *)SRDS_PCCE(base), X10G_PCCE);
> > + out_le32((void __iomem *)SRDS_PCCC(base), XFI_PCCC);
> > +
> > + err = sd1_reset_both(base, keep);
>
> When entering 40g4x10g from 2x40g, why do you need to reset both lane
> groups rather than just lanes E-H?
Right, not needed !, some pending code from the initial development.
I'll update it into a v7.
FYI, since the patch 11 did the same, I'll remove your Reviewed-by on
it so I'll appreciate if you can review the 11's v7 once again, please.
big thanks,
Vincent
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v6 12/13] doc: lx2160a: document the sd1 hwconfig option
2026-10-07 10:47 ` Vladimir Oltean
@ 2026-10-08 22:36 ` Vincent Jardin
0 siblings, 0 replies; 21+ messages in thread
From: Vincent Jardin @ 2026-10-08 22:36 UTC (permalink / raw)
To: Vladimir Oltean
Cc: u-boot, Priyanka Jain, Wasim Khan, Tom Rini, Peng Fan,
Ioana Ciornei, Hemant Agrawal, Meenakshi Aggarwal
Hi Vladimir,
> 2x40g should have the "SRDS_PRTCL_S1" field as "13 or 20" as well, no?
> Because protocol 20 is literally 2x40g.
right -> v7
> Why "of protocol 13"? You could simply say "Active DPMACs for each mode:"
ok
> For clarity, I would recommend one more column
thanks, I'll take your recommendation with the template from your former
email.
> Also, I think a clarification is in order, that your SerDes1 protocol
> naming convention needs to be read from right to left, compared to the
> SRDS_PRTCL_S1 table from the hardware RM.
Right, and it is good to mention it since I had face that issue.
I'll comment it into the v7.
Best regards,
Vincent
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2026-10-08 22:36 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-01 20:47 [PATCH v6 00/13] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 01/13] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 02/13] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 03/13] board: lx2160a: serdes: rename SPLIT_POLL_US to SRDS_POLL_US Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 04/13] board: lx2160a: serdes: move the SD1 halt and reset into helpers Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 05/13] board: lx2160a: serdes: set SD1 with a table Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 06/13] board: lx2160a: serdes: report unknown SD1 cases Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 07/13] board: lx2160a: serdes: no SD1 config once MC runs Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 08/13] board: lx2160a: serdes: add serdes1:2x40g Vincent Jardin
2026-10-02 14:07 ` Vladimir Oltean
2026-10-06 14:10 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 09/13] board: lx2160a: serdes: enter a SD1 mode through the mode it starts from Vincent Jardin
2026-10-02 14:08 ` Vladimir Oltean
2026-10-01 20:47 ` [PATCH v6 10/13] board: lx2160a: serdes: add serdes1:40g4x10g Vincent Jardin
2026-10-07 11:27 ` Vladimir Oltean
2026-10-08 22:32 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 11/13] board: lx2160a: serdes: add serdes1:100g4x10g Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 12/13] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
2026-10-07 10:47 ` Vladimir Oltean
2026-10-08 22:36 ` Vincent Jardin
2026-10-01 20:47 ` [PATCH v6 13/13] board: nbxv3: apply sd1 hwconfig before MC starts Vincent Jardin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.