summaryrefslogtreecommitdiff
path: root/src/i830_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i830_display.c')
-rw-r--r--src/i830_display.c78
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;