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