2 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
3 * Copyright (c) 1994 Charles M. Hannum. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Charles M. Hannum.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * from NetBSD: pci_machdep.c,v 1.18 2001/07/22 11:29:48 wiz Exp
34 #include <sys/param.h>
35 #include <sys/systm.h>
38 #include <sys/kernel.h>
40 #include <dev/ofw/openfirm.h>
41 #include <dev/ofw/ofw_pci.h>
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcivar.h>
46 #include <powerpc/ofw/ofw_pci.h>
50 static void fixup_node(device_t, phandle_t);
51 static int find_node_intr(phandle_t, u_int32_t *, u_int32_t *);
54 ofw_pci_find_node(device_t dev)
56 phandle_t node, nextnode;
57 struct ofw_pci_register pcir;
60 for (node = OF_peer(0); node; node = nextnode) {
61 l = OF_getprop(node, "reg", &pcir, sizeof(pcir));
63 b = OFW_PCI_PHYS_HI_BUS(pcir.phys_hi);
64 s = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
65 f = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
67 if (b == pci_get_bus(dev) && s == pci_get_slot(dev) &&
68 f == pci_get_function(dev))
72 if ((nextnode = OF_child(node)))
75 if ((nextnode = OF_peer(node)) != 0)
77 node = OF_parent(node);
85 ofw_pci_fixup(device_t dev, u_int bus, phandle_t parentnode)
89 for (node = OF_child(parentnode); node; node = OF_peer(node)) {
90 fixup_node(dev, node);
95 fixup_node(device_t dev, phandle_t node)
97 u_int32_t csr, intr, irqs[4], npintr, paddr[4];
98 struct ofw_pci_register addr[8];
101 len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr));
102 if (len < (int)sizeof(struct ofw_pci_register)) {
106 csr = PCIB_READ_CONFIG(dev, OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi),
107 OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi),
108 OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_COMMAND, 4);
109 csr &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN);
111 for (i = 0; i < len / sizeof(struct ofw_pci_register); i++) {
112 switch (addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
113 case OFW_PCI_PHYS_HI_SPACE_IO:
114 csr |= PCIM_CMD_PORTEN;
116 case OFW_PCI_PHYS_HI_SPACE_MEM32:
117 csr |= PCIM_CMD_MEMEN;
122 PCIB_WRITE_CONFIG(dev, OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi),
123 OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi),
124 OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_COMMAND, csr, 4);
127 * Create PCI interrupt-map array element. pci-mid/pci-lo
128 * aren't required, but the 'interrupts' property needs
132 OF_getprop(node, "interrupts", &npintr, 4);
133 paddr[0] = addr[0].phys_hi;
138 if (find_node_intr(node, paddr, irqs) != -1) {
139 intr = PCIB_READ_CONFIG(dev,
140 OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi),
141 OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi),
142 OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_INTLINE, 2);
144 intr |= irqs[0] & 0xff;
145 PCIB_WRITE_CONFIG(dev,
146 OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi),
147 OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi),
148 OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_INTLINE,
155 find_node_intr(phandle_t node, u_int32_t *addr, u_int32_t *intr)
157 phandle_t parent, iparent;
158 int len, mlen, match, i;
159 u_int32_t map[160], *mp, imask[8], maskedaddr[8], icells;
162 len = OF_getprop(node, "AAPL,interrupts", intr, 4);
167 parent = OF_parent(node);
168 len = OF_getprop(parent, "interrupt-map", map, sizeof(map));
169 mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask));
171 if (len == -1 || mlen == -1)
174 memcpy(maskedaddr, addr, mlen);
175 for (i = 0; i < mlen/4; i++)
176 maskedaddr[i] &= imask[i];
180 match = bcmp(maskedaddr, mp, mlen);
185 * We must read "#interrupt-cells" for each time because
186 * interrupt-parent may be different.
190 if (OF_getprop(iparent, "#interrupt-cells", &icells, 4) != 4)
195 bcopy(mp, intr, icells * 4);
205 * If the node has no interrupt property and the parent is a PCI
206 * bridge, use the parent's interrupt. This occurs on a PCI slot.
208 bzero(name, sizeof(name));
209 OF_getprop(parent, "name", name, sizeof(name));
210 if (strcmp(name, "pci-bridge") == 0) {
211 len = OF_getprop(parent, "AAPL,interrupts", intr, 4);
217 * XXX I don't know what is the correct local address.
218 * XXX Use the first entry for now.
220 len = OF_getprop(parent, "interrupt-map", map, sizeof(map));
223 /* XXX Use 0 for 'interrupts' for compat */
224 return (find_node_intr(parent, addr, intr));