Commit 6651875a authored by David Zhang's avatar David Zhang Committed by Alex Deucher

drm/amd/display: Add PSR-SU-RC support in DC

[Why]

PSR-SU Rate Control - or PSR-SU-RC - enables PSR-SU panels to work with
variable refresh rate to allow for more power savings. Lowering the
refresh rate can increase PSR residency by expanding the eDP main link
shut down duration. It can also lower panel power consumption.

There is a complication with PSR, since the eDP main link can be shut
down. Therefore, the timing controller (TCON) on the eDP sink nees to be
able to scan out its remote buffer independent of the main link. To
allow the eDP source to specify the sink's refresh rate while the link
is off, vendor-specific DPCD registers are used. This allows the eDP
source to then "Rate Control" the panel during PSR active.

[How]

Add DC support to communicate with PSR-SU-RC supported eDP sinks. The
sink will need to know the desired VTotal during PSR active.

This change only adds support to DC, support in amdgpu_dm is still
pending to enable this fully.
Signed-off-by: default avatarDavid Zhang <dingchen.zhang@amd.com>
Signed-off-by: default avatarLeo Li <sunpeng.li@amd.com>
Reviewed-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 6bad4ff8
......@@ -1795,6 +1795,7 @@ static bool dc_link_construct_legacy(struct dc_link *link,
*/
program_hpd_filter(link);
link->psr_settings.psr_vtotal_control_support = false;
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);
......@@ -3227,6 +3228,7 @@ bool dc_link_setup_psr(struct dc_link *link,
/* updateSinkPsrDpcdConfig*/
union dpcd_psr_configuration psr_configuration;
union dpcd_alpm_configuration alpm_configuration;
union dpcd_sink_active_vtotal_control_mode vtotal_control = {0};
psr_context->controllerId = CONTROLLER_ID_UNDEFINED;
......@@ -3296,6 +3298,13 @@ bool dc_link_setup_psr(struct dc_link *link,
psr_config->su_y_granularity;
psr_context->line_time_in_us =
psr_config->line_time_in_us;
if (link->psr_settings.psr_vtotal_control_support) {
psr_context->rate_control_caps = psr_config->rate_control_caps;
vtotal_control.bits.ENABLE = true;
core_link_write_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE,
&vtotal_control.raw, sizeof(vtotal_control.raw));
}
}
psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
......@@ -3428,6 +3437,19 @@ void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency)
*residency = 0;
}
bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
{
struct dc *dc = link->ctx->dc;
struct dmub_psr *psr = dc->res_pool->psr;
if (psr == NULL || !link->psr_settings.psr_feature_enabled || !link->psr_settings.psr_vtotal_control_support)
return false;
psr->funcs->psr_set_sink_vtotal_in_psr_active(psr, psr_vtotal_idle, psr_vtotal_su);
return true;
}
const struct dc_link_status *dc_link_get_status(const struct dc_link *link)
{
return &link->link_status;
......
......@@ -100,6 +100,7 @@ struct psr_settings {
bool psr_feature_enabled; // PSR is supported by sink
bool psr_allow_active; // PSR is currently active
enum dc_psr_version psr_version; // Internal PSR version, determined based on DPCD
bool psr_vtotal_control_support; // Vtotal control is supported by sink
/* These parameters are calculated in Driver,
* based on display timing and Sink capabilities.
......@@ -325,6 +326,8 @@ void dc_link_blank_all_dp_displays(struct dc *dc);
void dc_link_blank_all_edp_displays(struct dc *dc);
void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init);
bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link,
uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su);
/* Request DC to detect if there is a Panel connected.
* boot - If this call is during initial boot.
......
......@@ -684,6 +684,7 @@ struct psr_config {
/* psr2 selective update y granularity capability */
uint8_t su_y_granularity;
unsigned int line_time_in_us;
uint8_t rate_control_caps;
};
union dmcu_psr_level {
......@@ -794,6 +795,7 @@ struct psr_context {
/* psr2 selective update y granularity capability */
uint8_t su_y_granularity;
unsigned int line_time_in_us;
uint8_t rate_control_caps;
};
struct colorspace_transform {
......
......@@ -250,6 +250,27 @@ static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level, uint8_
dc_dmub_srv_wait_idle(dc->dmub_srv);
}
/**
* Set PSR vtotal requirement for FreeSync PSR.
*/
static void dmub_psr_set_sink_vtotal_in_psr_active(struct dmub_psr *dmub,
uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
{
union dmub_rb_cmd cmd;
struct dc_context *dc = dmub->ctx;
memset(&cmd, 0, sizeof(cmd));
cmd.psr_set_vtotal.header.type = DMUB_CMD__PSR;
cmd.psr_set_vtotal.header.sub_type = DMUB_CMD__SET_SINK_VTOTAL_IN_PSR_ACTIVE;
cmd.psr_set_vtotal.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_vtotal_data);
cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_idle = psr_vtotal_idle;
cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_su = psr_vtotal_su;
dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
dc_dmub_srv_cmd_execute(dc->dmub_srv);
dc_dmub_srv_wait_idle(dc->dmub_srv);
}
/*
* Set PSR power optimization flags.
*/
......@@ -358,6 +379,7 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
copy_settings_data->line_capture_indication = 0;
copy_settings_data->line_time_in_us = psr_context->line_time_in_us;
copy_settings_data->rate_control_caps = psr_context->rate_control_caps;
copy_settings_data->fec_enable_status = (link->fec_state == dc_link_fec_enabled);
copy_settings_data->fec_enable_delay_in100us = link->dc->debug.fec_enable_delay_in100us;
copy_settings_data->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;
......@@ -435,6 +457,7 @@ static const struct dmub_psr_funcs psr_funcs = {
.psr_set_level = dmub_psr_set_level,
.psr_force_static = dmub_psr_force_static,
.psr_get_residency = dmub_psr_get_residency,
.psr_set_sink_vtotal_in_psr_active = dmub_psr_set_sink_vtotal_in_psr_active,
.psr_set_power_opt = dmub_psr_set_power_opt,
};
......
......@@ -46,6 +46,8 @@ struct dmub_psr_funcs {
void (*psr_force_static)(struct dmub_psr *dmub, uint8_t panel_inst);
void (*psr_get_residency)(struct dmub_psr *dmub, uint32_t *residency,
uint8_t panel_inst);
void (*psr_set_sink_vtotal_in_psr_active)(struct dmub_psr *dmub,
uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su);
void (*psr_set_power_opt)(struct dmub_psr *dmub, unsigned int power_opt, uint8_t panel_inst);
};
......
......@@ -101,6 +101,14 @@ union dpcd_alpm_configuration {
unsigned char raw;
};
union dpcd_sink_active_vtotal_control_mode {
struct {
unsigned char ENABLE : 1;
unsigned char RESERVED : 7;
} bits;
unsigned char raw;
};
union psr_error_status {
struct {
unsigned char LINK_CRC_ERROR :1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment