p4080/serdes: Implement the XAUI workaround for SERDES9 erratum
authorEmil Medve <Emilian.Medve@freescale.com>
Wed, 1 Sep 2010 03:57:38 +0000 (22:57 -0500)
committerKumar Gala <galak@kernel.crashing.org>
Thu, 28 Apr 2011 03:29:04 +0000 (22:29 -0500)
Signed-off-by: Emil Medve <Emilian.Medve@Freescale.com>
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
arch/powerpc/cpu/mpc85xx/cmd_errata.c
arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c
arch/powerpc/include/asm/config_mpc85xx.h
arch/powerpc/include/asm/fsl_serdes.h
arch/powerpc/include/asm/immap_85xx.h

index e94975a1c6857c27b111dc4792f0d622e86b7a1c..05648169ad41f9cd272617fb6b3fac90b1fb0a46 100644 (file)
@@ -44,6 +44,9 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 #if defined(CONFIG_SYS_P4080_ERRATUM_SERDES8)
        puts("Work-around for Erratum SERDES8 enabled\n");
 #endif
+#if defined(CONFIG_SYS_P4080_ERRATUM_SERDES9)
+       puts("Work-around for Erratum SERDES9 enabled\n");
+#endif
 #if defined(CONFIG_SYS_P4080_ERRATUM_CPU22)
        puts("Work-around for Erratum CPU22 enabled\n");
 #endif
index 1177247e787776ac7250929f47bdd57996c90347..d39f96352ef9d9c839fc879d9ef41c7df0323035 100644 (file)
@@ -168,6 +168,90 @@ int serdes_get_first_lane(enum srds_prtcl device)
        return __serdes_get_first_lane(prtcl, device);
 }
 
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
+/*
+ * Returns the SERDES bank (1, 2, or 3) that a given device is on for a given
+ * SERDES protocol.
+ *
+ * Returns a negative error code if the given device is not supported for the
+ * given SERDES protocol.
+ */
+static int serdes_get_bank_by_device(uint32_t prtcl, enum srds_prtcl device)
+{
+       int lane;
+
+       lane = __serdes_get_first_lane(prtcl, device);
+       if (unlikely(lane < 0))
+               return lane;
+
+       return serdes_get_bank_by_lane(lane);
+}
+
+static uint32_t __serdes_get_lane_count(uint32_t prtcl, enum srds_prtcl device,
+                                       int first)
+{
+       int lane;
+
+       for (lane = first; lane < SRDS_MAX_LANES; lane++) {
+               if (serdes_get_prtcl(prtcl, lane) != device)
+                       break;
+       }
+
+       return lane - first;
+}
+
+static void __serdes_reset_rx(serdes_corenet_t *regs,
+                             uint32_t prtcl,
+                             enum srds_prtcl device)
+{
+       int lane, idx, first, last;
+
+       lane = __serdes_get_first_lane(prtcl, device);
+       if (unlikely(lane < 0))
+               return;
+       first = serdes_get_lane_idx(lane);
+       last = first + __serdes_get_lane_count(prtcl, device, lane);
+
+       /*
+        * Set BnGCRy0[RRST] = 0 for each lane in the each bank that is
+        * selected as XAUI to place the lane into reset.
+       */
+       for (idx = first; idx < last; idx++)
+               clrbits_be32(&regs->lane[idx].gcr0, SRDS_GCR0_RRST);
+
+       /* Wait at least 250 ns */
+       udelay(1);
+
+       /*
+        * Set BnGCRy0[RRST] = 1 for each lane in the each bank that is
+        * selected as XAUI to bring the lane out of reset.
+        */
+       for (idx = first; idx < last; idx++)
+               setbits_be32(&regs->lane[idx].gcr0, SRDS_GCR0_RRST);
+}
+
+void serdes_reset_rx(enum srds_prtcl device)
+{
+       u32 prtcl;
+       const ccsr_gur_t *gur;
+       serdes_corenet_t *regs;
+
+       if (unlikely(device == NONE))
+               return;
+
+       gur = (typeof(gur))CONFIG_SYS_MPC85xx_GUTS_ADDR;
+
+       /* Is serdes enabled at all? */
+       if (unlikely((in_be32(&gur->rcwsr[5]) & 0x2000) == 0))
+               return;
+
+       regs = (typeof(regs))CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+       prtcl = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;
+
+       __serdes_reset_rx(regs, prtcl, device);
+}
+#endif
+
 #ifndef CONFIG_SYS_DCSRBAR_PHYS
 #define CONFIG_SYS_DCSRBAR_PHYS        0x80000000 /* Must be 1GB-aligned for rev1.0 */
 #define CONFIG_SYS_DCSRBAR     0x80000000
