linux/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
<<
>>
Prefs
   1/*
   2 * Copyright 2015 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#include "pp_debug.h"
  24#include <linux/delay.h>
  25#include <linux/fb.h>
  26#include <linux/module.h>
  27#include <linux/pci.h>
  28#include <linux/slab.h>
  29#include <asm/div64.h>
  30#include <drm/amdgpu_drm.h>
  31#include "ppatomctrl.h"
  32#include "atombios.h"
  33#include "pptable_v1_0.h"
  34#include "pppcielanes.h"
  35#include "amd_pcie_helpers.h"
  36#include "hardwaremanager.h"
  37#include "process_pptables_v1_0.h"
  38#include "cgs_common.h"
  39
  40#include "smu7_common.h"
  41
  42#include "hwmgr.h"
  43#include "smu7_hwmgr.h"
  44#include "smu_ucode_xfer_vi.h"
  45#include "smu7_powertune.h"
  46#include "smu7_dyn_defaults.h"
  47#include "smu7_thermal.h"
  48#include "smu7_clockpowergating.h"
  49#include "processpptables.h"
  50#include "pp_thermal.h"
  51
  52#include "ivsrcid/ivsrcid_vislands30.h"
  53
  54#define MC_CG_ARB_FREQ_F0           0x0a
  55#define MC_CG_ARB_FREQ_F1           0x0b
  56#define MC_CG_ARB_FREQ_F2           0x0c
  57#define MC_CG_ARB_FREQ_F3           0x0d
  58
  59#define MC_CG_SEQ_DRAMCONF_S0       0x05
  60#define MC_CG_SEQ_DRAMCONF_S1       0x06
  61#define MC_CG_SEQ_YCLK_SUSPEND      0x04
  62#define MC_CG_SEQ_YCLK_RESUME       0x0a
  63
  64#define SMC_CG_IND_START            0xc0030000
  65#define SMC_CG_IND_END              0xc0040000
  66
  67#define MEM_FREQ_LOW_LATENCY        25000
  68#define MEM_FREQ_HIGH_LATENCY       80000
  69
  70#define MEM_LATENCY_HIGH            45
  71#define MEM_LATENCY_LOW             35
  72#define MEM_LATENCY_ERR             0xFFFF
  73
  74#define MC_SEQ_MISC0_GDDR5_SHIFT 28
  75#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
  76#define MC_SEQ_MISC0_GDDR5_VALUE 5
  77
  78#define PCIE_BUS_CLK                10000
  79#define TCLK                        (PCIE_BUS_CLK / 10)
  80
  81static struct profile_mode_setting smu7_profiling[7] =
  82                                        {{0, 0, 0, 0, 0, 0, 0, 0},
  83                                         {1, 0, 100, 30, 1, 0, 100, 10},
  84                                         {1, 10, 0, 30, 0, 0, 0, 0},
  85                                         {0, 0, 0, 0, 1, 10, 16, 31},
  86                                         {1, 0, 11, 50, 1, 0, 100, 10},
  87                                         {1, 0, 5, 30, 0, 0, 0, 0},
  88                                         {0, 0, 0, 0, 0, 0, 0, 0},
  89                                        };
  90
  91#define PPSMC_MSG_SetVBITimeout_VEGAM    ((uint16_t) 0x310)
  92
  93#define ixPWR_SVI2_PLANE1_LOAD                     0xC0200280
  94#define PWR_SVI2_PLANE1_LOAD__PSI1_MASK                    0x00000020L
  95#define PWR_SVI2_PLANE1_LOAD__PSI0_EN_MASK                 0x00000040L
  96#define PWR_SVI2_PLANE1_LOAD__PSI1__SHIFT                  0x00000005
  97#define PWR_SVI2_PLANE1_LOAD__PSI0_EN__SHIFT               0x00000006
  98
  99/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
 100enum DPM_EVENT_SRC {
 101        DPM_EVENT_SRC_ANALOG = 0,
 102        DPM_EVENT_SRC_EXTERNAL = 1,
 103        DPM_EVENT_SRC_DIGITAL = 2,
 104        DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,
 105        DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4
 106};
 107
 108static const unsigned long PhwVIslands_Magic = (unsigned long)(PHM_VIslands_Magic);
 109static int smu7_force_clock_level(struct pp_hwmgr *hwmgr,
 110                enum pp_clock_type type, uint32_t mask);
 111
 112static struct smu7_power_state *cast_phw_smu7_power_state(
 113                                  struct pp_hw_power_state *hw_ps)
 114{
 115        PP_ASSERT_WITH_CODE((PhwVIslands_Magic == hw_ps->magic),
 116                                "Invalid Powerstate Type!",
 117                                 return NULL);
 118
 119        return (struct smu7_power_state *)hw_ps;
 120}
 121
 122static const struct smu7_power_state *cast_const_phw_smu7_power_state(
 123                                 const struct pp_hw_power_state *hw_ps)
 124{
 125        PP_ASSERT_WITH_CODE((PhwVIslands_Magic == hw_ps->magic),
 126                                "Invalid Powerstate Type!",
 127                                 return NULL);
 128
 129        return (const struct smu7_power_state *)hw_ps;
 130}
 131
 132/**
 133 * Find the MC microcode version and store it in the HwMgr struct
 134 *
 135 * @param    hwmgr  the address of the powerplay hardware manager.
 136 * @return   always 0
 137 */
 138static int smu7_get_mc_microcode_version(struct pp_hwmgr *hwmgr)
 139{
 140        cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
 141
 142        hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
 143
 144        return 0;
 145}
 146
 147static uint16_t smu7_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
 148{
 149        uint32_t speedCntl = 0;
 150
 151        /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
 152        speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
 153                        ixPCIE_LC_SPEED_CNTL);
 154        return((uint16_t)PHM_GET_FIELD(speedCntl,
 155                        PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
 156}
 157
 158static int smu7_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
 159{
 160        uint32_t link_width;
 161
 162        /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
 163        link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
 164                        PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
 165
 166        PP_ASSERT_WITH_CODE((7 >= link_width),
 167                        "Invalid PCIe lane width!", return 0);
 168
 169        return decode_pcie_lane_width(link_width);
 170}
 171
 172/**
 173* Enable voltage control
 174*
 175* @param    pHwMgr  the address of the powerplay hardware manager.
 176* @return   always PP_Result_OK
 177*/
 178static int smu7_enable_smc_voltage_controller(struct pp_hwmgr *hwmgr)
 179{
 180        if (hwmgr->chip_id == CHIP_VEGAM) {
 181                PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
 182                                CGS_IND_REG__SMC, PWR_SVI2_PLANE1_LOAD, PSI1, 0);
 183                PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
 184                                CGS_IND_REG__SMC, PWR_SVI2_PLANE1_LOAD, PSI0_EN, 0);
 185        }
 186
 187        if (hwmgr->feature_mask & PP_SMC_VOLTAGE_CONTROL_MASK)
 188                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Voltage_Cntl_Enable);
 189
 190        return 0;
 191}
 192
 193/**
 194* Checks if we want to support voltage control
 195*
 196* @param    hwmgr  the address of the powerplay hardware manager.
 197*/
 198static bool smu7_voltage_control(const struct pp_hwmgr *hwmgr)
 199{
 200        const struct smu7_hwmgr *data =
 201                        (const struct smu7_hwmgr *)(hwmgr->backend);
 202
 203        return (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control);
 204}
 205
 206/**
 207* Enable voltage control
 208*
 209* @param    hwmgr  the address of the powerplay hardware manager.
 210* @return   always 0
 211*/
 212static int smu7_enable_voltage_control(struct pp_hwmgr *hwmgr)
 213{
 214        /* enable voltage control */
 215        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 216                        GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
 217
 218        return 0;
 219}
 220
 221static int phm_get_svi2_voltage_table_v0(pp_atomctrl_voltage_table *voltage_table,
 222                struct phm_clock_voltage_dependency_table *voltage_dependency_table
 223                )
 224{
 225        uint32_t i;
 226
 227        PP_ASSERT_WITH_CODE((NULL != voltage_table),
 228                        "Voltage Dependency Table empty.", return -EINVAL;);
 229
 230        voltage_table->mask_low = 0;
 231        voltage_table->phase_delay = 0;
 232        voltage_table->count = voltage_dependency_table->count;
 233
 234        for (i = 0; i < voltage_dependency_table->count; i++) {
 235                voltage_table->entries[i].value =
 236                        voltage_dependency_table->entries[i].v;
 237                voltage_table->entries[i].smio_low = 0;
 238        }
 239
 240        return 0;
 241}
 242
 243
 244/**
 245* Create Voltage Tables.
 246*
 247* @param    hwmgr  the address of the powerplay hardware manager.
 248* @return   always 0
 249*/
 250static int smu7_construct_voltage_tables(struct pp_hwmgr *hwmgr)
 251{
 252        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 253        struct phm_ppt_v1_information *table_info =
 254                        (struct phm_ppt_v1_information *)hwmgr->pptable;
 255        int result = 0;
 256        uint32_t tmp;
 257
 258        if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
 259                result = atomctrl_get_voltage_table_v3(hwmgr,
 260                                VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT,
 261                                &(data->mvdd_voltage_table));
 262                PP_ASSERT_WITH_CODE((0 == result),
 263                                "Failed to retrieve MVDD table.",
 264                                return result);
 265        } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
 266                if (hwmgr->pp_table_version == PP_TABLE_V1)
 267                        result = phm_get_svi2_mvdd_voltage_table(&(data->mvdd_voltage_table),
 268                                        table_info->vdd_dep_on_mclk);
 269                else if (hwmgr->pp_table_version == PP_TABLE_V0)
 270                        result = phm_get_svi2_voltage_table_v0(&(data->mvdd_voltage_table),
 271                                        hwmgr->dyn_state.mvdd_dependency_on_mclk);
 272
 273                PP_ASSERT_WITH_CODE((0 == result),
 274                                "Failed to retrieve SVI2 MVDD table from dependency table.",
 275                                return result;);
 276        }
 277
 278        if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
 279                result = atomctrl_get_voltage_table_v3(hwmgr,
 280                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
 281                                &(data->vddci_voltage_table));
 282                PP_ASSERT_WITH_CODE((0 == result),
 283                                "Failed to retrieve VDDCI table.",
 284                                return result);
 285        } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
 286                if (hwmgr->pp_table_version == PP_TABLE_V1)
 287                        result = phm_get_svi2_vddci_voltage_table(&(data->vddci_voltage_table),
 288                                        table_info->vdd_dep_on_mclk);
 289                else if (hwmgr->pp_table_version == PP_TABLE_V0)
 290                        result = phm_get_svi2_voltage_table_v0(&(data->vddci_voltage_table),
 291                                        hwmgr->dyn_state.vddci_dependency_on_mclk);
 292                PP_ASSERT_WITH_CODE((0 == result),
 293                                "Failed to retrieve SVI2 VDDCI table from dependency table.",
 294                                return result);
 295        }
 296
 297        if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
 298                /* VDDGFX has only SVI2 voltage control */
 299                result = phm_get_svi2_vdd_voltage_table(&(data->vddgfx_voltage_table),
 300                                        table_info->vddgfx_lookup_table);
 301                PP_ASSERT_WITH_CODE((0 == result),
 302                        "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result;);
 303        }
 304
 305
 306        if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) {
 307                result = atomctrl_get_voltage_table_v3(hwmgr,
 308                                        VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT,
 309                                        &data->vddc_voltage_table);
 310                PP_ASSERT_WITH_CODE((0 == result),
 311                        "Failed to retrieve VDDC table.", return result;);
 312        } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
 313
 314                if (hwmgr->pp_table_version == PP_TABLE_V0)
 315                        result = phm_get_svi2_voltage_table_v0(&data->vddc_voltage_table,
 316                                        hwmgr->dyn_state.vddc_dependency_on_mclk);
 317                else if (hwmgr->pp_table_version == PP_TABLE_V1)
 318                        result = phm_get_svi2_vdd_voltage_table(&(data->vddc_voltage_table),
 319                                table_info->vddc_lookup_table);
 320
 321                PP_ASSERT_WITH_CODE((0 == result),
 322                        "Failed to retrieve SVI2 VDDC table from dependency table.", return result;);
 323        }
 324
 325        tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDC);
 326        PP_ASSERT_WITH_CODE(
 327                        (data->vddc_voltage_table.count <= tmp),
 328                "Too many voltage values for VDDC. Trimming to fit state table.",
 329                        phm_trim_voltage_table_to_fit_state_table(tmp,
 330                                                &(data->vddc_voltage_table)));
 331
 332        tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDGFX);
 333        PP_ASSERT_WITH_CODE(
 334                        (data->vddgfx_voltage_table.count <= tmp),
 335                "Too many voltage values for VDDC. Trimming to fit state table.",
 336                        phm_trim_voltage_table_to_fit_state_table(tmp,
 337                                                &(data->vddgfx_voltage_table)));
 338
 339        tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDCI);
 340        PP_ASSERT_WITH_CODE(
 341                        (data->vddci_voltage_table.count <= tmp),
 342                "Too many voltage values for VDDCI. Trimming to fit state table.",
 343                        phm_trim_voltage_table_to_fit_state_table(tmp,
 344                                        &(data->vddci_voltage_table)));
 345
 346        tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_MVDD);
 347        PP_ASSERT_WITH_CODE(
 348                        (data->mvdd_voltage_table.count <= tmp),
 349                "Too many voltage values for MVDD. Trimming to fit state table.",
 350                        phm_trim_voltage_table_to_fit_state_table(tmp,
 351                                                &(data->mvdd_voltage_table)));
 352
 353        return 0;
 354}
 355
 356/**
 357* Programs static screed detection parameters
 358*
 359* @param    hwmgr  the address of the powerplay hardware manager.
 360* @return   always 0
 361*/
 362static int smu7_program_static_screen_threshold_parameters(
 363                                                        struct pp_hwmgr *hwmgr)
 364{
 365        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 366
 367        /* Set static screen threshold unit */
 368        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 369                        CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
 370                        data->static_screen_threshold_unit);
 371        /* Set static screen threshold */
 372        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 373                        CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
 374                        data->static_screen_threshold);
 375
 376        return 0;
 377}
 378
 379/**
 380* Setup display gap for glitch free memory clock switching.
 381*
 382* @param    hwmgr  the address of the powerplay hardware manager.
 383* @return   always  0
 384*/
 385static int smu7_enable_display_gap(struct pp_hwmgr *hwmgr)
 386{
 387        uint32_t display_gap =
 388                        cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 389                                        ixCG_DISPLAY_GAP_CNTL);
 390
 391        display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
 392                        DISP_GAP, DISPLAY_GAP_IGNORE);
 393
 394        display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
 395                        DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
 396
 397        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 398                        ixCG_DISPLAY_GAP_CNTL, display_gap);
 399
 400        return 0;
 401}
 402
 403/**
 404* Programs activity state transition voting clients
 405*
 406* @param    hwmgr  the address of the powerplay hardware manager.
 407* @return   always  0
 408*/
 409static int smu7_program_voting_clients(struct pp_hwmgr *hwmgr)
 410{
 411        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 412        int i;
 413
 414        /* Clear reset for voting clients before enabling DPM */
 415        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 416                        SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
 417        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 418                        SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
 419
 420        for (i = 0; i < 8; i++)
 421                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 422                                        ixCG_FREQ_TRAN_VOTING_0 + i * 4,
 423                                        data->voting_rights_clients[i]);
 424        return 0;
 425}
 426
 427static int smu7_clear_voting_clients(struct pp_hwmgr *hwmgr)
 428{
 429        int i;
 430
 431        /* Reset voting clients before disabling DPM */
 432        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 433                        SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
 434        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 435                        SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
 436
 437        for (i = 0; i < 8; i++)
 438                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 439                                ixCG_FREQ_TRAN_VOTING_0 + i * 4, 0);
 440
 441        return 0;
 442}
 443
 444/* Copy one arb setting to another and then switch the active set.
 445 * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
 446 */
 447static int smu7_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
 448                uint32_t arb_src, uint32_t arb_dest)
 449{
 450        uint32_t mc_arb_dram_timing;
 451        uint32_t mc_arb_dram_timing2;
 452        uint32_t burst_time;
 453        uint32_t mc_cg_config;
 454
 455        switch (arb_src) {
 456        case MC_CG_ARB_FREQ_F0:
 457                mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
 458                mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
 459                burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
 460                break;
 461        case MC_CG_ARB_FREQ_F1:
 462                mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
 463                mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
 464                burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
 465                break;
 466        default:
 467                return -EINVAL;
 468        }
 469
 470        switch (arb_dest) {
 471        case MC_CG_ARB_FREQ_F0:
 472                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
 473                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
 474                PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
 475                break;
 476        case MC_CG_ARB_FREQ_F1:
 477                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
 478                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
 479                PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
 480                break;
 481        default:
 482                return -EINVAL;
 483        }
 484
 485        mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
 486        mc_cg_config |= 0x0000000F;
 487        cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
 488        PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
 489
 490        return 0;
 491}
 492
 493static int smu7_reset_to_default(struct pp_hwmgr *hwmgr)
 494{
 495        return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ResetToDefaults);
 496}
 497
 498/**
 499* Initial switch from ARB F0->F1
 500*
 501* @param    hwmgr  the address of the powerplay hardware manager.
 502* @return   always 0
 503* This function is to be called from the SetPowerState table.
 504*/
 505static int smu7_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
 506{
 507        return smu7_copy_and_switch_arb_sets(hwmgr,
 508                        MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
 509}
 510
 511static int smu7_force_switch_to_arbf0(struct pp_hwmgr *hwmgr)
 512{
 513        uint32_t tmp;
 514
 515        tmp = (cgs_read_ind_register(hwmgr->device,
 516                        CGS_IND_REG__SMC, ixSMC_SCRATCH9) &
 517                        0x0000ff00) >> 8;
 518
 519        if (tmp == MC_CG_ARB_FREQ_F0)
 520                return 0;
 521
 522        return smu7_copy_and_switch_arb_sets(hwmgr,
 523                        tmp, MC_CG_ARB_FREQ_F0);
 524}
 525
 526static int smu7_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
 527{
 528        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 529
 530        struct phm_ppt_v1_information *table_info =
 531                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 532        struct phm_ppt_v1_pcie_table *pcie_table = NULL;
 533
 534        uint32_t i, max_entry;
 535        uint32_t tmp;
 536
 537        PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
 538                        data->use_pcie_power_saving_levels), "No pcie performance levels!",
 539                        return -EINVAL);
 540
 541        if (table_info != NULL)
 542                pcie_table = table_info->pcie_table;
 543
 544        if (data->use_pcie_performance_levels &&
 545                        !data->use_pcie_power_saving_levels) {
 546                data->pcie_gen_power_saving = data->pcie_gen_performance;
 547                data->pcie_lane_power_saving = data->pcie_lane_performance;
 548        } else if (!data->use_pcie_performance_levels &&
 549                        data->use_pcie_power_saving_levels) {
 550                data->pcie_gen_performance = data->pcie_gen_power_saving;
 551                data->pcie_lane_performance = data->pcie_lane_power_saving;
 552        }
 553        tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_LINK);
 554        phm_reset_single_dpm_table(&data->dpm_table.pcie_speed_table,
 555                                        tmp,
 556                                        MAX_REGULAR_DPM_NUMBER);
 557
 558        if (pcie_table != NULL) {
 559                /* max_entry is used to make sure we reserve one PCIE level
 560                 * for boot level (fix for A+A PSPP issue).
 561                 * If PCIE table from PPTable have ULV entry + 8 entries,
 562                 * then ignore the last entry.*/
 563                max_entry = (tmp < pcie_table->count) ? tmp : pcie_table->count;
 564                for (i = 1; i < max_entry; i++) {
 565                        phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
 566                                        get_pcie_gen_support(data->pcie_gen_cap,
 567                                                        pcie_table->entries[i].gen_speed),
 568                                        get_pcie_lane_support(data->pcie_lane_cap,
 569                                                        pcie_table->entries[i].lane_width));
 570                }
 571                data->dpm_table.pcie_speed_table.count = max_entry - 1;
 572                smum_update_smc_table(hwmgr, SMU_BIF_TABLE);
 573        } else {
 574                /* Hardcode Pcie Table */
 575                phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
 576                                get_pcie_gen_support(data->pcie_gen_cap,
 577                                                PP_Min_PCIEGen),
 578                                get_pcie_lane_support(data->pcie_lane_cap,
 579                                                PP_Max_PCIELane));
 580                phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
 581                                get_pcie_gen_support(data->pcie_gen_cap,
 582                                                PP_Min_PCIEGen),
 583                                get_pcie_lane_support(data->pcie_lane_cap,
 584                                                PP_Max_PCIELane));
 585                phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
 586                                get_pcie_gen_support(data->pcie_gen_cap,
 587                                                PP_Max_PCIEGen),
 588                                get_pcie_lane_support(data->pcie_lane_cap,
 589                                                PP_Max_PCIELane));
 590                phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
 591                                get_pcie_gen_support(data->pcie_gen_cap,
 592                                                PP_Max_PCIEGen),
 593                                get_pcie_lane_support(data->pcie_lane_cap,
 594                                                PP_Max_PCIELane));
 595                phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
 596                                get_pcie_gen_support(data->pcie_gen_cap,
 597                                                PP_Max_PCIEGen),
 598                                get_pcie_lane_support(data->pcie_lane_cap,
 599                                                PP_Max_PCIELane));
 600                phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
 601                                get_pcie_gen_support(data->pcie_gen_cap,
 602                                                PP_Max_PCIEGen),
 603                                get_pcie_lane_support(data->pcie_lane_cap,
 604                                                PP_Max_PCIELane));
 605
 606                data->dpm_table.pcie_speed_table.count = 6;
 607        }
 608        /* Populate last level for boot PCIE level, but do not increment count. */
 609        if (hwmgr->chip_family == AMDGPU_FAMILY_CI) {
 610                for (i = 0; i <= data->dpm_table.pcie_speed_table.count; i++)
 611                        phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i,
 612                                get_pcie_gen_support(data->pcie_gen_cap,
 613                                                PP_Max_PCIEGen),
 614                                data->vbios_boot_state.pcie_lane_bootup_value);
 615        } else {
 616                phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
 617                        data->dpm_table.pcie_speed_table.count,
 618                        get_pcie_gen_support(data->pcie_gen_cap,
 619                                        PP_Min_PCIEGen),
 620                        get_pcie_lane_support(data->pcie_lane_cap,
 621                                        PP_Max_PCIELane));
 622        }
 623        return 0;
 624}
 625
 626static int smu7_reset_dpm_tables(struct pp_hwmgr *hwmgr)
 627{
 628        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 629
 630        memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table));
 631
 632        phm_reset_single_dpm_table(
 633                        &data->dpm_table.sclk_table,
 634                                smum_get_mac_definition(hwmgr,
 635                                        SMU_MAX_LEVELS_GRAPHICS),
 636                                        MAX_REGULAR_DPM_NUMBER);
 637        phm_reset_single_dpm_table(
 638                        &data->dpm_table.mclk_table,
 639                        smum_get_mac_definition(hwmgr,
 640                                SMU_MAX_LEVELS_MEMORY), MAX_REGULAR_DPM_NUMBER);
 641
 642        phm_reset_single_dpm_table(
 643                        &data->dpm_table.vddc_table,
 644                                smum_get_mac_definition(hwmgr,
 645                                        SMU_MAX_LEVELS_VDDC),
 646                                        MAX_REGULAR_DPM_NUMBER);
 647        phm_reset_single_dpm_table(
 648                        &data->dpm_table.vddci_table,
 649                        smum_get_mac_definition(hwmgr,
 650                                SMU_MAX_LEVELS_VDDCI), MAX_REGULAR_DPM_NUMBER);
 651
 652        phm_reset_single_dpm_table(
 653                        &data->dpm_table.mvdd_table,
 654                                smum_get_mac_definition(hwmgr,
 655                                        SMU_MAX_LEVELS_MVDD),
 656                                        MAX_REGULAR_DPM_NUMBER);
 657        return 0;
 658}
 659/*
 660 * This function is to initialize all DPM state tables
 661 * for SMU7 based on the dependency table.
 662 * Dynamic state patching function will then trim these
 663 * state tables to the allowed range based
 664 * on the power policy or external client requests,
 665 * such as UVD request, etc.
 666 */
 667
 668static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
 669{
 670        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 671        struct phm_clock_voltage_dependency_table *allowed_vdd_sclk_table =
 672                hwmgr->dyn_state.vddc_dependency_on_sclk;
 673        struct phm_clock_voltage_dependency_table *allowed_vdd_mclk_table =
 674                hwmgr->dyn_state.vddc_dependency_on_mclk;
 675        struct phm_cac_leakage_table *std_voltage_table =
 676                hwmgr->dyn_state.cac_leakage_table;
 677        uint32_t i;
 678
 679        PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
 680                "SCLK dependency table is missing. This table is mandatory", return -EINVAL);
 681        PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1,
 682                "SCLK dependency table has to have is missing. This table is mandatory", return -EINVAL);
 683
 684        PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
 685                "MCLK dependency table is missing. This table is mandatory", return -EINVAL);
 686        PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1,
 687                "VMCLK dependency table has to have is missing. This table is mandatory", return -EINVAL);
 688
 689
 690        /* Initialize Sclk DPM table based on allow Sclk values*/
 691        data->dpm_table.sclk_table.count = 0;
 692
 693        for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
 694                if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
 695                                allowed_vdd_sclk_table->entries[i].clk) {
 696                        data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
 697                                allowed_vdd_sclk_table->entries[i].clk;
 698                        data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0;
 699                        data->dpm_table.sclk_table.count++;
 700                }
 701        }
 702
 703        PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
 704                "MCLK dependency table is missing. This table is mandatory", return -EINVAL);
 705        /* Initialize Mclk DPM table based on allow Mclk values */
 706        data->dpm_table.mclk_table.count = 0;
 707        for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
 708                if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value !=
 709                        allowed_vdd_mclk_table->entries[i].clk) {
 710                        data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
 711                                allowed_vdd_mclk_table->entries[i].clk;
 712                        data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = (i == 0) ? 1 : 0;
 713                        data->dpm_table.mclk_table.count++;
 714                }
 715        }
 716
 717        /* Initialize Vddc DPM table based on allow Vddc values.  And populate corresponding std values. */
 718        for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
 719                data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v;
 720                data->dpm_table.vddc_table.dpm_levels[i].param1 = std_voltage_table->entries[i].Leakage;
 721                /* param1 is for corresponding std voltage */
 722                data->dpm_table.vddc_table.dpm_levels[i].enabled = 1;
 723        }
 724
 725        data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count;
 726        allowed_vdd_mclk_table = hwmgr->dyn_state.vddci_dependency_on_mclk;
 727
 728        if (NULL != allowed_vdd_mclk_table) {
 729                /* Initialize Vddci DPM table based on allow Mclk values */
 730                for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
 731                        data->dpm_table.vddci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v;
 732                        data->dpm_table.vddci_table.dpm_levels[i].enabled = 1;
 733                }
 734                data->dpm_table.vddci_table.count = allowed_vdd_mclk_table->count;
 735        }
 736
 737        allowed_vdd_mclk_table = hwmgr->dyn_state.mvdd_dependency_on_mclk;
 738
 739        if (NULL != allowed_vdd_mclk_table) {
 740                /*
 741                 * Initialize MVDD DPM table based on allow Mclk
 742                 * values
 743                 */
 744                for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
 745                        data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v;
 746                        data->dpm_table.mvdd_table.dpm_levels[i].enabled = 1;
 747                }
 748                data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count;
 749        }
 750
 751        return 0;
 752}
 753
 754static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr)
 755{
 756        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 757        struct phm_ppt_v1_information *table_info =
 758                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 759        uint32_t i;
 760
 761        struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table;
 762        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
 763
 764        if (table_info == NULL)
 765                return -EINVAL;
 766
 767        dep_sclk_table = table_info->vdd_dep_on_sclk;
 768        dep_mclk_table = table_info->vdd_dep_on_mclk;
 769
 770        PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
 771                        "SCLK dependency table is missing.",
 772                        return -EINVAL);
 773        PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
 774                        "SCLK dependency table count is 0.",
 775                        return -EINVAL);
 776
 777        PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
 778                        "MCLK dependency table is missing.",
 779                        return -EINVAL);
 780        PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
 781                        "MCLK dependency table count is 0",
 782                        return -EINVAL);
 783
 784        /* Initialize Sclk DPM table based on allow Sclk values */
 785        data->dpm_table.sclk_table.count = 0;
 786        for (i = 0; i < dep_sclk_table->count; i++) {
 787                if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count - 1].value !=
 788                                                dep_sclk_table->entries[i].clk) {
 789
 790                        data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
 791                                        dep_sclk_table->entries[i].clk;
 792
 793                        data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled =
 794                                        (i == 0) ? true : false;
 795                        data->dpm_table.sclk_table.count++;
 796                }
 797        }
 798        if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0)
 799                hwmgr->platform_descriptor.overdriveLimit.engineClock = dep_sclk_table->entries[i-1].clk;
 800        /* Initialize Mclk DPM table based on allow Mclk values */
 801        data->dpm_table.mclk_table.count = 0;
 802        for (i = 0; i < dep_mclk_table->count; i++) {
 803                if (i == 0 || data->dpm_table.mclk_table.dpm_levels
 804                                [data->dpm_table.mclk_table.count - 1].value !=
 805                                                dep_mclk_table->entries[i].clk) {
 806                        data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
 807                                                        dep_mclk_table->entries[i].clk;
 808                        data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled =
 809                                                        (i == 0) ? true : false;
 810                        data->dpm_table.mclk_table.count++;
 811                }
 812        }
 813
 814        if (hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0)
 815                hwmgr->platform_descriptor.overdriveLimit.memoryClock = dep_mclk_table->entries[i-1].clk;
 816        return 0;
 817}
 818
 819static int smu7_odn_initial_default_setting(struct pp_hwmgr *hwmgr)
 820{
 821        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 822        struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table);
 823        struct phm_ppt_v1_information *table_info =
 824                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 825        uint32_t i;
 826
 827        struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table;
 828        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
 829        struct phm_odn_performance_level *entries;
 830
 831        if (table_info == NULL)
 832                return -EINVAL;
 833
 834        dep_sclk_table = table_info->vdd_dep_on_sclk;
 835        dep_mclk_table = table_info->vdd_dep_on_mclk;
 836
 837        odn_table->odn_core_clock_dpm_levels.num_of_pl =
 838                                                data->golden_dpm_table.sclk_table.count;
 839        entries = odn_table->odn_core_clock_dpm_levels.entries;
 840        for (i=0; i<data->golden_dpm_table.sclk_table.count; i++) {
 841                entries[i].clock = data->golden_dpm_table.sclk_table.dpm_levels[i].value;
 842                entries[i].enabled = true;
 843                entries[i].vddc = dep_sclk_table->entries[i].vddc;
 844        }
 845
 846        smu_get_voltage_dependency_table_ppt_v1(dep_sclk_table,
 847                (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk));
 848
 849        odn_table->odn_memory_clock_dpm_levels.num_of_pl =
 850                                                data->golden_dpm_table.mclk_table.count;
 851        entries = odn_table->odn_memory_clock_dpm_levels.entries;
 852        for (i=0; i<data->golden_dpm_table.mclk_table.count; i++) {
 853                entries[i].clock = data->golden_dpm_table.mclk_table.dpm_levels[i].value;
 854                entries[i].enabled = true;
 855                entries[i].vddc = dep_mclk_table->entries[i].vddc;
 856        }
 857
 858        smu_get_voltage_dependency_table_ppt_v1(dep_mclk_table,
 859                (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk));
 860
 861        return 0;
 862}
 863
 864static void smu7_setup_voltage_range_from_vbios(struct pp_hwmgr *hwmgr)
 865{
 866        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 867        struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table;
 868        struct phm_ppt_v1_information *table_info =
 869                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 870        uint32_t min_vddc = 0;
 871        uint32_t max_vddc = 0;
 872
 873        if (!table_info)
 874                return;
 875
 876        dep_sclk_table = table_info->vdd_dep_on_sclk;
 877
 878        atomctrl_get_voltage_range(hwmgr, &max_vddc, &min_vddc);
 879
 880        if (min_vddc == 0 || min_vddc > 2000
 881                || min_vddc > dep_sclk_table->entries[0].vddc)
 882                min_vddc = dep_sclk_table->entries[0].vddc;
 883
 884        if (max_vddc == 0 || max_vddc > 2000
 885                || max_vddc < dep_sclk_table->entries[dep_sclk_table->count-1].vddc)
 886                max_vddc = dep_sclk_table->entries[dep_sclk_table->count-1].vddc;
 887
 888        data->odn_dpm_table.min_vddc = min_vddc;
 889        data->odn_dpm_table.max_vddc = max_vddc;
 890}
 891
 892static void smu7_check_dpm_table_updated(struct pp_hwmgr *hwmgr)
 893{
 894        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 895        struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table);
 896        struct phm_ppt_v1_information *table_info =
 897                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 898        uint32_t i;
 899
 900        struct phm_ppt_v1_clock_voltage_dependency_table *dep_table;
 901        struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table;
 902
 903        if (table_info == NULL)
 904                return;
 905
 906        for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
 907                if (odn_table->odn_core_clock_dpm_levels.entries[i].clock !=
 908                                        data->dpm_table.sclk_table.dpm_levels[i].value) {
 909                        data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
 910                        break;
 911                }
 912        }
 913
 914        for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
 915                if (odn_table->odn_memory_clock_dpm_levels.entries[i].clock !=
 916                                        data->dpm_table.mclk_table.dpm_levels[i].value) {
 917                        data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
 918                        break;
 919                }
 920        }
 921
 922        dep_table = table_info->vdd_dep_on_mclk;
 923        odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk);
 924
 925        for (i = 0; i < dep_table->count; i++) {
 926                if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) {
 927                        data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK;
 928                        return;
 929                }
 930        }
 931
 932        dep_table = table_info->vdd_dep_on_sclk;
 933        odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk);
 934        for (i = 0; i < dep_table->count; i++) {
 935                if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) {
 936                        data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK;
 937                        return;
 938                }
 939        }
 940        if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_VDDC) {
 941                data->need_update_smu7_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC;
 942                data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK;
 943        }
 944}
 945
 946static int smu7_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
 947{
 948        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 949
 950        smu7_reset_dpm_tables(hwmgr);
 951
 952        if (hwmgr->pp_table_version == PP_TABLE_V1)
 953                smu7_setup_dpm_tables_v1(hwmgr);
 954        else if (hwmgr->pp_table_version == PP_TABLE_V0)
 955                smu7_setup_dpm_tables_v0(hwmgr);
 956
 957        smu7_setup_default_pcie_table(hwmgr);
 958
 959        /* save a copy of the default DPM table */
 960        memcpy(&(data->golden_dpm_table), &(data->dpm_table),
 961                        sizeof(struct smu7_dpm_table));
 962
 963        /* initialize ODN table */
 964        if (hwmgr->od_enabled) {
 965                if (data->odn_dpm_table.max_vddc) {
 966                        smu7_check_dpm_table_updated(hwmgr);
 967                } else {
 968                        smu7_setup_voltage_range_from_vbios(hwmgr);
 969                        smu7_odn_initial_default_setting(hwmgr);
 970                }
 971        }
 972        return 0;
 973}
 974
 975static int smu7_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
 976{
 977
 978        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 979                        PHM_PlatformCaps_RegulatorHot))
 980                return smum_send_msg_to_smc(hwmgr,
 981                                PPSMC_MSG_EnableVRHotGPIOInterrupt);
 982
 983        return 0;
 984}
 985
 986static int smu7_enable_sclk_control(struct pp_hwmgr *hwmgr)
 987{
 988        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
 989                        SCLK_PWRMGT_OFF, 0);
 990        return 0;
 991}
 992
 993static int smu7_enable_ulv(struct pp_hwmgr *hwmgr)
 994{
 995        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 996
 997        if (data->ulv_supported)
 998                return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableULV);
 999
