1 /* $NetBSD: hyperfb.c,v 1.35 2026/05/19 09:24:10 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2024 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * a native driver for HCRX / hyperdrive cards 31 * tested on a HCRX24Z in a C360 only so far 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: hyperfb.c,v 1.35 2026/05/19 09:24:10 macallan Exp $"); 36 37 #include "opt_cputype.h" 38 #include "opt_hyperfb.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 44 #include <sys/bus.h> 45 #include <machine/iomod.h> 46 #include <machine/autoconf.h> 47 48 #include <dev/wscons/wsdisplayvar.h> 49 #include <dev/wscons/wsconsio.h> 50 #include <dev/wsfont/wsfont.h> 51 #include <dev/rasops/rasops.h> 52 #include <dev/wscons/wsdisplay_vconsvar.h> 53 #include <dev/wscons/wsdisplay_glyphcachevar.h> 54 55 #include <dev/ic/stireg.h> 56 #include <dev/ic/stivar.h> 57 #include <dev/ic/nglereg.h> 58 59 #include <hppa/dev/cpudevs.h> 60 #include <hppa/hppa/machdep.h> 61 62 #ifdef HYPERFB_DEBUG 63 #define DPRINTF printf 64 #else 65 #define DPRINTF if (0) printf 66 #endif 67 68 #define STI_ROMSIZE (sizeof(struct sti_dd) * 4) 69 70 #define HCRX_FBOFFSET 0x01000000 71 #define HCRX_FBLEN 0x01000000 72 #define HCRX_REGOFFSET 0x00100000 73 #define HCRX_REGLEN 0x00290000 74 75 #define HCRX_CONFIG_24BIT 0x100 76 77 int hyperfb_match(device_t, cfdata_t, void *); 78 void hyperfb_attach(device_t, device_t, void *); 79 80 struct hyperfb_softc { 81 device_t sc_dev; 82 bus_space_tag_t sc_iot; 83 bus_addr_t sc_base; 84 bus_space_handle_t sc_hfb, sc_hreg; 85 void *sc_fb; 86 87 int sc_width, sc_height; 88 int sc_locked, sc_is_console, sc_24bit; 89 struct vcons_screen sc_console_screen; 90 struct wsscreen_descr sc_defaultscreen_descr; 91 const struct wsscreen_descr *sc_screens[1]; 92 struct wsscreen_list sc_screenlist; 93 struct vcons_data vd; 94 int sc_mode, sc_fbflag; 95 u_char sc_cmap_red[256]; 96 u_char sc_cmap_green[256]; 97 u_char sc_cmap_blue[256]; 98 kmutex_t sc_hwlock; 99 uint32_t sc_sba, sc_dba; 100 /* cursor stuff */ 101 int sc_cursor_x, sc_cursor_y; 102 int sc_hot_x, sc_hot_y, sc_enabled; 103 int sc_video_on; 104 /* glyphcache etc. */ 105 glyphcache sc_gc; 106 }; 107 108 extern struct cfdriver hyperfb_cd; 109 110 CFATTACH_DECL_NEW(hyperfb, sizeof(struct hyperfb_softc), hyperfb_match, 111 hyperfb_attach, NULL, NULL); 112 113 static inline void hyperfb_setup_fb(struct hyperfb_softc *); 114 static inline void hyperfb_setup_fb24(struct hyperfb_softc *); 115 static void hyperfb_init_screen(void *, struct vcons_screen *, 116 int, long *); 117 static int hyperfb_ioctl(void *, void *, u_long, void *, int, 118 struct lwp *); 119 static paddr_t hyperfb_mmap(void *, void *, off_t, int); 120 121 static int hyperfb_putcmap(struct hyperfb_softc *, 122 struct wsdisplay_cmap *); 123 static int hyperfb_getcmap(struct hyperfb_softc *, 124 struct wsdisplay_cmap *); 125 static void hyperfb_restore_palette(struct hyperfb_softc *); 126 static int hyperfb_putpalreg(struct hyperfb_softc *, uint8_t, uint8_t, 127 uint8_t, uint8_t); 128 void hyperfb_setup(struct hyperfb_softc *); 129 static void hyperfb_set_video(struct hyperfb_softc *, int); 130 131 static void hyperfb_rectfill(struct hyperfb_softc *, int, int, int, int, 132 uint32_t); 133 static void hyperfb_rectfill_a(void *, int, int, int, int, long); 134 static void hyperfb_bitblt(void *, int, int, int, int, int, 135 int, int); 136 137 static void hyperfb_cursor(void *, int, int, int); 138 static void hyperfb_putchar(void *, int, int, u_int, long); 139 static void hyperfb_putchar_aa(void *, int, int, u_int, long); 140 static int hyperfb_allocattr(void *, int, int, int, long *); 141 static void hyperfb_copycols(void *, int, int, int, int); 142 static void hyperfb_erasecols(void *, int, int, int, long); 143 static void hyperfb_copyrows(void *, int, int, int); 144 static void hyperfb_eraserows(void *, int, int, long); 145 146 static void hyperfb_move_cursor(struct hyperfb_softc *, int, int); 147 static int hyperfb_do_cursor(struct hyperfb_softc *, 148 struct wsdisplay_cursor *); 149 150 static inline void hyperfb_wait_fifo(struct hyperfb_softc *, uint32_t); 151 152 struct wsdisplay_accessops hyperfb_accessops = { 153 hyperfb_ioctl, 154 hyperfb_mmap, 155 NULL, /* alloc_screen */ 156 NULL, /* free_screen */ 157 NULL, /* show_screen */ 158 NULL, /* load_font */ 159 NULL, /* pollc */ 160 NULL /* scroll */ 161 }; 162 163 static inline uint32_t 164 hyperfb_read4(struct hyperfb_softc *sc, uint32_t offset) 165 { 166 return bus_space_read_4(sc->sc_iot, sc->sc_hreg, offset); 167 } 168 169 static inline uint8_t 170 hyperfb_read1(struct hyperfb_softc *sc, uint32_t offset) 171 { 172 return bus_space_read_1(sc->sc_iot, sc->sc_hreg, offset); 173 } 174 175 static inline void 176 hyperfb_write4(struct hyperfb_softc *sc, uint32_t offset, uint32_t val) 177 { 178 bus_space_write_4(sc->sc_iot, sc->sc_hreg, offset, val); 179 } 180 181 static inline void 182 hyperfb_write1(struct hyperfb_softc *sc, uint32_t offset, uint8_t val) 183 { 184 bus_space_write_1(sc->sc_iot, sc->sc_hreg, offset, val); 185 } 186 187 static inline void 188 hyperfb_wait(struct hyperfb_softc *sc) 189 { 190 uint8_t stat; 191 192 do { 193 stat = hyperfb_read1(sc, NGLE_BUSY); 194 if (stat == 0) 195 stat = hyperfb_read1(sc, NGLE_BUSY); 196 } while (stat != 0); 197 } 198 199 static inline void 200 hyperfb_wait_fifo(struct hyperfb_softc *sc, uint32_t slots) 201 { 202 uint32_t reg; 203 204 do { 205 reg = hyperfb_read4(sc, NGLE_FIFO); 206 } while (reg < slots); 207 } 208 209 static inline void 210 hyperfb_sba(struct hyperfb_softc *sc, uint32_t mode) 211 { 212 if (sc->sc_sba != mode) { 213 hyperfb_wait(sc); 214 hyperfb_write4(sc, NGLE_SBA, mode); 215 sc->sc_sba = mode; 216 } 217 } 218 219 static inline void 220 hyperfb_dba(struct hyperfb_softc *sc, uint32_t mode) 221 { 222 if (sc->sc_dba != mode) { 223 hyperfb_wait_fifo(sc, 2); 224 hyperfb_write4(sc, NGLE_DBA, mode); 225 sc->sc_dba = mode; 226 } 227 } 228 229 static inline void 230 hyperfb_both(struct hyperfb_softc *sc, uint32_t mode) 231 { 232 if ((sc->sc_dba != mode) || (sc->sc_sba != mode)) { 233 hyperfb_wait(sc); 234 hyperfb_write4(sc, NGLE_BAboth, mode); 235 sc->sc_dba = mode; 236 sc->sc_sba = mode; 237 } 238 } 239 240 static inline void 241 hyperfb_fbflag(struct hyperfb_softc *sc, int flag) 242 { 243 if (flag != 0) flag = 1; 244 if (sc->sc_fbflag == flag) return; 245 sc->sc_fbflag = flag; 246 hyperfb_write1(sc, NGLE_CONTROL_FB, flag); 247 } 248 249 static inline void 250 hyperfb_setup_fb(struct hyperfb_softc *sc) 251 { 252 253 /* 254 * turns out the plane mask is applied to everything, including 255 * direct framebuffer writes, so make sure we always set it 256 */ 257 hyperfb_wait(sc); 258 if ((sc->sc_mode != WSDISPLAYIO_MODE_EMUL) && sc->sc_24bit) { 259 hyperfb_both(sc, 260 BA(FractDcd, Otc01, Ots08, AddrLong, 0, BINapp0F8, 0)); 261 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 262 } else { 263 hyperfb_both(sc, 264 BA(IndexedDcd, Otc04, Ots08, AddrByte, 0, BINovly, 0)); 265 hyperfb_write4(sc, NGLE_PLANEMASK, 0xff); 266 } 267 hyperfb_write4(sc, NGLE_IBO, 0x83000300); 268 //IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, 1, 0, 0); 269 hyperfb_wait(sc); 270 hyperfb_fbflag(sc, 1); 271 } 272 273 static inline void 274 hyperfb_setup_fb24(struct hyperfb_softc *sc) 275 { 276 277 hyperfb_wait(sc); 278 hyperfb_write4(sc, NGLE_HCRX_HB_MODE, 279 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE); 280 hyperfb_write4(sc, NGLE_HCRX_HB_MODE, 281 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE); 282 hyperfb_both(sc, BA(FractDcd, Otc01, Ots08, AddrLong, 0, BINapp0F8, 0)); 283 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 284 hyperfb_write4(sc, NGLE_IBO, 0x83000300); 285 //IBOvals(RopSrc,0,BitmapExtent08,0,DataDynamic,1,0,0) 286 hyperfb_wait(sc); 287 hyperfb_fbflag(sc, 1); 288 } 289 290 int 291 hyperfb_match(device_t parent, cfdata_t cf, void *aux) 292 { 293 struct confargs *ca = aux; 294 bus_space_handle_t romh; 295 paddr_t rom; 296 uint32_t id = 0; 297 u_char devtype; 298 int rv = 0, romunmapped = 0; 299 300 if (ca->ca_type.iodc_type != HPPA_TYPE_FIO) 301 return 0; 302 303 /* these need further checking for the graphics id */ 304 if (ca->ca_type.iodc_sv_model != HPPA_FIO_GSGC && 305 ca->ca_type.iodc_sv_model != HPPA_FIO_SGC) 306 return 0; 307 308 if (ca->ca_naddrs > 0) 309 rom = ca->ca_addrs[0].addr; 310 else 311 rom = ca->ca_hpa; 312 313 DPRINTF("%s: hpa=%x, rom=%x\n", __func__, (uint)ca->ca_hpa, 314 (uint)rom); 315 316 /* if it does not map, probably part of the lasi space */ 317 if (bus_space_map(ca->ca_iot, rom, STI_ROMSIZE, 0, &romh)) { 318 DPRINTF("%s: can't map rom space (%d)\n", __func__, rv); 319 320 if ((rom & HPPA_IOBEGIN) == HPPA_IOBEGIN) { 321 romh = rom; 322 romunmapped++; 323 } else { 324 /* in this case nobody has no freaking idea */ 325 return 0; 326 } 327 } 328 329 devtype = bus_space_read_1(ca->ca_iot, romh, 3); 330 DPRINTF("%s: devtype=%d\n", __func__, devtype); 331 rv = 1; 332 switch (devtype) { 333 case STI_DEVTYPE4: 334 id = bus_space_read_4(ca->ca_iot, romh, STI_DEV4_DD_GRID); 335 break; 336 case STI_DEVTYPE1: 337 id = (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 338 + 3) << 24) | 339 (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 340 + 7) << 16) | 341 (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 342 + 11) << 8) | 343 (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 344 + 15)); 345 break; 346 default: 347 DPRINTF("%s: unknown type (%x)\n", __func__, devtype); 348 rv = 0; 349 } 350 351 if (id == STI_DD_HCRX) 352 rv = 100; /* beat out sti */ 353 354 ca->ca_addrs[ca->ca_naddrs].addr = rom; 355 ca->ca_addrs[ca->ca_naddrs].size = sti_rom_size(ca->ca_iot, romh); 356 ca->ca_naddrs++; 357 358 if (!romunmapped) 359 bus_space_unmap(ca->ca_iot, romh, STI_ROMSIZE); 360 return rv; 361 } 362 363 void 364 hyperfb_attach(device_t parent, device_t self, void *aux) 365 { 366 struct hyperfb_softc *sc = device_private(self); 367 struct confargs *ca = aux; 368 struct rasops_info *ri; 369 struct wsemuldisplaydev_attach_args aa; 370 bus_space_handle_t hrom; 371 hppa_hpa_t consaddr; 372 long defattr; 373 int pagezero_cookie; 374 paddr_t rom; 375 uint32_t config; 376 377 pagezero_cookie = hppa_pagezero_map(); 378 consaddr = (hppa_hpa_t)PAGE0->mem_cons.pz_hpa; 379 hppa_pagezero_unmap(pagezero_cookie); 380 381 sc->sc_dev = self; 382 sc->sc_base = ca->ca_hpa; 383 sc->sc_iot = ca->ca_iot; 384 sc->sc_is_console =(ca->ca_hpa == consaddr); 385 sc->sc_width = 1280; 386 sc->sc_height = 1024; 387 sc->sc_sba = sc->sc_dba = 0; 388 389 /* we can *not* be interrupted when doing colour map accesses */ 390 mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH); 391 392 /* we stashed rom addr/len into the last slot during probe */ 393 rom = ca->ca_addrs[ca->ca_naddrs - 1].addr; 394 395 if (bus_space_map(sc->sc_iot, 396 sc->sc_base + HCRX_FBOFFSET, HCRX_FBLEN, 397 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, 398 &sc->sc_hfb)) { 399 aprint_error_dev(sc->sc_dev, 400 "failed to map the framebuffer\n"); 401 return; 402 } 403 sc->sc_fb = bus_space_vaddr(sc->sc_iot, sc->sc_hfb); 404 405 if (bus_space_map(sc->sc_iot, 406 sc->sc_base + HCRX_REGOFFSET, HCRX_REGLEN, 0, &sc->sc_hreg)) { 407 aprint_error_dev(sc->sc_dev, "failed to map registers\n"); 408 return; 409 } 410 411 /* 412 * we really only need the first word so we can grab the config bits 413 * between the bytes 414 */ 415 if (bus_space_map(sc->sc_iot, rom, 4, 0, &hrom)) { 416 aprint_error_dev(sc->sc_dev, 417 "failed to map ROM, assuming 8bit\n"); 418 config = 0; 419 } else { 420 /* alright, we got the ROM. now do the idle dance. */ 421 volatile uint32_t r = hyperfb_read4(sc, NGLE_BUSY); 422 __USE(r); 423 hyperfb_wait(sc); 424 config = bus_space_read_4(sc->sc_iot, hrom, 0); 425 bus_space_unmap(sc->sc_iot, hrom, 4); 426 } 427 sc->sc_24bit = ((config & HCRX_CONFIG_24BIT) != 0); 428 429 printf(" %s\n", sc->sc_24bit ? "HCRX24" : "HCRX"); 430 #ifdef HP7300LC_CPU 431 /* 432 * PCXL2: enable accel I/O for this space, see PCX-L2 ERS "ACCEL_IO". 433 * "pcxl2_ers.{ps,pdf}", (section / chapter . rel. page / abs. page) 434 * 8.7.4 / 8-12 / 92, 11.3.14 / 11-14 / 122 and 14.8 / 14-5 / 203. 435 */ 436 if (hppa_cpu_info->hci_cputype == hpcxl2 437 && ca->ca_hpa >= PCXL2_ACCEL_IO_START 438 && ca->ca_hpa <= PCXL2_ACCEL_IO_END) 439 eaio_l2(PCXL2_ACCEL_IO_ADDR2MASK(ca->ca_hpa)); 440 #endif /* HP7300LC_CPU */ 441 442 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 443 sc->sc_locked = 0; 444 445 hyperfb_setup(sc); 446 hyperfb_setup_fb(sc); 447 448 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 449 "default", 450 0, 0, 451 NULL, 452 8, 16, 453 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 454 WSSCREEN_RESIZE, 455 NULL 456 }; 457 458 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 459 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 460 461 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 462 &hyperfb_accessops); 463 sc->vd.init_screen = hyperfb_init_screen; 464 sc->vd.show_screen_cookie = &sc->sc_gc; 465 sc->vd.show_screen_cb = glyphcache_adapt; 466 467 ri = &sc->sc_console_screen.scr_ri; 468 469 sc->sc_gc.gc_bitblt = hyperfb_bitblt; 470 sc->sc_gc.gc_rectfill = hyperfb_rectfill_a; 471 sc->sc_gc.gc_blitcookie = sc; 472 sc->sc_gc.gc_rop = RopSrc; 473 474 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr); 475 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 476 477 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 478 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 479 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 480 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 481 482 hyperfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 483 ri->ri_devcmap[(defattr >> 16) & 0xff]); 484 hyperfb_restore_palette(sc); 485 486 glyphcache_init(&sc->sc_gc, 1024, 487 1024, 488 1280, 489 ri->ri_font->fontwidth, 490 ri->ri_font->fontheight, 491 defattr); 492 493 if (sc->sc_is_console) { 494 495 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 496 defattr); 497 vcons_replay_msgbuf(&sc->sc_console_screen); 498 } 499 500 /* no suspend/resume support yet */ 501 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 502 aprint_error_dev(sc->sc_dev, 503 "couldn't establish power handler\n"); 504 505 aa.console = sc->sc_is_console; 506 aa.scrdata = &sc->sc_screenlist; 507 aa.accessops = &hyperfb_accessops; 508 aa.accesscookie = &sc->vd; 509 510 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 511 512 hyperfb_setup_fb(sc); 513 } 514 515 static void 516 hyperfb_init_screen(void *cookie, struct vcons_screen *scr, 517 int existing, long *defattr) 518 { 519 struct hyperfb_softc *sc = cookie; 520 struct rasops_info *ri = &scr->scr_ri; 521 522 ri->ri_depth = 8; 523 ri->ri_width = 1280; 524 #ifdef HYPERFB_DEBUG 525 ri->ri_height = 900; 526 #else 527 ri->ri_height = 1024; 528 #endif 529 ri->ri_stride = 2048; 530 ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB | RI_FULLCLEAR | 531 RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 532 533 ri->ri_bits = (void *)sc->sc_fb; 534 rasops_init(ri, 0, 0); 535 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 536 WSSCREEN_RESIZE; 537 scr->scr_flags |= VCONS_LOADFONT; 538 539 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 540 sc->sc_width / ri->ri_font->fontwidth); 541 542 ri->ri_hw = scr; 543 544 ri->ri_ops.copyrows = hyperfb_copyrows; 545 ri->ri_ops.copycols = hyperfb_copycols; 546 ri->ri_ops.eraserows = hyperfb_eraserows; 547 ri->ri_ops.erasecols = hyperfb_erasecols; 548 ri->ri_ops.cursor = hyperfb_cursor; 549 ri->ri_ops.allocattr = hyperfb_allocattr; 550 if (FONT_IS_ALPHA(ri->ri_font)) { 551 ri->ri_ops.putchar = hyperfb_putchar_aa; 552 } else 553 ri->ri_ops.putchar = hyperfb_putchar; 554 } 555 556 static int 557 hyperfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 558 struct lwp *l) 559 { 560 struct vcons_data *vd = v; 561 struct hyperfb_softc *sc = vd->cookie; 562 struct wsdisplay_fbinfo *wdf; 563 struct vcons_screen *ms = vd->active; 564 565 switch (cmd) { 566 case WSDISPLAYIO_GTYPE: 567 *(u_int *)data = WSDISPLAY_TYPE_STI; 568 return 0; 569 570 case GCID: 571 *(u_int *)data = STI_DD_HCRX; 572 return 0; 573 574 case WSDISPLAYIO_GINFO: 575 if (ms == NULL) 576 return ENODEV; 577 wdf = (void *)data; 578 wdf->height = ms->scr_ri.ri_height; 579 wdf->width = sc->sc_24bit ? ms->scr_ri.ri_width << 2 580 : ms->scr_ri.ri_width; 581 wdf->depth = ms->scr_ri.ri_depth; 582 wdf->cmsize = 256; 583 return 0; 584 585 case WSDISPLAYIO_GETCMAP: 586 return hyperfb_getcmap(sc, 587 (struct wsdisplay_cmap *)data); 588 589 case WSDISPLAYIO_PUTCMAP: 590 return hyperfb_putcmap(sc, 591 (struct wsdisplay_cmap *)data); 592 case WSDISPLAYIO_LINEBYTES: 593 *(u_int *)data = sc->sc_24bit ? 8192 : 2048; 594 return 0; 595 596 case WSDISPLAYIO_SMODE: { 597 int new_mode = *(int*)data; 598 if (new_mode != sc->sc_mode) { 599 sc->sc_mode = new_mode; 600 if (new_mode == WSDISPLAYIO_MODE_EMUL) { 601 hyperfb_setup(sc); 602 hyperfb_restore_palette(sc); 603 glyphcache_wipe(&sc->sc_gc); 604 hyperfb_rectfill(sc, 0, 0, sc->sc_width, 605 sc->sc_height, ms->scr_ri.ri_devcmap[ 606 (ms->scr_defattr >> 16) & 0xff]); 607 vcons_redraw_screen(ms); 608 hyperfb_set_video(sc, 1); 609 } else { 610 hyperfb_setup(sc); 611 hyperfb_rectfill(sc, 0, 0, sc->sc_width, 612 sc->sc_height, 0xff); 613 hyperfb_setup_fb24(sc); 614 } 615 } 616 } 617 return 0; 618 619 case WSDISPLAYIO_GET_FBINFO: { 620 struct wsdisplayio_fbinfo *fbi = data; 621 int ret; 622 623 ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 624 fbi->fbi_fbsize = sc->sc_height * 2048; 625 if (sc->sc_24bit) { 626 fbi->fbi_stride = 8192; 627 fbi->fbi_bitsperpixel = 32; 628 fbi->fbi_pixeltype = WSFB_RGB; 629 fbi->fbi_subtype.fbi_rgbmasks.red_offset = 16; 630 fbi->fbi_subtype.fbi_rgbmasks.red_size = 8; 631 fbi->fbi_subtype.fbi_rgbmasks.green_offset = 8; 632 fbi->fbi_subtype.fbi_rgbmasks.green_size = 8; 633 fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 0; 634 fbi->fbi_subtype.fbi_rgbmasks.blue_size = 8; 635 fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 0; 636 fbi->fbi_fbsize = sc->sc_height * 8192; 637 } 638 return ret; 639 } 640 641 case WSDISPLAYIO_GCURPOS: { 642 struct wsdisplay_curpos *cp = (void *)data; 643 644 cp->x = sc->sc_cursor_x; 645 cp->y = sc->sc_cursor_y; 646 } 647 return 0; 648 649 case WSDISPLAYIO_SCURPOS: { 650 struct wsdisplay_curpos *cp = (void *)data; 651 652 hyperfb_move_cursor(sc, cp->x, cp->y); 653 } 654 return 0; 655 656 case WSDISPLAYIO_GCURMAX: { 657 struct wsdisplay_curpos *cp = (void *)data; 658 659 cp->x = 64; 660 cp->y = 64; 661 } 662 return 0; 663 664 case WSDISPLAYIO_SCURSOR: { 665 struct wsdisplay_cursor *cursor = (void *)data; 666 667 return hyperfb_do_cursor(sc, cursor); 668 } 669 670 case WSDISPLAYIO_SVIDEO: 671 hyperfb_set_video(sc, *(int *)data); 672 return 0; 673 case WSDISPLAYIO_GVIDEO: 674 *(u_int *)data = sc->sc_video_on ? 675 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 676 return 0; 677 } 678 return EPASSTHROUGH; 679 } 680 681 static paddr_t 682 hyperfb_mmap(void *v, void *vs, off_t offset, int prot) 683 { 684 struct vcons_data *vd = v; 685 struct hyperfb_softc *sc = vd->cookie; 686 paddr_t pa = -1; 687 688 689 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) 690 return -1; 691 692 /* GSC framebuffer space is 16MB */ 693 if (offset >= 0 && offset < 0x1000000) { 694 /* framebuffer */ 695 pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_FBOFFSET, 696 offset, prot, 697 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 698 } else if (offset >= 0x80000000 && offset < 0x80400000) { 699 /* blitter registers etc. */ 700 pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_REGOFFSET, 701 offset - 0x80000000, prot, BUS_SPACE_MAP_LINEAR); 702 } 703 704 return pa; 705 } 706 707 static int 708 hyperfb_putcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm) 709 { 710 u_char *r, *g, *b; 711 u_int index = cm->index; 712 u_int count = cm->count; 713 int i, error; 714 u_char rbuf[256], gbuf[256], bbuf[256]; 715 716 if (cm->index >= 256 || cm->count > 256 || 717 (cm->index + cm->count) > 256) 718 return EINVAL; 719 error = copyin(cm->red, &rbuf[index], count); 720 if (error) 721 return error; 722 error = copyin(cm->green, &gbuf[index], count); 723 if (error) 724 return error; 725 error = copyin(cm->blue, &bbuf[index], count); 726 if (error) 727 return error; 728 729 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 730 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 731 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 732 733 r = &sc->sc_cmap_red[index]; 734 g = &sc->sc_cmap_green[index]; 735 b = &sc->sc_cmap_blue[index]; 736 737 for (i = 0; i < count; i++) { 738 hyperfb_putpalreg(sc, index, *r, *g, *b); 739 index++; 740 r++, g++, b++; 741 } 742 return 0; 743 } 744 745 static int 746 hyperfb_getcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm) 747 { 748 u_int index = cm->index; 749 u_int count = cm->count; 750 int error; 751 752 if (index >= 255 || count > 256 || index + count > 256) 753 return EINVAL; 754 755 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 756 if (error) 757 return error; 758 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 759 if (error) 760 return error; 761 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 762 if (error) 763 return error; 764 765 return 0; 766 } 767 768 static void 769 hyperfb_restore_palette(struct hyperfb_softc *sc) 770 { 771 uint8_t cmap[768]; 772 int i, j; 773 774 j = 0; 775 rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap)); 776 for (i = 0; i < 256; i++) { 777 sc->sc_cmap_red[i] = cmap[j]; 778 sc->sc_cmap_green[i] = cmap[j + 1]; 779 sc->sc_cmap_blue[i] = cmap[j + 2]; 780 hyperfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 781 j += 3; 782 } 783 } 784 785 static int 786 hyperfb_putpalreg(struct hyperfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 787 uint8_t b) 788 { 789 mutex_enter(&sc->sc_hwlock); 790 hyperfb_both(sc, BA(FractDcd, Otc01, Ots08, Addr24, 0, BINcmap, 0)); // 0xbbe0f000 791 hyperfb_write4(sc, NGLE_IBO, 792 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0)); // 0x03000300 793 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 794 795 hyperfb_wait(sc); 796 hyperfb_write4(sc, NGLE_BINC_DST, 0x400 | (idx << 2)); 797 hyperfb_write4(sc, NGLE_BINC_DATA_R, (r << 16) | (g << 8) | b); 798 799 hyperfb_write4(sc, NGLE_BINC_SRC, 0x400); 800 hyperfb_write4(sc, NGLE_HCRX_LUTBLT, 0x82000100); 801 // LBC_ENABLE | (0x200 << OFFSET_SHIFT) | LBC_TYPE_CMAP | 0x100 802 hyperfb_setup_fb(sc); 803 mutex_exit(&sc->sc_hwlock); 804 return 0; 805 } 806 807 void 808 hyperfb_setup(struct hyperfb_softc *sc) 809 { 810 int i; 811 812 sc->sc_hot_x = 0; 813 sc->sc_hot_y = 0; 814 sc->sc_enabled = 0; 815 sc->sc_video_on = 1; 816 sc->sc_sba = sc->sc_dba = 0; 817 818 /* first enable all planes */ 819 hyperfb_wait(sc); 820 hyperfb_write4(sc, NGLE_HCRX_PLANE_ENABLE, 0xffffffff); 821 822 /* 823 * When in terminal mode we set hyperbowl to 2x 8bit image buffers 824 * with no transparencies so we can abuse one of them as glyph cache. 825 * In FB mode we switch to 8bit overlay / 24bit image buffer(s), with 826 * colour 255 transparent so we can easily turn the overlay invisible 827 * by blitting it all white. There may or may not be another register 828 * to control this, but we don't know anything about it. 829 */ 830 hyperfb_write4(sc, NGLE_HCRX_HB_MODE, 831 HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES); 832 hyperfb_write4(sc, NGLE_HCRX_HB_MODE, 833 HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES); 834 /* write must happen twice because hw bug */ 835 if (sc->sc_24bit) { 836 hyperfb_write4(sc, NGLE_HCRX_HB_MODE2, HYPERBOWL_MODE2_8_24); 837 /* Set lut 0 to be the direct color */ 838 hyperfb_write4(sc, NGLE_REG_42, 0x014c0148); 839 hyperfb_write4(sc, NGLE_REG_43, 0x404c4048); 840 hyperfb_write4(sc, NGLE_REG_44, 0x034c0348); 841 hyperfb_write4(sc, NGLE_REG_45, 0x444c4448); 842 } else { 843 844 hyperfb_write4(sc, NGLE_REG_42, 0); 845 hyperfb_write4(sc, NGLE_REG_43, 0); 846 hyperfb_write4(sc, NGLE_REG_44, 0); 847 hyperfb_write4(sc, NGLE_REG_45, 0x444c4048); 848 } 849 850 /* attr. planes */ 851 /* 852 * XXX 853 * This is odd. 854 * We tell the blitter to write 8 bit deep but expect a 32bit value 855 * to be written. Then again, writing to BINattr is already special 856 * by using NGLE_REG_12 as source instead of the fg/bg registers, it 857 * may always write all planes, who knows. This is what the NGLE code 858 * in XFree86 3.3 does. 859 * Also, the value itself is not one of the CMAP defines in nglehdw.h, 860 * but it's used in hyperResetPlanes() and does what we want. 861 * Then there are HYPER_CMAP* defines with yet another set of 862 * different values that aren't used anywhere. 863 */ 864 hyperfb_dba(sc, 865 BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINattr, 0)); 866 hyperfb_wait_fifo(sc, 5); 867 hyperfb_write4(sc, NGLE_IBO, 868 IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 1, 0)); 869 hyperfb_write4(sc, NGLE_CPR, 0x04000F00); 870 hyperfb_write4(sc, NGLE_TRANSFER_DATA, 0xffffffff); 871 hyperfb_write4(sc, NGLE_DST_XY, 0x00000000); 872 hyperfb_write4(sc, NGLE_RECT_SIZE_START, 873 (sc->sc_width << 16) | sc->sc_height); 874 /* 875 * blit into offscreen memory to force flush previous - apparently 876 * some chips have a bug this works around 877 */ 878 hyperfb_wait(sc); 879 hyperfb_write4(sc, NGLE_DST_XY, 0x05000000); 880 hyperfb_write4(sc, NGLE_RECT_SIZE_START, 0x00040001); 881 hyperfb_write4(sc, NGLE_CPR, 0x00000000); 882 hyperfb_wait(sc); 883 884 /* 885 * on 24bit-capable hardware we: 886 * - make overlay colour 255 transparent 887 * - blit the 24bit buffer all white 888 * - install a linear ramp in CMAP 0 889 */ 890 if (sc->sc_24bit) { 891 /* overlay transparency */ 892 hyperfb_dba(sc, 893 BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINovly, 0)); 894 hyperfb_wait_fifo(sc, 7); 895 hyperfb_write4(sc, NGLE_IBO, 896 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 897 0, 0)); //0x03000300 898 /* 899 * apparently the overlay transparency register lives at a 900 * magical location in the overlay plane, outside visible 901 * memory. Normal blits cut off beyond X 1280. 902 */ 903 hyperfb_write4(sc, NGLE_BINC_DST, 0x000017f0); 904 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 905 hyperfb_write4(sc, NGLE_BINC_MASK, 0xffffffff); 906 hyperfb_write4(sc, NGLE_BINC_DATA, 0x0); 907 908 hyperfb_wait(sc); 909 910 /* clear 24bit buffer */ 911 hyperfb_wait(sc); 912 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 913 hyperfb_write4(sc, NGLE_TRANSFER_DATA, 0xffffffff); 914 /* bitmap op */ 915 hyperfb_write4(sc, NGLE_IBO, 916 IBOvals(RopSrc, 0, BitmapExtent32, 0, DataDynamic, MaskOtc, 917 0, 0)); 918 /* dst bitmap access */ 919 hyperfb_dba(sc, 920 BA(FractDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0F8, 921 0)); 922 hyperfb_wait_fifo(sc, 3); 923 hyperfb_write4(sc, NGLE_FG, 0x00ffffff); 924 hyperfb_write4(sc, NGLE_DST_XY, 0x00000000); 925 hyperfb_write4(sc, NGLE_RECT_SIZE_START, 926 (sc->sc_width << 16) | sc->sc_height); 927 928 /* write a linear ramp into CMAP0 */ 929 hyperfb_both(sc, 930 BA(FractDcd, Otc01, Ots08, Addr24, 0, BINcmap, 0)); // 0xbbe0f000 931 hyperfb_wait_fifo(sc, 2); 932 hyperfb_write4(sc, NGLE_IBO, 933 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0)); // 0x03000300 934 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 935 936 hyperfb_wait(sc); 937 hyperfb_write4(sc, NGLE_BINC_DST, 0); 938 for (i = 0; i < 256; i++) { 939 hyperfb_wait(sc); 940 hyperfb_write4(sc, NGLE_BINC_DATA_R, 941 (i << 16) | (i << 8) | i); 942 } 943 hyperfb_write4(sc, NGLE_BINC_SRC, 0x0); 944 hyperfb_write4(sc, NGLE_HCRX_LUTBLT, 945 LBC_ENABLE | LBC_TYPE_CMAP | 0x100); 946 hyperfb_wait(sc); 947 } 948 949 /* cursor mask */ 950 hyperfb_wait(sc); 951 hyperfb_write4(sc, NGLE_HCRX_CURSOR_ADDR, 0); 952 for (i = 0; i < 64; i++) { 953 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, 0xffffffff); 954 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, 0xffffffff); 955 } 956 957 /* cursor image */ 958 hyperfb_wait(sc); 959 hyperfb_write4(sc, NGLE_HCRX_CURSOR_ADDR, 0x80); 960 for (i = 0; i < 64; i++) { 961 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, 0xff00ff00); 962 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, 0xff00ff00); 963 } 964 965 /* colour map */ 966 hyperfb_both(sc, BA(FractDcd, Otc01, Ots08, Addr24, 0, BINcmap, 0)); // 0xbbe0f000 967 hyperfb_wait_fifo(sc, 2); 968 hyperfb_write4(sc, NGLE_IBO, 969 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0)); // 0x03000300 970 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 971 hyperfb_wait(sc); 972 hyperfb_write4(sc, NGLE_BINC_DST, 0); 973 hyperfb_write4(sc, NGLE_BINC_DATA_R, 0x000000ff); /* BG */ 974 hyperfb_write4(sc, NGLE_BINC_DATA_R, 0x00ff0000); /* FG */ 975 hyperfb_wait(sc); 976 hyperfb_write4(sc, NGLE_BINC_SRC, 0); 977 hyperfb_write4(sc, NGLE_HCRX_LUTBLT, LBC_ENABLE | LBC_TYPE_CURSOR | 4); 978 hyperfb_wait(sc); 979 hyperfb_setup_fb(sc); 980 981 hyperfb_move_cursor(sc, 100, 100); 982 } 983 984 static void 985 hyperfb_set_video(struct hyperfb_softc *sc, int on) 986 { 987 uint32_t reg; 988 989 if (sc->sc_video_on == on) 990 return; 991 992 sc->sc_video_on = on; 993 994 hyperfb_wait(sc); 995 hyperfb_write4(sc, NGLE_HCRX_VBUS, 0); 996 reg = hyperfb_read4(sc, NGLE_HCRX_MISCVID); 997 998 if (on) { 999 hyperfb_write4(sc, NGLE_HCRX_MISCVID, reg | HCRX_VIDEO_ENABLE); 1000 } else { 1001 hyperfb_write4(sc, NGLE_HCRX_MISCVID, reg & ~HCRX_VIDEO_ENABLE); 1002 } 1003 /* 1004 * XXX 1005 * force writing BAboth, otherwise strange things happen here... 1006 */ 1007 sc->sc_sba = 0; 1008 hyperfb_setup_fb(sc); 1009 } 1010 1011 static inline void 1012 hyperfb_fillmode(struct hyperfb_softc *sc) 1013 { 1014 hyperfb_dba(sc, 1015 BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINovly, 0)); 1016 hyperfb_wait_fifo(sc, 4); 1017 hyperfb_write4(sc, NGLE_PLANEMASK, 0xff); 1018 hyperfb_write4(sc, NGLE_IBO, 1019 IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, 0, 0, 0)); 1020 hyperfb_fbflag(sc, 0); 1021 } 1022 1023 static void 1024 hyperfb_rectfill(struct hyperfb_softc *sc, int x, int y, int wi, int he, 1025 uint32_t bg) 1026 { 1027 1028 hyperfb_fillmode(sc); 1029 1030 hyperfb_wait_fifo(sc, 4); 1031 /* 1032 * XXX - the NGLE code calls this 'transfer data' 1033 * in reality it's a bit mask applied per pixel, 1034 * foreground colour in reg 35, bg in 36 1035 */ 1036 hyperfb_write4(sc, NGLE_TRANSFER_DATA, 0xffffffff); 1037 1038 hyperfb_write4(sc, NGLE_FG, bg); 1039 hyperfb_write4(sc, NGLE_DST_XY, (x << 16) | y); 1040 hyperfb_write4(sc, NGLE_RECT_SIZE_START, (wi << 16) | he); 1041 } 1042 1043 static void 1044 hyperfb_rectfill_a(void *cookie, int dstx, int dsty, 1045 int width, int height, long attr) 1046 { 1047 struct hyperfb_softc *sc = cookie; 1048 1049 hyperfb_rectfill(sc, dstx, dsty, width, height, 1050 sc->vd.active->scr_ri.ri_devcmap[(attr >> 24 & 0xf)]); 1051 } 1052 1053 static void 1054 hyperfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, 1055 int he, int rop) 1056 { 1057 struct hyperfb_softc *sc = cookie; 1058 1059 if (ys > 1023) { 1060 hyperfb_sba(sc, BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINapp0I, 0)); 1061 ys -= 1024; 1062 } else 1063 hyperfb_sba(sc, BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINovly, 0)); 1064 if (yd > 1023) { 1065 hyperfb_dba(sc, BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINapp0I, 0)); 1066 yd -= 1024; 1067 } else 1068 hyperfb_dba(sc, BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINovly, 0)); 1069 hyperfb_wait_fifo(sc, 6); 1070 hyperfb_fbflag(sc, 0); 1071 hyperfb_write4(sc, NGLE_PLANEMASK, 0xff); 1072 hyperfb_write4(sc, NGLE_IBO, ((rop << 8) & 0xf00) | 0x23000000); 1073 /* IBOvals(rop, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 0, 0) */ 1074 hyperfb_write4(sc, NGLE_SRC_XY, (xs << 16) | ys); 1075 hyperfb_write4(sc, NGLE_SIZE, (wi << 16) | he); 1076 hyperfb_write4(sc, NGLE_BLT_DST_START, (xd << 16) | yd); 1077 } 1078 1079 static void 1080 hyperfb_nuke_cursor(struct rasops_info *ri) 1081 { 1082 struct vcons_screen *scr = ri->ri_hw; 1083 struct hyperfb_softc *sc = scr->scr_cookie; 1084 int wi, he, x, y; 1085 1086 if (ri->ri_flg & RI_CURSOR) { 1087 wi = ri->ri_font->fontwidth; 1088 he = ri->ri_font->fontheight; 1089 x = ri->ri_ccol * wi + ri->ri_xorigin; 1090 y = ri->ri_crow * he + ri->ri_yorigin; 1091 hyperfb_bitblt(sc, x, y, x, y, wi, he, RopInv); 1092 ri->ri_flg &= ~RI_CURSOR; 1093 } 1094 } 1095 1096 static void 1097 hyperfb_cursor(void *cookie, int on, int row, int col) 1098 { 1099 struct rasops_info *ri = cookie; 1100 struct vcons_screen *scr = ri->ri_hw; 1101 struct hyperfb_softc *sc = scr->scr_cookie; 1102 int x, y, wi, he; 1103 1104 wi = ri->ri_font->fontwidth; 1105 he = ri->ri_font->fontheight; 1106 1107 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1108 if (on) { 1109 if (ri->ri_flg & RI_CURSOR) { 1110 hyperfb_nuke_cursor(ri); 1111 } 1112 x = col * wi + ri->ri_xorigin; 1113 y = row * he + ri->ri_yorigin; 1114 hyperfb_bitblt(sc, x, y, x, y, wi, he, RopInv); 1115 ri->ri_flg |= RI_CURSOR; 1116 } 1117 ri->ri_crow = row; 1118 ri->ri_ccol = col; 1119 } else { 1120 ri->ri_crow = row; 1121 ri->ri_ccol = col; 1122 ri->ri_flg &= ~RI_CURSOR; 1123 } 1124 } 1125 1126 static void 1127 hyperfb_putchar(void *cookie, int row, int col, u_int c, long attr) 1128 { 1129 struct rasops_info *ri = cookie; 1130 struct wsdisplay_font *font = PICK_FONT(ri, c); 1131 struct vcons_screen *scr = ri->ri_hw; 1132 struct hyperfb_softc *sc = scr->scr_cookie; 1133 void *data; 1134 int i, x, y, wi, he; 1135 uint32_t bg, fg, mask, cmask; 1136 1137 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1138 return; 1139 1140 if (!CHAR_IN_FONT(c, font)) 1141 return; 1142 1143 if (row == ri->ri_crow && col == ri->ri_ccol) { 1144 ri->ri_flg &= ~RI_CURSOR; 1145 } 1146 1147 wi = font->fontwidth; 1148 he = font->fontheight; 1149 1150 x = ri->ri_xorigin + col * wi; 1151 y = ri->ri_yorigin + row * he; 1152 1153 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1154 fg = ri->ri_devcmap[(attr >> 24) & 0x0f]; 1155 1156 1157 /* if we're drawing a space we're done here */ 1158 if (c == 0x20) { 1159 /* clear the character cell */ 1160 hyperfb_rectfill(sc, x, y, wi, he, bg); 1161 if (attr & WSATTR_UNDERLINE) 1162 hyperfb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1163 return; 1164 } 1165 1166 data = WSFONT_GLYPH(c, font); 1167 1168 hyperfb_fillmode(sc); 1169 1170 hyperfb_wait_fifo(sc, 4); 1171 1172 /* character colour */ 1173 hyperfb_write4(sc, NGLE_FG, fg); 1174 hyperfb_write4(sc, NGLE_BG, bg); 1175 /* pixel address in 32bit since we're in AddrLong mode */ 1176 hyperfb_write4(sc, NGLE_BINC_DST, (x << 2) | (y << 13)); 1177 /* make a mask covering the character width */ 1178 cmask = 0xffffffff << (32 - wi); 1179 hyperfb_write4(sc, NGLE_BINC_MASK, cmask); 1180 /* 1181 * ...and now we hammer pixel data into BINC, moving down. 1182 * Unlike FX, we *can* overrun the pipeline with BINC writes, 1183 * especially with colour expansion while scrolling. 1184 * HCRX seems to have a 32 entry pipeline, let's assume we won't 1185 * encounter fonts taller than that for now... 1186 */ 1187 if (he > 31) { 1188 hyperfb_wait(sc); 1189 } else 1190 hyperfb_wait_fifo(sc, he); 1191 1192 if (attr & WSATTR_HILIT) { 1193 if (ri->ri_font->stride == 1) { 1194 uint8_t *data8 = data; 1195 for (i = 0; i < he; i++) { 1196 mask = *data8; 1197 mask |= mask >> 1; 1198 hyperfb_write4(sc, NGLE_BINC_DATA_D, mask << 24); 1199 data8++; 1200 } 1201 } else { 1202 uint16_t *data16 = data; 1203 for (i = 0; i < he; i++) { 1204 mask = *data16; 1205 mask |= mask >> 1; 1206 hyperfb_write4(sc, NGLE_BINC_DATA_D, mask << 16); 1207 data16++; 1208 } 1209 } 1210 } else { 1211 if (ri->ri_font->stride == 1) { 1212 uint8_t *data8 = data; 1213 for (i = 0; i < he; i++) { 1214 mask = *data8; 1215 hyperfb_write4(sc, NGLE_BINC_DATA_D, mask << 24); 1216 data8++; 1217 } 1218 } else { 1219 uint16_t *data16 = data; 1220 for (i = 0; i < he; i++) { 1221 mask = *data16; 1222 hyperfb_write4(sc, NGLE_BINC_DATA_D, mask << 16); 1223 data16++; 1224 } 1225 } 1226 } 1227 if (attr & WSATTR_UNDERLINE) { 1228 hyperfb_wait_fifo(sc, 2); 1229 hyperfb_write4(sc, NGLE_BINC_DST, 1230 (x << 2) | ((y + he - 2) << 13)); 1231 hyperfb_write4(sc, NGLE_BINC_DATA_D, cmask); 1232 } 1233 } 1234 1235 static void 1236 hyperfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1237 { 1238 struct rasops_info *ri = cookie; 1239 struct wsdisplay_font *font = PICK_FONT(ri, c); 1240 struct vcons_screen *scr = ri->ri_hw; 1241 struct hyperfb_softc *sc = scr->scr_cookie; 1242 int x, y, wi, he, rv = GC_NOPE; 1243 uint32_t bg; 1244 uint32_t latch = 0, bg8, fg8, pixel, mask; 1245 int i, line, r, g, b, aval; 1246 int r1, g1, b1, r0, g0, b0, fgo, bgo; 1247 uint8_t *data8; 1248 1249 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1250 return; 1251 1252 if (!CHAR_IN_FONT(c, font)) 1253 return; 1254 1255 if (row == ri->ri_crow && col == ri->ri_ccol) { 1256 ri->ri_flg &= ~RI_CURSOR; 1257 } 1258 1259 wi = font->fontwidth; 1260 he = font->fontheight; 1261 1262 x = ri->ri_xorigin + col * wi; 1263 y = ri->ri_yorigin + row * he; 1264 1265 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1266 1267 if (c == 0x20) { 1268 hyperfb_rectfill(sc, x, y, wi, he, bg); 1269 if (attr & WSATTR_UNDERLINE) 1270 glyphcache_underline(&sc->sc_gc, x, y, attr); 1271 return; 1272 } 1273 1274 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1275 if (rv == GC_OK) 1276 return; 1277 1278 hyperfb_dba(sc, BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINovly, 0)); 1279 hyperfb_wait_fifo(sc, 6); 1280 hyperfb_fbflag(sc, 0); 1281 hyperfb_write4(sc, NGLE_PLANEMASK, 0xff); 1282 hyperfb_write4(sc, NGLE_IBO, 1283 IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 0, 0)); 1284 1285 /* 1286 * we need the RGB colours here, so get offsets into rasops_cmap 1287 */ 1288 fgo = ((attr >> 24) & 0xf) * 3; 1289 bgo = ((attr >> 16) & 0xf) * 3; 1290 1291 r0 = rasops_cmap[bgo]; 1292 r1 = rasops_cmap[fgo]; 1293 g0 = rasops_cmap[bgo + 1]; 1294 g1 = rasops_cmap[fgo + 1]; 1295 b0 = rasops_cmap[bgo + 2]; 1296 b1 = rasops_cmap[fgo + 2]; 1297 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 1298 bg8 = R3G3B2(r0, g0, b0); 1299 fg8 = R3G3B2(r1, g1, b1); 1300 1301 /* 1302 * This is for masking off pixels at the end of a line if it's not a 1303 * multiple of 4. Would be nice if we knew where the clipping registers 1304 * live... 1305 */ 1306 mask = 0xf0000000 << (4 - (wi & 3)); 1307 1308 data8 = WSFONT_GLYPH(c, font); 1309 1310 for (line = 0; line < he; line++) { 1311 /* setup BINC write */ 1312 hyperfb_wait_fifo(sc, wi / 2); 1313 hyperfb_write4(sc, NGLE_BINC_DST, (x << 2) | ((y + line) << 13)); 1314 hyperfb_write4(sc, NGLE_BINC_MASK, 0xffffffff); 1315 for (i = 0; i < wi; i++) { 1316 aval = *data8; 1317 if (aval == 0) { 1318 pixel = bg8; 1319 } else if (aval == 255) { 1320 pixel = fg8; 1321 } else { 1322 r = aval * r1 + (255 - aval) * r0; 1323 g = aval * g1 + (255 - aval) * g0; 1324 b = aval * b1 + (255 - aval) * b0; 1325 pixel = ((r & 0xe000) >> 8) | 1326 ((g & 0xe000) >> 11) | 1327 ((b & 0xc000) >> 14); 1328 } 1329 latch = (latch << 8) | pixel; 1330 /* write in 32bit chunks */ 1331 if ((i & 3) == 3) { 1332 hyperfb_write4(sc, NGLE_BINC_DATA_R, latch); 1333 latch = 0; 1334 } 1335 data8++; 1336 } 1337 /* if we have pixels left in latch write them out */ 1338 if ((i & 3) != 0) { 1339 latch = latch << ((4 - (i & 3)) << 3); 1340 /* make sure we write only the pixels in the latch */ 1341 hyperfb_write4(sc, NGLE_BINC_MASK, mask); 1342 hyperfb_write4(sc, NGLE_BINC_DATA_R, latch); 1343 } 1344 } 1345 1346 if (rv == GC_ADD) 1347 glyphcache_add(&sc->sc_gc, c, x, y); 1348 if (attr & WSATTR_UNDERLINE) 1349 glyphcache_underline(&sc->sc_gc, x, y, attr); 1350 } 1351 1352 static int 1353 hyperfb_allocattr(void *cookie, int fg0, int bg0, int flg, long *attr) 1354 { 1355 struct rasops_info *ri = cookie; 1356 int fg = fg0, bg = bg0; 1357 1358 if ((flg & WSATTR_BLINK) != 0) 1359 return EINVAL; 1360 1361 if ((flg & WSATTR_REVERSE) != 0) { 1362 fg = bg0; 1363 bg = fg0; 1364 } 1365 1366 if (FONT_IS_ALPHA(ri->ri_font) && ((flg & WSATTR_HILIT) != 0)) { 1367 fg = fg0 < 8 ? fg0 + 8 : fg0; 1368 } 1369 1370 *attr = (bg << 16) | (fg << 24) | flg; 1371 return 0; 1372 } 1373 1374 static void 1375 hyperfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1376 { 1377 struct rasops_info *ri = cookie; 1378 struct vcons_screen *scr = ri->ri_hw; 1379 struct hyperfb_softc *sc = scr->scr_cookie; 1380 int32_t xs, xd, y, width, height; 1381 1382 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1383 if (ri->ri_crow == row && 1384 (ri->ri_ccol >= srccol && ri->ri_ccol < (srccol + ncols)) && 1385 (ri->ri_flg & RI_CURSOR)) { 1386 hyperfb_nuke_cursor(ri); 1387 } 1388 1389 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1390 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1391 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1392 width = ri->ri_font->fontwidth * ncols; 1393 height = ri->ri_font->fontheight; 1394 hyperfb_bitblt(sc, xs, y, xd, y, width, height, RopSrc); 1395 if (ri->ri_crow == row && 1396 (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols))) 1397 ri->ri_flg &= ~RI_CURSOR; 1398 } 1399 } 1400 1401 static void 1402 hyperfb_erasecols(void *cookie, int row, int startcol, int ncols, 1403 long fillattr) 1404 { 1405 struct rasops_info *ri = cookie; 1406 struct vcons_screen *scr = ri->ri_hw; 1407 struct hyperfb_softc *sc = scr->scr_cookie; 1408 int32_t x, y, width, height, fg, bg, ul; 1409 1410 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1411 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1412 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1413 width = ri->ri_font->fontwidth * ncols; 1414 height = ri->ri_font->fontheight; 1415 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1416 1417 hyperfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1418 if (ri->ri_crow == row && 1419 (ri->ri_ccol >= startcol && 1420 ri->ri_ccol < (startcol + ncols))) 1421 ri->ri_flg &= ~RI_CURSOR; 1422 } 1423 } 1424 1425 static void 1426 hyperfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1427 { 1428 struct rasops_info *ri = cookie; 1429 struct vcons_screen *scr = ri->ri_hw; 1430 struct hyperfb_softc *sc = scr->scr_cookie; 1431 int32_t x, ys, yd, width, height; 1432 1433 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1434 if ((ri->ri_crow >= srcrow && 1435 ri->ri_crow < (srcrow + nrows)) && 1436 (ri->ri_flg & RI_CURSOR)) { 1437 hyperfb_nuke_cursor(ri); 1438 } 1439 x = ri->ri_xorigin; 1440 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1441 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1442 width = ri->ri_emuwidth; 1443 height = ri->ri_font->fontheight * nrows; 1444 hyperfb_bitblt(sc, x, ys, x, yd, width, height, RopSrc); 1445 if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows)) 1446 ri->ri_flg &= ~RI_CURSOR; 1447 } 1448 } 1449 1450 static void 1451 hyperfb_eraserows(void *cookie, int row, int nrows, long fillattr) 1452 { 1453 struct rasops_info *ri = cookie; 1454 struct vcons_screen *scr = ri->ri_hw; 1455 struct hyperfb_softc *sc = scr->scr_cookie; 1456 int32_t x, y, width, height, fg, bg, ul; 1457 1458 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1459 if (row == 0 && nrows == ri->ri_rows) { 1460 x = 0; 1461 y = 0; 1462 width = sc->sc_width; 1463 height = sc->sc_height; 1464 } else { 1465 x = ri->ri_xorigin; 1466 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1467 width = ri->ri_emuwidth; 1468 height = ri->ri_font->fontheight * nrows; 1469 } 1470 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1471 1472 hyperfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1473 1474 if (ri->ri_crow >= row && ri->ri_crow < (row + nrows)) 1475 ri->ri_flg &= ~RI_CURSOR; 1476 } 1477 } 1478 1479 static void 1480 hyperfb_move_cursor(struct hyperfb_softc *sc, int x, int y) 1481 { 1482 uint32_t pos; 1483 1484 sc->sc_cursor_x = x; 1485 x -= sc->sc_hot_x; 1486 sc->sc_cursor_y = y; 1487 y -= sc->sc_hot_y; 1488 1489 if (x < 0) x = 0x1000 - x; 1490 if (y < 0) y = 0x1000 - y; 1491 pos = (x << 16) | y; 1492 if (sc->sc_enabled) pos |= HCRX_ENABLE_CURSOR; 1493 hyperfb_wait_fifo(sc, 2); 1494 hyperfb_write4(sc, NGLE_HCRX_VBUS, 0); 1495 hyperfb_write4(sc, NGLE_HCRX_CURSOR, pos); 1496 } 1497 1498 static int 1499 hyperfb_do_cursor(struct hyperfb_softc *sc, struct wsdisplay_cursor *cur) 1500 { 1501 1502 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 1503 1504 sc->sc_enabled = cur->enable; 1505 cur->which |= WSDISPLAY_CURSOR_DOPOS; 1506 } 1507 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 1508 1509 sc->sc_hot_x = cur->hot.x; 1510 sc->sc_hot_y = cur->hot.y; 1511 cur->which |= WSDISPLAY_CURSOR_DOPOS; 1512 } 1513 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 1514 1515 hyperfb_move_cursor(sc, cur->pos.x, cur->pos.y); 1516 } 1517 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 1518 uint32_t rgb; 1519 uint8_t r[2], g[2], b[2]; 1520 1521 copyin(cur->cmap.blue, b, 2); 1522 copyin(cur->cmap.green, g, 2); 1523 copyin(cur->cmap.red, r, 2); 1524 mutex_enter(&sc->sc_hwlock); 1525 hyperfb_sba(sc, 1526 BA(FractDcd, Otc01, Ots08, Addr24, 0, BINcmap, 0)); // 0xbbe0f000 1527 hyperfb_dba(sc, 1528 BA(FractDcd, Otc01, Ots08, Addr24, 0, BINcmap, 0)); // 0xbbe0f000 1529 hyperfb_wait_fifo(sc, 2); 1530 hyperfb_write4(sc, NGLE_IBO, 1531 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0)); // 0x03000300 1532 hyperfb_write4(sc, NGLE_PLANEMASK, 0xffffffff); 1533 hyperfb_wait(sc); 1534 hyperfb_write4(sc, NGLE_BINC_DST, 0); 1535 rgb = (r[0] << 16) | (g[0] << 8) | b[0]; 1536 hyperfb_write4(sc, NGLE_BINC_DATA_R, rgb); /* BG */ 1537 rgb = (r[1] << 16) | (g[1] << 8) | b[1]; 1538 hyperfb_write4(sc, NGLE_BINC_DATA_R, rgb); /* FG */ 1539 hyperfb_write4(sc, NGLE_BINC_SRC, 0); 1540 hyperfb_write4(sc, NGLE_HCRX_LUTBLT, 1541 LBC_ENABLE | LBC_TYPE_CURSOR | 4); 1542 1543 hyperfb_setup_fb(sc); 1544 mutex_exit(&sc->sc_hwlock); 1545 } 1546 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 1547 uint32_t buffer[128], latch, tmp; 1548 int i; 1549 1550 copyin(cur->mask, buffer, 512); 1551 hyperfb_wait(sc); 1552 hyperfb_write4(sc, NGLE_HCRX_CURSOR_ADDR, 0); 1553 for (i = 0; i < 128; i += 2) { 1554 latch = 0; 1555 tmp = buffer[i] & 0x80808080; 1556 latch |= tmp >> 7; 1557 tmp = buffer[i] & 0x40404040; 1558 latch |= tmp >> 5; 1559 tmp = buffer[i] & 0x20202020; 1560 latch |= tmp >> 3; 1561 tmp = buffer[i] & 0x10101010; 1562 latch |= tmp >> 1; 1563 tmp = buffer[i] & 0x08080808; 1564 latch |= tmp << 1; 1565 tmp = buffer[i] & 0x04040404; 1566 latch |= tmp << 3; 1567 tmp = buffer[i] & 0x02020202; 1568 latch |= tmp << 5; 1569 tmp = buffer[i] & 0x01010101; 1570 latch |= tmp << 7; 1571 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, latch); 1572 latch = 0; 1573 tmp = buffer[i + 1] & 0x80808080; 1574 latch |= tmp >> 7; 1575 tmp = buffer[i + 1] & 0x40404040; 1576 latch |= tmp >> 5; 1577 tmp = buffer[i + 1] & 0x20202020; 1578 latch |= tmp >> 3; 1579 tmp = buffer[i + 1] & 0x10101010; 1580 latch |= tmp >> 1; 1581 tmp = buffer[i + 1] & 0x08080808; 1582 latch |= tmp << 1; 1583 tmp = buffer[i + 1] & 0x04040404; 1584 latch |= tmp << 3; 1585 tmp = buffer[i + 1] & 0x02020202; 1586 latch |= tmp << 5; 1587 tmp = buffer[i + 1] & 0x01010101; 1588 latch |= tmp << 7; 1589 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, latch); 1590 } 1591 1592 copyin(cur->image, buffer, 512); 1593 hyperfb_wait(sc); 1594 hyperfb_write4(sc, NGLE_HCRX_CURSOR_ADDR, 0x80); 1595 for (i = 0; i < 128; i += 2) { 1596 latch = 0; 1597 tmp = buffer[i] & 0x80808080; 1598 latch |= tmp >> 7; 1599 tmp = buffer[i] & 0x40404040; 1600 latch |= tmp >> 5; 1601 tmp = buffer[i] & 0x20202020; 1602 latch |= tmp >> 3; 1603 tmp = buffer[i] & 0x10101010; 1604 latch |= tmp >> 1; 1605 tmp = buffer[i] & 0x08080808; 1606 latch |= tmp << 1; 1607 tmp = buffer[i] & 0x04040404; 1608 latch |= tmp << 3; 1609 tmp = buffer[i] & 0x02020202; 1610 latch |= tmp << 5; 1611 tmp = buffer[i] & 0x01010101; 1612 latch |= tmp << 7; 1613 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, latch); 1614 latch = 0; 1615 tmp = buffer[i + 1] & 0x80808080; 1616 latch |= tmp >> 7; 1617 tmp = buffer[i + 1] & 0x40404040; 1618 latch |= tmp >> 5; 1619 tmp = buffer[i + 1] & 0x20202020; 1620 latch |= tmp >> 3; 1621 tmp = buffer[i + 1] & 0x10101010; 1622 latch |= tmp >> 1; 1623 tmp = buffer[i + 1] & 0x08080808; 1624 latch |= tmp << 1; 1625 tmp = buffer[i + 1] & 0x04040404; 1626 latch |= tmp << 3; 1627 tmp = buffer[i + 1] & 0x02020202; 1628 latch |= tmp << 5; 1629 tmp = buffer[i + 1] & 0x01010101; 1630 latch |= tmp << 7; 1631 hyperfb_write4(sc, NGLE_HCRX_CURSOR_DATA, latch); 1632 } 1633 hyperfb_setup_fb(sc); 1634 } 1635 1636 return 0; 1637 } 1638