xf86-video-intel: src/i810_reg.h src/i830_crt.c src/i830_display.c src/i830_driver.c src/i830.h

Keith Packard keithp at kemper.freedesktop.org
Sat May 12 20:20:37 PDT 2007


 src/i810_reg.h     |    4 ++
 src/i830.h         |    2 +
 src/i830_crt.c     |   95 ++++++++++++++++++++++++++++++++++-------------------
 src/i830_display.c |    1 
 src/i830_driver.c  |   10 +++++
 5 files changed, 79 insertions(+), 33 deletions(-)

New commits:
diff-tree b31bef1a8effa9acb6de7edd206b9d8c48d88144 (from 3b769af53e0ef6ef9b56afd679446c73a0e63ea5)
Author: Keith Packard <keithp at work.jf.intel.com>
Date:   Sat May 12 20:04:31 2007 -0700

    Deal with i830 CRT load detection which cannot use FORCE_BORDER.
    
    Chips newer than the i830 can force the border color for the active period
    of the screen, allowing the load detection to easily see the right data. In
    addition, newer chips appear to have more sensible load detection hardware
    which either ignores inactive periods on the screen or performs some
    longer-term averaging. The i830 appears to provide unfiltered samples of the
    detected load.
    
    For the i830, then, emit a border at the bottom of the screen and, for load
    detection, simply turn it purple and wait for the current line to be within
    the border. Sample an entire scanline, counting the number of times the load
    detection sees a monitor. In my testing, the presence of a monitor will
    cause the detection to succeed every time, while the absense will cause it
    to fail about 75% of the time. The code here, checks for presence at least
    75% of the time, which should be adequate.
    
    Also, as the new mode configuration code has already taken care to enable
    the CRT output, eliminate much of the load detection code which is simply
    duplicating functionality from the general mode setting code. This should
    result in faster load detection as this code will now run in no more than
    one frame time. It does burn the CPU the whole time though, polling the
    displayed scanline register.

diff --git a/src/i810_reg.h b/src/i810_reg.h
index c3db5c9..234d124 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -1938,6 +1938,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 #define TV_V_CHROMA_42		0x684a8
 /** @} */
 
+#define PIPEA_DSL		0x70000
+
 #define PIPEACONF 0x70008
 #define PIPEACONF_ENABLE	(1<<31)
 #define PIPEACONF_DISABLE	0
@@ -1966,6 +1968,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 #define PIPEAFRAMEPIXEL		0x70044
 
 
+#define PIPEB_DSL		0x71000
+
 #define PIPEBCONF 0x71008
 #define PIPEBCONF_ENABLE	(1<<31)
 #define PIPEBCONF_DISABLE	0
