summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c144
1 files changed, 84 insertions, 60 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 240d5e198904..d24bdea65a3d 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -37,10 +37,12 @@
#include "display/intel_de.h"
#include "display/intel_display_trace.h"
#include "display/intel_display_types.h"
+#include "display/intel_fdi_regs.h"
#include "display/intel_fifo_underrun.h"
#include "display/intel_hotplug.h"
#include "display/intel_lpe_audio.h"
#include "display/intel_psr.h"
+#include "display/intel_psr_regs.h"
#include "gt/intel_breadcrumbs.h"
#include "gt/intel_gt.h"
@@ -52,7 +54,6 @@
#include "i915_driver.h"
#include "i915_drv.h"
#include "i915_irq.h"
-#include "intel_pm.h"
/**
* DOC: interrupt handling
@@ -81,8 +82,7 @@ static inline void pmu_irq_stats(struct drm_i915_private *i915,
}
typedef bool (*long_pulse_detect_func)(enum hpd_pin pin, u32 val);
-typedef u32 (*hotplug_enables_func)(struct drm_i915_private *i915,
- enum hpd_pin pin);
+typedef u32 (*hotplug_enables_func)(struct intel_encoder *encoder);
static const u32 hpd_ilk[HPD_NUM_PINS] = {
[HPD_PORT_A] = DE_DP_A_HOTPLUG,
@@ -199,6 +199,8 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
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)
@@ -884,7 +886,7 @@ static u32 intel_hpd_hotplug_enables(struct drm_i915_private *i915,
u32 hotplug = 0;
for_each_intel_encoder(&i915->drm, encoder)
- hotplug |= hotplug_enables(i915, encoder->hpd_pin);
+ hotplug |= hotplug_enables(encoder);
return hotplug;
}
@@ -2835,10 +2837,11 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv)
spin_unlock_irq(&dev_priv->irq_lock);
}
-static u32 ibx_hotplug_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 ibx_hotplug_enables(struct intel_encoder *encoder)
{
- switch (pin) {
+ 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
@@ -2890,31 +2893,29 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
ibx_hpd_detection_setup(dev_priv);
}
-static u32 icp_ddi_hotplug_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 icp_ddi_hotplug_enables(struct intel_encoder *encoder)
{
- switch (pin) {
+ switch (encoder->hpd_pin) {
case HPD_PORT_A:
case HPD_PORT_B:
case HPD_PORT_C:
case HPD_PORT_D:
- return SHOTPLUG_CTL_DDI_HPD_ENABLE(pin);
+ return SHOTPLUG_CTL_DDI_HPD_ENABLE(encoder->hpd_pin);
default:
return 0;
}
}
-static u32 icp_tc_hotplug_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 icp_tc_hotplug_enables(struct intel_encoder *encoder)
{
- switch (pin) {
+ switch (encoder->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(pin);
+ return ICP_TC_HPD_ENABLE(encoder->hpd_pin);
default:
return 0;
}
@@ -2958,17 +2959,16 @@ static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv)
icp_tc_hpd_detection_setup(dev_priv);
}
-static u32 gen11_hotplug_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 gen11_hotplug_enables(struct intel_encoder *encoder)
{
- switch (pin) {
+ switch (encoder->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(pin);
+ return GEN11_HOTPLUG_CTL_ENABLE(encoder->hpd_pin);
default:
return 0;
}
@@ -3031,10 +3031,9 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
icp_hpd_irq_setup(dev_priv);
}
-static u32 spt_hotplug_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 spt_hotplug_enables(struct intel_encoder *encoder)
{
- switch (pin) {
+ switch (encoder->hpd_pin) {
case HPD_PORT_A:
return PORTA_HOTPLUG_ENABLE;
case HPD_PORT_B:
@@ -3048,10 +3047,9 @@ static u32 spt_hotplug_enables(struct drm_i915_private *i915,
}
}
-static u32 spt_hotplug2_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 spt_hotplug2_enables(struct intel_encoder *encoder)
{
- switch (pin) {
+ switch (encoder->hpd_pin) {
case HPD_PORT_E:
return PORTE_HOTPLUG_ENABLE;
default:
@@ -3094,10 +3092,9 @@ static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
spt_hpd_detection_setup(dev_priv);
}
-static u32 ilk_hotplug_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 ilk_hotplug_enables(struct intel_encoder *encoder)
{
- switch (pin) {
+ switch (encoder->hpd_pin) {
case HPD_PORT_A:
return DIGITAL_PORTA_HOTPLUG_ENABLE |
DIGITAL_PORTA_PULSE_DURATION_2ms;
@@ -3135,25 +3132,24 @@ static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
ibx_hpd_irq_setup(dev_priv);
}
-static u32 bxt_hotplug_enables(struct drm_i915_private *i915,
- enum hpd_pin pin)
+static u32 bxt_hotplug_enables(struct intel_encoder *encoder)
{
u32 hotplug;
- switch (pin) {
+ switch (encoder->hpd_pin) {
case HPD_PORT_A:
hotplug = PORTA_HOTPLUG_ENABLE;
- if (intel_bios_is_port_hpd_inverted(i915, PORT_A))
+ 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_is_port_hpd_inverted(i915, PORT_B))
+ 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_is_port_hpd_inverted(i915, PORT_C))
+ if (intel_bios_encoder_hpd_invert(encoder->devdata))
hotplug |= BXT_DDIC_HPD_INVERT;
return hotplug;
default:
@@ -3471,15 +3467,33 @@ static void i8xx_irq_reset(struct drm_i915_private *dev_priv)
dev_priv->irq_mask = ~0u;
}
+static u32 i9xx_error_mask(struct drm_i915_private *i915)
+{
+ /*
+ * On gen2/3 FBC generates (seemingly spurious)
+ * display INVALID_GTT/INVALID_GTT_PTE table errors.
+ *
+ * Also gen3 bspec has this to say:
+ * "DISPA_INVALID_GTT_PTE
+ " [DevNapa] : Reserved. This bit does not reflect the page
+ " table error for the display plane A."
+ *
+ * Unfortunately we can't mask off individual PGTBL_ER bits,
+ * so we just have to mask off all page table errors via EMR.
+ */
+ if (HAS_FBC(i915))
+ return ~I915_ERROR_MEMORY_REFRESH;
+ else
+ return ~(I915_ERROR_PAGE_TABLE |
+ I915_ERROR_MEMORY_REFRESH);
+}
+
static void i8xx_irq_postinstall(struct drm_i915_private *dev_priv)
{
struct intel_uncore *uncore = &dev_priv->uncore;
u16 enable_mask;
- intel_uncore_write16(uncore,
- EMR,
- ~(I915_ERROR_PAGE_TABLE |
- I915_ERROR_MEMORY_REFRESH));
+ intel_uncore_write16(uncore, EMR, i9xx_error_mask(dev_priv));
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask =
@@ -3510,9 +3524,7 @@ static void i8xx_error_irq_ack(struct drm_i915_private *i915,
u16 emr;
*eir = intel_uncore_read16(uncore, EIR);
-
- if (*eir)
- intel_uncore_write16(uncore, EIR, *eir);
+ intel_uncore_write16(uncore, EIR, *eir);
*eir_stuck = intel_uncore_read16(uncore, EIR);
if (*eir_stuck == 0)
@@ -3541,6 +3553,9 @@ static void i8xx_error_irq_handler(struct drm_i915_private *dev_priv,
if (eir_stuck)
drm_dbg(&dev_priv->drm, "EIR stuck: 0x%04x, masked\n",
eir_stuck);
+
+ drm_dbg(&dev_priv->drm, "PGTBL_ER: 0x%08x\n",
+ intel_uncore_read(&dev_priv->uncore, PGTBL_ER));
}
static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv,
@@ -3548,7 +3563,8 @@ static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv,
{
u32 emr;
- *eir = intel_uncore_rmw(&dev_priv->uncore, EIR, 0, 0);
+ *eir = intel_uncore_read(&dev_priv->uncore, EIR);
+ intel_uncore_write(&dev_priv->uncore, EIR, *eir);
*eir_stuck = intel_uncore_read(&dev_priv->uncore, EIR);
if (*eir_stuck == 0)
@@ -3564,7 +3580,8 @@ static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv,
* (or by a GPU reset) so we mask any bit that
* remains set.
*/
- emr = intel_uncore_rmw(&dev_priv->uncore, EMR, ~0, 0xffffffff);
+ emr = intel_uncore_read(&dev_priv->uncore, EMR);
+ intel_uncore_write(&dev_priv->uncore, EMR, 0xffffffff);
intel_uncore_write(&dev_priv->uncore, EMR, emr | *eir_stuck);
}
@@ -3576,6 +3593,9 @@ static void i9xx_error_irq_handler(struct drm_i915_private *dev_priv,
if (eir_stuck)
drm_dbg(&dev_priv->drm, "EIR stuck: 0x%08x, masked\n",
eir_stuck);
+
+ drm_dbg(&dev_priv->drm, "PGTBL_ER: 0x%08x\n",
+ intel_uncore_read(&dev_priv->uncore, PGTBL_ER));
}
static irqreturn_t i8xx_irq_handler(int irq, void *arg)
@@ -3645,8 +3665,7 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv)
struct intel_uncore *uncore = &dev_priv->uncore;
u32 enable_mask;
- intel_uncore_write(uncore, EMR, ~(I915_ERROR_PAGE_TABLE |
- I915_ERROR_MEMORY_REFRESH));
+ intel_uncore_write(uncore, EMR, i9xx_error_mask(dev_priv));
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask =
@@ -3749,26 +3768,31 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv)
dev_priv->irq_mask = ~0u;
}
-static void i965_irq_postinstall(struct drm_i915_private *dev_priv)
+static u32 i965_error_mask(struct drm_i915_private *i915)
{
- struct intel_uncore *uncore = &dev_priv->uncore;
- u32 enable_mask;
- u32 error_mask;
-
/*
* Enable some error detection, note the instruction error mask
* bit is reserved, so we leave it masked.
+ *
+ * i965 FBC no longer generates spurious GTT errors,
+ * so we can always enable the page table errors.
*/
- if (IS_G4X(dev_priv)) {
- error_mask = ~(GM45_ERROR_PAGE_TABLE |
- GM45_ERROR_MEM_PRIV |
- GM45_ERROR_CP_PRIV |
- I915_ERROR_MEMORY_REFRESH);
- } else {
- error_mask = ~(I915_ERROR_PAGE_TABLE |
- I915_ERROR_MEMORY_REFRESH);
- }
- intel_uncore_write(uncore, EMR, error_mask);
+ if (IS_G4X(i915))
+ return ~(GM45_ERROR_PAGE_TABLE |
+ GM45_ERROR_MEM_PRIV |
+ GM45_ERROR_CP_PRIV |
+ I915_ERROR_MEMORY_REFRESH);
+ else
+ return ~(I915_ERROR_PAGE_TABLE |
+ I915_ERROR_MEMORY_REFRESH);
+}
+
+static void i965_irq_postinstall(struct drm_i915_private *dev_priv)
+{
+ struct intel_uncore *uncore = &dev_priv->uncore;
+ u32 enable_mask;
+
+ intel_uncore_write(uncore, EMR, i965_error_mask(dev_priv));
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask =