|
@@ -650,12 +650,74 @@ 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;
|
|
|
|
|
|
#ifdef CONFIG_44x
|
|
|
|
|
|
+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);
|
|
|
+}
|
|
|
+
|
|
|
/* Check various reset bits of the 440SPe PCIe core */
|
|
|
static int __init ppc440spe_pciex_check_reset(struct device_node *np)
|
|
|
{
|
|
@@ -806,7 +868,7 @@ 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)
|
|
@@ -856,6 +918,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 +926,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)
|
|
@@ -944,7 +1008,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 +1036,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)
|
|
@@ -1075,7 +1140,7 @@ static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
|
|
|
|
|
|
port->has_ibpre = 1;
|
|
|
|
|
|
- return 0;
|
|
|
+ return ppc4xx_pciex_port_reset_sdr(port);
|
|
|
}
|
|
|
|
|
|
static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port)
|
|
@@ -1089,6 +1154,7 @@ 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 = ppc4xx_pciex_check_link_sdr,
|
|
|
};
|
|
|
|
|
|
#endif /* CONFIG_44x */
|
|
@@ -1154,7 +1220,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 +1249,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 +1327,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,40 +1337,8 @@ 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);
|
|
|
+ if (ppc4xx_pciex_hwops->check_link)
|
|
|
+ ppc4xx_pciex_hwops->check_link(port);
|
|
|
|
|
|
/*
|
|
|
* Initialize mapping: disable all regions and configure
|
|
@@ -1347,14 +1361,17 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
|
|
|
/*
|
|
|
* Check for VC0 active 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 (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;
|