From 6d567f5f089a66e08432bb2098794ddc204dc0aa Mon Sep 17 00:00:00 2001
From: Alex Deucher <alexander.deucher@amd.com>
Date: Thu, 31 May 2012 14:12:55 -0400
Subject: [PATCH] drm/radeon: apply Murphy's law to the kms hpd irq code

Follow on to Christian's:
drm/radeon: apply Murphy's law to the kms irq code

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/evergreen.c      |   30 ++++++++++++---------
 drivers/gpu/drm/radeon/r100.c           |   14 ++++++---
 drivers/gpu/drm/radeon/r600.c           |   42 +++++++++++++++++--------------
 drivers/gpu/drm/radeon/radeon.h         |    2 +
 drivers/gpu/drm/radeon/radeon_irq_kms.c |   29 +++++++++++++++++++++
 drivers/gpu/drm/radeon/rs600.c          |   14 ++++++---
 6 files changed, 89 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 95fccbf..b78cb5e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -430,33 +430,34 @@ void evergreen_hpd_init(struct radeon_device *rdev)
 	struct drm_connector *connector;
 	u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) |
 		DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN;
+	u32 hpd_mask = 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, tmp);
-			rdev->irq.hpd[0] = true;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
 			WREG32(DC_HPD2_CONTROL, tmp);
-			rdev->irq.hpd[1] = true;
+			hpd_mask |= (1 << 1);
 			break;
 		case RADEON_HPD_3:
 			WREG32(DC_HPD3_CONTROL, tmp);
-			rdev->irq.hpd[2] = true;
+			hpd_mask |= (1 << 2);
 			break;
 		case RADEON_HPD_4:
 			WREG32(DC_HPD4_CONTROL, tmp);
-			rdev->irq.hpd[3] = true;
+			hpd_mask |= (1 << 3);
 			break;
 		case RADEON_HPD_5:
 			WREG32(DC_HPD5_CONTROL, tmp);
-			rdev->irq.hpd[4] = true;
+			hpd_mask |= (1 << 4);
 			break;
 		case RADEON_HPD_6:
 			WREG32(DC_HPD6_CONTROL, tmp);
-			rdev->irq.hpd[5] = true;
+			hpd_mask |= (1 << 5);
 			break;
 		default:
 			break;
@@ -464,45 +465,48 @@ void evergreen_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		evergreen_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void evergreen_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 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);
-			rdev->irq.hpd[0] = false;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
 			WREG32(DC_HPD2_CONTROL, 0);
-			rdev->irq.hpd[1] = false;
+			hpd_mask |= (1 << 1);
 			break;
 		case RADEON_HPD_3:
 			WREG32(DC_HPD3_CONTROL, 0);
-			rdev->irq.hpd[2] = false;
+			hpd_mask |= (1 << 2);
 			break;
 		case RADEON_HPD_4:
 			WREG32(DC_HPD4_CONTROL, 0);
-			rdev->irq.hpd[3] = false;
+			hpd_mask |= (1 << 3);
 			break;
 		case RADEON_HPD_5:
 			WREG32(DC_HPD5_CONTROL, 0);
-			rdev->irq.hpd[4] = false;
+			hpd_mask |= (1 << 4);
 			break;
 		case RADEON_HPD_6:
 			WREG32(DC_HPD6_CONTROL, 0);
-			rdev->irq.hpd[5] = false;
+			hpd_mask |= (1 << 5);
 			break;
 		default:
 			break;
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 /* watermark setup */
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 2587426..9b40363 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -567,15 +567,16 @@ void r100_hpd_init(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 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:
-			rdev->irq.hpd[0] = true;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
-			rdev->irq.hpd[1] = true;
+			hpd_mask |= (1 << 1);
 			break;
 		default:
 			break;
@@ -583,27 +584,30 @@ void r100_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		r100_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void r100_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 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:
-			rdev->irq.hpd[0] = false;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
-			rdev->irq.hpd[1] = false;
+			hpd_mask |= (1 << 1);
 			break;
 		default:
 			break;
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 /*
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 90c6639..4f1ac83 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -709,6 +709,7 @@ void r600_hpd_init(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -729,28 +730,28 @@ void r600_hpd_init(struct radeon_device *rdev)
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HPD1_CONTROL, tmp);
-				rdev->irq.hpd[0] = true;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HPD2_CONTROL, tmp);
-				rdev->irq.hpd[1] = true;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HPD3_CONTROL, tmp);
-				rdev->irq.hpd[2] = true;
+				hpd_mask |= (1 << 2);
 				break;
 			case RADEON_HPD_4:
 				WREG32(DC_HPD4_CONTROL, tmp);
-				rdev->irq.hpd[3] = true;
+				hpd_mask |= (1 << 3);
 				break;
 				/* DCE 3.2 */
 			case RADEON_HPD_5:
 				WREG32(DC_HPD5_CONTROL, tmp);
-				rdev->irq.hpd[4] = true;
+				hpd_mask |= (1 << 4);
 				break;
 			case RADEON_HPD_6:
 				WREG32(DC_HPD6_CONTROL, tmp);
-				rdev->irq.hpd[5] = true;
+				hpd_mask |= (1 << 5);
 				break;
 			default:
 				break;
@@ -759,15 +760,15 @@ void r600_hpd_init(struct radeon_device *rdev)
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-				rdev->irq.hpd[0] = true;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HOT_PLUG_DETECT2_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-				rdev->irq.hpd[1] = true;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HOT_PLUG_DETECT3_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-				rdev->irq.hpd[2] = true;
+				hpd_mask |= (1 << 2);
 				break;
 			default:
 				break;
@@ -776,13 +777,14 @@ void r600_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		r600_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void r600_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	if (ASIC_IS_DCE3(rdev)) {
 		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -790,28 +792,28 @@ void r600_hpd_fini(struct radeon_device *rdev)
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HPD1_CONTROL, 0);
-				rdev->irq.hpd[0] = false;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HPD2_CONTROL, 0);
-				rdev->irq.hpd[1] = false;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HPD3_CONTROL, 0);
-				rdev->irq.hpd[2] = false;
+				hpd_mask |= (1 << 2);
 				break;
 			case RADEON_HPD_4:
 				WREG32(DC_HPD4_CONTROL, 0);
