diff options
-rw-r--r-- | arch/sh/drivers/pci/ops-sh7786.c | 35 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pcie-sh7786.c | 29 |
2 files changed, 55 insertions, 9 deletions
diff --git a/arch/sh/drivers/pci/ops-sh7786.c b/arch/sh/drivers/pci/ops-sh7786.c index 4728199f71a6..01cb70fbd803 100644 --- a/arch/sh/drivers/pci/ops-sh7786.c +++ b/arch/sh/drivers/pci/ops-sh7786.c | |||
@@ -25,23 +25,49 @@ static int sh7786_pcie_config_access(unsigned char access_type, | |||
25 | struct pci_bus *bus, unsigned int devfn, int where, u32 *data) | 25 | struct pci_bus *bus, unsigned int devfn, int where, u32 *data) |
26 | { | 26 | { |
27 | struct pci_channel *chan = bus->sysdata; | 27 | struct pci_channel *chan = bus->sysdata; |
28 | int dev, func, type; | 28 | int dev, func, type, reg; |
29 | 29 | ||
30 | dev = PCI_SLOT(devfn); | 30 | dev = PCI_SLOT(devfn); |
31 | func = PCI_FUNC(devfn); | 31 | func = PCI_FUNC(devfn); |
32 | type = !!bus->parent; | 32 | type = !!bus->parent; |
33 | reg = where & ~3; | ||
33 | 34 | ||
34 | if (bus->number > 255 || dev > 31 || func > 7) | 35 | if (bus->number > 255 || dev > 31 || func > 7) |
35 | return PCIBIOS_FUNC_NOT_SUPPORTED; | 36 | return PCIBIOS_FUNC_NOT_SUPPORTED; |
36 | if (bus->parent == NULL && dev) | 37 | |
37 | return PCIBIOS_DEVICE_NOT_FOUND; | 38 | /* |
39 | * While each channel has its own memory-mapped extended config | ||
40 | * space, it's generally only accessible when in endpoint mode. | ||
41 | * When in root complex mode, the controller is unable to target | ||
42 | * itself with either type 0 or type 1 accesses, and indeed, any | ||
43 | * controller initiated target transfer to its own config space | ||
44 | * result in a completer abort. | ||
45 | * | ||
46 | * Each channel effectively only supports a single device, but as | ||
47 | * the same channel <-> device access works for any PCI_SLOT() | ||
48 | * value, we cheat a bit here and bind the controller's config | ||
49 | * space to devfn 0 in order to enable self-enumeration. In this | ||
50 | * case the regular PAR/PDR path is sidelined and the mangled | ||
51 | * config access itself is initiated as a SuperHyway transaction. | ||
52 | */ | ||
53 | if (pci_is_root_bus(bus)) { | ||
54 | if (dev == 0) { | ||
55 | if (access_type == PCI_ACCESS_READ) | ||
56 | *data = pci_read_reg(chan, PCI_REG(reg)); | ||
57 | else | ||
58 | pci_write_reg(chan, *data, PCI_REG(reg)); | ||
59 | |||
60 | return PCIBIOS_SUCCESSFUL; | ||
61 | } else if (dev > 1) | ||
62 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
63 | } | ||
38 | 64 | ||
39 | /* Clear errors */ | 65 | /* Clear errors */ |
40 | pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR); | 66 | pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR); |
41 | 67 | ||
42 | /* Set the PIO address */ | 68 | /* Set the PIO address */ |
43 | pci_write_reg(chan, (bus->number << 24) | (dev << 19) | | 69 | pci_write_reg(chan, (bus->number << 24) | (dev << 19) | |
44 | (func << 16) | (where & ~3), SH4A_PCIEPAR); | 70 | (func << 16) | reg, SH4A_PCIEPAR); |
45 | 71 | ||
46 | /* Enable the configuration access */ | 72 | /* Enable the configuration access */ |
47 | pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR); | 73 | pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR); |
@@ -49,6 +75,7 @@ static int sh7786_pcie_config_access(unsigned char access_type, | |||
49 | /* Check for errors */ | 75 | /* Check for errors */ |
50 | if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10) | 76 | if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10) |
51 | return PCIBIOS_DEVICE_NOT_FOUND; | 77 | return PCIBIOS_DEVICE_NOT_FOUND; |
78 | |||
52 | /* Check for master and target aborts */ | 79 | /* Check for master and target aborts */ |
53 | if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28))) | 80 | if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28))) |
54 | return PCIBIOS_DEVICE_NOT_FOUND; | 81 | return PCIBIOS_DEVICE_NOT_FOUND; |
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 | ||
124 | static 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 | } | ||
139 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786, | ||
140 | sh7786_pci_fixup); | ||
141 | |||
124 | static int phy_wait_for_ack(struct pci_channel *chan) | 142 | static 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); |