1 /* $NetBSD: tcx.c,v 1.69 2026/07/07 09:11:31 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1998, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg and Michael Lorenz. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * color display (TCX) driver. 34 * 35 * Does not handle interrupts, even though they can occur. 36 * 37 * XXX should defer colormap updates to vertical retrace interrupts 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: tcx.c,v 1.69 2026/07/07 09:11:31 macallan Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/buf.h> 46 #include <sys/device.h> 47 #include <sys/ioctl.h> 48 #include <sys/mman.h> 49 #include <sys/tty.h> 50 #include <sys/conf.h> 51 52 #ifdef DEBUG 53 #include <sys/proc.h> 54 #include <sys/syslog.h> 55 #endif 56 57 #include <sys/bus.h> 58 #include <machine/autoconf.h> 59 60 #include <dev/sun/fbio.h> 61 #include <dev/sun/fbvar.h> 62 #include <dev/sun/btreg.h> 63 #include <dev/sun/btvar.h> 64 65 #include <dev/sbus/sbusvar.h> 66 #include <dev/sbus/tcxreg.h> 67 68 #include <dev/wscons/wsdisplayvar.h> 69 #include <dev/wscons/wsconsio.h> 70 #include <dev/wsfont/wsfont.h> 71 #include <dev/rasops/rasops.h> 72 73 #include <dev/wscons/wsdisplay_vconsvar.h> 74 75 #include "opt_wsemul.h" 76 77 #include "ioconf.h" 78 79 /* per-display variables */ 80 struct tcx_softc { 81 device_t sc_dev; /* base device */ 82 struct fbdevice sc_fb; /* frame buffer device */ 83 bus_space_tag_t sc_bustag; 84 struct openprom_addr sc_physaddr[TCX_NREG];/* phys addr of h/w */ 85 86 bus_space_handle_t sc_bt; /* Brooktree registers */ 87 bus_space_handle_t sc_thc; /* THC registers */ 88 uint8_t *sc_fbaddr; /* framebuffer */ 89 volatile uint64_t *sc_rblit; /* blitspace */ 90 volatile uint64_t *sc_rstip; /* stipple space */ 91 92 short sc_8bit; /* true if 8-bit hardware */ 93 short sc_blanked; /* true if blanked */ 94 uint32_t sc_fbsize; /* size of the 8bit fb */ 95 int sc_depth; /* depth of the fb we mmap() */ 96 u_char sc_cmap_red[256]; 97 u_char sc_cmap_green[256]; 98 u_char sc_cmap_blue[256]; 99 int sc_mode, sc_bg; 100 int sc_cursor_x, sc_cursor_y; 101 int sc_hotspot_x, sc_hotspot_y; 102 struct vcons_data vd; 103 }; 104 105 static struct vcons_screen tcx_console_screen; 106 107 extern const u_char rasops_cmap[768]; 108 109 struct wsscreen_descr tcx_defscreendesc = { 110 "default", 111 0, 0, 112 NULL, 113 8, 16, 114 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 115 WSSCREEN_REVERSE | WSSCREEN_RESIZE, 116 }; 117 118 const struct wsscreen_descr *_tcx_scrlist[] = { 119 &tcx_defscreendesc, 120 /* XXX other formats, graphics screen? */ 121 }; 122 123 struct wsscreen_list tcx_screenlist = { 124 sizeof(_tcx_scrlist) / sizeof(struct wsscreen_descr *), 125 _tcx_scrlist 126 }; 127 128 /* autoconfiguration driver */ 129 static void tcxattach(device_t, device_t, void *); 130 static int tcxmatch(device_t, cfdata_t, void *); 131 static void tcx_unblank(device_t); 132 133 CFATTACH_DECL_NEW(tcx, sizeof(struct tcx_softc), 134 tcxmatch, tcxattach, NULL, NULL); 135 136 dev_type_open(tcxopen); 137 dev_type_close(tcxclose); 138 dev_type_ioctl(tcxioctl); 139 dev_type_mmap(tcxmmap); 140 141 const struct cdevsw tcx_cdevsw = { 142 .d_open = tcxopen, 143 .d_close = tcxclose, 144 .d_read = noread, 145 .d_write = nowrite, 146 .d_ioctl = tcxioctl, 147 .d_stop = nostop, 148 .d_tty = notty, 149 .d_poll = nopoll, 150 .d_mmap = tcxmmap, 151 .d_kqfilter = nokqfilter, 152 .d_discard = nodiscard, 153 .d_flag = 0 154 }; 155 156 /* frame buffer generic driver */ 157 static struct fbdriver tcx_fbdriver = { 158 tcx_unblank, tcxopen, tcxclose, tcxioctl, nopoll, tcxmmap, 159 nokqfilter 160 }; 161 162 static void tcx_reset(struct tcx_softc *); 163 static void tcx_loadcmap(struct tcx_softc *, int, int); 164 165 static int tcx_ioctl(void *, void *, u_long, void *, int, struct lwp *); 166 static paddr_t tcx_mmap(void *, void *, off_t, int); 167 168 static void tcx_init_cmap(struct tcx_softc *); 169 static void tcx_init_screen(void *, struct vcons_screen *, int, long *); 170 static void tcx_clearscreen(struct tcx_softc *, int); 171 static void tcx_copyrows(void *, int, int, int); 172 static void tcx_eraserows(void *, int, int, long); 173 static void tcx_erasecols(void *, int, int, int, long); 174 static void tcx_putchar(void *, int, int, u_int, long); 175 static int tcx_allocattr(void *, int, int, int, long *); 176 177 static void tcx_set_video(struct tcx_softc *, int); 178 static int tcx_do_cursor(struct tcx_softc *, struct wsdisplay_cursor *); 179 static void tcx_set_cursor(struct tcx_softc *); 180 181 struct wsdisplay_accessops tcx_accessops = { 182 tcx_ioctl, 183 tcx_mmap, 184 NULL, /* vcons_alloc_screen */ 185 NULL, /* vcons_free_screen */ 186 NULL, /* vcons_show_screen */ 187 NULL, /* load_font */ 188 NULL, /* polls */ 189 NULL, /* scroll */ 190 }; 191 192 #define OBPNAME "SUNW,tcx" 193 194 /* 195 * Match a tcx. 196 */ 197 int 198 tcxmatch(device_t parent, cfdata_t cf, void *aux) 199 { 200 struct sbus_attach_args *sa = aux; 201 202 if (strcmp(sa->sa_name, OBPNAME) == 0) 203 return 100; /* beat genfb */ 204 return 0; 205 } 206 207 /* 208 * Attach a display. 209 */ 210 void 211 tcxattach(device_t parent, device_t self, void *args) 212 { 213 struct tcx_softc *sc = device_private(self); 214 struct sbus_attach_args *sa = args; 215 struct wsemuldisplaydev_attach_args aa; 216 struct rasops_info *ri; 217 unsigned long defattr; 218 int node; 219 struct fbdevice *fb = &sc->sc_fb; 220 bus_space_handle_t bh; 221 int isconsole; 222 uint32_t confreg; 223 224 sc->sc_dev = self; 225 sc->sc_bustag = sa->sa_bustag; 226 node = sa->sa_node; 227 228 sc->sc_cursor_x = 0x7fff; 229 sc->sc_cursor_y = 0x7fff; 230 sc->sc_hotspot_x = 0; 231 sc->sc_hotspot_y = 0; 232 233 fb->fb_driver = &tcx_fbdriver; 234 fb->fb_device = sc->sc_dev; 235 /* Mask out invalid flags from the user. */ 236 fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK; 237 /* 238 * The onboard framebuffer on the SS4 supports only 8-bit mode; 239 * it can be distinguished from the S24 card for the SS5 by the 240 * presence of the "tcx-8-bit" attribute on the SS4 version. 241 */ 242 sc->sc_8bit = node_has_property(node, "tcx-8-bit"); 243 fb->fb_type.fb_depth = 8; 244 fb_setsize_obp(fb, fb->fb_type.fb_depth, 1152, 900, node); 245 246 /* 247 * actual FB size ( of the 8bit region ) 248 * no reason to restrict userland mappings to the visible VRAM 249 */ 250 if (sc->sc_8bit) { 251 aprint_normal(" (8-bit only TCX)\n"); 252 /* at least the SS4 can have 2MB with a VSIMM */ 253 sc->sc_fbsize = 0x100000 * prom_getpropint(node, "vram", 1); 254 sc->sc_depth = 8; 255 } else { 256 aprint_normal(" (S24)\n"); 257 /* all S24 I know of have 4MB, non-expandable */ 258 sc->sc_fbsize = 0x100000; 259 sc->sc_depth = 32; 260 } 261 262 fb->fb_type.fb_cmsize = 256; 263 fb->fb_type.fb_size = sc->sc_fbsize; /* later code assumes 8bit */ 264 aprint_normal_dev(self, "%s, %d x %d\n", OBPNAME, 265 fb->fb_type.fb_width, 266 fb->fb_type.fb_height); 267 268 fb->fb_type.fb_type = FBTYPE_TCXCOLOR; 269 270 if (sa->sa_nreg != TCX_NREG) { 271 aprint_error("\n"); 272 aprint_error_dev(self, "only %d register sets\n", 273 sa->sa_nreg); 274 return; 275 } 276 if (sa->sa_reg[TCX_REG_STIP].oa_size < 0x1000) { 277 aprint_error("\n"); 278 aprint_error_dev(self, "STIP register too small (0x%x)\n", 279 sa->sa_reg[TCX_REG_STIP].oa_size); 280 return; 281 } 282 283 memcpy(sc->sc_physaddr, sa->sa_reg, 284 sa->sa_nreg * sizeof(struct openprom_addr)); 285 286 /* Map the register banks we care about */ 287 if (sbus_bus_map(sa->sa_bustag, 288 sc->sc_physaddr[TCX_REG_THC].oa_space, 289 sc->sc_physaddr[TCX_REG_THC].oa_base, 290 0x1000, 291 BUS_SPACE_MAP_LINEAR, &sc->sc_thc) != 0) { 292 aprint_error_dev(self, 293 "tcxattach: cannot map thc registers\n"); 294 return; 295 } 296 297 if (sbus_bus_map(sa->sa_bustag, 298 sc->sc_physaddr[TCX_REG_CMAP].oa_space, 299 sc->sc_physaddr[TCX_REG_CMAP].oa_base, 300 0x1000, 301 BUS_SPACE_MAP_LINEAR, &sc->sc_bt) != 0) { 302 aprint_error_dev(self, "tcxattach: cannot map DAC registers\n"); 303 return; 304 } 305 306 /* map the 8bit dumb FB for the console */ 307 if (sbus_bus_map(sa->sa_bustag, 308 sc->sc_physaddr[TCX_REG_DFB8].oa_space, 309 sc->sc_physaddr[TCX_REG_DFB8].oa_base, 310 sc->sc_fbsize, 311 BUS_SPACE_MAP_LINEAR, 312 &bh) != 0) { 313 aprint_error_dev(self, "tcxattach: cannot map framebuffer\n"); 314 return; 315 } 316 sc->sc_fbaddr = bus_space_vaddr(sa->sa_bustag, bh); 317 318 /* 319 * 8bit tcx has the RSTIP and RBLIT ranges set to size 0. 320 * On Real Hardware they work anyway ( on my SS4 at least ) but 321 * emulators may not be so forgiving. 322 */ 323 if (sc->sc_8bit) { 324 /* BLIT space */ 325 if (sbus_bus_map(sa->sa_bustag, 326 sc->sc_physaddr[TCX_REG_BLIT].oa_space, 327 sc->sc_physaddr[TCX_REG_BLIT].oa_base, 328 sc->sc_fbsize << 3, 329 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 330 &bh) != 0) { 331 aprint_error_dev(self, 332 "tcxattach: cannot map BLIT space\n"); 333 return; 334 } 335 sc->sc_rblit = bus_space_vaddr(sa->sa_bustag, bh); 336 337 /* STIP space */ 338 if (sbus_bus_map(sa->sa_bustag, 339 sc->sc_physaddr[TCX_REG_STIP].oa_space, 340 sc->sc_physaddr[TCX_REG_STIP].oa_base, 341 sc->sc_fbsize << 3, 342 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 343 &bh) != 0) { 344 aprint_error_dev(self, 345 "tcxattach: cannot map STIP space\n"); 346 return; 347 } 348 sc->sc_rstip = bus_space_vaddr(sa->sa_bustag, bh); 349 } else { 350 /* RBLIT space */ 351 if (sbus_bus_map(sa->sa_bustag, 352 sc->sc_physaddr[TCX_REG_RBLIT].oa_space, 353 sc->sc_physaddr[TCX_REG_RBLIT].oa_base, 354 sc->sc_fbsize << 3, 355 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 356 &bh) != 0) { 357 aprint_error_dev(self, 358 "tcxattach: cannot map RBLIT space\n"); 359 return; 360 } 361 sc->sc_rblit = bus_space_vaddr(sa->sa_bustag, bh); 362 363 /* RSTIP space */ 364 if (sbus_bus_map(sa->sa_bustag, 365 sc->sc_physaddr[TCX_REG_RSTIP].oa_space, 366 sc->sc_physaddr[TCX_REG_RSTIP].oa_base, 367 sc->sc_fbsize << 3, 368 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 369 &bh) != 0) { 370 aprint_error_dev(self, 371 "tcxattach: cannot map RSTIP space\n"); 372 return; 373 } 374 sc->sc_rstip = bus_space_vaddr(sa->sa_bustag, bh); 375 } 376 isconsole = fb_is_console(node); 377 378 confreg = bus_space_read_4(sa->sa_bustag, sc->sc_thc, THC_CONFIG); 379 aprint_normal_dev(self, "id %d, rev %d, sense %d\n", 380 (confreg & THC_CFG_FBID) >> THC_CFG_FBID_SHIFT, 381 (confreg & THC_CFG_REV) >> THC_CFG_REV_SHIFT, 382 (confreg & THC_CFG_SENSE) >> THC_CFG_SENSE_SHIFT 383 ); 384 385 /* reset cursor & frame buffer controls */ 386 tcx_reset(sc); 387 388 if (!sc->sc_8bit) 389 tcx_set_cursor(sc); 390 391 /* enable video */ 392 confreg = bus_space_read_4(sa->sa_bustag, sc->sc_thc, THC_MISC); 393 confreg |= THC_MISC_VIDEN; 394 bus_space_write_4(sa->sa_bustag, sc->sc_thc, THC_MISC, confreg); 395 396 if (isconsole) { 397 aprint_normal_dev(self, "(console)\n"); 398 } 399 400 fb_attach(&sc->sc_fb, isconsole); 401 402 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 403 wsfont_init(); 404 405 vcons_init(&sc->vd, sc, &tcx_defscreendesc, &tcx_accessops); 406 sc->vd.init_screen = tcx_init_screen; 407 408 vcons_init_screen(&sc->vd, &tcx_console_screen, 1, &defattr); 409 tcx_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 410 411 ri = &tcx_console_screen.scr_ri; 412 413 sc->sc_bg = ri->ri_devcmap[(defattr >> 16) & 0xff]; 414 tcx_clearscreen(sc, 0); 415 tcx_init_cmap(sc); 416 417 tcx_defscreendesc.nrows = ri->ri_rows; 418 tcx_defscreendesc.ncols = ri->ri_cols; 419 tcx_defscreendesc.textops = &ri->ri_ops; 420 tcx_defscreendesc.capabilities = ri->ri_caps; 421 422 if(isconsole) { 423 wsdisplay_cnattach(&tcx_defscreendesc, ri, 0, 0, defattr); 424 vcons_replay_msgbuf(&tcx_console_screen); 425 } 426 427 aa.console = isconsole; 428 aa.scrdata = &tcx_screenlist; 429 aa.accessops = &tcx_accessops; 430 aa.accesscookie = &sc->vd; 431 432 config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE); 433 /* 434 * we need to do this again - something overwrites a handful 435 * palette registers and we end up with white in reg. 0 436 */ 437 tcx_loadcmap(sc, 0, 256); 438 } 439 440 int 441 tcxopen(dev_t dev, int flags, int mode, struct lwp *l) 442 { 443 return (0); 444 } 445 446 int 447 tcxclose(dev_t dev, int flags, int mode, struct lwp *l) 448 { 449 struct tcx_softc *sc = device_lookup_private(&tcx_cd, minor(dev)); 450 451 tcx_reset(sc); 452 /* we may want to clear and redraw the console here */ 453 return (0); 454 } 455 456 int 457 tcxioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 458 { 459 struct tcx_softc *sc = device_lookup_private(&tcx_cd, minor(dev)); 460 461 switch (cmd) { 462 463 case FBIOGTYPE: 464 *(struct fbtype *)data = sc->sc_fb.fb_type; 465 break; 466 467 case FBIOGATTR: 468 #define fba ((struct fbgattr *)data) 469 fba->real_type = sc->sc_fb.fb_type.fb_type; 470 fba->owner = 0; /* XXX ??? */ 471 fba->fbtype = sc->sc_fb.fb_type; 472 fba->sattr.flags = 0; 473 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 474 fba->sattr.dev_specific[0] = -1; 475 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 476 fba->emu_types[1] = FBTYPE_SUN3COLOR; 477 fba->emu_types[2] = -1; 478 #undef fba 479 break; 480 481 case FBIOGETCMAP: 482 #define p ((struct fbcmap *)data) 483 if (p->index > 256 || p->count > 256 - p->index) 484 return EINVAL; 485 if (copyout(&sc->sc_cmap_red[p->index], p->red, p->count) != 0) 486 return EINVAL; 487 if (copyout(&sc->sc_cmap_green[p->index], p->green, p->count) 488 != 0) 489 return EINVAL; 490 if (copyout(&sc->sc_cmap_blue[p->index], p->blue, p->count) 491 != 0) 492 return EINVAL; 493 return 0; 494 495 case FBIOPUTCMAP: 496 /* copy to software map */ 497 if (p->index > 256 || p->count > 256 - p->index) 498 return EINVAL; 499 if (copyin(p->red, &sc->sc_cmap_red[p->index], p->count) != 0) 500 return EINVAL; 501 if (copyin(p->green, &sc->sc_cmap_green[p->index], p->count) 502 != 0) 503 return EINVAL; 504 if (copyin(p->blue, &sc->sc_cmap_blue[p->index], p->count) != 0) 505 return EINVAL; 506 tcx_loadcmap(sc, p->index, p->count); 507 #undef p 508 break; 509 case FBIOGVIDEO: 510 *(int *)data = sc->sc_blanked; 511 break; 512 513 case FBIOSVIDEO: 514 tcx_set_video(sc, *(int *)data); 515 break; 516 517 default: 518 #ifdef DEBUG 519 log(LOG_NOTICE, "tcxioctl(0x%lx) (%s[%d])\n", cmd, 520 l->l_proc->p_comm, l->l_proc->p_pid); 521 #endif 522 return (ENOTTY); 523 } 524 return (0); 525 } 526 527 /* 528 * Clean up hardware state (e.g., after bootup or after X crashes). 529 */ 530 static void 531 tcx_reset(struct tcx_softc *sc) 532 { 533 uint32_t reg; 534 535 reg = bus_space_read_4(sc->sc_bustag, sc->sc_thc, THC_MISC); 536 reg |= THC_MISC_CURSRES; 537 bus_space_write_4(sc->sc_bustag, sc->sc_thc, THC_MISC, reg); 538 } 539 540 static void 541 tcx_init_cmap(struct tcx_softc *sc) 542 { 543 int i, j; 544 545 /* Initialize the default color map. */ 546 j = 0; 547 for (i = 0; i < 256; i++) { 548 549 sc->sc_cmap_red[i] = rasops_cmap[j]; 550 sc->sc_cmap_green[i] = rasops_cmap[j + 1]; 551 sc->sc_cmap_blue[i] = rasops_cmap[j + 2]; 552 j += 3; 553 } 554 tcx_loadcmap(sc, 0, 256); 555 } 556 557 static void 558 tcx_loadcmap(struct tcx_softc *sc, int start, int ncolors) 559 { 560 int i; 561 562 for (i = 0; i < ncolors; i++) { 563 bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_ADDRESS, 564 (start + i) << 24); 565 bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_FB_LUT, 566 sc->sc_cmap_red[i + start] << 24); 567 bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_FB_LUT, 568 sc->sc_cmap_green[i + start] << 24); 569 bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_FB_LUT, 570 sc->sc_cmap_blue[i + start] << 24); 571 } 572 bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_ADDRESS, 0); 573 } 574 575 static void 576 tcx_unblank(device_t dev) 577 { 578 struct tcx_softc *sc = device_private(dev); 579 580 if (sc->sc_blanked) { 581 uint32_t reg; 582 sc->sc_blanked = 0; 583 reg = bus_space_read_4(sc->sc_bustag, sc->sc_thc, THC_MISC); 584 reg &= ~THC_MISC_VSYNC_DISABLE; 585 reg &= ~THC_MISC_HSYNC_DISABLE; 586 reg |= THC_MISC_VIDEN; 587 bus_space_write_4(sc->sc_bustag, sc->sc_thc, THC_MISC, reg); 588 } 589 } 590 591 static void 592 tcx_set_video(struct tcx_softc *sc, int unblank) 593 { 594 uint32_t reg; 595 if (unblank) { 596 sc->sc_blanked = 0; 597 reg = bus_space_read_4(sc->sc_bustag, sc->sc_thc, THC_MISC); 598 reg &= ~THC_MISC_VSYNC_DISABLE; 599 reg &= ~THC_MISC_HSYNC_DISABLE; 600 reg |= THC_MISC_VIDEN; 601 bus_space_write_4(sc->sc_bustag, sc->sc_thc, THC_MISC, reg); 602 } else { 603 sc->sc_blanked = 1; 604 reg = bus_space_read_4(sc->sc_bustag, sc->sc_thc, THC_MISC); 605 reg |= THC_MISC_VSYNC_DISABLE; 606 reg |= THC_MISC_HSYNC_DISABLE; 607 reg &= ~THC_MISC_VIDEN; 608 bus_space_write_4(sc->sc_bustag, sc->sc_thc, THC_MISC, reg); 609 } 610 } 611 612 /* 613 * Base addresses at which users can mmap() the various pieces of a tcx. 614 */ 615 #define TCX_USER_RAM 0x00000000 616 #define TCX_USER_RAM24 0x01000000 617 #define TCX_USER_RAM_COMPAT 0x04000000 /* cg3 emulation */ 618 #define TCX_USER_STIP 0x10000000 619 #define TCX_USER_BLIT 0x20000000 620 #define TCX_USER_RDFB32 0x28000000 621 #define TCX_USER_RSTIP 0x30000000 622 #define TCX_USER_RBLIT 0x38000000 623 #define TCX_USER_TEC 0x70001000 624 #define TCX_USER_BTREGS 0x70002000 625 #define TCX_USER_THC 0x70004000 626 #define TCX_USER_DHC 0x70008000 627 #define TCX_USER_ALT 0x7000a000 628 #define TCX_USER_UART 0x7000c000 629 #define TCX_USER_VRT 0x7000e000 630 #define TCX_USER_ROM 0x70010000 631 632 struct mmo { 633 u_int mo_uaddr; /* user (virtual) address */ 634 u_int mo_size; /* size, or 0 for video ram size */ 635 u_int mo_bank; /* register bank number */ 636 }; 637 638 /* 639 * Return the address that would map the given device at the given 640 * offset, allowing for the given protection, or return -1 for error. 641 * 642 * XXX needs testing against `demanding' applications (e.g., aviator) 643 */ 644 paddr_t 645 tcxmmap(dev_t dev, off_t off, int prot) 646 { 647 struct tcx_softc *sc = device_lookup_private(&tcx_cd, minor(dev)); 648 struct openprom_addr *rr = sc->sc_physaddr; 649 struct mmo *mo, *mo_end; 650 u_int u, sz; 651 static struct mmo mmo[] = { 652 { TCX_USER_RAM, 0, TCX_REG_DFB8 }, 653 { TCX_USER_RAM24, 0, TCX_REG_DFB24 }, 654 { TCX_USER_RAM_COMPAT, 0, TCX_REG_DFB8 }, 655 656 { TCX_USER_STIP, 1, TCX_REG_STIP }, 657 { TCX_USER_BLIT, 1, TCX_REG_BLIT }, 658 { TCX_USER_RDFB32, 0, TCX_REG_RDFB32 }, 659 { TCX_USER_RSTIP, 1, TCX_REG_RSTIP }, 660 { TCX_USER_RBLIT, 1, TCX_REG_RBLIT }, 661 { TCX_USER_TEC, 1, TCX_REG_TEC }, 662 { TCX_USER_BTREGS, 8192 /* XXX */, TCX_REG_CMAP }, 663 { TCX_USER_THC, 0x2000, TCX_REG_THC }, 664 { TCX_USER_DHC, 1, TCX_REG_DHC }, 665 { TCX_USER_ALT, 1, TCX_REG_ALT }, 666 { TCX_USER_ROM, 65536, TCX_REG_ROM }, 667 }; 668 #define NMMO (sizeof mmo / sizeof *mmo) 669 670 if (off & PGOFSET) 671 panic("tcxmmap"); 672 673 /* 674 * Entries with size 0 map video RAM (i.e., the size in fb data). 675 * Entries that map 32-bit deep regions are adjusted for their 676 * depth (fb_size gives the size of the 8-bit-deep region). 677 * 678 * Since we work in pages, the fact that the map offset table's 679 * sizes are sometimes bizarre (e.g., 1) is effectively ignored: 680 * one byte is as good as one page. 681 */ 682 683 mo = mmo; 684 mo_end = &mmo[NMMO]; 685 686 for (; mo < mo_end; mo++) { 687 if ((u_int)off < mo->mo_uaddr) 688 continue; 689 690 u = off - mo->mo_uaddr; 691 sz = mo->mo_size; 692 693 if (sz == 0) { 694 sz = sc->sc_fb.fb_type.fb_size; 695 /* 696 * check for the 32-bit-deep regions and adjust 697 * accordingly 698 */ 699 if (mo->mo_uaddr == TCX_USER_RAM24 || 700 mo->mo_uaddr == TCX_USER_RDFB32) { 701 if (sc->sc_8bit) { 702 /* 703 * not present on 8-bit hardware 704 */ 705 continue; 706 } 707 sz *= 4; 708 } 709 } 710 if (sz == 1) 711 sz = rr[mo->mo_bank].oa_size; 712 713 if (u < sz) { 714 return (bus_space_mmap(sc->sc_bustag, 715 BUS_ADDR(rr[mo->mo_bank].oa_space, 716 rr[mo->mo_bank].oa_base), 717 u, 718 prot, 719 BUS_SPACE_MAP_LINEAR)); 720 } 721 } 722 return (-1); 723 } 724 725 int 726 tcx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 727 struct lwp *l) 728 { 729 struct vcons_data *vd = v; 730 struct tcx_softc *sc = vd->cookie; 731 struct wsdisplay_fbinfo *wdf; 732 struct vcons_screen *ms = vd->active; 733 734 switch (cmd) { 735 case WSDISPLAYIO_GTYPE: 736 *(u_int *)data = WSDISPLAY_TYPE_SUNTCX; 737 return 0; 738 739 case FBIOGVIDEO: 740 case WSDISPLAYIO_GVIDEO: 741 *(int *)data = !sc->sc_blanked; 742 return 0; 743 744 case WSDISPLAYIO_SVIDEO: 745 case FBIOSVIDEO: 746 tcx_set_video(sc, *(int *)data); 747 return 0; 748 749 case WSDISPLAYIO_GINFO: 750 wdf = (void *)data; 751 wdf->height = ms->scr_ri.ri_height; 752 wdf->width = ms->scr_ri.ri_width; 753 if (sc->sc_8bit) { 754 wdf->depth = 8; 755 } else { 756 wdf->depth = 32; 757 } 758 wdf->cmsize = 256; 759 return 0; 760 case WSDISPLAYIO_LINEBYTES: 761 { 762 int *ret = (int *)data; 763 *ret = sc->sc_8bit ? ms->scr_ri.ri_width : 764 ms->scr_ri.ri_width << 2; 765 } 766 return 0; 767 768 case WSDISPLAYIO_GETCMAP: 769 #define p ((struct wsdisplay_cmap *)data) 770 if (p->index > 256 || p->count > 256 - p->index) 771 return EINVAL; 772 if (copyout(&sc->sc_cmap_red[p->index], p->red, p->count) != 0) 773 return EINVAL; 774 if (copyout(&sc->sc_cmap_green[p->index], p->green, p->count) 775 != 0) 776 return EINVAL; 777 if (copyout(&sc->sc_cmap_blue[p->index], p->blue, p->count) 778 != 0) 779 return EINVAL; 780 return 0; 781 782 case WSDISPLAYIO_PUTCMAP: 783 /* copy to software map */ 784 if (p->index > 256 || p->count > 256 - p->index) 785 return EINVAL; 786 if (copyin(p->red, &sc->sc_cmap_red[p->index], p->count) != 0) 787 return EINVAL; 788 if (copyin(p->green, &sc->sc_cmap_green[p->index], p->count) 789 != 0) 790 return EINVAL; 791 if (copyin(p->blue, &sc->sc_cmap_blue[p->index], p->count) != 0) 792 return EINVAL; 793 tcx_loadcmap(sc, p->index, p->count); 794 return 0; 795 #undef p 796 797 case WSDISPLAYIO_SMODE: 798 { 799 int new_mode = *(int*)data; 800 if (new_mode != sc->sc_mode) 801 { 802 sc->sc_mode = new_mode; 803 if (new_mode == WSDISPLAYIO_MODE_EMUL) 804 { 805 tcx_init_cmap(sc); 806 tcx_clearscreen(sc, 0); 807 vcons_redraw_screen(ms); 808 } else if (sc->sc_depth == 32) { 809 /* 810 * make sure we set the control 811 * bits correctly 812 */ 813 tcx_clearscreen(sc, 3); 814 } else 815 tcx_clearscreen(sc, 0); 816 } 817 } 818 return 0; 819 820 case WSDISPLAYIO_GCURPOS: 821 if (sc->sc_8bit) { 822 return EOPNOTSUPP; 823 } else { 824 struct wsdisplay_curpos *cp = (void *)data; 825 826 cp->x = sc->sc_cursor_x; 827 cp->y = sc->sc_cursor_y; 828 } 829 return 0; 830 831 case WSDISPLAYIO_SCURPOS: 832 if (sc->sc_8bit) { 833 return EOPNOTSUPP; 834 } else { 835 struct wsdisplay_curpos *cp = (void *)data; 836 837 sc->sc_cursor_x = cp->x; 838 sc->sc_cursor_y = cp->y; 839 tcx_set_cursor(sc); 840 } 841 return 0; 842 843 case WSDISPLAYIO_GCURMAX: 844 if (sc->sc_8bit) { 845 return EOPNOTSUPP; 846 } else { 847 struct wsdisplay_curpos *cp = (void *)data; 848 849 cp->x = 32; 850 cp->y = 32; 851 } 852 return 0; 853 854 case WSDISPLAYIO_SCURSOR: 855 if (sc->sc_8bit) { 856 return EOPNOTSUPP; 857 } else { 858 struct wsdisplay_cursor *cursor = (void *)data; 859 860 return tcx_do_cursor(sc, cursor); 861 } 862 break; /* shouldn't ever get here */ 863 864 case WSDISPLAYIO_SET_DEPTH: 865 { 866 int new_depth = *(int*)data; 867 868 if (sc->sc_8bit) { 869 return ( new_depth == 8) ? 0 : EINVAL; 870 } else if ((new_depth == 8) || (new_depth == 32)) { 871 sc->sc_depth = new_depth; 872 return 0; 873 } 874 return EINVAL; 875 } 876 877 case WSDISPLAYIO_GET_FBINFO: 878 { 879 struct wsdisplayio_fbinfo *fbi = data; 880 881 if (sc->sc_depth == 8) { 882 fbi->fbi_fbsize = sc->sc_fbsize; 883 fbi->fbi_stride = sc->sc_fb.fb_type.fb_width; 884 fbi->fbi_bitsperpixel = 8; 885 fbi->fbi_pixeltype = WSFB_CI; 886 } else { 887 fbi->fbi_fbsize = sc->sc_fbsize * 4; 888 fbi->fbi_stride = sc->sc_fb.fb_type.fb_width * 4; 889 fbi->fbi_bitsperpixel = 32; 890 fbi->fbi_pixeltype = WSFB_RGB; 891 } 892 fbi->fbi_width = sc->sc_fb.fb_type.fb_width; 893 fbi->fbi_height = sc->sc_fb.fb_type.fb_height; 894 fbi->fbi_subtype.fbi_rgbmasks.red_offset = 0; 895 fbi->fbi_subtype.fbi_rgbmasks.red_size = 8; 896 fbi->fbi_subtype.fbi_rgbmasks.green_offset = 8; 897 fbi->fbi_subtype.fbi_rgbmasks.green_size = 8; 898 fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 16; 899 fbi->fbi_subtype.fbi_rgbmasks.blue_size = 8; 900 fbi->fbi_subtype.fbi_rgbmasks.alpha_offset = 0; 901 fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 0; 902 return 0; 903 } 904 905 } 906 return EPASSTHROUGH; 907 } 908 909 static paddr_t 910 tcx_mmap(void *v, void *vs, off_t offset, int prot) 911 { 912 struct vcons_data *vd = v; 913 struct tcx_softc *sc = vd->cookie; 914 915 /* 'regular' framebuffer mmap()ing */ 916 if (sc->sc_depth == 8) { 917 /* on 8Bit boards hand over the 8 bit aperture */ 918 if (offset > sc->sc_fbsize) 919 return -1; 920 return bus_space_mmap(sc->sc_bustag, 921 sc->sc_physaddr[TCX_REG_DFB8].oa_base + offset, 0, prot, 922 BUS_SPACE_MAP_LINEAR); 923 } else { 924 /* ... but if we have a 24bit aperture we use it */ 925 if (offset > sc->sc_fbsize * 4) 926 return -1; 927 return bus_space_mmap(sc->sc_bustag, 928 sc->sc_physaddr[TCX_REG_DFB24].oa_base + offset, 0, prot, 929 BUS_SPACE_MAP_LINEAR); 930 } 931 return -1; 932 } 933 934 static void 935 tcx_init_screen(void *cookie, struct vcons_screen *scr, 936 int existing, long *defattr) 937 { 938 struct tcx_softc *sc = cookie; 939 struct rasops_info *ri = &scr->scr_ri; 940 941 ri->ri_depth = 8; 942 ri->ri_width = sc->sc_fb.fb_type.fb_width; 943 ri->ri_height = sc->sc_fb.fb_type.fb_height; 944 ri->ri_stride = sc->sc_fb.fb_linebytes; 945 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 946 947 ri->ri_bits = sc->sc_fbaddr; 948 949 rasops_init(ri, 0, 0); 950 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 951 WSSCREEN_REVERSE | WSSCREEN_RESIZE; 952 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 953 ri->ri_width / ri->ri_font->fontwidth); 954 955 scr->scr_flags |= VCONS_NO_COPYCOLS | VCONS_NO_CURSOR | VCONS_LOADFONT; 956 /* enable acceleration */ 957 ri->ri_ops.copyrows = tcx_copyrows; 958 ri->ri_ops.eraserows = tcx_eraserows; 959 ri->ri_ops.erasecols = tcx_erasecols; 960 ri->ri_ops.putchar = tcx_putchar; 961 ri->ri_ops.allocattr = tcx_allocattr; 962 #if 0 963 ri->ri_ops.cursor = tcx_cursor; 964 ri->ri_ops.copycols = tcx_copycols; 965 #endif 966 } 967 968 static void 969 tcx_clearscreen(struct tcx_softc *sc, int spc) 970 { 971 /* ROP in the upper 4bit is necessary, tcx actually uses it */ 972 volatile uint64_t bg = 0x30000000ffffffffLL; 973 volatile uint64_t spc64; 974 int i, len; 975 976 spc64 = ((spc & 3) << 24); 977 bg |= (spc64 << 32); 978 979 len = sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height; 980 for (i = 0; i < len; i += 32) 981 sc->sc_rstip[i] = bg; 982 } 983 984 static void 985 tcx_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 986 { 987 struct rasops_info *ri = cookie; 988 struct vcons_screen *scr = ri->ri_hw; 989 struct tcx_softc *sc = scr->scr_cookie; 990 int i, last, first, len, dest, leftover; 991 992 if ((ri->ri_crow >= srcrow && ri->ri_crow < (srcrow + nrows)) && 993 (ri->ri_flg & RI_CURSOR)) { 994 int ofs = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 995 tcx_putchar(cookie, ri->ri_crow, ri->ri_ccol, 996 scr->scr_chars[ofs], scr->scr_attrs[ofs]); 997 ri->ri_flg &= ~RI_CURSOR; 998 } 999 1000 if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows)) 1001 ri->ri_flg &= ~RI_CURSOR; 1002 1003 i = ri->ri_width * ri->ri_font->fontheight * nrows; 1004 len = i & 0xffffe0; 1005 leftover = i & 0x1f; 1006 if (srcrow < dstrow) { 1007 /* we must go bottom to top */ 1008 first = ri->ri_width * 1009 (ri->ri_font->fontheight * srcrow + ri->ri_yorigin); 1010 last = first + len; 1011 dest = ri->ri_width * 1012 (ri->ri_font->fontheight * dstrow + ri->ri_yorigin) + len; 1013 if (leftover > 0) { 1014 sc->sc_rblit[dest + 32] = 1015 (uint64_t)((leftover - 1) << 24) | 1016 (uint64_t)(i + 32); 1017 } 1018 for (i = last; i >= first; i -= 32) { 1019 sc->sc_rblit[dest] = 0x300000001f000000LL | (uint64_t)i; 1020 dest -= 32; 1021 } 1022 } else { 1023 /* top to bottom */ 1024 first = ri->ri_width * 1025 (ri->ri_font->fontheight * srcrow + ri->ri_yorigin); 1026 dest = ri->ri_width * 1027 (ri->ri_font->fontheight * dstrow + ri->ri_yorigin); 1028 last = first + len; 1029 for (i = first; i <= last; i+= 32) { 1030 sc->sc_rblit[dest] = 0x300000001f000000LL | (uint64_t)i; 1031 dest += 32; 1032 } 1033 if (leftover > 0) { 1034 sc->sc_rblit[dest] = 1035 (uint64_t)((leftover - 1) << 24) | (uint64_t)i; 1036 } 1037 } 1038 } 1039 1040 static void 1041 tcx_eraserows(void *cookie, int start, int nrows, long attr) 1042 { 1043 struct rasops_info *ri = cookie; 1044 struct vcons_screen *scr = ri->ri_hw; 1045 struct tcx_softc *sc = scr->scr_cookie; 1046 volatile uint64_t temp; 1047 int i, last, first, len, leftover; 1048 1049 if (ri->ri_crow >= start && ri->ri_crow < (start + nrows)) 1050 ri->ri_flg &= ~RI_CURSOR; 1051 1052 i = ri->ri_width * ri->ri_font->fontheight * nrows; 1053 len = i & 0xffffe0; 1054 leftover = i & 0x1f; 1055 first = ri->ri_width * 1056 (ri->ri_font->fontheight * start + ri->ri_yorigin); 1057 last = first + len; 1058 temp = 0x30000000ffffffffLL | 1059 ((uint64_t)((ri->ri_devcmap[(attr >> 16) & 0xff]) & 0xff) << 32); 1060 1061 for (i = first; i < last; i+= 32) 1062 sc->sc_rstip[i] = temp; 1063 1064 if (leftover > 0) { 1065 temp &= 0xffffffffffffffffLL << (32 - leftover); 1066 sc->sc_rstip[i] = temp; 1067 } 1068 } 1069 1070 static void 1071 tcx_erasecols(void *cookie, int row, int startcol, int ncols, long attr) 1072 { 1073 struct rasops_info *ri = cookie; 1074 struct vcons_screen *scr = ri->ri_hw; 1075 struct tcx_softc *sc = scr->scr_cookie; 1076 volatile uint64_t temp, cmd, rcmd, lcmd; 1077 uint32_t pmask; 1078 int i, fullsteps, line, dst; 1079 int x1 = startcol * ri->ri_font->fontwidth + ri->ri_xorigin; 1080 int x2 = (startcol + ncols) * ri->ri_font->fontwidth + ri->ri_xorigin; 1081 1082 temp = 0x3000000000000000LL | 1083 ((uint64_t)((ri->ri_devcmap[(attr >> 16) & 0xff]) & 0xff) << 32), 1084 dst = ri->ri_width * (ri->ri_font->fontheight * row + ri->ri_yorigin) + 1085 x1; 1086 dst &= 0xffffffe0; 1087 1088 /* see if the whole thing falls into one 32bit chunk */ 1089 if ((x1 & 0xffe0) == (x2 & 0xffe0)) { 1090 /* first zero out pixels on the right */ 1091 pmask = 0xffffffff << (31 - (x2 & 0x1f)); 1092 /* then mask out pixels on the left */ 1093 pmask &= (0xffffffff >> (x1 & 0x1f)); 1094 cmd = temp | pmask; 1095 for (i = 0; i < ri->ri_font->fontheight; i++) { 1096 sc->sc_rstip[dst] = cmd; 1097 dst += ri->ri_width; 1098 } 1099 } else { 1100 /* at least two writes per line */ 1101 pmask = 0xffffffff << (31 - (x2 & 0x1f)); 1102 rcmd = temp | (uint64_t)pmask; 1103 pmask = 0xffffffff >> (x1 & 0x1f); 1104 lcmd = temp | (uint64_t)pmask; 1105 cmd = temp | 0xffffffffLL; 1106 dst &= 0xffffffe0; 1107 fullsteps = ((x2 >> 5) - (x1 >> 5)); 1108 fullsteps = fullsteps << 5; 1109 for (line = 0; line < ri->ri_font->fontheight; line++) { 1110 sc->sc_rstip[dst] = lcmd; 1111 for (i = 32; i < fullsteps; i+= 32) 1112 sc->sc_rstip[dst + i] = cmd; 1113 sc->sc_rstip[dst + i] = rcmd; 1114 dst += ri->ri_width; 1115 } 1116 } 1117 } 1118 1119 /* 1120 * The stipple engine is 100% stupid. All drawing operations have to start 1121 * at 32 pixel boundaries so we'll have to deal with characters being split. 1122 */ 1123 1124 static void 1125 tcx_putchar(void *cookie, int row, int col, u_int c, long attr) 1126 { 1127 struct rasops_info *ri = cookie; 1128 struct wsdisplay_font *font = PICK_FONT(ri, c); 1129 struct vcons_screen *scr = ri->ri_hw; 1130 struct tcx_softc *sc = scr->scr_cookie; 1131 volatile uint64_t bg, fg, temp, mask; 1132 int addr, i, uc, shift; 1133 uint32_t fmask; 1134 uint8_t *cdata, cc; 1135 uint16_t *wdata, w; 1136 int bold = (attr & WSATTR_HILIT) != 0; 1137 1138 addr = ri->ri_xorigin + col * font->fontwidth + 1139 (ri->ri_yorigin + row * font->fontheight) * ri->ri_width; 1140 1141 /* check if the character is crossing a 32 pixel boundary */ 1142 if ((addr & 0xffffe0) == 1143 ((addr + font->fontwidth - 1) & 0xffffe0)) { 1144 /* phew, not split */ 1145 shift = addr & 0x1f; 1146 addr &= 0xffffe0; 1147 fmask = 0xffffffff >> (32 - font->fontwidth); 1148 fmask = fmask << (32 - font->fontwidth - shift); 1149 mask = fmask; 1150 bg = 0x3000000000000000LL | 1151 ((uint64_t)ri->ri_devcmap[(attr >> 16) & 0xff] & 1152 0xff) << 32; 1153 bg |= mask; 1154 temp = 0x3000000000000000LL | 1155 ((uint64_t)ri->ri_devcmap[(attr >> 24) & 0xff] & 0xff) << 1156 32; 1157 uc = c - font->firstchar; 1158 cdata = (uint8_t *)font->data + uc * ri->ri_fontscale; 1159 1160 if (font->fontwidth < 9) { 1161 /* byte by byte */ 1162 for (i = 0; i < font->fontheight - 1; i++) { 1163 sc->sc_rstip[addr] = bg; 1164 cc = *cdata; 1165 if (cc != 0) { 1166 if (bold) cc |= cc >> 1; 1167 if (shift > 24) { 1168 fg = (uint64_t)(cc >> 1169 (shift - 24)); 1170 } else { 1171 fg = (uint64_t)(cc << 1172 (24 - shift)); 1173 } 1174 sc->sc_rstip[addr] = fg | temp; 1175 } 1176 cdata++; 1177 addr += ri->ri_width; 1178 } 1179 if (attr & WSATTR_UNDERLINE) { 1180 sc->sc_rstip[addr] = temp | mask; 1181 } else { 1182 sc->sc_rstip[addr] = bg; 1183 cc = *cdata; 1184 if (cc != 0) { 1185 if (bold) cc |= cc >> 1; 1186 if (shift > 24) { 1187 fg = (uint64_t)(cc >> (shift - 24)); 1188 } else { 1189 fg = (uint64_t)(cc << (24 - shift)); 1190 } 1191 sc->sc_rstip[addr] = fg | temp; 1192 } 1193 } 1194 } else if (font->fontwidth < 17) { 1195 /* short by short */ 1196 wdata = (uint16_t *)cdata; 1197 for (i = 0; i < font->fontheight - 1; i++) { 1198 sc->sc_rstip[addr] = bg; 1199 w = *wdata; 1200 if (w != 0) { 1201 if (bold) w |= w >> 1; 1202 if (shift > 16) { 1203 fg = temp | (uint64_t)(w >> 1204 (shift - 16)); 1205 } else { 1206 fg = temp | (uint64_t)(w << 1207 (16 - shift)); 1208 } 1209 sc->sc_rstip[addr] = fg; 1210 } 1211 wdata++; 1212 addr += ri->ri_width; 1213 } 1214 if (attr & WSATTR_UNDERLINE) { 1215 sc->sc_rstip[addr] = temp | mask; 1216 } else { 1217 sc->sc_rstip[addr] = bg; 1218 w = *wdata; 1219 if (w != 0) { 1220 if (bold) w |= w >> 1; 1221 if (shift > 16) { 1222 fg = temp | (uint64_t)(w >> 1223 (shift - 16)); 1224 } else { 1225 fg = temp | (uint64_t)(w << 1226 (16 - shift)); 1227 } 1228 sc->sc_rstip[addr] = fg; 1229 } 1230 } 1231 } 1232 } else { 1233 /* and now the split case ( man this hardware is dumb ) */ 1234 volatile uint64_t bgr, maskr, fgr; 1235 uint32_t bork; 1236 1237 shift = addr & 0x1f; 1238 addr &= 0xffffe0; 1239 mask = 0xffffffff >> shift; 1240 maskr = (uint64_t)(0xffffffffUL << 1241 (32 - (font->fontwidth + shift - 32))); 1242 bg = 0x3000000000000000LL | 1243 ((uint64_t)ri->ri_devcmap[(attr >> 16) & 0xff] & 1244 0xff) << 32; 1245 bgr = bg | maskr; 1246 bg |= mask; 1247 temp = 0x3000000000000000LL | 1248 ((uint64_t)ri->ri_devcmap[(attr >> 24) & 0xff] & 0xff) << 1249 32; 1250 1251 uc = c - font->firstchar; 1252 cdata = (uint8_t *)font->data + uc * ri->ri_fontscale; 1253 1254 if (font->fontwidth < 9) { 1255 /* byte by byte */ 1256 for (i = 0; i < font->fontheight - 1; i++) { 1257 sc->sc_rstip[addr] = bg; 1258 sc->sc_rstip[addr + 32] = bgr; 1259 bork = *cdata; 1260 if (bork != 0) { 1261 if (bold) bork |= bork >> 1; 1262 fg = (uint64_t)bork >> (shift - 24); 1263 sc->sc_rstip[addr] = fg | temp; 1264 fgr = (uint64_t)(bork << (52 - shift)); 1265 sc->sc_rstip[addr] = fgr | temp; 1266 } 1267 cdata++; 1268 addr += ri->ri_width; 1269 } 1270 if (attr & WSATTR_UNDERLINE) { 1271 sc->sc_rstip[addr] = temp | mask; 1272 sc->sc_rstip[addr + 32] = temp | maskr; 1273 } else { 1274 sc->sc_rstip[addr] = bg; 1275 sc->sc_rstip[addr + 32] = bgr; 1276 bork = *cdata; 1277 if (bork != 0) { 1278 if (bold) bork |= bork >> 1; 1279 fg = (uint64_t)bork >> (shift - 24); 1280 sc->sc_rstip[addr] = fg | temp; 1281 fgr = (uint64_t)(bork << (52 - shift)); 1282 sc->sc_rstip[addr] = fgr | temp; 1283 } 1284 } 1285 } else if (font->fontwidth < 17) { 1286 /* short by short */ 1287 wdata = (uint16_t *)cdata; 1288 for (i = 0; i < font->fontheight - 1; i++) { 1289 sc->sc_rstip[addr] = bg; 1290 sc->sc_rstip[addr + 32] = bgr; 1291 bork = *wdata; 1292 if (bork != 0) { 1293 if (bold) bork |= bork >> 1; 1294 fg = (uint64_t)bork >> (shift - 16); 1295 sc->sc_rstip[addr] = fg | temp; 1296 fgr = (uint64_t)(bork << (48 - shift)); 1297 sc->sc_rstip[addr + 32] = fgr | temp; 1298 } 1299 wdata++; 1300 addr += ri->ri_width; 1301 } 1302 if (attr & WSATTR_UNDERLINE) { 1303 sc->sc_rstip[addr] = temp | mask; 1304 sc->sc_rstip[addr + 32] = temp | maskr; 1305 } else { 1306 sc->sc_rstip[addr] = bg; 1307 sc->sc_rstip[addr + 32] = bgr; 1308 bork = *wdata; 1309 if (bork != 0) { 1310 if (bold) bork |= bork >> 1; 1311 fg = (uint64_t)bork >> (shift - 16); 1312 sc->sc_rstip[addr] = fg | temp; 1313 fgr = (uint64_t)(bork << (48 - shift)); 1314 sc->sc_rstip[addr + 32] = fgr | temp; 1315 } 1316 } 1317 } 1318 } 1319 } 1320 1321 static int 1322 tcx_allocattr(void *cookie, int fg0, int bg0, int flg, long *attrp) 1323 { 1324 int fg = fg0, bg = bg0; 1325 1326 if ((flg & WSATTR_BLINK) != 0) 1327 return EINVAL; 1328 1329 if ((flg & WSATTR_REVERSE) != 0) { 1330 fg = bg0; 1331 bg = fg0; 1332 } 1333 1334 *attrp = (bg << 16) | (fg << 24) | flg; 1335 return 0; 1336 } 1337 1338 static int 1339 tcx_do_cursor(struct tcx_softc *sc, struct wsdisplay_cursor *cur) 1340 { 1341 if (sc->sc_8bit) { 1342 /* hw cursor is not implemented on tcx */ 1343 return -1; 1344 } 1345 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 1346 1347 if (cur->enable) { 1348 tcx_set_cursor(sc); 1349 } else { 1350 /* move the cursor out of sight */ 1351 bus_space_write_4(sc->sc_bustag, sc->sc_thc, 1352 THC_CURSOR_POS, 0x7fff7fff); 1353 } 1354 } 1355 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 1356 1357 sc->sc_hotspot_x = cur->hot.x; 1358 sc->sc_hotspot_y = cur->hot.y; 1359 tcx_set_cursor(sc); 1360 } 1361 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 1362 1363 sc->sc_cursor_x = cur->pos.x; 1364 sc->sc_cursor_y = cur->pos.y; 1365 tcx_set_cursor(sc); 1366 } 1367 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 1368 #if 0 1369 /* 1370 * apparently we're not writing in the right register here - if we do 1371 * this the screen goes all funky 1372 */ 1373 int i; 1374 1375 for (i = 0; i < cur->cmap.count; i++) { 1376 bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_ADDRESS, 1377 (cur->cmap.index + i + 2) << 24); 1378 bus_space_write_4(sc->sc_bustag, sc->sc_bt, 1379 DAC_CURSOR_LUT, cur->cmap.red[i] << 24); 1380 bus_space_write_4(sc->sc_bustag, sc->sc_bt, 1381 DAC_CURSOR_LUT, cur->cmap.green[i] << 24); 1382 bus_space_write_4(sc->sc_bustag, sc->sc_bt, 1383 DAC_CURSOR_LUT, cur->cmap.blue[i] << 24); 1384 } 1385 #endif 1386 } 1387 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 1388 int i; 1389 uint32_t temp, poof; 1390 1391 for (i = 0; i < 128; i += 4) { 1392 memcpy(&temp, &cur->mask[i], 4); 1393 poof = ((temp & 0x80808080) >> 7) | 1394 ((temp & 0x40404040) >> 5) | 1395 ((temp & 0x20202020) >> 3) | 1396 ((temp & 0x10101010) >> 1) | 1397 ((temp & 0x08080808) << 1) | 1398 ((temp & 0x04040404) << 3) | 1399 ((temp & 0x02020202) << 5) | 1400 ((temp & 0x01010101) << 7); 1401 bus_space_write_4(sc->sc_bustag, sc->sc_thc, 1402 THC_CURSOR_1 + i, poof); 1403 memcpy(&temp, &cur->image[i], 4); 1404 poof = ((temp & 0x80808080) >> 7) | 1405 ((temp & 0x40404040) >> 5) | 1406 ((temp & 0x20202020) >> 3) | 1407 ((temp & 0x10101010) >> 1) | 1408 ((temp & 0x08080808) << 1) | 1409 ((temp & 0x04040404) << 3) | 1410 ((temp & 0x02020202) << 5) | 1411 ((temp & 0x01010101) << 7); 1412 bus_space_write_4(sc->sc_bustag, sc->sc_thc, 1413 THC_CURSOR_0 + i, poof); 1414 } 1415 } 1416 return 0; 1417 } 1418 1419 static void 1420 tcx_set_cursor(struct tcx_softc *sc) 1421 { 1422 uint32_t reg; 1423 1424 reg = (((sc->sc_cursor_x - sc->sc_hotspot_x) & 0xfff) << 16) | 1425 ((sc->sc_cursor_y - sc->sc_hotspot_y) & 0x0fff); 1426 bus_space_write_4(sc->sc_bustag, sc->sc_thc, THC_CURSOR_POS, reg); 1427 } 1428 1429