aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3010-drm-amd-display-Add-ability-to-set-preferred-link-tr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3010-drm-amd-display-Add-ability-to-set-preferred-link-tr.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3010-drm-amd-display-Add-ability-to-set-preferred-link-tr.patch895
1 files changed, 895 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3010-drm-amd-display-Add-ability-to-set-preferred-link-tr.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3010-drm-amd-display-Add-ability-to-set-preferred-link-tr.patch
new file mode 100644
index 00000000..8793efd1
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3010-drm-amd-display-Add-ability-to-set-preferred-link-tr.patch
@@ -0,0 +1,895 @@
+From df04ab320b7ac0e0cd458b824c84553e88d7bff7 Mon Sep 17 00:00:00 2001
+From: David Galiffi <David.Galiffi@amd.com>
+Date: Thu, 30 May 2019 11:56:39 -0400
+Subject: [PATCH 3010/4256] drm/amd/display: Add ability to set preferred link
+ training parameters.
+
+[WHY]
+To add support for OS requirement to set preferred link training
+parameters.
+
+[HOW]
+Create new structure of dp link training overrides. During link training
+processes, these values should be used instead of the default training
+parameters.
+
+Signed-off-by: David Galiffi <David.Galiffi@amd.com>
+Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
+Acked-by: Anthony Koo <Anthony.Koo@amd.com>
+Acked-by: Leo Li <sunpeng.li@amd.com>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 46 ++-
+ .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 337 +++++++++++++-----
+ .../drm/amd/display/dc/core/dc_link_hwss.c | 28 +-
+ drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 21 ++
+ drivers/gpu/drm/amd/display/dc/dc_link.h | 11 +
+ .../gpu/drm/amd/display/dc/inc/link_hwss.h | 2 +-
+ .../amd/display/include/link_service_types.h | 17 +-
+ 7 files changed, 338 insertions(+), 124 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+index dbc925273512..accd0f72e03f 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+@@ -1187,6 +1187,9 @@ static bool construct(
+ link->ctx = dc_ctx;
+ link->link_index = init_params->link_index;
+
++ memset(&link->preferred_training_settings, 0, sizeof(struct dc_link_training_overrides));
++ memset(&link->preferred_link_setting, 0, sizeof(struct dc_link_settings));
++
+ link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index);
+
+ if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
+@@ -1465,6 +1468,9 @@ static enum dc_status enable_link_dp(
+ struct dc_link *link = stream->link;
+ struct dc_link_settings link_settings = {0};
+ enum dp_panel_mode panel_mode;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ bool fec_enable;
++#endif
+
+ /* get link settings for video mode timing */
+ decide_link_settings(stream, &link_settings);
+@@ -1509,10 +1515,20 @@ static enum dc_status enable_link_dp(
+ skip_video_pattern = false;
+
+ #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+- dp_set_fec_ready(link, true);
++ if (link->preferred_training_settings.fec_enable != NULL)
++ fec_enable = *link->preferred_training_settings.fec_enable;
++ else
++ fec_enable = true;
++
++ dp_set_fec_ready(link, fec_enable);
+ #endif
+
+- if (perform_link_training_with_retries(
++ 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,
+ &link_settings,
+ skip_video_pattern,
+@@ -1524,7 +1540,7 @@ static enum dc_status enable_link_dp(
+ status = DC_FAIL_DP_LINK_TRAINING;
+
+ #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+- dp_set_fec_enable(link, true);
++ dp_set_fec_enable(link, fec_enable);
+ #endif
+ return status;
+ }
+@@ -3012,6 +3028,29 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
+ dp_retrain_link_dp_test(link, &store_settings, false);
+ }
+
++void dc_link_set_preferred_training_settings(struct dc *dc,
++ struct dc_link_settings *link_setting,
++ struct dc_link_training_overrides *lt_overrides,
++ struct dc_link *link,
++ bool skip_immediate_retrain)
++{
++ if (lt_overrides != NULL)
++ link->preferred_training_settings = *lt_overrides;
++ else
++ memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
++
++ if (link_setting != NULL) {
++ link->preferred_link_setting = *link_setting;
++ } else {
++ link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
++ link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
++ }
++
++ /* Retrain now, or wait until next stream update to apply */
++ if (skip_immediate_retrain == false)
++ dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
++}
++
+ void dc_link_enable_hpd(const struct dc_link *link)
+ {
+ dc_link_dp_enable_hpd(link);
+@@ -3022,7 +3061,6 @@ void dc_link_disable_hpd(const struct dc_link *link)
+ dc_link_dp_disable_hpd(link);
+ }
+
+-
+ void dc_link_set_test_pattern(struct dc_link *link,
+ enum dp_test_pattern test_pattern,
+ const struct link_training_settings *p_link_settings,
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+index 056be4c34a98..3f8a8f61cd76 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+@@ -49,7 +49,7 @@ static struct dc_link_settings get_common_supported_link_settings(
+ struct dc_link_settings link_setting_a,
+ struct dc_link_settings link_setting_b);
+
+-static void wait_for_training_aux_rd_interval(
++static uint32_t get_training_aux_rd_interval(
+ struct dc_link *link,
+ uint32_t default_wait_in_micro_secs)
+ {
+@@ -68,15 +68,21 @@ static void wait_for_training_aux_rd_interval(
+ sizeof(training_rd_interval));
+
+ if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
+- default_wait_in_micro_secs =
+- training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
++ default_wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
+ }
+
+- udelay(default_wait_in_micro_secs);
++ return default_wait_in_micro_secs;
++}
++
++static void wait_for_training_aux_rd_interval(
++ struct dc_link *link,
++ uint32_t wait_in_micro_secs)
++{
++ udelay(wait_in_micro_secs);
+
+ DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
+ __func__,
+- default_wait_in_micro_secs);
++ wait_in_micro_secs);
+ }
+
+ static void dpcd_set_training_pattern(
+@@ -95,27 +101,27 @@ static void dpcd_set_training_pattern(
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+ }
+
+-static enum hw_dp_training_pattern get_supported_tp(struct dc_link *link)
++static enum dc_dp_training_pattern get_supported_tp(struct dc_link *link)
+ {
+- enum hw_dp_training_pattern highest_tp = HW_DP_TRAINING_PATTERN_2;
++ enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_2;
+ struct encoder_feature_support *features = &link->link_enc->features;
+ struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
+
+ if (features->flags.bits.IS_TPS3_CAPABLE)
+- highest_tp = HW_DP_TRAINING_PATTERN_3;
++ highest_tp = DP_TRAINING_PATTERN_SEQUENCE_3;
+
+ if (features->flags.bits.IS_TPS4_CAPABLE)
+- highest_tp = HW_DP_TRAINING_PATTERN_4;
++ highest_tp = DP_TRAINING_PATTERN_SEQUENCE_4;
+
+ if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED &&
+- highest_tp >= HW_DP_TRAINING_PATTERN_4)
+- return HW_DP_TRAINING_PATTERN_4;
++ highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_4)
++ return DP_TRAINING_PATTERN_SEQUENCE_4;
+
+ if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED &&
+- highest_tp >= HW_DP_TRAINING_PATTERN_3)
+- return HW_DP_TRAINING_PATTERN_3;
++ highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_3)
++ return DP_TRAINING_PATTERN_SEQUENCE_3;
+
+- return HW_DP_TRAINING_PATTERN_2;
++ return DP_TRAINING_PATTERN_SEQUENCE_2;
+ }
+
+ static void dpcd_set_link_settings(
+@@ -126,7 +132,7 @@ static void dpcd_set_link_settings(
+
+ union down_spread_ctrl downspread = { {0} };
+ union lane_count_set lane_count_set = { {0} };
+- enum hw_dp_training_pattern hw_tr_pattern;
++ enum dc_dp_training_pattern dp_tr_pattern;
+
+ downspread.raw = (uint8_t)
+ (lt_settings->link_settings.link_spread);
+@@ -134,21 +140,21 @@ static void dpcd_set_link_settings(
+ lane_count_set.bits.LANE_COUNT_SET =
+ lt_settings->link_settings.lane_count;
+
+- lane_count_set.bits.ENHANCED_FRAMING = 1;
+-
++ lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+- hw_tr_pattern = get_supported_tp(link);
+- if (hw_tr_pattern != HW_DP_TRAINING_PATTERN_4) {
++ dp_tr_pattern = get_supported_tp(link);
++
++ if (dp_tr_pattern != DP_TRAINING_PATTERN_SEQUENCE_4) {
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
+ link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
+ }
+
+ core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
+- &downspread.raw, sizeof(downspread));
++ &downspread.raw, sizeof(downspread));
+
+ core_link_write_dpcd(link, DP_LANE_COUNT_SET,
+- &lane_count_set.raw, 1);
++ &lane_count_set.raw, 1);
+
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
+ lt_settings->link_settings.use_link_rate_set == true) {
+@@ -162,46 +168,47 @@ static void dpcd_set_link_settings(
+ }
+
+ if (rate) {
+- DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n",
++ DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+ __func__,
+ DP_LINK_BW_SET,
+ lt_settings->link_settings.link_rate,
+ DP_LANE_COUNT_SET,
+ lt_settings->link_settings.lane_count,
++ lt_settings->enhanced_framing,
+ DP_DOWNSPREAD_CTRL,
+ lt_settings->link_settings.link_spread);
+ } else {
+- DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x\n %x spread = %x\n",
++ DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+ __func__,
+ DP_LINK_RATE_SET,
+ lt_settings->link_settings.link_rate_set,
+ DP_LANE_COUNT_SET,
+ lt_settings->link_settings.lane_count,
++ lt_settings->enhanced_framing,
+ DP_DOWNSPREAD_CTRL,
+ lt_settings->link_settings.link_spread);
+ }
+-
+ }
+
+ static enum dpcd_training_patterns
+- hw_training_pattern_to_dpcd_training_pattern(
++ dc_dp_training_pattern_to_dpcd_training_pattern(
+ struct dc_link *link,
+- enum hw_dp_training_pattern pattern)
++ enum dc_dp_training_pattern pattern)
+ {
+ enum dpcd_training_patterns dpcd_tr_pattern =
+ DPCD_TRAINING_PATTERN_VIDEOIDLE;
+
+ switch (pattern) {
+- case HW_DP_TRAINING_PATTERN_1:
++ case DP_TRAINING_PATTERN_SEQUENCE_1:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
+ break;
+- case HW_DP_TRAINING_PATTERN_2:
++ case DP_TRAINING_PATTERN_SEQUENCE_2:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
+ break;
+- case HW_DP_TRAINING_PATTERN_3:
++ case DP_TRAINING_PATTERN_SEQUENCE_3:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
+ break;
+- case HW_DP_TRAINING_PATTERN_4:
++ case DP_TRAINING_PATTERN_SEQUENCE_4:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
+ break;
+ default:
+@@ -212,13 +219,12 @@ static enum dpcd_training_patterns
+ }
+
+ return dpcd_tr_pattern;
+-
+ }
+
+ static void dpcd_set_lt_pattern_and_lane_settings(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings,
+- enum hw_dp_training_pattern pattern)
++ enum dc_dp_training_pattern pattern)
+ {
+ union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } };
+ const uint32_t dpcd_base_lt_offset =
+@@ -233,7 +239,7 @@ static void dpcd_set_lt_pattern_and_lane_settings(
+ * DpcdAddress_TrainingPatternSet
+ *****************************************************************/
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
+- hw_training_pattern_to_dpcd_training_pattern(link, pattern);
++ dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
+
+ dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset]
+ = dpcd_pattern.raw;
+@@ -346,12 +352,20 @@ static void update_drive_settings(
+ {
+ uint32_t lane;
+ for (lane = 0; lane < src.link_settings.lane_count; lane++) {
+- dest->lane_settings[lane].VOLTAGE_SWING =
+- src.lane_settings[lane].VOLTAGE_SWING;
+- dest->lane_settings[lane].PRE_EMPHASIS =
+- src.lane_settings[lane].PRE_EMPHASIS;
+- dest->lane_settings[lane].POST_CURSOR2 =
+- src.lane_settings[lane].POST_CURSOR2;
++ if (dest->voltage_swing == NULL)
++ dest->lane_settings[lane].VOLTAGE_SWING = src.lane_settings[lane].VOLTAGE_SWING;
++ else
++ dest->lane_settings[lane].VOLTAGE_SWING = *dest->voltage_swing;
++
++ if (dest->pre_emphasis == NULL)
++ dest->lane_settings[lane].PRE_EMPHASIS = src.lane_settings[lane].PRE_EMPHASIS;
++ else
++ dest->lane_settings[lane].PRE_EMPHASIS = *dest->pre_emphasis;
++
++ if (dest->post_cursor2 == NULL)
++ dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2;
++ else
++ dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2;
+ }
+ }
+
+@@ -754,15 +768,15 @@ static enum link_training_result perform_channel_equalization_sequence(
+ struct link_training_settings *lt_settings)
+ {
+ struct link_training_settings req_settings;
+- enum hw_dp_training_pattern hw_tr_pattern;
++ enum dc_dp_training_pattern tr_pattern;
+ uint32_t retries_ch_eq;
+ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+ union lane_align_status_updated dpcd_lane_status_updated = { {0} };
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
+
+- hw_tr_pattern = get_supported_tp(link);
++ tr_pattern = lt_settings->pattern_for_eq;
+
+- dp_set_hw_training_pattern(link, hw_tr_pattern);
++ dp_set_hw_training_pattern(link, tr_pattern);
+
+ for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
+ retries_ch_eq++) {
+@@ -776,12 +790,12 @@ static enum link_training_result perform_channel_equalization_sequence(
+ dpcd_set_lt_pattern_and_lane_settings(
+ link,
+ lt_settings,
+- hw_tr_pattern);
++ tr_pattern);
+ else
+ dpcd_set_lane_settings(link, lt_settings);
+
+ /* 3. wait for receiver to lock-on*/
+- wait_for_training_aux_rd_interval(link, 400);
++ wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time);
+
+ /* 4. Read lane status and requested
+ * drive settings as set by the sink*/
+@@ -817,27 +831,16 @@ static enum link_training_result perform_clock_recovery_sequence(
+ {
+ uint32_t retries_cr;
+ uint32_t retry_count;
+- uint32_t lane;
+ struct link_training_settings req_settings;
+- enum dc_lane_count lane_count =
+- lt_settings->link_settings.lane_count;
+- enum hw_dp_training_pattern hw_tr_pattern = HW_DP_TRAINING_PATTERN_1;
++ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
++ enum dc_dp_training_pattern tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
+ union lane_align_status_updated dpcd_lane_status_updated;
+
+ retries_cr = 0;
+ retry_count = 0;
+- /* initial drive setting (VS/PE/PC2)*/
+- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+- lt_settings->lane_settings[lane].VOLTAGE_SWING =
+- VOLTAGE_SWING_LEVEL0;
+- lt_settings->lane_settings[lane].PRE_EMPHASIS =
+- PRE_EMPHASIS_DISABLED;
+- lt_settings->lane_settings[lane].POST_CURSOR2 =
+- POST_CURSOR2_DISABLED;
+- }
+
+- dp_set_hw_training_pattern(link, hw_tr_pattern);
++ dp_set_hw_training_pattern(link, tr_pattern);
+
+ /* najeeb - The synaptics MST hub can put the LT in
+ * infinite loop by switching the VS
+@@ -845,7 +848,7 @@ static enum link_training_result perform_clock_recovery_sequence(
+ /* between level 0 and level 1 continuously, here
+ * we try for CR lock for LinkTrainingMaxCRRetry count*/
+ while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
+- (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
++ (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
+ memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
+ memset(&dpcd_lane_status_updated, '\0',
+@@ -863,7 +866,7 @@ static enum link_training_result perform_clock_recovery_sequence(
+ dpcd_set_lt_pattern_and_lane_settings(
+ link,
+ lt_settings,
+- hw_tr_pattern);
++ tr_pattern);
+ else
+ dpcd_set_lane_settings(
+ link,
+@@ -872,7 +875,7 @@ static enum link_training_result perform_clock_recovery_sequence(
+ /* 3. wait receiver to lock-on*/
+ wait_for_training_aux_rd_interval(
+ link,
+- 100);
++ lt_settings->cr_pattern_time);
+
+ /* 4. Read lane status and requested drive
+ * settings as set by the sink
+@@ -939,7 +942,7 @@ static inline enum link_training_result perform_link_training_int(
+ * TPS4 must be used instead of POST_LT_ADJ_REQ.
+ */
+ if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
+- get_supported_tp(link) == HW_DP_TRAINING_PATTERN_4)
++ get_supported_tp(link) == DP_TRAINING_PATTERN_SEQUENCE_4)
+ return status;
+
+ if (status == LINK_TRAINING_SUCCESS &&
+@@ -947,7 +950,7 @@ static inline enum link_training_result perform_link_training_int(
+ status = LINK_TRAINING_LQA_FAIL;
+
+ lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
+- lane_count_set.bits.ENHANCED_FRAMING = 1;
++ lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+ core_link_write_dpcd(
+@@ -959,24 +962,28 @@ static inline enum link_training_result perform_link_training_int(
+ return status;
+ }
+
+-enum link_training_result dc_link_dp_perform_link_training(
+- struct dc_link *link,
++static void initialize_training_settings(
++ struct dc_link *link,
+ const struct dc_link_settings *link_setting,
+- bool skip_video_pattern)
++ struct link_training_settings *lt_settings)
+ {
+- enum link_training_result status = LINK_TRAINING_SUCCESS;
++ uint32_t lane;
+
+- char *link_rate = "Unknown";
+- char *lt_result = "Unknown";
++ memset(lt_settings, '\0', sizeof(struct link_training_settings));
+
+- struct link_training_settings lt_settings;
++ /* Initialize link settings */
++ lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
++ lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
+
+- memset(&lt_settings, '\0', sizeof(lt_settings));
++ if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
++ lt_settings->link_settings.link_rate = link->preferred_link_setting.link_rate;
++ else
++ lt_settings->link_settings.link_rate = link_setting->link_rate;
+
+- lt_settings.link_settings.link_rate = link_setting->link_rate;
+- lt_settings.link_settings.lane_count = link_setting->lane_count;
+- lt_settings.link_settings.use_link_rate_set = link_setting->use_link_rate_set;
+- lt_settings.link_settings.link_rate_set = link_setting->link_rate_set;
++ if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN)
++ lt_settings->link_settings.lane_count = link->preferred_link_setting.lane_count;
++ else
++ lt_settings->link_settings.lane_count = link_setting->lane_count;
+
+ /*@todo[vdevulap] move SS to LS, should not be handled by displaypath*/
+
+@@ -987,31 +994,75 @@ enum link_training_result dc_link_dp_perform_link_training(
+ * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
+ * LINK_SPREAD_DISABLED;
+ */
++ /* Initialize link spread */
+ if (link->dp_ss_off)
+- lt_settings.link_settings.link_spread = LINK_SPREAD_DISABLED;
++ lt_settings->link_settings.link_spread = LINK_SPREAD_DISABLED;
++ else if (link->preferred_training_settings.downspread != NULL)
++ lt_settings->link_settings.link_spread
++ = *link->preferred_training_settings.downspread
++ ? LINK_SPREAD_05_DOWNSPREAD_30KHZ
++ : LINK_SPREAD_DISABLED;
+ else
+- lt_settings.link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
++ lt_settings->link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+
+- /* 1. set link rate, lane count and spread*/
+- dpcd_set_link_settings(link, &lt_settings);
++ /* Initialize lane settings overrides */
++ if (link->preferred_training_settings.voltage_swing != NULL)
++ lt_settings->voltage_swing = link->preferred_training_settings.voltage_swing;
+
+- /* 2. perform link training (set link training done
+- * to false is done as well)*/
+- status = perform_clock_recovery_sequence(link, &lt_settings);
+- if (status == LINK_TRAINING_SUCCESS) {
+- status = perform_channel_equalization_sequence(link,
+- &lt_settings);
+- }
++ if (link->preferred_training_settings.pre_emphasis != NULL)
++ lt_settings->pre_emphasis = link->preferred_training_settings.pre_emphasis;
+
+- if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
+- status = perform_link_training_int(link,
+- &lt_settings,
+- status);
++ if (link->preferred_training_settings.post_cursor2 != NULL)
++ lt_settings->post_cursor2 = link->preferred_training_settings.post_cursor2;
++
++ /* Initialize lane settings (VS/PE/PC2) */
++ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
++ lt_settings->lane_settings[lane].VOLTAGE_SWING =
++ lt_settings->voltage_swing != NULL ?
++ *lt_settings->voltage_swing :
++ VOLTAGE_SWING_LEVEL0;
++ lt_settings->lane_settings[lane].PRE_EMPHASIS =
++ lt_settings->pre_emphasis != NULL ?
++ *lt_settings->pre_emphasis
++ : PRE_EMPHASIS_DISABLED;
++ lt_settings->lane_settings[lane].POST_CURSOR2 =
++ lt_settings->post_cursor2 != NULL ?
++ *lt_settings->post_cursor2
++ : POST_CURSOR2_DISABLED;
+ }
+
+- /* 6. print status message*/
+- switch (lt_settings.link_settings.link_rate) {
++ /* Initialize training timings */
++ if (link->preferred_training_settings.cr_pattern_time != NULL)
++ lt_settings->cr_pattern_time = *link->preferred_training_settings.cr_pattern_time;
++ else
++ lt_settings->cr_pattern_time = get_training_aux_rd_interval(link, 100);
++
++ if (link->preferred_training_settings.eq_pattern_time != NULL)
++ lt_settings->eq_pattern_time = *link->preferred_training_settings.eq_pattern_time;
++ else
++ lt_settings->eq_pattern_time = get_training_aux_rd_interval(link, 400);
++
++ if (link->preferred_training_settings.pattern_for_eq != NULL)
++ lt_settings->pattern_for_eq = *link->preferred_training_settings.pattern_for_eq;
++ else
++ lt_settings->pattern_for_eq = get_supported_tp(link);
++
++ if (link->preferred_training_settings.enhanced_framing != NULL)
++ lt_settings->enhanced_framing = *link->preferred_training_settings.enhanced_framing;
++ else
++ lt_settings->enhanced_framing = 1;
++}
++
++static void print_status_message(
++ struct dc_link *link,
++ const struct link_training_settings *lt_settings,
++ enum link_training_result status)
++{
++ char *link_rate = "Unknown";
++ char *lt_result = "Unknown";
++ char *lt_spread = "Disabled";
+
++ switch (lt_settings->link_settings.link_rate) {
+ case LINK_RATE_LOW:
+ link_rate = "RBR";
+ break;
+@@ -1057,13 +1108,102 @@ enum link_training_result dc_link_dp_perform_link_training(
+ break;
+ }
+
++ switch (lt_settings->link_settings.link_spread) {
++ case LINK_SPREAD_DISABLED:
++ lt_spread = "Disabled";
++ break;
++ case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
++ lt_spread = "0.5% 30KHz";
++ break;
++ case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
++ lt_spread = "0.5% 33KHz";
++ break;
++ default:
++ break;
++ }
++
+ /* Connectivity log: link training */
+- CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d",
+- link_rate,
+- lt_settings.link_settings.lane_count,
+- lt_result,
+- lt_settings.lane_settings[0].VOLTAGE_SWING,
+- lt_settings.lane_settings[0].PRE_EMPHASIS);
++ CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
++ link_rate,
++ lt_settings->link_settings.lane_count,
++ lt_result,
++ lt_settings->lane_settings[0].VOLTAGE_SWING,
++ lt_settings->lane_settings[0].PRE_EMPHASIS,
++ lt_spread);
++}
++
++bool dc_link_dp_perform_link_training_skip_aux(
++ struct dc_link *link,
++ const struct dc_link_settings *link_setting)
++{
++ struct link_training_settings lt_settings;
++ enum dc_dp_training_pattern pattern_for_cr = DP_TRAINING_PATTERN_SEQUENCE_1;
++
++ initialize_training_settings(link, link_setting, &lt_settings);
++
++ /* 1. Perform_clock_recovery_sequence. */
++
++ /* transmit training pattern for clock recovery */
++ dp_set_hw_training_pattern(link, pattern_for_cr);
++
++ /* call HWSS to set lane settings*/
++ dp_set_hw_lane_settings(link, &lt_settings);
++
++ /* wait receiver to lock-on*/
++ wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
++
++ /* 2. Perform_channel_equalization_sequence. */
++
++ /* transmit training pattern for channel equalization. */
++ dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq);
++
++ /* call HWSS to set lane settings*/
++ dp_set_hw_lane_settings(link, &lt_settings);
++
++ /* wait receiver to lock-on. */
++ wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
++
++ /* 3. Perform_link_training_int. */
++
++ /* Mainlink output idle pattern. */
++ dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
++
++ print_status_message(link, &lt_settings, LINK_TRAINING_SUCCESS);
++
++ return true;
++}
++
++enum link_training_result dc_link_dp_perform_link_training(
++ struct dc_link *link,
++ const struct dc_link_settings *link_setting,
++ bool skip_video_pattern)
++{
++ enum link_training_result status = LINK_TRAINING_SUCCESS;
++
++ struct link_training_settings lt_settings;
++
++ initialize_training_settings(link, link_setting, &lt_settings);
++
++ /* 1. set link rate, lane count and spread. */
++ dpcd_set_link_settings(link, &lt_settings);
++
++ /* 2. perform link training (set link training done
++ * to false is done as well)
++ */
++ status = perform_clock_recovery_sequence(link, &lt_settings);
++ if (status == LINK_TRAINING_SUCCESS) {
++ status = perform_channel_equalization_sequence(link,
++ &lt_settings);
++ }
++
++ if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
++ status = perform_link_training_int(link,
++ &lt_settings,
++ status);
++ }
++
++ /* 6. print status message*/
++ print_status_message(link, &lt_settings, status);
+
+ if (status != LINK_TRAINING_SUCCESS)
+ link->ctx->dc->debug_data.ltFailCount++;
+@@ -1071,7 +1211,6 @@ enum link_training_result dc_link_dp_perform_link_training(
+ return status;
+ }
+
+-
+ bool perform_link_training_with_retries(
+ struct dc_link *link,
+ const struct dc_link_settings *link_setting,
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+index 2d019e1f6135..211fadefe2f5 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+@@ -25,10 +25,11 @@ enum dc_status core_link_read_dpcd(
+ uint8_t *data,
+ uint32_t size)
+ {
+- if (!dm_helpers_dp_read_dpcd(link->ctx,
+- link,
+- address, data, size))
+- return DC_ERROR_UNEXPECTED;
++ if (!link->aux_access_disabled &&
++ !dm_helpers_dp_read_dpcd(link->ctx,
++ link, address, data, size)) {
++ return DC_ERROR_UNEXPECTED;
++ }
+
+ return DC_OK;
+ }
+@@ -39,10 +40,11 @@ enum dc_status core_link_write_dpcd(
+ const uint8_t *data,
+ uint32_t size)
+ {
+- if (!dm_helpers_dp_write_dpcd(link->ctx,
+- link,
+- address, data, size))
+- return DC_ERROR_UNEXPECTED;
++ if (!link->aux_access_disabled &&
++ !dm_helpers_dp_write_dpcd(link->ctx,
++ link, address, data, size)) {
++ return DC_ERROR_UNEXPECTED;
++ }
+
+ return DC_OK;
+ }
+@@ -203,21 +205,21 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal)
+
+ bool dp_set_hw_training_pattern(
+ struct dc_link *link,
+- enum hw_dp_training_pattern pattern)
++ enum dc_dp_training_pattern pattern)
+ {
+ enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
+
+ switch (pattern) {
+- case HW_DP_TRAINING_PATTERN_1:
++ case DP_TRAINING_PATTERN_SEQUENCE_1:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
+ break;
+- case HW_DP_TRAINING_PATTERN_2:
++ case DP_TRAINING_PATTERN_SEQUENCE_2:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
+ break;
+- case HW_DP_TRAINING_PATTERN_3:
++ case DP_TRAINING_PATTERN_SEQUENCE_3:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
+ break;
+- case HW_DP_TRAINING_PATTERN_4:
++ case DP_TRAINING_PATTERN_SEQUENCE_4:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
+ break;
+ default:
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+index dfcec4d3e9c0..efa7a47f6b7e 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+@@ -90,6 +90,13 @@ enum dc_post_cursor2 {
+ POST_CURSOR2_MAX_LEVEL = POST_CURSOR2_LEVEL3,
+ };
+
++enum dc_dp_training_pattern {
++ DP_TRAINING_PATTERN_SEQUENCE_1 = 0,
++ DP_TRAINING_PATTERN_SEQUENCE_2,
++ DP_TRAINING_PATTERN_SEQUENCE_3,
++ DP_TRAINING_PATTERN_SEQUENCE_4,
++};
++
+ struct dc_link_settings {
+ enum dc_lane_count lane_count;
+ enum dc_link_rate link_rate;
+@@ -109,6 +116,20 @@ struct dc_link_training_settings {
+ struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX];
+ };
+
++struct dc_link_training_overrides {
++ enum dc_voltage_swing *voltage_swing;
++ enum dc_pre_emphasis *pre_emphasis;
++ enum dc_post_cursor2 *post_cursor2;
++
++ uint16_t *cr_pattern_time;
++ uint16_t *eq_pattern_time;
++ enum dc_dp_training_pattern *pattern_for_eq;
++
++ enum dc_link_spread *downspread;
++ bool *alternate_scrambler_reset;
++ bool *enhanced_framing;
++ bool *fec_enable;
++};
+
+ union dpcd_rev {
+ struct {
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
+index 6f0b80111e58..d6ff5af70c71 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
+@@ -83,6 +83,7 @@ struct dc_link {
+ bool is_hpd_filter_disabled;
+ bool dp_ss_off;
+ bool link_state_valid;
++ bool aux_access_disabled;
+
+ /* caps is the same as reported_link_cap. link_traing use
+ * reported_link_cap. Will clean up. TODO
+@@ -92,6 +93,7 @@ struct dc_link {
+ struct dc_link_settings cur_link_settings;
+ struct dc_lane_settings cur_lane_setting;
+ struct dc_link_settings preferred_link_setting;
++ struct dc_link_training_overrides preferred_training_settings;
+
+ uint8_t ddc_hw_inst;
+
+@@ -217,6 +219,10 @@ void dc_link_dp_set_drive_settings(
+ struct dc_link *link,
+ struct link_training_settings *lt_settings);
+
++bool dc_link_dp_perform_link_training_skip_aux(
++ struct dc_link *link,
++ const struct dc_link_settings *link_setting);
++
+ enum link_training_result dc_link_dp_perform_link_training(
+ struct dc_link *link,
+ const struct dc_link_settings *link_setting,
+@@ -251,6 +257,11 @@ void dc_link_perform_link_training(struct dc *dc,
+ void dc_link_set_preferred_link_settings(struct dc *dc,
+ struct dc_link_settings *link_setting,
+ struct dc_link *link);
++void dc_link_set_preferred_training_settings(struct dc *dc,
++ struct dc_link_settings *link_setting,
++ struct dc_link_training_overrides *lt_overrides,
++ struct dc_link *link,
++ bool skip_immediate_retrain);
+ void dc_link_enable_hpd(const struct dc_link *link);
+ void dc_link_disable_hpd(const struct dc_link *link);
+ void dc_link_set_test_pattern(struct dc_link *link,
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
+index 30be7bb4a01a..3680846674e8 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
+@@ -60,7 +60,7 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal);
+
+ bool dp_set_hw_training_pattern(
+ struct dc_link *link,
+- enum hw_dp_training_pattern pattern);
++ enum dc_dp_training_pattern pattern);
+
+ void dp_set_hw_lane_settings(
+ struct dc_link *link,
+diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h
+index 80f0d93cfd94..876b0b3e1a9c 100644
+--- a/drivers/gpu/drm/amd/display/include/link_service_types.h
++++ b/drivers/gpu/drm/amd/display/include/link_service_types.h
+@@ -71,14 +71,17 @@ enum link_training_result {
+ struct link_training_settings {
+ struct dc_link_settings link_settings;
+ struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX];
+- bool allow_invalid_msa_timing_param;
+-};
+
+-enum hw_dp_training_pattern {
+- HW_DP_TRAINING_PATTERN_1 = 0,
+- HW_DP_TRAINING_PATTERN_2,
+- HW_DP_TRAINING_PATTERN_3,
+- HW_DP_TRAINING_PATTERN_4
++ enum dc_voltage_swing *voltage_swing;
++ enum dc_pre_emphasis *pre_emphasis;
++ enum dc_post_cursor2 *post_cursor2;
++
++ uint16_t cr_pattern_time;
++ uint16_t eq_pattern_time;
++ enum dc_dp_training_pattern pattern_for_eq;
++
++ bool enhanced_framing;
++ bool allow_invalid_msa_timing_param;
+ };
+
+ /*TODO: Move this enum test harness*/
+--
+2.17.1
+