164779Storek /*
2*65800Sbostic * Copyright (c) 1993
3*65800Sbostic * The Regents of the University of California. All rights reserved.
464779Storek *
564779Storek * This software was developed by the Computer Systems Engineering group
664779Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
764779Storek * contributed to Berkeley.
864779Storek *
964779Storek * All advertising materials mentioning features or use of this software
1064779Storek * must display the following acknowledgement:
1164779Storek * This product includes software developed by the University of
1264779Storek * California, Lawrence Berkeley Laboratory.
1364779Storek *
1464779Storek * %sccs.include.redist.c%
1564779Storek *
16*65800Sbostic * @(#)cgsix.c 8.4 (Berkeley) 01/21/94
1764779Storek *
1864779Storek * from: $Header: cgsix.c,v 1.2 93/10/18 00:01:51 torek Exp $
1964779Storek */
2064779Storek
2164779Storek /*
2264779Storek * color display (cgsix) driver.
2364779Storek *
2464779Storek * Does not handle interrupts, even though they can occur.
2564779Storek *
2664779Storek * XXX should defer colormap updates to vertical retrace interrupts
2764779Storek */
2864779Storek
2964779Storek #include <sys/param.h>
3064779Storek #include <sys/buf.h>
3164779Storek #include <sys/device.h>
3264779Storek #include <sys/fbio.h>
3364779Storek #include <sys/ioctl.h>
3464779Storek #include <sys/malloc.h>
3564779Storek #include <sys/mman.h>
3664779Storek #include <sys/tty.h>
3764779Storek
3864779Storek #ifdef DEBUG
3964779Storek #include <sys/proc.h>
4064779Storek #include <sys/syslog.h>
4164779Storek #endif
4264779Storek
4364779Storek #include <machine/autoconf.h>
4464779Storek #include <machine/pmap.h>
4564779Storek #include <machine/fbvar.h>
4664779Storek
4764779Storek #include <sparc/sbus/btreg.h>
4864779Storek #include <sparc/sbus/btvar.h>
4964779Storek #include <sparc/sbus/cgsixreg.h>
5064779Storek #include <sparc/sbus/sbusvar.h>
5164779Storek
5264779Storek union cursor_cmap { /* colormap, like bt_cmap, but tiny */
5364779Storek u_char cm_map[2][3]; /* 2 R/G/B entries */
5464779Storek u_int cm_chip[2]; /* 2 chip equivalents */
5564779Storek };
5664779Storek
5764779Storek struct cg6_cursor { /* cg6 hardware cursor status */
5864779Storek short cc_enable; /* cursor is enabled */
5964779Storek struct fbcurpos cc_pos; /* position */
6064779Storek struct fbcurpos cc_hot; /* hot-spot */
6164779Storek struct fbcurpos cc_size; /* size of mask & image fields */
6264779Storek u_int cc_bits[2][32]; /* space for mask & image bits */
6364779Storek union cursor_cmap cc_color; /* cursor colormap */
6464779Storek };
6564779Storek
6664779Storek /* per-display variables */
6764779Storek struct cgsix_softc {
6864779Storek struct device sc_dev; /* base device */
6964779Storek struct sbusdev sc_sd; /* sbus device */
7064779Storek struct fbdevice sc_fb; /* frame buffer device */
7164779Storek volatile struct cg6_layout *sc_physadr; /* phys addr of h/w */
7264779Storek volatile struct bt_regs *sc_bt; /* Brooktree registers */
7365111Storek volatile int *sc_fhc; /* FHC register */
7464779Storek volatile struct cg6_thc *sc_thc; /* THC registers */
7565141Storek volatile struct cg6_tec_xxx *sc_tec; /* TEC registers */
7665141Storek short sc_fhcrev; /* hardware rev */
7765141Storek short sc_blanked; /* true if blanked */
7864779Storek struct cg6_cursor sc_cursor; /* software cursor info */
7964779Storek union bt_cmap sc_cmap; /* Brooktree color map */
8064779Storek };
8164779Storek
8264779Storek /* autoconfiguration driver */
8364779Storek static void cgsixattach(struct device *, struct device *, void *);
8464779Storek struct cfdriver cgsixcd =
8564779Storek { NULL, "cgsix", matchbyname, cgsixattach,
8664779Storek DV_DULL, sizeof(struct cgsix_softc) };
8764779Storek
8864779Storek /* frame buffer generic driver */
8964779Storek static void cg6_unblank(struct device *);
9064779Storek static struct fbdriver cg6_fbdriver = { cg6_unblank };
9164779Storek
9264779Storek /*
9364779Storek * Unlike the bw2 and cg3 drivers, we do not need to provide an rconsole
9464779Storek * interface, as the cg6 is fast enough.
9564779Storek */
9664779Storek
9764779Storek extern int fbnode;
9864779Storek
9964779Storek #define CGSIX_MAJOR 67 /* XXX */
10064779Storek
10165111Storek static void cg6_reset __P((struct cgsix_softc *));
10264779Storek static void cg6_loadcmap __P((struct cgsix_softc *, int, int));
10364779Storek static void cg6_loadomap __P((struct cgsix_softc *));
10464779Storek static void cg6_setcursor __P((struct cgsix_softc *));/* set position */
10564779Storek static void cg6_loadcursor __P((struct cgsix_softc *));/* set shape */
10664779Storek
10764779Storek /*
10864779Storek * Attach a display.
10964779Storek */
11064779Storek void
cgsixattach(parent,self,args)11164779Storek cgsixattach(parent, self, args)
11264779Storek struct device *parent, *self;
11364779Storek void *args;
11464779Storek {
11564779Storek register struct cgsix_softc *sc = (struct cgsix_softc *)self;
11664779Storek register struct sbus_attach_args *sa = args;
11764779Storek register int node = sa->sa_ra.ra_node, ramsize, i;
11864779Storek register volatile struct bt_regs *bt;
11964779Storek register volatile struct cg6_layout *p;
12064779Storek
12164779Storek sc->sc_fb.fb_major = CGSIX_MAJOR; /* XXX to be removed */
12264779Storek
12364779Storek sc->sc_fb.fb_driver = &cg6_fbdriver;
12464779Storek sc->sc_fb.fb_device = &sc->sc_dev;
12564779Storek sc->sc_fb.fb_type.fb_type = FBTYPE_SUNFAST_COLOR;
12664779Storek sc->sc_fb.fb_type.fb_width = getpropint(node, "width", 1152);
12764779Storek sc->sc_fb.fb_type.fb_height = getpropint(node, "height", 900);
12864779Storek sc->sc_fb.fb_linebytes = getpropint(node, "linebytes", 1152);
12964779Storek ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes;
13064779Storek sc->sc_fb.fb_type.fb_depth = 8;
13164779Storek sc->sc_fb.fb_type.fb_cmsize = 256;
13264779Storek sc->sc_fb.fb_type.fb_size = ramsize;
13364779Storek printf(": %s, %d x %d", getpropstring(node, "model"),
13464779Storek sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height);
13564779Storek
13664779Storek /*
13764779Storek * Dunno what the PROM has mapped, though obviously it must have
13864779Storek * the video RAM mapped. Just map what we care about for ourselves
13965111Storek * (the FHC, THC, and Brooktree registers).
14064779Storek */
14164779Storek sc->sc_physadr = p = (struct cg6_layout *)sa->sa_ra.ra_paddr;
14264779Storek sc->sc_bt = bt = (volatile struct bt_regs *)
14365141Storek mapiodev((caddr_t)&p->cg6_bt_un.un_btregs, sizeof *sc->sc_bt);
14465111Storek sc->sc_fhc = (volatile int *)
14565141Storek mapiodev((caddr_t)&p->cg6_fhc_un.un_fhc, sizeof *sc->sc_fhc);
14664779Storek sc->sc_thc = (volatile struct cg6_thc *)
14765141Storek mapiodev((caddr_t)&p->cg6_thc_un.un_thc, sizeof *sc->sc_thc);
14865141Storek sc->sc_tec = (volatile struct cg6_tec_xxx *)
14965141Storek mapiodev((caddr_t)&p->cg6_tec_un.un_tec, sizeof *sc->sc_tec);
15064779Storek
15165141Storek sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) &
15265141Storek (FHC_REV_MASK >> FHC_REV_SHIFT);
15365141Storek printf(", rev %d", sc->sc_fhcrev);
15465141Storek
15565111Storek /* reset cursor & frame buffer controls */
15665111Storek cg6_reset(sc);
15765111Storek
15864779Storek /* grab initial (current) color map (DOES THIS WORK?) */
15964779Storek bt->bt_addr = 0;
16064779Storek for (i = 0; i < 256 * 3; i++)
16164779Storek ((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24;
16264779Storek
16364779Storek /* enable video */
16464779Storek sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
16564779Storek
16664779Storek printf("\n");
16764779Storek sbus_establish(&sc->sc_sd, &sc->sc_dev);
16864779Storek if (node == fbnode)
16964779Storek fb_attach(&sc->sc_fb);
17064779Storek }
17164779Storek
17264779Storek int
cgsixopen(dev,flags,mode,p)17364779Storek cgsixopen(dev, flags, mode, p)
17464779Storek dev_t dev;
17564779Storek int flags, mode;
17664779Storek struct proc *p;
17764779Storek {
17864779Storek int unit = minor(dev);
17964779Storek
18064779Storek if (unit >= cgsixcd.cd_ndevs || cgsixcd.cd_devs[unit] == NULL)
18164779Storek return (ENXIO);
18264779Storek return (0);
18364779Storek }
18464779Storek
18564779Storek int
cgsixclose(dev,flags,mode,p)18664779Storek cgsixclose(dev, flags, mode, p)
18764779Storek dev_t dev;
18864779Storek int flags, mode;
18964779Storek struct proc *p;
19064779Storek {
19165111Storek struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)];
19264779Storek
19365111Storek cg6_reset(sc);
19464779Storek return (0);
19564779Storek }
19664779Storek
19764779Storek int
cgsixioctl(dev,cmd,data,flags,p)19864779Storek cgsixioctl(dev, cmd, data, flags, p)
19964779Storek dev_t dev;
20064779Storek int cmd;
20164779Storek register caddr_t data;
20264779Storek int flags;
20364779Storek struct proc *p;
20464779Storek {
20564779Storek register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)];
20664779Storek u_int count;
20764779Storek int i, v, error;
20864779Storek union cursor_cmap tcm;
20964779Storek
21064779Storek switch (cmd) {
21164779Storek
21264779Storek case FBIOGTYPE:
21364779Storek *(struct fbtype *)data = sc->sc_fb.fb_type;
21464779Storek break;
21564779Storek
21664779Storek case FBIOGATTR:
21764779Storek #define fba ((struct fbgattr *)data)
21864779Storek fba->real_type = sc->sc_fb.fb_type.fb_type;
21964779Storek fba->owner = 0; /* XXX ??? */
22064779Storek fba->fbtype = sc->sc_fb.fb_type;
22164779Storek fba->sattr.flags = 0;
22264779Storek fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
22364779Storek fba->sattr.dev_specific[0] = -1;
22464779Storek fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
22564779Storek fba->emu_types[1] = -1;
22664779Storek #undef fba
22764779Storek break;
22864779Storek
22964779Storek case FBIOGETCMAP:
23064779Storek return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256));
23164779Storek
23264779Storek case FBIOPUTCMAP:
23364779Storek /* copy to software map */
23464779Storek #define p ((struct fbcmap *)data)
23564779Storek error = bt_putcmap(p, &sc->sc_cmap, 256);
23664779Storek if (error)
23764779Storek return (error);
23864779Storek /* now blast them into the chip */
23964779Storek /* XXX should use retrace interrupt */
24064779Storek cg6_loadcmap(sc, p->index, p->count);
24164779Storek #undef p
24264779Storek break;
24364779Storek
24464779Storek case FBIOGVIDEO:
24564779Storek *(int *)data = sc->sc_blanked;
24664779Storek break;
24764779Storek
24864779Storek case FBIOSVIDEO:
24964779Storek if (*(int *)data)
25064779Storek cg6_unblank(&sc->sc_dev);
25164779Storek else if (!sc->sc_blanked) {
25264779Storek sc->sc_blanked = 1;
25364779Storek sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN;
25464779Storek }
25564779Storek break;
25664779Storek
25764779Storek /* these are for both FBIOSCURSOR and FBIOGCURSOR */
25864779Storek #define p ((struct fbcursor *)data)
25964779Storek #define cc (&sc->sc_cursor)
26064779Storek
26164779Storek case FBIOGCURSOR:
26264779Storek /* do not quite want everything here... */
26364779Storek p->set = FB_CUR_SETALL; /* close enough, anyway */
26464779Storek p->enable = cc->cc_enable;
26564779Storek p->pos = cc->cc_pos;
26664779Storek p->hot = cc->cc_hot;
26764779Storek p->size = cc->cc_size;
26864779Storek
26964779Storek /* begin ugh ... can we lose some of this crap?? */
27064779Storek if (p->image != NULL) {
27164779Storek count = cc->cc_size.y * 32 / NBBY;
27264779Storek error = copyout((caddr_t)cc->cc_bits[1],
27364779Storek (caddr_t)p->image, count);
27464779Storek if (error)
27564779Storek return (error);
27664779Storek error = copyout((caddr_t)cc->cc_bits[0],
27764779Storek (caddr_t)p->mask, count);
27864779Storek if (error)
27964779Storek return (error);
28064779Storek }
28164779Storek if (p->cmap.red != NULL) {
28264779Storek error = bt_getcmap(&p->cmap,
28364779Storek (union bt_cmap *)&cc->cc_color, 2);
28464779Storek if (error)
28564779Storek return (error);
28664779Storek } else {
28764779Storek p->cmap.index = 0;
28864779Storek p->cmap.count = 2;
28964779Storek }
29064779Storek /* end ugh */
29164779Storek break;
29264779Storek
29364779Storek case FBIOSCURSOR:
29464779Storek /*
29564779Storek * For setcmap and setshape, verify parameters, so that
29664779Storek * we do not get halfway through an update and then crap
29764779Storek * out with the software state screwed up.
29864779Storek */
29964779Storek v = p->set;
30064779Storek if (v & FB_CUR_SETCMAP) {
30164779Storek /*
30264779Storek * This use of a temporary copy of the cursor
30364779Storek * colormap is not terribly efficient, but these
30464779Storek * copies are small (8 bytes)...
30564779Storek */
30664779Storek tcm = cc->cc_color;
30764779Storek error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2);
30864779Storek if (error)
30964779Storek return (error);
31064779Storek }
31164779Storek if (v & FB_CUR_SETSHAPE) {
31264779Storek if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32)
31364779Storek return (EINVAL);
31464779Storek count = p->size.y * 32 / NBBY;
31564779Storek if (!useracc(p->image, count, B_READ) ||
31664779Storek !useracc(p->mask, count, B_READ))
31764779Storek return (EFAULT);
31864779Storek }
31964779Storek
32064779Storek /* parameters are OK; do it */
32164779Storek if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) {
32264779Storek if (v & FB_CUR_SETCUR)
32364779Storek cc->cc_enable = p->enable;
32464779Storek if (v & FB_CUR_SETPOS)
32564779Storek cc->cc_pos = p->pos;
32664779Storek if (v & FB_CUR_SETHOT)
32764779Storek cc->cc_hot = p->hot;
32864779Storek cg6_setcursor(sc);
32964779Storek }
33064779Storek if (v & FB_CUR_SETCMAP) {
33164779Storek cc->cc_color = tcm;
33264779Storek cg6_loadomap(sc); /* XXX defer to vertical retrace */
33364779Storek }
33464779Storek if (v & FB_CUR_SETSHAPE) {
33564779Storek cc->cc_size = p->size;
33664779Storek count = p->size.y * 32 / NBBY;
33764779Storek bzero((caddr_t)cc->cc_bits, sizeof cc->cc_bits);
33864779Storek bcopy(p->mask, (caddr_t)cc->cc_bits[0], count);
33964779Storek bcopy(p->image, (caddr_t)cc->cc_bits[1], count);
34064779Storek cg6_loadcursor(sc);
34164779Storek }
34264779Storek break;
34364779Storek
34464779Storek #undef p
34564779Storek #undef cc
34664779Storek
34764779Storek case FBIOGCURPOS:
34864779Storek *(struct fbcurpos *)data = sc->sc_cursor.cc_pos;
34964779Storek break;
35064779Storek
35164779Storek case FBIOSCURPOS:
35264779Storek sc->sc_cursor.cc_pos = *(struct fbcurpos *)data;
35364779Storek cg6_setcursor(sc);
35464779Storek break;
35564779Storek
35664779Storek case FBIOGCURMAX:
35764779Storek /* max cursor size is 32x32 */
35864779Storek ((struct fbcurpos *)data)->x = 32;
35964779Storek ((struct fbcurpos *)data)->y = 32;
36064779Storek break;
36164779Storek
36264779Storek default:
36364779Storek #ifdef DEBUG
36464779Storek log(LOG_NOTICE, "cgsixioctl(%x) (%s[%d])\n", cmd,
36564779Storek p->p_comm, p->p_pid);
36664779Storek #endif
36764779Storek return (ENOTTY);
36864779Storek }
36964779Storek return (0);
37064779Storek }
37164779Storek
37265111Storek /*
37365111Storek * Clean up hardware state (e.g., after bootup or after X crashes).
37465111Storek */
37564779Storek static void
cg6_reset(sc)37665111Storek cg6_reset(sc)
37765111Storek register struct cgsix_softc *sc;
37865111Storek {
37965141Storek register volatile struct cg6_tec_xxx *tec;
38065141Storek register int fhc;
38165111Storek register volatile struct bt_regs *bt;
38265111Storek
38365111Storek /* hide the cursor, just in case */
38465111Storek sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF;
38565111Storek
38665141Storek /* turn off frobs in transform engine (makes X11 work) */
38765141Storek tec = sc->sc_tec;
38865141Storek tec->tec_mv = 0;
38965141Storek tec->tec_clip = 0;
39065141Storek tec->tec_vdc = 0;
39165141Storek
39265141Storek /* take care of hardware bugs in old revisions */
39365141Storek if (sc->sc_fhcrev < 5) {
39465111Storek /*
39565111Storek * Keep current resolution; set cpu to 68020, set test
39665111Storek * window (size 1Kx1K), and for rev 1, disable dest cache.
39765111Storek */
39865141Storek fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 |
39965141Storek FHC_TEST |
40065111Storek (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT);
40165141Storek if (sc->sc_fhcrev < 2)
40265141Storek fhc |= FHC_DST_DISABLE;
40365141Storek *sc->sc_fhc = fhc;
40465111Storek }
40565111Storek
40665111Storek /* Enable cursor in Brooktree DAC. */
40765111Storek bt = sc->sc_bt;
40865111Storek bt->bt_addr = 0x06 << 24;
40965111Storek bt->bt_ctrl |= 0x03 << 24;
41065111Storek }
41165111Storek
41265111Storek static void
cg6_setcursor(sc)41364779Storek cg6_setcursor(sc)
41464779Storek register struct cgsix_softc *sc;
41564779Storek {
41664779Storek
41764779Storek /* we need to subtract the hot-spot value here */
41864779Storek #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f)
41964779Storek sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ?
42064779Storek ((COORD(x) << 16) | (COORD(y) & 0xffff)) :
42164779Storek (THC_CURSOFF << 16) | THC_CURSOFF;
42264779Storek #undef COORD
42364779Storek }
42464779Storek
42564779Storek static void
cg6_loadcursor(sc)42664779Storek cg6_loadcursor(sc)
42764779Storek register struct cgsix_softc *sc;
42864779Storek {
42964779Storek register volatile struct cg6_thc *thc;
43064779Storek register u_int edgemask, m;
43164779Storek register int i;
43264779Storek
43364779Storek /*
43464779Storek * Keep the top size.x bits. Here we *throw out* the top
43564779Storek * size.x bits from an all-one-bits word, introducing zeros in
43664779Storek * the top size.x bits, then invert all the bits to get what
43764779Storek * we really wanted as our mask. But this fails if size.x is
43864779Storek * 32---a sparc uses only the low 5 bits of the shift count---
43964779Storek * so we have to special case that.
44064779Storek */
44164779Storek edgemask = ~0;
44264779Storek if (sc->sc_cursor.cc_size.x < 32)
44364779Storek edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x);
44464779Storek thc = sc->sc_thc;
44564779Storek for (i = 0; i < 32; i++) {
44664779Storek m = sc->sc_cursor.cc_bits[0][i] & edgemask;
44764779Storek thc->thc_cursmask[i] = m;
44864779Storek thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i];
44964779Storek }
45064779Storek }
45164779Storek
45264779Storek /*
45364779Storek * Load a subset of the current (new) colormap into the color DAC.
45464779Storek */
45564779Storek static void
cg6_loadcmap(sc,start,ncolors)45664779Storek cg6_loadcmap(sc, start, ncolors)
45764779Storek register struct cgsix_softc *sc;
45864779Storek register int start, ncolors;
45964779Storek {
46064779Storek register volatile struct bt_regs *bt;
46164779Storek register u_int *ip, i;
46264779Storek register int count;
46364779Storek
46464779Storek ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
46564779Storek count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
46664779Storek bt = sc->sc_bt;
46764779Storek bt->bt_addr = BT_D4M4(start) << 24;
46864779Storek while (--count >= 0) {
46964779Storek i = *ip++;
47064779Storek /* hardware that makes one want to pound boards with hammers */
47164779Storek bt->bt_cmap = i;
47264779Storek bt->bt_cmap = i << 8;
47364779Storek bt->bt_cmap = i << 16;
47464779Storek bt->bt_cmap = i << 24;
47564779Storek }
47664779Storek }
47764779Storek
47864779Storek /*
47964779Storek * Load the cursor (overlay `foreground' and `background') colors.
48064779Storek */
48164779Storek static void
cg6_loadomap(sc)48264779Storek cg6_loadomap(sc)
48364779Storek register struct cgsix_softc *sc;
48464779Storek {
48564779Storek register volatile struct bt_regs *bt;
48664779Storek register u_int i;
48764779Storek
48864779Storek bt = sc->sc_bt;
48964779Storek bt->bt_addr = 0x01 << 24; /* set background color */
49064779Storek i = sc->sc_cursor.cc_color.cm_chip[0];
49164779Storek bt->bt_omap = i; /* R */
49264779Storek bt->bt_omap = i << 8; /* G */
49364779Storek bt->bt_omap = i << 16; /* B */
49464779Storek
49564779Storek bt->bt_addr = 0x03 << 24; /* set foreground color */
49664779Storek bt->bt_omap = i << 24; /* R */
49764779Storek i = sc->sc_cursor.cc_color.cm_chip[1];
49864779Storek bt->bt_omap = i; /* G */
49964779Storek bt->bt_omap = i << 8; /* B */
50064779Storek }
50164779Storek
50264779Storek static void
cg6_unblank(dev)50364779Storek cg6_unblank(dev)
50464779Storek struct device *dev;
50564779Storek {
50664779Storek struct cgsix_softc *sc = (struct cgsix_softc *)dev;
50764779Storek
50864779Storek if (sc->sc_blanked) {
50964779Storek sc->sc_blanked = 0;
51064779Storek sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
51164779Storek }
51264779Storek }
51364779Storek
51464779Storek /* XXX the following should be moved to a "user interface" header */
51564779Storek /*
51664779Storek * Base addresses at which users can mmap() the various pieces of a cg6.
51764779Storek * Note that although the Brooktree color registers do not occupy 8K,
51864779Storek * the X server dies if we do not allow it to map 8K there (it just maps
51964779Storek * from 0x70000000 forwards, as a contiguous chunk).
52064779Storek */
52164779Storek #define CG6_USER_FBC 0x70000000
52264779Storek #define CG6_USER_TEC 0x70001000
52364779Storek #define CG6_USER_BTREGS 0x70002000
52464779Storek #define CG6_USER_FHC 0x70004000
52564779Storek #define CG6_USER_THC 0x70005000
52664779Storek #define CG6_USER_ROM 0x70006000
52764779Storek #define CG6_USER_RAM 0x70016000
52864779Storek #define CG6_USER_DHC 0x80000000
52964779Storek
53064779Storek struct mmo {
53164779Storek u_int mo_uaddr; /* user (virtual) address */
53264779Storek u_int mo_size; /* size, or 0 for video ram size */
53364779Storek u_int mo_physoff; /* offset from sc_physadr */
53464779Storek };
53564779Storek
53664779Storek /*
53764779Storek * Return the address that would map the given device at the given
53864779Storek * offset, allowing for the given protection, or return -1 for error.
53964779Storek *
54064779Storek * XXX needs testing against `demanding' applications (e.g., aviator)
54164779Storek */
54264779Storek int
cgsixmap(dev,off,prot)54364779Storek cgsixmap(dev, off, prot)
54464779Storek dev_t dev;
54564779Storek int off, prot;
54664779Storek {
54764779Storek register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)];
54864779Storek register struct mmo *mo;
54964779Storek register u_int u, sz;
55064779Storek #define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb))
55164779Storek static struct mmo mmo[] = {
55264779Storek { CG6_USER_RAM, 0, O(cg6_ram) },
55364779Storek
55464779Storek /* do not actually know how big most of these are! */
55564779Storek { CG6_USER_FBC, 1, O(cg6_fbc_un) },
55664779Storek { CG6_USER_TEC, 1, O(cg6_tec_un) },
55764779Storek { CG6_USER_BTREGS, 8192 /* XXX */, O(cg6_bt_un) },
55864779Storek { CG6_USER_FHC, 1, O(cg6_fhc_un) },
55964779Storek { CG6_USER_THC, sizeof(struct cg6_thc), O(cg6_thc_un) },
56064779Storek { CG6_USER_ROM, 65536, O(cg6_rom_un) },
56164779Storek { CG6_USER_DHC, 1, O(cg6_dhc_un) },
56264779Storek };
56364779Storek #define NMMO (sizeof mmo / sizeof *mmo)
56464779Storek
56564779Storek if (off & PGOFSET)
56664779Storek panic("cgsixmap");
56764779Storek
56864779Storek /*
56964779Storek * Entries with size 0 map video RAM (i.e., the size in fb data).
57064779Storek *
57164779Storek * Since we work in pages, the fact that the map offset table's
57264779Storek * sizes are sometimes bizarre (e.g., 1) is effectively ignored:
57364779Storek * one byte is as good as one page.
57464779Storek */
57564779Storek for (mo = mmo; mo < &mmo[NMMO]; mo++) {
57664779Storek if ((u_int)off < mo->mo_uaddr)
57764779Storek continue;
57864779Storek u = off - mo->mo_uaddr;
57964779Storek sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size;
58064779Storek if (u < sz)
58164779Storek return ((int)sc->sc_physadr + u + mo->mo_physoff +
58264779Storek PMAP_OBIO + PMAP_NC);
58364779Storek }
58464779Storek #ifdef DEBUG
58564779Storek {
58664779Storek register struct proc *p = curproc; /* XXX */
58764779Storek log(LOG_NOTICE, "cgsixmap(%x) (%s[%d])\n", off, p->p_comm, p->p_pid);
58864779Storek }
58964779Storek #endif
59064779Storek return (-1); /* not a user-map offset */
59164779Storek }
592