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