drm/kms/radeon: pick digitial encoders smarter. (v2)
Subsystems (2)
Dave Airlie
maintainerPATCH 1/1 drm/kms/radeon: pick digitial encoders smarter. (v2)
From: Dave Airlie <[email protected]>
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.
V2: fix silly addition of connector dig_block and cleanup the other places in the code that pick the encoder.
TODO: test on W500 hw.
Signed-off-by Dave Airlie <[email protected]>
--- drivers/gpu/drm/radeon/radeon_encoders.c | 147 ++++++++++++++++-------------- 1 files changed, 80 insertions(+), 67 deletions(-)
drivers/gpu/drm/radeon/radeon_encoders.c +80 -67
@@ -156,6 +156,26 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_treturn 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);
@@ -852,17 +852,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v2.acConfig.fCoherentMode =1 ; } }else { + args.v1.ucConfig =ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL ; +if (dig->dig_block) + args.v1.ucConfig |=ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER ; +else + args.v1.ucConfig |=ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER ; +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) - args.v1.ucConfig |=ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER ; -else - args.v1.ucConfig |=ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER ;if (rdev->flags &RADEON_IS_IGP ) {if (radeon_encoder->pixel_clock >165000 ) {if (dig_connector->igp_lane_info &0x3 )
@@ -881,10 +880,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } }break ; -case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA : -/* Only dig2 encoder can drive LVTMA */ - args.v1.ucConfig |=ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER ; -break ; }if (radeon_encoder->pixel_clock >165000 )
@@ -1052,6 +1047,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)union crtc_sourc_param args;int index =GetIndexIntoMasterTable (COMMAND , SelectCRTC_Source);uint8_t frev, crev; +struct radeon_encoder_atom_dig *dig;memset (&args,0 ,sizeof (args));
@@ -1115,40 +1111,16 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)case ENCODER_OBJECT_ID_INTERNAL_UNIPHY :case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 :case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 : -if (ASIC_IS_DCE32 (rdev)) { -if (radeon_crtc->crtc_id) - args.v2.ucEncoderID =ASIC_INT_DIG2_ENCODER_ID ; -else - args.v2.ucEncoderID =ASIC_INT_DIG1_ENCODER_ID ; - }else { -struct drm_connector *connector; -struct radeon_connector *radeon_connector; -struct radeon_connector_atom_dig *dig_connector; - - connector =radeon_get_connector_for_encoder (encoder); -if (!connector) -return ; - radeon_connector =to_radeon_connector (connector); -if (!radeon_connector->con_priv) -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) - args.v2.ucEncoderID =ASIC_INT_DIG2_ENCODER_ID ; -else - args.v2.ucEncoderID =ASIC_INT_DIG1_ENCODER_ID ; - } +case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA : + dig = radeon_encoder->enc_priv; +if (dig->dig_block) + args.v2.ucEncoderID =ASIC_INT_DIG2_ENCODER_ID ; +else + args.v2.ucEncoderID =ASIC_INT_DIG1_ENCODER_ID ;break ;case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 : args.v2.ucEncoderID =ASIC_INT_DVO_ENCODER_ID ;break ; -case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA : -/* Only dig2 encoder can drive LVTMA */ - args.v2.ucEncoderID =ASIC_INT_DIG2_ENCODER_ID ; -break ;case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 :if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT )) args.v2.ucEncoderID =ASIC_INT_TV_ENCODER_ID ;
@@ -1208,6 +1180,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 +1230,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 +1391,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 +1454,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; }
Signature · 10 lines
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 --