cfb.c revision 1.22
1/* $NetBSD: cfb.c,v 1.22 2000/06/28 17:05:21 mrg 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.22 2000/06/28 17:05: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 45#include <machine/bus.h> 46#include <machine/intr.h> 47 48#include <dev/wscons/wsconsio.h> 49#include <dev/wscons/wsdisplayvar.h> 50 51#include <dev/rasops/rasops.h> 52#include <dev/wsfont/wsfont.h> 53 54#include <dev/tc/tcvar.h> 55#include <dev/ic/bt459reg.h> 56 57#include <uvm/uvm_extern.h> 58 59#if defined(pmax) 60#define machine_btop(x) mips_btop(x) 61#define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x) 62#endif 63 64#if defined(__alpha__) || defined(alpha) 65/* 66 * Digital UNIX never supports PMAG-BA 67 */ 68#define machine_btop(x) alpha_btop(x) 69#define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x) 70#endif 71 72/* 73 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have 74 * obscure register layout such as 2nd and 3rd Bt459 registers are 75 * adjacent each other in a word, i.e., 76 * struct bt459triplet { 77 * struct { 78 * u_int8_t u0; 79 * u_int8_t u1; 80 * u_int8_t u2; 81 * unsigned :8; 82 * } bt_lo; 83 * ... 84 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble. 85 * 86 * struct bt459reg { 87 * u_int32_t bt_lo; 88 * u_int32_t bt_hi; 89 * u_int32_t bt_reg; 90 * u_int32_t bt_cmap; 91 * }; 92 * 93 */ 94 95/* Bt459 hardware registers */ 96#define bt_lo 0 97#define bt_hi 1 98#define bt_reg 2 99#define bt_cmap 3 100 101#define REG(base, index) *((u_int32_t *)(base) + (index)) 102#define SELECT(vdac, regno) do { \ 103 REG(vdac, bt_lo) = ((regno) & 0x00ff); \ 104 REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8; \ 105 tc_wmb(); \ 106 } while (0) 107 108struct fb_devconfig { 109 vaddr_t dc_vaddr; /* memory space virtual base address */ 110 paddr_t dc_paddr; /* memory space physical base address */ 111 vsize_t dc_size; /* size of slot memory */ 112 int dc_wid; /* width of frame buffer */ 113 int dc_ht; /* height of frame buffer */ 114 int dc_depth; /* depth, bits per pixel */ 115 int dc_rowbytes; /* bytes in a FB scan line */ 116 vaddr_t dc_videobase; /* base of flat frame buffer */ 117 int dc_blanked; /* currently has video disabled */ 118 119 struct rasops_info rinfo; 120}; 121 122struct hwcmap256 { 123#define CMAP_SIZE 256 /* 256 R/G/B entries */ 124 u_int8_t r[CMAP_SIZE]; 125 u_int8_t g[CMAP_SIZE]; 126 u_int8_t b[CMAP_SIZE]; 127}; 128 129struct hwcursor64 { 130 struct wsdisplay_curpos cc_pos; 131 struct wsdisplay_curpos cc_hot; 132 struct wsdisplay_curpos cc_size; 133 struct wsdisplay_curpos cc_magic; 134#define CURSOR_MAX_SIZE 64 135 u_int8_t cc_color[6]; 136 u_int64_t cc_image[64 + 64]; 137}; 138 139struct cfb_softc { 140 struct device sc_dev; 141 struct fb_devconfig *sc_dc; /* device configuration */ 142 struct hwcmap256 sc_cmap; /* software copy of colormap */ 143 struct hwcursor64 sc_cursor; /* software copy of cursor */ 144 int sc_curenb; /* cursor sprite enabled */ 145 int sc_changed; /* need update of colormap */ 146#define DATA_ENB_CHANGED 0x01 /* cursor enable changed */ 147#define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */ 148#define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */ 149#define DATA_CMAP_CHANGED 0x08 /* colormap changed */ 150#define DATA_ALL_CHANGED 0x0f 151 int nscreens; 152}; 153 154#define CX_MAGIC_X 220 155#define CX_MAGIC_Y 35 156 157#define CX_FB_OFFSET 0x000000 158#define CX_FB_SIZE 0x100000 159#define CX_BT459_OFFSET 0x200000 160#define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 161 162static int cfbmatch __P((struct device *, struct cfdata *, void *)); 163static void cfbattach __P((struct device *, struct device *, void *)); 164 165const struct cfattach cfb_ca = { 166 sizeof(struct cfb_softc), cfbmatch, cfbattach, 167}; 168 169static void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 170static struct fb_devconfig cfb_console_dc; 171static tc_addr_t cfb_consaddr; 172 173static struct wsscreen_descr cfb_stdscreen = { 174 "std", 0, 0, 175 0, /* textops */ 176 0, 0, 177 WSSCREEN_REVERSE 178}; 179 180static const struct wsscreen_descr *_cfb_scrlist[] = { 181 &cfb_stdscreen, 182}; 183 184static const struct wsscreen_list cfb_screenlist = { 185 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist 186}; 187 188static int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 189static paddr_t cfbmmap __P((void *, off_t, int)); 190 191static int cfb_alloc_screen __P((void *, const struct wsscreen_descr *, 192 void **, int *, int *, long *)); 193static void cfb_free_screen __P((void *, void *)); 194static int cfb_show_screen __P((void *, void *, int, 195 void (*) (void *, int, int), void *)); 196 197static const struct wsdisplay_accessops cfb_accessops = { 198 cfbioctl, 199 cfbmmap, 200 cfb_alloc_screen, 201 cfb_free_screen, 202 cfb_show_screen, 203 0 /* load_font */ 204}; 205 206int cfb_cnattach __P((tc_addr_t)); 207static int cfbintr __P((void *)); 208static void cfbinit __P((struct fb_devconfig *)); 209 210static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 211static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 212static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 213static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 214static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *)); 215static void bt459_set_curpos __P((struct cfb_softc *)); 216 217/* 218 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 219 * M M M M I I I I M I M I M I M I 220 * [ before ] [ after ] 221 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 222 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 223 */ 224static const u_int8_t shuffle[256] = { 225 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 226 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 227 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 228 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 229 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 230 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 231 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 232 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 233 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 234 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 235 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 236 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 237 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 238 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 239 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 240 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 241 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 242 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 243 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 244 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 245 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 246 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 247 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 248 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 249 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 250 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 251 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 252 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 253 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 254 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 255 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 256 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 257}; 258 259static int 260cfbmatch(parent, match, aux) 261 struct device *parent; 262 struct cfdata *match; 263 void *aux; 264{ 265 struct tc_attach_args *ta = aux; 266 267 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0) 268 return (0); 269 270 return (1); 271} 272 273static void 274cfb_getdevconfig(dense_addr, dc) 275 tc_addr_t dense_addr; 276 struct fb_devconfig *dc; 277{ 278 int i, cookie; 279 280 dc->dc_vaddr = dense_addr; 281 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET); 282 283 dc->dc_wid = 1024; 284 dc->dc_ht = 864; 285 dc->dc_depth = 8; 286 dc->dc_rowbytes = 1024; 287 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET; 288 dc->dc_blanked = 0; 289 290 /* initialize colormap and cursor resource */ 291 cfbinit(dc); 292 293 /* clear the screen */ 294 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 295 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 296 297 dc->rinfo.ri_flg = RI_CENTER; 298 dc->rinfo.ri_depth = dc->dc_depth; 299 dc->rinfo.ri_bits = (void *)dc->dc_videobase; 300 dc->rinfo.ri_width = dc->dc_wid; 301 dc->rinfo.ri_height = dc->dc_ht; 302 dc->rinfo.ri_stride = dc->dc_rowbytes; 303 304 wsfont_init(); 305 /* prefer 8 pixel wide font */ 306 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0) 307 cookie = wsfont_find(NULL, 0, 0, 0); 308 if (cookie <= 0) { 309 printf("cfb: font table is empty\n"); 310 return; 311 } 312 313 if (wsfont_lock(cookie, &dc->rinfo.ri_font, 314 WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) { 315 printf("cfb: couldn't lock font\n"); 316 return; 317 } 318 dc->rinfo.ri_wsfcookie = cookie; 319 320 rasops_init(&dc->rinfo, 34, 80); 321 322 /* XXX shouldn't be global */ 323 cfb_stdscreen.nrows = dc->rinfo.ri_rows; 324 cfb_stdscreen.ncols = dc->rinfo.ri_cols; 325 cfb_stdscreen.textops = &dc->rinfo.ri_ops; 326 cfb_stdscreen.capabilities = dc->rinfo.ri_caps; 327} 328 329static void 330cfbattach(parent, self, aux) 331 struct device *parent, *self; 332 void *aux; 333{ 334 struct cfb_softc *sc = (struct cfb_softc *)self; 335 struct tc_attach_args *ta = aux; 336 struct wsemuldisplaydev_attach_args waa; 337 int console; 338 339 console = (ta->ta_addr == cfb_consaddr); 340 if (console) { 341 sc->sc_dc = &cfb_console_dc; 342 sc->nscreens = 1; 343 } 344 else { 345 sc->sc_dc = (struct fb_devconfig *) 346 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 347 cfb_getdevconfig(ta->ta_addr, sc->sc_dc); 348 } 349 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht, 350 sc->sc_dc->dc_depth); 351 352 memcpy(&sc->sc_cmap, rasops_cmap, sizeof(struct hwcmap256)); 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, 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 369static int 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 437paddr_t 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 450static int 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->rinfo; /* one and only for now */ 465 *curxp = 0; 466 *curyp = 0; 467 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 468 *attrp = defattr; 469 sc->nscreens++; 470 return (0); 471} 472 473static void 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 486static int 487cfb_show_screen(v, cookie, waitok, cb, cbarg) 488 void *v; 489 void *cookie; 490 int waitok; 491 void (*cb) __P((void *, int, int)); 492 void *cbarg; 493{ 494 495 return (0); 496} 497 498/* EXPORT */ int 499cfb_cnattach(addr) 500 tc_addr_t addr; 501{ 502 struct fb_devconfig *dcp = &cfb_console_dc; 503 long defattr; 504 505 cfb_getdevconfig(addr, dcp); 506 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr); 507 wsdisplay_cnattach(&cfb_stdscreen, &dcp->rinfo, 0, 0, defattr); 508 cfb_consaddr = addr; 509 return(0); 510} 511 512static int 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 SELECT(vdac, BT459_IREG_CCR); 530 REG(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 SELECT(vdac, BT459_IREG_CCOLOR_2); 536 REG(vdac, bt_reg) = cp[1]; tc_wmb(); 537 REG(vdac, bt_reg) = cp[3]; tc_wmb(); 538 REG(vdac, bt_reg) = cp[5]; tc_wmb(); 539 540 REG(vdac, bt_reg) = cp[0]; tc_wmb(); 541 REG(vdac, bt_reg) = cp[2]; tc_wmb(); 542 REG(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 SELECT(vdac, BT459_IREG_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 REG(vdac, bt_reg) = 0; tc_wmb(); 559 REG(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 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 567 u = (msk & 0xf0) | (img & 0xf0) >> 4; 568 REG(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 REG(vdac, bt_reg) = 0; tc_wmb(); 575 REG(vdac, bt_reg) = 0; tc_wmb(); 576 bcnt += 2; 577 } 578 } 579 if (v & DATA_CMAP_CHANGED) { 580 struct hwcmap256 *cm = &sc->sc_cmap; 581 int index; 582 583 SELECT(vdac, 0); 584 for (index = 0; index < CMAP_SIZE; index++) { 585 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb(); 586 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb(); 587 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb(); 588 } 589 } 590 return (1); 591} 592 593static void 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 SELECT(vdac, BT459_IREG_COMMAND_0); 602 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb(); 603 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb(); 604 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb(); 605 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb(); 606 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb(); 607 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb(); 608 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb(); 609 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb(); 610 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb(); 611 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb(); 612 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb(); 613 614 SELECT(vdac, BT459_IREG_CCR); 615 REG(vdac, bt_reg) = 0x0; tc_wmb(); 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 629 /* build sane colormap */ 630 SELECT(vdac, 0); 631 for (i = 0; i < CMAP_SIZE; i++) { 632 REG(vdac, bt_cmap) = rasops_cmap[3 * i + 0]; 633 tc_wmb(); 634 REG(vdac, bt_cmap) = rasops_cmap[3 * i + 1]; 635 tc_wmb(); 636 REG(vdac, bt_cmap) = rasops_cmap[3 * i + 2]; 637 tc_wmb(); 638 } 639 640 /* clear out cursor image */ 641 SELECT(vdac, BT459_IREG_CRAM_BASE); 642 for (i = 0; i < 1024; i++) 643 REG(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 SELECT(vdac, BT459_IREG_CCOLOR_1); 651 REG(vdac, bt_reg) = 0xff; tc_wmb(); 652 REG(vdac, bt_reg) = 0xff; tc_wmb(); 653 REG(vdac, bt_reg) = 0xff; tc_wmb(); 654 655 REG(vdac, bt_reg) = 0; tc_wmb(); 656 REG(vdac, bt_reg) = 0; tc_wmb(); 657 REG(vdac, bt_reg) = 0; tc_wmb(); 658 659 REG(vdac, bt_reg) = 0xff; tc_wmb(); 660 REG(vdac, bt_reg) = 0xff; tc_wmb(); 661 REG(vdac, bt_reg) = 0xff; tc_wmb(); 662} 663 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 807 x += sc->sc_cursor.cc_magic.x; 808 y += sc->sc_cursor.cc_magic.y; 809 810 s = spltty(); 811 812 SELECT(vdac, BT459_IREG_CURSOR_X_LOW); 813 REG(vdac, bt_reg) = x; tc_wmb(); 814 REG(vdac, bt_reg) = x >> 8; tc_wmb(); 815 REG(vdac, bt_reg) = y; tc_wmb(); 816 REG(vdac, bt_reg) = y >> 8; tc_wmb(); 817 818 splx(s); 819} 820