#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.33 2026/06/30 22:28:00 rkujawa Exp $");
#include "opt_interrupt.h"
#include "opt_multiprocessor.h"
#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <dev/pci/pcivar.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>
#include <arch/powerpc/pic/picvar.h>
#ifdef MULTIPROCESSOR
#include <arch/powerpc/pic/ipivar.h>
#endif
#include <machine/pci_machdep.h>
#include <machine/autoconf.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
int mainbus_match(device_t, cfdata_t, void *);
void mainbus_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(mainbus, 0,
mainbus_match, mainbus_attach, NULL, NULL);
int mainbus_found = 0;
struct pic_ops *isa_pic;
#ifdef PIC_PREPIVR
vaddr_t prep_intr_reg;
uint32_t prep_intr_reg_off;
#endif
extern ofw_pic_node_t picnodes[8];
extern int nrofpics;
extern int primary_pic;
#ifdef PIC_PREPIVR
static struct pic_ops *
init_prepivr(int node)
{
int pcinode;
uint32_t ivr;
pcinode = OF_finddevice("/pci");
if (OF_getprop(pcinode, "8259-interrupt-acknowledge", &ivr,
sizeof(ivr)) != sizeof(ivr)) {
aprint_error("Incorrectly identified i8259 as prepivr\n");
return setup_i8259();
}
prep_intr_reg = (vaddr_t)mapiodev(ivr, sizeof(uint32_t), false);
prep_intr_reg_off = 0;
if (!prep_intr_reg)
panic("startup: no room for interrupt register");
return setup_prepivr(PIC_IVR_MOT);
}
#endif
static int
init_openpic(int node)
{
struct ofw_pci_register aadr;
struct ranges {
uint32_t pci_hi, pci_mid, pci_lo;
uint32_t host;
uint32_t size_hi, size_lo;
} ranges[6];
uint32_t reg[12];
int parent, len;
#if defined(PIC_OPENPIC) || defined(PIC_DISTOPENPIC)
unsigned char *baseaddr;
#endif
#ifdef PIC_OPENPIC
struct ranges *rp = ranges;
#endif
#ifdef PIC_DISTOPENPIC
unsigned char *isu[OPENPIC_MAX_ISUS];
int i, j;
int isumap[OPENPIC_MAX_ISUS];
#endif
if (OF_getprop(node, "assigned-addresses", &aadr, sizeof(aadr))
!= sizeof(aadr))
goto noaadr;
parent = OF_parent(node);
len = OF_getprop(parent, "ranges", ranges, sizeof(ranges));
if (len == -1)
goto noaadr;
#ifdef PIC_OPENPIC
while (len >= sizeof(ranges[0])) {
if ((rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) ==
(aadr.phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) &&
(aadr.size_lo + aadr.phys_lo <= (rp->size_lo+rp->host))) {
baseaddr = (unsigned char *)mapiodev(
rp->host | aadr.phys_lo, aadr.size_lo, false);
aprint_normal("Found openpic at %08x\n",
rp->host | aadr.phys_lo);
setup_openpic(baseaddr, 0);
#ifdef MULTIPROCESSOR
setup_openpic_ipi();
ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
for (i=1; i < ncpu; i++) {
aprint_verbose("Enabling interrupts "
"for cpu%d\n", i);
openpic_set_priority(i, 0);
}
#endif
return TRUE;
}
rp++;
len -= sizeof(ranges[0]);
}
#endif
return FALSE;
noaadr:
len = OF_getprop(node, "reg", ®, sizeof(reg));
if (len < sizeof(int)*2)
return FALSE;
if (len == sizeof(int)*2) {
aprint_verbose("Found openpic at %08x\n", reg[0]);
#ifdef PIC_OPENPIC
baseaddr = (unsigned char *)mapiodev(reg[0], reg[1], false);
(void)setup_openpic(baseaddr, 0);
#ifdef MULTIPROCESSOR
setup_openpic_ipi();
ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
for (i=1; i < ncpu; i++) {
aprint_verbose("Enabling interrupts for cpu%d\n", i);
openpic_set_priority(i, 0);
}
#endif
return TRUE;
#else
aprint_error("No openpic support compiled into kernel!");
return FALSE;
#endif
}
#ifdef PIC_DISTOPENPIC
i = len/(sizeof(int)*2) - 1;
if (i == 0)
return FALSE;
if (i > OPENPIC_MAX_ISUS)
aprint_error("Increase OPENPIC_MAX_ISUS to %d\n", i);
baseaddr = (unsigned char *)mapiodev(reg[0], 0x40000, false);
aprint_verbose("Found openpic at %08x\n", reg[0]);
for (j=0; j < i; j++) {
isu[j] = (unsigned char *)mapiodev(reg[(j+1)*2],
reg[(j+1)*2+1], false);
isumap[j] = reg[(j+1)*2+1];
}
(void)setup_distributed_openpic(baseaddr, i, (void **)isu, isumap);
#ifdef MULTIPROCESSOR
setup_openpic_ipi();
ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
for (i=1; i < ncpu; i++) {
aprint_verbose("Enabling interrupts for cpu%d\n", i);
openpic_set_priority(i, 0);
}
#endif
return TRUE;
#endif
aprint_error("PIC support not present or PIC error\n");
return FALSE;
}
int
mainbus_match(device_t parent, cfdata_t cf, void *aux)
{
if (mainbus_found)
return 0;
return 1;
}
void
mainbus_attach(device_t parent, device_t self, void *aux)
{
struct ofbus_attach_args oba;
struct confargs ca;
int node, rtnode, i;
u_int32_t reg[4];
char name[32];
mainbus_found = 1;
aprint_normal("\n");
rtnode = OF_finddevice("/rtas");
if (rtnode != -1) {
memset(name, 0, sizeof(name));
if (OF_getprop(rtnode, "name", name, sizeof(name)) != -1) {
ca.ca_name = name;
ca.ca_node = rtnode;
ca.ca_nreg = OF_getprop(rtnode, "reg", reg,
sizeof(reg));
ca.ca_reg = reg;
config_found(self, &ca, NULL, CFARGS_NONE);
}
}
for (i = 0; i < CPU_MAXNUM; i++) {
ca.ca_name = "cpu";
ca.ca_reg = reg;
reg[0] = i;
config_found(self, &ca, NULL, CFARGS_NONE);
}
node = OF_peer(0);
if (node) {
oba.oba_busname = "ofw";
oba.oba_phandle = node;
config_found(self, &oba, NULL, CFARGS_NONE);
}
if (strcmp(model_name, "Pegasos2") == 0) {
ca.ca_name = "gt";
config_found(self, &ca, NULL, CFARGS_NONE);
goto config_fin;
}
for (node = OF_child(OF_finddevice("/")); node; node = OF_peer(node)) {
memset(name, 0, sizeof(name));
if (OF_getprop(node, "name", name, sizeof(name)) == -1)
continue;
if (node == rtnode)
continue;
ca.ca_name = name;
ca.ca_node = node;
ca.ca_nreg = OF_getprop(node, "reg", reg, sizeof(reg));
ca.ca_reg = reg;
config_found(self, &ca, NULL, CFARGS_NONE);
}
config_fin:
pic_finish_setup();
}
void
init_interrupt(void)
{
}
void
init_ofppc_interrupt(void)
{
int node, i, isa_cascade = 0;
node = OF_finddevice("/");
if (node <= 0)
panic("Can't find root OFW device node\n");
genofw_find_ofpics(node);
genofw_fixup_picnode_offsets();
pic_init();
for (i = 0; i < nrofpics; i++) {
if (picnodes[i].type == PICNODE_TYPE_8259) {
aprint_debug("calling i8259 setup\n");
#ifdef PIC_I8259
isa_pic = setup_i8259();
#endif
}
if (picnodes[i].type == PICNODE_TYPE_IVR) {
aprint_debug("calling prepivr setup\n");
#ifdef PIC_PREPIVR
isa_pic = init_prepivr(picnodes[i].node);
#elif defined(PIC_I8259)
isa_pic = setup_i8259();
#endif
}
}
for (i = 0; i < nrofpics; i++) {
if (picnodes[i].type == PICNODE_TYPE_8259)
continue;
if (picnodes[i].type == PICNODE_TYPE_IVR)
continue;
if (picnodes[i].type == PICNODE_TYPE_OPENPIC) {
aprint_debug("calling openpic setup\n");
if (isa_pic != NULL)
isa_cascade = 1;
(void)init_openpic(picnodes[i].node);
} else if (picnodes[i].type == PICNODE_TYPE_MPC5200) {
aprint_debug("mpc5200 SIU pic set up as a device\n");
} else
aprint_error("Unhandled pic node type node=%x\n",
picnodes[i].node);
}
if (isa_cascade) {
primary_pic = 1;
intr_establish(16, IST_LEVEL, IPL_HIGH, pic_handle_intr,
isa_pic);
}
}