root/dev/sbus/cgtwelve.c

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

DEFINITIONS

This source file includes following definitions.
  1. cgtwelvematch
  2. cgtwelveattach
  3. cgtwelve_ioctl
  4. cgtwelve_reset
  5. cgtwelve_mmap
  6. cgtwelve_alloc_screen
  7. cgtwelve_free_screen
  8. cgtwelve_show_screen
  9. cgtwelve_ramdac_wraddr
  10. cgtwelve_prom

    1 /*      $OpenBSD: cgtwelve.c,v 1.5 2007/03/13 19:40:49 miod Exp $       */
    2 
    3 /*
    4  * Copyright (c) 2002, 2003 Miodrag Vallat.  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  * cgtwelve (GS) accelerated 24-bit framebuffer driver.
   30  *
   31  * Enough experiments and SMI's cg12reg.h made this possible.
   32  */
   33 
   34 /*
   35  * The cgtwelve framebuffer is a 3-slot SBUS card, that will fit only in
   36  * SPARCstation 1, 1+, 2 and 5, or in an xbox SBUS extension.
   37  *
   38  * It is a 24-bit 3D accelerated framebuffer made by Matrox, featuring 4MB
   39  * (regular model) or 8MB (high-res model) of video memory, a complex
   40  * windowing engine, double buffering modes, three video planes (overlay,
   41  * 8 bit and 24 bit color), and a lot of colormap combinations.
   42  *
   43  * All of this is driven by a set of three Bt462 ramdacs (latched unless
   44  * explicitely programmed), and a couple of other Matrox-specific chips.
   45  *
   46  * XXX The high res card is untested.
   47  */
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/buf.h>
   52 #include <sys/device.h>
   53 #include <sys/ioctl.h>
   54 #include <sys/conf.h>
   55 
   56 #include <uvm/uvm_extern.h>
   57 
   58 #include <machine/autoconf.h>
   59 #include <machine/bus.h>
   60 #include <machine/pmap.h>
   61 #include <machine/cpu.h>
   62 #include <machine/conf.h>
   63 
   64 #include <dev/wscons/wsconsio.h>
   65 #include <dev/wscons/wsdisplayvar.h>
   66 #include <dev/rasops/rasops.h>
   67 #include <machine/fbvar.h>
   68 
   69 #include <dev/sbus/sbusvar.h>
   70 
   71 #include <dev/sbus/cgtwelvereg.h>
   72 
   73 #include <dev/cons.h>   /* for prom console hook */
   74 
   75 /* per-display variables */
   76 struct cgtwelve_softc {
   77         struct  sunfb   sc_sunfb;       /* common base device */
   78         bus_space_tag_t sc_bustag;
   79         bus_addr_t      sc_paddr;
   80 
   81         volatile struct cgtwelve_dpu *sc_dpu;
   82         volatile struct cgtwelve_apu *sc_apu;
   83         volatile struct cgtwelve_dac *sc_ramdac;        /* RAMDAC registers */
   84         volatile u_char *sc_overlay;    /* overlay or enable plane */
   85         volatile u_long *sc_inten;      /* true color plane */
   86 
   87         int     sc_highres;
   88         int     sc_nscreens;
   89 };
   90 
   91 int     cgtwelve_ioctl(void *, u_long, caddr_t, int, struct proc *);
   92 int     cgtwelve_alloc_screen(void *, const struct wsscreen_descr *, void **,
   93             int *, int *, long *);
   94 void    cgtwelve_free_screen(void *, void *);
   95 int     cgtwelve_show_screen(void *, void *, int, void (*cb)(void *, int, int),
   96             void *);
   97 paddr_t cgtwelve_mmap(void *, off_t, int);
   98 void    cgtwelve_reset(struct cgtwelve_softc *, int);
   99 void    cgtwelve_prom(void *);
  100 
  101 static __inline__ void cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc,
  102             u_int32_t addr);
  103 
  104 struct wsdisplay_accessops cgtwelve_accessops = {
  105         cgtwelve_ioctl,
  106         cgtwelve_mmap,
  107         cgtwelve_alloc_screen,
  108         cgtwelve_free_screen,
  109         cgtwelve_show_screen,
  110         NULL,   /* load_font */
  111         NULL,   /* scrollback */
  112         NULL,   /* getchar */
  113         NULL    /* burner */
  114 };
  115 
  116 int     cgtwelvematch(struct device *, void *, void *);
  117 void    cgtwelveattach(struct device *, struct device *, void *);
  118 
  119 struct cfattach cgtwelve_ca = {
  120         sizeof(struct cgtwelve_softc), cgtwelvematch, cgtwelveattach
  121 };
  122 
  123 struct cfdriver cgtwelve_cd = {
  124         NULL, "cgtwelve", DV_DULL
  125 };
  126 
  127 
  128 /*
  129  * Match a cgtwelve.
  130  */
  131 int
  132 cgtwelvematch(struct device *parent, void *vcf, void *aux)
  133 {
  134         struct cfdata *cf = vcf;
  135         struct sbus_attach_args *sa = aux;
  136 
  137         if (strcmp(cf->cf_driver->cd_name, sa->sa_name) != 0)
  138                 return (0);
  139 
  140         return (1);
  141 }
  142 
  143 /*
  144  * Attach and initialize a cgtwelve.
  145  */
  146 void
  147 cgtwelveattach(struct device *parent, struct device *self, void *args)
  148 {
  149         struct cgtwelve_softc *sc = (struct cgtwelve_softc *)self;
  150         struct sbus_attach_args *sa = args;
  151         bus_space_tag_t bt;
  152         bus_space_handle_t bh;
  153         int node, isconsole = 0;
  154         char *ps;
  155 
  156         bt = sa->sa_bustag;
  157         node = sa->sa_node;
  158 
  159         printf(": %s", getpropstring(node, "model"));
  160         ps = getpropstring(node, "dev_id");
  161         if (*ps != '\0')
  162                 printf(" (%s)", ps);
  163         printf("\n");
  164 
  165         isconsole = node == fbnode;
  166 
  167         if (sa->sa_nreg == 0) {
  168                 printf("%s: no SBus registers!\n", self->dv_xname);
  169                 return;
  170         }
  171 
  172         sc->sc_bustag = bt;
  173 
  174         /*
  175          * Map registers
  176          */
  177         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
  178             CG12_OFF_DPU, sizeof(struct cgtwelve_dpu),
  179             BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  180                 printf("%s: can't map DPU registers\n", self->dv_xname);
  181                 return;
  182         }
  183         sc->sc_dpu = bus_space_vaddr(bt, bh);
  184         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
  185             CG12_OFF_APU, sizeof(struct cgtwelve_apu),
  186             BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  187                 printf("%s: can't map APU registers\n", self->dv_xname);
  188                 return;
  189         }
  190         sc->sc_apu = bus_space_vaddr(bt, bh);
  191         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
  192             CG12_OFF_DAC, sizeof(struct cgtwelve_dac),
  193             BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  194                 printf("%s: can't map RAMDAC registers\n", self->dv_xname);
  195                 return;
  196         }
  197         sc->sc_ramdac = bus_space_vaddr(bt, bh);
  198 
  199         /*
  200          * The console is using the 1-bit overlay plane, while the prom
  201          * will correctly report 32 bit depth.
  202          */
  203         fb_setsize(&sc->sc_sunfb, 1, CG12_WIDTH, CG12_HEIGHT,
  204             node, 0);
  205         sc->sc_sunfb.sf_depth = 1;
  206         sc->sc_sunfb.sf_linebytes = sc->sc_sunfb.sf_width / 8;
  207         sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_height *
  208             sc->sc_sunfb.sf_linebytes;
  209 
  210         sc->sc_highres = sc->sc_sunfb.sf_width == CG12_WIDTH_HR;
  211 
  212         /*
  213          * Map planes
  214          */
  215         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
  216             (sc->sc_highres ? CG12_OFF_OVERLAY0_HR : CG12_OFF_OVERLAY0),
  217             round_page(sc->sc_highres ? CG12_SIZE_OVERLAY_HR :
  218                 CG12_SIZE_OVERLAY), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  219                 printf("%s: can't map overlay plane\n", self->dv_xname);
  220                 return;
  221         }
  222         sc->sc_overlay = bus_space_vaddr(bt, bh);
  223         if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
  224             (sc->sc_highres ? CG12_OFF_INTEN_HR : CG12_OFF_INTEN),
  225             round_page(sc->sc_highres ? CG12_SIZE_COLOR24_HR :
  226                 CG12_SIZE_COLOR24), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  227                 printf("%s: can't map color plane\n", self->dv_xname);
  228                 return;
  229         }
  230         sc->sc_inten = bus_space_vaddr(bt, bh);
  231         sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset +
  232             (sc->sc_highres ? CG12_OFF_INTEN_HR : CG12_OFF_INTEN));
  233 
  234         /* reset cursor & frame buffer controls */
  235         sc->sc_sunfb.sf_depth = 0;      /* force action */
  236         cgtwelve_reset(sc, 1);
  237 
  238         sc->sc_sunfb.sf_ro.ri_bits = (void *)sc->sc_overlay;
  239         sc->sc_sunfb.sf_ro.ri_hw = sc;
  240         fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR);
  241 
  242         if (isconsole) {
  243                 fbwscons_console_init(&sc->sc_sunfb, -1);
  244                 shutdownhook_establish(cgtwelve_prom, sc);
  245         }
  246 
  247         printf("%s: %dx%d", self->dv_xname,
  248             sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
  249         ps = getpropstring(node, "ucoderev");
  250         if (*ps != '\0')
  251                 printf(", microcode rev. %s", ps);
  252         printf("\n");
  253 
  254         fbwscons_attach(&sc->sc_sunfb, &cgtwelve_accessops, isconsole);
  255 }
  256 
  257 int
  258 cgtwelve_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  259 {
  260         struct cgtwelve_softc *sc = dev;
  261         struct wsdisplay_fbinfo *wdf;
  262 
  263         /*
  264          * Note that, although the emulation (text) mode is running in the
  265          * overlay plane, we advertize the frame buffer as the full-blown
  266          * 32-bit beast it is.
  267          */
  268         switch (cmd) {
  269         case WSDISPLAYIO_GTYPE:
  270                 *(u_int *)data = WSDISPLAY_TYPE_SUNCG12;
  271                 break;
  272         case WSDISPLAYIO_GINFO:
  273                 wdf = (struct wsdisplay_fbinfo *)data;
  274                 wdf->height = sc->sc_sunfb.sf_height;
  275                 wdf->width = sc->sc_sunfb.sf_width;
  276                 wdf->depth = 32;
  277                 wdf->cmsize = 0;
  278                 break;
  279         case WSDISPLAYIO_GETSUPPORTEDDEPTH:
  280                 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
  281                 break;
  282         case WSDISPLAYIO_LINEBYTES:
  283                 *(u_int *)data = sc->sc_sunfb.sf_linebytes * 32;
  284                 break;
  285 
  286         case WSDISPLAYIO_GETCMAP:
  287         case WSDISPLAYIO_PUTCMAP:
  288                 break;
  289 
  290         case WSDISPLAYIO_SMODE:
  291                 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
  292                         /* Back from X11 to text mode */
  293                         cgtwelve_reset(sc, 1);
  294                 } else {
  295                         /* Starting X11, switch to 32 bit mode */
  296                         cgtwelve_reset(sc, 32);
  297                 }
  298                 break;
  299 
  300         case WSDISPLAYIO_SVIDEO:
  301         case WSDISPLAYIO_GVIDEO:
  302                 break;
  303 
  304         default:
  305                 return (-1);    /* not supported yet */
  306         }
  307 
  308         return (0);
  309 }
  310 
  311 /*
  312  * Clean up hardware state (e.g., after bootup or after X crashes).
  313  */
  314 void
  315 cgtwelve_reset(struct cgtwelve_softc *sc, int depth)
  316 {
  317         u_int32_t c;
  318 
  319         if (sc->sc_sunfb.sf_depth != depth) {
  320                 if (depth == 1) {
  321                         /*
  322                          * Select the enable plane as sc_overlay, and fill it.
  323                          */
  324                         sc->sc_apu->hpage = sc->sc_highres ?
  325                             CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE;
  326                         sc->sc_apu->haccess = CG12_HACCESS_ENABLE;
  327                         sc->sc_dpu->pln_sl_host = CG12_PLN_SL_ENABLE;
  328                         sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_ENABLE;
  329                         sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_ENABLE;
  330 
  331                         memset((void *)sc->sc_overlay, 0xff, sc->sc_highres ?
  332                             CG12_SIZE_ENABLE_HR : CG12_SIZE_ENABLE);
  333 
  334                         /*
  335                          * Select the overlay plane as sc_overlay.
  336                          */
  337                         sc->sc_apu->hpage = sc->sc_highres ?
  338                             CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY;
  339                         sc->sc_apu->haccess = CG12_HACCESS_OVERLAY;
  340                         sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY;
  341                         sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY;
  342                         sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY;
  343 
  344                         /*
  345                          * Upload a strict mono colormap, or the text
  346                          * upon returning from 32 bit mode would appear
  347                          * as (slightly dark) white on white.
  348                          */
  349                         cgtwelve_ramdac_wraddr(sc, 0);
  350                         sc->sc_ramdac->color = 0x00000000;
  351                         for (c = 1; c < 256; c++)
  352                                 sc->sc_ramdac->color = 0x00ffffff;
  353                 } else {
  354                         /*
  355                          * Select the overlay plane as sc_overlay.
  356                          */
  357                         sc->sc_apu->hpage = sc->sc_highres ?
  358                             CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY;
  359                         sc->sc_apu->haccess = CG12_HACCESS_OVERLAY;
  360                         sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY;
  361                         sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY;
  362                         sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY;
  363 
  364                         /*
  365                          * Do not attempt to somewhat preserve screen
  366                          * contents - reading the overlay plane and writing
  367                          * to the color plane at the same time is not
  368                          * reliable, and allocating memory to save a copy
  369                          * of the overlay plane would be awful.
  370                          */
  371                         bzero((void *)sc->sc_overlay, sc->sc_highres ?
  372                             CG12_SIZE_OVERLAY_HR : CG12_SIZE_OVERLAY);
  373 
  374                         /*
  375                          * Select the enable plane as sc_overlay, and clear it.
  376                          */
  377                         sc->sc_apu->hpage = sc->sc_highres ?
  378                             CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE;
  379                         sc->sc_apu->haccess = CG12_HACCESS_ENABLE;
  380                         sc->sc_dpu->pln_sl_host = CG12_PLN_SL_ENABLE;
  381                         sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_ENABLE;
  382                         sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_ENABLE;
  383 
  384                         bzero((void *)sc->sc_overlay, sc->sc_highres ?
  385                             CG12_SIZE_ENABLE_HR : CG12_SIZE_ENABLE);
  386 
  387                         /*
  388                          * Select the intensity (color) plane, and clear it.
  389                          */
  390                         sc->sc_apu->hpage = sc->sc_highres ?
  391                             CG12_HPAGE_24BIT_HR : CG12_HPAGE_24BIT;
  392                         sc->sc_apu->haccess = CG12_HACCESS_24BIT;
  393                         sc->sc_dpu->pln_sl_host = CG12_PLN_SL_24BIT;
  394                         sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_24BIT;
  395                         sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_24BIT;
  396 
  397                         memset((void *)sc->sc_inten, 0x00ffffff,
  398                             sc->sc_highres ?
  399                               CG12_SIZE_COLOR24_HR : CG12_SIZE_COLOR24);
  400 
  401                         /*
  402                          * Use a direct colormap (ramp)
  403                          */
  404                         cgtwelve_ramdac_wraddr(sc, 0);
  405                         for (c = 0; c < 256; c++)
  406                                 sc->sc_ramdac->color = c | (c << 8) | (c << 16);
  407                 }
  408         }
  409 
  410         sc->sc_sunfb.sf_depth = depth;
  411 }
  412 
  413 /*
  414  * Return the address that would map the given device at the given
  415  * offset, allowing for the given protection, or return -1 for error.
  416  */
  417 paddr_t
  418 cgtwelve_mmap(void *v, off_t offset, int prot)
  419 {
  420         struct cgtwelve_softc *sc = v;
  421 
  422         if (offset & PGOFSET || offset < 0)
  423                 return (-1);
  424 
  425         /*
  426          * Note that mmap() will invoke this function only if we are NOT
  427          * in emulation mode, so we can assume 32 bit mode safely here.
  428          */
  429         if (offset < sc->sc_sunfb.sf_fbsize * 32) {
  430                 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, offset,
  431                     prot, BUS_SPACE_MAP_LINEAR));
  432         }
  433 
  434         return (-1);
  435 }
  436 
  437 int
  438 cgtwelve_alloc_screen(void *v, const struct wsscreen_descr *type,
  439     void **cookiep, int *curxp, int *curyp, long *attrp)
  440 {
  441         struct cgtwelve_softc *sc = v;
  442 
  443         if (sc->sc_nscreens > 0)
  444                 return (ENOMEM);
  445 
  446         *cookiep = &sc->sc_sunfb.sf_ro;
  447         *curyp = 0;
  448         *curxp = 0;
  449         sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
  450              0, 0, 0, attrp);
  451         sc->sc_nscreens++;
  452         return (0);
  453 }
  454 
  455 void
  456 cgtwelve_free_screen(void *v, void *cookie)
  457 {
  458         struct cgtwelve_softc *sc = v;
  459 
  460         sc->sc_nscreens--;
  461 }
  462 
  463 int
  464 cgtwelve_show_screen(void *v, void *cookie, int waitok,
  465     void (*cb)(void *, int, int), void *cbarg)
  466 {
  467         return (0);
  468 }
  469 
  470 /*
  471  * Simple Bt462 programming routines.
  472  */
  473 
  474 static __inline__ void 
  475 cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc, u_int32_t addr)
  476 {
  477         sc->sc_ramdac->addr_lo = (addr & 0xff);
  478         sc->sc_ramdac->addr_hi = ((addr >> 8) & 0xff);
  479 }
  480 
  481 /*
  482  * Shutdown hook used to restore PROM-compatible video mode on shutdown,
  483  * so that the PROM prompt is visible again.
  484  */
  485 void
  486 cgtwelve_prom(void *v)
  487 {
  488         struct cgtwelve_softc *sc = v;
  489         extern struct consdev consdev_prom;
  490 
  491         if (sc->sc_sunfb.sf_depth != 1) {
  492                 cgtwelve_reset(sc, 1);
  493 
  494                 /*
  495                  * Go back to prom output for the last few messages, so they
  496                  * will be displayed correctly.
  497                  */
  498                 cn_tab = &consdev_prom;
  499         }
  500 }

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