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