Annotation of sys/dev/sbus/tvtwo.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: tvtwo.c,v 1.11 2007/03/13 19:40:49 miod Exp $ */
2: /*
3: * Copyright (c) 2003, 2006, 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 Parallax XVideo and PowerVideo graphics boards.
31: *
32: * Some details about these board are available at:
33: * http://www.jlw.com/~woolsey/parallax/support/developers/xvideotech.html
34: */
35:
36: /*
37: * The Parallax XVideo series frame buffers are 8/24-bit accelerated
38: * frame buffers, with hardware MPEG capabilities using a CCube chipset.
39: */
40:
41: /*
42: * Currently, this driver can only handle the 8-bit and 24-bit planes of the
43: * frame buffer, in an unaccelerated mode.
44: *
45: * TODO:
46: * - nvram handling
47: * - use the accelerator
48: * - interface to the c^3
49: */
50:
51: #include <sys/param.h>
52: #include <sys/systm.h>
53: #include <sys/buf.h>
54: #include <sys/device.h>
55: #include <sys/ioctl.h>
56: #include <sys/mman.h>
57: #include <sys/conf.h>
58:
59: #include <uvm/uvm_extern.h>
60:
61: #include <machine/autoconf.h>
62: #include <machine/bus.h>
63: #include <machine/pmap.h>
64: #include <machine/cpu.h>
65: #include <machine/conf.h>
66:
67: #include <dev/wscons/wsconsio.h>
68: #include <dev/wscons/wsdisplayvar.h>
69: #include <dev/rasops/rasops.h>
70: #include <machine/fbvar.h>
71:
72: #include <dev/sbus/sbusvar.h>
73:
74: /*
75: * The memory layout of the board is as follows:
76: *
77: * PROM0 000000 - 00ffff
78: * overlay plane 010000 - 037fff
79: * registers 040000 - 0404d0
80: * CCube 050000 - 05ffff
81: * 8-bit plane 080000 - 17ffff
82: * 24-bit plane 200000 - 6fffff
83: * PROM1 7f0000 - 7fffff
84: *
85: * Older XVideo provide two sets of SBus registers:
86: * R0 040000 - 040800
87: * R1 080000 - 17d200
88: * While the more recent revisions provide only one register:
89: * R0 000000 - 7fffff
90: *
91: * We currently refuse to attach to the old version because mapping
92: * things requires us to play with the sbus register ranges, and I
93: * don't want to play this game without the hardware at hand -- miod
94: */
95:
96: #define PX_PROM0_OFFSET 0x000000
97: #define PX_OVERLAY_OFFSET 0x010000
98: #define PX_REG_OFFSET 0x040000
99: #define PX_CCUBE_OFFSET 0x050000
100: #define PX_PLANE8_OFFSET 0x080000
101: #define PX_PLANE24_OFFSET 0x200000
102: #define PX_PROM1_OFFSET 0x7f0000
103:
104: /*
105: * Partial registers layout
106: */
107:
108: #define PX_REG_DISPKLUDGE 0x00b8 /* write only */
109: #define DISPKLUDGE_DEFAULT 0xc41f
110: #define DISPKLUDGE_BLANK (1 << 12)
111: #define DISPKLUDGE_SYNC (1 << 13)
112:
113: #define PX_REG_BT463_RED 0x0480
114: #define PX_REG_BT463_GREEN 0x0490
115: #define PX_REG_BT463_BLUE 0x04a0
116: #define PX_REG_BT463_ALL 0x04b0
117:
118: #define PX_REG_SIZE 0x04d0
119:
120:
121: /* per-display variables */
122: struct tvtwo_softc {
123: struct sunfb sc_sunfb; /* common base device */
124:
125: bus_space_tag_t sc_bustag;
126: bus_addr_t sc_paddr;
127:
128: volatile u_int8_t *sc_m8;
129: volatile u_int8_t *sc_m24;
130: volatile u_int8_t *sc_regs;
131:
132: int sc_nscreens;
133: };
134:
135: int tvtwo_ioctl(void *, u_long, caddr_t, int, struct proc *);
136: int tvtwo_alloc_screen(void *, const struct wsscreen_descr *, void **,
137: int *, int *, long *);
138: void tvtwo_free_screen(void *, void *);
139: int tvtwo_show_screen(void *, void *, int, void (*cb)(void *, int, int),
140: void *);
141: paddr_t tvtwo_mmap(void *, off_t, int);
142: void tvtwo_burner(void *, u_int, u_int);
143:
144: struct wsdisplay_accessops tvtwo_accessops = {
145: tvtwo_ioctl,
146: tvtwo_mmap,
147: tvtwo_alloc_screen,
148: tvtwo_free_screen,
149: tvtwo_show_screen,
150: NULL, /* load_font */
151: NULL, /* scrollback */
152: NULL, /* getchar */
153: tvtwo_burner,
154: };
155:
156: void tvtwo_directcmap(struct tvtwo_softc *);
157: static __inline__
158: void tvtwo_ramdac_wraddr(struct tvtwo_softc *, u_int32_t);
159: void tvtwo_reset(struct tvtwo_softc *, u_int);
160: void tvtwo_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
161:
162: int tvtwomatch(struct device *, void *, void *);
163: void tvtwoattach(struct device *, struct device *, void *);
164:
165: struct cfattach tvtwo_ca = {
166: sizeof(struct tvtwo_softc), tvtwomatch, tvtwoattach
167: };
168:
169: struct cfdriver tvtwo_cd = {
170: NULL, "tvtwo", DV_DULL
171: };
172:
173: /*
174: * Default frame buffer resolution, depending upon the "freqcode"
175: */
176: #define NFREQCODE 5
177: const int defwidth[NFREQCODE] = { 1152, 1152, 1152, 1024, 640 };
178: const int defheight[NFREQCODE] = { 900, 900, 900, 768, 480 };
179:
180: /*
181: * Match an XVideo or PowerVideo card.
182: */
183: int
184: tvtwomatch(struct device *parent, void *vcf, void *aux)
185: {
186: struct sbus_attach_args *sa = aux;
187:
188: if (strcmp(sa->sa_name, "PGI,tvtwo") == 0 ||
189: strcmp(sa->sa_name, "PGI,tvthree") == 0)
190: return (1);
191:
192: return (0);
193: }
194:
195: /*
196: * Attach a display.
197: */
198: void
199: tvtwoattach(struct device *parent, struct device *self, void *args)
200: {
201: struct tvtwo_softc *sc = (struct tvtwo_softc *)self;
202: struct sbus_attach_args *sa = args;
203: bus_space_tag_t bt;
204: bus_space_handle_t bh;
205: int node, width, height, freqcode;
206: int isconsole;
207: char *freqstring;
208:
209: bt = sa->sa_bustag;
210: node = sa->sa_node;
211:
212: printf(": %s", getpropstring(node, "model"));
213: printf(", revision %s\n", getpropstring(node, "revision"));
214:
215: /* We do not handle older boards yet. */
216: if (sa->sa_nreg != 1) {
217: printf("%s: old-style boards with %d registers are not supported\n"
218: "%s: please report this to <sparc@openbsd.org>\n",
219: self->dv_xname, sa->sa_nreg,
220: self->dv_xname);
221: return;
222: }
223:
224: isconsole = node == fbnode;
225:
226: /* Map registers. */
227: sc->sc_bustag = bt;
228: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_REG_OFFSET,
229: PX_REG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
230: printf("%s: couldn't map registers\n", self->dv_xname);
231: return;
232: }
233: sc->sc_regs = bus_space_vaddr(bt, bh);
234:
235: /* Compute framebuffer size. */
236: freqstring = getpropstring(node, "freqcode");
237: freqcode = (int)*freqstring;
238: if (freqcode == 'g') {
239: width = height = 1024;
240: } else {
241: if (freqcode < '1' || freqcode > '6')
242: freqcode = 0;
243: else
244: freqcode -= '1';
245: width = defwidth[freqcode];
246: height = defheight[freqcode];
247: }
248:
249: width = getpropint(node, "hres", width);
250: height = getpropint(node, "vres", height);
251:
252: /*
253: * Since the depth property is usually missing, we could do
254: * fb_setsize(&sc->sc_sunfb, 8, width, height, node, 0);
255: * but for safety in case it would exist and be set to 32, do it
256: * manually...
257: */
258: sc->sc_sunfb.sf_depth = 8;
259: sc->sc_sunfb.sf_width = width;
260: sc->sc_sunfb.sf_height = height;
261: sc->sc_sunfb.sf_linebytes = width >= 1024 ? width : 1024;
262: sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_linebytes * height;
263:
264: /* Map the frame buffer memory area we're interested in. */
265: sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset);
266: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE8_OFFSET,
267: round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
268: &bh) != 0) {
269: printf("%s: couldn't map 8-bit video plane\n", self->dv_xname);
270: return;
271: }
272: sc->sc_m8 = bus_space_vaddr(bt, bh);
273: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE24_OFFSET,
274: round_page(4 * sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
275: &bh) != 0) {
276: printf("%s: couldn't map 32-bit video plane\n", self->dv_xname);
277: return;
278: }
279: sc->sc_m24 = bus_space_vaddr(bt, bh);
280:
281: /* Enable video. */
282: tvtwo_burner(sc, 1, 0);
283:
284: sc->sc_sunfb.sf_ro.ri_hw = sc;
285: sc->sc_sunfb.sf_ro.ri_bits = (u_char *)sc->sc_m8;
286:
287: /*
288: * If the framebuffer width is under 1024, we will switch from
289: * the PROM font to the more adequate 8x16 font here.
290: */
291: fbwscons_init(&sc->sc_sunfb,
292: isconsole && (width >= 1024) ? RI_CLEARMARGINS : RI_CLEAR);
293: fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
294:
295: if (isconsole) {
296: fbwscons_console_init(&sc->sc_sunfb,
297: width >= 1024 ? -1 : 0);
298: }
299:
300: printf("%s: %dx%d\n", self->dv_xname,
301: sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
302:
303: fbwscons_attach(&sc->sc_sunfb, &tvtwo_accessops, isconsole);
304: }
305:
306: int
307: tvtwo_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
308: {
309: struct tvtwo_softc *sc = dev;
310: struct wsdisplay_fbinfo *wdf;
311:
312: /*
313: * Note that, although the emulation (text) mode is running in a
314: * 8-bit plane, we advertize the frame buffer as 32-bit.
315: */
316: switch (cmd) {
317: case WSDISPLAYIO_GTYPE:
318: *(u_int *)data = WSDISPLAY_TYPE_SUN24;
319: break;
320: case WSDISPLAYIO_GINFO:
321: wdf = (struct wsdisplay_fbinfo *)data;
322: wdf->height = sc->sc_sunfb.sf_height;
323: wdf->width = sc->sc_sunfb.sf_width;
324: wdf->depth = 32;
325: wdf->cmsize = 0;
326: break;
327: case WSDISPLAYIO_GETSUPPORTEDDEPTH:
328: *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
329: break;
330: case WSDISPLAYIO_LINEBYTES:
331: *(u_int *)data = sc->sc_sunfb.sf_linebytes * 4;
332: break;
333:
334: case WSDISPLAYIO_GETCMAP:
335: case WSDISPLAYIO_PUTCMAP:
336: break;
337:
338: case WSDISPLAYIO_SMODE:
339: if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
340: /* Back from X11 to text mode */
341: tvtwo_reset(sc, 8);
342: } else {
343: /* Starting X11, initialize 32-bit mode */
344: tvtwo_reset(sc, 32);
345: }
346: break;
347:
348: case WSDISPLAYIO_SVIDEO:
349: case WSDISPLAYIO_GVIDEO:
350: break;
351:
352: case WSDISPLAYIO_GCURPOS:
353: case WSDISPLAYIO_SCURPOS:
354: case WSDISPLAYIO_GCURMAX:
355: case WSDISPLAYIO_GCURSOR:
356: case WSDISPLAYIO_SCURSOR:
357: default:
358: return (-1);
359: }
360:
361: return (0);
362: }
363:
364: /*
365: * Return the address that would map the given device at the given
366: * offset, allowing for the given protection, or return -1 for error.
367: */
368: paddr_t
369: tvtwo_mmap(void *v, off_t offset, int prot)
370: {
371: struct tvtwo_softc *sc = v;
372:
373: if (offset & PGOFSET)
374: return (-1);
375:
376: /* Allow mapping as a dumb framebuffer from offset 0 */
377: if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize * 4) {
378: return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
379: PX_PLANE24_OFFSET + offset, prot, BUS_SPACE_MAP_LINEAR));
380: }
381:
382: return (-1);
383: }
384:
385: int
386: tvtwo_alloc_screen(void *v, const struct wsscreen_descr *type,
387: void **cookiep, int *curxp, int *curyp, long *attrp)
388: {
389: struct tvtwo_softc *sc = v;
390:
391: if (sc->sc_nscreens > 0)
392: return (ENOMEM);
393:
394: *cookiep = &sc->sc_sunfb.sf_ro;
395: *curyp = 0;
396: *curxp = 0;
397: sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
398: 0, 0, 0, attrp);
399: sc->sc_nscreens++;
400: return (0);
401: }
402:
403: void
404: tvtwo_free_screen(void *v, void *cookie)
405: {
406: struct tvtwo_softc *sc = v;
407:
408: sc->sc_nscreens--;
409: }
410:
411: int
412: tvtwo_show_screen(void *v, void *cookie, int waitok,
413: void (*cb)(void *, int, int), void *cbarg)
414: {
415: return (0);
416: }
417:
418: void
419: tvtwo_burner(void *v, u_int on, u_int flags)
420: {
421: struct tvtwo_softc *sc = v;
422: u_int32_t dispkludge;
423:
424: if (on)
425: dispkludge = DISPKLUDGE_DEFAULT & ~DISPKLUDGE_BLANK;
426: else {
427: dispkludge = DISPKLUDGE_DEFAULT | DISPKLUDGE_BLANK;
428: if (flags & WSDISPLAY_BURN_VBLANK)
429: dispkludge |= DISPKLUDGE_SYNC;
430: }
431:
432: *(volatile u_int32_t *)(sc->sc_regs + PX_REG_DISPKLUDGE) =
433: dispkludge;
434: }
435:
436: void
437: tvtwo_reset(struct tvtwo_softc *sc, u_int depth)
438: {
439: if (depth == 32) {
440: /* Initialize a direct color map. */
441: tvtwo_directcmap(sc);
442: } else {
443: fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
444: }
445: }
446:
447: /*
448: * Simple Bt463 programming routines.
449: */
450:
451: static __inline__ void
452: tvtwo_ramdac_wraddr(struct tvtwo_softc *sc, u_int32_t addr)
453: {
454: volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
455:
456: dac[0] = (addr & 0xff); /* lo addr */
457: dac[1] = ((addr >> 8) & 0xff); /* hi addr */
458: }
459:
460: void
461: tvtwo_directcmap(struct tvtwo_softc *sc)
462: {
463: volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
464: u_int32_t c;
465:
466: tvtwo_ramdac_wraddr(sc, 0);
467: for (c = 0; c < 256; c++) {
468: dac[3] = c; /* R */
469: dac[3] = c; /* G */
470: dac[3] = c; /* B */
471: }
472: }
473:
474: void
475: tvtwo_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
476: {
477: struct tvtwo_softc *sc = v;
478: volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
479:
480: tvtwo_ramdac_wraddr(sc, index);
481: dac[3] = r;
482: dac[3] = g;
483: dac[3] = b;
484: }
CVSweb