cfb.c revision 1.57
1/* $NetBSD: cfb.c,v 1.57 2009/08/22 17:38:06 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.57 2009/08/22 17:38:06 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 100struct 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 107struct 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 118struct 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 139static int cfbmatch(device_t, cfdata_t, void *); 140static void cfbattach(device_t, device_t, void *); 141 142CFATTACH_DECL_NEW(cfb, sizeof(struct cfb_softc), 143 cfbmatch, cfbattach, NULL, NULL); 144 145static void cfb_common_init(struct rasops_info *); 146static struct rasops_info cfb_console_ri; 147static tc_addr_t cfb_consaddr; 148 149static struct wsscreen_descr cfb_stdscreen = { 150 "std", 0, 0, 151 0, /* textops */ 152 0, 0, 153 WSSCREEN_REVERSE 154}; 155 156static const struct wsscreen_descr *_cfb_scrlist[] = { 157 &cfb_stdscreen, 158}; 159 160static const struct wsscreen_list cfb_screenlist = { 161 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist 162}; 163 164static int cfbioctl(void *, void *, u_long, void *, int, struct lwp *); 165static paddr_t cfbmmap(void *, void *, off_t, int); 166 167static int cfb_alloc_screen(void *, const struct wsscreen_descr *, 168 void **, int *, int *, long *); 169static void cfb_free_screen(void *, void *); 170static int cfb_show_screen(void *, void *, int, 171 void (*) (void *, int, int), void *); 172 173static 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 182int cfb_cnattach(tc_addr_t); 183static int cfbintr(void *); 184static void cfbhwinit(void *); 185static void cfb_cmap_init(struct cfb_softc *); 186 187static int get_cmap(struct cfb_softc *, struct wsdisplay_cmap *); 188static int set_cmap(struct cfb_softc *, struct wsdisplay_cmap *); 189static int set_cursor(struct cfb_softc *, struct wsdisplay_cursor *); 190static int get_cursor(struct cfb_softc *, struct wsdisplay_cursor *); 191static 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 */ 200static 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 235static int 236cfbmatch(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 246static void 247cfbattach(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 sc->nscreens = 1; 259 } 260 else { 261 ri = malloc(sizeof(struct rasops_info), 262 M_DEVBUF, M_NOWAIT|M_ZERO); 263 if (ri == NULL) { 264 printf(": can't alloc memory\n"); 265 return; 266 } 267 268 ri->ri_hw = (void *)ta->ta_addr; 269 cfb_common_init(ri); 270 sc->sc_ri = ri; 271 } 272 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 273 274 cfb_cmap_init(sc); 275 276 sc->sc_vaddr = ta->ta_addr; 277 sc->sc_cursor.cc_magic.x = CX_MAGIC_X; 278 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y; 279 sc->sc_blanked = sc->sc_curenb = 0; 280 281 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc); 282 283 /* clear any pending interrupts */ 284 *(volatile uint8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0; 285 286 waa.console = console; 287 waa.scrdata = &cfb_screenlist; 288 waa.accessops = &cfb_accessops; 289 waa.accesscookie = sc; 290 291 config_found(self, &waa, wsemuldisplaydevprint); 292} 293 294static void 295cfb_cmap_init(struct cfb_softc *sc) 296{ 297 struct hwcmap256 *cm; 298 const uint8_t *p; 299 int index; 300 301 cm = &sc->sc_cmap; 302 p = rasops_cmap; 303 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 304 cm->r[index] = p[0]; 305 cm->g[index] = p[1]; 306 cm->b[index] = p[2]; 307 } 308} 309 310static void 311cfb_common_init(struct rasops_info *ri) 312{ 313 char *base; 314 int cookie; 315 316 base = (void *)ri->ri_hw; 317 318 /* initialize colormap and cursor hardware */ 319 cfbhwinit(base); 320 321 ri->ri_flg = RI_CENTER; 322 ri->ri_depth = 8; 323 ri->ri_width = 1024; 324 ri->ri_height = 864; 325 ri->ri_stride = 1024; 326 ri->ri_bits = base + CX_FB_OFFSET; 327 328 /* clear the screen */ 329 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 330 331 wsfont_init(); 332 /* prefer 12 pixel wide font */ 333 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R, 334 WSDISPLAY_FONTORDER_L2R); 335 if (cookie <= 0) 336 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 337 WSDISPLAY_FONTORDER_L2R); 338 if (cookie <= 0) { 339 printf("cfb: font table is empty\n"); 340 return; 341 } 342 343 if (wsfont_lock(cookie, &ri->ri_font)) { 344 printf("cfb: couldn't lock font\n"); 345 return; 346 } 347 ri->ri_wsfcookie = cookie; 348 349 rasops_init(ri, 34, 80); 350 351 /* XXX shouldn't be global */ 352 cfb_stdscreen.nrows = ri->ri_rows; 353 cfb_stdscreen.ncols = ri->ri_cols; 354 cfb_stdscreen.textops = &ri->ri_ops; 355 cfb_stdscreen.capabilities = ri->ri_caps; 356} 357 358static int 359cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 360{ 361 struct cfb_softc *sc = v; 362 struct rasops_info *ri = sc->sc_ri; 363 int turnoff, s; 364 365 switch (cmd) { 366 case WSDISPLAYIO_GTYPE: 367 *(u_int *)data = WSDISPLAY_TYPE_CFB; 368 return (0); 369 370 case WSDISPLAYIO_GINFO: 371#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 372 wsd_fbip->height = ri->ri_height; 373 wsd_fbip->width = ri->ri_width; 374 wsd_fbip->depth = ri->ri_depth; 375 wsd_fbip->cmsize = CMAP_SIZE; 376#undef fbt 377 return (0); 378 379 case WSDISPLAYIO_GETCMAP: 380 return get_cmap(sc, (struct wsdisplay_cmap *)data); 381 382 case WSDISPLAYIO_PUTCMAP: 383 return set_cmap(sc, (struct wsdisplay_cmap *)data); 384 385 case WSDISPLAYIO_SVIDEO: 386 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 387 if (sc->sc_blanked != turnoff) { 388 sc->sc_blanked = turnoff; 389 /* XXX later XXX */ 390 } 391 return (0); 392 393 case WSDISPLAYIO_GVIDEO: 394 *(u_int *)data = sc->sc_blanked ? 395 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 396 return (0); 397 398 case WSDISPLAYIO_GCURPOS: 399 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 400 return (0); 401 402 case WSDISPLAYIO_SCURPOS: 403 s = spltty(); 404 set_curpos(sc, (struct wsdisplay_curpos *)data); 405 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS; 406 splx(s); 407 return (0); 408 409 case WSDISPLAYIO_GCURMAX: 410 ((struct wsdisplay_curpos *)data)->x = 411 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 412 return (0); 413 414 case WSDISPLAYIO_GCURSOR: 415 return get_cursor(sc, (struct wsdisplay_cursor *)data); 416 417 case WSDISPLAYIO_SCURSOR: 418 return set_cursor(sc, (struct wsdisplay_cursor *)data); 419 420 case WSDISPLAYIO_SMODE: 421 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { 422 s = spltty(); 423 cfb_cmap_init(sc); 424 sc->sc_curenb = 0; 425 sc->sc_blanked = 0; 426 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR | 427 WSDISPLAY_CMAP_DOLUT); 428 splx(s); 429 } 430 return (0); 431 } 432 return EPASSTHROUGH; 433} 434 435paddr_t 436cfbmmap(void *v, void *vs, off_t offset, int prot) 437{ 438 struct cfb_softc *sc = v; 439 440 if (offset >= CX_FB_SIZE || offset < 0) 441 return (-1); 442 return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset); 443} 444 445static int 446cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 447 int *curxp, int *curyp, long *attrp) 448{ 449 struct cfb_softc *sc = v; 450 struct rasops_info *ri = sc->sc_ri; 451 long defattr; 452 453 if (sc->nscreens > 0) 454 return (ENOMEM); 455 456 *cookiep = ri; /* one and only for now */ 457 *curxp = 0; 458 *curyp = 0; 459 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 460 *attrp = defattr; 461 sc->nscreens++; 462 return (0); 463} 464 465static void 466cfb_free_screen(void *v, void *cookie) 467{ 468 struct cfb_softc *sc = v; 469 470 if (sc->sc_ri == &cfb_console_ri) 471 panic("cfb_free_screen: console"); 472 473 sc->nscreens--; 474} 475 476static int 477cfb_show_screen(void *v, void *cookie, int waitok, 478 void (*cb)(void *, int, int), void *cbarg) 479{ 480 481 return (0); 482} 483 484/* EXPORT */ int 485cfb_cnattach(tc_addr_t addr) 486{ 487 struct rasops_info *ri; 488 long defattr; 489 490 ri = &cfb_console_ri; 491 ri->ri_hw = (void *)addr; 492 cfb_common_init(ri); 493 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 494 wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr); 495 cfb_consaddr = addr; 496 return(0); 497} 498 499static int 500cfbintr(void *arg) 501{ 502 struct cfb_softc *sc = arg; 503 char *base, *vdac; 504 int v; 505 506 base = (void *)sc->sc_ri->ri_hw; 507 *(uint8_t *)(base + CX_OFFSET_IREQ) = 0; 508 if (sc->sc_changed == 0) 509 return (1); 510 511 vdac = base + CX_BT459_OFFSET; 512 v = sc->sc_changed; 513 if (v & WSDISPLAY_CURSOR_DOCUR) { 514 VDACSELECT(vdac, BT459_IREG_CCR); 515 REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00); 516 } 517 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 518 int x, y; 519 520 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 521 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 522 523 x += sc->sc_cursor.cc_magic.x; 524 y += sc->sc_cursor.cc_magic.y; 525 526 VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW); 527 REGWRITE32(vdac, bt_reg, x); 528 REGWRITE32(vdac, bt_reg, x >> 8); 529 REGWRITE32(vdac, bt_reg, y); 530 REGWRITE32(vdac, bt_reg, y >> 8); 531 } 532 if (v & WSDISPLAY_CURSOR_DOCMAP) { 533 uint8_t *cp = sc->sc_cursor.cc_color; 534 535 VDACSELECT(vdac, BT459_IREG_CCOLOR_2); 536 REGWRITE32(vdac, bt_reg, cp[1]); 537 REGWRITE32(vdac, bt_reg, cp[3]); 538 REGWRITE32(vdac, bt_reg, cp[5]); 539 540 REGWRITE32(vdac, bt_reg, cp[0]); 541 REGWRITE32(vdac, bt_reg, cp[2]); 542 REGWRITE32(vdac, bt_reg, cp[4]); 543 } 544 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 545 uint8_t *ip, *mp, img, msk; 546 uint8_t u; 547 int bcnt; 548 549 ip = (uint8_t *)sc->sc_cursor.cc_image; 550 mp = (uint8_t *)sc->sc_cursor.cc_mask; 551 552 bcnt = 0; 553 VDACSELECT(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 REGWRITE32(vdac, bt_reg, 0); 559 REGWRITE32(vdac, bt_reg, 0); 560 } 561 else { 562 img = *ip++; 563 msk = *mp++; 564 img &= msk; /* cookie off image */ 565 u = (msk & 0x0f) << 4 | (img & 0x0f); 566 REGWRITE32(vdac, bt_reg, shuffle[u]); 567 u = (msk & 0xf0) | (img & 0xf0) >> 4; 568 REGWRITE32(vdac, bt_reg, shuffle[u]); 569 } 570 bcnt += 2; 571 } 572 /* pad unoccupied scan lines */ 573 while (bcnt < CURSOR_MAX_SIZE * 16) { 574 REGWRITE32(vdac, bt_reg, 0); 575 REGWRITE32(vdac, bt_reg, 0); 576 bcnt += 2; 577 } 578 } 579 if (v & WSDISPLAY_CMAP_DOLUT) { 580 struct hwcmap256 *cm = &sc->sc_cmap; 581 int index; 582 583 VDACSELECT(vdac, 0); 584 for (index = 0; index < CMAP_SIZE; index++) { 585 REGWRITE32(vdac, bt_cmap, cm->r[index]); 586 REGWRITE32(vdac, bt_cmap, cm->g[index]); 587 REGWRITE32(vdac, bt_cmap, cm->b[index]); 588 } 589 } 590 sc->sc_changed = 0; 591 return (1); 592} 593 594static void 595cfbhwinit(void *cfbbase) 596{ 597 char *vdac = (char *)cfbbase + CX_BT459_OFFSET; 598 const uint8_t *p; 599 int i; 600 601 VDACSELECT(vdac, BT459_IREG_COMMAND_0); 602 REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */ 603 REGWRITE32(vdac, bt_reg, 0x0); /* CMD1 */ 604 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */ 605 REGWRITE32(vdac, bt_reg, 0xff); /* PRM */ 606 REGWRITE32(vdac, bt_reg, 0); /* 205 */ 607 REGWRITE32(vdac, bt_reg, 0x0); /* PBM */ 608 REGWRITE32(vdac, bt_reg, 0); /* 207 */ 609 REGWRITE32(vdac, bt_reg, 0x0); /* ORM */ 610 REGWRITE32(vdac, bt_reg, 0x0); /* OBM */ 611 REGWRITE32(vdac, bt_reg, 0x0); /* ILV */ 612 REGWRITE32(vdac, bt_reg, 0x0); /* TEST */ 613 614 VDACSELECT(vdac, BT459_IREG_CCR); 615 REGWRITE32(vdac, bt_reg, 0x0); 616 REGWRITE32(vdac, bt_reg, 0x0); 617 REGWRITE32(vdac, bt_reg, 0x0); 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 629 /* build sane colormap */ 630 VDACSELECT(vdac, 0); 631 p = rasops_cmap; 632 for (i = 0; i < CMAP_SIZE; i++, p += 3) { 633 REGWRITE32(vdac, bt_cmap, p[0]); 634 REGWRITE32(vdac, bt_cmap, p[1]); 635 REGWRITE32(vdac, bt_cmap, p[2]); 636 } 637 638 /* clear out cursor image */ 639 VDACSELECT(vdac, BT459_IREG_CRAM_BASE); 640 for (i = 0; i < 1024; i++) 641 REGWRITE32(vdac, bt_reg, 0xff); 642 643 /* 644 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 645 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for 646 * image color. CCOLOR_1 will be never used. 647 */ 648 VDACSELECT(vdac, BT459_IREG_CCOLOR_1); 649 REGWRITE32(vdac, bt_reg, 0xff); 650 REGWRITE32(vdac, bt_reg, 0xff); 651 REGWRITE32(vdac, bt_reg, 0xff); 652 653 REGWRITE32(vdac, bt_reg, 0); 654 REGWRITE32(vdac, bt_reg, 0); 655 REGWRITE32(vdac, bt_reg, 0); 656 657 REGWRITE32(vdac, bt_reg, 0xff); 658 REGWRITE32(vdac, bt_reg, 0xff); 659 REGWRITE32(vdac, bt_reg, 0xff); 660} 661 662static int 663get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p) 664{ 665 u_int index = p->index, count = p->count; 666 int error; 667 668 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 669 return (EINVAL); 670 671 error = copyout(&sc->sc_cmap.r[index], p->red, count); 672 if (error) 673 return error; 674 error = copyout(&sc->sc_cmap.g[index], p->green, count); 675 if (error) 676 return error; 677 error = copyout(&sc->sc_cmap.b[index], p->blue, count); 678 return error; 679} 680 681static int 682set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p) 683{ 684 struct hwcmap256 cmap; 685 u_int index = p->index, count = p->count; 686 int error, s; 687 688 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 689 return (EINVAL); 690 691 error = copyin(p->red, &cmap.r[index], count); 692 if (error) 693 return error; 694 error = copyin(p->green, &cmap.g[index], count); 695 if (error) 696 return error; 697 error = copyin(p->blue, &cmap.b[index], count); 698 if (error) 699 return error; 700 s = spltty(); 701 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count); 702 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count); 703 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count); 704 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 705 splx(s); 706 return (0); 707} 708 709static int 710set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p) 711{ 712#define cc (&sc->sc_cursor) 713 u_int v, index = 0, count = 0, icount = 0; 714 uint8_t r[2], g[2], b[2], image[512], mask[512]; 715 int error, s; 716 717 v = p->which; 718 if (v & WSDISPLAY_CURSOR_DOCMAP) { 719 index = p->cmap.index; 720 count = p->cmap.count; 721 if (index >= 2 || (index + count) > 2) 722 return (EINVAL); 723 error = copyin(p->cmap.red, &r[index], count); 724 if (error) 725 return error; 726 error = copyin(p->cmap.green, &g[index], count); 727 if (error) 728 return error; 729 error = copyin(p->cmap.blue, &b[index], count); 730 if (error) 731 return error; 732 } 733 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 734 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 735 return (EINVAL); 736 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 737 error = copyin(p->image, image, icount); 738 if (error) 739 return error; 740 error = copyin(p->mask, mask, icount); 741 if (error) 742 return error; 743 } 744 745 s = spltty(); 746 if (v & WSDISPLAY_CURSOR_DOCUR) 747 sc->sc_curenb = p->enable; 748 if (v & WSDISPLAY_CURSOR_DOPOS) 749 set_curpos(sc, &p->pos); 750 if (v & WSDISPLAY_CURSOR_DOHOT) 751 cc->cc_hot = p->hot; 752 if (v & WSDISPLAY_CURSOR_DOCMAP) { 753 memcpy(&cc->cc_color[index], &r[index], count); 754 memcpy(&cc->cc_color[index + 2], &g[index], count); 755 memcpy(&cc->cc_color[index + 4], &b[index], count); 756 } 757 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 758 cc->cc_size = p->size; 759 memset(cc->cc_image, 0, sizeof cc->cc_image); 760 memcpy(cc->cc_image, image, icount); 761 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 762 memcpy(cc->cc_mask, mask, icount); 763 } 764 sc->sc_changed |= v; 765 splx(s); 766 767 return (0); 768#undef cc 769} 770 771static int 772get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p) 773{ 774 return (EPASSTHROUGH); /* XXX */ 775} 776 777static void 778set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos) 779{ 780 struct rasops_info *ri = sc->sc_ri; 781 int x = curpos->x, y = curpos->y; 782 783 if (y < 0) 784 y = 0; 785 else if (y > ri->ri_height) 786 y = ri->ri_height; 787 if (x < 0) 788 x = 0; 789 else if (x > ri->ri_width) 790 x = ri->ri_width; 791 sc->sc_cursor.cc_pos.x = x; 792 sc->sc_cursor.cc_pos.y = y; 793} 794