1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2025 Advanced Micro Devices, Inc. 4 5 #include "dcn42_soc_and_ip_translator.h" 6 #include "../dcn401/dcn401_soc_and_ip_translator.h" 7 #include "bounding_boxes/dcn42_soc_bb.h" 8 #include "bounding_boxes/dcn42b_soc_bb.h" 9 10 /* soc_and_ip_translator component used to get up-to-date values for bounding box. 11 * Bounding box values are stored in several locations and locations can vary with DCN revision. 12 * This component provides an interface to get DCN-specific bounding box values. 13 */ 14 15 static void get_default_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc) 16 { 17 if (dc->ctx->dce_version == DCN_VERSION_4_2B) { 18 memcpy(soc_bb, &dml2_socbb_dcn42b, sizeof(struct dml2_soc_bb)); 19 memcpy(&soc_bb->qos_parameters, &dml_dcn42b_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters)); 20 } else { 21 memcpy(soc_bb, &dml2_socbb_dcn42, sizeof(struct dml2_soc_bb)); 22 memcpy(&soc_bb->qos_parameters, &dml_dcn42_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters)); 23 } 24 } 25 26 /* 27 * DC clock table is obtained from SMU during runtime. 28 * SMU stands for System Management Unit. It is a power management processor. 29 * It owns the initialization of dc's clock table and programming of clock values 30 * based on dc's requests. 31 * Our clock values in base soc bb is a dummy placeholder. The real clock values 32 * are retrieved from SMU firmware to dc clock table at runtime. 33 * This function overrides our dummy placeholder values with real values in dc 34 * clock table. 35 */ 36 static void dcn42_convert_dc_clock_table_to_soc_bb_clock_table( 37 struct dml2_soc_state_table *dml_clk_table, 38 struct dml2_soc_vmin_clock_limits *vmin_limit, 39 const struct clk_bw_params *dc_bw_params) 40 { 41 int i; 42 const struct clk_limit_table *dc_clk_table; 43 44 if (dc_bw_params == NULL) 45 /* skip if bw params could not be obtained from smu */ 46 return; 47 48 dc_clk_table = &dc_bw_params->clk_table; 49 50 /* fclk/dcfclk - dcn42 pmfw table can have 0 entries for inactive dpm levels 51 * for use with dml we need to fill in using an active value aiming for >= 2x DCFCLK 52 */ 53 if (dc_clk_table->num_entries_per_clk.num_fclk_levels && dc_clk_table->num_entries_per_clk.num_dcfclk_levels) { 54 dml_clk_table->fclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dcfclk_levels; 55 dml_clk_table->dcfclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dcfclk_levels; 56 for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) { 57 if (i < (int)dc_clk_table->num_entries_per_clk.num_dcfclk_levels) { 58 int j, max_fclk = 0; 59 60 dml_clk_table->dcfclk.clk_values_khz[i] = dc_clk_table->entries[i].dcfclk_mhz * 1000; 61 for (j = 0; j < MAX_NUM_DPM_LVL; j++) { 62 if ((uint32_t)(dc_clk_table->entries[j].fclk_mhz * 1000) > (uint32_t)max_fclk) 63 max_fclk = dc_clk_table->entries[j].fclk_mhz * 1000; 64 dml_clk_table->fclk.clk_values_khz[i] = max_fclk; 65 if ((uint32_t)max_fclk >= 2 * dml_clk_table->dcfclk.clk_values_khz[i]) 66 break; 67 } 68 } else { 69 dml_clk_table->dcfclk.clk_values_khz[i] = 0; 70 dml_clk_table->fclk.clk_values_khz[i] = 0; 71 } 72 } 73 } 74 75 /* uclk */ 76 if (dc_clk_table->num_entries_per_clk.num_memclk_levels) { 77 dml_clk_table->uclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_memclk_levels; 78 for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) { 79 if (i < dml_clk_table->uclk.num_clk_values) { 80 dml_clk_table->uclk.clk_values_khz[i] = dc_clk_table->entries[i].memclk_mhz * 1000; 81 dml_clk_table->wck_ratio.clk_values_khz[i] = dc_clk_table->entries[i].wck_ratio; 82 } else { 83 dml_clk_table->uclk.clk_values_khz[i] = 0; 84 dml_clk_table->wck_ratio.clk_values_khz[i] = 0; 85 } 86 } 87 } 88 89 /* dispclk */ 90 if (dc_clk_table->num_entries_per_clk.num_dispclk_levels) { 91 dml_clk_table->dispclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dispclk_levels; 92 for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) { 93 if (i < dml_clk_table->dispclk.num_clk_values) { 94 dml_clk_table->dispclk.clk_values_khz[i] = dc_clk_table->entries[i].dispclk_mhz * 1000; 95 } else { 96 dml_clk_table->dispclk.clk_values_khz[i] = 0; 97 } 98 } 99 vmin_limit->dispclk_khz = min(dc_clk_table->entries[0].dispclk_mhz * 1000, vmin_limit->dispclk_khz); 100 /* dispclk is always fine-grain */ 101 dml_clk_table->dispclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dispclk_levels >= 2 ? 2 : 1; 102 dml_clk_table->dispclk.clk_values_khz[0] = 0; 103 dml_clk_table->dispclk.clk_values_khz[1] = dc_clk_table->entries[dc_clk_table->num_entries_per_clk.num_dispclk_levels - 1].dispclk_mhz * 1000; 104 } 105 106 /* dppclk */ 107 if (dc_clk_table->num_entries_per_clk.num_dppclk_levels) { 108 dml_clk_table->dppclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dppclk_levels; 109 for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) { 110 if (i < dml_clk_table->dppclk.num_clk_values) { 111 dml_clk_table->dppclk.clk_values_khz[i] = dc_clk_table->entries[i].dppclk_mhz * 1000; 112 } else { 113 dml_clk_table->dppclk.clk_values_khz[i] = 0; 114 } 115 } 116 /* dppclk is always fine-grain */ 117 dml_clk_table->dppclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dppclk_levels >= 2 ? 2 : 1; 118 dml_clk_table->dppclk.clk_values_khz[0] = 0; 119 dml_clk_table->dppclk.clk_values_khz[1] = dc_clk_table->entries[dc_clk_table->num_entries_per_clk.num_dppclk_levels - 1].dppclk_mhz * 1000; 120 } 121 122 /* dtbclk */ 123 if (dc_clk_table->num_entries_per_clk.num_dtbclk_levels) { 124 dml_clk_table->dtbclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dtbclk_levels; 125 for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) { 126 if (i < dml_clk_table->dtbclk.num_clk_values) { 127 dml_clk_table->dtbclk.clk_values_khz[i] = dc_clk_table->entries[i].dtbclk_mhz * 1000; 128 } else { 129 dml_clk_table->dtbclk.clk_values_khz[i] = 0; 130 } 131 } 132 } 133 134 /* socclk */ 135 if (dc_clk_table->num_entries_per_clk.num_socclk_levels) { 136 dml_clk_table->socclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_socclk_levels; 137 for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) { 138 if (i < dml_clk_table->socclk.num_clk_values) { 139 dml_clk_table->socclk.clk_values_khz[i] = dc_clk_table->entries[i].socclk_mhz * 1000; 140 } else { 141 dml_clk_table->socclk.clk_values_khz[i] = 0; 142 } 143 } 144 } 145 146 /* dram config */ 147 dml_clk_table->dram_config.channel_count = dc_bw_params->num_channels; 148 dml_clk_table->dram_config.channel_width_bytes = dc_bw_params->dram_channel_width_bytes; 149 } 150 151 static void dcn42_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc_bb, const struct dc *dc) 152 { 153 soc_bb->dprefclk_mhz = dc->clk_mgr->dprefclk_khz / 1000; 154 soc_bb->dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; 155 soc_bb->mall_allocated_for_dcn_mbytes = dc->caps.mall_size_total / (1024 * 1024); 156 157 if (dc->clk_mgr->funcs->is_smu_present && 158 dc->clk_mgr->funcs->is_smu_present(dc->clk_mgr)) { 159 dcn42_convert_dc_clock_table_to_soc_bb_clock_table(&soc_bb->clk_table, &soc_bb->vmin_limit, 160 dc->clk_mgr->bw_params); 161 } 162 163 if (dc->clk_mgr->bw_params->vram_type == Ddr5MemType) { 164 soc_bb->power_management_parameters = dcn42_ddr5_power_management_parameters; 165 } 166 } 167 168 static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) 169 { 170 (void)config; 171 /* Individual modification can be overwritten even if it was obtained by a previous function. 172 * Modifications are acquired in order of priority (lowest to highest). 173 */ 174 dc_assert_fp_enabled(); 175 176 dcn42_update_soc_bb_with_values_from_clk_mgr(soc_bb, dc); 177 dcn401_update_soc_bb_with_values_from_vbios(soc_bb, dc); 178 dcn401_update_soc_bb_with_values_from_software_policy(soc_bb, dc); 179 } 180 181 void dcn42_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) 182 { 183 //get default soc_bb with static values 184 get_default_soc_bb(soc_bb, dc); 185 //update soc_bb values with more accurate values 186 apply_soc_bb_updates(soc_bb, dc, config); 187 } 188 189 static void dcn42_get_ip_caps(struct dml2_ip_capabilities *ip_caps) 190 { 191 *ip_caps = dml2_dcn42_max_ip_caps; 192 } 193 194 static struct soc_and_ip_translator_funcs dcn42_translator_funcs = { 195 .get_soc_bb = dcn42_get_soc_bb, 196 .get_ip_caps = dcn42_get_ip_caps, 197 }; 198 199 void dcn42_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator) 200 { 201 soc_and_ip_translator->translator_funcs = &dcn42_translator_funcs; 202 } 203 204