mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-06 06:37:59 +00:00
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> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
33e0a44583
commit
8628d02f60
3 changed files with 142 additions and 65 deletions
|
@ -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,17 +1642,102 @@ bool dp_validate_mode_timing(
|
|||
return false;
|
||||
}
|
||||
|
||||
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, false, 0};
|
||||
struct dc_link_settings current_link_setting =
|
||||
initial_link_setting;
|
||||
uint32_t link_bw;
|
||||
|
||||
/* 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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
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_settings initial_link_setting = {
|
||||
LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED};
|
||||
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);
|
||||
|
||||
|
@ -1664,38 +1762,11 @@ void decide_link_settings(struct dc_stream_state *stream,
|
|||
return;
|
||||
}
|
||||
|
||||
/* EDP use the link cap setting */
|
||||
if (link->connector_signal == SIGNAL_TYPE_EDP) {
|
||||
*link_setting = link->verified_link_cap;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
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;
|
||||
if (decide_edp_link_settings(link, link_setting, req_bw))
|
||||
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;
|
||||
}
|
||||
}
|
||||
} 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue