From 82e02f0a49cee28db7f5c7f222e03ab31527e8be Mon Sep 17 00:00:00 2001 From: Paul Hsieh Date: Fri, 1 Nov 2019 14:41:37 +0800 Subject: [PATCH 4673/4736] drm/amd/display: Reset PHY in link re-training [Why] Link training failed randomly when plugging USB-C display in/out. [How] If link training failed, reset PHY in link re-training. Change-Id: Ic0f8c50e5da346777e96fa73f1137e6c4abef9f2 Signed-off-by: Paul Hsieh Reviewed-by: Wenjing Liu Acked-by: Leo Li --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 31 ++------- .../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(+), 52 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 9f53cbcc7152..1c056a687161 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1529,40 +1529,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.17.1