1 /* $NetBSD: cfb.c,v 1.59 2010/05/15 08:53:27 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.59 2010/05/15 08:53:27 tsutsui Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/buf.h> 41 #include <sys/ioctl.h> 42 43 #include <sys/bus.h> 44 #include <sys/intr.h> 45 46 #include <dev/wscons/wsconsio.h> 47 #include <dev/wscons/wsdisplayvar.h> 48 49 #include <dev/rasops/rasops.h> 50 #include <dev/wsfont/wsfont.h> 51 52 #include <dev/tc/tcvar.h> 53 #include <dev/ic/bt459reg.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #if defined(pmax) 58 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x)) 59 #endif 60 61 #if defined(alpha) 62 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x)) 63 #endif 64 65 /* 66 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have 67 * obscure register layout such as 2nd and 3rd Bt459 registers are 68 * adjacent each other in a word, i.e., 69 * struct bt459triplet { 70 * struct { 71 * uint8_t u0; 72 * uint8_t u1; 73 * uint8_t u2; 74 * unsigned :8; 75 * } bt_lo; 76 * ... 77 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble. 78 * struct bt459reg { 79 * uint32_t bt_lo; 80 * uint32_t bt_hi; 81 * uint32_t bt_reg; 82 * uint32_t bt_cmap; 83 * }; 84 */ 85 86 /* Bt459 hardware registers, memory-mapped in 32bit stride */ 87 #define bt_lo 0x0 88 #define bt_hi 0x4 89 #define bt_reg 0x8 90 #define bt_cmap 0xc 91 92 #define REGWRITE32(p,i,v) do { \ 93 *(volatile uint32_t *)((p) + (i)) = (v); tc_wmb(); \ 94 } while (0) 95 #define VDACSELECT(p,r) do { \ 96 REGWRITE32(p, bt_lo, 0xff & (r)); \ 97 REGWRITE32(p, bt_hi, 0x0f & ((r)>>8)); \ 98 } while (0) 99 100 struct hwcmap256 { 101 #define CMAP_SIZE 256 /* 256 R/G/B entries */ 102 uint8_t r[CMAP_SIZE]; 103 uint8_t g[CMAP_SIZE]; 104 uint8_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 uint8_t cc_color[6]; 114 uint64_t cc_image[CURSOR_MAX_SIZE]; 115 uint64_t cc_mask[CURSOR_MAX_SIZE]; 116 }; 117 118 struct cfb_softc { 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(device_t, cfdata_t, void *); 140 static void cfbattach(device_t, device_t, void *); 141 142 CFATTACH_DECL_NEW(cfb, sizeof(struct cfb_softc), 143 cfbmatch, cfbattach, NULL, NULL); 144 145 static void cfb_common_init(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(void *, void *, u_long, void *, int, struct lwp *); 165 static paddr_t cfbmmap(void *, void *, off_t, int); 166 167 static int cfb_alloc_screen(void *, const struct wsscreen_descr *, 168 void **, int *, int *, long *); 169 static void cfb_free_screen(void *, void *); 170 static int cfb_show_screen(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(tc_addr_t); 183 static int cfbintr(void *); 184 static void cfbhwinit(void *); 185 static void cfb_cmap_init(struct cfb_softc *); 186 187 static int get_cmap(struct cfb_softc *, struct wsdisplay_cmap *); 188 static int set_cmap(struct cfb_softc *, struct wsdisplay_cmap *); 189 static int set_cursor(struct cfb_softc *, struct wsdisplay_cursor *); 190 static int get_cursor(struct cfb_softc *, struct wsdisplay_cursor *); 191 static void set_curpos(struct cfb_softc *, struct wsdisplay_curpos *); 192 193 /* 194 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 195 * M M M M I I I I M I M I M I M I 196 * [ before ] [ after ] 197 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 198 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 199 */ 200 static const uint8_t shuffle[256] = { 201 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 202 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 203 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 204 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 205 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 206 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 207 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 208 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 209 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 210 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 211 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 212 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 213 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 214 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 215 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 216 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 217 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 218 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 219 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 220 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 221 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 222 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 223 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 224 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 225 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 226 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 227 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 228 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 229 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 230 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 231 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 232 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 233 }; 234 235 static int 236 cfbmatch(device_t parent, cfdata_t match, void *aux) 237 { 238 struct tc_attach_args *ta = aux; 239 240 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0) 241 return (0); 242 243 return (1); 244 } 245 246 static void 247 cfbattach(device_t parent, device_t self, void *aux) 248 { 249 struct cfb_softc *sc = device_private(self); 250 struct tc_attach_args *ta = aux; 251 struct rasops_info *ri; 252 struct wsemuldisplaydev_attach_args waa; 253 int console; 254 255 console = (ta->ta_addr == cfb_consaddr); 256 if (console) { 257 sc->sc_ri = ri = &cfb_console_ri; 258 ri->ri_flg &= ~RI_NO_AUTO; 259 sc->nscreens = 1; 260 } 261 else { 262 ri = malloc(sizeof(struct rasops_info), 263 M_DEVBUF, M_NOWAIT|M_ZERO); 264 if (ri == NULL) { 265 printf(": can't alloc memory\n"); 266 return; 267 } 268 269 ri->ri_hw = (void *)ta->ta_addr; 270 cfb_common_init(ri); 271 sc->sc_ri = ri; 272 } 273 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 274 275 cfb_cmap_init(sc); 276 277 sc->sc_vaddr = ta->ta_addr; 278 sc->sc_cursor.cc_magic.x = CX_MAGIC_X; 279 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y; 280 sc->sc_blanked = sc->sc_curenb = 0; 281 282 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc); 283 284 /* clear any pending interrupts */ 285 *(volatile uint8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0; 286 287 waa.console = console; 288 waa.scrdata = &cfb_screenlist; 289 waa.accessops = &cfb_accessops; 290 waa.accesscookie = sc; 291 292 config_found(self, &waa, wsemuldisplaydevprint); 293 } 294 295 static void 296 cfb_cmap_init(struct cfb_softc *sc) 297 { 298 struct hwcmap256 *cm; 299 const uint8_t *p; 300 int index; 301 302 cm = &sc->sc_cmap; 303 p = rasops_cmap; 304 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 305 cm->r[index] = p[0]; 306 cm->g[index] = p[1]; 307 cm->b[index] = p[2]; 308 } 309 } 310 311 static void 312 cfb_common_init(struct rasops_info *ri) 313 { 314 char *base; 315 int cookie; 316 317 base = (void *)ri->ri_hw; 318 319 /* initialize colormap and cursor hardware */ 320 cfbhwinit(base); 321 322 ri->ri_flg = RI_CENTER; 323 if (ri == &cfb_console_ri) 324 ri->ri_flg |= RI_NO_AUTO; 325 ri->ri_depth = 8; 326 ri->ri_width = 1024; 327 ri->ri_height = 864; 328 ri->ri_stride = 1024; 329 ri->ri_bits = base + CX_FB_OFFSET; 330 331 /* clear the screen */ 332 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 333 334 wsfont_init(); 335 /* prefer 12 pixel wide font */ 336 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R, 337 WSDISPLAY_FONTORDER_L2R); 338 if (cookie <= 0) 339 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 340 WSDISPLAY_FONTORDER_L2R); 341 if (cookie <= 0) { 342 printf("cfb: font table is empty\n"); 343 return; 344 } 345 346 if (wsfont_lock(cookie, &ri->ri_font)) { 347 printf("cfb: couldn't lock font\n"); 348 return; 349 } 350 ri->ri_wsfcookie = cookie; 351 352 rasops_init(ri, 34, 80); 353 354 /* XXX shouldn't be global */ 355 cfb_stdscreen.nrows = ri->ri_rows; 356 cfb_stdscreen.ncols = ri->ri_cols; 357 cfb_stdscreen.textops = &ri->ri_ops; 358 cfb_stdscreen.capabilities = ri->ri_caps; 359 } 360 361 static int 362 cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 363 { 364 struct cfb_softc *sc = v; 365 struct rasops_info *ri = sc->sc_ri; 366 int turnoff, s; 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 != 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 s = spltty(); 407 set_curpos(sc, (struct wsdisplay_curpos *)data); 408 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS; 409 splx(s); 410 return (0); 411 412 case WSDISPLAYIO_GCURMAX: 413 ((struct wsdisplay_curpos *)data)->x = 414 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 415 return (0); 416 417 case WSDISPLAYIO_GCURSOR: 418 return get_cursor(sc, (struct wsdisplay_cursor *)data); 419 420 case WSDISPLAYIO_SCURSOR: 421 return set_cursor(sc, (struct wsdisplay_cursor *)data); 422 423 case WSDISPLAYIO_SMODE: 424 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { 425 s = spltty(); 426 cfb_cmap_init(sc); 427 sc->sc_curenb = 0; 428 sc->sc_blanked = 0; 429 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR | 430 WSDISPLAY_CMAP_DOLUT); 431 splx(s); 432 } 433 return (0); 434 } 435 return EPASSTHROUGH; 436 } 437 438 paddr_t 439 cfbmmap(void *v, void *vs, off_t offset, 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_vaddr + CX_FB_OFFSET + offset); 446 } 447 448 static int 449 cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 450 int *curxp, int *curyp, long *attrp) 451 { 452 struct cfb_softc *sc = v; 453 struct rasops_info *ri = sc->sc_ri; 454 long defattr; 455 456 if (sc->nscreens > 0) 457 return (ENOMEM); 458 459 *cookiep = ri; /* one and only for now */ 460 *curxp = 0; 461 *curyp = 0; 462 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 463 *attrp = defattr; 464 sc->nscreens++; 465 return (0); 466 } 467 468 static void 469 cfb_free_screen(void *v, void *cookie) 470 { 471 struct cfb_softc *sc = v; 472 473 if (sc->sc_ri == &cfb_console_ri) 474 panic("cfb_free_screen: console"); 475 476 sc->nscreens--; 477 } 478 479 static int 480 cfb_show_screen(void *v, void *cookie, int waitok, 481 void (*cb)(void *, int, int), void *cbarg) 482 { 483 484 return (0); 485 } 486 487 /* EXPORT */ int 488 cfb_cnattach(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(void *arg) 504 { 505 struct cfb_softc *sc = arg; 506 char *base, *vdac; 507 int v; 508 509 base = (void *)sc->sc_ri->ri_hw; 510 *(uint8_t *)(base + CX_OFFSET_IREQ) = 0; 511 if (sc->sc_changed == 0) 512 return (1); 513 514 vdac = base + CX_BT459_OFFSET; 515 v = sc->sc_changed; 516 if (v & WSDISPLAY_CURSOR_DOCUR) { 517 VDACSELECT(vdac, BT459_IREG_CCR); 518 REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00); 519 } 520 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 521 int x, y; 522 523 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 524 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 525 526 x += sc->sc_cursor.cc_magic.x; 527 y += sc->sc_cursor.cc_magic.y; 528 529 VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW); 530 REGWRITE32(vdac, bt_reg, x); 531 REGWRITE32(vdac, bt_reg, x >> 8); 532 REGWRITE32(vdac, bt_reg, y); 533 REGWRITE32(vdac, bt_reg, y >> 8); 534 } 535 if (v & WSDISPLAY_CURSOR_DOCMAP) { 536 uint8_t *cp = sc->sc_cursor.cc_color; 537 538 VDACSELECT(vdac, BT459_IREG_CCOLOR_2); 539 REGWRITE32(vdac, bt_reg, cp[1]); 540 REGWRITE32(vdac, bt_reg, cp[3]); 541 REGWRITE32(vdac, bt_reg, cp[5]); 542 543 REGWRITE32(vdac, bt_reg, cp[0]); 544 REGWRITE32(vdac, bt_reg, cp[2]); 545 REGWRITE32(vdac, bt_reg, cp[4]); 546 } 547 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 548 uint8_t *ip, *mp, img, msk; 549 uint8_t u; 550 int bcnt; 551 552 ip = (uint8_t *)sc->sc_cursor.cc_image; 553 mp = (uint8_t *)sc->sc_cursor.cc_mask; 554 555 bcnt = 0; 556 VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0); 557 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 558 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 559 /* pad right half 32 pixel when smaller than 33 */ 560 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 561 REGWRITE32(vdac, bt_reg, 0); 562 REGWRITE32(vdac, bt_reg, 0); 563 } 564 else { 565 img = *ip++; 566 msk = *mp++; 567 img &= msk; /* cookie off image */ 568 u = (msk & 0x0f) << 4 | (img & 0x0f); 569 REGWRITE32(vdac, bt_reg, shuffle[u]); 570 u = (msk & 0xf0) | (img & 0xf0) >> 4; 571 REGWRITE32(vdac, bt_reg, shuffle[u]); 572 } 573 bcnt += 2; 574 } 575 /* pad unoccupied scan lines */ 576 while (bcnt < CURSOR_MAX_SIZE * 16) { 577 REGWRITE32(vdac, bt_reg, 0); 578 REGWRITE32(vdac, bt_reg, 0); 579 bcnt += 2; 580 } 581 } 582 if (v & WSDISPLAY_CMAP_DOLUT) { 583 struct hwcmap256 *cm = &sc->sc_cmap; 584 int index; 585 586 VDACSELECT(vdac, 0); 587 for (index = 0; index < CMAP_SIZE; index++) { 588 REGWRITE32(vdac, bt_cmap, cm->r[index]); 589 REGWRITE32(vdac, bt_cmap, cm->g[index]); 590 REGWRITE32(vdac, bt_cmap, cm->b[index]); 591 } 592 } 593 sc->sc_changed = 0; 594 return (1); 595 } 596 597 static void 598 cfbhwinit(void *cfbbase) 599 { 600 char *vdac = (char *)cfbbase + CX_BT459_OFFSET; 601 const uint8_t *p; 602 int i; 603 604 VDACSELECT(vdac, BT459_IREG_COMMAND_0); 605 REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */ 606 REGWRITE32(vdac, bt_reg, 0x0); /* CMD1 */ 607 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */ 608 REGWRITE32(vdac, bt_reg, 0xff); /* PRM */ 609 REGWRITE32(vdac, bt_reg, 0); /* 205 */ 610 REGWRITE32(vdac, bt_reg, 0x0); /* PBM */ 611 REGWRITE32(vdac, bt_reg, 0); /* 207 */ 612 REGWRITE32(vdac, bt_reg, 0x0); /* ORM */ 613 REGWRITE32(vdac, bt_reg, 0x0); /* OBM */ 614 REGWRITE32(vdac, bt_reg, 0x0); /* ILV */ 615 REGWRITE32(vdac, bt_reg, 0x0); /* TEST */ 616 617 VDACSELECT(vdac, BT459_IREG_CCR); 618 REGWRITE32(vdac, bt_reg, 0x0); 619 REGWRITE32(vdac, bt_reg, 0x0); 620 REGWRITE32(vdac, bt_reg, 0x0); 621 REGWRITE32(vdac, bt_reg, 0x0); 622 REGWRITE32(vdac, bt_reg, 0x0); 623 REGWRITE32(vdac, bt_reg, 0x0); 624 REGWRITE32(vdac, bt_reg, 0x0); 625 REGWRITE32(vdac, bt_reg, 0x0); 626 REGWRITE32(vdac, bt_reg, 0x0); 627 REGWRITE32(vdac, bt_reg, 0x0); 628 REGWRITE32(vdac, bt_reg, 0x0); 629 REGWRITE32(vdac, bt_reg, 0x0); 630 REGWRITE32(vdac, bt_reg, 0x0); 631 632 /* build sane colormap */ 633 VDACSELECT(vdac, 0); 634 p = rasops_cmap; 635 for (i = 0; i < CMAP_SIZE; i++, p += 3) { 636 REGWRITE32(vdac, bt_cmap, p[0]); 637 REGWRITE32(vdac, bt_cmap, p[1]); 638 REGWRITE32(vdac, bt_cmap, p[2]); 639 } 640 641 /* clear out cursor image */ 642 VDACSELECT(vdac, BT459_IREG_CRAM_BASE); 643 for (i = 0; i < 1024; i++) 644 REGWRITE32(vdac, bt_reg, 0xff); 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 VDACSELECT(vdac, BT459_IREG_CCOLOR_1); 652 REGWRITE32(vdac, bt_reg, 0xff); 653 REGWRITE32(vdac, bt_reg, 0xff); 654 REGWRITE32(vdac, bt_reg, 0xff); 655 656 REGWRITE32(vdac, bt_reg, 0); 657 REGWRITE32(vdac, bt_reg, 0); 658 REGWRITE32(vdac, bt_reg, 0); 659 660 REGWRITE32(vdac, bt_reg, 0xff); 661 REGWRITE32(vdac, bt_reg, 0xff); 662 REGWRITE32(vdac, bt_reg, 0xff); 663 } 664 665 static int 666 get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p) 667 { 668 u_int index = p->index, count = p->count; 669 int error; 670 671 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 672 return (EINVAL); 673 674 error = copyout(&sc->sc_cmap.r[index], p->red, count); 675 if (error) 676 return error; 677 error = copyout(&sc->sc_cmap.g[index], p->green, count); 678 if (error) 679 return error; 680 error = copyout(&sc->sc_cmap.b[index], p->blue, count); 681 return error; 682 } 683 684 static int 685 set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p) 686 { 687 struct hwcmap256 cmap; 688 u_int index = p->index, count = p->count; 689 int error, s; 690 691 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 692 return (EINVAL); 693 694 error = copyin(p->red, &cmap.r[index], count); 695 if (error) 696 return error; 697 error = copyin(p->green, &cmap.g[index], count); 698 if (error) 699 return error; 700 error = copyin(p->blue, &cmap.b[index], count); 701 if (error) 702 return error; 703 s = spltty(); 704 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count); 705 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count); 706 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count); 707 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 708 splx(s); 709 return (0); 710 } 711 712 static int 713 set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p) 714 { 715 #define cc (&sc->sc_cursor) 716 u_int v, index = 0, count = 0, icount = 0; 717 uint8_t r[2], g[2], b[2], image[512], mask[512]; 718 int error, s; 719 720 v = p->which; 721 if (v & WSDISPLAY_CURSOR_DOCMAP) { 722 index = p->cmap.index; 723 count = p->cmap.count; 724 if (index >= 2 || (index + count) > 2) 725 return (EINVAL); 726 error = copyin(p->cmap.red, &r[index], count); 727 if (error) 728 return error; 729 error = copyin(p->cmap.green, &g[index], count); 730 if (error) 731 return error; 732 error = copyin(p->cmap.blue, &b[index], count); 733 if (error) 734 return error; 735 } 736 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 737 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 738 return (EINVAL); 739 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 740 error = copyin(p->image, image, icount); 741 if (error) 742 return error; 743 error = copyin(p->mask, mask, icount); 744 if (error) 745 return error; 746 } 747 748 s = spltty(); 749 if (v & WSDISPLAY_CURSOR_DOCUR) 750 sc->sc_curenb = p->enable; 751 if (v & WSDISPLAY_CURSOR_DOPOS) 752 set_curpos(sc, &p->pos); 753 if (v & WSDISPLAY_CURSOR_DOHOT) 754 cc->cc_hot = p->hot; 755 if (v & WSDISPLAY_CURSOR_DOCMAP) { 756 memcpy(&cc->cc_color[index], &r[index], count); 757 memcpy(&cc->cc_color[index + 2], &g[index], count); 758 memcpy(&cc->cc_color[index + 4], &b[index], count); 759 } 760 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 761 cc->cc_size = p->size; 762 memset(cc->cc_image, 0, sizeof cc->cc_image); 763 memcpy(cc->cc_image, image, icount); 764 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 765 memcpy(cc->cc_mask, mask, icount); 766 } 767 sc->sc_changed |= v; 768 splx(s); 769 770 return (0); 771 #undef cc 772 } 773 774 static int 775 get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p) 776 { 777 return (EPASSTHROUGH); /* XXX */ 778 } 779 780 static void 781 set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos) 782 { 783 struct rasops_info *ri = sc->sc_ri; 784 int x = curpos->x, y = curpos->y; 785 786 if (y < 0) 787 y = 0; 788 else if (y > ri->ri_height) 789 y = ri->ri_height; 790 if (x < 0) 791 x = 0; 792 else if (x > ri->ri_width) 793 x = ri->ri_width; 794 sc->sc_cursor.cc_pos.x = x; 795 sc->sc_cursor.cc_pos.y = y; 796 } 797