Home | History | Annotate | Line # | Download | only in dev
cg4.c revision 1.11
      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