1 /* $NetBSD: mainbus.c,v 1.32 2021/08/07 16:19:01 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 *
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.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.32 2021/08/07 16:19:01 thorpej Exp $");
34
35 #include "opt_interrupt.h"
36 #include "opt_multiprocessor.h"
37
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/systm.h>
41
42 #include <dev/pci/pcivar.h>
43 #include <dev/ofw/openfirm.h>
44 #include <dev/ofw/ofw_pci.h>
45 #include <arch/powerpc/pic/picvar.h>
46 #ifdef MULTIPROCESSOR
47 #include <arch/powerpc/pic/ipivar.h>
48 #endif
49 #include <machine/pci_machdep.h>
50 #include <machine/autoconf.h>
51
52 #include <dev/isa/isareg.h>
53 #include <dev/isa/isavar.h>
54
55 int mainbus_match(device_t, cfdata_t, void *);
56 void mainbus_attach(device_t, device_t, void *);
57
58 CFATTACH_DECL_NEW(mainbus, 0,
59 mainbus_match, mainbus_attach, NULL, NULL);
60
61 int mainbus_found = 0;
62 struct pic_ops *isa_pic;
63
64 #ifdef PIC_PREPIVR
65 vaddr_t prep_intr_reg;
66 uint32_t prep_intr_reg_off;
67 #endif
68
69 extern ofw_pic_node_t picnodes[8];
70 extern int nrofpics;
71 extern int primary_pic;
72
73 #ifdef PIC_PREPIVR
74 static struct pic_ops *
init_prepivr(int node)75 init_prepivr(int node)
76 {
77 int pcinode;
78 uint32_t ivr;
79
80 pcinode = OF_finddevice("/pci");
81 if (OF_getprop(pcinode, "8259-interrupt-acknowledge", &ivr,
82 sizeof(ivr)) != sizeof(ivr)) {
83 aprint_error("Incorrectly identified i8259 as prepivr\n");
84 return setup_i8259();
85 }
86 prep_intr_reg = (vaddr_t)mapiodev(ivr, sizeof(uint32_t), false);
87 prep_intr_reg_off = 0; /* hack */
88 if (!prep_intr_reg)
89 panic("startup: no room for interrupt register");
90
91 return setup_prepivr(PIC_IVR_MOT);
92 }
93 #endif
94
95 static int
init_openpic(int node)96 init_openpic(int node)
97 {
98 struct ofw_pci_register aadr;
99 struct ranges {
100 uint32_t pci_hi, pci_mid, pci_lo;
101 uint32_t host;
102 uint32_t size_hi, size_lo;
103 } ranges[6];
104 uint32_t reg[12];
105 int parent, len;
106 #if defined(PIC_OPENPIC) || defined(PIC_DISTOPENPIC)
107 unsigned char *baseaddr;
108 #endif
109 #ifdef PIC_OPENPIC
110 struct ranges *rp = ranges;
111 #endif
112 #ifdef PIC_DISTOPENPIC
113 unsigned char *isu[OPENPIC_MAX_ISUS];
114 int i, j;
115 int isumap[OPENPIC_MAX_ISUS];
116 #endif
117
118 if (OF_getprop(node, "assigned-addresses", &aadr, sizeof(aadr))
119 != sizeof(aadr))
120 goto noaadr;
121
122 parent = OF_parent(node);
123 len = OF_getprop(parent, "ranges", ranges, sizeof(ranges));
124 if (len == -1)
125 goto noaadr;
126
127 #ifdef PIC_OPENPIC
128 while (len >= sizeof(ranges[0])) {
129 if ((rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) ==
130 (aadr.phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) &&
131 (aadr.size_lo + aadr.phys_lo <= (rp->size_lo+rp->host))) {
132 baseaddr = (unsigned char *)mapiodev(
133 rp->host | aadr.phys_lo, aadr.size_lo, false);
134 aprint_normal("Found openpic at %08x\n",
135 rp->host | aadr.phys_lo);
136 setup_openpic(baseaddr, 0);
137 #ifdef MULTIPROCESSOR
138 setup_openpic_ipi();
139 ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
140 for (i=1; i < ncpu; i++) {
141 aprint_verbose("Enabling interrupts "
142 "for cpu%d\n", i);
143 openpic_set_priority(i, 0);
144 }
145 #endif
146 return TRUE;
147 }
148 rp++;
149 len -= sizeof(ranges[0]);
150 }
151 #endif
152 return FALSE;
153 noaadr:
154 /* this isn't a PCI-attached openpic */
155 len = OF_getprop(node, "reg", ®, sizeof(reg));
156 if (len < sizeof(int)*2)
157 return FALSE;
158
159 if (len == sizeof(int)*2) {
160 aprint_verbose("Found openpic at %08x\n", reg[0]);
161 #ifdef PIC_OPENPIC
162 baseaddr = (unsigned char *)mapiodev(reg[0], reg[1], false);
163 (void)setup_openpic(baseaddr, 0);
164 #ifdef MULTIPROCESSOR
165 setup_openpic_ipi();
166 ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
167 for (i=1; i < ncpu; i++) {
168 aprint_verbose("Enabling interrupts for cpu%d\n", i);
169 openpic_set_priority(i, 0);
170 }
171 #endif
172 return TRUE;
173 #else
174 aprint_error("No openpic support compiled into kernel!");
175 return FALSE;
176 #endif
177 }
178
179 #ifdef PIC_DISTOPENPIC
180 /* otherwise, we have a distributed openpic */
181 i = len/(sizeof(int)*2) - 1;
182 if (i == 0)
183 return FALSE;
184 if (i > OPENPIC_MAX_ISUS)
185 aprint_error("Increase OPENPIC_MAX_ISUS to %d\n", i);
186
187 baseaddr = (unsigned char *)mapiodev(reg[0], 0x40000, false);
188 aprint_verbose("Found openpic at %08x\n", reg[0]);
189
190 for (j=0; j < i; j++) {
191 isu[j] = (unsigned char *)mapiodev(reg[(j+1)*2],
192 reg[(j+1)*2+1], false);
193 isumap[j] = reg[(j+1)*2+1];
194 }
195 (void)setup_distributed_openpic(baseaddr, i, (void **)isu, isumap);
196 #ifdef MULTIPROCESSOR
197 setup_openpic_ipi();
198 ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
199 for (i=1; i < ncpu; i++) {
200 aprint_verbose("Enabling interrupts for cpu%d\n", i);
201 openpic_set_priority(i, 0);
202 }
203 #endif
204 return TRUE;
205 #endif
206 aprint_error("PIC support not present or PIC error\n");
207 return FALSE;
208 }
209
210
211 /*
212 * Probe for the mainbus; always succeeds.
213 */
214 int
mainbus_match(device_t parent,cfdata_t cf,void * aux)215 mainbus_match(device_t parent, cfdata_t cf, void *aux)
216 {
217 if (mainbus_found)
218 return 0;
219 return 1;
220 }
221
222 /*
223 * Attach the mainbus.
224 */
225 void
mainbus_attach(device_t parent,device_t self,void * aux)226 mainbus_attach(device_t parent, device_t self, void *aux)
227 {
228 struct ofbus_attach_args oba;
229 struct confargs ca;
230 int node, rtnode, i;
231 u_int32_t reg[4];
232 char name[32];
233
234 mainbus_found = 1;
235
236 aprint_normal("\n");
237
238 /* Find rtas first */
239 rtnode = OF_finddevice("/rtas");
240 if (rtnode != -1) {
241 memset(name, 0, sizeof(name));
242 if (OF_getprop(rtnode, "name", name, sizeof(name)) != -1) {
243 ca.ca_name = name;
244 ca.ca_node = rtnode;
245 ca.ca_nreg = OF_getprop(rtnode, "reg", reg,
246 sizeof(reg));
247 ca.ca_reg = reg;
248 config_found(self, &ca, NULL, CFARGS_NONE);
249 }
250 }
251
252 /* Now find CPU's */
253 for (i = 0; i < CPU_MAXNUM; i++) {
254 ca.ca_name = "cpu";
255 ca.ca_reg = reg;
256 reg[0] = i;
257 config_found(self, &ca, NULL, CFARGS_NONE);
258 }
259
260 node = OF_peer(0);
261 if (node) {
262 oba.oba_busname = "ofw";
263 oba.oba_phandle = node;
264 config_found(self, &oba, NULL, CFARGS_NONE);
265 }
266
267 if (strcmp(model_name, "Pegasos2") == 0) {
268 /*
269 * Configure to System Controller MV64361.
270 * And skip other devices. These attached from it.
271 */
272 ca.ca_name = "gt";
273
274 config_found(self, &ca, NULL, CFARGS_NONE);
275
276 goto config_fin;
277 }
278
279 /* this primarily searches for pci bridges on the root bus */
280 for (node = OF_child(OF_finddevice("/")); node; node = OF_peer(node)) {
281 memset(name, 0, sizeof(name));
282 if (OF_getprop(node, "name", name, sizeof(name)) == -1)
283 continue;
284 /* skip rtas */
285 if (node == rtnode)
286 continue;
287
288 ca.ca_name = name;
289 ca.ca_node = node;
290 ca.ca_nreg = OF_getprop(node, "reg", reg, sizeof(reg));
291 ca.ca_reg = reg;
292
293 config_found(self, &ca, NULL, CFARGS_NONE);
294 }
295
296 config_fin:
297 pic_finish_setup();
298 }
299
300 void
init_interrupt(void)301 init_interrupt(void)
302 {
303 /* Do nothing, not ready yet */
304 }
305
306 void
init_ofppc_interrupt(void)307 init_ofppc_interrupt(void)
308 {
309 int node, i, isa_cascade = 0;
310
311 /* Now setup the PIC's */
312 node = OF_finddevice("/");
313 if (node <= 0)
314 panic("Can't find root OFW device node\n");
315 genofw_find_ofpics(node);
316 genofw_fixup_picnode_offsets();
317 pic_init();
318
319 /* find ISA first */
320 for (i = 0; i < nrofpics; i++) {
321 if (picnodes[i].type == PICNODE_TYPE_8259) {
322 aprint_debug("calling i8259 setup\n");
323 isa_pic = setup_i8259();
324 }
325 if (picnodes[i].type == PICNODE_TYPE_IVR) {
326 aprint_debug("calling prepivr setup\n");
327 #ifdef PIC_PREPIVR
328 isa_pic = init_prepivr(picnodes[i].node);
329 #else
330 isa_pic = setup_i8259();
331 #endif
332 }
333 }
334 for (i = 0; i < nrofpics; i++) {
335 if (picnodes[i].type == PICNODE_TYPE_8259)
336 continue;
337 if (picnodes[i].type == PICNODE_TYPE_IVR)
338 continue;
339 if (picnodes[i].type == PICNODE_TYPE_OPENPIC) {
340 aprint_debug("calling openpic setup\n");
341 if (isa_pic != NULL)
342 isa_cascade = 1;
343 (void)init_openpic(picnodes[i].node);
344 } else
345 aprint_error("Unhandled pic node type node=%x\n",
346 picnodes[i].node);
347 }
348 if (isa_cascade) {
349 primary_pic = 1;
350 intr_establish(16, IST_LEVEL, IPL_HIGH, pic_handle_intr,
351 isa_pic);
352 }
353 }
354