diff options
Diffstat (limited to 'drivers/ssb/driver_pcicore.c')
-rw-r--r-- | drivers/ssb/driver_pcicore.c | 160 |
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. */ |
61 | static struct ssb_pcicore *extpci_core; | 61 | static struct ssb_pcicore *extpci_core; |
62 | 62 | ||
63 | static u32 ssb_pcicore_pcibus_iobase = 0x100; | ||
64 | static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; | ||
65 | |||
66 | int 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 | |||
103 | static 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 | } | ||
128 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); | ||
129 | |||
130 | int __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 | ||
135 | static u32 get_cfgspace_addr(struct ssb_pcicore *pc, | 64 | static 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 | ||
252 | static u32 ssb_pcicore_pcibus_iobase = 0x100; | ||
253 | static 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. */ | ||
257 | int 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. */ | ||
300 | static 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 | } | ||
329 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge); | ||
330 | |||
331 | /* PCI device IRQ mapping. */ | ||
332 | int 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 | |||
323 | static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) | 341 | static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) |
324 | { | 342 | { |
325 | u32 val; | 343 | u32 val; |