On Thu, May 04, 2023 at 07:57:30PM +0300, Jani Nikula wrote: > 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]. > > Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> \o/ - special celebration after having had to deal with hpd irq changes on the recent rebase of Xe... Reviewed-by: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx> > --- > 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 f2ac803e35b4..b8520aea6068 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 13519f78cf9f..ab57bc0873f1 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 4361c1ac65c3..9019071abcbf 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 02b6cbb832e9..0ead32154f81 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; > @@ -2943,696 +2267,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 | > @@ -4267,40 +2934,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; > @@ -4360,43 +2993,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 > @@ -4419,10 +3015,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 > @@ -4435,27 +3027,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 >