Annotation of sys/dev/sbus/cgtwelve.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cgtwelve.c,v 1.5 2007/03/13 19:40:49 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2002, 2003 Miodrag Vallat. All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25: * POSSIBILITY OF SUCH DAMAGE.
26: */
27:
28: /*
29: * cgtwelve (GS) accelerated 24-bit framebuffer driver.
30: *
31: * Enough experiments and SMI's cg12reg.h made this possible.
32: */
33:
34: /*
35: * The cgtwelve framebuffer is a 3-slot SBUS card, that will fit only in
36: * SPARCstation 1, 1+, 2 and 5, or in an xbox SBUS extension.
37: *
38: * It is a 24-bit 3D accelerated framebuffer made by Matrox, featuring 4MB
39: * (regular model) or 8MB (high-res model) of video memory, a complex
40: * windowing engine, double buffering modes, three video planes (overlay,
41: * 8 bit and 24 bit color), and a lot of colormap combinations.
42: *
43: * All of this is driven by a set of three Bt462 ramdacs (latched unless
44: * explicitely programmed), and a couple of other Matrox-specific chips.
45: *
46: * XXX The high res card is untested.
47: */
48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/buf.h>
52: #include <sys/device.h>
53: #include <sys/ioctl.h>
54: #include <sys/conf.h>
55:
56: #include <uvm/uvm_extern.h>
57:
58: #include <machine/autoconf.h>
59: #include <machine/bus.h>
60: #include <machine/pmap.h>
61: #include <machine/cpu.h>
62: #include <machine/conf.h>
63:
64: #include <dev/wscons/wsconsio.h>
65: #include <dev/wscons/wsdisplayvar.h>
66: #include <dev/rasops/rasops.h>
67: #include <machine/fbvar.h>
68:
69: #include <dev/sbus/sbusvar.h>
70:
71: #include <dev/sbus/cgtwelvereg.h>
72:
73: #include <dev/cons.h> /* for prom console hook */
74:
75: /* per-display variables */
76: struct cgtwelve_softc {
77: struct sunfb sc_sunfb; /* common base device */
78: bus_space_tag_t sc_bustag;
79: bus_addr_t sc_paddr;
80:
81: volatile struct cgtwelve_dpu *sc_dpu;
82: volatile struct cgtwelve_apu *sc_apu;
83: volatile struct cgtwelve_dac *sc_ramdac; /* RAMDAC registers */
84: volatile u_char *sc_overlay; /* overlay or enable plane */
85: volatile u_long *sc_inten; /* true color plane */
86:
87: int sc_highres;
88: int sc_nscreens;
89: };
90:
91: int cgtwelve_ioctl(void *, u_long, caddr_t, int, struct proc *);
92: int cgtwelve_alloc_screen(void *, const struct wsscreen_descr *, void **,
93: int *, int *, long *);
94: void cgtwelve_free_screen(void *, void *);
95: int cgtwelve_show_screen(void *, void *, int, void (*cb)(void *, int, int),
96: void *);
97: paddr_t cgtwelve_mmap(void *, off_t, int);
98: void cgtwelve_reset(struct cgtwelve_softc *, int);
99: void cgtwelve_prom(void *);
100:
101: static __inline__ void cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc,
102: u_int32_t addr);
103:
104: struct wsdisplay_accessops cgtwelve_accessops = {
105: cgtwelve_ioctl,
106: cgtwelve_mmap,
107: cgtwelve_alloc_screen,
108: cgtwelve_free_screen,
109: cgtwelve_show_screen,
110: NULL, /* load_font */
111: NULL, /* scrollback */
112: NULL, /* getchar */
113: NULL /* burner */
114: };
115:
116: int cgtwelvematch(struct device *, void *, void *);
117: void cgtwelveattach(struct device *, struct device *, void *);
118:
119: struct cfattach cgtwelve_ca = {
120: sizeof(struct cgtwelve_softc), cgtwelvematch, cgtwelveattach
121: };
122:
123: struct cfdriver cgtwelve_cd = {
124: NULL, "cgtwelve", DV_DULL
125: };
126:
127:
128: /*
129: * Match a cgtwelve.
130: */
131: int
132: cgtwelvematch(struct device *parent, void *vcf, void *aux)
133: {
134: struct cfdata *cf = vcf;
135: struct sbus_attach_args *sa = aux;
136:
137: if (strcmp(cf->cf_driver->cd_name, sa->sa_name) != 0)
138: return (0);
139:
140: return (1);
141: }
142:
143: /*
144: * Attach and initialize a cgtwelve.
145: */
146: void
147: cgtwelveattach(struct device *parent, struct device *self, void *args)
148: {
149: struct cgtwelve_softc *sc = (struct cgtwelve_softc *)self;
150: struct sbus_attach_args *sa = args;
151: bus_space_tag_t bt;
152: bus_space_handle_t bh;
153: int node, isconsole = 0;
154: char *ps;
155:
156: bt = sa->sa_bustag;
157: node = sa->sa_node;
158:
159: printf(": %s", getpropstring(node, "model"));
160: ps = getpropstring(node, "dev_id");
161: if (*ps != '\0')
162: printf(" (%s)", ps);
163: printf("\n");
164:
165: isconsole = node == fbnode;
166:
167: if (sa->sa_nreg == 0) {
168: printf("%s: no SBus registers!\n", self->dv_xname);
169: return;
170: }
171:
172: sc->sc_bustag = bt;
173:
174: /*
175: * Map registers
176: */
177: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
178: CG12_OFF_DPU, sizeof(struct cgtwelve_dpu),
179: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
180: printf("%s: can't map DPU registers\n", self->dv_xname);
181: return;
182: }
183: sc->sc_dpu = bus_space_vaddr(bt, bh);
184: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
185: CG12_OFF_APU, sizeof(struct cgtwelve_apu),
186: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
187: printf("%s: can't map APU registers\n", self->dv_xname);
188: return;
189: }
190: sc->sc_apu = bus_space_vaddr(bt, bh);
191: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
192: CG12_OFF_DAC, sizeof(struct cgtwelve_dac),
193: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
194: printf("%s: can't map RAMDAC registers\n", self->dv_xname);
195: return;
196: }
197: sc->sc_ramdac = bus_space_vaddr(bt, bh);
198:
199: /*
200: * The console is using the 1-bit overlay plane, while the prom
201: * will correctly report 32 bit depth.
202: */
203: fb_setsize(&sc->sc_sunfb, 1, CG12_WIDTH, CG12_HEIGHT,
204: node, 0);
205: sc->sc_sunfb.sf_depth = 1;
206: sc->sc_sunfb.sf_linebytes = sc->sc_sunfb.sf_width / 8;
207: sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_height *
208: sc->sc_sunfb.sf_linebytes;
209:
210: sc->sc_highres = sc->sc_sunfb.sf_width == CG12_WIDTH_HR;
211:
212: /*
213: * Map planes
214: */
215: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
216: (sc->sc_highres ? CG12_OFF_OVERLAY0_HR : CG12_OFF_OVERLAY0),
217: round_page(sc->sc_highres ? CG12_SIZE_OVERLAY_HR :
218: CG12_SIZE_OVERLAY), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
219: printf("%s: can't map overlay plane\n", self->dv_xname);
220: return;
221: }
222: sc->sc_overlay = bus_space_vaddr(bt, bh);
223: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
224: (sc->sc_highres ? CG12_OFF_INTEN_HR : CG12_OFF_INTEN),
225: round_page(sc->sc_highres ? CG12_SIZE_COLOR24_HR :
226: CG12_SIZE_COLOR24), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
227: printf("%s: can't map color plane\n", self->dv_xname);
228: return;
229: }
230: sc->sc_inten = bus_space_vaddr(bt, bh);
231: sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset +
232: (sc->sc_highres ? CG12_OFF_INTEN_HR : CG12_OFF_INTEN));
233:
234: /* reset cursor & frame buffer controls */
235: sc->sc_sunfb.sf_depth = 0; /* force action */
236: cgtwelve_reset(sc, 1);
237:
238: sc->sc_sunfb.sf_ro.ri_bits = (void *)sc->sc_overlay;
239: sc->sc_sunfb.sf_ro.ri_hw = sc;
240: fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR);
241:
242: if (isconsole) {
243: fbwscons_console_init(&sc->sc_sunfb, -1);
244: shutdownhook_establish(cgtwelve_prom, sc);
245: }
246:
247: printf("%s: %dx%d", self->dv_xname,
248: sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
249: ps = getpropstring(node, "ucoderev");
250: if (*ps != '\0')
251: printf(", microcode rev. %s", ps);
252: printf("\n");
253:
254: fbwscons_attach(&sc->sc_sunfb, &cgtwelve_accessops, isconsole);
255: }
256:
257: int
258: cgtwelve_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
259: {
260: struct cgtwelve_softc *sc = dev;
261: struct wsdisplay_fbinfo *wdf;
262:
263: /*
264: * Note that, although the emulation (text) mode is running in the
265: * overlay plane, we advertize the frame buffer as the full-blown
266: * 32-bit beast it is.
267: */
268: switch (cmd) {
269: case WSDISPLAYIO_GTYPE:
270: *(u_int *)data = WSDISPLAY_TYPE_SUNCG12;
271: break;
272: case WSDISPLAYIO_GINFO:
273: wdf = (struct wsdisplay_fbinfo *)data;
274: wdf->height = sc->sc_sunfb.sf_height;
275: wdf->width = sc->sc_sunfb.sf_width;
276: wdf->depth = 32;
277: wdf->cmsize = 0;
278: break;
279: case WSDISPLAYIO_GETSUPPORTEDDEPTH:
280: *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
281: break;
282: case WSDISPLAYIO_LINEBYTES:
283: *(u_int *)data = sc->sc_sunfb.sf_linebytes * 32;
284: break;
285:
286: case WSDISPLAYIO_GETCMAP:
287: case WSDISPLAYIO_PUTCMAP:
288: break;
289:
290: case WSDISPLAYIO_SMODE:
291: if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
292: /* Back from X11 to text mode */
293: cgtwelve_reset(sc, 1);
294: } else {
295: /* Starting X11, switch to 32 bit mode */
296: cgtwelve_reset(sc, 32);
297: }
298: break;
299:
300: case WSDISPLAYIO_SVIDEO:
301: case WSDISPLAYIO_GVIDEO:
302: break;
303:
304: default:
305: return (-1); /* not supported yet */
306: }
307:
308: return (0);
309: }
310:
311: /*
312: * Clean up hardware state (e.g., after bootup or after X crashes).
313: */
314: void
315: cgtwelve_reset(struct cgtwelve_softc *sc, int depth)
316: {
317: u_int32_t c;
318:
319: if (sc->sc_sunfb.sf_depth != depth) {
320: if (depth == 1) {
321: /*
322: * Select the enable plane as sc_overlay, and fill it.
323: */
324: sc->sc_apu->hpage = sc->sc_highres ?
325: CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE;
326: sc->sc_apu->haccess = CG12_HACCESS_ENABLE;
327: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_ENABLE;
328: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_ENABLE;
329: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_ENABLE;
330:
331: memset((void *)sc->sc_overlay, 0xff, sc->sc_highres ?
332: CG12_SIZE_ENABLE_HR : CG12_SIZE_ENABLE);
333:
334: /*
335: * Select the overlay plane as sc_overlay.
336: */
337: sc->sc_apu->hpage = sc->sc_highres ?
338: CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY;
339: sc->sc_apu->haccess = CG12_HACCESS_OVERLAY;
340: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY;
341: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY;
342: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY;
343:
344: /*
345: * Upload a strict mono colormap, or the text
346: * upon returning from 32 bit mode would appear
347: * as (slightly dark) white on white.
348: */
349: cgtwelve_ramdac_wraddr(sc, 0);
350: sc->sc_ramdac->color = 0x00000000;
351: for (c = 1; c < 256; c++)
352: sc->sc_ramdac->color = 0x00ffffff;
353: } else {
354: /*
355: * Select the overlay plane as sc_overlay.
356: */
357: sc->sc_apu->hpage = sc->sc_highres ?
358: CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY;
359: sc->sc_apu->haccess = CG12_HACCESS_OVERLAY;
360: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY;
361: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY;
362: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY;
363:
364: /*
365: * Do not attempt to somewhat preserve screen
366: * contents - reading the overlay plane and writing
367: * to the color plane at the same time is not
368: * reliable, and allocating memory to save a copy
369: * of the overlay plane would be awful.
370: */
371: bzero((void *)sc->sc_overlay, sc->sc_highres ?
372: CG12_SIZE_OVERLAY_HR : CG12_SIZE_OVERLAY);
373:
374: /*
375: * Select the enable plane as sc_overlay, and clear it.
376: */
377: sc->sc_apu->hpage = sc->sc_highres ?
378: CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE;
379: sc->sc_apu->haccess = CG12_HACCESS_ENABLE;
380: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_ENABLE;
381: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_ENABLE;
382: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_ENABLE;
383:
384: bzero((void *)sc->sc_overlay, sc->sc_highres ?
385: CG12_SIZE_ENABLE_HR : CG12_SIZE_ENABLE);
386:
387: /*
388: * Select the intensity (color) plane, and clear it.
389: */
390: sc->sc_apu->hpage = sc->sc_highres ?
391: CG12_HPAGE_24BIT_HR : CG12_HPAGE_24BIT;
392: sc->sc_apu->haccess = CG12_HACCESS_24BIT;
393: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_24BIT;
394: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_24BIT;
395: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_24BIT;
396:
397: memset((void *)sc->sc_inten, 0x00ffffff,
398: sc->sc_highres ?
399: CG12_SIZE_COLOR24_HR : CG12_SIZE_COLOR24);
400:
401: /*
402: * Use a direct colormap (ramp)
403: */
404: cgtwelve_ramdac_wraddr(sc, 0);
405: for (c = 0; c < 256; c++)
406: sc->sc_ramdac->color = c | (c << 8) | (c << 16);
407: }
408: }
409:
410: sc->sc_sunfb.sf_depth = depth;
411: }
412:
413: /*
414: * Return the address that would map the given device at the given
415: * offset, allowing for the given protection, or return -1 for error.
416: */
417: paddr_t
418: cgtwelve_mmap(void *v, off_t offset, int prot)
419: {
420: struct cgtwelve_softc *sc = v;
421:
422: if (offset & PGOFSET || offset < 0)
423: return (-1);
424:
425: /*
426: * Note that mmap() will invoke this function only if we are NOT
427: * in emulation mode, so we can assume 32 bit mode safely here.
428: */
429: if (offset < sc->sc_sunfb.sf_fbsize * 32) {
430: return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, offset,
431: prot, BUS_SPACE_MAP_LINEAR));
432: }
433:
434: return (-1);
435: }
436:
437: int
438: cgtwelve_alloc_screen(void *v, const struct wsscreen_descr *type,
439: void **cookiep, int *curxp, int *curyp, long *attrp)
440: {
441: struct cgtwelve_softc *sc = v;
442:
443: if (sc->sc_nscreens > 0)
444: return (ENOMEM);
445:
446: *cookiep = &sc->sc_sunfb.sf_ro;
447: *curyp = 0;
448: *curxp = 0;
449: sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
450: 0, 0, 0, attrp);
451: sc->sc_nscreens++;
452: return (0);
453: }
454:
455: void
456: cgtwelve_free_screen(void *v, void *cookie)
457: {
458: struct cgtwelve_softc *sc = v;
459:
460: sc->sc_nscreens--;
461: }
462:
463: int
464: cgtwelve_show_screen(void *v, void *cookie, int waitok,
465: void (*cb)(void *, int, int), void *cbarg)
466: {
467: return (0);
468: }
469:
470: /*
471: * Simple Bt462 programming routines.
472: */
473:
474: static __inline__ void
475: cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc, u_int32_t addr)
476: {
477: sc->sc_ramdac->addr_lo = (addr & 0xff);
478: sc->sc_ramdac->addr_hi = ((addr >> 8) & 0xff);
479: }
480:
481: /*
482: * Shutdown hook used to restore PROM-compatible video mode on shutdown,
483: * so that the PROM prompt is visible again.
484: */
485: void
486: cgtwelve_prom(void *v)
487: {
488: struct cgtwelve_softc *sc = v;
489: extern struct consdev consdev_prom;
490:
491: if (sc->sc_sunfb.sf_depth != 1) {
492: cgtwelve_reset(sc, 1);
493:
494: /*
495: * Go back to prom output for the last few messages, so they
496: * will be displayed correctly.
497: */
498: cn_tab = &consdev_prom;
499: }
500: }
CVSweb