1 /* $NetBSD: machdep.c,v 1.123 2026/09/13 09:08:30 macallan Exp $ */ 2 /*- 3 * Copyright (c) 2007 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Tim Rightnour 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.123 2026/09/13 09:08:30 macallan Exp $"); 33 34 #include "opt_ofwoea.h" 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/buf.h> 39 #include <sys/boot_flag.h> 40 #include <sys/mount.h> 41 #include <sys/kernel.h> 42 #include <sys/device.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <dev/ofw/openfirm.h> 47 #include <dev/cons.h> 48 49 #include <machine/autoconf.h> 50 #include <machine/pmap.h> 51 #include <machine/powerpc.h> 52 #include <machine/trap.h> 53 #include <sys/bus.h> 54 #include <machine/isa_machdep.h> 55 56 #include <powerpc/spr.h> 57 #include <powerpc/oea/spr.h> 58 #include <powerpc/oea/bat.h> 59 #include <powerpc/ofw_cons.h> 60 #include <powerpc/rtas.h> 61 #include <powerpc/ofw_machdep.h> 62 63 #include <dev/wsfb/genfbvar.h> 64 65 #include "com.h" 66 #if (NCOM > 0) 67 #include <sys/termios.h> 68 #include <dev/ic/comreg.h> 69 #include <dev/ic/comvar.h> 70 #endif 71 #include "rtas.h" 72 73 extern struct pmap ofw_pmap; 74 extern char bootpath[256]; 75 76 extern u_int l2cr_config; 77 #if (NRTAS > 0) 78 extern int machine_has_rtas; 79 #endif 80 extern int console_instance; 81 82 struct model_data modeldata; 83 static void model_init(void); 84 85 struct genfb_colormap_callback gfb_cb; 86 87 #ifdef OFWOEA_DEBUG 88 #define DPRINTF ofprint 89 #else 90 #define DPRINTF while (0) printf 91 #endif 92 93 /* 94 * Scan the device tree for ranges, and return them as bitmap 0..15 95 */ 96 static uint16_t 97 ranges_bitmap(int node, uint16_t bitmap) 98 { 99 int child, mlen, acells, scells, reclen, i, j; 100 uint32_t addr, len, map[160]; 101 102 for (child = OF_child(node); child; child = OF_peer(child)) { 103 mlen = OF_getprop(child, "ranges", map, sizeof(map)); 104 if (mlen == -1) 105 goto noranges; 106 107 j = OF_getprop(child, "#address-cells", &acells, 108 sizeof(acells)); 109 if (j == -1) 110 goto noranges; 111 112 j = OF_getprop(child, "#size-cells", &scells, 113 sizeof(scells)); 114 if (j == -1) 115 goto noranges; 116 117 reclen = acells + modeldata.ranges_offset + scells; 118 119 for (i = 0; i < (mlen / 4) / reclen; i++) { 120 addr = map[reclen * i + acells]; 121 len = map[reclen * i + reclen - 1]; 122 for (j = 0; j < len / 0x10000000; j++) 123 bitmap |= 1 << ((addr+j*0x10000000) >> 28); 124 bitmap |= 1 << (addr >> 28); 125 } 126 noranges: 127 bitmap |= ranges_bitmap(child, bitmap); 128 continue; 129 } 130 return bitmap; 131 } 132 133 void 134 initppc(u_int startkernel, u_int endkernel, char *args) 135 { 136 int node, i; 137 uint16_t bitmap; 138 139 node = OF_finddevice("/"); 140 if (node != -1) { 141 i = OF_getprop(node, "model", model_name, sizeof(model_name)); 142 if (i == -1) { 143 OF_getprop(node, "name", model_name, 144 sizeof(model_name)); 145 } 146 } 147 model_init(); 148 149 if ((oeacpufeat & OEACPU_NOBAT) == 0) { 150 node = OF_finddevice("/"); 151 152 bitmap = ranges_bitmap(node, 0); 153 oea_batinit(0); 154 155 for (i = 1; i < 0x0f; i++) { 156 /* skip the three vital SR regions */ 157 if (i == USER_SR || i == KERNEL_SR || i == KERNEL2_SR) { 158 continue; 159 } 160 if (bitmap & (1 << i)) { 161 oea_iobat_add(0x10000000 * i, BAT_BL_256M); 162 DPRINTF("Batmapped 256M at 0x%x\n", 163 0x10000000 * i); 164 } 165 } 166 if (bitmap & 0x8000) { 167 /* grackle space is 0x80000000 - 0xff000000 */ 168 oea_iobat_add(0xf0000000, BAT_BL_128M); 169 oea_iobat_add(0xf8000000, BAT_BL_64M); 170 oea_iobat_add(0xfc000000, BAT_BL_32M); 171 oea_iobat_add(0xfe000000, BAT_BL_16M); 172 } 173 } 174 175 #if defined(MULTIPROCESSOR) 176 int l; 177 char cpupath[32]; 178 179 extern void cpu_spinstart(u_int); 180 extern volatile u_int cpu_spinstart_ack; 181 182 for (i = 1; i < CPU_MAXNUM; i++) { 183 snprintf(cpupath, sizeof(cpupath), "/cpus/@%x", i); 184 node = OF_finddevice(cpupath); 185 if (node <= 0) 186 continue; 187 aprint_verbose("Starting up CPU %d %s\n", i, cpupath); 188 OF_start_cpu(node, (u_int)cpu_spinstart, i); 189 for (l = 0; l < 100000000; l++) { 190 if (cpu_spinstart_ack == i) { 191 aprint_verbose("CPU %d spun up.\n", i); 192 break; 193 } 194 __asm volatile ("sync"); 195 } 196 } 197 #endif /* MULTIPROCESSOR */ 198 199 ofwoea_initppc(startkernel, endkernel, args); 200 } 201 202 /* perform model-specific actions at initppc() */ 203 static void 204 model_init(void) 205 { 206 int qhandle, phandle, j; 207 208 memset(&modeldata, 0, sizeof(struct model_data)); 209 /* provide sane defaults */ 210 for (j=0; j < MAX_PCI_BUSSES; j++) { 211 modeldata.pciiodata[j].start = 0x00008000; 212 modeldata.pciiodata[j].limit = 0x0000ffff; 213 } 214 modeldata.ranges_offset = 1; 215 216 if (strncmp(model_name, "FirePower,", 10) == 0) { 217 modeldata.ranges_offset = 0; 218 } 219 if (strcmp(model_name, "MOT,PowerStack_II_Pro4000") == 0) { 220 modeldata.ranges_offset = 0; 221 } 222 223 /* 7044-270 and 7044-170 */ 224 if (strncmp(model_name, "IBM,7044", 8) == 0) { 225 for (j=0; j < MAX_PCI_BUSSES; j++) { 226 modeldata.pciiodata[j].start = 0x00fff000; 227 modeldata.pciiodata[j].limit = 0x00ffffff; 228 } 229 } 230 231 /* Pegasos1, Pegasos2 */ 232 if (strncmp(model_name, "Pegasos", 7) == 0) { 233 static uint16_t modew[] = { 640, 800, 1024, 1280, 0 }; 234 static uint16_t modeh[] = { 480, 600, 768, 1024, 0 }; 235 uint32_t width, height, mode, fbaddr; 236 char buf[32]; 237 int i; 238 239 modeldata.pciiodata[0].start = 0x00001400; 240 modeldata.pciiodata[0].limit = 0x0000ffff; 241 242 /* the pegasos doesn't bother to set the L2 cache up */ 243 l2cr_config = L2CR_L2PE; 244 245 /* fix the device_type property of a graphics card */ 246 for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { 247 if (OF_getprop(qhandle, "name", buf, sizeof buf) > 0 248 && strncmp(buf, "display", 7) == 0) { 249 OF_setprop(qhandle, "device_type", "display", 8); 250 break; 251 } 252 if ((phandle = OF_child(qhandle))) 253 continue; 254 while (qhandle) { 255 if ((phandle = OF_peer(qhandle))) 256 break; 257 qhandle = OF_parent(qhandle); 258 } 259 } 260 261 /* 262 * Get screen width/height and switch to framebuffer mode. 263 * The default dimensions are: 800 x 600 264 */ 265 OF_interpret("screen-width", 0, 1, &width); 266 if (width == 0) 267 width = 800; 268 269 OF_interpret("screen-height", 0, 1, &height); 270 if (height == 0) 271 height = 600; 272 273 /* find VESA mode */ 274 for (i = 0, mode = 0; modew[i] != 0; i++) { 275 if (modew[i] == width && modeh[i] == height) { 276 mode = 0x101 + 2 * i; 277 break; 278 } 279 } 280 if (!mode) { 281 mode = 0x103; 282 width = 800; 283 height = 600; 284 } 285 286 /* init frame buffer mode */ 287 snprintf(buf, sizeof(buf), "%x vesa-set-mode", mode); 288 OF_interpret(buf, 0, 0); 289 290 /* set dimensions and frame buffer address in OFW */ 291 snprintf(buf, sizeof(buf), "%x to screen-width", width); 292 OF_interpret(buf, 0, 0); 293 snprintf(buf, sizeof(buf), "%x to screen-height", height); 294 OF_interpret(buf, 0, 0); 295 OF_interpret("vesa-frame-buffer-adr", 0, 1, &fbaddr); 296 if (fbaddr != 0) { 297 snprintf(buf, sizeof(buf), "%x to frame-buffer-adr", fbaddr); 298 OF_interpret(buf, 0, 0); 299 } 300 } 301 } 302 303 void 304 cpu_startup(void) 305 { 306 oea_startup(model_name[0] ? model_name : NULL); 307 bus_space_mallocok(); 308 } 309 310 311 void 312 consinit(void) 313 { 314 ofwoea_consinit(); 315 } 316 317 318 void 319 dumpsys(void) 320 { 321 aprint_normal("dumpsys: TBD\n"); 322 } 323 324 /* 325 * Halt or reboot the machine after syncing/dumping according to howto. 326 */ 327 328 void 329 cpu_reboot(int howto, char *what) 330 { 331 static int syncing; 332 static char str[256]; 333 char *ap = str, *ap1 = ap; 334 #if (NRTAS > 0) 335 int junk; 336 #endif 337 338 boothowto = howto; 339 if (!cold && !(howto & RB_NOSYNC) && !syncing) { 340 syncing = 1; 341 vfs_shutdown(); /* sync */ 342 } 343 splhigh(); 344 if (howto & RB_HALT) { 345 doshutdownhooks(); 346 pmf_system_shutdown(boothowto); 347 aprint_normal("halted\n\n"); 348 #if (NRTAS > 0) 349 if ((howto & 0x800) && machine_has_rtas && 350 rtas_has_func(RTAS_FUNC_POWER_OFF)) 351 rtas_call(RTAS_FUNC_POWER_OFF, 2, 1, 0, 0, &junk); 352 #endif 353 ppc_exit(); 354 } 355 if (!cold && (howto & RB_DUMP)) 356 oea_dumpsys(); 357 doshutdownhooks(); 358 359 pmf_system_shutdown(boothowto); 360 aprint_normal("rebooting\n\n"); 361 362 #if (NRTAS > 0) 363 if (machine_has_rtas && rtas_has_func(RTAS_FUNC_SYSTEM_REBOOT)) { 364 rtas_call(RTAS_FUNC_SYSTEM_REBOOT, 0, 1, &junk); 365 for(;;); 366 } 367 #endif 368 if (what && *what) { 369 if (strlen(what) > sizeof str - 5) 370 aprint_normal("boot string too large, ignored\n"); 371 else { 372 strcpy(str, what); 373 ap1 = ap = str + strlen(str); 374 *ap++ = ' '; 375 } 376 } 377 *ap++ = '-'; 378 if (howto & RB_SINGLE) 379 *ap++ = 's'; 380 if (howto & RB_KDB) 381 *ap++ = 'd'; 382 *ap++ = 0; 383 if (ap[-2] == '-') 384 *ap1 = 0; 385 ppc_boot(str); 386 } 387 388 /* 389 */ 390 391 #define divrnd(n, q) (((n)*2/(q)+1)/2) 392 393 void 394 ofppc_init_comcons(int isa_node) 395 { 396 #if (NCOM > 0) 397 char name[64]; 398 uint32_t reg[2], comfreq; 399 uint8_t dll, dlm; 400 int speed, rate, err, com_node, child; 401 bus_space_handle_t comh; 402 403 /* if we have a serial cons, we have work to do */ 404 memset(name, 0, sizeof(name)); 405 OF_getprop(console_node, "device_type", name, sizeof(name)); 406 if (strcmp(name, "serial") != 0) 407 return; 408 409 /* scan ISA children for serial devices to match our console */ 410 com_node = -1; 411 for (child = OF_child(isa_node); child; child = OF_peer(child)) { 412 memset(name, 0, sizeof(name)); 413 OF_getprop(child, "device_type", name, sizeof(name)); 414 if (strcmp(name, "serial") == 0) { 415 /* 416 * Serial device even matches our console_node? 417 * Then we're done! 418 */ 419 if (child == console_node) { 420 com_node = child; 421 break; 422 } 423 /* remember first serial device found */ 424 if (com_node == -1) 425 com_node = child; 426 } 427 } 428 429 if (com_node == -1) 430 return; 431 432 if (OF_getprop(com_node, "reg", reg, sizeof(reg)) == -1) 433 return; 434 435 if (OF_getprop(com_node, "clock-frequency", &comfreq, 4) == -1) 436 comfreq = 0; 437 438 if (comfreq == 0) 439 comfreq = COM_FREQ; 440 441 /* we need to BSM this, and then undo that before calling 442 * comcnattach. 443 */ 444 445 if (bus_space_map(&genppc_isa_io_space_tag, reg[1], 8, 0, &comh) != 0) 446 panic("Can't map isa serial\n"); 447 448 bus_space_write_1(&genppc_isa_io_space_tag, comh, com_cfcr, LCR_DLAB); 449 dll = bus_space_read_1(&genppc_isa_io_space_tag, comh, com_dlbl); 450 dlm = bus_space_read_1(&genppc_isa_io_space_tag, comh, com_dlbh); 451 rate = dll | (dlm << 8); 452 bus_space_write_1(&genppc_isa_io_space_tag, comh, com_cfcr, LCR_8BITS); 453 speed = divrnd((comfreq / 16), rate); 454 err = speed - (speed + 150)/300 * 300; 455 speed -= err; 456 if (err < 0) 457 err = -err; 458 if (err > 50) 459 speed = 9600; 460 461 bus_space_unmap(&genppc_isa_io_space_tag, comh, 8); 462 463 /* Now we can attach the comcons */ 464 aprint_verbose("Switching to COM console at speed %d", speed); 465 if (comcnattach(&genppc_isa_io_space_tag, reg[1], 466 speed, comfreq, COM_TYPE_NORMAL, 467 ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8))) 468 panic("Can't init serial console"); 469 aprint_verbose("\n"); 470 #endif /*NCOM*/ 471 } 472 473 static void 474 of_set_palette(void *cookie, int index, int r, int g, int b) 475 { 476 int ih = (int)cookie; 477 478 OF_call_method_1("color!", ih, 4, r, g, b, index); 479 } 480 481 void 482 copy_disp_props(device_t dev, int node, prop_dictionary_t dict) 483 { 484 uint64_t cmap_cb; 485 uint32_t temp; 486 char typestr[32]; 487 488 memset(typestr, 0, sizeof(typestr)); 489 OF_getprop(console_node, "device_type", typestr, sizeof(typestr)); 490 if (strcmp(typestr, "serial") != 0) { 491 /* this is our console, when we don't have a serial console */ 492 prop_dictionary_set_bool(dict, "is_console", 1); 493 } 494 495 if (!of_to_uint32_prop(dict, node, "width", "width")) { 496 497 OF_interpret("screen-width", 0, 1, &temp); 498 prop_dictionary_set_uint32(dict, "width", temp); 499 } 500 if (!of_to_uint32_prop(dict, node, "height", "height")) { 501 502 OF_interpret("screen-height", 0, 1, &temp); 503 prop_dictionary_set_uint32(dict, "height", temp); 504 } 505 of_to_uint32_prop(dict, node, "linebytes", "linebytes"); 506 if (!of_to_uint32_prop(dict, node, "depth", "depth")) { 507 /* 508 * XXX we should check linebytes vs. width but those 509 * FBs that don't have a depth property ( /chaos/control... ) 510 * won't have linebytes either 511 */ 512 prop_dictionary_set_uint32(dict, "depth", 8); 513 } 514 if (of_to_dataprop(dict, node, "EDID", "EDID")) { 515 aprint_debug("found EDID property...\n"); 516 } else if (of_to_dataprop(dict, node, "edid", "EDID")) { 517 aprint_debug("found edid\n"); 518 } 519 520 gfb_cb.gcc_cookie = (void *)console_instance; 521 gfb_cb.gcc_set_mapreg = of_set_palette; 522 cmap_cb = (uint64_t)(uintptr_t)&gfb_cb; 523 prop_dictionary_set_uint64(dict, "cmap_callback", cmap_cb); 524 525 if (!of_to_uint32_prop(dict, node, "address", "address")) { 526 uint32_t fbaddr = 0; 527 528 OF_interpret("frame-buffer-adr", 0, 1, &fbaddr); 529 if (fbaddr != 0) 530 prop_dictionary_set_uint32(dict, "address", fbaddr); 531 } 532 } 533