diff options
Diffstat (limited to 'arch/ppc/platforms/adir_pci.c')
-rw-r--r-- | arch/ppc/platforms/adir_pci.c | 247 |
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 | |||
31 | static inline int __init | ||
32 | adir_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 | |||
108 | static void | ||
109 | adir_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 | */ | ||
135 | static int | ||
136 | adir_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 | |||
144 | void 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 | } | ||