1#ifdef HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5/* All drivers should typically include these */ 6#include "xf86.h" 7#include "xf86_OSproc.h" 8 9/* Drivers that need to access the PCI config space directly need this */ 10#include "xf86Pci.h" 11 12#include "mga_reg.h" 13#include "mga.h" 14 15#define MNP_TABLE_SIZE 64 16#define CLKSEL_MGA 0x0c 17#define PLLLOCK 0x40 18 19static CARD32 G450ApplyPFactor(ScrnInfoPtr pScrn, CARD8 ucP, CARD32 *pulFIn) 20{ 21 if(!(ucP & 0x40)) 22 { 23 *pulFIn = *pulFIn / (2L << (ucP & 3)); 24 } 25 26 return TRUE; 27} 28 29 30static CARD32 G450RemovePFactor(ScrnInfoPtr pScrn, CARD8 ucP, CARD32 *pulFIn) 31{ 32 if(!(ucP & 0x40)) 33 { 34 *pulFIn = *pulFIn * (2L << (ucP & 3)); 35 } 36 37 return TRUE; 38} 39 40 41static CARD32 G450CalculVCO(ScrnInfoPtr pScrn, CARD32 ulMNP, CARD32 *pulF) 42{ 43 CARD8 ucM, ucN; 44 45 ucM = (CARD8)((ulMNP >> 16) & 0xff); 46 ucN = (CARD8)((ulMNP >> 8) & 0xff); 47 48 *pulF = (27000 * (2 * (ucN + 2)) + ((ucM + 1) >> 1)) / (ucM + 1); 49 50 return TRUE; 51} 52 53 54static CARD32 G450CalculDeltaFreq(ScrnInfoPtr pScrn, CARD32 ulF1, 55 CARD32 ulF2, CARD32 *pulDelta) 56{ 57 if(ulF2 < ulF1) 58 { 59 *pulDelta = ((ulF1 - ulF2) * 1000) / ulF1; 60 } 61 else 62 { 63 *pulDelta = ((ulF2 - ulF1) * 1000) / ulF1; 64 } 65 66 return TRUE; 67} 68 69 70 71 72static CARD32 G450FindNextPLLParam(ScrnInfoPtr pScrn, CARD32 ulFout, 73 CARD32 *pulPLLMNP) 74{ 75 CARD8 ucM, ucN, ucP, ucS; 76 CARD32 ulVCO, ulVCOMin; 77 78 ucM = (CARD8)((*pulPLLMNP >> 16) & 0xff); 79 ucN = (CARD8)((*pulPLLMNP >> 8) & 0xff); 80 ucP = (CARD8)(*pulPLLMNP & 0x43); 81 82 ulVCOMin = 256000; 83 84 if(ulVCOMin >= (255L * 8000)) 85 { 86 ulVCOMin = 230000; 87 } 88 89 if((ucM == 9) && (ucP & 0x40)) 90 { 91 *pulPLLMNP = 0xffffffff; 92 } else if (ucM == 9) 93 { 94 if(ucP) 95 { 96 ucP--; 97 } 98 else 99 { 100 ucP = 0x40; 101 } 102 ucM = 0; 103 } 104 else 105 { 106 ucM++; 107 } 108 109 ulVCO = ulFout; 110 111 G450RemovePFactor(pScrn, ucP, &ulVCO); 112 113 if(ulVCO < ulVCOMin) 114 { 115 *pulPLLMNP = 0xffffffff; 116 } 117 118 if(*pulPLLMNP != 0xffffffff) 119 { 120 ucN = (CARD8)(((ulVCO * (ucM+1) + 27000)/(27000 * 2)) - 2); 121 122 ucS = 5; 123 if(ulVCO < 1300000) ucS = 4; 124 if(ulVCO < 1100000) ucS = 3; 125 if(ulVCO < 900000) ucS = 2; 126 if(ulVCO < 700000) ucS = 1; 127 if(ulVCO < 550000) ucS = 0; 128 129 ucP |= (CARD8)(ucS << 3); 130 131 *pulPLLMNP &= 0xff000000; 132 *pulPLLMNP |= (CARD32)ucM << 16; 133 *pulPLLMNP |= (CARD32)ucN << 8; 134 *pulPLLMNP |= (CARD32)ucP; 135 136#ifdef DEBUG 137 ErrorF("FINS_S: VCO = %d, S = %02X, *pulPLLMNP = %08X\n", (unsigned)ulVCO, (unsigned)ucS, (unsigned)*pulPLLMNP); 138#endif 139 } 140 141 return TRUE; 142} 143 144 145static CARD32 G450FindFirstPLLParam(ScrnInfoPtr pScrn, CARD32 ulFout, 146 CARD32 *pulPLLMNP) 147{ 148 CARD8 ucP; 149 CARD32 ulVCO; 150 CARD32 ulVCOMax; 151 152 /* Default value */ 153 ulVCOMax = 1300000; 154 155 if(ulFout > (ulVCOMax/2)) 156 { 157 ucP = 0x40; 158 ulVCO = ulFout; 159 } 160 else 161 { 162 ucP = 3; 163 ulVCO = ulFout; 164 G450RemovePFactor(pScrn, ucP, &ulVCO); 165 while(ucP && (ulVCO > ulVCOMax)) 166 { 167 ucP--; 168 ulVCO = ulFout; 169 G450RemovePFactor(pScrn, ucP, &ulVCO); 170 } 171 } 172 173 if(ulVCO > ulVCOMax) 174 { 175 *pulPLLMNP = 0xffffffff; 176 } 177 else 178 { 179 /* Pixel clock: 1 */ 180 *pulPLLMNP = (1 << 24) + 0xff0000 + ucP; 181 G450FindNextPLLParam(pScrn, ulFout, pulPLLMNP); 182 } 183 184 return TRUE; 185 186} 187 188 189static CARD32 G450WriteMNP(ScrnInfoPtr pScrn, CARD32 ulMNP) 190{ 191 MGAPtr pMga = MGAPTR(pScrn); 192 193 if (!pMga->SecondCrtc) { 194 outMGAdac(MGA1064_PIX_PLLC_M, (CARD8)(ulMNP >> 16)); 195 outMGAdac(MGA1064_PIX_PLLC_N, (CARD8)(ulMNP >> 8)); 196 outMGAdac(MGA1064_PIX_PLLC_P, (CARD8) ulMNP); 197 } else { 198 outMGAdac(MGA1064_VID_PLL_M, (CARD8)(ulMNP >> 16)); 199 outMGAdac(MGA1064_VID_PLL_N, (CARD8)(ulMNP >> 8)); 200 outMGAdac(MGA1064_VID_PLL_P, (CARD8) ulMNP); 201 } 202 return TRUE; 203} 204 205static CARD32 G450ReadMNP(ScrnInfoPtr pScrn) 206{ 207 MGAPtr pMga = MGAPTR(pScrn); 208 CARD32 ret = 0; 209 210 if (!pMga->SecondCrtc) { 211 ret = (CARD8)inMGAdac(MGA1064_PIX_PLLC_M) << 16; 212 ret |= (CARD8)inMGAdac(MGA1064_PIX_PLLC_N) << 8; 213 ret |= (CARD8)inMGAdac(MGA1064_PIX_PLLC_P); 214 } else { 215 ret = (CARD8)inMGAdac(MGA1064_VID_PLL_M) << 16; 216 ret |= (CARD8)inMGAdac(MGA1064_VID_PLL_N) << 8; 217 ret |= (CARD8)inMGAdac(MGA1064_VID_PLL_P); 218 } 219 return ret; 220} 221 222 223static CARD32 G450CompareMNP(ScrnInfoPtr pScrn, CARD32 ulFout, CARD32 ulMNP1, 224 CARD32 ulMNP2, long *pulResult) 225{ 226 CARD32 ulFreq, ulDelta1, ulDelta2; 227 228 G450CalculVCO(pScrn, ulMNP1, &ulFreq); 229 G450ApplyPFactor(pScrn, (CARD8) ulMNP1, &ulFreq); 230 G450CalculDeltaFreq(pScrn, ulFout, ulFreq, &ulDelta1); 231 232 G450CalculVCO(pScrn, ulMNP2, &ulFreq); 233 G450ApplyPFactor(pScrn, (CARD8) ulMNP2, &ulFreq); 234 G450CalculDeltaFreq(pScrn, ulFout, ulFreq, &ulDelta2); 235 236 if(ulDelta1 < ulDelta2) 237 { 238 *pulResult = -1; 239 } 240 else if(ulDelta1 > ulDelta2) 241 { 242 *pulResult = 1; 243 } 244 else 245 { 246 *pulResult = 0; 247 } 248 249 if((ulDelta1 <= 5) && (ulDelta2 <= 5)) 250 { 251 if((ulMNP1 & 0xff0000) < (ulMNP2 & 0xff0000)) 252 { 253 *pulResult = -1; 254 } 255 else if((ulMNP1 & 0xff0000) > (ulMNP2 & 0xff0000)) 256 { 257 *pulResult = 1; 258 } 259 } 260 261 return TRUE; 262} 263 264 265static CARD32 G450IsPllLocked(ScrnInfoPtr pScrn, Bool *lpbLocked) 266{ 267 CARD32 ulFallBackCounter, ulLockCount, ulCount; 268 CARD8 ucPLLStatus; 269 270 MGAPtr pMga = MGAPTR(pScrn); 271 272 if (!pMga->SecondCrtc) 273 OUTREG8(0x3c00, MGA1064_PIX_PLL_STAT); 274 else 275 OUTREG8(0x3c00, MGA1064_VID_PLL_STAT); 276 277 ulFallBackCounter = 0; 278 279 do 280 { 281 ucPLLStatus = INREG8(0x3c0a); 282 ulFallBackCounter++; 283 } while(!(ucPLLStatus & PLLLOCK) && (ulFallBackCounter < 1000)); 284 285 ulLockCount = 0; 286 if(ulFallBackCounter < 1000) 287 { 288 for(ulCount = 0; ulCount < 100; ulCount++) 289 { 290 ucPLLStatus = INREG8(0x3c0a); 291 if(ucPLLStatus & PLLLOCK) 292 { 293 ulLockCount++; 294 } 295 } 296 } 297 298 *lpbLocked = ulLockCount >= 90; 299 300 return TRUE; 301} 302 303 304double MGAG450SetPLLFreq(ScrnInfoPtr pScrn, long f_out) 305{ 306 Bool bFoundValidPLL; 307 Bool bLocked; 308 CARD8 ucMisc, ucSIndex, ucSTable[4]; 309 CARD32 ulMaxIndex; 310 CARD32 ulMNP; 311 CARD32 ulMNPTable[MNP_TABLE_SIZE]; 312 CARD32 ulIndex; 313 CARD32 ulTryMNP; 314 long lCompareResult; 315 MGAPtr pMga = MGAPTR(pScrn); 316 317#ifdef DEBUG 318 xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Restoring PLLClk = %ld\n", f_out); 319#endif 320 G450FindFirstPLLParam(pScrn, f_out, &ulMNP); 321 ulMNPTable[0] = ulMNP; 322 G450FindNextPLLParam(pScrn, f_out, &ulMNP); 323 ulMaxIndex = 1; 324 while(ulMNP != 0xffffffff) 325 { 326 int ulIndex; 327 Bool bSkipValue; 328 329 bSkipValue = FALSE; 330 if(ulMaxIndex == MNP_TABLE_SIZE) 331 { 332 G450CompareMNP(pScrn, f_out, ulMNP, ulMNPTable[MNP_TABLE_SIZE - 1], 333 &lCompareResult); 334 335 if(lCompareResult > 0) 336 { 337 bSkipValue = TRUE; 338 } 339 else 340 { 341 ulMaxIndex--; 342 } 343 } 344 345 if(!bSkipValue) 346 { 347 for(ulIndex = ulMaxIndex; !bSkipValue && (ulIndex > 0); ulIndex--) 348 { 349 G450CompareMNP(pScrn, f_out, ulMNP, ulMNPTable[ulIndex - 1], 350 &lCompareResult); 351 352 if(lCompareResult < 0) 353 { 354 ulMNPTable[ulIndex] = ulMNPTable[ulIndex - 1]; 355 } 356 else 357 { 358 break; 359 } 360 } 361 ulMNPTable[ulIndex] = ulMNP; 362 ulMaxIndex++; 363 } 364 365 G450FindNextPLLParam(pScrn, f_out, &ulMNP); 366 } 367 368 bFoundValidPLL = FALSE; 369 ulMNP = 0; 370 371 /* For pixel pll */ 372 if (!pMga->SecondCrtc) { 373 ucMisc = INREG8(0x1FCC); 374 OUTREG8(0x1fc2, (CARD8)(ucMisc | CLKSEL_MGA)); 375 } 376 377 for(ulIndex = 0; !bFoundValidPLL && (ulIndex < ulMaxIndex); ulIndex++) 378 { 379 ulTryMNP = ulMNPTable[ulIndex]; 380 381 ucSTable[3] = 0xff; 382 ucSTable[2] = 0xff; 383 ucSTable[0] = (CARD8) (ulTryMNP & 0x38); 384 385 if (ucSTable[0] != 0) { 386 ucSTable[1] = ucSTable[0] - 8; 387 if (ucSTable[0] != 0x38) { 388 ucSTable[2] = ucSTable[0] + 8; 389 } 390 } else { 391 ucSTable[1] = 8; 392 } 393 394 for(ucSIndex = 0; !bFoundValidPLL && (ucSTable[ucSIndex] != 0xff); 395 ucSIndex++) { 396 ulTryMNP &= 0xffffffc7; 397 ulTryMNP |= (CARD32)ucSTable[ucSIndex]; 398 399 bLocked = TRUE; 400 if((ulMNPTable[ulIndex] & 0xff00) < 0x300 || 401 (ulMNPTable[ulIndex] & 0xff00) > 0x7a00) 402 { 403 bLocked = FALSE; 404 } 405 406 if(bLocked) 407 { 408 G450WriteMNP(pScrn, ulTryMNP - 0x300); 409 G450IsPllLocked(pScrn, &bLocked); 410 } 411 412 if(bLocked) 413 { 414 G450WriteMNP(pScrn, ulTryMNP + 0x300); 415 G450IsPllLocked(pScrn, &bLocked); 416 } 417 418 if(bLocked) 419 { 420 G450WriteMNP(pScrn, ulTryMNP - 0x200); 421 G450IsPllLocked(pScrn, &bLocked); 422 } 423 424 if(bLocked) 425 { 426 G450WriteMNP(pScrn, ulTryMNP + 0x200); 427 G450IsPllLocked(pScrn, &bLocked); 428 } 429 430 if(bLocked) 431 { 432 G450WriteMNP(pScrn, ulTryMNP - 0x100); 433 G450IsPllLocked(pScrn, &bLocked); 434 } 435 436 if(bLocked) 437 { 438 G450WriteMNP(pScrn, ulTryMNP + 0x100); 439 G450IsPllLocked(pScrn, &bLocked); 440 } 441 442 if(bLocked) 443 { 444 G450WriteMNP(pScrn, ulTryMNP); 445 G450IsPllLocked(pScrn, &bLocked); 446 } 447 else if(!ulMNP) 448 { 449 G450WriteMNP(pScrn, ulTryMNP); 450 G450IsPllLocked(pScrn, &bLocked); 451 if(bLocked) 452 { 453 ulMNP = ulMNPTable[ulIndex]; 454 } 455 bLocked = FALSE; 456 } 457 458 if(bLocked) 459 { 460 bFoundValidPLL = TRUE; 461 } 462 } 463 } 464 465 if(!bFoundValidPLL) 466 { 467 if(ulMNP) 468 { 469 G450WriteMNP(pScrn, ulMNP); 470 } 471 else 472 { 473 G450WriteMNP(pScrn, ulMNPTable[0]); 474 } 475 } 476 477 return TRUE; 478} 479 480long 481MGAG450SavePLLFreq(ScrnInfoPtr pScrn) 482{ 483 CARD32 ulMNP = G450ReadMNP(pScrn); 484 CARD8 ucP; 485 CARD32 freq; 486 487 G450CalculVCO(pScrn, ulMNP, &freq); 488 ucP = (CARD8)(ulMNP & 0x03); 489 G450ApplyPFactor(pScrn, ucP, &freq); 490 491#ifdef DEBUG 492 xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Saved PLLClk = %u\n", (unsigned)freq); 493#endif 494 return freq; 495} 496 497#ifdef DEBUG 498void 499MGAG450PrintPLL(ScrnInfoPtr pScrn) 500{ 501 CARD32 ulMNP = G450ReadMNP(pScrn); 502 CARD8 ucP; 503 CARD32 freq; 504 505 G450CalculVCO(pScrn, ulMNP, &freq); 506 ucP = (CARD8)(ulMNP & 0x03); 507 G450ApplyPFactor(pScrn, ucP, &freq); 508 509 xf86DrvMsg(pScrn->scrnIndex,X_INFO,"MGAGClock = %u -- MNP = 0x%x\n", 510 (unsigned)freq, (unsigned)ulMNP); 511} 512#endif 513