cfb.c revision 1.52
1/* $NetBSD: cfb.c,v 1.52 2007/03/04 15:17:06 yamt 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.52 2007/03/04 15:17:06 yamt 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, memory-mapped in 32bit stride */ 88#define bt_lo 0x0 89#define bt_hi 0x4 90#define bt_reg 0x8 91#define bt_cmap 0xc 92 93#define REGWRITE32(p,i,v) do { \ 94 *(volatile u_int32_t *)((p) + (i)) = (v); tc_wmb(); \ 95 } while (0) 96#define VDACSELECT(p,r) do { \ 97 REGWRITE32(p, bt_lo, 0xff & (r)); \ 98 REGWRITE32(p, bt_hi, 0x0f & ((r)>>8)); \ 99 } while (0) 100 101struct hwcmap256 { 102#define CMAP_SIZE 256 /* 256 R/G/B entries */ 103 u_int8_t r[CMAP_SIZE]; 104 u_int8_t g[CMAP_SIZE]; 105 u_int8_t b[CMAP_SIZE]; 106}; 107 108struct hwcursor64 { 109 struct wsdisplay_curpos cc_pos; 110 struct wsdisplay_curpos cc_hot; 111 struct wsdisplay_curpos cc_size; 112 struct wsdisplay_curpos cc_magic; 113#define CURSOR_MAX_SIZE 64 114 u_int8_t cc_color[6]; 115 u_int64_t cc_image[CURSOR_MAX_SIZE]; 116 u_int64_t cc_mask[CURSOR_MAX_SIZE]; 117}; 118 119struct cfb_softc { 120 struct device sc_dev; 121 vaddr_t sc_vaddr; 122 size_t sc_size; 123 struct rasops_info *sc_ri; 124 struct hwcmap256 sc_cmap; /* software copy of colormap */ 125 struct hwcursor64 sc_cursor; /* software copy of cursor */ 126 int sc_blanked; 127 int sc_curenb; /* cursor sprite enabled */ 128 int sc_changed; /* need update of hardware */ 129#define WSDISPLAY_CMAP_DOLUT 0x20 130 int nscreens; 131}; 132 133#define CX_MAGIC_X 220 134#define CX_MAGIC_Y 35 135 136#define CX_FB_OFFSET 0x000000 137#define CX_FB_SIZE 0x100000 138#define CX_BT459_OFFSET 0x200000 139#define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 140 141static int cfbmatch(struct device *, struct cfdata *, void *); 142static void cfbattach(struct device *, struct device *, void *); 143 144CFATTACH_DECL(cfb, sizeof(struct cfb_softc), 145 cfbmatch, cfbattach, NULL, NULL); 146 147static void cfb_common_init(struct rasops_info *); 148static struct rasops_info cfb_console_ri; 149static tc_addr_t cfb_consaddr; 150 151static struct wsscreen_descr cfb_stdscreen = { 152 "std", 0, 0, 153 0, /* textops */ 154 0, 0, 155 WSSCREEN_REVERSE 156}; 157 158static const struct wsscreen_descr *_cfb_scrlist[] = { 159 &cfb_stdscreen, 160}; 161 162static const struct wsscreen_list cfb_screenlist = { 163 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist 164}; 165 166static int cfbioctl(void *, void *, u_long, void *, int, struct lwp *); 167static paddr_t cfbmmap(void *, void *, off_t, int); 168 169static int cfb_alloc_screen(void *, const struct wsscreen_descr *, 170 void **, int *, int *, long *); 171static void cfb_free_screen(void *, void *); 172static int cfb_show_screen(void *, void *, int, 173 void (*) (void *, int, int), void *); 174 175static const struct wsdisplay_accessops cfb_accessops = { 176 cfbioctl, 177 cfbmmap, 178 cfb_alloc_screen, 179 cfb_free_screen, 180 cfb_show_screen, 181 0 /* load_font */ 182}; 183 184int cfb_cnattach(tc_addr_t); 185static int cfbintr(void *); 186static void cfbhwinit(void *); 187static void cfb_cmap_init(struct cfb_softc *); 188 189static int get_cmap(struct cfb_softc *, struct wsdisplay_cmap *); 190static int set_cmap(struct cfb_softc *, struct wsdisplay_cmap *); 191static int set_cursor(struct cfb_softc *, struct wsdisplay_cursor *); 192static int get_cursor(struct cfb_softc *, struct wsdisplay_cursor *); 193static void set_curpos(struct cfb_softc *, struct wsdisplay_curpos *); 194 195/* 196 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 197 * M M M M I I I I M I M I M I M I 198 * [ before ] [ after ] 199 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 200 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 201 */ 202static const u_int8_t shuffle[256] = { 203 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 204 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 205 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 206 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 207 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 208 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 209 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 210 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 211 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 212 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 213 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 214 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 215 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 216 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 217 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 218 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 219 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 220 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 221 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 222 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 223 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 224 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 225 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 226 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 227 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 228 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 229 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 230 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 231 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 232 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 233 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 234 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 235}; 236 237static int 238cfbmatch(struct device *parent, struct cfdata *match, 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 248static void 249cfbattach(struct device *parent, struct device *self, void *aux) 250{ 251 struct cfb_softc *sc = device_private(self); 252 struct tc_attach_args *ta = aux; 253 struct rasops_info *ri; 254 struct wsemuldisplaydev_attach_args waa; 255 int console; 256 257 console = (ta->ta_addr == cfb_consaddr); 258 if (console) { 259 sc->sc_ri = ri = &cfb_console_ri; 260 sc->nscreens = 1; 261 } 262 else { 263 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info), 264 M_DEVBUF, M_NOWAIT); 265 if (ri == NULL) { 266 printf(": can't alloc memory\n"); 267 return; 268 } 269 memset(ri, 0, sizeof(struct rasops_info)); 270 271 ri->ri_hw = (void *)ta->ta_addr; 272 cfb_common_init(ri); 273 sc->sc_ri = ri; 274 } 275 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 276 277 cfb_cmap_init(sc); 278 279 sc->sc_vaddr = ta->ta_addr; 280 sc->sc_cursor.cc_magic.x = CX_MAGIC_X; 281 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y; 282 sc->sc_blanked = sc->sc_curenb = 0; 283 284 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc); 285 286 /* clear any pending interrupts */ 287 *(volatile u_int8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0; 288 289 waa.console = console; 290 waa.scrdata = &cfb_screenlist; 291 waa.accessops = &cfb_accessops; 292 waa.accesscookie = sc; 293 294 config_found(self, &waa, wsemuldisplaydevprint); 295} 296 297static void 298cfb_cmap_init(struct cfb_softc *sc) 299{ 300 struct hwcmap256 *cm; 301 const u_int8_t *p; 302 int index; 303 304 cm = &sc->sc_cmap; 305 p = rasops_cmap; 306 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 307 cm->r[index] = p[0]; 308 cm->g[index] = p[1]; 309 cm->b[index] = p[2]; 310 } 311} 312 313static void 314cfb_common_init(struct rasops_info *ri) 315{ 316 char *base; 317 int cookie; 318 319 base = (void *)ri->ri_hw; 320 321 /* initialize colormap and cursor hardware */ 322 cfbhwinit(base); 323 324 ri->ri_flg = RI_CENTER; 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 361static int 362cfbioctl(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 438paddr_t 439cfbmmap(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 448static int 449cfb_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 468static void 469cfb_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 479static int 480cfb_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 488cfb_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 502static int 503cfbintr(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 *(u_int8_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 u_int8_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 u_int8_t *ip, *mp, img, msk; 549 u_int8_t u; 550 int bcnt; 551 552 ip = (u_int8_t *)sc->sc_cursor.cc_image; 553 mp = (u_int8_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 597static void 598cfbhwinit(void *cfbbase) 599{ 600 char *vdac = (char *)cfbbase + CX_BT459_OFFSET; 601 const u_int8_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 665static int 666get_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 684static int 685set_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 712static int 713set_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 774static int 775get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p) 776{ 777 return (EPASSTHROUGH); /* XXX */ 778} 779 780static void 781set_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