]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
powerpc/srio: Workaround for srio erratrm a004034
authorLiu Gang <Gang.Liu@freescale.com>
Fri, 28 Sep 2012 21:26:19 +0000 (21:26 +0000)
committerAndy Fleming <afleming@freescale.com>
Mon, 22 Oct 2012 19:31:12 +0000 (14:31 -0500)
Erratum: A-004034
Affects: SRIO

Description: During port initialization, the SRIO port performs
lane synchronization (detecting valid symbols on a lane) and
lane alignment (coordinating multiple lanes to receive valid data
across lanes). Internal errors in lane synchronization and lane
alignment may cause failure to achieve link initialization at
the configured port width.

An SRIO port configured as a 4x port may see one of these scenarios:

1. One or more lanes fails to achieve lane synchronization.
Depending on which lanes fail, this may result in downtraining
from 4x to 1x on lane 0, 4x to 1x on lane R (redundant lane).

2. The link may fail to achieve lane alignment as a 4x, even
though all 4 lanes achieve lane synchronization, and downtrain
to a 1x. An SRIO port configured as a 1x port may fail to complete
port initialization (PnESCSR[PU] never deasserts) because of
scenario 1.

Impact: SRIO port may downtrain to 1x, or may fail to complete
link initialization. Once a port completes link initialization
successfully, it will operate normally.

Signed-off-by: Liu Gang <Gang.Liu@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
arch/powerpc/cpu/mpc85xx/cmd_errata.c
arch/powerpc/cpu/mpc8xxx/srio.c
arch/powerpc/include/asm/config_mpc85xx.h

index 7e4cc036408f7bcac761678fe98bb7ff542f9f69..bc7e5e36e2eb5de0eb135fa7551d02a6945d113a 100644 (file)
@@ -127,6 +127,9 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 #endif
 #ifdef CONFIG_SYS_FSL_ERRATUM_A004510
        puts("Work-around for Erratum A004510 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+       puts("Work-around for Erratum SRIO-A004034 enabled\n");
 #endif
        return 0;
 }
index 0cb65b32e48919f2a38cebec329389be8db3dcf1..e7ff59a1ca963aa06eb8574630135ee649f7e024 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/fsl_law.h>
 #include <asm/fsl_serdes.h>
 #include <asm/fsl_srio.h>
