aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.19.8/1306-drm-amd-display-optionally-optimize-edp-link-rate-ba.patch
diff options
context:
space:
mode:
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.patch370
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);
++ &lt_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(
++ &current_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,
+ &current_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
+