From: Paul Hsieh <paul.hs...@amd.com>

[Why]
Link training failed randomly when plugging USB-C display in/out.

[How]
If link training failed, reset PHY in link re-training.

Signed-off-by: Paul Hsieh <paul.hs...@amd.com>
Reviewed-by: Wenjing Liu <wenjing....@amd.com>
Acked-by: Leo Li <sunpeng...@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc_link.c | 32 ++-------
 .../gpu/drm/amd/display/dc/core/dc_link_dp.c  | 68 +++++++++++++++----
 .../drm/amd/display/dc/core/dc_link_hwss.c    | 14 +---
 .../gpu/drm/amd/display/dc/inc/dc_link_dp.h   |  5 +-
 4 files changed, 66 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index 093f6c808876..5a35395e6060 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -1495,7 +1495,6 @@ static enum dc_status enable_link_dp(
        bool skip_video_pattern;
        struct dc_link *link = stream->link;
        struct dc_link_settings link_settings = {0};
-       enum dp_panel_mode panel_mode;
        bool fec_enable;
        int i;
        bool apply_seamless_boot_optimization = false;
@@ -1531,40 +1530,17 @@ static enum dc_status enable_link_dp(
        if (state->clk_mgr && !apply_seamless_boot_optimization)
                state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, 
false);
 
-       dp_enable_link_phy(
-               link,
-               pipe_ctx->stream->signal,
-               pipe_ctx->clock_source->id,
-               &link_settings);
-
-       if (stream->sink_patches.dppowerup_delay > 0) {
-               int delay_dp_power_up_in_ms = 
stream->sink_patches.dppowerup_delay;
-
-               msleep(delay_dp_power_up_in_ms);
-       }
-
-       panel_mode = dp_get_panel_mode(link);
-       dp_set_panel_mode(link, panel_mode);
-
-       /* We need to do this before the link training to ensure the idle 
pattern in SST
-        * mode will be sent right after the link training */
-       link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
-                                                   
pipe_ctx->stream_res.stream_enc->id, true);
        skip_video_pattern = true;
 
        if (link_settings.link_rate == LINK_RATE_LOW)
                        skip_video_pattern = false;
 
