cfb.c revision 1.17
1/* $NetBSD: cfb.c,v 1.17 1999/12/15 15:09:37 ad 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.17 1999/12/15 15:09:37 ad 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 162static int cfbmatch __P((struct device *, struct cfdata *, void *)); 163static void cfbattach __P((struct device *, struct device *, void *)); 164 165const struct cfattach cfb_ca = { 166 sizeof(struct cfb_softc), cfbmatch, cfbattach, 167}; 168 169static void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 170static struct fb_devconfig cfb_console_dc; 171static tc_addr_t cfb_consaddr; 172 173static const struct 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 184static struct wsscreen_descr cfb_stdscreen = { 185 "std", 0, 0, 186 &cfb_emulops, 187 0, 0, 188 WSSCREEN_REVERSE 189}; 190 191static const struct wsscreen_descr *_cfb_scrlist[] = { 192 &cfb_stdscreen, 193}; 194 195static const struct wsscreen_list cfb_screenlist = { 196 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist 197}; 198 199static int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 200static int cfbmmap __P((void *, off_t, int)); 201 202static int cfb_alloc_screen __P((void *, const struct wsscreen_descr *, 203 void **, int *, int *, long *)); 204static void cfb_free_screen __P((void *, void *)); 205static int cfb_show_screen __P((void *, void *, int, 206 void (*) (void *, int, int), void *)); 207 208static const struct wsdisplay_accessops cfb_accessops = { 209 cfbioctl, 210 cfbmmap, 211 cfb_alloc_screen, 212 cfb_free_screen, 213 cfb_show_screen, 214 0 /* load_font */ 215}; 216 217int cfb_cnattach __P((tc_addr_t)); 218static int cfbintr __P((void *)); 219static void cfbinit __P((struct fb_devconfig *)); 220 221static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 222static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 223static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 224static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 225static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *)); 226static void bt459_set_curpos __P((struct cfb_softc *)); 227 228/* 229 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 230 * M M M M I I I I M I M I M I M I 231 * [ before ] [ after ] 232 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 233 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 234 */ 235static const u_int8_t shuffle[256] = { 236 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 237 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 238 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 239 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 240 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 241 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 242 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 243 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 244 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 245 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 246 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 247 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 248 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 249 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 250 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 251 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 252 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 253 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 254 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 255 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 256 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 257 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 258 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 259 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 260 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 261 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 262 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 263 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 264 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 265 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 266 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 267 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 268}; 269 270static int 271cfbmatch(parent, match, aux) 272 struct device *parent; 273 struct cfdata *match; 274 void *aux; 275{ 276 struct tc_attach_args *ta = aux; 277 278 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0) 279 return (0); 280 281 return (1); 282} 283 284static void 285cfb_getdevconfig(dense_addr, dc) 286 tc_addr_t dense_addr; 287 struct fb_devconfig *dc; 288{ 289 struct raster *rap; 290 struct rcons *rcp; 291 int i; 292 293 dc->dc_vaddr = dense_addr; 294 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET); 295 296 dc->dc_wid = 1024; 297 dc->dc_ht = 864; 298 dc->dc_depth = 8; 299 dc->dc_rowbytes = 1024; 300 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET; 301 dc->dc_blanked = 0; 302 303 /* initialize colormap and cursor resource */ 304 cfbinit(dc); 305 306 /* clear the screen */ 307 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 308 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 309 310 /* initialize the raster */ 311 rap = &dc->dc_raster; 312 rap->width = dc->dc_wid; 313 rap->height = dc->dc_ht; 314 rap->depth = dc->dc_depth; 315 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t); 316 rap->pixels = (u_int32_t *)dc->dc_videobase; 317 318 /* initialize the raster console blitter */ 319 rcp = &dc->dc_rcons; 320 rcp->rc_sp = rap; 321 rcp->rc_crow = rcp->rc_ccol = -1; 322 rcp->rc_crowp = &rcp->rc_crow; 323 rcp->rc_ccolp = &rcp->rc_ccol; 324 rcons_init(rcp, 34, 80); 325 326 cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow; 327 cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol; 328} 329 330static void 331cfbattach(parent, self, aux) 332 struct device *parent, *self; 333 void *aux; 334{ 335 struct cfb_softc *sc = (struct cfb_softc *)self; 336 struct tc_attach_args *ta = aux; 337 struct wsemuldisplaydev_attach_args waa; 338 struct hwcmap256 *cm; 339 int console; 340 341 console = (ta->ta_addr == cfb_consaddr); 342 if (console) { 343 sc->sc_dc = &cfb_console_dc; 344 sc->nscreens = 1; 345 } 346 else { 347 sc->sc_dc = (struct fb_devconfig *) 348 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 349 cfb_getdevconfig(ta->ta_addr, sc->sc_dc); 350 } 351 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht, 352 sc->sc_dc->dc_depth); 353 354 cm = &sc->sc_cmap; 355 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */ 356 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */ 357 358 sc->sc_cursor.cc_magic.x = CX_MAGIC_X; 359 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y; 360 361 /* Establish an interrupt handler, and clear any pending interrupts */ 362 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc); 363 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0; 364 365 waa.console = console; 366 waa.scrdata = &cfb_screenlist; 367 waa.accessops = &cfb_accessops; 368 waa.accesscookie = sc; 369 370 config_found(self, &waa, wsemuldisplaydevprint); 371} 372 373static int 374cfbioctl(v, cmd, data, flag, p) 375 void *v; 376 u_long cmd; 377 caddr_t data; 378 int flag; 379 struct proc *p; 380{ 381 struct cfb_softc *sc = v; 382 struct fb_devconfig *dc = sc->sc_dc; 383 int turnoff; 384 385 switch (cmd) { 386 case WSDISPLAYIO_GTYPE: 387 *(u_int *)data = WSDISPLAY_TYPE_CFB; 388 return (0); 389 390 case WSDISPLAYIO_GINFO: 391#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 392 wsd_fbip->height = sc->sc_dc->dc_ht; 393 wsd_fbip->width = sc->sc_dc->dc_wid; 394 wsd_fbip->depth = sc->sc_dc->dc_depth; 395 wsd_fbip->cmsize = CMAP_SIZE; 396#undef fbt 397 return (0); 398 399 case WSDISPLAYIO_GETCMAP: 400 return get_cmap(sc, (struct wsdisplay_cmap *)data); 401 402 case WSDISPLAYIO_PUTCMAP: 403 return set_cmap(sc, (struct wsdisplay_cmap *)data); 404 405 case WSDISPLAYIO_SVIDEO: 406 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 407 if ((dc->dc_blanked == 0) ^ turnoff) { 408 dc->dc_blanked = turnoff; 409 /* XXX later XXX */ 410 } 411 return (0); 412 413 case WSDISPLAYIO_GVIDEO: 414 *(u_int *)data = dc->dc_blanked ? 415 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 416 return (0); 417 418 case WSDISPLAYIO_GCURPOS: 419 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 420 return (0); 421 422 case WSDISPLAYIO_SCURPOS: 423 set_curpos(sc, (struct wsdisplay_curpos *)data); 424 bt459_set_curpos(sc); 425 return (0); 426 427 case WSDISPLAYIO_GCURMAX: 428 ((struct wsdisplay_curpos *)data)->x = 429 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 430 return (0); 431 432 case WSDISPLAYIO_GCURSOR: 433 return get_cursor(sc, (struct wsdisplay_cursor *)data); 434 435 case WSDISPLAYIO_SCURSOR: 436 return set_cursor(sc, (struct wsdisplay_cursor *)data); 437 } 438 return ENOTTY; 439} 440 441int 442cfbmmap(v, offset, prot) 443 void *v; 444 off_t offset; 445 int prot; 446{ 447 struct cfb_softc *sc = v; 448 449 if (offset >= CX_FB_SIZE || offset < 0) 450 return (-1); 451 return machine_btop(sc->sc_dc->dc_paddr + offset); 452} 453 454static int 455cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 456 void *v; 457 const struct wsscreen_descr *type; 458 void **cookiep; 459 int *curxp, *curyp; 460 long *attrp; 461{ 462 struct cfb_softc *sc = v; 463 long defattr; 464 465 if (sc->nscreens > 0) 466 return (ENOMEM); 467 468 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */ 469 *curxp = 0; 470 *curyp = 0; 471 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr); 472 *attrp = defattr; 473 sc->nscreens++; 474 return (0); 475} 476 477static void 478cfb_free_screen(v, cookie) 479 void *v; 480 void *cookie; 481{ 482 struct cfb_softc *sc = v; 483 484 if (sc->sc_dc == &cfb_console_dc) 485 panic("cfb_free_screen: console"); 486 487 sc->nscreens--; 488} 489 490static int 491cfb_show_screen(v, cookie, waitok, cb, cbarg) 492 void *v; 493 void *cookie; 494 int waitok; 495 void (*cb) __P((void *, int, int)); 496 void *cbarg; 497{ 498 499 return (0); 500} 501 502/* EXPORT */ int 503cfb_cnattach(addr) 504 tc_addr_t addr; 505{ 506 struct fb_devconfig *dcp = &cfb_console_dc; 507 long defattr; 508 509 cfb_getdevconfig(addr, dcp); 510 511 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr); 512 513 wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons, 514 0, 0, defattr); 515 cfb_consaddr = addr; 516 return(0); 517} 518 519 520static int 521cfbintr(arg) 522 void *arg; 523{ 524 struct cfb_softc *sc = arg; 525 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 526 struct bt459reg *vdac; 527 int v; 528 529 *(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0; 530 if (sc->sc_changed == 0) 531 return (1); 532 533 vdac = (void *)(cfbbase + CX_BT459_OFFSET); 534 v = sc->sc_changed; 535 sc->sc_changed = 0; 536 if (v & DATA_ENB_CHANGED) { 537 SELECT(vdac, BT459_IREG_CCR); 538 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00; 539 } 540 if (v & DATA_CURCMAP_CHANGED) { 541 u_int8_t *cp = sc->sc_cursor.cc_color; 542 543 SELECT(vdac, BT459_IREG_CCOLOR_2); 544 REG(vdac, bt_reg) = cp[1]; tc_wmb(); 545 REG(vdac, bt_reg) = cp[3]; tc_wmb(); 546 REG(vdac, bt_reg) = cp[5]; tc_wmb(); 547 548 REG(vdac, bt_reg) = cp[0]; tc_wmb(); 549 REG(vdac, bt_reg) = cp[2]; tc_wmb(); 550 REG(vdac, bt_reg) = cp[4]; tc_wmb(); 551 } 552 if (v & DATA_CURSHAPE_CHANGED) { 553 u_int8_t *ip, *mp, img, msk; 554 u_int8_t u; 555 int bcnt; 556 557 ip = (u_int8_t *)sc->sc_cursor.cc_image; 558 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 559 560 bcnt = 0; 561 SELECT(vdac, BT459_IREG_CRAM_BASE+0); 562 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 563 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 564 /* pad right half 32 pixel when smaller than 33 */ 565 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 566 REG(vdac, bt_reg) = 0; tc_wmb(); 567 REG(vdac, bt_reg) = 0; tc_wmb(); 568 } 569 else { 570 img = *ip++; 571 msk = *mp++; 572 img &= msk; /* cookie off image */ 573 u = (msk & 0x0f) << 4 | (img & 0x0f); 574 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 575 u = (msk & 0xf0) | (img & 0xf0) >> 4; 576 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 577 } 578 bcnt += 2; 579 } 580 /* pad unoccupied scan lines */ 581 while (bcnt < CURSOR_MAX_SIZE * 16) { 582 REG(vdac, bt_reg) = 0; tc_wmb(); 583 REG(vdac, bt_reg) = 0; tc_wmb(); 584 bcnt += 2; 585 } 586 } 587 if (v & DATA_CMAP_CHANGED) { 588 struct hwcmap256 *cm = &sc->sc_cmap; 589 int index; 590 591 SELECT(vdac, 0); 592 for (index = 0; index < CMAP_SIZE; index++) { 593 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb(); 594 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb(); 595 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb(); 596 } 597 } 598 return (1); 599} 600 601static void 602cfbinit(dc) 603 struct fb_devconfig *dc; 604{ 605 caddr_t cfbbase = (caddr_t)dc->dc_vaddr; 606 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 607 int i; 608 609 SELECT(vdac, BT459_IREG_COMMAND_0); 610 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb(); 611 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb(); 612 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb(); 613 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb(); 614 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb(); 615 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb(); 616 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb(); 617 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb(); 618 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb(); 619 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb(); 620 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb(); 621 622 SELECT(vdac, BT459_IREG_CCR); 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 REG(vdac, bt_reg) = 0x0; tc_wmb(); 631 REG(vdac, bt_reg) = 0x0; tc_wmb(); 632 REG(vdac, bt_reg) = 0x0; tc_wmb(); 633 REG(vdac, bt_reg) = 0x0; tc_wmb(); 634 REG(vdac, bt_reg) = 0x0; tc_wmb(); 635 REG(vdac, bt_reg) = 0x0; tc_wmb(); 636 637 /* build sane colormap */ 638 SELECT(vdac, 0); 639 REG(vdac, bt_cmap) = 0; tc_wmb(); 640 REG(vdac, bt_cmap) = 0; tc_wmb(); 641 REG(vdac, bt_cmap) = 0; tc_wmb(); 642 for (i = 1; i < CMAP_SIZE; i++) { 643 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 644 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 645 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 646 } 647 648 /* clear out cursor image */ 649 SELECT(vdac, BT459_IREG_CRAM_BASE); 650 for (i = 0; i < 1024; i++) 651 REG(vdac, bt_reg) = 0xff; tc_wmb(); 652 653 /* 654 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 655 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for 656 * image color. CCOLOR_1 will be never used. 657 */ 658 SELECT(vdac, BT459_IREG_CCOLOR_1); 659 REG(vdac, bt_reg) = 0xff; tc_wmb(); 660 REG(vdac, bt_reg) = 0xff; tc_wmb(); 661 REG(vdac, bt_reg) = 0xff; tc_wmb(); 662 663 REG(vdac, bt_reg) = 0; tc_wmb(); 664 REG(vdac, bt_reg) = 0; tc_wmb(); 665 REG(vdac, bt_reg) = 0; tc_wmb(); 666 667 REG(vdac, bt_reg) = 0xff; tc_wmb(); 668 REG(vdac, bt_reg) = 0xff; tc_wmb(); 669 REG(vdac, bt_reg) = 0xff; tc_wmb(); 670} 671 672static int 673get_cmap(sc, p) 674 struct cfb_softc *sc; 675 struct wsdisplay_cmap *p; 676{ 677 u_int index = p->index, count = p->count; 678 679 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 680 return (EINVAL); 681 682 if (!uvm_useracc(p->red, count, B_WRITE) || 683 !uvm_useracc(p->green, count, B_WRITE) || 684 !uvm_useracc(p->blue, count, B_WRITE)) 685 return (EFAULT); 686 687 copyout(&sc->sc_cmap.r[index], p->red, count); 688 copyout(&sc->sc_cmap.g[index], p->green, count); 689 copyout(&sc->sc_cmap.b[index], p->blue, count); 690 691 return (0); 692} 693 694static int 695set_cmap(sc, p) 696 struct cfb_softc *sc; 697 struct wsdisplay_cmap *p; 698{ 699 u_int index = p->index, count = p->count; 700 701 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 702 return (EINVAL); 703 704 if (!uvm_useracc(p->red, count, B_READ) || 705 !uvm_useracc(p->green, count, B_READ) || 706 !uvm_useracc(p->blue, count, B_READ)) 707 return (EFAULT); 708 709 copyin(p->red, &sc->sc_cmap.r[index], count); 710 copyin(p->green, &sc->sc_cmap.g[index], count); 711 copyin(p->blue, &sc->sc_cmap.b[index], count); 712 713 sc->sc_changed |= DATA_CMAP_CHANGED; 714 715 return (0); 716} 717 718static int 719set_cursor(sc, p) 720 struct cfb_softc *sc; 721 struct wsdisplay_cursor *p; 722{ 723#define cc (&sc->sc_cursor) 724 int v, index, count, icount; 725 726 v = p->which; 727 if (v & WSDISPLAY_CURSOR_DOCMAP) { 728 index = p->cmap.index; 729 count = p->cmap.count; 730 if (index >= 2 || (index + count) > 2) 731 return (EINVAL); 732 if (!uvm_useracc(p->cmap.red, count, B_READ) || 733 !uvm_useracc(p->cmap.green, count, B_READ) || 734 !uvm_useracc(p->cmap.blue, count, B_READ)) 735 return (EFAULT); 736 } 737 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 738 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 739 return (EINVAL); 740 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 741 if (!uvm_useracc(p->image, icount, B_READ) || 742 !uvm_useracc(p->mask, icount, B_READ)) 743 return (EFAULT); 744 } 745 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 746 if (v & WSDISPLAY_CURSOR_DOCUR) 747 cc->cc_hot = p->hot; 748 if (v & WSDISPLAY_CURSOR_DOPOS) 749 set_curpos(sc, &p->pos); 750 bt459_set_curpos(sc); 751 } 752 753 sc->sc_changed = 0; 754 if (v & WSDISPLAY_CURSOR_DOCUR) { 755 sc->sc_curenb = p->enable; 756 sc->sc_changed |= DATA_ENB_CHANGED; 757 } 758 if (v & WSDISPLAY_CURSOR_DOCMAP) { 759 copyin(p->cmap.red, &cc->cc_color[index], count); 760 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 761 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 762 sc->sc_changed |= DATA_CURCMAP_CHANGED; 763 } 764 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 765 cc->cc_size = p->size; 766 memset(cc->cc_image, 0, sizeof cc->cc_image); 767 copyin(p->image, cc->cc_image, icount); 768 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount); 769 sc->sc_changed |= DATA_CURSHAPE_CHANGED; 770 } 771 772 return (0); 773#undef cc 774} 775 776static int 777get_cursor(sc, p) 778 struct cfb_softc *sc; 779 struct wsdisplay_cursor *p; 780{ 781 return (ENOTTY); /* XXX */ 782} 783 784static void 785set_curpos(sc, curpos) 786 struct cfb_softc *sc; 787 struct wsdisplay_curpos *curpos; 788{ 789 struct fb_devconfig *dc = sc->sc_dc; 790 int x = curpos->x, y = curpos->y; 791 792 if (y < 0) 793 y = 0; 794 else if (y > dc->dc_ht) 795 y = dc->dc_ht; 796 if (x < 0) 797 x = 0; 798 else if (x > dc->dc_wid) 799 x = dc->dc_wid; 800 sc->sc_cursor.cc_pos.x = x; 801 sc->sc_cursor.cc_pos.y = y; 802} 803 804void 805bt459_set_curpos(sc) 806 struct cfb_softc *sc; 807{ 808 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 809 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 810 int x, y, s; 811 812 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 813 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 814 815 x += sc->sc_cursor.cc_magic.x; 816 y += sc->sc_cursor.cc_magic.y; 817 818 s = spltty(); 819 820 SELECT(vdac, BT459_IREG_CURSOR_X_LOW); 821 REG(vdac, bt_reg) = x; tc_wmb(); 822 REG(vdac, bt_reg) = x >> 8; tc_wmb(); 823 REG(vdac, bt_reg) = y; tc_wmb(); 824 REG(vdac, bt_reg) = y >> 8; tc_wmb(); 825 826 splx(s); 827} 828