xf86-video-intel: Branch 'display-port' - src/i830_display.c src/i830_dp.c src/i830_driver.c src/i830.h

Keith Packard keithp at kemper.freedesktop.org
Fri Apr 3 13:26:24 PDT 2009


 src/i830.h         |   10 ++
 src/i830_display.c |    5 +
 src/i830_dp.c      |  187 ++++++++++++++++++++++++++++++++++-------------------
 src/i830_driver.c  |   24 ++++++
 4 files changed, 159 insertions(+), 67 deletions(-)

New commits:
commit 922fe23c21b1a84019064b2660d881bcb790d8e9
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Apr 3 13:23:24 2009 -0700

    Save/restore DP link/gmch ratios. Set link ratios before enabling pipe.
    
    The DP link ratios control how the pipe sends data to the output, and so
    should be configured before the pipe is turned on. This should make the
    output work the first time it is enabled. This bug was masked because the
    server didn't save and restore the ratio registers, so subsequent calls to
    enable the output would work using the values previously stored in those
    registers.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/src/i830.h b/src/i830.h
index c8fb8f9..ace5af0 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -703,6 +703,14 @@ typedef struct _I830Rec {
    uint32_t saveDSPCLK_GATE_D;
    uint32_t saveRAMCLK_GATE_D;
    uint32_t savePWRCTXA;
+   uint32_t savePIPEA_GMCH_DATA_M;
+   uint32_t savePIPEA_GMCH_DATA_N;
+   uint32_t savePIPEA_DP_LINK_M;
+   uint32_t savePIPEA_DP_LINK_N;
+   uint32_t savePIPEB_GMCH_DATA_M;
+   uint32_t savePIPEB_GMCH_DATA_N;
+   uint32_t savePIPEB_DP_LINK_M;
+   uint32_t savePIPEB_DP_LINK_N;
 
    enum last_3d last_3d;
 
@@ -879,6 +887,8 @@ void i830_crt_init(ScrnInfoPtr pScrn);
 
 /* i830_dp.c */
 Bool i830_dp_init(ScrnInfoPtr pScrn, int output_reg);
+void i830_dp_set_m_n(xf86CrtcPtr crtc, DisplayModePtr mode,
+		     DisplayModePtr adjusted_mode);
 
 /* i830_dvo.c */
 void i830_dvo_init(ScrnInfoPtr pScrn);
diff --git a/src/i830_display.c b/src/i830_display.c
index ddefef1..7d2cc4c 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1539,6 +1539,11 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
 	usleep(150);
     }
 
+    /* The Display Port M/N ratio needs to be set before the DPLL is enabled
+     */
+    if (is_dp)
+	i830_dp_set_m_n(crtc, mode, adjusted_mode);
+
     /* 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.
diff --git a/src/i830_dp.c b/src/i830_dp.c
index f7d4779..a6ca5b6 100644
--- a/src/i830_dp.c
+++ b/src/i830_dp.c
@@ -39,10 +39,14 @@
 #define DP_LINK_STATUS_SIZE	6
 #define DP_LINK_CHECK_TIMEOUT	(10 * 1000)
 
+#define DP_LINK_CONFIGURATION_SIZE	9
+
 struct i830_dp_priv {
     uint32_t output_reg;
+    uint32_t DP;
+    uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
     uint32_t save_DP;
-    uint8_t  save_link_configuration[0x9];
+    uint8_t  save_link_configuration[DP_LINK_CONFIGURATION_SIZE];
     Bool has_audio;
     uint16_t i2c_address;
     uint8_t link_bw;
@@ -53,7 +57,11 @@ struct i830_dp_priv {
 };
 
 static void
-i830_dp_link_train(xf86OutputPtr output, uint32_t DP);
+i830_dp_link_train(xf86OutputPtr output, uint32_t DP,
+		   uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]);
+
+static void
+i830_dp_link_down(xf86OutputPtr output, uint32_t DP);
 
 static int
 i830_dp_max_lane_count(xf86OutputPtr output)
@@ -445,10 +453,6 @@ i830_dp_compute_m_n(int bytes_per_pixel,
 {
 	m_n->tu = 64;
 	m_n->gmch_m = pixel_clock * bytes_per_pixel;
-	/*
-	 * I do not understand this one -- the docs say nlanes,
-	 * and yet (nlanes + 1) appears to be the correct value
-	 */
 	m_n->gmch_n = link_clock * nlanes;
 	i830_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
 	m_n->link_m = pixel_clock;
