1 /* 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)cgsix.c 8.4 (Berkeley) 01/21/94 17 * 18 * from: $Header: cgsix.c,v 1.2 93/10/18 00:01:51 torek Exp $ 19 */ 20 21 /* 22 * color display (cgsix) driver. 23 * 24 * Does not handle interrupts, even though they can occur. 25 * 26 * XXX should defer colormap updates to vertical retrace interrupts 27 */ 28 29 #include <sys/param.h> 30 #include <sys/buf.h> 31 #include <sys/device.h> 32 #include <sys/fbio.h> 33 #include <sys/ioctl.h> 34 #include <sys/malloc.h> 35 #include <sys/mman.h> 36 #include <sys/tty.h> 37 38 #ifdef DEBUG 39 #include <sys/proc.h> 40 #include <sys/syslog.h> 41 #endif 42 43 #include <machine/autoconf.h> 44 #include <machine/pmap.h> 45 #include <machine/fbvar.h> 46 47 #include <sparc/sbus/btreg.h> 48 #include <sparc/sbus/btvar.h> 49 #include <sparc/sbus/cgsixreg.h> 50 #include <sparc/sbus/sbusvar.h> 51 52 union cursor_cmap { /* colormap, like bt_cmap, but tiny */ 53 u_char cm_map[2][3]; /* 2 R/G/B entries */ 54 u_int cm_chip[2]; /* 2 chip equivalents */ 55 }; 56 57 struct cg6_cursor { /* cg6 hardware cursor status */ 58 short cc_enable; /* cursor is enabled */ 59 struct fbcurpos cc_pos; /* position */ 60 struct fbcurpos cc_hot; /* hot-spot */ 61 struct fbcurpos cc_size; /* size of mask & image fields */ 62 u_int cc_bits[2][32]; /* space for mask & image bits */ 63 union cursor_cmap cc_color; /* cursor colormap */ 64 }; 65 66 /* per-display variables */ 67 struct cgsix_softc { 68 struct device sc_dev; /* base device */ 69 struct sbusdev sc_sd; /* sbus device */ 70 struct fbdevice sc_fb; /* frame buffer device */ 71 volatile struct cg6_layout *sc_physadr; /* phys addr of h/w */ 72 volatile struct bt_regs *sc_bt; /* Brooktree registers */ 73 volatile int *sc_fhc; /* FHC register */ 74 volatile struct cg6_thc *sc_thc; /* THC registers */ 75 volatile struct cg6_tec_xxx *sc_tec; /* TEC registers */ 76 short sc_fhcrev; /* hardware rev */ 77 short sc_blanked; /* true if blanked */ 78 struct cg6_cursor sc_cursor; /* software cursor info */ 79 union bt_cmap sc_cmap; /* Brooktree color map */ 80 }; 81 82 /* autoconfiguration driver */ 83 static void cgsixattach(struct device *, struct device *, void *); 84 struct cfdriver cgsixcd = 85 { NULL, "cgsix", matchbyname, cgsixattach, 86 DV_DULL, sizeof(struct cgsix_softc) }; 87 88 /* frame buffer generic driver */ 89 static void cg6_unblank(struct device *); 90 static struct fbdriver cg6_fbdriver = { cg6_unblank }; 91 92 /* 93 * Unlike the bw2 and cg3 drivers, we do not need to provide an rconsole 94 * interface, as the cg6 is fast enough. 95 */ 96 97 extern int fbnode; 98 99 #define CGSIX_MAJOR 67 /* XXX */ 100 101 static void cg6_reset __P((struct cgsix_softc *)); 102 static void cg6_loadcmap __P((struct cgsix_softc *, int, int)); 103 static void cg6_loadomap __P((struct cgsix_softc *)); 104 static void cg6_setcursor __P((struct cgsix_softc *));/* set position */ 105 static void cg6_loadcursor __P((struct cgsix_softc *));/* set shape */ 106 107 /* 108 * Attach a display. 109 */ 110 void 111 cgsixattach(parent, self, args) 112 struct device *parent, *self; 113 void *args; 114 { 115 register struct cgsix_softc *sc = (struct cgsix_softc *)self; 116 register struct sbus_attach_args *sa = args; 117 register int node = sa->sa_ra.ra_node, ramsize, i; 118 register volatile struct bt_regs *bt; 119 register volatile struct cg6_layout *p; 120 121 sc->sc_fb.fb_major = CGSIX_MAJOR; /* XXX to be removed */ 122 123 sc->sc_fb.fb_driver = &cg6_fbdriver; 124 sc->sc_fb.fb_device = &sc->sc_dev; 125 sc->sc_fb.fb_type.fb_type = FBTYPE_SUNFAST_COLOR; 126 sc->sc_fb.fb_type.fb_width = getpropint(node, "width", 1152); 127 sc->sc_fb.fb_type.fb_height = getpropint(node, "height", 900); 128 sc->sc_fb.fb_linebytes = getpropint(node, "linebytes", 1152); 129 ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes; 130 sc->sc_fb.fb_type.fb_depth = 8; 131 sc->sc_fb.fb_type.fb_cmsize = 256; 132 sc->sc_fb.fb_type.fb_size = ramsize; 133 printf(": %s, %d x %d", getpropstring(node, "model"), 134 sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); 135 136 /* 137 * Dunno what the PROM has mapped, though obviously it must have 138 * the video RAM mapped. Just map what we care about for ourselves 139 * (the FHC, THC, and Brooktree registers). 140 */ 141 sc->sc_physadr = p = (struct cg6_layout *)sa->sa_ra.ra_paddr; 142 sc->sc_bt = bt = (volatile struct bt_regs *) 143 mapiodev((caddr_t)&p->cg6_bt_un.un_btregs, sizeof *sc->sc_bt); 144 sc->sc_fhc = (volatile int *) 145 mapiodev((caddr_t)&p->cg6_fhc_un.un_fhc, sizeof *sc->sc_fhc); 146 sc->sc_thc = (volatile struct cg6_thc *) 147 mapiodev((caddr_t)&p->cg6_thc_un.un_thc, sizeof *sc->sc_thc); 148 sc->sc_tec = (volatile struct cg6_tec_xxx *) 149 mapiodev((caddr_t)&p->cg6_tec_un.un_tec, sizeof *sc->sc_tec); 150 151 sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) & 152 (FHC_REV_MASK >> FHC_REV_SHIFT); 153 printf(", rev %d", sc->sc_fhcrev); 154 155 /* reset cursor & frame buffer controls */ 156 cg6_reset(sc); 157 158 /* grab initial (current) color map (DOES THIS WORK?) */ 159 bt->bt_addr = 0; 160 for (i = 0; i < 256 * 3; i++) 161 ((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24; 162 163 /* enable video */ 164 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 165 166 printf("\n"); 167 sbus_establish(&sc->sc_sd, &sc->sc_dev); 168 if (node == fbnode) 169 fb_attach(&sc->sc_fb); 170 } 171 172 int 173 cgsixopen(dev, flags, mode, p) 174 dev_t dev; 175 int flags, mode; 176 struct proc *p; 177 { 178 int unit = minor(dev); 179 180 if (unit >= cgsixcd.cd_ndevs || cgsixcd.cd_devs[unit] == NULL) 181 return (ENXIO); 182 return (0); 183 } 184 185 int 186 cgsixclose(dev, flags, mode, p) 187 dev_t dev; 188 int flags, mode; 189 struct proc *p; 190 { 191 struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; 192 193 cg6_reset(sc); 194 return (0); 195 } 196 197 int 198 cgsixioctl(dev, cmd, data, flags, p) 199 dev_t dev; 200 int cmd; 201 register caddr_t data; 202 int flags; 203 struct proc *p; 204 { 205 register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; 206 u_int count; 207 int i, v, error; 208 union cursor_cmap tcm; 209 210 switch (cmd) { 211 212 case FBIOGTYPE: 213 *(struct fbtype *)data = sc->sc_fb.fb_type; 214 break; 215 216 case FBIOGATTR: 217 #define fba ((struct fbgattr *)data) 218 fba->real_type = sc->sc_fb.fb_type.fb_type; 219 fba->owner = 0; /* XXX ??? */ 220 fba->fbtype = sc->sc_fb.fb_type; 221 fba->sattr.flags = 0; 222 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 223 fba->sattr.dev_specific[0] = -1; 224 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 225 fba->emu_types[1] = -1; 226 #undef fba 227 break; 228 229 case FBIOGETCMAP: 230 return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); 231 232 case FBIOPUTCMAP: 233 /* copy to software map */ 234 #define p ((struct fbcmap *)data) 235 error = bt_putcmap(p, &sc->sc_cmap, 256); 236 if (error) 237 return (error); 238 /* now blast them into the chip */ 239 /* XXX should use retrace interrupt */ 240 cg6_loadcmap(sc, p->index, p->count); 241 #undef p 242 break; 243 244 case FBIOGVIDEO: 245 *(int *)data = sc->sc_blanked; 246 break; 247 248 case FBIOSVIDEO: 249 if (*(int *)data) 250 cg6_unblank(&sc->sc_dev); 251 else if (!sc->sc_blanked) { 252 sc->sc_blanked = 1; 253 sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN; 254 } 255 break; 256 257 /* these are for both FBIOSCURSOR and FBIOGCURSOR */ 258 #define p ((struct fbcursor *)data) 259 #define cc (&sc->sc_cursor) 260 261 case FBIOGCURSOR: 262 /* do not quite want everything here... */ 263 p->set = FB_CUR_SETALL; /* close enough, anyway */ 264 p->enable = cc->cc_enable; 265 p->pos = cc->cc_pos; 266 p->hot = cc->cc_hot; 267 p->size = cc->cc_size; 268 269 /* begin ugh ... can we lose some of this crap?? */ 270 if (p->image != NULL) { 271 count = cc->cc_size.y * 32 / NBBY; 272 error = copyout((caddr_t)cc->cc_bits[1], 273 (caddr_t)p->image, count); 274 if (error) 275 return (error); 276 error = copyout((caddr_t)cc->cc_bits[0], 277 (caddr_t)p->mask, count); 278 if (error) 279 return (error); 280 } 281 if (p->cmap.red != NULL) { 282 error = bt_getcmap(&p->cmap, 283 (union bt_cmap *)&cc->cc_color, 2); 284 if (error) 285 return (error); 286 } else { 287 p->cmap.index = 0; 288 p->cmap.count = 2; 289 } 290 /* end ugh */ 291 break; 292 293 case FBIOSCURSOR: 294 /* 295 * For setcmap and setshape, verify parameters, so that 296 * we do not get halfway through an update and then crap 297 * out with the software state screwed up. 298 */ 299 v = p->set; 300 if (v & FB_CUR_SETCMAP) { 301 /* 302 * This use of a temporary copy of the cursor 303 * colormap is not terribly efficient, but these 304 * copies are small (8 bytes)... 305 */ 306 tcm = cc->cc_color; 307 error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2); 308 if (error) 309 return (error); 310 } 311 if (v & FB_CUR_SETSHAPE) { 312 if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32) 313 return (EINVAL); 314 count = p->size.y * 32 / NBBY; 315 if (!useracc(p->image, count, B_READ) || 316 !useracc(p->mask, count, B_READ)) 317 return (EFAULT); 318 } 319 320 /* parameters are OK; do it */ 321 if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) { 322 if (v & FB_CUR_SETCUR) 323 cc->cc_enable = p->enable; 324 if (v & FB_CUR_SETPOS) 325 cc->cc_pos = p->pos; 326 if (v & FB_CUR_SETHOT) 327 cc->cc_hot = p->hot; 328 cg6_setcursor(sc); 329 } 330 if (v & FB_CUR_SETCMAP) { 331 cc->cc_color = tcm; 332 cg6_loadomap(sc); /* XXX defer to vertical retrace */ 333 } 334 if (v & FB_CUR_SETSHAPE) { 335 cc->cc_size = p->size; 336 count = p->size.y * 32 / NBBY; 337 bzero((caddr_t)cc->cc_bits, sizeof cc->cc_bits); 338 bcopy(p->mask, (caddr_t)cc->cc_bits[0], count); 339 bcopy(p->image, (caddr_t)cc->cc_bits[1], count); 340 cg6_loadcursor(sc); 341 } 342 break; 343 344 #undef p 345 #undef cc 346 347 case FBIOGCURPOS: 348 *(struct fbcurpos *)data = sc->sc_cursor.cc_pos; 349 break; 350 351 case FBIOSCURPOS: 352 sc->sc_cursor.cc_pos = *(struct fbcurpos *)data; 353 cg6_setcursor(sc); 354 break; 355 356 case FBIOGCURMAX: 357 /* max cursor size is 32x32 */ 358 ((struct fbcurpos *)data)->x = 32; 359 ((struct fbcurpos *)data)->y = 32; 360 break; 361 362 default: 363 #ifdef DEBUG 364 log(LOG_NOTICE, "cgsixioctl(%x) (%s[%d])\n", cmd, 365 p->p_comm, p->p_pid); 366 #endif 367 return (ENOTTY); 368 } 369 return (0); 370 } 371 372 /* 373 * Clean up hardware state (e.g., after bootup or after X crashes). 374 */ 375 static void 376 cg6_reset(sc) 377 register struct cgsix_softc *sc; 378 { 379 register volatile struct cg6_tec_xxx *tec; 380 register int fhc; 381 register volatile struct bt_regs *bt; 382 383 /* hide the cursor, just in case */ 384 sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF; 385 386 /* turn off frobs in transform engine (makes X11 work) */ 387 tec = sc->sc_tec; 388 tec->tec_mv = 0; 389 tec->tec_clip = 0; 390 tec->tec_vdc = 0; 391 392 /* take care of hardware bugs in old revisions */ 393 if (sc->sc_fhcrev < 5) { 394 /* 395 * Keep current resolution; set cpu to 68020, set test 396 * window (size 1Kx1K), and for rev 1, disable dest cache. 397 */ 398 fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 | 399 FHC_TEST | 400 (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT); 401 if (sc->sc_fhcrev < 2) 402 fhc |= FHC_DST_DISABLE; 403 *sc->sc_fhc = fhc; 404 } 405 406 /* Enable cursor in Brooktree DAC. */ 407 bt = sc->sc_bt; 408 bt->bt_addr = 0x06 << 24; 409 bt->bt_ctrl |= 0x03 << 24; 410 } 411 412 static void 413 cg6_setcursor(sc) 414 register struct cgsix_softc *sc; 415 { 416 417 /* we need to subtract the hot-spot value here */ 418 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f) 419 sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ? 420 ((COORD(x) << 16) | (COORD(y) & 0xffff)) : 421 (THC_CURSOFF << 16) | THC_CURSOFF; 422 #undef COORD 423 } 424 425 static void 426 cg6_loadcursor(sc) 427 register struct cgsix_softc *sc; 428 { 429 register volatile struct cg6_thc *thc; 430 register u_int edgemask, m; 431 register int i; 432 433 /* 434 * Keep the top size.x bits. Here we *throw out* the top 435 * size.x bits from an all-one-bits word, introducing zeros in 436 * the top size.x bits, then invert all the bits to get what 437 * we really wanted as our mask. But this fails if size.x is 438 * 32---a sparc uses only the low 5 bits of the shift count--- 439 * so we have to special case that. 440 */ 441 edgemask = ~0; 442 if (sc->sc_cursor.cc_size.x < 32) 443 edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x); 444 thc = sc->sc_thc; 445 for (i = 0; i < 32; i++) { 446 m = sc->sc_cursor.cc_bits[0][i] & edgemask; 447 thc->thc_cursmask[i] = m; 448 thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i]; 449 } 450 } 451 452 /* 453 * Load a subset of the current (new) colormap into the color DAC. 454 */ 455 static void 456 cg6_loadcmap(sc, start, ncolors) 457 register struct cgsix_softc *sc; 458 register int start, ncolors; 459 { 460 register volatile struct bt_regs *bt; 461 register u_int *ip, i; 462 register int count; 463 464 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ 465 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 466 bt = sc->sc_bt; 467 bt->bt_addr = BT_D4M4(start) << 24; 468 while (--count >= 0) { 469 i = *ip++; 470 /* hardware that makes one want to pound boards with hammers */ 471 bt->bt_cmap = i; 472 bt->bt_cmap = i << 8; 473 bt->bt_cmap = i << 16; 474 bt->bt_cmap = i << 24; 475 } 476 } 477 478 /* 479 * Load the cursor (overlay `foreground' and `background') colors. 480 */ 481 static void 482 cg6_loadomap(sc) 483 register struct cgsix_softc *sc; 484 { 485 register volatile struct bt_regs *bt; 486 register u_int i; 487 488 bt = sc->sc_bt; 489 bt->bt_addr = 0x01 << 24; /* set background color */ 490 i = sc->sc_cursor.cc_color.cm_chip[0]; 491 bt->bt_omap = i; /* R */ 492 bt->bt_omap = i << 8; /* G */ 493 bt->bt_omap = i << 16; /* B */ 494 495 bt->bt_addr = 0x03 << 24; /* set foreground color */ 496 bt->bt_omap = i << 24; /* R */ 497 i = sc->sc_cursor.cc_color.cm_chip[1]; 498 bt->bt_omap = i; /* G */ 499 bt->bt_omap = i << 8; /* B */ 500 } 501 502 static void 503 cg6_unblank(dev) 504 struct device *dev; 505 { 506 struct cgsix_softc *sc = (struct cgsix_softc *)dev; 507 508 if (sc->sc_blanked) { 509 sc->sc_blanked = 0; 510 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 511 } 512 } 513 514 /* XXX the following should be moved to a "user interface" header */ 515 /* 516 * Base addresses at which users can mmap() the various pieces of a cg6. 517 * Note that although the Brooktree color registers do not occupy 8K, 518 * the X server dies if we do not allow it to map 8K there (it just maps 519 * from 0x70000000 forwards, as a contiguous chunk). 520 */ 521 #define CG6_USER_FBC 0x70000000 522 #define CG6_USER_TEC 0x70001000 523 #define CG6_USER_BTREGS 0x70002000 524 #define CG6_USER_FHC 0x70004000 525 #define CG6_USER_THC 0x70005000 526 #define CG6_USER_ROM 0x70006000 527 #define CG6_USER_RAM 0x70016000 528 #define CG6_USER_DHC 0x80000000 529 530 struct mmo { 531 u_int mo_uaddr; /* user (virtual) address */ 532 u_int mo_size; /* size, or 0 for video ram size */ 533 u_int mo_physoff; /* offset from sc_physadr */ 534 }; 535 536 /* 537 * Return the address that would map the given device at the given 538 * offset, allowing for the given protection, or return -1 for error. 539 * 540 * XXX needs testing against `demanding' applications (e.g., aviator) 541 */ 542 int 543 cgsixmap(dev, off, prot) 544 dev_t dev; 545 int off, prot; 546 { 547 register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; 548 register struct mmo *mo; 549 register u_int u, sz; 550 #define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb)) 551 static struct mmo mmo[] = { 552 { CG6_USER_RAM, 0, O(cg6_ram) }, 553 554 /* do not actually know how big most of these are! */ 555 { CG6_USER_FBC, 1, O(cg6_fbc_un) }, 556 { CG6_USER_TEC, 1, O(cg6_tec_un) }, 557 { CG6_USER_BTREGS, 8192 /* XXX */, O(cg6_bt_un) }, 558 { CG6_USER_FHC, 1, O(cg6_fhc_un) }, 559 { CG6_USER_THC, sizeof(struct cg6_thc), O(cg6_thc_un) }, 560 { CG6_USER_ROM, 65536, O(cg6_rom_un) }, 561 { CG6_USER_DHC, 1, O(cg6_dhc_un) }, 562 }; 563 #define NMMO (sizeof mmo / sizeof *mmo) 564 565 if (off & PGOFSET) 566 panic("cgsixmap"); 567 568 /* 569 * Entries with size 0 map video RAM (i.e., the size in fb data). 570 * 571 * Since we work in pages, the fact that the map offset table's 572 * sizes are sometimes bizarre (e.g., 1) is effectively ignored: 573 * one byte is as good as one page. 574 */ 575 for (mo = mmo; mo < &mmo[NMMO]; mo++) { 576 if ((u_int)off < mo->mo_uaddr) 577 continue; 578 u = off - mo->mo_uaddr; 579 sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size; 580 if (u < sz) 581 return ((int)sc->sc_physadr + u + mo->mo_physoff + 582 PMAP_OBIO + PMAP_NC); 583 } 584 #ifdef DEBUG 585 { 586 register struct proc *p = curproc; /* XXX */ 587 log(LOG_NOTICE, "cgsixmap(%x) (%s[%d])\n", off, p->p_comm, p->p_pid); 588 } 589 #endif 590 return (-1); /* not a user-map offset */ 591 } 592