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