@@ -456,26 +460,38 @@ i830_dp_compute_m_n(int bytes_per_pixel,
 	i830_reduce_ratio(&m_n->link_m, &m_n->link_n);
 }
 
-static void
-i830_dp_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+void
+i830_dp_set_m_n(xf86CrtcPtr crtc, DisplayModePtr mode,
 		   DisplayModePtr adjusted_mode)
 {
-    ScrnInfoPtr pScrn = output->scrn;
-    I830OutputPrivatePtr intel_output = output->driver_private;
-    struct i830_dp_priv *dev_priv = intel_output->dev_priv;
-    I830Ptr pI830 = I830PTR(pScrn);
-    xf86CrtcPtr crtc = output->crtc;
+    ScrnInfoPtr pScrn = crtc->scrn;
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
-    uint32_t dp;
+    I830Ptr pI830 = I830PTR(pScrn);
+    int lane_count = 4;
+    int i;
     struct i830_dp_m_n m_n;
-    uint8_t link_configuration[0x9];
+
+    /*
+     * Find the lane count in the output private
+     */
+    for (i = 0; i < xf86_config->num_output; i++) {
+	xf86OutputPtr output = xf86_config->output[i];
+	I830OutputPrivatePtr intel_output = output->driver_private;
+	struct i830_dp_priv *dev_priv = intel_output->dev_priv;
+
+	if (output->crtc == crtc && intel_output->type == I830_OUTPUT_DISPLAYPORT) {
+	    lane_count = dev_priv->lane_count;
+	    break;
+	}
+    }
 
     /*
      * Compute the GMCH and Link ratios. The '3' here is
      * the number of bytes_per_pixel post-LUT, which we always
      * set up for 8-bits of R/G/B, or 3 bytes total.
      */
-    i830_dp_compute_m_n(3, dev_priv->lane_count,
+    i830_dp_compute_m_n(3, lane_count,
 			mode->Clock, adjusted_mode->Clock, &m_n);
 
     if (intel_crtc->pipe == 0) {
@@ -495,50 +511,56 @@ i830_dp_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 	OUTREG(PIPEB_DP_LINK_M, m_n.link_m);
 	OUTREG(PIPEB_DP_LINK_N, m_n.link_n);
     }
+}
+
+static void
+i830_dp_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		   DisplayModePtr adjusted_mode)
+{
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_dp_priv *dev_priv = intel_output->dev_priv;
+    xf86CrtcPtr crtc = output->crtc;
+    I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
 
-    dp = (DP_LINK_TRAIN_OFF |
-	  DP_VOLTAGE_0_4 |
-	  DP_PRE_EMPHASIS_0 |
-	  DP_SYNC_VS_HIGH |
-	  DP_SYNC_HS_HIGH);
+    dev_priv->DP = (DP_LINK_TRAIN_OFF |
+		    DP_VOLTAGE_0_4 |
+		    DP_PRE_EMPHASIS_0 |
+		    DP_SYNC_VS_HIGH |
+		    DP_SYNC_HS_HIGH);
 
     switch (dev_priv->lane_count) {
     case 1:
-	dp |= DP_PORT_WIDTH_1;
+	dev_priv->DP |= DP_PORT_WIDTH_1;
 	break;
     case 2:
-	dp |= DP_PORT_WIDTH_2;
+	dev_priv->DP |= DP_PORT_WIDTH_2;
 	break;
     case 4:
-	dp |= DP_PORT_WIDTH_4;
+	dev_priv->DP |= DP_PORT_WIDTH_4;
 	break;
     }
     if (dev_priv->has_audio)
-	    dp |= DP_AUDIO_OUTPUT_ENABLE;
+	dev_priv->DP |= DP_AUDIO_OUTPUT_ENABLE;
 
-    memset(link_configuration, 0, sizeof (link_configuration));
-    link_configuration[0] = dev_priv->link_bw;
-    link_configuration[1] = dev_priv->lane_count;
+    memset(dev_priv->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
+    dev_priv->link_configuration[0] = dev_priv->link_bw;
+    dev_priv->link_configuration[1] = dev_priv->lane_count;
 
     /*
      * Check for DPCD version > 1.1,
      * enable enahanced frame stuff in that case
      */
     if (dev_priv->dpcd[0] >= 0x11) {
-	link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-	dp |= DP_ENHANCED_FRAMING;
+	dev_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+	dev_priv->DP |= DP_ENHANCED_FRAMING;
     }
 
-    i830_dp_aux_native_write(pScrn, dev_priv->output_reg, 0x100,
-			     link_configuration, sizeof (link_configuration));
-
     if (intel_crtc->pipe == 1)
-	dp |= DP_PIPEB_SELECT;
-
-    OUTREG(dev_priv->output_reg, dp);
-    POSTING_READ(dev_priv->output_reg);
+	dev_priv->DP |= DP_PIPEB_SELECT;
 }
 
+#include "i830_debug.h"
+
 static CARD32
 i830_dp_link_check_timer(OsTimerPtr timer, CARD32 now, pointer arg);
 
@@ -549,22 +571,48 @@ i830_dp_dpms(xf86OutputPtr output, int mode)
     I830OutputPrivatePtr intel_output = output->driver_private;
     struct i830_dp_priv *dev_priv = intel_output->dev_priv;
     I830Ptr pI830 = I830PTR(pScrn);
-    uint32_t  temp;
+    uint32_t  dp_reg = INREG(dev_priv->output_reg);
 
     if (mode == DPMSModeOff) {
-	temp = INREG(dev_priv->output_reg);
-	OUTREG(dev_priv->output_reg, temp & ~DP_PORT_EN);
+	if (dp_reg & DP_PORT_EN)
+	    i830_dp_link_down(output, dev_priv->DP);
 	if (dev_priv->link_check_timer) {
 	    TimerFree(dev_priv->link_check_timer);
 	    dev_priv->link_check_timer = NULL;
 	}
     } else {
-	temp = INREG(dev_priv->output_reg);
-	temp |= DP_PORT_EN;
-
-	i830_dp_link_train(output, temp);
-	dev_priv->link_check_timer = TimerSet(NULL, 0, DP_LINK_CHECK_TIMEOUT,
-					      i830_dp_link_check_timer, output);
+	if (!(dp_reg & DP_PORT_EN)) {
+	    uint32_t	pipestat;
+	    uint32_t	pipestat_reg;
+	    xf86CrtcPtr crtc = output->crtc;
+	    I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+	    if (intel_crtc->pipe == 1)
+		pipestat_reg = PIPEBSTAT;
+	    else
+		pipestat_reg = PIPEASTAT;
+	    OUTREG(pipestat_reg, INREG(pipestat_reg));	/* clear interrupt status */
+	    do {
+		pipestat = INREG(pipestat_reg);
+	    } while (!(pipestat & VSYNC_INT_STATUS));
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Registers before link training\n");
+	    i830DumpRegs(pScrn);
+	    i830_dp_link_train(output, dev_priv->DP, dev_priv->link_configuration);
+
+	    i830WaitForVblank(pScrn);
+	    i830_dp_link_down(output, dev_priv->DP);
+	    i830WaitForVblank(pScrn);
+	    crtc->funcs->dpms(crtc, DPMSModeOff);
+	    i830WaitForVblank(pScrn);
+	    crtc->funcs->dpms(crtc, DPMSModeOn);
+	    i830WaitForVblank(pScrn);
+	    i830_dp_link_train(output, dev_priv->DP, dev_priv->link_configuration);
+	    i830WaitForVblank(pScrn);
+
+	    if (!dev_priv->link_check_timer)
+		dev_priv->link_check_timer = TimerSet(NULL, 0, DP_LINK_CHECK_TIMEOUT,
+						      i830_dp_link_check_timer, output);
+	}
     }
 }
 
