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