+#include <asm/errno.h>
 
 #define SRIO_PORT_ACCEPT_ALL 0x10000001
 #define SRIO_IB_ATMU_AR 0x80f55000
 #error "No defines for DEVDISR_SRIO"
 #endif
 
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+/*
+ * Erratum A-004034
+ * Affects: SRIO
+ * Description: During port initialization, the SRIO port performs
+ * lane synchronization (detecting valid symbols on a lane) and
+ * lane alignment (coordinating multiple lanes to receive valid data
+ * across lanes). Internal errors in lane synchronization and lane
+ * alignment may cause failure to achieve link initialization at
+ * the configured port width.
+ * An SRIO port configured as a 4x port may see one of these scenarios:
+ * 1. One or more lanes fails to achieve lane synchronization. Depending
+ * on which lanes fail, this may result in downtraining from 4x to 1x
+ * on lane 0, 4x to 1x on lane R (redundant lane).
+ * 2. The link may fail to achieve lane alignment as a 4x, even though
+ * all 4 lanes achieve lane synchronization, and downtrain to a 1x.
+ * An SRIO port configured as a 1x port may fail to complete port
+ * initialization (PnESCSR[PU] never deasserts) because of scenario 1.
+ * Impact: SRIO port may downtrain to 1x, or may fail to complete
+ * link initialization. Once a port completes link initialization
+ * successfully, it will operate normally.
+ */
+static int srio_erratum_a004034(u8 port)
+{
+       serdes_corenet_t *srds_regs;
+       u32 conf_lane;
+       u32 init_lane;
+       int idx, first, last;
+       u32 i;
+       unsigned long long end_tick;
+       struct ccsr_rio *srio_regs = (void *)CONFIG_SYS_FSL_SRIO_ADDR;
+
+       srds_regs = (void *)(CONFIG_SYS_FSL_CORENET_SERDES_ADDR);
+       conf_lane = (in_be32((void *)&srds_regs->srdspccr0)
+                       >> (12 - port * 4)) & 0x3;
+       init_lane = (in_be32((void *)&srio_regs->lp_serial
+                       .port[port].pccsr) >> 27) & 0x7;
+
+       /*
+        * Start a counter set to ~2 ms after the SERDES reset is
+        * complete (SERDES SRDSBnRSTCTL[RST_DONE]=1 for n
+        * corresponding to the SERDES bank/PLL for the SRIO port).
+        */
+        if (in_be32((void *)&srds_regs->bank[0].rstctl)
+               & SRDS_RSTCTL_RSTDONE) {
+               /*
+                * Poll the port uninitialized status (SRIO PnESCSR[PO]) until
+                * PO=1 or the counter expires. If the counter expires, the
+                * port has failed initialization: go to recover steps. If PO=1
+                * and the desired port width is 1x, go to normal steps. If
+                * PO = 1 and the desired port width is 4x, go to recover steps.
+                */
+               end_tick = usec2ticks(2000) + get_ticks();
+               do {
+                       if (in_be32((void *)&srio_regs->lp_serial
+                               .port[port].pescsr) & 0x2) {
+                               if (conf_lane == 0x1)
+                                       goto host_ok;
+                               else {
+                                       if (init_lane == 0x2)
+                                               goto host_ok;
+                                       else
+                                               break;
+                               }
+                       }
+               } while (end_tick > get_ticks());
+
+               /* recover at most 3 times */
+               for (i = 0; i < 3; i++) {
+                       /* Set SRIO PnCCSR[PD]=1 */
+                       setbits_be32((void *)&srio_regs->lp_serial
+                                       .port[port].pccsr,
+                                       0x800000);
+                       /*
+                       * Set SRIO PnPCR[OBDEN] on the host to
+                       * enable the discarding of any pending packets.
+                       */
+                       setbits_be32((void *)&srio_regs->impl.port[port].pcr,
+                               0x04);
+                       /* Wait 50 us */
+                       udelay(50);
+                       /* Run sync command */
+                       isync();
+
+                       if (port)
+                               first = serdes_get_first_lane(SRIO2);
+                       else
+                               first = serdes_get_first_lane(SRIO1);
+                       if (unlikely(first < 0))
+                               return -ENODEV;
+                       if (conf_lane == 0x1)
+                               last = first;
+                       else
+                               last = first + 3;
+                       /*
+                        * Set SERDES BnGCRm0[RRST]=0 for each SRIO
+                        * bank n and lane m.
+                        */
+                       for (idx = first; idx <= last; idx++)
+                               clrbits_be32(&srds_regs->lane[idx].gcr0,
+                               SRDS_GCR0_RRST);
+                       /*
+                        * Read SERDES BnGCRm0 for each SRIO
+                        * bank n and lane m
+                        */
+                       for (idx = first; idx <= last; idx++)
+                               in_be32(&srds_regs->lane[idx].gcr0);
+                       /* Run sync command */
+                       isync();
+                       /* Wait >= 100 ns */
+                       udelay(1);
+                       /*
+                        * Set SERDES BnGCRm0[RRST]=1 for each SRIO
+                        * bank n and lane m.
+                        */
+                       for (idx = first; idx <= last; idx++)
+                               setbits_be32(&srds_regs->lane[idx].gcr0,
+                               SRDS_GCR0_RRST);
+                       /*
+                        * Read SERDES BnGCRm0 for each SRIO
+                        * bank n and lane m
+                        */
+                       for (idx = first; idx <= last; idx++)
+                               in_be32(&srds_regs->lane[idx].gcr0);
+                       /* Run sync command */
+                       isync();
+                       /* Wait >= 300 ns */
+                       udelay(1);
+
+                       /* Write 1 to clear all bits in SRIO PnSLCSR */
+                       out_be32((void *)&srio_regs->impl.port[port].slcsr,
+                               0xffffffff);
+                       /* Clear SRIO PnPCR[OBDEN] on the host */
+                       clrbits_be32((void *)&srio_regs->impl.port[port].pcr,
+                               0x04);
+                       /* Set SRIO PnCCSR[PD]=0 */
+                       clrbits_be32((void *)&srio_regs->lp_serial
+                               .port[port].pccsr,
+                               0x800000);
+                       /* Wait >= 24 ms */
+                       udelay(24000);
+                       /* Poll the state of the port again */
+                       init_lane =
+                               (in_be32((void *)&srio_regs->lp_serial
+                                       .port[port].pccsr) >> 27) & 0x7;
+                       if (in_be32((void *)&srio_regs->lp_serial
+                               .port[port].pescsr) & 0x2) {
+                               if (conf_lane == 0x1)
+                                       goto host_ok;
+                               else {
+                                       if (init_lane == 0x2)
+                                               goto host_ok;
+                               }
+                       }
+                       if (i == 2)
+                               return -ENODEV;
+               }
+       } else
+               return -ENODEV;
+
+host_ok:
+       /* Poll PnESCSR[OES] on the host until it is clear */
+       end_tick = usec2ticks(1000000) + get_ticks();
+       do {
+               if (!(in_be32((void *)&srio_regs->lp_serial.port[port].pescsr)
+                       & 0x10000)) {
+                       out_be32(((void *)&srio_regs->lp_serial
+                               .port[port].pescsr), 0xffffffff);
+                       out_be32(((void *)&srio_regs->phys_err
+                               .port[port].edcsr), 0);
+                       out_be32(((void *)&srio_regs->logical_err.ltledcsr), 0);
+                       return 0;
+               }
+       } while (end_tick > get_ticks());
+
+       return -ENODEV;
+}
+#endif
+
 void srio_init(void)
 {
        ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
@@ -62,6 +242,11 @@ void srio_init(void)
                                law_size_bits(CONFIG_SYS_SRIO1_MEM_SIZE),
                                LAW_TRGT_IF_RIO_1);
                srio1_used = 1;
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+               if (srio_erratum_a004034(0) < 0)
+                       printf("SRIO1: enabled but port error\n");
+               else
+#endif
                printf("SRIO1: enabled\n");
        } else {
                printf("SRIO1: disabled\n");
@@ -73,7 +258,13 @@ void srio_init(void)
                                law_size_bits(CONFIG_SYS_SRIO2_MEM_SIZE),
                                LAW_TRGT_IF_RIO_2);
                srio2_used = 1;
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+               if (srio_erratum_a004034(1) < 0)
+                       printf("SRIO2: enabled but port error\n");
+               else
+#endif
                printf("SRIO2: enabled\n");
+
        } else {
                printf("SRIO2: disabled\n");
        }
index 39a3cdede0a92817676bd726ce83bde104e0aad8..0013ba85ee45a127c5d1d8aba7b52a7c63852290 100644 (file)
 #define CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV 0x10
 #define CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV2        0x11
 #define CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY 0xf0000000
+#define CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
 
 #elif defined(CONFIG_PPC_P3041)
 #define CONFIG_MAX_CPUS                        4
 #define CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV 0x10
 #define CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV2        0x11
 #define CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY 0xf0000000
+#define CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
 
 #elif defined(CONFIG_PPC_P4080) /* also supports P4040 */
 #define CONFIG_MAX_CPUS                        8
 #define CONFIG_SYS_FSL_ERRATUM_A004510
 #define CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV 0x20
 #define CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY 0xff000000
+#define CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
 
 #elif defined(CONFIG_PPC_P5020) /* also supports P5010 */
 #define CONFIG_MAX_CPUS                        2
 #define CONFIG_SYS_FSL_ERRATUM_A004510
 #define CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV 0x10
 #define CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY 0xc0000000
+#define CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
 
 #elif defined(CONFIG_BSC9131)
 #define CONFIG_MAX_CPUS                        1