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