cfb.c revision 1.13
1/* $NetBSD: cfb.c,v 1.13 1999/10/19 00:49:34 nisimura Exp $ */ 2 3/* 4 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Tohru Nishimura 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 35__KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.13 1999/10/19 00:49:34 nisimura Exp $"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/device.h> 41#include <sys/malloc.h> 42#include <sys/buf.h> 43#include <sys/ioctl.h> 44#include <vm/vm.h> 45 46#include <machine/bus.h> 47#include <machine/intr.h> 48 49#include <dev/rcons/raster.h> 50#include <dev/wscons/wsconsio.h> 51#include <dev/wscons/wscons_raster.h> 52#include <dev/wscons/wsdisplayvar.h> 53 54#include <dev/tc/tcvar.h> 55#include <dev/ic/bt459reg.h> 56 57#include <uvm/uvm_extern.h> 58 59#if defined(pmax) 60#define machine_btop(x) mips_btop(x) 61#define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x) 62#endif 63 64#if defined(__alpha__) || defined(alpha) 65/* 66 * Digital UNIX never supports PMAG-BA 67 */ 68#define machine_btop(x) alpha_btop(x) 69#define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x) 70#endif 71 72/* 73 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have 74 * obscure register layout such as 2nd and 3rd Bt459 registers are 75 * adjacent each other in a word, i.e., 76 * struct bt459triplet { 77 * struct { 78 * u_int8_t u0; 79 * u_int8_t u1; 80 * u_int8_t u2; 81 * unsigned :8; 82 * } bt_lo; 83 * ... 84 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble. 85 * 86 * struct bt459reg { 87 * u_int32_t bt_lo; 88 * u_int32_t bt_hi; 89 * u_int32_t bt_reg; 90 * u_int32_t bt_cmap; 91 * }; 92 * 93 */ 94 95/* Bt459 hardware registers */ 96#define bt_lo 0 97#define bt_hi 1 98#define bt_reg 2 99#define bt_cmap 3 100 101#define REG(base, index) *((u_int32_t *)(base) + (index)) 102#define SELECT(vdac, regno) do { \ 103 REG(vdac, bt_lo) = ((regno) & 0x00ff); \ 104 REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8; \ 105 tc_wmb(); \ 106 } while (0) 107 108struct fb_devconfig { 109 vaddr_t dc_vaddr; /* memory space virtual base address */ 110 paddr_t dc_paddr; /* memory space physical base address */ 111 vsize_t dc_size; /* size of slot memory */ 112 int dc_wid; /* width of frame buffer */ 113 int dc_ht; /* height of frame buffer */ 114 int dc_depth; /* depth, bits per pixel */ 115 int dc_rowbytes; /* bytes in a FB scan line */ 116 vaddr_t dc_videobase; /* base of flat frame buffer */ 117 struct raster dc_raster; /* raster description */ 118 struct rcons dc_rcons; /* raster blitter control info */ 119 int dc_blanked; /* currently has video disabled */ 120}; 121 122struct hwcmap256 { 123#define CMAP_SIZE 256 /* 256 R/G/B entries */ 124 u_int8_t r[CMAP_SIZE]; 125 u_int8_t g[CMAP_SIZE]; 126 u_int8_t b[CMAP_SIZE]; 127}; 128 129struct hwcursor64 { 130 struct wsdisplay_curpos cc_pos; 131 struct wsdisplay_curpos cc_hot; 132 struct wsdisplay_curpos cc_size; 133 struct wsdisplay_curpos cc_magic; 134#define CURSOR_MAX_SIZE 64 135 u_int8_t cc_color[6]; 136 u_int64_t cc_image[64 + 64]; 137}; 138 139struct cfb_softc { 140 struct device sc_dev; 141 struct fb_devconfig *sc_dc; /* device configuration */ 142 struct hwcmap256 sc_cmap; /* software copy of colormap */ 143 struct hwcursor64 sc_cursor; /* software copy of cursor */ 144 int sc_curenb; /* cursor sprite enabled */ 145 int sc_changed; /* need update of colormap */ 146#define DATA_ENB_CHANGED 0x01 /* cursor enable changed */ 147#define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */ 148#define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */ 149#define DATA_CMAP_CHANGED 0x08 /* colormap changed */ 150#define DATA_ALL_CHANGED 0x0f 151 int nscreens; 152}; 153 154#define CX_MAGIC_X 220 155#define CX_MAGIC_Y 35 156 157#define CX_FB_OFFSET 0x000000 158#define CX_FB_SIZE 0x100000 159#define CX_BT459_OFFSET 0x200000 160#define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 161 162int cfbmatch __P((struct device *, struct cfdata *, void *)); 163void cfbattach __P((struct device *, struct device *, void *)); 164 165struct cfattach cfb_ca = { 166 sizeof(struct cfb_softc), cfbmatch, cfbattach, 167}; 168 169void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 170struct fb_devconfig cfb_console_dc; 171tc_addr_t cfb_consaddr; 172 173struct wsdisplay_emulops cfb_emulops = { 174 rcons_cursor, /* could use hardware cursor; punt */ 175 rcons_mapchar, 176 rcons_putchar, 177 rcons_copycols, 178 rcons_erasecols, 179 rcons_copyrows, 180 rcons_eraserows, 181 rcons_alloc_attr 182}; 183 184struct wsscreen_descr cfb_stdscreen = { 185 "std", 0, 0, 186 &cfb_emulops, 187 0, 0, 188 WSSCREEN_REVERSE 189}; 190 191const struct wsscreen_descr *_cfb_scrlist[] = { 192 &cfb_stdscreen, 193}; 194 195struct wsscreen_list cfb_screenlist = { 196 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist 197}; 198 199int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 200int cfbmmap __P((void *, off_t, int)); 201 202int cfb_alloc_screen __P((void *, const struct wsscreen_descr *, 203 void **, int *, int *, long *)); 204void cfb_free_screen __P((void *, void *)); 205void cfb_show_screen __P((void *, void *)); 206 207struct wsdisplay_accessops cfb_accessops = { 208 cfbioctl, 209 cfbmmap, 210 cfb_alloc_screen, 211 cfb_free_screen, 212 cfb_show_screen, 213 0 /* load_font */ 214}; 215 216int cfb_cnattach __P((tc_addr_t)); 217int cfbintr __P((void *)); 218void cfbinit __P((struct fb_devconfig *)); 219 220static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 221static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 222static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 223static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 224static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *)); 225static void bt459_set_curpos __P((struct cfb_softc *)); 226 227/* 228 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 229 * M M M M I I I I M I M I M I M I 230 * [ before ] [ after ] 231 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 232 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 233 */ 234const static u_int8_t shuffle[256] = { 235 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 236 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 237 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 238 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 239 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 240 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 241 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 242 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 243 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 244 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 245 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 246 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 247 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 248 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 249 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 250 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 251 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 252 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 253 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 254 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 255 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 256 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 257 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 258 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 259 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 260 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 261 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 262 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 263 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 264 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 265 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 266 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 267}; 268 269int 270cfbmatch(parent, match, aux) 271 struct device *parent; 272 struct cfdata *match; 273 void *aux; 274{ 275 struct tc_attach_args *ta = aux; 276 277 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0) 278 return (0); 279 280 return (1); 281} 282 283void 284cfb_getdevconfig(dense_addr, dc) 285 tc_addr_t dense_addr; 286 struct fb_devconfig *dc; 287{ 288 struct raster *rap; 289 struct rcons *rcp; 290 int i; 291 292 dc->dc_vaddr = dense_addr; 293 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET); 294 295 dc->dc_wid = 1024; 296 dc->dc_ht = 864; 297 dc->dc_depth = 8; 298 dc->dc_rowbytes = 1024; 299 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET; 300 dc->dc_blanked = 0; 301 302 /* initialize colormap and cursor resource */ 303 cfbinit(dc); 304 305 /* clear the screen */ 306 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 307 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 308 309 /* initialize the raster */ 310 rap = &dc->dc_raster; 311 rap->width = dc->dc_wid; 312 rap->height = dc->dc_ht; 313 rap->depth = dc->dc_depth; 314 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t); 315 rap->pixels = (u_int32_t *)dc->dc_videobase; 316 317 /* initialize the raster console blitter */ 318 rcp = &dc->dc_rcons; 319 rcp->rc_sp = rap; 320 rcp->rc_crow = rcp->rc_ccol = -1; 321 rcp->rc_crowp = &rcp->rc_crow; 322 rcp->rc_ccolp = &rcp->rc_ccol; 323 rcons_init(rcp, 34, 80); 324 325 cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow; 326 cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol; 327} 328 329void 330cfbattach(parent, self, aux) 331 struct device *parent, *self; 332 void *aux; 333{ 334 struct cfb_softc *sc = (struct cfb_softc *)self; 335 struct tc_attach_args *ta = aux; 336 struct wsemuldisplaydev_attach_args waa; 337 struct hwcmap256 *cm; 338 int console; 339 340 console = (ta->ta_addr == cfb_consaddr); 341 if (console) { 342 sc->sc_dc = &cfb_console_dc; 343 sc->nscreens = 1; 344 } 345 else { 346 sc->sc_dc = (struct fb_devconfig *) 347 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 348 cfb_getdevconfig(ta->ta_addr, sc->sc_dc); 349 } 350 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht, 351 sc->sc_dc->dc_depth); 352 353 cm = &sc->sc_cmap; 354 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */ 355 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */ 356 357 sc->sc_cursor.cc_magic.x = CX_MAGIC_X; 358 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y; 359 360 /* Establish an interrupt handler, and clear any pending interrupts */ 361 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, cfbintr, sc); 362 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0; 363 364 waa.console = console; 365 waa.scrdata = &cfb_screenlist; 366 waa.accessops = &cfb_accessops; 367 waa.accesscookie = sc; 368 369 config_found(self, &waa, wsemuldisplaydevprint); 370} 371 372int 373cfbioctl(v, cmd, data, flag, p) 374 void *v; 375 u_long cmd; 376 caddr_t data; 377 int flag; 378 struct proc *p; 379{ 380 struct cfb_softc *sc = v; 381 struct fb_devconfig *dc = sc->sc_dc; 382 int turnoff; 383 384 switch (cmd) { 385 case WSDISPLAYIO_GTYPE: 386 *(u_int *)data = WSDISPLAY_TYPE_CFB; 387 return (0); 388 389 case WSDISPLAYIO_GINFO: 390#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 391 wsd_fbip->height = sc->sc_dc->dc_ht; 392 wsd_fbip->width = sc->sc_dc->dc_wid; 393 wsd_fbip->depth = sc->sc_dc->dc_depth; 394 wsd_fbip->cmsize = CMAP_SIZE; 395#undef fbt 396 return (0); 397 398 case WSDISPLAYIO_GETCMAP: 399 return get_cmap(sc, (struct wsdisplay_cmap *)data); 400 401 case WSDISPLAYIO_PUTCMAP: 402 return set_cmap(sc, (struct wsdisplay_cmap *)data); 403 404 case WSDISPLAYIO_SVIDEO: 405 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 406 if ((dc->dc_blanked == 0) ^ turnoff) { 407 dc->dc_blanked = turnoff; 408 /* XXX later XXX */ 409 } 410 return (0); 411 412 case WSDISPLAYIO_GVIDEO: 413 *(u_int *)data = dc->dc_blanked ? 414 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 415 return (0); 416 417 case WSDISPLAYIO_GCURPOS: 418 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 419 return (0); 420 421 case WSDISPLAYIO_SCURPOS: 422 set_curpos(sc, (struct wsdisplay_curpos *)data); 423 bt459_set_curpos(sc); 424 return (0); 425 426 case WSDISPLAYIO_GCURMAX: 427 ((struct wsdisplay_curpos *)data)->x = 428 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 429 return (0); 430 431 case WSDISPLAYIO_GCURSOR: 432 return get_cursor(sc, (struct wsdisplay_cursor *)data); 433 434 case WSDISPLAYIO_SCURSOR: 435 return set_cursor(sc, (struct wsdisplay_cursor *)data); 436 } 437 return ENOTTY; 438} 439 440int 441cfbmmap(v, offset, prot) 442 void *v; 443 off_t offset; 444 int prot; 445{ 446 struct cfb_softc *sc = v; 447 448 if (offset >= CX_FB_SIZE || offset < 0) 449 return (-1); 450 return machine_btop(sc->sc_dc->dc_paddr + offset); 451} 452 453int 454cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 455 void *v; 456 const struct wsscreen_descr *type; 457 void **cookiep; 458 int *curxp, *curyp; 459 long *attrp; 460{ 461 struct cfb_softc *sc = v; 462 long defattr; 463 464 if (sc->nscreens > 0) 465 return (ENOMEM); 466 467 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */ 468 *curxp = 0; 469 *curyp = 0; 470 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr); 471 *attrp = defattr; 472 sc->nscreens++; 473 return (0); 474} 475 476void 477cfb_free_screen(v, cookie) 478 void *v; 479 void *cookie; 480{ 481 struct cfb_softc *sc = v; 482 483 if (sc->sc_dc == &cfb_console_dc) 484 panic("cfb_free_screen: console"); 485 486 sc->nscreens--; 487} 488 489void 490cfb_show_screen(v, cookie) 491 void *v; 492 void *cookie; 493{ 494} 495 496int 497cfb_cnattach(addr) 498 tc_addr_t addr; 499{ 500 struct fb_devconfig *dcp = &cfb_console_dc; 501 long defattr; 502 503 cfb_getdevconfig(addr, dcp); 504 505 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr); 506 507 wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons, 508 0, 0, defattr); 509 cfb_consaddr = addr; 510 return(0); 511} 512 513 514int 515cfbintr(arg) 516 void *arg; 517{ 518 struct cfb_softc *sc = arg; 519 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 520 struct bt459reg *vdac; 521 int v; 522 523 *(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0; 524 if (sc->sc_changed == 0) 525 return (1); 526 527 vdac = (void *)(cfbbase + CX_BT459_OFFSET); 528 v = sc->sc_changed; 529 sc->sc_changed = 0; 530 if (v & DATA_ENB_CHANGED) { 531 SELECT(vdac, BT459_REG_CCR); 532 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00; 533 } 534 if (v & DATA_CURCMAP_CHANGED) { 535 u_int8_t *cp = sc->sc_cursor.cc_color; 536 537 SELECT(vdac, BT459_REG_CCOLOR_2); 538 REG(vdac, bt_reg) = cp[1]; tc_wmb(); 539 REG(vdac, bt_reg) = cp[3]; tc_wmb(); 540 REG(vdac, bt_reg) = cp[5]; tc_wmb(); 541 542 REG(vdac, bt_reg) = cp[0]; tc_wmb(); 543 REG(vdac, bt_reg) = cp[2]; tc_wmb(); 544 REG(vdac, bt_reg) = cp[4]; tc_wmb(); 545 } 546 if (v & DATA_CURSHAPE_CHANGED) { 547 u_int8_t *ip, *mp, img, msk; 548 u_int8_t u; 549 int bcnt; 550 551 ip = (u_int8_t *)sc->sc_cursor.cc_image; 552 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 553 554 bcnt = 0; 555 SELECT(vdac, BT459_REG_CRAM_BASE+0); 556 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 557 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 558 /* pad right half 32 pixel when smaller than 33 */ 559 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 560 REG(vdac, bt_reg) = 0; tc_wmb(); 561 REG(vdac, bt_reg) = 0; tc_wmb(); 562 } 563 else { 564 img = *ip++; 565 msk = *mp++; 566 img &= msk; /* cookie off image */ 567 u = (msk & 0x0f) << 4 | (img & 0x0f); 568 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 569 u = (msk & 0xf0) | (img & 0xf0) >> 4; 570 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 571 } 572 bcnt += 2; 573 } 574 /* pad unoccupied scan lines */ 575 while (bcnt < CURSOR_MAX_SIZE * 16) { 576 REG(vdac, bt_reg) = 0; tc_wmb(); 577 REG(vdac, bt_reg) = 0; tc_wmb(); 578 bcnt += 2; 579 } 580 } 581 if (v & DATA_CMAP_CHANGED) { 582 struct hwcmap256 *cm = &sc->sc_cmap; 583 int index; 584 585 SELECT(vdac, 0); 586 for (index = 0; index < CMAP_SIZE; index++) { 587 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb(); 588 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb(); 589 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb(); 590 } 591 } 592 return (1); 593} 594 595void 596cfbinit(dc) 597 struct fb_devconfig *dc; 598{ 599 caddr_t cfbbase = (caddr_t)dc->dc_vaddr; 600 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 601 int i; 602 603 SELECT(vdac, BT459_REG_COMMAND_0); 604 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb(); 605 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb(); 606 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb(); 607 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb(); 608 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb(); 609 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb(); 610 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb(); 611 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb(); 612 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb(); 613 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb(); 614 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb(); 615 616 SELECT(vdac, BT459_REG_CCR); 617 REG(vdac, bt_reg) = 0x0; tc_wmb(); 618 REG(vdac, bt_reg) = 0x0; tc_wmb(); 619 REG(vdac, bt_reg) = 0x0; tc_wmb(); 620 REG(vdac, bt_reg) = 0x0; tc_wmb(); 621 REG(vdac, bt_reg) = 0x0; tc_wmb(); 622 REG(vdac, bt_reg) = 0x0; tc_wmb(); 623 REG(vdac, bt_reg) = 0x0; tc_wmb(); 624 REG(vdac, bt_reg) = 0x0; tc_wmb(); 625 REG(vdac, bt_reg) = 0x0; tc_wmb(); 626 REG(vdac, bt_reg) = 0x0; tc_wmb(); 627 REG(vdac, bt_reg) = 0x0; tc_wmb(); 628 REG(vdac, bt_reg) = 0x0; tc_wmb(); 629 REG(vdac, bt_reg) = 0x0; tc_wmb(); 630 631 /* build sane colormap */ 632 SELECT(vdac, 0); 633 REG(vdac, bt_cmap) = 0; tc_wmb(); 634 REG(vdac, bt_cmap) = 0; tc_wmb(); 635 REG(vdac, bt_cmap) = 0; tc_wmb(); 636 for (i = 1; i < CMAP_SIZE; i++) { 637 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 638 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 639 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 640 } 641 642 /* clear out cursor image */ 643 SELECT(vdac, BT459_REG_CRAM_BASE); 644 for (i = 0; i < 1024; i++) 645 REG(vdac, bt_reg) = 0xff; tc_wmb(); 646 647 /* 648 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 649 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for 650 * image color. CCOLOR_1 will be never used. 651 */ 652 SELECT(vdac, BT459_REG_CCOLOR_1); 653 REG(vdac, bt_reg) = 0xff; tc_wmb(); 654 REG(vdac, bt_reg) = 0xff; tc_wmb(); 655 REG(vdac, bt_reg) = 0xff; tc_wmb(); 656 657 REG(vdac, bt_reg) = 0; tc_wmb(); 658 REG(vdac, bt_reg) = 0; tc_wmb(); 659 REG(vdac, bt_reg) = 0; tc_wmb(); 660 661 REG(vdac, bt_reg) = 0xff; tc_wmb(); 662 REG(vdac, bt_reg) = 0xff; tc_wmb(); 663 REG(vdac, bt_reg) = 0xff; tc_wmb(); 664} 665 666static int 667get_cmap(sc, p) 668 struct cfb_softc *sc; 669 struct wsdisplay_cmap *p; 670{ 671 u_int index = p->index, count = p->count; 672 673 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 674 return (EINVAL); 675 676 if (!uvm_useracc(p->red, count, B_WRITE) || 677 !uvm_useracc(p->green, count, B_WRITE) || 678 !uvm_useracc(p->blue, count, B_WRITE)) 679 return (EFAULT); 680 681 copyout(&sc->sc_cmap.r[index], p->red, count); 682 copyout(&sc->sc_cmap.g[index], p->green, count); 683 copyout(&sc->sc_cmap.b[index], p->blue, count); 684 685 return (0); 686} 687 688static int 689set_cmap(sc, p) 690 struct cfb_softc *sc; 691 struct wsdisplay_cmap *p; 692{ 693 u_int index = p->index, count = p->count; 694 695 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 696 return (EINVAL); 697 698 if (!uvm_useracc(p->red, count, B_READ) || 699 !uvm_useracc(p->green, count, B_READ) || 700 !uvm_useracc(p->blue, count, B_READ)) 701 return (EFAULT); 702 703 copyin(p->red, &sc->sc_cmap.r[index], count); 704 copyin(p->green, &sc->sc_cmap.g[index], count); 705 copyin(p->blue, &sc->sc_cmap.b[index], count); 706 707 sc->sc_changed |= DATA_CMAP_CHANGED; 708 709 return (0); 710} 711 712static int 713set_cursor(sc, p) 714 struct cfb_softc *sc; 715 struct wsdisplay_cursor *p; 716{ 717#define cc (&sc->sc_cursor) 718 int v, index, count, icount; 719 720 v = p->which; 721 if (v & WSDISPLAY_CURSOR_DOCMAP) { 722 index = p->cmap.index; 723 count = p->cmap.count; 724 if (index >= 2 || (index + count) > 2) 725 return (EINVAL); 726 if (!uvm_useracc(p->cmap.red, count, B_READ) || 727 !uvm_useracc(p->cmap.green, count, B_READ) || 728 !uvm_useracc(p->cmap.blue, count, B_READ)) 729 return (EFAULT); 730 } 731 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 732 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 733 return (EINVAL); 734 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 735 if (!uvm_useracc(p->image, icount, B_READ) || 736 !uvm_useracc(p->mask, icount, B_READ)) 737 return (EFAULT); 738 } 739 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 740 if (v & WSDISPLAY_CURSOR_DOCUR) 741 cc->cc_hot = p->hot; 742 if (v & WSDISPLAY_CURSOR_DOPOS) 743 set_curpos(sc, &p->pos); 744 bt459_set_curpos(sc); 745 } 746 747 sc->sc_changed = 0; 748 if (v & WSDISPLAY_CURSOR_DOCUR) { 749 sc->sc_curenb = p->enable; 750 sc->sc_changed |= DATA_ENB_CHANGED; 751 } 752 if (v & WSDISPLAY_CURSOR_DOCMAP) { 753 copyin(p->cmap.red, &cc->cc_color[index], count); 754 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 755 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 756 sc->sc_changed |= DATA_CURCMAP_CHANGED; 757 } 758 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 759 cc->cc_size = p->size; 760 memset(cc->cc_image, 0, sizeof cc->cc_image); 761 copyin(p->image, cc->cc_image, icount); 762 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount); 763 sc->sc_changed |= DATA_CURSHAPE_CHANGED; 764 } 765 766 return (0); 767#undef cc 768} 769 770static int 771get_cursor(sc, p) 772 struct cfb_softc *sc; 773 struct wsdisplay_cursor *p; 774{ 775 return (ENOTTY); /* XXX */ 776} 777 778static void 779set_curpos(sc, curpos) 780 struct cfb_softc *sc; 781 struct wsdisplay_curpos *curpos; 782{ 783 struct fb_devconfig *dc = sc->sc_dc; 784 int x = curpos->x, y = curpos->y; 785 786 if (y < 0) 787 y = 0; 788 else if (y > dc->dc_ht) 789 y = dc->dc_ht; 790 if (x < 0) 791 x = 0; 792 else if (x > dc->dc_wid) 793 x = dc->dc_wid; 794 sc->sc_cursor.cc_pos.x = x; 795 sc->sc_cursor.cc_pos.y = y; 796} 797 798void 799bt459_set_curpos(sc) 800 struct cfb_softc *sc; 801{ 802 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 803 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 804 int x, y, s; 805 806 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 807 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 808 809 x += sc->sc_cursor.cc_magic.x; 810 y += sc->sc_cursor.cc_magic.y; 811 812 s = spltty(); 813 814 SELECT(vdac, BT459_REG_CURSOR_X_LOW); 815 REG(vdac, bt_reg) = x; tc_wmb(); 816 REG(vdac, bt_reg) = x >> 8; tc_wmb(); 817 REG(vdac, bt_reg) = y; tc_wmb(); 818 REG(vdac, bt_reg) = y >> 8; tc_wmb(); 819 820 splx(s); 821} 822