1 /* $NetBSD: machdep.c,v 1.13 2023/12/20 15:29:06 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: machdep.c,v 1.13 2023/12/20 15:29:06 thorpej Exp $"); 34 35 #include "opt_compat_netbsd.h" 36 #include "opt_ddb.h" 37 #include "opt_modular.h" 38 39 #include <sys/param.h> 40 #include <sys/buf.h> 41 #include <sys/bus.h> 42 #include <sys/conf.h> 43 #include <sys/device.h> 44 #include <sys/exec.h> 45 #include <sys/extent.h> 46 #include <sys/intr.h> 47 #include <sys/kernel.h> 48 #include <sys/ksyms.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/sysctl.h> 56 #include <sys/syslog.h> 57 #include <sys/systm.h> 58 59 #include <uvm/uvm_extern.h> 60 61 #include <machine/autoconf.h> 62 #include <machine/bootinfo.h> 63 #include <machine/powerpc.h> 64 #include <machine/iplcb.h> 65 66 #include <powerpc/pmap.h> 67 #include <powerpc/trap.h> 68 69 #include <powerpc/oea/bat.h> 70 #include <powerpc/pio.h> 71 #include <powerpc/pic/picvar.h> 72 73 #include <dev/cons.h> 74 75 #include "com.h" 76 #if (NCOM > 0) 77 #include <sys/termios.h> 78 #include <dev/ic/comreg.h> 79 #include <dev/ic/comvar.h> 80 void comsoft(void); 81 #endif 82 83 #ifdef DDB 84 #include <powerpc/db_machdep.h> 85 #include <ddb/db_extern.h> 86 #endif 87 88 #include "ksyms.h" 89 90 void initppc(u_long, u_long, u_int, void *); 91 void dumpsys(void); 92 void strayintr(int); 93 void rs6000_bus_space_init(void); 94 void setled(uint32_t); 95 void say_hi(void); 96 static void init_intr(void); 97 98 char bootinfo[BOOTINFO_MAXSIZE]; 99 char bootpath[256]; 100 struct ipl_directory *ipldir; 101 struct ipl_cb *iplcb; 102 struct ipl_info *iplinfo; 103 int led_avail; 104 struct sys_info *sysinfo; 105 struct buc_info *bucinfo[MAX_BUCS]; 106 int nrofbucs; 107 108 struct pic_ops *pic_iocc; 109 110 #define OFMEMREGIONS 32 111 struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS]; 112 113 paddr_t avail_end; /* XXX temporary */ 114 extern register_t iosrtable[16]; 115 116 #if NKSYMS || defined(DDB) || defined(MODULAR) 117 extern void *endsym, *startsym; 118 #endif 119 120 #ifndef CONCOMADDR 121 #define CONCOMADDR 0x30 122 #endif 123 124 #ifndef CONSPEED 125 #define CONSPEED 9600 126 #endif 127 128 #ifndef CONMODE 129 #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ 130 #endif 131 132 int comcnspeed = CONSPEED; 133 int comcnmode = CONMODE; 134 struct consdev kcomcons; 135 static void kcomcnputc(dev_t, int); 136 137 extern struct pic_ops *setup_iocc(void); 138 139 140 void 141 say_hi(void) 142 { 143 printf("HELLO?!\n"); 144 setled(0x55500000); 145 #ifdef DDB 146 Debugger(); 147 #endif 148 #if 0 149 li %r28,0x00000041 /* PUT A to R28*/ 150 li %r29,0x30 /* put serial addr to r29*/ 151 addis %r29,%r29,0xc000 /* r29 now holds serial addr*/ 152 stb %r28,0(%r29) /* slam it to serial port*/ 153 loopforever: 154 bla loopforever 155 #endif 156 } 157 /* 158 * Set LED's. Yes I know this is ugly. Yes I will rewrite it in pure asm. 159 */ 160 void 161 setled(uint32_t val) 162 { 163 #if 0 164 register_t savemsr, msr, savesr15; 165 166 __asm volatile ("mfmsr %0" : "=r"(savemsr)); 167 msr = savemsr & ~PSL_DR; 168 __asm volatile ("mtmsr %0" : : "r"(msr)); 169 170 __asm volatile ("mfsr %0,15;isync" : "=r"(savesr15)); 171 __asm volatile ("mtsr 15,%0" : : "r"(0x82040080)); 172 __asm volatile ("mtmsr %0" : : "r"(msr|PSL_DR)); 173 __asm volatile ("isync"); 174 *(uint32_t *)0xF0A00300 = val; 175 __asm volatile ("mtmsr %0" : : "r"(savemsr)); 176 __asm volatile ("mtsr 15,%0;isync" : : "r"(savesr15)); 177 #endif 178 if (led_avail) 179 *(uint32_t *)0xFF600300 = val; 180 } 181 182 #if 0 183 int 184 power_cputype(void) 185 { 186 uint32_t model; 187 188 model = iplinfo->model; 189 if (model & 0x08000000) { 190 /* ppc */ 191 return 0; 192 } else if (model & 0x02000000) 193 return POWER_RSC; 194 else if (model & 0x04000000) 195 return POWER_2; 196 else 197 return POWER_1; 198 } 199 #endif 200 201 202 void 203 initppc(u_long startkernel, u_long endkernel, u_int args, void *btinfo) 204 { 205 u_long ekern; 206 struct ipl_cb *r_iplcb; 207 struct ipl_directory *r_ipldir; 208 struct buc_info *bi; 209 int i; 210 register_t savemsr, msr; 211 212 /* indicate we have control */ 213 //setled(0x40000000); 214 *(uint8_t *)0xe0000030 = '1'; 215 216 /* copy bootinfo */ 217 memcpy(bootinfo, btinfo, sizeof(bootinfo)); 218 *(uint8_t *)0xe0000030 = '2'; 219 220 /* copy iplcb data */ 221 { 222 struct btinfo_iplcb *iplcbinfo; 223 224 iplcbinfo = 225 (struct btinfo_iplcb *)lookup_bootinfo(BTINFO_IPLCB); 226 if (!iplcbinfo) 227 panic("no iplcb information found in bootinfo"); 228 229 /* round_page endkernel, copy down to there, adjust */ 230 ekern = round_page(endkernel); 231 232 r_iplcb = (struct ipl_cb *)iplcbinfo->addr; 233 r_ipldir = (struct ipl_directory *)&r_iplcb->dir; 234 memcpy((void *)ekern, r_iplcb, r_ipldir->cb_bitmap_size); 235 iplcb = (struct ipl_cb *)ekern; 236 ipldir = (struct ipl_directory *)&iplcb->dir; 237 iplinfo = (struct ipl_info *)((char *)iplcb + 238 ipldir->iplinfo_off); 239 sysinfo = (struct sys_info *)((char *)iplcb + 240 ipldir->sysinfo_offset); 241 242 ekern += r_ipldir->cb_bitmap_size; 243 endkernel = ekern; 244 245 } 246 247 /* IPLCB copydown successful */ 248 setled(0x40100000); 249 250 /* Set memory region */ 251 { 252 u_long memsize = iplinfo->ram_size; 253 254 /* 255 * Some machines incorrectly report memory size in 256 * MB. Stupid stupid IBM breaking their own spec. 257 * on conformant machines, it is: 258 * The highest addressable real memory address byte+1 259 */ 260 if (memsize < 4069) 261 memsize = memsize * 1024 * 1024; 262 else 263 memsize -= 1; 264 physmemr[0].start = 0; 265 physmemr[0].size = memsize & ~PGOFSET; 266 availmemr[0].start = round_page(endkernel); 267 availmemr[0].size = memsize - availmemr[0].start; 268 } 269 avail_end = physmemr[0].start + physmemr[0].size; /* XXX temporary */ 270 *(uint8_t *)0xe0000030 = '3'; 271 272 #ifdef NOTYET 273 /* hrmm.. there is no timebase crap on POWER */ 274 /* 275 * Set CPU clock 276 */ 277 { 278 struct btinfo_clock *clockinfo; 279 extern u_long ticks_per_sec, ns_per_tick; 280 281 clockinfo = 282 (struct btinfo_clock *)lookup_bootinfo(BTINFO_CLOCK); 283 if (!clockinfo) 284 panic("not found clock information in bootinfo"); 285 286 ticks_per_sec = clockinfo->ticks_per_sec; 287 ns_per_tick = 1000000000 / ticks_per_sec; 288 } 289 #endif 290 /* boothowto */ 291 boothowto = args; 292 293 /* 294 * Now setup fixed bat registers 295 * 1) POWER has no bat registers. 296 * 2) NVRAM, IPL ROM, and other fun bits all live at 0xFF000000 on the 297 * 60x RS6000's, however if you try to map any less than 256MB 298 * on a 601 it wedges. 299 */ 300 #if !defined(POWER) 301 setled(0x40200000); 302 oea_batinit( 303 0xF0000000, BAT_BL_256M, 304 /* 305 RS6000_BUS_SPACE_MEM, BAT_BL_256M, 306 RS6000_BUS_SPACE_IO, BAT_BL_256M, 307 0xbf800000, BAT_BL_8M, 308 */ 309 0); 310 led_avail = 1; 311 #endif 312 setled(0x40200000); 313 314 /* set the IO segreg for the first IOCC */ 315 #ifdef POWER 316 iosrtable[0xc] = 0x820C00E0; 317 #else 318 iosrtable[0xc] = 0x82000080; 319 #endif 320 __asm volatile ("mfmsr %0" : "=r"(savemsr)); 321 msr = savemsr & ~PSL_DR; 322 __asm volatile ("mtmsr %0" : : "r"(msr)); 323 __asm volatile ("mtsr 0xc,%0" : : "r"(iosrtable[0xc])); 324 __asm volatile ("mtmsr %0" : : "r"(msr|PSL_DR)); 325 __asm volatile ("isync"); 326 __asm volatile ("mtmsr %0;isync" : : "r"(savemsr)); 327 328 cn_tab = &kcomcons; 329 printf("\nNetBSD/rs6000 booting ...\n"); 330 setled(0x40300000); 331 332 /* Install vectors and interrupt handler. */ 333 oea_init(NULL); 334 setled(0x40400000); 335 336 /* Initialize pmap module. */ 337 uvm_md_init(); 338 pmap_bootstrap(startkernel, endkernel); 339 setled(0x40500000); 340 341 /* populate the bucinfo stuff now that we can malloc */ 342 bi = (struct buc_info *)((char *)iplcb + ipldir->bucinfo_off); 343 nrofbucs = bi->nrof_structs; 344 /*printf("nrof=%d\n", nrofbucs);*/ 345 if (nrofbucs > MAX_BUCS) 346 aprint_error("WARNING: increase MAX_BUCS to at least %d\n", 347 nrofbucs); 348 for (i=0; i < nrofbucs && i < MAX_BUCS; i++) { 349 #ifdef DEBUG 350 printf("bi addr= %p\n", &bi); 351 printf("i=%d ssize=%x\n", i, bi->struct_size); 352 #endif 353 bucinfo[i] = bi; 354 bi = (struct buc_info *)((char *)iplcb + ipldir->bucinfo_off + 355 bi->struct_size); 356 } 357 #ifdef DEBUG 358 printf("found %d bucs\n", nrofbucs); 359 for (i=0; i < nrofbucs; i++) { 360 printf("BUC type: %d\n", bucinfo[i]->dev_type); 361 printf("BUC cfg incr: %x\n", bucinfo[i]->cfg_addr_incr); 362 printf("BUC devid reg: %x\n", bucinfo[i]->device_id_reg); 363 printf("BUC iocc?= %d\n", bucinfo[i]->IOCC_flag); 364 printf("BUC location= %x%x%x%x\n", bucinfo[i]->location[0], 365 bucinfo[i]->location[1], bucinfo[i]->location[2], 366 bucinfo[i]->location[3]); 367 } 368 printf("sysinfo scr_addr %p -> %x\n", sysinfo->scr_addr, 369 *sysinfo->scr_addr); 370 #endif 371 372 /* Initialize bus_space. */ 373 rs6000_bus_space_init(); 374 setled(0x40600000); 375 376 /* Initialize the console */ 377 consinit(); 378 setled(0x41000000); 379 380 #if NKSYMS || defined(DDB) || defined(MODULAR) 381 ksyms_addsyms_elf((int)((u_long)endsym - (u_long)startsym), startsym, endsym); 382 #endif 383 384 #ifdef DDB 385 if (boothowto & RB_KDB) 386 Debugger(); 387 #endif 388 } 389 390 void 391 mem_regions(struct mem_region **mem, struct mem_region **avail) 392 { 393 394 *mem = physmemr; 395 *avail = availmemr; 396 } 397 398 static void 399 init_intr(void) 400 { 401 pic_init(); 402 pic_iocc = setup_iocc(); 403 oea_install_extint(pic_ext_intr); 404 } 405 406 /* 407 * Machine dependent startup code. 408 */ 409 void 410 cpu_startup(void) 411 { 412 /* 420 indicates we are entering cpu_startup() */ 413 setled(0x42000000); 414 /* Do common startup. */ 415 oea_startup("rs6000"); 416 417 /* 418 * Inititalize the IOCC interrupt stuff 419 */ 420 init_intr(); 421 422 /* 423 * Now allow hardware interrupts. 424 */ 425 { 426 int msr; 427 428 splraise(-1); 429 __asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0" 430 : "=r"(msr) : "K"(PSL_EE)); 431 setled(0x42200000); 432 } 433 /* 434 * Now safe for bus space allocation to use malloc. 435 */ 436 bus_space_mallocok(); 437 } 438 439 /* 440 * lookup_bootinfo: 441 * Look up information in bootinfo of boot loader. 442 */ 443 void * 444 lookup_bootinfo(int type) 445 { 446 struct btinfo_common *bt; 447 struct btinfo_common *help = (struct btinfo_common *)bootinfo; 448 449 do { 450 bt = help; 451 if (bt->type == type) 452 return (help); 453 help = (struct btinfo_common *)((char*)help + bt->next); 454 } while (bt->next && 455 (size_t)help < (size_t)bootinfo + sizeof (bootinfo)); 456 457 return (NULL); 458 } 459 460 /* 461 * Reboot an RS6K 462 */ 463 static void 464 reset_rs6000(void) 465 { 466 mtmsr(mfmsr() | PSL_IP); 467 468 /* writing anything to the power/reset reg on an rs6k will cause 469 * a soft reboot. Supposedly. 470 */ 471 if (sysinfo->prcr_addr) 472 outb(sysinfo->prcr_addr, 0x1); 473 } 474 475 /* 476 * Halt or reboot the machine after syncing/dumping according to howto. 477 */ 478 void 479 cpu_reboot(int howto, char *what) 480 { 481 static int syncing; 482 483 if (cold) { 484 howto |= RB_HALT; 485 goto halt_sys; 486 } 487 488 boothowto = howto; 489 if ((howto & RB_NOSYNC) == 0 && syncing == 0) { 490 syncing = 1; 491 vfs_shutdown(); /* sync */ 492 //resettodr(); /* set wall clock */ 493 } 494 495 /* Disable intr */ 496 splhigh(); 497 498 /* Do dump if requested */ 499 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 500 oea_dumpsys(); 501 502 halt_sys: 503 doshutdownhooks(); 504 505 pmf_system_shutdown(boothowto); 506 507 if (howto & RB_HALT) { 508 printf("\n"); 509 printf("The operating system has halted.\n"); 510 printf("Please press any key to reboot.\n\n"); 511 cnpollc(1); /* for proper keyboard command handling */ 512 cngetc(); 513 cnpollc(0); 514 } 515 516 printf("rebooting...\n\n"); 517 518 reset_rs6000(); 519 520 for (;;) 521 continue; 522 /* NOTREACHED */ 523 } 524 525 /* The iocc0 mapping is set by init_ppc to 0xC via an iosegreg */ 526 struct powerpc_bus_space rs6000_iocc0_io_space_tag = { 527 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE, 528 .pbs_offset = 0xC0000000, 529 .pbs_base = 0x00000000, 530 .pbs_limit = 0x10000000, 531 }; 532 533 static char ex_storage[2][EXTENT_FIXED_STORAGE_SIZE(8)] 534 __attribute__((aligned(8))); 535 536 void 537 rs6000_bus_space_init(void) 538 { 539 int error; 540 541 error = bus_space_init(&rs6000_iocc0_io_space_tag, "ioport", 542 ex_storage[0], sizeof(ex_storage[0])); 543 if (error) 544 panic("rs6000_bus_space_init: can't init io tag"); 545 546 #if 0 547 error = extent_alloc_region(rs6000_iocc0_io_space_tag.pbs_extent, 548 0x10000, 0x7F0000, EX_NOWAIT); 549 if (error) 550 panic("rs6000_bus_space_init: can't block out reserved I/O" 551 " space 0x10000-0x7fffff: error=%d", error); 552 error = bus_space_init(&prep_mem_space_tag, "iomem", 553 ex_storage[1], sizeof(ex_storage[1])); 554 if (error) 555 panic("prep_bus_space_init: can't init mem tag"); 556 557 rs6000_iocc0_io_space_tag.pbs_extent = prep_io_space_tag.pbs_extent; 558 error = bus_space_init(&prep_isa_io_space_tag, "isa-ioport", NULL, 0); 559 if (error) 560 panic("prep_bus_space_init: can't init isa io tag"); 561 562 prep_isa_mem_space_tag.pbs_extent = prep_mem_space_tag.pbs_extent; 563 error = bus_space_init(&prep_isa_mem_space_tag, "isa-iomem", NULL, 0); 564 if (error) 565 panic("prep_bus_space_init: can't init isa mem tag"); 566 #endif 567 } 568 569 static bus_space_handle_t kcom_base = (bus_space_handle_t) (0xc0000000 + CONCOMADDR); 570 extern void bsw1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int8_t v); 571 extern int bsr1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o); 572 #define KCOM_GETBYTE(r) bsr1(0, kcom_base, (r)) 573 #define KCOM_PUTBYTE(r,v) bsw1(0, kcom_base, (r), (v)) 574 575 static int 576 kcomcngetc(dev_t dev) 577 { 578 int stat, c; 579 register_t msr; 580 581 msr = mfmsr(); 582 mtmsr(msr|PSL_DR); 583 __asm volatile ("isync"); 584 585 /* block until a character becomes available */ 586 while (!ISSET(stat = KCOM_GETBYTE(com_lsr), LSR_RXRDY)) 587 ; 588 589 c = KCOM_GETBYTE(com_data); 590 stat = KCOM_GETBYTE(com_iir); 591 mtmsr(msr); 592 __asm volatile ("isync"); 593 return c; 594 } 595 596 /* 597 * Console kernel output character routine. 598 */ 599 static void 600 kcomcnputc(dev_t dev, int c) 601 { 602 int timo; 603 register_t msr; 604 605 msr = mfmsr(); 606 mtmsr(msr|PSL_DR); 607 __asm volatile ("isync"); 608 /* wait for any pending transmission to finish */ 609 timo = 150000; 610 while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 611 continue; 612 613 KCOM_PUTBYTE(com_data, c); 614 615 /* wait for this transmission to complete */ 616 timo = 1500000; 617 while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 618 continue; 619 mtmsr(msr); 620 __asm volatile ("isync"); 621 } 622 623 static void 624 kcomcnpollc(dev_t dev, int on) 625 { 626 } 627 628 struct consdev kcomcons = { 629 NULL, NULL, kcomcngetc, kcomcnputc, kcomcnpollc, NULL, 630 NULL, NULL, NODEV, CN_NORMAL 631 }; 632