diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/1306-drm-amd-display-optionally-optimize-edp-link-rate-ba.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.19.8/1306-drm-amd-display-optionally-optimize-edp-link-rate-ba.patch | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/1306-drm-amd-display-optionally-optimize-edp-link-rate-ba.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/1306-drm-amd-display-optionally-optimize-edp-link-rate-ba.patch new file mode 100644 index 00000000..d2acfca1 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/1306-drm-amd-display-optionally-optimize-edp-link-rate-ba.patch @@ -0,0 +1,370 @@ +From a07f4e789a997c756c7950cd46cdd040e3142e8a Mon Sep 17 00:00:00 2001 +From: Josip Pavic <Josip.Pavic@amd.com> +Date: Tue, 5 Feb 2019 19:27:38 -0500 +Subject: [PATCH 1306/2940] drm/amd/display: optionally optimize edp link rate + based on timing + +[Why] +eDP v1.4 allows panels to report link rates other than RBR/HBR/HBR2, that +may be more optimal for the panel's timing. Power can be saved by using +a link rate closer to the required bandwidth of the panel's timing. + +[How] +Scan the table of reported link rates from the panel, and select the +minimum link rate that satisfies the bandwidth requirements of the panel's +timing. Include a flag to make the feature optional. + +Signed-off-by: Josip Pavic <Josip.Pavic@amd.com> +Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> +Acked-by: Anthony Koo <Anthony.Koo@amd.com> +Acked-by: Leo Li <sunpeng.li@amd.com> +--- + .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 195 ++++++++++++------ + drivers/gpu/drm/amd/display/dc/dc.h | 6 +- + drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 2 + + 3 files changed, 140 insertions(+), 63 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 09d301216076..8ad79df56bf8 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 +@@ -93,12 +93,10 @@ static void dpcd_set_link_settings( + struct dc_link *link, + const struct link_training_settings *lt_settings) + { +- uint8_t rate = (uint8_t) +- (lt_settings->link_settings.link_rate); ++ uint8_t rate; + + union down_spread_ctrl downspread = { {0} }; + union lane_count_set lane_count_set = { {0} }; +- uint8_t link_set_buffer[2]; + + downspread.raw = (uint8_t) + (lt_settings->link_settings.link_spread); +@@ -111,29 +109,42 @@ static void dpcd_set_link_settings( + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = + link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + +- link_set_buffer[0] = rate; +- link_set_buffer[1] = lane_count_set.raw; +- +- core_link_write_dpcd(link, DP_LINK_BW_SET, +- link_set_buffer, 2); + core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + &downspread.raw, sizeof(downspread)); + ++ core_link_write_dpcd(link, DP_LANE_COUNT_SET, ++ &lane_count_set.raw, 1); ++ + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && +- (link->dpcd_caps.link_rate_set >= 1 && +- link->dpcd_caps.link_rate_set <= 8)) { ++ lt_settings->link_settings.use_link_rate_set == true) { ++ rate = 0; ++ core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + core_link_write_dpcd(link, DP_LINK_RATE_SET, +- &link->dpcd_caps.link_rate_set, 1); ++ <_settings->link_settings.link_rate_set, 1); ++ } else { ++ rate = (uint8_t) (lt_settings->link_settings.link_rate); ++ core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + } + +- DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %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, +- DP_DOWNSPREAD_CTRL, +- lt_settings->link_settings.link_spread); ++ if (rate) { ++ DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %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, ++ 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", ++ __func__, ++ DP_LINK_RATE_SET, ++ lt_settings->link_settings.link_rate_set, ++ DP_LANE_COUNT_SET, ++ lt_settings->link_settings.lane_count, ++ DP_DOWNSPREAD_CTRL, ++ lt_settings->link_settings.link_spread); ++ } + + } + +@@ -952,6 +963,8 @@ enum link_training_result dc_link_dp_perform_link_training( + + 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; + + /*@todo[vdevulap] move SS to LS, should not be handled by displaypath*/ + +@@ -1075,7 +1088,7 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) + { + /* Set Default link settings */ + struct dc_link_settings max_link_cap = {LANE_COUNT_FOUR, LINK_RATE_HIGH, +- LINK_SPREAD_05_DOWNSPREAD_30KHZ}; ++ LINK_SPREAD_05_DOWNSPREAD_30KHZ, false, 0}; + + /* Higher link settings based on feature supported */ + if (link->link_enc->features.flags.bits.IS_HBR2_CAPABLE) +@@ -1629,47 +1642,65 @@ bool dp_validate_mode_timing( + return false; + } + +-void decide_link_settings(struct dc_stream_state *stream, +- struct dc_link_settings *link_setting) ++static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) + { +- + struct dc_link_settings initial_link_setting = { +- LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED}; ++ LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0}; + struct dc_link_settings current_link_setting = + initial_link_setting; +- struct dc_link *link; +- uint32_t req_bw; + uint32_t link_bw; + +- req_bw = bandwidth_in_kbps_from_timing(&stream->timing); +- +- link = stream->link; +- +- /* if preferred is specified through AMDDP, use it, if it's enough +- * to drive the mode ++ /* search for the minimum link setting that: ++ * 1. is supported according to the link training result ++ * 2. could support the b/w requested by the timing + */ +- if (link->preferred_link_setting.lane_count != +- LANE_COUNT_UNKNOWN && +- link->preferred_link_setting.link_rate != +- LINK_RATE_UNKNOWN) { +- *link_setting = link->preferred_link_setting; +- return; +- } ++ while (current_link_setting.link_rate <= ++ link->verified_link_cap.link_rate) { ++ link_bw = bandwidth_in_kbps_from_link_settings( ++ ¤t_link_setting); ++ if (req_bw <= link_bw) { ++ *link_setting = current_link_setting; ++ return true; ++ } + +- /* MST doesn't perform link training for now +- * TODO: add MST specific link training routine +- */ +- if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { +- *link_setting = link->verified_link_cap; +- return; ++ if (current_link_setting.lane_count < ++ link->verified_link_cap.lane_count) { ++ current_link_setting.lane_count = ++ increase_lane_count( ++ current_link_setting.lane_count); ++ } else { ++ current_link_setting.link_rate = ++ increase_link_rate( ++ current_link_setting.link_rate); ++ current_link_setting.lane_count = ++ initial_link_setting.lane_count; ++ } + } + +- /* EDP use the link cap setting */ +- if (link->connector_signal == SIGNAL_TYPE_EDP) { ++ return false; ++} ++ ++static bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) ++{ ++ struct dc_link_settings initial_link_setting; ++ struct dc_link_settings current_link_setting; ++ uint32_t link_bw; ++ ++ if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14 || ++ link->dpcd_caps.edp_supported_link_rates_count == 0 || ++ link->dc->config.optimize_edp_link_rate == false) { + *link_setting = link->verified_link_cap; +- return; ++ return true; + } + ++ memset(&initial_link_setting, 0, sizeof(initial_link_setting)); ++ initial_link_setting.lane_count = LANE_COUNT_ONE; ++ initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0]; ++ initial_link_setting.link_spread = LINK_SPREAD_DISABLED; ++ initial_link_setting.use_link_rate_set = true; ++ initial_link_setting.link_rate_set = 0; ++ current_link_setting = initial_link_setting; ++ + /* search for the minimum link setting that: + * 1. is supported according to the link training result + * 2. could support the b/w requested by the timing +@@ -1680,7 +1711,7 @@ void decide_link_settings(struct dc_stream_state *stream, + ¤t_link_setting); + if (req_bw <= link_bw) { + *link_setting = current_link_setting; +- return; ++ return true; + } + + if (current_link_setting.lane_count < +@@ -1689,13 +1720,53 @@ void decide_link_settings(struct dc_stream_state *stream, + increase_lane_count( + current_link_setting.lane_count); + } else { +- current_link_setting.link_rate = +- increase_link_rate( +- current_link_setting.link_rate); +- current_link_setting.lane_count = +- initial_link_setting.lane_count; ++ if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { ++ current_link_setting.link_rate_set++; ++ current_link_setting.link_rate = ++ link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; ++ current_link_setting.lane_count = ++ initial_link_setting.lane_count; ++ } else ++ break; + } + } ++ return false; ++} ++ ++void decide_link_settings(struct dc_stream_state *stream, ++ struct dc_link_settings *link_setting) ++{ ++ struct dc_link *link; ++ uint32_t req_bw; ++ ++ req_bw = bandwidth_in_kbps_from_timing(&stream->timing); ++ ++ link = stream->link; ++ ++ /* if preferred is specified through AMDDP, use it, if it's enough ++ * to drive the mode ++ */ ++ if (link->preferred_link_setting.lane_count != ++ LANE_COUNT_UNKNOWN && ++ link->preferred_link_setting.link_rate != ++ LINK_RATE_UNKNOWN) { ++ *link_setting = link->preferred_link_setting; ++ return; ++ } ++ ++ /* MST doesn't perform link training for now ++ * TODO: add MST specific link training routine ++ */ ++ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { ++ *link_setting = link->verified_link_cap; ++ return; ++ } ++ ++ if (link->connector_signal == SIGNAL_TYPE_EDP) { ++ if (decide_edp_link_settings(link, link_setting, req_bw)) ++ return; ++ } else if (decide_dp_link_settings(link, link_setting, req_bw)) ++ return; + + BREAK_TO_DEBUGGER(); + ASSERT(link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN); +@@ -2536,31 +2607,31 @@ enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz) + + void detect_edp_sink_caps(struct dc_link *link) + { +- uint8_t supported_link_rates[16] = {0}; ++ uint8_t supported_link_rates[16]; + uint32_t entry; + uint32_t link_rate_in_khz; + enum dc_link_rate link_rate = LINK_RATE_UNKNOWN; + + retrieve_link_cap(link); ++ link->dpcd_caps.edp_supported_link_rates_count = 0; ++ memset(supported_link_rates, 0, sizeof(supported_link_rates)); + +- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) { ++ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && ++ link->dc->config.optimize_edp_link_rate) { + // Read DPCD 00010h - 0001Fh 16 bytes at one shot + core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, + supported_link_rates, sizeof(supported_link_rates)); + +- link->dpcd_caps.link_rate_set = 0; + for (entry = 0; entry < 16; entry += 2) { + // DPCD register reports per-lane link rate = 16-bit link rate capability +- // value X 200 kHz. Need multipler to find link rate in kHz. ++ // value X 200 kHz. Need multiplier to find link rate in kHz. + link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 + + supported_link_rates[entry]) * 200; + + if (link_rate_in_khz != 0) { + link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); +- if (link->reported_link_cap.link_rate < link_rate) { +- link->reported_link_cap.link_rate = link_rate; +- link->dpcd_caps.link_rate_set = entry; +- } ++ link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate; ++ link->dpcd_caps.edp_supported_link_rates_count++; + } + } + } +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index 321ba9c6c827..31a2ca998032 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -164,6 +164,7 @@ struct dc_config { + bool gpu_vm_support; + bool disable_disp_pll_sharing; + bool fbc_support; ++ bool optimize_edp_link_rate; + }; + + enum visual_confirm { +@@ -648,6 +649,10 @@ struct dpcd_caps { + union max_lane_count max_ln_count; + union max_down_spread max_down_spread; + ++ /* valid only for eDP v1.4 or higher*/ ++ uint8_t edp_supported_link_rates_count; ++ enum dc_link_rate edp_supported_link_rates[8]; ++ + /* dongle type (DP converter, CV smart dongle) */ + enum display_dongle_type dongle_type; + /* Dongle's downstream count. */ +@@ -665,7 +670,6 @@ struct dpcd_caps { + int8_t branch_dev_name[6]; + int8_t branch_hw_revision; + int8_t branch_fw_revision[2]; +- uint8_t link_rate_set; + + bool allow_invalid_MSA_timing_param; + bool panel_mode_edp; +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 d4eab33c453b..ec403cd8b834 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +@@ -94,6 +94,8 @@ struct dc_link_settings { + enum dc_lane_count lane_count; + enum dc_link_rate link_rate; + enum dc_link_spread link_spread; ++ bool use_link_rate_set; ++ uint8_t link_rate_set; + }; + + struct dc_lane_settings { +-- +2.17.1 + |