]> www.infradead.org Git - users/hch/misc.git/commitdiff
drm/amd/display: Add Component To Handle Bounding Box Values and IP Caps
authorAustin Zheng <Austin.Zheng@amd.com>
Thu, 14 Aug 2025 13:54:45 +0000 (09:54 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 29 Aug 2025 14:14:02 +0000 (10:14 -0400)
[Why]
Bounding box values can be stored in multiple locations. (e.g. PMFW, VBIOS, DMUB).
The source and interpretation of these values can vary with DCN revision
so there should be a component that can gather these values and translate
them accordingly

[How]
Have component start with the statically defined values as a base.
Then update them as needed with DCN-specific logic
Guard this component with FPU flags since values need to be in float point.

Reviewed-by: Jun Lei <jun.lei@amd.com>
Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
13 files changed:
drivers/gpu/drm/amd/display/Makefile
drivers/gpu/drm/amd/display/dc/Makefile
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c
drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c
drivers/gpu/drm/amd/display/dc/inc/soc_and_ip_translator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/soc_and_ip_translator.c [new file with mode: 0644]

index 89d605de05955c18a25b19bf7b5cbfdc311bb3d0..0084a8d55254573e0eea71969abe99b067a076a7 100644 (file)
@@ -44,6 +44,7 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/mmhubbub
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/mpc
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/opp
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/pg
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/soc_and_ip_translator
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color
index 3c9ecea7eebc7120e98d486c18edb1e2dfbb0b05..dc943abd6dba35c9bc2aec860b3c1419513359a7 100644 (file)
@@ -37,6 +37,7 @@ DC_LIBS += dcn301
 DC_LIBS += dcn31
 DC_LIBS += dml
 DC_LIBS += dml2
+DC_LIBS += soc_and_ip_translator
 endif
 
 DC_LIBS += dce120
index c30d9ee51c83d5be977bc576cf787dcf1276d898..261b7d43e91d479114483dcb2ace2eb42017a409 100644 (file)
@@ -84,6 +84,7 @@
 
 #if defined(CONFIG_DRM_AMD_DC_FP)
 #include "dml2/dml2_internal_types.h"
+#include "soc_and_ip_translator.h"
 #endif
 
 #include "dce/dmub_outbox.h"
@@ -949,7 +950,9 @@ static void dc_destruct(struct dc *dc)
        }
 
        dc_destroy_resource_pool(dc);
-
+#ifdef CONFIG_DRM_AMD_DC_FP
+       dc_destroy_soc_and_ip_translator(&dc->soc_and_ip_translator);
+#endif
        if (dc->link_srv)
                link_destroy_link_service(&dc->link_srv);
 
@@ -1153,6 +1156,9 @@ static bool dc_construct(struct dc *dc,
                dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
                DC_FP_END();
        }
+       dc->soc_and_ip_translator = dc_create_soc_and_ip_translator(dc_ctx->dce_version);
+       if (!dc->soc_and_ip_translator)
+               goto fail;
 #endif
 
        if (!create_links(dc, init_params->num_virtual_links))
