1 /* $NetBSD: gftfb.c,v 1.41 2026/05/19 09:24:10 macallan Exp $ */ 2 3 /* $OpenBSD: sti_pci.c,v 1.7 2009/02/06 22:51:04 miod Exp $ */ 4 5 /* 6 * Copyright (c) 2006, 2007 Miodrag Vallat. 7 ^ 2024 Michael Lorenz 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice, this permission notice, and the disclaimer below 12 * appear in all copies. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23 /* 24 * a native driver for HP Visualize EG PCI graphics cards 25 * STI portions are from Miodrag Vallat's sti_pci.c 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/kmem.h> 31 #include <sys/device.h> 32 #include <sys/mutex.h> 33 34 #include <dev/pci/pcivar.h> 35 #include <dev/pci/pcireg.h> 36 #include <dev/pci/pcidevs.h> 37 #include <dev/pci/pciio.h> 38 39 #include <dev/wscons/wsdisplayvar.h> 40 #include <dev/wscons/wsconsio.h> 41 #include <dev/wsfont/wsfont.h> 42 #include <dev/rasops/rasops.h> 43 #include <dev/wscons/wsdisplay_vconsvar.h> 44 #include <dev/pci/wsdisplay_pci.h> 45 #include <dev/wscons/wsdisplay_glyphcachevar.h> 46 47 #include <dev/ic/stireg.h> 48 #include <dev/ic/stivar.h> 49 #include <dev/ic/nglereg.h> 50 #include <hppa/dev/sti_pci_var.h> 51 #include "opt_gftfb.h" 52 53 #ifdef GFTFB_DEBUG 54 #define DPRINTF(s) printf(s) 55 #else 56 #define DPRINTF(s) /* */ 57 #endif 58 59 int gftfb_match(device_t, cfdata_t, void *); 60 void gftfb_attach(device_t, device_t, void *); 61 62 struct gftfb_softc { 63 device_t sc_dev; 64 pci_chipset_tag_t sc_pc; 65 pcitag_t sc_tag; 66 67 /* stuff we need in order to use the STI ROM */ 68 struct sti_softc sc_base; 69 struct sti_screen sc_scr; 70 bus_space_handle_t sc_romh; 71 72 int sc_width, sc_height; 73 int sc_locked; 74 struct vcons_screen sc_console_screen; 75 struct wsscreen_descr sc_defaultscreen_descr; 76 const struct wsscreen_descr *sc_screens[1]; 77 struct wsscreen_list sc_screenlist; 78 struct vcons_data vd; 79 int sc_mode; 80 void (*sc_putchar)(void *, int, int, u_int, long); 81 u_char sc_cmap_red[256]; 82 u_char sc_cmap_green[256]; 83 u_char sc_cmap_blue[256]; 84 kmutex_t sc_hwlock; 85 uint32_t sc_sba, sc_dba; 86 /* cursor stuff */ 87 int sc_cursor_x, sc_cursor_y; 88 int sc_hot_x, sc_hot_y, sc_enabled; 89 int sc_video_on; 90 glyphcache sc_gc; 91 }; 92 93 CFATTACH_DECL_NEW(gftfb, sizeof(struct gftfb_softc), 94 gftfb_match, gftfb_attach, NULL, NULL); 95 96 void gftfb_enable_rom(struct sti_softc *); 97 void gftfb_disable_rom(struct sti_softc *); 98 99 void gftfb_setup(struct gftfb_softc *); 100 101 #define ngle_bt458_write(memt, memh, r, v) \ 102 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24) 103 104 105 /* XXX these really need to go into their own header */ 106 int sti_pci_is_console(struct pci_attach_args *, bus_addr_t *); 107 int sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t, 108 bus_space_handle_t, bus_addr_t *, u_int); 109 int sti_screen_setup(struct sti_screen *, int); 110 void sti_describe_screen(struct sti_softc *, struct sti_screen *); 111 112 /* wsdisplay stuff */ 113 static int gftfb_ioctl(void *, void *, u_long, void *, int, 114 struct lwp *); 115 static paddr_t gftfb_mmap(void *, void *, off_t, int); 116 static void gftfb_init_screen(void *, struct vcons_screen *, int, long *); 117 118 static int gftfb_putcmap(struct gftfb_softc *, struct wsdisplay_cmap *); 119 static int gftfb_getcmap(struct gftfb_softc *, struct wsdisplay_cmap *); 120 static void gftfb_restore_palette(struct gftfb_softc *); 121 static int gftfb_putpalreg(struct gftfb_softc *, uint8_t, uint8_t, 122 uint8_t, uint8_t); 123 124 static void gftfb_rectfill(struct gftfb_softc *, int, int, int, int, 125 uint32_t); 126 static void gftfb_rectfill_a(void *, int, int, int, int, long); 127 128 static void gftfb_bitblt(void *, int, int, int, int, int, 129 int, int); 130 131 static void gftfb_cursor(void *, int, int, int); 132 static void gftfb_putchar(void *, int, int, u_int, long); 133 static void gftfb_putchar_aa(void *, int, int, u_int, long); 134 static int gftfb_allocattr(void *, int, int, int, long *); 135 static void gftfb_copycols(void *, int, int, int, int); 136 static void gftfb_erasecols(void *, int, int, int, long); 137 static void gftfb_copyrows(void *, int, int, int); 138 static void gftfb_eraserows(void *, int, int, long); 139 140 static void gftfb_move_cursor(struct gftfb_softc *, int, int); 141 static int gftfb_do_cursor(struct gftfb_softc *, struct wsdisplay_cursor *); 142 143 static void gftfb_set_video(struct gftfb_softc *, int); 144 145 struct wsdisplay_accessops gftfb_accessops = { 146 gftfb_ioctl, 147 gftfb_mmap, 148 NULL, /* alloc_screen */ 149 NULL, /* free_screen */ 150 NULL, /* show_screen */ 151 NULL, /* load_font */ 152 NULL, /* pollc */ 153 NULL /* scroll */ 154 }; 155 156 static inline void gftfb_wait_fifo(struct gftfb_softc *, uint32_t); 157 158 int 159 gftfb_match(device_t parent, cfdata_t cf, void *aux) 160 { 161 struct pci_attach_args *paa = aux; 162 163 if (PCI_VENDOR(paa->pa_id) != PCI_VENDOR_HP) 164 return 0; 165 166 if (PCI_PRODUCT(paa->pa_id) == PCI_PRODUCT_HP_VISUALIZE_EG) 167 return 10; /* beat out sti at pci */ 168 169 return 0; 170 } 171 172 static inline uint32_t 173 gftfb_read4(struct gftfb_softc *sc, uint32_t offset) 174 { 175 struct sti_rom *rom = sc->sc_base.sc_rom; 176 bus_space_tag_t memt = rom->memt; 177 bus_space_handle_t memh = rom->regh[2]; 178 return bus_space_read_stream_4(memt, memh, offset); 179 } 180 181 static inline void 182 gftfb_write4(struct gftfb_softc *sc, uint32_t offset, uint32_t val) 183 { 184 struct sti_rom *rom = sc->sc_base.sc_rom; 185 bus_space_tag_t memt = rom->memt; 186 bus_space_handle_t memh = rom->regh[2]; 187 bus_space_write_stream_4(memt, memh, offset, val); 188 } 189 190 static inline uint8_t 191 gftfb_read1(struct gftfb_softc *sc, uint32_t offset) 192 { 193 struct sti_rom *rom = sc->sc_base.sc_rom; 194 bus_space_tag_t memt = rom->memt; 195 bus_space_handle_t memh = rom->regh[2]; 196 return bus_space_read_1(memt, memh, offset); 197 } 198 199 static inline void 200 gftfb_write1(struct gftfb_softc *sc, uint32_t offset, uint8_t val) 201 { 202 struct sti_rom *rom = sc->sc_base.sc_rom; 203 bus_space_tag_t memt = rom->memt; 204 bus_space_handle_t memh = rom->regh[2]; 205 bus_space_write_1(memt, memh, offset, val); 206 } 207 208 static inline void 209 gftfb_wait(struct gftfb_softc *sc) 210 { 211 uint8_t stat; 212 213 do { 214 stat = gftfb_read1(sc, NGLE_BUSY); 215 if (stat == 0) 216 stat = gftfb_read1(sc, NGLE_BUSY); 217 } while (stat != 0); 218 } 219 220 static inline void 221 gftfb_wait_fifo(struct gftfb_softc *sc, uint32_t slots) 222 { 223 uint32_t reg; 224 225 do { 226 reg = gftfb_read4(sc, NGLE_FIFO); 227 } while (reg < slots); 228 } 229 230 static inline void 231 gftfb_sba(struct gftfb_softc *sc, uint32_t mode) 232 { 233 if (sc->sc_sba != mode) { 234 gftfb_wait(sc); 235 gftfb_write4(sc, NGLE_SBA, mode); 236 sc->sc_sba = mode; 237 } 238 } 239 240 static inline void 241 gftfb_dba(struct gftfb_softc *sc, uint32_t mode) 242 { 243 if (sc->sc_dba != mode) { 244 gftfb_wait_fifo(sc, 2); 245 gftfb_write4(sc, NGLE_DBA, mode); 246 sc->sc_dba = mode; 247 } 248 } 249 250 static inline void 251 gftfb_both(struct gftfb_softc *sc, uint32_t mode) 252 { 253 if ((sc->sc_dba != mode) || (sc->sc_sba != mode)) { 254 gftfb_wait(sc); 255 gftfb_write4(sc, NGLE_BAboth, mode); 256 sc->sc_dba = mode; 257 sc->sc_sba = mode; 258 } 259 } 260 261 void 262 gftfb_attach(device_t parent, device_t self, void *aux) 263 { 264 struct gftfb_softc *sc = device_private(self); 265 struct pci_attach_args *paa = aux; 266 struct sti_rom *rom; 267 struct rasops_info *ri; 268 struct wsemuldisplaydev_attach_args aa; 269 bus_size_t romsize; 270 unsigned long defattr = 0; 271 int ret, is_console = 0; 272 273 sc->sc_dev = self; 274 275 sc->sc_pc = paa->pa_pc; 276 sc->sc_tag = paa->pa_tag; 277 sc->sc_base.sc_dev = self; 278 sc->sc_base.sc_enable_rom = gftfb_enable_rom; 279 sc->sc_base.sc_disable_rom = gftfb_disable_rom; 280 281 /* we can *not* be interrupted when doing colour map accesses */ 282 mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH); 283 284 aprint_normal("\n"); 285 286 if (sti_pci_check_rom(&sc->sc_base, paa, &sc->sc_romh, &romsize) != 0) 287 return; 288 289 ret = sti_pci_is_console(paa, sc->sc_base. bases); 290 if (ret != 0) { 291 sc->sc_base.sc_flags |= STI_CONSOLE; 292 is_console = 1; 293 } 294 rom = (struct sti_rom *)kmem_zalloc(sizeof(*rom), KM_SLEEP); 295 rom->rom_softc = &sc->sc_base; 296 ret = sti_rom_setup(rom, paa->pa_iot, paa->pa_memt, sc->sc_romh, 297 sc->sc_base.bases, STI_CODEBASE_MAIN); 298 if (ret != 0) { 299 kmem_free(rom, sizeof(*rom)); 300 return; 301 } 302 303 sc->sc_base.sc_rom = rom; 304 305 sc->sc_scr.scr_rom = sc->sc_base.sc_rom; 306 ret = sti_screen_setup(&sc->sc_scr, STI_FBMODE); 307 308 sc->sc_width = sc->sc_scr.scr_cfg.scr_width; 309 sc->sc_height = sc->sc_scr.scr_cfg.scr_height; 310 311 //bus_space_unmap(paa->pa_memt, sc->sc_romh, romsize); 312 313 aprint_normal_dev(sc->sc_dev, "%s at %dx%d\n", sc->sc_scr.name, 314 sc->sc_width, sc->sc_height); 315 gftfb_setup(sc); 316 317 #ifdef GFTFB_DEBUG 318 sc->sc_height -= 200; 319 #endif 320 321 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 322 "default", 323 0, 0, 324 NULL, 325 8, 16, 326 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 327 WSSCREEN_RESIZE, 328 NULL 329 }; 330 331 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 332 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 333 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 334 sc->sc_locked = 0; 335 336 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 337 &gftfb_accessops); 338 sc->vd.init_screen = gftfb_init_screen; 339 sc->vd.show_screen_cookie = &sc->sc_gc; 340 sc->vd.show_screen_cb = glyphcache_adapt; 341 342 ri = &sc->sc_console_screen.scr_ri; 343 344 sc->sc_gc.gc_bitblt = gftfb_bitblt; 345 sc->sc_gc.gc_blitcookie = sc; 346 sc->sc_gc.gc_rectfill = gftfb_rectfill_a; 347 sc->sc_gc.gc_rop = RopSrc; 348 349 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr); 350 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 351 352 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 353 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 354 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 355 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 356 357 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 358 sc->sc_scr.fbheight - sc->sc_height - 5, 359 sc->sc_scr.fbwidth, 360 ri->ri_font->fontwidth, 361 ri->ri_font->fontheight, 362 defattr); 363 364 gftfb_restore_palette(sc); 365 gftfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 366 ri->ri_devcmap[(defattr >> 16) & 0xff]); 367 368 if (is_console) { 369 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 370 defattr); 371 372 vcons_replay_msgbuf(&sc->sc_console_screen); 373 } 374 375 /* no suspend/resume support yet */ 376 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 377 aprint_error_dev(sc->sc_dev, 378 "couldn't establish power handler\n"); 379 380 aa.console = is_console; 381 aa.scrdata = &sc->sc_screenlist; 382 aa.accessops = &gftfb_accessops; 383 aa.accesscookie = &sc->vd; 384 385 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 386 } 387 388 /* 389 * Enable PCI ROM. 390 */ 391 392 void 393 gftfb_enable_rom(struct sti_softc *sc) 394 { 395 struct gftfb_softc *spc = device_private(sc->sc_dev); 396 uint32_t address; 397 398 if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) { 399 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM); 400 address |= PCI_MAPREG_ROM_ENABLE; 401 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address); 402 } 403 SET(sc->sc_flags, STI_ROM_ENABLED); 404 } 405 406 /* 407 * Disable PCI ROM. 408 */ 409 410 void 411 gftfb_disable_rom(struct sti_softc *sc) 412 { 413 struct gftfb_softc *spc = device_private(sc->sc_dev); 414 uint32_t address; 415 416 if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) { 417 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM); 418 address &= ~PCI_MAPREG_ROM_ENABLE; 419 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address); 420 } 421 CLR(sc->sc_flags, STI_ROM_ENABLED); 422 } 423 424 static inline void 425 gftfb_setup_fb(struct gftfb_softc *sc) 426 { 427 gftfb_both(sc, BA(IndexedDcd, Otc04, Ots08, AddrByte, 0, BINapp0I, 0)); 428 gftfb_write4(sc, NGLE_IBO, 429 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, 1, 0, 0)); 430 gftfb_wait(sc); 431 gftfb_write1(sc, NGLE_CONTROL_FB, 1); 432 } 433 434 void 435 gftfb_setup(struct gftfb_softc *sc) 436 { 437 struct sti_rom *rom = sc->sc_base.sc_rom; 438 bus_space_tag_t memt = rom->memt; 439 bus_space_handle_t memh = rom->regh[2]; 440 int i; 441 442 sc->sc_hot_x = 0; 443 sc->sc_hot_y = 0; 444 sc->sc_enabled = 0; 445 sc->sc_video_on = 1; 446 sc->sc_sba = sc->sc_dba = 0; 447 448 /* set Bt458 read mask register to all planes */ 449 gftfb_wait(sc); 450 ngle_bt458_write(memt, memh, 0x08, 0x04); 451 ngle_bt458_write(memt, memh, 0x0a, 0xff); 452 453 gftfb_setup_fb(sc); 454 455 /* attr. planes */ 456 gftfb_wait(sc); 457 gftfb_dba(sc, 458 BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINattr, 0)); 459 gftfb_write4(sc, NGLE_IBO, 460 IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, 0, 1, 0)); 461 gftfb_write4(sc, NGLE_CPR, NGLE_ARTIST_CMAP0); 462 gftfb_write4(sc, NGLE_TRANSFER_DATA, 0xffffffff); 463 464 gftfb_wait(sc); 465 gftfb_write4(sc, NGLE_DST_XY, 0x00000000); 466 gftfb_write4(sc, NGLE_RECT_SIZE_START, 467 (sc->sc_scr.scr_cfg.scr_width << 16) | sc->sc_scr.scr_cfg.scr_height); 468 /* 469 * blit into offscreen memory to force flush previous - apparently 470 * some chips have a bug this works around 471 */ 472 gftfb_write4(sc, NGLE_DST_XY, 0x05000000); 473 gftfb_write4(sc, NGLE_RECT_SIZE_START, 0x00040001); 474 475 gftfb_wait(sc); 476 gftfb_write4(sc, NGLE_CPR, 0x00000000); 477 478 gftfb_setup_fb(sc); 479 480 /* make sure video output is enabled */ 481 gftfb_wait(sc); 482 gftfb_write4(sc, NGLE_EG_MISCVID, 483 gftfb_read4(sc, NGLE_EG_MISCVID) | MISCVID_VIDEO_ON); 484 gftfb_write4(sc, NGLE_EG_MISCCTL, 485 gftfb_read4(sc, NGLE_EG_MISCCTL) | MISCCTL_VIDEO_ON); 486 487 /* initialize cursor sprite */ 488 gftfb_wait(sc); 489 490 /* cursor mask */ 491 gftfb_wait(sc); 492 gftfb_write4(sc, NGLE_IBO, 0x300); 493 gftfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 494 gftfb_dba(sc, BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcmask, 0)); 495 gftfb_write4(sc, NGLE_BINC_DST, 0); 496 for (i = 0; i < 64; i++) { 497 gftfb_write4(sc, NGLE_BINC_DATA_R, 0xffffffff); 498 gftfb_write4(sc, NGLE_BINC_DATA_DL, 0xffffffff); 499 } 500 501 /* cursor image */ 502 gftfb_wait(sc); 503 gftfb_write4(sc, NGLE_IBO, 0x300); 504 gftfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 505 gftfb_dba(sc, BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcursor, 0)); 506 gftfb_write4(sc, NGLE_BINC_DST, 0); 507 for (i = 0; i < 64; i++) { 508 gftfb_write4(sc, NGLE_BINC_DATA_R, 0xff00ff00); 509 gftfb_write4(sc, NGLE_BINC_DATA_DL, 0xff00ff00); 510 } 511 512 /* colour map */ 513 gftfb_both(sc, BA(FractDcd, Otc24, Ots08, Addr24, 0, BINcmap, 0)); 514 gftfb_write4(sc, NGLE_IBO, 515 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0)); 516 gftfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 517 gftfb_wait(sc); 518 gftfb_write4(sc, NGLE_BINC_DST, 0); 519 gftfb_write4(sc, NGLE_BINC_DATA_R, 0); 520 gftfb_write4(sc, NGLE_BINC_DATA_R, 0); 521 gftfb_write4(sc, NGLE_BINC_DATA_R, 0x000000ff); /* BG */ 522 gftfb_write4(sc, NGLE_BINC_DATA_R, 0x00ff0000); /* FG */ 523 gftfb_wait(sc); 524 gftfb_write4(sc, NGLE_BINC_SRC, 0); 525 gftfb_write4(sc, NGLE_EG_LUTBLT, 0x80008004); 526 gftfb_setup_fb(sc); 527 528 gftfb_move_cursor(sc, 100, 100); 529 530 } 531 532 static int 533 gftfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 534 struct lwp *l) 535 { 536 struct vcons_data *vd = v; 537 struct gftfb_softc *sc = vd->cookie; 538 struct wsdisplay_fbinfo *wdf; 539 struct vcons_screen *ms = vd->active; 540 541 switch (cmd) { 542 case WSDISPLAYIO_GTYPE: 543 *(u_int *)data = WSDISPLAY_TYPE_STI; 544 return 0; 545 546 case GCID: 547 *(u_int *)data = STI_DD_EG; 548 return 0; 549 550 /* PCI config read/write passthrough. */ 551 case PCI_IOC_CFGREAD: 552 case PCI_IOC_CFGWRITE: 553 return pci_devioctl(sc->sc_pc, sc->sc_tag, 554 cmd, data, flag, l); 555 556 case WSDISPLAYIO_GET_BUSID: 557 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 558 sc->sc_tag, data); 559 560 case WSDISPLAYIO_GINFO: 561 if (ms == NULL) 562 return ENODEV; 563 wdf = (void *)data; 564 wdf->height = ms->scr_ri.ri_height; 565 wdf->width = ms->scr_ri.ri_width; 566 wdf->depth = ms->scr_ri.ri_depth; 567 wdf->cmsize = 256; 568 return 0; 569 570 case WSDISPLAYIO_GETCMAP: 571 return gftfb_getcmap(sc, 572 (struct wsdisplay_cmap *)data); 573 574 case WSDISPLAYIO_PUTCMAP: 575 return gftfb_putcmap(sc, 576 (struct wsdisplay_cmap *)data); 577 578 case WSDISPLAYIO_LINEBYTES: 579 *(u_int *)data = 2048; 580 return 0; 581 582 case WSDISPLAYIO_SMODE: { 583 int new_mode = *(int*)data; 584 if (new_mode != sc->sc_mode) { 585 sc->sc_mode = new_mode; 586 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 587 gftfb_setup(sc); 588 gftfb_restore_palette(sc); 589 glyphcache_wipe(&sc->sc_gc); 590 gftfb_rectfill(sc, 0, 0, sc->sc_width, 591 sc->sc_height, ms->scr_ri.ri_devcmap[ 592 (ms->scr_defattr >> 16) & 0xff]); 593 vcons_redraw_screen(ms); 594 gftfb_set_video(sc, 1); 595 } else 596 gftfb_setup_fb(sc); 597 } 598 } 599 return 0; 600 601 case WSDISPLAYIO_GET_FBINFO: 602 { 603 struct wsdisplayio_fbinfo *fbi = data; 604 int ret; 605 606 ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 607 fbi->fbi_fbsize = sc->sc_scr.fbheight * 2048; 608 return ret; 609 } 610 611 case WSDISPLAYIO_GCURPOS: 612 { 613 struct wsdisplay_curpos *cp = (void *)data; 614 615 cp->x = sc->sc_cursor_x; 616 cp->y = sc->sc_cursor_y; 617 } 618 return 0; 619 620 case WSDISPLAYIO_SCURPOS: 621 { 622 struct wsdisplay_curpos *cp = (void *)data; 623 624 gftfb_move_cursor(sc, cp->x, cp->y); 625 } 626 return 0; 627 628 case WSDISPLAYIO_GCURMAX: 629 { 630 struct wsdisplay_curpos *cp = (void *)data; 631 632 cp->x = 64; 633 cp->y = 64; 634 } 635 return 0; 636 637 case WSDISPLAYIO_SCURSOR: 638 { 639 struct wsdisplay_cursor *cursor = (void *)data; 640 641 return gftfb_do_cursor(sc, cursor); 642 } 643 644 case WSDISPLAYIO_SVIDEO: 645 gftfb_set_video(sc, *(int *)data); 646 return 0; 647 case WSDISPLAYIO_GVIDEO: 648 *(u_int *)data = sc->sc_video_on ? 649 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 650 return 0; 651 } 652 return EPASSTHROUGH; 653 } 654 655 static paddr_t 656 gftfb_mmap(void *v, void *vs, off_t offset, int prot) 657 { 658 struct vcons_data *vd = v; 659 struct gftfb_softc *sc = vd->cookie; 660 struct sti_rom *rom = sc->sc_base.sc_rom; 661 paddr_t pa = -1; 662 663 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) 664 return -1; 665 666 if (offset >= 0 && offset < sc->sc_scr.fblen) { 667 /* framebuffer */ 668 pa = bus_space_mmap(rom->memt, sc->sc_scr.fbaddr, offset, 669 prot, BUS_SPACE_MAP_LINEAR); 670 } else if (offset >= 0x80000000 && offset < 0x80400000) { 671 /* blitter registers etc. */ 672 pa = bus_space_mmap(rom->memt, rom->regh[2], 673 offset - 0x80000000, prot, BUS_SPACE_MAP_LINEAR); 674 } 675 676 return pa; 677 } 678 679 static void 680 gftfb_init_screen(void *cookie, struct vcons_screen *scr, 681 int existing, long *defattr) 682 { 683 struct gftfb_softc *sc = cookie; 684 struct rasops_info *ri = &scr->scr_ri; 685 686 ri->ri_depth = 8; 687 ri->ri_width = sc->sc_width; 688 ri->ri_height = sc->sc_height; 689 ri->ri_stride = 2048; 690 ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB | RI_FULLCLEAR | 691 RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 692 693 ri->ri_bits = (void *)sc->sc_scr.fbaddr; 694 rasops_init(ri, 0, 0); 695 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 696 WSSCREEN_RESIZE; 697 scr->scr_flags |= VCONS_LOADFONT; 698 699 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 700 sc->sc_width / ri->ri_font->fontwidth); 701 702 ri->ri_hw = scr; 703 sc->sc_putchar = ri->ri_ops.putchar; 704 ri->ri_ops.copyrows = gftfb_copyrows; 705 ri->ri_ops.copycols = gftfb_copycols; 706 ri->ri_ops.eraserows = gftfb_eraserows; 707 ri->ri_ops.erasecols = gftfb_erasecols; 708 ri->ri_ops.cursor = gftfb_cursor; 709 ri->ri_ops.allocattr = gftfb_allocattr; 710 if (FONT_IS_ALPHA(ri->ri_font)) { 711 ri->ri_ops.putchar = gftfb_putchar_aa; 712 } else 713 ri->ri_ops.putchar = gftfb_putchar; 714 } 715 716 static int 717 gftfb_putcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm) 718 { 719 u_char *r, *g, *b; 720 u_int index = cm->index; 721 u_int count = cm->count; 722 int i, error; 723 u_char rbuf[256], gbuf[256], bbuf[256]; 724 725 if (cm->index >= 256 || cm->count > 256 || 726 (cm->index + cm->count) > 256) 727 return EINVAL; 728 error = copyin(cm->red, &rbuf[index], count); 729 if (error) 730 return error; 731 error = copyin(cm->green, &gbuf[index], count); 732 if (error) 733 return error; 734 error = copyin(cm->blue, &bbuf[index], count); 735 if (error) 736 return error; 737 738 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 739 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 740 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 741 742 r = &sc->sc_cmap_red[index]; 743 g = &sc->sc_cmap_green[index]; 744 b = &sc->sc_cmap_blue[index]; 745 746 for (i = 0; i < count; i++) { 747 gftfb_putpalreg(sc, index, *r, *g, *b); 748 index++; 749 r++, g++, b++; 750 } 751 return 0; 752 } 753 754 static int 755 gftfb_getcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm) 756 { 757 u_int index = cm->index; 758 u_int count = cm->count; 759 int error; 760 761 if (index >= 255 || count > 256 || index + count > 256) 762 return EINVAL; 763 764 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 765 if (error) 766 return error; 767 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 768 if (error) 769 return error; 770 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 771 if (error) 772 return error; 773 774 return 0; 775 } 776 777 static void 778 gftfb_restore_palette(struct gftfb_softc *sc) 779 { 780 uint8_t cmap[768]; 781 int i, j; 782 783 j = 0; 784 rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap)); 785 for (i = 0; i < 256; i++) { 786 sc->sc_cmap_red[i] = cmap[j]; 787 sc->sc_cmap_green[i] = cmap[j + 1]; 788 sc->sc_cmap_blue[i] = cmap[j + 2]; 789 gftfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 790 j += 3; 791 } 792 } 793 794 static int 795 gftfb_putpalreg(struct gftfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 796 uint8_t b) 797 { 798 mutex_enter(&sc->sc_hwlock); 799 gftfb_both(sc, BA(FractDcd, Otc24, Ots08, Addr24, 0, BINcmap, 0)); 800 gftfb_write4(sc, NGLE_IBO, 0x03000300); 801 gftfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 802 803 gftfb_wait(sc); 804 gftfb_write4(sc, NGLE_BINC_DST, 0x400 | (idx << 2)); 805 gftfb_write4(sc, NGLE_BINC_DATA_R, (r << 16) | (g << 8) | b); 806 807 gftfb_write4(sc, NGLE_BINC_SRC, 0x400); 808 gftfb_write4(sc, NGLE_EG_LUTBLT, 0x80000100); 809 gftfb_setup_fb(sc); 810 mutex_exit(&sc->sc_hwlock); 811 return 0; 812 } 813 814 static inline void 815 gftfb_fillmode(struct gftfb_softc *sc) 816 { 817 gftfb_dba(sc, 818 BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0I, 0)); 819 gftfb_wait_fifo(sc, 3); 820 gftfb_write4(sc, NGLE_PLANEMASK, 0xff); 821 gftfb_write4(sc, NGLE_IBO, 822 IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, 0, 0, 0)); 823 } 824 825 static void 826 gftfb_rectfill(struct gftfb_softc *sc, int x, int y, int wi, int he, 827 uint32_t bg) 828 { 829 gftfb_fillmode(sc); 830 831 gftfb_wait_fifo(sc, 4); 832 833 gftfb_write4(sc, NGLE_TRANSFER_DATA, 0xffffffff); 834 gftfb_write4(sc, NGLE_FG, bg); 835 gftfb_write4(sc, NGLE_DST_XY, (x << 16) | y); 836 gftfb_write4(sc, NGLE_RECT_SIZE_START, (wi << 16) | he); 837 838 } 839 840 static void 841 gftfb_rectfill_a(void *cookie, int dstx, int dsty, 842 int width, int height, long attr) 843 { 844 struct gftfb_softc *sc = cookie; 845 846 gftfb_rectfill(sc, dstx, dsty, width, height, 847 sc->vd.active->scr_ri.ri_devcmap[(attr >> 24 & 0xf)]); 848 } 849 850 static void 851 gftfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, 852 int he, int rop) 853 { 854 struct gftfb_softc *sc = cookie; 855 856 gftfb_both(sc, BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINapp0I, 0)); 857 gftfb_wait_fifo(sc, 5); 858 gftfb_write4(sc, NGLE_IBO, 859 IBOvals(rop, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 0, 0)); 860 gftfb_write4(sc, NGLE_PLANEMASK, 0xff); 861 gftfb_write4(sc, NGLE_SRC_XY, (xs << 16) | ys); 862 gftfb_write4(sc, NGLE_SIZE, (wi << 16) | he); 863 gftfb_write4(sc, NGLE_BLT_DST_START, (xd << 16) | yd); 864 } 865 866 static void 867 gftfb_nuke_cursor(struct rasops_info *ri) 868 { 869 struct vcons_screen *scr = ri->ri_hw; 870 struct gftfb_softc *sc = scr->scr_cookie; 871 int wi, he, x, y; 872 873 if (ri->ri_flg & RI_CURSOR) { 874 wi = ri->ri_font->fontwidth; 875 he = ri->ri_font->fontheight; 876 x = ri->ri_ccol * wi + ri->ri_xorigin; 877 y = ri->ri_crow * he + ri->ri_yorigin; 878 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv); 879 ri->ri_flg &= ~RI_CURSOR; 880 } 881 } 882 883 static void 884 gftfb_cursor(void *cookie, int on, int row, int col) 885 { 886 struct rasops_info *ri = cookie; 887 struct vcons_screen *scr = ri->ri_hw; 888 struct gftfb_softc *sc = scr->scr_cookie; 889 int x, y, wi, he; 890 891 wi = ri->ri_font->fontwidth; 892 he = ri->ri_font->fontheight; 893 894 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 895 if (on) { 896 if (ri->ri_flg & RI_CURSOR) { 897 gftfb_nuke_cursor(ri); 898 } 899 x = col * wi + ri->ri_xorigin; 900 y = row * he + ri->ri_yorigin; 901 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv); 902 ri->ri_flg |= RI_CURSOR; 903 } 904 ri->ri_crow = row; 905 ri->ri_ccol = col; 906 } else 907 { 908 ri->ri_crow = row; 909 ri->ri_ccol = col; 910 ri->ri_flg &= ~RI_CURSOR; 911 } 912 913 } 914 915 static void 916 gftfb_putchar(void *cookie, int row, int col, u_int c, long attr) 917 { 918 struct rasops_info *ri = cookie; 919 struct wsdisplay_font *font = PICK_FONT(ri, c); 920 struct vcons_screen *scr = ri->ri_hw; 921 struct gftfb_softc *sc = scr->scr_cookie; 922 void *data; 923 int i, x, y, wi, he; 924 uint32_t bg, fg, mask, cmask; 925 926 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 927 return; 928 929 if (!CHAR_IN_FONT(c, font)) 930 return; 931 932 if (row == ri->ri_crow && col == ri->ri_ccol) { 933 ri->ri_flg &= ~RI_CURSOR; 934 } 935 936 wi = font->fontwidth; 937 he = font->fontheight; 938 939 x = ri->ri_xorigin + col * wi; 940 y = ri->ri_yorigin + row * he; 941 942 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 943 fg = ri->ri_devcmap[(attr >> 24) & 0x0f]; 944 945 /* if we're drawing a space we're done here */ 946 if (c == 0x20) { 947 gftfb_rectfill(sc, x, y, wi, he, bg); 948 if (attr & WSATTR_UNDERLINE) 949 gftfb_rectfill(sc, x, y + he - 2, wi, 1, fg); 950 return; 951 } 952 953 data = WSFONT_GLYPH(c, font); 954 955 /* 956 * rectangle fills are implemented as colour expansion by the hardware, 957 * so we can use the same settings and avoid a bunch of writes to DBA 958 */ 959 gftfb_fillmode(sc); 960 961 gftfb_wait_fifo(sc, 4); 962 963 gftfb_write4(sc, NGLE_FG, fg); 964 gftfb_write4(sc, NGLE_BG, bg); 965 /* pixel address in 32bit since we're in AddrLong mode */ 966 gftfb_write4(sc, NGLE_BINC_DST, (x << 2) | (y << 13)); 967 /* make a mask covering the character width */ 968 cmask = 0xffffffff << (32 - wi); 969 gftfb_write4(sc, NGLE_BINC_MASK, cmask); 970 /* 971 * ...and now we hammer pixel data into BINC, moving down. 972 * Unlike FX, we *can* overrun the pipeline with BINC writes, 973 * especially with colour expansion while scrolling. 974 * HCRX seems to have a 32 entry pipeline, let's assume we won't 975 * encounter fonts taller than that for now... 976 */ 977 if (he > 31) { 978 gftfb_wait(sc); 979 } else 980 gftfb_wait_fifo(sc, he); 981 982 if (attr & WSATTR_HILIT) { 983 if (ri->ri_font->stride == 1) { 984 uint8_t *data8 = data; 985 for (i = 0; i < he; i++) { 986 mask = *data8; 987 mask |= mask >> 1; 988 gftfb_write4(sc, NGLE_BINC_DATA_D, mask << 24); 989 data8++; 990 } 991 } else { 992 uint16_t *data16 = data; 993 for (i = 0; i < he; i++) { 994 mask = *data16; 995 mask |= mask >> 1; 996 gftfb_write4(sc, NGLE_BINC_DATA_D, mask << 16); 997 data16++; 998 } 999 } 1000 } else { 1001 if (ri->ri_font->stride == 1) { 1002 uint8_t *data8 = data; 1003 for (i = 0; i < he; i++) { 1004 mask = *data8; 1005 gftfb_write4(sc, NGLE_BINC_DATA_D, mask << 24); 1006 data8++; 1007 } 1008 } else { 1009 uint16_t *data16 = data; 1010 for (i = 0; i < he; i++) { 1011 mask = *data16; 1012 gftfb_write4(sc, NGLE_BINC_DATA_D, mask << 16); 1013 data16++; 1014 } 1015 } 1016 } 1017 1018 if (attr & WSATTR_UNDERLINE) { 1019 gftfb_wait_fifo(sc, 2); 1020 gftfb_write4(sc, NGLE_BINC_DST, 1021 (x << 2) | ((y + he - 2) << 13)); 1022 gftfb_write4(sc, NGLE_BINC_DATA_D, cmask); 1023 } 1024 } 1025 1026 static void 1027 gftfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1028 { 1029 struct rasops_info *ri = cookie; 1030 struct wsdisplay_font *font = PICK_FONT(ri, c); 1031 struct vcons_screen *scr = ri->ri_hw; 1032 struct gftfb_softc *sc = scr->scr_cookie; 1033 int x, y, wi, he, rv = GC_NOPE; 1034 uint32_t bg; 1035 uint32_t latch = 0, bg8, fg8, pixel, mask; 1036 int i, line, r, g, b, aval; 1037 int r1, g1, b1, r0, g0, b0, fgo, bgo; 1038 uint8_t *data8; 1039 1040 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1041 return; 1042 1043 if (!CHAR_IN_FONT(c, font)) 1044 return; 1045 1046 if (row == ri->ri_crow && col == ri->ri_ccol) { 1047 ri->ri_flg &= ~RI_CURSOR; 1048 } 1049 1050 wi = font->fontwidth; 1051 he = font->fontheight; 1052 1053 x = ri->ri_xorigin + col * wi; 1054 y = ri->ri_yorigin + row * he; 1055 1056 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1057 1058 if (c == 0x20) { 1059 gftfb_rectfill(sc, x, y, wi, he, bg); 1060 if (attr & WSATTR_UNDERLINE) 1061 glyphcache_underline(&sc->sc_gc, x, y, attr); 1062 return; 1063 } 1064 1065 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1066 if (rv == GC_OK) 1067 return; 1068 1069 gftfb_dba(sc, BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINapp0I, 0)); 1070 gftfb_wait_fifo(sc, 6); 1071 gftfb_write4(sc, NGLE_PLANEMASK, 0xff); 1072 gftfb_write4(sc, NGLE_IBO, 1073 IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 0, 0)); 1074 1075 /* 1076 * we need the RGB colours here, so get offsets into rasops_cmap 1077 */ 1078 fgo = ((attr >> 24) & 0xf) * 3; 1079 bgo = ((attr >> 16) & 0xf) * 3; 1080 1081 r0 = rasops_cmap[bgo]; 1082 r1 = rasops_cmap[fgo]; 1083 g0 = rasops_cmap[bgo + 1]; 1084 g1 = rasops_cmap[fgo + 1]; 1085 b0 = rasops_cmap[bgo + 2]; 1086 b1 = rasops_cmap[fgo + 2]; 1087 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 1088 bg8 = R3G3B2(r0, g0, b0); 1089 fg8 = R3G3B2(r1, g1, b1); 1090 1091 /* 1092 * This is for masking off pixels at the end of a line if it's not a 1093 * multiple of 4. Would be nice if we knew where the clipping registers 1094 * live... 1095 */ 1096 mask = 0xf0000000 << (4 - (wi & 3)); 1097 1098 data8 = WSFONT_GLYPH(c, font); 1099 1100 for (line = 0; line < he; line++) { 1101 /* setup BINC write */ 1102 gftfb_wait_fifo(sc, wi / 2); 1103 gftfb_write4(sc, NGLE_BINC_DST, (x << 2) | ((y + line) << 13)); 1104 gftfb_write4(sc, NGLE_BINC_MASK, 0xffffffff); 1105 for (i = 0; i < wi; i++) { 1106 aval = *data8; 1107 if (aval == 0) { 1108 pixel = bg8; 1109 } else if (aval == 255) { 1110 pixel = fg8; 1111 } else { 1112 r = aval * r1 + (255 - aval) * r0; 1113 g = aval * g1 + (255 - aval) * g0; 1114 b = aval * b1 + (255 - aval) * b0; 1115 pixel = ((r & 0xe000) >> 8) | 1116 ((g & 0xe000) >> 11) | 1117 ((b & 0xc000) >> 14); 1118 } 1119 latch = (latch << 8) | pixel; 1120 /* write in 32bit chunks */ 1121 if ((i & 3) == 3) { 1122 gftfb_write4(sc, NGLE_BINC_DATA_R, latch); 1123 latch = 0; 1124 } 1125 data8++; 1126 } 1127 /* if we have pixels left in latch write them out */ 1128 if ((i & 3) != 0) { 1129 latch = latch << ((4 - (i & 3)) << 3); 1130 /* make sure we write only the pixels in the latch */ 1131 gftfb_write4(sc, NGLE_BINC_MASK, mask); 1132 gftfb_write4(sc, NGLE_BINC_DATA_R, latch); 1133 } 1134 } 1135 1136 if (rv == GC_ADD) 1137 glyphcache_add(&sc->sc_gc, c, x, y); 1138 if (attr & WSATTR_UNDERLINE) 1139 glyphcache_underline(&sc->sc_gc, x, y, attr); 1140 } 1141 1142 static int 1143 gftfb_allocattr(void *cookie, int fg0, int bg0, int flg, long *attr) 1144 { 1145 struct rasops_info *ri = cookie; 1146 int fg = fg0, bg = bg0; 1147 1148 if ((flg & WSATTR_BLINK) != 0) 1149 return EINVAL; 1150 1151 if ((flg & WSATTR_REVERSE) != 0) { 1152 fg = bg0; 1153 bg = fg0; 1154 } 1155 1156 if (FONT_IS_ALPHA(ri->ri_font) && ((flg & WSATTR_HILIT) != 0)) { 1157 fg = fg0 < 8 ? fg0 + 8 : fg0; 1158 } 1159 1160 *attr = (bg << 16) | (fg << 24) | flg; 1161 return 0; 1162 } 1163 1164 static void 1165 gftfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1166 { 1167 struct rasops_info *ri = cookie; 1168 struct vcons_screen *scr = ri->ri_hw; 1169 struct gftfb_softc *sc = scr->scr_cookie; 1170 int32_t xs, xd, y, width, height; 1171 1172 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1173 if (ri->ri_crow == row && 1174 (ri->ri_ccol >= srccol && ri->ri_ccol < (srccol + ncols)) && 1175 (ri->ri_flg & RI_CURSOR)) { 1176 gftfb_nuke_cursor(ri); 1177 } 1178 1179 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1180 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1181 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1182 width = ri->ri_font->fontwidth * ncols; 1183 height = ri->ri_font->fontheight; 1184 gftfb_bitblt(sc, xs, y, xd, y, width, height, RopSrc); 1185 if (ri->ri_crow == row && 1186 (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols))) 1187 ri->ri_flg &= ~RI_CURSOR; 1188 } 1189 } 1190 1191 static void 1192 gftfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1193 { 1194 struct rasops_info *ri = cookie; 1195 struct vcons_screen *scr = ri->ri_hw; 1196 struct gftfb_softc *sc = scr->scr_cookie; 1197 int32_t x, y, width, height, fg, bg, ul; 1198 1199 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1200 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1201 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1202 width = ri->ri_font->fontwidth * ncols; 1203 height = ri->ri_font->fontheight; 1204 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1205 1206 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1207 if (ri->ri_crow == row && 1208 (ri->ri_ccol >= startcol && ri->ri_ccol < (startcol + ncols))) 1209 ri->ri_flg &= ~RI_CURSOR; 1210 } 1211 } 1212 1213 static void 1214 gftfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1215 { 1216 struct rasops_info *ri = cookie; 1217 struct vcons_screen *scr = ri->ri_hw; 1218 struct gftfb_softc *sc = scr->scr_cookie; 1219 int32_t x, ys, yd, width, height; 1220 1221 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1222 if ((ri->ri_crow >= srcrow && ri->ri_crow < (srcrow + nrows)) && 1223 (ri->ri_flg & RI_CURSOR)) { 1224 gftfb_nuke_cursor(ri); 1225 } 1226 x = ri->ri_xorigin; 1227 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1228 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1229 width = ri->ri_emuwidth; 1230 height = ri->ri_font->fontheight * nrows; 1231 gftfb_bitblt(sc, x, ys, x, yd, width, height, RopSrc); 1232 if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows)) 1233 ri->ri_flg &= ~RI_CURSOR; 1234 } 1235 } 1236 1237 static void 1238 gftfb_eraserows(void *cookie, int row, int nrows, long fillattr) 1239 { 1240 struct rasops_info *ri = cookie; 1241 struct vcons_screen *scr = ri->ri_hw; 1242 struct gftfb_softc *sc = scr->scr_cookie; 1243 int32_t x, y, width, height, fg, bg, ul; 1244 1245 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1246 if (row == 0 && nrows == ri->ri_rows) { 1247 x = 0; 1248 y = 0; 1249 width = sc->sc_width; 1250 height = sc->sc_height; 1251 } else { 1252 x = ri->ri_xorigin; 1253 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1254 width = ri->ri_emuwidth; 1255 height = ri->ri_font->fontheight * nrows; 1256 } 1257 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1258 1259 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1260 1261 if (ri->ri_crow >= row && ri->ri_crow < (row + nrows)) 1262 ri->ri_flg &= ~RI_CURSOR; 1263 } 1264 } 1265 1266 /* 1267 * cursor sprite handling 1268 * like most hw info, xf86 3.3 -> nglehdw.h was used as documentation 1269 * problem is, the PCI EG doesn't quite behave like an S9000_ID_ARTIST 1270 * the cursor position register behaves like the one on HCRX while using 1271 * the same address as Artist, including the enable bit and weird handling 1272 * of negative coordinates. The rest of it, colour map, sprite image etc., 1273 * behave like Artist. 1274 */ 1275 1276 static void 1277 gftfb_move_cursor(struct gftfb_softc *sc, int x, int y) 1278 { 1279 uint32_t pos; 1280 1281 sc->sc_cursor_x = x; 1282 x -= sc->sc_hot_x; 1283 sc->sc_cursor_y = y; 1284 y -= sc->sc_hot_y; 1285 1286 if (x < 0) x = 0x1000 - x; 1287 if (y < 0) y = 0x1000 - y; 1288 pos = (x << 16) | y; 1289 if (sc->sc_enabled) pos |= 0x80000000; 1290 gftfb_wait_fifo(sc, 2); 1291 gftfb_write4(sc, NGLE_EG_CURSOR, pos); 1292 } 1293 1294 static int 1295 gftfb_do_cursor(struct gftfb_softc *sc, struct wsdisplay_cursor *cur) 1296 { 1297 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 1298 1299 sc->sc_enabled = cur->enable; 1300 cur->which |= WSDISPLAY_CURSOR_DOPOS; 1301 } 1302 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 1303 1304 sc->sc_hot_x = cur->hot.x; 1305 sc->sc_hot_y = cur->hot.y; 1306 cur->which |= WSDISPLAY_CURSOR_DOPOS; 1307 } 1308 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 1309 1310 gftfb_move_cursor(sc, cur->pos.x, cur->pos.y); 1311 } 1312 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 1313 uint32_t rgb; 1314 uint8_t r[2], g[2], b[2]; 1315 1316 copyin(cur->cmap.blue, b, 2); 1317 copyin(cur->cmap.green, g, 2); 1318 copyin(cur->cmap.red, r, 2); 1319 mutex_enter(&sc->sc_hwlock); 1320 gftfb_both(sc, 1321 BA(FractDcd, Otc24, Ots08, Addr24, 0, BINcmap, 0)); 1322 gftfb_write4(sc, NGLE_IBO, 1323 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 1324 0, 0)); 1325 gftfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 1326 gftfb_wait(sc); 1327 gftfb_write4(sc, NGLE_BINC_DST, 0); 1328 gftfb_write4(sc, NGLE_BINC_DATA_R, 0); 1329 gftfb_write4(sc, NGLE_BINC_DATA_R, 0); 1330 rgb = (r[0] << 16) | (g[0] << 8) | b[0]; 1331 gftfb_write4(sc, NGLE_BINC_DATA_R, rgb); /* BG */ 1332 rgb = (r[1] << 16) | (g[1] << 8) | b[1]; 1333 gftfb_write4(sc, NGLE_BINC_DATA_R, rgb); /* FG */ 1334 gftfb_write4(sc, NGLE_BINC_SRC, 0); 1335 gftfb_write4(sc, NGLE_EG_LUTBLT, 0x80008004); 1336 gftfb_setup_fb(sc); 1337 mutex_exit(&sc->sc_hwlock); 1338 1339 } 1340 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 1341 uint32_t buffer[128], latch, tmp; 1342 int i; 1343 1344 copyin(cur->mask, buffer, 512); 1345 gftfb_wait(sc); 1346 gftfb_write4(sc, NGLE_IBO, 0x300); 1347 gftfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 1348 gftfb_dba(sc, 1349 BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcmask, 0)); 1350 gftfb_write4(sc, NGLE_BINC_DST, 0); 1351 for (i = 0; i < 128; i += 2) { 1352 latch = 0; 1353 tmp = buffer[i] & 0x80808080; 1354 latch |= tmp >> 7; 1355 tmp = buffer[i] & 0x40404040; 1356 latch |= tmp >> 5; 1357 tmp = buffer[i] & 0x20202020; 1358 latch |= tmp >> 3; 1359 tmp = buffer[i] & 0x10101010; 1360 latch |= tmp >> 1; 1361 tmp = buffer[i] & 0x08080808; 1362 latch |= tmp << 1; 1363 tmp = buffer[i] & 0x04040404; 1364 latch |= tmp << 3; 1365 tmp = buffer[i] & 0x02020202; 1366 latch |= tmp << 5; 1367 tmp = buffer[i] & 0x01010101; 1368 latch |= tmp << 7; 1369 gftfb_write4(sc, NGLE_BINC_DATA_R, latch); 1370 latch = 0; 1371 tmp = buffer[i + 1] & 0x80808080; 1372 latch |= tmp >> 7; 1373 tmp = buffer[i + 1] & 0x40404040; 1374 latch |= tmp >> 5; 1375 tmp = buffer[i + 1] & 0x20202020; 1376 latch |= tmp >> 3; 1377 tmp = buffer[i + 1] & 0x10101010; 1378 latch |= tmp >> 1; 1379 tmp = buffer[i + 1] & 0x08080808; 1380 latch |= tmp << 1; 1381 tmp = buffer[i + 1] & 0x04040404; 1382 latch |= tmp << 3; 1383 tmp = buffer[i + 1] & 0x02020202; 1384 latch |= tmp << 5; 1385 tmp = buffer[i + 1] & 0x01010101; 1386 latch |= tmp << 7; 1387 gftfb_write4(sc, NGLE_BINC_DATA_DL, latch); 1388 } 1389 1390 copyin(cur->image, buffer, 512); 1391 gftfb_wait(sc); 1392 gftfb_write4(sc, NGLE_IBO, 0x300); 1393 gftfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 1394 gftfb_dba(sc, 1395 BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcursor, 0)); 1396 gftfb_write4(sc, NGLE_BINC_DST, 0); 1397 for (i = 0; i < 128; i += 2) { 1398 latch = 0; 1399 tmp = buffer[i] & 0x80808080; 1400 latch |= tmp >> 7; 1401 tmp = buffer[i] & 0x40404040; 1402 latch |= tmp >> 5; 1403 tmp = buffer[i] & 0x20202020; 1404 latch |= tmp >> 3; 1405 tmp = buffer[i] & 0x10101010; 1406 latch |= tmp >> 1; 1407 tmp = buffer[i] & 0x08080808; 1408 latch |= tmp << 1; 1409 tmp = buffer[i] & 0x04040404; 1410 latch |= tmp << 3; 1411 tmp = buffer[i] & 0x02020202; 1412 latch |= tmp << 5; 1413 tmp = buffer[i] & 0x01010101; 1414 latch |= tmp << 7; 1415 gftfb_write4(sc, NGLE_BINC_DATA_R, latch); 1416 latch = 0; 1417 tmp = buffer[i + 1] & 0x80808080; 1418 latch |= tmp >> 7; 1419 tmp = buffer[i + 1] & 0x40404040; 1420 latch |= tmp >> 5; 1421 tmp = buffer[i + 1] & 0x20202020; 1422 latch |= tmp >> 3; 1423 tmp = buffer[i + 1] & 0x10101010; 1424 latch |= tmp >> 1; 1425 tmp = buffer[i + 1] & 0x08080808; 1426 latch |= tmp << 1; 1427 tmp = buffer[i + 1] & 0x04040404; 1428 latch |= tmp << 3; 1429 tmp = buffer[i + 1] & 0x02020202; 1430 latch |= tmp << 5; 1431 tmp = buffer[i + 1] & 0x01010101; 1432 latch |= tmp << 7; 1433 gftfb_write4(sc, NGLE_BINC_DATA_DL, latch); 1434 } 1435 gftfb_setup_fb(sc); 1436 } 1437 1438 return 0; 1439 } 1440 1441 static void 1442 gftfb_set_video(struct gftfb_softc *sc, int on) 1443 { 1444 if (sc->sc_video_on == on) 1445 return; 1446 1447 sc->sc_video_on = on; 1448 1449 gftfb_wait(sc); 1450 if (on) { 1451 gftfb_write4(sc, NGLE_EG_MISCVID, 1452 gftfb_read4(sc, NGLE_EG_MISCVID) | MISCVID_VIDEO_ON); 1453 gftfb_write4(sc, NGLE_EG_MISCCTL, 1454 gftfb_read4(sc, NGLE_EG_MISCCTL) | MISCCTL_VIDEO_ON); 1455 } else { 1456 gftfb_write4(sc, NGLE_EG_MISCVID, 1457 gftfb_read4(sc, NGLE_EG_MISCVID) & ~MISCVID_VIDEO_ON); 1458 gftfb_write4(sc, NGLE_EG_MISCCTL, 1459 gftfb_read4(sc, NGLE_EG_MISCCTL) & ~MISCCTL_VIDEO_ON); 1460 } 1461 } 1462