summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c2675
1 files changed, 22 insertions, 2653 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d24bdea65a3d..82fbabcdd7a5 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -33,15 +33,11 @@
#include <drm/drm_drv.h>
-#include "display/icl_dsi_regs.h"
-#include "display/intel_de.h"
-#include "display/intel_display_trace.h"
+#include "display/intel_display_irq.h"
#include "display/intel_display_types.h"
-#include "display/intel_fdi_regs.h"
-#include "display/intel_fifo_underrun.h"
#include "display/intel_hotplug.h"
+#include "display/intel_hotplug_irq.h"
#include "display/intel_lpe_audio.h"
-#include "display/intel_psr.h"
#include "display/intel_psr_regs.h"
#include "gt/intel_breadcrumbs.h"
@@ -54,6 +50,7 @@
#include "i915_driver.h"
#include "i915_drv.h"
#include "i915_irq.h"
+#include "i915_reg.h"
/**
* DOC: interrupt handling
@@ -81,159 +78,6 @@ static inline void pmu_irq_stats(struct drm_i915_private *i915,
WRITE_ONCE(i915->pmu.irq_count, i915->pmu.irq_count + 1);
}
-typedef bool (*long_pulse_detect_func)(enum hpd_pin pin, u32 val);
-typedef u32 (*hotplug_enables_func)(struct intel_encoder *encoder);
-
-static const u32 hpd_ilk[HPD_NUM_PINS] = {
- [HPD_PORT_A] = DE_DP_A_HOTPLUG,
-};
-
-static const u32 hpd_ivb[HPD_NUM_PINS] = {
- [HPD_PORT_A] = DE_DP_A_HOTPLUG_IVB,
-};
-
-static const u32 hpd_bdw[HPD_NUM_PINS] = {
- [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A),
-};
-
-static const u32 hpd_ibx[HPD_NUM_PINS] = {
- [HPD_CRT] = SDE_CRT_HOTPLUG,
- [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
- [HPD_PORT_B] = SDE_PORTB_HOTPLUG,
- [HPD_PORT_C] = SDE_PORTC_HOTPLUG,
- [HPD_PORT_D] = SDE_PORTD_HOTPLUG,
-};
-
-static const u32 hpd_cpt[HPD_NUM_PINS] = {
- [HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
- [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
- [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
- [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
- [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
-};
-
-static const u32 hpd_spt[HPD_NUM_PINS] = {
- [HPD_PORT_A] = SDE_PORTA_HOTPLUG_SPT,
- [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
- [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
- [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
- [HPD_PORT_E] = SDE_PORTE_HOTPLUG_SPT,
-};
-
-static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
- [HPD_CRT] = CRT_HOTPLUG_INT_EN,
- [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
- [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
- [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN,
- [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN,
- [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN,
-};
-
-static const u32 hpd_status_g4x[HPD_NUM_PINS] = {
- [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
- [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
- [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
- [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
- [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
- [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS,
-};
-
-static const u32 hpd_status_i915[HPD_NUM_PINS] = {
- [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
- [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
- [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
- [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
- [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
- [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS,
-};
-
-static const u32 hpd_bxt[HPD_NUM_PINS] = {
- [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A),
- [HPD_PORT_B] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_B),
- [HPD_PORT_C] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_C),
-};
-
-static const u32 hpd_gen11[HPD_NUM_PINS] = {
- [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(HPD_PORT_TC1) | GEN11_TBT_HOTPLUG(HPD_PORT_TC1),
- [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(HPD_PORT_TC2) | GEN11_TBT_HOTPLUG(HPD_PORT_TC2),
- [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(HPD_PORT_TC3) | GEN11_TBT_HOTPLUG(HPD_PORT_TC3),
- [HPD_PORT_TC4] = GEN11_TC_HOTPLUG(HPD_PORT_TC4) | GEN11_TBT_HOTPLUG(HPD_PORT_TC4),
- [HPD_PORT_TC5] = GEN11_TC_HOTPLUG(HPD_PORT_TC5) | GEN11_TBT_HOTPLUG(HPD_PORT_TC5),
- [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(HPD_PORT_TC6) | GEN11_TBT_HOTPLUG(HPD_PORT_TC6),
-};
-
-static const u32 hpd_icp[HPD_NUM_PINS] = {
- [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A),
- [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B),
- [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C),
- [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC1),
- [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC2),
- [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC3),
- [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC4),
- [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC5),
- [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC6),
-};
-
-static const u32 hpd_sde_dg1[HPD_NUM_PINS] = {
- [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A),
- [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B),
- [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C),
- [HPD_PORT_D] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_D),
- [HPD_PORT_TC1] = SDE_TC_HOTPLUG_DG2(HPD_PORT_TC1),
-};
-
-static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
-{
- struct intel_hotplug *hpd = &dev_priv->display.hotplug;
-
- if (HAS_GMCH(dev_priv)) {
- if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
- IS_CHERRYVIEW(dev_priv))
- hpd->hpd = hpd_status_g4x;
- else
- hpd->hpd = hpd_status_i915;
- return;
- }
-
- if (DISPLAY_VER(dev_priv) >= 11)
- hpd->hpd = hpd_gen11;
- else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))
- hpd->hpd = hpd_bxt;
- else if (DISPLAY_VER(dev_priv) == 9)
- hpd->hpd = NULL; /* no north HPD on SKL */
- else if (DISPLAY_VER(dev_priv) >= 8)
- hpd->hpd = hpd_bdw;
- else if (DISPLAY_VER(dev_priv) >= 7)
- hpd->hpd = hpd_ivb;
- else
- hpd->hpd = hpd_ilk;
-
- if ((INTEL_PCH_TYPE(dev_priv) < PCH_DG1) &&
- (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv)))
- return;
-
- if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1)
- hpd->pch_hpd = hpd_sde_dg1;
- else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
- hpd->pch_hpd = hpd_icp;
- else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv))
- hpd->pch_hpd = hpd_spt;
- else if (HAS_PCH_LPT(dev_priv) || HAS_PCH_CPT(dev_priv))
- hpd->pch_hpd = hpd_cpt;
- else if (HAS_PCH_IBX(dev_priv))
- hpd->pch_hpd = hpd_ibx;
- else
- MISSING_CASE(INTEL_PCH_TYPE(dev_priv));
-}
-
-static void
-intel_handle_vblank(struct drm_i915_private *dev_priv, enum pipe pipe)
-{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
-
- drm_crtc_handle_vblank(&crtc->base);
-}
-
void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
i915_reg_t iir, i915_reg_t ier)
{
@@ -266,7 +110,7 @@ static void gen2_irq_reset(struct intel_uncore *uncore)
/*
* We should clear IMR at preinstall/uninstall, and just check at postinstall.
*/
-static void gen3_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg)
+void gen3_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg)
{
u32 val = intel_uncore_read(uncore, reg);
@@ -320,302 +164,6 @@ static void gen2_irq_init(struct intel_uncore *uncore,
intel_uncore_posting_read16(uncore, GEN2_IMR);
}
-/* For display hotplug interrupt */
-static inline void
-i915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv,
- u32 mask,
- u32 bits)
-{
- lockdep_assert_held(&dev_priv->irq_lock);
- drm_WARN_ON(&dev_priv->drm, bits & ~mask);
-
- intel_uncore_rmw(&dev_priv->uncore, PORT_HOTPLUG_EN, mask, bits);
-}
-
-/**
- * i915_hotplug_interrupt_update - update hotplug interrupt enable
- * @dev_priv: driver private
- * @mask: bits to update
- * @bits: bits to enable
- * NOTE: the HPD enable bits are modified both inside and outside
- * of an interrupt context. To avoid that read-modify-write cycles
- * interfer, these bits are protected by a spinlock. Since this
- * function is usually not called from a context where the lock is
- * held already, this function acquires the lock itself. A non-locking
- * version is also available.
- */
-void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
- u32 mask,
- u32 bits)
-{
- spin_lock_irq(&dev_priv->irq_lock);
- i915_hotplug_interrupt_update_locked(dev_priv, mask, bits);
- spin_unlock_irq(&dev_priv->irq_lock);
-}
-
-/**
- * ilk_update_display_irq - update DEIMR
- * @dev_priv: driver private
- * @interrupt_mask: mask of interrupt bits to update
- * @enabled_irq_mask: mask of interrupt bits to enable
- */
-static void ilk_update_display_irq(struct drm_i915_private *dev_priv,
- u32 interrupt_mask, u32 enabled_irq_mask)
-{
- u32 new_val;
-
- lockdep_assert_held(&dev_priv->irq_lock);
- drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
-
- new_val = dev_priv->irq_mask;
- new_val &= ~interrupt_mask;
- new_val |= (~enabled_irq_mask & interrupt_mask);
-
- if (new_val != dev_priv->irq_mask &&
- !drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv))) {
- dev_priv->irq_mask = new_val;
- intel_uncore_write(&dev_priv->uncore, DEIMR, dev_priv->irq_mask);
- intel_uncore_posting_read(&dev_priv->uncore, DEIMR);
- }
-}
-
-void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits)
-{
- ilk_update_display_irq(i915, bits, bits);
-}
-
-void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits)
-{
- ilk_update_display_irq(i915, bits, 0);
-}
-
-/**
- * bdw_update_port_irq - update DE port interrupt
- * @dev_priv: driver private
- * @interrupt_mask: mask of interrupt bits to update
- * @enabled_irq_mask: mask of interrupt bits to enable
- */
-static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
- u32 interrupt_mask,
- u32 enabled_irq_mask)
-{
- u32 new_val;
- u32 old_val;
-
- lockdep_assert_held(&dev_priv->irq_lock);
-
- drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
-
- if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
- return;
-
- old_val = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PORT_IMR);
-
- new_val = old_val;
- new_val &= ~interrupt_mask;
- new_val |= (~enabled_irq_mask & interrupt_mask);
-
- if (new_val != old_val) {
- intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IMR, new_val);
- intel_uncore_posting_read(&dev_priv->uncore, GEN8_DE_PORT_IMR);
- }
-}
-
-/**
- * bdw_update_pipe_irq - update DE pipe interrupt
- * @dev_priv: driver private
- * @pipe: pipe whose interrupt to update
- * @interrupt_mask: mask of interrupt bits to update
- * @enabled_irq_mask: mask of interrupt bits to enable
- */
-static void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
- enum pipe pipe, u32 interrupt_mask,
- u32 enabled_irq_mask)
-{
- u32 new_val;
-
- lockdep_assert_held(&dev_priv->irq_lock);
-
- drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
-
- if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
- return;
-
- new_val = dev_priv->de_irq_mask[pipe];
- new_val &= ~interrupt_mask;
- new_val |= (~enabled_irq_mask & interrupt_mask);
-
- if (new_val != dev_priv->de_irq_mask[pipe]) {
- dev_priv->de_irq_mask[pipe] = new_val;
- intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
- intel_uncore_posting_read(&dev_priv->uncore, GEN8_DE_PIPE_IMR(pipe));
- }
-}
-
-void bdw_enable_pipe_irq(struct drm_i915_private *i915,
- enum pipe pipe, u32 bits)
-{
- bdw_update_pipe_irq(i915, pipe, bits, bits);
-}
-
-void bdw_disable_pipe_irq(struct drm_i915_private *i915,
- enum pipe pipe, u32 bits)
-{
- bdw_update_pipe_irq(i915, pipe, bits, 0);
-}
-
-/**
- * ibx_display_interrupt_update - update SDEIMR
- * @dev_priv: driver private
- * @interrupt_mask: mask of interrupt bits to update
- * @enabled_irq_mask: mask of interrupt bits to enable
- */
-static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
- u32 interrupt_mask,
- u32 enabled_irq_mask)
-{
- u32 sdeimr = intel_uncore_read(&dev_priv->uncore, SDEIMR);
- sdeimr &= ~interrupt_mask;
- sdeimr |= (~enabled_irq_mask & interrupt_mask);
-
- drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
-
- lockdep_assert_held(&dev_priv->irq_lock);
-
- if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
- return;
-
- intel_uncore_write(&dev_priv->uncore, SDEIMR, sdeimr);
- intel_uncore_posting_read(&dev_priv->uncore, SDEIMR);
-}
-
-void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits)
-{
- ibx_display_interrupt_update(i915, bits, bits);
-}
-
-void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits)
-{
- ibx_display_interrupt_update(i915, bits, 0);
-}
-
-u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
- enum pipe pipe)
-{
- u32 status_mask = dev_priv->pipestat_irq_mask[pipe];
- u32 enable_mask = status_mask << 16;
-
- lockdep_assert_held(&dev_priv->irq_lock);
-
- if (DISPLAY_VER(dev_priv) < 5)
- goto out;
-
- /*
- * On pipe A we don't support the PSR interrupt yet,
- * on pipe B and C the same bit MBZ.
- */
- if (drm_WARN_ON_ONCE(&dev_priv->drm,
- status_mask & PIPE_A_PSR_STATUS_VLV))
- return 0;
- /*
- * On pipe B and C we don't support the PSR interrupt yet, on pipe
- * A the same bit is for perf counters which we don't use either.
- */
- if (drm_WARN_ON_ONCE(&dev_priv->drm,
- status_mask & PIPE_B_PSR_STATUS_VLV))
- return 0;
-
- enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS |
- SPRITE0_FLIP_DONE_INT_EN_VLV |
- SPRITE1_FLIP_DONE_INT_EN_VLV);
- if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV)
- enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV;
- if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
- enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
-
-out:
- drm_WARN_ONCE(&dev_priv->drm,
- enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
- status_mask & ~PIPESTAT_INT_STATUS_MASK,
- "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
- pipe_name(pipe), enable_mask, status_mask);
-
- return enable_mask;
-}
-
-void i915_enable_pipestat(struct drm_i915_private *dev_priv,
- enum pipe pipe, u32 status_mask)
-{
- i915_reg_t reg = PIPESTAT(pipe);
- u32 enable_mask;
-
- drm_WARN_ONCE(&dev_priv->drm, status_mask & ~PIPESTAT_INT_STATUS_MASK,
- "pipe %c: status_mask=0x%x\n",
- pipe_name(pipe), status_mask);
-
- lockdep_assert_held(&dev_priv->irq_lock);
- drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv));
-
- if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == status_mask)
- return;
-
- dev_priv->pipestat_irq_mask[pipe] |= status_mask;
- enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
-
- intel_uncore_write(&dev_priv->uncore, reg, enable_mask | status_mask);
- intel_uncore_posting_read(&dev_priv->uncore, reg);
-}
-
-void i915_disable_pipestat(struct drm_i915_private *dev_priv,
- enum pipe pipe, u32 status_mask)
-{
- i915_reg_t reg = PIPESTAT(pipe);
- u32 enable_mask;
-
- drm_WARN_ONCE(&dev_priv->drm, status_mask & ~PIPESTAT_INT_STATUS_MASK,
- "pipe %c: status_mask=0x%x\n",
- pipe_name(pipe), status_mask);
-
- lockdep_assert_held(&dev_priv->irq_lock);
- drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv));
-
- if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == 0)
- return;
-
- dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
- enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
-
- intel_uncore_write(&dev_priv->uncore, reg, enable_mask | status_mask);
- intel_uncore_posting_read(&dev_priv->uncore, reg);
-}
-
-static bool i915_has_asle(struct drm_i915_private *dev_priv)
-{
- if (!dev_priv->display.opregion.asle)
- return false;
-
- return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv);
-}
-
-/**
- * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
- * @dev_priv: i915 device private
- */
-static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
-{
- if (!i915_has_asle(dev_priv))
- return;
-
- spin_lock_irq(&dev_priv->irq_lock);
-
- i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
- if (DISPLAY_VER(dev_priv) >= 4)
- i915_enable_pipestat(dev_priv, PIPE_A,
- PIPE_LEGACY_BLC_EVENT_STATUS);
-
- spin_unlock_irq(&dev_priv->irq_lock);
-}
-
/**
* ivb_parity_work - Workqueue called when a parity error interrupt
* occurred.
@@ -700,544 +248,6 @@ out:
mutex_unlock(&dev_priv->drm.struct_mutex);
}
-static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_TC1:
- case HPD_PORT_TC2:
- case HPD_PORT_TC3:
- case HPD_PORT_TC4:
- case HPD_PORT_TC5:
- case HPD_PORT_TC6:
- return val & GEN11_HOTPLUG_CTL_LONG_DETECT(pin);
- default:
- return false;
- }
-}
-
-static bool bxt_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_A:
- return val & PORTA_HOTPLUG_LONG_DETECT;
- case HPD_PORT_B:
- return val & PORTB_HOTPLUG_LONG_DETECT;
- case HPD_PORT_C:
- return val & PORTC_HOTPLUG_LONG_DETECT;
- default:
- return false;
- }
-}
-
-static bool icp_ddi_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_A:
- case HPD_PORT_B:
- case HPD_PORT_C:
- case HPD_PORT_D:
- return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(pin);
- default:
- return false;
- }
-}
-
-static bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_TC1:
- case HPD_PORT_TC2:
- case HPD_PORT_TC3:
- case HPD_PORT_TC4:
- case HPD_PORT_TC5:
- case HPD_PORT_TC6:
- return val & ICP_TC_HPD_LONG_DETECT(pin);
- default:
- return false;
- }
-}
-
-static bool spt_port_hotplug2_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_E:
- return val & PORTE_HOTPLUG_LONG_DETECT;
- default:
- return false;
- }
-}
-
-static bool spt_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_A:
- return val & PORTA_HOTPLUG_LONG_DETECT;
- case HPD_PORT_B:
- return val & PORTB_HOTPLUG_LONG_DETECT;
- case HPD_PORT_C:
- return val & PORTC_HOTPLUG_LONG_DETECT;
- case HPD_PORT_D:
- return val & PORTD_HOTPLUG_LONG_DETECT;
- default:
- return false;
- }
-}
-
-static bool ilk_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_A:
- return val & DIGITAL_PORTA_HOTPLUG_LONG_DETECT;
- default:
- return false;
- }
-}
-
-static bool pch_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_B:
- return val & PORTB_HOTPLUG_LONG_DETECT;
- case HPD_PORT_C:
- return val & PORTC_HOTPLUG_LONG_DETECT;
- case HPD_PORT_D:
- return val & PORTD_HOTPLUG_LONG_DETECT;
- default:
- return false;
- }
-}
-
-static bool i9xx_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
-{
- switch (pin) {
- case HPD_PORT_B:
- return val & PORTB_HOTPLUG_INT_LONG_PULSE;
- case HPD_PORT_C:
- return val & PORTC_HOTPLUG_INT_LONG_PULSE;
- case HPD_PORT_D:
- return val & PORTD_HOTPLUG_INT_LONG_PULSE;
- default:
- return false;
- }
-}
-
-/*
- * Get a bit mask of pins that have triggered, and which ones may be long.
- * This can be called multiple times with the same masks to accumulate
- * hotplug detection results from several registers.
- *
- * Note that the caller is expected to zero out the masks initially.
- */
-static void intel_get_hpd_pins(struct drm_i915_private *dev_priv,
- u32 *pin_mask, u32 *long_mask,
- u32 hotplug_trigger, u32 dig_hotplug_reg,
- const u32 hpd[HPD_NUM_PINS],
- bool long_pulse_detect(enum hpd_pin pin, u32 val))
-{
- enum hpd_pin pin;
-
- BUILD_BUG_ON(BITS_PER_TYPE(*pin_mask) < HPD_NUM_PINS);
-
- for_each_hpd_pin(pin) {
- if ((hpd[pin] & hotplug_trigger) == 0)
- continue;
-
- *pin_mask |= BIT(pin);
-
- if (long_pulse_detect(pin, dig_hotplug_reg))
- *long_mask |= BIT(pin);
- }
-
- drm_dbg(&dev_priv->drm,
- "hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x, long 0x%08x\n",
- hotplug_trigger, dig_hotplug_reg, *pin_mask, *long_mask);
-
-}
-
-static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
- const u32 hpd[HPD_NUM_PINS])
-{
- struct intel_encoder *encoder;
- u32 enabled_irqs = 0;
-
- for_each_intel_encoder(&dev_priv->drm, encoder)
- if (dev_priv->display.hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
- enabled_irqs |= hpd[encoder->hpd_pin];
-
- return enabled_irqs;
-}
-
-static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv,
- const u32 hpd[HPD_NUM_PINS])
-{
- struct intel_encoder *encoder;
- u32 hotplug_irqs = 0;
-
- for_each_intel_encoder(&dev_priv->drm, encoder)
- hotplug_irqs |= hpd[encoder->hpd_pin];
-
- return hotplug_irqs;
-}
-
-static u32 intel_hpd_hotplug_enables(struct drm_i915_private *i915,
- hotplug_enables_func hotplug_enables)
-{
- struct intel_encoder *encoder;
- u32 hotplug = 0;
-
- for_each_intel_encoder(&i915->drm, encoder)
- hotplug |= hotplug_enables(encoder);
-
- return hotplug;
-}
-
-static void gmbus_irq_handler(struct drm_i915_private *dev_priv)
-{
- wake_up_all(&dev_priv->display.gmbus.wait_queue);
-}
-
-static void dp_aux_irq_handler(struct drm_i915_private *dev_priv)
-{
- wake_up_all(&dev_priv->display.gmbus.wait_queue);
-}
-
-#if defined(CONFIG_DEBUG_FS)
-static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
- enum pipe pipe,
- u32 crc0, u32 crc1,
- u32 crc2, u32 crc3,
- u32 crc4)
-{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
- struct intel_pipe_crc *pipe_crc = &crtc->pipe_crc;
- u32 crcs[5] = { crc0, crc1, crc2, crc3, crc4 };
-
- trace_intel_pipe_crc(crtc, crcs);
-
- spin_lock(&pipe_crc->lock);
- /*
- * For some not yet identified reason, the first CRC is
- * bonkers. So let's just wait for the next vblank and read
- * out the buggy result.
- *
- * On GEN8+ sometimes the second CRC is bonkers as well, so
- * don't trust that one either.
- */
- if (pipe_crc->skipped <= 0 ||
- (DISPLAY_VER(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
- pipe_crc->skipped++;
- spin_unlock(&pipe_crc->lock);
- return;
- }
- spin_unlock(&pipe_crc->lock);
-
- drm_crtc_add_crc_entry(&crtc->base, true,
- drm_crtc_accurate_vblank_count(&crtc->base),
- crcs);
-}
-#else
-static inline void
-display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
- enum pipe pipe,
- u32 crc0, u32 crc1,
- u32 crc2, u32 crc3,
- u32 crc4) {}
-#endif
-
-static void flip_done_handler(struct drm_i915_private *i915,
- enum pipe pipe)
-{
- struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe);
- struct drm_crtc_state *crtc_state = crtc->base.state;
- struct drm_pending_vblank_event *e = crtc_state->event;
- struct drm_device *dev = &i915->drm;
- unsigned long irqflags;
-
- spin_lock_irqsave(&dev->event_lock, irqflags);
-
- crtc_state->event = NULL;
-
- drm_crtc_send_vblank_event(&crtc->base, e);
-
- spin_unlock_irqrestore(&dev->event_lock, irqflags);
-}
-
-static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
- enum pipe pipe)
-{
- display_pipe_crc_irq_handler(dev_priv, pipe,
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_1_IVB(pipe)),
- 0, 0, 0, 0);
-}
-
-static void ivb_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
- enum pipe pipe)
-{
- display_pipe_crc_irq_handler(dev_priv, pipe,
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_1_IVB(pipe)),
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_2_IVB(pipe)),
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_3_IVB(pipe)),
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_4_IVB(pipe)),
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_5_IVB(pipe)));
-}
-
-static void i9xx_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
- enum pipe pipe)
-{
- u32 res1, res2;
-
- if (DISPLAY_VER(dev_priv) >= 3)
- res1 = intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_RES1_I915(pipe));
- else
- res1 = 0;
-
- if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))
- res2 = intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_RES2_G4X(pipe));
- else
- res2 = 0;
-
- display_pipe_crc_irq_handler(dev_priv, pipe,
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_RED(pipe)),
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_GREEN(pipe)),
- intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_BLUE(pipe)),
- res1, res2);
-}
-
-static void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv)
-{
- enum pipe pipe;
-
- for_each_pipe(dev_priv, pipe) {
- intel_uncore_write(&dev_priv->uncore, PIPESTAT(pipe),
- PIPESTAT_INT_STATUS_MASK |
- PIPE_FIFO_UNDERRUN_STATUS);
-
- dev_priv->pipestat_irq_mask[pipe] = 0;
- }
-}
-
-static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
- u32 iir, u32 pipe_stats[I915_MAX_PIPES])
-{
- enum pipe pipe;
-
- spin_lock(&dev_priv->irq_lock);
-
- if (!dev_priv->display_irqs_enabled) {
- spin_unlock(&dev_priv->irq_lock);
- return;
- }
-
- for_each_pipe(dev_priv, pipe) {
- i915_reg_t reg;
- u32 status_mask, enable_mask, iir_bit = 0;
-
- /*
- * PIPESTAT bits get signalled even when the interrupt is
- * disabled with the mask bits, and some of the status bits do
- * not generate interrupts at all (like the underrun bit). Hence
- * we need to be careful that we only handle what we want to
- * handle.
- */
-
- /* fifo underruns are filterered in the underrun handler. */
- status_mask = PIPE_FIFO_UNDERRUN_STATUS;
-
- switch (pipe) {
- default:
- case PIPE_A:
- iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
- break;
- case PIPE_B:
- iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
- break;
- case PIPE_C:
- iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
- break;
- }
- if (iir & iir_bit)
- status_mask |= dev_priv->pipestat_irq_mask[pipe];
-
- if (!status_mask)
- continue;
-
- reg = PIPESTAT(pipe);
- pipe_stats[pipe] = intel_uncore_read(&dev_priv->uncore, reg) & status_mask;
- enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
-
- /*
- * Clear the PIPE*STAT regs before the IIR
- *
- * Toggle the enable bits to make sure we get an
- * edge in the ISR pipe event bit if we don't clear
- * all the enabled status bits. Otherwise the edge
- * triggered IIR on i965/g4x wouldn't notice that
- * an interrupt is still pending.
- */
- if (pipe_stats[pipe]) {
- intel_uncore_write(&dev_priv->uncore, reg, pipe_stats[pipe]);
- intel_uncore_write(&dev_priv->uncore, reg, enable_mask);
- }
- }
- spin_unlock(&dev_priv->irq_lock);
-}
-
-static void i8xx_pipestat_irq_handler(struct drm_i915_private *dev_priv,
- u16 iir, u32 pipe_stats[I915_MAX_PIPES])
-{
- enum pipe pipe;
-
- for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
- intel_handle_vblank(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
- i9xx_pipe_crc_irq_handler(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
- }
-}
-
-static void i915_pipestat_irq_handler(struct drm_i915_private *dev_priv,
- u32 iir, u32 pipe_stats[I915_MAX_PIPES])
-{
- bool blc_event = false;
- enum pipe pipe;
-
- for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
- intel_handle_vblank(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
- blc_event = true;
-
- if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
- i9xx_pipe_crc_irq_handler(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
- }
-
- if (blc_event || (iir & I915_ASLE_INTERRUPT))
- intel_opregion_asle_intr(dev_priv);
-}
-
-static void i965_pipestat_irq_handler(struct drm_i915_private *dev_priv,
- u32 iir, u32 pipe_stats[I915_MAX_PIPES])
-{
- bool blc_event = false;
- enum pipe pipe;
-
- for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
- intel_handle_vblank(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
- blc_event = true;
-
- if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
- i9xx_pipe_crc_irq_handler(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
- }
-
- if (blc_event || (iir & I915_ASLE_INTERRUPT))
- intel_opregion_asle_intr(dev_priv);
-
- if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
- gmbus_irq_handler(dev_priv);
-}
-
-static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
- u32 pipe_stats[I915_MAX_PIPES])
-{
- enum pipe pipe;
-
- for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
- intel_handle_vblank(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
- flip_done_handler(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
- i9xx_pipe_crc_irq_handler(dev_priv, pipe);
-
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
- }
-
- if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
- gmbus_irq_handler(dev_priv);
-}
-
-static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv)
-{
- u32 hotplug_status = 0, hotplug_status_mask;
- int i;
-
- if (IS_G4X(dev_priv) ||
- IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- hotplug_status_mask = HOTPLUG_INT_STATUS_G4X |
- DP_AUX_CHANNEL_MASK_INT_STATUS_G4X;
- else
- hotplug_status_mask = HOTPLUG_INT_STATUS_I915;
-
- /*
- * We absolutely have to clear all the pending interrupt
- * bits in PORT_HOTPLUG_STAT. Otherwise the ISR port
- * interrupt bit won't have an edge, and the i965/g4x
- * edge triggered IIR will not notice that an interrupt
- * is still pending. We can't use PORT_HOTPLUG_EN to
- * guarantee the edge as the act of toggling the enable
- * bits can itself generate a new hotplug interrupt :(
- */
- for (i = 0; i < 10; i++) {
- u32 tmp = intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT) & hotplug_status_mask;
-
- if (tmp == 0)
- return hotplug_status;
-
- hotplug_status |= tmp;
- intel_uncore_write(&dev_priv->uncore, PORT_HOTPLUG_STAT, hotplug_status);
- }
-
- drm_WARN_ONCE(&dev_priv->drm, 1,
- "PORT_HOTPLUG_STAT did not clear (0x%08x)\n",
- intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT));
-
- return hotplug_status;
-}
-
-static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
- u32 hotplug_status)
-{
- u32 pin_mask = 0, long_mask = 0;
- u32 hotplug_trigger;
-
- if (IS_G4X(dev_priv) ||
- IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
- else
- hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
-
- if (hotplug_trigger) {
- intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
- hotplug_trigger, hotplug_trigger,
- dev_priv->display.hotplug.hpd,
- i9xx_port_hotplug_long_detect);
-
- intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
- }
-
- if ((IS_G4X(dev_priv) ||
- IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
- hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
- dp_aux_irq_handler(dev_priv);
-}
-
static irqreturn_t valleyview_irq_handler(int irq, void *arg)
{
struct drm_i915_private *dev_priv = arg;
@@ -1402,338 +412,6 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
return ret;
}
-static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv,
- u32 hotplug_trigger)
-{
- u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
-
- /*
- * Somehow the PCH doesn't seem to really ack the interrupt to the CPU
- * unless we touch the hotplug register, even if hotplug_trigger is
- * zero. Not acking leads to "The master control interrupt lied (SDE)!"
- * errors.
- */
- dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG);
- if (!hotplug_trigger) {
- u32 mask = PORTA_HOTPLUG_STATUS_MASK |
- PORTD_HOTPLUG_STATUS_MASK |
- PORTC_HOTPLUG_STATUS_MASK |
- PORTB_HOTPLUG_STATUS_MASK;
- dig_hotplug_reg &= ~mask;
- }
-
- intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, dig_hotplug_reg);
- if (!hotplug_trigger)
- return;
-
- intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
- hotplug_trigger, dig_hotplug_reg,
- dev_priv->display.hotplug.pch_hpd,
- pch_port_hotplug_long_detect);
-
- intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
-}
-
-static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
-{
- enum pipe pipe;
- u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
-
- ibx_hpd_irq_handler(dev_priv, hotplug_trigger);
-
- if (pch_iir & SDE_AUDIO_POWER_MASK) {
- int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
- SDE_AUDIO_POWER_SHIFT);
- drm_dbg(&dev_priv->drm, "PCH audio power change on port %d\n",
- port_name(port));
- }
-
- if (pch_iir & SDE_AUX_MASK)
- dp_aux_irq_handler(dev_priv);
-
- if (pch_iir & SDE_GMBUS)
- gmbus_irq_handler(dev_priv);
-
- if (pch_iir & SDE_AUDIO_HDCP_MASK)
- drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n");