Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / arch / ppc / platforms / adir_pci.c
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 }