root/dev/sbus/mgx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mgxmatch
  2. mgxattach
  3. mgx_ioctl
  4. mgx_mmap
  5. mgx_alloc_screen
  6. mgx_free_screen
  7. mgx_show_screen
  8. mgx_burner
  9. mgx_setcolor
  10. mgx_loadcmap
  11. mgx_getcmap
  12. mgx_putcmap

    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 }

/* [<][>][^][v][top][bottom][index][help] */