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( ...@@ -1495,7 +1495,6 @@ static enum dc_status enable_link_dp(
bool skip_video_pattern; bool skip_video_pattern;
struct dc_link *link = stream->link; struct dc_link *link = stream->link;
struct dc_link_settings link_settings = {0}; struct dc_link_settings link_settings = {0};
enum dp_panel_mode panel_mode;
bool fec_enable; bool fec_enable;
int i; int i;
bool apply_seamless_boot_optimization = false; bool apply_seamless_boot_optimization = false;
...@@ -1531,40 +1530,17 @@ static enum dc_status enable_link_dp( ...@@ -1531,40 +1530,17 @@ static enum dc_status enable_link_dp(
if (state->clk_mgr && !apply_seamless_boot_optimization) if (state->clk_mgr && !apply_seamless_boot_optimization)
state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false); 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; skip_video_pattern = true;
if (link_settings.link_rate == LINK_RATE_LOW) if (link_settings.link_rate == LINK_RATE_LOW)
skip_video_pattern = false; skip_video_pattern = false;
if (link->aux_access_disabled) { if (perform_link_training_with_retries(
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,
&link_settings, &link_settings,
skip_video_pattern, skip_video_pattern,
LINK_TRAINING_ATTEMPTS)) { LINK_TRAINING_ATTEMPTS,
pipe_ctx,
pipe_ctx->stream->signal)) {
link->cur_link_settings = link_settings; link->cur_link_settings = link_settings;
status = DC_OK; status = DC_OK;
} }
......
...@@ -1433,23 +1433,58 @@ enum link_training_result dc_link_dp_perform_link_training( ...@@ -1433,23 +1433,58 @@ enum link_training_result dc_link_dp_perform_link_training(
} }
bool perform_link_training_with_retries( bool perform_link_training_with_retries(
struct dc_link *link,
const struct dc_link_settings *link_setting, const struct dc_link_settings *link_setting,
bool skip_video_pattern, bool skip_video_pattern,
int attempts) int attempts,
struct pipe_ctx *pipe_ctx,
enum signal_type signal)
{ {
uint8_t j; uint8_t j;
uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY; 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) { 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,
link_setting, link_setting,
skip_video_pattern) == LINK_TRAINING_SUCCESS) skip_video_pattern) == LINK_TRAINING_SUCCESS)
return true; 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); msleep(delay_between_attempts);
delay_between_attempts += LINK_TRAINING_RETRY_DELAY; 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 ...@@ -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), sizeof(hpd_irq_dpcd_data),
"Status: "); "Status: ");
perform_link_training_with_retries(link,
&link->cur_link_settings,
true, LINK_TRAINING_ATTEMPTS);
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link && if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
pipe_ctx->stream->dpms_off == false && break;
pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { }
dc_link_allocate_mst_payload(pipe_ctx);
} 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; status = false;
......
...@@ -333,20 +333,12 @@ void dp_retrain_link_dp_test(struct dc_link *link, ...@@ -333,20 +333,12 @@ void dp_retrain_link_dp_test(struct dc_link *link,
memset(&link->cur_link_settings, 0, memset(&link->cur_link_settings, 0,
sizeof(link->cur_link_settings)); 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( perform_link_training_with_retries(
link,
link_setting, link_setting,
skip_video_pattern, skip_video_pattern,
LINK_TRAINING_ATTEMPTS); LINK_TRAINING_ATTEMPTS,
&pipes[i],
SIGNAL_TYPE_DISPLAY_PORT);
link->dc->hwss.enable_stream(&pipes[i]); link->dc->hwss.enable_stream(&pipes[i]);
......
...@@ -57,10 +57,11 @@ void decide_link_settings( ...@@ -57,10 +57,11 @@ void decide_link_settings(
struct dc_link_settings *link_setting); struct dc_link_settings *link_setting);
bool perform_link_training_with_retries( bool perform_link_training_with_retries(
struct dc_link *link,
const struct dc_link_settings *link_setting, const struct dc_link_settings *link_setting,
bool skip_video_pattern, 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); 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