mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 06:41:39 -04:00
drm/amd/display: Add DCN42 PMO policy for DML2.1
[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 <dillon.varone@amd.com> Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Signed-off-by: Roman Li <roman.li@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
committed by
Alex Deucher
parent
136d15b077
commit
bcfeed1748
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user