cfb.c revision 1.11
1/* $NetBSD: cfb.c,v 1.11 1999/05/07 08:00:30 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.11 1999/05/07 08:00:30 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 hwcmap256 { 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 hwcursor64 { 119 struct wsdisplay_curpos cc_pos; 120 struct wsdisplay_curpos cc_hot; 121 struct wsdisplay_curpos cc_size; 122 struct wsdisplay_curpos cc_magic; 123#define CURSOR_MAX_SIZE 64 124 u_int8_t cc_color[6]; 125 u_int64_t cc_image[64 + 64]; 126}; 127 128struct cfb_softc { 129 struct device sc_dev; 130 struct fb_devconfig *sc_dc; /* device configuration */ 131 struct hwcmap256 sc_cmap; /* software copy of colormap */ 132 struct hwcursor64 sc_cursor; /* software copy of cursor */ 133 int sc_curenb; /* cursor sprite enabled */ 134 int sc_changed; /* need update of colormap */ 135#define DATA_ENB_CHANGED 0x01 /* cursor enable changed */ 136#define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */ 137#define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */ 138#define DATA_CMAP_CHANGED 0x08 /* colormap changed */ 139#define DATA_ALL_CHANGED 0x0f 140 int nscreens; 141}; 142 143#define CX_MAGIC_X 220 144#define CX_MAGIC_Y 35 145 146#define CX_FB_OFFSET 0x000000 147#define CX_FB_SIZE 0x100000 148#define CX_BT459_OFFSET 0x200000 149#define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 150 151int cfbmatch __P((struct device *, struct cfdata *, void *)); 152void cfbattach __P((struct device *, struct device *, void *)); 153 154struct cfattach cfb_ca = { 155 sizeof(struct cfb_softc), cfbmatch, cfbattach, 156}; 157 158void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 159struct fb_devconfig cfb_console_dc; 160tc_addr_t cfb_consaddr; 161 162struct wsdisplay_emulops cfb_emulops = { 163 rcons_cursor, /* could use hardware cursor; punt */ 164 rcons_mapchar, 165 rcons_putchar, 166 rcons_copycols, 167 rcons_erasecols, 168 rcons_copyrows, 169 rcons_eraserows, 170 rcons_alloc_attr 171}; 172 173struct wsscreen_descr cfb_stdscreen = { 174 "std", 0, 0, 175 &cfb_emulops, 176 0, 0, 177 0 178}; 179 180const struct wsscreen_descr *_cfb_scrlist[] = { 181 &cfb_stdscreen, 182}; 183 184struct wsscreen_list cfb_screenlist = { 185 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist 186}; 187 188int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 189int cfbmmap __P((void *, off_t, int)); 190 191int cfb_alloc_screen __P((void *, const struct wsscreen_descr *, 192 void **, int *, int *, long *)); 193void cfb_free_screen __P((void *, void *)); 194void cfb_show_screen __P((void *, void *)); 195 196struct wsdisplay_accessops cfb_accessops = { 197 cfbioctl, 198 cfbmmap, 199 cfb_alloc_screen, 200 cfb_free_screen, 201 cfb_show_screen, 202 0 /* load_font */ 203}; 204 205int cfb_cnattach __P((tc_addr_t)); 206int cfbintr __P((void *)); 207void cfbinit __P((struct fb_devconfig *)); 208 209static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 210static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 211static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 212static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 213static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *)); 214static void bt459_set_curpos __P((struct cfb_softc *)); 215 216/* XXX XXX XXX */ 217#define BT459_SELECT(vdac, regno) do { \ 218 vdac->bt_lo = (regno) & 0x00ff; \ 219 vdac->bt_hi = ((regno)& 0x0f00) >> 8; \ 220 tc_wmb(); \ 221 } while (0) 222/* XXX XXX XXX */ 223 224/* 225 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 226 * M M M M I I I I M I M I M I M I 227 * [ before ] [ after ] 228 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 229 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 230 */ 231const static u_int8_t shuffle[256] = { 232 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 233 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 234 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 235 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 236 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 237 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 238 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 239 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 240 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 241 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 242 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 243 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 244 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 245 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 246 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 247 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 248 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 249 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 250 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 251 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 252 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 253 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 254 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 255 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 256 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 257 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 258 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 259 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 260 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 261 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 262 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 263 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 264}; 265 266int 267cfbmatch(parent, match, aux) 268 struct device *parent; 269 struct cfdata *match; 270 void *aux; 271{ 272 struct tc_attach_args *ta = aux; 273 274 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0) 275 return (0); 276 277 return (1); 278} 279 280void 281cfb_getdevconfig(dense_addr, dc) 282 tc_addr_t dense_addr; 283 struct fb_devconfig *dc; 284{ 285 struct raster *rap; 286 struct rcons *rcp; 287 int i; 288 289 dc->dc_vaddr = dense_addr; 290 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET); 291 292 dc->dc_wid = 1024; 293 dc->dc_ht = 864; 294 dc->dc_depth = 8; 295 dc->dc_rowbytes = 1024; 296 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET; 297 dc->dc_blanked = 0; 298 299 /* initialize colormap and cursor resource */ 300 cfbinit(dc); 301 302 /* clear the screen */ 303 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 304 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 305 306 /* initialize the raster */ 307 rap = &dc->dc_raster; 308 rap->width = dc->dc_wid; 309 rap->height = dc->dc_ht; 310 rap->depth = dc->dc_depth; 311 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t); 312 rap->pixels = (u_int32_t *)dc->dc_videobase; 313 314 /* initialize the raster console blitter */ 315 rcp = &dc->dc_rcons; 316 rcp->rc_sp = rap; 317 rcp->rc_crow = rcp->rc_ccol = -1; 318 rcp->rc_crowp = &rcp->rc_crow; 319 rcp->rc_ccolp = &rcp->rc_ccol; 320 rcons_init(rcp, 34, 80); 321 322 cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow; 323 cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol; 324} 325 326void 327cfbattach(parent, self, aux) 328 struct device *parent, *self; 329 void *aux; 330{ 331 struct cfb_softc *sc = (struct cfb_softc *)self; 332 struct tc_attach_args *ta = aux; 333 struct wsemuldisplaydev_attach_args waa; 334 struct hwcmap256 *cm; 335 int console; 336 337 console = (ta->ta_addr == cfb_consaddr); 338 if (console) { 339 sc->sc_dc = &cfb_console_dc; 340 sc->nscreens = 1; 341 } 342 else { 343 sc->sc_dc = (struct fb_devconfig *) 344 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 345 cfb_getdevconfig(ta->ta_addr, sc->sc_dc); 346 } 347 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht, 348 sc->sc_dc->dc_depth); 349 350 cm = &sc->sc_cmap; 351 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */ 352 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */ 353 354 sc->sc_cursor.cc_magic.x = CX_MAGIC_X; 355 sc->sc_cursor.cc_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 hwcmap256 *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 806 x += sc->sc_cursor.cc_magic.x; 807 y += sc->sc_cursor.cc_magic.y; 808 809 s = spltty(); 810 811 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW); 812 vdac->bt_reg = x; tc_wmb(); 813 vdac->bt_reg = x >> 8; tc_wmb(); 814 vdac->bt_reg = y; tc_wmb(); 815 vdac->bt_reg = y >> 8; tc_wmb(); 816 817 splx(s); 818} 819