s3_Trio64DAC.c revision 340e3fbd
1/* 2 * Copyright 2001 Ani Joshi <ajoshi@unixbox.com> 3 * 4 * XFree86 4.x driver for S3 chipsets 5 * 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that copyright 10 * notice and this permission notice appear in supporting documentation and 11 * that the name of Ani Joshi not be used in advertising or 12 * publicity pertaining to distribution of the software without specific, 13 * written prior permission. Ani Joshi makes no representations 14 * about the suitability of this software for any purpose. It is provided 15 * "as-is" without express or implied warranty. 16 * 17 * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19 * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 23 * PERFORMANCE OF THIS SOFTWARE. 24 * 25 * 26 */ 27/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/s3/s3_Trio64DAC.c,v 1.7tsi Exp $ */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include "xf86.h" 34#include "xf86_OSproc.h" 35 36#include "compiler.h" 37 38#include "s3.h" 39 40/* this is really quite dumb */ 41Bool S3Trio64DACProbe(ScrnInfoPtr pScrn) 42{ 43 S3Ptr pS3 = S3PTR(pScrn); 44 45 if (!S3_TRIO_SERIES()) 46 return FALSE; 47 48 RamDacInit(pScrn, pS3->RamDacRec); 49 50 pS3->RamDac = RamDacHelperCreateInfoRec(); 51 pS3->RamDac->RamDacType = TRIO64_RAMDAC; 52 53 return TRUE; 54} 55 56 57void S3Trio64DAC_Save(ScrnInfoPtr pScrn) 58{ 59 S3Ptr pS3 = S3PTR(pScrn); 60 S3RegPtr save = &pS3->SavedRegs; 61 62 save->dacregs[0] = inb(0x3cc); 63 64 outb(0x3c4, 0x08); 65 save->dacregs[1] = inb(0x3c5); 66 outb(0x3c5, 0x06); 67 68 outb(0x3c4, 0x09); 69 save->dacregs[2] = inb(0x3c5); 70 outb(0x3c4, 0x0a); 71 save->dacregs[3] = inb(0x3c5); 72 outb(0x3c4, 0x0b); 73 save->dacregs[4] = inb(0x3c5); 74 outb(0x3c4, 0x0d); 75 save->dacregs[5] = inb(0x3c5); 76 outb(0x3c4, 0x15); 77 save->dacregs[6] = inb(0x3c5) & 0xfe; 78 outb(0x3c5, save->dacregs[6]); 79 80 outb(0x3c4, 0x18); 81 save->dacregs[7] = inb(0x3c5); 82 outb(0x3c4, 0x10); 83 save->dacregs[8] = inb(0x3c5); 84 outb(0x3c4, 0x11); 85 save->dacregs[9] = inb(0x3c5); 86 outb(0x3c4, 0x12); 87 save->dacregs[10] = inb(0x3c5); 88 outb(0x3c4, 0x13); 89 save->dacregs[11] = inb(0x3c5); 90 outb(0x3c4, 0x1a); 91 save->dacregs[12] = inb(0x3c5); 92 outb(0x3c4, 0x1b); 93 save->dacregs[13] = inb(0x3c5); 94 95 if (pS3->Chipset == PCI_CHIP_AURORA64VP) { 96 int i; 97 98 for (i=0x1a; i <= 0x6f; i++) { 99 outb(0x3c4, i); 100 save->dacregs[i] = inb(0x3c5); 101 } 102 } 103 104 outb(0x3c4, 0x08); 105 outb(0x3c5, 0x00); 106} 107 108 109void S3Trio64DAC_Restore(ScrnInfoPtr pScrn) 110{ 111 S3Ptr pS3 = S3PTR(pScrn); 112 S3RegPtr restore = &pS3->SavedRegs; 113 unsigned char tmp; 114 115 outb(0x3c2, restore->dacregs[0]); 116 outb(0x3c4, 0x08); 117 outb(0x3c5, 0x06); 118 119 outb(0x3c4, 0x09); 120 outb(0x3c5, restore->dacregs[2]); 121 outb(0x3c4, 0x0a); 122 outb(0x3c5, restore->dacregs[3]); 123 outb(0x3c4, 0x0b); 124 outb(0x3c5, restore->dacregs[4]); 125 outb(0x3c4, 0x0d); 126 outb(0x3c5, restore->dacregs[5]); 127 128 outb(0x3c4, 0x10); 129 outb(0x3c5, restore->dacregs[8]); 130 outb(0x3c4, 0x11); 131 outb(0x3c5, restore->dacregs[9]); 132 outb(0x3c4, 0x12); 133 outb(0x3c5, restore->dacregs[10]); 134 outb(0x3c4, 0x13); 135 outb(0x3c5, restore->dacregs[11]); 136 outb(0x3c4, 0x1a); 137 outb(0x3c5, restore->dacregs[12]); 138 outb(0x3c4, 0x1b); 139 outb(0x3c5, restore->dacregs[13]); 140 outb(0x3c4, 0x15); 141 tmp = inb(0x3c5); 142 outb(0x3c4, tmp & ~0x20); 143 outb(0x3c4, tmp | 0x20); 144 outb(0x3c4, tmp & ~0x20); 145 146 outb(0x3c4, 0x15); 147 outb(0x3c5, restore->dacregs[6]); 148 outb(0x3c4, 0x18); 149 outb(0x3c5, restore->dacregs[7]); 150 151 if (pS3->Chipset == PCI_CHIP_AURORA64VP) { 152 int i; 153 154 for (i = 0x1a; i <= 0x6f; i++) { 155 outb(0x3c4, i); 156 outb(0x3c5, restore->dacregs[i]); 157 } 158 } 159 160 outb(0x3c4, 0x08); 161 outb(0x3c5, restore->dacregs[1]); 162} 163 164 165static void 166S3TrioCalcClock(long freq, int min_m, int min_n1, int max_n1, int min_n2, 167 int max_n2, long freq_min, long freq_max, 168 unsigned char *mdiv, unsigned char *ndiv) 169{ 170 double ffreq, ffreq_min, ffreq_max; 171 double div, diff, best_diff; 172 unsigned int m; 173 unsigned char n1, n2, best_n1=18, best_n2=2, best_m=127; 174 175#define BASE_FREQ 14.31818 176 ffreq = freq / 1000.0 / BASE_FREQ; 177 ffreq_min = freq_min / 1000.0 / BASE_FREQ; 178 ffreq_max = freq_max / 1000.0 / BASE_FREQ; 179 180 if (ffreq < ffreq_min / (1<<max_n2)) { 181 ErrorF("invalid frequency %1.3f Mhz [freq >= %1.3f Mhz]\n", 182 ffreq*BASE_FREQ, ffreq_min*BASE_FREQ/(1<<max_n2)); 183 ffreq = ffreq_min / (1<<max_n2); 184 } 185 if (ffreq > ffreq_max / (1<<min_n2)) { 186 ErrorF("invalid frequency %1.3f Mhz [freq <= %1.3f Mhz]\n", 187 ffreq*BASE_FREQ, ffreq_max*BASE_FREQ/(1<<min_n2)); 188 ffreq = ffreq_max / (1<<min_n2); 189 } 190 191 best_diff = ffreq; 192 193 for(n2=min_n2; n2<=max_n2; n2++) { 194 for(n1=min_n1+2; n1<=max_n1+2; n1++) { 195 m = (int)(ffreq*n1*(1<<n2)+0.5); 196 if (m<min_m+2 || m > 127+2) 197 continue; 198 div = (double)(m)/(double)(n1); 199 if ((div >= ffreq_min) && 200 (div <= ffreq_max)) { 201 diff = ffreq - div / (1<<n2); 202 if (diff < 0.0) 203 diff = -diff; 204 if (diff < best_diff) { 205 best_diff = diff; 206 best_m = m; 207 best_n1 = n1; 208 best_n2 = n2; 209 } 210 } 211 } 212 } 213 214 if (max_n1 == 63) 215 *ndiv = (best_n1 - 2) | (best_n2 << 6); 216 else 217 *ndiv = (best_n1 - 2) | (best_n2 << 5); 218 *mdiv = best_m - 2; 219} 220 221 222static void S3TrioSetPLL(ScrnInfoPtr pScrn, int clk, unsigned char m, 223 unsigned char n) 224{ 225 unsigned char tmp; 226 227 if (clk < 2) { 228 tmp = inb(0x3cc); 229 outb(0x3c2, (tmp & 0xf3) | (clk << 2)); 230 } else { 231 tmp = inb(0x3cc); 232 outb(0x3c2, tmp | 0x0c); 233 234 outb(0x3c4, 0x08); 235 outb(0x3c5, 0x06); /* unlock extended CR9-18 */ 236 237 if (clk != 10) { 238 outb(0x3c4, 0x12); 239 outb(0x3c5, n); 240 outb(0x3c4, 0x13); 241 outb(0x3c5, m); 242 243 outb(0x3c4, 0x15); 244 tmp = inb(0x3c5) & ~0x21; 245 outb(0x3c5, tmp | 0x02); 246 outb(0x3c5, tmp | 0x22); 247 outb(0x3c5, tmp | 0x02); 248 } else { 249 outb(0x3c4, 0x10); 250 outb(0x3c5, n); 251 outb(0x3c4, 0x11); 252 outb(0x3c5, m); 253 outb(0x3c4, 0x1a); 254 outb(0x3c5, n); 255 256 outb(0x3c4, 0x15); 257 tmp = inb(0x3c5) & ~0x21; 258 outb(0x3c5, tmp | 0x01); 259 outb(0x3c5, tmp | 0x21); 260 outb(0x3c5, tmp | 0x01); 261 outb(0x3c5, tmp); 262 } 263 264 outb(0x3c4, 0x08); 265 outb(0x3c5, 0x00); /* lock em */ 266 } 267} 268 269 270static void S3TrioSetClock(ScrnInfoPtr pScrn, long freq, int clk, int min_m, 271 int min_n1, int max_n1, int min_n2, int max_n2, 272 int pll_type, long freq_min, long freq_max) 273{ 274 unsigned char m, n; 275 276 S3TrioCalcClock(freq, min_m, min_n1, max_n1, min_n2, max_n2, 277 freq_min, freq_max, &m, &n); 278 279 /* XXX for pll_type == TRIO */ 280 S3TrioSetPLL(pScrn, clk, m, n); 281} 282 283void S3Trio64DAC_PreInit(ScrnInfoPtr pScrn) 284{ 285 S3Ptr pS3 = S3PTR(pScrn); 286 unsigned char SR8, SR27; 287 int m, n, n1, n2, mclk; 288 289 outb(0x3c4, 0x08); 290 SR8 = inb(0x3c5); 291 outb(0x3c5, 0x06); 292 293 outb(0x3c4, 0x11); 294 m = inb(0x3c5); 295 outb(0x3c4, 0x10); 296 n = inb(0x3c5); 297 298 m &= 0x7f; 299 n1 = n & 0x1f; 300 n2 = (n >> 5) & 0x03; 301 mclk = ((1431818 * (m+2)) / (n1+2) / (1<<n2)+50)/100; 302 if (pS3->Chipset == PCI_CHIP_AURORA64VP) { 303 outb(0x3c4, 0x27); 304 SR27 = inb(0x3c5); 305 outb(0x3c4, 0x28); 306 (void) inb(0x3c5); 307 mclk /= ((SR27 >> 2) & 0x03) + 1; 308 } 309 pS3->mclk = mclk; 310 311 outb(0x3c4, 0x08); 312 outb(0x3c5, SR8); 313 314 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MCLK %1.3f Mhz\n", 315 mclk / 1000.0); 316} 317 318 319void S3Trio64DAC_Init(ScrnInfoPtr pScrn, DisplayModePtr mode) 320{ 321 S3Ptr pS3 = S3PTR(pScrn); 322 int pixmux=0, invert_vclk=0, sr8, sr15, sr18, cr33; 323 unsigned char blank, tmp; 324 325 if (pS3->Chipset == PCI_CHIP_AURORA64VP) 326 S3TrioSetClock(pScrn, mode->Clock, 2, 1, 1, 63, 0, 3, 2, 327 135000, 270000); 328 else if (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX) 329 S3TrioSetClock(pScrn, mode->Clock, 2, 1, 1, 31, 0, 3, 2, 330 170000, 270000); 331 else 332 S3TrioSetClock(pScrn, mode->Clock, 2, 1, 1, 31, 0, 3, 2, 333 135000, 270000); 334 335 336 outb(0x3c4, 1); 337 blank = inb(0x3c5); 338 outb(0x3c5, blank | 0x20); /* blank the screen */ 339 340 outb(0x3c4, 0x08); 341 sr8 = inb(0x3c5); 342 outb(0x3c5, 0x06); 343 344 outb(0x3c4, 0x0d0); 345 tmp = inb(0x3c5) & ~1; 346 outb(0x3c5, tmp); 347 348 outb(0x3c4, 0x15); 349 sr15 = inb(0x3c5) & ~0x10; 350 351 outb(0x3c4, 0x18); 352 sr18 = inb(0x3c5) & ~0x80; 353 outb(pS3->vgaCRIndex, 0x33); 354 cr33 = inb(pS3->vgaCRReg) & ~0x28; 355 356 if (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX) 357 { 358 cr33 |= 0x20; 359 } 360 361 /* ! pixmux */ 362 switch (pScrn->depth) { 363 case 8: 364 break; 365 case 15: 366 cr33 |= 0x08; 367 pixmux = 0x30; 368 break; 369 case 16: 370 cr33 |= 0x08; 371 pixmux = 0x50; 372 break; 373 case 32: 374 pixmux = 0xd0; 375 break; 376 } 377 378 outb(pS3->vgaCRReg, cr33); 379 380 outb(pS3->vgaCRIndex, 0x67); 381 outb(pS3->vgaCRReg, pixmux | invert_vclk); 382 383 outb(0x3c4, 0x15); 384 outb(0x3c5, sr15); 385 outb(0x3c4, 0x18); 386 outb(0x3c5, sr18); 387 388 if (pS3->Chipset == PCI_CHIP_AURORA64VP) { 389 outb(0x3c4, 0x28); 390 outb(0x3c5, 0x00); 391 } 392 393 outb(0x3c4, 0x08); 394 outb(0x3c5, sr8); 395 396 outb(0x3c4, 1); 397 outb(0x3c5, blank); /* unblank the screen */ 398} 399