cfb.c revision 1.9
1/* $NetBSD: cfb.c,v 1.9 1999/03/24 05:51:21 mrg 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.9 1999/03/24 05:51:21 mrg 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#include <machine/autoconf.h> 54 55#include <dev/tc/tcvar.h> 56#include <dev/ic/bt459reg.h> 57 58#include <uvm/uvm_extern.h> 59 60/* XXX BUS'IFYING XXX */ 61 62#if defined(pmax) 63#define machine_btop(x) mips_btop(x) 64#define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x) 65#endif 66 67#if defined(__alpha__) || defined(alpha) 68/* 69 * Digital UNIX never supports PMAG-BA 70 */ 71#define machine_btop(x) alpha_btop(x) 72#define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x) 73#endif 74 75/* 76 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have 77 * obscure register layout such as 2nd and 3rd Bt459 registers are 78 * adjacent each other in a word, i.e., 79 * struct bt459triplet { 80 * struct { 81 * u_int8_t u0; 82 * u_int8_t u1; 83 * u_int8_t u2; 84 * unsigned :8; 85 * } bt_lo; 86 * ... 87 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble. 88 */ 89struct bt459reg { 90 u_int32_t bt_lo; 91 u_int32_t bt_hi; 92 u_int32_t bt_reg; 93 u_int32_t bt_cmap; 94}; 95 96/* XXX XXX XXX */ 97 98struct fb_devconfig { 99 vaddr_t dc_vaddr; /* memory space virtual base address */ 100 paddr_t dc_paddr; /* memory space physical base address */ 101 vsize_t dc_size; /* size of slot memory */ 102 int dc_wid; /* width of frame buffer */ 103 int dc_ht; /* height of frame buffer */ 104 int dc_depth; /* depth, bits per pixel */ 105 int dc_rowbytes; /* bytes in a FB scan line */ 106 vaddr_t dc_videobase; /* base of flat frame buffer */ 107 struct raster dc_raster; /* raster description */ 108 struct rcons dc_rcons; /* raster blitter control info */ 109 int dc_blanked; /* currently has video disabled */ 110}; 111 112struct hwcmap { 113#define CMAP_SIZE 256 /* 256 R/G/B entries */ 114 u_int8_t r[CMAP_SIZE]; 115 u_int8_t g[CMAP_SIZE]; 116 u_int8_t b[CMAP_SIZE]; 117}; 118 119struct hwcursor { 120 struct wsdisplay_curpos cc_pos; 121 struct wsdisplay_curpos cc_hot; 122 struct wsdisplay_curpos cc_size; 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 hwcmap sc_cmap; /* software copy of colormap */ 132 struct hwcursor 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 short magic_x, magic_y; /* CX cursor location offset */ 142#define CX_MAGIC_X 220 143#define CX_MAGIC_Y 35 144}; 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 hwcmap *cm; 335 int console, i; 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 cm->r[0] = cm->g[0] = cm->b[0] = 0; 352 for (i = 1; i < CMAP_SIZE; i++) { 353 cm->r[i] = cm->g[i] = cm->b[i] = 0xff; 354 } 355 sc->magic_x = CX_MAGIC_X; 356 sc->magic_y = CX_MAGIC_Y; 357 358 /* Establish an interrupt handler, and clear any pending interrupts */ 359 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, cfbintr, sc); 360 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0; 361 362 waa.console = console; 363 waa.scrdata = &cfb_screenlist; 364 waa.accessops = &cfb_accessops; 365 waa.accesscookie = sc; 366 367 config_found(self, &waa, wsemuldisplaydevprint); 368} 369 370int 371cfbioctl(v, cmd, data, flag, p) 372 void *v; 373 u_long cmd; 374 caddr_t data; 375 int flag; 376 struct proc *p; 377{ 378 struct cfb_softc *sc = v; 379 struct fb_devconfig *dc = sc->sc_dc; 380 int turnoff; 381 382 switch (cmd) { 383 case WSDISPLAYIO_GTYPE: 384 *(u_int *)data = WSDISPLAY_TYPE_CFB; 385 return (0); 386 387 case WSDISPLAYIO_GINFO: 388#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 389 wsd_fbip->height = sc->sc_dc->dc_ht; 390 wsd_fbip->width = sc->sc_dc->dc_wid; 391 wsd_fbip->depth = sc->sc_dc->dc_depth; 392 wsd_fbip->cmsize = CMAP_SIZE; 393#undef fbt 394 return (0); 395 396 case WSDISPLAYIO_GETCMAP: 397 return get_cmap(sc, (struct wsdisplay_cmap *)data); 398 399 case WSDISPLAYIO_PUTCMAP: 400 return set_cmap(sc, (struct wsdisplay_cmap *)data); 401 402 case WSDISPLAYIO_SVIDEO: 403 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 404 if ((dc->dc_blanked == 0) ^ turnoff) { 405 dc->dc_blanked = turnoff; 406 /* XXX later XXX */ 407 } 408 return (0); 409 410 case WSDISPLAYIO_GVIDEO: 411 *(u_int *)data = dc->dc_blanked ? 412 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 413 return (0); 414 415 case WSDISPLAYIO_GCURPOS: 416 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 417 return (0); 418 419 case WSDISPLAYIO_SCURPOS: 420 set_curpos(sc, (struct wsdisplay_curpos *)data); 421 bt459_set_curpos(sc); 422 return (0); 423 424 case WSDISPLAYIO_GCURMAX: 425 ((struct wsdisplay_curpos *)data)->x = 426 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 427 return (0); 428 429 case WSDISPLAYIO_GCURSOR: 430 return get_cursor(sc, (struct wsdisplay_cursor *)data); 431 432 case WSDISPLAYIO_SCURSOR: 433 return set_cursor(sc, (struct wsdisplay_cursor *)data); 434 } 435 return ENOTTY; 436} 437 438int 439cfbmmap(v, offset, prot) 440 void *v; 441 off_t offset; 442 int prot; 443{ 444 struct cfb_softc *sc = v; 445 446 if (offset >= CX_FB_SIZE || offset < 0) 447 return (-1); 448 return machine_btop(sc->sc_dc->dc_paddr + offset); 449} 450 451int 452cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 453 void *v; 454 const struct wsscreen_descr *type; 455 void **cookiep; 456 int *curxp, *curyp; 457 long *attrp; 458{ 459 struct cfb_softc *sc = v; 460 long defattr; 461 462 if (sc->nscreens > 0) 463 return (ENOMEM); 464 465 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */ 466 *curxp = 0; 467 *curyp = 0; 468 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr); 469 *attrp = defattr; 470 sc->nscreens++; 471 return (0); 472} 473 474void 475cfb_free_screen(v, cookie) 476 void *v; 477 void *cookie; 478{ 479 struct cfb_softc *sc = v; 480 481 if (sc->sc_dc == &cfb_console_dc) 482 panic("cfb_free_screen: console"); 483 484 sc->nscreens--; 485} 486 487void 488cfb_show_screen(v, cookie) 489 void *v; 490 void *cookie; 491{ 492} 493 494int 495cfb_cnattach(addr) 496 tc_addr_t addr; 497{ 498 struct fb_devconfig *dcp = &cfb_console_dc; 499 long defattr; 500 501 cfb_getdevconfig(addr, dcp); 502 503 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr); 504 505 wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons, 506 0, 0, defattr); 507 cfb_consaddr = addr; 508 return(0); 509} 510 511 512int 513cfbintr(arg) 514 void *arg; 515{ 516 struct cfb_softc *sc = arg; 517 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 518 struct bt459reg *vdac; 519 int v; 520 521 *(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0; 522 if (sc->sc_changed == 0) 523 return (1); 524 525 vdac = (void *)(cfbbase + CX_BT459_OFFSET); 526 v = sc->sc_changed; 527 sc->sc_changed = 0; 528 if (v & DATA_ENB_CHANGED) { 529 BT459_SELECT(vdac, BT459_REG_CCR); 530 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00; 531 } 532 if (v & DATA_CURCMAP_CHANGED) { 533 u_int8_t *cp = sc->sc_cursor.cc_color; 534 535 BT459_SELECT(vdac, BT459_REG_CCOLOR_2); 536 vdac->bt_reg = cp[1]; tc_wmb(); 537 vdac->bt_reg = cp[3]; tc_wmb(); 538 vdac->bt_reg = cp[5]; tc_wmb(); 539 540 vdac->bt_reg = cp[0]; tc_wmb(); 541 vdac->bt_reg = cp[2]; tc_wmb(); 542 vdac->bt_reg = cp[4]; tc_wmb(); 543 } 544 if (v & DATA_CURSHAPE_CHANGED) { 545 u_int8_t *ip, *mp, img, msk; 546 u_int8_t u; 547 int bcnt; 548 549 ip = (u_int8_t *)sc->sc_cursor.cc_image; 550 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 551 552 bcnt = 0; 553 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0); 554 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 555 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 556 /* pad right half 32 pixel when smaller than 33 */ 557 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 558 vdac->bt_reg = 0; tc_wmb(); 559 vdac->bt_reg = 0; tc_wmb(); 560 } 561 else { 562 img = *ip++; 563 msk = *mp++; 564 img &= msk; /* cookie off image */ 565 u = (msk & 0x0f) << 4 | (img & 0x0f); 566 vdac->bt_reg = shuffle[u]; tc_wmb(); 567 u = (msk & 0xf0) | (img & 0xf0) >> 4; 568 vdac->bt_reg = shuffle[u]; tc_wmb(); 569 } 570 bcnt += 2; 571 } 572 /* pad unoccupied scan lines */ 573 while (bcnt < CURSOR_MAX_SIZE * 16) { 574 vdac->bt_reg = 0; tc_wmb(); 575 vdac->bt_reg = 0; tc_wmb(); 576 bcnt += 2; 577 } 578 } 579 if (v & DATA_CMAP_CHANGED) { 580 struct hwcmap *cm = &sc->sc_cmap; 581 int index; 582 583 BT459_SELECT(vdac, 0); 584 for (index = 0; index < CMAP_SIZE; index++) { 585 vdac->bt_cmap = cm->r[index]; tc_wmb(); 586 vdac->bt_cmap = cm->g[index]; tc_wmb(); 587 vdac->bt_cmap = cm->b[index]; tc_wmb(); 588 } 589 } 590 return (1); 591} 592 593void 594cfbinit(dc) 595 struct fb_devconfig *dc; 596{ 597 caddr_t cfbbase = (caddr_t)dc->dc_vaddr; 598 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 599 int i; 600 601 BT459_SELECT(vdac, BT459_REG_COMMAND_0); 602 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb(); 603 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb(); 604 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb(); 605 vdac->bt_reg = 0xff; /* PRM */ tc_wmb(); 606 vdac->bt_reg = 0; /* 205 */ tc_wmb(); 607 vdac->bt_reg = 0x0; /* PBM */ tc_wmb(); 608 vdac->bt_reg = 0; /* 207 */ tc_wmb(); 609 vdac->bt_reg = 0x0; /* ORM */ tc_wmb(); 610 vdac->bt_reg = 0x0; /* OBM */ tc_wmb(); 611 vdac->bt_reg = 0x0; /* ILV */ tc_wmb(); 612 vdac->bt_reg = 0x0; /* TEST */ tc_wmb(); 613 614 BT459_SELECT(vdac, BT459_REG_CCR); 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 vdac->bt_reg = 0x0; tc_wmb(); 628 629 /* build sane colormap */ 630 BT459_SELECT(vdac, 0); 631 vdac->bt_cmap = 0; tc_wmb(); 632 vdac->bt_cmap = 0; tc_wmb(); 633 vdac->bt_cmap = 0; tc_wmb(); 634 for (i = 1; i < CMAP_SIZE; i++) { 635 vdac->bt_cmap = 0xff; tc_wmb(); 636 vdac->bt_cmap = 0xff; tc_wmb(); 637 vdac->bt_cmap = 0xff; tc_wmb(); 638 } 639 640 /* clear out cursor image */ 641 BT459_SELECT(vdac, BT459_REG_CRAM_BASE); 642 for (i = 0; i < 1024; i++) 643 vdac->bt_reg = 0xff; tc_wmb(); 644 645 /* 646 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 647 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for 648 * image color. CCOLOR_1 will be never used. 649 */ 650 BT459_SELECT(vdac, BT459_REG_CCOLOR_1); 651 vdac->bt_reg = 0xff; tc_wmb(); 652 vdac->bt_reg = 0xff; tc_wmb(); 653 vdac->bt_reg = 0xff; tc_wmb(); 654 655 vdac->bt_reg = 0; tc_wmb(); 656 vdac->bt_reg = 0; tc_wmb(); 657 vdac->bt_reg = 0; tc_wmb(); 658 659 vdac->bt_reg = 0xff; tc_wmb(); 660 vdac->bt_reg = 0xff; tc_wmb(); 661 vdac->bt_reg = 0xff; tc_wmb(); 662} 663 664static int 665get_cmap(sc, p) 666 struct cfb_softc *sc; 667 struct wsdisplay_cmap *p; 668{ 669 u_int index = p->index, count = p->count; 670 671 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 672 return (EINVAL); 673 674 if (!uvm_useracc(p->red, count, B_WRITE) || 675 !uvm_useracc(p->green, count, B_WRITE) || 676 !uvm_useracc(p->blue, count, B_WRITE)) 677 return (EFAULT); 678 679 copyout(&sc->sc_cmap.r[index], p->red, count); 680 copyout(&sc->sc_cmap.g[index], p->green, count); 681 copyout(&sc->sc_cmap.b[index], p->blue, count); 682 683 return (0); 684} 685 686static int 687set_cmap(sc, p) 688 struct cfb_softc *sc; 689 struct wsdisplay_cmap *p; 690{ 691 u_int index = p->index, count = p->count; 692 693 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 694 return (EINVAL); 695 696 if (!uvm_useracc(p->red, count, B_READ) || 697 !uvm_useracc(p->green, count, B_READ) || 698 !uvm_useracc(p->blue, count, B_READ)) 699 return (EFAULT); 700 701 copyin(p->red, &sc->sc_cmap.r[index], count); 702 copyin(p->green, &sc->sc_cmap.g[index], count); 703 copyin(p->blue, &sc->sc_cmap.b[index], count); 704 705 sc->sc_changed |= DATA_CMAP_CHANGED; 706 707 return (0); 708} 709 710static int 711set_cursor(sc, p) 712 struct cfb_softc *sc; 713 struct wsdisplay_cursor *p; 714{ 715#define cc (&sc->sc_cursor) 716 int v, index, count, icount; 717 718 v = p->which; 719 if (v & WSDISPLAY_CURSOR_DOCMAP) { 720 index = p->cmap.index; 721 count = p->cmap.count; 722 if (index >= 2 || (index + count) > 2) 723 return (EINVAL); 724 if (!uvm_useracc(p->cmap.red, count, B_READ) || 725 !uvm_useracc(p->cmap.green, count, B_READ) || 726 !uvm_useracc(p->cmap.blue, count, B_READ)) 727 return (EFAULT); 728 } 729 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 730 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 731 return (EINVAL); 732 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 733 if (!uvm_useracc(p->image, icount, B_READ) || 734 !uvm_useracc(p->mask, icount, B_READ)) 735 return (EFAULT); 736 } 737 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 738 if (v & WSDISPLAY_CURSOR_DOCUR) 739 cc->cc_hot = p->hot; 740 if (v & WSDISPLAY_CURSOR_DOPOS) 741 set_curpos(sc, &p->pos); 742 bt459_set_curpos(sc); 743 } 744 745 sc->sc_changed = 0; 746 if (v & WSDISPLAY_CURSOR_DOCUR) { 747 sc->sc_curenb = p->enable; 748 sc->sc_changed |= DATA_ENB_CHANGED; 749 } 750 if (v & WSDISPLAY_CURSOR_DOCMAP) { 751 copyin(p->cmap.red, &cc->cc_color[index], count); 752 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 753 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 754 sc->sc_changed |= DATA_CURCMAP_CHANGED; 755 } 756 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 757 cc->cc_size = p->size; 758 memset(cc->cc_image, 0, sizeof cc->cc_image); 759 copyin(p->image, cc->cc_image, icount); 760 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount); 761 sc->sc_changed |= DATA_CURSHAPE_CHANGED; 762 } 763 764 return (0); 765#undef cc 766} 767 768static int 769get_cursor(sc, p) 770 struct cfb_softc *sc; 771 struct wsdisplay_cursor *p; 772{ 773 return (ENOTTY); /* XXX */ 774} 775 776static void 777set_curpos(sc, curpos) 778 struct cfb_softc *sc; 779 struct wsdisplay_curpos *curpos; 780{ 781 struct fb_devconfig *dc = sc->sc_dc; 782 int x = curpos->x, y = curpos->y; 783 784 if (y < 0) 785 y = 0; 786 else if (y > dc->dc_ht) 787 y = dc->dc_ht; 788 if (x < 0) 789 x = 0; 790 else if (x > dc->dc_wid) 791 x = dc->dc_wid; 792 sc->sc_cursor.cc_pos.x = x; 793 sc->sc_cursor.cc_pos.y = y; 794} 795 796void 797bt459_set_curpos(sc) 798 struct cfb_softc *sc; 799{ 800 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 801 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 802 int x, y, s; 803 804 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 805 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 806 x += sc->magic_x; y += sc->magic_y; /* magic offset of CX coordinate */ 807 808 s = spltty(); 809 810 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW); 811 vdac->bt_reg = x; tc_wmb(); 812 vdac->bt_reg = x >> 8; tc_wmb(); 813 vdac->bt_reg = y; tc_wmb(); 814 vdac->bt_reg = y >> 8; tc_wmb(); 815 816 splx(s); 817} 818