Annotation of sys/dev/sbus/mgx.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mgx.c,v 1.8 2007/02/18 18:38:55 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 <dev/sbus/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:
90: bus_space_tag_t sc_bustag;
91: bus_addr_t sc_paddr;
92:
93: u_int8_t sc_cmap[256 * 3]; /* shadow colormap */
94: volatile u_int8_t *sc_vidc; /* ramdac registers */
95:
96: int sc_nscreens;
97: };
98:
99: int mgx_ioctl(void *, u_long, caddr_t, int, struct proc *);
100: int mgx_alloc_screen(void *, const struct wsscreen_descr *, void **,
101: int *, int *, long *);
102: void mgx_free_screen(void *, void *);
103: int mgx_show_screen(void *, void *, int, void (*cb)(void *, int, int),
104: void *);
105: paddr_t mgx_mmap(void *, off_t, int);
106: void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
107: int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *);
108: int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *);
109: void mgx_loadcmap(struct mgx_softc *, int, int);
110: void mgx_burner(void *, u_int ,u_int);
111:
112: struct wsdisplay_accessops mgx_accessops = {
113: mgx_ioctl,
114: mgx_mmap,
115: mgx_alloc_screen,
116: mgx_free_screen,
117: mgx_show_screen,
118: NULL, /* load_font */
119: NULL, /* scrollback */
120: NULL, /* getchar */
121: mgx_burner
122: };
123:
124: int mgxmatch(struct device *, void *, void *);
125: void mgxattach(struct device *, struct device *, void *);
126:
127: struct cfattach mgx_ca = {
128: sizeof(struct mgx_softc), mgxmatch, mgxattach
129: };
130:
131: struct cfdriver mgx_cd = {
132: NULL, "mgx", DV_DULL
133: };
134:
135: /*
136: * Match an MGX or MGX+ card.
137: */
138: int
139: mgxmatch(struct device *parent, void *vcf, void *aux)
140: {
141: struct sbus_attach_args *sa = aux;
142:
143: if (strcmp(sa->sa_name, "SMSI,mgx") != 0 &&
144: strcmp(sa->sa_name, "mgx") != 0)
145: return (0);
146:
147: return (1);
148: }
149:
150: /*
151: * Attach an MGX frame buffer.
152: * This will keep the frame buffer in the actual PROM mode, and attach
153: * a wsdisplay child device to itself.
154: */
155: void
156: mgxattach(struct device *parent, struct device *self, void *args)
157: {
158: struct mgx_softc *sc = (struct mgx_softc *)self;
159: struct sbus_attach_args *sa = args;
160: bus_space_tag_t bt;
161: bus_space_handle_t bh;
162: int node, fbsize;
163: int isconsole;
164:
165: bt = sa->sa_bustag;
166: node = sa->sa_node;
167:
168: printf(": %s", getpropstring(node, "model"));
169:
170: isconsole = node == fbnode;
171:
172: /* Check registers */
173: if (sa->sa_nreg < MGX_NREG) {
174: printf("\n%s: expected %d registers, got %d\n",
175: self->dv_xname, MGX_NREG, sa->sa_nreg);
176: return;
177: }
178:
179: sc->sc_bustag = bt;
180: if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_CRTC].sbr_slot,
181: sa->sa_reg[MGX_REG_CRTC].sbr_offset, PAGE_SIZE,
182: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
183: printf("\n%s: couldn't map crtc registers\n", self->dv_xname);
184: return;
185: }
186: sc->sc_vidc = (volatile u_int8_t *)bus_space_vaddr(bt, bh);
187:
188: /* enable video */
189: mgx_burner(sc, 1, 0);
190:
191: fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
192:
193: /* Sanity check frame buffer memory */
194: fbsize = getpropint(node, "fb_size", 0);
195: if (fbsize != 0 && sc->sc_sunfb.sf_fbsize > fbsize) {
196: printf("\n%s: expected at least %d bytes of vram, but card "
197: "only provides %d\n",
198: self->dv_xname, sc->sc_sunfb.sf_fbsize, fbsize);
199: return;
200: }
201:
202: /* Map the frame buffer memory area we're interested in */
203: sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
204: sa->sa_reg[MGX_REG_VRAM8].sbr_offset);
205: if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
206: sa->sa_reg[MGX_REG_VRAM8].sbr_offset,
207: round_page(sc->sc_sunfb.sf_fbsize),
208: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
209: printf("\n%s: couldn't map video memory\n", self->dv_xname);
210: return;
211: }
212: sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
213: sc->sc_sunfb.sf_ro.ri_hw = sc;
214:
215: fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR);
216:
217: bzero(sc->sc_cmap, sizeof(sc->sc_cmap));
218: fbwscons_setcolormap(&sc->sc_sunfb, mgx_setcolor);
219:
220: printf(", %dx%d\n",
221: sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
222:
223: if (isconsole) {
224: fbwscons_console_init(&sc->sc_sunfb, -1);
225: }
226:
227: fbwscons_attach(&sc->sc_sunfb, &mgx_accessops, isconsole);
228: }
229:
230: /*
231: * wsdisplay operations
232: */
233:
234: int
235: mgx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
236: {
237: struct mgx_softc *sc = dev;
238: struct wsdisplay_cmap *cm;
239: struct wsdisplay_fbinfo *wdf;
240: int error;
241:
242: switch (cmd) {
243: case WSDISPLAYIO_GTYPE:
244: *(u_int *)data = WSDISPLAY_TYPE_MGX;
245: break;
246: case WSDISPLAYIO_GINFO:
247: wdf = (struct wsdisplay_fbinfo *)data;
248: wdf->height = sc->sc_sunfb.sf_height;
249: wdf->width = sc->sc_sunfb.sf_width;
250: wdf->depth = sc->sc_sunfb.sf_depth;
251: wdf->cmsize = 256;
252: break;
253: case WSDISPLAYIO_LINEBYTES:
254: *(u_int *)data = sc->sc_sunfb.sf_linebytes;
255: break;
256:
257: case WSDISPLAYIO_GETCMAP:
258: cm = (struct wsdisplay_cmap *)data;
259: error = mgx_getcmap(sc->sc_cmap, cm);
260: if (error != 0)
261: return (error);
262: break;
263: case WSDISPLAYIO_PUTCMAP:
264: cm = (struct wsdisplay_cmap *)data;
265: error = mgx_putcmap(sc->sc_cmap, cm);
266: if (error != 0)
267: return (error);
268: mgx_loadcmap(sc, cm->index, cm->count);
269: break;
270:
271: case WSDISPLAYIO_SVIDEO:
272: case WSDISPLAYIO_GVIDEO:
273: break;
274:
275: default:
276: return (-1);
277: }
278:
279: return (0);
280: }
281:
282: paddr_t
283: mgx_mmap(void *v, off_t offset, int prot)
284: {
285: struct mgx_softc *sc = v;
286:
287: if (offset & PGOFSET)
288: return (-1);
289:
290: /* Allow mapping as a dumb framebuffer from offset 0 */
291: if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
292: return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
293: offset, prot, BUS_SPACE_MAP_LINEAR));
294: }
295:
296: return (-1);
297: }
298:
299: int
300: mgx_alloc_screen(void *v, const struct wsscreen_descr *type,
301: void **cookiep, int *curxp, int *curyp, long *attrp)
302: {
303: struct mgx_softc *sc = v;
304:
305: if (sc->sc_nscreens > 0)
306: return (ENOMEM);
307:
308: *cookiep = &sc->sc_sunfb.sf_ro;
309: *curyp = 0;
310: *curxp = 0;
311: sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
312: 0, 0, 0, attrp);
313: sc->sc_nscreens++;
314: return (0);
315: }
316:
317: void
318: mgx_free_screen(void *v, void *cookie)
319: {
320: struct mgx_softc *sc = v;
321:
322: sc->sc_nscreens--;
323: }
324:
325: int
326: mgx_show_screen(void *v, void *cookie, int waitok,
327: void (*cb)(void *, int, int), void *cbarg)
328: {
329: return (0);
330: }
331:
332: void
333: mgx_burner(void *v, u_int on, u_int flags)
334: {
335: struct mgx_softc *sc = v;
336:
337: sc->sc_vidc[CRTC_INDEX] = 1; /* TS mode register */
338: if (on)
339: sc->sc_vidc[CRTC_DATA] &= ~CD_DISABLEVIDEO;
340: else
341: sc->sc_vidc[CRTC_DATA] |= CD_DISABLEVIDEO;
342: }
343:
344: /*
345: * Colormap handling routines
346: */
347:
348: void
349: mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
350: {
351: struct mgx_softc *sc = v;
352:
353: index *= 3;
354: sc->sc_cmap[index++] = r;
355: sc->sc_cmap[index++] = g;
356: sc->sc_cmap[index] = b;
357:
358: mgx_loadcmap(sc, index, 1);
359: }
360:
361: void
362: mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors)
363: {
364: u_int8_t *color;
365: int i;
366:
367: #if 0
368: sc->sc_vidc[CMAP_WRITE_INDEX] = start;
369: color = sc->sc_cmap + start * 3;
370: #else
371: /*
372: * Apparently there is no way to load an incomplete cmap to this
373: * DAC. What a waste.
374: */
375: ncolors = 256;
376: color = sc->sc_cmap;
377: #endif
378: for (i = ncolors * 3; i != 0; i--)
379: sc->sc_vidc[CMAP_DATA] = *color++;
380: }
381:
382: int
383: mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
384: {
385: u_int index = rcm->index, count = rcm->count, i;
386: int error;
387:
388: if (index >= 256 || count > 256 - index)
389: return (EINVAL);
390:
391: for (i = 0; i < count; i++) {
392: if ((error =
393: copyout(cm + (index + i) * 3 + 0, &rcm->red[i], 1)) != 0)
394: return (error);
395: if ((error =
396: copyout(cm + (index + i) * 3 + 1, &rcm->green[i], 1)) != 0)
397: return (error);
398: if ((error =
399: copyout(cm + (index + i) * 3 + 2, &rcm->blue[i], 1)) != 0)
400: return (error);
401: }
402:
403: return (0);
404: }
405:
406: int
407: mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
408: {
409: u_int index = rcm->index, count = rcm->count, i;
410: int error;
411:
412: if (index >= 256 || count > 256 - index)
413: return (EINVAL);
414:
415: for (i = 0; i < count; i++) {
416: if ((error =
417: copyin(&rcm->red[i], cm + (index + i) * 3 + 0, 1)) != 0)
418: return (error);
419: if ((error =
420: copyin(&rcm->green[i], cm + (index + i) * 3 + 1, 1)) != 0)
421: return (error);
422: if ((error =
423: copyin(&rcm->blue[i], cm + (index + i) * 3 + 2, 1)) != 0)
424: return (error);
425: }
426:
427: return (0);
428: }
CVSweb