* [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void
@ 2023-05-12 10:23 Jani Nikula
2023-05-12 10:23 ` [Intel-gfx] [PATCH 2/3] drm/i915/irq: split out hotplug irq handling Jani Nikula
` (5 more replies)
0 siblings, 6 replies; 15+ messages in thread
From: Jani Nikula @ 2023-05-12 10:23 UTC (permalink / raw)
To: intel-gfx; +Cc: jani.nikula
The return value is not used for anything.
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
drivers/gpu/drm/i915/i915_irq.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 02b6cbb832e9..64cc52538206 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2124,10 +2124,8 @@ static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_i
intel_de_write(i915, PICAINTERRUPT_IER, pica_ier);
}
-static irqreturn_t
-gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
+static void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
{
- irqreturn_t ret = IRQ_NONE;
u32 iir;
enum pipe pipe;
@@ -2137,7 +2135,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR);
if (iir) {
intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir);
- ret = IRQ_HANDLED;
gen8_de_misc_irq_handler(dev_priv, iir);
} else {
drm_err_ratelimited(&dev_priv->drm,
@@ -2149,7 +2146,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR);
if (iir) {
intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir);
- ret = IRQ_HANDLED;
gen11_hpd_irq_handler(dev_priv, iir);
} else {
drm_err_ratelimited(&dev_priv->drm,
@@ -2163,7 +2159,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
bool found = false;
intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir);
- ret = IRQ_HANDLED;
if (iir & gen8_de_port_aux_mask(dev_priv)) {
intel_dp_aux_irq_handler(dev_priv);
@@ -2223,7 +2218,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
continue;
}
- ret = IRQ_HANDLED;
intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir);
if (iir & GEN8_PIPE_VBLANK)
@@ -2257,8 +2251,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
*/
gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir);
if (iir) {
- ret = IRQ_HANDLED;
-
if (pica_iir)
xelpdp_pica_irq_handler(dev_priv, pica_iir);
@@ -2277,8 +2269,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
"The master control interrupt lied (SDE)!\n");
}
}
-
- return ret;
}
static inline u32 gen8_master_intr_disable(void __iomem * const regs)
--
2.39.2
^ permalink raw reply related [flat|nested] 15+ messages in thread* [Intel-gfx] [PATCH 2/3] drm/i915/irq: split out hotplug irq handling 2023-05-12 10:23 [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Jani Nikula @ 2023-05-12 10:23 ` Jani Nikula 2023-05-12 10:23 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display " Jani Nikula ` (4 subsequent siblings) 5 siblings, 0 replies; 15+ messages in thread From: Jani Nikula @ 2023-05-12 10:23 UTC (permalink / raw) To: intel-gfx; +Cc: jani.nikula, Rodrigo Vivi Split hotplug irq handling out of i915_irq.[ch] into display/intel_hotplug_irq.[ch]. The line between the new intel_hotplug_irq.[ch] and the existing intel_hotplug.[ch] needs further clarification, but the first step is to move the stuff out of i915_irq.[ch]. Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_crt.c | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 1 + drivers/gpu/drm/i915/display/intel_hotplug.c | 1 + .../gpu/drm/i915/display/intel_hotplug_irq.c | 1442 ++++++++++++++++ .../gpu/drm/i915/display/intel_hotplug_irq.h | 35 + drivers/gpu/drm/i915/i915_irq.c | 1504 +---------------- drivers/gpu/drm/i915/i915_irq.h | 12 +- 8 files changed, 1525 insertions(+), 1472 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_hotplug_irq.c create mode 100644 drivers/gpu/drm/i915/display/intel_hotplug_irq.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7587fe856e67..7f7569c5f9a9 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -261,6 +261,7 @@ i915-y += \ display/intel_hdcp.o \ display/intel_hdcp_gsc.o \ display/intel_hotplug.o \ + display/intel_hotplug_irq.o \ display/intel_hti.o \ display/intel_load_detect.o \ display/intel_lpe_audio.o \ diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index f0f4897b3c3c..673c03646696 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -48,6 +48,7 @@ #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hotplug.h" +#include "intel_hotplug_irq.h" #include "intel_load_detect.h" #include "intel_pch_display.h" #include "intel_pch_refclk.h" diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0cc57681dc4d..b35ab251f543 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -68,6 +68,7 @@ #include "intel_hdcp.h" #include "intel_hdmi.h" #include "intel_hotplug.h" +#include "intel_hotplug_irq.h" #include "intel_lspcon.h" #include "intel_lvds.h" #include "intel_panel.h" diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index b12900446828..23a5e1a875f1 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -27,6 +27,7 @@ #include "i915_irq.h" #include "intel_display_types.h" #include "intel_hotplug.h" +#include "intel_hotplug_irq.h" /** * DOC: Hotplug diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c new file mode 100644 index 000000000000..1d7ae49e073e --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -0,0 +1,1442 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" +#include "i915_irq.h" +#include "i915_reg.h" +#include "intel_de.h" +#include "intel_display_types.h" +#include "intel_dp_aux.h" +#include "intel_gmbus.h" +#include "intel_hotplug.h" +#include "intel_hotplug_irq.h" + +typedef bool (*long_pulse_detect_func)(enum hpd_pin pin, u32 val); +typedef u32 (*hotplug_enables_func)(struct intel_encoder *encoder); +typedef u32 (*hotplug_mask_func)(enum hpd_pin pin); + +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_xelpdp[HPD_NUM_PINS] = { + [HPD_PORT_TC1] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC1) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC1), + [HPD_PORT_TC2] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC2) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC2), + [HPD_PORT_TC3] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC3) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC3), + [HPD_PORT_TC4] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC4) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC4), +}; + +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 const u32 hpd_mtp[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_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), +}; + +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) >= 14) + hpd->hpd = hpd_xelpdp; + else 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_MTP) + hpd->pch_hpd = hpd_mtp; + 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)); +} + +/* For display hotplug interrupt */ +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); +} + +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_mask(struct drm_i915_private *i915, + hotplug_mask_func hotplug_mask) +{ + enum hpd_pin pin; + u32 hotplug = 0; + + for_each_hpd_pin(pin) + hotplug |= hotplug_mask(pin); + + return hotplug; +} + +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; +} + +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; +} + +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) + intel_dp_aux_irq_handler(dev_priv); +} + +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); +} + +void xelpdp_pica_irq_handler(struct drm_i915_private *i915, u32 iir) +{ + enum hpd_pin pin; + u32 hotplug_trigger = iir & (XELPDP_DP_ALT_HOTPLUG_MASK | XELPDP_TBT_HOTPLUG_MASK); + u32 trigger_aux = iir & XELPDP_AUX_TC_MASK; + u32 pin_mask = 0, long_mask = 0; + + for (pin = HPD_PORT_TC1; pin <= HPD_PORT_TC4; pin++) { + u32 val; + + if (!(i915->display.hotplug.hpd[pin] & hotplug_trigger)) + continue; + + pin_mask |= BIT(pin); + + val = intel_de_read(i915, XELPDP_PORT_HOTPLUG_CTL(pin)); + intel_de_write(i915, XELPDP_PORT_HOTPLUG_CTL(pin), val); + + if (val & (XELPDP_DP_ALT_HPD_LONG_DETECT | XELPDP_TBT_HPD_LONG_DETECT)) + long_mask |= BIT(pin); + } + + if (pin_mask) { + drm_dbg(&i915->drm, + "pica hotplug event received, stat 0x%08x, pins 0x%08x, long 0x%08x\n", + hotplug_trigger, pin_mask, long_mask); + + intel_hpd_irq_handler(i915, pin_mask, long_mask); + } + + if (trigger_aux) + intel_dp_aux_irq_handler(i915); + + if (!pin_mask && !trigger_aux) + drm_err(&i915->drm, + "Unexpected DE HPD/AUX interrupt 0x%08x\n", iir); +} + +void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) +{ + u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_HOTPLUG_MASK_ICP; + u32 tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_MASK_ICP; + u32 pin_mask = 0, long_mask = 0; + + if (ddi_hotplug_trigger) { + u32 dig_hotplug_reg; + + /* Locking due to DSI native GPIO sequences */ + spin_lock(&dev_priv->irq_lock); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, 0, 0); + spin_unlock(&dev_priv->irq_lock); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + ddi_hotplug_trigger, dig_hotplug_reg, + dev_priv->display.hotplug.pch_hpd, + icp_ddi_port_hotplug_long_detect); + } + + if (tc_hotplug_trigger) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC, 0, 0); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + tc_hotplug_trigger, dig_hotplug_reg, + dev_priv->display.hotplug.pch_hpd, + icp_tc_port_hotplug_long_detect); + } + + if (pin_mask) + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); + + if (pch_iir & SDE_GMBUS_ICP) + intel_gmbus_irq_handler(dev_priv); +} + +void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) +{ + u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT & + ~SDE_PORTE_HOTPLUG_SPT; + u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT; + u32 pin_mask = 0, long_mask = 0; + + if (hotplug_trigger) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug_trigger, dig_hotplug_reg, + dev_priv->display.hotplug.pch_hpd, + spt_port_hotplug_long_detect); + } + + if (hotplug2_trigger) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, 0, 0); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug2_trigger, dig_hotplug_reg, + dev_priv->display.hotplug.pch_hpd, + spt_port_hotplug2_long_detect); + } + + if (pin_mask) + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); + + if (pch_iir & SDE_GMBUS_CPT) + intel_gmbus_irq_handler(dev_priv); +} + +void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 hotplug_trigger) +{ + u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; + + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, 0, 0); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug_trigger, dig_hotplug_reg, + dev_priv->display.hotplug.hpd, + ilk_port_hotplug_long_detect); + + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); +} + +void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 hotplug_trigger) +{ + u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; + + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug_trigger, dig_hotplug_reg, + dev_priv->display.hotplug.hpd, + bxt_port_hotplug_long_detect); + + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); +} + +void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) +{ + u32 pin_mask = 0, long_mask = 0; + u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK; + u32 trigger_tbt = iir & GEN11_DE_TBT_HOTPLUG_MASK; + + if (trigger_tc) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, 0, 0); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + trigger_tc, dig_hotplug_reg, + dev_priv->display.hotplug.hpd, + gen11_port_hotplug_long_detect); + } + + if (trigger_tbt) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, 0, 0); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + trigger_tbt, dig_hotplug_reg, + dev_priv->display.hotplug.hpd, + gen11_port_hotplug_long_detect); + } + + if (pin_mask) + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); + else + drm_err(&dev_priv->drm, + "Unexpected DE HPD interrupt 0x%08x\n", iir); +} + +static u32 ibx_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_A: + return PORTA_HOTPLUG_ENABLE; + case HPD_PORT_B: + return PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_MASK; + case HPD_PORT_C: + return PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_MASK; + case HPD_PORT_D: + return PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_MASK; + default: + return 0; + } +} + +static u32 ibx_hotplug_enables(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + switch (encoder->hpd_pin) { + case HPD_PORT_A: + /* + * When CPU and PCH are on the same package, port A + * HPD must be enabled in both north and south. + */ + return HAS_PCH_LPT_LP(i915) ? + PORTA_HOTPLUG_ENABLE : 0; + case HPD_PORT_B: + return PORTB_HOTPLUG_ENABLE | + PORTB_PULSE_DURATION_2ms; + case HPD_PORT_C: + return PORTC_HOTPLUG_ENABLE | + PORTC_PULSE_DURATION_2ms; + case HPD_PORT_D: + return PORTD_HOTPLUG_ENABLE | + PORTD_PULSE_DURATION_2ms; + default: + return 0; + } +} + +static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + /* + * Enable digital hotplug on the PCH, and configure the DP short pulse + * duration to 2ms (which is the minimum in the Display Port spec). + * The pulse duration bits are reserved on LPT+. + */ + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, + intel_hpd_hotplug_mask(dev_priv, ibx_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables)); +} + +static void ibx_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG, + ibx_hotplug_mask(encoder->hpd_pin), + ibx_hotplug_enables(encoder)); +} + +static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + + ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); + + ibx_hpd_detection_setup(dev_priv); +} + +static u32 icp_ddi_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_A: + case HPD_PORT_B: + case HPD_PORT_C: + case HPD_PORT_D: + return SHOTPLUG_CTL_DDI_HPD_ENABLE(hpd_pin); + default: + return 0; + } +} + +static u32 icp_ddi_hotplug_enables(struct intel_encoder *encoder) +{ + return icp_ddi_hotplug_mask(encoder->hpd_pin); +} + +static u32 icp_tc_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_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 ICP_TC_HPD_ENABLE(hpd_pin); + default: + return 0; + } +} + +static u32 icp_tc_hotplug_enables(struct intel_encoder *encoder) +{ + return icp_tc_hotplug_mask(encoder->hpd_pin); +} + +static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, + intel_hpd_hotplug_mask(dev_priv, icp_ddi_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables)); +} + +static void icp_ddi_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_uncore_rmw(&i915->uncore, SHOTPLUG_CTL_DDI, + icp_ddi_hotplug_mask(encoder->hpd_pin), + icp_ddi_hotplug_enables(encoder)); +} + +static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC, + intel_hpd_hotplug_mask(dev_priv, icp_tc_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables)); +} + +static void icp_tc_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_uncore_rmw(&i915->uncore, SHOTPLUG_CTL_TC, + icp_tc_hotplug_mask(encoder->hpd_pin), + icp_tc_hotplug_enables(encoder)); +} + +static void icp_hpd_enable_detection(struct intel_encoder *encoder) +{ + icp_ddi_hpd_enable_detection(encoder); + icp_tc_hpd_enable_detection(encoder); +} + +static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + + if (INTEL_PCH_TYPE(dev_priv) <= PCH_TGP) + intel_uncore_write(&dev_priv->uncore, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); + + ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); + + icp_ddi_hpd_detection_setup(dev_priv); + icp_tc_hpd_detection_setup(dev_priv); +} + +static u32 gen11_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_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 GEN11_HOTPLUG_CTL_ENABLE(hpd_pin); + default: + return 0; + } +} + +static u32 gen11_hotplug_enables(struct intel_encoder *encoder) +{ + return gen11_hotplug_mask(encoder->hpd_pin); +} + +static void dg1_hpd_invert(struct drm_i915_private *i915) +{ + u32 val = (INVERT_DDIA_HPD | + INVERT_DDIB_HPD | + INVERT_DDIC_HPD | + INVERT_DDID_HPD); + intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN1, 0, val); +} + +static void dg1_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + dg1_hpd_invert(i915); + icp_hpd_enable_detection(encoder); +} + +static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + dg1_hpd_invert(dev_priv); + icp_hpd_irq_setup(dev_priv); +} + +static void gen11_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, + intel_hpd_hotplug_mask(dev_priv, gen11_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables)); +} + +static void gen11_tc_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_uncore_rmw(&i915->uncore, GEN11_TC_HOTPLUG_CTL, + gen11_hotplug_mask(encoder->hpd_pin), + gen11_hotplug_enables(encoder)); +} + +static void gen11_tbt_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, + intel_hpd_hotplug_mask(dev_priv, gen11_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables)); +} + +static void gen11_tbt_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_uncore_rmw(&i915->uncore, GEN11_TBT_HOTPLUG_CTL, + gen11_hotplug_mask(encoder->hpd_pin), + gen11_hotplug_enables(encoder)); +} + +static void gen11_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + gen11_tc_hpd_enable_detection(encoder); + gen11_tbt_hpd_enable_detection(encoder); + + if (INTEL_PCH_TYPE(i915) >= PCH_ICP) + icp_hpd_enable_detection(encoder); +} + +static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); + + intel_uncore_rmw(&dev_priv->uncore, GEN11_DE_HPD_IMR, hotplug_irqs, + ~enabled_irqs & hotplug_irqs); + intel_uncore_posting_read(&dev_priv->uncore, GEN11_DE_HPD_IMR); + + gen11_tc_hpd_detection_setup(dev_priv); + gen11_tbt_hpd_detection_setup(dev_priv); + + if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + icp_hpd_irq_setup(dev_priv); +} + +static u32 mtp_ddi_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_A: + case HPD_PORT_B: + return SHOTPLUG_CTL_DDI_HPD_ENABLE(hpd_pin); + default: + return 0; + } +} + +static u32 mtp_ddi_hotplug_enables(struct intel_encoder *encoder) +{ + return mtp_ddi_hotplug_mask(encoder->hpd_pin); +} + +static u32 mtp_tc_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_TC1: + case HPD_PORT_TC2: + case HPD_PORT_TC3: + case HPD_PORT_TC4: + return ICP_TC_HPD_ENABLE(hpd_pin); + default: + return 0; + } +} + +static u32 mtp_tc_hotplug_enables(struct intel_encoder *encoder) +{ + return mtp_tc_hotplug_mask(encoder->hpd_pin); +} + +static void mtp_ddi_hpd_detection_setup(struct drm_i915_private *i915) +{ + intel_de_rmw(i915, SHOTPLUG_CTL_DDI, + intel_hpd_hotplug_mask(i915, mtp_ddi_hotplug_mask), + intel_hpd_hotplug_enables(i915, mtp_ddi_hotplug_enables)); +} + +static void mtp_ddi_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_de_rmw(i915, SHOTPLUG_CTL_DDI, + mtp_ddi_hotplug_mask(encoder->hpd_pin), + mtp_ddi_hotplug_enables(encoder)); +} + +static void mtp_tc_hpd_detection_setup(struct drm_i915_private *i915) +{ + intel_de_rmw(i915, SHOTPLUG_CTL_TC, + intel_hpd_hotplug_mask(i915, mtp_tc_hotplug_mask), + intel_hpd_hotplug_enables(i915, mtp_tc_hotplug_enables)); +} + +static void mtp_tc_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_de_rmw(i915, SHOTPLUG_CTL_DDI, + mtp_tc_hotplug_mask(encoder->hpd_pin), + mtp_tc_hotplug_enables(encoder)); +} + +static void mtp_hpd_invert(struct drm_i915_private *i915) +{ + u32 val = (INVERT_DDIA_HPD | + INVERT_DDIB_HPD | + INVERT_DDIC_HPD | + INVERT_TC1_HPD | + INVERT_TC2_HPD | + INVERT_TC3_HPD | + INVERT_TC4_HPD | + INVERT_DDID_HPD_MTP | + INVERT_DDIE_HPD); + intel_de_rmw(i915, SOUTH_CHICKEN1, 0, val); +} + +static void mtp_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + mtp_hpd_invert(i915); + mtp_ddi_hpd_enable_detection(encoder); + mtp_tc_hpd_enable_detection(encoder); +} + +static void mtp_hpd_irq_setup(struct drm_i915_private *i915) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(i915, i915->display.hotplug.pch_hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(i915, i915->display.hotplug.pch_hpd); + + intel_de_write(i915, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); + + mtp_hpd_invert(i915); + ibx_display_interrupt_update(i915, hotplug_irqs, enabled_irqs); + + mtp_ddi_hpd_detection_setup(i915); + mtp_tc_hpd_detection_setup(i915); +} + +static bool is_xelpdp_pica_hpd_pin(enum hpd_pin hpd_pin) +{ + return hpd_pin >= HPD_PORT_TC1 && hpd_pin <= HPD_PORT_TC4; +} + +static void _xelpdp_pica_hpd_detection_setup(struct drm_i915_private *i915, + enum hpd_pin hpd_pin, bool enable) +{ + u32 mask = XELPDP_TBT_HOTPLUG_ENABLE | + XELPDP_DP_ALT_HOTPLUG_ENABLE; + + if (!is_xelpdp_pica_hpd_pin(hpd_pin)) + return; + + intel_de_rmw(i915, XELPDP_PORT_HOTPLUG_CTL(hpd_pin), + mask, enable ? mask : 0); +} + +static void xelpdp_pica_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + _xelpdp_pica_hpd_detection_setup(i915, encoder->hpd_pin, true); +} + +static void xelpdp_pica_hpd_detection_setup(struct drm_i915_private *i915) +{ + struct intel_encoder *encoder; + u32 available_pins = 0; + enum hpd_pin pin; + + BUILD_BUG_ON(BITS_PER_TYPE(available_pins) < HPD_NUM_PINS); + + for_each_intel_encoder(&i915->drm, encoder) + available_pins |= BIT(encoder->hpd_pin); + + for_each_hpd_pin(pin) + _xelpdp_pica_hpd_detection_setup(i915, pin, available_pins & BIT(pin)); +} + +static void xelpdp_hpd_enable_detection(struct intel_encoder *encoder) +{ + xelpdp_pica_hpd_enable_detection(encoder); + mtp_hpd_enable_detection(encoder); +} + +static void xelpdp_hpd_irq_setup(struct drm_i915_private *i915) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(i915, i915->display.hotplug.hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(i915, i915->display.hotplug.hpd); + + intel_de_rmw(i915, PICAINTERRUPT_IMR, hotplug_irqs, + ~enabled_irqs & hotplug_irqs); + intel_uncore_posting_read(&i915->uncore, PICAINTERRUPT_IMR); + + xelpdp_pica_hpd_detection_setup(i915); + + if (INTEL_PCH_TYPE(i915) >= PCH_MTP) + mtp_hpd_irq_setup(i915); +} + +static u32 spt_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_A: + return PORTA_HOTPLUG_ENABLE; + case HPD_PORT_B: + return PORTB_HOTPLUG_ENABLE; + case HPD_PORT_C: + return PORTC_HOTPLUG_ENABLE; + case HPD_PORT_D: + return PORTD_HOTPLUG_ENABLE; + default: + return 0; + } +} + +static u32 spt_hotplug_enables(struct intel_encoder *encoder) +{ + return spt_hotplug_mask(encoder->hpd_pin); +} + +static u32 spt_hotplug2_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_E: + return PORTE_HOTPLUG_ENABLE; + default: + return 0; + } +} + +static u32 spt_hotplug2_enables(struct intel_encoder *encoder) +{ + return spt_hotplug2_mask(encoder->hpd_pin); +} + +static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + /* Display WA #1179 WaHardHangonHotPlug: cnp */ + if (HAS_PCH_CNP(dev_priv)) { + intel_uncore_rmw(&dev_priv->uncore, SOUTH_CHICKEN1, CHASSIS_CLK_REQ_DURATION_MASK, + CHASSIS_CLK_REQ_DURATION(0xf)); + } + + /* Enable digital hotplug on the PCH */ + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, + intel_hpd_hotplug_mask(dev_priv, spt_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables)); + + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, + intel_hpd_hotplug_mask(dev_priv, spt_hotplug2_mask), + intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables)); +} + +static void spt_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + /* Display WA #1179 WaHardHangonHotPlug: cnp */ + if (HAS_PCH_CNP(i915)) { + intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN1, + CHASSIS_CLK_REQ_DURATION_MASK, + CHASSIS_CLK_REQ_DURATION(0xf)); + } + + intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG, + spt_hotplug_mask(encoder->hpd_pin), + spt_hotplug_enables(encoder)); + + intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG2, + spt_hotplug2_mask(encoder->hpd_pin), + spt_hotplug2_enables(encoder)); +} + +static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) + intel_uncore_write(&dev_priv->uncore, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + + ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); + + spt_hpd_detection_setup(dev_priv); +} + +static u32 ilk_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_A: + return DIGITAL_PORTA_HOTPLUG_ENABLE | + DIGITAL_PORTA_PULSE_DURATION_MASK; + default: + return 0; + } +} + +static u32 ilk_hotplug_enables(struct intel_encoder *encoder) +{ + switch (encoder->hpd_pin) { + case HPD_PORT_A: + return DIGITAL_PORTA_HOTPLUG_ENABLE | + DIGITAL_PORTA_PULSE_DURATION_2ms; + default: + return 0; + } +} + +static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + /* + * Enable digital hotplug on the CPU, and configure the DP short pulse + * duration to 2ms (which is the minimum in the Display Port spec) + * The pulse duration bits are reserved on HSW+. + */ + intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, + intel_hpd_hotplug_mask(dev_priv, ilk_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables)); +} + +static void ilk_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_uncore_rmw(&i915->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, + ilk_hotplug_mask(encoder->hpd_pin), + ilk_hotplug_enables(encoder)); + + ibx_hpd_enable_detection(encoder); +} + +static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); + + if (DISPLAY_VER(dev_priv) >= 8) + bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); + else + ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs); + + ilk_hpd_detection_setup(dev_priv); + + ibx_hpd_irq_setup(dev_priv); +} + +static u32 bxt_hotplug_mask(enum hpd_pin hpd_pin) +{ + switch (hpd_pin) { + case HPD_PORT_A: + return PORTA_HOTPLUG_ENABLE | BXT_DDIA_HPD_INVERT; + case HPD_PORT_B: + return PORTB_HOTPLUG_ENABLE | BXT_DDIB_HPD_INVERT; + case HPD_PORT_C: + return PORTC_HOTPLUG_ENABLE | BXT_DDIC_HPD_INVERT; + default: + return 0; + } +} + +static u32 bxt_hotplug_enables(struct intel_encoder *encoder) +{ + u32 hotplug; + + switch (encoder->hpd_pin) { + case HPD_PORT_A: + hotplug = PORTA_HOTPLUG_ENABLE; + if (intel_bios_encoder_hpd_invert(encoder->devdata)) + hotplug |= BXT_DDIA_HPD_INVERT; + return hotplug; + case HPD_PORT_B: + hotplug = PORTB_HOTPLUG_ENABLE; + if (intel_bios_encoder_hpd_invert(encoder->devdata)) + hotplug |= BXT_DDIB_HPD_INVERT; + return hotplug; + case HPD_PORT_C: + hotplug = PORTC_HOTPLUG_ENABLE; + if (intel_bios_encoder_hpd_invert(encoder->devdata)) + hotplug |= BXT_DDIC_HPD_INVERT; + return hotplug; + default: + return 0; + } +} + +static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, + intel_hpd_hotplug_mask(dev_priv, bxt_hotplug_mask), + intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables)); +} + +static void bxt_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG, + bxt_hotplug_mask(encoder->hpd_pin), + bxt_hotplug_enables(encoder)); +} + +static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); + + bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); + + bxt_hpd_detection_setup(dev_priv); +} + +static void i915_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + u32 hotplug_en = hpd_mask_i915[encoder->hpd_pin]; + + /* HPD sense and interrupt enable are one and the same */ + i915_hotplug_interrupt_update(i915, hotplug_en, hotplug_en); +} + +static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_en; + + lockdep_assert_held(&dev_priv->irq_lock); + + /* + * Note HDMI and DP share hotplug bits. Enable bits are the same for all + * generations. + */ + hotplug_en = intel_hpd_enabled_irqs(dev_priv, hpd_mask_i915); + /* + * Programming the CRT detection parameters tends to generate a spurious + * hotplug event about three seconds later. So just do it once. + */ + if (IS_G4X(dev_priv)) + hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; + hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; + + /* Ignore TV since it's buggy */ + i915_hotplug_interrupt_update_locked(dev_priv, + HOTPLUG_INT_EN_MASK | + CRT_HOTPLUG_VOLTAGE_COMPARE_MASK | + CRT_HOTPLUG_ACTIVATION_PERIOD_64, + hotplug_en); +} + +struct intel_hotplug_funcs { + /* Enable HPD sense and interrupts for all present encoders */ + void (*hpd_irq_setup)(struct drm_i915_private *i915); + /* Enable HPD sense for a single encoder */ + void (*hpd_enable_detection)(struct intel_encoder *encoder); +}; + +#define HPD_FUNCS(platform) \ +static const struct intel_hotplug_funcs platform##_hpd_funcs = { \ + .hpd_irq_setup = platform##_hpd_irq_setup, \ + .hpd_enable_detection = platform##_hpd_enable_detection, \ +} + +HPD_FUNCS(i915); +HPD_FUNCS(xelpdp); +HPD_FUNCS(dg1); +HPD_FUNCS(gen11); +HPD_FUNCS(bxt); +HPD_FUNCS(icp); +HPD_FUNCS(spt); +HPD_FUNCS(ilk); +#undef HPD_FUNCS + +void intel_hpd_enable_detection(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + if (i915->display.funcs.hotplug) + i915->display.funcs.hotplug->hpd_enable_detection(encoder); +} + +void intel_hpd_irq_setup(struct drm_i915_private *i915) +{ + if (i915->display_irqs_enabled && i915->display.funcs.hotplug) + i915->display.funcs.hotplug->hpd_irq_setup(i915); +} + +void intel_hotplug_irq_init(struct drm_i915_private *i915) +{ + intel_hpd_init_pins(i915); + + intel_hpd_init_early(i915); + + if (HAS_GMCH(i915)) { + if (I915_HAS_HOTPLUG(i915)) + i915->display.funcs.hotplug = &i915_hpd_funcs; + } else { + if (HAS_PCH_DG2(i915)) + i915->display.funcs.hotplug = &icp_hpd_funcs; + else if (HAS_PCH_DG1(i915)) + i915->display.funcs.hotplug = &dg1_hpd_funcs; + else if (DISPLAY_VER(i915) >= 14) + i915->display.funcs.hotplug = &xelpdp_hpd_funcs; + else if (DISPLAY_VER(i915) >= 11) + i915->display.funcs.hotplug = &gen11_hpd_funcs; + else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) + i915->display.funcs.hotplug = &bxt_hpd_funcs; + else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) + i915->display.funcs.hotplug = &icp_hpd_funcs; + else if (INTEL_PCH_TYPE(i915) >= PCH_SPT) + i915->display.funcs.hotplug = &spt_hpd_funcs; + else + i915->display.funcs.hotplug = &ilk_hpd_funcs; + } +} diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.h b/drivers/gpu/drm/i915/display/intel_hotplug_irq.h new file mode 100644 index 000000000000..e4db752df096 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_HOTPLUG_IRQ_H__ +#define __INTEL_HOTPLUG_IRQ_H__ + +#include <linux/types.h> + +struct drm_i915_private; +struct intel_encoder; + +u32 i9xx_hpd_irq_ack(struct drm_i915_private *i915); + +void i9xx_hpd_irq_handler(struct drm_i915_private *i915, u32 hotplug_status); +void ibx_hpd_irq_handler(struct drm_i915_private *i915, u32 hotplug_trigger); +void ilk_hpd_irq_handler(struct drm_i915_private *i915, u32 hotplug_trigger); +void gen11_hpd_irq_handler(struct drm_i915_private *i915, u32 iir); +void bxt_hpd_irq_handler(struct drm_i915_private *i915, u32 hotplug_trigger); +void xelpdp_pica_irq_handler(struct drm_i915_private *i915, u32 iir); +void icp_irq_handler(struct drm_i915_private *i915, u32 pch_iir); +void spt_irq_handler(struct drm_i915_private *i915, u32 pch_iir); + +void i915_hotplug_interrupt_update_locked(struct drm_i915_private *i915, + u32 mask, u32 bits); +void i915_hotplug_interrupt_update(struct drm_i915_private *i915, + u32 mask, u32 bits); + +void intel_hpd_enable_detection(struct intel_encoder *encoder); +void intel_hpd_irq_setup(struct drm_i915_private *i915); + +void intel_hotplug_irq_init(struct drm_i915_private *i915); + +#endif /* __INTEL_HOTPLUG_IRQ_H__ */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 64cc52538206..61f53b283210 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -42,6 +42,7 @@ #include "display/intel_fifo_underrun.h" #include "display/intel_gmbus.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" @@ -84,172 +85,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); -typedef u32 (*hotplug_mask_func)(enum hpd_pin pin); - -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_xelpdp[HPD_NUM_PINS] = { - [HPD_PORT_TC1] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC1) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC1), - [HPD_PORT_TC2] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC2) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC2), - [HPD_PORT_TC3] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC3) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC3), - [HPD_PORT_TC4] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC4) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC4), -}; - -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 const u32 hpd_mtp[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_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), -}; - -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) >= 14) - hpd->hpd = hpd_xelpdp; - else 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_MTP) - hpd->pch_hpd = hpd_mtp; - 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) { @@ -344,47 +179,14 @@ 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) +void ilk_update_display_irq(struct drm_i915_private *dev_priv, + u32 interrupt_mask, u32 enabled_irq_mask) { u32 new_val; @@ -419,9 +221,8 @@ void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits) * @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) +void bdw_update_port_irq(struct drm_i915_private *dev_priv, + u32 interrupt_mask, u32 enabled_irq_mask) { u32 new_val; u32 old_val; @@ -494,9 +295,9 @@ void bdw_disable_pipe_irq(struct drm_i915_private *i915, * @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) +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; @@ -724,209 +525,6 @@ static void ivb_parity_work(struct work_struct *work) 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_mask(struct drm_i915_private *i915, - hotplug_mask_func hotplug_mask) -{ - enum hpd_pin pin; - u32 hotplug = 0; - - for_each_hpd_pin(pin) - hotplug |= hotplug_mask(pin); - - return hotplug; -} - -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; -} - #if defined(CONFIG_DEBUG_FS) static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, enum pipe pipe, @@ -1199,71 +797,6 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv, intel_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) - intel_dp_aux_irq_handler(dev_priv); -} - static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_i915_private *dev_priv = arg; @@ -1428,38 +961,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; @@ -1585,133 +1086,6 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) cpt_serr_int_handler(dev_priv); } -static void xelpdp_pica_irq_handler(struct drm_i915_private *i915, u32 iir) -{ - enum hpd_pin pin; - u32 hotplug_trigger = iir & (XELPDP_DP_ALT_HOTPLUG_MASK | XELPDP_TBT_HOTPLUG_MASK); - u32 trigger_aux = iir & XELPDP_AUX_TC_MASK; - u32 pin_mask = 0, long_mask = 0; - - for (pin = HPD_PORT_TC1; pin <= HPD_PORT_TC4; pin++) { - u32 val; - - if (!(i915->display.hotplug.hpd[pin] & hotplug_trigger)) - continue; - - pin_mask |= BIT(pin); - - val = intel_de_read(i915, XELPDP_PORT_HOTPLUG_CTL(pin)); - intel_de_write(i915, XELPDP_PORT_HOTPLUG_CTL(pin), val); - - if (val & (XELPDP_DP_ALT_HPD_LONG_DETECT | XELPDP_TBT_HPD_LONG_DETECT)) - long_mask |= BIT(pin); - } - - if (pin_mask) { - drm_dbg(&i915->drm, - "pica hotplug event received, stat 0x%08x, pins 0x%08x, long 0x%08x\n", - hotplug_trigger, pin_mask, long_mask); - - intel_hpd_irq_handler(i915, pin_mask, long_mask); - } - - if (trigger_aux) - intel_dp_aux_irq_handler(i915); - - if (!pin_mask && !trigger_aux) - drm_err(&i915->drm, - "Unexpected DE HPD/AUX interrupt 0x%08x\n", iir); -} - -static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) -{ - u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_HOTPLUG_MASK_ICP; - u32 tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_MASK_ICP; - u32 pin_mask = 0, long_mask = 0; - - if (ddi_hotplug_trigger) { - u32 dig_hotplug_reg; - - /* Locking due to DSI native GPIO sequences */ - spin_lock(&dev_priv->irq_lock); - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, 0, 0); - spin_unlock(&dev_priv->irq_lock); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - ddi_hotplug_trigger, dig_hotplug_reg, - dev_priv->display.hotplug.pch_hpd, - icp_ddi_port_hotplug_long_detect); - } - - if (tc_hotplug_trigger) { - u32 dig_hotplug_reg; - - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC, 0, 0); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - tc_hotplug_trigger, dig_hotplug_reg, - dev_priv->display.hotplug.pch_hpd, - icp_tc_port_hotplug_long_detect); - } - - if (pin_mask) - intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); - - if (pch_iir & SDE_GMBUS_ICP) - intel_gmbus_irq_handler(dev_priv); -} - -static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) -{ - u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT & - ~SDE_PORTE_HOTPLUG_SPT; - u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT; - u32 pin_mask = 0, long_mask = 0; - - if (hotplug_trigger) { - u32 dig_hotplug_reg; - - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - hotplug_trigger, dig_hotplug_reg, - dev_priv->display.hotplug.pch_hpd, - spt_port_hotplug_long_detect); - } - - if (hotplug2_trigger) { - u32 dig_hotplug_reg; - - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, 0, 0); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - hotplug2_trigger, dig_hotplug_reg, - dev_priv->display.hotplug.pch_hpd, - spt_port_hotplug2_long_detect); - } - - if (pin_mask) - intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); - - if (pch_iir & SDE_GMBUS_CPT) - intel_gmbus_irq_handler(dev_priv); -} - -static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv, - u32 hotplug_trigger) -{ - u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; - - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, 0, 0); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - hotplug_trigger, dig_hotplug_reg, - dev_priv->display.hotplug.hpd, - ilk_port_hotplug_long_detect); - - intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); -} - static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) { @@ -1876,56 +1250,6 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) return ret; } -static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, - u32 hotplug_trigger) -{ - u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; - - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - hotplug_trigger, dig_hotplug_reg, - dev_priv->display.hotplug.hpd, - bxt_port_hotplug_long_detect); - - intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); -} - -static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) -{ - u32 pin_mask = 0, long_mask = 0; - u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK; - u32 trigger_tbt = iir & GEN11_DE_TBT_HOTPLUG_MASK; - - if (trigger_tc) { - u32 dig_hotplug_reg; - - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, 0, 0); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - trigger_tc, dig_hotplug_reg, - dev_priv->display.hotplug.hpd, - gen11_port_hotplug_long_detect); - } - - if (trigger_tbt) { - u32 dig_hotplug_reg; - - dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, 0, 0); - - intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, - trigger_tbt, dig_hotplug_reg, - dev_priv->display.hotplug.hpd, - gen11_port_hotplug_long_detect); - } - - if (pin_mask) - intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); - else - drm_err(&dev_priv->drm, - "Unexpected DE HPD interrupt 0x%08x\n", iir); -} - static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) { u32 mask; @@ -2933,696 +2257,39 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } -static u32 ibx_hotplug_mask(enum hpd_pin hpd_pin) +/* + * SDEIER is also touched by the interrupt handler to work around missed PCH + * interrupts. Hence we can't update it after the interrupt handler is enabled - + * instead we unconditionally enable all PCH interrupt sources here, but then + * only unmask them as needed with SDEIMR. + * + * Note that we currently do this after installing the interrupt handler, + * but before we enable the master interrupt. That should be sufficient + * to avoid races with the irq handler, assuming we have MSI. Shared legacy + * interrupts could still race. + */ +static void ibx_irq_postinstall(struct drm_i915_private *dev_priv) { - switch (hpd_pin) { - case HPD_PORT_A: - return PORTA_HOTPLUG_ENABLE; - case HPD_PORT_B: - return PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_MASK; - case HPD_PORT_C: - return PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_MASK; - case HPD_PORT_D: - return PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_MASK; - default: - return 0; - } + struct intel_uncore *uncore = &dev_priv->uncore; + u32 mask; + + if (HAS_PCH_NOP(dev_priv)) + return; + + if (HAS_PCH_IBX(dev_priv)) + mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; + else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; + else + mask = SDE_GMBUS_CPT; + + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); } -static u32 ibx_hotplug_enables(struct intel_encoder *encoder) +static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - switch (encoder->hpd_pin) { - case HPD_PORT_A: - /* - * When CPU and PCH are on the same package, port A - * HPD must be enabled in both north and south. - */ - return HAS_PCH_LPT_LP(i915) ? - PORTA_HOTPLUG_ENABLE : 0; - case HPD_PORT_B: - return PORTB_HOTPLUG_ENABLE | - PORTB_PULSE_DURATION_2ms; - case HPD_PORT_C: - return PORTC_HOTPLUG_ENABLE | - PORTC_PULSE_DURATION_2ms; - case HPD_PORT_D: - return PORTD_HOTPLUG_ENABLE | - PORTD_PULSE_DURATION_2ms; - default: - return 0; - } -} - -static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - /* - * Enable digital hotplug on the PCH, and configure the DP short pulse - * duration to 2ms (which is the minimum in the Display Port spec). - * The pulse duration bits are reserved on LPT+. - */ - intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, - intel_hpd_hotplug_mask(dev_priv, ibx_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables)); -} - -static void ibx_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG, - ibx_hotplug_mask(encoder->hpd_pin), - ibx_hotplug_enables(encoder)); -} - -static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - u32 hotplug_irqs, enabled_irqs; - - enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); - - ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); - - ibx_hpd_detection_setup(dev_priv); -} - -static u32 icp_ddi_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_pin) { - case HPD_PORT_A: - case HPD_PORT_B: - case HPD_PORT_C: - case HPD_PORT_D: - return SHOTPLUG_CTL_DDI_HPD_ENABLE(hpd_pin); - default: - return 0; - } -} - -static u32 icp_ddi_hotplug_enables(struct intel_encoder *encoder) -{ - return icp_ddi_hotplug_mask(encoder->hpd_pin); -} - -static u32 icp_tc_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_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 ICP_TC_HPD_ENABLE(hpd_pin); - default: - return 0; - } -} - -static u32 icp_tc_hotplug_enables(struct intel_encoder *encoder) -{ - return icp_tc_hotplug_mask(encoder->hpd_pin); -} - -static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, - intel_hpd_hotplug_mask(dev_priv, icp_ddi_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables)); -} - -static void icp_ddi_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_uncore_rmw(&i915->uncore, SHOTPLUG_CTL_DDI, - icp_ddi_hotplug_mask(encoder->hpd_pin), - icp_ddi_hotplug_enables(encoder)); -} - -static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC, - intel_hpd_hotplug_mask(dev_priv, icp_tc_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables)); -} - -static void icp_tc_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_uncore_rmw(&i915->uncore, SHOTPLUG_CTL_TC, - icp_tc_hotplug_mask(encoder->hpd_pin), - icp_tc_hotplug_enables(encoder)); -} - -static void icp_hpd_enable_detection(struct intel_encoder *encoder) -{ - icp_ddi_hpd_enable_detection(encoder); - icp_tc_hpd_enable_detection(encoder); -} - -static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - u32 hotplug_irqs, enabled_irqs; - - enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); - - if (INTEL_PCH_TYPE(dev_priv) <= PCH_TGP) - intel_uncore_write(&dev_priv->uncore, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); - - ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); - - icp_ddi_hpd_detection_setup(dev_priv); - icp_tc_hpd_detection_setup(dev_priv); -} - -static u32 gen11_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_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 GEN11_HOTPLUG_CTL_ENABLE(hpd_pin); - default: - return 0; - } -} - -static u32 gen11_hotplug_enables(struct intel_encoder *encoder) -{ - return gen11_hotplug_mask(encoder->hpd_pin); -} - -static void dg1_hpd_invert(struct drm_i915_private *i915) -{ - u32 val = (INVERT_DDIA_HPD | - INVERT_DDIB_HPD | - INVERT_DDIC_HPD | - INVERT_DDID_HPD); - intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN1, 0, val); -} - -static void dg1_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - dg1_hpd_invert(i915); - icp_hpd_enable_detection(encoder); -} - -static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - dg1_hpd_invert(dev_priv); - icp_hpd_irq_setup(dev_priv); -} - -static void gen11_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, - intel_hpd_hotplug_mask(dev_priv, gen11_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables)); -} - -static void gen11_tc_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_uncore_rmw(&i915->uncore, GEN11_TC_HOTPLUG_CTL, - gen11_hotplug_mask(encoder->hpd_pin), - gen11_hotplug_enables(encoder)); -} - -static void gen11_tbt_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, - intel_hpd_hotplug_mask(dev_priv, gen11_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables)); -} - -static void gen11_tbt_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_uncore_rmw(&i915->uncore, GEN11_TBT_HOTPLUG_CTL, - gen11_hotplug_mask(encoder->hpd_pin), - gen11_hotplug_enables(encoder)); -} - -static void gen11_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - gen11_tc_hpd_enable_detection(encoder); - gen11_tbt_hpd_enable_detection(encoder); - - if (INTEL_PCH_TYPE(i915) >= PCH_ICP) - icp_hpd_enable_detection(encoder); -} - -static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - u32 hotplug_irqs, enabled_irqs; - - enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); - - intel_uncore_rmw(&dev_priv->uncore, GEN11_DE_HPD_IMR, hotplug_irqs, - ~enabled_irqs & hotplug_irqs); - intel_uncore_posting_read(&dev_priv->uncore, GEN11_DE_HPD_IMR); - - gen11_tc_hpd_detection_setup(dev_priv); - gen11_tbt_hpd_detection_setup(dev_priv); - - if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - icp_hpd_irq_setup(dev_priv); -} - -static u32 mtp_ddi_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_pin) { - case HPD_PORT_A: - case HPD_PORT_B: - return SHOTPLUG_CTL_DDI_HPD_ENABLE(hpd_pin); - default: - return 0; - } -} - -static u32 mtp_ddi_hotplug_enables(struct intel_encoder *encoder) -{ - return mtp_ddi_hotplug_mask(encoder->hpd_pin); -} - -static u32 mtp_tc_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_pin) { - case HPD_PORT_TC1: - case HPD_PORT_TC2: - case HPD_PORT_TC3: - case HPD_PORT_TC4: - return ICP_TC_HPD_ENABLE(hpd_pin); - default: - return 0; - } -} - -static u32 mtp_tc_hotplug_enables(struct intel_encoder *encoder) -{ - return mtp_tc_hotplug_mask(encoder->hpd_pin); -} - -static void mtp_ddi_hpd_detection_setup(struct drm_i915_private *i915) -{ - intel_de_rmw(i915, SHOTPLUG_CTL_DDI, - intel_hpd_hotplug_mask(i915, mtp_ddi_hotplug_mask), - intel_hpd_hotplug_enables(i915, mtp_ddi_hotplug_enables)); -} - -static void mtp_ddi_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_de_rmw(i915, SHOTPLUG_CTL_DDI, - mtp_ddi_hotplug_mask(encoder->hpd_pin), - mtp_ddi_hotplug_enables(encoder)); -} - -static void mtp_tc_hpd_detection_setup(struct drm_i915_private *i915) -{ - intel_de_rmw(i915, SHOTPLUG_CTL_TC, - intel_hpd_hotplug_mask(i915, mtp_tc_hotplug_mask), - intel_hpd_hotplug_enables(i915, mtp_tc_hotplug_enables)); -} - -static void mtp_tc_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_de_rmw(i915, SHOTPLUG_CTL_DDI, - mtp_tc_hotplug_mask(encoder->hpd_pin), - mtp_tc_hotplug_enables(encoder)); -} - -static void mtp_hpd_invert(struct drm_i915_private *i915) -{ - u32 val = (INVERT_DDIA_HPD | - INVERT_DDIB_HPD | - INVERT_DDIC_HPD | - INVERT_TC1_HPD | - INVERT_TC2_HPD | - INVERT_TC3_HPD | - INVERT_TC4_HPD | - INVERT_DDID_HPD_MTP | - INVERT_DDIE_HPD); - intel_de_rmw(i915, SOUTH_CHICKEN1, 0, val); -} - -static void mtp_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - mtp_hpd_invert(i915); - mtp_ddi_hpd_enable_detection(encoder); - mtp_tc_hpd_enable_detection(encoder); -} - -static void mtp_hpd_irq_setup(struct drm_i915_private *i915) -{ - u32 hotplug_irqs, enabled_irqs; - - enabled_irqs = intel_hpd_enabled_irqs(i915, i915->display.hotplug.pch_hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(i915, i915->display.hotplug.pch_hpd); - - intel_de_write(i915, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); - - mtp_hpd_invert(i915); - ibx_display_interrupt_update(i915, hotplug_irqs, enabled_irqs); - - mtp_ddi_hpd_detection_setup(i915); - mtp_tc_hpd_detection_setup(i915); -} - -static bool is_xelpdp_pica_hpd_pin(enum hpd_pin hpd_pin) -{ - return hpd_pin >= HPD_PORT_TC1 && hpd_pin <= HPD_PORT_TC4; -} - -static void _xelpdp_pica_hpd_detection_setup(struct drm_i915_private *i915, - enum hpd_pin hpd_pin, bool enable) -{ - u32 mask = XELPDP_TBT_HOTPLUG_ENABLE | - XELPDP_DP_ALT_HOTPLUG_ENABLE; - - if (!is_xelpdp_pica_hpd_pin(hpd_pin)) - return; - - intel_de_rmw(i915, XELPDP_PORT_HOTPLUG_CTL(hpd_pin), - mask, enable ? mask : 0); -} - -static void xelpdp_pica_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - _xelpdp_pica_hpd_detection_setup(i915, encoder->hpd_pin, true); -} - -static void xelpdp_pica_hpd_detection_setup(struct drm_i915_private *i915) -{ - struct intel_encoder *encoder; - u32 available_pins = 0; - enum hpd_pin pin; - - BUILD_BUG_ON(BITS_PER_TYPE(available_pins) < HPD_NUM_PINS); - - for_each_intel_encoder(&i915->drm, encoder) - available_pins |= BIT(encoder->hpd_pin); - - for_each_hpd_pin(pin) - _xelpdp_pica_hpd_detection_setup(i915, pin, available_pins & BIT(pin)); -} - -static void xelpdp_hpd_enable_detection(struct intel_encoder *encoder) -{ - xelpdp_pica_hpd_enable_detection(encoder); - mtp_hpd_enable_detection(encoder); -} - -static void xelpdp_hpd_irq_setup(struct drm_i915_private *i915) -{ - u32 hotplug_irqs, enabled_irqs; - - enabled_irqs = intel_hpd_enabled_irqs(i915, i915->display.hotplug.hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(i915, i915->display.hotplug.hpd); - - intel_de_rmw(i915, PICAINTERRUPT_IMR, hotplug_irqs, - ~enabled_irqs & hotplug_irqs); - intel_uncore_posting_read(&i915->uncore, PICAINTERRUPT_IMR); - - xelpdp_pica_hpd_detection_setup(i915); - - if (INTEL_PCH_TYPE(i915) >= PCH_MTP) - mtp_hpd_irq_setup(i915); -} - -static u32 spt_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_pin) { - case HPD_PORT_A: - return PORTA_HOTPLUG_ENABLE; - case HPD_PORT_B: - return PORTB_HOTPLUG_ENABLE; - case HPD_PORT_C: - return PORTC_HOTPLUG_ENABLE; - case HPD_PORT_D: - return PORTD_HOTPLUG_ENABLE; - default: - return 0; - } -} - -static u32 spt_hotplug_enables(struct intel_encoder *encoder) -{ - return spt_hotplug_mask(encoder->hpd_pin); -} - -static u32 spt_hotplug2_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_pin) { - case HPD_PORT_E: - return PORTE_HOTPLUG_ENABLE; - default: - return 0; - } -} - -static u32 spt_hotplug2_enables(struct intel_encoder *encoder) -{ - return spt_hotplug2_mask(encoder->hpd_pin); -} - -static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - /* Display WA #1179 WaHardHangonHotPlug: cnp */ - if (HAS_PCH_CNP(dev_priv)) { - intel_uncore_rmw(&dev_priv->uncore, SOUTH_CHICKEN1, CHASSIS_CLK_REQ_DURATION_MASK, - CHASSIS_CLK_REQ_DURATION(0xf)); - } - - /* Enable digital hotplug on the PCH */ - intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, - intel_hpd_hotplug_mask(dev_priv, spt_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables)); - - intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, - intel_hpd_hotplug_mask(dev_priv, spt_hotplug2_mask), - intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables)); -} - -static void spt_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - /* Display WA #1179 WaHardHangonHotPlug: cnp */ - if (HAS_PCH_CNP(i915)) { - intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN1, - CHASSIS_CLK_REQ_DURATION_MASK, - CHASSIS_CLK_REQ_DURATION(0xf)); - } - - intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG, - spt_hotplug_mask(encoder->hpd_pin), - spt_hotplug_enables(encoder)); - - intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG2, - spt_hotplug2_mask(encoder->hpd_pin), - spt_hotplug2_enables(encoder)); -} - -static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - u32 hotplug_irqs, enabled_irqs; - - if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) - intel_uncore_write(&dev_priv->uncore, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); - - enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); - - ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); - - spt_hpd_detection_setup(dev_priv); -} - -static u32 ilk_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_pin) { - case HPD_PORT_A: - return DIGITAL_PORTA_HOTPLUG_ENABLE | - DIGITAL_PORTA_PULSE_DURATION_MASK; - default: - return 0; - } -} - -static u32 ilk_hotplug_enables(struct intel_encoder *encoder) -{ - switch (encoder->hpd_pin) { - case HPD_PORT_A: - return DIGITAL_PORTA_HOTPLUG_ENABLE | - DIGITAL_PORTA_PULSE_DURATION_2ms; - default: - return 0; - } -} - -static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - /* - * Enable digital hotplug on the CPU, and configure the DP short pulse - * duration to 2ms (which is the minimum in the Display Port spec) - * The pulse duration bits are reserved on HSW+. - */ - intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, - intel_hpd_hotplug_mask(dev_priv, ilk_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables)); -} - -static void ilk_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_uncore_rmw(&i915->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, - ilk_hotplug_mask(encoder->hpd_pin), - ilk_hotplug_enables(encoder)); - - ibx_hpd_enable_detection(encoder); -} - -static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - u32 hotplug_irqs, enabled_irqs; - - enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); - - if (DISPLAY_VER(dev_priv) >= 8) - bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); - else - ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs); - - ilk_hpd_detection_setup(dev_priv); - - ibx_hpd_irq_setup(dev_priv); -} - -static u32 bxt_hotplug_mask(enum hpd_pin hpd_pin) -{ - switch (hpd_pin) { - case HPD_PORT_A: - return PORTA_HOTPLUG_ENABLE | BXT_DDIA_HPD_INVERT; - case HPD_PORT_B: - return PORTB_HOTPLUG_ENABLE | BXT_DDIB_HPD_INVERT; - case HPD_PORT_C: - return PORTC_HOTPLUG_ENABLE | BXT_DDIC_HPD_INVERT; - default: - return 0; - } -} - -static u32 bxt_hotplug_enables(struct intel_encoder *encoder) -{ - u32 hotplug; - - switch (encoder->hpd_pin) { - case HPD_PORT_A: - hotplug = PORTA_HOTPLUG_ENABLE; - if (intel_bios_encoder_hpd_invert(encoder->devdata)) - hotplug |= BXT_DDIA_HPD_INVERT; - return hotplug; - case HPD_PORT_B: - hotplug = PORTB_HOTPLUG_ENABLE; - if (intel_bios_encoder_hpd_invert(encoder->devdata)) - hotplug |= BXT_DDIB_HPD_INVERT; - return hotplug; - case HPD_PORT_C: - hotplug = PORTC_HOTPLUG_ENABLE; - if (intel_bios_encoder_hpd_invert(encoder->devdata)) - hotplug |= BXT_DDIC_HPD_INVERT; - return hotplug; - default: - return 0; - } -} - -static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv) -{ - intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, - intel_hpd_hotplug_mask(dev_priv, bxt_hotplug_mask), - intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables)); -} - -static void bxt_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - intel_uncore_rmw(&i915->uncore, PCH_PORT_HOTPLUG, - bxt_hotplug_mask(encoder->hpd_pin), - bxt_hotplug_enables(encoder)); -} - -static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - u32 hotplug_irqs, enabled_irqs; - - enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); - hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); - - bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); - - bxt_hpd_detection_setup(dev_priv); -} - -/* - * SDEIER is also touched by the interrupt handler to work around missed PCH - * interrupts. Hence we can't update it after the interrupt handler is enabled - - * instead we unconditionally enable all PCH interrupt sources here, but then - * only unmask them as needed with SDEIMR. - * - * Note that we currently do this after installing the interrupt handler, - * but before we enable the master interrupt. That should be sufficient - * to avoid races with the irq handler, assuming we have MSI. Shared legacy - * interrupts could still race. - */ -static void ibx_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 mask; - - if (HAS_PCH_NOP(dev_priv)) - return; - - if (HAS_PCH_IBX(dev_priv)) - mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; - else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) - mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; - else - mask = SDE_GMBUS_CPT; - - GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); -} - -static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 display_mask, extra_mask; + struct intel_uncore *uncore = &dev_priv->uncore; + u32 display_mask, extra_mask; if (GRAPHICS_VER(dev_priv) >= 7) { display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | @@ -4257,40 +2924,6 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv) i915_enable_asle_pipestat(dev_priv); } -static void i915_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - u32 hotplug_en = hpd_mask_i915[encoder->hpd_pin]; - - /* HPD sense and interrupt enable are one and the same */ - i915_hotplug_interrupt_update(i915, hotplug_en, hotplug_en); -} - -static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv) -{ - u32 hotplug_en; - - lockdep_assert_held(&dev_priv->irq_lock); - - /* Note HDMI and DP share hotplug bits */ - /* enable bits are the same for all generations */ - hotplug_en = intel_hpd_enabled_irqs(dev_priv, hpd_mask_i915); - /* Programming the CRT detection parameters tends - to generate a spurious hotplug event about three - seconds later. So just do it once. - */ - if (IS_G4X(dev_priv)) - hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; - hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; - - /* Ignore TV since it's buggy */ - i915_hotplug_interrupt_update_locked(dev_priv, - HOTPLUG_INT_EN_MASK | - CRT_HOTPLUG_VOLTAGE_COMPARE_MASK | - CRT_HOTPLUG_ACTIVATION_PERIOD_64, - hotplug_en); -} - static irqreturn_t i965_irq_handler(int irq, void *arg) { struct drm_i915_private *dev_priv = arg; @@ -4350,43 +2983,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) return ret; } -struct intel_hotplug_funcs { - /* Enable HPD sense and interrupts for all present encoders */ - void (*hpd_irq_setup)(struct drm_i915_private *i915); - /* Enable HPD sense for a single encoder */ - void (*hpd_enable_detection)(struct intel_encoder *encoder); -}; - -#define HPD_FUNCS(platform) \ -static const struct intel_hotplug_funcs platform##_hpd_funcs = { \ - .hpd_irq_setup = platform##_hpd_irq_setup, \ - .hpd_enable_detection = platform##_hpd_enable_detection, \ -} - -HPD_FUNCS(i915); -HPD_FUNCS(xelpdp); -HPD_FUNCS(dg1); -HPD_FUNCS(gen11); -HPD_FUNCS(bxt); -HPD_FUNCS(icp); -HPD_FUNCS(spt); -HPD_FUNCS(ilk); -#undef HPD_FUNCS - -void intel_hpd_enable_detection(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - - if (i915->display.funcs.hotplug) - i915->display.funcs.hotplug->hpd_enable_detection(encoder); -} - -void intel_hpd_irq_setup(struct drm_i915_private *i915) -{ - if (i915->display_irqs_enabled && i915->display.funcs.hotplug) - i915->display.funcs.hotplug->hpd_irq_setup(i915); -} - /** * intel_irq_init - initializes irq support * @dev_priv: i915 device instance @@ -4409,10 +3005,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; - intel_hpd_init_pins(dev_priv); - - intel_hpd_init_early(dev_priv); - dev_priv->drm.vblank_disable_immediate = true; /* Most platforms treat the display irq block as an always-on @@ -4425,27 +3017,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) dev_priv->display_irqs_enabled = false; - if (HAS_GMCH(dev_priv)) { - if (I915_HAS_HOTPLUG(dev_priv)) - dev_priv->display.funcs.hotplug = &i915_hpd_funcs; - } else { - if (HAS_PCH_DG2(dev_priv)) - dev_priv->display.funcs.hotplug = &icp_hpd_funcs; - else if (HAS_PCH_DG1(dev_priv)) - dev_priv->display.funcs.hotplug = &dg1_hpd_funcs; - else if (DISPLAY_VER(dev_priv) >= 14) - dev_priv->display.funcs.hotplug = &xelpdp_hpd_funcs; - else if (DISPLAY_VER(dev_priv) >= 11) - dev_priv->display.funcs.hotplug = &gen11_hpd_funcs; - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - dev_priv->display.funcs.hotplug = &bxt_hpd_funcs; - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - dev_priv->display.funcs.hotplug = &icp_hpd_funcs; - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) - dev_priv->display.funcs.hotplug = &spt_hpd_funcs; - else - dev_priv->display.funcs.hotplug = &ilk_hpd_funcs; - } + intel_hotplug_irq_init(dev_priv); } /** diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h index dd47e473ba4f..913c854f873d 100644 --- a/drivers/gpu/drm/i915/i915_irq.h +++ b/drivers/gpu/drm/i915/i915_irq.h @@ -38,18 +38,18 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv); void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv); -void intel_hpd_enable_detection(struct intel_encoder *encoder); -void intel_hpd_irq_setup(struct drm_i915_private *i915); -void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv, - u32 mask, - u32 bits); - +void ilk_update_display_irq(struct drm_i915_private *i915, + u32 interrupt_mask, u32 enabled_irq_mask); void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits); void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits); +void bdw_update_port_irq(struct drm_i915_private *i915, + u32 interrupt_mask, u32 enabled_irq_mask); void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); +void ibx_display_interrupt_update(struct drm_i915_private *i915, + u32 interrupt_mask, u32 enabled_irq_mask); void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits); void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits); -- 2.39.2 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-12 10:23 [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Jani Nikula 2023-05-12 10:23 ` [Intel-gfx] [PATCH 2/3] drm/i915/irq: split out hotplug irq handling Jani Nikula @ 2023-05-12 10:23 ` Jani Nikula 2023-05-12 13:13 ` kernel test robot ` (2 more replies) 2023-05-12 11:52 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Patchwork ` (3 subsequent siblings) 5 siblings, 3 replies; 15+ messages in thread From: Jani Nikula @ 2023-05-12 10:23 UTC (permalink / raw) To: intel-gfx; +Cc: jani.nikula Split (non-hotplug) display irq handling out of i915_irq.[ch] into display/intel_display_irq.[ch]. v2: - Rebase - Preserve [I915_MAX_PIPES] in functions (kernel test robot) Signed-off-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/i9xx_plane.c | 2 +- drivers/gpu/drm/i915/display/intel_crtc.c | 2 +- .../gpu/drm/i915/display/intel_display_irq.c | 1668 +++++++++++++++++ .../gpu/drm/i915/display/intel_display_irq.h | 81 + .../i915/display/intel_display_power_well.c | 1 + .../drm/i915/display/intel_fifo_underrun.c | 2 +- .../gpu/drm/i915/display/intel_hotplug_irq.c | 2 +- drivers/gpu/drm/i915/display/intel_tv.c | 2 +- .../drm/i915/display/skl_universal_plane.c | 2 +- drivers/gpu/drm/i915/gt/intel_rps.c | 1 + drivers/gpu/drm/i915/i915_irq.c | 1666 +--------------- drivers/gpu/drm/i915/i915_irq.h | 46 +- 13 files changed, 1763 insertions(+), 1713 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.c create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7f7569c5f9a9..310c692e2fcd 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -239,6 +239,7 @@ i915-y += \ display/intel_cursor.o \ display/intel_display.o \ display/intel_display_driver.o \ + display/intel_display_irq.o \ display/intel_display_power.o \ display/intel_display_power_map.o \ display/intel_display_power_well.o \ diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index ecaeb7dc196b..616654adbfb8 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -8,12 +8,12 @@ #include <drm/drm_blend.h> #include <drm/drm_fourcc.h> -#include "i915_irq.h" #include "i915_reg.h" #include "i9xx_plane.h" #include "intel_atomic.h" #include "intel_atomic_plane.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index df7d05f1e14b..a79930a4e40f 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -11,7 +11,6 @@ #include <drm/drm_plane.h> #include <drm/drm_vblank_work.h> -#include "i915_irq.h" #include "i915_vgpu.h" #include "i9xx_plane.h" #include "icl_dsi.h" @@ -21,6 +20,7 @@ #include "intel_crtc.h" #include "intel_cursor.h" #include "intel_display_debugfs.h" +#include "intel_display_irq.h" #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_drrs.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c new file mode 100644 index 000000000000..0eedd1ebb389 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -0,0 +1,1668 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" +#include "i915_irq.h" +#include "i915_reg.h" +#include "icl_dsi_regs.h" +#include "intel_display_irq.h" +#include "intel_display_types.h" +#include "intel_hotplug_irq.h" +#include "intel_psr_regs.h" +#include "intel_crtc.h" +#include "intel_display_trace.h" +#include "intel_dp_aux.h" +#include "intel_gmbus.h" +#include "intel_fifo_underrun.h" +#include "intel_psr.h" +#include "intel_fdi_regs.h" +#include "gt/intel_rps.h" +#include "intel_de.h" + +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); +} + +/** + * 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 + */ +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 + */ +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 + */ +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 + */ +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); +} + +#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); +} + +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; + } +} + +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); +} + +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); + } +} + +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); +} + +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) + intel_gmbus_irq_handler(dev_priv); +} + +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) + intel_gmbus_irq_handler(dev_priv); +} + +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) + intel_dp_aux_irq_handler(dev_priv); + + if (pch_iir & SDE_GMBUS) + intel_gmbus_irq_handler(dev_priv); + + if (pch_iir & SDE_AUDIO_HDCP_MASK) + drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n"); + + if (pch_iir & SDE_AUDIO_TRANS_MASK) + drm_dbg(&dev_priv->drm, "PCH transcoder audio interrupt\n"); + + if (pch_iir & SDE_POISON) + drm_err(&dev_priv->drm, "PCH poison interrupt\n"); + + if (pch_iir & SDE_FDI_MASK) { + for_each_pipe(dev_priv, pipe) + drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", + pipe_name(pipe), + intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); + } + + if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) + drm_dbg(&dev_priv->drm, "PCH transcoder CRC done interrupt\n"); + + if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) + drm_dbg(&dev_priv->drm, + "PCH transcoder CRC error interrupt\n"); + + if (pch_iir & SDE_TRANSA_FIFO_UNDER) + intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A); + + if (pch_iir & SDE_TRANSB_FIFO_UNDER) + intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B); +} + +static void ivb_err_int_handler(struct drm_i915_private *dev_priv) +{ + u32 err_int = intel_uncore_read(&dev_priv->uncore, GEN7_ERR_INT); + enum pipe pipe; + + if (err_int & ERR_INT_POISON) + drm_err(&dev_priv->drm, "Poison interrupt\n"); + + for_each_pipe(dev_priv, pipe) { + if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) + intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); + + if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { + if (IS_IVYBRIDGE(dev_priv)) + ivb_pipe_crc_irq_handler(dev_priv, pipe); + else + hsw_pipe_crc_irq_handler(dev_priv, pipe); + } + } + + intel_uncore_write(&dev_priv->uncore, GEN7_ERR_INT, err_int); +} + +static void cpt_serr_int_handler(struct drm_i915_private *dev_priv) +{ + u32 serr_int = intel_uncore_read(&dev_priv->uncore, SERR_INT); + enum pipe pipe; + + if (serr_int & SERR_INT_POISON) + drm_err(&dev_priv->drm, "PCH poison interrupt\n"); + + for_each_pipe(dev_priv, pipe) + if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe)) + intel_pch_fifo_underrun_irq_handler(dev_priv, pipe); + + intel_uncore_write(&dev_priv->uncore, SERR_INT, serr_int); +} + +static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) +{ + enum pipe pipe; + u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; + + ibx_hpd_irq_handler(dev_priv, hotplug_trigger); + + if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { + int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> + SDE_AUDIO_POWER_SHIFT_CPT); + drm_dbg(&dev_priv->drm, "PCH audio power change on port %c\n", + port_name(port)); + } + + if (pch_iir & SDE_AUX_MASK_CPT) + intel_dp_aux_irq_handler(dev_priv); + + if (pch_iir & SDE_GMBUS_CPT) + intel_gmbus_irq_handler(dev_priv); + + if (pch_iir & SDE_AUDIO_CP_REQ_CPT) + drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n"); + + if (pch_iir & SDE_AUDIO_CP_CHG_CPT) + drm_dbg(&dev_priv->drm, "Audio CP change interrupt\n"); + + if (pch_iir & SDE_FDI_MASK_CPT) { + for_each_pipe(dev_priv, pipe) + drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", + pipe_name(pipe), + intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); + } + + if (pch_iir & SDE_ERROR_CPT) + cpt_serr_int_handler(dev_priv); +} + +void ilk_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) +{ + enum pipe pipe; + u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; + + if (hotplug_trigger) + ilk_hpd_irq_handler(dev_priv, hotplug_trigger); + + if (de_iir & DE_AUX_CHANNEL_A) + intel_dp_aux_irq_handler(dev_priv); + + if (de_iir & DE_GSE) + intel_opregion_asle_intr(dev_priv); + + if (de_iir & DE_POISON) + drm_err(&dev_priv->drm, "Poison interrupt\n"); + + for_each_pipe(dev_priv, pipe) { + if (de_iir & DE_PIPE_VBLANK(pipe)) + intel_handle_vblank(dev_priv, pipe); + + if (de_iir & DE_PLANE_FLIP_DONE(pipe)) + flip_done_handler(dev_priv, pipe); + + if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) + intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); + + if (de_iir & DE_PIPE_CRC_DONE(pipe)) + i9xx_pipe_crc_irq_handler(dev_priv, pipe); + } + + /* check event from PCH */ + if (de_iir & DE_PCH_EVENT) { + u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); + + if (HAS_PCH_CPT(dev_priv)) + cpt_irq_handler(dev_priv, pch_iir); + else + ibx_irq_handler(dev_priv, pch_iir); + + /* should clear PCH hotplug event before clear CPU irq */ + intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); + } + + if (DISPLAY_VER(dev_priv) == 5 && de_iir & DE_PCU_EVENT) + gen5_rps_irq_handler(&to_gt(dev_priv)->rps); +} + +void ivb_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) +{ + enum pipe pipe; + u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; + + if (hotplug_trigger) + ilk_hpd_irq_handler(dev_priv, hotplug_trigger); + + if (de_iir & DE_ERR_INT_IVB) + ivb_err_int_handler(dev_priv); + + if (de_iir & DE_AUX_CHANNEL_A_IVB) + intel_dp_aux_irq_handler(dev_priv); + + if (de_iir & DE_GSE_IVB) + intel_opregion_asle_intr(dev_priv); + + for_each_pipe(dev_priv, pipe) { + if (de_iir & DE_PIPE_VBLANK_IVB(pipe)) + intel_handle_vblank(dev_priv, pipe); + + if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) + flip_done_handler(dev_priv, pipe); + } + + /* check event from PCH */ + if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) { + u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); + + cpt_irq_handler(dev_priv, pch_iir); + + /* clear PCH hotplug event before clear CPU irq */ + intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); + } +} + +static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) +{ + u32 mask; + + if (DISPLAY_VER(dev_priv) >= 14) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB; + else if (DISPLAY_VER(dev_priv) >= 13) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB | + TGL_DE_PORT_AUX_DDIC | + XELPD_DE_PORT_AUX_DDID | + XELPD_DE_PORT_AUX_DDIE | + TGL_DE_PORT_AUX_USBC1 | + TGL_DE_PORT_AUX_USBC2 | + TGL_DE_PORT_AUX_USBC3 | + TGL_DE_PORT_AUX_USBC4; + else if (DISPLAY_VER(dev_priv) >= 12) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB | + TGL_DE_PORT_AUX_DDIC | + TGL_DE_PORT_AUX_USBC1 | + TGL_DE_PORT_AUX_USBC2 | + TGL_DE_PORT_AUX_USBC3 | + TGL_DE_PORT_AUX_USBC4 | + TGL_DE_PORT_AUX_USBC5 | + TGL_DE_PORT_AUX_USBC6; + + mask = GEN8_AUX_CHANNEL_A; + if (DISPLAY_VER(dev_priv) >= 9) + mask |= GEN9_AUX_CHANNEL_B | + GEN9_AUX_CHANNEL_C | + GEN9_AUX_CHANNEL_D; + + if (DISPLAY_VER(dev_priv) == 11) { + mask |= ICL_AUX_CHANNEL_F; + mask |= ICL_AUX_CHANNEL_E; + } + + return mask; +} + +static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) +{ + if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) + return RKL_DE_PIPE_IRQ_FAULT_ERRORS; + else if (DISPLAY_VER(dev_priv) >= 11) + return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; + else if (DISPLAY_VER(dev_priv) >= 9) + return GEN9_DE_PIPE_IRQ_FAULT_ERRORS; + else + return GEN8_DE_PIPE_IRQ_FAULT_ERRORS; +} + +static void +gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) +{ + bool found = false; + + if (iir & GEN8_DE_MISC_GSE) { + intel_opregion_asle_intr(dev_priv); + found = true; + } + + if (iir & GEN8_DE_EDP_PSR) { + struct intel_encoder *encoder; + u32 psr_iir; + i915_reg_t iir_reg; + + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (DISPLAY_VER(dev_priv) >= 12) + iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder); + else + iir_reg = EDP_PSR_IIR; + + psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0); + + if (psr_iir) + found = true; + + intel_psr_irq_handler(intel_dp, psr_iir); + + /* prior GEN12 only have one EDP PSR */ + if (DISPLAY_VER(dev_priv) < 12) + break; + } + } + + if (!found) + drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); +} + +static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, + u32 te_trigger) +{ + enum pipe pipe = INVALID_PIPE; + enum transcoder dsi_trans; + enum port port; + u32 val, tmp; + + /* + * Incase of dual link, TE comes from DSI_1 + * this is to check if dual link is enabled + */ + val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0)); + val &= PORT_SYNC_MODE_ENABLE; + + /* + * if dual link is enabled, then read DSI_0 + * transcoder registers + */ + port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ? + PORT_A : PORT_B; + dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1; + + /* Check if DSI configured in command mode */ + val = intel_uncore_read(&dev_priv->uncore, DSI_TRANS_FUNC_CONF(dsi_trans)); + val = val & OP_MODE_MASK; + + if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) { + drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n"); + return; + } + + /* Get PIPE for handling VBLANK event */ + val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL(dsi_trans)); + switch (val & TRANS_DDI_EDP_INPUT_MASK) { + case TRANS_DDI_EDP_INPUT_A_ON: + pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + pipe = PIPE_C; + break; + default: + drm_err(&dev_priv->drm, "Invalid PIPE\n"); + return; + } + + intel_handle_vblank(dev_priv, pipe); + + /* clear TE in dsi IIR */ + port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; + tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); +} + +static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915) +{ + if (DISPLAY_VER(i915) >= 9) + return GEN9_PIPE_PLANE1_FLIP_DONE; + else + return GEN8_PIPE_PRIMARY_FLIP_DONE; +} + +u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv) +{ + u32 mask = GEN8_PIPE_FIFO_UNDERRUN; + + if (DISPLAY_VER(dev_priv) >= 13) + mask |= XELPD_PIPE_SOFT_UNDERRUN | + XELPD_PIPE_HARD_UNDERRUN; + + return mask; +} + +static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_iir, u32 *pica_iir) +{ + u32 pica_ier = 0; + + *pica_iir = 0; + *pch_iir = intel_de_read(i915, SDEIIR); + if (!*pch_iir) + return; + + /** + * PICA IER must be disabled/re-enabled around clearing PICA IIR and + * SDEIIR, to avoid losing PICA IRQs and to ensure that such IRQs set + * their flags both in the PICA and SDE IIR. + */ + if (*pch_iir & SDE_PICAINTERRUPT) { + drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); + + pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); + *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); + intel_de_write(i915, PICAINTERRUPT_IIR, *pica_iir); + } + + intel_de_write(i915, SDEIIR, *pch_iir); + + if (pica_ier) + intel_de_write(i915, PICAINTERRUPT_IER, pica_ier); +} + +void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) +{ + u32 iir; + enum pipe pipe; + + drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DISPLAY(dev_priv)); + + if (master_ctl & GEN8_DE_MISC_IRQ) { + iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); + if (iir) { + intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir); + gen8_de_misc_irq_handler(dev_priv, iir); + } else { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied (DE MISC)!\n"); + } + } + + if (DISPLAY_VER(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { + iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR); + if (iir) { + intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir); + gen11_hpd_irq_handler(dev_priv, iir); + } else { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied, (DE HPD)!\n"); + } + } + + if (master_ctl & GEN8_DE_PORT_IRQ) { + iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PORT_IIR); + if (iir) { + bool found = false; + + intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir); + + if (iir & gen8_de_port_aux_mask(dev_priv)) { + intel_dp_aux_irq_handler(dev_priv); + found = true; + } + + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { + u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; + + if (hotplug_trigger) { + bxt_hpd_irq_handler(dev_priv, hotplug_trigger); + found = true; + } + } else if (IS_BROADWELL(dev_priv)) { + u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK; + + if (hotplug_trigger) { + ilk_hpd_irq_handler(dev_priv, hotplug_trigger); + found = true; + } + } + + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + (iir & BXT_DE_PORT_GMBUS)) { + intel_gmbus_irq_handler(dev_priv); + found = true; + } + + if (DISPLAY_VER(dev_priv) >= 11) { + u32 te_trigger = iir & (DSI0_TE | DSI1_TE); + + if (te_trigger) { + gen11_dsi_te_interrupt_handler(dev_priv, te_trigger); + found = true; + } + } + + if (!found) + drm_err_ratelimited(&dev_priv->drm, + "Unexpected DE Port interrupt\n"); + } else { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied (DE PORT)!\n"); + } + } + + for_each_pipe(dev_priv, pipe) { + u32 fault_errors; + + if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) + continue; + + iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe)); + if (!iir) { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied (DE PIPE)!\n"); + continue; + } + + intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir); + + if (iir & GEN8_PIPE_VBLANK) + intel_handle_vblank(dev_priv, pipe); + + if (iir & gen8_de_pipe_flip_done_mask(dev_priv)) + flip_done_handler(dev_priv, pipe); + + if (iir & GEN8_PIPE_CDCLK_CRC_DONE) + hsw_pipe_crc_irq_handler(dev_priv, pipe); + + if (iir & gen8_de_pipe_underrun_mask(dev_priv)) + intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); + + fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv); + if (fault_errors) + drm_err_ratelimited(&dev_priv->drm, + "Fault errors on pipe %c: 0x%08x\n", + pipe_name(pipe), + fault_errors); + } + + if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) && + master_ctl & GEN8_DE_PCH_IRQ) { + u32 pica_iir; + + /* + * FIXME(BDW): Assume for now that the new interrupt handling + * scheme also closed the SDE interrupt handling race we've seen + * on older pch-split platforms. But this needs testing. + */ + gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir); + if (iir) { + if (pica_iir) + xelpdp_pica_irq_handler(dev_priv, pica_iir); + + if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + icp_irq_handler(dev_priv, iir); + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) + spt_irq_handler(dev_priv, iir); + else + cpt_irq_handler(dev_priv, iir); + } else { + /* + * Like on previous PCH there seems to be something + * fishy going on with forwarding PCH interrupts. + */ + drm_dbg(&dev_priv->drm, + "The master control interrupt lied (SDE)!\n"); + } + } +} + +u32 gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl) +{ + void __iomem * const regs = i915->uncore.regs; + u32 iir; + + if (!(master_ctl & GEN11_GU_MISC_IRQ)) + return 0; + + iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); + if (likely(iir)) + raw_reg_write(regs, GEN11_GU_MISC_IIR, iir); + + return iir; +} + +void gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir) +{ + if (iir & GEN11_GU_MISC_GSE) + intel_opregion_asle_intr(i915); +} + +void gen11_display_irq_handler(struct drm_i915_private *i915) +{ + void __iomem * const regs = i915->uncore.regs; + const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL); + + disable_rpm_wakeref_asserts(&i915->runtime_pm); + /* + * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ + * for the display related bits. + */ + raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, 0x0); + gen8_de_irq_handler(i915, disp_ctl); + raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, + GEN11_DISPLAY_IRQ_ENABLE); + + enable_rpm_wakeref_asserts(&i915->runtime_pm); +} + +/* Called from drm generic code, passed 'crtc' which + * we use as a pipe index + */ +int i8xx_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return 0; +} + +int i915gm_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + + /* + * Vblank interrupts fail to wake the device up from C2+. + * Disabling render clock gating during C-states avoids + * the problem. There is a small power cost so we do this + * only when vblank interrupts are actually enabled. + */ + if (dev_priv->vblank_enabled++ == 0) + intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); + + return i8xx_enable_vblank(crtc); +} + +int i965_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_enable_pipestat(dev_priv, pipe, + PIPE_START_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return 0; +} + +int ilk_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + u32 bit = DISPLAY_VER(dev_priv) >= 7 ? + DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ilk_enable_display_irq(dev_priv, bit); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + /* Even though there is no DMC, frame counter can get stuck when + * PSR is active as no frames are generated. + */ + if (HAS_PSR(dev_priv)) + drm_crtc_vblank_restore(crtc); + + return 0; +} + +static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, + bool enable) +{ + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + enum port port; + + if (!(intel_crtc->mode_flags & + (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) + return false; + + /* for dual link cases we consider TE from slave */ + if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1) + port = PORT_B; + else + port = PORT_A; + + intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT, + enable ? 0 : DSI_TE_EVENT); + + intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); + + return true; +} + +int bdw_enable_vblank(struct drm_crtc *_crtc) +{ + struct intel_crtc *crtc = to_intel_crtc(_crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + unsigned long irqflags; + + if (gen11_dsi_configure_te(crtc, true)) + return 0; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + /* Even if there is no DMC, frame counter can get stuck when + * PSR is active as no frames are generated, so check only for PSR. + */ + if (HAS_PSR(dev_priv)) + drm_crtc_vblank_restore(&crtc->base); + + return 0; +} + +/* Called from drm generic code, passed 'crtc' which + * we use as a pipe index + */ +void i8xx_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void i915gm_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + + i8xx_disable_vblank(crtc); + + if (--dev_priv->vblank_enabled == 0) + intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); +} + +void i965_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_disable_pipestat(dev_priv, pipe, + PIPE_START_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void ilk_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + u32 bit = DISPLAY_VER(dev_priv) >= 7 ? + DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ilk_disable_display_irq(dev_priv, bit); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void bdw_disable_vblank(struct drm_crtc *_crtc) +{ + struct intel_crtc *crtc = to_intel_crtc(_crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + unsigned long irqflags; + + if (gen11_dsi_configure_te(crtc, false)) + return; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void vlv_display_irq_reset(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + if (IS_CHERRYVIEW(dev_priv)) + intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); + else + intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); + + i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); + intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); + + i9xx_pipestat_irq_reset(dev_priv); + + GEN3_IRQ_RESET(uncore, VLV_); + dev_priv->irq_mask = ~0u; +} + +void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + u32 pipestat_mask; + u32 enable_mask; + enum pipe pipe; + + pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS; + + i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); + for_each_pipe(dev_priv, pipe) + i915_enable_pipestat(dev_priv, pipe, pipestat_mask); + + enable_mask = I915_DISPLAY_PORT_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT; + + if (IS_CHERRYVIEW(dev_priv)) + enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | + I915_LPE_PIPE_C_INTERRUPT; + + drm_WARN_ON(&dev_priv->drm, dev_priv->irq_mask != ~0u); + + dev_priv->irq_mask = ~enable_mask; + + GEN3_IRQ_INIT(uncore, VLV_, dev_priv->irq_mask, enable_mask); +} + +void gen8_display_irq_reset(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + enum pipe pipe; + + if (!HAS_DISPLAY(dev_priv)) + return; + + intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); + intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); + + for_each_pipe(dev_priv, pipe) + if (intel_display_power_is_enabled(dev_priv, + POWER_DOMAIN_PIPE(pipe))) + GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); + + GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); + GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); +} + +void gen11_display_irq_reset(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + enum pipe pipe; + u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | + BIT(TRANSCODER_C) | BIT(TRANSCODER_D); + + if (!HAS_DISPLAY(dev_priv)) + return; + + intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0); + + if (DISPLAY_VER(dev_priv) >= 12) { + enum transcoder trans; + + for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { + enum intel_display_power_domain domain; + + domain = POWER_DOMAIN_TRANSCODER(trans); + if (!intel_display_power_is_enabled(dev_priv, domain)) + continue; + + intel_uncore_write(uncore, TRANS_PSR_IMR(trans), 0xffffffff); + intel_uncore_write(uncore, TRANS_PSR_IIR(trans), 0xffffffff); + } + } else { + intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); + intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); + } + + for_each_pipe(dev_priv, pipe) + if (intel_display_power_is_enabled(dev_priv, + POWER_DOMAIN_PIPE(pipe))) + GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); + + GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); + GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); + + if (DISPLAY_VER(dev_priv) >= 14) + GEN3_IRQ_RESET(uncore, PICAINTERRUPT_); + else + GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); + + if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + GEN3_IRQ_RESET(uncore, SDE); +} + +void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, + u8 pipe_mask) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 extra_ier = GEN8_PIPE_VBLANK | + gen8_de_pipe_underrun_mask(dev_priv) | + gen8_de_pipe_flip_done_mask(dev_priv); + enum pipe pipe; + + spin_lock_irq(&dev_priv->irq_lock); + + if (!intel_irqs_enabled(dev_priv)) { + spin_unlock_irq(&dev_priv->irq_lock); + return; + } + + for_each_pipe_masked(dev_priv, pipe, pipe_mask) + GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, + dev_priv->de_irq_mask[pipe], + ~dev_priv->de_irq_mask[pipe] | extra_ier); + + spin_unlock_irq(&dev_priv->irq_lock); +} + +void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, + u8 pipe_mask) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + enum pipe pipe; + + spin_lock_irq(&dev_priv->irq_lock); + + if (!intel_irqs_enabled(dev_priv)) { + spin_unlock_irq(&dev_priv->irq_lock); + return; + } + + for_each_pipe_masked(dev_priv, pipe, pipe_mask) + GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); + + spin_unlock_irq(&dev_priv->irq_lock); + + /* make sure we're done processing display irqs */ + intel_synchronize_irq(dev_priv); +} + +/* + * SDEIER is also touched by the interrupt handler to work around missed PCH + * interrupts. Hence we can't update it after the interrupt handler is enabled - + * instead we unconditionally enable all PCH interrupt sources here, but then + * only unmask them as needed with SDEIMR. + * + * Note that we currently do this after installing the interrupt handler, + * but before we enable the master interrupt. That should be sufficient + * to avoid races with the irq handler, assuming we have MSI. Shared legacy + * interrupts could still race. + */ +void ibx_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 mask; + + if (HAS_PCH_NOP(dev_priv)) + return; + + if (HAS_PCH_IBX(dev_priv)) + mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; + else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; + else + mask = SDE_GMBUS_CPT; + + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); +} + +void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) +{ + lockdep_assert_held(&dev_priv->irq_lock); + + if (dev_priv->display_irqs_enabled) + return; + + dev_priv->display_irqs_enabled = true; + + if (intel_irqs_enabled(dev_priv)) { + vlv_display_irq_reset(dev_priv); + vlv_display_irq_postinstall(dev_priv); + } +} + +void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) +{ + lockdep_assert_held(&dev_priv->irq_lock); + + if (!dev_priv->display_irqs_enabled) + return; + + dev_priv->display_irqs_enabled = false; + + if (intel_irqs_enabled(dev_priv)) + vlv_display_irq_reset(dev_priv); +} + +void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + u32 de_pipe_masked = gen8_de_pipe_fault_mask(dev_priv) | + GEN8_PIPE_CDCLK_CRC_DONE; + u32 de_pipe_enables; + u32 de_port_masked = gen8_de_port_aux_mask(dev_priv); + u32 de_port_enables; + u32 de_misc_masked = GEN8_DE_EDP_PSR; + u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | + BIT(TRANSCODER_C) | BIT(TRANSCODER_D); + enum pipe pipe; + + if (!HAS_DISPLAY(dev_priv)) + return; + + if (DISPLAY_VER(dev_priv) <= 10) + de_misc_masked |= GEN8_DE_MISC_GSE; + + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + de_port_masked |= BXT_DE_PORT_GMBUS; + + if (DISPLAY_VER(dev_priv) >= 11) { + enum port port; + + if (intel_bios_is_dsi_present(dev_priv, &port)) + de_port_masked |= DSI0_TE | DSI1_TE; + } + + de_pipe_enables = de_pipe_masked | + GEN8_PIPE_VBLANK | + gen8_de_pipe_underrun_mask(dev_priv) | + gen8_de_pipe_flip_done_mask(dev_priv); + + de_port_enables = de_port_masked; + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; + else if (IS_BROADWELL(dev_priv)) + de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; + + if (DISPLAY_VER(dev_priv) >= 12) { + enum transcoder trans; + + for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { + enum intel_display_power_domain domain; + + domain = POWER_DOMAIN_TRANSCODER(trans); + if (!intel_display_power_is_enabled(dev_priv, domain)) + continue; + + gen3_assert_iir_is_zero(uncore, TRANS_PSR_IIR(trans)); + } + } else { + gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR); + } + + for_each_pipe(dev_priv, pipe) { + dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; + + if (intel_display_power_is_enabled(dev_priv, + POWER_DOMAIN_PIPE(pipe))) + GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, + dev_priv->de_irq_mask[pipe], + de_pipe_enables); + } + + GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables); + GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); + + if (IS_DISPLAY_VER(dev_priv, 11, 13)) { + u32 de_hpd_masked = 0; + u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | + GEN11_DE_TBT_HOTPLUG_MASK; + + GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked, + de_hpd_enables); + } +} + +void mtp_irq_postinstall(struct drm_i915_private *i915) +{ + struct intel_uncore *uncore = &i915->uncore; + u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT; + u32 de_hpd_mask = XELPDP_AUX_TC_MASK; + u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK | + XELPDP_TBT_HOTPLUG_MASK; + + GEN3_IRQ_INIT(uncore, PICAINTERRUPT_, ~de_hpd_mask, + de_hpd_enables); + + GEN3_IRQ_INIT(uncore, SDE, ~sde_mask, 0xffffffff); +} + +void icp_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 mask = SDE_GMBUS_ICP; + + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); +} + +void gen11_de_irq_postinstall(struct drm_i915_private *dev_priv) +{ + if (!HAS_DISPLAY(dev_priv)) + return; + + gen8_de_irq_postinstall(dev_priv); + + intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, + GEN11_DISPLAY_IRQ_ENABLE); +} + diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h new file mode 100644 index 000000000000..8db03e83d23d --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_irq.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DISPLAY_IRQ_H__ +#define __INTEL_DISPLAY_IRQ_H__ + +#include <linux/types.h> + +#include "intel_display_limits.h" + +enum pipe; +struct drm_i915_private; +struct drm_crtc; + +void valleyview_enable_display_irqs(struct drm_i915_private *i915); +void valleyview_disable_display_irqs(struct drm_i915_private *i915); + +void ilk_update_display_irq(struct drm_i915_private *i915, + u32 interrupt_mask, u32 enabled_irq_mask); +void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits); +void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits); + +void bdw_update_port_irq(struct drm_i915_private *i915, u32 interrupt_mask, u32 enabled_irq_mask); +void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); +void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); + +void ibx_display_interrupt_update(struct drm_i915_private *i915, + u32 interrupt_mask, u32 enabled_irq_mask); +void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits); +void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits); + +void gen8_irq_power_well_post_enable(struct drm_i915_private *i915, u8 pipe_mask); +void gen8_irq_power_well_pre_disable(struct drm_i915_private *i915, u8 pipe_mask); +u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *i915); + +int i8xx_enable_vblank(struct drm_crtc *crtc); +int i915gm_enable_vblank(struct drm_crtc *crtc); +int i965_enable_vblank(struct drm_crtc *crtc); +int ilk_enable_vblank(struct drm_crtc *crtc); +int bdw_enable_vblank(struct drm_crtc *crtc); +void i8xx_disable_vblank(struct drm_crtc *crtc); +void i915gm_disable_vblank(struct drm_crtc *crtc); +void i965_disable_vblank(struct drm_crtc *crtc); +void ilk_disable_vblank(struct drm_crtc *crtc); +void bdw_disable_vblank(struct drm_crtc *crtc); + +void ivb_display_irq_handler(struct drm_i915_private *i915, u32 de_iir); +void ilk_display_irq_handler(struct drm_i915_private *i915, u32 de_iir); +void gen8_de_irq_handler(struct drm_i915_private *i915, u32 master_ctl); +void gen11_display_irq_handler(struct drm_i915_private *i915); + +u32 gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl); +void gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir); + +void vlv_display_irq_reset(struct drm_i915_private *i915); +void gen8_display_irq_reset(struct drm_i915_private *i915); +void gen11_display_irq_reset(struct drm_i915_private *i915); + +void ibx_irq_postinstall(struct drm_i915_private *i915); +void vlv_display_irq_postinstall(struct drm_i915_private *i915); +void icp_irq_postinstall(struct drm_i915_private *i915); +void gen8_de_irq_postinstall(struct drm_i915_private *i915); +void mtp_irq_postinstall(struct drm_i915_private *i915); +void gen11_de_irq_postinstall(struct drm_i915_private *i915); + +u32 i915_pipestat_enable_mask(struct drm_i915_private *i915, enum pipe pipe); +void i915_enable_pipestat(struct drm_i915_private *i915, enum pipe pipe, u32 status_mask); +void i915_disable_pipestat(struct drm_i915_private *i915, enum pipe pipe, u32 status_mask); +void i915_enable_asle_pipestat(struct drm_i915_private *i915); +void i9xx_pipestat_irq_reset(struct drm_i915_private *i915); + +void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); + +void i915_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_stats[I915_MAX_PIPES]); +void i965_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_stats[I915_MAX_PIPES]); +void valleyview_pipestat_irq_handler(struct drm_i915_private *i915, u32 pipe_stats[I915_MAX_PIPES]); +void i8xx_pipestat_irq_handler(struct drm_i915_private *i915, u16 iir, u32 pipe_stats[I915_MAX_PIPES]); + +#endif /* __INTEL_DISPLAY_IRQ_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 41eabdf3e871..916009894d89 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -11,6 +11,7 @@ #include "intel_combo_phy_regs.h" #include "intel_crt.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_dkl_phy.h" diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c index e7f77a225739..09a7fa6c0c37 100644 --- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c +++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c @@ -27,8 +27,8 @@ #include "i915_drv.h" #include "i915_reg.h" -#include "i915_irq.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_fbc.h" diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 1d7ae49e073e..f95fa793fabb 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -4,9 +4,9 @@ */ #include "i915_drv.h" -#include "i915_irq.h" #include "i915_reg.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_dp_aux.h" #include "intel_gmbus.h" diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 96fe4a280077..36b479b46b60 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -35,11 +35,11 @@ #include <drm/drm_edid.h> #include "i915_drv.h" -#include "i915_irq.h" #include "i915_reg.h" #include "intel_connector.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_dpll.h" #include "intel_hotplug.h" diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 8ea0598a5a07..1ea664a366c1 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -9,10 +9,10 @@ #include <drm/drm_fourcc.h> #include "i915_drv.h" -#include "i915_irq.h" #include "i915_reg.h" #include "intel_atomic_plane.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 80968e49e2c3..e68a99205599 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -8,6 +8,7 @@ #include <drm/i915_drm.h> #include "display/intel_display.h" +#include "display/intel_display_irq.h" #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 61f53b283210..82fbabcdd7a5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -33,18 +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_dp_aux.h" -#include "display/intel_fdi_regs.h" -#include "display/intel_fifo_underrun.h" -#include "display/intel_gmbus.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" @@ -85,14 +78,6 @@ static inline void pmu_irq_stats(struct drm_i915_private *i915, WRITE_ONCE(i915->pmu.irq_count, i915->pmu.irq_count + 1); } -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) { @@ -125,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); @@ -179,268 +164,6 @@ static void gen2_irq_init(struct intel_uncore *uncore, intel_uncore_posting_read16(uncore, GEN2_IMR); } -/** - * 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 - */ -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 - */ -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 - */ -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. @@ -525,278 +248,6 @@ static void ivb_parity_work(struct work_struct *work) mutex_unlock(&dev_priv->drm.struct_mutex); } -#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) - intel_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) - intel_gmbus_irq_handler(dev_priv); -} - static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_i915_private *dev_priv = arg; @@ -961,217 +412,6 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) return ret; } -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) - intel_dp_aux_irq_handler(dev_priv); - - if (pch_iir & SDE_GMBUS) - intel_gmbus_irq_handler(dev_priv); - - if (pch_iir & SDE_AUDIO_HDCP_MASK) - drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n"); - - if (pch_iir & SDE_AUDIO_TRANS_MASK) - drm_dbg(&dev_priv->drm, "PCH transcoder audio interrupt\n"); - - if (pch_iir & SDE_POISON) - drm_err(&dev_priv->drm, "PCH poison interrupt\n"); - - if (pch_iir & SDE_FDI_MASK) { - for_each_pipe(dev_priv, pipe) - drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", - pipe_name(pipe), - intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); - } - - if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) - drm_dbg(&dev_priv->drm, "PCH transcoder CRC done interrupt\n"); - - if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) - drm_dbg(&dev_priv->drm, - "PCH transcoder CRC error interrupt\n"); - - if (pch_iir & SDE_TRANSA_FIFO_UNDER) - intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A); - - if (pch_iir & SDE_TRANSB_FIFO_UNDER) - intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B); -} - -static void ivb_err_int_handler(struct drm_i915_private *dev_priv) -{ - u32 err_int = intel_uncore_read(&dev_priv->uncore, GEN7_ERR_INT); - enum pipe pipe; - - if (err_int & ERR_INT_POISON) - drm_err(&dev_priv->drm, "Poison interrupt\n"); - - for_each_pipe(dev_priv, pipe) { - if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) - intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); - - if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { - if (IS_IVYBRIDGE(dev_priv)) - ivb_pipe_crc_irq_handler(dev_priv, pipe); - else - hsw_pipe_crc_irq_handler(dev_priv, pipe); - } - } - - intel_uncore_write(&dev_priv->uncore, GEN7_ERR_INT, err_int); -} - -static void cpt_serr_int_handler(struct drm_i915_private *dev_priv) -{ - u32 serr_int = intel_uncore_read(&dev_priv->uncore, SERR_INT); - enum pipe pipe; - - if (serr_int & SERR_INT_POISON) - drm_err(&dev_priv->drm, "PCH poison interrupt\n"); - - for_each_pipe(dev_priv, pipe) - if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe)) - intel_pch_fifo_underrun_irq_handler(dev_priv, pipe); - - intel_uncore_write(&dev_priv->uncore, SERR_INT, serr_int); -} - -static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) -{ - enum pipe pipe; - u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - - ibx_hpd_irq_handler(dev_priv, hotplug_trigger); - - if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { - int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> - SDE_AUDIO_POWER_SHIFT_CPT); - drm_dbg(&dev_priv->drm, "PCH audio power change on port %c\n", - port_name(port)); - } - - if (pch_iir & SDE_AUX_MASK_CPT) - intel_dp_aux_irq_handler(dev_priv); - - if (pch_iir & SDE_GMBUS_CPT) - intel_gmbus_irq_handler(dev_priv); - - if (pch_iir & SDE_AUDIO_CP_REQ_CPT) - drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n"); - - if (pch_iir & SDE_AUDIO_CP_CHG_CPT) - drm_dbg(&dev_priv->drm, "Audio CP change interrupt\n"); - - if (pch_iir & SDE_FDI_MASK_CPT) { - for_each_pipe(dev_priv, pipe) - drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", - pipe_name(pipe), - intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); - } - - if (pch_iir & SDE_ERROR_CPT) - cpt_serr_int_handler(dev_priv); -} - -static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, - u32 de_iir) -{ - enum pipe pipe; - u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; - - if (hotplug_trigger) - ilk_hpd_irq_handler(dev_priv, hotplug_trigger); - - if (de_iir & DE_AUX_CHANNEL_A) - intel_dp_aux_irq_handler(dev_priv); - - if (de_iir & DE_GSE) - intel_opregion_asle_intr(dev_priv); - - if (de_iir & DE_POISON) - drm_err(&dev_priv->drm, "Poison interrupt\n"); - - for_each_pipe(dev_priv, pipe) { - if (de_iir & DE_PIPE_VBLANK(pipe)) - intel_handle_vblank(dev_priv, pipe); - - if (de_iir & DE_PLANE_FLIP_DONE(pipe)) - flip_done_handler(dev_priv, pipe); - - if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) - intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); - - if (de_iir & DE_PIPE_CRC_DONE(pipe)) - i9xx_pipe_crc_irq_handler(dev_priv, pipe); - } - - /* check event from PCH */ - if (de_iir & DE_PCH_EVENT) { - u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); - - if (HAS_PCH_CPT(dev_priv)) - cpt_irq_handler(dev_priv, pch_iir); - else - ibx_irq_handler(dev_priv, pch_iir); - - /* should clear PCH hotplug event before clear CPU irq */ - intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); - } - - if (DISPLAY_VER(dev_priv) == 5 && de_iir & DE_PCU_EVENT) - gen5_rps_irq_handler(&to_gt(dev_priv)->rps); -} - -static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, - u32 de_iir) -{ - enum pipe pipe; - u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; - - if (hotplug_trigger) - ilk_hpd_irq_handler(dev_priv, hotplug_trigger); - - if (de_iir & DE_ERR_INT_IVB) - ivb_err_int_handler(dev_priv); - - if (de_iir & DE_AUX_CHANNEL_A_IVB) - intel_dp_aux_irq_handler(dev_priv); - - if (de_iir & DE_GSE_IVB) - intel_opregion_asle_intr(dev_priv); - - for_each_pipe(dev_priv, pipe) { - if (de_iir & DE_PIPE_VBLANK_IVB(pipe)) - intel_handle_vblank(dev_priv, pipe); - - if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) - flip_done_handler(dev_priv, pipe); - } - - /* check event from PCH */ - if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) { - u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); - - cpt_irq_handler(dev_priv, pch_iir); - - /* clear PCH hotplug event before clear CPU irq */ - intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); - } -} - /* * To handle irqs with the minimum potential races with fresh interrupts, we: * 1 - Disable Master Interrupt Control. @@ -1246,353 +486,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) /* IRQs are synced during runtime_suspend, we don't require a wakeref */ enable_rpm_wakeref_asserts(&i915->runtime_pm); - - return ret; -} - -static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) -{ - u32 mask; - - if (DISPLAY_VER(dev_priv) >= 14) - return TGL_DE_PORT_AUX_DDIA | - TGL_DE_PORT_AUX_DDIB; - else if (DISPLAY_VER(dev_priv) >= 13) - return TGL_DE_PORT_AUX_DDIA | - TGL_DE_PORT_AUX_DDIB | - TGL_DE_PORT_AUX_DDIC | - XELPD_DE_PORT_AUX_DDID | - XELPD_DE_PORT_AUX_DDIE | - TGL_DE_PORT_AUX_USBC1 | - TGL_DE_PORT_AUX_USBC2 | - TGL_DE_PORT_AUX_USBC3 | - TGL_DE_PORT_AUX_USBC4; - else if (DISPLAY_VER(dev_priv) >= 12) - return TGL_DE_PORT_AUX_DDIA | - TGL_DE_PORT_AUX_DDIB | - TGL_DE_PORT_AUX_DDIC | - TGL_DE_PORT_AUX_USBC1 | - TGL_DE_PORT_AUX_USBC2 | - TGL_DE_PORT_AUX_USBC3 | - TGL_DE_PORT_AUX_USBC4 | - TGL_DE_PORT_AUX_USBC5 | - TGL_DE_PORT_AUX_USBC6; - - - mask = GEN8_AUX_CHANNEL_A; - if (DISPLAY_VER(dev_priv) >= 9) - mask |= GEN9_AUX_CHANNEL_B | - GEN9_AUX_CHANNEL_C | - GEN9_AUX_CHANNEL_D; - - if (DISPLAY_VER(dev_priv) == 11) { - mask |= ICL_AUX_CHANNEL_F; - mask |= ICL_AUX_CHANNEL_E; - } - - return mask; -} - -static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) -{ - if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) - return RKL_DE_PIPE_IRQ_FAULT_ERRORS; - else if (DISPLAY_VER(dev_priv) >= 11) - return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; - else if (DISPLAY_VER(dev_priv) >= 9) - return GEN9_DE_PIPE_IRQ_FAULT_ERRORS; - else - return GEN8_DE_PIPE_IRQ_FAULT_ERRORS; -} - -static void -gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) -{ - bool found = false; - - if (iir & GEN8_DE_MISC_GSE) { - intel_opregion_asle_intr(dev_priv); - found = true; - } - - if (iir & GEN8_DE_EDP_PSR) { - struct intel_encoder *encoder; - u32 psr_iir; - i915_reg_t iir_reg; - - for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - if (DISPLAY_VER(dev_priv) >= 12) - iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder); - else - iir_reg = EDP_PSR_IIR; - - psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0); - - if (psr_iir) - found = true; - - intel_psr_irq_handler(intel_dp, psr_iir); - - /* prior GEN12 only have one EDP PSR */ - if (DISPLAY_VER(dev_priv) < 12) - break; - } - } - - if (!found) - drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); -} - -static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, - u32 te_trigger) -{ - enum pipe pipe = INVALID_PIPE; - enum transcoder dsi_trans; - enum port port; - u32 val, tmp; - - /* - * Incase of dual link, TE comes from DSI_1 - * this is to check if dual link is enabled - */ - val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0)); - val &= PORT_SYNC_MODE_ENABLE; - - /* - * if dual link is enabled, then read DSI_0 - * transcoder registers - */ - port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ? - PORT_A : PORT_B; - dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1; - - /* Check if DSI configured in command mode */ - val = intel_uncore_read(&dev_priv->uncore, DSI_TRANS_FUNC_CONF(dsi_trans)); - val = val & OP_MODE_MASK; - - if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) { - drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n"); - return; - } - - /* Get PIPE for handling VBLANK event */ - val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL(dsi_trans)); - switch (val & TRANS_DDI_EDP_INPUT_MASK) { - case TRANS_DDI_EDP_INPUT_A_ON: - pipe = PIPE_A; - break; - case TRANS_DDI_EDP_INPUT_B_ONOFF: - pipe = PIPE_B; - break; - case TRANS_DDI_EDP_INPUT_C_ONOFF: - pipe = PIPE_C; - break; - default: - drm_err(&dev_priv->drm, "Invalid PIPE\n"); - return; - } - - intel_handle_vblank(dev_priv, pipe); - - /* clear TE in dsi IIR */ - port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; - tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); -} - -static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915) -{ - if (DISPLAY_VER(i915) >= 9) - return GEN9_PIPE_PLANE1_FLIP_DONE; - else - return GEN8_PIPE_PRIMARY_FLIP_DONE; -} - -u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv) -{ - u32 mask = GEN8_PIPE_FIFO_UNDERRUN; - - if (DISPLAY_VER(dev_priv) >= 13) - mask |= XELPD_PIPE_SOFT_UNDERRUN | - XELPD_PIPE_HARD_UNDERRUN; - - return mask; -} - -static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_iir, u32 *pica_iir) -{ - u32 pica_ier = 0; - - *pica_iir = 0; - *pch_iir = intel_de_read(i915, SDEIIR); - if (!*pch_iir) - return; - - /** - * PICA IER must be disabled/re-enabled around clearing PICA IIR and - * SDEIIR, to avoid losing PICA IRQs and to ensure that such IRQs set - * their flags both in the PICA and SDE IIR. - */ - if (*pch_iir & SDE_PICAINTERRUPT) { - drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); - - pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); - *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); - intel_de_write(i915, PICAINTERRUPT_IIR, *pica_iir); - } - - intel_de_write(i915, SDEIIR, *pch_iir); - - if (pica_ier) - intel_de_write(i915, PICAINTERRUPT_IER, pica_ier); -} - -static void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) -{ - u32 iir; - enum pipe pipe; - - drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DISPLAY(dev_priv)); - - if (master_ctl & GEN8_DE_MISC_IRQ) { - iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); - if (iir) { - intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir); - gen8_de_misc_irq_handler(dev_priv, iir); - } else { - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied (DE MISC)!\n"); - } - } - - if (DISPLAY_VER(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { - iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR); - if (iir) { - intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir); - gen11_hpd_irq_handler(dev_priv, iir); - } else { - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied, (DE HPD)!\n"); - } - } - - if (master_ctl & GEN8_DE_PORT_IRQ) { - iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PORT_IIR); - if (iir) { - bool found = false; - - intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir); - - if (iir & gen8_de_port_aux_mask(dev_priv)) { - intel_dp_aux_irq_handler(dev_priv); - found = true; - } - - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { - u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; - - if (hotplug_trigger) { - bxt_hpd_irq_handler(dev_priv, hotplug_trigger); - found = true; - } - } else if (IS_BROADWELL(dev_priv)) { - u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK; - - if (hotplug_trigger) { - ilk_hpd_irq_handler(dev_priv, hotplug_trigger); - found = true; - } - } - - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && - (iir & BXT_DE_PORT_GMBUS)) { - intel_gmbus_irq_handler(dev_priv); - found = true; - } - - if (DISPLAY_VER(dev_priv) >= 11) { - u32 te_trigger = iir & (DSI0_TE | DSI1_TE); - - if (te_trigger) { - gen11_dsi_te_interrupt_handler(dev_priv, te_trigger); - found = true; - } - } - - if (!found) - drm_err_ratelimited(&dev_priv->drm, - "Unexpected DE Port interrupt\n"); - } - else - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied (DE PORT)!\n"); - } - - for_each_pipe(dev_priv, pipe) { - u32 fault_errors; - - if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) - continue; - - iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe)); - if (!iir) { - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied (DE PIPE)!\n"); - continue; - } - - intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir); - - if (iir & GEN8_PIPE_VBLANK) - intel_handle_vblank(dev_priv, pipe); - - if (iir & gen8_de_pipe_flip_done_mask(dev_priv)) - flip_done_handler(dev_priv, pipe); - - if (iir & GEN8_PIPE_CDCLK_CRC_DONE) - hsw_pipe_crc_irq_handler(dev_priv, pipe); - - if (iir & gen8_de_pipe_underrun_mask(dev_priv)) - intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); - - fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv); - if (fault_errors) - drm_err_ratelimited(&dev_priv->drm, - "Fault errors on pipe %c: 0x%08x\n", - pipe_name(pipe), - fault_errors); - } - - if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) && - master_ctl & GEN8_DE_PCH_IRQ) { - u32 pica_iir; - - /* - * FIXME(BDW): Assume for now that the new interrupt handling - * scheme also closed the SDE interrupt handling race we've seen - * on older pch-split platforms. But this needs testing. - */ - gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir); - if (iir) { - if (pica_iir) - xelpdp_pica_irq_handler(dev_priv, pica_iir); - - if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - icp_irq_handler(dev_priv, iir); - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) - spt_irq_handler(dev_priv, iir); - else - cpt_irq_handler(dev_priv, iir); - } else { - /* - * Like on previous PCH there seems to be something - * fishy going on with forwarding PCH interrupts. - */ - drm_dbg(&dev_priv->drm, - "The master control interrupt lied (SDE)!\n"); - } - } + + return ret; } static inline u32 gen8_master_intr_disable(void __iomem * const regs) @@ -1645,29 +540,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static u32 -gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl) -{ - void __iomem * const regs = i915->uncore.regs; - u32 iir; - - if (!(master_ctl & GEN11_GU_MISC_IRQ)) - return 0; - - iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); - if (likely(iir)) - raw_reg_write(regs, GEN11_GU_MISC_IIR, iir); - - return iir; -} - -static void -gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir) -{ - if (iir & GEN11_GU_MISC_GSE) - intel_opregion_asle_intr(i915); -} - static inline u32 gen11_master_intr_disable(void __iomem * const regs) { raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0); @@ -1686,25 +558,6 @@ static inline void gen11_master_intr_enable(void __iomem * const regs) raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ); } -static void -gen11_display_irq_handler(struct drm_i915_private *i915) -{ - void __iomem * const regs = i915->uncore.regs; - const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL); - - disable_rpm_wakeref_asserts(&i915->runtime_pm); - /* - * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ - * for the display related bits. - */ - raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, 0x0); - gen8_de_irq_handler(i915, disp_ctl); - raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, - GEN11_DISPLAY_IRQ_ENABLE); - - enable_rpm_wakeref_asserts(&i915->runtime_pm); -} - static irqreturn_t gen11_irq_handler(int irq, void *arg) { struct drm_i915_private *i915 = arg; @@ -1806,184 +659,6 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -/* Called from drm generic code, passed 'crtc' which - * we use as a pipe index - */ -int i8xx_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - return 0; -} - -int i915gm_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - - /* - * Vblank interrupts fail to wake the device up from C2+. - * Disabling render clock gating during C-states avoids - * the problem. There is a small power cost so we do this - * only when vblank interrupts are actually enabled. - */ - if (dev_priv->vblank_enabled++ == 0) - intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); - - return i8xx_enable_vblank(crtc); -} - -int i965_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_enable_pipestat(dev_priv, pipe, - PIPE_START_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - return 0; -} - -int ilk_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - u32 bit = DISPLAY_VER(dev_priv) >= 7 ? - DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - ilk_enable_display_irq(dev_priv, bit); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - /* Even though there is no DMC, frame counter can get stuck when - * PSR is active as no frames are generated. - */ - if (HAS_PSR(dev_priv)) - drm_crtc_vblank_restore(crtc); - - return 0; -} - -static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, - bool enable) -{ - struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); - enum port port; - - if (!(intel_crtc->mode_flags & - (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) - return false; - - /* for dual link cases we consider TE from slave */ - if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1) - port = PORT_B; - else - port = PORT_A; - - intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT, - enable ? 0 : DSI_TE_EVENT); - - intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); - - return true; -} - -int bdw_enable_vblank(struct drm_crtc *_crtc) -{ - struct intel_crtc *crtc = to_intel_crtc(_crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - unsigned long irqflags; - - if (gen11_dsi_configure_te(crtc, true)) - return 0; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - /* Even if there is no DMC, frame counter can get stuck when - * PSR is active as no frames are generated, so check only for PSR. - */ - if (HAS_PSR(dev_priv)) - drm_crtc_vblank_restore(&crtc->base); - - return 0; -} - -/* Called from drm generic code, passed 'crtc' which - * we use as a pipe index - */ -void i8xx_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - -void i915gm_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - - i8xx_disable_vblank(crtc); - - if (--dev_priv->vblank_enabled == 0) - intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); -} - -void i965_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_disable_pipestat(dev_priv, pipe, - PIPE_START_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - -void ilk_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - u32 bit = DISPLAY_VER(dev_priv) >= 7 ? - DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - ilk_disable_display_irq(dev_priv, bit); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - -void bdw_disable_vblank(struct drm_crtc *_crtc) -{ - struct intel_crtc *crtc = to_intel_crtc(_crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - unsigned long irqflags; - - if (gen11_dsi_configure_te(crtc, false)) - return; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - static void ibx_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -1997,55 +672,6 @@ static void ibx_irq_reset(struct drm_i915_private *dev_priv) intel_uncore_write(&dev_priv->uncore, SERR_INT, 0xffffffff); } -static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - - if (IS_CHERRYVIEW(dev_priv)) - intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); - else - intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); - - i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); - intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); - - i9xx_pipestat_irq_reset(dev_priv); - - GEN3_IRQ_RESET(uncore, VLV_); - dev_priv->irq_mask = ~0u; -} - -static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - - u32 pipestat_mask; - u32 enable_mask; - enum pipe pipe; - - pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS; - - i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); - for_each_pipe(dev_priv, pipe) - i915_enable_pipestat(dev_priv, pipe, pipestat_mask); - - enable_mask = I915_DISPLAY_PORT_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_LPE_PIPE_A_INTERRUPT | - I915_LPE_PIPE_B_INTERRUPT; - - if (IS_CHERRYVIEW(dev_priv)) - enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | - I915_LPE_PIPE_C_INTERRUPT; - - drm_WARN_ON(&dev_priv->drm, dev_priv->irq_mask != ~0u); - - dev_priv->irq_mask = ~enable_mask; - - GEN3_IRQ_INIT(uncore, VLV_, dev_priv->irq_mask, enable_mask); -} - /* drm_dma.h hooks */ static void ilk_irq_reset(struct drm_i915_private *dev_priv) @@ -2081,26 +707,6 @@ static void valleyview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } -static void gen8_display_irq_reset(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - enum pipe pipe; - - if (!HAS_DISPLAY(dev_priv)) - return; - - intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); - intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); - - for_each_pipe(dev_priv, pipe) - if (intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_PIPE(pipe))) - GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); - - GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); - GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); -} - static void gen8_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2116,53 +722,6 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv) } -static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - enum pipe pipe; - u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | - BIT(TRANSCODER_C) | BIT(TRANSCODER_D); - - if (!HAS_DISPLAY(dev_priv)) - return; - - intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0); - - if (DISPLAY_VER(dev_priv) >= 12) { - enum transcoder trans; - - for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { - enum intel_display_power_domain domain; - - domain = POWER_DOMAIN_TRANSCODER(trans); - if (!intel_display_power_is_enabled(dev_priv, domain)) - continue; - - intel_uncore_write(uncore, TRANS_PSR_IMR(trans), 0xffffffff); - intel_uncore_write(uncore, TRANS_PSR_IIR(trans), 0xffffffff); - } - } else { - intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); - intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); - } - - for_each_pipe(dev_priv, pipe) - if (intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_PIPE(pipe))) - GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); - - GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); - GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); - - if (DISPLAY_VER(dev_priv) >= 14) - GEN3_IRQ_RESET(uncore, PICAINTERRUPT_); - else - GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); - - if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - GEN3_IRQ_RESET(uncore, SDE); -} - static void gen11_irq_reset(struct drm_i915_private *dev_priv) { struct intel_gt *gt = to_gt(dev_priv); @@ -2194,52 +753,6 @@ static void dg1_irq_reset(struct drm_i915_private *dev_priv) GEN3_IRQ_RESET(uncore, GEN8_PCU_); } -void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, - u8 pipe_mask) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 extra_ier = GEN8_PIPE_VBLANK | - gen8_de_pipe_underrun_mask(dev_priv) | - gen8_de_pipe_flip_done_mask(dev_priv); - enum pipe pipe; - - spin_lock_irq(&dev_priv->irq_lock); - - if (!intel_irqs_enabled(dev_priv)) { - spin_unlock_irq(&dev_priv->irq_lock); - return; - } - - for_each_pipe_masked(dev_priv, pipe, pipe_mask) - GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, - dev_priv->de_irq_mask[pipe], - ~dev_priv->de_irq_mask[pipe] | extra_ier); - - spin_unlock_irq(&dev_priv->irq_lock); -} - -void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, - u8 pipe_mask) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - enum pipe pipe; - - spin_lock_irq(&dev_priv->irq_lock); - - if (!intel_irqs_enabled(dev_priv)) { - spin_unlock_irq(&dev_priv->irq_lock); - return; - } - - for_each_pipe_masked(dev_priv, pipe, pipe_mask) - GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); - - spin_unlock_irq(&dev_priv->irq_lock); - - /* make sure we're done processing display irqs */ - intel_synchronize_irq(dev_priv); -} - static void cherryview_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2257,35 +770,6 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } -/* - * SDEIER is also touched by the interrupt handler to work around missed PCH - * interrupts. Hence we can't update it after the interrupt handler is enabled - - * instead we unconditionally enable all PCH interrupt sources here, but then - * only unmask them as needed with SDEIMR. - * - * Note that we currently do this after installing the interrupt handler, - * but before we enable the master interrupt. That should be sufficient - * to avoid races with the irq handler, assuming we have MSI. Shared legacy - * interrupts could still race. - */ -static void ibx_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 mask; - - if (HAS_PCH_NOP(dev_priv)) - return; - - if (HAS_PCH_IBX(dev_priv)) - mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; - else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) - mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; - else - mask = SDE_GMBUS_CPT; - - GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); -} - static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2329,35 +813,6 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) display_mask | extra_mask); } -void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) -{ - lockdep_assert_held(&dev_priv->irq_lock); - - if (dev_priv->display_irqs_enabled) - return; - - dev_priv->display_irqs_enabled = true; - - if (intel_irqs_enabled(dev_priv)) { - vlv_display_irq_reset(dev_priv); - vlv_display_irq_postinstall(dev_priv); - } -} - -void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) -{ - lockdep_assert_held(&dev_priv->irq_lock); - - if (!dev_priv->display_irqs_enabled) - return; - - dev_priv->display_irqs_enabled = false; - - if (intel_irqs_enabled(dev_priv)) - vlv_display_irq_reset(dev_priv); -} - - static void valleyview_irq_postinstall(struct drm_i915_private *dev_priv) { gen5_gt_irq_postinstall(to_gt(dev_priv)); @@ -2371,108 +826,6 @@ static void valleyview_irq_postinstall(struct drm_i915_private *dev_priv) intel_uncore_posting_read(&dev_priv->uncore, VLV_MASTER_IER); } -static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - - u32 de_pipe_masked = gen8_de_pipe_fault_mask(dev_priv) | - GEN8_PIPE_CDCLK_CRC_DONE; - u32 de_pipe_enables; - u32 de_port_masked = gen8_de_port_aux_mask(dev_priv); - u32 de_port_enables; - u32 de_misc_masked = GEN8_DE_EDP_PSR; - u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | - BIT(TRANSCODER_C) | BIT(TRANSCODER_D); - enum pipe pipe; - - if (!HAS_DISPLAY(dev_priv)) - return; - - if (DISPLAY_VER(dev_priv) <= 10) - de_misc_masked |= GEN8_DE_MISC_GSE; - - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - de_port_masked |= BXT_DE_PORT_GMBUS; - - if (DISPLAY_VER(dev_priv) >= 11) { - enum port port; - - if (intel_bios_is_dsi_present(dev_priv, &port)) - de_port_masked |= DSI0_TE | DSI1_TE; - } - - de_pipe_enables = de_pipe_masked | - GEN8_PIPE_VBLANK | - gen8_de_pipe_underrun_mask(dev_priv) | - gen8_de_pipe_flip_done_mask(dev_priv); - - de_port_enables = de_port_masked; - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; - else if (IS_BROADWELL(dev_priv)) - de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; - - if (DISPLAY_VER(dev_priv) >= 12) { - enum transcoder trans; - - for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { - enum intel_display_power_domain domain; - - domain = POWER_DOMAIN_TRANSCODER(trans); - if (!intel_display_power_is_enabled(dev_priv, domain)) - continue; - - gen3_assert_iir_is_zero(uncore, TRANS_PSR_IIR(trans)); - } - } else { - gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR); - } - - for_each_pipe(dev_priv, pipe) { - dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; - - if (intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_PIPE(pipe))) - GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, - dev_priv->de_irq_mask[pipe], - de_pipe_enables); - } - - GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables); - GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); - - if (IS_DISPLAY_VER(dev_priv, 11, 13)) { - u32 de_hpd_masked = 0; - u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | - GEN11_DE_TBT_HOTPLUG_MASK; - - GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked, - de_hpd_enables); - } -} - -static void mtp_irq_postinstall(struct drm_i915_private *i915) -{ - struct intel_uncore *uncore = &i915->uncore; - u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT; - u32 de_hpd_mask = XELPDP_AUX_TC_MASK; - u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK | - XELPDP_TBT_HOTPLUG_MASK; - - GEN3_IRQ_INIT(uncore, PICAINTERRUPT_, ~de_hpd_mask, - de_hpd_enables); - - GEN3_IRQ_INIT(uncore, SDE, ~sde_mask, 0xffffffff); -} - -static void icp_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 mask = SDE_GMBUS_ICP; - - GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); -} - static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) { if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) @@ -2486,17 +839,6 @@ static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) gen8_master_intr_enable(dev_priv->uncore.regs); } -static void gen11_de_irq_postinstall(struct drm_i915_private *dev_priv) -{ - if (!HAS_DISPLAY(dev_priv)) - return; - - gen8_de_irq_postinstall(dev_priv); - - intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, - GEN11_DISPLAY_IRQ_ENABLE); -} - static void gen11_irq_postinstall(struct drm_i915_private *dev_priv) { struct intel_gt *gt = to_gt(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h index 913c854f873d..e665a1b007dc 100644 --- a/drivers/gpu/drm/i915/i915_irq.h +++ b/drivers/gpu/drm/i915/i915_irq.h @@ -25,34 +25,6 @@ void intel_irq_fini(struct drm_i915_private *dev_priv); int intel_irq_install(struct drm_i915_private *dev_priv); void intel_irq_uninstall(struct drm_i915_private *dev_priv); -u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv, - enum pipe pipe); -void -i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, - u32 status_mask); - -void -i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, - u32 status_mask); - -void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv); -void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv); - -void ilk_update_display_irq(struct drm_i915_private *i915, - u32 interrupt_mask, u32 enabled_irq_mask); -void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits); -void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits); - -void bdw_update_port_irq(struct drm_i915_private *i915, - u32 interrupt_mask, u32 enabled_irq_mask); -void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); -void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); - -void ibx_display_interrupt_update(struct drm_i915_private *i915, - u32 interrupt_mask, u32 enabled_irq_mask); -void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits); -void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits); - void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, u32 mask); void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, u32 mask); void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv); @@ -68,23 +40,7 @@ bool intel_irqs_enabled(struct drm_i915_private *dev_priv); void intel_synchronize_irq(struct drm_i915_private *i915); void intel_synchronize_hardirq(struct drm_i915_private *i915); -void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, - u8 pipe_mask); -void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, - u8 pipe_mask); -u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv); - - -int i8xx_enable_vblank(struct drm_crtc *crtc); -int i915gm_enable_vblank(struct drm_crtc *crtc); -int i965_enable_vblank(struct drm_crtc *crtc); -int ilk_enable_vblank(struct drm_crtc *crtc); -int bdw_enable_vblank(struct drm_crtc *crtc); -void i8xx_disable_vblank(struct drm_crtc *crtc); -void i915gm_disable_vblank(struct drm_crtc *crtc); -void i965_disable_vblank(struct drm_crtc *crtc); -void ilk_disable_vblank(struct drm_crtc *crtc); -void bdw_disable_vblank(struct drm_crtc *crtc); +void gen3_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg); void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr, i915_reg_t iir, i915_reg_t ier); -- 2.39.2 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-12 10:23 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display " Jani Nikula @ 2023-05-12 13:13 ` kernel test robot 2023-05-12 13:44 ` kernel test robot 2023-05-12 13:48 ` Gustavo Sousa 2 siblings, 0 replies; 15+ messages in thread From: kernel test robot @ 2023-05-12 13:13 UTC (permalink / raw) To: Jani Nikula, intel-gfx; +Cc: jani.nikula, oe-kbuild-all Hi Jani, kernel test robot noticed the following build errors: [auto build test ERROR on drm-intel/for-linux-next] [also build test ERROR on next-20230512] [cannot apply to drm-intel/for-linux-next-fixes linus/master v6.4-rc1] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Jani-Nikula/drm-i915-irq-split-out-hotplug-irq-handling/20230512-182445 base: git://anongit.freedesktop.org/drm-intel for-linux-next patch link: https://lore.kernel.org/r/20230512102310.1398406-3-jani.nikula%40intel.com patch subject: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling config: i386-defconfig (https://download.01.org/0day-ci/archive/20230512/202305122141.7yr9QGpe-lkp@intel.com/config) compiler: gcc-11 (Debian 11.3.0-12) 11.3.0 reproduce (this is a W=1 build): # https://github.com/intel-lab-lkp/linux/commit/40f02fc9ce92df7a661245796cb4b53471edb004 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Jani-Nikula/drm-i915-irq-split-out-hotplug-irq-handling/20230512-182445 git checkout 40f02fc9ce92df7a661245796cb4b53471edb004 # save the config file mkdir build_dir && cp config build_dir/.config make W=1 O=build_dir ARCH=i386 olddefconfig make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/gpu/drm/i915/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202305122141.7yr9QGpe-lkp@intel.com/ All errors (new ones prefixed by >>): >> drivers/gpu/drm/i915/display/intel_display_irq.c:411:41: error: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Werror=array-parameter=] 411 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:74:73: note: previously declared as 'u32 *' {aka 'unsigned int *'} 74 | void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ cc1: all warnings being treated as errors vim +411 drivers/gpu/drm/i915/display/intel_display_irq.c 409 410 void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv, > 411 u32 iir, u32 pipe_stats[I915_MAX_PIPES]) 412 { 413 enum pipe pipe; 414 415 spin_lock(&dev_priv->irq_lock); 416 417 if (!dev_priv->display_irqs_enabled) { 418 spin_unlock(&dev_priv->irq_lock); 419 return; 420 } 421 422 for_each_pipe(dev_priv, pipe) { 423 i915_reg_t reg; 424 u32 status_mask, enable_mask, iir_bit = 0; 425 426 /* 427 * PIPESTAT bits get signalled even when the interrupt is 428 * disabled with the mask bits, and some of the status bits do 429 * not generate interrupts at all (like the underrun bit). Hence 430 * we need to be careful that we only handle what we want to 431 * handle. 432 */ 433 434 /* fifo underruns are filterered in the underrun handler. */ 435 status_mask = PIPE_FIFO_UNDERRUN_STATUS; 436 437 switch (pipe) { 438 default: 439 case PIPE_A: 440 iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; 441 break; 442 case PIPE_B: 443 iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; 444 break; 445 case PIPE_C: 446 iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; 447 break; 448 } 449 if (iir & iir_bit) 450 status_mask |= dev_priv->pipestat_irq_mask[pipe]; 451 452 if (!status_mask) 453 continue; 454 455 reg = PIPESTAT(pipe); 456 pipe_stats[pipe] = intel_uncore_read(&dev_priv->uncore, reg) & status_mask; 457 enable_mask = i915_pipestat_enable_mask(dev_priv, pipe); 458 459 /* 460 * Clear the PIPE*STAT regs before the IIR 461 * 462 * Toggle the enable bits to make sure we get an 463 * edge in the ISR pipe event bit if we don't clear 464 * all the enabled status bits. Otherwise the edge 465 * triggered IIR on i965/g4x wouldn't notice that 466 * an interrupt is still pending. 467 */ 468 if (pipe_stats[pipe]) { 469 intel_uncore_write(&dev_priv->uncore, reg, pipe_stats[pipe]); 470 intel_uncore_write(&dev_priv->uncore, reg, enable_mask); 471 } 472 } 473 spin_unlock(&dev_priv->irq_lock); 474 } 475 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-12 10:23 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display " Jani Nikula 2023-05-12 13:13 ` kernel test robot @ 2023-05-12 13:44 ` kernel test robot 2023-05-12 13:48 ` Gustavo Sousa 2 siblings, 0 replies; 15+ messages in thread From: kernel test robot @ 2023-05-12 13:44 UTC (permalink / raw) To: Jani Nikula, intel-gfx; +Cc: jani.nikula, oe-kbuild-all Hi Jani, kernel test robot noticed the following build warnings: [auto build test WARNING on drm-intel/for-linux-next] [also build test WARNING on next-20230512] [cannot apply to drm-intel/for-linux-next-fixes linus/master v6.4-rc1] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Jani-Nikula/drm-i915-irq-split-out-hotplug-irq-handling/20230512-182445 base: git://anongit.freedesktop.org/drm-intel for-linux-next patch link: https://lore.kernel.org/r/20230512102310.1398406-3-jani.nikula%40intel.com patch subject: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling config: x86_64-randconfig-a011 (https://download.01.org/0day-ci/archive/20230512/202305122119.ReGv8vXc-lkp@intel.com/config) compiler: gcc-11 (Debian 11.3.0-12) 11.3.0 reproduce (this is a W=1 build): # https://github.com/intel-lab-lkp/linux/commit/40f02fc9ce92df7a661245796cb4b53471edb004 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Jani-Nikula/drm-i915-irq-split-out-hotplug-irq-handling/20230512-182445 git checkout 40f02fc9ce92df7a661245796cb4b53471edb004 # save the config file mkdir build_dir && cp config build_dir/.config make W=1 O=build_dir ARCH=x86_64 olddefconfig make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/gpu/drm/i915/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202305122119.ReGv8vXc-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/gpu/drm/i915/display/intel_display_irq.c:411:41: warning: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Warray-parameter=] 411 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:74:73: note: previously declared as 'u32 *' {aka 'unsigned int *'} 74 | void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ vim +411 drivers/gpu/drm/i915/display/intel_display_irq.c 409 410 void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv, > 411 u32 iir, u32 pipe_stats[I915_MAX_PIPES]) 412 { 413 enum pipe pipe; 414 415 spin_lock(&dev_priv->irq_lock); 416 417 if (!dev_priv->display_irqs_enabled) { 418 spin_unlock(&dev_priv->irq_lock); 419 return; 420 } 421 422 for_each_pipe(dev_priv, pipe) { 423 i915_reg_t reg; 424 u32 status_mask, enable_mask, iir_bit = 0; 425 426 /* 427 * PIPESTAT bits get signalled even when the interrupt is 428 * disabled with the mask bits, and some of the status bits do 429 * not generate interrupts at all (like the underrun bit). Hence 430 * we need to be careful that we only handle what we want to 431 * handle. 432 */ 433 434 /* fifo underruns are filterered in the underrun handler. */ 435 status_mask = PIPE_FIFO_UNDERRUN_STATUS; 436 437 switch (pipe) { 438 default: 439 case PIPE_A: 440 iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; 441 break; 442 case PIPE_B: 443 iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; 444 break; 445 case PIPE_C: 446 iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; 447 break; 448 } 449 if (iir & iir_bit) 450 status_mask |= dev_priv->pipestat_irq_mask[pipe]; 451 452 if (!status_mask) 453 continue; 454 455 reg = PIPESTAT(pipe); 456 pipe_stats[pipe] = intel_uncore_read(&dev_priv->uncore, reg) & status_mask; 457 enable_mask = i915_pipestat_enable_mask(dev_priv, pipe); 458 459 /* 460 * Clear the PIPE*STAT regs before the IIR 461 * 462 * Toggle the enable bits to make sure we get an 463 * edge in the ISR pipe event bit if we don't clear 464 * all the enabled status bits. Otherwise the edge 465 * triggered IIR on i965/g4x wouldn't notice that 466 * an interrupt is still pending. 467 */ 468 if (pipe_stats[pipe]) { 469 intel_uncore_write(&dev_priv->uncore, reg, pipe_stats[pipe]); 470 intel_uncore_write(&dev_priv->uncore, reg, enable_mask); 471 } 472 } 473 spin_unlock(&dev_priv->irq_lock); 474 } 475 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-12 10:23 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display " Jani Nikula 2023-05-12 13:13 ` kernel test robot 2023-05-12 13:44 ` kernel test robot @ 2023-05-12 13:48 ` Gustavo Sousa 2023-05-12 18:21 ` Jani Nikula 2023-05-15 10:05 ` Jani Nikula 2 siblings, 2 replies; 15+ messages in thread From: Gustavo Sousa @ 2023-05-12 13:48 UTC (permalink / raw) To: Jani Nikula, intel-gfx; +Cc: jani.nikula Quoting Jani Nikula (2023-05-12 07:23:10) >Split (non-hotplug) display irq handling out of i915_irq.[ch] into >display/intel_display_irq.[ch]. > >v2: >- Rebase >- Preserve [I915_MAX_PIPES] in functions (kernel test robot) > >Signed-off-by: Jani Nikula <jani.nikula@intel.com> >--- > drivers/gpu/drm/i915/Makefile | 1 + > drivers/gpu/drm/i915/display/i9xx_plane.c | 2 +- > drivers/gpu/drm/i915/display/intel_crtc.c | 2 +- > .../gpu/drm/i915/display/intel_display_irq.c | 1668 +++++++++++++++++ > .../gpu/drm/i915/display/intel_display_irq.h | 81 + > .../i915/display/intel_display_power_well.c | 1 + > .../drm/i915/display/intel_fifo_underrun.c | 2 +- > .../gpu/drm/i915/display/intel_hotplug_irq.c | 2 +- > drivers/gpu/drm/i915/display/intel_tv.c | 2 +- > .../drm/i915/display/skl_universal_plane.c | 2 +- > drivers/gpu/drm/i915/gt/intel_rps.c | 1 + > drivers/gpu/drm/i915/i915_irq.c | 1666 +--------------- > drivers/gpu/drm/i915/i915_irq.h | 46 +- > 13 files changed, 1763 insertions(+), 1713 deletions(-) > create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.c > create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.h > >diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile >index 7f7569c5f9a9..310c692e2fcd 100644 >--- a/drivers/gpu/drm/i915/Makefile >+++ b/drivers/gpu/drm/i915/Makefile >@@ -239,6 +239,7 @@ i915-y += \ > display/intel_cursor.o \ > display/intel_display.o \ > display/intel_display_driver.o \ >+ display/intel_display_irq.o \ > display/intel_display_power.o \ > display/intel_display_power_map.o \ > display/intel_display_power_well.o \ >diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c >index ecaeb7dc196b..616654adbfb8 100644 >--- a/drivers/gpu/drm/i915/display/i9xx_plane.c >+++ b/drivers/gpu/drm/i915/display/i9xx_plane.c >@@ -8,12 +8,12 @@ > #include <drm/drm_blend.h> > #include <drm/drm_fourcc.h> > >-#include "i915_irq.h" > #include "i915_reg.h" > #include "i9xx_plane.h" > #include "intel_atomic.h" > #include "intel_atomic_plane.h" > #include "intel_de.h" >+#include "intel_display_irq.h" > #include "intel_display_types.h" > #include "intel_fb.h" > #include "intel_fbc.h" >diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c >index df7d05f1e14b..a79930a4e40f 100644 >--- a/drivers/gpu/drm/i915/display/intel_crtc.c >+++ b/drivers/gpu/drm/i915/display/intel_crtc.c >@@ -11,7 +11,6 @@ > #include <drm/drm_plane.h> > #include <drm/drm_vblank_work.h> > >-#include "i915_irq.h" > #include "i915_vgpu.h" > #include "i9xx_plane.h" > #include "icl_dsi.h" >@@ -21,6 +20,7 @@ > #include "intel_crtc.h" > #include "intel_cursor.h" > #include "intel_display_debugfs.h" >+#include "intel_display_irq.h" > #include "intel_display_trace.h" > #include "intel_display_types.h" > #include "intel_drrs.h" >diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c >new file mode 100644 >index 000000000000..0eedd1ebb389 >--- /dev/null >+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c >@@ -0,0 +1,1668 @@ >+// SPDX-License-Identifier: MIT >+/* >+ * Copyright © 2023 Intel Corporation >+ */ >+ >+#include "i915_drv.h" >+#include "i915_irq.h" >+#include "i915_reg.h" >+#include "icl_dsi_regs.h" >+#include "intel_display_irq.h" >+#include "intel_display_types.h" >+#include "intel_hotplug_irq.h" >+#include "intel_psr_regs.h" >+#include "intel_crtc.h" >+#include "intel_display_trace.h" >+#include "intel_dp_aux.h" >+#include "intel_gmbus.h" >+#include "intel_fifo_underrun.h" >+#include "intel_psr.h" >+#include "intel_fdi_regs.h" >+#include "gt/intel_rps.h" >+#include "intel_de.h" >+ >+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); >+} >+ >+/** >+ * 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 >+ */ >+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 >+ */ >+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 >+ */ >+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 >+ */ >+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); >+} >+ >+#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); >+} >+ >+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; >+ } >+} >+ >+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); >+} >+ >+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); >+ } >+} >+ >+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); >+} >+ >+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) >+ intel_gmbus_irq_handler(dev_priv); >+} >+ >+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) >+ intel_gmbus_irq_handler(dev_priv); >+} >+ >+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) >+ intel_dp_aux_irq_handler(dev_priv); >+ >+ if (pch_iir & SDE_GMBUS) >+ intel_gmbus_irq_handler(dev_priv); >+ >+ if (pch_iir & SDE_AUDIO_HDCP_MASK) >+ drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n"); >+ >+ if (pch_iir & SDE_AUDIO_TRANS_MASK) >+ drm_dbg(&dev_priv->drm, "PCH transcoder audio interrupt\n"); >+ >+ if (pch_iir & SDE_POISON) >+ drm_err(&dev_priv->drm, "PCH poison interrupt\n"); >+ >+ if (pch_iir & SDE_FDI_MASK) { >+ for_each_pipe(dev_priv, pipe) >+ drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", >+ pipe_name(pipe), >+ intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); >+ } >+ >+ if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) >+ drm_dbg(&dev_priv->drm, "PCH transcoder CRC done interrupt\n"); >+ >+ if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) >+ drm_dbg(&dev_priv->drm, >+ "PCH transcoder CRC error interrupt\n"); >+ >+ if (pch_iir & SDE_TRANSA_FIFO_UNDER) >+ intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A); >+ >+ if (pch_iir & SDE_TRANSB_FIFO_UNDER) >+ intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B); >+} >+ >+static void ivb_err_int_handler(struct drm_i915_private *dev_priv) >+{ >+ u32 err_int = intel_uncore_read(&dev_priv->uncore, GEN7_ERR_INT); >+ enum pipe pipe; >+ >+ if (err_int & ERR_INT_POISON) >+ drm_err(&dev_priv->drm, "Poison interrupt\n"); >+ >+ for_each_pipe(dev_priv, pipe) { >+ if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) >+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); >+ >+ if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { >+ if (IS_IVYBRIDGE(dev_priv)) >+ ivb_pipe_crc_irq_handler(dev_priv, pipe); >+ else >+ hsw_pipe_crc_irq_handler(dev_priv, pipe); >+ } >+ } >+ >+ intel_uncore_write(&dev_priv->uncore, GEN7_ERR_INT, err_int); >+} >+ >+static void cpt_serr_int_handler(struct drm_i915_private *dev_priv) >+{ >+ u32 serr_int = intel_uncore_read(&dev_priv->uncore, SERR_INT); >+ enum pipe pipe; >+ >+ if (serr_int & SERR_INT_POISON) >+ drm_err(&dev_priv->drm, "PCH poison interrupt\n"); >+ >+ for_each_pipe(dev_priv, pipe) >+ if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe)) >+ intel_pch_fifo_underrun_irq_handler(dev_priv, pipe); >+ >+ intel_uncore_write(&dev_priv->uncore, SERR_INT, serr_int); >+} >+ >+static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) >+{ >+ enum pipe pipe; >+ u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; >+ >+ ibx_hpd_irq_handler(dev_priv, hotplug_trigger); >+ >+ if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { >+ int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> >+ SDE_AUDIO_POWER_SHIFT_CPT); >+ drm_dbg(&dev_priv->drm, "PCH audio power change on port %c\n", >+ port_name(port)); >+ } >+ >+ if (pch_iir & SDE_AUX_MASK_CPT) >+ intel_dp_aux_irq_handler(dev_priv); >+ >+ if (pch_iir & SDE_GMBUS_CPT) >+ intel_gmbus_irq_handler(dev_priv); >+ >+ if (pch_iir & SDE_AUDIO_CP_REQ_CPT) >+ drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n"); >+ >+ if (pch_iir & SDE_AUDIO_CP_CHG_CPT) >+ drm_dbg(&dev_priv->drm, "Audio CP change interrupt\n"); >+ >+ if (pch_iir & SDE_FDI_MASK_CPT) { >+ for_each_pipe(dev_priv, pipe) >+ drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", >+ pipe_name(pipe), >+ intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); >+ } >+ >+ if (pch_iir & SDE_ERROR_CPT) >+ cpt_serr_int_handler(dev_priv); >+} >+ >+void ilk_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) >+{ >+ enum pipe pipe; >+ u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; >+ >+ if (hotplug_trigger) >+ ilk_hpd_irq_handler(dev_priv, hotplug_trigger); >+ >+ if (de_iir & DE_AUX_CHANNEL_A) >+ intel_dp_aux_irq_handler(dev_priv); >+ >+ if (de_iir & DE_GSE) >+ intel_opregion_asle_intr(dev_priv); >+ >+ if (de_iir & DE_POISON) >+ drm_err(&dev_priv->drm, "Poison interrupt\n"); >+ >+ for_each_pipe(dev_priv, pipe) { >+ if (de_iir & DE_PIPE_VBLANK(pipe)) >+ intel_handle_vblank(dev_priv, pipe); >+ >+ if (de_iir & DE_PLANE_FLIP_DONE(pipe)) >+ flip_done_handler(dev_priv, pipe); >+ >+ if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) >+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); >+ >+ if (de_iir & DE_PIPE_CRC_DONE(pipe)) >+ i9xx_pipe_crc_irq_handler(dev_priv, pipe); >+ } >+ >+ /* check event from PCH */ >+ if (de_iir & DE_PCH_EVENT) { >+ u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); >+ >+ if (HAS_PCH_CPT(dev_priv)) >+ cpt_irq_handler(dev_priv, pch_iir); >+ else >+ ibx_irq_handler(dev_priv, pch_iir); >+ >+ /* should clear PCH hotplug event before clear CPU irq */ >+ intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); >+ } >+ >+ if (DISPLAY_VER(dev_priv) == 5 && de_iir & DE_PCU_EVENT) >+ gen5_rps_irq_handler(&to_gt(dev_priv)->rps); >+} >+ >+void ivb_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) >+{ >+ enum pipe pipe; >+ u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; >+ >+ if (hotplug_trigger) >+ ilk_hpd_irq_handler(dev_priv, hotplug_trigger); >+ >+ if (de_iir & DE_ERR_INT_IVB) >+ ivb_err_int_handler(dev_priv); >+ >+ if (de_iir & DE_AUX_CHANNEL_A_IVB) >+ intel_dp_aux_irq_handler(dev_priv); >+ >+ if (de_iir & DE_GSE_IVB) >+ intel_opregion_asle_intr(dev_priv); >+ >+ for_each_pipe(dev_priv, pipe) { >+ if (de_iir & DE_PIPE_VBLANK_IVB(pipe)) >+ intel_handle_vblank(dev_priv, pipe); >+ >+ if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) >+ flip_done_handler(dev_priv, pipe); >+ } >+ >+ /* check event from PCH */ >+ if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) { >+ u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); >+ >+ cpt_irq_handler(dev_priv, pch_iir); >+ >+ /* clear PCH hotplug event before clear CPU irq */ >+ intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); >+ } >+} >+ >+static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) >+{ >+ u32 mask; >+ >+ if (DISPLAY_VER(dev_priv) >= 14) >+ return TGL_DE_PORT_AUX_DDIA | >+ TGL_DE_PORT_AUX_DDIB; >+ else if (DISPLAY_VER(dev_priv) >= 13) >+ return TGL_DE_PORT_AUX_DDIA | >+ TGL_DE_PORT_AUX_DDIB | >+ TGL_DE_PORT_AUX_DDIC | >+ XELPD_DE_PORT_AUX_DDID | >+ XELPD_DE_PORT_AUX_DDIE | >+ TGL_DE_PORT_AUX_USBC1 | >+ TGL_DE_PORT_AUX_USBC2 | >+ TGL_DE_PORT_AUX_USBC3 | >+ TGL_DE_PORT_AUX_USBC4; >+ else if (DISPLAY_VER(dev_priv) >= 12) >+ return TGL_DE_PORT_AUX_DDIA | >+ TGL_DE_PORT_AUX_DDIB | >+ TGL_DE_PORT_AUX_DDIC | >+ TGL_DE_PORT_AUX_USBC1 | >+ TGL_DE_PORT_AUX_USBC2 | >+ TGL_DE_PORT_AUX_USBC3 | >+ TGL_DE_PORT_AUX_USBC4 | >+ TGL_DE_PORT_AUX_USBC5 | >+ TGL_DE_PORT_AUX_USBC6; >+ >+ mask = GEN8_AUX_CHANNEL_A; >+ if (DISPLAY_VER(dev_priv) >= 9) >+ mask |= GEN9_AUX_CHANNEL_B | >+ GEN9_AUX_CHANNEL_C | >+ GEN9_AUX_CHANNEL_D; >+ >+ if (DISPLAY_VER(dev_priv) == 11) { >+ mask |= ICL_AUX_CHANNEL_F; >+ mask |= ICL_AUX_CHANNEL_E; >+ } >+ >+ return mask; >+} >+ >+static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) >+{ >+ if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) >+ return RKL_DE_PIPE_IRQ_FAULT_ERRORS; >+ else if (DISPLAY_VER(dev_priv) >= 11) >+ return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; >+ else if (DISPLAY_VER(dev_priv) >= 9) >+ return GEN9_DE_PIPE_IRQ_FAULT_ERRORS; >+ else >+ return GEN8_DE_PIPE_IRQ_FAULT_ERRORS; >+} >+ >+static void >+gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) >+{ >+ bool found = false; >+ >+ if (iir & GEN8_DE_MISC_GSE) { >+ intel_opregion_asle_intr(dev_priv); >+ found = true; >+ } >+ >+ if (iir & GEN8_DE_EDP_PSR) { >+ struct intel_encoder *encoder; >+ u32 psr_iir; >+ i915_reg_t iir_reg; >+ >+ for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { >+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder); >+ >+ if (DISPLAY_VER(dev_priv) >= 12) >+ iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder); >+ else >+ iir_reg = EDP_PSR_IIR; >+ >+ psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0); >+ >+ if (psr_iir) >+ found = true; >+ >+ intel_psr_irq_handler(intel_dp, psr_iir); >+ >+ /* prior GEN12 only have one EDP PSR */ >+ if (DISPLAY_VER(dev_priv) < 12) >+ break; >+ } >+ } >+ >+ if (!found) >+ drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); >+} >+ >+static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, >+ u32 te_trigger) >+{ >+ enum pipe pipe = INVALID_PIPE; >+ enum transcoder dsi_trans; >+ enum port port; >+ u32 val, tmp; >+ >+ /* >+ * Incase of dual link, TE comes from DSI_1 >+ * this is to check if dual link is enabled >+ */ >+ val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0)); >+ val &= PORT_SYNC_MODE_ENABLE; >+ >+ /* >+ * if dual link is enabled, then read DSI_0 >+ * transcoder registers >+ */ >+ port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ? >+ PORT_A : PORT_B; >+ dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1; >+ >+ /* Check if DSI configured in command mode */ >+ val = intel_uncore_read(&dev_priv->uncore, DSI_TRANS_FUNC_CONF(dsi_trans)); >+ val = val & OP_MODE_MASK; >+ >+ if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) { >+ drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n"); >+ return; >+ } >+ >+ /* Get PIPE for handling VBLANK event */ >+ val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL(dsi_trans)); >+ switch (val & TRANS_DDI_EDP_INPUT_MASK) { >+ case TRANS_DDI_EDP_INPUT_A_ON: >+ pipe = PIPE_A; >+ break; >+ case TRANS_DDI_EDP_INPUT_B_ONOFF: >+ pipe = PIPE_B; >+ break; >+ case TRANS_DDI_EDP_INPUT_C_ONOFF: >+ pipe = PIPE_C; >+ break; >+ default: >+ drm_err(&dev_priv->drm, "Invalid PIPE\n"); >+ return; >+ } >+ >+ intel_handle_vblank(dev_priv, pipe); >+ >+ /* clear TE in dsi IIR */ >+ port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; >+ tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); >+} >+ >+static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915) >+{ >+ if (DISPLAY_VER(i915) >= 9) >+ return GEN9_PIPE_PLANE1_FLIP_DONE; >+ else >+ return GEN8_PIPE_PRIMARY_FLIP_DONE; >+} >+ >+u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv) >+{ >+ u32 mask = GEN8_PIPE_FIFO_UNDERRUN; >+ >+ if (DISPLAY_VER(dev_priv) >= 13) >+ mask |= XELPD_PIPE_SOFT_UNDERRUN | >+ XELPD_PIPE_HARD_UNDERRUN; >+ >+ return mask; >+} >+ >+static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_iir, u32 *pica_iir) >+{ >+ u32 pica_ier = 0; >+ >+ *pica_iir = 0; >+ *pch_iir = intel_de_read(i915, SDEIIR); >+ if (!*pch_iir) >+ return; >+ >+ /** >+ * PICA IER must be disabled/re-enabled around clearing PICA IIR and >+ * SDEIIR, to avoid losing PICA IRQs and to ensure that such IRQs set >+ * their flags both in the PICA and SDE IIR. >+ */ >+ if (*pch_iir & SDE_PICAINTERRUPT) { >+ drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); >+ >+ pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); >+ *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); >+ intel_de_write(i915, PICAINTERRUPT_IIR, *pica_iir); >+ } >+ >+ intel_de_write(i915, SDEIIR, *pch_iir); >+ >+ if (pica_ier) >+ intel_de_write(i915, PICAINTERRUPT_IER, pica_ier); >+} >+ >+void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) >+{ >+ u32 iir; >+ enum pipe pipe; >+ >+ drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DISPLAY(dev_priv)); >+ >+ if (master_ctl & GEN8_DE_MISC_IRQ) { >+ iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); >+ if (iir) { >+ intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir); >+ gen8_de_misc_irq_handler(dev_priv, iir); >+ } else { >+ drm_err_ratelimited(&dev_priv->drm, >+ "The master control interrupt lied (DE MISC)!\n"); >+ } >+ } >+ >+ if (DISPLAY_VER(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { >+ iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR); >+ if (iir) { >+ intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir); >+ gen11_hpd_irq_handler(dev_priv, iir); >+ } else { >+ drm_err_ratelimited(&dev_priv->drm, >+ "The master control interrupt lied, (DE HPD)!\n"); >+ } >+ } >+ >+ if (master_ctl & GEN8_DE_PORT_IRQ) { >+ iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PORT_IIR); >+ if (iir) { >+ bool found = false; >+ >+ intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir); >+ >+ if (iir & gen8_de_port_aux_mask(dev_priv)) { >+ intel_dp_aux_irq_handler(dev_priv); >+ found = true; >+ } >+ >+ if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { >+ u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; >+ >+ if (hotplug_trigger) { >+ bxt_hpd_irq_handler(dev_priv, hotplug_trigger); >+ found = true; >+ } >+ } else if (IS_BROADWELL(dev_priv)) { >+ u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK; >+ >+ if (hotplug_trigger) { >+ ilk_hpd_irq_handler(dev_priv, hotplug_trigger); >+ found = true; >+ } >+ } >+ >+ if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && >+ (iir & BXT_DE_PORT_GMBUS)) { >+ intel_gmbus_irq_handler(dev_priv); >+ found = true; >+ } >+ >+ if (DISPLAY_VER(dev_priv) >= 11) { >+ u32 te_trigger = iir & (DSI0_TE | DSI1_TE); >+ >+ if (te_trigger) { >+ gen11_dsi_te_interrupt_handler(dev_priv, te_trigger); >+ found = true; >+ } >+ } >+ >+ if (!found) >+ drm_err_ratelimited(&dev_priv->drm, >+ "Unexpected DE Port interrupt\n"); >+ } else { >+ drm_err_ratelimited(&dev_priv->drm, >+ "The master control interrupt lied (DE PORT)!\n"); >+ } >+ } >+ >+ for_each_pipe(dev_priv, pipe) { >+ u32 fault_errors; >+ >+ if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) >+ continue; >+ >+ iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe)); >+ if (!iir) { >+ drm_err_ratelimited(&dev_priv->drm, >+ "The master control interrupt lied (DE PIPE)!\n"); >+ continue; >+ } >+ >+ intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir); >+ >+ if (iir & GEN8_PIPE_VBLANK) >+ intel_handle_vblank(dev_priv, pipe); >+ >+ if (iir & gen8_de_pipe_flip_done_mask(dev_priv)) >+ flip_done_handler(dev_priv, pipe); >+ >+ if (iir & GEN8_PIPE_CDCLK_CRC_DONE) >+ hsw_pipe_crc_irq_handler(dev_priv, pipe); >+ >+ if (iir & gen8_de_pipe_underrun_mask(dev_priv)) >+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); >+ >+ fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv); >+ if (fault_errors) >+ drm_err_ratelimited(&dev_priv->drm, >+ "Fault errors on pipe %c: 0x%08x\n", >+ pipe_name(pipe), >+ fault_errors); >+ } >+ >+ if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) && >+ master_ctl & GEN8_DE_PCH_IRQ) { >+ u32 pica_iir; >+ >+ /* >+ * FIXME(BDW): Assume for now that the new interrupt handling >+ * scheme also closed the SDE interrupt handling race we've seen >+ * on older pch-split platforms. But this needs testing. >+ */ >+ gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir); >+ if (iir) { >+ if (pica_iir) >+ xelpdp_pica_irq_handler(dev_priv, pica_iir); >+ >+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) >+ icp_irq_handler(dev_priv, iir); >+ else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) >+ spt_irq_handler(dev_priv, iir); >+ else >+ cpt_irq_handler(dev_priv, iir); >+ } else { >+ /* >+ * Like on previous PCH there seems to be something >+ * fishy going on with forwarding PCH interrupts. >+ */ >+ drm_dbg(&dev_priv->drm, >+ "The master control interrupt lied (SDE)!\n"); >+ } >+ } >+} >+ >+u32 gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl) >+{ >+ void __iomem * const regs = i915->uncore.regs; >+ u32 iir; >+ >+ if (!(master_ctl & GEN11_GU_MISC_IRQ)) >+ return 0; >+ >+ iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); >+ if (likely(iir)) >+ raw_reg_write(regs, GEN11_GU_MISC_IIR, iir); >+ >+ return iir; >+} >+ >+void gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir) >+{ >+ if (iir & GEN11_GU_MISC_GSE) >+ intel_opregion_asle_intr(i915); >+} >+ >+void gen11_display_irq_handler(struct drm_i915_private *i915) >+{ >+ void __iomem * const regs = i915->uncore.regs; >+ const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL); >+ >+ disable_rpm_wakeref_asserts(&i915->runtime_pm); >+ /* >+ * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ >+ * for the display related bits. >+ */ >+ raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, 0x0); >+ gen8_de_irq_handler(i915, disp_ctl); >+ raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, >+ GEN11_DISPLAY_IRQ_ENABLE); >+ >+ enable_rpm_wakeref_asserts(&i915->runtime_pm); >+} >+ >+/* Called from drm generic code, passed 'crtc' which >+ * we use as a pipe index >+ */ >+int i8xx_enable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ enum pipe pipe = to_intel_crtc(crtc)->pipe; >+ unsigned long irqflags; >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+ >+ return 0; >+} >+ >+int i915gm_enable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ >+ /* >+ * Vblank interrupts fail to wake the device up from C2+. >+ * Disabling render clock gating during C-states avoids >+ * the problem. There is a small power cost so we do this >+ * only when vblank interrupts are actually enabled. >+ */ >+ if (dev_priv->vblank_enabled++ == 0) >+ intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); >+ >+ return i8xx_enable_vblank(crtc); >+} >+ >+int i965_enable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ enum pipe pipe = to_intel_crtc(crtc)->pipe; >+ unsigned long irqflags; >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ i915_enable_pipestat(dev_priv, pipe, >+ PIPE_START_VBLANK_INTERRUPT_STATUS); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+ >+ return 0; >+} >+ >+int ilk_enable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ enum pipe pipe = to_intel_crtc(crtc)->pipe; >+ unsigned long irqflags; >+ u32 bit = DISPLAY_VER(dev_priv) >= 7 ? >+ DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ ilk_enable_display_irq(dev_priv, bit); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+ >+ /* Even though there is no DMC, frame counter can get stuck when >+ * PSR is active as no frames are generated. >+ */ >+ if (HAS_PSR(dev_priv)) >+ drm_crtc_vblank_restore(crtc); >+ >+ return 0; >+} >+ >+static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, >+ bool enable) >+{ >+ struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); >+ enum port port; >+ >+ if (!(intel_crtc->mode_flags & >+ (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) >+ return false; >+ >+ /* for dual link cases we consider TE from slave */ >+ if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1) >+ port = PORT_B; >+ else >+ port = PORT_A; >+ >+ intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT, >+ enable ? 0 : DSI_TE_EVENT); >+ >+ intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); >+ >+ return true; >+} >+ >+int bdw_enable_vblank(struct drm_crtc *_crtc) >+{ >+ struct intel_crtc *crtc = to_intel_crtc(_crtc); >+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); >+ enum pipe pipe = crtc->pipe; >+ unsigned long irqflags; >+ >+ if (gen11_dsi_configure_te(crtc, true)) >+ return 0; >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+ >+ /* Even if there is no DMC, frame counter can get stuck when >+ * PSR is active as no frames are generated, so check only for PSR. >+ */ >+ if (HAS_PSR(dev_priv)) >+ drm_crtc_vblank_restore(&crtc->base); >+ >+ return 0; >+} >+ >+/* Called from drm generic code, passed 'crtc' which >+ * we use as a pipe index >+ */ >+void i8xx_disable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ enum pipe pipe = to_intel_crtc(crtc)->pipe; >+ unsigned long irqflags; >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+} >+ >+void i915gm_disable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ >+ i8xx_disable_vblank(crtc); >+ >+ if (--dev_priv->vblank_enabled == 0) >+ intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); >+} >+ >+void i965_disable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ enum pipe pipe = to_intel_crtc(crtc)->pipe; >+ unsigned long irqflags; >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ i915_disable_pipestat(dev_priv, pipe, >+ PIPE_START_VBLANK_INTERRUPT_STATUS); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+} >+ >+void ilk_disable_vblank(struct drm_crtc *crtc) >+{ >+ struct drm_i915_private *dev_priv = to_i915(crtc->dev); >+ enum pipe pipe = to_intel_crtc(crtc)->pipe; >+ unsigned long irqflags; >+ u32 bit = DISPLAY_VER(dev_priv) >= 7 ? >+ DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ ilk_disable_display_irq(dev_priv, bit); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+} >+ >+void bdw_disable_vblank(struct drm_crtc *_crtc) >+{ >+ struct intel_crtc *crtc = to_intel_crtc(_crtc); >+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); >+ enum pipe pipe = crtc->pipe; >+ unsigned long irqflags; >+ >+ if (gen11_dsi_configure_te(crtc, false)) >+ return; >+ >+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >+ bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); >+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >+} >+ >+void vlv_display_irq_reset(struct drm_i915_private *dev_priv) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ >+ if (IS_CHERRYVIEW(dev_priv)) >+ intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); >+ else >+ intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); >+ >+ i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); >+ intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); >+ >+ i9xx_pipestat_irq_reset(dev_priv); >+ >+ GEN3_IRQ_RESET(uncore, VLV_); >+ dev_priv->irq_mask = ~0u; >+} >+ >+void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ >+ u32 pipestat_mask; >+ u32 enable_mask; >+ enum pipe pipe; >+ >+ pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS; >+ >+ i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); >+ for_each_pipe(dev_priv, pipe) >+ i915_enable_pipestat(dev_priv, pipe, pipestat_mask); >+ >+ enable_mask = I915_DISPLAY_PORT_INTERRUPT | >+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | >+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | >+ I915_LPE_PIPE_A_INTERRUPT | >+ I915_LPE_PIPE_B_INTERRUPT; >+ >+ if (IS_CHERRYVIEW(dev_priv)) >+ enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | >+ I915_LPE_PIPE_C_INTERRUPT; >+ >+ drm_WARN_ON(&dev_priv->drm, dev_priv->irq_mask != ~0u); >+ >+ dev_priv->irq_mask = ~enable_mask; >+ >+ GEN3_IRQ_INIT(uncore, VLV_, dev_priv->irq_mask, enable_mask); >+} >+ >+void gen8_display_irq_reset(struct drm_i915_private *dev_priv) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ enum pipe pipe; >+ >+ if (!HAS_DISPLAY(dev_priv)) >+ return; >+ >+ intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); >+ intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); >+ >+ for_each_pipe(dev_priv, pipe) >+ if (intel_display_power_is_enabled(dev_priv, >+ POWER_DOMAIN_PIPE(pipe))) >+ GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); >+ >+ GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); >+ GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); >+} >+ >+void gen11_display_irq_reset(struct drm_i915_private *dev_priv) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ enum pipe pipe; >+ u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | >+ BIT(TRANSCODER_C) | BIT(TRANSCODER_D); >+ >+ if (!HAS_DISPLAY(dev_priv)) >+ return; >+ >+ intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0); >+ >+ if (DISPLAY_VER(dev_priv) >= 12) { >+ enum transcoder trans; >+ >+ for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { >+ enum intel_display_power_domain domain; >+ >+ domain = POWER_DOMAIN_TRANSCODER(trans); >+ if (!intel_display_power_is_enabled(dev_priv, domain)) >+ continue; >+ >+ intel_uncore_write(uncore, TRANS_PSR_IMR(trans), 0xffffffff); >+ intel_uncore_write(uncore, TRANS_PSR_IIR(trans), 0xffffffff); >+ } >+ } else { >+ intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); >+ intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); >+ } >+ >+ for_each_pipe(dev_priv, pipe) >+ if (intel_display_power_is_enabled(dev_priv, >+ POWER_DOMAIN_PIPE(pipe))) >+ GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); >+ >+ GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); >+ GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); >+ >+ if (DISPLAY_VER(dev_priv) >= 14) >+ GEN3_IRQ_RESET(uncore, PICAINTERRUPT_); >+ else >+ GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); >+ >+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) >+ GEN3_IRQ_RESET(uncore, SDE); >+} >+ >+void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, >+ u8 pipe_mask) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ u32 extra_ier = GEN8_PIPE_VBLANK | >+ gen8_de_pipe_underrun_mask(dev_priv) | >+ gen8_de_pipe_flip_done_mask(dev_priv); >+ enum pipe pipe; >+ >+ spin_lock_irq(&dev_priv->irq_lock); >+ >+ if (!intel_irqs_enabled(dev_priv)) { >+ spin_unlock_irq(&dev_priv->irq_lock); >+ return; >+ } >+ >+ for_each_pipe_masked(dev_priv, pipe, pipe_mask) >+ GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, >+ dev_priv->de_irq_mask[pipe], >+ ~dev_priv->de_irq_mask[pipe] | extra_ier); >+ >+ spin_unlock_irq(&dev_priv->irq_lock); >+} >+ >+void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, >+ u8 pipe_mask) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ enum pipe pipe; >+ >+ spin_lock_irq(&dev_priv->irq_lock); >+ >+ if (!intel_irqs_enabled(dev_priv)) { >+ spin_unlock_irq(&dev_priv->irq_lock); >+ return; >+ } >+ >+ for_each_pipe_masked(dev_priv, pipe, pipe_mask) >+ GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); >+ >+ spin_unlock_irq(&dev_priv->irq_lock); >+ >+ /* make sure we're done processing display irqs */ >+ intel_synchronize_irq(dev_priv); >+} >+ >+/* >+ * SDEIER is also touched by the interrupt handler to work around missed PCH >+ * interrupts. Hence we can't update it after the interrupt handler is enabled - >+ * instead we unconditionally enable all PCH interrupt sources here, but then >+ * only unmask them as needed with SDEIMR. >+ * >+ * Note that we currently do this after installing the interrupt handler, >+ * but before we enable the master interrupt. That should be sufficient >+ * to avoid races with the irq handler, assuming we have MSI. Shared legacy >+ * interrupts could still race. >+ */ >+void ibx_irq_postinstall(struct drm_i915_private *dev_priv) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ u32 mask; >+ >+ if (HAS_PCH_NOP(dev_priv)) >+ return; >+ >+ if (HAS_PCH_IBX(dev_priv)) >+ mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; >+ else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) >+ mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; >+ else >+ mask = SDE_GMBUS_CPT; >+ >+ GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); >+} >+ >+void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) >+{ >+ lockdep_assert_held(&dev_priv->irq_lock); >+ >+ if (dev_priv->display_irqs_enabled) >+ return; >+ >+ dev_priv->display_irqs_enabled = true; >+ >+ if (intel_irqs_enabled(dev_priv)) { >+ vlv_display_irq_reset(dev_priv); >+ vlv_display_irq_postinstall(dev_priv); >+ } >+} >+ >+void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) >+{ >+ lockdep_assert_held(&dev_priv->irq_lock); >+ >+ if (!dev_priv->display_irqs_enabled) >+ return; >+ >+ dev_priv->display_irqs_enabled = false; >+ >+ if (intel_irqs_enabled(dev_priv)) >+ vlv_display_irq_reset(dev_priv); >+} >+ >+void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ >+ u32 de_pipe_masked = gen8_de_pipe_fault_mask(dev_priv) | >+ GEN8_PIPE_CDCLK_CRC_DONE; >+ u32 de_pipe_enables; >+ u32 de_port_masked = gen8_de_port_aux_mask(dev_priv); >+ u32 de_port_enables; >+ u32 de_misc_masked = GEN8_DE_EDP_PSR; >+ u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | >+ BIT(TRANSCODER_C) | BIT(TRANSCODER_D); >+ enum pipe pipe; >+ >+ if (!HAS_DISPLAY(dev_priv)) >+ return; >+ >+ if (DISPLAY_VER(dev_priv) <= 10) >+ de_misc_masked |= GEN8_DE_MISC_GSE; >+ >+ if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) >+ de_port_masked |= BXT_DE_PORT_GMBUS; >+ >+ if (DISPLAY_VER(dev_priv) >= 11) { >+ enum port port; >+ >+ if (intel_bios_is_dsi_present(dev_priv, &port)) >+ de_port_masked |= DSI0_TE | DSI1_TE; >+ } >+ >+ de_pipe_enables = de_pipe_masked | >+ GEN8_PIPE_VBLANK | >+ gen8_de_pipe_underrun_mask(dev_priv) | >+ gen8_de_pipe_flip_done_mask(dev_priv); >+ >+ de_port_enables = de_port_masked; >+ if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) >+ de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; >+ else if (IS_BROADWELL(dev_priv)) >+ de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; >+ >+ if (DISPLAY_VER(dev_priv) >= 12) { >+ enum transcoder trans; >+ >+ for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { >+ enum intel_display_power_domain domain; >+ >+ domain = POWER_DOMAIN_TRANSCODER(trans); >+ if (!intel_display_power_is_enabled(dev_priv, domain)) >+ continue; >+ >+ gen3_assert_iir_is_zero(uncore, TRANS_PSR_IIR(trans)); >+ } >+ } else { >+ gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR); >+ } >+ >+ for_each_pipe(dev_priv, pipe) { >+ dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; >+ >+ if (intel_display_power_is_enabled(dev_priv, >+ POWER_DOMAIN_PIPE(pipe))) >+ GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, >+ dev_priv->de_irq_mask[pipe], >+ de_pipe_enables); >+ } >+ >+ GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables); >+ GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); >+ >+ if (IS_DISPLAY_VER(dev_priv, 11, 13)) { >+ u32 de_hpd_masked = 0; >+ u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | >+ GEN11_DE_TBT_HOTPLUG_MASK; >+ >+ GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked, >+ de_hpd_enables); >+ } >+} >+ >+void mtp_irq_postinstall(struct drm_i915_private *i915) >+{ >+ struct intel_uncore *uncore = &i915->uncore; >+ u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT; >+ u32 de_hpd_mask = XELPDP_AUX_TC_MASK; >+ u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK | >+ XELPDP_TBT_HOTPLUG_MASK; >+ >+ GEN3_IRQ_INIT(uncore, PICAINTERRUPT_, ~de_hpd_mask, >+ de_hpd_enables); >+ >+ GEN3_IRQ_INIT(uncore, SDE, ~sde_mask, 0xffffffff); >+} >+ >+void icp_irq_postinstall(struct drm_i915_private *dev_priv) >+{ >+ struct intel_uncore *uncore = &dev_priv->uncore; >+ u32 mask = SDE_GMBUS_ICP; >+ >+ GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); >+} >+ >+void gen11_de_irq_postinstall(struct drm_i915_private *dev_priv) >+{ >+ if (!HAS_DISPLAY(dev_priv)) >+ return; >+ >+ gen8_de_irq_postinstall(dev_priv); >+ >+ intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, >+ GEN11_DISPLAY_IRQ_ENABLE); >+} >+ >diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h >new file mode 100644 >index 000000000000..8db03e83d23d >--- /dev/null >+++ b/drivers/gpu/drm/i915/display/intel_display_irq.h >@@ -0,0 +1,81 @@ >+/* SPDX-License-Identifier: MIT */ >+/* >+ * Copyright © 2023 Intel Corporation >+ */ >+ >+#ifndef __INTEL_DISPLAY_IRQ_H__ >+#define __INTEL_DISPLAY_IRQ_H__ >+ >+#include <linux/types.h> >+ >+#include "intel_display_limits.h" >+ >+enum pipe; >+struct drm_i915_private; >+struct drm_crtc; >+ >+void valleyview_enable_display_irqs(struct drm_i915_private *i915); >+void valleyview_disable_display_irqs(struct drm_i915_private *i915); >+ >+void ilk_update_display_irq(struct drm_i915_private *i915, >+ u32 interrupt_mask, u32 enabled_irq_mask); >+void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits); >+void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits); >+ >+void bdw_update_port_irq(struct drm_i915_private *i915, u32 interrupt_mask, u32 enabled_irq_mask); >+void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); >+void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); >+ >+void ibx_display_interrupt_update(struct drm_i915_private *i915, >+ u32 interrupt_mask, u32 enabled_irq_mask); >+void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits); >+void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits); >+ >+void gen8_irq_power_well_post_enable(struct drm_i915_private *i915, u8 pipe_mask); >+void gen8_irq_power_well_pre_disable(struct drm_i915_private *i915, u8 pipe_mask); >+u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *i915); >+ >+int i8xx_enable_vblank(struct drm_crtc *crtc); >+int i915gm_enable_vblank(struct drm_crtc *crtc); >+int i965_enable_vblank(struct drm_crtc *crtc); >+int ilk_enable_vblank(struct drm_crtc *crtc); >+int bdw_enable_vblank(struct drm_crtc *crtc); >+void i8xx_disable_vblank(struct drm_crtc *crtc); >+void i915gm_disable_vblank(struct drm_crtc *crtc); >+void i965_disable_vblank(struct drm_crtc *crtc); >+void ilk_disable_vblank(struct drm_crtc *crtc); >+void bdw_disable_vblank(struct drm_crtc *crtc); >+ >+void ivb_display_irq_handler(struct drm_i915_private *i915, u32 de_iir); >+void ilk_display_irq_handler(struct drm_i915_private *i915, u32 de_iir); >+void gen8_de_irq_handler(struct drm_i915_private *i915, u32 master_ctl); >+void gen11_display_irq_handler(struct drm_i915_private *i915); >+ >+u32 gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl); >+void gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir); >+ >+void vlv_display_irq_reset(struct drm_i915_private *i915); >+void gen8_display_irq_reset(struct drm_i915_private *i915); >+void gen11_display_irq_reset(struct drm_i915_private *i915); >+ >+void ibx_irq_postinstall(struct drm_i915_private *i915); >+void vlv_display_irq_postinstall(struct drm_i915_private *i915); >+void icp_irq_postinstall(struct drm_i915_private *i915); >+void gen8_de_irq_postinstall(struct drm_i915_private *i915); >+void mtp_irq_postinstall(struct drm_i915_private *i915); >+void gen11_de_irq_postinstall(struct drm_i915_private *i915); >+ >+u32 i915_pipestat_enable_mask(struct drm_i915_private *i915, enum pipe pipe); >+void i915_enable_pipestat(struct drm_i915_private *i915, enum pipe pipe, u32 status_mask); >+void i915_disable_pipestat(struct drm_i915_private *i915, enum pipe pipe, u32 status_mask); >+void i915_enable_asle_pipestat(struct drm_i915_private *i915); >+void i9xx_pipestat_irq_reset(struct drm_i915_private *i915); >+ >+void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); I guess this one slipped out when fixing the error diagnosed by "-Werror=array-parameter=". Used "git show --color-moved ..." to help me review this one and changes look sane to me. With the above fixed, Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com> >+ >+void i915_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_stats[I915_MAX_PIPES]); >+void i965_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_stats[I915_MAX_PIPES]); >+void valleyview_pipestat_irq_handler(struct drm_i915_private *i915, u32 pipe_stats[I915_MAX_PIPES]); >+void i8xx_pipestat_irq_handler(struct drm_i915_private *i915, u16 iir, u32 pipe_stats[I915_MAX_PIPES]); >+ >+#endif /* __INTEL_DISPLAY_IRQ_H__ */ >diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c >index 41eabdf3e871..916009894d89 100644 >--- a/drivers/gpu/drm/i915/display/intel_display_power_well.c >+++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c >@@ -11,6 +11,7 @@ > #include "intel_combo_phy_regs.h" > #include "intel_crt.h" > #include "intel_de.h" >+#include "intel_display_irq.h" > #include "intel_display_power_well.h" > #include "intel_display_types.h" > #include "intel_dkl_phy.h" >diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c >index e7f77a225739..09a7fa6c0c37 100644 >--- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c >+++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c >@@ -27,8 +27,8 @@ > > #include "i915_drv.h" > #include "i915_reg.h" >-#include "i915_irq.h" > #include "intel_de.h" >+#include "intel_display_irq.h" > #include "intel_display_trace.h" > #include "intel_display_types.h" > #include "intel_fbc.h" >diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c >index 1d7ae49e073e..f95fa793fabb 100644 >--- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c >+++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c >@@ -4,9 +4,9 @@ > */ > > #include "i915_drv.h" >-#include "i915_irq.h" > #include "i915_reg.h" > #include "intel_de.h" >+#include "intel_display_irq.h" > #include "intel_display_types.h" > #include "intel_dp_aux.h" > #include "intel_gmbus.h" >diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c >index 96fe4a280077..36b479b46b60 100644 >--- a/drivers/gpu/drm/i915/display/intel_tv.c >+++ b/drivers/gpu/drm/i915/display/intel_tv.c >@@ -35,11 +35,11 @@ > #include <drm/drm_edid.h> > > #include "i915_drv.h" >-#include "i915_irq.h" > #include "i915_reg.h" > #include "intel_connector.h" > #include "intel_crtc.h" > #include "intel_de.h" >+#include "intel_display_irq.h" > #include "intel_display_types.h" > #include "intel_dpll.h" > #include "intel_hotplug.h" >diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c >index 8ea0598a5a07..1ea664a366c1 100644 >--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c >+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c >@@ -9,10 +9,10 @@ > #include <drm/drm_fourcc.h> > > #include "i915_drv.h" >-#include "i915_irq.h" > #include "i915_reg.h" > #include "intel_atomic_plane.h" > #include "intel_de.h" >+#include "intel_display_irq.h" > #include "intel_display_types.h" > #include "intel_fb.h" > #include "intel_fbc.h" >diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c >index 80968e49e2c3..e68a99205599 100644 >--- a/drivers/gpu/drm/i915/gt/intel_rps.c >+++ b/drivers/gpu/drm/i915/gt/intel_rps.c >@@ -8,6 +8,7 @@ > #include <drm/i915_drm.h> > > #include "display/intel_display.h" >+#include "display/intel_display_irq.h" > #include "i915_drv.h" > #include "i915_irq.h" > #include "i915_reg.h" >diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c >index 61f53b283210..82fbabcdd7a5 100644 >--- a/drivers/gpu/drm/i915/i915_irq.c >+++ b/drivers/gpu/drm/i915/i915_irq.c >@@ -33,18 +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_dp_aux.h" >-#include "display/intel_fdi_regs.h" >-#include "display/intel_fifo_underrun.h" >-#include "display/intel_gmbus.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" >@@ -85,14 +78,6 @@ static inline void pmu_irq_stats(struct drm_i915_private *i915, > WRITE_ONCE(i915->pmu.irq_count, i915->pmu.irq_count + 1); > } > >-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) > { >@@ -125,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); > >@@ -179,268 +164,6 @@ static void gen2_irq_init(struct intel_uncore *uncore, > intel_uncore_posting_read16(uncore, GEN2_IMR); > } > >-/** >- * 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 >- */ >-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 >- */ >-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 >- */ >-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. >@@ -525,278 +248,6 @@ static void ivb_parity_work(struct work_struct *work) > mutex_unlock(&dev_priv->drm.struct_mutex); > } > >-#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) >- intel_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) >- intel_gmbus_irq_handler(dev_priv); >-} >- > static irqreturn_t valleyview_irq_handler(int irq, void *arg) > { > struct drm_i915_private *dev_priv = arg; >@@ -961,217 +412,6 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) > return ret; > } > >-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) >- intel_dp_aux_irq_handler(dev_priv); >- >- if (pch_iir & SDE_GMBUS) >- intel_gmbus_irq_handler(dev_priv); >- >- if (pch_iir & SDE_AUDIO_HDCP_MASK) >- drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n"); >- >- if (pch_iir & SDE_AUDIO_TRANS_MASK) >- drm_dbg(&dev_priv->drm, "PCH transcoder audio interrupt\n"); >- >- if (pch_iir & SDE_POISON) >- drm_err(&dev_priv->drm, "PCH poison interrupt\n"); >- >- if (pch_iir & SDE_FDI_MASK) { >- for_each_pipe(dev_priv, pipe) >- drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", >- pipe_name(pipe), >- intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); >- } >- >- if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) >- drm_dbg(&dev_priv->drm, "PCH transcoder CRC done interrupt\n"); >- >- if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) >- drm_dbg(&dev_priv->drm, >- "PCH transcoder CRC error interrupt\n"); >- >- if (pch_iir & SDE_TRANSA_FIFO_UNDER) >- intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A); >- >- if (pch_iir & SDE_TRANSB_FIFO_UNDER) >- intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B); >-} >- >-static void ivb_err_int_handler(struct drm_i915_private *dev_priv) >-{ >- u32 err_int = intel_uncore_read(&dev_priv->uncore, GEN7_ERR_INT); >- enum pipe pipe; >- >- if (err_int & ERR_INT_POISON) >- drm_err(&dev_priv->drm, "Poison interrupt\n"); >- >- for_each_pipe(dev_priv, pipe) { >- if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) >- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); >- >- if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { >- if (IS_IVYBRIDGE(dev_priv)) >- ivb_pipe_crc_irq_handler(dev_priv, pipe); >- else >- hsw_pipe_crc_irq_handler(dev_priv, pipe); >- } >- } >- >- intel_uncore_write(&dev_priv->uncore, GEN7_ERR_INT, err_int); >-} >- >-static void cpt_serr_int_handler(struct drm_i915_private *dev_priv) >-{ >- u32 serr_int = intel_uncore_read(&dev_priv->uncore, SERR_INT); >- enum pipe pipe; >- >- if (serr_int & SERR_INT_POISON) >- drm_err(&dev_priv->drm, "PCH poison interrupt\n"); >- >- for_each_pipe(dev_priv, pipe) >- if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe)) >- intel_pch_fifo_underrun_irq_handler(dev_priv, pipe); >- >- intel_uncore_write(&dev_priv->uncore, SERR_INT, serr_int); >-} >- >-static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) >-{ >- enum pipe pipe; >- u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; >- >- ibx_hpd_irq_handler(dev_priv, hotplug_trigger); >- >- if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { >- int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> >- SDE_AUDIO_POWER_SHIFT_CPT); >- drm_dbg(&dev_priv->drm, "PCH audio power change on port %c\n", >- port_name(port)); >- } >- >- if (pch_iir & SDE_AUX_MASK_CPT) >- intel_dp_aux_irq_handler(dev_priv); >- >- if (pch_iir & SDE_GMBUS_CPT) >- intel_gmbus_irq_handler(dev_priv); >- >- if (pch_iir & SDE_AUDIO_CP_REQ_CPT) >- drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n"); >- >- if (pch_iir & SDE_AUDIO_CP_CHG_CPT) >- drm_dbg(&dev_priv->drm, "Audio CP change interrupt\n"); >- >- if (pch_iir & SDE_FDI_MASK_CPT) { >- for_each_pipe(dev_priv, pipe) >- drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", >- pipe_name(pipe), >- intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); >- } >- >- if (pch_iir & SDE_ERROR_CPT) >- cpt_serr_int_handler(dev_priv); >-} >- >-static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, >- u32 de_iir) >-{ >- enum pipe pipe; >- u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; >- >- if (hotplug_trigger) >- ilk_hpd_irq_handler(dev_priv, hotplug_trigger); >- >- if (de_iir & DE_AUX_CHANNEL_A) >- intel_dp_aux_irq_handler(dev_priv); >- >- if (de_iir & DE_GSE) >- intel_opregion_asle_intr(dev_priv); >- >- if (de_iir & DE_POISON) >- drm_err(&dev_priv->drm, "Poison interrupt\n"); >- >- for_each_pipe(dev_priv, pipe) { >- if (de_iir & DE_PIPE_VBLANK(pipe)) >- intel_handle_vblank(dev_priv, pipe); >- >- if (de_iir & DE_PLANE_FLIP_DONE(pipe)) >- flip_done_handler(dev_priv, pipe); >- >- if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) >- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); >- >- if (de_iir & DE_PIPE_CRC_DONE(pipe)) >- i9xx_pipe_crc_irq_handler(dev_priv, pipe); >- } >- >- /* check event from PCH */ >- if (de_iir & DE_PCH_EVENT) { >- u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); >- >- if (HAS_PCH_CPT(dev_priv)) >- cpt_irq_handler(dev_priv, pch_iir); >- else >- ibx_irq_handler(dev_priv, pch_iir); >- >- /* should clear PCH hotplug event before clear CPU irq */ >- intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); >- } >- >- if (DISPLAY_VER(dev_priv) == 5 && de_iir & DE_PCU_EVENT) >- gen5_rps_irq_handler(&to_gt(dev_priv)->rps); >-} >- >-static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, >- u32 de_iir) >-{ >- enum pipe pipe; >- u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; >- >- if (hotplug_trigger) >- ilk_hpd_irq_handler(dev_priv, hotplug_trigger); >- >- if (de_iir & DE_ERR_INT_IVB) >- ivb_err_int_handler(dev_priv); >- >- if (de_iir & DE_AUX_CHANNEL_A_IVB) >- intel_dp_aux_irq_handler(dev_priv); >- >- if (de_iir & DE_GSE_IVB) >- intel_opregion_asle_intr(dev_priv); >- >- for_each_pipe(dev_priv, pipe) { >- if (de_iir & DE_PIPE_VBLANK_IVB(pipe)) >- intel_handle_vblank(dev_priv, pipe); >- >- if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) >- flip_done_handler(dev_priv, pipe); >- } >- >- /* check event from PCH */ >- if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) { >- u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); >- >- cpt_irq_handler(dev_priv, pch_iir); >- >- /* clear PCH hotplug event before clear CPU irq */ >- intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); >- } >-} >- > /* > * To handle irqs with the minimum potential races with fresh interrupts, we: > * 1 - Disable Master Interrupt Control. >@@ -1246,353 +486,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) > > /* IRQs are synced during runtime_suspend, we don't require a wakeref */ > enable_rpm_wakeref_asserts(&i915->runtime_pm); >- >- return ret; >-} >- >-static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) >-{ >- u32 mask; >- >- if (DISPLAY_VER(dev_priv) >= 14) >- return TGL_DE_PORT_AUX_DDIA | >- TGL_DE_PORT_AUX_DDIB; >- else if (DISPLAY_VER(dev_priv) >= 13) >- return TGL_DE_PORT_AUX_DDIA | >- TGL_DE_PORT_AUX_DDIB | >- TGL_DE_PORT_AUX_DDIC | >- XELPD_DE_PORT_AUX_DDID | >- XELPD_DE_PORT_AUX_DDIE | >- TGL_DE_PORT_AUX_USBC1 | >- TGL_DE_PORT_AUX_USBC2 | >- TGL_DE_PORT_AUX_USBC3 | >- TGL_DE_PORT_AUX_USBC4; >- else if (DISPLAY_VER(dev_priv) >= 12) >- return TGL_DE_PORT_AUX_DDIA | >- TGL_DE_PORT_AUX_DDIB | >- TGL_DE_PORT_AUX_DDIC | >- TGL_DE_PORT_AUX_USBC1 | >- TGL_DE_PORT_AUX_USBC2 | >- TGL_DE_PORT_AUX_USBC3 | >- TGL_DE_PORT_AUX_USBC4 | >- TGL_DE_PORT_AUX_USBC5 | >- TGL_DE_PORT_AUX_USBC6; >- >- >- mask = GEN8_AUX_CHANNEL_A; >- if (DISPLAY_VER(dev_priv) >= 9) >- mask |= GEN9_AUX_CHANNEL_B | >- GEN9_AUX_CHANNEL_C | >- GEN9_AUX_CHANNEL_D; >- >- if (DISPLAY_VER(dev_priv) == 11) { >- mask |= ICL_AUX_CHANNEL_F; >- mask |= ICL_AUX_CHANNEL_E; >- } >- >- return mask; >-} >- >-static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) >-{ >- if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) >- return RKL_DE_PIPE_IRQ_FAULT_ERRORS; >- else if (DISPLAY_VER(dev_priv) >= 11) >- return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; >- else if (DISPLAY_VER(dev_priv) >= 9) >- return GEN9_DE_PIPE_IRQ_FAULT_ERRORS; >- else >- return GEN8_DE_PIPE_IRQ_FAULT_ERRORS; >-} >- >-static void >-gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) >-{ >- bool found = false; >- >- if (iir & GEN8_DE_MISC_GSE) { >- intel_opregion_asle_intr(dev_priv); >- found = true; >- } >- >- if (iir & GEN8_DE_EDP_PSR) { >- struct intel_encoder *encoder; >- u32 psr_iir; >- i915_reg_t iir_reg; >- >- for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { >- struct intel_dp *intel_dp = enc_to_intel_dp(encoder); >- >- if (DISPLAY_VER(dev_priv) >= 12) >- iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder); >- else >- iir_reg = EDP_PSR_IIR; >- >- psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0); >- >- if (psr_iir) >- found = true; >- >- intel_psr_irq_handler(intel_dp, psr_iir); >- >- /* prior GEN12 only have one EDP PSR */ >- if (DISPLAY_VER(dev_priv) < 12) >- break; >- } >- } >- >- if (!found) >- drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); >-} >- >-static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, >- u32 te_trigger) >-{ >- enum pipe pipe = INVALID_PIPE; >- enum transcoder dsi_trans; >- enum port port; >- u32 val, tmp; >- >- /* >- * Incase of dual link, TE comes from DSI_1 >- * this is to check if dual link is enabled >- */ >- val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0)); >- val &= PORT_SYNC_MODE_ENABLE; >- >- /* >- * if dual link is enabled, then read DSI_0 >- * transcoder registers >- */ >- port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ? >- PORT_A : PORT_B; >- dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1; >- >- /* Check if DSI configured in command mode */ >- val = intel_uncore_read(&dev_priv->uncore, DSI_TRANS_FUNC_CONF(dsi_trans)); >- val = val & OP_MODE_MASK; >- >- if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) { >- drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n"); >- return; >- } >- >- /* Get PIPE for handling VBLANK event */ >- val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL(dsi_trans)); >- switch (val & TRANS_DDI_EDP_INPUT_MASK) { >- case TRANS_DDI_EDP_INPUT_A_ON: >- pipe = PIPE_A; >- break; >- case TRANS_DDI_EDP_INPUT_B_ONOFF: >- pipe = PIPE_B; >- break; >- case TRANS_DDI_EDP_INPUT_C_ONOFF: >- pipe = PIPE_C; >- break; >- default: >- drm_err(&dev_priv->drm, "Invalid PIPE\n"); >- return; >- } >- >- intel_handle_vblank(dev_priv, pipe); >- >- /* clear TE in dsi IIR */ >- port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; >- tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); >-} >- >-static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915) >-{ >- if (DISPLAY_VER(i915) >= 9) >- return GEN9_PIPE_PLANE1_FLIP_DONE; >- else >- return GEN8_PIPE_PRIMARY_FLIP_DONE; >-} >- >-u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv) >-{ >- u32 mask = GEN8_PIPE_FIFO_UNDERRUN; >- >- if (DISPLAY_VER(dev_priv) >= 13) >- mask |= XELPD_PIPE_SOFT_UNDERRUN | >- XELPD_PIPE_HARD_UNDERRUN; >- >- return mask; >-} >- >-static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_iir, u32 *pica_iir) >-{ >- u32 pica_ier = 0; >- >- *pica_iir = 0; >- *pch_iir = intel_de_read(i915, SDEIIR); >- if (!*pch_iir) >- return; >- >- /** >- * PICA IER must be disabled/re-enabled around clearing PICA IIR and >- * SDEIIR, to avoid losing PICA IRQs and to ensure that such IRQs set >- * their flags both in the PICA and SDE IIR. >- */ >- if (*pch_iir & SDE_PICAINTERRUPT) { >- drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); >- >- pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); >- *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); >- intel_de_write(i915, PICAINTERRUPT_IIR, *pica_iir); >- } >- >- intel_de_write(i915, SDEIIR, *pch_iir); >- >- if (pica_ier) >- intel_de_write(i915, PICAINTERRUPT_IER, pica_ier); >-} >- >-static void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) >-{ >- u32 iir; >- enum pipe pipe; >- >- drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DISPLAY(dev_priv)); >- >- if (master_ctl & GEN8_DE_MISC_IRQ) { >- iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); >- if (iir) { >- intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir); >- gen8_de_misc_irq_handler(dev_priv, iir); >- } else { >- drm_err_ratelimited(&dev_priv->drm, >- "The master control interrupt lied (DE MISC)!\n"); >- } >- } >- >- if (DISPLAY_VER(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { >- iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR); >- if (iir) { >- intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir); >- gen11_hpd_irq_handler(dev_priv, iir); >- } else { >- drm_err_ratelimited(&dev_priv->drm, >- "The master control interrupt lied, (DE HPD)!\n"); >- } >- } >- >- if (master_ctl & GEN8_DE_PORT_IRQ) { >- iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PORT_IIR); >- if (iir) { >- bool found = false; >- >- intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir); >- >- if (iir & gen8_de_port_aux_mask(dev_priv)) { >- intel_dp_aux_irq_handler(dev_priv); >- found = true; >- } >- >- if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { >- u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; >- >- if (hotplug_trigger) { >- bxt_hpd_irq_handler(dev_priv, hotplug_trigger); >- found = true; >- } >- } else if (IS_BROADWELL(dev_priv)) { >- u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK; >- >- if (hotplug_trigger) { >- ilk_hpd_irq_handler(dev_priv, hotplug_trigger); >- found = true; >- } >- } >- >- if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && >- (iir & BXT_DE_PORT_GMBUS)) { >- intel_gmbus_irq_handler(dev_priv); >- found = true; >- } >- >- if (DISPLAY_VER(dev_priv) >= 11) { >- u32 te_trigger = iir & (DSI0_TE | DSI1_TE); >- >- if (te_trigger) { >- gen11_dsi_te_interrupt_handler(dev_priv, te_trigger); >- found = true; >- } >- } >- >- if (!found) >- drm_err_ratelimited(&dev_priv->drm, >- "Unexpected DE Port interrupt\n"); >- } >- else >- drm_err_ratelimited(&dev_priv->drm, >- "The master control interrupt lied (DE PORT)!\n"); >- } >- >- for_each_pipe(dev_priv, pipe) { >- u32 fault_errors; >- >- if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) >- continue; >- >- iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe)); >- if (!iir) { >- drm_err_ratelimited(&dev_priv->drm, >- "The master control interrupt lied (DE PIPE)!\n"); >- continue; >- } >- >- intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir); >- >- if (iir & GEN8_PIPE_VBLANK) >- intel_handle_vblank(dev_priv, pipe); >- >- if (iir & gen8_de_pipe_flip_done_mask(dev_priv)) >- flip_done_handler(dev_priv, pipe); >- >- if (iir & GEN8_PIPE_CDCLK_CRC_DONE) >- hsw_pipe_crc_irq_handler(dev_priv, pipe); >- >- if (iir & gen8_de_pipe_underrun_mask(dev_priv)) >- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); >- >- fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv); >- if (fault_errors) >- drm_err_ratelimited(&dev_priv->drm, >- "Fault errors on pipe %c: 0x%08x\n", >- pipe_name(pipe), >- fault_errors); >- } >- >- if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) && >- master_ctl & GEN8_DE_PCH_IRQ) { >- u32 pica_iir; >- >- /* >- * FIXME(BDW): Assume for now that the new interrupt handling >- * scheme also closed the SDE interrupt handling race we've seen >- * on older pch-split platforms. But this needs testing. >- */ >- gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir); >- if (iir) { >- if (pica_iir) >- xelpdp_pica_irq_handler(dev_priv, pica_iir); >- >- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) >- icp_irq_handler(dev_priv, iir); >- else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) >- spt_irq_handler(dev_priv, iir); >- else >- cpt_irq_handler(dev_priv, iir); >- } else { >- /* >- * Like on previous PCH there seems to be something >- * fishy going on with forwarding PCH interrupts. >- */ >- drm_dbg(&dev_priv->drm, >- "The master control interrupt lied (SDE)!\n"); >- } >- } >+ >+ return ret; > } > > static inline u32 gen8_master_intr_disable(void __iomem * const regs) >@@ -1645,29 +540,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) > return IRQ_HANDLED; > } > >-static u32 >-gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl) >-{ >- void __iomem * const regs = i915->uncore.regs; >- u32 iir; >- >- if (!(master_ctl & GEN11_GU_MISC_IRQ)) >- return 0; >- >- iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); >- if (likely(iir)) >- raw_reg_write(regs, GEN11_GU_MISC_IIR, iir); >- >- return iir; >-} >- >-static void >-gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir) >-{ >- if (iir & GEN11_GU_MISC_GSE) >- intel_opregion_asle_intr(i915); >-} >- > static inline u32 gen11_master_intr_disable(void __iomem * const regs) > { > raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0); >@@ -1686,25 +558,6 @@ static inline void gen11_master_intr_enable(void __iomem * const regs) > raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ); > } > >-static void >-gen11_display_irq_handler(struct drm_i915_private *i915) >-{ >- void __iomem * const regs = i915->uncore.regs; >- const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL); >- >- disable_rpm_wakeref_asserts(&i915->runtime_pm); >- /* >- * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ >- * for the display related bits. >- */ >- raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, 0x0); >- gen8_de_irq_handler(i915, disp_ctl); >- raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, >- GEN11_DISPLAY_IRQ_ENABLE); >- >- enable_rpm_wakeref_asserts(&i915->runtime_pm); >-} >- > static irqreturn_t gen11_irq_handler(int irq, void *arg) > { > struct drm_i915_private *i915 = arg; >@@ -1806,184 +659,6 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) > return IRQ_HANDLED; > } > >-/* Called from drm generic code, passed 'crtc' which >- * we use as a pipe index >- */ >-int i8xx_enable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- enum pipe pipe = to_intel_crtc(crtc)->pipe; >- unsigned long irqflags; >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >- >- return 0; >-} >- >-int i915gm_enable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- >- /* >- * Vblank interrupts fail to wake the device up from C2+. >- * Disabling render clock gating during C-states avoids >- * the problem. There is a small power cost so we do this >- * only when vblank interrupts are actually enabled. >- */ >- if (dev_priv->vblank_enabled++ == 0) >- intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); >- >- return i8xx_enable_vblank(crtc); >-} >- >-int i965_enable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- enum pipe pipe = to_intel_crtc(crtc)->pipe; >- unsigned long irqflags; >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- i915_enable_pipestat(dev_priv, pipe, >- PIPE_START_VBLANK_INTERRUPT_STATUS); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >- >- return 0; >-} >- >-int ilk_enable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- enum pipe pipe = to_intel_crtc(crtc)->pipe; >- unsigned long irqflags; >- u32 bit = DISPLAY_VER(dev_priv) >= 7 ? >- DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- ilk_enable_display_irq(dev_priv, bit); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >- >- /* Even though there is no DMC, frame counter can get stuck when >- * PSR is active as no frames are generated. >- */ >- if (HAS_PSR(dev_priv)) >- drm_crtc_vblank_restore(crtc); >- >- return 0; >-} >- >-static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, >- bool enable) >-{ >- struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); >- enum port port; >- >- if (!(intel_crtc->mode_flags & >- (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) >- return false; >- >- /* for dual link cases we consider TE from slave */ >- if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1) >- port = PORT_B; >- else >- port = PORT_A; >- >- intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT, >- enable ? 0 : DSI_TE_EVENT); >- >- intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); >- >- return true; >-} >- >-int bdw_enable_vblank(struct drm_crtc *_crtc) >-{ >- struct intel_crtc *crtc = to_intel_crtc(_crtc); >- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); >- enum pipe pipe = crtc->pipe; >- unsigned long irqflags; >- >- if (gen11_dsi_configure_te(crtc, true)) >- return 0; >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >- >- /* Even if there is no DMC, frame counter can get stuck when >- * PSR is active as no frames are generated, so check only for PSR. >- */ >- if (HAS_PSR(dev_priv)) >- drm_crtc_vblank_restore(&crtc->base); >- >- return 0; >-} >- >-/* Called from drm generic code, passed 'crtc' which >- * we use as a pipe index >- */ >-void i8xx_disable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- enum pipe pipe = to_intel_crtc(crtc)->pipe; >- unsigned long irqflags; >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >-} >- >-void i915gm_disable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- >- i8xx_disable_vblank(crtc); >- >- if (--dev_priv->vblank_enabled == 0) >- intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); >-} >- >-void i965_disable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- enum pipe pipe = to_intel_crtc(crtc)->pipe; >- unsigned long irqflags; >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- i915_disable_pipestat(dev_priv, pipe, >- PIPE_START_VBLANK_INTERRUPT_STATUS); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >-} >- >-void ilk_disable_vblank(struct drm_crtc *crtc) >-{ >- struct drm_i915_private *dev_priv = to_i915(crtc->dev); >- enum pipe pipe = to_intel_crtc(crtc)->pipe; >- unsigned long irqflags; >- u32 bit = DISPLAY_VER(dev_priv) >= 7 ? >- DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- ilk_disable_display_irq(dev_priv, bit); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >-} >- >-void bdw_disable_vblank(struct drm_crtc *_crtc) >-{ >- struct intel_crtc *crtc = to_intel_crtc(_crtc); >- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); >- enum pipe pipe = crtc->pipe; >- unsigned long irqflags; >- >- if (gen11_dsi_configure_te(crtc, false)) >- return; >- >- spin_lock_irqsave(&dev_priv->irq_lock, irqflags); >- bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); >- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); >-} >- > static void ibx_irq_reset(struct drm_i915_private *dev_priv) > { > struct intel_uncore *uncore = &dev_priv->uncore; >@@ -1997,55 +672,6 @@ static void ibx_irq_reset(struct drm_i915_private *dev_priv) > intel_uncore_write(&dev_priv->uncore, SERR_INT, 0xffffffff); > } > >-static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- >- if (IS_CHERRYVIEW(dev_priv)) >- intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); >- else >- intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); >- >- i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); >- intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); >- >- i9xx_pipestat_irq_reset(dev_priv); >- >- GEN3_IRQ_RESET(uncore, VLV_); >- dev_priv->irq_mask = ~0u; >-} >- >-static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- >- u32 pipestat_mask; >- u32 enable_mask; >- enum pipe pipe; >- >- pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS; >- >- i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); >- for_each_pipe(dev_priv, pipe) >- i915_enable_pipestat(dev_priv, pipe, pipestat_mask); >- >- enable_mask = I915_DISPLAY_PORT_INTERRUPT | >- I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | >- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | >- I915_LPE_PIPE_A_INTERRUPT | >- I915_LPE_PIPE_B_INTERRUPT; >- >- if (IS_CHERRYVIEW(dev_priv)) >- enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | >- I915_LPE_PIPE_C_INTERRUPT; >- >- drm_WARN_ON(&dev_priv->drm, dev_priv->irq_mask != ~0u); >- >- dev_priv->irq_mask = ~enable_mask; >- >- GEN3_IRQ_INIT(uncore, VLV_, dev_priv->irq_mask, enable_mask); >-} >- > /* drm_dma.h hooks > */ > static void ilk_irq_reset(struct drm_i915_private *dev_priv) >@@ -2081,26 +707,6 @@ static void valleyview_irq_reset(struct drm_i915_private *dev_priv) > spin_unlock_irq(&dev_priv->irq_lock); > } > >-static void gen8_display_irq_reset(struct drm_i915_private *dev_priv) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- enum pipe pipe; >- >- if (!HAS_DISPLAY(dev_priv)) >- return; >- >- intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); >- intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); >- >- for_each_pipe(dev_priv, pipe) >- if (intel_display_power_is_enabled(dev_priv, >- POWER_DOMAIN_PIPE(pipe))) >- GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); >- >- GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); >- GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); >-} >- > static void gen8_irq_reset(struct drm_i915_private *dev_priv) > { > struct intel_uncore *uncore = &dev_priv->uncore; >@@ -2116,53 +722,6 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv) > > } > >-static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- enum pipe pipe; >- u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | >- BIT(TRANSCODER_C) | BIT(TRANSCODER_D); >- >- if (!HAS_DISPLAY(dev_priv)) >- return; >- >- intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0); >- >- if (DISPLAY_VER(dev_priv) >= 12) { >- enum transcoder trans; >- >- for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { >- enum intel_display_power_domain domain; >- >- domain = POWER_DOMAIN_TRANSCODER(trans); >- if (!intel_display_power_is_enabled(dev_priv, domain)) >- continue; >- >- intel_uncore_write(uncore, TRANS_PSR_IMR(trans), 0xffffffff); >- intel_uncore_write(uncore, TRANS_PSR_IIR(trans), 0xffffffff); >- } >- } else { >- intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); >- intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); >- } >- >- for_each_pipe(dev_priv, pipe) >- if (intel_display_power_is_enabled(dev_priv, >- POWER_DOMAIN_PIPE(pipe))) >- GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); >- >- GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); >- GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); >- >- if (DISPLAY_VER(dev_priv) >= 14) >- GEN3_IRQ_RESET(uncore, PICAINTERRUPT_); >- else >- GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); >- >- if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) >- GEN3_IRQ_RESET(uncore, SDE); >-} >- > static void gen11_irq_reset(struct drm_i915_private *dev_priv) > { > struct intel_gt *gt = to_gt(dev_priv); >@@ -2194,52 +753,6 @@ static void dg1_irq_reset(struct drm_i915_private *dev_priv) > GEN3_IRQ_RESET(uncore, GEN8_PCU_); > } > >-void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, >- u8 pipe_mask) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- u32 extra_ier = GEN8_PIPE_VBLANK | >- gen8_de_pipe_underrun_mask(dev_priv) | >- gen8_de_pipe_flip_done_mask(dev_priv); >- enum pipe pipe; >- >- spin_lock_irq(&dev_priv->irq_lock); >- >- if (!intel_irqs_enabled(dev_priv)) { >- spin_unlock_irq(&dev_priv->irq_lock); >- return; >- } >- >- for_each_pipe_masked(dev_priv, pipe, pipe_mask) >- GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, >- dev_priv->de_irq_mask[pipe], >- ~dev_priv->de_irq_mask[pipe] | extra_ier); >- >- spin_unlock_irq(&dev_priv->irq_lock); >-} >- >-void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, >- u8 pipe_mask) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- enum pipe pipe; >- >- spin_lock_irq(&dev_priv->irq_lock); >- >- if (!intel_irqs_enabled(dev_priv)) { >- spin_unlock_irq(&dev_priv->irq_lock); >- return; >- } >- >- for_each_pipe_masked(dev_priv, pipe, pipe_mask) >- GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); >- >- spin_unlock_irq(&dev_priv->irq_lock); >- >- /* make sure we're done processing display irqs */ >- intel_synchronize_irq(dev_priv); >-} >- > static void cherryview_irq_reset(struct drm_i915_private *dev_priv) > { > struct intel_uncore *uncore = &dev_priv->uncore; >@@ -2257,35 +770,6 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv) > spin_unlock_irq(&dev_priv->irq_lock); > } > >-/* >- * SDEIER is also touched by the interrupt handler to work around missed PCH >- * interrupts. Hence we can't update it after the interrupt handler is enabled - >- * instead we unconditionally enable all PCH interrupt sources here, but then >- * only unmask them as needed with SDEIMR. >- * >- * Note that we currently do this after installing the interrupt handler, >- * but before we enable the master interrupt. That should be sufficient >- * to avoid races with the irq handler, assuming we have MSI. Shared legacy >- * interrupts could still race. >- */ >-static void ibx_irq_postinstall(struct drm_i915_private *dev_priv) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- u32 mask; >- >- if (HAS_PCH_NOP(dev_priv)) >- return; >- >- if (HAS_PCH_IBX(dev_priv)) >- mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; >- else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) >- mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; >- else >- mask = SDE_GMBUS_CPT; >- >- GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); >-} >- > static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) > { > struct intel_uncore *uncore = &dev_priv->uncore; >@@ -2329,35 +813,6 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) > display_mask | extra_mask); > } > >-void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) >-{ >- lockdep_assert_held(&dev_priv->irq_lock); >- >- if (dev_priv->display_irqs_enabled) >- return; >- >- dev_priv->display_irqs_enabled = true; >- >- if (intel_irqs_enabled(dev_priv)) { >- vlv_display_irq_reset(dev_priv); >- vlv_display_irq_postinstall(dev_priv); >- } >-} >- >-void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) >-{ >- lockdep_assert_held(&dev_priv->irq_lock); >- >- if (!dev_priv->display_irqs_enabled) >- return; >- >- dev_priv->display_irqs_enabled = false; >- >- if (intel_irqs_enabled(dev_priv)) >- vlv_display_irq_reset(dev_priv); >-} >- >- > static void valleyview_irq_postinstall(struct drm_i915_private *dev_priv) > { > gen5_gt_irq_postinstall(to_gt(dev_priv)); >@@ -2371,108 +826,6 @@ static void valleyview_irq_postinstall(struct drm_i915_private *dev_priv) > intel_uncore_posting_read(&dev_priv->uncore, VLV_MASTER_IER); > } > >-static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- >- u32 de_pipe_masked = gen8_de_pipe_fault_mask(dev_priv) | >- GEN8_PIPE_CDCLK_CRC_DONE; >- u32 de_pipe_enables; >- u32 de_port_masked = gen8_de_port_aux_mask(dev_priv); >- u32 de_port_enables; >- u32 de_misc_masked = GEN8_DE_EDP_PSR; >- u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | >- BIT(TRANSCODER_C) | BIT(TRANSCODER_D); >- enum pipe pipe; >- >- if (!HAS_DISPLAY(dev_priv)) >- return; >- >- if (DISPLAY_VER(dev_priv) <= 10) >- de_misc_masked |= GEN8_DE_MISC_GSE; >- >- if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) >- de_port_masked |= BXT_DE_PORT_GMBUS; >- >- if (DISPLAY_VER(dev_priv) >= 11) { >- enum port port; >- >- if (intel_bios_is_dsi_present(dev_priv, &port)) >- de_port_masked |= DSI0_TE | DSI1_TE; >- } >- >- de_pipe_enables = de_pipe_masked | >- GEN8_PIPE_VBLANK | >- gen8_de_pipe_underrun_mask(dev_priv) | >- gen8_de_pipe_flip_done_mask(dev_priv); >- >- de_port_enables = de_port_masked; >- if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) >- de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; >- else if (IS_BROADWELL(dev_priv)) >- de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; >- >- if (DISPLAY_VER(dev_priv) >= 12) { >- enum transcoder trans; >- >- for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { >- enum intel_display_power_domain domain; >- >- domain = POWER_DOMAIN_TRANSCODER(trans); >- if (!intel_display_power_is_enabled(dev_priv, domain)) >- continue; >- >- gen3_assert_iir_is_zero(uncore, TRANS_PSR_IIR(trans)); >- } >- } else { >- gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR); >- } >- >- for_each_pipe(dev_priv, pipe) { >- dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; >- >- if (intel_display_power_is_enabled(dev_priv, >- POWER_DOMAIN_PIPE(pipe))) >- GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, >- dev_priv->de_irq_mask[pipe], >- de_pipe_enables); >- } >- >- GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables); >- GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); >- >- if (IS_DISPLAY_VER(dev_priv, 11, 13)) { >- u32 de_hpd_masked = 0; >- u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | >- GEN11_DE_TBT_HOTPLUG_MASK; >- >- GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked, >- de_hpd_enables); >- } >-} >- >-static void mtp_irq_postinstall(struct drm_i915_private *i915) >-{ >- struct intel_uncore *uncore = &i915->uncore; >- u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT; >- u32 de_hpd_mask = XELPDP_AUX_TC_MASK; >- u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK | >- XELPDP_TBT_HOTPLUG_MASK; >- >- GEN3_IRQ_INIT(uncore, PICAINTERRUPT_, ~de_hpd_mask, >- de_hpd_enables); >- >- GEN3_IRQ_INIT(uncore, SDE, ~sde_mask, 0xffffffff); >-} >- >-static void icp_irq_postinstall(struct drm_i915_private *dev_priv) >-{ >- struct intel_uncore *uncore = &dev_priv->uncore; >- u32 mask = SDE_GMBUS_ICP; >- >- GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); >-} >- > static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) > { > if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) >@@ -2486,17 +839,6 @@ static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) > gen8_master_intr_enable(dev_priv->uncore.regs); > } > >-static void gen11_de_irq_postinstall(struct drm_i915_private *dev_priv) >-{ >- if (!HAS_DISPLAY(dev_priv)) >- return; >- >- gen8_de_irq_postinstall(dev_priv); >- >- intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, >- GEN11_DISPLAY_IRQ_ENABLE); >-} >- > static void gen11_irq_postinstall(struct drm_i915_private *dev_priv) > { > struct intel_gt *gt = to_gt(dev_priv); >diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h >index 913c854f873d..e665a1b007dc 100644 >--- a/drivers/gpu/drm/i915/i915_irq.h >+++ b/drivers/gpu/drm/i915/i915_irq.h >@@ -25,34 +25,6 @@ void intel_irq_fini(struct drm_i915_private *dev_priv); > int intel_irq_install(struct drm_i915_private *dev_priv); > void intel_irq_uninstall(struct drm_i915_private *dev_priv); > >-u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv, >- enum pipe pipe); >-void >-i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, >- u32 status_mask); >- >-void >-i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, >- u32 status_mask); >- >-void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv); >-void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv); >- >-void ilk_update_display_irq(struct drm_i915_private *i915, >- u32 interrupt_mask, u32 enabled_irq_mask); >-void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits); >-void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits); >- >-void bdw_update_port_irq(struct drm_i915_private *i915, >- u32 interrupt_mask, u32 enabled_irq_mask); >-void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); >-void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); >- >-void ibx_display_interrupt_update(struct drm_i915_private *i915, >- u32 interrupt_mask, u32 enabled_irq_mask); >-void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits); >-void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits); >- > void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, u32 mask); > void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, u32 mask); > void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv); >@@ -68,23 +40,7 @@ bool intel_irqs_enabled(struct drm_i915_private *dev_priv); > void intel_synchronize_irq(struct drm_i915_private *i915); > void intel_synchronize_hardirq(struct drm_i915_private *i915); > >-void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, >- u8 pipe_mask); >-void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, >- u8 pipe_mask); >-u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv); >- >- >-int i8xx_enable_vblank(struct drm_crtc *crtc); >-int i915gm_enable_vblank(struct drm_crtc *crtc); >-int i965_enable_vblank(struct drm_crtc *crtc); >-int ilk_enable_vblank(struct drm_crtc *crtc); >-int bdw_enable_vblank(struct drm_crtc *crtc); >-void i8xx_disable_vblank(struct drm_crtc *crtc); >-void i915gm_disable_vblank(struct drm_crtc *crtc); >-void i965_disable_vblank(struct drm_crtc *crtc); >-void ilk_disable_vblank(struct drm_crtc *crtc); >-void bdw_disable_vblank(struct drm_crtc *crtc); >+void gen3_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg); > > void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr, > i915_reg_t iir, i915_reg_t ier); >-- >2.39.2 > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-12 13:48 ` Gustavo Sousa @ 2023-05-12 18:21 ` Jani Nikula 2023-05-15 10:05 ` Jani Nikula 1 sibling, 0 replies; 15+ messages in thread From: Jani Nikula @ 2023-05-12 18:21 UTC (permalink / raw) To: Gustavo Sousa, intel-gfx On Fri, 12 May 2023, Gustavo Sousa <gustavo.sousa@intel.com> wrote: > Quoting Jani Nikula (2023-05-12 07:23:10) >>Split (non-hotplug) display irq handling out of i915_irq.[ch] into >>display/intel_display_irq.[ch]. >> >>v2: >>- Rebase >>- Preserve [I915_MAX_PIPES] in functions (kernel test robot) >> >>Signed-off-by: Jani Nikula <jani.nikula@intel.com> >>+void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); > > I guess this one slipped out when fixing the error diagnosed by "-Werror=array-parameter=". Indeed, *facepalm*. I'm still rolling with gcc 10, and I believe that was introduced in gcc 11. > Used "git show --color-moved ..." to help me review this one and changes look > sane to me. With the above fixed, > > Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com> Thanks, Jani. -- Jani Nikula, Intel Open Source Graphics Center ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-12 13:48 ` Gustavo Sousa 2023-05-12 18:21 ` Jani Nikula @ 2023-05-15 10:05 ` Jani Nikula 1 sibling, 0 replies; 15+ messages in thread From: Jani Nikula @ 2023-05-15 10:05 UTC (permalink / raw) To: Gustavo Sousa, intel-gfx On Fri, 12 May 2023, Gustavo Sousa <gustavo.sousa@intel.com> wrote: > Used "git show --color-moved ..." to help me review this one and changes look > sane to me. Also, thanks for clueing me in on 'git show --color-moved'. It's fantastic! BR, Jani. -- Jani Nikula, Intel Open Source Graphics Center ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void 2023-05-12 10:23 [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Jani Nikula 2023-05-12 10:23 ` [Intel-gfx] [PATCH 2/3] drm/i915/irq: split out hotplug irq handling Jani Nikula 2023-05-12 10:23 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display " Jani Nikula @ 2023-05-12 11:52 ` Patchwork 2023-05-12 11:52 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork ` (2 subsequent siblings) 5 siblings, 0 replies; 15+ messages in thread From: Patchwork @ 2023-05-12 11:52 UTC (permalink / raw) To: Jani Nikula; +Cc: intel-gfx == Series Details == Series: series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void URL : https://patchwork.freedesktop.org/series/117682/ State : warning == Summary == Error: dim checkpatch failed 6066890538dc drm/i915/irq: convert gen8_de_irq_handler() to void 3bfbcdbdd7d4 drm/i915/irq: split out hotplug irq handling Traceback (most recent call last): File "scripts/spdxcheck.py", line 6, in <module> from ply import lex, yacc ModuleNotFoundError: No module named 'ply' Traceback (most recent call last): File "scripts/spdxcheck.py", line 6, in <module> from ply import lex, yacc ModuleNotFoundError: No module named 'ply' -:65: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating? #65: new file mode 100644 -:506: WARNING:LONG_LINE: line length of 104 exceeds 100 columns #506: FILE: drivers/gpu/drm/i915/display/intel_hotplug_irq.c:437: + u32 tmp = intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT) & hotplug_status_mask; total: 0 errors, 2 warnings, 0 checks, 3133 lines checked a9341aabe31a drm/i915/irq: split out display irq handling Traceback (most recent call last): File "scripts/spdxcheck.py", line 6, in <module> from ply import lex, yacc ModuleNotFoundError: No module named 'ply' Traceback (most recent call last): File "scripts/spdxcheck.py", line 6, in <module> from ply import lex, yacc ModuleNotFoundError: No module named 'ply' -:66: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating? #66: new file mode 100644 -:195: WARNING:LONG_LINE: line length of 107 exceeds 100 columns #195: FILE: drivers/gpu/drm/i915/display/intel_display_irq.c:125: + intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); -:442: WARNING:LONG_LINE: line length of 101 exceeds 100 columns #442: FILE: drivers/gpu/drm/i915/display/intel_display_irq.c:372: + intel_uncore_read(&dev_priv->uncore, PIPE_CRC_RES_5_IVB(pipe))); -:1256: WARNING:LONG_LINE: line length of 115 exceeds 100 columns #1256: FILE: drivers/gpu/drm/i915/display/intel_display_irq.c:1186: + intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); -:1364: WARNING:LONG_LINE: line length of 116 exceeds 100 columns #1364: FILE: drivers/gpu/drm/i915/display/intel_display_irq.c:1294: + intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); -:1820: WARNING:LONG_LINE: line length of 103 exceeds 100 columns #1820: FILE: drivers/gpu/drm/i915/display/intel_display_irq.h:76: +void i915_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_stats[I915_MAX_PIPES]); -:1821: WARNING:LONG_LINE: line length of 103 exceeds 100 columns #1821: FILE: drivers/gpu/drm/i915/display/intel_display_irq.h:77: +void i965_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_stats[I915_MAX_PIPES]); -:1823: WARNING:LONG_LINE: line length of 103 exceeds 100 columns #1823: FILE: drivers/gpu/drm/i915/display/intel_display_irq.h:79: +void i8xx_pipestat_irq_handler(struct drm_i915_private *i915, u16 iir, u32 pipe_stats[I915_MAX_PIPES]); total: 0 errors, 8 warnings, 0 checks, 3675 lines checked ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void 2023-05-12 10:23 [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Jani Nikula ` (2 preceding siblings ...) 2023-05-12 11:52 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Patchwork @ 2023-05-12 11:52 ` Patchwork 2023-05-12 12:10 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork 2023-05-12 12:50 ` [Intel-gfx] [PATCH 1/3] " Gustavo Sousa 5 siblings, 0 replies; 15+ messages in thread From: Patchwork @ 2023-05-12 11:52 UTC (permalink / raw) To: Jani Nikula; +Cc: intel-gfx == Series Details == Series: series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void URL : https://patchwork.freedesktop.org/series/117682/ State : warning == Summary == Error: dim sparse failed Sparse version: v0.6.2 Fast mode used, each commit won't be checked separately. +./arch/x86/include/asm/bitops.h:117:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:117:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:148:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:148:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:150:9: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:150:9: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:154:26: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:154:26: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:156:16: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:156:16: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:156:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:156:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:174:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:174:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:176:9: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:176:9: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:180:35: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:180:35: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:182:16: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:182:16: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:182:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:182:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:186:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:186:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:188:9: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:188:9: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:192:35: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:192:35: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:195:16: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:195:16: warning: unreplaced symbol 'oldbit' +./arch/x86/include/asm/bitops.h:195:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:195:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:237:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:237:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:239:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:239:9: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:66:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:66:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:92:1: warning: unreplaced symbol 'return' +./arch/x86/include/asm/bitops.h:92:1: warning: unreplaced symbol 'return' +drivers/gpu/drm/i915/i915_irq.c:495:9: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:503:16: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:508:9: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:545:9: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:553:16: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:558:9: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:601:9: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:604:15: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:608:9: warning: trying to copy expression type 31 +drivers/gpu/drm/i915/i915_irq.c:615:9: warning: trying to copy expression type 31 +./include/asm-generic/bitops/generic-non-atomic.h:100:17: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:100:17: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:100:23: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:100:23: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:100:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:100:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:105:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:105:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:107:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:107:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:108:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:108:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:109:9: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:109:9: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:111:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:111:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:111:14: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:111:14: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:111:20: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:111:20: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:112:17: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:112:17: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:112:23: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:112:23: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:112:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:112:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:121:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:121:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:128:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:128:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:166:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:166:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:168:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:168:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:169:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:169:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:170:9: warning: unreplaced symbol 'val' +./include/asm-generic/bitops/generic-non-atomic.h:170:9: warning: unreplaced symbol 'val' +./include/asm-generic/bitops/generic-non-atomic.h:172:19: warning: unreplaced symbol 'val' +./include/asm-generic/bitops/generic-non-atomic.h:172:19: warning: unreplaced symbol 'val' +./include/asm-generic/bitops/generic-non-atomic.h:172:25: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:172:25: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:172:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:172:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:28:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:28:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:30:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:30:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:31:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:31:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:33:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:33:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:33:16: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:33:16: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:37:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:37:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:39:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:39:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:40:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:40:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:42:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:42:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:42:16: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:42:16: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:55:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:55:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:57:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:57:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:58:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:58:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:60:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:60:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:60:15: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:60:15: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:73:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:73:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:75:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:75:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:76:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:76:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:77:9: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:77:9: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:79:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:79:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:79:14: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:79:14: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:79:20: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:79:20: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:80:17: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:80:17: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:80:23: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:80:23: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:80:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:80:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:93:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:93:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/generic-non-atomic.h:95:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:95:9: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:96:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:96:9: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:97:9: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:97:9: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:99:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:99:10: warning: unreplaced symbol 'p' +./include/asm-generic/bitops/generic-non-atomic.h:99:14: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:99:14: warning: unreplaced symbol 'old' +./include/asm-generic/bitops/generic-non-atomic.h:99:21: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/generic-non-atomic.h:99:21: warning: unreplaced symbol 'mask' +./include/asm-generic/bitops/instrumented-non-atomic.h:100:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:100:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:112:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:112:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:115:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:115:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:127:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:127:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:130:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:130:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:139:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:139:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:142:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:142:9: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:26:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:26:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:42:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:42:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:58:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:58:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:97:1: warning: unreplaced symbol 'return' +./include/asm-generic/bitops/instrumented-non-atomic.h:97:1: warning: unreplaced symbol 'return' -O:drivers/gpu/drm/i915/i915_irq.c:2286:9: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2294:16: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2299:9: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2359:9: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2367:16: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2372:9: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2434:9: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2437:15: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2441:9: warning: trying to copy expression type 31 -O:drivers/gpu/drm/i915/i915_irq.c:2448:9: warning: trying to copy expression type 31 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Intel-gfx] ✗ Fi.CI.BAT: failure for series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void 2023-05-12 10:23 [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Jani Nikula ` (3 preceding siblings ...) 2023-05-12 11:52 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork @ 2023-05-12 12:10 ` Patchwork 2023-05-12 12:50 ` [Intel-gfx] [PATCH 1/3] " Gustavo Sousa 5 siblings, 0 replies; 15+ messages in thread From: Patchwork @ 2023-05-12 12:10 UTC (permalink / raw) To: Jani Nikula; +Cc: intel-gfx [-- Attachment #1: Type: text/plain, Size: 8762 bytes --] == Series Details == Series: series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void URL : https://patchwork.freedesktop.org/series/117682/ State : failure == Summary == CI Bug Log - changes from CI_DRM_13141 -> Patchwork_117682v1 ==================================================== Summary ------- **FAILURE** Serious unknown changes coming with Patchwork_117682v1 absolutely need to be verified manually. If you think the reported changes have nothing to do with the changes introduced in Patchwork_117682v1, please notify your bug team to allow them to document this new failure mode, which will reduce false positives in CI. External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/index.html Participating hosts (41 -> 40) ------------------------------ Missing (1): fi-snb-2520m Possible new issues ------------------- Here are the unknown changes that may have been introduced in Patchwork_117682v1: ### IGT changes ### #### Possible regressions #### * igt@dmabuf@all-tests@dma_fence: - bat-adlm-1: NOTRUN -> [DMESG-FAIL][1] [1]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-adlm-1/igt@dmabuf@all-tests@dma_fence.html * igt@gem_ctx_create@basic: - fi-kbl-soraka: [PASS][2] -> [INCOMPLETE][3] [2]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/fi-kbl-soraka/igt@gem_ctx_create@basic.html [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/fi-kbl-soraka/igt@gem_ctx_create@basic.html * igt@gem_tiled_blits@basic: - bat-adls-5: [PASS][4] -> [DMESG-WARN][5] +1 similar issue [4]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-adls-5/igt@gem_tiled_blits@basic.html [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-adls-5/igt@gem_tiled_blits@basic.html Known issues ------------ Here are the changes found in Patchwork_117682v1 that come from known issues: ### IGT changes ### #### Issues hit #### * igt@dmabuf@all-tests@sanitycheck: - bat-adlm-1: NOTRUN -> [ABORT][6] ([i915#8423]) [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-adlm-1/igt@dmabuf@all-tests@sanitycheck.html * igt@i915_pm_backlight@basic-brightness@edp-1: - bat-rplp-1: NOTRUN -> [ABORT][7] ([i915#7077]) [7]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-rplp-1/igt@i915_pm_backlight@basic-brightness@edp-1.html * igt@kms_chamelium_hpd@common-hpd-after-suspend: - bat-jsl-3: NOTRUN -> [SKIP][8] ([i915#7828]) [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-jsl-3/igt@kms_chamelium_hpd@common-hpd-after-suspend.html * igt@kms_pipe_crc_basic@nonblocking-crc-frame-sequence: - bat-dg2-11: NOTRUN -> [SKIP][9] ([i915#1845] / [i915#5354]) +2 similar issues [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-dg2-11/igt@kms_pipe_crc_basic@nonblocking-crc-frame-sequence.html #### Possible fixes #### * igt@gem_exec_gttfill@basic: - bat-adls-5: [DMESG-WARN][10] -> [PASS][11] [10]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-adls-5/igt@gem_exec_gttfill@basic.html [11]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-adls-5/igt@gem_exec_gttfill@basic.html * igt@gem_exec_suspend@basic-s0@smem: - bat-jsl-3: [ABORT][12] ([i915#5122]) -> [PASS][13] [12]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-jsl-3/igt@gem_exec_suspend@basic-s0@smem.html [13]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-jsl-3/igt@gem_exec_suspend@basic-s0@smem.html * igt@i915_selftest@live@gt_heartbeat: - fi-kbl-soraka: [DMESG-FAIL][14] ([i915#5334] / [i915#7872]) -> [PASS][15] [14]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/fi-kbl-soraka/igt@i915_selftest@live@gt_heartbeat.html [15]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/fi-kbl-soraka/igt@i915_selftest@live@gt_heartbeat.html * igt@i915_selftest@live@hangcheck: - bat-adlm-1: [INCOMPLETE][16] ([i915#4983] / [i915#7677]) -> [PASS][17] [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-adlm-1/igt@i915_selftest@live@hangcheck.html [17]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-adlm-1/igt@i915_selftest@live@hangcheck.html * igt@i915_selftest@live@requests: - {bat-mtlp-6}: [ABORT][18] ([i915#4983] / [i915#7920] / [i915#7953]) -> [PASS][19] [18]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-mtlp-6/igt@i915_selftest@live@requests.html [19]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-mtlp-6/igt@i915_selftest@live@requests.html * igt@i915_selftest@live@slpc: - {bat-mtlp-8}: [DMESG-WARN][20] ([i915#6367] / [i915#7953]) -> [PASS][21] [20]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-mtlp-8/igt@i915_selftest@live@slpc.html [21]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-mtlp-8/igt@i915_selftest@live@slpc.html * igt@i915_suspend@basic-s3-without-i915: - bat-jsl-3: [FAIL][22] ([fdo#103375]) -> [PASS][23] [22]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-jsl-3/igt@i915_suspend@basic-s3-without-i915.html [23]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-jsl-3/igt@i915_suspend@basic-s3-without-i915.html #### Warnings #### * igt@i915_selftest@live@reset: - bat-rpls-2: [ABORT][24] ([i915#4983] / [i915#7461] / [i915#7913] / [i915#8347]) -> [ABORT][25] ([i915#4983] / [i915#7461] / [i915#7913] / [i915#7981] / [i915#8347]) [24]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-rpls-2/igt@i915_selftest@live@reset.html [25]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-rpls-2/igt@i915_selftest@live@reset.html * igt@kms_setmode@basic-clone-single-crtc: - bat-rplp-1: [ABORT][26] ([i915#4579] / [i915#8260]) -> [SKIP][27] ([i915#3555] / [i915#4579]) [26]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_13141/bat-rplp-1/igt@kms_setmode@basic-clone-single-crtc.html [27]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/bat-rplp-1/igt@kms_setmode@basic-clone-single-crtc.html {name}: This element is suppressed. This means it is ignored when computing the status of the difference (SUCCESS, WARNING, or FAILURE). [fdo#103375]: https://bugs.freedesktop.org/show_bug.cgi?id=103375 [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845 [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555 [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078 [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579 [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983 [i915#5122]: https://gitlab.freedesktop.org/drm/intel/issues/5122 [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334 [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354 [i915#6367]: https://gitlab.freedesktop.org/drm/intel/issues/6367 [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645 [i915#7077]: https://gitlab.freedesktop.org/drm/intel/issues/7077 [i915#7461]: https://gitlab.freedesktop.org/drm/intel/issues/7461 [i915#7677]: https://gitlab.freedesktop.org/drm/intel/issues/7677 [i915#7828]: https://gitlab.freedesktop.org/drm/intel/issues/7828 [i915#7872]: https://gitlab.freedesktop.org/drm/intel/issues/7872 [i915#7913]: https://gitlab.freedesktop.org/drm/intel/issues/7913 [i915#7920]: https://gitlab.freedesktop.org/drm/intel/issues/7920 [i915#7953]: https://gitlab.freedesktop.org/drm/intel/issues/7953 [i915#7981]: https://gitlab.freedesktop.org/drm/intel/issues/7981 [i915#8260]: https://gitlab.freedesktop.org/drm/intel/issues/8260 [i915#8347]: https://gitlab.freedesktop.org/drm/intel/issues/8347 [i915#8423]: https://gitlab.freedesktop.org/drm/intel/issues/8423 Build changes ------------- * Linux: CI_DRM_13141 -> Patchwork_117682v1 CI-20190529: 20190529 CI_DRM_13141: c201176285d7a79884421d1b907ec858c5aee657 @ git://anongit.freedesktop.org/gfx-ci/linux IGT_7285: d1cbf2bad9c2664ab8bd3bd0946510a52800912f @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git Patchwork_117682v1: c201176285d7a79884421d1b907ec858c5aee657 @ git://anongit.freedesktop.org/gfx-ci/linux ### Linux commits 6d6604b9d1a0 drm/i915/irq: split out display irq handling 70be5fc5d1c5 drm/i915/irq: split out hotplug irq handling f64fdd504a1d drm/i915/irq: convert gen8_de_irq_handler() to void == Logs == For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_117682v1/index.html [-- Attachment #2: Type: text/html, Size: 10180 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void 2023-05-12 10:23 [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Jani Nikula ` (4 preceding siblings ...) 2023-05-12 12:10 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork @ 2023-05-12 12:50 ` Gustavo Sousa 5 siblings, 0 replies; 15+ messages in thread From: Gustavo Sousa @ 2023-05-12 12:50 UTC (permalink / raw) To: Jani Nikula, intel-gfx; +Cc: jani.nikula Quoting Jani Nikula (2023-05-12 07:23:08) >The return value is not used for anything. > >Signed-off-by: Jani Nikula <jani.nikula@intel.com> Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com> >--- > drivers/gpu/drm/i915/i915_irq.c | 12 +----------- > 1 file changed, 1 insertion(+), 11 deletions(-) > >diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c >index 02b6cbb832e9..64cc52538206 100644 >--- a/drivers/gpu/drm/i915/i915_irq.c >+++ b/drivers/gpu/drm/i915/i915_irq.c >@@ -2124,10 +2124,8 @@ static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_i > intel_de_write(i915, PICAINTERRUPT_IER, pica_ier); > } > >-static irqreturn_t >-gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) >+static void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) > { >- irqreturn_t ret = IRQ_NONE; > u32 iir; > enum pipe pipe; > >@@ -2137,7 +2135,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) > iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); > if (iir) { > intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir); >- ret = IRQ_HANDLED; > gen8_de_misc_irq_handler(dev_priv, iir); > } else { > drm_err_ratelimited(&dev_priv->drm, >@@ -2149,7 +2146,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) > iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR); > if (iir) { > intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir); >- ret = IRQ_HANDLED; > gen11_hpd_irq_handler(dev_priv, iir); > } else { > drm_err_ratelimited(&dev_priv->drm, >@@ -2163,7 +2159,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) > bool found = false; > > intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir); >- ret = IRQ_HANDLED; > > if (iir & gen8_de_port_aux_mask(dev_priv)) { > intel_dp_aux_irq_handler(dev_priv); >@@ -2223,7 +2218,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) > continue; > } > >- ret = IRQ_HANDLED; > intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir); > > if (iir & GEN8_PIPE_VBLANK) >@@ -2257,8 +2251,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) > */ > gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir); > if (iir) { >- ret = IRQ_HANDLED; >- > if (pica_iir) > xelpdp_pica_irq_handler(dev_priv, pica_iir); > >@@ -2277,8 +2269,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) > "The master control interrupt lied (SDE)!\n"); > } > } >- >- return ret; > } > > static inline u32 gen8_master_intr_disable(void __iomem * const regs) >-- >2.39.2 > ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Intel-gfx] [PATCH 0/3] drm/i915: hotplug and display irq refactoring @ 2023-05-04 16:57 Jani Nikula 2023-05-04 16:57 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling Jani Nikula 0 siblings, 1 reply; 15+ messages in thread From: Jani Nikula @ 2023-05-04 16:57 UTC (permalink / raw) To: intel-gfx; +Cc: jani.nikula, rodrigo.vivi Move hotplug and display irq handling to their respective files under display/. This is a start, with mostly just code movement. Further work clarifying the borders between these files as well as renames is to be expected. BR, Jani. Jani Nikula (3): drm/i915/irq: relocate gmbus and dp aux irq handlers drm/i915/irq: split out hotplug irq handling drm/i915/irq: split out display irq handling drivers/gpu/drm/i915/Makefile | 2 + drivers/gpu/drm/i915/display/i9xx_plane.c | 2 +- drivers/gpu/drm/i915/display/intel_crt.c | 1 + drivers/gpu/drm/i915/display/intel_crtc.c | 2 +- .../gpu/drm/i915/display/intel_display_irq.c | 1677 ++++++++ .../gpu/drm/i915/display/intel_display_irq.h | 79 + .../i915/display/intel_display_power_well.c | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 1 + drivers/gpu/drm/i915/display/intel_dp_aux.c | 5 + drivers/gpu/drm/i915/display/intel_dp_aux.h | 3 + .../drm/i915/display/intel_fifo_underrun.c | 2 +- drivers/gpu/drm/i915/display/intel_gmbus.c | 5 + drivers/gpu/drm/i915/display/intel_gmbus.h | 2 + drivers/gpu/drm/i915/display/intel_hotplug.c | 1 + .../gpu/drm/i915/display/intel_hotplug_irq.c | 1442 +++++++ .../gpu/drm/i915/display/intel_hotplug_irq.h | 35 + drivers/gpu/drm/i915/display/intel_tv.c | 2 +- .../drm/i915/display/skl_universal_plane.c | 2 +- drivers/gpu/drm/i915/gt/intel_rps.c | 1 + drivers/gpu/drm/i915/i915_irq.c | 3638 ++--------------- drivers/gpu/drm/i915/i915_irq.h | 46 +- 21 files changed, 3528 insertions(+), 3421 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.c create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.h create mode 100644 drivers/gpu/drm/i915/display/intel_hotplug_irq.c create mode 100644 drivers/gpu/drm/i915/display/intel_hotplug_irq.h -- 2.39.2 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-04 16:57 [Intel-gfx] [PATCH 0/3] drm/i915: hotplug and display irq refactoring Jani Nikula @ 2023-05-04 16:57 ` Jani Nikula 2023-05-04 18:42 ` kernel test robot 2023-05-04 20:15 ` kernel test robot 0 siblings, 2 replies; 15+ messages in thread From: Jani Nikula @ 2023-05-04 16:57 UTC (permalink / raw) To: intel-gfx; +Cc: jani.nikula, rodrigo.vivi Split (non-hotplug) display irq handling out of i915_irq.[ch] into display/intel_display_irq.[ch]. Signed-off-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/i9xx_plane.c | 2 +- drivers/gpu/drm/i915/display/intel_crtc.c | 2 +- .../gpu/drm/i915/display/intel_display_irq.c | 1677 +++++++++++++++++ .../gpu/drm/i915/display/intel_display_irq.h | 79 + .../i915/display/intel_display_power_well.c | 1 + .../drm/i915/display/intel_fifo_underrun.c | 2 +- .../gpu/drm/i915/display/intel_hotplug_irq.c | 2 +- drivers/gpu/drm/i915/display/intel_tv.c | 2 +- .../drm/i915/display/skl_universal_plane.c | 2 +- drivers/gpu/drm/i915/gt/intel_rps.c | 1 + drivers/gpu/drm/i915/i915_irq.c | 1676 +--------------- drivers/gpu/drm/i915/i915_irq.h | 46 +- 13 files changed, 1770 insertions(+), 1723 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.c create mode 100644 drivers/gpu/drm/i915/display/intel_display_irq.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b8520aea6068..5a9ad491a2fd 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -239,6 +239,7 @@ i915-y += \ display/intel_cursor.o \ display/intel_display.o \ display/intel_display_driver.o \ + display/intel_display_irq.o \ display/intel_display_power.o \ display/intel_display_power_map.o \ display/intel_display_power_well.o \ diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index ecaeb7dc196b..616654adbfb8 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -8,12 +8,12 @@ #include <drm/drm_blend.h> #include <drm/drm_fourcc.h> -#include "i915_irq.h" #include "i915_reg.h" #include "i9xx_plane.h" #include "intel_atomic.h" #include "intel_atomic_plane.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index df7d05f1e14b..a79930a4e40f 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -11,7 +11,6 @@ #include <drm/drm_plane.h> #include <drm/drm_vblank_work.h> -#include "i915_irq.h" #include "i915_vgpu.h" #include "i9xx_plane.h" #include "icl_dsi.h" @@ -21,6 +20,7 @@ #include "intel_crtc.h" #include "intel_cursor.h" #include "intel_display_debugfs.h" +#include "intel_display_irq.h" #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_drrs.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c new file mode 100644 index 000000000000..e50821639da0 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -0,0 +1,1677 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" +#include "i915_irq.h" +#include "i915_reg.h" +#include "icl_dsi_regs.h" +#include "intel_display_irq.h" +#include "intel_display_types.h" +#include "intel_hotplug_irq.h" +#include "intel_psr_regs.h" +#include "intel_crtc.h" +#include "intel_display_trace.h" +#include "intel_dp_aux.h" +#include "intel_gmbus.h" +#include "intel_fifo_underrun.h" +#include "intel_psr.h" +#include "intel_fdi_regs.h" +#include "gt/intel_rps.h" +#include "intel_de.h" + +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); +} + +/** + * 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 + */ +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 + */ +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 + */ +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 + */ +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); +} + +#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); +} + +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; + } +} + +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); +} + +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); + } +} + +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); +} + +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) + intel_gmbus_irq_handler(dev_priv); +} + +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) + intel_gmbus_irq_handler(dev_priv); +} + +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) + intel_dp_aux_irq_handler(dev_priv); + + if (pch_iir & SDE_GMBUS) + intel_gmbus_irq_handler(dev_priv); + + if (pch_iir & SDE_AUDIO_HDCP_MASK) + drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n"); + + if (pch_iir & SDE_AUDIO_TRANS_MASK) + drm_dbg(&dev_priv->drm, "PCH transcoder audio interrupt\n"); + + if (pch_iir & SDE_POISON) + drm_err(&dev_priv->drm, "PCH poison interrupt\n"); + + if (pch_iir & SDE_FDI_MASK) { + for_each_pipe(dev_priv, pipe) + drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", + pipe_name(pipe), + intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); + } + + if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) + drm_dbg(&dev_priv->drm, "PCH transcoder CRC done interrupt\n"); + + if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) + drm_dbg(&dev_priv->drm, + "PCH transcoder CRC error interrupt\n"); + + if (pch_iir & SDE_TRANSA_FIFO_UNDER) + intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A); + + if (pch_iir & SDE_TRANSB_FIFO_UNDER) + intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B); +} + +static void ivb_err_int_handler(struct drm_i915_private *dev_priv) +{ + u32 err_int = intel_uncore_read(&dev_priv->uncore, GEN7_ERR_INT); + enum pipe pipe; + + if (err_int & ERR_INT_POISON) + drm_err(&dev_priv->drm, "Poison interrupt\n"); + + for_each_pipe(dev_priv, pipe) { + if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) + intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); + + if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { + if (IS_IVYBRIDGE(dev_priv)) + ivb_pipe_crc_irq_handler(dev_priv, pipe); + else + hsw_pipe_crc_irq_handler(dev_priv, pipe); + } + } + + intel_uncore_write(&dev_priv->uncore, GEN7_ERR_INT, err_int); +} + +static void cpt_serr_int_handler(struct drm_i915_private *dev_priv) +{ + u32 serr_int = intel_uncore_read(&dev_priv->uncore, SERR_INT); + enum pipe pipe; + + if (serr_int & SERR_INT_POISON) + drm_err(&dev_priv->drm, "PCH poison interrupt\n"); + + for_each_pipe(dev_priv, pipe) + if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe)) + intel_pch_fifo_underrun_irq_handler(dev_priv, pipe); + + intel_uncore_write(&dev_priv->uncore, SERR_INT, serr_int); +} + +static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) +{ + enum pipe pipe; + u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; + + ibx_hpd_irq_handler(dev_priv, hotplug_trigger); + + if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { + int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> + SDE_AUDIO_POWER_SHIFT_CPT); + drm_dbg(&dev_priv->drm, "PCH audio power change on port %c\n", + port_name(port)); + } + + if (pch_iir & SDE_AUX_MASK_CPT) + intel_dp_aux_irq_handler(dev_priv); + + if (pch_iir & SDE_GMBUS_CPT) + intel_gmbus_irq_handler(dev_priv); + + if (pch_iir & SDE_AUDIO_CP_REQ_CPT) + drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n"); + + if (pch_iir & SDE_AUDIO_CP_CHG_CPT) + drm_dbg(&dev_priv->drm, "Audio CP change interrupt\n"); + + if (pch_iir & SDE_FDI_MASK_CPT) { + for_each_pipe(dev_priv, pipe) + drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", + pipe_name(pipe), + intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); + } + + if (pch_iir & SDE_ERROR_CPT) + cpt_serr_int_handler(dev_priv); +} + +void ilk_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) +{ + enum pipe pipe; + u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; + + if (hotplug_trigger) + ilk_hpd_irq_handler(dev_priv, hotplug_trigger); + + if (de_iir & DE_AUX_CHANNEL_A) + intel_dp_aux_irq_handler(dev_priv); + + if (de_iir & DE_GSE) + intel_opregion_asle_intr(dev_priv); + + if (de_iir & DE_POISON) + drm_err(&dev_priv->drm, "Poison interrupt\n"); + + for_each_pipe(dev_priv, pipe) { + if (de_iir & DE_PIPE_VBLANK(pipe)) + intel_handle_vblank(dev_priv, pipe); + + if (de_iir & DE_PLANE_FLIP_DONE(pipe)) + flip_done_handler(dev_priv, pipe); + + if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) + intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); + + if (de_iir & DE_PIPE_CRC_DONE(pipe)) + i9xx_pipe_crc_irq_handler(dev_priv, pipe); + } + + /* check event from PCH */ + if (de_iir & DE_PCH_EVENT) { + u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); + + if (HAS_PCH_CPT(dev_priv)) + cpt_irq_handler(dev_priv, pch_iir); + else + ibx_irq_handler(dev_priv, pch_iir); + + /* should clear PCH hotplug event before clear CPU irq */ + intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); + } + + if (DISPLAY_VER(dev_priv) == 5 && de_iir & DE_PCU_EVENT) + gen5_rps_irq_handler(&to_gt(dev_priv)->rps); +} + +void ivb_display_irq_handler(struct drm_i915_private *dev_priv, u32 de_iir) +{ + enum pipe pipe; + u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; + + if (hotplug_trigger) + ilk_hpd_irq_handler(dev_priv, hotplug_trigger); + + if (de_iir & DE_ERR_INT_IVB) + ivb_err_int_handler(dev_priv); + + if (de_iir & DE_AUX_CHANNEL_A_IVB) + intel_dp_aux_irq_handler(dev_priv); + + if (de_iir & DE_GSE_IVB) + intel_opregion_asle_intr(dev_priv); + + for_each_pipe(dev_priv, pipe) { + if (de_iir & DE_PIPE_VBLANK_IVB(pipe)) + intel_handle_vblank(dev_priv, pipe); + + if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) + flip_done_handler(dev_priv, pipe); + } + + /* check event from PCH */ + if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) { + u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); + + cpt_irq_handler(dev_priv, pch_iir); + + /* clear PCH hotplug event before clear CPU irq */ + intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); + } +} + +static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) +{ + u32 mask; + + if (DISPLAY_VER(dev_priv) >= 14) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB; + else if (DISPLAY_VER(dev_priv) >= 13) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB | + TGL_DE_PORT_AUX_DDIC | + XELPD_DE_PORT_AUX_DDID | + XELPD_DE_PORT_AUX_DDIE | + TGL_DE_PORT_AUX_USBC1 | + TGL_DE_PORT_AUX_USBC2 | + TGL_DE_PORT_AUX_USBC3 | + TGL_DE_PORT_AUX_USBC4; + else if (DISPLAY_VER(dev_priv) >= 12) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB | + TGL_DE_PORT_AUX_DDIC | + TGL_DE_PORT_AUX_USBC1 | + TGL_DE_PORT_AUX_USBC2 | + TGL_DE_PORT_AUX_USBC3 | + TGL_DE_PORT_AUX_USBC4 | + TGL_DE_PORT_AUX_USBC5 | + TGL_DE_PORT_AUX_USBC6; + + mask = GEN8_AUX_CHANNEL_A; + if (DISPLAY_VER(dev_priv) >= 9) + mask |= GEN9_AUX_CHANNEL_B | + GEN9_AUX_CHANNEL_C | + GEN9_AUX_CHANNEL_D; + + if (DISPLAY_VER(dev_priv) == 11) { + mask |= ICL_AUX_CHANNEL_F; + mask |= ICL_AUX_CHANNEL_E; + } + + return mask; +} + +static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) +{ + if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) + return RKL_DE_PIPE_IRQ_FAULT_ERRORS; + else if (DISPLAY_VER(dev_priv) >= 11) + return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; + else if (DISPLAY_VER(dev_priv) >= 9) + return GEN9_DE_PIPE_IRQ_FAULT_ERRORS; + else + return GEN8_DE_PIPE_IRQ_FAULT_ERRORS; +} + +static void +gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) +{ + bool found = false; + + if (iir & GEN8_DE_MISC_GSE) { + intel_opregion_asle_intr(dev_priv); + found = true; + } + + if (iir & GEN8_DE_EDP_PSR) { + struct intel_encoder *encoder; + u32 psr_iir; + i915_reg_t iir_reg; + + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (DISPLAY_VER(dev_priv) >= 12) + iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder); + else + iir_reg = EDP_PSR_IIR; + + psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0); + + if (psr_iir) + found = true; + + intel_psr_irq_handler(intel_dp, psr_iir); + + /* prior GEN12 only have one EDP PSR */ + if (DISPLAY_VER(dev_priv) < 12) + break; + } + } + + if (!found) + drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); +} + +static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, + u32 te_trigger) +{ + enum pipe pipe = INVALID_PIPE; + enum transcoder dsi_trans; + enum port port; + u32 val, tmp; + + /* + * Incase of dual link, TE comes from DSI_1 + * this is to check if dual link is enabled + */ + val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0)); + val &= PORT_SYNC_MODE_ENABLE; + + /* + * if dual link is enabled, then read DSI_0 + * transcoder registers + */ + port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ? + PORT_A : PORT_B; + dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1; + + /* Check if DSI configured in command mode */ + val = intel_uncore_read(&dev_priv->uncore, DSI_TRANS_FUNC_CONF(dsi_trans)); + val = val & OP_MODE_MASK; + + if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) { + drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n"); + return; + } + + /* Get PIPE for handling VBLANK event */ + val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL(dsi_trans)); + switch (val & TRANS_DDI_EDP_INPUT_MASK) { + case TRANS_DDI_EDP_INPUT_A_ON: + pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + pipe = PIPE_C; + break; + default: + drm_err(&dev_priv->drm, "Invalid PIPE\n"); + return; + } + + intel_handle_vblank(dev_priv, pipe); + + /* clear TE in dsi IIR */ + port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; + tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); +} + +static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915) +{ + if (DISPLAY_VER(i915) >= 9) + return GEN9_PIPE_PLANE1_FLIP_DONE; + else + return GEN8_PIPE_PRIMARY_FLIP_DONE; +} + +u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv) +{ + u32 mask = GEN8_PIPE_FIFO_UNDERRUN; + + if (DISPLAY_VER(dev_priv) >= 13) + mask |= XELPD_PIPE_SOFT_UNDERRUN | + XELPD_PIPE_HARD_UNDERRUN; + + return mask; +} + +static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_iir, u32 *pica_iir) +{ + u32 pica_ier = 0; + + *pica_iir = 0; + *pch_iir = intel_de_read(i915, SDEIIR); + if (!*pch_iir) + return; + + /** + * PICA IER must be disabled/re-enabled around clearing PICA IIR and + * SDEIIR, to avoid losing PICA IRQs and to ensure that such IRQs set + * their flags both in the PICA and SDE IIR. + */ + if (*pch_iir & SDE_PICAINTERRUPT) { + drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); + + pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); + *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); + intel_de_write(i915, PICAINTERRUPT_IIR, *pica_iir); + } + + intel_de_write(i915, SDEIIR, *pch_iir); + + if (pica_ier) + intel_de_write(i915, PICAINTERRUPT_IER, pica_ier); +} + +void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) +{ + irqreturn_t ret = IRQ_NONE; + u32 iir; + enum pipe pipe; + + drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DISPLAY(dev_priv)); + + if (master_ctl & GEN8_DE_MISC_IRQ) { + iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); + if (iir) { + intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir); + ret = IRQ_HANDLED; + gen8_de_misc_irq_handler(dev_priv, iir); + } else { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied (DE MISC)!\n"); + } + } + + if (DISPLAY_VER(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { + iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR); + if (iir) { + intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir); + ret = IRQ_HANDLED; + gen11_hpd_irq_handler(dev_priv, iir); + } else { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied, (DE HPD)!\n"); + } + } + + if (master_ctl & GEN8_DE_PORT_IRQ) { + iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PORT_IIR); + if (iir) { + bool found = false; + + intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir); + ret = IRQ_HANDLED; + + if (iir & gen8_de_port_aux_mask(dev_priv)) { + intel_dp_aux_irq_handler(dev_priv); + found = true; + } + + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { + u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; + + if (hotplug_trigger) { + bxt_hpd_irq_handler(dev_priv, hotplug_trigger); + found = true; + } + } else if (IS_BROADWELL(dev_priv)) { + u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK; + + if (hotplug_trigger) { + ilk_hpd_irq_handler(dev_priv, hotplug_trigger); + found = true; + } + } + + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + (iir & BXT_DE_PORT_GMBUS)) { + intel_gmbus_irq_handler(dev_priv); + found = true; + } + + if (DISPLAY_VER(dev_priv) >= 11) { + u32 te_trigger = iir & (DSI0_TE | DSI1_TE); + + if (te_trigger) { + gen11_dsi_te_interrupt_handler(dev_priv, te_trigger); + found = true; + } + } + + if (!found) + drm_err_ratelimited(&dev_priv->drm, + "Unexpected DE Port interrupt\n"); + } else { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied (DE PORT)!\n"); + } + } + + for_each_pipe(dev_priv, pipe) { + u32 fault_errors; + + if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) + continue; + + iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe)); + if (!iir) { + drm_err_ratelimited(&dev_priv->drm, + "The master control interrupt lied (DE PIPE)!\n"); + continue; + } + + ret = IRQ_HANDLED; + intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir); + + if (iir & GEN8_PIPE_VBLANK) + intel_handle_vblank(dev_priv, pipe); + + if (iir & gen8_de_pipe_flip_done_mask(dev_priv)) + flip_done_handler(dev_priv, pipe); + + if (iir & GEN8_PIPE_CDCLK_CRC_DONE) + hsw_pipe_crc_irq_handler(dev_priv, pipe); + + if (iir & gen8_de_pipe_underrun_mask(dev_priv)) + intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); + + fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv); + if (fault_errors) + drm_err_ratelimited(&dev_priv->drm, + "Fault errors on pipe %c: 0x%08x\n", + pipe_name(pipe), + fault_errors); + } + + if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) && + master_ctl & GEN8_DE_PCH_IRQ) { + u32 pica_iir; + + /* + * FIXME(BDW): Assume for now that the new interrupt handling + * scheme also closed the SDE interrupt handling race we've seen + * on older pch-split platforms. But this needs testing. + */ + gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir); + if (iir) { + ret = IRQ_HANDLED; + + if (pica_iir) + xelpdp_pica_irq_handler(dev_priv, pica_iir); + + if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + icp_irq_handler(dev_priv, iir); + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) + spt_irq_handler(dev_priv, iir); + else + cpt_irq_handler(dev_priv, iir); + } else { + /* + * Like on previous PCH there seems to be something + * fishy going on with forwarding PCH interrupts. + */ + drm_dbg(&dev_priv->drm, + "The master control interrupt lied (SDE)!\n"); + } + } + + /* FIXME: return ret; */ +} + +u32 gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl) +{ + void __iomem * const regs = i915->uncore.regs; + u32 iir; + + if (!(master_ctl & GEN11_GU_MISC_IRQ)) + return 0; + + iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); + if (likely(iir)) + raw_reg_write(regs, GEN11_GU_MISC_IIR, iir); + + return iir; +} + +void gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir) +{ + if (iir & GEN11_GU_MISC_GSE) + intel_opregion_asle_intr(i915); +} + +void gen11_display_irq_handler(struct drm_i915_private *i915) +{ + void __iomem * const regs = i915->uncore.regs; + const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL); + + disable_rpm_wakeref_asserts(&i915->runtime_pm); + /* + * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ + * for the display related bits. + */ + raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, 0x0); + gen8_de_irq_handler(i915, disp_ctl); + raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, + GEN11_DISPLAY_IRQ_ENABLE); + + enable_rpm_wakeref_asserts(&i915->runtime_pm); +} + +/* Called from drm generic code, passed 'crtc' which + * we use as a pipe index + */ +int i8xx_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return 0; +} + +int i915gm_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + + /* + * Vblank interrupts fail to wake the device up from C2+. + * Disabling render clock gating during C-states avoids + * the problem. There is a small power cost so we do this + * only when vblank interrupts are actually enabled. + */ + if (dev_priv->vblank_enabled++ == 0) + intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); + + return i8xx_enable_vblank(crtc); +} + +int i965_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_enable_pipestat(dev_priv, pipe, + PIPE_START_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return 0; +} + +int ilk_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + u32 bit = DISPLAY_VER(dev_priv) >= 7 ? + DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ilk_enable_display_irq(dev_priv, bit); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + /* Even though there is no DMC, frame counter can get stuck when + * PSR is active as no frames are generated. + */ + if (HAS_PSR(dev_priv)) + drm_crtc_vblank_restore(crtc); + + return 0; +} + +static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, + bool enable) +{ + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + enum port port; + + if (!(intel_crtc->mode_flags & + (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) + return false; + + /* for dual link cases we consider TE from slave */ + if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1) + port = PORT_B; + else + port = PORT_A; + + intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT, + enable ? 0 : DSI_TE_EVENT); + + intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); + + return true; +} + +int bdw_enable_vblank(struct drm_crtc *_crtc) +{ + struct intel_crtc *crtc = to_intel_crtc(_crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + unsigned long irqflags; + + if (gen11_dsi_configure_te(crtc, true)) + return 0; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + /* Even if there is no DMC, frame counter can get stuck when + * PSR is active as no frames are generated, so check only for PSR. + */ + if (HAS_PSR(dev_priv)) + drm_crtc_vblank_restore(&crtc->base); + + return 0; +} + +/* Called from drm generic code, passed 'crtc' which + * we use as a pipe index + */ +void i8xx_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void i915gm_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + + i8xx_disable_vblank(crtc); + + if (--dev_priv->vblank_enabled == 0) + intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); +} + +void i965_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_disable_pipestat(dev_priv, pipe, + PIPE_START_VBLANK_INTERRUPT_STATUS); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void ilk_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum pipe pipe = to_intel_crtc(crtc)->pipe; + unsigned long irqflags; + u32 bit = DISPLAY_VER(dev_priv) >= 7 ? + DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ilk_disable_display_irq(dev_priv, bit); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void bdw_disable_vblank(struct drm_crtc *_crtc) +{ + struct intel_crtc *crtc = to_intel_crtc(_crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + unsigned long irqflags; + + if (gen11_dsi_configure_te(crtc, false)) + return; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void vlv_display_irq_reset(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + if (IS_CHERRYVIEW(dev_priv)) + intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); + else + intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); + + i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); + intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); + + i9xx_pipestat_irq_reset(dev_priv); + + GEN3_IRQ_RESET(uncore, VLV_); + dev_priv->irq_mask = ~0u; +} + +void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + u32 pipestat_mask; + u32 enable_mask; + enum pipe pipe; + + pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS; + + i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); + for_each_pipe(dev_priv, pipe) + i915_enable_pipestat(dev_priv, pipe, pipestat_mask); + + enable_mask = I915_DISPLAY_PORT_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT; + + if (IS_CHERRYVIEW(dev_priv)) + enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | + I915_LPE_PIPE_C_INTERRUPT; + + drm_WARN_ON(&dev_priv->drm, dev_priv->irq_mask != ~0u); + + dev_priv->irq_mask = ~enable_mask; + + GEN3_IRQ_INIT(uncore, VLV_, dev_priv->irq_mask, enable_mask); +} + +void gen8_display_irq_reset(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + enum pipe pipe; + + if (!HAS_DISPLAY(dev_priv)) + return; + + intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); + intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); + + for_each_pipe(dev_priv, pipe) + if (intel_display_power_is_enabled(dev_priv, + POWER_DOMAIN_PIPE(pipe))) + GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); + + GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); + GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); +} + +void gen11_display_irq_reset(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + enum pipe pipe; + u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | + BIT(TRANSCODER_C) | BIT(TRANSCODER_D); + + if (!HAS_DISPLAY(dev_priv)) + return; + + intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0); + + if (DISPLAY_VER(dev_priv) >= 12) { + enum transcoder trans; + + for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { + enum intel_display_power_domain domain; + + domain = POWER_DOMAIN_TRANSCODER(trans); + if (!intel_display_power_is_enabled(dev_priv, domain)) + continue; + + intel_uncore_write(uncore, TRANS_PSR_IMR(trans), 0xffffffff); + intel_uncore_write(uncore, TRANS_PSR_IIR(trans), 0xffffffff); + } + } else { + intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); + intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); + } + + for_each_pipe(dev_priv, pipe) + if (intel_display_power_is_enabled(dev_priv, + POWER_DOMAIN_PIPE(pipe))) + GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); + + GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); + GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); + + if (DISPLAY_VER(dev_priv) >= 14) + GEN3_IRQ_RESET(uncore, PICAINTERRUPT_); + else + GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); + + if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + GEN3_IRQ_RESET(uncore, SDE); +} + +void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, + u8 pipe_mask) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 extra_ier = GEN8_PIPE_VBLANK | + gen8_de_pipe_underrun_mask(dev_priv) | + gen8_de_pipe_flip_done_mask(dev_priv); + enum pipe pipe; + + spin_lock_irq(&dev_priv->irq_lock); + + if (!intel_irqs_enabled(dev_priv)) { + spin_unlock_irq(&dev_priv->irq_lock); + return; + } + + for_each_pipe_masked(dev_priv, pipe, pipe_mask) + GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, + dev_priv->de_irq_mask[pipe], + ~dev_priv->de_irq_mask[pipe] | extra_ier); + + spin_unlock_irq(&dev_priv->irq_lock); +} + +void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, + u8 pipe_mask) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + enum pipe pipe; + + spin_lock_irq(&dev_priv->irq_lock); + + if (!intel_irqs_enabled(dev_priv)) { + spin_unlock_irq(&dev_priv->irq_lock); + return; + } + + for_each_pipe_masked(dev_priv, pipe, pipe_mask) + GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); + + spin_unlock_irq(&dev_priv->irq_lock); + + /* make sure we're done processing display irqs */ + intel_synchronize_irq(dev_priv); +} + +/* + * SDEIER is also touched by the interrupt handler to work around missed PCH + * interrupts. Hence we can't update it after the interrupt handler is enabled - + * instead we unconditionally enable all PCH interrupt sources here, but then + * only unmask them as needed with SDEIMR. + * + * Note that we currently do this after installing the interrupt handler, + * but before we enable the master interrupt. That should be sufficient + * to avoid races with the irq handler, assuming we have MSI. Shared legacy + * interrupts could still race. + */ +void ibx_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 mask; + + if (HAS_PCH_NOP(dev_priv)) + return; + + if (HAS_PCH_IBX(dev_priv)) + mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; + else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; + else + mask = SDE_GMBUS_CPT; + + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); +} + +void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) +{ + lockdep_assert_held(&dev_priv->irq_lock); + + if (dev_priv->display_irqs_enabled) + return; + + dev_priv->display_irqs_enabled = true; + + if (intel_irqs_enabled(dev_priv)) { + vlv_display_irq_reset(dev_priv); + vlv_display_irq_postinstall(dev_priv); + } +} + +void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) +{ + lockdep_assert_held(&dev_priv->irq_lock); + + if (!dev_priv->display_irqs_enabled) + return; + + dev_priv->display_irqs_enabled = false; + + if (intel_irqs_enabled(dev_priv)) + vlv_display_irq_reset(dev_priv); +} + +void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + u32 de_pipe_masked = gen8_de_pipe_fault_mask(dev_priv) | + GEN8_PIPE_CDCLK_CRC_DONE; + u32 de_pipe_enables; + u32 de_port_masked = gen8_de_port_aux_mask(dev_priv); + u32 de_port_enables; + u32 de_misc_masked = GEN8_DE_EDP_PSR; + u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | + BIT(TRANSCODER_C) | BIT(TRANSCODER_D); + enum pipe pipe; + + if (!HAS_DISPLAY(dev_priv)) + return; + + if (DISPLAY_VER(dev_priv) <= 10) + de_misc_masked |= GEN8_DE_MISC_GSE; + + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + de_port_masked |= BXT_DE_PORT_GMBUS; + + if (DISPLAY_VER(dev_priv) >= 11) { + enum port port; + + if (intel_bios_is_dsi_present(dev_priv, &port)) + de_port_masked |= DSI0_TE | DSI1_TE; + } + + de_pipe_enables = de_pipe_masked | + GEN8_PIPE_VBLANK | + gen8_de_pipe_underrun_mask(dev_priv) | + gen8_de_pipe_flip_done_mask(dev_priv); + + de_port_enables = de_port_masked; + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; + else if (IS_BROADWELL(dev_priv)) + de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; + + if (DISPLAY_VER(dev_priv) >= 12) { + enum transcoder trans; + + for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { + enum intel_display_power_domain domain; + + domain = POWER_DOMAIN_TRANSCODER(trans); + if (!intel_display_power_is_enabled(dev_priv, domain)) + continue; + + gen3_assert_iir_is_zero(uncore, TRANS_PSR_IIR(trans)); + } + } else { + gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR); + } + + for_each_pipe(dev_priv, pipe) { + dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; + + if (intel_display_power_is_enabled(dev_priv, + POWER_DOMAIN_PIPE(pipe))) + GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, + dev_priv->de_irq_mask[pipe], + de_pipe_enables); + } + + GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables); + GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); + + if (IS_DISPLAY_VER(dev_priv, 11, 13)) { + u32 de_hpd_masked = 0; + u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | + GEN11_DE_TBT_HOTPLUG_MASK; + + GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked, + de_hpd_enables); + } +} + +void mtp_irq_postinstall(struct drm_i915_private *i915) +{ + struct intel_uncore *uncore = &i915->uncore; + u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT; + u32 de_hpd_mask = XELPDP_AUX_TC_MASK; + u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK | + XELPDP_TBT_HOTPLUG_MASK; + + GEN3_IRQ_INIT(uncore, PICAINTERRUPT_, ~de_hpd_mask, + de_hpd_enables); + + GEN3_IRQ_INIT(uncore, SDE, ~sde_mask, 0xffffffff); +} + +void icp_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 mask = SDE_GMBUS_ICP; + + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); +} + +void gen11_de_irq_postinstall(struct drm_i915_private *dev_priv) +{ + if (!HAS_DISPLAY(dev_priv)) + return; + + gen8_de_irq_postinstall(dev_priv); + + intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, + GEN11_DISPLAY_IRQ_ENABLE); +} + diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h new file mode 100644 index 000000000000..c4dfa55b192d --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_irq.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DISPLAY_IRQ_H__ +#define __INTEL_DISPLAY_IRQ_H__ + +#include <linux/types.h> + +enum pipe; +struct drm_i915_private; +struct drm_crtc; + +void valleyview_enable_display_irqs(struct drm_i915_private *i915); +void valleyview_disable_display_irqs(struct drm_i915_private *i915); + +void ilk_update_display_irq(struct drm_i915_private *i915, + u32 interrupt_mask, u32 enabled_irq_mask); +void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits); +void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits); + +void bdw_update_port_irq(struct drm_i915_private *i915, u32 interrupt_mask, u32 enabled_irq_mask); +void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); +void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); + +void ibx_display_interrupt_update(struct drm_i915_private *i915, + u32 interrupt_mask, u32 enabled_irq_mask); +void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits); +void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits); + +void gen8_irq_power_well_post_enable(struct drm_i915_private *i915, u8 pipe_mask); +void gen8_irq_power_well_pre_disable(struct drm_i915_private *i915, u8 pipe_mask); +u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *i915); + +int i8xx_enable_vblank(struct drm_crtc *crtc); +int i915gm_enable_vblank(struct drm_crtc *crtc); +int i965_enable_vblank(struct drm_crtc *crtc); +int ilk_enable_vblank(struct drm_crtc *crtc); +int bdw_enable_vblank(struct drm_crtc *crtc); +void i8xx_disable_vblank(struct drm_crtc *crtc); +void i915gm_disable_vblank(struct drm_crtc *crtc); +void i965_disable_vblank(struct drm_crtc *crtc); +void ilk_disable_vblank(struct drm_crtc *crtc); +void bdw_disable_vblank(struct drm_crtc *crtc); + +void ivb_display_irq_handler(struct drm_i915_private *i915, u32 de_iir); +void ilk_display_irq_handler(struct drm_i915_private *i915, u32 de_iir); +void gen8_de_irq_handler(struct drm_i915_private *i915, u32 master_ctl); +void gen11_display_irq_handler(struct drm_i915_private *i915); + +u32 gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl); +void gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir); + +void vlv_display_irq_reset(struct drm_i915_private *i915); +void gen8_display_irq_reset(struct drm_i915_private *i915); +void gen11_display_irq_reset(struct drm_i915_private *i915); + +void ibx_irq_postinstall(struct drm_i915_private *i915); +void vlv_display_irq_postinstall(struct drm_i915_private *i915); +void icp_irq_postinstall(struct drm_i915_private *i915); +void gen8_de_irq_postinstall(struct drm_i915_private *i915); +void mtp_irq_postinstall(struct drm_i915_private *i915); +void gen11_de_irq_postinstall(struct drm_i915_private *i915); + +u32 i915_pipestat_enable_mask(struct drm_i915_private *i915, enum pipe pipe); +void i915_enable_pipestat(struct drm_i915_private *i915, enum pipe pipe, u32 status_mask); +void i915_disable_pipestat(struct drm_i915_private *i915, enum pipe pipe, u32 status_mask); +void i915_enable_asle_pipestat(struct drm_i915_private *i915); +void i9xx_pipestat_irq_reset(struct drm_i915_private *i915); + +void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); + +void i915_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); +void i965_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); +void valleyview_pipestat_irq_handler(struct drm_i915_private *i915, u32 *pipe_stats); +void i8xx_pipestat_irq_handler(struct drm_i915_private *i915, u16 iir, u32 *pipe_stats); + +#endif /* __INTEL_DISPLAY_IRQ_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 41eabdf3e871..916009894d89 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -11,6 +11,7 @@ #include "intel_combo_phy_regs.h" #include "intel_crt.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_dkl_phy.h" diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c index e7f77a225739..09a7fa6c0c37 100644 --- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c +++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c @@ -27,8 +27,8 @@ #include "i915_drv.h" #include "i915_reg.h" -#include "i915_irq.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_fbc.h" diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 1d7ae49e073e..f95fa793fabb 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -4,9 +4,9 @@ */ #include "i915_drv.h" -#include "i915_irq.h" #include "i915_reg.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_dp_aux.h" #include "intel_gmbus.h" diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index e3ccface0c9d..26059355e3d8 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -35,11 +35,11 @@ #include <drm/drm_edid.h> #include "i915_drv.h" -#include "i915_irq.h" #include "i915_reg.h" #include "intel_connector.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_dpll.h" #include "intel_hotplug.h" diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 8ea0598a5a07..1ea664a366c1 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -9,10 +9,10 @@ #include <drm/drm_fourcc.h> #include "i915_drv.h" -#include "i915_irq.h" #include "i915_reg.h" #include "intel_atomic_plane.h" #include "intel_de.h" +#include "intel_display_irq.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 80968e49e2c3..e68a99205599 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -8,6 +8,7 @@ #include <drm/i915_drm.h> #include "display/intel_display.h" +#include "display/intel_display_irq.h" #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0ead32154f81..82fbabcdd7a5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -33,18 +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_dp_aux.h" -#include "display/intel_fdi_regs.h" -#include "display/intel_fifo_underrun.h" -#include "display/intel_gmbus.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" @@ -85,14 +78,6 @@ static inline void pmu_irq_stats(struct drm_i915_private *i915, WRITE_ONCE(i915->pmu.irq_count, i915->pmu.irq_count + 1); } -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) { @@ -125,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); @@ -179,268 +164,6 @@ static void gen2_irq_init(struct intel_uncore *uncore, intel_uncore_posting_read16(uncore, GEN2_IMR); } -/** - * 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 - */ -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 - */ -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 - */ -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. @@ -525,278 +248,6 @@ static void ivb_parity_work(struct work_struct *work) mutex_unlock(&dev_priv->drm.struct_mutex); } -#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) - intel_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) - intel_gmbus_irq_handler(dev_priv); -} - static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_i915_private *dev_priv = arg; @@ -961,217 +412,6 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) return ret; } -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) - intel_dp_aux_irq_handler(dev_priv); - - if (pch_iir & SDE_GMBUS) - intel_gmbus_irq_handler(dev_priv); - - if (pch_iir & SDE_AUDIO_HDCP_MASK) - drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n"); - - if (pch_iir & SDE_AUDIO_TRANS_MASK) - drm_dbg(&dev_priv->drm, "PCH transcoder audio interrupt\n"); - - if (pch_iir & SDE_POISON) - drm_err(&dev_priv->drm, "PCH poison interrupt\n"); - - if (pch_iir & SDE_FDI_MASK) { - for_each_pipe(dev_priv, pipe) - drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", - pipe_name(pipe), - intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); - } - - if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) - drm_dbg(&dev_priv->drm, "PCH transcoder CRC done interrupt\n"); - - if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) - drm_dbg(&dev_priv->drm, - "PCH transcoder CRC error interrupt\n"); - - if (pch_iir & SDE_TRANSA_FIFO_UNDER) - intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A); - - if (pch_iir & SDE_TRANSB_FIFO_UNDER) - intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B); -} - -static void ivb_err_int_handler(struct drm_i915_private *dev_priv) -{ - u32 err_int = intel_uncore_read(&dev_priv->uncore, GEN7_ERR_INT); - enum pipe pipe; - - if (err_int & ERR_INT_POISON) - drm_err(&dev_priv->drm, "Poison interrupt\n"); - - for_each_pipe(dev_priv, pipe) { - if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) - intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); - - if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { - if (IS_IVYBRIDGE(dev_priv)) - ivb_pipe_crc_irq_handler(dev_priv, pipe); - else - hsw_pipe_crc_irq_handler(dev_priv, pipe); - } - } - - intel_uncore_write(&dev_priv->uncore, GEN7_ERR_INT, err_int); -} - -static void cpt_serr_int_handler(struct drm_i915_private *dev_priv) -{ - u32 serr_int = intel_uncore_read(&dev_priv->uncore, SERR_INT); - enum pipe pipe; - - if (serr_int & SERR_INT_POISON) - drm_err(&dev_priv->drm, "PCH poison interrupt\n"); - - for_each_pipe(dev_priv, pipe) - if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe)) - intel_pch_fifo_underrun_irq_handler(dev_priv, pipe); - - intel_uncore_write(&dev_priv->uncore, SERR_INT, serr_int); -} - -static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) -{ - enum pipe pipe; - u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - - ibx_hpd_irq_handler(dev_priv, hotplug_trigger); - - if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { - int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> - SDE_AUDIO_POWER_SHIFT_CPT); - drm_dbg(&dev_priv->drm, "PCH audio power change on port %c\n", - port_name(port)); - } - - if (pch_iir & SDE_AUX_MASK_CPT) - intel_dp_aux_irq_handler(dev_priv); - - if (pch_iir & SDE_GMBUS_CPT) - intel_gmbus_irq_handler(dev_priv); - - if (pch_iir & SDE_AUDIO_CP_REQ_CPT) - drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n"); - - if (pch_iir & SDE_AUDIO_CP_CHG_CPT) - drm_dbg(&dev_priv->drm, "Audio CP change interrupt\n"); - - if (pch_iir & SDE_FDI_MASK_CPT) { - for_each_pipe(dev_priv, pipe) - drm_dbg(&dev_priv->drm, " pipe %c FDI IIR: 0x%08x\n", - pipe_name(pipe), - intel_uncore_read(&dev_priv->uncore, FDI_RX_IIR(pipe))); - } - - if (pch_iir & SDE_ERROR_CPT) - cpt_serr_int_handler(dev_priv); -} - -static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, - u32 de_iir) -{ - enum pipe pipe; - u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; - - if (hotplug_trigger) - ilk_hpd_irq_handler(dev_priv, hotplug_trigger); - - if (de_iir & DE_AUX_CHANNEL_A) - intel_dp_aux_irq_handler(dev_priv); - - if (de_iir & DE_GSE) - intel_opregion_asle_intr(dev_priv); - - if (de_iir & DE_POISON) - drm_err(&dev_priv->drm, "Poison interrupt\n"); - - for_each_pipe(dev_priv, pipe) { - if (de_iir & DE_PIPE_VBLANK(pipe)) - intel_handle_vblank(dev_priv, pipe); - - if (de_iir & DE_PLANE_FLIP_DONE(pipe)) - flip_done_handler(dev_priv, pipe); - - if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) - intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); - - if (de_iir & DE_PIPE_CRC_DONE(pipe)) - i9xx_pipe_crc_irq_handler(dev_priv, pipe); - } - - /* check event from PCH */ - if (de_iir & DE_PCH_EVENT) { - u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); - - if (HAS_PCH_CPT(dev_priv)) - cpt_irq_handler(dev_priv, pch_iir); - else - ibx_irq_handler(dev_priv, pch_iir); - - /* should clear PCH hotplug event before clear CPU irq */ - intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); - } - - if (DISPLAY_VER(dev_priv) == 5 && de_iir & DE_PCU_EVENT) - gen5_rps_irq_handler(&to_gt(dev_priv)->rps); -} - -static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, - u32 de_iir) -{ - enum pipe pipe; - u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; - - if (hotplug_trigger) - ilk_hpd_irq_handler(dev_priv, hotplug_trigger); - - if (de_iir & DE_ERR_INT_IVB) - ivb_err_int_handler(dev_priv); - - if (de_iir & DE_AUX_CHANNEL_A_IVB) - intel_dp_aux_irq_handler(dev_priv); - - if (de_iir & DE_GSE_IVB) - intel_opregion_asle_intr(dev_priv); - - for_each_pipe(dev_priv, pipe) { - if (de_iir & DE_PIPE_VBLANK_IVB(pipe)) - intel_handle_vblank(dev_priv, pipe); - - if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) - flip_done_handler(dev_priv, pipe); - } - - /* check event from PCH */ - if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) { - u32 pch_iir = intel_uncore_read(&dev_priv->uncore, SDEIIR); - - cpt_irq_handler(dev_priv, pch_iir); - - /* clear PCH hotplug event before clear CPU irq */ - intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); - } -} - /* * To handle irqs with the minimum potential races with fresh interrupts, we: * 1 - Disable Master Interrupt Control. @@ -1244,363 +484,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) pmu_irq_stats(i915, ret); - /* IRQs are synced during runtime_suspend, we don't require a wakeref */ - enable_rpm_wakeref_asserts(&i915->runtime_pm); - - return ret; -} - -static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) -{ - u32 mask; - - if (DISPLAY_VER(dev_priv) >= 14) - return TGL_DE_PORT_AUX_DDIA | - TGL_DE_PORT_AUX_DDIB; - else if (DISPLAY_VER(dev_priv) >= 13) - return TGL_DE_PORT_AUX_DDIA | - TGL_DE_PORT_AUX_DDIB | - TGL_DE_PORT_AUX_DDIC | - XELPD_DE_PORT_AUX_DDID | - XELPD_DE_PORT_AUX_DDIE | - TGL_DE_PORT_AUX_USBC1 | - TGL_DE_PORT_AUX_USBC2 | - TGL_DE_PORT_AUX_USBC3 | - TGL_DE_PORT_AUX_USBC4; - else if (DISPLAY_VER(dev_priv) >= 12) - return TGL_DE_PORT_AUX_DDIA | - TGL_DE_PORT_AUX_DDIB | - TGL_DE_PORT_AUX_DDIC | - TGL_DE_PORT_AUX_USBC1 | - TGL_DE_PORT_AUX_USBC2 | - TGL_DE_PORT_AUX_USBC3 | - TGL_DE_PORT_AUX_USBC4 | - TGL_DE_PORT_AUX_USBC5 | - TGL_DE_PORT_AUX_USBC6; - - - mask = GEN8_AUX_CHANNEL_A; - if (DISPLAY_VER(dev_priv) >= 9) - mask |= GEN9_AUX_CHANNEL_B | - GEN9_AUX_CHANNEL_C | - GEN9_AUX_CHANNEL_D; - - if (DISPLAY_VER(dev_priv) == 11) { - mask |= ICL_AUX_CHANNEL_F; - mask |= ICL_AUX_CHANNEL_E; - } - - return mask; -} - -static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) -{ - if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) - return RKL_DE_PIPE_IRQ_FAULT_ERRORS; - else if (DISPLAY_VER(dev_priv) >= 11) - return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; - else if (DISPLAY_VER(dev_priv) >= 9) - return GEN9_DE_PIPE_IRQ_FAULT_ERRORS; - else - return GEN8_DE_PIPE_IRQ_FAULT_ERRORS; -} - -static void -gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) -{ - bool found = false; - - if (iir & GEN8_DE_MISC_GSE) { - intel_opregion_asle_intr(dev_priv); - found = true; - } - - if (iir & GEN8_DE_EDP_PSR) { - struct intel_encoder *encoder; - u32 psr_iir; - i915_reg_t iir_reg; - - for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - if (DISPLAY_VER(dev_priv) >= 12) - iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder); - else - iir_reg = EDP_PSR_IIR; - - psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0); - - if (psr_iir) - found = true; - - intel_psr_irq_handler(intel_dp, psr_iir); - - /* prior GEN12 only have one EDP PSR */ - if (DISPLAY_VER(dev_priv) < 12) - break; - } - } - - if (!found) - drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); -} - -static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, - u32 te_trigger) -{ - enum pipe pipe = INVALID_PIPE; - enum transcoder dsi_trans; - enum port port; - u32 val, tmp; - - /* - * Incase of dual link, TE comes from DSI_1 - * this is to check if dual link is enabled - */ - val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0)); - val &= PORT_SYNC_MODE_ENABLE; - - /* - * if dual link is enabled, then read DSI_0 - * transcoder registers - */ - port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ? - PORT_A : PORT_B; - dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1; - - /* Check if DSI configured in command mode */ - val = intel_uncore_read(&dev_priv->uncore, DSI_TRANS_FUNC_CONF(dsi_trans)); - val = val & OP_MODE_MASK; - - if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) { - drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n"); - return; - } - - /* Get PIPE for handling VBLANK event */ - val = intel_uncore_read(&dev_priv->uncore, TRANS_DDI_FUNC_CTL(dsi_trans)); - switch (val & TRANS_DDI_EDP_INPUT_MASK) { - case TRANS_DDI_EDP_INPUT_A_ON: - pipe = PIPE_A; - break; - case TRANS_DDI_EDP_INPUT_B_ONOFF: - pipe = PIPE_B; - break; - case TRANS_DDI_EDP_INPUT_C_ONOFF: - pipe = PIPE_C; - break; - default: - drm_err(&dev_priv->drm, "Invalid PIPE\n"); - return; - } - - intel_handle_vblank(dev_priv, pipe); - - /* clear TE in dsi IIR */ - port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; - tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); -} - -static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915) -{ - if (DISPLAY_VER(i915) >= 9) - return GEN9_PIPE_PLANE1_FLIP_DONE; - else - return GEN8_PIPE_PRIMARY_FLIP_DONE; -} - -u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv) -{ - u32 mask = GEN8_PIPE_FIFO_UNDERRUN; - - if (DISPLAY_VER(dev_priv) >= 13) - mask |= XELPD_PIPE_SOFT_UNDERRUN | - XELPD_PIPE_HARD_UNDERRUN; - - return mask; -} - -static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_iir, u32 *pica_iir) -{ - u32 pica_ier = 0; - - *pica_iir = 0; - *pch_iir = intel_de_read(i915, SDEIIR); - if (!*pch_iir) - return; - - /** - * PICA IER must be disabled/re-enabled around clearing PICA IIR and - * SDEIIR, to avoid losing PICA IRQs and to ensure that such IRQs set - * their flags both in the PICA and SDE IIR. - */ - if (*pch_iir & SDE_PICAINTERRUPT) { - drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); - - pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); - *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); - intel_de_write(i915, PICAINTERRUPT_IIR, *pica_iir); - } - - intel_de_write(i915, SDEIIR, *pch_iir); - - if (pica_ier) - intel_de_write(i915, PICAINTERRUPT_IER, pica_ier); -} - -static irqreturn_t -gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) -{ - irqreturn_t ret = IRQ_NONE; - u32 iir; - enum pipe pipe; - - drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DISPLAY(dev_priv)); - - if (master_ctl & GEN8_DE_MISC_IRQ) { - iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); - if (iir) { - intel_uncore_write(&dev_priv->uncore, GEN8_DE_MISC_IIR, iir); - ret = IRQ_HANDLED; - gen8_de_misc_irq_handler(dev_priv, iir); - } else { - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied (DE MISC)!\n"); - } - } - - if (DISPLAY_VER(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { - iir = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IIR); - if (iir) { - intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IIR, iir); - ret = IRQ_HANDLED; - gen11_hpd_irq_handler(dev_priv, iir); - } else { - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied, (DE HPD)!\n"); - } - } - - if (master_ctl & GEN8_DE_PORT_IRQ) { - iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PORT_IIR); - if (iir) { - bool found = false; - - intel_uncore_write(&dev_priv->uncore, GEN8_DE_PORT_IIR, iir); - ret = IRQ_HANDLED; - - if (iir & gen8_de_port_aux_mask(dev_priv)) { - intel_dp_aux_irq_handler(dev_priv); - found = true; - } - - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { - u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; - - if (hotplug_trigger) { - bxt_hpd_irq_handler(dev_priv, hotplug_trigger); - found = true; - } - } else if (IS_BROADWELL(dev_priv)) { - u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK; - - if (hotplug_trigger) { - ilk_hpd_irq_handler(dev_priv, hotplug_trigger); - found = true; - } - } - - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && - (iir & BXT_DE_PORT_GMBUS)) { - intel_gmbus_irq_handler(dev_priv); - found = true; - } - - if (DISPLAY_VER(dev_priv) >= 11) { - u32 te_trigger = iir & (DSI0_TE | DSI1_TE); - - if (te_trigger) { - gen11_dsi_te_interrupt_handler(dev_priv, te_trigger); - found = true; - } - } - - if (!found) - drm_err_ratelimited(&dev_priv->drm, - "Unexpected DE Port interrupt\n"); - } - else - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied (DE PORT)!\n"); - } - - for_each_pipe(dev_priv, pipe) { - u32 fault_errors; - - if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) - continue; - - iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe)); - if (!iir) { - drm_err_ratelimited(&dev_priv->drm, - "The master control interrupt lied (DE PIPE)!\n"); - continue; - } - - ret = IRQ_HANDLED; - intel_uncore_write(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe), iir); - - if (iir & GEN8_PIPE_VBLANK) - intel_handle_vblank(dev_priv, pipe); - - if (iir & gen8_de_pipe_flip_done_mask(dev_priv)) - flip_done_handler(dev_priv, pipe); - - if (iir & GEN8_PIPE_CDCLK_CRC_DONE) - hsw_pipe_crc_irq_handler(dev_priv, pipe); - - if (iir & gen8_de_pipe_underrun_mask(dev_priv)) - intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); - - fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv); - if (fault_errors) - drm_err_ratelimited(&dev_priv->drm, - "Fault errors on pipe %c: 0x%08x\n", - pipe_name(pipe), - fault_errors); - } - - if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) && - master_ctl & GEN8_DE_PCH_IRQ) { - u32 pica_iir; - - /* - * FIXME(BDW): Assume for now that the new interrupt handling - * scheme also closed the SDE interrupt handling race we've seen - * on older pch-split platforms. But this needs testing. - */ - gen8_read_and_ack_pch_irqs(dev_priv, &iir, &pica_iir); - if (iir) { - ret = IRQ_HANDLED; - - if (pica_iir) - xelpdp_pica_irq_handler(dev_priv, pica_iir); - - if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - icp_irq_handler(dev_priv, iir); - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) - spt_irq_handler(dev_priv, iir); - else - cpt_irq_handler(dev_priv, iir); - } else { - /* - * Like on previous PCH there seems to be something - * fishy going on with forwarding PCH interrupts. - */ - drm_dbg(&dev_priv->drm, - "The master control interrupt lied (SDE)!\n"); - } - } + /* IRQs are synced during runtime_suspend, we don't require a wakeref */ + enable_rpm_wakeref_asserts(&i915->runtime_pm); return ret; } @@ -1655,29 +540,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static u32 -gen11_gu_misc_irq_ack(struct drm_i915_private *i915, const u32 master_ctl) -{ - void __iomem * const regs = i915->uncore.regs; - u32 iir; - - if (!(master_ctl & GEN11_GU_MISC_IRQ)) - return 0; - - iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); - if (likely(iir)) - raw_reg_write(regs, GEN11_GU_MISC_IIR, iir); - - return iir; -} - -static void -gen11_gu_misc_irq_handler(struct drm_i915_private *i915, const u32 iir) -{ - if (iir & GEN11_GU_MISC_GSE) - intel_opregion_asle_intr(i915); -} - static inline u32 gen11_master_intr_disable(void __iomem * const regs) { raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0); @@ -1696,25 +558,6 @@ static inline void gen11_master_intr_enable(void __iomem * const regs) raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ); } -static void -gen11_display_irq_handler(struct drm_i915_private *i915) -{ - void __iomem * const regs = i915->uncore.regs; - const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL); - - disable_rpm_wakeref_asserts(&i915->runtime_pm); - /* - * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ - * for the display related bits. - */ - raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, 0x0); - gen8_de_irq_handler(i915, disp_ctl); - raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, - GEN11_DISPLAY_IRQ_ENABLE); - - enable_rpm_wakeref_asserts(&i915->runtime_pm); -} - static irqreturn_t gen11_irq_handler(int irq, void *arg) { struct drm_i915_private *i915 = arg; @@ -1816,184 +659,6 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -/* Called from drm generic code, passed 'crtc' which - * we use as a pipe index - */ -int i8xx_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - return 0; -} - -int i915gm_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - - /* - * Vblank interrupts fail to wake the device up from C2+. - * Disabling render clock gating during C-states avoids - * the problem. There is a small power cost so we do this - * only when vblank interrupts are actually enabled. - */ - if (dev_priv->vblank_enabled++ == 0) - intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); - - return i8xx_enable_vblank(crtc); -} - -int i965_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_enable_pipestat(dev_priv, pipe, - PIPE_START_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - return 0; -} - -int ilk_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - u32 bit = DISPLAY_VER(dev_priv) >= 7 ? - DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - ilk_enable_display_irq(dev_priv, bit); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - /* Even though there is no DMC, frame counter can get stuck when - * PSR is active as no frames are generated. - */ - if (HAS_PSR(dev_priv)) - drm_crtc_vblank_restore(crtc); - - return 0; -} - -static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, - bool enable) -{ - struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); - enum port port; - - if (!(intel_crtc->mode_flags & - (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) - return false; - - /* for dual link cases we consider TE from slave */ - if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1) - port = PORT_B; - else - port = PORT_A; - - intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT, - enable ? 0 : DSI_TE_EVENT); - - intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); - - return true; -} - -int bdw_enable_vblank(struct drm_crtc *_crtc) -{ - struct intel_crtc *crtc = to_intel_crtc(_crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - unsigned long irqflags; - - if (gen11_dsi_configure_te(crtc, true)) - return 0; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - /* Even if there is no DMC, frame counter can get stuck when - * PSR is active as no frames are generated, so check only for PSR. - */ - if (HAS_PSR(dev_priv)) - drm_crtc_vblank_restore(&crtc->base); - - return 0; -} - -/* Called from drm generic code, passed 'crtc' which - * we use as a pipe index - */ -void i8xx_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - -void i915gm_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - - i8xx_disable_vblank(crtc); - - if (--dev_priv->vblank_enabled == 0) - intel_uncore_write(&dev_priv->uncore, SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE)); -} - -void i965_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_disable_pipestat(dev_priv, pipe, - PIPE_START_VBLANK_INTERRUPT_STATUS); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - -void ilk_disable_vblank(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - enum pipe pipe = to_intel_crtc(crtc)->pipe; - unsigned long irqflags; - u32 bit = DISPLAY_VER(dev_priv) >= 7 ? - DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe); - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - ilk_disable_display_irq(dev_priv, bit); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - -void bdw_disable_vblank(struct drm_crtc *_crtc) -{ - struct intel_crtc *crtc = to_intel_crtc(_crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - unsigned long irqflags; - - if (gen11_dsi_configure_te(crtc, false)) - return; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -} - static void ibx_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2007,55 +672,6 @@ static void ibx_irq_reset(struct drm_i915_private *dev_priv) intel_uncore_write(&dev_priv->uncore, SERR_INT, 0xffffffff); } -static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - - if (IS_CHERRYVIEW(dev_priv)) - intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); - else - intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); - - i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); - intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); - - i9xx_pipestat_irq_reset(dev_priv); - - GEN3_IRQ_RESET(uncore, VLV_); - dev_priv->irq_mask = ~0u; -} - -static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - - u32 pipestat_mask; - u32 enable_mask; - enum pipe pipe; - - pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS; - - i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); - for_each_pipe(dev_priv, pipe) - i915_enable_pipestat(dev_priv, pipe, pipestat_mask); - - enable_mask = I915_DISPLAY_PORT_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_LPE_PIPE_A_INTERRUPT | - I915_LPE_PIPE_B_INTERRUPT; - - if (IS_CHERRYVIEW(dev_priv)) - enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | - I915_LPE_PIPE_C_INTERRUPT; - - drm_WARN_ON(&dev_priv->drm, dev_priv->irq_mask != ~0u); - - dev_priv->irq_mask = ~enable_mask; - - GEN3_IRQ_INIT(uncore, VLV_, dev_priv->irq_mask, enable_mask); -} - /* drm_dma.h hooks */ static void ilk_irq_reset(struct drm_i915_private *dev_priv) @@ -2091,26 +707,6 @@ static void valleyview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } -static void gen8_display_irq_reset(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - enum pipe pipe; - - if (!HAS_DISPLAY(dev_priv)) - return; - - intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); - intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); - - for_each_pipe(dev_priv, pipe) - if (intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_PIPE(pipe))) - GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); - - GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); - GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); -} - static void gen8_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2126,53 +722,6 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv) } -static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - enum pipe pipe; - u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | - BIT(TRANSCODER_C) | BIT(TRANSCODER_D); - - if (!HAS_DISPLAY(dev_priv)) - return; - - intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0); - - if (DISPLAY_VER(dev_priv) >= 12) { - enum transcoder trans; - - for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { - enum intel_display_power_domain domain; - - domain = POWER_DOMAIN_TRANSCODER(trans); - if (!intel_display_power_is_enabled(dev_priv, domain)) - continue; - - intel_uncore_write(uncore, TRANS_PSR_IMR(trans), 0xffffffff); - intel_uncore_write(uncore, TRANS_PSR_IIR(trans), 0xffffffff); - } - } else { - intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); - intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); - } - - for_each_pipe(dev_priv, pipe) - if (intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_PIPE(pipe))) - GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); - - GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); - GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); - - if (DISPLAY_VER(dev_priv) >= 14) - GEN3_IRQ_RESET(uncore, PICAINTERRUPT_); - else - GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); - - if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - GEN3_IRQ_RESET(uncore, SDE); -} - static void gen11_irq_reset(struct drm_i915_private *dev_priv) { struct intel_gt *gt = to_gt(dev_priv); @@ -2204,52 +753,6 @@ static void dg1_irq_reset(struct drm_i915_private *dev_priv) GEN3_IRQ_RESET(uncore, GEN8_PCU_); } -void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, - u8 pipe_mask) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 extra_ier = GEN8_PIPE_VBLANK | - gen8_de_pipe_underrun_mask(dev_priv) | - gen8_de_pipe_flip_done_mask(dev_priv); - enum pipe pipe; - - spin_lock_irq(&dev_priv->irq_lock); - - if (!intel_irqs_enabled(dev_priv)) { - spin_unlock_irq(&dev_priv->irq_lock); - return; - } - - for_each_pipe_masked(dev_priv, pipe, pipe_mask) - GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, - dev_priv->de_irq_mask[pipe], - ~dev_priv->de_irq_mask[pipe] | extra_ier); - - spin_unlock_irq(&dev_priv->irq_lock); -} - -void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, - u8 pipe_mask) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - enum pipe pipe; - - spin_lock_irq(&dev_priv->irq_lock); - - if (!intel_irqs_enabled(dev_priv)) { - spin_unlock_irq(&dev_priv->irq_lock); - return; - } - - for_each_pipe_masked(dev_priv, pipe, pipe_mask) - GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe); - - spin_unlock_irq(&dev_priv->irq_lock); - - /* make sure we're done processing display irqs */ - intel_synchronize_irq(dev_priv); -} - static void cherryview_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2267,35 +770,6 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } -/* - * SDEIER is also touched by the interrupt handler to work around missed PCH - * interrupts. Hence we can't update it after the interrupt handler is enabled - - * instead we unconditionally enable all PCH interrupt sources here, but then - * only unmask them as needed with SDEIMR. - * - * Note that we currently do this after installing the interrupt handler, - * but before we enable the master interrupt. That should be sufficient - * to avoid races with the irq handler, assuming we have MSI. Shared legacy - * interrupts could still race. - */ -static void ibx_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 mask; - - if (HAS_PCH_NOP(dev_priv)) - return; - - if (HAS_PCH_IBX(dev_priv)) - mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; - else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv)) - mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; - else - mask = SDE_GMBUS_CPT; - - GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); -} - static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -2339,35 +813,6 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv) display_mask | extra_mask); } -void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) -{ - lockdep_assert_held(&dev_priv->irq_lock); - - if (dev_priv->display_irqs_enabled) - return; - - dev_priv->display_irqs_enabled = true; - - if (intel_irqs_enabled(dev_priv)) { - vlv_display_irq_reset(dev_priv); - vlv_display_irq_postinstall(dev_priv); - } -} - -void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) -{ - lockdep_assert_held(&dev_priv->irq_lock); - - if (!dev_priv->display_irqs_enabled) - return; - - dev_priv->display_irqs_enabled = false; - - if (intel_irqs_enabled(dev_priv)) - vlv_display_irq_reset(dev_priv); -} - - static void valleyview_irq_postinstall(struct drm_i915_private *dev_priv) { gen5_gt_irq_postinstall(to_gt(dev_priv)); @@ -2381,108 +826,6 @@ static void valleyview_irq_postinstall(struct drm_i915_private *dev_priv) intel_uncore_posting_read(&dev_priv->uncore, VLV_MASTER_IER); } -static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - - u32 de_pipe_masked = gen8_de_pipe_fault_mask(dev_priv) | - GEN8_PIPE_CDCLK_CRC_DONE; - u32 de_pipe_enables; - u32 de_port_masked = gen8_de_port_aux_mask(dev_priv); - u32 de_port_enables; - u32 de_misc_masked = GEN8_DE_EDP_PSR; - u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | - BIT(TRANSCODER_C) | BIT(TRANSCODER_D); - enum pipe pipe; - - if (!HAS_DISPLAY(dev_priv)) - return; - - if (DISPLAY_VER(dev_priv) <= 10) - de_misc_masked |= GEN8_DE_MISC_GSE; - - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - de_port_masked |= BXT_DE_PORT_GMBUS; - - if (DISPLAY_VER(dev_priv) >= 11) { - enum port port; - - if (intel_bios_is_dsi_present(dev_priv, &port)) - de_port_masked |= DSI0_TE | DSI1_TE; - } - - de_pipe_enables = de_pipe_masked | - GEN8_PIPE_VBLANK | - gen8_de_pipe_underrun_mask(dev_priv) | - gen8_de_pipe_flip_done_mask(dev_priv); - - de_port_enables = de_port_masked; - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; - else if (IS_BROADWELL(dev_priv)) - de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; - - if (DISPLAY_VER(dev_priv) >= 12) { - enum transcoder trans; - - for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) { - enum intel_display_power_domain domain; - - domain = POWER_DOMAIN_TRANSCODER(trans); - if (!intel_display_power_is_enabled(dev_priv, domain)) - continue; - - gen3_assert_iir_is_zero(uncore, TRANS_PSR_IIR(trans)); - } - } else { - gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR); - } - - for_each_pipe(dev_priv, pipe) { - dev_priv->de_irq_mask[pipe] = ~de_pipe_masked; - - if (intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_PIPE(pipe))) - GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe, - dev_priv->de_irq_mask[pipe], - de_pipe_enables); - } - - GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables); - GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); - - if (IS_DISPLAY_VER(dev_priv, 11, 13)) { - u32 de_hpd_masked = 0; - u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | - GEN11_DE_TBT_HOTPLUG_MASK; - - GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked, - de_hpd_enables); - } -} - -static void mtp_irq_postinstall(struct drm_i915_private *i915) -{ - struct intel_uncore *uncore = &i915->uncore; - u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT; - u32 de_hpd_mask = XELPDP_AUX_TC_MASK; - u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK | - XELPDP_TBT_HOTPLUG_MASK; - - GEN3_IRQ_INIT(uncore, PICAINTERRUPT_, ~de_hpd_mask, - de_hpd_enables); - - GEN3_IRQ_INIT(uncore, SDE, ~sde_mask, 0xffffffff); -} - -static void icp_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 mask = SDE_GMBUS_ICP; - - GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); -} - static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) { if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) @@ -2496,17 +839,6 @@ static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) gen8_master_intr_enable(dev_priv->uncore.regs); } -static void gen11_de_irq_postinstall(struct drm_i915_private *dev_priv) -{ - if (!HAS_DISPLAY(dev_priv)) - return; - - gen8_de_irq_postinstall(dev_priv); - - intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, - GEN11_DISPLAY_IRQ_ENABLE); -} - static void gen11_irq_postinstall(struct drm_i915_private *dev_priv) { struct intel_gt *gt = to_gt(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h index 913c854f873d..e665a1b007dc 100644 --- a/drivers/gpu/drm/i915/i915_irq.h +++ b/drivers/gpu/drm/i915/i915_irq.h @@ -25,34 +25,6 @@ void intel_irq_fini(struct drm_i915_private *dev_priv); int intel_irq_install(struct drm_i915_private *dev_priv); void intel_irq_uninstall(struct drm_i915_private *dev_priv); -u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv, - enum pipe pipe); -void -i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, - u32 status_mask); - -void -i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, - u32 status_mask); - -void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv); -void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv); - -void ilk_update_display_irq(struct drm_i915_private *i915, - u32 interrupt_mask, u32 enabled_irq_mask); -void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits); -void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits); - -void bdw_update_port_irq(struct drm_i915_private *i915, - u32 interrupt_mask, u32 enabled_irq_mask); -void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); -void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits); - -void ibx_display_interrupt_update(struct drm_i915_private *i915, - u32 interrupt_mask, u32 enabled_irq_mask); -void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits); -void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits); - void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, u32 mask); void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, u32 mask); void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv); @@ -68,23 +40,7 @@ bool intel_irqs_enabled(struct drm_i915_private *dev_priv); void intel_synchronize_irq(struct drm_i915_private *i915); void intel_synchronize_hardirq(struct drm_i915_private *i915); -void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, - u8 pipe_mask); -void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, - u8 pipe_mask); -u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv); - - -int i8xx_enable_vblank(struct drm_crtc *crtc); -int i915gm_enable_vblank(struct drm_crtc *crtc); -int i965_enable_vblank(struct drm_crtc *crtc); -int ilk_enable_vblank(struct drm_crtc *crtc); -int bdw_enable_vblank(struct drm_crtc *crtc); -void i8xx_disable_vblank(struct drm_crtc *crtc); -void i915gm_disable_vblank(struct drm_crtc *crtc); -void i965_disable_vblank(struct drm_crtc *crtc); -void ilk_disable_vblank(struct drm_crtc *crtc); -void bdw_disable_vblank(struct drm_crtc *crtc); +void gen3_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg); void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr, i915_reg_t iir, i915_reg_t ier); -- 2.39.2 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-04 16:57 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling Jani Nikula @ 2023-05-04 18:42 ` kernel test robot 2023-05-04 20:15 ` kernel test robot 1 sibling, 0 replies; 15+ messages in thread From: kernel test robot @ 2023-05-04 18:42 UTC (permalink / raw) To: Jani Nikula, intel-gfx; +Cc: jani.nikula, rodrigo.vivi, oe-kbuild-all Hi Jani, kernel test robot noticed the following build errors: [auto build test ERROR on drm-tip/drm-tip] url: https://github.com/intel-lab-lkp/linux/commits/Jani-Nikula/drm-i915-irq-relocate-gmbus-and-dp-aux-irq-handlers/20230505-005945 base: git://anongit.freedesktop.org/drm/drm-tip drm-tip patch link: https://lore.kernel.org/r/d175e7571d188e791a3b691919d22b6a55ba8b16.1683219363.git.jani.nikula%40intel.com patch subject: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling config: i386-randconfig-a004-20230501 (https://download.01.org/0day-ci/archive/20230505/202305050224.cPO0Oxii-lkp@intel.com/config) compiler: gcc-11 (Debian 11.3.0-12) 11.3.0 reproduce (this is a W=1 build): # https://github.com/intel-lab-lkp/linux/commit/8ace6b1f9c8d5dce9faa2181a85d61b33d550b8e git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Jani-Nikula/drm-i915-irq-relocate-gmbus-and-dp-aux-irq-handlers/20230505-005945 git checkout 8ace6b1f9c8d5dce9faa2181a85d61b33d550b8e # save the config file mkdir build_dir && cp config build_dir/.config make W=1 O=build_dir ARCH=i386 olddefconfig make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/gpu/drm/i915/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202305050224.cPO0Oxii-lkp@intel.com/ All errors (new ones prefixed by >>): >> drivers/gpu/drm/i915/display/intel_display_irq.c:411:41: error: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Werror=array-parameter=] 411 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:72:73: note: previously declared as 'u32 *' {aka 'unsigned int *'} 72 | void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:477:45: error: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Werror=array-parameter=] 477 | u16 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:77:77: note: previously declared as 'u32 *' {aka 'unsigned int *'} 77 | void i8xx_pipestat_irq_handler(struct drm_i915_private *i915, u16 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:494:45: error: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Werror=array-parameter=] 494 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:74:77: note: previously declared as 'u32 *' {aka 'unsigned int *'} 74 | void i915_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:518:45: error: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Werror=array-parameter=] 518 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:75:77: note: previously declared as 'u32 *' {aka 'unsigned int *'} 75 | void i965_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:545:42: error: argument 2 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Werror=array-parameter=] 545 | u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:76:74: note: previously declared as 'u32 *' {aka 'unsigned int *'} 76 | void valleyview_pipestat_irq_handler(struct drm_i915_private *i915, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ cc1: all warnings being treated as errors vim +411 drivers/gpu/drm/i915/display/intel_display_irq.c 409 410 void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv, > 411 u32 iir, u32 pipe_stats[I915_MAX_PIPES]) 412 { 413 enum pipe pipe; 414 415 spin_lock(&dev_priv->irq_lock); 416 417 if (!dev_priv->display_irqs_enabled) { 418 spin_unlock(&dev_priv->irq_lock); 419 return; 420 } 421 422 for_each_pipe(dev_priv, pipe) { 423 i915_reg_t reg; 424 u32 status_mask, enable_mask, iir_bit = 0; 425 426 /* 427 * PIPESTAT bits get signalled even when the interrupt is 428 * disabled with the mask bits, and some of the status bits do 429 * not generate interrupts at all (like the underrun bit). Hence 430 * we need to be careful that we only handle what we want to 431 * handle. 432 */ 433 434 /* fifo underruns are filterered in the underrun handler. */ 435 status_mask = PIPE_FIFO_UNDERRUN_STATUS; 436 437 switch (pipe) { 438 default: 439 case PIPE_A: 440 iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; 441 break; 442 case PIPE_B: 443 iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; 444 break; 445 case PIPE_C: 446 iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; 447 break; 448 } 449 if (iir & iir_bit) 450 status_mask |= dev_priv->pipestat_irq_mask[pipe]; 451 452 if (!status_mask) 453 continue; 454 455 reg = PIPESTAT(pipe); 456 pipe_stats[pipe] = intel_uncore_read(&dev_priv->uncore, reg) & status_mask; 457 enable_mask = i915_pipestat_enable_mask(dev_priv, pipe); 458 459 /* 460 * Clear the PIPE*STAT regs before the IIR 461 * 462 * Toggle the enable bits to make sure we get an 463 * edge in the ISR pipe event bit if we don't clear 464 * all the enabled status bits. Otherwise the edge 465 * triggered IIR on i965/g4x wouldn't notice that 466 * an interrupt is still pending. 467 */ 468 if (pipe_stats[pipe]) { 469 intel_uncore_write(&dev_priv->uncore, reg, pipe_stats[pipe]); 470 intel_uncore_write(&dev_priv->uncore, reg, enable_mask); 471 } 472 } 473 spin_unlock(&dev_priv->irq_lock); 474 } 475 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling 2023-05-04 16:57 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling Jani Nikula 2023-05-04 18:42 ` kernel test robot @ 2023-05-04 20:15 ` kernel test robot 1 sibling, 0 replies; 15+ messages in thread From: kernel test robot @ 2023-05-04 20:15 UTC (permalink / raw) To: Jani Nikula, intel-gfx; +Cc: jani.nikula, rodrigo.vivi, oe-kbuild-all Hi Jani, kernel test robot noticed the following build warnings: [auto build test WARNING on drm-tip/drm-tip] url: https://github.com/intel-lab-lkp/linux/commits/Jani-Nikula/drm-i915-irq-relocate-gmbus-and-dp-aux-irq-handlers/20230505-005945 base: git://anongit.freedesktop.org/drm/drm-tip drm-tip patch link: https://lore.kernel.org/r/d175e7571d188e791a3b691919d22b6a55ba8b16.1683219363.git.jani.nikula%40intel.com patch subject: [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling config: x86_64-randconfig-a002-20230501 (https://download.01.org/0day-ci/archive/20230505/202305050427.FtwE2pE7-lkp@intel.com/config) compiler: gcc-11 (Debian 11.3.0-12) 11.3.0 reproduce (this is a W=1 build): # https://github.com/intel-lab-lkp/linux/commit/8ace6b1f9c8d5dce9faa2181a85d61b33d550b8e git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Jani-Nikula/drm-i915-irq-relocate-gmbus-and-dp-aux-irq-handlers/20230505-005945 git checkout 8ace6b1f9c8d5dce9faa2181a85d61b33d550b8e # save the config file mkdir build_dir && cp config build_dir/.config make W=1 O=build_dir ARCH=x86_64 olddefconfig make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/gpu/drm/i915/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202305050427.FtwE2pE7-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/gpu/drm/i915/display/intel_display_irq.c:411:41: warning: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Warray-parameter=] 411 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:72:73: note: previously declared as 'u32 *' {aka 'unsigned int *'} 72 | void i9xx_pipestat_irq_ack(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:477:45: warning: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Warray-parameter=] 477 | u16 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:77:77: note: previously declared as 'u32 *' {aka 'unsigned int *'} 77 | void i8xx_pipestat_irq_handler(struct drm_i915_private *i915, u16 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:494:45: warning: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Warray-parameter=] 494 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:74:77: note: previously declared as 'u32 *' {aka 'unsigned int *'} 74 | void i915_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:518:45: warning: argument 3 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Warray-parameter=] 518 | u32 iir, u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:75:77: note: previously declared as 'u32 *' {aka 'unsigned int *'} 75 | void i965_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ drivers/gpu/drm/i915/display/intel_display_irq.c:545:42: warning: argument 2 of type 'u32[4]' {aka 'unsigned int[4]'} with mismatched bound [-Warray-parameter=] 545 | u32 pipe_stats[I915_MAX_PIPES]) | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/gpu/drm/i915/display/intel_display_irq.c:10: drivers/gpu/drm/i915/display/intel_display_irq.h:76:74: note: previously declared as 'u32 *' {aka 'unsigned int *'} 76 | void valleyview_pipestat_irq_handler(struct drm_i915_private *i915, u32 *pipe_stats); | ~~~~~^~~~~~~~~~ vim +411 drivers/gpu/drm/i915/display/intel_display_irq.c 409 410 void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv, > 411 u32 iir, u32 pipe_stats[I915_MAX_PIPES]) 412 { 413 enum pipe pipe; 414 415 spin_lock(&dev_priv->irq_lock); 416 417 if (!dev_priv->display_irqs_enabled) { 418 spin_unlock(&dev_priv->irq_lock); 419 return; 420 } 421 422 for_each_pipe(dev_priv, pipe) { 423 i915_reg_t reg; 424 u32 status_mask, enable_mask, iir_bit = 0; 425 426 /* 427 * PIPESTAT bits get signalled even when the interrupt is 428 * disabled with the mask bits, and some of the status bits do 429 * not generate interrupts at all (like the underrun bit). Hence 430 * we need to be careful that we only handle what we want to 431 * handle. 432 */ 433 434 /* fifo underruns are filterered in the underrun handler. */ 435 status_mask = PIPE_FIFO_UNDERRUN_STATUS; 436 437 switch (pipe) { 438 default: 439 case PIPE_A: 440 iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; 441 break; 442 case PIPE_B: 443 iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; 444 break; 445 case PIPE_C: 446 iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; 447 break; 448 } 449 if (iir & iir_bit) 450 status_mask |= dev_priv->pipestat_irq_mask[pipe]; 451 452 if (!status_mask) 453 continue; 454 455 reg = PIPESTAT(pipe); 456 pipe_stats[pipe] = intel_uncore_read(&dev_priv->uncore, reg) & status_mask; 457 enable_mask = i915_pipestat_enable_mask(dev_priv, pipe); 458 459 /* 460 * Clear the PIPE*STAT regs before the IIR 461 * 462 * Toggle the enable bits to make sure we get an 463 * edge in the ISR pipe event bit if we don't clear 464 * all the enabled status bits. Otherwise the edge 465 * triggered IIR on i965/g4x wouldn't notice that 466 * an interrupt is still pending. 467 */ 468 if (pipe_stats[pipe]) { 469 intel_uncore_write(&dev_priv->uncore, reg, pipe_stats[pipe]); 470 intel_uncore_write(&dev_priv->uncore, reg, enable_mask); 471 } 472 } 473 spin_unlock(&dev_priv->irq_lock); 474 } 475 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2023-05-15 10:06 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-05-12 10:23 [Intel-gfx] [PATCH 1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Jani Nikula 2023-05-12 10:23 ` [Intel-gfx] [PATCH 2/3] drm/i915/irq: split out hotplug irq handling Jani Nikula 2023-05-12 10:23 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display " Jani Nikula 2023-05-12 13:13 ` kernel test robot 2023-05-12 13:44 ` kernel test robot 2023-05-12 13:48 ` Gustavo Sousa 2023-05-12 18:21 ` Jani Nikula 2023-05-15 10:05 ` Jani Nikula 2023-05-12 11:52 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/3] drm/i915/irq: convert gen8_de_irq_handler() to void Patchwork 2023-05-12 11:52 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork 2023-05-12 12:10 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork 2023-05-12 12:50 ` [Intel-gfx] [PATCH 1/3] " Gustavo Sousa -- strict thread matches above, loose matches on Subject: below -- 2023-05-04 16:57 [Intel-gfx] [PATCH 0/3] drm/i915: hotplug and display irq refactoring Jani Nikula 2023-05-04 16:57 ` [Intel-gfx] [PATCH 3/3] drm/i915/irq: split out display irq handling Jani Nikula 2023-05-04 18:42 ` kernel test robot 2023-05-04 20:15 ` kernel test robot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox