1 /* $NetBSD: gftfb.c,v 1.27 2024/11/13 08:21:16 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 50 #include "opt_gftfb.h" 51 52 #ifdef GFTFB_DEBUG 53 #define DPRINTF(s) printf(s) 54 #else 55 #define DPRINTF(s) /* */ 56 #endif 57 58 int gftfb_match(device_t, cfdata_t, void *); 59 void gftfb_attach(device_t, device_t, void *); 60 61 struct gftfb_softc { 62 device_t sc_dev; 63 pci_chipset_tag_t sc_pc; 64 pcitag_t sc_tag; 65 66 /* stuff we need in order to use the STI ROM */ 67 struct sti_softc sc_base; 68 struct sti_screen sc_scr; 69 bus_space_handle_t sc_romh; 70 71 int sc_width, sc_height; 72 int sc_locked; 73 struct vcons_screen sc_console_screen; 74 struct wsscreen_descr sc_defaultscreen_descr; 75 const struct wsscreen_descr *sc_screens[1]; 76 struct wsscreen_list sc_screenlist; 77 struct vcons_data vd; 78 int sc_mode; 79 void (*sc_putchar)(void *, int, int, u_int, long); 80 u_char sc_cmap_red[256]; 81 u_char sc_cmap_green[256]; 82 u_char sc_cmap_blue[256]; 83 kmutex_t sc_hwlock; 84 uint32_t sc_hwmode; 85 #define HW_FB 0 86 #define HW_FILL 1 87 #define HW_BLIT 2 88 /* cursor stuff */ 89 int sc_cursor_x, sc_cursor_y; 90 int sc_hot_x, sc_hot_y, sc_enabled; 91 int sc_video_on; 92 glyphcache sc_gc; 93 }; 94 95 CFATTACH_DECL_NEW(gftfb, sizeof(struct gftfb_softc), 96 gftfb_match, gftfb_attach, NULL, NULL); 97 98 int gftfb_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int); 99 int gftfb_check_rom(struct gftfb_softc *, struct pci_attach_args *); 100 void gftfb_enable_rom(struct sti_softc *); 101 void gftfb_disable_rom(struct sti_softc *); 102 void gftfb_enable_rom_internal(struct gftfb_softc *); 103 void gftfb_disable_rom_internal(struct gftfb_softc *); 104 105 void gftfb_setup(struct gftfb_softc *); 106 107 #define ngle_bt458_write(memt, memh, r, v) \ 108 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24) 109 110 111 /* XXX these really need to go into their own header */ 112 int sti_pci_is_console(struct pci_attach_args *, bus_addr_t *); 113 int sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t, 114 bus_space_handle_t, bus_addr_t *, u_int); 115 int sti_screen_setup(struct sti_screen *, int); 116 void sti_describe_screen(struct sti_softc *, struct sti_screen *); 117 118 #define PCI_ROM_SIZE(mr) \ 119 (PCI_MAPREG_ROM_ADDR(mr) & -PCI_MAPREG_ROM_ADDR(mr)) 120 121 /* wsdisplay stuff */ 122 static int gftfb_ioctl(void *, void *, u_long, void *, int, 123 struct lwp *); 124 static paddr_t gftfb_mmap(void *, void *, off_t, int); 125 static void gftfb_init_screen(void *, struct vcons_screen *, int, long *); 126 127 static int gftfb_putcmap(struct gftfb_softc *, struct wsdisplay_cmap *); 128 static int gftfb_getcmap(struct gftfb_softc *, struct wsdisplay_cmap *); 129 static void gftfb_restore_palette(struct gftfb_softc *); 130 static int gftfb_putpalreg(struct gftfb_softc *, uint8_t, uint8_t, 131 uint8_t, uint8_t); 132 133 static void gftfb_rectfill(struct gftfb_softc *, int, int, int, int, 134 uint32_t); 135 static void gftfb_bitblt(void *, int, int, int, int, int, 136 int, int); 137 138 static void gftfb_cursor(void *, int, int, int); 139 static void gftfb_putchar(void *, int, int, u_int, long); 140 static void gftfb_putchar_aa(void *, int, int, u_int, long); 141 static void gftfb_copycols(void *, int, int, int, int); 142 static void gftfb_erasecols(void *, int, int, int, long); 143 static void gftfb_copyrows(void *, int, int, int); 144 static void gftfb_eraserows(void *, int, int, long); 145 146 static void gftfb_move_cursor(struct gftfb_softc *, int, int); 147 static int gftfb_do_cursor(struct gftfb_softc *, struct wsdisplay_cursor *); 148 149 static void gftfb_set_video(struct gftfb_softc *, int); 150 151 struct wsdisplay_accessops gftfb_accessops = { 152 gftfb_ioctl, 153 gftfb_mmap, 154 NULL, /* alloc_screen */ 155 NULL, /* free_screen */ 156 NULL, /* show_screen */ 157 NULL, /* load_font */ 158 NULL, /* pollc */ 159 NULL /* scroll */ 160 }; 161 162 static inline void gftfb_wait_fifo(struct gftfb_softc *, uint32_t); 163 164 int 165 gftfb_match(device_t parent, cfdata_t cf, void *aux) 166 { 167 struct pci_attach_args *paa = aux; 168 169 if (PCI_VENDOR(paa->pa_id) != PCI_VENDOR_HP) 170 return 0; 171 172 if (PCI_PRODUCT(paa->pa_id) == PCI_PRODUCT_HP_VISUALIZE_EG) 173 return 10; /* beat out sti at pci */ 174 175 return 0; 176 } 177 178 static inline uint32_t 179 gftfb_read4(struct gftfb_softc *sc, uint32_t offset) 180 { 181 struct sti_rom *rom = sc->sc_base.sc_rom; 182 bus_space_tag_t memt = rom->memt; 183 bus_space_handle_t memh = rom->regh[2]; 184 return bus_space_read_stream_4(memt, memh, offset); 185 } 186 187 static inline void 188 gftfb_write4(struct gftfb_softc *sc, uint32_t offset, uint32_t val) 189 { 190 struct sti_rom *rom = sc->sc_base.sc_rom; 191 bus_space_tag_t memt = rom->memt; 192 bus_space_handle_t memh = rom->regh[2]; 193 bus_space_write_stream_4(memt, memh, offset, val); 194 } 195 196 static inline uint8_t 197 gftfb_read1(struct gftfb_softc *sc, uint32_t offset) 198 { 199 struct sti_rom *rom = sc->sc_base.sc_rom; 200 bus_space_tag_t memt = rom->memt; 201 bus_space_handle_t memh = rom->regh[2]; 202 return bus_space_read_1(memt, memh, offset); 203 } 204 205 static inline void 206 gftfb_write1(struct gftfb_softc *sc, uint32_t offset, uint8_t val) 207 { 208 struct sti_rom *rom = sc->sc_base.sc_rom; 209 bus_space_tag_t memt = rom->memt; 210 bus_space_handle_t memh = rom->regh[2]; 211 bus_space_write_1(memt, memh, offset, val); 212 } 213 214 void 215 gftfb_attach(device_t parent, device_t self, void *aux) 216 { 217 struct gftfb_softc *sc = device_private(self); 218 struct pci_attach_args *paa = aux; 219 struct sti_rom *rom; 220 struct rasops_info *ri; 221 struct wsemuldisplaydev_attach_args aa; 222 unsigned long defattr = 0; 223 int ret, is_console = 0; 224 225 sc->sc_dev = self; 226 227 sc->sc_pc = paa->pa_pc; 228 sc->sc_tag = paa->pa_tag; 229 sc->sc_base.sc_dev = self; 230 sc->sc_base.sc_enable_rom = gftfb_enable_rom; 231 sc->sc_base.sc_disable_rom = gftfb_disable_rom; 232 233 /* we can *not* be interrupted when doing colour map accesses */ 234 mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH); 235 236 aprint_normal("\n"); 237 238 if (gftfb_check_rom(sc, paa) != 0) 239 return; 240 241 ret = sti_pci_is_console(paa, sc->sc_base. bases); 242 if (ret != 0) { 243 sc->sc_base.sc_flags |= STI_CONSOLE; 244 is_console = 1; 245 } 246 rom = (struct sti_rom *)kmem_zalloc(sizeof(*rom), KM_SLEEP); 247 rom->rom_softc = &sc->sc_base; 248 ret = sti_rom_setup(rom, paa->pa_iot, paa->pa_memt, sc->sc_romh, 249 sc->sc_base.bases, STI_CODEBASE_MAIN); 250 if (ret != 0) { 251 kmem_free(rom, sizeof(*rom)); 252 return; 253 } 254 255 sc->sc_base.sc_rom = rom; 256 257 sc->sc_scr.scr_rom = sc->sc_base.sc_rom; 258 ret = sti_screen_setup(&sc->sc_scr, STI_FBMODE); 259 260 sc->sc_width = sc->sc_scr.scr_cfg.scr_width; 261 sc->sc_height = sc->sc_scr.scr_cfg.scr_height; 262 263 aprint_normal_dev(sc->sc_dev, "%s at %dx%d\n", sc->sc_scr.name, 264 sc->sc_width, sc->sc_height); 265 gftfb_setup(sc); 266 267 #ifdef GFTFB_DEBUG 268 sc->sc_height -= 200; 269 #endif 270 271 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 272 "default", 273 0, 0, 274 NULL, 275 8, 16, 276 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 277 WSSCREEN_RESIZE, 278 NULL 279 }; 280 281 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 282 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 283 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 284 sc->sc_locked = 0; 285 286 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 287 &gftfb_accessops); 288 sc->vd.init_screen = gftfb_init_screen; 289 sc->vd.show_screen_cookie = &sc->sc_gc; 290 sc->vd.show_screen_cb = glyphcache_adapt; 291 292 ri = &sc->sc_console_screen.scr_ri; 293 294 sc->sc_gc.gc_bitblt = gftfb_bitblt; 295 sc->sc_gc.gc_blitcookie = sc; 296 sc->sc_gc.gc_rop = RopSrc; 297 298 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr); 299 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 300 301 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 302 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 303 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 304 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 305 306 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 307 sc->sc_scr.fbheight - sc->sc_height - 5, 308 sc->sc_scr.fbwidth, 309 ri->ri_font->fontwidth, 310 ri->ri_font->fontheight, 311 defattr); 312 313 gftfb_restore_palette(sc); 314 gftfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 315 ri->ri_devcmap[(defattr >> 16) & 0xff]); 316 317 if (is_console) { 318 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 319 defattr); 320 321 vcons_replay_msgbuf(&sc->sc_console_screen); 322 } 323 324 /* no suspend/resume support yet */ 325 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 326 aprint_error_dev(sc->sc_dev, 327 "couldn't establish power handler\n"); 328 329 aa.console = is_console; 330 aa.scrdata = &sc->sc_screenlist; 331 aa.accessops = &gftfb_accessops; 332 aa.accesscookie = &sc->vd; 333 334 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 335 } 336 337 /* 338 * Grovel the STI ROM image. 339 */ 340 int 341 gftfb_check_rom(struct gftfb_softc *spc, struct pci_attach_args *pa) 342 { 343 struct sti_softc *sc = &spc->sc_base; 344 pcireg_t address, mask; 345 bus_space_handle_t romh; 346 bus_size_t romsize, subsize, stiromsize; 347 bus_addr_t selected, offs, suboffs; 348 uint32_t tmp; 349 int i; 350 int rc; 351 352 /* sort of inline sti_pci_enable_rom(sc) */ 353 address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM); 354 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, 355 ~PCI_MAPREG_ROM_ENABLE); 356 mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM); 357 address |= PCI_MAPREG_ROM_ENABLE; 358 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, address); 359 sc->sc_flags |= STI_ROM_ENABLED; 360 /* 361 * Map the complete ROM for now. 362 */ 363 364 romsize = PCI_ROM_SIZE(mask); 365 DPRINTF(("%s: mapping rom @ %lx for %lx\n", __func__, 366 (long)PCI_MAPREG_ROM_ADDR(address), (long)romsize)); 367 368 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address), romsize, 369 0, &romh); 370 if (rc != 0) { 371 aprint_error_dev(sc->sc_dev, "can't map PCI ROM (%d)\n", rc); 372 goto fail2; 373 } 374 375 gftfb_disable_rom_internal(spc); 376 /* 377 * Iterate over the ROM images, pick the best candidate. 378 */ 379 380 selected = (bus_addr_t)-1; 381 for (offs = 0; offs < romsize; offs += subsize) { 382 gftfb_enable_rom_internal(spc); 383 /* 384 * Check for a valid ROM header. 385 */ 386 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0); 387 tmp = le32toh(tmp); 388 if (tmp != 0x55aa0000) { 389 gftfb_disable_rom_internal(spc); 390 if (offs == 0) { 391 aprint_error_dev(sc->sc_dev, 392 "invalid PCI ROM header signature (%08x)\n", 393 tmp); 394 rc = EINVAL; 395 } 396 break; 397 } 398 399 /* 400 * Check ROM type. 401 */ 402 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4); 403 tmp = le32toh(tmp); 404 if (tmp != 0x00000001) { /* 1 == STI ROM */ 405 gftfb_disable_rom_internal(spc); 406 if (offs == 0) { 407 aprint_error_dev(sc->sc_dev, 408 "invalid PCI ROM type (%08x)\n", tmp); 409 rc = EINVAL; 410 } 411 break; 412 } 413 414 subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, 415 offs + 0x0c); 416 subsize <<= 9; 417 418 #ifdef GFTFB_DEBUG 419 gftfb_disable_rom_internal(spc); 420 DPRINTF(("ROM offset %08x size %08x type %08x", 421 (u_int)offs, (u_int)subsize, tmp)); 422 gftfb_enable_rom_internal(spc); 423 #endif 424 425 /* 426 * Check for a valid ROM data structure. 427 * We do not need it except to know what architecture the ROM 428 * code is for. 429 */ 430 431 suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh, 432 offs + 0x18); 433 tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0); 434 tmp = le32toh(tmp); 435 if (tmp != 0x50434952) { /* PCIR */ 436 gftfb_disable_rom_internal(spc); 437 if (offs == 0) { 438 aprint_error_dev(sc->sc_dev, "invalid PCI data" 439 " signature (%08x)\n", tmp); 440 rc = EINVAL; 441 } else { 442 DPRINTF((" invalid PCI data signature %08x\n", 443 tmp)); 444 continue; 445 } 446 } 447 448 tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14); 449 gftfb_disable_rom_internal(spc); 450 DPRINTF((" code %02x", tmp)); 451 452 switch (tmp) { 453 #ifdef __hppa__ 454 case 0x10: 455 if (selected == (bus_addr_t)-1) 456 selected = offs; 457 break; 458 #endif 459 #ifdef __i386__ 460 case 0x00: 461 if (selected == (bus_addr_t)-1) 462 selected = offs; 463 break; 464 #endif 465 default: 466 DPRINTF((" (wrong architecture)")); 467 break; 468 } 469 DPRINTF(("%s\n", selected == offs ? " -> SELECTED" : "")); 470 } 471 472 if (selected == (bus_addr_t)-1) { 473 if (rc == 0) { 474 aprint_error_dev(sc->sc_dev, "found no ROM with " 475 "correct microcode architecture\n"); 476 rc = ENOEXEC; 477 } 478 goto fail; 479 } 480 481 /* 482 * Read the STI region BAR assignments. 483 */ 484 485 gftfb_enable_rom_internal(spc); 486 offs = selected + 487 (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e); 488 for (i = 0; i < STI_REGION_MAX; i++) { 489 rc = gftfb_readbar(sc, pa, i, 490 bus_space_read_1(pa->pa_memt, romh, offs + i)); 491 if (rc != 0) 492 goto fail; 493 } 494 495 /* 496 * Find out where the STI ROM itself lies, and its size. 497 */ 498 499 offs = selected + 500 (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08); 501 stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, 502 offs + 0x18); 503 stiromsize = le32toh(stiromsize); 504 gftfb_disable_rom_internal(spc); 505 506 /* 507 * Replace our mapping with a smaller mapping of only the area 508 * we are interested in. 509 */ 510 511 DPRINTF(("remapping rom @ %lx for %lx\n", 512 (long)(PCI_MAPREG_ROM_ADDR(address) + offs), (long)stiromsize)); 513 bus_space_unmap(pa->pa_memt, romh, romsize); 514 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address) + offs, 515 stiromsize, 0, &spc->sc_romh); 516 if (rc != 0) { 517 aprint_error_dev(sc->sc_dev, "can't map STI ROM (%d)\n", 518 rc); 519 goto fail2; 520 } 521 gftfb_disable_rom_internal(spc); 522 sc->sc_flags &= ~STI_ROM_ENABLED; 523 524 return 0; 525 526 fail: 527 bus_space_unmap(pa->pa_memt, romh, romsize); 528 fail2: 529 gftfb_disable_rom_internal(spc); 530 531 return rc; 532 } 533 534 /* 535 * Decode a BAR register. 536 */ 537 int 538 gftfb_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region, 539 int bar) 540 { 541 bus_addr_t addr; 542 bus_size_t size; 543 uint32_t cf; 544 int rc; 545 546 if (bar == 0) { 547 sc->bases[region] = 0; 548 return (0); 549 } 550 551 #ifdef DIAGNOSTIC 552 if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) { 553 gftfb_disable_rom(sc); 554 printf("%s: unexpected bar %02x for region %d\n", 555 device_xname(sc->sc_dev), bar, region); 556 gftfb_enable_rom(sc); 557 } 558 #endif 559 560 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar); 561 562 rc = pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, PCI_MAPREG_TYPE(cf), 563 &addr, &size, NULL); 564 565 if (rc != 0) { 566 gftfb_disable_rom(sc); 567 aprint_error_dev(sc->sc_dev, "invalid bar %02x for region %d\n", 568 bar, region); 569 gftfb_enable_rom(sc); 570 return (rc); 571 } 572 573 sc->bases[region] = addr; 574 return (0); 575 } 576 577 /* 578 * Enable PCI ROM. 579 */ 580 void 581 gftfb_enable_rom_internal(struct gftfb_softc *spc) 582 { 583 pcireg_t address; 584 585 KASSERT(spc != NULL); 586 587 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM); 588 address |= PCI_MAPREG_ROM_ENABLE; 589 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address); 590 } 591 592 void 593 gftfb_enable_rom(struct sti_softc *sc) 594 { 595 struct gftfb_softc *spc = device_private(sc->sc_dev); 596 597 if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) { 598 gftfb_enable_rom_internal(spc); 599 } 600 SET(sc->sc_flags, STI_ROM_ENABLED); 601 } 602 603 /* 604 * Disable PCI ROM. 605 */ 606 void 607 gftfb_disable_rom_internal(struct gftfb_softc *spc) 608 { 609 pcireg_t address; 610 611 KASSERT(spc != NULL); 612 613 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM); 614 address &= ~PCI_MAPREG_ROM_ENABLE; 615 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address); 616 } 617 618 void 619 gftfb_disable_rom(struct sti_softc *sc) 620 { 621 struct gftfb_softc *spc = device_private(sc->sc_dev); 622 623 if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) { 624 gftfb_disable_rom_internal(spc); 625 } 626 CLR(sc->sc_flags, STI_ROM_ENABLED); 627 } 628 629 static inline void 630 gftfb_wait(struct gftfb_softc *sc) 631 { 632 uint8_t stat; 633 634 do { 635 stat = gftfb_read1(sc, NGLE_REG_15b0); 636 if (stat == 0) 637 stat = gftfb_read1(sc, NGLE_REG_15b0); 638 } while (stat != 0); 639 } 640 641 static inline void 642 gftfb_setup_fb(struct gftfb_softc *sc) 643 { 644 gftfb_wait(sc); 645 gftfb_write4(sc, NGLE_REG_10, 646 BA(IndexedDcd, Otc04, Ots08, AddrByte, 0, BINapp0I, 0)); 647 gftfb_write4(sc, NGLE_REG_14, 0x83000300); 648 gftfb_wait(sc); 649 gftfb_write1(sc, NGLE_REG_16b1, 1); 650 sc->sc_hwmode = HW_FB; 651 } 652 653 void 654 gftfb_setup(struct gftfb_softc *sc) 655 { 656 struct sti_rom *rom = sc->sc_base.sc_rom; 657 bus_space_tag_t memt = rom->memt; 658 bus_space_handle_t memh = rom->regh[2]; 659 int i; 660 661 sc->sc_hwmode = HW_FB; 662 sc->sc_hot_x = 0; 663 sc->sc_hot_y = 0; 664 sc->sc_enabled = 0; 665 sc->sc_video_on = 1; 666 667 668 /* set Bt458 read mask register to all planes */ 669 gftfb_wait(sc); 670 ngle_bt458_write(memt, memh, 0x08, 0x04); 671 ngle_bt458_write(memt, memh, 0x0a, 0xff); 672 673 gftfb_setup_fb(sc); 674 675 /* attr. planes */ 676 gftfb_wait(sc); 677 gftfb_write4(sc, NGLE_REG_11, 0x2ea0d000); 678 gftfb_write4(sc, NGLE_REG_14, 0x23000302); 679 gftfb_write4(sc, NGLE_REG_12, NGLE_ARTIST_CMAP0); 680 gftfb_write4(sc, NGLE_REG_8, 0xffffffff); 681 682 gftfb_wait(sc); 683 gftfb_write4(sc, NGLE_REG_6, 0x00000000); 684 gftfb_write4(sc, NGLE_REG_9, 685 (sc->sc_scr.scr_cfg.scr_width << 16) | sc->sc_scr.scr_cfg.scr_height); 686 /* 687 * blit into offscreen memory to force flush previous - apparently 688 * some chips have a bug this works around 689 */ 690 gftfb_write4(sc, NGLE_REG_6, 0x05000000); 691 gftfb_write4(sc, NGLE_REG_9, 0x00040001); 692 693 gftfb_wait(sc); 694 gftfb_write4(sc, NGLE_REG_12, 0x00000000); 695 696 gftfb_setup_fb(sc); 697 698 /* make sure video output is enabled */ 699 gftfb_wait(sc); 700 gftfb_write4(sc, NGLE_REG_21, 701 gftfb_read4(sc, NGLE_REG_21) | 0x0a000000); 702 gftfb_write4(sc, NGLE_REG_27, 703 gftfb_read4(sc, NGLE_REG_27) | 0x00800000); 704 705 /* initialize cursor sprite */ 706 gftfb_wait(sc); 707 708 /* cursor mask */ 709 gftfb_wait(sc); 710 gftfb_write4(sc, NGLE_REG_14, 0x300); 711 gftfb_write4(sc, NGLE_REG_13, 0xffffffff); 712 gftfb_write4(sc, NGLE_REG_11, 713 BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcmask, 0)); 714 gftfb_write4(sc, NGLE_REG_3, 0); 715 for (i = 0; i < 64; i++) { 716 gftfb_write4(sc, NGLE_REG_4, 0xffffffff); 717 gftfb_write4(sc, NGLE_REG_5, 0xffffffff); 718 } 719 720 /* cursor image */ 721 gftfb_wait(sc); 722 gftfb_write4(sc, NGLE_REG_14, 0x300); 723 gftfb_write4(sc, NGLE_REG_13, 0xffffffff); 724 gftfb_write4(sc, NGLE_REG_11, 725 BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcursor, 0)); 726 gftfb_write4(sc, NGLE_REG_3, 0); 727 for (i = 0; i < 64; i++) { 728 gftfb_write4(sc, NGLE_REG_4, 0xff00ff00); 729 gftfb_write4(sc, NGLE_REG_5, 0xff00ff00); 730 } 731 732 /* colour map */ 733 gftfb_wait(sc); 734 gftfb_write4(sc, NGLE_REG_10, 735 BA(FractDcd, Otc24, Ots08, Addr24, 0, BINcmap, 0)); 736 gftfb_write4(sc, NGLE_REG_14, 0x03000300); 737 gftfb_write4(sc, NGLE_REG_13, 0xffffffff); 738 gftfb_wait(sc); 739 gftfb_write4(sc, NGLE_REG_3, 0); 740 gftfb_write4(sc, NGLE_REG_4, 0); 741 gftfb_write4(sc, NGLE_REG_4, 0); 742 gftfb_write4(sc, NGLE_REG_4, 0x000000ff); /* BG */ 743 gftfb_write4(sc, NGLE_REG_4, 0x00ff0000); /* FG */ 744 gftfb_wait(sc); 745 gftfb_write4(sc, NGLE_REG_2, 0); 746 gftfb_write4(sc, NGLE_REG_26, 0x80008004); 747 gftfb_setup_fb(sc); 748 749 gftfb_move_cursor(sc, 100, 100); 750 751 } 752 753 static int 754 gftfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 755 struct lwp *l) 756 { 757 struct vcons_data *vd = v; 758 struct gftfb_softc *sc = vd->cookie; 759 struct wsdisplay_fbinfo *wdf; 760 struct vcons_screen *ms = vd->active; 761 762 switch (cmd) { 763 case WSDISPLAYIO_GTYPE: 764 *(u_int *)data = WSDISPLAY_TYPE_STI; 765 return 0; 766 767 case GCID: 768 *(u_int *)data = STI_DD_EG; 769 return 0; 770 771 /* PCI config read/write passthrough. */ 772 case PCI_IOC_CFGREAD: 773 case PCI_IOC_CFGWRITE: 774 return pci_devioctl(sc->sc_pc, sc->sc_tag, 775 cmd, data, flag, l); 776 777 case WSDISPLAYIO_GET_BUSID: 778 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 779 sc->sc_tag, data); 780 781 case WSDISPLAYIO_GINFO: 782 if (ms == NULL) 783 return ENODEV; 784 wdf = (void *)data; 785 wdf->height = ms->scr_ri.ri_height; 786 wdf->width = ms->scr_ri.ri_width; 787 wdf->depth = ms->scr_ri.ri_depth; 788 wdf->cmsize = 256; 789 return 0; 790 791 case WSDISPLAYIO_GETCMAP: 792 return gftfb_getcmap(sc, 793 (struct wsdisplay_cmap *)data); 794 795 case WSDISPLAYIO_PUTCMAP: 796 return gftfb_putcmap(sc, 797 (struct wsdisplay_cmap *)data); 798 799 case WSDISPLAYIO_LINEBYTES: 800 *(u_int *)data = 2048; 801 return 0; 802 803 case WSDISPLAYIO_SMODE: { 804 int new_mode = *(int*)data; 805 if (new_mode != sc->sc_mode) { 806 sc->sc_mode = new_mode; 807 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 808 gftfb_setup(sc); 809 gftfb_restore_palette(sc); 810 glyphcache_wipe(&sc->sc_gc); 811 gftfb_rectfill(sc, 0, 0, sc->sc_width, 812 sc->sc_height, ms->scr_ri.ri_devcmap[ 813 (ms->scr_defattr >> 16) & 0xff]); 814 vcons_redraw_screen(ms); 815 gftfb_set_video(sc, 1); 816 } 817 } 818 } 819 return 0; 820 821 case WSDISPLAYIO_GET_FBINFO: 822 { 823 struct wsdisplayio_fbinfo *fbi = data; 824 int ret; 825 826 ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 827 fbi->fbi_fbsize = sc->sc_scr.fbheight * 2048; 828 return ret; 829 } 830 831 case WSDISPLAYIO_GCURPOS: 832 { 833 struct wsdisplay_curpos *cp = (void *)data; 834 835 cp->x = sc->sc_cursor_x; 836 cp->y = sc->sc_cursor_y; 837 } 838 return 0; 839 840 case WSDISPLAYIO_SCURPOS: 841 { 842 struct wsdisplay_curpos *cp = (void *)data; 843 844 gftfb_move_cursor(sc, cp->x, cp->y); 845 } 846 return 0; 847 848 case WSDISPLAYIO_GCURMAX: 849 { 850 struct wsdisplay_curpos *cp = (void *)data; 851 852 cp->x = 64; 853 cp->y = 64; 854 } 855 return 0; 856 857 case WSDISPLAYIO_SCURSOR: 858 { 859 struct wsdisplay_cursor *cursor = (void *)data; 860 861 return gftfb_do_cursor(sc, cursor); 862 } 863 864 case WSDISPLAYIO_SVIDEO: 865 gftfb_set_video(sc, *(int *)data); 866 return 0; 867 case WSDISPLAYIO_GVIDEO: 868 *(u_int *)data = sc->sc_video_on ? 869 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 870 return 0; 871 } 872 return EPASSTHROUGH; 873 } 874 875 static paddr_t 876 gftfb_mmap(void *v, void *vs, off_t offset, int prot) 877 { 878 struct vcons_data *vd = v; 879 struct gftfb_softc *sc = vd->cookie; 880 struct sti_rom *rom = sc->sc_base.sc_rom; 881 paddr_t pa = -1; 882 883 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) 884 return -1; 885 886 if (offset >= 0 && offset < sc->sc_scr.fblen) { 887 /* framebuffer */ 888 pa = bus_space_mmap(rom->memt, sc->sc_scr.fbaddr, offset, 889 prot, BUS_SPACE_MAP_LINEAR); 890 } else if (offset >= 0x80000000 && offset < 0x80400000) { 891 /* blitter registers etc. */ 892 pa = bus_space_mmap(rom->memt, rom->regh[2], 893 offset - 0x80000000, prot, BUS_SPACE_MAP_LINEAR); 894 } 895 896 return pa; 897 } 898 899 static void 900 gftfb_init_screen(void *cookie, struct vcons_screen *scr, 901 int existing, long *defattr) 902 { 903 struct gftfb_softc *sc = cookie; 904 struct rasops_info *ri = &scr->scr_ri; 905 906 ri->ri_depth = 8; 907 ri->ri_width = sc->sc_width; 908 ri->ri_height = sc->sc_height; 909 ri->ri_stride = 2048; 910 ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB | 911 RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 912 913 ri->ri_bits = (void *)sc->sc_scr.fbaddr; 914 rasops_init(ri, 0, 0); 915 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 916 WSSCREEN_RESIZE; 917 scr->scr_flags |= VCONS_LOADFONT; 918 919 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 920 sc->sc_width / ri->ri_font->fontwidth); 921 922 ri->ri_hw = scr; 923 sc->sc_putchar = ri->ri_ops.putchar; 924 ri->ri_ops.copyrows = gftfb_copyrows; 925 ri->ri_ops.copycols = gftfb_copycols; 926 ri->ri_ops.eraserows = gftfb_eraserows; 927 ri->ri_ops.erasecols = gftfb_erasecols; 928 ri->ri_ops.cursor = gftfb_cursor; 929 if (FONT_IS_ALPHA(ri->ri_font)) { 930 ri->ri_ops.putchar = gftfb_putchar_aa; 931 } else 932 ri->ri_ops.putchar = gftfb_putchar; 933 } 934 935 static int 936 gftfb_putcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm) 937 { 938 u_char *r, *g, *b; 939 u_int index = cm->index; 940 u_int count = cm->count; 941 int i, error; 942 u_char rbuf[256], gbuf[256], bbuf[256]; 943 944 if (cm->index >= 256 || cm->count > 256 || 945 (cm->index + cm->count) > 256) 946 return EINVAL; 947 error = copyin(cm->red, &rbuf[index], count); 948 if (error) 949 return error; 950 error = copyin(cm->green, &gbuf[index], count); 951 if (error) 952 return error; 953 error = copyin(cm->blue, &bbuf[index], count); 954 if (error) 955 return error; 956 957 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 958 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 959 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 960 961 r = &sc->sc_cmap_red[index]; 962 g = &sc->sc_cmap_green[index]; 963 b = &sc->sc_cmap_blue[index]; 964 965 for (i = 0; i < count; i++) { 966 gftfb_putpalreg(sc, index, *r, *g, *b); 967 index++; 968 r++, g++, b++; 969 } 970 return 0; 971 } 972 973 static int 974 gftfb_getcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm) 975 { 976 u_int index = cm->index; 977 u_int count = cm->count; 978 int error; 979 980 if (index >= 255 || count > 256 || index + count > 256) 981 return EINVAL; 982 983 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 984 if (error) 985 return error; 986 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 987 if (error) 988 return error; 989 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 990 if (error) 991 return error; 992 993 return 0; 994 } 995 996 static void 997 gftfb_restore_palette(struct gftfb_softc *sc) 998 { 999 uint8_t cmap[768]; 1000 int i, j; 1001 1002 j = 0; 1003 rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap)); 1004 for (i = 0; i < 256; i++) { 1005 sc->sc_cmap_red[i] = cmap[j]; 1006 sc->sc_cmap_green[i] = cmap[j + 1]; 1007 sc->sc_cmap_blue[i] = cmap[j + 2]; 1008 gftfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 1009 j += 3; 1010 } 1011 } 1012 1013 static int 1014 gftfb_putpalreg(struct gftfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 1015 uint8_t b) 1016 { 1017 mutex_enter(&sc->sc_hwlock); 1018 gftfb_wait(sc); 1019 gftfb_write4(sc, NGLE_REG_10, 1020 BA(FractDcd, Otc24, Ots08, Addr24, 0, BINcmap, 0)); 1021 gftfb_write4(sc, NGLE_REG_14, 0x03000300); 1022 gftfb_write4(sc, NGLE_REG_13, 0xffffffff); 1023 1024 gftfb_wait(sc); 1025 gftfb_write4(sc, NGLE_REG_3, 0x400 | (idx << 2)); 1026 gftfb_write4(sc, NGLE_REG_4, (r << 16) | (g << 8) | b); 1027 1028 gftfb_write4(sc, NGLE_REG_2, 0x400); 1029 gftfb_write4(sc, NGLE_REG_26, 0x80000100); 1030 gftfb_setup_fb(sc); 1031 mutex_exit(&sc->sc_hwlock); 1032 return 0; 1033 } 1034 1035 static inline void 1036 gftfb_wait_fifo(struct gftfb_softc *sc, uint32_t slots) 1037 { 1038 uint32_t reg; 1039 1040 do { 1041 reg = gftfb_read4(sc, NGLE_REG_34); 1042 } while (reg < slots); 1043 } 1044 1045 static void 1046 gftfb_rectfill(struct gftfb_softc *sc, int x, int y, int wi, int he, 1047 uint32_t bg) 1048 { 1049 uint32_t mask = 0xffffffff; 1050 1051 if (sc->sc_hwmode != HW_FILL) { 1052 gftfb_wait_fifo(sc, 3); 1053 /* plane mask */ 1054 gftfb_write4(sc, NGLE_REG_13, 0xff); 1055 /* bitmap op */ 1056 gftfb_write4(sc, NGLE_REG_14, 1057 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 1, 0)); 1058 /* dst bitmap access */ 1059 gftfb_write4(sc, NGLE_REG_11, 1060 BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0I, 0)); 1061 sc->sc_hwmode = HW_FILL; 1062 } 1063 gftfb_wait_fifo(sc, 4); 1064 1065 if (wi < 32) 1066 mask = 0xffffffff << (32 - wi); 1067 /* transfer data */ 1068 gftfb_write4(sc, NGLE_REG_8, mask); 1069 gftfb_write4(sc, NGLE_REG_35, bg); 1070 /* dst XY */ 1071 gftfb_write4(sc, NGLE_REG_6, (x << 16) | y); 1072 /* len XY start */ 1073 gftfb_write4(sc, NGLE_REG_9, (wi << 16) | he); 1074 1075 } 1076 1077 static void 1078 gftfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, 1079 int he, int rop) 1080 { 1081 struct gftfb_softc *sc = cookie; 1082 1083 if (sc->sc_hwmode != HW_BLIT) { 1084 gftfb_wait(sc); 1085 gftfb_write4(sc, NGLE_REG_10, 1086 BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINapp0I, 0)); 1087 sc->sc_hwmode = HW_BLIT; 1088 } 1089 gftfb_wait_fifo(sc, 5); 1090 gftfb_write4(sc, NGLE_REG_14, 1091 IBOvals(rop, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 0, 0)); 1092 gftfb_write4(sc, NGLE_REG_13, 0xff); 1093 gftfb_write4(sc, NGLE_REG_24, (xs << 16) | ys); 1094 gftfb_write4(sc, NGLE_REG_7, (wi << 16) | he); 1095 gftfb_write4(sc, NGLE_REG_25, (xd << 16) | yd); 1096 } 1097 1098 static void 1099 gftfb_nuke_cursor(struct rasops_info *ri) 1100 { 1101 struct vcons_screen *scr = ri->ri_hw; 1102 struct gftfb_softc *sc = scr->scr_cookie; 1103 int wi, he, x, y; 1104 1105 if (ri->ri_flg & RI_CURSOR) { 1106 wi = ri->ri_font->fontwidth; 1107 he = ri->ri_font->fontheight; 1108 x = ri->ri_ccol * wi + ri->ri_xorigin; 1109 y = ri->ri_crow * he + ri->ri_yorigin; 1110 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv); 1111 ri->ri_flg &= ~RI_CURSOR; 1112 } 1113 } 1114 1115 static void 1116 gftfb_cursor(void *cookie, int on, int row, int col) 1117 { 1118 struct rasops_info *ri = cookie; 1119 struct vcons_screen *scr = ri->ri_hw; 1120 struct gftfb_softc *sc = scr->scr_cookie; 1121 int x, y, wi, he; 1122 1123 wi = ri->ri_font->fontwidth; 1124 he = ri->ri_font->fontheight; 1125 1126 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1127 if (on) { 1128 if (ri->ri_flg & RI_CURSOR) { 1129 gftfb_nuke_cursor(ri); 1130 } 1131 x = col * wi + ri->ri_xorigin; 1132 y = row * he + ri->ri_yorigin; 1133 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv); 1134 ri->ri_flg |= RI_CURSOR; 1135 } 1136 ri->ri_crow = row; 1137 ri->ri_ccol = col; 1138 } else 1139 { 1140 ri->ri_crow = row; 1141 ri->ri_ccol = col; 1142 ri->ri_flg &= ~RI_CURSOR; 1143 } 1144 1145 } 1146 1147 static void 1148 gftfb_putchar(void *cookie, int row, int col, u_int c, long attr) 1149 { 1150 struct rasops_info *ri = cookie; 1151 struct wsdisplay_font *font = PICK_FONT(ri, c); 1152 struct vcons_screen *scr = ri->ri_hw; 1153 struct gftfb_softc *sc = scr->scr_cookie; 1154 void *data; 1155 int i, x, y, wi, he, rv = GC_NOPE; 1156 uint32_t bg, fg, mask; 1157 1158 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1159 return; 1160 1161 if (!CHAR_IN_FONT(c, font)) 1162 return; 1163 1164 if (row == ri->ri_crow && col == ri->ri_ccol) { 1165 ri->ri_flg &= ~RI_CURSOR; 1166 } 1167 1168 wi = font->fontwidth; 1169 he = font->fontheight; 1170 1171 x = ri->ri_xorigin + col * wi; 1172 y = ri->ri_yorigin + row * he; 1173 1174 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1175 1176 /* if we're drawing a space we're done here */ 1177 if (c == 0x20) { 1178 gftfb_rectfill(sc, x, y, wi, he, bg); 1179 return; 1180 } 1181 1182 fg = ri->ri_devcmap[(attr >> 24) & 0x0f]; 1183 1184 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1185 if (rv == GC_OK) 1186 return; 1187 1188 /* clear the character cell */ 1189 gftfb_rectfill(sc, x, y, wi, he, bg); 1190 1191 data = WSFONT_GLYPH(c, font); 1192 1193 /* 1194 * we're in rectangle mode with transparency enabled from the call to 1195 * gftfb_rectfill() above, so all we need to do is reset the starting 1196 * cordinates, then hammer mask and size/start. Starting coordinates 1197 * will automatically move down the y-axis 1198 */ 1199 gftfb_wait_fifo(sc, 2); 1200 1201 /* character colour */ 1202 gftfb_write4(sc, NGLE_REG_35, fg); 1203 /* dst XY */ 1204 gftfb_write4(sc, NGLE_REG_6, (x << 16) | y); 1205 1206 if (ri->ri_font->stride == 1) { 1207 uint8_t *data8 = data; 1208 for (i = 0; i < he; i++) { 1209 gftfb_wait_fifo(sc, 2); 1210 mask = *data8; 1211 gftfb_write4(sc, NGLE_REG_8, mask << 24); 1212 gftfb_write4(sc, NGLE_REG_9, (wi << 16) | 1); 1213 data8++; 1214 } 1215 } else { 1216 uint16_t *data16 = data; 1217 for (i = 0; i < he; i++) { 1218 gftfb_wait_fifo(sc, 2); 1219 mask = *data16; 1220 gftfb_write4(sc, NGLE_REG_8, mask << 16); 1221 gftfb_write4(sc, NGLE_REG_9, (wi << 16) | 1); 1222 data16++; 1223 } 1224 } 1225 1226 if (rv == GC_ADD) 1227 glyphcache_add(&sc->sc_gc, c, x, y); 1228 } 1229 1230 static void 1231 gftfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1232 { 1233 struct rasops_info *ri = cookie; 1234 struct wsdisplay_font *font = PICK_FONT(ri, c); 1235 struct vcons_screen *scr = ri->ri_hw; 1236 struct gftfb_softc *sc = scr->scr_cookie; 1237 int x, y, wi, he, rv = GC_NOPE; 1238 uint32_t bg; 1239 1240 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1241 return; 1242 1243 if (!CHAR_IN_FONT(c, font)) 1244 return; 1245 1246 if (row == ri->ri_crow && col == ri->ri_ccol) { 1247 ri->ri_flg &= ~RI_CURSOR; 1248 } 1249 1250 wi = font->fontwidth; 1251 he = font->fontheight; 1252 1253 x = ri->ri_xorigin + col * wi; 1254 y = ri->ri_yorigin + row * he; 1255 1256 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1257 1258 if (c == 0x20) { 1259 gftfb_rectfill(sc, x, y, wi, he, bg); 1260 return; 1261 } 1262 1263 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1264 if (rv == GC_OK) 1265 return; 1266 1267 if (sc->sc_hwmode != HW_FB) gftfb_setup_fb(sc); 1268 sc->sc_putchar(cookie, row, col, c, attr); 1269 1270 if (rv == GC_ADD) 1271 glyphcache_add(&sc->sc_gc, c, x, y); 1272 } 1273 1274 static void 1275 gftfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1276 { 1277 struct rasops_info *ri = cookie; 1278 struct vcons_screen *scr = ri->ri_hw; 1279 struct gftfb_softc *sc = scr->scr_cookie; 1280 int32_t xs, xd, y, width, height; 1281 1282 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1283 if (ri->ri_crow == row && 1284 (ri->ri_ccol >= srccol && ri->ri_ccol < (srccol + ncols)) && 1285 (ri->ri_flg & RI_CURSOR)) { 1286 gftfb_nuke_cursor(ri); 1287 } 1288 1289 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1290 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1291 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1292 width = ri->ri_font->fontwidth * ncols; 1293 height = ri->ri_font->fontheight; 1294 gftfb_bitblt(sc, xs, y, xd, y, width, height, RopSrc); 1295 if (ri->ri_crow == row && 1296 (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols))) 1297 ri->ri_flg &= ~RI_CURSOR; 1298 } 1299 } 1300 1301 static void 1302 gftfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1303 { 1304 struct rasops_info *ri = cookie; 1305 struct vcons_screen *scr = ri->ri_hw; 1306 struct gftfb_softc *sc = scr->scr_cookie; 1307 int32_t x, y, width, height, fg, bg, ul; 1308 1309 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1310 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1311 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1312 width = ri->ri_font->fontwidth * ncols; 1313 height = ri->ri_font->fontheight; 1314 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1315 1316 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1317 if (ri->ri_crow == row && 1318 (ri->ri_ccol >= startcol && ri->ri_ccol < (startcol + ncols))) 1319 ri->ri_flg &= ~RI_CURSOR; 1320 } 1321 } 1322 1323 static void 1324 gftfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1325 { 1326 struct rasops_info *ri = cookie; 1327 struct vcons_screen *scr = ri->ri_hw; 1328 struct gftfb_softc *sc = scr->scr_cookie; 1329 int32_t x, ys, yd, width, height; 1330 1331 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1332 if ((ri->ri_crow >= srcrow && ri->ri_crow < (srcrow + nrows)) && 1333 (ri->ri_flg & RI_CURSOR)) { 1334 gftfb_nuke_cursor(ri); 1335 } 1336 x = ri->ri_xorigin; 1337 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1338 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1339 width = ri->ri_emuwidth; 1340 height = ri->ri_font->fontheight * nrows; 1341 gftfb_bitblt(sc, x, ys, x, yd, width, height, RopSrc); 1342 if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows)) 1343 ri->ri_flg &= ~RI_CURSOR; 1344 } 1345 } 1346 1347 static void 1348 gftfb_eraserows(void *cookie, int row, int nrows, long fillattr) 1349 { 1350 struct rasops_info *ri = cookie; 1351 struct vcons_screen *scr = ri->ri_hw; 1352 struct gftfb_softc *sc = scr->scr_cookie; 1353 int32_t x, y, width, height, fg, bg, ul; 1354 1355 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1356 x = ri->ri_xorigin; 1357 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1358 width = ri->ri_emuwidth; 1359 height = ri->ri_font->fontheight * nrows; 1360 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1361 1362 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1363 1364 if (ri->ri_crow >= row && ri->ri_crow < (row + nrows)) 1365 ri->ri_flg &= ~RI_CURSOR; 1366 } 1367 } 1368 1369 /* 1370 * cursor sprite handling 1371 * like most hw info, xf86 3.3 -> nglehdw.h was used as documentation 1372 * problem is, the PCI EG doesn't quite behave like an S9000_ID_ARTIST 1373 * the cursor position register bahaves like the one on HCRX while using 1374 * the same address as Artist, incuding the enable bit and weird handling 1375 * of negative coordinates. The rest of it, colour map, sprite image etc., 1376 * behave like Artist. 1377 */ 1378 1379 static void 1380 gftfb_move_cursor(struct gftfb_softc *sc, int x, int y) 1381 { 1382 uint32_t pos; 1383 1384 sc->sc_cursor_x = x; 1385 x -= sc->sc_hot_x; 1386 sc->sc_cursor_y = y; 1387 y -= sc->sc_hot_y; 1388 1389 if (x < 0) x = 0x1000 - x; 1390 if (y < 0) y = 0x1000 - y; 1391 pos = (x << 16) | y; 1392 if (sc->sc_enabled) pos |= 0x80000000; 1393 gftfb_wait(sc); 1394 gftfb_write4(sc, NGLE_REG_17, pos); 1395 gftfb_write4(sc, NGLE_REG_18, 0x80); 1396 } 1397 1398 static int 1399 gftfb_do_cursor(struct gftfb_softc *sc, struct wsdisplay_cursor *cur) 1400 { 1401 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 1402 1403 sc->sc_enabled = cur->enable; 1404 cur->which |= WSDISPLAY_CURSOR_DOPOS; 1405 } 1406 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 1407 1408 sc->sc_hot_x = cur->hot.x; 1409 sc->sc_hot_y = cur->hot.y; 1410 cur->which |= WSDISPLAY_CURSOR_DOPOS; 1411 } 1412 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 1413 1414 gftfb_move_cursor(sc, cur->pos.x, cur->pos.y); 1415 } 1416 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 1417 uint32_t rgb; 1418 uint8_t r[2], g[2], b[2]; 1419 1420 copyin(cur->cmap.blue, b, 2); 1421 copyin(cur->cmap.green, g, 2); 1422 copyin(cur->cmap.red, r, 2); 1423 mutex_enter(&sc->sc_hwlock); 1424 gftfb_wait(sc); 1425 gftfb_write4(sc, NGLE_REG_10, 1426 BA(FractDcd, Otc24, Ots08, Addr24, 0, BINcmap, 0)); 1427 gftfb_write4(sc, NGLE_REG_14, 0x03000300); 1428 gftfb_write4(sc, NGLE_REG_13, 0xffffffff); 1429 gftfb_wait(sc); 1430 gftfb_write4(sc, NGLE_REG_3, 0); 1431 gftfb_write4(sc, NGLE_REG_4, 0); 1432 gftfb_write4(sc, NGLE_REG_4, 0); 1433 rgb = (r[0] << 16) | (g[0] << 8) | b[0]; 1434 gftfb_write4(sc, NGLE_REG_4, rgb); /* BG */ 1435 rgb = (r[1] << 16) | (g[1] << 8) | b[1]; 1436 gftfb_write4(sc, NGLE_REG_4, rgb); /* FG */ 1437 gftfb_write4(sc, NGLE_REG_2, 0); 1438 gftfb_write4(sc, NGLE_REG_26, 0x80008004); 1439 gftfb_setup_fb(sc); 1440 mutex_exit(&sc->sc_hwlock); 1441 1442 } 1443 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 1444 uint32_t buffer[128], latch, tmp; 1445 int i; 1446 1447 copyin(cur->mask, buffer, 512); 1448 gftfb_wait(sc); 1449 gftfb_write4(sc, NGLE_REG_14, 0x300); 1450 gftfb_write4(sc, NGLE_REG_13, 0xffffffff); 1451 gftfb_write4(sc, NGLE_REG_11, 1452 BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcmask, 0)); 1453 gftfb_write4(sc, NGLE_REG_3, 0); 1454 for (i = 0; i < 128; i += 2) { 1455 latch = 0; 1456 tmp = buffer[i] & 0x80808080; 1457 latch |= tmp >> 7; 1458 tmp = buffer[i] & 0x40404040; 1459 latch |= tmp >> 5; 1460 tmp = buffer[i] & 0x20202020; 1461 latch |= tmp >> 3; 1462 tmp = buffer[i] & 0x10101010; 1463 latch |= tmp >> 1; 1464 tmp = buffer[i] & 0x08080808; 1465 latch |= tmp << 1; 1466 tmp = buffer[i] & 0x04040404; 1467 latch |= tmp << 3; 1468 tmp = buffer[i] & 0x02020202; 1469 latch |= tmp << 5; 1470 tmp = buffer[i] & 0x01010101; 1471 latch |= tmp << 7; 1472 gftfb_write4(sc, NGLE_REG_4, latch); 1473 latch = 0; 1474 tmp = buffer[i + 1] & 0x80808080; 1475 latch |= tmp >> 7; 1476 tmp = buffer[i + 1] & 0x40404040; 1477 latch |= tmp >> 5; 1478 tmp = buffer[i + 1] & 0x20202020; 1479 latch |= tmp >> 3; 1480 tmp = buffer[i + 1] & 0x10101010; 1481 latch |= tmp >> 1; 1482 tmp = buffer[i + 1] & 0x08080808; 1483 latch |= tmp << 1; 1484 tmp = buffer[i + 1] & 0x04040404; 1485 latch |= tmp << 3; 1486 tmp = buffer[i + 1] & 0x02020202; 1487 latch |= tmp << 5; 1488 tmp = buffer[i + 1] & 0x01010101; 1489 latch |= tmp << 7; 1490 gftfb_write4(sc, NGLE_REG_5, latch); 1491 } 1492 1493 copyin(cur->image, buffer, 512); 1494 gftfb_wait(sc); 1495 gftfb_write4(sc, NGLE_REG_14, 0x300); 1496 gftfb_write4(sc, NGLE_REG_13, 0xffffffff); 1497 gftfb_write4(sc, NGLE_REG_11, 1498 BA(IndexedDcd, Otc32, 0, AddrLong, 0, BINcursor, 0)); 1499 gftfb_write4(sc, NGLE_REG_3, 0); 1500 for (i = 0; i < 128; i += 2) { 1501 latch = 0; 1502 tmp = buffer[i] & 0x80808080; 1503 latch |= tmp >> 7; 1504 tmp = buffer[i] & 0x40404040; 1505 latch |= tmp >> 5; 1506 tmp = buffer[i] & 0x20202020; 1507 latch |= tmp >> 3; 1508 tmp = buffer[i] & 0x10101010; 1509 latch |= tmp >> 1; 1510 tmp = buffer[i] & 0x08080808; 1511 latch |= tmp << 1; 1512 tmp = buffer[i] & 0x04040404; 1513 latch |= tmp << 3; 1514 tmp = buffer[i] & 0x02020202; 1515 latch |= tmp << 5; 1516 tmp = buffer[i] & 0x01010101; 1517 latch |= tmp << 7; 1518 gftfb_write4(sc, NGLE_REG_4, latch); 1519 latch = 0; 1520 tmp = buffer[i + 1] & 0x80808080; 1521 latch |= tmp >> 7; 1522 tmp = buffer[i + 1] & 0x40404040; 1523 latch |= tmp >> 5; 1524 tmp = buffer[i + 1] & 0x20202020; 1525 latch |= tmp >> 3; 1526 tmp = buffer[i + 1] & 0x10101010; 1527 latch |= tmp >> 1; 1528 tmp = buffer[i + 1] & 0x08080808; 1529 latch |= tmp << 1; 1530 tmp = buffer[i + 1] & 0x04040404; 1531 latch |= tmp << 3; 1532 tmp = buffer[i + 1] & 0x02020202; 1533 latch |= tmp << 5; 1534 tmp = buffer[i + 1] & 0x01010101; 1535 latch |= tmp << 7; 1536 gftfb_write4(sc, NGLE_REG_5, latch); 1537 } 1538 gftfb_setup_fb(sc); 1539 } 1540 1541 return 0; 1542 } 1543 1544 static void 1545 gftfb_set_video(struct gftfb_softc *sc, int on) 1546 { 1547 if (sc->sc_video_on == on) 1548 return; 1549 1550 sc->sc_video_on = on; 1551 1552 gftfb_wait(sc); 1553 if (on) { 1554 gftfb_write4(sc, NGLE_REG_21, 1555 gftfb_read4(sc, NGLE_REG_21) | 0x0a000000); 1556 gftfb_write4(sc, NGLE_REG_27, 1557 gftfb_read4(sc, NGLE_REG_27) | 0x00800000); 1558 } else { 1559 gftfb_write4(sc, NGLE_REG_21, 1560 gftfb_read4(sc, NGLE_REG_21) & ~0x0a000000); 1561 gftfb_write4(sc, NGLE_REG_27, 1562 gftfb_read4(sc, NGLE_REG_27) & ~0x00800000); 1563 } 1564 } 1565