1 /* $NetBSD: vidcvideo.c,v 1.16 2002/10/02 15:45:14 thorpej 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.16 2002/10/02 15:45:14 thorpej 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 CFATTACH_DECL(vidcvideo, sizeof(struct vidcvideo_softc), 147 vidcvideo_match, vidcvideo_attach, NULL, NULL); 148 149 static struct fb_devconfig vidcvideo_console_dc; 150 static int vidcvideo_is_console; 151 152 153 static struct wsscreen_descr vidcvideo_stdscreen = { 154 "std", 0, 0, 155 0, /* textops */ 156 0, 0, 157 WSSCREEN_REVERSE 158 }; 159 160 static const struct wsscreen_descr *_vidcvideo_scrlist[] = { 161 &vidcvideo_stdscreen, 162 }; 163 164 static const struct wsscreen_list vidcvideo_screenlist = { 165 sizeof(_vidcvideo_scrlist) / sizeof(struct wsscreen_descr *), _vidcvideo_scrlist 166 }; 167 168 static int vidcvideoioctl __P((void *, u_long, caddr_t, int, struct proc *)); 169 static paddr_t vidcvideommap __P((void *, off_t, int)); 170 171 static int vidcvideo_alloc_screen __P((void *, const struct wsscreen_descr *, 172 void **, int *, int *, long *)); 173 static void vidcvideo_free_screen __P((void *, void *)); 174 static int vidcvideo_show_screen __P((void *, void *, int, 175 void (*) (void *, int, int), void *)); 176 177 static const struct wsdisplay_accessops vidcvideo_accessops = { 178 vidcvideoioctl, 179 vidcvideommap, 180 vidcvideo_alloc_screen, 181 vidcvideo_free_screen, 182 vidcvideo_show_screen, 183 0 /* load_font */ 184 }; 185 186 187 /* Function prototypes */ 188 int vidcvideo_cnattach __P((vaddr_t)); 189 static void vidcvideo_colourmap_and_cursor_init __P((struct fb_devconfig *)); 190 191 static int get_cmap __P((struct vidcvideo_softc *, struct wsdisplay_cmap *)); 192 static int set_cmap __P((struct vidcvideo_softc *, struct wsdisplay_cmap *)); 193 static int set_cursor __P((struct vidcvideo_softc *, struct wsdisplay_cursor *)); 194 static int get_cursor __P((struct vidcvideo_softc *, struct wsdisplay_cursor *)); 195 static void set_curpos __P((struct vidcvideo_softc *, struct wsdisplay_curpos *)); 196 static void vidcvideo_getdevconfig __P((vaddr_t, struct fb_devconfig *)); 197 198 static int vidcvideointr __P((void *)); 199 static void vidcvideo_config_wscons __P((struct fb_devconfig *)); 200 201 202 /* Acceleration function prototypes */ 203 static void vv_copyrows __P((void *, int, int, int)); 204 static void vv_eraserows __P((void *, int, int, long)); 205 static void vv_putchar __P((void *c, int row, int col, u_int uc, long attr)); 206 207 208 static int 209 vidcvideo_match(parent, match, aux) 210 struct device *parent; 211 struct cfdata *match; 212 void *aux; 213 { 214 /* Can't probe AFAIK ; how ? */ 215 return (1); 216 } 217 218 219 static void 220 vidcvideo_getdevconfig(dense_addr, dc) 221 vaddr_t dense_addr; 222 struct fb_devconfig *dc; 223 { 224 dc->dc_vaddr = dense_addr; 225 (void) pmap_extract(pmap_kernel(), dc->dc_vaddr, &(dc->dc_paddr)); 226 227 vidcvideo_getmode(&dc->mode_info); 228 229 dc->dc_wid = dc->mode_info.hder; 230 dc->dc_ht = dc->mode_info.vder; 231 dc->dc_log2_depth = dc->mode_info.log2_bpp; 232 dc->dc_depth = 1 << dc->dc_log2_depth; 233 dc->dc_videobase = dc->dc_vaddr; 234 dc->dc_blanked = 0; 235 236 /* this should/could be done somewhat more elegant! */ 237 switch (dc->dc_depth) { 238 case 1: 239 dc->dc_rowbytes = dc->dc_wid / 8; 240 break; 241 case 2: 242 dc->dc_rowbytes = dc->dc_wid / 4; 243 break; 244 case 4: 245 dc->dc_rowbytes = dc->dc_wid / 2; 246 break; 247 case 8: 248 dc->dc_rowbytes = dc->dc_wid; 249 break; 250 case 16: 251 dc->dc_rowbytes = dc->dc_wid * 2; 252 break; 253 case 32: 254 dc->dc_rowbytes = dc->dc_wid * 4; 255 break; 256 default: 257 printf("Unknown colour depth %d ... what to do ?", dc->dc_depth); 258 break; 259 }; 260 261 /* euhm... correct ? i.e. not complete VIDC memory */ 262 dc->dc_size = dc->mode_info.vder * dc->dc_rowbytes; 263 264 /* initialize colormap and cursor resource */ 265 vidcvideo_colourmap_and_cursor_init(dc); 266 267 dc->rinfo.ri_flg = 0; /* RI_CENTER; */ 268 dc->rinfo.ri_depth = dc->dc_depth; 269 dc->rinfo.ri_bits = (void *) dc->dc_videobase; 270 dc->rinfo.ri_width = dc->dc_wid; 271 dc->rinfo.ri_height = dc->dc_ht; 272 dc->rinfo.ri_stride = dc->dc_rowbytes; 273 dc->rinfo.ri_hw = dc; /* link back */ 274 275 /* intitialise miscelanious */ 276 dc->dc_writeback_delay = 0; 277 } 278 279 280 static void 281 vidcvideo_config_wscons(dc) 282 struct fb_devconfig *dc; 283 { 284 int i, cookie, font_not_locked; 285 286 /* clear the screen ; why not a memset ? - it was this way so keep it for now */ 287 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 288 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 289 290 wsfont_init(); 291 292 /* prefer 8 pixel wide font */ 293 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_L2R, 294 WSDISPLAY_FONTORDER_L2R); 295 if (cookie <= 0) 296 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 297 WSDISPLAY_FONTORDER_L2R); 298 299 if (cookie < 0) { 300 /* Can I even print here ? */ 301 printf("Font table empty! exiting\n"); 302 return; 303 }; 304 305 font_not_locked = wsfont_lock(cookie, &dc->rinfo.ri_font); 306 307 dc->rinfo.ri_wsfcookie = cookie; 308 309 rasops_init(&dc->rinfo, 310 dc->rinfo.ri_height / dc->rinfo.ri_font->fontheight, 311 dc->rinfo.ri_width / dc->rinfo.ri_font->fontwidth 312 ); 313 314 /* 315 * Provide a hook for the acceleration functions and make a copy of the 316 * original rasops functions for passing on calls 317 */ 318 dc->rinfo.ri_hw = dc; 319 memcpy(&(dc->orig_ri_ops), &(dc->rinfo.ri_ops), sizeof(struct wsdisplay_emulops)); 320 321 /* add our accelerated functions */ 322 dc->rinfo.ri_ops.eraserows = vv_eraserows; 323 dc->rinfo.ri_ops.copyrows = vv_copyrows; 324 325 /* add the extra activity measuring functions; they just delegate on */ 326 dc->rinfo.ri_ops.putchar = vv_putchar; 327 328 /* XXX shouldn't be global */ 329 vidcvideo_stdscreen.nrows = dc->rinfo.ri_rows; 330 vidcvideo_stdscreen.ncols = dc->rinfo.ri_cols; 331 vidcvideo_stdscreen.textops = &dc->rinfo.ri_ops; 332 vidcvideo_stdscreen.capabilities = dc->rinfo.ri_caps; 333 334 if (font_not_locked) { 335 printf(" warning ... couldn't lock font! "); 336 }; 337 } 338 339 340 static void 341 vidcvideo_attach(parent, self, aux) 342 struct device *parent, *self; 343 void *aux; 344 { 345 struct vidcvideo_softc *sc = (struct vidcvideo_softc *)self; 346 struct fb_devconfig *dc; 347 struct wsemuldisplaydev_attach_args waa; 348 struct hwcmap256 *cm; 349 const u_int8_t *p; 350 long defattr; 351 int index; 352 353 vidcvideo_init(); 354 if (sc->nscreens == 0) { 355 sc->sc_dc = &vidcvideo_console_dc; 356 if (!vidcvideo_is_console) { 357 printf(" : non console (no kbd yet) "); 358 vidcvideo_getdevconfig(videomemory.vidm_vbase, sc->sc_dc); 359 vidcvideo_config_wscons(sc->sc_dc); 360 (*sc->sc_dc->rinfo.ri_ops.allocattr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 361 }; 362 sc->nscreens = 1; 363 } else { 364 printf(": allready attached ... can't cope with this\n"); 365 return; 366 }; 367 368 dc = sc->sc_dc; 369 370 vidcvideo_printdetails(); 371 printf(": using %d x %d, %dbpp\n", dc->dc_wid, dc->dc_ht, 372 dc->dc_depth); 373 374 /* initialise rasops */ 375 cm = &dc->dc_cmap; 376 p = rasops_cmap; 377 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 378 cm->r[index] = p[0]; 379 cm->g[index] = p[1]; 380 cm->b[index] = p[2]; 381 } 382 383 /* what does these do ? */ 384 dc->dc_cursor.cc_magic.x = CX_MAGIC_X; 385 dc->dc_cursor.cc_magic.y = CX_MAGIC_Y; 386 387 /* set up interrupt flags */ 388 dc->dc_changed |= WSDISPLAY_CMAP_DOLUT; 389 390 /* 391 * Set up a link in the rasops structure to our device config 392 * for acceleration stuff 393 */ 394 dc->rinfo.ri_hw = sc->sc_dc; 395 396 /* Establish an interrupt handler, and clear any pending interrupts */ 397 intr_claim(IRQ_FLYBACK, IPL_TTY, "vblank", vidcvideointr, dc); 398 399 waa.console = (vidcvideo_is_console ? 1 : 0); 400 waa.scrdata = &vidcvideo_screenlist; 401 waa.accessops = &vidcvideo_accessops; 402 waa.accesscookie = sc; 403 404 config_found(self, &waa, wsemuldisplaydevprint); 405 } 406 407 408 static int 409 vidcvideoioctl(v, cmd, data, flag, p) 410 void *v; 411 u_long cmd; 412 caddr_t data; 413 int flag; 414 struct proc *p; 415 { 416 struct vidcvideo_softc *sc = v; 417 struct fb_devconfig *dc = sc->sc_dc; 418 int state; 419 420 switch (cmd) { 421 case WSDISPLAYIO_GTYPE: 422 *(u_int *)data = WSDISPLAY_TYPE_VIDC; 423 return (0); 424 425 case WSDISPLAYIO_GINFO: 426 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 427 wsd_fbip->height = dc->dc_ht; 428 wsd_fbip->width = dc->dc_wid; 429 wsd_fbip->depth = dc->dc_depth; 430 wsd_fbip->cmsize = CMAP_SIZE; 431 #undef fbt 432 return (0); 433 434 case WSDISPLAYIO_GETCMAP: 435 return get_cmap(sc, (struct wsdisplay_cmap *)data); 436 437 case WSDISPLAYIO_PUTCMAP: 438 return set_cmap(sc, (struct wsdisplay_cmap *)data); 439 440 case WSDISPLAYIO_SVIDEO: 441 state = *(int *)data; 442 dc->dc_blanked = (state == WSDISPLAYIO_VIDEO_OFF); 443 dc->dc_changed |= WSDISPLAY_VIDEO_ONOFF; 444 /* done on video blank */ 445 return (0); 446 447 case WSDISPLAYIO_GVIDEO: 448 *(u_int *)data = dc->dc_blanked ? 449 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 450 return (0); 451 452 case WSDISPLAYIO_GCURPOS: 453 *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos; 454 return (0); 455 456 case WSDISPLAYIO_SCURPOS: 457 set_curpos(sc, (struct wsdisplay_curpos *)data); 458 dc->dc_changed |= WSDISPLAY_CURSOR_DOPOS; 459 return (0); 460 461 case WSDISPLAYIO_GCURMAX: 462 ((struct wsdisplay_curpos *)data)->x = CURSOR_MAX_WIDTH; 463 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_HEIGHT; 464 return (0); 465 466 case WSDISPLAYIO_GCURSOR: 467 return get_cursor(sc, (struct wsdisplay_cursor *)data); 468 469 case WSDISPLAYIO_SCURSOR: 470 return set_cursor(sc, (struct wsdisplay_cursor *)data); 471 472 case WSDISPLAYIO_SMODE: 473 state = *(int *)data; 474 if (state == WSDISPLAYIO_MODE_MAPPED) { 475 dc->dc_hwscroll_cookie = vidcvideo_hwscroll_reset(); 476 }; 477 if (state == WSDISPLAYIO_MODE_EMUL) { 478 vidcvideo_hwscroll_back(dc->dc_hwscroll_cookie); 479 }; 480 vidcvideo_progr_scroll(); 481 482 return (0); 483 } 484 return EPASSTHROUGH; 485 } 486 487 488 paddr_t 489 vidcvideommap(v, offset, prot) 490 void *v; 491 off_t offset; 492 int prot; 493 { 494 struct vidcvideo_softc *sc = v; 495 496 if (offset >= sc->sc_dc->dc_size || offset < 0) 497 return (-1); 498 499 return arm_btop(sc->sc_dc->dc_paddr + offset); 500 } 501 502 503 static int 504 vidcvideo_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 505 void *v; 506 const struct wsscreen_descr *type; 507 void **cookiep; 508 int *curxp, *curyp; 509 long *attrp; 510 { 511 struct vidcvideo_softc *sc = v; 512 struct fb_devconfig *dc = sc->sc_dc; 513 long defattr; 514 515 /* 516 * One and just only one for now :( ... if the vidcconsole is not the 517 * console then this makes one wsconsole screen free for use ! 518 */ 519 if ((sc->nscreens > 1) || vidcvideo_is_console) 520 return (ENOMEM); 521 522 /* Add the screen to wscons to control */ 523 *cookiep = &dc->rinfo; 524 *curxp = 0; 525 *curyp = 0; 526 vidcvideo_getdevconfig(videomemory.vidm_vbase, dc); 527 vidcvideo_config_wscons(dc); 528 (*dc->rinfo.ri_ops.allocattr)(&dc->rinfo, 0, 0, 0, &defattr); 529 *attrp = defattr; 530 sc->nscreens++; 531 532 return (0); 533 } 534 535 536 static void 537 vidcvideo_free_screen(v, cookie) 538 void *v; 539 void *cookie; 540 { 541 struct vidcvideo_softc *sc = v; 542 543 if (sc->sc_dc == &vidcvideo_console_dc) 544 panic("vidcvideo_free_screen: console"); 545 546 sc->nscreens--; 547 } 548 549 550 static int 551 vidcvideo_show_screen(v, cookie, waitok, cb, cbarg) 552 void *v; 553 void *cookie; 554 int waitok; 555 void (*cb) __P((void *, int, int)); 556 void *cbarg; 557 { 558 559 return (0); 560 } 561 562 563 /* EXPORT */ int 564 vidcvideo_cnattach(addr) 565 vaddr_t addr; 566 { 567 struct fb_devconfig *dcp = &vidcvideo_console_dc; 568 long defattr; 569 570 vidcvideo_init(); 571 vidcvideo_getdevconfig(addr, dcp); 572 vidcvideo_config_wscons(dcp); 573 (*dcp->rinfo.ri_ops.allocattr)(&dcp->rinfo, 0, 0, 0, &defattr); 574 wsdisplay_cnattach(&vidcvideo_stdscreen, &dcp->rinfo, 0, 0, defattr); 575 576 vidcvideo_is_console = 1; 577 return(0); 578 } 579 580 581 static int 582 vidcvideointr(arg) 583 void *arg; 584 { 585 struct fb_devconfig *dc = arg; 586 int v, cleared = 0; 587 588 v = dc->dc_changed; 589 if (v == 0) 590 return (1); 591 592 if (v & WSDISPLAY_WB_COUNTER) { 593 dc->dc_writeback_delay--; 594 if (dc->dc_writeback_delay == 0) { 595 cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size); 596 cleared |= WSDISPLAY_WB_COUNTER; 597 }; 598 } 599 600 if (v & WSDISPLAY_CMAP_DOLUT) { 601 struct hwcmap256 *cm = &dc->dc_cmap; 602 int index; 603 604 if (dc->dc_depth == 4) { 605 /* palette for 4 bpp is different from 8bpp */ 606 vidcvideo_write(VIDC_PALREG, 0x00000000); 607 for (index=0; index < (1 << dc->dc_depth); index++) 608 vidcvideo_write(VIDC_PALETTE, 609 VIDC_COL(cm->r[index], 610 cm->g[index], 611 cm->b[index])); 612 ; 613 }; 614 615 if (dc->dc_depth == 8) { 616 /* dunno what to do in more than 8bpp */ 617 /* palettes only make sense in 8bpp and less modes on VIDC */ 618 vidcvideo_write(VIDC_PALREG, 0x00000000); 619 for (index = 0; index < CMAP_SIZE; index++) { 620 vidcvideo_write(VIDC_PALETTE, 621 VIDC_COL(cm->r[index], cm->g[index], cm->b[index]) 622 ); 623 }; 624 }; 625 cleared |= WSDISPLAY_CMAP_DOLUT; 626 } 627 628 if (v & WSDISPLAY_VIDEO_ONOFF) { 629 vidcvideo_blank(dc->dc_blanked); 630 cleared |= WSDISPLAY_VIDEO_ONOFF; 631 }; 632 633 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 634 int x, y; 635 x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x; 636 y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y; 637 638 vidcvideo_updatecursor(x, y); 639 cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT; 640 }; 641 642 if (v & WSDISPLAY_CURSOR_DOCUR) { 643 vidcvideo_enablecursor(dc->dc_curenb); 644 cleared |= WSDISPLAY_CURSOR_DOCUR; 645 }; 646 647 648 #if 0 /* XXX snip XXX */ 649 /* XXX kept here as an archive for now XXX */ 650 651 vdac = vidcvideobase + CX_BT459_OFFSET; 652 v = sc->sc_changed; 653 if (v & WSDISPLAY_CURSOR_DOCUR) { 654 SELECT(vdac, BT459_IREG_CCR); 655 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00; 656 } 657 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 658 int x, y; 659 660 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 661 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 662 663 x += sc->sc_cursor.cc_magic.x; 664 y += sc->sc_cursor.cc_magic.y; 665 666 SELECT(vdac, BT459_IREG_CURSOR_X_LOW); 667 REG(vdac, bt_reg) = x; tc_wmb(); 668 REG(vdac, bt_reg) = x >> 8; tc_wmb(); 669 REG(vdac, bt_reg) = y; tc_wmb(); 670 REG(vdac, bt_reg) = y >> 8; tc_wmb(); 671 } 672 if (v & WSDISPLAY_CURSOR_DOCMAP) { 673 u_int8_t *cp = sc->sc_cursor.cc_color; 674 675 SELECT(vdac, BT459_IREG_CCOLOR_2); 676 REG(vdac, bt_reg) = cp[1]; tc_wmb(); 677 REG(vdac, bt_reg) = cp[3]; tc_wmb(); 678 REG(vdac, bt_reg) = cp[5]; tc_wmb(); 679 680 REG(vdac, bt_reg) = cp[0]; tc_wmb(); 681 REG(vdac, bt_reg) = cp[2]; tc_wmb(); 682 REG(vdac, bt_reg) = cp[4]; tc_wmb(); 683 } 684 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 685 u_int8_t *ip, *mp, img, msk; 686 u_int8_t u; 687 int bcnt; 688 689 ip = (u_int8_t *)sc->sc_cursor.cc_image; 690 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_HEIGHT); 691 692 bcnt = 0; 693 SELECT(vdac, BT459_IREG_CRAM_BASE+0); 694 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 695 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 696 /* pad right half 32 pixel when smaller than 33 */ 697 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 698 REG(vdac, bt_reg) = 0; tc_wmb(); 699 REG(vdac, bt_reg) = 0; tc_wmb(); 700 } 701 else { 702 img = *ip++; 703 msk = *mp++; 704 img &= msk; /* cookie off image */ 705 u = (msk & 0x0f) << 4 | (img & 0x0f); 706 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 707 u = (msk & 0xf0) | (img & 0xf0) >> 4; 708 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 709 } 710 bcnt += 2; 711 } 712 /* pad unoccupied scan lines */ 713 while (bcnt < CURSOR_MAX_HEIGHT * 16) { 714 REG(vdac, bt_reg) = 0; tc_wmb(); 715 REG(vdac, bt_reg) = 0; tc_wmb(); 716 bcnt += 2; 717 } 718 } 719 #endif /* XXX snip XXX */ 720 721 dc->dc_changed ^= cleared; 722 723 return (1); 724 } 725 726 727 static u_char ri_col_data[6][6] = { 728 { 0, 0, 0, 0, 0, 0}, /* 1 bpp */ 729 { 0, 0, 0, 0, 0, 0}, /* 2 bpp */ 730 { 0, 0, 0, 0, 0, 0}, /* 4 bpp */ 731 { 0, 0, 0, 0, 0, 0}, /* 8 bpp */ 732 { 6, 5, 5, 0, 6, 11}, /* 16 bpp */ 733 { 8, 8, 8, 0, 8, 16}, /* 32 bpp */ 734 }; 735 736 static void 737 vidcvideo_colourmap_and_cursor_init(dc) 738 struct fb_devconfig *dc; 739 { 740 struct rasops_info *ri = &dc->rinfo; 741 u_char *rgbdat; 742 743 /* Whatever we do later... just make sure we have a 744 * sane palette to start with 745 */ 746 vidcvideo_stdpalette(); 747 748 /* set up rgb bit pattern values for rasops_init */ 749 rgbdat = ri_col_data[dc->dc_log2_depth]; 750 ri->ri_rnum = rgbdat[0]; 751 ri->ri_gnum = rgbdat[1]; 752 ri->ri_bnum = rgbdat[2]; 753 ri->ri_rpos = rgbdat[3]; 754 ri->ri_gpos = rgbdat[4]; 755 ri->ri_bpos = rgbdat[5]; 756 757 } 758 759 760 static int 761 get_cmap(sc, p) 762 struct vidcvideo_softc *sc; 763 struct wsdisplay_cmap *p; 764 { 765 u_int index = p->index, count = p->count; 766 767 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 768 return (EINVAL); 769 770 if (!uvm_useracc(p->red, count, B_WRITE) || 771 !uvm_useracc(p->green, count, B_WRITE) || 772 !uvm_useracc(p->blue, count, B_WRITE)) 773 return (EFAULT); 774 775 copyout(&sc->sc_dc->dc_cmap.r[index], p->red, count); 776 copyout(&sc->sc_dc->dc_cmap.g[index], p->green, count); 777 copyout(&sc->sc_dc->dc_cmap.b[index], p->blue, count); 778 779 return (0); 780 } 781 782 783 static int 784 set_cmap(sc, p) 785 struct vidcvideo_softc *sc; 786 struct wsdisplay_cmap *p; 787 { 788 struct fb_devconfig *dc = sc->sc_dc; 789 u_int index = p->index, count = p->count; 790 791 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 792 return (EINVAL); 793 794 if (!uvm_useracc(p->red, count, B_READ) || 795 !uvm_useracc(p->green, count, B_READ) || 796 !uvm_useracc(p->blue, count, B_READ)) 797 return (EFAULT); 798 799 copyin(p->red, &dc->dc_cmap.r[index], count); 800 copyin(p->green, &dc->dc_cmap.g[index], count); 801 copyin(p->blue, &dc->dc_cmap.b[index], count); 802 dc->dc_changed |= WSDISPLAY_CMAP_DOLUT; 803 return (0); 804 } 805 806 807 static int 808 set_cursor(sc, p) 809 struct vidcvideo_softc *sc; 810 struct wsdisplay_cursor *p; 811 { 812 #define cc (&dc->dc_cursor) 813 struct fb_devconfig *dc = sc->sc_dc; 814 u_int v, index, count, icount; 815 816 v = p->which; 817 if (v & WSDISPLAY_CURSOR_DOCMAP) { 818 index = p->cmap.index; 819 count = p->cmap.count; 820 if (index >= CURSOR_MAX_COLOURS || (index + count) > CURSOR_MAX_COLOURS) 821 return (EINVAL); 822 if (!uvm_useracc(p->cmap.red, count, B_READ) || 823 !uvm_useracc(p->cmap.green, count, B_READ) || 824 !uvm_useracc(p->cmap.blue, count, B_READ)) 825 return (EFAULT); 826 } 827 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 828 if (p->size.x > CURSOR_MAX_WIDTH || p->size.y > CURSOR_MAX_HEIGHT) 829 return (EINVAL); 830 icount = sizeof(u_int32_t) * p->size.y; 831 if (!uvm_useracc(p->image, icount, B_READ) || 832 !uvm_useracc(p->mask, icount, B_READ)) 833 return (EFAULT); 834 } 835 836 if (v & WSDISPLAY_CURSOR_DOCUR) 837 dc->dc_curenb = p->enable; 838 if (v & WSDISPLAY_CURSOR_DOPOS) 839 set_curpos(sc, &p->pos); 840 if (v & WSDISPLAY_CURSOR_DOHOT) 841 cc->cc_hot = p->hot; 842 if (v & WSDISPLAY_CURSOR_DOCMAP) { 843 copyin(p->cmap.red, &cc->cc_color[index], count); 844 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 845 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 846 } 847 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 848 cc->cc_size = p->size; 849 memset(cc->cc_image, 0, sizeof cc->cc_image); 850 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 851 copyin(p->image, cc->cc_image, icount); 852 copyin(p->mask, cc->cc_mask, icount); 853 } 854 dc->dc_changed |= v; 855 856 return (0); 857 #undef cc 858 } 859 860 861 static int 862 get_cursor(sc, p) 863 struct vidcvideo_softc *sc; 864 struct wsdisplay_cursor *p; 865 { 866 return (EPASSTHROUGH); /* XXX */ 867 } 868 869 870 static void 871 set_curpos(sc, curpos) 872 struct vidcvideo_softc *sc; 873 struct wsdisplay_curpos *curpos; 874 { 875 struct fb_devconfig *dc = sc->sc_dc; 876 int x = curpos->x, y = curpos->y; 877 878 if (y < 0) 879 y = 0; 880 else if (y > dc->dc_ht) 881 y = dc->dc_ht; 882 if (x < 0) 883 x = 0; 884 else if (x > dc->dc_wid) 885 x = dc->dc_wid; 886 dc->dc_cursor.cc_pos.x = x; 887 dc->dc_cursor.cc_pos.y = y; 888 } 889 890 891 static void vv_copyrows(id, srcrow, dstrow, nrows) 892 void *id; 893 int srcrow, dstrow, nrows; 894 { 895 struct rasops_info *ri = id; 896 int height, offset, size; 897 int scrollup, scrolldown; 898 unsigned char *src, *dst; 899 900 /* All movements are done in multiples of character heigths */ 901 height = ri->ri_font->fontheight * nrows; 902 offset = (srcrow - dstrow) * ri->ri_yscale; 903 size = height * ri->ri_stride; 904 905 /* check if we are full screen scrolling */ 906 scrollup = (srcrow + nrows >= ri->ri_rows); 907 scrolldown = (dstrow + nrows >= ri->ri_rows); 908 909 if ((scrollup || scrolldown) && (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM)) { 910 ri->ri_bits = vidcvideo_hwscroll(offset); 911 vidcvideo_progr_scroll(); /* sadistic ; shouldnt this be on vsync? */ 912 913 /* wipe out remains of the screen if nessisary */ 914 if (ri->ri_emuheight != ri->ri_height) vv_eraserows(id, ri->ri_rows, 1, NULL); 915 return; 916 }; 917 918 /* Else we just copy the area : we're braindead for now 919 * Note: we can't use hardware scrolling when the softc isnt known yet... 920 * if its not known we dont have interrupts and we can't change the display 921 * address reliable other than in a Vsync 922 */ 923 924 src = ri->ri_bits + srcrow * ri->ri_font->fontheight * ri->ri_stride; 925 dst = ri->ri_bits + dstrow * ri->ri_font->fontheight * ri->ri_stride; 926 927 bcopy(src, dst, size); 928 } 929 930 931 static void vv_eraserows(id, startrow, nrows, attr) 932 void *id; 933 int startrow, nrows; 934 long attr; 935 { 936 struct rasops_info *ri = id; 937 int height; 938 unsigned char *src; 939 940 /* we're braindead for now */ 941 height = ri->ri_font->fontheight * nrows * ri->ri_stride; 942 943 src = ri->ri_bits + startrow * ri->ri_font->fontheight * ri->ri_stride; 944 945 bzero(src, height); 946 } 947 948 949 static void vv_putchar(id, row, col, uc, attr) 950 void *id; 951 int row, col; 952 u_int uc; 953 long attr; 954 { 955 struct rasops_info *ri = id; 956 struct fb_devconfig *dc = (struct fb_devconfig *) (ri->ri_hw); 957 958 /* delay the write back operation of the screen area */ 959 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 960 dc->dc_changed |= WSDISPLAY_WB_COUNTER; 961 962 /* just delegate */ 963 dc->orig_ri_ops.putchar(id, row, col, uc, attr); 964 } 965