1 /* $NetBSD: machdep.c,v 1.178 2025/07/01 14:19:45 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.178 2025/07/01 14:19:45 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 OF_package_to_path(clock, buffer, 128); 163 printf("clock %s\n", buffer); 164 165 int clock_ih = OF_open(buffer); 166 if (clock_ih != 0) { 167 OF_call_method_1("slew-high", clock_ih, 0); 168 OF_close(clock_ih); 169 } 170 } 171 } 172 if (strncmp(model_name, "PowerMac8,", 10) == 0) { 173 int smu_ih = OF_open("/smu"); 174 if (smu_ih != 0) { 175 OF_call_method_1("smu-powertune-hi", smu_ih, 0); 176 OF_close(smu_ih); 177 } 178 } 179 180 /* 181 * Initialize BAT mappings for our I/O regions. Note, 182 * on the 601, we use segment mappings under the covers. 183 */ 184 #ifdef PPC_OEA601 185 if ((mfpvr() >> 16 ) == MPC601) { 186 oea_batinit( 187 0x80000000, BAT_BL_256M, 188 0x90000000, BAT_BL_256M, 189 0xa0000000, BAT_BL_256M, 190 0xb0000000, BAT_BL_256M, 191 0xf0000000, BAT_BL_256M, 192 0); 193 } else 194 #endif /* PPC_OEA601 */ 195 { 196 oea_batinit( 197 0x80000000, BAT_BL_1G, 198 0xf0000000, BAT_BL_128M, 199 0xf8000000, BAT_BL_64M, 200 0xfe000000, BAT_BL_8M, /* Grackle IO */ 201 0); 202 } 203 204 ofwoea_initppc(startkernel, endkernel, args); 205 } 206 207 void 208 consinit(void) 209 { 210 ofwoea_consinit(); 211 } 212 213 /* 214 * Machine dependent startup code. 215 */ 216 void 217 cpu_startup(void) 218 { 219 oea_startup(NULL); 220 } 221 222 /* 223 * Crash dump handling. 224 */ 225 226 void 227 dumpsys(void) 228 { 229 printf("dumpsys: TBD\n"); 230 } 231 232 /* 233 * Halt or reboot the machine after syncing/dumping according to howto. 234 */ 235 void 236 cpu_reboot(int howto, char *what) 237 { 238 static int syncing; 239 static char str[256]; 240 char *ap = str, *ap1 = ap; 241 242 /* 243 * Enable external interrupts in case someone is rebooting 244 * from a strange context via ddb. 245 */ 246 mtmsr(mfmsr() | PSL_EE); 247 248 boothowto = howto; 249 if (!cold && !(howto & RB_NOSYNC) && !syncing) { 250 syncing = 1; 251 vfs_shutdown(); /* sync */ 252 } 253 254 #ifdef MULTIPROCESSOR 255 /* Halt other CPU */ 256 cpu_halt_others(); 257 delay(100000); /* XXX */ 258 #endif 259 260 splhigh(); 261 262 if (!cold && (howto & RB_DUMP)) 263 dumpsys(); 264 265 doshutdownhooks(); 266 267 pmf_system_shutdown(boothowto); 268 269 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) { 270 delay(1000000); 271 #if NCUDA > 0 272 cuda_poweroff(); 273 #endif 274 #if NPMU > 0 275 pmu_poweroff(); 276 #endif 277 #if NADB > 0 278 adb_poweroff(); 279 printf("WARNING: powerdown failed!\n"); 280 #endif 281 #if NSMU > 0 282 smu_poweroff(); 283 #endif 284 } 285 286 if (howto & RB_HALT) { 287 printf("halted\n\n"); 288 289 /* flush cache for msgbuf */ 290 __syncicache((void *)msgbuf_paddr, round_page(MSGBUFSIZE)); 291 292 ppc_exit(); 293 } 294 295 printf("rebooting\n\n"); 296 if (what && *what) { 297 if (strlen(what) > sizeof str - 5) 298 printf("boot string too large, ignored\n"); 299 else { 300 strcpy(str, what); 301 ap1 = ap = str + strlen(str); 302 *ap++ = ' '; 303 } 304 } 305 *ap++ = '-'; 306 if (howto & RB_SINGLE) 307 *ap++ = 's'; 308 if (howto & RB_KDB) 309 *ap++ = 'd'; 310 *ap++ = 0; 311 if (ap[-2] == '-') 312 *ap1 = 0; 313 314 /* flush cache for msgbuf */ 315 __syncicache((void *)msgbuf_paddr, round_page(MSGBUFSIZE)); 316 317 #if NCUDA > 0 318 cuda_restart(); 319 #endif 320 #if NPMU > 0 321 pmu_restart(); 322 #endif 323 #if NADB > 0 324 adb_restart(); /* not return */ 325 #endif 326 #if NSMU > 0 327 smu_restart(); 328 #endif 329 ppc_exit(); 330 } 331 332 #if 0 333 /* 334 * OpenFirmware callback routine 335 */ 336 void 337 callback(void *p) 338 { 339 panic("callback"); /* for now XXX */ 340 } 341 #endif 342 343 void 344 copy_disp_props(device_t dev, int node, prop_dictionary_t dict) 345 { 346 char name[32]; 347 uint32_t temp; 348 uint64_t cmap_cb, backlight_cb, brightness_cb; 349 int have_backlight = 0; 350 int have_palette = 1; 351 352 if (node != console_node) { 353 /* 354 * see if any child matches since OF attaches nodes for 355 * each head and /chosen/stdout points to the head 356 * rather than the device itself in this case 357 */ 358 int sub; 359 360 sub = OF_child(node); 361 while ((sub != 0) && (sub != console_node)) { 362 sub = OF_peer(sub); 363 } 364 if (sub != console_node) 365 return; 366 node = sub; 367 } 368 369 prop_dictionary_set_bool(dict, "is_console", 1); 370 if (!of_to_uint32_prop(dict, node, "width", "width")) { 371 372 OF_interpret("screen-width", 0, 1, &temp); 373 prop_dictionary_set_uint32(dict, "width", temp); 374 } 375 if (!of_to_uint32_prop(dict, node, "height", "height")) { 376 377 OF_interpret("screen-height", 0, 1, &temp); 378 prop_dictionary_set_uint32(dict, "height", temp); 379 } 380 of_to_uint32_prop(dict, node, "linebytes", "linebytes"); 381 if (!of_to_uint32_prop(dict, node, "depth", "depth")) { 382 /* 383 * XXX we should check linebytes vs. width but those 384 * FBs that don't have a depth property ( /chaos/control... ) 385 * won't have linebytes either 386 */ 387 prop_dictionary_set_uint32(dict, "depth", 8); 388 } 389 if (!of_to_uint32_prop(dict, node, "address", "address")) { 390 uint32_t fbaddr = 0; 391 OF_interpret("frame-buffer-adr", 0, 1, &fbaddr); 392 if (fbaddr != 0) 393 prop_dictionary_set_uint32(dict, "address", fbaddr); 394 } 395 if (of_to_dataprop(dict, node, "EDID", "EDID")) { 396 aprint_debug("found EDID property...\n"); 397 } else if (of_to_dataprop(dict, node, "EDID,A", "EDID")) { 398 aprint_debug("found EDID,A\n"); 399 } else if (of_to_dataprop(dict, node, "EDID,B", "EDID")) { 400 memset(name, 0, sizeof(name)); 401 OF_getprop(node, "name", name, sizeof(name)); 402 if (strcmp(name, "NVDA,NVMac") == 0) { 403 aprint_debug("found EDID,B on nvidia - assuming digital output\n"); 404 prop_dictionary_set_bool(dict, "no_palette_control", 1); 405 have_palette = 0; 406 } 407 } 408 add_model_specifics(dict); 409 410 temp = 0; 411 if (OF_getprop(node, "ATY,RefCLK", &temp, sizeof(temp)) != 4) { 412 413 OF_getprop(OF_parent(node), "ATY,RefCLK", &temp, 414 sizeof(temp)); 415 } 416 if (temp != 0) 417 prop_dictionary_set_uint32(dict, "refclk", temp / 10); 418 419 if (have_palette && ofw_quiesce) { 420 aprint_debug( 421 "OFW has been quiesced - disabling palette callback\n"); 422 have_palette = 0; 423 } 424 425 if (have_palette) { 426 gfb_cb.gcc_cookie = (void *)console_instance; 427 gfb_cb.gcc_set_mapreg = of_set_palette; 428 cmap_cb = (uint64_t)(uintptr_t)&gfb_cb; 429 prop_dictionary_set_uint64(dict, "cmap_callback", cmap_cb); 430 } 431 432 /* now let's look for backlight control */ 433 have_backlight = 0; 434 if (OF_getprop(node, "backlight-control", &temp, sizeof(temp)) == 4) { 435 have_backlight = 1; 436 } else if (OF_getprop(OF_parent(node), "backlight-control", &temp, 437 sizeof(temp)) == 4) { 438 have_backlight = 1; 439 } 440 441 if (have_backlight && ofw_quiesce) { 442 aprint_debug( 443 "OFW has been quiesced - disabling backlight callbacks\n"); 444 have_backlight = 0; 445 } 446 447 if (have_backlight) { 448 449 gpc_backlight.gpc_cookie = (void *)console_instance; 450 gpc_backlight.gpc_set_parameter = of_set_backlight; 451 gpc_backlight.gpc_get_parameter = of_get_backlight; 452 gpc_backlight.gpc_upd_parameter = NULL; 453 backlight_cb = (uint64_t)(uintptr_t)&gpc_backlight; 454 prop_dictionary_set_uint64(dict, "backlight_callback", 455 backlight_cb); 456 457 gpc_brightness.gpc_cookie = (void *)console_instance; 458 gpc_brightness.gpc_set_parameter = of_set_brightness; 459 gpc_brightness.gpc_get_parameter = of_get_brightness; 460 gpc_brightness.gpc_upd_parameter = of_upd_brightness; 461 brightness_cb = (uint64_t)(uintptr_t)&gpc_brightness; 462 prop_dictionary_set_uint64(dict, "brightness_callback", 463 brightness_cb); 464 } 465 } 466 467 static void 468 add_model_specifics(prop_dictionary_t dict) 469 { 470 const char *bl_rev_models[] = { 471 "PowerBook4,3", "PowerBook6,3", "PowerBook6,5", NULL}; 472 const char *clamshell[] = { 473 "PowerBook2,1", "PowerBook2,2", NULL}; 474 const char *pismo[] = { 475 "PowerBook3,1", NULL}; 476 const char *mini1[] = { 477 "PowerMac10,1", NULL}; 478 const char *mini2[] = { 479 "PowerMac10,2", NULL}; 480 int node; 481 482 node = OF_finddevice("/"); 483 484 if (of_compatible(node, bl_rev_models)) { 485 prop_dictionary_set_bool(dict, "backlight_level_reverted", 1); 486 } 487 if (of_compatible(node, clamshell)) { 488 prop_data_t edid; 489 490 edid = prop_data_create_nocopy(edid_clamshell, sizeof(edid_clamshell)); 491 prop_dictionary_set(dict, "EDID", edid); 492 prop_object_release(edid); 493 } 494 if (of_compatible(node, pismo)) { 495 prop_data_t edid; 496 497 edid = prop_data_create_nocopy(edid_pismo, sizeof(edid_pismo)); 498 prop_dictionary_set(dict, "EDID", edid); 499 prop_object_release(edid); 500 } 501 if (of_compatible(node, mini1)) { 502 prop_dictionary_set_bool(dict, "dvi-internal", 1); 503 } 504 if (of_compatible(node, mini2)) { 505 prop_dictionary_set_bool(dict, "dvi-external", 1); 506 } 507 } 508 509 static void 510 of_set_palette(void *cookie, int index, int r, int g, int b) 511 { 512 int ih = (int)cookie; 513 514 OF_call_method_1("color!", ih, 4, r, g, b, index); 515 } 516 517 static int 518 of_get_backlight(void *cookie, int *state) 519 { 520 if (backlight_state < 0) 521 return ENODEV; 522 *state = backlight_state; 523 return 0; 524 } 525 526 static int 527 of_set_backlight(void *cookie, int state) 528 { 529 int ih = (int)cookie; 530 531 KASSERT(state >= 0 && state <= 1); 532 533 backlight_state = state; 534 if (state) 535 OF_call_method_1("backlight-on", ih, 0); 536 else 537 OF_call_method_1("backlight-off", ih, 0); 538 539 return 0; /* XXX or use return value of OF_call_method_1? */ 540 } 541 542 static int 543 of_get_brightness(void *cookie, int *level) 544 { 545 /* 546 * We don't know how to read the brightness level from OF alone - we 547 * should read the value from the PMU. Here, we just return whatever 548 * we set last (if any). 549 */ 550 if (brightness_level < 0) 551 return ENODEV; 552 *level = brightness_level; 553 return 0; 554 } 555 556 static int 557 of_set_brightness(void *cookie, int level) 558 { 559 int ih = (int)cookie; 560 561 KASSERT(level >= 0 && level <= 255); 562 563 brightness_level = level; 564 OF_call_method_1("set-contrast", ih, 1, brightness_level); 565 566 return 0; /* XXX or use return value of OF_call_method_1? */ 567 } 568 569 static int 570 of_upd_brightness(void *cookie, int delta) 571 { 572 int ih = (int)cookie; 573 574 if (brightness_level < 0) 575 return ENODEV; 576 577 brightness_level += delta; 578 if (brightness_level < 0) brightness_level = 0; 579 if (brightness_level > 255) brightness_level = 255; 580 OF_call_method_1("set-contrast", ih, 1, brightness_level); 581 582 return 0; /* XXX or use return value of OF_call_method_1? */ 583 } 584