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