[PATCH 1/3] drm/radeon: Cleanup display interrupt handling for evergreen, si

Lyude lyude at redhat.com
Tue May 16 21:11:58 UTC 2017


The current code here is really, really bad. A huge amount of it looks
to be copy pasted, it has some weird hatred of arrays and code sharing,
switch cases everywhere for things that really don't need them, and it
makes the file seem immensely more complex then it actually is. This is
a pain for maintanence, and is vulnerable to more weird irq handling
bugs.

So, let's start cleaning this up a bit. Modify all of the IRQ handlers
for evergreen/si so that they just use for loops. As well, we add a
helper function radeon_irq_kms_set_irq_n_enabled(), whose purpose is
just to update the state of registers that enable/disable interrupts
while printing any changes to the set of enabled interrupts to the
kernel log.

There is one change here that doesn't look very important (testing
hasn't shown that it changes anyything afaict), but should be noted in
case this patch breaks something. The way the code originally handled
enabling or acking IRQs went like this:

 - Check enable/interrupt status of all IRQs
 - Write back any acknowledgements, enablements, or disablements to
   IRQs, all at the same time

But now with the helpers we've implemented, it goes a little more like
this
 - For each IRQ:
   - Check enable/interrupt status
   - Write back ack/new status

Signed-off-by: Lyude <lyude at redhat.com>
---
 drivers/gpu/drm/radeon/evergreen.c      | 699 ++++++--------------------------
 drivers/gpu/drm/radeon/evergreend.h     |  74 +---
 drivers/gpu/drm/radeon/radeon.h         |  13 +-
 drivers/gpu/drm/radeon/radeon_irq_kms.c |  35 ++
 drivers/gpu/drm/radeon/si.c             | 565 +++++---------------------
 drivers/gpu/drm/radeon/sid.h            |  72 +---
 6 files changed, 290 insertions(+), 1168 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 0bf1035..35baf0a 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1714,38 +1714,10 @@ void evergreen_pm_finish(struct radeon_device *rdev)
  */
 bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
 {
-	bool connected = false;
-
-	switch (hpd) {
-	case RADEON_HPD_1:
-		if (RREG32(DC_HPD1_INT_STATUS) & DC_HPDx_SENSE)
-			connected = true;
-		break;
-	case RADEON_HPD_2:
-		if (RREG32(DC_HPD2_INT_STATUS) & DC_HPDx_SENSE)
-			connected = true;
-		break;
-	case RADEON_HPD_3:
-		if (RREG32(DC_HPD3_INT_STATUS) & DC_HPDx_SENSE)
-			connected = true;
-		break;
-	case RADEON_HPD_4:
-		if (RREG32(DC_HPD4_INT_STATUS) & DC_HPDx_SENSE)
-			connected = true;
-		break;
-	case RADEON_HPD_5:
-		if (RREG32(DC_HPD5_INT_STATUS) & DC_HPDx_SENSE)
-			connected = true;
-		break;
-	case RADEON_HPD_6:
-		if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE)
-			connected = true;
-		break;
-	default:
-		break;
-	}
+	if (hpd == RADEON_HPD_NONE)
+		return false;
 
-	return connected;
+	return !!(RREG32(DC_HPDx_INT_STATUS(hpd)) & DC_HPDx_SENSE);
 }
 
 /**
@@ -1759,61 +1731,15 @@ bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
 void evergreen_hpd_set_polarity(struct radeon_device *rdev,
 				enum radeon_hpd_id hpd)
 {
-	u32 tmp;
 	bool connected = evergreen_hpd_sense(rdev, hpd);
 
-	switch (hpd) {
-	case RADEON_HPD_1:
-		tmp = RREG32(DC_HPD1_INT_CONTROL);
-		if (connected)
-			tmp &= ~DC_HPDx_INT_POLARITY;
-		else
-			tmp |= DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD1_INT_CONTROL, tmp);
-		break;
-	case RADEON_HPD_2:
-		tmp = RREG32(DC_HPD2_INT_CONTROL);
-		if (connected)
-			tmp &= ~DC_HPDx_INT_POLARITY;
-		else
-			tmp |= DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD2_INT_CONTROL, tmp);
-		break;
-	case RADEON_HPD_3:
-		tmp = RREG32(DC_HPD3_INT_CONTROL);
-		if (connected)
-			tmp &= ~DC_HPDx_INT_POLARITY;
-		else
-			tmp |= DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD3_INT_CONTROL, tmp);
-		break;
-	case RADEON_HPD_4:
-		tmp = RREG32(DC_HPD4_INT_CONTROL);
-		if (connected)
-			tmp &= ~DC_HPDx_INT_POLARITY;
-		else
-			tmp |= DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD4_INT_CONTROL, tmp);
-		break;
-	case RADEON_HPD_5:
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
-		if (connected)
-			tmp &= ~DC_HPDx_INT_POLARITY;
-		else
-			tmp |= DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD5_INT_CONTROL, tmp);
-			break;
-	case RADEON_HPD_6:
-		tmp = RREG32(DC_HPD6_INT_CONTROL);
-		if (connected)
-			tmp &= ~DC_HPDx_INT_POLARITY;
-		else
-			tmp |= DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD6_INT_CONTROL, tmp);
-		break;
-	default:
-		break;
-	}
+	if (hpd == RADEON_HPD_NONE)
+		return;
+
+	if (connected)
+		WREG32_AND(DC_HPDx_INT_CONTROL(hpd), ~DC_HPDx_INT_POLARITY);
+	else
+		WREG32_OR(DC_HPDx_INT_CONTROL(hpd), DC_HPDx_INT_POLARITY);
 }
 
 /**
@@ -1833,7 +1759,8 @@ void evergreen_hpd_init(struct radeon_device *rdev)
 		DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+		enum radeon_hpd_id hpd =
+			to_radeon_connector(connector)->hpd.hpd;
 
 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
 		    connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
@@ -1844,31 +1771,14 @@ void evergreen_hpd_init(struct radeon_device *rdev)
 			 */
 			continue;
 		}
-		switch (radeon_connector->hpd.hpd) {
-		case RADEON_HPD_1:
-			WREG32(DC_HPD1_CONTROL, tmp);
-			break;
-		case RADEON_HPD_2:
-			WREG32(DC_HPD2_CONTROL, tmp);
-			break;
-		case RADEON_HPD_3:
-			WREG32(DC_HPD3_CONTROL, tmp);
-			break;
-		case RADEON_HPD_4:
-			WREG32(DC_HPD4_CONTROL, tmp);
-			break;
-		case RADEON_HPD_5:
-			WREG32(DC_HPD5_CONTROL, tmp);
-			break;
-		case RADEON_HPD_6:
-			WREG32(DC_HPD6_CONTROL, tmp);
-			break;
-		default:
-			break;
-		}
-		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
-		if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
-			enabled |= 1 << radeon_connector->hpd.hpd;
+
+		if (hpd == RADEON_HPD_NONE)
+			continue;
+
+		WREG32(DC_HPDx_CONTROL(hpd), tmp);
+		enabled |= 1 << hpd;
+
+		radeon_hpd_set_polarity(rdev, hpd);
 	}
 	radeon_irq_kms_enable_hpd(rdev, enabled);
 }
