drm/kms/radeon: pick digitial encoders smarter.
Subsystems (2)
Dave Airlie
maintainerPATCH 1/1 drm/kms/radeon: pick digitial encoders smarter.
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.
TODO:
test on W500 hw.
--- drivers/gpu/drm/radeon/radeon_encoders.c | 103 ++++++++++++++++++++---------- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 2 files changed, 70 insertions(+), 34 deletions(-)
drivers/gpu/drm/radeon/radeon_encoders.c +69 -34
@@ -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);
@@ -856,10 +856,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_tswitch (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; }
drivers/gpu/drm/radeon/radeon_mode.h +1 -0
@@ -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 ];
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 --
Quoted 188 lines · Dave Airlie
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.
TODO:
test on W500 hw.Signed-off-by Dave Airlie <[email protected]>---
drivers/gpu/drm/radeon/radeon_encoders.c | 103 ++++++++++++++++++++----------drivers/gpu/drm/radeon/radeon_mode.h| 1 +2 files changed, 70 insertions(+), 34 deletions(-)drivers/gpu/drm/radeon/radeon_encoders.c +20
-0@@ -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(structdrm_device*dev) {drivers/gpu/drm/radeon/radeon_encoders.c +5
-25@@ -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;drivers/gpu/drm/radeon/radeon_encoders.c +1
-4@@ -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;drivers/gpu/drm/radeon/radeon_encoders.c +34
-0@@ -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(structdrm_encoder*encoder, structdrm_display_mode*mode,drivers/gpu/drm/radeon/radeon_encoders.c +8
-1@@ -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; }drivers/gpu/drm/radeon/radeon_mode.h +0
-0
drivers/gpu/drm/radeon/radeon_mode.h struct radeon_encoder { · line 338
Quoted 4 lines
drivers/gpu/drm/radeon/radeon_mode.h +1
-0@@ -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 */
that's not needed. the dig_block is already a member of the atom encoder struct.
Alex
Quoted 7 lines
drivers/gpu/drm/radeon/radeon_mode.h +0
-1/* displayport */ struct radeon_i2c_chan *dp_i2c_bus; u8 dpcd[8]; --1.6.6
Quoted 12 lines
------------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/dri-devel
------------------------------------------------------------------------------
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
--