1 /* $NetBSD: cg4.c,v 1.11 1996/10/29 19:54:19 gwr Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * from: @(#)cgthree.c 8.2 (Berkeley) 10/30/93 45 */ 46 47 /* 48 * color display (cg4) driver. 49 * 50 * Credits, history: 51 * Gordon Ross created this driver based on the cg3 driver from 52 * the sparc port as distributed in BSD 4.4 Lite, but included 53 * support for only the "type B" adapter (Brooktree DACs). 54 * Ezra Story added support for the "type A" (AMD DACs). 55 * 56 * Todo: 57 * Make this driver handle video interrupts. 58 * Defer colormap updates to vertical retrace interrupts. 59 */ 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/device.h> 64 #include <sys/ioctl.h> 65 #include <sys/malloc.h> 66 #include <sys/mman.h> 67 #include <sys/tty.h> 68 69 #include <vm/vm.h> 70 71 #include <machine/cpu.h> 72 #include <machine/fbio.h> 73 #include <machine/autoconf.h> 74 #include <machine/pmap.h> 75 76 #include "fbvar.h" 77 #include "btreg.h" 78 #include "btvar.h" 79 #include "cg4reg.h" 80 81 #define CG4_MMAP_SIZE (CG4_OVERLAY_SIZE + CG4_ENABLE_SIZE + CG4_PIXMAP_SIZE) 82 83 extern unsigned char cpu_machine_id; 84 85 #define CMAP_SIZE 256 86 struct soft_cmap { 87 u_char r[CMAP_SIZE]; 88 u_char g[CMAP_SIZE]; 89 u_char b[CMAP_SIZE]; 90 }; 91 92 /* per-display variables */ 93 struct cg4_softc { 94 struct device sc_dev; /* base device */ 95 struct fbdevice sc_fb; /* frame buffer device */ 96 int sc_cg4type; /* A or B */ 97 void *sc_va_cmap; /* Colormap h/w (mapped KVA) */ 98 int sc_pa_overlay; /* phys. addr. of overlay plane */ 99 int sc_pa_enable; /* phys. addr. of enable plane */ 100 int sc_pa_pixmap; /* phys. addr. of color plane */ 101 int sc_blanked; /* true if blanked */ 102 103 union bt_cmap *sc_btcm; /* Brooktree color map */ 104 struct soft_cmap sc_cmap; /* Generic soft colormap. */ 105 }; 106 107 /* autoconfiguration driver */ 108 static void cg4attach __P((struct device *, struct device *, void *)); 109 static int cg4match __P((struct device *, void *, void *)); 110 111 struct cfattach cgfour_ca = { 112 sizeof(struct cg4_softc), cg4match, cg4attach 113 }; 114 115 struct cfdriver cgfour_cd = { 116 NULL, "cgfour", DV_DULL 117 }; 118 119 /* frame buffer generic driver */ 120 int cg4open(), cg4close(), cg4mmap(); 121 122 static int cg4gattr __P((struct fbdevice *, struct fbgattr *)); 123 static int cg4gvideo __P((struct fbdevice *, int *)); 124 static int cg4svideo __P((struct fbdevice *, int *)); 125 static int cg4getcmap __P((struct fbdevice *, struct fbcmap *)); 126 static int cg4putcmap __P((struct fbdevice *, struct fbcmap *)); 127 128 static void cg4a_init __P((struct cg4_softc *)); 129 static void cg4a_svideo __P((struct cg4_softc *, int)); 130 static void cg4a_ldcmap __P((struct cg4_softc *)); 131 132 static void cg4b_init __P((struct cg4_softc *)); 133 static void cg4b_svideo __P((struct cg4_softc *, int)); 134 static void cg4b_ldcmap __P((struct cg4_softc *)); 135 136 static struct fbdriver cg4_fbdriver = { 137 cg4open, cg4close, cg4mmap, cg4gattr, 138 cg4gvideo, cg4svideo, 139 cg4getcmap, cg4putcmap }; 140 141 /* 142 * Match a cg4. 143 */ 144 static int 145 cg4match(parent, vcf, args) 146 struct device *parent; 147 void *vcf, *args; 148 { 149 struct confargs *ca = args; 150 int paddr; 151 152 /* XXX: Huge hack due to lack of probe info... */ 153 /* XXX: Machines that might have a cg4 (gag). */ 154 /* XXX: Need info on the "P4" register... */ 155 switch (cpu_machine_id) { 156 157 case SUN3_MACH_110: 158 /* XXX: Assume type A. */ 159 if (ca->ca_paddr == -1) 160 ca->ca_paddr = CG4A_DEF_BASE; 161 if (bus_peek(ca->ca_bustype, ca->ca_paddr, 1) == -1) 162 return (0); 163 if (bus_peek(BUS_OBIO, CG4A_OBIO_CMAP, 1) == -1) 164 return (0); 165 break; 166 167 case SUN3_MACH_60: 168 /* XXX: Assume type A. */ 169 if (ca->ca_paddr == -1) 170 ca->ca_paddr = CG4B_DEF_BASE; 171 paddr = ca->ca_paddr; 172 if (bus_peek(ca->ca_bustype, paddr, 1) == -1) 173 return (0); 174 /* Make sure we're color */ 175 paddr += CG4B_OFF_PIXMAP; 176 if (bus_peek(ca->ca_bustype, paddr, 1) == -1) 177 return (0); 178 break; 179 180 default: 181 return (0); 182 } 183 184 return (1); 185 } 186 187 /* 188 * Attach a display. We need to notice if it is the console, too. 189 */ 190 static void 191 cg4attach(parent, self, args) 192 struct device *parent, *self; 193 void *args; 194 { 195 struct cg4_softc *sc = (struct cg4_softc *)self; 196 struct fbdevice *fb = &sc->sc_fb; 197 struct confargs *ca = args; 198 struct fbtype *fbt; 199 200 /* XXX: should do better than this... */ 201 switch (cpu_machine_id) { 202 case SUN3_MACH_110: 203 sc->sc_cg4type = CG4_TYPE_A; 204 break; 205 case SUN3_MACH_60: 206 default: 207 sc->sc_cg4type = CG4_TYPE_B; 208 } 209 210 fb->fb_driver = &cg4_fbdriver; 211 fb->fb_private = sc; 212 fb->fb_name = sc->sc_dev.dv_xname; 213 214 fbt = &fb->fb_fbtype; 215 fbt->fb_type = FBTYPE_SUN4COLOR; 216 fbt->fb_depth = 8; 217 fbt->fb_cmsize = 256; 218 219 fbt->fb_width = 1152; 220 fbt->fb_height = 900; 221 fbt->fb_size = CG4_MMAP_SIZE; 222 223 switch (sc->sc_cg4type) { 224 case CG4_TYPE_A: /* Sun3/110 */ 225 sc->sc_va_cmap = bus_mapin(BUS_OBIO, CG4A_OBIO_CMAP, 226 sizeof(struct amd_regs)); 227 sc->sc_pa_overlay = ca->ca_paddr + CG4A_OFF_OVERLAY; 228 sc->sc_pa_enable = ca->ca_paddr + CG4A_OFF_ENABLE; 229 sc->sc_pa_pixmap = ca->ca_paddr + CG4A_OFF_PIXMAP; 230 sc->sc_btcm = NULL; 231 cg4a_init(sc); 232 break; 233 234 case CG4_TYPE_B: /* Sun3/60 */ 235 default: 236 sc->sc_va_cmap = (struct bt_regs *) 237 bus_mapin(ca->ca_bustype, ca->ca_paddr, 238 sizeof(struct bt_regs *)); 239 sc->sc_pa_overlay = ca->ca_paddr + CG4B_OFF_OVERLAY; 240 sc->sc_pa_enable = ca->ca_paddr + CG4B_OFF_ENABLE; 241 sc->sc_pa_pixmap = ca->ca_paddr + CG4B_OFF_PIXMAP; 242 sc->sc_btcm = malloc(sizeof(union bt_cmap), M_DEVBUF, M_WAITOK); 243 cg4b_init(sc); 244 break; 245 } 246 247 printf(" (%dx%d)\n", fbt->fb_width, fbt->fb_height); 248 fb_attach(fb, 4); 249 } 250 251 int 252 cg4open(dev, flags, mode, p) 253 dev_t dev; 254 int flags, mode; 255 struct proc *p; 256 { 257 int unit = minor(dev); 258 259 if (unit >= cgfour_cd.cd_ndevs || cgfour_cd.cd_devs[unit] == NULL) 260 return (ENXIO); 261 return (0); 262 } 263 264 int 265 cg4close(dev, flags, mode, p) 266 dev_t dev; 267 int flags, mode; 268 struct proc *p; 269 { 270 271 return (0); 272 } 273 274 int 275 cg4ioctl(dev, cmd, data, flags, p) 276 dev_t dev; 277 u_long cmd; 278 caddr_t data; 279 int flags; 280 struct proc *p; 281 { 282 struct cg4_softc *sc = cgfour_cd.cd_devs[minor(dev)]; 283 284 return (fbioctlfb(&sc->sc_fb, cmd, data)); 285 } 286 287 /* 288 * Return the address that would map the given device at the given 289 * offset, allowing for the given protection, or return -1 for error. 290 * 291 * X11 expects its mmap'd region to look like this: 292 * 128k overlay data memory 293 * 128k overlay enable bitmap 294 * 1024k color memory 295 * 296 * The hardware really looks like this (starting at ca_paddr) 297 * 4 bytes Brooktree DAC registers 298 * 2MB-4 gap 299 * 128k overlay memory 300 * 1920k gap 301 * 128k overlay-enable bitmap 302 * 1920k gap 303 * 1024k color memory 304 */ 305 int 306 cg4mmap(dev, off, prot) 307 dev_t dev; 308 register int off; 309 int prot; 310 { 311 struct cg4_softc *sc = cgfour_cd.cd_devs[minor(dev)]; 312 register int physbase; 313 314 if (off & PGOFSET) 315 panic("cg4mmap"); 316 317 if ((unsigned)off >= CG4_MMAP_SIZE) 318 return (-1); 319 320 if (off < 0x40000) { 321 if (off < 0x20000) { 322 physbase = sc->sc_pa_overlay; 323 } else { 324 /* enable plane */ 325 off -= 0x20000; 326 physbase = sc->sc_pa_enable; 327 } 328 } else { 329 /* pixel map */ 330 off -= 0x40000; 331 physbase = sc->sc_pa_pixmap; 332 } 333 334 /* 335 * I turned on PMAP_NC here to disable the cache as I was 336 * getting horribly broken behaviour with it on. 337 */ 338 return ((physbase + off) | PMAP_NC); 339 } 340 341 /* 342 * Internal ioctl functions. 343 */ 344 345 /* FBIOGATTR: */ 346 static int cg4gattr(fb, fba) 347 struct fbdevice *fb; 348 struct fbgattr *fba; 349 { 350 351 fba->real_type = fb->fb_fbtype.fb_type; 352 fba->owner = 0; /* XXX - TIOCCONS stuff? */ 353 fba->fbtype = fb->fb_fbtype; 354 fba->sattr.flags = 0; 355 fba->sattr.emu_type = fb->fb_fbtype.fb_type; 356 fba->sattr.dev_specific[0] = -1; 357 fba->emu_types[0] = fb->fb_fbtype.fb_type; 358 fba->emu_types[1] = -1; 359 return (0); 360 } 361 362 /* FBIOGVIDEO: */ 363 static int cg4gvideo(fb, on) 364 struct fbdevice *fb; 365 int *on; 366 { 367 struct cg4_softc *sc = fb->fb_private; 368 369 *on = !sc->sc_blanked; 370 return (0); 371 } 372 373 /* FBIOSVIDEO: */ 374 static int cg4svideo(fb, on) 375 struct fbdevice *fb; 376 int *on; 377 { 378 struct cg4_softc *sc = fb->fb_private; 379 int state; 380 381 state = *on; 382 if (sc->sc_cg4type == CG4_TYPE_A) 383 cg4a_svideo(sc, state); 384 else 385 cg4b_svideo(sc, state); 386 return (0); 387 } 388 389 /* 390 * FBIOGETCMAP: 391 * Copy current colormap out to user space. 392 */ 393 static int cg4getcmap(fb, fbcm) 394 struct fbdevice *fb; 395 struct fbcmap *fbcm; 396 { 397 struct cg4_softc *sc = fb->fb_private; 398 struct soft_cmap *cm = &sc->sc_cmap; 399 int error, start, count; 400 401 start = fbcm->index; 402 count = fbcm->count; 403 if ((start < 0) || (start >= CMAP_SIZE) || 404 (count < 0) || (start + count > CMAP_SIZE) ) 405 return (EINVAL); 406 407 if ((error = copyout(&cm->r[start], fbcm->red, count)) != 0) 408 return (error); 409 410 if ((error = copyout(&cm->g[start], fbcm->green, count)) != 0) 411 return (error); 412 413 if ((error = copyout(&cm->b[start], fbcm->blue, count)) != 0) 414 return (error); 415 416 return (0); 417 } 418 419 /* 420 * FBIOPUTCMAP: 421 * Copy new colormap from user space and load. 422 */ 423 static int cg4putcmap(fb, fbcm) 424 struct fbdevice *fb; 425 struct fbcmap *fbcm; 426 { 427 struct cg4_softc *sc = fb->fb_private; 428 struct soft_cmap *cm = &sc->sc_cmap; 429 int error, start, count; 430 431 start = fbcm->index; 432 count = fbcm->count; 433 if ((start < 0) || (start >= CMAP_SIZE) || 434 (count < 0) || (start + count > CMAP_SIZE) ) 435 return (EINVAL); 436 437 if ((error = copyin(fbcm->red, &cm->r[start], count)) != 0) 438 return (error); 439 440 if ((error = copyin(fbcm->green, &cm->g[start], count)) != 0) 441 return (error); 442 443 if ((error = copyin(fbcm->blue, &cm->b[start], count)) != 0) 444 return (error); 445 446 if (sc->sc_cg4type == CG4_TYPE_A) 447 cg4a_ldcmap(sc); 448 else 449 cg4b_ldcmap(sc); 450 451 return (0); 452 } 453 454 /**************************************************************** 455 * Routines for the "Type A" hardware 456 ****************************************************************/ 457 458 static void 459 cg4a_init(sc) 460 struct cg4_softc *sc; 461 { 462 volatile struct amd_regs *ar = sc->sc_va_cmap; 463 struct soft_cmap *cm = &sc->sc_cmap; 464 int i; 465 466 /* grab initial (current) color map */ 467 for(i = 0; i < 256; i++) { 468 cm->r[i] = ar->r[i]; 469 cm->g[i] = ar->g[i]; 470 cm->b[i] = ar->b[i]; 471 } 472 } 473 474 static void 475 cg4a_ldcmap(sc) 476 struct cg4_softc *sc; 477 { 478 volatile struct amd_regs *ar = sc->sc_va_cmap; 479 struct soft_cmap *cm = &sc->sc_cmap; 480 int i; 481 482 /* 483 * Now blast them into the chip! 484 * XXX Should use retrace interrupt! 485 * Just set a "need load" bit and let the 486 * retrace interrupt handler do the work. 487 */ 488 for(i = 0; i < 256; i++) { 489 ar->r[i] = cm->r[i]; 490 ar->g[i] = cm->g[i]; 491 ar->b[i] = cm->b[i]; 492 } 493 } 494 495 static void 496 cg4a_svideo(sc, on) 497 struct cg4_softc *sc; 498 int on; 499 { 500 volatile struct amd_regs *ar = sc->sc_va_cmap; 501 int i; 502 503 if ((on == 0) && (sc->sc_blanked == 0)) { 504 /* Turn OFF video (make it blank). */ 505 sc->sc_blanked = 1; 506 /* Load fake "all zero" colormap. */ 507 for (i = 0; i < 256; i++) { 508 ar->r[i] = 0; 509 ar->g[i] = 0; 510 ar->b[i] = 0; 511 } 512 } 513 514 if ((on != 0) && (sc->sc_blanked != 0)) { 515 /* Turn video back ON (unblank). */ 516 sc->sc_blanked = 0; 517 /* Restore normal colormap. */ 518 cg4a_ldcmap(sc); 519 } 520 } 521 522 523 /**************************************************************** 524 * Routines for the "Type B" hardware 525 ****************************************************************/ 526 527 static void 528 cg4b_init(sc) 529 struct cg4_softc *sc; 530 { 531 volatile struct bt_regs *bt = sc->sc_va_cmap; 532 struct soft_cmap *cm = &sc->sc_cmap; 533 union bt_cmap *btcm = sc->sc_btcm; 534 int i; 535 536 /* 537 * BT458 chip initialization as described in Brooktree's 538 * 1993 Graphics and Imaging Product Databook (DB004-1/93). 539 */ 540 bt->bt_addr = 0x04; /* select read mask register */ 541 bt->bt_ctrl = 0xff; /* all planes on */ 542 bt->bt_addr = 0x05; /* select blink mask register */ 543 bt->bt_ctrl = 0x00; /* all planes non-blinking */ 544 bt->bt_addr = 0x06; /* select command register */ 545 bt->bt_ctrl = 0x43; /* palette enabled, overlay planes enabled */ 546 bt->bt_addr = 0x07; /* select test register */ 547 bt->bt_ctrl = 0x00; /* set test mode */ 548 549 /* grab initial (current) color map */ 550 bt->bt_addr = 0; 551 for (i = 0; i < (256 * 3 / 4); i++) { 552 btcm->cm_chip[i] = bt->bt_cmap; 553 } 554 555 /* Transpose into S/W form. */ 556 for (i = 0; i < 256; i++) { 557 cm->r[i] = btcm->cm_map[i][0]; 558 cm->g[i] = btcm->cm_map[i][1]; 559 cm->b[i] = btcm->cm_map[i][2]; 560 } 561 } 562 563 static void 564 cg4b_ldcmap(sc) 565 struct cg4_softc *sc; 566 { 567 volatile struct bt_regs *bt = sc->sc_va_cmap; 568 struct soft_cmap *cm = &sc->sc_cmap; 569 union bt_cmap *btcm = sc->sc_btcm; 570 int i; 571 572 /* 573 * Now blast them into the chip! 574 * XXX Should use retrace interrupt! 575 * Just set a "need load" bit and let the 576 * retrace interrupt handler do the work. 577 */ 578 579 /* Transpose into H/W form. */ 580 for (i = 0; i < 256; i++) { 581 btcm->cm_map[i][0] = cm->r[i]; 582 btcm->cm_map[i][1] = cm->g[i]; 583 btcm->cm_map[i][2] = cm->b[i]; 584 } 585 586 bt->bt_addr = 0; 587 for (i = 0; i < (256 * 3 / 4); i++) { 588 bt->bt_cmap = btcm->cm_chip[i]; 589 } 590 } 591 592 static void 593 cg4b_svideo(sc, on) 594 struct cg4_softc *sc; 595 int on; 596 { 597 volatile struct bt_regs *bt = sc->sc_va_cmap; 598 int i; 599 600 if ((on == 0) && (sc->sc_blanked == 0)) { 601 /* Turn OFF video (make it blank). */ 602 sc->sc_blanked = 1; 603 /* Load fake "all zero" colormap. */ 604 bt->bt_addr = 0; 605 for (i = 0; i < (256 * 3 / 4); i++) 606 bt->bt_cmap = 0; 607 } 608 609 if ((on != 0) && (sc->sc_blanked != 0)) { 610 /* Turn video back ON (unblank). */ 611 sc->sc_blanked = 0; 612 /* Restore normal colormap. */ 613 cg4b_ldcmap(sc); 614 } 615 } 616 617