From: Dave Airlie <airl...@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 <airl...@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 -- _______________________________________________ Dri-devel mailing list Dri-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/dri-devel