From 819a47b27cd4728feb269a08be32403304993ffa Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 30 Oct 2006 09:50:33 -0800 Subject: [PATCH] Use the new fields for SDVO pixel multiply on the G965. This should fix display at resolutions/refresh rates in a different multiplier class than the console display (generally, high resolution modes). --- src/i810_reg.h | 54 +++++++++++++++++++++++++++++++++++++++++++++- src/i830.h | 2 ++ src/i830_display.c | 7 ++---- src/i830_driver.c | 8 +++++++ src/i830_sdvo.c | 9 ++++++-- 5 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/i810_reg.h b/src/i810_reg.h index a80b66ee..bc6c0f8b 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -799,10 +799,56 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define PLL_REF_INPUT_TVCLKINBC (2 << 13) # define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) # define DISPLAY_RATE_SELECT_FPA1 (1 << 8) +/** + * SDVO multiplier for 945G/GM. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ # define SDVO_MULTIPLIER_MASK 0x000000ff # define SDVO_MULTIPLIER_SHIFT_HIRES 4 # define SDVO_MULTIPLIER_SHIFT_VGA 0 +/** @defgroup DPLL_MD + * @{ + */ +/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_A_MD 0x0601c +/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_B_MD 0x06020 +/** + * UDI pixel divider, controlling how many pixels are stuffed into a packet. + * + * Value is pixels minus 1. Must be set to 1 pixel for SDVO. + */ +# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +# define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/** + * SDVO/UDI pixel multiplier. + * + * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus + * clock rate is 10 times the DPLL clock. At low resolution/refresh rate + * modes, the bus rate would be below the limits, so SDVO allows for stuffing + * dummy bytes in the datastream at an increased clock rate, with both sides of + * the link knowing how many bytes are fill. + * + * So, for a mode with a dotclock of 65Mhz, we would want to double the clock + * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be + * set to 130Mhz, and the SDVO multiplier set to 2x in this register and + * through an SDVO command. + * + * This register field has values of multiplication factor minus 1, with + * a maximum multiplier of 5 for SDVO. + */ +# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. */ +# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +/** @} */ + #define BLC_PWM_CTL 0x61254 #define BACKLIGHT_MODULATION_FREQ_SHIFT (17) #define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) @@ -842,7 +888,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SDVO_PIPE_B_SELECT (1 << 30) #define SDVO_STALL_SELECT (1 << 29) #define SDVO_INTERRUPT_ENABLE (1 << 26) -/* Programmed value is multiplier - 1, up to 5x. alv, gdg only */ +/** + * 915G/GM SDVO pixel multiplier. + * + * Programmed value is multiplier - 1, up to 5x. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ #define SDVO_PORT_MULTIPLY_MASK (7 << 23) #define SDVO_PORT_MULTIPLY_SHIFT 23 #define SDVO_PHASE_SELECT_MASK (15 << 19) diff --git a/src/i830.h b/src/i830.h index 3f4eacc1..40c8cce6 100644 --- a/src/i830.h +++ b/src/i830.h @@ -509,6 +509,7 @@ typedef struct _I830Rec { CARD32 saveFPA0; CARD32 saveFPA1; CARD32 saveDPLL_A; + CARD32 saveDPLL_A_MD; CARD32 saveHTOTAL_A; CARD32 saveHBLANK_A; CARD32 saveHSYNC_A; @@ -523,6 +524,7 @@ typedef struct _I830Rec { CARD32 saveFPB0; CARD32 saveFPB1; CARD32 saveDPLL_B; + CARD32 saveDPLL_B_MD; CARD32 saveHTOTAL_B; CARD32 saveHBLANK_B; CARD32 saveHSYNC_B; diff --git a/src/i830_display.c b/src/i830_display.c index a94e21da..41f8c213 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -472,11 +472,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) } } - /* 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. + /* Adjust the clock for pixel multiplication. + * See DPLL_MD_UDI_MULTIPLIER_MASK. */ if (is_sdvo) { pixel_clock *= i830_sdvo_get_pixel_multiplier(pMode); diff --git a/src/i830_driver.c b/src/i830_driver.c index 10c6f09e..5494abb6 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2506,6 +2506,8 @@ SaveHWState(ScrnInfoPtr pScrn) pI830->saveFPA0 = INREG(FPA0); pI830->saveFPA1 = INREG(FPA1); pI830->saveDPLL_A = INREG(DPLL_A); + if (IS_I965G(pI830)) + pI830->saveDPLL_A_MD = INREG(DPLL_A_MD); pI830->saveHTOTAL_A = INREG(HTOTAL_A); pI830->saveHBLANK_A = INREG(HBLANK_A); pI830->saveHSYNC_A = INREG(HSYNC_A); @@ -2528,6 +2530,8 @@ SaveHWState(ScrnInfoPtr pScrn) pI830->saveFPB0 = INREG(FPB0); pI830->saveFPB1 = INREG(FPB1); pI830->saveDPLL_B = INREG(DPLL_B); + if (IS_I965G(pI830)) + pI830->saveDPLL_B_MD = INREG(DPLL_B_MD); pI830->saveHTOTAL_B = INREG(HTOTAL_B); pI830->saveHBLANK_B = INREG(HBLANK_B); pI830->saveHSYNC_B = INREG(HSYNC_B); @@ -2611,6 +2615,8 @@ RestoreHWState(ScrnInfoPtr pScrn) OUTREG(FPA0, pI830->saveFPA0); OUTREG(FPA1, pI830->saveFPA1); OUTREG(DPLL_A, pI830->saveDPLL_A); + if (IS_I965G(pI830)) + OUTREG(DPLL_A_MD, pI830->saveDPLL_A_MD); OUTREG(HTOTAL_A, pI830->saveHTOTAL_A); OUTREG(HBLANK_A, pI830->saveHBLANK_A); OUTREG(HSYNC_A, pI830->saveHSYNC_A); @@ -2630,6 +2636,8 @@ RestoreHWState(ScrnInfoPtr pScrn) OUTREG(FPB0, pI830->saveFPB0); OUTREG(FPB1, pI830->saveFPB1); OUTREG(DPLL_B, pI830->saveDPLL_B); + if (IS_I965G(pI830)) + OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD); OUTREG(HTOTAL_B, pI830->saveHTOTAL_B); OUTREG(HBLANK_B, pI830->saveHBLANK_B); OUTREG(HSYNC_B, pI830->saveHSYNC_B); diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index 87453b9b..bbc1c725 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -600,6 +600,7 @@ i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, Bool out1, out2, input1, input2; CARD32 dpll, sdvob, sdvoc; int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B; + int dpll_md_reg = (output->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; int sdvo_pixel_multiply; CARD8 status; @@ -630,10 +631,14 @@ i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, dpll = INREG(dpll_reg); sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(mode); - if (IS_I945G(pI830) || IS_I945GM(pI830)) + if (IS_I965G(pI830)) { + OUTREG(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | + ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + } else if (IS_I945G(pI830) || IS_I945GM(pI830)) { dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; - else + } else { sdvob |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; + } OUTREG(dpll_reg, dpll | DPLL_DVO_HIGH_SPEED);