1 /* $NetBSD: machdep.c,v 1.180 2026/11/08 13:15:11 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.180 2026/11/08 13:15:11 macallan Exp $"); 36 37 #include "opt_compat_netbsd.h" 38 #include "opt_ddb.h" 39 #include "opt_kgdb.h" 40 #include "opt_altivec.h" 41 #include "opt_multiprocessor.h" 42 #include "opt_ppcarch.h" 43 #include "adb.h" 44 #include "zsc.h" 45 46 #include <sys/param.h> 47 #include <sys/buf.h> 48 #include <sys/boot_flag.h> 49 #include <sys/bus.h> 50 #include <sys/conf.h> 51 #include <sys/device.h> 52 #include <sys/exec.h> 53 #include <sys/kernel.h> 54 #include <sys/ksyms.h> 55 #include <sys/mbuf.h> 56 #include <sys/mount.h> 57 #include <sys/msgbuf.h> 58 #include <sys/proc.h> 59 #include <sys/reboot.h> 60 #include <sys/syscallargs.h> 61 #include <sys/syslog.h> 62 #include <sys/systm.h> 63 64 #ifdef DDB 65 #include <powerpc/db_machdep.h> 66 #include <ddb/db_extern.h> 67 #endif 68 69 #ifdef KGDB 70 #include <sys/kgdb.h> 71 #endif 72 73 #include <dev/ofw/openfirm.h> 74 #include <dev/wsfb/genfbvar.h> 75 76 #include <machine/autoconf.h> 77 #include <machine/powerpc.h> 78 79 #include <powerpc/trap.h> 80 #include <powerpc/fpu.h> 81 #include <powerpc/oea/bat.h> 82 #include <powerpc/oea/spr.h> 83 #include <powerpc/spr.h> 84 #ifdef ALTIVEC 85 #include <powerpc/altivec.h> 86 #endif 87 #include <powerpc/ofw_cons.h> 88 89 #include <powerpc/pic/picvar.h> 90 #ifdef MULTIPROCESSOR 91 #include <powerpc/pic/ipivar.h> 92 #endif 93 94 #include <macppc/dev/adbvar.h> 95 #include <macppc/dev/pmuvar.h> 96 #include <macppc/dev/cudavar.h> 97 #include <macppc/dev/smuvar.h> 98 99 #include <macppc/macppc/static_edid.h> 100 101 #include "ksyms.h" 102 #include "pmu.h" 103 #include "cuda.h" 104 #include "smu.h" 105 106 struct genfb_colormap_callback gfb_cb; 107 struct genfb_parameter_callback gpc_backlight, gpc_brightness; 108 109 /* 110 * OpenFirmware gives us no way to check the brightness level or the backlight 111 * state so we assume the backlight is on and about 4/5 up which seems 112 * reasonable for most laptops 113 */ 114 115 int backlight_state = 1; 116 int brightness_level = 200; 117 118 static void of_set_palette(void *, int, int, int, int); 119 static void add_model_specifics(prop_dictionary_t); 120 static int of_get_backlight(void *, int *); 121 static int of_set_backlight(void *, int); 122 static int of_get_brightness(void *, int *); 123 static int of_set_brightness(void *, int); 124 static int of_upd_brightness(void *, int); 125 126 void 127 initppc(u_int startkernel, u_int endkernel, char *args) 128 { 129 int node, l; 130 131 node = OF_finddevice("/"); 132 if (node != -1) { 133 l = OF_getprop(node, "model", model_name, sizeof(model_name)); 134 if (l == -1) { 135 OF_getprop(node, "name", model_name, 136 sizeof(model_name)); 137 } 138 } 139 140 ofw_quiesce = strncmp(model_name, "PowerMac11,2", 12) == 0 || 141 strncmp(model_name, "PowerMac12,1", 12) == 0 || 142 strncmp(model_name, "PowerMac7,2", 10) == 0; 143 144 /* switch CPUs to full speed */ 145 if (strncmp(model_name, "PowerMac7,", 10) == 0) { 146 /* 147 * some G5 have two i2c-hwclock, we need to find the one that 148 * generates the CPU clock 149 */ 150 int i2c = OF_finddevice("/u3/i2c"); 151 int clock = 0, ch = OF_child(i2c); 152 char type[16], buffer[128]; 153 while ((ch != 0) && (clock == 0)) { 154 if (OF_getprop(ch, "hwctrl-location", type, 16) > 0) { 155 if (strcmp(type, "CPU CLOCK") == 0) { 156 clock = ch; 157 } 158 } 159 ch = OF_peer(ch); 160 } 161 if (clock != 0) { 162 int len; 163 len = OF_package_to_path(clock, buffer, 128); 164 if (len >= 0) buffer[len] = 0; 165 printf("clock %s\n", buffer); 166 167 int clock_ih = OF_open(buffer); 168 if (clock_ih != 0) { 169 OF_call_method_1("slew-high", clock_ih, 0); 170 OF_close(clock_ih); 171 } 172 } 173 } 174 if (strncmp(model_name, "PowerMac8,", 10) == 0) { 175 int smu_ih = OF_open("/smu"); 176 if (smu_ih != 0) { 177 OF_call_method_1("smu-powertune-hi", smu_ih, 0); 178 OF_close(smu_ih); 179 } 180 } 181 182 /* 183 * Initialize BAT mappings for our I/O regions. Note, 184 * on the 601, we use segment mappings under the covers. 185 */ 186 #ifdef PPC_OEA601 187 if ((mfpvr() >> 16 ) == MPC601) { 188 oea_batinit( 189 0x80000000, BAT_BL_256M, 190 0x90000000, BAT_BL_256M, 191 0xa0000000, BAT_BL_256M, 192 0xb0000000, BAT_BL_256M, 193 0xf0000000, BAT_BL_256M, 194 0); 195 } else 196 #endif /* PPC_OEA601 */ 197 { 198 oea_batinit( 199 0x80000000, BAT_BL_1G, 200 0xf0000000, BAT_BL_128M, 201 0xf8000000, BAT_BL_64M, 202 0xfe000000, BAT_BL_8M, /* Grackle IO */ 203 0); 204 } 205 206 ofwoea_initppc(startkernel, endkernel, args); 207 } 208 209 void 210 consinit(void) 211 { 212 ofwoea_consinit(); 213 } 214 215 /* 216 * Machine dependent startup code. 217 */ 218 void 219 cpu_startup(void) 220 { 221 oea_startup(NULL); 222 } 223 224 /* 225 * Crash dump handling. 226 */ 227 228 void 229 dumpsys(void) 230 { 231 oea_dumpsys(); 232 } 233 234 /* 235 * Halt or reboot the machine after syncing/dumping according to howto. 236 */ 237 void 238 cpu_reboot(int howto, char *what) 239 { 240 static int syncing; 241 static char str[256]; 242 char *ap = str, *ap1 = ap; 243 244 /* 245 * Enable external interrupts in case someone is rebooting 246 * from a strange context via ddb. 247 */ 248 mtmsr(mfmsr() | PSL_EE); 249 250 boothowto = howto; 251 if (!cold && !(howto & RB_NOSYNC) && !syncing) { 252 syncing = 1; 253 vfs_shutdown(); /* sync */ 254 } 255 256 #ifdef MULTIPROCESSOR 257 /* Halt other CPU */ 258 cpu_halt_others(); 259 delay(100000); /* XXX */ 260 #endif 261 262 splhigh(); 263 264 if (!cold && (howto & RB_DUMP)) 265 dumpsys(); 266 267 doshutdownhooks(); 268 269 pmf_system_shutdown(boothowto); 270 271 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) { 272 delay(1000000); 273 #if NCUDA > 0 274 cuda_poweroff(); 275 #endif 276 #if NPMU > 0 277 pmu_poweroff(); 278 #endif 279 #if NADB > 0 280 adb_poweroff(); 281 printf("WARNING: powerdown failed!\n"); 282 #endif 283 #if NSMU > 0 284 smu_poweroff(); 285 #endif 286 } 287 288 if (howto & RB_HALT) { 289 printf("halted\n\n"); 290 291 /* flush cache for msgbuf */ 292 __syncicache((void *)msgbuf_paddr, round_page(MSGBUFSIZE)); 293 294 ppc_exit(); 295 } 296 297 printf("rebooting\n\n"); 298 if (what && *what) { 299 if (strlen(what) > sizeof str - 5) 300 printf("boot string too large, ignored\n"); 301 else { 302 strcpy(str, what); 303 ap1 = ap = str + strlen(str); 304 *ap++ = ' '; 305 } 306 } 307 *ap++ = '-'; 308 if (howto & RB_SINGLE) 309 *ap++ = 's'; 310 if (howto & RB_KDB) 311 *ap++ = 'd'; 312 *ap++ = 0; 313 if (ap[-2] == '-') 314 *ap1 = 0; 315 316 /* flush cache for msgbuf */ 317 __syncicache((void *)msgbuf_paddr, round_page(MSGBUFSIZE)); 318 319 #if NCUDA > 0 320 cuda_restart(); 321 #endif 322 #if NPMU > 0 323 pmu_restart(); 324 #endif 325 #if NADB > 0 326 adb_restart(); /* not return */ 327 #endif 328 #if NSMU > 0 329 smu_restart(); 330 #endif 331 ppc_exit(); 332 } 333 334 #if 0 335 /* 336 * OpenFirmware callback routine 337 */ 338 void 339 callback(void *p) 340 { 341 panic("callback"); /* for now XXX */ 342 } 343 #endif 344 345 void 346 copy_disp_props(device_t dev, int node, prop_dictionary_t dict) 347 { 348 char name[32]; 349 uint32_t temp; 350 uint64_t cmap_cb, backlight_cb, brightness_cb; 351 int have_backlight = 0; 352 int have_palette = 1; 353 354 if (node != console_node) { 355 /* 356 * see if any child matches since OF attaches nodes for 357 * each head and /chosen/stdout points to the head 358 * rather than the device itself in this case 359 */ 360 int sub; 361 362 sub = OF_child(node); 363 while ((sub != 0) && (sub != console_node)) { 364 sub = OF_peer(sub); 365 } 366 if (sub != console_node) 367 return; 368 node = sub; 369 } 370 371 prop_dictionary_set_bool(dict, "is_console", 1); 372 if (!of_to_uint32_prop(dict, node, "width", "width")) { 373 374 OF_interpret("screen-width", 0, 1, &temp); 375 prop_dictionary_set_uint32(dict, "width", temp); 376 } 377 if (!of_to_uint32_prop(dict, node, "height", "height")) { 378 379 OF_interpret("screen-height", 0, 1, &temp); 380 prop_dictionary_set_uint32(dict, "height", temp); 381 } 382 of_to_uint32_prop(dict, node, "linebytes", "linebytes"); 383 if (!of_to_uint32_prop(dict, node, "depth", "depth")) { 384 /* 385 * XXX we should check linebytes vs. width but those 386 * FBs that don't have a depth property ( /chaos/control... ) 387 * won't have linebytes either 388 */ 389 prop_dictionary_set_uint32(dict, "depth", 8); 390 } 391 if (!of_to_uint32_prop(dict, node, "address", "address")) { 392 uint32_t fbaddr = 0; 393 OF_interpret("frame-buffer-adr", 0, 1, &fbaddr); 394 if (fbaddr != 0) 395 prop_dictionary_set_uint32(dict, "address", fbaddr); 396 } 397 if (of_to_dataprop(dict, node, "EDID", "EDID")) { 398 aprint_debug("found EDID property...\n"); 399 } else if (of_to_dataprop(dict, node, "EDID,A", "EDID")) { 400 aprint_debug("found EDID,A\n"); 401 } else if (of_to_dataprop(dict, node, "EDID,B", "EDID")) { 402 memset(name, 0, sizeof(name)); 403 OF_getprop(node, "name", name, sizeof(name)); 404 if (strcmp(name, "NVDA,NVMac") == 0) { 405 aprint_debug("found EDID,B on nvidia - assuming digital output\n"); 406 prop_dictionary_set_bool(dict, "no_palette_control", 1); 407 have_palette = 0; 408 } 409 } 410 add_model_specifics(dict); 411 412 temp = 0; 413 if (OF_getprop(node, "ATY,RefCLK", &temp, sizeof(temp)) != 4) { 414 415 OF_getprop(OF_parent(node), "ATY,RefCLK", &temp, 416 sizeof(temp)); 417 } 418 if (temp != 0) 419 prop_dictionary_set_uint32(dict, "refclk", temp / 10); 420 421 if (have_palette && ofw_quiesce) { 422 aprint_debug( 423 "OFW has been quiesced - disabling palette callback\n"); 424 have_palette = 0; 425 } 426 427 if (have_palette) { 428 gfb_cb.gcc_cookie = (void *)console_instance; 429 gfb_cb.gcc_set_mapreg = of_set_palette; 430 cmap_cb = (uint64_t)(uintptr_t)&gfb_cb; 431 prop_dictionary_set_uint64(dict, "cmap_callback", cmap_cb); 432 } 433 434 /* now let's look for backlight control */ 435 have_backlight = 0; 436 if (OF_getprop(node, "backlight-control", &temp, sizeof(temp)) == 4) { 437 have_backlight = 1; 438 } else if (OF_getprop(OF_parent(node), "backlight-control", &temp, 439 sizeof(temp)) == 4) { 440 have_backlight = 1; 441 } 442 443 if (have_backlight && ofw_quiesce) { 444 aprint_debug( 445 "OFW has been quiesced - disabling backlight callbacks\n"); 446 have_backlight = 0; 447 } 448 449 if (have_backlight) { 450 451 gpc_backlight.gpc_cookie = (void *)console_instance; 452 gpc_backlight.gpc_set_parameter = of_set_backlight; 453 gpc_backlight.gpc_get_parameter = of_get_backlight; 454 gpc_backlight.gpc_upd_parameter = NULL; 455 backlight_cb = (uint64_t)(uintptr_t)&gpc_backlight; 456 prop_dictionary_set_uint64(dict, "backlight_callback", 457 backlight_cb); 458 459 gpc_brightness.gpc_cookie = (void *)console_instance; 460 gpc_brightness.gpc_set_parameter = of_set_brightness; 461 gpc_brightness.gpc_get_parameter = of_get_brightness; 462 gpc_brightness.gpc_upd_parameter = of_upd_brightness; 463 brightness_cb = (uint64_t)(uintptr_t)&gpc_brightness; 464 prop_dictionary_set_uint64(dict, "brightness_callback", 465 brightness_cb); 466 } 467 } 468 469 static void 470 add_model_specifics(prop_dictionary_t dict) 471 { 472 const char *bl_rev_models[] = { 473 "PowerBook4,3", "PowerBook6,3", "PowerBook6,5", NULL}; 474 const char *clamshell[] = { 475 "PowerBook2,1", "PowerBook2,2", NULL}; 476 const char *pismo[] = { 477 "PowerBook3,1", NULL}; 478 const char *mini1[] = { 479 "PowerMac10,1", NULL}; 480 const char *mini2[] = { 481 "PowerMac10,2", NULL}; 482 int node; 483 484 node = OF_finddevice("/"); 485 486 if (of_compatible(node, bl_rev_models)) { 487 prop_dictionary_set_bool(dict, "backlight_level_reverted", 1); 488 } 489 if (of_compatible(node, clamshell)) { 490 prop_data_t edid; 491 492 edid = prop_data_create_nocopy(edid_clamshell, sizeof(edid_clamshell)); 493 prop_dictionary_set(dict, "EDID", edid); 494 prop_object_release(edid); 495 } 496 if (of_compatible(node, pismo)) { 497 prop_data_t edid; 498 499 edid = prop_data_create_nocopy(edid_pismo, sizeof(edid_pismo)); 500 prop_dictionary_set(dict, "EDID", edid); 501 prop_object_release(edid); 502 } 503 if (of_compatible(node, mini1)) { 504 prop_dictionary_set_bool(dict, "dvi-internal", 1); 505 } 506 if (of_compatible(node, mini2)) { 507 prop_dictionary_set_bool(dict, "dvi-external", 1); 508 } 509 } 510 511 static void 512 of_set_palette(void *cookie, int index, int r, int g, int b) 513 { 514 int ih = (int)cookie; 515 516 OF_call_method_1("color!", ih, 4, r, g, b, index); 517 } 518 519 static int 520 of_get_backlight(void *cookie, int *state) 521 { 522 if (backlight_state < 0) 523 return ENODEV; 524 *state = backlight_state; 525 return 0; 526 } 527 528 static int 529 of_set_backlight(void *cookie, int state) 530 { 531 int ih = (int)cookie; 532 533 KASSERT(state >= 0 && state <= 1); 534 535 backlight_state = state; 536 if (state) 537 OF_call_method_1("backlight-on", ih, 0); 538 else 539 OF_call_method_1("backlight-off", ih, 0); 540 541 return 0; /* XXX or use return value of OF_call_method_1? */ 542 } 543 544 static int 545 of_get_brightness(void *cookie, int *level) 546 { 547 /* 548 * We don't know how to read the brightness level from OF alone - we 549 * should read the value from the PMU. Here, we just return whatever 550 * we set last (if any). 551 */ 552 if (brightness_level < 0) 553 return ENODEV; 554 *level = brightness_level; 555 return 0; 556 } 557 558 static int 559 of_set_brightness(void *cookie, int level) 560 { 561 int ih = (int)cookie; 562 563 KASSERT(level >= 0 && level <= 255); 564 565 brightness_level = level; 566 OF_call_method_1("set-contrast", ih, 1, brightness_level); 567 568 return 0; /* XXX or use return value of OF_call_method_1? */ 569 } 570 571 static int 572 of_upd_brightness(void *cookie, int delta) 573 { 574 int ih = (int)cookie; 575 576 if (brightness_level < 0) 577 return ENODEV; 578 579 brightness_level += delta; 580 if (brightness_level < 0) brightness_level = 0; 581 if (brightness_level > 255) brightness_level = 255; 582 OF_call_method_1("set-contrast", ih, 1, brightness_level); 583 584 return 0; /* XXX or use return value of OF_call_method_1? */ 585 } 586