On Thu, Jan 28, 2010 at 2:17 AM, Dave Airlie <airl...@gmail.com> wrote: > 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 */
that's not needed. the dig_block is already a member of the atom encoder struct. Alex > /* 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 > ------------------------------------------------------------------------------ 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