-       if (link->aux_access_disabled) {
-               dc_link_dp_perform_link_training_skip_aux(link, &link_settings);
-
-               link->cur_link_settings = link_settings;
-               status = DC_OK;
-       } else if (perform_link_training_with_retries(
-                       link,
+       if (perform_link_training_with_retries(
                        &link_settings,
                        skip_video_pattern,
-                       LINK_TRAINING_ATTEMPTS)) {
+                       LINK_TRAINING_ATTEMPTS,
+                       pipe_ctx,
+                       pipe_ctx->stream->signal)) {
                link->cur_link_settings = link_settings;
                status = DC_OK;
        }
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index 272261192e82..537b4dee8f22 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -1433,23 +1433,58 @@ enum link_training_result 
dc_link_dp_perform_link_training(
 }
 
 bool perform_link_training_with_retries(
-       struct dc_link *link,
        const struct dc_link_settings *link_setting,
        bool skip_video_pattern,
-       int attempts)
+       int attempts,
+       struct pipe_ctx *pipe_ctx,
+       enum signal_type signal)
 {
        uint8_t j;
        uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
+       enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
 
        for (j = 0; j < attempts; ++j) {
 
-               if (dc_link_dp_perform_link_training(
+               dp_enable_link_phy(
+                       link,
+                       signal,
+                       pipe_ctx->clock_source->id,
+                       link_setting);
+
+               if (stream->sink_patches.dppowerup_delay > 0) {
+                       int delay_dp_power_up_in_ms = 
stream->sink_patches.dppowerup_delay;
+
+                       msleep(delay_dp_power_up_in_ms);
+               }
+
+               dp_set_panel_mode(link, panel_mode);
+
+               /* We need to do this before the link training to ensure the 
idle pattern in SST
+                * mode will be sent right after the link training
+                */
+               link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
+                                                               
pipe_ctx->stream_res.stream_enc->id, true);
+
+               if (link->aux_access_disabled) {
+                       dc_link_dp_perform_link_training_skip_aux(link, 
link_setting);
+                       return true;
+               } else if (dc_link_dp_perform_link_training(
                                link,
                                link_setting,
                                skip_video_pattern) == LINK_TRAINING_SUCCESS)
                        return true;
 
+               /* latest link training still fail, skip delay and keep PHY on
+                */
+               if (j == (attempts - 1))
+                       break;
+
+               dp_disable_link_phy(link, signal);
+
                msleep(delay_between_attempts);
+
                delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
        }
 
@@ -2770,17 +2805,26 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, 
union hpd_irq_data *out_hpd
                                        sizeof(hpd_irq_dpcd_data),
                                        "Status: ");
 
-               perform_link_training_with_retries(link,
-                       &link->cur_link_settings,
-                       true, LINK_TRAINING_ATTEMPTS);
-
                for (i = 0; i < MAX_PIPES; i++) {
                        pipe_ctx = 
&link->dc->current_state->res_ctx.pipe_ctx[i];
-                       if (pipe_ctx && pipe_ctx->stream && 
pipe_ctx->stream->link == link &&
-                                       pipe_ctx->stream->dpms_off == false &&
-                                       pipe_ctx->stream->signal == 
SIGNAL_TYPE_DISPLAY_PORT_MST) {
-                               dc_link_allocate_mst_payload(pipe_ctx);
-                       }
+                       if (pipe_ctx && pipe_ctx->stream && 
pipe_ctx->stream->link == link)
+                               break;
+               }
+
+               if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
+                       return false;
+
+               dp_disable_link_phy(link, pipe_ctx->stream->signal);
+
+               perform_link_training_with_retries(&link->cur_link_settings,
+                       true, LINK_TRAINING_ATTEMPTS,
+                       pipe_ctx,
+                       pipe_ctx->stream->signal);
+
+               if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == 
link &&
+                               pipe_ctx->stream->dpms_off == false &&
+                               pipe_ctx->stream->signal == 
SIGNAL_TYPE_DISPLAY_PORT_MST) {
+                       dc_link_allocate_mst_payload(pipe_ctx);
                }
 
                status = false;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
index 67ce12df23f1..548aac02ca11 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
@@ -333,20 +333,12 @@ void dp_retrain_link_dp_test(struct dc_link *link,
                        memset(&link->cur_link_settings, 0,
                                sizeof(link->cur_link_settings));
 
-                       link->link_enc->funcs->enable_dp_output(
-                                               link->link_enc,
-                                               link_setting,
-                                               pipes[i].clock_source->id);
-                       link->cur_link_settings = *link_setting;
-
-                       dp_receiver_power_ctrl(link, true);
-
                        perform_link_training_with_retries(
-                                       link,
                                        link_setting,
                                        skip_video_pattern,
-                                       LINK_TRAINING_ATTEMPTS);
-
+                                       LINK_TRAINING_ATTEMPTS,
+                                       &pipes[i],
+                                       SIGNAL_TYPE_DISPLAY_PORT);
 
                        link->dc->hwss.enable_stream(&pipes[i]);
 
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h 
b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
index 4879cf54d8f1..6198bccd6199 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
@@ -57,10 +57,11 @@ void decide_link_settings(
        struct dc_link_settings *link_setting);
 
 bool perform_link_training_with_retries(
-       struct dc_link *link,
        const struct dc_link_settings *link_setting,
        bool skip_video_pattern,
-       int attempts);
+       int attempts,
+       struct pipe_ctx *pipe_ctx,
+       enum signal_type signal);
 
 bool is_mst_supported(struct dc_link *link);
 
-- 
2.24.0

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to