Annotation of sys/arch/sparc/dev/vigra.c, Revision 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