Annotation of sys/arch/sparc/dev/vigra.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: vigra.c,v 1.17 2007/02/18 18:40:35 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2002, 2003, Miodrag Vallat.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: *
28: */
29:
30: /*
31: * Driver for the Vigra VS series of SBus framebuffers.
32: *
33: * The VS10, VS11 and VS12 models are supported. VS10-EK is handled by the
34: * regular cgthree driver.
35: *
36: * The monochrome VS14, 16 grays VS15, and color VS18 are not supported.
37: */
38:
39: #include <sys/param.h>
40: #include <sys/systm.h>
41: #include <sys/buf.h>
42: #include <sys/device.h>
43: #include <sys/ioctl.h>
44: #include <sys/malloc.h>
45: #include <sys/mman.h>
46: #include <sys/tty.h>
47: #include <sys/conf.h>
48:
49: #include <uvm/uvm_extern.h>
50:
51: #include <machine/autoconf.h>
52: #include <machine/pmap.h>
53: #include <machine/cpu.h>
54: #include <machine/conf.h>
55:
56: #include <dev/wscons/wsconsio.h>
57: #include <dev/wscons/wsdisplayvar.h>
58: #include <dev/rasops/rasops.h>
59: #include <machine/fbvar.h>
60:
61: #include <sparc/dev/sbusvar.h>
62:
63: /*
64: * The hardware information below has been gathered through experiments, as
65: * well as the debug information of the SunOS 4.x vigfb driver.
66: */
67:
68: /*
69: * Control and status registers
70: */
71:
72: struct csregs {
73: u_int32_t sosr;
74: u_int32_t g3rr;
75: u_int32_t bcr; /* board control register */
76: u_int32_t spr;
77: u_int32_t g3sr; /* ramdac status register */
78: #define STATUS_INTR 0x0001
79: u_int32_t imr; /* interrupt mode register */
80: u_int32_t ewcr;
81: u_int32_t ssr;
82: };
83:
84: /*
85: * G300 layout
86: */
87:
88: struct g300dac {
89: u_int32_t cmap[256];
90: u_int32_t g3null;
91: u_int32_t unused1[32];
92: u_int32_t half_sync;
93: u_int32_t back_porch;
94: u_int32_t display;
95: u_int32_t short_display;
96: u_int32_t broad_pulse;
97: u_int32_t vsync;
98: u_int32_t vblank;
99: u_int32_t vdisplay;
100: u_int32_t line_time;
101: u_int32_t tos1;
102: u_int32_t mem_init;
103: u_int32_t transfer_delay;
104: u_int32_t unused2[19];
105: u_int32_t mask;
106: u_int32_t unused3[31];
107: u_int32_t cr;
108: u_int32_t unused4[31];
109: u_int32_t tos2;
110: u_int32_t unused5[31];
111: u_int32_t boot_location;
112: };
113:
114: /*
115: * G335 layout
116: */
117:
118: struct g335dac {
119: u_int32_t boot_location;
120: u_int32_t unused1[32];
121: u_int32_t half_sync;
122: u_int32_t back_porch;
123: u_int32_t display;
124: u_int32_t short_display;
125: u_int32_t broad_pulse;
126: u_int32_t vsync;
127: u_int32_t vpre_equalize;
128: u_int32_t vpost_equalize;
129: u_int32_t vblank;
130: u_int32_t vdisplay;
131: u_int32_t line_time;
132: u_int32_t tos1;
133: u_int32_t mem_init;
134: u_int32_t transfer_delay;
135: u_int32_t unused2[17];
136: u_int32_t mask;
137: u_int32_t unused3[31];
138: u_int32_t cra;
139: u_int32_t unused4[15];
140: u_int32_t crb;
141: u_int32_t unused5[15];
142: u_int32_t tos2;
143: u_int32_t unused6[32];
144: u_int32_t cursor_palette[3];
145: u_int32_t unused7[28];
146: u_int32_t checksum[3];
147: u_int32_t unused8[4];
148: u_int32_t cursor_position;
149: u_int32_t unused9[56];
150: u_int32_t cmap[256];
151: u_int32_t cursor_store[512];
152: };
153:
154: union dac {
155: struct g300dac g300;
156: struct g335dac g335;
157: };
158:
159: /*
160: * SBUS register mappings
161: */
162: #define VIGRA_REG_RAMDAC 1 /* either G300 or G335 */
163: #define VIGRA_REG_CSR 2
164: #define VIGRA_REG_VRAM 3
165:
166: #define VIGRA_NREG 4
167:
168: union vigracmap {
169: u_char cm_map[256][4]; /* 256 R/G/B entries plus pad */
170: u_int32_t cm_chip[256]; /* the way the chip gets loaded */
171: };
172:
173: /* per-display variables */
174: struct vigra_softc {
175: struct sunfb sc_sunfb; /* common base part */
176: struct rom_reg sc_phys; /* phys address description */
177: volatile struct csregs *sc_regs;/* control registers */
178: volatile union dac *sc_ramdac; /* ramdac registers */
179: union vigracmap sc_cmap; /* current colormap */
180: int sc_g300;
181: struct intrhand sc_ih;
182: };
183:
184: void vigra_burner(void *, u_int, u_int);
185: int vigra_getcmap(union vigracmap *, struct wsdisplay_cmap *, int);
186: int vigra_intr(void *);
187: int vigra_ioctl(void *, u_long, caddr_t, int, struct proc *);
188: static __inline__
189: void vigra_loadcmap_deferred(struct vigra_softc *, u_int, u_int);
190: void vigra_loadcmap_immediate(struct vigra_softc *, int, int);
191: paddr_t vigra_mmap(void *, off_t, int);
192: int vigra_putcmap(union vigracmap *, struct wsdisplay_cmap *, int);
193: void vigra_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
194:
195: struct wsdisplay_accessops vigra_accessops = {
196: vigra_ioctl,
197: vigra_mmap,
198: NULL, /* alloc_screen */
199: NULL, /* free_screen */
200: NULL, /* show_screen */
201: NULL, /* load_font */
202: NULL, /* scrollback */
203: NULL, /* getchar */
204: vigra_burner,
205: NULL /* pollc */
206: };
207:
208: int vigramatch(struct device *, void *, void *);
209: void vigraattach(struct device *, struct device *, void *);
210:
211: struct cfattach vigra_ca = {
212: sizeof (struct vigra_softc), vigramatch, vigraattach
213: };
214:
215: struct cfdriver vigra_cd = {
216: NULL, "vigra", DV_DULL
217: };
218:
219: /*
220: * Match a supported vigra card.
221: */
222: int
223: vigramatch(struct device *parent, void *vcf, void *aux)
224: {
225: struct confargs *ca = aux;
226: struct romaux *ra = &ca->ca_ra;
227:
228: if (strcmp("vs10", ra->ra_name) != 0 &&
229: strcmp("vs11", ra->ra_name) != 0 &&
230: strcmp("vs12", ra->ra_name) != 0)
231: return (0);
232:
233: return (1);
234: }
235:
236: /*
237: * Attach and initialize a vigra display, as well as a child wsdisplay.
238: */
239: void
240: vigraattach(struct device *parent, struct device *self, void *args)
241: {
242: struct vigra_softc *sc = (struct vigra_softc *)self;
243: struct confargs *ca = args;
244: int node, pri, row, isconsole = 0;
245: char *nam;
246:
247: pri = ca->ca_ra.ra_intr[0].int_pri;
248: printf(" pri %d", pri);
249:
250: if (ca->ca_ra.ra_nreg < VIGRA_NREG) {
251: printf("\n%s: expected %d registers, got %d",
252: self->dv_xname, VIGRA_NREG, ca->ca_ra.ra_nreg);
253: return;
254: }
255:
256: node = ca->ca_ra.ra_node;
257: nam = getpropstring(node, "model");
258: if (*nam == '\0')
259: nam = (char *)ca->ca_ra.ra_name;
260: printf(": %s", nam);
261:
262: isconsole = node == fbnode;
263:
264: /*
265: * Check whether we are using an G300 or an G335 chip.
266: * The VS10 and VS12 use the G300, while the VS11 uses a G335.
267: */
268: sc->sc_g300 = strncmp(nam, "VIGRA,vs11", strlen("VIGRA,vs11"));
269:
270: sc->sc_regs = mapiodev(&ca->ca_ra.ra_reg[VIGRA_REG_CSR], 0,
271: ca->ca_ra.ra_reg[VIGRA_REG_CSR].rr_len);
272: sc->sc_ramdac = mapiodev(&ca->ca_ra.ra_reg[VIGRA_REG_RAMDAC], 0,
273: ca->ca_ra.ra_reg[VIGRA_REG_RAMDAC].rr_len);
274: sc->sc_phys = ca->ca_ra.ra_reg[VIGRA_REG_VRAM];
275:
276: sc->sc_ih.ih_fun = vigra_intr;
277: sc->sc_ih.ih_arg = sc;
278: intr_establish(pri, &sc->sc_ih, IPL_FB, self->dv_xname);
279:
280: /* enable video */
281: vigra_burner(sc, 1, 0);
282:
283: fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype);
284: sc->sc_sunfb.sf_ro.ri_bits = mapiodev(&ca->ca_ra.ra_reg[VIGRA_REG_VRAM],
285: 0, round_page(sc->sc_sunfb.sf_fbsize));
286: sc->sc_sunfb.sf_ro.ri_hw = sc;
287:
288: printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
289:
290: /*
291: * If the framebuffer width is under 1024x768, we will switch from the
292: * PROM font to the more adequate 8x16 font here.
293: * However, we need to adjust two things in this case:
294: * - the display row should be overrided from the current PROM metrics,
295: * to prevent us from overwriting the last few lines of text.
296: * - if the 80x34 screen would make a large margin appear around it,
297: * choose to clear the screen rather than keeping old prom output in
298: * the margins.
299: * XXX there should be a rasops "clear margins" feature
300: *
301: * Also, in 1280x1024 resolution, the PROM display is not centered
302: * vertically (why? no other frame buffer does this in such a mode!),
303: * so be lazy and clear the screen here too anyways...
304: */
305: fbwscons_init(&sc->sc_sunfb, isconsole && (sc->sc_sunfb.sf_width != 800
306: && sc->sc_sunfb.sf_width != 1280) ? 0 : RI_CLEAR);
307: fbwscons_setcolormap(&sc->sc_sunfb, vigra_setcolor);
308:
309: if (isconsole) {
310: switch (sc->sc_sunfb.sf_width) {
311: case 640:
312: row = sc->sc_sunfb.sf_ro.ri_rows - 1;
313: break;
314: case 800:
315: case 1280:
316: row = 0; /* screen has been cleared above */
317: break;
318: default:
319: row = -1;
320: break;
321: }
322:
323: fbwscons_console_init(&sc->sc_sunfb, row);
324: }
325:
326: fbwscons_attach(&sc->sc_sunfb, &vigra_accessops, isconsole);
327: }
328:
329: int
330: vigra_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
331: {
332: struct vigra_softc *sc = v;
333: struct wsdisplay_cmap *cm;
334: struct wsdisplay_fbinfo *wdf;
335: int error;
336:
337: switch (cmd) {
338: case WSDISPLAYIO_GTYPE:
339: *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
340: break;
341: case WSDISPLAYIO_GINFO:
342: wdf = (struct wsdisplay_fbinfo *)data;
343: wdf->height = sc->sc_sunfb.sf_height;
344: wdf->width = sc->sc_sunfb.sf_width;
345: wdf->depth = sc->sc_sunfb.sf_depth;
346: wdf->cmsize = 256;
347: break;
348: case WSDISPLAYIO_LINEBYTES:
349: *(u_int *)data = sc->sc_sunfb.sf_linebytes;
350: break;
351:
352: case WSDISPLAYIO_GETCMAP:
353: cm = (struct wsdisplay_cmap *)data;
354: error = vigra_getcmap(&sc->sc_cmap, cm, sc->sc_g300);
355: if (error)
356: return (error);
357: break;
358: case WSDISPLAYIO_PUTCMAP:
359: cm = (struct wsdisplay_cmap *)data;
360: error = vigra_putcmap(&sc->sc_cmap, cm, sc->sc_g300);
361: if (error)
362: return (error);
363: vigra_loadcmap_deferred(sc, cm->index, cm->count);
364: break;
365:
366: case WSDISPLAYIO_SVIDEO:
367: case WSDISPLAYIO_GVIDEO:
368: break;
369:
370: case WSDISPLAYIO_GCURPOS:
371: case WSDISPLAYIO_SCURPOS:
372: case WSDISPLAYIO_GCURMAX:
373: case WSDISPLAYIO_GCURSOR:
374: case WSDISPLAYIO_SCURSOR:
375: default:
376: return (-1); /* not supported yet */
377: }
378:
379: return (0);
380: }
381:
382: paddr_t
383: vigra_mmap(void *v, off_t offset, int prot)
384: {
385: struct vigra_softc *sc = v;
386:
387: if (offset & PGOFSET)
388: return (-1);
389:
390: if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
391: return (REG2PHYS(&sc->sc_phys, offset) | PMAP_NC);
392: }
393:
394: return (-1);
395: }
396:
397: void
398: vigra_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
399: {
400: struct vigra_softc *sc = v;
401:
402: if (sc->sc_g300) {
403: sc->sc_cmap.cm_map[index][3] = r;
404: sc->sc_cmap.cm_map[index][2] = g;
405: sc->sc_cmap.cm_map[index][1] = b;
406: } else {
407: sc->sc_cmap.cm_map[index][3] = b;
408: sc->sc_cmap.cm_map[index][2] = g;
409: sc->sc_cmap.cm_map[index][1] = r;
410: }
411: sc->sc_cmap.cm_map[index][0] = 0; /* no alpha channel */
412:
413: vigra_loadcmap_immediate(sc, index, 1);
414: }
415:
416: int
417: vigra_getcmap(union vigracmap *cm, struct wsdisplay_cmap *rcm, int g300)
418: {
419: u_int index = rcm->index, count = rcm->count, i;
420: int error;
421:
422: if (index >= 256 || count > 256 - index)
423: return (EINVAL);
424:
425: if (g300) {
426: for (i = 0; i < count; i++) {
427: if ((error = copyout(&cm->cm_map[index + i][3],
428: &rcm->red[i], 1)) != 0)
429: return (error);
430: if ((error = copyout(&cm->cm_map[index + i][1],
431: &rcm->blue[i], 1)) != 0)
432: return (error);
433: }
434: } else {
435: for (i = 0; i < count; i++) {
436: if ((error = copyout(&cm->cm_map[index + i][1],
437: &rcm->red[i], 1)) != 0)
438: return (error);
439: if ((error = copyout(&cm->cm_map[index + i][3],
440: &rcm->blue[i], 1)) != 0)
441: return (error);
442: }
443: }
444:
445: for (i = 0; i < count; i++) {
446: if ((error = copyout(&cm->cm_map[index + i][2],
447: &rcm->green[i], 1)) != 0)
448: return (error);
449: }
450: return (0);
451: }
452:
453: int
454: vigra_putcmap(union vigracmap *cm, struct wsdisplay_cmap *rcm, int g300)
455: {
456: u_int index = rcm->index, count = rcm->count, i;
457: int error;
458:
459: if (index >= 256 || count > 256 - index)
460: return (EINVAL);
461:
462: if (g300) {
463: for (i = 0; i < count; i++) {
464: if ((error = copyin(&rcm->red[i],
465: &cm->cm_map[index + i][3], 1)) != 0)
466: return (error);
467: if ((error = copyin(&rcm->blue[i],
468: &cm->cm_map[index + i][1], 1)) != 0)
469: return (error);
470: }
471: } else {
472: for (i = 0; i < count; i++) {
473: if ((error = copyin(&rcm->red[i],
474: &cm->cm_map[index + i][1], 1)) != 0)
475: return (error);
476: if ((error = copyin(&rcm->blue[i],
477: &cm->cm_map[index + i][3], 1)) != 0)
478: return (error);
479: }
480: }
481:
482: for (i = 0; i < count; i++) {
483: if ((error = copyin(&rcm->green[i],
484: &cm->cm_map[index + i][2], 1)) != 0)
485: return (error);
486: cm->cm_map[index + i][0] = 0; /* no alpha channel */
487: }
488: return (0);
489: }
490:
491: void
492: vigra_loadcmap_immediate(struct vigra_softc *sc, int start, int ncolors)
493: {
494: u_int32_t *colp = &sc->sc_cmap.cm_chip[start];
495: volatile u_int32_t *lutp;
496:
497: if (sc->sc_g300)
498: lutp = &(sc->sc_ramdac->g300.cmap[start]);
499: else
500: lutp = &(sc->sc_ramdac->g335.cmap[start]);
501:
502: while (--ncolors >= 0)
503: *lutp++ = *colp++;
504: }
505:
506: static __inline__ void
507: vigra_loadcmap_deferred(struct vigra_softc *sc, u_int start, u_int ncolors)
508: {
509:
510: sc->sc_regs->imr = 1;
511: }
512:
513: void
514: vigra_burner(void *v, u_int on, u_int flags)
515: {
516: struct vigra_softc *sc = v;
517:
518: if (on) {
519: sc->sc_regs->bcr = 0;
520: } else {
521: sc->sc_regs->bcr = 1;
522: }
523: }
524:
525: int
526: vigra_intr(void *v)
527: {
528: struct vigra_softc *sc = v;
529:
530: if (sc->sc_regs->imr == 0 ||
531: !ISSET(sc->sc_regs->g3sr, STATUS_INTR)) {
532: /* Not expecting an interrupt, it's not for us. */
533: return (0);
534: }
535:
536: /* Acknowledge the interrupt and disable it. */
537: sc->sc_regs->imr = 0;
538:
539: vigra_loadcmap_immediate(sc, 0, 256);
540:
541: return (1);
542: }
CVSweb