From patchwork Fri Sep 4 05:09:23 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaohua Li X-Patchwork-Id: 45514 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n8459Q6h021377 for ; Fri, 4 Sep 2009 05:09:26 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 834669EAF5; Thu, 3 Sep 2009 22:09:26 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga03.intel.com (mga03.intel.com [143.182.124.21]) by gabe.freedesktop.org (Postfix) with ESMTP id 73FD49E9FB for ; Thu, 3 Sep 2009 22:09:25 -0700 (PDT) Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga101.ch.intel.com with ESMTP; 03 Sep 2009 22:09:24 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.44,271,1249282800"; d="scan'208";a="184000646" Received: from sli10-conroe.sh.intel.com (HELO sli10-desk.sh.intel.com) ([10.239.13.175]) by azsmga001.ch.intel.com with ESMTP; 03 Sep 2009 22:09:23 -0700 Received: from david by sli10-desk.sh.intel.com with local (Exim 4.69) (envelope-from ) id 1MjR35-0004C5-58; Fri, 04 Sep 2009 13:09:23 +0800 Date: Fri, 4 Sep 2009 13:09:23 +0800 From: Shaohua Li To: intel-gfx@lists.freedesktop.org Message-ID: <20090904050923.GA15129@sli10-desk.sh.intel.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) Cc: peng.li@intel.com Subject: [Intel-gfx] [PATCH]DRM/IGD: Support IGD EOS - takes 2 X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org 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 --- drivers/gpu/drm/i915/i915_drv.h | 1 drivers/gpu/drm/i915/i915_irq.c | 16 +++++++ drivers/gpu/drm/i915/i915_reg.h | 2 drivers/gpu/drm/i915/intel_crt.c | 83 ++++++++++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 1 5 files changed, 96 insertions(+), 7 deletions(-) Index: linux/drivers/gpu/drm/i915/i915_reg.h =================================================================== --- linux.orig/drivers/gpu/drm/i915/i915_reg.h 2009-09-03 13:58:41.000000000 +0800 +++ linux/drivers/gpu/drm/i915/i915_reg.h 2009-09-03 14:01:10.000000000 +0800 @@ -683,6 +683,7 @@ #define SDVOB_HOTPLUG_INT_EN (1 << 26) #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) +#define CRT_EOS_INT_EN (1 << 10) #define CRT_HOTPLUG_INT_EN (1 << 9) #define CRT_HOTPLUG_FORCE_DETECT (1 << 3) #define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8) @@ -717,6 +718,7 @@ #define DPC_HOTPLUG_INT_STATUS (1 << 28) #define HDMID_HOTPLUG_INT_STATUS (1 << 27) #define DPD_HOTPLUG_INT_STATUS (1 << 27) +#define CRT_EOS_INT_STATUS (1 << 12) #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) #define CRT_HOTPLUG_MONITOR_MASK (3 << 8) Index: linux/drivers/gpu/drm/i915/i915_irq.c =================================================================== --- linux.orig/drivers/gpu/drm/i915/i915_irq.c 2009-09-03 13:58:41.000000000 +0800 +++ linux/drivers/gpu/drm/i915/i915_irq.c 2009-09-03 14:01:10.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,9 +562,11 @@ 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); @@ -960,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-03 13:58:41.000000000 +0800 +++ linux/drivers/gpu/drm/i915/intel_crt.c 2009-09-03 14:15:44.000000000 +0800 @@ -60,10 +60,45 @@ 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; } I915_WRITE(reg, temp); + + if (IS_IGD(dev)) { + if (mode == DRM_MODE_DPMS_OFF) { + /* turn off DAC */ + 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); + } else { + /* turn on DAC. EOS interrupt must be enabled after DAC + * is enabled, so it sounds not good to enable it in + * i915_driver_irq_postinstall() + * wait 12.5ms after DAC is enabled + */ + msleep(13); + temp = I915_READ(PORT_HOTPLUG_STAT); + if (temp & CRT_EOS_INT_STATUS) + I915_WRITE(PORT_HOTPLUG_STAT, + CRT_EOS_INT_STATUS); + temp = I915_READ(PORT_HOTPLUG_EN); + temp |= CRT_EOS_INT_EN; + I915_WRITE(PORT_HOTPLUG_EN, temp); + } + } } static int intel_crt_mode_valid(struct drm_connector *connector, @@ -134,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)) @@ -147,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; @@ -197,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 @@ -246,6 +280,43 @@ 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); @@ -395,7 +466,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-03 13:58:41.000000000 +0800 +++ linux/drivers/gpu/drm/i915/intel_drv.h 2009-09-03 14:01:10.000000000 +0800 @@ -177,4 +177,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__ */ Index: linux/drivers/gpu/drm/i915/i915_drv.h =================================================================== --- linux.orig/drivers/gpu/drm/i915/i915_drv.h 2009-09-03 13:58:41.000000000 +0800 +++ linux/drivers/gpu/drm/i915/i915_drv.h 2009-09-03 14:01:10.000000000 +0800 @@ -190,6 +190,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;