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