[BACK]Return to vigra.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / dev

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