xref: /original-bsd/sys/sparc/sbus/cgthree.c (revision a810125e)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * All advertising materials mentioning features or use of this software
10  * must display the following acknowledgement:
11  *	This product includes software developed by the University of
12  *	California, Lawrence Berkeley Laboratories.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)cgthree.c	7.3 (Berkeley) 10/11/92
17  *
18  * from: $Header: cgthree.c,v 1.5 92/06/17 06:59:31 torek Exp $
19  */
20 
21 /*
22  * color display (cgthree) driver.
23  *
24  * Does not handle interrupts, even though they can occur.
25  */
26 
27 #include "cgthree.h"
28 
29 #include <sys/param.h>
30 #include <sys/buf.h>
31 #include <sys/device.h>
32 #include <sys/fbio.h>
33 #include <sys/ioctl.h>
34 #include <sys/malloc.h>
35 #include <sys/mman.h>
36 #include <sys/tty.h>
37 
38 #include <machine/autoconf.h>
39 #include <machine/pmap.h>
40 #include <machine/fbvar.h>
41 
42 #include <sparc/sbus/cgthreereg.h>
43 #include <sparc/sbus/sbusvar.h>
44 
45 union colormap {
46 	u_char	cm_map[256][3];		/* 256 R/G/B entries */
47 	u_int	cm_chip[256 * 3 / 4];	/* the way the chip gets loaded */
48 };
49 
50 /* per-display variables */
51 struct cgthree_softc {
52 	struct	device sc_dev;		/* base device */
53 	struct	sbusdev sc_sd;		/* sbus device */
54 	struct	fbdevice sc_fb;		/* frame buffer device */
55 	volatile struct cgthreereg *sc_reg;/* control registers */
56 	caddr_t	sc_phys;		/* display RAM (phys addr) */
57 	int	sc_blanked;		/* true if blanked */
58 	union	colormap sc_cmap;	/* current color map */
59 };
60 
61 /* autoconfiguration driver */
62 static void	cgthreeattach(struct device *, struct device *, void *);
63 struct cfdriver cgthreecd =
64     { NULL, "cgthree", matchbyname, cgthreeattach,
65       DV_DULL, sizeof(struct cgthree_softc) };
66 
67 /*
68  * XXX we do not handle frame buffer interrupts (do not know how) ... we
69  * need these to do color map loading at vertical retrace time!
70  */
71 
72 /* frame buffer generic driver */
73 static void	cgthreeunblank(struct device *);
74 static struct fbdriver cgthreefbdriver = { cgthreeunblank };
75 
76 extern int fbnode;
77 extern struct tty *fbconstty;
78 extern int (*v_putc)();
79 extern int nullop();
80 static int cgthree_cnputc();
81 #ifdef notdef
82 static struct cgthree_softc *bwcons;
83 #endif
84 
85 #define	CGTHREE_MAJOR	55		/* XXX */
86 
87 /*
88  * Attach a display.  We need to notice if it is the console, too.
89  */
90 void
91 cgthreeattach(parent, self, args)
92 	struct device *parent, *self;
93 	void *args;
94 {
95 	register struct cgthree_softc *sc = (struct cgthree_softc *)self;
96 	register struct sbus_attach_args *sa = args;
97 	register int node = sa->sa_ra.ra_node, ramsize, i;
98 	register volatile struct cgthreereg *cg3;
99 	register struct cgthree_all *p;
100 	int isconsole;
101 
102 	sc->sc_fb.fb_major = CGTHREE_MAJOR;	/* XXX to be removed */
103 
104 	sc->sc_fb.fb_driver = &cgthreefbdriver;
105 	sc->sc_fb.fb_device = &sc->sc_dev;
106 	/*
107 	 * The defaults below match my screen, but are not guaranteed
108 	 * to be correct as defaults go...
109 	 */
110 	sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR;
111 	sc->sc_fb.fb_type.fb_width = getpropint(node, "width", 1152);
112 	sc->sc_fb.fb_type.fb_height = getpropint(node, "height", 900);
113 	sc->sc_fb.fb_linebytes = getpropint(node, "linebytes", 1152);
114 	ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes;
115 	sc->sc_fb.fb_type.fb_depth = 8;
116 	sc->sc_fb.fb_type.fb_cmsize = 256;
117 	sc->sc_fb.fb_type.fb_size = ramsize;
118 	printf(": %s, %d x %d", getpropstring(node, "model"),
119 	    sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height);
120 
121 	/*
122 	 * When the ROM has mapped in a cgthree display, the address
123 	 * maps only the video RAM, so in any case we have to map the
124 	 * registers ourselves.  We only need the video RAM if we are
125 	 * going to print characters via rconsole.
126 	 */
127 	isconsole = node == fbnode && fbconstty != NULL;
128 	p = (struct cgthree_all *)sa->sa_ra.ra_paddr;
129 	if ((sc->sc_fb.fb_pixels = sa->sa_ra.ra_vaddr) == NULL && isconsole) {
130 		/* this probably cannot happen, but what the heck */
131 		sc->sc_fb.fb_pixels = mapiodev(p->ba_ram, ramsize);
132 	}
133 	sc->sc_reg = cg3 = (volatile struct cgthreereg *)
134 	    mapiodev((caddr_t)&p->ba_reg, sizeof(p->ba_reg));
135 	sc->sc_phys = p->ba_ram;
136 
137 	/* grab initial (current) color map, then set video */
138 	cg3->cg3_addr = 0;
139 	for (i = 0; i < 256 * 3 / 4; i++)
140 		sc->sc_cmap.cm_chip[i] = cg3->cg3_cmap;
141 	cgthreeunblank(&sc->sc_dev);
142 
143 	if (isconsole) {
144 		printf(" (console)\n");
145 #ifdef RCONSOLE
146 		rcons_init(&sc->sc_fb);
147 #endif
148 	} else
149 		printf("\n");
150 	sbus_establish(&sc->sc_sd, &sc->sc_dev);
151 	if (node == fbnode)
152 		fb_attach(&sc->sc_fb);
153 }
154 
155 int
156 cgthreeopen(dev, flags, mode, p)
157 	dev_t dev;
158 	int flags, mode;
159 	struct proc *p;
160 {
161 	int unit = minor(dev);
162 
163 	if (unit >= cgthreecd.cd_ndevs || cgthreecd.cd_devs[unit] == NULL)
164 		return (ENXIO);
165 	return (0);
166 }
167 
168 int
169 cgthreeclose(dev, flags, mode, p)
170 	dev_t dev;
171 	int flags, mode;
172 	struct proc *p;
173 {
174 
175 	return (0);
176 }
177 
178 int
179 cgthreeioctl(dev, cmd, data, flags, p)
180 	dev_t dev;
181 	int cmd;
182 	caddr_t data;
183 	int flags;
184 	struct proc *p;
185 {
186 	register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
187 	register struct fbgattr *fba;
188 
189 	switch (cmd) {
190 
191 	case FBIOGTYPE:
192 		*(struct fbtype *)data = sc->sc_fb.fb_type;
193 		break;
194 
195 	case FBIOGATTR:
196 		fba = (struct fbgattr *)data;
197 		fba->real_type = sc->sc_fb.fb_type.fb_type;
198 		fba->owner = 0;		/* XXX ??? */
199 		fba->fbtype = sc->sc_fb.fb_type;
200 		fba->sattr.flags = 0;
201 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
202 		fba->sattr.dev_specific[0] = -1;
203 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
204 		fba->emu_types[1] = -1;
205 		break;
206 
207 	case FBIOGETCMAP: {
208 		register struct fbcmap *p = (struct fbcmap *)data;
209 		register int i, color, count, error;
210 		register u_char *cp;
211 
212 		/* get color map from software copy */
213 		if ((unsigned)(color = p->index) >= 256 ||
214 		    (unsigned)(count = p->count) > 256 - color)
215 			return (EINVAL);
216 		if (!useracc(p->red, count, B_WRITE) ||
217 		    !useracc(p->green, count, B_WRITE) ||
218 		    !useracc(p->blue, count, B_WRITE))
219 			return (EFAULT);
220 		cp = &sc->sc_cmap.cm_map[color][0];
221 		for (i = 0; i < count; cp += 3, i++) {
222 			p->red[i] = cp[0];
223 			p->green[i] = cp[1];
224 			p->blue[i] = cp[2];
225 		}
226 	}
227 		break;
228 
229 	case FBIOPUTCMAP: {
230 		register struct fbcmap *p = (struct fbcmap *)data;
231 		register int i, color, count, error;
232 		register u_char *cp;
233 		register u_int *ip;
234 
235 		/* update software copy */
236 		if ((unsigned)(color = p->index) >= 256 ||
237 		    (unsigned)(count = p->count) > 256 - color)
238 			return (EINVAL);
239 		if (!useracc(p->red, count, B_READ) ||
240 		    !useracc(p->green, count, B_READ) ||
241 		    !useracc(p->blue, count, B_READ))
242 			return (EFAULT);
243 		cp = &sc->sc_cmap.cm_map[color][0];
244 		for (i = 0; i < count; cp += 3, i++) {
245 			cp[0] = p->red[i];
246 			cp[1] = p->green[i];
247 			cp[2] = p->blue[i];
248 		}
249 		/* then blast them into the chip */
250 		/* XXX should use retrace interrupt */
251 #define	D4M3(x)	((((x) >> 2) << 1) + ((x) >> 2))	/* (x / 4) * 3 */
252 #define	D4M4(x)	((x) & ~3)				/* (x / 4) * 4 */
253 		ip = &sc->sc_cmap.cm_chip[D4M3(color)];
254 		count = D4M3(color + count - 1) - D4M3(color) + 3;
255 		sc->sc_reg->cg3_addr = D4M4(color);
256 		while (--count >= 0)
257 			sc->sc_reg->cg3_cmap = *ip++;
258 	}
259 		break;
260 
261 	case FBIOGVIDEO:
262 		*(int *)data = sc->sc_blanked;
263 		break;
264 
265 	case FBIOSVIDEO:
266 		if (*(int *)data)
267 			cgthreeunblank(&sc->sc_dev);
268 		else {
269 			register volatile struct cgthreereg *cg3 = sc->sc_reg;
270 
271 			sc->sc_blanked = 1;
272 			cg3->cg3_addr = 0x06;	/* command reg */
273 			cg3->cg3_ctrl = 0x70;	/* overlay plane */
274 			cg3->cg3_addr = 0x04;	/* read mask */
275 			cg3->cg3_ctrl = 0x00;	/* color planes */
276 			/* set color 0 to black; scribble on R of color 1 */
277 			cg3->cg3_addr = 0;
278 			cg3->cg3_cmap = 0;
279 		}
280 		break;
281 
282 	default:
283 		return (ENOTTY);
284 	}
285 	return (0);
286 }
287 
288 static void
289 cgthreeunblank(dev)
290 	struct device *dev;
291 {
292 	struct cgthree_softc *sc = (struct cgthree_softc *)dev;
293 	register volatile struct cgthreereg *cg3 = sc->sc_reg;
294 
295 	sc->sc_blanked = 0;
296 	cg3->cg3_addr = 0x06;	/* command reg */
297 	cg3->cg3_ctrl = 0x73;	/* overlay plane */
298 	cg3->cg3_addr = 0x04;	/* read mask */
299 	cg3->cg3_ctrl = 0xff;	/* color planes */
300 	/* restore color 0 and R of color 1 */
301 	cg3->cg3_addr = 0;
302 	cg3->cg3_cmap = sc->sc_cmap.cm_chip[0];
303 }
304 
305 /*
306  * Return the address that would map the given device at the given
307  * offset, allowing for the given protection, or return -1 for error.
308  *
309  * The cg3 is mapped starting at 256KB, for pseudo-compatibility with
310  * the cg4 (which had an overlay plane in the first 128K and an enable
311  * plane in the next 128K).  X11 uses only 256k+ region but tries to
312  * map the whole thing, so we repeatedly map the first 256K to the
313  * first page of the color screen.  If someone tries to use the overlay
314  * and enable regions, they will get a surprise....
315  */
316 int
317 cgthreemap(dev, off, prot)
318 	dev_t dev;
319 	int off, prot;
320 {
321 	register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
322 #define	START	(128*1024 + 128*1024)
323 
324 	if (off & PGOFSET)
325 		panic("cgthreemap");
326 	if ((unsigned)off < START)
327 		off = 0;
328 	else
329 		off -= START;
330 	if ((unsigned)off >= sc->sc_fb.fb_type.fb_size)
331 		return (-1);
332 	/*
333 	 * I turned on PMAP_NC here to disable the cache as I was
334 	 * getting horribly broken behaviour with it on.
335 	 */
336 	return ((int)sc->sc_phys + off + PMAP_OBIO + PMAP_NC);
337 }
338