[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