aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb/driver_pcicore.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ssb/driver_pcicore.c')
-rw-r--r--drivers/ssb/driver_pcicore.c160
1 files changed, 89 insertions, 71 deletions
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 74b9a8aea52b..33a7d5620474 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -60,77 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock);
60/* Core to access the external PCI config space. Can only have one. */ 60/* Core to access the external PCI config space. Can only have one. */
61static struct ssb_pcicore *extpci_core; 61static struct ssb_pcicore *extpci_core;
62 62
63static u32 ssb_pcicore_pcibus_iobase = 0x100;
64static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
65
66int pcibios_plat_dev_init(struct pci_dev *d)
67{
68 struct resource *res;
69 int pos, size;
70 u32 *base;
71
72 ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
73 pci_name(d));
74
75 /* Fix up resource bases */
76 for (pos = 0; pos < 6; pos++) {
77 res = &d->resource[pos];
78 if (res->flags & IORESOURCE_IO)
79 base = &ssb_pcicore_pcibus_iobase;
80 else
81 base = &ssb_pcicore_pcibus_membase;
82 res->flags |= IORESOURCE_PCI_FIXED;
83 if (res->end) {
84 size = res->end - res->start + 1;
85 if (*base & (size - 1))
86 *base = (*base + size) & ~(size - 1);
87 res->start = *base;
88 res->end = res->start + size - 1;
89 *base += size;
90 pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
91 }
92 /* Fix up PCI bridge BAR0 only */
93 if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
94 break;
95 }
96 /* Fix up interrupt lines */
97 d->irq = ssb_mips_irq(extpci_core->dev) + 2;
98 pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
99
100 return 0;
101}
102
103static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
104{
105 u8 lat;
106
107 if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
108 return;
109
110 ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
111
112 /* Enable PCI bridge bus mastering and memory space */
113 pci_set_master(dev);
114 if (pcibios_enable_device(dev, ~0) < 0) {
115 ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
116 return;
117 }
118
119 /* Enable PCI bridge BAR1 prefetch and burst */
120 pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
121
122 /* Make sure our latency is high enough to handle the devices behind us */
123 lat = 168;
124 ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
125 pci_name(dev), lat);
126 pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
127}
128DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
129
130int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
131{
132 return ssb_mips_irq(extpci_core->dev) + 2;
133}
134 63
135static u32 get_cfgspace_addr(struct ssb_pcicore *pc, 64static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
136 unsigned int bus, unsigned int dev, 65 unsigned int bus, unsigned int dev,
@@ -320,6 +249,95 @@ static struct pci_controller ssb_pcicore_controller = {
320 .mem_offset = 0x24000000, 249 .mem_offset = 0x24000000,
321}; 250};
322 251
252static u32 ssb_pcicore_pcibus_iobase = 0x100;
253static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
254
255/* This function is called when doing a pci_enable_device().
256 * We must first check if the device is a device on the PCI-core bridge. */
257int ssb_pcicore_plat_dev_init(struct pci_dev *d)
258{
259 struct resource *res;
260 int pos, size;
261 u32 *base;
262
263 if (d->bus->ops != &ssb_pcicore_pciops) {
264 /* This is not a device on the PCI-core bridge. */
265 return -ENODEV;
266 }
267
268 ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
269 pci_name(d));
270
271 /* Fix up resource bases */
272 for (pos = 0; pos < 6; pos++) {
273 res = &d->resource[pos];
274 if (res->flags & IORESOURCE_IO)
275 base = &ssb_pcicore_pcibus_iobase;
276 else
277 base = &ssb_pcicore_pcibus_membase;
278 res->flags |= IORESOURCE_PCI_FIXED;
279 if (res->end) {
280 size = res->end - res->start + 1;
281 if (*base & (size - 1))
282 *base = (*base + size) & ~(size - 1);
283 res->start = *base;
284 res->end = res->start + size - 1;
285 *base += size;
286 pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
287 }
288 /* Fix up PCI bridge BAR0 only */
289 if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
290 break;
291 }
292 /* Fix up interrupt lines */
293 d->irq = ssb_mips_irq(extpci_core->dev) + 2;
294 pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
295
296 return 0;
297}
298
299/* Early PCI fixup for a device on the PCI-core bridge. */
300static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)
301{
302 u8 lat;
303
304 if (dev->bus->ops != &ssb_pcicore_pciops) {
305 /* This is not a device on the PCI-core bridge. */
306 return;
307 }
308 if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
309 return;
310
311 ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
312
313 /* Enable PCI bridge bus mastering and memory space */
314 pci_set_master(dev);
315 if (pcibios_enable_device(dev, ~0) < 0) {
316 ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
317 return;
318 }
319
320 /* Enable PCI bridge BAR1 prefetch and burst */
321 pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
322
323 /* Make sure our latency is high enough to handle the devices behind us */
324 lat = 168;
325 ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
326 pci_name(dev), lat);
327 pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
328}
329DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge);
330
331/* PCI device IRQ mapping. */
332int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
333{
334 if (dev->bus->ops != &ssb_pcicore_pciops) {
335 /* This is not a device on the PCI-core bridge. */
336 return -ENODEV;
337 }
338 return ssb_mips_irq(extpci_core->dev) + 2;
339}
340
323static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) 341static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
324{ 342{
325 u32 val; 343 u32 val;