1 /* $OpenBSD: ofw_machdep.c,v 1.65 2024/04/13 23:44:11 jsg Exp $ */
2 /* $NetBSD: ofw_machdep.c,v 1.1 1996/09/30 16:34:50 ws Exp $ */
3
4 /*
5 * Copyright (C) 1996 Wolfgang Solfrank.
6 * Copyright (C) 1996 TooLs GmbH.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include "akbd.h"
36 #include "ukbd.h"
37 #include "wsdisplay.h"
38 #include "zstty.h"
39
40 #include <sys/param.h>
41 #include <sys/conf.h>
42 #include <sys/device.h>
43 #include <sys/systm.h>
44
45 #include <uvm/uvm_extern.h>
46
47 #include <powerpc/powerpc.h>
48 #include <machine/autoconf.h>
49
50 #include <dev/ofw/openfirm.h>
51 #include <dev/ofw/ofw_pci.h>
52
53 #include <macppc/macppc/ofw_machdep.h>
54
55 #if NAKBD > 0
56 #include <dev/adb/akbdvar.h>
57 #endif
58
59 #if NUKBD > 0
60 #include <dev/usb/ukbdvar.h>
61 #endif
62
63 #if NWSDISPLAY > 0
64 #include <dev/wscons/wsconsio.h>
65 #include <dev/wscons/wsdisplayvar.h>
66 #include <dev/rasops/rasops.h>
67 #endif
68
69 struct mem_region64 {
70 uint64_t start;
71 uint32_t size;
72 } __packed;
73
74 #define OFMEM_REGIONS 32
75 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
76 static struct mem_region64 OFmem64[OFMEM_REGIONS + 1];
77
78 /*
79 * Section 5.1.7. Memory Management Unit properties.
80 */
81 struct ofw_map {
82 uint32_t om_virt;
83 uint32_t om_size;
84 uint32_t om_phys;
85 uint32_t om_mode;
86 } __packed;
87
88 struct ofw_map64 {
89 uint32_t om_virt;
90 uint32_t om_size;
91 uint64_t om_phys;
92 uint32_t om_mode;
93 } __packed;
94
95 static struct ofw_map ofw_maps[OFMEM_REGIONS];
96 static struct ofw_map64 ofw_maps64[OFMEM_REGIONS];
97
98 #if NWSDISPLAY > 0
99 struct ofwfb {
100 struct rasops_info ofw_ri;
101 struct wsscreen_descr ofw_wsd;
102 };
103
104 /* Early boot framebuffer */
105 static struct ofwfb ofwfb;
106 #endif
107
108 int save_ofw_mapping(void);
109 void ofw_consinit(int);
110 void ofw_read_mem_regions(int, int, int);
111
112 int ofw_set_param(struct wsdisplay_param *);
113 int ofw_get_param(struct wsdisplay_param *);
114
115 /*
116 * This is called during initppc, before the system is really initialized.
117 * It shall provide the total and the available regions of RAM.
118 * Both lists must have a zero-size entry as terminator.
119 * The available regions need not take the kernel into account, but needs
120 * to provide space for two additional entry beyond the terminating one.
121 */
122 void
ppc_mem_regions(struct mem_region ** memp,struct mem_region ** availp)123 ppc_mem_regions(struct mem_region **memp, struct mem_region **availp)
124 {
125 *memp = OFmem;
126
127 /* HACK */
128 if (OFmem[0].size == 0) {
129 *memp = OFavail;
130 }
131
132 *availp = OFavail;
133 }
134
135 void
ofw_read_mem_regions(int phandle,int address_cells,int size_cells)136 ofw_read_mem_regions(int phandle, int address_cells, int size_cells)
137 {
138 int nreg, navail;
139 int i, j;
140
141 switch (address_cells) {
142 default:
143 case 1:
144 nreg = OF_getprop(phandle, "reg", OFmem,
145 sizeof(OFmem[0]) * OFMEM_REGIONS) / sizeof(OFmem[0]);
146 break;
147 case 2:
148 nreg = OF_getprop(phandle, "reg", OFmem64,
149 sizeof(OFmem64[0]) * OFMEM_REGIONS) / sizeof(OFmem64[0]);
150 break;
151 }
152
153 navail = OF_getprop(phandle, "available", OFavail,
154 sizeof(OFavail[0]) * OFMEM_REGIONS) / sizeof(OFavail[0]);
155 if (nreg <= 0 || navail <= 0)
156 panic("no memory?");
157
158 /* Eliminate empty or unreachable regions. */
159 switch (address_cells) {
160 default:
161 case 1:
162 for (i = 0, j = 0; i < nreg; i++) {
163 if (OFmem[i].size == 0)
164 continue;
165 if (i != j) {
166 OFmem[j].start = OFmem[i].start;
167 OFmem[j].size = OFmem[i].size;
168 OFmem[i].start = 0;
169 OFmem[i].size = 0;
170 }
171 j++;
172 }
173 break;
174 case 2:
175 for (i = 0, j = 0; i < nreg; i++) {
176 if (OFmem64[i].size == 0)
177 continue;
178 if (OFmem64[i].start >= 1ULL << 32)
179 continue;
180 OFmem[j].start = OFmem64[i].start;
181 if (OFmem64[i].start + OFmem64[i].size >= 1ULL << 32)
182 OFmem[j].size = (1ULL << 32) - OFmem64[i].start;
183 else
184 OFmem[j].size = OFmem64[i].size;
185 j++;
186 }
187 break;
188 }
189 }
190
191 typedef void (fwcall_f)(int, int);
192 extern fwcall_f *fwcall;
193 fwcall_f fwentry;
194
195 int OF_stdout;
196 int OF_stdin;
197
198 /*
199 * Called early in the boot process, we are still running on the stack
200 * provided by the bootloader using the firmware's page table.
201 */
202 int
save_ofw_mapping(void)203 save_ofw_mapping(void)
204 {
205 int chosen, memory, root, mmui, mmu = -1;
206 int acells, scells;
207 int i, len;
208
209 if ((chosen = OF_finddevice("/chosen")) == -1)
210 return (0);
211
212 ofw_consinit(chosen);
213
214 /* Get memory node. */
215 memory = OF_finddevice("/memory");
216 if (memory == -1)
217 panic("no memory?");
218
219 /* Are physical addresses encoded in 32 or 64 bits? */
220 root = OF_parent(memory);
221 if (OF_getprop(root, "#address-cells", &acells, 4) <= 0)
222 acells = 1;
223 if (OF_getprop(root, "#size-cells", &scells, 4) <= 0)
224 scells = 1;
225
226 if (scells != 1)
227 panic("unexpected memory layout %d:%d", acells, scells);
228
229 ofw_read_mem_regions(memory, acells, scells);
230
231 /* Get firmware mappings. */
232 if (OF_getprop(chosen, "mmu", &mmui, sizeof(int)) != -1)
233 mmu = OF_instance_to_package(mmui);
234 if (mmu != -1) {
235 len = OF_getproplen(mmu, "translations");
236 if (len <= 0)
237 return (0);
238 }
239
240 switch (acells) {
241 case 2:
242 OF_getprop(mmu, "translations", ofw_maps64, sizeof(ofw_maps64));
243
244 for (i = 0; i < nitems(ofw_maps64); i++) {
245 if (ofw_maps64[i].om_phys >= 1ULL << 32)
246 continue;
247
248 ofw_maps[i].om_virt = ofw_maps64[i].om_virt;
249 ofw_maps[i].om_size = ofw_maps64[i].om_size;
250 ofw_maps[i].om_phys = (uint32_t)ofw_maps64[i].om_phys;
251 ofw_maps[i].om_mode = ofw_maps64[i].om_mode;
252 }
253 break;
254 case 1:
255 default:
256 OF_getprop(mmu, "translations", ofw_maps, sizeof(ofw_maps));
257 break;
258 }
259
260 /*
261 * Next time we'll call the firmware make sure we save and
262 * restore our MMU settings.
263 */
264 fwcall = &fwentry;
265
266 return (0);
267 }
268
269 static int display_ofh;
270 int cons_backlight;
271 int cons_brightness;
272 int cons_backlight_available;
273 int fbnode;
274
275 void of_display_console(void);
276
277 void
ofwconprobe(void)278 ofwconprobe(void)
279 {
280 char type[32];
281 int stdout_node;
282
283 stdout_node = OF_instance_to_package(OF_stdout);
284
285 /* handle different types of console */
286
287 bzero(type, sizeof(type));
288 if (OF_getprop(stdout_node, "device_type", type, sizeof(type)) == -1) {
289 return; /* XXX */
290 }
291 if (strcmp(type, "display") == 0) {
292 of_display_console();
293 return;
294 }
295 if (strcmp(type, "serial") == 0) {
296 #if NZSTTY > 0
297 /* zscnprobe/zscninit do all the required initialization */
298 return;
299 #endif
300 }
301
302 OF_stdout = OF_open("screen");
303 OF_stdin = OF_open("keyboard");
304
305 /* cross fingers that this works. */
306 of_display_console();
307
308 return;
309 }
310
311 #define DEVTREE_UNKNOWN 0
312 #define DEVTREE_USB 1
313 #define DEVTREE_ADB 2
314 int ofw_devtree = DEVTREE_UNKNOWN;
315
316 #define OFW_HAVE_USBKBD 1
317 #define OFW_HAVE_ADBKBD 2
318 int ofw_have_kbd = 0;
319
320 void ofw_recurse_keyboard(int pnode);
321 void ofw_find_keyboard(void);
322
323 void
ofw_recurse_keyboard(int pnode)324 ofw_recurse_keyboard(int pnode)
325 {
326 char name[32];
327 int old_devtree;
328 int len;
329 int node;
330
331 for (node = OF_child(pnode); node != 0; node = OF_peer(node)) {
332
333 len = OF_getprop(node, "name", name, 20);
334 if (len == 0)
335 continue;
336 name[len] = 0;
337 if (strcmp(name, "keyboard") == 0) {
338 /* found a keyboard node, where is it? */
339 if (ofw_devtree == DEVTREE_USB) {
340 ofw_have_kbd |= OFW_HAVE_USBKBD;
341 } else if (ofw_devtree == DEVTREE_ADB) {
342 ofw_have_kbd |= OFW_HAVE_ADBKBD;
343 } else {
344 /* hid or some other keyboard? ignore */
345 }
346 continue;
347 }
348
349 old_devtree = ofw_devtree;
350
351 if (strcmp(name, "adb") == 0) {
352 ofw_devtree = DEVTREE_ADB;
353 }
354 if (strcmp(name, "usb") == 0) {
355 ofw_devtree = DEVTREE_USB;
356 }
357
358 ofw_recurse_keyboard(node);
359
360 ofw_devtree = old_devtree; /* nest? */
361 }
362 }
363
364 void
ofw_find_keyboard(void)365 ofw_find_keyboard(void)
366 {
367 int stdin_node;
368 char iname[32];
369 int len, attach = 0;
370
371 stdin_node = OF_instance_to_package(OF_stdin);
372 len = OF_getprop(stdin_node, "name", iname, 20);
373 iname[len] = 0;
374 printf(" console in [%s]", iname);
375
376 /* GRR, apple removed the interface once used for keyboard
377 * detection walk the OFW tree to find keyboards and what type.
378 */
379
380 ofw_recurse_keyboard(OF_peer(0));
381
382 len = OF_getprop(OF_peer(0), "model", iname, sizeof(iname));
383 iname[len] = 0;
384
385 if (ofw_have_kbd == (OFW_HAVE_USBKBD | OFW_HAVE_ADBKBD)) {
386 /*
387 * If a PowerBook reports having ABD and USB keyboards,
388 * use the builtin ADB one for console, the USB one is
389 * certainly a HID device.
390 */
391 if (strncmp(iname, "PowerBook", 9) == 0)
392 ofw_have_kbd = OFW_HAVE_ADBKBD;
393 else
394 ofw_have_kbd = OFW_HAVE_USBKBD;
395 printf("USB and ADB found");
396 }
397 if (ofw_have_kbd == OFW_HAVE_USBKBD) {
398 #if NUKBD > 0
399 printf(", using USB\n");
400 ukbd_cnattach();
401 attach = 1;
402 #endif
403 } else if (ofw_have_kbd == OFW_HAVE_ADBKBD) {
404 #if NAKBD >0
405 printf(", using ADB\n");
406 akbd_cnattach();
407 attach = 1;
408 #endif
409 }
410 if (attach == 0) {
411 #if NUKBD > 0
412 printf(", no keyboard attached, trying usb anyway\n");
413 ukbd_cnattach();
414 #else
415 printf(", no keyboard found!\n");
416 #endif
417 }
418 }
419
420 void
of_display_console(void)421 of_display_console(void)
422 {
423 struct ofw_pci_register addr[8];
424 int cons_height, cons_width, cons_linebytes, cons_depth;
425 uint32_t cons_addr;
426 char name[32];
427 int len, err;
428 int stdout_node;
429
430 stdout_node = OF_instance_to_package(OF_stdout);
431 len = OF_getprop(stdout_node, "name", name, 20);
432 name[len] = 0;
433 printf("console out [%s]", name);
434 display_ofh = OF_stdout;
435 err = OF_getprop(stdout_node, "width", &cons_width, 4);
436 if ( err != 4) {
437 cons_width = 0;
438 }
439 err = OF_getprop(stdout_node, "linebytes", &cons_linebytes, 4);
440 if ( err != 4) {
441 cons_linebytes = cons_width;
442 }
443 err = OF_getprop(stdout_node, "height", &cons_height, 4);
444 if ( err != 4) {
445 cons_height = 0;
446 }
447 err = OF_getprop(stdout_node, "depth", &cons_depth, 4);
448 if ( err != 4) {
449 cons_depth = 0;
450 }
451 err = OF_getprop(stdout_node, "address", &cons_addr, 4);
452 if ( err != 4) {
453 OF_interpret("frame-buffer-adr", 1, &cons_addr);
454 }
455
456 ofw_find_keyboard();
457
458 fbnode = stdout_node;
459 len = OF_getprop(stdout_node, "assigned-addresses", addr, sizeof(addr));
460 if (len == -1) {
461 fbnode = OF_parent(stdout_node);
462 len = OF_getprop(fbnode, "name", name, 20);
463 name[len] = 0;
464
465 printf("using parent %s:", name);
466 len = OF_getprop(fbnode, "assigned-addresses",
467 addr, sizeof(addr));
468 if (len < sizeof(addr[0])) {
469 panic(": no address");
470 }
471 }
472
473 if (OF_getnodebyname(0, "backlight") != 0) {
474 cons_backlight_available = 1;
475 cons_backlight = WSDISPLAYIO_VIDEO_ON;
476 of_setbrightness(DEFAULT_BRIGHTNESS);
477
478 /* wsconsctl hooks */
479 ws_get_param = ofw_get_param;
480 ws_set_param = ofw_set_param;
481 }
482
483 #if 1
484 printf(": memaddr %x, size %x ", addr[0].phys_lo, addr[0].size_lo);
485 printf(": consaddr %x ", cons_addr);
486 printf(": ioaddr %x, size %x", addr[1].phys_lo, addr[1].size_lo);
487 printf(": width %d linebytes %d height %d depth %d\n",
488 cons_width, cons_linebytes, cons_height, cons_depth);
489 #endif
490
491 #if NWSDISPLAY > 0
492 {
493 struct ofwfb *fb = &ofwfb;
494 struct rasops_info *ri = &fb->ofw_ri;
495 uint32_t defattr;
496
497 ri->ri_width = cons_width;
498 ri->ri_height = cons_height;
499 ri->ri_depth = cons_depth;
500 ri->ri_stride = cons_linebytes;
501 ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_CLEAR;
502 ri->ri_bits = (void *)mapiodev(cons_addr, cons_linebytes * cons_height);
503 ri->ri_hw = fb;
504
505 if (cons_depth == 8)
506 of_setcolors(rasops_cmap, 0, 256);
507
508 rasops_init(ri, 160, 160);
509
510 strlcpy(fb->ofw_wsd.name, "std", sizeof(fb->ofw_wsd.name));
511 fb->ofw_wsd.capabilities = ri->ri_caps;
512 fb->ofw_wsd.ncols = ri->ri_cols;
513 fb->ofw_wsd.nrows = ri->ri_rows;
514 fb->ofw_wsd.textops = &ri->ri_ops;
515 #if 0
516 fb->ofw_wsd.fontwidth = ri->ri_font->fontwidth;
517 fb->ofw_wsd.fontheight = ri->ri_font->fontheight;
518 #endif
519
520 ri->ri_ops.pack_attr(ri, 0, 0, 0, &defattr);
521 wsdisplay_cnattach(&fb->ofw_wsd, ri, 0, 0, defattr);
522 }
523 #endif
524 }
525
526 void
ofwconsswitch(struct rasops_info * ri)527 ofwconsswitch(struct rasops_info *ri)
528 {
529 #if NWSDISPLAY > 0
530 ri->ri_width = ofwfb.ofw_ri.ri_width;
531 ri->ri_height = ofwfb.ofw_ri.ri_height;
532 ri->ri_depth = ofwfb.ofw_ri.ri_depth;
533 ri->ri_stride = ofwfb.ofw_ri.ri_stride;
534
535 ri->ri_bits = ofwfb.ofw_ri.ri_bits /* XXX */;
536 #endif
537 }
538
539 void
of_setbacklight(int on)540 of_setbacklight(int on)
541 {
542 if (cons_backlight_available == 0)
543 return;
544
545 cons_backlight = on;
546
547 if (on)
548 OF_call_method_1("backlight-on", display_ofh, 0);
549 else
550 OF_call_method_1("backlight-off", display_ofh, 0);
551 }
552
553 void
of_setbrightness(int brightness)554 of_setbrightness(int brightness)
555 {
556 if (cons_backlight_available == 0)
557 return;
558
559 if (brightness < MIN_BRIGHTNESS)
560 brightness = MIN_BRIGHTNESS;
561 else if (brightness > MAX_BRIGHTNESS)
562 brightness = MAX_BRIGHTNESS;
563
564 cons_brightness = brightness;
565
566 /*
567 * The OF method is called "set-contrast" but affects brightness.
568 * Don't ask.
569 */
570 OF_call_method_1("set-contrast", display_ofh, 1, cons_brightness);
571
572 /* XXX this routine should also save the brightness settings in the nvram */
573 }
574
575 uint8_t of_cmap[256 * 3];
576
577 void
of_setcolors(const uint8_t * cmap,unsigned int index,unsigned int count)578 of_setcolors(const uint8_t *cmap, unsigned int index, unsigned int count)
579 {
580 bcopy(cmap, of_cmap, sizeof(of_cmap));
581 OF_call_method_1("set-colors", display_ofh, 3, &of_cmap, index, count);
582 }
583
584 #include <dev/cons.h>
585
586 cons_decl(ofw);
587
588 /*
589 * Console support functions
590 */
591 void
ofwcnprobe(struct consdev * cd)592 ofwcnprobe(struct consdev *cd)
593 {
594 }
595
596 void
ofwcninit(struct consdev * cd)597 ofwcninit(struct consdev *cd)
598 {
599 }
600 void
ofwcnputc(dev_t dev,int c)601 ofwcnputc(dev_t dev, int c)
602 {
603 char ch = c;
604
605 OF_write(OF_stdout, &ch, 1);
606 }
607 int
ofwcngetc(dev_t dev)608 ofwcngetc(dev_t dev)
609 {
610 unsigned char ch = '\0';
611 int l;
612
613 while ((l = OF_read(OF_stdin, &ch, 1)) != 1)
614 if (l != -2 && l != 0)
615 return -1;
616 return ch;
617 }
618
619 void
ofwcnpollc(dev_t dev,int on)620 ofwcnpollc(dev_t dev, int on)
621 {
622 }
623
624 struct consdev consdev_ofw = {
625 ofwcnprobe,
626 ofwcninit,
627 ofwcngetc,
628 ofwcnputc,
629 ofwcnpollc,
630 NULL,
631 };
632
633 void
ofw_consinit(int chosen)634 ofw_consinit(int chosen)
635 {
636 struct consdev *cp = &consdev_ofw;
637
638 OF_getprop(chosen, "stdin", &OF_stdin, sizeof(OF_stdin));
639 OF_getprop(chosen, "stdout", &OF_stdout, sizeof(OF_stdout));
640
641 /* If the screen is to be console, but not active, open it */
642 if (OF_stdout == 0)
643 OF_stdout = OF_open("screen");
644
645 cn_tab = cp;
646 }
647
648 int
ofw_set_param(struct wsdisplay_param * dp)649 ofw_set_param(struct wsdisplay_param *dp)
650 {
651 switch (dp->param) {
652 case WSDISPLAYIO_PARAM_BRIGHTNESS:
653 if (cons_backlight_available != 0) {
654 of_setbrightness(dp->curval);
655 return 0;
656 }
657 break;
658 case WSDISPLAYIO_PARAM_BACKLIGHT:
659 if (cons_backlight_available != 0) {
660 of_setbacklight(dp->curval ? WSDISPLAYIO_VIDEO_ON
661 : WSDISPLAYIO_VIDEO_OFF);
662 return 0;
663 }
664 break;
665 default:
666 break;
667 }
668
669 return -1;
670 }
671
672 int
ofw_get_param(struct wsdisplay_param * dp)673 ofw_get_param(struct wsdisplay_param *dp)
674 {
675 switch (dp->param) {
676 case WSDISPLAYIO_PARAM_BRIGHTNESS:
677 if (cons_backlight_available != 0) {
678 dp->min = MIN_BRIGHTNESS;
679 dp->max = MAX_BRIGHTNESS;
680 dp->curval = cons_brightness;
681 return 0;
682 }
683 break;
684 case WSDISPLAYIO_PARAM_BACKLIGHT:
685 if (cons_backlight_available != 0) {
686 dp->min = 0;
687 dp->max = 1;
688 dp->curval = cons_backlight;
689 return 0;
690 }
691 break;
692 default:
693 break;
694 }
695
696 return -1;
697 }
698