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