[Intel-gfx] [Patch 4/5]: DRM/I915: Add the load-detection for crt detect

yakui_zhao yakui.zhao at intel.com
Mon Mar 9 03:32:15 CET 2009


The following is the updated patch.
 
    This covers:
    Add the load-detection for CRT detect
    And when it fails in DDC CRT detection, the load-detection will be
used.

Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>
---
 drivers/gpu/drm/i915/intel_crt.c |  140
++++++++++++++++++++++++++++++++++++++-
 1 file changed, 137 insertions(+), 3 deletions(-)

Index: linux-2.6/drivers/gpu/drm/i915/intel_crt.c
===================================================================
--- linux-2.6.orig/drivers/gpu/drm/i915/intel_crt.c	2009-03-09
09:53:33.000000000 +0800
+++ linux-2.6/drivers/gpu/drm/i915/intel_crt.c	2009-03-09
10:14:23.000000000 +0800
@@ -198,9 +198,124 @@
 	return intel_ddc_probe(intel_output);
 }
 
+/*
+ * Detects CRT presence by checking for load.
+ *
+ * Requires that the current pipe's DPLL is active.  This will cause
flicker
+ * on the CRT, so it should not be used while the display is being
used.  Only
+ * color (not monochrome) displays are detected.
+ *
+ * return TRUE if CRT is connected.
+ * return FALSE if CRT is disconnected.
+ */
+static bool intel_crt_detect_load(struct intel_crtc *intel_crtc,
+					struct intel_output *intel_output)
+{
+	struct drm_encoder *encoder = &intel_output->enc;
+	struct drm_device *dev = encoder->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32	save_bclrpat, save_vtotal, vtotal, vactive, vsample, vblank;
+	u32	vblank_start, vblank_end, dsl;
+	u8	st00;
+	int	bclrpat_reg, pipeconf_reg, pipe_dsl_reg, vtotal_reg;
+	u32	vblank_reg, vsync_reg, pipe;
+	bool	present;
+
+	pipe = intel_crtc->pipe;
+	if (pipe == 0) {
+		bclrpat_reg = BCLRPAT_A;
+		vtotal_reg = VTOTAL_A;
+		vblank_reg = VBLANK_A;
+		vsync_reg = VSYNC_A;
+		pipeconf_reg = PIPEACONF;
+		pipe_dsl_reg = PIPEADSL;
+	} else {
+		bclrpat_reg = BCLRPAT_B;
+		vtotal_reg = VTOTAL_B;
+		vblank_reg = VBLANK_B;
+		vsync_reg = VSYNC_B;
+		pipeconf_reg = PIPEBCONF;
+		pipe_dsl_reg = PIPEBDSL;
+	}
+	save_bclrpat = I915_READ(bclrpat_reg);
+	save_vtotal = I915_READ(vtotal_reg);
+	vblank = I915_READ(vblank_reg);
+
+	vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
+	vactive = (save_vtotal & 0x7ff) + 1;
+
+	vblank_start = (vblank & 0xfff) + 1;
+	vblank_end = ((vblank >> 16) & 0xfff) + 1;
+
+	/* Set the border color to purple. */
+	I915_WRITE(bclrpat_reg, 0x500050);
+	if (IS_I9XX(dev)) {
+		u32 pipeconf = I915_READ(pipeconf_reg);
+		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
+		st00 = I915_READ8(VGA_MSR_WRITE);
+		present = (st00 & (1 << 4)) != 0;
+		I915_WRITE(pipeconf_reg, pipeconf);
+	} else {
+		bool restore_vblank = false;
+		int count, detect;
+
+		/*
+		 * If there isn't any border, add some.
+		 * Yes, this will flicker
+		 */
+		if (vblank_start <= vactive && vblank_end >= vtotal) {
+			u32 vsync = I915_READ(vsync_reg);
+			u32 vsync_start = (vsync & 0xffff) + 1;
+			vblank_start = vsync_start;
+			I915_WRITE(vblank_reg, (vblank_start - 1) |
+					((vblank_end - 1) << 16));
+			restore_vblank = true;
+		}
+		/* sample in the vertical border, setting the larger one */
+		if ((vblank_start - vactive) >= (vtotal - vblank_end))
+			vsample = (vblank_start + vactive) >> 1;
+		else
+			vsample = (vtotal + vblank_end) >> 1;
+		/* wait for the border to be displayed */
+		while (I915_READ(pipe_dsl_reg) >= vactive)
+			;
+		while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample)
+			;
+		/* watch St00 for entire scanline */
+		detect = 0;
+		count = 0;
+		do {
+			count++;
+			/* read the ST00 VGA status register */
+			st00 = I915_READ8(VGA_MSR_WRITE);
+			if (st00 & (1 << 4))
+				detect++;
+		} while ((I915_READ(pipe_dsl_reg) == dsl));
+		/* restore the vblank if necessary */
+		if (restore_vblank)
+			I915_WRITE(vblank_reg, vblank);
+		/*
+		 * if more than 3/4 of the scanline detected the monitor, it
+		 * assumed to be present. This works event on i830, where
+		 * there isn't any way to force the border color accross the
+		 * screen
+		 */
+		present = detect * 4 > count * 3;
+	}
+
+	/* Restore previous settings */
+	I915_WRITE(bclrpat_reg, save_bclrpat);
+	return present;
+}
+
 static enum drm_connector_status intel_crt_detect(struct drm_connector
*connector)
 {
 	struct drm_device *dev = connector->dev;
+	struct drm_crtc *drm_crtc;
+	struct intel_crtc *intel_crtc;
+	struct intel_output *intel_output;
+	enum drm_connector_status status;
+	int dpms_mode;
 
 	if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
 		if (intel_crt_detect_hotplug(connector))
@@ -209,11 +324,30 @@
 			return connector_status_disconnected;
 	}
 
-	if (intel_crt_detect_ddc(connector))
-		return connector_status_connected;
+	intel_output = to_intel_output(connector);
+	drm_crtc = intel_get_load_detect_pipe(intel_output,
+			NULL, &dpms_mode);
+	intel_crtc = to_intel_crtc(drm_crtc);
+	if (!intel_crtc) {
+			status = connector_status_unknown;
+			goto done;
+	}
+
+	if (intel_crt_detect_ddc(connector)) {
+		status = connector_status_connected;
+		goto out_release_pipe;
+	}
 
 	/* TODO use load detect */
-	return connector_status_unknown;
+	if (intel_crt_detect_load(intel_crtc, intel_output))
+		status = connector_status_connected;
+	else
+		status = connector_status_disconnected;
+
+out_release_pipe:
+	intel_release_load_detect_pipe(intel_output, dpms_mode);
+done:
+	return status;
 }
 
 static void intel_crt_destroy(struct drm_connector *connector)





More information about the Intel-gfx mailing list