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 <[email protected]>

---

Changes in v7:
- Reset only LNE-LNH, as 100g4x25g (Vladimir)

Changes in v5:
- sd1_reset_req()

Changes in v4:
- was on v3 3/5, now let's add an entry of the mode table

 board/nxp/lx2160a/serdes_split.c | 51 ++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/board/nxp/lx2160a/serdes_split.c b/board/nxp/lx2160a/serdes_split.c
index 41208ca79ab..316d500292a 100644
--- a/board/nxp/lx2160a/serdes_split.c
+++ b/board/nxp/lx2160a/serdes_split.c
@@ -572,6 +572,50 @@ 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_enter_40g4x10g(unsigned long base)
+{
+       unsigned long lanes = SD1_LNE_LNH;
+       int m, ret, err;
+
+       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);
+
+       sd1_reset_req(base, lanes);
+       err = sd1_reset_wait(base, lanes);
+
+       return err ? err : ret;
+}
+
 static const struct sd1_mode sd1_modes[] = {
        {
                .name = "2x100g",
@@ -592,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_find(const char *name, size_t len)
-- 
2.43.0

Reply via email to