xf86-video-intel: src/i810_reg.h src/i830_debug.c src/i830_display.c src/i830_driver.c src/i830_lvds.c

Eric Anholt anholt at kemper.freedesktop.org
Wed Mar 21 00:06:34 EET 2007


 src/i810_reg.h     |   50 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/i830_debug.c   |   15 ++++++++++++++-
 src/i830_display.c |   50 ++++++++++++++++++++++++++++++++++++++++----------
 src/i830_driver.c  |    5 +++++
 src/i830_lvds.c    |    9 +--------
 5 files changed, 108 insertions(+), 21 deletions(-)

New commits:
diff-tree 223944878cf38f86580df5a7d3102d86cfc061b9 (from 4c4faf260eb4dad1b1919c6168fa9ef477b98a39)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Mar 20 14:33:53 2007 -0700

    Attempt to fix single/dual-channel issues on i9xx LVDS panels.
    
    - Use the existing single/dual-channel state when available, as changing it
      doesn't appear to work out.
    - Set the power state of the CLKB and B0-B3 pairs according to whether
      choose to go dual-channel or not.
    - Restore the LVDS register at the appropriate point (before DPLLs are
      re-programmed.

diff --git a/src/i810_reg.h b/src/i810_reg.h
index d63be02..4c6e582 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -1128,11 +1128,57 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 #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)
-# define LVDS_CLKA_POWER_DOWN		(0 << 8)
-# define LVDS_CLKA_POWER_UP		(3 << 8)
+
+/**
+ * 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)
+
+/**
+ * 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)
+
+/** @} */
 
 /** @defgroup TV_CTL
  * @{
diff --git a/src/i830_debug.c b/src/i830_debug.c
index c746d35..c0261a6 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 faa3781..d55e0a6 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -298,8 +298,9 @@ i830PllIsValid(xf86CrtcPtr crtc, intel_c
 }
 
 /**
- * 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 ta
     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,13 +904,29 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, Dis
 	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)
     {
-	/* 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.
+	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);
+
+	/* 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.
 	 */
-	OUTREG(LVDS, INREG(LVDS) | LVDS_PORT_EN | LVDS_PIPEB_SELECT);
+
+	OUTREG(LVDS, lvds);
 	POSTING_READ(LVDS);
     }
 
diff --git a/src/i830_driver.c b/src/i830_driver.c
index c6aea5c..f41beb0 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1729,6 +1729,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++) {
@@ -1771,6 +1773,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 adfbe4f..6f7750a 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -98,7 +98,7 @@ i830_lvds_dpms (xf86OutputPtr output, in
     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 outpu
 	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.



More information about the xorg-commit mailing list