Home | History | Annotate | Line # | Download | only in ofppc
      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 *
     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
     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
    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
    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
    301 init_interrupt(void)
    302 {
    303 	/* Do nothing, not ready yet */
    304 }
    305 
    306 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