i915: TV hotplug fixes
In order to avoid recursive ->detect->interrupt->detect->interrupt->... we need to disable TV hotplug interrupts in intel_tv.c:intel_tv_detect_type. We also need to enable the TV interrupt detection and hotplug sequence properly in i915_irq.c.main
parent
a51e38548c
commit
d32ce7f621
|
@ -1360,11 +1360,21 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)
|
|||
struct drm_device *dev = output->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_output *intel_output = output->driver_private;
|
||||
u32 pipeastat, pipeastat_save;
|
||||
u32 tv_ctl, save_tv_ctl;
|
||||
u32 tv_dac, save_tv_dac;
|
||||
int type = ConnectorUnknown;
|
||||
|
||||
tv_dac = I915_READ(TV_DAC);
|
||||
|
||||
/* Disable TV interrupts around load detect or we'll recurse */
|
||||
pipeastat = I915_READ(I915REG_PIPEASTAT);
|
||||
pipeastat_save = pipeastat;
|
||||
pipeastat &= ~I915_HOTPLUG_INTERRUPT_ENABLE;
|
||||
pipeastat &= ~I915_HOTPLUG_TV_INTERRUPT_ENABLE;
|
||||
I915_WRITE(I915REG_PIPEASTAT, pipeastat | I915_HOTPLUG_TV_CLEAR |
|
||||
I915_HOTPLUG_CLEAR);
|
||||
|
||||
/*
|
||||
* Detect TV by polling)
|
||||
*/
|
||||
|
@ -1412,6 +1422,10 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)
|
|||
type = -1;
|
||||
}
|
||||
|
||||
/* Restore interrupt config */
|
||||
I915_WRITE(I915REG_PIPEASTAT, pipeastat_save | I915_HOTPLUG_TV_CLEAR |
|
||||
I915_HOTPLUG_CLEAR);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -1434,10 +1448,15 @@ intel_tv_detect(struct drm_output *output)
|
|||
mode = reported_modes[0];
|
||||
drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
|
||||
|
||||
if (output->crtc) {
|
||||
type = intel_tv_detect_type(output->crtc, output);
|
||||
} else {
|
||||
crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode);
|
||||
if (crtc) {
|
||||
type = intel_tv_detect_type(crtc, output);
|
||||
intel_release_load_detect_pipe(output, dpms_mode);
|
||||
} else
|
||||
type = -1;
|
||||
}
|
||||
|
||||
if (type != tv_priv->type) {
|
||||
|
|
|
@ -471,7 +471,6 @@ static void i915_hotplug_tv(struct drm_device *dev)
|
|||
if (iout == 0)
|
||||
goto unlock;
|
||||
|
||||
/* may need to I915_WRITE(TVDAC, 1<<31) to ack the interrupt */
|
||||
status = output->funcs->detect(output);
|
||||
drm_hotplug_stage_two(dev, output,
|
||||
status == output_status_connected ? 1 : 0);
|
||||
|
@ -631,7 +630,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
struct drm_i915_master_private *master_priv;
|
||||
struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
|
||||
u32 iir;
|
||||
u32 pipea_stats, pipeb_stats;
|
||||
u32 pipea_stats = 0, pipeb_stats, tvdac;
|
||||
int hotplug = 0;
|
||||
int vblank = 0;
|
||||
|
||||
|
@ -672,10 +671,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
}
|
||||
|
||||
/* This is a global event, and not a pipe A event */
|
||||
if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) ||
|
||||
(pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS))
|
||||
if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS)
|
||||
hotplug = 1;
|
||||
|
||||
if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) {
|
||||
hotplug = 1;
|
||||
/* Toggle hotplug detection to clear hotplug status */
|
||||
tvdac = I915_READ(TV_DAC);
|
||||
I915_WRITE(TV_DAC, tvdac & ~TVDAC_STATE_CHG_EN);
|
||||
I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN);
|
||||
}
|
||||
|
||||
I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
|
||||
}
|
||||
|
||||
|
@ -1001,6 +1007,9 @@ void i915_enable_interrupt (struct drm_device *dev)
|
|||
|
||||
I915_WRITE(SDVOB, I915_READ(SDVOB) | SDVO_INTERRUPT_ENABLE);
|
||||
I915_WRITE(SDVOC, I915_READ(SDVOC) | SDVO_INTERRUPT_ENABLE);
|
||||
|
||||
/* TV */
|
||||
I915_WRITE(TV_DAC, I915_READ(TV_DAC) | TVDAC_STATE_CHG_EN);
|
||||
} else {
|
||||
/* DVO ???? */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue