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]
The policy has been added in a prior patch, this patch enables it based
on pmo flag.

Reviewed-by: Dillon Varone <[email protected]>
Signed-off-by: Nicholas Kazlauskas <[email protected]>
Signed-off-by: Ivan Lipski <[email protected]>
---
 .../dml2_0/dml21/dml21_translation_helper.c   |   5 +-
 .../dc/dml2_0/dml21/inc/dml_top_types.h       |   1 +
 .../dml21/src/dml2_pmo/dml2_pmo_dcn42.c       | 144 ++++++++++++++++--
 .../dml21/src/dml2_pmo/dml2_pmo_dcn42.h       |   1 +
 .../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c  |   4 -
 .../dml21/src/dml2_pmo/dml2_pmo_factory.c     |  16 ++
 .../dml21/src/dml2_top/dml2_top_soc15.c       |  30 +++-
 .../drm/amd/display/dc/dml2_0/dml2_wrapper.h  |   1 +
 8 files changed, 184 insertions(+), 18 deletions(-)

diff --git 
a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
index 25557c99a28e..f849fb882b2a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
@@ -36,6 +36,8 @@ static void dml21_populate_pmo_options(struct 
dml2_pmo_options *pmo_options,
        pmo_options->disable_drr_var_when_var_active = 
in_dc->debug.disable_fams_gaming == INGAME_FAMS_DISABLE ||
                        in_dc->debug.disable_fams_gaming == 
INGAME_FAMS_MULTI_DISP_CLAMPED_ONLY;
        pmo_options->disable_drr_clamped_when_var_active = 
in_dc->debug.disable_fams_gaming == INGAME_FAMS_DISABLE;
+
+       pmo_options->force_mandatory_uclk_pstate_support = 
config->pmo.force_mandatory_uclk_pstate_support;
 }
 
 static enum dml2_project_id dml21_dcn_revision_to_dml2_project_id(enum 
dce_version dcn_version)
@@ -690,7 +692,8 @@ static void 
populate_dml21_plane_config_from_plane_state(struct dml2_context *dm
        plane->overrides.gpuvm_min_page_size_kbytes = 
soc_bb->gpuvm_min_page_size_kbytes;
        plane->overrides.hostvm_min_page_size_kbytes = 
soc_bb->hostvm_min_page_size_kbytes;
 
-       plane->immediate_flip = plane_state->flip_immediate;
+       //Always true for DAL, we want to validate the worst case scenario as 
we have to switch b/w the two without possibility of failure.
+       plane->immediate_flip = true;
 
        plane->composition.rect_out_height_spans_vactive =
                plane_state->dst_rect.height >= stream->src.height &&
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
index dff903a103db..8d7960a340c2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
@@ -71,6 +71,7 @@ struct dml2_pmo_options {
        bool disable_dyn_odm;
        bool disable_dyn_odm_for_multi_stream;
        bool disable_dyn_odm_for_stream_with_svp;
+       bool force_mandatory_uclk_pstate_support;
        struct dml2_pmo_pstate_strategy 
*override_strategy_lists[DML2_MAX_PLANES];
        unsigned int num_override_strategies_per_list[DML2_MAX_PLANES];
 };
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 30fd5efe4b87..4e0d757388ca 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,10 +13,12 @@
  * 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
        {
-               .per_stream_pstate_method = { dml2_pstate_method_vblank, 
dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
+               .per_stream_pstate_method = { dml2_pstate_method_vactive, 
dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
                .allow_state_increase = true,
        },
 };
@@ -26,7 +28,7 @@ static const int dcn42_strategy_list_1_display_size = 
sizeof(dcn42_strategy_list
 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 },
+               .per_stream_pstate_method = { dml2_pstate_method_vactive, 
dml2_pstate_method_vactive, dml2_pstate_method_na, dml2_pstate_method_na },
                .allow_state_increase = true,
        },
 };
@@ -36,7 +38,7 @@ static const int dcn42_strategy_list_2_display_size = 
sizeof(dcn42_strategy_list
 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 },
