aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/platforms/adir_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/platforms/adir_pci.c')
-rw-r--r--arch/ppc/platforms/adir_pci.c247
1 files changed, 0 insertions, 247 deletions
diff --git a/arch/ppc/platforms/adir_pci.c b/arch/ppc/platforms/adir_pci.c
deleted file mode 100644
index f94ac53e0711..000000000000
--- a/arch/ppc/platforms/adir_pci.c
+++ /dev/null
@@ -1,247 +0,0 @@
1/*
2 * arch/ppc/platforms/adir_pci.c
3 *
4 * PCI support for SBS Adirondack
5 *
6 * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
7 * based on the K2 version by Matt Porter <mporter@mvista.com>
8 */
9
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/pci.h>
13#include <linux/slab.h>
14
15#include <asm/byteorder.h>
16#include <asm/io.h>
17#include <asm/uaccess.h>
18#include <asm/machdep.h>
19#include <asm/pci-bridge.h>
20
21#include <syslib/cpc710.h>
22#include "adir.h"
23
24#undef DEBUG
25#ifdef DEBUG
26#define DBG(x...) printk(x)
27#else
28#define DBG(x...)
29#endif /* DEBUG */
30
31static inline int __init
32adir_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
33{
34#define PCIIRQ(a,b,c,d) {ADIR_IRQ_##a,ADIR_IRQ_##b,ADIR_IRQ_##c,ADIR_IRQ_##d},
35 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
36 /*
37 * The three PCI devices on the motherboard have dedicated lines to the
38 * CPLD interrupt controller, bypassing the standard PCI INTA-D and the
39 * PC interrupt controller. All other PCI devices (slots) have usual
40 * staggered INTA-D lines, resulting in 8 lines total (PCI0 INTA-D and
41 * PCI1 INTA-D). All 8 go to the CPLD interrupt controller. PCI0 INTA-D
42 * also go to the south bridge, so we have the option of taking them
43 * via the CPLD interrupt controller or via the south bridge 8259
44 * 8258 thingy. PCI1 INTA-D can only be taken via the CPLD interrupt
45 * controller. We take all PCI interrupts via the CPLD interrupt
46 * controller as recommended by SBS.
47 *
48 * We also have some monkey business with the PCI devices within the
49 * VT82C686B south bridge itself. This chip actually has 7 functions on
50 * its IDSEL. Function 0 is the actual south bridge, function 1 is IDE,
51 * and function 4 is some special stuff. The other 4 functions are just
52 * regular PCI devices bundled in the chip. 2 and 3 are USB UHCIs and 5
53 * and 6 are audio (not supported on the Adirondack).
54 *
55 * This is where the monkey business begins. PCI devices are supposed
56 * to signal normal PCI interrupts. But the 4 functions in question are
57 * located in the south bridge chip, which is designed with the
58 * assumption that it will be fielding PCI INTA-D interrupts rather
59 * than generating them. Here's what it does. Each of the functions in
60 * question routes its interrupt to one of the IRQs on the 8259 thingy.
61 * Which one? It looks at the Interrupt Line register in the PCI config
62 * space, even though the PCI spec says it's for BIOS/OS interaction
63 * only.
64 *
65 * How do we deal with this? We take these interrupts via 8259 IRQs as
66 * we have to. We return the desired IRQ numbers from this routine when
67 * called for the functions in question. The PCI scan code will then
68 * stick our return value into the Interrupt Line register in the PCI
69 * config space, and the interrupt will actually go there. We identify
70 * these functions within the south bridge IDSEL by their interrupt pin
71 * numbers, as the VT82C686B has 04 in the Interrupt Pin register for
72 * USB and 03 for audio.
73 */
74 if (!hose->index) {
75 static char pci_irq_table[][4] =
76 /*
77 * PCI IDSEL/INTPIN->INTLINE
78 * A B C D
79 */
80 {
81 /* south bridge */ PCIIRQ(IDE0, NONE, VIA_AUDIO, VIA_USB)
82 /* Ethernet 0 */ PCIIRQ(MBETH0, MBETH0, MBETH0, MBETH0)
83 /* PCI0 slot 1 */ PCIIRQ(PCI0_INTB, PCI0_INTC, PCI0_INTD, PCI0_INTA)
84 /* PCI0 slot 2 */ PCIIRQ(PCI0_INTC, PCI0_INTD, PCI0_INTA, PCI0_INTB)
85 /* PCI0 slot 3 */ PCIIRQ(PCI0_INTD, PCI0_INTA, PCI0_INTB, PCI0_INTC)
86 };
87 const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
88 return PCI_IRQ_TABLE_LOOKUP;
89 } else {
90 static char pci_irq_table[][4] =
91 /*
92 * PCI IDSEL/INTPIN->INTLINE
93 * A B C D
94 */
95 {
96 /* Ethernet 1 */ PCIIRQ(MBETH1, MBETH1, MBETH1, MBETH1)
97 /* SCSI */ PCIIRQ(MBSCSI, MBSCSI, MBSCSI, MBSCSI)
98 /* PCI1 slot 1 */ PCIIRQ(PCI1_INTB, PCI1_INTC, PCI1_INTD, PCI1_INTA)
99 /* PCI1 slot 2 */ PCIIRQ(PCI1_INTC, PCI1_INTD, PCI1_INTA, PCI1_INTB)
100 /* PCI1 slot 3 */ PCIIRQ(PCI1_INTD, PCI1_INTA, PCI1_INTB, PCI1_INTC)
101 };
102 const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
103 return PCI_IRQ_TABLE_LOOKUP;
104 }
105#undef PCIIRQ
106}
107
108static void
109adir_pcibios_fixup_resources(struct pci_dev *dev)
110{
111 int i;
112
113 if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
114 (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64))
115 {
116 DBG("Fixup CPC710 resources\n");
117 for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
118 {
119 dev->resource[i].start = 0;
120 dev->resource[i].end = 0;
121 }
122 }
123}
124
125/*
126 * CPC710 DD3 has an errata causing it to hang the system if a type 0 config
127 * cycle is attempted on its PCI32 interface with a device number > 21.
128 * CPC710's PCI bridges map device numbers 1 through 21 to AD11 through AD31.
129 * Per the PCI spec it MUST accept all other device numbers and do nothing, and
130 * software MUST scan all device numbers without assuming how IDSELs are
131 * mapped. However, as the CPC710 DD3's errata causes such correct scanning
132 * procedure to hang the system, we have no choice but to introduce this hack
133 * of knowingly avoiding device numbers > 21 on PCI0,
134 */
135static int
136adir_exclude_device(u_char bus, u_char devfn)
137{
138 if ((bus == 0) && (PCI_SLOT(devfn) > 21))
139 return PCIBIOS_DEVICE_NOT_FOUND;
140 else
141 return PCIBIOS_SUCCESSFUL;
142}
143
144void adir_find_bridges(void)
145{
146 struct pci_controller *hose_a, *hose_b;
147
148 /* Setup PCI32 hose */
149 hose_a = pcibios_alloc_controller();
150 if (!hose_a)
151 return;
152
153 hose_a->first_busno = 0;
154 hose_a->last_busno = 0xff;
155 hose_a->pci_mem_offset = ADIR_PCI32_MEM_BASE;
156 hose_a->io_space.start = 0;
157 hose_a->io_space.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
158 hose_a->mem_space.start = 0;
159 hose_a->mem_space.end = ADIR_PCI32_MEM_SIZE - 1;
160 hose_a->io_resource.start = 0;
161 hose_a->io_resource.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
162 hose_a->io_resource.flags = IORESOURCE_IO;
163 hose_a->mem_resources[0].start = ADIR_PCI32_MEM_BASE;
164 hose_a->mem_resources[0].end = ADIR_PCI32_MEM_BASE +
165 ADIR_PCI32_MEM_SIZE - 1;
166 hose_a->mem_resources[0].flags = IORESOURCE_MEM;
167 hose_a->io_base_phys = ADIR_PCI32_IO_BASE;
168 hose_a->io_base_virt = (void *) ADIR_PCI32_VIRT_IO_BASE;
169
170 ppc_md.pci_exclude_device = adir_exclude_device;
171 setup_indirect_pci(hose_a, ADIR_PCI32_CONFIG_ADDR,
172 ADIR_PCI32_CONFIG_DATA);
173
174 /* Initialize PCI32 bus registers */
175 early_write_config_byte(hose_a,
176 hose_a->first_busno,
177 PCI_DEVFN(0, 0),
178 CPC710_BUS_NUMBER,
179 hose_a->first_busno);
180 early_write_config_byte(hose_a,
181 hose_a->first_busno,
182 PCI_DEVFN(0, 0),
183 CPC710_SUB_BUS_NUMBER,
184 hose_a->last_busno);
185
186 hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
187
188 /* Write out correct max subordinate bus number for hose A */
189 early_write_config_byte(hose_a,
190 hose_a->first_busno,
191 PCI_DEVFN(0, 0),
192 CPC710_SUB_BUS_NUMBER,
193 hose_a->last_busno);
194
195 /* Setup PCI64 hose */
196 hose_b = pcibios_alloc_controller();
197 if (!hose_b)
198 return;
199
200 hose_b->first_busno = hose_a->last_busno + 1;
201 hose_b->last_busno = 0xff;
202 hose_b->pci_mem_offset = ADIR_PCI64_MEM_BASE;
203 hose_b->io_space.start = 0;
204 hose_b->io_space.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
205 hose_b->mem_space.start = 0;
206 hose_b->mem_space.end = ADIR_PCI64_MEM_SIZE - 1;
207 hose_b->io_resource.start = 0;
208 hose_b->io_resource.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
209 hose_b->io_resource.flags = IORESOURCE_IO;
210 hose_b->mem_resources[0].start = ADIR_PCI64_MEM_BASE;
211 hose_b->mem_resources[0].end = ADIR_PCI64_MEM_BASE +
212 ADIR_PCI64_MEM_SIZE - 1;
213 hose_b->mem_resources[0].flags = IORESOURCE_MEM;
214 hose_b->io_base_phys = ADIR_PCI64_IO_BASE;
215 hose_b->io_base_virt = (void *) ADIR_PCI64_VIRT_IO_BASE;
216
217 setup_indirect_pci(hose_b, ADIR_PCI64_CONFIG_ADDR,
218 ADIR_PCI64_CONFIG_DATA);
219
220 /* Initialize PCI64 bus registers */
221 early_write_config_byte(hose_b,
222 0,
223 PCI_DEVFN(0, 0),
224 CPC710_SUB_BUS_NUMBER,
225 0xff);
226
227 early_write_config_byte(hose_b,
228 0,
229 PCI_DEVFN(0, 0),
230 CPC710_BUS_NUMBER,
231 hose_b->first_busno);
232
233 hose_b->last_busno = pciauto_bus_scan(hose_b,
234 hose_b->first_busno);
235
236 /* Write out correct max subordinate bus number for hose B */
237 early_write_config_byte(hose_b,
238 hose_b->first_busno,
239 PCI_DEVFN(0, 0),
240 CPC710_SUB_BUS_NUMBER,
241 hose_b->last_busno);
242
243 ppc_md.pcibios_fixup = NULL;
244 ppc_md.pcibios_fixup_resources = adir_pcibios_fixup_resources;
245 ppc_md.pci_swizzle = common_swizzle;
246 ppc_md.pci_map_irq = adir_map_irq;
247}