1 /* $NetBSD: pci_machdep_ofw.c,v 1.11 2008/02/23 21:11:22 phx Exp $ */
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Generic OFW routines for pci_machdep
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: pci_machdep_ofw.c,v 1.11 2008/02/23 21:11:22 phx Exp $");
39 #include <sys/types.h>
40 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/errno.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
47 #include <uvm/uvm_extern.h>
49 #include <machine/bus.h>
51 #include <machine/autoconf.h>
52 #include <machine/pio.h>
53 #include <machine/intr.h>
55 #include <dev/pci/pcivar.h>
56 #include <dev/pci/pcireg.h>
57 #include <dev/pci/ppbreg.h>
58 #include <dev/pci/pcidevs.h>
59 #include <dev/pci/pciconf.h>
61 #include <dev/ofw/openfirm.h>
62 #include <dev/ofw/ofw_pci.h>
64 pcitag_t
genppc_pci_indirect_make_tag(void *, int, int, int);
65 void genppc_pci_indirect_decompose_tag(void *, pcitag_t
, int *, int *, int *);
67 ofw_pic_node_t picnodes
[8];
71 genofw_find_picnode(int node
)
75 for (i
= 0; i
< 8; i
++)
76 if (node
== picnodes
[i
].node
)
82 genofw_find_ofpics(int startnode
)
84 int node
, iparent
, child
, iranges
[6], irgot
=0, i
;
88 for (node
= startnode
; node
; node
= OF_peer(node
)) {
89 if ((child
= OF_child(node
)) != 0)
90 genofw_find_ofpics(child
);
91 memset(name
, 0, sizeof(name
));
92 if (OF_getprop(node
, "name", name
, sizeof(name
)) == -1)
94 if (strncmp(name
, "interrupt-controller", 20) == 0)
97 if (OF_getprop(node
, "interrupt-controller", name
,
101 if (OF_getprop(node
, "device_type", name
, sizeof(name
)) == -1)
103 if (strncmp(name
, "interrupt-controller", 20) == 0)
106 /* if we didn't find one, skip to the next */
109 picnodes
[nrofpics
].node
= node
;
110 if (OF_getprop(node
, "interrupt-parent", &iparent
,
111 sizeof(iparent
)) == sizeof(iparent
))
112 picnodes
[nrofpics
].parent
= iparent
;
113 if (OF_getprop(node
, "#interrupt-cells", &iparent
,
114 sizeof(iparent
)) == sizeof(iparent
))
115 picnodes
[nrofpics
].cells
= iparent
;
117 picnodes
[nrofpics
].cells
= 1;
119 picnodes
[nrofpics
].intrs
= 0;
120 irgot
= OF_getprop(node
, "interrupt-ranges", iranges
,
121 sizeof(int)*6); /* XXX is this ok? */
122 if (irgot
>= sizeof(int)) {
123 for (i
=0; i
< irgot
/4; i
++)
124 if (!picnodes
[nrofpics
].intrs
)
125 picnodes
[nrofpics
].intrs
= iranges
[i
];
128 irgot
= OF_getprop(node
, "reg", reg
, sizeof(reg
));
130 if (!picnodes
[nrofpics
].intrs
)
131 picnodes
[nrofpics
].intrs
= 16;
134 picnodes
[nrofpics
].offset
= picnodes
[nrofpics
-1].offset
135 + picnodes
[nrofpics
-1].intrs
;
137 picnodes
[nrofpics
].offset
= 0;
138 OF_getprop(node
, "device_type", name
, sizeof(name
));
139 if (strcmp(name
, "open-pic") == 0)
140 picnodes
[nrofpics
].type
= PICNODE_TYPE_OPENPIC
;
141 if (strcmp(name
, "interrupt-controller") == 0) {
142 OF_getprop(node
, "compatible", name
, sizeof(name
));
143 if (strcmp(name
, "heathrow") == 0)
144 picnodes
[nrofpics
].type
= PICNODE_TYPE_HEATHROW
;
145 if (strcmp(name
, "pnpPNP,0") == 0)
146 picnodes
[nrofpics
].type
= PICNODE_TYPE_8259
;
147 if (strcmp(name
, "chrp,iic") == 0) {
148 picnodes
[nrofpics
].type
= PICNODE_TYPE_8259
;
149 if (irgot
>= 9 * sizeof(uint32_t) &&
151 picnodes
[nrofpics
].type
=
155 if (strlen(name
) == 0) {
156 /* probably a Pegasos, assume 8259 */
157 picnodes
[nrofpics
].type
= PICNODE_TYPE_8259
;
163 /* Fix up the various picnode offsets */
165 genofw_fixup_picnode_offsets(void)
171 for (i
=0; i
< nrofpics
; i
++) {
172 if (picnodes
[i
].type
== PICNODE_TYPE_8259
||
173 picnodes
[i
].type
== PICNODE_TYPE_IVR
) {
174 picnodes
[i
].offset
= 0;
175 curoff
= picnodes
[i
].intrs
;
178 for (i
=0; i
< nrofpics
; i
++) {
179 /* now skip the 8259 */
180 if (picnodes
[i
].type
== PICNODE_TYPE_8259
)
182 if (picnodes
[i
].type
== PICNODE_TYPE_IVR
)
185 picnodes
[i
].offset
= curoff
;
186 curoff
+= picnodes
[i
].intrs
;
190 /* we are given a pci devnode, and dig from there */
192 genofw_setup_pciintr_map(void *v
, struct genppc_pci_chipset_businfo
*pbi
,
198 int curdev
, foundirqs
=0;
199 int i
, reclen
, nrofpcidevs
=0;
200 u_int32_t acells
, icells
, pcells
;
201 prop_dictionary_t dict
;
202 prop_dictionary_t sub
=0;
203 pci_chipset_tag_t pc
= (pci_chipset_tag_t
)v
;
205 len
= OF_getprop(pcinode
, "interrupt-map", map
, sizeof(map
));
209 if (OF_getprop(pcinode
, "#address-cells", &acells
,
210 sizeof(acells
)) == -1)
212 if (OF_getprop(pcinode
, "#interrupt-cells", &icells
,
213 sizeof(icells
)) == -1)
216 parent
= map
[acells
+icells
];
217 if (OF_getprop(parent
, "#interrupt-cells", &pcells
,
218 sizeof(pcells
)) == -1)
221 reclen
= acells
+pcells
+icells
+1;
222 nrofpcidevs
= len
/ (reclen
* sizeof(int));
224 dict
= prop_dictionary_create_with_capacity(nrofpcidevs
*2);
225 KASSERT(dict
!= NULL
);
228 prop_dictionary_set(pbi
->pbi_properties
, "ofw-pci-intrmap", dict
);
229 for (i
= 0; i
< nrofpcidevs
; i
++) {
230 prop_number_t intr_num
;
231 int dev
, pin
, pic
, func
;
234 pic
= genofw_find_picnode(map
[i
*reclen
+ acells
+ icells
]);
236 dev
= (map
[i
*reclen
] >> 8) / 0x8;
237 func
= (map
[i
*reclen
] >> 8) % 0x8;
239 sub
= prop_dictionary_create_with_capacity(4);
240 pin
= map
[i
*reclen
+ acells
];
241 intr_num
= prop_number_create_integer(map
[i
*reclen
+ acells
+ icells
+ 1] + picnodes
[pic
].offset
);
242 sprintf(key
, "pin-%c", 'A' + (pin
-1));
243 prop_dictionary_set(sub
, key
, intr_num
);
244 prop_object_release(intr_num
);
245 /* should we care about level? */
247 sprintf(key
, "devfunc-%d", dev
*0x8 + func
);
248 prop_dictionary_set(dict
, key
, sub
);
250 prop_object_release(sub
);
254 /* the mapping is complete */
255 prop_object_release(dict
);
256 aprint_debug("%s\n", prop_dictionary_externalize(pbi
->pbi_properties
));
260 /* so, we have one of those annoying machines that doesn't provide
261 * a nice simple map of interrupts. We get to do this the hard
262 * way instead. Lucky us.
264 for (node
= OF_child(pcinode
), nrofpcidevs
=0; node
;
265 node
= OF_peer(node
))
267 dict
= prop_dictionary_create_with_capacity(nrofpcidevs
*2);
268 KASSERT(dict
!= NULL
);
269 prop_dictionary_set(pbi
->pbi_properties
, "ofw-pci-intrmap", dict
);
271 for (node
= OF_child(pcinode
); node
; node
= OF_peer(node
)) {
272 uint32_t irqs
[4], reg
[5];
273 prop_number_t intr_num
;
277 /* walk the bus looking for pci devices and map them */
278 if (OF_getprop(node
, "AAPL,interrupts", irqs
, 4) > 0) {
280 if (OF_getprop(node
, "reg", reg
, 5) > 0) {
281 dev
= ((reg
[0] & 0x0000ff00) >> 8) / 0x8;
282 func
= ((reg
[0] & 0x0000ff00) >> 8) % 0x8;
283 } else if (OF_getprop(node
, "assigned-addresses",
285 dev
= ((reg
[0] & 0x0000ff00) >> 8) / 0x8;
286 func
= ((reg
[0] & 0x0000ff00) >> 8) % 0x8;
289 aprint_error("cannot figure out device num "
290 "for node 0x%x\n", node
);
293 sub
= prop_dictionary_create_with_capacity(4);
294 if (OF_getprop(node
, "interrupts", &pin
, 4) < 0)
296 intr_num
= prop_number_create_integer(irqs
[0]);
297 sprintf(key
, "pin-%c", 'A' + (pin
-1));
298 prop_dictionary_set(sub
, key
, intr_num
);
299 prop_object_release(intr_num
);
300 sprintf(key
, "devfunc-%d", dev
*0x8 + func
);
301 prop_dictionary_set(dict
, key
, sub
);
302 prop_object_release(sub
);
310 * If we got this far, we have a super-annoying OFW.
311 * They didn't bother to fill in any interrupt properties anywhere,
312 * so we pray that they filled in the ones on the pci devices.
314 for (node
= OF_child(pcinode
); node
; node
= OF_peer(node
)) {
315 uint32_t reg
[5], irq
;
316 prop_number_t intr_num
;
321 if (OF_getprop(node
, "reg", reg
, 5) > 0) {
322 dev
= ((reg
[0] & 0x0000ff00) >> 8) / 0x8;
323 func
= ((reg
[0] & 0x0000ff00) >> 8) % 0x8;
325 tag
= pci_make_tag(pc
, pc
->pc_bus
, dev
, func
);
326 irq
= PCI_INTERRUPT_LINE(pci_conf_read(pc
, tag
,
331 sub
= prop_dictionary_create_with_capacity(4);
332 if (OF_getprop(node
, "interrupts", &pin
, 4) < 0)
334 intr_num
= prop_number_create_integer(irq
);
335 sprintf(key
, "pin-%c", 'A' + (pin
-1));
336 prop_dictionary_set(sub
, key
, intr_num
);
337 prop_object_release(intr_num
);
338 sprintf(key
, "devfunc-%d", dev
*0x8 + func
);
339 prop_dictionary_set(dict
, key
, sub
);
340 prop_object_release(sub
);
343 aprint_debug("%s\n", prop_dictionary_externalize(pbi
->pbi_properties
));
347 genofw_find_node_by_devfunc(int startnode
, int bus
, int dev
, int func
)
352 for (node
= startnode
; node
; node
= p
) {
353 sz
= OF_getprop(node
, "reg", ®
, sizeof(reg
));
354 if (sz
!= sizeof(reg
))
356 if (OFW_PCI_PHYS_HI_BUS(reg
) == bus
&&
357 OFW_PCI_PHYS_HI_DEVICE(reg
) == dev
&&
358 OFW_PCI_PHYS_HI_FUNCTION(reg
) == func
)
360 if ((p
= OF_child(node
)))
363 if ((p
= OF_peer(node
)))
365 node
= OF_parent(node
);
368 /* couldn't find it */
373 genofw_pci_intr_map(struct pci_attach_args
*pa
, pci_intr_handle_t
*ihp
)
375 struct genppc_pci_chipset_businfo
*pbi
;
376 prop_dictionary_t dict
, devsub
;
377 prop_object_t pinsub
;
379 int busno
, bus
, pin
, line
, swiz
, dev
, origdev
, func
, i
;
382 pin
= pa
->pa_intrpin
;
383 line
= pa
->pa_intrline
;
384 bus
= busno
= pa
->pa_bus
;
385 swiz
= pa
->pa_intrswiz
;
386 origdev
= dev
= pa
->pa_device
;
387 func
= pa
->pa_function
;
390 pbi
= SIMPLEQ_FIRST(&pa
->pa_pc
->pc_pbi
);
392 pbi
= SIMPLEQ_NEXT(pbi
, next
);
393 KASSERT(pbi
!= NULL
);
395 dict
= prop_dictionary_get(pbi
->pbi_properties
, "ofw-pci-intrmap");
398 i
= prop_dictionary_count(dict
);
400 if (dict
== NULL
|| i
== 0) {
401 /* We have an unmapped bus, now it gets hard */
402 pbus
= prop_dictionary_get(pbi
->pbi_properties
,
403 "ofw-pcibus-parent");
406 busno
= prop_number_integer_value(pbus
);
407 pbus
= prop_dictionary_get(pbi
->pbi_properties
,
408 "ofw-pcibus-rawdevnum");
409 dev
= prop_number_integer_value(pbus
);
411 /* now that we know the parent bus, we need to find it's pbi */
412 pbi
= SIMPLEQ_FIRST(&pa
->pa_pc
->pc_pbi
);
414 pbi
= SIMPLEQ_NEXT(pbi
, next
);
415 KASSERT(pbi
!= NULL
);
417 /* swizzle the pin */
418 pin
= ((pin
+ origdev
- 1) & 3) + 1;
420 /* now we have the pbi, ask for dict again */
421 dict
= prop_dictionary_get(pbi
->pbi_properties
,
431 aprint_error("pci_intr_map: bad interrupt pin %d\n", pin
);
435 sprintf(key
, "devfunc-%d", dev
*0x8 + func
);
436 devsub
= prop_dictionary_get(dict
, key
);
439 sprintf(key
, "pin-%c", 'A' + (pin
-1));
440 pinsub
= prop_dictionary_get(devsub
, key
);
443 line
= prop_number_integer_value(pinsub
);
445 if (line
== 0 || line
== 255) {
446 aprint_error("pci_intr_map: no mapping for pin %c\n",'@' + pin
);
459 genofw_pci_conf_hook(pci_chipset_tag_t pct
, int bus
, int dev
, int func
,
462 struct genppc_pci_chipset_businfo
*pbi
;
468 /* We have already mapped MPIC's if we have them, so leave them alone */
469 if (PCI_VENDOR(id
) == PCI_VENDOR_IBM
&&
470 PCI_PRODUCT(id
) == PCI_PRODUCT_IBM_MPIC2
)
473 if (PCI_VENDOR(id
) == PCI_VENDOR_IBM
&&
474 PCI_PRODUCT(id
) == PCI_PRODUCT_IBM_MPIC
)
477 /* I highly doubt there are any CHRP ravens, but just in case */
478 if (PCI_VENDOR(id
) == PCI_VENDOR_MOT
&&
479 PCI_PRODUCT(id
) == PCI_PRODUCT_MOT_RAVEN
)
480 return (PCI_CONF_ALL
& ~PCI_CONF_MAP_MEM
);
483 * Pegasos2 specific stuff.
485 if (strncmp(model_name
, "Pegasos2", 8) == 0) {
487 /* never reconfigure the MV64361 host bridge */
488 if (PCI_VENDOR(id
) == PCI_VENDOR_MARVELL
&&
489 PCI_PRODUCT(id
) == PCI_PRODUCT_MARVELL_GT64360
)
492 /* we want to leave viaide(4) alone */
493 if (PCI_VENDOR(id
) == PCI_VENDOR_VIATECH
&&
494 PCI_PRODUCT(id
) == PCI_PRODUCT_VIATECH_VT82C586A_IDE
)
497 /* leave the audio IO alone */
498 if (PCI_VENDOR(id
) == PCI_VENDOR_VIATECH
&&
499 PCI_PRODUCT(id
) == PCI_PRODUCT_VIATECH_VT82C686A_AC97
)
500 return (PCI_CONF_ALL
& ~PCI_CONF_MAP_IO
);
504 tag
= pci_make_tag(pct
, bus
, dev
, func
);
505 class = pci_conf_read(pct
, tag
, PCI_CLASS_REG
);
507 /* leave video cards alone */
508 if (PCI_CLASS(class) == PCI_CLASS_DISPLAY
)
511 /* NOTE, all device specific stuff must be above this line */
512 /* don't do this on the primary host bridge */
513 if (bus
== 0 && dev
== 0 && func
== 0)
514 return PCI_CONF_DEFAULT
;
517 * PCI bridges have special needs. We need to discover where they
518 * came from, and wire them appropriately.
520 if (PCI_CLASS(class) == PCI_CLASS_BRIDGE
&&
521 PCI_SUBCLASS(class) == PCI_SUBCLASS_BRIDGE_PCI
) {
522 pbi
= malloc(sizeof(struct genppc_pci_chipset_businfo
),
524 KASSERT(pbi
!= NULL
);
525 pbi
->pbi_properties
= prop_dictionary_create();
526 KASSERT(pbi
->pbi_properties
!= NULL
);
527 node
= genofw_find_node_by_devfunc(pct
->pc_node
, bus
, dev
,
530 aprint_error("Cannot find node for device "
531 "bus %d dev %d func %d\n", bus
, dev
, func
);
532 prop_object_release(pbi
->pbi_properties
);
534 return (PCI_CONF_DEFAULT
);
536 genofw_setup_pciintr_map((void *)pct
, pbi
, node
);
538 /* record the parent bus, and the parent device number */
539 pbus
= prop_number_create_integer(bus
);
540 prop_dictionary_set(pbi
->pbi_properties
, "ofw-pcibus-parent",
542 prop_object_release(pbus
);
543 pbus
= prop_number_create_integer(dev
);
544 prop_dictionary_set(pbi
->pbi_properties
, "ofw-pcibus-rawdevnum",
546 prop_object_release(pbus
);
548 SIMPLEQ_INSERT_TAIL(&pct
->pc_pbi
, pbi
, next
);
551 return (PCI_CONF_DEFAULT
);