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