Subject: Patch DRM/I915: Add the load-detection for crt detect
From: Zhao Yakui <yakui.z...@intel.com>
 
    Add the load-detection for crt detect

Signed-off-by: Zhao Yakui <yakui.z...@intel.com>
---
 drivers/gpu/drm/i915/intel_crt.c |  136 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 133 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-03 
18:01:04.000000000 +0800
+++ linux-2.6/drivers/gpu/drm/i915/intel_crt.c  2009-03-03 18:01:12.000000000 
+0800
@@ -217,9 +217,120 @@
        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 *drm_dev = encoder->dev;
+       struct drm_i915_private *dev_priv = drm_dev->dev_private;
+       u32     save_bclrpat, save_vtotal, vtotal, vactive, vsample, vblank,
+               vblank_start, vblank_end, dsl;
+       u8      st00;
+       int     bclrpat_reg, pipeconf_reg, pipe_dsl_reg, vtotal_reg,
+               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(drm_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))
@@ -228,11 +339,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)



------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to