wcfb.c revision 1.15
1215976Sjmallett/* $NetBSD: wcfb.c,v 1.15 2017/03/24 00:51:43 macallan Exp $ */ 2232812Sjmallett 3215976Sjmallett/* 4215976Sjmallett * Copyright (c) 2007, 2008, 2009 Miodrag Vallat. 5215976Sjmallett * 2010 Michael Lorenz 6215976Sjmallett * 7215976Sjmallett * Permission to use, copy, modify, and distribute this software for any 8215976Sjmallett * purpose with or without fee is hereby granted, provided that the above 9215976Sjmallett * copyright notice and this permission notice appear in all copies. 10215976Sjmallett * 11215976Sjmallett * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12215976Sjmallett * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13215976Sjmallett * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14215976Sjmallett * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15215976Sjmallett * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16215976Sjmallett * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17215976Sjmallett * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18232812Sjmallett */ 19215976Sjmallett 20215976Sjmallett/* a driver for (some) 3DLabs Wildcat cards, based on OpenBSD's ifb driver */ 21215976Sjmallett 22215976Sjmallett#include <sys/cdefs.h> 23215976Sjmallett__KERNEL_RCSID(0, "$NetBSD: wcfb.c,v 1.15 2017/03/24 00:51:43 macallan Exp $"); 24215976Sjmallett 25215976Sjmallett#include <sys/param.h> 26215976Sjmallett#include <sys/systm.h> 27215976Sjmallett#include <sys/kernel.h> 28215976Sjmallett#include <sys/device.h> 29232812Sjmallett#include <sys/proc.h> 30215976Sjmallett#include <sys/mutex.h> 31215976Sjmallett#include <sys/ioctl.h> 32215976Sjmallett#include <sys/kernel.h> 33215976Sjmallett#include <sys/systm.h> 34215976Sjmallett#include <sys/kauth.h> 35215976Sjmallett#include <sys/kmem.h> 36215976Sjmallett 37215976Sjmallett#include <dev/pci/pcidevs.h> 38215976Sjmallett#include <dev/pci/pcireg.h> 39215976Sjmallett#include <dev/pci/pcivar.h> 40215976Sjmallett#include <dev/pci/pciio.h> 41215976Sjmallett#include <dev/pci/wcfbreg.h> 42215976Sjmallett 43215976Sjmallett#include <dev/wscons/wsdisplayvar.h> 44215976Sjmallett#include <dev/wscons/wsconsio.h> 45215976Sjmallett#include <dev/wsfont/wsfont.h> 46215976Sjmallett#include <dev/rasops/rasops.h> 47215976Sjmallett#include <dev/wscons/wsdisplay_vconsvar.h> 48215976Sjmallett#include <dev/pci/wsdisplay_pci.h> 49215976Sjmallett 50215976Sjmallett#include "opt_wsfb.h" 51215976Sjmallett#include "opt_wsdisplay_compat.h" 52215976Sjmallett 53215976Sjmallett#ifdef WCFB_DEBUG 54215976Sjmallett# define DPRINTF printf 55215976Sjmallett#else 56215976Sjmallett# define DPRINTF while (0) printf 57215976Sjmallett#endif 58215976Sjmallett 59215976Sjmallettstatic int wcfb_match(device_t, cfdata_t, void *); 60215976Sjmallettstatic void wcfb_attach(device_t, device_t, void *); 61215976Sjmallettstatic int wcfb_ioctl(void *, void *, u_long, void *, int, 62215976Sjmallett struct lwp *); 63215976Sjmallettstatic paddr_t wcfb_mmap(void *, void *, off_t, int); 64215976Sjmallett 65215976Sjmallettstruct wcfb_softc { 66215976Sjmallett device_t sc_dev; 67215976Sjmallett 68215976Sjmallett pci_chipset_tag_t sc_pc; 69215976Sjmallett pcitag_t sc_pcitag; 70215976Sjmallett 71215976Sjmallett bus_space_tag_t sc_memt; 72215976Sjmallett bus_space_tag_t sc_regt, sc_wtft; 73215976Sjmallett bus_space_tag_t sc_iot; 74215976Sjmallett 75215976Sjmallett bus_space_handle_t sc_fbh; 76215976Sjmallett bus_space_handle_t sc_regh; 77215976Sjmallett bus_addr_t sc_fb, sc_reg; 78215976Sjmallett bus_size_t sc_fbsize, sc_regsize; 79215976Sjmallett 80215976Sjmallett int sc_width, sc_height, sc_stride; 81215976Sjmallett int sc_locked; 82215976Sjmallett uint8_t *sc_fbaddr, *sc_fb0, *sc_fb1, *sc_shadow; 83215976Sjmallett struct vcons_screen sc_console_screen; 84215976Sjmallett struct wsscreen_descr sc_defaultscreen_descr; 85215976Sjmallett const struct wsscreen_descr *sc_screens[1]; 86215976Sjmallett struct wsscreen_list sc_screenlist; 87215976Sjmallett struct vcons_data vd; 88215976Sjmallett int sc_mode; 89215976Sjmallett u_char sc_cmap_red[256]; 90215976Sjmallett u_char sc_cmap_green[256]; 91215976Sjmallett u_char sc_cmap_blue[256]; 92215976Sjmallett uint32_t sc_fb0off, sc_fb1off, sc_fb8size; 93215976Sjmallett 94215976Sjmallett void (*copycols)(void *, int, int, int, int); 95215976Sjmallett void (*erasecols)(void *, int, int, int, long); 96215976Sjmallett void (*copyrows)(void *, int, int, int); 97215976Sjmallett void (*eraserows)(void *, int, int, long); 98215976Sjmallett void (*putchar)(void *, int, int, u_int, long); 99215976Sjmallett void (*cursor)(void *, int, int, int); 100215976Sjmallett int sc_is_jfb; 101215976Sjmallett}; 102215976Sjmallett 103215976Sjmallettstatic void wcfb_init_screen(void *, struct vcons_screen *, int, long *); 104215976Sjmallett 105215976SjmallettCFATTACH_DECL_NEW(wcfb, sizeof(struct wcfb_softc), 106215976Sjmallett wcfb_match, wcfb_attach, NULL, NULL); 107215976Sjmallett 108215976Sjmallettstruct wsdisplay_accessops wcfb_accessops = { 109215976Sjmallett wcfb_ioctl, 110215976Sjmallett wcfb_mmap, 111215976Sjmallett NULL, /* alloc_screen */ 112215976Sjmallett NULL, /* free_screen */ 113215976Sjmallett NULL, /* show_screen */ 114215976Sjmallett NULL, /* load_font */ 115215976Sjmallett NULL, /* pollc */ 116215976Sjmallett NULL /* scroll */ 117215976Sjmallett}; 118215976Sjmallett 119215976Sjmallettstatic void wcfb_putchar(void *, int, int, u_int, long); 120215976Sjmallettstatic void wcfb_cursor(void *, int, int, int); 121215976Sjmallettstatic void wcfb_copycols(void *, int, int, int, int); 122215976Sjmallettstatic void wcfb_erasecols(void *, int, int, int, long); 123215976Sjmallettstatic void wcfb_copyrows(void *, int, int, int); 124215976Sjmallettstatic void wcfb_eraserows(void *, int, int, long); 125215976Sjmallett 126215976Sjmallettstatic void wcfb_acc_putchar(void *, int, int, u_int, long); 127215976Sjmallettstatic void wcfb_acc_cursor(void *, int, int, int); 128215976Sjmallettstatic void wcfb_acc_copycols(void *, int, int, int, int); 129215976Sjmallettstatic void wcfb_acc_erasecols(void *, int, int, int, long); 130215976Sjmallettstatic void wcfb_acc_copyrows(void *, int, int, int); 131215976Sjmallettstatic void wcfb_acc_eraserows(void *, int, int, long); 132215976Sjmallett 133215976Sjmallettstatic void wcfb_putpalreg(struct wcfb_softc *, int, int, int, int); 134215976Sjmallett 135215976Sjmallettstatic void wcfb_bitblt(struct wcfb_softc *, int, int, int, int, int, 136215976Sjmallett int, uint32_t); 137215976Sjmallettstatic void wcfb_rectfill(struct wcfb_softc *, int, int, int, int, int); 138215976Sjmallettstatic void wcfb_rop_common(struct wcfb_softc *, bus_addr_t, int, int, int, 139215976Sjmallett int, int, int, uint32_t, int32_t); 140215976Sjmallettstatic void wcfb_rop_jfb(struct wcfb_softc *, int, int, int, int, int, int, 141215976Sjmallett uint32_t, int32_t); 142215976Sjmallettstatic int wcfb_rop_wait(struct wcfb_softc *); 143215976Sjmallett 144215976Sjmallettstatic int 145215976Sjmallettwcfb_match(device_t parent, cfdata_t match, void *aux) 146215976Sjmallett{ 147215976Sjmallett struct pci_attach_args *pa = aux; 148215976Sjmallett 149215976Sjmallett if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3DLABS && 150215976Sjmallett PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_WILDCAT5110) 151215976Sjmallett return 100; 152215976Sjmallett 153215976Sjmallett return 0; 154215976Sjmallett} 155215976Sjmallett 156215976Sjmallettstatic void 157215976Sjmallettwcfb_attach(device_t parent, device_t self, void *aux) 158215976Sjmallett{ 159215976Sjmallett struct wcfb_softc *sc = device_private(self); 160215976Sjmallett struct pci_attach_args *pa = aux; 161215976Sjmallett struct rasops_info *ri; 162215976Sjmallett prop_dictionary_t dict; 163215976Sjmallett struct wsemuldisplaydev_attach_args aa; 164215976Sjmallett int i, j; 165215976Sjmallett uint32_t reg; 166215976Sjmallett unsigned long defattr; 167215976Sjmallett bool is_console = 0; 168215976Sjmallett uint32_t sub; 169215976Sjmallett 170215976Sjmallett sc->sc_dev = self; 171215976Sjmallett sc->putchar = NULL; 172215976Sjmallett pci_aprint_devinfo(pa, NULL); 173215976Sjmallett 174215976Sjmallett dict = device_properties(self); 175215976Sjmallett prop_dictionary_get_bool(dict, "is_console", &is_console); 176#ifndef WCFB_DEBUG 177 if (!is_console) return; 178#endif 179 sc->sc_memt = pa->pa_memt; 180 sc->sc_iot = pa->pa_iot; 181 sc->sc_pc = pa->pa_pc; 182 sc->sc_pcitag = pa->pa_tag; 183 184 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, 185 &sc->sc_regt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { 186 aprint_error("%s: failed to map registers.\n", 187 device_xname(sc->sc_dev)); 188 } 189 190 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 191 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, 192 &sc->sc_memt, &sc->sc_fbh, &sc->sc_fb, &sc->sc_fbsize)) { 193 aprint_error("%s: failed to map framebuffer.\n", 194 device_xname(sc->sc_dev)); 195 } 196 197 sc->sc_fbaddr = bus_space_vaddr(sc->sc_memt, sc->sc_fbh); 198#ifdef DEBUG 199 memset(sc->sc_fbaddr, 0, sc->sc_fbsize); 200#endif 201 sc->sc_fb0off = 202 bus_space_read_4(sc->sc_regt, sc->sc_regh, 203 WC_FB8_ADDR0) - sc->sc_fb; 204 sc->sc_fb0 = sc->sc_fbaddr + sc->sc_fb0off; 205 sc->sc_fb1off = 206 bus_space_read_4(sc->sc_regt, sc->sc_regh, 207 WC_FB8_ADDR1) - sc->sc_fb; 208 sc->sc_fb1 = sc->sc_fbaddr + sc->sc_fb1off; 209 sc->sc_fb8size = 2 * (sc->sc_fb1off - sc->sc_fb0off); 210printf("fb %08x %08x %08x\n", sc->sc_fb0off, sc->sc_fb1off, sc->sc_fb8size); 211 212 sub = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PCI_SUBSYS_ID_REG); 213 aprint_normal("subsys: %08x\n", sub); 214 switch (sub) { 215 case WC_XVR1200: 216 sc->sc_is_jfb = 1; 217 break; 218 default: 219 sc->sc_is_jfb = 0; 220 } 221 222 reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_RESOLUTION); 223 sc->sc_height = (reg >> 16) + 1; 224#ifdef WCFB_DEBUG 225 sc->sc_height -= 200; 226#endif 227 sc->sc_width = (reg & 0xffff) + 1; 228 sc->sc_stride = 1 << 229 ((bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_CONFIG) & 230 0x00ff0000) >> 16); 231 aprint_normal_dev(self, "%d x %d, %d\n", 232 sc->sc_width, sc->sc_height, sc->sc_stride); 233 234 if (sc->sc_is_jfb == 0) { 235 sc->sc_shadow = kmem_alloc(sc->sc_stride * sc->sc_height, 236 KM_SLEEP); 237 if (sc->sc_shadow == NULL) { 238 aprint_error_dev(self, 239 "failed to allocate shadow buffer\n"); 240 return; 241 } 242 } 243 244 for (i = 0x40; i < 0x100; i += 16) { 245 aprint_normal("%04x:", i); 246 for (j = 0; j < 16; j += 4) { 247 aprint_normal(" %08x", bus_space_read_4(sc->sc_regt, 248 sc->sc_regh, 0x8000 + i + j)); 249 } 250 aprint_normal("\n"); 251 } 252 253 /* make sure video output is on */ 254 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_DPMS_STATE, WC_DPMS_ON); 255 256#if 0 257 /* testing & debugging voodoo */ 258 memset(sc->sc_fb0, 0x01, 0x00100000); 259 memset(sc->sc_fb1, 0x00, 0x00100000); 260 wcfb_rop_wait(sc); 261 wcfb_rop_jfb(sc, 0, 0, 0, 0, 600, 600, WC_ROP_SET, 0xffffffff); 262 wcfb_rop_wait(sc); 263 delay(4000000); 264 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_FB8_ADDR1, 265 bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_FB8_ADDR0)); 266 delay(8000000); 267#endif 268 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 269 "default", 270 0, 0, 271 NULL, 272 8, 16, 273 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 274 NULL 275 }; 276 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 277 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 278 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 279 sc->sc_locked = 0; 280 281 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 282 &wcfb_accessops); 283 sc->vd.init_screen = wcfb_init_screen; 284 285 /* init engine here */ 286#if 0 287 wcfb_init(sc); 288#endif 289 290 ri = &sc->sc_console_screen.scr_ri; 291 292 j = 0; 293 for (i = 0; i < 256; i++) { 294 295 sc->sc_cmap_red[i] = rasops_cmap[j]; 296 sc->sc_cmap_green[i] = rasops_cmap[j + 1]; 297 sc->sc_cmap_blue[i] = rasops_cmap[j + 2]; 298 wcfb_putpalreg(sc, i, rasops_cmap[j], rasops_cmap[j + 1], 299 rasops_cmap[j + 2]); 300 j += 3; 301 } 302 303 if (is_console) { 304 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 305 &defattr); 306 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 307 308 if (sc->sc_is_jfb) { 309 wcfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 310 ri->ri_devcmap[(defattr >> 16) & 0xff]); 311 } else { 312 memset(sc->sc_fb0, 313 ri->ri_devcmap[(defattr >> 16) & 0xff], 314 sc->sc_stride * sc->sc_height); 315 memset(sc->sc_fb1, 316 ri->ri_devcmap[(defattr >> 16) & 0xff], 317 sc->sc_stride * sc->sc_height); 318 } 319 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 320 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 321 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 322 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 323 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 324 defattr); 325 vcons_replay_msgbuf(&sc->sc_console_screen); 326 } else { 327 /* 328 * since we're not the console we can postpone the rest 329 * until someone actually allocates a screen for us 330 */ 331 memset(sc->sc_fb0, WS_DEFAULT_BG, 332 sc->sc_stride * sc->sc_height); 333 memset(sc->sc_fb1, WS_DEFAULT_BG, 334 sc->sc_stride * sc->sc_height); 335 return; 336 } 337 338 aa.console = is_console; 339 aa.scrdata = &sc->sc_screenlist; 340 aa.accessops = &wcfb_accessops; 341 aa.accesscookie = &sc->vd; 342 343 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint); 344} 345 346static int 347wcfb_putcmap(struct wcfb_softc *sc, struct wsdisplay_cmap *cm) 348{ 349 u_char *r, *g, *b; 350 u_int index = cm->index; 351 u_int count = cm->count; 352 int i, error; 353 u_char rbuf[256], gbuf[256], bbuf[256]; 354 355 if (cm->index >= 256 || cm->count > 256 || 356 (cm->index + cm->count) > 256) 357 return EINVAL; 358 error = copyin(cm->red, &rbuf[index], count); 359 if (error) 360 return error; 361 error = copyin(cm->green, &gbuf[index], count); 362 if (error) 363 return error; 364 error = copyin(cm->blue, &bbuf[index], count); 365 if (error) 366 return error; 367 368 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 369 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 370 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 371 372 r = &sc->sc_cmap_red[index]; 373 g = &sc->sc_cmap_green[index]; 374 b = &sc->sc_cmap_blue[index]; 375 376 for (i = 0; i < count; i++) { 377 wcfb_putpalreg(sc, index, *r, *g, *b); 378 index++; 379 r++, g++, b++; 380 } 381 return 0; 382} 383 384static int 385wcfb_getcmap(struct wcfb_softc *sc, struct wsdisplay_cmap *cm) 386{ 387 u_int index = cm->index; 388 u_int count = cm->count; 389 int error; 390 391 if (index >= 255 || count > 256 || index + count > 256) 392 return EINVAL; 393 394 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 395 if (error) 396 return error; 397 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 398 if (error) 399 return error; 400 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 401 if (error) 402 return error; 403 404 return 0; 405} 406 407static int 408wcfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 409 struct lwp *l) 410{ 411 struct vcons_data *vd = v; 412 struct wcfb_softc *sc = vd->cookie; 413 414 switch (cmd) { 415 case WSDISPLAYIO_GTYPE: 416 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 417 return 0; 418 419 /* PCI config read/write passthrough. */ 420 case PCI_IOC_CFGREAD: 421 case PCI_IOC_CFGWRITE: 422 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 423 cmd, data, flag, l); 424 425 case WSDISPLAYIO_GET_BUSID: 426 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 427 sc->sc_pcitag, data); 428 429 case WSDISPLAYIO_SMODE: { 430 /*int new_mode = *(int*)data, i;*/ 431 } 432 return 0; 433 434 case WSDISPLAYIO_GETCMAP: 435 return wcfb_getcmap(sc, 436 (struct wsdisplay_cmap *)data); 437 438 case WSDISPLAYIO_PUTCMAP: 439 return wcfb_putcmap(sc, 440 (struct wsdisplay_cmap *)data); 441 442 case WSDISPLAYIO_GET_FBINFO: { 443 struct wsdisplayio_fbinfo *fbi = data; 444 445 fbi->fbi_fbsize = sc->sc_fb8size; 446 fbi->fbi_fboffset = 0; 447 fbi->fbi_width = sc->sc_width; 448 fbi->fbi_height = sc->sc_height; 449 fbi->fbi_bitsperpixel = 8; 450 fbi->fbi_stride = sc->sc_stride; 451 fbi->fbi_pixeltype = WSFB_CI; 452 fbi->fbi_subtype.fbi_cmapinfo.cmap_entries = 256; 453 fbi->fbi_flags = WSFB_VRAM_IS_SPLIT; 454 return 0; 455 } 456 } 457 return EPASSTHROUGH; 458} 459 460static paddr_t 461wcfb_mmap(void *v, void *vs, off_t offset, int prot) 462{ 463 struct vcons_data *vd = v; 464 struct wcfb_softc *sc = vd->cookie; 465 466 /* XXX in theory the order is not fixed... */ 467 468 if (offset < sc->sc_fb8size) 469 return bus_space_mmap(sc->sc_memt, sc->sc_fb + sc->sc_fb0off, 470 offset, prot, 471 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 472 /* 473 * restrict all other mappings to processes with superuser privileges 474 * or the kernel itself 475 */ 476 if (kauth_authorize_machdep(kauth_cred_get(), 477 KAUTH_MACHDEP_UNMANAGEDMEM, 478 NULL, NULL, NULL, NULL) != 0) { 479 aprint_normal_dev(sc->sc_dev, "mmap() rejected.\n"); 480 return -1; 481 } 482 483 /* may want to mmap() registers at some point */ 484 485 return -1; 486} 487 488static void 489wcfb_init_screen(void *cookie, struct vcons_screen *scr, 490 int existing, long *defattr) 491{ 492 struct wcfb_softc *sc = cookie; 493 struct rasops_info *ri = &scr->scr_ri; 494 495 ri->ri_depth = 8; 496 ri->ri_width = sc->sc_width; 497 ri->ri_height = sc->sc_height; 498 ri->ri_stride = sc->sc_stride; 499 ri->ri_flg = RI_CENTER /*| RI_FULLCLEAR*/; 500 501 if (sc->sc_is_jfb) { 502 ri->ri_bits = sc->sc_fb0; 503 } else { 504 ri->ri_bits = sc->sc_shadow; 505 } 506 if (existing) { 507 ri->ri_flg |= RI_CLEAR; 508 } 509 510 rasops_init(ri, 0, 0); 511 ri->ri_caps = WSSCREEN_WSCOLORS; 512 513 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 514 sc->sc_width / ri->ri_font->fontwidth); 515 516 ri->ri_hw = scr; 517 sc->putchar = ri->ri_ops.putchar; 518 sc->copyrows = ri->ri_ops.copyrows; 519 sc->eraserows = ri->ri_ops.eraserows; 520 sc->copycols = ri->ri_ops.copycols; 521 sc->erasecols = ri->ri_ops.erasecols; 522 523 if (sc->sc_is_jfb) { 524 ri->ri_ops.copyrows = wcfb_acc_copyrows; 525 ri->ri_ops.copycols = wcfb_acc_copycols; 526 ri->ri_ops.eraserows = wcfb_acc_eraserows; 527 ri->ri_ops.erasecols = wcfb_acc_erasecols; 528 ri->ri_ops.putchar = wcfb_acc_putchar; 529 ri->ri_ops.cursor = wcfb_acc_cursor; 530 } else { 531 ri->ri_ops.copyrows = wcfb_copyrows; 532 ri->ri_ops.copycols = wcfb_copycols; 533 ri->ri_ops.eraserows = wcfb_eraserows; 534 ri->ri_ops.erasecols = wcfb_erasecols; 535 ri->ri_ops.putchar = wcfb_putchar; 536 ri->ri_ops.cursor = wcfb_cursor; 537 } 538} 539 540static void 541wcfb_putchar(void *cookie, int row, int col, u_int c, long attr) 542{ 543 struct rasops_info *ri = cookie; 544 struct vcons_screen *scr = ri->ri_hw; 545 struct wcfb_softc *sc = scr->scr_cookie; 546 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 547 sc->sc_stride + ri->ri_xorigin + col * ri->ri_font->fontwidth; 548 uint8_t *from, *to0, *to1; 549 int i; 550 551 sc->putchar(ri, row, col, c, attr); 552 from = sc->sc_shadow + offset; 553 to0 = sc->sc_fb0 + offset; 554 to1 = sc->sc_fb1 + offset; 555 for (i = 0; i < ri->ri_font->fontheight; i++) { 556 memcpy(to0, from, ri->ri_font->fontwidth); 557 memcpy(to1, from, ri->ri_font->fontwidth); 558 to0 += sc->sc_stride; 559 to1 += sc->sc_stride; 560 from += sc->sc_stride; 561 } 562} 563 564static void 565wcfb_putpalreg(struct wcfb_softc *sc, int i, int r, int g, int b) 566{ 567 uint32_t rgb; 568 569 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_CMAP_INDEX, i); 570 rgb = (b << 22) | (g << 12) | (r << 2); 571 bus_space_write_4(sc->sc_regt, sc->sc_regh, WC_CMAP_DATA, rgb); 572} 573 574static void 575wcfb_cursor(void *cookie, int on, int row, int col) 576{ 577 struct rasops_info *ri = cookie; 578 struct vcons_screen *scr = ri->ri_hw; 579 struct wcfb_softc *sc = scr->scr_cookie; 580 int coffset; 581 582 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 583 584 if (ri->ri_flg & RI_CURSOR) { 585 /* remove cursor */ 586 coffset = ri->ri_ccol + (ri->ri_crow * ri->ri_cols); 587#ifdef WSDISPLAY_SCROLLSUPPORT 588 coffset += scr->scr_offset_to_zero; 589#endif 590 wcfb_putchar(cookie, ri->ri_crow, 591 ri->ri_ccol, scr->scr_chars[coffset], 592 scr->scr_attrs[coffset]); 593 ri->ri_flg &= ~RI_CURSOR; 594 } 595 ri->ri_crow = row; 596 ri->ri_ccol = col; 597 if (on) { 598 long attr, revattr; 599 coffset = col + (row * ri->ri_cols); 600#ifdef WSDISPLAY_SCROLLSUPPORT 601 coffset += scr->scr_offset_to_zero; 602#endif 603 attr = scr->scr_attrs[coffset]; 604 revattr = attr ^ 0xffff0000; 605 606 wcfb_putchar(cookie, ri->ri_crow, ri->ri_ccol, 607 scr->scr_chars[coffset], revattr); 608 ri->ri_flg |= RI_CURSOR; 609 } 610 } else { 611 ri->ri_crow = row; 612 ri->ri_ccol = col; 613 ri->ri_flg &= ~RI_CURSOR; 614 } 615} 616 617static void 618wcfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 619{ 620 struct rasops_info *ri = cookie; 621 struct vcons_screen *scr = ri->ri_hw; 622 struct wcfb_softc *sc = scr->scr_cookie; 623 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 624 sc->sc_stride + ri->ri_xorigin + dstcol * ri->ri_font->fontwidth; 625 uint8_t *from, *to0, *to1; 626 int i; 627 628 sc->copycols(ri, row, srccol, dstcol, ncols); 629 from = sc->sc_shadow + offset; 630 to0 = sc->sc_fb0 + offset; 631 to1 = sc->sc_fb1 + offset; 632 for (i = 0; i < ri->ri_font->fontheight; i++) { 633 memcpy(to0, from, ri->ri_font->fontwidth * ncols); 634 memcpy(to1, from, ri->ri_font->fontwidth * ncols); 635 to0 += sc->sc_stride; 636 to1 += sc->sc_stride; 637 from += sc->sc_stride; 638 } 639} 640 641static void 642wcfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 643{ 644 struct rasops_info *ri = cookie; 645 struct vcons_screen *scr = ri->ri_hw; 646 struct wcfb_softc *sc = scr->scr_cookie; 647 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 648 sc->sc_stride + ri->ri_xorigin + startcol * ri->ri_font->fontwidth; 649 uint8_t *to0, *to1; 650 int i; 651 652 sc->erasecols(ri, row, startcol, ncols, fillattr); 653 654 to0 = sc->sc_fb0 + offset; 655 to1 = sc->sc_fb1 + offset; 656 for (i = 0; i < ri->ri_font->fontheight; i++) { 657 memset(to0, ri->ri_devcmap[(fillattr >> 16) & 0xff], 658 ri->ri_font->fontwidth * ncols); 659 memset(to1, ri->ri_devcmap[(fillattr >> 16) & 0xff], 660 ri->ri_font->fontwidth * ncols); 661 to0 += sc->sc_stride; 662 to1 += sc->sc_stride; 663 } 664} 665 666static void 667wcfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 668{ 669 struct rasops_info *ri = cookie; 670 struct vcons_screen *scr = ri->ri_hw; 671 struct wcfb_softc *sc = scr->scr_cookie; 672 int offset = (ri->ri_yorigin + dstrow * ri->ri_font->fontheight) * 673 sc->sc_stride + ri->ri_xorigin; 674 uint8_t *from, *to0, *to1; 675 int i; 676 677 sc->copyrows(ri, srcrow, dstrow, nrows); 678 679 from = sc->sc_shadow + offset; 680 to0 = sc->sc_fb0 + offset; 681 to1 = sc->sc_fb1 + offset; 682 for (i = 0; i < ri->ri_font->fontheight * nrows; i++) { 683 memcpy(to0, from, ri->ri_emuwidth); 684 memcpy(to1, from, ri->ri_emuwidth); 685 to0 += sc->sc_stride; 686 to1 += sc->sc_stride; 687 from += sc->sc_stride; 688 } 689} 690 691static void 692wcfb_eraserows(void *cookie, int row, int nrows, long fillattr) 693{ 694 struct rasops_info *ri = cookie; 695 struct vcons_screen *scr = ri->ri_hw; 696 struct wcfb_softc *sc = scr->scr_cookie; 697 int offset = (ri->ri_yorigin + row * ri->ri_font->fontheight) * 698 sc->sc_stride + ri->ri_xorigin; 699 uint8_t *to0, *to1; 700 int i; 701 702 sc->eraserows(ri, row, nrows, fillattr); 703 704 to0 = sc->sc_fb0 + offset; 705 to1 = sc->sc_fb1 + offset; 706 for (i = 0; i < ri->ri_font->fontheight * nrows; i++) { 707 memset(to0, ri->ri_devcmap[(fillattr >> 16) & 0xff], 708 ri->ri_emuwidth); 709 memset(to1, ri->ri_devcmap[(fillattr >> 16) & 0xff], 710 ri->ri_emuwidth); 711 to0 += sc->sc_stride; 712 to1 += sc->sc_stride; 713 } 714} 715 716static void 717wcfb_bitblt(struct wcfb_softc *sc, int sx, int sy, int dx, int dy, int w, 718 int h, uint32_t rop) 719{ 720 wcfb_rop_wait(sc); 721 wcfb_rop_jfb(sc, sx, sy, dx, dy, w, h, rop, 0x0f); 722} 723 724static void 725wcfb_rectfill(struct wcfb_softc *sc, int x, int y, int w, int h, int bg) 726{ 727 int32_t mask; 728 729 /* clear everything just in case... */ 730 wcfb_rop_wait(sc); 731 wcfb_rop_jfb(sc, x, y, x, y, w, h, WC_ROP_CLEAR, 0xffffffff); 732 733 /* pixels to set... */ 734 mask = 0x0f & bg; 735 if (mask != 0) { 736 wcfb_rop_wait(sc); 737 wcfb_rop_jfb(sc, x, y, x, y, w, h, WC_ROP_SET, mask); 738 } 739 740} 741 742void 743wcfb_rop_common(struct wcfb_softc *sc, bus_addr_t reg, int sx, int sy, 744 int dx, int dy, int w, int h, uint32_t rop, int32_t planemask) 745{ 746 int dir = 0; 747 748 /* 749 * Compute rop direction. This only really matters for 750 * screen-to-screen copies. 751 */ 752 if (sy < dy /* && sy + h > dy */) { 753 sy += h - 1; 754 dy += h; 755 dir |= WC_BLT_DIR_BACKWARDS_Y; 756 } 757 if (sx < dx /* && sx + w > dx */) { 758 sx += w - 1; 759 dx += w; 760 dir |= WC_BLT_DIR_BACKWARDS_X; 761 } 762 763 /* Which one of those below is your magic number for today? */ 764 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x61000001); 765 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); 766 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x6301c080); 767 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x80000000); 768 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, rop); 769 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, planemask); 770 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); 771 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x64000303); 772 /* 773 * This value is a pixel offset within the destination area. It is 774 * probably used to define complex polygon shapes, with the 775 * last pixel in the list being back to (0,0). 776 */ 777 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(0, 0)); 778 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); 779 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x00030000); 780 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x2200010d); 781 782 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x33f01000 | dir); 783 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(dx, dy)); 784 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(w, h)); 785 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(sx, sy)); 786} 787 788 789static void 790wcfb_rop_jfb(struct wcfb_softc *sc, int sx, int sy, int dx, int dy, 791 int w, int h, uint32_t rop, int32_t planemask) 792{ 793 bus_addr_t reg = WC_JFB_ENGINE; 794 uint32_t spr, splr; 795 796#if 0 797 /* 798 * Pick the current spr and splr values from the communication 799 * area if possible. 800 */ 801 if (sc->sc_comm != NULL) { 802 spr = sc->sc_comm[IFB_SHARED_TERM8_SPR >> 2]; 803 splr = sc->sc_comm[IFB_SHARED_TERM8_SPLR >> 2]; 804 } else 805#endif 806 { 807 /* supposedly sane defaults */ 808 spr = 0x54ff0303; 809 splr = 0x5c0000ff; 810 } 811 812 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x00400016); 813 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5b000002); 814 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5a000000); 815 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, spr); 816 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, splr); 817 818 wcfb_rop_common(sc, reg, sx, sy, dx, dy, w, h, rop, planemask); 819 820 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5a000001); 821 bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5b000001); 822} 823 824static int 825wcfb_rop_wait(struct wcfb_softc *sc) 826{ 827 int i; 828 829 for (i = 1000000; i != 0; i--) { 830 if (bus_space_read_4(sc->sc_regt, sc->sc_regh, 831 WC_STATUS) & WC_STATUS_DONE) 832 break; 833 delay(1); 834 } 835 836 return i; 837} 838 839static void 840wcfb_acc_putchar(void *cookie, int row, int col, u_int c, long attr) 841{ 842 struct rasops_info *ri = cookie; 843 struct vcons_screen *scr = ri->ri_hw; 844 struct wcfb_softc *sc = scr->scr_cookie; 845 struct wsdisplay_font *font = PICK_FONT(ri, c); 846 int x, y, wi, he; 847 uint32_t bg; 848 849 wi = font->fontwidth; 850 he = font->fontheight; 851 x = ri->ri_xorigin + col * wi; 852 y = ri->ri_yorigin + row * he; 853 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 854 if (c == 0x20) { 855 wcfb_rectfill(sc, x, y, wi, he, bg); 856 return; 857 } 858 /* we wait until the blitter is idle... */ 859 wcfb_rop_wait(sc); 860 /* ... draw the character into buffer 0 ... */ 861 sc->putchar(ri, row, col, c, attr); 862 /* ... and then blit it into buffer 1 */ 863 wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_COPY); 864} 865 866static void 867wcfb_acc_cursor(void *cookie, int on, int row, int col) 868{ 869 struct rasops_info *ri = cookie; 870 struct vcons_screen *scr = ri->ri_hw; 871 struct wcfb_softc *sc = scr->scr_cookie; 872 int x, y, wi, he; 873 874 wi = ri->ri_font->fontwidth; 875 he = ri->ri_font->fontheight; 876 877 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 878 x = ri->ri_ccol * wi + ri->ri_xorigin; 879 y = ri->ri_crow * he + ri->ri_yorigin; 880 if (ri->ri_flg & RI_CURSOR) { 881 wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_XOR); 882 ri->ri_flg &= ~RI_CURSOR; 883 } 884 ri->ri_crow = row; 885 ri->ri_ccol = col; 886 if (on) { 887 x = ri->ri_ccol * wi + ri->ri_xorigin; 888 y = ri->ri_crow * he + ri->ri_yorigin; 889 wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_XOR); 890 ri->ri_flg |= RI_CURSOR; 891 } 892 } else { 893 scr->scr_ri.ri_crow = row; 894 scr->scr_ri.ri_ccol = col; 895 scr->scr_ri.ri_flg &= ~RI_CURSOR; 896 } 897 898} 899 900static void 901wcfb_acc_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 902{ 903 struct rasops_info *ri = cookie; 904 struct vcons_screen *scr = ri->ri_hw; 905 struct wcfb_softc *sc = scr->scr_cookie; 906 int32_t xs, xd, y, width, height; 907 908 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 909 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 910 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 911 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 912 width = ri->ri_font->fontwidth * ncols; 913 height = ri->ri_font->fontheight; 914 wcfb_bitblt(sc, xs, y, xd, y, width, height, WC_ROP_COPY); 915 } 916} 917 918static void 919wcfb_acc_erasecols(void *cookie, int row, int startcol, int ncols, 920 long fillattr) 921{ 922 struct rasops_info *ri = cookie; 923 struct vcons_screen *scr = ri->ri_hw; 924 struct wcfb_softc *sc = scr->scr_cookie; 925 int32_t x, y, width, height, fg, bg, ul; 926 927 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 928 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 929 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 930 width = ri->ri_font->fontwidth * ncols; 931 height = ri->ri_font->fontheight; 932 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 933 934 wcfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 935 } 936} 937 938static void 939wcfb_acc_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 940{ 941 struct rasops_info *ri = cookie; 942 struct vcons_screen *scr = ri->ri_hw; 943 struct wcfb_softc *sc = scr->scr_cookie; 944 int32_t x, ys, yd, width, height; 945 946 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 947 x = ri->ri_xorigin; 948 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 949 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 950 width = ri->ri_emuwidth; 951 height = ri->ri_font->fontheight * nrows; 952 wcfb_bitblt(sc, x, ys, x, yd, width, height, WC_ROP_COPY); 953 } 954} 955 956static void 957wcfb_acc_eraserows(void *cookie, int row, int nrows, long fillattr) 958{ 959 struct rasops_info *ri = cookie; 960 struct vcons_screen *scr = ri->ri_hw; 961 struct wcfb_softc *sc = scr->scr_cookie; 962 int32_t x, y, width, height, fg, bg, ul; 963 964 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 965 x = ri->ri_xorigin; 966 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 967 width = ri->ri_emuwidth; 968 height = ri->ri_font->fontheight * nrows; 969 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 970 971 wcfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 972 } 973} 974