1 /*
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This software was developed by the Computer Systems Engineering group
6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7 * contributed to Berkeley.
8 *
9 * All advertising materials mentioning features or use of this software
10 * must display the following acknowledgement:
11 * This product includes software developed by the University of
12 * California, Lawrence Berkeley Laboratory.
13 *
14 * %sccs.include.redist.c%
15 *
16 * @(#)cgthree.c 8.2 (Berkeley) 10/30/93
17 *
18 * from: $Header: cgthree.c,v 1.8 93/10/31 05:09:24 torek Exp $
19 */
20
21 /*
22 * color display (cgthree) driver.
23 *
24 * Does not handle interrupts, even though they can occur.
25 *
26 * XXX should defer colormap updates to vertical retrace interrupts
27 */
28
29 #include <sys/param.h>
30 #include <sys/buf.h>
31 #include <sys/device.h>
32 #include <sys/fbio.h>
33 #include <sys/ioctl.h>
34 #include <sys/malloc.h>
35 #include <sys/mman.h>
36 #include <sys/tty.h>
37
38 #include <machine/autoconf.h>
39 #include <machine/pmap.h>
40 #include <machine/fbvar.h>
41
42 #include <sparc/sbus/btreg.h>
43 #include <sparc/sbus/btvar.h>
44 #include <sparc/sbus/cgthreereg.h>
45 #include <sparc/sbus/sbusvar.h>
46
47 /* per-display variables */
48 struct cgthree_softc {
49 struct device sc_dev; /* base device */
50 struct sbusdev sc_sd; /* sbus device */
51 struct fbdevice sc_fb; /* frame buffer device */
52 volatile struct bt_regs *sc_bt; /* Brooktree registers */
53 caddr_t sc_phys; /* display RAM (phys addr) */
54 int sc_blanked; /* true if blanked */
55 union bt_cmap sc_cmap; /* Brooktree color map */
56 };
57
58 /* autoconfiguration driver */
59 static void cgthreeattach(struct device *, struct device *, void *);
60 struct cfdriver cgthreecd =
61 { NULL, "cgthree", matchbyname, cgthreeattach,
62 DV_DULL, sizeof(struct cgthree_softc) };
63
64 /* frame buffer generic driver */
65 static void cgthreeunblank(struct device *);
66 static struct fbdriver cgthreefbdriver = { cgthreeunblank };
67
68 extern int fbnode;
69 extern struct tty *fbconstty;
70 extern int (*v_putc)();
71 extern int nullop();
72 static int cgthree_cnputc();
73
74 static void cgthreeloadcmap __P((struct cgthree_softc *, int, int));
75
76 #define CGTHREE_MAJOR 55 /* XXX */
77
78 /*
79 * Attach a display. We need to notice if it is the console, too.
80 */
81 void
cgthreeattach(parent,self,args)82 cgthreeattach(parent, self, args)
83 struct device *parent, *self;
84 void *args;
85 {
86 register struct cgthree_softc *sc = (struct cgthree_softc *)self;
87 register struct sbus_attach_args *sa = args;
88 register int node = sa->sa_ra.ra_node, ramsize, i;
89 register volatile struct bt_regs *bt;
90 register struct cgthree_all *p;
91 int isconsole;
92
93 sc->sc_fb.fb_major = CGTHREE_MAJOR; /* XXX to be removed */
94
95 sc->sc_fb.fb_driver = &cgthreefbdriver;
96 sc->sc_fb.fb_device = &sc->sc_dev;
97 /*
98 * The defaults below match my screen, but are not guaranteed
99 * to be correct as defaults go...
100 */
101 sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR;
102 sc->sc_fb.fb_type.fb_width = getpropint(node, "width", 1152);
103 sc->sc_fb.fb_type.fb_height = getpropint(node, "height", 900);
104 sc->sc_fb.fb_linebytes = getpropint(node, "linebytes", 1152);
105 ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes;
106 sc->sc_fb.fb_type.fb_depth = 8;
107 sc->sc_fb.fb_type.fb_cmsize = 256;
108 sc->sc_fb.fb_type.fb_size = ramsize;
109 printf(": %s, %d x %d", getpropstring(node, "model"),
110 sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height);
111
112 /*
113 * When the ROM has mapped in a cgthree display, the address
114 * maps only the video RAM, so in any case we have to map the
115 * registers ourselves. We only need the video RAM if we are
116 * going to print characters via rconsole.
117 */
118 isconsole = node == fbnode && fbconstty != NULL;
119 p = (struct cgthree_all *)sa->sa_ra.ra_paddr;
120 if ((sc->sc_fb.fb_pixels = sa->sa_ra.ra_vaddr) == NULL && isconsole) {
121 /* this probably cannot happen, but what the heck */
122 sc->sc_fb.fb_pixels = mapiodev(p->ba_ram, ramsize);
123 }
124 sc->sc_bt = bt = (volatile struct bt_regs *)
125 mapiodev((caddr_t)&p->ba_btreg, sizeof(p->ba_btreg));
126 sc->sc_phys = p->ba_ram;
127
128 /* grab initial (current) color map */
129 bt->bt_addr = 0;
130 for (i = 0; i < 256 * 3 / 4; i++)
131 sc->sc_cmap.cm_chip[i] = bt->bt_cmap;
132 /* make sure we are not blanked (see cgthreeunblank) */
133 bt->bt_addr = 0x06; /* command reg */
134 bt->bt_ctrl = 0x73; /* overlay plane */
135 bt->bt_addr = 0x04; /* read mask */
136 bt->bt_ctrl = 0xff; /* color planes */
137
138 if (isconsole) {
139 printf(" (console)\n");
140 #ifdef RCONSOLE
141 rcons_init(&sc->sc_fb);
142 #endif
143 } else
144 printf("\n");
145 sbus_establish(&sc->sc_sd, &sc->sc_dev);
146 if (node == fbnode)
147 fb_attach(&sc->sc_fb);
148 }
149
150 int
cgthreeopen(dev,flags,mode,p)151 cgthreeopen(dev, flags, mode, p)
152 dev_t dev;
153 int flags, mode;
154 struct proc *p;
155 {
156 int unit = minor(dev);
157
158 if (unit >= cgthreecd.cd_ndevs || cgthreecd.cd_devs[unit] == NULL)
159 return (ENXIO);
160 return (0);
161 }
162
163 int
cgthreeclose(dev,flags,mode,p)164 cgthreeclose(dev, flags, mode, p)
165 dev_t dev;
166 int flags, mode;
167 struct proc *p;
168 {
169
170 return (0);
171 }
172
173 int
cgthreeioctl(dev,cmd,data,flags,p)174 cgthreeioctl(dev, cmd, data, flags, p)
175 dev_t dev;
176 int cmd;
177 register caddr_t data;
178 int flags;
179 struct proc *p;
180 {
181 register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
182 register struct fbgattr *fba;
183 int error;
184
185 switch (cmd) {
186
187 case FBIOGTYPE:
188 *(struct fbtype *)data = sc->sc_fb.fb_type;
189 break;
190
191 case FBIOGATTR:
192 fba = (struct fbgattr *)data;
193 fba->real_type = sc->sc_fb.fb_type.fb_type;
194 fba->owner = 0; /* XXX ??? */
195 fba->fbtype = sc->sc_fb.fb_type;
196 fba->sattr.flags = 0;
197 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
198 fba->sattr.dev_specific[0] = -1;
199 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
200 fba->emu_types[1] = -1;
201 break;
202
203 case FBIOGETCMAP:
204 return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256));
205
206 case FBIOPUTCMAP:
207 /* copy to software map */
208 #define p ((struct fbcmap *)data)
209 error = bt_putcmap(p, &sc->sc_cmap, 256);
210 if (error)
211 return (error);
212 /* now blast them into the chip */
213 /* XXX should use retrace interrupt */
214 cgthreeloadcmap(sc, p->index, p->count);
215 #undef p
216 break;
217
218 case FBIOGVIDEO:
219 *(int *)data = sc->sc_blanked;
220 break;
221
222 case FBIOSVIDEO:
223 if (*(int *)data)
224 cgthreeunblank(&sc->sc_dev);
225 else if (!sc->sc_blanked) {
226 register volatile struct bt_regs *bt;
227
228 bt = sc->sc_bt;
229 bt->bt_addr = 0x06; /* command reg */
230 bt->bt_ctrl = 0x70; /* overlay plane */
231 bt->bt_addr = 0x04; /* read mask */
232 bt->bt_ctrl = 0x00; /* color planes */
233 /*
234 * Set color 0 to black -- note that this overwrites
235 * R of color 1.
236 */
237 bt->bt_addr = 0;
238 bt->bt_cmap = 0;
239
240 sc->sc_blanked = 1;
241 }
242 break;
243
244 default:
245 return (ENOTTY);
246 }
247 return (0);
248 }
249
250 /*
251 * Undo the effect of an FBIOSVIDEO that turns the video off.
252 */
253 static void
cgthreeunblank(dev)254 cgthreeunblank(dev)
255 struct device *dev;
256 {
257 struct cgthree_softc *sc = (struct cgthree_softc *)dev;
258 register volatile struct bt_regs *bt;
259
260 if (sc->sc_blanked) {
261 sc->sc_blanked = 0;
262 bt = sc->sc_bt;
263 /* restore color 0 (and R of color 1) */
264 bt->bt_addr = 0;
265 bt->bt_cmap = sc->sc_cmap.cm_chip[0];
266
267 /* restore read mask */
268 bt->bt_addr = 0x06; /* command reg */
269 bt->bt_ctrl = 0x73; /* overlay plane */
270 bt->bt_addr = 0x04; /* read mask */
271 bt->bt_ctrl = 0xff; /* color planes */
272 }
273 }
274
275 /*
276 * Load a subset of the current (new) colormap into the Brooktree DAC.
277 */
278 static void
cgthreeloadcmap(sc,start,ncolors)279 cgthreeloadcmap(sc, start, ncolors)
280 register struct cgthree_softc *sc;
281 register int start, ncolors;
282 {
283 register volatile struct bt_regs *bt;
284 register u_int *ip;
285 register int count;
286
287 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
288 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
289 bt = sc->sc_bt;
290 bt->bt_addr = BT_D4M4(start);
291 while (--count >= 0)
292 bt->bt_cmap = *ip++;
293 }
294
295 /*
296 * Return the address that would map the given device at the given
297 * offset, allowing for the given protection, or return -1 for error.
298 *
299 * The cg3 is mapped starting at 256KB, for pseudo-compatibility with
300 * the cg4 (which had an overlay plane in the first 128K and an enable
301 * plane in the next 128K). X11 uses only 256k+ region but tries to
302 * map the whole thing, so we repeatedly map the first 256K to the
303 * first page of the color screen. If someone tries to use the overlay
304 * and enable regions, they will get a surprise....
305 */
306 int
cgthreemap(dev,off,prot)307 cgthreemap(dev, off, prot)
308 dev_t dev;
309 int off, prot;
310 {
311 register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
312 #define START (128*1024 + 128*1024)
313
314 if (off & PGOFSET)
315 panic("cgthreemap");
316 if ((unsigned)off < START)
317 off = 0;
318 else
319 off -= START;
320 if ((unsigned)off >= sc->sc_fb.fb_type.fb_size)
321 return (-1);
322 /*
323 * I turned on PMAP_NC here to disable the cache as I was
324 * getting horribly broken behaviour with it on.
325 */
326 return ((int)sc->sc_phys + off + PMAP_OBIO + PMAP_NC);
327 }
328