aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/drivers/pci/pcie-sh7786.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-09-20 02:39:54 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-09-20 02:39:54 -0400
commit2c65d75ec4dde5e619a462e70cdd7b67e0e64bb8 (patch)
tree92bf4545d694888073a39c963b1d4f278785642c /arch/sh/drivers/pci/pcie-sh7786.c
parentcabdf8bf488bfa3b565360b9fa1322d2db7747eb (diff)
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 'arch/sh/drivers/pci/pcie-sh7786.c')
-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[] = {
121 DEFINE_CONTROLLER(0xfcc00000, 2), 121 DEFINE_CONTROLLER(0xfcc00000, 2),
122}; 122};
123 123
124static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
125{
126 /*
127 * Prevent enumeration of root complex resources.
128 */
129 if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
130 int i;
131
132 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
133 dev->resource[i].start = 0;
134 dev->resource[i].end = 0;
135 dev->resource[i].flags = 0;
136 }
137 }
138}
139DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
140 sh7786_pci_fixup);
141
124static int phy_wait_for_ack(struct pci_channel *chan) 142static int phy_wait_for_ack(struct pci_channel *chan)
125{ 143{
126 unsigned int timeout = 100; 144 unsigned int timeout = 100;
@@ -229,11 +247,12 @@ static int pcie_init(struct sh7786_pcie_port *port)
229 /* Begin initialization */ 247 /* Begin initialization */
230 pcie_reset(port); 248 pcie_reset(port);
231 249
232 /* Initialize as type1. */ 250 /*
233 data = pci_read_reg(chan, SH4A_PCIEPCICONF3); 251 * Initial header for port config space is type 1, set the device
234 data &= ~(0x7f << 16); 252 * class to match. Hardware takes care of propagating the IDSETR
235 data |= PCI_HEADER_TYPE_BRIDGE << 16; 253 * settings, so there is no need to bother with a quirk.
236 pci_write_reg(chan, data, SH4A_PCIEPCICONF3); 254 */
255 pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1);
237 256
238 /* Initialize default capabilities. */ 257 /* Initialize default capabilities. */
239 data = pci_read_reg(chan, SH4A_PCIEEXPCAP0); 258 data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);