Home | History | Annotate | Line # | Download | only in prep
      1 /*	$NetBSD: machdep.c,v 1.82 2026/09/08 11:29:14 macallan Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
      5  * Copyright (C) 1995, 1996 TooLs GmbH.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by TooLs GmbH.
     19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.82 2026/09/08 11:29:14 macallan Exp $");
     36 
     37 #include "opt_compat_netbsd.h"
     38 #include "opt_openpic.h"
     39 
     40 #include <sys/param.h>
     41 #include <sys/buf.h>
     42 #include <sys/bus.h>
     43 #include <sys/conf.h>
     44 #include <sys/device.h>
     45 #include <sys/exec.h>
     46 #include <sys/extent.h>
     47 #include <sys/intr.h>
     48 #include <sys/kernel.h>
     49 #include <sys/mbuf.h>
     50 #include <sys/mount.h>
     51 #include <sys/msgbuf.h>
     52 #include <sys/proc.h>
     53 #include <sys/reboot.h>
     54 #include <sys/syscallargs.h>
     55 #include <sys/syslog.h>
     56 #include <sys/systm.h>
     57 #include <sys/sysctl.h>
     58 
     59 #include <uvm/uvm_extern.h>
     60 
     61 #include <machine/autoconf.h>
     62 #include <machine/bootinfo.h>
     63 #include <machine/platform.h>
     64 #include <machine/powerpc.h>
     65 #include <machine/residual.h>
     66 
     67 #include <powerpc/pmap.h>
     68 #include <powerpc/trap.h>
     69 
     70 #include <powerpc/oea/bat.h>
     71 #include <powerpc/openpic.h>
     72 #include <powerpc/pic/picvar.h>
     73 #ifdef MULTIPROCESSOR
     74 #include <powerpc/pic/ipivar.h>
     75 #endif
     76 
     77 #include <dev/cons.h>
     78 
     79 #include "com.h"
     80 #if (NCOM > 0)
     81 #include <sys/termios.h>
     82 #include <dev/ic/comreg.h>
     83 #include <dev/ic/comvar.h>
     84 #endif
     85 
     86 #include "opt_interrupt.h"
     87 
     88 void initppc(u_long, u_long, u_int, void *);
     89 void dumpsys(void);
     90 static void prep_init(void);
     91 static void init_intr(void);
     92 
     93 char bootinfo[BOOTINFO_MAXSIZE];
     94 char bootpath[256];
     95 
     96 vaddr_t prep_intr_reg;			/* PReP interrupt vector register */
     97 uint32_t prep_intr_reg_off;		/* IVR offset within the mapped page */
     98 
     99 #define	OFMEMREGIONS	32
    100 struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS];
    101 
    102 paddr_t avail_end;			/* XXX temporary */
    103 struct pic_ops *isa_pic;
    104 int isa_pcmciamask = 0x8b28;
    105 uint32_t busfreq;
    106 
    107 extern int primary_pic;
    108 extern struct platform_quirkdata platform_quirks[];
    109 
    110 RESIDUAL *res;
    111 RESIDUAL resdata;
    112 
    113 void
    114 initppc(u_long startkernel, u_long endkernel, u_int args, void *btinfo)
    115 {
    116 
    117 	/*
    118 	 * copy bootinfo
    119 	 */
    120 	memcpy(bootinfo, btinfo, sizeof(bootinfo));
    121 
    122 	/*
    123 	 * copy residual data
    124 	 */
    125 	{
    126 		struct btinfo_residual *resinfo;
    127 
    128 		resinfo =
    129 		    (struct btinfo_residual *)lookup_bootinfo(BTINFO_RESIDUAL);
    130 		if (!resinfo)
    131 			panic("not found residual information in bootinfo");
    132 
    133 		if (((RESIDUAL *)resinfo->addr != 0) &&
    134 		    ((RESIDUAL *)resinfo->addr)->ResidualLength != 0) {
    135 			memcpy(&resdata, resinfo->addr, sizeof(resdata));
    136 			res = &resdata;
    137 		} else
    138 			panic("No residual data.");
    139 	}
    140 	aprint_normal("got residual data\n");
    141 
    142 	/*
    143 	 * Set memory region
    144 	 */
    145 	{
    146 		u_long memsize = res->TotalMemory;
    147 
    148 		physmemr[0].start = 0;
    149 		physmemr[0].size = memsize & ~PGOFSET;
    150 		availmemr[0].start = (endkernel + PGOFSET) & ~PGOFSET;
    151 		availmemr[0].size = memsize - availmemr[0].start;
    152 	}
    153 	avail_end = physmemr[0].start + physmemr[0].size;    /* XXX temporary */
    154 
    155 	/*
    156 	 * Set CPU clock
    157 	 */
    158 	{
    159 		struct btinfo_clock *clockinfo;
    160 		extern u_long ticks_per_sec, ns_per_tick;
    161 		VPD *vpd;
    162 
    163 		clockinfo =
    164 		    (struct btinfo_clock *)lookup_bootinfo(BTINFO_CLOCK);
    165 		if (!clockinfo)
    166 			panic("not found clock information in bootinfo");
    167 
    168 		ticks_per_sec = clockinfo->ticks_per_sec;
    169 		ns_per_tick = 1000000000 / ticks_per_sec;
    170 
    171 		vpd = &res->VitalProductData;
    172 		busfreq = be32toh(vpd->ProcessorBusHz);
    173 	}
    174 
    175 	prep_initppc(startkernel, endkernel, args,
    176 	    /* rs6k-style PCI bridge */
    177 	    0xbf800000, BAT_BL_8M,		/* XXX magic number */
    178 	    0);
    179 }
    180 
    181 /*
    182  * Machine dependent startup code.
    183  */
    184 void
    185 cpu_startup(void)
    186 {
    187 	/*
    188 	 * Do common startup.
    189 	 */
    190 	oea_startup(res->VitalProductData.PrintableModel);
    191 
    192 	/*
    193 	 * General prep setup using pnp residual. Also provides for
    194 	 * external interrupt handler install
    195 	 */
    196 	prep_init();
    197 
    198 	/*
    199 	 * Now allow hardware interrupts.
    200 	 */
    201 	{
    202 		int msr;
    203 
    204 		splraise(-1);
    205 		__asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
    206 			      : "=r"(msr) : "K"(PSL_EE));
    207 	}
    208 	/*
    209 	 * Now safe for bus space allocation to use malloc.
    210 	 */
    211 	bus_space_mallocok();
    212 }
    213 
    214 /*
    215  * lookup_bootinfo:
    216  * Look up information in bootinfo of boot loader.
    217  */
    218 void *
    219 lookup_bootinfo(int type)
    220 {
    221 	struct btinfo_common *bt;
    222 	struct btinfo_common *help = (struct btinfo_common *)bootinfo;
    223 
    224 	do {
    225 		bt = help;
    226 		if (bt->type == type)
    227 			return (help);
    228 		help = (struct btinfo_common *)((char*)help + bt->next);
    229 	} while (bt->next &&
    230 		(size_t)help < (size_t)bootinfo + sizeof (bootinfo));
    231 
    232 	return (NULL);
    233 }
    234 
    235 /*
    236  * Halt or reboot the machine after syncing/dumping according to howto.
    237  */
    238 void
    239 cpu_reboot(int howto, char *what)
    240 {
    241 	static int syncing;
    242 
    243 	if (cold) {
    244 		howto |= RB_HALT;
    245 		goto halt_sys;
    246 	}
    247 
    248 	boothowto = howto;
    249 	if ((howto & RB_NOSYNC) == 0 && syncing == 0) {
    250 		syncing = 1;
    251 		vfs_shutdown();		/* sync */
    252 	}
    253 
    254 	/* Disable intr */
    255 	splhigh();
    256 
    257 #ifdef MULTIPROCESSOR
    258 	/* Halt other CPUs */
    259 	ppc_send_ipi(IPI_T_NOTME, PPC_IPI_HALT);
    260 	delay(100000);  /* XXX */
    261 #endif
    262 
    263 	/* Do dump if requested */
    264 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
    265 		oea_dumpsys();
    266 
    267 halt_sys:
    268 	doshutdownhooks();
    269 
    270 	pmf_system_shutdown(boothowto);
    271 
    272 	if (howto & RB_HALT) {
    273                 printf("\n");
    274                 printf("The operating system has halted.\n");
    275                 printf("Please press any key to reboot.\n\n");
    276                 cnpollc(true);	/* for proper keyboard command handling */
    277                 cngetc();
    278                 cnpollc(false);
    279 	}
    280 
    281 	printf("rebooting...\n\n");
    282 
    283 	reset_prep();
    284 
    285 	for (;;)
    286 		continue;
    287 	/* NOTREACHED */
    288 }
    289 
    290 struct powerpc_bus_space prep_eisa_io_space_tag = {
    291 	.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
    292 	.pbs_offset = 0x80000000,
    293 	.pbs_base = 0x00000000,
    294 	.pbs_limit = 0x0000f000,
    295 };
    296 
    297 struct powerpc_bus_space prep_eisa_mem_space_tag = {
    298 	.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE,
    299 	.pbs_offset = 0xC0000000,
    300 	.pbs_base = 0x00000000,
    301 	.pbs_limit = 0x3f000000,
    302 };
    303 
    304 #if defined(PIC_OPENPIC)
    305 
    306 static int
    307 prep_setup_openpic(PPC_DEVICE *dev)
    308 {
    309 	uint32_t l;
    310 	uint8_t *p;
    311 	int tag, size, item, i;
    312 	unsigned char *baseaddr = NULL;
    313 
    314 	l = be32toh(dev->AllocatedOffset);
    315 	p = res->DevicePnPHeap + l;
    316 
    317         i = find_platform_quirk(res->VitalProductData.PrintableModel);
    318 
    319 	/* look for the large vendor item that describes the MPIC's memory
    320 	 * range */
    321 	for (; p[0] != END_TAG; p += size) {
    322 		struct _L4_Pack *pack = (void *)p;
    323 		struct _L4_PPCPack *pa = &pack->L4_Data.L4_PPCPack;
    324 
    325 		tag = *p;
    326 		if (tag_type(p[0]) == PNP_SMALL) {
    327 			size = tag_small_count(tag) + 1;
    328 			continue;
    329 		}
    330 		size = (p[1] | (p[2] << 8)) + 3 /* tag + length */;
    331 		item = tag_large_item_name(tag);
    332 		if (item != LargeVendorItem || pa->Type != LV_GenericAddress)
    333 			continue;
    334 		/* otherwise, we have a memory packet */
    335 		if (pa->PPCData[0] == 1)
    336 			baseaddr = (unsigned char *)mapiodev(
    337 			    le64dec(&pa->PPCData[4]) | PREP_BUS_SPACE_IO,
    338 			    le64dec(&pa->PPCData[12]), false);
    339 		else if (pa->PPCData[0] == 2)
    340 			baseaddr = (unsigned char *)mapiodev(
    341 			    le64dec(&pa->PPCData[4]) | PREP_BUS_SPACE_MEM,
    342 			    le64dec(&pa->PPCData[12]), false);
    343 		if (baseaddr == NULL)
    344 			return 0;
    345 		pic_init();
    346         	if (i != -1 &&
    347 		    (platform_quirks[i].quirk & PLAT_QUIRK_ISA_HANDLER &&
    348                      platform_quirks[i].isa_intr_handler == EXT_INTR_I8259)) {
    349 			isa_pic = setup_prepivr(PIC_IVR_MOT);
    350                 } else
    351 			isa_pic = setup_prepivr(PIC_IVR_IBM);
    352 		(void)setup_openpic(baseaddr, 0);
    353 		/* set the timebase frequency to 1/8th busfreq */
    354 		openpic_write(OPENPIC_TIMER_FREQ, busfreq/8);
    355 		primary_pic = 1;
    356 		/* set up the IVR as a cascade on openpic 0 */
    357 		intr_establish(16, IST_LEVEL_HIGH, IPL_HIGH, pic_handle_intr,
    358 		    isa_pic);
    359 		oea_install_extint(pic_ext_intr);
    360 #ifdef MULTIPROCESSOR
    361 		setup_openpic_ipi();
    362 #endif
    363 		return 1;
    364 	}
    365 	return 0;
    366 }
    367 
    368 #endif /* PIC_OPENPIC */
    369 
    370 /*
    371  * Locate and setup the isa_ivr.
    372  */
    373 
    374 static void
    375 setup_ivr(PPC_DEVICE *dev)
    376 {
    377 	uint32_t l, addr;
    378 	uint8_t *p;
    379 	int tag, size, item;
    380 
    381 	l = be32toh(dev->AllocatedOffset);
    382 	p = res->DevicePnPHeap + l;
    383 
    384 	/* Find the IVR vector's Generic Address in a LVI */
    385 	for (; p[0] != END_TAG; p += size) {
    386 		struct _L4_Pack *pack = (void *)p;
    387 		struct _L4_PPCPack *pa = &pack->L4_Data.L4_PPCPack;
    388 
    389 		tag = *p;
    390 		if (tag_type(p[0]) == PNP_SMALL) {
    391 			size = tag_small_count(tag) + 1;
    392 			continue;
    393 		}
    394 		size = (p[1] | (p[2] << 8)) + 3 /* tag + length */;
    395 		item = tag_large_item_name(tag);
    396 		if (item != LargeVendorItem || pa->Type != LV_GenericAddress)
    397 			continue;
    398 		/* otherwise we have a memory packet */
    399 		addr = le64dec(&pa->PPCData[4]) & ~(PAGE_SIZE-1);
    400 		prep_intr_reg_off = le64dec(&pa->PPCData[4]) & (PAGE_SIZE-1);
    401 		prep_intr_reg = (vaddr_t)mapiodev(addr, PAGE_SIZE, false);
    402 		if (!prep_intr_reg)
    403 			panic("startup: no room for interrupt register");
    404 		return;
    405 	}
    406 }
    407 
    408 /*
    409  * There are a few things that need setting up early on in the prep
    410  * architecture.  Foremost of these is the MPIC (if present) and the
    411  * l2 cache controller.  This is a cut-down version of pnpbus_search()
    412  * that looks for specific devices, and sets them up accordingly.
    413  * This should also look for and wire up the interrupt vector.
    414  */
    415 
    416 static void
    417 prep_init(void)
    418 {
    419 	PPC_DEVICE *ppc_dev;
    420 	int i, foundmpic;
    421 	uint32_t ndev;
    422 
    423 	ndev = be32toh(res->ActualNumDevices);
    424 	ppc_dev = res->Devices;
    425 	foundmpic = 0;
    426 	prep_intr_reg = 0;
    427 
    428 	for (i = 0; i < ((ndev > MAX_DEVICES) ? MAX_DEVICES : ndev); i++) {
    429 		if (ppc_dev[i].DeviceId.DevId == 0x41d00000) /* ISA_PIC */
    430 			setup_ivr(&ppc_dev[i]);
    431 #if defined(PIC_OPENPIC)
    432 		if (ppc_dev[i].DeviceId.DevId == 0x244d000d) { /* MPIC */
    433 			foundmpic = prep_setup_openpic(&ppc_dev[i]);
    434 		}
    435 #endif
    436 
    437 	}
    438 	if (!prep_intr_reg) {
    439 		/*
    440 		 * For some reason we never found one, this is known to
    441 		 * occur on certain motorola VME boards.  Instead we need
    442 		 * to just hardcode it.
    443 		 */
    444 		prep_intr_reg = (vaddr_t) mapiodev(PREP_INTR_REG, PAGE_SIZE, false);
    445 		if (!prep_intr_reg)
    446 			panic("startup: no room for interrupt register");
    447 		prep_intr_reg_off = INTR_VECTOR_REG;
    448 	}
    449 	if (!foundmpic)
    450 		init_intr();
    451 }
    452 
    453 static void
    454 init_intr(void)
    455 {
    456         int i;
    457 
    458 #if defined(PIC_OPENPIC)
    459         openpic_base = 0;
    460 #endif
    461 
    462 	pic_init();
    463         i = find_platform_quirk(res->VitalProductData.PrintableModel);
    464         if (i != -1)
    465                 if (platform_quirks[i].quirk & PLAT_QUIRK_ISA_HANDLER &&
    466                     platform_quirks[i].isa_intr_handler == EXT_INTR_I8259) {
    467 			isa_pic = setup_prepivr(PIC_IVR_MOT);
    468                         return;
    469                 }
    470 	isa_pic = setup_prepivr(PIC_IVR_IBM);
    471         oea_install_extint(pic_ext_intr);
    472 }
    473