-				rdev->irq.hpd[3] = false;
+				hpd_mask |= (1 << 3);
 				break;
 				/* DCE 3.2 */
 			case RADEON_HPD_5:
 				WREG32(DC_HPD5_CONTROL, 0);
-				rdev->irq.hpd[4] = false;
+				hpd_mask |= (1 << 4);
 				break;
 			case RADEON_HPD_6:
 				WREG32(DC_HPD6_CONTROL, 0);
-				rdev->irq.hpd[5] = false;
+				hpd_mask |= (1 << 5);
 				break;
 			default:
 				break;
@@ -823,21 +825,23 @@ void r600_hpd_fini(struct radeon_device *rdev)
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HOT_PLUG_DETECT1_CONTROL, 0);
-				rdev->irq.hpd[0] = false;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HOT_PLUG_DETECT2_CONTROL, 0);
-				rdev->irq.hpd[1] = false;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HOT_PLUG_DETECT3_CONTROL, 0);
-				rdev->irq.hpd[2] = false;
+				hpd_mask |= (1 << 2);
 				break;
 			default:
 				break;
 			}
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 /*
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 54eea81..3dd9b59 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -634,6 +634,8 @@ void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc);
 void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
 void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block);
 void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block);
+void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, u32 hpd_mask);
+void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, u32 hpd_mask);
 int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev);
 
 /*
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 11fc4f7..8f9ee4a 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -298,6 +298,35 @@ void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block)
 	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
+void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, u32 hpd_mask)
+{
+	unsigned long irqflags;
+	int i;
+
+	spin_lock_irqsave(&rdev->irq.lock, irqflags);
+	for (i = 0; i < RADEON_MAX_HPD_PINS; i++) {
+		if (hpd_mask & (1 << i))
+			rdev->irq.hpd[i] = true;
+	}
+	radeon_irq_set(rdev);
+	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+
+}
+
+void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, u32 hpd_mask)
+{
+	unsigned long irqflags;
+	int i;
+
+	spin_lock_irqsave(&rdev->irq.lock, irqflags);
+	for (i = 0; i < RADEON_MAX_HPD_PINS; i++) {
+		if (hpd_mask & (1 << i))
+			rdev->irq.hpd[i] = false;
+	}
+	radeon_irq_set(rdev);
+	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+}
+
 int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev)
 {
 	unsigned long irqflags;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 4e9c41a..3c8cd95 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -294,6 +294,7 @@ void rs600_hpd_init(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -301,12 +302,12 @@ void rs600_hpd_init(struct radeon_device *rdev)
 		case RADEON_HPD_1:
 			WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
 			       S_007D00_DC_HOT_PLUG_DETECT1_EN(1));
-			rdev->irq.hpd[0] = true;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
 			WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
 			       S_007D10_DC_HOT_PLUG_DETECT2_EN(1));
-			rdev->irq.hpd[1] = true;
+			hpd_mask |= (1 << 0);
 			break;
 		default:
 			break;
@@ -314,13 +315,14 @@ void rs600_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		rs600_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void rs600_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -328,17 +330,19 @@ void rs600_hpd_fini(struct radeon_device *rdev)
 		case RADEON_HPD_1:
 			WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
 			       S_007D00_DC_HOT_PLUG_DETECT1_EN(0));
-			rdev->irq.hpd[0] = false;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
 			WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
 			       S_007D10_DC_HOT_PLUG_DETECT2_EN(0));
-			rdev->irq.hpd[1] = false;
+			hpd_mask |= (1 << 1);
 			break;
 		default:
 			break;
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 int rs600_asic_reset(struct radeon_device *rdev)
-- 
1.7.7.5

