diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0623-drm-amd-display-link-training-fallback-actions.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0623-drm-amd-display-link-training-fallback-actions.patch | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0623-drm-amd-display-link-training-fallback-actions.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0623-drm-amd-display-link-training-fallback-actions.patch new file mode 100644 index 00000000..e4ccbcba --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0623-drm-amd-display-link-training-fallback-actions.patch @@ -0,0 +1,428 @@ +From 8430e07bea784739e289bbe3da8cf72a756a94bd Mon Sep 17 00:00:00 2001 +From: Ding Wang <Ding.Wang@amd.com> +Date: Thu, 13 Jul 2017 12:09:57 -0400 +Subject: [PATCH 0623/4131] drm/amd/display: link training fallback actions + +Signed-off-by: Ding Wang <ding.wang@amd.com> +Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> +Acked-by: Harry Wentland <Harry.Wentland@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 239 +++++++++++++++++---- + drivers/gpu/drm/amd/display/dc/dc.h | 2 +- + drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h | 8 + + .../drm/amd/display/include/link_service_types.h | 9 + + 4 files changed, 215 insertions(+), 43 deletions(-) + +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 98048fe..dd3f57f 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 +@@ -731,7 +731,7 @@ static enum hw_dp_training_pattern get_supported_tp(struct core_link *link) + return HW_DP_TRAINING_PATTERN_2; + } + +-static bool perform_channel_equalization_sequence( ++static enum link_training_result perform_channel_equalization_sequence( + struct core_link *link, + struct link_training_settings *lt_settings) + { +@@ -777,19 +777,19 @@ static bool perform_channel_equalization_sequence( + + /* 5. check CR done*/ + if (!is_cr_done(lane_count, dpcd_lane_status)) +- return false; ++ return LINK_TRAINING_EQ_FAIL_CR; + + /* 6. check CHEQ done*/ + if (is_ch_eq_done(lane_count, + dpcd_lane_status, + &dpcd_lane_status_updated)) +- return true; ++ return LINK_TRAINING_SUCCESS; + + /* 7. update VS/PE/PC2 in lt_settings*/ + update_drive_settings(lt_settings, req_settings); + } + +- return false; ++ return LINK_TRAINING_EQ_FAIL_EQ; + + } + +@@ -943,18 +943,17 @@ static inline bool perform_link_training_int( + return status; + } + +-bool dc_link_dp_perform_link_training( ++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 core_link *core_link = DC_LINK_TO_CORE(link); +- bool status; + + char *link_rate = "Unknown"; + struct link_training_settings lt_settings; + +- status = false; + memset(<_settings, '\0', sizeof(lt_settings)); + + lt_settings.link_settings.link_rate = link_setting->link_rate; +@@ -976,16 +975,23 @@ bool dc_link_dp_perform_link_training( + + /* 2. perform link training (set link training done + * to false is done as well)*/ +- if (perform_clock_recovery_sequence(core_link, <_settings)) { +- +- if (perform_channel_equalization_sequence(core_link, +- <_settings)) +- status = true; ++ if (!perform_clock_recovery_sequence(core_link, <_settings)) { ++ status = LINK_TRAINING_CR_FAIL; ++ } else { ++ status = perform_channel_equalization_sequence(core_link, ++ <_settings); + } + +- if (status || !skip_video_pattern) +- status = perform_link_training_int(core_link, +- <_settings, status); ++ if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { ++ if (!perform_link_training_int(core_link, ++ <_settings, ++ status == LINK_TRAINING_SUCCESS)) { ++ /* the next link training setting in this case ++ * would be the same as CR failure case. ++ */ ++ status = LINK_TRAINING_CR_FAIL; ++ } ++ } + + /* 6. print status message*/ + switch (lt_settings.link_settings.link_rate) { +@@ -1013,7 +1019,9 @@ bool dc_link_dp_perform_link_training( + CONN_MSG_LT(core_link, "%sx%d %s VS=%d, PE=%d", + link_rate, + lt_settings.link_settings.lane_count, +- status ? "pass" : "fail", ++ (status == LINK_TRAINING_SUCCESS) ? "pass" : ++ ((status == LINK_TRAINING_CR_FAIL) ? "CR failed" : ++ "EQ failed"), + lt_settings.lane_settings[0].VOLTAGE_SWING, + lt_settings.lane_settings[0].PRE_EMPHASIS); + +@@ -1035,7 +1043,7 @@ bool perform_link_training_with_retries( + if (dc_link_dp_perform_link_training( + &link->public, + link_setting, +- skip_video_pattern)) ++ skip_video_pattern) == LINK_TRAINING_SUCCESS) + return true; + + msleep(delay_between_attempts); +@@ -1068,15 +1076,6 @@ static const struct dc_link_settings *get_link_training_fallback_table( + return &link_training_fallback_table[i]; + } + +-static bool exceeded_limit_link_setting( +- const struct dc_link_settings *link_setting, +- const struct dc_link_settings *limit_link_setting) +-{ +- return (link_setting->lane_count * link_setting->link_rate +- > limit_link_setting->lane_count * limit_link_setting->link_rate ? +- true : false); +-} +- + static struct dc_link_settings get_max_link_cap(struct core_link *link) + { + /* Set Default link settings */ +@@ -1109,13 +1108,15 @@ bool dp_hbr_verify_link_cap( + struct dc_link_settings *known_limit_link_setting) + { + struct dc_link_settings max_link_cap = {0}; ++ struct dc_link_settings cur_link_setting = {0}; ++ struct dc_link_settings *cur = &cur_link_setting; ++ struct dc_link_settings initial_link_settings = {0}; + bool success; + bool skip_link_training; +- const struct dc_link_settings *cur; + bool skip_video_pattern; +- uint32_t i; + struct clock_source *dp_cs; + enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; ++ enum link_training_result status; + + success = false; + skip_link_training = false; +@@ -1142,19 +1143,16 @@ bool dp_hbr_verify_link_cap( + ASSERT(dp_cs); + } + +- for (i = 0; i < get_link_training_fallback_table_len(link) && +- !success; i++) { +- cur = get_link_training_fallback_table(link, i); +- +- if (known_limit_link_setting->lane_count != LANE_COUNT_UNKNOWN && +- exceeded_limit_link_setting(cur, +- known_limit_link_setting)) +- continue; +- +- if (!is_link_setting_supported(cur, &max_link_cap)) +- continue; +- ++ /* link training starts with the maximum common settings ++ * supported by both sink and ASIC. ++ */ ++ initial_link_settings = get_common_supported_link_settings( ++ *known_limit_link_setting, ++ max_link_cap); ++ cur_link_setting = initial_link_settings; ++ do { + skip_video_pattern = true; ++ + if (cur->link_rate == LINK_RATE_LOW) + skip_video_pattern = false; + +@@ -1167,10 +1165,12 @@ bool dp_hbr_verify_link_cap( + if (skip_link_training) + success = true; + else { +- success = dc_link_dp_perform_link_training( ++ status = dc_link_dp_perform_link_training( + &link->public, + cur, + skip_video_pattern); ++ if (status == LINK_TRAINING_SUCCESS) ++ success = true; + } + + if (success) +@@ -1181,7 +1181,8 @@ bool dp_hbr_verify_link_cap( + * based on the actual mode we're driving + */ + dp_disable_link_phy(link, link->public.connector_signal); +- } ++ } while (!success && decide_fallback_link_setting( ++ initial_link_settings, cur, status)); + + /* Link Training failed for all Link Settings + * (Lane Count is still unknown) +@@ -1202,6 +1203,160 @@ bool dp_hbr_verify_link_cap( + return success; + } + ++struct dc_link_settings get_common_supported_link_settings ( ++ struct dc_link_settings link_setting_a, ++ struct dc_link_settings link_setting_b) ++{ ++ struct dc_link_settings link_settings = {0}; ++ ++ link_settings.lane_count = ++ (link_setting_a.lane_count <= ++ link_setting_b.lane_count) ? ++ link_setting_a.lane_count : ++ link_setting_b.lane_count; ++ link_settings.link_rate = ++ (link_setting_a.link_rate <= ++ link_setting_b.link_rate) ? ++ link_setting_a.link_rate : ++ link_setting_b.link_rate; ++ link_settings.link_spread = LINK_SPREAD_DISABLED; ++ ++ /* in DP compliance test, DPR-120 may have ++ * a random value in its MAX_LINK_BW dpcd field. ++ * We map it to the maximum supported link rate that ++ * is smaller than MAX_LINK_BW in this case. ++ */ ++ if (link_settings.link_rate > LINK_RATE_HIGH3) { ++ link_settings.link_rate = LINK_RATE_HIGH3; ++ } else if (link_settings.link_rate < LINK_RATE_HIGH3 ++ && link_settings.link_rate > LINK_RATE_HIGH2) { ++ link_settings.link_rate = LINK_RATE_HIGH2; ++ } else if (link_settings.link_rate < LINK_RATE_HIGH2 ++ && link_settings.link_rate > LINK_RATE_HIGH) { ++ link_settings.link_rate = LINK_RATE_HIGH; ++ } else if (link_settings.link_rate < LINK_RATE_HIGH ++ && link_settings.link_rate > LINK_RATE_LOW) { ++ link_settings.link_rate = LINK_RATE_LOW; ++ } else if (link_settings.link_rate < LINK_RATE_LOW) { ++ link_settings.link_rate = LINK_RATE_UNKNOWN; ++ } ++ ++ return link_settings; ++} ++ ++bool reached_minimum_lane_count(enum dc_lane_count lane_count) ++{ ++ return lane_count <= LANE_COUNT_ONE; ++} ++ ++bool reached_minimum_link_rate(enum dc_link_rate link_rate) ++{ ++ return link_rate <= LINK_RATE_LOW; ++} ++ ++enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count) ++{ ++ switch (lane_count) { ++ case LANE_COUNT_FOUR: ++ return LANE_COUNT_TWO; ++ case LANE_COUNT_TWO: ++ return LANE_COUNT_ONE; ++ case LANE_COUNT_ONE: ++ return LANE_COUNT_UNKNOWN; ++ default: ++ return LANE_COUNT_UNKNOWN; ++ } ++} ++ ++enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate) ++{ ++ switch (link_rate) { ++ case LINK_RATE_HIGH3: ++ return LINK_RATE_HIGH2; ++ case LINK_RATE_HIGH2: ++ return LINK_RATE_HIGH; ++ case LINK_RATE_HIGH: ++ return LINK_RATE_LOW; ++ case LINK_RATE_LOW: ++ return LINK_RATE_UNKNOWN; ++ default: ++ return LINK_RATE_UNKNOWN; ++ } ++} ++ ++/* ++ * function: set link rate and lane count fallback based ++ * on current link setting and last link training result ++ * return value: ++ * true - link setting could be set ++ * false - has reached minimum setting ++ * and no further fallback could be done ++ */ ++bool decide_fallback_link_setting( ++ struct dc_link_settings initial_link_settings, ++ struct dc_link_settings *current_link_setting, ++ enum link_training_result training_result) ++{ ++ if (!current_link_setting) ++ return false; ++ ++ switch (training_result) { ++ case LINK_TRAINING_CR_FAIL: ++ { ++ if (!reached_minimum_link_rate ++ (current_link_setting->link_rate)) { ++ current_link_setting->link_rate = ++ reduce_link_rate( ++ current_link_setting->link_rate); ++ } else if (!reached_minimum_lane_count ++ (current_link_setting->lane_count)) { ++ current_link_setting->link_rate = ++ initial_link_settings.link_rate; ++ current_link_setting->lane_count = ++ reduce_lane_count( ++ current_link_setting->lane_count); ++ } else { ++ return false; ++ } ++ break; ++ } ++ case LINK_TRAINING_EQ_FAIL_EQ: ++ { ++ if (!reached_minimum_lane_count ++ (current_link_setting->lane_count)) { ++ current_link_setting->lane_count = ++ reduce_lane_count( ++ current_link_setting->lane_count); ++ } else if (!reached_minimum_link_rate ++ (current_link_setting->link_rate)) { ++ current_link_setting->lane_count = ++ initial_link_settings.lane_count; ++ current_link_setting->link_rate = ++ reduce_link_rate( ++ current_link_setting->link_rate); ++ } else { ++ return false; ++ } ++ break; ++ } ++ case LINK_TRAINING_EQ_FAIL_CR: ++ { ++ if (!reached_minimum_link_rate ++ (current_link_setting->link_rate)) { ++ current_link_setting->link_rate = ++ reduce_link_rate( ++ current_link_setting->link_rate); ++ } else { ++ return false; ++ } ++ break; ++ } ++ default: ++ return false; ++ } ++ return true; ++} ++ + static uint32_t bandwidth_in_kbps_from_timing( + const struct dc_crtc_timing *timing) + { +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index cd89814..6a22c91 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -777,7 +777,7 @@ void dc_link_dp_set_drive_settings( + const struct dc_link *link, + struct link_training_settings *lt_settings); + +-bool dc_link_dp_perform_link_training( ++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); +diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +index 92c56e6..b6ef1bf 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +@@ -37,6 +37,14 @@ bool dp_hbr_verify_link_cap( + struct core_link *link, + struct dc_link_settings *known_limit_link_setting); + ++bool decide_fallback_link_setting(struct dc_link_settings link_setting_init, ++ struct dc_link_settings *link_setting_current, ++ enum link_training_result training_result); ++ ++struct dc_link_settings get_common_supported_link_settings ( ++ struct dc_link_settings link_setting_a, ++ struct dc_link_settings link_setting_b); ++ + bool dp_validate_mode_timing( + struct core_link *link, + const struct dc_crtc_timing *timing); +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 fe8b514..adea1a5 100644 +--- a/drivers/gpu/drm/amd/display/include/link_service_types.h ++++ b/drivers/gpu/drm/amd/display/include/link_service_types.h +@@ -56,6 +56,15 @@ enum { + LINK_RATE_REF_FREQ_IN_KHZ = 27000 /*27MHz*/ + }; + ++enum link_training_result { ++ LINK_TRAINING_SUCCESS, ++ LINK_TRAINING_CR_FAIL, ++ /* CR DONE bit is cleared during EQ step */ ++ LINK_TRAINING_EQ_FAIL_CR, ++ /* other failure during EQ step */ ++ LINK_TRAINING_EQ_FAIL_EQ, ++}; ++ + struct link_training_settings { + struct dc_link_settings link_settings; + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]; +-- +2.7.4 + |