1 /* $NetBSD: wcfb.c,v 1.22 2025/10/04 03:58:38 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008, 2009 Miodrag Vallat. 5 * 2010 Michael Lorenz 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* a driver for (some) 3DLabs Wildcat cards, based on OpenBSD's ifb driver */ 21 22 #include <sys/cdefs.h> 23 __KERNEL_RCSID(0, "$NetBSD: wcfb.c,v 1.22 2025/10/04 03:58:38 thorpej Exp $"); 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/kernel.h> 28 #include <sys/device.h> 29 #include <sys/proc.h> 30 #include <sys/mutex.h> 31 #include <sys/ioctl.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/kauth.h> 35 #include <sys/kmem.h> 36 37 #include <dev/pci/pcidevs.h> 38 #include <dev/pci/pcireg.h> 39 #include <dev/pci/pcivar.h> 40 #include <dev/pci/pciio.h> 41 #include <dev/pci/wcfbreg.h> 42 43 #include <dev/wscons/wsdisplayvar.h> 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/wsfont/wsfont.h> 46 #include <dev/rasops/rasops.h> 47 #include <dev/wscons/wsdisplay_vconsvar.h> 48 #include <dev/pci/wsdisplay_pci.h> 49 50 #include "opt_wsfb.h" 51 #include "opt_wsdisplay_compat.h" 52 53 #ifdef WCFB_DEBUG 54 # define DPRINTF printf 55 #else 56 # define DPRINTF while (0) printf 57 #endif 58 59 static int wcfb_match(device_t, cfdata_t, void *); 60 static void wcfb_attach(device_t, device_t, void *); 61 static int wcfb_ioctl(void *, void *, u_long, void *, int, 62 struct lwp *); 63 static paddr_t wcfb_mmap(void *, void *, off_t, int); 64 65 struct wcfb_softc { 66 device_t sc_dev; 67 68 pci_chipset_tag_t sc_pc; 69 pcitag_t sc_pcitag; 70 71 bus_space_tag_t sc_memt; 72 bus_space_tag_t sc_regt, sc_wtft; 73 bus_space_tag_t sc_iot; 74 75 bus_space_handle_t sc_fbh; 76 bus_space_handle_t sc_regh; 77 bus_addr_t sc_fb, sc_reg; 78 bus_size_t sc_fbsize, sc_regsize; 79 80 int sc_width, sc_height, sc_stride; 81 int sc_locked; 82 uint8_t *sc_fbaddr, *sc_fb0, *sc_fb1, *sc_shadow; 83 struct vcons_screen sc_console_screen; 84 struct wsscreen_descr sc_defaultscreen_descr; 85 const struct wsscreen_descr *sc_screens[1]; 86 struct wsscreen_list sc_screenlist; 87 struct vcons_data vd; 88 int sc_mode, sc_dpms; 89 u_char sc_cmap_red[256]; 90 u_char sc_cmap_green[256]; 91 u_char sc_cmap_blue[256]; 92 uint32_t sc_fb0off, sc_fb1off, sc_fb8size; 93 94 void (*copycols)(void *, int, int, int, int); 95 void (*erasecols)(void *, int, int, int, long); 96 void (*copyrows)(void *, int, int, int); 97 void (*eraserows)(void *, int, int, long); 98 void (*putchar)(void *, int, int, u_int, long); 99 void (*cursor)(void *, int, int, int); 100 int sc_is_jfb; 101 }; 102 103 static void wcfb_init_screen(void *, struct vcons_screen *, int, long *); 104 105 CFATTACH_DECL_NEW(wcfb, sizeof(struct wcfb_softc), 106 wcfb_match, wcfb_attach, NULL, NULL); 107 108 struct wsdisplay_accessops wcfb_accessops = { 109 wcfb_ioctl, 110 wcfb_mmap, 111 NULL, /* alloc_screen */ 112 NULL, /* free_screen */ 113 NULL, /* show_screen */ 114 NULL, /* load_font */ 115 NULL, /* pollc */ 116 NULL /* scroll */ 117 }; 118 119 static void wcfb_putchar(void *, int, int, u_int, long); 120 static void wcfb_cursor(void *, int, int, int); 121 static void wcfb_copycols(void *, int, int, int, int); 122 static void wcfb_erasecols(void *, int, int, int, long); 123 static void wcfb_copyrows(void *, int, int, int); 124 static void wcfb_eraserows(void *, int, int, long); 125 126 static void wcfb_acc_putchar(void *, int, int, u_int, long); 127 static void wcfb_acc_cursor(void *, int, int, int); 128 static void wcfb_acc_copycols(void *, int, int, int, int); 129 static void wcfb_acc_erasecols(void *, int, int, int, long); 130 static void wcfb_acc_copyrows(void *, int, int, int); 131 static void wcfb_acc_eraserows(void *, int, int, long); 132 133 static void wcfb_putpalreg(struct wcfb_softc *, int, int, int, int); 134 135 static void wcfb_bitblt(struct wcfb_softc *, int, int, int, int, int, 136 int, uint32_t); 137 static void wcfb_rectfill(struct wcfb_softc *, int, int, int, int, int); 138 static void wcfb_rop_common(struct wcfb_softc *, bus_addr_t, int, int, int, 139 int, int, int, uint32_t, int32_t); 140 static void wcfb_rop_jfb(struct wcfb_softc *, int, int, int, int, int, int, 141 uint32_t, int32_t); 142 static int wcfb_rop_wait(struct wcfb_softc *); 143 144 static int 145 wcfb_match(device_t parent, cfdata_t match, void *aux) 146 { 147 struct pci_attach_args *pa = aux; 148 149 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3DLABS && 150 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_WILDCAT5110) 151 return 100; 152 153 return 0; 154 } 155 156 static void 157 wcfb_attach(device_t parent, device_t self, void *aux) 158 { 159 struct wcfb_softc *sc = device_private(self); 160 struct pci_attach_args *pa = aux; 161 struct rasops_info *ri; 162 struct wsemuldisplaydev_attach_args aa; 163 int i, j; 164 uint32_t reg; 165 unsigned long defattr; 166 bool is_console; 167 uint32_t sub; 168 169 sc->sc_dev = self; 170 sc->putchar = NULL; 171 pci_aprint_devinfo(pa, NULL); 172 173 is_console = device_getprop_bool(self, "is_console"); 174 175 #ifndef WCFB_DEBUG 176 if (!is_console) return; 177 #endif 178 sc->sc_memt = pa->pa_memt; 179 sc->sc_iot = pa->pa_iot; 180 sc->sc_pc = pa->pa_pc; 181 sc->sc_pcitag = pa->pa_tag; 182 183 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, 184 &sc->sc_regt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { 185 aprint_error("%s: failed to map registers.\n", 186 device_xname(sc->sc_dev)); 187 } 188 189 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 190 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, 191 &sc->sc_memt, &sc->sc_fbh, &sc->sc_fb, &sc->sc_fbsize)) { 192 aprint_error("%s: failed to map framebuffer.\n", 193 device_xname(sc->sc_dev)); 194 } 195 196 sc->sc_fbaddr = bus_space_vaddr(sc->sc_memt, sc->sc_fbh); 197 #ifdef DEBUG 198 memset(sc->sc_fbaddr, 0, sc->sc_fbsize); 199 #endif 200 sc->sc_fb0off = 201 bus_space_read_4(sc->sc_regt, sc->sc_regh, 202 WC_FB8_ADDR0) - sc->sc_fb; 203 sc->sc_fb0 = sc->sc_fbaddr + sc->sc_fb0off; 204 sc->sc_fb1off = 205 bus_space_read_4(sc->sc_regt, sc->sc_regh, 206 WC_FB8_ADDR1) - sc->sc_fb; 207 sc->sc_fb1 = sc->sc_fbaddr + sc->sc_fb1off; 208 sc->sc_fb8size = 2 * (sc->sc_fb1off - sc->sc_fb0off); 209 210 sub = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PCI_SUBSYS_ID_REG); 211 aprint_normal("subsys: %08x\n", sub); 212 switch (sub) { 213 case WC_XVR1200: 214 sc->sc_is_jfb = 1; 215 break; 216 default: 217 sc->sc_is_jfb = 0; 218 } 219 220 reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_RESOLUTION); 221 sc->sc_height = (reg >> 16) + 1; 222 #ifdef WCFB_DEBUG 223 sc->sc_height -= 200; 224 #endif 225 sc->sc_width = (reg & 0xffff) + 1; 226 sc->sc_stride = 1 << 227 ((bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_CONFIG) & 228 0x00ff0000) >> 16); 229 aprint_normal_dev(self, "%d x %d, %d\n", 230 sc->sc_width, sc->sc_height, sc->sc_stride); 231 232 if (sc->sc_is_jfb == 0) { 233 sc->sc_shadow = kmem_alloc(sc->sc_stride * sc->sc_height, 234 KM_SLEEP); 235 } 236 237 for (i = 0x40; i < 0x100; i += 16) { 238 aprint_normal("%04x:", i); 239 for (j = 0; j < 16; j += 4) { 240 aprint_normal(" %08x", bus_space_read_4(sc->sc_regt, 241 sc->sc_regh, 0x8000 + i + j)); 242 } 243 aprint_normal("\n"); 244 } 245 246 /* make sure video output is on */ 247 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_DPMS_STATE, WC_DPMS_ON); 248 sc->sc_dpms = WSDISPLAYIO_VIDEO_ON; 249 250 #if 0 251 /* testing & debugging voodoo */ 252 memset(sc->sc_fb0, 0x01, 0x00100000); 253 memset(sc->sc_fb1, 0x00, 0x00100000); 254 wcfb_rop_wait(sc); 255 wcfb_rop_jfb(sc, 0, 0, 0, 0, 600, 600, WC_ROP_SET, 0xffffffff); 256 wcfb_rop_wait(sc); 257 delay(4000000); 258 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_FB8_ADDR1, 259 bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_FB8_ADDR0)); 260 delay(8000000); 261 #endif 262 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 263 "default", 264 0, 0, 265 NULL, 266 8, 16, 267 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 268 NULL 269 }; 270 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 271 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 272 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 273 sc->sc_locked = 0; 274 275 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 276 &wcfb_accessops); 277 sc->vd.init_screen = wcfb_init_screen; 278 279 /* init engine here */ 280 #if 0 281 wcfb_init(sc); 282 #endif 283 284 ri = &sc->sc_console_screen.scr_ri; 285 286 j = 0; 287 for (i = 0; i < 256; i++) { 288 289 sc->sc_cmap_red[i] = rasops_cmap[j]; 290 sc->sc_cmap_green[i] = rasops_cmap[j + 1]; 291 sc->sc_cmap_blue[i] = rasops_cmap[j + 2]; 292 wcfb_putpalreg(sc, i, rasops_cmap[j], rasops_cmap[j + 1], 293 rasops_cmap[j + 2]); 294 j += 3; 295 } 296 297 if (is_console) { 298 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 299 &defattr); 300 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 301 302 if (sc->sc_is_jfb) { 303 wcfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 304 ri->ri_devcmap[(defattr >> 16) & 0xff]); 305 } else { 306 memset(sc->sc_fb0, 307 ri->ri_devcmap[(defattr >> 16) & 0xff], 308 sc->sc_stride * sc->sc_height); 309 memset(sc->sc_fb1, 310 ri->ri_devcmap[(defattr >> 16) & 0xff], 311 sc->sc_stride * sc->sc_height); 312 } 313 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 314 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 315 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 316 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 317 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 318 defattr); 319 vcons_replay_msgbuf(&sc->sc_console_screen); 320 } else { 321 /* 322 * since we're not the console we can postpone the rest 323 * until someone actually allocates a screen for us 324 */ 325 memset(sc->sc_fb0, WS_DEFAULT_BG, 326 sc->sc_stride * sc->sc_height); 327 memset(sc->sc_fb1, WS_DEFAULT_BG, 328 sc->sc_stride * sc->sc_height); 329 return; 330 } 331 332 aa.console = is_console; 333 aa.scrdata = &sc->sc_screenlist; 334 aa.accessops = &wcfb_accessops; 335 aa.accesscookie = &sc->vd; 336 337 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 338 } 339 340 static int 341 wcfb_putcmap(struct wcfb_softc *sc, struct wsdisplay_cmap *cm) 342 { 343 u_char *r, *g, *b; 344 u_int index = cm->index; 345 u_int count = cm->count; 346 int i, error; 347 u_char rbuf[256], gbuf[256], bbuf[256]; 348 349 if (cm->index >= 256 || cm->count > 256 || 350 (cm->index + cm->count) > 256) 351 return EINVAL; 352 error = copyin(cm->red, &rbuf[index], count); 353 if (error) 354 return error; 355 error = copyin(cm->green, &gbuf[index], count); 356 if (error) 357 return error; 358 error = copyin(cm->blue, &bbuf[index], count); 359 if (error) 360 return error; 361 362 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 363 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 364 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 365 366 r = &sc->sc_cmap_red[index]; 367 g = &sc->sc_cmap_green[index]; 368 b = &sc->sc_cmap_blue[index]; 369 370 for (i = 0; i < count; i++) { 371 wcfb_putpalreg(sc, index, *r, *g, *b); 372 index++; 373 r++, g++, b++; 374 } 375 return 0; 376 } 377 378 static int 379 wcfb_getcmap(struct wcfb_softc *sc, struct wsdisplay_cmap *cm) 380 { 381 u_int index = cm->index; 382 u_int count = cm->count; 383 int error; 384 385 if (index >= 255 || count > 256 || index + count > 256) 386 return EINVAL; 387 388 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 389 if (error) 390 return error; 391 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 392 if (error) 393 return error; 394 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 395 if (error) 396 return error; 397 398 return 0; 399 } 400 401 static int 402 wcfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 403 struct lwp *l) 404 { 405 struct vcons_data *vd = v; 406 struct wcfb_softc *sc = vd->cookie; 407 408 switch (cmd) { 409 case WSDISPLAYIO_GTYPE: 410 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 411 return 0; 412 413 /* PCI config read/write passthrough. */ 414 case PCI_IOC_CFGREAD: 415 case PCI_IOC_CFGWRITE: 416 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 417 cmd, data, flag, l); 418 419 case WSDISPLAYIO_GET_BUSID: 420 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 421 sc->sc_pcitag, data); 422 423 case WSDISPLAYIO_SVIDEO: { 424 int new_mode = *(int*)data; 425 if (new_mode != sc->sc_dpms) { 426 sc->sc_dpms = new_mode; 427 bus_space_write_4(sc->sc_regt, sc->sc_regh, 428 WC_DPMS_STATE, 429 (new_mode == WSDISPLAYIO_VIDEO_ON) ? 430 WC_DPMS_ON : WC_DPMS_STANDBY); 431 } 432 } 433 return 0; 434 435 case WSDISPLAYIO_GVIDEO: 436 *(int*)data = sc->sc_dpms; 437 return 0; 438 439 case WSDISPLAYIO_GETCMAP: 440 return wcfb_getcmap(sc, 441 (struct wsdisplay_cmap *)data); 442 443 case WSDISPLAYIO_PUTCMAP: 444 return wcfb_putcmap(sc, 445 (struct wsdisplay_cmap *)data); 446 447 case WSDISPLAYIO_GET_FBINFO: { 448 struct wsdisplayio_fbinfo *fbi = data; 449 450 fbi->fbi_fbsize = sc->sc_fb8size; 451 fbi->fbi_fboffset = 0; 452 fbi->fbi_width = sc->sc_width; 453 fbi->fbi_height = sc->sc_height; 454 fbi->fbi_bitsperpixel = 8; 455 fbi->fbi_stride = sc->sc_stride; 456 fbi->fbi_pixeltype = WSFB_CI; 457 fbi->fbi_subtype.fbi_cmapinfo.cmap_entries = 256; 458 fbi->fbi_flags = WSFB_VRAM_IS_SPLIT; 459 return 0; 460 } 461 } 462 return EPASSTHROUGH; 463 } 464 465 static paddr_t 466 wcfb_mmap(void *v, void *vs, off_t offset, int prot) 467 { 468 struct vcons_data *vd = v; 469 struct wcfb_softc *sc = vd->cookie; 470 471 /* XXX in theory the order is not fixed... */ 472 473 if (offset < sc->sc_fb8size) 474 return bus_space_mmap(sc->sc_memt, sc->sc_fb + sc->sc_fb0off, 475 offset, prot, 476 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 477 /* 478 * restrict all other mappings to processes with superuser privileges 479 * or the kernel itself 480 */ 481 if (kauth_authorize_machdep(kauth_cred_get(), 482 KAUTH_MACHDEP_UNMANAGEDMEM, 483 NULL, NULL, NULL, NULL) != 0) { 484 aprint_normal_dev(sc->sc_dev, "mmap() rejected.\n"); 485 return -1; 486 } 487 488 /* may want to mmap() registers at some point */ 489 490 return -1; 491 } 492 493 static void 494 wcfb_init_screen(void *cookie, struct vcons_screen *scr, 495 int existing, long *defattr) 496 { 497 struct wcfb_softc *sc = cookie; 498 struct rasops_info *ri = &scr->scr_ri; 499 500 ri->ri_depth = 8; 501 ri->ri_width = sc->sc_width; 502 ri->ri_height = sc->sc_height; 503 ri->ri_stride = sc->sc_stride; 504 ri->ri_flg = RI_CENTER /*| RI_FULLCLEAR*/; 505 506 if (sc->sc_is_jfb) { 507 ri->ri_bits = sc->sc_fb0; 508 } else { 509 ri->ri_bits = sc->sc_shadow; 510 } 511 if (existing) { 512 ri->ri_flg |= RI_CLEAR; 513 } 514 515 rasops_init(ri, 0, 0); 516 ri->ri_caps = WSSCREEN_WSCOLORS; 517 518 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 519 sc->sc_width / ri->ri_font->fontwidth); 520 521 ri->ri_hw = scr; 522 sc->putchar = ri->ri_ops.putchar; 523 sc->copyrows = ri->ri_ops.copyrows; 524 sc->eraserows = ri->ri_ops.eraserows; 525 sc->copycols = ri->ri_ops.copycols; 526 sc->erasecols = ri->ri_ops.erasecols; 527 528 if (sc->sc_is_jfb) { 529 ri->ri_ops.copyrows = wcfb_acc_copyrows; 530 ri->ri_ops.copycols = wcfb_acc_copycols; 531 ri->ri_ops.eraserows = wcfb_acc_eraserows; 532 ri->ri_ops.erasecols = wcfb_acc_erasecols; 533 ri->ri_ops.putchar = wcfb_acc_putchar; 534 ri->ri_ops.cursor = wcfb_acc_cursor; 535 } else { 536 ri->ri_ops.copyrows = wcfb_copyrows; 537 ri->ri_ops.copycols = wcfb_copycols; 538 ri->ri_ops.eraserows = wcfb_eraserows; 539 ri->ri_ops.erasecols = wcfb_erasecols; 540 ri->ri_ops.putchar = wcfb_putchar; 541 ri->ri_ops.cursor = wcfb_cursor; 542 } 543 } 544 545 static void 546 wcfb_putchar(void *cookie, int row, int col, u_int c, long attr) 547 { 548 struct rasops_info *ri = cookie; 549 struct vcons_screen *scr = ri->ri_hw; 550 struct wcfb_softc *sc = scr->scr_cookie; 551 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 552 sc->sc_stride + ri->ri_xorigin + col * ri->ri_font->fontwidth; 553 uint8_t *from, *to0, *to1; 554 int i; 555 556 sc->putchar(ri, row, col, c, attr); 557 from = sc->sc_shadow + offset; 558 to0 = sc->sc_fb0 + offset; 559 to1 = sc->sc_fb1 + offset; 560 for (i = 0; i < ri->ri_font->fontheight; i++) { 561 memcpy(to0, from, ri->ri_font->fontwidth); 562 memcpy(to1, from, ri->ri_font->fontwidth); 563 to0 += sc->sc_stride; 564 to1 += sc->sc_stride; 565 from += sc->sc_stride; 566 } 567 } 568 569 static void 570 wcfb_putpalreg(struct wcfb_softc *sc, int i, int r, int g, int b) 571 { 572 uint32_t rgb; 573 574 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_CMAP_INDEX, i); 575 rgb = (b << 22) | (g << 12) | (r << 2); 576 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_CMAP_DATA, rgb); 577 } 578 579 static void 580 wcfb_cursor(void *cookie, int on, int row, int col) 581 { 582 struct rasops_info *ri = cookie; 583 struct vcons_screen *scr = ri->ri_hw; 584 struct wcfb_softc *sc = scr->scr_cookie; 585 int coffset; 586 587 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 588 589 if (ri->ri_flg & RI_CURSOR) { 590 /* remove cursor */ 591 coffset = ri->ri_ccol + (ri->ri_crow * ri->ri_cols); 592 coffset += vcons_offset_to_zero(scr); 593 wcfb_putchar(cookie, ri->ri_crow, 594 ri->ri_ccol, scr->scr_chars[coffset], 595 scr->scr_attrs[coffset]); 596 ri->ri_flg &= ~RI_CURSOR; 597 } 598 ri->ri_crow = row; 599 ri->ri_ccol = col; 600 if (on) { 601 long attr, revattr; 602 coffset = col + (row * ri->ri_cols); 603 #ifdef WSDISPLAY_SCROLLSUPPORT 604 coffset += scr->scr_offset_to_zero; 605 #endif 606 attr = scr->scr_attrs[coffset]; 607 revattr = attr ^ 0xffff0000; 608 609 wcfb_putchar(cookie, ri->ri_crow, ri->ri_ccol, 610 scr->scr_chars[coffset], revattr); 611 ri->ri_flg |= RI_CURSOR; 612 } 613 } else { 614 ri->ri_crow = row; 615 ri->ri_ccol = col; 616 ri->ri_flg &= ~RI_CURSOR; 617 } 618 } 619 620 static void 621 wcfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 622 { 623 struct rasops_info *ri = cookie; 624 struct vcons_screen *scr = ri->ri_hw; 625 struct wcfb_softc *sc = scr->scr_cookie; 626 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 627 sc->sc_stride + ri->ri_xorigin + dstcol * ri->ri_font->fontwidth; 628 uint8_t *from, *to0, *to1; 629 int i; 630 631 sc->copycols(ri, row, srccol, dstcol, ncols); 632 from = sc->sc_shadow + offset; 633 to0 = sc->sc_fb0 + offset; 634 to1 = sc->sc_fb1 + offset; 635 for (i = 0; i < ri->ri_font->fontheight; i++) { 636 memcpy(to0, from, ri->ri_font->fontwidth * ncols); 637 memcpy(to1, from, ri->ri_font->fontwidth * ncols); 638 to0 += sc->sc_stride; 639 to1 += sc->sc_stride; 640 from += sc->sc_stride; 641 } 642 } 643 644 static void 645 wcfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 646 { 647 struct rasops_info *ri = cookie; 648 struct vcons_screen *scr = ri->ri_hw; 649 struct wcfb_softc *sc = scr->scr_cookie; 650 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 651 sc->sc_stride + ri->ri_xorigin + startcol * ri->ri_font->fontwidth; 652 uint8_t *to0, *to1; 653 int i; 654 655 sc->erasecols(ri, row, startcol, ncols, fillattr); 656 657 to0 = sc->sc_fb0 + offset; 658 to1 = sc->sc_fb1 + offset; 659 for (i = 0; i < ri->ri_font->fontheight; i++) { 660 memset(to0, ri->ri_devcmap[(fillattr >> 16) & 0xff], 661 ri->ri_font->fontwidth * ncols); 662 memset(to1, ri->ri_devcmap[(fillattr >> 16) & 0xff], 663 ri->ri_font->fontwidth * ncols); 664 to0 += sc->sc_stride; 665 to1 += sc->sc_stride; 666 } 667 } 668 669 static void 670 wcfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 671 { 672 struct rasops_info *ri = cookie; 673 struct vcons_screen *scr = ri->ri_hw; 674 struct wcfb_softc *sc = scr->scr_cookie; 675 int offset = (ri->ri_yorigin + dstrow * ri->ri_font->fontheight) * 676 sc->sc_stride + ri->ri_xorigin; 677 uint8_t *from, *to0, *to1; 678 int i; 679 680 sc->copyrows(ri, srcrow, dstrow, nrows); 681 682 from = sc->sc_shadow + offset; 683 to0 = sc->sc_fb0 + offset; 684 to1 = sc->sc_fb1 + offset; 685 for (i = 0; i < ri->ri_font->fontheight * nrows; i++) { 686 memcpy(to0, from, ri->ri_emuwidth); 687 memcpy(to1, from, ri->ri_emuwidth); 688 to0 += sc->sc_stride; 689 to1 += sc->sc_stride; 690 from += sc->sc_stride; 691 } 692 } 693 694 static void 695 wcfb_eraserows(void *cookie, int row, int nrows, long fillattr) 696 { 697 struct rasops_info *ri = cookie; 698 struct vcons_screen *scr = ri->ri_hw; 699 struct wcfb_softc *sc = scr->scr_cookie; 700 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 701 sc->sc_stride + ri->ri_xorigin; 702 uint8_t *to0, *to1; 703 int i; 704 705 sc->eraserows(ri, row, nrows, fillattr); 706 707 to0 = sc->sc_fb0 + offset; 708 to1 = sc->sc_fb1 + offset; 709 for (i = 0; i < ri->ri_font->fontheight * nrows; i++) { 710 memset(to0, ri->ri_devcmap[(fillattr >> 16) & 0xff], 711 ri->ri_emuwidth); 712 memset(to1, ri->ri_devcmap[(fillattr >> 16) & 0xff], 713 ri->ri_emuwidth); 714 to0 += sc->sc_stride; 715 to1 += sc->sc_stride; 716 } 717 } 718 719 static void 720 wcfb_bitblt(struct wcfb_softc *sc, int sx, int sy, int dx, int dy, int w, 721 int h, uint32_t rop) 722 { 723 wcfb_rop_wait(sc); 724 wcfb_rop_jfb(sc, sx, sy, dx, dy, w, h, rop, 0x0f); 725 } 726 727 static void 728 wcfb_rectfill(struct wcfb_softc *sc, int x, int y, int w, int h, int bg) 729 { 730 int32_t mask; 731 732 /* clear everything just in case... */ 733 wcfb_rop_wait(sc); 734 wcfb_rop_jfb(sc, x, y, x, y, w, h, WC_ROP_CLEAR, 0xffffffff); 735 736 /* pixels to set... */ 737 mask = 0x0f & bg; 738 if (mask != 0) { 739 wcfb_rop_wait(sc); 740 wcfb_rop_jfb(sc, x, y, x, y, w, h, WC_ROP_SET, mask); 741 } 742 743 } 744 745 void 746 wcfb_rop_common(struct wcfb_softc *sc, bus_addr_t reg, int sx, int sy, 747 int dx, int dy, int w, int h, uint32_t rop, int32_t planemask) 748 { 749 int dir = 0; 750 751 /* 752 * Compute rop direction. This only really matters for 753 * screen-to-screen copies. 754 */ 755 if (sy < dy /* && sy + h > dy */) { 756 sy += h - 1; 757 dy += h; 758 dir |= WC_BLT_DIR_BACKWARDS_Y; 759 } 760 if (sx < dx /* && sx + w > dx */) { 761 sx += w - 1; 762 dx += w; 763 dir |= WC_BLT_DIR_BACKWARDS_X; 764 } 765 766 /* Which one of those below is your magic number for today? */ 767 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x61000001); 768 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); 769 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x6301c080); 770 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x80000000); 771 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, rop); 772 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, planemask); 773 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); 774 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x64000303); 775 /* 776 * This value is a pixel offset within the destination area. It is 777 * probably used to define complex polygon shapes, with the 778 * last pixel in the list being back to (0,0). 779 */ 780 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(0, 0)); 781 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); 782 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x00030000); 783 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x2200010d); 784 785 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x33f01000 | dir); 786 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(dx, dy)); 787 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(w, h)); 788 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(sx, sy)); 789 } 790 791 792 static void 793 wcfb_rop_jfb(struct wcfb_softc *sc, int sx, int sy, int dx, int dy, 794 int w, int h, uint32_t rop, int32_t planemask) 795 { 796 bus_addr_t reg = WC_JFB_ENGINE; 797 uint32_t spr, splr; 798 799 #if 0 800 /* 801 * Pick the current spr and splr values from the communication 802 * area if possible. 803 */ 804 if (sc->sc_comm != NULL) { 805 spr = sc->sc_comm[IFB_SHARED_TERM8_SPR >> 2]; 806 splr = sc->sc_comm[IFB_SHARED_TERM8_SPLR >> 2]; 807 } else 808 #endif 809 { 810 /* supposedly sane defaults */ 811 spr = 0x54ff0303; 812 splr = 0x5c0000ff; 813 } 814 815 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x00400016); 816 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5b000002); 817 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5a000000); 818 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, spr); 819 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, splr); 820 821 wcfb_rop_common(sc, reg, sx, sy, dx, dy, w, h, rop, planemask); 822 823 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5a000001); 824 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5b000001); 825 } 826 827 static int 828 wcfb_rop_wait(struct wcfb_softc *sc) 829 { 830 int i; 831 832 for (i = 1000000; i != 0; i--) { 833 if (bus_space_read_4(sc->sc_regt, sc->sc_regh, 834 WC_STATUS) & WC_STATUS_DONE) 835 break; 836 delay(1); 837 } 838 839 return i; 840 } 841 842 static void 843 wcfb_acc_putchar(void *cookie, int row, int col, u_int c, long attr) 844 { 845 struct rasops_info *ri = cookie; 846 struct vcons_screen *scr = ri->ri_hw; 847 struct wcfb_softc *sc = scr->scr_cookie; 848 struct wsdisplay_font *font = PICK_FONT(ri, c); 849 int x, y, wi, he; 850 uint32_t bg; 851 852 wi = font->fontwidth; 853 he = font->fontheight; 854 x = ri->ri_xorigin + col * wi; 855 y = ri->ri_yorigin + row * he; 856 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 857 if (c == 0x20) { 858 wcfb_rectfill(sc, x, y, wi, he, bg); 859 return; 860 } 861 /* we wait until the blitter is idle... */ 862 wcfb_rop_wait(sc); 863 /* ... draw the character into buffer 0 ... */ 864 sc->putchar(ri, row, col, c, attr); 865 /* ... and then blit it into buffer 1 */ 866 wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_COPY); 867 } 868 869 static void 870 wcfb_acc_cursor(void *cookie, int on, int row, int col) 871 { 872 struct rasops_info *ri = cookie; 873 struct vcons_screen *scr = ri->ri_hw; 874 struct wcfb_softc *sc = scr->scr_cookie; 875 int x, y, wi, he; 876 877 wi = ri->ri_font->fontwidth; 878 he = ri->ri_font->fontheight; 879 880 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 881 x = ri->ri_ccol * wi + ri->ri_xorigin; 882 y = ri->ri_crow * he + ri->ri_yorigin; 883 if (ri->ri_flg & RI_CURSOR) { 884 wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_XOR); 885 ri->ri_flg &= ~RI_CURSOR; 886 } 887 ri->ri_crow = row; 888 ri->ri_ccol = col; 889 if (on) { 890 x = ri->ri_ccol * wi + ri->ri_xorigin; 891 y = ri->ri_crow * he + ri->ri_yorigin; 892 wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_XOR); 893 ri->ri_flg |= RI_CURSOR; 894 } 895 } else { 896 scr->scr_ri.ri_crow = row; 897 scr->scr_ri.ri_ccol = col; 898 scr->scr_ri.ri_flg &= ~RI_CURSOR; 899 } 900 901 } 902 903 static void 904 wcfb_acc_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 905 { 906 struct rasops_info *ri = cookie; 907 struct vcons_screen *scr = ri->ri_hw; 908 struct wcfb_softc *sc = scr->scr_cookie; 909 int32_t xs, xd, y, width, height; 910 911 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 912 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 913 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 914 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 915 width = ri->ri_font->fontwidth * ncols; 916 height = ri->ri_font->fontheight; 917 wcfb_bitblt(sc, xs, y, xd, y, width, height, WC_ROP_COPY); 918 } 919 } 920 921 static void 922 wcfb_acc_erasecols(void *cookie, int row, int startcol, int ncols, 923 long fillattr) 924 { 925 struct rasops_info *ri = cookie; 926 struct vcons_screen *scr = ri->ri_hw; 927 struct wcfb_softc *sc = scr->scr_cookie; 928 int32_t x, y, width, height, fg, bg, ul; 929 930 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 931 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 932 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 933 width = ri->ri_font->fontwidth * ncols; 934 height = ri->ri_font->fontheight; 935 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 936 937 wcfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 938 } 939 } 940 941 static void 942 wcfb_acc_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 943 { 944 struct rasops_info *ri = cookie; 945 struct vcons_screen *scr = ri->ri_hw; 946 struct wcfb_softc *sc = scr->scr_cookie; 947 int32_t x, ys, yd, width, height; 948 949 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 950 x = ri->ri_xorigin; 951 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 952 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 953 width = ri->ri_emuwidth; 954 height = ri->ri_font->fontheight * nrows; 955 wcfb_bitblt(sc, x, ys, x, yd, width, height, WC_ROP_COPY); 956 } 957 } 958 959 static void 960 wcfb_acc_eraserows(void *cookie, int row, int nrows, long fillattr) 961 { 962 struct rasops_info *ri = cookie; 963 struct vcons_screen *scr = ri->ri_hw; 964 struct wcfb_softc *sc = scr->scr_cookie; 965 int32_t x, y, width, height, fg, bg, ul; 966 967 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 968 x = ri->ri_xorigin; 969 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 970 width = ri->ri_emuwidth; 971 height = ri->ri_font->fontheight * nrows; 972 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 973 974 wcfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 975 } 976 } 977