linux/drivers/gpu/drm/amd/powerplay/renoir_ppt.c
<<
>>
Prefs
   1/*
   2 * Copyright 2019 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#include "amdgpu.h"
  25#include "amdgpu_smu.h"
  26#include "smu_internal.h"
  27#include "smu_v12_0_ppsmc.h"
  28#include "smu12_driver_if.h"
  29#include "smu_v12_0.h"
  30#include "renoir_ppt.h"
  31
  32
  33#define CLK_MAP(clk, index) \
  34        [SMU_##clk] = {1, (index)}
  35
  36#define MSG_MAP(msg, index) \
  37        [SMU_MSG_##msg] = {1, (index)}
  38
  39#define TAB_MAP_VALID(tab) \
  40        [SMU_TABLE_##tab] = {1, TABLE_##tab}
  41
  42#define TAB_MAP_INVALID(tab) \
  43        [SMU_TABLE_##tab] = {0, TABLE_##tab}
  44
  45static struct smu_12_0_cmn2aisc_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = {
  46        MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage),
  47        MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion),
  48        MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion),
  49        MSG_MAP(PowerUpGfx,                     PPSMC_MSG_PowerUpGfx),
  50        MSG_MAP(AllowGfxOff,                    PPSMC_MSG_EnableGfxOff),
  51        MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisableGfxOff),
  52        MSG_MAP(PowerDownIspByTile,             PPSMC_MSG_PowerDownIspByTile),
  53        MSG_MAP(PowerUpIspByTile,               PPSMC_MSG_PowerUpIspByTile),
  54        MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn),
  55        MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn),
  56        MSG_MAP(PowerDownSdma,                  PPSMC_MSG_PowerDownSdma),
  57        MSG_MAP(PowerUpSdma,                    PPSMC_MSG_PowerUpSdma),
  58        MSG_MAP(SetHardMinIspclkByFreq,         PPSMC_MSG_SetHardMinIspclkByFreq),
  59        MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn),
  60        MSG_MAP(Spare1,                         PPSMC_MSG_spare1),
  61        MSG_MAP(Spare2,                         PPSMC_MSG_spare2),
  62        MSG_MAP(SetAllowFclkSwitch,             PPSMC_MSG_SetAllowFclkSwitch),
  63        MSG_MAP(SetMinVideoGfxclkFreq,          PPSMC_MSG_SetMinVideoGfxclkFreq),
  64        MSG_MAP(ActiveProcessNotify,            PPSMC_MSG_ActiveProcessNotify),
  65        MSG_MAP(SetCustomPolicy,                PPSMC_MSG_SetCustomPolicy),
  66        MSG_MAP(SetVideoFps,                    PPSMC_MSG_SetVideoFps),
  67        MSG_MAP(NumOfDisplays,                  PPSMC_MSG_SetDisplayCount),
  68        MSG_MAP(QueryPowerLimit,                PPSMC_MSG_QueryPowerLimit),
  69        MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh),
  70        MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow),
  71        MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram),
  72        MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu),
  73        MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset),
  74        MSG_MAP(SetGfxclkOverdriveByFreqVid,    PPSMC_MSG_SetGfxclkOverdriveByFreqVid),
  75        MSG_MAP(SetHardMinDcfclkByFreq,         PPSMC_MSG_SetHardMinDcfclkByFreq),
  76        MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq),
  77        MSG_MAP(ControlIgpuATS,                 PPSMC_MSG_ControlIgpuATS),
  78        MSG_MAP(SetMinVideoFclkFreq,            PPSMC_MSG_SetMinVideoFclkFreq),
  79        MSG_MAP(SetMinDeepSleepDcfclk,          PPSMC_MSG_SetMinDeepSleepDcfclk),
  80        MSG_MAP(ForcePowerDownGfx,              PPSMC_MSG_ForcePowerDownGfx),
  81        MSG_MAP(SetPhyclkVoltageByFreq,         PPSMC_MSG_SetPhyclkVoltageByFreq),
  82        MSG_MAP(SetDppclkVoltageByFreq,         PPSMC_MSG_SetDppclkVoltageByFreq),
  83        MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn),
  84        MSG_MAP(EnablePostCode,                 PPSMC_MSG_EnablePostCode),
  85        MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency),
  86        MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency),
  87        MSG_MAP(GetMinGfxclkFrequency,          PPSMC_MSG_GetMinGfxclkFrequency),
  88        MSG_MAP(GetMaxGfxclkFrequency,          PPSMC_MSG_GetMaxGfxclkFrequency),
  89        MSG_MAP(SoftReset,                      PPSMC_MSG_SoftReset),
  90        MSG_MAP(SetGfxCGPG,                     PPSMC_MSG_SetGfxCGPG),
  91        MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk),
  92        MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk),
  93        MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq),
  94        MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq),
  95        MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn),
  96        MSG_MAP(PowerGateMmHub,                 PPSMC_MSG_PowerGateMmHub),
  97        MSG_MAP(UpdatePmeRestore,               PPSMC_MSG_UpdatePmeRestore),
  98        MSG_MAP(GpuChangeState,                 PPSMC_MSG_GpuChangeState),
  99        MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage),
 100        MSG_MAP(ForceGfxContentSave,            PPSMC_MSG_ForceGfxContentSave),
 101        MSG_MAP(EnableTmdp48MHzRefclkPwrDown,   PPSMC_MSG_EnableTmdp48MHzRefclkPwrDown),
 102        MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg),
 103        MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg),
 104        MSG_MAP(PowerGateAtHub,                 PPSMC_MSG_PowerGateAtHub),
 105        MSG_MAP(SetSoftMinJpeg,                 PPSMC_MSG_SetSoftMinJpeg),
 106        MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq),
 107};
 108
 109static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = {
 110        CLK_MAP(GFXCLK, CLOCK_GFXCLK),
 111        CLK_MAP(SCLK,   CLOCK_GFXCLK),
 112        CLK_MAP(SOCCLK, CLOCK_SOCCLK),
 113        CLK_MAP(UCLK, CLOCK_FCLK),
 114        CLK_MAP(MCLK, CLOCK_FCLK),
 115};
 116
 117static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = {
 118        TAB_MAP_VALID(WATERMARKS),
 119        TAB_MAP_INVALID(CUSTOM_DPM),
 120        TAB_MAP_VALID(DPMCLOCKS),
 121        TAB_MAP_VALID(SMU_METRICS),
 122};
 123
 124static int renoir_get_smu_msg_index(struct smu_context *smc, uint32_t index)
 125{
 126        struct smu_12_0_cmn2aisc_mapping mapping;
 127
 128        if (index >= SMU_MSG_MAX_COUNT)
 129                return -EINVAL;
 130
 131        mapping = renoir_message_map[index];
 132        if (!(mapping.valid_mapping))
 133                return -EINVAL;
 134
 135        return mapping.map_to;
 136}
 137
 138static int renoir_get_smu_clk_index(struct smu_context *smc, uint32_t index)
 139{
 140        struct smu_12_0_cmn2aisc_mapping mapping;
 141
 142        if (index >= SMU_CLK_COUNT)
 143                return -EINVAL;
 144
 145        mapping = renoir_clk_map[index];
 146        if (!(mapping.valid_mapping)) {
 147                return -EINVAL;
 148        }
 149
 150        return mapping.map_to;
 151}
 152
 153static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index)
 154{
 155        struct smu_12_0_cmn2aisc_mapping mapping;
 156
 157        if (index >= SMU_TABLE_COUNT)
 158                return -EINVAL;
 159
 160        mapping = renoir_table_map[index];
 161        if (!(mapping.valid_mapping))
 162                return -EINVAL;
 163
 164        return mapping.map_to;
 165}
 166
 167static int renoir_get_metrics_table(struct smu_context *smu,
 168                                    SmuMetrics_t *metrics_table)
 169{
 170        struct smu_table_context *smu_table= &smu->smu_table;
 171        int ret = 0;
 172
 173        mutex_lock(&smu->metrics_lock);
 174        if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) {
 175                ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
 176                                (void *)smu_table->metrics_table, false);
 177                if (ret) {
 178                        pr_info("Failed to export SMU metrics table!\n");
 179                        mutex_unlock(&smu->metrics_lock);
 180                        return ret;
 181                }
 182                smu_table->metrics_time = jiffies;
 183        }
 184
 185        memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
 186        mutex_unlock(&smu->metrics_lock);
 187
 188        return ret;
 189}
 190
 191static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables)
 192{
 193        struct smu_table_context *smu_table = &smu->smu_table;
 194
 195        SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
 196                PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 197        SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
 198                PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 199        SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
 200                PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 201
 202        smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
 203        if (!smu_table->clocks_table)
 204                return -ENOMEM;
 205
 206        smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
 207        if (!smu_table->metrics_table)
 208                return -ENOMEM;
 209        smu_table->metrics_time = 0;
 210
 211        smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
 212        if (!smu_table->watermarks_table)
 213                return -ENOMEM;
 214
 215        return 0;
 216}
 217
 218/**
 219 * This interface just for getting uclk ultimate freq and should't introduce
 220 * other likewise function result in overmuch callback.
 221 */
 222static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
 223                                                uint32_t dpm_level, uint32_t *freq)
 224{
 225        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 226
 227        if (!clk_table || clk_type >= SMU_CLK_COUNT)
 228                return -EINVAL;
 229
 230        GET_DPM_CUR_FREQ(clk_table, clk_type, dpm_level, *freq);
 231
 232        return 0;
 233}
 234
 235static int renoir_print_clk_levels(struct smu_context *smu,
 236                        enum smu_clk_type clk_type, char *buf)
 237{
 238        int i, size = 0, ret = 0;
 239        uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
 240        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 241        SmuMetrics_t metrics;
 242        bool cur_value_match_level = false;
 243
 244        if (!clk_table || clk_type >= SMU_CLK_COUNT)
 245                return -EINVAL;
 246
 247        memset(&metrics, 0, sizeof(metrics));
 248
 249        ret = renoir_get_metrics_table(smu, &metrics);
 250        if (ret)
 251                return ret;
 252
 253        switch (clk_type) {
 254        case SMU_GFXCLK:
 255        case SMU_SCLK:
 256                /* retirve table returned paramters unit is MHz */
 257                cur_value = metrics.ClockFrequency[CLOCK_GFXCLK];
 258                ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min, &max, false);
 259                if (!ret) {
 260                        /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */
 261                        if (cur_value  == max)
 262                                i = 2;
 263                        else if (cur_value == min)
 264                                i = 0;
 265                        else
 266                                i = 1;
 267
 268                        size += sprintf(buf + size, "0: %uMhz %s\n", min,
 269                                        i == 0 ? "*" : "");
 270                        size += sprintf(buf + size, "1: %uMhz %s\n",
 271                                        i == 1 ? cur_value : RENOIR_UMD_PSTATE_GFXCLK,
 272                                        i == 1 ? "*" : "");
 273                        size += sprintf(buf + size, "2: %uMhz %s\n", max,
 274                                        i == 2 ? "*" : "");
 275                }
 276                return size;
 277        case SMU_SOCCLK:
 278                count = NUM_SOCCLK_DPM_LEVELS;
 279                cur_value = metrics.ClockFrequency[CLOCK_SOCCLK];
 280                break;
 281        case SMU_MCLK:
 282                count = NUM_MEMCLK_DPM_LEVELS;
 283                cur_value = metrics.ClockFrequency[CLOCK_FCLK];
 284                break;
 285        case SMU_DCEFCLK:
 286                count = NUM_DCFCLK_DPM_LEVELS;
 287                cur_value = metrics.ClockFrequency[CLOCK_DCFCLK];
 288                break;
 289        case SMU_FCLK:
 290                count = NUM_FCLK_DPM_LEVELS;
 291                cur_value = metrics.ClockFrequency[CLOCK_FCLK];
 292                break;
 293        default:
 294                return -EINVAL;
 295        }
 296
 297        for (i = 0; i < count; i++) {
 298                GET_DPM_CUR_FREQ(clk_table, clk_type, i, value);
 299                if (!value)
 300                        continue;
 301                size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
 302                                cur_value == value ? "*" : "");
 303                if (cur_value == value)
 304                        cur_value_match_level = true;
 305        }
 306
 307        if (!cur_value_match_level)
 308                size += sprintf(buf + size, "   %uMhz *\n", cur_value);
 309
 310        return size;
 311}
 312
 313static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context *smu)
 314{
 315        enum amd_pm_state_type pm_type;
 316        struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
 317
 318        if (!smu_dpm_ctx->dpm_context ||
 319            !smu_dpm_ctx->dpm_current_power_state)
 320                return -EINVAL;
 321
 322        switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) {
 323        case SMU_STATE_UI_LABEL_BATTERY:
 324                pm_type = POWER_STATE_TYPE_BATTERY;
 325                break;
 326        case SMU_STATE_UI_LABEL_BALLANCED:
 327                pm_type = POWER_STATE_TYPE_BALANCED;
 328                break;
 329        case SMU_STATE_UI_LABEL_PERFORMANCE:
 330                pm_type = POWER_STATE_TYPE_PERFORMANCE;
 331                break;
 332        default:
 333                if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT)
 334                        pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
 335                else
 336                        pm_type = POWER_STATE_TYPE_DEFAULT;
 337                break;
 338        }
 339
 340        return pm_type;
 341}
 342
 343static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
 344{
 345        struct smu_power_context *smu_power = &smu->smu_power;
 346        struct smu_power_gate *power_gate = &smu_power->power_gate;
 347        int ret = 0;
 348
 349        if (enable) {
 350                /* vcn dpm on is a prerequisite for vcn power gate messages */
 351                if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
 352                        ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL);
 353                        if (ret)
 354                                return ret;
 355                }
 356                power_gate->vcn_gated = false;
 357        } else {
 358                if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
 359                        ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL);
 360                        if (ret)
 361                                return ret;
 362                }
 363                power_gate->vcn_gated = true;
 364        }
 365
 366        return ret;
 367}
 368
 369static int renoir_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
 370{
 371        struct smu_power_context *smu_power = &smu->smu_power;
 372        struct smu_power_gate *power_gate = &smu_power->power_gate;
 373        int ret = 0;
 374
 375        if (enable) {
 376                if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
 377                        ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL);
 378                        if (ret)
 379                                return ret;
 380                }
 381                power_gate->jpeg_gated = false;
 382        } else {
 383                if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
 384                        ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0, NULL);
 385                        if (ret)
 386                                return ret;
 387                }
 388                power_gate->jpeg_gated = true;
 389        }
 390
 391        return ret;
 392}
 393
 394static int renoir_get_current_clk_freq_by_table(struct smu_context *smu,
 395                                       enum smu_clk_type clk_type,
 396                                       uint32_t *value)
 397{
 398        int ret = 0, clk_id = 0;
 399        SmuMetrics_t metrics;
 400
 401        ret = renoir_get_metrics_table(smu, &metrics);
 402        if (ret)
 403                return ret;
 404
 405        clk_id = smu_clk_get_index(smu, clk_type);
 406        if (clk_id < 0)
 407                return clk_id;
 408
 409        *value = metrics.ClockFrequency[clk_id];
 410
 411        return ret;
 412}
 413
 414static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest)
 415{
 416        int ret = 0, i = 0;
 417        uint32_t min_freq, max_freq, force_freq;
 418        enum smu_clk_type clk_type;
 419
 420        enum smu_clk_type clks[] = {
 421                SMU_GFXCLK,
 422                SMU_MCLK,
 423                SMU_SOCCLK,
 424        };
 425
 426        for (i = 0; i < ARRAY_SIZE(clks); i++) {
 427                clk_type = clks[i];
 428                ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
 429                if (ret)
 430                        return ret;
 431
 432                force_freq = highest ? max_freq : min_freq;
 433                ret = smu_set_soft_freq_range(smu, clk_type, force_freq, force_freq, false);
 434                if (ret)
 435                        return ret;
 436        }
 437
 438        return ret;
 439}
 440
 441static int renoir_unforce_dpm_levels(struct smu_context *smu) {
 442
 443        int ret = 0, i = 0;
 444        uint32_t min_freq, max_freq;
 445        enum smu_clk_type clk_type;
 446
 447        struct clk_feature_map {
 448                enum smu_clk_type clk_type;
 449                uint32_t        feature;
 450        } clk_feature_map[] = {
 451                {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT},
 452                {SMU_MCLK,   SMU_FEATURE_DPM_UCLK_BIT},
 453                {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
 454        };
 455
 456        for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
 457                if (!smu_feature_is_enabled(smu, clk_feature_map[i].feature))
 458                    continue;
 459
 460                clk_type = clk_feature_map[i].clk_type;
 461
 462                ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
 463                if (ret)
 464                        return ret;
 465
 466                ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq, false);
 467                if (ret)
 468                        return ret;
 469        }
 470
 471        return ret;
 472}
 473
 474static int renoir_get_gpu_temperature(struct smu_context *smu, uint32_t *value)
 475{
 476        int ret = 0;
 477        SmuMetrics_t metrics;
 478
 479        if (!value)
 480                return -EINVAL;
 481
 482        ret = renoir_get_metrics_table(smu, &metrics);
 483        if (ret)
 484                return ret;
 485
 486        *value = (metrics.GfxTemperature / 100) *
 487                SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
 488
 489        return 0;
 490}
 491
 492static int renoir_get_current_activity_percent(struct smu_context *smu,
 493                                               enum amd_pp_sensors sensor,
 494                                               uint32_t *value)
 495{
 496        int ret = 0;
 497        SmuMetrics_t metrics;
 498
 499        if (!value)
 500                return -EINVAL;
 501
 502        ret = renoir_get_metrics_table(smu, &metrics);
 503        if (ret)
 504                return ret;
 505
 506        switch (sensor) {
 507        case AMDGPU_PP_SENSOR_GPU_LOAD:
 508                *value = metrics.AverageGfxActivity / 100;
 509                break;
 510        default:
 511                pr_err("Invalid sensor for retrieving clock activity\n");
 512                return -EINVAL;
 513        }
 514
 515        return 0;
 516}
 517
 518static int renoir_get_workload_type(struct smu_context *smu, uint32_t profile)
 519{
 520
 521        uint32_t  pplib_workload = 0;
 522
 523        switch (profile) {
 524        case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
 525                pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
 526                break;
 527        case PP_SMC_POWER_PROFILE_CUSTOM:
 528                pplib_workload = WORKLOAD_PPLIB_COUNT;
 529                break;
 530        case PP_SMC_POWER_PROFILE_VIDEO:
 531                pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
 532                break;
 533        case PP_SMC_POWER_PROFILE_VR:
 534                pplib_workload = WORKLOAD_PPLIB_VR_BIT;
 535                break;
 536        case PP_SMC_POWER_PROFILE_COMPUTE:
 537                pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
 538                break;
 539        default:
 540                return -EINVAL;
 541        }
 542
 543        return pplib_workload;
 544}
 545
 546static int renoir_get_profiling_clk_mask(struct smu_context *smu,
 547                                         enum amd_dpm_forced_level level,
 548                                         uint32_t *sclk_mask,
 549                                         uint32_t *mclk_mask,
 550                                         uint32_t *soc_mask)
 551{
 552
 553        if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
 554                if (sclk_mask)
 555                        *sclk_mask = 0;
 556        } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
 557                if (mclk_mask)
 558                        *mclk_mask = 0;
 559        } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
 560                if(sclk_mask)
 561                        /* The sclk as gfxclk and has three level about max/min/current */
 562                        *sclk_mask = 3 - 1;
 563
 564                if(mclk_mask)
 565                        *mclk_mask = NUM_MEMCLK_DPM_LEVELS - 1;
 566
 567                if(soc_mask)
 568                        *soc_mask = NUM_SOCCLK_DPM_LEVELS - 1;
 569        }
 570
 571        return 0;
 572}
 573
 574/**
 575 * This interface get dpm clock table for dc
 576 */
 577static int renoir_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
 578{
 579        DpmClocks_t *table = smu->smu_table.clocks_table;
 580        int i;
 581
 582        if (!clock_table || !table)
 583                return -EINVAL;
 584
 585        for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) {
 586                clock_table->DcfClocks[i].Freq = table->DcfClocks[i].Freq;
 587                clock_table->DcfClocks[i].Vol = table->DcfClocks[i].Vol;
 588        }
 589
 590        for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
 591                clock_table->SocClocks[i].Freq = table->SocClocks[i].Freq;
 592                clock_table->SocClocks[i].Vol = table->SocClocks[i].Vol;
 593        }
 594
 595        for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
 596                clock_table->FClocks[i].Freq = table->FClocks[i].Freq;
 597                clock_table->FClocks[i].Vol = table->FClocks[i].Vol;
 598        }
 599
 600        for (i = 0; i<  NUM_MEMCLK_DPM_LEVELS; i++) {
 601                clock_table->MemClocks[i].Freq = table->MemClocks[i].Freq;
 602                clock_table->MemClocks[i].Vol = table->MemClocks[i].Vol;
 603        }
 604
 605        return 0;
 606}
 607
 608static int renoir_force_clk_levels(struct smu_context *smu,
 609                                   enum smu_clk_type clk_type, uint32_t mask)
 610{
 611
 612        int ret = 0 ;
 613        uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0;
 614        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 615
 616        soft_min_level = mask ? (ffs(mask) - 1) : 0;
 617        soft_max_level = mask ? (fls(mask) - 1) : 0;
 618
 619        switch (clk_type) {
 620        case SMU_GFXCLK:
 621        case SMU_SCLK:
 622                if (soft_min_level > 2 || soft_max_level > 2) {
 623                        pr_info("Currently sclk only support 3 levels on APU\n");
 624                        return -EINVAL;
 625                }
 626
 627                ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min_freq, &max_freq, false);
 628                if (ret)
 629                        return ret;
 630                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
 631                                        soft_max_level == 0 ? min_freq :
 632                                        soft_max_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : max_freq,
 633                                        NULL);
 634                if (ret)
 635                        return ret;
 636                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
 637                                        soft_min_level == 2 ? max_freq :
 638                                        soft_min_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : min_freq,
 639                                        NULL);
 640                if (ret)
 641                        return ret;
 642                break;
 643        case SMU_SOCCLK:
 644                GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq);
 645                GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq);
 646                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max_freq, NULL);
 647                if (ret)
 648                        return ret;
 649                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min_freq, NULL);
 650                if (ret)
 651                        return ret;
 652                break;
 653        case SMU_MCLK:
 654        case SMU_FCLK:
 655                GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq);
 656                GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq);
 657                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max_freq, NULL);
 658                if (ret)
 659                        return ret;
 660                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min_freq, NULL);
 661                if (ret)
 662                        return ret;
 663                break;
 664        default:
 665                break;
 666        }
 667
 668        return ret;
 669}
 670
 671static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
 672{
 673        int workload_type, ret;
 674        uint32_t profile_mode = input[size];
 675
 676        if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
 677                pr_err("Invalid power profile mode %d\n", smu->power_profile_mode);
 678                return -EINVAL;
 679        }
 680
 681        /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
 682        workload_type = smu_workload_get_type(smu, smu->power_profile_mode);
 683        if (workload_type < 0) {
 684                /*
 685                 * TODO: If some case need switch to powersave/default power mode
 686                 * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
 687                 */
 688                pr_err_once("Unsupported power profile mode %d on RENOIR\n",smu->power_profile_mode);
 689                return -EINVAL;
 690        }
 691
 692        ret = smu_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
 693                                    1 << workload_type,
 694                                    NULL);
 695        if (ret) {
 696                pr_err_once("Fail to set workload type %d\n", workload_type);
 697                return ret;
 698        }
 699
 700        smu->power_profile_mode = profile_mode;
 701
 702        return 0;
 703}
 704
 705static int renoir_set_peak_clock_by_device(struct smu_context *smu)
 706{
 707        int ret = 0;
 708        uint32_t sclk_freq = 0, uclk_freq = 0;
 709
 710        ret = smu_get_dpm_freq_range(smu, SMU_SCLK, NULL, &sclk_freq, false);
 711        if (ret)
 712                return ret;
 713
 714        ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq, false);
 715        if (ret)
 716                return ret;
 717
 718        ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &uclk_freq, false);
 719        if (ret)
 720                return ret;
 721
 722        ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq, false);
 723        if (ret)
 724                return ret;
 725
 726        return ret;
 727}
 728
 729static int renoir_set_performance_level(struct smu_context *smu,
 730                                        enum amd_dpm_forced_level level)
 731{
 732        int ret = 0;
 733        uint32_t sclk_mask, mclk_mask, soc_mask;
 734
 735        switch (level) {
 736        case AMD_DPM_FORCED_LEVEL_HIGH:
 737                ret = smu_force_dpm_limit_value(smu, true);
 738                break;
 739        case AMD_DPM_FORCED_LEVEL_LOW:
 740                ret = smu_force_dpm_limit_value(smu, false);
 741                break;
 742        case AMD_DPM_FORCED_LEVEL_AUTO:
 743        case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
 744                ret = smu_unforce_dpm_levels(smu);
 745                break;
 746        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
 747        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
 748                ret = smu_get_profiling_clk_mask(smu, level,
 749                                                 &sclk_mask,
 750                                                 &mclk_mask,
 751                                                 &soc_mask);
 752                if (ret)
 753                        return ret;
 754                smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask, false);
 755                smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask, false);
 756                smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask, false);
 757                break;
 758        case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
 759                ret = renoir_set_peak_clock_by_device(smu);
 760                break;
 761        case AMD_DPM_FORCED_LEVEL_MANUAL:
 762        case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
 763        default:
 764                break;
 765        }
 766        return ret;
 767}
 768
 769/* save watermark settings into pplib smu structure,
 770 * also pass data to smu controller
 771 */
 772static int renoir_set_watermarks_table(
 773                struct smu_context *smu,
 774                void *watermarks,
 775                struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges)
 776{
 777        int i;
 778        int ret = 0;
 779        Watermarks_t *table = watermarks;
 780
 781        if (!table || !clock_ranges)
 782                return -EINVAL;
 783
 784        if (clock_ranges->num_wm_dmif_sets > 4 ||
 785                        clock_ranges->num_wm_mcif_sets > 4)
 786                return -EINVAL;
 787
 788        /* save into smu->smu_table.tables[SMU_TABLE_WATERMARKS]->cpu_addr*/
 789        for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
 790                table->WatermarkRow[WM_DCFCLK][i].MinClock =
 791                        cpu_to_le16((uint16_t)
 792                        (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz));
 793                table->WatermarkRow[WM_DCFCLK][i].MaxClock =
 794                        cpu_to_le16((uint16_t)
 795                        (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz));
 796                table->WatermarkRow[WM_DCFCLK][i].MinMclk =
 797                        cpu_to_le16((uint16_t)
 798                        (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz));
 799                table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
 800                        cpu_to_le16((uint16_t)
 801                        (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz));
 802                table->WatermarkRow[WM_DCFCLK][i].WmSetting = (uint8_t)
 803                                clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
 804        }
 805
 806        for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
 807                table->WatermarkRow[WM_SOCCLK][i].MinClock =
 808                        cpu_to_le16((uint16_t)
 809                        (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz));
 810                table->WatermarkRow[WM_SOCCLK][i].MaxClock =
 811                        cpu_to_le16((uint16_t)
 812                        (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz));
 813                table->WatermarkRow[WM_SOCCLK][i].MinMclk =
 814                        cpu_to_le16((uint16_t)
 815                        (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz));
 816                table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
 817                        cpu_to_le16((uint16_t)
 818                        (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz));
 819                table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t)
 820                                clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
 821        }
 822
 823        smu->watermarks_bitmap |= WATERMARKS_EXIST;
 824
 825        /* pass data to smu controller */
 826        if (!(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
 827                ret = smu_write_watermarks_table(smu);
 828                if (ret) {
 829                        pr_err("Failed to update WMTABLE!");
 830                        return ret;
 831                }
 832                smu->watermarks_bitmap |= WATERMARKS_LOADED;
 833        }
 834
 835        return 0;
 836}
 837
 838static int renoir_get_power_profile_mode(struct smu_context *smu,
 839                                           char *buf)
 840{
 841        static const char *profile_name[] = {
 842                                        "BOOTUP_DEFAULT",
 843                                        "3D_FULL_SCREEN",
 844                                        "POWER_SAVING",
 845                                        "VIDEO",
 846                                        "VR",
 847                                        "COMPUTE",
 848                                        "CUSTOM"};
 849        uint32_t i, size = 0;
 850        int16_t workload_type = 0;
 851
 852        if (!buf)
 853                return -EINVAL;
 854
 855        for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
 856                /*
 857                 * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
 858                 * Not all profile modes are supported on arcturus.
 859                 */
 860                workload_type = smu_workload_get_type(smu, i);
 861                if (workload_type < 0)
 862                        continue;
 863
 864                size += sprintf(buf + size, "%2d %14s%s\n",
 865                        i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
 866        }
 867
 868        return size;
 869}
 870
 871static int renoir_read_sensor(struct smu_context *smu,
 872                                 enum amd_pp_sensors sensor,
 873                                 void *data, uint32_t *size)
 874{
 875        int ret = 0;
 876
 877        if (!data || !size)
 878                return -EINVAL;
 879
 880        mutex_lock(&smu->sensor_lock);
 881        switch (sensor) {
 882        case AMDGPU_PP_SENSOR_GPU_LOAD:
 883                ret = renoir_get_current_activity_percent(smu, sensor, (uint32_t *)data);
 884                *size = 4;
 885                break;
 886        case AMDGPU_PP_SENSOR_GPU_TEMP:
 887                ret = renoir_get_gpu_temperature(smu, (uint32_t *)data);
 888                *size = 4;
 889                break;
 890        default:
 891                ret = smu_v12_0_read_sensor(smu, sensor, data, size);
 892        }
 893        mutex_unlock(&smu->sensor_lock);
 894
 895        return ret;
 896}
 897
 898static bool renoir_is_dpm_running(struct smu_context *smu)
 899{
 900        struct amdgpu_device *adev = smu->adev;
 901
 902        /*
 903         * Until now, the pmfw hasn't exported the interface of SMU
 904         * feature mask to APU SKU so just force on all the feature
 905         * at early initial stage.
 906         */
 907        if (adev->in_suspend)
 908                return false;
 909        else
 910                return true;
 911
 912}
 913
 914static const struct pptable_funcs renoir_ppt_funcs = {
 915        .get_smu_msg_index = renoir_get_smu_msg_index,
 916        .get_smu_clk_index = renoir_get_smu_clk_index,
 917        .get_smu_table_index = renoir_get_smu_table_index,
 918        .tables_init = renoir_tables_init,
 919        .set_power_state = NULL,
 920        .get_dpm_clk_limited = renoir_get_dpm_clk_limited,
 921        .print_clk_levels = renoir_print_clk_levels,
 922        .get_current_power_state = renoir_get_current_power_state,
 923        .dpm_set_uvd_enable = renoir_dpm_set_uvd_enable,
 924        .dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable,
 925        .get_current_clk_freq_by_table = renoir_get_current_clk_freq_by_table,
 926        .force_dpm_limit_value = renoir_force_dpm_limit_value,
 927        .unforce_dpm_levels = renoir_unforce_dpm_levels,
 928        .get_workload_type = renoir_get_workload_type,
 929        .get_profiling_clk_mask = renoir_get_profiling_clk_mask,
 930        .force_clk_levels = renoir_force_clk_levels,
 931        .set_power_profile_mode = renoir_set_power_profile_mode,
 932        .set_performance_level = renoir_set_performance_level,
 933        .get_dpm_clock_table = renoir_get_dpm_clock_table,
 934        .set_watermarks_table = renoir_set_watermarks_table,
 935        .get_power_profile_mode = renoir_get_power_profile_mode,
 936        .read_sensor = renoir_read_sensor,
 937        .check_fw_status = smu_v12_0_check_fw_status,
 938        .check_fw_version = smu_v12_0_check_fw_version,
 939        .powergate_sdma = smu_v12_0_powergate_sdma,
 940        .powergate_vcn = smu_v12_0_powergate_vcn,
 941        .powergate_jpeg = smu_v12_0_powergate_jpeg,
 942        .send_smc_msg_with_param = smu_v12_0_send_msg_with_param,
 943        .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg,
 944        .gfx_off_control = smu_v12_0_gfx_off_control,
 945        .init_smc_tables = smu_v12_0_init_smc_tables,
 946        .fini_smc_tables = smu_v12_0_fini_smc_tables,
 947        .populate_smc_tables = smu_v12_0_populate_smc_tables,
 948        .get_enabled_mask = smu_v12_0_get_enabled_mask,
 949        .get_current_clk_freq = smu_v12_0_get_current_clk_freq,
 950        .get_dpm_ultimate_freq = smu_v12_0_get_dpm_ultimate_freq,
 951        .mode2_reset = smu_v12_0_mode2_reset,
 952        .set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range,
 953        .set_driver_table_location = smu_v12_0_set_driver_table_location,
 954        .is_dpm_running = renoir_is_dpm_running,
 955};
 956
 957void renoir_set_ppt_funcs(struct smu_context *smu)
 958{
 959        smu->ppt_funcs = &renoir_ppt_funcs;
 960        smu->smc_driver_if_version = SMU12_DRIVER_IF_VERSION;
 961        smu->is_apu = true;
 962}
 963