Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2020 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  */
0023 
0024 #define SWSMU_CODE_LAYER_L2
0025 
0026 #include "amdgpu.h"
0027 #include "amdgpu_smu.h"
0028 #include "smu_v13_0.h"
0029 #include "smu13_driver_if_yellow_carp.h"
0030 #include "yellow_carp_ppt.h"
0031 #include "smu_v13_0_1_ppsmc.h"
0032 #include "smu_v13_0_1_pmfw.h"
0033 #include "smu_cmn.h"
0034 
0035 /*
0036  * DO NOT use these for err/warn/info/debug messages.
0037  * Use dev_err, dev_warn, dev_info and dev_dbg instead.
0038  * They are more MGPU friendly.
0039  */
0040 #undef pr_err
0041 #undef pr_warn
0042 #undef pr_info
0043 #undef pr_debug
0044 
0045 #define regSMUIO_GFX_MISC_CNTL                          0x00c5
0046 #define regSMUIO_GFX_MISC_CNTL_BASE_IDX                 0
0047 #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK     0x00000006L
0048 #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT          0x1L
0049 
0050 #define FEATURE_MASK(feature) (1ULL << feature)
0051 #define SMC_DPM_FEATURE ( \
0052     FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
0053     FEATURE_MASK(FEATURE_VCN_DPM_BIT)    | \
0054     FEATURE_MASK(FEATURE_FCLK_DPM_BIT)   | \
0055     FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)     | \
0056     FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)     | \
0057     FEATURE_MASK(FEATURE_LCLK_DPM_BIT)   | \
0058     FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)    | \
0059     FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
0060     FEATURE_MASK(FEATURE_GFX_DPM_BIT))
0061 
0062 static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = {
0063     MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,          1),
0064     MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,        1),
0065     MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,       1),
0066     MSG_MAP(EnableGfxOff,                   PPSMC_MSG_EnableGfxOff,         1),
0067     MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff,          1),
0068     MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,       1),
0069     MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,         1),
0070     MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn,           1),
0071     MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn,        1),
0072     MSG_MAP(PrepareMp1ForUnload,            PPSMC_MSG_PrepareMp1ForUnload,      1),
0073     MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh,    1),
0074     MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow,     1),
0075     MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,    1),
0076     MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,    1),
0077     MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset,     1),
0078     MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,    1),
0079     MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq,   1),
0080     MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn,        1),
0081     MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency,       1),
0082     MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency,     1),
0083     MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk,     1),
0084     MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk,     1),
0085     MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq,   1),
0086     MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq,     1),
0087     MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn,        1),
0088     MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage,  1),
0089     MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg,        1),
0090     MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg,          1),
0091     MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq,     1),
0092     MSG_MAP(SetSoftMinSocclkByFreq,         PPSMC_MSG_SetSoftMinSocclkByFreq,   1),
0093 };
0094 
0095 static struct cmn2asic_mapping yellow_carp_feature_mask_map[SMU_FEATURE_COUNT] = {
0096     FEA_MAP(CCLK_DPM),
0097     FEA_MAP(FAN_CONTROLLER),
0098     FEA_MAP(PPT),
0099     FEA_MAP(TDC),
0100     FEA_MAP(THERMAL),
0101     FEA_MAP(ULV),
0102     FEA_MAP(VCN_DPM),
0103     FEA_MAP_REVERSE(FCLK),
0104     FEA_MAP_REVERSE(SOCCLK),
0105     FEA_MAP(LCLK_DPM),
0106     FEA_MAP(SHUBCLK_DPM),
0107     FEA_MAP(DCFCLK_DPM),
0108     FEA_MAP_HALF_REVERSE(GFX),
0109     FEA_MAP(DS_GFXCLK),
0110     FEA_MAP(DS_SOCCLK),
0111     FEA_MAP(DS_LCLK),
0112     FEA_MAP(DS_DCFCLK),
0113     FEA_MAP(DS_FCLK),
0114     FEA_MAP(DS_MP1CLK),
0115     FEA_MAP(DS_MP0CLK),
0116     FEA_MAP(GFX_DEM),
0117     FEA_MAP(PSI),
0118     FEA_MAP(PROCHOT),
0119     FEA_MAP(CPUOFF),
0120     FEA_MAP(STAPM),
0121     FEA_MAP(S0I3),
0122     FEA_MAP(PERF_LIMIT),
0123     FEA_MAP(CORE_DLDO),
0124     FEA_MAP(RSMU_LOW_POWER),
0125     FEA_MAP(SMN_LOW_POWER),
0126     FEA_MAP(THM_LOW_POWER),
0127     FEA_MAP(SMUIO_LOW_POWER),
0128     FEA_MAP(MP1_LOW_POWER),
0129     FEA_MAP(DS_VCN),
0130     FEA_MAP(CPPC),
0131     FEA_MAP(DF_CSTATES),
0132     FEA_MAP(MSMU_LOW_POWER),
0133     FEA_MAP(ATHUB_PG),
0134 };
0135 
0136 static struct cmn2asic_mapping yellow_carp_table_map[SMU_TABLE_COUNT] = {
0137     TAB_MAP_VALID(WATERMARKS),
0138     TAB_MAP_VALID(SMU_METRICS),
0139     TAB_MAP_VALID(CUSTOM_DPM),
0140     TAB_MAP_VALID(DPMCLOCKS),
0141 };
0142     
0143 static int yellow_carp_init_smc_tables(struct smu_context *smu)
0144 {
0145     struct smu_table_context *smu_table = &smu->smu_table;
0146     struct smu_table *tables = smu_table->tables;
0147 
0148     SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
0149         PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
0150     SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
0151         PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
0152     SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
0153         PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
0154 
0155     smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
0156     if (!smu_table->clocks_table)
0157         goto err0_out;
0158 
0159     smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
0160     if (!smu_table->metrics_table)
0161         goto err1_out;
0162     smu_table->metrics_time = 0;
0163 
0164     smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
0165     if (!smu_table->watermarks_table)
0166         goto err2_out;
0167 
0168     smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1);
0169     smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
0170     if (!smu_table->gpu_metrics_table)
0171         goto err3_out;
0172 
0173     return 0;
0174 
0175 err3_out:
0176     kfree(smu_table->watermarks_table);
0177 err2_out:
0178     kfree(smu_table->metrics_table);
0179 err1_out:
0180     kfree(smu_table->clocks_table);
0181 err0_out:
0182     return -ENOMEM;
0183 }
0184 
0185 static int yellow_carp_fini_smc_tables(struct smu_context *smu)
0186 {
0187     struct smu_table_context *smu_table = &smu->smu_table;
0188 
0189     kfree(smu_table->clocks_table);
0190     smu_table->clocks_table = NULL;
0191 
0192     kfree(smu_table->metrics_table);
0193     smu_table->metrics_table = NULL;
0194 
0195     kfree(smu_table->watermarks_table);
0196     smu_table->watermarks_table = NULL;
0197 
0198     kfree(smu_table->gpu_metrics_table);
0199     smu_table->gpu_metrics_table = NULL;
0200 
0201     return 0;
0202 }
0203 
0204 static int yellow_carp_system_features_control(struct smu_context *smu, bool en)
0205 {
0206     struct amdgpu_device *adev = smu->adev;
0207     int ret = 0;
0208 
0209     if (!en && !adev->in_s0ix)
0210         ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
0211 
0212     return ret;
0213 }
0214 
0215 static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
0216 {
0217     int ret = 0;
0218 
0219     /* vcn dpm on is a prerequisite for vcn power gate messages */
0220     if (enable)
0221         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn,
0222                               0, NULL);
0223     else
0224         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn,
0225                               0, NULL);
0226 
0227     return ret;
0228 }
0229 
0230 static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
0231 {
0232     int ret = 0;
0233 
0234     if (enable)
0235         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg,
0236                               0, NULL);
0237     else
0238         ret = smu_cmn_send_smc_msg_with_param(smu,
0239                               SMU_MSG_PowerDownJpeg, 0,
0240                               NULL);
0241 
0242     return ret;
0243 }
0244 
0245 
0246 static bool yellow_carp_is_dpm_running(struct smu_context *smu)
0247 {
0248     int ret = 0;
0249     uint64_t feature_enabled;
0250 
0251     ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
0252 
0253     if (ret)
0254         return false;
0255 
0256     return !!(feature_enabled & SMC_DPM_FEATURE);
0257 }
0258 
0259 static int yellow_carp_post_smu_init(struct smu_context *smu)
0260 {
0261     struct amdgpu_device *adev = smu->adev;
0262     int ret = 0;
0263 
0264     /* allow message will be sent after enable message on Yellow Carp*/
0265     ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL);
0266     if (ret)
0267         dev_err(adev->dev, "Failed to Enable GfxOff!\n");
0268     return ret;
0269 }
0270 
0271 static int yellow_carp_mode_reset(struct smu_context *smu, int type)
0272 {
0273     int ret = 0;
0274 
0275     ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, type, NULL);
0276     if (ret)
0277         dev_err(smu->adev->dev, "Failed to mode reset!\n");
0278 
0279     return ret;
0280 }
0281 
0282 static int yellow_carp_mode2_reset(struct smu_context *smu)
0283 {
0284     return yellow_carp_mode_reset(smu, SMU_RESET_MODE_2);
0285 }
0286 
0287 
0288 static void yellow_carp_get_ss_power_percent(SmuMetrics_t *metrics,
0289                     uint32_t *apu_percent, uint32_t *dgpu_percent)
0290 {
0291     uint32_t apu_boost = 0;
0292     uint32_t dgpu_boost = 0;
0293     uint16_t apu_limit = 0;
0294     uint16_t dgpu_limit = 0;
0295     uint16_t apu_power = 0;
0296     uint16_t dgpu_power = 0;
0297 
0298     /* APU and dGPU power values are reported in milli Watts
0299      * and STAPM power limits are in Watts */
0300     apu_power = metrics->ApuPower/1000;
0301     apu_limit = metrics->StapmOpnLimit;
0302     if (apu_power > apu_limit && apu_limit != 0)
0303         apu_boost =  ((apu_power - apu_limit) * 100) / apu_limit;
0304     apu_boost = (apu_boost > 100) ? 100 : apu_boost;
0305 
0306     dgpu_power = metrics->dGpuPower/1000;
0307     if (metrics->StapmCurrentLimit > metrics->StapmOpnLimit)
0308         dgpu_limit = metrics->StapmCurrentLimit - metrics->StapmOpnLimit;
0309     if (dgpu_power > dgpu_limit && dgpu_limit != 0)
0310         dgpu_boost = ((dgpu_power - dgpu_limit) * 100) / dgpu_limit;
0311     dgpu_boost = (dgpu_boost > 100) ? 100 : dgpu_boost;
0312 
0313     if (dgpu_boost >= apu_boost)
0314         apu_boost = 0;
0315     else
0316         dgpu_boost = 0;
0317 
0318     *apu_percent = apu_boost;
0319     *dgpu_percent = dgpu_boost;
0320 
0321 }
0322 
0323 static int yellow_carp_get_smu_metrics_data(struct smu_context *smu,
0324                             MetricsMember_t member,
0325                             uint32_t *value)
0326 {
0327     struct smu_table_context *smu_table = &smu->smu_table;
0328 
0329     SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
0330     int ret = 0;
0331     uint32_t apu_percent = 0;
0332     uint32_t dgpu_percent = 0;
0333 
0334     ret = smu_cmn_get_metrics_table(smu, NULL, false);
0335     if (ret)
0336         return ret;
0337 
0338     switch (member) {
0339     case METRICS_AVERAGE_GFXCLK:
0340         *value = metrics->GfxclkFrequency;
0341         break;
0342     case METRICS_AVERAGE_SOCCLK:
0343         *value = metrics->SocclkFrequency;
0344         break;
0345     case METRICS_AVERAGE_VCLK:
0346         *value = metrics->VclkFrequency;
0347         break;
0348     case METRICS_AVERAGE_DCLK:
0349         *value = metrics->DclkFrequency;
0350         break;
0351     case METRICS_AVERAGE_UCLK:
0352         *value = metrics->MemclkFrequency;
0353         break;
0354     case METRICS_AVERAGE_GFXACTIVITY:
0355         *value = metrics->GfxActivity / 100;
0356         break;
0357     case METRICS_AVERAGE_VCNACTIVITY:
0358         *value = metrics->UvdActivity;
0359         break;
0360     case METRICS_AVERAGE_SOCKETPOWER:
0361         *value = (metrics->CurrentSocketPower << 8) / 1000;
0362         break;
0363     case METRICS_TEMPERATURE_EDGE:
0364         *value = metrics->GfxTemperature / 100 *
0365         SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
0366         break;
0367     case METRICS_TEMPERATURE_HOTSPOT:
0368         *value = metrics->SocTemperature / 100 *
0369         SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
0370         break;
0371     case METRICS_THROTTLER_STATUS:
0372         *value = metrics->ThrottlerStatus;
0373         break;
0374     case METRICS_VOLTAGE_VDDGFX:
0375         *value = metrics->Voltage[0];
0376         break;
0377     case METRICS_VOLTAGE_VDDSOC:
0378         *value = metrics->Voltage[1];
0379         break;
0380     case METRICS_SS_APU_SHARE:
0381         /* return the percentage of APU power boost
0382          * with respect to APU's power limit.
0383          */
0384         yellow_carp_get_ss_power_percent(metrics, &apu_percent, &dgpu_percent);
0385         *value = apu_percent;
0386         break;
0387     case METRICS_SS_DGPU_SHARE:
0388         /* return the percentage of dGPU power boost
0389          * with respect to dGPU's power limit.
0390          */
0391         yellow_carp_get_ss_power_percent(metrics, &apu_percent, &dgpu_percent);
0392         *value = dgpu_percent;
0393         break;
0394     default:
0395         *value = UINT_MAX;
0396         break;
0397     }
0398 
0399     return ret;
0400 }
0401 
0402 static int yellow_carp_read_sensor(struct smu_context *smu,
0403                     enum amd_pp_sensors sensor,
0404                     void *data, uint32_t *size)
0405 {
0406     int ret = 0;
0407 
0408     if (!data || !size)
0409         return -EINVAL;
0410 
0411     switch (sensor) {
0412     case AMDGPU_PP_SENSOR_GPU_LOAD:
0413         ret = yellow_carp_get_smu_metrics_data(smu,
0414                                 METRICS_AVERAGE_GFXACTIVITY,
0415                                 (uint32_t *)data);
0416         *size = 4;
0417         break;
0418     case AMDGPU_PP_SENSOR_GPU_POWER:
0419         ret = yellow_carp_get_smu_metrics_data(smu,
0420                                 METRICS_AVERAGE_SOCKETPOWER,
0421                                 (uint32_t *)data);
0422         *size = 4;
0423         break;
0424     case AMDGPU_PP_SENSOR_EDGE_TEMP:
0425         ret = yellow_carp_get_smu_metrics_data(smu,
0426                                 METRICS_TEMPERATURE_EDGE,
0427                                 (uint32_t *)data);
0428         *size = 4;
0429         break;
0430     case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
0431         ret = yellow_carp_get_smu_metrics_data(smu,
0432                                 METRICS_TEMPERATURE_HOTSPOT,
0433                                 (uint32_t *)data);
0434         *size = 4;
0435         break;
0436     case AMDGPU_PP_SENSOR_GFX_MCLK:
0437         ret = yellow_carp_get_smu_metrics_data(smu,
0438                                 METRICS_AVERAGE_UCLK,
0439                                 (uint32_t *)data);
0440         *(uint32_t *)data *= 100;
0441         *size = 4;
0442         break;
0443     case AMDGPU_PP_SENSOR_GFX_SCLK:
0444         ret = yellow_carp_get_smu_metrics_data(smu,
0445                                 METRICS_AVERAGE_GFXCLK,
0446                                 (uint32_t *)data);
0447         *(uint32_t *)data *= 100;
0448         *size = 4;
0449         break;
0450     case AMDGPU_PP_SENSOR_VDDGFX:
0451         ret = yellow_carp_get_smu_metrics_data(smu,
0452                                 METRICS_VOLTAGE_VDDGFX,
0453                                 (uint32_t *)data);
0454         *size = 4;
0455         break;
0456     case AMDGPU_PP_SENSOR_VDDNB:
0457         ret = yellow_carp_get_smu_metrics_data(smu,
0458                                 METRICS_VOLTAGE_VDDSOC,
0459                                 (uint32_t *)data);
0460         *size = 4;
0461         break;
0462     case AMDGPU_PP_SENSOR_SS_APU_SHARE:
0463         ret = yellow_carp_get_smu_metrics_data(smu,
0464                                METRICS_SS_APU_SHARE,
0465                                (uint32_t *)data);
0466         *size = 4;
0467         break;
0468     case AMDGPU_PP_SENSOR_SS_DGPU_SHARE:
0469         ret = yellow_carp_get_smu_metrics_data(smu,
0470                                METRICS_SS_DGPU_SHARE,
0471                                (uint32_t *)data);
0472         *size = 4;
0473         break;
0474     default:
0475         ret = -EOPNOTSUPP;
0476         break;
0477     }
0478 
0479     return ret;
0480 }
0481 
0482 static int yellow_carp_set_watermarks_table(struct smu_context *smu,
0483                 struct pp_smu_wm_range_sets *clock_ranges)
0484 {
0485     int i;
0486     int ret = 0;
0487     Watermarks_t *table = smu->smu_table.watermarks_table;
0488 
0489     if (!table || !clock_ranges)
0490         return -EINVAL;
0491 
0492     if (clock_ranges) {
0493         if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
0494             clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
0495             return -EINVAL;
0496 
0497         for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
0498             table->WatermarkRow[WM_DCFCLK][i].MinClock =
0499                 clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
0500             table->WatermarkRow[WM_DCFCLK][i].MaxClock =
0501                 clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
0502             table->WatermarkRow[WM_DCFCLK][i].MinMclk =
0503                 clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
0504             table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
0505                 clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
0506 
0507             table->WatermarkRow[WM_DCFCLK][i].WmSetting =
0508                 clock_ranges->reader_wm_sets[i].wm_inst;
0509         }
0510 
0511         for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
0512             table->WatermarkRow[WM_SOCCLK][i].MinClock =
0513                 clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
0514             table->WatermarkRow[WM_SOCCLK][i].MaxClock =
0515                 clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
0516             table->WatermarkRow[WM_SOCCLK][i].MinMclk =
0517                 clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
0518             table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
0519                 clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
0520 
0521             table->WatermarkRow[WM_SOCCLK][i].WmSetting =
0522                 clock_ranges->writer_wm_sets[i].wm_inst;
0523         }
0524 
0525         smu->watermarks_bitmap |= WATERMARKS_EXIST;
0526     }
0527 
0528     /* pass data to smu controller */
0529     if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
0530          !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
0531         ret = smu_cmn_write_watermarks_table(smu);
0532         if (ret) {
0533             dev_err(smu->adev->dev, "Failed to update WMTABLE!");
0534             return ret;
0535         }
0536         smu->watermarks_bitmap |= WATERMARKS_LOADED;
0537     }
0538 
0539     return 0;
0540 }
0541 
0542 static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu,
0543                         void **table)
0544 {
0545     struct smu_table_context *smu_table = &smu->smu_table;
0546     struct gpu_metrics_v2_1 *gpu_metrics =
0547         (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
0548     SmuMetrics_t metrics;
0549     int ret = 0;
0550 
0551     ret = smu_cmn_get_metrics_table(smu, &metrics, true);
0552     if (ret)
0553         return ret;
0554 
0555     smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1);
0556 
0557     gpu_metrics->temperature_gfx = metrics.GfxTemperature;
0558     gpu_metrics->temperature_soc = metrics.SocTemperature;
0559     memcpy(&gpu_metrics->temperature_core[0],
0560         &metrics.CoreTemperature[0],
0561         sizeof(uint16_t) * 8);
0562     gpu_metrics->temperature_l3[0] = metrics.L3Temperature;
0563 
0564     gpu_metrics->average_gfx_activity = metrics.GfxActivity;
0565     gpu_metrics->average_mm_activity = metrics.UvdActivity;
0566 
0567     gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
0568     gpu_metrics->average_gfx_power = metrics.Power[0];
0569     gpu_metrics->average_soc_power = metrics.Power[1];
0570     memcpy(&gpu_metrics->average_core_power[0],
0571         &metrics.CorePower[0],
0572         sizeof(uint16_t) * 8);
0573 
0574     gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
0575     gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
0576     gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
0577     gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
0578     gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
0579     gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
0580 
0581     memcpy(&gpu_metrics->current_coreclk[0],
0582         &metrics.CoreFrequency[0],
0583         sizeof(uint16_t) * 8);
0584     gpu_metrics->current_l3clk[0] = metrics.L3Frequency;
0585 
0586     gpu_metrics->throttle_status = metrics.ThrottlerStatus;
0587 
0588     gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
0589 
0590     *table = (void *)gpu_metrics;
0591 
0592     return sizeof(struct gpu_metrics_v2_1);
0593 }
0594 
0595 /**
0596  * yellow_carp_get_gfxoff_status - get gfxoff status
0597  *
0598  * @smu: smu_context pointer
0599  *
0600  * This function will be used to get gfxoff status
0601  *
0602  * Returns 0=GFXOFF(default).
0603  * Returns 1=Transition out of GFX State.
0604  * Returns 2=Not in GFXOFF.
0605  * Returns 3=Transition into GFXOFF.
0606  */
0607 static uint32_t yellow_carp_get_gfxoff_status(struct smu_context *smu)
0608 {
0609     uint32_t reg;
0610     uint32_t gfxoff_status = 0;
0611     struct amdgpu_device *adev = smu->adev;
0612 
0613     reg = RREG32_SOC15(SMUIO, 0, regSMUIO_GFX_MISC_CNTL);
0614     gfxoff_status = (reg & SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK)
0615         >> SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT;
0616 
0617     return gfxoff_status;
0618 }
0619 
0620 static int yellow_carp_set_default_dpm_tables(struct smu_context *smu)
0621 {
0622     struct smu_table_context *smu_table = &smu->smu_table;
0623 
0624     return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
0625 }
0626 
0627 static int yellow_carp_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
0628                     long input[], uint32_t size)
0629 {
0630     struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
0631     int ret = 0;
0632 
0633     /* Only allowed in manual mode */
0634     if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
0635         return -EINVAL;
0636 
0637     switch (type) {
0638     case PP_OD_EDIT_SCLK_VDDC_TABLE:
0639         if (size != 2) {
0640             dev_err(smu->adev->dev, "Input parameter number not correct\n");
0641             return -EINVAL;
0642         }
0643 
0644         if (input[0] == 0) {
0645             if (input[1] < smu->gfx_default_hard_min_freq) {
0646                 dev_warn(smu->adev->dev,
0647                     "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
0648                     input[1], smu->gfx_default_hard_min_freq);
0649                 return -EINVAL;
0650             }
0651             smu->gfx_actual_hard_min_freq = input[1];
0652         } else if (input[0] == 1) {
0653             if (input[1] > smu->gfx_default_soft_max_freq) {
0654                 dev_warn(smu->adev->dev,
0655                     "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
0656                     input[1], smu->gfx_default_soft_max_freq);
0657                 return -EINVAL;
0658             }
0659             smu->gfx_actual_soft_max_freq = input[1];
0660         } else {
0661             return -EINVAL;
0662         }
0663         break;
0664     case PP_OD_RESTORE_DEFAULT_TABLE:
0665         if (size != 0) {
0666             dev_err(smu->adev->dev, "Input parameter number not correct\n");
0667             return -EINVAL;
0668         } else {
0669             smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
0670             smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
0671         }
0672         break;
0673     case PP_OD_COMMIT_DPM_TABLE:
0674         if (size != 0) {
0675             dev_err(smu->adev->dev, "Input parameter number not correct\n");
0676             return -EINVAL;
0677         } else {
0678             if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
0679                 dev_err(smu->adev->dev,
0680                     "The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
0681                     smu->gfx_actual_hard_min_freq,
0682                     smu->gfx_actual_soft_max_freq);
0683                 return -EINVAL;
0684             }
0685 
0686             ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
0687                                     smu->gfx_actual_hard_min_freq, NULL);
0688             if (ret) {
0689                 dev_err(smu->adev->dev, "Set hard min sclk failed!");
0690                 return ret;
0691             }
0692 
0693             ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
0694                                     smu->gfx_actual_soft_max_freq, NULL);
0695             if (ret) {
0696                 dev_err(smu->adev->dev, "Set soft max sclk failed!");
0697                 return ret;
0698             }
0699         }
0700         break;
0701     default:
0702         return -ENOSYS;
0703     }
0704 
0705     return ret;
0706 }
0707 
0708 static int yellow_carp_get_current_clk_freq(struct smu_context *smu,
0709                         enum smu_clk_type clk_type,
0710                         uint32_t *value)
0711 {
0712     MetricsMember_t member_type;
0713 
0714     switch (clk_type) {
0715     case SMU_SOCCLK:
0716         member_type = METRICS_AVERAGE_SOCCLK;
0717         break;
0718     case SMU_VCLK:
0719         member_type = METRICS_AVERAGE_VCLK;
0720         break;
0721     case SMU_DCLK:
0722         member_type = METRICS_AVERAGE_DCLK;
0723         break;
0724     case SMU_MCLK:
0725         member_type = METRICS_AVERAGE_UCLK;
0726         break;
0727     case SMU_FCLK:
0728         return smu_cmn_send_smc_msg_with_param(smu,
0729                 SMU_MSG_GetFclkFrequency, 0, value);
0730     case SMU_GFXCLK:
0731     case SMU_SCLK:
0732         return smu_cmn_send_smc_msg_with_param(smu,
0733                 SMU_MSG_GetGfxclkFrequency, 0, value);
0734         break;
0735     default:
0736         return -EINVAL;
0737     }
0738 
0739     return yellow_carp_get_smu_metrics_data(smu, member_type, value);
0740 }
0741 
0742 static int yellow_carp_get_dpm_level_count(struct smu_context *smu,
0743                         enum smu_clk_type clk_type,
0744                         uint32_t *count)
0745 {
0746     DpmClocks_t *clk_table = smu->smu_table.clocks_table;
0747 
0748     switch (clk_type) {
0749     case SMU_SOCCLK:
0750         *count = clk_table->NumSocClkLevelsEnabled;
0751         break;
0752     case SMU_VCLK:
0753         *count = clk_table->VcnClkLevelsEnabled;
0754         break;
0755     case SMU_DCLK:
0756         *count = clk_table->VcnClkLevelsEnabled;
0757         break;
0758     case SMU_MCLK:
0759         *count = clk_table->NumDfPstatesEnabled;
0760         break;
0761     case SMU_FCLK:
0762         *count = clk_table->NumDfPstatesEnabled;
0763         break;
0764     default:
0765         break;
0766     }
0767 
0768     return 0;
0769 }
0770 
0771 static int yellow_carp_get_dpm_freq_by_index(struct smu_context *smu,
0772                         enum smu_clk_type clk_type,
0773                         uint32_t dpm_level,
0774                         uint32_t *freq)
0775 {
0776     DpmClocks_t *clk_table = smu->smu_table.clocks_table;
0777 
0778     if (!clk_table || clk_type >= SMU_CLK_COUNT)
0779         return -EINVAL;
0780 
0781     switch (clk_type) {
0782     case SMU_SOCCLK:
0783         if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
0784             return -EINVAL;
0785         *freq = clk_table->SocClocks[dpm_level];
0786         break;
0787     case SMU_VCLK:
0788         if (dpm_level >= clk_table->VcnClkLevelsEnabled)
0789             return -EINVAL;
0790         *freq = clk_table->VClocks[dpm_level];
0791         break;
0792     case SMU_DCLK:
0793         if (dpm_level >= clk_table->VcnClkLevelsEnabled)
0794             return -EINVAL;
0795         *freq = clk_table->DClocks[dpm_level];
0796         break;
0797     case SMU_UCLK:
0798     case SMU_MCLK:
0799         if (dpm_level >= clk_table->NumDfPstatesEnabled)
0800             return -EINVAL;
0801         *freq = clk_table->DfPstateTable[dpm_level].MemClk;
0802         break;
0803     case SMU_FCLK:
0804         if (dpm_level >= clk_table->NumDfPstatesEnabled)
0805             return -EINVAL;
0806         *freq = clk_table->DfPstateTable[dpm_level].FClk;
0807         break;
0808     default:
0809         return -EINVAL;
0810     }
0811 
0812     return 0;
0813 }
0814 
0815 static bool yellow_carp_clk_dpm_is_enabled(struct smu_context *smu,
0816                         enum smu_clk_type clk_type)
0817 {
0818     enum smu_feature_mask feature_id = 0;
0819 
0820     switch (clk_type) {
0821     case SMU_MCLK:
0822     case SMU_UCLK:
0823     case SMU_FCLK:
0824         feature_id = SMU_FEATURE_DPM_FCLK_BIT;
0825         break;
0826     case SMU_GFXCLK:
0827     case SMU_SCLK:
0828         feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
0829         break;
0830     case SMU_SOCCLK:
0831         feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
0832         break;
0833     case SMU_VCLK:
0834     case SMU_DCLK:
0835         feature_id = SMU_FEATURE_VCN_DPM_BIT;
0836         break;
0837     default:
0838         return true;
0839     }
0840 
0841     return smu_cmn_feature_is_enabled(smu, feature_id);
0842 }
0843 
0844 static int yellow_carp_get_dpm_ultimate_freq(struct smu_context *smu,
0845                             enum smu_clk_type clk_type,
0846                             uint32_t *min,
0847                             uint32_t *max)
0848 {
0849     DpmClocks_t *clk_table = smu->smu_table.clocks_table;
0850     uint32_t clock_limit;
0851     uint32_t max_dpm_level, min_dpm_level;
0852     int ret = 0;
0853 
0854     if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type)) {
0855         switch (clk_type) {
0856         case SMU_MCLK:
0857         case SMU_UCLK:
0858             clock_limit = smu->smu_table.boot_values.uclk;
0859             break;
0860         case SMU_FCLK:
0861             clock_limit = smu->smu_table.boot_values.fclk;
0862             break;
0863         case SMU_GFXCLK:
0864         case SMU_SCLK:
0865             clock_limit = smu->smu_table.boot_values.gfxclk;
0866             break;
0867         case SMU_SOCCLK:
0868             clock_limit = smu->smu_table.boot_values.socclk;
0869             break;
0870         case SMU_VCLK:
0871             clock_limit = smu->smu_table.boot_values.vclk;
0872             break;
0873         case SMU_DCLK:
0874             clock_limit = smu->smu_table.boot_values.dclk;
0875             break;
0876         default:
0877             clock_limit = 0;
0878             break;
0879         }
0880 
0881         /* clock in Mhz unit */
0882         if (min)
0883             *min = clock_limit / 100;
0884         if (max)
0885             *max = clock_limit / 100;
0886 
0887         return 0;
0888     }
0889 
0890     if (max) {
0891         switch (clk_type) {
0892         case SMU_GFXCLK:
0893         case SMU_SCLK:
0894             *max = clk_table->MaxGfxClk;
0895             break;
0896         case SMU_MCLK:
0897         case SMU_UCLK:
0898         case SMU_FCLK:
0899             max_dpm_level = 0;
0900             break;
0901         case SMU_SOCCLK:
0902             max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1;
0903             break;
0904         case SMU_VCLK:
0905         case SMU_DCLK:
0906             max_dpm_level = clk_table->VcnClkLevelsEnabled - 1;
0907             break;
0908         default:
0909             ret = -EINVAL;
0910             goto failed;
0911         }
0912 
0913         if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
0914             ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max);
0915             if (ret)
0916                 goto failed;
0917         }
0918     }
0919 
0920     if (min) {
0921         switch (clk_type) {
0922         case SMU_GFXCLK:
0923         case SMU_SCLK:
0924             *min = clk_table->MinGfxClk;
0925             break;
0926         case SMU_MCLK:
0927         case SMU_UCLK:
0928         case SMU_FCLK:
0929             min_dpm_level = clk_table->NumDfPstatesEnabled - 1;
0930             break;
0931         case SMU_SOCCLK:
0932             min_dpm_level = 0;
0933             break;
0934         case SMU_VCLK:
0935         case SMU_DCLK:
0936             min_dpm_level = 0;
0937             break;
0938         default:
0939             ret = -EINVAL;
0940             goto failed;
0941         }
0942 
0943         if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
0944             ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min);
0945             if (ret)
0946                 goto failed;
0947         }
0948     }
0949 
0950 failed:
0951     return ret;
0952 }
0953 
0954 static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu,
0955                             enum smu_clk_type clk_type,
0956                             uint32_t min,
0957                             uint32_t max)
0958 {
0959     enum smu_message_type msg_set_min, msg_set_max;
0960     int ret = 0;
0961 
0962     if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type))
0963         return -EINVAL;
0964 
0965     switch (clk_type) {
0966     case SMU_GFXCLK:
0967     case SMU_SCLK:
0968         msg_set_min = SMU_MSG_SetHardMinGfxClk;
0969         msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
0970         break;
0971     case SMU_FCLK:
0972         msg_set_min = SMU_MSG_SetHardMinFclkByFreq;
0973         msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq;
0974         break;
0975     case SMU_SOCCLK:
0976         msg_set_min = SMU_MSG_SetHardMinSocclkByFreq;
0977         msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq;
0978         break;
0979     case SMU_VCLK:
0980     case SMU_DCLK:
0981         msg_set_min = SMU_MSG_SetHardMinVcn;
0982         msg_set_max = SMU_MSG_SetSoftMaxVcn;
0983         break;
0984     default:
0985         return -EINVAL;
0986     }
0987 
0988     ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL);
0989     if (ret)
0990         goto out;
0991 
0992     ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL);
0993     if (ret)
0994         goto out;
0995 
0996 out:
0997     return ret;
0998 }
0999 
1000 static int yellow_carp_print_clk_levels(struct smu_context *smu,
1001                 enum smu_clk_type clk_type, char *buf)
1002 {
1003     int i, size = 0, ret = 0;
1004     uint32_t cur_value = 0, value = 0, count = 0;
1005     uint32_t min, max;
1006 
1007     smu_cmn_get_sysfs_buf(&buf, &size);
1008 
1009     switch (clk_type) {
1010     case SMU_OD_SCLK:
1011         size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
1012         size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
1013         (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
1014         size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
1015         (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
1016         break;
1017     case SMU_OD_RANGE:
1018         size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
1019         size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
1020                         smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
1021         break;
1022     case SMU_SOCCLK:
1023     case SMU_VCLK:
1024     case SMU_DCLK:
1025     case SMU_MCLK:
1026     case SMU_FCLK:
1027         ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
1028         if (ret)
1029             goto print_clk_out;
1030 
1031         ret = yellow_carp_get_dpm_level_count(smu, clk_type, &count);
1032         if (ret)
1033             goto print_clk_out;
1034 
1035         for (i = 0; i < count; i++) {
1036             ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, i, &value);
1037             if (ret)
1038                 goto print_clk_out;
1039 
1040             size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
1041                     cur_value == value ? "*" : "");
1042         }
1043         break;
1044     case SMU_GFXCLK:
1045     case SMU_SCLK:
1046         ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
1047         if (ret)
1048             goto print_clk_out;
1049         min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
1050         max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
1051         if (cur_value  == max)
1052             i = 2;
1053         else if (cur_value == min)
1054             i = 0;
1055         else
1056             i = 1;
1057         size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,
1058                 i == 0 ? "*" : "");
1059         size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
1060                 i == 1 ? cur_value : YELLOW_CARP_UMD_PSTATE_GFXCLK,
1061                 i == 1 ? "*" : "");
1062         size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,
1063                 i == 2 ? "*" : "");
1064         break;
1065     default:
1066         break;
1067     }
1068 
1069 print_clk_out:
1070     return size;
1071 }
1072 
1073 static int yellow_carp_force_clk_levels(struct smu_context *smu,
1074                 enum smu_clk_type clk_type, uint32_t mask)
1075 {
1076     uint32_t soft_min_level = 0, soft_max_level = 0;
1077     uint32_t min_freq = 0, max_freq = 0;
1078     int ret = 0;
1079 
1080     soft_min_level = mask ? (ffs(mask) - 1) : 0;
1081     soft_max_level = mask ? (fls(mask) - 1) : 0;
1082 
1083     switch (clk_type) {
1084     case SMU_SOCCLK:
1085     case SMU_FCLK:
1086     case SMU_VCLK:
1087     case SMU_DCLK:
1088         ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
1089         if (ret)
1090             goto force_level_out;
1091 
1092         ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
1093         if (ret)
1094             goto force_level_out;
1095 
1096         ret = yellow_carp_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
1097         if (ret)
1098             goto force_level_out;
1099         break;
1100     default:
1101         ret = -EINVAL;
1102         break;
1103     }
1104 
1105 force_level_out:
1106     return ret;
1107 }
1108 
1109 static int yellow_carp_set_performance_level(struct smu_context *smu,
1110                         enum amd_dpm_forced_level level)
1111 {
1112     struct amdgpu_device *adev = smu->adev;
1113     uint32_t sclk_min = 0, sclk_max = 0;
1114     uint32_t fclk_min = 0, fclk_max = 0;
1115     uint32_t socclk_min = 0, socclk_max = 0;
1116     int ret = 0;
1117 
1118     switch (level) {
1119     case AMD_DPM_FORCED_LEVEL_HIGH:
1120         yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);
1121         yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max);
1122         yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max);
1123         sclk_min = sclk_max;
1124         fclk_min = fclk_max;
1125         socclk_min = socclk_max;
1126         break;
1127     case AMD_DPM_FORCED_LEVEL_LOW:
1128         yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);
1129         yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL);
1130         yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL);
1131         sclk_max = sclk_min;
1132         fclk_max = fclk_min;
1133         socclk_max = socclk_min;
1134         break;
1135     case AMD_DPM_FORCED_LEVEL_AUTO:
1136         yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);
1137         yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max);
1138         yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max);
1139         break;
1140     case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1141     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1142     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
1143     case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1144         /* Temporarily do nothing since the optimal clocks haven't been provided yet */
1145         break;
1146     case AMD_DPM_FORCED_LEVEL_MANUAL:
1147     case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1148         return 0;
1149     default:
1150         dev_err(adev->dev, "Invalid performance level %d\n", level);
1151         return -EINVAL;
1152     }
1153 
1154     if (sclk_min && sclk_max) {
1155         ret = yellow_carp_set_soft_freq_limited_range(smu,
1156                                 SMU_SCLK,
1157                                 sclk_min,
1158                                 sclk_max);
1159         if (ret)
1160             return ret;
1161 
1162         smu->gfx_actual_hard_min_freq = sclk_min;
1163         smu->gfx_actual_soft_max_freq = sclk_max;
1164     }
1165 
1166     if (fclk_min && fclk_max) {
1167         ret = yellow_carp_set_soft_freq_limited_range(smu,
1168                                 SMU_FCLK,
1169                                 fclk_min,
1170                                 fclk_max);
1171         if (ret)
1172             return ret;
1173     }
1174 
1175     if (socclk_min && socclk_max) {
1176         ret = yellow_carp_set_soft_freq_limited_range(smu,
1177                                 SMU_SOCCLK,
1178                                 socclk_min,
1179                                 socclk_max);
1180         if (ret)
1181             return ret;
1182     }
1183 
1184     return ret;
1185 }
1186 
1187 static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
1188 {
1189     DpmClocks_t *clk_table = smu->smu_table.clocks_table;
1190 
1191     smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
1192     smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
1193     smu->gfx_actual_hard_min_freq = 0;
1194     smu->gfx_actual_soft_max_freq = 0;
1195 
1196     return 0;
1197 }
1198 
1199 static const struct pptable_funcs yellow_carp_ppt_funcs = {
1200     .check_fw_status = smu_v13_0_check_fw_status,
1201     .check_fw_version = smu_v13_0_check_fw_version,
1202     .init_smc_tables = yellow_carp_init_smc_tables,
1203     .fini_smc_tables = yellow_carp_fini_smc_tables,
1204     .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
1205     .system_features_control = yellow_carp_system_features_control,
1206     .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
1207     .send_smc_msg = smu_cmn_send_smc_msg,
1208     .dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable,
1209     .dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable,
1210     .set_default_dpm_table = yellow_carp_set_default_dpm_tables,
1211     .read_sensor = yellow_carp_read_sensor,
1212     .is_dpm_running = yellow_carp_is_dpm_running,
1213     .set_watermarks_table = yellow_carp_set_watermarks_table,
1214     .get_gpu_metrics = yellow_carp_get_gpu_metrics,
1215     .get_enabled_mask = smu_cmn_get_enabled_mask,
1216     .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
1217     .set_driver_table_location = smu_v13_0_set_driver_table_location,
1218     .gfx_off_control = smu_v13_0_gfx_off_control,
1219     .get_gfx_off_status = yellow_carp_get_gfxoff_status,
1220     .post_init = yellow_carp_post_smu_init,
1221     .mode2_reset = yellow_carp_mode2_reset,
1222     .get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq,
1223     .od_edit_dpm_table = yellow_carp_od_edit_dpm_table,
1224     .print_clk_levels = yellow_carp_print_clk_levels,
1225     .force_clk_levels = yellow_carp_force_clk_levels,
1226     .set_performance_level = yellow_carp_set_performance_level,
1227     .set_fine_grain_gfx_freq_parameters = yellow_carp_set_fine_grain_gfx_freq_parameters,
1228 };
1229 
1230 void yellow_carp_set_ppt_funcs(struct smu_context *smu)
1231 {
1232     smu->ppt_funcs = &yellow_carp_ppt_funcs;
1233     smu->message_map = yellow_carp_message_map;
1234     smu->feature_map = yellow_carp_feature_mask_map;
1235     smu->table_map = yellow_carp_table_map;
1236     smu->is_apu = true;
1237     smu_v13_0_set_smu_mailbox_registers(smu);
1238 }