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