From 7c5495d0903a50af7eb9908aec2af0ed6f83340a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 24 Apr 2006 17:23:06 -0700 Subject: Try to choose the right SDVO clock rate multiplier for the mode, so we stay within the appropriate bus limits. This currently causes me to fail to sync with my DVI output. --- src/i830_display.c | 28 ++++++++++++++++++++++++++-- src/i830_sdvo.c | 20 ++++++++++++++++---- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/i830_display.c b/src/i830_display.c index 95fa936d..72866510 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -257,7 +257,7 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr; CARD32 pipesrc, dspsize, adpa, sdvoc = 0; Bool ok, is_sdvo; - int refclk, pixel_clock; + int refclk, pixel_clock, sdvo_mult; int outputs; ErrorF("Requested pix clock: %d\n", pMode->Clock); @@ -353,6 +353,24 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) return FALSE; } + /* Find the multiplier for SDVO to keep the bus's clock rate (10 times the + * pixel rate) between 1.0Ghz and 2.0Ghz. One doc says the multiplier is + * 1 <= mult <= 5, the other says 1, 2, or 4. Be conservative. + */ + for (sdvo_mult = 1; sdvo_mult <= 4; sdvo_mult *= 2) { + if (pixel_clock * sdvo_mult >= 100000 && + pixel_clock * sdvo_mult <= 200000) + { + break; + } + } + if (sdvo_mult > 4 && is_sdvo) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't find port multiplier for SDVO with clock %d\n", + pixel_clock); + } + ErrorF("mult %d\n", sdvo_mult); + dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS; if (IS_I9XX(pI830)) { if (outputs & PIPE_LCD_ACTIVE) @@ -384,7 +402,6 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) dpll |= PLL_REF_INPUT_TVCLKINBC; else dpll |= PLL_REF_INPUT_DREFCLK; - dpll |= SDVO_DEFAULT_MULTIPLIER; if (is_sdvo) { dpll |= DPLL_DVO_HIGH_SPEED; @@ -397,6 +414,13 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) sdvoc |= SDVO_PIPE_B_SELECT; // sdvoc |= SDVO_PHASE_SELECT_DEFAULT; sdvoc |= SDVO_BORDER_ENABLE; + + if (IS_I915G(pI830) || IS_I915GM(pI830)) { + sdvoc |= 1 << (23 + sdvo_mult - 1); + } else { + dpll |= 1 << (4 + sdvo_mult - 1); + } + OUTREG(SDVOC, INREG(SDVOC) & ~SDVO_ENABLE); } diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index 99cdc6ac..5f2d37e3 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -477,6 +477,7 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode) CARD8 c17a[8]; CARD16 out_timings[6]; CARD16 clock_min, clock_max; + int mult; /* do some mode translations */ h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart; @@ -536,10 +537,21 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode) I830SDVOSetInputTimingsPart2(s, curr_table[3], curr_table[4], out_timings[5]); - /*if (mode->PrivFlags & I830_MFLAG_DOUBLE) - I830SDVOSetClockRateMult(s, 0x02); - else */ - I830SDVOSetClockRateMult(s, 0x01); + for (mult = 1; mult <= 4; mult *= 2) { + if (mode->Clock * mult >= 100000 && mode->Clock * mult <= 200000) + break; + } + switch (mult) { + case 1: + I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_1X); + break; + case 2: + I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_2X); + break; + case 4: + I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_4X); + break; + } return TRUE; } -- cgit v1.2.3