]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/gpu/drm/radeon/atombios_dp.c
drm/radeon/kms: fix DP training for DPEncoderService revision bigger than 1.1
[linux-beck.git] / drivers / gpu / drm / radeon / atombios_dp.c
index 8c0f9e36ff8e1ee452db546d6b88611991a518ea..645b84b3d203395b59f35d6a545c0ca488aaedf9 100644 (file)
@@ -627,6 +627,7 @@ struct radeon_dp_link_train_info {
        u8 train_set[4];
        u8 link_status[DP_LINK_STATUS_SIZE];
        u8 tries;
+       bool use_dpencoder;
 };
 
 static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
@@ -646,7 +647,7 @@ static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
        int rtp = 0;
 
        /* set training pattern on the source */
-       if (ASIC_IS_DCE4(dp_info->rdev)) {
+       if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) {
                switch (tp) {
                case DP_TRAINING_PATTERN_1:
                        rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
@@ -706,7 +707,7 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
        radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
 
        /* start training on the source */
-       if (ASIC_IS_DCE4(dp_info->rdev))
+       if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
                atombios_dig_encoder_setup(dp_info->encoder,
                                           ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
        else
@@ -731,7 +732,7 @@ static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info
                              DP_TRAINING_PATTERN_DISABLE);
 
        /* disable the training pattern on the source */
-       if (ASIC_IS_DCE4(dp_info->rdev))
+       if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
                atombios_dig_encoder_setup(dp_info->encoder,
                                           ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
        else
@@ -869,7 +870,8 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
        struct radeon_dp_link_train_info dp_info;
-       u8 tmp;
+       int index;
+       u8 tmp, frev, crev;
 
        if (!radeon_encoder->enc_priv)
                return;
@@ -884,6 +886,18 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
            (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
                return;
 
+       /* DPEncoderService newer than 1.1 can't program properly the
+        * training pattern. When facing such version use the
+        * DIGXEncoderControl (X== 1 | 2)
+        */
+       dp_info.use_dpencoder = true;
+       index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
+       if (atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) {
+               if (crev > 1) {
+                       dp_info.use_dpencoder = false;
+               }
+       }
+
        dp_info.enc_id = 0;
        if (dig->dig_encoder)
                dp_info.enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;