@@ -802,7 +850,7 @@ i830_dp_set_link_train(xf86OutputPtr output,
 
 	OUTREG(dev_priv->output_reg, dp_reg_value);
 	POSTING_READ(dev_priv->output_reg);
-	if (first)
+//	if (first)
 		i830WaitForVblank(pScrn);
 
 	i830_dp_aux_native_write_1(pScrn, dev_priv->output_reg,
@@ -820,7 +868,8 @@ i830_dp_set_link_train(xf86OutputPtr output,
 }
 
 static void
-i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
+i830_dp_link_train(xf86OutputPtr output, uint32_t DP,
+		   uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE])
 {
     ScrnInfoPtr pScrn = output->scrn;
     I830OutputPrivatePtr intel_output = output->driver_private;
@@ -835,15 +884,13 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
     Bool first = TRUE;
     int tries;
 
-    if ((DP & DP_PORT_EN) == 0) {
-	OUTREG(dev_priv->output_reg, DP);
-	POSTING_READ(dev_priv->output_reg);
-	return;
-    }
-    DP &= ~DP_LINK_TRAIN_MASK;
+    /* Write the link configuration data */
+    i830_dp_aux_native_write(pScrn, dev_priv->output_reg, 0x100,
+			     link_configuration, DP_LINK_CONFIGURATION_SIZE);
 
+    DP |= DP_PORT_EN;
+    DP &= ~DP_LINK_TRAIN_MASK;
     memset(train_set, 0, 4);
-
     voltage = 0xff;
     tries = 0;
     clock_recovery = FALSE;
@@ -948,10 +995,20 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
 
     OUTREG(dev_priv->output_reg, DP | DP_LINK_TRAIN_OFF);
     POSTING_READ(dev_priv->output_reg);
-    usleep (15*1000);
     i830_dp_aux_native_write_1(pScrn, dev_priv->output_reg,
 			DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
-    usleep (15*1000);
+}
+
+static void
+i830_dp_link_down(xf86OutputPtr output, uint32_t DP)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_dp_priv *dev_priv = intel_output->dev_priv;
+    I830Ptr pI830 = I830PTR(pScrn);
+
+    OUTREG(dev_priv->output_reg, DP & ~DP_PORT_EN);
+    POSTING_READ(dev_priv->output_reg);
 }
 
 /*
@@ -1080,13 +1137,13 @@ i830_dp_i2c_init(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr,
 static void
 i830_dp_restore(xf86OutputPtr output)
 {
-    ScrnInfoPtr pScrn = output->scrn;
     I830OutputPrivatePtr intel_output = output->driver_private;
     struct i830_dp_priv *dev_priv = intel_output->dev_priv;
 
-    i830_dp_aux_native_write(pScrn, dev_priv->output_reg, 0x100,
-		     dev_priv->save_link_configuration, sizeof (dev_priv->save_link_configuration));
-    i830_dp_link_train(output, dev_priv->save_DP);
+    if (dev_priv->save_DP & DP_PORT_EN)
+	i830_dp_link_train(output, dev_priv->save_DP, dev_priv->save_link_configuration);
+    else
+	i830_dp_link_down(output,  dev_priv->save_DP);
 }
 
 /*
@@ -1101,24 +1158,20 @@ i830_dp_restore(xf86OutputPtr output)
 static void
 i830_dp_check_link_status(xf86OutputPtr output)
 {
-	ScrnInfoPtr	pScrn = output->scrn;
 	I830OutputPrivatePtr intel_output = output->driver_private;
 	struct i830_dp_priv *dev_priv = intel_output->dev_priv;
-	I830Ptr pI830 = I830PTR(pScrn);
 	uint8_t link_status[DP_LINK_STATUS_SIZE];
 
 	if (!output->crtc)
 		return;
 
 	if (!i830_dp_get_link_status(output, link_status)) {
-		OUTREG(dev_priv->output_reg,
-		       INREG(dev_priv->output_reg) & ~DP_PORT_EN);
+		i830_dp_link_down(output, dev_priv->DP);
 		return;
 	}
 
 	if (!i830_channel_eq_ok(link_status, dev_priv->lane_count))
-		i830_dp_link_train(output,
-				   INREG(dev_priv->output_reg) | DP_PORT_EN);
+		i830_dp_link_train(output, dev_priv->DP, dev_priv->link_configuration);
 }
 
 static CARD32
diff --git a/src/i830_driver.c b/src/i830_driver.c
index b78ef87..d23cf95 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -2190,6 +2190,12 @@ SaveHWState(ScrnInfoPtr pScrn)
    pI830->saveDSPASIZE = INREG(DSPASIZE);
    pI830->saveDSPAPOS = INREG(DSPAPOS);
    pI830->saveDSPABASE = INREG(DSPABASE);
+   if (IS_G4X(pI830)) {
+      pI830->savePIPEA_GMCH_DATA_M = INREG(PIPEA_GMCH_DATA_M);
+      pI830->savePIPEA_GMCH_DATA_N = INREG(PIPEA_GMCH_DATA_N);
+      pI830->savePIPEA_DP_LINK_M = INREG(PIPEA_DP_LINK_M);
+      pI830->savePIPEA_DP_LINK_N = INREG(PIPEA_DP_LINK_N);
+   }
 
    i830_save_palette(pI830, PIPE_A);
 
@@ -2213,6 +2219,12 @@ SaveHWState(ScrnInfoPtr pScrn)
       pI830->saveDSPBSIZE = INREG(DSPBSIZE);
       pI830->saveDSPBPOS = INREG(DSPBPOS);
       pI830->saveDSPBBASE = INREG(DSPBBASE);
+      if (IS_G4X(pI830)) {
+	 pI830->savePIPEB_GMCH_DATA_M = INREG(PIPEB_GMCH_DATA_M);
+	 pI830->savePIPEB_GMCH_DATA_N = INREG(PIPEB_GMCH_DATA_N);
+	 pI830->savePIPEB_DP_LINK_M = INREG(PIPEB_DP_LINK_M);
+	 pI830->savePIPEB_DP_LINK_N = INREG(PIPEB_DP_LINK_N);
+      }
 
       i830_save_palette(pI830, PIPE_B);
    }
@@ -2381,6 +2393,12 @@ RestoreHWState(ScrnInfoPtr pScrn)
       OUTREG(DSPASURF, pI830->saveDSPASURF);
       OUTREG(DSPATILEOFF, pI830->saveDSPATILEOFF);
    }
+   if (IS_G4X(pI830)) {
+      OUTREG(PIPEA_GMCH_DATA_M, pI830->savePIPEA_GMCH_DATA_M);
+      OUTREG(PIPEA_GMCH_DATA_N, pI830->savePIPEA_GMCH_DATA_N);
+      OUTREG(PIPEA_DP_LINK_M, pI830->savePIPEA_DP_LINK_M);
+      OUTREG(PIPEA_DP_LINK_N, pI830->savePIPEA_DP_LINK_N);
+   }
 
    OUTREG(PIPEACONF, pI830->savePIPEACONF);
    POSTING_READ(PIPEACONF);
@@ -2448,6 +2466,12 @@ RestoreHWState(ScrnInfoPtr pScrn)
 	 OUTREG(DSPBSURF, pI830->saveDSPBSURF);
 	 OUTREG(DSPBTILEOFF, pI830->saveDSPBTILEOFF);
       }
+      if (IS_G4X(pI830)) {
+	 OUTREG(PIPEB_GMCH_DATA_M, pI830->savePIPEB_GMCH_DATA_M);
+	 OUTREG(PIPEB_GMCH_DATA_N, pI830->savePIPEB_GMCH_DATA_N);
+	 OUTREG(PIPEB_DP_LINK_M, pI830->savePIPEB_DP_LINK_M);
+	 OUTREG(PIPEB_DP_LINK_N, pI830->savePIPEB_DP_LINK_N);
+      }
 
       OUTREG(PIPEBCONF, pI830->savePIPEBCONF);
       POSTING_READ(PIPEBCONF);


More information about the xorg-commit mailing list