+ SDR_WRITE(PESDR2_RCSSET,
+ (SDR_READ(PESDR2_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12);
+ break;
+ }
+ /*
+ * Notice: the following delay has critical impact on device
+ * initialization - if too short (<50ms) the link doesn't get up.
+ */
+ mdelay(100);
+
+ switch (port) {
+ case 0:
+ val = SDR_READ(PESDR0_RCSSTS);
+ break;
+ case 1:
+ val = SDR_READ(PESDR1_RCSSTS);
+ break;
+ case 2:
+ val = SDR_READ(PESDR2_RCSSTS);
+ break;
+ }
+
+ if (val & (1 << 20)) {
+ printf("PCIE%d: PGRST failed %08x\n", port, val);
+ return -1;
+ }
+
+ /*
+ * Verify link is up
+ */
+ val = 0;
+ switch (port) {
+ case 0:
+ val = SDR_READ(PESDR0_LOOP);
+ break;
+ case 1:
+ val = SDR_READ(PESDR1_LOOP);
+ break;
+ case 2:
+ val = SDR_READ(PESDR2_LOOP);
+ break;
+ }
+ if (!(val & 0x00001000)) {
+ printf("PCIE%d: link is not up.\n", port);
+ return -1;
+ }
+
+ /*
+ * Setup UTL registers - but only on revA!
+ * We use default settings for revB chip.
+ */
+ if (!ppc440spe_revB())
+ ppc440spe_setup_utl(port);
+
+ /*
+ * We map PCI Express configuration access into the 512MB regions
+ *
+ * NOTICE: revB is very strict about PLB real addressess and ranges to
+ * be mapped for config space; it seems to only work with d_nnnn_nnnn
+ * range (hangs the core upon config transaction attempts when set
+ * otherwise) while revA uses c_nnnn_nnnn.
+ *
+ * For revA:
+ * PCIE0: 0xc_4000_0000
+ * PCIE1: 0xc_8000_0000
+ * PCIE2: 0xc_c000_0000
+ *
+ * For revB:
+ * PCIE0: 0xd_0000_0000
+ * PCIE1: 0xd_2000_0000
+ * PCIE2: 0xd_4000_0000
+ */
+
+ switch (port) {
+ case 0:
+ if (ppc440spe_revB()) {
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000d);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x00000000);
+ } else {
+ /* revA */
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000);
+ }
+ mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */
+ break;
+
+ case 1:
+ if (ppc440spe_revB()) {
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000d);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x20000000);
+ } else {
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000);
+ }
+ mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */
+ break;
+
+ case 2:
+ if (ppc440spe_revB()) {
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000d);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0x40000000);
+ } else {
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000);
+ }
+ mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */
+ break;
+ }
+
+ /*
+ * Check for VC0 active and assert RDY.
+ */
+ attempts = 10;
+ switch (port) {
+ case 0:
+ while(!(SDR_READ(PESDR0_RCSSTS) & (1 << 16))) {
+ if (!(attempts--)) {
+ printf("PCIE0: VC0 not active\n");
+ return -1;
+ }
+ mdelay(1000);
+ }
+ SDR_WRITE(PESDR0_RCSSET, SDR_READ(PESDR0_RCSSET) | 1 << 20);
+ break;
+ case 1:
+ while(!(SDR_READ(PESDR1_RCSSTS) & (1 << 16))) {
+ if (!(attempts--)) {
+ printf("PCIE1: VC0 not active\n");
+ return -1;
+ }
+ mdelay(1000);
+ }
+
+ SDR_WRITE(PESDR1_RCSSET, SDR_READ(PESDR1_RCSSET) | 1 << 20);
+ break;
+ case 2:
+ while(!(SDR_READ(PESDR2_RCSSTS) & (1 << 16))) {
+ if (!(attempts--)) {
+ printf("PCIE2: VC0 not active\n");
+ return -1;
+ }
+ mdelay(1000);
+ }
+
+ SDR_WRITE(PESDR2_RCSSET, SDR_READ(PESDR2_RCSSET) | 1 << 20);
+ break;
+ }
+ mdelay(100);
+
+ return 0;
+}
+
+int ppc440spe_init_pcie_endport(int port)
+{
+ static int core_init;
+ volatile u32 val = 0;
+ int attempts;
+
+ if (!core_init) {
+ ++core_init;
+ if (ppc440spe_init_pcie())
+ return -1;
+ }
+
+ /*
+ * Initialize various parts of the PCI Express core for our port:
+ *
+ * - Set as a end port and enable max width
+ * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4).
+ * - Set up UTL configuration.
+ * - Increase SERDES drive strength to levels suggested by AMCC.
+ * - De-assert RSTPYN, RSTDL and RSTGU.
+ *
+ * NOTICE for revB chip: PESDRn_UTLSET2 is not set - we leave it with
+ * default setting 0x11310000. The register has new fields,
+ * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core
+ * hang.
+ */
+ switch (port) {
+ case 0:
+ SDR_WRITE(PESDR0_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X8 << 12);
+
+ SDR_WRITE(PESDR0_UTLSET1, 0x20222222);
+ if (!ppc440spe_revB())
+ SDR_WRITE(PESDR0_UTLSET2, 0x11000000);
+ SDR_WRITE(PESDR0_HSSL0SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL1SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL2SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL3SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000);
+ SDR_WRITE(PESDR0_RCSSET,
+ (SDR_READ(PESDR0_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12);
+ break;
+
+ case 1:
+ SDR_WRITE(PESDR1_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X4 << 12);
+ SDR_WRITE(PESDR1_UTLSET1, 0x20222222);
+ if (!ppc440spe_revB())
+ SDR_WRITE(PESDR1_UTLSET2, 0x11000000);
+ SDR_WRITE(PESDR1_HSSL0SET1, 0x35000000);
+ SDR_WRITE(PESDR1_HSSL1SET1, 0x35000000);
+ SDR_WRITE(PESDR1_HSSL2SET1, 0x35000000);
+ SDR_WRITE(PESDR1_HSSL3SET1, 0x35000000);
+ SDR_WRITE(PESDR1_RCSSET,
+ (SDR_READ(PESDR1_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12);
+ break;
+
+ case 2:
+ SDR_WRITE(PESDR2_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X4 << 12);
+ SDR_WRITE(PESDR2_UTLSET1, 0x20222222);
+ if (!ppc440spe_revB())
+ SDR_WRITE(PESDR2_UTLSET2, 0x11000000);
+ SDR_WRITE(PESDR2_HSSL0SET1, 0x35000000);
+ SDR_WRITE(PESDR2_HSSL1SET1, 0x35000000);
+ SDR_WRITE(PESDR2_HSSL2SET1, 0x35000000);
+ SDR_WRITE(PESDR2_HSSL3SET1, 0x35000000);