1000        return 0;
1001}
1002
1003static int smu7_disable_ulv(struct pp_hwmgr *hwmgr)
1004{
1005        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1006
1007        if (data->ulv_supported)
1008                return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableULV);
1009
1010        return 0;
1011}
1012
1013static int smu7_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
1014{
1015        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1016                        PHM_PlatformCaps_SclkDeepSleep)) {
1017                if (smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MASTER_DeepSleep_ON))
1018                        PP_ASSERT_WITH_CODE(false,
1019                                        "Attempt to enable Master Deep Sleep switch failed!",
1020                                        return -EINVAL);
1021        } else {
1022                if (smum_send_msg_to_smc(hwmgr,
1023                                PPSMC_MSG_MASTER_DeepSleep_OFF)) {
1024                        PP_ASSERT_WITH_CODE(false,
1025                                        "Attempt to disable Master Deep Sleep switch failed!",
1026                                        return -EINVAL);
1027                }
1028        }
1029
1030        return 0;
1031}
1032
1033static int smu7_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
1034{
1035        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1036                        PHM_PlatformCaps_SclkDeepSleep)) {
1037                if (smum_send_msg_to_smc(hwmgr,
1038                                PPSMC_MSG_MASTER_DeepSleep_OFF)) {
1039                        PP_ASSERT_WITH_CODE(false,
1040                                        "Attempt to disable Master Deep Sleep switch failed!",
1041                                        return -EINVAL);
1042                }
1043        }
1044
1045        return 0;
1046}
1047
1048static int smu7_disable_sclk_vce_handshake(struct pp_hwmgr *hwmgr)
1049{
1050        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1051        uint32_t soft_register_value = 0;
1052        uint32_t handshake_disables_offset = data->soft_regs_start
1053                                + smum_get_offsetof(hwmgr,
1054                                        SMU_SoftRegisters, HandshakeDisables);
1055
1056        soft_register_value = cgs_read_ind_register(hwmgr->device,
1057                                CGS_IND_REG__SMC, handshake_disables_offset);
1058        soft_register_value |= SMU7_VCE_SCLK_HANDSHAKE_DISABLE;
1059        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1060                        handshake_disables_offset, soft_register_value);
1061        return 0;
1062}
1063
1064static int smu7_disable_handshake_uvd(struct pp_hwmgr *hwmgr)
1065{
1066        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1067        uint32_t soft_register_value = 0;
1068        uint32_t handshake_disables_offset = data->soft_regs_start
1069                                + smum_get_offsetof(hwmgr,
1070                                        SMU_SoftRegisters, HandshakeDisables);
1071
1072        soft_register_value = cgs_read_ind_register(hwmgr->device,
1073                                CGS_IND_REG__SMC, handshake_disables_offset);
1074        soft_register_value |= smum_get_mac_definition(hwmgr,
1075                                        SMU_UVD_MCLK_HANDSHAKE_DISABLE);
1076        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1077                        handshake_disables_offset, soft_register_value);
1078        return 0;
1079}
1080
1081static int smu7_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
1082{
1083        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1084
1085        /* enable SCLK dpm */
1086        if (!data->sclk_dpm_key_disabled) {
1087                if (hwmgr->chip_id == CHIP_VEGAM)
1088                        smu7_disable_sclk_vce_handshake(hwmgr);
1089
1090                PP_ASSERT_WITH_CODE(
1091                (0 == smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DPM_Enable)),
1092                "Failed to enable SCLK DPM during DPM Start Function!",
1093                return -EINVAL);
1094        }
1095
1096        /* enable MCLK dpm */
1097        if (0 == data->mclk_dpm_key_disabled) {
1098                if (!(hwmgr->feature_mask & PP_UVD_HANDSHAKE_MASK))
1099                        smu7_disable_handshake_uvd(hwmgr);
1100
1101                PP_ASSERT_WITH_CODE(
1102                                (0 == smum_send_msg_to_smc(hwmgr,
1103                                                PPSMC_MSG_MCLKDPM_Enable)),
1104                                "Failed to enable MCLK DPM during DPM Start Function!",
1105                                return -EINVAL);
1106
1107                if (hwmgr->chip_family != CHIP_VEGAM)
1108                        PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
1109
1110
1111                if (hwmgr->chip_family == AMDGPU_FAMILY_CI) {
1112                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d30, 0x5);
1113                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d3c, 0x5);
1114                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d80, 0x100005);
1115                        udelay(10);
1116                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d30, 0x400005);
1117                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d3c, 0x400005);
1118                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d80, 0x500005);
1119                } else {
1120                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x5);
1121                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x5);
1122                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x100005);
1123                        udelay(10);
1124                        if (hwmgr->chip_id == CHIP_VEGAM) {
1125                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x400009);
1126                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x400009);
1127                        } else {
1128                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x400005);
1129                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x400005);
1130                        }
1131                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x500005);
1132                }
1133        }
1134
1135        return 0;
1136}
1137
1138static int smu7_start_dpm(struct pp_hwmgr *hwmgr)
1139{
1140        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1141
1142        /*enable general power management */
1143
1144        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
1145                        GLOBAL_PWRMGT_EN, 1);
1146
1147        /* enable sclk deep sleep */
1148
1149        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
1150                        DYNAMIC_PM_EN, 1);
1151
1152        /* prepare for PCIE DPM */
1153
1154        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1155                        data->soft_regs_start +
1156                        smum_get_offsetof(hwmgr, SMU_SoftRegisters,
1157                                                VoltageChangeTimeout), 0x1000);
1158        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
1159                        SWRST_COMMAND_1, RESETLC, 0x0);
1160
1161        if (hwmgr->chip_family == AMDGPU_FAMILY_CI)
1162                cgs_write_register(hwmgr->device, 0x1488,
1163                        (cgs_read_register(hwmgr->device, 0x1488) & ~0x1));
1164
1165        if (smu7_enable_sclk_mclk_dpm(hwmgr)) {
1166                pr_err("Failed to enable Sclk DPM and Mclk DPM!");
1167                return -EINVAL;
1168        }
1169
1170        /* enable PCIE dpm */
1171        if (0 == data->pcie_dpm_key_disabled) {
1172                PP_ASSERT_WITH_CODE(
1173                                (0 == smum_send_msg_to_smc(hwmgr,
1174                                                PPSMC_MSG_PCIeDPM_Enable)),
1175                                "Failed to enable pcie DPM during DPM Start Function!",
1176                                return -EINVAL);
1177        }
1178
1179        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1180                                PHM_PlatformCaps_Falcon_QuickTransition)) {
1181                PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr,
1182                                PPSMC_MSG_EnableACDCGPIOInterrupt)),
1183                                "Failed to enable AC DC GPIO Interrupt!",
1184                                );
1185        }
1186
1187        return 0;
1188}
1189
1190static int smu7_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
1191{
1192        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1193
1194        /* disable SCLK dpm */
1195        if (!data->sclk_dpm_key_disabled) {
1196                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
1197                                "Trying to disable SCLK DPM when DPM is disabled",
1198                                return 0);
1199                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DPM_Disable);
1200        }
1201
1202        /* disable MCLK dpm */
1203        if (!data->mclk_dpm_key_disabled) {
1204                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
1205                                "Trying to disable MCLK DPM when DPM is disabled",
1206                                return 0);
1207                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_Disable);
1208        }
1209
1210        return 0;
1211}
1212
1213static int smu7_stop_dpm(struct pp_hwmgr *hwmgr)
1214{
1215        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1216
1217        /* disable general power management */
1218        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
1219                        GLOBAL_PWRMGT_EN, 0);
1220        /* disable sclk deep sleep */
1221        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
1222                        DYNAMIC_PM_EN, 0);
1223
1224        /* disable PCIE dpm */
1225        if (!data->pcie_dpm_key_disabled) {
1226                PP_ASSERT_WITH_CODE(
1227                                (smum_send_msg_to_smc(hwmgr,
1228                                                PPSMC_MSG_PCIeDPM_Disable) == 0),
1229                                "Failed to disable pcie DPM during DPM Stop Function!",
1230                                return -EINVAL);
1231        }
1232
1233        smu7_disable_sclk_mclk_dpm(hwmgr);
1234
1235        PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
1236                        "Trying to disable voltage DPM when DPM is disabled",
1237                        return 0);
1238
1239        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Voltage_Cntl_Disable);
1240
1241        return 0;
1242}
1243
1244static void smu7_set_dpm_event_sources(struct pp_hwmgr *hwmgr, uint32_t sources)
1245{
1246        bool protection;
1247        enum DPM_EVENT_SRC src;
1248
1249        switch (sources) {
1250        default:
1251                pr_err("Unknown throttling event sources.");
1252                /* fall through */
1253        case 0:
1254                protection = false;
1255                /* src is unused */
1256                break;
1257        case (1 << PHM_AutoThrottleSource_Thermal):
1258                protection = true;
1259                src = DPM_EVENT_SRC_DIGITAL;
1260                break;
1261        case (1 << PHM_AutoThrottleSource_External):
1262                protection = true;
1263                src = DPM_EVENT_SRC_EXTERNAL;
1264                break;
1265        case (1 << PHM_AutoThrottleSource_External) |
1266                        (1 << PHM_AutoThrottleSource_Thermal):
1267                protection = true;
1268                src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
1269                break;
1270        }
1271        /* Order matters - don't enable thermal protection for the wrong source. */
1272        if (protection) {
1273                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
1274                                DPM_EVENT_SRC, src);
1275                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
1276                                THERMAL_PROTECTION_DIS,
1277                                !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1278                                                PHM_PlatformCaps_ThermalController));
1279        } else
1280                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
1281                                THERMAL_PROTECTION_DIS, 1);
1282}
1283
1284static int smu7_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
1285                PHM_AutoThrottleSource source)
1286{
1287        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1288
1289        if (!(data->active_auto_throttle_sources & (1 << source))) {
1290                data->active_auto_throttle_sources |= 1 << source;
1291                smu7_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
1292        }
1293        return 0;
1294}
1295
1296static int smu7_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
1297{
1298        return smu7_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
1299}
1300
1301static int smu7_disable_auto_throttle_source(struct pp_hwmgr *hwmgr,
1302                PHM_AutoThrottleSource source)
1303{
1304        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1305
1306        if (data->active_auto_throttle_sources & (1 << source)) {
1307                data->active_auto_throttle_sources &= ~(1 << source);
1308                smu7_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
1309        }
1310        return 0;
1311}
1312
1313static int smu7_disable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
1314{
1315        return smu7_disable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
1316}
1317
1318static int smu7_pcie_performance_request(struct pp_hwmgr *hwmgr)
1319{
1320        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1321        data->pcie_performance_request = true;
1322
1323        return 0;
1324}
1325
1326static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
1327{
1328        int tmp_result = 0;
1329        int result = 0;
1330
1331        if (smu7_voltage_control(hwmgr)) {
1332                tmp_result = smu7_enable_voltage_control(hwmgr);
1333                PP_ASSERT_WITH_CODE(tmp_result == 0,
1334                                "Failed to enable voltage control!",
1335                                result = tmp_result);
1336
1337                tmp_result = smu7_construct_voltage_tables(hwmgr);
1338                PP_ASSERT_WITH_CODE((0 == tmp_result),
1339                                "Failed to construct voltage tables!",
1340                                result = tmp_result);
1341        }
1342        smum_initialize_mc_reg_table(hwmgr);
1343
1344        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1345                        PHM_PlatformCaps_EngineSpreadSpectrumSupport))
1346                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1347                                GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
1348
1349        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1350                        PHM_PlatformCaps_ThermalController))
1351                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1352                                GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
1353
1354        tmp_result = smu7_program_static_screen_threshold_parameters(hwmgr);
1355        PP_ASSERT_WITH_CODE((0 == tmp_result),
1356                        "Failed to program static screen threshold parameters!",
1357                        result = tmp_result);
1358
1359        tmp_result = smu7_enable_display_gap(hwmgr);
1360        PP_ASSERT_WITH_CODE((0 == tmp_result),
1361                        "Failed to enable display gap!", result = tmp_result);
1362
1363        tmp_result = smu7_program_voting_clients(hwmgr);
1364        PP_ASSERT_WITH_CODE((0 == tmp_result),
1365                        "Failed to program voting clients!", result = tmp_result);
1366
1367        tmp_result = smum_process_firmware_header(hwmgr);
1368        PP_ASSERT_WITH_CODE((0 == tmp_result),
1369                        "Failed to process firmware header!", result = tmp_result);
1370
1371        if (hwmgr->chip_id != CHIP_VEGAM) {
1372                tmp_result = smu7_initial_switch_from_arbf0_to_f1(hwmgr);
1373                PP_ASSERT_WITH_CODE((0 == tmp_result),
1374                                "Failed to initialize switch from ArbF0 to F1!",
1375                                result = tmp_result);
1376        }
1377
1378        result = smu7_setup_default_dpm_tables(hwmgr);
1379        PP_ASSERT_WITH_CODE(0 == result,
1380                        "Failed to setup default DPM tables!", return result);
1381
1382        tmp_result = smum_init_smc_table(hwmgr);
1383        PP_ASSERT_WITH_CODE((0 == tmp_result),
1384                        "Failed to initialize SMC table!", result = tmp_result);
1385
1386        tmp_result = smu7_enable_vrhot_gpio_interrupt(hwmgr);
1387        PP_ASSERT_WITH_CODE((0 == tmp_result),
1388                        "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
1389
1390        smum_send_msg_to_smc(hwmgr, (PPSMC_Msg)PPSMC_NoDisplay);
1391
1392        tmp_result = smu7_enable_sclk_control(hwmgr);
1393        PP_ASSERT_WITH_CODE((0 == tmp_result),
1394                        "Failed to enable SCLK control!", result = tmp_result);
1395
1396        tmp_result = smu7_enable_smc_voltage_controller(hwmgr);
1397        PP_ASSERT_WITH_CODE((0 == tmp_result),
1398                        "Failed to enable voltage control!", result = tmp_result);
1399
1400        tmp_result = smu7_enable_ulv(hwmgr);
1401        PP_ASSERT_WITH_CODE((0 == tmp_result),
1402                        "Failed to enable ULV!", result = tmp_result);
1403
1404        tmp_result = smu7_enable_deep_sleep_master_switch(hwmgr);
1405        PP_ASSERT_WITH_CODE((0 == tmp_result),
1406                        "Failed to enable deep sleep master switch!", result = tmp_result);
1407
1408        tmp_result = smu7_enable_didt_config(hwmgr);
1409        PP_ASSERT_WITH_CODE((tmp_result == 0),
1410                        "Failed to enable deep sleep master switch!", result = tmp_result);
1411
1412        tmp_result = smu7_start_dpm(hwmgr);
1413        PP_ASSERT_WITH_CODE((0 == tmp_result),
1414                        "Failed to start DPM!", result = tmp_result);
1415
1416        tmp_result = smu7_enable_smc_cac(hwmgr);
1417        PP_ASSERT_WITH_CODE((0 == tmp_result),
1418                        "Failed to enable SMC CAC!", result = tmp_result);
1419
1420        tmp_result = smu7_enable_power_containment(hwmgr);
1421        PP_ASSERT_WITH_CODE((0 == tmp_result),
1422                        "Failed to enable power containment!", result = tmp_result);
1423
1424        tmp_result = smu7_power_control_set_level(hwmgr);
1425        PP_ASSERT_WITH_CODE((0 == tmp_result),
1426                        "Failed to power control set level!", result = tmp_result);
1427
1428        tmp_result = smu7_enable_thermal_auto_throttle(hwmgr);
1429        PP_ASSERT_WITH_CODE((0 == tmp_result),
1430                        "Failed to enable thermal auto throttle!", result = tmp_result);
1431
1432        tmp_result = smu7_pcie_performance_request(hwmgr);
1433        PP_ASSERT_WITH_CODE((0 == tmp_result),
1434                        "pcie performance request failed!", result = tmp_result);
1435
1436        return 0;
1437}
1438
1439static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable)
1440{
1441        if (!hwmgr->avfs_supported)
1442                return 0;
1443
1444        if (enable) {
1445                if (!PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
1446                                CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) {
1447                        PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(
1448                                        hwmgr, PPSMC_MSG_EnableAvfs),
1449                                        "Failed to enable AVFS!",
1450                                        return -EINVAL);
1451                }
1452        } else if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
1453                        CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) {
1454                PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(
1455                                hwmgr, PPSMC_MSG_DisableAvfs),
1456                                "Failed to disable AVFS!",
1457                                return -EINVAL);
1458        }
1459
1460        return 0;
1461}
1462
1463static int smu7_update_avfs(struct pp_hwmgr *hwmgr)
1464{
1465        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1466
1467        if (!hwmgr->avfs_supported)
1468                return 0;
1469
1470        if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_VDDC) {
1471                smu7_avfs_control(hwmgr, false);
1472        } else if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
1473                smu7_avfs_control(hwmgr, false);
1474                smu7_avfs_control(hwmgr, true);
1475        } else {
1476                smu7_avfs_control(hwmgr, true);
1477        }
1478
1479        return 0;
1480}
1481
1482int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
1483{
1484        int tmp_result, result = 0;
1485
1486        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1487                        PHM_PlatformCaps_ThermalController))
1488                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1489                                GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 1);
1490
1491        tmp_result = smu7_disable_power_containment(hwmgr);
1492        PP_ASSERT_WITH_CODE((tmp_result == 0),
1493                        "Failed to disable power containment!", result = tmp_result);
1494
1495        tmp_result = smu7_disable_smc_cac(hwmgr);
1496        PP_ASSERT_WITH_CODE((tmp_result == 0),
1497                        "Failed to disable SMC CAC!", result = tmp_result);
1498
1499        tmp_result = smu7_disable_didt_config(hwmgr);
1500        PP_ASSERT_WITH_CODE((tmp_result == 0),
1501                        "Failed to disable DIDT!", result = tmp_result);
1502
1503        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1504                        CG_SPLL_SPREAD_SPECTRUM, SSEN, 0);
1505        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1506                        GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 0);
1507
1508        tmp_result = smu7_disable_thermal_auto_throttle(hwmgr);
1509        PP_ASSERT_WITH_CODE((tmp_result == 0),
1510                        "Failed to disable thermal auto throttle!", result = tmp_result);
1511
1512        tmp_result = smu7_avfs_control(hwmgr, false);
1513        PP_ASSERT_WITH_CODE((tmp_result == 0),
1514                        "Failed to disable AVFS!", result = tmp_result);
1515
1516        tmp_result = smu7_stop_dpm(hwmgr);
1517        PP_ASSERT_WITH_CODE((tmp_result == 0),
1518                        "Failed to stop DPM!", result = tmp_result);
1519
1520        tmp_result = smu7_disable_deep_sleep_master_switch(hwmgr);
1521        PP_ASSERT_WITH_CODE((tmp_result == 0),
1522                        "Failed to disable deep sleep master switch!", result = tmp_result);
1523
1524        tmp_result = smu7_disable_ulv(hwmgr);
1525        PP_ASSERT_WITH_CODE((tmp_result == 0),
1526                        "Failed to disable ULV!", result = tmp_result);
1527
1528        tmp_result = smu7_clear_voting_clients(hwmgr);
1529        PP_ASSERT_WITH_CODE((tmp_result == 0),
1530                        "Failed to clear voting clients!", result = tmp_result);
1531
1532        tmp_result = smu7_reset_to_default(hwmgr);
1533        PP_ASSERT_WITH_CODE((tmp_result == 0),
1534                        "Failed to reset to default!", result = tmp_result);
1535
1536        tmp_result = smu7_force_switch_to_arbf0(hwmgr);
1537        PP_ASSERT_WITH_CODE((tmp_result == 0),
1538                        "Failed to force to switch arbf0!", result = tmp_result);
1539
1540        return result;
1541}
1542
1543int smu7_reset_asic_tasks(struct pp_hwmgr *hwmgr)
1544{
1545
1546        return 0;
1547}
1548
1549static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr)
1550{
1551        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1552        struct phm_ppt_v1_information *table_info =
1553                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1554        struct amdgpu_device *adev = hwmgr->adev;
1555
1556        data->dll_default_on = false;
1557        data->mclk_dpm0_activity_target = 0xa;
1558        data->vddc_vddgfx_delta = 300;
1559        data->static_screen_threshold = SMU7_STATICSCREENTHRESHOLD_DFLT;
1560        data->static_screen_threshold_unit = SMU7_STATICSCREENTHRESHOLDUNIT_DFLT;
1561        data->voting_rights_clients[0] = SMU7_VOTINGRIGHTSCLIENTS_DFLT0;
1562        data->voting_rights_clients[1]= SMU7_VOTINGRIGHTSCLIENTS_DFLT1;
1563        data->voting_rights_clients[2] = SMU7_VOTINGRIGHTSCLIENTS_DFLT2;
1564        data->voting_rights_clients[3]= SMU7_VOTINGRIGHTSCLIENTS_DFLT3;
1565        data->voting_rights_clients[4]= SMU7_VOTINGRIGHTSCLIENTS_DFLT4;
1566        data->voting_rights_clients[5]= SMU7_VOTINGRIGHTSCLIENTS_DFLT5;
1567        data->voting_rights_clients[6]= SMU7_VOTINGRIGHTSCLIENTS_DFLT6;
1568        data->voting_rights_clients[7]= SMU7_VOTINGRIGHTSCLIENTS_DFLT7;
1569
1570        data->mclk_dpm_key_disabled = hwmgr->feature_mask & PP_MCLK_DPM_MASK ? false : true;
1571        data->sclk_dpm_key_disabled = hwmgr->feature_mask & PP_SCLK_DPM_MASK ? false : true;
1572        data->pcie_dpm_key_disabled = hwmgr->feature_mask & PP_PCIE_DPM_MASK ? false : true;
1573        /* need to set voltage control types before EVV patching */
1574        data->voltage_control = SMU7_VOLTAGE_CONTROL_NONE;
1575        data->vddci_control = SMU7_VOLTAGE_CONTROL_NONE;
1576        data->mvdd_control = SMU7_VOLTAGE_CONTROL_NONE;
1577        data->enable_tdc_limit_feature = true;
1578        data->enable_pkg_pwr_tracking_feature = true;
1579        data->force_pcie_gen = PP_PCIEGenInvalid;
1580        data->ulv_supported = hwmgr->feature_mask & PP_ULV_MASK ? true : false;
1581        data->current_profile_setting.bupdate_sclk = 1;
1582        data->current_profile_setting.sclk_up_hyst = 0;
1583        data->current_profile_setting.sclk_down_hyst = 100;
1584        data->current_profile_setting.sclk_activity = SMU7_SCLK_TARGETACTIVITY_DFLT;
1585        data->current_profile_setting.bupdate_mclk = 1;
1586        data->current_profile_setting.mclk_up_hyst = 0;
1587        data->current_profile_setting.mclk_down_hyst = 100;
1588        data->current_profile_setting.mclk_activity = SMU7_MCLK_TARGETACTIVITY_DFLT;
1589        hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
1590        hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
1591        hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
1592
1593        if (hwmgr->chip_id == CHIP_POLARIS12 || hwmgr->is_kicker) {
1594                uint8_t tmp1, tmp2;
1595                uint16_t tmp3 = 0;
1596                atomctrl_get_svi2_info(hwmgr, VOLTAGE_TYPE_VDDC, &tmp1, &tmp2,
1597                                                &tmp3);
1598                tmp3 = (tmp3 >> 5) & 0x3;
1599                data->vddc_phase_shed_control = ((tmp3 << 1) | (tmp3 >> 1)) & 0x3;
1600        } else if (hwmgr->chip_family == AMDGPU_FAMILY_CI) {
1601                data->vddc_phase_shed_control = 1;
1602        } else {
1603                data->vddc_phase_shed_control = 0;
1604        }
1605
1606        if (hwmgr->chip_id  == CHIP_HAWAII) {
1607                data->thermal_temp_setting.temperature_low = 94500;
1608                data->thermal_temp_setting.temperature_high = 95000;
1609                data->thermal_temp_setting.temperature_shutdown = 104000;
1610        } else {
1611                data->thermal_temp_setting.temperature_low = 99500;
1612                data->thermal_temp_setting.temperature_high = 100000;
1613                data->thermal_temp_setting.temperature_shutdown = 104000;
1614        }
1615
1616        data->fast_watermark_threshold = 100;
1617        if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
1618                        VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
1619                data->voltage_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
1620        else if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
1621                        VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT))
1622                data->voltage_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
1623
1624        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1625                        PHM_PlatformCaps_ControlVDDGFX)) {
1626                if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
1627                        VOLTAGE_TYPE_VDDGFX, VOLTAGE_OBJ_SVID2)) {
1628                        data->vdd_gfx_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
1629                }
1630        }
1631
1632        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1633                        PHM_PlatformCaps_EnableMVDDControl)) {
1634                if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
1635                                VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
1636                        data->mvdd_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
1637                else if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
1638                                VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
1639                        data->mvdd_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
1640        }
1641
1642        if (SMU7_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control)
1643                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
1644                        PHM_PlatformCaps_ControlVDDGFX);
1645
1646        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1647                        PHM_PlatformCaps_ControlVDDCI)) {
1648                if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
1649                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
1650                        data->vddci_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
1651                else if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
1652                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
1653                        data->vddci_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
1654        }
1655
1656        if (data->mvdd_control == SMU7_VOLTAGE_CONTROL_NONE)
1657                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
1658                                PHM_PlatformCaps_EnableMVDDControl);
1659
1660        if (data->vddci_control == SMU7_VOLTAGE_CONTROL_NONE)
1661                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
1662                                PHM_PlatformCaps_ControlVDDCI);
1663
1664        if ((hwmgr->pp_table_version != PP_TABLE_V0) && (hwmgr->feature_mask & PP_CLOCK_STRETCH_MASK)
1665                && (table_info->cac_dtp_table->usClockStretchAmount != 0))
1666                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1667                                        PHM_PlatformCaps_ClockStretcher);
1668
1669        data->pcie_gen_performance.max = PP_PCIEGen1;
1670        data->pcie_gen_performance.min = PP_PCIEGen3;
1671        data->pcie_gen_power_saving.max = PP_PCIEGen1;
1672        data->pcie_gen_power_saving.min = PP_PCIEGen3;
1673        data->pcie_lane_performance.max = 0;
1674        data->pcie_lane_performance.min = 16;
1675        data->pcie_lane_power_saving.max = 0;
1676        data->pcie_lane_power_saving.min = 16;
1677
1678
1679        if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
1680                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1681                              PHM_PlatformCaps_UVDPowerGating);
1682        if (adev->pg_flags & AMD_PG_SUPPORT_VCE)
1683                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1684                              PHM_PlatformCaps_VCEPowerGating);
1685}
1686
1687/**
1688* Get Leakage VDDC based on leakage ID.
1689*
1690* @param    hwmgr  the address of the powerplay hardware manager.
1691* @return   always 0
1692*/
1693static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr)
1694{
1695        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1696        uint16_t vv_id;
1697        uint16_t vddc = 0;
1698        uint16_t vddgfx = 0;
1699        uint16_t i, j;
1700        uint32_t sclk = 0;
1701        struct phm_ppt_v1_information *table_info =
1702                        (struct phm_ppt_v1_information *)hwmgr->pptable;
1703        struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = NULL;
1704
1705
1706        for (i = 0; i < SMU7_MAX_LEAKAGE_COUNT; i++) {
1707                vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
1708
1709                if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
1710                        if ((hwmgr->pp_table_version == PP_TABLE_V1)
1711                            && !phm_get_sclk_for_voltage_evv(hwmgr,
1712                                                table_info->vddgfx_lookup_table, vv_id, &sclk)) {
1713                                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1714                                                        PHM_PlatformCaps_ClockStretcher)) {
1715                                        sclk_table = table_info->vdd_dep_on_sclk;
1716
1717                                        for (j = 1; j < sclk_table->count; j++) {
1718                                                if (sclk_table->entries[j].clk == sclk &&
1719                                                                sclk_table->entries[j].cks_enable == 0) {
1720                                                        sclk += 5000;
1721                                                        break;
1722                                                }
1723                                        }
1724                                }
1725                                if (0 == atomctrl_get_voltage_evv_on_sclk
1726                                    (hwmgr, VOLTAGE_TYPE_VDDGFX, sclk,
1727                                     vv_id, &vddgfx)) {
1728                                        /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
1729                                        PP_ASSERT_WITH_CODE((vddgfx < 2000 && vddgfx != 0), "Invalid VDDGFX value!", return -EINVAL);
1730
1731                                        /* the voltage should not be zero nor equal to leakage ID */
1732                                        if (vddgfx != 0 && vddgfx != vv_id) {
1733                                                data->vddcgfx_leakage.actual_voltage[data->vddcgfx_leakage.count] = vddgfx;
1734                                                data->vddcgfx_leakage.leakage_id[data->vddcgfx_leakage.count] = vv_id;
1735                                                data->vddcgfx_leakage.count++;
1736                                        }
1737                                } else {
1738                                        pr_info("Error retrieving EVV voltage value!\n");
1739                                }
1740                        }
1741                } else {
1742                        if ((hwmgr->pp_table_version == PP_TABLE_V0)
1743                                || !phm_get_sclk_for_voltage_evv(hwmgr,
1744                                        table_info->vddc_lookup_table, vv_id, &sclk)) {
1745                                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1746                                                PHM_PlatformCaps_ClockStretcher)) {
1747                                        if (table_info == NULL)
1748                                                return -EINVAL;
1749                                        sclk_table = table_info->vdd_dep_on_sclk;
1750
1751                                        for (j = 1; j < sclk_table->count; j++) {
1752                                                if (sclk_table->entries[j].clk == sclk &&
1753                                                                sclk_table->entries[j].cks_enable == 0) {
1754                                                        sclk += 5000;
1755                                                        break;
1756                                                }
1757                                        }
1758                                }
1759
1760                                if (phm_get_voltage_evv_on_sclk(hwmgr,
1761                                                        VOLTAGE_TYPE_VDDC,
1762                                                        sclk, vv_id, &vddc) == 0) {
1763                                        if (vddc >= 2000 || vddc == 0)
1764                                                return -EINVAL;
1765                                } else {
1766                                        pr_debug("failed to retrieving EVV voltage!\n");
1767                                        continue;
1768                                }
1769
1770                                /* the voltage should not be zero nor equal to leakage ID */
1771                                if (vddc != 0 && vddc != vv_id) {
1772                                        data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = (uint16_t)(vddc);
1773                                        data->vddc_leakage.leakage_id[data->vddc_leakage.count] = vv_id;
1774                                        data->vddc_leakage.count++;
1775                                }
1776                        }
1777                }
1778        }
1779
1780        return 0;
1781}
1782
1783/**
1784 * Change virtual leakage voltage to actual value.
1785 *
1786 * @param     hwmgr  the address of the powerplay hardware manager.
1787 * @param     pointer to changing voltage
1788 * @param     pointer to leakage table
1789 */
1790static void smu7_patch_ppt_v1_with_vdd_leakage(struct pp_hwmgr *hwmgr,
1791                uint16_t *voltage, struct smu7_leakage_voltage *leakage_table)
1792{
1793        uint32_t index;
1794
1795        /* search for leakage voltage ID 0xff01 ~ 0xff08 */
1796        for (index = 0; index < leakage_table->count; index++) {
1797                /* if this voltage matches a leakage voltage ID */
1798                /* patch with actual leakage voltage */
1799                if (leakage_table->leakage_id[index] == *voltage) {
1800                        *voltage = leakage_table->actual_voltage[index];
1801                        break;
1802                }
1803        }
1804
1805        if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
1806                pr_err("Voltage value looks like a Leakage ID but it's not patched \n");
1807}
1808
1809/**
1810* Patch voltage lookup table by EVV leakages.
1811*
1812* @param     hwmgr  the address of the powerplay hardware manager.
1813* @param     pointer to voltage lookup table
1814* @param     pointer to leakage table
1815* @return     always 0
1816*/
1817static int smu7_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
1818                phm_ppt_v1_voltage_lookup_table *lookup_table,
1819                struct smu7_leakage_voltage *leakage_table)
1820{
1821        uint32_t i;
1822
1823        for (i = 0; i < lookup_table->count; i++)
1824                smu7_patch_ppt_v1_with_vdd_leakage(hwmgr,
1825                                &lookup_table->entries[i].us_vdd, leakage_table);
1826
1827        return 0;
1828}
1829
1830static int smu7_patch_clock_voltage_limits_with_vddc_leakage(
1831                struct pp_hwmgr *hwmgr, struct smu7_leakage_voltage *leakage_table,
1832                uint16_t *vddc)
1833{
1834        struct phm_ppt_v1_information *table_info =
1835                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1836        smu7_patch_ppt_v1_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
1837        hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
1838                        table_info->max_clock_voltage_on_dc.vddc;
1839        return 0;
1840}
1841
1842static int smu7_patch_voltage_dependency_tables_with_lookup_table(
1843                struct pp_hwmgr *hwmgr)
1844{
1845        uint8_t entry_id;
1846        uint8_t voltage_id;
1847        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1848        struct phm_ppt_v1_information *table_info =
1849                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1850
1851        struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
1852                        table_info->vdd_dep_on_sclk;
1853        struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
1854                        table_info->vdd_dep_on_mclk;
1855        struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1856                        table_info->mm_dep_table;
1857
1858        if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
1859                for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
1860                        voltage_id = sclk_table->entries[entry_id].vddInd;
1861                        sclk_table->entries[entry_id].vddgfx =
1862                                table_info->vddgfx_lookup_table->entries[voltage_id].us_vdd;
1863                }
1864        } else {
1865                for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
1866                        voltage_id = sclk_table->entries[entry_id].vddInd;
1867                        sclk_table->entries[entry_id].vddc =
1868                                table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
1869                }
1870        }
1871
1872        for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
1873                voltage_id = mclk_table->entries[entry_id].vddInd;
1874                mclk_table->entries[entry_id].vddc =
1875                        table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
1876        }
1877
1878        for (entry_id = 0; entry_id < mm_table->count; ++entry_id) {
1879                voltage_id = mm_table->entries[entry_id].vddcInd;
1880                mm_table->entries[entry_id].vddc =
1881                        table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
1882        }
1883
1884        return 0;
1885
1886}
1887
1888static int phm_add_voltage(struct pp_hwmgr *hwmgr,
1889                        phm_ppt_v1_voltage_lookup_table *look_up_table,
1890                        phm_ppt_v1_voltage_lookup_record *record)
1891{
1892        uint32_t i;
1893
1894        PP_ASSERT_WITH_CODE((NULL != look_up_table),
1895                "Lookup Table empty.", return -EINVAL);
1896        PP_ASSERT_WITH_CODE((0 != look_up_table->count),
1897                "Lookup Table empty.", return -EINVAL);
1898
1899        i = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDGFX);
1900        PP_ASSERT_WITH_CODE((i >= look_up_table->count),
1901                "Lookup Table is full.", return -EINVAL);
1902
1903        /* This is to avoid entering duplicate calculated records. */
1904        for (i = 0; i < look_up_table->count; i++) {
1905                if (look_up_table->entries[i].us_vdd == record->us_vdd) {
1906                        if (look_up_table->entries[i].us_calculated == 1)
1907                                return 0;
1908                        break;
1909                }
1910        }
1911
1912        look_up_table->entries[i].us_calculated = 1;
1913        look_up_table->entries[i].us_vdd = record->us_vdd;
1914        look_up_table->entries[i].us_cac_low = record->us_cac_low;
1915        look_up_table->entries[i].us_cac_mid = record->us_cac_mid;
1916        look_up_table->entries[i].us_cac_high = record->us_cac_high;
1917        /* Only increment the count when we're appending, not replacing duplicate entry. */
1918        if (i == look_up_table->count)
1919                look_up_table->count++;
1920
1921        return 0;
1922}
1923
1924
1925static int smu7_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
1926{
1927        uint8_t entry_id;
1928        struct phm_ppt_v1_voltage_lookup_record v_record;
1929        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1930        struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1931
1932        phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
1933        phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
1934
1935        if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
1936                for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
1937                        if (sclk_table->entries[entry_id].vdd_offset & (1 << 15))
1938                                v_record.us_vdd = sclk_table->entries[entry_id].vddgfx +
1939                                        sclk_table->entries[entry_id].vdd_offset - 0xFFFF;
1940                        else
1941                                v_record.us_vdd = sclk_table->entries[entry_id].vddgfx +
1942                                        sclk_table->entries[entry_id].vdd_offset;
1943
1944                        sclk_table->entries[entry_id].vddc =
1945                                v_record.us_cac_low = v_record.us_cac_mid =
1946                                v_record.us_cac_high = v_record.us_vdd;
1947
1948                        phm_add_voltage(hwmgr, pptable_info->vddc_lookup_table, &v_record);
1949                }
1950
1951                for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
1952                        if (mclk_table->entries[entry_id].vdd_offset & (1 << 15))
1953                                v_record.us_vdd = mclk_table->entries[entry_id].vddc +
1954                                        mclk_table->entries[entry_id].vdd_offset - 0xFFFF;
1955                        else
1956                                v_record.us_vdd = mclk_table->entries[entry_id].vddc +
1957                                        mclk_table->entries[entry_id].vdd_offset;
1958
1959                        mclk_table->entries[entry_id].vddgfx = v_record.us_cac_low =
1960                                v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
1961                        phm_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
1962                }
1963        }
1964        return 0;
1965}
1966
1967static int smu7_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
1968{
1969        uint8_t entry_id;
1970        struct phm_ppt_v1_voltage_lookup_record v_record;
1971        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1972        struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1973        phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
1974
1975        if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
1976                for (entry_id = 0; entry_id < mm_table->count; entry_id++) {
1977                        if (mm_table->entries[entry_id].vddgfx_offset & (1 << 15))
1978                                v_record.us_vdd = mm_table->entries[entry_id].vddc +
1979                                        mm_table->entries[entry_id].vddgfx_offset - 0xFFFF;
1980                        else
1981                                v_record.us_vdd = mm_table->entries[entry_id].vddc +
1982                                        mm_table->entries[entry_id].vddgfx_offset;
1983
1984                        /* Add the calculated VDDGFX to the VDDGFX lookup table */
1985                        mm_table->entries[entry_id].vddgfx = v_record.us_cac_low =
1986                                v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
1987                        phm_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
1988                }
1989        }
1990        return 0;
1991}
1992
1993static int smu7_sort_lookup_table(struct pp_hwmgr *hwmgr,
1994                struct phm_ppt_v1_voltage_lookup_table *lookup_table)
1995{
1996        uint32_t table_size, i, j;
1997        struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
1998        table_size = lookup_table->count;
1999
2000        PP_ASSERT_WITH_CODE(0 != lookup_table->count,
2001                "Lookup table is empty", return -EINVAL);
2002
2003        /* Sorting voltages */
2004        for (i = 0; i < table_size - 1; i++) {
2005                for (j = i + 1; j > 0; j--) {
2006                        if (lookup_table->entries[j].us_vdd <
2007                                        lookup_table->entries[j - 1].us_vdd) {
2008                                tmp_voltage_lookup_record = lookup_table->entries[j - 1];
2009                                lookup_table->entries[j - 1] = lookup_table->entries[j];
2010                                lookup_table->entries[j] = tmp_voltage_lookup_record;
2011                        }
2012                }
2013        }
2014
2015        return 0;
2016}
2017
2018static int smu7_complete_dependency_tables(struct pp_hwmgr *hwmgr)
2019{
2020        int result = 0;
2021        int tmp_result;
2022        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2023        struct phm_ppt_v1_information *table_info =
2024                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2025
2026        if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
2027                tmp_result = smu7_patch_lookup_table_with_leakage(hwmgr,
2028                        table_info->vddgfx_lookup_table, &(data->vddcgfx_leakage));
2029                if (tmp_result != 0)
2030                        result = tmp_result;
2031
2032                smu7_patch_ppt_v1_with_vdd_leakage(hwmgr,
2033                        &table_info->max_clock_voltage_on_dc.vddgfx, &(data->vddcgfx_leakage));
2034        } else {
2035
2036                tmp_result = smu7_patch_lookup_table_with_leakage(hwmgr,
2037                                table_info->vddc_lookup_table, &(data->vddc_leakage));
2038                if (tmp_result)
2039                        result = tmp_result;
2040
2041                tmp_result = smu7_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
2042                                &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
2043                if (tmp_result)
2044                        result = tmp_result;
2045        }
2046
2047        tmp_result = smu7_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
2048        if (tmp_result)
2049                result = tmp_result;
2050
2051        tmp_result = smu7_calc_voltage_dependency_tables(hwmgr);
2052        if (tmp_result)
2053                result = tmp_result;
2054
2055        tmp_result = smu7_calc_mm_voltage_dependency_table(hwmgr);
2056        if (tmp_result)
2057                result = tmp_result;
2058
2059        tmp_result = smu7_sort_lookup_table(hwmgr, table_info->vddgfx_lookup_table);
2060        if (tmp_result)
2061                result = tmp_result;
2062
2063        tmp_result = smu7_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
2064        if (tmp_result)
2065                result = tmp_result;
2066
2067        return result;
2068}
2069
2070static int smu7_set_private_data_based_on_pptable_v1(struct pp_hwmgr *hwmgr)
2071{
2072        struct phm_ppt_v1_information *table_info =
2073                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2074
2075        struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
2076                                                table_info->vdd_dep_on_sclk;
2077        struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
2078                                                table_info->vdd_dep_on_mclk;
2079
2080        PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
2081                "VDD dependency on SCLK table is missing.",
2082                return -EINVAL);
2083        PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
2084                "VDD dependency on SCLK table has to have is missing.",
2085                return -EINVAL);
2086
2087        PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
2088                "VDD dependency on MCLK table is missing",
2089                return -EINVAL);
2090        PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
2091                "VDD dependency on MCLK table has to have is missing.",
2092                return -EINVAL);
2093
2094        table_info->max_clock_voltage_on_ac.sclk =
2095                allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
2096        table_info->max_clock_voltage_on_ac.mclk =
2097                allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
2098        table_info->max_clock_voltage_on_ac.vddc =
2099                allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
2100        table_info->max_clock_voltage_on_ac.vddci =
2101                allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
2102
2103        hwmgr->dyn_state.max_clock_voltage_on_ac.sclk = table_info->max_clock_voltage_on_ac.sclk;
2104        hwmgr->dyn_state.max_clock_voltage_on_ac.mclk = table_info->max_clock_voltage_on_ac.mclk;
2105        hwmgr->dyn_state.max_clock_voltage_on_ac.vddc = table_info->max_clock_voltage_on_ac.vddc;
2106        hwmgr->dyn_state.max_clock_voltage_on_ac.vddci = table_info->max_clock_voltage_on_ac.vddci;
2107
2108        return 0;
2109}
2110
2111static int smu7_patch_voltage_workaround(struct pp_hwmgr *hwmgr)
2112{
2113        struct phm_ppt_v1_information *table_info =
2114                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
2115        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
2116        struct phm_ppt_v1_voltage_lookup_table *lookup_table;
2117        uint32_t i;
2118        uint32_t hw_revision, sub_vendor_id, sub_sys_id;
2119        struct amdgpu_device *adev = hwmgr->adev;
2120
2121        if (table_info != NULL) {
2122                dep_mclk_table = table_info->vdd_dep_on_mclk;
2123                lookup_table = table_info->vddc_lookup_table;
2124        } else
2125                return 0;
2126
2127        hw_revision = adev->pdev->revision;
2128        sub_sys_id = adev->pdev->subsystem_device;
2129        sub_vendor_id = adev->pdev->subsystem_vendor;
2130
2131        if (hwmgr->chip_id == CHIP_POLARIS10 && hw_revision == 0xC7 &&
2132                        ((sub_sys_id == 0xb37 && sub_vendor_id == 0x1002) ||
2133                    (sub_sys_id == 0x4a8 && sub_vendor_id == 0x1043) ||
2134                    (sub_sys_id == 0x9480 && sub_vendor_id == 0x1682))) {
2135                if (lookup_table->entries[dep_mclk_table->entries[dep_mclk_table->count-1].vddInd].us_vdd >= 1000)
2136                        return 0;
2137
2138                for (i = 0; i < lookup_table->count; i++) {
2139                        if (lookup_table->entries[i].us_vdd < 0xff01 && lookup_table->entries[i].us_vdd >= 1000) {
2140                                dep_mclk_table->entries[dep_mclk_table->count-1].vddInd = (uint8_t) i;
2141                                return 0;
2142                        }
2143                }
2144        }
2145        return 0;
2146}
2147
2148static int smu7_thermal_parameter_init(struct pp_hwmgr *hwmgr)
2149{
2150        struct pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
2151        uint32_t temp_reg;
2152        struct phm_ppt_v1_information *table_info =
2153                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2154
2155
2156        if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, &gpio_pin_assignment)) {
2157                temp_reg = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL);
2158                switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) {
2159                case 0:
2160                        temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1);
2161                        break;
2162                case 1:
2163                        temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2);
2164                        break;
2165                case 2:
2166                        temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW, 0x1);
2167                        break;
2168                case 3:
2169                        temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1);
2170                        break;
2171                case 4:
2172                        temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1);
2173                        break;
2174                default:
2175                        break;
2176                }
2177                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL, temp_reg);
2178        }
2179
2180        if (table_info == NULL)
2181                return 0;
2182
2183        if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp != 0 &&
2184                hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode) {
2185                hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMMinLimit =
2186                        (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit;
2187
2188                hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMMaxLimit =
2189                        (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
2190
2191                hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMStep = 1;
2192
2193                hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMaxLimit = 100;
2194
2195                hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMinLimit =
2196                        (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit;
2197
2198                hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMStep = 1;
2199
2200                table_info->cac_dtp_table->usDefaultTargetOperatingTemp = (table_info->cac_dtp_table->usDefaultTargetOperatingTemp >= 50) ?
2201                                                                (table_info->cac_dtp_table->usDefaultTargetOperatingTemp - 50) : 0;
2202
2203                table_info->cac_dtp_table->usOperatingTempMaxLimit = table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
2204                table_info->cac_dtp_table->usOperatingTempStep = 1;
2205                table_info->cac_dtp_table->usOperatingTempHyst = 1;
2206
2207                hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
2208                               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
2209
2210                hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
2211                               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
2212
2213                hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
2214                               table_info->cac_dtp_table->usOperatingTempMinLimit;
2215
2216                hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
2217                               table_info->cac_dtp_table->usOperatingTempMaxLimit;
2218
2219                hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
2220                               table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
2221
2222                hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
2223                               table_info->cac_dtp_table->usOperatingTempStep;
2224
2225                hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
2226                               table_info->cac_dtp_table->usTargetOperatingTemp;
2227                if (hwmgr->feature_mask & PP_OD_FUZZY_FAN_CONTROL_MASK)
2228                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2229                                        PHM_PlatformCaps_ODFuzzyFanControlSupport);
2230        }
2231
2232        return 0;
2233}
2234
2235/**
2236 * Change virtual leakage voltage to actual value.
2237 *
2238 * @param     hwmgr  the address of the powerplay hardware manager.
2239 * @param     pointer to changing voltage
2240 * @param     pointer to leakage table
2241 */
2242static void smu7_patch_ppt_v0_with_vdd_leakage(struct pp_hwmgr *hwmgr,
2243                uint32_t *voltage, struct smu7_leakage_voltage *leakage_table)
2244{
2245        uint32_t index;
2246
2247        /* search for leakage voltage ID 0xff01 ~ 0xff08 */
2248        for (index = 0; index < leakage_table->count; index++) {
2249                /* if this voltage matches a leakage voltage ID */
2250                /* patch with actual leakage voltage */
2251                if (leakage_table->leakage_id[index] == *voltage) {
2252                        *voltage = leakage_table->actual_voltage[index];
2253                        break;
2254                }
2255        }
2256
2257        if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
2258                pr_err("Voltage value looks like a Leakage ID but it's not patched \n");
2259}
2260
2261
2262static int smu7_patch_vddc(struct pp_hwmgr *hwmgr,
2263                              struct phm_clock_voltage_dependency_table *tab)
2264{
2265        uint16_t i;
2266        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2267
2268        if (tab)
2269                for (i = 0; i < tab->count; i++)
2270                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
2271                                                &data->vddc_leakage);
2272
2273        return 0;
2274}
2275
2276static int smu7_patch_vddci(struct pp_hwmgr *hwmgr,
2277                               struct phm_clock_voltage_dependency_table *tab)
2278{
2279        uint16_t i;
2280        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2281
2282        if (tab)
2283                for (i = 0; i < tab->count; i++)
2284                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
2285                                                        &data->vddci_leakage);
2286
2287        return 0;
2288}
2289
2290static int smu7_patch_vce_vddc(struct pp_hwmgr *hwmgr,
2291                                  struct phm_vce_clock_voltage_dependency_table *tab)
2292{
2293        uint16_t i;
2294        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2295
2296        if (tab)
2297                for (i = 0; i < tab->count; i++)
2298                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
2299                                                        &data->vddc_leakage);
2300
2301        return 0;
2302}
2303
2304
2305static int smu7_patch_uvd_vddc(struct pp_hwmgr *hwmgr,
2306                                  struct phm_uvd_clock_voltage_dependency_table *tab)
2307{
2308        uint16_t i;
2309        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2310
2311        if (tab)
2312                for (i = 0; i < tab->count; i++)
2313                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
2314                                                        &data->vddc_leakage);
2315
2316        return 0;
2317}
2318
2319static int smu7_patch_vddc_shed_limit(struct pp_hwmgr *hwmgr,
2320                                         struct phm_phase_shedding_limits_table *tab)
2321{
2322        uint16_t i;
2323        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2324
2325        if (tab)
2326                for (i = 0; i < tab->count; i++)
2327                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].Voltage,
2328                                                        &data->vddc_leakage);
2329
2330        return 0;
2331}
2332
2333static int smu7_patch_samu_vddc(struct pp_hwmgr *hwmgr,
2334                                   struct phm_samu_clock_voltage_dependency_table *tab)
2335{
2336        uint16_t i;
2337        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2338
2339        if (tab)
2340                for (i = 0; i < tab->count; i++)
2341                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
2342                                                        &data->vddc_leakage);
2343
2344        return 0;
2345}
2346
2347static int smu7_patch_acp_vddc(struct pp_hwmgr *hwmgr,
2348                                  struct phm_acp_clock_voltage_dependency_table *tab)
2349{
2350        uint16_t i;
2351        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2352
2353        if (tab)
2354                for (i = 0; i < tab->count; i++)
2355                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
2356                                        &data->vddc_leakage);
2357
2358        return 0;
2359}
2360
2361static int smu7_patch_limits_vddc(struct pp_hwmgr *hwmgr,
2362                                  struct phm_clock_and_voltage_limits *tab)
2363{
2364        uint32_t vddc, vddci;
2365        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2366
2367        if (tab) {
2368                vddc = tab->vddc;
2369                smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &vddc,
2370                                                   &data->vddc_leakage);
2371                tab->vddc = vddc;
2372                vddci = tab->vddci;
2373                smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &vddci,
2374                                                   &data->vddci_leakage);
2375                tab->vddci = vddci;
2376        }
2377
2378        return 0;
2379}
2380
2381static int smu7_patch_cac_vddc(struct pp_hwmgr *hwmgr, struct phm_cac_leakage_table *tab)
2382{
2383        uint32_t i;
2384        uint32_t vddc;
2385        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2386
2387        if (tab) {
2388                for (i = 0; i < tab->count; i++) {
2389                        vddc = (uint32_t)(tab->entries[i].Vddc);
2390                        smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &vddc, &data->vddc_leakage);
2391                        tab->entries[i].Vddc = (uint16_t)vddc;
2392                }
2393        }
2394
2395        return 0;
2396}
2397
2398static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr)
2399{
2400        int tmp;
2401
2402        tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_sclk);
2403        if (tmp)
2404                return -EINVAL;
2405
2406        tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_mclk);
2407        if (tmp)
2408                return -EINVAL;
2409
2410        tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
2411        if (tmp)
2412                return -EINVAL;
2413
2414        tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk);
2415        if (tmp)
2416                return -EINVAL;
2417
2418        tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table);
2419        if (tmp)
2420                return -EINVAL;
2421
2422        tmp = smu7_patch_uvd_vddc(hwmgr, hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
2423        if (tmp)
2424                return -EINVAL;
2425
2426        tmp = smu7_patch_samu_vddc(hwmgr, hwmgr->dyn_state.samu_clock_voltage_dependency_table);
2427        if (tmp)
2428                return -EINVAL;
2429
2430        tmp = smu7_patch_acp_vddc(hwmgr, hwmgr->dyn_state.acp_clock_voltage_dependency_table);
2431        if (tmp)
2432                return -EINVAL;
2433
2434        tmp = smu7_patch_vddc_shed_limit(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table);
2435        if (tmp)
2436                return -EINVAL;
2437
2438        tmp = smu7_patch_limits_vddc(hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_ac);
2439        if (tmp)
2440                return -EINVAL;
2441
2442        tmp = smu7_patch_limits_vddc(hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_dc);
2443        if (tmp)
2444                return -EINVAL;
2445
2446        tmp = smu7_patch_cac_vddc(hwmgr, hwmgr->dyn_state.cac_leakage_table);
2447        if (tmp)
2448                return -EINVAL;
2449
2450        return 0;
2451}
2452
2453
2454static int smu7_set_private_data_based_on_pptable_v0(struct pp_hwmgr *hwmgr)
2455{
2456        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2457
2458        struct phm_clock_voltage_dependency_table *allowed_sclk_vddc_table = hwmgr->dyn_state.vddc_dependency_on_sclk;
2459        struct phm_clock_voltage_dependency_table *allowed_mclk_vddc_table = hwmgr->dyn_state.vddc_dependency_on_mclk;
2460        struct phm_clock_voltage_dependency_table *allowed_mclk_vddci_table = hwmgr->dyn_state.vddci_dependency_on_mclk;
2461
2462        PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table != NULL,
2463                "VDDC dependency on SCLK table is missing. This table is mandatory",
2464                return -EINVAL);
2465        PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table->count >= 1,
2466                "VDDC dependency on SCLK table has to have is missing. This table is mandatory",
2467                return -EINVAL);
2468
2469        PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table != NULL,
2470                "VDDC dependency on MCLK table is missing. This table is mandatory",
2471                return -EINVAL);
2472        PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table->count >= 1,
2473                "VDD dependency on MCLK table has to have is missing. This table is mandatory",
2474                return -EINVAL);
2475
2476        data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vddc_table->entries[0].v;
2477        data->max_vddc_in_pptable = (uint16_t)allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
2478
2479        hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
2480                allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
2481        hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
2482                allowed_mclk_vddc_table->entries[allowed_mclk_vddc_table->count - 1].clk;
2483        hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
2484                allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
2485
2486        if (allowed_mclk_vddci_table != NULL && allowed_mclk_vddci_table->count >= 1) {
2487                data->min_vddci_in_pptable = (uint16_t)allowed_mclk_vddci_table->entries[0].v;
2488                data->max_vddci_in_pptable = (uint16_t)allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
2489        }
2490
2491        if (hwmgr->dyn_state.vddci_dependency_on_mclk != NULL && hwmgr->dyn_state.vddci_dependency_on_mclk->count >= 1)
2492                hwmgr->dyn_state.max_clock_voltage_on_ac.vddci = hwmgr->dyn_state.vddci_dependency_on_mclk->entries[hwmgr->dyn_state.vddci_dependency_on_mclk->count - 1].v;
2493
2494        return 0;
2495}
2496
2497static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
2498{
2499        kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
2500        hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
2501        kfree(hwmgr->backend);
2502        hwmgr->backend = NULL;
2503
2504        return 0;
2505}
2506
2507static int smu7_get_elb_voltages(struct pp_hwmgr *hwmgr)
2508{
2509        uint16_t virtual_voltage_id, vddc, vddci, efuse_voltage_id;
2510        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2511        int i;
2512
2513        if (atomctrl_get_leakage_id_from_efuse(hwmgr, &efuse_voltage_id) == 0) {
2514                for (i = 0; i < SMU7_MAX_LEAKAGE_COUNT; i++) {
2515                        virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
2516                        if (atomctrl_get_leakage_vddc_base_on_leakage(hwmgr, &vddc, &vddci,
2517                                                                virtual_voltage_id,
2518                                                                efuse_voltage_id) == 0) {
2519                                if (vddc != 0 && vddc != virtual_voltage_id) {
2520                                        data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = vddc;
2521                                        data->vddc_leakage.leakage_id[data->vddc_leakage.count] = virtual_voltage_id;
2522                                        data->vddc_leakage.count++;
2523                                }
2524                                if (vddci != 0 && vddci != virtual_voltage_id) {
2525                                        data->vddci_leakage.actual_voltage[data->vddci_leakage.count] = vddci;
2526                                        data->vddci_leakage.leakage_id[data->vddci_leakage.count] = virtual_voltage_id;
2527                                        data->vddci_leakage.count++;
2528                                }
2529                        }
2530                }
2531        }
2532        return 0;
2533}
2534
2535static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
2536{
2537        struct smu7_hwmgr *data;
2538        int result = 0;
2539
2540        data = kzalloc(sizeof(struct smu7_hwmgr), GFP_KERNEL);
2541        if (data == NULL)
2542                return -ENOMEM;
2543
2544        hwmgr->backend = data;
2545        smu7_patch_voltage_workaround(hwmgr);
2546        smu7_init_dpm_defaults(hwmgr);
2547
2548        /* Get leakage voltage based on leakage ID. */
2549        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2550                        PHM_PlatformCaps_EVV)) {
2551                result = smu7_get_evv_voltages(hwmgr);
2552                if (result) {
2553                        pr_info("Get EVV Voltage Failed.  Abort Driver loading!\n");
2554                        return -EINVAL;
2555                }
2556        } else {
2557                smu7_get_elb_voltages(hwmgr);
2558        }
2559
2560        if (hwmgr->pp_table_version == PP_TABLE_V1) {
2561                smu7_complete_dependency_tables(hwmgr);
2562                smu7_set_private_data_based_on_pptable_v1(hwmgr);
2563        } else if (hwmgr->pp_table_version == PP_TABLE_V0) {
2564                smu7_patch_dependency_tables_with_leakage(hwmgr);
2565                smu7_set_private_data_based_on_pptable_v0(hwmgr);
2566        }
2567
2568        /* Initalize Dynamic State Adjustment Rule Settings */
2569        result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
2570
2571        if (0 == result) {
2572                struct amdgpu_device *adev = hwmgr->adev;
2573
2574                data->is_tlu_enabled = false;
2575
2576                hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
2577                                                        SMU7_MAX_HARDWARE_POWERLEVELS;
2578                hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
2579                hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
2580
2581                data->pcie_gen_cap = adev->pm.pcie_gen_mask;
2582                if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
2583                        data->pcie_spc_cap = 20;
2584                data->pcie_lane_cap = adev->pm.pcie_mlw_mask;
2585
2586                hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
2587/* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
2588                hwmgr->platform_descriptor.clockStep.engineClock = 500;
2589                hwmgr->platform_descriptor.clockStep.memoryClock = 500;
2590                smu7_thermal_parameter_init(hwmgr);
2591        } else {
2592                /* Ignore return value in here, we are cleaning up a mess. */
2593                smu7_hwmgr_backend_fini(hwmgr);
2594        }
2595
2596        return 0;
2597}
2598
2599static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr)
2600{
2601        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2602        uint32_t level, tmp;
2603
2604        if (!data->pcie_dpm_key_disabled) {
2605                if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
2606                        level = 0;
2607                        tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
2608                        while (tmp >>= 1)
2609                                level++;
2610
2611                        if (level)
2612                                smum_send_msg_to_smc_with_parameter(hwmgr,
2613                                                PPSMC_MSG_PCIeDPM_ForceLevel, level);
2614                }
2615        }
2616
2617        if (!data->sclk_dpm_key_disabled) {
2618                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
2619                        level = 0;
2620                        tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
2621                        while (tmp >>= 1)
2622                                level++;
2623
2624                        if (level)
2625                                smum_send_msg_to_smc_with_parameter(hwmgr,
2626                                                PPSMC_MSG_SCLKDPM_SetEnabledMask,
2627                                                (1 << level));
2628                }
2629        }
2630
2631        if (!data->mclk_dpm_key_disabled) {
2632                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
2633                        level = 0;
2634                        tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
2635                        while (tmp >>= 1)
2636                                level++;
2637
2638                        if (level)
2639                                smum_send_msg_to_smc_with_parameter(hwmgr,
2640                                                PPSMC_MSG_MCLKDPM_SetEnabledMask,
2641                                                (1 << level));
2642                }
2643        }
2644
2645        return 0;
2646}
2647
2648static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
2649{
2650        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2651
2652        if (hwmgr->pp_table_version == PP_TABLE_V1)
2653                phm_apply_dal_min_voltage_request(hwmgr);
2654/* TO DO  for v0 iceland and Ci*/
2655
2656        if (!data->sclk_dpm_key_disabled) {
2657                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
2658                        smum_send_msg_to_smc_with_parameter(hwmgr,
2659                                        PPSMC_MSG_SCLKDPM_SetEnabledMask,
2660                                        data->dpm_level_enable_mask.sclk_dpm_enable_mask);
2661        }
2662
2663        if (!data->mclk_dpm_key_disabled) {
2664                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask)
2665                        smum_send_msg_to_smc_with_parameter(hwmgr,
2666                                        PPSMC_MSG_MCLKDPM_SetEnabledMask,
2667                                        data->dpm_level_enable_mask.mclk_dpm_enable_mask);
2668        }
2669
2670        return 0;
2671}
2672
2673static int smu7_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
2674{
2675        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2676
2677        if (!smum_is_dpm_running(hwmgr))
2678                return -EINVAL;
2679
2680        if (!data->pcie_dpm_key_disabled) {
2681                smum_send_msg_to_smc(hwmgr,
2682                                PPSMC_MSG_PCIeDPM_UnForceLevel);
2683        }
2684
2685        return smu7_upload_dpm_level_enable_mask(hwmgr);
2686}
2687
2688static int smu7_force_dpm_lowest(struct pp_hwmgr *hwmgr)
2689{
2690        struct smu7_hwmgr *data =
2691                        (struct smu7_hwmgr *)(hwmgr->backend);
2692        uint32_t level;
2693
2694        if (!data->sclk_dpm_key_disabled)
2695                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
2696                        level = phm_get_lowest_enabled_level(hwmgr,
2697                                                              data->dpm_level_enable_mask.sclk_dpm_enable_mask);
2698                        smum_send_msg_to_smc_with_parameter(hwmgr,
2699                                                            PPSMC_MSG_SCLKDPM_SetEnabledMask,
2700                                                            (1 << level));
2701
2702        }
2703
2704        if (!data->mclk_dpm_key_disabled) {
2705                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
2706                        level = phm_get_lowest_enabled_level(hwmgr,
2707                                                              data->dpm_level_enable_mask.mclk_dpm_enable_mask);
2708                        smum_send_msg_to_smc_with_parameter(hwmgr,
2709                                                            PPSMC_MSG_MCLKDPM_SetEnabledMask,
2710                                                            (1 << level));
2711                }
2712        }
2713
2714        if (!data->pcie_dpm_key_disabled) {
2715                if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
2716                        level = phm_get_lowest_enabled_level(hwmgr,
2717                                                              data->dpm_level_enable_mask.pcie_dpm_enable_mask);
2718                        smum_send_msg_to_smc_with_parameter(hwmgr,
2719                                                            PPSMC_MSG_PCIeDPM_ForceLevel,
2720                                                            (level));
2721                }
2722        }
2723
2724        return 0;
2725}
2726
2727static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level,
2728                                uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *pcie_mask)
2729{
2730        uint32_t percentage;
2731        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2732        struct smu7_dpm_table *golden_dpm_table = &data->golden_dpm_table;
2733        int32_t tmp_mclk;
2734        int32_t tmp_sclk;
2735        int32_t count;
2736
2737        if (golden_dpm_table->mclk_table.count < 1)
2738                return -EINVAL;
2739
2740        percentage = 100 * golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count - 1].value /
2741                        golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value;
2742
2743        if (golden_dpm_table->mclk_table.count == 1) {
2744                percentage = 70;
2745                tmp_mclk = golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value;
2746                *mclk_mask = golden_dpm_table->mclk_table.count - 1;
2747        } else {
2748                tmp_mclk = golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 2].value;
2749                *mclk_mask = golden_dpm_table->mclk_table.count - 2;
2750        }
2751
2752        tmp_sclk = tmp_mclk * percentage / 100;
2753
2754        if (hwmgr->pp_table_version == PP_TABLE_V0) {
2755                for (count = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1;
2756                        count >= 0; count--) {
2757                        if (tmp_sclk >= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk) {
2758                                tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk;
2759                                *sclk_mask = count;
2760                                break;
2761                        }
2762                }
2763                if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2764                        *sclk_mask = 0;
2765                        tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].clk;
2766                }
2767
2768                if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
2769                        *sclk_mask = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1;
2770        } else if (hwmgr->pp_table_version == PP_TABLE_V1) {
2771                struct phm_ppt_v1_information *table_info =
2772                                (struct phm_ppt_v1_information *)(hwmgr->pptable);
2773
2774                for (count = table_info->vdd_dep_on_sclk->count-1; count >= 0; count--) {
2775                        if (tmp_sclk >= table_info->vdd_dep_on_sclk->entries[count].clk) {
2776                                tmp_sclk = table_info->vdd_dep_on_sclk->entries[count].clk;
2777                                *sclk_mask = count;
2778                                break;
2779                        }
2780                }
2781                if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2782                        *sclk_mask = 0;
2783                        tmp_sclk =  table_info->vdd_dep_on_sclk->entries[0].clk;
2784                }
2785
2786                if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
2787                        *sclk_mask = table_info->vdd_dep_on_sclk->count - 1;
2788        }
2789
2790        if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK)
2791                *mclk_mask = 0;
2792        else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
2793                *mclk_mask = golden_dpm_table->mclk_table.count - 1;
2794
2795        *pcie_mask = data->dpm_table.pcie_speed_table.count - 1;
2796        hwmgr->pstate_sclk = tmp_sclk;
2797        hwmgr->pstate_mclk = tmp_mclk;
2798
2799        return 0;
2800}
2801
2802static int smu7_force_dpm_level(struct pp_hwmgr *hwmgr,
2803                                enum amd_dpm_forced_level level)
2804{
2805        int ret = 0;
2806        uint32_t sclk_mask = 0;
2807        uint32_t mclk_mask = 0;
2808        uint32_t pcie_mask = 0;
2809
2810        if (hwmgr->pstate_sclk == 0)
2811                smu7_get_profiling_clk(hwmgr, level, &sclk_mask, &mclk_mask, &pcie_mask);
2812
2813        switch (level) {
2814        case AMD_DPM_FORCED_LEVEL_HIGH:
2815                ret = smu7_force_dpm_highest(hwmgr);
2816                break;
2817        case AMD_DPM_FORCED_LEVEL_LOW:
2818                ret = smu7_force_dpm_lowest(hwmgr);
2819                break;
2820        case AMD_DPM_FORCED_LEVEL_AUTO:
2821                ret = smu7_unforce_dpm_levels(hwmgr);
2822                break;
2823        case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
2824        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
2825        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
2826        case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
2827                ret = smu7_get_profiling_clk(hwmgr, level, &sclk_mask, &mclk_mask, &pcie_mask);
2828                if (ret)
2829                        return ret;
2830                smu7_force_clock_level(hwmgr, PP_SCLK, 1<<sclk_mask);
2831                smu7_force_clock_level(hwmgr, PP_MCLK, 1<<mclk_mask);
2832                smu7_force_clock_level(hwmgr, PP_PCIE, 1<<pcie_mask);
2833                break;
2834        case AMD_DPM_FORCED_LEVEL_MANUAL:
2835        case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
2836        default:
2837                break;
2838        }
2839
2840        if (!ret) {
2841                if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
2842                        smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
2843                else if (level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
2844                        smu7_fan_ctrl_reset_fan_speed_to_default(hwmgr);
2845        }
2846        return ret;
2847}
2848
2849static int smu7_get_power_state_size(struct pp_hwmgr *hwmgr)
2850{
2851        return sizeof(struct smu7_power_state);
2852}
2853
2854static int smu7_vblank_too_short(struct pp_hwmgr *hwmgr,
2855                                 uint32_t vblank_time_us)
2856{
2857        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2858        uint32_t switch_limit_us;
2859
2860        switch (hwmgr->chip_id) {
2861        case CHIP_POLARIS10:
2862        case CHIP_POLARIS11:
2863        case CHIP_POLARIS12:
2864                if (hwmgr->is_kicker)
2865                        switch_limit_us = data->is_memory_gddr5 ? 450 : 150;
2866                else
2867                        switch_limit_us = data->is_memory_gddr5 ? 190 : 150;
2868                break;
2869        case CHIP_VEGAM:
2870                switch_limit_us = 30;
2871                break;
2872        default:
2873                switch_limit_us = data->is_memory_gddr5 ? 450 : 150;
2874                break;
2875        }
2876
2877        if (vblank_time_us < switch_limit_us)
2878                return true;
2879        else
2880                return false;
2881}
2882
2883static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
2884                                struct pp_power_state *request_ps,
2885                        const struct pp_power_state *current_ps)
2886{
2887        struct amdgpu_device *adev = hwmgr->adev;
2888        struct smu7_power_state *smu7_ps =
2889                                cast_phw_smu7_power_state(&request_ps->hardware);
2890        uint32_t sclk;
2891        uint32_t mclk;
2892        struct PP_Clocks minimum_clocks = {0};
2893        bool disable_mclk_switching;
2894        bool disable_mclk_switching_for_frame_lock;
2895        const struct phm_clock_and_voltage_limits *max_limits;
2896        uint32_t i;
2897        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2898        struct phm_ppt_v1_information *table_info =
2899                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2900        int32_t count;
2901        int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
2902
2903        data->battery_state = (PP_StateUILabel_Battery ==
2904                        request_ps->classification.ui_label);
2905
2906        PP_ASSERT_WITH_CODE(smu7_ps->performance_level_count == 2,
2907                                 "VI should always have 2 performance levels",
2908                                );
2909
2910        max_limits = adev->pm.ac_power ?
2911                        &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
2912                        &(hwmgr->dyn_state.max_clock_voltage_on_dc);
2913
2914        /* Cap clock DPM tables at DC MAX if it is in DC. */
2915        if (!adev->pm.ac_power) {
2916                for (i = 0; i < smu7_ps->performance_level_count; i++) {
2917                        if (smu7_ps->performance_levels[i].memory_clock > max_limits->mclk)
2918                                smu7_ps->performance_levels[i].memory_clock = max_limits->mclk;
2919                        if (smu7_ps->performance_levels[i].engine_clock > max_limits->sclk)
2920                                smu7_ps->performance_levels[i].engine_clock = max_limits->sclk;
2921                }
2922        }
2923
2924        minimum_clocks.engineClock = hwmgr->display_config->min_core_set_clock;
2925        minimum_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
2926
2927        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2928                        PHM_PlatformCaps_StablePState)) {
2929                max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
2930                stable_pstate_sclk = (max_limits->sclk * 75) / 100;
2931
2932                for (count = table_info->vdd_dep_on_sclk->count - 1;
2933                                count >= 0; count--) {
2934                        if (stable_pstate_sclk >=
2935                                        table_info->vdd_dep_on_sclk->entries[count].clk) {
2936                                stable_pstate_sclk =
2937                                                table_info->vdd_dep_on_sclk->entries[count].clk;
2938                                break;
2939                        }
2940                }
2941
2942                if (count < 0)
2943                        stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
2944
2945                stable_pstate_mclk = max_limits->mclk;
2946
2947                minimum_clocks.engineClock = stable_pstate_sclk;
2948                minimum_clocks.memoryClock = stable_pstate_mclk;
2949        }
2950
2951        disable_mclk_switching_for_frame_lock = phm_cap_enabled(
2952                                    hwmgr->platform_descriptor.platformCaps,
2953                                    PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
2954
2955
2956        if (hwmgr->display_config->num_display == 0)
2957                disable_mclk_switching = false;
2958        else
2959                disable_mclk_switching = ((1 < hwmgr->display_config->num_display) ||
2960                                          disable_mclk_switching_for_frame_lock ||
2961                                          smu7_vblank_too_short(hwmgr, hwmgr->display_config->min_vblank_time));
2962
2963        sclk = smu7_ps->performance_levels[0].engine_clock;
2964        mclk = smu7_ps->performance_levels[0].memory_clock;
2965
2966        if (disable_mclk_switching)
2967                mclk = smu7_ps->performance_levels
2968                [smu7_ps->performance_level_count - 1].memory_clock;
2969
2970        if (sclk < minimum_clocks.engineClock)
2971                sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
2972                                max_limits->sclk : minimum_clocks.engineClock;
2973
2974        if (mclk < minimum_clocks.memoryClock)
2975                mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
2976                                max_limits->mclk : minimum_clocks.memoryClock;
2977
2978        smu7_ps->performance_levels[0].engine_clock = sclk;
2979        smu7_ps->performance_levels[0].memory_clock = mclk;
2980
2981        smu7_ps->performance_levels[1].engine_clock =
2982                (smu7_ps->performance_levels[1].engine_clock >=
2983                                smu7_ps->performance_levels[0].engine_clock) ?
2984                                                smu7_ps->performance_levels[1].engine_clock :
2985                                                smu7_ps->performance_levels[0].engine_clock;
2986
2987        if (disable_mclk_switching) {
2988                if (mclk < smu7_ps->performance_levels[1].memory_clock)
2989                        mclk = smu7_ps->performance_levels[1].memory_clock;
2990
2991                smu7_ps->performance_levels[0].memory_clock = mclk;
2992                smu7_ps->performance_levels[1].memory_clock = mclk;
2993        } else {
2994                if (smu7_ps->performance_levels[1].memory_clock <
2995                                smu7_ps->performance_levels[0].memory_clock)
2996                        smu7_ps->performance_levels[1].memory_clock =
2997                                        smu7_ps->performance_levels[0].memory_clock;
2998        }
2999
3000        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3001                        PHM_PlatformCaps_StablePState)) {
3002                for (i = 0; i < smu7_ps->performance_level_count; i++) {
3003                        smu7_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
3004                        smu7_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
3005                        smu7_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
3006                        smu7_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
3007                }
3008        }
3009        return 0;
3010}
3011
3012
3013static uint32_t smu7_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
3014{
3015        struct pp_power_state  *ps;
3016        struct smu7_power_state  *smu7_ps;
3017
3018        if (hwmgr == NULL)
3019                return -EINVAL;
3020
3021        ps = hwmgr->request_ps;
3022
3023        if (ps == NULL)
3024                return -EINVAL;
3025
3026        smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
3027
3028        if (low)
3029                return smu7_ps->performance_levels[0].memory_clock;
3030        else
3031                return smu7_ps->performance_levels
3032                                [smu7_ps->performance_level_count-1].memory_clock;
3033}
3034
3035static uint32_t smu7_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
3036{
3037        struct pp_power_state  *ps;
3038        struct smu7_power_state  *smu7_ps;
3039
3040        if (hwmgr == NULL)
3041                return -EINVAL;
3042
3043        ps = hwmgr->request_ps;
3044
3045        if (ps == NULL)
3046                return -EINVAL;
3047
3048        smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
3049
3050        if (low)
3051                return smu7_ps->performance_levels[0].engine_clock;
3052        else
3053                return smu7_ps->performance_levels
3054                                [smu7_ps->performance_level_count-1].engine_clock;
3055}
3056
3057static int smu7_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
3058                                        struct pp_hw_power_state *hw_ps)
3059{
3060        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3061        struct smu7_power_state *ps = (struct smu7_power_state *)hw_ps;
3062        ATOM_FIRMWARE_INFO_V2_2 *fw_info;
3063        uint16_t size;
3064        uint8_t frev, crev;
3065        int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
3066
3067        /* First retrieve the Boot clocks and VDDC from the firmware info table.
3068         * We assume here that fw_info is unchanged if this call fails.
3069         */
3070        fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)smu_atom_get_data_table(hwmgr->adev, index,
3071                        &size, &frev, &crev);
3072        if (!fw_info)
3073                /* During a test, there is no firmware info table. */
3074                return 0;
3075
3076        /* Patch the state. */
3077        data->vbios_boot_state.sclk_bootup_value =
3078                        le32_to_cpu(fw_info->ulDefaultEngineClock);
3079        data->vbios_boot_state.mclk_bootup_value =
3080                        le32_to_cpu(fw_info->ulDefaultMemoryClock);
3081        data->vbios_boot_state.mvdd_bootup_value =
3082                        le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
3083        data->vbios_boot_state.vddc_bootup_value =
3084                        le16_to_cpu(fw_info->usBootUpVDDCVoltage);
3085        data->vbios_boot_state.vddci_bootup_value =
3086                        le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
3087        data->vbios_boot_state.pcie_gen_bootup_value =
3088                        smu7_get_current_pcie_speed(hwmgr);
3089
3090        data->vbios_boot_state.pcie_lane_bootup_value =
3091                        (uint16_t)smu7_get_current_pcie_lane_number(hwmgr);
3092
3093        /* set boot power state */
3094        ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
3095        ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
3096        ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
3097        ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
3098
3099        return 0;
3100}
3101
3102static int smu7_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
3103{
3104        int result;
3105        unsigned long ret = 0;
3106
3107        if (hwmgr->pp_table_version == PP_TABLE_V0) {
3108                result = pp_tables_get_num_of_entries(hwmgr, &ret);
3109                return result ? 0 : ret;
3110        } else if (hwmgr->pp_table_version == PP_TABLE_V1) {
3111                result = get_number_of_powerplay_table_entries_v1_0(hwmgr);
3112                return result;
3113        }
3114        return 0;
3115}
3116
3117static int smu7_get_pp_table_entry_callback_func_v1(struct pp_hwmgr *hwmgr,
3118                void *state, struct pp_power_state *power_state,
3119                void *pp_table, uint32_t classification_flag)
3120{
3121        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3122        struct smu7_power_state  *smu7_power_state =
3123                        (struct smu7_power_state *)(&(power_state->hardware));
3124        struct smu7_performance_level *performance_level;
3125        ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
3126        ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
3127                        (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
3128        PPTable_Generic_SubTable_Header *sclk_dep_table =
3129                        (PPTable_Generic_SubTable_Header *)
3130                        (((unsigned long)powerplay_table) +
3131                                le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
3132
3133        ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
3134                        (ATOM_Tonga_MCLK_Dependency_Table *)
3135                        (((unsigned long)powerplay_table) +
3136                                le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
3137
3138        /* The following fields are not initialized here: id orderedList allStatesList */
3139        power_state->classification.ui_label =
3140                        (le16_to_cpu(state_entry->usClassification) &
3141                        ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
3142                        ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
3143        power_state->classification.flags = classification_flag;
3144        /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
3145
3146        power_state->classification.temporary_state = false;
3147        power_state->classification.to_be_deleted = false;
3148
3149        power_state->validation.disallowOnDC =
3150                        (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
3151                                        ATOM_Tonga_DISALLOW_ON_DC));
3152
3153        power_state->pcie.lanes = 0;
3154
3155        power_state->display.disableFrameModulation = false;
3156        power_state->display.limitRefreshrate = false;
3157        power_state->display.enableVariBright =
3158                        (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
3159                                        ATOM_Tonga_ENABLE_VARIBRIGHT));
3160
3161        power_state->validation.supportedPowerLevels = 0;
3162        power_state->uvd_clocks.VCLK = 0;
3163        power_state->uvd_clocks.DCLK = 0;
3164        power_state->temperatures.min = 0;
3165        power_state->temperatures.max = 0;
3166
3167        performance_level = &(smu7_power_state->performance_levels
3168                        [smu7_power_state->performance_level_count++]);
3169
3170        PP_ASSERT_WITH_CODE(
3171                        (smu7_power_state->performance_level_count < smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_GRAPHICS)),
3172                        "Performance levels exceeds SMC limit!",
3173                        return -EINVAL);
3174
3175        PP_ASSERT_WITH_CODE(
3176                        (smu7_power_state->performance_level_count <=
3177                                        hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
3178                        "Performance levels exceeds Driver limit!",
3179                        return -EINVAL);
3180
3181        /* Performance levels are arranged from low to high. */
3182        performance_level->memory_clock = mclk_dep_table->entries
3183                        [state_entry->ucMemoryClockIndexLow].ulMclk;
3184        if (sclk_dep_table->ucRevId == 0)
3185                performance_level->engine_clock = ((ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table)->entries
3186                        [state_entry->ucEngineClockIndexLow].ulSclk;
3187        else if (sclk_dep_table->ucRevId == 1)
3188                performance_level->engine_clock = ((ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table)->entries
3189                        [state_entry->ucEngineClockIndexLow].ulSclk;
3190        performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
3191                        state_entry->ucPCIEGenLow);
3192        performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
3193                        state_entry->ucPCIELaneLow);
3194
3195        performance_level = &(smu7_power_state->performance_levels
3196                        [smu7_power_state->performance_level_count++]);
3197        performance_level->memory_clock = mclk_dep_table->entries
3198                        [state_entry->ucMemoryClockIndexHigh].ulMclk;
3199
3200        if (sclk_dep_table->ucRevId == 0)
3201                performance_level->engine_clock = ((ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table)->entries
3202                        [state_entry->ucEngineClockIndexHigh].ulSclk;
3203        else if (sclk_dep_table->ucRevId == 1)
3204                performance_level->engine_clock = ((ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table)->entries
3205                        [state_entry->ucEngineClockIndexHigh].ulSclk;
3206
3207        performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
3208                        state_entry->ucPCIEGenHigh);
3209        performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
3210                        state_entry->ucPCIELaneHigh);
3211
3212        return 0;
3213}
3214
3215static int smu7_get_pp_table_entry_v1(struct pp_hwmgr *hwmgr,
3216                unsigned long entry_index, struct pp_power_state *state)
3217{
3218        int result;
3219        struct smu7_power_state *ps;
3220        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3221        struct phm_ppt_v1_information *table_info =
3222                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
3223        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
3224                        table_info->vdd_dep_on_mclk;
3225
3226        state->hardware.magic = PHM_VIslands_Magic;
3227
3228        ps = (struct smu7_power_state *)(&state->hardware);
3229
3230        result = get_powerplay_table_entry_v1_0(hwmgr, entry_index, state,
3231                        smu7_get_pp_table_entry_callback_func_v1);
3232
3233        /* This is the earliest time we have all the dependency table and the VBIOS boot state
3234         * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
3235         * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
3236         */
3237        if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
3238                if (dep_mclk_table->entries[0].clk !=
3239                                data->vbios_boot_state.mclk_bootup_value)
3240                        pr_debug("Single MCLK entry VDDCI/MCLK dependency table "
3241                                        "does not match VBIOS boot MCLK level");
3242                if (dep_mclk_table->entries[0].vddci !=
3243                                data->vbios_boot_state.vddci_bootup_value)
3244                        pr_debug("Single VDDCI entry VDDCI/MCLK dependency table "
3245                                        "does not match VBIOS boot VDDCI level");
3246        }
3247
3248        /* set DC compatible flag if this state supports DC */
3249        if (!state->validation.disallowOnDC)
3250                ps->dc_compatible = true;
3251
3252        if (state->classification.flags & PP_StateClassificationFlag_ACPI)
3253                data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
3254
3255        ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
3256        ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
3257
3258        if (!result) {
3259                uint32_t i;
3260
3261                switch (state->classification.ui_label) {
3262                case PP_StateUILabel_Performance:
3263                        data->use_pcie_performance_levels = true;
3264                        for (i = 0; i < ps->performance_level_count; i++) {
3265                                if (data->pcie_gen_performance.max <
3266                                                ps->performance_levels[i].pcie_gen)
3267                                        data->pcie_gen_performance.max =
3268                                                        ps->performance_levels[i].pcie_gen;
3269
3270                                if (data->pcie_gen_performance.min >
3271                                                ps->performance_levels[i].pcie_gen)
3272                                        data->pcie_gen_performance.min =
3273                                                        ps->performance_levels[i].pcie_gen;
3274
3275                                if (data->pcie_lane_performance.max <
3276                                                ps->performance_levels[i].pcie_lane)
3277                                        data->pcie_lane_performance.max =
3278                                                        ps->performance_levels[i].pcie_lane;
3279                                if (data->pcie_lane_performance.min >
3280                                                ps->performance_levels[i].pcie_lane)
3281                                        data->pcie_lane_performance.min =
3282                                                        ps->performance_levels[i].pcie_lane;
3283                        }
3284                        break;
3285                case PP_StateUILabel_Battery:
3286                        data->use_pcie_power_saving_levels = true;
3287
3288                        for (i = 0; i < ps->performance_level_count; i++) {
3289                                if (data->pcie_gen_power_saving.max <
3290                                                ps->performance_levels[i].pcie_gen)
3291                                        data->pcie_gen_power_saving.max =
3292                                                        ps->performance_levels[i].pcie_gen;
3293
3294                                if (data->pcie_gen_power_saving.min >
3295                                                ps->performance_levels[i].pcie_gen)
3296                                        data->pcie_gen_power_saving.min =
3297                                                        ps->performance_levels[i].pcie_gen;
3298
3299                                if (data->pcie_lane_power_saving.max <
3300                                                ps->performance_levels[i].pcie_lane)
3301                                        data->pcie_lane_power_saving.max =
3302                                                        ps->performance_levels[i].pcie_lane;
3303
3304                                if (data->pcie_lane_power_saving.min >
3305                                                ps->performance_levels[i].pcie_lane)
3306                                        data->pcie_lane_power_saving.min =
3307                                                        ps->performance_levels[i].pcie_lane;
3308                        }
3309                        break;
3310                default:
3311                        break;
3312                }
3313        }
3314        return 0;
3315}
3316
3317static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr,
3318                                        struct pp_hw_power_state *power_state,
3319                                        unsigned int index, const void *clock_info)
3320{
3321        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3322        struct smu7_power_state  *ps = cast_phw_smu7_power_state(power_state);
3323        const ATOM_PPLIB_CI_CLOCK_INFO *visland_clk_info = clock_info;
3324        struct smu7_performance_level *performance_level;
3325        uint32_t engine_clock, memory_clock;
3326        uint16_t pcie_gen_from_bios;
3327
3328        engine_clock = visland_clk_info->ucEngineClockHigh << 16 | visland_clk_info->usEngineClockLow;
3329        memory_clock = visland_clk_info->ucMemoryClockHigh << 16 | visland_clk_info->usMemoryClockLow;
3330
3331        if (!(data->mc_micro_code_feature & DISABLE_MC_LOADMICROCODE) && memory_clock > data->highest_mclk)
3332                data->highest_mclk = memory_clock;
3333
3334        PP_ASSERT_WITH_CODE(
3335                        (ps->performance_level_count < smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_GRAPHICS)),
3336                        "Performance levels exceeds SMC limit!",
3337                        return -EINVAL);
3338
3339        PP_ASSERT_WITH_CODE(
3340                        (ps->performance_level_count <
3341                                        hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
3342                        "Performance levels exceeds Driver limit, Skip!",
3343                        return 0);
3344
3345        performance_level = &(ps->performance_levels
3346                        [ps->performance_level_count++]);
3347
3348        /* Performance levels are arranged from low to high. */
3349        performance_level->memory_clock = memory_clock;
3350        performance_level->engine_clock = engine_clock;
3351
3352        pcie_gen_from_bios = visland_clk_info->ucPCIEGen;
3353
3354        performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap, pcie_gen_from_bios);
3355        performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap, visland_clk_info->usPCIELane);
3356
3357        return 0;
3358}
3359
3360static int smu7_get_pp_table_entry_v0(struct pp_hwmgr *hwmgr,
3361                unsigned long entry_index, struct pp_power_state *state)
3362{
3363        int result;
3364        struct smu7_power_state *ps;
3365        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3366        struct phm_clock_voltage_dependency_table *dep_mclk_table =
3367                        hwmgr->dyn_state.vddci_dependency_on_mclk;
3368
3369        memset(&state->hardware, 0x00, sizeof(struct pp_hw_power_state));
3370
3371        state->hardware.magic = PHM_VIslands_Magic;
3372
3373        ps = (struct smu7_power_state *)(&state->hardware);
3374
3375        result = pp_tables_get_entry(hwmgr, entry_index, state,
3376                        smu7_get_pp_table_entry_callback_func_v0);
3377
3378        /*
3379         * This is the earliest time we have all the dependency table
3380         * and the VBIOS boot state as
3381         * PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot
3382         * state if there is only one VDDCI/MCLK level, check if it's
3383         * the same as VBIOS boot state
3384         */
3385        if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
3386                if (dep_mclk_table->entries[0].clk !=
3387                                data->vbios_boot_state.mclk_bootup_value)
3388                        pr_debug("Single MCLK entry VDDCI/MCLK dependency table "
3389                                        "does not match VBIOS boot MCLK level");
3390                if (dep_mclk_table->entries[0].v !=
3391                                data->vbios_boot_state.vddci_bootup_value)
3392                        pr_debug("Single VDDCI entry VDDCI/MCLK dependency table "
3393                                        "does not match VBIOS boot VDDCI level");
3394        }
3395
3396        /* set DC compatible flag if this state supports DC */
3397        if (!state->validation.disallowOnDC)
3398                ps->dc_compatible = true;
3399
3400        if (state->classification.flags & PP_StateClassificationFlag_ACPI)
3401                data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
3402
3403        ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
3404        ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
3405
3406        if (!result) {
3407                uint32_t i;
3408
3409                switch (state->classification.ui_label) {
3410                case PP_StateUILabel_Performance:
3411                        data->use_pcie_performance_levels = true;
3412
3413                        for (i = 0; i < ps->performance_level_count; i++) {
3414                                if (data->pcie_gen_performance.max <
3415                                                ps->performance_levels[i].pcie_gen)
3416                                        data->pcie_gen_performance.max =
3417                                                        ps->performance_levels[i].pcie_gen;
3418
3419                                if (data->pcie_gen_performance.min >
3420                                                ps->performance_levels[i].pcie_gen)
3421                                        data->pcie_gen_performance.min =
3422                                                        ps->performance_levels[i].pcie_gen;
3423
3424                                if (data->pcie_lane_performance.max <
3425                                                ps->performance_levels[i].pcie_lane)
3426                                        data->pcie_lane_performance.max =
3427                                                        ps->performance_levels[i].pcie_lane;
3428
3429                                if (data->pcie_lane_performance.min >
3430                                                ps->performance_levels[i].pcie_lane)
3431                                        data->pcie_lane_performance.min =
3432                                                        ps->performance_levels[i].pcie_lane;
3433                        }
3434                        break;
3435                case PP_StateUILabel_Battery:
3436                        data->use_pcie_power_saving_levels = true;
3437
3438                        for (i = 0; i < ps->performance_level_count; i++) {
3439                                if (data->pcie_gen_power_saving.max <
3440                                                ps->performance_levels[i].pcie_gen)
3441                                        data->pcie_gen_power_saving.max =
3442                                                        ps->performance_levels[i].pcie_gen;
3443
3444                                if (data->pcie_gen_power_saving.min >
3445                                                ps->performance_levels[i].pcie_gen)
3446                                        data->pcie_gen_power_saving.min =
3447                                                        ps->performance_levels[i].pcie_gen;
3448
3449                                if (data->pcie_lane_power_saving.max <
3450                                                ps->performance_levels[i].pcie_lane)
3451                                        data->pcie_lane_power_saving.max =
3452                                                        ps->performance_levels[i].pcie_lane;
3453
3454                                if (data->pcie_lane_power_saving.min >
3455                                                ps->performance_levels[i].pcie_lane)
3456                                        data->pcie_lane_power_saving.min =
3457                                                        ps->performance_levels[i].pcie_lane;
3458                        }
3459                        break;
3460                default:
3461                        break;
3462                }
3463        }
3464        return 0;
3465}
3466
3467static int smu7_get_pp_table_entry(struct pp_hwmgr *hwmgr,
3468                unsigned long entry_index, struct pp_power_state *state)
3469{
3470        if (hwmgr->pp_table_version == PP_TABLE_V0)
3471                return smu7_get_pp_table_entry_v0(hwmgr, entry_index, state);
3472        else if (hwmgr->pp_table_version == PP_TABLE_V1)
3473                return smu7_get_pp_table_entry_v1(hwmgr, entry_index, state);
3474
3475        return 0;
3476}
3477
3478static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr, u32 *query)
3479{
3480        int i;
3481        u32 tmp = 0;
3482
3483        if (!query)
3484                return -EINVAL;
3485
3486        smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetCurrPkgPwr, 0);
3487        tmp = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
3488        *query = tmp;
3489
3490        if (tmp != 0)
3491                return 0;
3492
3493        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PmStatusLogStart);
3494        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3495                                                        ixSMU_PM_STATUS_95, 0);
3496
3497        for (i = 0; i < 10; i++) {
3498                msleep(500);
3499                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PmStatusLogSample);
3500                tmp = cgs_read_ind_register(hwmgr->device,
3501                                                CGS_IND_REG__SMC,
3502                                                ixSMU_PM_STATUS_95);
3503                if (tmp != 0)
3504                        break;
3505        }
3506        *query = tmp;
3507
3508        return 0;
3509}
3510
3511static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx,
3512                            void *value, int *size)
3513{
3514        uint32_t sclk, mclk, activity_percent;
3515        uint32_t offset, val_vid;
3516        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3517
3518        /* size must be at least 4 bytes for all sensors */
3519        if (*size < 4)
3520                return -EINVAL;
3521
3522        switch (idx) {
3523        case AMDGPU_PP_SENSOR_GFX_SCLK:
3524                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetSclkFrequency);
3525                sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
3526                *((uint32_t *)value) = sclk;
3527                *size = 4;
3528                return 0;
3529        case AMDGPU_PP_SENSOR_GFX_MCLK:
3530                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetMclkFrequency);
3531                mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
3532                *((uint32_t *)value) = mclk;
3533                *size = 4;
3534                return 0;
3535        case AMDGPU_PP_SENSOR_GPU_LOAD:
3536        case AMDGPU_PP_SENSOR_MEM_LOAD:
3537                offset = data->soft_regs_start + smum_get_offsetof(hwmgr,
3538                                                                SMU_SoftRegisters,
3539                                                                (idx == AMDGPU_PP_SENSOR_GPU_LOAD) ?
3540                                                                AverageGraphicsActivity:
3541                                                                AverageMemoryActivity);
3542
3543                activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
3544                activity_percent += 0x80;
3545                activity_percent >>= 8;
3546                *((uint32_t *)value) = activity_percent > 100 ? 100 : activity_percent;
3547                *size = 4;
3548                return 0;
3549        case AMDGPU_PP_SENSOR_GPU_TEMP:
3550                *((uint32_t *)value) = smu7_thermal_get_temperature(hwmgr);
3551                *size = 4;
3552                return 0;
3553        case AMDGPU_PP_SENSOR_UVD_POWER:
3554                *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
3555                *size = 4;
3556                return 0;
3557        case AMDGPU_PP_SENSOR_VCE_POWER:
3558                *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
3559                *size = 4;
3560                return 0;
3561        case AMDGPU_PP_SENSOR_GPU_POWER:
3562                return smu7_get_gpu_power(hwmgr, (uint32_t *)value);
3563        case AMDGPU_PP_SENSOR_VDDGFX:
3564                if ((data->vr_config & 0xff) == 0x2)
3565                        val_vid = PHM_READ_INDIRECT_FIELD(hwmgr->device,
3566                                        CGS_IND_REG__SMC, PWR_SVI2_STATUS, PLANE2_VID);
3567                else
3568                        val_vid = PHM_READ_INDIRECT_FIELD(hwmgr->device,
3569                                        CGS_IND_REG__SMC, PWR_SVI2_STATUS, PLANE1_VID);
3570
3571                *((uint32_t *)value) = (uint32_t)convert_to_vddc(val_vid);
3572                return 0;
3573        default:
3574                return -EINVAL;
3575        }
3576}
3577
3578static int smu7_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
3579{
3580        const struct phm_set_power_state_input *states =
3581                        (const struct phm_set_power_state_input *)input;
3582        const struct smu7_power_state *smu7_ps =
3583                        cast_const_phw_smu7_power_state(states->pnew_state);
3584        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3585        struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
3586        uint32_t sclk = smu7_ps->performance_levels
3587                        [smu7_ps->performance_level_count - 1].engine_clock;
3588        struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
3589        uint32_t mclk = smu7_ps->performance_levels
3590                        [smu7_ps->performance_level_count - 1].memory_clock;
3591        struct PP_Clocks min_clocks = {0};
3592        uint32_t i;
3593
3594        for (i = 0; i < sclk_table->count; i++) {
3595                if (sclk == sclk_table->dpm_levels[i].value)
3596                        break;
3597        }
3598
3599        if (i >= sclk_table->count) {
3600                if (sclk > sclk_table->dpm_levels[i-1].value) {
3601                        data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
3602                        sclk_table->dpm_levels[i-1].value = sclk;
3603                }
3604        } else {
3605        /* TODO: Check SCLK in DAL's minimum clocks
3606         * in case DeepSleep divider update is required.
3607         */
3608                if (data->display_timing.min_clock_in_sr != min_clocks.engineClockInSR &&
3609                        (min_clocks.engineClockInSR >= SMU7_MINIMUM_ENGINE_CLOCK ||
3610                                data->display_timing.min_clock_in_sr >= SMU7_MINIMUM_ENGINE_CLOCK))
3611                        data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
3612        }
3613
3614        for (i = 0; i < mclk_table->count; i++) {
3615                if (mclk == mclk_table->dpm_levels[i].value)
3616                        break;
3617        }
3618
3619        if (i >= mclk_table->count) {
3620                if (mclk > mclk_table->dpm_levels[i-1].value) {
3621                        data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
3622                        mclk_table->dpm_levels[i-1].value = mclk;
3623                }
3624        }
3625
3626        if (data->display_timing.num_existing_displays != hwmgr->display_config->num_display)
3627                data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
3628
3629        return 0;
3630}
3631
3632static uint16_t smu7_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
3633                const struct smu7_power_state *smu7_ps)
3634{
3635        uint32_t i;
3636        uint32_t sclk, max_sclk = 0;
3637        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3638        struct smu7_dpm_table *dpm_table = &data->dpm_table;
3639
3640        for (i = 0; i < smu7_ps->performance_level_count; i++) {
3641                sclk = smu7_ps->performance_levels[i].engine_clock;
3642                if (max_sclk < sclk)
3643                        max_sclk = sclk;
3644        }
3645
3646        for (i = 0; i < dpm_table->sclk_table.count; i++) {
3647                if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
3648                        return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
3649                                        dpm_table->pcie_speed_table.dpm_levels
3650                                        [dpm_table->pcie_speed_table.count - 1].value :
3651                                        dpm_table->pcie_speed_table.dpm_levels[i].value);
3652        }
3653
3654        return 0;
3655}
3656
3657static int smu7_request_link_speed_change_before_state_change(
3658                struct pp_hwmgr *hwmgr, const void *input)
3659{
3660        const struct phm_set_power_state_input *states =
3661                        (const struct phm_set_power_state_input *)input;
3662        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3663        const struct smu7_power_state *smu7_nps =
3664                        cast_const_phw_smu7_power_state(states->pnew_state);
3665        const struct smu7_power_state *polaris10_cps =
3666                        cast_const_phw_smu7_power_state(states->pcurrent_state);
3667
3668        uint16_t target_link_speed = smu7_get_maximum_link_speed(hwmgr, smu7_nps);
3669        uint16_t current_link_speed;
3670
3671        if (data->force_pcie_gen == PP_PCIEGenInvalid)
3672                current_link_speed = smu7_get_maximum_link_speed(hwmgr, polaris10_cps);
3673        else
3674                current_link_speed = data->force_pcie_gen;
3675
3676        data->force_pcie_gen = PP_PCIEGenInvalid;
3677        data->pspp_notify_required = false;
3678
3679        if (target_link_speed > current_link_speed) {
3680                switch (target_link_speed) {
3681#ifdef CONFIG_ACPI
3682                case PP_PCIEGen3:
3683                        if (0 == amdgpu_acpi_pcie_performance_request(hwmgr->adev, PCIE_PERF_REQ_GEN3, false))
3684                                break;
3685                        data->force_pcie_gen = PP_PCIEGen2;
3686                        if (current_link_speed == PP_PCIEGen2)
3687                                break;
3688                        /* fall through */
3689                case PP_PCIEGen2:
3690                        if (0 == amdgpu_acpi_pcie_performance_request(hwmgr->adev, PCIE_PERF_REQ_GEN2, false))
3691                                break;
3692#endif
3693                        /* fall through */
3694                default:
3695                        data->force_pcie_gen = smu7_get_current_pcie_speed(hwmgr);
3696                        break;
3697                }
3698        } else {
3699                if (target_link_speed < current_link_speed)
3700                        data->pspp_notify_required = true;
3701        }
3702
3703        return 0;
3704}
3705
3706static int smu7_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
3707{
3708        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3709
3710        if (0 == data->need_update_smu7_dpm_table)
3711                return 0;
3712
3713        if ((0 == data->sclk_dpm_key_disabled) &&
3714                (data->need_update_smu7_dpm_table &
3715                        (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
3716                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
3717                                "Trying to freeze SCLK DPM when DPM is disabled",
3718                                );
3719                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
3720                                PPSMC_MSG_SCLKDPM_FreezeLevel),
3721                                "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
3722                                return -EINVAL);
3723        }
3724
3725        if ((0 == data->mclk_dpm_key_disabled) &&
3726                (data->need_update_smu7_dpm_table &
3727                 DPMTABLE_OD_UPDATE_MCLK)) {
3728                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
3729                                "Trying to freeze MCLK DPM when DPM is disabled",
3730                                );
3731                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
3732                                PPSMC_MSG_MCLKDPM_FreezeLevel),
3733                                "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
3734                                return -EINVAL);
3735        }
3736
3737        return 0;
3738}
3739
3740static int smu7_populate_and_upload_sclk_mclk_dpm_levels(
3741                struct pp_hwmgr *hwmgr, const void *input)
3742{
3743        int result = 0;
3744        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3745        struct smu7_dpm_table *dpm_table = &data->dpm_table;
3746        uint32_t count;
3747        struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table);
3748        struct phm_odn_clock_levels *odn_sclk_table = &(odn_table->odn_core_clock_dpm_levels);
3749        struct phm_odn_clock_levels *odn_mclk_table = &(odn_table->odn_memory_clock_dpm_levels);
3750
3751        if (0 == data->need_update_smu7_dpm_table)
3752                return 0;
3753
3754        if (hwmgr->od_enabled && data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
3755                for (count = 0; count < dpm_table->sclk_table.count; count++) {
3756                        dpm_table->sclk_table.dpm_levels[count].enabled = odn_sclk_table->entries[count].enabled;
3757                        dpm_table->sclk_table.dpm_levels[count].value = odn_sclk_table->entries[count].clock;
3758                }
3759        }
3760
3761        if (hwmgr->od_enabled && data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
3762                for (count = 0; count < dpm_table->mclk_table.count; count++) {
3763                        dpm_table->mclk_table.dpm_levels[count].enabled = odn_mclk_table->entries[count].enabled;
3764                        dpm_table->mclk_table.dpm_levels[count].value = odn_mclk_table->entries[count].clock;
3765                }
3766        }
3767
3768        if (data->need_update_smu7_dpm_table &
3769                        (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
3770                result = smum_populate_all_graphic_levels(hwmgr);
3771                PP_ASSERT_WITH_CODE((0 == result),
3772                                "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
3773                                return result);
3774        }
3775
3776        if (data->need_update_smu7_dpm_table &
3777                        (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
3778                /*populate MCLK dpm table to SMU7 */
3779                result = smum_populate_all_memory_levels(hwmgr);
3780                PP_ASSERT_WITH_CODE((0 == result),
3781                                "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
3782                                return result);
3783        }
3784
3785        return result;
3786}
3787
3788static int smu7_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
3789                          struct smu7_single_dpm_table *dpm_table,
3790                        uint32_t low_limit, uint32_t high_limit)
3791{
3792        uint32_t i;
3793
3794        for (i = 0; i < dpm_table->count; i++) {
3795        /*skip the trim if od is enabled*/
3796                if (!hwmgr->od_enabled && (dpm_table->dpm_levels[i].value < low_limit
3797                        || dpm_table->dpm_levels[i].value > high_limit))
3798                        dpm_table->dpm_levels[i].enabled = false;
3799                else
3800                        dpm_table->dpm_levels[i].enabled = true;
3801        }
3802
3803        return 0;
3804}
3805
3806static int smu7_trim_dpm_states(struct pp_hwmgr *hwmgr,
3807                const struct smu7_power_state *smu7_ps)
3808{
3809        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3810        uint32_t high_limit_count;
3811
3812        PP_ASSERT_WITH_CODE((smu7_ps->performance_level_count >= 1),
3813                        "power state did not have any performance level",
3814                        return -EINVAL);
3815
3816        high_limit_count = (1 == smu7_ps->performance_level_count) ? 0 : 1;
3817
3818        smu7_trim_single_dpm_states(hwmgr,
3819                        &(data->dpm_table.sclk_table),
3820                        smu7_ps->performance_levels[0].engine_clock,
3821                        smu7_ps->performance_levels[high_limit_count].engine_clock);
3822
3823        smu7_trim_single_dpm_states(hwmgr,
3824                        &(data->dpm_table.mclk_table),
3825                        smu7_ps->performance_levels[0].memory_clock,
3826                        smu7_ps->performance_levels[high_limit_count].memory_clock);
3827
3828        return 0;
3829}
3830
3831static int smu7_generate_dpm_level_enable_mask(
3832                struct pp_hwmgr *hwmgr, const void *input)
3833{
3834        int result = 0;
3835        const struct phm_set_power_state_input *states =
3836                        (const struct phm_set_power_state_input *)input;
3837        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3838        const struct smu7_power_state *smu7_ps =
3839                        cast_const_phw_smu7_power_state(states->pnew_state);
3840
3841
3842        result = smu7_trim_dpm_states(hwmgr, smu7_ps);
3843        if (result)
3844                return result;
3845
3846        data->dpm_level_enable_mask.sclk_dpm_enable_mask =
3847                        phm_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
3848        data->dpm_level_enable_mask.mclk_dpm_enable_mask =
3849                        phm_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
3850        data->dpm_level_enable_mask.pcie_dpm_enable_mask =
3851                        phm_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
3852
3853        return 0;
3854}
3855
3856static int smu7_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
3857{
3858        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3859
3860        if (0 == data->need_update_smu7_dpm_table)
3861                return 0;
3862
3863        if ((0 == data->sclk_dpm_key_disabled) &&
3864                (data->need_update_smu7_dpm_table &
3865                (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
3866
3867                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
3868                                "Trying to Unfreeze SCLK DPM when DPM is disabled",
3869                                );
3870                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
3871                                PPSMC_MSG_SCLKDPM_UnfreezeLevel),
3872                        "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
3873                        return -EINVAL);
3874        }
3875
3876        if ((0 == data->mclk_dpm_key_disabled) &&
3877                (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
3878
3879                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
3880                                "Trying to Unfreeze MCLK DPM when DPM is disabled",
3881                                );
3882                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
3883                                PPSMC_MSG_MCLKDPM_UnfreezeLevel),
3884                    "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
3885                    return -EINVAL);
3886        }
3887
3888        data->need_update_smu7_dpm_table &= DPMTABLE_OD_UPDATE_VDDC;
3889
3890        return 0;
3891}
3892
3893static int smu7_notify_link_speed_change_after_state_change(
3894                struct pp_hwmgr *hwmgr, const void *input)
3895{
3896        const struct phm_set_power_state_input *states =
3897                        (const struct phm_set_power_state_input *)input;
3898        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3899        const struct smu7_power_state *smu7_ps =
3900                        cast_const_phw_smu7_power_state(states->pnew_state);
3901        uint16_t target_link_speed = smu7_get_maximum_link_speed(hwmgr, smu7_ps);
3902        uint8_t  request;
3903
3904        if (data->pspp_notify_required) {
3905                if (target_link_speed == PP_PCIEGen3)
3906                        request = PCIE_PERF_REQ_GEN3;
3907                else if (target_link_speed == PP_PCIEGen2)
3908                        request = PCIE_PERF_REQ_GEN2;
3909                else
3910                        request = PCIE_PERF_REQ_GEN1;
3911
3912                if (request == PCIE_PERF_REQ_GEN1 &&
3913                                smu7_get_current_pcie_speed(hwmgr) > 0)
3914                        return 0;
3915
3916#ifdef CONFIG_ACPI
3917                if (amdgpu_acpi_pcie_performance_request(hwmgr->adev, request, false)) {
3918                        if (PP_PCIEGen2 == target_link_speed)
3919                                pr_info("PSPP request to switch to Gen2 from Gen3 Failed!");
3920                        else
3921                                pr_info("PSPP request to switch to Gen1 from Gen2 Failed!");
3922                }
3923#endif
3924        }
3925
3926        return 0;
3927}
3928
3929static int smu7_notify_smc_display(struct pp_hwmgr *hwmgr)
3930{
3931        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3932
3933        if (hwmgr->feature_mask & PP_VBI_TIME_SUPPORT_MASK) {
3934                if (hwmgr->chip_id == CHIP_VEGAM)
3935                        smum_send_msg_to_smc_with_parameter(hwmgr,
3936                                        (PPSMC_Msg)PPSMC_MSG_SetVBITimeout_VEGAM, data->frame_time_x2);
3937                else
3938                        smum_send_msg_to_smc_with_parameter(hwmgr,
3939                                        (PPSMC_Msg)PPSMC_MSG_SetVBITimeout, data->frame_time_x2);
3940        }
3941        return (smum_send_msg_to_smc(hwmgr, (PPSMC_Msg)PPSMC_HasDisplay) == 0) ?  0 : -EINVAL;
3942}
3943
3944static int smu7_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
3945{
3946        int tmp_result, result = 0;
3947        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3948
3949        tmp_result = smu7_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
3950        PP_ASSERT_WITH_CODE((0 == tmp_result),
3951                        "Failed to find DPM states clocks in DPM table!",
3952                        result = tmp_result);
3953
3954        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3955                        PHM_PlatformCaps_PCIEPerformanceRequest)) {
3956                tmp_result =
3957                        smu7_request_link_speed_change_before_state_change(hwmgr, input);
3958                PP_ASSERT_WITH_CODE((0 == tmp_result),
3959                                "Failed to request link speed change before state change!",
3960                                result = tmp_result);
3961        }
3962
3963        tmp_result = smu7_freeze_sclk_mclk_dpm(hwmgr);
3964        PP_ASSERT_WITH_CODE((0 == tmp_result),
3965                        "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
3966
3967        tmp_result = smu7_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
3968        PP_ASSERT_WITH_CODE((0 == tmp_result),
3969                        "Failed to populate and upload SCLK MCLK DPM levels!",
3970                        result = tmp_result);
3971
3972        tmp_result = smu7_update_avfs(hwmgr);
3973        PP_ASSERT_WITH_CODE((0 == tmp_result),
3974                        "Failed to update avfs voltages!",
3975                        result = tmp_result);
3976
3977        tmp_result = smu7_generate_dpm_level_enable_mask(hwmgr, input);
3978        PP_ASSERT_WITH_CODE((0 == tmp_result),
3979                        "Failed to generate DPM level enabled mask!",
3980                        result = tmp_result);
3981
3982        tmp_result = smum_update_sclk_threshold(hwmgr);
3983        PP_ASSERT_WITH_CODE((0 == tmp_result),
3984                        "Failed to update SCLK threshold!",
3985                        result = tmp_result);
3986
3987        tmp_result = smu7_notify_smc_display(hwmgr);
3988        PP_ASSERT_WITH_CODE((0 == tmp_result),
3989                        "Failed to notify smc display settings!",
3990                        result = tmp_result);
3991
3992        tmp_result = smu7_unfreeze_sclk_mclk_dpm(hwmgr);
3993        PP_ASSERT_WITH_CODE((0 == tmp_result),
3994                        "Failed to unfreeze SCLK MCLK DPM!",
3995                        result = tmp_result);
3996
3997        tmp_result = smu7_upload_dpm_level_enable_mask(hwmgr);
3998        PP_ASSERT_WITH_CODE((0 == tmp_result),
3999                        "Failed to upload DPM level enabled mask!",
4000                        result = tmp_result);
4001
4002        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4003                        PHM_PlatformCaps_PCIEPerformanceRequest)) {
4004                tmp_result =
4005                        smu7_notify_link_speed_change_after_state_change(hwmgr, input);
4006                PP_ASSERT_WITH_CODE((0 == tmp_result),
4007                                "Failed to notify link speed change after state change!",
4008                                result = tmp_result);
4009        }
4010        data->apply_optimized_settings = false;
4011        return result;
4012}
4013
4014static int smu7_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
4015{
4016        hwmgr->thermal_controller.
4017        advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
4018
4019        return smum_send_msg_to_smc_with_parameter(hwmgr,
4020                        PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
4021}
4022
4023static int
4024smu7_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
4025{
4026        PPSMC_Msg msg = has_display ? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
4027
4028        return (smum_send_msg_to_smc(hwmgr, msg) == 0) ?  0 : -1;
4029}
4030
4031static int
4032smu7_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
4033{
4034        if (hwmgr->display_config->num_display > 1 &&
4035                        !hwmgr->display_config->multi_monitor_in_sync)
4036                smu7_notify_smc_display_change(hwmgr, false);
4037
4038        return 0;
4039}
4040
4041/**
4042* Programs the display gap
4043*
4044* @param    hwmgr  the address of the powerplay hardware manager.
4045* @return   always OK
4046*/
4047static int smu7_program_display_gap(struct pp_hwmgr *hwmgr)
4048{
4049        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4050        uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
4051        uint32_t display_gap2;
4052        uint32_t pre_vbi_time_in_us;
4053        uint32_t frame_time_in_us;
4054        uint32_t ref_clock, refresh_rate;
4055
4056        display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, DISP_GAP, (hwmgr->display_config->num_display > 0) ? DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
4057        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap);
4058
4059        ref_clock =  amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
4060        refresh_rate = hwmgr->display_config->vrefresh;
4061
4062        if (0 == refresh_rate)
4063                refresh_rate = 60;
4064
4065        frame_time_in_us = 1000000 / refresh_rate;
4066
4067        pre_vbi_time_in_us = frame_time_in_us - 200 - hwmgr->display_config->min_vblank_time;
4068
4069        data->frame_time_x2 = frame_time_in_us * 2 / 100;
4070
4071        display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
4072
4073        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
4074
4075        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4076                        data->soft_regs_start + smum_get_offsetof(hwmgr,
4077                                                        SMU_SoftRegisters,
4078                                                        PreVBlankGap), 0x64);
4079
4080        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4081                        data->soft_regs_start + smum_get_offsetof(hwmgr,
4082                                                        SMU_SoftRegisters,
4083                                                        VBlankTimeout),
4084                                        (frame_time_in_us - pre_vbi_time_in_us));
4085
4086        return 0;
4087}
4088
4089static int smu7_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
4090{
4091        return smu7_program_display_gap(hwmgr);
4092}
4093
4094/**
4095*  Set maximum target operating fan output RPM
4096*
4097* @param    hwmgr:  the address of the powerplay hardware manager.
4098* @param    usMaxFanRpm:  max operating fan RPM value.
4099* @return   The response that came from the SMC.
4100*/
4101static int smu7_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_rpm)
4102{
4103        hwmgr->thermal_controller.
4104        advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
4105
4106        return smum_send_msg_to_smc_with_parameter(hwmgr,
4107                        PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
4108}
4109
4110static const struct amdgpu_irq_src_funcs smu7_irq_funcs = {
4111        .process = phm_irq_process,
4112};
4113
4114static int smu7_register_irq_handlers(struct pp_hwmgr *hwmgr)
4115{
4116        struct amdgpu_irq_src *source =
4117                kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL);
4118
4119        if (!source)
4120                return -ENOMEM;
4121
4122        source->funcs = &smu7_irq_funcs;
4123
4124        amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
4125                        AMDGPU_IRQ_CLIENTID_LEGACY,
4126                        VISLANDS30_IV_SRCID_CG_TSS_THERMAL_LOW_TO_HIGH,
4127                        source);
4128        amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
4129                        AMDGPU_IRQ_CLIENTID_LEGACY,
4130                        VISLANDS30_IV_SRCID_CG_TSS_THERMAL_HIGH_TO_LOW,
4131                        source);
4132
4133        /* Register CTF(GPIO_19) interrupt */
4134        amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
4135                        AMDGPU_IRQ_CLIENTID_LEGACY,
4136                        VISLANDS30_IV_SRCID_GPIO_19,
4137                        source);
4138
4139        return 0;
4140}
4141
4142static bool
4143smu7_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
4144{
4145        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4146        bool is_update_required = false;
4147
4148        if (data->display_timing.num_existing_displays != hwmgr->display_config->num_display)
4149                is_update_required = true;
4150
4151        if (data->display_timing.vrefresh != hwmgr->display_config->vrefresh)
4152                is_update_required = true;
4153
4154        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
4155                if (data->display_timing.min_clock_in_sr != hwmgr->display_config->min_core_set_clock_in_sr &&
4156                        (data->display_timing.min_clock_in_sr >= SMU7_MINIMUM_ENGINE_CLOCK ||
4157                        hwmgr->display_config->min_core_set_clock_in_sr >= SMU7_MINIMUM_ENGINE_CLOCK))
4158                        is_update_required = true;
4159        }
4160        return is_update_required;
4161}
4162
4163static inline bool smu7_are_power_levels_equal(const struct smu7_performance_level *pl1,
4164                                                           const struct smu7_performance_level *pl2)
4165{
4166        return ((pl1->memory_clock == pl2->memory_clock) &&
4167                  (pl1->engine_clock == pl2->engine_clock) &&
4168                  (pl1->pcie_gen == pl2->pcie_gen) &&
4169                  (pl1->pcie_lane == pl2->pcie_lane));
4170}
4171
4172static int smu7_check_states_equal(struct pp_hwmgr *hwmgr,
4173                const struct pp_hw_power_state *pstate1,
4174                const struct pp_hw_power_state *pstate2, bool *equal)
4175{
4176        const struct smu7_power_state *psa;
4177        const struct smu7_power_state *psb;
4178        int i;
4179        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4180
4181        if (pstate1 == NULL || pstate2 == NULL || equal == NULL)
4182                return -EINVAL;
4183
4184        psa = cast_const_phw_smu7_power_state(pstate1);
4185        psb = cast_const_phw_smu7_power_state(pstate2);
4186        /* If the two states don't even have the same number of performance levels they cannot be the same state. */
4187        if (psa->performance_level_count != psb->performance_level_count) {
4188                *equal = false;
4189                return 0;
4190        }
4191
4192        for (i = 0; i < psa->performance_level_count; i++) {
4193                if (!smu7_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
4194                        /* If we have found even one performance level pair that is different the states are different. */
4195                        *equal = false;
4196                        return 0;
4197                }
4198        }
4199
4200        /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
4201        *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk));
4202        *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk));
4203        *equal &= (psa->sclk_threshold == psb->sclk_threshold);
4204        /* For OD call, set value based on flag */
4205        *equal &= !(data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK |
4206                                                        DPMTABLE_OD_UPDATE_MCLK |
4207                                                        DPMTABLE_OD_UPDATE_VDDC));
4208
4209        return 0;
4210}
4211
4212static int smu7_check_mc_firmware(struct pp_hwmgr *hwmgr)
4213{
4214        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4215
4216        uint32_t vbios_version;
4217        uint32_t tmp;
4218
4219        /* Read MC indirect register offset 0x9F bits [3:0] to see
4220         * if VBIOS has already loaded a full version of MC ucode
4221         * or not.
4222         */
4223
4224        smu7_get_mc_microcode_version(hwmgr);
4225        vbios_version = hwmgr->microcode_version_info.MC & 0xf;
4226
4227        data->need_long_memory_training = false;
4228
4229        cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX,
4230                                                        ixMC_IO_DEBUG_UP_13);
4231        tmp = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
4232
4233        if (tmp & (1 << 23)) {
4234                data->mem_latency_high = MEM_LATENCY_HIGH;
4235                data->mem_latency_low = MEM_LATENCY_LOW;
4236                if ((hwmgr->chip_id == CHIP_POLARIS10) ||
4237                    (hwmgr->chip_id == CHIP_POLARIS11) ||
4238                    (hwmgr->chip_id == CHIP_POLARIS12))
4239                        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableFFC);
4240        } else {
4241                data->mem_latency_high = 330;
4242                data->mem_latency_low = 330;
4243                if ((hwmgr->chip_id == CHIP_POLARIS10) ||
4244                    (hwmgr->chip_id == CHIP_POLARIS11) ||
4245                    (hwmgr->chip_id == CHIP_POLARIS12))
4246                        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableFFC);
4247        }
4248
4249        return 0;
4250}
4251
4252static int smu7_read_clock_registers(struct pp_hwmgr *hwmgr)
4253{
4254        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4255
4256        data->clock_registers.vCG_SPLL_FUNC_CNTL         =
4257                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL);
4258        data->clock_registers.vCG_SPLL_FUNC_CNTL_2       =
4259                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2);
4260        data->clock_registers.vCG_SPLL_FUNC_CNTL_3       =
4261                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_3);
4262        data->clock_registers.vCG_SPLL_FUNC_CNTL_4       =
4263                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4);
4264        data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM   =
4265                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM);
4266        data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
4267                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM_2);
4268        data->clock_registers.vDLL_CNTL                  =
4269                cgs_read_register(hwmgr->device, mmDLL_CNTL);
4270        data->clock_registers.vMCLK_PWRMGT_CNTL          =
4271                cgs_read_register(hwmgr->device, mmMCLK_PWRMGT_CNTL);
4272        data->clock_registers.vMPLL_AD_FUNC_CNTL         =
4273                cgs_read_register(hwmgr->device, mmMPLL_AD_FUNC_CNTL);
4274        data->clock_registers.vMPLL_DQ_FUNC_CNTL         =
4275                cgs_read_register(hwmgr->device, mmMPLL_DQ_FUNC_CNTL);
4276        data->clock_registers.vMPLL_FUNC_CNTL            =
4277                cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL);
4278        data->clock_registers.vMPLL_FUNC_CNTL_1          =
4279                cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_1);
4280        data->clock_registers.vMPLL_FUNC_CNTL_2          =
4281                cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_2);
4282        data->clock_registers.vMPLL_SS1                  =
4283                cgs_read_register(hwmgr->device, mmMPLL_SS1);
4284        data->clock_registers.vMPLL_SS2                  =
4285                cgs_read_register(hwmgr->device, mmMPLL_SS2);
4286        return 0;
4287
4288}
4289
4290/**
4291 * Find out if memory is GDDR5.
4292 *
4293 * @param    hwmgr  the address of the powerplay hardware manager.
4294 * @return   always 0
4295 */
4296static int smu7_get_memory_type(struct pp_hwmgr *hwmgr)
4297{
4298        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4299        struct amdgpu_device *adev = hwmgr->adev;
4300
4301        data->is_memory_gddr5 = (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5);
4302
4303        return 0;
4304}
4305
4306/**
4307 * Enables Dynamic Power Management by SMC
4308 *
4309 * @param    hwmgr  the address of the powerplay hardware manager.
4310 * @return   always 0
4311 */
4312static int smu7_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
4313{
4314        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
4315                        GENERAL_PWRMGT, STATIC_PM_EN, 1);
4316
4317        return 0;
4318}
4319
4320/**
4321 * Initialize PowerGating States for different engines
4322 *
4323 * @param    hwmgr  the address of the powerplay hardware manager.
4324 * @return   always 0
4325 */
4326static int smu7_init_power_gate_state(struct pp_hwmgr *hwmgr)
4327{
4328        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4329
4330        data->uvd_power_gated = false;
4331        data->vce_power_gated = false;
4332
4333        return 0;
4334}
4335
4336static int smu7_init_sclk_threshold(struct pp_hwmgr *hwmgr)
4337{
4338        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4339
4340        data->low_sclk_interrupt_threshold = 0;
4341        return 0;
4342}
4343
4344static int smu7_setup_asic_task(struct pp_hwmgr *hwmgr)
4345{
4346        int tmp_result, result = 0;
4347
4348        smu7_check_mc_firmware(hwmgr);
4349
4350        tmp_result = smu7_read_clock_registers(hwmgr);
4351        PP_ASSERT_WITH_CODE((0 == tmp_result),
4352                        "Failed to read clock registers!", result = tmp_result);
4353
4354        tmp_result = smu7_get_memory_type(hwmgr);
4355        PP_ASSERT_WITH_CODE((0 == tmp_result),
4356                        "Failed to get memory type!", result = tmp_result);
4357
4358        tmp_result = smu7_enable_acpi_power_management(hwmgr);
4359        PP_ASSERT_WITH_CODE((0 == tmp_result),
4360                        "Failed to enable ACPI power management!", result = tmp_result);
4361
4362        tmp_result = smu7_init_power_gate_state(hwmgr);
4363        PP_ASSERT_WITH_CODE((0 == tmp_result),
4364                        "Failed to init power gate state!", result = tmp_result);
4365
4366        tmp_result = smu7_get_mc_microcode_version(hwmgr);
4367        PP_ASSERT_WITH_CODE((0 == tmp_result),
4368                        "Failed to get MC microcode version!", result = tmp_result);
4369
4370        tmp_result = smu7_init_sclk_threshold(hwmgr);
4371        PP_ASSERT_WITH_CODE((0 == tmp_result),
4372                        "Failed to init sclk threshold!", result = tmp_result);
4373
4374        return result;
4375}
4376
4377static int smu7_force_clock_level(struct pp_hwmgr *hwmgr,
4378                enum pp_clock_type type, uint32_t mask)
4379{
4380        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4381
4382        if (mask == 0)
4383                return -EINVAL;
4384
4385        switch (type) {
4386        case PP_SCLK:
4387                if (!data->sclk_dpm_key_disabled)
4388                        smum_send_msg_to_smc_with_parameter(hwmgr,
4389                                        PPSMC_MSG_SCLKDPM_SetEnabledMask,
4390                                        data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
4391                break;
4392        case PP_MCLK:
4393                if (!data->mclk_dpm_key_disabled)
4394                        smum_send_msg_to_smc_with_parameter(hwmgr,
4395                                        PPSMC_MSG_MCLKDPM_SetEnabledMask,
4396                                        data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
4397                break;
4398        case PP_PCIE:
4399        {
4400                uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
4401
4402                if (!data->pcie_dpm_key_disabled) {
4403                        if (fls(tmp) != ffs(tmp))
4404                                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PCIeDPM_UnForceLevel);
4405                        else
4406                                smum_send_msg_to_smc_with_parameter(hwmgr,
4407                                        PPSMC_MSG_PCIeDPM_ForceLevel,
4408                                        fls(tmp) - 1);
4409                }
4410                break;
4411        }
4412        default:
4413                break;
4414        }
4415
4416        return 0;
4417}
4418
4419static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
4420                enum pp_clock_type type, char *buf)
4421{
4422        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4423        struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
4424        struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
4425        struct smu7_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table);
4426        struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table);
4427        struct phm_odn_clock_levels *odn_sclk_table = &(odn_table->odn_core_clock_dpm_levels);
4428        struct phm_odn_clock_levels *odn_mclk_table = &(odn_table->odn_memory_clock_dpm_levels);
4429        int i, now, size = 0;
4430        uint32_t clock, pcie_speed;
4431
4432        switch (type) {
4433        case PP_SCLK:
4434                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetSclkFrequency);
4435                clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
4436
4437                for (i = 0; i < sclk_table->count; i++) {
4438                        if (clock > sclk_table->dpm_levels[i].value)
4439                                continue;
4440                        break;
4441                }
4442                now = i;
4443
4444                for (i = 0; i < sclk_table->count; i++)
4445                        size += sprintf(buf + size, "%d: %uMhz %s\n",
4446                                        i, sclk_table->dpm_levels[i].value / 100,
4447                                        (i == now) ? "*" : "");
4448                break;
4449        case PP_MCLK:
4450                smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetMclkFrequency);
4451                clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
4452
4453                for (i = 0; i < mclk_table->count; i++) {
4454                        if (clock > mclk_table->dpm_levels[i].value)
4455                                continue;
4456                        break;
4457                }
4458                now = i;
4459
4460                for (i = 0; i < mclk_table->count; i++)
4461                        size += sprintf(buf + size, "%d: %uMhz %s\n",
4462                                        i, mclk_table->dpm_levels[i].value / 100,
4463                                        (i == now) ? "*" : "");
4464                break;
4465        case PP_PCIE:
4466                pcie_speed = smu7_get_current_pcie_speed(hwmgr);
4467                for (i = 0; i < pcie_table->count; i++) {
4468                        if (pcie_speed != pcie_table->dpm_levels[i].value)
4469                                continue;
4470                        break;
4471                }
4472                now = i;
4473
4474                for (i = 0; i < pcie_table->count; i++)
4475                        size += sprintf(buf + size, "%d: %s %s\n", i,
4476                                        (pcie_table->dpm_levels[i].value == 0) ? "2.5GT/s, x8" :
4477                                        (pcie_table->dpm_levels[i].value == 1) ? "5.0GT/s, x16" :
4478                                        (pcie_table->dpm_levels[i].value == 2) ? "8.0GT/s, x16" : "",
4479                                        (i == now) ? "*" : "");
4480                break;
4481        case OD_SCLK:
4482                if (hwmgr->od_enabled) {
4483                        size = sprintf(buf, "%s:\n", "OD_SCLK");
4484                        for (i = 0; i < odn_sclk_table->num_of_pl; i++)
4485                                size += sprintf(buf + size, "%d: %10uMHz %10umV\n",
4486                                        i, odn_sclk_table->entries[i].clock/100,
4487                                        odn_sclk_table->entries[i].vddc);
4488                }
4489                break;
4490        case OD_MCLK:
4491                if (hwmgr->od_enabled) {
4492                        size = sprintf(buf, "%s:\n", "OD_MCLK");
4493                        for (i = 0; i < odn_mclk_table->num_of_pl; i++)
4494                                size += sprintf(buf + size, "%d: %10uMHz %10umV\n",
4495                                        i, odn_mclk_table->entries[i].clock/100,
4496                                        odn_mclk_table->entries[i].vddc);
4497                }
4498                break;
4499        case OD_RANGE:
4500                if (hwmgr->od_enabled) {
4501                        size = sprintf(buf, "%s:\n", "OD_RANGE");
4502                        size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
4503                                data->golden_dpm_table.sclk_table.dpm_levels[0].value/100,
4504                                hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
4505                        size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n",
4506                                data->golden_dpm_table.mclk_table.dpm_levels[0].value/100,
4507                                hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
4508                        size += sprintf(buf + size, "VDDC: %7umV %11umV\n",
4509                                data->odn_dpm_table.min_vddc,
4510                                data->odn_dpm_table.max_vddc);
4511                }
4512                break;
4513        default:
4514                break;
4515        }
4516        return size;
4517}
4518
4519static void smu7_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
4520{
4521        switch (mode) {
4522        case AMD_FAN_CTRL_NONE:
4523                smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
4524                break;
4525        case AMD_FAN_CTRL_MANUAL:
4526                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4527                        PHM_PlatformCaps_MicrocodeFanControl))
4528                        smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
4529                break;
4530        case AMD_FAN_CTRL_AUTO:
4531                if (!smu7_fan_ctrl_set_static_mode(hwmgr, mode))
4532                        smu7_fan_ctrl_start_smc_fan_control(hwmgr);
4533                break;
4534        default:
4535                break;
4536        }
4537}
4538
4539static uint32_t smu7_get_fan_control_mode(struct pp_hwmgr *hwmgr)
4540{
4541        return hwmgr->fan_ctrl_enabled ? AMD_FAN_CTRL_AUTO : AMD_FAN_CTRL_MANUAL;
4542}
4543
4544static int smu7_get_sclk_od(struct pp_hwmgr *hwmgr)
4545{
4546        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4547        struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
4548        struct smu7_single_dpm_table *golden_sclk_table =
4549                        &(data->golden_dpm_table.sclk_table);
4550        int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
4551        int golden_value = golden_sclk_table->dpm_levels
4552                        [golden_sclk_table->count - 1].value;
4553
4554        value -= golden_value;
4555        value = DIV_ROUND_UP(value * 100, golden_value);
4556
4557        return value;
4558}
4559
4560static int smu7_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
4561{
4562        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4563        struct smu7_single_dpm_table *golden_sclk_table =
4564                        &(data->golden_dpm_table.sclk_table);
4565        struct pp_power_state  *ps;
4566        struct smu7_power_state  *smu7_ps;
4567
4568        if (value > 20)
4569                value = 20;
4570
4571        ps = hwmgr->request_ps;
4572
4573        if (ps == NULL)
4574                return -EINVAL;
4575
4576        smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
4577
4578        smu7_ps->performance_levels[smu7_ps->performance_level_count - 1].engine_clock =
4579                        golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
4580                        value / 100 +
4581                        golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
4582
4583        return 0;
4584}
4585
4586static int smu7_get_mclk_od(struct pp_hwmgr *hwmgr)
4587{
4588        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4589        struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
4590        struct smu7_single_dpm_table *golden_mclk_table =
4591                        &(data->golden_dpm_table.mclk_table);
4592        int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
4593        int golden_value = golden_mclk_table->dpm_levels
4594                        [golden_mclk_table->count - 1].value;
4595
4596        value -= golden_value;
4597        value = DIV_ROUND_UP(value * 100, golden_value);
4598
4599        return value;
4600}
4601
4602static int smu7_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
4603{
4604        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4605        struct smu7_single_dpm_table *golden_mclk_table =
4606                        &(data->golden_dpm_table.mclk_table);
4607        struct pp_power_state  *ps;
4608        struct smu7_power_state  *smu7_ps;
4609
4610        if (value > 20)
4611                value = 20;
4612
4613        ps = hwmgr->request_ps;
4614
4615        if (ps == NULL)
4616                return -EINVAL;
4617
4618        smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
4619
4620        smu7_ps->performance_levels[smu7_ps->performance_level_count - 1].memory_clock =
4621                        golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
4622                        value / 100 +
4623                        golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
4624
4625        return 0;
4626}
4627
4628
4629static int smu7_get_sclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks)
4630{
4631        struct phm_ppt_v1_information *table_info =
4632                        (struct phm_ppt_v1_information *)hwmgr->pptable;
4633        struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table = NULL;
4634        struct phm_clock_voltage_dependency_table *sclk_table;
4635        int i;
4636
4637        if (hwmgr->pp_table_version == PP_TABLE_V1) {
4638                if (table_info == NULL || table_info->vdd_dep_on_sclk == NULL)
4639                        return -EINVAL;
4640                dep_sclk_table = table_info->vdd_dep_on_sclk;
4641                for (i = 0; i < dep_sclk_table->count; i++)
4642                        clocks->clock[i] = dep_sclk_table->entries[i].clk * 10;
4643                clocks->count = dep_sclk_table->count;
4644        } else if (hwmgr->pp_table_version == PP_TABLE_V0) {
4645                sclk_table = hwmgr->dyn_state.vddc_dependency_on_sclk;
4646                for (i = 0; i < sclk_table->count; i++)
4647                        clocks->clock[i] = sclk_table->entries[i].clk * 10;
4648                clocks->count = sclk_table->count;
4649        }
4650
4651        return 0;
4652}
4653
4654static uint32_t smu7_get_mem_latency(struct pp_hwmgr *hwmgr, uint32_t clk)
4655{
4656        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4657
4658        if (clk >= MEM_FREQ_LOW_LATENCY && clk < MEM_FREQ_HIGH_LATENCY)
4659                return data->mem_latency_high;
4660        else if (clk >= MEM_FREQ_HIGH_LATENCY)
4661                return data->mem_latency_low;
4662        else
4663                return MEM_LATENCY_ERR;
4664}
4665
4666static int smu7_get_mclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks)
4667{
4668        struct phm_ppt_v1_information *table_info =
4669                        (struct phm_ppt_v1_information *)hwmgr->pptable;
4670        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
4671        int i;
4672        struct phm_clock_voltage_dependency_table *mclk_table;
4673
4674        if (hwmgr->pp_table_version == PP_TABLE_V1) {
4675                if (table_info == NULL)
4676                        return -EINVAL;
4677                dep_mclk_table = table_info->vdd_dep_on_mclk;
4678                for (i = 0; i < dep_mclk_table->count; i++) {
4679                        clocks->clock[i] = dep_mclk_table->entries[i].clk * 10;
4680                        clocks->latency[i] = smu7_get_mem_latency(hwmgr,
4681                                                dep_mclk_table->entries[i].clk);
4682                }
4683                clocks->count = dep_mclk_table->count;
4684        } else if (hwmgr->pp_table_version == PP_TABLE_V0) {
4685                mclk_table = hwmgr->dyn_state.vddc_dependency_on_mclk;
4686                for (i = 0; i < mclk_table->count; i++)
4687                        clocks->clock[i] = mclk_table->entries[i].clk * 10;
4688                clocks->count = mclk_table->count;
4689        }
4690        return 0;
4691}
4692
4693static int smu7_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type,
4694                                                struct amd_pp_clocks *clocks)
4695{
4696        switch (type) {
4697        case amd_pp_sys_clock:
4698                smu7_get_sclks(hwmgr, clocks);
4699                break;
4700        case amd_pp_mem_clock:
4701                smu7_get_mclks(hwmgr, clocks);
4702                break;
4703        default:
4704                return -EINVAL;
4705        }
4706
4707        return 0;
4708}
4709
4710static int smu7_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
4711                                        uint32_t virtual_addr_low,
4712                                        uint32_t virtual_addr_hi,
4713                                        uint32_t mc_addr_low,
4714                                        uint32_t mc_addr_hi,
4715                                        uint32_t size)
4716{
4717        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4718
4719        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4720                                        data->soft_regs_start +
4721                                        smum_get_offsetof(hwmgr,
4722                                        SMU_SoftRegisters, DRAM_LOG_ADDR_H),
4723                                        mc_addr_hi);
4724
4725        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4726                                        data->soft_regs_start +
4727                                        smum_get_offsetof(hwmgr,
4728                                        SMU_SoftRegisters, DRAM_LOG_ADDR_L),
4729                                        mc_addr_low);
4730
4731        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4732                                        data->soft_regs_start +
4733                                        smum_get_offsetof(hwmgr,
4734                                        SMU_SoftRegisters, DRAM_LOG_PHY_ADDR_H),
4735                                        virtual_addr_hi);
4736
4737        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4738                                        data->soft_regs_start +
4739                                        smum_get_offsetof(hwmgr,
4740                                        SMU_SoftRegisters, DRAM_LOG_PHY_ADDR_L),
4741                                        virtual_addr_low);
4742
4743        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4744                                        data->soft_regs_start +
4745                                        smum_get_offsetof(hwmgr,
4746                                        SMU_SoftRegisters, DRAM_LOG_BUFF_SIZE),
4747                                        size);
4748        return 0;
4749}
4750
4751static int smu7_get_max_high_clocks(struct pp_hwmgr *hwmgr,
4752                                        struct amd_pp_simple_clock_info *clocks)
4753{
4754        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4755        struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
4756        struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
4757
4758        if (clocks == NULL)
4759                return -EINVAL;
4760
4761        clocks->memory_max_clock = mclk_table->count > 1 ?
4762                                mclk_table->dpm_levels[mclk_table->count-1].value :
4763                                mclk_table->dpm_levels[0].value;
4764        clocks->engine_max_clock = sclk_table->count > 1 ?
4765                                sclk_table->dpm_levels[sclk_table->count-1].value :
4766                                sclk_table->dpm_levels[0].value;
4767        return 0;
4768}
4769
4770static int smu7_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
4771                struct PP_TemperatureRange *thermal_data)
4772{
4773        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4774        struct phm_ppt_v1_information *table_info =
4775                        (struct phm_ppt_v1_information *)hwmgr->pptable;
4776
4777        memcpy(thermal_data, &SMU7ThermalPolicy[0], sizeof(struct PP_TemperatureRange));
4778
4779        if (hwmgr->pp_table_version == PP_TABLE_V1)
4780                thermal_data->max = table_info->cac_dtp_table->usSoftwareShutdownTemp *
4781                        PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4782        else if (hwmgr->pp_table_version == PP_TABLE_V0)
4783                thermal_data->max = data->thermal_temp_setting.temperature_shutdown *
4784                        PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4785
4786        return 0;
4787}
4788
4789static bool smu7_check_clk_voltage_valid(struct pp_hwmgr *hwmgr,
4790                                        enum PP_OD_DPM_TABLE_COMMAND type,
4791                                        uint32_t clk,
4792                                        uint32_t voltage)
4793{
4794        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4795
4796        if (voltage < data->odn_dpm_table.min_vddc || voltage > data->odn_dpm_table.max_vddc) {
4797                pr_info("OD voltage is out of range [%d - %d] mV\n",
4798                                                data->odn_dpm_table.min_vddc,
4799                                                data->odn_dpm_table.max_vddc);
4800                return false;
4801        }
4802
4803        if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
4804                if (data->golden_dpm_table.sclk_table.dpm_levels[0].value > clk ||
4805                        hwmgr->platform_descriptor.overdriveLimit.engineClock < clk) {
4806                        pr_info("OD engine clock is out of range [%d - %d] MHz\n",
4807                                data->golden_dpm_table.sclk_table.dpm_levels[0].value/100,
4808                                hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
4809                        return false;
4810                }
4811        } else if (type == PP_OD_EDIT_MCLK_VDDC_TABLE) {
4812                if (data->golden_dpm_table.mclk_table.dpm_levels[0].value > clk ||
4813                        hwmgr->platform_descriptor.overdriveLimit.memoryClock < clk) {
4814                        pr_info("OD memory clock is out of range [%d - %d] MHz\n",
4815                                data->golden_dpm_table.mclk_table.dpm_levels[0].value/100,
4816                                hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
4817                        return false;
4818                }
4819        } else {
4820                return false;
4821        }
4822
4823        return true;
4824}
4825
4826static int smu7_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
4827                                        enum PP_OD_DPM_TABLE_COMMAND type,
4828                                        long *input, uint32_t size)
4829{
4830        uint32_t i;
4831        struct phm_odn_clock_levels *podn_dpm_table_in_backend = NULL;
4832        struct smu7_odn_clock_voltage_dependency_table *podn_vdd_dep_in_backend = NULL;
4833        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4834
4835        uint32_t input_clk;
4836        uint32_t input_vol;
4837        uint32_t input_level;
4838
4839        PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
4840                                return -EINVAL);
4841
4842        if (!hwmgr->od_enabled) {
4843                pr_info("OverDrive feature not enabled\n");
4844                return -EINVAL;
4845        }
4846
4847        if (PP_OD_EDIT_SCLK_VDDC_TABLE == type) {
4848                podn_dpm_table_in_backend = &data->odn_dpm_table.odn_core_clock_dpm_levels;
4849                podn_vdd_dep_in_backend = &data->odn_dpm_table.vdd_dependency_on_sclk;
4850                PP_ASSERT_WITH_CODE((podn_dpm_table_in_backend && podn_vdd_dep_in_backend),
4851                                "Failed to get ODN SCLK and Voltage tables",
4852                                return -EINVAL);
4853        } else if (PP_OD_EDIT_MCLK_VDDC_TABLE == type) {
4854                podn_dpm_table_in_backend = &data->odn_dpm_table.odn_memory_clock_dpm_levels;
4855                podn_vdd_dep_in_backend = &data->odn_dpm_table.vdd_dependency_on_mclk;
4856
4857                PP_ASSERT_WITH_CODE((podn_dpm_table_in_backend && podn_vdd_dep_in_backend),
4858                        "Failed to get ODN MCLK and Voltage tables",
4859                        return -EINVAL);
4860        } else if (PP_OD_RESTORE_DEFAULT_TABLE == type) {
4861                smu7_odn_initial_default_setting(hwmgr);
4862                return 0;
4863        } else if (PP_OD_COMMIT_DPM_TABLE == type) {
4864                smu7_check_dpm_table_updated(hwmgr);
4865                return 0;
4866        } else {
4867                return -EINVAL;
4868        }
4869
4870        for (i = 0; i < size; i += 3) {
4871                if (i + 3 > size || input[i] >= podn_dpm_table_in_backend->num_of_pl) {
4872                        pr_info("invalid clock voltage input \n");
4873                        return 0;
4874                }
4875                input_level = input[i];
4876                input_clk = input[i+1] * 100;
4877                input_vol = input[i+2];
4878
4879                if (smu7_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) {
4880                        podn_dpm_table_in_backend->entries[input_level].clock = input_clk;
4881                        podn_vdd_dep_in_backend->entries[input_level].clk = input_clk;
4882                        podn_dpm_table_in_backend->entries[input_level].vddc = input_vol;
4883                        podn_vdd_dep_in_backend->entries[input_level].vddc = input_vol;
4884                        podn_vdd_dep_in_backend->entries[input_level].vddgfx = input_vol;
4885                } else {
4886                        return -EINVAL;
4887                }
4888        }
4889
4890        return 0;
4891}
4892
4893static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
4894{
4895        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4896        uint32_t i, size = 0;
4897        uint32_t len;
4898
4899        static const char *profile_name[7] = {"BOOTUP_DEFAULT",
4900                                        "3D_FULL_SCREEN",
4901                                        "POWER_SAVING",
4902                                        "VIDEO",
4903                                        "VR",
4904                                        "COMPUTE",
4905                                        "CUSTOM"};
4906
4907        static const char *title[8] = {"NUM",
4908                        "MODE_NAME",
4909                        "SCLK_UP_HYST",
4910                        "SCLK_DOWN_HYST",
4911                        "SCLK_ACTIVE_LEVEL",
4912                        "MCLK_UP_HYST",
4913                        "MCLK_DOWN_HYST",
4914                        "MCLK_ACTIVE_LEVEL"};
4915
4916        if (!buf)
4917                return -EINVAL;
4918
4919        size += sprintf(buf + size, "%s %16s %16s %16s %16s %16s %16s %16s\n",
4920                        title[0], title[1], title[2], title[3],
4921                        title[4], title[5], title[6], title[7]);
4922
4923        len = sizeof(smu7_profiling) / sizeof(struct profile_mode_setting);
4924
4925        for (i = 0; i < len; i++) {
4926                if (i == hwmgr->power_profile_mode) {
4927                        size += sprintf(buf + size, "%3d %14s %s: %8d %16d %16d %16d %16d %16d\n",
4928                        i, profile_name[i], "*",
4929                        data->current_profile_setting.sclk_up_hyst,
4930                        data->current_profile_setting.sclk_down_hyst,
4931                        data->current_profile_setting.sclk_activity,
4932                        data->current_profile_setting.mclk_up_hyst,
4933                        data->current_profile_setting.mclk_down_hyst,
4934                        data->current_profile_setting.mclk_activity);
4935                        continue;
4936                }
4937                if (smu7_profiling[i].bupdate_sclk)
4938                        size += sprintf(buf + size, "%3d %16s: %8d %16d %16d ",
4939                        i, profile_name[i], smu7_profiling[i].sclk_up_hyst,
4940                        smu7_profiling[i].sclk_down_hyst,
4941                        smu7_profiling[i].sclk_activity);
4942                else
4943                        size += sprintf(buf + size, "%3d %16s: %8s %16s %16s ",
4944                        i, profile_name[i], "-", "-", "-");
4945
4946                if (smu7_profiling[i].bupdate_mclk)
4947                        size += sprintf(buf + size, "%16d %16d %16d\n",
4948                        smu7_profiling[i].mclk_up_hyst,
4949                        smu7_profiling[i].mclk_down_hyst,
4950                        smu7_profiling[i].mclk_activity);
4951                else
4952                        size += sprintf(buf + size, "%16s %16s %16s\n",
4953                        "-", "-", "-");
4954        }
4955
4956        return size;
4957}
4958
4959static void smu7_patch_compute_profile_mode(struct pp_hwmgr *hwmgr,
4960                                        enum PP_SMC_POWER_PROFILE requst)
4961{
4962        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4963        uint32_t tmp, level;
4964
4965        if (requst == PP_SMC_POWER_PROFILE_COMPUTE) {
4966                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
4967                        level = 0;
4968                        tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
4969                        while (tmp >>= 1)
4970                                level++;
4971                        if (level > 0)
4972                                smu7_force_clock_level(hwmgr, PP_SCLK, 3 << (level-1));
4973                }
4974        } else if (hwmgr->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) {
4975                smu7_force_clock_level(hwmgr, PP_SCLK, data->dpm_level_enable_mask.sclk_dpm_enable_mask);
4976        }
4977}
4978
4979static int smu7_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size)
4980{
4981        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4982        struct profile_mode_setting tmp;
4983        enum PP_SMC_POWER_PROFILE mode;
4984
4985        if (input == NULL)
4986                return -EINVAL;
4987
4988        mode = input[size];
4989        switch (mode) {
4990        case PP_SMC_POWER_PROFILE_CUSTOM:
4991                if (size < 8 && size != 0)
4992                        return -EINVAL;
4993                /* If only CUSTOM is passed in, use the saved values. Check
4994                 * that we actually have a CUSTOM profile by ensuring that
4995                 * the "use sclk" or the "use mclk" bits are set
4996                 */
4997                tmp = smu7_profiling[PP_SMC_POWER_PROFILE_CUSTOM];
4998                if (size == 0) {
4999                        if (tmp.bupdate_sclk == 0 && tmp.bupdate_mclk == 0)
5000                                return -EINVAL;
5001                } else {
5002                        tmp.bupdate_sclk = input[0];
5003                        tmp.sclk_up_hyst = input[1];
5004                        tmp.sclk_down_hyst = input[2];
5005                        tmp.sclk_activity = input[3];
5006                        tmp.bupdate_mclk = input[4];
5007                        tmp.mclk_up_hyst = input[5];
5008                        tmp.mclk_down_hyst = input[6];
5009                        tmp.mclk_activity = input[7];
5010                        smu7_profiling[PP_SMC_POWER_PROFILE_CUSTOM] = tmp;
5011                }
5012                if (!smum_update_dpm_settings(hwmgr, &tmp)) {
5013                        memcpy(&data->current_profile_setting, &tmp, sizeof(struct profile_mode_setting));
5014                        hwmgr->power_profile_mode = mode;
5015                }
5016                break;
5017        case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
5018        case PP_SMC_POWER_PROFILE_POWERSAVING:
5019        case PP_SMC_POWER_PROFILE_VIDEO:
5020        case PP_SMC_POWER_PROFILE_VR:
5021        case PP_SMC_POWER_PROFILE_COMPUTE:
5022                if (mode == hwmgr->power_profile_mode)
5023                        return 0;
5024
5025                memcpy(&tmp, &smu7_profiling[mode], sizeof(struct profile_mode_setting));
5026                if (!smum_update_dpm_settings(hwmgr, &tmp)) {
5027                        if (tmp.bupdate_sclk) {
5028                                data->current_profile_setting.bupdate_sclk = tmp.bupdate_sclk;
5029                                data->current_profile_setting.sclk_up_hyst = tmp.sclk_up_hyst;
5030                                data->current_profile_setting.sclk_down_hyst = tmp.sclk_down_hyst;
5031                                data->current_profile_setting.sclk_activity = tmp.sclk_activity;
5032                        }
5033                        if (tmp.bupdate_mclk) {
5034                                data->current_profile_setting.bupdate_mclk = tmp.bupdate_mclk;
5035                                data->current_profile_setting.mclk_up_hyst = tmp.mclk_up_hyst;
5036                                data->current_profile_setting.mclk_down_hyst = tmp.mclk_down_hyst;
5037                                data->current_profile_setting.mclk_activity = tmp.mclk_activity;
5038                        }
5039                        smu7_patch_compute_profile_mode(hwmgr, mode);
5040                        hwmgr->power_profile_mode = mode;
5041                }
5042                break;
5043        default:
5044                return -EINVAL;
5045        }
5046
5047        return 0;
5048}
5049
5050static int smu7_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
5051                                PHM_PerformanceLevelDesignation designation, uint32_t index,
5052                                PHM_PerformanceLevel *level)
5053{
5054        const struct smu7_power_state *ps;
5055        struct smu7_hwmgr *data;
5056        uint32_t i;
5057
5058        if (level == NULL || hwmgr == NULL || state == NULL)
5059                return -EINVAL;
5060
5061        data = hwmgr->backend;
5062        ps = cast_const_phw_smu7_power_state(state);
5063
5064        i = index > ps->performance_level_count - 1 ?
5065                        ps->performance_level_count - 1 : index;
5066
5067        level->coreClock = ps->performance_levels[i].engine_clock;
5068        level->memory_clock = ps->performance_levels[i].memory_clock;
5069
5070        return 0;
5071}
5072
5073static int smu7_power_off_asic(struct pp_hwmgr *hwmgr)
5074{
5075        int result;
5076
5077        result = smu7_disable_dpm_tasks(hwmgr);
5078        PP_ASSERT_WITH_CODE((0 == result),
5079                        "[disable_dpm_tasks] Failed to disable DPM!",
5080                        );
5081
5082        return result;
5083}
5084
5085static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
5086        .backend_init = &smu7_hwmgr_backend_init,
5087        .backend_fini = &smu7_hwmgr_backend_fini,
5088        .asic_setup = &smu7_setup_asic_task,
5089        .dynamic_state_management_enable = &smu7_enable_dpm_tasks,
5090        .apply_state_adjust_rules = smu7_apply_state_adjust_rules,
5091        .force_dpm_level = &smu7_force_dpm_level,
5092        .power_state_set = smu7_set_power_state_tasks,
5093        .get_power_state_size = smu7_get_power_state_size,
5094        .get_mclk = smu7_dpm_get_mclk,
5095        .get_sclk = smu7_dpm_get_sclk,
5096        .patch_boot_state = smu7_dpm_patch_boot_state,
5097        .get_pp_table_entry = smu7_get_pp_table_entry,
5098        .get_num_of_pp_table_entries = smu7_get_number_of_powerplay_table_entries,
5099        .powerdown_uvd = smu7_powerdown_uvd,
5100        .powergate_uvd = smu7_powergate_uvd,
5101        .powergate_vce = smu7_powergate_vce,
5102        .disable_clock_power_gating = smu7_disable_clock_power_gating,
5103        .update_clock_gatings = smu7_update_clock_gatings,
5104        .notify_smc_display_config_after_ps_adjustment = smu7_notify_smc_display_config_after_ps_adjustment,
5105        .display_config_changed = smu7_display_configuration_changed_task,
5106        .set_max_fan_pwm_output = smu7_set_max_fan_pwm_output,
5107        .set_max_fan_rpm_output = smu7_set_max_fan_rpm_output,
5108        .stop_thermal_controller = smu7_thermal_stop_thermal_controller,
5109        .get_fan_speed_info = smu7_fan_ctrl_get_fan_speed_info,
5110        .get_fan_speed_percent = smu7_fan_ctrl_get_fan_speed_percent,
5111        .set_fan_speed_percent = smu7_fan_ctrl_set_fan_speed_percent,
5112        .reset_fan_speed_to_default = smu7_fan_ctrl_reset_fan_speed_to_default,
5113        .get_fan_speed_rpm = smu7_fan_ctrl_get_fan_speed_rpm,
5114        .set_fan_speed_rpm = smu7_fan_ctrl_set_fan_speed_rpm,
5115        .uninitialize_thermal_controller = smu7_thermal_ctrl_uninitialize_thermal_controller,
5116        .register_irq_handlers = smu7_register_irq_handlers,
5117        .check_smc_update_required_for_display_configuration = smu7_check_smc_update_required_for_display_configuration,
5118        .check_states_equal = smu7_check_states_equal,
5119        .set_fan_control_mode = smu7_set_fan_control_mode,
5120        .get_fan_control_mode = smu7_get_fan_control_mode,
5121        .force_clock_level = smu7_force_clock_level,
5122        .print_clock_levels = smu7_print_clock_levels,
5123        .powergate_gfx = smu7_powergate_gfx,
5124        .get_sclk_od = smu7_get_sclk_od,
5125        .set_sclk_od = smu7_set_sclk_od,
5126        .get_mclk_od = smu7_get_mclk_od,
5127        .set_mclk_od = smu7_set_mclk_od,
5128        .get_clock_by_type = smu7_get_clock_by_type,
5129        .read_sensor = smu7_read_sensor,
5130        .dynamic_state_management_disable = smu7_disable_dpm_tasks,
5131        .avfs_control = smu7_avfs_control,
5132        .disable_smc_firmware_ctf = smu7_thermal_disable_alert,
5133        .start_thermal_controller = smu7_start_thermal_controller,
5134        .notify_cac_buffer_info = smu7_notify_cac_buffer_info,
5135        .get_max_high_clocks = smu7_get_max_high_clocks,
5136        .get_thermal_temperature_range = smu7_get_thermal_temperature_range,
5137        .odn_edit_dpm_table = smu7_odn_edit_dpm_table,
5138        .set_power_limit = smu7_set_power_limit,
5139        .get_power_profile_mode = smu7_get_power_profile_mode,
5140        .set_power_profile_mode = smu7_set_power_profile_mode,
5141        .get_performance_level = smu7_get_performance_level,
5142        .power_off_asic = smu7_power_off_asic,
5143};
5144
5145uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
5146                uint32_t clock_insr)
5147{
5148        uint8_t i;
5149        uint32_t temp;
5150        uint32_t min = max(clock_insr, (uint32_t)SMU7_MINIMUM_ENGINE_CLOCK);
5151
5152        PP_ASSERT_WITH_CODE((clock >= min), "Engine clock can't satisfy stutter requirement!", return 0);
5153        for (i = SMU7_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
5154                temp = clock >> i;
5155
5156                if (temp >= min || i == 0)
5157                        break;
5158        }
5159        return i;
5160}
5161
5162int smu7_init_function_pointers(struct pp_hwmgr *hwmgr)
5163{
5164        int ret = 0;
5165
5166        hwmgr->hwmgr_func = &smu7_hwmgr_funcs;
5167        if (hwmgr->pp_table_version == PP_TABLE_V0)
5168                hwmgr->pptable_func = &pptable_funcs;
5169        else if (hwmgr->pp_table_version == PP_TABLE_V1)
5170                hwmgr->pptable_func = &pptable_v1_0_funcs;
5171
5172        return ret;
5173}
5174