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