root/dev/sbus/tvtwo.c

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

DEFINITIONS

This source file includes following definitions.
  1. tvtwomatch
  2. tvtwoattach
  3. tvtwo_ioctl
  4. tvtwo_mmap
  5. tvtwo_alloc_screen
  6. tvtwo_free_screen
  7. tvtwo_show_screen
  8. tvtwo_burner
  9. tvtwo_reset
  10. tvtwo_ramdac_wraddr
  11. tvtwo_directcmap
  12. tvtwo_setcolor

    1 /*      $OpenBSD: tvtwo.c,v 1.11 2007/03/13 19:40:49 miod Exp $ */
    2 /*
    3  * Copyright (c) 2003, 2006, 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 Parallax XVideo and PowerVideo graphics boards.
   31  *
   32  * Some details about these board are available at:
   33  * http://www.jlw.com/~woolsey/parallax/support/developers/xvideotech.html
   34  */
   35 
   36 /*
   37  * The Parallax XVideo series frame buffers are 8/24-bit accelerated
   38  * frame buffers, with hardware MPEG capabilities using a CCube chipset.
   39  */
   40 
   41 /*
   42  * Currently, this driver can only handle the 8-bit and 24-bit planes of the
   43  * frame buffer, in an unaccelerated mode.
   44  *
   45  * TODO:
   46  * - nvram handling
   47  * - use the accelerator
   48  * - interface to the c^3
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/buf.h>
   54 #include <sys/device.h>
   55 #include <sys/ioctl.h>
   56 #include <sys/mman.h>
   57 #include <sys/conf.h>
   58 
   59 #include <uvm/uvm_extern.h>
   60 
   61 #include <machine/autoconf.h>
   62 #include <machine/bus.h>
   63 #include <machine/pmap.h>
   64 #include <machine/cpu.h>
   65 #include <machine/conf.h>
   66 
   67 #include <dev/wscons/wsconsio.h>
   68 #include <dev/wscons/wsdisplayvar.h>
   69 #include <dev/rasops/rasops.h>
   70 #include <machine/fbvar.h>
   71 
   72 #include <dev/sbus/sbusvar.h>
   73 
   74 /*
   75  * The memory layout of the board is as follows:
   76  *
   77  *      PROM0           000000 - 00ffff
   78  *      overlay plane   010000 - 037fff
   79  *      registers       040000 - 0404d0
   80  *      CCube           050000 - 05ffff
   81  *      8-bit plane     080000 - 17ffff
   82  *      24-bit plane    200000 - 6fffff
   83  *      PROM1           7f0000 - 7fffff
   84  *
   85  * Older XVideo provide two sets of SBus registers:
   86  *      R0              040000 - 040800
   87  *      R1              080000 - 17d200
   88  * While the more recent revisions provide only one register:
   89  *      R0              000000 - 7fffff
   90  *
   91  * We currently refuse to attach to the old version because mapping
   92  * things requires us to play with the sbus register ranges, and I
   93  * don't want to play this game without the hardware at hand -- miod
   94  */
   95 
   96 #define PX_PROM0_OFFSET         0x000000
   97 #define PX_OVERLAY_OFFSET       0x010000
   98 #define PX_REG_OFFSET           0x040000
   99 #define PX_CCUBE_OFFSET         0x050000
  100 #define PX_PLANE8_OFFSET        0x080000
  101 #define PX_PLANE24_OFFSET       0x200000
  102 #define PX_PROM1_OFFSET         0x7f0000
  103 
  104 /*
  105  * Partial registers layout
  106  */
  107 
  108 #define PX_REG_DISPKLUDGE       0x00b8  /* write only */
  109 #define DISPKLUDGE_DEFAULT      0xc41f
  110 #define DISPKLUDGE_BLANK        (1 << 12)
  111 #define DISPKLUDGE_SYNC         (1 << 13)
  112 
  113 #define PX_REG_BT463_RED        0x0480
  114 #define PX_REG_BT463_GREEN      0x0490
  115 #define PX_REG_BT463_BLUE       0x04a0
  116 #define PX_REG_BT463_ALL        0x04b0
  117 
  118 #define PX_REG_SIZE             0x04d0
  119 
  120 
  121 /* per-display variables */
  122 struct tvtwo_softc {
  123         struct  sunfb   sc_sunfb;       /* common base device */
  124 
  125         bus_space_tag_t sc_bustag;
  126         bus_addr_t      sc_paddr;
  127 
  128         volatile u_int8_t *sc_m8;
  129         volatile u_int8_t *sc_m24;
  130         volatile u_int8_t *sc_regs;
  131 
  132         int     sc_nscreens;
  133 };
  134 
  135 int     tvtwo_ioctl(void *, u_long, caddr_t, int, struct proc *);
  136 int     tvtwo_alloc_screen(void *, const struct wsscreen_descr *, void **,
  137             int *, int *, long *);
  138 void    tvtwo_free_screen(void *, void *);
  139 int     tvtwo_show_screen(void *, void *, int, void (*cb)(void *, int, int),
  140             void *);
  141 paddr_t tvtwo_mmap(void *, off_t, int);
  142 void    tvtwo_burner(void *, u_int, u_int);
  143 
  144 struct wsdisplay_accessops tvtwo_accessops = {
  145         tvtwo_ioctl,
  146         tvtwo_mmap,
  147         tvtwo_alloc_screen,
  148         tvtwo_free_screen,
  149         tvtwo_show_screen,
  150         NULL,   /* load_font */
  151         NULL,   /* scrollback */
  152         NULL,   /* getchar */
  153         tvtwo_burner,
  154 };
  155 
  156 void    tvtwo_directcmap(struct tvtwo_softc *);
  157 static __inline__
  158 void    tvtwo_ramdac_wraddr(struct tvtwo_softc *, u_int32_t);
  159 void    tvtwo_reset(struct tvtwo_softc *, u_int);
  160 void    tvtwo_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
  161 
  162 int     tvtwomatch(struct device *, void *, void *);
  163 void    tvtwoattach(struct device *, struct device *, void *);
  164 
  165 struct cfattach tvtwo_ca = {
  166         sizeof(struct tvtwo_softc), tvtwomatch, tvtwoattach
  167 };
  168 
  169 struct cfdriver tvtwo_cd = {
  170         NULL, "tvtwo", DV_DULL
  171 };
  172 
  173 /*
  174  * Default frame buffer resolution, depending upon the "freqcode"
  175  */
  176 #define NFREQCODE       5
  177 const int defwidth[NFREQCODE] = { 1152, 1152, 1152, 1024, 640 };
  178 const int defheight[NFREQCODE] = { 900, 900, 900, 768, 480 };
  179 
  180 /*
  181  * Match an XVideo or PowerVideo card.
  182  */
  183 int
  184 tvtwomatch(struct device *parent, void *vcf, void *aux)
  185 {
  186         struct sbus_attach_args *sa = aux;
  187 
  188         if (strcmp(sa->sa_name, "PGI,tvtwo") == 0 ||
  189             strcmp(sa->sa_name, "PGI,tvthree") == 0)
  190                 return (1);
  191 
  192         return (0);
  193 }
  194 
  195 /*
  196  * Attach a display.
  197  */
  198 void
  199 tvtwoattach(struct device *parent, struct device *self, void *args)
  200 {
  201         struct tvtwo_softc *sc = (struct tvtwo_softc *)self;
  202         struct sbus_attach_args *sa = args;
  203         bus_space_tag_t bt;
  204         bus_space_handle_t bh;
  205         int node, width, height, freqcode;
  206         int isconsole;
  207         char *freqstring;
  208 
  209         bt = sa->sa_bustag;
  210         node = sa->sa_node;
  211 
  212         printf(": %s", getpropstring(node, "model"));
  213         printf(", revision %s\n", getpropstring(node, "revision"));
  214 
  215         /* We do not handle older boards yet. */
  216         if (sa->sa_nreg != 1) {
  217                 printf("%s: old-style boards with %d registers are not supported\n"
  218                     "%s: please report this to <sparc@openbsd.org>\n",
  219                     self->dv_xname, sa->sa_nreg,
  220                     self->dv_xname);
  221                 return;
  222         }
  223 
  224         isconsole = node == fbnode;
  225 
  226         /* Map registers. */
  227         sc->sc_bustag = bt;
  228         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_REG_OFFSET,
  229             PX_REG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  230                 printf("%s: couldn't map registers\n", self->dv_xname);
  231                 return;
  232         }
  233         sc->sc_regs = bus_space_vaddr(bt, bh);
  234 
  235         /* Compute framebuffer size. */
  236         freqstring = getpropstring(node, "freqcode");
  237         freqcode = (int)*freqstring;
  238         if (freqcode == 'g') {
  239                 width = height = 1024;
  240         } else {
  241                 if (freqcode < '1' || freqcode > '6')
  242                         freqcode = 0;
  243                 else
  244                         freqcode -= '1';
  245                 width = defwidth[freqcode];
  246                 height = defheight[freqcode];
  247         }
  248 
  249         width = getpropint(node, "hres", width);
  250         height = getpropint(node, "vres", height);
  251 
  252         /*
  253          * Since the depth property is usually missing, we could do
  254          * fb_setsize(&sc->sc_sunfb, 8, width, height, node, 0);
  255          * but for safety in case it would exist and be set to 32, do it
  256          * manually...
  257          */
  258         sc->sc_sunfb.sf_depth = 8;
  259         sc->sc_sunfb.sf_width = width;
  260         sc->sc_sunfb.sf_height = height;
  261         sc->sc_sunfb.sf_linebytes = width >= 1024 ? width : 1024;
  262         sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_linebytes * height;
  263 
  264         /* Map the frame buffer memory area we're interested in. */
  265         sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset);
  266         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE8_OFFSET,
  267             round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
  268             &bh) != 0) {
  269                 printf("%s: couldn't map 8-bit video plane\n", self->dv_xname);
  270                 return;
  271         }
  272         sc->sc_m8 = bus_space_vaddr(bt, bh);
  273         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE24_OFFSET,
  274             round_page(4 * sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
  275             &bh) != 0) {
  276                 printf("%s: couldn't map 32-bit video plane\n", self->dv_xname);
  277                 return;
  278         }
  279         sc->sc_m24 = bus_space_vaddr(bt, bh);
  280 
  281         /* Enable video. */
  282         tvtwo_burner(sc, 1, 0);
  283 
  284         sc->sc_sunfb.sf_ro.ri_hw = sc;
  285         sc->sc_sunfb.sf_ro.ri_bits = (u_char *)sc->sc_m8;
  286 
  287         /*
  288          * If the framebuffer width is under 1024, we will switch from
  289          * the PROM font to the more adequate 8x16 font here.
  290          */
  291         fbwscons_init(&sc->sc_sunfb,
  292             isconsole && (width >= 1024) ? RI_CLEARMARGINS : RI_CLEAR);
  293         fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
  294 
  295         if (isconsole) {
  296                 fbwscons_console_init(&sc->sc_sunfb,
  297                     width >= 1024 ? -1 : 0);
  298         }
  299 
  300         printf("%s: %dx%d\n", self->dv_xname,
  301             sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
  302 
  303         fbwscons_attach(&sc->sc_sunfb, &tvtwo_accessops, isconsole);
  304 }
  305 
  306 int
  307 tvtwo_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  308 {
  309         struct tvtwo_softc *sc = dev;
  310         struct wsdisplay_fbinfo *wdf;
  311 
  312         /*
  313          * Note that, although the emulation (text) mode is running in a
  314          * 8-bit plane, we advertize the frame buffer as 32-bit.
  315          */
  316         switch (cmd) {
  317         case WSDISPLAYIO_GTYPE:
  318                 *(u_int *)data = WSDISPLAY_TYPE_SUN24;
  319                 break;
  320         case WSDISPLAYIO_GINFO:
  321                 wdf = (struct wsdisplay_fbinfo *)data;
  322                 wdf->height = sc->sc_sunfb.sf_height;
  323                 wdf->width = sc->sc_sunfb.sf_width;
  324                 wdf->depth = 32;
  325                 wdf->cmsize = 0;
  326                 break;
  327         case WSDISPLAYIO_GETSUPPORTEDDEPTH:
  328                 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
  329                 break;
  330         case WSDISPLAYIO_LINEBYTES:
  331                 *(u_int *)data = sc->sc_sunfb.sf_linebytes * 4;
  332                 break;
  333 
  334         case WSDISPLAYIO_GETCMAP:
  335         case WSDISPLAYIO_PUTCMAP:
  336                 break;
  337 
  338         case WSDISPLAYIO_SMODE:
  339                 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
  340                         /* Back from X11 to text mode */
  341                         tvtwo_reset(sc, 8);
  342                 } else {
  343                         /* Starting X11, initialize 32-bit mode */
  344                         tvtwo_reset(sc, 32);
  345                 }
  346                 break;
  347 
  348         case WSDISPLAYIO_SVIDEO:
  349         case WSDISPLAYIO_GVIDEO:
  350                 break;
  351 
  352         case WSDISPLAYIO_GCURPOS:
  353         case WSDISPLAYIO_SCURPOS:
  354         case WSDISPLAYIO_GCURMAX:
  355         case WSDISPLAYIO_GCURSOR:
  356         case WSDISPLAYIO_SCURSOR:
  357         default:
  358                 return (-1);
  359         }
  360 
  361         return (0);
  362 }
  363 
  364 /*
  365  * Return the address that would map the given device at the given
  366  * offset, allowing for the given protection, or return -1 for error.
  367  */
  368 paddr_t
  369 tvtwo_mmap(void *v, off_t offset, int prot)
  370 {
  371         struct tvtwo_softc *sc = v;
  372 
  373         if (offset & PGOFSET)
  374                 return (-1);
  375 
  376         /* Allow mapping as a dumb framebuffer from offset 0 */
  377         if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize * 4) {
  378                 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
  379                     PX_PLANE24_OFFSET + offset, prot, BUS_SPACE_MAP_LINEAR));
  380         }
  381 
  382         return (-1);
  383 }
  384 
  385 int
  386 tvtwo_alloc_screen(void *v, const struct wsscreen_descr *type,
  387     void **cookiep, int *curxp, int *curyp, long *attrp)
  388 {
  389         struct tvtwo_softc *sc = v;
  390 
  391         if (sc->sc_nscreens > 0)
  392                 return (ENOMEM);
  393 
  394         *cookiep = &sc->sc_sunfb.sf_ro;
  395         *curyp = 0;
  396         *curxp = 0;
  397         sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
  398              0, 0, 0, attrp);
  399         sc->sc_nscreens++;
  400         return (0);
  401 }
  402 
  403 void
  404 tvtwo_free_screen(void *v, void *cookie)
  405 {
  406         struct tvtwo_softc *sc = v;
  407 
  408         sc->sc_nscreens--;
  409 }
  410 
  411 int
  412 tvtwo_show_screen(void *v, void *cookie, int waitok,
  413     void (*cb)(void *, int, int), void *cbarg)
  414 {
  415         return (0);
  416 }
  417 
  418 void
  419 tvtwo_burner(void *v, u_int on, u_int flags)
  420 {
  421         struct tvtwo_softc *sc = v;
  422         u_int32_t dispkludge;
  423 
  424         if (on)
  425                 dispkludge = DISPKLUDGE_DEFAULT & ~DISPKLUDGE_BLANK;
  426         else {
  427                 dispkludge = DISPKLUDGE_DEFAULT | DISPKLUDGE_BLANK;
  428                 if (flags & WSDISPLAY_BURN_VBLANK)
  429                         dispkludge |= DISPKLUDGE_SYNC;
  430         }
  431 
  432         *(volatile u_int32_t *)(sc->sc_regs + PX_REG_DISPKLUDGE) =
  433             dispkludge;
  434 }
  435 
  436 void
  437 tvtwo_reset(struct tvtwo_softc *sc, u_int depth)
  438 {
  439         if (depth == 32) {
  440                 /* Initialize a direct color map. */
  441                 tvtwo_directcmap(sc);
  442         } else {
  443                 fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
  444         }
  445 }
  446 
  447 /*
  448  * Simple Bt463 programming routines.
  449  */
  450 
  451 static __inline__ void
  452 tvtwo_ramdac_wraddr(struct tvtwo_softc *sc, u_int32_t addr)
  453 {
  454         volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
  455 
  456         dac[0] = (addr & 0xff);         /* lo addr */
  457         dac[1] = ((addr >> 8) & 0xff);  /* hi addr */
  458 }
  459 
  460 void
  461 tvtwo_directcmap(struct tvtwo_softc *sc)
  462 {
  463         volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
  464         u_int32_t c;
  465 
  466         tvtwo_ramdac_wraddr(sc, 0);
  467         for (c = 0; c < 256; c++) {
  468                 dac[3] = c;     /* R */
  469                 dac[3] = c;     /* G */
  470                 dac[3] = c;     /* B */
  471         }
  472 }
  473 
  474 void
  475 tvtwo_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
  476 {
  477         struct tvtwo_softc *sc = v;
  478         volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
  479 
  480         tvtwo_ramdac_wraddr(sc, index);
  481         dac[3] = r;
  482         dac[3] = g;
  483         dac[3] = b;
  484 }

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