Commit e379787c authored by Tom Chung's avatar Tom Chung Committed by Alex Deucher

drm/amd/display: Add some functions for Panel Replay

[WHY]
Prepare for enabling the Panel Replay feature

[HOW]
- Add some Panel Replay setting functions in DC
- Add the Panel Replay resource in dcn35_resource.c
- Add debug masks for Panel Replay
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Acked-by: default avatarRodrigo Siqueira <rodrigo.siqueira@amd.com>
Reviewed-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarTom Chung <chiahsuan.chung@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent d6398866
...@@ -4770,6 +4770,38 @@ bool dc_set_psr_allow_active(struct dc *dc, bool enable) ...@@ -4770,6 +4770,38 @@ bool dc_set_psr_allow_active(struct dc *dc, bool enable)
return true; return true;
} }
/* enable/disable eDP Replay without specify stream for eDP */
bool dc_set_replay_allow_active(struct dc *dc, bool active)
{
int i;
bool allow_active;
for (i = 0; i < dc->current_state->stream_count; i++) {
struct dc_link *link;
struct dc_stream_state *stream = dc->current_state->streams[i];
link = stream->link;
if (!link)
continue;
if (link->replay_settings.replay_feature_enabled) {
if (active && !link->replay_settings.replay_allow_active) {
allow_active = true;
if (!dc_link_set_replay_allow_active(link, &allow_active,
false, false, NULL))
return false;
} else if (!active && link->replay_settings.replay_allow_active) {
allow_active = false;
if (!dc_link_set_replay_allow_active(link, &allow_active,
true, false, NULL))
return false;
}
}
}
return true;
}
void dc_allow_idle_optimizations(struct dc *dc, bool allow) void dc_allow_idle_optimizations(struct dc *dc, bool allow)
{ {
if (dc->debug.disable_idle_power_optimizations) if (dc->debug.disable_idle_power_optimizations)
...@@ -5315,6 +5347,8 @@ bool dc_abm_save_restore( ...@@ -5315,6 +5347,8 @@ bool dc_abm_save_restore(
struct dc_link *link = stream->sink->link; struct dc_link *link = stream->sink->link;
struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_links[MAX_NUM_EDP];
if (link->replay_settings.replay_feature_enabled)
return false;
/*find primary pipe associated with stream*/ /*find primary pipe associated with stream*/
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
......
...@@ -467,6 +467,13 @@ bool dc_link_setup_psr(struct dc_link *link, ...@@ -467,6 +467,13 @@ bool dc_link_setup_psr(struct dc_link *link,
return link->dc->link_srv->edp_setup_psr(link, stream, psr_config, psr_context); return link->dc->link_srv->edp_setup_psr(link, stream, psr_config, psr_context);
} }
bool dc_link_set_replay_allow_active(struct dc_link *link, const bool *allow_active,
bool wait, bool force_static, const unsigned int *power_opts)
{
return link->dc->link_srv->edp_set_replay_allow_active(link, allow_active, wait,
force_static, power_opts);
}
bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state) bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state)
{ {
return link->dc->link_srv->edp_get_replay_state(link, state); return link->dc->link_srv->edp_get_replay_state(link, state);
......
...@@ -463,6 +463,12 @@ enum dml_hostvm_override_opts { ...@@ -463,6 +463,12 @@ enum dml_hostvm_override_opts {
DML_HOSTVM_OVERRIDE_TRUE = 0x2, DML_HOSTVM_OVERRIDE_TRUE = 0x2,
}; };
enum dc_replay_power_opts {
replay_power_opt_invalid = 0x0,
replay_power_opt_smu_opt_static_screen = 0x1,
replay_power_opt_z10_static_screen = 0x10,
};
enum dcc_option { enum dcc_option {
DCC_ENABLE = 0, DCC_ENABLE = 0,
DCC_DISABLE = 1, DCC_DISABLE = 1,
...@@ -2077,6 +2083,20 @@ bool dc_link_setup_psr(struct dc_link *dc_link, ...@@ -2077,6 +2083,20 @@ bool dc_link_setup_psr(struct dc_link *dc_link,
const struct dc_stream_state *stream, struct psr_config *psr_config, const struct dc_stream_state *stream, struct psr_config *psr_config,
struct psr_context *psr_context); struct psr_context *psr_context);
/*
* Communicate with DMUB to allow or disallow Panel Replay on the specified link:
*
* @link: pointer to the dc_link struct instance
* @enable: enable(active) or disable(inactive) replay
* @wait: state transition need to wait the active set completed.
* @force_static: force disable(inactive) the replay
* @power_opts: set power optimazation parameters to DMUB.
*
* return: allow Replay active will return true, else will return false.
*/
bool dc_link_set_replay_allow_active(struct dc_link *dc_link, const bool *enable,
bool wait, bool force_static, const unsigned int *power_opts);
bool dc_link_get_replay_state(const struct dc_link *dc_link, uint64_t *state); bool dc_link_get_replay_state(const struct dc_link *dc_link, uint64_t *state);
/* On eDP links this function call will stall until T12 has elapsed. /* On eDP links this function call will stall until T12 has elapsed.
...@@ -2321,6 +2341,9 @@ void dc_hardware_release(struct dc *dc); ...@@ -2321,6 +2341,9 @@ void dc_hardware_release(struct dc *dc);
void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc); void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc);
bool dc_set_psr_allow_active(struct dc *dc, bool enable); bool dc_set_psr_allow_active(struct dc *dc, bool enable);
bool dc_set_replay_allow_active(struct dc *dc, bool active);
void dc_z10_restore(const struct dc *dc); void dc_z10_restore(const struct dc *dc);
void dc_z10_save_init(struct dc *dc); void dc_z10_save_init(struct dc *dc);
......
...@@ -258,13 +258,97 @@ static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst, ...@@ -258,13 +258,97 @@ static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst,
*residency = 0; *residency = 0;
} }
/**
* Set REPLAY power optimization flags and coasting vtotal.
*/
static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dmub,
unsigned int power_opt, uint8_t panel_inst, uint16_t coasting_vtotal)
{
union dmub_rb_cmd cmd;
struct dc_context *dc = dmub->ctx;
memset(&cmd, 0, sizeof(cmd));
cmd.replay_set_power_opt_and_coasting_vtotal.header.type = DMUB_CMD__REPLAY;
cmd.replay_set_power_opt_and_coasting_vtotal.header.sub_type =
DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL;
cmd.replay_set_power_opt_and_coasting_vtotal.header.payload_bytes =
sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal);
cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_power_opt_data.power_opt = power_opt;
cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_power_opt_data.panel_inst = panel_inst;
cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_coasting_vtotal_data.coasting_vtotal = coasting_vtotal;
dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
/**
* send Replay general cmd to DMUB.
*/
static void dmub_replay_send_cmd(struct dmub_replay *dmub,
enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element)
{
union dmub_rb_cmd cmd;
struct dc_context *ctx = NULL;
if (dmub == NULL || cmd_element == NULL)
return;
ctx = dmub->ctx;
if (ctx != NULL) {
if (msg != Replay_Msg_Not_Support) {
memset(&cmd, 0, sizeof(cmd));
//Header
cmd.replay_set_timing_sync.header.type = DMUB_CMD__REPLAY;
} else
return;
} else
return;
switch (msg) {
case Replay_Set_Timing_Sync_Supported:
//Header
cmd.replay_set_timing_sync.header.sub_type =
DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED;
cmd.replay_set_timing_sync.header.payload_bytes =
sizeof(struct dmub_rb_cmd_replay_set_timing_sync);
//Cmd Body
cmd.replay_set_timing_sync.replay_set_timing_sync_data.panel_inst =
cmd_element->sync_data.panel_inst;
cmd.replay_set_timing_sync.replay_set_timing_sync_data.timing_sync_supported =
cmd_element->sync_data.timing_sync_supported;
break;
case Replay_Set_Residency_Frameupdate_Timer:
//Header
cmd.replay_set_frameupdate_timer.header.sub_type =
DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER;
cmd.replay_set_frameupdate_timer.header.payload_bytes =
sizeof(struct dmub_rb_cmd_replay_set_frameupdate_timer);
//Cmd Body
cmd.replay_set_frameupdate_timer.data.panel_inst =
cmd_element->panel_inst;
cmd.replay_set_frameupdate_timer.data.enable =
cmd_element->timer_data.enable;
cmd.replay_set_frameupdate_timer.data.frameupdate_count =
cmd_element->timer_data.frameupdate_count;
break;
case Replay_Msg_Not_Support:
default:
return;
break;
}
dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
static const struct dmub_replay_funcs replay_funcs = { static const struct dmub_replay_funcs replay_funcs = {
.replay_copy_settings = dmub_replay_copy_settings, .replay_copy_settings = dmub_replay_copy_settings,
.replay_enable = dmub_replay_enable, .replay_enable = dmub_replay_enable,
.replay_get_state = dmub_replay_get_state, .replay_get_state = dmub_replay_get_state,
.replay_set_power_opt = dmub_replay_set_power_opt, .replay_set_power_opt = dmub_replay_set_power_opt,
.replay_set_coasting_vtotal = dmub_replay_set_coasting_vtotal, .replay_set_coasting_vtotal = dmub_replay_set_coasting_vtotal,
.replay_residency = dmub_replay_residency, .replay_residency = dmub_replay_residency,
.replay_set_power_opt_and_coasting_vtotal = dmub_replay_set_power_opt_and_coasting_vtotal,
.replay_send_cmd = dmub_replay_send_cmd,
}; };
/* /*
......
...@@ -51,6 +51,8 @@ struct dmub_replay_funcs { ...@@ -51,6 +51,8 @@ struct dmub_replay_funcs {
uint8_t panel_inst); uint8_t panel_inst);
void (*replay_residency)(struct dmub_replay *dmub, void (*replay_residency)(struct dmub_replay *dmub,
uint8_t panel_inst, uint32_t *residency, const bool is_start, const bool is_alpm); uint8_t panel_inst, uint32_t *residency, const bool is_start, const bool is_alpm);
void (*replay_set_power_opt_and_coasting_vtotal)(struct dmub_replay *dmub,
unsigned int power_opt, uint8_t panel_inst, uint16_t coasting_vtotal);
}; };
struct dmub_replay *dmub_replay_create(struct dc_context *ctx); struct dmub_replay *dmub_replay_create(struct dc_context *ctx);
......
...@@ -289,6 +289,8 @@ struct link_service { ...@@ -289,6 +289,8 @@ struct link_service {
bool (*edp_replay_residency)(const struct dc_link *link, bool (*edp_replay_residency)(const struct dc_link *link,
unsigned int *residency, const bool is_start, unsigned int *residency, const bool is_start,
const bool is_alpm); const bool is_alpm);
bool (*edp_set_replay_power_opt_and_coasting_vtotal)(struct dc_link *link,
const unsigned int *power_opts, uint16_t coasting_vtotal);
bool (*edp_wait_for_t12)(struct dc_link *link); bool (*edp_wait_for_t12)(struct dc_link *link);
bool (*edp_is_ilr_optimization_required)(struct dc_link *link, bool (*edp_is_ilr_optimization_required)(struct dc_link *link,
......
...@@ -216,6 +216,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s ...@@ -216,6 +216,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s
link_srv->edp_send_replay_cmd = edp_send_replay_cmd; link_srv->edp_send_replay_cmd = edp_send_replay_cmd;
link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal; link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal;
link_srv->edp_replay_residency = edp_replay_residency; link_srv->edp_replay_residency = edp_replay_residency;
link_srv->edp_set_replay_power_opt_and_coasting_vtotal = edp_set_replay_power_opt_and_coasting_vtotal;
link_srv->edp_wait_for_t12 = edp_wait_for_t12; link_srv->edp_wait_for_t12 = edp_wait_for_t12;
link_srv->edp_is_ilr_optimization_required = link_srv->edp_is_ilr_optimization_required =
......
...@@ -1068,6 +1068,33 @@ bool edp_replay_residency(const struct dc_link *link, ...@@ -1068,6 +1068,33 @@ bool edp_replay_residency(const struct dc_link *link,
return true; return true;
} }
bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
const unsigned int *power_opts, uint16_t coasting_vtotal)
{
struct dc *dc = link->ctx->dc;
struct dmub_replay *replay = dc->res_pool->replay;
unsigned int panel_inst;
if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
return false;
/* Only both power and coasting vtotal changed, this func could return true */
if (power_opts && link->replay_settings.replay_power_opt_active != *power_opts &&
coasting_vtotal && link->replay_settings.coasting_vtotal != coasting_vtotal) {
if (link->replay_settings.replay_feature_enabled &&
replay->funcs->replay_set_power_opt_and_coasting_vtotal) {
replay->funcs->replay_set_power_opt_and_coasting_vtotal(replay,
*power_opts, panel_inst, coasting_vtotal);
link->replay_settings.replay_power_opt_active = *power_opts;
link->replay_settings.coasting_vtotal = coasting_vtotal;
} else
return false;
} else
return false;
return true;
}
static struct abm *get_abm_from_stream_res(const struct dc_link *link) static struct abm *get_abm_from_stream_res(const struct dc_link *link)
{ {
int i; int i;
......
...@@ -63,6 +63,8 @@ bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal); ...@@ -63,6 +63,8 @@ bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal);
bool edp_replay_residency(const struct dc_link *link, bool edp_replay_residency(const struct dc_link *link,
unsigned int *residency, const bool is_start, const bool is_alpm); unsigned int *residency, const bool is_start, const bool is_alpm);
bool edp_get_replay_state(const struct dc_link *link, uint64_t *state); bool edp_get_replay_state(const struct dc_link *link, uint64_t *state);
bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
const unsigned int *power_opts, uint16_t coasting_vtotal);
bool edp_wait_for_t12(struct dc_link *link); bool edp_wait_for_t12(struct dc_link *link);
bool edp_is_ilr_optimization_required(struct dc_link *link, bool edp_is_ilr_optimization_required(struct dc_link *link,
struct dc_crtc_timing *crtc_timing); struct dc_crtc_timing *crtc_timing);
......
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
#include "reg_helper.h" #include "reg_helper.h"
#include "dce/dmub_abm.h" #include "dce/dmub_abm.h"
#include "dce/dmub_psr.h" #include "dce/dmub_psr.h"
#include "dce/dmub_replay.h"
#include "dce/dce_aux.h" #include "dce/dce_aux.h"
#include "dce/dce_i2c.h" #include "dce/dce_i2c.h"
#include "dml/dcn31/display_mode_vba_31.h" /*temp*/ #include "dml/dcn31/display_mode_vba_31.h" /*temp*/
...@@ -788,6 +789,7 @@ static const struct dc_panel_config panel_config_defaults = { ...@@ -788,6 +789,7 @@ static const struct dc_panel_config panel_config_defaults = {
.psr = { .psr = {
.disable_psr = false, .disable_psr = false,
.disallow_psrsu = false, .disallow_psrsu = false,
.disallow_replay = false,
}, },
.ilr = { .ilr = {
.optimize_edp_link_rate = true, .optimize_edp_link_rate = true,
...@@ -1546,6 +1548,9 @@ static void dcn35_resource_destruct(struct dcn35_resource_pool *pool) ...@@ -1546,6 +1548,9 @@ static void dcn35_resource_destruct(struct dcn35_resource_pool *pool)
if (pool->base.psr != NULL) if (pool->base.psr != NULL)
dmub_psr_destroy(&pool->base.psr); dmub_psr_destroy(&pool->base.psr);
if (pool->base.replay != NULL)
dmub_replay_destroy(&pool->base.replay);
if (pool->base.pg_cntl != NULL) if (pool->base.pg_cntl != NULL)
dcn_pg_cntl_destroy(&pool->base.pg_cntl); dcn_pg_cntl_destroy(&pool->base.pg_cntl);
...@@ -2030,6 +2035,14 @@ static bool dcn35_resource_construct( ...@@ -2030,6 +2035,14 @@ static bool dcn35_resource_construct(
goto create_fail; goto create_fail;
} }
/* Replay */
pool->base.replay = dmub_replay_create(ctx);
if (pool->base.replay == NULL) {
dm_error("DC: failed to create replay obj!\n");
BREAK_TO_DEBUGGER();
goto create_fail;
}
/* ABM */ /* ABM */
for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
pool->base.multiple_abms[i] = dmub_abm_create(ctx, pool->base.multiple_abms[i] = dmub_abm_create(ctx,
......
...@@ -973,6 +973,34 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link, ...@@ -973,6 +973,34 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
return true; return true;
} }
void set_replay_coasting_vtotal(struct dc_link *link,
enum replay_coasting_vtotal_type type,
uint16_t vtotal)
{
link->replay_settings.coasting_vtotal_table[type] = vtotal;
}
void calculate_replay_link_off_frame_count(struct dc_link *link,
uint16_t vtotal, uint16_t htotal)
{
uint8_t max_link_off_frame_count = 0;
uint16_t max_deviation_line = 0, pixel_deviation_per_line = 0;
max_deviation_line = link->dpcd_caps.pr_info.max_deviation_line;
pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line;
if (htotal != 0 && vtotal != 0)
max_link_off_frame_count = htotal * max_deviation_line / (pixel_deviation_per_line * vtotal);
else
ASSERT(0);
link->replay_settings.link_off_frame_count_level =
max_link_off_frame_count >= PR_LINK_OFF_FRAME_COUNT_BEST ? PR_LINK_OFF_FRAME_COUNT_BEST :
max_link_off_frame_count >= PR_LINK_OFF_FRAME_COUNT_GOOD ? PR_LINK_OFF_FRAME_COUNT_GOOD :
PR_LINK_OFF_FRAME_COUNT_FAIL;
}
bool fill_custom_backlight_caps(unsigned int config_no, struct dm_acpi_atif_backlight_caps *caps) bool fill_custom_backlight_caps(unsigned int config_no, struct dm_acpi_atif_backlight_caps *caps)
{ {
unsigned int data_points_size; unsigned int data_points_size;
......
...@@ -54,6 +54,11 @@ bool dmub_init_abm_config(struct resource_pool *res_pool, ...@@ -54,6 +54,11 @@ bool dmub_init_abm_config(struct resource_pool *res_pool,
unsigned int inst); unsigned int inst);
void init_replay_config(struct dc_link *link, struct replay_config *pr_config); void init_replay_config(struct dc_link *link, struct replay_config *pr_config);
void set_replay_coasting_vtotal(struct dc_link *link,
enum replay_coasting_vtotal_type type,
uint16_t vtotal);
void calculate_replay_link_off_frame_count(struct dc_link *link,
uint16_t vtotal, uint16_t htotal);
bool is_psr_su_specific_panel(struct dc_link *link); bool is_psr_su_specific_panel(struct dc_link *link);
void mod_power_calc_psr_configs(struct psr_config *psr_config, void mod_power_calc_psr_configs(struct psr_config *psr_config,
......
...@@ -257,6 +257,7 @@ enum DC_DEBUG_MASK { ...@@ -257,6 +257,7 @@ enum DC_DEBUG_MASK {
DC_ENABLE_DPIA_TRACE = 0x80, DC_ENABLE_DPIA_TRACE = 0x80,
DC_ENABLE_DML2 = 0x100, DC_ENABLE_DML2 = 0x100,
DC_DISABLE_PSR_SU = 0x200, DC_DISABLE_PSR_SU = 0x200,
DC_DISABLE_REPLAY = 0x400,
}; };
enum amd_dpm_forced_level; enum amd_dpm_forced_level;
......
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