summaryrefslogtreecommitdiff
path: root/arch/powerpc/sysdev/ppc4xx_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_pci.c')
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c253
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")