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