1 /* $NetBSD: cgfourteen.c,v 1.85 2018/01/25 14:45:58 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 1996 5 * The President and Fellows of Harvard College. All rights reserved. 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This software was developed by the Computer Systems Engineering group 10 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 11 * contributed to Berkeley. 12 * 13 * All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Harvard University. 16 * This product includes software developed by the University of 17 * California, Lawrence Berkeley Laboratory. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions 21 * are met: 22 * 1. Redistributions of source code must retain the above copyright 23 * notice, this list of conditions and the following disclaimer. 24 * 2. Redistributions in binary form must reproduce the above copyright 25 * notice, this list of conditions and the following disclaimer in the 26 * documentation and/or other materials provided with the distribution. 27 * 3. All advertising materials mentioning features or use of this software 28 * must display the following acknowledgement: 29 * This product includes software developed by the University of 30 * California, Berkeley and its contributors. 31 * This product includes software developed by Harvard University and 32 * its contributors. 33 * 4. Neither the name of the University nor the names of its contributors 34 * may be used to endorse or promote products derived from this software 35 * without specific prior written permission. 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * 49 * Based on: 50 * NetBSD: cgthree.c,v 1.28 1996/05/31 09:59:22 pk Exp 51 * NetBSD: cgsix.c,v 1.25 1996/04/01 17:30:00 christos Exp 52 */ 53 54 /* 55 * Driver for Campus-II on-board mbus-based video (cgfourteen). 56 * 57 * Does not handle interrupts, even though they can occur. 58 * 59 * XXX should defer colormap updates to vertical retrace interrupts 60 */ 61 62 /* 63 * The following is for debugging only; it opens up a security hole 64 * enabled by allowing any user to map the control registers for the 65 * cg14 into their space. 66 */ 67 #undef CG14_MAP_REGS 68 69 #include "opt_wsemul.h" 70 #include "sx.h" 71 72 #include <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/buf.h> 75 #include <sys/device.h> 76 #include <sys/ioctl.h> 77 #include <sys/malloc.h> 78 #include <sys/kmem.h> 79 #include <sys/mman.h> 80 #include <sys/tty.h> 81 #include <sys/conf.h> 82 #include <dev/pci/pciio.h> 83 84 #include <uvm/uvm_extern.h> 85 86 #include <dev/sun/fbio.h> 87 #include <machine/autoconf.h> 88 #include <machine/pmap.h> 89 #include <dev/sun/fbvar.h> 90 #include <machine/cpu.h> 91 #include <dev/sbus/sbusvar.h> 92 93 #include "wsdisplay.h" 94 #include <dev/wscons/wsconsio.h> 95 #include <dev/wsfont/wsfont.h> 96 #include <dev/rasops/rasops.h> 97 98 #include <dev/wscons/wsdisplay_vconsvar.h> 99 #include <dev/wscons/wsdisplay_glyphcachevar.h> 100 101 #include <sparc/sparc/asm.h> 102 #include <sparc/dev/cgfourteenreg.h> 103 #include <sparc/dev/cgfourteenvar.h> 104 #include <sparc/dev/sxreg.h> 105 #include <sparc/dev/sxvar.h> 106 107 /* autoconfiguration driver */ 108 static int cgfourteenmatch(device_t, struct cfdata *, void *); 109 static void cgfourteenattach(device_t, device_t, void *); 110 static void cgfourteenunblank(device_t); 111 112 CFATTACH_DECL_NEW(cgfourteen, sizeof(struct cgfourteen_softc), 113 cgfourteenmatch, cgfourteenattach, NULL, NULL); 114 115 extern struct cfdriver cgfourteen_cd; 116 117 dev_type_open(cgfourteenopen); 118 dev_type_close(cgfourteenclose); 119 dev_type_ioctl(cgfourteenioctl); 120 dev_type_mmap(cgfourteenmmap); 121 dev_type_poll(cgfourteenpoll); 122 123 const struct cdevsw cgfourteen_cdevsw = { 124 .d_open = cgfourteenopen, 125 .d_close = cgfourteenclose, 126 .d_read = noread, 127 .d_write = nowrite, 128 .d_ioctl = cgfourteenioctl, 129 .d_stop = nostop, 130 .d_tty = notty, 131 .d_poll = cgfourteenpoll, 132 .d_mmap = cgfourteenmmap, 133 .d_kqfilter = nokqfilter, 134 .d_discard = nodiscard, 135 .d_flag = 0 136 }; 137 138 /* frame buffer generic driver */ 139 static struct fbdriver cgfourteenfbdriver = { 140 cgfourteenunblank, cgfourteenopen, cgfourteenclose, cgfourteenioctl, 141 cgfourteenpoll, cgfourteenmmap, nokqfilter 142 }; 143 144 static void cg14_set_video(struct cgfourteen_softc *, int); 145 static int cg14_get_video(struct cgfourteen_softc *); 146 static int cg14_get_cmap(struct fbcmap *, union cg14cmap *, int); 147 static int cg14_put_cmap(struct fbcmap *, union cg14cmap *, int); 148 static void cg14_load_hwcmap(struct cgfourteen_softc *, int, int); 149 static void cg14_init(struct cgfourteen_softc *); 150 static void cg14_reset(struct cgfourteen_softc *); 151 152 #if NWSDISPLAY > 0 153 static void cg14_setup_wsdisplay(struct cgfourteen_softc *, int); 154 static void cg14_init_cmap(struct cgfourteen_softc *); 155 static int cg14_putcmap(struct cgfourteen_softc *, struct wsdisplay_cmap *); 156 static int cg14_getcmap(struct cgfourteen_softc *, struct wsdisplay_cmap *); 157 static void cg14_set_depth(struct cgfourteen_softc *, int); 158 static void cg14_move_cursor(struct cgfourteen_softc *, int, int); 159 static int cg14_do_cursor(struct cgfourteen_softc *, 160 struct wsdisplay_cursor *); 161 162 #if NSX > 0 163 static void cg14_wait_idle(struct cgfourteen_softc *); 164 static void cg14_rectfill(struct cgfourteen_softc *, int, int, int, int, 165 uint32_t); 166 static void cg14_rectfill_a(void *, int, int, int, int, long); 167 static void cg14_invert(struct cgfourteen_softc *, int, int, int, int); 168 static void cg14_bitblt(void *, int, int, int, int, int, int, int); 169 static void cg14_bitblt_gc(void *, int, int, int, int, int, int, int); 170 171 static void cg14_putchar_aa(void *, int, int, u_int, long); 172 static void cg14_cursor(void *, int, int, int); 173 static void cg14_putchar(void *, int, int, u_int, long); 174 static void cg14_copycols(void *, int, int, int, int); 175 static void cg14_erasecols(void *, int, int, int, long); 176 static void cg14_copyrows(void *, int, int, int); 177 static void cg14_eraserows(void *, int, int, long); 178 #endif /* NSX > 0 */ 179 180 #endif 181 182 /* 183 * Match a cgfourteen. 184 */ 185 int 186 cgfourteenmatch(device_t parent, struct cfdata *cf, void *aux) 187 { 188 union obio_attach_args *uoba = aux; 189 struct sbus_attach_args *sa = &uoba->uoba_sbus; 190 191 /* 192 * The cgfourteen is a local-bus video adaptor, accessed directly 193 * via the processor, and not through device space or an external 194 * bus. Thus we look _only_ at the obio bus. 195 * Additionally, these things exist only on the Sun4m. 196 */ 197 198 if (uoba->uoba_isobio4 != 0 || !CPU_ISSUN4M) 199 return (0); 200 201 /* Check driver name */ 202 return (strcmp(cf->cf_name, sa->sa_name) == 0); 203 } 204 205 #if NWSDISPLAY > 0 206 static int cg14_ioctl(void *, void *, u_long, void *, int, struct lwp *); 207 static paddr_t cg14_mmap(void *, void *, off_t, int); 208 static void cg14_init_screen(void *, struct vcons_screen *, int, long *); 209 210 211 struct wsdisplay_accessops cg14_accessops = { 212 cg14_ioctl, 213 cg14_mmap, 214 NULL, /* alloc_screen */ 215 NULL, /* free_screen */ 216 NULL, /* show_screen */ 217 NULL, /* load_font */ 218 NULL, /* pollc */ 219 NULL /* scroll */ 220 }; 221 #endif 222 223 /* 224 * Attach a display. We need to notice if it is the console, too. 225 */ 226 void 227 cgfourteenattach(device_t parent, device_t self, void *aux) 228 { 229 union obio_attach_args *uoba = aux; 230 struct sbus_attach_args *sa = &uoba->uoba_sbus; 231 struct cgfourteen_softc *sc = device_private(self); 232 struct fbdevice *fb = &sc->sc_fb; 233 bus_space_handle_t bh; 234 int node; 235 volatile uint32_t *lut; 236 int i, isconsole, items; 237 uint32_t fbva[2] = {0, 0}; 238 uint32_t *ptr = fbva; 239 #if NSX > 0 240 device_t dv; 241 deviter_t di; 242 #endif 243 244 sc->sc_dev = self; 245 sc->sc_opens = 0; 246 node = sa->sa_node; 247 248 /* Remember cookies for cgfourteenmmap() */ 249 sc->sc_bustag = sa->sa_bustag; 250 251 fb->fb_driver = &cgfourteenfbdriver; 252 fb->fb_device = sc->sc_dev; 253 /* Mask out invalid flags from the user. */ 254 fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK; 255 256 fb->fb_type.fb_type = FBTYPE_MDICOLOR; 257 fb->fb_type.fb_depth = 32; 258 259 fb_setsize_obp(fb, sc->sc_fb.fb_type.fb_depth, 1152, 900, node); 260 261 fb->fb_type.fb_cmsize = CG14_CLUT_SIZE; 262 263 if (sa->sa_nreg < 2) { 264 printf("%s: only %d register sets\n", 265 device_xname(self), sa->sa_nreg); 266 return; 267 } 268 memcpy(sc->sc_physadr, sa->sa_reg, 269 sa->sa_nreg * sizeof(struct sbus_reg)); 270 271 sc->sc_vramsize = sc->sc_physadr[CG14_PXL_IDX].sbr_size; 272 fb->fb_type.fb_size = sc->sc_vramsize; 273 274 printf(": %d MB VRAM", (uint32_t)(sc->sc_vramsize >> 20)); 275 /* 276 * Now map in the 8 useful pages of registers 277 */ 278 if (sa->sa_size < 0x10000) { 279 #ifdef DIAGNOSTIC 280 printf("warning: can't find all cgfourteen registers...\n"); 281 #endif 282 sa->sa_size = 0x10000; 283 } 284 if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, 285 sa->sa_offset, 286 sa->sa_size, 287 0 /*BUS_SPACE_MAP_LINEAR*/, 288 &bh) != 0) { 289 printf("%s: cannot map control registers\n", 290 device_xname(self)); 291 return; 292 } 293 sc->sc_regh = bh; 294 sc->sc_regaddr = BUS_ADDR(sa->sa_slot, sa->sa_offset); 295 sc->sc_fbaddr = BUS_ADDR(sc->sc_physadr[CG14_PXL_IDX].sbr_slot, 296 sc->sc_physadr[CG14_PXL_IDX].sbr_offset); 297 298 sc->sc_ctl = (struct cg14ctl *) (bh); 299 sc->sc_hwc = (struct cg14curs *) (bh + CG14_OFFSET_CURS); 300 sc->sc_dac = (struct cg14dac *) (bh + CG14_OFFSET_DAC); 301 sc->sc_xlut = (struct cg14xlut *) (bh + CG14_OFFSET_XLUT); 302 sc->sc_clut1 = (struct cg14clut *) (bh + CG14_OFFSET_CLUT1); 303 sc->sc_clut2 = (struct cg14clut *) (bh + CG14_OFFSET_CLUT2); 304 sc->sc_clut3 = (struct cg14clut *) (bh + CG14_OFFSET_CLUT3); 305 sc->sc_clutincr = (u_int *) (bh + CG14_OFFSET_CLUTINCR); 306 307 /* 308 * Let the user know that we're here 309 */ 310 printf(": %dx%d", 311 fb->fb_type.fb_width, fb->fb_type.fb_height); 312 313 /* 314 * Enable the video. 315 */ 316 cg14_set_video(sc, 1); 317 318 /* 319 * Grab the initial colormap 320 */ 321 lut = sc->sc_clut1->clut_lut; 322 for (i = 0; i < CG14_CLUT_SIZE; i++) 323 sc->sc_cmap.cm_chip[i] = lut[i]; 324 325 /* See if we're the console */ 326 isconsole = fb_is_console(node); 327 328 #if NWSDISPLAY > 0 329 prom_getprop(sa->sa_node, "address", 4, &items, &ptr); 330 if (fbva[1] == 0) { 331 if (sbus_bus_map( sc->sc_bustag, 332 sc->sc_physadr[CG14_PXL_IDX].sbr_slot, 333 sc->sc_physadr[CG14_PXL_IDX].sbr_offset, 334 sc->sc_vramsize, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 335 &bh) != 0) { 336 printf("%s: cannot map pixels\n", 337 device_xname(sc->sc_dev)); 338 return; 339 } 340 sc->sc_fb.fb_pixels = bus_space_vaddr(sc->sc_bustag, bh); 341 } else { 342 sc->sc_fb.fb_pixels = (void *)fbva[1]; 343 } 344 345 if (isconsole) 346 printf(" (console)\n"); 347 else 348 printf("\n"); 349 350 sc->sc_depth = 8; 351 352 #if NSX > 0 353 /* see if we've got an SX to help us */ 354 sc->sc_sx = NULL; 355 for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); 356 dv != NULL; 357 dv = deviter_next(&di)) { 358 if (device_is_a(dv, "sx")) { 359 sc->sc_sx = device_private(dv); 360 } 361 } 362 deviter_release(&di); 363 if (sc->sc_sx != NULL) { 364 sc->sc_fb_paddr = bus_space_mmap(sc->sc_bustag, 365 sc->sc_fbaddr, 0, 0, 0) & 0xfffff000; 366 aprint_normal_dev(sc->sc_dev, "using %s\n", 367 device_xname(sc->sc_sx->sc_dev)); 368 aprint_debug_dev(sc->sc_dev, "fb paddr: %08x\n", 369 sc->sc_fb_paddr); 370 sx_write(sc->sc_sx, SX_PAGE_BOUND_LOWER, sc->sc_fb_paddr); 371 sx_write(sc->sc_sx, SX_PAGE_BOUND_UPPER, 372 sc->sc_fb_paddr + 0x03ffffff); 373 } 374 cg14_wait_idle(sc); 375 #endif 376 cg14_setup_wsdisplay(sc, isconsole); 377 #endif 378 379 /* Attach to /dev/fb */ 380 fb_attach(&sc->sc_fb, isconsole); 381 } 382 383 /* 384 * Keep track of the number of opens made. In the 24-bit driver, we need to 385 * switch to 24-bit mode on the first open, and switch back to 8-bit on 386 * the last close. This kind of nonsense is needed to give screenblank 387 * a fighting chance of working. 388 */ 389 390 int 391 cgfourteenopen(dev_t dev, int flags, int mode, struct lwp *l) 392 { 393 struct cgfourteen_softc *sc; 394 int oldopens; 395 396 sc = device_lookup_private(&cgfourteen_cd, minor(dev)); 397 if (sc == NULL) 398 return(ENXIO); 399 oldopens = sc->sc_opens++; 400 401 /* Setup the cg14 as we want it, and save the original PROM state */ 402 if (oldopens == 0) /* first open only, to make screenblank work */ 403 cg14_init(sc); 404 405 return (0); 406 } 407 408 int 409 cgfourteenclose(dev_t dev, int flags, int mode, struct lwp *l) 410 { 411 struct cgfourteen_softc *sc = 412 device_lookup_private(&cgfourteen_cd, minor(dev)); 413 int opens; 414 415 opens = --sc->sc_opens; 416 if (sc->sc_opens < 0) 417 opens = sc->sc_opens = 0; 418 419 /* 420 * Restore video state to make the PROM happy, on last close. 421 */ 422 if (opens == 0) { 423 cg14_reset(sc); 424 #if NSX > 0 425 if (sc->sc_sx) 426 glyphcache_wipe(&sc->sc_gc); 427 #endif 428 } 429 return (0); 430 } 431 432 int 433 cgfourteenioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 434 { 435 struct cgfourteen_softc *sc = 436 device_lookup_private(&cgfourteen_cd, minor(dev)); 437 struct fbgattr *fba; 438 int error; 439 440 switch (cmd) { 441 442 case FBIOGTYPE: 443 *(struct fbtype *)data = sc->sc_fb.fb_type; 444 break; 445 446 case FBIOGATTR: 447 fba = (struct fbgattr *)data; 448 fba->real_type = FBTYPE_MDICOLOR; 449 fba->owner = 0; /* XXX ??? */ 450 fba->fbtype = sc->sc_fb.fb_type; 451 fba->sattr.flags = 0; 452 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 453 fba->sattr.dev_specific[0] = -1; 454 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 455 fba->emu_types[1] = -1; 456 break; 457 458 case FBIOGETCMAP: 459 return(cg14_get_cmap((struct fbcmap *)data, &sc->sc_cmap, 460 CG14_CLUT_SIZE)); 461 462 case FBIOPUTCMAP: 463 /* copy to software map */ 464 #define p ((struct fbcmap *)data) 465 error = cg14_put_cmap(p, &sc->sc_cmap, CG14_CLUT_SIZE); 466 if (error) 467 return (error); 468 /* now blast them into the chip */ 469 /* XXX should use retrace interrupt */ 470 cg14_load_hwcmap(sc, p->index, p->count); 471 #undef p 472 break; 473 474 case FBIOGVIDEO: 475 *(int *)data = cg14_get_video(sc); 476 break; 477 478 case FBIOSVIDEO: 479 cg14_set_video(sc, *(int *)data); 480 break; 481 482 case CG14_SET_PIXELMODE: { 483 int depth = *(int *)data; 484 485 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) 486 return EINVAL; 487 488 cg14_set_depth(sc, depth); 489 } 490 break; 491 default: 492 return (ENOTTY); 493 } 494 return (0); 495 } 496 497 /* 498 * Undo the effect of an FBIOSVIDEO that turns the video off. 499 */ 500 static void 501 cgfourteenunblank(device_t dev) 502 { 503 struct cgfourteen_softc *sc = device_private(dev); 504 505 cg14_set_video(sc, 1); 506 #if NWSDISPLAY > 0 507 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) { 508 cg14_set_depth(sc, 8); 509 cg14_init_cmap(sc); 510 vcons_redraw_screen(sc->sc_vd.active); 511 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 512 } 513 #endif 514 } 515 516 /* 517 * Return the address that would map the given device at the given 518 * offset, allowing for the given protection, or return -1 for error. 519 */ 520 paddr_t 521 cgfourteenmmap(dev_t dev, off_t off, int prot) 522 { 523 struct cgfourteen_softc *sc = 524 device_lookup_private(&cgfourteen_cd, minor(dev)); 525 off_t offset = -1; 526 527 if (off & PGOFSET) 528 panic("cgfourteenmmap"); 529 530 if (off < 0) 531 return (-1); 532 533 if (off >= 0 && off < 0x10000) { 534 offset = sc->sc_regaddr; 535 } else if (off >= CG14_CURSOR_VOFF && 536 off < (CG14_CURSOR_VOFF + 0x1000)) { 537 offset = sc->sc_regaddr + CG14_OFFSET_CURS; 538 off -= CG14_CURSOR_VOFF; 539 } else if (off >= CG14_DIRECT_VOFF && 540 off < (CG14_DIRECT_VOFF + sc->sc_vramsize)) { 541 offset = sc->sc_fbaddr + CG14_FB_VRAM; 542 off -= CG14_DIRECT_VOFF; 543 } else if (off >= CG14_BGR_VOFF && 544 off < (CG14_BGR_VOFF + sc->sc_vramsize)) { 545 offset = sc->sc_fbaddr + CG14_FB_CBGR; 546 off -= CG14_BGR_VOFF; 547 } else if (off >= CG14_X32_VOFF && 548 off < (CG14_X32_VOFF + (sc->sc_vramsize >> 2))) { 549 offset = sc->sc_fbaddr + CG14_FB_PX32; 550 off -= CG14_X32_VOFF; 551 } else if (off >= CG14_B32_VOFF && 552 off < (CG14_B32_VOFF + (sc->sc_vramsize >> 2))) { 553 offset = sc->sc_fbaddr + CG14_FB_PB32; 554 off -= CG14_B32_VOFF; 555 } else if (off >= CG14_G32_VOFF && 556 off < (CG14_G32_VOFF + (sc->sc_vramsize >> 2))) { 557 offset = sc->sc_fbaddr + CG14_FB_PG32; 558 off -= CG14_G32_VOFF; 559 } else if (off >= CG14_R32_VOFF && 560 off < CG14_R32_VOFF + (sc->sc_vramsize >> 2)) { 561 offset = sc->sc_fbaddr + CG14_FB_PR32; 562 off -= CG14_R32_VOFF; 563 #if NSX > 0 564 /* 565 * for convenience we also map the SX ranges here: 566 * - one page userland registers 567 * - CG14-sized IO space at 0x800000000 ( not a typo, it's above 4GB ) 568 */ 569 } else if (sc->sc_sx == NULL) { 570 return -1; 571 } else if (off >= CG14_SXREG_VOFF && 572 off < (CG14_SXREG_VOFF + 0x400)) { 573 return (bus_space_mmap(sc->sc_sx->sc_tag, sc->sc_sx->sc_uregs, 574 0, prot, BUS_SPACE_MAP_LINEAR)); 575 } else if (off >= CG14_SXIO_VOFF && 576 off < (CG14_SXIO_VOFF + 0x03ffffff)) { 577 return (bus_space_mmap(sc->sc_sx->sc_tag, 0x800000000LL, 578 sc->sc_fb_paddr + (off - CG14_SXIO_VOFF), 579 prot, BUS_SPACE_MAP_LINEAR)); 580 #endif 581 } else 582 return -1; 583 584 return (bus_space_mmap(sc->sc_bustag, offset, off, prot, 585 BUS_SPACE_MAP_LINEAR)); 586 } 587 588 int 589 cgfourteenpoll(dev_t dev, int events, struct lwp *l) 590 { 591 592 return (seltrue(dev, events, l)); 593 } 594 595 /* 596 * Miscellaneous helper functions 597 */ 598 599 /* Initialize the framebuffer, storing away useful state for later reset */ 600 static void 601 cg14_init(struct cgfourteen_softc *sc) 602 { 603 cg14_set_depth(sc, 32); 604 } 605 606 static void 607 /* Restore the state saved on cg14_init */ 608 cg14_reset(struct cgfourteen_softc *sc) 609 { 610 cg14_set_depth(sc, 8); 611 } 612 613 /* Enable/disable video display; power down monitor if DPMS-capable */ 614 static void 615 cg14_set_video(struct cgfourteen_softc *sc, int enable) 616 { 617 /* 618 * We can only use DPMS to power down the display if the chip revision 619 * is greater than 0. 620 */ 621 if (enable) { 622 if ((sc->sc_ctl->ctl_rsr & CG14_RSR_REVMASK) > 0) 623 sc->sc_ctl->ctl_mctl |= (CG14_MCTL_ENABLEVID | 624 CG14_MCTL_POWERCTL); 625 else 626 sc->sc_ctl->ctl_mctl |= CG14_MCTL_ENABLEVID; 627 } else { 628 if ((sc->sc_ctl->ctl_rsr & CG14_RSR_REVMASK) > 0) 629 sc->sc_ctl->ctl_mctl &= ~(CG14_MCTL_ENABLEVID | 630 CG14_MCTL_POWERCTL); 631 else 632 sc->sc_ctl->ctl_mctl &= ~CG14_MCTL_ENABLEVID; 633 } 634 } 635 636 /* Get status of video display */ 637 static int 638 cg14_get_video(struct cgfourteen_softc *sc) 639 { 640 return ((sc->sc_ctl->ctl_mctl & CG14_MCTL_ENABLEVID) != 0); 641 } 642 643 /* Read the software shadow colormap */ 644 static int 645 cg14_get_cmap(struct fbcmap *p, union cg14cmap *cm, int cmsize) 646 { 647 u_int i, start, count; 648 u_char *cp; 649 int error; 650 651 start = p->index; 652 count = p->count; 653 if (start >= cmsize || count > cmsize - start) 654 return (EINVAL); 655 656 for (cp = &cm->cm_map[start][0], i = 0; i < count; cp += 4, i++) { 657 error = copyout(&cp[3], &p->red[i], 1); 658 if (error) 659 return error; 660 error = copyout(&cp[2], &p->green[i], 1); 661 if (error) 662 return error; 663 error = copyout(&cp[1], &p->blue[i], 1); 664 if (error) 665 return error; 666 } 667 return (0); 668 } 669 670 /* Write the software shadow colormap */ 671 static int 672 cg14_put_cmap(struct fbcmap *p, union cg14cmap *cm, int cmsize) 673 { 674 u_int i, start, count; 675 u_char *cp; 676 u_char cmap[256][4]; 677 int error; 678 679 start = p->index; 680 count = p->count; 681 if (start >= cmsize || count > cmsize - start) 682 return (EINVAL); 683 684 memcpy(&cmap, &cm->cm_map, sizeof cmap); 685 for (cp = &cmap[start][0], i = 0; i < count; cp += 4, i++) { 686 error = copyin(&p->red[i], &cp[3], 1); 687 if (error) 688 return error; 689 error = copyin(&p->green[i], &cp[2], 1); 690 if (error) 691 return error; 692 error = copyin(&p->blue[i], &cp[1], 1); 693 if (error) 694 return error; 695 cp[0] = 0; /* no alpha channel */ 696 } 697 memcpy(&cm->cm_map, &cmap, sizeof cmap); 698 return (0); 699 } 700 701 static void 702 cg14_load_hwcmap(struct cgfourteen_softc *sc, int start, int ncolors) 703 { 704 /* XXX switch to auto-increment, and on retrace intr */ 705 706 /* Setup pointers to source and dest */ 707 uint32_t *colp = &sc->sc_cmap.cm_chip[start]; 708 volatile uint32_t *lutp = &sc->sc_clut1->clut_lut[start]; 709 710 /* Copy by words */ 711 while (--ncolors >= 0) 712 *lutp++ = *colp++; 713 } 714 715 static void 716 cg14_setup_wsdisplay(struct cgfourteen_softc *sc, int is_cons) 717 { 718 struct wsemuldisplaydev_attach_args aa; 719 struct rasops_info *ri; 720 long defattr; 721 722 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 723 "default", 724 0, 0, 725 NULL, 726 8, 16, 727 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 728 WSSCREEN_RESIZE, 729 NULL 730 }; 731 cg14_set_depth(sc, 8); 732 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 733 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 734 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 735 vcons_init(&sc->sc_vd, sc, &sc->sc_defaultscreen_descr, 736 &cg14_accessops); 737 sc->sc_vd.init_screen = cg14_init_screen; 738 sc->sc_vd.show_screen_cookie = &sc->sc_gc; 739 sc->sc_vd.show_screen_cb = glyphcache_adapt; 740 741 ri = &sc->sc_console_screen.scr_ri; 742 743 sc->sc_gc.gc_bitblt = cg14_bitblt_gc; 744 sc->sc_gc.gc_blitcookie = sc; 745 sc->sc_gc.gc_rectfill = cg14_rectfill_a; 746 sc->sc_gc.gc_rop = 0xc; 747 if (is_cons) { 748 vcons_init_screen(&sc->sc_vd, &sc->sc_console_screen, 1, 749 &defattr); 750 751 /* clear the screen with the default background colour */ 752 if (sc->sc_sx != NULL) { 753 cg14_rectfill(sc, 0, 0, ri->ri_width, ri->ri_height, 754 ri->ri_devcmap[(defattr >> 16) & 0xf]); 755 } else { 756 memset(sc->sc_fb.fb_pixels, 757 ri->ri_devcmap[(defattr >> 16) & 0xf], 758 ri->ri_stride * ri->ri_height); 759 } 760 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 761 762 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 763 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 764 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 765 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 766 glyphcache_init(&sc->sc_gc, sc->sc_fb.fb_type.fb_height + 5, 767 (sc->sc_vramsize / sc->sc_fb.fb_type.fb_width) - 768 sc->sc_fb.fb_type.fb_height - 5, 769 sc->sc_fb.fb_type.fb_width, 770 ri->ri_font->fontwidth, 771 ri->ri_font->fontheight, 772 defattr); 773 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 774 defattr); 775 vcons_replay_msgbuf(&sc->sc_console_screen); 776 } else { 777 /* 778 * since we're not the console we can postpone the rest 779 * until someone actually allocates a screen for us 780 */ 781 glyphcache_init(&sc->sc_gc, sc->sc_fb.fb_type.fb_height + 5, 782 (sc->sc_vramsize / sc->sc_fb.fb_type.fb_width) - 783 sc->sc_fb.fb_type.fb_height - 5, 784 sc->sc_fb.fb_type.fb_width, 785 ri->ri_font->fontwidth, 786 ri->ri_font->fontheight, 787 DEFATTR); 788 } 789 790 cg14_init_cmap(sc); 791 792 aa.console = is_cons; 793 aa.scrdata = &sc->sc_screenlist; 794 aa.accessops = &cg14_accessops; 795 aa.accesscookie = &sc->sc_vd; 796 797 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint); 798 } 799 800 static void 801 cg14_init_cmap(struct cgfourteen_softc *sc) 802 { 803 struct rasops_info *ri = &sc->sc_console_screen.scr_ri; 804 int i, j = 0; 805 uint8_t cmap[768]; 806 807 rasops_get_cmap(ri, cmap, sizeof(cmap)); 808 809 for (i = 0; i < 256; i++) { 810 811 sc->sc_cmap.cm_map[i][3] = cmap[j]; 812 sc->sc_cmap.cm_map[i][2] = cmap[j + 1]; 813 sc->sc_cmap.cm_map[i][1] = cmap[j + 2]; 814 j += 3; 815 } 816 cg14_load_hwcmap(sc, 0, 256); 817 } 818 819 static int 820 cg14_putcmap(struct cgfourteen_softc *sc, struct wsdisplay_cmap *cm) 821 { 822 u_int index = cm->index; 823 u_int count = cm->count; 824 int i, error; 825 u_char rbuf[256], gbuf[256], bbuf[256]; 826 827 if (cm->index >= 256 || cm->count > 256 || 828 (cm->index + cm->count) > 256) 829 return EINVAL; 830 error = copyin(cm->red, &rbuf[index], count); 831 if (error) 832 return error; 833 error = copyin(cm->green, &gbuf[index], count); 834 if (error) 835 return error; 836 error = copyin(cm->blue, &bbuf[index], count); 837 if (error) 838 return error; 839 840 for (i = 0; i < count; i++) { 841 sc->sc_cmap.cm_map[index][3] = rbuf[index]; 842 sc->sc_cmap.cm_map[index][2] = gbuf[index]; 843 sc->sc_cmap.cm_map[index][1] = bbuf[index]; 844 845 index++; 846 } 847 cg14_load_hwcmap(sc, 0, 256); 848 return 0; 849 } 850 851 static int 852 cg14_getcmap(struct cgfourteen_softc *sc, struct wsdisplay_cmap *cm) 853 { 854 uint8_t rbuf[256], gbuf[256], bbuf[256]; 855 u_int index = cm->index; 856 u_int count = cm->count; 857 int error, i; 858 859 if (index >= 255 || count > 256 || index + count > 256) 860 return EINVAL; 861 862 863 for (i = 0; i < count; i++) { 864 rbuf[i] = sc->sc_cmap.cm_map[index][3]; 865 gbuf[i] = sc->sc_cmap.cm_map[index][2]; 866 bbuf[i] = sc->sc_cmap.cm_map[index][1]; 867 868 index++; 869 } 870 error = copyout(rbuf, cm->red, count); 871 if (error) 872 return error; 873 error = copyout(gbuf, cm->green, count); 874 if (error) 875 return error; 876 error = copyout(bbuf, cm->blue, count); 877 if (error) 878 return error; 879 880 return 0; 881 } 882 883 static int 884 cg14_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 885 struct lwp *l) 886 { 887 struct vcons_data *vd = v; 888 struct cgfourteen_softc *sc = vd->cookie; 889 struct wsdisplay_fbinfo *wdf; 890 struct vcons_screen *ms = vd->active; 891 892 switch (cmd) { 893 894 case WSDISPLAYIO_GTYPE: 895 *(uint32_t *)data = WSDISPLAY_TYPE_SUNCG14; 896 return 0; 897 898 case WSDISPLAYIO_GINFO: 899 wdf = (void *)data; 900 wdf->height = ms->scr_ri.ri_height; 901 wdf->width = ms->scr_ri.ri_width; 902 wdf->depth = 32; 903 wdf->cmsize = 256; 904 return 0; 905 906 case WSDISPLAYIO_GETCMAP: 907 return cg14_getcmap(sc, 908 (struct wsdisplay_cmap *)data); 909 910 case WSDISPLAYIO_PUTCMAP: 911 return cg14_putcmap(sc, 912 (struct wsdisplay_cmap *)data); 913 914 case WSDISPLAYIO_LINEBYTES: 915 *(u_int *)data = ms->scr_ri.ri_stride << 2; 916 return 0; 917 918 case WSDISPLAYIO_SMODE: 919 { 920 int new_mode = *(int*)data; 921 if (new_mode != sc->sc_mode) { 922 sc->sc_mode = new_mode; 923 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 924 bus_space_write_1(sc->sc_bustag, 925 sc->sc_regh, 926 CG14_CURSOR_CONTROL, 0); 927 928 cg14_set_depth(sc, 8); 929 cg14_init_cmap(sc); 930 #if NSX > 0 931 if (sc->sc_sx) 932 glyphcache_wipe(&sc->sc_gc); 933 #endif 934 vcons_redraw_screen(ms); 935 } else { 936 937 cg14_set_depth(sc, 32); 938 } 939 } 940 } 941 return 0; 942 case WSDISPLAYIO_SVIDEO: 943 cg14_set_video(sc, *(int *)data); 944 return 0; 945 case WSDISPLAYIO_GVIDEO: 946 return cg14_get_video(sc) ? 947 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 948 case WSDISPLAYIO_GCURPOS: 949 { 950 struct wsdisplay_curpos *cp = (void *)data; 951 952 cp->x = sc->sc_cursor.cc_pos.x; 953 cp->y = sc->sc_cursor.cc_pos.y; 954 } 955 return 0; 956 case WSDISPLAYIO_SCURPOS: 957 { 958 struct wsdisplay_curpos *cp = (void *)data; 959 960 cg14_move_cursor(sc, cp->x, cp->y); 961 } 962 return 0; 963 case WSDISPLAYIO_GCURMAX: 964 { 965 struct wsdisplay_curpos *cp = (void *)data; 966 967 cp->x = 32; 968 cp->y = 32; 969 } 970 return 0; 971 case WSDISPLAYIO_SCURSOR: 972 { 973 struct wsdisplay_cursor *cursor = (void *)data; 974 975 return cg14_do_cursor(sc, cursor); 976 } 977 case PCI_IOC_CFGREAD: 978 case PCI_IOC_CFGWRITE: 979 return EINVAL; 980 981 } 982 return EPASSTHROUGH; 983 } 984 985 static paddr_t 986 cg14_mmap(void *v, void *vs, off_t offset, int prot) 987 { 988 struct vcons_data *vd = v; 989 struct cgfourteen_softc *sc = vd->cookie; 990 991 /* allow mmap()ing the full framebuffer, not just what we use */ 992 if (offset < sc->sc_vramsize) 993 return bus_space_mmap(sc->sc_bustag, 994 BUS_ADDR(sc->sc_physadr[CG14_PXL_IDX].sbr_slot, 995 sc->sc_physadr[CG14_PXL_IDX].sbr_offset), 996 offset + CG14_FB_CBGR, prot, BUS_SPACE_MAP_LINEAR); 997 998 return -1; 999 } 1000 1001 static void 1002 cg14_init_screen(void *cookie, struct vcons_screen *scr, 1003 int existing, long *defattr) 1004 { 1005 struct cgfourteen_softc *sc = cookie; 1006 struct rasops_info *ri = &scr->scr_ri; 1007 1008 ri->ri_depth = 8; 1009 ri->ri_width = sc->sc_fb.fb_type.fb_width; 1010 ri->ri_height = sc->sc_fb.fb_type.fb_height; 1011 ri->ri_stride = ri->ri_width; 1012 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 1013 1014 ri->ri_bits = (char *)sc->sc_fb.fb_pixels; 1015 1016 scr->scr_flags |= VCONS_LOADFONT; 1017 #if NSX > 0 1018 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 1019 1020 /* 1021 * unaligned copies with horizontal overlap are slow, so don't bother 1022 * handling them in cg14_bitblt() and use putchar() instead 1023 */ 1024 if (sc->sc_sx != NULL) { 1025 scr->scr_flags |= VCONS_NO_COPYCOLS; 1026 } else 1027 #endif 1028 scr->scr_flags |= VCONS_DONT_READ; 1029 1030 if (existing) { 1031 ri->ri_flg |= RI_CLEAR; 1032 } 1033 1034 rasops_init(ri, 0, 0); 1035 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 1036 WSSCREEN_RESIZE; 1037 1038 rasops_reconfig(ri, 1039 sc->sc_fb.fb_type.fb_height / ri->ri_font->fontheight, 1040 sc->sc_fb.fb_type.fb_width / ri->ri_font->fontwidth); 1041 1042 ri->ri_hw = scr; 1043 #if NSX > 0 1044 if (sc->sc_sx != NULL) { 1045 ri->ri_ops.copyrows = cg14_copyrows; 1046 ri->ri_ops.copycols = cg14_copycols; 1047 ri->ri_ops.eraserows = cg14_eraserows; 1048 ri->ri_ops.erasecols = cg14_erasecols; 1049 ri->ri_ops.cursor = cg14_cursor; 1050 if (FONT_IS_ALPHA(ri->ri_font)) { 1051 ri->ri_ops.putchar = cg14_putchar_aa; 1052 } else 1053 ri->ri_ops.putchar = cg14_putchar; 1054 } 1055 #endif /* NSX > 0 */ 1056 } 1057 1058 static void 1059 cg14_set_depth(struct cgfourteen_softc *sc, int depth) 1060 { 1061 int i; 1062 1063 if (sc->sc_depth == depth) 1064 return; 1065 1066 switch (depth) { 1067 case 8: 1068 bus_space_write_1(sc->sc_bustag, sc->sc_regh, 1069 CG14_MCTL, CG14_MCTL_ENABLEVID | 1070 CG14_MCTL_PIXMODE_8 | CG14_MCTL_POWERCTL); 1071 sc->sc_depth = 8; 1072 /* everything is CLUT1 */ 1073 for (i = 0; i < CG14_CLUT_SIZE; i++) 1074 sc->sc_xlut->xlut_lut[i] = 0; 1075 break; 1076 case 32: 1077 bus_space_write_1(sc->sc_bustag, sc->sc_regh, 1078 CG14_MCTL, CG14_MCTL_ENABLEVID | 1079 CG14_MCTL_PIXMODE_32 | CG14_MCTL_POWERCTL); 1080 sc->sc_depth = 32; 1081 for (i = 0; i < CG14_CLUT_SIZE; i++) 1082 sc->sc_xlut->xlut_lut[i] = 0; 1083 break; 1084 default: 1085 printf("%s: can't change to depth %d\n", 1086 device_xname(sc->sc_dev), depth); 1087 } 1088 } 1089 1090 static void 1091 cg14_move_cursor(struct cgfourteen_softc *sc, int x, int y) 1092 { 1093 uint32_t pos; 1094 1095 sc->sc_cursor.cc_pos.x = x; 1096 sc->sc_cursor.cc_pos.y = y; 1097 pos = ((sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x ) << 16) | 1098 ((sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y ) & 0xffff); 1099 bus_space_write_4(sc->sc_bustag, sc->sc_regh, CG14_CURSOR_X, pos); 1100 } 1101 1102 static int 1103 cg14_do_cursor(struct cgfourteen_softc *sc, struct wsdisplay_cursor *cur) 1104 { 1105 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 1106 1107 bus_space_write_1(sc->sc_bustag, sc->sc_regh, 1108 CG14_CURSOR_CONTROL, cur->enable ? CG14_CRSR_ENABLE : 0); 1109 } 1110 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 1111 1112 sc->sc_cursor.cc_hot.x = cur->hot.x; 1113 sc->sc_cursor.cc_hot.y = cur->hot.y; 1114 cur->which |= WSDISPLAY_CURSOR_DOPOS; 1115 } 1116 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 1117 1118 cg14_move_cursor(sc, cur->pos.x, cur->pos.y); 1119 } 1120 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 1121 int i; 1122 uint32_t val; 1123 1124 if ((cur->cmap.index > 2) || (cur->cmap.count > 3) || 1125 (cur->cmap.index + cur->cmap.count > 3)) 1126 return EINVAL; 1127 1128 for (i = 0; i < min(cur->cmap.count, 3); i++) { 1129 val = (cur->cmap.red[i] ) | 1130 (cur->cmap.green[i] << 8) | 1131 (cur->cmap.blue[i] << 16); 1132 bus_space_write_4(sc->sc_bustag, sc->sc_regh, 1133 CG14_CURSOR_COLOR1 + ((i + cur->cmap.index) << 2), 1134 val); 1135 } 1136 } 1137 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 1138 uint32_t buffer[32], latch, tmp; 1139 int i; 1140 1141 copyin(cur->mask, buffer, 128); 1142 for (i = 0; i < 32; i++) { 1143 latch = 0; 1144 tmp = buffer[i] & 0x80808080; 1145 latch |= tmp >> 7; 1146 tmp = buffer[i] & 0x40404040; 1147 latch |= tmp >> 5; 1148 tmp = buffer[i] & 0x20202020; 1149 latch |= tmp >> 3; 1150 tmp = buffer[i] & 0x10101010; 1151 latch |= tmp >> 1; 1152 tmp = buffer[i] & 0x08080808; 1153 latch |= tmp << 1; 1154 tmp = buffer[i] & 0x04040404; 1155 latch |= tmp << 3; 1156 tmp = buffer[i] & 0x02020202; 1157 latch |= tmp << 5; 1158 tmp = buffer[i] & 0x01010101; 1159 latch |= tmp << 7; 1160 bus_space_write_4(sc->sc_bustag, sc->sc_regh, 1161 CG14_CURSOR_PLANE0 + (i << 2), latch); 1162 } 1163 copyin(cur->image, buffer, 128); 1164 for (i = 0; i < 32; i++) { 1165 latch = 0; 1166 tmp = buffer[i] & 0x80808080; 1167 latch |= tmp >> 7; 1168 tmp = buffer[i] & 0x40404040; 1169 latch |= tmp >> 5; 1170 tmp = buffer[i] & 0x20202020; 1171 latch |= tmp >> 3; 1172 tmp = buffer[i] & 0x10101010; 1173 latch |= tmp >> 1; 1174 tmp = buffer[i] & 0x08080808; 1175 latch |= tmp << 1; 1176 tmp = buffer[i] & 0x04040404; 1177 latch |= tmp << 3; 1178 tmp = buffer[i] & 0x02020202; 1179 latch |= tmp << 5; 1180 tmp = buffer[i] & 0x01010101; 1181 latch |= tmp << 7; 1182 bus_space_write_4(sc->sc_bustag, sc->sc_regh, 1183 CG14_CURSOR_PLANE1 + (i << 2), latch); 1184 } 1185 } 1186 return 0; 1187 } 1188 1189 #if NSX > 0 1190 1191 static void 1192 cg14_wait_idle(struct cgfourteen_softc *sc) 1193 { 1194 } 1195 1196 static void 1197 cg14_rectfill(struct cgfourteen_softc *sc, int x, int y, int wi, int he, 1198 uint32_t colour) 1199 { 1200 uint32_t addr, pptr; 1201 int line, cnt, pre, words; 1202 int stride = sc->sc_fb.fb_type.fb_width; 1203 1204 addr = sc->sc_fb_paddr + x + stride * y; 1205 sx_write(sc->sc_sx, SX_QUEUED(8), colour); 1206 sx_write(sc->sc_sx, SX_QUEUED(9), colour); 1207 /* 1208 * Calculate the number of pixels we need to do one by one 1209 * until we're 32bit aligned, then do the rest in 32bit 1210 * mode. Assumes that stride is always a multiple of 4. 1211 */ 1212 /* TODO: use 32bit writes with byte mask instead */ 1213 pre = addr & 3; 1214 if (pre != 0) pre = 4 - pre; 1215 for (line = 0; line < he; line++) { 1216 pptr = addr; 1217 cnt = wi; 1218 if (pre) { 1219 sta(pptr & ~7, ASI_SX, SX_STBS(8, pre - 1, pptr & 7)); 1220 pptr += pre; 1221 cnt -= pre; 1222 } 1223 /* now do the aligned pixels in 32bit chunks */ 1224 while(cnt > 3) { 1225 words = min(32, cnt >> 2); 1226 sta(pptr & ~7, ASI_SX, SX_STS(8, words - 1, pptr & 7)); 1227 pptr += words << 2; 1228 cnt -= words << 2; 1229 } 1230 /* do any remaining pixels byte-wise again */ 1231 if (cnt > 0) 1232 sta(pptr & ~7, ASI_SX, SX_STBS(8, cnt - 1, pptr & 7)); 1233 addr += stride; 1234 } 1235 } 1236 1237 static void 1238 cg14_rectfill_a(void *cookie, int dstx, int dsty, 1239 int width, int height, long attr) 1240 { 1241 struct cgfourteen_softc *sc = cookie; 1242 1243 cg14_rectfill(sc, dstx, dsty, width, height, 1244 sc->sc_vd.active->scr_ri.ri_devcmap[(attr >> 24 & 0xf)]); 1245 } 1246 1247 static void 1248 cg14_invert(struct cgfourteen_softc *sc, int x, int y, int wi, int he) 1249 { 1250 uint32_t addr, pptr; 1251 int line, cnt, pre, words; 1252 int stride = sc->sc_fb.fb_type.fb_width; 1253 1254 addr = sc->sc_fb_paddr + x + stride * y; 1255 sx_write(sc->sc_sx, SX_ROP_CONTROL, 0x33); /* ~src a */ 1256 /* 1257 * Calculate the number of pixels we need to do one by one 1258 * until we're 32bit aligned, then do the rest in 32bit 1259 * mode. Assumes that stride is always a multiple of 4. 1260 */ 1261 /* TODO: use 32bit writes with byte mask instead */ 1262 pre = addr & 3; 1263 if (pre != 0) pre = 4 - pre; 1264 for (line = 0; line < he; line++) { 1265 pptr = addr; 1266 cnt = wi; 1267 if (pre) { 1268 sta(pptr & ~7, ASI_SX, SX_LDB(8, pre - 1, pptr & 7)); 1269 sx_write(sc->sc_sx, SX_INSTRUCTIONS, 1270 SX_ROP(8, 8, 32, pre - 1)); 1271 sta(pptr & ~7, ASI_SX, SX_STB(32, pre - 1, pptr & 7)); 1272 pptr += pre; 1273 cnt -= pre; 1274 } 1275 /* now do the aligned pixels in 32bit chunks */ 1276 while(cnt > 15) { 1277 words = min(16, cnt >> 2); 1278 sta(pptr & ~7, ASI_SX, SX_LD(8, words - 1, pptr & 7)); 1279 sx_write(sc->sc_sx, SX_INSTRUCTIONS, 1280 SX_ROP(8, 8, 32, words - 1)); 1281 sta(pptr & ~7, ASI_SX, SX_ST(32, words - 1, pptr & 7)); 1282 pptr += words << 2; 1283 cnt -= words << 2; 1284 } 1285 /* do any remaining pixels byte-wise again */ 1286 if (cnt > 0) 1287 sta(pptr & ~7, ASI_SX, SX_LDB(8, cnt - 1, pptr & 7)); 1288 sx_write(sc->sc_sx, SX_INSTRUCTIONS, 1289 SX_ROP(8, 8, 32, cnt - 1)); 1290 sta(pptr & ~7, ASI_SX, SX_STB(32, cnt - 1, pptr & 7)); 1291 addr += stride; 1292 } 1293 } 1294 1295 static inline void 1296 cg14_slurp(int reg, uint32_t addr, int cnt) 1297 { 1298 int num; 1299 while (cnt > 0) { 1300 num = min(32, cnt); 1301 sta(addr & ~7, ASI_SX, SX_LD(reg, num - 1, addr & 7)); 1302 cnt -= num; 1303 reg += num; 1304 addr += (num << 2); 1305 } 1306 } 1307 1308 static inline void 1309 cg14_spit(int reg, uint32_t addr, int cnt) 1310 { 1311 int num; 1312 while (cnt > 0) { 1313 num = min(32, cnt); 1314 sta(addr & ~7, ASI_SX, SX_ST(reg, num - 1, addr & 7)); 1315 cnt -= num; 1316 reg += num; 1317 addr += (num << 2); 1318 } 1319 } 1320 1321 static void 1322 cg14_bitblt(void *cookie, int xs, int ys, int xd, int yd, 1323 int wi, int he, int rop) 1324 { 1325 struct cgfourteen_softc *sc = cookie; 1326 uint32_t saddr, daddr, sptr, dptr; 1327 int line, cnt, stride = sc->sc_fb.fb_type.fb_width; 1328 int num, words, skip; 1329 1330 if (ys < yd) { 1331 /* need to go bottom-up */ 1332 saddr = sc->sc_fb_paddr + xs + stride * (ys + he - 1); 1333 daddr = sc->sc_fb_paddr + xd + stride * (yd + he - 1); 1334 skip = -stride; 1335 } else { 1336 saddr = sc->sc_fb_paddr + xs + stride * ys; 1337 daddr = sc->sc_fb_paddr + xd + stride * yd; 1338 skip = stride; 1339 } 1340 1341 if ((saddr & 3) == (daddr & 3)) { 1342 int pre = saddr & 3; /* pixels to copy byte-wise */ 1343 if (pre != 0) pre = 4 - pre; 1344 for (line = 0; line < he; line++) { 1345 sptr = saddr; 1346 dptr = daddr; 1347 cnt = wi; 1348 if (pre > 0) { 1349 sta(sptr & ~7, ASI_SX, 1350 SX_LDB(32, pre - 1, sptr & 7)); 1351 sta(dptr & ~7, ASI_SX, 1352 SX_STB(32, pre - 1, dptr & 7)); 1353 cnt -= pre; 1354 sptr += pre; 1355 dptr += pre; 1356 } 1357 words = cnt >> 2; 1358 while(cnt > 3) { 1359 num = min(120, words); 1360 cg14_slurp(8, sptr, num); 1361 cg14_spit(8, dptr, num); 1362 sptr += num << 2; 1363 dptr += num << 2; 1364 cnt -= num << 2; 1365 } 1366 if (cnt > 0) { 1367 sta(sptr & ~7, ASI_SX, 1368 SX_LDB(32, cnt - 1, sptr & 7)); 1369 sta(dptr & ~7, ASI_SX, 1370 SX_STB(32, cnt - 1, dptr & 7)); 1371 } 1372 saddr += skip; 1373 daddr += skip; 1374 } 1375 } else { 1376 /* unaligned, have to use byte mode */ 1377 /* funnel shifter & byte mask trickery? */ 1378 for (line = 0; line < he; line++) { 1379 sptr = saddr; 1380 dptr = daddr; 1381 cnt = wi; 1382 while(cnt > 31) { 1383 sta(sptr & ~7, ASI_SX, SX_LDB(32, 31, sptr & 7)); 1384 sta(dptr & ~7, ASI_SX, SX_STB(32, 31, dptr & 7)); 1385 sptr += 32; 1386 dptr += 32; 1387 cnt -= 32; 1388 } 1389 if (cnt > 0) { 1390 sta(sptr & ~7, ASI_SX, 1391 SX_LDB(32, cnt - 1, sptr & 7)); 1392 sta(dptr & ~7, ASI_SX, 1393 SX_STB(32, cnt - 1, dptr & 7)); 1394 } 1395 saddr += skip; 1396 daddr += skip; 1397 } 1398 } 1399 } 1400 1401 /* 1402 * for copying glyphs around 1403 * - uses all quads for reads 1404 * - uses quads for writes as far as possible 1405 * - limited by number of registers - won't do more than 120 wide 1406 * - doesn't handle overlaps 1407 */ 1408 static void 1409 cg14_bitblt_gc(void *cookie, int xs, int ys, int xd, int yd, 1410 int wi, int he, int rop) 1411 { 1412 struct cgfourteen_softc *sc = cookie; 1413 uint32_t saddr, daddr; 1414 int line, cnt = wi, stride = sc->sc_fb.fb_type.fb_width; 1415 int dreg = 8, swi = wi, dd; 1416 int in = 0, q = 0, out = 0, r; 1417 1418 saddr = sc->sc_fb_paddr + xs + stride * ys; 1419 daddr = sc->sc_fb_paddr + xd + stride * yd; 1420 1421 if (saddr & 3) { 1422 swi += saddr & 3; 1423 dreg += saddr & 3; 1424 saddr &= ~3; 1425 } 1426 swi = (swi + 3) >> 2; /* round up, number of quads to read */ 1427 1428 if (daddr & 3) { 1429 in = 4 - (daddr & 3); /* pixels to write in byte mode */ 1430 cnt -= in; 1431 } 1432 1433 q = cnt >> 2; 1434 out = cnt & 3; 1435 1436 for (line = 0; line < he; line++) { 1437 /* read source line, in all quads */ 1438 sta(saddr & ~7, ASI_SX, SX_LDUQ0(8, swi - 1, saddr & 7)); 1439 /* now write it out */ 1440 dd = daddr; 1441 r = dreg; 1442 if (in > 0) { 1443 sta(dd & ~7, ASI_SX, SX_STB(r, in - 1, dd & 7)); 1444 dd += in; 1445 r += in; 1446 } 1447 if (q > 0) { 1448 sta(dd & ~7, ASI_SX, SX_STUQ0(r, q - 1, dd & 7)); 1449 r += q << 2; 1450 dd += q << 2; 1451 } 1452 if (out > 0) { 1453 sta(dd & ~7, ASI_SX, SX_STB(r, out - 1, dd & 7)); 1454 } 1455 saddr += stride; 1456 daddr += stride; 1457 } 1458 } 1459 1460 static void 1461 cg14_putchar(void *cookie, int row, int col, u_int c, long attr) 1462 { 1463 struct rasops_info *ri = cookie; 1464 struct wsdisplay_font *font = PICK_FONT(ri, c); 1465 struct vcons_screen *scr = ri->ri_hw; 1466 struct cgfourteen_softc *sc = scr->scr_cookie; 1467 void *data; 1468 uint32_t fg, bg; 1469 int i, x, y, wi, he; 1470 uint32_t addr; 1471 int stride = sc->sc_fb.fb_type.fb_width; 1472 1473 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1474 return; 1475 1476 if (!CHAR_IN_FONT(c, font)) 1477 return; 1478 1479 wi = font->fontwidth; 1480 he = font->fontheight; 1481 1482 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1483 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1484 1485 x = ri->ri_xorigin + col * wi; 1486 y = ri->ri_yorigin + row * he; 1487 1488 if (c == 0x20) { 1489 cg14_rectfill(sc, x, y, wi, he, bg); 1490 if (attr & 1) 1491 cg14_rectfill(sc, x, y + he - 2, wi, 1, fg); 1492 return; 1493 } 1494 1495 sx_write(sc->sc_sx, SX_QUEUED(8), bg); 1496 sx_write(sc->sc_sx, SX_QUEUED(9), fg); 1497 1498 data = WSFONT_GLYPH(c, font); 1499 addr = sc->sc_fb_paddr + x + stride * y; 1500 1501 switch (font->stride) { 1502 case 1: { 1503 uint8_t *data8 = data; 1504 uint32_t reg; 1505 for (i = 0; i < he; i++) { 1506 reg = *data8; 1507 sx_write(sc->sc_sx, SX_QUEUED(R_MASK), 1508 reg << 24); 1509 sta(addr & ~7, ASI_SX, SX_STBS(8, wi - 1, addr & 7)); 1510 data8++; 1511 addr += stride; 1512 } 1513 break; 1514 } 1515 case 2: { 1516 uint16_t *data16 = data; 1517 uint32_t reg; 1518 for (i = 0; i < he; i++) { 1519 reg = *data16; 1520 sx_write(sc->sc_sx, SX_QUEUED(R_MASK), 1521 reg << 16); 1522 sta(addr & ~7, ASI_SX, SX_STBS(8, wi - 1, addr & 7)); 1523 data16++; 1524 addr += stride; 1525 } 1526 break; 1527 } 1528 } 1529 if (attr & 1) 1530 cg14_rectfill(sc, x, y + he - 2, wi, 1, fg); 1531 } 1532 1533 static void 1534 cg14_cursor(void *cookie, int on, int row, int col) 1535 { 1536 struct rasops_info *ri = cookie; 1537 struct vcons_screen *scr = ri->ri_hw; 1538 struct cgfourteen_softc *sc = scr->scr_cookie; 1539 int x, y, wi, he; 1540 1541 wi = ri->ri_font->fontwidth; 1542 he = ri->ri_font->fontheight; 1543 1544 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1545 x = ri->ri_ccol * wi + ri->ri_xorigin; 1546 y = ri->ri_crow * he + ri->ri_yorigin; 1547 if (ri->ri_flg & RI_CURSOR) { 1548 cg14_invert(sc, x, y, wi, he); 1549 ri->ri_flg &= ~RI_CURSOR; 1550 } 1551 ri->ri_crow = row; 1552 ri->ri_ccol = col; 1553 if (on) { 1554 x = ri->ri_ccol * wi + ri->ri_xorigin; 1555 y = ri->ri_crow * he + ri->ri_yorigin; 1556 cg14_invert(sc, x, y, wi, he); 1557 ri->ri_flg |= RI_CURSOR; 1558 } 1559 } else { 1560 scr->scr_ri.ri_crow = row; 1561 scr->scr_ri.ri_ccol = col; 1562 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1563 } 1564 1565 } 1566 1567 static void 1568 cg14_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1569 { 1570 struct rasops_info *ri = cookie; 1571 struct wsdisplay_font *font = PICK_FONT(ri, c); 1572 struct vcons_screen *scr = ri->ri_hw; 1573 struct cgfourteen_softc *sc = scr->scr_cookie; 1574 int stride = sc->sc_fb.fb_type.fb_width; 1575 uint32_t bg, fg, addr, bg8, fg8, pixel, in, q, next; 1576 int i, j, x, y, wi, he, r, g, b, aval, cnt, reg; 1577 int r1, g1, b1, r0, g0, b0, fgo, bgo, rv; 1578 uint8_t *data8; 1579 1580 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1581 return; 1582 1583 if (!CHAR_IN_FONT(c, font)) 1584 return; 1585 1586 wi = font->fontwidth; 1587 he = font->fontheight; 1588 1589 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1590 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1591 x = ri->ri_xorigin + col * wi; 1592 y = ri->ri_yorigin + row * he; 1593 if (c == 0x20) { 1594 cg14_rectfill(sc, x, y, wi, he, bg); 1595 if (attr & 1) 1596 cg14_rectfill(sc, x, y + he - 2, wi, 1, fg); 1597 return; 1598 } 1599 1600 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1601 if (rv == GC_OK) 1602 return; 1603 1604 addr = sc->sc_fb_paddr + x + stride * y; 1605 data8 = WSFONT_GLYPH(c, font); 1606 1607 /* 1608 * we need the RGB colours here, so get offsets into rasops_cmap 1609 */ 1610 fgo = ((attr >> 24) & 0xf) * 3; 1611 bgo = ((attr >> 16) & 0xf) * 3; 1612 1613 r0 = rasops_cmap[bgo]; 1614 r1 = rasops_cmap[fgo]; 1615 g0 = rasops_cmap[bgo + 1]; 1616 g1 = rasops_cmap[fgo + 1]; 1617 b0 = rasops_cmap[bgo + 2]; 1618 b1 = rasops_cmap[fgo + 2]; 1619 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 1620 bg8 = R3G3B2(r0, g0, b0); 1621 fg8 = R3G3B2(r1, g1, b1); 1622 1623 for (i = 0; i < he; i++) { 1624 /* calculate one line of pixels */ 1625 for (j = 0; j < wi; j++) { 1626 aval = *data8; 1627 if (aval == 0) { 1628 pixel = bg8; 1629 } else if (aval == 255) { 1630 pixel = fg8; 1631 } else { 1632 r = aval * r1 + (255 - aval) * r0; 1633 g = aval * g1 + (255 - aval) * g0; 1634 b = aval * b1 + (255 - aval) * b0; 1635 pixel = ((r & 0xe000) >> 8) | 1636 ((g & 0xe000) >> 11) | 1637 ((b & 0xc000) >> 14); 1638 } 1639 /* 1640 * stick them into SX registers and hope we never have 1641 * to deal with fonts more than 120 pixels wide 1642 */ 1643 sx_write(sc->sc_sx, SX_QUEUED(j + 8), pixel); 1644 data8++; 1645 } 1646 /* now write them into video memory */ 1647 in = (addr & 3); 1648 next = addr; 1649 reg = 8; 1650 cnt = wi; 1651 if (in != 0) { 1652 in = 4 - in; /* pixels to write until aligned */ 1653 sta(next & ~7, ASI_SX, SX_STB(8, in - 1, next & 7)); 1654 next += in; 1655 reg = 8 + in; 1656 cnt -= in; 1657 } 1658 q = cnt >> 2; /* number of writes we can do in quads */ 1659 if (q > 0) { 1660 sta(next & ~7, ASI_SX, SX_STUQ0(reg, q - 1, next & 7)); 1661 next += (q << 2); 1662 cnt -= (q << 2); 1663 reg += (q << 2); 1664 } 1665 if (cnt > 0) { 1666 sta(next & ~7, ASI_SX, SX_STB(reg, cnt - 1, next & 7)); 1667 } 1668 1669 addr += stride; 1670 } 1671 1672 if (rv == GC_ADD) { 1673 glyphcache_add(&sc->sc_gc, c, x, y); 1674 } else if (attr & 1) 1675 cg14_rectfill(sc, x, y + he - 2, wi, 1, fg); 1676 1677 } 1678 1679 static void 1680 cg14_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1681 { 1682 struct rasops_info *ri = cookie; 1683 struct vcons_screen *scr = ri->ri_hw; 1684 struct cgfourteen_softc *sc = scr->scr_cookie; 1685 int32_t xs, xd, y, width, height; 1686 1687 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1688 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1689 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1690 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1691 width = ri->ri_font->fontwidth * ncols; 1692 height = ri->ri_font->fontheight; 1693 cg14_bitblt(sc, xs, y, xd, y, width, height, 0x0c); 1694 } 1695 } 1696 1697 static void 1698 cg14_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1699 { 1700 struct rasops_info *ri = cookie; 1701 struct vcons_screen *scr = ri->ri_hw; 1702 struct cgfourteen_softc *sc = scr->scr_cookie; 1703 int32_t x, y, width, height, fg, bg, ul; 1704 1705 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1706 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1707 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1708 width = ri->ri_font->fontwidth * ncols; 1709 height = ri->ri_font->fontheight; 1710 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1711 1712 cg14_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1713 } 1714 } 1715 1716 static void 1717 cg14_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1718 { 1719 struct rasops_info *ri = cookie; 1720 struct vcons_screen *scr = ri->ri_hw; 1721 struct cgfourteen_softc *sc = scr->scr_cookie; 1722 int32_t x, ys, yd, width, height; 1723 1724 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1725 x = ri->ri_xorigin; 1726 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1727 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1728 width = ri->ri_emuwidth; 1729 height = ri->ri_font->fontheight * nrows; 1730 cg14_bitblt(sc, x, ys, x, yd, width, height, 0x0c); 1731 } 1732 } 1733 1734 static void 1735 cg14_eraserows(void *cookie, int row, int nrows, long fillattr) 1736 { 1737 struct rasops_info *ri = cookie; 1738 struct vcons_screen *scr = ri->ri_hw; 1739 struct cgfourteen_softc *sc = scr->scr_cookie; 1740 int32_t x, y, width, height, fg, bg, ul; 1741 1742 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1743 x = ri->ri_xorigin; 1744 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1745 width = ri->ri_emuwidth; 1746 height = ri->ri_font->fontheight * nrows; 1747 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1748 1749 cg14_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1750 } 1751 } 1752 1753 #endif /* NSX > 0 */ 1754 1755