@@ -1888,31 +1798,14 @@ void evergreen_hpd_fini(struct radeon_device *rdev)
 	unsigned disabled = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
-		switch (radeon_connector->hpd.hpd) {
-		case RADEON_HPD_1:
-			WREG32(DC_HPD1_CONTROL, 0);
-			break;
-		case RADEON_HPD_2:
-			WREG32(DC_HPD2_CONTROL, 0);
-			break;
-		case RADEON_HPD_3:
-			WREG32(DC_HPD3_CONTROL, 0);
-			break;
-		case RADEON_HPD_4:
-			WREG32(DC_HPD4_CONTROL, 0);
-			break;
-		case RADEON_HPD_5:
-			WREG32(DC_HPD5_CONTROL, 0);
-			break;
-		case RADEON_HPD_6:
-			WREG32(DC_HPD6_CONTROL, 0);
-			break;
-		default:
-			break;
-		}
-		if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
-			disabled |= 1 << radeon_connector->hpd.hpd;
+		enum radeon_hpd_id hpd =
+			to_radeon_connector(connector)->hpd.hpd;
+
+		if (hpd == RADEON_HPD_NONE)
+			continue;
+
+		WREG32(DC_HPDx_CONTROL(hpd), 0);
+		disabled |= 1 << hpd;
 	}
 	radeon_irq_kms_disable_hpd(rdev, disabled);
 }
@@ -4543,6 +4436,7 @@ u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc)
 
 void evergreen_disable_interrupt_state(struct radeon_device *rdev)
 {
+	int i;
 	u32 tmp;
 
 	if (rdev->family >= CHIP_CAYMAN) {
@@ -4558,16 +4452,8 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
 	WREG32(DMA_CNTL, tmp);
 	WREG32(GRBM_INT_CNTL, 0);
 	WREG32(SRBM_INT_CNTL, 0);
-	WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-	WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-	if (rdev->num_crtc >= 4) {
-		WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-		WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
-	}
+	for (i = 0; i < rdev->num_crtc; i++)
+		WREG32(INT_MASK + crtc_offsets[i], 0);
 
 	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
 	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@@ -4585,27 +4471,15 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
 		WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
 	WREG32(DACB_AUTODETECT_INT_CONTROL, 0);
 
-	tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-	WREG32(DC_HPD1_INT_CONTROL, tmp);
-	tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-	WREG32(DC_HPD2_INT_CONTROL, tmp);
-	tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-	WREG32(DC_HPD3_INT_CONTROL, tmp);
-	tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-	WREG32(DC_HPD4_INT_CONTROL, tmp);
-	tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-	WREG32(DC_HPD5_INT_CONTROL, tmp);
-	tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-	WREG32(DC_HPD6_INT_CONTROL, tmp);
-
+	for (i = 0; i < EVERGREEN_MAX_DISP_REGISTERS; i++)
+		WREG32_AND(DC_HPDx_INT_CONTROL(i), DC_HPDx_INT_POLARITY);
 }
 
 int evergreen_irq_set(struct radeon_device *rdev)
 {
+	int i;
 	u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
 	u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0;
-	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
-	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
 	u32 grbm_int_cntl = 0;
 	u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;
 	u32 dma_cntl, dma_cntl1 = 0;
@@ -4623,12 +4497,6 @@ int evergreen_irq_set(struct radeon_device *rdev)
 		return 0;
 	}
 
-	hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-	hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-	hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-	hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
 	if (rdev->family == CHIP_ARUBA)
 		thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) &
 			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
@@ -4685,60 +4553,6 @@ int evergreen_irq_set(struct radeon_device *rdev)
 		thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
 	}
 
-	if (rdev->irq.crtc_vblank_int[0] ||
-	    atomic_read(&rdev->irq.pflip[0])) {
-		DRM_DEBUG("evergreen_irq_set: vblank 0\n");
-		crtc1 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[1] ||
-	    atomic_read(&rdev->irq.pflip[1])) {
-		DRM_DEBUG("evergreen_irq_set: vblank 1\n");
-		crtc2 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[2] ||
-	    atomic_read(&rdev->irq.pflip[2])) {
-		DRM_DEBUG("evergreen_irq_set: vblank 2\n");
-		crtc3 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[3] ||
-	    atomic_read(&rdev->irq.pflip[3])) {
-		DRM_DEBUG("evergreen_irq_set: vblank 3\n");
-		crtc4 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[4] ||
-	    atomic_read(&rdev->irq.pflip[4])) {
-		DRM_DEBUG("evergreen_irq_set: vblank 4\n");
-		crtc5 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[5] ||
-	    atomic_read(&rdev->irq.pflip[5])) {
-		DRM_DEBUG("evergreen_irq_set: vblank 5\n");
-		crtc6 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.hpd[0]) {
-		DRM_DEBUG("evergreen_irq_set: hpd 1\n");
-		hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[1]) {
-		DRM_DEBUG("evergreen_irq_set: hpd 2\n");
-		hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[2]) {
-		DRM_DEBUG("evergreen_irq_set: hpd 3\n");
-		hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[3]) {
-		DRM_DEBUG("evergreen_irq_set: hpd 4\n");
-		hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[4]) {
-		DRM_DEBUG("evergreen_irq_set: hpd 5\n");
-		hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[5]) {
-		DRM_DEBUG("evergreen_irq_set: hpd 6\n");
-		hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
 	if (rdev->irq.afmt[0]) {
 		DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
 		afmt1 |= AFMT_AZ_FORMAT_WTRIG_MASK;
@@ -4778,17 +4592,6 @@ int evergreen_irq_set(struct radeon_device *rdev)
 
 	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
 
-	WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
-	WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
-	if (rdev->num_crtc >= 4) {
-		WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
-		WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
-		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
-	}
-
 	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET,
 	       GRPH_PFLIP_INT_MASK);
 	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET,
@@ -4806,12 +4609,21 @@ int evergreen_irq_set(struct radeon_device *rdev)
 		       GRPH_PFLIP_INT_MASK);
 	}
 
-	WREG32(DC_HPD1_INT_CONTROL, hpd1);
-	WREG32(DC_HPD2_INT_CONTROL, hpd2);
-	WREG32(DC_HPD3_INT_CONTROL, hpd3);
-	WREG32(DC_HPD4_INT_CONTROL, hpd4);
-	WREG32(DC_HPD5_INT_CONTROL, hpd5);
-	WREG32(DC_HPD6_INT_CONTROL, hpd6);
+	for (i = 0; i < EVERGREEN_MAX_DISP_REGISTERS; i++) {
+		radeon_irq_kms_set_irq_n_enabled(rdev,
+						 DC_HPDx_INT_CONTROL(i),
+						 DC_HPDx_INT_EN |
+						 DC_HPDx_RX_INT_EN,
+						 rdev->irq.hpd[i], "HPD", i);
+
+		if (i < rdev->num_crtc) {
+			radeon_irq_kms_set_irq_n_enabled(
+			    rdev, INT_MASK + crtc_offsets[i], VBLANK_INT_MASK,
+			    rdev->irq.crtc_vblank_int[i] ||
+			    atomic_read(&rdev->irq.pflip[i]), "vblank", i);
+		}
+	}
+
 	if (rdev->family == CHIP_ARUBA)
 		WREG32(TN_CG_THERMAL_INT_CTRL, thermal_int);
 	else
