diff options
Diffstat (limited to 'src/i830_display.c')
-rw-r--r-- | src/i830_display.c | 78 |
1 files changed, 59 insertions, 19 deletions
diff --git a/src/i830_display.c b/src/i830_display.c index a94e21da..fea9911a 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -46,7 +46,7 @@ /** Returns the pixel clock for the given refclk and divisors. */ static int i830_clock(int refclk, int m1, int m2, int n, int p1, int p2) { - return refclk * (5 * m1 + m2) / n / (p1 * p2); + return (refclk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2)) / (p1 * p2); } static void @@ -65,7 +65,7 @@ i830PrintPll(char *prefix, int refclk, int m1, int m2, int n, int p1, int p2) * the given outputs. * * The equation for these divisors would be: - * clk = refclk * (5 * m1 + m2) / n / (p1 * p2) + * clk = refclk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / (p1 * p2) */ static Bool i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2, @@ -78,11 +78,11 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2, if (IS_I9XX(pI830)) { min_m1 = 10; - max_m1 = 20; + max_m1 = 31; min_m2 = 5; max_m2 = 9; min_m = 70; - max_m = 120; + max_m = 180; min_n = 3; max_n = 8; min_p1 = 1; @@ -95,9 +95,9 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2, max_p = 80; } min_vco = 1400000; - max_vco = 2800000; + max_vco = 3800000; min_dot = 20000; - max_dot = 400000; + max_dot = 1600000; } else { min_m1 = 18; max_m1 = 26; @@ -118,8 +118,8 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2, } p = p1 * p2; - m = 5 * m1 + m2; - vco = refclk * m / n; + m = 5 * (m1 + 2) + (m2 + 2); + vco = refclk * m / (n + 2); dotclock = i830_clock(refclk, m1, m2, n, p1, p2); if (p1 < min_p1 || p1 > max_p1) @@ -150,7 +150,7 @@ i830PllIsValid(ScrnInfoPtr pScrn, int outputs, int refclk, int m1, int m2, /** * Returns a set of divisors for the desired target clock with the given refclk, * or FALSE. Divisor values are the actual divisors for - * clk = refclk * (5 * m1 + m2) / n / (p1 * p2) + * clk = refclk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / (p1 * p2) */ static Bool i830FindBestPLL(ScrnInfoPtr pScrn, int outputs, int target, int refclk, @@ -163,7 +163,7 @@ i830FindBestPLL(ScrnInfoPtr pScrn, int outputs, int target, int refclk, if (IS_I9XX(pI830)) { min_m1 = 10; - max_m1 = 20; + max_m1 = 31; min_m2 = 5; max_m2 = 9; min_n = 3; @@ -205,10 +205,16 @@ i830FindBestPLL(ScrnInfoPtr pScrn, int outputs, int target, int refclk, if (!i830PllIsValid(pScrn, outputs, refclk, m1, m2, n, p1, p2)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "mode %d %d %d %d %d = invalid\n", + m1, m2, n, p1, p2); continue; } clock = i830_clock(refclk, m1, m2, n, p1, p2); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "mode %d %d %d %d %d = %d\n", + m1, m2, n, p1, p2, clock); this_err = abs(clock - target); if (this_err < err) { *outm1 = m1; @@ -435,6 +441,7 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) pipesrc = ((pMode->HDisplay - 1) << 16) | (pMode->VDisplay - 1); dspsize = ((pMode->VDisplay - 1) << 16) | (pMode->HDisplay - 1); pixel_clock = pMode->Clock; + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "mode clock %d\n", pixel_clock); if (is_lvds && pI830->panel_fixed_hactive != 0) { /* To enable panel fitting, we need to set the pipe timings to that of @@ -479,7 +486,13 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) * bytes. */ if (is_sdvo) { - pixel_clock *= i830_sdvo_get_pixel_multiplier(pMode); + int pixel_multiply = i830_sdvo_get_pixel_multiplier(pMode); + pixel_clock *= pixel_multiply; + if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_I965G(pI830)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "pixel multiply is %d\n", pixel_multiply); + dpll |= (pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + } } if (IS_I9XX(pI830)) { @@ -528,10 +541,14 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) else if (is_lvds) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; #endif + else if (is_sdvo) + dpll |= DPLL_DVO_HIGH_SPEED; else dpll |= PLL_REF_INPUT_DREFCLK; - fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2); + /* set phase */ + dpll |= (6 << 9); + fp = (n << 16) | (m1 << 8) | m2; #if 1 ErrorF("hact: %d htot: %d hbstart: %d hbend: %d hsyncstart: %d hsyncend: %d\n", @@ -580,6 +597,11 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) OUTREG(VGACNTRL, VGA_DISP_DISABLE); /* Finally, set the mode. */ + /* Disable ports */ + /* XXX */ + temp = INREG(ADPA); + OUTREG(ADPA, temp & ~ADPA_DAC_ENABLE); + /* First, disable display planes */ temp = INREG(dspcntr_reg); OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); @@ -591,13 +613,22 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) temp = INREG(pipeconf_reg); OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + temp = INREG(VGACNTRL); + OUTREG(VGACNTRL, temp | VGA_DISP_DISABLE); + + /* finally, disable the PLL */ + temp = INREG(dpll_reg); + OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE); + + i830WaitForVblank(pScrn); + + /* enable the PLL */ + OUTREG(fp_reg, fp); + /* writing DPLL triggers PLL frequency shift */ + i830WaitForVblank(pScrn); OUTREG(dpll_reg, dpll); - - for (i = 0; i < pI830->num_outputs; i++) { - if (pI830->output[i].pipe == pipe) - pI830->output[i].post_set_mode(pScrn, &pI830->output[i], pMode); - } + i830WaitForVblank(pScrn); OUTREG(htot_reg, htot); OUTREG(hblank_reg, hblank); @@ -608,16 +639,25 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp); OUTREG(dspsize_reg, dspsize); OUTREG(dsppos_reg, 0); + i830PipeSetBase(pScrn, pipe, pI830->pipeX[pipe], pI830->pipeX[pipe]); OUTREG(pipesrc_reg, pipesrc); - /* Then, turn the pipe on first */ + i830WaitForVblank(pScrn); + + /* enable the pipe */ temp = INREG(pipeconf_reg); OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE); - /* And then turn the plane on */ + /* enable the plane */ OUTREG(dspcntr_reg, dspcntr); + /* enable the ports */ + for (i = 0; i < pI830->num_outputs; i++) { + if (pI830->output[i].pipe == pipe && !pI830->output[i].disabled) + pI830->output[i].post_set_mode(pScrn, &pI830->output[i], pMode); + } + pI830->pipeCurMode[pipe] = *pMode; return TRUE; |