1068ea8bdSYifan Zhang /* 2068ea8bdSYifan Zhang * Copyright 2020 Advanced Micro Devices, Inc. 3068ea8bdSYifan Zhang * 4068ea8bdSYifan Zhang * Permission is hereby granted, free of charge, to any person obtaining a 5068ea8bdSYifan Zhang * copy of this software and associated documentation files (the "Software"), 6068ea8bdSYifan Zhang * to deal in the Software without restriction, including without limitation 7068ea8bdSYifan Zhang * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8068ea8bdSYifan Zhang * and/or sell copies of the Software, and to permit persons to whom the 9068ea8bdSYifan Zhang * Software is furnished to do so, subject to the following conditions: 10068ea8bdSYifan Zhang * 11068ea8bdSYifan Zhang * The above copyright notice and this permission notice shall be included in 12068ea8bdSYifan Zhang * all copies or substantial portions of the Software. 13068ea8bdSYifan Zhang * 14068ea8bdSYifan Zhang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15068ea8bdSYifan Zhang * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16068ea8bdSYifan Zhang * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17068ea8bdSYifan Zhang * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18068ea8bdSYifan Zhang * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19068ea8bdSYifan Zhang * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20068ea8bdSYifan Zhang * OTHER DEALINGS IN THE SOFTWARE. 21068ea8bdSYifan Zhang * 22068ea8bdSYifan Zhang */ 23068ea8bdSYifan Zhang 24068ea8bdSYifan Zhang #define SWSMU_CODE_LAYER_L2 25068ea8bdSYifan Zhang 26068ea8bdSYifan Zhang #include "amdgpu.h" 27068ea8bdSYifan Zhang #include "amdgpu_smu.h" 28068ea8bdSYifan Zhang #include "smu_v13_0.h" 29068ea8bdSYifan Zhang #include "smu13_driver_if_v13_0_5.h" 30068ea8bdSYifan Zhang #include "smu_v13_0_5_ppt.h" 31068ea8bdSYifan Zhang #include "smu_v13_0_5_ppsmc.h" 32068ea8bdSYifan Zhang #include "smu_v13_0_5_pmfw.h" 33068ea8bdSYifan Zhang #include "smu_cmn.h" 34068ea8bdSYifan Zhang 35068ea8bdSYifan Zhang /* 36068ea8bdSYifan Zhang * DO NOT use these for err/warn/info/debug messages. 37068ea8bdSYifan Zhang * Use dev_err, dev_warn, dev_info and dev_dbg instead. 38068ea8bdSYifan Zhang * They are more MGPU friendly. 39068ea8bdSYifan Zhang */ 40068ea8bdSYifan Zhang #undef pr_err 41068ea8bdSYifan Zhang #undef pr_warn 42068ea8bdSYifan Zhang #undef pr_info 43068ea8bdSYifan Zhang #undef pr_debug 44068ea8bdSYifan Zhang 45da1db031SAlex Deucher #define mmMP1_C2PMSG_2 (0xbee142 + 0xb00000 / 4) 46da1db031SAlex Deucher #define mmMP1_C2PMSG_2_BASE_IDX 0 47da1db031SAlex Deucher 48da1db031SAlex Deucher #define mmMP1_C2PMSG_34 (0xbee262 + 0xb00000 / 4) 49da1db031SAlex Deucher #define mmMP1_C2PMSG_34_BASE_IDX 0 50da1db031SAlex Deucher 51da1db031SAlex Deucher #define mmMP1_C2PMSG_33 (0xbee261 + 0xb00000 / 4) 52da1db031SAlex Deucher #define mmMP1_C2PMSG_33_BASE_IDX 0 53da1db031SAlex Deucher 54068ea8bdSYifan Zhang #define FEATURE_MASK(feature) (1ULL << feature) 55068ea8bdSYifan Zhang #define SMC_DPM_FEATURE ( \ 56068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ 57068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ 58068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ 59068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \ 60068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ 61068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \ 62068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)| \ 63068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)| \ 64068ea8bdSYifan Zhang FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)) 65068ea8bdSYifan Zhang 66068ea8bdSYifan Zhang static struct cmn2asic_msg_mapping smu_v13_0_5_message_map[SMU_MSG_MAX_COUNT] = { 67068ea8bdSYifan Zhang MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), 68068ea8bdSYifan Zhang MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), 69068ea8bdSYifan Zhang MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 1), 70068ea8bdSYifan Zhang MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 1), 71068ea8bdSYifan Zhang MSG_MAP(SetHardMinVcn, PPSMC_MSG_SetHardMinVcn, 1), 72068ea8bdSYifan Zhang MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxclk, 1), 73068ea8bdSYifan Zhang MSG_MAP(Spare0, PPSMC_MSG_Spare0, 1), 74068ea8bdSYifan Zhang MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDeviceDriverReset, 1), 75068ea8bdSYifan Zhang MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), 76068ea8bdSYifan Zhang MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), 77068ea8bdSYifan Zhang MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), 78068ea8bdSYifan Zhang MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu , 1), 79068ea8bdSYifan Zhang MSG_MAP(GetGfxclkFrequency, PPSMC_MSG_GetGfxclkFrequency, 1), 80068ea8bdSYifan Zhang MSG_MAP(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1), 81068ea8bdSYifan Zhang MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn, 1), 82068ea8bdSYifan Zhang MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 1), 83068ea8bdSYifan Zhang MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 1), 84068ea8bdSYifan Zhang MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), 85068ea8bdSYifan Zhang MSG_MAP(SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk, 1), 86068ea8bdSYifan Zhang MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 1), 87068ea8bdSYifan Zhang MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 1), 88068ea8bdSYifan Zhang MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn, 1), 89068ea8bdSYifan Zhang MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), 90068ea8bdSYifan Zhang MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1), 91068ea8bdSYifan Zhang }; 92068ea8bdSYifan Zhang 93068ea8bdSYifan Zhang static struct cmn2asic_mapping smu_v13_0_5_feature_mask_map[SMU_FEATURE_COUNT] = { 94068ea8bdSYifan Zhang FEA_MAP(DATA_CALCULATION), 95068ea8bdSYifan Zhang FEA_MAP(PPT), 96068ea8bdSYifan Zhang FEA_MAP(TDC), 97068ea8bdSYifan Zhang FEA_MAP(THERMAL), 98068ea8bdSYifan Zhang FEA_MAP(PROCHOT), 99068ea8bdSYifan Zhang FEA_MAP(CCLK_DPM), 100068ea8bdSYifan Zhang FEA_MAP_REVERSE(FCLK), 101068ea8bdSYifan Zhang FEA_MAP(LCLK_DPM), 102068ea8bdSYifan Zhang FEA_MAP(DF_CSTATES), 103068ea8bdSYifan Zhang FEA_MAP(FAN_CONTROLLER), 104068ea8bdSYifan Zhang FEA_MAP(CPPC), 105068ea8bdSYifan Zhang FEA_MAP_HALF_REVERSE(GFX), 106068ea8bdSYifan Zhang FEA_MAP(DS_GFXCLK), 107068ea8bdSYifan Zhang FEA_MAP(S0I3), 108068ea8bdSYifan Zhang FEA_MAP(VCN_DPM), 109068ea8bdSYifan Zhang FEA_MAP(DS_VCN), 110068ea8bdSYifan Zhang FEA_MAP(DCFCLK_DPM), 111068ea8bdSYifan Zhang FEA_MAP(ATHUB_PG), 112068ea8bdSYifan Zhang FEA_MAP_REVERSE(SOCCLK), 113068ea8bdSYifan Zhang FEA_MAP(SHUBCLK_DPM), 114068ea8bdSYifan Zhang FEA_MAP(GFXOFF), 115068ea8bdSYifan Zhang }; 116068ea8bdSYifan Zhang 117068ea8bdSYifan Zhang static struct cmn2asic_mapping smu_v13_0_5_table_map[SMU_TABLE_COUNT] = { 118068ea8bdSYifan Zhang TAB_MAP_VALID(WATERMARKS), 119068ea8bdSYifan Zhang TAB_MAP_VALID(SMU_METRICS), 120068ea8bdSYifan Zhang TAB_MAP_VALID(CUSTOM_DPM), 121068ea8bdSYifan Zhang TAB_MAP_VALID(DPMCLOCKS), 122068ea8bdSYifan Zhang }; 123068ea8bdSYifan Zhang 124068ea8bdSYifan Zhang static int smu_v13_0_5_init_smc_tables(struct smu_context *smu) 125068ea8bdSYifan Zhang { 126068ea8bdSYifan Zhang struct smu_table_context *smu_table = &smu->smu_table; 127068ea8bdSYifan Zhang struct smu_table *tables = smu_table->tables; 128068ea8bdSYifan Zhang 129068ea8bdSYifan Zhang SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), 130068ea8bdSYifan Zhang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); 131068ea8bdSYifan Zhang SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t), 132068ea8bdSYifan Zhang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); 133068ea8bdSYifan Zhang SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), 134068ea8bdSYifan Zhang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); 135068ea8bdSYifan Zhang 136068ea8bdSYifan Zhang smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); 137068ea8bdSYifan Zhang if (!smu_table->clocks_table) 138068ea8bdSYifan Zhang goto err0_out; 139068ea8bdSYifan Zhang 140068ea8bdSYifan Zhang smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); 141068ea8bdSYifan Zhang if (!smu_table->metrics_table) 142068ea8bdSYifan Zhang goto err1_out; 143068ea8bdSYifan Zhang smu_table->metrics_time = 0; 144068ea8bdSYifan Zhang 145068ea8bdSYifan Zhang smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); 146068ea8bdSYifan Zhang if (!smu_table->watermarks_table) 147068ea8bdSYifan Zhang goto err2_out; 148068ea8bdSYifan Zhang 149068ea8bdSYifan Zhang smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1); 150068ea8bdSYifan Zhang smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); 151068ea8bdSYifan Zhang if (!smu_table->gpu_metrics_table) 152068ea8bdSYifan Zhang goto err3_out; 153068ea8bdSYifan Zhang 154068ea8bdSYifan Zhang return 0; 155068ea8bdSYifan Zhang 156068ea8bdSYifan Zhang err3_out: 157068ea8bdSYifan Zhang kfree(smu_table->watermarks_table); 158068ea8bdSYifan Zhang err2_out: 159068ea8bdSYifan Zhang kfree(smu_table->metrics_table); 160068ea8bdSYifan Zhang err1_out: 161068ea8bdSYifan Zhang kfree(smu_table->clocks_table); 162068ea8bdSYifan Zhang err0_out: 163068ea8bdSYifan Zhang return -ENOMEM; 164068ea8bdSYifan Zhang } 165068ea8bdSYifan Zhang 166068ea8bdSYifan Zhang static int smu_v13_0_5_fini_smc_tables(struct smu_context *smu) 167068ea8bdSYifan Zhang { 168068ea8bdSYifan Zhang struct smu_table_context *smu_table = &smu->smu_table; 169068ea8bdSYifan Zhang 170068ea8bdSYifan Zhang kfree(smu_table->clocks_table); 171068ea8bdSYifan Zhang smu_table->clocks_table = NULL; 172068ea8bdSYifan Zhang 173068ea8bdSYifan Zhang kfree(smu_table->metrics_table); 174068ea8bdSYifan Zhang smu_table->metrics_table = NULL; 175068ea8bdSYifan Zhang 176068ea8bdSYifan Zhang kfree(smu_table->watermarks_table); 177068ea8bdSYifan Zhang smu_table->watermarks_table = NULL; 178068ea8bdSYifan Zhang 179541d54e4SZhen Ni kfree(smu_table->gpu_metrics_table); 180541d54e4SZhen Ni smu_table->gpu_metrics_table = NULL; 181541d54e4SZhen Ni 182068ea8bdSYifan Zhang return 0; 183068ea8bdSYifan Zhang } 184068ea8bdSYifan Zhang 185068ea8bdSYifan Zhang static int smu_v13_0_5_system_features_control(struct smu_context *smu, bool en) 186068ea8bdSYifan Zhang { 187068ea8bdSYifan Zhang struct amdgpu_device *adev = smu->adev; 188068ea8bdSYifan Zhang int ret = 0; 189068ea8bdSYifan Zhang 190068ea8bdSYifan Zhang if (!en && !adev->in_s0ix) 191068ea8bdSYifan Zhang ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); 192068ea8bdSYifan Zhang 193068ea8bdSYifan Zhang return ret; 194068ea8bdSYifan Zhang } 195068ea8bdSYifan Zhang 196068ea8bdSYifan Zhang static int smu_v13_0_5_dpm_set_vcn_enable(struct smu_context *smu, bool enable) 197068ea8bdSYifan Zhang { 198068ea8bdSYifan Zhang int ret = 0; 199068ea8bdSYifan Zhang 200068ea8bdSYifan Zhang /* vcn dpm on is a prerequisite for vcn power gate messages */ 201068ea8bdSYifan Zhang if (enable) 202068ea8bdSYifan Zhang ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 203068ea8bdSYifan Zhang 0, NULL); 204068ea8bdSYifan Zhang else 205068ea8bdSYifan Zhang ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, 206068ea8bdSYifan Zhang 0, NULL); 207068ea8bdSYifan Zhang 208068ea8bdSYifan Zhang return ret; 209068ea8bdSYifan Zhang } 210068ea8bdSYifan Zhang 211068ea8bdSYifan Zhang static int smu_v13_0_5_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) 212068ea8bdSYifan Zhang { 213068ea8bdSYifan Zhang int ret = 0; 214068ea8bdSYifan Zhang 215068ea8bdSYifan Zhang if (enable) 216068ea8bdSYifan Zhang ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 217068ea8bdSYifan Zhang 0, NULL); 218068ea8bdSYifan Zhang else 219068ea8bdSYifan Zhang ret = smu_cmn_send_smc_msg_with_param(smu, 220068ea8bdSYifan Zhang SMU_MSG_PowerDownJpeg, 0, 221068ea8bdSYifan Zhang NULL); 222068ea8bdSYifan Zhang 223068ea8bdSYifan Zhang return ret; 224068ea8bdSYifan Zhang } 225068ea8bdSYifan Zhang 226068ea8bdSYifan Zhang 227068ea8bdSYifan Zhang static bool smu_v13_0_5_is_dpm_running(struct smu_context *smu) 228068ea8bdSYifan Zhang { 229068ea8bdSYifan Zhang int ret = 0; 230068ea8bdSYifan Zhang uint64_t feature_enabled; 231068ea8bdSYifan Zhang 232068ea8bdSYifan Zhang ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); 233068ea8bdSYifan Zhang 234068ea8bdSYifan Zhang if (ret) 235068ea8bdSYifan Zhang return false; 236068ea8bdSYifan Zhang 237068ea8bdSYifan Zhang return !!(feature_enabled & SMC_DPM_FEATURE); 238068ea8bdSYifan Zhang } 239068ea8bdSYifan Zhang 240068ea8bdSYifan Zhang static int smu_v13_0_5_mode_reset(struct smu_context *smu, int type) 241068ea8bdSYifan Zhang { 2420bb319e7SYifan Zhang int ret = 0; 243068ea8bdSYifan Zhang 2440bb319e7SYifan Zhang ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, type, NULL); 245068ea8bdSYifan Zhang if (ret) 246068ea8bdSYifan Zhang dev_err(smu->adev->dev, "Failed to mode reset!\n"); 247068ea8bdSYifan Zhang 248068ea8bdSYifan Zhang return ret; 249068ea8bdSYifan Zhang } 250068ea8bdSYifan Zhang 251068ea8bdSYifan Zhang static int smu_v13_0_5_mode2_reset(struct smu_context *smu) 252068ea8bdSYifan Zhang { 253068ea8bdSYifan Zhang return smu_v13_0_5_mode_reset(smu, SMU_RESET_MODE_2); 254068ea8bdSYifan Zhang } 255068ea8bdSYifan Zhang 256068ea8bdSYifan Zhang static int smu_v13_0_5_get_smu_metrics_data(struct smu_context *smu, 257068ea8bdSYifan Zhang MetricsMember_t member, 258068ea8bdSYifan Zhang uint32_t *value) 259068ea8bdSYifan Zhang { 260068ea8bdSYifan Zhang struct smu_table_context *smu_table = &smu->smu_table; 261068ea8bdSYifan Zhang 262068ea8bdSYifan Zhang SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; 263068ea8bdSYifan Zhang int ret = 0; 264068ea8bdSYifan Zhang 265068ea8bdSYifan Zhang ret = smu_cmn_get_metrics_table(smu, NULL, false); 266068ea8bdSYifan Zhang if (ret) 267068ea8bdSYifan Zhang return ret; 268068ea8bdSYifan Zhang 269068ea8bdSYifan Zhang switch (member) { 270068ea8bdSYifan Zhang case METRICS_AVERAGE_GFXCLK: 271068ea8bdSYifan Zhang *value = metrics->GfxclkFrequency; 272068ea8bdSYifan Zhang break; 273068ea8bdSYifan Zhang case METRICS_AVERAGE_SOCCLK: 274068ea8bdSYifan Zhang *value = metrics->SocclkFrequency; 275068ea8bdSYifan Zhang break; 276068ea8bdSYifan Zhang case METRICS_AVERAGE_VCLK: 277068ea8bdSYifan Zhang *value = metrics->VclkFrequency; 278068ea8bdSYifan Zhang break; 279068ea8bdSYifan Zhang case METRICS_AVERAGE_DCLK: 280068ea8bdSYifan Zhang *value = metrics->DclkFrequency; 281068ea8bdSYifan Zhang break; 282068ea8bdSYifan Zhang case METRICS_AVERAGE_UCLK: 283068ea8bdSYifan Zhang *value = metrics->MemclkFrequency; 284068ea8bdSYifan Zhang break; 285068ea8bdSYifan Zhang case METRICS_AVERAGE_GFXACTIVITY: 286068ea8bdSYifan Zhang *value = metrics->GfxActivity / 100; 287068ea8bdSYifan Zhang break; 288068ea8bdSYifan Zhang case METRICS_AVERAGE_VCNACTIVITY: 289068ea8bdSYifan Zhang *value = metrics->UvdActivity; 290068ea8bdSYifan Zhang break; 291068ea8bdSYifan Zhang case METRICS_AVERAGE_SOCKETPOWER: 292068ea8bdSYifan Zhang *value = (metrics->CurrentSocketPower << 8) / 1000; 293068ea8bdSYifan Zhang break; 294068ea8bdSYifan Zhang case METRICS_TEMPERATURE_EDGE: 295068ea8bdSYifan Zhang *value = metrics->GfxTemperature / 100 * 296068ea8bdSYifan Zhang SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; 297068ea8bdSYifan Zhang break; 298068ea8bdSYifan Zhang case METRICS_TEMPERATURE_HOTSPOT: 299068ea8bdSYifan Zhang *value = metrics->SocTemperature / 100 * 300068ea8bdSYifan Zhang SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; 301068ea8bdSYifan Zhang break; 302068ea8bdSYifan Zhang case METRICS_THROTTLER_STATUS: 303068ea8bdSYifan Zhang *value = metrics->ThrottlerStatus; 304068ea8bdSYifan Zhang break; 305068ea8bdSYifan Zhang case METRICS_VOLTAGE_VDDGFX: 306068ea8bdSYifan Zhang *value = metrics->Voltage[0]; 307068ea8bdSYifan Zhang break; 308068ea8bdSYifan Zhang case METRICS_VOLTAGE_VDDSOC: 309068ea8bdSYifan Zhang *value = metrics->Voltage[1]; 310068ea8bdSYifan Zhang break; 311068ea8bdSYifan Zhang default: 312068ea8bdSYifan Zhang *value = UINT_MAX; 313068ea8bdSYifan Zhang break; 314068ea8bdSYifan Zhang } 315068ea8bdSYifan Zhang 316068ea8bdSYifan Zhang return ret; 317068ea8bdSYifan Zhang } 318068ea8bdSYifan Zhang 319068ea8bdSYifan Zhang static int smu_v13_0_5_read_sensor(struct smu_context *smu, 320068ea8bdSYifan Zhang enum amd_pp_sensors sensor, 321068ea8bdSYifan Zhang void *data, uint32_t *size) 322068ea8bdSYifan Zhang { 323068ea8bdSYifan Zhang int ret = 0; 324068ea8bdSYifan Zhang 325068ea8bdSYifan Zhang if (!data || !size) 326068ea8bdSYifan Zhang return -EINVAL; 327068ea8bdSYifan Zhang 328068ea8bdSYifan Zhang switch (sensor) { 329068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_GPU_LOAD: 330068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 331068ea8bdSYifan Zhang METRICS_AVERAGE_GFXACTIVITY, 332068ea8bdSYifan Zhang (uint32_t *)data); 333068ea8bdSYifan Zhang *size = 4; 334068ea8bdSYifan Zhang break; 335068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_GPU_POWER: 336068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 337068ea8bdSYifan Zhang METRICS_AVERAGE_SOCKETPOWER, 338068ea8bdSYifan Zhang (uint32_t *)data); 339068ea8bdSYifan Zhang *size = 4; 340068ea8bdSYifan Zhang break; 341068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_EDGE_TEMP: 342068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 343068ea8bdSYifan Zhang METRICS_TEMPERATURE_EDGE, 344068ea8bdSYifan Zhang (uint32_t *)data); 345068ea8bdSYifan Zhang *size = 4; 346068ea8bdSYifan Zhang break; 347068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: 348068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 349068ea8bdSYifan Zhang METRICS_TEMPERATURE_HOTSPOT, 350068ea8bdSYifan Zhang (uint32_t *)data); 351068ea8bdSYifan Zhang *size = 4; 352068ea8bdSYifan Zhang break; 353068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_GFX_MCLK: 354068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 355068ea8bdSYifan Zhang METRICS_AVERAGE_UCLK, 356068ea8bdSYifan Zhang (uint32_t *)data); 357068ea8bdSYifan Zhang *(uint32_t *)data *= 100; 358068ea8bdSYifan Zhang *size = 4; 359068ea8bdSYifan Zhang break; 360068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_GFX_SCLK: 361068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 362068ea8bdSYifan Zhang METRICS_AVERAGE_GFXCLK, 363068ea8bdSYifan Zhang (uint32_t *)data); 364068ea8bdSYifan Zhang *(uint32_t *)data *= 100; 365068ea8bdSYifan Zhang *size = 4; 366068ea8bdSYifan Zhang break; 367068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_VDDGFX: 368068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 369068ea8bdSYifan Zhang METRICS_VOLTAGE_VDDGFX, 370068ea8bdSYifan Zhang (uint32_t *)data); 371068ea8bdSYifan Zhang *size = 4; 372068ea8bdSYifan Zhang break; 373068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_VDDNB: 374068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 375068ea8bdSYifan Zhang METRICS_VOLTAGE_VDDSOC, 376068ea8bdSYifan Zhang (uint32_t *)data); 377068ea8bdSYifan Zhang *size = 4; 378068ea8bdSYifan Zhang break; 379068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_SS_APU_SHARE: 380068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 381068ea8bdSYifan Zhang METRICS_SS_APU_SHARE, 382068ea8bdSYifan Zhang (uint32_t *)data); 383068ea8bdSYifan Zhang *size = 4; 384068ea8bdSYifan Zhang break; 385068ea8bdSYifan Zhang case AMDGPU_PP_SENSOR_SS_DGPU_SHARE: 386068ea8bdSYifan Zhang ret = smu_v13_0_5_get_smu_metrics_data(smu, 387068ea8bdSYifan Zhang METRICS_SS_DGPU_SHARE, 388068ea8bdSYifan Zhang (uint32_t *)data); 389068ea8bdSYifan Zhang *size = 4; 390068ea8bdSYifan Zhang break; 391068ea8bdSYifan Zhang default: 392068ea8bdSYifan Zhang ret = -EOPNOTSUPP; 393068ea8bdSYifan Zhang break; 394068ea8bdSYifan Zhang } 395068ea8bdSYifan Zhang 396068ea8bdSYifan Zhang return ret; 397068ea8bdSYifan Zhang } 398068ea8bdSYifan Zhang 399068ea8bdSYifan Zhang static int smu_v13_0_5_set_watermarks_table(struct smu_context *smu, 400068ea8bdSYifan Zhang struct pp_smu_wm_range_sets *clock_ranges) 401068ea8bdSYifan Zhang { 402068ea8bdSYifan Zhang int i; 403068ea8bdSYifan Zhang int ret = 0; 404068ea8bdSYifan Zhang Watermarks_t *table = smu->smu_table.watermarks_table; 405068ea8bdSYifan Zhang 406068ea8bdSYifan Zhang if (!table || !clock_ranges) 407068ea8bdSYifan Zhang return -EINVAL; 408068ea8bdSYifan Zhang 409068ea8bdSYifan Zhang if (clock_ranges) { 410068ea8bdSYifan Zhang if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES || 411068ea8bdSYifan Zhang clock_ranges->num_writer_wm_sets > NUM_WM_RANGES) 412068ea8bdSYifan Zhang return -EINVAL; 413068ea8bdSYifan Zhang 414068ea8bdSYifan Zhang for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) { 415068ea8bdSYifan Zhang table->WatermarkRow[WM_DCFCLK][i].MinClock = 416068ea8bdSYifan Zhang clock_ranges->reader_wm_sets[i].min_drain_clk_mhz; 417068ea8bdSYifan Zhang table->WatermarkRow[WM_DCFCLK][i].MaxClock = 418068ea8bdSYifan Zhang clock_ranges->reader_wm_sets[i].max_drain_clk_mhz; 419068ea8bdSYifan Zhang table->WatermarkRow[WM_DCFCLK][i].MinMclk = 420068ea8bdSYifan Zhang clock_ranges->reader_wm_sets[i].min_fill_clk_mhz; 421068ea8bdSYifan Zhang table->WatermarkRow[WM_DCFCLK][i].MaxMclk = 422068ea8bdSYifan Zhang clock_ranges->reader_wm_sets[i].max_fill_clk_mhz; 423068ea8bdSYifan Zhang 424068ea8bdSYifan Zhang table->WatermarkRow[WM_DCFCLK][i].WmSetting = 425068ea8bdSYifan Zhang clock_ranges->reader_wm_sets[i].wm_inst; 426068ea8bdSYifan Zhang } 427068ea8bdSYifan Zhang 428068ea8bdSYifan Zhang for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) { 429068ea8bdSYifan Zhang table->WatermarkRow[WM_SOCCLK][i].MinClock = 430068ea8bdSYifan Zhang clock_ranges->writer_wm_sets[i].min_fill_clk_mhz; 431068ea8bdSYifan Zhang table->WatermarkRow[WM_SOCCLK][i].MaxClock = 432068ea8bdSYifan Zhang clock_ranges->writer_wm_sets[i].max_fill_clk_mhz; 433068ea8bdSYifan Zhang table->WatermarkRow[WM_SOCCLK][i].MinMclk = 434068ea8bdSYifan Zhang clock_ranges->writer_wm_sets[i].min_drain_clk_mhz; 435068ea8bdSYifan Zhang table->WatermarkRow[WM_SOCCLK][i].MaxMclk = 436068ea8bdSYifan Zhang clock_ranges->writer_wm_sets[i].max_drain_clk_mhz; 437068ea8bdSYifan Zhang 438068ea8bdSYifan Zhang table->WatermarkRow[WM_SOCCLK][i].WmSetting = 439068ea8bdSYifan Zhang clock_ranges->writer_wm_sets[i].wm_inst; 440068ea8bdSYifan Zhang } 441068ea8bdSYifan Zhang 442068ea8bdSYifan Zhang smu->watermarks_bitmap |= WATERMARKS_EXIST; 443068ea8bdSYifan Zhang } 444068ea8bdSYifan Zhang 445068ea8bdSYifan Zhang /* pass data to smu controller */ 446068ea8bdSYifan Zhang if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && 447068ea8bdSYifan Zhang !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { 448068ea8bdSYifan Zhang ret = smu_cmn_write_watermarks_table(smu); 449068ea8bdSYifan Zhang if (ret) { 450068ea8bdSYifan Zhang dev_err(smu->adev->dev, "Failed to update WMTABLE!"); 451068ea8bdSYifan Zhang return ret; 452068ea8bdSYifan Zhang } 453068ea8bdSYifan Zhang smu->watermarks_bitmap |= WATERMARKS_LOADED; 454068ea8bdSYifan Zhang } 455068ea8bdSYifan Zhang 456068ea8bdSYifan Zhang return 0; 457068ea8bdSYifan Zhang } 458068ea8bdSYifan Zhang 459068ea8bdSYifan Zhang static ssize_t smu_v13_0_5_get_gpu_metrics(struct smu_context *smu, 460068ea8bdSYifan Zhang void **table) 461068ea8bdSYifan Zhang { 462068ea8bdSYifan Zhang struct smu_table_context *smu_table = &smu->smu_table; 463068ea8bdSYifan Zhang struct gpu_metrics_v2_1 *gpu_metrics = 464068ea8bdSYifan Zhang (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; 465068ea8bdSYifan Zhang SmuMetrics_t metrics; 466068ea8bdSYifan Zhang int ret = 0; 467068ea8bdSYifan Zhang 468068ea8bdSYifan Zhang ret = smu_cmn_get_metrics_table(smu, &metrics, true); 469068ea8bdSYifan Zhang if (ret) 470068ea8bdSYifan Zhang return ret; 471068ea8bdSYifan Zhang 472068ea8bdSYifan Zhang smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1); 473068ea8bdSYifan Zhang 474068ea8bdSYifan Zhang gpu_metrics->temperature_gfx = metrics.GfxTemperature; 475068ea8bdSYifan Zhang gpu_metrics->temperature_soc = metrics.SocTemperature; 476068ea8bdSYifan Zhang 477068ea8bdSYifan Zhang gpu_metrics->average_gfx_activity = metrics.GfxActivity; 478068ea8bdSYifan Zhang gpu_metrics->average_mm_activity = metrics.UvdActivity; 479068ea8bdSYifan Zhang 480068ea8bdSYifan Zhang gpu_metrics->average_socket_power = metrics.CurrentSocketPower; 481068ea8bdSYifan Zhang gpu_metrics->average_gfx_power = metrics.Power[0]; 482068ea8bdSYifan Zhang gpu_metrics->average_soc_power = metrics.Power[1]; 483068ea8bdSYifan Zhang gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency; 484068ea8bdSYifan Zhang gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency; 485068ea8bdSYifan Zhang gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency; 486068ea8bdSYifan Zhang gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency; 487068ea8bdSYifan Zhang gpu_metrics->average_vclk_frequency = metrics.VclkFrequency; 488068ea8bdSYifan Zhang gpu_metrics->average_dclk_frequency = metrics.DclkFrequency; 489068ea8bdSYifan Zhang gpu_metrics->throttle_status = metrics.ThrottlerStatus; 490068ea8bdSYifan Zhang gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); 491068ea8bdSYifan Zhang 492068ea8bdSYifan Zhang *table = (void *)gpu_metrics; 493068ea8bdSYifan Zhang 494068ea8bdSYifan Zhang return sizeof(struct gpu_metrics_v2_1); 495068ea8bdSYifan Zhang } 496068ea8bdSYifan Zhang 497068ea8bdSYifan Zhang static int smu_v13_0_5_set_default_dpm_tables(struct smu_context *smu) 498068ea8bdSYifan Zhang { 499068ea8bdSYifan Zhang struct smu_table_context *smu_table = &smu->smu_table; 500068ea8bdSYifan Zhang 501068ea8bdSYifan Zhang return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false); 502068ea8bdSYifan Zhang } 503068ea8bdSYifan Zhang 504068ea8bdSYifan Zhang static int smu_v13_0_5_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, 505068ea8bdSYifan Zhang long input[], uint32_t size) 506068ea8bdSYifan Zhang { 507068ea8bdSYifan Zhang struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); 508068ea8bdSYifan Zhang int ret = 0; 509068ea8bdSYifan Zhang 510068ea8bdSYifan Zhang /* Only allowed in manual mode */ 511068ea8bdSYifan Zhang if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) 512068ea8bdSYifan Zhang return -EINVAL; 513068ea8bdSYifan Zhang 514068ea8bdSYifan Zhang switch (type) { 515068ea8bdSYifan Zhang case PP_OD_EDIT_SCLK_VDDC_TABLE: 516068ea8bdSYifan Zhang if (size != 2) { 517068ea8bdSYifan Zhang dev_err(smu->adev->dev, "Input parameter number not correct\n"); 518068ea8bdSYifan Zhang return -EINVAL; 519068ea8bdSYifan Zhang } 520068ea8bdSYifan Zhang 521068ea8bdSYifan Zhang if (input[0] == 0) { 522068ea8bdSYifan Zhang if (input[1] < smu->gfx_default_hard_min_freq) { 523068ea8bdSYifan Zhang dev_warn(smu->adev->dev, 524068ea8bdSYifan Zhang "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n", 525068ea8bdSYifan Zhang input[1], smu->gfx_default_hard_min_freq); 526068ea8bdSYifan Zhang return -EINVAL; 527068ea8bdSYifan Zhang } 528068ea8bdSYifan Zhang smu->gfx_actual_hard_min_freq = input[1]; 529068ea8bdSYifan Zhang } else if (input[0] == 1) { 530068ea8bdSYifan Zhang if (input[1] > smu->gfx_default_soft_max_freq) { 531068ea8bdSYifan Zhang dev_warn(smu->adev->dev, 532068ea8bdSYifan Zhang "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n", 533068ea8bdSYifan Zhang input[1], smu->gfx_default_soft_max_freq); 534068ea8bdSYifan Zhang return -EINVAL; 535068ea8bdSYifan Zhang } 536068ea8bdSYifan Zhang smu->gfx_actual_soft_max_freq = input[1]; 537068ea8bdSYifan Zhang } else { 538068ea8bdSYifan Zhang return -EINVAL; 539068ea8bdSYifan Zhang } 540068ea8bdSYifan Zhang break; 541068ea8bdSYifan Zhang case PP_OD_RESTORE_DEFAULT_TABLE: 542068ea8bdSYifan Zhang if (size != 0) { 543068ea8bdSYifan Zhang dev_err(smu->adev->dev, "Input parameter number not correct\n"); 544068ea8bdSYifan Zhang return -EINVAL; 545068ea8bdSYifan Zhang } else { 546068ea8bdSYifan Zhang smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; 547068ea8bdSYifan Zhang smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; 548068ea8bdSYifan Zhang } 549068ea8bdSYifan Zhang break; 550068ea8bdSYifan Zhang case PP_OD_COMMIT_DPM_TABLE: 551068ea8bdSYifan Zhang if (size != 0) { 552068ea8bdSYifan Zhang dev_err(smu->adev->dev, "Input parameter number not correct\n"); 553068ea8bdSYifan Zhang return -EINVAL; 554068ea8bdSYifan Zhang } else { 555068ea8bdSYifan Zhang if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) { 556068ea8bdSYifan Zhang dev_err(smu->adev->dev, 557068ea8bdSYifan Zhang "The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n", 558068ea8bdSYifan Zhang smu->gfx_actual_hard_min_freq, 559068ea8bdSYifan Zhang smu->gfx_actual_soft_max_freq); 560068ea8bdSYifan Zhang return -EINVAL; 561068ea8bdSYifan Zhang } 562068ea8bdSYifan Zhang 563068ea8bdSYifan Zhang ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, 564068ea8bdSYifan Zhang smu->gfx_actual_hard_min_freq, NULL); 565068ea8bdSYifan Zhang if (ret) { 566068ea8bdSYifan Zhang dev_err(smu->adev->dev, "Set hard min sclk failed!"); 567068ea8bdSYifan Zhang return ret; 568068ea8bdSYifan Zhang } 569068ea8bdSYifan Zhang 570068ea8bdSYifan Zhang ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, 571068ea8bdSYifan Zhang smu->gfx_actual_soft_max_freq, NULL); 572068ea8bdSYifan Zhang if (ret) { 573068ea8bdSYifan Zhang dev_err(smu->adev->dev, "Set soft max sclk failed!"); 574068ea8bdSYifan Zhang return ret; 575068ea8bdSYifan Zhang } 576068ea8bdSYifan Zhang } 577068ea8bdSYifan Zhang break; 578068ea8bdSYifan Zhang default: 579068ea8bdSYifan Zhang return -ENOSYS; 580068ea8bdSYifan Zhang } 581068ea8bdSYifan Zhang 582068ea8bdSYifan Zhang return ret; 583068ea8bdSYifan Zhang } 584068ea8bdSYifan Zhang 585068ea8bdSYifan Zhang static int smu_v13_0_5_get_current_clk_freq(struct smu_context *smu, 586068ea8bdSYifan Zhang enum smu_clk_type clk_type, 587068ea8bdSYifan Zhang uint32_t *value) 588068ea8bdSYifan Zhang { 589068ea8bdSYifan Zhang MetricsMember_t member_type; 590068ea8bdSYifan Zhang 591068ea8bdSYifan Zhang switch (clk_type) { 592068ea8bdSYifan Zhang case SMU_SOCCLK: 593068ea8bdSYifan Zhang member_type = METRICS_AVERAGE_SOCCLK; 594068ea8bdSYifan Zhang break; 595068ea8bdSYifan Zhang case SMU_VCLK: 596068ea8bdSYifan Zhang member_type = METRICS_AVERAGE_VCLK; 597068ea8bdSYifan Zhang break; 598068ea8bdSYifan Zhang case SMU_DCLK: 599068ea8bdSYifan Zhang member_type = METRICS_AVERAGE_DCLK; 600068ea8bdSYifan Zhang break; 601068ea8bdSYifan Zhang case SMU_MCLK: 602068ea8bdSYifan Zhang member_type = METRICS_AVERAGE_UCLK; 603068ea8bdSYifan Zhang break; 604cefbe724SYifan Zhang case SMU_GFXCLK: 605cefbe724SYifan Zhang case SMU_SCLK: 606068ea8bdSYifan Zhang return smu_cmn_send_smc_msg_with_param(smu, 607cefbe724SYifan Zhang SMU_MSG_GetGfxclkFrequency, 0, value); 608cefbe724SYifan Zhang break; 609068ea8bdSYifan Zhang default: 610068ea8bdSYifan Zhang return -EINVAL; 611068ea8bdSYifan Zhang } 612068ea8bdSYifan Zhang 613068ea8bdSYifan Zhang return smu_v13_0_5_get_smu_metrics_data(smu, member_type, value); 614068ea8bdSYifan Zhang } 615068ea8bdSYifan Zhang 616068ea8bdSYifan Zhang static int smu_v13_0_5_get_dpm_level_count(struct smu_context *smu, 617068ea8bdSYifan Zhang enum smu_clk_type clk_type, 618068ea8bdSYifan Zhang uint32_t *count) 619068ea8bdSYifan Zhang { 620068ea8bdSYifan Zhang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 621068ea8bdSYifan Zhang 622068ea8bdSYifan Zhang switch (clk_type) { 623068ea8bdSYifan Zhang case SMU_SOCCLK: 624068ea8bdSYifan Zhang *count = clk_table->NumSocClkLevelsEnabled; 625068ea8bdSYifan Zhang break; 626068ea8bdSYifan Zhang case SMU_VCLK: 627068ea8bdSYifan Zhang *count = clk_table->VcnClkLevelsEnabled; 628068ea8bdSYifan Zhang break; 629068ea8bdSYifan Zhang case SMU_DCLK: 630068ea8bdSYifan Zhang *count = clk_table->VcnClkLevelsEnabled; 631068ea8bdSYifan Zhang break; 632068ea8bdSYifan Zhang case SMU_MCLK: 633068ea8bdSYifan Zhang *count = clk_table->NumDfPstatesEnabled; 634068ea8bdSYifan Zhang break; 635068ea8bdSYifan Zhang case SMU_FCLK: 636068ea8bdSYifan Zhang *count = clk_table->NumDfPstatesEnabled; 637068ea8bdSYifan Zhang break; 638068ea8bdSYifan Zhang default: 639068ea8bdSYifan Zhang break; 640068ea8bdSYifan Zhang } 641068ea8bdSYifan Zhang 642068ea8bdSYifan Zhang return 0; 643068ea8bdSYifan Zhang } 644068ea8bdSYifan Zhang 645068ea8bdSYifan Zhang static int smu_v13_0_5_get_dpm_freq_by_index(struct smu_context *smu, 646068ea8bdSYifan Zhang enum smu_clk_type clk_type, 647068ea8bdSYifan Zhang uint32_t dpm_level, 648068ea8bdSYifan Zhang uint32_t *freq) 649068ea8bdSYifan Zhang { 650068ea8bdSYifan Zhang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 651068ea8bdSYifan Zhang 652068ea8bdSYifan Zhang if (!clk_table || clk_type >= SMU_CLK_COUNT) 653068ea8bdSYifan Zhang return -EINVAL; 654068ea8bdSYifan Zhang 655068ea8bdSYifan Zhang switch (clk_type) { 656068ea8bdSYifan Zhang case SMU_SOCCLK: 657068ea8bdSYifan Zhang if (dpm_level >= clk_table->NumSocClkLevelsEnabled) 658068ea8bdSYifan Zhang return -EINVAL; 659068ea8bdSYifan Zhang *freq = clk_table->SocClocks[dpm_level]; 660068ea8bdSYifan Zhang break; 661068ea8bdSYifan Zhang case SMU_VCLK: 662068ea8bdSYifan Zhang if (dpm_level >= clk_table->VcnClkLevelsEnabled) 663068ea8bdSYifan Zhang return -EINVAL; 664068ea8bdSYifan Zhang *freq = clk_table->VClocks[dpm_level]; 665068ea8bdSYifan Zhang break; 666068ea8bdSYifan Zhang case SMU_DCLK: 667068ea8bdSYifan Zhang if (dpm_level >= clk_table->VcnClkLevelsEnabled) 668068ea8bdSYifan Zhang return -EINVAL; 669068ea8bdSYifan Zhang *freq = clk_table->DClocks[dpm_level]; 670068ea8bdSYifan Zhang break; 671068ea8bdSYifan Zhang case SMU_UCLK: 672068ea8bdSYifan Zhang case SMU_MCLK: 673068ea8bdSYifan Zhang if (dpm_level >= clk_table->NumDfPstatesEnabled) 674068ea8bdSYifan Zhang return -EINVAL; 675068ea8bdSYifan Zhang *freq = clk_table->DfPstateTable[dpm_level].MemClk; 676068ea8bdSYifan Zhang break; 677068ea8bdSYifan Zhang case SMU_FCLK: 678068ea8bdSYifan Zhang if (dpm_level >= clk_table->NumDfPstatesEnabled) 679068ea8bdSYifan Zhang return -EINVAL; 680068ea8bdSYifan Zhang *freq = clk_table->DfPstateTable[dpm_level].FClk; 681068ea8bdSYifan Zhang break; 682068ea8bdSYifan Zhang default: 683068ea8bdSYifan Zhang return -EINVAL; 684068ea8bdSYifan Zhang } 685068ea8bdSYifan Zhang 686068ea8bdSYifan Zhang return 0; 687068ea8bdSYifan Zhang } 688068ea8bdSYifan Zhang 689068ea8bdSYifan Zhang static bool smu_v13_0_5_clk_dpm_is_enabled(struct smu_context *smu, 690068ea8bdSYifan Zhang enum smu_clk_type clk_type) 691068ea8bdSYifan Zhang { 692068ea8bdSYifan Zhang enum smu_feature_mask feature_id = 0; 693068ea8bdSYifan Zhang 694068ea8bdSYifan Zhang switch (clk_type) { 695068ea8bdSYifan Zhang case SMU_MCLK: 696068ea8bdSYifan Zhang case SMU_UCLK: 697068ea8bdSYifan Zhang case SMU_FCLK: 698068ea8bdSYifan Zhang feature_id = SMU_FEATURE_DPM_FCLK_BIT; 699068ea8bdSYifan Zhang break; 700068ea8bdSYifan Zhang case SMU_GFXCLK: 701068ea8bdSYifan Zhang case SMU_SCLK: 702068ea8bdSYifan Zhang feature_id = SMU_FEATURE_DPM_GFXCLK_BIT; 703068ea8bdSYifan Zhang break; 704068ea8bdSYifan Zhang case SMU_SOCCLK: 705068ea8bdSYifan Zhang feature_id = SMU_FEATURE_DPM_SOCCLK_BIT; 706068ea8bdSYifan Zhang break; 707068ea8bdSYifan Zhang case SMU_VCLK: 708068ea8bdSYifan Zhang case SMU_DCLK: 709068ea8bdSYifan Zhang feature_id = SMU_FEATURE_VCN_DPM_BIT; 710068ea8bdSYifan Zhang break; 711068ea8bdSYifan Zhang default: 712068ea8bdSYifan Zhang return true; 713068ea8bdSYifan Zhang } 714068ea8bdSYifan Zhang 715068ea8bdSYifan Zhang return smu_cmn_feature_is_enabled(smu, feature_id); 716068ea8bdSYifan Zhang } 717068ea8bdSYifan Zhang 718068ea8bdSYifan Zhang static int smu_v13_0_5_get_dpm_ultimate_freq(struct smu_context *smu, 719068ea8bdSYifan Zhang enum smu_clk_type clk_type, 720068ea8bdSYifan Zhang uint32_t *min, 721068ea8bdSYifan Zhang uint32_t *max) 722068ea8bdSYifan Zhang { 723068ea8bdSYifan Zhang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 724068ea8bdSYifan Zhang uint32_t clock_limit; 725068ea8bdSYifan Zhang uint32_t max_dpm_level, min_dpm_level; 726068ea8bdSYifan Zhang int ret = 0; 727068ea8bdSYifan Zhang 728068ea8bdSYifan Zhang if (!smu_v13_0_5_clk_dpm_is_enabled(smu, clk_type)) { 729068ea8bdSYifan Zhang switch (clk_type) { 730068ea8bdSYifan Zhang case SMU_MCLK: 731068ea8bdSYifan Zhang case SMU_UCLK: 732068ea8bdSYifan Zhang clock_limit = smu->smu_table.boot_values.uclk; 733068ea8bdSYifan Zhang break; 734068ea8bdSYifan Zhang case SMU_FCLK: 735068ea8bdSYifan Zhang clock_limit = smu->smu_table.boot_values.fclk; 736068ea8bdSYifan Zhang break; 737068ea8bdSYifan Zhang case SMU_GFXCLK: 738068ea8bdSYifan Zhang case SMU_SCLK: 739068ea8bdSYifan Zhang clock_limit = smu->smu_table.boot_values.gfxclk; 740068ea8bdSYifan Zhang break; 741068ea8bdSYifan Zhang case SMU_SOCCLK: 742068ea8bdSYifan Zhang clock_limit = smu->smu_table.boot_values.socclk; 743068ea8bdSYifan Zhang break; 744068ea8bdSYifan Zhang case SMU_VCLK: 745068ea8bdSYifan Zhang clock_limit = smu->smu_table.boot_values.vclk; 746068ea8bdSYifan Zhang break; 747068ea8bdSYifan Zhang case SMU_DCLK: 748068ea8bdSYifan Zhang clock_limit = smu->smu_table.boot_values.dclk; 749068ea8bdSYifan Zhang break; 750068ea8bdSYifan Zhang default: 751068ea8bdSYifan Zhang clock_limit = 0; 752068ea8bdSYifan Zhang break; 753068ea8bdSYifan Zhang } 754068ea8bdSYifan Zhang 755068ea8bdSYifan Zhang /* clock in Mhz unit */ 756068ea8bdSYifan Zhang if (min) 757068ea8bdSYifan Zhang *min = clock_limit / 100; 758068ea8bdSYifan Zhang if (max) 759068ea8bdSYifan Zhang *max = clock_limit / 100; 760068ea8bdSYifan Zhang 761068ea8bdSYifan Zhang return 0; 762068ea8bdSYifan Zhang } 763068ea8bdSYifan Zhang 764068ea8bdSYifan Zhang if (max) { 765068ea8bdSYifan Zhang switch (clk_type) { 766068ea8bdSYifan Zhang case SMU_GFXCLK: 767068ea8bdSYifan Zhang case SMU_SCLK: 768068ea8bdSYifan Zhang *max = clk_table->MaxGfxClk; 769068ea8bdSYifan Zhang break; 770068ea8bdSYifan Zhang case SMU_MCLK: 771068ea8bdSYifan Zhang case SMU_UCLK: 772068ea8bdSYifan Zhang case SMU_FCLK: 773068ea8bdSYifan Zhang max_dpm_level = 0; 774068ea8bdSYifan Zhang break; 775068ea8bdSYifan Zhang case SMU_SOCCLK: 776068ea8bdSYifan Zhang max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1; 777068ea8bdSYifan Zhang break; 778068ea8bdSYifan Zhang case SMU_VCLK: 779068ea8bdSYifan Zhang case SMU_DCLK: 780068ea8bdSYifan Zhang max_dpm_level = clk_table->VcnClkLevelsEnabled - 1; 781068ea8bdSYifan Zhang break; 782068ea8bdSYifan Zhang default: 783068ea8bdSYifan Zhang ret = -EINVAL; 784068ea8bdSYifan Zhang goto failed; 785068ea8bdSYifan Zhang } 786068ea8bdSYifan Zhang 787068ea8bdSYifan Zhang if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { 788068ea8bdSYifan Zhang ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max); 789068ea8bdSYifan Zhang if (ret) 790068ea8bdSYifan Zhang goto failed; 791068ea8bdSYifan Zhang } 792068ea8bdSYifan Zhang } 793068ea8bdSYifan Zhang 794068ea8bdSYifan Zhang if (min) { 795068ea8bdSYifan Zhang switch (clk_type) { 796068ea8bdSYifan Zhang case SMU_GFXCLK: 797068ea8bdSYifan Zhang case SMU_SCLK: 798068ea8bdSYifan Zhang *min = clk_table->MinGfxClk; 799068ea8bdSYifan Zhang break; 800068ea8bdSYifan Zhang case SMU_MCLK: 801068ea8bdSYifan Zhang case SMU_UCLK: 802068ea8bdSYifan Zhang case SMU_FCLK: 803068ea8bdSYifan Zhang min_dpm_level = clk_table->NumDfPstatesEnabled - 1; 804068ea8bdSYifan Zhang break; 805068ea8bdSYifan Zhang case SMU_SOCCLK: 806068ea8bdSYifan Zhang min_dpm_level = 0; 807068ea8bdSYifan Zhang break; 808068ea8bdSYifan Zhang case SMU_VCLK: 809068ea8bdSYifan Zhang case SMU_DCLK: 810068ea8bdSYifan Zhang min_dpm_level = 0; 811068ea8bdSYifan Zhang break; 812068ea8bdSYifan Zhang default: 813068ea8bdSYifan Zhang ret = -EINVAL; 814068ea8bdSYifan Zhang goto failed; 815068ea8bdSYifan Zhang } 816068ea8bdSYifan Zhang 817068ea8bdSYifan Zhang if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { 818068ea8bdSYifan Zhang ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min); 819068ea8bdSYifan Zhang if (ret) 820068ea8bdSYifan Zhang goto failed; 821068ea8bdSYifan Zhang } 822068ea8bdSYifan Zhang } 823068ea8bdSYifan Zhang 824068ea8bdSYifan Zhang failed: 825068ea8bdSYifan Zhang return ret; 826068ea8bdSYifan Zhang } 827068ea8bdSYifan Zhang 828068ea8bdSYifan Zhang static int smu_v13_0_5_set_soft_freq_limited_range(struct smu_context *smu, 829068ea8bdSYifan Zhang enum smu_clk_type clk_type, 830068ea8bdSYifan Zhang uint32_t min, 831068ea8bdSYifan Zhang uint32_t max) 832068ea8bdSYifan Zhang { 833068ea8bdSYifan Zhang enum smu_message_type msg_set_min, msg_set_max; 834e22821e6STim Huang uint32_t min_clk = min; 835e22821e6STim Huang uint32_t max_clk = max; 836068ea8bdSYifan Zhang int ret = 0; 837068ea8bdSYifan Zhang 838068ea8bdSYifan Zhang if (!smu_v13_0_5_clk_dpm_is_enabled(smu, clk_type)) 839068ea8bdSYifan Zhang return -EINVAL; 840068ea8bdSYifan Zhang 841068ea8bdSYifan Zhang switch (clk_type) { 842068ea8bdSYifan Zhang case SMU_GFXCLK: 843068ea8bdSYifan Zhang case SMU_SCLK: 844068ea8bdSYifan Zhang msg_set_min = SMU_MSG_SetHardMinGfxClk; 845068ea8bdSYifan Zhang msg_set_max = SMU_MSG_SetSoftMaxGfxClk; 846068ea8bdSYifan Zhang break; 847068ea8bdSYifan Zhang case SMU_VCLK: 848068ea8bdSYifan Zhang case SMU_DCLK: 849068ea8bdSYifan Zhang msg_set_min = SMU_MSG_SetHardMinVcn; 850068ea8bdSYifan Zhang msg_set_max = SMU_MSG_SetSoftMaxVcn; 851068ea8bdSYifan Zhang break; 852068ea8bdSYifan Zhang default: 853068ea8bdSYifan Zhang return -EINVAL; 854068ea8bdSYifan Zhang } 855068ea8bdSYifan Zhang 856e22821e6STim Huang if (clk_type == SMU_VCLK) { 857e22821e6STim Huang min_clk = min << SMU_13_VCLK_SHIFT; 858e22821e6STim Huang max_clk = max << SMU_13_VCLK_SHIFT; 859e22821e6STim Huang } 860e22821e6STim Huang 861e22821e6STim Huang ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min_clk, NULL); 862068ea8bdSYifan Zhang if (ret) 863068ea8bdSYifan Zhang goto out; 864068ea8bdSYifan Zhang 865e22821e6STim Huang ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max_clk, NULL); 866068ea8bdSYifan Zhang if (ret) 867068ea8bdSYifan Zhang goto out; 868068ea8bdSYifan Zhang 869068ea8bdSYifan Zhang out: 870068ea8bdSYifan Zhang return ret; 871068ea8bdSYifan Zhang } 872068ea8bdSYifan Zhang 873068ea8bdSYifan Zhang static int smu_v13_0_5_print_clk_levels(struct smu_context *smu, 874068ea8bdSYifan Zhang enum smu_clk_type clk_type, char *buf) 875068ea8bdSYifan Zhang { 876d9ed111bSTim Huang int i, idx, size = 0, ret = 0; 877068ea8bdSYifan Zhang uint32_t cur_value = 0, value = 0, count = 0; 878cefbe724SYifan Zhang uint32_t min = 0, max = 0; 879068ea8bdSYifan Zhang 880068ea8bdSYifan Zhang smu_cmn_get_sysfs_buf(&buf, &size); 881068ea8bdSYifan Zhang 882068ea8bdSYifan Zhang switch (clk_type) { 883068ea8bdSYifan Zhang case SMU_OD_SCLK: 884068ea8bdSYifan Zhang size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); 885068ea8bdSYifan Zhang size += sysfs_emit_at(buf, size, "0: %10uMhz\n", 886068ea8bdSYifan Zhang (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq); 887068ea8bdSYifan Zhang size += sysfs_emit_at(buf, size, "1: %10uMhz\n", 888068ea8bdSYifan Zhang (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq); 889068ea8bdSYifan Zhang break; 890068ea8bdSYifan Zhang case SMU_OD_RANGE: 891068ea8bdSYifan Zhang size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); 892068ea8bdSYifan Zhang size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", 893068ea8bdSYifan Zhang smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq); 894068ea8bdSYifan Zhang break; 895068ea8bdSYifan Zhang case SMU_SOCCLK: 896068ea8bdSYifan Zhang case SMU_VCLK: 897068ea8bdSYifan Zhang case SMU_DCLK: 898068ea8bdSYifan Zhang case SMU_MCLK: 899068ea8bdSYifan Zhang ret = smu_v13_0_5_get_current_clk_freq(smu, clk_type, &cur_value); 900068ea8bdSYifan Zhang if (ret) 901068ea8bdSYifan Zhang goto print_clk_out; 902068ea8bdSYifan Zhang 903068ea8bdSYifan Zhang ret = smu_v13_0_5_get_dpm_level_count(smu, clk_type, &count); 904068ea8bdSYifan Zhang if (ret) 905068ea8bdSYifan Zhang goto print_clk_out; 906068ea8bdSYifan Zhang 907068ea8bdSYifan Zhang for (i = 0; i < count; i++) { 908d9ed111bSTim Huang idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i; 909d9ed111bSTim Huang ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, idx, &value); 910068ea8bdSYifan Zhang if (ret) 911068ea8bdSYifan Zhang goto print_clk_out; 912068ea8bdSYifan Zhang 913068ea8bdSYifan Zhang size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, 914068ea8bdSYifan Zhang cur_value == value ? "*" : ""); 915068ea8bdSYifan Zhang } 916068ea8bdSYifan Zhang break; 917cefbe724SYifan Zhang case SMU_GFXCLK: 918cefbe724SYifan Zhang case SMU_SCLK: 919cefbe724SYifan Zhang ret = smu_v13_0_5_get_current_clk_freq(smu, clk_type, &cur_value); 920cefbe724SYifan Zhang if (ret) 921cefbe724SYifan Zhang goto print_clk_out; 922cefbe724SYifan Zhang min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; 923cefbe724SYifan Zhang max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; 924cefbe724SYifan Zhang if (cur_value == max) 925cefbe724SYifan Zhang i = 2; 926cefbe724SYifan Zhang else if (cur_value == min) 927cefbe724SYifan Zhang i = 0; 928cefbe724SYifan Zhang else 929cefbe724SYifan Zhang i = 1; 930cefbe724SYifan Zhang size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, 931cefbe724SYifan Zhang i == 0 ? "*" : ""); 932cefbe724SYifan Zhang size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", 933cefbe724SYifan Zhang i == 1 ? cur_value : SMU_13_0_5_UMD_PSTATE_GFXCLK, 934cefbe724SYifan Zhang i == 1 ? "*" : ""); 935cefbe724SYifan Zhang size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, 936cefbe724SYifan Zhang i == 2 ? "*" : ""); 937cefbe724SYifan Zhang break; 938068ea8bdSYifan Zhang default: 939068ea8bdSYifan Zhang break; 940068ea8bdSYifan Zhang } 941068ea8bdSYifan Zhang 942068ea8bdSYifan Zhang print_clk_out: 943068ea8bdSYifan Zhang return size; 944068ea8bdSYifan Zhang } 945068ea8bdSYifan Zhang 946cefbe724SYifan Zhang 947068ea8bdSYifan Zhang static int smu_v13_0_5_force_clk_levels(struct smu_context *smu, 948068ea8bdSYifan Zhang enum smu_clk_type clk_type, uint32_t mask) 949068ea8bdSYifan Zhang { 950068ea8bdSYifan Zhang uint32_t soft_min_level = 0, soft_max_level = 0; 951068ea8bdSYifan Zhang uint32_t min_freq = 0, max_freq = 0; 952068ea8bdSYifan Zhang int ret = 0; 953068ea8bdSYifan Zhang 954068ea8bdSYifan Zhang soft_min_level = mask ? (ffs(mask) - 1) : 0; 955068ea8bdSYifan Zhang soft_max_level = mask ? (fls(mask) - 1) : 0; 956068ea8bdSYifan Zhang 957068ea8bdSYifan Zhang switch (clk_type) { 958068ea8bdSYifan Zhang case SMU_VCLK: 959068ea8bdSYifan Zhang case SMU_DCLK: 960068ea8bdSYifan Zhang ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); 961068ea8bdSYifan Zhang if (ret) 962068ea8bdSYifan Zhang goto force_level_out; 963068ea8bdSYifan Zhang 964068ea8bdSYifan Zhang ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); 965068ea8bdSYifan Zhang if (ret) 966068ea8bdSYifan Zhang goto force_level_out; 967068ea8bdSYifan Zhang 968068ea8bdSYifan Zhang ret = smu_v13_0_5_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); 969068ea8bdSYifan Zhang if (ret) 970068ea8bdSYifan Zhang goto force_level_out; 971068ea8bdSYifan Zhang break; 972068ea8bdSYifan Zhang default: 973068ea8bdSYifan Zhang ret = -EINVAL; 974068ea8bdSYifan Zhang break; 975068ea8bdSYifan Zhang } 976068ea8bdSYifan Zhang 977068ea8bdSYifan Zhang force_level_out: 978068ea8bdSYifan Zhang return ret; 979068ea8bdSYifan Zhang } 980068ea8bdSYifan Zhang 981*121f17acSTim Huang static int smu_v13_0_5_get_dpm_profile_freq(struct smu_context *smu, 982*121f17acSTim Huang enum amd_dpm_forced_level level, 983*121f17acSTim Huang enum smu_clk_type clk_type, 984*121f17acSTim Huang uint32_t *min_clk, 985*121f17acSTim Huang uint32_t *max_clk) 986*121f17acSTim Huang { 987*121f17acSTim Huang int ret = 0; 988*121f17acSTim Huang uint32_t clk_limit = 0; 989*121f17acSTim Huang 990*121f17acSTim Huang switch (clk_type) { 991*121f17acSTim Huang case SMU_GFXCLK: 992*121f17acSTim Huang case SMU_SCLK: 993*121f17acSTim Huang clk_limit = SMU_13_0_5_UMD_PSTATE_GFXCLK; 994*121f17acSTim Huang if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) 995*121f17acSTim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit); 996*121f17acSTim Huang else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) 997*121f17acSTim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL); 998*121f17acSTim Huang break; 999*121f17acSTim Huang case SMU_VCLK: 1000*121f17acSTim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit); 1001*121f17acSTim Huang break; 1002*121f17acSTim Huang case SMU_DCLK: 1003*121f17acSTim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit); 1004*121f17acSTim Huang break; 1005*121f17acSTim Huang default: 1006*121f17acSTim Huang ret = -EINVAL; 1007*121f17acSTim Huang break; 1008*121f17acSTim Huang } 1009*121f17acSTim Huang *min_clk = *max_clk = clk_limit; 1010*121f17acSTim Huang return ret; 1011*121f17acSTim Huang } 1012*121f17acSTim Huang 1013068ea8bdSYifan Zhang static int smu_v13_0_5_set_performance_level(struct smu_context *smu, 1014068ea8bdSYifan Zhang enum amd_dpm_forced_level level) 1015068ea8bdSYifan Zhang { 1016068ea8bdSYifan Zhang struct amdgpu_device *adev = smu->adev; 1017068ea8bdSYifan Zhang uint32_t sclk_min = 0, sclk_max = 0; 1018fcdb3832STim Huang uint32_t vclk_min = 0, vclk_max = 0; 1019fcdb3832STim Huang uint32_t dclk_min = 0, dclk_max = 0; 1020068ea8bdSYifan Zhang int ret = 0; 1021068ea8bdSYifan Zhang 1022068ea8bdSYifan Zhang switch (level) { 1023068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_HIGH: 1024068ea8bdSYifan Zhang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max); 1025fcdb3832STim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max); 1026fcdb3832STim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max); 1027068ea8bdSYifan Zhang sclk_min = sclk_max; 1028fcdb3832STim Huang vclk_min = vclk_max; 1029fcdb3832STim Huang dclk_min = dclk_max; 1030068ea8bdSYifan Zhang break; 1031068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_LOW: 1032068ea8bdSYifan Zhang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL); 1033fcdb3832STim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL); 1034fcdb3832STim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL); 1035068ea8bdSYifan Zhang sclk_max = sclk_min; 1036fcdb3832STim Huang vclk_max = vclk_min; 1037fcdb3832STim Huang dclk_max = dclk_min; 1038068ea8bdSYifan Zhang break; 1039068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_AUTO: 1040068ea8bdSYifan Zhang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max); 1041fcdb3832STim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max); 1042fcdb3832STim Huang smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max); 1043068ea8bdSYifan Zhang break; 1044068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: 1045068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: 1046068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: 1047*121f17acSTim Huang smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max); 1048*121f17acSTim Huang smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max); 1049*121f17acSTim Huang smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max); 1050068ea8bdSYifan Zhang break; 1051*121f17acSTim Huang case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: 1052*121f17acSTim Huang dev_err(adev->dev, "The performance level profile_min_mclk is not supported."); 1053*121f17acSTim Huang return -EOPNOTSUPP; 1054068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_MANUAL: 1055068ea8bdSYifan Zhang case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: 1056068ea8bdSYifan Zhang return 0; 1057068ea8bdSYifan Zhang default: 1058068ea8bdSYifan Zhang dev_err(adev->dev, "Invalid performance level %d\n", level); 1059068ea8bdSYifan Zhang return -EINVAL; 1060068ea8bdSYifan Zhang } 1061068ea8bdSYifan Zhang 106260d61f4eSYifan Zhang if (sclk_min && sclk_max && smu_v13_0_5_clk_dpm_is_enabled(smu, SMU_SCLK)) { 1063068ea8bdSYifan Zhang ret = smu_v13_0_5_set_soft_freq_limited_range(smu, 1064068ea8bdSYifan Zhang SMU_SCLK, 1065068ea8bdSYifan Zhang sclk_min, 1066068ea8bdSYifan Zhang sclk_max); 1067068ea8bdSYifan Zhang if (ret) 1068068ea8bdSYifan Zhang return ret; 1069068ea8bdSYifan Zhang 1070068ea8bdSYifan Zhang smu->gfx_actual_hard_min_freq = sclk_min; 1071068ea8bdSYifan Zhang smu->gfx_actual_soft_max_freq = sclk_max; 1072068ea8bdSYifan Zhang } 1073068ea8bdSYifan Zhang 1074fcdb3832STim Huang if (vclk_min && vclk_max) { 1075fcdb3832STim Huang ret = smu_v13_0_5_set_soft_freq_limited_range(smu, 1076fcdb3832STim Huang SMU_VCLK, 1077fcdb3832STim Huang vclk_min, 1078fcdb3832STim Huang vclk_max); 1079fcdb3832STim Huang if (ret) 1080fcdb3832STim Huang return ret; 1081fcdb3832STim Huang } 1082fcdb3832STim Huang 1083fcdb3832STim Huang if (dclk_min && dclk_max) { 1084fcdb3832STim Huang ret = smu_v13_0_5_set_soft_freq_limited_range(smu, 1085fcdb3832STim Huang SMU_DCLK, 1086fcdb3832STim Huang dclk_min, 1087fcdb3832STim Huang dclk_max); 1088fcdb3832STim Huang if (ret) 1089fcdb3832STim Huang return ret; 1090fcdb3832STim Huang } 1091068ea8bdSYifan Zhang return ret; 1092068ea8bdSYifan Zhang } 1093068ea8bdSYifan Zhang 1094068ea8bdSYifan Zhang static int smu_v13_0_5_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) 1095068ea8bdSYifan Zhang { 1096068ea8bdSYifan Zhang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 1097068ea8bdSYifan Zhang 1098068ea8bdSYifan Zhang smu->gfx_default_hard_min_freq = clk_table->MinGfxClk; 1099068ea8bdSYifan Zhang smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk; 1100068ea8bdSYifan Zhang smu->gfx_actual_hard_min_freq = 0; 1101068ea8bdSYifan Zhang smu->gfx_actual_soft_max_freq = 0; 1102068ea8bdSYifan Zhang 1103068ea8bdSYifan Zhang return 0; 1104068ea8bdSYifan Zhang } 1105068ea8bdSYifan Zhang 1106068ea8bdSYifan Zhang static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { 1107068ea8bdSYifan Zhang .check_fw_status = smu_v13_0_check_fw_status, 1108068ea8bdSYifan Zhang .check_fw_version = smu_v13_0_check_fw_version, 1109068ea8bdSYifan Zhang .init_smc_tables = smu_v13_0_5_init_smc_tables, 1110068ea8bdSYifan Zhang .fini_smc_tables = smu_v13_0_5_fini_smc_tables, 1111068ea8bdSYifan Zhang .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, 1112068ea8bdSYifan Zhang .system_features_control = smu_v13_0_5_system_features_control, 1113068ea8bdSYifan Zhang .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, 1114068ea8bdSYifan Zhang .send_smc_msg = smu_cmn_send_smc_msg, 1115068ea8bdSYifan Zhang .dpm_set_vcn_enable = smu_v13_0_5_dpm_set_vcn_enable, 1116068ea8bdSYifan Zhang .dpm_set_jpeg_enable = smu_v13_0_5_dpm_set_jpeg_enable, 1117068ea8bdSYifan Zhang .set_default_dpm_table = smu_v13_0_5_set_default_dpm_tables, 1118068ea8bdSYifan Zhang .read_sensor = smu_v13_0_5_read_sensor, 1119068ea8bdSYifan Zhang .is_dpm_running = smu_v13_0_5_is_dpm_running, 1120068ea8bdSYifan Zhang .set_watermarks_table = smu_v13_0_5_set_watermarks_table, 1121068ea8bdSYifan Zhang .get_gpu_metrics = smu_v13_0_5_get_gpu_metrics, 1122068ea8bdSYifan Zhang .get_enabled_mask = smu_cmn_get_enabled_mask, 1123068ea8bdSYifan Zhang .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, 1124068ea8bdSYifan Zhang .set_driver_table_location = smu_v13_0_set_driver_table_location, 1125068ea8bdSYifan Zhang .gfx_off_control = smu_v13_0_gfx_off_control, 1126068ea8bdSYifan Zhang .mode2_reset = smu_v13_0_5_mode2_reset, 1127068ea8bdSYifan Zhang .get_dpm_ultimate_freq = smu_v13_0_5_get_dpm_ultimate_freq, 1128068ea8bdSYifan Zhang .od_edit_dpm_table = smu_v13_0_5_od_edit_dpm_table, 1129068ea8bdSYifan Zhang .print_clk_levels = smu_v13_0_5_print_clk_levels, 1130068ea8bdSYifan Zhang .force_clk_levels = smu_v13_0_5_force_clk_levels, 1131068ea8bdSYifan Zhang .set_performance_level = smu_v13_0_5_set_performance_level, 1132068ea8bdSYifan Zhang .set_fine_grain_gfx_freq_parameters = smu_v13_0_5_set_fine_grain_gfx_freq_parameters, 1133068ea8bdSYifan Zhang }; 1134068ea8bdSYifan Zhang 1135068ea8bdSYifan Zhang void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) 1136068ea8bdSYifan Zhang { 1137da1db031SAlex Deucher struct amdgpu_device *adev = smu->adev; 1138da1db031SAlex Deucher 1139068ea8bdSYifan Zhang smu->ppt_funcs = &smu_v13_0_5_ppt_funcs; 1140068ea8bdSYifan Zhang smu->message_map = smu_v13_0_5_message_map; 1141068ea8bdSYifan Zhang smu->feature_map = smu_v13_0_5_feature_mask_map; 1142068ea8bdSYifan Zhang smu->table_map = smu_v13_0_5_table_map; 1143068ea8bdSYifan Zhang smu->is_apu = true; 11449661bf68SLijo Lazar smu->smc_driver_if_version = SMU13_0_5_DRIVER_IF_VERSION; 1145da1db031SAlex Deucher smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); 1146da1db031SAlex Deucher smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); 1147da1db031SAlex Deucher smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); 1148068ea8bdSYifan Zhang } 1149