[Intel-gfx] [PATCH]DRM/IGD: Support IGD EOS - takes 2
Eric Anholt
eric at anholt.net
Fri Sep 4 21:40:44 CEST 2009
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.
> ---
> 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;
--
Eric Anholt
eric at anholt.net eric.anholt at intel.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: This is a digitally signed message part
URL: <http://lists.freedesktop.org/archives/intel-gfx/attachments/20090904/2009c899/attachment.sig>
More information about the Intel-gfx
mailing list