From: Alexander Chechik <[email protected]> [Why] mode_support does not require UCLK pstate today, so later PMO optimization stages can push a plane's VActive latency-hiding margin below zero without rechecking that the config still supports UCLK pstate. This can blank the display on high-bandwidth configs.
[How] Plumb the PMO-selected per-plane pstate method into mode_support and fail the config only when UCLK pstate is required (method != na) but not supported. For planes committed to a vactive method, require a non-negative VActive latency-hiding margin, and skip the check when all streams are blanked. No-op the PMO DCN42 pstate test (returning false only on the initial candidate so the optimize/FAMS2 stage-3 setup still runs), since reserved time is guaranteed by the override and the vactive margin is now enforced in core mode_support. Reviewed-by: Dillon Varone <[email protected]> Signed-off-by: Alexander Chechik <[email protected]> Signed-off-by: Matthew Stewart <[email protected]> Tested-by: Dan Wheeler <[email protected]> --- .../dml21/src/dml2_core/dml2_core_dcn4.c | 8 +++++ .../src/dml2_core/dml2_core_dcn4_calcs.c | 18 +++++++++++ .../dml21/src/dml2_pmo/dml2_pmo_dcn42.c | 32 ++++++------------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c index 727b01ca18bf..45f1bf5e14bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c @@ -554,6 +554,14 @@ bool core_dcn4_mode_support(struct dml2_core_mode_support_in_out *in_out) l->mode_support_ex_params.min_clk_index = in_out->min_clk_index; l->mode_support_ex_params.out_evaluation_info = &in_out->mode_support_result.cfg_support_info.clean_me_up.support_info; + for (i = 0; i < l->svp_expanded_display_cfg.num_planes; i++) { + if (i < in_out->display_cfg->display_config.num_planes) + core->clean_me_up.mode_lib.ms.uclk_pstate_switch_modes[i] = + in_out->display_cfg->stage3.pstate_switch_modes[i]; + else + core->clean_me_up.mode_lib.ms.uclk_pstate_switch_modes[i] = dml2_pstate_method_na; + } + result = dml2_core_calcs_mode_support_ex(&l->mode_support_ex_params); in_out->mode_support_result.cfg_support_info.is_supported = result; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index 110ab26a6a39..da9a1c4e2bdc 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -9637,6 +9637,22 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out DML_LOG_VERBOSE("DML::%s: ROBSupport = %u\n", __func__, mode_lib->ms.support.ROBSupport); #endif + mode_lib->ms.support.global_dram_clock_change_support_required = false; + + if (!display_cfg->overrides.all_streams_blanked) { + for (k = 0; k < mode_lib->ms.num_active_planes; k++) { + if (mode_lib->ms.uclk_pstate_switch_modes[k] == dml2_pstate_method_na) + continue; + + mode_lib->ms.support.global_dram_clock_change_support_required = true; + + if ((mode_lib->ms.uclk_pstate_switch_modes[k] == dml2_pstate_method_vactive || + mode_lib->ms.uclk_pstate_switch_modes[k] == dml2_pstate_method_fw_vactive_drr) && + mode_lib->ms.VActiveLatencyHidingMargin[k] < 0) + mode_lib->ms.support.global_dram_clock_change_supported = false; + } + } + /*Mode Support, Voltage State and SOC Configuration*/ { if (mode_lib->ms.support.ScaleRatioAndTapsSupport @@ -9683,6 +9699,8 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out && mode_lib->ms.support.DCCMetaBufferSizeNotExceeded && !mode_lib->ms.support.ExceededMALLSize && mode_lib->ms.support.g6_temp_read_support + && (mode_lib->ms.support.global_dram_clock_change_supported + || !mode_lib->ms.support.global_dram_clock_change_support_required) && ((!display_cfg->hostvm_enable && !s->ImmediateFlipRequired) || mode_lib->ms.support.ImmediateFlipSupport)) { DML_LOG_VERBOSE("DML::%s: mode is supported\n", __func__); mode_lib->ms.support.ModeSupport = true; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c index 790aef95caa6..57a6a7d5b740 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c @@ -13,8 +13,6 @@ * configurations, ensuring p-state watermark support in the blank period only. */ -static const double MIN_VACTIVE_MARGIN_PCT = 0.25; // We need more than non-zero margin because DET buffer granularity can alter vactive latency hiding - static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_1_display[] = { // VBlank only { @@ -179,7 +177,7 @@ bool pmo_dcn42_init_for_pstate_support(struct dml2_pmo_init_for_pstate_support_i // Figure out which streams can do vactive, and also build up implicit SVP and FAMS2 meta for (stream_index = 0; stream_index < display_config->display_config.num_streams; stream_index++) { - if (dcn4_get_vactive_pstate_margin(display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) >= (int)(MIN_VACTIVE_MARGIN_PCT * pmo->soc_bb->power_management_parameters.dram_clk_change_blackout_us)) + if (dcn4_get_vactive_pstate_margin(display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) >= 0) dcn42_set_bit_in_bitfield(&s->pmo_dcn4.stream_vactive_capability_mask, stream_index); } @@ -259,27 +257,17 @@ bool pmo_dcn42_fams2_optimize_for_pstate_support(struct dml2_pmo_optimize_for_ps bool pmo_dcn42_test_for_pstate_support(struct dml2_pmo_test_for_pstate_support_in_out *in_out) { - const struct dml2_pmo_scratch *s = &in_out->instance->scratch; - bool p_state_supported = true; - unsigned int stream_index; - - if (s->pmo_dcn4.cur_pstate_candidate < 0) + /* Return false on the initial candidate (cur_pstate_candidate == -1) so the + * optimization phase runs at least one optimize iteration; otherwise the + * FAMS2/stage-3 setup in the optimize callback is skipped. + */ + if (in_out->instance->scratch.pmo_dcn4.cur_pstate_candidate < 0) return false; - for (stream_index = 0; stream_index < in_out->base_display_config->display_config.num_streams; stream_index++) { - if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive) { - if (dcn4_get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (int)in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us || - dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (int)(MIN_VACTIVE_MARGIN_PCT * in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us)) { - p_state_supported = false; - break; - } - } else { - p_state_supported = false; - break; - } - } - - return p_state_supported; + /* No-op: reserved time is guaranteed by the override and vactive p-state + * margin is now enforced in core mode support. + */ + return true; } bool pmo_dcn42_initialize(struct dml2_pmo_initialize_in_out *in_out) -- 2.53.0