+               .per_stream_pstate_method = { dml2_pstate_method_vactive, 
dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_na },
                .allow_state_increase = true,
        },
 };
@@ -46,31 +48,149 @@ static const int dcn42_strategy_list_3_display_size = 
sizeof(dcn42_strategy_list
 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 
},
+               .per_stream_pstate_method = { dml2_pstate_method_vactive, 
dml2_pstate_method_vactive, dml2_pstate_method_vactive, 
dml2_pstate_method_vactive },
                .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);
 
+static bool is_bit_set_in_bitfield(unsigned int bit_field, unsigned int 
bit_offset)
+{
+       if (bit_field & (0x1 << bit_offset))
+               return true;
+
+       return false;
+}
+
+static void setup_planes_for_vactive_by_mask(struct 
display_configuation_with_meta *display_config,
+       struct dml2_pmo_instance *pmo,
+       int plane_mask)
+{
+       unsigned int plane_index;
+       unsigned int stream_index;
+       struct dml2_plane_parameters *plane;
+
+       for (plane_index = 0; plane_index < 
display_config->display_config.num_planes; plane_index++) {
+               if (is_bit_set_in_bitfield(plane_mask, plane_index)) {
+                       plane = 
&display_config->display_config.plane_descriptors[plane_index];
+                       stream_index = 
display_config->display_config.plane_descriptors[plane_index].stream_index;
+
+                       plane->overrides.reserved_vblank_time_ns = 
(long)math_max2(pmo->soc_bb->power_management_parameters.dram_clk_change_blackout_us
 * 1000.0,
+                                       
plane->overrides.reserved_vblank_time_ns);
+                       if (!pmo->options->disable_vactive_det_fill_bw_pad) {
+                               
display_config->display_config.plane_descriptors[plane_index].overrides.max_vactive_det_fill_delay_us[dml2_pstate_type_uclk]
 =
+                                       (unsigned 
int)math_floor(pmo->scratch.pmo_dcn4.stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us);
+                       }
+
+                       display_config->stage3.pstate_switch_modes[plane_index] 
= dml2_pstate_method_vactive;
+               }
+       }
+}
+
+static void reset_display_configuration(struct display_configuation_with_meta 
*display_config)
+{
+       unsigned int plane_index;
+       unsigned int stream_index;
+       struct dml2_plane_parameters *plane;
+
+       for (stream_index = 0; stream_index < 
display_config->display_config.num_streams; stream_index++) {
+               display_config->stage3.stream_svp_meta[stream_index].valid = 
false;
+       }
+
+       for (plane_index = 0; plane_index < 
display_config->display_config.num_planes; plane_index++) {
+               plane = 
&display_config->display_config.plane_descriptors[plane_index];
+
+               // Unset SubVP
+               plane->overrides.legacy_svp_config = 
dml2_svp_mode_override_auto;
+
+               // Remove reserve time
+               plane->overrides.reserved_vblank_time_ns = 0;
+
+               // Reset strategy to auto
+               plane->overrides.uclk_pstate_change_strategy = 
dml2_uclk_pstate_change_strategy_auto;
+
+               display_config->stage3.pstate_switch_modes[plane_index] = 
dml2_pstate_method_na;
+       }
+}
+
+static bool setup_display_config(struct display_configuation_with_meta 
*display_config, struct dml2_pmo_instance *pmo, int strategy_index)
+{
+       struct dml2_pmo_scratch *scratch = &pmo->scratch;
+
+       bool fams2_required = false;
+       bool success = true;
+       unsigned int stream_index;
+
+       reset_display_configuration(display_config);
+
+       for (stream_index = 0; stream_index < 
display_config->display_config.num_streams; stream_index++) {
+
+               if 
(pmo->scratch.pmo_dcn4.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index]
 == dml2_pstate_method_na) {
+                       success = false;
+                       break;
+               } else if 
(scratch->pmo_dcn4.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index]
 == dml2_pstate_method_vactive) {
+                       setup_planes_for_vactive_by_mask(display_config, pmo, 
scratch->pmo_dcn4.stream_plane_mask[stream_index]);
+               }
+       }
+
+       /* copy FAMS2 meta */
+       if (success) {
+               display_config->stage3.fams2_required = fams2_required;
+               memcpy(&display_config->stage3.stream_pstate_meta,
+                       &scratch->pmo_dcn4.stream_pstate_meta,
+                       sizeof(struct dml2_pstate_meta) * DML2_MAX_PLANES);
+       }
+
+       return success;
+}
+
+bool pmo_dcn42_fams2_optimize_for_pstate_support(struct 
dml2_pmo_optimize_for_pstate_support_in_out *in_out)
+{
+       bool success = false;
+       struct dml2_pmo_scratch *s = &in_out->instance->scratch;
+
+       memcpy(in_out->optimized_display_config, in_out->base_display_config, 
sizeof(struct display_configuation_with_meta));
+
+       if (in_out->last_candidate_failed) {
+               if 
(s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].allow_state_increase
 &&
+                       s->pmo_dcn4.cur_latency_index < 
s->pmo_dcn4.max_latency_index - 1) {
+                       s->pmo_dcn4.cur_latency_index++;
+
+                       success = true;
+               }
+       }
+
+       if (!success) {
+               s->pmo_dcn4.cur_latency_index = s->pmo_dcn4.min_latency_index;
+               s->pmo_dcn4.cur_pstate_candidate++;
+
+               if (s->pmo_dcn4.cur_pstate_candidate < 
s->pmo_dcn4.num_pstate_candidates) {
+                       success = true;
+               }
+       }
+
+       if (success) {
+               
in_out->optimized_display_config->stage3.min_clk_index_for_latency = 
s->pmo_dcn4.cur_latency_index;
+               setup_display_config(in_out->optimized_display_config, 
in_out->instance, in_out->instance->scratch.pmo_dcn4.cur_pstate_candidate);
+       }
+
+       return success;
+}
+
 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) {
+               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;
                        }
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
index 31ba8575351d..5db7877bb8ca 100644
--- 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
@@ -12,6 +12,7 @@ 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_fams2_optimize_for_pstate_support(struct 
dml2_pmo_optimize_for_pstate_support_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 b348c65a0f75..8301e23ab89f 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
@@ -1884,10 +1884,6 @@ bool pmo_dcn4_fams2_init_for_pstate_support(struct 
dml2_pmo_init_for_pstate_supp
 
        memset(s, 0, sizeof(struct dml2_pmo_scratch));
 
-       if (display_config->display_config.overrides.all_streams_blanked) {
-               return true;
-       }
-
        pmo->scratch.pmo_dcn4.min_latency_index = 
in_out->base_display_config->stage1.min_clk_index_for_latency;
        pmo->scratch.pmo_dcn4.max_latency_index = pmo->mcg_clock_table_size;
        pmo->scratch.pmo_dcn4.cur_latency_index = 
in_out->base_display_config->stage1.min_clk_index_for_latency;
diff --git 
a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c
index af2ba7d08a61..a1164de13a05 100644
--- 
a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c
+++ 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c
@@ -5,6 +5,7 @@
 #include "dml2_pmo_factory.h"
 #include "dml2_pmo_dcn4_fams2.h"
 #include "dml2_pmo_dcn3.h"
+#include "dml2_pmo_dcn42.h"
 #include "dml2_external_lib_deps.h"
 
 static bool dummy_init_for_stutter(struct dml2_pmo_init_for_stutter_in_out 
*in_out)
@@ -60,6 +61,21 @@ bool dml2_pmo_create(enum dml2_project_id project_id, struct 
dml2_pmo_instance *
                result = true;
                break;
        case dml2_project_dcn42:
+               out->initialize = pmo_dcn42_initialize;
+
+               out->init_for_vmin = pmo_dcn4_fams2_init_for_vmin;
+               out->test_for_vmin = pmo_dcn4_fams2_test_for_vmin;
+               out->optimize_for_vmin = pmo_dcn4_fams2_optimize_for_vmin;
+
+               out->init_for_uclk_pstate = 
pmo_dcn4_fams2_init_for_pstate_support;
+               out->test_for_uclk_pstate = pmo_dcn42_test_for_pstate_support;
+               out->optimize_for_uclk_pstate = 
pmo_dcn42_fams2_optimize_for_pstate_support;
+
+               out->init_for_stutter = pmo_dcn4_fams2_init_for_stutter;
+               out->test_for_stutter = pmo_dcn4_fams2_test_for_stutter;
+               out->optimize_for_stutter = pmo_dcn4_fams2_optimize_for_stutter;
+               result = true;
+               break;
        case dml2_project_dcn4x_stage2_auto_drr_svp:
                out->initialize = pmo_dcn4_fams2_initialize;
 
diff --git 
a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c
index fa20a91c6e16..e6c49c27035c 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c
@@ -782,6 +782,7 @@ static bool dml2_top_soc15_check_mode_supported(struct 
dml2_check_mode_supported
 
        bool result = false;
        bool mcache_success = false;
+       bool uclk_pstate_success = false;
        memset(dpmm_programming, 0, sizeof(struct 
dml2_display_cfg_programming));
 
        setup_unoptimized_display_config_with_meta(dml, 
&l->base_display_config_with_meta, in_out->display_config);
@@ -805,6 +806,24 @@ static bool dml2_top_soc15_check_mode_supported(struct 
dml2_check_mode_supported
                mcache_success = 
dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, 
&mcache_phase);
        }
 
+       if (result) {
+               if (dml->pmo_options.force_mandatory_uclk_pstate_support) {
+                       struct optimization_phase_params uclk_phase =   {
+                       .dml = dml,
+                       .display_config = &l->base_display_config_with_meta,
+                       .init_function = 
dml2_top_optimization_init_function_uclk_pstate,
+                       .test_function = 
dml2_top_optimization_test_function_uclk_pstate,
+                       .optimize_function = 
dml2_top_optimization_optimize_function_uclk_pstate,
+                       .optimized_display_config = 
&l->optimized_display_config_with_meta,
+                       .all_or_nothing = false,
+                       };
+
+                       uclk_pstate_success = 
dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, 
&uclk_phase);
+               } else {
+                       uclk_pstate_success = true;
+               }
+       }
+
        /*
        * Call DPMM to map all requirements to minimum clock state
        */
@@ -817,7 +836,7 @@ static bool dml2_top_soc15_check_mode_supported(struct 
dml2_check_mode_supported
                result = 
dml->dpmm_instance.map_mode_to_soc_dpm(&l->dppm_map_mode_params);
        }
 
-       in_out->is_supported = mcache_success;
+       in_out->is_supported = mcache_success & uclk_pstate_success;
        result = result && in_out->is_supported;
 
        return result;
@@ -928,6 +947,15 @@ static bool dml2_top_soc15_build_mode_programming(struct 
dml2_build_mode_program
        if (uclk_pstate_success) {
                memcpy(&l->base_display_config_with_meta, 
&l->optimized_display_config_with_meta, sizeof(struct 
display_configuation_with_meta));
                l->base_display_config_with_meta.stage3.success = true;
+       } else if (dml->pmo_options.force_mandatory_uclk_pstate_support) {
+               l->informative_params.instance = &dml->core_instance;
+               l->informative_params.programming = in_out->programming;
+               l->informative_params.mode_is_supported = false;
+
+               dml->core_instance.populate_informative(&l->informative_params);
+
+               in_out->programming->informative.failed_mcache_validation = 
true;
+               return false;
        }
 
        /*
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.h 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.h
index 5ee489682f2e..2f2ae05dd59c 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.h
@@ -232,6 +232,7 @@ struct dml2_configuration_options {
        /* Only for debugging purposes when initializing SOCBB params via tool 
for DML21. */
        struct socbb_ip_params_external *external_socbb_ip_params;
        struct {
+               bool force_mandatory_uclk_pstate_support;
                bool force_pstate_method_enable;
                enum dml2_force_pstate_methods 
force_pstate_method_values[MAX_PIPES];
        } pmo;
-- 
2.43.0

Reply via email to