[BACK]Return to mgx.c CVS log [TXT][DIR] Up to [local] / sys / dev / sbus

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