From: Nicholas Kazlauskas <[email protected]> [Why] The MinTTU policy in DML2.1 does not guarantee that we support p-state in blank. This is a delta vs dml2 and earlier revisions as the prefetch mode override has been removed in favor of a more configurable pstate optimizer.
[How] Split off DCN42 with its own PMO helpers so that we can use a simpler strategy of only allowing the mode if we support p-state in vblank and if vactive has enough latency hiding. The actual hookup to use these helpers in the PMO factory will be done in a later patch to satisfy build system requirements. Reviewed-by: Dillon Varone <[email protected]> Signed-off-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Roman Li <[email protected]> --- .../gpu/drm/amd/display/dc/dml2_0/Makefile | 1 + .../dml21/src/dml2_pmo/dml2_pmo_dcn42.c | 192 ++++++++++++++++++ .../dml21/src/dml2_pmo/dml2_pmo_dcn42.h | 17 ++ .../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c | 16 +- .../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h | 10 + 5 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile index 2625943d7f7e..8a451c36fdb3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile @@ -100,6 +100,7 @@ DML21 += src/dml2_mcg/dml2_mcg_factory.o DML21 += src/dml2_pmo/dml2_pmo_dcn3.o DML21 += src/dml2_pmo/dml2_pmo_factory.o DML21 += src/dml2_pmo/dml2_pmo_dcn4_fams2.o +DML21 += src/dml2_pmo/dml2_pmo_dcn42.o DML21 += src/dml2_standalone_libraries/lib_float_math.o DML21 += dml21_translation_helper.o DML21 += dml21_wrapper.o 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 new file mode 100644 index 000000000000..30fd5efe4b87 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2026 Advanced Micro Devices, Inc. + +#include "dml2_pmo_dcn42.h" +#include "lib_float_math.h" +#include "dml2_debug.h" +#include "dml2_pmo_dcn4_fams2.h" + +/* + * DCN42 PMO Policy Implementation + * This implementation provides VBlank-only strategies for 1, 2, 3, and 4 display + * configurations, ensuring p-state watermark support in the blank period only. + */ + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_1_display[] = { + // VBlank only + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_1_display_size = sizeof(dcn42_strategy_list_1_display) / sizeof(struct dml2_pmo_pstate_strategy); + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_2_display[] = { + // VBlank only for both displays + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_2_display_size = sizeof(dcn42_strategy_list_2_display) / sizeof(struct dml2_pmo_pstate_strategy); + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_3_display[] = { + // VBlank only for all three displays + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_3_display_size = sizeof(dcn42_strategy_list_3_display) / sizeof(struct dml2_pmo_pstate_strategy); + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_4_display[] = { + // VBlank only for all four displays + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_4_display_size = sizeof(dcn42_strategy_list_4_display) / sizeof(struct dml2_pmo_pstate_strategy); + +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; + const int REQUIRED_RESERVED_TIME = + (int)in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us; + bool p_state_supported = true; + unsigned int stream_index; + + if (in_out->base_display_config->display_config.overrides.all_streams_blanked) + return true; + + if (s->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_vblank) { + if (dcn4_get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < REQUIRED_RESERVED_TIME || + dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) > 0) { + p_state_supported = false; + break; + } + } else { + p_state_supported = false; + break; + } + } + + return p_state_supported; +} + +bool pmo_dcn42_initialize(struct dml2_pmo_initialize_in_out *in_out) +{ + int i = 0; + struct dml2_pmo_instance *pmo = in_out->instance; + + unsigned int base_list_size = 0; + const struct dml2_pmo_pstate_strategy *base_list = NULL; + unsigned int *expanded_list_size = NULL; + struct dml2_pmo_pstate_strategy *expanded_list = NULL; + + DML_LOG_COMP_IF_ENTER(); + + pmo->soc_bb = in_out->soc_bb; + pmo->ip_caps = in_out->ip_caps; + pmo->mpc_combine_limit = 2; + pmo->odm_combine_limit = 4; + pmo->mcg_clock_table_size = in_out->mcg_clock_table_size; + + /* + * DCN42 does not support FAMS features like SubVP and DRR. + * These parameters are initialized to safe values but won't be used + * since our strategies only use VBlank. + */ + pmo->fams_params.v2.subvp.refresh_rate_limit_max = 0; + pmo->fams_params.v2.subvp.refresh_rate_limit_min = 0; + pmo->fams_params.v2.drr.refresh_rate_limit_max = 0; + pmo->fams_params.v2.drr.refresh_rate_limit_min = 0; + + pmo->options = in_out->options; + + /* Generate permutations of p-state configs from base strategy list */ + for (i = 0; i < PMO_DCN4_MAX_DISPLAYS; i++) { + switch (i+1) { + case 1: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_1_display; + base_list_size = dcn42_strategy_list_1_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_1_display; + + break; + case 2: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_2_display; + base_list_size = dcn42_strategy_list_2_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_2_display; + + break; + case 3: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_3_display; + base_list_size = dcn42_strategy_list_3_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_3_display; + + break; + case 4: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_4_display; + base_list_size = dcn42_strategy_list_4_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_4_display; + + break; + } + + DML_ASSERT(base_list_size <= PMO_DCN4_MAX_BASE_STRATEGIES); + + /* + * Populate list using DCN4 FAMS2 expansion function. + * Since our strategies only contain VBlank methods, the expansion + * will not introduce any FAMS-specific logic. + */ + pmo_dcn4_fams2_expand_base_pstate_strategies( + base_list, + base_list_size, + i + 1, + expanded_list, + expanded_list_size); + } + + DML_LOG_DEBUG("%s exit with true\n", __func__); + DML_LOG_COMP_IF_EXIT(); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h new file mode 100644 index 000000000000..31ba8575351d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#ifndef __DML2_PMO_DCN42_H__ +#define __DML2_PMO_DCN42_H__ + +#include "dml2_internal_shared_types.h" + +struct dml2_pmo_initialize_in_out; +struct dml2_pmo_test_for_pstate_support_in_out; + +bool pmo_dcn42_initialize(struct dml2_pmo_initialize_in_out *in_out); +bool pmo_dcn42_test_for_pstate_support(struct dml2_pmo_test_for_pstate_support_in_out *in_out); + +#endif /* __DML2_PMO_DCN42_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c index f7c10dbfc154..b348c65a0f75 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c @@ -1662,7 +1662,7 @@ static bool validate_pstate_support_strategy_cofunctionality(struct dml2_pmo_ins return is_config_schedulable(pmo, display_cfg, pstate_strategy); } -static int get_vactive_pstate_margin(const struct display_configuation_with_meta *display_cfg, int plane_mask) +int dcn4_get_vactive_pstate_margin(const struct display_configuation_with_meta *display_cfg, int plane_mask) { unsigned int i; int min_vactive_margin_us = 0xFFFFFFF; @@ -1907,7 +1907,7 @@ bool pmo_dcn4_fams2_init_for_pstate_support(struct dml2_pmo_init_for_pstate_supp // 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 (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]) >= (int)(MIN_VACTIVE_MARGIN_PCT * pmo->soc_bb->power_management_parameters.dram_clk_change_blackout_us)) set_bit_in_bitfield(&s->pmo_dcn4.stream_vactive_capability_mask, stream_index); /* FAMS2 meta */ @@ -2182,7 +2182,9 @@ static bool setup_display_config(struct display_configuation_with_meta *display_ return success; } -static int get_minimum_reserved_time_us_for_planes(struct display_configuation_with_meta *display_config, int plane_mask) +int dcn4_get_minimum_reserved_time_us_for_planes( + const struct display_configuation_with_meta *display_config, + int plane_mask) { int min_time_us = 0xFFFFFF; unsigned int plane_index = 0; @@ -2222,16 +2224,16 @@ bool pmo_dcn4_fams2_test_for_pstate_support(struct dml2_pmo_test_for_pstate_supp if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive || s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vactive_drr) { - if (get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (MIN_VACTIVE_MARGIN_PCT * in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us) || + if (dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (MIN_VACTIVE_MARGIN_PCT * in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us) || get_vactive_det_fill_latency_delay_us(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) > stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_us) { p_state_supported = false; break; } } else if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vblank || s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vblank_drr) { - if (get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < + if (dcn4_get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < REQUIRED_RESERVED_TIME || - get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_VBLANK) { + dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_VBLANK) { p_state_supported = false; break; } @@ -2243,7 +2245,7 @@ bool pmo_dcn4_fams2_test_for_pstate_support(struct dml2_pmo_test_for_pstate_supp } } else if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_drr) { if (!all_planes_match_method(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index], dml2_pstate_method_fw_drr) || - get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_DRR) { + dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_DRR) { p_state_supported = false; break; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h index 6baab7ad6ecc..f0afa8002a2f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h @@ -7,6 +7,16 @@ #include "dml2_internal_shared_types.h" +struct display_configuation_with_meta; + +int dcn4_get_vactive_pstate_margin( + const struct display_configuation_with_meta *display_cfg, + int plane_mask); + +int dcn4_get_minimum_reserved_time_us_for_planes( + const struct display_configuation_with_meta *display_config, + int plane_mask); + bool pmo_dcn4_fams2_initialize(struct dml2_pmo_initialize_in_out *in_out); bool pmo_dcn4_fams2_optimize_dcc_mcache(struct dml2_pmo_optimize_dcc_mcache_in_out *in_out); -- 2.34.1
