Home | History | Annotate | Line # | Download | only in dev
cg4.c revision 1.13
      1 /*	$NetBSD: cg4.c,v 1.13 1998/01/12 20:32:19 thorpej 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/conf.h>
     64 #include <sys/device.h>
     65 #include <sys/ioctl.h>
     66 #include <sys/malloc.h>
     67 #include <sys/mman.h>
     68 #include <sys/proc.h>
     69 #include <sys/tty.h>
     70 
     71 #include <vm/vm.h>
     72 
     73 #include <machine/autoconf.h>
     74 #include <machine/cpu.h>
     75 #include <machine/fbio.h>
     76 #include <machine/idprom.h>
     77 #include <machine/pmap.h>
     78 
     79 #include "fbvar.h"
     80 #include "btreg.h"
     81 #include "btvar.h"
     82 #include "cg4reg.h"
     83 
     84 cdev_decl(cg4);
     85 
     86 #define	CG4_MMAP_SIZE (CG4_OVERLAY_SIZE + CG4_ENABLE_SIZE + CG4_PIXMAP_SIZE)
     87 
     88 extern unsigned char cpu_machine_id;
     89 
     90 #define CMAP_SIZE 256
     91 struct soft_cmap {
     92 	u_char r[CMAP_SIZE];
     93 	u_char g[CMAP_SIZE];
     94 	u_char b[CMAP_SIZE];
     95 };
     96 
     97 /* per-display variables */
     98 struct cg4_softc {
     99 	struct	device sc_dev;		/* base device */
    100 	struct	fbdevice sc_fb;		/* frame buffer device */
    101 	int 	sc_cg4type;		/* A or B */
    102 	void	*sc_va_cmap;		/* Colormap h/w (mapped KVA) */
    103 	int 	sc_pa_overlay;		/* phys. addr. of overlay plane */
    104 	int 	sc_pa_enable;		/* phys. addr. of enable plane */
    105 	int 	sc_pa_pixmap;		/* phys. addr. of color plane */
    106 	int 	sc_blanked;		/* true if blanked */
    107 
    108 	union bt_cmap *sc_btcm;		/* Brooktree color map */
    109 	struct soft_cmap sc_cmap;	/* Generic soft colormap. */
    110 };
    111 
    112 /* autoconfiguration driver */
    113 static void	cg4attach __P((struct device *, struct device *, void *));
    114 static int	cg4match __P((struct device *, struct cfdata *, void *));
    115 
    116 struct cfattach cgfour_ca = {
    117 	sizeof(struct cg4_softc), cg4match, cg4attach
    118 };
    119 
    120 extern struct cfdriver cgfour_cd;
    121 
    122 static int	cg4gattr   __P((struct fbdevice *, void *));
    123 static int	cg4gvideo  __P((struct fbdevice *, void *));
    124 static int	cg4svideo  __P((struct fbdevice *, void *));
    125 static int	cg4getcmap __P((struct fbdevice *, void *));
    126 static int	cg4putcmap __P((struct fbdevice *, void *));
    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, cf, args)
    146 	struct device *parent;
    147 	struct cfdata *cf;
    148 	void *args;
    149 {
    150 	struct confargs *ca = args;
    151 	int paddr;
    152 
    153 	/* XXX: Huge hack due to lack of probe info... */
    154 	/* XXX: Machines that might have a cg4 (gag). */
    155 	/* XXX: Need info on the "P4" register... */
    156 	switch (cpu_machine_id) {
    157 
    158 	case SUN3_MACH_110:
    159 		/* XXX: Assume type A. */
    160 		if (ca->ca_paddr == -1)
    161 			ca->ca_paddr = CG4A_DEF_BASE;
    162 		if (bus_peek(ca->ca_bustype, ca->ca_paddr, 1) == -1)
    163 			return (0);
    164 		if (bus_peek(BUS_OBIO, CG4A_OBIO_CMAP, 1) == -1)
    165 			return (0);
    166 		break;
    167 
    168 	case SUN3_MACH_60:
    169 		/* XXX: Assume type A. */
    170 		if (ca->ca_paddr == -1)
    171 			ca->ca_paddr = CG4B_DEF_BASE;
    172 		paddr = ca->ca_paddr;
    173 		if (bus_peek(ca->ca_bustype, paddr, 1) == -1)
    174 			return (0);
    175         /* Make sure we're color */
    176 		paddr += CG4B_OFF_PIXMAP;
    177 		if (bus_peek(ca->ca_bustype, paddr, 1) == -1)
    178 			return (0);
    179 		break;
    180 
    181 	default:
    182 		return (0);
    183 	}
    184 
    185 	return (1);
    186 }
    187 
    188 /*
    189  * Attach a display.  We need to notice if it is the console, too.
    190  */
    191 static void
    192 cg4attach(parent, self, args)
    193 	struct device *parent, *self;
    194 	void *args;
    195 {
    196 	struct cg4_softc *sc = (struct cg4_softc *)self;
    197 	struct fbdevice *fb = &sc->sc_fb;
    198 	struct confargs *ca = args;
    199 	struct fbtype *fbt;
    200 
    201 	/* XXX: should do better than this... */
    202 	switch (cpu_machine_id) {
    203 	case SUN3_MACH_110:
    204 		sc->sc_cg4type = CG4_TYPE_A;
    205 		break;
    206 	case SUN3_MACH_60:
    207 	default:
    208 		sc->sc_cg4type = CG4_TYPE_B;
    209 	}
    210 
    211 	fb->fb_driver = &cg4_fbdriver;
    212 	fb->fb_private = sc;
    213 	fb->fb_name = sc->sc_dev.dv_xname;
    214 
    215 	fbt = &fb->fb_fbtype;
    216 	fbt->fb_type = FBTYPE_SUN4COLOR;
    217 	fbt->fb_depth = 8;
    218 	fbt->fb_cmsize = 256;
    219 
    220 	fbt->fb_width = 1152;
    221 	fbt->fb_height = 900;
    222 	fbt->fb_size = CG4_MMAP_SIZE;
    223 
    224 	switch (sc->sc_cg4type) {
    225 	case CG4_TYPE_A:	/* Sun3/110 */
    226 		sc->sc_va_cmap = bus_mapin(BUS_OBIO, CG4A_OBIO_CMAP,
    227 		                           sizeof(struct amd_regs));
    228 		sc->sc_pa_overlay = ca->ca_paddr + CG4A_OFF_OVERLAY;
    229 		sc->sc_pa_enable  = ca->ca_paddr + CG4A_OFF_ENABLE;
    230 		sc->sc_pa_pixmap  = ca->ca_paddr + CG4A_OFF_PIXMAP;
    231 		sc->sc_btcm = NULL;
    232 		cg4a_init(sc);
    233 		break;
    234 
    235 	case CG4_TYPE_B:	/* Sun3/60 */
    236 	default:
    237 		sc->sc_va_cmap = (struct bt_regs *)
    238 			bus_mapin(ca->ca_bustype, ca->ca_paddr,
    239 					  sizeof(struct bt_regs *));
    240 		sc->sc_pa_overlay = ca->ca_paddr + CG4B_OFF_OVERLAY;
    241 		sc->sc_pa_enable  = ca->ca_paddr + CG4B_OFF_ENABLE;
    242 		sc->sc_pa_pixmap  = ca->ca_paddr + CG4B_OFF_PIXMAP;
    243 		sc->sc_btcm = malloc(sizeof(union bt_cmap), M_DEVBUF, M_WAITOK);
    244 		cg4b_init(sc);
    245 		break;
    246 	}
    247 
    248 	printf(" (%dx%d)\n", fbt->fb_width, fbt->fb_height);
    249 	fb_attach(fb, 4);
    250 }
    251 
    252 int
    253 cg4open(dev, flags, mode, p)
    254 	dev_t dev;
    255 	int flags, mode;
    256 	struct proc *p;
    257 {
    258 	int unit = minor(dev);
    259 
    260 	if (unit >= cgfour_cd.cd_ndevs || cgfour_cd.cd_devs[unit] == NULL)
    261 		return (ENXIO);
    262 	return (0);
    263 }
    264 
    265 int
    266 cg4close(dev, flags, mode, p)
    267 	dev_t dev;
    268 	int flags, mode;
    269 	struct proc *p;
    270 {
    271 
    272 	return (0);
    273 }
    274 
    275 int
    276 cg4ioctl(dev, cmd, data, flags, p)
    277 	dev_t dev;
    278 	u_long cmd;
    279 	caddr_t data;
    280 	int flags;
    281 	struct proc *p;
    282 {
    283 	struct cg4_softc *sc = cgfour_cd.cd_devs[minor(dev)];
    284 
    285 	return (fbioctlfb(&sc->sc_fb, cmd, data));
    286 }
    287 
    288 /*
    289  * Return the address that would map the given device at the given
    290  * offset, allowing for the given protection, or return -1 for error.
    291  *
    292  * X11 expects its mmap'd region to look like this:
    293  * 	128k overlay data memory
    294  * 	128k overlay enable bitmap
    295  * 	1024k color memory
    296  *
    297  * The hardware really looks like this (starting at ca_paddr)
    298  *  4 bytes Brooktree DAC registers
    299  *  2MB-4 gap
    300  * 	128k overlay memory
    301  * 	1920k gap
    302  * 	128k overlay-enable bitmap
    303  * 	1920k gap
    304  * 	1024k color memory
    305  */
    306 int
    307 cg4mmap(dev, off, prot)
    308 	dev_t dev;
    309 	register int off;
    310 	int prot;
    311 {
    312 	struct cg4_softc *sc = cgfour_cd.cd_devs[minor(dev)];
    313 	register int physbase;
    314 
    315 	if (off & PGOFSET)
    316 		panic("cg4mmap");
    317 
    318 	if ((unsigned)off >= CG4_MMAP_SIZE)
    319 		return (-1);
    320 
    321 	if (off < 0x40000) {
    322 		if (off < 0x20000) {
    323 			physbase = sc->sc_pa_overlay;
    324 		} else {
    325 			/* enable plane */
    326 			off -= 0x20000;
    327 			physbase = sc->sc_pa_enable;
    328 		}
    329 	} else {
    330 		/* pixel map */
    331 		off -= 0x40000;
    332 		physbase = sc->sc_pa_pixmap;
    333 	}
    334 
    335 	/*
    336 	 * I turned on PMAP_NC here to disable the cache as I was
    337 	 * getting horribly broken behaviour with it on.
    338 	 */
    339 	return ((physbase + off) | PMAP_NC);
    340 }
    341 
    342 /*
    343  * Internal ioctl functions.
    344  */
    345 
    346 /* FBIOGATTR: */
    347 static int  cg4gattr(fb, data)
    348 	struct fbdevice *fb;
    349 	void *data;
    350 {
    351 	struct fbgattr *fba = data;
    352 
    353 	fba->real_type = fb->fb_fbtype.fb_type;
    354 	fba->owner = 0;		/* XXX - TIOCCONS stuff? */
    355 	fba->fbtype = fb->fb_fbtype;
    356 	fba->sattr.flags = 0;
    357 	fba->sattr.emu_type = fb->fb_fbtype.fb_type;
    358 	fba->sattr.dev_specific[0] = -1;
    359 	fba->emu_types[0] = fb->fb_fbtype.fb_type;
    360 	fba->emu_types[1] = -1;
    361 	return (0);
    362 }
    363 
    364 /* FBIOGVIDEO: */
    365 static int  cg4gvideo(fb, data)
    366 	struct fbdevice *fb;
    367 	void *data;
    368 {
    369 	int *on = data;
    370 	struct cg4_softc *sc = fb->fb_private;
    371 
    372 	*on = !sc->sc_blanked;
    373 	return (0);
    374 }
    375 
    376 /* FBIOSVIDEO: */
    377 static int cg4svideo(fb, data)
    378 	struct fbdevice *fb;
    379 	void *data;
    380 {
    381 	int *on = data;
    382 	struct cg4_softc *sc = fb->fb_private;
    383 	int state;
    384 
    385 	state = *on;
    386 	if (sc->sc_cg4type == CG4_TYPE_A)
    387 		cg4a_svideo(sc, state);
    388 	else
    389 		cg4b_svideo(sc, state);
    390 	return (0);
    391 }
    392 
    393 /*
    394  * FBIOGETCMAP:
    395  * Copy current colormap out to user space.
    396  */
    397 static int cg4getcmap(fb, data)
    398 	struct fbdevice *fb;
    399 	void *data;
    400 {
    401 	struct fbcmap *fbcm = data;
    402 	struct cg4_softc *sc = fb->fb_private;
    403 	struct soft_cmap *cm = &sc->sc_cmap;
    404 	int error, start, count;
    405 
    406 	start = fbcm->index;
    407 	count = fbcm->count;
    408 	if ((start < 0) || (start >= CMAP_SIZE) ||
    409 	    (count < 0) || (start + count > CMAP_SIZE) )
    410 		return (EINVAL);
    411 
    412 	if ((error = copyout(&cm->r[start], fbcm->red, count)) != 0)
    413 		return (error);
    414 
    415 	if ((error = copyout(&cm->g[start], fbcm->green, count)) != 0)
    416 		return (error);
    417 
    418 	if ((error = copyout(&cm->b[start], fbcm->blue, count)) != 0)
    419 		return (error);
    420 
    421 	return (0);
    422 }
    423 
    424 /*
    425  * FBIOPUTCMAP:
    426  * Copy new colormap from user space and load.
    427  */
    428 static int cg4putcmap(fb, data)
    429 	struct fbdevice *fb;
    430 	void *data;
    431 {
    432 	struct fbcmap *fbcm = data;
    433 	struct cg4_softc *sc = fb->fb_private;
    434 	struct soft_cmap *cm = &sc->sc_cmap;
    435 	int error, start, count;
    436 
    437 	start = fbcm->index;
    438 	count = fbcm->count;
    439 	if ((start < 0) || (start >= CMAP_SIZE) ||
    440 	    (count < 0) || (start + count > CMAP_SIZE) )
    441 		return (EINVAL);
    442 
    443 	if ((error = copyin(fbcm->red, &cm->r[start], count)) != 0)
    444 		return (error);
    445 
    446 	if ((error = copyin(fbcm->green, &cm->g[start], count)) != 0)
    447 		return (error);
    448 
    449 	if ((error = copyin(fbcm->blue, &cm->b[start], count)) != 0)
    450 		return (error);
    451 
    452 	if (sc->sc_cg4type == CG4_TYPE_A)
    453 		cg4a_ldcmap(sc);
    454 	else
    455 		cg4b_ldcmap(sc);
    456 
    457 	return (0);
    458 }
    459 
    460 /****************************************************************
    461  * Routines for the "Type A" hardware
    462  ****************************************************************/
    463 
    464 static void
    465 cg4a_init(sc)
    466 	struct cg4_softc *sc;
    467 {
    468 	volatile struct amd_regs *ar = sc->sc_va_cmap;
    469 	struct soft_cmap *cm = &sc->sc_cmap;
    470 	int i;
    471 
    472 	/* grab initial (current) color map */
    473 	for(i = 0; i < 256; i++) {
    474 		cm->r[i] = ar->r[i];
    475 		cm->g[i] = ar->g[i];
    476 		cm->b[i] = ar->b[i];
    477 	}
    478 }
    479 
    480 static void
    481 cg4a_ldcmap(sc)
    482 	struct cg4_softc *sc;
    483 {
    484 	volatile struct amd_regs *ar = sc->sc_va_cmap;
    485 	struct soft_cmap *cm = &sc->sc_cmap;
    486 	int i;
    487 
    488 	/*
    489 	 * Now blast them into the chip!
    490 	 * XXX Should use retrace interrupt!
    491 	 * Just set a "need load" bit and let the
    492 	 * retrace interrupt handler do the work.
    493 	 */
    494 	for(i = 0; i < 256; i++) {
    495 		ar->r[i] = cm->r[i];
    496 		ar->g[i] = cm->g[i];
    497 		ar->b[i] = cm->b[i];
    498 	}
    499 }
    500 
    501 static void
    502 cg4a_svideo(sc, on)
    503 	struct cg4_softc *sc;
    504 	int on;
    505 {
    506 	volatile struct amd_regs *ar = sc->sc_va_cmap;
    507 	int i;
    508 
    509 	if ((on == 0) && (sc->sc_blanked == 0)) {
    510 		/* Turn OFF video (make it blank). */
    511 		sc->sc_blanked = 1;
    512 		/* Load fake "all zero" colormap. */
    513 		for (i = 0; i < 256; i++) {
    514 			ar->r[i] = 0;
    515 			ar->g[i] = 0;
    516 			ar->b[i] = 0;
    517 		}
    518 	}
    519 
    520 	if ((on != 0) && (sc->sc_blanked != 0)) {
    521 		/* Turn video back ON (unblank). */
    522 		sc->sc_blanked = 0;
    523 		/* Restore normal colormap. */
    524 		cg4a_ldcmap(sc);
    525 	}
    526 }
    527 
    528 
    529 /****************************************************************
    530  * Routines for the "Type B" hardware
    531  ****************************************************************/
    532 
    533 static void
    534 cg4b_init(sc)
    535 	struct cg4_softc *sc;
    536 {
    537 	volatile struct bt_regs *bt = sc->sc_va_cmap;
    538 	struct soft_cmap *cm = &sc->sc_cmap;
    539 	union bt_cmap *btcm = sc->sc_btcm;
    540 	int i;
    541 
    542 	/*
    543 	 * BT458 chip initialization as described in Brooktree's
    544 	 * 1993 Graphics and Imaging Product Databook (DB004-1/93).
    545 	 */
    546 	bt->bt_addr = 0x04;	/* select read mask register */
    547 	bt->bt_ctrl = 0xff;	/* all planes on */
    548 	bt->bt_addr = 0x05;	/* select blink mask register */
    549 	bt->bt_ctrl = 0x00;	/* all planes non-blinking */
    550 	bt->bt_addr = 0x06;	/* select command register */
    551 	bt->bt_ctrl = 0x43;	/* palette enabled, overlay planes enabled */
    552 	bt->bt_addr = 0x07;	/* select test register */
    553 	bt->bt_ctrl = 0x00;	/* set test mode */
    554 
    555 	/* grab initial (current) color map */
    556 	bt->bt_addr = 0;
    557 	for (i = 0; i < (256 * 3 / 4); i++) {
    558 		btcm->cm_chip[i] = bt->bt_cmap;
    559 	}
    560 
    561 	/* Transpose into S/W form. */
    562 	for (i = 0; i < 256; i++) {
    563 		cm->r[i] = btcm->cm_map[i][0];
    564 		cm->g[i] = btcm->cm_map[i][1];
    565 		cm->b[i] = btcm->cm_map[i][2];
    566 	}
    567 }
    568 
    569 static void
    570 cg4b_ldcmap(sc)
    571 	struct cg4_softc *sc;
    572 {
    573 	volatile struct bt_regs *bt = sc->sc_va_cmap;
    574 	struct soft_cmap *cm = &sc->sc_cmap;
    575 	union bt_cmap *btcm = sc->sc_btcm;
    576 	int i;
    577 
    578 	/*
    579 	 * Now blast them into the chip!
    580 	 * XXX Should use retrace interrupt!
    581 	 * Just set a "need load" bit and let the
    582 	 * retrace interrupt handler do the work.
    583 	 */
    584 
    585 	/* Transpose into H/W form. */
    586 	for (i = 0; i < 256; i++) {
    587 		btcm->cm_map[i][0] = cm->r[i];
    588 		btcm->cm_map[i][1] = cm->g[i];
    589 		btcm->cm_map[i][2] = cm->b[i];
    590 	}
    591 
    592 	bt->bt_addr = 0;
    593 	for (i = 0; i < (256 * 3 / 4); i++) {
    594 		bt->bt_cmap = btcm->cm_chip[i];
    595 	}
    596 }
    597 
    598 static void
    599 cg4b_svideo(sc, on)
    600 	struct cg4_softc *sc;
    601 	int on;
    602 {
    603 	volatile struct bt_regs *bt = sc->sc_va_cmap;
    604 	int i;
    605 
    606 	if ((on == 0) && (sc->sc_blanked == 0)) {
    607 		/* Turn OFF video (make it blank). */
    608 		sc->sc_blanked = 1;
    609 		/* Load fake "all zero" colormap. */
    610 		bt->bt_addr = 0;
    611 		for (i = 0; i < (256 * 3 / 4); i++)
    612 			bt->bt_cmap = 0;
    613 	}
    614 
    615 	if ((on != 0) && (sc->sc_blanked != 0)) {
    616 		/* Turn video back ON (unblank). */
    617 		sc->sc_blanked = 0;
    618 		/* Restore normal colormap. */
    619 		cg4b_ldcmap(sc);
    620 	}
    621 }
    622 
    623