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