X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=arch%2Fpowerpc%2Fcpu%2Fmpc8xxx%2Fsrio.c;h=6e6f7dcc3fd927a96383b6b457620f82d1d49296;hp=e46d328067df71ae3b4e100d2656f707e30fae10;hb=c68436fa427a69ea308d74c410067507d6c7103b;hpb=a09b9b68d492e978ef0e14cae93ff9cfbc2d3e4b diff --git a/arch/powerpc/cpu/mpc8xxx/srio.c b/arch/powerpc/cpu/mpc8xxx/srio.c index e46d328067..6e6f7dcc3f 100644 --- a/arch/powerpc/cpu/mpc8xxx/srio.c +++ b/arch/powerpc/cpu/mpc8xxx/srio.c @@ -21,10 +21,28 @@ #include #include #include +#include +#include + +#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#define SRIO_PORT_ACCEPT_ALL 0x10000001 +#define SRIO_IB_ATMU_AR 0x80f55000 +#define SRIO_OB_ATMU_AR_MAINT 0x80077000 +#define SRIO_OB_ATMU_AR_RW 0x80045000 +#define SRIO_LCSBA1CSR_OFFSET 0x5c +#define SRIO_MAINT_WIN_SIZE 0x1000000 /* 16M */ +#define SRIO_RW_WIN_SIZE 0x100000 /* 1M */ +#define SRIO_LCSBA1CSR 0x60000000 +#endif #if defined(CONFIG_FSL_CORENET) +#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2 + #define _DEVDISR_SRIO1 FSL_CORENET_DEVDISR3_SRIO1 + #define _DEVDISR_SRIO2 FSL_CORENET_DEVDISR3_SRIO2 +#else #define _DEVDISR_SRIO1 FSL_CORENET_DEVDISR_SRIO1 #define _DEVDISR_SRIO2 FSL_CORENET_DEVDISR_SRIO2 +#endif #define _DEVDISR_RMU FSL_CORENET_DEVDISR_RMU #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR #elif defined(CONFIG_MPC85xx) @@ -42,16 +60,206 @@ #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; int srio1_used = 0, srio2_used = 0; + u32 *devdisr; +#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2 + devdisr = &gur->devdisr3; +#else + devdisr = &gur->devdisr; +#endif if (is_serdes_configured(SRIO1)) { set_next_law(CONFIG_SYS_SRIO1_MEM_PHYS, 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"); @@ -63,7 +271,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"); } @@ -72,15 +286,174 @@ void srio_init(void) #ifdef CONFIG_FSL_CORENET /* On FSL_CORENET devices we can disable individual ports */ if (!srio1_used) - setbits_be32(&gur->devdisr, FSL_CORENET_DEVDISR_SRIO1); + setbits_be32(devdisr, _DEVDISR_SRIO1); if (!srio2_used) - setbits_be32(&gur->devdisr, FSL_CORENET_DEVDISR_SRIO2); + setbits_be32(devdisr, _DEVDISR_SRIO2); #endif /* neither port is used - disable everything */ if (!srio1_used && !srio2_used) { - setbits_be32(&gur->devdisr, _DEVDISR_SRIO1); - setbits_be32(&gur->devdisr, _DEVDISR_SRIO2); - setbits_be32(&gur->devdisr, _DEVDISR_RMU); + setbits_be32(devdisr, _DEVDISR_SRIO1); + setbits_be32(devdisr, _DEVDISR_SRIO2); + setbits_be32(devdisr, _DEVDISR_RMU); } } + +#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +void srio_boot_master(int port) +{ + struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR; + + /* set port accept-all */ + out_be32((void *)&srio->impl.port[port - 1].ptaacr, + SRIO_PORT_ACCEPT_ALL); + + debug("SRIOBOOT - MASTER: Master port [ %d ] for srio boot.\n", port); + /* configure inbound window for slave's u-boot image */ + debug("SRIOBOOT - MASTER: Inbound window for slave's image; " + "Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n", + (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS, + (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1, + CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE); + out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwtar, + CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS >> 12); + out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwbar, + CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1 >> 12); + out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwar, + SRIO_IB_ATMU_AR + | atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE)); + + /* configure inbound window for slave's u-boot image */ + debug("SRIOBOOT - MASTER: Inbound window for slave's image; " + "Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n", + (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS, + (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2, + CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE); + out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwtar, + CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS >> 12); + out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwbar, + CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2 >> 12); + out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwar, + SRIO_IB_ATMU_AR + | atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE)); + + /* configure inbound window for slave's ucode and ENV */ + debug("SRIOBOOT - MASTER: Inbound window for slave's ucode and ENV; " + "Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n", + (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS, + (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS, + CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE); + out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwtar, + CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS >> 12); + out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwbar, + CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS >> 12); + out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwar, + SRIO_IB_ATMU_AR + | atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE)); +} + +void srio_boot_master_release_slave(int port) +{ + struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR; + u32 escsr; + debug("SRIOBOOT - MASTER: " + "Check the port status and release slave core ...\n"); + + escsr = in_be32((void *)&srio->lp_serial.port[port - 1].pescsr); + if (escsr & 0x2) { + if (escsr & 0x10100) { + debug("SRIOBOOT - MASTER: Port [ %d ] is error.\n", + port); + } else { + debug("SRIOBOOT - MASTER: " + "Port [ %d ] is ready, now release slave's core ...\n", + port); + /* + * configure outbound window + * with maintenance attribute to set slave's LCSBA1CSR + */ + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[1].rowtar, 0); + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[1].rowtear, 0); + if (port - 1) + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[1].rowbar, + CONFIG_SYS_SRIO2_MEM_PHYS >> 12); + else + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[1].rowbar, + CONFIG_SYS_SRIO1_MEM_PHYS >> 12); + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[1].rowar, + SRIO_OB_ATMU_AR_MAINT + | atmu_size_mask(SRIO_MAINT_WIN_SIZE)); + + /* + * configure outbound window + * with R/W attribute to set slave's BRR + */ + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[2].rowtar, + SRIO_LCSBA1CSR >> 9); + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[2].rowtear, 0); + if (port - 1) + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[2].rowbar, + (CONFIG_SYS_SRIO2_MEM_PHYS + + SRIO_MAINT_WIN_SIZE) >> 12); + else + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[2].rowbar, + (CONFIG_SYS_SRIO1_MEM_PHYS + + SRIO_MAINT_WIN_SIZE) >> 12); + out_be32((void *)&srio->atmu.port[port - 1] + .outbw[2].rowar, + SRIO_OB_ATMU_AR_RW + | atmu_size_mask(SRIO_RW_WIN_SIZE)); + + /* + * Set the LCSBA1CSR register in slave + * by the maint-outbound window + */ + if (port - 1) { + out_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT + + SRIO_LCSBA1CSR_OFFSET, + SRIO_LCSBA1CSR); + while (in_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT + + SRIO_LCSBA1CSR_OFFSET) + != SRIO_LCSBA1CSR) + ; + /* + * And then set the BRR register + * to release slave core + */ + out_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT + + SRIO_MAINT_WIN_SIZE + + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET, + CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK); + } else { + out_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT + + SRIO_LCSBA1CSR_OFFSET, + SRIO_LCSBA1CSR); + while (in_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT + + SRIO_LCSBA1CSR_OFFSET) + != SRIO_LCSBA1CSR) + ; + /* + * And then set the BRR register + * to release slave core + */ + out_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT + + SRIO_MAINT_WIN_SIZE + + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET, + CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK); + } + debug("SRIOBOOT - MASTER: " + "Release slave successfully! Now the slave should start up!\n"); + } + } else + debug("SRIOBOOT - MASTER: Port [ %d ] is not ready.\n", port); +} +#endif