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