1 /* $NetBSD: diofb.c,v 1.6 2021/04/24 23:36:37 thorpej Exp $ */ 2 /* $OpenBSD: diofb.c,v 1.18 2010/12/26 15:40:59 miod Exp $ */ 3 4 /* 5 * Copyright (c) 2005, Miodrag Vallat 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 ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /* 29 * Copyright (c) 1988 University of Utah. 30 * Copyright (c) 1990, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This code is derived from software contributed to Berkeley by 34 * the Systems Programming Group of the University of Utah Computer 35 * Science Department. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62 #include <sys/param.h> 63 #include <sys/conf.h> 64 #include <sys/proc.h> 65 #include <sys/ioctl.h> 66 #include <sys/tty.h> 67 #include <sys/systm.h> 68 #include <sys/device.h> 69 #include <sys/bus.h> 70 #include <sys/cpu.h> 71 72 #include <machine/autoconf.h> 73 74 #include <dev/wscons/wsconsio.h> 75 #include <dev/wscons/wsdisplayvar.h> 76 #include <dev/rasops/rasops.h> 77 78 #include <hp300/dev/dioreg.h> 79 #include <hp300/dev/diovar.h> 80 #include <hp300/dev/diofbreg.h> 81 #include <hp300/dev/diofbvar.h> 82 83 static void diofb_do_cursor(struct rasops_info *); 84 static void diofb_copycols(void *, int, int, int, int); 85 static void diofb_erasecols(void *, int, int, int, long); 86 static void diofb_copyrows(void *, int, int, int); 87 static void diofb_eraserows(void *, int, int, long); 88 static int diofb_allocattr(void *, int, int, int, long *); 89 90 struct diofb diofb_cn; 91 92 /* 93 * Frame buffer geometry initialization 94 */ 95 96 int 97 diofb_fbinquire(struct diofb *fb, int scode, struct diofbreg *fbr) 98 { 99 int fboff, regsize; 100 101 if (ISIIOVA(fbr)) 102 fb->regaddr = (uint8_t *)IIOP(fbr); 103 else 104 fb->regaddr = dio_scodetopa(scode); 105 106 if (fb->fbwidth == 0 || fb->fbheight == 0) { 107 fb->fbwidth = (fbr->fbwmsb << 8) | fbr->fbwlsb; 108 fb->fbheight = (fbr->fbhmsb << 8) | fbr->fbhlsb; 109 } 110 fb->fbsize = fb->fbwidth * fb->fbheight; 111 112 fb->regkva = (uint8_t *)fbr; 113 fboff = (fbr->fbomsb << 8) | fbr->fbolsb; 114 fb->fbaddr = (uint8_t *) (*((uint8_t *)fbr + fboff) << 16); 115 116 if (fb->regaddr >= (uint8_t *)DIOII_BASE) { 117 /* 118 * For DIO-II space the fbaddr just computed is 119 * the offset from the select code base (regaddr) 120 * of the framebuffer. Hence it is also implicitly 121 * the size of the set. 122 */ 123 regsize = (uintptr_t)fb->fbaddr; 124 fb->fbaddr = fb->regaddr + (uintptr_t)fb->fbaddr; 125 fb->fbkva = (uint8_t *)fbr + regsize; 126 } else { 127 /* 128 * For internal or DIO-I space we need to map the separate 129 * framebuffer. 130 */ 131 fb->fbkva = iomap(fb->fbaddr, fb->fbsize); 132 if (fb->fbkva == NULL) 133 return ENOMEM; 134 } 135 if (fb->dwidth == 0 || fb->dheight == 0) { 136 fb->dwidth = (fbr->dwmsb << 8) | fbr->dwlsb; 137 fb->dheight = (fbr->dhmsb << 8) | fbr->dhlsb; 138 } 139 140 /* 141 * Some displays, such as the DaVinci, appear to return a display 142 * height larger than the frame buffer height. 143 */ 144 if (fb->dwidth > fb->fbwidth) 145 fb->dwidth = fb->fbwidth; 146 if (fb->dheight > fb->fbheight) 147 fb->dheight = fb->fbheight; 148 149 /* 150 * Some displays, such as the HP332 and HP340 internal video 151 * appear to return a display width of 1024 instead of 512. 152 */ 153 if (fbr->num_planes == 1 || fbr->num_planes == 4) { 154 if (fb->dwidth == 1024 && fb->dheight == 400) 155 fb->dwidth = 512; 156 } 157 158 fb->planes = fbr->num_planes; 159 if (fb->planes > 8) 160 fb->planes = 8; 161 fb->planemask = (1 << fb->planes) - 1; 162 163 fb->mapmode = WSDISPLAYIO_MODE_DUMBFB; 164 165 return 0; 166 } 167 168 /* 169 * Frame buffer rasops and colormap setup 170 */ 171 172 void 173 diofb_fbsetup(struct diofb *fb) 174 { 175 struct rasops_info *ri = &fb->ri; 176 177 /* 178 * Pretend we are an 8bpp frame buffer, unless ri_depth is already 179 * initialized, since this is how it is supposed to be addressed. 180 * (Hyperion forces 1bpp because it is really 1bpp addressed). 181 */ 182 if (ri->ri_depth == 0) 183 ri->ri_depth = 8; 184 ri->ri_stride = (fb->fbwidth * ri->ri_depth) / 8; 185 186 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 187 /* We don't really support colors on less than 4bpp frame buffers */ 188 if (fb->planes < 4) 189 ri->ri_flg |= RI_FORCEMONO; 190 if (fb == &diofb_cn) 191 ri->ri_flg |= RI_NO_AUTO; 192 ri->ri_bits = fb->fbkva; 193 ri->ri_width = fb->dwidth; 194 ri->ri_height = fb->dheight; 195 ri->ri_hw = fb; 196 197 /* 198 * Ask for an unholy big display, rasops will trim this to more 199 * reasonable values. 200 */ 201 rasops_init(ri, 160, 160); 202 203 diofb_resetcmap(fb); 204 205 /* 206 * For low depth frame buffers, since we have faked a 8bpp frame buffer 207 * to rasops, we actually have to remove capabilities. 208 */ 209 if (fb->planes == 4) { 210 ri->ri_ops.allocattr = diofb_allocattr; 211 ri->ri_caps &= ~WSSCREEN_HILIT; 212 } 213 214 ri->ri_ops.copycols = diofb_copycols; 215 ri->ri_ops.erasecols = diofb_erasecols; 216 if (ri->ri_depth != 1) { 217 ri->ri_ops.copyrows = diofb_copyrows; 218 ri->ri_ops.eraserows = diofb_eraserows; 219 ri->ri_do_cursor = diofb_do_cursor; 220 } 221 222 /* Clear entire display, including non visible areas */ 223 (*fb->bmv)(fb, 0, 0, 0, 0, fb->fbwidth, fb->fbheight, RR_CLEAR, 0xff); 224 225 fb->wsd.name = fb->wsdname; 226 fb->wsd.ncols = ri->ri_cols; 227 fb->wsd.nrows = ri->ri_rows; 228 fb->wsd.textops = &ri->ri_ops; 229 fb->wsd.fontwidth = ri->ri_font->fontwidth; 230 fb->wsd.fontheight = ri->ri_font->fontheight; 231 fb->wsd.capabilities = ri->ri_caps; 232 strlcpy(fb->wsdname, "std", sizeof(fb->wsdname)); 233 } 234 235 /* 236 * Setup default emulation mode colormap 237 */ 238 void 239 diofb_resetcmap(struct diofb *fb) 240 { 241 const u_char *color; 242 u_int i; 243 244 /* start with the rasops colormap */ 245 color = (const u_char *)rasops_cmap; 246 for (i = 0; i < 256; i++) { 247 fb->cmap.r[i] = *color++; 248 fb->cmap.g[i] = *color++; 249 fb->cmap.b[i] = *color++; 250 } 251 252 /* 253 * Tweak colormap 254 * 255 * Due to the way rasops cursor work, we need to provide 256 * copies of the 8 or 16 basic colors at extra locations 257 * in 4bpp and 6bpp mode. This is because missing planes 258 * accept writes but read back as zero. 259 * 260 * So, in 6bpp mode: 261 * 00 gets inverted to ff, read back as 3f 262 * 3f gets inverted to c0, read back as 00 263 * and in 4bpp mode: 264 * 00 gets inverted to ff, read back as 0f 265 * 0f gets inverted to f0, read back as 00 266 */ 267 268 switch (fb->planes) { 269 case 6: 270 /* 271 * 00-0f normal colors 272 * 30-3f inverted colors 273 * c0-cf normal colors 274 * f0-ff inverted colors 275 */ 276 memcpy(fb->cmap.r + 0xc0, fb->cmap.r + 0x00, 0x10); 277 memcpy(fb->cmap.g + 0xc0, fb->cmap.g + 0x00, 0x10); 278 memcpy(fb->cmap.b + 0xc0, fb->cmap.b + 0x00, 0x10); 279 memcpy(fb->cmap.r + 0x30, fb->cmap.r + 0xf0, 0x10); 280 memcpy(fb->cmap.g + 0x30, fb->cmap.g + 0xf0, 0x10); 281 memcpy(fb->cmap.b + 0x30, fb->cmap.b + 0xf0, 0x10); 282 break; 283 case 4: 284 /* 285 * 00-07 normal colors 286 * 08-0f inverted colors 287 * highlighted colors are not available. 288 */ 289 memcpy(fb->cmap.r + 0x08, fb->cmap.r + 0xf8, 0x08); 290 memcpy(fb->cmap.g + 0x08, fb->cmap.g + 0xf8, 0x08); 291 memcpy(fb->cmap.b + 0x08, fb->cmap.b + 0xf8, 0x08); 292 break; 293 } 294 } 295 296 /* 297 * Attachment helpers 298 */ 299 300 void 301 diofb_cnattach(struct diofb *fb) 302 { 303 long defattr; 304 struct rasops_info *ri; 305 306 ri = &fb->ri; 307 ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr); 308 wsdisplay_cnattach(&fb->wsd, ri, 0, 0, defattr); 309 } 310 311 void 312 diofb_end_attach(device_t self, struct wsdisplay_accessops *accessops, 313 struct diofb *fb, int console, const char *descr) 314 { 315 struct wsemuldisplaydev_attach_args waa; 316 317 aprint_normal(": %dx%d", fb->dwidth, fb->dheight); 318 319 if (fb->planes == 1) 320 aprint_normal(" monochrome"); 321 else 322 aprint_normal("x%d", fb->planes); 323 324 if (descr != NULL) 325 aprint_normal(" %s", descr); 326 aprint_normal(" frame buffer\n"); 327 328 fb->scrlist[0] = &fb->wsd; 329 fb->wsl.nscreens = 1; 330 fb->wsl.screens = (void *)fb->scrlist; 331 332 waa.console = console; 333 waa.scrdata = &fb->wsl; 334 waa.accessops = accessops; 335 waa.accesscookie = fb; 336 337 config_found(self, &waa, wsemuldisplaydevprint, CFARG_EOL); 338 } 339 340 /* 341 * Common wsdisplay emulops for DIO frame buffers 342 */ 343 344 int 345 diofb_allocattr(void *cookie, int fg, int bg, int flg, long *attr) 346 { 347 348 if ((flg & (WSATTR_BLINK | WSATTR_HILIT)) != 0) 349 return EINVAL; 350 351 if ((flg & WSATTR_WSCOLORS) == 0) { 352 fg = WSCOL_WHITE; 353 bg = WSCOL_BLACK; 354 } 355 356 if ((flg & WSATTR_REVERSE) != 0) { 357 int swap; 358 swap = fg; 359 fg = bg; 360 bg = swap; 361 } 362 363 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 364 365 *attr = (bg << 16) | (fg << 24) | flg; 366 367 return 0; 368 } 369 370 void 371 diofb_copycols(void *cookie, int row, int src, int dst, int n) 372 { 373 struct rasops_info *ri = cookie; 374 struct diofb *fb = ri->ri_hw; 375 376 n *= ri->ri_font->fontwidth; 377 src *= ri->ri_font->fontwidth; 378 dst *= ri->ri_font->fontwidth; 379 row *= ri->ri_font->fontheight; 380 381 (*fb->bmv)(fb, ri->ri_xorigin + src, ri->ri_yorigin + row, 382 ri->ri_xorigin + dst, ri->ri_yorigin + row, 383 n, ri->ri_font->fontheight, RR_COPY, 0xff); 384 } 385 386 void 387 diofb_copyrows(void *cookie, int src, int dst, int n) 388 { 389 struct rasops_info *ri = cookie; 390 struct diofb *fb = ri->ri_hw; 391 392 n *= ri->ri_font->fontheight; 393 src *= ri->ri_font->fontheight; 394 dst *= ri->ri_font->fontheight; 395 396 (*fb->bmv)(fb, ri->ri_xorigin, ri->ri_yorigin + src, 397 ri->ri_xorigin, ri->ri_yorigin + dst, 398 ri->ri_emuwidth, n, RR_COPY, 0xff); 399 } 400 401 void 402 diofb_erasecols(void *cookie, int row, int col, int num, long attr) 403 { 404 struct rasops_info *ri = cookie; 405 struct diofb *fb = ri->ri_hw; 406 int fg, bg; 407 int snum, scol, srow; 408 409 rasops_unpack_attr(attr, &fg, &bg, NULL); 410 411 snum = num * ri->ri_font->fontwidth; 412 scol = col * ri->ri_font->fontwidth + ri->ri_xorigin; 413 srow = row * ri->ri_font->fontheight + ri->ri_yorigin; 414 415 /* 416 * If this is too tricky for the simple raster ops engine, 417 * pass the fun to rasops. 418 */ 419 if ((*fb->bmv)(fb, scol, srow, scol, srow, snum, 420 ri->ri_font->fontheight, RR_CLEAR, 0xff ^ bg) != 0) 421 rasops_erasecols(cookie, row, col, num, attr); 422 } 423 424 void 425 diofb_eraserows(void *cookie, int row, int num, long attr) 426 { 427 struct rasops_info *ri = cookie; 428 struct diofb *fb = ri->ri_hw; 429 int fg, bg; 430 int srow, snum; 431 int rc; 432 433 rasops_unpack_attr(attr, &fg, &bg, NULL); 434 bg ^= 0xff; 435 436 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) { 437 rc = (*fb->bmv)(fb, 0, 0, 0, 0, ri->ri_width, ri->ri_height, 438 RR_CLEAR, bg); 439 } else { 440 srow = row * ri->ri_font->fontheight + ri->ri_yorigin; 441 snum = num * ri->ri_font->fontheight; 442 rc = (*fb->bmv)(fb, ri->ri_xorigin, srow, ri->ri_xorigin, 443 srow, ri->ri_emuwidth, snum, RR_CLEAR, bg); 444 } 445 if (rc != 0) 446 rasops_eraserows(cookie, row, num, attr); 447 } 448 449 void 450 diofb_do_cursor(struct rasops_info *ri) 451 { 452 struct diofb *fb = ri->ri_hw; 453 int x, y; 454 455 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 456 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 457 (*fb->bmv)(fb, x, y, x, y, ri->ri_font->fontwidth, 458 ri->ri_font->fontheight, RR_INVERT, 0xff); 459 } 460 461 /* 462 * Common wsdisplay accessops for DIO frame buffers 463 */ 464 465 int 466 diofb_alloc_screen(void *v, const struct wsscreen_descr *type, 467 void **cookiep, int *curxp, int *curyp, long *attrp) 468 { 469 struct diofb *fb = v; 470 struct rasops_info *ri = &fb->ri; 471 472 if (fb->nscreens > 0) 473 return ENOMEM; 474 475 *cookiep = ri; 476 *curxp = *curyp = 0; 477 ri->ri_ops.allocattr(ri, 0, 0, 0, attrp); 478 fb->nscreens++; 479 480 return 0; 481 } 482 483 void 484 diofb_free_screen(void *v, void *cookie) 485 { 486 struct diofb *fb = v; 487 488 fb->nscreens--; 489 } 490 491 int 492 diofb_show_screen(void *v, void *cookie, int waitok, 493 void (*cb)(void *, int, int), void *cbarg) 494 { 495 496 return 0; 497 } 498 499 paddr_t 500 diofb_mmap(void *v, void *vs, off_t offset, int prot) 501 { 502 struct diofb *fb = v; 503 504 if ((offset & PAGE_MASK) != 0) 505 return -1; 506 507 switch (fb->mapmode) { 508 case WSDISPLAYIO_MODE_MAPPED: 509 if (offset >= 0 && offset < DIOFB_REGSPACE) 510 return m68k_btop(fb->regaddr + offset); 511 offset -= DIOFB_REGSPACE; 512 /* FALLTHROUGH */ 513 case WSDISPLAYIO_MODE_DUMBFB: 514 if (offset >= 0 && offset < fb->fbsize) 515 return m68k_btop(fb->fbaddr + offset); 516 break; 517 } 518 519 return -1; 520 } 521 522 int 523 diofb_getcmap(struct diofb *fb, struct wsdisplay_cmap *cm) 524 { 525 u_int index = cm->index, count = cm->count; 526 u_int colcount = 1 << fb->planes; 527 int error; 528 529 if (index >= colcount || count > colcount - index) 530 return EINVAL; 531 532 if ((error = copyout(fb->cmap.r + index, cm->red, count)) != 0) 533 return error; 534 if ((error = copyout(fb->cmap.g + index, cm->green, count)) != 0) 535 return error; 536 if ((error = copyout(fb->cmap.b + index, cm->blue, count)) != 0) 537 return error; 538 539 return 0; 540 } 541