linux/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c
<<
>>
Prefs
   1/*
   2 * Copyright 2017 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 <linux/module.h>
  24#include <linux/slab.h>
  25#include <linux/fb.h>
  26#include "linux/delay.h"
  27#include <linux/types.h>
  28
  29#include "smumgr.h"
  30#include "pp_debug.h"
  31#include "ci_smumgr.h"
  32#include "ppsmc.h"
  33#include "smu7_hwmgr.h"
  34#include "hardwaremanager.h"
  35#include "ppatomctrl.h"
  36#include "cgs_common.h"
  37#include "atombios.h"
  38#include "pppcielanes.h"
  39
  40#include "smu/smu_7_0_1_d.h"
  41#include "smu/smu_7_0_1_sh_mask.h"
  42
  43#include "dce/dce_8_0_d.h"
  44#include "dce/dce_8_0_sh_mask.h"
  45
  46#include "bif/bif_4_1_d.h"
  47#include "bif/bif_4_1_sh_mask.h"
  48
  49#include "gca/gfx_7_2_d.h"
  50#include "gca/gfx_7_2_sh_mask.h"
  51
  52#include "gmc/gmc_7_1_d.h"
  53#include "gmc/gmc_7_1_sh_mask.h"
  54
  55#include "processpptables.h"
  56
  57#define MC_CG_ARB_FREQ_F0           0x0a
  58#define MC_CG_ARB_FREQ_F1           0x0b
  59#define MC_CG_ARB_FREQ_F2           0x0c
  60#define MC_CG_ARB_FREQ_F3           0x0d
  61
  62#define SMC_RAM_END 0x40000
  63
  64#define CISLAND_MINIMUM_ENGINE_CLOCK 800
  65#define CISLAND_MAX_DEEPSLEEP_DIVIDER_ID 5
  66
  67static const struct ci_pt_defaults defaults_hawaii_xt = {
  68        1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
  69        { 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
  70        { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
  71};
  72
  73static const struct ci_pt_defaults defaults_hawaii_pro = {
  74        1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
  75        { 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
  76        { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
  77};
  78
  79static const struct ci_pt_defaults defaults_bonaire_xt = {
  80        1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
  81        { 0x79,  0x253, 0x25D, 0xAE,  0x72,  0x80,  0x83,  0x86,  0x6F,  0xC8,  0xC9,  0xC9,  0x2F,  0x4D,  0x61  },
  82        { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
  83};
  84
  85
  86static const struct ci_pt_defaults defaults_saturn_xt = {
  87        1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x70000,
  88        { 0x8C,  0x247, 0x249, 0xA6,  0x80,  0x81,  0x8B,  0x89,  0x86,  0xC9,  0xCA,  0xC9,  0x4D,  0x4D,  0x4D  },
  89        { 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 }
  90};
  91
  92
  93static int ci_set_smc_sram_address(struct pp_hwmgr *hwmgr,
  94                                        uint32_t smc_addr, uint32_t limit)
  95{
  96        if ((0 != (3 & smc_addr))
  97                || ((smc_addr + 3) >= limit)) {
  98                pr_err("smc_addr invalid \n");
  99                return -EINVAL;
 100        }
 101
 102        cgs_write_register(hwmgr->device, mmSMC_IND_INDEX_0, smc_addr);
 103        PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
 104        return 0;
 105}
 106
 107static int ci_copy_bytes_to_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address,
 108                                const uint8_t *src, uint32_t byte_count, uint32_t limit)
 109{
 110        int result;
 111        uint32_t data = 0;
 112        uint32_t original_data;
 113        uint32_t addr = 0;
 114        uint32_t extra_shift;
 115
 116        if ((3 & smc_start_address)
 117                || ((smc_start_address + byte_count) >= limit)) {
 118                pr_err("smc_start_address invalid \n");
 119                return -EINVAL;
 120        }
 121
 122        addr = smc_start_address;
 123
 124        while (byte_count >= 4) {
 125        /* Bytes are written into the SMC address space with the MSB first. */
 126                data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
 127
 128                result = ci_set_smc_sram_address(hwmgr, addr, limit);
 129
 130                if (0 != result)
 131                        return result;
 132
 133                cgs_write_register(hwmgr->device, mmSMC_IND_DATA_0, data);
 134
 135                src += 4;
 136                byte_count -= 4;
 137                addr += 4;
 138        }
 139
 140        if (0 != byte_count) {
 141
 142                data = 0;
 143
 144                result = ci_set_smc_sram_address(hwmgr, addr, limit);
 145
 146                if (0 != result)
 147                        return result;
 148
 149
 150                original_data = cgs_read_register(hwmgr->device, mmSMC_IND_DATA_0);
 151
 152                extra_shift = 8 * (4 - byte_count);
 153
 154                while (byte_count > 0) {
 155                        /* Bytes are written into the SMC addres space with the MSB first. */
 156                        data = (0x100 * data) + *src++;
 157                        byte_count--;
 158                }
 159
 160                data <<= extra_shift;
 161
 162                data |= (original_data & ~((~0UL) << extra_shift));
 163
 164                result = ci_set_smc_sram_address(hwmgr, addr, limit);
 165
 166                if (0 != result)
 167                        return result;
 168
 169                cgs_write_register(hwmgr->device, mmSMC_IND_DATA_0, data);
 170        }
 171
 172        return 0;
 173}
 174
 175
 176static int ci_program_jump_on_start(struct pp_hwmgr *hwmgr)
 177{
 178        static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 };
 179
 180        ci_copy_bytes_to_smc(hwmgr, 0x0, data, 4, sizeof(data)+1);
 181
 182        return 0;
 183}
 184
 185bool ci_is_smc_ram_running(struct pp_hwmgr *hwmgr)
 186{
 187        return ((0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
 188                        CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
 189        && (0x20100 <= cgs_read_ind_register(hwmgr->device,
 190                        CGS_IND_REG__SMC, ixSMC_PC_C)));
 191}
 192
 193static int ci_read_smc_sram_dword(struct pp_hwmgr *hwmgr, uint32_t smc_addr,
 194                                uint32_t *value, uint32_t limit)
 195{
 196        int result;
 197
 198        result = ci_set_smc_sram_address(hwmgr, smc_addr, limit);
 199
 200        if (result)
 201                return result;
 202
 203        *value = cgs_read_register(hwmgr->device, mmSMC_IND_DATA_0);
 204        return 0;
 205}
 206
 207static int ci_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
 208{
 209        int ret;
 210
 211        cgs_write_register(hwmgr->device, mmSMC_RESP_0, 0);
 212        cgs_write_register(hwmgr->device, mmSMC_MESSAGE_0, msg);
 213
 214        PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0);
 215
 216        ret = PHM_READ_FIELD(hwmgr->device, SMC_RESP_0, SMC_RESP);
 217
 218        if (ret != 1)
 219                pr_info("\n failed to send message %x ret is %d\n",  msg, ret);
 220
 221        return 0;
 222}
 223
 224static int ci_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
 225                                        uint16_t msg, uint32_t parameter)
 226{
 227        cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, parameter);
 228        return ci_send_msg_to_smc(hwmgr, msg);
 229}
 230
 231static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
 232{
 233        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 234        struct amdgpu_device *adev = hwmgr->adev;
 235        uint32_t dev_id;
 236
 237        dev_id = adev->pdev->device;
 238
 239        switch (dev_id) {
 240        case 0x67BA:
 241        case 0x66B1:
 242                smu_data->power_tune_defaults = &defaults_hawaii_pro;
 243                break;
 244        case 0x67B8:
 245        case 0x66B0:
 246                smu_data->power_tune_defaults = &defaults_hawaii_xt;
 247                break;
 248        case 0x6640:
 249        case 0x6641:
 250        case 0x6646:
 251        case 0x6647:
 252                smu_data->power_tune_defaults = &defaults_saturn_xt;
 253                break;
 254        case 0x6649:
 255        case 0x6650:
 256        case 0x6651:
 257        case 0x6658:
 258        case 0x665C:
 259        case 0x665D:
 260        case 0x67A0:
 261        case 0x67A1:
 262        case 0x67A2:
 263        case 0x67A8:
 264        case 0x67A9:
 265        case 0x67AA:
 266        case 0x67B9:
 267        case 0x67BE:
 268        default:
 269                smu_data->power_tune_defaults = &defaults_bonaire_xt;
 270                break;
 271        }
 272}
 273
 274static int ci_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
 275        struct phm_clock_voltage_dependency_table *allowed_clock_voltage_table,
 276        uint32_t clock, uint32_t *vol)
 277{
 278        uint32_t i = 0;
 279
 280        if (allowed_clock_voltage_table->count == 0)
 281                return -EINVAL;
 282
 283        for (i = 0; i < allowed_clock_voltage_table->count; i++) {
 284                if (allowed_clock_voltage_table->entries[i].clk >= clock) {
 285                        *vol = allowed_clock_voltage_table->entries[i].v;
 286                        return 0;
 287                }
 288        }
 289
 290        *vol = allowed_clock_voltage_table->entries[i - 1].v;
 291        return 0;
 292}
 293
 294static int ci_calculate_sclk_params(struct pp_hwmgr *hwmgr,
 295                uint32_t clock, struct SMU7_Discrete_GraphicsLevel *sclk)
 296{
 297        const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 298        struct pp_atomctrl_clock_dividers_vi dividers;
 299        uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
 300        uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
 301        uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
 302        uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
 303        uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
 304        uint32_t ref_clock;
 305        uint32_t ref_divider;
 306        uint32_t fbdiv;
 307        int result;
 308
 309        /* get the engine clock dividers for this clock value */
 310        result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock,  &dividers);
 311
 312        PP_ASSERT_WITH_CODE(result == 0,
 313                        "Error retrieving Engine Clock dividers from VBIOS.",
 314                        return result);
 315
 316        /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
 317        ref_clock = atomctrl_get_reference_clock(hwmgr);
 318        ref_divider = 1 + dividers.uc_pll_ref_div;
 319
 320        /* low 14 bits is fraction and high 12 bits is divider */
 321        fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
 322
 323        /* SPLL_FUNC_CNTL setup */
 324        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
 325                        SPLL_REF_DIV, dividers.uc_pll_ref_div);
 326        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
 327                        SPLL_PDIV_A,  dividers.uc_pll_post_div);
 328
 329        /* SPLL_FUNC_CNTL_3 setup*/
 330        spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
 331                        SPLL_FB_DIV, fbdiv);
 332
 333        /* set to use fractional accumulation*/
 334        spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
 335                        SPLL_DITHEN, 1);
 336
 337        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 338                                PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
 339                struct pp_atomctrl_internal_ss_info ss_info;
 340                uint32_t vco_freq = clock * dividers.uc_pll_post_div;
 341
 342                if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
 343                                vco_freq, &ss_info)) {
 344                        uint32_t clk_s = ref_clock * 5 /
 345                                        (ref_divider * ss_info.speed_spectrum_rate);
 346                        uint32_t clk_v = 4 * ss_info.speed_spectrum_percentage *
 347                                        fbdiv / (clk_s * 10000);
 348
 349                        cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
 350                                        CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
 351                        cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
 352                                        CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
 353                        cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
 354                                        CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
 355                }
 356        }
 357
 358        sclk->SclkFrequency        = clock;
 359        sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
 360        sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
 361        sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
 362        sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
 363        sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
 364
 365        return 0;
 366}
 367
 368static void ci_populate_phase_value_based_on_sclk(struct pp_hwmgr *hwmgr,
 369                                const struct phm_phase_shedding_limits_table *pl,
 370                                        uint32_t sclk, uint32_t *p_shed)
 371{
 372        unsigned int i;
 373
 374        /* use the minimum phase shedding */
 375        *p_shed = 1;
 376
 377        for (i = 0; i < pl->count; i++) {
 378                if (sclk < pl->entries[i].Sclk) {
 379                        *p_shed = i;
 380                        break;
 381                }
 382        }
 383}
 384
 385static uint8_t ci_get_sleep_divider_id_from_clock(uint32_t clock,
 386                        uint32_t clock_insr)
 387{
 388        uint8_t i;
 389        uint32_t temp;
 390        uint32_t min = min_t(uint32_t, clock_insr, CISLAND_MINIMUM_ENGINE_CLOCK);
 391
 392        if (clock < min) {
 393                pr_info("Engine clock can't satisfy stutter requirement!\n");
 394                return 0;
 395        }
 396        for (i = CISLAND_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
 397                temp = clock >> i;
 398
 399                if (temp >= min || i == 0)
 400                        break;
 401        }
 402        return i;
 403}
 404
 405static int ci_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
 406                uint32_t clock, struct SMU7_Discrete_GraphicsLevel *level)
 407{
 408        int result;
 409        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 410
 411
 412        result = ci_calculate_sclk_params(hwmgr, clock, level);
 413
 414        /* populate graphics levels */
 415        result = ci_get_dependency_volt_by_clk(hwmgr,
 416                        hwmgr->dyn_state.vddc_dependency_on_sclk, clock,
 417                        (uint32_t *)(&level->MinVddc));
 418        if (result) {
 419                pr_err("vdd_dep_on_sclk table is NULL\n");
 420                return result;
 421        }
 422
 423        level->SclkFrequency = clock;
 424        level->MinVddcPhases = 1;
 425
 426        if (data->vddc_phase_shed_control)
 427                ci_populate_phase_value_based_on_sclk(hwmgr,
 428                                hwmgr->dyn_state.vddc_phase_shed_limits_table,
 429                                clock,
 430                                &level->MinVddcPhases);
 431
 432        level->ActivityLevel = data->current_profile_setting.sclk_activity;
 433        level->CcPwrDynRm = 0;
 434        level->CcPwrDynRm1 = 0;
 435        level->EnabledForActivity = 0;
 436        /* this level can be used for throttling.*/
 437        level->EnabledForThrottle = 1;
 438        level->UpH = data->current_profile_setting.sclk_up_hyst;
 439        level->DownH = data->current_profile_setting.sclk_down_hyst;
 440        level->VoltageDownH = 0;
 441        level->PowerThrottle = 0;
 442
 443
 444        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 445                        PHM_PlatformCaps_SclkDeepSleep))
 446                level->DeepSleepDivId =
 447                                ci_get_sleep_divider_id_from_clock(clock,
 448                                                CISLAND_MINIMUM_ENGINE_CLOCK);
 449
 450        /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
 451        level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
 452
 453        if (0 == result) {
 454                level->MinVddc = PP_HOST_TO_SMC_UL(level->MinVddc * VOLTAGE_SCALE);
 455                CONVERT_FROM_HOST_TO_SMC_UL(level->MinVddcPhases);
 456                CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
 457                CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
 458                CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
 459                CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
 460                CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
 461                CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
 462                CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
 463                CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
 464        }
 465
 466        return result;
 467}
 468
 469static int ci_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
 470{
 471        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 472        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 473        struct smu7_dpm_table *dpm_table = &data->dpm_table;
 474        int result = 0;
 475        uint32_t array = smu_data->dpm_table_start +
 476                        offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
 477        uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) *
 478                        SMU7_MAX_LEVELS_GRAPHICS;
 479        struct SMU7_Discrete_GraphicsLevel *levels =
 480                        smu_data->smc_state_table.GraphicsLevel;
 481        uint32_t i;
 482
 483        for (i = 0; i < dpm_table->sclk_table.count; i++) {
 484                result = ci_populate_single_graphic_level(hwmgr,
 485                                dpm_table->sclk_table.dpm_levels[i].value,
 486                                &levels[i]);
 487                if (result)
 488                        return result;
 489                if (i > 1)
 490                        smu_data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
 491                if (i == (dpm_table->sclk_table.count - 1))
 492                        smu_data->smc_state_table.GraphicsLevel[i].DisplayWatermark =
 493                                PPSMC_DISPLAY_WATERMARK_HIGH;
 494        }
 495
 496        smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
 497
 498        smu_data->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count;
 499        data->dpm_level_enable_mask.sclk_dpm_enable_mask =
 500                phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
 501
 502        result = ci_copy_bytes_to_smc(hwmgr, array,
 503                                   (u8 *)levels, array_size,
 504                                   SMC_RAM_END);
 505
 506        return result;
 507
 508}
 509
 510static int ci_populate_svi_load_line(struct pp_hwmgr *hwmgr)
 511{
 512        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 513        const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
 514
 515        smu_data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
 516        smu_data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddc;
 517        smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
 518        smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
 519
 520        return 0;
 521}
 522
 523static int ci_populate_tdc_limit(struct pp_hwmgr *hwmgr)
 524{
 525        uint16_t tdc_limit;
 526        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 527        const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
 528
 529        tdc_limit = (uint16_t)(hwmgr->dyn_state.cac_dtp_table->usTDC * 256);
 530        smu_data->power_tune_table.TDC_VDDC_PkgLimit =
 531                        CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
 532        smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
 533                        defaults->tdc_vddc_throttle_release_limit_perc;
 534        smu_data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
 535
 536        return 0;
 537}
 538
 539static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
 540{
 541        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 542        const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
 543        uint32_t temp;
 544
 545        if (ci_read_smc_sram_dword(hwmgr,
 546                        fuse_table_offset +
 547                        offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
 548                        (uint32_t *)&temp, SMC_RAM_END))
 549                PP_ASSERT_WITH_CODE(false,
 550                                "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
 551                                return -EINVAL);
 552        else
 553                smu_data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
 554
 555        return 0;
 556}
 557
 558static int ci_populate_fuzzy_fan(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
 559{
 560        uint16_t tmp;
 561        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 562
 563        if ((hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity & (1 << 15))
 564                || 0 == hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity)
 565                tmp = hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity;
 566        else
 567                tmp = hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity;
 568
 569        smu_data->power_tune_table.FuzzyFan_PwmSetDelta = CONVERT_FROM_HOST_TO_SMC_US(tmp);
 570
 571        return 0;
 572}
 573
 574static int ci_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr)
 575{
 576        int i;
 577        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 578        uint8_t *hi_vid = smu_data->power_tune_table.BapmVddCVidHiSidd;
 579        uint8_t *lo_vid = smu_data->power_tune_table.BapmVddCVidLoSidd;
 580        uint8_t *hi2_vid = smu_data->power_tune_table.BapmVddCVidHiSidd2;
 581
 582        PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.cac_leakage_table,
 583                            "The CAC Leakage table does not exist!", return -EINVAL);
 584        PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count <= 8,
 585                            "There should never be more than 8 entries for BapmVddcVid!!!", return -EINVAL);
 586        PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count == hwmgr->dyn_state.vddc_dependency_on_sclk->count,
 587                            "CACLeakageTable->count and VddcDependencyOnSCLk->count not equal", return -EINVAL);
 588
 589        for (i = 0; (uint32_t) i < hwmgr->dyn_state.cac_leakage_table->count; i++) {
 590                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EVV)) {
 591                        lo_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc1);
 592                        hi_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc2);
 593                        hi2_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc3);
 594                } else {
 595                        lo_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc);
 596                        hi_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Leakage);
 597                }
 598        }
 599
 600        return 0;
 601}
 602
 603static int ci_populate_vddc_vid(struct pp_hwmgr *hwmgr)
 604{
 605        int i;
 606        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 607        uint8_t *vid = smu_data->power_tune_table.VddCVid;
 608        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 609
 610        PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 8,
 611                "There should never be more than 8 entries for VddcVid!!!",
 612                return -EINVAL);
 613
 614        for (i = 0; i < (int)data->vddc_voltage_table.count; i++)
 615                vid[i] = convert_to_vid(data->vddc_voltage_table.entries[i].value);
 616
 617        return 0;
 618}
 619
 620static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct pp_hwmgr *hwmgr)
 621{
 622        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 623        u8 *hi_vid = smu_data->power_tune_table.BapmVddCVidHiSidd;
 624        u8 *lo_vid = smu_data->power_tune_table.BapmVddCVidLoSidd;
 625        int i, min, max;
 626
 627        min = max = hi_vid[0];
 628        for (i = 0; i < 8; i++) {
 629                if (0 != hi_vid[i]) {
 630                        if (min > hi_vid[i])
 631                                min = hi_vid[i];
 632                        if (max < hi_vid[i])
 633                                max = hi_vid[i];
 634                }
 635
 636                if (0 != lo_vid[i]) {
 637                        if (min > lo_vid[i])
 638                                min = lo_vid[i];
 639                        if (max < lo_vid[i])
 640                                max = lo_vid[i];
 641                }
 642        }
 643
 644        if ((min == 0) || (max == 0))
 645                return -EINVAL;
 646        smu_data->power_tune_table.GnbLPMLMaxVid = (u8)max;
 647        smu_data->power_tune_table.GnbLPMLMinVid = (u8)min;
 648
 649        return 0;
 650}
 651
 652static int ci_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
 653{
 654        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 655        uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
 656        uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
 657        struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
 658
 659        HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
 660        LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
 661
 662        smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
 663                        CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
 664        smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
 665                        CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
 666
 667        return 0;
 668}
 669
 670static int ci_populate_pm_fuses(struct pp_hwmgr *hwmgr)
 671{
 672        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 673        uint32_t pm_fuse_table_offset;
 674        int ret = 0;
 675
 676        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 677                        PHM_PlatformCaps_PowerContainment)) {
 678                if (ci_read_smc_sram_dword(hwmgr,
 679                                SMU7_FIRMWARE_HEADER_LOCATION +
 680                                offsetof(SMU7_Firmware_Header, PmFuseTable),
 681                                &pm_fuse_table_offset, SMC_RAM_END)) {
 682                        pr_err("Attempt to get pm_fuse_table_offset Failed!\n");
 683                        return -EINVAL;
 684                }
 685
 686                /* DW0 - DW3 */
 687                ret = ci_populate_bapm_vddc_vid_sidd(hwmgr);
 688                /* DW4 - DW5 */
 689                ret |= ci_populate_vddc_vid(hwmgr);
 690                /* DW6 */
 691                ret |= ci_populate_svi_load_line(hwmgr);
 692                /* DW7 */
 693                ret |= ci_populate_tdc_limit(hwmgr);
 694                /* DW8 */
 695                ret |= ci_populate_dw8(hwmgr, pm_fuse_table_offset);
 696
 697                ret |= ci_populate_fuzzy_fan(hwmgr, pm_fuse_table_offset);
 698
 699                ret |= ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(hwmgr);
 700
 701                ret |= ci_populate_bapm_vddc_base_leakage_sidd(hwmgr);
 702                if (ret)
 703                        return ret;
 704
 705                ret = ci_copy_bytes_to_smc(hwmgr, pm_fuse_table_offset,
 706                                (uint8_t *)&smu_data->power_tune_table,
 707                                sizeof(struct SMU7_Discrete_PmFuses), SMC_RAM_END);
 708        }
 709        return ret;
 710}
 711
 712static int ci_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
 713{
 714        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 715        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 716        const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
 717        SMU7_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
 718        struct phm_cac_tdp_table *cac_dtp_table = hwmgr->dyn_state.cac_dtp_table;
 719        struct phm_ppm_table *ppm = hwmgr->dyn_state.ppm_parameter_table;
 720        const uint16_t *def1, *def2;
 721        int i, j, k;
 722
 723        dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 256));
 724        dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
 725
 726        dpm_table->DTETjOffset = 0;
 727        dpm_table->GpuTjMax = (uint8_t)(data->thermal_temp_setting.temperature_high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES);
 728        dpm_table->GpuTjHyst = 8;
 729
 730        dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
 731
 732        if (ppm) {
 733                dpm_table->PPM_PkgPwrLimit = (uint16_t)ppm->dgpu_tdp * 256 / 1000;
 734                dpm_table->PPM_TemperatureLimit = (uint16_t)ppm->tj_max * 256;
 735        } else {
 736                dpm_table->PPM_PkgPwrLimit = 0;
 737                dpm_table->PPM_TemperatureLimit = 0;
 738        }
 739
 740        CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_PkgPwrLimit);
 741        CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_TemperatureLimit);
 742
 743        dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bapm_temp_gradient);
 744        def1 = defaults->bapmti_r;
 745        def2 = defaults->bapmti_rc;
 746
 747        for (i = 0; i < SMU7_DTE_ITERATIONS; i++) {
 748                for (j = 0; j < SMU7_DTE_SOURCES; j++) {
 749                        for (k = 0; k < SMU7_DTE_SINKS; k++) {
 750                                dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*def1);
 751                                dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*def2);
 752                                def1++;
 753                                def2++;
 754                        }
 755                }
 756        }
 757
 758        return 0;
 759}
 760
 761static int ci_get_std_voltage_value_sidd(struct pp_hwmgr *hwmgr,
 762                pp_atomctrl_voltage_table_entry *tab, uint16_t *hi,
 763                uint16_t *lo)
 764{
 765        uint16_t v_index;
 766        bool vol_found = false;
 767        *hi = tab->value * VOLTAGE_SCALE;
 768        *lo = tab->value * VOLTAGE_SCALE;
 769
 770        PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.vddc_dependency_on_sclk,
 771                        "The SCLK/VDDC Dependency Table does not exist.\n",
 772                        return -EINVAL);
 773
 774        if (NULL == hwmgr->dyn_state.cac_leakage_table) {
 775                pr_warn("CAC Leakage Table does not exist, using vddc.\n");
 776                return 0;
 777        }
 778
 779        for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
 780                if (tab->value == hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
 781                        vol_found = true;
 782                        if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
 783                                *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
 784                                *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage * VOLTAGE_SCALE);
 785                        } else {
 786                                pr_warn("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index, using maximum index from CAC table.\n");
 787                                *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
 788                                *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
 789                        }
 790                        break;
 791                }
 792        }
 793
 794        if (!vol_found) {
 795                for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
 796                        if (tab->value <= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
 797                                vol_found = true;
 798                                if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
 799                                        *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
 800                                        *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage) * VOLTAGE_SCALE;
 801                                } else {
 802                                        pr_warn("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index in second look up, using maximum index from CAC table.");
 803                                        *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
 804                                        *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
 805                                }
 806                                break;
 807                        }
 808                }
 809
 810                if (!vol_found)
 811                        pr_warn("Unable to get std_vddc from SCLK/VDDC Dependency Table, using vddc.\n");
 812        }
 813
 814        return 0;
 815}
 816
 817static int ci_populate_smc_voltage_table(struct pp_hwmgr *hwmgr,
 818                pp_atomctrl_voltage_table_entry *tab,
 819                SMU7_Discrete_VoltageLevel *smc_voltage_tab)
 820{
 821        int result;
 822
 823        result = ci_get_std_voltage_value_sidd(hwmgr, tab,
 824                        &smc_voltage_tab->StdVoltageHiSidd,
 825                        &smc_voltage_tab->StdVoltageLoSidd);
 826        if (result) {
 827                smc_voltage_tab->StdVoltageHiSidd = tab->value * VOLTAGE_SCALE;
 828                smc_voltage_tab->StdVoltageLoSidd = tab->value * VOLTAGE_SCALE;
 829        }
 830
 831        smc_voltage_tab->Voltage = PP_HOST_TO_SMC_US(tab->value * VOLTAGE_SCALE);
 832        CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd);
 833        CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageLoSidd);
 834
 835        return 0;
 836}
 837
 838static int ci_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
 839                        SMU7_Discrete_DpmTable *table)
 840{
 841        unsigned int count;
 842        int result;
 843        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 844
 845        table->VddcLevelCount = data->vddc_voltage_table.count;
 846        for (count = 0; count < table->VddcLevelCount; count++) {
 847                result = ci_populate_smc_voltage_table(hwmgr,
 848                                &(data->vddc_voltage_table.entries[count]),
 849                                &(table->VddcLevel[count]));
 850                PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDC voltage table", return -EINVAL);
 851
 852                /* GPIO voltage control */
 853                if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) {
 854                        table->VddcLevel[count].Smio = (uint8_t) count;
 855                        table->Smio[count] |= data->vddc_voltage_table.entries[count].smio_low;
 856                        table->SmioMaskVddcVid |= data->vddc_voltage_table.entries[count].smio_low;
 857                } else {
 858                        table->VddcLevel[count].Smio = 0;
 859                }
 860        }
 861
 862        CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
 863
 864        return 0;
 865}
 866
 867static int ci_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
 868                        SMU7_Discrete_DpmTable *table)
 869{
 870        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 871        uint32_t count;
 872        int result;
 873
 874        table->VddciLevelCount = data->vddci_voltage_table.count;
 875
 876        for (count = 0; count < table->VddciLevelCount; count++) {
 877                result = ci_populate_smc_voltage_table(hwmgr,
 878                                &(data->vddci_voltage_table.entries[count]),
 879                                &(table->VddciLevel[count]));
 880                PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC VDDCI voltage table", return -EINVAL);
 881                if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
 882                        table->VddciLevel[count].Smio = (uint8_t) count;
 883                        table->Smio[count] |= data->vddci_voltage_table.entries[count].smio_low;
 884                        table->SmioMaskVddciVid |= data->vddci_voltage_table.entries[count].smio_low;
 885                } else {
 886                        table->VddciLevel[count].Smio = 0;
 887                }
 888        }
 889
 890        CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
 891
 892        return 0;
 893}
 894
 895static int ci_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
 896                        SMU7_Discrete_DpmTable *table)
 897{
 898        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 899        uint32_t count;
 900        int result;
 901
 902        table->MvddLevelCount = data->mvdd_voltage_table.count;
 903
 904        for (count = 0; count < table->MvddLevelCount; count++) {
 905                result = ci_populate_smc_voltage_table(hwmgr,
 906                                &(data->mvdd_voltage_table.entries[count]),
 907                                &table->MvddLevel[count]);
 908                PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC mvdd voltage table", return -EINVAL);
 909                if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
 910                        table->MvddLevel[count].Smio = (uint8_t) count;
 911                        table->Smio[count] |= data->mvdd_voltage_table.entries[count].smio_low;
 912                        table->SmioMaskMvddVid |= data->mvdd_voltage_table.entries[count].smio_low;
 913                } else {
 914                        table->MvddLevel[count].Smio = 0;
 915                }
 916        }
 917
 918        CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
 919
 920        return 0;
 921}
 922
 923
 924static int ci_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
 925        SMU7_Discrete_DpmTable *table)
 926{
 927        int result;
 928
 929        result = ci_populate_smc_vddc_table(hwmgr, table);
 930        PP_ASSERT_WITH_CODE(0 == result,
 931                        "can not populate VDDC voltage table to SMC", return -EINVAL);
 932
 933        result = ci_populate_smc_vdd_ci_table(hwmgr, table);
 934        PP_ASSERT_WITH_CODE(0 == result,
 935                        "can not populate VDDCI voltage table to SMC", return -EINVAL);
 936
 937        result = ci_populate_smc_mvdd_table(hwmgr, table);
 938        PP_ASSERT_WITH_CODE(0 == result,
 939                        "can not populate MVDD voltage table to SMC", return -EINVAL);
 940
 941        return 0;
 942}
 943
 944static int ci_populate_ulv_level(struct pp_hwmgr *hwmgr,
 945                struct SMU7_Discrete_Ulv *state)
 946{
 947        uint32_t voltage_response_time, ulv_voltage;
 948        int result;
 949        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 950
 951        state->CcPwrDynRm = 0;
 952        state->CcPwrDynRm1 = 0;
 953
 954        result = pp_tables_get_response_times(hwmgr, &voltage_response_time, &ulv_voltage);
 955        PP_ASSERT_WITH_CODE((0 == result), "can not get ULV voltage value", return result;);
 956
 957        if (ulv_voltage == 0) {
 958                data->ulv_supported = false;
 959                return 0;
 960        }
 961
 962        if (data->voltage_control != SMU7_VOLTAGE_CONTROL_BY_SVID2) {
 963                /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
 964                if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
 965                        state->VddcOffset = 0;
 966                else
 967                        /* used in SMIO Mode. not implemented for now. this is backup only for CI. */
 968                        state->VddcOffset = (uint16_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage);
 969        } else {
 970                /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
 971                if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
 972                        state->VddcOffsetVid = 0;
 973                else  /* used in SVI2 Mode */
 974                        state->VddcOffsetVid = (uint8_t)(
 975                                        (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage)
 976                                                * VOLTAGE_VID_OFFSET_SCALE2
 977                                                / VOLTAGE_VID_OFFSET_SCALE1);
 978        }
 979        state->VddcPhase = 1;
 980
 981        CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
 982        CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
 983        CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
 984
 985        return 0;
 986}
 987
 988static int ci_populate_ulv_state(struct pp_hwmgr *hwmgr,
 989                 SMU7_Discrete_Ulv *ulv_level)
 990{
 991        return ci_populate_ulv_level(hwmgr, ulv_level);
 992}
 993
 994static int ci_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU7_Discrete_DpmTable *table)
 995{
 996        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 997        struct smu7_dpm_table *dpm_table = &data->dpm_table;
 998        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
 999        uint32_t i;
1000
1001/* Index dpm_table->pcie_speed_table.count is reserved for PCIE boot level.*/
1002        for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
1003                table->LinkLevel[i].PcieGenSpeed  =
1004                        (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
1005                table->LinkLevel[i].PcieLaneCount =
1006                        (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
1007                table->LinkLevel[i].EnabledForActivity = 1;
1008                table->LinkLevel[i].DownT = PP_HOST_TO_SMC_UL(5);
1009                table->LinkLevel[i].UpT = PP_HOST_TO_SMC_UL(30);
1010        }
1011
1012        smu_data->smc_state_table.LinkLevelCount =
1013                (uint8_t)dpm_table->pcie_speed_table.count;
1014        data->dpm_level_enable_mask.pcie_dpm_enable_mask =
1015                phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
1016
1017        return 0;
1018}
1019
1020static int ci_calculate_mclk_params(
1021                struct pp_hwmgr *hwmgr,
1022                uint32_t memory_clock,
1023                SMU7_Discrete_MemoryLevel *mclk,
1024                bool strobe_mode,
1025                bool dllStateOn
1026                )
1027{
1028        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1029        uint32_t  dll_cntl = data->clock_registers.vDLL_CNTL;
1030        uint32_t  mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
1031        uint32_t  mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
1032        uint32_t  mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
1033        uint32_t  mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
1034        uint32_t  mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
1035        uint32_t  mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
1036        uint32_t  mpll_ss1 = data->clock_registers.vMPLL_SS1;
1037        uint32_t  mpll_ss2 = data->clock_registers.vMPLL_SS2;
1038
1039        pp_atomctrl_memory_clock_param mpll_param;
1040        int result;
1041
1042        result = atomctrl_get_memory_pll_dividers_si(hwmgr,
1043                                memory_clock, &mpll_param, strobe_mode);
1044        PP_ASSERT_WITH_CODE(0 == result,
1045                "Error retrieving Memory Clock Parameters from VBIOS.", return result);
1046
1047        mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
1048
1049        mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
1050                                                        MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
1051        mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
1052                                                        MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
1053        mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
1054                                                        MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
1055
1056        mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
1057                                                        MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
1058
1059        if (data->is_memory_gddr5) {
1060                mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
1061                                                                MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
1062                mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
1063                                                                MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
1064        }
1065
1066        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1067                        PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
1068                pp_atomctrl_internal_ss_info ss_info;
1069                uint32_t freq_nom;
1070                uint32_t tmp;
1071                uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
1072
1073                /* for GDDR5 for all modes and DDR3 */
1074                if (1 == mpll_param.qdr)
1075                        freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
1076                else
1077                        freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
1078
1079                /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
1080                tmp = (freq_nom / reference_clock);
1081                tmp = tmp * tmp;
1082
1083                if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
1084                        uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
1085                        uint32_t clkv =
1086                                (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
1087                                                        ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
1088
1089                        mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
1090                        mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
1091                }
1092        }
1093
1094        mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1095                MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
1096        mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1097                MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
1098        mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1099                MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
1100
1101
1102        mclk->MclkFrequency   = memory_clock;
1103        mclk->MpllFuncCntl    = mpll_func_cntl;
1104        mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
1105        mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
1106        mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
1107        mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
1108        mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
1109        mclk->DllCntl         = dll_cntl;
1110        mclk->MpllSs1         = mpll_ss1;
1111        mclk->MpllSs2         = mpll_ss2;
1112
1113        return 0;
1114}
1115
1116static uint8_t ci_get_mclk_frequency_ratio(uint32_t memory_clock,
1117                bool strobe_mode)
1118{
1119        uint8_t mc_para_index;
1120
1121        if (strobe_mode) {
1122                if (memory_clock < 12500)
1123                        mc_para_index = 0x00;
1124                else if (memory_clock > 47500)
1125                        mc_para_index = 0x0f;
1126                else
1127                        mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
1128        } else {
1129                if (memory_clock < 65000)
1130                        mc_para_index = 0x00;
1131                else if (memory_clock > 135000)
1132                        mc_para_index = 0x0f;
1133                else
1134                        mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
1135        }
1136
1137        return mc_para_index;
1138}
1139
1140static uint8_t ci_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
1141{
1142        uint8_t mc_para_index;
1143
1144        if (memory_clock < 10000)
1145                mc_para_index = 0;
1146        else if (memory_clock >= 80000)
1147                mc_para_index = 0x0f;
1148        else
1149                mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
1150
1151        return mc_para_index;
1152}
1153
1154static int ci_populate_phase_value_based_on_mclk(struct pp_hwmgr *hwmgr, const struct phm_phase_shedding_limits_table *pl,
1155                                        uint32_t memory_clock, uint32_t *p_shed)
1156{
1157        unsigned int i;
1158
1159        *p_shed = 1;
1160
1161        for (i = 0; i < pl->count; i++) {
1162                if (memory_clock < pl->entries[i].Mclk) {
1163                        *p_shed = i;
1164                        break;
1165                }
1166        }
1167
1168        return 0;
1169}
1170
1171static int ci_populate_single_memory_level(
1172                struct pp_hwmgr *hwmgr,
1173                uint32_t memory_clock,
1174                SMU7_Discrete_MemoryLevel *memory_level
1175                )
1176{
1177        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1178        int result = 0;
1179        bool dll_state_on;
1180        uint32_t mclk_edc_wr_enable_threshold = 40000;
1181        uint32_t mclk_edc_enable_threshold = 40000;
1182        uint32_t mclk_strobe_mode_threshold = 40000;
1183
1184        if (hwmgr->dyn_state.vddc_dependency_on_mclk != NULL) {
1185                result = ci_get_dependency_volt_by_clk(hwmgr,
1186                        hwmgr->dyn_state.vddc_dependency_on_mclk, memory_clock, &memory_level->MinVddc);
1187                PP_ASSERT_WITH_CODE((0 == result),
1188                        "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
1189        }
1190
1191        if (NULL != hwmgr->dyn_state.vddci_dependency_on_mclk) {
1192                result = ci_get_dependency_volt_by_clk(hwmgr,
1193                                hwmgr->dyn_state.vddci_dependency_on_mclk,
1194                                memory_clock,
1195                                &memory_level->MinVddci);
1196                PP_ASSERT_WITH_CODE((0 == result),
1197                        "can not find MinVddci voltage value from memory VDDCI voltage dependency table", return result);
1198        }
1199
1200        if (NULL != hwmgr->dyn_state.mvdd_dependency_on_mclk) {
1201                result = ci_get_dependency_volt_by_clk(hwmgr,
1202                                hwmgr->dyn_state.mvdd_dependency_on_mclk,
1203                                memory_clock,
1204                                &memory_level->MinMvdd);
1205                PP_ASSERT_WITH_CODE((0 == result),
1206                        "can not find MinVddci voltage value from memory MVDD voltage dependency table", return result);
1207        }
1208
1209        memory_level->MinVddcPhases = 1;
1210
1211        if (data->vddc_phase_shed_control) {
1212                ci_populate_phase_value_based_on_mclk(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table,
1213                                memory_clock, &memory_level->MinVddcPhases);
1214        }
1215
1216        memory_level->EnabledForThrottle = 1;
1217        memory_level->EnabledForActivity = 1;
1218        memory_level->UpH = data->current_profile_setting.mclk_up_hyst;
1219        memory_level->DownH = data->current_profile_setting.mclk_down_hyst;
1220        memory_level->VoltageDownH = 0;
1221
1222        /* Indicates maximum activity level for this performance level.*/
1223        memory_level->ActivityLevel = data->current_profile_setting.mclk_activity;
1224        memory_level->StutterEnable = 0;
1225        memory_level->StrobeEnable = 0;
1226        memory_level->EdcReadEnable = 0;
1227        memory_level->EdcWriteEnable = 0;
1228        memory_level->RttEnable = 0;
1229
1230        /* default set to low watermark. Highest level will be set to high later.*/
1231        memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1232
1233        data->display_timing.num_existing_displays = hwmgr->display_config->num_display;
1234        data->display_timing.vrefresh = hwmgr->display_config->vrefresh;
1235
1236        /* stutter mode not support on ci */
1237
1238        /* decide strobe mode*/
1239        memory_level->StrobeEnable = (mclk_strobe_mode_threshold != 0) &&
1240                (memory_clock <= mclk_strobe_mode_threshold);
1241
1242        /* decide EDC mode and memory clock ratio*/
1243        if (data->is_memory_gddr5) {
1244                memory_level->StrobeRatio = ci_get_mclk_frequency_ratio(memory_clock,
1245                                        memory_level->StrobeEnable);
1246
1247                if ((mclk_edc_enable_threshold != 0) &&
1248                                (memory_clock > mclk_edc_enable_threshold)) {
1249                        memory_level->EdcReadEnable = 1;
1250                }
1251
1252                if ((mclk_edc_wr_enable_threshold != 0) &&
1253                                (memory_clock > mclk_edc_wr_enable_threshold)) {
1254                        memory_level->EdcWriteEnable = 1;
1255                }
1256
1257                if (memory_level->StrobeEnable) {
1258                        if (ci_get_mclk_frequency_ratio(memory_clock, 1) >=
1259                                        ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf))
1260                                dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
1261                        else
1262                                dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
1263                } else
1264                        dll_state_on = data->dll_default_on;
1265        } else {
1266                memory_level->StrobeRatio =
1267                        ci_get_ddr3_mclk_frequency_ratio(memory_clock);
1268                dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
1269        }
1270
1271        result = ci_calculate_mclk_params(hwmgr,
1272                memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
1273
1274        if (0 == result) {
1275                memory_level->MinVddc = PP_HOST_TO_SMC_UL(memory_level->MinVddc * VOLTAGE_SCALE);
1276                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinVddcPhases);
1277                memory_level->MinVddci = PP_HOST_TO_SMC_UL(memory_level->MinVddci * VOLTAGE_SCALE);
1278                memory_level->MinMvdd = PP_HOST_TO_SMC_UL(memory_level->MinMvdd * VOLTAGE_SCALE);
1279                /* MCLK frequency in units of 10KHz*/
1280                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
1281                /* Indicates maximum activity level for this performance level.*/
1282                CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
1283                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
1284                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
1285                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
1286                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
1287                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
1288                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
1289                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
1290                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
1291                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
1292        }
1293
1294        return result;
1295}
1296
1297static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
1298{
1299        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1300        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1301        struct smu7_dpm_table *dpm_table = &data->dpm_table;
1302        int result;
1303        struct amdgpu_device *adev = hwmgr->adev;
1304        uint32_t dev_id;
1305
1306        uint32_t level_array_address = smu_data->dpm_table_start + offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
1307        uint32_t level_array_size = sizeof(SMU7_Discrete_MemoryLevel) * SMU7_MAX_LEVELS_MEMORY;
1308        SMU7_Discrete_MemoryLevel *levels = smu_data->smc_state_table.MemoryLevel;
1309        uint32_t i;
1310
1311        memset(levels, 0x00, level_array_size);
1312
1313        for (i = 0; i < dpm_table->mclk_table.count; i++) {
1314                PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
1315                        "can not populate memory level as memory clock is zero", return -EINVAL);
1316                result = ci_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
1317                        &(smu_data->smc_state_table.MemoryLevel[i]));
1318                if (0 != result)
1319                        return result;
1320        }
1321
1322        smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
1323
1324        dev_id = adev->pdev->device;
1325
1326        if ((dpm_table->mclk_table.count >= 2)
1327                && ((dev_id == 0x67B0) ||  (dev_id == 0x67B1))) {
1328                smu_data->smc_state_table.MemoryLevel[1].MinVddci =
1329                                smu_data->smc_state_table.MemoryLevel[0].MinVddci;
1330                smu_data->smc_state_table.MemoryLevel[1].MinMvdd =
1331                                smu_data->smc_state_table.MemoryLevel[0].MinMvdd;
1332        }
1333        smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
1334        CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
1335
1336        smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
1337        data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
1338        smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
1339
1340        result = ci_copy_bytes_to_smc(hwmgr,
1341                level_array_address, (uint8_t *)levels, (uint32_t)level_array_size,
1342                SMC_RAM_END);
1343
1344        return result;
1345}
1346
1347static int ci_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk,
1348                                        SMU7_Discrete_VoltageLevel *voltage)
1349{
1350        const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1351
1352        uint32_t i = 0;
1353
1354        if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
1355                /* find mvdd value which clock is more than request */
1356                for (i = 0; i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count; i++) {
1357                        if (mclk <= hwmgr->dyn_state.mvdd_dependency_on_mclk->entries[i].clk) {
1358                                /* Always round to higher voltage. */
1359                                voltage->Voltage = data->mvdd_voltage_table.entries[i].value;
1360                                break;
1361                        }
1362                }
1363
1364                PP_ASSERT_WITH_CODE(i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count,
1365                        "MVDD Voltage is outside the supported range.", return -EINVAL);
1366
1367        } else {
1368                return -EINVAL;
1369        }
1370
1371        return 0;
1372}
1373
1374static int ci_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
1375        SMU7_Discrete_DpmTable *table)
1376{
1377        int result = 0;
1378        const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1379        struct pp_atomctrl_clock_dividers_vi dividers;
1380
1381        SMU7_Discrete_VoltageLevel voltage_level;
1382        uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
1383        uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
1384        uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
1385        uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
1386
1387
1388        /* The ACPI state should not do DPM on DC (or ever).*/
1389        table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
1390
1391        if (data->acpi_vddc)
1392                table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->acpi_vddc * VOLTAGE_SCALE);
1393        else
1394                table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->min_vddc_in_pptable * VOLTAGE_SCALE);
1395
1396        table->ACPILevel.MinVddcPhases = data->vddc_phase_shed_control ? 0 : 1;
1397        /* assign zero for now*/
1398        table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
1399
1400        /* get the engine clock dividers for this clock value*/
1401        result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
1402                table->ACPILevel.SclkFrequency,  &dividers);
1403
1404        PP_ASSERT_WITH_CODE(result == 0,
1405                "Error retrieving Engine Clock dividers from VBIOS.", return result);
1406
1407        /* divider ID for required SCLK*/
1408        table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
1409        table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1410        table->ACPILevel.DeepSleepDivId = 0;
1411
1412        spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
1413                                                        CG_SPLL_FUNC_CNTL,   SPLL_PWRON,     0);
1414        spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
1415                                                        CG_SPLL_FUNC_CNTL,   SPLL_RESET,     1);
1416        spll_func_cntl_2    = PHM_SET_FIELD(spll_func_cntl_2,
1417                                                        CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL,   4);
1418
1419        table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
1420        table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
1421        table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
1422        table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
1423        table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
1424        table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
1425        table->ACPILevel.CcPwrDynRm = 0;
1426        table->ACPILevel.CcPwrDynRm1 = 0;
1427
1428        /* For various features to be enabled/disabled while this level is active.*/
1429        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
1430        /* SCLK frequency in units of 10KHz*/
1431        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
1432        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
1433        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
1434        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
1435        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
1436        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
1437        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
1438        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
1439        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
1440
1441
1442        /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
1443        table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
1444        table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
1445
1446        if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
1447                table->MemoryACPILevel.MinVddci = table->MemoryACPILevel.MinVddc;
1448        else {
1449                if (data->acpi_vddci != 0)
1450                        table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->acpi_vddci * VOLTAGE_SCALE);
1451                else
1452                        table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->min_vddci_in_pptable * VOLTAGE_SCALE);
1453        }
1454
1455        if (0 == ci_populate_mvdd_value(hwmgr, 0, &voltage_level))
1456                table->MemoryACPILevel.MinMvdd =
1457                        PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
1458        else
1459                table->MemoryACPILevel.MinMvdd = 0;
1460
1461        /* Force reset on DLL*/
1462        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1463                MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
1464        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1465                MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
1466
1467        /* Disable DLL in ACPIState*/
1468        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1469                MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
1470        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1471                MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
1472
1473        /* Enable DLL bypass signal*/
1474        dll_cntl            = PHM_SET_FIELD(dll_cntl,
1475                DLL_CNTL, MRDCK0_BYPASS, 0);
1476        dll_cntl            = PHM_SET_FIELD(dll_cntl,
1477                DLL_CNTL, MRDCK1_BYPASS, 0);
1478
1479        table->MemoryACPILevel.DllCntl            =
1480                PP_HOST_TO_SMC_UL(dll_cntl);
1481        table->MemoryACPILevel.MclkPwrmgtCntl     =
1482                PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
1483        table->MemoryACPILevel.MpllAdFuncCntl     =
1484                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
1485        table->MemoryACPILevel.MpllDqFuncCntl     =
1486                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
1487        table->MemoryACPILevel.MpllFuncCntl       =
1488                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
1489        table->MemoryACPILevel.MpllFuncCntl_1     =
1490                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
1491        table->MemoryACPILevel.MpllFuncCntl_2     =
1492                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
1493        table->MemoryACPILevel.MpllSs1            =
1494                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
1495        table->MemoryACPILevel.MpllSs2            =
1496                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
1497
1498        table->MemoryACPILevel.EnabledForThrottle = 0;
1499        table->MemoryACPILevel.EnabledForActivity = 0;
1500        table->MemoryACPILevel.UpH = 0;
1501        table->MemoryACPILevel.DownH = 100;
1502        table->MemoryACPILevel.VoltageDownH = 0;
1503        /* Indicates maximum activity level for this performance level.*/
1504        table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity);
1505
1506        table->MemoryACPILevel.StutterEnable = 0;
1507        table->MemoryACPILevel.StrobeEnable = 0;
1508        table->MemoryACPILevel.EdcReadEnable = 0;
1509        table->MemoryACPILevel.EdcWriteEnable = 0;
1510        table->MemoryACPILevel.RttEnable = 0;
1511
1512        return result;
1513}
1514
1515static int ci_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
1516                                        SMU7_Discrete_DpmTable *table)
1517{
1518        int result = 0;
1519        uint8_t count;
1520        struct pp_atomctrl_clock_dividers_vi dividers;
1521        struct phm_uvd_clock_voltage_dependency_table *uvd_table =
1522                hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
1523
1524        table->UvdLevelCount = (uint8_t)(uvd_table->count);
1525
1526        for (count = 0; count < table->UvdLevelCount; count++) {
1527                table->UvdLevel[count].VclkFrequency =
1528                                        uvd_table->entries[count].vclk;
1529                table->UvdLevel[count].DclkFrequency =
1530                                        uvd_table->entries[count].dclk;
1531                table->UvdLevel[count].MinVddc =
1532                                        uvd_table->entries[count].v * VOLTAGE_SCALE;
1533                table->UvdLevel[count].MinVddcPhases = 1;
1534
1535                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1536                                table->UvdLevel[count].VclkFrequency, &dividers);
1537                PP_ASSERT_WITH_CODE((0 == result),
1538                                "can not find divide id for Vclk clock", return result);
1539
1540                table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
1541
1542                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1543                                table->UvdLevel[count].DclkFrequency, &dividers);
1544                PP_ASSERT_WITH_CODE((0 == result),
1545                                "can not find divide id for Dclk clock", return result);
1546
1547                table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
1548                CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
1549                CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
1550                CONVERT_FROM_HOST_TO_SMC_US(table->UvdLevel[count].MinVddc);
1551        }
1552
1553        return result;
1554}
1555
1556static int ci_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
1557                SMU7_Discrete_DpmTable *table)
1558{
1559        int result = -EINVAL;
1560        uint8_t count;
1561        struct pp_atomctrl_clock_dividers_vi dividers;
1562        struct phm_vce_clock_voltage_dependency_table *vce_table =
1563                                hwmgr->dyn_state.vce_clock_voltage_dependency_table;
1564
1565        table->VceLevelCount = (uint8_t)(vce_table->count);
1566        table->VceBootLevel = 0;
1567
1568        for (count = 0; count < table->VceLevelCount; count++) {
1569                table->VceLevel[count].Frequency = vce_table->entries[count].evclk;
1570                table->VceLevel[count].MinVoltage =
1571                                vce_table->entries[count].v * VOLTAGE_SCALE;
1572                table->VceLevel[count].MinPhases = 1;
1573
1574                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1575                                table->VceLevel[count].Frequency, &dividers);
1576                PP_ASSERT_WITH_CODE((0 == result),
1577                                "can not find divide id for VCE engine clock",
1578                                return result);
1579
1580                table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1581
1582                CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
1583                CONVERT_FROM_HOST_TO_SMC_US(table->VceLevel[count].MinVoltage);
1584        }
1585        return result;
1586}
1587
1588static int ci_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
1589                                        SMU7_Discrete_DpmTable *table)
1590{
1591        int result = -EINVAL;
1592        uint8_t count;
1593        struct pp_atomctrl_clock_dividers_vi dividers;
1594        struct phm_acp_clock_voltage_dependency_table *acp_table =
1595                                hwmgr->dyn_state.acp_clock_voltage_dependency_table;
1596
1597        table->AcpLevelCount = (uint8_t)(acp_table->count);
1598        table->AcpBootLevel = 0;
1599
1600        for (count = 0; count < table->AcpLevelCount; count++) {
1601                table->AcpLevel[count].Frequency = acp_table->entries[count].acpclk;
1602                table->AcpLevel[count].MinVoltage = acp_table->entries[count].v;
1603                table->AcpLevel[count].MinPhases = 1;
1604
1605                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1606                                table->AcpLevel[count].Frequency, &dividers);
1607                PP_ASSERT_WITH_CODE((0 == result),
1608                                "can not find divide id for engine clock", return result);
1609
1610                table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1611
1612                CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
1613                CONVERT_FROM_HOST_TO_SMC_US(table->AcpLevel[count].MinVoltage);
1614        }
1615        return result;
1616}
1617
1618static int ci_populate_memory_timing_parameters(
1619                struct pp_hwmgr *hwmgr,
1620                uint32_t engine_clock,
1621                uint32_t memory_clock,
1622                struct SMU7_Discrete_MCArbDramTimingTableEntry *arb_regs
1623                )
1624{
1625        uint32_t dramTiming;
1626        uint32_t dramTiming2;
1627        uint32_t burstTime;
1628        int result;
1629
1630        result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
1631                                engine_clock, memory_clock);
1632
1633        PP_ASSERT_WITH_CODE(result == 0,
1634                "Error calling VBIOS to set DRAM_TIMING.", return result);
1635
1636        dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
1637        dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
1638        burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
1639
1640        arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
1641        arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
1642        arb_regs->McArbBurstTime = (uint8_t)burstTime;
1643
1644        return 0;
1645}
1646
1647static int ci_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
1648{
1649        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1650        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1651        int result = 0;
1652        SMU7_Discrete_MCArbDramTimingTable  arb_regs;
1653        uint32_t i, j;
1654
1655        memset(&arb_regs, 0x00, sizeof(SMU7_Discrete_MCArbDramTimingTable));
1656
1657        for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
1658                for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
1659                        result = ci_populate_memory_timing_parameters
1660                                (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
1661                                 data->dpm_table.mclk_table.dpm_levels[j].value,
1662                                 &arb_regs.entries[i][j]);
1663
1664                        if (0 != result)
1665                                break;
1666                }
1667        }
1668
1669        if (0 == result) {
1670                result = ci_copy_bytes_to_smc(
1671                                hwmgr,
1672                                smu_data->arb_table_start,
1673                                (uint8_t *)&arb_regs,
1674                                sizeof(SMU7_Discrete_MCArbDramTimingTable),
1675                                SMC_RAM_END
1676                                );
1677        }
1678
1679        return result;
1680}
1681
1682static int ci_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
1683                        SMU7_Discrete_DpmTable *table)
1684{
1685        int result = 0;
1686        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1687        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1688
1689        table->GraphicsBootLevel = 0;
1690        table->MemoryBootLevel = 0;
1691
1692        /* find boot level from dpm table*/
1693        result = phm_find_boot_level(&(data->dpm_table.sclk_table),
1694                        data->vbios_boot_state.sclk_bootup_value,
1695                        (uint32_t *)&(smu_data->smc_state_table.GraphicsBootLevel));
1696
1697        if (0 != result) {
1698                smu_data->smc_state_table.GraphicsBootLevel = 0;
1699                pr_err("VBIOS did not find boot engine clock value in dependency table. Using Graphics DPM level 0!\n");
1700                result = 0;
1701        }
1702
1703        result = phm_find_boot_level(&(data->dpm_table.mclk_table),
1704                data->vbios_boot_state.mclk_bootup_value,
1705                (uint32_t *)&(smu_data->smc_state_table.MemoryBootLevel));
1706
1707        if (0 != result) {
1708                smu_data->smc_state_table.MemoryBootLevel = 0;
1709                pr_err("VBIOS did not find boot engine clock value in dependency table. Using Memory DPM level 0!\n");
1710                result = 0;
1711        }
1712
1713        table->BootVddc = data->vbios_boot_state.vddc_bootup_value;
1714        table->BootVddci = data->vbios_boot_state.vddci_bootup_value;
1715        table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
1716
1717        return result;
1718}
1719
1720static int ci_populate_mc_reg_address(struct pp_hwmgr *hwmgr,
1721                                 SMU7_Discrete_MCRegisters *mc_reg_table)
1722{
1723        const struct ci_smumgr *smu_data = (struct ci_smumgr *)hwmgr->smu_backend;
1724
1725        uint32_t i, j;
1726
1727        for (i = 0, j = 0; j < smu_data->mc_reg_table.last; j++) {
1728                if (smu_data->mc_reg_table.validflag & 1<<j) {
1729                        PP_ASSERT_WITH_CODE(i < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE,
1730                                "Index of mc_reg_table->address[] array out of boundary", return -EINVAL);
1731                        mc_reg_table->address[i].s0 =
1732                                PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s0);
1733                        mc_reg_table->address[i].s1 =
1734                                PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s1);
1735                        i++;
1736                }
1737        }
1738
1739        mc_reg_table->last = (uint8_t)i;
1740
1741        return 0;
1742}
1743
1744static void ci_convert_mc_registers(
1745        const struct ci_mc_reg_entry *entry,
1746        SMU7_Discrete_MCRegisterSet *data,
1747        uint32_t num_entries, uint32_t valid_flag)
1748{
1749        uint32_t i, j;
1750
1751        for (i = 0, j = 0; j < num_entries; j++) {
1752                if (valid_flag & 1<<j) {
1753                        data->value[i] = PP_HOST_TO_SMC_UL(entry->mc_data[j]);
1754                        i++;
1755                }
1756        }
1757}
1758
1759static int ci_convert_mc_reg_table_entry_to_smc(
1760                struct pp_hwmgr *hwmgr,
1761                const uint32_t memory_clock,
1762                SMU7_Discrete_MCRegisterSet *mc_reg_table_data
1763                )
1764{
1765        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1766        uint32_t i = 0;
1767
1768        for (i = 0; i < smu_data->mc_reg_table.num_entries; i++) {
1769                if (memory_clock <=
1770                        smu_data->mc_reg_table.mc_reg_table_entry[i].mclk_max) {
1771                        break;
1772                }
1773        }
1774
1775        if ((i == smu_data->mc_reg_table.num_entries) && (i > 0))
1776                --i;
1777
1778        ci_convert_mc_registers(&smu_data->mc_reg_table.mc_reg_table_entry[i],
1779                                mc_reg_table_data, smu_data->mc_reg_table.last,
1780                                smu_data->mc_reg_table.validflag);
1781
1782        return 0;
1783}
1784
1785static int ci_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
1786                SMU7_Discrete_MCRegisters *mc_regs)
1787{
1788        int result = 0;
1789        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1790        int res;
1791        uint32_t i;
1792
1793        for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
1794                res = ci_convert_mc_reg_table_entry_to_smc(
1795                                hwmgr,
1796                                data->dpm_table.mclk_table.dpm_levels[i].value,
1797                                &mc_regs->data[i]
1798                                );
1799
1800                if (0 != res)
1801                        result = res;
1802        }
1803
1804        return result;
1805}
1806
1807static int ci_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
1808{
1809        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1810        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1811        uint32_t address;
1812        int32_t result;
1813
1814        if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
1815                return 0;
1816
1817
1818        memset(&smu_data->mc_regs, 0, sizeof(SMU7_Discrete_MCRegisters));
1819
1820        result = ci_convert_mc_reg_table_to_smc(hwmgr, &(smu_data->mc_regs));
1821
1822        if (result != 0)
1823                return result;
1824
1825        address = smu_data->mc_reg_table_start + (uint32_t)offsetof(SMU7_Discrete_MCRegisters, data[0]);
1826
1827        return  ci_copy_bytes_to_smc(hwmgr, address,
1828                                 (uint8_t *)&smu_data->mc_regs.data[0],
1829                                sizeof(SMU7_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
1830                                SMC_RAM_END);
1831}
1832
1833static int ci_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
1834{
1835        int result;
1836        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1837
1838        memset(&smu_data->mc_regs, 0x00, sizeof(SMU7_Discrete_MCRegisters));
1839        result = ci_populate_mc_reg_address(hwmgr, &(smu_data->mc_regs));
1840        PP_ASSERT_WITH_CODE(0 == result,
1841                "Failed to initialize MCRegTable for the MC register addresses!", return result;);
1842
1843        result = ci_convert_mc_reg_table_to_smc(hwmgr, &smu_data->mc_regs);
1844        PP_ASSERT_WITH_CODE(0 == result,
1845                "Failed to initialize MCRegTable for driver state!", return result;);
1846
1847        return ci_copy_bytes_to_smc(hwmgr, smu_data->mc_reg_table_start,
1848                        (uint8_t *)&smu_data->mc_regs, sizeof(SMU7_Discrete_MCRegisters), SMC_RAM_END);
1849}
1850
1851static int ci_populate_smc_initial_state(struct pp_hwmgr *hwmgr)
1852{
1853        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1854        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1855        uint8_t count, level;
1856
1857        count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->count);
1858
1859        for (level = 0; level < count; level++) {
1860                if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[level].clk
1861                         >= data->vbios_boot_state.sclk_bootup_value) {
1862                        smu_data->smc_state_table.GraphicsBootLevel = level;
1863                        break;
1864                }
1865        }
1866
1867        count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_mclk->count);
1868
1869        for (level = 0; level < count; level++) {
1870                if (hwmgr->dyn_state.vddc_dependency_on_mclk->entries[level].clk
1871                        >= data->vbios_boot_state.mclk_bootup_value) {
1872                        smu_data->smc_state_table.MemoryBootLevel = level;
1873                        break;
1874                }
1875        }
1876
1877        return 0;
1878}
1879
1880static int ci_populate_smc_svi2_config(struct pp_hwmgr *hwmgr,
1881                                            SMU7_Discrete_DpmTable *table)
1882{
1883        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1884
1885        if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control)
1886                table->SVI2Enable = 1;
1887        else
1888                table->SVI2Enable = 0;
1889        return 0;
1890}
1891
1892static int ci_start_smc(struct pp_hwmgr *hwmgr)
1893{
1894        /* set smc instruct start point at 0x0 */
1895        ci_program_jump_on_start(hwmgr);
1896
1897        /* enable smc clock */
1898        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
1899
1900        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
1901
1902        PHM_WAIT_INDIRECT_FIELD(hwmgr, SMC_IND, FIRMWARE_FLAGS,
1903                                 INTERRUPTS_ENABLED, 1);
1904
1905        return 0;
1906}
1907
1908static int ci_populate_vr_config(struct pp_hwmgr *hwmgr, SMU7_Discrete_DpmTable *table)
1909{
1910        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1911        uint16_t config;
1912
1913        config = VR_SVI2_PLANE_1;
1914        table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
1915
1916        if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1917                config = VR_SVI2_PLANE_2;
1918                table->VRConfig |= config;
1919        } else {
1920                pr_info("VDDCshould be on SVI2 controller!");
1921        }
1922
1923        if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
1924                config = VR_SVI2_PLANE_2;
1925                table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
1926        } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
1927                config = VR_SMIO_PATTERN_1;
1928                table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
1929        }
1930
1931        if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1932                config = VR_SMIO_PATTERN_2;
1933                table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
1934        }
1935
1936        return 0;
1937}
1938
1939static int ci_init_smc_table(struct pp_hwmgr *hwmgr)
1940{
1941        int result;
1942        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1943        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
1944        SMU7_Discrete_DpmTable  *table = &(smu_data->smc_state_table);
1945        struct pp_atomctrl_gpio_pin_assignment gpio_pin;
1946        u32 i;
1947
1948        ci_initialize_power_tune_defaults(hwmgr);
1949        memset(&(smu_data->smc_state_table), 0x00, sizeof(smu_data->smc_state_table));
1950
1951        if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control)
1952                ci_populate_smc_voltage_tables(hwmgr, table);
1953
1954        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1955                        PHM_PlatformCaps_AutomaticDCTransition))
1956                table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
1957
1958
1959        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1960                        PHM_PlatformCaps_StepVddc))
1961                table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
1962
1963        if (data->is_memory_gddr5)
1964                table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
1965
1966        if (data->ulv_supported) {
1967                result = ci_populate_ulv_state(hwmgr, &(table->Ulv));
1968                PP_ASSERT_WITH_CODE(0 == result,
1969                        "Failed to initialize ULV state!", return result);
1970
1971                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1972                        ixCG_ULV_PARAMETER, 0x40035);
1973        }
1974
1975        result = ci_populate_all_graphic_levels(hwmgr);
1976        PP_ASSERT_WITH_CODE(0 == result,
1977                "Failed to initialize Graphics Level!", return result);
1978
1979        result = ci_populate_all_memory_levels(hwmgr);
1980        PP_ASSERT_WITH_CODE(0 == result,
1981                "Failed to initialize Memory Level!", return result);
1982
1983        result = ci_populate_smc_link_level(hwmgr, table);
1984        PP_ASSERT_WITH_CODE(0 == result,
1985                "Failed to initialize Link Level!", return result);
1986
1987        result = ci_populate_smc_acpi_level(hwmgr, table);
1988        PP_ASSERT_WITH_CODE(0 == result,
1989                "Failed to initialize ACPI Level!", return result);
1990
1991        result = ci_populate_smc_vce_level(hwmgr, table);
1992        PP_ASSERT_WITH_CODE(0 == result,
1993                "Failed to initialize VCE Level!", return result);
1994
1995        result = ci_populate_smc_acp_level(hwmgr, table);
1996        PP_ASSERT_WITH_CODE(0 == result,
1997                "Failed to initialize ACP Level!", return result);
1998
1999        /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
2000        /* need to populate the  ARB settings for the initial state. */
2001        result = ci_program_memory_timing_parameters(hwmgr);
2002        PP_ASSERT_WITH_CODE(0 == result,
2003                "Failed to Write ARB settings for the initial state.", return result);
2004
2005        result = ci_populate_smc_uvd_level(hwmgr, table);
2006        PP_ASSERT_WITH_CODE(0 == result,
2007                "Failed to initialize UVD Level!", return result);
2008
2009        table->UvdBootLevel  = 0;
2010        table->VceBootLevel  = 0;
2011        table->AcpBootLevel  = 0;
2012        table->SamuBootLevel  = 0;
2013
2014        table->GraphicsBootLevel = 0;
2015        table->MemoryBootLevel = 0;
2016
2017        result = ci_populate_smc_boot_level(hwmgr, table);
2018        PP_ASSERT_WITH_CODE(0 == result,
2019                "Failed to initialize Boot Level!", return result);
2020
2021        result = ci_populate_smc_initial_state(hwmgr);
2022        PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize Boot State!", return result);
2023
2024        result = ci_populate_bapm_parameters_in_dpm_table(hwmgr);
2025        PP_ASSERT_WITH_CODE(0 == result, "Failed to populate BAPM Parameters!", return result);
2026
2027        table->UVDInterval = 1;
2028        table->VCEInterval = 1;
2029        table->ACPInterval = 1;
2030        table->SAMUInterval = 1;
2031        table->GraphicsVoltageChangeEnable  = 1;
2032        table->GraphicsThermThrottleEnable  = 1;
2033        table->GraphicsInterval = 1;
2034        table->VoltageInterval  = 1;
2035        table->ThermalInterval  = 1;
2036
2037        table->TemperatureLimitHigh =
2038                (data->thermal_temp_setting.temperature_high *
2039                 SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
2040        table->TemperatureLimitLow =
2041                (data->thermal_temp_setting.temperature_low *
2042                SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
2043
2044        table->MemoryVoltageChangeEnable  = 1;
2045        table->MemoryInterval  = 1;
2046        table->VoltageResponseTime  = 0;
2047        table->VddcVddciDelta = 4000;
2048        table->PhaseResponseTime  = 0;
2049        table->MemoryThermThrottleEnable  = 1;
2050
2051        PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
2052                        "There must be 1 or more PCIE levels defined in PPTable.",
2053                        return -EINVAL);
2054
2055        table->PCIeBootLinkLevel = (uint8_t)data->dpm_table.pcie_speed_table.count;
2056        table->PCIeGenInterval = 1;
2057
2058        result = ci_populate_vr_config(hwmgr, table);
2059        PP_ASSERT_WITH_CODE(0 == result,
2060                        "Failed to populate VRConfig setting!", return result);
2061        data->vr_config = table->VRConfig;
2062
2063        ci_populate_smc_svi2_config(hwmgr, table);
2064
2065        for (i = 0; i < SMU7_MAX_ENTRIES_SMIO; i++)
2066                CONVERT_FROM_HOST_TO_SMC_UL(table->Smio[i]);
2067
2068        table->ThermGpio  = 17;
2069        table->SclkStepSize = 0x4000;
2070        if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
2071                table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
2072                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2073                                PHM_PlatformCaps_RegulatorHot);
2074        } else {
2075                table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
2076                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2077                                PHM_PlatformCaps_RegulatorHot);
2078        }
2079
2080        table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
2081
2082        CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
2083        CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
2084        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcVid);
2085        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcPhase);
2086        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddciVid);
2087        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskMvddVid);
2088        CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
2089        CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
2090        CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
2091        table->VddcVddciDelta = PP_HOST_TO_SMC_US(table->VddcVddciDelta);
2092        CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
2093        CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
2094
2095        table->BootVddc = PP_HOST_TO_SMC_US(table->BootVddc * VOLTAGE_SCALE);
2096        table->BootVddci = PP_HOST_TO_SMC_US(table->BootVddci * VOLTAGE_SCALE);
2097        table->BootMVdd = PP_HOST_TO_SMC_US(table->BootMVdd * VOLTAGE_SCALE);
2098
2099        /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
2100        result = ci_copy_bytes_to_smc(hwmgr, smu_data->dpm_table_start +
2101                                        offsetof(SMU7_Discrete_DpmTable, SystemFlags),
2102                                        (uint8_t *)&(table->SystemFlags),
2103                                        sizeof(SMU7_Discrete_DpmTable)-3 * sizeof(SMU7_PIDController),
2104                                        SMC_RAM_END);
2105
2106        PP_ASSERT_WITH_CODE(0 == result,
2107                "Failed to upload dpm data to SMC memory!", return result;);
2108
2109        result = ci_populate_initial_mc_reg_table(hwmgr);
2110        PP_ASSERT_WITH_CODE((0 == result),
2111                "Failed to populate initialize MC Reg table!", return result);
2112
2113        result = ci_populate_pm_fuses(hwmgr);
2114        PP_ASSERT_WITH_CODE(0 == result,
2115                        "Failed to  populate PM fuses to SMC memory!", return result);
2116
2117        ci_start_smc(hwmgr);
2118
2119        return 0;
2120}
2121
2122static int ci_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
2123{
2124        struct ci_smumgr *ci_data = (struct ci_smumgr *)(hwmgr->smu_backend);
2125        SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
2126        uint32_t duty100;
2127        uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
2128        uint16_t fdo_min, slope1, slope2;
2129        uint32_t reference_clock;
2130        int res;
2131        uint64_t tmp64;
2132
2133        if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
2134                return 0;
2135
2136        if (hwmgr->thermal_controller.fanInfo.bNoFan) {
2137                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2138                        PHM_PlatformCaps_MicrocodeFanControl);
2139                return 0;
2140        }
2141
2142        if (0 == ci_data->fan_table_start) {
2143                phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
2144                return 0;
2145        }
2146
2147        duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
2148
2149        if (0 == duty100) {
2150                phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
2151                return 0;
2152        }
2153
2154        tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
2155        do_div(tmp64, 10000);
2156        fdo_min = (uint16_t)tmp64;
2157
2158        t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
2159        t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
2160
2161        pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
2162        pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
2163
2164        slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
2165        slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
2166
2167        fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
2168        fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
2169        fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
2170
2171        fan_table.Slope1 = cpu_to_be16(slope1);
2172        fan_table.Slope2 = cpu_to_be16(slope2);
2173
2174        fan_table.FdoMin = cpu_to_be16(fdo_min);
2175
2176        fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
2177
2178        fan_table.HystUp = cpu_to_be16(1);
2179
2180        fan_table.HystSlope = cpu_to_be16(1);
2181
2182        fan_table.TempRespLim = cpu_to_be16(5);
2183
2184        reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
2185
2186        fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
2187
2188        fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
2189
2190        fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
2191
2192        res = ci_copy_bytes_to_smc(hwmgr, ci_data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), SMC_RAM_END);
2193
2194        return 0;
2195}
2196
2197static int ci_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
2198{
2199        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2200
2201        if (data->need_update_smu7_dpm_table &
2202                        (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
2203                return ci_program_memory_timing_parameters(hwmgr);
2204
2205        return 0;
2206}
2207
2208static int ci_update_sclk_threshold(struct pp_hwmgr *hwmgr)
2209{
2210        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2211        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
2212
2213        int result = 0;
2214        uint32_t low_sclk_interrupt_threshold = 0;
2215
2216        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2217                        PHM_PlatformCaps_SclkThrottleLowNotification)
2218                && (data->low_sclk_interrupt_threshold != 0)) {
2219                low_sclk_interrupt_threshold =
2220                                data->low_sclk_interrupt_threshold;
2221
2222                CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
2223
2224                result = ci_copy_bytes_to_smc(
2225                                hwmgr,
2226                                smu_data->dpm_table_start +
2227                                offsetof(SMU7_Discrete_DpmTable,
2228                                        LowSclkInterruptT),
2229                                (uint8_t *)&low_sclk_interrupt_threshold,
2230                                sizeof(uint32_t),
2231                                SMC_RAM_END);
2232        }
2233
2234        result = ci_update_and_upload_mc_reg_table(hwmgr);
2235
2236        PP_ASSERT_WITH_CODE((0 == result), "Failed to upload MC reg table!", return result);
2237
2238        result = ci_program_mem_timing_parameters(hwmgr);
2239        PP_ASSERT_WITH_CODE((result == 0),
2240                        "Failed to program memory timing parameters!",
2241                        );
2242
2243        return result;
2244}
2245
2246static uint32_t ci_get_offsetof(uint32_t type, uint32_t member)
2247{
2248        switch (type) {
2249        case SMU_SoftRegisters:
2250                switch (member) {
2251                case HandshakeDisables:
2252                        return offsetof(SMU7_SoftRegisters, HandshakeDisables);
2253                case VoltageChangeTimeout:
2254                        return offsetof(SMU7_SoftRegisters, VoltageChangeTimeout);
2255                case AverageGraphicsActivity:
2256                        return offsetof(SMU7_SoftRegisters, AverageGraphicsA);
2257                case PreVBlankGap:
2258                        return offsetof(SMU7_SoftRegisters, PreVBlankGap);
2259                case VBlankTimeout:
2260                        return offsetof(SMU7_SoftRegisters, VBlankTimeout);
2261                case DRAM_LOG_ADDR_H:
2262                        return offsetof(SMU7_SoftRegisters, DRAM_LOG_ADDR_H);
2263                case DRAM_LOG_ADDR_L:
2264                        return offsetof(SMU7_SoftRegisters, DRAM_LOG_ADDR_L);
2265                case DRAM_LOG_PHY_ADDR_H:
2266                        return offsetof(SMU7_SoftRegisters, DRAM_LOG_PHY_ADDR_H);
2267                case DRAM_LOG_PHY_ADDR_L:
2268                        return offsetof(SMU7_SoftRegisters, DRAM_LOG_PHY_ADDR_L);
2269                case DRAM_LOG_BUFF_SIZE:
2270                        return offsetof(SMU7_SoftRegisters, DRAM_LOG_BUFF_SIZE);
2271                }
2272                break;
2273        case SMU_Discrete_DpmTable:
2274                switch (member) {
2275                case LowSclkInterruptThreshold:
2276                        return offsetof(SMU7_Discrete_DpmTable, LowSclkInterruptT);
2277                }
2278                break;
2279        }
2280        pr_debug("can't get the offset of type %x member %x\n", type, member);
2281        return 0;
2282}
2283
2284static uint32_t ci_get_mac_definition(uint32_t value)
2285{
2286        switch (value) {
2287        case SMU_MAX_LEVELS_GRAPHICS:
2288                return SMU7_MAX_LEVELS_GRAPHICS;
2289        case SMU_MAX_LEVELS_MEMORY:
2290                return SMU7_MAX_LEVELS_MEMORY;
2291        case SMU_MAX_LEVELS_LINK:
2292                return SMU7_MAX_LEVELS_LINK;
2293        case SMU_MAX_ENTRIES_SMIO:
2294                return SMU7_MAX_ENTRIES_SMIO;
2295        case SMU_MAX_LEVELS_VDDC:
2296                return SMU7_MAX_LEVELS_VDDC;
2297        case SMU_MAX_LEVELS_VDDCI:
2298                return SMU7_MAX_LEVELS_VDDCI;
2299        case SMU_MAX_LEVELS_MVDD:
2300                return SMU7_MAX_LEVELS_MVDD;
2301        }
2302
2303        pr_debug("can't get the mac of %x\n", value);
2304        return 0;
2305}
2306
2307static int ci_load_smc_ucode(struct pp_hwmgr *hwmgr)
2308{
2309        uint32_t byte_count, start_addr;
2310        uint8_t *src;
2311        uint32_t data;
2312
2313        struct cgs_firmware_info info = {0};
2314
2315        cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, &info);
2316
2317        hwmgr->is_kicker = info.is_kicker;
2318        hwmgr->smu_version = info.version;
2319        byte_count = info.image_size;
2320        src = (uint8_t *)info.kptr;
2321        start_addr = info.ucode_start_address;
2322
2323        if  (byte_count > SMC_RAM_END) {
2324                pr_err("SMC address is beyond the SMC RAM area.\n");
2325                return -EINVAL;
2326        }
2327
2328        cgs_write_register(hwmgr->device, mmSMC_IND_INDEX_0, start_addr);
2329        PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
2330
2331        for (; byte_count >= 4; byte_count -= 4) {
2332                data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
2333                cgs_write_register(hwmgr->device, mmSMC_IND_DATA_0, data);
2334                src += 4;
2335        }
2336        PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
2337
2338        if (0 != byte_count) {
2339                pr_err("SMC size must be divisible by 4\n");
2340                return -EINVAL;
2341        }
2342
2343        return 0;
2344}
2345
2346static int ci_upload_firmware(struct pp_hwmgr *hwmgr)
2347{
2348        if (ci_is_smc_ram_running(hwmgr)) {
2349                pr_info("smc is running, no need to load smc firmware\n");
2350                return 0;
2351        }
2352        PHM_WAIT_INDIRECT_FIELD(hwmgr, SMC_IND, RCU_UC_EVENTS,
2353                        boot_seq_done, 1);
2354        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_MISC_CNTL,
2355                        pre_fetcher_en, 1);
2356
2357        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
2358        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
2359        return ci_load_smc_ucode(hwmgr);
2360}
2361
2362static int ci_process_firmware_header(struct pp_hwmgr *hwmgr)
2363{
2364        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2365        struct ci_smumgr *ci_data = (struct ci_smumgr *)(hwmgr->smu_backend);
2366
2367        uint32_t tmp = 0;
2368        int result;
2369        bool error = false;
2370
2371        if (ci_upload_firmware(hwmgr))
2372                return -EINVAL;
2373
2374        result = ci_read_smc_sram_dword(hwmgr,
2375                                SMU7_FIRMWARE_HEADER_LOCATION +
2376                                offsetof(SMU7_Firmware_Header, DpmTable),
2377                                &tmp, SMC_RAM_END);
2378
2379        if (0 == result)
2380                ci_data->dpm_table_start = tmp;
2381
2382        error |= (0 != result);
2383
2384        result = ci_read_smc_sram_dword(hwmgr,
2385                                SMU7_FIRMWARE_HEADER_LOCATION +
2386                                offsetof(SMU7_Firmware_Header, SoftRegisters),
2387                                &tmp, SMC_RAM_END);
2388
2389        if (0 == result) {
2390                data->soft_regs_start = tmp;
2391                ci_data->soft_regs_start = tmp;
2392        }
2393
2394        error |= (0 != result);
2395
2396        result = ci_read_smc_sram_dword(hwmgr,
2397                                SMU7_FIRMWARE_HEADER_LOCATION +
2398                                offsetof(SMU7_Firmware_Header, mcRegisterTable),
2399                                &tmp, SMC_RAM_END);
2400
2401        if (0 == result)
2402                ci_data->mc_reg_table_start = tmp;
2403
2404        result = ci_read_smc_sram_dword(hwmgr,
2405                                SMU7_FIRMWARE_HEADER_LOCATION +
2406                                offsetof(SMU7_Firmware_Header, FanTable),
2407                                &tmp, SMC_RAM_END);
2408
2409        if (0 == result)
2410                ci_data->fan_table_start = tmp;
2411
2412        error |= (0 != result);
2413
2414        result = ci_read_smc_sram_dword(hwmgr,
2415                                SMU7_FIRMWARE_HEADER_LOCATION +
2416                                offsetof(SMU7_Firmware_Header, mcArbDramTimingTable),
2417                                &tmp, SMC_RAM_END);
2418
2419        if (0 == result)
2420                ci_data->arb_table_start = tmp;
2421
2422        error |= (0 != result);
2423
2424        result = ci_read_smc_sram_dword(hwmgr,
2425                                SMU7_FIRMWARE_HEADER_LOCATION +
2426                                offsetof(SMU7_Firmware_Header, Version),
2427                                &tmp, SMC_RAM_END);
2428
2429        if (0 == result)
2430                hwmgr->microcode_version_info.SMC = tmp;
2431
2432        error |= (0 != result);
2433
2434        return error ? 1 : 0;
2435}
2436
2437static uint8_t ci_get_memory_modile_index(struct pp_hwmgr *hwmgr)
2438{
2439        return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
2440}
2441
2442static bool ci_check_s0_mc_reg_index(uint16_t in_reg, uint16_t *out_reg)
2443{
2444        bool result = true;
2445
2446        switch (in_reg) {
2447        case  mmMC_SEQ_RAS_TIMING:
2448                *out_reg = mmMC_SEQ_RAS_TIMING_LP;
2449                break;
2450
2451        case  mmMC_SEQ_DLL_STBY:
2452                *out_reg = mmMC_SEQ_DLL_STBY_LP;
2453                break;
2454
2455        case  mmMC_SEQ_G5PDX_CMD0:
2456                *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
2457                break;
2458
2459        case  mmMC_SEQ_G5PDX_CMD1:
2460                *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
2461                break;
2462
2463        case  mmMC_SEQ_G5PDX_CTRL:
2464                *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
2465                break;
2466
2467        case mmMC_SEQ_CAS_TIMING:
2468                *out_reg = mmMC_SEQ_CAS_TIMING_LP;
2469                break;
2470
2471        case mmMC_SEQ_MISC_TIMING:
2472                *out_reg = mmMC_SEQ_MISC_TIMING_LP;
2473                break;
2474
2475        case mmMC_SEQ_MISC_TIMING2:
2476                *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
2477                break;
2478
2479        case mmMC_SEQ_PMG_DVS_CMD:
2480                *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
2481                break;
2482
2483        case mmMC_SEQ_PMG_DVS_CTL:
2484                *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
2485                break;
2486
2487        case mmMC_SEQ_RD_CTL_D0:
2488                *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
2489                break;
2490
2491        case mmMC_SEQ_RD_CTL_D1:
2492                *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
2493                break;
2494
2495        case mmMC_SEQ_WR_CTL_D0:
2496                *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
2497                break;
2498
2499        case mmMC_SEQ_WR_CTL_D1:
2500                *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
2501                break;
2502
2503        case mmMC_PMG_CMD_EMRS:
2504                *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
2505                break;
2506
2507        case mmMC_PMG_CMD_MRS:
2508                *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
2509                break;
2510
2511        case mmMC_PMG_CMD_MRS1:
2512                *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
2513                break;
2514
2515        case mmMC_SEQ_PMG_TIMING:
2516                *out_reg = mmMC_SEQ_PMG_TIMING_LP;
2517                break;
2518
2519        case mmMC_PMG_CMD_MRS2:
2520                *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
2521                break;
2522
2523        case mmMC_SEQ_WR_CTL_2:
2524                *out_reg = mmMC_SEQ_WR_CTL_2_LP;
2525                break;
2526
2527        default:
2528                result = false;
2529                break;
2530        }
2531
2532        return result;
2533}
2534
2535static int ci_set_s0_mc_reg_index(struct ci_mc_reg_table *table)
2536{
2537        uint32_t i;
2538        uint16_t address;
2539
2540        for (i = 0; i < table->last; i++) {
2541                table->mc_reg_address[i].s0 =
2542                        ci_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
2543                        ? address : table->mc_reg_address[i].s1;
2544        }
2545        return 0;
2546}
2547
2548static int ci_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table,
2549                                        struct ci_mc_reg_table *ni_table)
2550{
2551        uint8_t i, j;
2552
2553        PP_ASSERT_WITH_CODE((table->last <= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2554                "Invalid VramInfo table.", return -EINVAL);
2555        PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
2556                "Invalid VramInfo table.", return -EINVAL);
2557
2558        for (i = 0; i < table->last; i++)
2559                ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
2560
2561        ni_table->last = table->last;
2562
2563        for (i = 0; i < table->num_entries; i++) {
2564                ni_table->mc_reg_table_entry[i].mclk_max =
2565                        table->mc_reg_table_entry[i].mclk_max;
2566                for (j = 0; j < table->last; j++) {
2567                        ni_table->mc_reg_table_entry[i].mc_data[j] =
2568                                table->mc_reg_table_entry[i].mc_data[j];
2569                }
2570        }
2571
2572        ni_table->num_entries = table->num_entries;
2573
2574        return 0;
2575}
2576
2577static int ci_set_mc_special_registers(struct pp_hwmgr *hwmgr,
2578                                        struct ci_mc_reg_table *table)
2579{
2580        uint8_t i, j, k;
2581        uint32_t temp_reg;
2582        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2583
2584        for (i = 0, j = table->last; i < table->last; i++) {
2585                PP_ASSERT_WITH_CODE((j < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2586                        "Invalid VramInfo table.", return -EINVAL);
2587
2588                switch (table->mc_reg_address[i].s1) {
2589
2590                case mmMC_SEQ_MISC1:
2591                        temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
2592                        table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
2593                        table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
2594                        for (k = 0; k < table->num_entries; k++) {
2595                                table->mc_reg_table_entry[k].mc_data[j] =
2596                                        ((temp_reg & 0xffff0000)) |
2597                                        ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
2598                        }
2599                        j++;
2600
2601                        PP_ASSERT_WITH_CODE((j < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2602                                "Invalid VramInfo table.", return -EINVAL);
2603                        temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
2604                        table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
2605                        table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
2606                        for (k = 0; k < table->num_entries; k++) {
2607                                table->mc_reg_table_entry[k].mc_data[j] =
2608                                        (temp_reg & 0xffff0000) |
2609                                        (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
2610
2611                                if (!data->is_memory_gddr5)
2612                                        table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
2613                        }
2614                        j++;
2615
2616                        if (!data->is_memory_gddr5) {
2617                                PP_ASSERT_WITH_CODE((j < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2618                                        "Invalid VramInfo table.", return -EINVAL);
2619                                table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
2620                                table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
2621                                for (k = 0; k < table->num_entries; k++) {
2622                                        table->mc_reg_table_entry[k].mc_data[j] =
2623                                                (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
2624                                }
2625                                j++;
2626                        }
2627
2628                        break;
2629
2630                case mmMC_SEQ_RESERVE_M:
2631                        temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
2632                        table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
2633                        table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
2634                        for (k = 0; k < table->num_entries; k++) {
2635                                table->mc_reg_table_entry[k].mc_data[j] =
2636                                        (temp_reg & 0xffff0000) |
2637                                        (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
2638                        }
2639                        j++;
2640                        break;
2641
2642                default:
2643                        break;
2644                }
2645
2646        }
2647
2648        table->last = j;
2649
2650        return 0;
2651}
2652
2653static int ci_set_valid_flag(struct ci_mc_reg_table *table)
2654{
2655        uint8_t i, j;
2656
2657        for (i = 0; i < table->last; i++) {
2658                for (j = 1; j < table->num_entries; j++) {
2659                        if (table->mc_reg_table_entry[j-1].mc_data[i] !=
2660                                table->mc_reg_table_entry[j].mc_data[i]) {
2661                                table->validflag |= (1 << i);
2662                                break;
2663                        }
2664                }
2665        }
2666
2667        return 0;
2668}
2669
2670static int ci_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
2671{
2672        int result;
2673        struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
2674        pp_atomctrl_mc_reg_table *table;
2675        struct ci_mc_reg_table *ni_table = &smu_data->mc_reg_table;
2676        uint8_t module_index = ci_get_memory_modile_index(hwmgr);
2677
2678        table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
2679
2680        if (NULL == table)
2681                return -ENOMEM;
2682
2683        /* Program additional LP registers that are no longer programmed by VBIOS */
2684        cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
2685        cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
2686        cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
2687        cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
2688        cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
2689        cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
2690        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
2691        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
2692        cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
2693        cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
2694        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
2695        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
2696        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
2697        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
2698        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
2699        cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
2700        cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
2701        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
2702        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
2703        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
2704
2705        memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
2706
2707        result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
2708
2709        if (0 == result)
2710                result = ci_copy_vbios_smc_reg_table(table, ni_table);
2711
2712        if (0 == result) {
2713                ci_set_s0_mc_reg_index(ni_table);
2714                result = ci_set_mc_special_registers(hwmgr, ni_table);
2715        }
2716
2717        if (0 == result)
2718                ci_set_valid_flag(ni_table);
2719
2720        kfree(table);
2721
2722        return result;
2723}
2724
2725static bool ci_is_dpm_running(struct pp_hwmgr *hwmgr)
2726{
2727        return ci_is_smc_ram_running(hwmgr);
2728}
2729
2730static int ci_smu_init(struct pp_hwmgr *hwmgr)
2731{
2732        struct ci_smumgr *ci_priv = NULL;
2733
2734        ci_priv = kzalloc(sizeof(struct ci_smumgr), GFP_KERNEL);
2735
2736        if (ci_priv == NULL)
2737                return -ENOMEM;
2738
2739        hwmgr->smu_backend = ci_priv;
2740
2741        return 0;
2742}
2743
2744static int ci_smu_fini(struct pp_hwmgr *hwmgr)
2745{
2746        kfree(hwmgr->smu_backend);
2747        hwmgr->smu_backend = NULL;
2748        return 0;
2749}
2750
2751static int ci_start_smu(struct pp_hwmgr *hwmgr)
2752{
2753        return 0;
2754}
2755
2756static int ci_update_dpm_settings(struct pp_hwmgr *hwmgr,
2757                                void *profile_setting)
2758{
2759        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2760        struct ci_smumgr *smu_data = (struct ci_smumgr *)
2761                        (hwmgr->smu_backend);
2762        struct profile_mode_setting *setting;
2763        struct SMU7_Discrete_GraphicsLevel *levels =
2764                        smu_data->smc_state_table.GraphicsLevel;
2765        uint32_t array = smu_data->dpm_table_start +
2766                        offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
2767
2768        uint32_t mclk_array = smu_data->dpm_table_start +
2769                        offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
2770        struct SMU7_Discrete_MemoryLevel *mclk_levels =
2771                        smu_data->smc_state_table.MemoryLevel;
2772        uint32_t i;
2773        uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp;
2774
2775        if (profile_setting == NULL)
2776                return -EINVAL;
2777
2778        setting = (struct profile_mode_setting *)profile_setting;
2779
2780        if (setting->bupdate_sclk) {
2781                if (!data->sclk_dpm_key_disabled)
2782                        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel);
2783                for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) {
2784                        if (levels[i].ActivityLevel !=
2785                                cpu_to_be16(setting->sclk_activity)) {
2786                                levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity);
2787
2788                                clk_activity_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i)
2789                                                + offsetof(SMU7_Discrete_GraphicsLevel, ActivityLevel);
2790                                offset = clk_activity_offset & ~0x3;
2791                                tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
2792                                tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t));
2793                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
2794
2795                        }
2796                        if (levels[i].UpH != setting->sclk_up_hyst ||
2797                                levels[i].DownH != setting->sclk_down_hyst) {
2798                                levels[i].UpH = setting->sclk_up_hyst;
2799                                levels[i].DownH = setting->sclk_down_hyst;
2800                                up_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i)
2801                                                + offsetof(SMU7_Discrete_GraphicsLevel, UpH);
2802                                down_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i)
2803                                                + offsetof(SMU7_Discrete_GraphicsLevel, DownH);
2804                                offset = up_hyst_offset & ~0x3;
2805                                tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
2806                                tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpH, sizeof(uint8_t));
2807                                tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownH, sizeof(uint8_t));
2808                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
2809                        }
2810                }
2811                if (!data->sclk_dpm_key_disabled)
2812                        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel);
2813        }
2814
2815        if (setting->bupdate_mclk) {
2816                if (!data->mclk_dpm_key_disabled)
2817                        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel);
2818                for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) {
2819                        if (mclk_levels[i].ActivityLevel !=
2820                                cpu_to_be16(setting->mclk_activity)) {
2821                                mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity);
2822
2823                                clk_activity_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i)
2824                                                + offsetof(SMU7_Discrete_MemoryLevel, ActivityLevel);
2825                                offset = clk_activity_offset & ~0x3;
2826                                tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
2827                                tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t));
2828                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
2829
2830                        }
2831                        if (mclk_levels[i].UpH != setting->mclk_up_hyst ||
2832                                mclk_levels[i].DownH != setting->mclk_down_hyst) {
2833                                mclk_levels[i].UpH = setting->mclk_up_hyst;
2834                                mclk_levels[i].DownH = setting->mclk_down_hyst;
2835                                up_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i)
2836                                                + offsetof(SMU7_Discrete_MemoryLevel, UpH);
2837                                down_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i)
2838                                                + offsetof(SMU7_Discrete_MemoryLevel, DownH);
2839                                offset = up_hyst_offset & ~0x3;
2840                                tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
2841                                tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpH, sizeof(uint8_t));
2842                                tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownH, sizeof(uint8_t));
2843                                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
2844                        }
2845                }
2846                if (!data->mclk_dpm_key_disabled)
2847                        smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel);
2848        }
2849        return 0;
2850}
2851
2852static int ci_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
2853{
2854        struct amdgpu_device *adev = hwmgr->adev;
2855        struct smu7_hwmgr *data = hwmgr->backend;
2856        struct ci_smumgr *smu_data = hwmgr->smu_backend;
2857        struct phm_uvd_clock_voltage_dependency_table *uvd_table =
2858                        hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
2859        uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
2860                                        AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
2861                                        AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
2862                                        AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
2863        uint32_t max_vddc = adev->pm.ac_power ? hwmgr->dyn_state.max_clock_voltage_on_ac.vddc :
2864                                                hwmgr->dyn_state.max_clock_voltage_on_dc.vddc;
2865        int32_t i;
2866
2867        if (PP_CAP(PHM_PlatformCaps_UVDDPM) || uvd_table->count <= 0)
2868                smu_data->smc_state_table.UvdBootLevel = 0;
2869        else
2870                smu_data->smc_state_table.UvdBootLevel = uvd_table->count - 1;
2871
2872        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, DPM_TABLE_475,
2873                                UvdBootLevel, smu_data->smc_state_table.UvdBootLevel);
2874
2875        data->dpm_level_enable_mask.uvd_dpm_enable_mask = 0;
2876
2877        for (i = uvd_table->count - 1; i >= 0; i--) {
2878                if (uvd_table->entries[i].v <= max_vddc)
2879                        data->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i;
2880                if (hwmgr->dpm_level & profile_mode_mask || !PP_CAP(PHM_PlatformCaps_UVDDPM))
2881                        break;
2882        }
2883        ci_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_UVDDPM_SetEnabledMask,
2884                                data->dpm_level_enable_mask.uvd_dpm_enable_mask);
2885
2886        return 0;
2887}
2888
2889static int ci_update_vce_smc_table(struct pp_hwmgr *hwmgr)
2890{
2891        struct amdgpu_device *adev = hwmgr->adev;
2892        struct smu7_hwmgr *data = hwmgr->backend;
2893        struct phm_vce_clock_voltage_dependency_table *vce_table =
2894                        hwmgr->dyn_state.vce_clock_voltage_dependency_table;
2895        uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
2896                                        AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
2897                                        AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
2898                                        AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
2899        uint32_t max_vddc = adev->pm.ac_power ? hwmgr->dyn_state.max_clock_voltage_on_ac.vddc :
2900                                                hwmgr->dyn_state.max_clock_voltage_on_dc.vddc;
2901        int32_t i;
2902
2903        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, DPM_TABLE_475,
2904                                VceBootLevel, 0); /* temp hard code to level 0, vce can set min evclk*/
2905
2906        data->dpm_level_enable_mask.vce_dpm_enable_mask = 0;
2907
2908        for (i = vce_table->count - 1; i >= 0; i--) {
2909                if (vce_table->entries[i].v <= max_vddc)
2910                        data->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i;
2911                if (hwmgr->dpm_level & profile_mode_mask || !PP_CAP(PHM_PlatformCaps_VCEDPM))
2912                        break;
2913        }
2914        ci_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_VCEDPM_SetEnabledMask,
2915                                data->dpm_level_enable_mask.vce_dpm_enable_mask);
2916
2917        return 0;
2918}
2919
2920static int ci_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
2921{
2922        switch (type) {
2923        case SMU_UVD_TABLE:
2924                ci_update_uvd_smc_table(hwmgr);
2925                break;
2926        case SMU_VCE_TABLE:
2927                ci_update_vce_smc_table(hwmgr);
2928                break;
2929        default:
2930                break;
2931        }
2932        return 0;
2933}
2934
2935const struct pp_smumgr_func ci_smu_funcs = {
2936        .smu_init = ci_smu_init,
2937        .smu_fini = ci_smu_fini,
2938        .start_smu = ci_start_smu,
2939        .check_fw_load_finish = NULL,
2940        .request_smu_load_fw = NULL,
2941        .request_smu_load_specific_fw = NULL,
2942        .send_msg_to_smc = ci_send_msg_to_smc,
2943        .send_msg_to_smc_with_parameter = ci_send_msg_to_smc_with_parameter,
2944        .download_pptable_settings = NULL,
2945        .upload_pptable_settings = NULL,
2946        .get_offsetof = ci_get_offsetof,
2947        .process_firmware_header = ci_process_firmware_header,
2948        .init_smc_table = ci_init_smc_table,
2949        .update_sclk_threshold = ci_update_sclk_threshold,
2950        .thermal_setup_fan_table = ci_thermal_setup_fan_table,
2951        .populate_all_graphic_levels = ci_populate_all_graphic_levels,
2952        .populate_all_memory_levels = ci_populate_all_memory_levels,
2953        .get_mac_definition = ci_get_mac_definition,
2954        .initialize_mc_reg_table = ci_initialize_mc_reg_table,
2955        .is_dpm_running = ci_is_dpm_running,
2956        .update_dpm_settings = ci_update_dpm_settings,
2957        .update_smc_table = ci_update_smc_table,
2958};
2959