xref: /netbsd-src/sys/arch/ofppc/ofppc/mainbus.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
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", &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