index c2bf583f30a7b37f0fb7a7c1f387592d6fb56539..e81b488cd72d453d8b1f2931f65618315777b6ab 100644 (file)
@@ -1776,7 +1776,7 @@ struct dc {
        struct dml2_configuration_options dml2_options;
        struct dml2_configuration_options dml2_dc_power_options;
        enum dc_acpi_cm_power_state power_state;
-
+       struct soc_and_ip_translator *soc_and_ip_translator;
 };
 
 struct dc_scaling_info {
index d6c77d96e4f706ddd895cc5d01b9c8c5c3ea2776..f6879e622271006000062c68f88d44463cab6c43 100644 (file)
@@ -8,7 +8,7 @@
 #include "dml2_internal_types.h"
 #include "dml21_utils.h"
 #include "dml21_translation_helper.h"
-#include "bounding_boxes/dcn4_soc_bb.h"
+#include "soc_and_ip_translator.h"
 
 static void dml21_populate_pmo_options(struct dml2_pmo_options *pmo_options,
                const struct dc *in_dc,
@@ -38,375 +38,37 @@ static void dml21_populate_pmo_options(struct dml2_pmo_options *pmo_options,
        pmo_options->disable_drr_clamped_when_var_active = in_dc->debug.disable_fams_gaming == INGAME_FAMS_DISABLE;
 }
 
-/*
- * Populate dml_init based on default static values in soc bb. The default
- * values are for reference and support at least minimal operation of current
- * SoC and DCN hardware. The values could be modifed by subsequent override
- * functions to reflect our true hardware capability.
- */
-static void populate_default_dml_init_params(struct dml2_initialize_instance_in_out *dml_init,
-               const struct dml2_configuration_options *config,
-               const struct dc *in_dc)
+static enum dml2_project_id dml21_dcn_revision_to_dml2_project_id(enum dce_version dcn_version)
 {
-       switch (in_dc->ctx->dce_version) {
+       enum dml2_project_id project_id;
+       switch (dcn_version) {
        case DCN_VERSION_4_01:
-               dml_init->options.project_id = dml2_project_dcn4x_stage2_auto_drr_svp;
-               dml21_populate_pmo_options(&dml_init->options.pmo_options, in_dc, config);
-               dml_init->soc_bb = dml2_socbb_dcn401;
-               dml_init->soc_bb.qos_parameters = dml_dcn4_variant_a_soc_qos_params;
-               dml_init->ip_caps = dml2_dcn401_max_ip_caps;
+               project_id = dml2_project_dcn4x_stage2_auto_drr_svp;
                break;
        default:
-               memset(dml_init, 0, sizeof(*dml_init));
+               project_id = dml2_project_invalid;
                DC_ERR("unsupported dcn version for DML21!");
-               return;
-       }
-}
-
-static void override_dml_init_with_values_from_hardware_default(struct dml2_initialize_instance_in_out *dml_init,
-               const struct dml2_configuration_options *config,
-               const struct dc *in_dc)
-{
-       dml_init->soc_bb.dchub_refclk_mhz = in_dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
-       dml_init->soc_bb.dprefclk_mhz = in_dc->clk_mgr->dprefclk_khz / 1000;
-       dml_init->soc_bb.dispclk_dppclk_vco_speed_mhz = in_dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-}
-
-/*
- * SMU stands for System Management Unit. It is a power management processor.
- * It owns the initialization of dc's clock table and programming of clock values
- * based on dc's requests.
- * Our clock values in base soc bb is a dummy placeholder. The real clock values
- * are retrieved from SMU firmware to dc clock table at runtime.
- * This function overrides our dummy placeholder values with real values in dc
- * clock table.
- */
-static void override_dml_init_with_values_from_smu(
-               struct dml2_initialize_instance_in_out *dml_init,
-               const struct dml2_configuration_options *config,
-               const struct dc *in_dc)
-{
-       int i;
-       const struct clk_bw_params *dc_bw_params = in_dc->clk_mgr->bw_params;
-       const struct clk_limit_table *dc_clk_table = &dc_bw_params->clk_table;
-       struct dml2_soc_state_table *dml_clk_table = &dml_init->soc_bb.clk_table;
-
-       if (!in_dc->clk_mgr->funcs->is_smu_present ||
-                       !in_dc->clk_mgr->funcs->is_smu_present(in_dc->clk_mgr))
-               /* skip if smu is not present */
-               return;
-
-       /* dcfclk */
-       if (dc_clk_table->num_entries_per_clk.num_dcfclk_levels) {
-               dml_clk_table->dcfclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dcfclk_levels;
-               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
-                       if (i < dml_clk_table->dcfclk.num_clk_values) {
-                               if (config->use_clock_dc_limits && dc_bw_params->dc_mode_limit.dcfclk_mhz &&
-                                               dc_clk_table->entries[i].dcfclk_mhz > dc_bw_params->dc_mode_limit.dcfclk_mhz) {
-                                       if (i == 0 || dc_clk_table->entries[i-1].dcfclk_mhz < dc_bw_params->dc_mode_limit.dcfclk_mhz) {
-                                               dml_clk_table->dcfclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dcfclk_mhz * 1000;
-                                               dml_clk_table->dcfclk.num_clk_values = i + 1;
-                                       } else {
-                                               dml_clk_table->dcfclk.clk_values_khz[i] = 0;
-                                               dml_clk_table->dcfclk.num_clk_values = i;
-                                       }
-                               } else {
-                                       dml_clk_table->dcfclk.clk_values_khz[i] = dc_clk_table->entries[i].dcfclk_mhz * 1000;
-                               }
-                       } else {
-                               dml_clk_table->dcfclk.clk_values_khz[i] = 0;
-                       }
-               }
-       }
-
-       /* fclk */
-       if (dc_clk_table->num_entries_per_clk.num_fclk_levels) {
-               dml_clk_table->fclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_fclk_levels;
-               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
-                       if (i < dml_clk_table->fclk.num_clk_values) {
-                               if (config->use_clock_dc_limits && dc_bw_params->dc_mode_limit.fclk_mhz &&
-                                               dc_clk_table->entries[i].fclk_mhz > dc_bw_params->dc_mode_limit.fclk_mhz) {
-                                       if (i == 0 || dc_clk_table->entries[i-1].fclk_mhz < dc_bw_params->dc_mode_limit.fclk_mhz) {
-                                               dml_clk_table->fclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.fclk_mhz * 1000;
-                                               dml_clk_table->fclk.num_clk_values = i + 1;
-                                       } else {
-                                               dml_clk_table->fclk.clk_values_khz[i] = 0;
-                                               dml_clk_table->fclk.num_clk_values = i;
-                                       }
-                               } else {
-                                       dml_clk_table->fclk.clk_values_khz[i] = dc_clk_table->entries[i].fclk_mhz * 1000;
-                               }
-                       } else {
-                               dml_clk_table->fclk.clk_values_khz[i] = 0;
-                       }
-               }
-       }
-
-       /* uclk */
-       if (dc_clk_table->num_entries_per_clk.num_memclk_levels) {
-               dml_clk_table->uclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_memclk_levels;
-               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
-                       if (i < dml_clk_table->uclk.num_clk_values) {
-                               if (config->use_clock_dc_limits && dc_bw_params->dc_mode_limit.memclk_mhz &&
-                                               dc_clk_table->entries[i].memclk_mhz > dc_bw_params->dc_mode_limit.memclk_mhz) {
-                                       if (i == 0 || dc_clk_table->entries[i-1].memclk_mhz < dc_bw_params->dc_mode_limit.memclk_mhz) {
-                                               dml_clk_table->uclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.memclk_mhz * 1000;
-                                               dml_clk_table->uclk.num_clk_values = i + 1;
-                                       } else {
-                                               dml_clk_table->uclk.clk_values_khz[i] = 0;
-                                               dml_clk_table->uclk.num_clk_values = i;
-                                       }
-                               } else {
-                                       dml_clk_table->uclk.clk_values_khz[i] = dc_clk_table->entries[i].memclk_mhz * 1000;
-                               }
-                       } else {
-                               dml_clk_table->uclk.clk_values_khz[i] = 0;
-                       }
-               }
-       }
-
-       /* dispclk */
-       if (dc_clk_table->num_entries_per_clk.num_dispclk_levels) {
-               dml_clk_table->dispclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dispclk_levels;
-               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
-                       if (i < dml_clk_table->dispclk.num_clk_values) {
-                               if (config->use_clock_dc_limits && dc_bw_params->dc_mode_limit.dispclk_mhz &&
-                                               dc_clk_table->entries[i].dispclk_mhz > dc_bw_params->dc_mode_limit.dispclk_mhz) {
-                                       if (i == 0 || dc_clk_table->entries[i-1].dispclk_mhz < dc_bw_params->dc_mode_limit.dispclk_mhz) {
-                                               dml_clk_table->dispclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dispclk_mhz * 1000;
-                                               dml_clk_table->dispclk.num_clk_values = i + 1;
-                                       } else {
-                                               dml_clk_table->dispclk.clk_values_khz[i] = 0;
-                                               dml_clk_table->dispclk.num_clk_values = i;
-                                       }
-                               } else {
-                                       dml_clk_table->dispclk.clk_values_khz[i] = dc_clk_table->entries[i].dispclk_mhz * 1000;
-                               }
-                       } else {
-                               dml_clk_table->dispclk.clk_values_khz[i] = 0;
-                       }
-               }
-       }
-
-       /* dppclk */
-       if (dc_clk_table->num_entries_per_clk.num_dppclk_levels) {
-               dml_clk_table->dppclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dppclk_levels;
-               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
-                       if (i < dml_clk_table->dppclk.num_clk_values) {
-                               if (config->use_clock_dc_limits && dc_bw_params->dc_mode_limit.dppclk_mhz &&
-                                               dc_clk_table->entries[i].dppclk_mhz > dc_bw_params->dc_mode_limit.dppclk_mhz) {
-                                       if (i == 0 || dc_clk_table->entries[i-1].dppclk_mhz < dc_bw_params->dc_mode_limit.dppclk_mhz) {
-                                               dml_clk_table->dppclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dppclk_mhz * 1000;
-                                               dml_clk_table->dppclk.num_clk_values = i + 1;
-                                       } else {
-                                               dml_clk_table->dppclk.clk_values_khz[i] = 0;
-                                               dml_clk_table->dppclk.num_clk_values = i;
-                                       }
-                               } else {
-                                       dml_clk_table->dppclk.clk_values_khz[i] = dc_clk_table->entries[i].dppclk_mhz * 1000;
-                               }
-                       } else {
-                               dml_clk_table->dppclk.clk_values_khz[i] = 0;
-                       }
-               }
-       }
-
-       /* dtbclk */
-       if (dc_clk_table->num_entries_per_clk.num_dtbclk_levels) {
-               dml_clk_table->dtbclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dtbclk_levels;
-               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
-                       if (i < dml_clk_table->dtbclk.num_clk_values) {
-                               if (config->use_clock_dc_limits && dc_bw_params->dc_mode_limit.dtbclk_mhz &&
-                                               dc_clk_table->entries[i].dtbclk_mhz > dc_bw_params->dc_mode_limit.dtbclk_mhz) {
-                                       if (i == 0 || dc_clk_table->entries[i-1].dtbclk_mhz < dc_bw_params->dc_mode_limit.dtbclk_mhz) {
-                                               dml_clk_table->dtbclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dtbclk_mhz * 1000;
-                                               dml_clk_table->dtbclk.num_clk_values = i + 1;
-                                       } else {
-                                               dml_clk_table->dtbclk.clk_values_khz[i] = 0;
-                                               dml_clk_table->dtbclk.num_clk_values = i;
-                                       }
-                               } else {
-                                       dml_clk_table->dtbclk.clk_values_khz[i] = dc_clk_table->entries[i].dtbclk_mhz * 1000;
-                               }
-                       } else {
-                               dml_clk_table->dtbclk.clk_values_khz[i] = 0;
-                       }
-               }
+               break;
        }
 
