2 * Copyright 2018 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
24 #include <linux/delay.h>
26 #include <linux/module.h>
27 #include <linux/slab.h>
30 #include "amd_powerplay.h"
31 #include "vega20_smumgr.h"
32 #include "hardwaremanager.h"
33 #include "ppatomfwctrl.h"
34 #include "atomfirmware.h"
35 #include "cgs_common.h"
36 #include "vega20_powertune.h"
37 #include "vega20_inc.h"
38 #include "pppcielanes.h"
39 #include "vega20_hwmgr.h"
40 #include "vega20_processpptables.h"
41 #include "vega20_pptable.h"
42 #include "vega20_thermal.h"
43 #include "vega20_ppsmc.h"
45 #include "amd_pcie_helpers.h"
46 #include "ppinterrupt.h"
47 #include "pp_overdriver.h"
48 #include "pp_thermal.h"
50 static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
52 struct vega20_hwmgr *data =
53 (struct vega20_hwmgr *)(hwmgr->backend);
55 data->gfxclk_average_alpha = PPVEGA20_VEGA20GFXCLKAVERAGEALPHA_DFLT;
56 data->socclk_average_alpha = PPVEGA20_VEGA20SOCCLKAVERAGEALPHA_DFLT;
57 data->uclk_average_alpha = PPVEGA20_VEGA20UCLKCLKAVERAGEALPHA_DFLT;
58 data->gfx_activity_average_alpha = PPVEGA20_VEGA20GFXACTIVITYAVERAGEALPHA_DFLT;
59 data->lowest_uclk_reserved_for_ulv = PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT;
61 data->display_voltage_mode = PPVEGA20_VEGA20DISPLAYVOLTAGEMODE_DFLT;
62 data->dcef_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
63 data->dcef_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
64 data->dcef_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
65 data->disp_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
66 data->disp_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
67 data->disp_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
68 data->pixel_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
69 data->pixel_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
70 data->pixel_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
71 data->phy_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
72 data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
73 data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
75 data->registry_data.disallowed_features = 0x0;
76 data->registry_data.od_state_in_dc_support = 0;
77 data->registry_data.thermal_support = 1;
78 data->registry_data.skip_baco_hardware = 0;
80 data->registry_data.log_avfs_param = 0;
81 data->registry_data.sclk_throttle_low_notification = 1;
82 data->registry_data.force_dpm_high = 0;
83 data->registry_data.stable_pstate_sclk_dpm_percentage = 75;
85 data->registry_data.didt_support = 0;
86 if (data->registry_data.didt_support) {
87 data->registry_data.didt_mode = 6;
88 data->registry_data.sq_ramping_support = 1;
89 data->registry_data.db_ramping_support = 0;
90 data->registry_data.td_ramping_support = 0;
91 data->registry_data.tcp_ramping_support = 0;
92 data->registry_data.dbr_ramping_support = 0;
93 data->registry_data.edc_didt_support = 1;
94 data->registry_data.gc_didt_support = 0;
95 data->registry_data.psm_didt_support = 0;
98 data->registry_data.pcie_lane_override = 0xff;
99 data->registry_data.pcie_speed_override = 0xff;
100 data->registry_data.pcie_clock_override = 0xffffffff;
101 data->registry_data.regulator_hot_gpio_support = 1;
102 data->registry_data.ac_dc_switch_gpio_support = 0;
103 data->registry_data.quick_transition_support = 0;
104 data->registry_data.zrpm_start_temp = 0xffff;
105 data->registry_data.zrpm_stop_temp = 0xffff;
106 data->registry_data.od8_feature_enable = 1;
107 data->registry_data.disable_water_mark = 0;
108 data->registry_data.disable_pp_tuning = 0;
109 data->registry_data.disable_xlpp_tuning = 0;
110 data->registry_data.disable_workload_policy = 0;
111 data->registry_data.perf_ui_tuning_profile_turbo = 0x19190F0F;
112 data->registry_data.perf_ui_tuning_profile_powerSave = 0x19191919;
113 data->registry_data.perf_ui_tuning_profile_xl = 0x00000F0A;
114 data->registry_data.force_workload_policy_mask = 0;
115 data->registry_data.disable_3d_fs_detection = 0;
116 data->registry_data.fps_support = 1;
117 data->registry_data.disable_auto_wattman = 1;
118 data->registry_data.auto_wattman_debug = 0;
119 data->registry_data.auto_wattman_sample_period = 100;
120 data->registry_data.auto_wattman_threshold = 50;
121 data->registry_data.gfxoff_controlled_by_driver = 1;
122 data->gfxoff_allowed = false;
123 data->counter_gfxoff = 0;
126 static int vega20_set_features_platform_caps(struct pp_hwmgr *hwmgr)
128 struct vega20_hwmgr *data =
129 (struct vega20_hwmgr *)(hwmgr->backend);
130 struct amdgpu_device *adev = hwmgr->adev;
132 if (data->vddci_control == VEGA20_VOLTAGE_CONTROL_NONE)
133 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
134 PHM_PlatformCaps_ControlVDDCI);
136 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
137 PHM_PlatformCaps_TablelessHardwareInterface);
139 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
140 PHM_PlatformCaps_EnableSMU7ThermalManagement);
142 if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
143 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
144 PHM_PlatformCaps_UVDPowerGating);
146 if (adev->pg_flags & AMD_PG_SUPPORT_VCE)
147 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
148 PHM_PlatformCaps_VCEPowerGating);
150 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
151 PHM_PlatformCaps_UnTabledHardwareInterface);
153 if (data->registry_data.od8_feature_enable)
154 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
155 PHM_PlatformCaps_OD8inACSupport);
157 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
158 PHM_PlatformCaps_ActivityReporting);
159 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
160 PHM_PlatformCaps_FanSpeedInTableIsRPM);
162 if (data->registry_data.od_state_in_dc_support) {
163 if (data->registry_data.od8_feature_enable)
164 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
165 PHM_PlatformCaps_OD8inDCSupport);
168 if (data->registry_data.thermal_support &&
169 data->registry_data.fuzzy_fan_control_support &&
170 hwmgr->thermal_controller.advanceFanControlParameters.usTMax)
171 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
172 PHM_PlatformCaps_ODFuzzyFanControlSupport);
174 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
175 PHM_PlatformCaps_DynamicPowerManagement);
176 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
177 PHM_PlatformCaps_SMC);
178 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
179 PHM_PlatformCaps_ThermalPolicyDelay);
181 if (data->registry_data.force_dpm_high)
182 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
183 PHM_PlatformCaps_ExclusiveModeAlwaysHigh);
185 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
186 PHM_PlatformCaps_DynamicUVDState);
188 if (data->registry_data.sclk_throttle_low_notification)
189 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
190 PHM_PlatformCaps_SclkThrottleLowNotification);
192 /* power tune caps */
193 /* assume disabled */
194 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
195 PHM_PlatformCaps_PowerContainment);
196 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
197 PHM_PlatformCaps_DiDtSupport);
198 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
199 PHM_PlatformCaps_SQRamping);
200 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
201 PHM_PlatformCaps_DBRamping);
202 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
203 PHM_PlatformCaps_TDRamping);
204 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
205 PHM_PlatformCaps_TCPRamping);
206 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
207 PHM_PlatformCaps_DBRRamping);
208 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
209 PHM_PlatformCaps_DiDtEDCEnable);
210 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
211 PHM_PlatformCaps_GCEDC);
212 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
213 PHM_PlatformCaps_PSM);
215 if (data->registry_data.didt_support) {
216 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
217 PHM_PlatformCaps_DiDtSupport);
218 if (data->registry_data.sq_ramping_support)
219 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
220 PHM_PlatformCaps_SQRamping);
221 if (data->registry_data.db_ramping_support)
222 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
223 PHM_PlatformCaps_DBRamping);
224 if (data->registry_data.td_ramping_support)
225 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
226 PHM_PlatformCaps_TDRamping);
227 if (data->registry_data.tcp_ramping_support)
228 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
229 PHM_PlatformCaps_TCPRamping);
230 if (data->registry_data.dbr_ramping_support)
231 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
232 PHM_PlatformCaps_DBRRamping);
233 if (data->registry_data.edc_didt_support)
234 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
235 PHM_PlatformCaps_DiDtEDCEnable);
236 if (data->registry_data.gc_didt_support)
237 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
238 PHM_PlatformCaps_GCEDC);
239 if (data->registry_data.psm_didt_support)
240 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
241 PHM_PlatformCaps_PSM);
244 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
245 PHM_PlatformCaps_RegulatorHot);
247 if (data->registry_data.ac_dc_switch_gpio_support) {
248 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
249 PHM_PlatformCaps_AutomaticDCTransition);
250 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
251 PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
254 if (data->registry_data.quick_transition_support) {
255 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
256 PHM_PlatformCaps_AutomaticDCTransition);
257 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
258 PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
259 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
260 PHM_PlatformCaps_Falcon_QuickTransition);
263 if (data->lowest_uclk_reserved_for_ulv != PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT) {
264 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
265 PHM_PlatformCaps_LowestUclkReservedForUlv);
266 if (data->lowest_uclk_reserved_for_ulv == 1)
267 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
268 PHM_PlatformCaps_LowestUclkReservedForUlv);
271 if (data->registry_data.custom_fan_support)
272 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
273 PHM_PlatformCaps_CustomFanControlSupport);
278 static void vega20_init_dpm_defaults(struct pp_hwmgr *hwmgr)
280 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
283 data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id =
284 FEATURE_DPM_PREFETCHER_BIT;
285 data->smu_features[GNLD_DPM_GFXCLK].smu_feature_id =
286 FEATURE_DPM_GFXCLK_BIT;
287 data->smu_features[GNLD_DPM_UCLK].smu_feature_id =
288 FEATURE_DPM_UCLK_BIT;
289 data->smu_features[GNLD_DPM_SOCCLK].smu_feature_id =
290 FEATURE_DPM_SOCCLK_BIT;
291 data->smu_features[GNLD_DPM_UVD].smu_feature_id =
293 data->smu_features[GNLD_DPM_VCE].smu_feature_id =
295 data->smu_features[GNLD_ULV].smu_feature_id =
297 data->smu_features[GNLD_DPM_MP0CLK].smu_feature_id =
298 FEATURE_DPM_MP0CLK_BIT;
299 data->smu_features[GNLD_DPM_LINK].smu_feature_id =
300 FEATURE_DPM_LINK_BIT;
301 data->smu_features[GNLD_DPM_DCEFCLK].smu_feature_id =
302 FEATURE_DPM_DCEFCLK_BIT;
303 data->smu_features[GNLD_DS_GFXCLK].smu_feature_id =
304 FEATURE_DS_GFXCLK_BIT;
305 data->smu_features[GNLD_DS_SOCCLK].smu_feature_id =
306 FEATURE_DS_SOCCLK_BIT;
307 data->smu_features[GNLD_DS_LCLK].smu_feature_id =
309 data->smu_features[GNLD_PPT].smu_feature_id =
311 data->smu_features[GNLD_TDC].smu_feature_id =
313 data->smu_features[GNLD_THERMAL].smu_feature_id =
315 data->smu_features[GNLD_GFX_PER_CU_CG].smu_feature_id =
316 FEATURE_GFX_PER_CU_CG_BIT;
317 data->smu_features[GNLD_RM].smu_feature_id =
319 data->smu_features[GNLD_DS_DCEFCLK].smu_feature_id =
320 FEATURE_DS_DCEFCLK_BIT;
321 data->smu_features[GNLD_ACDC].smu_feature_id =
323 data->smu_features[GNLD_VR0HOT].smu_feature_id =
325 data->smu_features[GNLD_VR1HOT].smu_feature_id =
327 data->smu_features[GNLD_FW_CTF].smu_feature_id =
329 data->smu_features[GNLD_LED_DISPLAY].smu_feature_id =
330 FEATURE_LED_DISPLAY_BIT;
331 data->smu_features[GNLD_FAN_CONTROL].smu_feature_id =
332 FEATURE_FAN_CONTROL_BIT;
333 data->smu_features[GNLD_DIDT].smu_feature_id = FEATURE_GFX_EDC_BIT;
334 data->smu_features[GNLD_GFXOFF].smu_feature_id = FEATURE_GFXOFF_BIT;
335 data->smu_features[GNLD_CG].smu_feature_id = FEATURE_CG_BIT;
336 data->smu_features[GNLD_DPM_FCLK].smu_feature_id = FEATURE_DPM_FCLK_BIT;
337 data->smu_features[GNLD_DS_FCLK].smu_feature_id = FEATURE_DS_FCLK_BIT;
338 data->smu_features[GNLD_DS_MP1CLK].smu_feature_id = FEATURE_DS_MP1CLK_BIT;
339 data->smu_features[GNLD_DS_MP0CLK].smu_feature_id = FEATURE_DS_MP0CLK_BIT;
340 data->smu_features[GNLD_XGMI].smu_feature_id = FEATURE_XGMI_BIT;
342 for (i = 0; i < GNLD_FEATURES_MAX; i++) {
343 data->smu_features[i].smu_feature_bitmap =
344 (uint64_t)(1ULL << data->smu_features[i].smu_feature_id);
345 data->smu_features[i].allowed =
346 ((data->registry_data.disallowed_features >> i) & 1) ?
351 static int vega20_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
356 static int vega20_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
358 kfree(hwmgr->backend);
359 hwmgr->backend = NULL;
364 static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
366 struct vega20_hwmgr *data;
367 struct amdgpu_device *adev = hwmgr->adev;
369 data = kzalloc(sizeof(struct vega20_hwmgr), GFP_KERNEL);
373 hwmgr->backend = data;
375 hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO];
376 hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO;
377 hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO;
379 vega20_set_default_registry_data(hwmgr);
381 data->disable_dpm_mask = 0xff;
383 /* need to set voltage control types before EVV patching */
384 data->vddc_control = VEGA20_VOLTAGE_CONTROL_NONE;
385 data->mvdd_control = VEGA20_VOLTAGE_CONTROL_NONE;
386 data->vddci_control = VEGA20_VOLTAGE_CONTROL_NONE;
388 data->water_marks_bitmap = 0;
389 data->avfs_exist = false;
391 vega20_set_features_platform_caps(hwmgr);
393 vega20_init_dpm_defaults(hwmgr);
395 /* Parse pptable data read from VBIOS */
396 vega20_set_private_data_based_on_pptable(hwmgr);
398 data->is_tlu_enabled = false;
400 hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
401 VEGA20_MAX_HARDWARE_POWERLEVELS;
402 hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
403 hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
405 hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
406 /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
407 hwmgr->platform_descriptor.clockStep.engineClock = 500;
408 hwmgr->platform_descriptor.clockStep.memoryClock = 500;
410 data->total_active_cus = adev->gfx.cu_info.number;
415 static int vega20_init_sclk_threshold(struct pp_hwmgr *hwmgr)
417 struct vega20_hwmgr *data =
418 (struct vega20_hwmgr *)(hwmgr->backend);
420 data->low_sclk_interrupt_threshold = 0;
425 static int vega20_setup_asic_task(struct pp_hwmgr *hwmgr)
429 ret = vega20_init_sclk_threshold(hwmgr);
430 PP_ASSERT_WITH_CODE(!ret,
431 "Failed to init sclk threshold!",
438 * @fn vega20_init_dpm_state
439 * @brief Function to initialize all Soft Min/Max and Hard Min/Max to 0xff.
441 * @param dpm_state - the address of the DPM Table to initiailize.
444 static void vega20_init_dpm_state(struct vega20_dpm_state *dpm_state)
446 dpm_state->soft_min_level = 0x0;
447 dpm_state->soft_max_level = 0xffff;
448 dpm_state->hard_min_level = 0x0;
449 dpm_state->hard_max_level = 0xffff;
452 static int vega20_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
453 PPCLK_e clk_id, uint32_t *num_of_levels)
457 ret = smum_send_msg_to_smc_with_parameter(hwmgr,
458 PPSMC_MSG_GetDpmFreqByIndex,
459 (clk_id << 16 | 0xFF));
460 PP_ASSERT_WITH_CODE(!ret,
461 "[GetNumOfDpmLevel] failed to get dpm levels!",
464 vega20_read_arg_from_smc(hwmgr, num_of_levels);
465 PP_ASSERT_WITH_CODE(*num_of_levels > 0,
466 "[GetNumOfDpmLevel] number of clk levels is invalid!",
472 static int vega20_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr,
473 PPCLK_e clk_id, uint32_t index, uint32_t *clk)
477 ret = smum_send_msg_to_smc_with_parameter(hwmgr,
478 PPSMC_MSG_GetDpmFreqByIndex,
479 (clk_id << 16 | index));
480 PP_ASSERT_WITH_CODE(!ret,
481 "[GetDpmFreqByIndex] failed to get dpm freq by index!",
484 vega20_read_arg_from_smc(hwmgr, clk);
485 PP_ASSERT_WITH_CODE(*clk,
486 "[GetDpmFreqByIndex] clk value is invalid!",
492 static int vega20_setup_single_dpm_table(struct pp_hwmgr *hwmgr,
493 struct vega20_single_dpm_table *dpm_table, PPCLK_e clk_id)
496 uint32_t i, num_of_levels, clk;
498 ret = vega20_get_number_of_dpm_level(hwmgr, clk_id, &num_of_levels);
499 PP_ASSERT_WITH_CODE(!ret,
500 "[SetupSingleDpmTable] failed to get clk levels!",
503 dpm_table->count = num_of_levels;
505 for (i = 0; i < num_of_levels; i++) {
506 ret = vega20_get_dpm_frequency_by_index(hwmgr, clk_id, i, &clk);
507 PP_ASSERT_WITH_CODE(!ret,
508 "[SetupSingleDpmTable] failed to get clk of specific level!",
510 dpm_table->dpm_levels[i].value = clk;
511 dpm_table->dpm_levels[i].enabled = true;
519 * This function is to initialize all DPM state tables
520 * for SMU based on the dependency table.
521 * Dynamic state patching function will then trim these
522 * state tables to the allowed range based
523 * on the power policy or external client requests,
524 * such as UVD request, etc.
526 static int vega20_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
528 struct vega20_hwmgr *data =
529 (struct vega20_hwmgr *)(hwmgr->backend);
530 struct vega20_single_dpm_table *dpm_table;
533 memset(&data->dpm_table, 0, sizeof(data->dpm_table));
536 dpm_table = &(data->dpm_table.soc_table);
537 if (data->smu_features[GNLD_DPM_SOCCLK].enabled) {
538 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_SOCCLK);
539 PP_ASSERT_WITH_CODE(!ret,
540 "[SetupDefaultDpmTable] failed to get socclk dpm levels!",
543 dpm_table->count = 1;
544 dpm_table->dpm_levels[0].value = data->vbios_boot_state.soc_clock / 100;
546 vega20_init_dpm_state(&(dpm_table->dpm_state));
549 dpm_table = &(data->dpm_table.gfx_table);
550 if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
551 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_GFXCLK);
552 PP_ASSERT_WITH_CODE(!ret,
553 "[SetupDefaultDpmTable] failed to get gfxclk dpm levels!",
556 dpm_table->count = 1;
557 dpm_table->dpm_levels[0].value = data->vbios_boot_state.gfx_clock / 100;
559 vega20_init_dpm_state(&(dpm_table->dpm_state));
562 dpm_table = &(data->dpm_table.mem_table);
563 if (data->smu_features[GNLD_DPM_UCLK].enabled) {
564 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_UCLK);
565 PP_ASSERT_WITH_CODE(!ret,
566 "[SetupDefaultDpmTable] failed to get memclk dpm levels!",
569 dpm_table->count = 1;
570 dpm_table->dpm_levels[0].value = data->vbios_boot_state.mem_clock / 100;
572 vega20_init_dpm_state(&(dpm_table->dpm_state));
575 dpm_table = &(data->dpm_table.eclk_table);
576 if (data->smu_features[GNLD_DPM_VCE].enabled) {
577 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_ECLK);
578 PP_ASSERT_WITH_CODE(!ret,
579 "[SetupDefaultDpmTable] failed to get eclk dpm levels!",
582 dpm_table->count = 1;
583 dpm_table->dpm_levels[0].value = data->vbios_boot_state.eclock / 100;
585 vega20_init_dpm_state(&(dpm_table->dpm_state));
588 dpm_table = &(data->dpm_table.vclk_table);
589 if (data->smu_features[GNLD_DPM_UVD].enabled) {
590 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_VCLK);
591 PP_ASSERT_WITH_CODE(!ret,
592 "[SetupDefaultDpmTable] failed to get vclk dpm levels!",
595 dpm_table->count = 1;
596 dpm_table->dpm_levels[0].value = data->vbios_boot_state.vclock / 100;
598 vega20_init_dpm_state(&(dpm_table->dpm_state));
601 dpm_table = &(data->dpm_table.dclk_table);
602 if (data->smu_features[GNLD_DPM_UVD].enabled) {
603 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCLK);
604 PP_ASSERT_WITH_CODE(!ret,
605 "[SetupDefaultDpmTable] failed to get dclk dpm levels!",
608 dpm_table->count = 1;
609 dpm_table->dpm_levels[0].value = data->vbios_boot_state.dclock / 100;
611 vega20_init_dpm_state(&(dpm_table->dpm_state));
614 dpm_table = &(data->dpm_table.dcef_table);
615 if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
616 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCEFCLK);
617 PP_ASSERT_WITH_CODE(!ret,
618 "[SetupDefaultDpmTable] failed to get dcefclk dpm levels!",
621 dpm_table->count = 1;
622 dpm_table->dpm_levels[0].value = data->vbios_boot_state.dcef_clock / 100;
624 vega20_init_dpm_state(&(dpm_table->dpm_state));
627 dpm_table = &(data->dpm_table.pixel_table);
628 if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
629 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PIXCLK);
630 PP_ASSERT_WITH_CODE(!ret,
631 "[SetupDefaultDpmTable] failed to get pixclk dpm levels!",
634 dpm_table->count = 0;
635 vega20_init_dpm_state(&(dpm_table->dpm_state));
638 dpm_table = &(data->dpm_table.display_table);
639 if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
640 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DISPCLK);
641 PP_ASSERT_WITH_CODE(!ret,
642 "[SetupDefaultDpmTable] failed to get dispclk dpm levels!",
645 dpm_table->count = 0;
646 vega20_init_dpm_state(&(dpm_table->dpm_state));
649 dpm_table = &(data->dpm_table.phy_table);
650 if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
651 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PHYCLK);
652 PP_ASSERT_WITH_CODE(!ret,
653 "[SetupDefaultDpmTable] failed to get phyclk dpm levels!",
656 dpm_table->count = 0;
657 vega20_init_dpm_state(&(dpm_table->dpm_state));
660 dpm_table = &(data->dpm_table.fclk_table);
661 if (data->smu_features[GNLD_DPM_FCLK].enabled) {
662 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_FCLK);
663 PP_ASSERT_WITH_CODE(!ret,
664 "[SetupDefaultDpmTable] failed to get fclk dpm levels!",
667 dpm_table->count = 0;
668 vega20_init_dpm_state(&(dpm_table->dpm_state));
670 /* save a copy of the default DPM table */
671 memcpy(&(data->golden_dpm_table), &(data->dpm_table),
672 sizeof(struct vega20_dpm_table));
678 * Initializes the SMC table and uploads it
680 * @param hwmgr the address of the powerplay hardware manager.
681 * @param pInput the pointer to input data (PowerState)
684 static int vega20_init_smc_table(struct pp_hwmgr *hwmgr)
687 struct vega20_hwmgr *data =
688 (struct vega20_hwmgr *)(hwmgr->backend);
689 PPTable_t *pp_table = &(data->smc_state_table.pp_table);
690 struct pp_atomfwctrl_bios_boot_up_values boot_up_values;
691 struct phm_ppt_v3_information *pptable_information =
692 (struct phm_ppt_v3_information *)hwmgr->pptable;
694 result = pp_atomfwctrl_get_vbios_bootup_values(hwmgr, &boot_up_values);
695 PP_ASSERT_WITH_CODE(!result,
696 "[InitSMCTable] Failed to get vbios bootup values!",
699 data->vbios_boot_state.vddc = boot_up_values.usVddc;
700 data->vbios_boot_state.vddci = boot_up_values.usVddci;
701 data->vbios_boot_state.mvddc = boot_up_values.usMvddc;
702 data->vbios_boot_state.gfx_clock = boot_up_values.ulGfxClk;
703 data->vbios_boot_state.mem_clock = boot_up_values.ulUClk;
704 data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk;
705 data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk;
706 data->vbios_boot_state.eclock = boot_up_values.ulEClk;
707 data->vbios_boot_state.vclock = boot_up_values.ulVClk;
708 data->vbios_boot_state.dclock = boot_up_values.ulDClk;
709 data->vbios_boot_state.uc_cooling_id = boot_up_values.ucCoolingID;
711 smum_send_msg_to_smc_with_parameter(hwmgr,
712 PPSMC_MSG_SetMinDeepSleepDcefclk,
713 (uint32_t)(data->vbios_boot_state.dcef_clock / 100));
715 memcpy(pp_table, pptable_information->smc_pptable, sizeof(PPTable_t));
717 result = vega20_copy_table_to_smc(hwmgr,
718 (uint8_t *)pp_table, TABLE_PPTABLE);
719 PP_ASSERT_WITH_CODE(!result,
720 "[InitSMCTable] Failed to upload PPtable!",
726 static int vega20_set_allowed_featuresmask(struct pp_hwmgr *hwmgr)
728 struct vega20_hwmgr *data =
729 (struct vega20_hwmgr *)(hwmgr->backend);
730 uint32_t allowed_features_low = 0, allowed_features_high = 0;
734 for (i = 0; i < GNLD_FEATURES_MAX; i++)
735 if (data->smu_features[i].allowed)
736 data->smu_features[i].smu_feature_id > 31 ?
737 (allowed_features_high |=
738 ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_HIGH_SHIFT)
740 (allowed_features_low |=
741 ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_LOW_SHIFT)
744 ret = smum_send_msg_to_smc_with_parameter(hwmgr,
745 PPSMC_MSG_SetAllowedFeaturesMaskHigh, allowed_features_high);
746 PP_ASSERT_WITH_CODE(!ret,
747 "[SetAllowedFeaturesMask] Attempt to set allowed features mask(high) failed!",
750 ret = smum_send_msg_to_smc_with_parameter(hwmgr,
751 PPSMC_MSG_SetAllowedFeaturesMaskLow, allowed_features_low);
752 PP_ASSERT_WITH_CODE(!ret,
753 "[SetAllowedFeaturesMask] Attempt to set allowed features mask (low) failed!",
759 static int vega20_run_btc_afll(struct pp_hwmgr *hwmgr)
761 return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAfllBtc);
764 static int vega20_enable_all_smu_features(struct pp_hwmgr *hwmgr)
766 struct vega20_hwmgr *data =
767 (struct vega20_hwmgr *)(hwmgr->backend);
768 uint64_t features_enabled;
773 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
774 PPSMC_MSG_EnableAllSmuFeatures)) == 0,
775 "[EnableAllSMUFeatures] Failed to enable all smu features!",
778 ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
779 PP_ASSERT_WITH_CODE(!ret,
780 "[EnableAllSmuFeatures] Failed to get enabled smc features!",
783 for (i = 0; i < GNLD_FEATURES_MAX; i++) {
784 enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
786 data->smu_features[i].enabled = enabled;
787 data->smu_features[i].supported = enabled;
790 if (data->smu_features[i].allowed && !enabled)
791 pr_info("[EnableAllSMUFeatures] feature %d is expected enabled!", i);
792 else if (!data->smu_features[i].allowed && enabled)
793 pr_info("[EnableAllSMUFeatures] feature %d is expected disabled!", i);
800 static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
802 struct vega20_hwmgr *data =
803 (struct vega20_hwmgr *)(hwmgr->backend);
804 uint64_t features_enabled;
809 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
810 PPSMC_MSG_DisableAllSmuFeatures)) == 0,
811 "[DisableAllSMUFeatures] Failed to disable all smu features!",
814 ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
815 PP_ASSERT_WITH_CODE(!ret,
816 "[DisableAllSMUFeatures] Failed to get enabled smc features!",
819 for (i = 0; i < GNLD_FEATURES_MAX; i++) {
820 enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
822 data->smu_features[i].enabled = enabled;
823 data->smu_features[i].supported = enabled;
829 static int vega20_od8_set_feature_capabilities(
830 struct pp_hwmgr *hwmgr)
832 struct phm_ppt_v3_information *pptable_information =
833 (struct phm_ppt_v3_information *)hwmgr->pptable;
834 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
835 struct vega20_od8_settings *od_settings = &(data->od8_settings);
837 od_settings->overdrive8_capabilities = 0;
839 if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
840 if (pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_GFXCLKFMAX] > 0 &&
841 pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_GFXCLKFMAX] > 0 &&
842 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_GFXCLKFMIN] > 0 &&
843 pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_GFXCLKFMIN] > 0)
844 od_settings->overdrive8_capabilities |= OD8_GFXCLK_LIMITS;
846 if (pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_VDDGFXCURVEFREQ_P1] > 0 &&
847 pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_VDDGFXCURVEFREQ_P2] > 0 &&
848 pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_VDDGFXCURVEFREQ_P3] > 0 &&
849 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_VDDGFXCURVEFREQ_P1] > 0 &&
850 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_VDDGFXCURVEFREQ_P2] > 0 &&
851 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_VDDGFXCURVEFREQ_P3] > 0 &&
852 pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_VDDGFXCURVEVOLTAGEOFFSET_P1] > 0 &&
853 pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_VDDGFXCURVEVOLTAGEOFFSET_P2] > 0 &&
854 pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_VDDGFXCURVEVOLTAGEOFFSET_P3] > 0 &&
855 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_VDDGFXCURVEVOLTAGEOFFSET_P1] > 0 &&
856 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_VDDGFXCURVEVOLTAGEOFFSET_P2] > 0 &&
857 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_VDDGFXCURVEVOLTAGEOFFSET_P3] > 0)
858 od_settings->overdrive8_capabilities |= OD8_GFXCLK_CURVE;
861 if (data->smu_features[GNLD_DPM_UCLK].enabled) {
862 if (pptable_information->od_settings_min[ATOM_VEGA20_ODSETTING_UCLKFMAX] > 0 &&
863 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_UCLKFMAX] > 0)
864 od_settings->overdrive8_capabilities |= OD8_UCLK_MAX;
867 if (pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE] > 0 &&
868 pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE] <= 100)
869 od_settings->overdrive8_capabilities |= OD8_POWER_LIMIT;
871 if (data->smu_features[GNLD_FAN_CONTROL].enabled) {
872 if (pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_FANRPMMIN] > 0)
873 od_settings->overdrive8_capabilities |= OD8_FAN_SPEED_MIN;
875 if (pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_FANRPMACOUSTICLIMIT] > 0)
876 od_settings->overdrive8_capabilities |= OD8_ACOUSTIC_LIMIT_SCLK;
879 if (data->smu_features[GNLD_THERMAL].enabled) {
880 if (pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_FANTARGETTEMPERATURE] > 0)
881 od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_FAN;
883 if (pptable_information->od_settings_max[ATOM_VEGA20_ODSETTING_OPERATINGTEMPMAX] > 0)
884 od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_SYSTEM;
890 static int vega20_od8_set_feature_id(
891 struct pp_hwmgr *hwmgr)
893 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
894 struct vega20_od8_settings *od_settings = &(data->od8_settings);
896 if (od_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
897 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
899 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
902 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
904 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
908 if (od_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
909 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
911 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
913 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
915 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
917 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
919 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
922 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
924 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
926 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
928 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
930 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
932 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
936 if (od_settings->overdrive8_capabilities & OD8_UCLK_MAX)
937 od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = OD8_UCLK_MAX;
939 od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = 0;
941 if (od_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
942 od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = OD8_POWER_LIMIT;
944 od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = 0;
946 if (od_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
947 od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
948 OD8_ACOUSTIC_LIMIT_SCLK;
950 od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
953 if (od_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
954 od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
957 od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
960 if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
961 od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
964 od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
967 if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
968 od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
969 OD8_TEMPERATURE_SYSTEM;
971 od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
977 static int vega20_od8_initialize_default_settings(
978 struct pp_hwmgr *hwmgr)
980 struct phm_ppt_v3_information *pptable_information =
981 (struct phm_ppt_v3_information *)hwmgr->pptable;
982 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
983 struct vega20_od8_settings *od8_settings = &(data->od8_settings);
984 OverDriveTable_t *od_table = &(data->smc_state_table.overdrive_table);
987 /* Set Feature Capabilities */
988 vega20_od8_set_feature_capabilities(hwmgr);
990 /* Map FeatureID to individual settings */
991 vega20_od8_set_feature_id(hwmgr);
993 /* Set default values */
994 ret = vega20_copy_table_from_smc(hwmgr, (uint8_t *)od_table, TABLE_OVERDRIVE);
995 PP_ASSERT_WITH_CODE(!ret,
996 "Failed to export over drive table!",
999 if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
1000 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1001 od_table->GfxclkFmin;
1002 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1003 od_table->GfxclkFmax;
1005 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1007 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1011 if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
1012 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1013 od_table->GfxclkFreq1;
1014 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value =
1015 od_table->GfxclkOffsetVolt1;
1016 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1017 od_table->GfxclkFreq2;
1018 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value =
1019 od_table->GfxclkOffsetVolt2;
1020 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1021 od_table->GfxclkFreq3;
1022 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value =
1023 od_table->GfxclkOffsetVolt3;
1025 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1027 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value =
1029 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1031 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value =
1033 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1035 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value =
1039 if (od8_settings->overdrive8_capabilities & OD8_UCLK_MAX)
1040 od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1043 od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1046 if (od8_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
1047 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1048 od_table->OverDrivePct;
1050 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1053 if (od8_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
1054 od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1055 od_table->FanMaximumRpm;
1057 od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1060 if (od8_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
1061 od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1062 od_table->FanMinimumPwm;
1064 od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1067 if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
1068 od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1069 od_table->FanTargetTemperature;
1071 od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1074 if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
1075 od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1076 od_table->MaxOpTemp;
1078 od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1081 for (i = 0; i < OD8_SETTING_COUNT; i++) {
1082 if (od8_settings->od8_settings_array[i].feature_id) {
1083 od8_settings->od8_settings_array[i].min_value =
1084 pptable_information->od_settings_min[i];
1085 od8_settings->od8_settings_array[i].max_value =
1086 pptable_information->od_settings_max[i];
1087 od8_settings->od8_settings_array[i].current_value =
1088 od8_settings->od8_settings_array[i].default_value;
1090 od8_settings->od8_settings_array[i].min_value =
1092 od8_settings->od8_settings_array[i].max_value =
1094 od8_settings->od8_settings_array[i].current_value =
1102 static int vega20_od8_set_settings(
1103 struct pp_hwmgr *hwmgr,
1107 OverDriveTable_t od_table;
1110 ret = vega20_copy_table_from_smc(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE);
1111 PP_ASSERT_WITH_CODE(!ret,
1112 "Failed to export over drive table!",
1116 case OD8_SETTING_GFXCLK_FMIN:
1117 od_table.GfxclkFmin = (uint16_t)value;
1119 case OD8_SETTING_GFXCLK_FMAX:
1120 od_table.GfxclkFmax = (uint16_t)value;
1122 case OD8_SETTING_GFXCLK_FREQ1:
1123 od_table.GfxclkFreq1 = (uint16_t)value;
1125 case OD8_SETTING_GFXCLK_VOLTAGE1:
1126 od_table.GfxclkOffsetVolt1 = (uint16_t)value;
1128 case OD8_SETTING_GFXCLK_FREQ2:
1129 od_table.GfxclkFreq2 = (uint16_t)value;
1131 case OD8_SETTING_GFXCLK_VOLTAGE2:
1132 od_table.GfxclkOffsetVolt2 = (uint16_t)value;
1134 case OD8_SETTING_GFXCLK_FREQ3:
1135 od_table.GfxclkFreq3 = (uint16_t)value;
1137 case OD8_SETTING_GFXCLK_VOLTAGE3:
1138 od_table.GfxclkOffsetVolt3 = (uint16_t)value;
1140 case OD8_SETTING_UCLK_FMAX:
1141 od_table.UclkFmax = (uint16_t)value;
1143 case OD8_SETTING_POWER_PERCENTAGE:
1144 od_table.OverDrivePct = (int16_t)value;
1146 case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
1147 od_table.FanMaximumRpm = (uint16_t)value;
1149 case OD8_SETTING_FAN_MIN_SPEED:
1150 od_table.FanMinimumPwm = (uint16_t)value;
1152 case OD8_SETTING_FAN_TARGET_TEMP:
1153 od_table.FanTargetTemperature = (uint16_t)value;
1155 case OD8_SETTING_OPERATING_TEMP_MAX:
1156 od_table.MaxOpTemp = (uint16_t)value;
1160 ret = vega20_copy_table_to_smc(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE);
1161 PP_ASSERT_WITH_CODE(!ret,
1162 "Failed to import over drive table!",
1168 static int vega20_get_sclk_od(
1169 struct pp_hwmgr *hwmgr)
1171 struct vega20_hwmgr *data = hwmgr->backend;
1172 struct vega20_single_dpm_table *sclk_table =
1173 &(data->dpm_table.gfx_table);
1174 struct vega20_single_dpm_table *golden_sclk_table =
1175 &(data->golden_dpm_table.gfx_table);
1179 value = DIV_ROUND_UP((sclk_table->dpm_levels[sclk_table->count - 1].value -
1180 golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * 100,
1181 golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value);
1186 static int vega20_set_sclk_od(
1187 struct pp_hwmgr *hwmgr, uint32_t value)
1189 struct vega20_hwmgr *data = hwmgr->backend;
1190 struct vega20_single_dpm_table *sclk_table =
1191 &(data->dpm_table.gfx_table);
1192 struct vega20_single_dpm_table *golden_sclk_table =
1193 &(data->golden_dpm_table.gfx_table);
1197 od_sclk = golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value * value;
1199 od_sclk += golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
1201 ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_GFXCLK_FMAX, od_sclk);
1202 PP_ASSERT_WITH_CODE(!ret,
1203 "[SetSclkOD] failed to set od gfxclk!",
1206 /* refresh gfxclk table */
1207 ret = vega20_setup_single_dpm_table(hwmgr, sclk_table, PPCLK_GFXCLK);
1208 PP_ASSERT_WITH_CODE(!ret,
1209 "[SetSclkOD] failed to refresh gfxclk table!",
1215 static int vega20_get_mclk_od(
1216 struct pp_hwmgr *hwmgr)
1218 struct vega20_hwmgr *data = hwmgr->backend;
1219 struct vega20_single_dpm_table *mclk_table =
1220 &(data->dpm_table.mem_table);
1221 struct vega20_single_dpm_table *golden_mclk_table =
1222 &(data->golden_dpm_table.mem_table);
1226 value = DIV_ROUND_UP((mclk_table->dpm_levels[mclk_table->count - 1].value -
1227 golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * 100,
1228 golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value);
1233 static int vega20_set_mclk_od(
1234 struct pp_hwmgr *hwmgr, uint32_t value)
1236 struct vega20_hwmgr *data = hwmgr->backend;
1237 struct vega20_single_dpm_table *mclk_table =
1238 &(data->dpm_table.mem_table);
1239 struct vega20_single_dpm_table *golden_mclk_table =
1240 &(data->golden_dpm_table.mem_table);
1244 od_mclk = golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value * value;
1246 od_mclk += golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
1248 ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_UCLK_FMAX, od_mclk);
1249 PP_ASSERT_WITH_CODE(!ret,
1250 "[SetMclkOD] failed to set od memclk!",
1253 /* refresh memclk table */
1254 ret = vega20_setup_single_dpm_table(hwmgr, mclk_table, PPCLK_UCLK);
1255 PP_ASSERT_WITH_CODE(!ret,
1256 "[SetMclkOD] failed to refresh memclk table!",
1262 static int vega20_populate_umdpstate_clocks(
1263 struct pp_hwmgr *hwmgr)
1265 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1266 struct vega20_single_dpm_table *gfx_table = &(data->dpm_table.gfx_table);
1267 struct vega20_single_dpm_table *mem_table = &(data->dpm_table.mem_table);
1269 hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value;
1270 hwmgr->pstate_mclk = mem_table->dpm_levels[0].value;
1272 if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
1273 mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
1274 hwmgr->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
1275 hwmgr->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
1278 hwmgr->pstate_sclk = hwmgr->pstate_sclk * 100;
1279 hwmgr->pstate_mclk = hwmgr->pstate_mclk * 100;
1284 static int vega20_get_max_sustainable_clock(struct pp_hwmgr *hwmgr,
1285 PP_Clock *clock, PPCLK_e clock_select)
1289 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1290 PPSMC_MSG_GetDcModeMaxDpmFreq,
1291 (clock_select << 16))) == 0,
1292 "[GetMaxSustainableClock] Failed to get max DC clock from SMC!",
1294 vega20_read_arg_from_smc(hwmgr, clock);
1296 /* if DC limit is zero, return AC limit */
1298 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1299 PPSMC_MSG_GetMaxDpmFreq,
1300 (clock_select << 16))) == 0,
1301 "[GetMaxSustainableClock] failed to get max AC clock from SMC!",
1303 vega20_read_arg_from_smc(hwmgr, clock);
1309 static int vega20_init_max_sustainable_clocks(struct pp_hwmgr *hwmgr)
1311 struct vega20_hwmgr *data =
1312 (struct vega20_hwmgr *)(hwmgr->backend);
1313 struct vega20_max_sustainable_clocks *max_sustainable_clocks =
1314 &(data->max_sustainable_clocks);
1317 max_sustainable_clocks->uclock = data->vbios_boot_state.mem_clock / 100;
1318 max_sustainable_clocks->soc_clock = data->vbios_boot_state.soc_clock / 100;
1319 max_sustainable_clocks->dcef_clock = data->vbios_boot_state.dcef_clock / 100;
1320 max_sustainable_clocks->display_clock = 0xFFFFFFFF;
1321 max_sustainable_clocks->phy_clock = 0xFFFFFFFF;
1322 max_sustainable_clocks->pixel_clock = 0xFFFFFFFF;
1324 if (data->smu_features[GNLD_DPM_UCLK].enabled)
1325 PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1326 &(max_sustainable_clocks->uclock),
1328 "[InitMaxSustainableClocks] failed to get max UCLK from SMC!",
1331 if (data->smu_features[GNLD_DPM_SOCCLK].enabled)
1332 PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1333 &(max_sustainable_clocks->soc_clock),
1334 PPCLK_SOCCLK)) == 0,
1335 "[InitMaxSustainableClocks] failed to get max SOCCLK from SMC!",
1338 if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
1339 PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1340 &(max_sustainable_clocks->dcef_clock),
1341 PPCLK_DCEFCLK)) == 0,
1342 "[InitMaxSustainableClocks] failed to get max DCEFCLK from SMC!",
1344 PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1345 &(max_sustainable_clocks->display_clock),
1346 PPCLK_DISPCLK)) == 0,
1347 "[InitMaxSustainableClocks] failed to get max DISPCLK from SMC!",
1349 PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1350 &(max_sustainable_clocks->phy_clock),
1351 PPCLK_PHYCLK)) == 0,
1352 "[InitMaxSustainableClocks] failed to get max PHYCLK from SMC!",
1354 PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1355 &(max_sustainable_clocks->pixel_clock),
1356 PPCLK_PIXCLK)) == 0,
1357 "[InitMaxSustainableClocks] failed to get max PIXCLK from SMC!",
1361 if (max_sustainable_clocks->soc_clock < max_sustainable_clocks->uclock)
1362 max_sustainable_clocks->uclock = max_sustainable_clocks->soc_clock;
1367 static void vega20_init_powergate_state(struct pp_hwmgr *hwmgr)
1369 struct vega20_hwmgr *data =
1370 (struct vega20_hwmgr *)(hwmgr->backend);
1372 data->uvd_power_gated = true;
1373 data->vce_power_gated = true;
1375 if (data->smu_features[GNLD_DPM_UVD].enabled)
1376 data->uvd_power_gated = false;
1378 if (data->smu_features[GNLD_DPM_VCE].enabled)
1379 data->vce_power_gated = false;
1382 static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
1386 smum_send_msg_to_smc_with_parameter(hwmgr,
1387 PPSMC_MSG_NumOfDisplays, 0);
1389 result = vega20_set_allowed_featuresmask(hwmgr);
1390 PP_ASSERT_WITH_CODE(!result,
1391 "[EnableDPMTasks] Failed to set allowed featuresmask!\n",
1394 result = vega20_init_smc_table(hwmgr);
1395 PP_ASSERT_WITH_CODE(!result,
1396 "[EnableDPMTasks] Failed to initialize SMC table!",
1399 result = vega20_run_btc_afll(hwmgr);
1400 PP_ASSERT_WITH_CODE(!result,
1401 "[EnableDPMTasks] Failed to run btc afll!",
1404 result = vega20_enable_all_smu_features(hwmgr);
1405 PP_ASSERT_WITH_CODE(!result,
1406 "[EnableDPMTasks] Failed to enable all smu features!",
1409 /* Initialize UVD/VCE powergating state */
1410 vega20_init_powergate_state(hwmgr);
1412 result = vega20_setup_default_dpm_tables(hwmgr);
1413 PP_ASSERT_WITH_CODE(!result,
1414 "[EnableDPMTasks] Failed to setup default DPM tables!",
1417 result = vega20_init_max_sustainable_clocks(hwmgr);
1418 PP_ASSERT_WITH_CODE(!result,
1419 "[EnableDPMTasks] Failed to get maximum sustainable clocks!",
1422 result = vega20_power_control_set_level(hwmgr);
1423 PP_ASSERT_WITH_CODE(!result,
1424 "[EnableDPMTasks] Failed to power control set level!",
1427 result = vega20_od8_initialize_default_settings(hwmgr);
1428 PP_ASSERT_WITH_CODE(!result,
1429 "[EnableDPMTasks] Failed to initialize odn settings!",
1432 result = vega20_populate_umdpstate_clocks(hwmgr);
1433 PP_ASSERT_WITH_CODE(!result,
1434 "[EnableDPMTasks] Failed to populate umdpstate clocks!",
1440 static uint32_t vega20_find_lowest_dpm_level(
1441 struct vega20_single_dpm_table *table)
1445 for (i = 0; i < table->count; i++) {
1446 if (table->dpm_levels[i].enabled)
1449 if (i >= table->count) {
1451 table->dpm_levels[i].enabled = true;
1457 static uint32_t vega20_find_highest_dpm_level(
1458 struct vega20_single_dpm_table *table)
1462 PP_ASSERT_WITH_CODE(table != NULL,
1463 "[FindHighestDPMLevel] DPM Table does not exist!",
1465 PP_ASSERT_WITH_CODE(table->count > 0,
1466 "[FindHighestDPMLevel] DPM Table has no entry!",
1468 PP_ASSERT_WITH_CODE(table->count <= MAX_REGULAR_DPM_NUMBER,
1469 "[FindHighestDPMLevel] DPM Table has too many entries!",
1470 return MAX_REGULAR_DPM_NUMBER - 1);
1472 for (i = table->count - 1; i >= 0; i--) {
1473 if (table->dpm_levels[i].enabled)
1478 table->dpm_levels[i].enabled = true;
1484 static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr)
1486 struct vega20_hwmgr *data =
1487 (struct vega20_hwmgr *)(hwmgr->backend);
1491 if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
1492 min_freq = data->dpm_table.gfx_table.dpm_state.soft_min_level;
1493 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1494 hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1495 (PPCLK_GFXCLK << 16) | (min_freq & 0xffff))),
1496 "Failed to set soft min gfxclk !",
1500 if (data->smu_features[GNLD_DPM_UCLK].enabled) {
1501 min_freq = data->dpm_table.mem_table.dpm_state.soft_min_level;
1502 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1503 hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1504 (PPCLK_UCLK << 16) | (min_freq & 0xffff))),
1505 "Failed to set soft min memclk !",
1508 min_freq = data->dpm_table.mem_table.dpm_state.hard_min_level;
1509 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1510 hwmgr, PPSMC_MSG_SetHardMinByFreq,
1511 (PPCLK_UCLK << 16) | (min_freq & 0xffff))),
1512 "Failed to set hard min memclk !",
1516 if (data->smu_features[GNLD_DPM_UVD].enabled) {
1517 min_freq = data->dpm_table.vclk_table.dpm_state.soft_min_level;
1519 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1520 hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1521 (PPCLK_VCLK << 16) | (min_freq & 0xffff))),
1522 "Failed to set soft min vclk!",
1525 min_freq = data->dpm_table.dclk_table.dpm_state.soft_min_level;
1527 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1528 hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1529 (PPCLK_DCLK << 16) | (min_freq & 0xffff))),
1530 "Failed to set soft min dclk!",
1534 if (data->smu_features[GNLD_DPM_VCE].enabled) {
1535 min_freq = data->dpm_table.eclk_table.dpm_state.soft_min_level;
1537 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1538 hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1539 (PPCLK_ECLK << 16) | (min_freq & 0xffff))),
1540 "Failed to set soft min eclk!",
1544 if (data->smu_features[GNLD_DPM_SOCCLK].enabled) {
1545 min_freq = data->dpm_table.soc_table.dpm_state.soft_min_level;
1547 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1548 hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1549 (PPCLK_SOCCLK << 16) | (min_freq & 0xffff))),
1550 "Failed to set soft min socclk!",
1557 static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr)
1559 struct vega20_hwmgr *data =
1560 (struct vega20_hwmgr *)(hwmgr->backend);
1564 if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
1565 max_freq = data->dpm_table.gfx_table.dpm_state.soft_max_level;
1567 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1568 hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1569 (PPCLK_GFXCLK << 16) | (max_freq & 0xffff))),
1570 "Failed to set soft max gfxclk!",
1574 if (data->smu_features[GNLD_DPM_UCLK].enabled) {
1575 max_freq = data->dpm_table.mem_table.dpm_state.soft_max_level;
1577 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1578 hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1579 (PPCLK_UCLK << 16) | (max_freq & 0xffff))),
1580 "Failed to set soft max memclk!",
1584 if (data->smu_features[GNLD_DPM_UVD].enabled) {
1585 max_freq = data->dpm_table.vclk_table.dpm_state.soft_max_level;
1587 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1588 hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1589 (PPCLK_VCLK << 16) | (max_freq & 0xffff))),
1590 "Failed to set soft max vclk!",
1593 max_freq = data->dpm_table.dclk_table.dpm_state.soft_max_level;
1594 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1595 hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1596 (PPCLK_DCLK << 16) | (max_freq & 0xffff))),
1597 "Failed to set soft max dclk!",
1601 if (data->smu_features[GNLD_DPM_VCE].enabled) {
1602 max_freq = data->dpm_table.eclk_table.dpm_state.soft_max_level;
1604 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1605 hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1606 (PPCLK_ECLK << 16) | (max_freq & 0xffff))),
1607 "Failed to set soft max eclk!",
1611 if (data->smu_features[GNLD_DPM_SOCCLK].enabled) {
1612 max_freq = data->dpm_table.soc_table.dpm_state.soft_max_level;
1614 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1615 hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1616 (PPCLK_SOCCLK << 16) | (max_freq & 0xffff))),
1617 "Failed to set soft max socclk!",
1624 int vega20_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
1626 struct vega20_hwmgr *data =
1627 (struct vega20_hwmgr *)(hwmgr->backend);
1630 if (data->smu_features[GNLD_DPM_VCE].supported) {
1631 if (data->smu_features[GNLD_DPM_VCE].enabled == enable) {
1633 PP_DBG_LOG("[EnableDisableVCEDPM] feature VCE DPM already enabled!\n");
1635 PP_DBG_LOG("[EnableDisableVCEDPM] feature VCE DPM already disabled!\n");
1638 ret = vega20_enable_smc_features(hwmgr,
1640 data->smu_features[GNLD_DPM_VCE].smu_feature_bitmap);
1641 PP_ASSERT_WITH_CODE(!ret,
1642 "Attempt to Enable/Disable DPM VCE Failed!",
1644 data->smu_features[GNLD_DPM_VCE].enabled = enable;
1650 static int vega20_get_clock_ranges(struct pp_hwmgr *hwmgr,
1652 PPCLK_e clock_select,
1659 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1660 PPSMC_MSG_GetMaxDpmFreq, (clock_select << 16))) == 0,
1661 "[GetClockRanges] Failed to get max clock from SMC!",
1663 vega20_read_arg_from_smc(hwmgr, clock);
1665 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1666 PPSMC_MSG_GetMinDpmFreq,
1667 (clock_select << 16))) == 0,
1668 "[GetClockRanges] Failed to get min clock from SMC!",
1670 vega20_read_arg_from_smc(hwmgr, clock);
1676 static uint32_t vega20_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
1678 struct vega20_hwmgr *data =
1679 (struct vega20_hwmgr *)(hwmgr->backend);
1683 PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_GFXCLK].enabled,
1684 "[GetSclks]: gfxclk dpm not enabled!\n",
1688 ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, false);
1689 PP_ASSERT_WITH_CODE(!ret,
1690 "[GetSclks]: fail to get min PPCLK_GFXCLK\n",
1693 ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, true);
1694 PP_ASSERT_WITH_CODE(!ret,
1695 "[GetSclks]: fail to get max PPCLK_GFXCLK\n",
1699 return (gfx_clk * 100);
1702 static uint32_t vega20_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
1704 struct vega20_hwmgr *data =
1705 (struct vega20_hwmgr *)(hwmgr->backend);
1709 PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_UCLK].enabled,
1710 "[MemMclks]: memclk dpm not enabled!\n",
1714 ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, false);
1715 PP_ASSERT_WITH_CODE(!ret,
1716 "[GetMclks]: fail to get min PPCLK_UCLK\n",
1719 ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, true);
1720 PP_ASSERT_WITH_CODE(!ret,
1721 "[GetMclks]: fail to get max PPCLK_UCLK\n",
1725 return (mem_clk * 100);
1728 static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
1732 SmuMetrics_t metrics_table;
1734 ret = vega20_copy_table_from_smc(hwmgr, (uint8_t *)&metrics_table, TABLE_SMU_METRICS);
1735 PP_ASSERT_WITH_CODE(!ret,
1736 "Failed to export SMU METRICS table!",
1739 *query = metrics_table.CurrSocketPower << 8;
1744 static int vega20_get_current_gfx_clk_freq(struct pp_hwmgr *hwmgr, uint32_t *gfx_freq)
1746 uint32_t gfx_clk = 0;
1751 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1752 PPSMC_MSG_GetDpmClockFreq, (PPCLK_GFXCLK << 16))) == 0,
1753 "[GetCurrentGfxClkFreq] Attempt to get Current GFXCLK Frequency Failed!",
1755 vega20_read_arg_from_smc(hwmgr, &gfx_clk);
1757 *gfx_freq = gfx_clk * 100;
1762 static int vega20_get_current_mclk_freq(struct pp_hwmgr *hwmgr, uint32_t *mclk_freq)
1764 uint32_t mem_clk = 0;
1769 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1770 PPSMC_MSG_GetDpmClockFreq, (PPCLK_UCLK << 16))) == 0,
1771 "[GetCurrentMClkFreq] Attempt to get Current MCLK Frequency Failed!",
1773 vega20_read_arg_from_smc(hwmgr, &mem_clk);
1775 *mclk_freq = mem_clk * 100;
1780 static int vega20_get_current_activity_percent(struct pp_hwmgr *hwmgr,
1781 uint32_t *activity_percent)
1784 SmuMetrics_t metrics_table;
1786 ret = vega20_copy_table_from_smc(hwmgr, (uint8_t *)&metrics_table, TABLE_SMU_METRICS);
1787 PP_ASSERT_WITH_CODE(!ret,
1788 "Failed to export SMU METRICS table!",
1791 *activity_percent = metrics_table.AverageGfxActivity;
1796 static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
1797 void *value, int *size)
1799 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1803 case AMDGPU_PP_SENSOR_GFX_SCLK:
1804 ret = vega20_get_current_gfx_clk_freq(hwmgr, (uint32_t *)value);
1808 case AMDGPU_PP_SENSOR_GFX_MCLK:
1809 ret = vega20_get_current_mclk_freq(hwmgr, (uint32_t *)value);
1813 case AMDGPU_PP_SENSOR_GPU_LOAD:
1814 ret = vega20_get_current_activity_percent(hwmgr, (uint32_t *)value);
1818 case AMDGPU_PP_SENSOR_GPU_TEMP:
1819 *((uint32_t *)value) = vega20_thermal_get_temperature(hwmgr);
1822 case AMDGPU_PP_SENSOR_UVD_POWER:
1823 *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
1826 case AMDGPU_PP_SENSOR_VCE_POWER:
1827 *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
1830 case AMDGPU_PP_SENSOR_GPU_POWER:
1832 ret = vega20_get_gpu_power(hwmgr, (uint32_t *)value);
1841 static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr,
1844 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1846 if (data->smu_features[GNLD_DPM_UCLK].enabled)
1847 return smum_send_msg_to_smc_with_parameter(hwmgr,
1848 PPSMC_MSG_SetUclkFastSwitch,
1854 int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
1855 struct pp_display_clock_request *clock_req)
1858 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1859 enum amd_pp_clock_type clk_type = clock_req->clock_type;
1860 uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
1861 PPCLK_e clk_select = 0;
1862 uint32_t clk_request = 0;
1864 if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
1866 case amd_pp_dcef_clock:
1867 clk_freq = clock_req->clock_freq_in_khz / 100;
1868 clk_select = PPCLK_DCEFCLK;
1870 case amd_pp_disp_clock:
1871 clk_select = PPCLK_DISPCLK;
1873 case amd_pp_pixel_clock:
1874 clk_select = PPCLK_PIXCLK;
1876 case amd_pp_phy_clock:
1877 clk_select = PPCLK_PHYCLK;
1880 pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
1886 clk_request = (clk_select << 16) | clk_freq;
1887 result = smum_send_msg_to_smc_with_parameter(hwmgr,
1888 PPSMC_MSG_SetHardMinByFreq,
1896 static int vega20_notify_smc_display_config_after_ps_adjustment(
1897 struct pp_hwmgr *hwmgr)
1899 struct vega20_hwmgr *data =
1900 (struct vega20_hwmgr *)(hwmgr->backend);
1901 struct PP_Clocks min_clocks = {0};
1902 struct pp_display_clock_request clock_req;
1905 if ((hwmgr->display_config->num_display > 1) &&
1906 !hwmgr->display_config->multi_monitor_in_sync &&
1907 !hwmgr->display_config->nb_pstate_switch_disable)
1908 vega20_notify_smc_display_change(hwmgr, false);
1910 vega20_notify_smc_display_change(hwmgr, true);
1912 min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
1913 min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
1914 min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
1916 if (data->smu_features[GNLD_DPM_DCEFCLK].supported) {
1917 clock_req.clock_type = amd_pp_dcef_clock;
1918 clock_req.clock_freq_in_khz = min_clocks.dcefClock;
1919 if (!vega20_display_clock_voltage_request(hwmgr, &clock_req)) {
1920 if (data->smu_features[GNLD_DS_DCEFCLK].supported)
1921 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(
1922 hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk,
1923 min_clocks.dcefClockInSR / 100)) == 0,
1924 "Attempt to set divider for DCEFCLK Failed!",
1927 pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
1934 static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr)
1936 struct vega20_hwmgr *data =
1937 (struct vega20_hwmgr *)(hwmgr->backend);
1938 uint32_t soft_level;
1941 soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
1943 data->dpm_table.gfx_table.dpm_state.soft_min_level =
1944 data->dpm_table.gfx_table.dpm_state.soft_max_level =
1945 data->dpm_table.gfx_table.dpm_levels[soft_level].value;
1947 soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
1949 data->dpm_table.mem_table.dpm_state.soft_min_level =
1950 data->dpm_table.mem_table.dpm_state.soft_max_level =
1951 data->dpm_table.mem_table.dpm_levels[soft_level].value;
1953 ret = vega20_upload_dpm_min_level(hwmgr);
1954 PP_ASSERT_WITH_CODE(!ret,
1955 "Failed to upload boot level to highest!",
1958 ret = vega20_upload_dpm_max_level(hwmgr);
1959 PP_ASSERT_WITH_CODE(!ret,
1960 "Failed to upload dpm max level to highest!",
1966 static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
1968 struct vega20_hwmgr *data =
1969 (struct vega20_hwmgr *)(hwmgr->backend);
1970 uint32_t soft_level;
1973 soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
1975 data->dpm_table.gfx_table.dpm_state.soft_min_level =
1976 data->dpm_table.gfx_table.dpm_state.soft_max_level =
1977 data->dpm_table.gfx_table.dpm_levels[soft_level].value;
1979 soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
1981 data->dpm_table.mem_table.dpm_state.soft_min_level =
1982 data->dpm_table.mem_table.dpm_state.soft_max_level =
1983 data->dpm_table.mem_table.dpm_levels[soft_level].value;
1985 ret = vega20_upload_dpm_min_level(hwmgr);
1986 PP_ASSERT_WITH_CODE(!ret,
1987 "Failed to upload boot level to highest!",
1990 ret = vega20_upload_dpm_max_level(hwmgr);
1991 PP_ASSERT_WITH_CODE(!ret,
1992 "Failed to upload dpm max level to highest!",
1999 static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
2003 ret = vega20_upload_dpm_min_level(hwmgr);
2004 PP_ASSERT_WITH_CODE(!ret,
2005 "Failed to upload DPM Bootup Levels!",
2008 ret = vega20_upload_dpm_max_level(hwmgr);
2009 PP_ASSERT_WITH_CODE(!ret,
2010 "Failed to upload DPM Max Levels!",
2016 static int vega20_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level,
2017 uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *soc_mask)
2019 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2020 struct vega20_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table);
2021 struct vega20_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table);
2022 struct vega20_single_dpm_table *soc_dpm_table = &(data->dpm_table.soc_table);
2028 if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
2029 mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
2030 soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
2031 *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
2032 *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
2033 *soc_mask = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
2036 if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2038 } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2040 } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2041 *sclk_mask = gfx_dpm_table->count - 1;
2042 *mclk_mask = mem_dpm_table->count - 1;
2043 *soc_mask = soc_dpm_table->count - 1;
2049 static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
2050 enum pp_clock_type type, uint32_t mask)
2052 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2053 uint32_t soft_min_level, soft_max_level;
2058 soft_min_level = mask ? (ffs(mask) - 1) : 0;
2059 soft_max_level = mask ? (fls(mask) - 1) : 0;
2061 data->dpm_table.gfx_table.dpm_state.soft_min_level =
2062 data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
2063 data->dpm_table.gfx_table.dpm_state.soft_max_level =
2064 data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
2066 ret = vega20_upload_dpm_min_level(hwmgr);
2067 PP_ASSERT_WITH_CODE(!ret,
2068 "Failed to upload boot level to lowest!",
2071 ret = vega20_upload_dpm_max_level(hwmgr);
2072 PP_ASSERT_WITH_CODE(!ret,
2073 "Failed to upload dpm max level to highest!",
2078 soft_min_level = mask ? (ffs(mask) - 1) : 0;
2079 soft_max_level = mask ? (fls(mask) - 1) : 0;
2081 data->dpm_table.mem_table.dpm_state.soft_min_level =
2082 data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
2083 data->dpm_table.mem_table.dpm_state.soft_max_level =
2084 data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
2086 ret = vega20_upload_dpm_min_level(hwmgr);
2087 PP_ASSERT_WITH_CODE(!ret,
2088 "Failed to upload boot level to lowest!",
2091 ret = vega20_upload_dpm_max_level(hwmgr);
2092 PP_ASSERT_WITH_CODE(!ret,
2093 "Failed to upload dpm max level to highest!",
2108 static int vega20_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
2109 enum amd_dpm_forced_level level)
2112 uint32_t sclk_mask, mclk_mask, soc_mask;
2115 case AMD_DPM_FORCED_LEVEL_HIGH:
2116 ret = vega20_force_dpm_highest(hwmgr);
2119 case AMD_DPM_FORCED_LEVEL_LOW:
2120 ret = vega20_force_dpm_lowest(hwmgr);
2123 case AMD_DPM_FORCED_LEVEL_AUTO:
2124 ret = vega20_unforce_dpm_levels(hwmgr);
2127 case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
2128 case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
2129 case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
2130 case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
2131 ret = vega20_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
2134 vega20_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask);
2135 vega20_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask);
2138 case AMD_DPM_FORCED_LEVEL_MANUAL:
2139 case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
2147 static uint32_t vega20_get_fan_control_mode(struct pp_hwmgr *hwmgr)
2149 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2151 if (data->smu_features[GNLD_FAN_CONTROL].enabled == false)
2152 return AMD_FAN_CTRL_MANUAL;
2154 return AMD_FAN_CTRL_AUTO;
2157 static int vega20_get_dal_power_level(struct pp_hwmgr *hwmgr,
2158 struct amd_pp_simple_clock_info *info)
2161 struct phm_ppt_v2_information *table_info =
2162 (struct phm_ppt_v2_information *)hwmgr->pptable;
2163 struct phm_clock_and_voltage_limits *max_limits =
2164 &table_info->max_clock_voltage_on_ac;
2166 info->engine_max_clock = max_limits->sclk;
2167 info->memory_max_clock = max_limits->mclk;
2173 static int vega20_get_sclks(struct pp_hwmgr *hwmgr,
2174 struct pp_clock_levels_with_latency *clocks)
2176 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2177 struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
2180 PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_GFXCLK].enabled,
2181 "[GetSclks]: gfxclk dpm not enabled!\n",
2184 count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2185 clocks->num_levels = count;
2187 for (i = 0; i < count; i++) {
2188 clocks->data[i].clocks_in_khz =
2189 dpm_table->dpm_levels[i].value * 100;
2190 clocks->data[i].latency_in_us = 0;
2196 static uint32_t vega20_get_mem_latency(struct pp_hwmgr *hwmgr,
2202 static int vega20_get_memclocks(struct pp_hwmgr *hwmgr,
2203 struct pp_clock_levels_with_latency *clocks)
2205 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2206 struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.mem_table);
2209 PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_UCLK].enabled,
2210 "[GetMclks]: uclk dpm not enabled!\n",
2213 count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2214 clocks->num_levels = data->mclk_latency_table.count = count;
2216 for (i = 0; i < count; i++) {
2217 clocks->data[i].clocks_in_khz =
2218 data->mclk_latency_table.entries[i].frequency =
2219 dpm_table->dpm_levels[i].value * 100;
2220 clocks->data[i].latency_in_us =
2221 data->mclk_latency_table.entries[i].latency =
2222 vega20_get_mem_latency(hwmgr, dpm_table->dpm_levels[i].value);
2228 static int vega20_get_dcefclocks(struct pp_hwmgr *hwmgr,
2229 struct pp_clock_levels_with_latency *clocks)
2231 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2232 struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.dcef_table);
2235 PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_DCEFCLK].enabled,
2236 "[GetDcfclocks]: dcefclk dpm not enabled!\n",
2239 count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2240 clocks->num_levels = count;
2242 for (i = 0; i < count; i++) {
2243 clocks->data[i].clocks_in_khz =
2244 dpm_table->dpm_levels[i].value * 100;
2245 clocks->data[i].latency_in_us = 0;
2251 static int vega20_get_socclocks(struct pp_hwmgr *hwmgr,
2252 struct pp_clock_levels_with_latency *clocks)
2254 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2255 struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.soc_table);
2258 PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_SOCCLK].enabled,
2259 "[GetSocclks]: socclk dpm not enabled!\n",
2262 count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2263 clocks->num_levels = count;
2265 for (i = 0; i < count; i++) {
2266 clocks->data[i].clocks_in_khz =
2267 dpm_table->dpm_levels[i].value * 100;
2268 clocks->data[i].latency_in_us = 0;
2275 static int vega20_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
2276 enum amd_pp_clock_type type,
2277 struct pp_clock_levels_with_latency *clocks)
2282 case amd_pp_sys_clock:
2283 ret = vega20_get_sclks(hwmgr, clocks);
2285 case amd_pp_mem_clock:
2286 ret = vega20_get_memclocks(hwmgr, clocks);
2288 case amd_pp_dcef_clock:
2289 ret = vega20_get_dcefclocks(hwmgr, clocks);
2291 case amd_pp_soc_clock:
2292 ret = vega20_get_socclocks(hwmgr, clocks);
2301 static int vega20_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
2302 enum amd_pp_clock_type type,
2303 struct pp_clock_levels_with_voltage *clocks)
2305 clocks->num_levels = 0;
2310 static int vega20_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
2313 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2314 Watermarks_t *table = &(data->smc_state_table.water_marks_table);
2315 struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges;
2317 if (!data->registry_data.disable_water_mark &&
2318 data->smu_features[GNLD_DPM_DCEFCLK].supported &&
2319 data->smu_features[GNLD_DPM_SOCCLK].supported) {
2320 smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges);
2321 data->water_marks_bitmap |= WaterMarksExist;
2322 data->water_marks_bitmap &= ~WaterMarksLoaded;
2328 static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
2329 enum PP_OD_DPM_TABLE_COMMAND type,
2330 long *input, uint32_t size)
2332 struct vega20_hwmgr *data =
2333 (struct vega20_hwmgr *)(hwmgr->backend);
2334 struct vega20_od8_single_setting *od8_settings =
2335 data->od8_settings.od8_settings_array;
2336 OverDriveTable_t *od_table =
2337 &(data->smc_state_table.overdrive_table);
2338 struct pp_clock_levels_with_latency clocks;
2339 int32_t input_index, input_clk, input_vol, i;
2342 PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
2346 case PP_OD_EDIT_SCLK_VDDC_TABLE:
2347 if (!(od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2348 od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
2349 pr_info("Sclk min/max frequency overdrive not supported\n");
2353 for (i = 0; i < size; i += 2) {
2355 pr_info("invalid number of input parameters %d\n",
2360 input_index = input[i];
2361 input_clk = input[i + 1];
2363 if (input_index != 0 && input_index != 1) {
2364 pr_info("Invalid index %d\n", input_index);
2365 pr_info("Support min/max sclk frequency setting only which index by 0/1\n");
2369 if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value ||
2370 input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) {
2371 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2373 od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
2374 od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
2378 if (input_index == 0)
2379 od_table->GfxclkFmin = input_clk;
2381 od_table->GfxclkFmax = input_clk;
2386 case PP_OD_EDIT_MCLK_VDDC_TABLE:
2387 if (!od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2388 pr_info("Mclk max frequency overdrive not supported\n");
2392 ret = vega20_get_memclocks(hwmgr, &clocks);
2393 PP_ASSERT_WITH_CODE(!ret,
2394 "Attempt to get memory clk levels failed!",
2397 for (i = 0; i < size; i += 2) {
2399 pr_info("invalid number of input parameters %d\n",
2404 input_index = input[i];
2405 input_clk = input[i + 1];
2407 if (input_index != 1) {
2408 pr_info("Invalid index %d\n", input_index);
2409 pr_info("Support max Mclk frequency setting only which index by 1\n");
2413 if (input_clk < clocks.data[0].clocks_in_khz / 100 ||
2414 input_clk > od8_settings[OD8_SETTING_UCLK_FMAX].max_value) {
2415 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2417 clocks.data[0].clocks_in_khz / 100,
2418 od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
2422 od_table->UclkFmax = input_clk;
2427 case PP_OD_EDIT_VDDC_CURVE:
2428 if (!(od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2429 od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2430 od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2431 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2432 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2433 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
2434 pr_info("Voltage curve calibrate not supported\n");
2438 for (i = 0; i < size; i += 3) {
2440 pr_info("invalid number of input parameters %d\n",
2445 input_index = input[i];
2446 input_clk = input[i + 1];
2447 input_vol = input[i + 2];
2449 if (input_index > 2) {
2450 pr_info("Setting for point %d is not supported\n",
2452 pr_info("Three supported points index by 0, 1, 2\n");
2456 if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value ||
2457 input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) {
2458 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2460 od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
2461 od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
2465 /* TODO: suppose voltage1/2/3 has the same min/max value */
2466 if (input_vol < od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value ||
2467 input_vol > od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value) {
2468 pr_info("clock voltage offset %d is not within allowed range [%d - %d]\n",
2470 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
2471 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
2475 switch (input_index) {
2477 od_table->GfxclkFreq1 = input_clk;
2478 od_table->GfxclkOffsetVolt1 = input_vol;
2481 od_table->GfxclkFreq2 = input_clk;
2482 od_table->GfxclkOffsetVolt2 = input_vol;
2485 od_table->GfxclkFreq3 = input_clk;
2486 od_table->GfxclkOffsetVolt3 = input_vol;
2492 case PP_OD_RESTORE_DEFAULT_TABLE:
2493 ret = vega20_copy_table_from_smc(hwmgr,
2494 (uint8_t *)od_table,
2496 PP_ASSERT_WITH_CODE(!ret,
2497 "Failed to export overdrive table!",
2501 case PP_OD_COMMIT_DPM_TABLE:
2502 ret = vega20_copy_table_to_smc(hwmgr,
2503 (uint8_t *)od_table,
2505 PP_ASSERT_WITH_CODE(!ret,
2506 "Failed to import overdrive table!",
2518 static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
2519 enum pp_clock_type type, char *buf)
2521 struct vega20_hwmgr *data =
2522 (struct vega20_hwmgr *)(hwmgr->backend);
2523 struct vega20_od8_single_setting *od8_settings =
2524 data->od8_settings.od8_settings_array;
2525 OverDriveTable_t *od_table =
2526 &(data->smc_state_table.overdrive_table);
2527 struct pp_clock_levels_with_latency clocks;
2528 int i, now, size = 0;
2533 ret = vega20_get_current_gfx_clk_freq(hwmgr, &now);
2534 PP_ASSERT_WITH_CODE(!ret,
2535 "Attempt to get current gfx clk Failed!",
2538 ret = vega20_get_sclks(hwmgr, &clocks);
2539 PP_ASSERT_WITH_CODE(!ret,
2540 "Attempt to get gfx clk levels Failed!",
2543 for (i = 0; i < clocks.num_levels; i++)
2544 size += sprintf(buf + size, "%d: %uMhz %s\n",
2545 i, clocks.data[i].clocks_in_khz / 100,
2546 (clocks.data[i].clocks_in_khz == now) ? "*" : "");
2550 ret = vega20_get_current_mclk_freq(hwmgr, &now);
2551 PP_ASSERT_WITH_CODE(!ret,
2552 "Attempt to get current mclk freq Failed!",
2555 ret = vega20_get_memclocks(hwmgr, &clocks);
2556 PP_ASSERT_WITH_CODE(!ret,
2557 "Attempt to get memory clk levels Failed!",
2560 for (i = 0; i < clocks.num_levels; i++)
2561 size += sprintf(buf + size, "%d: %uMhz %s\n",
2562 i, clocks.data[i].clocks_in_khz / 100,
2563 (clocks.data[i].clocks_in_khz == now) ? "*" : "");
2570 if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2571 od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
2572 size = sprintf(buf, "%s:\n", "OD_SCLK");
2573 size += sprintf(buf + size, "0: %10uMhz\n",
2574 od_table->GfxclkFmin);
2575 size += sprintf(buf + size, "1: %10uMhz\n",
2576 od_table->GfxclkFmax);
2581 if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2582 size = sprintf(buf, "%s:\n", "OD_MCLK");
2583 size += sprintf(buf + size, "1: %10uMhz\n",
2584 od_table->UclkFmax);
2590 if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2591 od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2592 od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2593 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2594 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2595 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
2596 size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE");
2597 size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
2598 od_table->GfxclkFreq1,
2599 od_table->GfxclkOffsetVolt1);
2600 size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
2601 od_table->GfxclkFreq2,
2602 od_table->GfxclkOffsetVolt2);
2603 size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
2604 od_table->GfxclkFreq3,
2605 od_table->GfxclkOffsetVolt3);
2611 size = sprintf(buf, "%s:\n", "OD_RANGE");
2613 if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2614 od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
2615 size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
2616 od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
2617 od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
2620 if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2621 ret = vega20_get_memclocks(hwmgr, &clocks);
2622 PP_ASSERT_WITH_CODE(!ret,
2623 "Fail to get memory clk levels!",
2626 size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
2627 clocks.data[0].clocks_in_khz / 100,
2628 od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
2631 if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2632 od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2633 od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2634 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2635 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2636 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
2637 size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
2638 od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value,
2639 od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value);
2640 size += sprintf(buf + size, "VDDC_CURVE_VOFF[0]: %7dmV %11dmV\n",
2641 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
2642 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
2643 size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
2644 od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value,
2645 od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value);
2646 size += sprintf(buf + size, "VDDC_CURVE_VOFF[1]: %7dmV %11dmV\n",
2647 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
2648 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
2649 size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
2650 od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value,
2651 od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value);
2652 size += sprintf(buf + size, "VDDC_CURVE_VOFF[2]: %7dmV %11dmV\n",
2653 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
2654 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
2664 static int vega20_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr,
2665 struct vega20_single_dpm_table *dpm_table)
2667 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2670 if (data->smu_features[GNLD_DPM_UCLK].enabled) {
2671 PP_ASSERT_WITH_CODE(dpm_table->count > 0,
2672 "[SetUclkToHightestDpmLevel] Dpm table has no entry!",
2674 PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_UCLK_DPM_LEVELS,
2675 "[SetUclkToHightestDpmLevel] Dpm table has too many entries!",
2678 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2679 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2680 PPSMC_MSG_SetHardMinByFreq,
2681 (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level)),
2682 "[SetUclkToHightestDpmLevel] Set hard min uclk failed!",
2689 static int vega20_pre_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
2691 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2694 smum_send_msg_to_smc_with_parameter(hwmgr,
2695 PPSMC_MSG_NumOfDisplays, 0);
2697 ret = vega20_set_uclk_to_highest_dpm_level(hwmgr,
2698 &data->dpm_table.mem_table);
2703 static int vega20_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
2705 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2707 Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table);
2709 if ((data->water_marks_bitmap & WaterMarksExist) &&
2710 !(data->water_marks_bitmap & WaterMarksLoaded)) {
2711 result = vega20_copy_table_to_smc(hwmgr,
2712 (uint8_t *)wm_table, TABLE_WATERMARKS);
2713 PP_ASSERT_WITH_CODE(!result,
2714 "Failed to update WMTABLE!",
2716 data->water_marks_bitmap |= WaterMarksLoaded;
2719 if ((data->water_marks_bitmap & WaterMarksExist) &&
2720 data->smu_features[GNLD_DPM_DCEFCLK].supported &&
2721 data->smu_features[GNLD_DPM_SOCCLK].supported) {
2722 result = smum_send_msg_to_smc_with_parameter(hwmgr,
2723 PPSMC_MSG_NumOfDisplays,
2724 hwmgr->display_config->num_display);
2730 int vega20_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
2732 struct vega20_hwmgr *data =
2733 (struct vega20_hwmgr *)(hwmgr->backend);
2736 if (data->smu_features[GNLD_DPM_UVD].supported) {
2737 if (data->smu_features[GNLD_DPM_UVD].enabled == enable) {
2739 PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already enabled!\n");
2741 PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already disabled!\n");
2744 ret = vega20_enable_smc_features(hwmgr,
2746 data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap);
2747 PP_ASSERT_WITH_CODE(!ret,
2748 "[EnableDisableUVDDPM] Attempt to Enable/Disable DPM UVD Failed!",
2750 data->smu_features[GNLD_DPM_UVD].enabled = enable;
2756 static void vega20_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate)
2758 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2760 if (data->vce_power_gated == bgate)
2763 data->vce_power_gated = bgate;
2764 vega20_enable_disable_vce_dpm(hwmgr, !bgate);
2767 static void vega20_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
2769 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2771 if (data->uvd_power_gated == bgate)
2774 data->uvd_power_gated = bgate;
2775 vega20_enable_disable_uvd_dpm(hwmgr, !bgate);
2778 static int vega20_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr)
2780 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2781 struct vega20_single_dpm_table *dpm_table;
2782 bool vblank_too_short = false;
2783 bool disable_mclk_switching;
2784 uint32_t i, latency;
2786 disable_mclk_switching = ((1 < hwmgr->display_config->num_display) &&
2787 !hwmgr->display_config->multi_monitor_in_sync) ||
2789 latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency;
2792 dpm_table = &(data->dpm_table.gfx_table);
2793 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2794 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2795 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2796 dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2798 if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
2799 if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
2800 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2801 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2804 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2805 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2806 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
2809 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2810 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2811 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2816 dpm_table = &(data->dpm_table.mem_table);
2817 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2818 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2819 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2820 dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2822 if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
2823 if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
2824 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
2825 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
2828 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2829 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2830 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
2833 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2834 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2835 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2839 /* honour DAL's UCLK Hardmin */
2840 if (dpm_table->dpm_state.hard_min_level < (hwmgr->display_config->min_mem_set_clock / 100))
2841 dpm_table->dpm_state.hard_min_level = hwmgr->display_config->min_mem_set_clock / 100;
2843 /* Hardmin is dependent on displayconfig */
2844 if (disable_mclk_switching) {
2845 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2846 for (i = 0; i < data->mclk_latency_table.count - 1; i++) {
2847 if (data->mclk_latency_table.entries[i].latency <= latency) {
2848 if (dpm_table->dpm_levels[i].value >= (hwmgr->display_config->min_mem_set_clock / 100)) {
2849 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
2856 if (hwmgr->display_config->nb_pstate_switch_disable)
2857 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2860 dpm_table = &(data->dpm_table.vclk_table);
2861 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2862 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2863 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2864 dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2866 if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
2867 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
2868 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2869 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2872 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2873 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2874 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2879 dpm_table = &(data->dpm_table.dclk_table);
2880 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2881 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2882 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2883 dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2885 if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
2886 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
2887 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2888 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2891 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2892 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2893 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2898 dpm_table = &(data->dpm_table.soc_table);
2899 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2900 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2901 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2902 dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2904 if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
2905 if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
2906 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
2907 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
2910 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2911 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2912 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2917 dpm_table = &(data->dpm_table.eclk_table);
2918 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2919 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2920 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2921 dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2923 if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
2924 if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
2925 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
2926 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
2929 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2930 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2931 dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2939 vega20_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
2941 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2942 bool is_update_required = false;
2944 if (data->display_timing.num_existing_displays !=
2945 hwmgr->display_config->num_display)
2946 is_update_required = true;
2948 if (data->registry_data.gfx_clk_deep_sleep_support &&
2949 (data->display_timing.min_clock_in_sr !=
2950 hwmgr->display_config->min_core_set_clock_in_sr))
2951 is_update_required = true;
2953 return is_update_required;
2956 static int vega20_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
2960 ret = vega20_disable_all_smu_features(hwmgr);
2961 PP_ASSERT_WITH_CODE(!ret,
2962 "[DisableDpmTasks] Failed to disable all smu features!",
2968 static int vega20_power_off_asic(struct pp_hwmgr *hwmgr)
2970 struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2973 result = vega20_disable_dpm_tasks(hwmgr);
2974 PP_ASSERT_WITH_CODE((0 == result),
2975 "[PowerOffAsic] Failed to disable DPM!",
2977 data->water_marks_bitmap &= ~(WaterMarksLoaded);
2982 static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
2984 DpmActivityMonitorCoeffInt_t activity_monitor;
2985 uint32_t i, size = 0;
2986 uint16_t workload_type = 0;
2987 static const char *profile_name[] = {
2994 static const char *title[] = {
2995 "PROFILE_INDEX(NAME)",
2999 "MinActiveFreqType",
3004 "PD_Data_error_coeff",
3005 "PD_Data_error_rate_coeff"};
3011 size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
3012 title[0], title[1], title[2], title[3], title[4], title[5],
3013 title[6], title[7], title[8], title[9], title[10]);
3015 for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
3016 /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
3017 workload_type = i + 1;
3018 result = vega20_get_activity_monitor_coeff(hwmgr,
3019 (uint8_t *)(&activity_monitor), workload_type);
3020 PP_ASSERT_WITH_CODE(!result,
3021 "[GetPowerProfile] Failed to get activity monitor!",
3024 size += sprintf(buf + size, "%2d(%14s%s)\n",
3025 i, profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ");
3027 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3031 activity_monitor.Gfx_FPS,
3032 activity_monitor.Gfx_UseRlcBusy,
3033 activity_monitor.Gfx_MinActiveFreqType,
3034 activity_monitor.Gfx_MinActiveFreq,
3035 activity_monitor.Gfx_BoosterFreqType,
3036 activity_monitor.Gfx_BoosterFreq,
3037 activity_monitor.Gfx_PD_Data_limit_c,
3038 activity_monitor.Gfx_PD_Data_error_coeff,
3039 activity_monitor.Gfx_PD_Data_error_rate_coeff);
3041 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3045 activity_monitor.Soc_FPS,
3046 activity_monitor.Soc_UseRlcBusy,
3047 activity_monitor.Soc_MinActiveFreqType,
3048 activity_monitor.Soc_MinActiveFreq,
3049 activity_monitor.Soc_BoosterFreqType,
3050 activity_monitor.Soc_BoosterFreq,
3051 activity_monitor.Soc_PD_Data_limit_c,
3052 activity_monitor.Soc_PD_Data_error_coeff,
3053 activity_monitor.Soc_PD_Data_error_rate_coeff);
3055 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3059 activity_monitor.Mem_FPS,
3060 activity_monitor.Mem_UseRlcBusy,
3061 activity_monitor.Mem_MinActiveFreqType,
3062 activity_monitor.Mem_MinActiveFreq,
3063 activity_monitor.Mem_BoosterFreqType,
3064 activity_monitor.Mem_BoosterFreq,
3065 activity_monitor.Mem_PD_Data_limit_c,
3066 activity_monitor.Mem_PD_Data_error_coeff,
3067 activity_monitor.Mem_PD_Data_error_rate_coeff);
3069 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3073 activity_monitor.Fclk_FPS,
3074 activity_monitor.Fclk_UseRlcBusy,
3075 activity_monitor.Fclk_MinActiveFreqType,
3076 activity_monitor.Fclk_MinActiveFreq,
3077 activity_monitor.Fclk_BoosterFreqType,
3078 activity_monitor.Fclk_BoosterFreq,
3079 activity_monitor.Fclk_PD_Data_limit_c,
3080 activity_monitor.Fclk_PD_Data_error_coeff,
3081 activity_monitor.Fclk_PD_Data_error_rate_coeff);
3087 static int vega20_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size)
3089 DpmActivityMonitorCoeffInt_t activity_monitor;
3092 hwmgr->power_profile_mode = input[size];
3094 if (hwmgr->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
3098 result = vega20_get_activity_monitor_coeff(hwmgr,
3099 (uint8_t *)(&activity_monitor),
3100 WORKLOAD_PPLIB_CUSTOM_BIT);
3101 PP_ASSERT_WITH_CODE(!result,
3102 "[SetPowerProfile] Failed to get activity monitor!",
3106 case 0: /* Gfxclk */
3107 activity_monitor.Gfx_FPS = input[1];
3108 activity_monitor.Gfx_UseRlcBusy = input[2];
3109 activity_monitor.Gfx_MinActiveFreqType = input[3];
3110 activity_monitor.Gfx_MinActiveFreq = input[4];
3111 activity_monitor.Gfx_BoosterFreqType = input[5];
3112 activity_monitor.Gfx_BoosterFreq = input[6];
3113 activity_monitor.Gfx_PD_Data_limit_c = input[7];
3114 activity_monitor.Gfx_PD_Data_error_coeff = input[8];
3115 activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
3117 case 1: /* Socclk */
3118 activity_monitor.Soc_FPS = input[1];
3119 activity_monitor.Soc_UseRlcBusy = input[2];
3120 activity_monitor.Soc_MinActiveFreqType = input[3];
3121 activity_monitor.Soc_MinActiveFreq = input[4];
3122 activity_monitor.Soc_BoosterFreqType = input[5];
3123 activity_monitor.Soc_BoosterFreq = input[6];
3124 activity_monitor.Soc_PD_Data_limit_c = input[7];
3125 activity_monitor.Soc_PD_Data_error_coeff = input[8];
3126 activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
3129 activity_monitor.Mem_FPS = input[1];
3130 activity_monitor.Mem_UseRlcBusy = input[2];
3131 activity_monitor.Mem_MinActiveFreqType = input[3];
3132 activity_monitor.Mem_MinActiveFreq = input[4];
3133 activity_monitor.Mem_BoosterFreqType = input[5];
3134 activity_monitor.Mem_BoosterFreq = input[6];
3135 activity_monitor.Mem_PD_Data_limit_c = input[7];
3136 activity_monitor.Mem_PD_Data_error_coeff = input[8];
3137 activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
3140 activity_monitor.Fclk_FPS = input[1];
3141 activity_monitor.Fclk_UseRlcBusy = input[2];
3142 activity_monitor.Fclk_MinActiveFreqType = input[3];
3143 activity_monitor.Fclk_MinActiveFreq = input[4];
3144 activity_monitor.Fclk_BoosterFreqType = input[5];
3145 activity_monitor.Fclk_BoosterFreq = input[6];
3146 activity_monitor.Fclk_PD_Data_limit_c = input[7];
3147 activity_monitor.Fclk_PD_Data_error_coeff = input[8];
3148 activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
3152 result = vega20_set_activity_monitor_coeff(hwmgr,
3153 (uint8_t *)(&activity_monitor),
3154 WORKLOAD_PPLIB_CUSTOM_BIT);
3155 PP_ASSERT_WITH_CODE(!result,
3156 "[SetPowerProfile] Failed to set activity monitor!",
3160 smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask,
3161 1 << hwmgr->power_profile_mode);
3166 static int vega20_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
3167 uint32_t virtual_addr_low,
3168 uint32_t virtual_addr_hi,
3169 uint32_t mc_addr_low,
3170 uint32_t mc_addr_hi,
3173 smum_send_msg_to_smc_with_parameter(hwmgr,
3174 PPSMC_MSG_SetSystemVirtualDramAddrHigh,
3176 smum_send_msg_to_smc_with_parameter(hwmgr,
3177 PPSMC_MSG_SetSystemVirtualDramAddrLow,
3179 smum_send_msg_to_smc_with_parameter(hwmgr,
3180 PPSMC_MSG_DramLogSetDramAddrHigh,
3183 smum_send_msg_to_smc_with_parameter(hwmgr,
3184 PPSMC_MSG_DramLogSetDramAddrLow,
3187 smum_send_msg_to_smc_with_parameter(hwmgr,
3188 PPSMC_MSG_DramLogSetDramSize,
3193 static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
3194 struct PP_TemperatureRange *thermal_data)
3196 struct phm_ppt_v3_information *pptable_information =
3197 (struct phm_ppt_v3_information *)hwmgr->pptable;
3199 memcpy(thermal_data, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange));
3201 thermal_data->max = pptable_information->us_software_shutdown_temp *
3202 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
3207 static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
3208 /* init/fini related */
3210 vega20_hwmgr_backend_init,
3212 vega20_hwmgr_backend_fini,
3214 vega20_setup_asic_task,
3216 vega20_power_off_asic,
3217 .dynamic_state_management_enable =
3218 vega20_enable_dpm_tasks,
3219 .dynamic_state_management_disable =
3220 vega20_disable_dpm_tasks,
3221 /* power state related */
3222 .apply_clocks_adjust_rules =
3223 vega20_apply_clocks_adjust_rules,
3224 .pre_display_config_changed =
3225 vega20_pre_display_configuration_changed_task,
3226 .display_config_changed =
3227 vega20_display_configuration_changed_task,
3228 .check_smc_update_required_for_display_configuration =
3229 vega20_check_smc_update_required_for_display_configuration,
3230 .notify_smc_display_config_after_ps_adjustment =
3231 vega20_notify_smc_display_config_after_ps_adjustment,
3234 vega20_dpm_get_sclk,
3236 vega20_dpm_get_mclk,
3237 .get_dal_power_level =
3238 vega20_get_dal_power_level,
3239 .get_clock_by_type_with_latency =
3240 vega20_get_clock_by_type_with_latency,
3241 .get_clock_by_type_with_voltage =
3242 vega20_get_clock_by_type_with_voltage,
3243 .set_watermarks_for_clocks_ranges =
3244 vega20_set_watermarks_for_clocks_ranges,
3245 .display_clock_voltage_request =
3246 vega20_display_clock_voltage_request,
3247 /* UMD pstate, profile related */
3249 vega20_dpm_force_dpm_level,
3250 .get_power_profile_mode =
3251 vega20_get_power_profile_mode,
3252 .set_power_profile_mode =
3253 vega20_set_power_profile_mode,
3256 vega20_set_power_limit,
3265 .odn_edit_dpm_table =
3266 vega20_odn_edit_dpm_table,
3267 /* for sysfs to retrive/set gfxclk/memclk */
3268 .force_clock_level =
3269 vega20_force_clock_level,
3270 .print_clock_levels =
3271 vega20_print_clock_levels,
3274 /* powergate related */
3276 vega20_power_gate_uvd,
3278 vega20_power_gate_vce,
3279 /* thermal related */
3280 .start_thermal_controller =
3281 vega20_start_thermal_controller,
3282 .stop_thermal_controller =
3283 vega20_thermal_stop_thermal_controller,
3284 .get_thermal_temperature_range =
3285 vega20_get_thermal_temperature_range,
3286 .register_irq_handlers =
3287 smu9_register_irq_handlers,
3288 .disable_smc_firmware_ctf =
3289 vega20_thermal_disable_alert,
3290 /* fan control related */
3291 .get_fan_speed_info =
3292 vega20_fan_ctrl_get_fan_speed_info,
3293 .get_fan_speed_rpm =
3294 vega20_fan_ctrl_get_fan_speed_rpm,
3295 .get_fan_control_mode =
3296 vega20_get_fan_control_mode,
3297 /* smu memory related */
3298 .notify_cac_buffer_info =
3299 vega20_notify_cac_buffer_info,
3302 int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
3304 hwmgr->hwmgr_func = &vega20_hwmgr_funcs;
3305 hwmgr->pptable_func = &vega20_pptable_funcs;