@@ -4832,14 +4644,28 @@ int evergreen_irq_set(struct radeon_device *rdev)
 
 static void evergreen_irq_ack(struct radeon_device *rdev)
 {
+	int i;
+	u32 *disp_int = rdev->irq.stat_regs.evergreen.disp_int;
 	u32 tmp;
 
-	rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS);
-	rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
-	rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
-	rdev->irq.stat_regs.evergreen.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
-	rdev->irq.stat_regs.evergreen.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
-	rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
+	for (i = 0; i < EVERGREEN_MAX_DISP_REGISTERS; i++) {
+		disp_int[i] = RREG32(DISP_INTERRUPT_STATUS(i));
+
+		if (disp_int[i] & DC_HPDx_INTERRUPT)
+			WREG32_OR(DC_HPDx_INT_CONTROL(i), DC_HPDx_INT_ACK);
+		if (disp_int[i] & DC_HPDx_RX_INTERRUPT)
+			WREG32_OR(DC_HPDx_INT_CONTROL(i), DC_HPDx_RX_INT_ACK);
+
+		if (i < rdev->num_crtc) {
+			if (disp_int[i] & LB_Dx_VBLANK_INTERRUPT)
+				WREG32(VBLANK_STATUS + crtc_offsets[i],
+				       VBLANK_ACK);
+			if (disp_int[i] & LB_Dx_VLINE_INTERRUPT)
+				WREG32(VLINE_STATUS + crtc_offsets[i],
+				       VLINE_ACK);
+		}
+	}
+
 	rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
 	rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
 	if (rdev->num_crtc >= 4) {
@@ -4862,28 +4688,12 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
 		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
 	if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
 		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
-	if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)
-		WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
-	if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)
-		WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
-		WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)
-		WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
 
 	if (rdev->num_crtc >= 4) {
 		if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
 		if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
 	}
 
 	if (rdev->num_crtc >= 6) {
@@ -4891,76 +4701,6 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
 		if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
-	}
-
-	if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
-		tmp = RREG32(DC_HPD1_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD1_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
-		tmp = RREG32(DC_HPD2_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD2_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
-		tmp = RREG32(DC_HPD3_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD3_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
-		tmp = RREG32(DC_HPD4_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD4_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD5_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-		tmp = RREG32(DC_HPD6_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD6_INT_CONTROL, tmp);
-	}
-
-	if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD1_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD1_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD2_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD2_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD3_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD3_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD4_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD4_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD5_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD6_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
 
 	if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
@@ -5037,6 +4777,9 @@ static u32 evergreen_get_ih_wptr(struct radeon_device *rdev)
 
 int evergreen_irq_process(struct radeon_device *rdev)
 {
+	u32 *disp_int = rdev->irq.stat_regs.evergreen.disp_int;
+	u32 crtc_idx, hpd_idx;
+	u32 mask;
 	u32 wptr;
 	u32 rptr;
 	u32 src_id, src_data;
@@ -5046,6 +4789,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
 	bool queue_dp = false;
 	bool queue_thermal = false;
 	u32 status, addr;
+	const char *event_name;
 
 	if (!rdev->ih.enabled || rdev->shutdown)
 		return IRQ_NONE;
@@ -5074,184 +4818,44 @@ int evergreen_irq_process(struct radeon_device *rdev)
 
 		switch (src_id) {
 		case 1: /* D1 vblank/vline */
-			switch (src_data) {
-			case 0: /* D1 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[0]) {
-					drm_handle_vblank(rdev->ddev, 0);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[0]))
-					radeon_crtc_handle_vblank(rdev, 0);
-				rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D1 vblank\n");
-
-				break;
-			case 1: /* D1 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D1 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 2: /* D2 vblank/vline */
-			switch (src_data) {
-			case 0: /* D2 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[1]) {
-					drm_handle_vblank(rdev->ddev, 1);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[1]))
-					radeon_crtc_handle_vblank(rdev, 1);
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D2 vblank\n");
-
-				break;
-			case 1: /* D2 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D2 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 3: /* D3 vblank/vline */
-			switch (src_data) {
-			case 0: /* D3 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: D3 vblank - IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[2]) {
-					drm_handle_vblank(rdev->ddev, 2);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[2]))
-					radeon_crtc_handle_vblank(rdev, 2);
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D3 vblank\n");
-
-				break;
-			case 1: /* D3 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: D3 vline - IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D3 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 4: /* D4 vblank/vline */
-			switch (src_data) {
-			case 0: /* D4 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: D4 vblank - IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[3]) {
-					drm_handle_vblank(rdev->ddev, 3);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[3]))
-					radeon_crtc_handle_vblank(rdev, 3);
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D4 vblank\n");
-
-				break;
-			case 1: /* D4 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: D4 vline - IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D4 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 5: /* D5 vblank/vline */
-			switch (src_data) {
-			case 0: /* D5 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: D5 vblank - IH event w/o asserted irq bit?\n");
+		case 6: /* D6 vblank/vline */
+			crtc_idx = src_id - 1;
 
-				if (rdev->irq.crtc_vblank_int[4]) {
-					drm_handle_vblank(rdev->ddev, 4);
+			if (src_data == 0) { /* vblank */
+				mask = LB_Dx_VBLANK_INTERRUPT;
+				event_name = "vblank";
+
+				if (rdev->irq.crtc_vblank_int[crtc_idx]) {
+					drm_handle_vblank(rdev->ddev, crtc_idx);
 					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 				}
-				if (atomic_read(&rdev->irq.pflip[4]))
-					radeon_crtc_handle_vblank(rdev, 4);
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D5 vblank\n");
-
-				break;
-			case 1: /* D5 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: D5 vline - IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D5 vline\n");
+				if (atomic_read(&rdev->irq.pflip[crtc_idx])) {
+					radeon_crtc_handle_vblank(rdev,
+								  crtc_idx);
+				}
 
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+			} else if (src_data == 1) { /* vline */
+				mask = LB_Dx_VLINE_INTERRUPT;
+				event_name = "vline";
+			} else {
+				DRM_DEBUG("Unhandled interrupt: %d %d\n",
+					  src_id, src_data);
 				break;
 			}
-			break;
-		case 6: /* D6 vblank/vline */
-			switch (src_data) {
-			case 0: /* D6 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: D6 vblank - IH event w/o asserted irq bit?\n");
 
-				if (rdev->irq.crtc_vblank_int[5]) {
-					drm_handle_vblank(rdev->ddev, 5);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[5]))
-					radeon_crtc_handle_vblank(rdev, 5);
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D6 vblank\n");
-
-				break;
-			case 1: /* D6 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: D6 vline - IH event w/o asserted irq bit?\n");
+			if (!(disp_int[crtc_idx] & mask)) {
+				DRM_DEBUG("IH: D%d %s - IH event w/o asserted irq bit?\n",
+					  crtc_idx + 1, event_name);
+			}
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D6 vline\n");
+			disp_int[crtc_idx] &= ~mask;
+			DRM_DEBUG("IH: D%d %s\n", crtc_idx + 1, event_name);
 
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
 			break;
 		case 8: /* D1 page flip */
 		case 10: /* D2 page flip */
@@ -5264,107 +4868,30 @@ int evergreen_irq_process(struct radeon_device *rdev)
 				radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1);
 			break;
 		case 42: /* HPD hotplug */
-			switch (src_data) {
-			case 0:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD1\n");
-				break;
-			case 1:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD2\n");
-				break;
-			case 2:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD3\n");
-				break;
-			case 3:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+			if (src_data <= 5) {
+				hpd_idx = src_data;
+				mask = DC_HPDx_INTERRUPT;
 				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD4\n");
-				break;
-			case 4:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+				event_name = "HPD";
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD5\n");
-				break;
-			case 5:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD6\n");
-				break;
-			case 6:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 1\n");
-				break;
-			case 7:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+			} else if (src_data <= 11) {
+				hpd_idx = src_data - 6;
+				mask = DC_HPDx_RX_INTERRUPT;
 				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 2\n");
-				break;
-			case 8:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+				event_name = "HPD_RX";
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 3\n");
+			} else {
+				DRM_DEBUG("Unhandled interrupt: %d %d\n",
+					  src_id, src_data);
 				break;
-			case 9:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+			}
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 4\n");
-				break;
-			case 10:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+			if (!(disp_int[hpd_idx] & mask))
+				DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 5\n");
-				break;
-			case 11:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+			disp_int[hpd_idx] &= ~mask;
+			DRM_DEBUG("IH: %s%d\n", event_name, hpd_idx + 1);
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 6\n");
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
 			break;
 		case 44: /* hdmi */
 			switch (src_data) {
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index f3d88ca..56d1e7e 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -36,6 +36,7 @@
 #define EVERGREEN_MAX_PIPES             8
 #define EVERGREEN_MAX_PIPES_MASK        0xFF
 #define EVERGREEN_MAX_LDS_NUM           0xFFFF
+#define EVERGREEN_MAX_DISP_REGISTERS    6
 
 #define CYPRESS_GB_ADDR_CONFIG_GOLDEN        0x02011003
 #define BARTS_GB_ADDR_CONFIG_GOLDEN          0x02011003
@@ -1285,85 +1286,52 @@
 #       define VBLANK_INT_MASK                          (1 << 0)
 #       define VLINE_INT_MASK                           (1 << 4)
 
-#define DISP_INTERRUPT_STATUS                           0x60f4
-#       define LB_D1_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D1_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD1_INTERRUPT                        (1 << 17)
-#       define DC_HPD1_RX_INTERRUPT                     (1 << 18)
+/* 0x60f4, 0x60f8, 0x60fc, 0x6100, 0x614c, 0x6150 */
+#define DISP_INTERRUPT_STATUS(i) \
+	((i < 4) ? 0x60f4 + (0x4 * i) : 0x614c + (0x4 * (i - 4)))
+#       define LB_Dx_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_Dx_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPDx_INTERRUPT                        (1 << 17)
+#       define DC_HPDx_RX_INTERRUPT                     (1 << 18)
+/* First reg only */
 #       define DACA_AUTODETECT_INTERRUPT                (1 << 22)
 #       define DACB_AUTODETECT_INTERRUPT                (1 << 23)
 #       define DC_I2C_SW_DONE_INTERRUPT                 (1 << 24)
 #       define DC_I2C_HW_DONE_INTERRUPT                 (1 << 25)
-#define DISP_INTERRUPT_STATUS_CONTINUE                  0x60f8
-#       define LB_D2_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D2_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD2_INTERRUPT                        (1 << 17)
-#       define DC_HPD2_RX_INTERRUPT                     (1 << 18)
+/* Second reg only */
 #       define DISP_TIMER_INTERRUPT                     (1 << 24)
-#define DISP_INTERRUPT_STATUS_CONTINUE2                 0x60fc
-#       define LB_D3_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D3_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD3_INTERRUPT                        (1 << 17)
-#       define DC_HPD3_RX_INTERRUPT                     (1 << 18)
-#define DISP_INTERRUPT_STATUS_CONTINUE3                 0x6100
-#       define LB_D4_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D4_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD4_INTERRUPT                        (1 << 17)
-#       define DC_HPD4_RX_INTERRUPT                     (1 << 18)
-#define DISP_INTERRUPT_STATUS_CONTINUE4                 0x614c
-#       define LB_D5_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D5_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD5_INTERRUPT                        (1 << 17)
-#       define DC_HPD5_RX_INTERRUPT                     (1 << 18)
-#define DISP_INTERRUPT_STATUS_CONTINUE5                 0x6150
-#       define LB_D6_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D6_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD6_INTERRUPT                        (1 << 17)
-#       define DC_HPD6_RX_INTERRUPT                     (1 << 18)
 
 /* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */
 #define GRPH_INT_STATUS                                 0x6858
 #       define GRPH_PFLIP_INT_OCCURRED                  (1 << 0)
 #       define GRPH_PFLIP_INT_CLEAR                     (1 << 8)
 /* 0x685c, 0x745c, 0x1005c, 0x10c5c, 0x1185c, 0x1245c */
-#define	GRPH_INT_CONTROL			        0x685c
+#define	GRPH_INT_CONTROL                                0x685c
 #       define GRPH_PFLIP_INT_MASK                      (1 << 0)
 #       define GRPH_PFLIP_INT_TYPE                      (1 << 8)
 
 #define	DACA_AUTODETECT_INT_CONTROL			0x66c8
 #define	DACB_AUTODETECT_INT_CONTROL			0x67c8
 
-#define DC_HPD1_INT_STATUS                              0x601c
-#define DC_HPD2_INT_STATUS                              0x6028
-#define DC_HPD3_INT_STATUS                              0x6034
-#define DC_HPD4_INT_STATUS                              0x6040
-#define DC_HPD5_INT_STATUS                              0x604c
-#define DC_HPD6_INT_STATUS                              0x6058
-#       define DC_HPDx_INT_STATUS                       (1 << 0)
+/* 0x601c, 0x6028, 0x6034, 0x6040, 0x604c, 0x6058 */
+#define DC_HPDx_INT_STATUS(x)                           (0x601c + (0xc * x))
+#       define DC_HPDx_INT_STATUS_MASK                  (1 << 0)
 #       define DC_HPDx_SENSE                            (1 << 1)
 #       define DC_HPDx_RX_INT_STATUS                    (1 << 8)
 
-#define DC_HPD1_INT_CONTROL                             0x6020
-#define DC_HPD2_INT_CONTROL                             0x602c
-#define DC_HPD3_INT_CONTROL                             0x6038
-#define DC_HPD4_INT_CONTROL                             0x6044
-#define DC_HPD5_INT_CONTROL                             0x6050
-#define DC_HPD6_INT_CONTROL                             0x605c
+/* 0x6020, 0x602c, 0x6038, 0x6044, 0x6050, 0x605c */
+#define DC_HPDx_INT_CONTROL(x)                          (0x6020 + (0xc * x))
 #       define DC_HPDx_INT_ACK                          (1 << 0)
 #       define DC_HPDx_INT_POLARITY                     (1 << 8)
 #       define DC_HPDx_INT_EN                           (1 << 16)
 #       define DC_HPDx_RX_INT_ACK                       (1 << 20)
 #       define DC_HPDx_RX_INT_EN                        (1 << 24)
 
-#define DC_HPD1_CONTROL                                   0x6024
-#define DC_HPD2_CONTROL                                   0x6030
-#define DC_HPD3_CONTROL                                   0x603c
-#define DC_HPD4_CONTROL                                   0x6048
-#define DC_HPD5_CONTROL                                   0x6054
-#define DC_HPD6_CONTROL                                   0x6060
-#       define DC_HPDx_CONNECTION_TIMER(x)                ((x) << 0)
-#       define DC_HPDx_RX_INT_TIMER(x)                    ((x) << 16)
-#       define DC_HPDx_EN                                 (1 << 28)
+/* 0x6024, 0x6030, 0x603c, 0x6048, 0x6054, 0x6060 */
+#define DC_HPDx_CONTROL(x)                              (0x6024 + (0xc * x))
+#       define DC_HPDx_CONNECTION_TIMER(x)              ((x) << 0)
+#       define DC_HPDx_RX_INT_TIMER(x)                  ((x) << 16)
+#       define DC_HPDx_EN                               (1 << 28)
 
 /* DCE4/5/6 FMT blocks */
 #define FMT_DYNAMIC_EXP_CNTL                 0x6fb4
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index c1c8e22..b6086ee 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -767,12 +767,7 @@ struct r600_irq_stat_regs {
 };
 
 struct evergreen_irq_stat_regs {
-	u32 disp_int;
-	u32 disp_int_cont;
-	u32 disp_int_cont2;
-	u32 disp_int_cont3;
-	u32 disp_int_cont4;
-	u32 disp_int_cont5;
+	u32 disp_int[6];
 	u32 d1grph_int;
 	u32 d2grph_int;
 	u32 d3grph_int;
@@ -2976,6 +2971,12 @@ int r600_cs_common_vline_parse(struct radeon_cs_parser *p,
 			       uint32_t *vline_start_end,
 			       uint32_t *vline_status);
 
+/* interrupt control register helpers */
+void radeon_irq_kms_set_irq_n_enabled(struct radeon_device *rdev,
+				      u32 reg, u32 mask,
+				      bool enable, const char *name,
+				      unsigned n);
+
 #include "radeon_object.h"
 
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 1b7528d..7aacb44 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -538,3 +538,38 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask)
 	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
+/**
+ * radeon_irq_kms_update_int_n - helper for updating interrupt enable registers
+ *
+ * @rdev: radeon device pointer
+ * @reg: the register to write to enable/disable interrupts
+ * @mask: the mask that enables the interrupts
+ * @enable: whether to enable or disable the interrupt register
+ * @name: the name of the interrupt register to print to the kernel log
+ * @num: the number of the interrupt register to print to the kernel log
+ *
+ * Helper for updating the enable state of interrupt registers. Checks whether
+ * or not the interrupt matches the enable state we want. If it doesn't, then
+ * we update it and print a debugging message to the kernel log indicating the
+ * new state of the interrupt register.
+ *
+ * Used for updating sequences of interrupts registers like HPD1, HPD2, etc.
+ */
+void radeon_irq_kms_set_irq_n_enabled(struct radeon_device *rdev,
+				      u32 reg, u32 mask,
+				      bool enable, const char *name, unsigned n)
+{
+	u32 tmp = RREG32(reg);
+
+	/* Interrupt state didn't change */
+	if (!!(tmp & mask) == enable)
+		return;
+
+	if (enable) {
+		DRM_DEBUG("%s%d interrupts enabled\n", name, n);
+		WREG32(reg, tmp |= mask);
+	} else {
+		DRM_DEBUG("%s%d interrupts disabled\n", name, n);
+		WREG32(reg, tmp & ~mask);
+	}
+}
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 76d1888..bb745e1 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -139,6 +139,16 @@ static void si_fini_pg(struct radeon_device *rdev);
 static void si_fini_cg(struct radeon_device *rdev);
 static void si_rlc_stop(struct radeon_device *rdev);
 
+static const u32 crtc_offsets[] =
+{
+	EVERGREEN_CRTC0_REGISTER_OFFSET,
+	EVERGREEN_CRTC1_REGISTER_OFFSET,
+	EVERGREEN_CRTC2_REGISTER_OFFSET,
+	EVERGREEN_CRTC3_REGISTER_OFFSET,
+	EVERGREEN_CRTC4_REGISTER_OFFSET,
+	EVERGREEN_CRTC5_REGISTER_OFFSET
+};
+
 static const u32 verde_rlc_save_restore_register_list[] =
 {
 	(0x8000 << 16) | (0x98f4 >> 2),
@@ -5916,6 +5926,7 @@ static void si_disable_interrupts(struct radeon_device *rdev)
 
 static void si_disable_interrupt_state(struct radeon_device *rdev)
 {
+	int i;
 	u32 tmp;
 
 	tmp = RREG32(CP_INT_CNTL_RING0) &
@@ -5929,18 +5940,8 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
 	WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp);
 	WREG32(GRBM_INT_CNTL, 0);
 	WREG32(SRBM_INT_CNTL, 0);
-	if (rdev->num_crtc >= 2) {
-		WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-		WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-	}
-	if (rdev->num_crtc >= 4) {
-		WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-		WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
-	}
+	for (i = 0; i < rdev->num_crtc; i++)
+		WREG32(INT_MASK + crtc_offsets[i], 0);
 
 	if (rdev->num_crtc >= 2) {
 		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
@@ -5958,18 +5959,9 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
 	if (!ASIC_IS_NODCE(rdev)) {
 		WREG32(DAC_AUTODETECT_INT_CONTROL, 0);
 
-		tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD1_INT_CONTROL, tmp);
-		tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD2_INT_CONTROL, tmp);
-		tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD3_INT_CONTROL, tmp);
-		tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD4_INT_CONTROL, tmp);
-		tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD5_INT_CONTROL, tmp);
-		tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
-		WREG32(DC_HPD6_INT_CONTROL, tmp);
+		for (i = 0; i < SI_MAX_DISP_REGISTERS; i++)
+			WREG32_AND(DC_HPDx_INT_CONTROL(i),
+				   DC_HPDx_INT_POLARITY);
 	}
 }
 
@@ -6046,10 +6038,9 @@ static int si_irq_init(struct radeon_device *rdev)
 
 int si_irq_set(struct radeon_device *rdev)
 {
+	int i;
 	u32 cp_int_cntl;
 	u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0;
-	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
-	u32 hpd1 = 0, hpd2 = 0, hpd3 = 0, hpd4 = 0, hpd5 = 0, hpd6 = 0;
 	u32 grbm_int_cntl = 0;
 	u32 dma_cntl, dma_cntl1;
 	u32 thermal_int = 0;
@@ -6069,15 +6060,6 @@ int si_irq_set(struct radeon_device *rdev)
 	cp_int_cntl = RREG32(CP_INT_CNTL_RING0) &
 		(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
 
-	if (!ASIC_IS_NODCE(rdev)) {
-		hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-		hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-		hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-		hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-		hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-		hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
-	}
-
 	dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
 	dma_cntl1 = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
 
@@ -6106,60 +6088,6 @@ int si_irq_set(struct radeon_device *rdev)
 		DRM_DEBUG("si_irq_set: sw int dma1\n");
 		dma_cntl1 |= TRAP_ENABLE;
 	}
-	if (rdev->irq.crtc_vblank_int[0] ||
-	    atomic_read(&rdev->irq.pflip[0])) {
-		DRM_DEBUG("si_irq_set: vblank 0\n");
-		crtc1 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[1] ||
-	    atomic_read(&rdev->irq.pflip[1])) {
-		DRM_DEBUG("si_irq_set: vblank 1\n");
-		crtc2 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[2] ||
-	    atomic_read(&rdev->irq.pflip[2])) {
-		DRM_DEBUG("si_irq_set: vblank 2\n");
-		crtc3 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[3] ||
-	    atomic_read(&rdev->irq.pflip[3])) {
-		DRM_DEBUG("si_irq_set: vblank 3\n");
-		crtc4 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[4] ||
-	    atomic_read(&rdev->irq.pflip[4])) {
-		DRM_DEBUG("si_irq_set: vblank 4\n");
-		crtc5 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.crtc_vblank_int[5] ||
-	    atomic_read(&rdev->irq.pflip[5])) {
-		DRM_DEBUG("si_irq_set: vblank 5\n");
-		crtc6 |= VBLANK_INT_MASK;
-	}
-	if (rdev->irq.hpd[0]) {
-		DRM_DEBUG("si_irq_set: hpd 1\n");
-		hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[1]) {
-		DRM_DEBUG("si_irq_set: hpd 2\n");
-		hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[2]) {
-		DRM_DEBUG("si_irq_set: hpd 3\n");
-		hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[3]) {
-		DRM_DEBUG("si_irq_set: hpd 4\n");
-		hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[4]) {
-		DRM_DEBUG("si_irq_set: hpd 5\n");
-		hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
-	if (rdev->irq.hpd[5]) {
-		DRM_DEBUG("si_irq_set: hpd 6\n");
-		hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
-	}
 
 	WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
 	WREG32(CP_INT_CNTL_RING1, cp_int_cntl1);
@@ -6176,19 +6104,6 @@ int si_irq_set(struct radeon_device *rdev)
 	}
 
 	if (rdev->num_crtc >= 2) {
-		WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
-		WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
-	}
-	if (rdev->num_crtc >= 4) {
-		WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
-		WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
-		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
-	}
-
-	if (rdev->num_crtc >= 2) {
 		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET,
 		       GRPH_PFLIP_INT_MASK);
 		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET,
@@ -6208,12 +6123,19 @@ int si_irq_set(struct radeon_device *rdev)
 	}
 
 	if (!ASIC_IS_NODCE(rdev)) {
-		WREG32(DC_HPD1_INT_CONTROL, hpd1);
-		WREG32(DC_HPD2_INT_CONTROL, hpd2);
-		WREG32(DC_HPD3_INT_CONTROL, hpd3);
-		WREG32(DC_HPD4_INT_CONTROL, hpd4);
-		WREG32(DC_HPD5_INT_CONTROL, hpd5);
-		WREG32(DC_HPD6_INT_CONTROL, hpd6);
+		for (i = 0; i < SI_MAX_DISP_REGISTERS; i++) {
+			radeon_irq_kms_set_irq_n_enabled(
+			    rdev, DC_HPDx_INT_CONTROL(i),
+			    DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN,
+			    rdev->irq.hpd[i], "HPD", i);
+		}
+	}
+
+	for (i = 0; i < rdev->num_crtc; i++) {
+		radeon_irq_kms_set_irq_n_enabled(
+		    rdev, INT_MASK + crtc_offsets[i], VBLANK_INT_MASK,
+		    rdev->irq.crtc_vblank_int[i] ||
+		    atomic_read(&rdev->irq.pflip[i]), "vblank", i);
 	}
 
 	WREG32(CG_THERMAL_INT, thermal_int);
@@ -6226,17 +6148,12 @@ int si_irq_set(struct radeon_device *rdev)
 
 static inline void si_irq_ack(struct radeon_device *rdev)
 {
-	u32 tmp;
+	int i;
+	u32 *disp_int = rdev->irq.stat_regs.evergreen.disp_int;
 
 	if (ASIC_IS_NODCE(rdev))
 		return;
 
-	rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS);
-	rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
-	rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
-	rdev->irq.stat_regs.evergreen.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
-	rdev->irq.stat_regs.evergreen.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
-	rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
 	rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
 	rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
 	if (rdev->num_crtc >= 4) {
@@ -6248,32 +6165,34 @@ static inline void si_irq_ack(struct radeon_device *rdev)
 		rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
 	}
 
+	for (i = 0; i < SI_MAX_DISP_REGISTERS; i++) {
+		disp_int[i] = RREG32(DISP_INTERRUPT_STATUS(i));
+
+		if (disp_int[i] & DC_HPDx_INTERRUPT)
+			WREG32_OR(DC_HPDx_INT_CONTROL(i), DC_HPDx_INT_ACK);
+		if (disp_int[i] & DC_HPDx_RX_INTERRUPT)
+			WREG32_OR(DC_HPDx_INT_CONTROL(i), DC_HPDx_RX_INT_ACK);
+
+		if (i < rdev->num_crtc) {
+			if (disp_int[i] & LB_Dx_VBLANK_INTERRUPT)
+				WREG32(VBLANK_STATUS + crtc_offsets[i],
+				       VBLANK_ACK);
+			if (disp_int[i] & LB_Dx_VLINE_INTERRUPT)
+				WREG32(VLINE_STATUS + crtc_offsets[i],
+				       VLINE_ACK);
+		}
+	}
+
 	if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
 		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
 	if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
 		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
-	if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)
-		WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
-	if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)
-		WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
-		WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)
-		WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
 
 	if (rdev->num_crtc >= 4) {
 		if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
 		if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
 	}
 
 	if (rdev->num_crtc >= 6) {
@@ -6281,76 +6200,6 @@ static inline void si_irq_ack(struct radeon_device *rdev)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
 		if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED)
 			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
-			WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
-		if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
-			WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
-	}
-
-	if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
-		tmp = RREG32(DC_HPD1_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD1_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
-		tmp = RREG32(DC_HPD2_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD2_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
-		tmp = RREG32(DC_HPD3_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD3_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
-		tmp = RREG32(DC_HPD4_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD4_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD5_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-		tmp = RREG32(DC_HPD6_INT_CONTROL);
-		tmp |= DC_HPDx_INT_ACK;
-		WREG32(DC_HPD6_INT_CONTROL, tmp);
-	}
-
-	if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD1_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD1_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD2_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD2_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD3_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD3_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD4_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD4_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD5_INT_CONTROL, tmp);
-	}
-	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD6_INT_CONTROL);
-		tmp |= DC_HPDx_RX_INT_ACK;
-		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
 }
 
@@ -6412,6 +6261,9 @@ static inline u32 si_get_ih_wptr(struct radeon_device *rdev)
  */
 int si_irq_process(struct radeon_device *rdev)
 {
+	u32 *disp_int = rdev->irq.stat_regs.evergreen.disp_int;
+	u32 crtc_idx, hpd_idx;
+	u32 mask;
 	u32 wptr;
 	u32 rptr;
 	u32 src_id, src_data, ring_id;
@@ -6420,6 +6272,7 @@ int si_irq_process(struct radeon_device *rdev)
 	bool queue_dp = false;
 	bool queue_thermal = false;
 	u32 status, addr;
+	const char *event_name;
 
 	if (!rdev->ih.enabled || rdev->shutdown)
 		return IRQ_NONE;
@@ -6449,184 +6302,44 @@ int si_irq_process(struct radeon_device *rdev)
 
 		switch (src_id) {
 		case 1: /* D1 vblank/vline */
-			switch (src_data) {
-			case 0: /* D1 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[0]) {
-					drm_handle_vblank(rdev->ddev, 0);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[0]))
-					radeon_crtc_handle_vblank(rdev, 0);
-				rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D1 vblank\n");
-
-				break;
-			case 1: /* D1 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D1 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 2: /* D2 vblank/vline */
-			switch (src_data) {
-			case 0: /* D2 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[1]) {
-					drm_handle_vblank(rdev->ddev, 1);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[1]))
-					radeon_crtc_handle_vblank(rdev, 1);
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D2 vblank\n");
-
-				break;
-			case 1: /* D2 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D2 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 3: /* D3 vblank/vline */
-			switch (src_data) {
-			case 0: /* D3 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[2]) {
-					drm_handle_vblank(rdev->ddev, 2);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[2]))
-					radeon_crtc_handle_vblank(rdev, 2);
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D3 vblank\n");
-
-				break;
-			case 1: /* D3 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D3 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 4: /* D4 vblank/vline */
-			switch (src_data) {
-			case 0: /* D4 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[3]) {
-					drm_handle_vblank(rdev->ddev, 3);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[3]))
-					radeon_crtc_handle_vblank(rdev, 3);
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D4 vblank\n");
-
-				break;
-			case 1: /* D4 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D4 vline\n");
-
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
-			break;
 		case 5: /* D5 vblank/vline */
-			switch (src_data) {
-			case 0: /* D5 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+		case 6: /* D6 vblank/vline */
+			crtc_idx = src_id - 1;
+
+			if (src_data == 0) { /* vblank */
+				mask = LB_Dx_VBLANK_INTERRUPT;
+				event_name = "vblank";
 
-				if (rdev->irq.crtc_vblank_int[4]) {
-					drm_handle_vblank(rdev->ddev, 4);
+				if (rdev->irq.crtc_vblank_int[crtc_idx]) {
+					drm_handle_vblank(rdev->ddev, crtc_idx);
 					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 				}
-				if (atomic_read(&rdev->irq.pflip[4]))
-					radeon_crtc_handle_vblank(rdev, 4);
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D5 vblank\n");
-
-				break;
-			case 1: /* D5 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D5 vline\n");
+				if (atomic_read(&rdev->irq.pflip[crtc_idx])) {
+					radeon_crtc_handle_vblank(rdev,
+								  crtc_idx);
+				}
 
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+			} else if (src_data == 1) { /* vline */
+				mask = LB_Dx_VLINE_INTERRUPT;
+				event_name = "vline";
+			} else {
+				DRM_DEBUG("Unhandled interrupt: %d %d\n",
+					  src_id, src_data);
 				break;
 			}
-			break;
-		case 6: /* D6 vblank/vline */
-			switch (src_data) {
-			case 0: /* D6 vblank */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				if (rdev->irq.crtc_vblank_int[5]) {
-					drm_handle_vblank(rdev->ddev, 5);
-					rdev->pm.vblank_sync = true;
-					wake_up(&rdev->irq.vblank_queue);
-				}
-				if (atomic_read(&rdev->irq.pflip[5]))
-					radeon_crtc_handle_vblank(rdev, 5);
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
-				DRM_DEBUG("IH: D6 vblank\n");
 
-				break;
-			case 1: /* D6 vline */
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+			if (!(disp_int[crtc_idx] & mask)) {
+				DRM_DEBUG("IH: D%d %s - IH event w/o asserted irq bit?\n",
+					  crtc_idx + 1, event_name);
+			}
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
-				DRM_DEBUG("IH: D6 vline\n");
+			disp_int[crtc_idx] &= ~mask;
+			DRM_DEBUG("IH: D%d %s\n", crtc_idx + 1, event_name);
 
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
 			break;
 		case 8: /* D1 page flip */
 		case 10: /* D2 page flip */
@@ -6639,119 +6352,29 @@ int si_irq_process(struct radeon_device *rdev)
 				radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1);
 			break;
 		case 42: /* HPD hotplug */
-			switch (src_data) {
-			case 0:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD1\n");
-
-				break;
-			case 1:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+			if (src_data <= 5) {
+				hpd_idx = src_data;
+				mask = DC_HPDx_INTERRUPT;
 				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD2\n");
+				event_name = "HPD";
 
-				break;
-			case 2:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD3\n");
-
-				break;
-			case 3:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD4\n");
-
-				break;
-			case 4:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD5\n");
-
-				break;
-			case 5:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
-				queue_hotplug = true;
-				DRM_DEBUG("IH: HPD6\n");
-
-				break;
-			case 6:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+			} else if (src_data <= 11) {
+				hpd_idx = src_data - 6;
+				mask = DC_HPDx_RX_INTERRUPT;
 				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 1\n");
-
-				break;
-			case 7:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 2\n");
-
-				break;
-			case 8:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 3\n");
-
-				break;
-			case 9:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 4\n");
-
-				break;
-			case 10:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
-				rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 5\n");
+				event_name = "HPD_RX";
 
+			} else {
+				DRM_DEBUG("Unhandled interrupt: %d %d\n",
+					  src_id, src_data);
 				break;
-			case 11:
-				if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT))
-					DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+			}
 
-				rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
-				queue_dp = true;
-				DRM_DEBUG("IH: HPD_RX 6\n");
+			if (!(disp_int[hpd_idx] & mask))
+				DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
 
-				break;
-			default:
-				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
-				break;
-			}
+			disp_int[hpd_idx] &= ~mask;
+			DRM_DEBUG("IH: %s%d\n", event_name, hpd_idx + 1);
 			break;
 		case 96:
 			DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index 65a911d..0ef68f0 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -47,6 +47,7 @@
 #define SI_MAX_LDS_NUM           0xFFFF
 #define SI_MAX_TCC               16
 #define SI_MAX_TCC_MASK          0xFFFF
+#define SI_MAX_DISP_REGISTERS    6
 
 /* SMC IND accessor regs */
 #define SMC_IND_INDEX_0                              0x200
@@ -820,41 +821,20 @@
 #       define VBLANK_INT_MASK                          (1 << 0)
 #       define VLINE_INT_MASK                           (1 << 4)
 
-#define DISP_INTERRUPT_STATUS                           0x60f4
-#       define LB_D1_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D1_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD1_INTERRUPT                        (1 << 17)
-#       define DC_HPD1_RX_INTERRUPT                     (1 << 18)
+/* 0x60f4, 0x60f8, 0x60fc, 0x6100, 0x614c, 0x6150 */
+#define DISP_INTERRUPT_STATUS(i) \
+	((i < 4) ? 0x60f4 + (0x4 * i) : 0x614c + (0x4 * (i - 4)))
+#       define LB_Dx_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_Dx_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPDx_INTERRUPT                        (1 << 17)
+#       define DC_HPDx_RX_INTERRUPT                     (1 << 18)
+/* First reg only */
 #       define DACA_AUTODETECT_INTERRUPT                (1 << 22)
 #       define DACB_AUTODETECT_INTERRUPT                (1 << 23)
 #       define DC_I2C_SW_DONE_INTERRUPT                 (1 << 24)
 #       define DC_I2C_HW_DONE_INTERRUPT                 (1 << 25)
-#define DISP_INTERRUPT_STATUS_CONTINUE                  0x60f8
-#       define LB_D2_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D2_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD2_INTERRUPT                        (1 << 17)
-#       define DC_HPD2_RX_INTERRUPT                     (1 << 18)
+/* Second reg only */
 #       define DISP_TIMER_INTERRUPT                     (1 << 24)
-#define DISP_INTERRUPT_STATUS_CONTINUE2                 0x60fc
-#       define LB_D3_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D3_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD3_INTERRUPT                        (1 << 17)
-#       define DC_HPD3_RX_INTERRUPT                     (1 << 18)
-#define DISP_INTERRUPT_STATUS_CONTINUE3                 0x6100
-#       define LB_D4_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D4_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD4_INTERRUPT                        (1 << 17)
-#       define DC_HPD4_RX_INTERRUPT                     (1 << 18)
-#define DISP_INTERRUPT_STATUS_CONTINUE4                 0x614c
-#       define LB_D5_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D5_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD5_INTERRUPT                        (1 << 17)
-#       define DC_HPD5_RX_INTERRUPT                     (1 << 18)
-#define DISP_INTERRUPT_STATUS_CONTINUE5                 0x6150
-#       define LB_D6_VLINE_INTERRUPT                    (1 << 2)
-#       define LB_D6_VBLANK_INTERRUPT                   (1 << 3)
-#       define DC_HPD6_INTERRUPT                        (1 << 17)
-#       define DC_HPD6_RX_INTERRUPT                     (1 << 18)
 
 /* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */
 #define GRPH_INT_STATUS                                 0x6858
@@ -867,37 +847,25 @@
 
 #define	DAC_AUTODETECT_INT_CONTROL			0x67c8
 
-#define DC_HPD1_INT_STATUS                              0x601c
-#define DC_HPD2_INT_STATUS                              0x6028
-#define DC_HPD3_INT_STATUS                              0x6034
-#define DC_HPD4_INT_STATUS                              0x6040
-#define DC_HPD5_INT_STATUS                              0x604c
-#define DC_HPD6_INT_STATUS                              0x6058
-#       define DC_HPDx_INT_STATUS                       (1 << 0)
+/* 0x601c, 0x6028, 0x6034, 0x6040, 0x604c, 0x6058 */
+#define DC_HPDx_INT_STATUS(x)                           (0x601c + (0xc * x))
+#       define DC_HPDx_INT_STATUS_MASK                  (1 << 0)
 #       define DC_HPDx_SENSE                            (1 << 1)
 #       define DC_HPDx_RX_INT_STATUS                    (1 << 8)
 
-#define DC_HPD1_INT_CONTROL                             0x6020
-#define DC_HPD2_INT_CONTROL                             0x602c
-#define DC_HPD3_INT_CONTROL                             0x6038
-#define DC_HPD4_INT_CONTROL                             0x6044
-#define DC_HPD5_INT_CONTROL                             0x6050
-#define DC_HPD6_INT_CONTROL                             0x605c
+/* 0x6020, 0x602c, 0x6038, 0x6044, 0x6050, 0x605c */
+#define DC_HPDx_INT_CONTROL(x)                          (0x6020 + (0xc * x))
 #       define DC_HPDx_INT_ACK                          (1 << 0)
 #       define DC_HPDx_INT_POLARITY                     (1 << 8)
 #       define DC_HPDx_INT_EN                           (1 << 16)
 #       define DC_HPDx_RX_INT_ACK                       (1 << 20)
 #       define DC_HPDx_RX_INT_EN                        (1 << 24)
 
-#define DC_HPD1_CONTROL                                   0x6024
-#define DC_HPD2_CONTROL                                   0x6030
-#define DC_HPD3_CONTROL                                   0x603c
-#define DC_HPD4_CONTROL                                   0x6048
-#define DC_HPD5_CONTROL                                   0x6054
-#define DC_HPD6_CONTROL                                   0x6060
-#       define DC_HPDx_CONNECTION_TIMER(x)                ((x) << 0)
-#       define DC_HPDx_RX_INT_TIMER(x)                    ((x) << 16)
-#       define DC_HPDx_EN                                 (1 << 28)
+/* 0x6024, 0x6030, 0x603c, 0x6048, 0x6054, 0x6060 */
+#define DC_HPDx_CONTROL(x)                              (0x6024 + (0xc * x))
+#       define DC_HPDx_CONNECTION_TIMER(x)              ((x) << 0)
+#       define DC_HPDx_RX_INT_TIMER(x)                  ((x) << 16)
+#       define DC_HPDx_EN                               (1 << 28)
 
 #define DPG_PIPE_STUTTER_CONTROL                          0x6cd4
 #       define STUTTER_ENABLE                             (1 << 0)
-- 
2.9.4



More information about the amd-gfx mailing list