[PATCH 09/10] drm/radeon: improve encoder picking functions

Dave Airlie airlied at gmail.com
Mon Feb 23 15:24:03 PST 2015


From: Dave Airlie <airlied at redhat.com>

For MST we need to be able to pick front end encoders
separate from backend, but only for MST, so we need to
make the encoder picking interface smarter.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 drivers/gpu/drm/radeon/atombios_encoders.c | 80 +++++++++++++++++++++---------
 drivers/gpu/drm/radeon/radeon_mode.h       |  6 +++
 2 files changed, 63 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index dc55139..e0a9136c 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -2015,7 +2015,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
 	}
 }
 
-static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx)
+{
+	if (enc_idx < 0)
+		return;
+	rdev->mode_info.active_encoders &= ~(1 << enc_idx);
+}
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -2024,71 +2031,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
 	struct drm_encoder *test_encoder;
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 	uint32_t dig_enc_in_use = 0;
+	int enc_idx = -1;
 
+	if (fe_idx >= 0) {
+		enc_idx = fe_idx;
+		goto assigned;
+	}
 	if (ASIC_IS_DCE6(rdev)) {
 		/* DCE6 */
 		switch (radeon_encoder->encoder_id) {
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 			if (dig->linkb)
-				return 1;
+				enc_idx = 1;
 			else
-				return 0;
+				enc_idx = 0;
 			break;
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 			if (dig->linkb)
-				return 3;
+				enc_idx = 3;
 			else
-				return 2;
+				enc_idx = 2;
 			break;
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
 			if (dig->linkb)
-				return 5;
+				enc_idx = 5;
 			else
-				return 4;
+				enc_idx = 4;
 			break;
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
-			return 6;
+			enc_idx = 6;
 			break;
 		}
+		goto assigned;
 	} else if (ASIC_IS_DCE4(rdev)) {
 		/* DCE4/5 */
 		if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
 			/* ontario follows DCE4 */
 			if (rdev->family == CHIP_PALM) {
 				if (dig->linkb)
-					return 1;
+					enc_idx = 1;
 				else
-					return 0;
+					enc_idx = 0;
 			} else
 				/* llano follows DCE3.2 */
-				return radeon_crtc->crtc_id;
+				enc_idx = radeon_crtc->crtc_id;
 		} else {
 			switch (radeon_encoder->encoder_id) {
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 				if (dig->linkb)
-					return 1;
+					enc_idx = 1;
 				else
-					return 0;
+					enc_idx = 0;
 				break;
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 				if (dig->linkb)
-					return 3;
+					enc_idx = 3;
 				else
-					return 2;
+					enc_idx = 2;
 				break;
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
 				if (dig->linkb)
-					return 5;
+					enc_idx = 5;
 				else
-					return 4;
+					enc_idx = 4;
 				break;
 			}
 		}
+		goto assigned;
 	}
 
 	/* on DCE32 and encoder can driver any block so just crtc id */
 	if (ASIC_IS_DCE32(rdev)) {
-		return radeon_crtc->crtc_id;
+		enc_idx = radeon_crtc->crtc_id;
+		goto assigned;
 	}
 
 	/* on DCE3 - LVTMA can only be driven by DIGB */
@@ -2116,6 +2131,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
 	if (!(dig_enc_in_use & 1))
 		return 0;
 	return 1;
+
+assigned:
+	if (enc_idx == -1) {
+		DRM_ERROR("Got encoder index incorrect - returning 0\n");
+		return 0;
+	}
+	if (rdev->mode_info.active_encoders & (1 << enc_idx)) {
+		DRM_ERROR("chosen encoder in use %d\n", enc_idx);
+	}
+	rdev->mode_info.active_encoders |= (1 << enc_idx);
+	return enc_idx;
 }
 
 /* This only needs to be called once at startup */
@@ -2370,7 +2396,7 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
 	     ENCODER_OBJECT_ID_NONE)) {
 		struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 		if (dig) {
-			dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
+			dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1);
 			if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
 				if (rdev->family >= CHIP_R600)
 					dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
@@ -2472,10 +2498,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 
 disable_done:
 	if (radeon_encoder_is_digital(encoder)) {
-		dig = radeon_encoder->enc_priv;
-		dig->dig_encoder = -1;
-	}
-	radeon_encoder->active_device = 0;
+		if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+			if (rdev->asic->display.hdmi_enable)
+				radeon_hdmi_enable(rdev, encoder, false);
+		}
+		if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) {
+			dig = radeon_encoder->enc_priv;
+			radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+			dig->dig_encoder = -1;
+			radeon_encoder->active_device = 0;
+		}
+	} else
+		radeon_encoder->active_device = 0;
 }
 
 /* these are handled by the primary encoders */
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 3d4f390..2cadee2a 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -265,6 +265,9 @@ struct radeon_mode_info {
 	u16 firmware_flags;
 	/* pointer to backlight encoder */
 	struct radeon_encoder *bl_encoder;
+
+	/* bitmask for active encoder frontends */
+	uint32_t active_encoders;
 };
 
 #define RADEON_MAX_BL_LEVEL 0xFF
@@ -945,4 +948,7 @@ void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector
 void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
 
 int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx);
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx);
 #endif
-- 
2.1.0



More information about the dri-devel mailing list