[Intel-gfx] [PATCH]DRM/IGD: Support IGD EOS - takes 2

Shaohua Li shaohua.li at intel.com
Mon Sep 7 09:43:20 CEST 2009


On Sat, Sep 05, 2009 at 03:40:44AM +0800, Eric Anholt wrote:
> On Fri, 2009-09-04 at 13:09 +0800, Shaohua Li wrote:
> > In the event that any one of the DAC analog outputs (R,G,B) were driven
> > at full-scale (white video) or some analog level close to full-scale
> > voltage, and if the video cable were then disconnected, the analog video
> > voltage level would exceed the maximum electrical overstress limit of the
> > native (thin-oxide) transistors thus causing a long-term reliability concern.
> > The electrical overstress condition occurs in this particular case.
> > 
> > This patch address the IGD EOS (electrical overstress condition) issue.
> > When the EOS interrupt occurs, OS should disable DAC and then disable EOS,
> > then the normal hotplug operation follows.
> > 
> > Signed-off-by: Shaohua Li <shaohua.li at intel.com>
> 
> The patch was already applied to -next, please supply updates in the
> form of patches.

Spec slightly changes the way to handle IGD EOS. This patch makes our driver
align to latest spec.

Signed-off-by: Shaohua Li <shaohua.li at intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h  |    1 
 drivers/gpu/drm/i915/i915_irq.c  |   37 ++++++++++----------------
 drivers/gpu/drm/i915/intel_crt.c |   54 ++++++++++++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_drv.h |    1 
 4 files changed, 65 insertions(+), 28 deletions(-)

