1 /* $NetBSD: vidcvideo.c,v 1.11 2002/04/03 16:03:50 reinoud Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Reinoud Zandijk 5 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Tohru Nishimura 18 * and Reinoud Zandijk for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Created vidcvideo.c from /dev/tc/cfb.c to fit the Acorn/ARM VIDC1 and VIDC20 chips 34 * 35 */ 36 37 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 38 39 __KERNEL_RCSID(0, "$NetBSD: vidcvideo.c,v 1.11 2002/04/03 16:03:50 reinoud Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/buf.h> 47 #include <sys/ioctl.h> 48 49 #include <arm/mainbus/mainbus.h> 50 #include <machine/bus.h> 51 #include <machine/intr.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 56 #include <dev/rasops/rasops.h> 57 #include <dev/wsfont/wsfont.h> 58 59 #include <uvm/uvm_extern.h> 60 #include <arm/arm32/pmap.h> 61 #include <arm/cpufunc.h> 62 #include <machine/intr.h> 63 64 /* for vidc_mode ... needs to be MI indepenent one day */ 65 #include <arm/iomd/vidc.h> 66 #include <arm/iomd/vidc20config.h> 67 #include <arm/iomd/vidcvideo.h> 68 #include <machine/bootconfig.h> 69 70 /* FOR DEBUG */ 71 extern videomemory_t videomemory; 72 73 struct hwcmap256 { 74 #define CMAP_SIZE 256 /* 256 R/G/B entries */ 75 u_int8_t r[CMAP_SIZE]; 76 u_int8_t g[CMAP_SIZE]; 77 u_int8_t b[CMAP_SIZE]; 78 }; 79 80 81 /* XXX for CURSOR_MAX_WIDTH = 32 */ 82 struct hwcursor32 { 83 struct wsdisplay_curpos cc_pos; 84 struct wsdisplay_curpos cc_hot; 85 struct wsdisplay_curpos cc_size; 86 struct wsdisplay_curpos cc_magic; 87 u_int8_t cc_color[6]; /* how many? */ 88 u_int32_t cc_image[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT]; 89 u_int32_t cc_mask[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT]; 90 }; 91 92 93 struct fb_devconfig { 94 vaddr_t dc_vaddr; /* memory space virtual base address */ 95 paddr_t dc_paddr; /* memory space physical base address */ 96 vsize_t dc_size; /* size of slot memory */ 97 int dc_wid; /* width of frame buffer */ 98 int dc_ht; /* height of frame buffer */ 99 int dc_log2_depth; /* log2 of bits per pixel */ 100 int dc_depth; /* depth, bits per pixel */ 101 int dc_rowbytes; /* bytes in a FB scan line */ 102 vaddr_t dc_videobase; /* base of flat frame buffer */ 103 int dc_blanked; /* currently has video disabled */ 104 void *dc_hwscroll_cookie; /* cookie for hardware scroll */ 105 106 int dc_curenb; /* is cursor sprite enabled ? */ 107 int dc_changed; /* need update of hardware */ 108 int dc_writeback_delay; /* Screenarea write back vsync counter */ 109 #define WSDISPLAY_CMAP_DOLUT 0x20 110 #define WSDISPLAY_VIDEO_ONOFF 0x40 111 #define WSDISPLAY_WB_COUNTER 0x80 112 113 struct hwcmap256 dc_cmap;/* software copy of colormap */ 114 struct hwcursor32 dc_cursor;/* software copy of cursor */ 115 116 struct vidc_mode mode_info; 117 struct rasops_info rinfo; 118 119 struct wsdisplay_emulops orig_ri_ops; /* Rasops functions for deligation */ 120 }; 121 122 123 struct vidcvideo_softc { 124 struct device sc_dev; 125 struct fb_devconfig *sc_dc; /* device configuration */ 126 int nscreens; /* number of screens configured */ 127 }; 128 129 130 /* XXX has to go XXX */ 131 #define CX_MAGIC_X 220 132 #define CX_MAGIC_Y 35 133 #define CX_FB_OFFSET 0x000000 134 #define CX_FB_SIZE 0x100000 135 #define CX_BT459_OFFSET 0x200000 136 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 137 /* XXX till here XXX */ 138 139 140 /* Function prototypes for glue */ 141 static int vidcvideo_match __P((struct device *, struct cfdata *, void *)); 142 static void vidcvideo_attach __P((struct device *, struct device *, void *)); 143 144 145 /* config glue */ 146 const struct cfattach vidcvideo_ca = { 147 sizeof(struct vidcvideo_softc), vidcvideo_match, vidcvideo_attach, 148 }; 149 150 151 static struct fb_devconfig vidcvideo_console_dc; 152 static int vidcvideo_is_console; 153 154 155 static struct wsscreen_descr vidcvideo_stdscreen = { 156 "std", 0, 0, 157 0, /* textops */ 158 0, 0, 159 WSSCREEN_REVERSE 160 }; 161 162 static const struct wsscreen_descr *_vidcvideo_scrlist[] = { 163 &vidcvideo_stdscreen, 164 }; 165 166 static const struct wsscreen_list vidcvideo_screenlist = { 167 sizeof(_vidcvideo_scrlist) / sizeof(struct wsscreen_descr *), _vidcvideo_scrlist 168 }; 169 170 static int vidcvideoioctl __P((void *, u_long, caddr_t, int, struct proc *)); 171 static paddr_t vidcvideommap __P((void *, off_t, int)); 172 173 static int vidcvideo_alloc_screen __P((void *, const struct wsscreen_descr *, 174 void **, int *, int *, long *)); 175 static void vidcvideo_free_screen __P((void *, void *)); 176 static int vidcvideo_show_screen __P((void *, void *, int, 177 void (*) (void *, int, int), void *)); 178 179 static const struct wsdisplay_accessops vidcvideo_accessops = { 180 vidcvideoioctl, 181 vidcvideommap, 182 vidcvideo_alloc_screen, 183 vidcvideo_free_screen, 184 vidcvideo_show_screen, 185 0 /* load_font */ 186 }; 187 188 189 /* Function prototypes */ 190 int vidcvideo_cnattach __P((vaddr_t)); 191 static void vidcvideo_colourmap_and_cursor_init __P((struct fb_devconfig *)); 192 193 static int get_cmap __P((struct vidcvideo_softc *, struct wsdisplay_cmap *)); 194 static int set_cmap __P((struct vidcvideo_softc *, struct wsdisplay_cmap *)); 195 static int set_cursor __P((struct vidcvideo_softc *, struct wsdisplay_cursor *)); 196 static int get_cursor __P((struct vidcvideo_softc *, struct wsdisplay_cursor *)); 197 static void set_curpos __P((struct vidcvideo_softc *, struct wsdisplay_curpos *)); 198 static void vidcvideo_getdevconfig __P((vaddr_t, struct fb_devconfig *)); 199 200 static int vidcvideointr __P((void *)); 201 static void vidcvideo_config_wscons __P((struct fb_devconfig *)); 202 203 204 /* Acceleration function prototypes */ 205 static void vv_copyrows __P((void *, int, int, int)); 206 static void vv_eraserows __P((void *, int, int, long)); 207 static void vv_putchar __P((void *c, int row, int col, u_int uc, long attr)); 208 209 210 static int 211 vidcvideo_match(parent, match, aux) 212 struct device *parent; 213 struct cfdata *match; 214 void *aux; 215 { 216 /* Can't probe AFAIK ; how ? */ 217 return (1); 218 } 219 220 221 static void 222 vidcvideo_getdevconfig(dense_addr, dc) 223 vaddr_t dense_addr; 224 struct fb_devconfig *dc; 225 { 226 dc->dc_vaddr = dense_addr; 227 (void) pmap_extract(pmap_kernel(), dc->dc_vaddr, &(dc->dc_paddr)); 228 229 vidcvideo_getmode(&dc->mode_info); 230 231 dc->dc_wid = dc->mode_info.hder; 232 dc->dc_ht = dc->mode_info.vder; 233 dc->dc_log2_depth = dc->mode_info.log2_bpp; 234 dc->dc_depth = 1 << dc->dc_log2_depth; 235 dc->dc_videobase = dc->dc_vaddr; 236 dc->dc_blanked = 0; 237 238 /* this should/could be done somewhat more elegant! */ 239 switch (dc->dc_depth) { 240 case 1: 241 dc->dc_rowbytes = dc->dc_wid / 8; 242 break; 243 case 2: 244 dc->dc_rowbytes = dc->dc_wid / 4; 245 break; 246 case 4: 247 dc->dc_rowbytes = dc->dc_wid / 2; 248 break; 249 case 8: 250 dc->dc_rowbytes = dc->dc_wid; 251 break; 252 case 16: 253 dc->dc_rowbytes = dc->dc_wid * 2; 254 break; 255 case 32: 256 dc->dc_rowbytes = dc->dc_wid * 4; 257 break; 258 default: 259 printf("Unknown colour depth %d ... what to do ?", dc->dc_depth); 260 break; 261 }; 262 263 /* euhm... correct ? i.e. not complete VIDC memory */ 264 dc->dc_size = dc->mode_info.vder * dc->dc_rowbytes; 265 266 /* initialize colormap and cursor resource */ 267 vidcvideo_colourmap_and_cursor_init(dc); 268 269 dc->rinfo.ri_flg = 0; /* RI_CENTER; */ 270 dc->rinfo.ri_depth = dc->dc_depth; 271 dc->rinfo.ri_bits = (void *) dc->dc_videobase; 272 dc->rinfo.ri_width = dc->dc_wid; 273 dc->rinfo.ri_height = dc->dc_ht; 274 dc->rinfo.ri_stride = dc->dc_rowbytes; 275 dc->rinfo.ri_hw = dc; /* link back */ 276 277 /* intitialise miscelanious */ 278 dc->dc_writeback_delay = 0; 279 } 280 281 282 static void 283 vidcvideo_config_wscons(dc) 284 struct fb_devconfig *dc; 285 { 286 int i, cookie, font_not_locked; 287 288 /* clear the screen ; why not a memset ? - it was this way so keep it for now */ 289 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 290 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 291 292 wsfont_init(); 293 294 /* prefer 8 pixel wide font */ 295 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_L2R, 296 WSDISPLAY_FONTORDER_L2R); 297 if (cookie <= 0) 298 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 299 WSDISPLAY_FONTORDER_L2R); 300 301 if (cookie < 0) { 302 /* Can I even print here ? */ 303 printf("Font table empty! exiting\n"); 304 return; 305 }; 306 307 font_not_locked = wsfont_lock(cookie, &dc->rinfo.ri_font); 308 309 dc->rinfo.ri_wsfcookie = cookie; 310 311 rasops_init(&dc->rinfo, 312 dc->rinfo.ri_height / dc->rinfo.ri_font->fontheight, 313 dc->rinfo.ri_width / dc->rinfo.ri_font->fontwidth 314 ); 315 316 /* 317 * Provide a hook for the acceleration functions and make a copy of the 318 * original rasops functions for passing on calls 319 */ 320 dc->rinfo.ri_hw = dc; 321 memcpy(&(dc->orig_ri_ops), &(dc->rinfo.ri_ops), sizeof(struct wsdisplay_emulops)); 322 323 /* add our accelerated functions */ 324 dc->rinfo.ri_ops.eraserows = vv_eraserows; 325 dc->rinfo.ri_ops.copyrows = vv_copyrows; 326 327 /* add the extra activity measuring functions; they just delegate on */ 328 dc->rinfo.ri_ops.putchar = vv_putchar; 329 330 /* XXX shouldn't be global */ 331 vidcvideo_stdscreen.nrows = dc->rinfo.ri_rows; 332 vidcvideo_stdscreen.ncols = dc->rinfo.ri_cols; 333 vidcvideo_stdscreen.textops = &dc->rinfo.ri_ops; 334 vidcvideo_stdscreen.capabilities = dc->rinfo.ri_caps; 335 336 if (font_not_locked) { 337 printf(" warning ... couldn't lock font! "); 338 }; 339 } 340 341 342 static void 343 vidcvideo_attach(parent, self, aux) 344 struct device *parent, *self; 345 void *aux; 346 { 347 struct vidcvideo_softc *sc = (struct vidcvideo_softc *)self; 348 struct fb_devconfig *dc; 349 struct wsemuldisplaydev_attach_args waa; 350 struct hwcmap256 *cm; 351 const u_int8_t *p; 352 long defattr; 353 int index; 354 355 vidcvideo_init(); 356 if (sc->nscreens == 0) { 357 sc->sc_dc = &vidcvideo_console_dc; 358 if (!vidcvideo_is_console) { 359 printf(" : non console (no kbd yet) "); 360 vidcvideo_getdevconfig(videomemory.vidm_vbase, sc->sc_dc); 361 vidcvideo_config_wscons(sc->sc_dc); 362 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 363 }; 364 sc->nscreens = 1; 365 } else { 366 printf(": allready attached ... can't cope with this\n"); 367 return; 368 }; 369 370 dc = sc->sc_dc; 371 372 vidcvideo_printdetails(); 373 printf(": using %d x %d, %dbpp\n", dc->dc_wid, dc->dc_ht, 374 dc->dc_depth); 375 376 /* initialise rasops */ 377 cm = &dc->dc_cmap; 378 p = rasops_cmap; 379 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 380 cm->r[index] = p[0]; 381 cm->g[index] = p[1]; 382 cm->b[index] = p[2]; 383 } 384 385 /* what does these do ? */ 386 dc->dc_cursor.cc_magic.x = CX_MAGIC_X; 387 dc->dc_cursor.cc_magic.y = CX_MAGIC_Y; 388 389 /* set up interrupt flags */ 390 dc->dc_changed |= WSDISPLAY_CMAP_DOLUT; 391 392 /* 393 * Set up a link in the rasops structure to our device config 394 * for acceleration stuff 395 */ 396 dc->rinfo.ri_hw = sc->sc_dc; 397 398 /* Establish an interrupt handler, and clear any pending interrupts */ 399 intr_claim(IRQ_FLYBACK, IPL_TTY, "vblank", vidcvideointr, dc); 400 401 waa.console = (vidcvideo_is_console ? 1 : 0); 402 waa.scrdata = &vidcvideo_screenlist; 403 waa.accessops = &vidcvideo_accessops; 404 waa.accesscookie = sc; 405 406 config_found(self, &waa, wsemuldisplaydevprint); 407 } 408 409 410 static int 411 vidcvideoioctl(v, cmd, data, flag, p) 412 void *v; 413 u_long cmd; 414 caddr_t data; 415 int flag; 416 struct proc *p; 417 { 418 struct vidcvideo_softc *sc = v; 419 struct fb_devconfig *dc = sc->sc_dc; 420 int state; 421 422 switch (cmd) { 423 case WSDISPLAYIO_GTYPE: 424 *(u_int *)data = WSDISPLAY_TYPE_VIDC; 425 return (0); 426 427 case WSDISPLAYIO_GINFO: 428 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 429 wsd_fbip->height = dc->dc_ht; 430 wsd_fbip->width = dc->dc_wid; 431 wsd_fbip->depth = dc->dc_depth; 432 wsd_fbip->cmsize = CMAP_SIZE; 433 #undef fbt 434 return (0); 435 436 case WSDISPLAYIO_GETCMAP: 437 return get_cmap(sc, (struct wsdisplay_cmap *)data); 438 439 case WSDISPLAYIO_PUTCMAP: 440 return set_cmap(sc, (struct wsdisplay_cmap *)data); 441 442 case WSDISPLAYIO_SVIDEO: 443 state = *(int *)data; 444 dc->dc_blanked = (state == WSDISPLAYIO_VIDEO_OFF); 445 dc->dc_changed |= WSDISPLAY_VIDEO_ONOFF; 446 /* done on video blank */ 447 return (0); 448 449 case WSDISPLAYIO_GVIDEO: 450 *(u_int *)data = dc->dc_blanked ? 451 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 452 return (0); 453 454 case WSDISPLAYIO_GCURPOS: 455 *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos; 456 return (0); 457 458 case WSDISPLAYIO_SCURPOS: 459 set_curpos(sc, (struct wsdisplay_curpos *)data); 460 dc->dc_changed |= WSDISPLAY_CURSOR_DOPOS; 461 return (0); 462 463 case WSDISPLAYIO_GCURMAX: 464 ((struct wsdisplay_curpos *)data)->x = CURSOR_MAX_WIDTH; 465 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_HEIGHT; 466 return (0); 467 468 case WSDISPLAYIO_GCURSOR: 469 return get_cursor(sc, (struct wsdisplay_cursor *)data); 470 471 case WSDISPLAYIO_SCURSOR: 472 return set_cursor(sc, (struct wsdisplay_cursor *)data); 473 474 case WSDISPLAYIO_SMODE: 475 state = *(int *)data; 476 if (state == WSDISPLAYIO_MODE_MAPPED) { 477 dc->dc_hwscroll_cookie = vidcvideo_hwscroll_reset(); 478 }; 479 if (state == WSDISPLAYIO_MODE_EMUL) { 480 vidcvideo_hwscroll_back(dc->dc_hwscroll_cookie); 481 }; 482 vidcvideo_progr_scroll(); 483 484 return (0); 485 } 486 return EPASSTHROUGH; 487 } 488 489 490 paddr_t 491 vidcvideommap(v, offset, prot) 492 void *v; 493 off_t offset; 494 int prot; 495 { 496 struct vidcvideo_softc *sc = v; 497 498 if (offset >= sc->sc_dc->dc_size || offset < 0) 499 return (-1); 500 501 return arm_btop(sc->sc_dc->dc_paddr + offset); 502 } 503 504 505 static int 506 vidcvideo_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 507 void *v; 508 const struct wsscreen_descr *type; 509 void **cookiep; 510 int *curxp, *curyp; 511 long *attrp; 512 { 513 struct vidcvideo_softc *sc = v; 514 struct fb_devconfig *dc = sc->sc_dc; 515 long defattr; 516 517 /* 518 * One and just only one for now :( ... if the vidcconsole is not the 519 * console then this makes one wsconsole screen free for use ! 520 */ 521 if ((sc->nscreens > 1) || vidcvideo_is_console) 522 return (ENOMEM); 523 524 /* Add the screen to wscons to control */ 525 *cookiep = &dc->rinfo; 526 *curxp = 0; 527 *curyp = 0; 528 vidcvideo_getdevconfig(videomemory.vidm_vbase, dc); 529 vidcvideo_config_wscons(dc); 530 (*dc->rinfo.ri_ops.alloc_attr)(&dc->rinfo, 0, 0, 0, &defattr); 531 *attrp = defattr; 532 sc->nscreens++; 533 534 return (0); 535 } 536 537 538 static void 539 vidcvideo_free_screen(v, cookie) 540 void *v; 541 void *cookie; 542 { 543 struct vidcvideo_softc *sc = v; 544 545 if (sc->sc_dc == &vidcvideo_console_dc) 546 panic("vidcvideo_free_screen: console"); 547 548 sc->nscreens--; 549 } 550 551 552 static int 553 vidcvideo_show_screen(v, cookie, waitok, cb, cbarg) 554 void *v; 555 void *cookie; 556 int waitok; 557 void (*cb) __P((void *, int, int)); 558 void *cbarg; 559 { 560 561 return (0); 562 } 563 564 565 /* EXPORT */ int 566 vidcvideo_cnattach(addr) 567 vaddr_t addr; 568 { 569 struct fb_devconfig *dcp = &vidcvideo_console_dc; 570 long defattr; 571 572 vidcvideo_init(); 573 vidcvideo_getdevconfig(addr, dcp); 574 vidcvideo_config_wscons(dcp); 575 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr); 576 wsdisplay_cnattach(&vidcvideo_stdscreen, &dcp->rinfo, 0, 0, defattr); 577 578 vidcvideo_is_console = 1; 579 return(0); 580 } 581 582 583 static int 584 vidcvideointr(arg) 585 void *arg; 586 { 587 struct fb_devconfig *dc = arg; 588 int v, cleared = 0; 589 590 v = dc->dc_changed; 591 if (v == 0) 592 return (1); 593 594 if (v & WSDISPLAY_WB_COUNTER) { 595 dc->dc_writeback_delay--; 596 if (dc->dc_writeback_delay == 0) { 597 cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size); 598 cleared |= WSDISPLAY_WB_COUNTER; 599 }; 600 } 601 602 if (v & WSDISPLAY_CMAP_DOLUT) { 603 struct hwcmap256 *cm = &dc->dc_cmap; 604 int index; 605 606 if (dc->dc_depth == 4) { 607 /* palette for 4 bpp is different from 8bpp */ 608 vidcvideo_write(VIDC_PALREG, 0x00000000); 609 for (index=0; index < (1 << dc->dc_depth); index++) 610 vidcvideo_write(VIDC_PALETTE, 611 VIDC_COL(cm->r[index], 612 cm->g[index], 613 cm->b[index])); 614 ; 615 }; 616 617 if (dc->dc_depth == 8) { 618 /* dunno what to do in more than 8bpp */ 619 /* palettes only make sense in 8bpp and less modes on VIDC */ 620 vidcvideo_write(VIDC_PALREG, 0x00000000); 621 for (index = 0; index < CMAP_SIZE; index++) { 622 vidcvideo_write(VIDC_PALETTE, 623 VIDC_COL(cm->r[index], cm->g[index], cm->b[index]) 624 ); 625 }; 626 }; 627 cleared |= WSDISPLAY_CMAP_DOLUT; 628 } 629 630 if (v & WSDISPLAY_VIDEO_ONOFF) { 631 vidcvideo_blank(dc->dc_blanked); 632 cleared |= WSDISPLAY_VIDEO_ONOFF; 633 }; 634 635 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 636 int x, y; 637 x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x; 638 y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y; 639 640 vidcvideo_updatecursor(x, y); 641 cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT; 642 }; 643 644 if (v & WSDISPLAY_CURSOR_DOCUR) { 645 vidcvideo_enablecursor(dc->dc_curenb); 646 cleared |= WSDISPLAY_CURSOR_DOCUR; 647 }; 648 649 650 #if 0 /* XXX snip XXX */ 651 /* XXX kept here as an archive for now XXX */ 652 653 vdac = vidcvideobase + CX_BT459_OFFSET; 654 v = sc->sc_changed; 655 if (v & WSDISPLAY_CURSOR_DOCUR) { 656 SELECT(vdac, BT459_IREG_CCR); 657 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00; 658 } 659 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 660 int x, y; 661 662 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 663 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 664 665 x += sc->sc_cursor.cc_magic.x; 666 y += sc->sc_cursor.cc_magic.y; 667 668 SELECT(vdac, BT459_IREG_CURSOR_X_LOW); 669 REG(vdac, bt_reg) = x; tc_wmb(); 670 REG(vdac, bt_reg) = x >> 8; tc_wmb(); 671 REG(vdac, bt_reg) = y; tc_wmb(); 672 REG(vdac, bt_reg) = y >> 8; tc_wmb(); 673 } 674 if (v & WSDISPLAY_CURSOR_DOCMAP) { 675 u_int8_t *cp = sc->sc_cursor.cc_color; 676 677 SELECT(vdac, BT459_IREG_CCOLOR_2); 678 REG(vdac, bt_reg) = cp[1]; tc_wmb(); 679 REG(vdac, bt_reg) = cp[3]; tc_wmb(); 680 REG(vdac, bt_reg) = cp[5]; tc_wmb(); 681 682 REG(vdac, bt_reg) = cp[0]; tc_wmb(); 683 REG(vdac, bt_reg) = cp[2]; tc_wmb(); 684 REG(vdac, bt_reg) = cp[4]; tc_wmb(); 685 } 686 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 687 u_int8_t *ip, *mp, img, msk; 688 u_int8_t u; 689 int bcnt; 690 691 ip = (u_int8_t *)sc->sc_cursor.cc_image; 692 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_HEIGHT); 693 694 bcnt = 0; 695 SELECT(vdac, BT459_IREG_CRAM_BASE+0); 696 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 697 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 698 /* pad right half 32 pixel when smaller than 33 */ 699 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 700 REG(vdac, bt_reg) = 0; tc_wmb(); 701 REG(vdac, bt_reg) = 0; tc_wmb(); 702 } 703 else { 704 img = *ip++; 705 msk = *mp++; 706 img &= msk; /* cookie off image */ 707 u = (msk & 0x0f) << 4 | (img & 0x0f); 708 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 709 u = (msk & 0xf0) | (img & 0xf0) >> 4; 710 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 711 } 712 bcnt += 2; 713 } 714 /* pad unoccupied scan lines */ 715 while (bcnt < CURSOR_MAX_HEIGHT * 16) { 716 REG(vdac, bt_reg) = 0; tc_wmb(); 717 REG(vdac, bt_reg) = 0; tc_wmb(); 718 bcnt += 2; 719 } 720 } 721 #endif /* XXX snip XXX */ 722 723 dc->dc_changed ^= cleared; 724 725 return (1); 726 } 727 728 729 static u_char ri_col_data[6][6] = { 730 { 0, 0, 0, 0, 0, 0}, /* 1 bpp */ 731 { 0, 0, 0, 0, 0, 0}, /* 2 bpp */ 732 { 0, 0, 0, 0, 0, 0}, /* 4 bpp */ 733 { 0, 0, 0, 0, 0, 0}, /* 8 bpp */ 734 { 5, 5, 5, 0, 5, 10}, /* 16 bpp */ 735 { 8, 8, 8, 0, 8, 16}, /* 32 bpp */ 736 }; 737 738 static void 739 vidcvideo_colourmap_and_cursor_init(dc) 740 struct fb_devconfig *dc; 741 { 742 struct rasops_info *ri = &dc->rinfo; 743 u_char *rgbdat; 744 745 /* Whatever we do later... just make sure we have a 746 * sane palette to start with 747 */ 748 vidcvideo_stdpalette(); 749 750 /* set up rgb bit pattern values for rasops_init */ 751 rgbdat = ri_col_data[dc->dc_log2_depth]; 752 ri->ri_rnum = rgbdat[0]; 753 ri->ri_gnum = rgbdat[1]; 754 ri->ri_bnum = rgbdat[2]; 755 ri->ri_rpos = rgbdat[3]; 756 ri->ri_gpos = rgbdat[4]; 757 ri->ri_bpos = rgbdat[5]; 758 759 } 760 761 762 static int 763 get_cmap(sc, p) 764 struct vidcvideo_softc *sc; 765 struct wsdisplay_cmap *p; 766 { 767 u_int index = p->index, count = p->count; 768 769 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 770 return (EINVAL); 771 772 if (!uvm_useracc(p->red, count, B_WRITE) || 773 !uvm_useracc(p->green, count, B_WRITE) || 774 !uvm_useracc(p->blue, count, B_WRITE)) 775 return (EFAULT); 776 777 copyout(&sc->sc_dc->dc_cmap.r[index], p->red, count); 778 copyout(&sc->sc_dc->dc_cmap.g[index], p->green, count); 779 copyout(&sc->sc_dc->dc_cmap.b[index], p->blue, count); 780 781 return (0); 782 } 783 784 785 static int 786 set_cmap(sc, p) 787 struct vidcvideo_softc *sc; 788 struct wsdisplay_cmap *p; 789 { 790 struct fb_devconfig *dc = sc->sc_dc; 791 u_int index = p->index, count = p->count; 792 793 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 794 return (EINVAL); 795 796 if (!uvm_useracc(p->red, count, B_READ) || 797 !uvm_useracc(p->green, count, B_READ) || 798 !uvm_useracc(p->blue, count, B_READ)) 799 return (EFAULT); 800 801 copyin(p->red, &dc->dc_cmap.r[index], count); 802 copyin(p->green, &dc->dc_cmap.g[index], count); 803 copyin(p->blue, &dc->dc_cmap.b[index], count); 804 dc->dc_changed |= WSDISPLAY_CMAP_DOLUT; 805 return (0); 806 } 807 808 809 static int 810 set_cursor(sc, p) 811 struct vidcvideo_softc *sc; 812 struct wsdisplay_cursor *p; 813 { 814 #define cc (&dc->dc_cursor) 815 struct fb_devconfig *dc = sc->sc_dc; 816 u_int v, index, count, icount; 817 818 v = p->which; 819 if (v & WSDISPLAY_CURSOR_DOCMAP) { 820 index = p->cmap.index; 821 count = p->cmap.count; 822 if (index >= CURSOR_MAX_COLOURS || (index + count) > CURSOR_MAX_COLOURS) 823 return (EINVAL); 824 if (!uvm_useracc(p->cmap.red, count, B_READ) || 825 !uvm_useracc(p->cmap.green, count, B_READ) || 826 !uvm_useracc(p->cmap.blue, count, B_READ)) 827 return (EFAULT); 828 } 829 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 830 if (p->size.x > CURSOR_MAX_WIDTH || p->size.y > CURSOR_MAX_HEIGHT) 831 return (EINVAL); 832 icount = sizeof(u_int32_t) * p->size.y; 833 if (!uvm_useracc(p->image, icount, B_READ) || 834 !uvm_useracc(p->mask, icount, B_READ)) 835 return (EFAULT); 836 } 837 838 if (v & WSDISPLAY_CURSOR_DOCUR) 839 dc->dc_curenb = p->enable; 840 if (v & WSDISPLAY_CURSOR_DOPOS) 841 set_curpos(sc, &p->pos); 842 if (v & WSDISPLAY_CURSOR_DOHOT) 843 cc->cc_hot = p->hot; 844 if (v & WSDISPLAY_CURSOR_DOCMAP) { 845 copyin(p->cmap.red, &cc->cc_color[index], count); 846 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 847 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 848 } 849 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 850 cc->cc_size = p->size; 851 memset(cc->cc_image, 0, sizeof cc->cc_image); 852 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 853 copyin(p->image, cc->cc_image, icount); 854 copyin(p->mask, cc->cc_mask, icount); 855 } 856 dc->dc_changed |= v; 857 858 return (0); 859 #undef cc 860 } 861 862 863 static int 864 get_cursor(sc, p) 865 struct vidcvideo_softc *sc; 866 struct wsdisplay_cursor *p; 867 { 868 return (EPASSTHROUGH); /* XXX */ 869 } 870 871 872 static void 873 set_curpos(sc, curpos) 874 struct vidcvideo_softc *sc; 875 struct wsdisplay_curpos *curpos; 876 { 877 struct fb_devconfig *dc = sc->sc_dc; 878 int x = curpos->x, y = curpos->y; 879 880 if (y < 0) 881 y = 0; 882 else if (y > dc->dc_ht) 883 y = dc->dc_ht; 884 if (x < 0) 885 x = 0; 886 else if (x > dc->dc_wid) 887 x = dc->dc_wid; 888 dc->dc_cursor.cc_pos.x = x; 889 dc->dc_cursor.cc_pos.y = y; 890 } 891 892 893 static void vv_copyrows(id, srcrow, dstrow, nrows) 894 void *id; 895 int srcrow, dstrow, nrows; 896 { 897 struct rasops_info *ri = id; 898 int height, offset, size; 899 int scrollup, scrolldown; 900 unsigned char *src, *dst; 901 902 /* All movements are done in multiples of character heigths */ 903 height = ri->ri_font->fontheight * nrows; 904 offset = (srcrow - dstrow) * ri->ri_yscale; 905 size = height * ri->ri_stride; 906 907 /* check if we are full screen scrolling */ 908 scrollup = (srcrow + nrows >= ri->ri_rows); 909 scrolldown = (dstrow + nrows >= ri->ri_rows); 910 911 if ((scrollup || scrolldown) && (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM)) { 912 ri->ri_bits = vidcvideo_hwscroll(offset); 913 vidcvideo_progr_scroll(); /* sadistic ; shouldnt this be on vsync? */ 914 915 /* wipe out remains of the screen if nessisary */ 916 if (ri->ri_emuheight != ri->ri_height) vv_eraserows(id, ri->ri_rows, 1, NULL); 917 return; 918 }; 919 920 /* Else we just copy the area : we're braindead for now 921 * Note: we can't use hardware scrolling when the softc isnt known yet... 922 * if its not known we dont have interrupts and we can't change the display 923 * address reliable other than in a Vsync 924 */ 925 926 src = ri->ri_bits + srcrow * ri->ri_font->fontheight * ri->ri_stride; 927 dst = ri->ri_bits + dstrow * ri->ri_font->fontheight * ri->ri_stride; 928 929 bcopy(src, dst, size); 930 } 931 932 933 static void vv_eraserows(id, startrow, nrows, attr) 934 void *id; 935 int startrow, nrows; 936 long attr; 937 { 938 struct rasops_info *ri = id; 939 int height; 940 unsigned char *src; 941 942 /* we're braindead for now */ 943 height = ri->ri_font->fontheight * nrows * ri->ri_stride; 944 945 src = ri->ri_bits + startrow * ri->ri_font->fontheight * ri->ri_stride; 946 947 bzero(src, height); 948 } 949 950 951 static void vv_putchar(id, row, col, uc, attr) 952 void *id; 953 int row, col; 954 u_int uc; 955 long attr; 956 { 957 struct rasops_info *ri = id; 958 struct fb_devconfig *dc = (struct fb_devconfig *) (ri->ri_hw); 959 960 /* delay the write back operation of the screen area */ 961 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 962 dc->dc_changed |= WSDISPLAY_WB_COUNTER; 963 964 /* just delegate */ 965 dc->orig_ri_ops.putchar(id, row, col, uc, attr); 966 } 967