-       /* socclk */
-       if (dc_clk_table->num_entries_per_clk.num_socclk_levels) {
-               dml_clk_table->socclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_socclk_levels;
-               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
-                       if (i < dml_clk_table->socclk.num_clk_values) {
-                               if (config->use_clock_dc_limits && dc_bw_params->dc_mode_limit.socclk_mhz &&
-                                               dc_clk_table->entries[i].socclk_mhz > dc_bw_params->dc_mode_limit.socclk_mhz) {
-                                       if (i == 0 || dc_clk_table->entries[i-1].socclk_mhz < dc_bw_params->dc_mode_limit.socclk_mhz) {
-                                               dml_clk_table->socclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.socclk_mhz * 1000;
-                                               dml_clk_table->socclk.num_clk_values = i + 1;
-                                       } else {
-                                               dml_clk_table->socclk.clk_values_khz[i] = 0;
-                                               dml_clk_table->socclk.num_clk_values = i;
-                                       }
-                               } else {
-                                       dml_clk_table->socclk.clk_values_khz[i] = dc_clk_table->entries[i].socclk_mhz * 1000;
-                               }
-                       } else {
-                               dml_clk_table->socclk.clk_values_khz[i] = 0;
-                       }
-               }
-       }
+       return project_id;
 }
 
