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