drm/amd/display: apply two different methods to validate modes

[Why]
In DML2, the current method to determine a
mode is supported involves checking the
voltage levels sequentially from the lowest,
until one is found that can support the
mode. It causes cursor lag due to low
performance.

[How]
We apply two methods for mode validation.
1) DC_VALIDATE_MODE_ONLY: only the
maximum voltage level is checked to
determine whether the mode is supported, which
improves performance and eliminate cursor lag.

2) DC_VALIDATE_MODE_AND_STATE_INDEX: when
the optimal voltage level is required, check
the voltage level from the lowest until
a suitable one is found found and returns
its index.

Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Yan Li <yan.li@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Yan Li
2025-05-21 16:02:55 -04:00
committed by Alex Deucher
parent 54f7a24e14
commit b02b0fc488
3 changed files with 42 additions and 25 deletions
@@ -10189,7 +10189,7 @@ dml_uint_t dml_mode_support_ex(struct dml_mode_support_ex_params_st *in_out_para
result = mode_support_pwr_states(&in_out_params->out_lowest_state_idx,
in_out_params->mode_lib,
in_out_params->in_display_cfg,
0,
in_out_params->in_start_state_idx,
in_out_params->mode_lib->states.num_states - 1);
if (result)
@@ -1917,6 +1917,7 @@ struct display_mode_lib_st {
struct dml_mode_support_ex_params_st {
struct display_mode_lib_st *mode_lib;
const struct dml_display_cfg_st *in_display_cfg;
dml_uint_t in_start_state_idx;
dml_uint_t out_lowest_state_idx;
struct dml_mode_support_info_st *out_evaluation_info;
};
@@ -93,12 +93,17 @@ static void map_hw_resources(struct dml2_context *dml2,
static unsigned int pack_and_call_dml_mode_support_ex(struct dml2_context *dml2,
const struct dml_display_cfg_st *display_cfg,
struct dml_mode_support_info_st *evaluation_info)
struct dml_mode_support_info_st *evaluation_info,
enum dc_validate_mode validate_mode)
{
struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
s->mode_support_params.mode_lib = &dml2->v20.dml_core_ctx;
s->mode_support_params.in_display_cfg = display_cfg;
if (validate_mode == DC_VALIDATE_MODE_ONLY)
s->mode_support_params.in_start_state_idx = dml2->v20.dml_core_ctx.states.num_states - 1;
else
s->mode_support_params.in_start_state_idx = 0;
s->mode_support_params.out_evaluation_info = evaluation_info;
memset(evaluation_info, 0, sizeof(struct dml_mode_support_info_st));
@@ -224,7 +229,8 @@ static bool optimize_configuration(struct dml2_context *dml2, struct dml2_wrappe
return optimization_done;
}
static int calculate_lowest_supported_state_for_temp_read(struct dml2_context *dml2, struct dc_state *display_state)
static int calculate_lowest_supported_state_for_temp_read(struct dml2_context *dml2, struct dc_state *display_state,
enum dc_validate_mode validate_mode)
{
struct dml2_calculate_lowest_supported_state_for_temp_read_scratch *s = &dml2->v20.scratch.dml2_calculate_lowest_supported_state_for_temp_read_scratch;
struct dml2_wrapper_scratch *s_global = &dml2->v20.scratch;
@@ -266,7 +272,8 @@ static int calculate_lowest_supported_state_for_temp_read(struct dml2_context *d
dml2->v20.dml_core_ctx.states.state_array[j].dram_clock_change_latency_us = s_global->dummy_pstate_table[i].dummy_pstate_latency_us;
}
dml_result = pack_and_call_dml_mode_support_ex(dml2, &s->cur_display_config, &s->evaluation_info);
dml_result = pack_and_call_dml_mode_support_ex(dml2, &s->cur_display_config, &s->evaluation_info,
validate_mode);
if (dml_result && s->evaluation_info.DRAMClockChangeSupport[0] == dml_dram_clock_change_vactive) {
map_hw_resources(dml2, &s->cur_display_config, &s->evaluation_info);
@@ -331,7 +338,8 @@ static bool does_configuration_meet_sw_policies(struct dml2_context *ctx, const
}
static bool dml_mode_support_wrapper(struct dml2_context *dml2,
struct dc_state *display_state)
struct dc_state *display_state,
enum dc_validate_mode validate_mode)
{
struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
unsigned int result = 0, i;
@@ -367,7 +375,8 @@ static bool dml_mode_support_wrapper(struct dml2_context *dml2,
result = pack_and_call_dml_mode_support_ex(dml2,
&s->cur_display_config,
&s->mode_support_info);
&s->mode_support_info,
validate_mode);
if (result)
result = does_configuration_meet_sw_policies(dml2, &s->cur_display_config, &s->mode_support_info);
@@ -388,7 +397,8 @@ static bool dml_mode_support_wrapper(struct dml2_context *dml2,
dml2->v20.dml_core_ctx.policy = s->new_policy;
optimized_result = pack_and_call_dml_mode_support_ex(dml2,
&s->new_display_config,
&s->mode_support_info);
&s->mode_support_info,
validate_mode);
if (optimized_result)
optimized_result = does_configuration_meet_sw_policies(dml2, &s->new_display_config, &s->mode_support_info);
@@ -407,7 +417,8 @@ static bool dml_mode_support_wrapper(struct dml2_context *dml2,
if (!optimized_result) {
result = pack_and_call_dml_mode_support_ex(dml2,
&s->cur_display_config,
&s->mode_support_info);
&s->mode_support_info,
validate_mode);
}
}
@@ -432,7 +443,8 @@ static int find_drr_eligible_stream(struct dc_state *display_state)
return -1;
}
static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct dc_state *display_state)
static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct dc_state *display_state,
enum dc_validate_mode validate_mode)
{
struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
bool pstate_optimization_done = false;
@@ -444,7 +456,7 @@ static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct d
display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;
display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false;
result = dml_mode_support_wrapper(dml2, display_state);
result = dml_mode_support_wrapper(dml2, display_state, validate_mode);
if (!result) {
pstate_optimization_done = true;
@@ -456,7 +468,7 @@ static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct d
if (display_state->stream_count == 1 && dml2->config.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch(dml2->config.callbacks.dc, display_state)) {
display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = true;
result = dml_mode_support_wrapper(dml2, display_state);
result = dml_mode_support_wrapper(dml2, display_state, validate_mode);
} else {
non_svp_streams = display_state->stream_count;
@@ -471,7 +483,7 @@ static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct d
if (result) {
result = dml_mode_support_wrapper(dml2, display_state);
result = dml_mode_support_wrapper(dml2, display_state, validate_mode);
} else {
pstate_optimization_done = true;
}
@@ -496,7 +508,8 @@ static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct d
if (dml2_svp_drr_schedulable(dml2, display_state, &display_state->streams[drr_display_index]->timing)) {
display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = true;
display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index = drr_display_index;
result = dml_mode_support_wrapper(dml2, display_state);
result = dml_mode_support_wrapper(dml2, display_state,
validate_mode);
}
if (result && s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported) {
@@ -522,13 +535,13 @@ static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct d
dml2_svp_remove_all_phantom_pipes(dml2, display_state);
display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;
display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false;
result = dml_mode_support_wrapper(dml2, display_state);
result = dml_mode_support_wrapper(dml2, display_state, validate_mode);
}
return result;
}
static bool call_dml_mode_support_and_programming(struct dc_state *context)
static bool call_dml_mode_support_and_programming(struct dc_state *context, enum dc_validate_mode validate_mode)
{
unsigned int result = 0;
unsigned int min_state = 0;
@@ -542,15 +555,16 @@ static bool call_dml_mode_support_and_programming(struct dc_state *context)
struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
if (!context->streams[0]->sink->link->dc->caps.is_apu) {
min_state_for_g6_temp_read = calculate_lowest_supported_state_for_temp_read(dml2, context);
min_state_for_g6_temp_read = calculate_lowest_supported_state_for_temp_read(dml2, context,
validate_mode);
ASSERT(min_state_for_g6_temp_read >= 0);
}
if (!dml2->config.use_native_pstate_optimization) {
result = optimize_pstate_with_svp_and_drr(dml2, context);
result = optimize_pstate_with_svp_and_drr(dml2, context, validate_mode);
} else {
result = dml_mode_support_wrapper(dml2, context);
result = dml_mode_support_wrapper(dml2, context, validate_mode);
}
/* Upon trying to sett certain frequencies in FRL, min_state_for_g6_temp_read is reported as -1. This leads to an invalid value of min_state causing crashes later on.
@@ -573,7 +587,8 @@ static bool call_dml_mode_support_and_programming(struct dc_state *context)
return result;
}
static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_state *context)
static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_state *context,
enum dc_validate_mode validate_mode)
{
struct dml2_context *dml2 = context->bw_ctx.dml2;
struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
@@ -609,7 +624,7 @@ static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_s
copy_dummy_pstate_table(s->dummy_pstate_table, in_dc->clk_mgr->bw_params->dummy_pstate_table, 4);
result = call_dml_mode_support_and_programming(context);
result = call_dml_mode_support_and_programming(context, validate_mode);
/* Call map dc pipes to map the pipes based on the DML output. For correctly determining if recalculation
* is required or not, the resource context needs to correctly reflect the number of active pipes. We would
* only know the correct number if active pipes after dml2_map_dc_pipes is called.
@@ -626,7 +641,7 @@ static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_s
need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch);
if (need_recalculation) {
/* Engage the DML again if recalculation is required. */
call_dml_mode_support_and_programming(context);
call_dml_mode_support_and_programming(context, validate_mode);
if (!dml2->config.skip_hw_state_mapping) {
dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state);
}
@@ -682,7 +697,7 @@ static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_s
return result;
}
static bool dml2_validate_only(struct dc_state *context)
static bool dml2_validate_only(struct dc_state *context, enum dc_validate_mode validate_mode)
{
struct dml2_context *dml2;
unsigned int result = 0;
@@ -706,7 +721,8 @@ static bool dml2_validate_only(struct dc_state *context)
result = pack_and_call_dml_mode_support_ex(dml2,
&dml2->v20.scratch.cur_display_config,
&dml2->v20.scratch.mode_support_info);
&dml2->v20.scratch.mode_support_info,
validate_mode);
if (result)
result = does_configuration_meet_sw_policies(dml2, &dml2->v20.scratch.cur_display_config, &dml2->v20.scratch.mode_support_info);
@@ -740,9 +756,9 @@ bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2
/* Use dml_validate_only for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX path */
if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING)
out = dml2_validate_only(context);
out = dml2_validate_only(context, validate_mode);
else
out = dml2_validate_and_build_resource(in_dc, context);
out = dml2_validate_and_build_resource(in_dc, context, validate_mode);
DC_FP_END();