diff options
-rw-r--r-- | src/i810_reg.h | 53 | ||||
-rw-r--r-- | src/i830_debug.c | 15 | ||||
-rw-r--r-- | src/i830_display.c | 53 | ||||
-rw-r--r-- | src/i830_driver.c | 5 | ||||
-rw-r--r-- | src/i830_lvds.c | 9 |
5 files changed, 105 insertions, 30 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h index f50646bd..e4bebafa 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -1128,8 +1128,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define DVO_SRCDIM_HORIZONTAL_SHIFT 12 #define DVO_SRCDIM_VERTICAL_SHIFT 0 +/** @defgroup LVDS + * @{ + */ +/** + * This register controls the LVDS output enable, pipe selection, and data + * format selection. + * + * All of the clock/data pairs are force powered down by power sequencing. + */ #define LVDS 0x61180 +/** + * Enables the LVDS port. This bit must be set before DPLLs are enabled, as + * the DPLL semantics change when the LVDS is assigned to that pipe. + */ # define LVDS_PORT_EN (1 << 31) +/** Selects pipe B for LVDS data. Must be set on pre-965. */ # define LVDS_PIPEB_SELECT (1 << 30) /* on 965, dithering is enabled in this register, not PFIT_CONTROL */ @@ -1189,18 +1203,39 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ # define LVDS_POWER_DOWN_TRI_STATE (1 << 10) -/* - * Clock A control; overridden by LVDS power sequencing +/** + * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per + * pixel. */ +# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +# define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +/** + * Controls the A3 data pair, which contains the additional LSBs for 24 bit + * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be + * on. + */ +# define LVDS_A3_POWER_MASK (3 << 6) +# define LVDS_A3_POWER_DOWN (0 << 6) +# define LVDS_A3_POWER_UP (3 << 6) +/** + * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP + * is set. + */ +# define LVDS_CLKB_POWER_MASK (3 << 4) +# define LVDS_CLKB_POWER_DOWN (0 << 4) +# define LVDS_CLKB_POWER_UP (3 << 4) -/* power down everything including A3 (0V) */ -# define LVDS_CLKA_POWER_DOWN (0 << 8) - -/* Partially active. A0, A1, A2 set to 0, timing active, clock active */ -# define LVDS_CLKA_POWER_PARTIAL (1 << 8) +/** + * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 + * setting for whether we are in dual-channel mode. The B3 pair will + * additionally only be powered up when LVDS_A3_POWER_UP is set. + */ +# define LVDS_B0B3_POWER_MASK (3 << 2) +# define LVDS_B0B3_POWER_DOWN (0 << 2) +# define LVDS_B0B3_POWER_UP (3 << 2) -/* running, data and clock active */ -# define LVDS_CLKA_POWER_UP (3 << 8) +/** @} */ /* * Two channel clock control. Turn this on if you need clkb for two channel mode diff --git a/src/i830_debug.c b/src/i830_debug.c index c746d35d..c0261a6c 100644 --- a/src/i830_debug.c +++ b/src/i830_debug.c @@ -269,8 +269,21 @@ DEBUGSTRING(i830_debug_lvds) { char pipe = val & LVDS_PIPEB_SELECT ? 'B' : 'A'; char *enable = val & LVDS_PORT_EN ? "enabled" : "disabled"; + int depth; + char *channels; - return XNFprintf("%s, pipe %c", enable, pipe); + if ((val & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + depth = 24; + else + depth = 18; + if ((val & LVDS_B0B3_POWER_MASK) == LVDS_B0B3_POWER_UP) + channels = "2 channels"; + else + channels = "1 channel"; + + + return XNFprintf("%s, pipe %c, %d bit, %s", + enable, pipe, depth, channels); } DEBUGSTRING(i830_debug_sdvo) diff --git a/src/i830_display.c b/src/i830_display.c index 2810a8be..5cedd778 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -298,8 +298,9 @@ i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock) } /** - * Returns a set of divisors for the desired target clock with the given refclk, - * or FALSE. Divisor values are the actual divisors for + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE. The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. */ static Bool i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_clock) @@ -310,10 +311,23 @@ i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_cl const intel_limit_t *limit = intel_limit (crtc); int err = target; - if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; - else - clock.p2 = limit->p2.p2_fast; + if (IS_I9XX(pI830) && i830PipeHasType(crtc, I830_OUTPUT_LVDS) && + (INREG(LVDS) & LVDS_PORT_EN) != 0) + { + /* For LVDS, if the panel is on, just rely on its current settings for + * dual-channel. We haven't figured out how to reliably set up + * different single/dual channel state, if we even can. + */ + if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } memset (best_clock, 0, sizeof (*best_clock)); @@ -890,22 +904,37 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, usleep(150); } + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ if (is_lvds) { - CARD32 lvds = INREG(LVDS); + CARD32 lvds = INREG(LVDS); + + lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (adjusted_mode->Clock >= I9XX_P2_LVDS_SLOW_LIMIT) + lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. */ - lvds |= LVDS_PORT_EN | LVDS_PIPEB_SELECT; + + /* Enable dithering if we're in 18-bit mode. */ if (IS_I965G(pI830)) { - if (pI830->panel_wants_dither) + if ((lvds & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) lvds |= LVDS_DITHER_ENABLE; else lvds &= ~LVDS_DITHER_ENABLE; } + OUTREG(LVDS, lvds); POSTING_READ(LVDS); } diff --git a/src/i830_driver.c b/src/i830_driver.c index 513b2065..20217538 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -1734,6 +1734,8 @@ SaveHWState(ScrnInfoPtr pScrn) pI830->saveSWF[15] = INREG(SWF31); pI830->saveSWF[16] = INREG(SWF32); + if (IS_MOBILE(pI830) && !IS_I830(pI830)) + pI830->saveLVDS = INREG(LVDS); pI830->savePFIT_CONTROL = INREG(PFIT_CONTROL); for (i = 0; i < xf86_config->num_output; i++) { @@ -1776,6 +1778,9 @@ RestoreHWState(ScrnInfoPtr pScrn) } i830WaitForVblank(pScrn); + if (IS_MOBILE(pI830) && !IS_I830(pI830)) + OUTREG(LVDS, pI830->saveLVDS); + if (!IS_I830(pI830) && !IS_845G(pI830)) OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL); diff --git a/src/i830_lvds.c b/src/i830_lvds.c index 23b61f28..7e5ce67a 100644 --- a/src/i830_lvds.c +++ b/src/i830_lvds.c @@ -98,7 +98,7 @@ i830_lvds_dpms (xf86OutputPtr output, int mode) else i830SetLVDSPanelPower(pScrn, FALSE); - /* XXX: We never power down the LVDS pair. */ + /* XXX: We never power down the LVDS pairs. */ } static void @@ -109,7 +109,6 @@ i830_lvds_save (xf86OutputPtr output) pI830->savePP_ON = INREG(LVDSPP_ON); pI830->savePP_OFF = INREG(LVDSPP_OFF); - pI830->saveLVDS = INREG(LVDS); pI830->savePP_CONTROL = INREG(PP_CONTROL); pI830->savePP_CYCLE = INREG(PP_CYCLE); pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL); @@ -133,7 +132,6 @@ i830_lvds_restore(xf86OutputPtr output) OUTREG(LVDSPP_ON, pI830->savePP_ON); OUTREG(LVDSPP_OFF, pI830->savePP_OFF); OUTREG(PP_CYCLE, pI830->savePP_CYCLE); - OUTREG(LVDS, pI830->saveLVDS); OUTREG(PP_CONTROL, pI830->savePP_CONTROL); if (pI830->savePP_CONTROL & POWER_TARGET_ON) i830SetLVDSPanelPower(pScrn, TRUE); @@ -204,11 +202,6 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V); } - /* XXX: if we don't have BIOS fixed timings (or we have - * a preferred mode from DDC, probably), we should use the - * DDC mode as the fixed timing. - */ - /* XXX: It would be nice to support lower refresh rates on the * panels to reduce power consumption, and perhaps match the * user's requested refresh rate. |