Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright 1992-2003 by Alan Hourihane, North Wales, UK.
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software
      5  * and its documentation for any purpose is hereby granted without
      6  * fee, provided that the above copyright notice appear in all copies
      7  * and that both that copyright notice and this permission notice
      8  * appear in supporting documentation, and that the name of Alan
      9  * Hourihane not be used in advertising or publicity pertaining to
     10  * distribution of the software without specific, written prior
     11  * permission.  Alan Hourihane makes no representations about the
     12  * suitability of this software for any purpose.  It is provided
     13  * "as is" without express or implied warranty.
     14  *
     15  * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
     16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
     17  * FITNESS, IN NO EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY
     18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     20  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     21  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     22  * SOFTWARE.
     23  *
     24  * Author:  Alan Hourihane, alanh (at) fairlite.demon.co.uk
     25  */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include "config.h"
     29 #endif
     30 
     31 #include "xf86.h"
     32 #include "xf86_OSproc.h"
     33 #include "xf86Pci.h"
     34 
     35 #include "vgaHW.h"
     36 
     37 #include "trident.h"
     38 #include "trident_regs.h"
     39 
     40 
     41 static void
     42 IsClearTV(ScrnInfoPtr pScrn)
     43 {
     44     int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
     45     TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
     46     CARD8 temp;
     47 
     48     if (pTrident->frequency != 0) return;
     49 
     50     OUTB(vgaIOBase + 4, 0xC0);
     51     temp = INB(vgaIOBase + 5);
     52     if (temp & 0x80)
     53         pTrident->frequency = PAL;
     54     else
     55         pTrident->frequency = NTSC;
     56 }
     57 
     58 void
     59 TGUISetClock(ScrnInfoPtr pScrn, int clock, CARD8 *a, CARD8 *b)
     60 {
     61     TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
     62     int powerup[4] = { 1, 2, 4, 8 };
     63     int clock_diff = 750;
     64     int freq, ffreq;
     65     int m, n, k;
     66     int p, q, r, s;
     67     int endn, endm, endk, startk;
     68 
     69     p = q = r = s = 0;
     70 
     71     IsClearTV(pScrn);
     72 
     73     if (pTrident->NewClockCode) {
     74         endn = 255;
     75         endm = 63;
     76         endk = 2;
     77         if (clock >= 100000) startk = 0; else
     78             if (clock >=  50000) startk = 1; else
     79                 startk = 2;
     80     } else {
     81         endn = 121;
     82         endm = 31;
     83         endk = 1;
     84         if (clock > 50000) startk = 1; else
     85             startk = 0;
     86     }
     87 
     88     freq = clock;
     89 
     90     for (k = startk; k <= endk; k++) {
     91         for (n = 0; n <= endn; n++) {
     92             for (m = 1; m <= endm; m++) {
     93                 ffreq = ((((n + 8) * pTrident->frequency) /
     94                             ((m + 2) * powerup[k])) * 1000);
     95                 if ((ffreq > freq - clock_diff) &&
     96                     (ffreq < freq + clock_diff)) {
     97                     /*
     98                      * It seems that the 9440 docs have this STRICT
     99                      * limitation, although most 9440 boards seem to
    100                      * cope. 96xx/Cyber chips don't need this limit
    101                      * so, I'm gonna remove it and it allows lower
    102                      * clocks < 25.175 too!
    103                      */
    104 #ifdef STRICT
    105                     if ((n + 8) * 100 / (m + 2) < 978 &&
    106                         (n + 8) * 100 / (m + 2) > 349) {
    107 #endif
    108                         clock_diff = (freq > ffreq) ?
    109                                         freq - ffreq : ffreq - freq;
    110                         p = n; q = m; r = k; s = ffreq;
    111 #ifdef STRICT
    112                     }
    113 #endif
    114                 }
    115             }
    116         }
    117     }
    118 
    119     if (s == 0) {
    120         FatalError("Unable to set programmable clock.\n"
    121                 "Frequency %d is not a valid clock.\n"
    122                 "Please modify XF86Config for a new clock.\n",
    123                 freq);
    124     }
    125 
    126     if (pTrident->NewClockCode) {
    127         /* N is all 8bits */
    128         *a = p;
    129         /* M is first 6bits, with K last 2bits */
    130         *b = (q & 0x3F) | (r << 6);
    131     } else {
    132         /* N is first 7bits, first M bit is 8th bit */
    133         *a = ((1 & q) << 7) | p;
    134         /* first 4bits are rest of M, 1bit for K value */
    135         *b = (((q & 0xFE) >> 1) | (r << 4));
    136     }
    137     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
    138                    "Found Clock %6.2f n=%i m=%i k=%i\n",
    139                    clock/1000., p, q, r);
    140 }
    141 
    142 void
    143 TridentFindClock(ScrnInfoPtr pScrn, int clock)
    144 {
    145     TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    146 
    147     pTrident->MUX = FALSE;
    148 #ifdef READOUT
    149     pTrident->DontSetClock = FALSE;
    150 #endif
    151     pTrident->currentClock = clock;
    152 
    153     if (pTrident->IsCyber) {
    154         Bool LCDActive;
    155 #ifdef READOUT
    156         Bool ShadowModeActive;
    157         Bool HStretch;
    158         Bool VStretch;
    159 #endif
    160         OUTB(0x3CE, FPConfig);
    161         LCDActive = (INB(0x3CF) & 0x10);
    162 #ifdef READOUT
    163         OUTB(0x3CE, HorStretch);
    164         HStretch = (INB(0x3CF) & 0x01);
    165         OUTB(0x3CE, VertStretch);
    166         VStretch = (INB(0x3CF) & 0x01);
    167 
    168         if (!(VStretch || HStretch) && LCDActive) {
    169             CARD8 temp;
    170             temp = INB(0x3C8);
    171             temp = INB(0x3C6);
    172             temp = INB(0x3C6);
    173             temp = INB(0x3C6);
    174             temp = INB(0x3C6);
    175             pTrident->MUX = ((INB(0x3C6) & 0x20) == 0x20);
    176             temp = INB(0x3C8);
    177             pTrident->DontSetClock = TRUE;
    178             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    179                         "Keeping Clock for LCD Mode\n");
    180             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    181                         "MUX is %s\n",
    182                         pTrident->MUX ? "on" : "off");
    183             return;
    184         } else
    185 #endif
    186         {
    187             if (pTrident->lcdMode != 0xff && LCDActive)
    188                 pTrident->currentClock = clock =
    189                                         LCD[pTrident->lcdMode].clock;
    190         }
    191 
    192     }
    193 #ifndef READOUT
    194     if (pTrident->Chipset != BLADEXP &&
    195         clock > pTrident->MUXThreshold)
    196         pTrident->MUX = TRUE;
    197     else
    198         pTrident->MUX = FALSE;
    199 #endif
    200 }
    201 
    202 float
    203 CalculateMCLK(ScrnInfoPtr pScrn)
    204 {
    205     int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
    206     TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    207     int a, b;
    208     int m, n, k;
    209     float freq = 0.0;
    210     int powerup[4] = { 1, 2, 4, 8 };
    211     CARD8 temp;
    212 
    213     if (pTrident->HasSGRAM) {
    214         OUTB(vgaIOBase + 4, 0x28);
    215         switch(INB(vgaIOBase + 5) & 0x07) {
    216         case 0:
    217             freq = 60;
    218             break;
    219         case 1:
    220             freq = 78;
    221             break;
    222         case 2:
    223             freq = 90;
    224             break;
    225         case 3:
    226             freq = 120;
    227             break;
    228         case 4:
    229             freq = 66;
    230             break;
    231         case 5:
    232             freq = 83;
    233             break;
    234         case 6:
    235             freq = 100;
    236             break;
    237         case 7:
    238             freq = 132;
    239             break;
    240         }
    241     } else {
    242         OUTB(0x3C4, NewMode1);
    243         temp = INB(0x3C5);
    244 
    245         OUTB(0x3C5, 0xC2);
    246         if (!Is3Dchip) {
    247             a = INB(0x43C6);
    248             b = INB(0x43C7);
    249         } else {
    250             OUTB(0x3C4, 0x16);
    251             a = INB(0x3C5);
    252             OUTB(0x3C4, 0x17);
    253             b = INB(0x3C5);
    254         }
    255 
    256         OUTB(0x3C4, NewMode1);
    257         OUTB(0x3C5, temp);
    258 
    259         IsClearTV(pScrn);
    260 
    261         if (pTrident->NewClockCode) {
    262             m = b & 0x3F;
    263             n = a;
    264             k = (b & 0xC0) >> 6;
    265         } else {
    266             m = (a & 0x07);
    267             k = (b & 0x02) >> 1;
    268             n = ((a & 0xF8) >> 3) | ((b&0x01) << 5);
    269         }
    270 
    271         freq = ((n + 8) * pTrident->frequency) /
    272                 ((m + 2) * powerup[k]);
    273     }
    274 
    275     return (freq);
    276 }
    277 
    278 void
    279 TGUISetMCLK(ScrnInfoPtr pScrn, int clock, CARD8 *a, CARD8 *b)
    280 {
    281     TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
    282     int powerup[4] = { 1,2,4,8 };
    283     int clock_diff = 750;
    284     int freq, ffreq;
    285     int m,n,k;
    286     int p, q, r, s;
    287     int startn, endn;
    288     int endm, endk;
    289 
    290     p = q = r = s = 0;
    291 
    292     IsClearTV(pScrn);
    293 
    294     if (pTrident->NewClockCode) {
    295         startn = 64;
    296         endn = 255;
    297         endm = 63;
    298         endk = 3;
    299     } else {
    300         startn = 0;
    301         endn = 121;
    302         endm = 31;
    303         endk = 1;
    304     }
    305 
    306     freq = clock;
    307 
    308     if (!pTrident->HasSGRAM) {
    309         for (k = 0; k <= endk; k++) {
    310             for (n = startn; n <= endn; n++) {
    311                 for (m = 1;m <= endm; m++) {
    312                     ffreq = ((((n + 8) * pTrident->frequency) /
    313                             ((m + 2) * powerup[k])) * 1000);
    314                     if ((ffreq > freq - clock_diff) &&
    315                         (ffreq < freq + clock_diff)) {
    316                         clock_diff = (freq > ffreq) ?
    317                                         freq - ffreq : ffreq - freq;
    318                         p = n; q = m; r = k; s = ffreq;
    319                     }
    320                 }
    321             }
    322         }
    323 
    324         if (s == 0) {
    325             FatalError("Unable to set memory clock.\n"
    326                         "Frequency %d is not a valid clock.\n"
    327                         "Please modify XF86Config for a new clock.\n",
    328                         freq);
    329         }
    330 
    331         if (pTrident->NewClockCode) {
    332             /* N is all 8bits */
    333             *a = p;
    334             /* M is first 6bits, with K last 2bits */
    335             *b = (q & 0x3F) | (r << 6);
    336         }
    337         else {
    338             /* N is first 7bits, first M bit is 8th bit */
    339             *a = ((1 & q) << 7) | p;
    340             /* first 4bits are rest of M, 1bit for K value */
    341             *b = (((q & 0xFE) >> 1) | (r << 4));
    342         }
    343     }
    344 }
    345