S3VMODETABLE * pmt;
S3VMODEENTRY * pmt;
S3SAVInit(mode)DisplayModePtr mode;{unsigned char tmp;int width,dclk;int i, j;unsigned int Refresh;#ifdef USEBIOSS3VMODETABLE * pmt;#endif   /* First we adjust the horizontal timings if needed */   if(s3vPriv.HorizScaleFactor != 1)      if (!mode->CrtcHAdjusted) {             mode->CrtcHDisplay *= s3vPriv.HorizScaleFactor;             mode->CrtcHSyncStart *= s3vPriv.HorizScaleFactor;             mode->CrtcHSyncEnd *= s3vPriv.HorizScaleFactor;             mode->CrtcHTotal *= s3vPriv.HorizScaleFactor;             mode->CrtcHSkew *= s3vPriv.HorizScaleFactor;             mode->CrtcHAdjusted = TRUE;             }   if(!vgaHWInit (mode, sizeof(vgaS3VRec)))      return FALSE;#ifdef USEBIOS   /* Scan through our BIOS list to locate the closest valid mode. */   /* If we ever break 4GHz clocks on video boards, we'll need to    * change this.    */   Refresh =       (vga256InfoRec.clock[mode->Clock] * 1000) /       (mode->HTotal * mode->VTotal);   new->mode = 0;#if EXTENDED_DEBUG   ErrorF( "Desired refresh rate = %dHz\n", Refresh );#endif   for( i = 0, pmt = s3vModeTable; i < s3vModeCount; i++, pmt++ )   {      if( (pmt->Width == mode->HDisplay) && (pmt->Height == mode->VDisplay) )      {         int j;	 int jDelta = 99;	 int jBest = 0;	 /* We have an acceptable mode.  Find a refresh rate. */	 new->mode = pmt->VesaMode;	 for( j = 0; j < pmt->RefreshCount; j++ )	 {	    if( pmt->RefreshRate[j] == Refresh )	    {	       /* Exact match. */	       jBest = j;	       break;	    }	    else if( iabs(pmt->RefreshRate[j] - Refresh) < jDelta )	    {	       jDelta = iabs(pmt->RefreshRate[j] - Refresh);	       jBest = j;	    }	 }	 new->refresh = pmt->RefreshRate[jBest];	 break;      }   }   if( new->mode > 0 ) {      /* Success: we found a match in the BIOS. */      if( xf86Verbose ) {	 ErrorF( "Chose mode %x at %dHz.\n", new->mode, new->refresh );      }      return TRUE;   }   /* We failed to find a match in the BIOS. */   /* Fallthrough to the traditional register-crunching.  */#endif /* USEBIOS */   /* Now we fill in the rest of the stuff we need for the virge */   /* Start with MMIO, linear addr. regs */   outb(vgaCRIndex, 0x3a);   tmp = inb(vgaCRReg);   if(!OFLG_ISSET(OPTION_PCI_BURST_ON, &vga256InfoRec.options))       new->CR3A = tmp | 0x95;      /* ENH 256, no PCI burst! */   else       new->CR3A = (tmp & 0x7f) | 0x15; /* ENH 256, PCI burst */   new->CR53 &= ~0x08;     /* Enables MMIO */   new->CR31 = 0x8c;     /* Dis. 64k window, en. ENH maps */       /* Enables S3D graphic engine and PCI disconnects */   new->CR66 = 0x89; /* Now set linear addr. registers *//* LAW size: always 8 MB for Savage3D */   outb(vgaCRIndex, 0x58);   new->CR58 = inb(vgaCRReg) & 0x80;   new->CR58 |= 0x13;/* ** On PCI bus, no need to reprogram the linear window base address *//* Now do clock PLL programming. Use the s3gendac function to get m,n *//* Also determine if we need doubling etc. */   dclk = vga256InfoRec.clock[mode->Clock];   new->CR67 = 0x00;             /* Defaults */   new->SR15 = 0x03 | 0x80;    new->SR18 = 0x00;   new->CR43 = 0x00;   new->CR45 = 0x00;   new->CR65 = 0x00;   outb(vgaCRIndex, 0x40);   new->CR40 = inb(vgaCRReg) & ~0x01;      /* Memory controller registers. Optimize for better graphics engine     * performance. These settings are adjusted/overridden below for other bpp/    * XConfig options.The idea here is to give a longer number of contiguous    * MCLK's to both refresh and the graphics engine, to diminish the     * relative penalty of 3 or 4 mclk's needed to setup memory transfers.     */   new->MMPR0 = 0x010400; /* defaults */   new->MMPR1 = 0x00;      new->MMPR2 = 0x0808;     new->MMPR3 = 0x08080810;    if (OFLG_ISSET(OPTION_FIFO_AGGRESSIVE, &vga256InfoRec.options) ||       OFLG_ISSET(OPTION_FIFO_MODERATE, &vga256InfoRec.options) ||      OFLG_ISSET(OPTION_FIFO_CONSERV, &vga256InfoRec.options)) {         new->MMPR1 = 0x0200;   /* Low P. stream waits before filling */         new->MMPR2 = 0x1808;   /* Let the FIFO refill itself */         new->MMPR3 = 0x08081810; /* And let the GE hold the bus for a while */      }   /* And setup here the new value for MCLK. We use the XConfig     * option "set_mclk", whose value gets stored in vga256InfoRec.s3MClk.    * I'm not sure what the maximum "permitted" value should be, probably    * 100 MHz is more than enough for now.      */   if(s3vPriv.MCLK> 0) {       commonCalcClock(s3vPriv.MCLK, 1, 1, 31, 0, 3,	   135000, 270000, &new->SR11, &new->SR10);       }   else {       new->SR10 = 255; /* This is a reserved value, so we use as flag */       new->SR11 = 255;        }   {       if (vgaBitsPerPixel == 8) {          if (dclk <= 110000) new->CR67 = 0x00; /* 8bpp, 135MHz */          else new->CR67 = 0x10;                /* 8bpp, 220MHz */          }       else if ((vgaBitsPerPixel == 16) && (vga256InfoRec.weight.green == 5)) {          if (dclk <= 110000) new->CR67 = 0x20; /* 15bpp, 135MHz */          else new->CR67 = 0x30;                /* 15bpp, 220MHz */          }       else if (vgaBitsPerPixel == 16) {          if (dclk <= 110000) new->CR67 = 0x40; /* 16bpp, 135MHz */          else new->CR67 = 0x50;                /* 16bpp, 220MHz */          }       else if ((vgaBitsPerPixel == 24) || (vgaBitsPerPixel == 32)) {          new->CR67 = 0xd0;                     /* 24bpp, 135MHz */          }       {          unsigned int m, n, r;	  savageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);          new->SR12 = (r << 6) | (n & 0x3F);          new->SR13 = m & 0xFF;          new->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;       }   }   /* Now adjust the value of the FIFO based upon options specified */   if(OFLG_ISSET(OPTION_FIFO_MODERATE, &vga256InfoRec.options)) {      if(vgaBitsPerPixel < 24)         new->MMPR0 -= 0x8000;      else          new->MMPR0 -= 0x4000;      }   else if(OFLG_ISSET(OPTION_FIFO_AGGRESSIVE, &vga256InfoRec.options)) {      if(vgaBitsPerPixel < 24)         new->MMPR0 -= 0xc000;      else          new->MMPR0 -= 0x6000;      }   /* If we have an interlace mode, set the interlace bit. Note that mode    * vertical timings are already adjusted by the standard VGA code     */   if(mode->Flags & V_INTERLACE) {        new->CR42 = 0x20; /* Set interlace mode */        }   else {        new->CR42 = 0x00;        }   /* Set display fifo */   new->CR34 = 0x10;     /* Now we adjust registers for extended mode timings */   /* This is taken without change from the accel/s3_virge code */   i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |       ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |       ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |       ((mode->CrtcHSyncStart & 0x800) >> 7);   if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)      i |= 0x08;   /* add another 64 DCLKs to blank pulse width */   if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)      i |= 0x20;   /* add another 32 DCLKs to hsync pulse width */   j = (  new->std.CRTC[0] + ((i&0x01)<<8)        + new->std.CRTC[4] + ((i&0x10)<<4) + 1) / 2;   if (j-(new->std.CRTC[4] + ((i&0x10)<<4)) < 4)      if (new->std.CRTC[4] + ((i&0x10)<<4) + 4 <= new->std.CRTC[0]+ ((i&0x01)<<8))         j = new->std.CRTC[4] + ((i&0x10)<<4) + 4;      else         j = new->std.CRTC[0]+ ((i&0x01)<<8) + 1;   new->CR3B = j & 0xFF;   i |= (j & 0x100) >> 2;   new->CR3C = (new->std.CRTC[0] + ((i&0x01)<<8))/2;   new->CR5D = i;   new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10)  |               (((mode->CrtcVDisplay - 1) & 0x400) >> 9) |               (((mode->CrtcVSyncStart) & 0x400) >> 8)   |               (((mode->CrtcVSyncStart) & 0x400) >> 6)   | 0x40;      width = (vga256InfoRec.displayWidth * (vgaBitsPerPixel / 8))>> 3;   new->std.CRTC[19] = 0xFF & width;   new->CR51 = (0x300 & width) >> 4; /* Extension bits */      /* And finally, select clock source 2 for programmable PLL */   new->std.MiscOutReg |= 0x0c;         /* Set frame buffer description */   if (vgaBitsPerPixel <= 8)      new->CR50 = 0;   else if (vgaBitsPerPixel <= 16)      new->CR50 = 0x10;   else      new->CR50 = 0x30;   if (vga256InfoRec.displayWidth == 640)      new->CR50 |= 0x40;   else if (vga256InfoRec.displayWidth == 800)      new->CR50 |= 0x80;   else if (vga256InfoRec.displayWidth == 1024);   else if (vga256InfoRec.displayWidth == 1152)      new->CR50 |= 0x01;   else if (vga256InfoRec.displayWidth == 1280)      new->CR50 |= 0x41;   else if (vga256InfoRec.displayWidth == 2048 && new->CR31 & 2);   else if (vga256InfoRec.displayWidth == 1600)      new->CR50 |= 0x81; /* TODO: need to consider bpp=4 */   else      new->CR50 |= 0xC1; /* default to use GlobalBD */   new->CR33 = 0x20;	    /* Now we handle various XConfig memory options and others */   outb(vgaCRIndex, 0x36);   new->CR36 = inb(vgaCRReg);      if (mode->Private) {      new->CR67 &= ~1;      if(         (s3vPriv.chip != S3_SAVAGE2000) &&        (mode->Private[0] & (1 << S3_INVERT_VCLK)) &&	(mode->Private[S3_INVERT_VCLK])      )	 new->CR67 |= 1;      if (mode->Private[0] & (1 << S3_BLANK_DELAY)) {	 new->CR65 = (new->CR65 & ~0x38) 	    | (mode->Private[S3_BLANK_DELAY] & 0x07) << 3;      }   }   outb(vgaCRIndex, 0x68);   new->CR68 = inb(vgaCRReg);   new->CR69 = 0;   outb(vgaCRIndex, 0x6F);   new->CR6F = inb(vgaCRReg);   outb(vgaCRIndex, 0x86);   new->CR86 = inb(vgaCRReg);   outb(vgaCRIndex, 0x88);   new->CR88 = inb(vgaCRReg) | 0x08;   outb(vgaCRIndex, 0xB0);   new->CRB0 = inb(vgaCRReg) | 0x80;   return TRUE;}