Commit 832aa63b authored by Paul Hsieh's avatar Paul Hsieh Committed by Alex Deucher

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.
Signed-off-by: default avatarPaul Hsieh <paul.hsieh@amd.com>
Reviewed-by: default avatarWenjing Liu <Wenjing.Liu@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent a4cea116
......@@ -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;
}
......
......@@ -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;
......
......@@ -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]);
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment