aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2013-03-27 10:55:01 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-03-27 12:10:44 -0400
commit82a28bcf5606ef1e9f527e9750cf9f44b0986de7 (patch)
treedd458089f80f7486ee3775fa93acd5e72839891b /drivers/gpu/drm/i915/i915_irq.c
parente5868a318d1ae28f760f77bb91ce5deb751733fd (diff)
drm/i915: implement ibx_hpd_irq_setup
This fixes a regression introduced in commit e5868a318d1ae28f760f77bb91ce5deb751733fd Author: Egbert Eich <eich@suse.de> Date: Thu Feb 28 04:17:12 2013 -0500 DRM/i915: Convert HPD interrupts to make use of HPD pin assignment in encode Due to the irq setup rework in 3.9, see commit 20afbda209d708be66944907966486d0c1331cb8 Author: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Tue Dec 11 14:05:07 2012 +0100 drm/i915: Fixup hpd irq register setup ordering Egbert Eich's hpd rework blows up on pch-split platforms - it walks the encoder list before that has been set up completely. The new init sequence is: 1. irq enabling 2. modeset init 3. hpd setup We need to move around the ibx setup a bit to fix this. Ville Syrjälä pointed out in his review that we can't touch SDEIER after the interrupt handler is set up, since that'll race with Paulo Zanoni's PCH interrupt race fix: commit 44498aea293b37af1d463acd9658cdce1ecdf427 Author: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Fri Feb 22 17:05:28 2013 -0300 drm/i915: also disable south interrupts when handling them We fix that by unconditionally enabling all interrupts in SDEIER, but masking them as-needed in SDEIMR. Since only the single-threaded setup/teardown (or suspend/resume) code touches that, no further locking is required. While at it also simplify the mask handling - we start out with all interrupts cleared in the postinstall hook, and never enable a hpd interrupt before hpd_irq_setup is called. And finally, for consistency rename the ibx hpd setup function to ibx_hpd_irq_setup. v2: Fix race around SDEIER writes (Ville). v3: Remove the superflous posting read for SDEIER, spotted by Ville. Ville also wondered whether we shouldn't clear SDEIIR, since now SDE interrupts are enabled before we have an irq handler installed. But the master interrupt control bit in DEIER is still cleared, so we should be fine. Cc: Egbert Eich <eich@suse.de> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=62798 Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c63
1 files changed, 35 insertions, 28 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ef9fce50530d..64c79a0cb570 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2028,7 +2028,13 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
2028 2028
2029 /* south display irq */ 2029 /* south display irq */
2030 I915_WRITE(SDEIMR, 0xffffffff); 2030 I915_WRITE(SDEIMR, 0xffffffff);
2031 I915_WRITE(SDEIER, 0x0); 2031 /*
2032 * SDEIER is also touched by the interrupt handler to work around missed
2033 * PCH interrupts. Hence we can't update it after the interrupt handler
2034 * is enabled - instead we unconditionally enable all PCH interrupt
2035 * sources here, but then only unmask them as needed with SDEIMR.
2036 */
2037 I915_WRITE(SDEIER, 0xffffffff);
2032 POSTING_READ(SDEIER); 2038 POSTING_READ(SDEIER);
2033} 2039}
2034 2040
@@ -2064,18 +2070,30 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
2064 POSTING_READ(VLV_IER); 2070 POSTING_READ(VLV_IER);
2065} 2071}
2066 2072
2067/* 2073static void ibx_hpd_irq_setup(struct drm_device *dev)
2068 * Enable digital hotplug on the PCH, and configure the DP short pulse
2069 * duration to 2ms (which is the minimum in the Display Port spec)
2070 *
2071 * This register is the same on all known PCH chips.
2072 */
2073
2074static void ibx_enable_hotplug(struct drm_device *dev)
2075{ 2074{
2076 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2075 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2077 u32 hotplug; 2076 struct drm_mode_config *mode_config = &dev->mode_config;
2077 struct intel_encoder *intel_encoder;
2078 u32 mask = ~I915_READ(SDEIMR);
2079 u32 hotplug;
2080
2081 if (HAS_PCH_IBX(dev)) {
2082 list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
2083 mask |= hpd_ibx[intel_encoder->hpd_pin];
2084 } else {
2085 list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
2086 mask |= hpd_cpt[intel_encoder->hpd_pin];
2087 }
2078 2088
2089 I915_WRITE(SDEIMR, ~mask);
2090
2091 /*
2092 * Enable digital hotplug on the PCH, and configure the DP short pulse
2093 * duration to 2ms (which is the minimum in the Display Port spec)
2094 *
2095 * This register is the same on all known PCH chips.
2096 */
2079 hotplug = I915_READ(PCH_PORT_HOTPLUG); 2097 hotplug = I915_READ(PCH_PORT_HOTPLUG);
2080 hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK); 2098 hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK);
2081 hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; 2099 hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
@@ -2087,27 +2105,14 @@ static void ibx_enable_hotplug(struct drm_device *dev)
2087static void ibx_irq_postinstall(struct drm_device *dev) 2105static void ibx_irq_postinstall(struct drm_device *dev)
2088{ 2106{
2089 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2107 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2090 struct drm_mode_config *mode_config = &dev->mode_config; 2108 u32 mask;
2091 struct intel_encoder *intel_encoder;
2092 u32 mask = I915_READ(SDEIER);
2093 2109
2094 if (HAS_PCH_IBX(dev)) { 2110 if (HAS_PCH_IBX(dev))
2095 mask &= ~SDE_HOTPLUG_MASK; 2111 mask = SDE_GMBUS | SDE_AUX_MASK;
2096 list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) 2112 else
2097 mask |= hpd_ibx[intel_encoder->hpd_pin]; 2113 mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
2098 mask |= SDE_GMBUS | SDE_AUX_MASK;
2099 } else {
2100 mask &= ~SDE_HOTPLUG_MASK_CPT;
2101 list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
2102 mask |= hpd_cpt[intel_encoder->hpd_pin];
2103 mask |= SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
2104 }
2105 I915_WRITE(SDEIIR, I915_READ(SDEIIR)); 2114 I915_WRITE(SDEIIR, I915_READ(SDEIIR));
2106 I915_WRITE(SDEIMR, ~mask); 2115 I915_WRITE(SDEIMR, ~mask);
2107 I915_WRITE(SDEIER, mask);
2108 POSTING_READ(SDEIER);
2109
2110 ibx_enable_hotplug(dev);
2111} 2116}
2112 2117
2113static int ironlake_irq_postinstall(struct drm_device *dev) 2118static int ironlake_irq_postinstall(struct drm_device *dev)
@@ -2977,6 +2982,7 @@ void intel_irq_init(struct drm_device *dev)
2977 dev->driver->irq_uninstall = ironlake_irq_uninstall; 2982 dev->driver->irq_uninstall = ironlake_irq_uninstall;
2978 dev->driver->enable_vblank = ivybridge_enable_vblank; 2983 dev->driver->enable_vblank = ivybridge_enable_vblank;
2979 dev->driver->disable_vblank = ivybridge_disable_vblank; 2984 dev->driver->disable_vblank = ivybridge_disable_vblank;
2985 dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
2980 } else if (HAS_PCH_SPLIT(dev)) { 2986 } else if (HAS_PCH_SPLIT(dev)) {
2981 dev->driver->irq_handler = ironlake_irq_handler; 2987 dev->driver->irq_handler = ironlake_irq_handler;
2982 dev->driver->irq_preinstall = ironlake_irq_preinstall; 2988 dev->driver->irq_preinstall = ironlake_irq_preinstall;
@@ -2984,6 +2990,7 @@ void intel_irq_init(struct drm_device *dev)
2984 dev->driver->irq_uninstall = ironlake_irq_uninstall; 2990 dev->driver->irq_uninstall = ironlake_irq_uninstall;
2985 dev->driver->enable_vblank = ironlake_enable_vblank; 2991 dev->driver->enable_vblank = ironlake_enable_vblank;
2986 dev->driver->disable_vblank = ironlake_disable_vblank; 2992 dev->driver->disable_vblank = ironlake_disable_vblank;
2993 dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
2987 } else { 2994 } else {
2988 if (INTEL_INFO(dev)->gen == 2) { 2995 if (INTEL_INFO(dev)->gen == 2) {
2989 dev->driver->irq_preinstall = i8xx_irq_preinstall; 2996 dev->driver->irq_preinstall = i8xx_irq_preinstall;