1 /* 2 * Copyright (c) 1993 The Regents of the University of California. 3 * 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.1 (Berkeley) 10/30/93 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 struct cg6_thc *sc_thc; /* THC registers */ 74 int sc_blanked; /* true if blanked */ 75 struct cg6_cursor sc_cursor; /* software cursor info */ 76 union bt_cmap sc_cmap; /* Brooktree color map */ 77 }; 78 79 /* autoconfiguration driver */ 80 static void cgsixattach(struct device *, struct device *, void *); 81 struct cfdriver cgsixcd = 82 { NULL, "cgsix", matchbyname, cgsixattach, 83 DV_DULL, sizeof(struct cgsix_softc) }; 84 85 /* frame buffer generic driver */ 86 static void cg6_unblank(struct device *); 87 static struct fbdriver cg6_fbdriver = { cg6_unblank }; 88 89 /* 90 * Unlike the bw2 and cg3 drivers, we do not need to provide an rconsole 91 * interface, as the cg6 is fast enough. 92 */ 93 94 extern int fbnode; 95 96 #define CGSIX_MAJOR 67 /* XXX */ 97 98 static void cg6_loadcmap __P((struct cgsix_softc *, int, int)); 99 static void cg6_loadomap __P((struct cgsix_softc *)); 100 static void cg6_setcursor __P((struct cgsix_softc *));/* set position */ 101 static void cg6_loadcursor __P((struct cgsix_softc *));/* set shape */ 102 103 /* 104 * Attach a display. 105 */ 106 void 107 cgsixattach(parent, self, args) 108 struct device *parent, *self; 109 void *args; 110 { 111 register struct cgsix_softc *sc = (struct cgsix_softc *)self; 112 register struct sbus_attach_args *sa = args; 113 register int node = sa->sa_ra.ra_node, ramsize, i; 114 register volatile struct bt_regs *bt; 115 register volatile struct cg6_layout *p; 116 117 sc->sc_fb.fb_major = CGSIX_MAJOR; /* XXX to be removed */ 118 119 sc->sc_fb.fb_driver = &cg6_fbdriver; 120 sc->sc_fb.fb_device = &sc->sc_dev; 121 sc->sc_fb.fb_type.fb_type = FBTYPE_SUNFAST_COLOR; 122 sc->sc_fb.fb_type.fb_width = getpropint(node, "width", 1152); 123 sc->sc_fb.fb_type.fb_height = getpropint(node, "height", 900); 124 sc->sc_fb.fb_linebytes = getpropint(node, "linebytes", 1152); 125 ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes; 126 sc->sc_fb.fb_type.fb_depth = 8; 127 sc->sc_fb.fb_type.fb_cmsize = 256; 128 sc->sc_fb.fb_type.fb_size = ramsize; 129 printf(": %s, %d x %d", getpropstring(node, "model"), 130 sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); 131 132 /* 133 * Dunno what the PROM has mapped, though obviously it must have 134 * the video RAM mapped. Just map what we care about for ourselves 135 * (the THC and Brooktree registers). 136 */ 137 sc->sc_physadr = p = (struct cg6_layout *)sa->sa_ra.ra_paddr; 138 sc->sc_bt = bt = (volatile struct bt_regs *) 139 mapiodev((caddr_t)&p->cg6_bt_un.un_btregs, sizeof(struct bt_regs)); 140 sc->sc_thc = (volatile struct cg6_thc *) 141 mapiodev((caddr_t)&p->cg6_thc_un.un_thc, sizeof(struct cg6_thc)); 142 143 /* grab initial (current) color map (DOES THIS WORK?) */ 144 bt->bt_addr = 0; 145 for (i = 0; i < 256 * 3; i++) 146 ((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24; 147 148 /* enable video */ 149 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 150 151 printf("\n"); 152 sbus_establish(&sc->sc_sd, &sc->sc_dev); 153 if (node == fbnode) 154 fb_attach(&sc->sc_fb); 155 } 156 157 int 158 cgsixopen(dev, flags, mode, p) 159 dev_t dev; 160 int flags, mode; 161 struct proc *p; 162 { 163 int unit = minor(dev); 164 165 if (unit >= cgsixcd.cd_ndevs || cgsixcd.cd_devs[unit] == NULL) 166 return (ENXIO); 167 return (0); 168 } 169 170 int 171 cgsixclose(dev, flags, mode, p) 172 dev_t dev; 173 int flags, mode; 174 struct proc *p; 175 { 176 177 return (0); 178 } 179 180 int 181 cgsixioctl(dev, cmd, data, flags, p) 182 dev_t dev; 183 int cmd; 184 register caddr_t data; 185 int flags; 186 struct proc *p; 187 { 188 register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; 189 u_int count; 190 int i, v, error; 191 union cursor_cmap tcm; 192 193 switch (cmd) { 194 195 case FBIOGTYPE: 196 *(struct fbtype *)data = sc->sc_fb.fb_type; 197 break; 198 199 case FBIOGATTR: 200 #define fba ((struct fbgattr *)data) 201 fba->real_type = sc->sc_fb.fb_type.fb_type; 202 fba->owner = 0; /* XXX ??? */ 203 fba->fbtype = sc->sc_fb.fb_type; 204 fba->sattr.flags = 0; 205 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 206 fba->sattr.dev_specific[0] = -1; 207 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 208 fba->emu_types[1] = -1; 209 #undef fba 210 break; 211 212 case FBIOGETCMAP: 213 return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); 214 215 case FBIOPUTCMAP: 216 /* copy to software map */ 217 #define p ((struct fbcmap *)data) 218 error = bt_putcmap(p, &sc->sc_cmap, 256); 219 if (error) 220 return (error); 221 /* now blast them into the chip */ 222 /* XXX should use retrace interrupt */ 223 cg6_loadcmap(sc, p->index, p->count); 224 #undef p 225 break; 226 227 case FBIOGVIDEO: 228 *(int *)data = sc->sc_blanked; 229 break; 230 231 case FBIOSVIDEO: 232 if (*(int *)data) 233 cg6_unblank(&sc->sc_dev); 234 else if (!sc->sc_blanked) { 235 sc->sc_blanked = 1; 236 sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN; 237 } 238 break; 239 240 /* these are for both FBIOSCURSOR and FBIOGCURSOR */ 241 #define p ((struct fbcursor *)data) 242 #define cc (&sc->sc_cursor) 243 244 case FBIOGCURSOR: 245 /* do not quite want everything here... */ 246 p->set = FB_CUR_SETALL; /* close enough, anyway */ 247 p->enable = cc->cc_enable; 248 p->pos = cc->cc_pos; 249 p->hot = cc->cc_hot; 250 p->size = cc->cc_size; 251 252 /* begin ugh ... can we lose some of this crap?? */ 253 if (p->image != NULL) { 254 count = cc->cc_size.y * 32 / NBBY; 255 error = copyout((caddr_t)cc->cc_bits[1], 256 (caddr_t)p->image, count); 257 if (error) 258 return (error); 259 error = copyout((caddr_t)cc->cc_bits[0], 260 (caddr_t)p->mask, count); 261 if (error) 262 return (error); 263 } 264 if (p->cmap.red != NULL) { 265 error = bt_getcmap(&p->cmap, 266 (union bt_cmap *)&cc->cc_color, 2); 267 if (error) 268 return (error); 269 } else { 270 p->cmap.index = 0; 271 p->cmap.count = 2; 272 } 273 /* end ugh */ 274 break; 275 276 case FBIOSCURSOR: 277 /* 278 * For setcmap and setshape, verify parameters, so that 279 * we do not get halfway through an update and then crap 280 * out with the software state screwed up. 281 */ 282 v = p->set; 283 if (v & FB_CUR_SETCMAP) { 284 /* 285 * This use of a temporary copy of the cursor 286 * colormap is not terribly efficient, but these 287 * copies are small (8 bytes)... 288 */ 289 tcm = cc->cc_color; 290 error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2); 291 if (error) 292 return (error); 293 } 294 if (v & FB_CUR_SETSHAPE) { 295 if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32) 296 return (EINVAL); 297 count = p->size.y * 32 / NBBY; 298 if (!useracc(p->image, count, B_READ) || 299 !useracc(p->mask, count, B_READ)) 300 return (EFAULT); 301 } 302 303 /* parameters are OK; do it */ 304 if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) { 305 if (v & FB_CUR_SETCUR) 306 cc->cc_enable = p->enable; 307 if (v & FB_CUR_SETPOS) 308 cc->cc_pos = p->pos; 309 if (v & FB_CUR_SETHOT) 310 cc->cc_hot = p->hot; 311 cg6_setcursor(sc); 312 } 313 if (v & FB_CUR_SETCMAP) { 314 cc->cc_color = tcm; 315 cg6_loadomap(sc); /* XXX defer to vertical retrace */ 316 } 317 if (v & FB_CUR_SETSHAPE) { 318 cc->cc_size = p->size; 319 count = p->size.y * 32 / NBBY; 320 bzero((caddr_t)cc->cc_bits, sizeof cc->cc_bits); 321 bcopy(p->mask, (caddr_t)cc->cc_bits[0], count); 322 bcopy(p->image, (caddr_t)cc->cc_bits[1], count); 323 cg6_loadcursor(sc); 324 } 325 break; 326 327 #undef p 328 #undef cc 329 330 case FBIOGCURPOS: 331 *(struct fbcurpos *)data = sc->sc_cursor.cc_pos; 332 break; 333 334 case FBIOSCURPOS: 335 sc->sc_cursor.cc_pos = *(struct fbcurpos *)data; 336 cg6_setcursor(sc); 337 break; 338 339 case FBIOGCURMAX: 340 /* max cursor size is 32x32 */ 341 ((struct fbcurpos *)data)->x = 32; 342 ((struct fbcurpos *)data)->y = 32; 343 break; 344 345 default: 346 #ifdef DEBUG 347 log(LOG_NOTICE, "cgsixioctl(%x) (%s[%d])\n", cmd, 348 p->p_comm, p->p_pid); 349 #endif 350 return (ENOTTY); 351 } 352 return (0); 353 } 354 355 static void 356 cg6_setcursor(sc) 357 register struct cgsix_softc *sc; 358 { 359 360 /* we need to subtract the hot-spot value here */ 361 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f) 362 sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ? 363 ((COORD(x) << 16) | (COORD(y) & 0xffff)) : 364 (THC_CURSOFF << 16) | THC_CURSOFF; 365 #undef COORD 366 } 367 368 static void 369 cg6_loadcursor(sc) 370 register struct cgsix_softc *sc; 371 { 372 register volatile struct cg6_thc *thc; 373 register u_int edgemask, m; 374 register int i; 375 376 /* 377 * Keep the top size.x bits. Here we *throw out* the top 378 * size.x bits from an all-one-bits word, introducing zeros in 379 * the top size.x bits, then invert all the bits to get what 380 * we really wanted as our mask. But this fails if size.x is 381 * 32---a sparc uses only the low 5 bits of the shift count--- 382 * so we have to special case that. 383 */ 384 edgemask = ~0; 385 if (sc->sc_cursor.cc_size.x < 32) 386 edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x); 387 thc = sc->sc_thc; 388 for (i = 0; i < 32; i++) { 389 m = sc->sc_cursor.cc_bits[0][i] & edgemask; 390 thc->thc_cursmask[i] = m; 391 thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i]; 392 } 393 } 394 395 /* 396 * Load a subset of the current (new) colormap into the color DAC. 397 */ 398 static void 399 cg6_loadcmap(sc, start, ncolors) 400 register struct cgsix_softc *sc; 401 register int start, ncolors; 402 { 403 register volatile struct bt_regs *bt; 404 register u_int *ip, i; 405 register int count; 406 407 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ 408 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 409 bt = sc->sc_bt; 410 bt->bt_addr = BT_D4M4(start) << 24; 411 while (--count >= 0) { 412 i = *ip++; 413 /* hardware that makes one want to pound boards with hammers */ 414 bt->bt_cmap = i; 415 bt->bt_cmap = i << 8; 416 bt->bt_cmap = i << 16; 417 bt->bt_cmap = i << 24; 418 } 419 } 420 421 /* 422 * Load the cursor (overlay `foreground' and `background') colors. 423 */ 424 static void 425 cg6_loadomap(sc) 426 register struct cgsix_softc *sc; 427 { 428 register volatile struct bt_regs *bt; 429 register u_int i; 430 431 bt = sc->sc_bt; 432 bt->bt_addr = 0x01 << 24; /* set background color */ 433 i = sc->sc_cursor.cc_color.cm_chip[0]; 434 bt->bt_omap = i; /* R */ 435 bt->bt_omap = i << 8; /* G */ 436 bt->bt_omap = i << 16; /* B */ 437 438 bt->bt_addr = 0x03 << 24; /* set foreground color */ 439 bt->bt_omap = i << 24; /* R */ 440 i = sc->sc_cursor.cc_color.cm_chip[1]; 441 bt->bt_omap = i; /* G */ 442 bt->bt_omap = i << 8; /* B */ 443 } 444 445 static void 446 cg6_unblank(dev) 447 struct device *dev; 448 { 449 struct cgsix_softc *sc = (struct cgsix_softc *)dev; 450 451 if (sc->sc_blanked) { 452 sc->sc_blanked = 0; 453 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 454 } 455 } 456 457 /* XXX the following should be moved to a "user interface" header */ 458 /* 459 * Base addresses at which users can mmap() the various pieces of a cg6. 460 * Note that although the Brooktree color registers do not occupy 8K, 461 * the X server dies if we do not allow it to map 8K there (it just maps 462 * from 0x70000000 forwards, as a contiguous chunk). 463 */ 464 #define CG6_USER_FBC 0x70000000 465 #define CG6_USER_TEC 0x70001000 466 #define CG6_USER_BTREGS 0x70002000 467 #define CG6_USER_FHC 0x70004000 468 #define CG6_USER_THC 0x70005000 469 #define CG6_USER_ROM 0x70006000 470 #define CG6_USER_RAM 0x70016000 471 #define CG6_USER_DHC 0x80000000 472 473 struct mmo { 474 u_int mo_uaddr; /* user (virtual) address */ 475 u_int mo_size; /* size, or 0 for video ram size */ 476 u_int mo_physoff; /* offset from sc_physadr */ 477 }; 478 479 /* 480 * Return the address that would map the given device at the given 481 * offset, allowing for the given protection, or return -1 for error. 482 * 483 * XXX needs testing against `demanding' applications (e.g., aviator) 484 */ 485 int 486 cgsixmap(dev, off, prot) 487 dev_t dev; 488 int off, prot; 489 { 490 register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; 491 register struct mmo *mo; 492 register u_int u, sz; 493 #define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb)) 494 static struct mmo mmo[] = { 495 { CG6_USER_RAM, 0, O(cg6_ram) }, 496 497 /* do not actually know how big most of these are! */ 498 { CG6_USER_FBC, 1, O(cg6_fbc_un) }, 499 { CG6_USER_TEC, 1, O(cg6_tec_un) }, 500 { CG6_USER_BTREGS, 8192 /* XXX */, O(cg6_bt_un) }, 501 { CG6_USER_FHC, 1, O(cg6_fhc_un) }, 502 { CG6_USER_THC, sizeof(struct cg6_thc), O(cg6_thc_un) }, 503 { CG6_USER_ROM, 65536, O(cg6_rom_un) }, 504 { CG6_USER_DHC, 1, O(cg6_dhc_un) }, 505 }; 506 #define NMMO (sizeof mmo / sizeof *mmo) 507 508 if (off & PGOFSET) 509 panic("cgsixmap"); 510 511 /* 512 * Entries with size 0 map video RAM (i.e., the size in fb data). 513 * 514 * Since we work in pages, the fact that the map offset table's 515 * sizes are sometimes bizarre (e.g., 1) is effectively ignored: 516 * one byte is as good as one page. 517 */ 518 for (mo = mmo; mo < &mmo[NMMO]; mo++) { 519 if ((u_int)off < mo->mo_uaddr) 520 continue; 521 u = off - mo->mo_uaddr; 522 sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size; 523 if (u < sz) 524 return ((int)sc->sc_physadr + u + mo->mo_physoff + 525 PMAP_OBIO + PMAP_NC); 526 } 527 #ifdef DEBUG 528 { 529 register struct proc *p = curproc; /* XXX */ 530 log(LOG_NOTICE, "cgsixmap(%x) (%s[%d])\n", off, p->p_comm, p->p_pid); 531 } 532 #endif 533 return (-1); /* not a user-map offset */ 534 } 535