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; 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_generate_cons_palette(sc->fb.fb_cmap, 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 vt_generate_cons_palette(sc->fb.fb_cmap, 461 COLOR_FORMAT_RGB, 255, 8, 255, 16, 255, 24); 462 else 463 vt_generate_cons_palette(sc->fb.fb_cmap, 464 COLOR_FORMAT_RGB, 255, 24, 255, 16, 255, 8); 465 } else { 466 if (sc->argb) 467 vt_generate_cons_palette(sc->fb.fb_cmap, 468 COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); 469 else 470 vt_generate_cons_palette(sc->fb.fb_cmap, 471 COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); 472 } 473 break; 474 475 default: 476 panic("Unknown color space depth %d", sc->fb.fb_bpp); 477 break; 478 } 479 } 480 481 static int 482 ofwfb_init(struct vt_device *vd) 483 { 484 struct ofwfb_softc *sc; 485 char buf[64]; 486 phandle_t chosen; 487 phandle_t node; 488 pcell_t depth, height, width, stride; 489 uint32_t vendor_id = 0; 490 cell_t adr[2]; 491 uint64_t user_phys; 492 bus_addr_t fb_phys; 493 bus_size_t fb_phys_size; 494 int i, j, len; 495 496 /* Initialize softc */ 497 vd->vd_softc = sc = &ofwfb_conssoftc; 498 499 node = -1; 500 chosen = OF_finddevice("/chosen"); 501 if (OF_getencprop(chosen, "stdout", &sc->sc_handle, 502 sizeof(ihandle_t)) == sizeof(ihandle_t)) 503 node = OF_instance_to_package(sc->sc_handle); 504 if (node == -1) 505 /* Try "/chosen/stdout-path" now */ 506 if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0) { 507 node = OF_finddevice(buf); 508 if (node != -1) 509 sc->sc_handle = OF_open(buf); 510 } 511 if (node == -1) { 512 /* 513 * The "/chosen/stdout" does not exist try 514 * using "screen" directly. 515 */ 516 node = OF_finddevice("screen"); 517 sc->sc_handle = OF_open("screen"); 518 } 519 OF_getprop(node, "device_type", buf, sizeof(buf)); 520 if (strcmp(buf, "display") != 0) 521 return (CN_DEAD); 522 523 /* 524 * Retrieve vendor-id from /chosen parent node, usually pointing to 525 * video card device. This is used to select pixel format later on 526 * ofwfb_initialize() 527 */ 528 if (OF_getencprop(OF_parent(node), "vendor-id", &vendor_id, 529 sizeof(vendor_id)) == sizeof(vendor_id)) 530 sc->vendor_id = vendor_id; 531 532 /* Keep track of the OF node */ 533 sc->sc_node = node; 534 535 /* 536 * Try to use a 32-bit framebuffer if possible. This may be 537 * unimplemented and fail. That's fine -- it just means we are 538 * stuck with the defaults. 539 */ 540 OF_call_method("set-depth", sc->sc_handle, 1, 1, (cell_t)32, &i); 541 542 /* Make sure we have needed properties */ 543 if (OF_getproplen(node, "height") != sizeof(height) || 544 OF_getproplen(node, "width") != sizeof(width) || 545 OF_getproplen(node, "depth") != sizeof(depth)) 546 return (CN_DEAD); 547 548 /* Only support 8 and 32-bit framebuffers */ 549 OF_getencprop(node, "depth", &depth, sizeof(depth)); 550 if (depth != 8 && depth != 32) 551 return (CN_DEAD); 552 sc->fb.fb_bpp = sc->fb.fb_depth = depth; 553 554 OF_getencprop(node, "height", &height, sizeof(height)); 555 OF_getencprop(node, "width", &width, sizeof(width)); 556 if (OF_getencprop(node, "linebytes", &stride, sizeof(stride)) != 557 sizeof(stride)) 558 stride = width*depth/8; 559 560 561 sc->fb.fb_height = height; 562 sc->fb.fb_width = width; 563 sc->fb.fb_stride = stride; 564 sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride; 565 sc->endian_flip = 0; 566 567 #if defined(__powerpc__) 568 if (OF_hasprop(node, "little-endian")) { 569 sc->sc_memt = &bs_le_tag; 570 #if BYTE_ORDER == BIG_ENDIAN 571 sc->endian_flip = 1; 572 #endif 573 } else if (OF_hasprop(node, "big-endian")) { 574 sc->sc_memt = &bs_be_tag; 575 #if BYTE_ORDER == LITTLE_ENDIAN 576 sc->endian_flip = 1; 577 #endif 578 } 579 else { 580 /* Assume the framebuffer is in native endian. */ 581 #if BYTE_ORDER == BIG_ENDIAN 582 sc->sc_memt = &bs_be_tag; 583 #else 584 sc->sc_memt = &bs_le_tag; 585 #endif 586 } 587 #elif defined(__arm__) 588 sc->sc_memt = fdtbus_bs_tag; 589 #else 590 #error Unsupported platform! 591 #endif 592 593 594 /* 595 * Grab the physical address of the framebuffer, and then map it 596 * into our memory space. If the MMU is not yet up, it will be 597 * remapped for us when relocation turns on. 598 * 599 * The ASPEED driver on recent petitboot versions doesn't expose the 600 * physical address of framebuffer anymore for security. So it should 601 * retrieve the address from PCI device properties. 602 */ 603 user_phys = 0; 604 TUNABLE_UINT64_FETCH("hw.ofwfb.physaddr", &user_phys); 605 606 if (user_phys) 607 sc->fb.fb_pbase = (vm_paddr_t)user_phys; 608 else if (sc->vendor_id == PCI_VID_ASPEED) 609 sc->fb.fb_pbase = find_pci_host_address(node); 610 else if (OF_hasprop(node, "address")) { 611 612 switch (OF_getproplen(node, "address")) { 613 case 4: 614 OF_getencprop(node, "address", adr, 4); 615 fb_phys = adr[0]; 616 break; 617 case 8: 618 OF_getencprop(node, "address", adr, 8); 619 fb_phys = ((uint64_t)adr[0] << 32) | adr[1]; 620 break; 621 default: 622 /* Bad property? */ 623 return (CN_DEAD); 624 } 625 626 sc->fb.fb_pbase = (vm_paddr_t)fb_phys; 627 } else { 628 #if defined(__powerpc__) 629 /* 630 * Some IBM systems don't have an address property. Try to 631 * guess the framebuffer region from the assigned addresses. 632 * This is ugly, but there doesn't seem to be an alternative. 633 * Linux does the same thing. 634 */ 635 636 struct ofw_pci_register pciaddrs[8]; 637 int num_pciaddrs = 0; 638 639 /* 640 * Get the PCI addresses of the adapter, if present. The node 641 * may be the child of the PCI device: in that case, try the 642 * parent for the assigned-addresses property. 643 */ 644 len = OF_getencprop(node, "assigned-addresses", 645 (pcell_t *)pciaddrs, sizeof(pciaddrs)); 646 if (len == -1) { 647 len = OF_getencprop(OF_parent(node), "assigned-addresses", 648 (pcell_t *)pciaddrs, sizeof(pciaddrs)); 649 } 650 if (len == -1) 651 len = 0; 652 num_pciaddrs = len / sizeof(struct ofw_pci_register); 653 654 j = num_pciaddrs; 655 for (i = 0; i < num_pciaddrs; i++) { 656 /* If it is too small, not the framebuffer */ 657 if (pciaddrs[i].size_lo < sc->fb.fb_stride * height) 658 continue; 659 /* If it is not memory, it isn't either */ 660 if (!(pciaddrs[i].phys_hi & 661 OFW_PCI_PHYS_HI_SPACE_MEM32)) 662 continue; 663 664 /* This could be the framebuffer */ 665 j = i; 666 667 /* If it is prefetchable, it certainly is */ 668 if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) 669 break; 670 } 671 672 if (j == num_pciaddrs) /* No candidates found */ 673 return (CN_DEAD); 674 675 if (ofw_reg_to_paddr(node, j, &fb_phys, &fb_phys_size, NULL) < 0) 676 return (CN_DEAD); 677 678 sc->fb.fb_pbase = (vm_paddr_t)fb_phys; 679 #else 680 /* No ability to interpret assigned-addresses otherwise */ 681 return (CN_DEAD); 682 #endif 683 } 684 685 if (!sc->fb.fb_pbase) 686 return (CN_DEAD); 687 688 bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size, 689 BUS_SPACE_MAP_PREFETCHABLE, 690 (bus_space_handle_t *)&sc->fb.fb_vbase); 691 692 #if defined(__powerpc__) 693 /* 694 * If we are running on PowerPC in real mode (supported only on AIM 695 * CPUs), the frame buffer may be inaccessible (real mode does not 696 * necessarily cover all RAM) and may also be mapped with the wrong 697 * cache properties (all real mode accesses are assumed cacheable). 698 * Just don't write to it for the time being. 699 */ 700 if (!(cpu_features & PPC_FEATURE_BOOKE) && !(mfmsr() & PSL_DR)) 701 sc->fb.fb_flags |= FB_FLAG_NOWRITE; 702 #endif 703 ofwfb_initialize(vd); 704 vt_fb_init(vd); 705 706 return (CN_INTERNAL); 707 } 708