Derive the mode from ${carrier}:

  nbv32              100g4x25g   1x 100GE + 4x 25G
  nbv32-40g          2x40g       2x 40GE
  nbv32-40g-4x10g    40g4x10g    1x 40GE + 4x 10G
  nbv32-100g-4x10g   100g4x10g   1x 100GE + 4x 10G

so that "setenv carrier <name>" alone selects the lanes and the data
path that describes them.

Signed-off-by: Vincent Jardin <[email protected]>

---

(no changes since v1)

 board/nxp/lx2160a/nbxv3/carrier.c   | 97 +++++++++++++++++++++++++++++
 board/nxp/lx2160a/nbxv3/carrier.h   |  6 ++
 board/nxp/lx2160a/nbxv3/eth_nbxv3.c |  4 +-
 doc/board/nxp/nbxv3.rst             | 22 +++++++
 4 files changed, 127 insertions(+), 2 deletions(-)

diff --git a/board/nxp/lx2160a/nbxv3/carrier.c 
b/board/nxp/lx2160a/nbxv3/carrier.c
index 06a54bed0eb..26b079a1d3a 100644
--- a/board/nxp/lx2160a/nbxv3/carrier.c
+++ b/board/nxp/lx2160a/nbxv3/carrier.c
@@ -23,16 +23,20 @@
  */
 
 #include <env.h>
+#include <hwconfig.h>
+#include <malloc.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/string.h>
 #include <vsprintf.h>
 #include <asm/io.h>
 #include <asm/arch/immap_lsch3.h>
 #include <asm/arch/soc.h>
 
 #include "carrier.h"
+#include "../serdes_split.h"
 
 #ifndef NBXV3_CARRIER_DEFAULT
 #define NBXV3_CARRIER_DEFAULT "nbv30"
@@ -148,3 +152,96 @@ void nbxv3_carrier_env_init(void)
        printf("Carrier:       %s (%s, not saved; setenv carrier <name> && 
saveenv to pin)\n",
               carrier, origin);
 }
