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

drm/amd/display: Add fallback and abort paths for DP link training.

[Why]
When enabling a DisplayPort stream:
- Optionally reducing link bandwidth between failed link training
attempts should progressively relax training requirements.
- Abandoning link training altogether if a sink is unplugged should
avoid unnecessary training attempts.

[How]
- Add fallback parameter to DP link training function and reduce link
bandwidth between failed training attempts as long as stream bandwidth
requirements are met.
- Add training status for sink unplug and abort training when this
status is reported.
Signed-off-by: default avatarJimmy Kizito <Jimmy.Kizito@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarStylon Wang <stylon.wang@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ede4f6da
...@@ -1750,6 +1750,8 @@ static enum dc_status enable_link_dp(struct dc_state *state, ...@@ -1750,6 +1750,8 @@ static enum dc_status enable_link_dp(struct dc_state *state,
bool apply_seamless_boot_optimization = false; bool apply_seamless_boot_optimization = false;
uint32_t bl_oled_enable_delay = 50; // in ms uint32_t bl_oled_enable_delay = 50; // in ms
const uint32_t post_oui_delay = 30; // 30ms const uint32_t post_oui_delay = 30; // 30ms
/* Reduce link bandwidth between failed link training attempts. */
bool do_fallback = false;
// check for seamless boot // check for seamless boot
for (i = 0; i < state->stream_count; i++) { for (i = 0; i < state->stream_count; i++) {
...@@ -1788,7 +1790,8 @@ static enum dc_status enable_link_dp(struct dc_state *state, ...@@ -1788,7 +1790,8 @@ static enum dc_status enable_link_dp(struct dc_state *state,
skip_video_pattern, skip_video_pattern,
LINK_TRAINING_ATTEMPTS, LINK_TRAINING_ATTEMPTS,
pipe_ctx, pipe_ctx,
pipe_ctx->stream->signal)) { pipe_ctx->stream->signal,
do_fallback)) {
link->cur_link_settings = link_settings; link->cur_link_settings = link_settings;
status = DC_OK; status = DC_OK;
} else { } else {
......
...@@ -1701,18 +1701,31 @@ bool perform_link_training_with_retries( ...@@ -1701,18 +1701,31 @@ bool perform_link_training_with_retries(
bool skip_video_pattern, bool skip_video_pattern,
int attempts, int attempts,
struct pipe_ctx *pipe_ctx, struct pipe_ctx *pipe_ctx,
enum signal_type signal) enum signal_type signal,
bool do_fallback)
{ {
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_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link; struct dc_link *link = stream->link;
enum dp_panel_mode panel_mode; enum dp_panel_mode panel_mode;
struct link_encoder *link_enc;
enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
struct dc_link_settings currnet_setting = *link_setting;
/* Dynamically assigned link encoders associated with stream rather than
* link.
*/
if (link->dc->res_pool->funcs->link_encs_assign)
link_enc = stream->link_enc;
else
link_enc = link->link_enc;
ASSERT(link_enc);
/* We need to do this before the link training to ensure the idle pattern in SST /* 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 * mode will be sent right after the link training
*/ */
link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, link_enc->funcs->connect_dig_be_to_fe(link_enc,
pipe_ctx->stream_res.stream_enc->id, true); pipe_ctx->stream_res.stream_enc->id, true);
for (j = 0; j < attempts; ++j) { for (j = 0; j < attempts; ++j) {
...@@ -1724,7 +1737,7 @@ bool perform_link_training_with_retries( ...@@ -1724,7 +1737,7 @@ bool perform_link_training_with_retries(
link, link,
signal, signal,
pipe_ctx->clock_source->id, pipe_ctx->clock_source->id,
link_setting); &currnet_setting);
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;
...@@ -1739,14 +1752,12 @@ bool perform_link_training_with_retries( ...@@ -1739,14 +1752,12 @@ bool perform_link_training_with_retries(
panel_mode != DP_PANEL_MODE_DEFAULT); panel_mode != DP_PANEL_MODE_DEFAULT);
if (link->aux_access_disabled) { if (link->aux_access_disabled) {
dc_link_dp_perform_link_training_skip_aux(link, link_setting); dc_link_dp_perform_link_training_skip_aux(link, &currnet_setting);
return true; return true;
} else { } else {
enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
status = dc_link_dp_perform_link_training( status = dc_link_dp_perform_link_training(
link, link,
link_setting, &currnet_setting,
skip_video_pattern); skip_video_pattern);
if (status == LINK_TRAINING_SUCCESS) if (status == LINK_TRAINING_SUCCESS)
return true; return true;
...@@ -1754,7 +1765,7 @@ bool perform_link_training_with_retries( ...@@ -1754,7 +1765,7 @@ bool perform_link_training_with_retries(
/* latest link training still fail, skip delay and keep PHY on /* latest link training still fail, skip delay and keep PHY on
*/ */
if (j == (attempts - 1)) 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\n",
...@@ -1762,6 +1773,19 @@ bool perform_link_training_with_retries( ...@@ -1762,6 +1773,19 @@ bool perform_link_training_with_retries(
dp_disable_link_phy(link, signal); dp_disable_link_phy(link, signal);
/* Abort link training if failure due to sink being unplugged. */
if (status == LINK_TRAINING_ABORT)
break;
else if (do_fallback) {
decide_fallback_link_setting(*link_setting, &currnet_setting, status);
/* Fail link training if reduced link bandwidth no longer meets
* stream requirements.
*/
if (dc_bandwidth_in_kbps_from_timing(&stream->timing) <
dc_link_bandwidth_kbps(link, &currnet_setting))
break;
}
msleep(delay_between_attempts); msleep(delay_between_attempts);
delay_between_attempts += LINK_TRAINING_RETRY_DELAY; delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
......
...@@ -384,7 +384,8 @@ void dp_retrain_link_dp_test(struct dc_link *link, ...@@ -384,7 +384,8 @@ void dp_retrain_link_dp_test(struct dc_link *link,
skip_video_pattern, skip_video_pattern,
LINK_TRAINING_ATTEMPTS, LINK_TRAINING_ATTEMPTS,
&pipes[i], &pipes[i],
SIGNAL_TYPE_DISPLAY_PORT); SIGNAL_TYPE_DISPLAY_PORT,
false);
link->dc->hwss.enable_stream(&pipes[i]); link->dc->hwss.enable_stream(&pipes[i]);
......
...@@ -65,7 +65,8 @@ bool perform_link_training_with_retries( ...@@ -65,7 +65,8 @@ bool perform_link_training_with_retries(
bool skip_video_pattern, bool skip_video_pattern,
int attempts, int attempts,
struct pipe_ctx *pipe_ctx, struct pipe_ctx *pipe_ctx,
enum signal_type signal); enum signal_type signal,
bool do_fallback);
bool is_mst_supported(struct dc_link *link); bool is_mst_supported(struct dc_link *link);
......
...@@ -68,6 +68,8 @@ enum link_training_result { ...@@ -68,6 +68,8 @@ enum link_training_result {
LINK_TRAINING_LQA_FAIL, LINK_TRAINING_LQA_FAIL,
/* one of the CR,EQ or symbol lock is dropped */ /* one of the CR,EQ or symbol lock is dropped */
LINK_TRAINING_LINK_LOSS, LINK_TRAINING_LINK_LOSS,
/* Abort link training (because sink unplugged) */
LINK_TRAINING_ABORT,
}; };
struct link_training_settings { struct link_training_settings {
......
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