1 /* $NetBSD: pci_machdep.c,v 1.36 2007/12/25 17:55:10 macallan Exp $ */
4 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
5 * Copyright (c) 1994 Charles M. Hannum. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Charles M. Hannum.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Machine-specific functions for PCI autoconfiguration.
36 * On PCs, there are two methods of generating PCI configuration cycles.
37 * We try to detect the appropriate mechanism for this machine and set
38 * up a few function pointers to access the correct method directly.
40 * The configuration method can be hard-coded in the config file by
41 * using `options PCI_CONF_MODE=N', where `N' is the configuration mode
42 * as defined section 3.6.4.1, `Generating Configuration Cycles'.
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.36 2007/12/25 17:55:10 macallan Exp $");
48 #include <sys/types.h>
49 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/errno.h>
53 #include <sys/device.h>
55 #include <uvm/uvm_extern.h>
57 #define _POWERPC_BUS_DMA_PRIVATE
58 #include <machine/bus.h>
60 #include <machine/autoconf.h>
61 #include <machine/intr.h>
63 #include <dev/pci/pcivar.h>
64 #include <dev/pci/pcireg.h>
65 #include <dev/pci/ppbreg.h>
66 #include <dev/pci/pcidevs.h>
68 #include <dev/ofw/openfirm.h>
69 #include <dev/ofw/ofw_pci.h>
71 #include "opt_macppc.h"
73 static void fixpci(int, pci_chipset_tag_t
);
74 static int find_node_intr(int, u_int32_t
*, u_int32_t
*);
75 static void fix_cardbus_bridge(int, pci_chipset_tag_t
, pcitag_t
);
77 #ifdef PB3400_CARDBUS_HACK
78 int cardbus_number
= 2;
79 const char *pb3400_compat
[] = {"AAPL,3400/2400", NULL
};
82 pcitag_t
genppc_pci_indirect_make_tag(void *, int, int, int);
83 void genppc_pci_indirect_decompose_tag(void *, pcitag_t
, int *, int *, int *);
86 macppc_pci_attach_hook(struct device
*parent
, struct device
*self
, struct pcibus_attach_args
*pba
)
88 pci_chipset_tag_t pc
= pba
->pba_pc
;
89 int bus
= pba
->pba_bus
;
93 for (node
= pc
->pc_node
; node
; node
= nn
) {
94 sz
= OF_getprop(node
, "bus-range", busrange
, 8);
95 if (sz
== 8 && busrange
[0] == bus
) {
99 if ((nn
= OF_child(node
)) != 0)
101 while ((nn
= OF_peer(node
)) == 0) {
102 node
= OF_parent(node
);
103 if (node
== pc
->pc_node
)
104 return; /* not found */
110 macppc_pci_get_chipset_tag(pci_chipset_tag_t pc
)
113 pc
->pc_conf_v
= (void *)pc
;
115 pc
->pc_attach_hook
= macppc_pci_attach_hook
;
116 pc
->pc_bus_maxdevs
= genppc_pci_bus_maxdevs
;
118 pc
->pc_make_tag
= genppc_pci_indirect_make_tag
;
119 pc
->pc_decompose_tag
= genppc_pci_indirect_decompose_tag
;
121 pc
->pc_intr_v
= (void *)pc
;
123 pc
->pc_intr_map
= genppc_pci_intr_map
;
124 pc
->pc_intr_string
= genppc_pci_intr_string
;
125 pc
->pc_intr_evcnt
= genppc_pci_intr_evcnt
;
126 pc
->pc_intr_establish
= genppc_pci_intr_establish
;
127 pc
->pc_intr_disestablish
= genppc_pci_intr_disestablish
;
129 pc
->pc_conf_interrupt
= genppc_pci_conf_interrupt
;
130 pc
->pc_conf_hook
= genppc_pci_conf_hook
;
139 (((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT)
141 (((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT)
143 (((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT)
146 fixpci(int parent
, pci_chipset_tag_t pc
)
150 pcireg_t csr
, intr
, id
, cr
;
154 u_int32_t phys_hi
, phys_mid
, phys_lo
;
155 u_int32_t size_hi
, size_lo
;
158 u_int32_t phys_hi
, phys_mid
, phys_lo
;
163 * first hack - here we make the Ethernet portion of a
164 * UMAX E100 card work
166 #ifdef UMAX_E100_HACK
167 tag
= pci_make_tag(pc
, 0, 17, 0);
168 id
= pci_conf_read(pc
, tag
, PCI_ID_REG
);
169 if ((PCI_VENDOR(id
) == PCI_VENDOR_DEC
) &&
170 (PCI_PRODUCT(id
) == PCI_PRODUCT_DEC_21140
)) {
171 /* this could be one */
173 pcitag_t tag_isp
= pci_make_tag(pc
, 0, 13, 0);
175 * here we go. We shouldn't encounter this anywhere else
176 * than on a UMAX S900 with an E100 board
177 * look at 00:0d:00 for a Qlogic ISP 1020 to
178 * make sure we really have an E100 here
180 aprint_debug("\nfound E100 candidate tlp");
181 isp
= pci_conf_read(pc
, tag_isp
, PCI_ID_REG
);
182 if ((PCI_VENDOR(isp
) == PCI_VENDOR_QLOGIC
) &&
183 (PCI_PRODUCT(isp
) == PCI_PRODUCT_QLOGIC_ISP1020
)) {
185 aprint_verbose("\nenabling UMAX E100 ethernet");
187 pci_conf_write(pc
, tag
, 0x14, 0x80000000);
189 /* now enable MMIO and busmastering */
190 reg
= pci_conf_read(pc
, tag
,
191 PCI_COMMAND_STATUS_REG
);
192 reg
|= PCI_COMMAND_MEM_ENABLE
|
193 PCI_COMMAND_MASTER_ENABLE
;
194 pci_conf_write(pc
, tag
, PCI_COMMAND_STATUS_REG
,
197 /* and finally the interrupt */
198 reg
= pci_conf_read(pc
, tag
, PCI_INTERRUPT_REG
);
199 reg
&= ~PCI_INTERRUPT_LINE_MASK
;
201 pci_conf_write(pc
, tag
, PCI_INTERRUPT_REG
, reg
);
206 len
= OF_getprop(parent
, "#interrupt-cells", &ilen
, sizeof(ilen
));
209 for (node
= OF_child(parent
); node
; node
= OF_peer(node
)) {
210 len
= OF_getprop(node
, "assigned-addresses", addr
,
212 if (len
< (int)sizeof(addr
[0]))
215 tag
= pci_make_tag(pc
, pcibus(addr
[0].phys_hi
),
216 pcidev(addr
[0].phys_hi
),
217 pcifunc(addr
[0].phys_hi
));
220 * Make sure the IO and MEM enable bits are set in the CSR.
222 csr
= pci_conf_read(pc
, tag
, PCI_COMMAND_STATUS_REG
);
223 csr
&= ~(PCI_COMMAND_IO_ENABLE
| PCI_COMMAND_MEM_ENABLE
);
225 for (i
= 0; i
< len
/ sizeof(addr
[0]); i
++) {
226 switch (addr
[i
].phys_hi
& OFW_PCI_PHYS_HI_SPACEMASK
) {
227 case OFW_PCI_PHYS_HI_SPACE_IO
:
228 csr
|= PCI_COMMAND_IO_ENABLE
;
231 case OFW_PCI_PHYS_HI_SPACE_MEM32
:
232 case OFW_PCI_PHYS_HI_SPACE_MEM64
:
233 csr
|= PCI_COMMAND_MEM_ENABLE
;
238 pci_conf_write(pc
, tag
, PCI_COMMAND_STATUS_REG
, csr
);
241 * Make sure the line register is programmed with the
246 * Early Apple OFW implementation don't handle
247 * interrupts as defined by the OFW PCI bindings.
249 len
= OF_getprop(node
, "AAPL,interrupts", irqs
, 4);
251 iaddr
.phys_hi
= addr
[0].phys_hi
;
252 iaddr
.phys_mid
= addr
[0].phys_mid
;
253 iaddr
.phys_lo
= addr
[0].phys_lo
;
255 * Thankfully, PCI can only have one entry in its
256 * "interrupts" property.
258 len
= OF_getprop(node
, "interrupts", &iaddr
.icells
[0],
262 len
= find_node_intr(node
, &iaddr
.phys_hi
, irqs
);
266 * If we still don't have an interrupt, try one
267 * more time. This case covers devices behind the
268 * PCI-PCI bridge in a UMAX S900 or similar (9500?)
269 * system. These slots all share the bridge's
272 len
= find_node_intr(node
, &addr
[0].phys_hi
, irqs
);
278 * For PowerBook 2400, 3400 and original G3:
279 * check if we have a 2nd ohare PIC - if so frob the built-in
281 * first see if we have something on bus 0 device 13 and if
284 id
= pci_conf_read(pc
, tag
, PCI_ID_REG
);
285 if ((tag
== pci_make_tag(pc
, 0, 13, 0)) &&
286 (PCI_VENDOR(id
) == PCI_VENDOR_DEC
) &&
287 (PCI_PRODUCT(id
) == PCI_PRODUCT_DEC_21041
)) {
289 /* now look for the 2nd ohare */
290 if (OF_finddevice("/bandit/pci106b,7") != -1) {
293 aprint_verbose("\nohare: frobbing tlp IRQ to 60");
297 intr
= pci_conf_read(pc
, tag
, PCI_INTERRUPT_REG
);
298 intr
&= ~PCI_INTERRUPT_LINE_MASK
;
299 intr
|= irqs
[0] & PCI_INTERRUPT_LINE_MASK
;
300 pci_conf_write(pc
, tag
, PCI_INTERRUPT_REG
, intr
);
302 /* fix secondary bus numbers on CardBus bridges */
303 cr
= pci_conf_read(pc
, tag
, PCI_CLASS_REG
);
304 if ((PCI_CLASS(cr
) == PCI_CLASS_BRIDGE
) &&
305 (PCI_SUBCLASS(cr
) == PCI_SUBCLASS_BRIDGE_CARDBUS
)) {
309 * we found a CardBus bridge. Check if the bus number
312 bi
= pci_conf_read(pc
, tag
, PPB_REG_BUSINFO
);
315 fix_cardbus_bridge(node
, pc
, tag
);
322 fix_cardbus_bridge(int node
, pci_chipset_tag_t pc
, pcitag_t tag
)
324 uint32_t bus_number
= 0xffffffff;
326 int bus
, dev
, fn
, ih
, len
;
329 #if PB3400_CARDBUS_HACK
332 root_node
= OF_finddevice("/");
333 if (of_compatible(root_node
, pb3400_compat
) != -1) {
335 bus_number
= cardbus_number
;
340 OF_call_method("load-ata", ih
, 0, 0);
343 OF_getprop(node
, "AAPL,bus-id", &bus_number
,
345 #if PB3400_CARDBUS_HACK
348 if (bus_number
!= 0xffffffff) {
350 len
= OF_package_to_path(node
, path
, sizeof(path
));
352 aprint_verbose("\n%s: fixing bus number to %d", path
, bus_number
);
353 pci_decompose_tag(pc
, tag
, &bus
, &dev
, &fn
);
354 bi
= pci_conf_read(pc
, tag
, PPB_REG_BUSINFO
);
356 /* XXX subordinate is always 32 here */
357 bi
|= (bus
& 0xff) | (bus_number
<< 8) | 0x200000;
358 pci_conf_write(pc
, tag
, PPB_REG_BUSINFO
, bi
);
363 * Find PCI IRQ of the node from OF tree.
366 find_node_intr(int node
, u_int32_t
*addr
, uint32_t *intr
)
368 int parent
, len
, mlen
, iparent
;
372 u_int32_t imapmask
[8], maskedaddr
[8];
373 u_int32_t acells
, icells
;
376 /* XXXSL: 1st check for a interrupt-parent property */
377 if (OF_getprop(node
, "interrupt-parent", &iparent
, sizeof(iparent
)) == sizeof(iparent
))
379 /* How many cells to specify an interrupt ?? */
380 if (OF_getprop(iparent
, "#interrupt-cells", &icells
, 4) != 4)
383 if (OF_getprop(node
, "interrupts", &map
, sizeof(map
)) != (icells
* 4))
386 memcpy(intr
, map
, icells
* 4);
390 parent
= OF_parent(node
);
391 len
= OF_getprop(parent
, "interrupt-map", map
, sizeof(map
));
392 mlen
= OF_getprop(parent
, "interrupt-map-mask", imapmask
,
396 memcpy(maskedaddr
, addr
, mlen
);
398 if (len
== -1 || mlen
== -1)
402 if (mlen
== sizeof(imapmask
)) {
403 aprint_error("interrupt-map too long\n");
408 /* mask addr by "interrupt-map-mask" */
409 for (i
= 0; i
< mlen
/ 4; i
++)
410 maskedaddr
[i
] &= imapmask
[i
];
415 match
= memcmp(maskedaddr
, mp
, mlen
);
420 * We must read "#address-cells" and "#interrupt-cells" each
421 * time because each interrupt-parent may be different.
425 i
= OF_getprop(iparent
, "#address-cells", &acells
, 4);
430 if (OF_getprop(iparent
, "#interrupt-cells", &icells
, 4) != 4)
436 * We matched on address/interrupt, but are we done?
438 if (acells
== 0) { /* XXX */
440 * If we are at the interrupt controller,
441 * we are finally done. Save the result and
444 memcpy(intr
, mp
, icells
* 4);
448 * We are now at an intermedia interrupt node. We
449 * need to use its interrupt mask and map the
450 * supplied address/interrupt via its map.
452 mlen
= OF_getprop(iparent
, "interrupt-map-mask",
453 imapmask
, sizeof(imapmask
));
455 if (mlen
!= (acells
+ icells
)*4) {
456 aprint_error("interrupt-map inconsistent (%d, %d)\n",
457 mlen
, (acells
+ icells
)*4);
461 memcpy(maskedaddr
, mp
, mlen
);
462 len
= OF_getprop(iparent
, "interrupt-map", map
,
467 mp
+= (acells
+ icells
);
468 len
-= (acells
+ icells
) * 4;
473 * If the node has no interrupt property and the parent is a
474 * pci-bridge, use parent's interrupt. This occurs on a PCI
475 * slot. (e.g. AHA-3940)
477 memset(name
, 0, sizeof(name
));
478 OF_getprop(parent
, "name", name
, sizeof(name
));
479 if (strcmp(name
, "pci-bridge") == 0) {
480 len
= OF_getprop(parent
, "AAPL,interrupts", intr
, 4) ;
485 * XXX I don't know what is the correct local address.
486 * XXX Use the first entry for now.
488 len
= OF_getprop(parent
, "interrupt-map", map
, sizeof(map
));
491 return find_node_intr(parent
, addr
, intr
);
497 * If all else fails, attempt to get AAPL, interrupts property.
498 * Grackle, at least, uses this instead of above in some cases.
500 len
= OF_getprop(node
, "AAPL,interrupts", intr
, 4) ;