linux/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
<<
>>
Prefs
   1/*
   2 * Copyright 2020 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 */
  23
  24#define SWSMU_CODE_LAYER_L2
  25
  26#include "amdgpu.h"
  27#include "amdgpu_smu.h"
  28#include "smu_v13_0.h"
  29#include "smu13_driver_if_yellow_carp.h"
  30#include "yellow_carp_ppt.h"
  31#include "smu_v13_0_1_ppsmc.h"
  32#include "smu_v13_0_1_pmfw.h"
  33#include "smu_cmn.h"
  34
  35/*
  36 * DO NOT use these for err/warn/info/debug messages.
  37 * Use dev_err, dev_warn, dev_info and dev_dbg instead.
  38 * They are more MGPU friendly.
  39 */
  40#undef pr_err
  41#undef pr_warn
  42#undef pr_info
  43#undef pr_debug
  44
  45#define FEATURE_MASK(feature) (1ULL << feature)
  46#define SMC_DPM_FEATURE ( \
  47        FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
  48        FEATURE_MASK(FEATURE_VCN_DPM_BIT)        | \
  49        FEATURE_MASK(FEATURE_FCLK_DPM_BIT)       | \
  50        FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)     | \
  51        FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)     | \
  52        FEATURE_MASK(FEATURE_LCLK_DPM_BIT)       | \
  53        FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)    | \
  54        FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
  55        FEATURE_MASK(FEATURE_GFX_DPM_BIT))
  56
  57static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = {
  58        MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,                  1),
  59        MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,                1),
  60        MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,           1),
  61        MSG_MAP(EnableGfxOff,                   PPSMC_MSG_EnableGfxOff,                 1),
  62        MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff,                  1),
  63        MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,               1),
  64        MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,                 1),
  65        MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn,                   1),
  66        MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn,                1),
  67        MSG_MAP(ActiveProcessNotify,            PPSMC_MSG_ActiveProcessNotify,          1),
  68        MSG_MAP(PrepareMp1ForUnload,            PPSMC_MSG_PrepareMp1ForUnload,      1),
  69        MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh,        1),
  70        MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow,         1),
  71        MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,        1),
  72        MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,        1),
  73        MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset,         1),
  74        MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,        1),
  75        MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq,       1),
  76        MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn,                1),
  77        MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency,           1),
  78        MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency,             1),
  79        MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk,             1),
  80        MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk,             1),
  81        MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq,       1),
  82        MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq,         1),
  83        MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn,                1),
  84        MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage,      1),
  85        MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg,                1),
  86        MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg,                  1),
  87        MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq,         1),
  88        MSG_MAP(SetSoftMinSocclkByFreq,         PPSMC_MSG_SetSoftMinSocclkByFreq,       1),
  89};
  90
  91static struct cmn2asic_mapping yellow_carp_feature_mask_map[SMU_FEATURE_COUNT] = {
  92        FEA_MAP(CCLK_DPM),
  93        FEA_MAP(FAN_CONTROLLER),
  94        FEA_MAP(PPT),
  95        FEA_MAP(TDC),
  96        FEA_MAP(THERMAL),
  97        FEA_MAP(ULV),
  98        FEA_MAP(VCN_DPM),
  99        FEA_MAP_REVERSE(FCLK),
 100        FEA_MAP_REVERSE(SOCCLK),
 101        FEA_MAP(LCLK_DPM),
 102        FEA_MAP(SHUBCLK_DPM),
 103        FEA_MAP(DCFCLK_DPM),
 104        FEA_MAP_HALF_REVERSE(GFX),
 105        FEA_MAP(DS_GFXCLK),
 106        FEA_MAP(DS_SOCCLK),
 107        FEA_MAP(DS_LCLK),
 108        FEA_MAP(DS_DCFCLK),
 109        FEA_MAP(DS_FCLK),
 110        FEA_MAP(DS_MP1CLK),
 111        FEA_MAP(DS_MP0CLK),
 112        FEA_MAP(GFX_DEM),
 113        FEA_MAP(PSI),
 114        FEA_MAP(PROCHOT),
 115        FEA_MAP(CPUOFF),
 116        FEA_MAP(STAPM),
 117        FEA_MAP(S0I3),
 118        FEA_MAP(PERF_LIMIT),
 119        FEA_MAP(CORE_DLDO),
 120        FEA_MAP(RSMU_LOW_POWER),
 121        FEA_MAP(SMN_LOW_POWER),
 122        FEA_MAP(THM_LOW_POWER),
 123        FEA_MAP(SMUIO_LOW_POWER),
 124        FEA_MAP(MP1_LOW_POWER),
 125        FEA_MAP(DS_VCN),
 126        FEA_MAP(CPPC),
 127        FEA_MAP(DF_CSTATES),
 128        FEA_MAP(MSMU_LOW_POWER),
 129        FEA_MAP(ATHUB_PG),
 130};
 131
 132static struct cmn2asic_mapping yellow_carp_table_map[SMU_TABLE_COUNT] = {
 133        TAB_MAP_VALID(WATERMARKS),
 134        TAB_MAP_VALID(SMU_METRICS),
 135        TAB_MAP_VALID(CUSTOM_DPM),
 136        TAB_MAP_VALID(DPMCLOCKS),
 137};
 138
 139static struct cmn2asic_mapping yellow_carp_workload_map[PP_SMC_POWER_PROFILE_COUNT] = {
 140        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D,         WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT),
 141        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO,                WORKLOAD_PPLIB_VIDEO_BIT),
 142        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR,                   WORKLOAD_PPLIB_VR_BIT),
 143        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE,              WORKLOAD_PPLIB_COMPUTE_BIT),
 144        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM,               WORKLOAD_PPLIB_CUSTOM_BIT),
 145};
 146        
 147static int yellow_carp_init_smc_tables(struct smu_context *smu)
 148{
 149        struct smu_table_context *smu_table = &smu->smu_table;
 150        struct smu_table *tables = smu_table->tables;
 151
 152        SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
 153                PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 154        SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
 155                PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 156        SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
 157                PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 158
 159        smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
 160        if (!smu_table->clocks_table)
 161                goto err0_out;
 162
 163        smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
 164        if (!smu_table->metrics_table)
 165                goto err1_out;
 166        smu_table->metrics_time = 0;
 167
 168        smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
 169        if (!smu_table->watermarks_table)
 170                goto err2_out;
 171
 172        smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1);
 173        smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
 174        if (!smu_table->gpu_metrics_table)
 175                goto err3_out;
 176
 177        return 0;
 178
 179err3_out:
 180        kfree(smu_table->watermarks_table);
 181err2_out:
 182        kfree(smu_table->metrics_table);
 183err1_out:
 184        kfree(smu_table->clocks_table);
 185err0_out:
 186        return -ENOMEM;
 187}
 188
 189static int yellow_carp_fini_smc_tables(struct smu_context *smu)
 190{
 191        struct smu_table_context *smu_table = &smu->smu_table;
 192
 193        kfree(smu_table->clocks_table);
 194        smu_table->clocks_table = NULL;
 195
 196        kfree(smu_table->metrics_table);
 197        smu_table->metrics_table = NULL;
 198
 199        kfree(smu_table->watermarks_table);
 200        smu_table->watermarks_table = NULL;
 201
 202        return 0;
 203}
 204
 205static int yellow_carp_system_features_control(struct smu_context *smu, bool en)
 206{
 207        struct smu_feature *feature = &smu->smu_feature;
 208        struct amdgpu_device *adev = smu->adev;
 209        uint32_t feature_mask[2];
 210        int ret = 0;
 211
 212        if (!en && !adev->in_s0ix)
 213                ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
 214
 215        bitmap_zero(feature->enabled, feature->feature_num);
 216        bitmap_zero(feature->supported, feature->feature_num);
 217
 218        if (!en)
 219                return ret;
 220
 221        ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
 222        if (ret)
 223                return ret;
 224
 225        bitmap_copy(feature->enabled, (unsigned long *)&feature_mask,
 226                    feature->feature_num);
 227        bitmap_copy(feature->supported, (unsigned long *)&feature_mask,
 228                    feature->feature_num);
 229
 230        return 0;
 231}
 232
 233static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
 234{
 235        int ret = 0;
 236
 237        /* vcn dpm on is a prerequisite for vcn power gate messages */
 238        if (enable)
 239                ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn,
 240                                                      0, NULL);
 241        else
 242                ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn,
 243                                                      0, NULL);
 244
 245        return ret;
 246}
 247
 248static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
 249{
 250        int ret = 0;
 251
 252        if (enable)
 253                ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg,
 254                                                      0, NULL);
 255        else
 256                ret = smu_cmn_send_smc_msg_with_param(smu,
 257                                                      SMU_MSG_PowerDownJpeg, 0,
 258                                                      NULL);
 259
 260        return ret;
 261}
 262
 263
 264static bool yellow_carp_is_dpm_running(struct smu_context *smu)
 265{
 266        int ret = 0;
 267        uint32_t feature_mask[2];
 268        uint64_t feature_enabled;
 269
 270        ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
 271
 272        if (ret)
 273                return false;
 274
 275        feature_enabled = (uint64_t)feature_mask[1] << 32 | feature_mask[0];
 276
 277        return !!(feature_enabled & SMC_DPM_FEATURE);
 278}
 279
 280static int yellow_carp_post_smu_init(struct smu_context *smu)
 281{
 282        struct amdgpu_device *adev = smu->adev;
 283        int ret = 0;
 284
 285        /* allow message will be sent after enable message on Yellow Carp*/
 286        ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL);
 287        if (ret)
 288                dev_err(adev->dev, "Failed to Enable GfxOff!\n");
 289        return ret;
 290}
 291
 292static int yellow_carp_mode_reset(struct smu_context *smu, int type)
 293{
 294        int ret = 0, index = 0;
 295
 296        index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
 297                                SMU_MSG_GfxDeviceDriverReset);
 298        if (index < 0)
 299                return index == -EACCES ? 0 : index;
 300
 301        ret = smu_cmn_send_smc_msg_with_param(smu, (uint16_t)index, type, NULL);
 302        if (ret)
 303                dev_err(smu->adev->dev, "Failed to mode reset!\n");
 304
 305        return ret;
 306}
 307
 308static int yellow_carp_mode2_reset(struct smu_context *smu)
 309{
 310        return yellow_carp_mode_reset(smu, SMU_RESET_MODE_2);
 311}
 312
 313static int yellow_carp_get_smu_metrics_data(struct smu_context *smu,
 314                                                        MetricsMember_t member,
 315                                                        uint32_t *value)
 316{
 317        struct smu_table_context *smu_table = &smu->smu_table;
 318
 319        SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
 320        int ret = 0;
 321
 322        mutex_lock(&smu->metrics_lock);
 323
 324        ret = smu_cmn_get_metrics_table_locked(smu, NULL, false);
 325        if (ret) {
 326                mutex_unlock(&smu->metrics_lock);
 327                return ret;
 328        }
 329
 330        switch (member) {
 331        case METRICS_AVERAGE_GFXCLK:
 332                *value = metrics->GfxclkFrequency;
 333                break;
 334        case METRICS_AVERAGE_SOCCLK:
 335                *value = metrics->SocclkFrequency;
 336                break;
 337        case METRICS_AVERAGE_VCLK:
 338                *value = metrics->VclkFrequency;
 339                break;
 340        case METRICS_AVERAGE_DCLK:
 341                *value = metrics->DclkFrequency;
 342                break;
 343        case METRICS_AVERAGE_UCLK:
 344                *value = metrics->MemclkFrequency;
 345                break;
 346        case METRICS_AVERAGE_GFXACTIVITY:
 347                *value = metrics->GfxActivity / 100;
 348                break;
 349        case METRICS_AVERAGE_VCNACTIVITY:
 350                *value = metrics->UvdActivity;
 351                break;
 352        case METRICS_AVERAGE_SOCKETPOWER:
 353                *value = (metrics->CurrentSocketPower << 8) / 1000;
 354                break;
 355        case METRICS_TEMPERATURE_EDGE:
 356                *value = metrics->GfxTemperature / 100 *
 357                SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
 358                break;
 359        case METRICS_TEMPERATURE_HOTSPOT:
 360                *value = metrics->SocTemperature / 100 *
 361                SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
 362                break;
 363        case METRICS_THROTTLER_STATUS:
 364                *value = metrics->ThrottlerStatus;
 365                break;
 366        case METRICS_VOLTAGE_VDDGFX:
 367                *value = metrics->Voltage[0];
 368                break;
 369        case METRICS_VOLTAGE_VDDSOC:
 370                *value = metrics->Voltage[1];
 371                break;
 372        case METRICS_SS_APU_SHARE:
 373                /* return the percentage of APU power with respect to APU's power limit.
 374                 * percentage is reported, this isn't boost value. Smartshift power
 375                 * boost/shift is only when the percentage is more than 100.
 376                 */
 377                if (metrics->StapmOpnLimit > 0)
 378                        *value =  (metrics->ApuPower * 100) / metrics->StapmOpnLimit;
 379                else
 380                        *value = 0;
 381                break;
 382        case METRICS_SS_DGPU_SHARE:
 383                /* return the percentage of dGPU power with respect to dGPU's power limit.
 384                 * percentage is reported, this isn't boost value. Smartshift power
 385                 * boost/shift is only when the percentage is more than 100.
 386                 */
 387                if ((metrics->dGpuPower > 0) &&
 388                    (metrics->StapmCurrentLimit > metrics->StapmOpnLimit))
 389                        *value = (metrics->dGpuPower * 100) /
 390                                  (metrics->StapmCurrentLimit - metrics->StapmOpnLimit);
 391                else
 392                        *value = 0;
 393                break;
 394        default:
 395                *value = UINT_MAX;
 396                break;
 397        }
 398
 399        mutex_unlock(&smu->metrics_lock);
 400
 401        return ret;
 402}
 403
 404static int yellow_carp_read_sensor(struct smu_context *smu,
 405                                        enum amd_pp_sensors sensor,
 406                                        void *data, uint32_t *size)
 407{
 408        int ret = 0;
 409
 410        if (!data || !size)
 411                return -EINVAL;
 412
 413        mutex_lock(&smu->sensor_lock);
 414        switch (sensor) {
 415        case AMDGPU_PP_SENSOR_GPU_LOAD:
 416                ret = yellow_carp_get_smu_metrics_data(smu,
 417                                                                METRICS_AVERAGE_GFXACTIVITY,
 418                                                                (uint32_t *)data);
 419                *size = 4;
 420                break;
 421        case AMDGPU_PP_SENSOR_GPU_POWER:
 422                ret = yellow_carp_get_smu_metrics_data(smu,
 423                                                                METRICS_AVERAGE_SOCKETPOWER,
 424                                                                (uint32_t *)data);
 425                *size = 4;
 426                break;
 427        case AMDGPU_PP_SENSOR_EDGE_TEMP:
 428                ret = yellow_carp_get_smu_metrics_data(smu,
 429                                                                METRICS_TEMPERATURE_EDGE,
 430                                                                (uint32_t *)data);
 431                *size = 4;
 432                break;
 433        case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
 434                ret = yellow_carp_get_smu_metrics_data(smu,
 435                                                                METRICS_TEMPERATURE_HOTSPOT,
 436                                                                (uint32_t *)data);
 437                *size = 4;
 438                break;
 439        case AMDGPU_PP_SENSOR_GFX_MCLK:
 440                ret = yellow_carp_get_smu_metrics_data(smu,
 441                                                                METRICS_AVERAGE_UCLK,
 442                                                                (uint32_t *)data);
 443                *(uint32_t *)data *= 100;
 444                *size = 4;
 445                break;
 446        case AMDGPU_PP_SENSOR_GFX_SCLK:
 447                ret = yellow_carp_get_smu_metrics_data(smu,
 448                                                                METRICS_AVERAGE_GFXCLK,
 449                                                                (uint32_t *)data);
 450                *(uint32_t *)data *= 100;
 451                *size = 4;
 452                break;
 453        case AMDGPU_PP_SENSOR_VDDGFX:
 454                ret = yellow_carp_get_smu_metrics_data(smu,
 455                                                                METRICS_VOLTAGE_VDDGFX,
 456                                                                (uint32_t *)data);
 457                *size = 4;
 458                break;
 459        case AMDGPU_PP_SENSOR_VDDNB:
 460                ret = yellow_carp_get_smu_metrics_data(smu,
 461                                                                METRICS_VOLTAGE_VDDSOC,
 462                                                                (uint32_t *)data);
 463                *size = 4;
 464                break;
 465        case AMDGPU_PP_SENSOR_SS_APU_SHARE:
 466                ret = yellow_carp_get_smu_metrics_data(smu,
 467                                                       METRICS_SS_APU_SHARE,
 468                                                       (uint32_t *)data);
 469                *size = 4;
 470                break;
 471        case AMDGPU_PP_SENSOR_SS_DGPU_SHARE:
 472                ret = yellow_carp_get_smu_metrics_data(smu,
 473                                                       METRICS_SS_DGPU_SHARE,
 474                                                       (uint32_t *)data);
 475                *size = 4;
 476                break;
 477        default:
 478                ret = -EOPNOTSUPP;
 479                break;
 480        }
 481        mutex_unlock(&smu->sensor_lock);
 482
 483        return ret;
 484}
 485
 486static int yellow_carp_set_watermarks_table(struct smu_context *smu,
 487                                struct pp_smu_wm_range_sets *clock_ranges)
 488{
 489        int i;
 490        int ret = 0;
 491        Watermarks_t *table = smu->smu_table.watermarks_table;
 492
 493        if (!table || !clock_ranges)
 494                return -EINVAL;
 495
 496        if (clock_ranges) {
 497                if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
 498                        clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
 499                        return -EINVAL;
 500
 501                for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
 502                        table->WatermarkRow[WM_DCFCLK][i].MinClock =
 503                                clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
 504                        table->WatermarkRow[WM_DCFCLK][i].MaxClock =
 505                                clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
 506                        table->WatermarkRow[WM_DCFCLK][i].MinMclk =
 507                                clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
 508                        table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
 509                                clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
 510
 511                        table->WatermarkRow[WM_DCFCLK][i].WmSetting =
 512                                clock_ranges->reader_wm_sets[i].wm_inst;
 513                }
 514
 515                for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
 516                        table->WatermarkRow[WM_SOCCLK][i].MinClock =
 517                                clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
 518                        table->WatermarkRow[WM_SOCCLK][i].MaxClock =
 519                                clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
 520                        table->WatermarkRow[WM_SOCCLK][i].MinMclk =
 521                                clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
 522                        table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
 523                                clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
 524
 525                        table->WatermarkRow[WM_SOCCLK][i].WmSetting =
 526                                clock_ranges->writer_wm_sets[i].wm_inst;
 527                }
 528
 529                smu->watermarks_bitmap |= WATERMARKS_EXIST;
 530        }
 531
 532        /* pass data to smu controller */
 533        if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
 534             !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
 535                ret = smu_cmn_write_watermarks_table(smu);
 536                if (ret) {
 537                        dev_err(smu->adev->dev, "Failed to update WMTABLE!");
 538                        return ret;
 539                }
 540                smu->watermarks_bitmap |= WATERMARKS_LOADED;
 541        }
 542
 543        return 0;
 544}
 545
 546static int yellow_carp_get_power_profile_mode(struct smu_context *smu,
 547                                                char *buf)
 548{
 549        static const char *profile_name[] = {
 550                                        "BOOTUP_DEFAULT",
 551                                        "3D_FULL_SCREEN",
 552                                        "POWER_SAVING",
 553                                        "VIDEO",
 554                                        "VR",
 555                                        "COMPUTE",
 556                                        "CUSTOM"};
 557        uint32_t i, size = 0;
 558        int16_t workload_type = 0;
 559
 560        if (!buf)
 561                return -EINVAL;
 562
 563        for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
 564                /*
 565                 * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT.
 566                 * Not all profile modes are supported on yellow carp.
 567                 */
 568                workload_type = smu_cmn_to_asic_specific_index(smu,
 569                                                               CMN2ASIC_MAPPING_WORKLOAD,
 570                                                               i);
 571
 572                if (workload_type < 0)
 573                        continue;
 574
 575                size += sysfs_emit_at(buf, size, "%2d %14s%s\n",
 576                        i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
 577        }
 578
 579        return size;
 580}
 581
 582static int yellow_carp_set_power_profile_mode(struct smu_context *smu,
 583                                                long *input, uint32_t size)
 584{
 585        int workload_type, ret;
 586        uint32_t profile_mode = input[size];
 587
 588        if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
 589                dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
 590                return -EINVAL;
 591        }
 592
 593        if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
 594                        profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
 595                return 0;
 596
 597        /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
 598        workload_type = smu_cmn_to_asic_specific_index(smu,
 599                                                       CMN2ASIC_MAPPING_WORKLOAD,
 600                                                       profile_mode);
 601        if (workload_type < 0) {
 602                dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on YELLOWCARP\n",
 603                                        profile_mode);
 604                return -EINVAL;
 605        }
 606
 607        ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
 608                                    1 << workload_type,
 609                                    NULL);
 610        if (ret) {
 611                dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
 612                                        workload_type);
 613                return ret;
 614        }
 615
 616        smu->power_profile_mode = profile_mode;
 617
 618        return 0;
 619}
 620
 621static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu,
 622                                                void **table)
 623{
 624        struct smu_table_context *smu_table = &smu->smu_table;
 625        struct gpu_metrics_v2_1 *gpu_metrics =
 626                (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
 627        SmuMetrics_t metrics;
 628        int ret = 0;
 629
 630        ret = smu_cmn_get_metrics_table(smu, &metrics, true);
 631        if (ret)
 632                return ret;
 633
 634        smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1);
 635
 636        gpu_metrics->temperature_gfx = metrics.GfxTemperature;
 637        gpu_metrics->temperature_soc = metrics.SocTemperature;
 638        memcpy(&gpu_metrics->temperature_core[0],
 639                &metrics.CoreTemperature[0],
 640                sizeof(uint16_t) * 8);
 641        gpu_metrics->temperature_l3[0] = metrics.L3Temperature;
 642
 643        gpu_metrics->average_gfx_activity = metrics.GfxActivity;
 644        gpu_metrics->average_mm_activity = metrics.UvdActivity;
 645
 646        gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
 647        gpu_metrics->average_gfx_power = metrics.Power[0];
 648        gpu_metrics->average_soc_power = metrics.Power[1];
 649        memcpy(&gpu_metrics->average_core_power[0],
 650                &metrics.CorePower[0],
 651                sizeof(uint16_t) * 8);
 652
 653        gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
 654        gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
 655        gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
 656        gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
 657        gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
 658        gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
 659
 660        memcpy(&gpu_metrics->current_coreclk[0],
 661                &metrics.CoreFrequency[0],
 662                sizeof(uint16_t) * 8);
 663        gpu_metrics->current_l3clk[0] = metrics.L3Frequency;
 664
 665        gpu_metrics->throttle_status = metrics.ThrottlerStatus;
 666
 667        gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
 668
 669        *table = (void *)gpu_metrics;
 670
 671        return sizeof(struct gpu_metrics_v2_1);
 672}
 673
 674static int yellow_carp_set_default_dpm_tables(struct smu_context *smu)
 675{
 676        struct smu_table_context *smu_table = &smu->smu_table;
 677
 678        return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
 679}
 680
 681static int yellow_carp_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
 682                                        long input[], uint32_t size)
 683{
 684        struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
 685        int ret = 0;
 686
 687        /* Only allowed in manual mode */
 688        if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
 689                return -EINVAL;
 690
 691        switch (type) {
 692        case PP_OD_EDIT_SCLK_VDDC_TABLE:
 693                if (size != 2) {
 694                        dev_err(smu->adev->dev, "Input parameter number not correct\n");
 695                        return -EINVAL;
 696                }
 697
 698                if (input[0] == 0) {
 699                        if (input[1] < smu->gfx_default_hard_min_freq) {
 700                                dev_warn(smu->adev->dev,
 701                                        "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
 702                                        input[1], smu->gfx_default_hard_min_freq);
 703                                return -EINVAL;
 704                        }
 705                        smu->gfx_actual_hard_min_freq = input[1];
 706                } else if (input[0] == 1) {
 707                        if (input[1] > smu->gfx_default_soft_max_freq) {
 708                                dev_warn(smu->adev->dev,
 709                                        "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
 710                                        input[1], smu->gfx_default_soft_max_freq);
 711                                return -EINVAL;
 712                        }
 713                        smu->gfx_actual_soft_max_freq = input[1];
 714                } else {
 715                        return -EINVAL;
 716                }
 717                break;
 718        case PP_OD_RESTORE_DEFAULT_TABLE:
 719                if (size != 0) {
 720                        dev_err(smu->adev->dev, "Input parameter number not correct\n");
 721                        return -EINVAL;
 722                } else {
 723                        smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
 724                        smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
 725                }
 726                break;
 727        case PP_OD_COMMIT_DPM_TABLE:
 728                if (size != 0) {
 729                        dev_err(smu->adev->dev, "Input parameter number not correct\n");
 730                        return -EINVAL;
 731                } else {
 732                        if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
 733                                dev_err(smu->adev->dev,
 734                                        "The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
 735                                        smu->gfx_actual_hard_min_freq,
 736                                        smu->gfx_actual_soft_max_freq);
 737                                return -EINVAL;
 738                        }
 739
 740                        ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
 741                                                                        smu->gfx_actual_hard_min_freq, NULL);
 742                        if (ret) {
 743                                dev_err(smu->adev->dev, "Set hard min sclk failed!");
 744                                return ret;
 745                        }
 746
 747                        ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
 748                                                                        smu->gfx_actual_soft_max_freq, NULL);
 749                        if (ret) {
 750                                dev_err(smu->adev->dev, "Set soft max sclk failed!");
 751                                return ret;
 752                        }
 753                }
 754                break;
 755        default:
 756                return -ENOSYS;
 757        }
 758
 759        return ret;
 760}
 761
 762static int yellow_carp_get_current_clk_freq(struct smu_context *smu,
 763                                                enum smu_clk_type clk_type,
 764                                                uint32_t *value)
 765{
 766        MetricsMember_t member_type;
 767
 768        switch (clk_type) {
 769        case SMU_SOCCLK:
 770                member_type = METRICS_AVERAGE_SOCCLK;
 771                break;
 772        case SMU_VCLK:
 773            member_type = METRICS_AVERAGE_VCLK;
 774                break;
 775        case SMU_DCLK:
 776                member_type = METRICS_AVERAGE_DCLK;
 777                break;
 778        case SMU_MCLK:
 779                member_type = METRICS_AVERAGE_UCLK;
 780                break;
 781        case SMU_FCLK:
 782                return smu_cmn_send_smc_msg_with_param(smu,
 783                                SMU_MSG_GetFclkFrequency, 0, value);
 784        default:
 785                return -EINVAL;
 786        }
 787
 788        return yellow_carp_get_smu_metrics_data(smu, member_type, value);
 789}
 790
 791static int yellow_carp_get_dpm_level_count(struct smu_context *smu,
 792                                                enum smu_clk_type clk_type,
 793                                                uint32_t *count)
 794{
 795        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 796
 797        switch (clk_type) {
 798        case SMU_SOCCLK:
 799                *count = clk_table->NumSocClkLevelsEnabled;
 800                break;
 801        case SMU_VCLK:
 802                *count = clk_table->VcnClkLevelsEnabled;
 803                break;
 804        case SMU_DCLK:
 805                *count = clk_table->VcnClkLevelsEnabled;
 806                break;
 807        case SMU_MCLK:
 808                *count = clk_table->NumDfPstatesEnabled;
 809                break;
 810        case SMU_FCLK:
 811                *count = clk_table->NumDfPstatesEnabled;
 812                break;
 813        default:
 814                break;
 815        }
 816
 817        return 0;
 818}
 819
 820static int yellow_carp_get_dpm_freq_by_index(struct smu_context *smu,
 821                                                enum smu_clk_type clk_type,
 822                                                uint32_t dpm_level,
 823                                                uint32_t *freq)
 824{
 825        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 826
 827        if (!clk_table || clk_type >= SMU_CLK_COUNT)
 828                return -EINVAL;
 829
 830        switch (clk_type) {
 831        case SMU_SOCCLK:
 832                if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
 833                        return -EINVAL;
 834                *freq = clk_table->SocClocks[dpm_level];
 835                break;
 836        case SMU_VCLK:
 837                if (dpm_level >= clk_table->VcnClkLevelsEnabled)
 838                        return -EINVAL;
 839                *freq = clk_table->VClocks[dpm_level];
 840                break;
 841        case SMU_DCLK:
 842                if (dpm_level >= clk_table->VcnClkLevelsEnabled)
 843                        return -EINVAL;
 844                *freq = clk_table->DClocks[dpm_level];
 845                break;
 846        case SMU_UCLK:
 847        case SMU_MCLK:
 848                if (dpm_level >= clk_table->NumDfPstatesEnabled)
 849                        return -EINVAL;
 850                *freq = clk_table->DfPstateTable[dpm_level].MemClk;
 851                break;
 852        case SMU_FCLK:
 853                if (dpm_level >= clk_table->NumDfPstatesEnabled)
 854                        return -EINVAL;
 855                *freq = clk_table->DfPstateTable[dpm_level].FClk;
 856                break;
 857        default:
 858                return -EINVAL;
 859        }
 860
 861        return 0;
 862}
 863
 864static bool yellow_carp_clk_dpm_is_enabled(struct smu_context *smu,
 865                                                enum smu_clk_type clk_type)
 866{
 867        enum smu_feature_mask feature_id = 0;
 868
 869        switch (clk_type) {
 870        case SMU_MCLK:
 871        case SMU_UCLK:
 872        case SMU_FCLK:
 873                feature_id = SMU_FEATURE_DPM_FCLK_BIT;
 874                break;
 875        case SMU_GFXCLK:
 876        case SMU_SCLK:
 877                feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
 878                break;
 879        case SMU_SOCCLK:
 880                feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
 881                break;
 882        case SMU_VCLK:
 883        case SMU_DCLK:
 884                feature_id = SMU_FEATURE_VCN_DPM_BIT;
 885                break;
 886        default:
 887                return true;
 888        }
 889
 890        return smu_cmn_feature_is_enabled(smu, feature_id);
 891}
 892
 893static int yellow_carp_get_dpm_ultimate_freq(struct smu_context *smu,
 894                                                        enum smu_clk_type clk_type,
 895                                                        uint32_t *min,
 896                                                        uint32_t *max)
 897{
 898        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 899        uint32_t clock_limit;
 900        uint32_t max_dpm_level, min_dpm_level;
 901        int ret = 0;
 902
 903        if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type)) {
 904                switch (clk_type) {
 905                case SMU_MCLK:
 906                case SMU_UCLK:
 907                        clock_limit = smu->smu_table.boot_values.uclk;
 908                        break;
 909                case SMU_FCLK:
 910                        clock_limit = smu->smu_table.boot_values.fclk;
 911                        break;
 912                case SMU_GFXCLK:
 913                case SMU_SCLK:
 914                        clock_limit = smu->smu_table.boot_values.gfxclk;
 915                        break;
 916                case SMU_SOCCLK:
 917                        clock_limit = smu->smu_table.boot_values.socclk;
 918                        break;
 919                case SMU_VCLK:
 920                        clock_limit = smu->smu_table.boot_values.vclk;
 921                        break;
 922                case SMU_DCLK:
 923                        clock_limit = smu->smu_table.boot_values.dclk;
 924                        break;
 925                default:
 926                        clock_limit = 0;
 927                        break;
 928                }
 929
 930                /* clock in Mhz unit */
 931                if (min)
 932                        *min = clock_limit / 100;
 933                if (max)
 934                        *max = clock_limit / 100;
 935
 936                return 0;
 937        }
 938
 939        if (max) {
 940                switch (clk_type) {
 941                case SMU_GFXCLK:
 942                case SMU_SCLK:
 943                        *max = clk_table->MaxGfxClk;
 944                        break;
 945                case SMU_MCLK:
 946                case SMU_UCLK:
 947                case SMU_FCLK:
 948                        max_dpm_level = 0;
 949                        break;
 950                case SMU_SOCCLK:
 951                        max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1;
 952                        break;
 953                case SMU_VCLK:
 954                case SMU_DCLK:
 955                        max_dpm_level = clk_table->VcnClkLevelsEnabled - 1;
 956                        break;
 957                default:
 958                        ret = -EINVAL;
 959                        goto failed;
 960                }
 961
 962                if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
 963                        ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max);
 964                        if (ret)
 965                                goto failed;
 966                }
 967        }
 968
 969        if (min) {
 970                switch (clk_type) {
 971                case SMU_GFXCLK:
 972                case SMU_SCLK:
 973                        *min = clk_table->MinGfxClk;
 974                        break;
 975                case SMU_MCLK:
 976                case SMU_UCLK:
 977                case SMU_FCLK:
 978                        min_dpm_level = clk_table->NumDfPstatesEnabled - 1;
 979                        break;
 980                case SMU_SOCCLK:
 981                        min_dpm_level = 0;
 982                        break;
 983                case SMU_VCLK:
 984                case SMU_DCLK:
 985                        min_dpm_level = 0;
 986                        break;
 987                default:
 988                        ret = -EINVAL;
 989                        goto failed;
 990                }
 991
 992                if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
 993                        ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min);
 994                        if (ret)
 995                                goto failed;
 996                }
 997        }
 998
 999failed:
