aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/drivers/pci/pcie-sh7786.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-09-20 15:39:54 +0900
committerPaul Mundt <lethal@linux-sh.org>2010-09-20 15:39:54 +0900
commit2c65d75ec4dde5e619a462e70cdd7b67e0e64bb8 (patch)
tree92bf4545d694888073a39c963b1d4f278785642c /arch/sh/drivers/pci/pcie-sh7786.c
parentsh: pci: Move Renesas PCI IDs to a better place. (diff)
downloadlinux-dev-2c65d75ec4dde5e619a462e70cdd7b67e0e64bb8.tar.xz
linux-dev-2c65d75ec4dde5e619a462e70cdd7b67e0e64bb8.zip
sh: pci: Support root complex config accesses on SH7786 PCIe.
The SH7786 PCIe is presently unable to enumerate itself in root complex mode, and has no visibility through either type 0 or type 1 accesses, despite having a mostly sensible extended config space for each port. Attempts to generate type 0 or type 1 config cycles result in completer aborts, so we're ultimately forced to use SuperHyway transactions instead. As each port has a single port <-> device mapping that resolves for any PCI_SLOT definition, we simply hijack devfn 0 for the SuperHyway transaction and bump up the devfn limit. With enumeration of the root complex now possible, we also need to insert an early fixup to hide the BARs from the kernel. With all of that done, it's now possible to use the pcieport services with all of the PCIe ports, which is the first step to power management support. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to '')
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index 4e6cf8804979..3dfc250b897a 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -121,6 +121,24 @@ static struct pci_channel sh7786_pci_channels[] = {
DEFINE_CONTROLLER(0xfcc00000, 2),
};
+static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
+{
+ /*
+ * Prevent enumeration of root complex resources.
+ */
+ if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
+ int i;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ dev->resource[i].flags = 0;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
+ sh7786_pci_fixup);
+
static int phy_wait_for_ack(struct pci_channel *chan)
{
unsigned int timeout = 100;
@@ -229,11 +247,12 @@ static int pcie_init(struct sh7786_pcie_port *port)
/* Begin initialization */
pcie_reset(port);
- /* Initialize as type1. */
- data = pci_read_reg(chan, SH4A_PCIEPCICONF3);
- data &= ~(0x7f << 16);
- data |= PCI_HEADER_TYPE_BRIDGE << 16;
- pci_write_reg(chan, data, SH4A_PCIEPCICONF3);
+ /*
+ * Initial header for port config space is type 1, set the device
+ * class to match. Hardware takes care of propagating the IDSETR
+ * settings, so there is no need to bother with a quirk.
+ */
+ pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1);
/* Initialize default capabilities. */
data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);