@@ -317,6 +401,9 @@ void fsl_serdes_init(void)
        char srds_lpd_opt[16];
        const char *srds_lpd_arg;
        size_t arglen;
+#endif
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
+       enum srds_prtcl device;
 #endif
        char buffer[HWCONFIG_BUFFER_SIZE];
        char *buf = NULL;
@@ -452,6 +539,17 @@ void fsl_serdes_init(void)
                        break;
                case XAUI_FM1:
                case XAUI_FM2:
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
+                       /*
+                        * Set BnTTLCRy0[FLT_SEL] = 000011 and set
+                        * BnTTLCRy0[17] = 1 for each of the SerDes lanes
+                        * selected as XAUI on each bank before XAUI is
+                        * initialized.
+                        */
+                       clrsetbits_be32(&srds_regs->lane[idx].ttlcr0,
+                                       SRDS_TTLCR0_FLT_SEL_MASK,
+                                       0x03000000 | SRDS_TTLCR0_PM_DIS);
+#endif
                        if (lane_prtcl == XAUI_FM1)
                                serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1    |
                                                    FSL_CORENET_DEVDISR2_10GEC1;
@@ -470,6 +568,8 @@ void fsl_serdes_init(void)
 
 #ifdef DEBUG
        puts("\n");
+#endif
+
 #endif
 
        for (idx = 0; idx < SRDS_MAX_BANK; idx++) {
@@ -527,4 +627,11 @@ void fsl_serdes_init(void)
                        continue;
                }
        }
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
+       for (device = XAUI_FM1; device <= XAUI_FM2; device++) {
+               if (is_serdes_configured(device))
+                       __serdes_reset_rx(srds_regs, cfg, device);
+       }
+#endif
 }
index 41fd86c4e222bf648a910b01a0dc93cdd1ffaea0..88bc0309c0570c8eef5a32368ed425e9ebb38073 100644 (file)
 #define CONFIG_SYS_FSL_ERRATUM_ESDHC136
 #define CONFIG_SYS_P4080_ERRATUM_CPU22
 #define CONFIG_SYS_P4080_ERRATUM_SERDES8
+#define CONFIG_SYS_P4080_ERRATUM_SERDES9
 
 /* P5010 is single core version of P5020 */
 #elif defined(CONFIG_PPC_P5010)
index 9d9f2e4cce1d57e26b71548d513c33153f51a3c3..0f31af1db320e8d9272eaefd8dbf9446a8b546a2 100644 (file)
@@ -55,6 +55,9 @@ void fsl_serdes_init(void);
 
 #ifdef CONFIG_FSL_CORENET
 int serdes_get_first_lane(enum srds_prtcl device);
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
+void serdes_reset_rx(enum srds_prtcl device);
+#endif
 #endif
 
 #endif /* __FSL_SERDES_H */
index d6ac61afaf53997ad6c440df5a1552cc78c03a5b..286ecb9a5caff922f8815dcfd8b43f43faadf33a 100644 (file)
@@ -2137,6 +2137,8 @@ typedef struct serdes_corenet {
 #define SRDS_TECR0_TEQ_TYPE_2LVL       0x10000000
                u32     res3;
                u32     ttlcr0; /* Transition Tracking Loop Ctrl 0 */
+#define SRDS_TTLCR0_FLT_SEL_MASK       0x3f000000
+#define SRDS_TTLCR0_PM_DIS             0x00004000
                u32     res4[7];
        } lane[24];
        u32 res6[384];