From 72e25a7488c2eabcc92e9e0769a89dee687f52fd Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 21 Jun 2006 16:04:18 -0700 Subject: [PATCH] Fix SDVO output at low pixel clocks. I had interpreted the docs as saying that the multiplier setting would further divide the clock and stuff dummy bytes in. Instead, we have to set the DPLL at the higher clock rate, and the pixel multiplier just controls the stuffing of dummy bytes. Also, we have to set the multiplier both in the graphics chip and on the SDVO device on the other side. --- src/i810_reg.h | 4 +++- src/i830_display.c | 25 +++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/i810_reg.h b/src/i810_reg.h index b95f795b..e8462f9d 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -726,7 +726,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) # define DISPLAY_RATE_SELECT_FPA1 (1 << 8) # define SDVO_MULTIPLIER_MASK 0x000000ff -# define SDVO_DEFAULT_MULTIPLIER 0x00000003 +# define SDVO_MULTIPLIER_SHIFT_HIRES 4 +# define SDVO_MULTIPLIER_SHIFT_VGA 0 #define BLC_PWM_CTL 0x61254 #define BACKLIGHT_MODULATION_FREQ_SHIFT (17) @@ -769,6 +770,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SDVO_INTERRUPT_ENABLE (1 << 26) /* Programmed value is multiplier - 1, up to 5x. alv, gdg only */ #define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 #define SDVO_PHASE_SELECT_MASK (15 << 19) #define SDVO_PHASE_SELECT_DEFAULT (6 << 19) #define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) diff --git a/src/i830_display.c b/src/i830_display.c index f1642da3..0fadc0c1 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -259,7 +259,7 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) CARD32 pipesrc, dspsize, adpa; CARD32 sdvob = 0, sdvoc= 0; Bool ok, is_sdvo; - int refclk, pixel_clock; + int refclk, pixel_clock, sdvo_pixel_multiply; int outputs; ErrorF("Requested pix clock: %d\n", pMode->Clock); @@ -342,6 +342,22 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) pixel_clock = pI830->panel_fixed_clock; } + if (pMode->Clock >= 100000) + sdvo_pixel_multiply = 1; + else if (pMode->Clock >= 50000) + sdvo_pixel_multiply = 2; + else + sdvo_pixel_multiply = 4; + + /* In SDVO, we need to keep the clock on the bus between 1Ghz and 2Ghz. + * The clock on the bus is 10 times the pixel clock normally. If that + * would be too low, we run the DPLL at a multiple of the pixel clock, and + * tell the SDVO device the multiplier so it can throw away the dummy bytes. + */ + if (is_sdvo) { + pixel_clock *= sdvo_pixel_multiply; + } + if (IS_I9XX(pI830)) { refclk = 96000; } else { @@ -386,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; @@ -399,6 +414,12 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) sdvoc |= 9 << 19; if (pipe == 1) sdvob |= SDVO_PIPE_B_SELECT; + + if (IS_I945G(pI830) || IS_I945GM(pI830)) + dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + else + sdvob |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; + OUTREG(SDVOC, INREG(SDVOC) & ~SDVO_ENABLE); OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE); }