diff --git a/src/i830.h b/src/i830.h
index 7b0ab15..c91be79 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -489,6 +489,7 @@ typedef struct _I830Rec {
    CARD32 saveVTOTAL_A;
    CARD32 saveVBLANK_A;
    CARD32 saveVSYNC_A;
+   CARD32 saveBCLRPAT_A;
    CARD32 saveDSPASTRIDE;
    CARD32 saveDSPASIZE;
    CARD32 saveDSPAPOS;
@@ -504,6 +505,7 @@ typedef struct _I830Rec {
    CARD32 saveVTOTAL_B;
    CARD32 saveVBLANK_B;
    CARD32 saveVSYNC_B;
+   CARD32 saveBCLRPAT_B;
    CARD32 saveDSPBSTRIDE;
    CARD32 saveDSPBSIZE;
    CARD32 saveDSPBPOS;
diff --git a/src/i830_crt.c b/src/i830_crt.c
index fbb4adc..879ae9f 100644
--- a/src/i830_crt.c
+++ b/src/i830_crt.c
@@ -97,6 +97,8 @@ static Bool
 i830_crt_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		    DisplayModePtr adjusted_mode)
 {
+    /* disable blanking so we can detect monitors */
+    adjusted_mode->CrtcVBlankStart = adjusted_mode->CrtcVTotal - 3;
     return TRUE;
 }
 
@@ -106,7 +108,7 @@ i830_crt_mode_set(xf86OutputPtr output, 
 {
     ScrnInfoPtr		    pScrn = output->scrn;
     I830Ptr		    pI830 = I830PTR(pScrn);
-    xf86CrtcPtr	    crtc = output->crtc;
+    xf86CrtcPtr		    crtc = output->crtc;
     I830CrtcPrivatePtr	    i830_crtc = crtc->driver_private;
     int			    dpll_md_reg;
     CARD32		    adpa, dpll_md;
@@ -132,9 +134,15 @@ i830_crt_mode_set(xf86OutputPtr output, 
 	adpa |= ADPA_VSYNC_ACTIVE_HIGH;
 
     if (i830_crtc->pipe == 0)
+    {
 	adpa |= ADPA_PIPE_A_SELECT;
+	OUTREG(BCLRPAT_A, 0);
+    }
     else
+    {
 	adpa |= ADPA_PIPE_B_SELECT;
+	OUTREG(BCLRPAT_B, 0);
+    }
 
     OUTREG(ADPA, adpa);
 }
@@ -193,58 +201,79 @@ i830_crt_detect_load (xf86CrtcPtr	    cr
     ScrnInfoPtr		    pScrn = output->scrn;
     I830Ptr		    pI830 = I830PTR(pScrn);
     I830CrtcPrivatePtr	    i830_crtc = I830CrtcPrivate(crtc);
-    CARD32		    save_adpa, adpa, pipeconf, bclrpat;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    CARD32		    save_bclrpat;
+    CARD32		    save_vtotal;
+    CARD32		    vtotal, vactive;
+    CARD32		    vsample;
+    CARD32		    dsl;
     CARD8		    st00;
-    int			    pipeconf_reg, bclrpat_reg, dpll_reg;
+    int			    bclrpat_reg, pipeconf_reg, pipe_dsl_reg;
+    int			    vtotal_reg;
     int			    pipe = i830_crtc->pipe;
+    int			    count, detect;
+    Bool		    present;
 
     if (pipe == 0) 
     {
 	bclrpat_reg = BCLRPAT_A;
+	vtotal_reg = VTOTAL_A;
 	pipeconf_reg = PIPEACONF;
-	dpll_reg = DPLL_A;
+	pipe_dsl_reg = PIPEA_DSL;
     }
     else 
     {
 	bclrpat_reg = BCLRPAT_B;
+	vtotal_reg = VTOTAL_B;
 	pipeconf_reg = PIPEBCONF;
-	dpll_reg = DPLL_B;
+	pipe_dsl_reg = PIPEB_DSL;
     }
 
-    adpa = INREG(ADPA);
-    save_adpa = adpa;
+    save_bclrpat = INREG(bclrpat_reg);
+    save_vtotal = INREG(vtotal_reg);
 
-    /* Enable CRT output. */
-    adpa |= ADPA_DAC_ENABLE;
-    if (pipe == 1)
- 	adpa |= ADPA_PIPE_B_SELECT;
-    else
- 	adpa &= ~ADPA_PIPE_B_SELECT;
-    adpa |= ADPA_VSYNC_CNTL_ENABLE | ADPA_HSYNC_CNTL_ENABLE;
-    OUTREG(ADPA, adpa);
+    vtotal = (save_vtotal >> 16) & 0xfff;
+    vactive = save_vtotal & 0x7ff;
+    
+    /* sample the middle of the blanking interval */
+    vsample = ((vtotal - 3) + (vactive)) >> 1;
 
     /* Set the border color to purple. */
-    bclrpat = INREG(bclrpat_reg);
-    OUTREG(bclrpat_reg, 0x00500050);
-
-    i830WaitForVblank(pScrn);
-
-    /* Force the border color through the active region */
-    pipeconf = INREG(pipeconf_reg);
-    OUTREG(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
-
-    /* Read the ST00 VGA status register */
-    st00 = pI830->readStandard(pI830, 0x3c2);
+    OUTREG(bclrpat_reg, 0x500050);
+    
+    /*
+     * Wait for the border to be displayed
+     */
+    while (INREG(pipe_dsl_reg) >= vactive)
+	;
+    while ((dsl = INREG(pipe_dsl_reg)) <= vsample)
+	;
+    /*
+     * Watch ST00 for an entire scanline
+     */
+    detect = 0;
+    count = 0;
+    do {
+	count++;
+	/* Read the ST00 VGA status register */
+	st00 = pI830->readStandard(pI830, 0x3c2);
+	if (st00 & (1 << 4))
+	    detect++;
+    } while ((INREG(pipe_dsl_reg) == dsl));
 
     /* Restore previous settings */
-    OUTREG(bclrpat_reg, bclrpat);
-    OUTREG(pipeconf_reg, pipeconf);
-    OUTREG(ADPA, save_adpa);
+    OUTREG(bclrpat_reg, save_bclrpat);
 
-    if (st00 & (1 << 4))
-	return TRUE;
-    else
-	return FALSE;
+    /*
+     * If more than 3/4 of the scanline detected a monitor,
+     * then it is assumed to be present. This works even on i830,
+     * where there isn't any way to force the border color across
+     * the screen
+     */
+    present = detect * 4 > count * 3;
+    xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "present: %s (%d of %d) at %ld desired %ld temp %d\n",
+		present ? "TRUE" : "FALSE", detect, count, dsl, vsample, intel_output->load_detect_temp);
+    return present;
 }
 
 /**
diff --git a/src/i830_display.c b/src/i830_display.c
index 727d1b2..4b205ba 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1255,6 +1255,7 @@ i830ReleaseLoadDetectPipe(xf86OutputPtr 
     
     if (intel_output->load_detect_temp) 
     {
+	output->crtc->enabled = FALSE;
 	output->crtc = NULL;
 	intel_output->load_detect_temp = FALSE;
 	xf86DisableUnusedFunctions(pScrn);
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 1d8b7f8..b4d9d08 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -744,6 +744,12 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
 	 break;
       case I830_OUTPUT_ANALOG:
 	 crtc_mask = ((1 << 0));
+	 /*
+	  * 915 cannot do double-wide on pipe B
+	  * 830 cannot put CRT on pipe B
+	  */
+	 if (!IS_I915G(pI830) && !IS_I915GM (pI830) && !IS_I830(pI830))
+	    crtc_mask |= ((1 << 1));
 	 clone_mask = ((1 << I830_OUTPUT_ANALOG) |
 		       (1 << I830_OUTPUT_DVO) |
 		       (1 << I830_OUTPUT_SDVO));
@@ -1735,6 +1741,7 @@ SaveHWState(ScrnInfoPtr pScrn)
    pI830->saveVTOTAL_A = INREG(VTOTAL_A);
    pI830->saveVBLANK_A = INREG(VBLANK_A);
    pI830->saveVSYNC_A = INREG(VSYNC_A);
+   pI830->saveBCLRPAT_A = INREG(BCLRPAT_A);
    pI830->saveDSPASTRIDE = INREG(DSPASTRIDE);
    pI830->saveDSPASIZE = INREG(DSPASIZE);
    pI830->saveDSPAPOS = INREG(DSPAPOS);
@@ -1759,6 +1766,7 @@ SaveHWState(ScrnInfoPtr pScrn)
       pI830->saveVTOTAL_B = INREG(VTOTAL_B);
       pI830->saveVBLANK_B = INREG(VBLANK_B);
       pI830->saveVSYNC_B = INREG(VSYNC_B);
+      pI830->saveBCLRPAT_B = INREG(BCLRPAT_B);
       pI830->saveDSPBSTRIDE = INREG(DSPBSTRIDE);
       pI830->saveDSPBSIZE = INREG(DSPBSIZE);
       pI830->saveDSPBPOS = INREG(DSPBPOS);
@@ -1857,6 +1865,7 @@ RestoreHWState(ScrnInfoPtr pScrn)
    OUTREG(VTOTAL_A, pI830->saveVTOTAL_A);
    OUTREG(VBLANK_A, pI830->saveVBLANK_A);
    OUTREG(VSYNC_A, pI830->saveVSYNC_A);
+   OUTREG(BCLRPAT_A, pI830->saveBCLRPAT_A);
    
    OUTREG(DSPASTRIDE, pI830->saveDSPASTRIDE);
    OUTREG(DSPASIZE, pI830->saveDSPASIZE);
@@ -1894,6 +1903,7 @@ RestoreHWState(ScrnInfoPtr pScrn)
       OUTREG(VTOTAL_B, pI830->saveVTOTAL_B);
       OUTREG(VBLANK_B, pI830->saveVBLANK_B);
       OUTREG(VSYNC_B, pI830->saveVSYNC_B);
+      OUTREG(BCLRPAT_B, pI830->saveBCLRPAT_B);
       OUTREG(DSPBSTRIDE, pI830->saveDSPBSTRIDE);
       OUTREG(DSPBSIZE, pI830->saveDSPBSIZE);
       OUTREG(DSPBPOS, pI830->saveDSPBPOS);


More information about the xorg-commit mailing list