1000        return ret;
1001}
1002
1003static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu,
1004                                                        enum smu_clk_type clk_type,
1005                                                        uint32_t min,
1006                                                        uint32_t max)
1007{
1008        enum smu_message_type msg_set_min, msg_set_max;
1009        int ret = 0;
1010
1011        if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type))
1012                return -EINVAL;
1013
1014        switch (clk_type) {
1015        case SMU_GFXCLK:
1016        case SMU_SCLK:
1017                msg_set_min = SMU_MSG_SetHardMinGfxClk;
1018                msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
1019                break;
1020        case SMU_FCLK:
1021                msg_set_min = SMU_MSG_SetHardMinFclkByFreq;
1022                msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq;
1023                break;
1024        case SMU_SOCCLK:
1025                msg_set_min = SMU_MSG_SetHardMinSocclkByFreq;
1026                msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq;
1027                break;
1028        case SMU_VCLK:
1029        case SMU_DCLK:
1030                msg_set_min = SMU_MSG_SetHardMinVcn;
1031                msg_set_max = SMU_MSG_SetSoftMaxVcn;
1032                break;
1033        default:
1034                return -EINVAL;
1035        }
1036
1037        ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL);
1038        if (ret)
1039                goto out;
1040
1041        ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL);
1042        if (ret)
1043                goto out;
1044
1045out:
1046        return ret;
1047}
1048
1049static int yellow_carp_print_clk_levels(struct smu_context *smu,
1050                                enum smu_clk_type clk_type, char *buf)
1051{
1052        int i, size = 0, ret = 0;
1053        uint32_t cur_value = 0, value = 0, count = 0;
1054
1055        smu_cmn_get_sysfs_buf(&buf, &size);
1056
1057        switch (clk_type) {
1058        case SMU_OD_SCLK:
1059                size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
1060                size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
1061                (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
1062                size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
1063                (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
1064                break;
1065        case SMU_OD_RANGE:
1066                size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
1067                size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
1068                                                smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
1069                break;
1070        case SMU_SOCCLK:
1071        case SMU_VCLK:
1072        case SMU_DCLK:
1073        case SMU_MCLK:
1074        case SMU_FCLK:
1075                ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
1076                if (ret)
1077                        goto print_clk_out;
1078
1079                ret = yellow_carp_get_dpm_level_count(smu, clk_type, &count);
1080                if (ret)
1081                        goto print_clk_out;
1082
1083                for (i = 0; i < count; i++) {
1084                        ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, i, &value);
1085                        if (ret)
1086                                goto print_clk_out;
1087
1088                        size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
1089                                        cur_value == value ? "*" : "");
1090                }
1091                break;
1092        default:
1093                break;
1094        }
1095
1096print_clk_out:
1097        return size;
1098}
1099
1100static int yellow_carp_force_clk_levels(struct smu_context *smu,
1101                                enum smu_clk_type clk_type, uint32_t mask)
1102{
1103        uint32_t soft_min_level = 0, soft_max_level = 0;
1104        uint32_t min_freq = 0, max_freq = 0;
1105        int ret = 0;
1106
1107        soft_min_level = mask ? (ffs(mask) - 1) : 0;
1108        soft_max_level = mask ? (fls(mask) - 1) : 0;
1109
1110        switch (clk_type) {
1111        case SMU_SOCCLK:
1112        case SMU_FCLK:
1113        case SMU_VCLK:
1114        case SMU_DCLK:
1115                ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
1116                if (ret)
1117                        goto force_level_out;
1118
1119                ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
1120                if (ret)
1121                        goto force_level_out;
1122
1123                ret = yellow_carp_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
1124                if (ret)
1125                        goto force_level_out;
1126                break;
1127        default:
1128                ret = -EINVAL;
1129                break;
1130        }
1131
1132force_level_out:
1133        return ret;
1134}
1135
1136static int yellow_carp_set_performance_level(struct smu_context *smu,
1137                                                enum amd_dpm_forced_level level)
1138{
1139        struct amdgpu_device *adev = smu->adev;
1140        uint32_t sclk_min = 0, sclk_max = 0;
1141        uint32_t fclk_min = 0, fclk_max = 0;
1142        uint32_t socclk_min = 0, socclk_max = 0;
1143        int ret = 0;
1144
1145        switch (level) {
1146        case AMD_DPM_FORCED_LEVEL_HIGH:
1147                yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);
1148                yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max);
1149                yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max);
1150                sclk_min = sclk_max;
1151                fclk_min = fclk_max;
1152                socclk_min = socclk_max;
1153                break;
1154        case AMD_DPM_FORCED_LEVEL_LOW:
1155                yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);
1156                yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL);
1157                yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL);
1158                sclk_max = sclk_min;
1159                fclk_max = fclk_min;
1160                socclk_max = socclk_min;
1161                break;
1162        case AMD_DPM_FORCED_LEVEL_AUTO:
1163                yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);
1164                yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max);
1165                yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max);
1166                break;
1167        case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1168        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1169        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
1170        case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1171                /* Temporarily do nothing since the optimal clocks haven't been provided yet */
1172                break;
1173        case AMD_DPM_FORCED_LEVEL_MANUAL:
1174        case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1175                return 0;
1176        default:
1177                dev_err(adev->dev, "Invalid performance level %d\n", level);
1178                return -EINVAL;
1179        }
1180
1181        if (sclk_min && sclk_max) {
1182                ret = yellow_carp_set_soft_freq_limited_range(smu,
1183                                                            SMU_SCLK,
1184                                                            sclk_min,
1185                                                            sclk_max);
1186                if (ret)
1187                        return ret;
1188
1189                smu->gfx_actual_hard_min_freq = sclk_min;
1190                smu->gfx_actual_soft_max_freq = sclk_max;
1191        }
1192
1193        if (fclk_min && fclk_max) {
1194                ret = yellow_carp_set_soft_freq_limited_range(smu,
1195                                                            SMU_FCLK,
1196                                                            fclk_min,
1197                                                            fclk_max);
1198                if (ret)
1199                        return ret;
1200        }
1201
1202        if (socclk_min && socclk_max) {
1203                ret = yellow_carp_set_soft_freq_limited_range(smu,
1204                                                            SMU_SOCCLK,
1205                                                            socclk_min,
1206                                                            socclk_max);
1207                if (ret)
1208                        return ret;
1209        }
1210
1211        return ret;
1212}
1213
1214static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
1215{
1216        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
1217
1218        smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
1219        smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
1220        smu->gfx_actual_hard_min_freq = 0;
1221        smu->gfx_actual_soft_max_freq = 0;
1222
1223        return 0;
1224}
1225
1226static const struct pptable_funcs yellow_carp_ppt_funcs = {
1227        .check_fw_status = smu_v13_0_check_fw_status,
1228        .check_fw_version = smu_v13_0_check_fw_version,
1229        .init_smc_tables = yellow_carp_init_smc_tables,
1230        .fini_smc_tables = yellow_carp_fini_smc_tables,
1231        .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
1232        .system_features_control = yellow_carp_system_features_control,
1233        .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
1234        .send_smc_msg = smu_cmn_send_smc_msg,
1235        .dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable,
1236        .dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable,
1237        .set_default_dpm_table = yellow_carp_set_default_dpm_tables,
1238        .read_sensor = yellow_carp_read_sensor,
1239        .is_dpm_running = yellow_carp_is_dpm_running,
1240        .set_watermarks_table = yellow_carp_set_watermarks_table,
1241        .get_power_profile_mode = yellow_carp_get_power_profile_mode,
1242        .set_power_profile_mode = yellow_carp_set_power_profile_mode,
1243        .get_gpu_metrics = yellow_carp_get_gpu_metrics,
1244        .get_enabled_mask = smu_cmn_get_enabled_32_bits_mask,
1245        .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
1246        .set_driver_table_location = smu_v13_0_set_driver_table_location,
1247        .gfx_off_control = smu_v13_0_gfx_off_control,
1248        .post_init = yellow_carp_post_smu_init,
1249        .mode2_reset = yellow_carp_mode2_reset,
1250        .get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq,
1251        .od_edit_dpm_table = yellow_carp_od_edit_dpm_table,
1252        .print_clk_levels = yellow_carp_print_clk_levels,
1253        .force_clk_levels = yellow_carp_force_clk_levels,
1254        .set_performance_level = yellow_carp_set_performance_level,
1255        .set_fine_grain_gfx_freq_parameters = yellow_carp_set_fine_grain_gfx_freq_parameters,
1256};
1257
1258void yellow_carp_set_ppt_funcs(struct smu_context *smu)
1259{
1260        smu->ppt_funcs = &yellow_carp_ppt_funcs;
1261        smu->message_map = yellow_carp_message_map;
1262        smu->feature_map = yellow_carp_feature_mask_map;
1263        smu->table_map = yellow_carp_table_map;
1264        smu->workload_map = yellow_carp_workload_map;
1265        smu->is_apu = true;
1266}
1267