diff options
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.patch | 895 |
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(<_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, <_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, <_settings); +- if (status == LINK_TRAINING_SUCCESS) { +- status = perform_channel_equalization_sequence(link, +- <_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, +- <_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, <_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, <_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, <_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, <_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, <_settings); ++ ++ /* 1. set link rate, lane count and spread. */ ++ dpcd_set_link_settings(link, <_settings); ++ ++ /* 2. perform link training (set link training done ++ * to false is done as well) ++ */ ++ status = perform_clock_recovery_sequence(link, <_settings); ++ if (status == LINK_TRAINING_SUCCESS) { ++ status = perform_channel_equalization_sequence(link, ++ <_settings); ++ } ++ ++ if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { ++ status = perform_link_training_int(link, ++ <_settings, ++ status); ++ } ++ ++ /* 6. print status message*/ ++ print_status_message(link, <_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 + |