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