* [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards
@ 2026-09-28 10:13 Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 01/10] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
` (10 more replies)
0 siblings, 11 replies; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
Vincent Jardin
The 1x100GE + 4x25G split of SerDes 1 is in next since v1, commit
035d68fc36b5 ("lx2160: add lx2160_serdes split and management").
v4 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
- 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
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 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 (10):
board: lx2160a: serdes: drop the split subcommand
board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g
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: 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 | 588 ++++++++++++++----
board/nxp/lx2160a/serdes_split.h | 16 +-
doc/README.fsl-hwconfig | 61 ++
6 files changed, 556 insertions(+), 123 deletions(-)
---
base-commit: 2b8902913c19eb581fb0d567201c09b8fa46ac74
branch: for-upstream/lx2160a-serdes1-v4
--
2.43.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH v4 01/10] board: lx2160a: serdes: drop the split subcommand
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 11:17 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 02/10] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g Vincent Jardin
` (9 subsequent siblings)
10 siblings, 1 reply; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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>
---
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] 23+ messages in thread
* [PATCH v4 02/10] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 01/10] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 11:18 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 03/10] board: lx2160a: serdes: set SD1 with a table Vincent Jardin
` (8 subsequent siblings)
10 siblings, 1 reply; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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 not longer meaningfull.
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>
---
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] 23+ messages in thread
* [PATCH v4 03/10] board: lx2160a: serdes: set SD1 with a table
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 01/10] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 02/10] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 12:02 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 04/10] board: lx2160a: serdes: report unknown SD1 cases Vincent Jardin
` (7 subsequent siblings)
10 siblings, 1 reply; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
Vincent Jardin
The SD1 lane configuration can support many cases, not just the
1x100GE + 4x25G split.
Let's describe each one as an entry of a table.
Then, let's check the serdes1:<mode> of hwconfig.
The master-lane lookup, the halt and the reset of the split become
helpers.
Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Vincent Jardin <vjardin@free.fr>
---
Changes in v4:
- New patch
board/nxp/lx2160a/serdes_split.c | 272 +++++++++++++++++++++----------
board/nxp/lx2160a/serdes_split.h | 16 +-
2 files changed, 192 insertions(+), 96 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 1a5c44e7740..11bec35fd22 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>
@@ -245,16 +246,22 @@ static void print_rcw_view(int sd)
#if defined(CONFIG_ARCH_LX2160A)
-/*
- * The split itself.
- *
- * 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 */
+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);
+};
+
+#define SD1_LNE_LNH GENMASK(7, 4)
+
+#define SRDS_POLL_US 10000 /* NXP waits ~100 cycles */
/*
+ * 1x 100GE + 4x 25G. This is NXP's e100g1_split.rcw sequence, adapted
+ * from the PBI sequence to U-Boot.
+ *
* PROTO_SEL=11010b (25G/50G/100G, shared) + IF_WIDTH=100b (40-bit),
* PORT_RST_LEFT=0 and PORT_LN0_B=0 so every lane becomes its own
* single-lane port. Only those last two bits actually change: the
@@ -264,31 +271,24 @@ 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 */
-
-static bool srds1_split_state(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));
- return PCCE_E100GA_CFG(pcce) == 0 &&
- PCCD_E25G_CFG(pccd, 0) && PCCD_E25G_CFG(pccd, 1) &&
- 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));
+ return PCCE_E100GA_CFG(pcce) != 0 && PCCE_E100GB_CFG(pcce) != 0 &&
+ PCCD_E25G_CFG(pccd, 0) == 0 && PCCD_E25G_CFG(pccd, 1) == 0 &&
+ PCCD_E25G_CFG(pccd, 2) == 0 && PCCD_E25G_CFG(pccd, 3) == 0;
}
-static bool srds1_is_unsplit(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));
- return PCCE_E100GA_CFG(pcce) != 0 && PCCE_E100GB_CFG(pcce) != 0 &&
- PCCD_E25G_CFG(pccd, 0) == 0 && PCCD_E25G_CFG(pccd, 1) == 0 &&
- PCCD_E25G_CFG(pccd, 2) == 0 && PCCD_E25G_CFG(pccd, 3) == 0;
+ return PCCE_E100GA_CFG(pcce) == 0 &&
+ PCCD_E25G_CFG(pccd, 0) && PCCD_E25G_CFG(pccd, 1) &&
+ PCCD_E25G_CFG(pccd, 2) && PCCD_E25G_CFG(pccd, 3);
}
/*
@@ -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))
@@ -309,79 +309,82 @@ 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;
- }
+ int m, master = -1;
- 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;
- }
-
- /*
- * 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, SPLIT_POLL_US);
- ret = -ETIMEDOUT;
+ 'A' + master, SRDS_POLL_US);
+ 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 skip)
+{
+ 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) {
+ if (m == skip)
+ continue;
out_le32((void __iomem *)SRDS_LNmTRSTCTL(base, m),
RSTCTL_RST_REQ);
out_le32((void __iomem *)SRDS_LNmRRSTCTL(base, m),
RSTCTL_RST_REQ);
}
+}
+
+static int sd1_reset_wait(unsigned long base, unsigned long lanes)
+{
+ int m, ret = 0;
- for (m = SPLIT_FIRST_LANE; m <= SPLIT_LAST_LANE; m++) {
+ for_each_set_bit(m, &lanes, SRDS_LANES) {
u32 t, r;
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;
}
@@ -395,33 +398,138 @@ int lx2160a_serdes1_split(void)
}
}
- 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 ret;
+}
+
+static int sd1_enter_100g4x25g(unsigned long base)
+{
+ unsigned long lanes = SD1_LNE_LNH;
+ int m, ret, err;
+
+ ret = sd1_halt_port(base, lanes);
+ if (ret == -EINVAL)
+ return ret;
+
+ /*
+ * Reconfigure while halted: four 1-lane ports instead of one
+ * 4-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, -1);
+ err = sd1_reset_wait(base, lanes);
+
+ 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)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sd1_modes); i++)
+ if (!strcmp(sd1_modes[i].name, name))
+ 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)));
+}
+
+/* Put SD1 in @mode, for serdes1:@target */
+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;
+ int ret;
+
+ if (mode->is_active(base))
+ return 0;
+
+ if (!mode->enter) {
+ printf("lx2160a serdes: serdes1:%s needs SD1 to be %s, it is not (",
+ target->name, mode->desc);
+ sd1_print_pcc(base);
+ printf("), refusing\n");
+ return -EINVAL;
+ }
+
+ from = sd1_mode_find(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);
+ 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>
+ *
+ * The modes are target states of the same 8 lanes, not steps:
+ * when several are given, the first one of sd1_modes[] is applied and
+ * the others are reported.
*
- * 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"))
- return;
+ const struct sd1_mode *mode = NULL;
+ int i;
- if (lx2160a_serdes1_is_split())
- return;
+ for (i = 0; i < ARRAY_SIZE(sd1_modes); i++) {
+ if (!hwconfig_sub("serdes1", sd1_modes[i].name))
+ continue;
+ if (mode) {
+ printf("lx2160a serdes: hwconfig also asks for serdes1:%s, ignored\n",
+ sd1_modes[i].name);
+ continue;
+ }
+ mode = &sd1_modes[i];
+ }
- lx2160a_serdes1_split();
+ if (mode)
+ sd1_enter(mode, mode, 0);
}
#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] 23+ messages in thread
* [PATCH v4 04/10] board: lx2160a: serdes: report unknown SD1 cases
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (2 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 03/10] board: lx2160a: serdes: set SD1 with a table Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 14:29 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 05/10] board: lx2160a: serdes: no SD1 config once MC runs Vincent Jardin
` (6 subsequent siblings)
10 siblings, 1 reply; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
Vincent Jardin
Check and if unknown display:
lx2160a serdes: unknown hwconfig serdes1:split, ignored
Signed-off-by: Vincent Jardin <vjardin@free.fr>
---
Changes in v4:
- New patch
board/nxp/lx2160a/serdes_split.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 11bec35fd22..a8fbb278b3a 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -443,17 +443,23 @@ static const struct sd1_mode sd1_modes[] = {
},
};
-static const struct sd1_mode *sd1_mode_find(const char *name)
+static const struct sd1_mode *sd1_mode_findn(const char *name, size_t n)
{
int i;
for (i = 0; i < ARRAY_SIZE(sd1_modes); i++)
- if (!strcmp(sd1_modes[i].name, name))
+ if (strlen(sd1_modes[i].name) == n &&
+ !strncmp(sd1_modes[i].name, name, n))
return &sd1_modes[i];
return NULL;
}
+static const struct sd1_mode *sd1_mode_find(const char *name)
+{
+ return sd1_mode_findn(name, strlen(name));
+}
+
static void sd1_print_pcc(unsigned long base)
{
printf("PCCC=%08x PCCD=%08x PCCE=%08x",
@@ -503,6 +509,26 @@ static int sd1_enter(const struct sd1_mode *mode,
return 0;
}
+static void sd1_report_unknown(void)
+{
+ const char *arg, *comma, *eq;
+ size_t len, n;
+
+ arg = hwconfig_arg("serdes1", &len);
+ while (arg && len) {
+ comma = memchr(arg, ',', len);
+ n = comma ? comma - arg : len;
+ eq = memchr(arg, '=', n);
+ if (n && !sd1_mode_findn(arg, eq ? eq - arg : n))
+ printf("lx2160a serdes: unknown hwconfig serdes1:%.*s, ignored\n",
+ (int)n, arg);
+ if (!comma)
+ break;
+ len -= n + 1;
+ arg = comma + 1;
+ }
+}
+
/*
* setenv hwconfig serdes1:<mode>
*
@@ -517,6 +543,8 @@ void lx2160a_serdes_apply_hwconfig(void)
const struct sd1_mode *mode = NULL;
int i;
+ sd1_report_unknown();
+
for (i = 0; i < ARRAY_SIZE(sd1_modes); i++) {
if (!hwconfig_sub("serdes1", sd1_modes[i].name))
continue;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v4 05/10] board: lx2160a: serdes: no SD1 config once MC runs
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (3 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 04/10] board: lx2160a: serdes: report unknown SD1 cases Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 14:50 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 06/10] board: lx2160a: serdes: add serdes1:2x40g Vincent Jardin
` (5 subsequent siblings)
10 siblings, 1 reply; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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>
---
Changes in v4:
- New patch
board/nxp/lx2160a/serdes_split.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index a8fbb278b3a..057d3c97739 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>
@@ -556,8 +557,16 @@ void lx2160a_serdes_apply_hwconfig(void)
mode = &sd1_modes[i];
}
- if (mode)
- sd1_enter(mode, mode, 0);
+ if (!mode || 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, mode, 0);
}
#endif /* CONFIG_ARCH_LX2160A */
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v4 06/10] board: lx2160a: serdes: add serdes1:2x40g
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (4 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 05/10] board: lx2160a: serdes: no SD1 config once MC runs Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 07/10] board: lx2160a: serdes: add serdes1:40g4x10g Vincent Jardin
` (4 subsequent siblings)
10 siblings, 0 replies; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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 v4:
- was on v3 2/5, now it is an entry of the mode table
board/nxp/lx2160a/serdes_split.c | 138 +++++++++++++++++++++++++++++++
1 file changed, 138 insertions(+)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 057d3c97739..104baa6b181 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)
@@ -255,6 +270,7 @@ struct sd1_mode {
int (*enter)(unsigned long base);
};
+#define SD1_LNA_LND GENMASK(3, 0)
#define SD1_LNE_LNH GENMASK(7, 4)
#define SRDS_POLL_US 10000 /* NXP waits ~100 cycles */
@@ -429,6 +445,121 @@ 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.
+ *
+ * 40GE lanes run at 10.3125 Gbaud. LNmTGCR0/LNmRGCR0[BY_N_RATE_SEL] is
+ * the lane rate as a fraction of the PLL clock: 011b (double) for 25G
+ * and 100GE, 000b (full) for 40GE, so the lanes cannot stay on PLLF (fast)
+ * and move to PLLS (slow).
+ *
+ * Protocol 13 powers PLLS down only through PLLnRSTCTL[DIS], which
+ * software can clear. PLLS then gets the values a board booted with
+ * protocol 20 reads back. They are for a 161.1328125 MHz reference
+ * clock: the board has to feed PLLS that, which the RCW does not
+ * describe for protocol 13 and which cannot be checked from here.
+ */
+#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",
@@ -442,6 +573,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_findn(const char *name, size_t n)
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v4 07/10] board: lx2160a: serdes: add serdes1:40g4x10g
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (5 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 06/10] board: lx2160a: serdes: add serdes1:2x40g Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 08/10] board: lx2160a: serdes: add serdes1:100g4x10g Vincent Jardin
` (3 subsequent siblings)
10 siblings, 0 replies; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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>
---
Changes in v4:
- was on v3 3/5, now let's add an entry of the mode table
board/nxp/lx2160a/serdes_split.c | 63 ++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 104baa6b181..1c228dd5c06 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -560,6 +560,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",
@@ -580,6 +636,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_findn(const char *name, size_t n)
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v4 08/10] board: lx2160a: serdes: add serdes1:100g4x10g
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (6 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 07/10] board: lx2160a: serdes: add serdes1:40g4x10g Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
` (2 subsequent siblings)
10 siblings, 0 replies; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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>
---
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 1c228dd5c06..7556ab57c73 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -616,6 +616,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",
@@ -643,6 +692,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_findn(const char *name, size_t n)
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (7 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 08/10] board: lx2160a: serdes: add serdes1:100g4x10g Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 15:05 ` Vladimir Oltean
2026-09-28 15:10 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 10/10] board: nbxv3: apply sd1 hwconfig before MC starts Vincent Jardin
2026-09-28 19:14 ` [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Tom Rini
10 siblings, 2 replies; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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 v4:
- was v3 5/5, rewritten using a table
.../cpu/armv8/fsl-layerscape/doc/README.soc | 7 +++
doc/README.fsl-hwconfig | 60 +++++++++++++++++++
2 files changed, 67 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..3f9d2ddad75 100644
--- a/doc/README.fsl-hwconfig
+++ b/doc/README.fsl-hwconfig
@@ -44,3 +44,63 @@ 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(): lx2160aqds.
+
+ 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 picks the grouping. The RCW, and RCWSR29, keep the
+ protocol number.
+
+ '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:
+
+ - The MC must not be running yet. Otherwise the mode is refused and
+ SD1 is left as it is.
+ - 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] 23+ messages in thread
* [PATCH v4 10/10] board: nbxv3: apply sd1 hwconfig before MC starts
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (8 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
@ 2026-09-28 10:13 ` Vincent Jardin
2026-09-28 15:07 ` Vladimir Oltean
2026-09-28 19:14 ` [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Tom Rini
10 siblings, 1 reply; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 10:13 UTC (permalink / raw)
To: u-boot
Cc: Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean,
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>
---
Changes in v4:
- New patch
board/nxp/lx2160a/nbxv3/eth_nbxv3.c | 3 +++
doc/README.fsl-hwconfig | 3 ++-
2 files changed, 5 insertions(+), 1 deletion(-)
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();
}
diff --git a/doc/README.fsl-hwconfig b/doc/README.fsl-hwconfig
index 3f9d2ddad75..dab24009f0f 100644
--- a/doc/README.fsl-hwconfig
+++ b/doc/README.fsl-hwconfig
@@ -47,7 +47,8 @@ usb
serdes1
Specific to the LX2160A boards whose reset_phy() calls
- lx2160a_serdes_apply_hwconfig() before mc_env_boot(): lx2160aqds.
+ lx2160a_serdes_apply_hwconfig() before mc_env_boot(): lx2160aqds,
+ nbxv3.
SRDS_PRTCL_S1 is latched at reset, but the eight SD1 (SerDes) lanes
can still be configured before the DPAA2 management complex (MC) starts.
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH v4 01/10] board: lx2160a: serdes: drop the split subcommand
2026-09-28 10:13 ` [PATCH v4 01/10] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
@ 2026-09-28 11:17 ` Vladimir Oltean
0 siblings, 0 replies; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 11:17 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:20PM +0200, Vincent Jardin wrote:
> 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>
>
> ---
>
> Changes in v4:
> - New patch
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 02/10] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g
2026-09-28 10:13 ` [PATCH v4 02/10] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g Vincent Jardin
@ 2026-09-28 11:18 ` Vladimir Oltean
0 siblings, 0 replies; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 11:18 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:21PM +0200, Vincent Jardin wrote:
> 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 not longer meaningfull.
Nitpick: 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>
>
> ---
>
> Changes in v4:
> - New patch
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 03/10] board: lx2160a: serdes: set SD1 with a table
2026-09-28 10:13 ` [PATCH v4 03/10] board: lx2160a: serdes: set SD1 with a table Vincent Jardin
@ 2026-09-28 12:02 ` Vladimir Oltean
0 siblings, 0 replies; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 12:02 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:22PM +0200, Vincent Jardin wrote:
> The SD1 lane configuration can support many cases, not just the
> 1x100GE + 4x25G split.
>
> Let's describe each one as an entry of a table.
> Then, let's check the serdes1:<mode> of hwconfig.
>
> The master-lane lookup, the halt and the reset of the split become
> helpers.
>
> Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Vincent Jardin <vjardin@free.fr>
>
> ---
Still hard to review due to unrelated changes mixed here.
>
> Changes in v4:
> - New patch
>
> board/nxp/lx2160a/serdes_split.c | 272 +++++++++++++++++++++----------
> board/nxp/lx2160a/serdes_split.h | 16 +-
> 2 files changed, 192 insertions(+), 96 deletions(-)
>
> diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
> index 1a5c44e7740..11bec35fd22 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>
> @@ -245,16 +246,22 @@ static void print_rcw_view(int sd)
>
> #if defined(CONFIG_ARCH_LX2160A)
>
> -/*
> - * The split itself.
> - *
> - * 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 */
> +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);
> +};
> +
> +#define SD1_LNE_LNH GENMASK(7, 4)
> +
> +#define SRDS_POLL_US 10000 /* NXP waits ~100 cycles */
>
> /*
> + * 1x 100GE + 4x 25G. This is NXP's e100g1_split.rcw sequence, adapted
> + * from the PBI sequence to U-Boot.
> + *
> * PROTO_SEL=11010b (25G/50G/100G, shared) + IF_WIDTH=100b (40-bit),
> * PORT_RST_LEFT=0 and PORT_LN0_B=0 so every lane becomes its own
> * single-lane port. Only those last two bits actually change: the
> @@ -264,31 +271,24 @@ 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 */
> -
> -static bool srds1_split_state(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));
>
> - return PCCE_E100GA_CFG(pcce) == 0 &&
> - PCCD_E25G_CFG(pccd, 0) && PCCD_E25G_CFG(pccd, 1) &&
> - 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));
> + return PCCE_E100GA_CFG(pcce) != 0 && PCCE_E100GB_CFG(pcce) != 0 &&
> + PCCD_E25G_CFG(pccd, 0) == 0 && PCCD_E25G_CFG(pccd, 1) == 0 &&
> + PCCD_E25G_CFG(pccd, 2) == 0 && PCCD_E25G_CFG(pccd, 3) == 0;
> }
>
> -static bool srds1_is_unsplit(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));
>
> - return PCCE_E100GA_CFG(pcce) != 0 && PCCE_E100GB_CFG(pcce) != 0 &&
> - PCCD_E25G_CFG(pccd, 0) == 0 && PCCD_E25G_CFG(pccd, 1) == 0 &&
> - PCCD_E25G_CFG(pccd, 2) == 0 && PCCD_E25G_CFG(pccd, 3) == 0;
> + return PCCE_E100GA_CFG(pcce) == 0 &&
> + PCCD_E25G_CFG(pccd, 0) && PCCD_E25G_CFG(pccd, 1) &&
> + PCCD_E25G_CFG(pccd, 2) && PCCD_E25G_CFG(pccd, 3);
It is not immediately obvious that the old 'split' configuration
corresponds to '100g4x25g' and 'unsplit' to '2x100g'. Better to
explicitly say this, so that reviewers can follow along.
And then, the diff looks kind of bad here, because you reverse the order
of the is_active() expressions. In the old code, 'split' was first then
'unsplit'. In the new code, '2x100g' comes first (aka unsplit), followed
by '100g4x25g' (aka split). So it looks as if the logic is changing,
plus there are gratuitous diff lines in the commit.
Not easy to review at all, and not obviously correct.
> }
>
> /*
> @@ -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;
Renaming SPLIT_POLL_US to SRDS_POLL_US is noise which can be isolated to
its own change.
>
> while (us--) {
> if (!(in_le32((void __iomem *)reg) & bit))
> @@ -309,79 +309,82 @@ 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;
> - }
> + int m, master = -1;
>
> - 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;
> - }
> -
> - /*
> - * 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)
Can you create sd1_halt_port() as a helper in a preparatory change?
> +{
> + 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, SPLIT_POLL_US);
> - ret = -ETIMEDOUT;
> + 'A' + master, SRDS_POLL_US);
> + 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 skip)
Nitpick: the skip logic is not needed as of this patch.
> +{
> + 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) {
> + if (m == skip)
> + continue;
> out_le32((void __iomem *)SRDS_LNmTRSTCTL(base, m),
> RSTCTL_RST_REQ);
> out_le32((void __iomem *)SRDS_LNmRRSTCTL(base, m),
> RSTCTL_RST_REQ);
> }
> +}
> +
> +static int sd1_reset_wait(unsigned long base, unsigned long lanes)
> +{
> + int m, ret = 0;
>
> - for (m = SPLIT_FIRST_LANE; m <= SPLIT_LAST_LANE; m++) {
> + for_each_set_bit(m, &lanes, SRDS_LANES) {
> u32 t, r;
>
> 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;
> }
> @@ -395,33 +398,138 @@ int lx2160a_serdes1_split(void)
> }
> }
>
> - 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 ret;
> +}
> +
> +static int sd1_enter_100g4x25g(unsigned long base)
> +{
> + unsigned long lanes = SD1_LNE_LNH;
> + int m, ret, err;
> +
> + ret = sd1_halt_port(base, lanes);
> + if (ret == -EINVAL)
> + return ret;
> +
> + /*
> + * Reconfigure while halted: four 1-lane ports instead of one
> + * 4-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, -1);
> + err = sd1_reset_wait(base, lanes);
> +
> + 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)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(sd1_modes); i++)
> + if (!strcmp(sd1_modes[i].name, name))
> + 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)));
> +}
> +
> +/* Put SD1 in @mode, for serdes1:@target */
> +static int sd1_enter(const struct sd1_mode *mode,
> + const struct sd1_mode *target, int depth)
This recursive sd1_enter() also deserves its own change. It's a bit
strange to pack it together with a change titled "set SD1 with a table",
when it permits the code to do something which it couldn't do before:
change SerDes protocols between A and B hop by hop, as long as there
exists a chain of intermediary states which is at most ARRAY_SIZE(sd1_modes)
nodes deep. Interesting idea for sure, but it isn't going to have the
proper review if it's buried so deep as it is now.
> +{
> + unsigned long base = srds_base(FSL_SRDS_1);
> + const struct sd1_mode *from;
> + int ret;
> +
> + if (mode->is_active(base))
> + return 0;
> +
> + if (!mode->enter) {
> + printf("lx2160a serdes: serdes1:%s needs SD1 to be %s, it is not (",
> + target->name, mode->desc);
> + sd1_print_pcc(base);
> + printf("), refusing\n");
> + return -EINVAL;
> + }
> +
> + from = sd1_mode_find(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);
> + 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;
> }
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 04/10] board: lx2160a: serdes: report unknown SD1 cases
2026-09-28 10:13 ` [PATCH v4 04/10] board: lx2160a: serdes: report unknown SD1 cases Vincent Jardin
@ 2026-09-28 14:29 ` Vladimir Oltean
0 siblings, 0 replies; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 14:29 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:23PM +0200, Vincent Jardin wrote:
> Check and if unknown display:
> lx2160a serdes: unknown hwconfig serdes1:split, ignored
>
> Signed-off-by: Vincent Jardin <vjardin@free.fr>
>
> ---
>
> Changes in v4:
> - New patch
>
> board/nxp/lx2160a/serdes_split.c | 32 ++++++++++++++++++++++++++++++--
> 1 file changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
> index 11bec35fd22..a8fbb278b3a 100644
> --- a/board/nxp/lx2160a/serdes_split.c
> +++ b/board/nxp/lx2160a/serdes_split.c
> @@ -443,17 +443,23 @@ static const struct sd1_mode sd1_modes[] = {
> },
> };
>
> -static const struct sd1_mode *sd1_mode_find(const char *name)
> +static const struct sd1_mode *sd1_mode_findn(const char *name, size_t n)
> {
> int i;
>
> for (i = 0; i < ARRAY_SIZE(sd1_modes); i++)
> - if (!strcmp(sd1_modes[i].name, name))
> + if (strlen(sd1_modes[i].name) == n &&
> + !strncmp(sd1_modes[i].name, name, n))
> return &sd1_modes[i];
>
> return NULL;
> }
>
> +static const struct sd1_mode *sd1_mode_find(const char *name)
> +{
> + return sd1_mode_findn(name, strlen(name));
> +}
Hmm, there's a single other caller of sd1_mode_find(), from sd1_enter().
Is it really worth it to implement a shim over sd1_mode_findn()?
I don't think so.
Can you please plan accordingly and modify sd1_mode_find() to take the
function prototype of sd1_mode_find() from the get go?
> +
> static void sd1_print_pcc(unsigned long base)
> {
> printf("PCCC=%08x PCCD=%08x PCCE=%08x",
> @@ -503,6 +509,26 @@ static int sd1_enter(const struct sd1_mode *mode,
> return 0;
> }
>
> +static void sd1_report_unknown(void)
> +{
> + const char *arg, *comma, *eq;
> + size_t len, n;
> +
> + arg = hwconfig_arg("serdes1", &len);
> + while (arg && len) {
> + comma = memchr(arg, ',', len);
> + n = comma ? comma - arg : len;
> + eq = memchr(arg, '=', n);
> + if (n && !sd1_mode_findn(arg, eq ? eq - arg : n))
> + printf("lx2160a serdes: unknown hwconfig serdes1:%.*s, ignored\n",
> + (int)n, arg);
> + if (!comma)
> + break;
> + len -= n + 1;
> + arg = comma + 1;
What is the point of this manual hand-rolling of sub-options?
As far as I can read from doc/README.fsl-hwconfig, the serdes1 syntax is
A: 'serdes1:2x100g[;other-options:other-values]', not
B: 'serdes1:suboption=value,suboption2=other_value[;other-options:other-values]'.
To parse syntax A, you don't need any comma or equal detection.
The 'len' provided by hwconfig_arg() should end at the next semicolon
separator already, or at the end of the string. You should be able to
print that directly. Or if not, you haven't explained the need for all
this complexity.
> + }
> +}
> +
> /*
> * setenv hwconfig serdes1:<mode>
> *
> @@ -517,6 +543,8 @@ void lx2160a_serdes_apply_hwconfig(void)
> const struct sd1_mode *mode = NULL;
> int i;
>
> + sd1_report_unknown();
> +
> for (i = 0; i < ARRAY_SIZE(sd1_modes); i++) {
> if (!hwconfig_sub("serdes1", sd1_modes[i].name))
> continue;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 05/10] board: lx2160a: serdes: no SD1 config once MC runs
2026-09-28 10:13 ` [PATCH v4 05/10] board: lx2160a: serdes: no SD1 config once MC runs Vincent Jardin
@ 2026-09-28 14:50 ` Vladimir Oltean
0 siblings, 0 replies; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 14:50 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:24PM +0200, Vincent Jardin wrote:
> 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>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option
2026-09-28 10:13 ` [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
@ 2026-09-28 15:05 ` Vladimir Oltean
2026-09-28 15:10 ` Vladimir Oltean
1 sibling, 0 replies; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 15:05 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:28PM +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 v4:
> - was v3 5/5, rewritten using a table
>
> .../cpu/armv8/fsl-layerscape/doc/README.soc | 7 +++
> doc/README.fsl-hwconfig | 60 +++++++++++++++++++
> 2 files changed, 67 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..3f9d2ddad75 100644
> --- a/doc/README.fsl-hwconfig
> +++ b/doc/README.fsl-hwconfig
> @@ -44,3 +44,63 @@ 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(): lx2160aqds.
> +
> + 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 picks the grouping. The RCW, and RCWSR29, keep the
> + protocol number.
I feel the last 2 sentences do not have a sharply defined meaning. Maybe
say "This option alters the Ethernet MAC-to-lane grouping after the fact
(RCWSR29 will continue 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:
> +
> + - The MC must not be running yet. Otherwise the mode is refused and
> + SD1 is left as it is.
What is actionable for the reader with this information? Assuming the
reader is a board user, and not a developer.
BTW, the first paragraph already says "Specific to the LX2160A boards
whose reset_phy() calls lx2160a_serdes_apply_hwconfig() before mc_env_boot()".
> + - 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.
- PLLS must be provisioned with a refclk frequency from which the 10.3125 GHz
clock net can be derived. This is kind of important, because this requirement
does not exist on the native SRDS_PRTCL_S1=13 boot, because there, PLLS is
simply powered down. You just _assume_ you can power it up and it will lock
at the frequency you want.
> +
> + '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] 23+ messages in thread
* Re: [PATCH v4 10/10] board: nbxv3: apply sd1 hwconfig before MC starts
2026-09-28 10:13 ` [PATCH v4 10/10] board: nbxv3: apply sd1 hwconfig before MC starts Vincent Jardin
@ 2026-09-28 15:07 ` Vladimir Oltean
0 siblings, 0 replies; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 15:07 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:29PM +0200, Vincent Jardin wrote:
> Apply this feature to the nbxv3 board too.
>
> Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Vincent Jardin <vjardin@free.fr>
>
> ---
>
> Changes in v4:
> - New patch
>
> board/nxp/lx2160a/nbxv3/eth_nbxv3.c | 3 +++
> doc/README.fsl-hwconfig | 3 ++-
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
> 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();
> }
> diff --git a/doc/README.fsl-hwconfig b/doc/README.fsl-hwconfig
> index 3f9d2ddad75..dab24009f0f 100644
> --- a/doc/README.fsl-hwconfig
> +++ b/doc/README.fsl-hwconfig
> @@ -47,7 +47,8 @@ usb
>
> serdes1
> Specific to the LX2160A boards whose reset_phy() calls
> - lx2160a_serdes_apply_hwconfig() before mc_env_boot(): lx2160aqds.
> + lx2160a_serdes_apply_hwconfig() before mc_env_boot(): lx2160aqds,
> + nbxv3.
Nitpick: cross-referencing boards like this is exactly the kind of thing
that bit rots very easily once more boards add support.
>
> SRDS_PRTCL_S1 is latched at reset, but the eight SD1 (SerDes) lanes
> can still be configured before the DPAA2 management complex (MC) starts.
> --
> 2.43.0
>
Nonetheless:
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option
2026-09-28 10:13 ` [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
2026-09-28 15:05 ` Vladimir Oltean
@ 2026-09-28 15:10 ` Vladimir Oltean
2026-09-28 22:13 ` Vincent Jardin
1 sibling, 1 reply; 23+ messages in thread
From: Vladimir Oltean @ 2026-09-28 15:10 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
On Mon, Sep 28, 2026 at 12:13:28PM +0200, Vincent Jardin wrote:
> + 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
How much do you plan to extend this, really?
Do you ever plan to support a mode with multiple 'from' modes?
Like for example, 100g4x25g can come either from 2x100g, or from 100g4x10g.
The sd1_enter() recursion and graph traversal becomes quite a bit more
complicated.
But in principle, there's nothing saying you can transition to one
SerDes protocol just from a single source. In that sense, I think your
choices are rather arbitrary and may not suit everyone, so talking about
multiple sources now seems rather adequate.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
` (9 preceding siblings ...)
2026-09-28 10:13 ` [PATCH v4 10/10] board: nbxv3: apply sd1 hwconfig before MC starts Vincent Jardin
@ 2026-09-28 19:14 ` Tom Rini
2026-09-28 20:59 ` Vincent Jardin
10 siblings, 1 reply; 23+ messages in thread
From: Tom Rini @ 2026-09-28 19:14 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean
[-- Attachment #1: Type: text/plain, Size: 2791 bytes --]
On Mon, Sep 28, 2026 at 12:13:19PM +0200, Vincent Jardin wrote:
>
> The 1x100GE + 4x25G split of SerDes 1 is in next since v1, commit
> 035d68fc36b5 ("lx2160: add lx2160_serdes split and management").
>
> v4 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
> - 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
>
> 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 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 (10):
> board: lx2160a: serdes: drop the split subcommand
> board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g
> 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: 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 | 588 ++++++++++++++----
> board/nxp/lx2160a/serdes_split.h | 16 +-
> doc/README.fsl-hwconfig | 61 ++
> 6 files changed, 556 insertions(+), 123 deletions(-)
Those two doc files, has anyone asked you to please convert them to rST
and then update them? And, I don't hate the idea of doing that as a
follow-up, but since we have people touching the files that understand
the content, this is the time to convert. Thanks!
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards
2026-09-28 19:14 ` [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Tom Rini
@ 2026-09-28 20:59 ` Vincent Jardin
2026-09-28 21:15 ` Tom Rini
0 siblings, 1 reply; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 20:59 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Peng Fan, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean
Hi Tom,
On Mon, Sep 28, 2026 at 01:14:12PM -0600, Tom Rini wrote:
> On Mon, Sep 28, 2026 at 12:13:19PM +0200, Vincent Jardin wrote:
> > .../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 | 588 ++++++++++++++----
> > board/nxp/lx2160a/serdes_split.h | 16 +-
> > doc/README.fsl-hwconfig | 61 ++
> > 6 files changed, 556 insertions(+), 123 deletions(-)
>
> Those two doc files, has anyone asked you to please convert them to rST
> and then update them? And, I don't hate the idea of doing that as a
> follow-up, but since we have people touching the files that understand
> the content, this is the time to convert. Thanks!
ok, I'll do it, but after this serie ? I'll emit a set to convert
those from legacy to RST.
Best regards,
Vincent
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards
2026-09-28 20:59 ` Vincent Jardin
@ 2026-09-28 21:15 ` Tom Rini
0 siblings, 0 replies; 23+ messages in thread
From: Tom Rini @ 2026-09-28 21:15 UTC (permalink / raw)
To: Vincent Jardin
Cc: u-boot, Peng Fan, Hemant Agrawal, Wasim Khan, Priyanka Jain,
Meenakshi Aggarwal, Ioana Ciornei, Vladimir Oltean
[-- Attachment #1: Type: text/plain, Size: 1088 bytes --]
On Mon, Sep 28, 2026 at 10:59:04PM +0200, Vincent Jardin wrote:
> Hi Tom,
>
> On Mon, Sep 28, 2026 at 01:14:12PM -0600, Tom Rini wrote:
> > On Mon, Sep 28, 2026 at 12:13:19PM +0200, Vincent Jardin wrote:
> > > .../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 | 588 ++++++++++++++----
> > > board/nxp/lx2160a/serdes_split.h | 16 +-
> > > doc/README.fsl-hwconfig | 61 ++
> > > 6 files changed, 556 insertions(+), 123 deletions(-)
> >
> > Those two doc files, has anyone asked you to please convert them to rST
> > and then update them? And, I don't hate the idea of doing that as a
> > follow-up, but since we have people touching the files that understand
> > the content, this is the time to convert. Thanks!
>
> ok, I'll do it, but after this serie ? I'll emit a set to convert
> those from legacy to RST.
Sounds good, thanks!
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option
2026-09-28 15:10 ` Vladimir Oltean
@ 2026-09-28 22:13 ` Vincent Jardin
0 siblings, 0 replies; 23+ messages in thread
From: Vincent Jardin @ 2026-09-28 22:13 UTC (permalink / raw)
To: Vladimir Oltean
Cc: u-boot, Peng Fan, Tom Rini, Hemant Agrawal, Wasim Khan,
Priyanka Jain, Meenakshi Aggarwal, Ioana Ciornei
Hi Vladimir,
> > + 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
>
> How much do you plan to extend this, really?
That's it. They are the 5 scenarios I am interested in for my use cases.
I did briefly try some others split of the first 4 lanes instead of 100G
and 40G, it seems workable.
I'll leave those to who ever needs it.
> Do you ever plan to support a mode with multiple 'from' modes?
>
> Like for example, 100g4x25g can come either from 2x100g, or from 100g4x10g.
> The sd1_enter() recursion and graph traversal becomes quite a bit more
> complicated.
I do not think it is needed starting from a uboot/boot settings.
At the current states, SD1 is always from RCW 13 (or 20).
It means that sd1 cannot be in 100G+4x10G when 100G+4x25G is requested.
> But in principle, there's nothing saying you can transition to one
> SerDes protocol just from a single source. In that sense, I think your
> choices are rather arbitrary and may not suit everyone, so talking about
> multiple sources now seems rather adequate.
I guess you are right that more transitions should be possible, but I'd
like to leave those for a later design. I guess, based on the current
user uboot shell and env/hwconfig, we can still reshuffle it later for
more scenarios.
best regards,
Vnincent
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2026-09-28 22:13 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28 10:13 [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 01/10] board: lx2160a: serdes: drop the split subcommand Vincent Jardin
2026-09-28 11:17 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 02/10] board: lx2160a: serdes: rename serdes1:split to serdes1:100g4x25g Vincent Jardin
2026-09-28 11:18 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 03/10] board: lx2160a: serdes: set SD1 with a table Vincent Jardin
2026-09-28 12:02 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 04/10] board: lx2160a: serdes: report unknown SD1 cases Vincent Jardin
2026-09-28 14:29 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 05/10] board: lx2160a: serdes: no SD1 config once MC runs Vincent Jardin
2026-09-28 14:50 ` Vladimir Oltean
2026-09-28 10:13 ` [PATCH v4 06/10] board: lx2160a: serdes: add serdes1:2x40g Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 07/10] board: lx2160a: serdes: add serdes1:40g4x10g Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 08/10] board: lx2160a: serdes: add serdes1:100g4x10g Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 09/10] doc: lx2160a: document the sd1 hwconfig option Vincent Jardin
2026-09-28 15:05 ` Vladimir Oltean
2026-09-28 15:10 ` Vladimir Oltean
2026-09-28 22:13 ` Vincent Jardin
2026-09-28 10:13 ` [PATCH v4 10/10] board: nbxv3: apply sd1 hwconfig before MC starts Vincent Jardin
2026-09-28 15:07 ` Vladimir Oltean
2026-09-28 19:14 ` [PATCH v4 00/10] board: lx2160a: runtime SD 1 lane configuration for LX2160A boards Tom Rini
2026-09-28 20:59 ` Vincent Jardin
2026-09-28 21:15 ` Tom Rini
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.