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