Fix the commit
035d68fc36b5 ("lx2160: add lx2160_serdes split and management")
which is in next.
It leads to the following commands which are more explicit:
lx2160_sd1 100g4x25g
CHANGES the SerDes 1 Ethernet mode: it re-groups SD1's
eight lanes and re-points its protocol converters.
lx2160_serdes status [1|2|3]
only READS, any of the three SerDes, unchanged syntax.
In order to prepare the next commits, this mode should be:
100g4x25g (1x 100G + 4x 25G),
instead of "split", same for its hwconfig key:
setenv hwconfig serdes1:100g4x25g && saveenv
The follow-up patches will add more SerDes 1 modes under the lx2160_sd1.
The SerDes 3 and LX2160A-only branches use IS_ENABLED() instead of
preprocessor conditionals, and the header no longer wraps its
declarations in CONFIG_ARCH_LX2160A: the definitions stay guarded in
serdes_split.c.
Signed-off-by: Vincent Jardin <[email protected]>
---
Changes in v3:
- Incremental on top of next, where v1 is merged as 035d68fc36b5:
v2 mistakenly re-sent the whole file as its patch 1 (reported by
Vladimir Oltean). Patch 1 is now only the delta: the lx2160_sd1 /
lx2160_serdes command split and the 100g4x25g naming.
- Patches 2-5 unchanged, rebased onto next
Changes in v2:
- The mode-changing command is lx2160_sd1, lx2160_serdes only reads
(v1 had both behind one lx2160_serdes command)
- New patches 2-4: the runtime SD1 conversions for many cases of
split (2x 100GE -> 2x 40GE, second 40GE port -> 4x 10G,
1x 100GE + 4x 10G)
- New patch 5: hwconfig and README.soc documentation
- Mode names say what they produce: 100g4x25g (v1: split), 2x40g
(was 40g), 40g4x10g (was 4x10g); 100g4x10g unchanged; same for the
hwconfig serdes1: keys
- Rebased onto main
board/nxp/lx2160a/eth_lx2160aqds.c | 2 +-
board/nxp/lx2160a/serdes_split.c | 119 ++++++++++++++++-------------
board/nxp/lx2160a/serdes_split.h | 11 +--
3 files changed, 70 insertions(+), 62 deletions(-)
diff --git a/board/nxp/lx2160a/eth_lx2160aqds.c
b/board/nxp/lx2160a/eth_lx2160aqds.c
index c1a060877cd..b13606354e0 100644
--- a/board/nxp/lx2160a/eth_lx2160aqds.c
+++ b/board/nxp/lx2160a/eth_lx2160aqds.c
@@ -18,7 +18,7 @@ void reset_phy(void)
{
/*
* Before the MC boots: it latches the live protocol-converter
- * configuration when it starts, so `hwconfig=serdes1:split` has to
+ * configuration when it starts, so `hwconfig=serdes1:100g4x25g` 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 ca3d7228977..04339a71350 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -2,7 +2,7 @@
/*
* Copyright 2026 Free Mobile - Vincent Jardin
*
- * LX2160A 28G-Lynx SerDes inspection (`lx2160_serdes`).
+ * LX2160A 28G-Lynx SerDes customization.
*/
#include <command.h>
@@ -19,11 +19,8 @@
#include "serdes_split.h"
-#if defined(CONFIG_SYS_NXP_SRDS_3)
-#define SRDS_COUNT 3
-#else
-#define SRDS_COUNT 2 /* LX2162A has no SerDes 3 */
-#endif
+/* LX2162A has no SerDes 3 */
+#define SRDS_COUNT (IS_ENABLED(CONFIG_SYS_NXP_SRDS_3) ? 3 : 2)
#define SRDS_LANES 8
#define SRDS_BLOCK_STRIDE 0x10000
#define SRDS_LANE_STRIDE 0x100
@@ -102,8 +99,9 @@ static void print_rstctl(const char *what, u32 v)
* must be 0 only on the port's master lane, and 0 on every single-lane
* port. So a run of lanes where exactly one has PORT_LN0_B=0 is one
* multi-lane port, and a run where all of them are 0 is that many
- * one-lane ports. That is precisely what the 100G -> 4x 25G split
- * changes, and it is invisible in RCWSR.
+ * one-lane ports.
+ * That is precisely what the 100G -> 4x 25G split changes, and it is
+ * invisible in RCWSR.
*/
static void print_lane(unsigned long base, int m)
{
@@ -126,15 +124,14 @@ static void print_lane(unsigned long base, int m)
/*
* Summarise the port grouping, which is the one line that says whether a
- * split happened. With PORT_RST_LEFT=0 the port's master is
- * its right-most lane (towards LNH), with PORT_RST_LEFT=1 it is the
- * left-most: PORT_LN0_B=0 marks that master, and is also 0 on every
- * single-lane port. So a group is a run of PORT_LN0_B=1 lanes terminated
- * (or led) by a PORT_LN0_B=0 lane.
+ * split happened.
+ * With PORT_RST_LEFT=0 the port's master is its right-most lane (towards LNH)
+ * With PORT_RST_LEFT=1 it is the left-most: PORT_LN0_B=0 marks that master
+ * and is also 0 on every single-lane port. So a group is a run of PORT_LN0_B=1
+ * lanes terminated (or led) by a PORT_LN0_B=0 lane.
*
- * Checked on board with the PBI split applied:
- * [LNA-LND] [LNE] [LNF] [LNG] [LNH] -- 1x 100G + 4x 25G
- * and without it lanes E-H would read as a second [LNE-LNH] group.
+ * Examples:
+ * [LNA-LND] [LNE] [LNF] [LNG] [LNH] 1x 100G + 4x 25G
*/
static void print_grouping(unsigned long base)
{
@@ -152,7 +149,7 @@ static void print_grouping(unsigned long base)
int s, e;
if (gcr0[m] & GCR0_PORT_LN0_B)
- continue; /* a follower, not a master */
+ continue; /* a follower, not a master */
s = m;
e = m;
@@ -225,13 +222,13 @@ static void print_rcw_view(int sd)
mask = FSL_CHASSIS3_SRDS2_PRTCL_MASK;
shift = FSL_CHASSIS3_SRDS2_PRTCL_SHIFT;
break;
-#if defined(CONFIG_SYS_NXP_SRDS_3)
case NXP_SRDS_3:
+ if (!IS_ENABLED(CONFIG_SYS_NXP_SRDS_3))
+ return;
regsr = FSL_CHASSIS3_SRDS3_REGSR;
mask = FSL_CHASSIS3_SRDS3_PRTCL_MASK;
shift = FSL_CHASSIS3_SRDS3_PRTCL_SHIFT;
break;
-#endif
default:
return;
}
@@ -248,8 +245,7 @@ static void print_rcw_view(int sd)
/*
* The split itself.
*
- * This is NXP's e100g1_split.rcw sequence, moved from the PBI into
- * U-Boot.
+ * This is NXP's e100g1_split.rcw sequence, adapted from the PBI into U-Boot
*/
#define SPLIT_FIRST_LANE 4 /* LNE */
#define SPLIT_LAST_LANE 7 /* LNH */
@@ -272,8 +268,10 @@ static bool srds1_split_state(unsigned long 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);
+ 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)
@@ -286,15 +284,17 @@ static bool srds1_is_unsplit(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 &&
+ 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;
}
/*
- * Wait for a self-clearing request bit. Per the doc, hardware
- * clears HLT_REQ when the halt completes and RST_REQ when the reset
- * completes.
+ * Wait for a self-clearing request bit. The CPU clears HLT_REQ
+ * when the halt completes and RST_REQ when the reset completes.
*/
static int poll_clear(unsigned long reg, u32 bit)
{
@@ -328,11 +328,11 @@ int lx2160a_serdes1_split(void)
/*
* 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.
+ * 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 but only wait on the lane where the bit
+ * can actually clear.
*/
for (m = SPLIT_FIRST_LANE; m <= SPLIT_LAST_LANE; m++) {
if (!(in_le32((void __iomem *)SRDS_LNmGCR0(base, m)) &
@@ -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())
@@ -441,19 +441,17 @@ static int do_serdes_status(int sd)
return CMD_RET_SUCCESS;
}
-static int do_lx2160_serdes(struct cmd_tbl *cmdtp, int flag,
- int argc, char *const argv[])
+static int do_lx2160_sd1(struct cmd_tbl *cmdtp, int flag,
+ int argc, char *const argv[])
{
- int sd;
-
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 (!strcmp(argv[1], "100g4x25g")) {
+ if (!IS_ENABLED(CONFIG_ARCH_LX2160A)) {
+ printf("no 100GE on SerDes 1 to split on this SoC\n");
+ return CMD_RET_FAILURE;
+ }
if (argc != 2)
return CMD_RET_USAGE;
if (lx2160a_serdes1_is_split()) {
@@ -463,9 +461,20 @@ static int do_lx2160_serdes(struct cmd_tbl *cmdtp, int
flag,
if (lx2160a_serdes1_split())
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
-#endif
}
+ return CMD_RET_USAGE;
+}
+
+/* reads SD1, SD2 or SD3 */
+static int do_lx2160_serdes(struct cmd_tbl *cmdtp, int flag,
+ int argc, char *const argv[])
+{
+ int sd;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
if (strcmp(argv[1], "status"))
return CMD_RET_USAGE;
@@ -488,15 +497,22 @@ static int do_lx2160_serdes(struct cmd_tbl *cmdtp, int
flag,
}
#if defined(CONFIG_ARCH_LX2160A)
-#define SPLIT_CMD_HELP \
- "lx2160_serdes split\n" \
+#define SD1_CMD_HELP \
+ "100g4x25g\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"
+ " that needs it: setenv hwconfig serdes1:100g4x25g && saveenv"
#else
-#define SPLIT_CMD_HELP ""
+#define SD1_CMD_HELP \
+ " - no SerDes 1 Ethernet modes on this SoC"
#endif
+U_BOOT_CMD(
+ lx2160_sd1, 3, 0, do_lx2160_sd1,
+ "select the LX2160A SerDes 1 Ethernet mode",
+ SD1_CMD_HELP
+);
+
U_BOOT_CMD(
lx2160_serdes, 3, 0, do_lx2160_serdes,
"inspect the LX2160A 28G-Lynx SerDes protocol configuration",
@@ -504,6 +520,5 @@ U_BOOT_CMD(
" - print the live protocol converters (PCCC/PCCD/PCCE) and the\n"
" 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
+ " No argument prints all CPU SerDes blocks."
);
diff --git a/board/nxp/lx2160a/serdes_split.h b/board/nxp/lx2160a/serdes_split.h
index 67e8c4873a7..764eb640029 100644
--- a/board/nxp/lx2160a/serdes_split.h
+++ b/board/nxp/lx2160a/serdes_split.h
@@ -7,10 +7,9 @@
#define __LX2160A_SERDES_SPLIT_H
/*
- * The split is LX2160A only: LX2162A's SerDes 1 is four lanes with no
- * 100GE in its protocol table.
+ * The SerDes 1 modes are LX2160A only: LX2162A's SerDes 1 is four lanes
+ * without 100GE in its protocol table.
*/
-#if defined(CONFIG_ARCH_LX2160A)
/* Is SerDes 1 already 1x 100G + 4x 25G? */
bool lx2160a_serdes1_is_split(void);
@@ -24,12 +23,6 @@ bool lx2160a_serdes1_is_split(void);
*/
int lx2160a_serdes1_split(void);
-/*
- * Apply `hwconfig=serdes1:split` if the board's environment asks for it.
- * Boards call this from reset_phy(), before mc_env_boot().
- */
void lx2160a_serdes_apply_hwconfig(void);
-#endif /* CONFIG_ARCH_LX2160A */
-
#endif /* __LX2160A_SERDES_SPLIT_H */
--
2.43.0