linux/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
<<
>>
Prefs
   1/*
   2 * Copyright 2021 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_v11_0.h"
  29#include "smu11_driver_if_cyan_skillfish.h"
  30#include "cyan_skillfish_ppt.h"
  31#include "smu_v11_8_ppsmc.h"
  32#include "smu_v11_8_pmfw.h"
  33#include "smu_cmn.h"
  34#include "soc15_common.h"
  35
  36/*
  37 * DO NOT use these for err/warn/info/debug messages.
  38 * Use dev_err, dev_warn, dev_info and dev_dbg instead.
  39 * They are more MGPU friendly.
  40 */
  41
  42#undef pr_err
  43#undef pr_warn
  44#undef pr_info
  45#undef pr_debug
  46
  47/* unit: MHz */
  48#define CYAN_SKILLFISH_SCLK_MIN                 1000
  49#define CYAN_SKILLFISH_SCLK_MAX                 2000
  50
  51/* unit: mV */
  52#define CYAN_SKILLFISH_VDDC_MIN                 700
  53#define CYAN_SKILLFISH_VDDC_MAX                 1129
  54#define CYAN_SKILLFISH_VDDC_MAGIC                       5118 // 0x13fe
  55
  56static struct gfx_user_settings {
  57        uint32_t sclk;
  58        uint32_t vddc;
  59} cyan_skillfish_user_settings;
  60
  61static uint32_t cyan_skillfish_sclk_default;
  62
  63#define FEATURE_MASK(feature) (1ULL << feature)
  64#define SMC_DPM_FEATURE ( \
  65        FEATURE_MASK(FEATURE_FCLK_DPM_BIT)      |       \
  66        FEATURE_MASK(FEATURE_SOC_DPM_BIT)       |       \
  67        FEATURE_MASK(FEATURE_GFX_DPM_BIT))
  68
  69static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT] = {
  70        MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,                  0),
  71        MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,                0),
  72        MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,           0),
  73        MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverTableDramAddrHigh,   0),
  74        MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverTableDramAddrLow,    0),
  75        MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,        0),
  76        MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,        0),
  77        MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,        0),
  78        MSG_MAP(RequestGfxclk,                  PPSMC_MSG_RequestGfxclk,                0),
  79        MSG_MAP(ForceGfxVid,                    PPSMC_MSG_ForceGfxVid,                  0),
  80        MSG_MAP(UnforceGfxVid,                  PPSMC_MSG_UnforceGfxVid,                0),
  81};
  82
  83static struct cmn2asic_mapping cyan_skillfish_table_map[SMU_TABLE_COUNT] = {
  84        TAB_MAP_VALID(SMU_METRICS),
  85};
  86
  87static int cyan_skillfish_tables_init(struct smu_context *smu)
  88{
  89        struct smu_table_context *smu_table = &smu->smu_table;
  90        struct smu_table *tables = smu_table->tables;
  91
  92        SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS,
  93                                sizeof(SmuMetrics_t),
  94                                PAGE_SIZE,
  95                                AMDGPU_GEM_DOMAIN_VRAM);
  96
  97        smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
  98        if (!smu_table->metrics_table)
  99                goto err0_out;
 100
 101        smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2);
 102        smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
 103        if (!smu_table->gpu_metrics_table)
 104                goto err1_out;
 105
 106        smu_table->metrics_time = 0;
 107
 108        return 0;
 109
 110err1_out:
 111        smu_table->gpu_metrics_table_size = 0;
 112        kfree(smu_table->metrics_table);
 113err0_out:
 114        return -ENOMEM;
 115}
 116
 117static int cyan_skillfish_init_smc_tables(struct smu_context *smu)
 118{
 119        int ret = 0;
 120
 121        ret = cyan_skillfish_tables_init(smu);
 122        if (ret)
 123                return ret;
 124
 125        return smu_v11_0_init_smc_tables(smu);
 126}
 127
 128static int cyan_skillfish_finit_smc_tables(struct smu_context *smu)
 129{
 130        struct smu_table_context *smu_table = &smu->smu_table;
 131
 132        kfree(smu_table->metrics_table);
 133        smu_table->metrics_table = NULL;
 134
 135        kfree(smu_table->gpu_metrics_table);
 136        smu_table->gpu_metrics_table = NULL;
 137        smu_table->gpu_metrics_table_size = 0;
 138
 139        smu_table->metrics_time = 0;
 140
 141        return 0;
 142}
 143
 144static int
 145cyan_skillfish_get_smu_metrics_data(struct smu_context *smu,
 146                                        MetricsMember_t member,
 147                                        uint32_t *value)
 148{
 149        struct smu_table_context *smu_table = &smu->smu_table;
 150        SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
 151        int ret = 0;
 152
 153        mutex_lock(&smu->metrics_lock);
 154
 155        ret = smu_cmn_get_metrics_table_locked(smu, NULL, false);
 156        if (ret) {
 157                mutex_unlock(&smu->metrics_lock);
 158                return ret;
 159        }
 160
 161        switch (member) {
 162        case METRICS_CURR_GFXCLK:
 163                *value = metrics->Current.GfxclkFrequency;
 164                break;
 165        case METRICS_CURR_SOCCLK:
 166                *value = metrics->Current.SocclkFrequency;
 167                break;
 168        case METRICS_CURR_VCLK:
 169                *value = metrics->Current.VclkFrequency;
 170                break;
 171        case METRICS_CURR_DCLK:
 172                *value = metrics->Current.DclkFrequency;
 173                break;
 174        case METRICS_CURR_UCLK:
 175                *value = metrics->Current.MemclkFrequency;
 176                break;
 177        case METRICS_AVERAGE_SOCKETPOWER:
 178                *value = (metrics->Current.CurrentSocketPower << 8) /
 179                                1000;
 180                break;
 181        case METRICS_TEMPERATURE_EDGE:
 182                *value = metrics->Current.GfxTemperature / 100 *
 183                                SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
 184                break;
 185        case METRICS_TEMPERATURE_HOTSPOT:
 186                *value = metrics->Current.SocTemperature / 100 *
 187                                SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
 188                break;
 189        case METRICS_VOLTAGE_VDDSOC:
 190                *value = metrics->Current.Voltage[0];
 191                break;
 192        case METRICS_VOLTAGE_VDDGFX:
 193                *value = metrics->Current.Voltage[1];
 194                break;
 195        case METRICS_THROTTLER_STATUS:
 196                *value = metrics->Current.ThrottlerStatus;
 197                break;
 198        default:
 199                *value = UINT_MAX;
 200                break;
 201        }
 202
 203        mutex_unlock(&smu->metrics_lock);
 204
 205        return ret;
 206}
 207
 208static int cyan_skillfish_read_sensor(struct smu_context *smu,
 209                                        enum amd_pp_sensors sensor,
 210                                        void *data,
 211                                        uint32_t *size)
 212{
 213        int ret = 0;
 214
 215        if (!data || !size)
 216                return -EINVAL;
 217
 218        mutex_lock(&smu->sensor_lock);
 219
 220        switch (sensor) {
 221        case AMDGPU_PP_SENSOR_GFX_SCLK:
 222                ret = cyan_skillfish_get_smu_metrics_data(smu,
 223                                                   METRICS_CURR_GFXCLK,
 224                                                   (uint32_t *)data);
 225                *(uint32_t *)data *= 100;
 226                *size = 4;
 227                break;
 228        case AMDGPU_PP_SENSOR_GFX_MCLK:
 229                ret = cyan_skillfish_get_smu_metrics_data(smu,
 230                                                   METRICS_CURR_UCLK,
 231                                                   (uint32_t *)data);
 232                *(uint32_t *)data *= 100;
 233                *size = 4;
 234                break;
 235        case AMDGPU_PP_SENSOR_GPU_POWER:
 236                ret = cyan_skillfish_get_smu_metrics_data(smu,
 237                                                   METRICS_AVERAGE_SOCKETPOWER,
 238                                                   (uint32_t *)data);
 239                *size = 4;
 240                break;
 241        case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
 242                ret = cyan_skillfish_get_smu_metrics_data(smu,
 243                                                   METRICS_TEMPERATURE_HOTSPOT,
 244                                                   (uint32_t *)data);
 245                *size = 4;
 246                break;
 247        case AMDGPU_PP_SENSOR_EDGE_TEMP:
 248                ret = cyan_skillfish_get_smu_metrics_data(smu,
 249                                                   METRICS_TEMPERATURE_EDGE,
 250                                                   (uint32_t *)data);
 251                *size = 4;
 252                break;
 253        case AMDGPU_PP_SENSOR_VDDNB:
 254                ret = cyan_skillfish_get_smu_metrics_data(smu,
 255                                                   METRICS_VOLTAGE_VDDSOC,
 256                                                   (uint32_t *)data);
 257                *size = 4;
 258                break;
 259        case AMDGPU_PP_SENSOR_VDDGFX:
 260                ret = cyan_skillfish_get_smu_metrics_data(smu,
 261                                                   METRICS_VOLTAGE_VDDGFX,
 262                                                   (uint32_t *)data);
 263                *size = 4;
 264                break;
 265        default:
 266                ret = -EOPNOTSUPP;
 267                break;
 268        }
 269
 270        mutex_unlock(&smu->sensor_lock);
 271
 272        return ret;
 273}
 274
 275static int cyan_skillfish_get_current_clk_freq(struct smu_context *smu,
 276                                                enum smu_clk_type clk_type,
 277                                                uint32_t *value)
 278{
 279        MetricsMember_t member_type;
 280
 281        switch (clk_type) {
 282        case SMU_GFXCLK:
 283        case SMU_SCLK:
 284                member_type = METRICS_CURR_GFXCLK;
 285                break;
 286        case SMU_FCLK:
 287        case SMU_MCLK:
 288                member_type = METRICS_CURR_UCLK;
 289                break;
 290        case SMU_SOCCLK:
 291                member_type = METRICS_CURR_SOCCLK;
 292                break;
 293        case SMU_VCLK:
 294                member_type = METRICS_CURR_VCLK;
 295                break;
 296        case SMU_DCLK:
 297                member_type = METRICS_CURR_DCLK;
 298                break;
 299        default:
 300                return -EINVAL;
 301        }
 302
 303        return cyan_skillfish_get_smu_metrics_data(smu, member_type, value);
 304}
 305
 306static int cyan_skillfish_print_clk_levels(struct smu_context *smu,
 307                                        enum smu_clk_type clk_type,
 308                                        char *buf)
 309{
 310        int ret = 0, size = 0;
 311        uint32_t cur_value = 0;
 312        int i;
 313
 314        smu_cmn_get_sysfs_buf(&buf, &size);
 315
 316        switch (clk_type) {
 317        case SMU_OD_SCLK:
 318                ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cur_value);
 319                if (ret)
 320                        return ret;
 321                size += sysfs_emit_at(buf, size,"%s:\n", "OD_SCLK");
 322                size += sysfs_emit_at(buf, size, "0: %uMhz *\n", cur_value);
 323                break;
 324        case SMU_OD_VDDC_CURVE:
 325                ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_VOLTAGE_VDDGFX, &cur_value);
 326                if (ret)
 327                        return ret;
 328                size += sysfs_emit_at(buf, size,"%s:\n", "OD_VDDC");
 329                size += sysfs_emit_at(buf, size, "0: %umV *\n", cur_value);
 330                break;
 331        case SMU_OD_RANGE:
 332                size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
 333                size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
 334                                                CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
 335                size += sysfs_emit_at(buf, size, "VDDC: %7umV  %10umV\n",
 336                                                CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
 337                break;
 338        case SMU_FCLK:
 339        case SMU_MCLK:
 340        case SMU_SOCCLK:
 341        case SMU_VCLK:
 342        case SMU_DCLK:
 343                ret = cyan_skillfish_get_current_clk_freq(smu, clk_type, &cur_value);
 344                if (ret)
 345                        return ret;
 346                size += sysfs_emit_at(buf, size, "0: %uMhz *\n", cur_value);
 347                break;
 348        case SMU_SCLK:
 349        case SMU_GFXCLK:
 350                ret = cyan_skillfish_get_current_clk_freq(smu, clk_type, &cur_value);
 351                if (ret)
 352                        return ret;
 353                if (cur_value  == CYAN_SKILLFISH_SCLK_MAX)
 354                        i = 2;
 355                else if (cur_value == CYAN_SKILLFISH_SCLK_MIN)
 356                        i = 0;
 357                else
 358                        i = 1;
 359                size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", CYAN_SKILLFISH_SCLK_MIN,
 360                                i == 0 ? "*" : "");
 361                size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
 362                                i == 1 ? cur_value : cyan_skillfish_sclk_default,
 363                                i == 1 ? "*" : "");
 364                size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", CYAN_SKILLFISH_SCLK_MAX,
 365                                i == 2 ? "*" : "");
 366                break;
 367        default:
 368                dev_warn(smu->adev->dev, "Unsupported clock type\n");
 369                return ret;
 370        }
 371
 372        return size;
 373}
 374
 375static bool cyan_skillfish_is_dpm_running(struct smu_context *smu)
 376{
 377        struct amdgpu_device *adev = smu->adev;
 378        int ret = 0;
 379        uint32_t feature_mask[2];
 380        uint64_t feature_enabled;
 381
 382        /* we need to re-init after suspend so return false */
 383        if (adev->in_suspend)
 384                return false;
 385
 386        ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
 387        if (ret)
 388                return false;
 389
 390        feature_enabled = (uint64_t)feature_mask[0] |
 391                                ((uint64_t)feature_mask[1] << 32);
 392
 393        /*
 394         * cyan_skillfish specific, query default sclk inseted of hard code.
 395         */
 396        if (!cyan_skillfish_sclk_default)
 397                cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK,
 398                        &cyan_skillfish_sclk_default);
 399
 400        return !!(feature_enabled & SMC_DPM_FEATURE);
 401}
 402
 403static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu,
 404                                                void **table)
 405{
 406        struct smu_table_context *smu_table = &smu->smu_table;
 407        struct gpu_metrics_v2_2 *gpu_metrics =
 408                (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table;
 409        SmuMetrics_t metrics;
 410        int i, ret = 0;
 411
 412        ret = smu_cmn_get_metrics_table(smu, &metrics, true);
 413        if (ret)
 414                return ret;
 415
 416        smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 2);
 417
 418        gpu_metrics->temperature_gfx = metrics.Current.GfxTemperature;
 419        gpu_metrics->temperature_soc = metrics.Current.SocTemperature;
 420
 421        gpu_metrics->average_socket_power = metrics.Current.CurrentSocketPower;
 422        gpu_metrics->average_soc_power = metrics.Current.Power[0];
 423        gpu_metrics->average_gfx_power = metrics.Current.Power[1];
 424
 425        gpu_metrics->average_gfxclk_frequency = metrics.Average.GfxclkFrequency;
 426        gpu_metrics->average_socclk_frequency = metrics.Average.SocclkFrequency;
 427        gpu_metrics->average_uclk_frequency = metrics.Average.MemclkFrequency;
 428        gpu_metrics->average_fclk_frequency = metrics.Average.MemclkFrequency;
 429        gpu_metrics->average_vclk_frequency = metrics.Average.VclkFrequency;
 430        gpu_metrics->average_dclk_frequency = metrics.Average.DclkFrequency;
 431
 432        gpu_metrics->current_gfxclk = metrics.Current.GfxclkFrequency;
 433        gpu_metrics->current_socclk = metrics.Current.SocclkFrequency;
 434        gpu_metrics->current_uclk = metrics.Current.MemclkFrequency;
 435        gpu_metrics->current_fclk = metrics.Current.MemclkFrequency;
 436        gpu_metrics->current_vclk = metrics.Current.VclkFrequency;
 437        gpu_metrics->current_dclk = metrics.Current.DclkFrequency;
 438
 439        for (i = 0; i < 6; i++) {
 440                gpu_metrics->temperature_core[i] = metrics.Current.CoreTemperature[i];
 441                gpu_metrics->average_core_power[i] = metrics.Average.CorePower[i];
 442                gpu_metrics->current_coreclk[i] = metrics.Current.CoreFrequency[i];
 443        }
 444
 445        for (i = 0; i < 2; i++) {
 446                gpu_metrics->temperature_l3[i] = metrics.Current.L3Temperature[i];
 447                gpu_metrics->current_l3clk[i] = metrics.Current.L3Frequency[i];
 448        }
 449
 450        gpu_metrics->throttle_status = metrics.Current.ThrottlerStatus;
 451        gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
 452
 453        *table = (void *)gpu_metrics;
 454
 455        return sizeof(struct gpu_metrics_v2_2);
 456}
 457
 458static int cyan_skillfish_od_edit_dpm_table(struct smu_context *smu,
 459                                        enum PP_OD_DPM_TABLE_COMMAND type,
 460                                        long input[], uint32_t size)
 461{
 462        int ret = 0;
 463        uint32_t vid;
 464
 465        switch (type) {
 466        case PP_OD_EDIT_VDDC_CURVE:
 467                if (size != 3 || input[0] != 0) {
 468                        dev_err(smu->adev->dev, "Invalid parameter!\n");
 469                        return -EINVAL;
 470                }
 471
 472                if (input[1] < CYAN_SKILLFISH_SCLK_MIN ||
 473                        input[1] > CYAN_SKILLFISH_SCLK_MAX) {
 474                        dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n",
 475                                        CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
 476                        return -EINVAL;
 477                }
 478
 479                if (input[2] < CYAN_SKILLFISH_VDDC_MIN ||
 480                        input[2] > CYAN_SKILLFISH_VDDC_MAX) {
 481                        dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n",
 482                                        CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
 483                        return -EINVAL;
 484                }
 485
 486                cyan_skillfish_user_settings.sclk = input[1];
 487                cyan_skillfish_user_settings.vddc = input[2];
 488
 489                break;
 490        case PP_OD_RESTORE_DEFAULT_TABLE:
 491                if (size != 0) {
 492                        dev_err(smu->adev->dev, "Invalid parameter!\n");
 493                        return -EINVAL;
 494                }
 495
 496                cyan_skillfish_user_settings.sclk = cyan_skillfish_sclk_default;
 497                cyan_skillfish_user_settings.vddc = CYAN_SKILLFISH_VDDC_MAGIC;
 498
 499                break;
 500        case PP_OD_COMMIT_DPM_TABLE:
 501                if (size != 0) {
 502                        dev_err(smu->adev->dev, "Invalid parameter!\n");
 503                        return -EINVAL;
 504                }
 505
 506                if (cyan_skillfish_user_settings.sclk < CYAN_SKILLFISH_SCLK_MIN ||
 507                    cyan_skillfish_user_settings.sclk > CYAN_SKILLFISH_SCLK_MAX) {
 508                        dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n",
 509                                        CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
 510                        return -EINVAL;
 511                }
 512
 513                if ((cyan_skillfish_user_settings.vddc != CYAN_SKILLFISH_VDDC_MAGIC) &&
 514                        (cyan_skillfish_user_settings.vddc < CYAN_SKILLFISH_VDDC_MIN ||
 515                        cyan_skillfish_user_settings.vddc > CYAN_SKILLFISH_VDDC_MAX)) {
 516                        dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n",
 517                                        CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
 518                        return -EINVAL;
 519                }
 520
 521                ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestGfxclk,
 522                                        cyan_skillfish_user_settings.sclk, NULL);
 523                if (ret) {
 524                        dev_err(smu->adev->dev, "Set sclk failed!\n");
 525                        return ret;
 526                }
 527
 528                if (cyan_skillfish_user_settings.vddc == CYAN_SKILLFISH_VDDC_MAGIC) {
 529                        ret = smu_cmn_send_smc_msg(smu, SMU_MSG_UnforceGfxVid, NULL);
 530                        if (ret) {
 531                                dev_err(smu->adev->dev, "Unforce vddc failed!\n");
 532                                return ret;
 533                        }
 534                } else {
 535                        /*
 536                         * PMFW accepts SVI2 VID code, convert voltage to VID:
 537                         * vid = (uint32_t)((1.55 - voltage) * 160.0 + 0.00001)
 538                         */
 539                        vid = (1550 - cyan_skillfish_user_settings.vddc) * 160 / 1000;
 540                        ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ForceGfxVid, vid, NULL);
 541                        if (ret) {
 542                                dev_err(smu->adev->dev, "Force vddc failed!\n");
 543                                return ret;
 544                        }
 545                }
 546
 547                break;
 548        default:
 549                return -EOPNOTSUPP;
 550        }
 551
 552        return ret;
 553}
 554
 555static const struct pptable_funcs cyan_skillfish_ppt_funcs = {
 556
 557        .check_fw_status = smu_v11_0_check_fw_status,
 558        .check_fw_version = smu_v11_0_check_fw_version,
 559        .init_power = smu_v11_0_init_power,
 560        .fini_power = smu_v11_0_fini_power,
 561        .init_smc_tables = cyan_skillfish_init_smc_tables,
 562        .fini_smc_tables = cyan_skillfish_finit_smc_tables,
 563        .read_sensor = cyan_skillfish_read_sensor,
 564        .print_clk_levels = cyan_skillfish_print_clk_levels,
 565        .is_dpm_running = cyan_skillfish_is_dpm_running,
 566        .get_gpu_metrics = cyan_skillfish_get_gpu_metrics,
 567        .od_edit_dpm_table = cyan_skillfish_od_edit_dpm_table,
 568        .register_irq_handler = smu_v11_0_register_irq_handler,
 569        .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
 570        .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
 571        .send_smc_msg = smu_cmn_send_smc_msg,
 572        .set_driver_table_location = smu_v11_0_set_driver_table_location,
 573        .interrupt_work = smu_v11_0_interrupt_work,
 574};
 575
 576void cyan_skillfish_set_ppt_funcs(struct smu_context *smu)
 577{
 578        smu->ppt_funcs = &cyan_skillfish_ppt_funcs;
 579        smu->message_map = cyan_skillfish_message_map;
 580        smu->table_map = cyan_skillfish_table_map;
 581        smu->is_apu = true;
 582}
 583