tcx.c revision 1.2 1 /* $NetBSD: tcx.c,v 1.2 2000/08/22 21:18:57 pk Exp $ */
2
3 /*
4 * Copyright (c) 1996,1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * color display (TCX) driver.
41 *
42 * Does not handle interrupts, even though they can occur.
43 *
44 * XXX should defer colormap updates to vertical retrace interrupts
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/buf.h>
50 #include <sys/device.h>
51 #include <sys/ioctl.h>
52 #include <sys/malloc.h>
53 #include <sys/mman.h>
54 #include <sys/tty.h>
55 #include <sys/conf.h>
56
57 #ifdef DEBUG
58 #include <sys/proc.h>
59 #include <sys/syslog.h>
60 #endif
61
62 #include <machine/bus.h>
63 #include <machine/autoconf.h>
64
65 #include <dev/sun/fbio.h>
66 #include <dev/sun/fbvar.h>
67 #include <dev/sun/btreg.h>
68 #include <dev/sun/btvar.h>
69
70 #include <dev/sbus/sbusvar.h>
71 #include <dev/sbus/tcxreg.h>
72
73 #include <machine/conf.h>
74
75 /* per-display variables */
76 struct tcx_softc {
77 struct device sc_dev; /* base device */
78 struct sbusdev sc_sd; /* sbus device */
79 struct fbdevice sc_fb; /* frame buffer device */
80 bus_space_tag_t sc_bustag;
81 struct sbus_reg sc_physadr[TCX_NREG]; /* phys addr of h/w */
82
83 volatile struct bt_regs *sc_bt; /* Brooktree registers */
84 volatile struct tcx_thc *sc_thc;/* THC registers */
85 short sc_blanked; /* true if blanked */
86 union bt_cmap sc_cmap; /* Brooktree color map */
87 };
88
89 /* autoconfiguration driver */
90 static void tcxattach __P((struct device *, struct device *, void *));
91 static int tcxmatch __P((struct device *, struct cfdata *, void *));
92 static void tcx_unblank __P((struct device *));
93
94 /* cdevsw prototypes */
95 cdev_decl(tcx);
96
97 struct cfattach tcx_ca = {
98 sizeof(struct tcx_softc), tcxmatch, tcxattach
99 };
100
101 extern struct cfdriver tcx_cd;
102
103 /* frame buffer generic driver */
104 static struct fbdriver tcx_fbdriver = {
105 tcx_unblank, tcxopen, tcxclose, tcxioctl, tcxpoll, tcxmmap
106 };
107
108 static void tcx_reset __P((struct tcx_softc *));
109 static void tcx_loadcmap __P((struct tcx_softc *, int, int));
110
111 #define OBPNAME "SUNW,tcx"
112 /*
113 * Match a tcx.
114 */
115 int
116 tcxmatch(parent, cf, aux)
117 struct device *parent;
118 struct cfdata *cf;
119 void *aux;
120 {
121 struct sbus_attach_args *sa = aux;
122
123 return (strcmp(sa->sa_name, OBPNAME) == 0);
124 }
125
126 /*
127 * Attach a display.
128 */
129 void
130 tcxattach(parent, self, args)
131 struct device *parent, *self;
132 void *args;
133 {
134 struct tcx_softc *sc = (struct tcx_softc *)self;
135 struct sbus_attach_args *sa = args;
136 int node, ramsize;
137 volatile struct bt_regs *bt;
138 struct fbdevice *fb = &sc->sc_fb;
139 bus_space_handle_t bh;
140 int isconsole;
141
142 sc->sc_bustag = sa->sa_bustag;
143 node = sa->sa_node;
144
145 fb->fb_driver = &tcx_fbdriver;
146 fb->fb_device = &sc->sc_dev;
147 /* Mask out invalid flags from the user. */
148 fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK;
149 fb->fb_type.fb_depth = node_has_property(node, "tcx-24-bit")
150 ? 24
151 : (node_has_property(node, "tcx-8-bit")
152 ? 8
153 : 8);
154
155 fb_setsize_obp(fb, fb->fb_type.fb_depth, 1152, 900, node);
156
157 ramsize = fb->fb_type.fb_height * fb->fb_linebytes;
158 fb->fb_type.fb_cmsize = 256;
159 fb->fb_type.fb_size = ramsize;
160 printf(": %s, %d x %d", OBPNAME,
161 fb->fb_type.fb_width,
162 fb->fb_type.fb_height);
163
164 /*
165 * XXX - should be set to FBTYPE_TCX.
166 * XXX For CG3 emulation to work in current (96/6) X11 servers,
167 * XXX `fbtype' must point to an "unregocnised" entry.
168 */
169 fb->fb_type.fb_type = FBTYPE_RESERVED3;
170
171
172 if (sa->sa_nreg != TCX_NREG) {
173 printf("%s: only %d register sets\n",
174 self->dv_xname, sa->sa_nreg);
175 return;
176 }
177 bcopy(sa->sa_reg, sc->sc_physadr,
178 sa->sa_nreg * sizeof(struct sbus_reg));
179
180 /* XXX - fix THC and TEC offsets */
181 sc->sc_physadr[TCX_REG_TEC].sbr_offset += 0x1000;
182 sc->sc_physadr[TCX_REG_THC].sbr_offset += 0x1000;
183
184 /* Map the register banks we care about */
185 if (sbus_bus_map(sa->sa_bustag,
186 (bus_type_t)sc->sc_physadr[TCX_REG_THC].sbr_slot,
187 (bus_addr_t)sc->sc_physadr[TCX_REG_THC].sbr_offset,
188 sizeof (struct tcx_thc),
189 BUS_SPACE_MAP_LINEAR,
190 0, &bh) != 0) {
191 printf("tcxattach: cannot map thc registers\n");
192 return;
193 }
194 sc->sc_thc = (volatile struct tcx_thc *)bh;
195
196 if (sbus_bus_map(sa->sa_bustag,
197 (bus_type_t)sc->sc_physadr[TCX_REG_CMAP].sbr_slot,
198 (bus_addr_t)sc->sc_physadr[TCX_REG_CMAP].sbr_offset,
199 sizeof (struct bt_regs),
200 BUS_SPACE_MAP_LINEAR,
201 0, &bh) != 0) {
202 printf("tcxattach: cannot map bt registers\n");
203 return;
204 }
205 sc->sc_bt = bt = (volatile struct bt_regs *)bh;
206
207 isconsole = fb_is_console(node);
208
209 printf(", id %d, rev %d, sense %d",
210 (sc->sc_thc->thc_config & THC_CFG_FBID) >> THC_CFG_FBID_SHIFT,
211 (sc->sc_thc->thc_config & THC_CFG_REV) >> THC_CFG_REV_SHIFT,
212 (sc->sc_thc->thc_config & THC_CFG_SENSE) >> THC_CFG_SENSE_SHIFT
213 );
214
215 /* reset cursor & frame buffer controls */
216 tcx_reset(sc);
217
218 /* Initialize the default color map. */
219 bt_initcmap(&sc->sc_cmap, 256);
220 tcx_loadcmap(sc, 0, 256);
221
222 /* enable video */
223 sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN;
224
225 if (isconsole) {
226 printf(" (console)\n");
227 } else
228 printf("\n");
229
230 sbus_establish(&sc->sc_sd, &sc->sc_dev);
231 fb_attach(&sc->sc_fb, isconsole);
232 }
233
234 int
235 tcxopen(dev, flags, mode, p)
236 dev_t dev;
237 int flags, mode;
238 struct proc *p;
239 {
240 int unit = minor(dev);
241
242 if (unit >= tcx_cd.cd_ndevs || tcx_cd.cd_devs[unit] == NULL)
243 return (ENXIO);
244 return (0);
245 }
246
247 int
248 tcxclose(dev, flags, mode, p)
249 dev_t dev;
250 int flags, mode;
251 struct proc *p;
252 {
253 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)];
254
255 tcx_reset(sc);
256 return (0);
257 }
258
259 int
260 tcxioctl(dev, cmd, data, flags, p)
261 dev_t dev;
262 u_long cmd;
263 caddr_t data;
264 int flags;
265 struct proc *p;
266 {
267 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)];
268 int error;
269
270 switch (cmd) {
271
272 case FBIOGTYPE:
273 *(struct fbtype *)data = sc->sc_fb.fb_type;
274 break;
275
276 case FBIOGATTR:
277 #define fba ((struct fbgattr *)data)
278 fba->real_type = sc->sc_fb.fb_type.fb_type;
279 fba->owner = 0; /* XXX ??? */
280 fba->fbtype = sc->sc_fb.fb_type;
281 fba->sattr.flags = 0;
282 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
283 fba->sattr.dev_specific[0] = -1;
284 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
285 fba->emu_types[1] = FBTYPE_SUN3COLOR;
286 fba->emu_types[2] = -1;
287 #undef fba
288 break;
289
290 case FBIOGETCMAP:
291 #define p ((struct fbcmap *)data)
292 return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
293
294 case FBIOPUTCMAP:
295 /* copy to software map */
296 error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
297 if (error)
298 return (error);
299 /* now blast them into the chip */
300 /* XXX should use retrace interrupt */
301 tcx_loadcmap(sc, p->index, p->count);
302 #undef p
303 break;
304
305 case FBIOGVIDEO:
306 *(int *)data = sc->sc_blanked;
307 break;
308
309 case FBIOSVIDEO:
310 if (*(int *)data)
311 tcx_unblank(&sc->sc_dev);
312 else if (!sc->sc_blanked) {
313 sc->sc_blanked = 1;
314 sc->sc_thc->thc_hcmisc &= ~THC_MISC_VIDEN;
315 /* Put monitor in `power-saving mode' */
316 sc->sc_thc->thc_hcmisc |= THC_MISC_VSYNC_DISABLE;
317 sc->sc_thc->thc_hcmisc |= THC_MISC_HSYNC_DISABLE;
318 }
319 break;
320
321 default:
322 #ifdef DEBUG
323 log(LOG_NOTICE, "tcxioctl(0x%lx) (%s[%d])\n", cmd,
324 p->p_comm, p->p_pid);
325 #endif
326 return (ENOTTY);
327 }
328 return (0);
329 }
330
331 int
332 tcxpoll(dev, events, p)
333 dev_t dev;
334 int events;
335 struct proc *p;
336 {
337
338 return (seltrue(dev, events, p));
339 }
340
341 /*
342 * Clean up hardware state (e.g., after bootup or after X crashes).
343 */
344 static void
345 tcx_reset(sc)
346 struct tcx_softc *sc;
347 {
348 volatile struct bt_regs *bt;
349
350 /* Enable cursor in Brooktree DAC. */
351 bt = sc->sc_bt;
352 bt->bt_addr = 0x06 << 24;
353 bt->bt_ctrl |= 0x03 << 24;
354 }
355
356 /*
357 * Load a subset of the current (new) colormap into the color DAC.
358 */
359 static void
360 tcx_loadcmap(sc, start, ncolors)
361 struct tcx_softc *sc;
362 int start, ncolors;
363 {
364 volatile struct bt_regs *bt;
365 u_int *ip, i;
366 int count;
367
368 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
369 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
370 bt = sc->sc_bt;
371 bt->bt_addr = BT_D4M4(start) << 24;
372 while (--count >= 0) {
373 i = *ip++;
374 /* hardware that makes one want to pound boards with hammers */
375 bt->bt_cmap = i;
376 bt->bt_cmap = i << 8;
377 bt->bt_cmap = i << 16;
378 bt->bt_cmap = i << 24;
379 }
380 }
381
382 static void
383 tcx_unblank(dev)
384 struct device *dev;
385 {
386 struct tcx_softc *sc = (struct tcx_softc *)dev;
387
388 if (sc->sc_blanked) {
389 sc->sc_blanked = 0;
390 sc->sc_thc->thc_hcmisc &= ~THC_MISC_VSYNC_DISABLE;
391 sc->sc_thc->thc_hcmisc &= ~THC_MISC_HSYNC_DISABLE;
392 sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN;
393 }
394 }
395
396 /*
397 * Base addresses at which users can mmap() the various pieces of a tcx.
398 */
399 #define TCX_USER_RAM 0x00000000
400 #define TCX_USER_RAM24 0x01000000
401 #define TCX_USER_RAM_COMPAT 0x04000000 /* cg3 emulation */
402 #define TCX_USER_STIP 0x10000000
403 #define TCX_USER_BLIT 0x20000000
404 #define TCX_USER_RDFB32 0x28000000
405 #define TCX_USER_RSTIP 0x30000000
406 #define TCX_USER_RBLIT 0x38000000
407 #define TCX_USER_TEC 0x70001000
408 #define TCX_USER_BTREGS 0x70002000
409 #define TCX_USER_THC 0x70004000
410 #define TCX_USER_DHC 0x70008000
411 #define TCX_USER_ALT 0x7000a000
412 #define TCX_USER_UART 0x7000c000
413 #define TCX_USER_VRT 0x7000e000
414 #define TCX_USER_ROM 0x70010000
415
416 struct mmo {
417 u_int mo_uaddr; /* user (virtual) address */
418 u_int mo_size; /* size, or 0 for video ram size */
419 u_int mo_bank; /* register bank number */
420 };
421
422 /*
423 * Return the address that would map the given device at the given
424 * offset, allowing for the given protection, or return -1 for error.
425 *
426 * XXX needs testing against `demanding' applications (e.g., aviator)
427 */
428 paddr_t
429 tcxmmap(dev, off, prot)
430 dev_t dev;
431 off_t off;
432 int prot;
433 {
434 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)];
435 bus_space_handle_t bh;
436 struct sbus_reg *rr = sc->sc_physadr;
437 struct mmo *mo;
438 u_int u, sz;
439 static struct mmo mmo[] = {
440 { TCX_USER_RAM, 0, TCX_REG_DFB8 },
441 { TCX_USER_RAM24, 0, TCX_REG_DFB24 },
442 { TCX_USER_RAM_COMPAT, 0, TCX_REG_DFB8 },
443
444 { TCX_USER_STIP, 1, TCX_REG_STIP },
445 { TCX_USER_BLIT, 1, TCX_REG_BLIT },
446 { TCX_USER_RDFB32, 1, TCX_REG_RDFB32 },
447 { TCX_USER_RSTIP, 1, TCX_REG_RSTIP },
448 { TCX_USER_RBLIT, 1, TCX_REG_RBLIT },
449 { TCX_USER_TEC, 1, TCX_REG_TEC },
450 { TCX_USER_BTREGS, 8192 /* XXX */, TCX_REG_CMAP },
451 { TCX_USER_THC, sizeof(struct tcx_thc), TCX_REG_THC },
452 { TCX_USER_DHC, 1, TCX_REG_DHC },
453 { TCX_USER_ALT, 1, TCX_REG_ALT },
454 { TCX_USER_ROM, 65536, TCX_REG_ROM },
455 };
456 #define NMMO (sizeof mmo / sizeof *mmo)
457
458 if (off & PGOFSET)
459 panic("tcxmmap");
460
461 /*
462 * Entries with size 0 map video RAM (i.e., the size in fb data).
463 *
464 * Since we work in pages, the fact that the map offset table's
465 * sizes are sometimes bizarre (e.g., 1) is effectively ignored:
466 * one byte is as good as one page.
467 */
468 for (mo = mmo; mo < &mmo[NMMO]; mo++) {
469 if ((u_int)off < mo->mo_uaddr)
470 continue;
471 u = off - mo->mo_uaddr;
472 sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size;
473 if (u < sz) {
474 bus_type_t t = (bus_type_t)rr[mo->mo_bank].sbr_slot;
475 bus_addr_t a = (bus_addr_t)rr[mo->mo_bank].sbr_offset;
476
477 if (bus_space_mmap(sc->sc_bustag,
478 t,
479 a + u,
480 BUS_SPACE_MAP_LINEAR, &bh))
481 return (-1);
482
483 return ((paddr_t)bh);
484 }
485 }
486 return (-1); /* not a user-map offset */
487 }
488