Index: linux/drivers/gpu/drm/i915/i915_drv.h
===================================================================
--- linux.orig/drivers/gpu/drm/i915/i915_drv.h	2009-09-07 15:16:44.000000000 +0800
+++ linux/drivers/gpu/drm/i915/i915_drv.h	2009-09-07 15:17:40.000000000 +0800
@@ -189,6 +189,7 @@ typedef struct drm_i915_private {
 	u32 de_irq_enable_reg;
 
 	u32 hotplug_supported_mask;
+	u32 hotplug_status;
 	struct work_struct hotplug_work;
 
 	int tex_lru_log_granularity;
Index: linux/drivers/gpu/drm/i915/i915_irq.c
===================================================================
--- linux.orig/drivers/gpu/drm/i915/i915_irq.c	2009-09-07 15:16:15.000000000 +0800
+++ linux/drivers/gpu/drm/i915/i915_irq.c	2009-09-07 15:30:04.000000000 +0800
@@ -237,6 +237,11 @@ static void i915_hotplug_work_func(struc
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct drm_connector *connector;
 
+	intel_igd_handle_eos(dev, dev_priv->hotplug_status);
+
+	if (!(dev_priv->hotplug_status & dev_priv->hotplug_supported_mask))
+		return;
+
 	if (mode_config->num_connector) {
 		list_for_each_entry(connector, &mode_config->connector_list, head) {
 			struct intel_output *intel_output = to_intel_output(connector);
@@ -557,35 +562,16 @@ irqreturn_t i915_driver_irq_handler(DRM_
 		    (iir & I915_DISPLAY_PORT_INTERRUPT)) {
 			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
 
+			dev_priv->hotplug_status = hotplug_status;
 			DRM_DEBUG("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
-			if (hotplug_status & dev_priv->hotplug_supported_mask)
+			if ((hotplug_status & dev_priv->hotplug_supported_mask) ||
+			   (IS_IGD(dev) && (hotplug_status & CRT_EOS_INT_STATUS)))
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
-
-			/* EOS interrupts occurs */
-			if (IS_IGD(dev) &&
-				(hotplug_status & CRT_EOS_INT_STATUS)) {
-				u32 temp;
-
-				DRM_DEBUG("EOS interrupt occurs\n");
-				/* status is already cleared */
-				temp = I915_READ(ADPA);
-				temp &= ~ADPA_DAC_ENABLE;
-				I915_WRITE(ADPA, temp);
-
-				temp = I915_READ(PORT_HOTPLUG_EN);
-				temp &= ~CRT_EOS_INT_EN;
-				I915_WRITE(PORT_HOTPLUG_EN, temp);
-
-				temp = I915_READ(PORT_HOTPLUG_STAT);
-				if (temp & CRT_EOS_INT_STATUS)
-					I915_WRITE(PORT_HOTPLUG_STAT,
-						CRT_EOS_INT_STATUS);
-			}
 		}
 
 		I915_WRITE(IIR, iir);
@@ -981,6 +967,13 @@ int i915_driver_irq_postinstall(struct d
 		hotplug_en |= HOTPLUG_EN_MASK;
 		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 
+		/*
+		 * The pipe select needs to be 1 when CRT Hot plug Interrupt
+		 * Detection Enable is set when DAC is off under IGD
+		 */
+		if (IS_IGD(dev))
+			I915_WRITE(ADPA, I915_READ(ADPA) | ADPA_PIPE_B_SELECT);
+
 		dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS |
 			TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS |
 			SDVOB_HOTPLUG_INT_STATUS;
Index: linux/drivers/gpu/drm/i915/intel_crt.c
===================================================================
--- linux.orig/drivers/gpu/drm/i915/intel_crt.c	2009-09-07 15:15:16.000000000 +0800
+++ linux/drivers/gpu/drm/i915/intel_crt.c	2009-09-07 15:30:31.000000000 +0800
@@ -60,6 +60,13 @@ static void intel_crt_dpms(struct drm_en
 		break;
 	case DRM_MODE_DPMS_OFF:
 		temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
+
+		/*
+		 * The pipe select needs to be 1 when CRT Hot plug Interrupt
+		 * Detection Enable is set when DAC is off under IGD
+		 */
+		if (IS_IGD(dev))
+			temp |= ADPA_PIPE_B_SELECT;
 		break;
 	}
 
@@ -162,6 +169,7 @@ static void intel_crt_mode_set(struct dr
 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
 		adpa |= ADPA_VSYNC_ACTIVE_HIGH;
 
+	adpa &= ~ADPA_PIPE_B_SELECT;
 	if (intel_crtc->pipe == 0) {
 		adpa |= ADPA_PIPE_A_SELECT;
 		if (!IS_IGDNG(dev))
@@ -175,9 +183,8 @@ static void intel_crt_mode_set(struct dr
 	I915_WRITE(adpa_reg, adpa);
 }
 
-static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
+static bool intel_igdng_crt_detect_hotplug(struct drm_device *dev)
 {
-	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 adpa, temp;
 	bool ret;
@@ -225,15 +232,14 @@ static bool intel_igdng_crt_detect_hotpl
  * \return true if CRT is connected.
  * \return false if CRT is disconnected.
  */
-static bool intel_crt_detect_hotplug(struct drm_connector *connector)
+static bool intel_crt_detect_hotplug(struct drm_device *dev)
 {
-	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 hotplug_en;
 	int i, tries = 0;
 
 	if (IS_IGDNG(dev))
-		return intel_igdng_crt_detect_hotplug(connector);
+		return intel_igdng_crt_detect_hotplug(dev);
 
 	/*
 	 * On 4 series desktop, CRT detect sequence need to be done twice
@@ -274,6 +280,42 @@ static bool intel_crt_detect_hotplug(str
 	return false;
 }
 
+void intel_igd_handle_eos(struct drm_device *dev, u32 hotplug_status)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 temp;
+	bool connected;
+
+	/* EOS interrupts occurs */
+	if (IS_IGD(dev) && (hotplug_status & CRT_EOS_INT_STATUS)) {
+		mutex_lock(&dev->mode_config.mutex);
+		connected = intel_crt_detect_hotplug(dev);
+		DRM_DEBUG("EOS interrupt occurs, VGA is %s\n",
+				connected ? "connected":"disconnected");
+
+		temp = I915_READ(PORT_HOTPLUG_STAT);
+		if (temp & CRT_EOS_INT_STATUS)
+			I915_WRITE(PORT_HOTPLUG_STAT, CRT_EOS_INT_STATUS);
+		if (connected) {
+			mutex_unlock(&dev->mode_config.mutex);
+			return;
+		}
+
+		temp = I915_READ(ADPA);
+		temp &= ~ADPA_DAC_ENABLE;
+		I915_WRITE(ADPA, temp);
+
+		temp = I915_READ(PORT_HOTPLUG_EN);
+		temp &= ~CRT_EOS_INT_EN;
+		I915_WRITE(PORT_HOTPLUG_EN, temp);
+
+		temp = I915_READ(PORT_HOTPLUG_STAT);
+		if (temp & CRT_EOS_INT_STATUS)
+			I915_WRITE(PORT_HOTPLUG_STAT, CRT_EOS_INT_STATUS);
+		mutex_unlock(&dev->mode_config.mutex);
+	}
+}
+
 static bool intel_crt_detect_ddc(struct drm_connector *connector)
 {
 	struct intel_output *intel_output = to_intel_output(connector);
@@ -423,7 +465,7 @@ static enum drm_connector_status intel_c
 	enum drm_connector_status status;
 
 	if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
-		if (intel_crt_detect_hotplug(connector))
+		if (intel_crt_detect_hotplug(dev))
 			return connector_status_connected;
 		else
 			return connector_status_disconnected;
Index: linux/drivers/gpu/drm/i915/intel_drv.h
===================================================================
--- linux.orig/drivers/gpu/drm/i915/intel_drv.h	2009-09-07 15:16:02.000000000 +0800
+++ linux/drivers/gpu/drm/i915/intel_drv.h	2009-09-07 15:18:08.000000000 +0800
@@ -181,4 +181,5 @@ extern int intel_framebuffer_create(stru
 				    struct drm_mode_fb_cmd *mode_cmd,
 				    struct drm_framebuffer **fb,
 				    struct drm_gem_object *obj);
+extern void intel_igd_handle_eos(struct drm_device *dev, u32 hotplug_status);
 #endif /* __INTEL_DRV_H__ */



More information about the Intel-gfx mailing list