155135Storek /*
263322Sbostic * Copyright (c) 1992, 1993
363322Sbostic * The Regents of the University of California. All rights reserved.
455135Storek *
555135Storek * This software was developed by the Computer Systems Engineering group
655135Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
755135Storek * contributed to Berkeley.
855135Storek *
955503Sbostic * All advertising materials mentioning features or use of this software
1055503Sbostic * must display the following acknowledgement:
1155503Sbostic * This product includes software developed by the University of
1259213Storek * California, Lawrence Berkeley Laboratory.
1355503Sbostic *
1455135Storek * %sccs.include.redist.c%
1555135Storek *
16*64776Storek * @(#)cgthree.c 8.2 (Berkeley) 10/30/93
1755135Storek *
18*64776Storek * from: $Header: cgthree.c,v 1.8 93/10/31 05:09:24 torek Exp $
1955135Storek */
2055135Storek
2155135Storek /*
2255135Storek * color display (cgthree) driver.
2355135Storek *
2455135Storek * Does not handle interrupts, even though they can occur.
25*64776Storek *
26*64776Storek * XXX should defer colormap updates to vertical retrace interrupts
2755135Storek */
2855135Storek
2956540Sbostic #include <sys/param.h>
3056540Sbostic #include <sys/buf.h>
3156540Sbostic #include <sys/device.h>
3256540Sbostic #include <sys/fbio.h>
3356540Sbostic #include <sys/ioctl.h>
3456540Sbostic #include <sys/malloc.h>
3556540Sbostic #include <sys/mman.h>
3656540Sbostic #include <sys/tty.h>
3755135Storek
3856540Sbostic #include <machine/autoconf.h>
3956540Sbostic #include <machine/pmap.h>
4056540Sbostic #include <machine/fbvar.h>
4155135Storek
42*64776Storek #include <sparc/sbus/btreg.h>
43*64776Storek #include <sparc/sbus/btvar.h>
4456540Sbostic #include <sparc/sbus/cgthreereg.h>
4556540Sbostic #include <sparc/sbus/sbusvar.h>
4655135Storek
4755135Storek /* per-display variables */
4855135Storek struct cgthree_softc {
4955135Storek struct device sc_dev; /* base device */
5055135Storek struct sbusdev sc_sd; /* sbus device */
5155135Storek struct fbdevice sc_fb; /* frame buffer device */
52*64776Storek volatile struct bt_regs *sc_bt; /* Brooktree registers */
5355135Storek caddr_t sc_phys; /* display RAM (phys addr) */
5455135Storek int sc_blanked; /* true if blanked */
55*64776Storek union bt_cmap sc_cmap; /* Brooktree color map */
5655135Storek };
5755135Storek
5855135Storek /* autoconfiguration driver */
5955135Storek static void cgthreeattach(struct device *, struct device *, void *);
6055135Storek struct cfdriver cgthreecd =
6155135Storek { NULL, "cgthree", matchbyname, cgthreeattach,
6255135Storek DV_DULL, sizeof(struct cgthree_softc) };
6355135Storek
6455135Storek /* frame buffer generic driver */
6555135Storek static void cgthreeunblank(struct device *);
6655135Storek static struct fbdriver cgthreefbdriver = { cgthreeunblank };
6755135Storek
6855135Storek extern int fbnode;
6955135Storek extern struct tty *fbconstty;
7055135Storek extern int (*v_putc)();
7155135Storek extern int nullop();
7255135Storek static int cgthree_cnputc();
7355135Storek
74*64776Storek static void cgthreeloadcmap __P((struct cgthree_softc *, int, int));
75*64776Storek
7655135Storek #define CGTHREE_MAJOR 55 /* XXX */
7755135Storek
7855135Storek /*
7955135Storek * Attach a display. We need to notice if it is the console, too.
8055135Storek */
8155135Storek void
cgthreeattach(parent,self,args)8255135Storek cgthreeattach(parent, self, args)
8355135Storek struct device *parent, *self;
8455135Storek void *args;
8555135Storek {
8655135Storek register struct cgthree_softc *sc = (struct cgthree_softc *)self;
8755135Storek register struct sbus_attach_args *sa = args;
8855135Storek register int node = sa->sa_ra.ra_node, ramsize, i;
89*64776Storek register volatile struct bt_regs *bt;
9055135Storek register struct cgthree_all *p;
9155135Storek int isconsole;
9255135Storek
9355135Storek sc->sc_fb.fb_major = CGTHREE_MAJOR; /* XXX to be removed */
9455135Storek
9555135Storek sc->sc_fb.fb_driver = &cgthreefbdriver;
9655135Storek sc->sc_fb.fb_device = &sc->sc_dev;
9755135Storek /*
9855135Storek * The defaults below match my screen, but are not guaranteed
9955135Storek * to be correct as defaults go...
10055135Storek */
10155135Storek sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR;
10255135Storek sc->sc_fb.fb_type.fb_width = getpropint(node, "width", 1152);
10355135Storek sc->sc_fb.fb_type.fb_height = getpropint(node, "height", 900);
10455135Storek sc->sc_fb.fb_linebytes = getpropint(node, "linebytes", 1152);
10555135Storek ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes;
10655135Storek sc->sc_fb.fb_type.fb_depth = 8;
10755135Storek sc->sc_fb.fb_type.fb_cmsize = 256;
10855135Storek sc->sc_fb.fb_type.fb_size = ramsize;
10955135Storek printf(": %s, %d x %d", getpropstring(node, "model"),
11055135Storek sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height);
11155135Storek
11255135Storek /*
11355135Storek * When the ROM has mapped in a cgthree display, the address
11455135Storek * maps only the video RAM, so in any case we have to map the
11555135Storek * registers ourselves. We only need the video RAM if we are
11655135Storek * going to print characters via rconsole.
11755135Storek */
11855135Storek isconsole = node == fbnode && fbconstty != NULL;
11955135Storek p = (struct cgthree_all *)sa->sa_ra.ra_paddr;
12055135Storek if ((sc->sc_fb.fb_pixels = sa->sa_ra.ra_vaddr) == NULL && isconsole) {
12155135Storek /* this probably cannot happen, but what the heck */
12255135Storek sc->sc_fb.fb_pixels = mapiodev(p->ba_ram, ramsize);
12355135Storek }
124*64776Storek sc->sc_bt = bt = (volatile struct bt_regs *)
125*64776Storek mapiodev((caddr_t)&p->ba_btreg, sizeof(p->ba_btreg));
12655135Storek sc->sc_phys = p->ba_ram;
12755135Storek
128*64776Storek /* grab initial (current) color map */
129*64776Storek bt->bt_addr = 0;
13055135Storek for (i = 0; i < 256 * 3 / 4; i++)
131*64776Storek sc->sc_cmap.cm_chip[i] = bt->bt_cmap;
132*64776Storek /* make sure we are not blanked (see cgthreeunblank) */
133*64776Storek bt->bt_addr = 0x06; /* command reg */
134*64776Storek bt->bt_ctrl = 0x73; /* overlay plane */
135*64776Storek bt->bt_addr = 0x04; /* read mask */
136*64776Storek bt->bt_ctrl = 0xff; /* color planes */
13755135Storek
13855135Storek if (isconsole) {
13955135Storek printf(" (console)\n");
14055135Storek #ifdef RCONSOLE
14155135Storek rcons_init(&sc->sc_fb);
14255135Storek #endif
14355135Storek } else
14455135Storek printf("\n");
14555135Storek sbus_establish(&sc->sc_sd, &sc->sc_dev);
14655135Storek if (node == fbnode)
14755135Storek fb_attach(&sc->sc_fb);
14855135Storek }
14955135Storek
15055135Storek int
cgthreeopen(dev,flags,mode,p)15155135Storek cgthreeopen(dev, flags, mode, p)
15255135Storek dev_t dev;
15355135Storek int flags, mode;
15455135Storek struct proc *p;
15555135Storek {
15655135Storek int unit = minor(dev);
15755135Storek
15855135Storek if (unit >= cgthreecd.cd_ndevs || cgthreecd.cd_devs[unit] == NULL)
15955135Storek return (ENXIO);
16055135Storek return (0);
16155135Storek }
16255135Storek
16355135Storek int
cgthreeclose(dev,flags,mode,p)16455135Storek cgthreeclose(dev, flags, mode, p)
16555135Storek dev_t dev;
16655135Storek int flags, mode;
16755135Storek struct proc *p;
16855135Storek {
16955135Storek
17055135Storek return (0);
17155135Storek }
17255135Storek
17355135Storek int
cgthreeioctl(dev,cmd,data,flags,p)17455135Storek cgthreeioctl(dev, cmd, data, flags, p)
17555135Storek dev_t dev;
17655135Storek int cmd;
177*64776Storek register caddr_t data;
17855135Storek int flags;
17955135Storek struct proc *p;
18055135Storek {
18155135Storek register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
18255135Storek register struct fbgattr *fba;
183*64776Storek int error;
18455135Storek
18555135Storek switch (cmd) {
18655135Storek
18755135Storek case FBIOGTYPE:
18855135Storek *(struct fbtype *)data = sc->sc_fb.fb_type;
18955135Storek break;
19055135Storek
19155135Storek case FBIOGATTR:
19255135Storek fba = (struct fbgattr *)data;
19355135Storek fba->real_type = sc->sc_fb.fb_type.fb_type;
19455135Storek fba->owner = 0; /* XXX ??? */
19555135Storek fba->fbtype = sc->sc_fb.fb_type;
19655135Storek fba->sattr.flags = 0;
19755135Storek fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
19855135Storek fba->sattr.dev_specific[0] = -1;
19955135Storek fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
20055135Storek fba->emu_types[1] = -1;
20155135Storek break;
20255135Storek
203*64776Storek case FBIOGETCMAP:
204*64776Storek return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256));
20555135Storek
206*64776Storek case FBIOPUTCMAP:
207*64776Storek /* copy to software map */
208*64776Storek #define p ((struct fbcmap *)data)
209*64776Storek error = bt_putcmap(p, &sc->sc_cmap, 256);
210*64776Storek if (error)
211*64776Storek return (error);
212*64776Storek /* now blast them into the chip */
21355135Storek /* XXX should use retrace interrupt */
214*64776Storek cgthreeloadcmap(sc, p->index, p->count);
215*64776Storek #undef p
21655135Storek break;
21755135Storek
21855135Storek case FBIOGVIDEO:
21955135Storek *(int *)data = sc->sc_blanked;
22055135Storek break;
22155135Storek
22255135Storek case FBIOSVIDEO:
22355135Storek if (*(int *)data)
22455135Storek cgthreeunblank(&sc->sc_dev);
225*64776Storek else if (!sc->sc_blanked) {
226*64776Storek register volatile struct bt_regs *bt;
22755135Storek
228*64776Storek bt = sc->sc_bt;
229*64776Storek bt->bt_addr = 0x06; /* command reg */
230*64776Storek bt->bt_ctrl = 0x70; /* overlay plane */
231*64776Storek bt->bt_addr = 0x04; /* read mask */
232*64776Storek bt->bt_ctrl = 0x00; /* color planes */
233*64776Storek /*
234*64776Storek * Set color 0 to black -- note that this overwrites
235*64776Storek * R of color 1.
236*64776Storek */
237*64776Storek bt->bt_addr = 0;
238*64776Storek bt->bt_cmap = 0;
239*64776Storek
24055135Storek sc->sc_blanked = 1;
24155135Storek }
24255135Storek break;
24355135Storek
24455135Storek default:
24555135Storek return (ENOTTY);
24655135Storek }
24755135Storek return (0);
24855135Storek }
24955135Storek
250*64776Storek /*
251*64776Storek * Undo the effect of an FBIOSVIDEO that turns the video off.
252*64776Storek */
25355135Storek static void
cgthreeunblank(dev)25455135Storek cgthreeunblank(dev)
25555135Storek struct device *dev;
25655135Storek {
25755135Storek struct cgthree_softc *sc = (struct cgthree_softc *)dev;
258*64776Storek register volatile struct bt_regs *bt;
25955135Storek
260*64776Storek if (sc->sc_blanked) {
261*64776Storek sc->sc_blanked = 0;
262*64776Storek bt = sc->sc_bt;
263*64776Storek /* restore color 0 (and R of color 1) */
264*64776Storek bt->bt_addr = 0;
265*64776Storek bt->bt_cmap = sc->sc_cmap.cm_chip[0];
266*64776Storek
267*64776Storek /* restore read mask */
268*64776Storek bt->bt_addr = 0x06; /* command reg */
269*64776Storek bt->bt_ctrl = 0x73; /* overlay plane */
270*64776Storek bt->bt_addr = 0x04; /* read mask */
271*64776Storek bt->bt_ctrl = 0xff; /* color planes */
272*64776Storek }
27355135Storek }
27455135Storek
27555135Storek /*
276*64776Storek * Load a subset of the current (new) colormap into the Brooktree DAC.
277*64776Storek */
278*64776Storek static void
cgthreeloadcmap(sc,start,ncolors)279*64776Storek cgthreeloadcmap(sc, start, ncolors)
280*64776Storek register struct cgthree_softc *sc;
281*64776Storek register int start, ncolors;
282*64776Storek {
283*64776Storek register volatile struct bt_regs *bt;
284*64776Storek register u_int *ip;
285*64776Storek register int count;
286*64776Storek
287*64776Storek ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
288*64776Storek count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
289*64776Storek bt = sc->sc_bt;
290*64776Storek bt->bt_addr = BT_D4M4(start);
291*64776Storek while (--count >= 0)
292*64776Storek bt->bt_cmap = *ip++;
293*64776Storek }
294*64776Storek
295*64776Storek /*
29655135Storek * Return the address that would map the given device at the given
29755135Storek * offset, allowing for the given protection, or return -1 for error.
29855135Storek *
29955135Storek * The cg3 is mapped starting at 256KB, for pseudo-compatibility with
30055135Storek * the cg4 (which had an overlay plane in the first 128K and an enable
30155135Storek * plane in the next 128K). X11 uses only 256k+ region but tries to
30255135Storek * map the whole thing, so we repeatedly map the first 256K to the
30355135Storek * first page of the color screen. If someone tries to use the overlay
30455135Storek * and enable regions, they will get a surprise....
30555135Storek */
30655135Storek int
cgthreemap(dev,off,prot)30755135Storek cgthreemap(dev, off, prot)
30855135Storek dev_t dev;
30955135Storek int off, prot;
31055135Storek {
31155135Storek register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
31255135Storek #define START (128*1024 + 128*1024)
31355135Storek
31455135Storek if (off & PGOFSET)
31555135Storek panic("cgthreemap");
31655135Storek if ((unsigned)off < START)
31755135Storek off = 0;
31855135Storek else
31955135Storek off -= START;
32055135Storek if ((unsigned)off >= sc->sc_fb.fb_type.fb_size)
32155135Storek return (-1);
32255135Storek /*
32355135Storek * I turned on PMAP_NC here to disable the cache as I was
32455135Storek * getting horribly broken behaviour with it on.
32555135Storek */
32655135Storek return ((int)sc->sc_phys + off + PMAP_OBIO + PMAP_NC);
32755135Storek }
328