All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dave Airlie <airlied@gmail.com>
To: dri-devel@lists.sf.net
Subject: [PATCH] drm/kms/radeon: pick digitial encoders smarter.
Date: Thu, 28 Jan 2010 17:17:24 +1000	[thread overview]
Message-ID: <1264663044-5664-1-git-send-email-airlied@gmail.com> (raw)

From: Dave Airlie <airlied@redhat.com>

booting a Lenovo W500 with LVDS + DP outputs showed up a TODO we had
on our list, to pick a correct digital encoder block. The LVTMA
encoder requires the second digital encoder, all others can use any
encoder at all.

This fixes the digital encoder selection logic to enable LVDS/DP combos
to work okay.

TODO:
test on W500 hw.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/radeon/radeon_encoders.c |  103 ++++++++++++++++++++----------
 drivers/gpu/drm/radeon/radeon_mode.h     |    1 +
 2 files changed, 70 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 18decfa..9074ad9 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -156,6 +156,26 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t
 	return ret;
 }
 
+static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	switch (radeon_encoder->encoder_id) {
+	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+	case ENCODER_OBJECT_ID_INTERNAL_DDI:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+		return true;
+	default:
+		return false;
+	}
+}
 void
 radeon_link_encoder_connector(struct drm_device *dev)
 {
@@ -679,31 +699,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
 
 	memset(&args, 0, sizeof(args));
 
-	if (ASIC_IS_DCE32(rdev)) {
-		if (dig->dig_block)
-			index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
-		else
-			index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
-		num = dig->dig_block + 1;
-	} else {
-		switch (radeon_encoder->encoder_id) {
-		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-			/* XXX doesn't really matter which dig encoder we pick as long as it's
-			 * not already in use
-			 */
-			if (dig_connector->linkb)
-				index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
-			else
-				index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
-			num = 1;
-			break;
-		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
-			/* Only dig2 encoder can drive LVTMA */
-			index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
-			num = 2;
-			break;
-		}
-	}
+	if (dig->dig_block)
+		index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
+	else
+		index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
+	num = dig->dig_block + 1;
 
 	atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
 
@@ -856,10 +856,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 
 		switch (radeon_encoder->encoder_id) {
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-			/* XXX doesn't really matter which dig encoder we pick as long as it's
-			 * not already in use
-			 */
-			if (dig_connector->linkb)
+			if (dig_connector->dig_block)
 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
 			else
 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
@@ -1133,10 +1130,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
 						return;
 					dig_connector = radeon_connector->con_priv;
 
-					/* XXX doesn't really matter which dig encoder we pick as long as it's
-					 * not already in use
-					 */
-					if (dig_connector->linkb)
+					if (dig_connector->dig_block)
 						args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
 					else
 						args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
@@ -1208,6 +1202,40 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
 	}
 }
 
+static int radeon_atom_pick_dig_block(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct drm_encoder *test_encoder;
+	struct radeon_encoder_atom_dig *dig;
+	uint32_t dig_enc_in_use = 0;
+	/* on DCE32 and encoder can driver any block so just crtc id */
+	if (ASIC_IS_DCE32(rdev))
+		return radeon_crtc->crtc_id;
+
+	/* on DCE3 - LVTMA can only be driven by block 2 */
+	list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
+		if (!radeon_encoder_is_digital(encoder))
+			continue;
+
+		dig = radeon_encoder->enc_priv;
+
+		if ((encoder != test_encoder) && (dig->dig_block >= 0))
+			dig_enc_in_use |= (1 << dig->dig_block);
+	}
+
+	if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) {
+		if (dig_enc_in_use & 0x2)
+			DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n");
+		return 1;
+	}
+	if (!(dig_enc_in_use & 1))
+		return 0;
+	return 1;
+}
+
 static void
 radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
 			     struct drm_display_mode *mode,
@@ -1224,7 +1252,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
 			struct radeon_encoder_atom_dig *dig;
 
 			dig = radeon_encoder->enc_priv;
-			dig->dig_block = radeon_crtc->crtc_id;
+			dig->dig_block = radeon_atom_pick_dig_block(encoder);
 		}
 	}
 	radeon_encoder->pixel_clock = adjusted_mode->clock;
@@ -1385,7 +1413,13 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
 static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 {
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig;
 	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+	if (radeon_encoder_is_digital(encoder)) {
+		dig = radeon_encoder->enc_priv;
+		dig->dig_block = -1;
+	}
 	radeon_encoder->active_device = 0;
 }
 
@@ -1442,6 +1476,7 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
 
 	/* coherent mode by default */
 	dig->coherent_mode = true;
+	dig->dig_block = -1;
 
 	return dig;
 }
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index a1fe11b..e58a654 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -335,6 +335,7 @@ struct radeon_encoder {
 struct radeon_connector_atom_dig {
 	uint32_t igp_lane_info;
 	bool linkb;
+	int dig_block; /* -1 invalid, 0 == DIG1, 1 == DIG2 */
 	/* displayport */
 	struct radeon_i2c_chan *dp_i2c_bus;
 	u8 dpcd[8];
-- 
1.6.6


------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
--

             reply	other threads:[~2010-01-28  7:17 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-28  7:17 Dave Airlie [this message]
2010-01-28  7:31 ` [PATCH] drm/kms/radeon: pick digitial encoders smarter Alex Deucher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1264663044-5664-1-git-send-email-airlied@gmail.com \
    --to=airlied@gmail.com \
    --cc=dri-devel@lists.sf.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.