+
+/*
+ * serdes 1 lane grouping of each carrier, as a hwconfig serdes1:<mode>
+ * of board/nxp/lx2160a/serdes_split.c. A carrier without an entry
+ * keeps what the RCW provides.
+ *
+ * nbv32-40g used to need an RCW at serdes 1 protocol 20. serdes1:2x40g
+ * builds the same grouping from the protocol 13 RCW, and it is void
+ * for a protocol 20 one.
+ */
+static const struct {
+       const char *carrier;
+       const char *mode;
+} nbxv3_serdes1_modes[] = {
+       { .carrier = "nbv32",                   .mode = "100g4x25g" },
+       { .carrier = "nbv32-40g",               .mode = "2x40g" },
+       { .carrier = "nbv32-40g-4x10g",         .mode = "40g4x10g" },
+       { .carrier = "nbv32-100g-4x10g",        .mode = "100g4x10g" },
+};
+
+/* Is ${hwconfig} serdes1:@mode ? */
+static bool nbxv3_serdes1_is(const char *mode)
+{
+       const char *arg;
+       size_t len;
+
+       arg = hwconfig_arg("serdes1", &len);
+
+       return arg && len == strlen(mode) && !strncmp(arg, mode, len);
+}
+
+/* Does ${hwconfig} name a SerDes 1 mode ? */
+static bool nbxv3_serdes1_named(void)
+{
+       int i;
+
+       if (nbxv3_serdes1_is("2x100g"))
+               return true;
+
+       for (i = 0; i < ARRAY_SIZE(nbxv3_serdes1_modes); i++)
+               if (nbxv3_serdes1_is(nbxv3_serdes1_modes[i].mode))
+                       return true;
+
+       return false;
+}
+
+void nbxv3_serdes1_apply(void)
+{
+       const char *carrier = env_get("carrier");
+       const char *mode = NULL;
+       const char *cur;
+       char *saved = NULL;
+       char *hw = NULL;
+       bool set = false;
+       int i;
+
+       for (i = 0; carrier && i < ARRAY_SIZE(nbxv3_serdes1_modes); i++)
+               if (!strcmp(carrier, nbxv3_serdes1_modes[i].carrier))
+                       mode = nbxv3_serdes1_modes[i].mode;
+
+       /* Put serdes1:<mode> in front of ${hwconfig} */
+       if (mode && !nbxv3_serdes1_named()) {
+               if (hwconfig("serdes1"))
+                       printf("Carrier:       ${hwconfig} serdes1 names no 
mode, serdes1:%s of %s used\n",
+                              mode, carrier);
+               cur = env_get("hwconfig");
+               if (cur && *cur)
+                       saved = strdup(cur);
+               hw = malloc(sizeof("serdes1:") + strlen(mode) +
+                           (saved ? strlen(saved) + 1 : 0));
+               if (hw && (saved || !cur || !*cur)) {
+                       sprintf(hw, "serdes1:%s%s%s", mode, saved ? ";" : "",
+                               saved ? saved : "");
+                       set = !env_set("hwconfig", hw);
+               }
+               if (!set)
+                       printf("Carrier:       WARNING: cannot add serdes1:%s 
to ${hwconfig}\n",
+                              mode);
+       }
+
+       lx2160a_serdes_apply_hwconfig();
+
+       /* The DS250 retimers do not follow the SerDes on their own */
+       if (nbxv3_serdes1_is("100g4x10g"))
+               printf("Carrier:       serdes1:100g4x10g mixes 25.78125 and 
10.3125 Gbd lanes, set each retimer CDR to the rate of its lane\n");
+
+       /* Put ${hwconfig} back; NULL deletes it again if it was not set */
+       if (set && env_set("hwconfig", saved))
+               printf("Carrier:       WARNING: cannot restore ${hwconfig}\n");
+
+       free(hw);
+       free(saved);
+}
diff --git a/board/nxp/lx2160a/nbxv3/carrier.h 
b/board/nxp/lx2160a/nbxv3/carrier.h
index 44b2ce1f047..063765821eb 100644
--- a/board/nxp/lx2160a/nbxv3/carrier.h
+++ b/board/nxp/lx2160a/nbxv3/carrier.h
@@ -15,4 +15,10 @@
  */
 void nbxv3_carrier_env_init(void);
 
+/*
+ * Apply the serdes 1 lane of ${carrier}, unless ${hwconfig}
+ * names a serdes1:<mode>
+ */
+void nbxv3_serdes1_apply(void);
+
 #endif /* __NBXV3_CARRIER_H */
diff --git a/board/nxp/lx2160a/nbxv3/eth_nbxv3.c 
b/board/nxp/lx2160a/nbxv3/eth_nbxv3.c
index 69873909733..6dd05b5fe23 100644
--- a/board/nxp/lx2160a/nbxv3/eth_nbxv3.c
+++ b/board/nxp/lx2160a/nbxv3/eth_nbxv3.c
@@ -15,7 +15,6 @@
 #include <fsl-mc/fsl_mc.h>
 
 #include "carrier.h"
-#include "../serdes_split.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -35,7 +34,8 @@ void reset_phy(void)
         */
        nbxv3_carrier_env_init();
 
-       lx2160a_serdes_apply_hwconfig();
+       /* Then SerDes 1, from ${hwconfig} or else from ${carrier} */
+       nbxv3_serdes1_apply();
 
        if (IS_ENABLED(CONFIG_FSL_MC_ENET))
                mc_env_boot();
diff --git a/doc/board/nxp/nbxv3.rst b/doc/board/nxp/nbxv3.rst
index 8259ca85095..0e3578b5742 100644
--- a/doc/board/nxp/nbxv3.rst
+++ b/doc/board/nxp/nbxv3.rst
@@ -121,6 +121,28 @@ no data path for the MC to manage and starting it hangs 
the boot.
 U-Boot clears ``mcinitcmd`` for that boot, whatever ``${carrier}`` is,
 and does not save it.
 
+SerDes 1 per carrier
+^^^^^^^^^^^^^^^^^^^^
+
+Before the MC starts, U-Boot should set the serdes 1 lane grouping
+that the MC's DPC and the DPL of ``${carrier}`` expect, using
+the ``serdes1`` hwconfig option. It can be used to
+override the RCW's protocol grouping for SerDes 1.
+
+==================== ================= ==============================
+``${carrier}``       serdes1 mode      SerDes 1
+==================== ================= ==============================
+nbv30                (none)            as built by the RCW
+nbv32                100g4x25g         1x 100GE + 4x 25G
+nbv32-40g            2x40g             2x 40GE
+nbv32-40g-4x10g      40g4x10g          1x 40GE + 4x 10G
+nbv32-100g-4x10g     100g4x10g         1x 100GE + 4x 10G
+==================== ================= ==============================
+
+Example to switch an NBV32 to 1x40GE + 4x10G::
+
+  => setenv carrier nbv32-40g-4x10g && saveenv && reset
+
 Boot flow
 ---------
 
-- 
2.43.0

Reply via email to