-static void override_dml_init_with_values_from_vbios(
-               struct dml2_initialize_instance_in_out *dml_init,
+void dml21_populate_dml_init_params(struct dml2_initialize_instance_in_out *dml_init,
                const struct dml2_configuration_options *config,
                const struct dc *in_dc)
 {
-       const struct clk_bw_params *dc_bw_params = in_dc->clk_mgr->bw_params;
-       struct dml2_soc_bb *dml_soc_bb = &dml_init->soc_bb;
-       struct dml2_soc_state_table *dml_clk_table = &dml_init->soc_bb.clk_table;
-
-       if (in_dc->ctx->dc_bios->bb_info.dram_clock_change_latency_100ns > 0)
-               dml_soc_bb->power_management_parameters.dram_clk_change_blackout_us =
-                               (in_dc->ctx->dc_bios->bb_info.dram_clock_change_latency_100ns + 9) / 10;
-
-       if (in_dc->ctx->dc_bios->bb_info.dram_sr_enter_exit_latency_100ns > 0)
-               dml_soc_bb->power_management_parameters.stutter_enter_plus_exit_latency_us =
-                               (in_dc->ctx->dc_bios->bb_info.dram_sr_enter_exit_latency_100ns + 9) / 10;
-
-       if (in_dc->ctx->dc_bios->bb_info.dram_sr_exit_latency_100ns > 0)
-               dml_soc_bb->power_management_parameters.stutter_exit_latency_us =
-                       (in_dc->ctx->dc_bios->bb_info.dram_sr_exit_latency_100ns + 9) / 10;
-
-       if (dc_bw_params->num_channels) {
-               dml_clk_table->dram_config.channel_count = dc_bw_params->num_channels;
-               dml_soc_bb->mall_allocated_for_dcn_mbytes = in_dc->caps.mall_size_total / 1048576;
-       } else if (in_dc->ctx->dc_bios->vram_info.num_chans) {
-               dml_clk_table->dram_config.channel_count = in_dc->ctx->dc_bios->vram_info.num_chans;
-               dml_soc_bb->mall_allocated_for_dcn_mbytes = in_dc->caps.mall_size_total / 1048576;
-       }
-
-       if (dc_bw_params->dram_channel_width_bytes) {
-               dml_clk_table->dram_config.channel_width_bytes = dc_bw_params->dram_channel_width_bytes;
-       } else if (in_dc->ctx->dc_bios->vram_info.dram_channel_width_bytes) {
-               dml_clk_table->dram_config.channel_width_bytes = in_dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
-       }
-
-       dml_init->soc_bb.xtalclk_mhz = in_dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency / 1000;
-}
+       dml_init->options.project_id = dml21_dcn_revision_to_dml2_project_id(in_dc->ctx->dce_version);
 
-
-static void override_dml_init_with_values_from_dmub(struct dml2_initialize_instance_in_out *dml_init,
-               const struct dml2_configuration_options *config,
-               const struct dc *in_dc)
-{
-       /*
-        * TODO - There seems to be overlaps between the values overriden from
-        * dmub and vbios. Investigate and identify the values that DMUB needs
-        * to own.
-        */
-//     const struct dmub_soc_bb_params *dmub_bb_params =
-//                     (const struct dmub_soc_bb_params *)config->bb_from_dmub;
-
-//     if (dmub_bb_params == NULL)
-//             return;
-
-//     if (dmub_bb_params->dram_clk_change_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.dram_clk_change_blackout_us =
-//                     (double) dmub_bb_params->dram_clk_change_blackout_ns / 1000.0;
-//     if (dmub_bb_params->dram_clk_change_read_only_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.dram_clk_change_read_only_us =
-//                     (double) dmub_bb_params->dram_clk_change_read_only_ns / 1000.0;
-//     if (dmub_bb_params->dram_clk_change_write_only_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.dram_clk_change_write_only_us =
-//                     (double) dmub_bb_params->dram_clk_change_write_only_ns / 1000.0;
-//     if (dmub_bb_params->fclk_change_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.fclk_change_blackout_us =
-//                     (double) dmub_bb_params->fclk_change_blackout_ns / 1000.0;
-//     if (dmub_bb_params->g7_ppt_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.g7_ppt_blackout_us =
-//                     (double) dmub_bb_params->g7_ppt_blackout_ns / 1000.0;
-//     if (dmub_bb_params->stutter_enter_plus_exit_latency_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.stutter_enter_plus_exit_latency_us =
-//                     (double) dmub_bb_params->stutter_enter_plus_exit_latency_ns / 1000.0;
-//     if (dmub_bb_params->stutter_exit_latency_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.stutter_exit_latency_us =
-//                     (double) dmub_bb_params->stutter_exit_latency_ns / 1000.0;
-//     if (dmub_bb_params->z8_stutter_enter_plus_exit_latency_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.z8_stutter_enter_plus_exit_latency_us =
-//                     (double) dmub_bb_params->z8_stutter_enter_plus_exit_latency_ns / 1000.0;
-//     if (dmub_bb_params->z8_stutter_exit_latency_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.z8_stutter_exit_latency_us =
-//                     (double) dmub_bb_params->z8_stutter_exit_latency_ns / 1000.0;
-//     if (dmub_bb_params->z8_min_idle_time_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.z8_min_idle_time =
-//                     (double) dmub_bb_params->z8_min_idle_time_ns / 1000.0;
-// #ifndef TRIM_DML2_DCN6B_IP_SENSITIVE
-//     if (dmub_bb_params->type_b_dram_clk_change_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.lpddr5_dram_clk_change_blackout_us =
-//                     (double) dmub_bb_params->type_b_dram_clk_change_blackout_ns / 1000.0;
-//     if (dmub_bb_params->type_b_ppt_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.lpddr5_ppt_blackout_us =
-//                     (double) dmub_bb_params->type_b_ppt_blackout_ns / 1000.0;
-// #else
-//     if (dmub_bb_params->type_b_dram_clk_change_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.type_b_dram_clk_change_blackout_us =
-//                     (double) dmub_bb_params->type_b_dram_clk_change_blackout_ns / 1000.0;
-//     if (dmub_bb_params->type_b_ppt_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.type_b_ppt_blackout_us =
-//                     (double) dmub_bb_params->type_b_ppt_blackout_ns / 1000.0;
-// #endif
-//     if (dmub_bb_params->vmin_limit_dispclk_khz > 0)
-//             dml_init->soc_bb.vmin_limit.dispclk_khz = dmub_bb_params->vmin_limit_dispclk_khz;
-//     if (dmub_bb_params->vmin_limit_dcfclk_khz > 0)
-//             dml_init->soc_bb.vmin_limit.dcfclk_khz = dmub_bb_params->vmin_limit_dcfclk_khz;
-//     if (dmub_bb_params->g7_temperature_read_blackout_ns > 0)
-//             dml_init->soc_bb.power_management_parameters.g7_temperature_read_blackout_us =
-//                             (double) dmub_bb_params->g7_temperature_read_blackout_ns / 1000.0;
-}
-
-static void override_dml_init_with_values_from_software_policy(struct dml2_initialize_instance_in_out *dml_init,
-               const struct dml2_configuration_options *config,
-               const struct dc *in_dc)
-{
-       if (!config->use_native_soc_bb_construction) {
+       if (config->use_native_soc_bb_construction) {
+               in_dc->soc_and_ip_translator->translator_funcs->get_soc_bb(&dml_init->soc_bb, in_dc, config);
+               in_dc->soc_and_ip_translator->translator_funcs->get_ip_caps(&dml_init->ip_caps);
+       } else {
                dml_init->soc_bb = config->external_socbb_ip_params->soc_bb;
                dml_init->ip_caps = config->external_socbb_ip_params->ip_params;
        }
 
-       if (in_dc->bb_overrides.sr_exit_time_ns)
-               dml_init->soc_bb.power_management_parameters.stutter_exit_latency_us =
-                               in_dc->bb_overrides.sr_exit_time_ns / 1000.0;
-
-       if (in_dc->bb_overrides.sr_enter_plus_exit_time_ns)
-               dml_init->soc_bb.power_management_parameters.stutter_enter_plus_exit_latency_us =
-                               in_dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
-
-       if (in_dc->bb_overrides.dram_clock_change_latency_ns)
-               dml_init->soc_bb.power_management_parameters.dram_clk_change_blackout_us =
-                               in_dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
-
-       if (in_dc->bb_overrides.fclk_clock_change_latency_ns)
-               dml_init->soc_bb.power_management_parameters.fclk_change_blackout_us =
-                               in_dc->bb_overrides.fclk_clock_change_latency_ns / 1000.0;
-}
-
-void dml21_populate_dml_init_params(struct dml2_initialize_instance_in_out *dml_init,
-               const struct dml2_configuration_options *config,
-               const struct dc *in_dc)
-{
-       populate_default_dml_init_params(dml_init, config, in_dc);
-
-       override_dml_init_with_values_from_hardware_default(dml_init, config, in_dc);
-
-       override_dml_init_with_values_from_smu(dml_init, config, in_dc);
-
-       override_dml_init_with_values_from_vbios(dml_init, config, in_dc);
-
-       override_dml_init_with_values_from_dmub(dml_init, config, in_dc);
-
-       override_dml_init_with_values_from_software_policy(dml_init, config, in_dc);
+       dml21_populate_pmo_options(&dml_init->options.pmo_options, in_dc, config);
 }
 
 static unsigned int calc_max_hardware_v_total(const struct dc_stream_state *stream)
index 03de3cf06ae59ae79cce3e8a143894ebb9c522b5..798abb2b2e676c41a842ce13e5e5a3d768586e3e 100644 (file)
@@ -60,7 +60,7 @@ static void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, con
 
        DC_FP_START();
 
-       dml21_populate_dml_init_params(&dml_ctx->v21.dml_init, config, in_dc);
+       dml21_populate_dml_init_params(&dml_ctx->v21.dml_init, &dml_ctx->config, in_dc);
 
        dml2_initialize_instance(&dml_ctx->v21.dml_init);
 
diff --git a/drivers/gpu/drm/amd/display/dc/inc/soc_and_ip_translator.h b/drivers/gpu/drm/amd/display/dc/inc/soc_and_ip_translator.h
new file mode 100644 (file)
index 0000000..23daf98
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#ifndef __SOC_AND_IP_TRANSLATOR_H__
+#define __SOC_AND_IP_TRANSLATOR_H__
+
+#include "dc.h"
+#include "dml_top_soc_parameter_types.h"
+
+struct soc_and_ip_translator_funcs {
+       void (*get_soc_bb)(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config);
+       void (*get_ip_caps)(struct dml2_ip_capabilities *dml_ip_caps);
+};
+
+struct soc_and_ip_translator {
+       const struct soc_and_ip_translator_funcs *translator_funcs;
+};
+
+struct soc_and_ip_translator *dc_create_soc_and_ip_translator(enum dce_version dc_version);
+void dc_destroy_soc_and_ip_translator(struct soc_and_ip_translator **soc_and_ip_translator);
+
+
+#endif // __SOC_AND_IP_TRANSLATOR_H__
diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/Makefile b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/Makefile
new file mode 100644 (file)
index 0000000..bc93356
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: MIT
+#
+# Copyright 2025 Advanced Micro Devices, Inc.
+# Makefile for bounding box component.
+# Floating point required due to nature of bounding box values
+
+soc_and_ip_translator_ccflags := $(CC_FLAGS_FPU)
+soc_and_ip_translator_rcflags := $(CC_FLAGS_NO_FPU)
+
+CFLAGS_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.o := $(soc_and_ip_translator_ccflags)
+
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.o := $(soc_and_ip_translator_rcflags)
+
+soc_and_ip_translator := soc_and_ip_translator.o
+soc_and_ip_translator += dcn401/dcn401_soc_and_ip_translator.o
+
+AMD_DAL_soc_and_ip_translator := $(addprefix $(AMDDALPATH)/dc/soc_and_ip_translator/, $(soc_and_ip_translator))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_soc_and_ip_translator)
diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.c
new file mode 100644 (file)
index 0000000..3190c76
--- /dev/null
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#include "dcn401_soc_and_ip_translator.h"
+#include "bounding_boxes/dcn4_soc_bb.h"
+
+/* soc_and_ip_translator component used to get up-to-date values for bounding box.
+ * Bounding box values are stored in several locations and locations can vary with DCN revision.
+ * This component provides an interface to get DCN-specific bounding box values.
+ */
+
+static void get_default_soc_bb(struct dml2_soc_bb *soc_bb)
+{
+       memcpy(soc_bb, &dml2_socbb_dcn401, sizeof(struct dml2_soc_bb));
+       memcpy(&soc_bb->qos_parameters, &dml_dcn4_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters));
+}
+
+/*
+ * DC clock table is obtained from SMU during runtime.
+ * SMU stands for System Management Unit. It is a power management processor.
+ * It owns the initialization of dc's clock table and programming of clock values
+ * based on dc's requests.
+ * Our clock values in base soc bb is a dummy placeholder. The real clock values
+ * are retrieved from SMU firmware to dc clock table at runtime.
+ * This function overrides our dummy placeholder values with real values in dc
+ * clock table.
+ */
+static void dcn401_convert_dc_clock_table_to_soc_bb_clock_table(
+               struct dml2_soc_state_table *dml_clk_table,
+               const struct clk_bw_params *dc_bw_params,
+               bool use_clock_dc_limits)
+{
+       int i;
+       const struct clk_limit_table *dc_clk_table;
+
+       if (dc_bw_params == NULL)
+               /* skip if bw params could not be obtained from smu */
+               return;
+
+       dc_clk_table = &dc_bw_params->clk_table;
+
+       /* dcfclk */
+       if (dc_clk_table->num_entries_per_clk.num_dcfclk_levels) {
+               dml_clk_table->dcfclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dcfclk_levels;
+               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
+                       if (i < dml_clk_table->dcfclk.num_clk_values) {
+                               if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dcfclk_mhz &&
+                                               dc_clk_table->entries[i].dcfclk_mhz > dc_bw_params->dc_mode_limit.dcfclk_mhz) {
+                                       if (i == 0 || dc_clk_table->entries[i-1].dcfclk_mhz < dc_bw_params->dc_mode_limit.dcfclk_mhz) {
+                                               dml_clk_table->dcfclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dcfclk_mhz * 1000;
+                                               dml_clk_table->dcfclk.num_clk_values = i + 1;
+                                       } else {
+                                               dml_clk_table->dcfclk.clk_values_khz[i] = 0;
+                                               dml_clk_table->dcfclk.num_clk_values = i;
+                                       }
+                               } else {
+                                       dml_clk_table->dcfclk.clk_values_khz[i] = dc_clk_table->entries[i].dcfclk_mhz * 1000;
+                               }
+                       } else {
+                               dml_clk_table->dcfclk.clk_values_khz[i] = 0;
+                       }
+               }
+       }
+
+       /* fclk */
+       if (dc_clk_table->num_entries_per_clk.num_fclk_levels) {
+               dml_clk_table->fclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_fclk_levels;
+               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
+                       if (i < dml_clk_table->fclk.num_clk_values) {
+                               if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.fclk_mhz &&
+                                               dc_clk_table->entries[i].fclk_mhz > dc_bw_params->dc_mode_limit.fclk_mhz) {
+                                       if (i == 0 || dc_clk_table->entries[i-1].fclk_mhz < dc_bw_params->dc_mode_limit.fclk_mhz) {
+                                               dml_clk_table->fclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.fclk_mhz * 1000;
+                                               dml_clk_table->fclk.num_clk_values = i + 1;
+                                       } else {
+                                               dml_clk_table->fclk.clk_values_khz[i] = 0;
+                                               dml_clk_table->fclk.num_clk_values = i;
+                                       }
+                               } else {
+                                       dml_clk_table->fclk.clk_values_khz[i] = dc_clk_table->entries[i].fclk_mhz * 1000;
+                               }
+                       } else {
+                               dml_clk_table->fclk.clk_values_khz[i] = 0;
+                       }
+               }
+       }
+
+       /* uclk */
+       if (dc_clk_table->num_entries_per_clk.num_memclk_levels) {
+               dml_clk_table->uclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_memclk_levels;
+               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
+                       if (i < dml_clk_table->uclk.num_clk_values) {
+                               if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.memclk_mhz &&
+                                               dc_clk_table->entries[i].memclk_mhz > dc_bw_params->dc_mode_limit.memclk_mhz) {
+                                       if (i == 0 || dc_clk_table->entries[i-1].memclk_mhz < dc_bw_params->dc_mode_limit.memclk_mhz) {
+                                               dml_clk_table->uclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.memclk_mhz * 1000;
+                                               dml_clk_table->uclk.num_clk_values = i + 1;
+                                       } else {
+                                               dml_clk_table->uclk.clk_values_khz[i] = 0;
+                                               dml_clk_table->uclk.num_clk_values = i;
+                                       }
+                               } else {
+                                       dml_clk_table->uclk.clk_values_khz[i] = dc_clk_table->entries[i].memclk_mhz * 1000;
+                               }
+                       } else {
+                               dml_clk_table->uclk.clk_values_khz[i] = 0;
+                       }
+               }
+       }
+
+       /* dispclk */
+       if (dc_clk_table->num_entries_per_clk.num_dispclk_levels) {
+               dml_clk_table->dispclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dispclk_levels;
+               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
+                       if (i < dml_clk_table->dispclk.num_clk_values) {
+                               if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dispclk_mhz &&
+                                               dc_clk_table->entries[i].dispclk_mhz > dc_bw_params->dc_mode_limit.dispclk_mhz) {
+                                       if (i == 0 || dc_clk_table->entries[i-1].dispclk_mhz < dc_bw_params->dc_mode_limit.dispclk_mhz) {
+                                               dml_clk_table->dispclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dispclk_mhz * 1000;
+                                               dml_clk_table->dispclk.num_clk_values = i + 1;
+                                       } else {
+                                               dml_clk_table->dispclk.clk_values_khz[i] = 0;
+                                               dml_clk_table->dispclk.num_clk_values = i;
+                                       }
+                               } else {
+                                       dml_clk_table->dispclk.clk_values_khz[i] = dc_clk_table->entries[i].dispclk_mhz * 1000;
+                               }
+                       } else {
+                               dml_clk_table->dispclk.clk_values_khz[i] = 0;
+                       }
+               }
+       }
+
+       /* dppclk */
+       if (dc_clk_table->num_entries_per_clk.num_dppclk_levels) {
+               dml_clk_table->dppclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dppclk_levels;
+               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
+                       if (i < dml_clk_table->dppclk.num_clk_values) {
+                               if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dppclk_mhz &&
+                                               dc_clk_table->entries[i].dppclk_mhz > dc_bw_params->dc_mode_limit.dppclk_mhz) {
+                                       if (i == 0 || dc_clk_table->entries[i-1].dppclk_mhz < dc_bw_params->dc_mode_limit.dppclk_mhz) {
+                                               dml_clk_table->dppclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dppclk_mhz * 1000;
+                                               dml_clk_table->dppclk.num_clk_values = i + 1;
+                                       } else {
+                                               dml_clk_table->dppclk.clk_values_khz[i] = 0;
+                                               dml_clk_table->dppclk.num_clk_values = i;
+                                       }
+                               } else {
+                                       dml_clk_table->dppclk.clk_values_khz[i] = dc_clk_table->entries[i].dppclk_mhz * 1000;
+                               }
+                       } else {
+                               dml_clk_table->dppclk.clk_values_khz[i] = 0;
+                       }
+               }
+       }
+
+       /* dtbclk */
+       if (dc_clk_table->num_entries_per_clk.num_dtbclk_levels) {
+               dml_clk_table->dtbclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dtbclk_levels;
+               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
+                       if (i < dml_clk_table->dtbclk.num_clk_values) {
+                               if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dtbclk_mhz &&
+                                               dc_clk_table->entries[i].dtbclk_mhz > dc_bw_params->dc_mode_limit.dtbclk_mhz) {
+                                       if (i == 0 || dc_clk_table->entries[i-1].dtbclk_mhz < dc_bw_params->dc_mode_limit.dtbclk_mhz) {
+                                               dml_clk_table->dtbclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dtbclk_mhz * 1000;
+                                               dml_clk_table->dtbclk.num_clk_values = i + 1;
+                                       } else {
+                                               dml_clk_table->dtbclk.clk_values_khz[i] = 0;
+                                               dml_clk_table->dtbclk.num_clk_values = i;
+                                       }
+                               } else {
+                                       dml_clk_table->dtbclk.clk_values_khz[i] = dc_clk_table->entries[i].dtbclk_mhz * 1000;
+                               }
+                       } else {
+                               dml_clk_table->dtbclk.clk_values_khz[i] = 0;
+                       }
+               }
+       }
+
+       /* socclk */
+       if (dc_clk_table->num_entries_per_clk.num_socclk_levels) {
+               dml_clk_table->socclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_socclk_levels;
+               for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
+                       if (i < dml_clk_table->socclk.num_clk_values) {
+                               if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.socclk_mhz &&
+                                               dc_clk_table->entries[i].socclk_mhz > dc_bw_params->dc_mode_limit.socclk_mhz) {
+                                       if (i == 0 || dc_clk_table->entries[i-1].socclk_mhz < dc_bw_params->dc_mode_limit.socclk_mhz) {
+                                               dml_clk_table->socclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.socclk_mhz * 1000;
+                                               dml_clk_table->socclk.num_clk_values = i + 1;
+                                       } else {
+                                               dml_clk_table->socclk.clk_values_khz[i] = 0;
+                                               dml_clk_table->socclk.num_clk_values = i;
+                                       }
+                               } else {
+                                       dml_clk_table->socclk.clk_values_khz[i] = dc_clk_table->entries[i].socclk_mhz * 1000;
+                               }
+                       } else {
+                               dml_clk_table->socclk.clk_values_khz[i] = 0;
+                       }
+               }
+       }
+
+       /* dram config */
+       dml_clk_table->dram_config.channel_count = dc_bw_params->num_channels;
+       dml_clk_table->dram_config.channel_width_bytes = dc_bw_params->dram_channel_width_bytes;
+}
+
+void dcn401_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
+{
+       soc_bb->dprefclk_mhz = dc->clk_mgr->dprefclk_khz / 1000;
+       soc_bb->dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+       soc_bb->mall_allocated_for_dcn_mbytes = dc->caps.mall_size_total / (1024 * 1024);
+
+       if (dc->clk_mgr->funcs->is_smu_present &&
+                       dc->clk_mgr->funcs->is_smu_present(dc->clk_mgr)) {
+               dcn401_convert_dc_clock_table_to_soc_bb_clock_table(&soc_bb->clk_table,
+                       dc->clk_mgr->bw_params,
+                       config->use_clock_dc_limits);
+       }
+}
+
+void dcn401_update_soc_bb_with_values_from_vbios(struct dml2_soc_bb *soc_bb, const struct dc *dc)
+{
+       soc_bb->dchub_refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
+       soc_bb->xtalclk_mhz = dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency / 1000;
+
+       /* latencies in vbios are platform specific and should be used if provided */
+       if (dc->ctx->dc_bios->bb_info.dram_clock_change_latency_100ns)
+               soc_bb->power_management_parameters.dram_clk_change_blackout_us =
+                               dc->ctx->dc_bios->bb_info.dram_clock_change_latency_100ns / 10.0;
+
+       if (dc->ctx->dc_bios->bb_info.dram_sr_enter_exit_latency_100ns)
+               soc_bb->power_management_parameters.stutter_enter_plus_exit_latency_us =
+                               dc->ctx->dc_bios->bb_info.dram_sr_enter_exit_latency_100ns / 10.0;
+
+       if (dc->ctx->dc_bios->bb_info.dram_sr_exit_latency_100ns)
+               soc_bb->power_management_parameters.stutter_exit_latency_us =
+                       dc->ctx->dc_bios->bb_info.dram_sr_exit_latency_100ns / 10.0;
+}
+
+void dcn401_update_soc_bb_with_values_from_software_policy(struct dml2_soc_bb *soc_bb, const struct dc *dc)
+{
+       /* set if the value is provided */
+       if (dc->bb_overrides.sr_exit_time_ns)
+               soc_bb->power_management_parameters.stutter_exit_latency_us =
+                               dc->bb_overrides.sr_exit_time_ns / 1000.0;
+
+       if (dc->bb_overrides.sr_enter_plus_exit_time_ns)
+               soc_bb->power_management_parameters.stutter_enter_plus_exit_latency_us =
+                               dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
+
+       if (dc->bb_overrides.dram_clock_change_latency_ns)
+               soc_bb->power_management_parameters.dram_clk_change_blackout_us =
+                               dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
+
+       if (dc->bb_overrides.fclk_clock_change_latency_ns)
+               soc_bb->power_management_parameters.fclk_change_blackout_us =
+                               dc->bb_overrides.fclk_clock_change_latency_ns / 1000.0;
+
+       //Z8 values not expected nor used on DCN401 but still added for completeness
+       if (dc->bb_overrides.sr_exit_z8_time_ns)
+               soc_bb->power_management_parameters.z8_stutter_exit_latency_us =
+                               dc->bb_overrides.sr_exit_z8_time_ns / 1000.0;
+
+       if (dc->bb_overrides.sr_enter_plus_exit_z8_time_ns)
+               soc_bb->power_management_parameters.z8_stutter_enter_plus_exit_latency_us =
+                               dc->bb_overrides.sr_enter_plus_exit_z8_time_ns / 1000.0;
+}
+
+static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
+{
+       /* Individual modification can be overwritten even if it was obtained by a previous function.
+        * Modifications are acquired in order of priority (lowest to highest).
+        */
+       dc_assert_fp_enabled();
+
+       dcn401_update_soc_bb_with_values_from_clk_mgr(soc_bb, dc, config);
+       dcn401_update_soc_bb_with_values_from_vbios(soc_bb, dc);
+       dcn401_update_soc_bb_with_values_from_software_policy(soc_bb, dc);
+}
+
+void dcn401_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
+{
+       //get default soc_bb with static values
+       get_default_soc_bb(soc_bb);
+       //update soc_bb values with more accurate values
+       apply_soc_bb_updates(soc_bb, dc, config);
+}
+
+static void dcn401_get_ip_caps(struct dml2_ip_capabilities *ip_caps)
+{
+       *ip_caps = dml2_dcn401_max_ip_caps;
+}
+
+static struct soc_and_ip_translator_funcs dcn401_translator_funcs = {
+       .get_soc_bb = dcn401_get_soc_bb,
+       .get_ip_caps = dcn401_get_ip_caps,
+};
+
+void dcn401_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator)
+{
+       soc_and_ip_translator->translator_funcs = &dcn401_translator_funcs;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.h b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.h
new file mode 100644 (file)
index 0000000..21d8428
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#ifndef _DCN401_SOC_AND_IP_TRANSLATOR_H_
+#define _DCN401_SOC_AND_IP_TRANSLATOR_H_
+
+#include "core_types.h"
+#include "dc.h"
+#include "clk_mgr.h"
+#include "soc_and_ip_translator.h"
+#include "dml2/dml21/inc/dml_top_soc_parameter_types.h"
+
+void dcn401_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator);
+
+/* Functions that can be re-used by higher DCN revisions of this component */
+void dcn401_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config);
+void dcn401_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config);
+void dcn401_update_soc_bb_with_values_from_vbios(struct dml2_soc_bb *soc_bb, const struct dc *dc);
+void dcn401_update_soc_bb_with_values_from_software_policy(struct dml2_soc_bb *soc_bb, const struct dc *dc);
+
+#endif /* _DCN401_SOC_AND_IP_TRANSLATOR_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c
new file mode 100644 (file)
index 0000000..c9e224d
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#include "dcn42_soc_and_ip_translator.h"
+#include "soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.h"
+#include "bounding_boxes/dcn42_soc_bb.h"
+
+/* soc_and_ip_translator component used to get up-to-date values for bounding box.
+ * Bounding box values are stored in several locations and locations can vary with DCN revision.
+ * This component provides an interface to get DCN-specific bounding box values.
+ */
+
+static void dcn42_get_ip_caps(struct dml2_ip_capabilities *ip_caps)
+{
+       *ip_caps = dml2_dcn42_max_ip_caps;
+}
+
+static struct soc_and_ip_translator_funcs dcn42_translator_funcs = {
+       .get_soc_bb = dcn401_get_soc_bb,
+       .get_ip_caps = dcn42_get_ip_caps,
+};
+
+void dcn42_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator)
+{
+       soc_and_ip_translator->translator_funcs = &dcn42_translator_funcs;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h
new file mode 100644 (file)
index 0000000..914dcbb
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#ifndef _DCN42_SOC_AND_IP_TRANSLATOR_H_
+#define _DCN42_SOC_AND_IP_TRANSLATOR_H_
+
+#include "core_types.h"
+#include "dc.h"
+#include "clk_mgr.h"
+#include "dml_top_soc_parameter_types.h"
+#include "soc_and_ip_translator.h"
+
+void dcn42_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator);
+
+#endif /* _DCN42_SOC_AND_IP_TRANSLATOR_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/soc_and_ip_translator.c
new file mode 100644 (file)
index 0000000..0fc0e5a
--- /dev/null
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#include "soc_and_ip_translator.h"
+#include "soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.h"
+
+static void dc_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator,
+               enum dce_version dc_version)
+{
+       switch (dc_version) {
+       case DCN_VERSION_4_01:
+               dcn401_construct_soc_and_ip_translator(soc_and_ip_translator);
+               break;
+       default:
+               break;
+       }
+}
+
+struct soc_and_ip_translator *dc_create_soc_and_ip_translator(enum dce_version dc_version)
+{
+       struct soc_and_ip_translator *soc_and_ip_translator;
+
+       soc_and_ip_translator = kzalloc(sizeof(*soc_and_ip_translator), GFP_KERNEL);
+       if (!soc_and_ip_translator)
+               return NULL;
+
+       dc_construct_soc_and_ip_translator(soc_and_ip_translator, dc_version);
+
+       return soc_and_ip_translator;
+}
+
+void dc_destroy_soc_and_ip_translator(struct soc_and_ip_translator **soc_and_ip_translator)
+{
+       kfree(*soc_and_ip_translator);
+       *soc_and_ip_translator = NULL;
+}