xref: /netbsd/sys/arch/sun3/dev/cg2.c (revision 1a918832)
1*1a918832Sdholland /*	$NetBSD: cg2.c,v 1.31 2014/07/25 08:10:35 dholland Exp $	*/
21feb639aSgwr 
31feb639aSgwr /*
41feb639aSgwr  * Copyright (c) 1992, 1993
51feb639aSgwr  *	The Regents of the University of California.  All rights reserved.
61feb639aSgwr  *
71feb639aSgwr  * This software was developed by the Computer Systems Engineering group
81feb639aSgwr  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
91feb639aSgwr  * contributed to Berkeley.
101feb639aSgwr  *
111feb639aSgwr  * All advertising materials mentioning features or use of this software
121feb639aSgwr  * must display the following acknowledgement:
131feb639aSgwr  *	This product includes software developed by the University of
141feb639aSgwr  *	California, Lawrence Berkeley Laboratory.
151feb639aSgwr  *
161feb639aSgwr  * Redistribution and use in source and binary forms, with or without
171feb639aSgwr  * modification, are permitted provided that the following conditions
181feb639aSgwr  * are met:
191feb639aSgwr  * 1. Redistributions of source code must retain the above copyright
201feb639aSgwr  *    notice, this list of conditions and the following disclaimer.
211feb639aSgwr  * 2. Redistributions in binary form must reproduce the above copyright
221feb639aSgwr  *    notice, this list of conditions and the following disclaimer in the
231feb639aSgwr  *    documentation and/or other materials provided with the distribution.
24aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
251feb639aSgwr  *    may be used to endorse or promote products derived from this software
261feb639aSgwr  *    without specific prior written permission.
271feb639aSgwr  *
281feb639aSgwr  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
291feb639aSgwr  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
301feb639aSgwr  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
311feb639aSgwr  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
321feb639aSgwr  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
331feb639aSgwr  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
341feb639aSgwr  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
351feb639aSgwr  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
361feb639aSgwr  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
371feb639aSgwr  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
381feb639aSgwr  * SUCH DAMAGE.
391feb639aSgwr  *
401feb639aSgwr  *	from: @(#)cgthree.c	8.2 (Berkeley) 10/30/93
411feb639aSgwr  */
421feb639aSgwr 
431feb639aSgwr /*
441feb639aSgwr  * color display (cg2) driver.
451feb639aSgwr  *
461feb639aSgwr  * Does not handle interrupts, even though they can occur.
471feb639aSgwr  *
481feb639aSgwr  * XXX should defer colormap updates to vertical retrace interrupts
491feb639aSgwr  */
501feb639aSgwr 
51ed517291Slukem #include <sys/cdefs.h>
52*1a918832Sdholland __KERNEL_RCSID(0, "$NetBSD: cg2.c,v 1.31 2014/07/25 08:10:35 dholland Exp $");
53ed517291Slukem 
541feb639aSgwr #include <sys/param.h>
550c5e3e49Sgwr #include <sys/systm.h>
560c5e3e49Sgwr #include <sys/conf.h>
571feb639aSgwr #include <sys/device.h>
581feb639aSgwr #include <sys/ioctl.h>
591feb639aSgwr #include <sys/malloc.h>
601feb639aSgwr #include <sys/mman.h>
610c5e3e49Sgwr #include <sys/proc.h>
621feb639aSgwr #include <sys/tty.h>
631feb639aSgwr 
649c11d316Smrg #include <uvm/uvm_extern.h>
651feb639aSgwr 
66e38a2e56Sthorpej #include <dev/sun/fbio.h>
671feb639aSgwr #include <machine/autoconf.h>
681feb639aSgwr #include <machine/pmap.h>
691feb639aSgwr #include <machine/cg2reg.h>
701feb639aSgwr 
712c5f71ccStsutsui #include "ioconf.h"
721feb639aSgwr #include "fbvar.h"
731feb639aSgwr 
741feb639aSgwr #define	CMSIZE 256
751feb639aSgwr 
761feb639aSgwr /* offset to and size of mapped part of frame buffer */
771feb639aSgwr #define PLANEMAP_SIZE		0x100000
781feb639aSgwr #define PIXELMAP_SIZE		0x100000
791feb639aSgwr #define ROWOPMAP_SIZE		0x100000
801feb639aSgwr 
811feb639aSgwr #define	CTLREGS_OFF 		0x300000
821feb639aSgwr #define	CTLREGS_SIZE		 0x10600
831feb639aSgwr 
841feb639aSgwr #define	CG2_MAPPED_OFFSET	(PLANEMAP_SIZE + PIXELMAP_SIZE)
85a1cc6d49Sgwr #define	CG2_MAPPED_SIZE 	(CTLREGS_OFF + CTLREGS_SIZE)
861feb639aSgwr 
871feb639aSgwr /* per-display variables */
881feb639aSgwr struct cg2_softc {
892c5f71ccStsutsui 	device_t sc_dev;		/* base device */
901feb639aSgwr 	struct	fbdevice sc_fb;		/* frame buffer device */
911feb639aSgwr 	int 	sc_phys;		/* display RAM (phys addr) */
921feb639aSgwr 	int 	sc_pmtype;		/* pmap type bits */
931feb639aSgwr 	struct	cg2fb *sc_ctlreg;	/* control registers */
941feb639aSgwr };
951feb639aSgwr 
961feb639aSgwr /* autoconfiguration driver */
972c5f71ccStsutsui static int	cg2match(device_t, cfdata_t, void *);
982c5f71ccStsutsui static void	cg2attach(device_t, device_t, void *);
991feb639aSgwr 
1002c5f71ccStsutsui CFATTACH_DECL_NEW(cgtwo, sizeof(struct cg2_softc),
1014bf871a7Sthorpej     cg2match, cg2attach, NULL, NULL);
1023cd14f75Sthorpej 
10377a6b82bSgehenna dev_type_open(cg2open);
10477a6b82bSgehenna dev_type_ioctl(cg2ioctl);
10577a6b82bSgehenna dev_type_mmap(cg2mmap);
10677a6b82bSgehenna 
10777a6b82bSgehenna const struct cdevsw cgtwo_cdevsw = {
10876258fa0Sdholland 	.d_open = cg2open,
10976258fa0Sdholland 	.d_close = nullclose,
11076258fa0Sdholland 	.d_read = noread,
11176258fa0Sdholland 	.d_write = nowrite,
11276258fa0Sdholland 	.d_ioctl = cg2ioctl,
11376258fa0Sdholland 	.d_stop = nostop,
11476258fa0Sdholland 	.d_tty = notty,
11576258fa0Sdholland 	.d_poll = nopoll,
11676258fa0Sdholland 	.d_mmap = cg2mmap,
11776258fa0Sdholland 	.d_kqfilter = nokqfilter,
118*1a918832Sdholland 	.d_discard = nodiscard,
11976258fa0Sdholland 	.d_flag = 0
12077a6b82bSgehenna };
12177a6b82bSgehenna 
12210b1a7beSchs static int cg2gattr(struct fbdevice *,  void *);
12310b1a7beSchs static int cg2gvideo(struct fbdevice *, void *);
12410b1a7beSchs static int cg2svideo(struct fbdevice *, void *);
12510b1a7beSchs static int cg2getcmap(struct fbdevice *, void *);
12610b1a7beSchs static int cg2putcmap(struct fbdevice *, void *);
1271feb639aSgwr 
1281feb639aSgwr static struct fbdriver cg2fbdriver = {
129e0cc03a0Sjdolecek 	cg2open, nullclose, cg2mmap, nokqfilter, cg2gattr,
1301feb639aSgwr 	cg2gvideo, cg2svideo,
1311feb639aSgwr 	cg2getcmap, cg2putcmap };
1321feb639aSgwr 
13310b1a7beSchs static int cg2intr(void *);
1341feb639aSgwr 
1351feb639aSgwr /*
1361feb639aSgwr  * Match a cg2.
1371feb639aSgwr  */
1381feb639aSgwr static int
cg2match(device_t parent,cfdata_t cf,void * aux)1392c5f71ccStsutsui cg2match(device_t parent, cfdata_t cf, void *aux)
1401feb639aSgwr {
141703ed32eSgwr 	struct confargs *ca = aux;
142703ed32eSgwr 	int probe_addr;
1431feb639aSgwr 
144703ed32eSgwr 	/* No default VME address. */
1451feb639aSgwr 	if (ca->ca_paddr == -1)
1462c5f71ccStsutsui 		return 0;
1471feb639aSgwr 
148703ed32eSgwr 	/* Make sure something is there... */
149703ed32eSgwr 	probe_addr = ca->ca_paddr + CTLREGS_OFF;
150703ed32eSgwr 	if (bus_peek(ca->ca_bustype, probe_addr, 1) == -1)
1512c5f71ccStsutsui 		return 0;
1521feb639aSgwr 
153703ed32eSgwr 	/* XXX: look at the ID reg? */
1542c5f71ccStsutsui 	/* aprint_debug("cg2: id=0x%x\n", x); */
1551feb639aSgwr 
156703ed32eSgwr 	/* Default interrupt priority. */
157703ed32eSgwr 	if (ca->ca_intpri == -1)
158703ed32eSgwr 		ca->ca_intpri = 4;
159703ed32eSgwr 
1602c5f71ccStsutsui 	return 1;
1611feb639aSgwr }
1621feb639aSgwr 
1631feb639aSgwr /*
1641feb639aSgwr  * Attach a display.  We need to notice if it is the console, too.
1651feb639aSgwr  */
1661feb639aSgwr static void
cg2attach(device_t parent,device_t self,void * args)1672c5f71ccStsutsui cg2attach(device_t parent, device_t self, void *args)
1681feb639aSgwr {
169fefb677dStsutsui 	struct cg2_softc *sc = device_private(self);
1701feb639aSgwr 	struct fbdevice *fb = &sc->sc_fb;
1711feb639aSgwr 	struct confargs *ca = args;
1721feb639aSgwr 	struct fbtype *fbt;
1731feb639aSgwr 
1742c5f71ccStsutsui 	sc->sc_dev = self;
1751feb639aSgwr 	sc->sc_phys = ca->ca_paddr;
1761feb639aSgwr 	sc->sc_pmtype = PMAP_NC | PMAP_VME16;
1771feb639aSgwr 
1781feb639aSgwr 	sc->sc_ctlreg = (struct cg2fb *)bus_mapin(ca->ca_bustype,
1791feb639aSgwr 	    ca->ca_paddr + CTLREGS_OFF, CTLREGS_SIZE);
1801feb639aSgwr 
1812c5f71ccStsutsui 	isr_add_vectored(cg2intr, sc, ca->ca_intpri, ca->ca_intvec);
1821feb639aSgwr 
1831feb639aSgwr 	/*
1841feb639aSgwr 	 * XXX - Initialize?  Determine type?
1851feb639aSgwr 	 */
1861feb639aSgwr 	sc->sc_ctlreg->intrptvec.reg = ca->ca_intvec;
1871feb639aSgwr 	sc->sc_ctlreg->status.word = 1;
1881feb639aSgwr 
1891feb639aSgwr 	fb->fb_driver = &cg2fbdriver;
1901feb639aSgwr 	fb->fb_private = sc;
1912c5f71ccStsutsui 	fb->fb_name = device_xname(self);
1921feb639aSgwr 
1931feb639aSgwr 	fbt = &fb->fb_fbtype;
1941feb639aSgwr 	fbt->fb_type = FBTYPE_SUN2COLOR;
1951feb639aSgwr 	fbt->fb_depth = 8;
1961feb639aSgwr 	fbt->fb_cmsize = CMSIZE;
1971feb639aSgwr 
1981feb639aSgwr 	fbt->fb_width = 1152;
1991feb639aSgwr 	fbt->fb_height = 900;
2001feb639aSgwr 	fbt->fb_size = CG2_MAPPED_SIZE;
2011feb639aSgwr 
2022c5f71ccStsutsui 	aprint_normal(" (%dx%d)\n", fbt->fb_width, fbt->fb_height);
2031feb639aSgwr 	fb_attach(fb, 2);
2041feb639aSgwr }
2051feb639aSgwr 
2061feb639aSgwr int
cg2open(dev_t dev,int flags,int mode,struct lwp * l)20795e1ffb1Schristos cg2open(dev_t dev, int flags, int mode, struct lwp *l)
2081feb639aSgwr {
209fefb677dStsutsui 	struct cg2_softc *sc;
2101feb639aSgwr 	int unit = minor(dev);
2111feb639aSgwr 
212fefb677dStsutsui 	sc = device_lookup_private(&cgtwo_cd, unit);
213fefb677dStsutsui 	if (sc == NULL)
2142c5f71ccStsutsui 		return ENXIO;
2152c5f71ccStsutsui 	return 0;
2161feb639aSgwr }
2171feb639aSgwr 
2181feb639aSgwr int
cg2ioctl(dev_t dev,u_long cmd,void * data,int flags,struct lwp * l)21953524e44Schristos cg2ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
2201feb639aSgwr {
221fefb677dStsutsui 	struct cg2_softc *sc = device_lookup_private(&cgtwo_cd, minor(dev));
2221feb639aSgwr 
2232c5f71ccStsutsui 	return fbioctlfb(&sc->sc_fb, cmd, data);
2241feb639aSgwr }
2251feb639aSgwr 
2261feb639aSgwr /*
2271feb639aSgwr  * Return the address that would map the given device at the given
2281feb639aSgwr  * offset, allowing for the given protection, or return -1 for error.
2291feb639aSgwr  */
230889c658bSsimonb paddr_t
cg2mmap(dev_t dev,off_t off,int prot)23110b1a7beSchs cg2mmap(dev_t dev, off_t off, int prot)
2321feb639aSgwr {
233fefb677dStsutsui 	struct cg2_softc *sc = device_lookup_private(&cgtwo_cd, minor(dev));
2341feb639aSgwr 
2351feb639aSgwr 	if (off & PGOFSET)
2362c5f71ccStsutsui 		panic("%s: bad offset", __func__);
2371feb639aSgwr 
238889c658bSsimonb 	if (off >= CG2_MAPPED_SIZE)
2392c5f71ccStsutsui 		return -1;
2401feb639aSgwr 
2411feb639aSgwr 	/*
2421feb639aSgwr 	 * I turned on PMAP_NC here to disable the cache as I was
2431feb639aSgwr 	 * getting horribly broken behaviour with it on.
2441feb639aSgwr 	 */
2452c5f71ccStsutsui 	return (sc->sc_phys + off) | sc->sc_pmtype;
2461feb639aSgwr }
2471feb639aSgwr 
2481feb639aSgwr /*
2491feb639aSgwr  * Internal ioctl functions.
2501feb639aSgwr  */
2511feb639aSgwr 
2521feb639aSgwr /* FBIOGATTR: */
25310b1a7beSchs static int
cg2gattr(struct fbdevice * fb,void * data)25410b1a7beSchs cg2gattr(struct fbdevice *fb, void *data)
2551feb639aSgwr {
2560c5e3e49Sgwr 	struct fbgattr *fba = data;
2571feb639aSgwr 
2581feb639aSgwr 	fba->real_type = fb->fb_fbtype.fb_type;
2591feb639aSgwr 	fba->owner = 0;		/* XXX - TIOCCONS stuff? */
2601feb639aSgwr 	fba->fbtype = fb->fb_fbtype;
2611feb639aSgwr 	fba->sattr.flags = 0;
2621feb639aSgwr 	fba->sattr.emu_type = fb->fb_fbtype.fb_type;
2631feb639aSgwr 	fba->sattr.dev_specific[0] = -1;
2641feb639aSgwr 	fba->emu_types[0] = fb->fb_fbtype.fb_type;
2651feb639aSgwr 	fba->emu_types[1] = -1;
2662c5f71ccStsutsui 	return 0;
2671feb639aSgwr }
2681feb639aSgwr 
2691feb639aSgwr /* FBIOGVIDEO: */
27010b1a7beSchs static int
cg2gvideo(struct fbdevice * fb,void * data)27110b1a7beSchs cg2gvideo(struct fbdevice *fb, void *data)
2721feb639aSgwr {
2730c5e3e49Sgwr 	int *on = data;
2741feb639aSgwr 	struct cg2_softc *sc = fb->fb_private;
2751feb639aSgwr 
2761feb639aSgwr 	*on = sc->sc_ctlreg->status.reg.video_enab;
2772c5f71ccStsutsui 	return 0;
2781feb639aSgwr }
2791feb639aSgwr 
2801feb639aSgwr /* FBIOSVIDEO: */
28110b1a7beSchs static int
cg2svideo(struct fbdevice * fb,void * data)28210b1a7beSchs cg2svideo(struct fbdevice *fb, void *data)
2831feb639aSgwr {
2840c5e3e49Sgwr 	int *on = data;
2851feb639aSgwr 	struct cg2_softc *sc = fb->fb_private;
2861feb639aSgwr 
2871feb639aSgwr 	sc->sc_ctlreg->status.reg.video_enab = (*on) & 1;
2881feb639aSgwr 
2892c5f71ccStsutsui 	return 0;
2901feb639aSgwr }
2911feb639aSgwr 
2921feb639aSgwr /* FBIOGETCMAP: */
29310b1a7beSchs static int
cg2getcmap(struct fbdevice * fb,void * data)29410b1a7beSchs cg2getcmap(struct fbdevice *fb, void *data)
2951feb639aSgwr {
2960c5e3e49Sgwr 	struct fbcmap *cmap = data;
2971feb639aSgwr 	struct cg2_softc *sc = fb->fb_private;
2982c5f71ccStsutsui 	uint8_t red[CMSIZE], green[CMSIZE], blue[CMSIZE];
2991feb639aSgwr 	int error, start, count, ecount;
300eabd6921Stsutsui 	u_int i;
3012c5f71ccStsutsui 	uint16_t *p;
3021feb639aSgwr 
3031feb639aSgwr 	start = cmap->index;
3041feb639aSgwr 	count = cmap->count;
3051feb639aSgwr 	ecount = start + count;
3068dd04cdcSitojun 	if (start >= CMSIZE || count > CMSIZE - start)
3072c5f71ccStsutsui 		return EINVAL;
3081feb639aSgwr 
3091feb639aSgwr 	/* XXX - Wait for retrace? */
3101feb639aSgwr 
3111feb639aSgwr 	/* Copy hardware to local arrays. */
3121feb639aSgwr 	p = &sc->sc_ctlreg->redmap[start];
3131feb639aSgwr 	for (i = start; i < ecount; i++)
3141feb639aSgwr 		red[i] = *p++;
3151feb639aSgwr 	p = &sc->sc_ctlreg->greenmap[start];
3161feb639aSgwr 	for (i = start; i < ecount; i++)
3171feb639aSgwr 		green[i] = *p++;
3181feb639aSgwr 	p = &sc->sc_ctlreg->bluemap[start];
3191feb639aSgwr 	for (i = start; i < ecount; i++)
3201feb639aSgwr 		blue[i] = *p++;
3211feb639aSgwr 
3221feb639aSgwr 	/* Copy local arrays to user space. */
3231feb639aSgwr 	if ((error = copyout(red + start, cmap->red, count)) != 0)
3242c5f71ccStsutsui 		return error;
3251feb639aSgwr 	if ((error = copyout(green + start, cmap->green, count)) != 0)
3262c5f71ccStsutsui 		return error;
3271feb639aSgwr 	if ((error = copyout(blue + start, cmap->blue, count)) != 0)
3282c5f71ccStsutsui 		return error;
3291feb639aSgwr 
3302c5f71ccStsutsui 	return 0;
3311feb639aSgwr }
3321feb639aSgwr 
3331feb639aSgwr /* FBIOPUTCMAP: */
33410b1a7beSchs static int
cg2putcmap(struct fbdevice * fb,void * data)33510b1a7beSchs cg2putcmap(struct fbdevice *fb, void *data)
3361feb639aSgwr {
3370c5e3e49Sgwr 	struct fbcmap *cmap = data;
3381feb639aSgwr 	struct cg2_softc *sc = fb->fb_private;
3392c5f71ccStsutsui 	uint8_t red[CMSIZE], green[CMSIZE], blue[CMSIZE];
34074954dadSjdolecek 	int error;
34174954dadSjdolecek 	u_int start, count, ecount;
342eabd6921Stsutsui 	u_int i;
3432c5f71ccStsutsui 	uint16_t *p;
3441feb639aSgwr 
3451feb639aSgwr 	start = cmap->index;
3461feb639aSgwr 	count = cmap->count;
3471feb639aSgwr 	ecount = start + count;
3488dd04cdcSitojun 	if (start >= CMSIZE || count > CMSIZE - start)
3492c5f71ccStsutsui 		return EINVAL;
3501feb639aSgwr 
3511feb639aSgwr 	/* Copy from user space to local arrays. */
3521feb639aSgwr 	if ((error = copyin(cmap->red, red + start, count)) != 0)
3532c5f71ccStsutsui 		return error;
3541feb639aSgwr 	if ((error = copyin(cmap->green, green + start, count)) != 0)
3552c5f71ccStsutsui 		return error;
3561feb639aSgwr 	if ((error = copyin(cmap->blue, blue + start, count)) != 0)
3572c5f71ccStsutsui 		return error;
3581feb639aSgwr 
3591feb639aSgwr 	/* XXX - Wait for retrace? */
3601feb639aSgwr 
3611feb639aSgwr 	/* Copy from local arrays to hardware. */
3621feb639aSgwr 	p = &sc->sc_ctlreg->redmap[start];
3631feb639aSgwr 	for (i = start; i < ecount; i++)
3641feb639aSgwr 		*p++ = red[i];
3651feb639aSgwr 	p = &sc->sc_ctlreg->greenmap[start];
3661feb639aSgwr 	for (i = start; i < ecount; i++)
3671feb639aSgwr 		*p++ = green[i];
3681feb639aSgwr 	p = &sc->sc_ctlreg->bluemap[start];
3691feb639aSgwr 	for (i = start; i < ecount; i++)
3701feb639aSgwr 		*p++ = blue[i];
3711feb639aSgwr 
3722c5f71ccStsutsui 	return 0;
3731feb639aSgwr 
3741feb639aSgwr }
3751feb639aSgwr 
3761feb639aSgwr static int
cg2intr(void * vsc)37710b1a7beSchs cg2intr(void *vsc)
3781feb639aSgwr {
3791feb639aSgwr 	struct cg2_softc *sc = vsc;
3801feb639aSgwr 
3811feb639aSgwr 	/* XXX - Just disable interrupts for now. */
3821feb639aSgwr 	sc->sc_ctlreg->status.reg.inten = 0;
3831feb639aSgwr 
384a087bfebSchristos 	printf("cg2intr\n");
3852c5f71ccStsutsui 	return 1;
3861feb639aSgwr }
387