Home | History | Annotate | Line # | Download | only in macppc
      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