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