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