#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.81 2025/12/21 07:00:28 skrll Exp $");
#include "opt_compat_netbsd.h"
#include "opt_openpic.h"
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/exec.h>
#include <sys/extent.h>
#include <sys/intr.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/mount.h>
#include <sys/msgbuf.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/syscallargs.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <uvm/uvm_extern.h>
#include <machine/autoconf.h>
#include <machine/bootinfo.h>
#include <machine/platform.h>
#include <machine/powerpc.h>
#include <machine/residual.h>
#include <powerpc/pmap.h>
#include <powerpc/trap.h>
#include <powerpc/oea/bat.h>
#include <powerpc/openpic.h>
#include <powerpc/pic/picvar.h>
#ifdef MULTIPROCESSOR
#include <powerpc/pic/ipivar.h>
#endif
#include <dev/cons.h>
#include "com.h"
#if (NCOM > 0)
#include <sys/termios.h>
#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
#endif
#include "opt_interrupt.h"
void initppc(u_long, u_long, u_int, void *);
void dumpsys(void);
static void prep_init(void);
static void init_intr(void);
char bootinfo[BOOTINFO_MAXSIZE];
char bootpath[256];
vaddr_t prep_intr_reg;
uint32_t prep_intr_reg_off;
#define OFMEMREGIONS 32
struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS];
paddr_t avail_end;
struct pic_ops *isa_pic;
int isa_pcmciamask = 0x8b28;
uint32_t busfreq;
extern int primary_pic;
extern struct platform_quirkdata platform_quirks[];
RESIDUAL *res;
RESIDUAL resdata;
void
initppc(u_long startkernel, u_long endkernel, u_int args, void *btinfo)
{
memcpy(bootinfo, btinfo, sizeof(bootinfo));
{
struct btinfo_residual *resinfo;
resinfo =
(struct btinfo_residual *)lookup_bootinfo(BTINFO_RESIDUAL);
if (!resinfo)
panic("not found residual information in bootinfo");
if (((RESIDUAL *)resinfo->addr != 0) &&
((RESIDUAL *)resinfo->addr)->ResidualLength != 0) {
memcpy(&resdata, resinfo->addr, sizeof(resdata));
res = &resdata;
} else
panic("No residual data.");
}
aprint_normal("got residual data\n");
{
u_long memsize = res->TotalMemory;
physmemr[0].start = 0;
physmemr[0].size = memsize & ~PGOFSET;
availmemr[0].start = (endkernel + PGOFSET) & ~PGOFSET;
availmemr[0].size = memsize - availmemr[0].start;
}
avail_end = physmemr[0].start + physmemr[0].size;
{
struct btinfo_clock *clockinfo;
extern u_long ticks_per_sec, ns_per_tick;
VPD *vpd;
clockinfo =
(struct btinfo_clock *)lookup_bootinfo(BTINFO_CLOCK);
if (!clockinfo)
panic("not found clock information in bootinfo");
ticks_per_sec = clockinfo->ticks_per_sec;
ns_per_tick = 1000000000 / ticks_per_sec;
vpd = &res->VitalProductData;
busfreq = be32toh(vpd->ProcessorBusHz);
}
prep_initppc(startkernel, endkernel, args,
0xbf800000, BAT_BL_8M,
0);
}
void
cpu_startup(void)
{
oea_startup(res->VitalProductData.PrintableModel);
prep_init();
{
int msr;
splraise(-1);
__asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
: "=r"(msr) : "K"(PSL_EE));
}
bus_space_mallocok();
}
void *
lookup_bootinfo(int type)
{
struct btinfo_common *bt;
struct btinfo_common *help = (struct btinfo_common *)bootinfo;
do {
bt = help;
if (bt->type == type)
return (help);
help = (struct btinfo_common *)((char*)help + bt->next);
} while (bt->next &&
(size_t)help < (size_t)bootinfo + sizeof (bootinfo));
return (NULL);
}
void
cpu_reboot(int howto, char *what)
{
static int syncing;
if (cold) {
howto |= RB_HALT;
goto halt_sys;
}
boothowto = howto;
if ((howto & RB_NOSYNC) == 0 && syncing == 0) {
syncing = 1;
vfs_shutdown();
}
splhigh();
#ifdef MULTIPROCESSOR
ppc_send_ipi(IPI_T_NOTME, PPC_IPI_HALT);
delay(100000);
#endif
if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
oea_dumpsys();
halt_sys:
doshutdownhooks();
pmf_system_shutdown(boothowto);
if (howto & RB_HALT) {
printf("\n");
printf("The operating system has halted.\n");
printf("Please press any key to reboot.\n\n");
cnpollc(true);
cngetc();
cnpollc(false);
}
printf("rebooting...\n\n");
reset_prep();
for (;;)
continue;
}
struct powerpc_bus_space prep_eisa_io_space_tag = {
.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
.pbs_offset = 0x80000000,
.pbs_base = 0x00000000,
.pbs_limit = 0x0000f000,
};
struct powerpc_bus_space prep_eisa_mem_space_tag = {
.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE,
.pbs_offset = 0xC0000000,
.pbs_base = 0x00000000,
.pbs_limit = 0x3f000000,
};
#if defined(PIC_OPENPIC)
static int
prep_setup_openpic(PPC_DEVICE *dev)
{
uint32_t l;
uint8_t *p;
int tag, size, item, i;
unsigned char *baseaddr = NULL;
l = be32toh(dev->AllocatedOffset);
p = res->DevicePnPHeap + l;
i = find_platform_quirk(res->VitalProductData.PrintableModel);
for (; p[0] != END_TAG; p += size) {
struct _L4_Pack *pack = (void *)p;
struct _L4_PPCPack *pa = &pack->L4_Data.L4_PPCPack;
tag = *p;
if (tag_type(p[0]) == PNP_SMALL) {
size = tag_small_count(tag) + 1;
continue;
}
size = (p[1] | (p[2] << 8)) + 3 ;
item = tag_large_item_name(tag);
if (item != LargeVendorItem || pa->Type != LV_GenericAddress)
continue;
if (pa->PPCData[0] == 1)
baseaddr = (unsigned char *)mapiodev(
le64dec(&pa->PPCData[4]) | PREP_BUS_SPACE_IO,
le64dec(&pa->PPCData[12]), false);
else if (pa->PPCData[0] == 2)
baseaddr = (unsigned char *)mapiodev(
le64dec(&pa->PPCData[4]) | PREP_BUS_SPACE_MEM,
le64dec(&pa->PPCData[12]), false);
if (baseaddr == NULL)
return 0;
pic_init();
if (i != -1 &&
(platform_quirks[i].quirk & PLAT_QUIRK_ISA_HANDLER &&
platform_quirks[i].isa_intr_handler == EXT_INTR_I8259)) {
isa_pic = setup_prepivr(PIC_IVR_MOT);
} else
isa_pic = setup_prepivr(PIC_IVR_IBM);
(void)setup_openpic(baseaddr, 0);
openpic_write(OPENPIC_TIMER_FREQ, busfreq/8);
primary_pic = 1;
intr_establish(16, IST_LEVEL, IPL_HIGH, pic_handle_intr,
isa_pic);
oea_install_extint(pic_ext_intr);
#ifdef MULTIPROCESSOR
setup_openpic_ipi();
#endif
return 1;
}
return 0;
}
#endif
static void
setup_ivr(PPC_DEVICE *dev)
{
uint32_t l, addr;
uint8_t *p;
int tag, size, item;
l = be32toh(dev->AllocatedOffset);
p = res->DevicePnPHeap + l;
for (; p[0] != END_TAG; p += size) {
struct _L4_Pack *pack = (void *)p;
struct _L4_PPCPack *pa = &pack->L4_Data.L4_PPCPack;
tag = *p;
if (tag_type(p[0]) == PNP_SMALL) {
size = tag_small_count(tag) + 1;
continue;
}
size = (p[1] | (p[2] << 8)) + 3 ;
item = tag_large_item_name(tag);
if (item != LargeVendorItem || pa->Type != LV_GenericAddress)
continue;
addr = le64dec(&pa->PPCData[4]) & ~(PAGE_SIZE-1);
prep_intr_reg_off = le64dec(&pa->PPCData[4]) & (PAGE_SIZE-1);
prep_intr_reg = (vaddr_t)mapiodev(addr, PAGE_SIZE, false);
if (!prep_intr_reg)
panic("startup: no room for interrupt register");
return;
}
}
static void
prep_init(void)
{
PPC_DEVICE *ppc_dev;
int i, foundmpic;
uint32_t ndev;
ndev = be32toh(res->ActualNumDevices);
ppc_dev = res->Devices;
foundmpic = 0;
prep_intr_reg = 0;
for (i = 0; i < ((ndev > MAX_DEVICES) ? MAX_DEVICES : ndev); i++) {
if (ppc_dev[i].DeviceId.DevId == 0x41d00000)
setup_ivr(&ppc_dev[i]);
#if defined(PIC_OPENPIC)
if (ppc_dev[i].DeviceId.DevId == 0x244d000d) {
foundmpic = prep_setup_openpic(&ppc_dev[i]);
}
#endif
}
if (!prep_intr_reg) {
prep_intr_reg = (vaddr_t) mapiodev(PREP_INTR_REG, PAGE_SIZE, false);
if (!prep_intr_reg)
panic("startup: no room for interrupt register");
prep_intr_reg_off = INTR_VECTOR_REG;
}
if (!foundmpic)
init_intr();
}
static void
init_intr(void)
{
int i;
#if defined(PIC_OPENPIC)
openpic_base = 0;
#endif
pic_init();
i = find_platform_quirk(res->VitalProductData.PrintableModel);
if (i != -1)
if (platform_quirks[i].quirk & PLAT_QUIRK_ISA_HANDLER &&
platform_quirks[i].isa_intr_handler == EXT_INTR_I8259) {
isa_pic = setup_prepivr(PIC_IVR_MOT);
return;
}
isa_pic = setup_prepivr(PIC_IVR_IBM);
oea_install_extint(pic_ext_intr);
}