drm/amd/display: Add fallback and abort paths for DP link training.
authorJimmy Kizito <Jimmy.Kizito@amd.com>
Wed, 7 Apr 2021 22:56:19 +0000 (18:56 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 10 May 2021 22:10:00 +0000 (18:10 -0400)
[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: Jimmy Kizito <Jimmy.Kizito@amd.com>
Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Acked-by: Stylon Wang <stylon.wang@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
drivers/gpu/drm/amd/display/include/link_service_types.h

index d040d23..c4405eb 100644 (file)
@@ -1750,6 +1750,8 @@ static enum dc_status enable_link_dp(struct dc_state *state,
        bool apply_seamless_boot_optimization = false;
        uint32_t bl_oled_enable_delay = 50; // in ms
        const uint32_t post_oui_delay = 30; // 30ms
+       /* Reduce link bandwidth between failed link training attempts. */
+       bool do_fallback = false;
 
        // check for seamless boot
        for (i = 0; i < state->stream_count; i++) {
@@ -1788,7 +1790,8 @@ static enum dc_status enable_link_dp(struct dc_state *state,
                                               skip_video_pattern,
                                               LINK_TRAINING_ATTEMPTS,
                                               pipe_ctx,
-                                              pipe_ctx->stream->signal)) {
+                                              pipe_ctx->stream->signal,
+                                              do_fallback)) {
                link->cur_link_settings = link_settings;
                status = DC_OK;
        } else {
index a87613f..dd95d00 100644 (file)
@@ -1701,18 +1701,31 @@ bool perform_link_training_with_retries(
        bool skip_video_pattern,
        int attempts,
        struct pipe_ctx *pipe_ctx,
-       enum signal_type signal)
+       enum signal_type signal,
+       bool do_fallback)
 {
        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;
+       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
         * 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);
 
        for (j = 0; j < attempts; ++j) {
@@ -1724,7 +1737,7 @@ bool perform_link_training_with_retries(
                        link,
                        signal,
                        pipe_ctx->clock_source->id,
-                       link_setting);
+                       &currnet_setting);
 
                if (stream->sink_patches.dppowerup_delay > 0) {
                        int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
@@ -1739,14 +1752,12 @@ bool perform_link_training_with_retries(
                         panel_mode != DP_PANEL_MODE_DEFAULT);
 
                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;
                } else {
-                       enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
-
                                status = dc_link_dp_perform_link_training(
                                                                                link,
-                                                                               link_setting,
+                                                                               &currnet_setting,
                                                                                skip_video_pattern);
                        if (status == LINK_TRAINING_SUCCESS)
                                return true;
@@ -1754,7 +1765,7 @@ bool perform_link_training_with_retries(
 
                /* 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;
 
                DC_LOG_WARNING("%s: Link training attempt %u of %d failed\n",
@@ -1762,6 +1773,19 @@ bool perform_link_training_with_retries(
 
                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);
 
                delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
index b426f87..13c5c4a 100644 (file)
@@ -384,7 +384,8 @@ void dp_retrain_link_dp_test(struct dc_link *link,
                                        skip_video_pattern,
                                        LINK_TRAINING_ATTEMPTS,
                                        &pipes[i],
-                                       SIGNAL_TYPE_DISPLAY_PORT);
+                                       SIGNAL_TYPE_DISPLAY_PORT,
+                                       false);
 
                        link->dc->hwss.enable_stream(&pipes[i]);
 
index 699de64..38e6fbf 100644 (file)
@@ -65,7 +65,8 @@ bool perform_link_training_with_retries(
        bool skip_video_pattern,
        int attempts,
        struct pipe_ctx *pipe_ctx,
-       enum signal_type signal);
+       enum signal_type signal,
+       bool do_fallback);
 
 bool is_mst_supported(struct dc_link *link);
 
index 7392a89..5a250f4 100644 (file)
@@ -68,6 +68,8 @@ enum link_training_result {
        LINK_TRAINING_LQA_FAIL,
        /* one of the CR,EQ or symbol lock is dropped */
        LINK_TRAINING_LINK_LOSS,
+       /* Abort link training (because sink unplugged) */
+       LINK_TRAINING_ABORT,
 };
 
 struct link_training_settings {