Annotation of sys/arch/sparc/dev/mgx.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mgx.c,v 1.12 2007/02/18 18:38:54 miod Exp $ */
2: /*
3: * Copyright (c) 2003, Miodrag Vallat.
4: * 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: /*
30: * Driver for the Southland Media Systems (now Quantum 3D) MGX and MGXPlus
31: * frame buffers.
32: *
33: * Pretty crude, due to the lack of documentation. Works as a dumb frame
34: * buffer in 8 bit mode, although the hardware can run in an 32 bit
35: * accelerated mode. Also, interrupts are not handled.
36: */
37:
38: #include <sys/param.h>
39: #include <sys/systm.h>
40: #include <sys/buf.h>
41: #include <sys/device.h>
42: #include <sys/ioctl.h>
43: #include <sys/malloc.h>
44: #include <sys/mman.h>
45: #include <sys/tty.h>
46: #include <sys/conf.h>
47:
48: #include <uvm/uvm_extern.h>
49:
50: #include <machine/autoconf.h>
51: #include <machine/pmap.h>
52: #include <machine/cpu.h>
53: #include <machine/conf.h>
54:
55: #include <dev/wscons/wsconsio.h>
56: #include <dev/wscons/wsdisplayvar.h>
57: #include <dev/rasops/rasops.h>
58: #include <machine/fbvar.h>
59:
60: #include <sparc/dev/sbusvar.h>
61:
62: /*
63: * MGX PROM register layout
64: */
65:
66: #define MGX_NREG 9
67: #define MGX_REG_CRTC 4 /* video control and ramdac */
68: #define MGX_REG_CTRL 5 /* control engine */
69: #define MGX_REG_VRAM8 8 /* 8-bit memory space */
70:
71: /*
72: * MGX CRTC empirical constants
73: */
74: #if _BYTE_ORDER == _LITTLE_ENDIAN
75: #define IO_ADDRESS(x) (x)
76: #else
77: #define IO_ADDRESS(x) ((x) ^ 0x03)
78: #endif
79: #define CRTC_INDEX IO_ADDRESS(0x03c4)
80: #define CRTC_DATA IO_ADDRESS(0x03c5)
81: #define CD_DISABLEVIDEO 0x0020
82: #define CMAP_READ_INDEX IO_ADDRESS(0x03c7)
83: #define CMAP_WRITE_INDEX IO_ADDRESS(0x03c8)
84: #define CMAP_DATA IO_ADDRESS(0x03c9)
85:
86: /* per-display variables */
87: struct mgx_softc {
88: struct sunfb sc_sunfb; /* common base device */
89: struct rom_reg sc_phys;
90: u_int8_t sc_cmap[256 * 3]; /* shadow colormap */
91: volatile u_int8_t *sc_vidc; /* ramdac registers */
92: };
93:
94: void mgx_burner(void *, u_int ,u_int);
95: int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *);
96: int mgx_ioctl(void *, u_long, caddr_t, int, struct proc *);
97: void mgx_loadcmap(struct mgx_softc *, int, int);
98: paddr_t mgx_mmap(void *, off_t, int);
99: int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *);
100: void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
101:
102: struct wsdisplay_accessops mgx_accessops = {
103: mgx_ioctl,
104: mgx_mmap,
105: NULL, /* alloc_screen */
106: NULL, /* free_screen */
107: NULL, /* show_screen */
108: NULL, /* load_font */
109: NULL, /* scrollback */
110: NULL, /* getchar */
111: mgx_burner,
112: NULL /* pollc */
113: };
114:
115: int mgxmatch(struct device *, void *, void *);
116: void mgxattach(struct device *, struct device *, void *);
117:
118: struct cfattach mgx_ca = {
119: sizeof(struct mgx_softc), mgxmatch, mgxattach
120: };
121:
122: struct cfdriver mgx_cd = {
123: NULL, "mgx", DV_DULL
124: };
125:
126: /*
127: * Match an MGX or MGX+ card.
128: */
129: int
130: mgxmatch(struct device *parent, void *vcf, void *aux)
131: {
132: struct confargs *ca = aux;
133: struct romaux *ra = &ca->ca_ra;
134:
135: if (strcmp(ra->ra_name, "SMSI,mgx") != 0 &&
136: strcmp(ra->ra_name, "mgx") != 0)
137: return (0);
138:
139: return (1);
140: }
141:
142: /*
143: * Attach an MGX frame buffer.
144: * This will keep the frame buffer in the actual PROM mode, and attach
145: * a wsdisplay child device to itself.
146: */
147: void
148: mgxattach(struct device *parent, struct device *self, void *args)
149: {
150: struct mgx_softc *sc = (struct mgx_softc *)self;
151: struct confargs *ca = args;
152: int node, fbsize;
153: int isconsole;
154:
155: node = ca->ca_ra.ra_node;
156:
157: printf(": %s", getpropstring(node, "model"));
158:
159: isconsole = node == fbnode;
160:
161: /* Check registers */
162: if (ca->ca_ra.ra_nreg < MGX_NREG) {
163: printf("\n%s: expected %d registers, got %d\n",
164: self->dv_xname, MGX_NREG, ca->ca_ra.ra_nreg);
165: return;
166: }
167:
168: sc->sc_vidc = (volatile u_int8_t *)mapiodev(
169: &ca->ca_ra.ra_reg[MGX_REG_CRTC], 0, PAGE_SIZE);
170:
171: /* enable video */
172: mgx_burner(sc, 1, 0);
173:
174: fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype);
175:
176: /* Sanity check frame buffer memory */
177: fbsize = getpropint(node, "fb_size", 0);
178: if (fbsize != 0 && sc->sc_sunfb.sf_fbsize > fbsize) {
179: printf("\n%s: expected at least %d bytes of vram, but card "
180: "only provides %d\n",
181: self->dv_xname, sc->sc_sunfb.sf_fbsize, fbsize);
182: return;
183: }
184:
185: /* Map the frame buffer memory area we're interested in */
186: sc->sc_phys = ca->ca_ra.ra_reg[MGX_REG_VRAM8];
187: sc->sc_sunfb.sf_ro.ri_bits = mapiodev(&sc->sc_phys,
188: 0, round_page(sc->sc_sunfb.sf_fbsize));
189: sc->sc_sunfb.sf_ro.ri_hw = sc;
190:
191: fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR);
192:
193: bzero(sc->sc_cmap, sizeof(sc->sc_cmap));
194: fbwscons_setcolormap(&sc->sc_sunfb, mgx_setcolor);
195:
196: printf(", %dx%d\n",
197: sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
198:
199: if (isconsole) {
200: fbwscons_console_init(&sc->sc_sunfb, -1);
201: }
202:
203: fbwscons_attach(&sc->sc_sunfb, &mgx_accessops, isconsole);
204: }
205:
206: /*
207: * wsdisplay operations
208: */
209:
210: int
211: mgx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
212: {
213: struct mgx_softc *sc = dev;
214: struct wsdisplay_cmap *cm;
215: struct wsdisplay_fbinfo *wdf;
216: int error;
217:
218: switch (cmd) {
219: case WSDISPLAYIO_GTYPE:
220: *(u_int *)data = WSDISPLAY_TYPE_MGX;
221: break;
222: case WSDISPLAYIO_GINFO:
223: wdf = (struct wsdisplay_fbinfo *)data;
224: wdf->height = sc->sc_sunfb.sf_height;
225: wdf->width = sc->sc_sunfb.sf_width;
226: wdf->depth = sc->sc_sunfb.sf_depth;
227: wdf->cmsize = 256;
228: break;
229: case WSDISPLAYIO_LINEBYTES:
230: *(u_int *)data = sc->sc_sunfb.sf_linebytes;
231: break;
232:
233: case WSDISPLAYIO_GETCMAP:
234: cm = (struct wsdisplay_cmap *)data;
235: error = mgx_getcmap(sc->sc_cmap, cm);
236: if (error != 0)
237: return (error);
238: break;
239: case WSDISPLAYIO_PUTCMAP:
240: cm = (struct wsdisplay_cmap *)data;
241: error = mgx_putcmap(sc->sc_cmap, cm);
242: if (error != 0)
243: return (error);
244: mgx_loadcmap(sc, cm->index, cm->count);
245: break;
246:
247: case WSDISPLAYIO_SVIDEO:
248: case WSDISPLAYIO_GVIDEO:
249: break;
250:
251: default:
252: return (-1);
253: }
254:
255: return (0);
256: }
257:
258: paddr_t
259: mgx_mmap(void *v, off_t offset, int prot)
260: {
261: struct mgx_softc *sc = v;
262:
263: if (offset & PGOFSET)
264: return (-1);
265:
266: /* Allow mapping as a dumb framebuffer from offset 0 */
267: if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
268: return (REG2PHYS(&sc->sc_phys, offset) | PMAP_NC);
269: }
270:
271: return (-1);
272: }
273:
274: void
275: mgx_burner(void *v, u_int on, u_int flags)
276: {
277: struct mgx_softc *sc = v;
278:
279: sc->sc_vidc[CRTC_INDEX] = 1; /* TS mode register */
280: if (on)
281: sc->sc_vidc[CRTC_DATA] &= ~CD_DISABLEVIDEO;
282: else
283: sc->sc_vidc[CRTC_DATA] |= CD_DISABLEVIDEO;
284: }
285:
286: /*
287: * Colormap handling routines
288: */
289:
290: void
291: mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
292: {
293: struct mgx_softc *sc = v;
294:
295: index *= 3;
296: sc->sc_cmap[index++] = r;
297: sc->sc_cmap[index++] = g;
298: sc->sc_cmap[index] = b;
299:
300: mgx_loadcmap(sc, index, 1);
301: }
302:
303: void
304: mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors)
305: {
306: u_int8_t *color;
307: int i;
308:
309: #if 0
310: sc->sc_vidc[CMAP_WRITE_INDEX] = start;
311: color = sc->sc_cmap + start * 3;
312: #else
313: /*
314: * Apparently there is no way to load an incomplete cmap to this
315: * DAC. What a waste.
316: */
317: ncolors = 256;
318: color = sc->sc_cmap;
319: #endif
320: for (i = ncolors * 3; i != 0; i--)
321: sc->sc_vidc[CMAP_DATA] = *color++;
322: }
323:
324: int
325: mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
326: {
327: u_int index = rcm->index, count = rcm->count, i;
328: int error;
329:
330: if (index >= 256 || count > 256 - index)
331: return (EINVAL);
332:
333: for (i = 0; i < count; i++) {
334: if ((error =
335: copyout(cm + (index + i) * 3 + 0, &rcm->red[i], 1)) != 0)
336: return (error);
337: if ((error =
338: copyout(cm + (index + i) * 3 + 1, &rcm->green[i], 1)) != 0)
339: return (error);
340: if ((error =
341: copyout(cm + (index + i) * 3 + 2, &rcm->blue[i], 1)) != 0)
342: return (error);
343: }
344:
345: return (0);
346: }
347:
348: int
349: mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
350: {
351: u_int index = rcm->index, count = rcm->count, i;
352: int error;
353:
354: if (index >= 256 || count > 256 - index)
355: return (EINVAL);
356:
357: for (i = 0; i < count; i++) {
358: if ((error =
359: copyin(&rcm->red[i], cm + (index + i) * 3 + 0, 1)) != 0)
360: return (error);
361: if ((error =
362: copyin(&rcm->green[i], cm + (index + i) * 3 + 1, 1)) != 0)
363: return (error);
364: if ((error =
365: copyin(&rcm->blue[i], cm + (index + i) * 3 + 2, 1)) != 0)
366: return (error);
367: }
368:
369: return (0);
370: }
CVSweb