cg4.c revision 1.11 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