xref: /freebsd/sys/dev/vt/hw/ofwfb/ofwfb.c (revision f499134dd403eeeba8283e2640e2654c8da62430)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011 Nathan Whitehorn
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/fbio.h>
36 
37 #include <dev/vt/vt.h>
38 #include <dev/vt/hw/fb/vt_fb.h>
39 #include <dev/vt/colors/vt_termcolors.h>
40 
41 #include <vm/vm.h>
42 #include <vm/pmap.h>
43 
44 #include <machine/bus.h>
45 #include <machine/cpu.h>
46 
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_pci.h>
50 #include <dev/ofw/ofw_subr.h>
51 
52 struct ofwfb_softc {
53 	struct fb_info	fb;
54 
55 	phandle_t	sc_node;
56 	ihandle_t	sc_handle;
57 	bus_space_tag_t	sc_memt;
58 	int		iso_palette;
59 	int		argb;
60 	int		endian_flip;
61 	uint32_t	vendor_id;
62 };
63 
64 #define PCI_VID_NVIDIA	0x10de	/* NVIDIA Corporation */
65 #define PCI_VID_ASPEED	0x1a03	/* ASPEED Technology, Inc. */
66 
67 static void ofwfb_initialize(struct vt_device *vd);
68 static vd_probe_t	ofwfb_probe;
69 static vd_init_t	ofwfb_init;
70 static vd_bitblt_text_t	ofwfb_bitblt_text;
71 static vd_bitblt_bmp_t	ofwfb_bitblt_bitmap;
72 
73 static const struct vt_driver vt_ofwfb_driver = {
74 	.vd_name	= "ofwfb",
75 	.vd_probe	= ofwfb_probe,
76 	.vd_init	= ofwfb_init,
77 	.vd_blank	= vt_fb_blank,
78 	.vd_bitblt_text	= ofwfb_bitblt_text,
79 	.vd_bitblt_bmp	= ofwfb_bitblt_bitmap,
80 	.vd_fb_ioctl	= vt_fb_ioctl,
81 	.vd_fb_mmap	= vt_fb_mmap,
82 	.vd_priority	= VD_PRIORITY_GENERIC+1,
83 };
84 
85 static unsigned char ofw_colors[16] = {
86 	/* See "16-color Text Extension" Open Firmware document, page 4 */
87 	0, 4, 2, 6, 1, 5, 3, 7,
88 	8, 12, 10, 14, 9, 13, 11, 15
89 };
90 
91 static struct ofwfb_softc ofwfb_conssoftc;
92 VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver);
93 
94 static int
95 ofwfb_probe(struct vt_device *vd)
96 {
97 	int disabled;
98 	phandle_t chosen, node;
99 	ihandle_t stdout;
100 	char buf[64];
101 
102 	disabled = 0;
103 	TUNABLE_INT_FETCH("hw.ofwfb.disable", &disabled);
104 	if (disabled)
105 		return (CN_DEAD);
106 
107 	chosen = OF_finddevice("/chosen");
108 	if (chosen == -1)
109 		return (CN_DEAD);
110 
111 	node = -1;
112 	if (OF_getencprop(chosen, "stdout", &stdout, sizeof(stdout)) ==
113 	    sizeof(stdout))
114 		node = OF_instance_to_package(stdout);
115 	if (node == -1)
116 		if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0)
117 			node = OF_finddevice(buf);
118 	if (node == -1) {
119 		/*
120 		 * The "/chosen/stdout" does not exist try
121 		 * using "screen" directly.
122 		 */
123 		node = OF_finddevice("screen");
124 	}
125 	OF_getprop(node, "device_type", buf, sizeof(buf));
126 	if (strcmp(buf, "display") != 0)
127 		return (CN_DEAD);
128 
129 	/* Looks OK... */
130 	return (CN_INTERNAL);
131 }
132 
133 static void
134 ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
135     const uint8_t *pattern, const uint8_t *mask,
136     unsigned int width, unsigned int height,
137     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
138 {
139 	struct fb_info *sc = vd->vd_softc;
140 	u_long line;
141 	uint32_t fgc, bgc;
142 	int c, l;
143 	uint8_t b, m;
144 	union {
145 		uint32_t l;
146 		uint8_t	 c[4];
147 	} ch1, ch2;
148 
149 #ifdef __powerpc__
150 	/* Deal with unmapped framebuffers */
151 	if (sc->fb_flags & FB_FLAG_NOWRITE) {
152 		if (pmap_bootstrapped) {
153 			sc->fb_flags &= ~FB_FLAG_NOWRITE;
154 			ofwfb_initialize(vd);
155 			vd->vd_driver->vd_blank(vd, TC_BLACK);
156 		} else {
157 			return;
158 		}
159 	}
160 #endif
161 
162 	fgc = sc->fb_cmap[fg];
163 	bgc = sc->fb_cmap[bg];
164 	b = m = 0;
165 
166 	if (((struct ofwfb_softc *)vd->vd_softc)->iso_palette) {
167 		fg = ofw_colors[fg];
168 		bg = ofw_colors[bg];
169 	}
170 
171 	line = (sc->fb_stride * y) + x * sc->fb_bpp/8;
172 	if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) {
173 		/* Don't try to put off screen pixels */
174 		if (((x + width) > vd->vd_width) || ((y + height) >
175 		    vd->vd_height))
176 			return;
177 
178 		for (; height > 0; height--) {
179 			for (c = 0; c < width; c += 8) {
180 				b = *pattern++;
181 
182 				/*
183 				 * Assume that there is more background than
184 				 * foreground in characters and init accordingly
185 				 */
186 				ch1.l = ch2.l = (bg << 24) | (bg << 16) |
187 				    (bg << 8) | bg;
188 
189 				/*
190 				 * Calculate 2 x 4-chars at a time, and then
191 				 * write these out.
192 				 */
193 				if (b & 0x80) ch1.c[0] = fg;
194 				if (b & 0x40) ch1.c[1] = fg;
195 				if (b & 0x20) ch1.c[2] = fg;
196 				if (b & 0x10) ch1.c[3] = fg;
197 
198 				if (b & 0x08) ch2.c[0] = fg;
199 				if (b & 0x04) ch2.c[1] = fg;
200 				if (b & 0x02) ch2.c[2] = fg;
201 				if (b & 0x01) ch2.c[3] = fg;
202 
203 				*(uint32_t *)(sc->fb_vbase + line + c) = ch1.l;
204 				*(uint32_t *)(sc->fb_vbase + line + c + 4) =
205 				    ch2.l;
206 			}
207 			line += sc->fb_stride;
208 		}
209 	} else {
210 		for (l = 0;
211 		    l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
212 		    l++) {
213 			for (c = 0;
214 			    c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
215 			    c++) {
216 				if (c % 8 == 0)
217 					b = *pattern++;
218 				else
219 					b <<= 1;
220 				if (mask != NULL) {
221 					if (c % 8 == 0)
222 						m = *mask++;
223 					else
224 						m <<= 1;
225 					/* Skip pixel write, if mask not set. */
226 					if ((m & 0x80) == 0)
227 						continue;
228 				}
229 				switch(sc->fb_bpp) {
230 				case 8:
231 					*(uint8_t *)(sc->fb_vbase + line + c) =
232 					    b & 0x80 ? fg : bg;
233 					break;
234 				case 32:
235 					*(uint32_t *)(sc->fb_vbase + line + 4*c)
236 					    = (b & 0x80) ? fgc : bgc;
237 					break;
238 				default:
239 					/* panic? */
240 					break;
241 				}
242 			}
243 			line += sc->fb_stride;
244 		}
245 	}
246 }
247 
248 void
249 ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
250     const term_rect_t *area)
251 {
252 	unsigned int col, row, x, y;
253 	struct vt_font *vf;
254 	term_char_t c;
255 	term_color_t fg, bg;
256 	const uint8_t *pattern;
257 
258 	vf = vw->vw_font;
259 
260 	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
261 		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
262 		    ++col) {
263 			x = col * vf->vf_width +
264 			    vw->vw_draw_area.tr_begin.tp_col;
265 			y = row * vf->vf_height +
266 			    vw->vw_draw_area.tr_begin.tp_row;
267 
268 			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
269 			pattern = vtfont_lookup(vf, c);
270 			vt_determine_colors(c,
271 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
272 
273 			ofwfb_bitblt_bitmap(vd, vw,
274 			    pattern, NULL, vf->vf_width, vf->vf_height,
275 			    x, y, fg, bg);
276 		}
277 	}
278 
279 #ifndef SC_NO_CUTPASTE
280 	if (!vd->vd_mshown)
281 		return;
282 
283 	term_rect_t drawn_area;
284 
285 	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
286 	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
287 	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
288 	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
289 
290 	if (vt_is_cursor_in_area(vd, &drawn_area)) {
291 		ofwfb_bitblt_bitmap(vd, vw,
292 		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
293 		    vd->vd_mcursor->width, vd->vd_mcursor->height,
294 		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
295 		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
296 		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
297 	}
298 #endif
299 }
300 
301 
302 /*
303  * Decode OpenFirmware/IEEE 1275-1994 "ranges" property
304  *
305  * XXX: this is similar to ofw_pcib_fill_ranges but cannot use it here because
306  *      it's not possible to allocate memory at the moment this is funcion is
307  *      used. Since there are other similar functions dealing with "ranges"
308  *      property, a proper refactoring is suggested.
309  */
310 static uint64_t
311 decode_pci_ranges_host_addr(phandle_t pcinode)
312 {
313 	struct simplebus_range {
314 		uint64_t bus;
315 		uint64_t host;
316 		uint64_t size;
317 	};
318 
319 	struct simplebus_range ranges[4];
320 	int nranges, host_address_cells;
321 	pcell_t acells, scells;
322 	cell_t base_ranges[64];
323 
324 	ssize_t nbase_ranges;
325 	int i, j, k;
326 
327 	if (!OF_hasprop(pcinode, "ranges"))
328 		return (0);
329 
330 	if (OF_getencprop(pcinode, "#address-cells", &acells, sizeof(acells)) !=
331 	    sizeof(acells))
332 		return (0);
333 
334 	if (OF_getencprop(pcinode, "#size-cells", &scells, sizeof(scells)) !=
335 		sizeof(scells))
336 		return (0);
337 
338 	if (OF_searchencprop(OF_parent(pcinode), "#address-cells",
339 		&host_address_cells, sizeof(host_address_cells)) !=
340 		sizeof(host_address_cells))
341 		return (0);
342 
343 	nbase_ranges = OF_getproplen(pcinode, "ranges");
344 	nranges = nbase_ranges / sizeof(cell_t) / (acells + host_address_cells + scells);
345 
346 	/* prevent buffer overflow during iteration */
347 	if (nranges > sizeof(ranges) / sizeof(ranges[0]))
348 		nranges = sizeof(ranges) / sizeof(ranges[0]);
349 
350 	/* decode range value and return the first valid address */
351 	OF_getencprop(pcinode, "ranges", base_ranges, nbase_ranges);
352 	for (i = 0, j = 0; i < nranges; i++) {
353 		ranges[i].bus = 0;
354 		for (k = 0; k < acells; k++) {
355 			ranges[i].bus <<= 32;
356 			ranges[i].bus |= base_ranges[j++];
357 		}
358 
359 		ranges[i].host = 0;
360 		for (k = 0; k < host_address_cells; k++) {
361 			ranges[i].host <<= 32;
362 			ranges[i].host |= base_ranges[j++];
363 		}
364 		ranges[i].size = 0;
365 		for (k = 0; k < scells; k++) {
366 			ranges[i].size <<= 32;
367 			ranges[i].size |= base_ranges[j++];
368 		}
369 
370 		if (ranges[i].host != 0)
371 			return (ranges[i].host);
372 	}
373 
374 	return (0);
375 }
376 
377 static bus_addr_t
378 find_pci_host_address(phandle_t node)
379 {
380 	uint64_t addr;
381 
382 	/*
383 	 * According to IEEE STD 1275, if property "ranges" exists but has a
384 	 * zero-length property value, the child address space is identical
385 	 * to the parent address space.
386 	 */
387 	while (node) {
388 		if (OF_hasprop(node, "ranges")) {
389 			addr = decode_pci_ranges_host_addr(node);
390 			if (addr != 0)
391 				return ((bus_addr_t)addr);
392 		}
393 		node = OF_parent(node);
394 	}
395 
396 	return (0);
397 }
398 
399 static void
400 ofwfb_initialize(struct vt_device *vd)
401 {
402 	struct ofwfb_softc *sc = vd->vd_softc;
403 	int i, err, r, g, b;
404 	cell_t retval;
405 
406 	sc->fb.fb_cmsize = 16;
407 
408 	if (sc->fb.fb_flags & FB_FLAG_NOWRITE)
409 		return;
410 
411 	/*
412 	 * Set up the color map
413 	 */
414 
415 	sc->iso_palette = 0;
416 	switch (sc->fb.fb_bpp) {
417 	case 8:
418 		/*
419 		 * No color format issues here, since we are passing the RGB
420 		 * components separately to Open Firmware.
421 		 */
422 		vt_config_cons_colors(&sc->fb, COLOR_FORMAT_RGB, 255,
423 		    16, 255, 8, 255, 0);
424 
425 		for (i = 0; i < 16; i++) {
426 			err = OF_call_method("color!", sc->sc_handle, 4, 1,
427 			    (cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff),
428 			    (cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff),
429 			    (cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff),
430 			    (cell_t)i, &retval);
431 			if (err)
432 				break;
433 		}
434 		if (i != 16)
435 			sc->iso_palette = 1;
436 
437 		break;
438 
439 	case 32:
440 		/*
441 		 * There are two main color formats in use.
442 		 * ARGB32 is used mainly on hardware that was designed for
443 		 * LE systems, and RGBA32 is used mainly on hardware designed
444 		 * for BE systems.
445 		 *
446 		 * PowerMacs use either, depending on the video card option.
447 		 * NVidia cards tend to be RGBA32, and ATI cards tend to be ARGB32.
448 		 *
449 		 * There is no good way to determine the correct option, as this
450 		 * is independent of endian swapping.
451 		 */
452 		if (sc->vendor_id == PCI_VID_NVIDIA)
453 			sc->argb = 0;
454 		else
455 			sc->argb = 1;
456 
457 		TUNABLE_INT_FETCH("hw.ofwfb.argb32_pixel", &sc->argb);
458 		if (sc->endian_flip) {
459 			if (sc->argb)
460 				r = 8, g = 16, b = 24;
461 			else
462 				r = 24, g = 16, b = 8;
463 		} else {
464 			if (sc->argb)
465 				r = 16, g = 8, b = 0;
466 			else
467 				r = 0, g = 8, b = 16;
468 		}
469 		vt_config_cons_colors(&sc->fb,
470 		    COLOR_FORMAT_RGB, 255, r, 255, g, 255, b);
471 		break;
472 
473 	default:
474 		panic("Unknown color space depth %d", sc->fb.fb_bpp);
475 		break;
476         }
477 }
478 
479 static int
480 ofwfb_init(struct vt_device *vd)
481 {
482 	struct ofwfb_softc *sc;
483 	char buf[64];
484 	phandle_t chosen;
485 	phandle_t node;
486 	pcell_t depth, height, width, stride;
487 	uint32_t vendor_id = 0;
488 	cell_t adr[2];
489 	uint64_t user_phys;
490 	bus_addr_t fb_phys;
491 	bus_size_t fb_phys_size;
492 	int i, j, len;
493 
494 	/* Initialize softc */
495 	vd->vd_softc = sc = &ofwfb_conssoftc;
496 
497 	node = -1;
498 	chosen = OF_finddevice("/chosen");
499 	if (OF_getencprop(chosen, "stdout", &sc->sc_handle,
500 	    sizeof(ihandle_t)) == sizeof(ihandle_t))
501 		node = OF_instance_to_package(sc->sc_handle);
502 	if (node == -1)
503 		/* Try "/chosen/stdout-path" now */
504 		if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0) {
505 			node = OF_finddevice(buf);
506 			if (node != -1)
507 				sc->sc_handle = OF_open(buf);
508 		}
509 	if (node == -1) {
510 		/*
511 		 * The "/chosen/stdout" does not exist try
512 		 * using "screen" directly.
513 		 */
514 		node = OF_finddevice("screen");
515 		sc->sc_handle = OF_open("screen");
516 	}
517 	OF_getprop(node, "device_type", buf, sizeof(buf));
518 	if (strcmp(buf, "display") != 0)
519 		return (CN_DEAD);
520 
521 	/*
522 	 * Retrieve vendor-id from /chosen parent node, usually pointing to
523 	 * video card device. This is used to select pixel format later on
524 	 * ofwfb_initialize()
525 	 */
526 	if (OF_getencprop(OF_parent(node), "vendor-id", &vendor_id,
527 	    sizeof(vendor_id)) == sizeof(vendor_id))
528 		sc->vendor_id = vendor_id;
529 
530 	/* Keep track of the OF node */
531 	sc->sc_node = node;
532 
533 	/*
534 	 * Try to use a 32-bit framebuffer if possible. This may be
535 	 * unimplemented and fail. That's fine -- it just means we are
536 	 * stuck with the defaults.
537 	 */
538 	OF_call_method("set-depth", sc->sc_handle, 1, 1, (cell_t)32, &i);
539 
540 	/* Make sure we have needed properties */
541 	if (OF_getproplen(node, "height") != sizeof(height) ||
542 	    OF_getproplen(node, "width") != sizeof(width) ||
543 	    OF_getproplen(node, "depth") != sizeof(depth))
544 		return (CN_DEAD);
545 
546 	/* Only support 8 and 32-bit framebuffers */
547 	OF_getencprop(node, "depth", &depth, sizeof(depth));
548 	if (depth != 8 && depth != 32)
549 		return (CN_DEAD);
550 	sc->fb.fb_bpp = sc->fb.fb_depth = depth;
551 
552 	OF_getencprop(node, "height", &height, sizeof(height));
553 	OF_getencprop(node, "width", &width, sizeof(width));
554 	if (OF_getencprop(node, "linebytes", &stride, sizeof(stride)) !=
555 	    sizeof(stride))
556 		stride = width*depth/8;
557 
558 
559 	sc->fb.fb_height = height;
560 	sc->fb.fb_width = width;
561 	sc->fb.fb_stride = stride;
562 	sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride;
563 	sc->endian_flip = 0;
564 
565 #if defined(__powerpc__)
566 	if (OF_hasprop(node, "little-endian")) {
567 		sc->sc_memt = &bs_le_tag;
568 #if BYTE_ORDER == BIG_ENDIAN
569 		sc->endian_flip = 1;
570 #endif
571         } else if (OF_hasprop(node, "big-endian")) {
572 		sc->sc_memt = &bs_be_tag;
573 #if BYTE_ORDER == LITTLE_ENDIAN
574 		sc->endian_flip = 1;
575 #endif
576 	}
577 	else {
578 		/* Assume the framebuffer is in native endian. */
579 #if BYTE_ORDER == BIG_ENDIAN
580 		sc->sc_memt = &bs_be_tag;
581 #else
582 		sc->sc_memt = &bs_le_tag;
583 #endif
584 	}
585 #elif defined(__arm__)
586 	sc->sc_memt = fdtbus_bs_tag;
587 #else
588 	#error Unsupported platform!
589 #endif
590 
591 
592 	/*
593 	 * Grab the physical address of the framebuffer, and then map it
594 	 * into our memory space. If the MMU is not yet up, it will be
595 	 * remapped for us when relocation turns on.
596 	 *
597 	 * The ASPEED driver on recent petitboot versions doesn't expose the
598 	 * physical address of framebuffer anymore for security. So it should
599 	 * retrieve the address from PCI device properties.
600 	 */
601 	user_phys = 0;
602 	TUNABLE_UINT64_FETCH("hw.ofwfb.physaddr", &user_phys);
603 
604 	if (user_phys)
605 		sc->fb.fb_pbase = (vm_paddr_t)user_phys;
606 	else if (sc->vendor_id == PCI_VID_ASPEED)
607 		sc->fb.fb_pbase = find_pci_host_address(node);
608 	else if (OF_hasprop(node, "address")) {
609 
610 		switch (OF_getproplen(node, "address")) {
611 		case 4:
612 			OF_getencprop(node, "address", adr, 4);
613 			fb_phys = adr[0];
614 			break;
615 		case 8:
616 			OF_getencprop(node, "address", adr, 8);
617 			fb_phys = ((uint64_t)adr[0] << 32) | adr[1];
618 			break;
619 		default:
620 			/* Bad property? */
621 			return (CN_DEAD);
622 		}
623 
624 		sc->fb.fb_pbase = (vm_paddr_t)fb_phys;
625 	} else {
626 #if defined(__powerpc__)
627 		/*
628 		 * Some IBM systems don't have an address property. Try to
629 		 * guess the framebuffer region from the assigned addresses.
630 		 * This is ugly, but there doesn't seem to be an alternative.
631 		 * Linux does the same thing.
632 		 */
633 
634 		struct ofw_pci_register pciaddrs[8];
635 		int num_pciaddrs = 0;
636 
637 		/*
638 		 * Get the PCI addresses of the adapter, if present. The node
639 		 * may be the child of the PCI device: in that case, try the
640 		 * parent for the assigned-addresses property.
641 		 */
642 		len = OF_getencprop(node, "assigned-addresses",
643 		    (pcell_t *)pciaddrs, sizeof(pciaddrs));
644 		if (len == -1) {
645 			len = OF_getencprop(OF_parent(node), "assigned-addresses",
646 			    (pcell_t *)pciaddrs, sizeof(pciaddrs));
647 		}
648 		if (len == -1)
649 			len = 0;
650 		num_pciaddrs = len / sizeof(struct ofw_pci_register);
651 
652 		j = num_pciaddrs;
653 		for (i = 0; i < num_pciaddrs; i++) {
654 			/* If it is too small, not the framebuffer */
655 			if (pciaddrs[i].size_lo < sc->fb.fb_stride * height)
656 				continue;
657 			/* If it is not memory, it isn't either */
658 			if (!(pciaddrs[i].phys_hi &
659 			    OFW_PCI_PHYS_HI_SPACE_MEM32))
660 				continue;
661 
662 			/* This could be the framebuffer */
663 			j = i;
664 
665 			/* If it is prefetchable, it certainly is */
666 			if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
667 				break;
668 		}
669 
670 		if (j == num_pciaddrs) /* No candidates found */
671 			return (CN_DEAD);
672 
673 		if (ofw_reg_to_paddr(node, j, &fb_phys, &fb_phys_size, NULL) < 0)
674 			return (CN_DEAD);
675 
676 		sc->fb.fb_pbase = (vm_paddr_t)fb_phys;
677 #else
678 		/* No ability to interpret assigned-addresses otherwise */
679 		return (CN_DEAD);
680 #endif
681         }
682 
683 	if (!sc->fb.fb_pbase)
684 		return (CN_DEAD);
685 
686 	bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size,
687 	    BUS_SPACE_MAP_PREFETCHABLE,
688 	    (bus_space_handle_t *)&sc->fb.fb_vbase);
689 
690 	#if defined(__powerpc__)
691 	/*
692 	 * If we are running on PowerPC in real mode (supported only on AIM
693 	 * CPUs), the frame buffer may be inaccessible (real mode does not
694 	 * necessarily cover all RAM) and may also be mapped with the wrong
695 	 * cache properties (all real mode accesses are assumed cacheable).
696 	 * Just don't write to it for the time being.
697 	 */
698 	if (!(cpu_features & PPC_FEATURE_BOOKE) && !(mfmsr() & PSL_DR))
699 		sc->fb.fb_flags |= FB_FLAG_NOWRITE;
700 	#endif
701 	ofwfb_initialize(vd);
702 	vt_fb_init(vd);
703 
704 	return (CN_INTERNAL);
705 }
706