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