--- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c.pll_parameters 2005-09-18 10:08:46.000000000 +0400 +++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c 2005-09-18 10:10:26.000000000 +0400 @@ -1200,34 +1200,53 @@ RADEONPLLPtr pll = &info->pll; unsigned char *RADEONMMIO = info->MMIO; unsigned char ppll_div_sel; - unsigned Nx, M; + unsigned mpll_fb_div, spll_fb_div, M; unsigned xclk, tmp, ref_div; int hTotal, vTotal, num, denom, m, n; - float hz, vclk, xtal; + float hz, prev_xtal, vclk, xtal, mpll, spll; long start_secs, start_usecs, stop_secs, stop_usecs, total_usecs; - int i; - - for(i=0; i<1000000; i++) - if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) + long to1_secs, to1_usecs, to2_secs, to2_usecs; + unsigned int f1, f2, f3; + int tries = 0; + + prev_xtal = 0; + again: + xtal = 0; + if (++tries > 10) + goto failed; + + xf86getsecs(&to1_secs, &to1_usecs); + f1 = INREG(RADEON_CRTC_CRNT_FRAME); + for (;;) { + f2 = INREG(RADEON_CRTC_CRNT_FRAME); + if (f1 != f2) break; - + xf86getsecs(&to2_secs, &to2_usecs); + if ((to2_secs - to1_secs) > 1) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Clock not counting...\n"); + goto failed; + } + } xf86getsecs(&start_secs, &start_usecs); - - for(i=0; i<1000000; i++) - if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0) + for(;;) { + f3 = INREG(RADEON_CRTC_CRNT_FRAME); + if (f3 != f2) break; - - for(i=0; i<1000000; i++) - if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) - break; - + xf86getsecs(&to2_secs, &to2_usecs); + if ((to2_secs - start_secs) > 1) + goto failed; + } xf86getsecs(&stop_secs, &stop_usecs); + if ((stop_secs - start_secs) != 0) + goto again; total_usecs = abs(stop_usecs - start_usecs); - hz = 1000000/total_usecs; + if (total_usecs == 0) + goto again; + hz = 1000000.0/(float)total_usecs; - hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8; - vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0x3ff) + 1); + hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x3ff) + 1) * 8; + vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0xfff) + 1); vclk = (float)(hTotal * (float)(vTotal * hz)); switch((INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x30000) >> 16) { @@ -1250,8 +1269,7 @@ break; } - OUTREG(RADEON_CLOCK_CNTL_INDEX, 1); - ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_DATA + 1) & 0x3; + ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3; n = (INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) & 0x7ff); m = (INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff); @@ -1289,20 +1307,91 @@ else if ((xtal > 29400000) && (xtal < 29600000)) xtal = 2950; else - return FALSE; + goto again; + failed: + if (xtal == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to probe xtal value ! " + "Using default 27Mhz\n"); + xtal = 2700; + } else { + if (prev_xtal == 0) { + prev_xtal = xtal; + tries = 0; + goto again; + } else if (prev_xtal != xtal) { + prev_xtal = 0; + goto again; + } + } tmp = INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV); ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff; - Nx = (tmp & 0xff00) >> 8; + /* Some sanity check based on the BIOS code .... */ + if (ref_div < 2) { + CARD32 tmp; + tmp = INPLL(pScrn, RADEON_PPLL_REF_DIV); + if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_RS300)) + ref_div = (tmp & R300_PPLL_REF_DIV_ACC_MASK) >> + R300_PPLL_REF_DIV_ACC_SHIFT; + else + ref_div = tmp & RADEON_PPLL_REF_DIV_MASK; + if (ref_div < 2) + ref_div = 12; + } + + /* Calculate "base" xclk straight from MPLL, though that isn't + * really useful (hopefully). This isn't called XCLK anymore on + * radeon's... + */ + mpll_fb_div = (tmp & 0xff00) >> 8; + spll_fb_div = (tmp & 0xff0000) >> 16; M = (tmp & 0xff); - xclk = RADEONDiv((2 * Nx * xtal), (2 * M)); + xclk = RADEONDiv((2 * mpll_fb_div * xtal), (M)); + + /* + * Calculate MCLK based on MCLK-A + */ + mpll = (2.0 * (float)mpll_fb_div * (xtal / 100.0)) / (float)M; + spll = (2.0 * (float)spll_fb_div * (xtal / 100.0)) / (float)M; + + tmp = INPLL(pScrn, RADEON_MCLK_CNTL) & 0x7; + switch(tmp) { + case 1: info->mclk = mpll; break; + case 2: info->mclk = mpll / 2.0; break; + case 3: info->mclk = mpll / 4.0; break; + case 4: info->mclk = mpll / 8.0; break; + case 7: info->mclk = spll; break; + default: + info->mclk = 200.00; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unsupported MCLKA source" + " setting %d, can't probe MCLK value !\n", tmp); + } + + /* + * Calculate SCLK + */ + tmp = INPLL(pScrn, RADEON_SCLK_CNTL) & 0x7; + switch(tmp) { + case 1: info->sclk = spll; break; + case 2: info->sclk = spll / 2.0; break; + case 3: info->sclk = spll / 4.0; break; + case 4: info->sclk = spll / 8.0; break; + case 7: info->sclk = mpll; + default: + info->sclk = 200.00; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unsupported SCLK source" + " setting %d, can't probe SCLK value !\n", tmp); + } /* we're done, hopefully these are sane values */ pll->reference_div = ref_div; pll->xclk = xclk; pll->reference_freq = xtal; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Probed PLL values: xtal: %f Mhz, " + "sclk: %f Mhz, mclk: %f Mhz\n", xtal/100.0, info->sclk, info->mclk); + return TRUE; } #endif