===================================================================
@@ -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;
===================================================================
@@ -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;
===================================================================
@@ -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;
===================================================================
@@ -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__ */