diff options
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_pci.c')
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 253 |
1 files changed, 163 insertions, 90 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 156aa7d36258..862f11b3821e 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -265,7 +265,7 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, if (ppc4xx_setup_one_pci_PMM(hose, reg, res->start, res->start - hose->pci_mem_offset, - res->end + 1 - res->start, + resource_size(res), res->flags, j) == 0) { j++; @@ -290,7 +290,7 @@ static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, void __iomem *reg, const struct resource *res) { - resource_size_t size = res->end - res->start + 1; + resource_size_t size = resource_size(res); u32 sa; /* Calculate window size */ @@ -349,7 +349,7 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) bus_range = of_get_property(np, "bus-range", NULL); /* Map registers */ - reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start); + reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg)); if (reg == NULL) { printk(KERN_ERR "%s: Can't map registers !", np->full_name); goto fail; @@ -465,7 +465,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, if (ppc4xx_setup_one_pcix_POM(hose, reg, res->start, res->start - hose->pci_mem_offset, - res->end + 1 - res->start, + resource_size(res), res->flags, j) == 0) { j++; @@ -492,7 +492,7 @@ static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, int big_pim, int enable_msi_hole) { - resource_size_t size = res->end - res->start + 1; + resource_size_t size = resource_size(res); u32 sa; /* RAM is always at 0 */ @@ -555,7 +555,7 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np) bus_range = of_get_property(np, "bus-range", NULL); /* Map registers */ - reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start); + reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg)); if (reg == NULL) { printk(KERN_ERR "%s: Can't map registers !", np->full_name); goto fail; @@ -650,10 +650,73 @@ struct ppc4xx_pciex_hwops int (*core_init)(struct device_node *np); int (*port_init_hw)(struct ppc4xx_pciex_port *port); int (*setup_utl)(struct ppc4xx_pciex_port *port); + void (*check_link)(struct ppc4xx_pciex_port *port); }; static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; +static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, + unsigned int sdr_offset, + unsigned int mask, + unsigned int value, + int timeout_ms) +{ + u32 val; + + while(timeout_ms--) { + val = mfdcri(SDR0, port->sdr_base + sdr_offset); + if ((val & mask) == value) { + pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", + port->index, sdr_offset, timeout_ms, val); + return 0; + } + msleep(1); + } + return -1; +} + +static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port) +{ + /* Wait for reset to complete */ + if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { + printk(KERN_WARNING "PCIE%d: PGRST failed\n", + port->index); + return -1; + } + return 0; +} + + +static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port) +{ + printk(KERN_INFO "PCIE%d: Checking link...\n", port->index); + + /* Check for card presence detect if supported, if not, just wait for + * link unconditionally. + * + * note that we don't fail if there is no link, we just filter out + * config space accesses. That way, it will be easier to implement + * hotplug later on. + */ + if (!port->has_ibpre || + !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, + 1 << 28, 1 << 28, 100)) { + printk(KERN_INFO + "PCIE%d: Device detected, waiting for link...\n", + port->index); + if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, + 0x1000, 0x1000, 2000)) + printk(KERN_WARNING + "PCIE%d: Link up failed\n", port->index); + else { + printk(KERN_INFO + "PCIE%d: link is up !\n", port->index); + port->link = 1; + } + } else + printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); +} + #ifdef CONFIG_44x /* Check various reset bits of the 440SPe PCIe core */ @@ -771,7 +834,7 @@ static int __init ppc440spe_pciex_core_init(struct device_node *np) return 3; } -static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val = 1 << 24; @@ -806,15 +869,15 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, (1 << 24) | (1 << 16), 1 << 12); - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } -static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { return ppc440spe_pciex_init_port_hw(port); } -static int ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { int rc = ppc440spe_pciex_init_port_hw(port); @@ -856,6 +919,7 @@ static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata = .core_init = ppc440spe_pciex_core_init, .port_init_hw = ppc440speA_pciex_init_port_hw, .setup_utl = ppc440speA_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = @@ -863,6 +927,7 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = .core_init = ppc440spe_pciex_core_init, .port_init_hw = ppc440speB_pciex_init_port_hw, .setup_utl = ppc440speB_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; static int __init ppc460ex_pciex_core_init(struct device_node *np) @@ -871,7 +936,7 @@ static int __init ppc460ex_pciex_core_init(struct device_node *np) return 2; } -static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val; u32 utlset1; @@ -944,7 +1009,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) port->has_ibpre = 1; - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port) @@ -972,6 +1037,7 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = .core_init = ppc460ex_pciex_core_init, .port_init_hw = ppc460ex_pciex_init_port_hw, .setup_utl = ppc460ex_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; static int __init ppc460sx_pciex_core_init(struct device_node *np) @@ -1026,6 +1092,10 @@ static int __init ppc460sx_pciex_core_init(struct device_node *np) mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000); mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000); + /* Set HSS PRBS enabled */ + mtdcri(SDR0, PESDR0_460SX_HSSCTLSET, 0x00001130); + mtdcri(SDR0, PESDR2_460SX_HSSCTLSET, 0x00001130); + udelay(100); /* De-assert PLLRESET */ @@ -1056,7 +1126,7 @@ static int __init ppc460sx_pciex_core_init(struct device_node *np) return 2; } -static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { if (port->endpoint) @@ -1066,29 +1136,55 @@ static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2, 0, 0x01000000); - /*Gen-1*/ - mtdcri(SDR0, port->sdr_base + PESDRn_460SX_RCEI, 0x08000000); - dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL), PESDRx_RCSSET_RSTPYN); port->has_ibpre = 1; - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) { /* Max 128 Bytes */ out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000); + /* Assert VRB and TXE - per datasheet turn off addr validation */ + out_be32(port->utl_base + PEUTL_PCTL, 0x80800000); return 0; } +static void __init ppc460sx_pciex_check_link(struct ppc4xx_pciex_port *port) +{ + void __iomem *mbase; + int attempt = 50; + + port->link = 0; + + mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); + if (mbase == NULL) { + printk(KERN_ERR "%s: Can't map internal config space !", + port->node->full_name); + goto done; + } + + while (attempt && (0 == (in_le32(mbase + PECFG_460SX_DLLSTA) + & PECFG_460SX_DLLSTA_LINKUP))) { + attempt--; + mdelay(10); + } + if (attempt) + port->link = 1; +done: + iounmap(mbase); + +} + static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { .core_init = ppc460sx_pciex_core_init, .port_init_hw = ppc460sx_pciex_init_port_hw, .setup_utl = ppc460sx_pciex_init_utl, + .check_link = ppc460sx_pciex_check_link, }; #endif /* CONFIG_44x */ @@ -1122,7 +1218,7 @@ static void ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port) mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000); } -static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val; @@ -1154,7 +1250,7 @@ static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) port->has_ibpre = 1; - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) @@ -1183,11 +1279,11 @@ static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata = .core_init = ppc405ex_pciex_core_init, .port_init_hw = ppc405ex_pciex_init_port_hw, .setup_utl = ppc405ex_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; #endif /* CONFIG_40x */ - /* Check that the core has been initied and if not, do it */ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) { @@ -1261,26 +1357,6 @@ static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); } -static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, - unsigned int sdr_offset, - unsigned int mask, - unsigned int value, - int timeout_ms) -{ - u32 val; - - while(timeout_ms--) { - val = mfdcri(SDR0, port->sdr_base + sdr_offset); - if ((val & mask) == value) { - pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", - port->index, sdr_offset, timeout_ms, val); - return 0; - } - msleep(1); - } - return -1; -} - static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) { int rc = 0; @@ -1291,47 +1367,15 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) if (rc != 0) return rc; - printk(KERN_INFO "PCIE%d: Checking link...\n", - port->index); - - /* Wait for reset to complete */ - if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { - printk(KERN_WARNING "PCIE%d: PGRST failed\n", - port->index); - return -1; - } - - /* Check for card presence detect if supported, if not, just wait for - * link unconditionally. - * - * note that we don't fail if there is no link, we just filter out - * config space accesses. That way, it will be easier to implement - * hotplug later on. - */ - if (!port->has_ibpre || - !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, - 1 << 28, 1 << 28, 100)) { - printk(KERN_INFO - "PCIE%d: Device detected, waiting for link...\n", - port->index); - if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, - 0x1000, 0x1000, 2000)) - printk(KERN_WARNING - "PCIE%d: Link up failed\n", port->index); - else { - printk(KERN_INFO - "PCIE%d: link is up !\n", port->index); - port->link = 1; - } - } else - printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); - /* * Initialize mapping: disable all regions and configure * CFG and REG regions based on resources in the device tree */ ppc4xx_pciex_port_init_mapping(port); + if (ppc4xx_pciex_hwops->check_link) + ppc4xx_pciex_hwops->check_link(port); + /* * Map UTL */ @@ -1345,16 +1389,29 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) ppc4xx_pciex_hwops->setup_utl(port); /* - * Check for VC0 active and assert RDY. + * Check for VC0 active or PLL Locked and assert RDY. */ - if (port->link && - ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, - 1 << 16, 1 << 16, 5000)) { - printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); - port->link = 0; + if (port->sdr_base) { + if (of_device_is_compatible(port->node, + "ibm,plb-pciex-460sx")){ + if (port->link && ppc4xx_pciex_wait_on_sdr(port, + PESDRn_RCSSTS, + 1 << 12, 1 << 12, 5000)) { + printk(KERN_INFO "PCIE%d: PLL not locked\n", + port->index); + port->link = 0; + } + } else if (port->link && + ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, + 1 << 16, 1 << 16, 5000)) { + printk(KERN_INFO "PCIE%d: VC0 not active\n", + port->index); + port->link = 0; + } + + dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); } - dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); msleep(100); return 0; @@ -1555,8 +1612,15 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); - /* Note that 3 here means enabled | single region */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); + /*Enabled and single region */ + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, + sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT + | DCRO_PEGPL_OMRxMSKL_VAL); + else + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, + sa | DCRO_PEGPL_OMR1MSKL_UOT + | DCRO_PEGPL_OMRxMSKL_VAL); break; case 1: out_le32(mbase + PECFG_POM1LAH, pciah); @@ -1564,8 +1628,8 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); - /* Note that 3 here means enabled | single region */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, + sa | DCRO_PEGPL_OMRxMSKL_VAL); break; case 2: out_le32(mbase + PECFG_POM2LAH, pciah); @@ -1574,7 +1638,9 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); /* Note that 3 here means enabled | IO space !!! */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, + sa | DCRO_PEGPL_OMR3MSKL_IO + | DCRO_PEGPL_OMRxMSKL_VAL); break; } @@ -1604,7 +1670,7 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, res->start, res->start - hose->pci_mem_offset, - res->end + 1 - res->start, + resource_size(res), res->flags, j) == 0) { j++; @@ -1639,7 +1705,7 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, void __iomem *mbase, struct resource *res) { - resource_size_t size = res->end - res->start + 1; + resource_size_t size = resource_size(res); u64 sa; if (port->endpoint) { @@ -1675,6 +1741,9 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, if (res->flags & IORESOURCE_PREFETCH) sa |= 0x8; + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + sa |= PCI_BASE_ADDRESS_MEM_TYPE_64; + out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); @@ -1836,6 +1905,10 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) } out_le16(mbase + 0x202, val); + /* Enable Bus master, memory, and io space */ + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + out_le16(mbase + 0x204, 0x7); + if (!port->endpoint) { /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ out_le32(mbase + 0x208, 0x06040001); @@ -1960,7 +2033,7 @@ static int __init ppc4xx_pci_find_bridges(void) { struct device_node *np; - ppc_pci_flags |= PPC_PCI_ENABLE_PROC_DOMAINS | PPC_PCI_COMPAT_DOMAIN_0; + pci_add_flags(PCI_ENABLE_PROC_DOMAINS | PCI_COMPAT_DOMAIN_0); #ifdef CONFIG_PPC4xx_PCI_EXPRESS for_each_compatible_node(np, NULL, "ibm,plb-pciex") |