diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 144 | 
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 =  |