1c4a9e910SFrançois Tigeot /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- 2c4a9e910SFrançois Tigeot */ 300640ec9SFrançois Tigeot /* 4c4a9e910SFrançois Tigeot * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 5c4a9e910SFrançois Tigeot * All Rights Reserved. 6c4a9e910SFrançois Tigeot * 7c4a9e910SFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 8c4a9e910SFrançois Tigeot * copy of this software and associated documentation files (the 9c4a9e910SFrançois Tigeot * "Software"), to deal in the Software without restriction, including 10c4a9e910SFrançois Tigeot * without limitation the rights to use, copy, modify, merge, publish, 11c4a9e910SFrançois Tigeot * distribute, sub license, and/or sell copies of the Software, and to 12c4a9e910SFrançois Tigeot * permit persons to whom the Software is furnished to do so, subject to 13c4a9e910SFrançois Tigeot * the following conditions: 14c4a9e910SFrançois Tigeot * 15c4a9e910SFrançois Tigeot * The above copyright notice and this permission notice (including the 16c4a9e910SFrançois Tigeot * next paragraph) shall be included in all copies or substantial portions 17c4a9e910SFrançois Tigeot * of the Software. 18c4a9e910SFrançois Tigeot * 19c4a9e910SFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20c4a9e910SFrançois Tigeot * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21c4a9e910SFrançois Tigeot * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22c4a9e910SFrançois Tigeot * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 23c4a9e910SFrançois Tigeot * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24c4a9e910SFrançois Tigeot * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25c4a9e910SFrançois Tigeot * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26c4a9e910SFrançois Tigeot * 27c4a9e910SFrançois Tigeot */ 28c4a9e910SFrançois Tigeot 29183e2373SFrançois Tigeot #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 30183e2373SFrançois Tigeot 31183e2373SFrançois Tigeot #include <linux/sysrq.h> 321487f786SFrançois Tigeot #include <linux/slab.h> 338621f407SFrançois Tigeot #include <linux/circ_buf.h> 3418e26a6dSFrançois Tigeot #include <drm/drmP.h> 355c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 36c4a9e910SFrançois Tigeot #include "i915_drv.h" 379edbd4a0SFrançois Tigeot #include "i915_trace.h" 38e3adcf8fSFrançois Tigeot #include "intel_drv.h" 39c4a9e910SFrançois Tigeot 402c9916cdSFrançois Tigeot /** 412c9916cdSFrançois Tigeot * DOC: interrupt handling 422c9916cdSFrançois Tigeot * 432c9916cdSFrançois Tigeot * These functions provide the basic support for enabling and disabling the 442c9916cdSFrançois Tigeot * interrupt handling support. There's a lot more functionality in i915_irq.c 452c9916cdSFrançois Tigeot * and related files, but that will be described in separate chapters. 462c9916cdSFrançois Tigeot */ 472c9916cdSFrançois Tigeot 48352ff8bdSFrançois Tigeot static const u32 hpd_ilk[HPD_NUM_PINS] = { 49352ff8bdSFrançois Tigeot [HPD_PORT_A] = DE_DP_A_HOTPLUG, 50352ff8bdSFrançois Tigeot }; 51352ff8bdSFrançois Tigeot 52352ff8bdSFrançois Tigeot static const u32 hpd_ivb[HPD_NUM_PINS] = { 53352ff8bdSFrançois Tigeot [HPD_PORT_A] = DE_DP_A_HOTPLUG_IVB, 54352ff8bdSFrançois Tigeot }; 55352ff8bdSFrançois Tigeot 56352ff8bdSFrançois Tigeot static const u32 hpd_bdw[HPD_NUM_PINS] = { 57352ff8bdSFrançois Tigeot [HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG, 58352ff8bdSFrançois Tigeot }; 59352ff8bdSFrançois Tigeot 602c9916cdSFrançois Tigeot static const u32 hpd_ibx[HPD_NUM_PINS] = { 618e26cdf6SFrançois Tigeot [HPD_CRT] = SDE_CRT_HOTPLUG, 628e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG, 638e26cdf6SFrançois Tigeot [HPD_PORT_B] = SDE_PORTB_HOTPLUG, 648e26cdf6SFrançois Tigeot [HPD_PORT_C] = SDE_PORTC_HOTPLUG, 658e26cdf6SFrançois Tigeot [HPD_PORT_D] = SDE_PORTD_HOTPLUG 668e26cdf6SFrançois Tigeot }; 678e26cdf6SFrançois Tigeot 682c9916cdSFrançois Tigeot static const u32 hpd_cpt[HPD_NUM_PINS] = { 698e26cdf6SFrançois Tigeot [HPD_CRT] = SDE_CRT_HOTPLUG_CPT, 708e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT, 718e26cdf6SFrançois Tigeot [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, 728e26cdf6SFrançois Tigeot [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, 738e26cdf6SFrançois Tigeot [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT 748e26cdf6SFrançois Tigeot }; 758e26cdf6SFrançois Tigeot 76a05eeebfSFrançois Tigeot static const u32 hpd_spt[HPD_NUM_PINS] = { 77352ff8bdSFrançois Tigeot [HPD_PORT_A] = SDE_PORTA_HOTPLUG_SPT, 78a05eeebfSFrançois Tigeot [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, 79a05eeebfSFrançois Tigeot [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, 80a05eeebfSFrançois Tigeot [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT, 81a05eeebfSFrançois Tigeot [HPD_PORT_E] = SDE_PORTE_HOTPLUG_SPT 82a05eeebfSFrançois Tigeot }; 83a05eeebfSFrançois Tigeot 842c9916cdSFrançois Tigeot static const u32 hpd_mask_i915[HPD_NUM_PINS] = { 858e26cdf6SFrançois Tigeot [HPD_CRT] = CRT_HOTPLUG_INT_EN, 868e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, 878e26cdf6SFrançois Tigeot [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN, 888e26cdf6SFrançois Tigeot [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN, 898e26cdf6SFrançois Tigeot [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN, 908e26cdf6SFrançois Tigeot [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN 918e26cdf6SFrançois Tigeot }; 928e26cdf6SFrançois Tigeot 932c9916cdSFrançois Tigeot static const u32 hpd_status_g4x[HPD_NUM_PINS] = { 948e26cdf6SFrançois Tigeot [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, 958e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, 968e26cdf6SFrançois Tigeot [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, 978e26cdf6SFrançois Tigeot [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, 988e26cdf6SFrançois Tigeot [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, 998e26cdf6SFrançois Tigeot [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS 1008e26cdf6SFrançois Tigeot }; 1018e26cdf6SFrançois Tigeot 10219c468b4SFrançois Tigeot static const u32 hpd_status_i915[HPD_NUM_PINS] = { 1038e26cdf6SFrançois Tigeot [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, 1048e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, 1058e26cdf6SFrançois Tigeot [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915, 1068e26cdf6SFrançois Tigeot [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, 1078e26cdf6SFrançois Tigeot [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, 1088e26cdf6SFrançois Tigeot [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS 1098e26cdf6SFrançois Tigeot }; 1108e26cdf6SFrançois Tigeot 11119c468b4SFrançois Tigeot /* BXT hpd list */ 11219c468b4SFrançois Tigeot static const u32 hpd_bxt[HPD_NUM_PINS] = { 113352ff8bdSFrançois Tigeot [HPD_PORT_A] = BXT_DE_PORT_HP_DDIA, 11419c468b4SFrançois Tigeot [HPD_PORT_B] = BXT_DE_PORT_HP_DDIB, 11519c468b4SFrançois Tigeot [HPD_PORT_C] = BXT_DE_PORT_HP_DDIC 11619c468b4SFrançois Tigeot }; 11719c468b4SFrançois Tigeot 118ba55f2f5SFrançois Tigeot /* IIR can theoretically queue up two events. Be paranoid. */ 119ba55f2f5SFrançois Tigeot #define GEN8_IRQ_RESET_NDX(type, which) do { \ 120ba55f2f5SFrançois Tigeot I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ 121ba55f2f5SFrançois Tigeot POSTING_READ(GEN8_##type##_IMR(which)); \ 122ba55f2f5SFrançois Tigeot I915_WRITE(GEN8_##type##_IER(which), 0); \ 123ba55f2f5SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ 124ba55f2f5SFrançois Tigeot POSTING_READ(GEN8_##type##_IIR(which)); \ 125ba55f2f5SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ 126ba55f2f5SFrançois Tigeot POSTING_READ(GEN8_##type##_IIR(which)); \ 127ba55f2f5SFrançois Tigeot } while (0) 128ba55f2f5SFrançois Tigeot 129ba55f2f5SFrançois Tigeot #define GEN5_IRQ_RESET(type) do { \ 130ba55f2f5SFrançois Tigeot I915_WRITE(type##IMR, 0xffffffff); \ 131ba55f2f5SFrançois Tigeot POSTING_READ(type##IMR); \ 132ba55f2f5SFrançois Tigeot I915_WRITE(type##IER, 0); \ 133ba55f2f5SFrançois Tigeot I915_WRITE(type##IIR, 0xffffffff); \ 134ba55f2f5SFrançois Tigeot POSTING_READ(type##IIR); \ 135ba55f2f5SFrançois Tigeot I915_WRITE(type##IIR, 0xffffffff); \ 136ba55f2f5SFrançois Tigeot POSTING_READ(type##IIR); \ 137ba55f2f5SFrançois Tigeot } while (0) 138ba55f2f5SFrançois Tigeot 139ba55f2f5SFrançois Tigeot /* 140ba55f2f5SFrançois Tigeot * We should clear IMR at preinstall/uninstall, and just check at postinstall. 141ba55f2f5SFrançois Tigeot */ 142aee94f86SFrançois Tigeot static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, 143aee94f86SFrançois Tigeot i915_reg_t reg) 144352ff8bdSFrançois Tigeot { 145352ff8bdSFrançois Tigeot u32 val = I915_READ(reg); 146352ff8bdSFrançois Tigeot 147352ff8bdSFrançois Tigeot if (val == 0) 148352ff8bdSFrançois Tigeot return; 149352ff8bdSFrançois Tigeot 150352ff8bdSFrançois Tigeot WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n", 151aee94f86SFrançois Tigeot i915_mmio_reg_offset(reg), val); 152352ff8bdSFrançois Tigeot I915_WRITE(reg, 0xffffffff); 153352ff8bdSFrançois Tigeot POSTING_READ(reg); 154352ff8bdSFrançois Tigeot I915_WRITE(reg, 0xffffffff); 155352ff8bdSFrançois Tigeot POSTING_READ(reg); 156352ff8bdSFrançois Tigeot } 157ba55f2f5SFrançois Tigeot 158ba55f2f5SFrançois Tigeot #define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \ 159352ff8bdSFrançois Tigeot gen5_assert_iir_is_zero(dev_priv, GEN8_##type##_IIR(which)); \ 160ba55f2f5SFrançois Tigeot I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \ 1612c9916cdSFrançois Tigeot I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \ 1622c9916cdSFrançois Tigeot POSTING_READ(GEN8_##type##_IMR(which)); \ 163ba55f2f5SFrançois Tigeot } while (0) 164ba55f2f5SFrançois Tigeot 165ba55f2f5SFrançois Tigeot #define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \ 166352ff8bdSFrançois Tigeot gen5_assert_iir_is_zero(dev_priv, type##IIR); \ 167ba55f2f5SFrançois Tigeot I915_WRITE(type##IER, (ier_val)); \ 1682c9916cdSFrançois Tigeot I915_WRITE(type##IMR, (imr_val)); \ 1692c9916cdSFrançois Tigeot POSTING_READ(type##IMR); \ 170ba55f2f5SFrançois Tigeot } while (0) 171ba55f2f5SFrançois Tigeot 1722c9916cdSFrançois Tigeot static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir); 1734be47400SFrançois Tigeot static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir); 1742c9916cdSFrançois Tigeot 175e3adcf8fSFrançois Tigeot /* For display hotplug interrupt */ 176352ff8bdSFrançois Tigeot static inline void 177352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv, 178352ff8bdSFrançois Tigeot uint32_t mask, 179352ff8bdSFrançois Tigeot uint32_t bits) 180c4a9e910SFrançois Tigeot { 181352ff8bdSFrançois Tigeot uint32_t val; 182352ff8bdSFrançois Tigeot 183*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 184352ff8bdSFrançois Tigeot WARN_ON(bits & ~mask); 185352ff8bdSFrançois Tigeot 186352ff8bdSFrançois Tigeot val = I915_READ(PORT_HOTPLUG_EN); 187352ff8bdSFrançois Tigeot val &= ~mask; 188352ff8bdSFrançois Tigeot val |= bits; 189352ff8bdSFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, val); 190352ff8bdSFrançois Tigeot } 191352ff8bdSFrançois Tigeot 192352ff8bdSFrançois Tigeot /** 193352ff8bdSFrançois Tigeot * i915_hotplug_interrupt_update - update hotplug interrupt enable 194352ff8bdSFrançois Tigeot * @dev_priv: driver private 195352ff8bdSFrançois Tigeot * @mask: bits to update 196352ff8bdSFrançois Tigeot * @bits: bits to enable 197352ff8bdSFrançois Tigeot * NOTE: the HPD enable bits are modified both inside and outside 198352ff8bdSFrançois Tigeot * of an interrupt context. To avoid that read-modify-write cycles 199352ff8bdSFrançois Tigeot * interfer, these bits are protected by a spinlock. Since this 200352ff8bdSFrançois Tigeot * function is usually not called from a context where the lock is 201352ff8bdSFrançois Tigeot * held already, this function acquires the lock itself. A non-locking 202352ff8bdSFrançois Tigeot * version is also available. 203352ff8bdSFrançois Tigeot */ 204352ff8bdSFrançois Tigeot void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv, 205352ff8bdSFrançois Tigeot uint32_t mask, 206352ff8bdSFrançois Tigeot uint32_t bits) 207352ff8bdSFrançois Tigeot { 208352ff8bdSFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 209352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update_locked(dev_priv, mask, bits); 210352ff8bdSFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 211352ff8bdSFrançois Tigeot } 212352ff8bdSFrançois Tigeot 213352ff8bdSFrançois Tigeot /** 214352ff8bdSFrançois Tigeot * ilk_update_display_irq - update DEIMR 215352ff8bdSFrançois Tigeot * @dev_priv: driver private 216352ff8bdSFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 217352ff8bdSFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 218352ff8bdSFrançois Tigeot */ 219aee94f86SFrançois Tigeot void ilk_update_display_irq(struct drm_i915_private *dev_priv, 220352ff8bdSFrançois Tigeot uint32_t interrupt_mask, 221352ff8bdSFrançois Tigeot uint32_t enabled_irq_mask) 222352ff8bdSFrançois Tigeot { 223352ff8bdSFrançois Tigeot uint32_t new_val; 224352ff8bdSFrançois Tigeot 225*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 226352ff8bdSFrançois Tigeot 227352ff8bdSFrançois Tigeot WARN_ON(enabled_irq_mask & ~interrupt_mask); 2289edbd4a0SFrançois Tigeot 22924edb884SFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 2309edbd4a0SFrançois Tigeot return; 2319edbd4a0SFrançois Tigeot 232352ff8bdSFrançois Tigeot new_val = dev_priv->irq_mask; 233352ff8bdSFrançois Tigeot new_val &= ~interrupt_mask; 234352ff8bdSFrançois Tigeot new_val |= (~enabled_irq_mask & interrupt_mask); 235352ff8bdSFrançois Tigeot 236352ff8bdSFrançois Tigeot if (new_val != dev_priv->irq_mask) { 237352ff8bdSFrançois Tigeot dev_priv->irq_mask = new_val; 238e3adcf8fSFrançois Tigeot I915_WRITE(DEIMR, dev_priv->irq_mask); 239e3adcf8fSFrançois Tigeot POSTING_READ(DEIMR); 240c4a9e910SFrançois Tigeot } 241c4a9e910SFrançois Tigeot } 242c4a9e910SFrançois Tigeot 2439edbd4a0SFrançois Tigeot /** 2449edbd4a0SFrançois Tigeot * ilk_update_gt_irq - update GTIMR 2459edbd4a0SFrançois Tigeot * @dev_priv: driver private 2469edbd4a0SFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 2479edbd4a0SFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 2489edbd4a0SFrançois Tigeot */ 2499edbd4a0SFrançois Tigeot static void ilk_update_gt_irq(struct drm_i915_private *dev_priv, 2509edbd4a0SFrançois Tigeot uint32_t interrupt_mask, 2519edbd4a0SFrançois Tigeot uint32_t enabled_irq_mask) 2529edbd4a0SFrançois Tigeot { 253*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 2549edbd4a0SFrançois Tigeot 2552c9916cdSFrançois Tigeot WARN_ON(enabled_irq_mask & ~interrupt_mask); 2562c9916cdSFrançois Tigeot 25724edb884SFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 2589edbd4a0SFrançois Tigeot return; 2599edbd4a0SFrançois Tigeot 2609edbd4a0SFrançois Tigeot dev_priv->gt_irq_mask &= ~interrupt_mask; 2619edbd4a0SFrançois Tigeot dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask); 2629edbd4a0SFrançois Tigeot I915_WRITE(GTIMR, dev_priv->gt_irq_mask); 2639edbd4a0SFrançois Tigeot } 2649edbd4a0SFrançois Tigeot 26524edb884SFrançois Tigeot void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) 2669edbd4a0SFrançois Tigeot { 2679edbd4a0SFrançois Tigeot ilk_update_gt_irq(dev_priv, mask, mask); 268bf017597SFrançois Tigeot POSTING_READ_FW(GTIMR); 2699edbd4a0SFrançois Tigeot } 2709edbd4a0SFrançois Tigeot 27124edb884SFrançois Tigeot void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) 2729edbd4a0SFrançois Tigeot { 2739edbd4a0SFrançois Tigeot ilk_update_gt_irq(dev_priv, mask, 0); 2749edbd4a0SFrançois Tigeot } 2759edbd4a0SFrançois Tigeot 276aee94f86SFrançois Tigeot static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv) 2772c9916cdSFrançois Tigeot { 2782c9916cdSFrançois Tigeot return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR; 2792c9916cdSFrançois Tigeot } 2802c9916cdSFrançois Tigeot 281aee94f86SFrançois Tigeot static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv) 2822c9916cdSFrançois Tigeot { 2832c9916cdSFrançois Tigeot return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR; 2842c9916cdSFrançois Tigeot } 2852c9916cdSFrançois Tigeot 286aee94f86SFrançois Tigeot static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv) 2872c9916cdSFrançois Tigeot { 2882c9916cdSFrançois Tigeot return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER; 2892c9916cdSFrançois Tigeot } 2902c9916cdSFrançois Tigeot 2919edbd4a0SFrançois Tigeot /** 2929edbd4a0SFrançois Tigeot * snb_update_pm_irq - update GEN6_PMIMR 2939edbd4a0SFrançois Tigeot * @dev_priv: driver private 2949edbd4a0SFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 2959edbd4a0SFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 2969edbd4a0SFrançois Tigeot */ 2979edbd4a0SFrançois Tigeot static void snb_update_pm_irq(struct drm_i915_private *dev_priv, 2989edbd4a0SFrançois Tigeot uint32_t interrupt_mask, 2999edbd4a0SFrançois Tigeot uint32_t enabled_irq_mask) 3009edbd4a0SFrançois Tigeot { 3019edbd4a0SFrançois Tigeot uint32_t new_val; 3029edbd4a0SFrançois Tigeot 3032c9916cdSFrançois Tigeot WARN_ON(enabled_irq_mask & ~interrupt_mask); 3049edbd4a0SFrançois Tigeot 305*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 3069edbd4a0SFrançois Tigeot 3074be47400SFrançois Tigeot new_val = dev_priv->pm_imr; 3089edbd4a0SFrançois Tigeot new_val &= ~interrupt_mask; 3099edbd4a0SFrançois Tigeot new_val |= (~enabled_irq_mask & interrupt_mask); 3109edbd4a0SFrançois Tigeot 3114be47400SFrançois Tigeot if (new_val != dev_priv->pm_imr) { 3124be47400SFrançois Tigeot dev_priv->pm_imr = new_val; 3134be47400SFrançois Tigeot I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_imr); 3142c9916cdSFrançois Tigeot POSTING_READ(gen6_pm_imr(dev_priv)); 3159edbd4a0SFrançois Tigeot } 3169edbd4a0SFrançois Tigeot } 3179edbd4a0SFrançois Tigeot 3184be47400SFrançois Tigeot void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask) 3199edbd4a0SFrançois Tigeot { 3202c9916cdSFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 3212c9916cdSFrançois Tigeot return; 3222c9916cdSFrançois Tigeot 3239edbd4a0SFrançois Tigeot snb_update_pm_irq(dev_priv, mask, mask); 3249edbd4a0SFrançois Tigeot } 3259edbd4a0SFrançois Tigeot 3264be47400SFrançois Tigeot static void __gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask) 3279edbd4a0SFrançois Tigeot { 3289edbd4a0SFrançois Tigeot snb_update_pm_irq(dev_priv, mask, 0); 3299edbd4a0SFrançois Tigeot } 3309edbd4a0SFrançois Tigeot 3314be47400SFrançois Tigeot void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask) 3325d0b1887SFrançois Tigeot { 33324edb884SFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 334ba55f2f5SFrançois Tigeot return; 335ba55f2f5SFrançois Tigeot 3364be47400SFrançois Tigeot __gen6_mask_pm_irq(dev_priv, mask); 3374be47400SFrançois Tigeot } 3384be47400SFrançois Tigeot 3394be47400SFrançois Tigeot void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 reset_mask) 3404be47400SFrançois Tigeot { 3414be47400SFrançois Tigeot i915_reg_t reg = gen6_pm_iir(dev_priv); 3424be47400SFrançois Tigeot 343*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 3444be47400SFrançois Tigeot 3454be47400SFrançois Tigeot I915_WRITE(reg, reset_mask); 3464be47400SFrançois Tigeot I915_WRITE(reg, reset_mask); 3474be47400SFrançois Tigeot POSTING_READ(reg); 3484be47400SFrançois Tigeot } 3494be47400SFrançois Tigeot 3504be47400SFrançois Tigeot void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, u32 enable_mask) 3514be47400SFrançois Tigeot { 352*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 3534be47400SFrançois Tigeot 3544be47400SFrançois Tigeot dev_priv->pm_ier |= enable_mask; 3554be47400SFrançois Tigeot I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier); 3564be47400SFrançois Tigeot gen6_unmask_pm_irq(dev_priv, enable_mask); 3574be47400SFrançois Tigeot /* unmask_pm_irq provides an implicit barrier (POSTING_READ) */ 3584be47400SFrançois Tigeot } 3594be47400SFrançois Tigeot 3604be47400SFrançois Tigeot void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_mask) 3614be47400SFrançois Tigeot { 362*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 3634be47400SFrançois Tigeot 3644be47400SFrançois Tigeot dev_priv->pm_ier &= ~disable_mask; 3654be47400SFrançois Tigeot __gen6_mask_pm_irq(dev_priv, disable_mask); 3664be47400SFrançois Tigeot I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier); 3674be47400SFrançois Tigeot /* though a barrier is missing here, but don't really need a one */ 368ba55f2f5SFrançois Tigeot } 369ba55f2f5SFrançois Tigeot 3701487f786SFrançois Tigeot void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv) 3715d0b1887SFrançois Tigeot { 3725e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 3734be47400SFrançois Tigeot gen6_reset_pm_iir(dev_priv, dev_priv->pm_rps_events); 374477eb7f9SFrançois Tigeot dev_priv->rps.pm_iir = 0; 3755e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 3765d0b1887SFrançois Tigeot } 3775d0b1887SFrançois Tigeot 3781487f786SFrançois Tigeot void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) 379ba55f2f5SFrançois Tigeot { 3801e12ee3bSFrançois Tigeot if (READ_ONCE(dev_priv->rps.interrupts_enabled)) 3811e12ee3bSFrançois Tigeot return; 3821e12ee3bSFrançois Tigeot 3835e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 384303bf270SFrançois Tigeot WARN_ON_ONCE(dev_priv->rps.pm_iir); 385303bf270SFrançois Tigeot WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); 3862c9916cdSFrançois Tigeot dev_priv->rps.interrupts_enabled = true; 3872c9916cdSFrançois Tigeot gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); 388ba55f2f5SFrançois Tigeot 3895e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 390ba55f2f5SFrançois Tigeot } 391ba55f2f5SFrançois Tigeot 3921487f786SFrançois Tigeot void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) 3935d0b1887SFrançois Tigeot { 3941e12ee3bSFrançois Tigeot if (!READ_ONCE(dev_priv->rps.interrupts_enabled)) 3951e12ee3bSFrançois Tigeot return; 3961e12ee3bSFrançois Tigeot 3975e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 3982c9916cdSFrançois Tigeot dev_priv->rps.interrupts_enabled = false; 3992c9916cdSFrançois Tigeot 4001e12ee3bSFrançois Tigeot I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u)); 4012c9916cdSFrançois Tigeot 4024be47400SFrançois Tigeot gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events); 4032c9916cdSFrançois Tigeot 4045e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 405303bf270SFrançois Tigeot synchronize_irq(dev_priv->drm.irq); 406477eb7f9SFrançois Tigeot 407303bf270SFrançois Tigeot /* Now that we will not be generating any more work, flush any 408303bf270SFrançois Tigeot * outsanding tasks. As we are called on the RPS idle path, 409303bf270SFrançois Tigeot * we will reset the GPU to minimum frequencies, so the current 410303bf270SFrançois Tigeot * state of the worker can be discarded. 411303bf270SFrançois Tigeot */ 412303bf270SFrançois Tigeot cancel_work_sync(&dev_priv->rps.work); 413303bf270SFrançois Tigeot gen6_reset_rps_interrupts(dev_priv); 4149edbd4a0SFrançois Tigeot } 4155d0b1887SFrançois Tigeot 4164be47400SFrançois Tigeot void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv) 4174be47400SFrançois Tigeot { 4184be47400SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 4194be47400SFrançois Tigeot gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events); 4204be47400SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 4214be47400SFrançois Tigeot } 4224be47400SFrançois Tigeot 4234be47400SFrançois Tigeot void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv) 4244be47400SFrançois Tigeot { 4254be47400SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 4264be47400SFrançois Tigeot if (!dev_priv->guc.interrupts_enabled) { 4274be47400SFrançois Tigeot WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & 4284be47400SFrançois Tigeot dev_priv->pm_guc_events); 4294be47400SFrançois Tigeot dev_priv->guc.interrupts_enabled = true; 4304be47400SFrançois Tigeot gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events); 4314be47400SFrançois Tigeot } 4324be47400SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 4334be47400SFrançois Tigeot } 4344be47400SFrançois Tigeot 4354be47400SFrançois Tigeot void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv) 4364be47400SFrançois Tigeot { 4374be47400SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 4384be47400SFrançois Tigeot dev_priv->guc.interrupts_enabled = false; 4394be47400SFrançois Tigeot 4404be47400SFrançois Tigeot gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events); 4414be47400SFrançois Tigeot 4424be47400SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 4434be47400SFrançois Tigeot synchronize_irq(dev_priv->drm.irq); 4444be47400SFrançois Tigeot 4454be47400SFrançois Tigeot gen9_reset_guc_interrupts(dev_priv); 4464be47400SFrançois Tigeot } 4474be47400SFrançois Tigeot 4489edbd4a0SFrançois Tigeot /** 449352ff8bdSFrançois Tigeot * bdw_update_port_irq - update DE port interrupt 450352ff8bdSFrançois Tigeot * @dev_priv: driver private 451352ff8bdSFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 452352ff8bdSFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 453352ff8bdSFrançois Tigeot */ 454352ff8bdSFrançois Tigeot static void bdw_update_port_irq(struct drm_i915_private *dev_priv, 455352ff8bdSFrançois Tigeot uint32_t interrupt_mask, 456352ff8bdSFrançois Tigeot uint32_t enabled_irq_mask) 457352ff8bdSFrançois Tigeot { 458352ff8bdSFrançois Tigeot uint32_t new_val; 459352ff8bdSFrançois Tigeot uint32_t old_val; 460352ff8bdSFrançois Tigeot 461*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 462352ff8bdSFrançois Tigeot 463352ff8bdSFrançois Tigeot WARN_ON(enabled_irq_mask & ~interrupt_mask); 464352ff8bdSFrançois Tigeot 465352ff8bdSFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 466352ff8bdSFrançois Tigeot return; 467352ff8bdSFrançois Tigeot 468352ff8bdSFrançois Tigeot old_val = I915_READ(GEN8_DE_PORT_IMR); 469352ff8bdSFrançois Tigeot 470352ff8bdSFrançois Tigeot new_val = old_val; 471352ff8bdSFrançois Tigeot new_val &= ~interrupt_mask; 472352ff8bdSFrançois Tigeot new_val |= (~enabled_irq_mask & interrupt_mask); 473352ff8bdSFrançois Tigeot 474352ff8bdSFrançois Tigeot if (new_val != old_val) { 475352ff8bdSFrançois Tigeot I915_WRITE(GEN8_DE_PORT_IMR, new_val); 476352ff8bdSFrançois Tigeot POSTING_READ(GEN8_DE_PORT_IMR); 477352ff8bdSFrançois Tigeot } 478352ff8bdSFrançois Tigeot } 479352ff8bdSFrançois Tigeot 480352ff8bdSFrançois Tigeot /** 481aee94f86SFrançois Tigeot * bdw_update_pipe_irq - update DE pipe interrupt 482aee94f86SFrançois Tigeot * @dev_priv: driver private 483aee94f86SFrançois Tigeot * @pipe: pipe whose interrupt to update 484aee94f86SFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 485aee94f86SFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 486aee94f86SFrançois Tigeot */ 487aee94f86SFrançois Tigeot void bdw_update_pipe_irq(struct drm_i915_private *dev_priv, 488aee94f86SFrançois Tigeot enum i915_pipe pipe, 489aee94f86SFrançois Tigeot uint32_t interrupt_mask, 490aee94f86SFrançois Tigeot uint32_t enabled_irq_mask) 491aee94f86SFrançois Tigeot { 492aee94f86SFrançois Tigeot uint32_t new_val; 493aee94f86SFrançois Tigeot 494*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 495aee94f86SFrançois Tigeot 496aee94f86SFrançois Tigeot WARN_ON(enabled_irq_mask & ~interrupt_mask); 497aee94f86SFrançois Tigeot 498aee94f86SFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 499aee94f86SFrançois Tigeot return; 500aee94f86SFrançois Tigeot 501aee94f86SFrançois Tigeot new_val = dev_priv->de_irq_mask[pipe]; 502aee94f86SFrançois Tigeot new_val &= ~interrupt_mask; 503aee94f86SFrançois Tigeot new_val |= (~enabled_irq_mask & interrupt_mask); 504aee94f86SFrançois Tigeot 505aee94f86SFrançois Tigeot if (new_val != dev_priv->de_irq_mask[pipe]) { 506aee94f86SFrançois Tigeot dev_priv->de_irq_mask[pipe] = new_val; 507aee94f86SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); 508aee94f86SFrançois Tigeot POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); 509aee94f86SFrançois Tigeot } 510aee94f86SFrançois Tigeot } 511aee94f86SFrançois Tigeot 512aee94f86SFrançois Tigeot /** 5139edbd4a0SFrançois Tigeot * ibx_display_interrupt_update - update SDEIMR 5149edbd4a0SFrançois Tigeot * @dev_priv: driver private 5159edbd4a0SFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 5169edbd4a0SFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 5179edbd4a0SFrançois Tigeot */ 5182c9916cdSFrançois Tigeot void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, 5199edbd4a0SFrançois Tigeot uint32_t interrupt_mask, 5209edbd4a0SFrançois Tigeot uint32_t enabled_irq_mask) 5219edbd4a0SFrançois Tigeot { 5229edbd4a0SFrançois Tigeot uint32_t sdeimr = I915_READ(SDEIMR); 5239edbd4a0SFrançois Tigeot sdeimr &= ~interrupt_mask; 5249edbd4a0SFrançois Tigeot sdeimr |= (~enabled_irq_mask & interrupt_mask); 5259edbd4a0SFrançois Tigeot 5262c9916cdSFrançois Tigeot WARN_ON(enabled_irq_mask & ~interrupt_mask); 5272c9916cdSFrançois Tigeot 528*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 5299edbd4a0SFrançois Tigeot 53024edb884SFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 5319edbd4a0SFrançois Tigeot return; 5329edbd4a0SFrançois Tigeot 5339edbd4a0SFrançois Tigeot I915_WRITE(SDEIMR, sdeimr); 5345d0b1887SFrançois Tigeot POSTING_READ(SDEIMR); 5355d0b1887SFrançois Tigeot } 5365d0b1887SFrançois Tigeot 537ba55f2f5SFrançois Tigeot static void 538ba55f2f5SFrançois Tigeot __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum i915_pipe pipe, 539ba55f2f5SFrançois Tigeot u32 enable_mask, u32 status_mask) 540c4a9e910SFrançois Tigeot { 541aee94f86SFrançois Tigeot i915_reg_t reg = PIPESTAT(pipe); 542ba55f2f5SFrançois Tigeot u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK; 543c4a9e910SFrançois Tigeot 544*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 5452c9916cdSFrançois Tigeot WARN_ON(!intel_irqs_enabled(dev_priv)); 5469edbd4a0SFrançois Tigeot 547ba55f2f5SFrançois Tigeot if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || 548ba55f2f5SFrançois Tigeot status_mask & ~PIPESTAT_INT_STATUS_MASK, 549ba55f2f5SFrançois Tigeot "pipe %c: enable_mask=0x%x, status_mask=0x%x\n", 550ba55f2f5SFrançois Tigeot pipe_name(pipe), enable_mask, status_mask)) 5518e26cdf6SFrançois Tigeot return; 5528e26cdf6SFrançois Tigeot 553ba55f2f5SFrançois Tigeot if ((pipestat & enable_mask) == enable_mask) 554ba55f2f5SFrançois Tigeot return; 555ba55f2f5SFrançois Tigeot 556ba55f2f5SFrançois Tigeot dev_priv->pipestat_irq_mask[pipe] |= status_mask; 557ba55f2f5SFrançois Tigeot 558c4a9e910SFrançois Tigeot /* Enable the interrupt, clear any pending status */ 559ba55f2f5SFrançois Tigeot pipestat |= enable_mask | status_mask; 5608e26cdf6SFrançois Tigeot I915_WRITE(reg, pipestat); 561e3adcf8fSFrançois Tigeot POSTING_READ(reg); 562c4a9e910SFrançois Tigeot } 563c4a9e910SFrançois Tigeot 564ba55f2f5SFrançois Tigeot static void 565ba55f2f5SFrançois Tigeot __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum i915_pipe pipe, 566ba55f2f5SFrançois Tigeot u32 enable_mask, u32 status_mask) 567c4a9e910SFrançois Tigeot { 568aee94f86SFrançois Tigeot i915_reg_t reg = PIPESTAT(pipe); 569ba55f2f5SFrançois Tigeot u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK; 570c4a9e910SFrançois Tigeot 571*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 5722c9916cdSFrançois Tigeot WARN_ON(!intel_irqs_enabled(dev_priv)); 5739edbd4a0SFrançois Tigeot 574ba55f2f5SFrançois Tigeot if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || 575ba55f2f5SFrançois Tigeot status_mask & ~PIPESTAT_INT_STATUS_MASK, 576ba55f2f5SFrançois Tigeot "pipe %c: enable_mask=0x%x, status_mask=0x%x\n", 577ba55f2f5SFrançois Tigeot pipe_name(pipe), enable_mask, status_mask)) 5788e26cdf6SFrançois Tigeot return; 5798e26cdf6SFrançois Tigeot 580ba55f2f5SFrançois Tigeot if ((pipestat & enable_mask) == 0) 581ba55f2f5SFrançois Tigeot return; 582ba55f2f5SFrançois Tigeot 583ba55f2f5SFrançois Tigeot dev_priv->pipestat_irq_mask[pipe] &= ~status_mask; 584ba55f2f5SFrançois Tigeot 585ba55f2f5SFrançois Tigeot pipestat &= ~enable_mask; 5868e26cdf6SFrançois Tigeot I915_WRITE(reg, pipestat); 587e3adcf8fSFrançois Tigeot POSTING_READ(reg); 588c4a9e910SFrançois Tigeot } 589c4a9e910SFrançois Tigeot 590ba55f2f5SFrançois Tigeot static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask) 591ba55f2f5SFrançois Tigeot { 592ba55f2f5SFrançois Tigeot u32 enable_mask = status_mask << 16; 593ba55f2f5SFrançois Tigeot 594ba55f2f5SFrançois Tigeot /* 595ba55f2f5SFrançois Tigeot * On pipe A we don't support the PSR interrupt yet, 596ba55f2f5SFrançois Tigeot * on pipe B and C the same bit MBZ. 597ba55f2f5SFrançois Tigeot */ 598ba55f2f5SFrançois Tigeot if (WARN_ON_ONCE(status_mask & PIPE_A_PSR_STATUS_VLV)) 599ba55f2f5SFrançois Tigeot return 0; 600ba55f2f5SFrançois Tigeot /* 601ba55f2f5SFrançois Tigeot * On pipe B and C we don't support the PSR interrupt yet, on pipe 602ba55f2f5SFrançois Tigeot * A the same bit is for perf counters which we don't use either. 603ba55f2f5SFrançois Tigeot */ 604ba55f2f5SFrançois Tigeot if (WARN_ON_ONCE(status_mask & PIPE_B_PSR_STATUS_VLV)) 605ba55f2f5SFrançois Tigeot return 0; 606ba55f2f5SFrançois Tigeot 607ba55f2f5SFrançois Tigeot enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS | 608ba55f2f5SFrançois Tigeot SPRITE0_FLIP_DONE_INT_EN_VLV | 609ba55f2f5SFrançois Tigeot SPRITE1_FLIP_DONE_INT_EN_VLV); 610ba55f2f5SFrançois Tigeot if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV) 611ba55f2f5SFrançois Tigeot enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV; 612ba55f2f5SFrançois Tigeot if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV) 613ba55f2f5SFrançois Tigeot enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV; 614ba55f2f5SFrançois Tigeot 615ba55f2f5SFrançois Tigeot return enable_mask; 616ba55f2f5SFrançois Tigeot } 617ba55f2f5SFrançois Tigeot 618ba55f2f5SFrançois Tigeot void 619ba55f2f5SFrançois Tigeot i915_enable_pipestat(struct drm_i915_private *dev_priv, enum i915_pipe pipe, 620ba55f2f5SFrançois Tigeot u32 status_mask) 621ba55f2f5SFrançois Tigeot { 622ba55f2f5SFrançois Tigeot u32 enable_mask; 623ba55f2f5SFrançois Tigeot 624aee94f86SFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 625303bf270SFrançois Tigeot enable_mask = vlv_get_pipestat_enable_mask(&dev_priv->drm, 626ba55f2f5SFrançois Tigeot status_mask); 627ba55f2f5SFrançois Tigeot else 628ba55f2f5SFrançois Tigeot enable_mask = status_mask << 16; 629ba55f2f5SFrançois Tigeot __i915_enable_pipestat(dev_priv, pipe, enable_mask, status_mask); 630ba55f2f5SFrançois Tigeot } 631ba55f2f5SFrançois Tigeot 632ba55f2f5SFrançois Tigeot void 633ba55f2f5SFrançois Tigeot i915_disable_pipestat(struct drm_i915_private *dev_priv, enum i915_pipe pipe, 634ba55f2f5SFrançois Tigeot u32 status_mask) 635ba55f2f5SFrançois Tigeot { 636ba55f2f5SFrançois Tigeot u32 enable_mask; 637ba55f2f5SFrançois Tigeot 638aee94f86SFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 639303bf270SFrançois Tigeot enable_mask = vlv_get_pipestat_enable_mask(&dev_priv->drm, 640ba55f2f5SFrançois Tigeot status_mask); 641ba55f2f5SFrançois Tigeot else 642ba55f2f5SFrançois Tigeot enable_mask = status_mask << 16; 643ba55f2f5SFrançois Tigeot __i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask); 644ba55f2f5SFrançois Tigeot } 645ba55f2f5SFrançois Tigeot 646c4a9e910SFrançois Tigeot /** 6475d0b1887SFrançois Tigeot * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion 6481487f786SFrançois Tigeot * @dev_priv: i915 device private 649e3adcf8fSFrançois Tigeot */ 6501487f786SFrançois Tigeot static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv) 651e3adcf8fSFrançois Tigeot { 6521487f786SFrançois Tigeot if (!dev_priv->opregion.asle || !IS_MOBILE(dev_priv)) 65300640ec9SFrançois Tigeot return; 65400640ec9SFrançois Tigeot 6555e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 656e3adcf8fSFrançois Tigeot 657ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS); 6581487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 4) 6599edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, 660ba55f2f5SFrançois Tigeot PIPE_LEGACY_BLC_EVENT_STATUS); 661e3adcf8fSFrançois Tigeot 6625e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 663e3adcf8fSFrançois Tigeot } 664e3adcf8fSFrançois Tigeot 665ba55f2f5SFrançois Tigeot /* 666ba55f2f5SFrançois Tigeot * This timing diagram depicts the video signal in and 667ba55f2f5SFrançois Tigeot * around the vertical blanking period. 668ba55f2f5SFrançois Tigeot * 669ba55f2f5SFrançois Tigeot * Assumptions about the fictitious mode used in this example: 670ba55f2f5SFrançois Tigeot * vblank_start >= 3 671ba55f2f5SFrançois Tigeot * vsync_start = vblank_start + 1 672ba55f2f5SFrançois Tigeot * vsync_end = vblank_start + 2 673ba55f2f5SFrançois Tigeot * vtotal = vblank_start + 3 674ba55f2f5SFrançois Tigeot * 675ba55f2f5SFrançois Tigeot * start of vblank: 676ba55f2f5SFrançois Tigeot * latch double buffered registers 677ba55f2f5SFrançois Tigeot * increment frame counter (ctg+) 678ba55f2f5SFrançois Tigeot * generate start of vblank interrupt (gen4+) 679ba55f2f5SFrançois Tigeot * | 680ba55f2f5SFrançois Tigeot * | frame start: 681ba55f2f5SFrançois Tigeot * | generate frame start interrupt (aka. vblank interrupt) (gmch) 682ba55f2f5SFrançois Tigeot * | may be shifted forward 1-3 extra lines via PIPECONF 683ba55f2f5SFrançois Tigeot * | | 684ba55f2f5SFrançois Tigeot * | | start of vsync: 685ba55f2f5SFrançois Tigeot * | | generate vsync interrupt 686ba55f2f5SFrançois Tigeot * | | | 687ba55f2f5SFrançois Tigeot * ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx 688ba55f2f5SFrançois Tigeot * . \hs/ . \hs/ \hs/ \hs/ . \hs/ 689ba55f2f5SFrançois Tigeot * ----va---> <-----------------vb--------------------> <--------va------------- 690ba55f2f5SFrançois Tigeot * | | <----vs-----> | 691ba55f2f5SFrançois Tigeot * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2) 692ba55f2f5SFrançois Tigeot * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+) 693ba55f2f5SFrançois Tigeot * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi) 694ba55f2f5SFrançois Tigeot * | | | 695ba55f2f5SFrançois Tigeot * last visible pixel first visible pixel 696ba55f2f5SFrançois Tigeot * | increment frame counter (gen3/4) 697ba55f2f5SFrançois Tigeot * pixel counter = vblank_start * htotal pixel counter = 0 (gen3/4) 698ba55f2f5SFrançois Tigeot * 699ba55f2f5SFrançois Tigeot * x = horizontal active 700ba55f2f5SFrançois Tigeot * _ = horizontal blanking 701ba55f2f5SFrançois Tigeot * hs = horizontal sync 702ba55f2f5SFrançois Tigeot * va = vertical active 703ba55f2f5SFrançois Tigeot * vb = vertical blanking 704ba55f2f5SFrançois Tigeot * vs = vertical sync 705ba55f2f5SFrançois Tigeot * vbs = vblank_start (number) 706ba55f2f5SFrançois Tigeot * 707ba55f2f5SFrançois Tigeot * Summary: 708ba55f2f5SFrançois Tigeot * - most events happen at the start of horizontal sync 709ba55f2f5SFrançois Tigeot * - frame start happens at the start of horizontal blank, 1-4 lines 710ba55f2f5SFrançois Tigeot * (depending on PIPECONF settings) after the start of vblank 711ba55f2f5SFrançois Tigeot * - gen3/4 pixel and frame counter are synchronized with the start 712ba55f2f5SFrançois Tigeot * of horizontal active on the first line of vertical active 713ba55f2f5SFrançois Tigeot */ 714ba55f2f5SFrançois Tigeot 715c4a9e910SFrançois Tigeot /* Called from drm generic code, passed a 'crtc', which 716c4a9e910SFrançois Tigeot * we use as a pipe index 717c4a9e910SFrançois Tigeot */ 718352ff8bdSFrançois Tigeot static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe) 719c4a9e910SFrançois Tigeot { 720303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 721aee94f86SFrançois Tigeot i915_reg_t high_frame, low_frame; 722ba55f2f5SFrançois Tigeot u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; 7234be47400SFrançois Tigeot struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, 7244be47400SFrançois Tigeot pipe); 725a05eeebfSFrançois Tigeot const struct drm_display_mode *mode = &intel_crtc->base.hwmode; 726*a85cb24fSFrançois Tigeot unsigned long irqflags; 7279edbd4a0SFrançois Tigeot 728ba55f2f5SFrançois Tigeot htotal = mode->crtc_htotal; 729ba55f2f5SFrançois Tigeot hsync_start = mode->crtc_hsync_start; 730ba55f2f5SFrançois Tigeot vbl_start = mode->crtc_vblank_start; 731ba55f2f5SFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) 732ba55f2f5SFrançois Tigeot vbl_start = DIV_ROUND_UP(vbl_start, 2); 7339edbd4a0SFrançois Tigeot 734ba55f2f5SFrançois Tigeot /* Convert to pixel count */ 735ba55f2f5SFrançois Tigeot vbl_start *= htotal; 736ba55f2f5SFrançois Tigeot 737ba55f2f5SFrançois Tigeot /* Start of vblank event occurs at start of hsync */ 738ba55f2f5SFrançois Tigeot vbl_start -= htotal - hsync_start; 739ba55f2f5SFrançois Tigeot 740e3adcf8fSFrançois Tigeot high_frame = PIPEFRAME(pipe); 741e3adcf8fSFrançois Tigeot low_frame = PIPEFRAMEPIXEL(pipe); 742e3adcf8fSFrançois Tigeot 743*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 744*a85cb24fSFrançois Tigeot 745c4a9e910SFrançois Tigeot /* 746c4a9e910SFrançois Tigeot * High & low register fields aren't synchronized, so make sure 747c4a9e910SFrançois Tigeot * we get a low value that's stable across two reads of the high 748c4a9e910SFrançois Tigeot * register. 749c4a9e910SFrançois Tigeot */ 750c4a9e910SFrançois Tigeot do { 751*a85cb24fSFrançois Tigeot high1 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK; 752*a85cb24fSFrançois Tigeot low = I915_READ_FW(low_frame); 753*a85cb24fSFrançois Tigeot high2 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK; 754c4a9e910SFrançois Tigeot } while (high1 != high2); 755c4a9e910SFrançois Tigeot 756*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 757*a85cb24fSFrançois Tigeot 758e3adcf8fSFrançois Tigeot high1 >>= PIPE_FRAME_HIGH_SHIFT; 7599edbd4a0SFrançois Tigeot pixel = low & PIPE_PIXEL_MASK; 760e3adcf8fSFrançois Tigeot low >>= PIPE_FRAME_LOW_SHIFT; 7619edbd4a0SFrançois Tigeot 7629edbd4a0SFrançois Tigeot /* 7639edbd4a0SFrançois Tigeot * The frame counter increments at beginning of active. 7649edbd4a0SFrançois Tigeot * Cook up a vblank counter by also checking the pixel 7659edbd4a0SFrançois Tigeot * counter against vblank start. 7669edbd4a0SFrançois Tigeot */ 7679edbd4a0SFrançois Tigeot return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff; 768c4a9e910SFrançois Tigeot } 769c4a9e910SFrançois Tigeot 770352ff8bdSFrançois Tigeot static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe) 771c4a9e910SFrançois Tigeot { 772303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 773c4a9e910SFrançois Tigeot 774352ff8bdSFrançois Tigeot return I915_READ(PIPE_FRMCOUNT_G4X(pipe)); 775c4a9e910SFrançois Tigeot } 776c4a9e910SFrançois Tigeot 777aee94f86SFrançois Tigeot /* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */ 778ba55f2f5SFrançois Tigeot static int __intel_get_crtc_scanline(struct intel_crtc *crtc) 7799edbd4a0SFrançois Tigeot { 780ba55f2f5SFrançois Tigeot struct drm_device *dev = crtc->base.dev; 781303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 782a05eeebfSFrançois Tigeot const struct drm_display_mode *mode = &crtc->base.hwmode; 783ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 784ba55f2f5SFrançois Tigeot int position, vtotal; 7859edbd4a0SFrançois Tigeot 786*a85cb24fSFrançois Tigeot if (!crtc->active) 787*a85cb24fSFrançois Tigeot return -1; 788*a85cb24fSFrançois Tigeot 789ba55f2f5SFrançois Tigeot vtotal = mode->crtc_vtotal; 790ba55f2f5SFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) 791ba55f2f5SFrançois Tigeot vtotal /= 2; 7929edbd4a0SFrançois Tigeot 7931487f786SFrançois Tigeot if (IS_GEN2(dev_priv)) 794aee94f86SFrançois Tigeot position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; 795ba55f2f5SFrançois Tigeot else 796aee94f86SFrançois Tigeot position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; 797ba55f2f5SFrançois Tigeot 798ba55f2f5SFrançois Tigeot /* 799a05eeebfSFrançois Tigeot * On HSW, the DSL reg (0x70000) appears to return 0 if we 800a05eeebfSFrançois Tigeot * read it just before the start of vblank. So try it again 801a05eeebfSFrançois Tigeot * so we don't accidentally end up spanning a vblank frame 802a05eeebfSFrançois Tigeot * increment, causing the pipe_update_end() code to squak at us. 803a05eeebfSFrançois Tigeot * 804a05eeebfSFrançois Tigeot * The nature of this problem means we can't simply check the ISR 805a05eeebfSFrançois Tigeot * bit and return the vblank start value; nor can we use the scanline 806a05eeebfSFrançois Tigeot * debug register in the transcoder as it appears to have the same 807a05eeebfSFrançois Tigeot * problem. We may need to extend this to include other platforms, 808a05eeebfSFrançois Tigeot * but so far testing only shows the problem on HSW. 809a05eeebfSFrançois Tigeot */ 8101487f786SFrançois Tigeot if (HAS_DDI(dev_priv) && !position) { 811a05eeebfSFrançois Tigeot int i, temp; 812a05eeebfSFrançois Tigeot 813a05eeebfSFrançois Tigeot for (i = 0; i < 100; i++) { 814a05eeebfSFrançois Tigeot udelay(1); 815*a85cb24fSFrançois Tigeot temp = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; 816a05eeebfSFrançois Tigeot if (temp != position) { 817a05eeebfSFrançois Tigeot position = temp; 818a05eeebfSFrançois Tigeot break; 819a05eeebfSFrançois Tigeot } 820a05eeebfSFrançois Tigeot } 821a05eeebfSFrançois Tigeot } 822a05eeebfSFrançois Tigeot 823a05eeebfSFrançois Tigeot /* 824ba55f2f5SFrançois Tigeot * See update_scanline_offset() for the details on the 825ba55f2f5SFrançois Tigeot * scanline_offset adjustment. 826ba55f2f5SFrançois Tigeot */ 827ba55f2f5SFrançois Tigeot return (position + crtc->scanline_offset) % vtotal; 8289edbd4a0SFrançois Tigeot } 8299edbd4a0SFrançois Tigeot 830352ff8bdSFrançois Tigeot static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, 831782e40d3SFrançois Tigeot unsigned int flags, int *vpos, int *hpos, 832352ff8bdSFrançois Tigeot ktime_t *stime, ktime_t *etime, 833352ff8bdSFrançois Tigeot const struct drm_display_mode *mode) 834e3adcf8fSFrançois Tigeot { 835303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 8364be47400SFrançois Tigeot struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, 8374be47400SFrançois Tigeot pipe); 8389edbd4a0SFrançois Tigeot int position; 839ba55f2f5SFrançois Tigeot int vbl_start, vbl_end, hsync_start, htotal, vtotal; 840e3adcf8fSFrançois Tigeot bool in_vbl = true; 841e3adcf8fSFrançois Tigeot int ret = 0; 8425e269720SFrançois Tigeot unsigned long irqflags; 843e3adcf8fSFrançois Tigeot 844a05eeebfSFrançois Tigeot if (WARN_ON(!mode->crtc_clock)) { 84500640ec9SFrançois Tigeot DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " 846e3adcf8fSFrançois Tigeot "pipe %c\n", pipe_name(pipe)); 847e3adcf8fSFrançois Tigeot return 0; 848e3adcf8fSFrançois Tigeot } 849e3adcf8fSFrançois Tigeot 8509edbd4a0SFrançois Tigeot htotal = mode->crtc_htotal; 851ba55f2f5SFrançois Tigeot hsync_start = mode->crtc_hsync_start; 8529edbd4a0SFrançois Tigeot vtotal = mode->crtc_vtotal; 8539edbd4a0SFrançois Tigeot vbl_start = mode->crtc_vblank_start; 8549edbd4a0SFrançois Tigeot vbl_end = mode->crtc_vblank_end; 855e3adcf8fSFrançois Tigeot 8569edbd4a0SFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) { 8579edbd4a0SFrançois Tigeot vbl_start = DIV_ROUND_UP(vbl_start, 2); 8589edbd4a0SFrançois Tigeot vbl_end /= 2; 8599edbd4a0SFrançois Tigeot vtotal /= 2; 8609edbd4a0SFrançois Tigeot } 8619edbd4a0SFrançois Tigeot 8629edbd4a0SFrançois Tigeot ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; 8639edbd4a0SFrançois Tigeot 8649edbd4a0SFrançois Tigeot /* 8659edbd4a0SFrançois Tigeot * Lock uncore.lock, as we will do multiple timing critical raw 8669edbd4a0SFrançois Tigeot * register reads, potentially with preemption disabled, so the 8679edbd4a0SFrançois Tigeot * following code must not block on uncore.lock. 8689edbd4a0SFrançois Tigeot */ 8695e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 8709edbd4a0SFrançois Tigeot 8719edbd4a0SFrançois Tigeot /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ 8729edbd4a0SFrançois Tigeot 8739edbd4a0SFrançois Tigeot /* Get optional system timestamp before query. */ 8749edbd4a0SFrançois Tigeot if (stime) 8759edbd4a0SFrançois Tigeot *stime = ktime_get(); 8769edbd4a0SFrançois Tigeot 8771487f786SFrançois Tigeot if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { 878e3adcf8fSFrançois Tigeot /* No obvious pixelcount register. Only query vertical 879e3adcf8fSFrançois Tigeot * scanout position from Display scan line register. 880e3adcf8fSFrançois Tigeot */ 881ba55f2f5SFrançois Tigeot position = __intel_get_crtc_scanline(intel_crtc); 882e3adcf8fSFrançois Tigeot } else { 883e3adcf8fSFrançois Tigeot /* Have access to pixelcount since start of frame. 884e3adcf8fSFrançois Tigeot * We can split this into vertical and horizontal 885e3adcf8fSFrançois Tigeot * scanout position. 886e3adcf8fSFrançois Tigeot */ 887aee94f86SFrançois Tigeot position = (I915_READ_FW(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; 888e3adcf8fSFrançois Tigeot 8899edbd4a0SFrançois Tigeot /* convert to pixel counts */ 8909edbd4a0SFrançois Tigeot vbl_start *= htotal; 8919edbd4a0SFrançois Tigeot vbl_end *= htotal; 8929edbd4a0SFrançois Tigeot vtotal *= htotal; 893ba55f2f5SFrançois Tigeot 894ba55f2f5SFrançois Tigeot /* 895ba55f2f5SFrançois Tigeot * In interlaced modes, the pixel counter counts all pixels, 896ba55f2f5SFrançois Tigeot * so one field will have htotal more pixels. In order to avoid 897ba55f2f5SFrançois Tigeot * the reported position from jumping backwards when the pixel 898ba55f2f5SFrançois Tigeot * counter is beyond the length of the shorter field, just 899ba55f2f5SFrançois Tigeot * clamp the position the length of the shorter field. This 900ba55f2f5SFrançois Tigeot * matches how the scanline counter based position works since 901ba55f2f5SFrançois Tigeot * the scanline counter doesn't count the two half lines. 902ba55f2f5SFrançois Tigeot */ 903ba55f2f5SFrançois Tigeot if (position >= vtotal) 904ba55f2f5SFrançois Tigeot position = vtotal - 1; 905ba55f2f5SFrançois Tigeot 906ba55f2f5SFrançois Tigeot /* 907ba55f2f5SFrançois Tigeot * Start of vblank interrupt is triggered at start of hsync, 908ba55f2f5SFrançois Tigeot * just prior to the first active line of vblank. However we 909ba55f2f5SFrançois Tigeot * consider lines to start at the leading edge of horizontal 910ba55f2f5SFrançois Tigeot * active. So, should we get here before we've crossed into 911ba55f2f5SFrançois Tigeot * the horizontal active of the first line in vblank, we would 912ba55f2f5SFrançois Tigeot * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that, 913ba55f2f5SFrançois Tigeot * always add htotal-hsync_start to the current pixel position. 914ba55f2f5SFrançois Tigeot */ 915ba55f2f5SFrançois Tigeot position = (position + htotal - hsync_start) % vtotal; 9169edbd4a0SFrançois Tigeot } 9179edbd4a0SFrançois Tigeot 9189edbd4a0SFrançois Tigeot /* Get optional system timestamp after query. */ 9199edbd4a0SFrançois Tigeot if (etime) 9209edbd4a0SFrançois Tigeot *etime = ktime_get(); 9219edbd4a0SFrançois Tigeot 9229edbd4a0SFrançois Tigeot /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ 9239edbd4a0SFrançois Tigeot 9245e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 9259edbd4a0SFrançois Tigeot 9269edbd4a0SFrançois Tigeot in_vbl = position >= vbl_start && position < vbl_end; 9279edbd4a0SFrançois Tigeot 9289edbd4a0SFrançois Tigeot /* 9299edbd4a0SFrançois Tigeot * While in vblank, position will be negative 9309edbd4a0SFrançois Tigeot * counting up towards 0 at vbl_end. And outside 9319edbd4a0SFrançois Tigeot * vblank, position will be positive counting 9329edbd4a0SFrançois Tigeot * up since vbl_end. 9339edbd4a0SFrançois Tigeot */ 9349edbd4a0SFrançois Tigeot if (position >= vbl_start) 9359edbd4a0SFrançois Tigeot position -= vbl_end; 9369edbd4a0SFrançois Tigeot else 9379edbd4a0SFrançois Tigeot position += vtotal - vbl_end; 9389edbd4a0SFrançois Tigeot 9391487f786SFrançois Tigeot if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { 9409edbd4a0SFrançois Tigeot *vpos = position; 9419edbd4a0SFrançois Tigeot *hpos = 0; 9429edbd4a0SFrançois Tigeot } else { 943e3adcf8fSFrançois Tigeot *vpos = position / htotal; 944e3adcf8fSFrançois Tigeot *hpos = position - (*vpos * htotal); 945e3adcf8fSFrançois Tigeot } 946e3adcf8fSFrançois Tigeot 947e3adcf8fSFrançois Tigeot /* In vblank? */ 948e3adcf8fSFrançois Tigeot if (in_vbl) 9491b13d190SFrançois Tigeot ret |= DRM_SCANOUTPOS_IN_VBLANK; 950e3adcf8fSFrançois Tigeot 951e3adcf8fSFrançois Tigeot return ret; 952e3adcf8fSFrançois Tigeot } 953e3adcf8fSFrançois Tigeot 954ba55f2f5SFrançois Tigeot int intel_get_crtc_scanline(struct intel_crtc *crtc) 955ba55f2f5SFrançois Tigeot { 956303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 9575e269720SFrançois Tigeot unsigned long irqflags; 958ba55f2f5SFrançois Tigeot int position; 959ba55f2f5SFrançois Tigeot 9605e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 961ba55f2f5SFrançois Tigeot position = __intel_get_crtc_scanline(crtc); 9625e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 963ba55f2f5SFrançois Tigeot 964ba55f2f5SFrançois Tigeot return position; 965ba55f2f5SFrançois Tigeot } 966ba55f2f5SFrançois Tigeot 967352ff8bdSFrançois Tigeot static int i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, 96800640ec9SFrançois Tigeot int *max_error, 96900640ec9SFrançois Tigeot struct timeval *vblank_time, 97000640ec9SFrançois Tigeot unsigned flags) 971e3adcf8fSFrançois Tigeot { 9724be47400SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 9734be47400SFrançois Tigeot struct intel_crtc *crtc; 974e3adcf8fSFrançois Tigeot 9754be47400SFrançois Tigeot if (pipe >= INTEL_INFO(dev_priv)->num_pipes) { 976352ff8bdSFrançois Tigeot DRM_ERROR("Invalid crtc %u\n", pipe); 977e3adcf8fSFrançois Tigeot return -EINVAL; 978e3adcf8fSFrançois Tigeot } 979e3adcf8fSFrançois Tigeot 980e3adcf8fSFrançois Tigeot /* Get drm_crtc to timestamp: */ 9814be47400SFrançois Tigeot crtc = intel_get_crtc_for_pipe(dev_priv, pipe); 982e3adcf8fSFrançois Tigeot if (crtc == NULL) { 983352ff8bdSFrançois Tigeot DRM_ERROR("Invalid crtc %u\n", pipe); 984e3adcf8fSFrançois Tigeot return -EINVAL; 985e3adcf8fSFrançois Tigeot } 986e3adcf8fSFrançois Tigeot 9874be47400SFrançois Tigeot if (!crtc->base.hwmode.crtc_clock) { 988352ff8bdSFrançois Tigeot DRM_DEBUG_KMS("crtc %u is disabled\n", pipe); 989e3adcf8fSFrançois Tigeot return -EBUSY; 990e3adcf8fSFrançois Tigeot } 991e3adcf8fSFrançois Tigeot 992e3adcf8fSFrançois Tigeot /* Helper routine in DRM core does all the work: */ 993e3adcf8fSFrançois Tigeot return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, 994e3adcf8fSFrançois Tigeot vblank_time, flags, 9954be47400SFrançois Tigeot &crtc->base.hwmode); 996e3adcf8fSFrançois Tigeot } 997e3adcf8fSFrançois Tigeot 9981487f786SFrançois Tigeot static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv) 999e3adcf8fSFrançois Tigeot { 1000e3adcf8fSFrançois Tigeot u32 busy_up, busy_down, max_avg, min_avg; 1001a2296444SFrançois Tigeot u8 new_delay; 1002a2296444SFrançois Tigeot 1003a2296444SFrançois Tigeot lockmgr(&mchdev_lock, LK_EXCLUSIVE); 1004a2296444SFrançois Tigeot 1005a2296444SFrançois Tigeot I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); 1006a2296444SFrançois Tigeot 100700640ec9SFrançois Tigeot new_delay = dev_priv->ips.cur_delay; 1008e3adcf8fSFrançois Tigeot 1009e3adcf8fSFrançois Tigeot I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); 1010e3adcf8fSFrançois Tigeot busy_up = I915_READ(RCPREVBSYTUPAVG); 1011e3adcf8fSFrançois Tigeot busy_down = I915_READ(RCPREVBSYTDNAVG); 1012e3adcf8fSFrançois Tigeot max_avg = I915_READ(RCBMAXAVG); 1013e3adcf8fSFrançois Tigeot min_avg = I915_READ(RCBMINAVG); 1014e3adcf8fSFrançois Tigeot 1015e3adcf8fSFrançois Tigeot /* Handle RCS change request from hw */ 1016e3adcf8fSFrançois Tigeot if (busy_up > max_avg) { 101700640ec9SFrançois Tigeot if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay) 101800640ec9SFrançois Tigeot new_delay = dev_priv->ips.cur_delay - 1; 101900640ec9SFrançois Tigeot if (new_delay < dev_priv->ips.max_delay) 102000640ec9SFrançois Tigeot new_delay = dev_priv->ips.max_delay; 1021e3adcf8fSFrançois Tigeot } else if (busy_down < min_avg) { 102200640ec9SFrançois Tigeot if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay) 102300640ec9SFrançois Tigeot new_delay = dev_priv->ips.cur_delay + 1; 102400640ec9SFrançois Tigeot if (new_delay > dev_priv->ips.min_delay) 102500640ec9SFrançois Tigeot new_delay = dev_priv->ips.min_delay; 1026e3adcf8fSFrançois Tigeot } 1027e3adcf8fSFrançois Tigeot 10281487f786SFrançois Tigeot if (ironlake_set_drps(dev_priv, new_delay)) 102900640ec9SFrançois Tigeot dev_priv->ips.cur_delay = new_delay; 1030e3adcf8fSFrançois Tigeot 1031a2296444SFrançois Tigeot lockmgr(&mchdev_lock, LK_RELEASE); 1032a2296444SFrançois Tigeot 1033e3adcf8fSFrançois Tigeot return; 1034e3adcf8fSFrançois Tigeot } 1035e3adcf8fSFrançois Tigeot 10368621f407SFrançois Tigeot static void notify_ring(struct intel_engine_cs *engine) 1037e3adcf8fSFrançois Tigeot { 1038*a85cb24fSFrançois Tigeot struct drm_i915_gem_request *rq = NULL; 1039*a85cb24fSFrançois Tigeot struct intel_wait *wait; 1040*a85cb24fSFrançois Tigeot 1041*a85cb24fSFrançois Tigeot atomic_inc(&engine->irq_count); 1042*a85cb24fSFrançois Tigeot set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted); 1043*a85cb24fSFrançois Tigeot 1044*a85cb24fSFrançois Tigeot lockmgr(&engine->breadcrumbs.irq_lock, LK_EXCLUSIVE); 1045*a85cb24fSFrançois Tigeot wait = engine->breadcrumbs.irq_wait; 1046*a85cb24fSFrançois Tigeot if (wait) { 1047*a85cb24fSFrançois Tigeot /* We use a callback from the dma-fence to submit 1048*a85cb24fSFrançois Tigeot * requests after waiting on our own requests. To 1049*a85cb24fSFrançois Tigeot * ensure minimum delay in queuing the next request to 1050*a85cb24fSFrançois Tigeot * hardware, signal the fence now rather than wait for 1051*a85cb24fSFrançois Tigeot * the signaler to be woken up. We still wake up the 1052*a85cb24fSFrançois Tigeot * waiter in order to handle the irq-seqno coherency 1053*a85cb24fSFrançois Tigeot * issues (we may receive the interrupt before the 1054*a85cb24fSFrançois Tigeot * seqno is written, see __i915_request_irq_complete()) 1055*a85cb24fSFrançois Tigeot * and to handle coalescing of multiple seqno updates 1056*a85cb24fSFrançois Tigeot * and many waiters. 1057*a85cb24fSFrançois Tigeot */ 1058*a85cb24fSFrançois Tigeot if (i915_seqno_passed(intel_engine_get_seqno(engine), 1059*a85cb24fSFrançois Tigeot wait->seqno) && 1060*a85cb24fSFrançois Tigeot !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, 1061*a85cb24fSFrançois Tigeot &wait->request->fence.flags)) 1062*a85cb24fSFrançois Tigeot rq = i915_gem_request_get(wait->request); 1063*a85cb24fSFrançois Tigeot 1064*a85cb24fSFrançois Tigeot wake_up_process(wait->tsk); 1065*a85cb24fSFrançois Tigeot } else { 1066*a85cb24fSFrançois Tigeot __intel_engine_disarm_breadcrumbs(engine); 1067*a85cb24fSFrançois Tigeot } 1068*a85cb24fSFrançois Tigeot lockmgr(&engine->breadcrumbs.irq_lock, LK_RELEASE); 1069*a85cb24fSFrançois Tigeot 1070*a85cb24fSFrançois Tigeot if (rq) { 1071*a85cb24fSFrançois Tigeot dma_fence_signal(&rq->fence); 1072*a85cb24fSFrançois Tigeot i915_gem_request_put(rq); 1073*a85cb24fSFrançois Tigeot } 1074*a85cb24fSFrançois Tigeot 1075*a85cb24fSFrançois Tigeot trace_intel_engine_notify(engine, wait); 1076e3adcf8fSFrançois Tigeot } 1077e3adcf8fSFrançois Tigeot 1078477eb7f9SFrançois Tigeot static void vlv_c0_read(struct drm_i915_private *dev_priv, 1079477eb7f9SFrançois Tigeot struct intel_rps_ei *ei) 108024edb884SFrançois Tigeot { 1081*a85cb24fSFrançois Tigeot ei->ktime = ktime_get_raw(); 1082477eb7f9SFrançois Tigeot ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT); 1083477eb7f9SFrançois Tigeot ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT); 108424edb884SFrançois Tigeot } 108524edb884SFrançois Tigeot 1086477eb7f9SFrançois Tigeot void gen6_rps_reset_ei(struct drm_i915_private *dev_priv) 1087477eb7f9SFrançois Tigeot { 10884be47400SFrançois Tigeot memset(&dev_priv->rps.ei, 0, sizeof(dev_priv->rps.ei)); 108924edb884SFrançois Tigeot } 109024edb884SFrançois Tigeot 1091477eb7f9SFrançois Tigeot static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir) 1092477eb7f9SFrançois Tigeot { 10934be47400SFrançois Tigeot const struct intel_rps_ei *prev = &dev_priv->rps.ei; 1094477eb7f9SFrançois Tigeot struct intel_rps_ei now; 1095477eb7f9SFrançois Tigeot u32 events = 0; 109624edb884SFrançois Tigeot 10974be47400SFrançois Tigeot if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0) 1098477eb7f9SFrançois Tigeot return 0; 109924edb884SFrançois Tigeot 1100477eb7f9SFrançois Tigeot vlv_c0_read(dev_priv, &now); 110124edb884SFrançois Tigeot 1102*a85cb24fSFrançois Tigeot if (prev->ktime) { 11034be47400SFrançois Tigeot u64 time, c0; 1104*a85cb24fSFrançois Tigeot u32 render, media; 11054be47400SFrançois Tigeot 1106*a85cb24fSFrançois Tigeot time = ktime_us_delta(now.ktime, prev->ktime); 11074be47400SFrançois Tigeot 11084be47400SFrançois Tigeot time *= dev_priv->czclk_freq; 11094be47400SFrançois Tigeot 11104be47400SFrançois Tigeot /* Workload can be split between render + media, 11114be47400SFrançois Tigeot * e.g. SwapBuffers being blitted in X after being rendered in 11124be47400SFrançois Tigeot * mesa. To account for this we need to combine both engines 11134be47400SFrançois Tigeot * into our activity counter. 11144be47400SFrançois Tigeot */ 1115*a85cb24fSFrançois Tigeot render = now.render_c0 - prev->render_c0; 1116*a85cb24fSFrançois Tigeot media = now.media_c0 - prev->media_c0; 1117*a85cb24fSFrançois Tigeot c0 = max(render, media); 1118*a85cb24fSFrançois Tigeot c0 *= 1000 * 100 << 8; /* to usecs and scale to threshold% */ 11194be47400SFrançois Tigeot 11204be47400SFrançois Tigeot if (c0 > time * dev_priv->rps.up_threshold) 11214be47400SFrançois Tigeot events = GEN6_PM_RP_UP_THRESHOLD; 11224be47400SFrançois Tigeot else if (c0 < time * dev_priv->rps.down_threshold) 11234be47400SFrançois Tigeot events = GEN6_PM_RP_DOWN_THRESHOLD; 112424edb884SFrançois Tigeot } 112524edb884SFrançois Tigeot 11264be47400SFrançois Tigeot dev_priv->rps.ei = now; 1127477eb7f9SFrançois Tigeot return events; 112824edb884SFrançois Tigeot } 112924edb884SFrançois Tigeot 113019c468b4SFrançois Tigeot static bool any_waiters(struct drm_i915_private *dev_priv) 113119c468b4SFrançois Tigeot { 11328621f407SFrançois Tigeot struct intel_engine_cs *engine; 11331e12ee3bSFrançois Tigeot enum intel_engine_id id; 113419c468b4SFrançois Tigeot 11351e12ee3bSFrançois Tigeot for_each_engine(engine, dev_priv, id) 1136303bf270SFrançois Tigeot if (intel_engine_has_waiter(engine)) 113719c468b4SFrançois Tigeot return true; 113819c468b4SFrançois Tigeot 113919c468b4SFrançois Tigeot return false; 114019c468b4SFrançois Tigeot } 114119c468b4SFrançois Tigeot 1142abf1f4f4SFrançois Tigeot static void gen6_pm_rps_work(struct work_struct *work) 1143e3adcf8fSFrançois Tigeot { 1144ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = 1145ba55f2f5SFrançois Tigeot container_of(work, struct drm_i915_private, rps.work); 1146*a85cb24fSFrançois Tigeot bool client_boost = false; 114719c468b4SFrançois Tigeot int new_delay, adj, min, max; 1148*a85cb24fSFrançois Tigeot u32 pm_iir = 0; 1149e3adcf8fSFrançois Tigeot 11505e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 1151*a85cb24fSFrançois Tigeot if (dev_priv->rps.interrupts_enabled) { 1152*a85cb24fSFrançois Tigeot pm_iir = fetch_and_zero(&dev_priv->rps.pm_iir); 1153*a85cb24fSFrançois Tigeot client_boost = fetch_and_zero(&dev_priv->rps.client_boost); 11542c9916cdSFrançois Tigeot } 11555e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 11569edbd4a0SFrançois Tigeot 11579edbd4a0SFrançois Tigeot /* Make sure we didn't queue anything we're not going to process. */ 1158ba55f2f5SFrançois Tigeot WARN_ON(pm_iir & ~dev_priv->pm_rps_events); 115919c468b4SFrançois Tigeot if ((pm_iir & dev_priv->pm_rps_events) == 0 && !client_boost) 1160*a85cb24fSFrançois Tigeot goto out; 1161e3adcf8fSFrançois Tigeot 1162a2fdbec6SFrançois Tigeot mutex_lock(&dev_priv->rps.hw_lock); 1163e3adcf8fSFrançois Tigeot 1164477eb7f9SFrançois Tigeot pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir); 1165477eb7f9SFrançois Tigeot 11669edbd4a0SFrançois Tigeot adj = dev_priv->rps.last_adj; 116719c468b4SFrançois Tigeot new_delay = dev_priv->rps.cur_freq; 116819c468b4SFrançois Tigeot min = dev_priv->rps.min_freq_softlimit; 116919c468b4SFrançois Tigeot max = dev_priv->rps.max_freq_softlimit; 117087df8fc6SFrançois Tigeot if (client_boost || any_waiters(dev_priv)) 117187df8fc6SFrançois Tigeot max = dev_priv->rps.max_freq; 117287df8fc6SFrançois Tigeot if (client_boost && new_delay < dev_priv->rps.boost_freq) { 117387df8fc6SFrançois Tigeot new_delay = dev_priv->rps.boost_freq; 117419c468b4SFrançois Tigeot adj = 0; 117519c468b4SFrançois Tigeot } else if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { 11769edbd4a0SFrançois Tigeot if (adj > 0) 11779edbd4a0SFrançois Tigeot adj *= 2; 117819c468b4SFrançois Tigeot else /* CHV needs even encode values */ 117919c468b4SFrançois Tigeot adj = IS_CHERRYVIEW(dev_priv) ? 2 : 1; 1180*a85cb24fSFrançois Tigeot 1181*a85cb24fSFrançois Tigeot if (new_delay >= dev_priv->rps.max_freq_softlimit) 118219c468b4SFrançois Tigeot adj = 0; 118387df8fc6SFrançois Tigeot } else if (client_boost || any_waiters(dev_priv)) { 118419c468b4SFrançois Tigeot adj = 0; 11859edbd4a0SFrançois Tigeot } else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) { 1186ba55f2f5SFrançois Tigeot if (dev_priv->rps.cur_freq > dev_priv->rps.efficient_freq) 1187ba55f2f5SFrançois Tigeot new_delay = dev_priv->rps.efficient_freq; 1188*a85cb24fSFrançois Tigeot else if (dev_priv->rps.cur_freq > dev_priv->rps.min_freq_softlimit) 1189ba55f2f5SFrançois Tigeot new_delay = dev_priv->rps.min_freq_softlimit; 11909edbd4a0SFrançois Tigeot adj = 0; 11919edbd4a0SFrançois Tigeot } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) { 11929edbd4a0SFrançois Tigeot if (adj < 0) 11939edbd4a0SFrançois Tigeot adj *= 2; 119419c468b4SFrançois Tigeot else /* CHV needs even encode values */ 119519c468b4SFrançois Tigeot adj = IS_CHERRYVIEW(dev_priv) ? -2 : -1; 1196*a85cb24fSFrançois Tigeot 1197*a85cb24fSFrançois Tigeot if (new_delay <= dev_priv->rps.min_freq_softlimit) 1198*a85cb24fSFrançois Tigeot adj = 0; 11999edbd4a0SFrançois Tigeot } else { /* unknown event */ 120019c468b4SFrançois Tigeot adj = 0; 12019edbd4a0SFrançois Tigeot } 1202e3adcf8fSFrançois Tigeot 120319c468b4SFrançois Tigeot dev_priv->rps.last_adj = adj; 120419c468b4SFrançois Tigeot 1205abf1f4f4SFrançois Tigeot /* sysfs frequency interfaces may have snuck in while servicing the 1206abf1f4f4SFrançois Tigeot * interrupt 1207e3adcf8fSFrançois Tigeot */ 120819c468b4SFrançois Tigeot new_delay += adj; 120919c468b4SFrançois Tigeot new_delay = clamp_t(int, new_delay, min, max); 12109edbd4a0SFrançois Tigeot 1211*a85cb24fSFrançois Tigeot if (intel_set_rps(dev_priv, new_delay)) { 1212*a85cb24fSFrançois Tigeot DRM_DEBUG_DRIVER("Failed to set new GPU frequency\n"); 1213*a85cb24fSFrançois Tigeot dev_priv->rps.last_adj = 0; 1214*a85cb24fSFrançois Tigeot } 12155d0b1887SFrançois Tigeot 1216a2fdbec6SFrançois Tigeot mutex_unlock(&dev_priv->rps.hw_lock); 1217*a85cb24fSFrançois Tigeot 1218*a85cb24fSFrançois Tigeot out: 1219*a85cb24fSFrançois Tigeot /* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */ 1220*a85cb24fSFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 1221*a85cb24fSFrançois Tigeot if (dev_priv->rps.interrupts_enabled) 1222*a85cb24fSFrançois Tigeot gen6_unmask_pm_irq(dev_priv, dev_priv->pm_rps_events); 1223*a85cb24fSFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 1224e3adcf8fSFrançois Tigeot } 1225e3adcf8fSFrançois Tigeot 12265e269720SFrançois Tigeot 122700640ec9SFrançois Tigeot /** 122800640ec9SFrançois Tigeot * ivybridge_parity_work - Workqueue called when a parity error interrupt 122900640ec9SFrançois Tigeot * occurred. 123000640ec9SFrançois Tigeot * @work: workqueue struct 123100640ec9SFrançois Tigeot * 123200640ec9SFrançois Tigeot * Doesn't actually do anything except notify userspace. As a consequence of 123300640ec9SFrançois Tigeot * this event, userspace should try to remap the bad rows since statistically 123400640ec9SFrançois Tigeot * it is likely the same row is more likely to go bad again. 123500640ec9SFrançois Tigeot */ 123600640ec9SFrançois Tigeot static void ivybridge_parity_work(struct work_struct *work) 123700640ec9SFrançois Tigeot { 1238ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = 1239ba55f2f5SFrançois Tigeot container_of(work, struct drm_i915_private, l3_parity.error_work); 124000640ec9SFrançois Tigeot u32 error_status, row, bank, subbank; 12419edbd4a0SFrançois Tigeot char *parity_event[6]; 124200640ec9SFrançois Tigeot uint32_t misccpctl; 12439edbd4a0SFrançois Tigeot uint8_t slice = 0; 124400640ec9SFrançois Tigeot 124500640ec9SFrançois Tigeot /* We must turn off DOP level clock gating to access the L3 registers. 124600640ec9SFrançois Tigeot * In order to prevent a get/put style interface, acquire struct mutex 124700640ec9SFrançois Tigeot * any time we access those registers. 124800640ec9SFrançois Tigeot */ 1249303bf270SFrançois Tigeot mutex_lock(&dev_priv->drm.struct_mutex); 125000640ec9SFrançois Tigeot 12519edbd4a0SFrançois Tigeot /* If we've screwed up tracking, just let the interrupt fire again */ 12529edbd4a0SFrançois Tigeot if (WARN_ON(!dev_priv->l3_parity.which_slice)) 12539edbd4a0SFrançois Tigeot goto out; 12549edbd4a0SFrançois Tigeot 125500640ec9SFrançois Tigeot misccpctl = I915_READ(GEN7_MISCCPCTL); 125600640ec9SFrançois Tigeot I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); 125700640ec9SFrançois Tigeot POSTING_READ(GEN7_MISCCPCTL); 125800640ec9SFrançois Tigeot 12599edbd4a0SFrançois Tigeot while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) { 1260aee94f86SFrançois Tigeot i915_reg_t reg; 12619edbd4a0SFrançois Tigeot 12629edbd4a0SFrançois Tigeot slice--; 12638621f407SFrançois Tigeot if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv))) 12649edbd4a0SFrançois Tigeot break; 12659edbd4a0SFrançois Tigeot 12669edbd4a0SFrançois Tigeot dev_priv->l3_parity.which_slice &= ~(1<<slice); 12679edbd4a0SFrançois Tigeot 1268aee94f86SFrançois Tigeot reg = GEN7_L3CDERRST1(slice); 12699edbd4a0SFrançois Tigeot 12709edbd4a0SFrançois Tigeot error_status = I915_READ(reg); 127100640ec9SFrançois Tigeot row = GEN7_PARITY_ERROR_ROW(error_status); 127200640ec9SFrançois Tigeot bank = GEN7_PARITY_ERROR_BANK(error_status); 127300640ec9SFrançois Tigeot subbank = GEN7_PARITY_ERROR_SUBBANK(error_status); 127400640ec9SFrançois Tigeot 12759edbd4a0SFrançois Tigeot I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE); 12769edbd4a0SFrançois Tigeot POSTING_READ(reg); 12779edbd4a0SFrançois Tigeot 12789edbd4a0SFrançois Tigeot parity_event[0] = I915_L3_PARITY_UEVENT "=1"; 1279c0e85e96SFrançois Tigeot parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row); 1280c0e85e96SFrançois Tigeot parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank); 1281c0e85e96SFrançois Tigeot parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank); 1282c0e85e96SFrançois Tigeot parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice); 12839edbd4a0SFrançois Tigeot parity_event[5] = NULL; 12849edbd4a0SFrançois Tigeot 1285303bf270SFrançois Tigeot kobject_uevent_env(&dev_priv->drm.primary->kdev->kobj, 12869edbd4a0SFrançois Tigeot KOBJ_CHANGE, parity_event); 12879edbd4a0SFrançois Tigeot 12889edbd4a0SFrançois Tigeot DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n", 12899edbd4a0SFrançois Tigeot slice, row, bank, subbank); 12909edbd4a0SFrançois Tigeot 12919edbd4a0SFrançois Tigeot kfree(parity_event[4]); 12929edbd4a0SFrançois Tigeot kfree(parity_event[3]); 12939edbd4a0SFrançois Tigeot kfree(parity_event[2]); 12949edbd4a0SFrançois Tigeot kfree(parity_event[1]); 12959edbd4a0SFrançois Tigeot } 129600640ec9SFrançois Tigeot 129700640ec9SFrançois Tigeot I915_WRITE(GEN7_MISCCPCTL, misccpctl); 129800640ec9SFrançois Tigeot 12999edbd4a0SFrançois Tigeot out: 13009edbd4a0SFrançois Tigeot WARN_ON(dev_priv->l3_parity.which_slice); 13015e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 13028621f407SFrançois Tigeot gen5_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv)); 13035e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 130400640ec9SFrançois Tigeot 1305303bf270SFrançois Tigeot mutex_unlock(&dev_priv->drm.struct_mutex); 130600640ec9SFrançois Tigeot } 130700640ec9SFrançois Tigeot 13088621f407SFrançois Tigeot static void ivybridge_parity_error_irq_handler(struct drm_i915_private *dev_priv, 13098621f407SFrançois Tigeot u32 iir) 131000640ec9SFrançois Tigeot { 13118621f407SFrançois Tigeot if (!HAS_L3_DPF(dev_priv)) 131200640ec9SFrançois Tigeot return; 131300640ec9SFrançois Tigeot 131400640ec9SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 13158621f407SFrançois Tigeot gen5_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv)); 131600640ec9SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 131700640ec9SFrançois Tigeot 13188621f407SFrançois Tigeot iir &= GT_PARITY_ERROR(dev_priv); 13199edbd4a0SFrançois Tigeot if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1) 13209edbd4a0SFrançois Tigeot dev_priv->l3_parity.which_slice |= 1 << 1; 13219edbd4a0SFrançois Tigeot 13229edbd4a0SFrançois Tigeot if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT) 13239edbd4a0SFrançois Tigeot dev_priv->l3_parity.which_slice |= 1 << 0; 13249edbd4a0SFrançois Tigeot 132500640ec9SFrançois Tigeot queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work); 132600640ec9SFrançois Tigeot } 132700640ec9SFrançois Tigeot 13288621f407SFrançois Tigeot static void ilk_gt_irq_handler(struct drm_i915_private *dev_priv, 13299edbd4a0SFrançois Tigeot u32 gt_iir) 13309edbd4a0SFrançois Tigeot { 1331303bf270SFrançois Tigeot if (gt_iir & GT_RENDER_USER_INTERRUPT) 13321e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[RCS]); 13339edbd4a0SFrançois Tigeot if (gt_iir & ILK_BSD_USER_INTERRUPT) 13341e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[VCS]); 13359edbd4a0SFrançois Tigeot } 13369edbd4a0SFrançois Tigeot 13378621f407SFrançois Tigeot static void snb_gt_irq_handler(struct drm_i915_private *dev_priv, 1338a2296444SFrançois Tigeot u32 gt_iir) 1339a2296444SFrançois Tigeot { 1340303bf270SFrançois Tigeot if (gt_iir & GT_RENDER_USER_INTERRUPT) 13411e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[RCS]); 13425d0b1887SFrançois Tigeot if (gt_iir & GT_BSD_USER_INTERRUPT) 13431e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[VCS]); 13445d0b1887SFrançois Tigeot if (gt_iir & GT_BLT_USER_INTERRUPT) 13451e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[BCS]); 1346a2296444SFrançois Tigeot 13475d0b1887SFrançois Tigeot if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT | 13485d0b1887SFrançois Tigeot GT_BSD_CS_ERROR_INTERRUPT | 13492c9916cdSFrançois Tigeot GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) 13502c9916cdSFrançois Tigeot DRM_DEBUG("Command parser error, gt_iir 0x%08x\n", gt_iir); 1351a2296444SFrançois Tigeot 13528621f407SFrançois Tigeot if (gt_iir & GT_PARITY_ERROR(dev_priv)) 13538621f407SFrançois Tigeot ivybridge_parity_error_irq_handler(dev_priv, gt_iir); 1354a2296444SFrançois Tigeot } 1355a2296444SFrançois Tigeot 1356aee94f86SFrançois Tigeot static __always_inline void 13578621f407SFrançois Tigeot gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift) 1358aee94f86SFrançois Tigeot { 1359*a85cb24fSFrançois Tigeot bool tasklet = false; 1360*a85cb24fSFrançois Tigeot 1361*a85cb24fSFrançois Tigeot if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift)) { 1362*a85cb24fSFrançois Tigeot set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); 1363*a85cb24fSFrançois Tigeot tasklet = true; 1364*a85cb24fSFrançois Tigeot } 1365*a85cb24fSFrançois Tigeot 1366*a85cb24fSFrançois Tigeot if (iir & (GT_RENDER_USER_INTERRUPT << test_shift)) { 13678621f407SFrançois Tigeot notify_ring(engine); 1368*a85cb24fSFrançois Tigeot tasklet |= i915.enable_guc_submission; 1369*a85cb24fSFrançois Tigeot } 1370*a85cb24fSFrançois Tigeot 1371*a85cb24fSFrançois Tigeot if (tasklet) 1372*a85cb24fSFrançois Tigeot tasklet_hi_schedule(&engine->irq_tasklet); 1373aee94f86SFrançois Tigeot } 1374aee94f86SFrançois Tigeot 13758621f407SFrançois Tigeot static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv, 13768621f407SFrançois Tigeot u32 master_ctl, 13778621f407SFrançois Tigeot u32 gt_iir[4]) 1378a2296444SFrançois Tigeot { 1379183e2373SFrançois Tigeot irqreturn_t ret = IRQ_NONE; 1380a2296444SFrançois Tigeot 13819edbd4a0SFrançois Tigeot if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { 13828621f407SFrançois Tigeot gt_iir[0] = I915_READ_FW(GEN8_GT_IIR(0)); 13838621f407SFrançois Tigeot if (gt_iir[0]) { 13848621f407SFrançois Tigeot I915_WRITE_FW(GEN8_GT_IIR(0), gt_iir[0]); 1385183e2373SFrançois Tigeot ret = IRQ_HANDLED; 13869edbd4a0SFrançois Tigeot } else 13879edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (GT0)!\n"); 13889edbd4a0SFrançois Tigeot } 1389a2296444SFrançois Tigeot 1390ba55f2f5SFrançois Tigeot if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) { 13918621f407SFrançois Tigeot gt_iir[1] = I915_READ_FW(GEN8_GT_IIR(1)); 13928621f407SFrançois Tigeot if (gt_iir[1]) { 13938621f407SFrançois Tigeot I915_WRITE_FW(GEN8_GT_IIR(1), gt_iir[1]); 1394183e2373SFrançois Tigeot ret = IRQ_HANDLED; 13959edbd4a0SFrançois Tigeot } else 13969edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (GT1)!\n"); 13979edbd4a0SFrançois Tigeot } 1398a2296444SFrançois Tigeot 139919c468b4SFrançois Tigeot if (master_ctl & GEN8_GT_VECS_IRQ) { 14008621f407SFrançois Tigeot gt_iir[3] = I915_READ_FW(GEN8_GT_IIR(3)); 14018621f407SFrançois Tigeot if (gt_iir[3]) { 14028621f407SFrançois Tigeot I915_WRITE_FW(GEN8_GT_IIR(3), gt_iir[3]); 1403183e2373SFrançois Tigeot ret = IRQ_HANDLED; 140419c468b4SFrançois Tigeot } else 140519c468b4SFrançois Tigeot DRM_ERROR("The master control interrupt lied (GT3)!\n"); 140619c468b4SFrançois Tigeot } 140719c468b4SFrançois Tigeot 14084be47400SFrançois Tigeot if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) { 14098621f407SFrançois Tigeot gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2)); 14104be47400SFrançois Tigeot if (gt_iir[2] & (dev_priv->pm_rps_events | 14114be47400SFrançois Tigeot dev_priv->pm_guc_events)) { 141219c468b4SFrançois Tigeot I915_WRITE_FW(GEN8_GT_IIR(2), 14134be47400SFrançois Tigeot gt_iir[2] & (dev_priv->pm_rps_events | 14144be47400SFrançois Tigeot dev_priv->pm_guc_events)); 1415183e2373SFrançois Tigeot ret = IRQ_HANDLED; 1416ba55f2f5SFrançois Tigeot } else 1417ba55f2f5SFrançois Tigeot DRM_ERROR("The master control interrupt lied (PM)!\n"); 1418ba55f2f5SFrançois Tigeot } 1419ba55f2f5SFrançois Tigeot 1420183e2373SFrançois Tigeot return ret; 1421a2296444SFrançois Tigeot } 1422a2296444SFrançois Tigeot 14238621f407SFrançois Tigeot static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv, 14248621f407SFrançois Tigeot u32 gt_iir[4]) 14258621f407SFrançois Tigeot { 14268621f407SFrançois Tigeot if (gt_iir[0]) { 14271e12ee3bSFrançois Tigeot gen8_cs_irq_handler(dev_priv->engine[RCS], 14288621f407SFrançois Tigeot gt_iir[0], GEN8_RCS_IRQ_SHIFT); 14291e12ee3bSFrançois Tigeot gen8_cs_irq_handler(dev_priv->engine[BCS], 14308621f407SFrançois Tigeot gt_iir[0], GEN8_BCS_IRQ_SHIFT); 14318621f407SFrançois Tigeot } 14328621f407SFrançois Tigeot 14338621f407SFrançois Tigeot if (gt_iir[1]) { 14341e12ee3bSFrançois Tigeot gen8_cs_irq_handler(dev_priv->engine[VCS], 14358621f407SFrançois Tigeot gt_iir[1], GEN8_VCS1_IRQ_SHIFT); 14361e12ee3bSFrançois Tigeot gen8_cs_irq_handler(dev_priv->engine[VCS2], 14378621f407SFrançois Tigeot gt_iir[1], GEN8_VCS2_IRQ_SHIFT); 14388621f407SFrançois Tigeot } 14398621f407SFrançois Tigeot 14408621f407SFrançois Tigeot if (gt_iir[3]) 14411e12ee3bSFrançois Tigeot gen8_cs_irq_handler(dev_priv->engine[VECS], 14428621f407SFrançois Tigeot gt_iir[3], GEN8_VECS_IRQ_SHIFT); 14438621f407SFrançois Tigeot 14448621f407SFrançois Tigeot if (gt_iir[2] & dev_priv->pm_rps_events) 14458621f407SFrançois Tigeot gen6_rps_irq_handler(dev_priv, gt_iir[2]); 14464be47400SFrançois Tigeot 14474be47400SFrançois Tigeot if (gt_iir[2] & dev_priv->pm_guc_events) 14484be47400SFrançois Tigeot gen9_guc_irq_handler(dev_priv, gt_iir[2]); 14498621f407SFrançois Tigeot } 14508621f407SFrançois Tigeot 1451a05eeebfSFrançois Tigeot static bool bxt_port_hotplug_long_detect(enum port port, u32 val) 145224edb884SFrançois Tigeot { 145324edb884SFrançois Tigeot switch (port) { 145424edb884SFrançois Tigeot case PORT_A: 1455352ff8bdSFrançois Tigeot return val & PORTA_HOTPLUG_LONG_DETECT; 1456352ff8bdSFrançois Tigeot case PORT_B: 1457352ff8bdSFrançois Tigeot return val & PORTB_HOTPLUG_LONG_DETECT; 1458352ff8bdSFrançois Tigeot case PORT_C: 1459352ff8bdSFrançois Tigeot return val & PORTC_HOTPLUG_LONG_DETECT; 1460352ff8bdSFrançois Tigeot default: 1461352ff8bdSFrançois Tigeot return false; 1462352ff8bdSFrançois Tigeot } 1463352ff8bdSFrançois Tigeot } 1464352ff8bdSFrançois Tigeot 1465352ff8bdSFrançois Tigeot static bool spt_port_hotplug2_long_detect(enum port port, u32 val) 1466352ff8bdSFrançois Tigeot { 1467352ff8bdSFrançois Tigeot switch (port) { 1468352ff8bdSFrançois Tigeot case PORT_E: 1469352ff8bdSFrançois Tigeot return val & PORTE_HOTPLUG_LONG_DETECT; 1470352ff8bdSFrançois Tigeot default: 1471352ff8bdSFrançois Tigeot return false; 1472352ff8bdSFrançois Tigeot } 1473352ff8bdSFrançois Tigeot } 1474352ff8bdSFrançois Tigeot 1475352ff8bdSFrançois Tigeot static bool spt_port_hotplug_long_detect(enum port port, u32 val) 1476352ff8bdSFrançois Tigeot { 1477352ff8bdSFrançois Tigeot switch (port) { 1478352ff8bdSFrançois Tigeot case PORT_A: 1479352ff8bdSFrançois Tigeot return val & PORTA_HOTPLUG_LONG_DETECT; 148024edb884SFrançois Tigeot case PORT_B: 1481a05eeebfSFrançois Tigeot return val & PORTB_HOTPLUG_LONG_DETECT; 148224edb884SFrançois Tigeot case PORT_C: 1483a05eeebfSFrançois Tigeot return val & PORTC_HOTPLUG_LONG_DETECT; 148424edb884SFrançois Tigeot case PORT_D: 1485a05eeebfSFrançois Tigeot return val & PORTD_HOTPLUG_LONG_DETECT; 1486a05eeebfSFrançois Tigeot default: 1487a05eeebfSFrançois Tigeot return false; 148824edb884SFrançois Tigeot } 148924edb884SFrançois Tigeot } 149024edb884SFrançois Tigeot 1491352ff8bdSFrançois Tigeot static bool ilk_port_hotplug_long_detect(enum port port, u32 val) 1492352ff8bdSFrançois Tigeot { 1493352ff8bdSFrançois Tigeot switch (port) { 1494352ff8bdSFrançois Tigeot case PORT_A: 1495352ff8bdSFrançois Tigeot return val & DIGITAL_PORTA_HOTPLUG_LONG_DETECT; 1496352ff8bdSFrançois Tigeot default: 1497352ff8bdSFrançois Tigeot return false; 1498352ff8bdSFrançois Tigeot } 1499352ff8bdSFrançois Tigeot } 1500352ff8bdSFrançois Tigeot 1501a05eeebfSFrançois Tigeot static bool pch_port_hotplug_long_detect(enum port port, u32 val) 150224edb884SFrançois Tigeot { 150324edb884SFrançois Tigeot switch (port) { 150424edb884SFrançois Tigeot case PORT_B: 1505a05eeebfSFrançois Tigeot return val & PORTB_HOTPLUG_LONG_DETECT; 150624edb884SFrançois Tigeot case PORT_C: 1507a05eeebfSFrançois Tigeot return val & PORTC_HOTPLUG_LONG_DETECT; 150824edb884SFrançois Tigeot case PORT_D: 1509a05eeebfSFrançois Tigeot return val & PORTD_HOTPLUG_LONG_DETECT; 151024edb884SFrançois Tigeot default: 1511a05eeebfSFrançois Tigeot return false; 151224edb884SFrançois Tigeot } 151324edb884SFrançois Tigeot } 151424edb884SFrançois Tigeot 1515a05eeebfSFrançois Tigeot static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) 15168e26cdf6SFrançois Tigeot { 1517a05eeebfSFrançois Tigeot switch (port) { 1518a05eeebfSFrançois Tigeot case PORT_B: 1519a05eeebfSFrançois Tigeot return val & PORTB_HOTPLUG_INT_LONG_PULSE; 1520a05eeebfSFrançois Tigeot case PORT_C: 1521a05eeebfSFrançois Tigeot return val & PORTC_HOTPLUG_INT_LONG_PULSE; 1522a05eeebfSFrançois Tigeot case PORT_D: 1523a05eeebfSFrançois Tigeot return val & PORTD_HOTPLUG_INT_LONG_PULSE; 1524a05eeebfSFrançois Tigeot default: 1525a05eeebfSFrançois Tigeot return false; 1526a05eeebfSFrançois Tigeot } 1527a05eeebfSFrançois Tigeot } 1528a05eeebfSFrançois Tigeot 1529352ff8bdSFrançois Tigeot /* 1530352ff8bdSFrançois Tigeot * Get a bit mask of pins that have triggered, and which ones may be long. 1531352ff8bdSFrançois Tigeot * This can be called multiple times with the same masks to accumulate 1532352ff8bdSFrançois Tigeot * hotplug detection results from several registers. 1533352ff8bdSFrançois Tigeot * 1534352ff8bdSFrançois Tigeot * Note that the caller is expected to zero out the masks initially. 1535352ff8bdSFrançois Tigeot */ 1536a05eeebfSFrançois Tigeot static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask, 1537a05eeebfSFrançois Tigeot u32 hotplug_trigger, u32 dig_hotplug_reg, 1538a05eeebfSFrançois Tigeot const u32 hpd[HPD_NUM_PINS], 1539a05eeebfSFrançois Tigeot bool long_pulse_detect(enum port port, u32 val)) 1540a05eeebfSFrançois Tigeot { 154124edb884SFrançois Tigeot enum port port; 1542a05eeebfSFrançois Tigeot int i; 15435d0b1887SFrançois Tigeot 1544a05eeebfSFrançois Tigeot for_each_hpd_pin(i) { 1545a05eeebfSFrançois Tigeot if ((hpd[i] & hotplug_trigger) == 0) 154624edb884SFrançois Tigeot continue; 15478e26cdf6SFrançois Tigeot 1548a05eeebfSFrançois Tigeot *pin_mask |= BIT(i); 154924edb884SFrançois Tigeot 1550a05eeebfSFrançois Tigeot if (!intel_hpd_pin_to_port(i, &port)) 15518e26cdf6SFrançois Tigeot continue; 15528e26cdf6SFrançois Tigeot 1553a05eeebfSFrançois Tigeot if (long_pulse_detect(port, dig_hotplug_reg)) 1554a05eeebfSFrançois Tigeot *long_mask |= BIT(i); 155524edb884SFrançois Tigeot } 155624edb884SFrançois Tigeot 1557a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n", 1558a05eeebfSFrançois Tigeot hotplug_trigger, dig_hotplug_reg, *pin_mask); 15598e26cdf6SFrançois Tigeot 15608e26cdf6SFrançois Tigeot } 15618e26cdf6SFrançois Tigeot 15621487f786SFrançois Tigeot static void gmbus_irq_handler(struct drm_i915_private *dev_priv) 1563a2fdbec6SFrançois Tigeot { 1564a2fdbec6SFrançois Tigeot wake_up_all(&dev_priv->gmbus_wait_queue); 1565a2fdbec6SFrançois Tigeot } 1566a2fdbec6SFrançois Tigeot 15671487f786SFrançois Tigeot static void dp_aux_irq_handler(struct drm_i915_private *dev_priv) 1568a2fdbec6SFrançois Tigeot { 1569a2fdbec6SFrançois Tigeot wake_up_all(&dev_priv->gmbus_wait_queue); 1570a2fdbec6SFrançois Tigeot } 1571a2fdbec6SFrançois Tigeot 15729edbd4a0SFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 15731487f786SFrançois Tigeot static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, 15741487f786SFrançois Tigeot enum i915_pipe pipe, 15759edbd4a0SFrançois Tigeot uint32_t crc0, uint32_t crc1, 15769edbd4a0SFrançois Tigeot uint32_t crc2, uint32_t crc3, 15779edbd4a0SFrançois Tigeot uint32_t crc4) 15785d0b1887SFrançois Tigeot { 15799edbd4a0SFrançois Tigeot struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; 15809edbd4a0SFrançois Tigeot struct intel_pipe_crc_entry *entry; 1581*a85cb24fSFrançois Tigeot struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); 1582*a85cb24fSFrançois Tigeot struct drm_driver *driver = dev_priv->drm.driver; 1583*a85cb24fSFrançois Tigeot uint32_t crcs[5]; 15849edbd4a0SFrançois Tigeot int head, tail; 15859edbd4a0SFrançois Tigeot 15861e12ee3bSFrançois Tigeot lockmgr(&pipe_crc->lock, LK_EXCLUSIVE); 1587*a85cb24fSFrançois Tigeot if (pipe_crc->source) { 15889edbd4a0SFrançois Tigeot if (!pipe_crc->entries) { 15891e12ee3bSFrançois Tigeot lockmgr(&pipe_crc->lock, LK_RELEASE); 15902c9916cdSFrançois Tigeot DRM_DEBUG_KMS("spurious interrupt\n"); 15919edbd4a0SFrançois Tigeot return; 15929edbd4a0SFrançois Tigeot } 15939edbd4a0SFrançois Tigeot 15949edbd4a0SFrançois Tigeot head = pipe_crc->head; 15959edbd4a0SFrançois Tigeot tail = pipe_crc->tail; 15969edbd4a0SFrançois Tigeot 15979edbd4a0SFrançois Tigeot if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) { 15981e12ee3bSFrançois Tigeot lockmgr(&pipe_crc->lock, LK_RELEASE); 15999edbd4a0SFrançois Tigeot DRM_ERROR("CRC buffer overflowing\n"); 16009edbd4a0SFrançois Tigeot return; 16019edbd4a0SFrançois Tigeot } 16029edbd4a0SFrançois Tigeot 16039edbd4a0SFrançois Tigeot entry = &pipe_crc->entries[head]; 16049edbd4a0SFrançois Tigeot 1605*a85cb24fSFrançois Tigeot entry->frame = driver->get_vblank_counter(&dev_priv->drm, pipe); 16069edbd4a0SFrançois Tigeot entry->crc[0] = crc0; 16079edbd4a0SFrançois Tigeot entry->crc[1] = crc1; 16089edbd4a0SFrançois Tigeot entry->crc[2] = crc2; 16099edbd4a0SFrançois Tigeot entry->crc[3] = crc3; 16109edbd4a0SFrançois Tigeot entry->crc[4] = crc4; 16119edbd4a0SFrançois Tigeot 16129edbd4a0SFrançois Tigeot head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); 16139edbd4a0SFrançois Tigeot pipe_crc->head = head; 16149edbd4a0SFrançois Tigeot 16151e12ee3bSFrançois Tigeot lockmgr(&pipe_crc->lock, LK_RELEASE); 16169edbd4a0SFrançois Tigeot 16179edbd4a0SFrançois Tigeot wake_up_interruptible(&pipe_crc->wq); 1618*a85cb24fSFrançois Tigeot } else { 1619*a85cb24fSFrançois Tigeot /* 1620*a85cb24fSFrançois Tigeot * For some not yet identified reason, the first CRC is 1621*a85cb24fSFrançois Tigeot * bonkers. So let's just wait for the next vblank and read 1622*a85cb24fSFrançois Tigeot * out the buggy result. 1623*a85cb24fSFrançois Tigeot * 1624*a85cb24fSFrançois Tigeot * On CHV sometimes the second CRC is bonkers as well, so 1625*a85cb24fSFrançois Tigeot * don't trust that one either. 1626*a85cb24fSFrançois Tigeot */ 1627*a85cb24fSFrançois Tigeot if (pipe_crc->skipped == 0 || 1628*a85cb24fSFrançois Tigeot (IS_CHERRYVIEW(dev_priv) && pipe_crc->skipped == 1)) { 1629*a85cb24fSFrançois Tigeot pipe_crc->skipped++; 1630*a85cb24fSFrançois Tigeot lockmgr(&pipe_crc->lock, LK_RELEASE); 1631*a85cb24fSFrançois Tigeot return; 1632*a85cb24fSFrançois Tigeot } 1633*a85cb24fSFrançois Tigeot lockmgr(&pipe_crc->lock, LK_RELEASE); 1634*a85cb24fSFrançois Tigeot crcs[0] = crc0; 1635*a85cb24fSFrançois Tigeot crcs[1] = crc1; 1636*a85cb24fSFrançois Tigeot crcs[2] = crc2; 1637*a85cb24fSFrançois Tigeot crcs[3] = crc3; 1638*a85cb24fSFrançois Tigeot crcs[4] = crc4; 1639*a85cb24fSFrançois Tigeot drm_crtc_add_crc_entry(&crtc->base, true, 1640*a85cb24fSFrançois Tigeot drm_accurate_vblank_count(&crtc->base), 1641*a85cb24fSFrançois Tigeot crcs); 1642*a85cb24fSFrançois Tigeot } 16439edbd4a0SFrançois Tigeot } 16449edbd4a0SFrançois Tigeot #else 16459edbd4a0SFrançois Tigeot static inline void 16461487f786SFrançois Tigeot display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, 16471487f786SFrançois Tigeot enum i915_pipe pipe, 16489edbd4a0SFrançois Tigeot uint32_t crc0, uint32_t crc1, 16499edbd4a0SFrançois Tigeot uint32_t crc2, uint32_t crc3, 16509edbd4a0SFrançois Tigeot uint32_t crc4) {} 16519edbd4a0SFrançois Tigeot #endif 16529edbd4a0SFrançois Tigeot 16539edbd4a0SFrançois Tigeot 16541487f786SFrançois Tigeot static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, 16551487f786SFrançois Tigeot enum i915_pipe pipe) 16569edbd4a0SFrançois Tigeot { 16571487f786SFrançois Tigeot display_pipe_crc_irq_handler(dev_priv, pipe, 16589edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_1_IVB(pipe)), 16599edbd4a0SFrançois Tigeot 0, 0, 0, 0); 16609edbd4a0SFrançois Tigeot } 16619edbd4a0SFrançois Tigeot 16621487f786SFrançois Tigeot static void ivb_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, 16631487f786SFrançois Tigeot enum i915_pipe pipe) 16649edbd4a0SFrançois Tigeot { 16651487f786SFrançois Tigeot display_pipe_crc_irq_handler(dev_priv, pipe, 16669edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_1_IVB(pipe)), 16679edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_2_IVB(pipe)), 16689edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_3_IVB(pipe)), 16699edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_4_IVB(pipe)), 16709edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_5_IVB(pipe))); 16719edbd4a0SFrançois Tigeot } 16729edbd4a0SFrançois Tigeot 16731487f786SFrançois Tigeot static void i9xx_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, 16741487f786SFrançois Tigeot enum i915_pipe pipe) 16759edbd4a0SFrançois Tigeot { 16769edbd4a0SFrançois Tigeot uint32_t res1, res2; 16779edbd4a0SFrançois Tigeot 16781487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 3) 16799edbd4a0SFrançois Tigeot res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe)); 16809edbd4a0SFrançois Tigeot else 16819edbd4a0SFrançois Tigeot res1 = 0; 16829edbd4a0SFrançois Tigeot 16831487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) 16849edbd4a0SFrançois Tigeot res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe)); 16859edbd4a0SFrançois Tigeot else 16869edbd4a0SFrançois Tigeot res2 = 0; 16879edbd4a0SFrançois Tigeot 16881487f786SFrançois Tigeot display_pipe_crc_irq_handler(dev_priv, pipe, 16899edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_RED(pipe)), 16909edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_GREEN(pipe)), 16919edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_BLUE(pipe)), 16929edbd4a0SFrançois Tigeot res1, res2); 16939edbd4a0SFrançois Tigeot } 16949edbd4a0SFrançois Tigeot 16959edbd4a0SFrançois Tigeot /* The RPS events need forcewake, so we add them to a work queue and mask their 16969edbd4a0SFrançois Tigeot * IMR bits until the work is done. Other interrupts can be processed without 16979edbd4a0SFrançois Tigeot * the work queue. */ 16989edbd4a0SFrançois Tigeot static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) 16999edbd4a0SFrançois Tigeot { 1700ba55f2f5SFrançois Tigeot if (pm_iir & dev_priv->pm_rps_events) { 17019edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 17024be47400SFrançois Tigeot gen6_mask_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events); 17032c9916cdSFrançois Tigeot if (dev_priv->rps.interrupts_enabled) { 17042c9916cdSFrançois Tigeot dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events; 1705303bf270SFrançois Tigeot schedule_work(&dev_priv->rps.work); 17065d0b1887SFrançois Tigeot } 17072c9916cdSFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 17082c9916cdSFrançois Tigeot } 17092c9916cdSFrançois Tigeot 17102c9916cdSFrançois Tigeot if (INTEL_INFO(dev_priv)->gen >= 8) 17112c9916cdSFrançois Tigeot return; 17125d0b1887SFrançois Tigeot 17138621f407SFrançois Tigeot if (HAS_VEBOX(dev_priv)) { 17145d0b1887SFrançois Tigeot if (pm_iir & PM_VEBOX_USER_INTERRUPT) 17151e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[VECS]); 17165d0b1887SFrançois Tigeot 17172c9916cdSFrançois Tigeot if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) 17182c9916cdSFrançois Tigeot DRM_DEBUG("Command parser error, pm_iir 0x%08x\n", pm_iir); 17195d0b1887SFrançois Tigeot } 17205d0b1887SFrançois Tigeot } 17215d0b1887SFrançois Tigeot 17224be47400SFrançois Tigeot static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir) 17234be47400SFrançois Tigeot { 17244be47400SFrançois Tigeot if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) { 17254be47400SFrançois Tigeot /* Sample the log buffer flush related bits & clear them out now 17264be47400SFrançois Tigeot * itself from the message identity register to minimize the 17274be47400SFrançois Tigeot * probability of losing a flush interrupt, when there are back 17284be47400SFrançois Tigeot * to back flush interrupts. 17294be47400SFrançois Tigeot * There can be a new flush interrupt, for different log buffer 17304be47400SFrançois Tigeot * type (like for ISR), whilst Host is handling one (for DPC). 17314be47400SFrançois Tigeot * Since same bit is used in message register for ISR & DPC, it 17324be47400SFrançois Tigeot * could happen that GuC sets the bit for 2nd interrupt but Host 17334be47400SFrançois Tigeot * clears out the bit on handling the 1st interrupt. 17344be47400SFrançois Tigeot */ 17354be47400SFrançois Tigeot u32 msg, flush; 17364be47400SFrançois Tigeot 17374be47400SFrançois Tigeot msg = I915_READ(SOFT_SCRATCH(15)); 1738*a85cb24fSFrançois Tigeot flush = msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED | 1739*a85cb24fSFrançois Tigeot INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER); 17404be47400SFrançois Tigeot if (flush) { 17414be47400SFrançois Tigeot /* Clear the message bits that are handled */ 17424be47400SFrançois Tigeot I915_WRITE(SOFT_SCRATCH(15), msg & ~flush); 17434be47400SFrançois Tigeot 17444be47400SFrançois Tigeot /* Handle flush interrupt in bottom half */ 1745*a85cb24fSFrançois Tigeot queue_work(dev_priv->guc.log.runtime.flush_wq, 1746*a85cb24fSFrançois Tigeot &dev_priv->guc.log.runtime.flush_work); 17474be47400SFrançois Tigeot 17484be47400SFrançois Tigeot dev_priv->guc.log.flush_interrupt_count++; 17494be47400SFrançois Tigeot } else { 17504be47400SFrançois Tigeot /* Not clearing of unhandled event bits won't result in 17514be47400SFrançois Tigeot * re-triggering of the interrupt. 17524be47400SFrançois Tigeot */ 17534be47400SFrançois Tigeot } 17544be47400SFrançois Tigeot } 17554be47400SFrançois Tigeot } 17564be47400SFrançois Tigeot 17571487f786SFrançois Tigeot static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv, 17581487f786SFrançois Tigeot enum i915_pipe pipe) 1759ba55f2f5SFrançois Tigeot { 17601487f786SFrançois Tigeot bool ret; 1761ba55f2f5SFrançois Tigeot 1762303bf270SFrançois Tigeot ret = drm_handle_vblank(&dev_priv->drm, pipe); 17631487f786SFrançois Tigeot if (ret) 17641487f786SFrançois Tigeot intel_finish_page_flip_mmio(dev_priv, pipe); 17651487f786SFrançois Tigeot 17661487f786SFrançois Tigeot return ret; 1767ba55f2f5SFrançois Tigeot } 1768ba55f2f5SFrançois Tigeot 17691487f786SFrançois Tigeot static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv, 17701487f786SFrançois Tigeot u32 iir, u32 pipe_stats[I915_MAX_PIPES]) 1771ba55f2f5SFrançois Tigeot { 1772ba55f2f5SFrançois Tigeot int pipe; 1773ba55f2f5SFrançois Tigeot 1774ba55f2f5SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 1775c0e85e96SFrançois Tigeot 1776c0e85e96SFrançois Tigeot if (!dev_priv->display_irqs_enabled) { 1777c0e85e96SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 1778c0e85e96SFrançois Tigeot return; 1779c0e85e96SFrançois Tigeot } 1780c0e85e96SFrançois Tigeot 17811b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 1782aee94f86SFrançois Tigeot i915_reg_t reg; 1783ba55f2f5SFrançois Tigeot u32 mask, iir_bit = 0; 1784ba55f2f5SFrançois Tigeot 1785ba55f2f5SFrançois Tigeot /* 1786ba55f2f5SFrançois Tigeot * PIPESTAT bits get signalled even when the interrupt is 1787ba55f2f5SFrançois Tigeot * disabled with the mask bits, and some of the status bits do 1788ba55f2f5SFrançois Tigeot * not generate interrupts at all (like the underrun bit). Hence 1789ba55f2f5SFrançois Tigeot * we need to be careful that we only handle what we want to 1790ba55f2f5SFrançois Tigeot * handle. 1791ba55f2f5SFrançois Tigeot */ 17922c9916cdSFrançois Tigeot 17932c9916cdSFrançois Tigeot /* fifo underruns are filterered in the underrun handler. */ 17942c9916cdSFrançois Tigeot mask = PIPE_FIFO_UNDERRUN_STATUS; 1795ba55f2f5SFrançois Tigeot 1796ba55f2f5SFrançois Tigeot switch (pipe) { 1797ba55f2f5SFrançois Tigeot case PIPE_A: 1798ba55f2f5SFrançois Tigeot iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; 1799ba55f2f5SFrançois Tigeot break; 1800ba55f2f5SFrançois Tigeot case PIPE_B: 1801ba55f2f5SFrançois Tigeot iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; 1802ba55f2f5SFrançois Tigeot break; 1803ba55f2f5SFrançois Tigeot case PIPE_C: 1804ba55f2f5SFrançois Tigeot iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; 1805ba55f2f5SFrançois Tigeot break; 1806ba55f2f5SFrançois Tigeot } 1807ba55f2f5SFrançois Tigeot if (iir & iir_bit) 1808ba55f2f5SFrançois Tigeot mask |= dev_priv->pipestat_irq_mask[pipe]; 1809ba55f2f5SFrançois Tigeot 1810ba55f2f5SFrançois Tigeot if (!mask) 1811ba55f2f5SFrançois Tigeot continue; 1812ba55f2f5SFrançois Tigeot 1813ba55f2f5SFrançois Tigeot reg = PIPESTAT(pipe); 1814ba55f2f5SFrançois Tigeot mask |= PIPESTAT_INT_ENABLE_MASK; 1815ba55f2f5SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg) & mask; 1816ba55f2f5SFrançois Tigeot 1817ba55f2f5SFrançois Tigeot /* 1818ba55f2f5SFrançois Tigeot * Clear the PIPE*STAT regs before the IIR 1819ba55f2f5SFrançois Tigeot */ 1820ba55f2f5SFrançois Tigeot if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS | 1821ba55f2f5SFrançois Tigeot PIPESTAT_INT_STATUS_MASK)) 1822ba55f2f5SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 1823ba55f2f5SFrançois Tigeot } 1824ba55f2f5SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 18258621f407SFrançois Tigeot } 18268621f407SFrançois Tigeot 18271487f786SFrançois Tigeot static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv, 18288621f407SFrançois Tigeot u32 pipe_stats[I915_MAX_PIPES]) 18298621f407SFrançois Tigeot { 18308621f407SFrançois Tigeot enum i915_pipe pipe; 1831ba55f2f5SFrançois Tigeot 18321b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 18331b13d190SFrançois Tigeot if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && 18341487f786SFrançois Tigeot intel_pipe_handle_vblank(dev_priv, pipe)) 18351487f786SFrançois Tigeot intel_check_page_flip(dev_priv, pipe); 1836ba55f2f5SFrançois Tigeot 18371487f786SFrançois Tigeot if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) 18381487f786SFrançois Tigeot intel_finish_page_flip_cs(dev_priv, pipe); 1839ba55f2f5SFrançois Tigeot 1840ba55f2f5SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 18411487f786SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev_priv, pipe); 1842ba55f2f5SFrançois Tigeot 18432c9916cdSFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 18442c9916cdSFrançois Tigeot intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); 1845ba55f2f5SFrançois Tigeot } 1846ba55f2f5SFrançois Tigeot 1847ba55f2f5SFrançois Tigeot if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) 18481487f786SFrançois Tigeot gmbus_irq_handler(dev_priv); 1849ba55f2f5SFrançois Tigeot } 1850ba55f2f5SFrançois Tigeot 18518621f407SFrançois Tigeot static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv) 1852ba55f2f5SFrançois Tigeot { 1853ba55f2f5SFrançois Tigeot u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 1854ba55f2f5SFrançois Tigeot 18558621f407SFrançois Tigeot if (hotplug_status) 1856ba55f2f5SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 18578621f407SFrançois Tigeot 18588621f407SFrançois Tigeot return hotplug_status; 18598621f407SFrançois Tigeot } 18608621f407SFrançois Tigeot 18611487f786SFrançois Tigeot static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv, 18628621f407SFrançois Tigeot u32 hotplug_status) 18638621f407SFrançois Tigeot { 18648621f407SFrançois Tigeot u32 pin_mask = 0, long_mask = 0; 186524edb884SFrançois Tigeot 18661487f786SFrançois Tigeot if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) || 18671487f786SFrançois Tigeot IS_CHERRYVIEW(dev_priv)) { 186824edb884SFrançois Tigeot u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; 186924edb884SFrançois Tigeot 1870352ff8bdSFrançois Tigeot if (hotplug_trigger) { 1871a05eeebfSFrançois Tigeot intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, 1872a05eeebfSFrançois Tigeot hotplug_trigger, hpd_status_g4x, 1873a05eeebfSFrançois Tigeot i9xx_port_hotplug_long_detect); 1874352ff8bdSFrançois Tigeot 18751487f786SFrançois Tigeot intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); 1876352ff8bdSFrançois Tigeot } 1877a05eeebfSFrançois Tigeot 1878a05eeebfSFrançois Tigeot if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) 18791487f786SFrançois Tigeot dp_aux_irq_handler(dev_priv); 188024edb884SFrançois Tigeot } else { 188124edb884SFrançois Tigeot u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; 188224edb884SFrançois Tigeot 1883352ff8bdSFrançois Tigeot if (hotplug_trigger) { 1884a05eeebfSFrançois Tigeot intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, 1885a05eeebfSFrançois Tigeot hotplug_trigger, hpd_status_i915, 1886a05eeebfSFrançois Tigeot i9xx_port_hotplug_long_detect); 18871487f786SFrançois Tigeot intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); 188824edb884SFrançois Tigeot } 1889ba55f2f5SFrançois Tigeot } 1890352ff8bdSFrançois Tigeot } 1891ba55f2f5SFrançois Tigeot 1892183e2373SFrançois Tigeot static irqreturn_t valleyview_irq_handler(int irq, void *arg) 1893e9243325SFrançois Tigeot { 1894ba55f2f5SFrançois Tigeot struct drm_device *dev = arg; 1895303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 1896183e2373SFrançois Tigeot irqreturn_t ret = IRQ_NONE; 1897ba55f2f5SFrançois Tigeot 18982c9916cdSFrançois Tigeot if (!intel_irqs_enabled(dev_priv)) 18992c9916cdSFrançois Tigeot return IRQ_NONE; 19002c9916cdSFrançois Tigeot 1901aee94f86SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 1902aee94f86SFrançois Tigeot disable_rpm_wakeref_asserts(dev_priv); 1903aee94f86SFrançois Tigeot 1904c0e85e96SFrançois Tigeot do { 19058621f407SFrançois Tigeot u32 iir, gt_iir, pm_iir; 19068621f407SFrançois Tigeot u32 pipe_stats[I915_MAX_PIPES] = {}; 19078621f407SFrançois Tigeot u32 hotplug_status = 0; 19088621f407SFrançois Tigeot u32 ier = 0; 19098621f407SFrançois Tigeot 19108621f407SFrançois Tigeot gt_iir = I915_READ(GTIIR); 19118621f407SFrançois Tigeot pm_iir = I915_READ(GEN6_PMIIR); 19128621f407SFrançois Tigeot iir = I915_READ(VLV_IIR); 19138621f407SFrançois Tigeot 19148621f407SFrançois Tigeot if (gt_iir == 0 && pm_iir == 0 && iir == 0) 19158621f407SFrançois Tigeot break; 19168621f407SFrançois Tigeot 1917183e2373SFrançois Tigeot ret = IRQ_HANDLED; 19188621f407SFrançois Tigeot 19198621f407SFrançois Tigeot /* 19208621f407SFrançois Tigeot * Theory on interrupt generation, based on empirical evidence: 19218621f407SFrançois Tigeot * 19228621f407SFrançois Tigeot * x = ((VLV_IIR & VLV_IER) || 19238621f407SFrançois Tigeot * (((GT_IIR & GT_IER) || (GEN6_PMIIR & GEN6_PMIER)) && 19248621f407SFrançois Tigeot * (VLV_MASTER_IER & MASTER_INTERRUPT_ENABLE))); 19258621f407SFrançois Tigeot * 19268621f407SFrançois Tigeot * A CPU interrupt will only be raised when 'x' has a 0->1 edge. 19278621f407SFrançois Tigeot * Hence we clear MASTER_INTERRUPT_ENABLE and VLV_IER to 19288621f407SFrançois Tigeot * guarantee the CPU interrupt will be raised again even if we 19298621f407SFrançois Tigeot * don't end up clearing all the VLV_IIR, GT_IIR, GEN6_PMIIR 19308621f407SFrançois Tigeot * bits this time around. 19318621f407SFrançois Tigeot */ 19328621f407SFrançois Tigeot I915_WRITE(VLV_MASTER_IER, 0); 19338621f407SFrançois Tigeot ier = I915_READ(VLV_IER); 19348621f407SFrançois Tigeot I915_WRITE(VLV_IER, 0); 19358621f407SFrançois Tigeot 19368621f407SFrançois Tigeot if (gt_iir) 19378621f407SFrançois Tigeot I915_WRITE(GTIIR, gt_iir); 19388621f407SFrançois Tigeot if (pm_iir) 19398621f407SFrançois Tigeot I915_WRITE(GEN6_PMIIR, pm_iir); 19408621f407SFrançois Tigeot 19418621f407SFrançois Tigeot if (iir & I915_DISPLAY_PORT_INTERRUPT) 19428621f407SFrançois Tigeot hotplug_status = i9xx_hpd_irq_ack(dev_priv); 19438621f407SFrançois Tigeot 19448621f407SFrançois Tigeot /* Call regardless, as some status bits might not be 19458621f407SFrançois Tigeot * signalled in iir */ 19461487f786SFrançois Tigeot valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); 19478621f407SFrançois Tigeot 1948*a85cb24fSFrançois Tigeot if (iir & (I915_LPE_PIPE_A_INTERRUPT | 1949*a85cb24fSFrançois Tigeot I915_LPE_PIPE_B_INTERRUPT)) 1950*a85cb24fSFrançois Tigeot intel_lpe_audio_irq_handler(dev_priv); 1951*a85cb24fSFrançois Tigeot 19528621f407SFrançois Tigeot /* 19538621f407SFrançois Tigeot * VLV_IIR is single buffered, and reflects the level 19548621f407SFrançois Tigeot * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. 19558621f407SFrançois Tigeot */ 19568621f407SFrançois Tigeot if (iir) 19578621f407SFrançois Tigeot I915_WRITE(VLV_IIR, iir); 19588621f407SFrançois Tigeot 19598621f407SFrançois Tigeot I915_WRITE(VLV_IER, ier); 19608621f407SFrançois Tigeot I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); 19618621f407SFrançois Tigeot POSTING_READ(VLV_MASTER_IER); 19628621f407SFrançois Tigeot 19638621f407SFrançois Tigeot if (gt_iir) 19648621f407SFrançois Tigeot snb_gt_irq_handler(dev_priv, gt_iir); 19658621f407SFrançois Tigeot if (pm_iir) 19668621f407SFrançois Tigeot gen6_rps_irq_handler(dev_priv, pm_iir); 19678621f407SFrançois Tigeot 19688621f407SFrançois Tigeot if (hotplug_status) 19691487f786SFrançois Tigeot i9xx_hpd_irq_handler(dev_priv, hotplug_status); 19708621f407SFrançois Tigeot 19711487f786SFrançois Tigeot valleyview_pipestat_irq_handler(dev_priv, pipe_stats); 19728621f407SFrançois Tigeot } while (0); 19738621f407SFrançois Tigeot 19748621f407SFrançois Tigeot enable_rpm_wakeref_asserts(dev_priv); 19758621f407SFrançois Tigeot 1976183e2373SFrançois Tigeot return ret; 19778621f407SFrançois Tigeot } 19788621f407SFrançois Tigeot 1979183e2373SFrançois Tigeot static irqreturn_t cherryview_irq_handler(int irq, void *arg) 19808621f407SFrançois Tigeot { 19818621f407SFrançois Tigeot struct drm_device *dev = arg; 1982303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 1983183e2373SFrançois Tigeot irqreturn_t ret = IRQ_NONE; 19848621f407SFrançois Tigeot 19858621f407SFrançois Tigeot if (!intel_irqs_enabled(dev_priv)) 19868621f407SFrançois Tigeot return IRQ_NONE; 19878621f407SFrançois Tigeot 19888621f407SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 19898621f407SFrançois Tigeot disable_rpm_wakeref_asserts(dev_priv); 19908621f407SFrançois Tigeot 19918621f407SFrançois Tigeot do { 19928621f407SFrançois Tigeot u32 master_ctl, iir; 19938621f407SFrançois Tigeot u32 gt_iir[4] = {}; 19948621f407SFrançois Tigeot u32 pipe_stats[I915_MAX_PIPES] = {}; 19958621f407SFrançois Tigeot u32 hotplug_status = 0; 19968621f407SFrançois Tigeot u32 ier = 0; 19978621f407SFrançois Tigeot 1998ba55f2f5SFrançois Tigeot master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL; 1999ba55f2f5SFrançois Tigeot iir = I915_READ(VLV_IIR); 2000ba55f2f5SFrançois Tigeot 2001ba55f2f5SFrançois Tigeot if (master_ctl == 0 && iir == 0) 2002ba55f2f5SFrançois Tigeot break; 2003ba55f2f5SFrançois Tigeot 2004183e2373SFrançois Tigeot ret = IRQ_HANDLED; 200524edb884SFrançois Tigeot 20068621f407SFrançois Tigeot /* 20078621f407SFrançois Tigeot * Theory on interrupt generation, based on empirical evidence: 20088621f407SFrançois Tigeot * 20098621f407SFrançois Tigeot * x = ((VLV_IIR & VLV_IER) || 20108621f407SFrançois Tigeot * ((GEN8_MASTER_IRQ & ~GEN8_MASTER_IRQ_CONTROL) && 20118621f407SFrançois Tigeot * (GEN8_MASTER_IRQ & GEN8_MASTER_IRQ_CONTROL))); 20128621f407SFrançois Tigeot * 20138621f407SFrançois Tigeot * A CPU interrupt will only be raised when 'x' has a 0->1 edge. 20148621f407SFrançois Tigeot * Hence we clear GEN8_MASTER_IRQ_CONTROL and VLV_IER to 20158621f407SFrançois Tigeot * guarantee the CPU interrupt will be raised again even if we 20168621f407SFrançois Tigeot * don't end up clearing all the VLV_IIR and GEN8_MASTER_IRQ_CONTROL 20178621f407SFrançois Tigeot * bits this time around. 20188621f407SFrançois Tigeot */ 2019ba55f2f5SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, 0); 20208621f407SFrançois Tigeot ier = I915_READ(VLV_IER); 20218621f407SFrançois Tigeot I915_WRITE(VLV_IER, 0); 2022ba55f2f5SFrançois Tigeot 20238621f407SFrançois Tigeot gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir); 202424edb884SFrançois Tigeot 202524edb884SFrançois Tigeot if (iir & I915_DISPLAY_PORT_INTERRUPT) 20268621f407SFrançois Tigeot hotplug_status = i9xx_hpd_irq_ack(dev_priv); 2027ba55f2f5SFrançois Tigeot 202824edb884SFrançois Tigeot /* Call regardless, as some status bits might not be 202924edb884SFrançois Tigeot * signalled in iir */ 20301487f786SFrançois Tigeot valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); 2031ba55f2f5SFrançois Tigeot 2032*a85cb24fSFrançois Tigeot if (iir & (I915_LPE_PIPE_A_INTERRUPT | 2033*a85cb24fSFrançois Tigeot I915_LPE_PIPE_B_INTERRUPT | 2034*a85cb24fSFrançois Tigeot I915_LPE_PIPE_C_INTERRUPT)) 2035*a85cb24fSFrançois Tigeot intel_lpe_audio_irq_handler(dev_priv); 2036*a85cb24fSFrançois Tigeot 20378621f407SFrançois Tigeot /* 20388621f407SFrançois Tigeot * VLV_IIR is single buffered, and reflects the level 20398621f407SFrançois Tigeot * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. 20408621f407SFrançois Tigeot */ 20418621f407SFrançois Tigeot if (iir) 20428621f407SFrançois Tigeot I915_WRITE(VLV_IIR, iir); 20438621f407SFrançois Tigeot 20448621f407SFrançois Tigeot I915_WRITE(VLV_IER, ier); 20458621f407SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); 2046ba55f2f5SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 20478621f407SFrançois Tigeot 20488621f407SFrançois Tigeot gen8_gt_irq_handler(dev_priv, gt_iir); 20498621f407SFrançois Tigeot 20508621f407SFrançois Tigeot if (hotplug_status) 20511487f786SFrançois Tigeot i9xx_hpd_irq_handler(dev_priv, hotplug_status); 20528621f407SFrançois Tigeot 20531487f786SFrançois Tigeot valleyview_pipestat_irq_handler(dev_priv, pipe_stats); 2054c0e85e96SFrançois Tigeot } while (0); 205524edb884SFrançois Tigeot 2056aee94f86SFrançois Tigeot enable_rpm_wakeref_asserts(dev_priv); 2057c0e85e96SFrançois Tigeot 2058183e2373SFrançois Tigeot return ret; 2059ba55f2f5SFrançois Tigeot } 2060ba55f2f5SFrançois Tigeot 20611487f786SFrançois Tigeot static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv, 20621487f786SFrançois Tigeot u32 hotplug_trigger, 2063352ff8bdSFrançois Tigeot const u32 hpd[HPD_NUM_PINS]) 2064352ff8bdSFrançois Tigeot { 2065352ff8bdSFrançois Tigeot u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; 2066352ff8bdSFrançois Tigeot 2067aee94f86SFrançois Tigeot /* 2068aee94f86SFrançois Tigeot * Somehow the PCH doesn't seem to really ack the interrupt to the CPU 2069aee94f86SFrançois Tigeot * unless we touch the hotplug register, even if hotplug_trigger is 2070aee94f86SFrançois Tigeot * zero. Not acking leads to "The master control interrupt lied (SDE)!" 2071aee94f86SFrançois Tigeot * errors. 2072aee94f86SFrançois Tigeot */ 2073352ff8bdSFrançois Tigeot dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); 2074aee94f86SFrançois Tigeot if (!hotplug_trigger) { 2075aee94f86SFrançois Tigeot u32 mask = PORTA_HOTPLUG_STATUS_MASK | 2076aee94f86SFrançois Tigeot PORTD_HOTPLUG_STATUS_MASK | 2077aee94f86SFrançois Tigeot PORTC_HOTPLUG_STATUS_MASK | 2078aee94f86SFrançois Tigeot PORTB_HOTPLUG_STATUS_MASK; 2079aee94f86SFrançois Tigeot dig_hotplug_reg &= ~mask; 2080aee94f86SFrançois Tigeot } 2081aee94f86SFrançois Tigeot 2082352ff8bdSFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); 2083aee94f86SFrançois Tigeot if (!hotplug_trigger) 2084aee94f86SFrançois Tigeot return; 2085352ff8bdSFrançois Tigeot 2086352ff8bdSFrançois Tigeot intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, 2087352ff8bdSFrançois Tigeot dig_hotplug_reg, hpd, 2088352ff8bdSFrançois Tigeot pch_port_hotplug_long_detect); 2089352ff8bdSFrançois Tigeot 20901487f786SFrançois Tigeot intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); 2091352ff8bdSFrançois Tigeot } 2092352ff8bdSFrançois Tigeot 20931487f786SFrançois Tigeot static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) 2094e3adcf8fSFrançois Tigeot { 2095e3adcf8fSFrançois Tigeot int pipe; 20968e26cdf6SFrançois Tigeot u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; 2097a05eeebfSFrançois Tigeot 20981487f786SFrançois Tigeot ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ibx); 20995d0b1887SFrançois Tigeot 21005d0b1887SFrançois Tigeot if (pch_iir & SDE_AUDIO_POWER_MASK) { 21015d0b1887SFrançois Tigeot int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> 2102e3adcf8fSFrançois Tigeot SDE_AUDIO_POWER_SHIFT); 21035d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", 21045d0b1887SFrançois Tigeot port_name(port)); 21055d0b1887SFrançois Tigeot } 2106e3adcf8fSFrançois Tigeot 2107a2fdbec6SFrançois Tigeot if (pch_iir & SDE_AUX_MASK) 21081487f786SFrançois Tigeot dp_aux_irq_handler(dev_priv); 2109a2fdbec6SFrançois Tigeot 2110e3adcf8fSFrançois Tigeot if (pch_iir & SDE_GMBUS) 21111487f786SFrançois Tigeot gmbus_irq_handler(dev_priv); 2112e3adcf8fSFrançois Tigeot 2113e3adcf8fSFrançois Tigeot if (pch_iir & SDE_AUDIO_HDCP_MASK) 2114a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n"); 2115e3adcf8fSFrançois Tigeot 2116e3adcf8fSFrançois Tigeot if (pch_iir & SDE_AUDIO_TRANS_MASK) 2117a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n"); 2118e3adcf8fSFrançois Tigeot 2119e3adcf8fSFrançois Tigeot if (pch_iir & SDE_POISON) 2120a2296444SFrançois Tigeot DRM_ERROR("PCH poison interrupt\n"); 2121e3adcf8fSFrançois Tigeot 2122e3adcf8fSFrançois Tigeot if (pch_iir & SDE_FDI_MASK) 21231b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 2124a2296444SFrançois Tigeot DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", 2125e3adcf8fSFrançois Tigeot pipe_name(pipe), 2126e3adcf8fSFrançois Tigeot I915_READ(FDI_RX_IIR(pipe))); 2127e3adcf8fSFrançois Tigeot 2128e3adcf8fSFrançois Tigeot if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) 2129a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n"); 2130e3adcf8fSFrançois Tigeot 2131e3adcf8fSFrançois Tigeot if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) 2132a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n"); 2133e3adcf8fSFrançois Tigeot 2134e3adcf8fSFrançois Tigeot if (pch_iir & SDE_TRANSA_FIFO_UNDER) 21352c9916cdSFrançois Tigeot intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_A); 21365d0b1887SFrançois Tigeot 21375d0b1887SFrançois Tigeot if (pch_iir & SDE_TRANSB_FIFO_UNDER) 21382c9916cdSFrançois Tigeot intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_B); 21395d0b1887SFrançois Tigeot } 21405d0b1887SFrançois Tigeot 21411487f786SFrançois Tigeot static void ivb_err_int_handler(struct drm_i915_private *dev_priv) 21425d0b1887SFrançois Tigeot { 21435d0b1887SFrançois Tigeot u32 err_int = I915_READ(GEN7_ERR_INT); 21449edbd4a0SFrançois Tigeot enum i915_pipe pipe; 21455d0b1887SFrançois Tigeot 21465d0b1887SFrançois Tigeot if (err_int & ERR_INT_POISON) 21475d0b1887SFrançois Tigeot DRM_ERROR("Poison interrupt\n"); 21485d0b1887SFrançois Tigeot 21491b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 21502c9916cdSFrançois Tigeot if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) 21512c9916cdSFrançois Tigeot intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); 21525d0b1887SFrançois Tigeot 21539edbd4a0SFrançois Tigeot if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { 21541487f786SFrançois Tigeot if (IS_IVYBRIDGE(dev_priv)) 21551487f786SFrançois Tigeot ivb_pipe_crc_irq_handler(dev_priv, pipe); 21569edbd4a0SFrançois Tigeot else 21571487f786SFrançois Tigeot hsw_pipe_crc_irq_handler(dev_priv, pipe); 21589edbd4a0SFrançois Tigeot } 21599edbd4a0SFrançois Tigeot } 21605d0b1887SFrançois Tigeot 21615d0b1887SFrançois Tigeot I915_WRITE(GEN7_ERR_INT, err_int); 21625d0b1887SFrançois Tigeot } 21635d0b1887SFrançois Tigeot 21641487f786SFrançois Tigeot static void cpt_serr_int_handler(struct drm_i915_private *dev_priv) 21655d0b1887SFrançois Tigeot { 21665d0b1887SFrançois Tigeot u32 serr_int = I915_READ(SERR_INT); 21675d0b1887SFrançois Tigeot 21685d0b1887SFrançois Tigeot if (serr_int & SERR_INT_POISON) 21695d0b1887SFrançois Tigeot DRM_ERROR("PCH poison interrupt\n"); 21705d0b1887SFrançois Tigeot 21715d0b1887SFrançois Tigeot if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN) 21722c9916cdSFrançois Tigeot intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_A); 21735d0b1887SFrançois Tigeot 21745d0b1887SFrançois Tigeot if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN) 21752c9916cdSFrançois Tigeot intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_B); 21765d0b1887SFrançois Tigeot 21775d0b1887SFrançois Tigeot if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN) 21782c9916cdSFrançois Tigeot intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_C); 21795d0b1887SFrançois Tigeot 21805d0b1887SFrançois Tigeot I915_WRITE(SERR_INT, serr_int); 2181a2296444SFrançois Tigeot } 2182a2296444SFrançois Tigeot 21831487f786SFrançois Tigeot static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) 2184a2296444SFrançois Tigeot { 2185a2296444SFrançois Tigeot int pipe; 2186352ff8bdSFrançois Tigeot u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; 2187a05eeebfSFrançois Tigeot 21881487f786SFrançois Tigeot ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_cpt); 21895d0b1887SFrançois Tigeot 21905d0b1887SFrançois Tigeot if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { 21915d0b1887SFrançois Tigeot int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> 2192a2296444SFrançois Tigeot SDE_AUDIO_POWER_SHIFT_CPT); 21935d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH audio power change on port %c\n", 21945d0b1887SFrançois Tigeot port_name(port)); 21955d0b1887SFrançois Tigeot } 2196a2296444SFrançois Tigeot 2197a2296444SFrançois Tigeot if (pch_iir & SDE_AUX_MASK_CPT) 21981487f786SFrançois Tigeot dp_aux_irq_handler(dev_priv); 2199a2296444SFrançois Tigeot 2200a2296444SFrançois Tigeot if (pch_iir & SDE_GMBUS_CPT) 22011487f786SFrançois Tigeot gmbus_irq_handler(dev_priv); 2202a2296444SFrançois Tigeot 2203a2296444SFrançois Tigeot if (pch_iir & SDE_AUDIO_CP_REQ_CPT) 2204a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("Audio CP request interrupt\n"); 2205a2296444SFrançois Tigeot 2206a2296444SFrançois Tigeot if (pch_iir & SDE_AUDIO_CP_CHG_CPT) 2207a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("Audio CP change interrupt\n"); 2208a2296444SFrançois Tigeot 2209a2296444SFrançois Tigeot if (pch_iir & SDE_FDI_MASK_CPT) 22101b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 2211a2296444SFrançois Tigeot DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", 2212a2296444SFrançois Tigeot pipe_name(pipe), 2213a2296444SFrançois Tigeot I915_READ(FDI_RX_IIR(pipe))); 22145d0b1887SFrançois Tigeot 22155d0b1887SFrançois Tigeot if (pch_iir & SDE_ERROR_CPT) 22161487f786SFrançois Tigeot cpt_serr_int_handler(dev_priv); 2217e3adcf8fSFrançois Tigeot } 2218e3adcf8fSFrançois Tigeot 22191487f786SFrançois Tigeot static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) 2220352ff8bdSFrançois Tigeot { 2221352ff8bdSFrançois Tigeot u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT & 2222352ff8bdSFrançois Tigeot ~SDE_PORTE_HOTPLUG_SPT; 2223352ff8bdSFrançois Tigeot u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT; 2224352ff8bdSFrançois Tigeot u32 pin_mask = 0, long_mask = 0; 2225352ff8bdSFrançois Tigeot 2226352ff8bdSFrançois Tigeot if (hotplug_trigger) { 2227352ff8bdSFrançois Tigeot u32 dig_hotplug_reg; 2228352ff8bdSFrançois Tigeot 2229352ff8bdSFrançois Tigeot dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); 2230352ff8bdSFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); 2231352ff8bdSFrançois Tigeot 2232352ff8bdSFrançois Tigeot intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, 2233352ff8bdSFrançois Tigeot dig_hotplug_reg, hpd_spt, 2234352ff8bdSFrançois Tigeot spt_port_hotplug_long_detect); 2235352ff8bdSFrançois Tigeot } 2236352ff8bdSFrançois Tigeot 2237352ff8bdSFrançois Tigeot if (hotplug2_trigger) { 2238352ff8bdSFrançois Tigeot u32 dig_hotplug_reg; 2239352ff8bdSFrançois Tigeot 2240352ff8bdSFrançois Tigeot dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2); 2241352ff8bdSFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG2, dig_hotplug_reg); 2242352ff8bdSFrançois Tigeot 2243352ff8bdSFrançois Tigeot intel_get_hpd_pins(&pin_mask, &long_mask, hotplug2_trigger, 2244352ff8bdSFrançois Tigeot dig_hotplug_reg, hpd_spt, 2245352ff8bdSFrançois Tigeot spt_port_hotplug2_long_detect); 2246352ff8bdSFrançois Tigeot } 2247352ff8bdSFrançois Tigeot 2248352ff8bdSFrançois Tigeot if (pin_mask) 22491487f786SFrançois Tigeot intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); 2250352ff8bdSFrançois Tigeot 2251352ff8bdSFrançois Tigeot if (pch_iir & SDE_GMBUS_CPT) 22521487f786SFrançois Tigeot gmbus_irq_handler(dev_priv); 2253352ff8bdSFrançois Tigeot } 2254352ff8bdSFrançois Tigeot 22551487f786SFrançois Tigeot static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv, 22561487f786SFrançois Tigeot u32 hotplug_trigger, 2257352ff8bdSFrançois Tigeot const u32 hpd[HPD_NUM_PINS]) 2258352ff8bdSFrançois Tigeot { 2259352ff8bdSFrançois Tigeot u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; 2260352ff8bdSFrançois Tigeot 2261352ff8bdSFrançois Tigeot dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL); 2262352ff8bdSFrançois Tigeot I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg); 2263352ff8bdSFrançois Tigeot 2264352ff8bdSFrançois Tigeot intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, 2265352ff8bdSFrançois Tigeot dig_hotplug_reg, hpd, 2266352ff8bdSFrançois Tigeot ilk_port_hotplug_long_detect); 2267352ff8bdSFrançois Tigeot 22681487f786SFrançois Tigeot intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); 2269352ff8bdSFrançois Tigeot } 2270352ff8bdSFrançois Tigeot 22711487f786SFrançois Tigeot static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, 22721487f786SFrançois Tigeot u32 de_iir) 2273c4a9e910SFrançois Tigeot { 22749edbd4a0SFrançois Tigeot enum i915_pipe pipe; 2275352ff8bdSFrançois Tigeot u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; 2276352ff8bdSFrançois Tigeot 2277352ff8bdSFrançois Tigeot if (hotplug_trigger) 22781487f786SFrançois Tigeot ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ilk); 2279e3adcf8fSFrançois Tigeot 2280a2fdbec6SFrançois Tigeot if (de_iir & DE_AUX_CHANNEL_A) 22811487f786SFrançois Tigeot dp_aux_irq_handler(dev_priv); 2282a2fdbec6SFrançois Tigeot 228300640ec9SFrançois Tigeot if (de_iir & DE_GSE) 22841487f786SFrançois Tigeot intel_opregion_asle_intr(dev_priv); 2285e3adcf8fSFrançois Tigeot 22865d0b1887SFrançois Tigeot if (de_iir & DE_POISON) 22875d0b1887SFrançois Tigeot DRM_ERROR("Poison interrupt\n"); 22885d0b1887SFrançois Tigeot 22891b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 22901b13d190SFrançois Tigeot if (de_iir & DE_PIPE_VBLANK(pipe) && 22911487f786SFrançois Tigeot intel_pipe_handle_vblank(dev_priv, pipe)) 22921487f786SFrançois Tigeot intel_check_page_flip(dev_priv, pipe); 22935d0b1887SFrançois Tigeot 22949edbd4a0SFrançois Tigeot if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) 22952c9916cdSFrançois Tigeot intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); 22965d0b1887SFrançois Tigeot 22979edbd4a0SFrançois Tigeot if (de_iir & DE_PIPE_CRC_DONE(pipe)) 22981487f786SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev_priv, pipe); 22999edbd4a0SFrançois Tigeot 23009edbd4a0SFrançois Tigeot /* plane/pipes map 1:1 on ilk+ */ 23011487f786SFrançois Tigeot if (de_iir & DE_PLANE_FLIP_DONE(pipe)) 23021487f786SFrançois Tigeot intel_finish_page_flip_cs(dev_priv, pipe); 2303e3adcf8fSFrançois Tigeot } 2304e3adcf8fSFrançois Tigeot 2305e3adcf8fSFrançois Tigeot /* check event from PCH */ 2306e3adcf8fSFrançois Tigeot if (de_iir & DE_PCH_EVENT) { 2307a2fdbec6SFrançois Tigeot u32 pch_iir = I915_READ(SDEIIR); 2308a2fdbec6SFrançois Tigeot 23091487f786SFrançois Tigeot if (HAS_PCH_CPT(dev_priv)) 23101487f786SFrançois Tigeot cpt_irq_handler(dev_priv, pch_iir); 2311a2296444SFrançois Tigeot else 23121487f786SFrançois Tigeot ibx_irq_handler(dev_priv, pch_iir); 2313a2fdbec6SFrançois Tigeot 2314a2fdbec6SFrançois Tigeot /* should clear PCH hotplug event before clear CPU irq */ 2315a2fdbec6SFrançois Tigeot I915_WRITE(SDEIIR, pch_iir); 2316e3adcf8fSFrançois Tigeot } 2317e3adcf8fSFrançois Tigeot 23181487f786SFrançois Tigeot if (IS_GEN5(dev_priv) && de_iir & DE_PCU_EVENT) 23191487f786SFrançois Tigeot ironlake_rps_change_irq_handler(dev_priv); 23209edbd4a0SFrançois Tigeot } 2321e3adcf8fSFrançois Tigeot 23221487f786SFrançois Tigeot static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, 23231487f786SFrançois Tigeot u32 de_iir) 23249edbd4a0SFrançois Tigeot { 2325ba55f2f5SFrançois Tigeot enum i915_pipe pipe; 2326352ff8bdSFrançois Tigeot u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; 2327352ff8bdSFrançois Tigeot 2328352ff8bdSFrançois Tigeot if (hotplug_trigger) 23291487f786SFrançois Tigeot ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ivb); 2330e3adcf8fSFrançois Tigeot 23319edbd4a0SFrançois Tigeot if (de_iir & DE_ERR_INT_IVB) 23321487f786SFrançois Tigeot ivb_err_int_handler(dev_priv); 23339edbd4a0SFrançois Tigeot 23349edbd4a0SFrançois Tigeot if (de_iir & DE_AUX_CHANNEL_A_IVB) 23351487f786SFrançois Tigeot dp_aux_irq_handler(dev_priv); 23369edbd4a0SFrançois Tigeot 23379edbd4a0SFrançois Tigeot if (de_iir & DE_GSE_IVB) 23381487f786SFrançois Tigeot intel_opregion_asle_intr(dev_priv); 23399edbd4a0SFrançois Tigeot 23401b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 23411b13d190SFrançois Tigeot if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) && 23421487f786SFrançois Tigeot intel_pipe_handle_vblank(dev_priv, pipe)) 23431487f786SFrançois Tigeot intel_check_page_flip(dev_priv, pipe); 23449edbd4a0SFrançois Tigeot 23459edbd4a0SFrançois Tigeot /* plane/pipes map 1:1 on ilk+ */ 23461487f786SFrançois Tigeot if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) 23471487f786SFrançois Tigeot intel_finish_page_flip_cs(dev_priv, pipe); 23489edbd4a0SFrançois Tigeot } 23499edbd4a0SFrançois Tigeot 23509edbd4a0SFrançois Tigeot /* check event from PCH */ 23511487f786SFrançois Tigeot if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) { 23529edbd4a0SFrançois Tigeot u32 pch_iir = I915_READ(SDEIIR); 23539edbd4a0SFrançois Tigeot 23541487f786SFrançois Tigeot cpt_irq_handler(dev_priv, pch_iir); 23559edbd4a0SFrançois Tigeot 23569edbd4a0SFrançois Tigeot /* clear PCH hotplug event before clear CPU irq */ 23579edbd4a0SFrançois Tigeot I915_WRITE(SDEIIR, pch_iir); 23589edbd4a0SFrançois Tigeot } 23599edbd4a0SFrançois Tigeot } 23609edbd4a0SFrançois Tigeot 236124edb884SFrançois Tigeot /* 236224edb884SFrançois Tigeot * To handle irqs with the minimum potential races with fresh interrupts, we: 236324edb884SFrançois Tigeot * 1 - Disable Master Interrupt Control. 236424edb884SFrançois Tigeot * 2 - Find the source(s) of the interrupt. 236524edb884SFrançois Tigeot * 3 - Clear the Interrupt Identity bits (IIR). 236624edb884SFrançois Tigeot * 4 - Process the interrupt(s) that had bits set in the IIRs. 236724edb884SFrançois Tigeot * 5 - Re-enable Master Interrupt Control. 236824edb884SFrançois Tigeot */ 2369183e2373SFrançois Tigeot static irqreturn_t ironlake_irq_handler(int irq, void *arg) 23709edbd4a0SFrançois Tigeot { 2371ba55f2f5SFrançois Tigeot struct drm_device *dev = arg; 2372303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 23739edbd4a0SFrançois Tigeot u32 de_iir, gt_iir, de_ier, sde_ier = 0; 2374183e2373SFrançois Tigeot irqreturn_t ret = IRQ_NONE; 23759edbd4a0SFrançois Tigeot 23762c9916cdSFrançois Tigeot if (!intel_irqs_enabled(dev_priv)) 23772c9916cdSFrançois Tigeot return IRQ_NONE; 23782c9916cdSFrançois Tigeot 2379aee94f86SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 2380aee94f86SFrançois Tigeot disable_rpm_wakeref_asserts(dev_priv); 2381aee94f86SFrançois Tigeot 23829edbd4a0SFrançois Tigeot /* disable master interrupt before clearing iir */ 23839edbd4a0SFrançois Tigeot de_ier = I915_READ(DEIER); 23849edbd4a0SFrançois Tigeot I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); 23859edbd4a0SFrançois Tigeot POSTING_READ(DEIER); 23869edbd4a0SFrançois Tigeot 23879edbd4a0SFrançois Tigeot /* Disable south interrupts. We'll only write to SDEIIR once, so further 23889edbd4a0SFrançois Tigeot * interrupts will will be stored on its back queue, and then we'll be 23899edbd4a0SFrançois Tigeot * able to process them after we restore SDEIER (as soon as we restore 23909edbd4a0SFrançois Tigeot * it, we'll get an interrupt if SDEIIR still has something to process 23919edbd4a0SFrançois Tigeot * due to its back queue). */ 23921487f786SFrançois Tigeot if (!HAS_PCH_NOP(dev_priv)) { 23939edbd4a0SFrançois Tigeot sde_ier = I915_READ(SDEIER); 23949edbd4a0SFrançois Tigeot I915_WRITE(SDEIER, 0); 23959edbd4a0SFrançois Tigeot POSTING_READ(SDEIER); 23969edbd4a0SFrançois Tigeot } 23979edbd4a0SFrançois Tigeot 239824edb884SFrançois Tigeot /* Find, clear, then process each source of interrupt */ 239924edb884SFrançois Tigeot 24009edbd4a0SFrançois Tigeot gt_iir = I915_READ(GTIIR); 24019edbd4a0SFrançois Tigeot if (gt_iir) { 240224edb884SFrançois Tigeot I915_WRITE(GTIIR, gt_iir); 2403183e2373SFrançois Tigeot ret = IRQ_HANDLED; 24041487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 6) 24058621f407SFrançois Tigeot snb_gt_irq_handler(dev_priv, gt_iir); 24069edbd4a0SFrançois Tigeot else 24078621f407SFrançois Tigeot ilk_gt_irq_handler(dev_priv, gt_iir); 24089edbd4a0SFrançois Tigeot } 2409e3adcf8fSFrançois Tigeot 24109edbd4a0SFrançois Tigeot de_iir = I915_READ(DEIIR); 24119edbd4a0SFrançois Tigeot if (de_iir) { 241224edb884SFrançois Tigeot I915_WRITE(DEIIR, de_iir); 2413183e2373SFrançois Tigeot ret = IRQ_HANDLED; 24141487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 7) 24151487f786SFrançois Tigeot ivb_display_irq_handler(dev_priv, de_iir); 24169edbd4a0SFrançois Tigeot else 24171487f786SFrançois Tigeot ilk_display_irq_handler(dev_priv, de_iir); 24189edbd4a0SFrançois Tigeot } 24199edbd4a0SFrançois Tigeot 24201487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 6) { 24219edbd4a0SFrançois Tigeot u32 pm_iir = I915_READ(GEN6_PMIIR); 24229edbd4a0SFrançois Tigeot if (pm_iir) { 24239edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIIR, pm_iir); 2424183e2373SFrançois Tigeot ret = IRQ_HANDLED; 242524edb884SFrançois Tigeot gen6_rps_irq_handler(dev_priv, pm_iir); 24269edbd4a0SFrançois Tigeot } 24279edbd4a0SFrançois Tigeot } 24289edbd4a0SFrançois Tigeot 2429e3adcf8fSFrançois Tigeot I915_WRITE(DEIER, de_ier); 2430e3adcf8fSFrançois Tigeot POSTING_READ(DEIER); 24311487f786SFrançois Tigeot if (!HAS_PCH_NOP(dev_priv)) { 2432a2fdbec6SFrançois Tigeot I915_WRITE(SDEIER, sde_ier); 2433a2fdbec6SFrançois Tigeot POSTING_READ(SDEIER); 2434e3adcf8fSFrançois Tigeot } 2435e3adcf8fSFrançois Tigeot 2436aee94f86SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 2437aee94f86SFrançois Tigeot enable_rpm_wakeref_asserts(dev_priv); 2438aee94f86SFrançois Tigeot 2439183e2373SFrançois Tigeot return ret; 24409edbd4a0SFrançois Tigeot } 24419edbd4a0SFrançois Tigeot 24421487f786SFrançois Tigeot static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, 24431487f786SFrançois Tigeot u32 hotplug_trigger, 2444352ff8bdSFrançois Tigeot const u32 hpd[HPD_NUM_PINS]) 244519c468b4SFrançois Tigeot { 2446352ff8bdSFrançois Tigeot u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; 244719c468b4SFrançois Tigeot 2448352ff8bdSFrançois Tigeot dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); 2449352ff8bdSFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); 245019c468b4SFrançois Tigeot 2451352ff8bdSFrançois Tigeot intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, 2452352ff8bdSFrançois Tigeot dig_hotplug_reg, hpd, 2453352ff8bdSFrançois Tigeot bxt_port_hotplug_long_detect); 245419c468b4SFrançois Tigeot 24551487f786SFrançois Tigeot intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); 245619c468b4SFrançois Tigeot } 245719c468b4SFrançois Tigeot 2458c0e85e96SFrançois Tigeot static irqreturn_t 2459c0e85e96SFrançois Tigeot gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) 24609edbd4a0SFrançois Tigeot { 2461183e2373SFrançois Tigeot irqreturn_t ret = IRQ_NONE; 2462c0e85e96SFrançois Tigeot u32 iir; 24639edbd4a0SFrançois Tigeot enum i915_pipe pipe; 24649edbd4a0SFrançois Tigeot 24659edbd4a0SFrançois Tigeot if (master_ctl & GEN8_DE_MISC_IRQ) { 2466c0e85e96SFrançois Tigeot iir = I915_READ(GEN8_DE_MISC_IIR); 2467c0e85e96SFrançois Tigeot if (iir) { 2468c0e85e96SFrançois Tigeot I915_WRITE(GEN8_DE_MISC_IIR, iir); 2469183e2373SFrançois Tigeot ret = IRQ_HANDLED; 2470c0e85e96SFrançois Tigeot if (iir & GEN8_DE_MISC_GSE) 24711487f786SFrançois Tigeot intel_opregion_asle_intr(dev_priv); 247224edb884SFrançois Tigeot else 247324edb884SFrançois Tigeot DRM_ERROR("Unexpected DE Misc interrupt\n"); 24749edbd4a0SFrançois Tigeot } 247524edb884SFrançois Tigeot else 247624edb884SFrançois Tigeot DRM_ERROR("The master control interrupt lied (DE MISC)!\n"); 24779edbd4a0SFrançois Tigeot } 24789edbd4a0SFrançois Tigeot 24799edbd4a0SFrançois Tigeot if (master_ctl & GEN8_DE_PORT_IRQ) { 2480c0e85e96SFrançois Tigeot iir = I915_READ(GEN8_DE_PORT_IIR); 2481c0e85e96SFrançois Tigeot if (iir) { 2482c0e85e96SFrançois Tigeot u32 tmp_mask; 248319c468b4SFrançois Tigeot bool found = false; 2484352ff8bdSFrançois Tigeot 2485c0e85e96SFrançois Tigeot I915_WRITE(GEN8_DE_PORT_IIR, iir); 2486183e2373SFrançois Tigeot ret = IRQ_HANDLED; 248719c468b4SFrançois Tigeot 2488c0e85e96SFrançois Tigeot tmp_mask = GEN8_AUX_CHANNEL_A; 2489c0e85e96SFrançois Tigeot if (INTEL_INFO(dev_priv)->gen >= 9) 2490c0e85e96SFrançois Tigeot tmp_mask |= GEN9_AUX_CHANNEL_B | 2491c0e85e96SFrançois Tigeot GEN9_AUX_CHANNEL_C | 2492c0e85e96SFrançois Tigeot GEN9_AUX_CHANNEL_D; 249319c468b4SFrançois Tigeot 2494c0e85e96SFrançois Tigeot if (iir & tmp_mask) { 24951487f786SFrançois Tigeot dp_aux_irq_handler(dev_priv); 249619c468b4SFrançois Tigeot found = true; 249719c468b4SFrançois Tigeot } 249819c468b4SFrançois Tigeot 2499*a85cb24fSFrançois Tigeot if (IS_GEN9_LP(dev_priv)) { 2500c0e85e96SFrançois Tigeot tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK; 2501c0e85e96SFrançois Tigeot if (tmp_mask) { 25021487f786SFrançois Tigeot bxt_hpd_irq_handler(dev_priv, tmp_mask, 25031487f786SFrançois Tigeot hpd_bxt); 250419c468b4SFrançois Tigeot found = true; 250519c468b4SFrançois Tigeot } 2506c0e85e96SFrançois Tigeot } else if (IS_BROADWELL(dev_priv)) { 2507c0e85e96SFrançois Tigeot tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG; 2508c0e85e96SFrançois Tigeot if (tmp_mask) { 25091487f786SFrançois Tigeot ilk_hpd_irq_handler(dev_priv, 25101487f786SFrançois Tigeot tmp_mask, hpd_bdw); 2511c0e85e96SFrançois Tigeot found = true; 2512c0e85e96SFrançois Tigeot } 2513c0e85e96SFrançois Tigeot } 251419c468b4SFrançois Tigeot 2515*a85cb24fSFrançois Tigeot if (IS_GEN9_LP(dev_priv) && (iir & BXT_DE_PORT_GMBUS)) { 25161487f786SFrançois Tigeot gmbus_irq_handler(dev_priv); 251719c468b4SFrançois Tigeot found = true; 251819c468b4SFrançois Tigeot } 251919c468b4SFrançois Tigeot 252019c468b4SFrançois Tigeot if (!found) 252124edb884SFrançois Tigeot DRM_ERROR("Unexpected DE Port interrupt\n"); 25229edbd4a0SFrançois Tigeot } 252324edb884SFrançois Tigeot else 252424edb884SFrançois Tigeot DRM_ERROR("The master control interrupt lied (DE PORT)!\n"); 25259edbd4a0SFrançois Tigeot } 25269edbd4a0SFrançois Tigeot 25271b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 2528c0e85e96SFrançois Tigeot u32 flip_done, fault_errors; 25299edbd4a0SFrançois Tigeot 25309edbd4a0SFrançois Tigeot if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) 25319edbd4a0SFrançois Tigeot continue; 25329edbd4a0SFrançois Tigeot 2533c0e85e96SFrançois Tigeot iir = I915_READ(GEN8_DE_PIPE_IIR(pipe)); 2534c0e85e96SFrançois Tigeot if (!iir) { 2535c0e85e96SFrançois Tigeot DRM_ERROR("The master control interrupt lied (DE PIPE)!\n"); 2536c0e85e96SFrançois Tigeot continue; 2537c0e85e96SFrançois Tigeot } 25382c9916cdSFrançois Tigeot 2539183e2373SFrançois Tigeot ret = IRQ_HANDLED; 2540c0e85e96SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir); 2541c0e85e96SFrançois Tigeot 2542c0e85e96SFrançois Tigeot if (iir & GEN8_PIPE_VBLANK && 25431487f786SFrançois Tigeot intel_pipe_handle_vblank(dev_priv, pipe)) 25441487f786SFrançois Tigeot intel_check_page_flip(dev_priv, pipe); 25459edbd4a0SFrançois Tigeot 2546c0e85e96SFrançois Tigeot flip_done = iir; 2547352ff8bdSFrançois Tigeot if (INTEL_INFO(dev_priv)->gen >= 9) 2548c0e85e96SFrançois Tigeot flip_done &= GEN9_PIPE_PLANE1_FLIP_DONE; 25492c9916cdSFrançois Tigeot else 2550c0e85e96SFrançois Tigeot flip_done &= GEN8_PIPE_PRIMARY_FLIP_DONE; 25512c9916cdSFrançois Tigeot 25521487f786SFrançois Tigeot if (flip_done) 25531487f786SFrançois Tigeot intel_finish_page_flip_cs(dev_priv, pipe); 25549edbd4a0SFrançois Tigeot 2555c0e85e96SFrançois Tigeot if (iir & GEN8_PIPE_CDCLK_CRC_DONE) 25561487f786SFrançois Tigeot hsw_pipe_crc_irq_handler(dev_priv, pipe); 25579edbd4a0SFrançois Tigeot 2558c0e85e96SFrançois Tigeot if (iir & GEN8_PIPE_FIFO_UNDERRUN) 2559c0e85e96SFrançois Tigeot intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); 25609edbd4a0SFrançois Tigeot 2561c0e85e96SFrançois Tigeot fault_errors = iir; 2562352ff8bdSFrançois Tigeot if (INTEL_INFO(dev_priv)->gen >= 9) 2563c0e85e96SFrançois Tigeot fault_errors &= GEN9_DE_PIPE_IRQ_FAULT_ERRORS; 25642c9916cdSFrançois Tigeot else 2565c0e85e96SFrançois Tigeot fault_errors &= GEN8_DE_PIPE_IRQ_FAULT_ERRORS; 25662c9916cdSFrançois Tigeot 25672c9916cdSFrançois Tigeot if (fault_errors) 25684be47400SFrançois Tigeot DRM_ERROR("Fault errors on pipe %c: 0x%08x\n", 25699edbd4a0SFrançois Tigeot pipe_name(pipe), 2570c0e85e96SFrançois Tigeot fault_errors); 25719edbd4a0SFrançois Tigeot } 25729edbd4a0SFrançois Tigeot 25731487f786SFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) && 257419c468b4SFrançois Tigeot master_ctl & GEN8_DE_PCH_IRQ) { 25759edbd4a0SFrançois Tigeot /* 25769edbd4a0SFrançois Tigeot * FIXME(BDW): Assume for now that the new interrupt handling 25779edbd4a0SFrançois Tigeot * scheme also closed the SDE interrupt handling race we've seen 25789edbd4a0SFrançois Tigeot * on older pch-split platforms. But this needs testing. 25799edbd4a0SFrançois Tigeot */ 2580c0e85e96SFrançois Tigeot iir = I915_READ(SDEIIR); 2581c0e85e96SFrançois Tigeot if (iir) { 2582c0e85e96SFrançois Tigeot I915_WRITE(SDEIIR, iir); 2583183e2373SFrançois Tigeot ret = IRQ_HANDLED; 2584352ff8bdSFrançois Tigeot 2585303bf270SFrançois Tigeot if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv)) 25861487f786SFrançois Tigeot spt_irq_handler(dev_priv, iir); 2587352ff8bdSFrançois Tigeot else 25881487f786SFrançois Tigeot cpt_irq_handler(dev_priv, iir); 2589aee94f86SFrançois Tigeot } else { 2590aee94f86SFrançois Tigeot /* 2591aee94f86SFrançois Tigeot * Like on previous PCH there seems to be something 2592aee94f86SFrançois Tigeot * fishy going on with forwarding PCH interrupts. 2593aee94f86SFrançois Tigeot */ 2594aee94f86SFrançois Tigeot DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n"); 2595aee94f86SFrançois Tigeot } 25969edbd4a0SFrançois Tigeot } 25979edbd4a0SFrançois Tigeot 2598183e2373SFrançois Tigeot return ret; 2599c0e85e96SFrançois Tigeot } 2600c0e85e96SFrançois Tigeot 2601183e2373SFrançois Tigeot static irqreturn_t gen8_irq_handler(int irq, void *arg) 2602c0e85e96SFrançois Tigeot { 2603c0e85e96SFrançois Tigeot struct drm_device *dev = arg; 2604303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 2605c0e85e96SFrançois Tigeot u32 master_ctl; 26068621f407SFrançois Tigeot u32 gt_iir[4] = {}; 2607183e2373SFrançois Tigeot irqreturn_t ret; 2608c0e85e96SFrançois Tigeot 2609c0e85e96SFrançois Tigeot if (!intel_irqs_enabled(dev_priv)) 2610c0e85e96SFrançois Tigeot return IRQ_NONE; 2611c0e85e96SFrançois Tigeot 2612c0e85e96SFrançois Tigeot master_ctl = I915_READ_FW(GEN8_MASTER_IRQ); 2613c0e85e96SFrançois Tigeot master_ctl &= ~GEN8_MASTER_IRQ_CONTROL; 2614c0e85e96SFrançois Tigeot if (!master_ctl) 2615c0e85e96SFrançois Tigeot return IRQ_NONE; 2616c0e85e96SFrançois Tigeot 2617c0e85e96SFrançois Tigeot I915_WRITE_FW(GEN8_MASTER_IRQ, 0); 2618c0e85e96SFrançois Tigeot 2619c0e85e96SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 2620c0e85e96SFrançois Tigeot disable_rpm_wakeref_asserts(dev_priv); 2621c0e85e96SFrançois Tigeot 2622c0e85e96SFrançois Tigeot /* Find, clear, then process each source of interrupt */ 2623183e2373SFrançois Tigeot ret = gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir); 26248621f407SFrançois Tigeot gen8_gt_irq_handler(dev_priv, gt_iir); 2625183e2373SFrançois Tigeot ret |= gen8_de_irq_handler(dev_priv, master_ctl); 2626c0e85e96SFrançois Tigeot 262719c468b4SFrançois Tigeot I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); 262819c468b4SFrançois Tigeot POSTING_READ_FW(GEN8_MASTER_IRQ); 26299edbd4a0SFrançois Tigeot 2630aee94f86SFrançois Tigeot enable_rpm_wakeref_asserts(dev_priv); 2631aee94f86SFrançois Tigeot 2632183e2373SFrançois Tigeot return ret; 26339edbd4a0SFrançois Tigeot } 26349edbd4a0SFrançois Tigeot 2635e3adcf8fSFrançois Tigeot /** 26362c9916cdSFrançois Tigeot * i915_reset_and_wakeup - do process context error handling work 26371487f786SFrançois Tigeot * @dev_priv: i915 device private 2638e3adcf8fSFrançois Tigeot * 2639e3adcf8fSFrançois Tigeot * Fire an error uevent so userspace can see that a hang or error 2640e3adcf8fSFrançois Tigeot * was detected. 2641e3adcf8fSFrançois Tigeot */ 26421487f786SFrançois Tigeot static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv) 2643e3adcf8fSFrançois Tigeot { 2644303bf270SFrançois Tigeot struct kobject *kobj = &dev_priv->drm.primary->kdev->kobj; 26459edbd4a0SFrançois Tigeot char *error_event[] = { I915_ERROR_UEVENT "=1", NULL }; 26469edbd4a0SFrançois Tigeot char *reset_event[] = { I915_RESET_UEVENT "=1", NULL }; 26479edbd4a0SFrançois Tigeot char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL }; 2648e3adcf8fSFrançois Tigeot 26491487f786SFrançois Tigeot kobject_uevent_env(kobj, KOBJ_CHANGE, error_event); 2650e3adcf8fSFrançois Tigeot 2651abf1f4f4SFrançois Tigeot DRM_DEBUG_DRIVER("resetting chip\n"); 26521487f786SFrançois Tigeot kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event); 2653a2fdbec6SFrançois Tigeot 26541487f786SFrançois Tigeot intel_prepare_reset(dev_priv); 26552c9916cdSFrançois Tigeot 2656*a85cb24fSFrançois Tigeot set_bit(I915_RESET_HANDOFF, &dev_priv->gpu_error.flags); 2657*a85cb24fSFrançois Tigeot wake_up_all(&dev_priv->gpu_error.wait_queue); 2658*a85cb24fSFrançois Tigeot 26591e12ee3bSFrançois Tigeot do { 2660ba55f2f5SFrançois Tigeot /* 26619edbd4a0SFrançois Tigeot * All state reset _must_ be completed before we update the 26629edbd4a0SFrançois Tigeot * reset counter, for otherwise waiters might miss the reset 26639edbd4a0SFrançois Tigeot * pending state and not properly drop locks, resulting in 26649edbd4a0SFrançois Tigeot * deadlocks with the reset work. 26659edbd4a0SFrançois Tigeot */ 26661e12ee3bSFrançois Tigeot if (mutex_trylock(&dev_priv->drm.struct_mutex)) { 26671e12ee3bSFrançois Tigeot i915_reset(dev_priv); 26681e12ee3bSFrançois Tigeot mutex_unlock(&dev_priv->drm.struct_mutex); 26691e12ee3bSFrançois Tigeot } 26701e12ee3bSFrançois Tigeot 26711e12ee3bSFrançois Tigeot /* We need to wait for anyone holding the lock to wakeup */ 26721e12ee3bSFrançois Tigeot } while (wait_on_bit_timeout(&dev_priv->gpu_error.flags, 2673*a85cb24fSFrançois Tigeot I915_RESET_HANDOFF, 26741e12ee3bSFrançois Tigeot TASK_UNINTERRUPTIBLE, 26751e12ee3bSFrançois Tigeot HZ)); 2676a2fdbec6SFrançois Tigeot 26771487f786SFrançois Tigeot intel_finish_reset(dev_priv); 2678ba55f2f5SFrançois Tigeot 26791e12ee3bSFrançois Tigeot if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags)) 26801487f786SFrançois Tigeot kobject_uevent_env(kobj, 2681a2fdbec6SFrançois Tigeot KOBJ_CHANGE, reset_done_event); 2682a2fdbec6SFrançois Tigeot 26839edbd4a0SFrançois Tigeot /* 26849edbd4a0SFrançois Tigeot * Note: The wake_up also serves as a memory barrier so that 26851e12ee3bSFrançois Tigeot * waiters see the updated value of the dev_priv->gpu_error. 2686e3adcf8fSFrançois Tigeot */ 2687*a85cb24fSFrançois Tigeot clear_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags); 26881487f786SFrançois Tigeot wake_up_all(&dev_priv->gpu_error.reset_queue); 2689e3adcf8fSFrançois Tigeot } 2690e3adcf8fSFrançois Tigeot 26911e12ee3bSFrançois Tigeot static inline void 26921e12ee3bSFrançois Tigeot i915_err_print_instdone(struct drm_i915_private *dev_priv, 26931e12ee3bSFrançois Tigeot struct intel_instdone *instdone) 2694e9243325SFrançois Tigeot { 26951e12ee3bSFrançois Tigeot int slice; 26961e12ee3bSFrançois Tigeot int subslice; 2697e9243325SFrançois Tigeot 26981e12ee3bSFrançois Tigeot pr_err(" INSTDONE: 0x%08x\n", instdone->instdone); 26991e12ee3bSFrançois Tigeot 27001e12ee3bSFrançois Tigeot if (INTEL_GEN(dev_priv) <= 3) 2701e9243325SFrançois Tigeot return; 2702e9243325SFrançois Tigeot 27031e12ee3bSFrançois Tigeot pr_err(" SC_INSTDONE: 0x%08x\n", instdone->slice_common); 270400640ec9SFrançois Tigeot 27051e12ee3bSFrançois Tigeot if (INTEL_GEN(dev_priv) <= 6) 27061e12ee3bSFrançois Tigeot return; 2707e9243325SFrançois Tigeot 27081e12ee3bSFrançois Tigeot for_each_instdone_slice_subslice(dev_priv, slice, subslice) 27091e12ee3bSFrançois Tigeot pr_err(" SAMPLER_INSTDONE[%d][%d]: 0x%08x\n", 27101e12ee3bSFrançois Tigeot slice, subslice, instdone->sampler[slice][subslice]); 2711e9243325SFrançois Tigeot 27121e12ee3bSFrançois Tigeot for_each_instdone_slice_subslice(dev_priv, slice, subslice) 27131e12ee3bSFrançois Tigeot pr_err(" ROW_INSTDONE[%d][%d]: 0x%08x\n", 27141e12ee3bSFrançois Tigeot slice, subslice, instdone->row[slice][subslice]); 2715e9243325SFrançois Tigeot } 2716e9243325SFrançois Tigeot 27171e12ee3bSFrançois Tigeot static void i915_clear_error_registers(struct drm_i915_private *dev_priv) 27181e12ee3bSFrançois Tigeot { 27191e12ee3bSFrançois Tigeot u32 eir; 2720e9243325SFrançois Tigeot 27211e12ee3bSFrançois Tigeot if (!IS_GEN2(dev_priv)) 27221e12ee3bSFrançois Tigeot I915_WRITE(PGTBL_ER, I915_READ(PGTBL_ER)); 2723e9243325SFrançois Tigeot 27241e12ee3bSFrançois Tigeot if (INTEL_GEN(dev_priv) < 4) 27251e12ee3bSFrançois Tigeot I915_WRITE(IPEIR, I915_READ(IPEIR)); 27261e12ee3bSFrançois Tigeot else 27271e12ee3bSFrançois Tigeot I915_WRITE(IPEIR_I965, I915_READ(IPEIR_I965)); 2728e9243325SFrançois Tigeot 27291e12ee3bSFrançois Tigeot I915_WRITE(EIR, I915_READ(EIR)); 2730e9243325SFrançois Tigeot eir = I915_READ(EIR); 2731e9243325SFrançois Tigeot if (eir) { 2732e9243325SFrançois Tigeot /* 2733e9243325SFrançois Tigeot * some errors might have become stuck, 2734e9243325SFrançois Tigeot * mask them. 2735e9243325SFrançois Tigeot */ 27361e12ee3bSFrançois Tigeot DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masking\n", eir); 2737e9243325SFrançois Tigeot I915_WRITE(EMR, I915_READ(EMR) | eir); 2738e9243325SFrançois Tigeot I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 2739e9243325SFrançois Tigeot } 2740e9243325SFrançois Tigeot } 2741e9243325SFrançois Tigeot 2742e9243325SFrançois Tigeot /** 27432c9916cdSFrançois Tigeot * i915_handle_error - handle a gpu error 27441487f786SFrançois Tigeot * @dev_priv: i915 device private 27458621f407SFrançois Tigeot * @engine_mask: mask representing engines that are hung 2746*a85cb24fSFrançois Tigeot * @fmt: Error message format string 2747*a85cb24fSFrançois Tigeot * 2748352ff8bdSFrançois Tigeot * Do some basic checking of register state at error time and 2749e9243325SFrançois Tigeot * dump it to the syslog. Also call i915_capture_error_state() to make 2750e9243325SFrançois Tigeot * sure we get a record and make it available in debugfs. Fire a uevent 2751e9243325SFrançois Tigeot * so userspace knows something bad happened (should trigger collection 2752e9243325SFrançois Tigeot * of a ring dump etc.). 2753e9243325SFrançois Tigeot */ 27541487f786SFrançois Tigeot void i915_handle_error(struct drm_i915_private *dev_priv, 27551487f786SFrançois Tigeot u32 engine_mask, 2756ba55f2f5SFrançois Tigeot const char *fmt, ...) 2757e9243325SFrançois Tigeot { 2758ba55f2f5SFrançois Tigeot va_list args; 2759ba55f2f5SFrançois Tigeot char error_msg[80]; 2760ba55f2f5SFrançois Tigeot 2761ba55f2f5SFrançois Tigeot va_start(args, fmt); 2762ba55f2f5SFrançois Tigeot vscnprintf(error_msg, sizeof(error_msg), fmt, args); 2763ba55f2f5SFrançois Tigeot va_end(args); 2764ba55f2f5SFrançois Tigeot 2765*a85cb24fSFrançois Tigeot /* 2766*a85cb24fSFrançois Tigeot * In most cases it's guaranteed that we get here with an RPM 2767*a85cb24fSFrançois Tigeot * reference held, for example because there is a pending GPU 2768*a85cb24fSFrançois Tigeot * request that won't finish until the reset is done. This 2769*a85cb24fSFrançois Tigeot * isn't the case at least when we get here by doing a 2770*a85cb24fSFrançois Tigeot * simulated reset via debugfs, so get an RPM reference. 2771*a85cb24fSFrançois Tigeot */ 2772*a85cb24fSFrançois Tigeot intel_runtime_pm_get(dev_priv); 2773*a85cb24fSFrançois Tigeot 27741487f786SFrançois Tigeot i915_capture_error_state(dev_priv, engine_mask, error_msg); 27751e12ee3bSFrançois Tigeot i915_clear_error_registers(dev_priv); 2776e9243325SFrançois Tigeot 27771e12ee3bSFrançois Tigeot if (!engine_mask) 2778*a85cb24fSFrançois Tigeot goto out; 27791e12ee3bSFrançois Tigeot 2780*a85cb24fSFrançois Tigeot if (test_and_set_bit(I915_RESET_BACKOFF, 27811e12ee3bSFrançois Tigeot &dev_priv->gpu_error.flags)) 2782*a85cb24fSFrançois Tigeot goto out; 2783e9243325SFrançois Tigeot 27841487f786SFrançois Tigeot i915_reset_and_wakeup(dev_priv); 2785*a85cb24fSFrançois Tigeot 2786*a85cb24fSFrançois Tigeot out: 2787*a85cb24fSFrançois Tigeot intel_runtime_pm_put(dev_priv); 2788e9243325SFrançois Tigeot } 2789e9243325SFrançois Tigeot 2790e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which 2791e9243325SFrançois Tigeot * we use as a pipe index 2792e9243325SFrançois Tigeot */ 27931e12ee3bSFrançois Tigeot static int i8xx_enable_vblank(struct drm_device *dev, unsigned int pipe) 2794e9243325SFrançois Tigeot { 2795303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 27965e269720SFrançois Tigeot unsigned long irqflags; 2797e9243325SFrançois Tigeot 27985e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 27991e12ee3bSFrançois Tigeot i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); 28001e12ee3bSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 28011e12ee3bSFrançois Tigeot 28021e12ee3bSFrançois Tigeot return 0; 28031e12ee3bSFrançois Tigeot } 28041e12ee3bSFrançois Tigeot 28051e12ee3bSFrançois Tigeot static int i965_enable_vblank(struct drm_device *dev, unsigned int pipe) 28061e12ee3bSFrançois Tigeot { 28071e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 28081e12ee3bSFrançois Tigeot unsigned long irqflags; 28091e12ee3bSFrançois Tigeot 28101e12ee3bSFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2811e9243325SFrançois Tigeot i915_enable_pipestat(dev_priv, pipe, 2812ba55f2f5SFrançois Tigeot PIPE_START_VBLANK_INTERRUPT_STATUS); 28135e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2814e9243325SFrançois Tigeot 2815e9243325SFrançois Tigeot return 0; 2816e9243325SFrançois Tigeot } 2817e9243325SFrançois Tigeot 2818352ff8bdSFrançois Tigeot static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe) 2819e9243325SFrançois Tigeot { 2820303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 28215e269720SFrançois Tigeot unsigned long irqflags; 28221e12ee3bSFrançois Tigeot uint32_t bit = INTEL_GEN(dev_priv) >= 7 ? 28231e12ee3bSFrançois Tigeot DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); 2824e9243325SFrançois Tigeot 28255e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2826aee94f86SFrançois Tigeot ilk_enable_display_irq(dev_priv, bit); 28275e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2828e9243325SFrançois Tigeot 2829e9243325SFrançois Tigeot return 0; 2830e9243325SFrançois Tigeot } 2831e9243325SFrançois Tigeot 2832352ff8bdSFrançois Tigeot static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe) 28339edbd4a0SFrançois Tigeot { 2834303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 28355e269720SFrançois Tigeot unsigned long irqflags; 28369edbd4a0SFrançois Tigeot 28375e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2838aee94f86SFrançois Tigeot bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); 28395e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2840aee94f86SFrançois Tigeot 28419edbd4a0SFrançois Tigeot return 0; 28429edbd4a0SFrançois Tigeot } 28439edbd4a0SFrançois Tigeot 2844e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which 2845e9243325SFrançois Tigeot * we use as a pipe index 2846e9243325SFrançois Tigeot */ 28471e12ee3bSFrançois Tigeot static void i8xx_disable_vblank(struct drm_device *dev, unsigned int pipe) 28481e12ee3bSFrançois Tigeot { 28491e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 28501e12ee3bSFrançois Tigeot unsigned long irqflags; 28511e12ee3bSFrançois Tigeot 28521e12ee3bSFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 28531e12ee3bSFrançois Tigeot i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); 28541e12ee3bSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 28551e12ee3bSFrançois Tigeot } 28561e12ee3bSFrançois Tigeot 28571e12ee3bSFrançois Tigeot static void i965_disable_vblank(struct drm_device *dev, unsigned int pipe) 2858e9243325SFrançois Tigeot { 2859303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 28605e269720SFrançois Tigeot unsigned long irqflags; 2861e9243325SFrançois Tigeot 28625e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2863e9243325SFrançois Tigeot i915_disable_pipestat(dev_priv, pipe, 2864ba55f2f5SFrançois Tigeot PIPE_START_VBLANK_INTERRUPT_STATUS); 28655e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2866e9243325SFrançois Tigeot } 2867e9243325SFrançois Tigeot 2868352ff8bdSFrançois Tigeot static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe) 2869e9243325SFrançois Tigeot { 2870303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 28715e269720SFrançois Tigeot unsigned long irqflags; 28721e12ee3bSFrançois Tigeot uint32_t bit = INTEL_GEN(dev_priv) >= 7 ? 28731e12ee3bSFrançois Tigeot DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); 2874e9243325SFrançois Tigeot 28755e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2876aee94f86SFrançois Tigeot ilk_disable_display_irq(dev_priv, bit); 28775e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2878e9243325SFrançois Tigeot } 2879e9243325SFrançois Tigeot 2880352ff8bdSFrançois Tigeot static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe) 28819edbd4a0SFrançois Tigeot { 2882303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 28835e269720SFrançois Tigeot unsigned long irqflags; 28849edbd4a0SFrançois Tigeot 28855e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2886aee94f86SFrançois Tigeot bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); 28875e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 28889edbd4a0SFrançois Tigeot } 28899edbd4a0SFrançois Tigeot 28904be47400SFrançois Tigeot static void ibx_irq_reset(struct drm_i915_private *dev_priv) 2891ba55f2f5SFrançois Tigeot { 28921e12ee3bSFrançois Tigeot if (HAS_PCH_NOP(dev_priv)) 28935d0b1887SFrançois Tigeot return; 28945d0b1887SFrançois Tigeot 2895ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(SDE); 2896ba55f2f5SFrançois Tigeot 28971e12ee3bSFrançois Tigeot if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) 2898ba55f2f5SFrançois Tigeot I915_WRITE(SERR_INT, 0xffffffff); 2899ba55f2f5SFrançois Tigeot } 2900ba55f2f5SFrançois Tigeot 29015d0b1887SFrançois Tigeot /* 2902ba55f2f5SFrançois Tigeot * SDEIER is also touched by the interrupt handler to work around missed PCH 2903ba55f2f5SFrançois Tigeot * interrupts. Hence we can't update it after the interrupt handler is enabled - 2904ba55f2f5SFrançois Tigeot * instead we unconditionally enable all PCH interrupt sources here, but then 2905ba55f2f5SFrançois Tigeot * only unmask them as needed with SDEIMR. 2906ba55f2f5SFrançois Tigeot * 2907ba55f2f5SFrançois Tigeot * This function needs to be called before interrupts are enabled. 29085d0b1887SFrançois Tigeot */ 2909ba55f2f5SFrançois Tigeot static void ibx_irq_pre_postinstall(struct drm_device *dev) 2910ba55f2f5SFrançois Tigeot { 2911303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 2912ba55f2f5SFrançois Tigeot 29131e12ee3bSFrançois Tigeot if (HAS_PCH_NOP(dev_priv)) 2914ba55f2f5SFrançois Tigeot return; 2915ba55f2f5SFrançois Tigeot 2916ba55f2f5SFrançois Tigeot WARN_ON(I915_READ(SDEIER) != 0); 29175d0b1887SFrançois Tigeot I915_WRITE(SDEIER, 0xffffffff); 29185d0b1887SFrançois Tigeot POSTING_READ(SDEIER); 2919e9243325SFrançois Tigeot } 2920e9243325SFrançois Tigeot 29214be47400SFrançois Tigeot static void gen5_gt_irq_reset(struct drm_i915_private *dev_priv) 29229edbd4a0SFrançois Tigeot { 2923ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(GT); 29244be47400SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 6) 2925ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(GEN6_PM); 29269edbd4a0SFrançois Tigeot } 29279edbd4a0SFrançois Tigeot 29288621f407SFrançois Tigeot static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) 29298621f407SFrançois Tigeot { 29308621f407SFrançois Tigeot enum i915_pipe pipe; 29318621f407SFrançois Tigeot 29328621f407SFrançois Tigeot if (IS_CHERRYVIEW(dev_priv)) 29338621f407SFrançois Tigeot I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV); 29348621f407SFrançois Tigeot else 29358621f407SFrançois Tigeot I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK); 29368621f407SFrançois Tigeot 29378621f407SFrançois Tigeot i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); 29388621f407SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 29398621f407SFrançois Tigeot 29408621f407SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 29418621f407SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 29428621f407SFrançois Tigeot PIPE_FIFO_UNDERRUN_STATUS | 29438621f407SFrançois Tigeot PIPESTAT_INT_STATUS_MASK); 29448621f407SFrançois Tigeot dev_priv->pipestat_irq_mask[pipe] = 0; 29458621f407SFrançois Tigeot } 29468621f407SFrançois Tigeot 29478621f407SFrançois Tigeot GEN5_IRQ_RESET(VLV_); 29488621f407SFrançois Tigeot dev_priv->irq_mask = ~0; 29498621f407SFrançois Tigeot } 29508621f407SFrançois Tigeot 29518621f407SFrançois Tigeot static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) 29528621f407SFrançois Tigeot { 29538621f407SFrançois Tigeot u32 pipestat_mask; 29548621f407SFrançois Tigeot u32 enable_mask; 29558621f407SFrançois Tigeot enum i915_pipe pipe; 29568621f407SFrançois Tigeot 29578621f407SFrançois Tigeot pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | 29588621f407SFrançois Tigeot PIPE_CRC_DONE_INTERRUPT_STATUS; 29598621f407SFrançois Tigeot 29608621f407SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); 29618621f407SFrançois Tigeot for_each_pipe(dev_priv, pipe) 29628621f407SFrançois Tigeot i915_enable_pipestat(dev_priv, pipe, pipestat_mask); 29638621f407SFrançois Tigeot 29648621f407SFrançois Tigeot enable_mask = I915_DISPLAY_PORT_INTERRUPT | 29658621f407SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 2966*a85cb24fSFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 2967*a85cb24fSFrançois Tigeot I915_LPE_PIPE_A_INTERRUPT | 2968*a85cb24fSFrançois Tigeot I915_LPE_PIPE_B_INTERRUPT; 2969*a85cb24fSFrançois Tigeot 29708621f407SFrançois Tigeot if (IS_CHERRYVIEW(dev_priv)) 2971*a85cb24fSFrançois Tigeot enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | 2972*a85cb24fSFrançois Tigeot I915_LPE_PIPE_C_INTERRUPT; 29738621f407SFrançois Tigeot 29748621f407SFrançois Tigeot WARN_ON(dev_priv->irq_mask != ~0); 29758621f407SFrançois Tigeot 29768621f407SFrançois Tigeot dev_priv->irq_mask = ~enable_mask; 29778621f407SFrançois Tigeot 29788621f407SFrançois Tigeot GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask); 29798621f407SFrançois Tigeot } 29808621f407SFrançois Tigeot 2981e9243325SFrançois Tigeot /* drm_dma.h hooks 2982e9243325SFrançois Tigeot */ 2983ba55f2f5SFrançois Tigeot static void ironlake_irq_reset(struct drm_device *dev) 2984e9243325SFrançois Tigeot { 2985303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 2986e9243325SFrançois Tigeot 2987ba55f2f5SFrançois Tigeot I915_WRITE(HWSTAM, 0xffffffff); 2988e9243325SFrançois Tigeot 2989ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(DE); 29901e12ee3bSFrançois Tigeot if (IS_GEN7(dev_priv)) 2991ba55f2f5SFrançois Tigeot I915_WRITE(GEN7_ERR_INT, 0xffffffff); 2992e9243325SFrançois Tigeot 29934be47400SFrançois Tigeot gen5_gt_irq_reset(dev_priv); 2994e9243325SFrançois Tigeot 29954be47400SFrançois Tigeot ibx_irq_reset(dev_priv); 2996e9243325SFrançois Tigeot } 2997e9243325SFrançois Tigeot 2998e9243325SFrançois Tigeot static void valleyview_irq_preinstall(struct drm_device *dev) 2999e9243325SFrançois Tigeot { 3000303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3001e9243325SFrançois Tigeot 30028621f407SFrançois Tigeot I915_WRITE(VLV_MASTER_IER, 0); 30038621f407SFrançois Tigeot POSTING_READ(VLV_MASTER_IER); 3004e9243325SFrançois Tigeot 30054be47400SFrançois Tigeot gen5_gt_irq_reset(dev_priv); 3006e9243325SFrançois Tigeot 30078621f407SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 30088621f407SFrançois Tigeot if (dev_priv->display_irqs_enabled) 30092c9916cdSFrançois Tigeot vlv_display_irq_reset(dev_priv); 30108621f407SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 3011e9243325SFrançois Tigeot } 3012e9243325SFrançois Tigeot 3013ba55f2f5SFrançois Tigeot static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv) 3014ba55f2f5SFrançois Tigeot { 3015ba55f2f5SFrançois Tigeot GEN8_IRQ_RESET_NDX(GT, 0); 3016ba55f2f5SFrançois Tigeot GEN8_IRQ_RESET_NDX(GT, 1); 3017ba55f2f5SFrançois Tigeot GEN8_IRQ_RESET_NDX(GT, 2); 3018ba55f2f5SFrançois Tigeot GEN8_IRQ_RESET_NDX(GT, 3); 3019ba55f2f5SFrançois Tigeot } 3020ba55f2f5SFrançois Tigeot 3021ba55f2f5SFrançois Tigeot static void gen8_irq_reset(struct drm_device *dev) 30229edbd4a0SFrançois Tigeot { 3023303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 30249edbd4a0SFrançois Tigeot int pipe; 30259edbd4a0SFrançois Tigeot 3026ba55f2f5SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, 0); 3027ba55f2f5SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 3028ba55f2f5SFrançois Tigeot 3029ba55f2f5SFrançois Tigeot gen8_gt_irq_reset(dev_priv); 3030ba55f2f5SFrançois Tigeot 30311b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 30322c9916cdSFrançois Tigeot if (intel_display_power_is_enabled(dev_priv, 303324edb884SFrançois Tigeot POWER_DOMAIN_PIPE(pipe))) 3034ba55f2f5SFrançois Tigeot GEN8_IRQ_RESET_NDX(DE_PIPE, pipe); 3035ba55f2f5SFrançois Tigeot 3036ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(GEN8_DE_PORT_); 3037ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(GEN8_DE_MISC_); 3038ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(GEN8_PCU_); 3039ba55f2f5SFrançois Tigeot 30401e12ee3bSFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv)) 30414be47400SFrançois Tigeot ibx_irq_reset(dev_priv); 3042ba55f2f5SFrançois Tigeot } 3043ba55f2f5SFrançois Tigeot 3044477eb7f9SFrançois Tigeot void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, 3045477eb7f9SFrançois Tigeot unsigned int pipe_mask) 304624edb884SFrançois Tigeot { 3047acf467cbSFrançois Tigeot uint32_t extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN; 3048c0e85e96SFrançois Tigeot enum i915_pipe pipe; 304924edb884SFrançois Tigeot 30505e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 3051c0e85e96SFrançois Tigeot for_each_pipe_masked(dev_priv, pipe, pipe_mask) 3052c0e85e96SFrançois Tigeot GEN8_IRQ_INIT_NDX(DE_PIPE, pipe, 3053c0e85e96SFrançois Tigeot dev_priv->de_irq_mask[pipe], 3054c0e85e96SFrançois Tigeot ~dev_priv->de_irq_mask[pipe] | extra_ier); 30555e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 305624edb884SFrançois Tigeot } 305724edb884SFrançois Tigeot 3058c0e85e96SFrançois Tigeot void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, 3059c0e85e96SFrançois Tigeot unsigned int pipe_mask) 3060c0e85e96SFrançois Tigeot { 3061c0e85e96SFrançois Tigeot enum i915_pipe pipe; 3062c0e85e96SFrançois Tigeot 3063c0e85e96SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 3064c0e85e96SFrançois Tigeot for_each_pipe_masked(dev_priv, pipe, pipe_mask) 3065c0e85e96SFrançois Tigeot GEN8_IRQ_RESET_NDX(DE_PIPE, pipe); 3066c0e85e96SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 3067c0e85e96SFrançois Tigeot 3068c0e85e96SFrançois Tigeot /* make sure we're done processing display irqs */ 3069303bf270SFrançois Tigeot synchronize_irq(dev_priv->drm.irq); 3070c0e85e96SFrançois Tigeot } 3071c0e85e96SFrançois Tigeot 3072ba55f2f5SFrançois Tigeot static void cherryview_irq_preinstall(struct drm_device *dev) 3073ba55f2f5SFrançois Tigeot { 3074303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 30759edbd4a0SFrançois Tigeot 30769edbd4a0SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, 0); 30779edbd4a0SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 30789edbd4a0SFrançois Tigeot 3079ba55f2f5SFrançois Tigeot gen8_gt_irq_reset(dev_priv); 30809edbd4a0SFrançois Tigeot 3081ba55f2f5SFrançois Tigeot GEN5_IRQ_RESET(GEN8_PCU_); 30829edbd4a0SFrançois Tigeot 30838621f407SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 30848621f407SFrançois Tigeot if (dev_priv->display_irqs_enabled) 30852c9916cdSFrançois Tigeot vlv_display_irq_reset(dev_priv); 30868621f407SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 30879edbd4a0SFrançois Tigeot } 30889edbd4a0SFrançois Tigeot 30891487f786SFrançois Tigeot static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv, 3090352ff8bdSFrançois Tigeot const u32 hpd[HPD_NUM_PINS]) 3091352ff8bdSFrançois Tigeot { 3092352ff8bdSFrançois Tigeot struct intel_encoder *encoder; 3093352ff8bdSFrançois Tigeot u32 enabled_irqs = 0; 3094352ff8bdSFrançois Tigeot 3095303bf270SFrançois Tigeot for_each_intel_encoder(&dev_priv->drm, encoder) 3096352ff8bdSFrançois Tigeot if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED) 3097352ff8bdSFrançois Tigeot enabled_irqs |= hpd[encoder->hpd_pin]; 3098352ff8bdSFrançois Tigeot 3099352ff8bdSFrançois Tigeot return enabled_irqs; 3100352ff8bdSFrançois Tigeot } 3101352ff8bdSFrançois Tigeot 3102*a85cb24fSFrançois Tigeot static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv) 3103*a85cb24fSFrançois Tigeot { 3104*a85cb24fSFrançois Tigeot u32 hotplug; 3105*a85cb24fSFrançois Tigeot 3106*a85cb24fSFrançois Tigeot /* 3107*a85cb24fSFrançois Tigeot * Enable digital hotplug on the PCH, and configure the DP short pulse 3108*a85cb24fSFrançois Tigeot * duration to 2ms (which is the minimum in the Display Port spec). 3109*a85cb24fSFrançois Tigeot * The pulse duration bits are reserved on LPT+. 3110*a85cb24fSFrançois Tigeot */ 3111*a85cb24fSFrançois Tigeot hotplug = I915_READ(PCH_PORT_HOTPLUG); 3112*a85cb24fSFrançois Tigeot hotplug &= ~(PORTB_PULSE_DURATION_MASK | 3113*a85cb24fSFrançois Tigeot PORTC_PULSE_DURATION_MASK | 3114*a85cb24fSFrançois Tigeot PORTD_PULSE_DURATION_MASK); 3115*a85cb24fSFrançois Tigeot hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms; 3116*a85cb24fSFrançois Tigeot hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms; 3117*a85cb24fSFrançois Tigeot hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; 3118*a85cb24fSFrançois Tigeot /* 3119*a85cb24fSFrançois Tigeot * When CPU and PCH are on the same package, port A 3120*a85cb24fSFrançois Tigeot * HPD must be enabled in both north and south. 3121*a85cb24fSFrançois Tigeot */ 3122*a85cb24fSFrançois Tigeot if (HAS_PCH_LPT_LP(dev_priv)) 3123*a85cb24fSFrançois Tigeot hotplug |= PORTA_HOTPLUG_ENABLE; 3124*a85cb24fSFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG, hotplug); 3125*a85cb24fSFrançois Tigeot } 3126*a85cb24fSFrançois Tigeot 31271487f786SFrançois Tigeot static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) 31288e26cdf6SFrançois Tigeot { 3129*a85cb24fSFrançois Tigeot u32 hotplug_irqs, enabled_irqs; 31308e26cdf6SFrançois Tigeot 31311487f786SFrançois Tigeot if (HAS_PCH_IBX(dev_priv)) { 31329edbd4a0SFrançois Tigeot hotplug_irqs = SDE_HOTPLUG_MASK; 31331487f786SFrançois Tigeot enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ibx); 31348e26cdf6SFrançois Tigeot } else { 31359edbd4a0SFrançois Tigeot hotplug_irqs = SDE_HOTPLUG_MASK_CPT; 31361487f786SFrançois Tigeot enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_cpt); 31378e26cdf6SFrançois Tigeot } 31388e26cdf6SFrançois Tigeot 31399edbd4a0SFrançois Tigeot ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); 31408e26cdf6SFrançois Tigeot 3141*a85cb24fSFrançois Tigeot ibx_hpd_detection_setup(dev_priv); 3142352ff8bdSFrançois Tigeot } 3143352ff8bdSFrançois Tigeot 31444be47400SFrançois Tigeot static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) 31454be47400SFrançois Tigeot { 31464be47400SFrançois Tigeot u32 hotplug; 31474be47400SFrançois Tigeot 31484be47400SFrançois Tigeot /* Enable digital hotplug on the PCH */ 31494be47400SFrançois Tigeot hotplug = I915_READ(PCH_PORT_HOTPLUG); 31504be47400SFrançois Tigeot hotplug |= PORTA_HOTPLUG_ENABLE | 31514be47400SFrançois Tigeot PORTB_HOTPLUG_ENABLE | 31524be47400SFrançois Tigeot PORTC_HOTPLUG_ENABLE | 31534be47400SFrançois Tigeot PORTD_HOTPLUG_ENABLE; 31544be47400SFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG, hotplug); 31554be47400SFrançois Tigeot 31564be47400SFrançois Tigeot hotplug = I915_READ(PCH_PORT_HOTPLUG2); 31574be47400SFrançois Tigeot hotplug |= PORTE_HOTPLUG_ENABLE; 31584be47400SFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG2, hotplug); 31594be47400SFrançois Tigeot } 31604be47400SFrançois Tigeot 31611487f786SFrançois Tigeot static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv) 3162352ff8bdSFrançois Tigeot { 31634be47400SFrançois Tigeot u32 hotplug_irqs, enabled_irqs; 3164352ff8bdSFrançois Tigeot 3165352ff8bdSFrançois Tigeot hotplug_irqs = SDE_HOTPLUG_MASK_SPT; 31661487f786SFrançois Tigeot enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_spt); 3167352ff8bdSFrançois Tigeot 3168352ff8bdSFrançois Tigeot ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); 3169352ff8bdSFrançois Tigeot 31704be47400SFrançois Tigeot spt_hpd_detection_setup(dev_priv); 3171a05eeebfSFrançois Tigeot } 3172352ff8bdSFrançois Tigeot 3173*a85cb24fSFrançois Tigeot static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv) 3174*a85cb24fSFrançois Tigeot { 3175*a85cb24fSFrançois Tigeot u32 hotplug; 3176*a85cb24fSFrançois Tigeot 3177*a85cb24fSFrançois Tigeot /* 3178*a85cb24fSFrançois Tigeot * Enable digital hotplug on the CPU, and configure the DP short pulse 3179*a85cb24fSFrançois Tigeot * duration to 2ms (which is the minimum in the Display Port spec) 3180*a85cb24fSFrançois Tigeot * The pulse duration bits are reserved on HSW+. 3181*a85cb24fSFrançois Tigeot */ 3182*a85cb24fSFrançois Tigeot hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL); 3183*a85cb24fSFrançois Tigeot hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK; 3184*a85cb24fSFrançois Tigeot hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE | 3185*a85cb24fSFrançois Tigeot DIGITAL_PORTA_PULSE_DURATION_2ms; 3186*a85cb24fSFrançois Tigeot I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug); 3187*a85cb24fSFrançois Tigeot } 3188*a85cb24fSFrançois Tigeot 31891487f786SFrançois Tigeot static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv) 3190352ff8bdSFrançois Tigeot { 3191*a85cb24fSFrançois Tigeot u32 hotplug_irqs, enabled_irqs; 3192352ff8bdSFrançois Tigeot 31931487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 8) { 3194352ff8bdSFrançois Tigeot hotplug_irqs = GEN8_PORT_DP_A_HOTPLUG; 31951487f786SFrançois Tigeot enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bdw); 3196352ff8bdSFrançois Tigeot 3197352ff8bdSFrançois Tigeot bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); 31981487f786SFrançois Tigeot } else if (INTEL_GEN(dev_priv) >= 7) { 3199352ff8bdSFrançois Tigeot hotplug_irqs = DE_DP_A_HOTPLUG_IVB; 32001487f786SFrançois Tigeot enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ivb); 3201352ff8bdSFrançois Tigeot 3202352ff8bdSFrançois Tigeot ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs); 3203352ff8bdSFrançois Tigeot } else { 3204352ff8bdSFrançois Tigeot hotplug_irqs = DE_DP_A_HOTPLUG; 32051487f786SFrançois Tigeot enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ilk); 3206352ff8bdSFrançois Tigeot 3207352ff8bdSFrançois Tigeot ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs); 3208352ff8bdSFrançois Tigeot } 3209352ff8bdSFrançois Tigeot 3210*a85cb24fSFrançois Tigeot ilk_hpd_detection_setup(dev_priv); 3211352ff8bdSFrançois Tigeot 32121487f786SFrançois Tigeot ibx_hpd_irq_setup(dev_priv); 3213e9243325SFrançois Tigeot } 3214e9243325SFrançois Tigeot 32154be47400SFrançois Tigeot static void __bxt_hpd_detection_setup(struct drm_i915_private *dev_priv, 32164be47400SFrançois Tigeot u32 enabled_irqs) 321719c468b4SFrançois Tigeot { 32184be47400SFrançois Tigeot u32 hotplug; 321919c468b4SFrançois Tigeot 3220352ff8bdSFrançois Tigeot hotplug = I915_READ(PCH_PORT_HOTPLUG); 32214be47400SFrançois Tigeot hotplug |= PORTA_HOTPLUG_ENABLE | 32224be47400SFrançois Tigeot PORTB_HOTPLUG_ENABLE | 32234be47400SFrançois Tigeot PORTC_HOTPLUG_ENABLE; 32248621f407SFrançois Tigeot 32258621f407SFrançois Tigeot DRM_DEBUG_KMS("Invert bit setting: hp_ctl:%x hp_port:%x\n", 32268621f407SFrançois Tigeot hotplug, enabled_irqs); 32278621f407SFrançois Tigeot hotplug &= ~BXT_DDI_HPD_INVERT_MASK; 32288621f407SFrançois Tigeot 32298621f407SFrançois Tigeot /* 32308621f407SFrançois Tigeot * For BXT invert bit has to be set based on AOB design 32318621f407SFrançois Tigeot * for HPD detection logic, update it based on VBT fields. 32328621f407SFrançois Tigeot */ 32338621f407SFrançois Tigeot if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) && 32348621f407SFrançois Tigeot intel_bios_is_port_hpd_inverted(dev_priv, PORT_A)) 32358621f407SFrançois Tigeot hotplug |= BXT_DDIA_HPD_INVERT; 32368621f407SFrançois Tigeot if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) && 32378621f407SFrançois Tigeot intel_bios_is_port_hpd_inverted(dev_priv, PORT_B)) 32388621f407SFrançois Tigeot hotplug |= BXT_DDIB_HPD_INVERT; 32398621f407SFrançois Tigeot if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) && 32408621f407SFrançois Tigeot intel_bios_is_port_hpd_inverted(dev_priv, PORT_C)) 32418621f407SFrançois Tigeot hotplug |= BXT_DDIC_HPD_INVERT; 32428621f407SFrançois Tigeot 3243352ff8bdSFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG, hotplug); 324419c468b4SFrançois Tigeot } 324519c468b4SFrançois Tigeot 32464be47400SFrançois Tigeot static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv) 32474be47400SFrançois Tigeot { 32484be47400SFrançois Tigeot __bxt_hpd_detection_setup(dev_priv, BXT_DE_PORT_HOTPLUG_MASK); 32494be47400SFrançois Tigeot } 32504be47400SFrançois Tigeot 32514be47400SFrançois Tigeot static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) 32524be47400SFrançois Tigeot { 32534be47400SFrançois Tigeot u32 hotplug_irqs, enabled_irqs; 32544be47400SFrançois Tigeot 32554be47400SFrançois Tigeot enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bxt); 32564be47400SFrançois Tigeot hotplug_irqs = BXT_DE_PORT_HOTPLUG_MASK; 32574be47400SFrançois Tigeot 32584be47400SFrançois Tigeot bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); 32594be47400SFrançois Tigeot 32604be47400SFrançois Tigeot __bxt_hpd_detection_setup(dev_priv, enabled_irqs); 32614be47400SFrançois Tigeot } 32624be47400SFrançois Tigeot 3263a2fdbec6SFrançois Tigeot static void ibx_irq_postinstall(struct drm_device *dev) 3264a2fdbec6SFrançois Tigeot { 3265303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3266a2fdbec6SFrançois Tigeot u32 mask; 3267a2fdbec6SFrançois Tigeot 32681e12ee3bSFrançois Tigeot if (HAS_PCH_NOP(dev_priv)) 32698e26cdf6SFrançois Tigeot return; 3270a2fdbec6SFrançois Tigeot 32711e12ee3bSFrançois Tigeot if (HAS_PCH_IBX(dev_priv)) 32729edbd4a0SFrançois Tigeot mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; 3273ba55f2f5SFrançois Tigeot else 32749edbd4a0SFrançois Tigeot mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; 32755d0b1887SFrançois Tigeot 3276352ff8bdSFrançois Tigeot gen5_assert_iir_is_zero(dev_priv, SDEIIR); 3277a2fdbec6SFrançois Tigeot I915_WRITE(SDEIMR, ~mask); 32784be47400SFrançois Tigeot 32794be47400SFrançois Tigeot if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) || 32804be47400SFrançois Tigeot HAS_PCH_LPT(dev_priv)) 3281*a85cb24fSFrançois Tigeot ibx_hpd_detection_setup(dev_priv); 32824be47400SFrançois Tigeot else 32834be47400SFrançois Tigeot spt_hpd_detection_setup(dev_priv); 3284a2fdbec6SFrançois Tigeot } 3285a2fdbec6SFrançois Tigeot 32869edbd4a0SFrançois Tigeot static void gen5_gt_irq_postinstall(struct drm_device *dev) 32879edbd4a0SFrançois Tigeot { 3288303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 32899edbd4a0SFrançois Tigeot u32 pm_irqs, gt_irqs; 32909edbd4a0SFrançois Tigeot 32919edbd4a0SFrançois Tigeot pm_irqs = gt_irqs = 0; 32929edbd4a0SFrançois Tigeot 32939edbd4a0SFrançois Tigeot dev_priv->gt_irq_mask = ~0; 32941e12ee3bSFrançois Tigeot if (HAS_L3_DPF(dev_priv)) { 32959edbd4a0SFrançois Tigeot /* L3 parity interrupt is always unmasked. */ 32961e12ee3bSFrançois Tigeot dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev_priv); 32971e12ee3bSFrançois Tigeot gt_irqs |= GT_PARITY_ERROR(dev_priv); 32989edbd4a0SFrançois Tigeot } 32999edbd4a0SFrançois Tigeot 33009edbd4a0SFrançois Tigeot gt_irqs |= GT_RENDER_USER_INTERRUPT; 33011e12ee3bSFrançois Tigeot if (IS_GEN5(dev_priv)) { 3302303bf270SFrançois Tigeot gt_irqs |= ILK_BSD_USER_INTERRUPT; 33039edbd4a0SFrançois Tigeot } else { 33049edbd4a0SFrançois Tigeot gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; 33059edbd4a0SFrançois Tigeot } 33069edbd4a0SFrançois Tigeot 3307ba55f2f5SFrançois Tigeot GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs); 33089edbd4a0SFrançois Tigeot 33094be47400SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 6) { 33102c9916cdSFrançois Tigeot /* 33112c9916cdSFrançois Tigeot * RPS interrupts will get enabled/disabled on demand when RPS 33122c9916cdSFrançois Tigeot * itself is enabled/disabled. 33132c9916cdSFrançois Tigeot */ 33144be47400SFrançois Tigeot if (HAS_VEBOX(dev_priv)) { 33159edbd4a0SFrançois Tigeot pm_irqs |= PM_VEBOX_USER_INTERRUPT; 33164be47400SFrançois Tigeot dev_priv->pm_ier |= PM_VEBOX_USER_INTERRUPT; 33174be47400SFrançois Tigeot } 33189edbd4a0SFrançois Tigeot 33194be47400SFrançois Tigeot dev_priv->pm_imr = 0xffffffff; 33204be47400SFrançois Tigeot GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs); 33219edbd4a0SFrançois Tigeot } 33229edbd4a0SFrançois Tigeot } 33239edbd4a0SFrançois Tigeot 3324e9243325SFrançois Tigeot static int ironlake_irq_postinstall(struct drm_device *dev) 3325e9243325SFrançois Tigeot { 3326303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 33279edbd4a0SFrançois Tigeot u32 display_mask, extra_mask; 33289edbd4a0SFrançois Tigeot 33294be47400SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 7) { 33309edbd4a0SFrançois Tigeot display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | 33319edbd4a0SFrançois Tigeot DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB | 33329edbd4a0SFrançois Tigeot DE_PLANEB_FLIP_DONE_IVB | 33339edbd4a0SFrançois Tigeot DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB); 33349edbd4a0SFrançois Tigeot extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB | 3335352ff8bdSFrançois Tigeot DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB | 3336352ff8bdSFrançois Tigeot DE_DP_A_HOTPLUG_IVB); 33379edbd4a0SFrançois Tigeot } else { 33389edbd4a0SFrançois Tigeot display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | 3339a2fdbec6SFrançois Tigeot DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | 33409edbd4a0SFrançois Tigeot DE_AUX_CHANNEL_A | 33419edbd4a0SFrançois Tigeot DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE | 33429edbd4a0SFrançois Tigeot DE_POISON); 3343352ff8bdSFrançois Tigeot extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT | 3344352ff8bdSFrançois Tigeot DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN | 3345352ff8bdSFrançois Tigeot DE_DP_A_HOTPLUG); 33469edbd4a0SFrançois Tigeot } 3347e9243325SFrançois Tigeot 3348e9243325SFrançois Tigeot dev_priv->irq_mask = ~display_mask; 3349e9243325SFrançois Tigeot 3350ba55f2f5SFrançois Tigeot I915_WRITE(HWSTAM, 0xeffe); 3351ba55f2f5SFrançois Tigeot 3352ba55f2f5SFrançois Tigeot ibx_irq_pre_postinstall(dev); 3353ba55f2f5SFrançois Tigeot 3354ba55f2f5SFrançois Tigeot GEN5_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask); 3355e9243325SFrançois Tigeot 33569edbd4a0SFrançois Tigeot gen5_gt_irq_postinstall(dev); 3357e9243325SFrançois Tigeot 3358*a85cb24fSFrançois Tigeot ilk_hpd_detection_setup(dev_priv); 3359*a85cb24fSFrançois Tigeot 3360a2fdbec6SFrançois Tigeot ibx_irq_postinstall(dev); 3361e9243325SFrançois Tigeot 33621e12ee3bSFrançois Tigeot if (IS_IRONLAKE_M(dev_priv)) { 33635d0b1887SFrançois Tigeot /* Enable PCU event interrupts 33645d0b1887SFrançois Tigeot * 33655d0b1887SFrançois Tigeot * spinlocking not required here for correctness since interrupt 33665d0b1887SFrançois Tigeot * setup is guaranteed to run in single-threaded context. But we 33675d0b1887SFrançois Tigeot * need it to make the assert_spin_locked happy. */ 33685e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 3369aee94f86SFrançois Tigeot ilk_enable_display_irq(dev_priv, DE_PCU_EVENT); 33705e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 3371e9243325SFrançois Tigeot } 3372e9243325SFrançois Tigeot 3373e9243325SFrançois Tigeot return 0; 3374e9243325SFrançois Tigeot } 3375e9243325SFrançois Tigeot 3376ba55f2f5SFrançois Tigeot void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) 3377ba55f2f5SFrançois Tigeot { 3378*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 3379ba55f2f5SFrançois Tigeot 3380ba55f2f5SFrançois Tigeot if (dev_priv->display_irqs_enabled) 3381ba55f2f5SFrançois Tigeot return; 3382ba55f2f5SFrançois Tigeot 3383ba55f2f5SFrançois Tigeot dev_priv->display_irqs_enabled = true; 3384ba55f2f5SFrançois Tigeot 33858621f407SFrançois Tigeot if (intel_irqs_enabled(dev_priv)) { 33868621f407SFrançois Tigeot vlv_display_irq_reset(dev_priv); 33878621f407SFrançois Tigeot vlv_display_irq_postinstall(dev_priv); 33888621f407SFrançois Tigeot } 3389ba55f2f5SFrançois Tigeot } 3390ba55f2f5SFrançois Tigeot 3391ba55f2f5SFrançois Tigeot void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) 3392ba55f2f5SFrançois Tigeot { 3393*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 3394ba55f2f5SFrançois Tigeot 3395ba55f2f5SFrançois Tigeot if (!dev_priv->display_irqs_enabled) 3396ba55f2f5SFrançois Tigeot return; 3397ba55f2f5SFrançois Tigeot 3398ba55f2f5SFrançois Tigeot dev_priv->display_irqs_enabled = false; 3399ba55f2f5SFrançois Tigeot 34002c9916cdSFrançois Tigeot if (intel_irqs_enabled(dev_priv)) 34018621f407SFrançois Tigeot vlv_display_irq_reset(dev_priv); 3402ba55f2f5SFrançois Tigeot } 3403ba55f2f5SFrançois Tigeot 3404e9243325SFrançois Tigeot 34052c9916cdSFrançois Tigeot static int valleyview_irq_postinstall(struct drm_device *dev) 34062c9916cdSFrançois Tigeot { 3407303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 34082c9916cdSFrançois Tigeot 34099edbd4a0SFrançois Tigeot gen5_gt_irq_postinstall(dev); 3410e9243325SFrançois Tigeot 34118621f407SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 34128621f407SFrançois Tigeot if (dev_priv->display_irqs_enabled) 34138621f407SFrançois Tigeot vlv_display_irq_postinstall(dev_priv); 34148621f407SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 3415e9243325SFrançois Tigeot 3416e9243325SFrançois Tigeot I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); 34178621f407SFrançois Tigeot POSTING_READ(VLV_MASTER_IER); 3418a2fdbec6SFrançois Tigeot 3419a2fdbec6SFrançois Tigeot return 0; 3420a2fdbec6SFrançois Tigeot } 3421a2fdbec6SFrançois Tigeot 34229edbd4a0SFrançois Tigeot static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) 34239edbd4a0SFrançois Tigeot { 34249edbd4a0SFrançois Tigeot /* These are interrupts we'll toggle with the ring mask register */ 34259edbd4a0SFrançois Tigeot uint32_t gt_interrupts[] = { 34269edbd4a0SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | 34271b13d190SFrançois Tigeot GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT | 34281b13d190SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT | 34291b13d190SFrançois Tigeot GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT, 34309edbd4a0SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | 34311b13d190SFrançois Tigeot GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | 34321b13d190SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT | 34331b13d190SFrançois Tigeot GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT, 34349edbd4a0SFrançois Tigeot 0, 34351b13d190SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT | 34361b13d190SFrançois Tigeot GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT 34379edbd4a0SFrançois Tigeot }; 34389edbd4a0SFrançois Tigeot 34398621f407SFrançois Tigeot if (HAS_L3_DPF(dev_priv)) 34408621f407SFrançois Tigeot gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; 34418621f407SFrançois Tigeot 34424be47400SFrançois Tigeot dev_priv->pm_ier = 0x0; 34434be47400SFrançois Tigeot dev_priv->pm_imr = ~dev_priv->pm_ier; 34441b13d190SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]); 34451b13d190SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]); 34462c9916cdSFrançois Tigeot /* 34472c9916cdSFrançois Tigeot * RPS interrupts will get enabled/disabled on demand when RPS itself 34484be47400SFrançois Tigeot * is enabled/disabled. Same wil be the case for GuC interrupts. 34492c9916cdSFrançois Tigeot */ 34504be47400SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier); 34511b13d190SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]); 34529edbd4a0SFrançois Tigeot } 34539edbd4a0SFrançois Tigeot 34549edbd4a0SFrançois Tigeot static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) 34559edbd4a0SFrançois Tigeot { 34562c9916cdSFrançois Tigeot uint32_t de_pipe_masked = GEN8_PIPE_CDCLK_CRC_DONE; 34572c9916cdSFrançois Tigeot uint32_t de_pipe_enables; 3458352ff8bdSFrançois Tigeot u32 de_port_masked = GEN8_AUX_CHANNEL_A; 3459352ff8bdSFrançois Tigeot u32 de_port_enables; 34601487f786SFrançois Tigeot u32 de_misc_masked = GEN8_DE_MISC_GSE; 3461352ff8bdSFrançois Tigeot enum i915_pipe pipe; 34622c9916cdSFrançois Tigeot 3463352ff8bdSFrançois Tigeot if (INTEL_INFO(dev_priv)->gen >= 9) { 34642c9916cdSFrançois Tigeot de_pipe_masked |= GEN9_PIPE_PLANE1_FLIP_DONE | 34652c9916cdSFrançois Tigeot GEN9_DE_PIPE_IRQ_FAULT_ERRORS; 3466352ff8bdSFrançois Tigeot de_port_masked |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C | 34672c9916cdSFrançois Tigeot GEN9_AUX_CHANNEL_D; 3468*a85cb24fSFrançois Tigeot if (IS_GEN9_LP(dev_priv)) 3469352ff8bdSFrançois Tigeot de_port_masked |= BXT_DE_PORT_GMBUS; 3470352ff8bdSFrançois Tigeot } else { 34712c9916cdSFrançois Tigeot de_pipe_masked |= GEN8_PIPE_PRIMARY_FLIP_DONE | 34722c9916cdSFrançois Tigeot GEN8_DE_PIPE_IRQ_FAULT_ERRORS; 3473352ff8bdSFrançois Tigeot } 34742c9916cdSFrançois Tigeot 34752c9916cdSFrançois Tigeot de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | 34762c9916cdSFrançois Tigeot GEN8_PIPE_FIFO_UNDERRUN; 34772c9916cdSFrançois Tigeot 3478352ff8bdSFrançois Tigeot de_port_enables = de_port_masked; 3479*a85cb24fSFrançois Tigeot if (IS_GEN9_LP(dev_priv)) 3480352ff8bdSFrançois Tigeot de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; 3481352ff8bdSFrançois Tigeot else if (IS_BROADWELL(dev_priv)) 3482352ff8bdSFrançois Tigeot de_port_enables |= GEN8_PORT_DP_A_HOTPLUG; 3483352ff8bdSFrançois Tigeot 34849edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked; 34859edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked; 34869edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked; 34879edbd4a0SFrançois Tigeot 34881b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 34892c9916cdSFrançois Tigeot if (intel_display_power_is_enabled(dev_priv, 349024edb884SFrançois Tigeot POWER_DOMAIN_PIPE(pipe))) 349124edb884SFrançois Tigeot GEN8_IRQ_INIT_NDX(DE_PIPE, pipe, 349224edb884SFrançois Tigeot dev_priv->de_irq_mask[pipe], 3493ba55f2f5SFrançois Tigeot de_pipe_enables); 34949edbd4a0SFrançois Tigeot 3495352ff8bdSFrançois Tigeot GEN5_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables); 34961487f786SFrançois Tigeot GEN5_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); 34974be47400SFrançois Tigeot 3498*a85cb24fSFrançois Tigeot if (IS_GEN9_LP(dev_priv)) 34994be47400SFrançois Tigeot bxt_hpd_detection_setup(dev_priv); 3500*a85cb24fSFrançois Tigeot else if (IS_BROADWELL(dev_priv)) 3501*a85cb24fSFrançois Tigeot ilk_hpd_detection_setup(dev_priv); 35029edbd4a0SFrançois Tigeot } 35039edbd4a0SFrançois Tigeot 35049edbd4a0SFrançois Tigeot static int gen8_irq_postinstall(struct drm_device *dev) 35059edbd4a0SFrançois Tigeot { 3506303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 35079edbd4a0SFrançois Tigeot 35081e12ee3bSFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv)) 3509ba55f2f5SFrançois Tigeot ibx_irq_pre_postinstall(dev); 3510ba55f2f5SFrançois Tigeot 35119edbd4a0SFrançois Tigeot gen8_gt_irq_postinstall(dev_priv); 35129edbd4a0SFrançois Tigeot gen8_de_irq_postinstall(dev_priv); 35139edbd4a0SFrançois Tigeot 35141e12ee3bSFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv)) 35159edbd4a0SFrançois Tigeot ibx_irq_postinstall(dev); 35169edbd4a0SFrançois Tigeot 35178621f407SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); 35189edbd4a0SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 35199edbd4a0SFrançois Tigeot 35209edbd4a0SFrançois Tigeot return 0; 35219edbd4a0SFrançois Tigeot } 35229edbd4a0SFrançois Tigeot 3523ba55f2f5SFrançois Tigeot static int cherryview_irq_postinstall(struct drm_device *dev) 3524ba55f2f5SFrançois Tigeot { 3525303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3526ba55f2f5SFrançois Tigeot 3527ba55f2f5SFrançois Tigeot gen8_gt_irq_postinstall(dev_priv); 3528ba55f2f5SFrançois Tigeot 35298621f407SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 35308621f407SFrançois Tigeot if (dev_priv->display_irqs_enabled) 35318621f407SFrançois Tigeot vlv_display_irq_postinstall(dev_priv); 35328621f407SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 35338621f407SFrançois Tigeot 35348621f407SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); 3535ba55f2f5SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 3536ba55f2f5SFrançois Tigeot 3537ba55f2f5SFrançois Tigeot return 0; 3538ba55f2f5SFrançois Tigeot } 3539ba55f2f5SFrançois Tigeot 35409edbd4a0SFrançois Tigeot static void gen8_irq_uninstall(struct drm_device *dev) 35419edbd4a0SFrançois Tigeot { 3542303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3543ba55f2f5SFrançois Tigeot 3544ba55f2f5SFrançois Tigeot if (!dev_priv) 3545ba55f2f5SFrançois Tigeot return; 3546ba55f2f5SFrançois Tigeot 3547ba55f2f5SFrançois Tigeot gen8_irq_reset(dev); 3548ba55f2f5SFrançois Tigeot } 3549ba55f2f5SFrançois Tigeot 3550ba55f2f5SFrançois Tigeot static void valleyview_irq_uninstall(struct drm_device *dev) 3551ba55f2f5SFrançois Tigeot { 3552303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 35539edbd4a0SFrançois Tigeot 35549edbd4a0SFrançois Tigeot if (!dev_priv) 35559edbd4a0SFrançois Tigeot return; 35569edbd4a0SFrançois Tigeot 3557ba55f2f5SFrançois Tigeot I915_WRITE(VLV_MASTER_IER, 0); 35588621f407SFrançois Tigeot POSTING_READ(VLV_MASTER_IER); 3559ba55f2f5SFrançois Tigeot 35604be47400SFrançois Tigeot gen5_gt_irq_reset(dev_priv); 3561ba55f2f5SFrançois Tigeot 3562ba55f2f5SFrançois Tigeot I915_WRITE(HWSTAM, 0xffffffff); 3563ba55f2f5SFrançois Tigeot 35648621f407SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 35658621f407SFrançois Tigeot if (dev_priv->display_irqs_enabled) 35668621f407SFrançois Tigeot vlv_display_irq_reset(dev_priv); 35678621f407SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 3568ba55f2f5SFrançois Tigeot } 3569ba55f2f5SFrançois Tigeot 3570ba55f2f5SFrançois Tigeot static void cherryview_irq_uninstall(struct drm_device *dev) 3571ba55f2f5SFrançois Tigeot { 3572303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3573ba55f2f5SFrançois Tigeot 3574ba55f2f5SFrançois Tigeot if (!dev_priv) 3575ba55f2f5SFrançois Tigeot return; 35769edbd4a0SFrançois Tigeot 35779edbd4a0SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, 0); 3578ba55f2f5SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 35799edbd4a0SFrançois Tigeot 35802c9916cdSFrançois Tigeot gen8_gt_irq_reset(dev_priv); 35819edbd4a0SFrançois Tigeot 35822c9916cdSFrançois Tigeot GEN5_IRQ_RESET(GEN8_PCU_); 35839edbd4a0SFrançois Tigeot 35848621f407SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 35858621f407SFrançois Tigeot if (dev_priv->display_irqs_enabled) 35868621f407SFrançois Tigeot vlv_display_irq_reset(dev_priv); 35878621f407SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 3588e9243325SFrançois Tigeot } 3589e9243325SFrançois Tigeot 3590e9243325SFrançois Tigeot static void ironlake_irq_uninstall(struct drm_device *dev) 3591e9243325SFrançois Tigeot { 3592303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3593e9243325SFrançois Tigeot 3594e9243325SFrançois Tigeot if (!dev_priv) 3595e9243325SFrançois Tigeot return; 3596e9243325SFrançois Tigeot 3597ba55f2f5SFrançois Tigeot ironlake_irq_reset(dev); 3598e9243325SFrançois Tigeot } 3599e9243325SFrançois Tigeot 3600e9243325SFrançois Tigeot static void i8xx_irq_preinstall(struct drm_device * dev) 3601e9243325SFrançois Tigeot { 3602303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3603e9243325SFrançois Tigeot int pipe; 3604e9243325SFrançois Tigeot 36051b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 3606e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3607e9243325SFrançois Tigeot I915_WRITE16(IMR, 0xffff); 3608e9243325SFrançois Tigeot I915_WRITE16(IER, 0x0); 3609e9243325SFrançois Tigeot POSTING_READ16(IER); 3610e9243325SFrançois Tigeot } 3611e9243325SFrançois Tigeot 3612e9243325SFrançois Tigeot static int i8xx_irq_postinstall(struct drm_device *dev) 3613e9243325SFrançois Tigeot { 3614303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3615e9243325SFrançois Tigeot 3616e9243325SFrançois Tigeot I915_WRITE16(EMR, 3617e9243325SFrançois Tigeot ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); 3618e9243325SFrançois Tigeot 3619e9243325SFrançois Tigeot /* Unmask the interrupts that we always want on. */ 3620e9243325SFrançois Tigeot dev_priv->irq_mask = 3621e9243325SFrançois Tigeot ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3622e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3623e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3624477eb7f9SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); 3625e9243325SFrançois Tigeot I915_WRITE16(IMR, dev_priv->irq_mask); 3626e9243325SFrançois Tigeot 3627e9243325SFrançois Tigeot I915_WRITE16(IER, 3628e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3629e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3630e9243325SFrançois Tigeot I915_USER_INTERRUPT); 3631e9243325SFrançois Tigeot POSTING_READ16(IER); 3632e9243325SFrançois Tigeot 36339edbd4a0SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 36349edbd4a0SFrançois Tigeot * just to make the assert_spin_locked check happy. */ 36355e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 3636ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS); 3637ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS); 36385e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 36399edbd4a0SFrançois Tigeot 3640e9243325SFrançois Tigeot return 0; 3641e9243325SFrançois Tigeot } 3642e9243325SFrançois Tigeot 36438e26cdf6SFrançois Tigeot /* 36448e26cdf6SFrançois Tigeot * Returns true when a page flip has completed. 36458e26cdf6SFrançois Tigeot */ 36461487f786SFrançois Tigeot static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv, 36479edbd4a0SFrançois Tigeot int plane, int pipe, u32 iir) 36488e26cdf6SFrançois Tigeot { 36499edbd4a0SFrançois Tigeot u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); 36508e26cdf6SFrançois Tigeot 36511487f786SFrançois Tigeot if (!intel_pipe_handle_vblank(dev_priv, pipe)) 36528e26cdf6SFrançois Tigeot return false; 36538e26cdf6SFrançois Tigeot 36548e26cdf6SFrançois Tigeot if ((iir & flip_pending) == 0) 36551b13d190SFrançois Tigeot goto check_page_flip; 36568e26cdf6SFrançois Tigeot 36578e26cdf6SFrançois Tigeot /* We detect FlipDone by looking for the change in PendingFlip from '1' 36588e26cdf6SFrançois Tigeot * to '0' on the following vblank, i.e. IIR has the Pendingflip 36598e26cdf6SFrançois Tigeot * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence 36608e26cdf6SFrançois Tigeot * the flip is completed (no longer pending). Since this doesn't raise 36618e26cdf6SFrançois Tigeot * an interrupt per se, we watch for the change at vblank. 36628e26cdf6SFrançois Tigeot */ 36638e26cdf6SFrançois Tigeot if (I915_READ16(ISR) & flip_pending) 36641b13d190SFrançois Tigeot goto check_page_flip; 36658e26cdf6SFrançois Tigeot 36661487f786SFrançois Tigeot intel_finish_page_flip_cs(dev_priv, pipe); 36678e26cdf6SFrançois Tigeot return true; 36681b13d190SFrançois Tigeot 36691b13d190SFrançois Tigeot check_page_flip: 36701487f786SFrançois Tigeot intel_check_page_flip(dev_priv, pipe); 36711b13d190SFrançois Tigeot return false; 36728e26cdf6SFrançois Tigeot } 36738e26cdf6SFrançois Tigeot 3674183e2373SFrançois Tigeot static irqreturn_t i8xx_irq_handler(int irq, void *arg) 3675e9243325SFrançois Tigeot { 3676ba55f2f5SFrançois Tigeot struct drm_device *dev = arg; 3677303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3678e9243325SFrançois Tigeot u16 iir, new_iir; 3679e9243325SFrançois Tigeot u32 pipe_stats[2]; 3680e9243325SFrançois Tigeot int pipe; 3681e9243325SFrançois Tigeot u16 flip_mask = 3682e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3683e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 3684183e2373SFrançois Tigeot irqreturn_t ret; 3685e9243325SFrançois Tigeot 36862c9916cdSFrançois Tigeot if (!intel_irqs_enabled(dev_priv)) 36872c9916cdSFrançois Tigeot return IRQ_NONE; 36882c9916cdSFrançois Tigeot 3689aee94f86SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 3690aee94f86SFrançois Tigeot disable_rpm_wakeref_asserts(dev_priv); 3691aee94f86SFrançois Tigeot 3692183e2373SFrançois Tigeot ret = IRQ_NONE; 3693e9243325SFrançois Tigeot iir = I915_READ16(IIR); 3694e9243325SFrançois Tigeot if (iir == 0) 3695aee94f86SFrançois Tigeot goto out; 3696e9243325SFrançois Tigeot 3697e9243325SFrançois Tigeot while (iir & ~flip_mask) { 3698e9243325SFrançois Tigeot /* Can't rely on pipestat interrupt bit in iir as it might 3699e9243325SFrançois Tigeot * have been cleared after the pipestat interrupt was received. 3700e9243325SFrançois Tigeot * It doesn't set the bit in iir again, but it still produces 3701e9243325SFrançois Tigeot * interrupts (for non-MSI). 3702e9243325SFrançois Tigeot */ 3703e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3704e9243325SFrançois Tigeot if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 37052c9916cdSFrançois Tigeot DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); 3706e9243325SFrançois Tigeot 37071b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 3708aee94f86SFrançois Tigeot i915_reg_t reg = PIPESTAT(pipe); 3709e9243325SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg); 3710e9243325SFrançois Tigeot 3711e9243325SFrançois Tigeot /* 3712e9243325SFrançois Tigeot * Clear the PIPE*STAT regs before the IIR 3713e9243325SFrançois Tigeot */ 3714ba55f2f5SFrançois Tigeot if (pipe_stats[pipe] & 0x8000ffff) 3715e9243325SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 3716e9243325SFrançois Tigeot } 3717e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3718e9243325SFrançois Tigeot 3719e9243325SFrançois Tigeot I915_WRITE16(IIR, iir & ~flip_mask); 3720e9243325SFrançois Tigeot new_iir = I915_READ16(IIR); /* Flush posted writes */ 3721e9243325SFrançois Tigeot 3722e9243325SFrançois Tigeot if (iir & I915_USER_INTERRUPT) 37231e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[RCS]); 3724e9243325SFrançois Tigeot 37251b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 37269edbd4a0SFrançois Tigeot int plane = pipe; 37271487f786SFrançois Tigeot if (HAS_FBC(dev_priv)) 37289edbd4a0SFrançois Tigeot plane = !plane; 3729e9243325SFrançois Tigeot 37309edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && 37311487f786SFrançois Tigeot i8xx_handle_vblank(dev_priv, plane, pipe, iir)) 37329edbd4a0SFrançois Tigeot flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); 37339edbd4a0SFrançois Tigeot 37349edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 37351487f786SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev_priv, pipe); 3736ba55f2f5SFrançois Tigeot 37372c9916cdSFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 37382c9916cdSFrançois Tigeot intel_cpu_fifo_underrun_irq_handler(dev_priv, 37392c9916cdSFrançois Tigeot pipe); 37409edbd4a0SFrançois Tigeot } 3741e9243325SFrançois Tigeot 3742e9243325SFrançois Tigeot iir = new_iir; 3743e9243325SFrançois Tigeot } 3744183e2373SFrançois Tigeot ret = IRQ_HANDLED; 3745e9243325SFrançois Tigeot 3746aee94f86SFrançois Tigeot out: 3747aee94f86SFrançois Tigeot enable_rpm_wakeref_asserts(dev_priv); 3748aee94f86SFrançois Tigeot 3749183e2373SFrançois Tigeot return ret; 3750e9243325SFrançois Tigeot } 3751e9243325SFrançois Tigeot 3752e9243325SFrançois Tigeot static void i8xx_irq_uninstall(struct drm_device * dev) 3753e9243325SFrançois Tigeot { 3754303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3755e9243325SFrançois Tigeot int pipe; 3756e9243325SFrançois Tigeot 37571b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 3758e9243325SFrançois Tigeot /* Clear enable bits; then clear status bits */ 3759e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3760e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); 3761e9243325SFrançois Tigeot } 3762e9243325SFrançois Tigeot I915_WRITE16(IMR, 0xffff); 3763e9243325SFrançois Tigeot I915_WRITE16(IER, 0x0); 3764e9243325SFrançois Tigeot I915_WRITE16(IIR, I915_READ16(IIR)); 3765e9243325SFrançois Tigeot } 3766e9243325SFrançois Tigeot 3767e9243325SFrançois Tigeot static void i915_irq_preinstall(struct drm_device * dev) 3768e9243325SFrançois Tigeot { 3769303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3770e9243325SFrançois Tigeot int pipe; 3771e9243325SFrançois Tigeot 37724be47400SFrançois Tigeot if (I915_HAS_HOTPLUG(dev_priv)) { 3773352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); 3774e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3775e9243325SFrançois Tigeot } 3776e9243325SFrançois Tigeot 3777e9243325SFrançois Tigeot I915_WRITE16(HWSTAM, 0xeffe); 37781b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 3779e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3780e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 3781e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 3782e9243325SFrançois Tigeot POSTING_READ(IER); 3783e9243325SFrançois Tigeot } 3784e9243325SFrançois Tigeot 3785e9243325SFrançois Tigeot static int i915_irq_postinstall(struct drm_device *dev) 3786e9243325SFrançois Tigeot { 3787303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3788e9243325SFrançois Tigeot u32 enable_mask; 3789e9243325SFrançois Tigeot 3790e9243325SFrançois Tigeot I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); 3791e9243325SFrançois Tigeot 3792e9243325SFrançois Tigeot /* Unmask the interrupts that we always want on. */ 3793e9243325SFrançois Tigeot dev_priv->irq_mask = 3794e9243325SFrançois Tigeot ~(I915_ASLE_INTERRUPT | 3795e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3796e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3797e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3798477eb7f9SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); 3799e9243325SFrançois Tigeot 3800e9243325SFrançois Tigeot enable_mask = 3801e9243325SFrançois Tigeot I915_ASLE_INTERRUPT | 3802e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3803e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3804e9243325SFrançois Tigeot I915_USER_INTERRUPT; 3805e9243325SFrançois Tigeot 38064be47400SFrançois Tigeot if (I915_HAS_HOTPLUG(dev_priv)) { 3807352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); 3808a2fdbec6SFrançois Tigeot POSTING_READ(PORT_HOTPLUG_EN); 3809a2fdbec6SFrançois Tigeot 3810e9243325SFrançois Tigeot /* Enable in IER... */ 3811e9243325SFrançois Tigeot enable_mask |= I915_DISPLAY_PORT_INTERRUPT; 3812e9243325SFrançois Tigeot /* and unmask in IMR */ 3813e9243325SFrançois Tigeot dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; 3814e9243325SFrançois Tigeot } 3815e9243325SFrançois Tigeot 3816e9243325SFrançois Tigeot I915_WRITE(IMR, dev_priv->irq_mask); 3817e9243325SFrançois Tigeot I915_WRITE(IER, enable_mask); 3818e9243325SFrançois Tigeot POSTING_READ(IER); 3819e9243325SFrançois Tigeot 38201487f786SFrançois Tigeot i915_enable_asle_pipestat(dev_priv); 3821e9243325SFrançois Tigeot 38229edbd4a0SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 38239edbd4a0SFrançois Tigeot * just to make the assert_spin_locked check happy. */ 38245e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 3825ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS); 3826ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS); 38275e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 38289edbd4a0SFrançois Tigeot 3829a2fdbec6SFrançois Tigeot return 0; 3830a2fdbec6SFrançois Tigeot } 3831a2fdbec6SFrançois Tigeot 38328e26cdf6SFrançois Tigeot /* 38338e26cdf6SFrançois Tigeot * Returns true when a page flip has completed. 38348e26cdf6SFrançois Tigeot */ 38351487f786SFrançois Tigeot static bool i915_handle_vblank(struct drm_i915_private *dev_priv, 38368e26cdf6SFrançois Tigeot int plane, int pipe, u32 iir) 3837a2fdbec6SFrançois Tigeot { 38388e26cdf6SFrançois Tigeot u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); 3839a2fdbec6SFrançois Tigeot 38401487f786SFrançois Tigeot if (!intel_pipe_handle_vblank(dev_priv, pipe)) 38418e26cdf6SFrançois Tigeot return false; 3842a2fdbec6SFrançois Tigeot 38438e26cdf6SFrançois Tigeot if ((iir & flip_pending) == 0) 38441b13d190SFrançois Tigeot goto check_page_flip; 3845e9243325SFrançois Tigeot 38468e26cdf6SFrançois Tigeot /* We detect FlipDone by looking for the change in PendingFlip from '1' 38478e26cdf6SFrançois Tigeot * to '0' on the following vblank, i.e. IIR has the Pendingflip 38488e26cdf6SFrançois Tigeot * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence 38498e26cdf6SFrançois Tigeot * the flip is completed (no longer pending). Since this doesn't raise 38508e26cdf6SFrançois Tigeot * an interrupt per se, we watch for the change at vblank. 38518e26cdf6SFrançois Tigeot */ 38528e26cdf6SFrançois Tigeot if (I915_READ(ISR) & flip_pending) 38531b13d190SFrançois Tigeot goto check_page_flip; 38548e26cdf6SFrançois Tigeot 38551487f786SFrançois Tigeot intel_finish_page_flip_cs(dev_priv, pipe); 38568e26cdf6SFrançois Tigeot return true; 38571b13d190SFrançois Tigeot 38581b13d190SFrançois Tigeot check_page_flip: 38591487f786SFrançois Tigeot intel_check_page_flip(dev_priv, pipe); 38601b13d190SFrançois Tigeot return false; 3861e9243325SFrançois Tigeot } 3862e9243325SFrançois Tigeot 3863183e2373SFrançois Tigeot static irqreturn_t i915_irq_handler(int irq, void *arg) 3864e9243325SFrançois Tigeot { 3865ba55f2f5SFrançois Tigeot struct drm_device *dev = arg; 3866303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3867e9243325SFrançois Tigeot u32 iir, new_iir, pipe_stats[I915_MAX_PIPES]; 3868e9243325SFrançois Tigeot u32 flip_mask = 3869e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3870e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 3871183e2373SFrançois Tigeot int pipe, ret = IRQ_NONE; 3872e9243325SFrançois Tigeot 38732c9916cdSFrançois Tigeot if (!intel_irqs_enabled(dev_priv)) 38742c9916cdSFrançois Tigeot return IRQ_NONE; 38752c9916cdSFrançois Tigeot 3876aee94f86SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 3877aee94f86SFrançois Tigeot disable_rpm_wakeref_asserts(dev_priv); 3878aee94f86SFrançois Tigeot 3879e9243325SFrançois Tigeot iir = I915_READ(IIR); 3880e9243325SFrançois Tigeot do { 3881e9243325SFrançois Tigeot bool irq_received = (iir & ~flip_mask) != 0; 3882e9243325SFrançois Tigeot bool blc_event = false; 3883e9243325SFrançois Tigeot 3884e9243325SFrançois Tigeot /* Can't rely on pipestat interrupt bit in iir as it might 3885e9243325SFrançois Tigeot * have been cleared after the pipestat interrupt was received. 3886e9243325SFrançois Tigeot * It doesn't set the bit in iir again, but it still produces 3887e9243325SFrançois Tigeot * interrupts (for non-MSI). 3888e9243325SFrançois Tigeot */ 3889e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3890e9243325SFrançois Tigeot if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 38912c9916cdSFrançois Tigeot DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); 3892e9243325SFrançois Tigeot 38931b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 3894aee94f86SFrançois Tigeot i915_reg_t reg = PIPESTAT(pipe); 3895e9243325SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg); 3896e9243325SFrançois Tigeot 3897e9243325SFrançois Tigeot /* Clear the PIPE*STAT regs before the IIR */ 3898e9243325SFrançois Tigeot if (pipe_stats[pipe] & 0x8000ffff) { 3899e9243325SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 3900e9243325SFrançois Tigeot irq_received = true; 3901e9243325SFrançois Tigeot } 3902e9243325SFrançois Tigeot } 3903e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3904e9243325SFrançois Tigeot 3905e9243325SFrançois Tigeot if (!irq_received) 3906e9243325SFrançois Tigeot break; 3907e9243325SFrançois Tigeot 3908e9243325SFrançois Tigeot /* Consume port. Then clear IIR or we'll miss events */ 39091487f786SFrançois Tigeot if (I915_HAS_HOTPLUG(dev_priv) && 39108621f407SFrançois Tigeot iir & I915_DISPLAY_PORT_INTERRUPT) { 39118621f407SFrançois Tigeot u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv); 39128621f407SFrançois Tigeot if (hotplug_status) 39131487f786SFrançois Tigeot i9xx_hpd_irq_handler(dev_priv, hotplug_status); 39148621f407SFrançois Tigeot } 3915e9243325SFrançois Tigeot 3916e9243325SFrançois Tigeot I915_WRITE(IIR, iir & ~flip_mask); 3917e9243325SFrançois Tigeot new_iir = I915_READ(IIR); /* Flush posted writes */ 3918e9243325SFrançois Tigeot 3919e9243325SFrançois Tigeot if (iir & I915_USER_INTERRUPT) 39201e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[RCS]); 3921e9243325SFrançois Tigeot 39221b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 3923e9243325SFrançois Tigeot int plane = pipe; 39241487f786SFrançois Tigeot if (HAS_FBC(dev_priv)) 3925e9243325SFrançois Tigeot plane = !plane; 39268e26cdf6SFrançois Tigeot 3927e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && 39281487f786SFrançois Tigeot i915_handle_vblank(dev_priv, plane, pipe, iir)) 39298e26cdf6SFrançois Tigeot flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); 3930e9243325SFrançois Tigeot 3931e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 3932e9243325SFrançois Tigeot blc_event = true; 39339edbd4a0SFrançois Tigeot 39349edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 39351487f786SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev_priv, pipe); 3936ba55f2f5SFrançois Tigeot 39372c9916cdSFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 39382c9916cdSFrançois Tigeot intel_cpu_fifo_underrun_irq_handler(dev_priv, 39392c9916cdSFrançois Tigeot pipe); 3940e9243325SFrançois Tigeot } 3941e9243325SFrançois Tigeot 3942e9243325SFrançois Tigeot if (blc_event || (iir & I915_ASLE_INTERRUPT)) 39431487f786SFrançois Tigeot intel_opregion_asle_intr(dev_priv); 3944e9243325SFrançois Tigeot 3945e9243325SFrançois Tigeot /* With MSI, interrupts are only generated when iir 3946e9243325SFrançois Tigeot * transitions from zero to nonzero. If another bit got 3947e9243325SFrançois Tigeot * set while we were handling the existing iir bits, then 3948e9243325SFrançois Tigeot * we would never get another interrupt. 3949e9243325SFrançois Tigeot * 3950e9243325SFrançois Tigeot * This is fine on non-MSI as well, as if we hit this path 3951e9243325SFrançois Tigeot * we avoid exiting the interrupt handler only to generate 3952e9243325SFrançois Tigeot * another one. 3953e9243325SFrançois Tigeot * 3954e9243325SFrançois Tigeot * Note that for MSI this could cause a stray interrupt report 3955e9243325SFrançois Tigeot * if an interrupt landed in the time between writing IIR and 3956e9243325SFrançois Tigeot * the posting read. This should be rare enough to never 3957e9243325SFrançois Tigeot * trigger the 99% of 100,000 interrupts test for disabling 3958e9243325SFrançois Tigeot * stray interrupts. 3959e9243325SFrançois Tigeot */ 3960183e2373SFrançois Tigeot ret = IRQ_HANDLED; 3961e9243325SFrançois Tigeot iir = new_iir; 3962e9243325SFrançois Tigeot } while (iir & ~flip_mask); 3963e9243325SFrançois Tigeot 3964aee94f86SFrançois Tigeot enable_rpm_wakeref_asserts(dev_priv); 3965aee94f86SFrançois Tigeot 3966183e2373SFrançois Tigeot return ret; 3967e9243325SFrançois Tigeot } 3968e9243325SFrançois Tigeot 3969e9243325SFrançois Tigeot static void i915_irq_uninstall(struct drm_device * dev) 3970e9243325SFrançois Tigeot { 3971303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3972e9243325SFrançois Tigeot int pipe; 3973e9243325SFrançois Tigeot 39744be47400SFrançois Tigeot if (I915_HAS_HOTPLUG(dev_priv)) { 3975352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); 3976e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3977e9243325SFrançois Tigeot } 3978e9243325SFrançois Tigeot 3979e9243325SFrançois Tigeot I915_WRITE16(HWSTAM, 0xffff); 39801b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 3981e9243325SFrançois Tigeot /* Clear enable bits; then clear status bits */ 3982e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3983e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); 3984e9243325SFrançois Tigeot } 3985e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 3986e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 3987e9243325SFrançois Tigeot 3988e9243325SFrançois Tigeot I915_WRITE(IIR, I915_READ(IIR)); 3989e9243325SFrançois Tigeot } 3990e9243325SFrançois Tigeot 3991e9243325SFrançois Tigeot static void i965_irq_preinstall(struct drm_device * dev) 3992e9243325SFrançois Tigeot { 3993303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3994e9243325SFrançois Tigeot int pipe; 3995e9243325SFrançois Tigeot 3996352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); 3997e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3998e9243325SFrançois Tigeot 3999e9243325SFrançois Tigeot I915_WRITE(HWSTAM, 0xeffe); 40001b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 4001e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 4002e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 4003e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 4004e9243325SFrançois Tigeot POSTING_READ(IER); 4005e9243325SFrançois Tigeot } 4006e9243325SFrançois Tigeot 4007e9243325SFrançois Tigeot static int i965_irq_postinstall(struct drm_device *dev) 4008e9243325SFrançois Tigeot { 4009303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 4010e9243325SFrançois Tigeot u32 enable_mask; 4011e9243325SFrançois Tigeot u32 error_mask; 4012e9243325SFrançois Tigeot 4013e9243325SFrançois Tigeot /* Unmask the interrupts that we always want on. */ 4014e9243325SFrançois Tigeot dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT | 4015e9243325SFrançois Tigeot I915_DISPLAY_PORT_INTERRUPT | 4016e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 4017e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 4018e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 4019e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | 4020e9243325SFrançois Tigeot I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 4021e9243325SFrançois Tigeot 4022e9243325SFrançois Tigeot enable_mask = ~dev_priv->irq_mask; 40238e26cdf6SFrançois Tigeot enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 40248e26cdf6SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); 4025e9243325SFrançois Tigeot enable_mask |= I915_USER_INTERRUPT; 4026e9243325SFrançois Tigeot 40271487f786SFrançois Tigeot if (IS_G4X(dev_priv)) 4028e9243325SFrançois Tigeot enable_mask |= I915_BSD_USER_INTERRUPT; 4029e9243325SFrançois Tigeot 40309edbd4a0SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 40319edbd4a0SFrançois Tigeot * just to make the assert_spin_locked check happy. */ 40325e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 4033ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); 4034ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS); 4035ba55f2f5SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS); 40365e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 4037e9243325SFrançois Tigeot 4038e9243325SFrançois Tigeot /* 4039e9243325SFrançois Tigeot * Enable some error detection, note the instruction error mask 4040e9243325SFrançois Tigeot * bit is reserved, so we leave it masked. 4041e9243325SFrançois Tigeot */ 40421487f786SFrançois Tigeot if (IS_G4X(dev_priv)) { 4043e9243325SFrançois Tigeot error_mask = ~(GM45_ERROR_PAGE_TABLE | 4044e9243325SFrançois Tigeot GM45_ERROR_MEM_PRIV | 4045e9243325SFrançois Tigeot GM45_ERROR_CP_PRIV | 4046e9243325SFrançois Tigeot I915_ERROR_MEMORY_REFRESH); 4047e9243325SFrançois Tigeot } else { 4048e9243325SFrançois Tigeot error_mask = ~(I915_ERROR_PAGE_TABLE | 4049e9243325SFrançois Tigeot I915_ERROR_MEMORY_REFRESH); 4050e9243325SFrançois Tigeot } 4051e9243325SFrançois Tigeot I915_WRITE(EMR, error_mask); 4052e9243325SFrançois Tigeot 4053e9243325SFrançois Tigeot I915_WRITE(IMR, dev_priv->irq_mask); 4054e9243325SFrançois Tigeot I915_WRITE(IER, enable_mask); 4055e9243325SFrançois Tigeot POSTING_READ(IER); 4056e9243325SFrançois Tigeot 4057352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); 4058a2fdbec6SFrançois Tigeot POSTING_READ(PORT_HOTPLUG_EN); 4059a2fdbec6SFrançois Tigeot 40601487f786SFrançois Tigeot i915_enable_asle_pipestat(dev_priv); 4061a2fdbec6SFrançois Tigeot 4062a2fdbec6SFrançois Tigeot return 0; 4063a2fdbec6SFrançois Tigeot } 4064a2fdbec6SFrançois Tigeot 40651487f786SFrançois Tigeot static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv) 4066a2fdbec6SFrançois Tigeot { 4067a2fdbec6SFrançois Tigeot u32 hotplug_en; 4068a2fdbec6SFrançois Tigeot 4069*a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->irq_lock); 40709edbd4a0SFrançois Tigeot 4071e9243325SFrançois Tigeot /* Note HDMI and DP share hotplug bits */ 40728e26cdf6SFrançois Tigeot /* enable bits are the same for all generations */ 40731487f786SFrançois Tigeot hotplug_en = intel_hpd_enabled_irqs(dev_priv, hpd_mask_i915); 4074e9243325SFrançois Tigeot /* Programming the CRT detection parameters tends 4075e9243325SFrançois Tigeot to generate a spurious hotplug event about three 4076e9243325SFrançois Tigeot seconds later. So just do it once. 4077e9243325SFrançois Tigeot */ 40781487f786SFrançois Tigeot if (IS_G4X(dev_priv)) 4079e9243325SFrançois Tigeot hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; 4080e9243325SFrançois Tigeot hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; 4081e9243325SFrançois Tigeot 4082e9243325SFrançois Tigeot /* Ignore TV since it's buggy */ 4083352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update_locked(dev_priv, 4084352ff8bdSFrançois Tigeot HOTPLUG_INT_EN_MASK | 4085352ff8bdSFrançois Tigeot CRT_HOTPLUG_VOLTAGE_COMPARE_MASK | 4086352ff8bdSFrançois Tigeot CRT_HOTPLUG_ACTIVATION_PERIOD_64, 4087352ff8bdSFrançois Tigeot hotplug_en); 4088e9243325SFrançois Tigeot } 4089e9243325SFrançois Tigeot 4090183e2373SFrançois Tigeot static irqreturn_t i965_irq_handler(int irq, void *arg) 4091e9243325SFrançois Tigeot { 4092ba55f2f5SFrançois Tigeot struct drm_device *dev = arg; 4093303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 4094e9243325SFrançois Tigeot u32 iir, new_iir; 4095e9243325SFrançois Tigeot u32 pipe_stats[I915_MAX_PIPES]; 4096183e2373SFrançois Tigeot int ret = IRQ_NONE, pipe; 40978e26cdf6SFrançois Tigeot u32 flip_mask = 40988e26cdf6SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 40998e26cdf6SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 4100e9243325SFrançois Tigeot 41012c9916cdSFrançois Tigeot if (!intel_irqs_enabled(dev_priv)) 41022c9916cdSFrançois Tigeot return IRQ_NONE; 41032c9916cdSFrançois Tigeot 4104aee94f86SFrançois Tigeot /* IRQs are synced during runtime_suspend, we don't require a wakeref */ 4105aee94f86SFrançois Tigeot disable_rpm_wakeref_asserts(dev_priv); 4106aee94f86SFrançois Tigeot 4107e9243325SFrançois Tigeot iir = I915_READ(IIR); 4108e9243325SFrançois Tigeot 4109e9243325SFrançois Tigeot for (;;) { 4110ba55f2f5SFrançois Tigeot bool irq_received = (iir & ~flip_mask) != 0; 4111e9243325SFrançois Tigeot bool blc_event = false; 4112e9243325SFrançois Tigeot 4113e9243325SFrançois Tigeot /* Can't rely on pipestat interrupt bit in iir as it might 4114e9243325SFrançois Tigeot * have been cleared after the pipestat interrupt was received. 4115e9243325SFrançois Tigeot * It doesn't set the bit in iir again, but it still produces 4116e9243325SFrançois Tigeot * interrupts (for non-MSI). 4117e9243325SFrançois Tigeot */ 4118e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 4119e9243325SFrançois Tigeot if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 41202c9916cdSFrançois Tigeot DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); 4121e9243325SFrançois Tigeot 41221b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 4123aee94f86SFrançois Tigeot i915_reg_t reg = PIPESTAT(pipe); 4124e9243325SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg); 4125e9243325SFrançois Tigeot 4126e9243325SFrançois Tigeot /* 4127e9243325SFrançois Tigeot * Clear the PIPE*STAT regs before the IIR 4128e9243325SFrançois Tigeot */ 4129e9243325SFrançois Tigeot if (pipe_stats[pipe] & 0x8000ffff) { 4130e9243325SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 4131ba55f2f5SFrançois Tigeot irq_received = true; 4132e9243325SFrançois Tigeot } 4133e9243325SFrançois Tigeot } 4134e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 4135e9243325SFrançois Tigeot 4136e9243325SFrançois Tigeot if (!irq_received) 4137e9243325SFrançois Tigeot break; 4138e9243325SFrançois Tigeot 4139183e2373SFrançois Tigeot ret = IRQ_HANDLED; 4140c0e85e96SFrançois Tigeot 4141e9243325SFrançois Tigeot /* Consume port. Then clear IIR or we'll miss events */ 41428621f407SFrançois Tigeot if (iir & I915_DISPLAY_PORT_INTERRUPT) { 41438621f407SFrançois Tigeot u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv); 41448621f407SFrançois Tigeot if (hotplug_status) 41451487f786SFrançois Tigeot i9xx_hpd_irq_handler(dev_priv, hotplug_status); 41468621f407SFrançois Tigeot } 4147e9243325SFrançois Tigeot 41488e26cdf6SFrançois Tigeot I915_WRITE(IIR, iir & ~flip_mask); 4149e9243325SFrançois Tigeot new_iir = I915_READ(IIR); /* Flush posted writes */ 4150e9243325SFrançois Tigeot 4151e9243325SFrançois Tigeot if (iir & I915_USER_INTERRUPT) 41521e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[RCS]); 4153e9243325SFrançois Tigeot if (iir & I915_BSD_USER_INTERRUPT) 41541e12ee3bSFrançois Tigeot notify_ring(dev_priv->engine[VCS]); 4155e9243325SFrançois Tigeot 41561b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) { 4157e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && 41581487f786SFrançois Tigeot i915_handle_vblank(dev_priv, pipe, pipe, iir)) 41598e26cdf6SFrançois Tigeot flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); 4160e9243325SFrançois Tigeot 4161e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 4162e9243325SFrançois Tigeot blc_event = true; 41639edbd4a0SFrançois Tigeot 41649edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 41651487f786SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev_priv, pipe); 4166e9243325SFrançois Tigeot 41672c9916cdSFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 41682c9916cdSFrançois Tigeot intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); 4169ba55f2f5SFrançois Tigeot } 41709edbd4a0SFrançois Tigeot 4171e9243325SFrançois Tigeot if (blc_event || (iir & I915_ASLE_INTERRUPT)) 41721487f786SFrançois Tigeot intel_opregion_asle_intr(dev_priv); 4173e9243325SFrançois Tigeot 4174a2fdbec6SFrançois Tigeot if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) 41751487f786SFrançois Tigeot gmbus_irq_handler(dev_priv); 4176a2fdbec6SFrançois Tigeot 4177e9243325SFrançois Tigeot /* With MSI, interrupts are only generated when iir 4178e9243325SFrançois Tigeot * transitions from zero to nonzero. If another bit got 4179e9243325SFrançois Tigeot * set while we were handling the existing iir bits, then 4180e9243325SFrançois Tigeot * we would never get another interrupt. 4181e9243325SFrançois Tigeot * 4182e9243325SFrançois Tigeot * This is fine on non-MSI as well, as if we hit this path 4183e9243325SFrançois Tigeot * we avoid exiting the interrupt handler only to generate 4184e9243325SFrançois Tigeot * another one. 4185e9243325SFrançois Tigeot * 4186e9243325SFrançois Tigeot * Note that for MSI this could cause a stray interrupt report 4187e9243325SFrançois Tigeot * if an interrupt landed in the time between writing IIR and 4188e9243325SFrançois Tigeot * the posting read. This should be rare enough to never 4189e9243325SFrançois Tigeot * trigger the 99% of 100,000 interrupts test for disabling 4190e9243325SFrançois Tigeot * stray interrupts. 4191e9243325SFrançois Tigeot */ 4192e9243325SFrançois Tigeot iir = new_iir; 4193e9243325SFrançois Tigeot } 4194e9243325SFrançois Tigeot 4195aee94f86SFrançois Tigeot enable_rpm_wakeref_asserts(dev_priv); 4196aee94f86SFrançois Tigeot 4197183e2373SFrançois Tigeot return ret; 4198e9243325SFrançois Tigeot } 4199e9243325SFrançois Tigeot 4200e9243325SFrançois Tigeot static void i965_irq_uninstall(struct drm_device * dev) 4201e9243325SFrançois Tigeot { 4202303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 4203e9243325SFrançois Tigeot int pipe; 4204e9243325SFrançois Tigeot 4205e9243325SFrançois Tigeot if (!dev_priv) 4206e9243325SFrançois Tigeot return; 4207e9243325SFrançois Tigeot 4208352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); 4209e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 4210e9243325SFrançois Tigeot 4211e9243325SFrançois Tigeot I915_WRITE(HWSTAM, 0xffffffff); 42121b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 4213e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 4214e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 4215e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 4216e9243325SFrançois Tigeot 42171b13d190SFrançois Tigeot for_each_pipe(dev_priv, pipe) 4218e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 4219e9243325SFrançois Tigeot I915_READ(PIPESTAT(pipe)) & 0x8000ffff); 4220e9243325SFrançois Tigeot I915_WRITE(IIR, I915_READ(IIR)); 4221e9243325SFrançois Tigeot } 4222e9243325SFrançois Tigeot 42232c9916cdSFrançois Tigeot /** 42242c9916cdSFrançois Tigeot * intel_irq_init - initializes irq support 42252c9916cdSFrançois Tigeot * @dev_priv: i915 device instance 42262c9916cdSFrançois Tigeot * 42272c9916cdSFrançois Tigeot * This function initializes all the irq support including work items, timers 42282c9916cdSFrançois Tigeot * and all the vtables. It does not setup the interrupt itself though. 42292c9916cdSFrançois Tigeot */ 42302c9916cdSFrançois Tigeot void intel_irq_init(struct drm_i915_private *dev_priv) 4231e9243325SFrançois Tigeot { 4232303bf270SFrançois Tigeot struct drm_device *dev = &dev_priv->drm; 4233e9243325SFrançois Tigeot 4234a05eeebfSFrançois Tigeot intel_hpd_init_work(dev_priv); 4235a05eeebfSFrançois Tigeot 4236e9243325SFrançois Tigeot INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); 423700640ec9SFrançois Tigeot INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); 4238e9243325SFrançois Tigeot 42394be47400SFrançois Tigeot if (HAS_GUC_SCHED(dev_priv)) 42404be47400SFrançois Tigeot dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT; 42414be47400SFrançois Tigeot 4242ba55f2f5SFrançois Tigeot /* Let's track the enabled rps events */ 4243aee94f86SFrançois Tigeot if (IS_VALLEYVIEW(dev_priv)) 42441b13d190SFrançois Tigeot /* WaGsvRC0ResidencyMethod:vlv */ 42454be47400SFrançois Tigeot dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED; 424624edb884SFrançois Tigeot else 4247ba55f2f5SFrançois Tigeot dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; 4248ba55f2f5SFrançois Tigeot 4249*a85cb24fSFrançois Tigeot dev_priv->rps.pm_intrmsk_mbz = 0; 42501487f786SFrançois Tigeot 42511487f786SFrançois Tigeot /* 4252*a85cb24fSFrançois Tigeot * SNB,IVB,HSW can while VLV,CHV may hard hang on looping batchbuffer 42531487f786SFrançois Tigeot * if GEN6_PM_UP_EI_EXPIRED is masked. 42541487f786SFrançois Tigeot * 42551487f786SFrançois Tigeot * TODO: verify if this can be reproduced on VLV,CHV. 42561487f786SFrançois Tigeot */ 4257*a85cb24fSFrançois Tigeot if (INTEL_INFO(dev_priv)->gen <= 7) 4258*a85cb24fSFrançois Tigeot dev_priv->rps.pm_intrmsk_mbz |= GEN6_PM_RP_UP_EI_EXPIRED; 42591487f786SFrançois Tigeot 42601487f786SFrançois Tigeot if (INTEL_INFO(dev_priv)->gen >= 8) 4261*a85cb24fSFrançois Tigeot dev_priv->rps.pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC; 42621487f786SFrançois Tigeot 42632c9916cdSFrançois Tigeot if (IS_GEN2(dev_priv)) { 426471f41f3eSFrançois Tigeot /* Gen2 doesn't have a hardware frame counter */ 42659edbd4a0SFrançois Tigeot dev->max_vblank_count = 0; 42662c9916cdSFrançois Tigeot } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) { 4267e9243325SFrançois Tigeot dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ 4268352ff8bdSFrançois Tigeot dev->driver->get_vblank_counter = g4x_get_vblank_counter; 42699edbd4a0SFrançois Tigeot } else { 42709edbd4a0SFrançois Tigeot dev->driver->get_vblank_counter = i915_get_vblank_counter; 42719edbd4a0SFrançois Tigeot dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ 4272e9243325SFrançois Tigeot } 4273e9243325SFrançois Tigeot 42741b13d190SFrançois Tigeot /* 42751b13d190SFrançois Tigeot * Opt out of the vblank disable timer on everything except gen2. 42761b13d190SFrançois Tigeot * Gen2 doesn't have a hardware frame counter and so depends on 42771b13d190SFrançois Tigeot * vblank interrupts to produce sane vblank seuquence numbers. 42781b13d190SFrançois Tigeot */ 42792c9916cdSFrançois Tigeot if (!IS_GEN2(dev_priv)) 42801b13d190SFrançois Tigeot dev->vblank_disable_immediate = true; 42811b13d190SFrançois Tigeot 42824be47400SFrançois Tigeot /* Most platforms treat the display irq block as an always-on 42834be47400SFrançois Tigeot * power domain. vlv/chv can disable it at runtime and need 42844be47400SFrançois Tigeot * special care to avoid writing any of the display block registers 42854be47400SFrançois Tigeot * outside of the power domain. We defer setting up the display irqs 42864be47400SFrançois Tigeot * in this case to the runtime pm. 42874be47400SFrançois Tigeot */ 42884be47400SFrançois Tigeot dev_priv->display_irqs_enabled = true; 42894be47400SFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 42904be47400SFrançois Tigeot dev_priv->display_irqs_enabled = false; 42914be47400SFrançois Tigeot 4292*a85cb24fSFrançois Tigeot dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD; 4293*a85cb24fSFrançois Tigeot 4294e9243325SFrançois Tigeot dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; 4295e9243325SFrançois Tigeot dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; 4296e9243325SFrançois Tigeot 42972c9916cdSFrançois Tigeot if (IS_CHERRYVIEW(dev_priv)) { 4298ba55f2f5SFrançois Tigeot dev->driver->irq_handler = cherryview_irq_handler; 4299ba55f2f5SFrançois Tigeot dev->driver->irq_preinstall = cherryview_irq_preinstall; 4300ba55f2f5SFrançois Tigeot dev->driver->irq_postinstall = cherryview_irq_postinstall; 4301ba55f2f5SFrançois Tigeot dev->driver->irq_uninstall = cherryview_irq_uninstall; 43021e12ee3bSFrançois Tigeot dev->driver->enable_vblank = i965_enable_vblank; 43031e12ee3bSFrançois Tigeot dev->driver->disable_vblank = i965_disable_vblank; 4304ba55f2f5SFrançois Tigeot dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; 43052c9916cdSFrançois Tigeot } else if (IS_VALLEYVIEW(dev_priv)) { 4306e9243325SFrançois Tigeot dev->driver->irq_handler = valleyview_irq_handler; 4307e9243325SFrançois Tigeot dev->driver->irq_preinstall = valleyview_irq_preinstall; 4308e9243325SFrançois Tigeot dev->driver->irq_postinstall = valleyview_irq_postinstall; 4309e9243325SFrançois Tigeot dev->driver->irq_uninstall = valleyview_irq_uninstall; 43101e12ee3bSFrançois Tigeot dev->driver->enable_vblank = i965_enable_vblank; 43111e12ee3bSFrançois Tigeot dev->driver->disable_vblank = i965_disable_vblank; 43128e26cdf6SFrançois Tigeot dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; 43132c9916cdSFrançois Tigeot } else if (INTEL_INFO(dev_priv)->gen >= 8) { 43149edbd4a0SFrançois Tigeot dev->driver->irq_handler = gen8_irq_handler; 4315ba55f2f5SFrançois Tigeot dev->driver->irq_preinstall = gen8_irq_reset; 43169edbd4a0SFrançois Tigeot dev->driver->irq_postinstall = gen8_irq_postinstall; 43179edbd4a0SFrançois Tigeot dev->driver->irq_uninstall = gen8_irq_uninstall; 43189edbd4a0SFrançois Tigeot dev->driver->enable_vblank = gen8_enable_vblank; 43199edbd4a0SFrançois Tigeot dev->driver->disable_vblank = gen8_disable_vblank; 4320*a85cb24fSFrançois Tigeot if (IS_GEN9_LP(dev_priv)) 432119c468b4SFrançois Tigeot dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; 43221e12ee3bSFrançois Tigeot else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv)) 4323352ff8bdSFrançois Tigeot dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; 4324352ff8bdSFrançois Tigeot else 4325352ff8bdSFrançois Tigeot dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; 43261e12ee3bSFrançois Tigeot } else if (HAS_PCH_SPLIT(dev_priv)) { 4327e9243325SFrançois Tigeot dev->driver->irq_handler = ironlake_irq_handler; 4328ba55f2f5SFrançois Tigeot dev->driver->irq_preinstall = ironlake_irq_reset; 4329e9243325SFrançois Tigeot dev->driver->irq_postinstall = ironlake_irq_postinstall; 4330e9243325SFrançois Tigeot dev->driver->irq_uninstall = ironlake_irq_uninstall; 4331e9243325SFrançois Tigeot dev->driver->enable_vblank = ironlake_enable_vblank; 4332e9243325SFrançois Tigeot dev->driver->disable_vblank = ironlake_disable_vblank; 4333352ff8bdSFrançois Tigeot dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; 4334e9243325SFrançois Tigeot } else { 43351487f786SFrançois Tigeot if (IS_GEN2(dev_priv)) { 4336e9243325SFrançois Tigeot dev->driver->irq_preinstall = i8xx_irq_preinstall; 4337e9243325SFrançois Tigeot dev->driver->irq_postinstall = i8xx_irq_postinstall; 4338e9243325SFrançois Tigeot dev->driver->irq_handler = i8xx_irq_handler; 4339e9243325SFrançois Tigeot dev->driver->irq_uninstall = i8xx_irq_uninstall; 43401e12ee3bSFrançois Tigeot dev->driver->enable_vblank = i8xx_enable_vblank; 43411e12ee3bSFrançois Tigeot dev->driver->disable_vblank = i8xx_disable_vblank; 43421487f786SFrançois Tigeot } else if (IS_GEN3(dev_priv)) { 4343e9243325SFrançois Tigeot dev->driver->irq_preinstall = i915_irq_preinstall; 4344e9243325SFrançois Tigeot dev->driver->irq_postinstall = i915_irq_postinstall; 4345e9243325SFrançois Tigeot dev->driver->irq_uninstall = i915_irq_uninstall; 4346e9243325SFrançois Tigeot dev->driver->irq_handler = i915_irq_handler; 43471e12ee3bSFrançois Tigeot dev->driver->enable_vblank = i8xx_enable_vblank; 43481e12ee3bSFrançois Tigeot dev->driver->disable_vblank = i8xx_disable_vblank; 4349e9243325SFrançois Tigeot } else { 4350e9243325SFrançois Tigeot dev->driver->irq_preinstall = i965_irq_preinstall; 4351e9243325SFrançois Tigeot dev->driver->irq_postinstall = i965_irq_postinstall; 4352e9243325SFrançois Tigeot dev->driver->irq_uninstall = i965_irq_uninstall; 4353e9243325SFrançois Tigeot dev->driver->irq_handler = i965_irq_handler; 43541e12ee3bSFrançois Tigeot dev->driver->enable_vblank = i965_enable_vblank; 43551e12ee3bSFrançois Tigeot dev->driver->disable_vblank = i965_disable_vblank; 4356e9243325SFrançois Tigeot } 43572c9916cdSFrançois Tigeot if (I915_HAS_HOTPLUG(dev_priv)) 43582c9916cdSFrançois Tigeot dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; 4359e9243325SFrançois Tigeot } 4360e9243325SFrançois Tigeot } 4361a2fdbec6SFrançois Tigeot 43622c9916cdSFrançois Tigeot /** 43632c9916cdSFrançois Tigeot * intel_irq_install - enables the hardware interrupt 43642c9916cdSFrançois Tigeot * @dev_priv: i915 device instance 43652c9916cdSFrançois Tigeot * 43662c9916cdSFrançois Tigeot * This function enables the hardware interrupt handling, but leaves the hotplug 43672c9916cdSFrançois Tigeot * handling still disabled. It is called after intel_irq_init(). 43682c9916cdSFrançois Tigeot * 43692c9916cdSFrançois Tigeot * In the driver load and resume code we need working interrupts in a few places 43702c9916cdSFrançois Tigeot * but don't want to deal with the hassle of concurrent probe and hotplug 43712c9916cdSFrançois Tigeot * workers. Hence the split into this two-stage approach. 43722c9916cdSFrançois Tigeot */ 43732c9916cdSFrançois Tigeot int intel_irq_install(struct drm_i915_private *dev_priv) 43749edbd4a0SFrançois Tigeot { 43752c9916cdSFrançois Tigeot /* 43762c9916cdSFrançois Tigeot * We enable some interrupt sources in our postinstall hooks, so mark 43772c9916cdSFrançois Tigeot * interrupts as enabled _before_ actually enabling them to avoid 43782c9916cdSFrançois Tigeot * special cases in our ordering checks. 43792c9916cdSFrançois Tigeot */ 43802c9916cdSFrançois Tigeot dev_priv->pm.irqs_enabled = true; 43819edbd4a0SFrançois Tigeot 4382303bf270SFrançois Tigeot return drm_irq_install(&dev_priv->drm, dev_priv->drm.pdev->irq); 43839edbd4a0SFrançois Tigeot } 43849edbd4a0SFrançois Tigeot 43852c9916cdSFrançois Tigeot /** 43862c9916cdSFrançois Tigeot * intel_irq_uninstall - finilizes all irq handling 43872c9916cdSFrançois Tigeot * @dev_priv: i915 device instance 43882c9916cdSFrançois Tigeot * 43892c9916cdSFrançois Tigeot * This stops interrupt and hotplug handling and unregisters and frees all 43902c9916cdSFrançois Tigeot * resources acquired in the init functions. 43912c9916cdSFrançois Tigeot */ 43922c9916cdSFrançois Tigeot void intel_irq_uninstall(struct drm_i915_private *dev_priv) 43939edbd4a0SFrançois Tigeot { 4394303bf270SFrançois Tigeot drm_irq_uninstall(&dev_priv->drm); 43952c9916cdSFrançois Tigeot intel_hpd_cancel_work(dev_priv); 43962c9916cdSFrançois Tigeot dev_priv->pm.irqs_enabled = false; 43972c9916cdSFrançois Tigeot } 43989edbd4a0SFrançois Tigeot 43992c9916cdSFrançois Tigeot /** 44002c9916cdSFrançois Tigeot * intel_runtime_pm_disable_interrupts - runtime interrupt disabling 44012c9916cdSFrançois Tigeot * @dev_priv: i915 device instance 44022c9916cdSFrançois Tigeot * 44032c9916cdSFrançois Tigeot * This function is used to disable interrupts at runtime, both in the runtime 44042c9916cdSFrançois Tigeot * pm and the system suspend/resume code. 44052c9916cdSFrançois Tigeot */ 44062c9916cdSFrançois Tigeot void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv) 44072c9916cdSFrançois Tigeot { 4408303bf270SFrançois Tigeot dev_priv->drm.driver->irq_uninstall(&dev_priv->drm); 44092c9916cdSFrançois Tigeot dev_priv->pm.irqs_enabled = false; 4410303bf270SFrançois Tigeot synchronize_irq(dev_priv->drm.irq); 44112c9916cdSFrançois Tigeot } 44122c9916cdSFrançois Tigeot 44132c9916cdSFrançois Tigeot /** 44142c9916cdSFrançois Tigeot * intel_runtime_pm_enable_interrupts - runtime interrupt enabling 44152c9916cdSFrançois Tigeot * @dev_priv: i915 device instance 44162c9916cdSFrançois Tigeot * 44172c9916cdSFrançois Tigeot * This function is used to enable interrupts at runtime, both in the runtime 44182c9916cdSFrançois Tigeot * pm and the system suspend/resume code. 44192c9916cdSFrançois Tigeot */ 44202c9916cdSFrançois Tigeot void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv) 44212c9916cdSFrançois Tigeot { 44222c9916cdSFrançois Tigeot dev_priv->pm.irqs_enabled = true; 4423303bf270SFrançois Tigeot dev_priv->drm.driver->irq_preinstall(&dev_priv->drm); 4424303bf270SFrançois Tigeot dev_priv->drm.driver->irq_postinstall(&dev_priv->drm); 44259edbd4a0SFrançois Tigeot } 4426