[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     ! 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