1 /* $OpenBSD: fb.c,v 1.31 2024/09/04 07:54:52 mglocker Exp $ */ 2 /* $NetBSD: fb.c,v 1.23 1997/07/07 23:30:22 pk Exp $ */ 3 4 /* 5 * Copyright (c) 2002, 2004, 2008 Miodrag Vallat. 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 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * 30 * Copyright (c) 1992, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This software was developed by the Computer Systems Engineering group 34 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 35 * contributed to Berkeley. 36 * 37 * All advertising materials mentioning features or use of this software 38 * must display the following acknowledgement: 39 * This product includes software developed by the University of 40 * California, Lawrence Berkeley Laboratory. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)fb.c 8.1 (Berkeley) 6/11/93 67 */ 68 69 /* 70 * Common wsdisplay framebuffer drivers helpers. 71 */ 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/device.h> 76 #include <sys/proc.h> 77 #include <sys/conf.h> 78 79 #include <machine/autoconf.h> 80 #include <machine/conf.h> 81 #include <machine/openfirm.h> 82 83 #include <dev/wscons/wsdisplayvar.h> 84 #include <dev/rasops/rasops.h> 85 #include <machine/fbvar.h> 86 87 #include "wsdisplay.h" 88 89 /* 90 * Sun specific color indexes. 91 * Black is not really 7, but rather ~0; to fit within the 8 ANSI color 92 * palette we are using on console, we pick (~0) & 0x07 instead. 93 * This essentially swaps WSCOL_BLACK and WSCOL_WHITE. 94 */ 95 #define WSCOL_SUN_WHITE 0 96 #define WSCOL_SUN_BLACK 7 97 98 /* 99 * emergency unblank code 100 * XXX should be somewhat moved to wscons MI code 101 */ 102 103 void (*fb_burner)(void *, u_int, u_int); 104 void *fb_cookie; 105 106 void 107 fb_unblank(void) 108 { 109 if (fb_burner != NULL) 110 (*fb_burner)(fb_cookie, 1, 0); 111 } 112 113 #if NWSDISPLAY > 0 114 115 static int a2int(char *, int); 116 int fb_get_console_metrics(int *, int *, int *, int *); 117 void fb_initwsd(struct sunfb *); 118 void fb_updatecursor(struct rasops_info *); 119 120 int fb_alloc_screen(void *, const struct wsscreen_descr *, void **, 121 int *, int *, uint32_t *); 122 void fb_free_screen(void *, void *); 123 int fb_show_screen(void *, void *, int, void (*)(void *, int, int), 124 void *); 125 int fb_load_font(void *, void *, struct wsdisplay_font *); 126 int fb_list_font(void *, struct wsdisplay_font *); 127 128 void 129 fb_setsize(struct sunfb *sf, int def_depth, int def_width, int def_height, 130 int node, int unused) 131 { 132 int def_linebytes; 133 134 /* 135 * Some PCI devices lack the `depth' property, but have a `depth ' 136 * property (with a trailing space) instead. 137 */ 138 sf->sf_depth = getpropint(node, "depth", 139 getpropint(node, "depth ", def_depth)); 140 sf->sf_width = getpropint(node, "width", def_width); 141 sf->sf_height = getpropint(node, "height", def_height); 142 143 def_linebytes = 144 roundup(sf->sf_width, sf->sf_depth) * sf->sf_depth / 8; 145 sf->sf_linebytes = getpropint(node, "linebytes", def_linebytes); 146 147 /* 148 * XXX If we are configuring a board in a wider depth level 149 * than the mode it is currently operating in, the PROM will 150 * return a linebytes property tied to the current depth value, 151 * which is NOT what we are relying upon! 152 */ 153 if (sf->sf_linebytes < (sf->sf_width * sf->sf_depth) / 8) 154 sf->sf_linebytes = def_linebytes; 155 156 sf->sf_fbsize = sf->sf_height * sf->sf_linebytes; 157 } 158 159 static int 160 a2int(char *cp, int deflt) 161 { 162 int i = 0; 163 164 if (*cp == '\0') 165 return (deflt); 166 while (*cp != '\0') 167 i = i * 10 + *cp++ - '0'; 168 return (i); 169 } 170 171 /* setup the embedded wsscreen_descr structure from rasops settings */ 172 void 173 fb_initwsd(struct sunfb *sf) 174 { 175 strlcpy(sf->sf_wsd.name, "std", sizeof(sf->sf_wsd.name)); 176 sf->sf_wsd.capabilities = sf->sf_ro.ri_caps; 177 sf->sf_wsd.nrows = sf->sf_ro.ri_rows; 178 sf->sf_wsd.ncols = sf->sf_ro.ri_cols; 179 sf->sf_wsd.textops = &sf->sf_ro.ri_ops; 180 } 181 182 void 183 fb_updatecursor(struct rasops_info *ri) 184 { 185 struct sunfb *sf = (struct sunfb *)ri->ri_hw; 186 187 if (sf->sf_crowp != NULL) 188 *sf->sf_crowp = ri->ri_crow; 189 if (sf->sf_ccolp != NULL) 190 *sf->sf_ccolp = ri->ri_ccol; 191 } 192 193 void 194 fbwscons_init(struct sunfb *sf, int flags, int isconsole) 195 { 196 struct rasops_info *ri = &sf->sf_ro; 197 int cols, rows, fw, fh, wt, wl; 198 199 /* ri_hw and ri_bits must have already been setup by caller */ 200 ri->ri_flg = RI_FULLCLEAR | flags; 201 ri->ri_depth = sf->sf_depth; 202 ri->ri_stride = sf->sf_linebytes; 203 ri->ri_width = sf->sf_width; 204 ri->ri_height = sf->sf_height; 205 206 rows = a2int(getpropstring(optionsnode, "screen-#rows"), 34); 207 cols = a2int(getpropstring(optionsnode, "screen-#columns"), 80); 208 209 /* 210 * If the framebuffer width is under 960 pixels, rasops will 211 * switch from the 12x22 font to the more adequate 8x16 font 212 * here. 213 * If we are the console device, we need to adjust two things: 214 * - the display row should be overridden from the current PROM 215 * metrics, since it will not match the PROM reality anymore. 216 * - the screen needs to be cleared. 217 * 218 * However, to accommodate laptops with specific small fonts, 219 * it is necessary to compare the resolution with the actual 220 * font metrics. 221 */ 222 223 if (isconsole) { 224 if (fb_get_console_metrics(&fw, &fh, &wt, &wl) != 0) { 225 /* 226 * Assume a 12x22 prom font and a centered 227 * 80x34 console window. 228 */ 229 fw = 12; fh = 22; 230 wt = wl = 0; 231 } else { 232 /* 233 * Make sure window-top and window-left 234 * values are consistent with the font metrics. 235 */ 236 if (wt <= 0 || wt > sf->sf_height - rows * fh || 237 wl <= 0 || wl > sf->sf_width - cols * fw) 238 wt = wl = 0; 239 } 240 if (wt == 0 /* || wl == 0 */) { 241 ri->ri_flg |= RI_CENTER; 242 243 /* 244 * Since the console window might not be 245 * centered (e.g. on a 1280x1024 vigra 246 * VS-12 frame buffer), have rasops 247 * clear the margins even if the screen is 248 * not cleared. 249 */ 250 ri->ri_flg |= RI_CLEARMARGINS; 251 } 252 253 if (ri->ri_wsfcookie != 0) { 254 /* driver handles font issues. do nothing. */ 255 } else { 256 /* 257 * If the PROM uses a different font than the 258 * one we are expecting it to use, or if the 259 * display is shorter than 960 pixels wide, 260 * we'll force a screen clear. 261 */ 262 if (fw != 12 || sf->sf_width < 12 * 80) 263 ri->ri_flg |= RI_CLEAR | RI_CENTER; 264 } 265 } else { 266 ri->ri_flg |= RI_CLEAR | RI_CENTER; 267 } 268 269 /* ifb(4) doesn't set ri_bits at the moment */ 270 if (ri->ri_bits == NULL) 271 ri->ri_flg &= ~(RI_CLEAR | RI_CLEARMARGINS); 272 273 rasops_init(ri, rows, cols); 274 275 /* 276 * If this is the console display and there is no font change, 277 * adjust our terminal window to the position of the PROM 278 * window - in case it is not exactly centered. 279 */ 280 if ((ri->ri_flg & RI_CENTER) == 0) { 281 /* code above made sure wt and wl are initialized */ 282 ri->ri_bits += wt * ri->ri_stride; 283 if (ri->ri_depth >= 8) /* for 15bpp to compute ok */ 284 ri->ri_bits += wl * ri->ri_pelbytes; 285 else 286 ri->ri_bits += (wl * ri->ri_depth) >> 3; 287 288 ri->ri_xorigin = wl; 289 ri->ri_yorigin = wt; 290 } 291 292 if (sf->sf_depth == 8) { 293 /* 294 * If we are running with an indexed palette, compensate 295 * the swap of black and white through ri_devcmap. 296 */ 297 ri->ri_devcmap[WSCOL_SUN_BLACK] = 0; 298 ri->ri_devcmap[WSCOL_SUN_WHITE] = 0xffffffff; 299 } else if (sf->sf_depth > 8) { 300 /* 301 * If we are running on a direct color frame buffer, 302 * make the ``normal'' white the same as the highlighted 303 * white. 304 */ 305 ri->ri_devcmap[WSCOL_WHITE] = ri->ri_devcmap[WSCOL_WHITE + 8]; 306 } 307 } 308 309 void 310 fbwscons_console_init(struct sunfb *sf, int row) 311 { 312 struct rasops_info *ri = &sf->sf_ro; 313 void *cookie; 314 uint32_t defattr; 315 316 if (romgetcursoraddr(&sf->sf_crowp, &sf->sf_ccolp)) 317 sf->sf_ccolp = sf->sf_crowp = NULL; 318 if (sf->sf_ccolp != NULL) 319 ri->ri_ccol = *sf->sf_ccolp; 320 321 if (ri->ri_flg & RI_CLEAR) { 322 /* 323 * If we have cleared the screen, this is because either 324 * we are not the console display, or the font has been 325 * changed. 326 * In this case, choose not to keep pointers to the PROM 327 * cursor position, as the values are likely to be inaccurate 328 * upon shutdown... 329 */ 330 sf->sf_crowp = sf->sf_ccolp = NULL; 331 row = 0; 332 } 333 334 if (row < 0) /* no override */ { 335 if (sf->sf_crowp != NULL) 336 ri->ri_crow = *sf->sf_crowp; 337 else 338 /* assume last row */ 339 ri->ri_crow = ri->ri_rows - 1; 340 } else { 341 ri->ri_crow = row; 342 } 343 344 /* 345 * Scale back rows and columns if the font would not otherwise 346 * fit on this display. Without this we would panic later. 347 */ 348 if (ri->ri_crow >= ri->ri_rows) 349 ri->ri_crow = ri->ri_rows - 1; 350 if (ri->ri_ccol >= ri->ri_cols) 351 ri->ri_ccol = ri->ri_cols - 1; 352 353 /* 354 * Take care of updating the PROM cursor position as well if we can. 355 */ 356 if (ri->ri_updatecursor != NULL && 357 (sf->sf_ccolp != NULL || sf->sf_crowp != NULL)) 358 ri->ri_updatecursor = fb_updatecursor; 359 360 if (ri->ri_flg & RI_VCONS) 361 cookie = ri->ri_active; 362 else 363 cookie = ri; 364 365 if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS)) 366 ri->ri_ops.pack_attr(cookie, 367 WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, &defattr); 368 else 369 ri->ri_ops.pack_attr(cookie, 0, 0, 0, &defattr); 370 371 fb_initwsd(sf); 372 wsdisplay_cnattach(&sf->sf_wsd, cookie, 373 ri->ri_ccol, ri->ri_crow, defattr); 374 } 375 376 void 377 fbwscons_setcolormap(struct sunfb *sf, 378 void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t)) 379 { 380 int i; 381 const u_char *color; 382 383 if (sf->sf_depth <= 8 && setcolor != NULL) { 384 for (i = 0; i < 16; i++) { 385 color = &rasops_cmap[i * 3]; 386 setcolor(sf, i, color[0], color[1], color[2]); 387 } 388 for (i = 240; i < 256; i++) { 389 color = &rasops_cmap[i * 3]; 390 setcolor(sf, i, color[0], color[1], color[2]); 391 } 392 /* 393 * Compensate for BoW default hardware palette: existing 394 * output (which we do not want to affect) is black on 395 * white with color index 0 being white and 0xff being 396 * black. 397 */ 398 setcolor(sf, WSCOL_SUN_WHITE, 0xff, 0xff, 0xff); 399 setcolor(sf, 0xff ^ WSCOL_SUN_WHITE, 0, 0, 0); 400 setcolor(sf, WSCOL_SUN_BLACK, 0, 0, 0); 401 setcolor(sf, 0xff ^ (WSCOL_SUN_BLACK), 0xff, 0xff, 0xff); 402 } 403 } 404 405 void 406 fbwscons_attach(struct sunfb *sf, struct wsdisplay_accessops *op, int isconsole) 407 { 408 struct wsemuldisplaydev_attach_args waa; 409 410 if (isconsole == 0) { 411 /* done in wsdisplay_cnattach() earlier if console */ 412 fb_initwsd(sf); 413 } else { 414 /* remember screen burner routine */ 415 fb_burner = op->burn_screen; 416 fb_cookie = sf; 417 } 418 419 /* plug common wsdisplay_accessops if necessary */ 420 if (op->alloc_screen == NULL) { 421 op->alloc_screen = fb_alloc_screen; 422 op->free_screen = fb_free_screen; 423 op->show_screen = fb_show_screen; 424 } 425 if (op->load_font == NULL) { 426 op->load_font = fb_load_font; 427 op->list_font = fb_list_font; 428 } 429 430 sf->sf_scrlist[0] = &sf->sf_wsd; 431 sf->sf_wsl.nscreens = 1; 432 sf->sf_wsl.screens = (const struct wsscreen_descr **)sf->sf_scrlist; 433 434 waa.console = isconsole; 435 waa.scrdata = &sf->sf_wsl; 436 waa.accessops = op; 437 waa.accesscookie = sf; 438 waa.defaultscreens = 0; 439 config_found(&sf->sf_dev, &waa, wsemuldisplaydevprint); 440 } 441 442 /* 443 * Common wsdisplay_accessops routines. 444 */ 445 int 446 fb_alloc_screen(void *v, const struct wsscreen_descr *type, 447 void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 448 { 449 struct sunfb *sf = v; 450 struct rasops_info *ri = &sf->sf_ro; 451 void *cookie; 452 453 if (sf->sf_nscreens > 0) 454 return (ENOMEM); 455 456 if (ri->ri_flg & RI_VCONS) 457 cookie = ri->ri_active; 458 else 459 cookie = ri; 460 461 *cookiep = cookie; 462 *curyp = 0; 463 *curxp = 0; 464 if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS)) 465 ri->ri_ops.pack_attr(cookie, 466 WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); 467 else 468 ri->ri_ops.pack_attr(cookie, 0, 0, 0, attrp); 469 sf->sf_nscreens++; 470 return (0); 471 } 472 473 void 474 fb_free_screen(void *v, void *cookie) 475 { 476 struct sunfb *sf = v; 477 478 sf->sf_nscreens--; 479 } 480 481 int 482 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), 483 void *cbarg) 484 { 485 return (0); 486 } 487 488 int 489 fb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font) 490 { 491 struct sunfb *sf = v; 492 struct rasops_info *ri = &sf->sf_ro; 493 494 return rasops_load_font(ri, emulcookie, font); 495 } 496 497 int 498 fb_list_font(void *v, struct wsdisplay_font *font) 499 { 500 struct sunfb *sf = v; 501 struct rasops_info *ri = &sf->sf_ro; 502 503 return rasops_list_font(ri, font); 504 } 505 506 int 507 fb_get_console_metrics(int *fontwidth, int *fontheight, int *wtop, int *wleft) 508 { 509 cell_t romheight, romwidth, windowtop, windowleft; 510 511 /* 512 * Get the PROM font metrics and address 513 */ 514 OF_interpret("stdout @ is my-self " 515 "addr char-height addr char-width " 516 "addr window-top addr window-left", 517 4, &windowleft, &windowtop, &romwidth, &romheight); 518 519 if (romheight == 0 || romwidth == 0 || 520 windowtop == 0 || windowleft == 0) 521 return (1); 522 523 *fontwidth = (int)*(uint64_t *)romwidth; 524 *fontheight = (int)*(uint64_t *)romheight; 525 *wtop = (int)*(uint64_t *)windowtop; 526 *wleft = (int)*(uint64_t *)windowleft; 527 528 return (0); 529 } 530 531 #endif /* NWSDISPLAY */ 532