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