The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/vgas3.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "io.h"
    7 #include "../port/error.h"
    8 
    9 #define Image   IMAGE
   10 #include <draw.h>
   11 #include <memdraw.h>
   12 #include <cursor.h>
   13 #include "screen.h"
   14 
   15 enum {
   16         PCIS3           = 0x5333,               /* PCI VID */
   17 
   18         SAVAGE3D        = 0x8A20,               /* PCI DID */
   19         SAVAGE3DMV      = 0x8A21,
   20         SAVAGE4         = 0x8A22,
   21         PROSAVAGEP      = 0x8A25,
   22         PROSAVAGEK      = 0x8A26,
   23         PROSAVAGE8      = 0x8D04,
   24         SAVAGEMXMV      = 0x8C10,
   25         SAVAGEMX        = 0x8C11,
   26         SAVAGEIXMV      = 0x8C12,
   27         SAVAGEIX        = 0x8C13,
   28         SUPERSAVAGEIXC16 = 0x8C2E,
   29         SAVAGE2000      = 0x9102,
   30 
   31         VIRGE           = 0x5631,
   32         VIRGEGX2        = 0x8A10,
   33         VIRGEDXGX       = 0x8A01,
   34         VIRGEVX         = 0x883D,
   35         VIRGEMX         = 0x8C01,
   36         VIRGEMXP        = 0x8C03,
   37 
   38         VIRTUALPC2004   = 0x8810,
   39         AURORA64VPLUS   = 0x8812,
   40 };
   41 
   42 static int
   43 s3pageset(VGAscr* scr, int page)
   44 {
   45         uchar crt35, crt51;
   46         int opage;
   47 
   48         crt35 = vgaxi(Crtx, 0x35);
   49         if(scr->gscreen->depth >= 8){
   50                 /*
   51                  * The S3 registers need to be unlocked for this.
   52                  * Let's hope they are already:
   53                  *      vgaxo(Crtx, 0x38, 0x48);
   54                  *      vgaxo(Crtx, 0x39, 0xA0);
   55                  *
   56                  * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
   57                  * the upper 2 in Crt51<3:2>.
   58                  */
   59                 vgaxo(Crtx, 0x35, page & 0x0F);
   60                 crt51 = vgaxi(Crtx, 0x51);
   61                 vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
   62                 opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
   63         }
   64         else{
   65                 vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
   66                 opage = (crt35>>2) & 0x03;
   67         }
   68 
   69         return opage;
   70 }
   71 
   72 static void
   73 s3page(VGAscr* scr, int page)
   74 {
   75         int id;
   76 
   77         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
   78         switch(id){
   79 
   80         case VIRGEGX2:
   81                 break;
   82 
   83         default:
   84                 lock(&scr->devlock);
   85                 s3pageset(scr, page);
   86                 unlock(&scr->devlock);
   87                 break;
   88         }
   89 }
   90 
   91 static void
   92 s3linear(VGAscr* scr, int, int)
   93 {
   94         int id, j;
   95         ulong mmiobase, mmiosize;
   96         Pcidev *p;
   97         
   98         vgalinearpciid(scr, PCIS3, 0);
   99         p = scr->pci;
  100         if(scr->paddr == 0 || p == nil)
  101                 return;
  102                 
  103         addvgaseg("s3screen", scr->paddr, scr->apsize);
  104         
  105         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
  106         switch(id){                     /* find mmio */
  107         case SAVAGE4:
  108         case PROSAVAGEP:
  109         case PROSAVAGEK:
  110         case PROSAVAGE8:
  111         case SUPERSAVAGEIXC16:
  112                 /*
  113                  * We could assume that the MMIO registers
  114                  * will be in the screen segment and just use
  115                  * that, but PCI software is allowed to move them
  116                  * if it feels like it, so we look for an aperture of
  117                  * the right size; only the first 512k actually means
  118                  * anything.  The S3 engineers overestimated how
  119                  * much space they would need in the first design.
  120                  */
  121                 for(j=0; j<nelem(p->mem); j++){
  122                         if((p->mem[j].bar&~0x0F) != scr->paddr)
  123                         if(p->mem[j].size==512*1024 || p->mem[j].size==16*1024*1024){
  124                                 mmiobase = p->mem[j].bar & ~0x0F;
  125                                 mmiosize = 512*1024;
  126                                 scr->mmio = vmap(mmiobase, mmiosize);
  127                                 if(scr->mmio == nil)
  128                                         return;
  129                                 addvgaseg("savagemmio", mmiobase, mmiosize);
  130                                 break;
  131                         }
  132                 }
  133         }
  134 }
  135 
  136 static void
  137 s3vsyncactive(void)
  138 {
  139         /*
  140          * Hardware cursor information is fetched from display memory
  141          * during the horizontal blank active time. The 80x chips may hang
  142          * if the cursor is turned on or off during this period.
  143          */
  144         while((vgai(Status1) & 0x08) == 0)
  145                 ;
  146 }
  147 
  148 static void
  149 s3disable(VGAscr*)
  150 {
  151         uchar crt45;
  152 
  153         /*
  154          * Turn cursor off.
  155          */
  156         crt45 = vgaxi(Crtx, 0x45) & 0xFE;
  157         s3vsyncactive();
  158         vgaxo(Crtx, 0x45, crt45);
  159 }
  160 
  161 static void
  162 s3load(VGAscr* scr, Cursor* curs)
  163 {
  164         uchar *p;
  165         int id, dolock, opage, x, y;
  166 
  167         /*
  168          * Disable the cursor and
  169          * set the pointer to the two planes.
  170          */
  171         s3disable(scr);
  172 
  173         opage = 0;
  174         p = scr->vaddr;
  175         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
  176         switch(id){
  177 
  178         case VIRTUALPC2004:
  179         case VIRGE:
  180         case VIRGEDXGX:
  181         case VIRGEGX2:
  182         case VIRGEVX:   
  183         case SAVAGEMXMV:
  184         case SAVAGEIXMV:
  185         case SAVAGE4:
  186         case PROSAVAGEP:
  187         case PROSAVAGEK:
  188         case PROSAVAGE8:
  189         case SUPERSAVAGEIXC16:
  190                 dolock = 0;
  191                 p += scr->storage;
  192                 break;
  193 
  194         default:
  195                 dolock = 1;
  196                 lock(&scr->devlock);
  197                 opage = s3pageset(scr, scr->storage>>16);
  198                 p += (scr->storage & 0xFFFF);
  199                 break;
  200         }
  201 
  202         /*
  203          * The cursor is set in Microsoft Windows format (the ViRGE/GX2 doesn't
  204          * support the X11 format) which gives the following truth table:
  205          *      and xor colour
  206          *       0   0  background colour
  207          *       0   1  foreground colour
  208          *       1   0  current screen pixel
  209          *       1   1  NOT current screen pixel
  210          * Put the cursor into the top-left of the 64x64 array.
  211          *
  212          * The cursor pattern in memory is interleaved words of
  213          * AND and XOR patterns.
  214          */
  215         for(y = 0; y < 64; y++){
  216                 for(x = 0; x < 64/8; x += 2){
  217                         if(x < 16/8 && y < 16){
  218                                 *p++ = ~(curs->clr[2*y + x]|curs->set[2*y + x]);
  219                                 *p++ = ~(curs->clr[2*y + x+1]|curs->set[2*y + x+1]);
  220                                 *p++ = curs->set[2*y + x];
  221                                 *p++ = curs->set[2*y + x+1];
  222                         }
  223                         else {
  224                                 *p++ = 0xFF;
  225                                 *p++ = 0xFF;
  226                                 *p++ = 0x00;
  227                                 *p++ = 0x00;
  228                         }
  229                 }
  230         }
  231 
  232         if(dolock){
  233                 s3pageset(scr, opage);
  234                 unlock(&scr->devlock);
  235         }
  236 
  237         /*
  238          * Save the cursor hotpoint and enable the cursor.
  239          */
  240         scr->offset = curs->offset;
  241         s3vsyncactive();
  242         vgaxo(Crtx, 0x45, 0x01);
  243 }
  244 
  245 static int
  246 s3move(VGAscr* scr, Point p)
  247 {
  248         int x, xo, y, yo;
  249 
  250         /*
  251          * Mustn't position the cursor offscreen even partially,
  252          * or it disappears. Therefore, if x or y is -ve, adjust the
  253          * cursor offset instead.
  254          * There seems to be a bug in that if the offset is 1, the
  255          * cursor doesn't disappear off the left edge properly, so
  256          * round it up to be even.
  257          */
  258         if((x = p.x+scr->offset.x) < 0){
  259                 xo = -x;
  260                 xo = ((xo+1)/2)*2;
  261                 x = 0;
  262         }
  263         else
  264                 xo = 0;
  265         if((y = p.y+scr->offset.y) < 0){
  266                 yo = -y;
  267                 y = 0;
  268         }
  269         else
  270                 yo = 0;
  271 
  272         vgaxo(Crtx, 0x46, (x>>8) & 0x07);
  273         vgaxo(Crtx, 0x47, x & 0xFF);
  274         vgaxo(Crtx, 0x49, y & 0xFF);
  275         vgaxo(Crtx, 0x4E, xo);
  276         vgaxo(Crtx, 0x4F, yo);
  277         vgaxo(Crtx, 0x48, (y>>8) & 0x07);
  278 
  279         return 0;
  280 }
  281 
  282 static void
  283 s3enable(VGAscr* scr)
  284 {
  285         int i;
  286         ulong storage;
  287 
  288         s3disable(scr);
  289 
  290         /*
  291          * Cursor colours. Set both the CR0[EF] and the colour
  292          * stack in case we are using a 16-bit RAMDAC.
  293          */
  294         vgaxo(Crtx, 0x0E, Pwhite);
  295         vgaxo(Crtx, 0x0F, Pblack);
  296         vgaxi(Crtx, 0x45);
  297 
  298         for(i = 0; i < 3; i++)
  299                 vgaxo(Crtx, 0x4A, Pblack);
  300         vgaxi(Crtx, 0x45);
  301         for(i = 0; i < 3; i++)
  302                 vgaxo(Crtx, 0x4B, Pwhite);
  303 
  304         /*
  305          * Find a place for the cursor data in display memory.
  306          * Must be on a 1024-byte boundary.
  307          */
  308         storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024;
  309         vgaxo(Crtx, 0x4C, storage>>8);
  310         vgaxo(Crtx, 0x4D, storage & 0xFF);
  311         storage *= 1024;
  312         scr->storage = storage;
  313 
  314         /*
  315          * Load, locate and enable the cursor
  316          * in Microsoft Windows format.
  317          */
  318         s3load(scr, &arrow);
  319         s3move(scr, ZP);
  320         vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
  321         s3vsyncactive();
  322         vgaxo(Crtx, 0x45, 0x01);
  323 }
  324 
  325 /*
  326  * The manual gives byte offsets, but we want ulong offsets, hence /4.
  327  */
  328 enum {
  329         SrcBase = 0xA4D4/4,
  330         DstBase = 0xA4D8/4,
  331         Stride = 0xA4E4/4,
  332         FgrdData = 0xA4F4/4,
  333         WidthHeight = 0xA504/4,
  334         SrcXY = 0xA508/4,
  335         DestXY = 0xA50C/4,
  336         Command = 0xA500/4,
  337         SubStat = 0x8504/4,
  338         FifoStat = 0x850C/4,
  339 };
  340 
  341 /*
  342  * Wait for writes to VGA memory via linear aperture to flush.
  343  */
  344 enum {Maxloop = 1<<24};
  345 struct {
  346         ulong linear;
  347         ulong fifo;
  348         ulong idle;
  349         ulong lineartimeout;
  350         ulong fifotimeout;
  351         ulong idletimeout;
  352 } waitcount;
  353 
  354 static void
  355 waitforlinearfifo(VGAscr *scr)
  356 {
  357         ulong *mmio;
  358         long x;
  359         static ulong nwaitforlinearfifo;
  360         ulong mask, val;
  361 
  362         switch(scr->id){
  363         default:
  364                 panic("unknown scr->id in s3 waitforlinearfifo");
  365         case 0x8A01:    /* ViRGE/[DG]X.  XFree86 says no waiting necessary */
  366                 return;
  367         case 0x5631:    /* ViRGE */
  368         case 0x883D:    /* ViRGE/VX */
  369                 mask = 0x0F<<6;
  370                 val = 0x08<<6;
  371                 break;
  372         case 0x8A10:    /* ViRGE/GX2 */
  373                 mask = 0x1F<<6;
  374                 val = 0x10<<6;
  375                 break;
  376         }
  377         mmio = scr->mmio;
  378         x = 0;
  379         while((mmio[FifoStat]&mask) != val && x++ < Maxloop)
  380                 waitcount.linear++;
  381         if(x >= Maxloop)
  382                 waitcount.lineartimeout++;
  383 }
  384 
  385 static void
  386 waitforfifo(VGAscr *scr, int entries)
  387 {
  388         ulong *mmio;
  389         long x;
  390         static ulong nwaitforfifo;
  391 
  392         mmio = scr->mmio;
  393         x = 0;
  394         while((mmio[SubStat]&0x1F00) < ((entries+2)<<8) && x++ < Maxloop)
  395                 waitcount.fifo++;
  396         if(x >= Maxloop)
  397                 waitcount.fifotimeout++;
  398 }
  399 
  400 static void
  401 waitforidle(VGAscr *scr)
  402 {
  403         ulong *mmio;
  404         long x;
  405 
  406         mmio = scr->mmio;
  407         x = 0;
  408         while((mmio[SubStat]&0x3F00) != 0x3000 && x++ < Maxloop)
  409                 waitcount.idle++;
  410         if(x >= Maxloop)
  411                 waitcount.idletimeout++;
  412 }
  413 
  414 static int
  415 hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
  416 {
  417         enum { Bitbltop = 0xCC };       /* copy source */
  418         ulong *mmio;
  419         ulong cmd, stride;
  420         Point dp, sp;
  421         int did, d;
  422 
  423         d = scr->gscreen->depth;
  424         did = (d-8)/8;
  425         cmd = 0x00000020|(Bitbltop<<17)|(did<<2);
  426         stride = Dx(scr->gscreen->r)*d/8;
  427 
  428         if(r.min.x <= sr.min.x){
  429                 cmd |= 1<<25;
  430                 dp.x = r.min.x;
  431                 sp.x = sr.min.x;
  432         }else{
  433                 dp.x = r.max.x-1;
  434                 sp.x = sr.max.x-1;
  435         }
  436 
  437         if(r.min.y <= sr.min.y){
  438                 cmd |= 1<<26;
  439                 dp.y = r.min.y;
  440                 sp.y = sr.min.y;
  441         }else{
  442                 dp.y = r.max.y-1;
  443                 sp.y = sr.max.y-1;
  444         }
  445 
  446         mmio = scr->mmio;
  447         waitforlinearfifo(scr);
  448         waitforfifo(scr, 7);
  449         mmio[SrcBase] = scr->paddr;
  450         mmio[DstBase] = scr->paddr;
  451         mmio[Stride] = (stride<<16)|stride;
  452         mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
  453         mmio[SrcXY] = (sp.x<<16)|sp.y;
  454         mmio[DestXY] = (dp.x<<16)|dp.y;
  455         mmio[Command] = cmd;
  456         waitforidle(scr);
  457         return 1;
  458 }
  459 
  460 static int
  461 hwfill(VGAscr *scr, Rectangle r, ulong sval)
  462 {
  463         enum { Bitbltop = 0xCC };       /* copy source */
  464         ulong *mmio;
  465         ulong cmd, stride;
  466         int did, d;
  467 
  468         d = scr->gscreen->depth;
  469         did = (d-8)/8;
  470         cmd = 0x16000120|(Bitbltop<<17)|(did<<2);
  471         stride = Dx(scr->gscreen->r)*d/8;
  472         mmio = scr->mmio;
  473         waitforlinearfifo(scr);
  474         waitforfifo(scr, 8);
  475         mmio[SrcBase] = scr->paddr;
  476         mmio[DstBase] = scr->paddr;
  477         mmio[DstBase] = scr->paddr;
  478         mmio[Stride] = (stride<<16)|stride;
  479         mmio[FgrdData] = sval;
  480         mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
  481         mmio[DestXY] = (r.min.x<<16)|r.min.y;
  482         mmio[Command] = cmd;
  483         waitforidle(scr);
  484         return 1;
  485 }
  486 
  487 enum {
  488         CursorSyncCtl = 0x0D,   /* in Seqx */
  489         VsyncHi = 0x80,
  490         VsyncLo = 0x40,
  491         HsyncHi = 0x20,
  492         HsyncLo = 0x10,
  493 };
  494 
  495 static void
  496 s3blank(VGAscr*, int blank)
  497 {
  498         uchar x;
  499 
  500         x = vgaxi(Seqx, CursorSyncCtl);
  501         x &= ~0xF0;
  502         if(blank)
  503                 x |= VsyncLo | HsyncLo;
  504         vgaxo(Seqx, CursorSyncCtl, x);
  505 }
  506 
  507 static void
  508 s3drawinit(VGAscr *scr)
  509 {
  510         extern void savageinit(VGAscr*);        /* vgasavage.c */
  511         ulong id;
  512 
  513         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
  514         scr->id = id;
  515 
  516         /*
  517          * It's highly likely that other ViRGEs will work without
  518          * change to the driver, with the exception of the size of
  519          * the linear aperture memory write FIFO.  Since we don't
  520          * know that size, I'm not turning them on.  See waitforlinearfifo
  521          * above.
  522          */
  523         scr->blank = s3blank;
  524         /* hwblank = 1;         not known to work well */
  525 
  526         switch(id){
  527         case VIRGE:
  528         case VIRGEVX:
  529         case VIRGEGX2:
  530                 scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
  531                 scr->fill = hwfill;
  532                 scr->scroll = hwscroll;
  533                 break;
  534         case SAVAGEMXMV:
  535         case SAVAGEIXMV:
  536                 scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
  537                 savageinit(scr);        
  538                 break;
  539         case SUPERSAVAGEIXC16:
  540         case SAVAGE4:
  541         case PROSAVAGEP:
  542         case PROSAVAGE8:
  543         case PROSAVAGEK:
  544                 /* scr->mmio is set by s3linear */
  545                 savageinit(scr);
  546                 break;
  547         }
  548 }
  549 
  550 VGAdev vgas3dev = {
  551         "s3",
  552 
  553         0,
  554         0,
  555         s3page,
  556         s3linear,
  557         s3drawinit,
  558 };
  559 
  560 VGAcur vgas3cur = {
  561         "s3hwgc",
  562 
  563         s3enable,
  564         s3disable,
  565         s3load,
  566         s3move,
  567 };
  568 

Cache object: 2be58fc334fc2336aec72b124d72761d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.