Commit d84c4d19 authored by Jimmy Kizito's avatar Jimmy Kizito Committed by Alex Deucher

drm/amd/display: Update link training fallback behaviour.

[Why]
Some displays may need several link training attempts before
link training succeeds.

[How]
If training succeeds after falling back to lower link bandwidth,
retry at original link bandwidth instead of abandoning link training
whenever link bandwidth is less than stream bandwidth.
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarQingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: default avatarJimmy Kizito <Jimmy.Kizito@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent c4955d9c
...@@ -2783,31 +2783,37 @@ bool perform_link_training_with_retries( ...@@ -2783,31 +2783,37 @@ bool perform_link_training_with_retries(
struct dc_link *link = stream->link; struct dc_link *link = stream->link;
enum dp_panel_mode panel_mode = dp_get_panel_mode(link); enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0; enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
struct dc_link_settings current_setting = *link_setting; struct dc_link_settings cur_link_settings = *link_setting;
const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
int fail_count = 0; int fail_count = 0;
bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
bool is_link_bw_min = /* RBR x 1 */
(cur_link_settings.link_rate <= LINK_RATE_LOW) &&
(cur_link_settings.lane_count <= LANE_COUNT_ONE);
dp_trace_commit_lt_init(link); dp_trace_commit_lt_init(link);
if (dp_get_link_encoding_format(&current_setting) == DP_8b_10b_ENCODING) if (dp_get_link_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
/* We need to do this before the link training to ensure the idle /* 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 * pattern in SST mode will be sent right after the link training
*/ */
link_hwss->setup_stream_encoder(pipe_ctx); link_hwss->setup_stream_encoder(pipe_ctx);
dp_trace_set_lt_start_timestamp(link, false); dp_trace_set_lt_start_timestamp(link, false);
for (j = 0; j < attempts; ++j) { j = 0;
while (j < attempts && fail_count < (attempts * 10)) {
DC_LOG_HW_LINK_TRAINING("%s: Beginning link training attempt %u of %d\n", DC_LOG_HW_LINK_TRAINING("%s: Beginning link training attempt %u of %d @ rate(%d) x lane(%d)\n",
__func__, (unsigned int)j + 1, attempts); __func__, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
cur_link_settings.lane_count);
dp_enable_link_phy( dp_enable_link_phy(
link, link,
&pipe_ctx->link_res, &pipe_ctx->link_res,
signal, signal,
pipe_ctx->clock_source->id, pipe_ctx->clock_source->id,
&current_setting); &cur_link_settings);
if (stream->sink_patches.dppowerup_delay > 0) { if (stream->sink_patches.dppowerup_delay > 0) {
int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
...@@ -2832,30 +2838,30 @@ bool perform_link_training_with_retries( ...@@ -2832,30 +2838,30 @@ bool perform_link_training_with_retries(
dp_set_panel_mode(link, panel_mode); dp_set_panel_mode(link, panel_mode);
if (link->aux_access_disabled) { if (link->aux_access_disabled) {
dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &current_setting); dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
return true; return true;
} else { } else {
/** @todo Consolidate USB4 DP and DPx.x training. */ /** @todo Consolidate USB4 DP and DPx.x training. */
if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
status = dc_link_dpia_perform_link_training(link, status = dc_link_dpia_perform_link_training(link,
&pipe_ctx->link_res, &pipe_ctx->link_res,
&current_setting, &cur_link_settings,
skip_video_pattern); skip_video_pattern);
/* Transmit idle pattern once training successful. */ /* Transmit idle pattern once training successful. */
if (status == LINK_TRAINING_SUCCESS) if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
} else { } else {
status = dc_link_dp_perform_link_training(link, status = dc_link_dp_perform_link_training(link,
&pipe_ctx->link_res, &pipe_ctx->link_res,
&current_setting, &cur_link_settings,
skip_video_pattern); skip_video_pattern);
} }
dp_trace_lt_total_count_increment(link, false); dp_trace_lt_total_count_increment(link, false);
dp_trace_lt_result_update(link, status, false); dp_trace_lt_result_update(link, status, false);
dp_trace_set_lt_end_timestamp(link, false); dp_trace_set_lt_end_timestamp(link, false);
if (status == LINK_TRAINING_SUCCESS) if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
return true; return true;
} }
...@@ -2866,8 +2872,9 @@ bool perform_link_training_with_retries( ...@@ -2866,8 +2872,9 @@ bool perform_link_training_with_retries(
if (j == (attempts - 1) && link->ep_type == DISPLAY_ENDPOINT_PHY) if (j == (attempts - 1) && link->ep_type == DISPLAY_ENDPOINT_PHY)
break; break;
DC_LOG_WARNING("%s: Link training attempt %u of %d failed\n", DC_LOG_WARNING("%s: Link training attempt %u of %d failed @ rate(%d) x lane(%d)\n",
__func__, (unsigned int)j + 1, attempts); __func__, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
cur_link_settings.lane_count);
dp_disable_link_phy(link, &pipe_ctx->link_res, signal); dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
...@@ -2876,27 +2883,49 @@ bool perform_link_training_with_retries( ...@@ -2876,27 +2883,49 @@ bool perform_link_training_with_retries(
enum dc_connection_type type = dc_connection_none; enum dc_connection_type type = dc_connection_none;
dc_link_detect_sink(link, &type); dc_link_detect_sink(link, &type);
if (type == dc_connection_none) if (type == dc_connection_none) {
DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
break; break;
} else if (do_fallback) { }
}
/* Try to train again at original settings if:
* - not falling back between training attempts;
* - aborted previous attempt due to reasons other than sink unplug;
* - successfully trained but at a link rate lower than that required by stream;
* - reached minimum link bandwidth.
*/
if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
(status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
is_link_bw_min) {
j++;
cur_link_settings = *link_setting;
delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
is_link_bw_low = false;
is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
(cur_link_settings.lane_count <= LANE_COUNT_ONE);
} else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
uint32_t req_bw; uint32_t req_bw;
uint32_t link_bw; uint32_t link_bw;
decide_fallback_link_setting(link, *link_setting, &current_setting, status); decide_fallback_link_setting(link, *link_setting, &cur_link_settings, status);
/* Fail link training if reduced link bandwidth no longer meets /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
* stream requirements. * minimum link bandwidth.
*/ */
req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
link_bw = dc_link_bandwidth_kbps(link, &current_setting); link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings);
if (req_bw > link_bw) is_link_bw_low = (req_bw > link_bw);
break; is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
(cur_link_settings.lane_count <= LANE_COUNT_ONE));
if (is_link_bw_low)
DC_LOG_WARNING("%s: Link bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
__func__, req_bw, link_bw);
} }
msleep(delay_between_attempts); msleep(delay_between_attempts);
delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
} }
return false; return false;
} }
......
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