// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_top_optimization.h"
#include "dml2_internal_shared_types.h"
#include "dml_top_mcache.h"
static void copy_display_configuration_with_meta(struct display_configuation_with_meta *dst, const struct display_configuation_with_meta *src)
{
memcpy(dst, src, sizeof(struct display_configuation_with_meta));
}
bool dml2_top_optimization_init_function_min_clk_for_latency(const struct optimization_init_function_params *params)
{
struct dml2_optimization_stage1_state *state = ¶ms->display_config->stage1;
state->performed = true;
return true;
}
bool dml2_top_optimization_test_function_min_clk_for_latency(const struct optimization_test_function_params *params)
{
struct dml2_optimization_stage1_state *state = ¶ms->display_config->stage1;
return state->min_clk_index_for_latency == 0;
}
bool dml2_top_optimization_optimize_function_min_clk_for_latency(const struct optimization_optimize_function_params *params)
{
bool result = false;
if (params->display_config->stage1.min_clk_index_for_latency > 0) {
copy_display_configuration_with_meta(params->optimized_display_config, params->display_config);
params->optimized_display_config->stage1.min_clk_index_for_latency--;
result = true;
}
return result;
}
bool dml2_top_optimization_test_function_mcache(const struct optimization_test_function_params *params)
{
struct dml2_optimization_test_function_locals *l = params->locals;
bool mcache_success = false;
bool result = false;
memset(l, 0, sizeof(struct dml2_optimization_test_function_locals));
l->test_mcache.calc_mcache_count_params.dml2_instance = params->dml;
l->test_mcache.calc_mcache_count_params.display_config = ¶ms->display_config->display_config;
l->test_mcache.calc_mcache_count_params.mcache_allocations = params->display_config->stage2.mcache_allocations;
result = dml2_top_mcache_calc_mcache_count_and_offsets(&l->test_mcache.calc_mcache_count_params); // use core to get the basic mcache_allocations
if (result) {
l->test_mcache.assign_global_mcache_ids_params.allocations = params->display_config->stage2.mcache_allocations;
l->test_mcache.assign_global_mcache_ids_params.num_allocations = params->display_config->display_config.num_planes;
dml2_top_mcache_assign_global_mcache_ids(&l->test_mcache.assign_global_mcache_ids_params);
l->test_mcache.validate_admissibility_params.dml2_instance = params->dml;
l->test_mcache.validate_admissibility_params.display_cfg = ¶ms->display_config->display_config;
l->test_mcache.validate_admissibility_params.mcache_allocations = params->display_config->stage2.mcache_allocations;
l->test_mcache.validate_admissibility_params.cfg_support_info = ¶ms->display_config->mode_support_result.cfg_support_info;
mcache_success = dml2_top_mcache_validate_admissability(&l->test_mcache.validate_admissibility_params); // also find the shift to make mcache allocation works
memcpy(params->display_config->stage2.per_plane_mcache_support, l->test_mcache.validate_admissibility_params.per_plane_status, sizeof(bool) * DML2_MAX_PLANES);
}
return mcache_success;
}
bool dml2_top_optimization_optimize_function_mcache(const struct optimization_optimize_function_params *params)
{
struct dml2_optimization_optimize_function_locals *l = params->locals;
bool optimize_success = false;
if (params->last_candidate_supported == false)
return false;
copy_display_configuration_with_meta(params->optimized_display_config, params->display_config);
l->optimize_mcache.optimize_mcache_params.instance = ¶ms->dml->pmo_instance;
l->optimize_mcache.optimize_mcache_params.dcc_mcache_supported = params->display_config->stage2.per_plane_mcache_support;
l->optimize_mcache.optimize_mcache_params.display_config = ¶ms->display_config->display_config;
l->optimize_mcache.optimize_mcache_params.optimized_display_cfg = ¶ms->optimized_display_config->display_config;
l->optimize_mcache.optimize_mcache_params.cfg_support_info = ¶ms->optimized_display_config->mode_support_result.cfg_support_info;
optimize_success = params->dml->pmo_instance.optimize_dcc_mcache(&l->optimize_mcache.optimize_mcache_params);
return optimize_success;
}
bool dml2_top_optimization_init_function_vmin(const struct optimization_init_function_params *params)
{
struct dml2_optimization_init_function_locals *l = params->locals;
l->vmin.init_params.instance = ¶ms->dml->pmo_instance;
l->vmin.init_params.base_display_config = params->display_config;
return params->dml->pmo_instance.init_for_vmin(&l->vmin.init_params);
}
bool dml2_top_optimization_test_function_vmin(const struct optimization_test_function_params *params)
{
struct dml2_optimization_test_function_locals *l = params->locals;
l->test_vmin.pmo_test_vmin_params.instance = ¶ms->dml->pmo_instance;
l->test_vmin.pmo_test_vmin_params.display_config = params->display_config;
l->test_vmin.pmo_test_vmin_params.vmin_limits = ¶ms->dml->soc_bbox.vmin_limit;
return params->dml->pmo_instance.test_for_vmin(&l->test_vmin.pmo_test_vmin_params);
}
bool dml2_top_optimization_optimize_function_vmin(const struct optimization_optimize_function_params *params)
{
struct dml2_optimization_optimize_function_locals *l = params->locals;
if (params->last_candidate_supported == false)
return false;
l->optimize_vmin.pmo_optimize_vmin_params.instance = ¶ms->dml->pmo_instance;
l->optimize_vmin.pmo_optimize_vmin_params.base_display_config = params->display_config;
l->optimize_vmin.pmo_optimize_vmin_params.optimized_display_config = params->optimized_display_config;
return params->dml->pmo_instance.optimize_for_vmin(&l->optimize_vmin.pmo_optimize_vmin_params);
}
bool dml2_top_optimization_perform_optimization_phase(struct dml2_optimization_phase_locals *l, const struct optimization_phase_params *params)
{
bool test_passed = false;
bool optimize_succeeded = true;
bool candidate_validation_passed = true;
struct optimization_init_function_params init_params = { 0 };
struct optimization_test_function_params test_params = { 0 };
struct optimization_optimize_function_params optimize_params = { 0 };
if (!params->dml ||
!params->optimize_function ||
!params->test_function ||
!params->display_config ||
!params->optimized_display_config)
return false;
copy_display_configuration_with_meta(&l->cur_candidate_display_cfg, params->display_config);
init_params.locals = &l->init_function_locals;
init_params.dml = params->dml;
init_params.display_config = &l->cur_candidate_display_cfg;
if (params->init_function && !params->init_function(&init_params))
return false;
test_params.locals = &l->test_function_locals;
test_params.dml = params->dml;
test_params.display_config = &l->cur_candidate_display_cfg;
test_passed = params->test_function(&test_params);
while (!test_passed && optimize_succeeded) {
memset(&optimize_params, 0, sizeof(struct optimization_optimize_function_params));
optimize_params.locals = &l->optimize_function_locals;
optimize_params.dml = params->dml;
optimize_params.display_config = &l->cur_candidate_display_cfg;
optimize_params.optimized_display_config = &l->next_candidate_display_cfg;
optimize_params.last_candidate_supported = candidate_validation_passed;
optimize_succeeded = params->optimize_function(&optimize_params);
if (optimize_succeeded) {
l->mode_support_params.instance = ¶ms->dml->core_instance;
l->mode_support_params.display_cfg = &l->next_candidate_display_cfg;
l->mode_support_params.min_clk_table = ¶ms->dml->min_clk_table;
if (l->next_candidate_display_cfg.stage3.performed)
l->mode_support_params.min_clk_index = l->next_candidate_display_cfg.stage3.min_clk_index_for_latency;
else
l->mode_support_params.min_clk_index = l->next_candidate_display_cfg.stage1.min_clk_index_for_latency;
candidate_validation_passed = params->dml->core_instance.mode_support(&l->mode_support_params);
l->next_candidate_display_cfg.mode_support_result = l->mode_support_params.mode_support_result;
}
if (optimize_succeeded && candidate_validation_passed) {
memset(&test_params, 0, sizeof(struct optimization_test_function_params));
test_params.locals = &l->test_function_locals;
test_params.dml = params->dml;
test_params.display_config = &l->next_candidate_display_cfg;
test_passed = params->test_function(&test_params);
copy_display_configuration_with_meta(&l->cur_candidate_display_cfg, &l->next_candidate_display_cfg);
// If optimization is not all or nothing, then store partial progress in output
if (!params->all_or_nothing)
copy_display_configuration_with_meta(params->optimized_display_config, &l->next_candidate_display_cfg);
}
}
if (test_passed)
copy_display_configuration_with_meta(params->optimized_display_config, &l->cur_candidate_display_cfg);
return test_passed;
}
bool dml2_top_optimization_perform_optimization_phase_1(struct dml2_optimization_phase_locals *l, const struct optimization_phase_params *params)
{
int highest_state, lowest_state, cur_state;
bool supported = false;
if (!params->dml ||
!params->optimize_function ||
!params->test_function ||
!params->display_config ||
!params->optimized_display_config)
return false;
copy_display_configuration_with_meta(&l->cur_candidate_display_cfg, params->display_config);
highest_state = l->cur_candidate_display_cfg.stage1.min_clk_index_for_latency;
lowest_state = 0;
while (highest_state > lowest_state) {
cur_state = (highest_state + lowest_state) / 2;
l->mode_support_params.instance = ¶ms->dml->core_instance;
l->mode_support_params.display_cfg = &l->cur_candidate_display_cfg;
l->mode_support_params.min_clk_table = ¶ms->dml->min_clk_table;
l->mode_support_params.min_clk_index = cur_state;
supported = params->dml->core_instance.mode_support(&l->mode_support_params);
if (supported) {
l->cur_candidate_display_cfg.mode_support_result = l->mode_support_params.mode_support_result;
highest_state = cur_state;
} else {
lowest_state = cur_state + 1;
}
}
l->cur_candidate_display_cfg.stage1.min_clk_index_for_latency = lowest_state;
copy_display_configuration_with_meta(params->optimized_display_config, &l->cur_candidate_display_cfg);
return true;
}
bool dml2_top_optimization_init_function_uclk_pstate(const struct optimization_init_function_params *params)
{
struct dml2_optimization_init_function_locals *l = params->locals;
l->uclk_pstate.init_params.instance = ¶ms->dml->pmo_instance;
l->uclk_pstate.init_params.base_display_config = params->display_config;
return params->dml->pmo_instance.init_for_uclk_pstate(&l->uclk_pstate.init_params);
}
bool dml2_top_optimization_test_function_uclk_pstate(const struct optimization_test_function_params *params)
{
struct dml2_optimization_test_function_locals *l = params->locals;
l->uclk_pstate.test_params.instance = ¶ms->dml->pmo_instance;
l->uclk_pstate.test_params.base_display_config = params->display_config;
return params->dml->pmo_instance.test_for_uclk_pstate(&l->uclk_pstate.test_params);
}
bool dml2_top_optimization_optimize_function_uclk_pstate(const struct optimization_optimize_function_params *params)
{
struct dml2_optimization_optimize_function_locals *l = params->locals;
l->uclk_pstate.optimize_params.instance = ¶ms->dml->pmo_instance;
l->uclk_pstate.optimize_params.base_display_config = params->display_config;
l->uclk_pstate.optimize_params.optimized_display_config = params->optimized_display_config;
l->uclk_pstate.optimize_params.last_candidate_failed = !params->last_candidate_supported;
return params->dml->pmo_instance.optimize_for_uclk_pstate(&l->uclk_pstate.optimize_params);
}
bool dml2_top_optimization_init_function_stutter(const struct optimization_init_function_params *params)
{
struct dml2_optimization_init_function_locals *l = params->locals;
l->uclk_pstate.init_params.instance = ¶ms->dml->pmo_instance;
l->uclk_pstate.init_params.base_display_config = params->display_config;
return params->dml->pmo_instance.init_for_stutter(&l->stutter.stutter_params);
}
bool dml2_top_optimization_test_function_stutter(const struct optimization_test_function_params *params)
{
struct dml2_optimization_test_function_locals *l = params->locals;
l->stutter.stutter_params.instance = ¶ms->dml->pmo_instance;
l->stutter.stutter_params.base_display_config = params->display_config;
return params->dml->pmo_instance.test_for_stutter(&l->stutter.stutter_params);
}
bool dml2_top_optimization_optimize_function_stutter(const struct optimization_optimize_function_params *params)
{
struct dml2_optimization_optimize_function_locals *l = params->locals;
l->stutter.stutter_params.instance = ¶ms->dml->pmo_instance;
l->stutter.stutter_params.base_display_config = params->display_config;
l->stutter.stutter_params.optimized_display_config = params->optimized_display_config;
l->stutter.stutter_params.last_candidate_failed = !params->last_candidate_supported;
return params->dml->pmo_instance.optimize_for_stutter(&l->stutter.stutter_params);
}