linux/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
<<
>>
Prefs
   1/*
   2 * Copyright 2015 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 */
  23#include <linux/module.h>
  24#include <linux/slab.h>
  25#include <linux/fb.h>
  26#include "linux/delay.h"
  27
  28#include "hwmgr.h"
  29#include "fiji_smumgr.h"
  30#include "atombios.h"
  31#include "hardwaremanager.h"
  32#include "ppatomctrl.h"
  33#include "atombios.h"
  34#include "cgs_common.h"
  35#include "fiji_dyn_defaults.h"
  36#include "fiji_powertune.h"
  37#include "smu73.h"
  38#include "smu/smu_7_1_3_d.h"
  39#include "smu/smu_7_1_3_sh_mask.h"
  40#include "gmc/gmc_8_1_d.h"
  41#include "gmc/gmc_8_1_sh_mask.h"
  42#include "bif/bif_5_0_d.h"
  43#include "bif/bif_5_0_sh_mask.h"
  44#include "dce/dce_10_0_d.h"
  45#include "dce/dce_10_0_sh_mask.h"
  46#include "pppcielanes.h"
  47#include "fiji_hwmgr.h"
  48#include "tonga_processpptables.h"
  49#include "tonga_pptable.h"
  50#include "pp_debug.h"
  51#include "pp_acpi.h"
  52#include "amd_pcie_helpers.h"
  53#include "cgs_linux.h"
  54#include "ppinterrupt.h"
  55
  56#include "fiji_clockpowergating.h"
  57#include "fiji_thermal.h"
  58
  59#define VOLTAGE_SCALE   4
  60#define SMC_RAM_END             0x40000
  61#define VDDC_VDDCI_DELTA        300
  62
  63#define MC_SEQ_MISC0_GDDR5_SHIFT 28
  64#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
  65#define MC_SEQ_MISC0_GDDR5_VALUE 5
  66
  67#define MC_CG_ARB_FREQ_F0           0x0a /* boot-up default */
  68#define MC_CG_ARB_FREQ_F1           0x0b
  69#define MC_CG_ARB_FREQ_F2           0x0c
  70#define MC_CG_ARB_FREQ_F3           0x0d
  71
  72/* From smc_reg.h */
  73#define SMC_CG_IND_START            0xc0030000
  74#define SMC_CG_IND_END              0xc0040000  /* First byte after SMC_CG_IND */
  75
  76#define VOLTAGE_SCALE               4
  77#define VOLTAGE_VID_OFFSET_SCALE1   625
  78#define VOLTAGE_VID_OFFSET_SCALE2   100
  79
  80#define VDDC_VDDCI_DELTA            300
  81
  82#define ixSWRST_COMMAND_1           0x1400103
  83#define MC_SEQ_CNTL__CAC_EN_MASK    0x40000000
  84
  85/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
  86enum DPM_EVENT_SRC {
  87    DPM_EVENT_SRC_ANALOG = 0,               /* Internal analog trip point */
  88    DPM_EVENT_SRC_EXTERNAL = 1,             /* External (GPIO 17) signal */
  89    DPM_EVENT_SRC_DIGITAL = 2,              /* Internal digital trip point (DIG_THERM_DPM) */
  90    DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,   /* Internal analog or external */
  91    DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4   /* Internal digital or external */
  92};
  93
  94
  95/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
  96 * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
  97 */
  98static const uint16_t fiji_clock_stretcher_lookup_table[2][4] =
  99{ {600, 1050, 3, 0}, {600, 1050, 6, 1} };
 100
 101/* [FF, SS] type, [] 4 voltage ranges, and
 102 * [Floor Freq, Boundary Freq, VID min , VID max]
 103 */
 104static const uint32_t fiji_clock_stretcher_ddt_table[2][4][4] =
 105{ { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
 106  { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
 107
 108/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
 109 * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
 110 */
 111static const uint8_t fiji_clock_stretch_amount_conversion[2][6] =
 112{ {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
 113
 114static const unsigned long PhwFiji_Magic = (unsigned long)(PHM_VIslands_Magic);
 115
 116struct fiji_power_state *cast_phw_fiji_power_state(
 117                                  struct pp_hw_power_state *hw_ps)
 118{
 119        PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
 120                                "Invalid Powerstate Type!",
 121                                 return NULL;);
 122
 123        return (struct fiji_power_state *)hw_ps;
 124}
 125
 126const struct fiji_power_state *cast_const_phw_fiji_power_state(
 127                                 const struct pp_hw_power_state *hw_ps)
 128{
 129        PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
 130                                "Invalid Powerstate Type!",
 131                                 return NULL;);
 132
 133        return (const struct fiji_power_state *)hw_ps;
 134}
 135
 136static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
 137{
 138        return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
 139                        CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
 140                        ? true : false;
 141}
 142
 143static void fiji_init_dpm_defaults(struct pp_hwmgr *hwmgr)
 144{
 145        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 146        struct fiji_ulv_parm *ulv = &data->ulv;
 147
 148        ulv->cg_ulv_parameter = PPFIJI_CGULVPARAMETER_DFLT;
 149        data->voting_rights_clients0 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0;
 150        data->voting_rights_clients1 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1;
 151        data->voting_rights_clients2 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2;
 152        data->voting_rights_clients3 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3;
 153        data->voting_rights_clients4 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4;
 154        data->voting_rights_clients5 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5;
 155        data->voting_rights_clients6 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6;
 156        data->voting_rights_clients7 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7;
 157
 158        data->static_screen_threshold_unit =
 159                        PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT;
 160        data->static_screen_threshold =
 161                        PPFIJI_STATICSCREENTHRESHOLD_DFLT;
 162
 163        /* Unset ABM cap as it moved to DAL.
 164         * Add PHM_PlatformCaps_NonABMSupportInPPLib
 165         * for re-direct ABM related request to DAL
 166         */
 167        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 168                        PHM_PlatformCaps_ABM);
 169        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 170                        PHM_PlatformCaps_NonABMSupportInPPLib);
 171
 172        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 173                        PHM_PlatformCaps_DynamicACTiming);
 174
 175        fiji_initialize_power_tune_defaults(hwmgr);
 176
 177        data->mclk_stutter_mode_threshold = 60000;
 178        data->pcie_gen_performance.max = PP_PCIEGen1;
 179        data->pcie_gen_performance.min = PP_PCIEGen3;
 180        data->pcie_gen_power_saving.max = PP_PCIEGen1;
 181        data->pcie_gen_power_saving.min = PP_PCIEGen3;
 182        data->pcie_lane_performance.max = 0;
 183        data->pcie_lane_performance.min = 16;
 184        data->pcie_lane_power_saving.max = 0;
 185        data->pcie_lane_power_saving.min = 16;
 186
 187        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 188                        PHM_PlatformCaps_DynamicUVDState);
 189}
 190
 191static int fiji_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
 192        phm_ppt_v1_voltage_lookup_table *lookup_table,
 193        uint16_t virtual_voltage_id, int32_t *sclk)
 194{
 195        uint8_t entryId;
 196        uint8_t voltageId;
 197        struct phm_ppt_v1_information *table_info =
 198                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 199
 200        PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
 201
 202        /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
 203        for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
 204                voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
 205                if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
 206                        break;
 207        }
 208
 209        PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
 210                        "Can't find requested voltage id in vdd_dep_on_sclk table!",
 211                        return -EINVAL;
 212                        );
 213
 214        *sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
 215
 216        return 0;
 217}
 218
 219/**
 220* Get Leakage VDDC based on leakage ID.
 221*
 222* @param    hwmgr  the address of the powerplay hardware manager.
 223* @return   always 0
 224*/
 225static int fiji_get_evv_voltages(struct pp_hwmgr *hwmgr)
 226{
 227        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 228        uint16_t    vv_id;
 229        uint16_t    vddc = 0;
 230        uint16_t    evv_default = 1150;
 231        uint16_t    i, j;
 232        uint32_t  sclk = 0;
 233        struct phm_ppt_v1_information *table_info =
 234                        (struct phm_ppt_v1_information *)hwmgr->pptable;
 235        struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
 236                        table_info->vdd_dep_on_sclk;
 237        int result;
 238
 239        for (i = 0; i < FIJI_MAX_LEAKAGE_COUNT; i++) {
 240                vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
 241                if (!fiji_get_sclk_for_voltage_evv(hwmgr,
 242                                table_info->vddc_lookup_table, vv_id, &sclk)) {
 243                        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 244                                        PHM_PlatformCaps_ClockStretcher)) {
 245                                for (j = 1; j < sclk_table->count; j++) {
 246                                        if (sclk_table->entries[j].clk == sclk &&
 247                                                        sclk_table->entries[j].cks_enable == 0) {
 248                                                sclk += 5000;
 249                                                break;
 250                                        }
 251                                }
 252                        }
 253
 254                        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 255                                        PHM_PlatformCaps_EnableDriverEVV))
 256                                result = atomctrl_calculate_voltage_evv_on_sclk(hwmgr,
 257                                                VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc, i, true);
 258                        else
 259                                result = -EINVAL;
 260
 261                        if (result)
 262                                result = atomctrl_get_voltage_evv_on_sclk(hwmgr,
 263                                                VOLTAGE_TYPE_VDDC, sclk,vv_id, &vddc);
 264
 265                        /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
 266                        PP_ASSERT_WITH_CODE((vddc < 2000),
 267                                        "Invalid VDDC value, greater than 2v!", result = -EINVAL;);
 268
 269                        if (result)
 270                                /* 1.15V is the default safe value for Fiji */
 271                                vddc = evv_default;
 272
 273                        /* the voltage should not be zero nor equal to leakage ID */
 274                        if (vddc != 0 && vddc != vv_id) {
 275                                data->vddc_leakage.actual_voltage
 276                                [data->vddc_leakage.count] = vddc;
 277                                data->vddc_leakage.leakage_id
 278                                [data->vddc_leakage.count] = vv_id;
 279                                data->vddc_leakage.count++;
 280                        }
 281                }
 282        }
 283        return 0;
 284}
 285
 286/**
 287 * Change virtual leakage voltage to actual value.
 288 *
 289 * @param     hwmgr  the address of the powerplay hardware manager.
 290 * @param     pointer to changing voltage
 291 * @param     pointer to leakage table
 292 */
 293static void fiji_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
 294                uint16_t *voltage, struct fiji_leakage_voltage *leakage_table)
 295{
 296        uint32_t index;
 297
 298        /* search for leakage voltage ID 0xff01 ~ 0xff08 */
 299        for (index = 0; index < leakage_table->count; index++) {
 300                /* if this voltage matches a leakage voltage ID */
 301                /* patch with actual leakage voltage */
 302                if (leakage_table->leakage_id[index] == *voltage) {
 303                        *voltage = leakage_table->actual_voltage[index];
 304                        break;
 305                }
 306        }
 307
 308        if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
 309                printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
 310}
 311
 312/**
 313* Patch voltage lookup table by EVV leakages.
 314*
 315* @param     hwmgr  the address of the powerplay hardware manager.
 316* @param     pointer to voltage lookup table
 317* @param     pointer to leakage table
 318* @return     always 0
 319*/
 320static int fiji_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
 321                phm_ppt_v1_voltage_lookup_table *lookup_table,
 322                struct fiji_leakage_voltage *leakage_table)
 323{
 324        uint32_t i;
 325
 326        for (i = 0; i < lookup_table->count; i++)
 327                fiji_patch_with_vdd_leakage(hwmgr,
 328                                &lookup_table->entries[i].us_vdd, leakage_table);
 329
 330        return 0;
 331}
 332
 333static int fiji_patch_clock_voltage_limits_with_vddc_leakage(
 334                struct pp_hwmgr *hwmgr, struct fiji_leakage_voltage *leakage_table,
 335                uint16_t *vddc)
 336{
 337        struct phm_ppt_v1_information *table_info =
 338                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 339        fiji_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
 340        hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
 341                        table_info->max_clock_voltage_on_dc.vddc;
 342        return 0;
 343}
 344
 345static int fiji_patch_voltage_dependency_tables_with_lookup_table(
 346                struct pp_hwmgr *hwmgr)
 347{
 348        uint8_t entryId;
 349        uint8_t voltageId;
 350        struct phm_ppt_v1_information *table_info =
 351                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 352
 353        struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
 354                        table_info->vdd_dep_on_sclk;
 355        struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
 356                        table_info->vdd_dep_on_mclk;
 357        struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
 358                        table_info->mm_dep_table;
 359
 360        for (entryId = 0; entryId < sclk_table->count; ++entryId) {
 361                voltageId = sclk_table->entries[entryId].vddInd;
 362                sclk_table->entries[entryId].vddc =
 363                                table_info->vddc_lookup_table->entries[voltageId].us_vdd;
 364        }
 365
 366        for (entryId = 0; entryId < mclk_table->count; ++entryId) {
 367                voltageId = mclk_table->entries[entryId].vddInd;
 368                mclk_table->entries[entryId].vddc =
 369                        table_info->vddc_lookup_table->entries[voltageId].us_vdd;
 370        }
 371
 372        for (entryId = 0; entryId < mm_table->count; ++entryId) {
 373                voltageId = mm_table->entries[entryId].vddcInd;
 374                mm_table->entries[entryId].vddc =
 375                        table_info->vddc_lookup_table->entries[voltageId].us_vdd;
 376        }
 377
 378        return 0;
 379
 380}
 381
 382static int fiji_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
 383{
 384        /* Need to determine if we need calculated voltage. */
 385        return 0;
 386}
 387
 388static int fiji_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
 389{
 390        /* Need to determine if we need calculated voltage from mm table. */
 391        return 0;
 392}
 393
 394static int fiji_sort_lookup_table(struct pp_hwmgr *hwmgr,
 395                struct phm_ppt_v1_voltage_lookup_table *lookup_table)
 396{
 397        uint32_t table_size, i, j;
 398        struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
 399        table_size = lookup_table->count;
 400
 401        PP_ASSERT_WITH_CODE(0 != lookup_table->count,
 402                "Lookup table is empty", return -EINVAL);
 403
 404        /* Sorting voltages */
 405        for (i = 0; i < table_size - 1; i++) {
 406                for (j = i + 1; j > 0; j--) {
 407                        if (lookup_table->entries[j].us_vdd <
 408                                        lookup_table->entries[j - 1].us_vdd) {
 409                                tmp_voltage_lookup_record = lookup_table->entries[j - 1];
 410                                lookup_table->entries[j - 1] = lookup_table->entries[j];
 411                                lookup_table->entries[j] = tmp_voltage_lookup_record;
 412                        }
 413                }
 414        }
 415
 416        return 0;
 417}
 418
 419static int fiji_complete_dependency_tables(struct pp_hwmgr *hwmgr)
 420{
 421        int result = 0;
 422        int tmp_result;
 423        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 424        struct phm_ppt_v1_information *table_info =
 425                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 426
 427        tmp_result = fiji_patch_lookup_table_with_leakage(hwmgr,
 428                        table_info->vddc_lookup_table, &(data->vddc_leakage));
 429        if (tmp_result)
 430                result = tmp_result;
 431
 432        tmp_result = fiji_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
 433                        &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
 434        if (tmp_result)
 435                result = tmp_result;
 436
 437        tmp_result = fiji_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
 438        if (tmp_result)
 439                result = tmp_result;
 440
 441        tmp_result = fiji_calc_voltage_dependency_tables(hwmgr);
 442        if (tmp_result)
 443                result = tmp_result;
 444
 445        tmp_result = fiji_calc_mm_voltage_dependency_table(hwmgr);
 446        if (tmp_result)
 447                result = tmp_result;
 448
 449        tmp_result = fiji_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
 450        if(tmp_result)
 451                result = tmp_result;
 452
 453        return result;
 454}
 455
 456static int fiji_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
 457{
 458        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 459        struct phm_ppt_v1_information *table_info =
 460                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 461
 462        struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
 463                        table_info->vdd_dep_on_sclk;
 464        struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
 465                        table_info->vdd_dep_on_mclk;
 466
 467        PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
 468                "VDD dependency on SCLK table is missing.       \
 469                This table is mandatory", return -EINVAL);
 470        PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
 471                "VDD dependency on SCLK table has to have is missing.   \
 472                This table is mandatory", return -EINVAL);
 473
 474        PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
 475                "VDD dependency on MCLK table is missing.       \
 476                This table is mandatory", return -EINVAL);
 477        PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
 478                "VDD dependency on MCLK table has to have is missing.    \
 479                This table is mandatory", return -EINVAL);
 480
 481        data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
 482        data->max_vddc_in_pptable =     (uint16_t)allowed_sclk_vdd_table->
 483                        entries[allowed_sclk_vdd_table->count - 1].vddc;
 484
 485        table_info->max_clock_voltage_on_ac.sclk =
 486                allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
 487        table_info->max_clock_voltage_on_ac.mclk =
 488                allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
 489        table_info->max_clock_voltage_on_ac.vddc =
 490                allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
 491        table_info->max_clock_voltage_on_ac.vddci =
 492                allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
 493
 494        hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
 495                table_info->max_clock_voltage_on_ac.sclk;
 496        hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
 497                table_info->max_clock_voltage_on_ac.mclk;
 498        hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
 499                table_info->max_clock_voltage_on_ac.vddc;
 500        hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
 501                table_info->max_clock_voltage_on_ac.vddci;
 502
 503        return 0;
 504}
 505
 506static uint16_t fiji_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
 507{
 508        uint32_t speedCntl = 0;
 509
 510        /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
 511        speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
 512                        ixPCIE_LC_SPEED_CNTL);
 513        return((uint16_t)PHM_GET_FIELD(speedCntl,
 514                        PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
 515}
 516
 517static int fiji_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
 518{
 519        uint32_t link_width;
 520
 521        /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
 522        link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
 523                        PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
 524
 525        PP_ASSERT_WITH_CODE((7 >= link_width),
 526                        "Invalid PCIe lane width!", return 0);
 527
 528        return decode_pcie_lane_width(link_width);
 529}
 530
 531/** Patch the Boot State to match VBIOS boot clocks and voltage.
 532*
 533* @param hwmgr Pointer to the hardware manager.
 534* @param pPowerState The address of the PowerState instance being created.
 535*
 536*/
 537static int fiji_patch_boot_state(struct pp_hwmgr *hwmgr,
 538                struct pp_hw_power_state *hw_ps)
 539{
 540        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 541        struct fiji_power_state *ps = (struct fiji_power_state *)hw_ps;
 542        ATOM_FIRMWARE_INFO_V2_2 *fw_info;
 543        uint16_t size;
 544        uint8_t frev, crev;
 545        int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
 546
 547        /* First retrieve the Boot clocks and VDDC from the firmware info table.
 548         * We assume here that fw_info is unchanged if this call fails.
 549         */
 550        fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
 551                        hwmgr->device, index,
 552                        &size, &frev, &crev);
 553        if (!fw_info)
 554                /* During a test, there is no firmware info table. */
 555                return 0;
 556
 557        /* Patch the state. */
 558        data->vbios_boot_state.sclk_bootup_value =
 559                        le32_to_cpu(fw_info->ulDefaultEngineClock);
 560        data->vbios_boot_state.mclk_bootup_value =
 561                        le32_to_cpu(fw_info->ulDefaultMemoryClock);
 562        data->vbios_boot_state.mvdd_bootup_value =
 563                        le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
 564        data->vbios_boot_state.vddc_bootup_value =
 565                        le16_to_cpu(fw_info->usBootUpVDDCVoltage);
 566        data->vbios_boot_state.vddci_bootup_value =
 567                        le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
 568        data->vbios_boot_state.pcie_gen_bootup_value =
 569                        fiji_get_current_pcie_speed(hwmgr);
 570        data->vbios_boot_state.pcie_lane_bootup_value =
 571                        (uint16_t)fiji_get_current_pcie_lane_number(hwmgr);
 572
 573        /* set boot power state */
 574        ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
 575        ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
 576        ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
 577        ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
 578
 579        return 0;
 580}
 581
 582static int fiji_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
 583{
 584        return phm_hwmgr_backend_fini(hwmgr);
 585}
 586
 587static int fiji_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
 588{
 589        struct fiji_hwmgr *data;
 590        uint32_t i;
 591        struct phm_ppt_v1_information *table_info =
 592                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 593        bool stay_in_boot;
 594        int result;
 595
 596        data = kzalloc(sizeof(struct fiji_hwmgr), GFP_KERNEL);
 597        if (data == NULL)
 598                return -ENOMEM;
 599
 600        hwmgr->backend = data;
 601
 602        data->dll_default_on = false;
 603        data->sram_end = SMC_RAM_END;
 604
 605        for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
 606                data->activity_target[i] = FIJI_AT_DFLT;
 607
 608        data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
 609
 610        data->mclk_activity_target = PPFIJI_MCLK_TARGETACTIVITY_DFLT;
 611        data->mclk_dpm0_activity_target = 0xa;
 612
 613        data->sclk_dpm_key_disabled = 0;
 614        data->mclk_dpm_key_disabled = 0;
 615        data->pcie_dpm_key_disabled = 0;
 616
 617        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 618                        PHM_PlatformCaps_UnTabledHardwareInterface);
 619        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 620                        PHM_PlatformCaps_TablelessHardwareInterface);
 621
 622        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 623                        PHM_PlatformCaps_SclkDeepSleep);
 624
 625        data->gpio_debug = 0;
 626
 627        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 628                        PHM_PlatformCaps_DynamicPatchPowerState);
 629
 630        /* need to set voltage control types before EVV patching */
 631        data->voltage_control = FIJI_VOLTAGE_CONTROL_NONE;
 632        data->vddci_control = FIJI_VOLTAGE_CONTROL_NONE;
 633        data->mvdd_control = FIJI_VOLTAGE_CONTROL_NONE;
 634
 635        data->force_pcie_gen = PP_PCIEGenInvalid;
 636
 637        if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 638                        VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
 639                data->voltage_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
 640
 641        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 642                        PHM_PlatformCaps_EnableMVDDControl))
 643                if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 644                                VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
 645                        data->mvdd_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
 646
 647        if (data->mvdd_control == FIJI_VOLTAGE_CONTROL_NONE)
 648                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 649                        PHM_PlatformCaps_EnableMVDDControl);
 650
 651        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 652                        PHM_PlatformCaps_ControlVDDCI)) {
 653                if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 654                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
 655                        data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
 656                else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 657                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
 658                        data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
 659        }
 660
 661        if (data->vddci_control == FIJI_VOLTAGE_CONTROL_NONE)
 662                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 663                                PHM_PlatformCaps_ControlVDDCI);
 664
 665        if (table_info && table_info->cac_dtp_table->usClockStretchAmount)
 666                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 667                                PHM_PlatformCaps_ClockStretcher);
 668
 669        fiji_init_dpm_defaults(hwmgr);
 670
 671        /* Get leakage voltage based on leakage ID. */
 672        fiji_get_evv_voltages(hwmgr);
 673
 674        /* Patch our voltage dependency table with actual leakage voltage
 675         * We need to perform leakage translation before it's used by other functions
 676         */
 677        fiji_complete_dependency_tables(hwmgr);
 678
 679        /* Parse pptable data read from VBIOS */
 680        fiji_set_private_data_based_on_pptable(hwmgr);
 681
 682        /* ULV Support */
 683        data->ulv.ulv_supported = true; /* ULV feature is enabled by default */
 684
 685        /* Initalize Dynamic State Adjustment Rule Settings */
 686        result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
 687
 688        if (!result) {
 689                data->uvd_enabled = false;
 690                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 691                                PHM_PlatformCaps_EnableSMU7ThermalManagement);
 692                data->vddc_phase_shed_control = false;
 693        }
 694
 695        stay_in_boot = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 696                        PHM_PlatformCaps_StayInBootState);
 697
 698        if (0 == result) {
 699                struct cgs_system_info sys_info = {0};
 700
 701                data->is_tlu_enabled = false;
 702                hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
 703                                FIJI_MAX_HARDWARE_POWERLEVELS;
 704                hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
 705                hwmgr->platform_descriptor.minimumClocksReductionPercentage  = 50;
 706
 707                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 708                                PHM_PlatformCaps_FanSpeedInTableIsRPM);
 709
 710                if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp &&
 711                                hwmgr->thermal_controller.
 712                                advanceFanControlParameters.ucFanControlMode) {
 713                        hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
 714                                        hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
 715                        hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
 716                                        hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
 717                        hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
 718                                        table_info->cac_dtp_table->usOperatingTempMinLimit;
 719                        hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
 720                                        table_info->cac_dtp_table->usOperatingTempMaxLimit;
 721                        hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
 722                                        table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
 723                        hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
 724                                        table_info->cac_dtp_table->usOperatingTempStep;
 725                        hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
 726                                        table_info->cac_dtp_table->usTargetOperatingTemp;
 727
 728                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 729                                        PHM_PlatformCaps_ODFuzzyFanControlSupport);
 730                }
 731
 732                sys_info.size = sizeof(struct cgs_system_info);
 733                sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
 734                result = cgs_query_system_info(hwmgr->device, &sys_info);
 735                if (result)
 736                        data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK;
 737                else
 738                        data->pcie_gen_cap = (uint32_t)sys_info.value;
 739                if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
 740                        data->pcie_spc_cap = 20;
 741                sys_info.size = sizeof(struct cgs_system_info);
 742                sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
 743                result = cgs_query_system_info(hwmgr->device, &sys_info);
 744                if (result)
 745                        data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK;
 746                else
 747                        data->pcie_lane_cap = (uint32_t)sys_info.value;
 748        } else {
 749                /* Ignore return value in here, we are cleaning up a mess. */
 750                fiji_hwmgr_backend_fini(hwmgr);
 751        }
 752
 753        return 0;
 754}
 755
 756/**
 757 * Read clock related registers.
 758 *
 759 * @param    hwmgr  the address of the powerplay hardware manager.
 760 * @return   always 0
 761 */
 762static int fiji_read_clock_registers(struct pp_hwmgr *hwmgr)
 763{
 764        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 765
 766        data->clock_registers.vCG_SPLL_FUNC_CNTL =
 767                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 768                                ixCG_SPLL_FUNC_CNTL);
 769        data->clock_registers.vCG_SPLL_FUNC_CNTL_2 =
 770                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 771                                ixCG_SPLL_FUNC_CNTL_2);
 772        data->clock_registers.vCG_SPLL_FUNC_CNTL_3 =
 773                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 774                                ixCG_SPLL_FUNC_CNTL_3);
 775        data->clock_registers.vCG_SPLL_FUNC_CNTL_4 =
 776                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 777                                ixCG_SPLL_FUNC_CNTL_4);
 778        data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM =
 779                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 780                                ixCG_SPLL_SPREAD_SPECTRUM);
 781        data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
 782                cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 783                                ixCG_SPLL_SPREAD_SPECTRUM_2);
 784
 785        return 0;
 786}
 787
 788/**
 789 * Find out if memory is GDDR5.
 790 *
 791 * @param    hwmgr  the address of the powerplay hardware manager.
 792 * @return   always 0
 793 */
 794static int fiji_get_memory_type(struct pp_hwmgr *hwmgr)
 795{
 796        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 797        uint32_t temp;
 798
 799        temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
 800
 801        data->is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
 802                        ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
 803                         MC_SEQ_MISC0_GDDR5_SHIFT));
 804
 805        return 0;
 806}
 807
 808/**
 809 * Enables Dynamic Power Management by SMC
 810 *
 811 * @param    hwmgr  the address of the powerplay hardware manager.
 812 * @return   always 0
 813 */
 814static int fiji_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
 815{
 816        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 817                        GENERAL_PWRMGT, STATIC_PM_EN, 1);
 818
 819        return 0;
 820}
 821
 822/**
 823 * Initialize PowerGating States for different engines
 824 *
 825 * @param    hwmgr  the address of the powerplay hardware manager.
 826 * @return   always 0
 827 */
 828static int fiji_init_power_gate_state(struct pp_hwmgr *hwmgr)
 829{
 830        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 831
 832        data->uvd_power_gated = false;
 833        data->vce_power_gated = false;
 834        data->samu_power_gated = false;
 835        data->acp_power_gated = false;
 836        data->pg_acp_init = true;
 837
 838        return 0;
 839}
 840
 841static int fiji_init_sclk_threshold(struct pp_hwmgr *hwmgr)
 842{
 843        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 844        data->low_sclk_interrupt_threshold = 0;
 845
 846        return 0;
 847}
 848
 849static int fiji_setup_asic_task(struct pp_hwmgr *hwmgr)
 850{
 851        int tmp_result, result = 0;
 852
 853        tmp_result = fiji_read_clock_registers(hwmgr);
 854        PP_ASSERT_WITH_CODE((0 == tmp_result),
 855                        "Failed to read clock registers!", result = tmp_result);
 856
 857        tmp_result = fiji_get_memory_type(hwmgr);
 858        PP_ASSERT_WITH_CODE((0 == tmp_result),
 859                        "Failed to get memory type!", result = tmp_result);
 860
 861        tmp_result = fiji_enable_acpi_power_management(hwmgr);
 862        PP_ASSERT_WITH_CODE((0 == tmp_result),
 863                        "Failed to enable ACPI power management!", result = tmp_result);
 864
 865        tmp_result = fiji_init_power_gate_state(hwmgr);
 866        PP_ASSERT_WITH_CODE((0 == tmp_result),
 867                        "Failed to init power gate state!", result = tmp_result);
 868
 869        tmp_result = tonga_get_mc_microcode_version(hwmgr);
 870        PP_ASSERT_WITH_CODE((0 == tmp_result),
 871                        "Failed to get MC microcode version!", result = tmp_result);
 872
 873        tmp_result = fiji_init_sclk_threshold(hwmgr);
 874        PP_ASSERT_WITH_CODE((0 == tmp_result),
 875                        "Failed to init sclk threshold!", result = tmp_result);
 876
 877        return result;
 878}
 879
 880/**
 881* Checks if we want to support voltage control
 882*
 883* @param    hwmgr  the address of the powerplay hardware manager.
 884*/
 885static bool fiji_voltage_control(const struct pp_hwmgr *hwmgr)
 886{
 887        const struct fiji_hwmgr *data =
 888                        (const struct fiji_hwmgr *)(hwmgr->backend);
 889
 890        return (FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control);
 891}
 892
 893/**
 894* Enable voltage control
 895*
 896* @param    hwmgr  the address of the powerplay hardware manager.
 897* @return   always 0
 898*/
 899static int fiji_enable_voltage_control(struct pp_hwmgr *hwmgr)
 900{
 901        /* enable voltage control */
 902        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
 903                        GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
 904
 905        return 0;
 906}
 907
 908/**
 909* Remove repeated voltage values and create table with unique values.
 910*
 911* @param    hwmgr  the address of the powerplay hardware manager.
 912* @param    vol_table  the pointer to changing voltage table
 913* @return    0 in success
 914*/
 915
 916static int fiji_trim_voltage_table(struct pp_hwmgr *hwmgr,
 917                struct pp_atomctrl_voltage_table *vol_table)
 918{
 919        uint32_t i, j;
 920        uint16_t vvalue;
 921        bool found = false;
 922        struct pp_atomctrl_voltage_table *table;
 923
 924        PP_ASSERT_WITH_CODE((NULL != vol_table),
 925                        "Voltage Table empty.", return -EINVAL);
 926        table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
 927                        GFP_KERNEL);
 928
 929        if (NULL == table)
 930                return -ENOMEM;
 931
 932        table->mask_low = vol_table->mask_low;
 933        table->phase_delay = vol_table->phase_delay;
 934
 935        for (i = 0; i < vol_table->count; i++) {
 936                vvalue = vol_table->entries[i].value;
 937                found = false;
 938
 939                for (j = 0; j < table->count; j++) {
 940                        if (vvalue == table->entries[j].value) {
 941                                found = true;
 942                                break;
 943                        }
 944                }
 945
 946                if (!found) {
 947                        table->entries[table->count].value = vvalue;
 948                        table->entries[table->count].smio_low =
 949                                        vol_table->entries[i].smio_low;
 950                        table->count++;
 951                }
 952        }
 953
 954        memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
 955        kfree(table);
 956
 957        return 0;
 958}
 959
 960static int fiji_get_svi2_mvdd_voltage_table(struct pp_hwmgr *hwmgr,
 961                phm_ppt_v1_clock_voltage_dependency_table *dep_table)
 962{
 963        uint32_t i;
 964        int result;
 965        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 966        struct pp_atomctrl_voltage_table *vol_table = &(data->mvdd_voltage_table);
 967
 968        PP_ASSERT_WITH_CODE((0 != dep_table->count),
 969                        "Voltage Dependency Table empty.", return -EINVAL);
 970
 971        vol_table->mask_low = 0;
 972        vol_table->phase_delay = 0;
 973        vol_table->count = dep_table->count;
 974
 975        for (i = 0; i < dep_table->count; i++) {
 976                vol_table->entries[i].value = dep_table->entries[i].mvdd;
 977                vol_table->entries[i].smio_low = 0;
 978        }
 979
 980        result = fiji_trim_voltage_table(hwmgr, vol_table);
 981        PP_ASSERT_WITH_CODE((0 == result),
 982                        "Failed to trim MVDD table.", return result);
 983
 984        return 0;
 985}
 986
 987static int fiji_get_svi2_vddci_voltage_table(struct pp_hwmgr *hwmgr,
 988                phm_ppt_v1_clock_voltage_dependency_table *dep_table)
 989{
 990        uint32_t i;
 991        int result;
 992        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
 993        struct pp_atomctrl_voltage_table *vol_table = &(data->vddci_voltage_table);
 994
 995        PP_ASSERT_WITH_CODE((0 != dep_table->count),
 996                        "Voltage Dependency Table empty.", return -EINVAL);
 997
 998        vol_table->mask_low = 0;
 999        vol_table->phase_delay = 0;
1000        vol_table->count = dep_table->count;
1001
1002        for (i = 0; i < dep_table->count; i++) {
1003                vol_table->entries[i].value = dep_table->entries[i].vddci;
1004                vol_table->entries[i].smio_low = 0;
1005        }
1006
1007        result = fiji_trim_voltage_table(hwmgr, vol_table);
1008        PP_ASSERT_WITH_CODE((0 == result),
1009                        "Failed to trim VDDCI table.", return result);
1010
1011        return 0;
1012}
1013
1014static int fiji_get_svi2_vdd_voltage_table(struct pp_hwmgr *hwmgr,
1015                phm_ppt_v1_voltage_lookup_table *lookup_table)
1016{
1017        int i = 0;
1018        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1019        struct pp_atomctrl_voltage_table *vol_table = &(data->vddc_voltage_table);
1020
1021        PP_ASSERT_WITH_CODE((0 != lookup_table->count),
1022                        "Voltage Lookup Table empty.", return -EINVAL);
1023
1024        vol_table->mask_low = 0;
1025        vol_table->phase_delay = 0;
1026
1027        vol_table->count = lookup_table->count;
1028
1029        for (i = 0; i < vol_table->count; i++) {
1030                vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
1031                vol_table->entries[i].smio_low = 0;
1032        }
1033
1034        return 0;
1035}
1036
1037/* ---- Voltage Tables ----
1038 * If the voltage table would be bigger than
1039 * what will fit into the state table on
1040 * the SMC keep only the higher entries.
1041 */
1042static void fiji_trim_voltage_table_to_fit_state_table(struct pp_hwmgr *hwmgr,
1043                uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table)
1044{
1045        unsigned int i, diff;
1046
1047        if (vol_table->count <= max_vol_steps)
1048                return;
1049
1050        diff = vol_table->count - max_vol_steps;
1051
1052        for (i = 0; i < max_vol_steps; i++)
1053                vol_table->entries[i] = vol_table->entries[i + diff];
1054
1055        vol_table->count = max_vol_steps;
1056
1057        return;
1058}
1059
1060/**
1061* Create Voltage Tables.
1062*
1063* @param    hwmgr  the address of the powerplay hardware manager.
1064* @return   always 0
1065*/
1066static int fiji_construct_voltage_tables(struct pp_hwmgr *hwmgr)
1067{
1068        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1069        struct phm_ppt_v1_information *table_info =
1070                        (struct phm_ppt_v1_information *)hwmgr->pptable;
1071        int result;
1072
1073        if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1074                result = atomctrl_get_voltage_table_v3(hwmgr,
1075                                VOLTAGE_TYPE_MVDDC,     VOLTAGE_OBJ_GPIO_LUT,
1076                                &(data->mvdd_voltage_table));
1077                PP_ASSERT_WITH_CODE((0 == result),
1078                                "Failed to retrieve MVDD table.",
1079                                return result);
1080        } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
1081                result = fiji_get_svi2_mvdd_voltage_table(hwmgr,
1082                                table_info->vdd_dep_on_mclk);
1083                PP_ASSERT_WITH_CODE((0 == result),
1084                                "Failed to retrieve SVI2 MVDD table from dependancy table.",
1085                                return result;);
1086        }
1087
1088        if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
1089                result = atomctrl_get_voltage_table_v3(hwmgr,
1090                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
1091                                &(data->vddci_voltage_table));
1092                PP_ASSERT_WITH_CODE((0 == result),
1093                                "Failed to retrieve VDDCI table.",
1094                                return result);
1095        } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
1096                result = fiji_get_svi2_vddci_voltage_table(hwmgr,
1097                                table_info->vdd_dep_on_mclk);
1098                PP_ASSERT_WITH_CODE((0 == result),
1099                                "Failed to retrieve SVI2 VDDCI table from dependancy table.",
1100                                return result);
1101        }
1102
1103        if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1104                result = fiji_get_svi2_vdd_voltage_table(hwmgr,
1105                                table_info->vddc_lookup_table);
1106                PP_ASSERT_WITH_CODE((0 == result),
1107                                "Failed to retrieve SVI2 VDDC table from lookup table.",
1108                                return result);
1109        }
1110
1111        PP_ASSERT_WITH_CODE(
1112                        (data->vddc_voltage_table.count <= (SMU73_MAX_LEVELS_VDDC)),
1113                        "Too many voltage values for VDDC. Trimming to fit state table.",
1114                        fiji_trim_voltage_table_to_fit_state_table(hwmgr,
1115                                        SMU73_MAX_LEVELS_VDDC, &(data->vddc_voltage_table)));
1116
1117        PP_ASSERT_WITH_CODE(
1118                        (data->vddci_voltage_table.count <= (SMU73_MAX_LEVELS_VDDCI)),
1119                        "Too many voltage values for VDDCI. Trimming to fit state table.",
1120                        fiji_trim_voltage_table_to_fit_state_table(hwmgr,
1121                                        SMU73_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table)));
1122
1123        PP_ASSERT_WITH_CODE(
1124                        (data->mvdd_voltage_table.count <= (SMU73_MAX_LEVELS_MVDD)),
1125                        "Too many voltage values for MVDD. Trimming to fit state table.",
1126                        fiji_trim_voltage_table_to_fit_state_table(hwmgr,
1127                                        SMU73_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table)));
1128
1129        return 0;
1130}
1131
1132static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
1133{
1134        /* Program additional LP registers
1135         * that are no longer programmed by VBIOS
1136         */
1137        cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
1138                        cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
1139        cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
1140                        cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
1141        cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
1142                        cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
1143        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
1144                        cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
1145        cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
1146                        cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
1147        cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
1148                        cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
1149        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
1150                        cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
1151
1152        return 0;
1153}
1154
1155/**
1156* Programs static screed detection parameters
1157*
1158* @param    hwmgr  the address of the powerplay hardware manager.
1159* @return   always 0
1160*/
1161static int fiji_program_static_screen_threshold_parameters(
1162                struct pp_hwmgr *hwmgr)
1163{
1164        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1165
1166        /* Set static screen threshold unit */
1167        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1168                        CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
1169                        data->static_screen_threshold_unit);
1170        /* Set static screen threshold */
1171        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1172                        CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
1173                        data->static_screen_threshold);
1174
1175        return 0;
1176}
1177
1178/**
1179* Setup display gap for glitch free memory clock switching.
1180*
1181* @param    hwmgr  the address of the powerplay hardware manager.
1182* @return   always  0
1183*/
1184static int fiji_enable_display_gap(struct pp_hwmgr *hwmgr)
1185{
1186        uint32_t displayGap =
1187                        cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1188                                        ixCG_DISPLAY_GAP_CNTL);
1189
1190        displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
1191                        DISP_GAP, DISPLAY_GAP_IGNORE);
1192
1193        displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
1194                        DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
1195
1196        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1197                        ixCG_DISPLAY_GAP_CNTL, displayGap);
1198
1199        return 0;
1200}
1201
1202/**
1203* Programs activity state transition voting clients
1204*
1205* @param    hwmgr  the address of the powerplay hardware manager.
1206* @return   always  0
1207*/
1208static int fiji_program_voting_clients(struct pp_hwmgr *hwmgr)
1209{
1210        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1211
1212        /* Clear reset for voting clients before enabling DPM */
1213        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1214                        SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
1215        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1216                        SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
1217
1218        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1219                        ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
1220        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1221                        ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
1222        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1223                        ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
1224        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1225                        ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
1226        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1227                        ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
1228        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1229                        ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
1230        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1231                        ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
1232        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1233                        ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
1234
1235        return 0;
1236}
1237
1238static int fiji_clear_voting_clients(struct pp_hwmgr *hwmgr)
1239{
1240        /* Reset voting clients before disabling DPM */
1241        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1242                        SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
1243        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1244                        SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
1245
1246        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1247                        ixCG_FREQ_TRAN_VOTING_0, 0);
1248        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1249                        ixCG_FREQ_TRAN_VOTING_1, 0);
1250        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1251                        ixCG_FREQ_TRAN_VOTING_2, 0);
1252        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1253                        ixCG_FREQ_TRAN_VOTING_3, 0);
1254        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1255                        ixCG_FREQ_TRAN_VOTING_4, 0);
1256        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1257                        ixCG_FREQ_TRAN_VOTING_5, 0);
1258        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1259                        ixCG_FREQ_TRAN_VOTING_6, 0);
1260        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1261                        ixCG_FREQ_TRAN_VOTING_7, 0);
1262
1263        return 0;
1264}
1265
1266/**
1267* Get the location of various tables inside the FW image.
1268*
1269* @param    hwmgr  the address of the powerplay hardware manager.
1270* @return   always  0
1271*/
1272static int fiji_process_firmware_header(struct pp_hwmgr *hwmgr)
1273{
1274        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1275        struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
1276        uint32_t tmp;
1277        int result;
1278        bool error = false;
1279
1280        result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1281                        SMU7_FIRMWARE_HEADER_LOCATION +
1282                        offsetof(SMU73_Firmware_Header, DpmTable),
1283                        &tmp, data->sram_end);
1284
1285        if (0 == result)
1286                data->dpm_table_start = tmp;
1287
1288        error |= (0 != result);
1289
1290        result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1291                        SMU7_FIRMWARE_HEADER_LOCATION +
1292                        offsetof(SMU73_Firmware_Header, SoftRegisters),
1293                        &tmp, data->sram_end);
1294
1295        if (!result) {
1296                data->soft_regs_start = tmp;
1297                smu_data->soft_regs_start = tmp;
1298        }
1299
1300        error |= (0 != result);
1301
1302        result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1303                        SMU7_FIRMWARE_HEADER_LOCATION +
1304                        offsetof(SMU73_Firmware_Header, mcRegisterTable),
1305                        &tmp, data->sram_end);
1306
1307        if (!result)
1308                data->mc_reg_table_start = tmp;
1309
1310        result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1311                        SMU7_FIRMWARE_HEADER_LOCATION +
1312                        offsetof(SMU73_Firmware_Header, FanTable),
1313                        &tmp, data->sram_end);
1314
1315        if (!result)
1316                data->fan_table_start = tmp;
1317
1318        error |= (0 != result);
1319
1320        result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1321                        SMU7_FIRMWARE_HEADER_LOCATION +
1322                        offsetof(SMU73_Firmware_Header, mcArbDramTimingTable),
1323                        &tmp, data->sram_end);
1324
1325        if (!result)
1326                data->arb_table_start = tmp;
1327
1328        error |= (0 != result);
1329
1330        result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1331                        SMU7_FIRMWARE_HEADER_LOCATION +
1332                        offsetof(SMU73_Firmware_Header, Version),
1333                        &tmp, data->sram_end);
1334
1335        if (!result)
1336                hwmgr->microcode_version_info.SMC = tmp;
1337
1338        error |= (0 != result);
1339
1340        return error ? -1 : 0;
1341}
1342
1343/* Copy one arb setting to another and then switch the active set.
1344 * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
1345 */
1346static int fiji_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
1347                uint32_t arb_src, uint32_t arb_dest)
1348{
1349        uint32_t mc_arb_dram_timing;
1350        uint32_t mc_arb_dram_timing2;
1351        uint32_t burst_time;
1352        uint32_t mc_cg_config;
1353
1354        switch (arb_src) {
1355        case MC_CG_ARB_FREQ_F0:
1356                mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
1357                mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
1358                burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
1359                break;
1360        case MC_CG_ARB_FREQ_F1:
1361                mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
1362                mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
1363                burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
1364                break;
1365        default:
1366                return -EINVAL;
1367        }
1368
1369        switch (arb_dest) {
1370        case MC_CG_ARB_FREQ_F0:
1371                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
1372                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
1373                PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
1374                break;
1375        case MC_CG_ARB_FREQ_F1:
1376                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
1377                cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
1378                PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
1379                break;
1380        default:
1381                return -EINVAL;
1382        }
1383
1384        mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
1385        mc_cg_config |= 0x0000000F;
1386        cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
1387        PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
1388
1389        return 0;
1390}
1391
1392/**
1393* Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1394*
1395* @param    hwmgr  the address of the powerplay hardware manager.
1396* @return   if success then 0;
1397*/
1398static int fiji_reset_to_default(struct pp_hwmgr *hwmgr)
1399{
1400        return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults);
1401}
1402
1403/**
1404* Initial switch from ARB F0->F1
1405*
1406* @param    hwmgr  the address of the powerplay hardware manager.
1407* @return   always 0
1408* This function is to be called from the SetPowerState table.
1409*/
1410static int fiji_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
1411{
1412        return fiji_copy_and_switch_arb_sets(hwmgr,
1413                        MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
1414}
1415
1416static int fiji_force_switch_to_arbf0(struct pp_hwmgr *hwmgr)
1417{
1418        uint32_t tmp;
1419
1420        tmp = (cgs_read_ind_register(hwmgr->device,
1421                        CGS_IND_REG__SMC, ixSMC_SCRATCH9) &
1422                        0x0000ff00) >> 8;
1423
1424        if (tmp == MC_CG_ARB_FREQ_F0)
1425                return 0;
1426
1427        return fiji_copy_and_switch_arb_sets(hwmgr,
1428                        tmp, MC_CG_ARB_FREQ_F0);
1429}
1430
1431static int fiji_reset_single_dpm_table(struct pp_hwmgr *hwmgr,
1432                struct fiji_single_dpm_table *dpm_table, uint32_t count)
1433{
1434        int i;
1435        PP_ASSERT_WITH_CODE(count <= MAX_REGULAR_DPM_NUMBER,
1436                        "Fatal error, can not set up single DPM table entries "
1437                        "to exceed max number!",);
1438
1439        dpm_table->count = count;
1440        for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
1441                dpm_table->dpm_levels[i].enabled = false;
1442
1443        return 0;
1444}
1445
1446static void fiji_setup_pcie_table_entry(
1447        struct fiji_single_dpm_table *dpm_table,
1448        uint32_t index, uint32_t pcie_gen,
1449        uint32_t pcie_lanes)
1450{
1451        dpm_table->dpm_levels[index].value = pcie_gen;
1452        dpm_table->dpm_levels[index].param1 = pcie_lanes;
1453        dpm_table->dpm_levels[index].enabled = true;
1454}
1455
1456static int fiji_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
1457{
1458        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1459        struct phm_ppt_v1_information *table_info =
1460                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1461        struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
1462        uint32_t i, max_entry;
1463
1464        PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
1465                        data->use_pcie_power_saving_levels), "No pcie performance levels!",
1466                        return -EINVAL);
1467
1468        if (data->use_pcie_performance_levels &&
1469                        !data->use_pcie_power_saving_levels) {
1470                data->pcie_gen_power_saving = data->pcie_gen_performance;
1471                data->pcie_lane_power_saving = data->pcie_lane_performance;
1472        } else if (!data->use_pcie_performance_levels &&
1473                        data->use_pcie_power_saving_levels) {
1474                data->pcie_gen_performance = data->pcie_gen_power_saving;
1475                data->pcie_lane_performance = data->pcie_lane_power_saving;
1476        }
1477
1478        fiji_reset_single_dpm_table(hwmgr,
1479                        &data->dpm_table.pcie_speed_table, SMU73_MAX_LEVELS_LINK);
1480
1481        if (pcie_table != NULL) {
1482                /* max_entry is used to make sure we reserve one PCIE level
1483                 * for boot level (fix for A+A PSPP issue).
1484                 * If PCIE table from PPTable have ULV entry + 8 entries,
1485                 * then ignore the last entry.*/
1486                max_entry = (SMU73_MAX_LEVELS_LINK < pcie_table->count) ?
1487                                SMU73_MAX_LEVELS_LINK : pcie_table->count;
1488                for (i = 1; i < max_entry; i++) {
1489                        fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
1490                                        get_pcie_gen_support(data->pcie_gen_cap,
1491                                                        pcie_table->entries[i].gen_speed),
1492                                        get_pcie_lane_support(data->pcie_lane_cap,
1493                                                        pcie_table->entries[i].lane_width));
1494                }
1495                data->dpm_table.pcie_speed_table.count = max_entry - 1;
1496        } else {
1497                /* Hardcode Pcie Table */
1498                fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
1499                                get_pcie_gen_support(data->pcie_gen_cap,
1500                                                PP_Min_PCIEGen),
1501                                get_pcie_lane_support(data->pcie_lane_cap,
1502                                                PP_Max_PCIELane));
1503                fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
1504                                get_pcie_gen_support(data->pcie_gen_cap,
1505                                                PP_Min_PCIEGen),
1506                                get_pcie_lane_support(data->pcie_lane_cap,
1507                                                PP_Max_PCIELane));
1508                fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
1509                                get_pcie_gen_support(data->pcie_gen_cap,
1510                                                PP_Max_PCIEGen),
1511                                get_pcie_lane_support(data->pcie_lane_cap,
1512                                                PP_Max_PCIELane));
1513                fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
1514                                get_pcie_gen_support(data->pcie_gen_cap,
1515                                                PP_Max_PCIEGen),
1516                                get_pcie_lane_support(data->pcie_lane_cap,
1517                                                PP_Max_PCIELane));
1518                fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
1519                                get_pcie_gen_support(data->pcie_gen_cap,
1520                                                PP_Max_PCIEGen),
1521                                get_pcie_lane_support(data->pcie_lane_cap,
1522                                                PP_Max_PCIELane));
1523                fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
1524                                get_pcie_gen_support(data->pcie_gen_cap,
1525                                                PP_Max_PCIEGen),
1526                                get_pcie_lane_support(data->pcie_lane_cap,
1527                                                PP_Max_PCIELane));
1528
1529                data->dpm_table.pcie_speed_table.count = 6;
1530        }
1531        /* Populate last level for boot PCIE level, but do not increment count. */
1532        fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
1533                        data->dpm_table.pcie_speed_table.count,
1534                        get_pcie_gen_support(data->pcie_gen_cap,
1535                                        PP_Min_PCIEGen),
1536                        get_pcie_lane_support(data->pcie_lane_cap,
1537                                        PP_Max_PCIELane));
1538
1539        return 0;
1540}
1541
1542/*
1543 * This function is to initalize all DPM state tables
1544 * for SMU7 based on the dependency table.
1545 * Dynamic state patching function will then trim these
1546 * state tables to the allowed range based
1547 * on the power policy or external client requests,
1548 * such as UVD request, etc.
1549 */
1550static int fiji_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
1551{
1552        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1553        struct phm_ppt_v1_information *table_info =
1554                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1555        uint32_t i;
1556
1557        struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table =
1558                        table_info->vdd_dep_on_sclk;
1559        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
1560                        table_info->vdd_dep_on_mclk;
1561
1562        PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
1563                        "SCLK dependency table is missing. This table is mandatory",
1564                        return -EINVAL);
1565        PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
1566                        "SCLK dependency table has to have is missing. "
1567                        "This table is mandatory",
1568                        return -EINVAL);
1569
1570        PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
1571                        "MCLK dependency table is missing. This table is mandatory",
1572                        return -EINVAL);
1573        PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
1574                        "MCLK dependency table has to have is missing. "
1575                        "This table is mandatory",
1576                        return -EINVAL);
1577
1578        /* clear the state table to reset everything to default */
1579        fiji_reset_single_dpm_table(hwmgr,
1580                        &data->dpm_table.sclk_table, SMU73_MAX_LEVELS_GRAPHICS);
1581        fiji_reset_single_dpm_table(hwmgr,
1582                        &data->dpm_table.mclk_table, SMU73_MAX_LEVELS_MEMORY);
1583
1584        /* Initialize Sclk DPM table based on allow Sclk values */
1585        data->dpm_table.sclk_table.count = 0;
1586        for (i = 0; i < dep_sclk_table->count; i++) {
1587                if (i == 0 || data->dpm_table.sclk_table.dpm_levels
1588                                [data->dpm_table.sclk_table.count - 1].value !=
1589                                                dep_sclk_table->entries[i].clk) {
1590                        data->dpm_table.sclk_table.dpm_levels
1591                        [data->dpm_table.sclk_table.count].value =
1592                                        dep_sclk_table->entries[i].clk;
1593                        data->dpm_table.sclk_table.dpm_levels
1594                        [data->dpm_table.sclk_table.count].enabled =
1595                                        (i == 0) ? true : false;
1596                        data->dpm_table.sclk_table.count++;
1597                }
1598        }
1599
1600        /* Initialize Mclk DPM table based on allow Mclk values */
1601        data->dpm_table.mclk_table.count = 0;
1602        for (i=0; i<dep_mclk_table->count; i++) {
1603                if ( i==0 || data->dpm_table.mclk_table.dpm_levels
1604                                [data->dpm_table.mclk_table.count - 1].value !=
1605                                                dep_mclk_table->entries[i].clk) {
1606                        data->dpm_table.mclk_table.dpm_levels
1607                        [data->dpm_table.mclk_table.count].value =
1608                                        dep_mclk_table->entries[i].clk;
1609                        data->dpm_table.mclk_table.dpm_levels
1610                        [data->dpm_table.mclk_table.count].enabled =
1611                                        (i == 0) ? true : false;
1612                        data->dpm_table.mclk_table.count++;
1613                }
1614        }
1615
1616        /* setup PCIE gen speed levels */
1617        fiji_setup_default_pcie_table(hwmgr);
1618
1619        /* save a copy of the default DPM table */
1620        memcpy(&(data->golden_dpm_table), &(data->dpm_table),
1621                        sizeof(struct fiji_dpm_table));
1622
1623        return 0;
1624}
1625
1626/**
1627 * @brief PhwFiji_GetVoltageOrder
1628 *  Returns index of requested voltage record in lookup(table)
1629 * @param lookup_table - lookup list to search in
1630 * @param voltage - voltage to look for
1631 * @return 0 on success
1632 */
1633uint8_t fiji_get_voltage_index(
1634                struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
1635{
1636        uint8_t count = (uint8_t) (lookup_table->count);
1637        uint8_t i;
1638
1639        PP_ASSERT_WITH_CODE((NULL != lookup_table),
1640                        "Lookup Table empty.", return 0);
1641        PP_ASSERT_WITH_CODE((0 != count),
1642                        "Lookup Table empty.", return 0);
1643
1644        for (i = 0; i < lookup_table->count; i++) {
1645                /* find first voltage equal or bigger than requested */
1646                if (lookup_table->entries[i].us_vdd >= voltage)
1647                        return i;
1648        }
1649        /* voltage is bigger than max voltage in the table */
1650        return i - 1;
1651}
1652
1653/**
1654* Preparation of vddc and vddgfx CAC tables for SMC.
1655*
1656* @param    hwmgr  the address of the hardware manager
1657* @param    table  the SMC DPM table structure to be populated
1658* @return   always 0
1659*/
1660static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr,
1661                struct SMU73_Discrete_DpmTable *table)
1662{
1663        uint32_t count;
1664        uint8_t index;
1665        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1666        struct phm_ppt_v1_information *table_info =
1667                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1668        struct phm_ppt_v1_voltage_lookup_table *lookup_table =
1669                        table_info->vddc_lookup_table;
1670        /* tables is already swapped, so in order to use the value from it,
1671         * we need to swap it back.
1672         * We are populating vddc CAC data to BapmVddc table
1673         * in split and merged mode
1674         */
1675        for( count = 0; count<lookup_table->count; count++) {
1676                index = fiji_get_voltage_index(lookup_table,
1677                                data->vddc_voltage_table.entries[count].value);
1678                table->BapmVddcVidLoSidd[count] = (uint8_t) ((6200 -
1679                                (lookup_table->entries[index].us_cac_low *
1680                                                VOLTAGE_SCALE)) / 25);
1681                table->BapmVddcVidHiSidd[count] = (uint8_t) ((6200 -
1682                                (lookup_table->entries[index].us_cac_high *
1683                                                VOLTAGE_SCALE)) / 25);
1684        }
1685
1686        return 0;
1687}
1688
1689/**
1690* Preparation of voltage tables for SMC.
1691*
1692* @param    hwmgr   the address of the hardware manager
1693* @param    table   the SMC DPM table structure to be populated
1694* @return   always  0
1695*/
1696
1697int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
1698                struct SMU73_Discrete_DpmTable *table)
1699{
1700        int result;
1701
1702        result = fiji_populate_cac_table(hwmgr, table);
1703        PP_ASSERT_WITH_CODE(0 == result,
1704                        "can not populate CAC voltage tables to SMC",
1705                        return -EINVAL);
1706
1707        return 0;
1708}
1709
1710static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr,
1711                struct SMU73_Discrete_Ulv *state)
1712{
1713        int result = 0;
1714        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1715        struct phm_ppt_v1_information *table_info =
1716                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1717
1718        state->CcPwrDynRm = 0;
1719        state->CcPwrDynRm1 = 0;
1720
1721        state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
1722        state->VddcOffsetVid = (uint8_t)( table_info->us_ulv_voltage_offset *
1723                        VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1 );
1724
1725        state->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1;
1726
1727        if (!result) {
1728                CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
1729                CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
1730                CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
1731        }
1732        return result;
1733}
1734
1735static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr,
1736                struct SMU73_Discrete_DpmTable *table)
1737{
1738        return fiji_populate_ulv_level(hwmgr, &table->Ulv);
1739}
1740
1741static int32_t fiji_get_dpm_level_enable_mask_value(
1742                struct fiji_single_dpm_table* dpm_table)
1743{
1744        int32_t i;
1745        int32_t mask = 0;
1746
1747        for (i = dpm_table->count; i > 0; i--) {
1748                mask = mask << 1;
1749                if (dpm_table->dpm_levels[i - 1].enabled)
1750                        mask |= 0x1;
1751                else
1752                        mask &= 0xFFFFFFFE;
1753        }
1754        return mask;
1755}
1756
1757static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr,
1758                struct SMU73_Discrete_DpmTable *table)
1759{
1760        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1761        struct fiji_dpm_table *dpm_table = &data->dpm_table;
1762        int i;
1763
1764        /* Index (dpm_table->pcie_speed_table.count)
1765         * is reserved for PCIE boot level. */
1766        for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
1767                table->LinkLevel[i].PcieGenSpeed  =
1768                                (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
1769                table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
1770                                dpm_table->pcie_speed_table.dpm_levels[i].param1);
1771                table->LinkLevel[i].EnabledForActivity = 1;
1772                table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
1773                table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
1774                table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
1775        }
1776
1777        data->smc_state_table.LinkLevelCount =
1778                        (uint8_t)dpm_table->pcie_speed_table.count;
1779        data->dpm_level_enable_mask.pcie_dpm_enable_mask =
1780                        fiji_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
1781
1782        return 0;
1783}
1784
1785/**
1786* Calculates the SCLK dividers using the provided engine clock
1787*
1788* @param    hwmgr  the address of the hardware manager
1789* @param    clock  the engine clock to use to populate the structure
1790* @param    sclk   the SMC SCLK structure to be populated
1791*/
1792static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr,
1793                uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk)
1794{
1795        const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1796        struct pp_atomctrl_clock_dividers_vi dividers;
1797        uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
1798        uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
1799        uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
1800        uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
1801        uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
1802        uint32_t ref_clock;
1803        uint32_t ref_divider;
1804        uint32_t fbdiv;
1805        int result;
1806
1807        /* get the engine clock dividers for this clock value */
1808        result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock,  &dividers);
1809
1810        PP_ASSERT_WITH_CODE(result == 0,
1811                        "Error retrieving Engine Clock dividers from VBIOS.",
1812                        return result);
1813
1814        /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
1815        ref_clock = atomctrl_get_reference_clock(hwmgr);
1816        ref_divider = 1 + dividers.uc_pll_ref_div;
1817
1818        /* low 14 bits is fraction and high 12 bits is divider */
1819        fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
1820
1821        /* SPLL_FUNC_CNTL setup */
1822        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1823                        SPLL_REF_DIV, dividers.uc_pll_ref_div);
1824        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1825                        SPLL_PDIV_A,  dividers.uc_pll_post_div);
1826
1827        /* SPLL_FUNC_CNTL_3 setup*/
1828        spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
1829                        SPLL_FB_DIV, fbdiv);
1830
1831        /* set to use fractional accumulation*/
1832        spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
1833                        SPLL_DITHEN, 1);
1834
1835        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1836                                PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
1837                struct pp_atomctrl_internal_ss_info ssInfo;
1838
1839                uint32_t vco_freq = clock * dividers.uc_pll_post_div;
1840                if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
1841                                vco_freq, &ssInfo)) {
1842                        /*
1843                         * ss_info.speed_spectrum_percentage -- in unit of 0.01%
1844                         * ss_info.speed_spectrum_rate -- in unit of khz
1845                         *
1846                         * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
1847                         */
1848                        uint32_t clk_s = ref_clock * 5 /
1849                                        (ref_divider * ssInfo.speed_spectrum_rate);
1850                        /* clkv = 2 * D * fbdiv / NS */
1851                        uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage *
1852                                        fbdiv / (clk_s * 10000);
1853
1854                        cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
1855                                        CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
1856                        cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
1857                                        CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
1858                        cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
1859                                        CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
1860                }
1861        }
1862
1863        sclk->SclkFrequency        = clock;
1864        sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
1865        sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
1866        sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
1867        sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
1868        sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
1869
1870        return 0;
1871}
1872
1873static uint16_t fiji_find_closest_vddci(struct pp_hwmgr *hwmgr, uint16_t vddci)
1874{
1875        uint32_t  i;
1876        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1877        struct pp_atomctrl_voltage_table *vddci_table =
1878                        &(data->vddci_voltage_table);
1879
1880        for (i = 0; i < vddci_table->count; i++) {
1881                if (vddci_table->entries[i].value >= vddci)
1882                        return vddci_table->entries[i].value;
1883        }
1884
1885        PP_ASSERT_WITH_CODE(false,
1886                        "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
1887                        return vddci_table->entries[i-1].value);
1888}
1889
1890static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
1891                struct phm_ppt_v1_clock_voltage_dependency_table* dep_table,
1892                uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
1893{
1894        uint32_t i;
1895        uint16_t vddci;
1896        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1897
1898        *voltage = *mvdd = 0;
1899
1900        /* clock - voltage dependency table is empty table */
1901        if (dep_table->count == 0)
1902                return -EINVAL;
1903
1904        for (i = 0; i < dep_table->count; i++) {
1905                /* find first sclk bigger than request */
1906                if (dep_table->entries[i].clk >= clock) {
1907                        *voltage |= (dep_table->entries[i].vddc *
1908                                        VOLTAGE_SCALE) << VDDC_SHIFT;
1909                        if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
1910                                *voltage |= (data->vbios_boot_state.vddci_bootup_value *
1911                                                VOLTAGE_SCALE) << VDDCI_SHIFT;
1912                        else if (dep_table->entries[i].vddci)
1913                                *voltage |= (dep_table->entries[i].vddci *
1914                                                VOLTAGE_SCALE) << VDDCI_SHIFT;
1915                        else {
1916                                vddci = fiji_find_closest_vddci(hwmgr,
1917                                                (dep_table->entries[i].vddc -
1918                                                                (uint16_t)data->vddc_vddci_delta));
1919                                *voltage |= (vddci * VOLTAGE_SCALE) <<  VDDCI_SHIFT;
1920                        }
1921
1922                        if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
1923                                *mvdd = data->vbios_boot_state.mvdd_bootup_value *
1924                                        VOLTAGE_SCALE;
1925                        else if (dep_table->entries[i].mvdd)
1926                                *mvdd = (uint32_t) dep_table->entries[i].mvdd *
1927                                        VOLTAGE_SCALE;
1928
1929                        *voltage |= 1 << PHASES_SHIFT;
1930                        return 0;
1931                }
1932        }
1933
1934        /* sclk is bigger than max sclk in the dependence table */
1935        *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
1936
1937        if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
1938                *voltage |= (data->vbios_boot_state.vddci_bootup_value *
1939                                VOLTAGE_SCALE) << VDDCI_SHIFT;
1940        else if (dep_table->entries[i-1].vddci) {
1941                vddci = fiji_find_closest_vddci(hwmgr,
1942                                (dep_table->entries[i].vddc -
1943                                                (uint16_t)data->vddc_vddci_delta));
1944                *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
1945        }
1946
1947        if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
1948                *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
1949        else if (dep_table->entries[i].mvdd)
1950                *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
1951
1952        return 0;
1953}
1954
1955static uint8_t fiji_get_sleep_divider_id_from_clock(uint32_t clock,
1956                uint32_t clock_insr)
1957{
1958        uint8_t i;
1959        uint32_t temp;
1960        uint32_t min = max(clock_insr, (uint32_t)FIJI_MINIMUM_ENGINE_CLOCK);
1961
1962        PP_ASSERT_WITH_CODE((clock >= min), "Engine clock can't satisfy stutter requirement!", return 0);
1963        for (i = FIJI_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
1964                temp = clock >> i;
1965
1966                if (temp >= min || i == 0)
1967                        break;
1968        }
1969        return i;
1970}
1971/**
1972* Populates single SMC SCLK structure using the provided engine clock
1973*
1974* @param    hwmgr      the address of the hardware manager
1975* @param    clock the engine clock to use to populate the structure
1976* @param    sclk        the SMC SCLK structure to be populated
1977*/
1978
1979static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
1980                uint32_t clock, uint16_t sclk_al_threshold,
1981                struct SMU73_Discrete_GraphicsLevel *level)
1982{
1983        int result;
1984        /* PP_Clocks minClocks; */
1985        uint32_t threshold, mvdd;
1986        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1987        struct phm_ppt_v1_information *table_info =
1988                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
1989
1990        result = fiji_calculate_sclk_params(hwmgr, clock, level);
1991
1992        /* populate graphics levels */
1993        result = fiji_get_dependency_volt_by_clk(hwmgr,
1994                        table_info->vdd_dep_on_sclk, clock,
1995                        &level->MinVoltage, &mvdd);
1996        PP_ASSERT_WITH_CODE((0 == result),
1997                        "can not find VDDC voltage value for "
1998                        "VDDC engine clock dependency table",
1999                        return result);
2000
2001        level->SclkFrequency = clock;
2002        level->ActivityLevel = sclk_al_threshold;
2003        level->CcPwrDynRm = 0;
2004        level->CcPwrDynRm1 = 0;
2005        level->EnabledForActivity = 0;
2006        level->EnabledForThrottle = 1;
2007        level->UpHyst = 10;
2008        level->DownHyst = 0;
2009        level->VoltageDownHyst = 0;
2010        level->PowerThrottle = 0;
2011
2012        threshold = clock * data->fast_watermark_threshold / 100;
2013
2014
2015        data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr;
2016
2017        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
2018                level->DeepSleepDivId = fiji_get_sleep_divider_id_from_clock(clock,
2019                                                                hwmgr->display_config.min_core_set_clock_in_sr);
2020
2021
2022        /* Default to slow, highest DPM level will be
2023         * set to PPSMC_DISPLAY_WATERMARK_LOW later.
2024         */
2025        level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2026
2027        CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
2028        CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
2029        CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
2030        CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
2031        CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
2032        CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
2033        CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
2034        CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
2035        CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
2036
2037        return 0;
2038}
2039/**
2040* Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2041*
2042* @param    hwmgr      the address of the hardware manager
2043*/
2044static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
2045{
2046        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2047        struct fiji_dpm_table *dpm_table = &data->dpm_table;
2048        struct phm_ppt_v1_information *table_info =
2049                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2050        struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
2051        uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
2052        int result = 0;
2053        uint32_t array = data->dpm_table_start +
2054                        offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
2055        uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
2056                        SMU73_MAX_LEVELS_GRAPHICS;
2057        struct SMU73_Discrete_GraphicsLevel *levels =
2058                        data->smc_state_table.GraphicsLevel;
2059        uint32_t i, max_entry;
2060        uint8_t hightest_pcie_level_enabled = 0,
2061                        lowest_pcie_level_enabled = 0,
2062                        mid_pcie_level_enabled = 0,
2063                        count = 0;
2064
2065        for (i = 0; i < dpm_table->sclk_table.count; i++) {
2066                result = fiji_populate_single_graphic_level(hwmgr,
2067                                dpm_table->sclk_table.dpm_levels[i].value,
2068                                (uint16_t)data->activity_target[i],
2069                                &levels[i]);
2070                if (result)
2071                        return result;
2072
2073                /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2074                if (i > 1)
2075                        levels[i].DeepSleepDivId = 0;
2076        }
2077
2078        /* Only enable level 0 for now.*/
2079        levels[0].EnabledForActivity = 1;
2080
2081        /* set highest level watermark to high */
2082        levels[dpm_table->sclk_table.count - 1].DisplayWatermark =
2083                        PPSMC_DISPLAY_WATERMARK_HIGH;
2084
2085        data->smc_state_table.GraphicsDpmLevelCount =
2086                        (uint8_t)dpm_table->sclk_table.count;
2087        data->dpm_level_enable_mask.sclk_dpm_enable_mask =
2088                        fiji_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
2089
2090        if (pcie_table != NULL) {
2091                PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
2092                                "There must be 1 or more PCIE levels defined in PPTable.",
2093                                return -EINVAL);
2094                max_entry = pcie_entry_cnt - 1;
2095                for (i = 0; i < dpm_table->sclk_table.count; i++)
2096                        levels[i].pcieDpmLevel =
2097                                        (uint8_t) ((i < max_entry)? i : max_entry);
2098        } else {
2099                while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
2100                                ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2101                                                (1 << (hightest_pcie_level_enabled + 1))) != 0 ))
2102                        hightest_pcie_level_enabled++;
2103
2104                while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
2105                                ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2106                                                (1 << lowest_pcie_level_enabled)) == 0 ))
2107                        lowest_pcie_level_enabled++;
2108
2109                while ((count < hightest_pcie_level_enabled) &&
2110                                ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2111                                                (1 << (lowest_pcie_level_enabled + 1 + count))) == 0 ))
2112                        count++;
2113
2114                mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1+ count) <
2115                                hightest_pcie_level_enabled?
2116                                                (lowest_pcie_level_enabled + 1 + count) :
2117                                                hightest_pcie_level_enabled;
2118
2119                /* set pcieDpmLevel to hightest_pcie_level_enabled */
2120                for(i = 2; i < dpm_table->sclk_table.count; i++)
2121                        levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
2122
2123                /* set pcieDpmLevel to lowest_pcie_level_enabled */
2124                levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
2125
2126                /* set pcieDpmLevel to mid_pcie_level_enabled */
2127                levels[1].pcieDpmLevel = mid_pcie_level_enabled;
2128        }
2129        /* level count will send to smc once at init smc table and never change */
2130        result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
2131                        (uint32_t)array_size, data->sram_end);
2132
2133        return result;
2134}
2135
2136/**
2137 * MCLK Frequency Ratio
2138 * SEQ_CG_RESP  Bit[31:24] - 0x0
2139 * Bit[27:24] \96 DDR3 Frequency ratio
2140 * 0x0 <= 100MHz,       450 < 0x8 <= 500MHz
2141 * 100 < 0x1 <= 150MHz,       500 < 0x9 <= 550MHz
2142 * 150 < 0x2 <= 200MHz,       550 < 0xA <= 600MHz
2143 * 200 < 0x3 <= 250MHz,       600 < 0xB <= 650MHz
2144 * 250 < 0x4 <= 300MHz,       650 < 0xC <= 700MHz
2145 * 300 < 0x5 <= 350MHz,       700 < 0xD <= 750MHz
2146 * 350 < 0x6 <= 400MHz,       750 < 0xE <= 800MHz
2147 * 400 < 0x7 <= 450MHz,       800 < 0xF
2148 */
2149static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock)
2150{
2151        if (mem_clock <= 10000) return 0x0;
2152        if (mem_clock <= 15000) return 0x1;
2153        if (mem_clock <= 20000) return 0x2;
2154        if (mem_clock <= 25000) return 0x3;
2155        if (mem_clock <= 30000) return 0x4;
2156        if (mem_clock <= 35000) return 0x5;
2157        if (mem_clock <= 40000) return 0x6;
2158        if (mem_clock <= 45000) return 0x7;
2159        if (mem_clock <= 50000) return 0x8;
2160        if (mem_clock <= 55000) return 0x9;
2161        if (mem_clock <= 60000) return 0xa;
2162        if (mem_clock <= 65000) return 0xb;
2163        if (mem_clock <= 70000) return 0xc;
2164        if (mem_clock <= 75000) return 0xd;
2165        if (mem_clock <= 80000) return 0xe;
2166        /* mem_clock > 800MHz */
2167        return 0xf;
2168}
2169
2170/**
2171* Populates the SMC MCLK structure using the provided memory clock
2172*
2173* @param    hwmgr   the address of the hardware manager
2174* @param    clock   the memory clock to use to populate the structure
2175* @param    sclk    the SMC SCLK structure to be populated
2176*/
2177static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr,
2178    uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk)
2179{
2180        struct pp_atomctrl_memory_clock_param mem_param;
2181        int result;
2182
2183        result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param);
2184        PP_ASSERT_WITH_CODE((0 == result),
2185                        "Failed to get Memory PLL Dividers.",);
2186
2187        /* Save the result data to outpupt memory level structure */
2188        mclk->MclkFrequency   = clock;
2189        mclk->MclkDivider     = (uint8_t)mem_param.mpll_post_divider;
2190        mclk->FreqRange       = fiji_get_mclk_frequency_ratio(clock);
2191
2192        return result;
2193}
2194
2195static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr,
2196                uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level)
2197{
2198        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2199        struct phm_ppt_v1_information *table_info =
2200                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2201        int result = 0;
2202
2203        if (table_info->vdd_dep_on_mclk) {
2204                result = fiji_get_dependency_volt_by_clk(hwmgr,
2205                                table_info->vdd_dep_on_mclk, clock,
2206                                &mem_level->MinVoltage, &mem_level->MinMvdd);
2207                PP_ASSERT_WITH_CODE((0 == result),
2208                                "can not find MinVddc voltage value from memory "
2209                                "VDDC voltage dependency table", return result);
2210        }
2211
2212        mem_level->EnabledForThrottle = 1;
2213        mem_level->EnabledForActivity = 0;
2214        mem_level->UpHyst = 0;
2215        mem_level->DownHyst = 100;
2216        mem_level->VoltageDownHyst = 0;
2217        mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
2218        mem_level->StutterEnable = false;
2219
2220        mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2221
2222        /* enable stutter mode if all the follow condition applied
2223         * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
2224         * &(data->DisplayTiming.numExistingDisplays));
2225         */
2226        data->display_timing.num_existing_displays = 1;
2227
2228        if ((data->mclk_stutter_mode_threshold) &&
2229                (clock <= data->mclk_stutter_mode_threshold) &&
2230                (!data->is_uvd_enabled) &&
2231                (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
2232                                STUTTER_ENABLE) & 0x1))
2233                mem_level->StutterEnable = true;
2234
2235        result = fiji_calculate_mclk_params(hwmgr, clock, mem_level);
2236        if (!result) {
2237                CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
2238                CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
2239                CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
2240                CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
2241        }
2242        return result;
2243}
2244
2245/**
2246* Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2247*
2248* @param    hwmgr      the address of the hardware manager
2249*/
2250static int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
2251{
2252        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2253        struct fiji_dpm_table *dpm_table = &data->dpm_table;
2254        int result;
2255        /* populate MCLK dpm table to SMU7 */
2256        uint32_t array = data->dpm_table_start +
2257                        offsetof(SMU73_Discrete_DpmTable, MemoryLevel);
2258        uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) *
2259                        SMU73_MAX_LEVELS_MEMORY;
2260        struct SMU73_Discrete_MemoryLevel *levels =
2261                        data->smc_state_table.MemoryLevel;
2262        uint32_t i;
2263
2264        for (i = 0; i < dpm_table->mclk_table.count; i++) {
2265                PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
2266                                "can not populate memory level as memory clock is zero",
2267                                return -EINVAL);
2268                result = fiji_populate_single_memory_level(hwmgr,
2269                                dpm_table->mclk_table.dpm_levels[i].value,
2270                                &levels[i]);
2271                if (result)
2272                        return result;
2273        }
2274
2275        /* Only enable level 0 for now. */
2276        levels[0].EnabledForActivity = 1;
2277
2278        /* in order to prevent MC activity from stutter mode to push DPM up.
2279         * the UVD change complements this by putting the MCLK in
2280         * a higher state by default such that we are not effected by
2281         * up threshold or and MCLK DPM latency.
2282         */
2283        levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target;
2284        CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
2285
2286        data->smc_state_table.MemoryDpmLevelCount =
2287                        (uint8_t)dpm_table->mclk_table.count;
2288        data->dpm_level_enable_mask.mclk_dpm_enable_mask =
2289                        fiji_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
2290        /* set highest level watermark to high */
2291        levels[dpm_table->mclk_table.count - 1].DisplayWatermark =
2292                        PPSMC_DISPLAY_WATERMARK_HIGH;
2293
2294        /* level count will send to smc once at init smc table and never change */
2295        result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
2296                        (uint32_t)array_size, data->sram_end);
2297
2298        return result;
2299}
2300
2301/**
2302* Populates the SMC MVDD structure using the provided memory clock.
2303*
2304* @param    hwmgr      the address of the hardware manager
2305* @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
2306* @param    voltage     the SMC VOLTAGE structure to be populated
2307*/
2308int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr,
2309                uint32_t mclk, SMIO_Pattern *smio_pat)
2310{
2311        const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2312        struct phm_ppt_v1_information *table_info =
2313                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2314        uint32_t i = 0;
2315
2316        if (FIJI_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
2317                /* find mvdd value which clock is more than request */
2318                for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
2319                        if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
2320                                smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
2321                                break;
2322                        }
2323                }
2324                PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
2325                                "MVDD Voltage is outside the supported range.",
2326                                return -EINVAL);
2327        } else
2328                return -EINVAL;
2329
2330        return 0;
2331}
2332
2333static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
2334                SMU73_Discrete_DpmTable *table)
2335{
2336        int result = 0;
2337        const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2338        struct phm_ppt_v1_information *table_info =
2339                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2340        struct pp_atomctrl_clock_dividers_vi dividers;
2341        SMIO_Pattern vol_level;
2342        uint32_t mvdd;
2343        uint16_t us_mvdd;
2344        uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
2345        uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
2346
2347        table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
2348
2349        if (!data->sclk_dpm_key_disabled) {
2350                /* Get MinVoltage and Frequency from DPM0,
2351                 * already converted to SMC_UL */
2352                table->ACPILevel.SclkFrequency =
2353                                data->dpm_table.sclk_table.dpm_levels[0].value;
2354                result = fiji_get_dependency_volt_by_clk(hwmgr,
2355                                table_info->vdd_dep_on_sclk,
2356                                table->ACPILevel.SclkFrequency,
2357                                &table->ACPILevel.MinVoltage, &mvdd);
2358                PP_ASSERT_WITH_CODE((0 == result),
2359                                "Cannot find ACPI VDDC voltage value "
2360                                "in Clock Dependency Table",);
2361        } else {
2362                table->ACPILevel.SclkFrequency =
2363                                data->vbios_boot_state.sclk_bootup_value;
2364                table->ACPILevel.MinVoltage =
2365                                data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE;
2366        }
2367
2368        /* get the engine clock dividers for this clock value */
2369        result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
2370                        table->ACPILevel.SclkFrequency,  &dividers);
2371        PP_ASSERT_WITH_CODE(result == 0,
2372                        "Error retrieving Engine Clock dividers from VBIOS.",
2373                        return result);
2374
2375        table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
2376        table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2377        table->ACPILevel.DeepSleepDivId = 0;
2378
2379        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
2380                        SPLL_PWRON, 0);
2381        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
2382                        SPLL_RESET, 1);
2383        spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
2384                        SCLK_MUX_SEL, 4);
2385
2386        table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
2387        table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
2388        table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
2389        table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
2390        table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
2391        table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
2392        table->ACPILevel.CcPwrDynRm = 0;
2393        table->ACPILevel.CcPwrDynRm1 = 0;
2394
2395        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
2396        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
2397        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
2398        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
2399        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
2400        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
2401        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
2402        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
2403        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
2404        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
2405        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
2406
2407        if (!data->mclk_dpm_key_disabled) {
2408                /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
2409                table->MemoryACPILevel.MclkFrequency =
2410                                data->dpm_table.mclk_table.dpm_levels[0].value;
2411                result = fiji_get_dependency_volt_by_clk(hwmgr,
2412                                table_info->vdd_dep_on_mclk,
2413                                table->MemoryACPILevel.MclkFrequency,
2414                                &table->MemoryACPILevel.MinVoltage, &mvdd);
2415                PP_ASSERT_WITH_CODE((0 == result),
2416                                "Cannot find ACPI VDDCI voltage value "
2417                                "in Clock Dependency Table",);
2418        } else {
2419                table->MemoryACPILevel.MclkFrequency =
2420                                data->vbios_boot_state.mclk_bootup_value;
2421                table->MemoryACPILevel.MinVoltage =
2422                                data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE;
2423        }
2424
2425        us_mvdd = 0;
2426        if ((FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
2427                        (data->mclk_dpm_key_disabled))
2428                us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
2429        else {
2430                if (!fiji_populate_mvdd_value(hwmgr,
2431                                data->dpm_table.mclk_table.dpm_levels[0].value,
2432                                &vol_level))
2433                        us_mvdd = vol_level.Voltage;
2434        }
2435
2436        table->MemoryACPILevel.MinMvdd =
2437                        PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE);
2438
2439        table->MemoryACPILevel.EnabledForThrottle = 0;
2440        table->MemoryACPILevel.EnabledForActivity = 0;
2441        table->MemoryACPILevel.UpHyst = 0;
2442        table->MemoryACPILevel.DownHyst = 100;
2443        table->MemoryACPILevel.VoltageDownHyst = 0;
2444        table->MemoryACPILevel.ActivityLevel =
2445                        PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
2446
2447        table->MemoryACPILevel.StutterEnable = false;
2448        CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
2449        CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
2450
2451        return result;
2452}
2453
2454static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
2455                SMU73_Discrete_DpmTable *table)
2456{
2457        int result = -EINVAL;
2458        uint8_t count;
2459        struct pp_atomctrl_clock_dividers_vi dividers;
2460        struct phm_ppt_v1_information *table_info =
2461                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2462        struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2463                        table_info->mm_dep_table;
2464        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2465
2466        table->VceLevelCount = (uint8_t)(mm_table->count);
2467        table->VceBootLevel = 0;
2468
2469        for(count = 0; count < table->VceLevelCount; count++) {
2470                table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
2471                table->VceLevel[count].MinVoltage = 0;
2472                table->VceLevel[count].MinVoltage |=
2473                                (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
2474                table->VceLevel[count].MinVoltage |=
2475                                ((mm_table->entries[count].vddc - data->vddc_vddci_delta) *
2476                                                VOLTAGE_SCALE) << VDDCI_SHIFT;
2477                table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2478
2479                /*retrieve divider value for VBIOS */
2480                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2481                                table->VceLevel[count].Frequency, &dividers);
2482                PP_ASSERT_WITH_CODE((0 == result),
2483                                "can not find divide id for VCE engine clock",
2484                                return result);
2485
2486                table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
2487
2488                CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
2489                CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
2490        }
2491        return result;
2492}
2493
2494static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
2495                SMU73_Discrete_DpmTable *table)
2496{
2497        int result = -EINVAL;
2498        uint8_t count;
2499        struct pp_atomctrl_clock_dividers_vi dividers;
2500        struct phm_ppt_v1_information *table_info =
2501                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2502        struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2503                        table_info->mm_dep_table;
2504        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2505
2506        table->AcpLevelCount = (uint8_t)(mm_table->count);
2507        table->AcpBootLevel = 0;
2508
2509        for (count = 0; count < table->AcpLevelCount; count++) {
2510                table->AcpLevel[count].Frequency = mm_table->entries[count].aclk;
2511                table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
2512                                VOLTAGE_SCALE) << VDDC_SHIFT;
2513                table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
2514                                data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
2515                table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2516
2517                /* retrieve divider value for VBIOS */
2518                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2519                                table->AcpLevel[count].Frequency, &dividers);
2520                PP_ASSERT_WITH_CODE((0 == result),
2521                                "can not find divide id for engine clock", return result);
2522
2523                table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
2524
2525                CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
2526                CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage);
2527        }
2528        return result;
2529}
2530
2531static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
2532                SMU73_Discrete_DpmTable *table)
2533{
2534        int result = -EINVAL;
2535        uint8_t count;
2536        struct pp_atomctrl_clock_dividers_vi dividers;
2537        struct phm_ppt_v1_information *table_info =
2538                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2539        struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2540                        table_info->mm_dep_table;
2541        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2542
2543        table->SamuBootLevel = 0;
2544        table->SamuLevelCount = (uint8_t)(mm_table->count);
2545
2546        for (count = 0; count < table->SamuLevelCount; count++) {
2547                /* not sure whether we need evclk or not */
2548                table->SamuLevel[count].MinVoltage = 0;
2549                table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
2550                table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
2551                                VOLTAGE_SCALE) << VDDC_SHIFT;
2552                table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
2553                                data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
2554                table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2555
2556                /* retrieve divider value for VBIOS */
2557                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2558                                table->SamuLevel[count].Frequency, &dividers);
2559                PP_ASSERT_WITH_CODE((0 == result),
2560                                "can not find divide id for samu clock", return result);
2561
2562                table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
2563
2564                CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
2565                CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
2566        }
2567        return result;
2568}
2569
2570static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
2571                int32_t eng_clock, int32_t mem_clock,
2572                struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs)
2573{
2574        uint32_t dram_timing;
2575        uint32_t dram_timing2;
2576        uint32_t burstTime;
2577        ULONG state, trrds, trrdl;
2578        int result;
2579
2580        result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
2581                        eng_clock, mem_clock);
2582        PP_ASSERT_WITH_CODE(result == 0,
2583                        "Error calling VBIOS to set DRAM_TIMING.", return result);
2584
2585        dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
2586        dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
2587        burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME);
2588
2589        state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0);
2590        trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0);
2591        trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0);
2592
2593        arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
2594        arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
2595        arb_regs->McArbBurstTime   = (uint8_t)burstTime;
2596        arb_regs->TRRDS            = (uint8_t)trrds;
2597        arb_regs->TRRDL            = (uint8_t)trrdl;
2598
2599        return 0;
2600}
2601
2602static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
2603{
2604        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2605        struct SMU73_Discrete_MCArbDramTimingTable arb_regs;
2606        uint32_t i, j;
2607        int result = 0;
2608
2609        for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
2610                for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
2611                        result = fiji_populate_memory_timing_parameters(hwmgr,
2612                                        data->dpm_table.sclk_table.dpm_levels[i].value,
2613                                        data->dpm_table.mclk_table.dpm_levels[j].value,
2614                                        &arb_regs.entries[i][j]);
2615                        if (result)
2616                                break;
2617                }
2618        }
2619
2620        if (!result)
2621                result = fiji_copy_bytes_to_smc(
2622                                hwmgr->smumgr,
2623                                data->arb_table_start,
2624                                (uint8_t *)&arb_regs,
2625                                sizeof(SMU73_Discrete_MCArbDramTimingTable),
2626                                data->sram_end);
2627        return result;
2628}
2629
2630static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
2631                struct SMU73_Discrete_DpmTable *table)
2632{
2633        int result = -EINVAL;
2634        uint8_t count;
2635        struct pp_atomctrl_clock_dividers_vi dividers;
2636        struct phm_ppt_v1_information *table_info =
2637                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2638        struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2639                        table_info->mm_dep_table;
2640        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2641
2642        table->UvdLevelCount = (uint8_t)(mm_table->count);
2643        table->UvdBootLevel = 0;
2644
2645        for (count = 0; count < table->UvdLevelCount; count++) {
2646                table->UvdLevel[count].MinVoltage = 0;
2647                table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
2648                table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
2649                table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
2650                                VOLTAGE_SCALE) << VDDC_SHIFT;
2651                table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
2652                                data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
2653                table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2654
2655                /* retrieve divider value for VBIOS */
2656                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2657                                table->UvdLevel[count].VclkFrequency, &dividers);
2658                PP_ASSERT_WITH_CODE((0 == result),
2659                                "can not find divide id for Vclk clock", return result);
2660
2661                table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
2662
2663                result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2664                                table->UvdLevel[count].DclkFrequency, &dividers);
2665                PP_ASSERT_WITH_CODE((0 == result),
2666                                "can not find divide id for Dclk clock", return result);
2667
2668                table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
2669
2670                CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
2671                CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
2672                CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
2673
2674        }
2675        return result;
2676}
2677
2678static int fiji_find_boot_level(struct fiji_single_dpm_table *table,
2679                uint32_t value, uint32_t *boot_level)
2680{
2681        int result = -EINVAL;
2682        uint32_t i;
2683
2684        for (i = 0; i < table->count; i++) {
2685                if (value == table->dpm_levels[i].value) {
2686                        *boot_level = i;
2687                        result = 0;
2688                }
2689        }
2690        return result;
2691}
2692
2693static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
2694                struct SMU73_Discrete_DpmTable *table)
2695{
2696        int result = 0;
2697        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2698
2699        table->GraphicsBootLevel = 0;
2700        table->MemoryBootLevel = 0;
2701
2702        /* find boot level from dpm table */
2703        result = fiji_find_boot_level(&(data->dpm_table.sclk_table),
2704                        data->vbios_boot_state.sclk_bootup_value,
2705                        (uint32_t *)&(table->GraphicsBootLevel));
2706
2707        result = fiji_find_boot_level(&(data->dpm_table.mclk_table),
2708                        data->vbios_boot_state.mclk_bootup_value,
2709                        (uint32_t *)&(table->MemoryBootLevel));
2710
2711        table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
2712                        VOLTAGE_SCALE;
2713        table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
2714                        VOLTAGE_SCALE;
2715        table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
2716                        VOLTAGE_SCALE;
2717
2718        CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
2719        CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
2720        CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
2721
2722        return 0;
2723}
2724
2725static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
2726{
2727        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2728        struct phm_ppt_v1_information *table_info =
2729                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2730        uint8_t count, level;
2731
2732        count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
2733        for (level = 0; level < count; level++) {
2734                if(table_info->vdd_dep_on_sclk->entries[level].clk >=
2735                                data->vbios_boot_state.sclk_bootup_value) {
2736                        data->smc_state_table.GraphicsBootLevel = level;
2737                        break;
2738                }
2739        }
2740
2741        count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
2742        for (level = 0; level < count; level++) {
2743                if(table_info->vdd_dep_on_mclk->entries[level].clk >=
2744                                data->vbios_boot_state.mclk_bootup_value) {
2745                        data->smc_state_table.MemoryBootLevel = level;
2746                        break;
2747                }
2748        }
2749
2750        return 0;
2751}
2752
2753static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
2754{
2755        uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
2756                        volt_with_cks, value;
2757        uint16_t clock_freq_u16;
2758        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2759        uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
2760                        volt_offset = 0;
2761        struct phm_ppt_v1_information *table_info =
2762                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2763        struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
2764                        table_info->vdd_dep_on_sclk;
2765
2766        stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
2767
2768        /* Read SMU_Eefuse to read and calculate RO and determine
2769         * if the part is SS or FF. if RO >= 1660MHz, part is FF.
2770         */
2771        efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2772                        ixSMU_EFUSE_0 + (146 * 4));
2773        efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2774                        ixSMU_EFUSE_0 + (148 * 4));
2775        efuse &= 0xFF000000;
2776        efuse = efuse >> 24;
2777        efuse2 &= 0xF;
2778
2779        if (efuse2 == 1)
2780                ro = (2300 - 1350) * efuse / 255 + 1350;
2781        else
2782                ro = (2500 - 1000) * efuse / 255 + 1000;
2783
2784        if (ro >= 1660)
2785                type = 0;
2786        else
2787                type = 1;
2788
2789        /* Populate Stretch amount */
2790        data->smc_state_table.ClockStretcherAmount = stretch_amount;
2791
2792        /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
2793        for (i = 0; i < sclk_table->count; i++) {
2794                data->smc_state_table.Sclk_CKS_masterEn0_7 |=
2795                                sclk_table->entries[i].cks_enable << i;
2796                volt_without_cks = (uint32_t)((14041 *
2797                        (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
2798                        (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
2799                volt_with_cks = (uint32_t)((13946 *
2800                        (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
2801                        (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
2802                if (volt_without_cks >= volt_with_cks)
2803                        volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
2804                                        sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
2805                data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
2806        }
2807
2808        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2809                        STRETCH_ENABLE, 0x0);
2810        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2811                        masterReset, 0x1);
2812        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2813                        staticEnable, 0x1);
2814        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2815                        masterReset, 0x0);
2816
2817        /* Populate CKS Lookup Table */
2818        if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
2819                stretch_amount2 = 0;
2820        else if (stretch_amount == 3 || stretch_amount == 4)
2821                stretch_amount2 = 1;
2822        else {
2823                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2824                                PHM_PlatformCaps_ClockStretcher);
2825                PP_ASSERT_WITH_CODE(false,
2826                                "Stretch Amount in PPTable not supported\n",
2827                                return -EINVAL);
2828        }
2829
2830        value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2831                        ixPWR_CKS_CNTL);
2832        value &= 0xFFC2FF87;
2833        data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
2834                        fiji_clock_stretcher_lookup_table[stretch_amount2][0];
2835        data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
2836                        fiji_clock_stretcher_lookup_table[stretch_amount2][1];
2837        clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(data->smc_state_table.
2838                        GraphicsLevel[data->smc_state_table.GraphicsDpmLevelCount - 1].
2839                        SclkFrequency) / 100);
2840        if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] <
2841                        clock_freq_u16 &&
2842            fiji_clock_stretcher_lookup_table[stretch_amount2][1] >
2843                        clock_freq_u16) {
2844                /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
2845                value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
2846                /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
2847                value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
2848                /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
2849                value |= (fiji_clock_stretch_amount_conversion
2850                                [fiji_clock_stretcher_lookup_table[stretch_amount2][3]]
2851                                 [stretch_amount]) << 3;
2852        }
2853        CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
2854                        CKS_LOOKUPTableEntry[0].minFreq);
2855        CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
2856                        CKS_LOOKUPTableEntry[0].maxFreq);
2857        data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
2858                        fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
2859        data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
2860                        (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
2861
2862        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2863                        ixPWR_CKS_CNTL, value);
2864
2865        /* Populate DDT Lookup Table */
2866        for (i = 0; i < 4; i++) {
2867                /* Assign the minimum and maximum VID stored
2868                 * in the last row of Clock Stretcher Voltage Table.
2869                 */
2870                data->smc_state_table.ClockStretcherDataTable.
2871                ClockStretcherDataTableEntry[i].minVID =
2872                                (uint8_t) fiji_clock_stretcher_ddt_table[type][i][2];
2873                data->smc_state_table.ClockStretcherDataTable.
2874                ClockStretcherDataTableEntry[i].maxVID =
2875                                (uint8_t) fiji_clock_stretcher_ddt_table[type][i][3];
2876                /* Loop through each SCLK and check the frequency
2877                 * to see if it lies within the frequency for clock stretcher.
2878                 */
2879                for (j = 0; j < data->smc_state_table.GraphicsDpmLevelCount; j++) {
2880                        cks_setting = 0;
2881                        clock_freq = PP_SMC_TO_HOST_UL(
2882                                        data->smc_state_table.GraphicsLevel[j].SclkFrequency);
2883                        /* Check the allowed frequency against the sclk level[j].
2884                         *  Sclk's endianness has already been converted,
2885                         *  and it's in 10Khz unit,
2886                         *  as opposed to Data table, which is in Mhz unit.
2887                         */
2888                        if (clock_freq >=
2889                                        (fiji_clock_stretcher_ddt_table[type][i][0]) * 100) {
2890                                cks_setting |= 0x2;
2891                                if (clock_freq <
2892                                                (fiji_clock_stretcher_ddt_table[type][i][1]) * 100)
2893                                        cks_setting |= 0x1;
2894                        }
2895                        data->smc_state_table.ClockStretcherDataTable.
2896                        ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
2897                }
2898                CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.
2899                                ClockStretcherDataTable.
2900                                ClockStretcherDataTableEntry[i].setting);
2901        }
2902
2903        value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
2904        value &= 0xFFFFFFFE;
2905        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
2906
2907        return 0;
2908}
2909
2910/**
2911* Populates the SMC VRConfig field in DPM table.
2912*
2913* @param    hwmgr   the address of the hardware manager
2914* @param    table   the SMC DPM table structure to be populated
2915* @return   always 0
2916*/
2917static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr,
2918                struct SMU73_Discrete_DpmTable *table)
2919{
2920        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2921        uint16_t config;
2922
2923        config = VR_MERGED_WITH_VDDC;
2924        table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
2925
2926        /* Set Vddc Voltage Controller */
2927        if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
2928                config = VR_SVI2_PLANE_1;
2929                table->VRConfig |= config;
2930        } else {
2931                PP_ASSERT_WITH_CODE(false,
2932                                "VDDC should be on SVI2 control in merged mode!",);
2933        }
2934        /* Set Vddci Voltage Controller */
2935        if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
2936                config = VR_SVI2_PLANE_2;  /* only in merged mode */
2937                table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
2938        } else if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
2939                config = VR_SMIO_PATTERN_1;
2940                table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
2941        } else {
2942                config = VR_STATIC_VOLTAGE;
2943                table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
2944        }
2945        /* Set Mvdd Voltage Controller */
2946        if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
2947                config = VR_SVI2_PLANE_2;
2948                table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
2949        } else if(FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
2950                config = VR_SMIO_PATTERN_2;
2951                table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
2952        } else {
2953                config = VR_STATIC_VOLTAGE;
2954                table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
2955        }
2956
2957        return 0;
2958}
2959
2960/**
2961* Initializes the SMC table and uploads it
2962*
2963* @param    hwmgr  the address of the powerplay hardware manager.
2964* @param    pInput  the pointer to input data (PowerState)
2965* @return   always 0
2966*/
2967static int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
2968{
2969        int result;
2970        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2971        struct phm_ppt_v1_information *table_info =
2972                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
2973        struct SMU73_Discrete_DpmTable *table = &(data->smc_state_table);
2974        const struct fiji_ulv_parm *ulv = &(data->ulv);
2975        uint8_t i;
2976        struct pp_atomctrl_gpio_pin_assignment gpio_pin;
2977
2978        result = fiji_setup_default_dpm_tables(hwmgr);
2979        PP_ASSERT_WITH_CODE(0 == result,
2980                        "Failed to setup default DPM tables!", return result);
2981
2982        if(FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control)
2983                fiji_populate_smc_voltage_tables(hwmgr, table);
2984
2985        table->SystemFlags = 0;
2986
2987        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2988                        PHM_PlatformCaps_AutomaticDCTransition))
2989                table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
2990
2991        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2992                        PHM_PlatformCaps_StepVddc))
2993                table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
2994
2995        if (data->is_memory_gddr5)
2996                table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
2997
2998        if (ulv->ulv_supported && table_info->us_ulv_voltage_offset) {
2999                result = fiji_populate_ulv_state(hwmgr, table);
3000                PP_ASSERT_WITH_CODE(0 == result,
3001                                "Failed to initialize ULV state!", return result);
3002                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3003                                ixCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
3004        }
3005
3006        result = fiji_populate_smc_link_level(hwmgr, table);
3007        PP_ASSERT_WITH_CODE(0 == result,
3008                        "Failed to initialize Link Level!", return result);
3009
3010        result = fiji_populate_all_graphic_levels(hwmgr);
3011        PP_ASSERT_WITH_CODE(0 == result,
3012                        "Failed to initialize Graphics Level!", return result);
3013
3014        result = fiji_populate_all_memory_levels(hwmgr);
3015        PP_ASSERT_WITH_CODE(0 == result,
3016                        "Failed to initialize Memory Level!", return result);
3017
3018        result = fiji_populate_smc_acpi_level(hwmgr, table);
3019        PP_ASSERT_WITH_CODE(0 == result,
3020                        "Failed to initialize ACPI Level!", return result);
3021
3022        result = fiji_populate_smc_vce_level(hwmgr, table);
3023        PP_ASSERT_WITH_CODE(0 == result,
3024                        "Failed to initialize VCE Level!", return result);
3025
3026        result = fiji_populate_smc_acp_level(hwmgr, table);
3027        PP_ASSERT_WITH_CODE(0 == result,
3028                        "Failed to initialize ACP Level!", return result);
3029
3030        result = fiji_populate_smc_samu_level(hwmgr, table);
3031        PP_ASSERT_WITH_CODE(0 == result,
3032                        "Failed to initialize SAMU Level!", return result);
3033
3034        /* Since only the initial state is completely set up at this point
3035         * (the other states are just copies of the boot state) we only
3036         * need to populate the  ARB settings for the initial state.
3037         */
3038        result = fiji_program_memory_timing_parameters(hwmgr);
3039        PP_ASSERT_WITH_CODE(0 == result,
3040                        "Failed to Write ARB settings for the initial state.", return result);
3041
3042        result = fiji_populate_smc_uvd_level(hwmgr, table);
3043        PP_ASSERT_WITH_CODE(0 == result,
3044                        "Failed to initialize UVD Level!", return result);
3045
3046        result = fiji_populate_smc_boot_level(hwmgr, table);
3047        PP_ASSERT_WITH_CODE(0 == result,
3048                        "Failed to initialize Boot Level!", return result);
3049
3050        result = fiji_populate_smc_initailial_state(hwmgr);
3051        PP_ASSERT_WITH_CODE(0 == result,
3052                        "Failed to initialize Boot State!", return result);
3053
3054        result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr);
3055        PP_ASSERT_WITH_CODE(0 == result,
3056                        "Failed to populate BAPM Parameters!", return result);
3057
3058        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3059                        PHM_PlatformCaps_ClockStretcher)) {
3060                result = fiji_populate_clock_stretcher_data_table(hwmgr);
3061                PP_ASSERT_WITH_CODE(0 == result,
3062                                "Failed to populate Clock Stretcher Data Table!",
3063                                return result);
3064        }
3065
3066        table->GraphicsVoltageChangeEnable  = 1;
3067        table->GraphicsThermThrottleEnable  = 1;
3068        table->GraphicsInterval = 1;
3069        table->VoltageInterval  = 1;
3070        table->ThermalInterval  = 1;
3071        table->TemperatureLimitHigh =
3072                        table_info->cac_dtp_table->usTargetOperatingTemp *
3073                        FIJI_Q88_FORMAT_CONVERSION_UNIT;
3074        table->TemperatureLimitLow  =
3075                        (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
3076                        FIJI_Q88_FORMAT_CONVERSION_UNIT;
3077        table->MemoryVoltageChangeEnable = 1;
3078        table->MemoryInterval = 1;
3079        table->VoltageResponseTime = 0;
3080        table->PhaseResponseTime = 0;
3081        table->MemoryThermThrottleEnable = 1;
3082        table->PCIeBootLinkLevel = 0;      /* 0:Gen1 1:Gen2 2:Gen3*/
3083        table->PCIeGenInterval = 1;
3084        table->VRConfig = 0;
3085
3086        result = fiji_populate_vr_config(hwmgr, table);
3087        PP_ASSERT_WITH_CODE(0 == result,
3088                        "Failed to populate VRConfig setting!", return result);
3089
3090        table->ThermGpio = 17;
3091        table->SclkStepSize = 0x4000;
3092
3093        if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
3094                table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
3095                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3096                                PHM_PlatformCaps_RegulatorHot);
3097        } else {
3098                table->VRHotGpio = FIJI_UNUSED_GPIO_PIN;
3099                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3100                                PHM_PlatformCaps_RegulatorHot);
3101        }
3102
3103        if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
3104                        &gpio_pin)) {
3105                table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
3106                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3107                                PHM_PlatformCaps_AutomaticDCTransition);
3108        } else {
3109                table->AcDcGpio = FIJI_UNUSED_GPIO_PIN;
3110                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3111                                PHM_PlatformCaps_AutomaticDCTransition);
3112        }
3113
3114        /* Thermal Output GPIO */
3115        if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
3116                        &gpio_pin)) {
3117                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3118                                PHM_PlatformCaps_ThermalOutGPIO);
3119
3120                table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
3121
3122                /* For porlarity read GPIOPAD_A with assigned Gpio pin
3123                 * since VBIOS will program this register to set 'inactive state',
3124                 * driver can then determine 'active state' from this and
3125                 * program SMU with correct polarity
3126                 */
3127                table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
3128                                (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
3129                table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
3130
3131                /* if required, combine VRHot/PCC with thermal out GPIO */
3132                if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3133                                PHM_PlatformCaps_RegulatorHot) &&
3134                        phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3135                                        PHM_PlatformCaps_CombinePCCWithThermalSignal))
3136                        table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
3137        } else {
3138                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3139                                PHM_PlatformCaps_ThermalOutGPIO);
3140                table->ThermOutGpio = 17;
3141                table->ThermOutPolarity = 1;
3142                table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
3143        }
3144
3145        for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++)
3146                table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
3147
3148        CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
3149        CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
3150        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
3151        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
3152        CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
3153        CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
3154        CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
3155        CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
3156        CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
3157
3158        /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3159        result = fiji_copy_bytes_to_smc(hwmgr->smumgr,
3160                        data->dpm_table_start +
3161                        offsetof(SMU73_Discrete_DpmTable, SystemFlags),
3162                        (uint8_t *)&(table->SystemFlags),
3163                        sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController),
3164                        data->sram_end);
3165        PP_ASSERT_WITH_CODE(0 == result,
3166                        "Failed to upload dpm data to SMC memory!", return result);
3167
3168        return 0;
3169}
3170
3171/**
3172* Initialize the ARB DRAM timing table's index field.
3173*
3174* @param    hwmgr  the address of the powerplay hardware manager.
3175* @return   always 0
3176*/
3177static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr)
3178{
3179        const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3180        uint32_t tmp;
3181        int result;
3182
3183        /* This is a read-modify-write on the first byte of the ARB table.
3184         * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
3185         * is the field 'current'.
3186         * This solution is ugly, but we never write the whole table only
3187         * individual fields in it.
3188         * In reality this field should not be in that structure
3189         * but in a soft register.
3190         */
3191        result = fiji_read_smc_sram_dword(hwmgr->smumgr,
3192                        data->arb_table_start, &tmp, data->sram_end);
3193
3194        if (result)
3195                return result;
3196
3197        tmp &= 0x00FFFFFF;
3198        tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
3199
3200        return fiji_write_smc_sram_dword(hwmgr->smumgr,
3201                        data->arb_table_start,  tmp, data->sram_end);
3202}
3203
3204static int fiji_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
3205{
3206        if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3207                        PHM_PlatformCaps_RegulatorHot))
3208                return smum_send_msg_to_smc(hwmgr->smumgr,
3209                                PPSMC_MSG_EnableVRHotGPIOInterrupt);
3210
3211        return 0;
3212}
3213
3214static int fiji_enable_sclk_control(struct pp_hwmgr *hwmgr)
3215{
3216        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
3217                        SCLK_PWRMGT_OFF, 0);
3218        return 0;
3219}
3220
3221static int fiji_enable_ulv(struct pp_hwmgr *hwmgr)
3222{
3223        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3224        struct fiji_ulv_parm *ulv = &(data->ulv);
3225
3226        if (ulv->ulv_supported)
3227                return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
3228
3229        return 0;
3230}
3231
3232static int fiji_disable_ulv(struct pp_hwmgr *hwmgr)
3233{
3234        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3235        struct fiji_ulv_parm *ulv = &(data->ulv);
3236
3237        if (ulv->ulv_supported)
3238                return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableULV);
3239
3240        return 0;
3241}
3242
3243static int fiji_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
3244{
3245        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3246                        PHM_PlatformCaps_SclkDeepSleep)) {
3247                if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
3248                        PP_ASSERT_WITH_CODE(false,
3249                                        "Attempt to enable Master Deep Sleep switch failed!",
3250                                        return -1);
3251        } else {
3252                if (smum_send_msg_to_smc(hwmgr->smumgr,
3253                                PPSMC_MSG_MASTER_DeepSleep_OFF)) {
3254                        PP_ASSERT_WITH_CODE(false,
3255                                        "Attempt to disable Master Deep Sleep switch failed!",
3256                                        return -1);
3257                }
3258        }
3259
3260        return 0;
3261}
3262
3263static int fiji_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
3264{
3265        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3266                        PHM_PlatformCaps_SclkDeepSleep)) {
3267                if (smum_send_msg_to_smc(hwmgr->smumgr,
3268                                PPSMC_MSG_MASTER_DeepSleep_OFF)) {
3269                        PP_ASSERT_WITH_CODE(false,
3270                                        "Attempt to disable Master Deep Sleep switch failed!",
3271                                        return -1);
3272                }
3273        }
3274
3275        return 0;
3276}
3277
3278static int fiji_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
3279{
3280        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3281        uint32_t   val, val0, val2;
3282        uint32_t   i, cpl_cntl, cpl_threshold, mc_threshold;
3283
3284        /* enable SCLK dpm */
3285        if(!data->sclk_dpm_key_disabled)
3286                PP_ASSERT_WITH_CODE(
3287                (0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
3288                "Failed to enable SCLK DPM during DPM Start Function!",
3289                return -1);
3290
3291        /* enable MCLK dpm */
3292        if(0 == data->mclk_dpm_key_disabled) {
3293                cpl_threshold = 0;
3294                mc_threshold = 0;
3295
3296                /* Read per MCD tile (0 - 7) */
3297                for (i = 0; i < 8; i++) {
3298                        PHM_WRITE_FIELD(hwmgr->device, MC_CONFIG_MCD, MC_RD_ENABLE, i);
3299                        val = cgs_read_register(hwmgr->device, mmMC_SEQ_RESERVE_0_S) & 0xf0000000;
3300                        if (0xf0000000 != val) {
3301                                /* count number of MCQ that has channel(s) enabled */
3302                                cpl_threshold++;
3303                                /* only harvest 3 or full 4 supported */
3304                                mc_threshold = val ? 3 : 4;
3305                        }
3306                }
3307                PP_ASSERT_WITH_CODE(0 != cpl_threshold,
3308                                "Number of MCQ is zero!", return -EINVAL;);
3309
3310                mc_threshold = ((mc_threshold & LCAC_MC0_CNTL__MC0_THRESHOLD_MASK) <<
3311                                LCAC_MC0_CNTL__MC0_THRESHOLD__SHIFT) |
3312                                                LCAC_MC0_CNTL__MC0_ENABLE_MASK;
3313                cpl_cntl = ((cpl_threshold & LCAC_CPL_CNTL__CPL_THRESHOLD_MASK) <<
3314                                LCAC_CPL_CNTL__CPL_THRESHOLD__SHIFT) |
3315                                                LCAC_CPL_CNTL__CPL_ENABLE_MASK;
3316                cpl_cntl = (cpl_cntl | (8 << LCAC_CPL_CNTL__CPL_BLOCK_ID__SHIFT));
3317                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3318                                ixLCAC_MC0_CNTL, mc_threshold);
3319                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3320                                ixLCAC_MC1_CNTL, mc_threshold);
3321                if (8 == cpl_threshold) {
3322                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3323                                        ixLCAC_MC2_CNTL, mc_threshold);
3324                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3325                                        ixLCAC_MC3_CNTL, mc_threshold);
3326                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3327                                        ixLCAC_MC4_CNTL, mc_threshold);
3328                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3329                                        ixLCAC_MC5_CNTL, mc_threshold);
3330                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3331                                        ixLCAC_MC6_CNTL, mc_threshold);
3332                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3333                                        ixLCAC_MC7_CNTL, mc_threshold);
3334                }
3335                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3336                                ixLCAC_CPL_CNTL, cpl_cntl);
3337
3338                udelay(5);
3339
3340                mc_threshold = mc_threshold |
3341                                (1 << LCAC_MC0_CNTL__MC0_SIGNAL_ID__SHIFT);
3342                cpl_cntl = cpl_cntl | (1 << LCAC_CPL_CNTL__CPL_SIGNAL_ID__SHIFT);
3343                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3344                                ixLCAC_MC0_CNTL, mc_threshold);
3345                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3346                                ixLCAC_MC1_CNTL, mc_threshold);
3347                if (8 == cpl_threshold) {
3348                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3349                                        ixLCAC_MC2_CNTL, mc_threshold);
3350                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3351                                        ixLCAC_MC3_CNTL, mc_threshold);
3352                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3353                                        ixLCAC_MC4_CNTL, mc_threshold);
3354                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3355                                        ixLCAC_MC5_CNTL, mc_threshold);
3356                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3357                                        ixLCAC_MC6_CNTL, mc_threshold);
3358                        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3359                                        ixLCAC_MC7_CNTL, mc_threshold);
3360                }
3361                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3362                                ixLCAC_CPL_CNTL, cpl_cntl);
3363
3364                /* Program CAC_EN per MCD (0-7) Tile */
3365                val0 = val = cgs_read_register(hwmgr->device, mmMC_CONFIG_MCD);
3366                val &= ~(MC_CONFIG_MCD__MCD0_WR_ENABLE_MASK |
3367                                MC_CONFIG_MCD__MCD1_WR_ENABLE_MASK |
3368                                MC_CONFIG_MCD__MCD2_WR_ENABLE_MASK |
3369                                MC_CONFIG_MCD__MCD3_WR_ENABLE_MASK |
3370                                MC_CONFIG_MCD__MCD4_WR_ENABLE_MASK |
3371                                MC_CONFIG_MCD__MCD5_WR_ENABLE_MASK |
3372                                MC_CONFIG_MCD__MCD6_WR_ENABLE_MASK |
3373                                MC_CONFIG_MCD__MCD7_WR_ENABLE_MASK |
3374                                MC_CONFIG_MCD__MC_RD_ENABLE_MASK);
3375
3376                for (i = 0; i < 8; i++) {
3377                        /* Enable MCD i Tile read & write */
3378                        val2  = (val | (i << MC_CONFIG_MCD__MC_RD_ENABLE__SHIFT) |
3379                                        (1 << i));
3380                        cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val2);
3381                        /* Enbale CAC_ON MCD i Tile */
3382                        val2 = cgs_read_register(hwmgr->device, mmMC_SEQ_CNTL);
3383                        val2 |= MC_SEQ_CNTL__CAC_EN_MASK;
3384                        cgs_write_register(hwmgr->device, mmMC_SEQ_CNTL, val2);
3385                }
3386                /* Set MC_CONFIG_MCD back to its default setting val0 */
3387                cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val0);
3388
3389                PP_ASSERT_WITH_CODE(
3390                                (0 == smum_send_msg_to_smc(hwmgr->smumgr,
3391                                                PPSMC_MSG_MCLKDPM_Enable)),
3392                                "Failed to enable MCLK DPM during DPM Start Function!",
3393                                return -1);
3394        }
3395        return 0;
3396}
3397
3398static int fiji_start_dpm(struct pp_hwmgr *hwmgr)
3399{
3400        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3401
3402        /*enable general power management */
3403        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3404                        GLOBAL_PWRMGT_EN, 1);
3405        /* enable sclk deep sleep */
3406        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
3407                        DYNAMIC_PM_EN, 1);
3408        /* prepare for PCIE DPM */
3409        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3410                        data->soft_regs_start + offsetof(SMU73_SoftRegisters,
3411                                        VoltageChangeTimeout), 0x1000);
3412        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
3413                        SWRST_COMMAND_1, RESETLC, 0x0);
3414
3415        PP_ASSERT_WITH_CODE(
3416                        (0 == smum_send_msg_to_smc(hwmgr->smumgr,
3417                                        PPSMC_MSG_Voltage_Cntl_Enable)),
3418                        "Failed to enable voltage DPM during DPM Start Function!",
3419                        return -1);
3420
3421        if (fiji_enable_sclk_mclk_dpm(hwmgr)) {
3422                printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
3423                return -1;
3424        }
3425
3426        /* enable PCIE dpm */
3427        if(!data->pcie_dpm_key_disabled) {
3428                PP_ASSERT_WITH_CODE(
3429                                (0 == smum_send_msg_to_smc(hwmgr->smumgr,
3430                                                PPSMC_MSG_PCIeDPM_Enable)),
3431                                "Failed to enable pcie DPM during DPM Start Function!",
3432                                return -1);
3433        }
3434
3435        return 0;
3436}
3437
3438static int fiji_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
3439{
3440        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3441
3442        /* disable SCLK dpm */
3443        if (!data->sclk_dpm_key_disabled)
3444                PP_ASSERT_WITH_CODE(
3445                                (smum_send_msg_to_smc(hwmgr->smumgr,
3446                                                PPSMC_MSG_DPM_Disable) == 0),
3447                                "Failed to disable SCLK DPM!",
3448                                return -1);
3449
3450        /* disable MCLK dpm */
3451        if (!data->mclk_dpm_key_disabled) {
3452                PP_ASSERT_WITH_CODE(
3453                                (smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3454                                PPSMC_MSG_MCLKDPM_SetEnabledMask, 1) == 0),
3455                                "Failed to force MCLK DPM0!",
3456                                return -1);
3457
3458                PP_ASSERT_WITH_CODE(
3459                                (smum_send_msg_to_smc(hwmgr->smumgr,
3460                                                PPSMC_MSG_MCLKDPM_Disable) == 0),
3461                                "Failed to disable MCLK DPM!",
3462                                return -1);
3463        }
3464
3465        return 0;
3466}
3467
3468static int fiji_stop_dpm(struct pp_hwmgr *hwmgr)
3469{
3470        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3471
3472        /* disable general power management */
3473        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3474                        GLOBAL_PWRMGT_EN, 0);
3475        /* disable sclk deep sleep */
3476        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
3477                        DYNAMIC_PM_EN, 0);
3478
3479        /* disable PCIE dpm */
3480        if (!data->pcie_dpm_key_disabled) {
3481                PP_ASSERT_WITH_CODE(
3482                                (smum_send_msg_to_smc(hwmgr->smumgr,
3483                                                PPSMC_MSG_PCIeDPM_Disable) == 0),
3484                                "Failed to disable pcie DPM during DPM Stop Function!",
3485                                return -1);
3486        }
3487
3488        if (fiji_disable_sclk_mclk_dpm(hwmgr)) {
3489                printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!");
3490                return -1;
3491        }
3492
3493        PP_ASSERT_WITH_CODE(
3494                        (smum_send_msg_to_smc(hwmgr->smumgr,
3495                                        PPSMC_MSG_Voltage_Cntl_Disable) == 0),
3496                        "Failed to disable voltage DPM during DPM Stop Function!",
3497                        return -1);
3498
3499        return 0;
3500}
3501
3502static void fiji_set_dpm_event_sources(struct pp_hwmgr *hwmgr,
3503                uint32_t sources)
3504{
3505        bool protection;
3506        enum DPM_EVENT_SRC src;
3507
3508        switch (sources) {
3509        default:
3510                printk(KERN_ERR "Unknown throttling event sources.");
3511                /* fall through */
3512        case 0:
3513                protection = false;
3514                /* src is unused */
3515                break;
3516        case (1 << PHM_AutoThrottleSource_Thermal):
3517                protection = true;
3518                src = DPM_EVENT_SRC_DIGITAL;
3519                break;
3520        case (1 << PHM_AutoThrottleSource_External):
3521                protection = true;
3522                src = DPM_EVENT_SRC_EXTERNAL;
3523                break;
3524        case (1 << PHM_AutoThrottleSource_External) |
3525                        (1 << PHM_AutoThrottleSource_Thermal):
3526                protection = true;
3527                src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
3528                break;
3529        }
3530        /* Order matters - don't enable thermal protection for the wrong source. */
3531        if (protection) {
3532                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
3533                                DPM_EVENT_SRC, src);
3534                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3535                                THERMAL_PROTECTION_DIS,
3536                                !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3537                                                PHM_PlatformCaps_ThermalController));
3538        } else
3539                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3540                                THERMAL_PROTECTION_DIS, 1);
3541}
3542
3543static int fiji_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
3544                PHM_AutoThrottleSource source)
3545{
3546        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3547
3548        if (!(data->active_auto_throttle_sources & (1 << source))) {
3549                data->active_auto_throttle_sources |= 1 << source;
3550                fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
3551        }
3552        return 0;
3553}
3554
3555static int fiji_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
3556{
3557        return fiji_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
3558}
3559
3560static int fiji_disable_auto_throttle_source(struct pp_hwmgr *hwmgr,
3561                PHM_AutoThrottleSource source)
3562{
3563        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3564
3565        if (data->active_auto_throttle_sources & (1 << source)) {
3566                data->active_auto_throttle_sources &= ~(1 << source);
3567                fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
3568        }
3569        return 0;
3570}
3571
3572static int fiji_disable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
3573{
3574        return fiji_disable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
3575}
3576
3577static int fiji_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
3578{
3579        int tmp_result, result = 0;
3580
3581        tmp_result = (!fiji_is_dpm_running(hwmgr))? 0 : -1;
3582        PP_ASSERT_WITH_CODE(result == 0,
3583                        "DPM is already running right now, no need to enable DPM!",
3584                        return 0);
3585
3586        if (fiji_voltage_control(hwmgr)) {
3587                tmp_result = fiji_enable_voltage_control(hwmgr);
3588                PP_ASSERT_WITH_CODE(tmp_result == 0,
3589                                "Failed to enable voltage control!",
3590                                result = tmp_result);
3591        }
3592
3593        if (fiji_voltage_control(hwmgr)) {
3594                tmp_result = fiji_construct_voltage_tables(hwmgr);
3595                PP_ASSERT_WITH_CODE((0 == tmp_result),
3596                                "Failed to contruct voltage tables!",
3597                                result = tmp_result);
3598        }
3599
3600        tmp_result = fiji_initialize_mc_reg_table(hwmgr);
3601        PP_ASSERT_WITH_CODE((0 == tmp_result),
3602                        "Failed to initialize MC reg table!", result = tmp_result);
3603
3604        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3605                        PHM_PlatformCaps_EngineSpreadSpectrumSupport))
3606                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3607                                GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
3608
3609        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3610                        PHM_PlatformCaps_ThermalController))
3611                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3612                                GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
3613
3614        tmp_result = fiji_program_static_screen_threshold_parameters(hwmgr);
3615        PP_ASSERT_WITH_CODE((0 == tmp_result),
3616                        "Failed to program static screen threshold parameters!",
3617                        result = tmp_result);
3618
3619        tmp_result = fiji_enable_display_gap(hwmgr);
3620        PP_ASSERT_WITH_CODE((0 == tmp_result),
3621                        "Failed to enable display gap!", result = tmp_result);
3622
3623        tmp_result = fiji_program_voting_clients(hwmgr);
3624        PP_ASSERT_WITH_CODE((0 == tmp_result),
3625                        "Failed to program voting clients!", result = tmp_result);
3626
3627        tmp_result = fiji_process_firmware_header(hwmgr);
3628        PP_ASSERT_WITH_CODE((0 == tmp_result),
3629                        "Failed to process firmware header!", result = tmp_result);
3630
3631        tmp_result = fiji_initial_switch_from_arbf0_to_f1(hwmgr);
3632        PP_ASSERT_WITH_CODE((0 == tmp_result),
3633                        "Failed to initialize switch from ArbF0 to F1!",
3634                        result = tmp_result);
3635
3636        tmp_result = fiji_init_smc_table(hwmgr);
3637        PP_ASSERT_WITH_CODE((0 == tmp_result),
3638                        "Failed to initialize SMC table!", result = tmp_result);
3639
3640        tmp_result = fiji_init_arb_table_index(hwmgr);
3641        PP_ASSERT_WITH_CODE((0 == tmp_result),
3642                        "Failed to initialize ARB table index!", result = tmp_result);
3643
3644        tmp_result = fiji_populate_pm_fuses(hwmgr);
3645        PP_ASSERT_WITH_CODE((0 == tmp_result),
3646                        "Failed to populate PM fuses!", result = tmp_result);
3647
3648        tmp_result = fiji_enable_vrhot_gpio_interrupt(hwmgr);
3649        PP_ASSERT_WITH_CODE((0 == tmp_result),
3650                        "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
3651
3652        tmp_result = tonga_notify_smc_display_change(hwmgr, false);
3653        PP_ASSERT_WITH_CODE((0 == tmp_result),
3654                        "Failed to notify no display!", result = tmp_result);
3655
3656        tmp_result = fiji_enable_sclk_control(hwmgr);
3657        PP_ASSERT_WITH_CODE((0 == tmp_result),
3658                        "Failed to enable SCLK control!", result = tmp_result);
3659
3660        tmp_result = fiji_enable_ulv(hwmgr);
3661        PP_ASSERT_WITH_CODE((0 == tmp_result),
3662                        "Failed to enable ULV!", result = tmp_result);
3663
3664        tmp_result = fiji_enable_deep_sleep_master_switch(hwmgr);
3665        PP_ASSERT_WITH_CODE((0 == tmp_result),
3666                        "Failed to enable deep sleep master switch!", result = tmp_result);
3667
3668        tmp_result = fiji_start_dpm(hwmgr);
3669        PP_ASSERT_WITH_CODE((0 == tmp_result),
3670                        "Failed to start DPM!", result = tmp_result);
3671
3672        tmp_result = fiji_enable_smc_cac(hwmgr);
3673        PP_ASSERT_WITH_CODE((0 == tmp_result),
3674                        "Failed to enable SMC CAC!", result = tmp_result);
3675
3676        tmp_result = fiji_enable_power_containment(hwmgr);
3677        PP_ASSERT_WITH_CODE((0 == tmp_result),
3678                        "Failed to enable power containment!", result = tmp_result);
3679
3680        tmp_result = fiji_power_control_set_level(hwmgr);
3681        PP_ASSERT_WITH_CODE((0 == tmp_result),
3682                        "Failed to power control set level!", result = tmp_result);
3683
3684        tmp_result = fiji_enable_thermal_auto_throttle(hwmgr);
3685        PP_ASSERT_WITH_CODE((0 == tmp_result),
3686                        "Failed to enable thermal auto throttle!", result = tmp_result);
3687
3688        return result;
3689}
3690
3691static int fiji_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
3692{
3693        int tmp_result, result = 0;
3694
3695        tmp_result = (fiji_is_dpm_running(hwmgr)) ? 0 : -1;
3696        PP_ASSERT_WITH_CODE(tmp_result == 0,
3697                        "DPM is not running right now, no need to disable DPM!",
3698                        return 0);
3699
3700        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3701                        PHM_PlatformCaps_ThermalController))
3702                PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3703                                GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 1);
3704
3705        tmp_result = fiji_disable_power_containment(hwmgr);
3706        PP_ASSERT_WITH_CODE((tmp_result == 0),
3707                        "Failed to disable power containment!", result = tmp_result);
3708
3709        tmp_result = fiji_disable_smc_cac(hwmgr);
3710        PP_ASSERT_WITH_CODE((tmp_result == 0),
3711                        "Failed to disable SMC CAC!", result = tmp_result);
3712
3713        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3714                        CG_SPLL_SPREAD_SPECTRUM, SSEN, 0);
3715        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3716                        GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 0);
3717
3718        tmp_result = fiji_disable_thermal_auto_throttle(hwmgr);
3719        PP_ASSERT_WITH_CODE((tmp_result == 0),
3720                        "Failed to disable thermal auto throttle!", result = tmp_result);
3721
3722        tmp_result = fiji_stop_dpm(hwmgr);
3723        PP_ASSERT_WITH_CODE((tmp_result == 0),
3724                        "Failed to stop DPM!", result = tmp_result);
3725
3726        tmp_result = fiji_disable_deep_sleep_master_switch(hwmgr);
3727        PP_ASSERT_WITH_CODE((tmp_result == 0),
3728                        "Failed to disable deep sleep master switch!", result = tmp_result);
3729
3730        tmp_result = fiji_disable_ulv(hwmgr);
3731        PP_ASSERT_WITH_CODE((tmp_result == 0),
3732                        "Failed to disable ULV!", result = tmp_result);
3733
3734        tmp_result = fiji_clear_voting_clients(hwmgr);
3735        PP_ASSERT_WITH_CODE((tmp_result == 0),
3736                        "Failed to clear voting clients!", result = tmp_result);
3737
3738        tmp_result = fiji_reset_to_default(hwmgr);
3739        PP_ASSERT_WITH_CODE((tmp_result == 0),
3740                        "Failed to reset to default!", result = tmp_result);
3741
3742        tmp_result = fiji_force_switch_to_arbf0(hwmgr);
3743        PP_ASSERT_WITH_CODE((tmp_result == 0),
3744                        "Failed to force to switch arbf0!", result = tmp_result);
3745
3746        return result;
3747}
3748
3749static int fiji_force_dpm_highest(struct pp_hwmgr *hwmgr)
3750{
3751        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3752        uint32_t level, tmp;
3753
3754        if (!data->sclk_dpm_key_disabled) {
3755                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
3756                        level = 0;
3757                        tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
3758                        while (tmp >>= 1)
3759                                level++;
3760                        if (level)
3761                                smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3762                                                PPSMC_MSG_SCLKDPM_SetEnabledMask,
3763                                                (1 << level));
3764                }
3765        }
3766
3767        if (!data->mclk_dpm_key_disabled) {
3768                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
3769                        level = 0;
3770                        tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
3771                        while (tmp >>= 1)
3772                                level++;
3773                        if (level)
3774                                smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3775                                                PPSMC_MSG_MCLKDPM_SetEnabledMask,
3776                                                (1 << level));
3777                }
3778        }
3779
3780        if (!data->pcie_dpm_key_disabled) {
3781                if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
3782                        level = 0;
3783                        tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
3784                        while (tmp >>= 1)
3785                                level++;
3786                        if (level)
3787                                smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3788                                                PPSMC_MSG_PCIeDPM_ForceLevel,
3789                                                (1 << level));
3790                }
3791        }
3792        return 0;
3793}
3794
3795static int fiji_upload_dpmlevel_enable_mask(struct pp_hwmgr *hwmgr)
3796{
3797        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3798
3799        phm_apply_dal_min_voltage_request(hwmgr);
3800
3801        if (!data->sclk_dpm_key_disabled) {
3802                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
3803                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3804                                        PPSMC_MSG_SCLKDPM_SetEnabledMask,
3805                                        data->dpm_level_enable_mask.sclk_dpm_enable_mask);
3806        }
3807        return 0;
3808}
3809
3810static int fiji_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
3811{
3812        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3813
3814        if (!fiji_is_dpm_running(hwmgr))
3815                return -EINVAL;
3816
3817        if (!data->pcie_dpm_key_disabled) {
3818                smum_send_msg_to_smc(hwmgr->smumgr,
3819                                PPSMC_MSG_PCIeDPM_UnForceLevel);
3820        }
3821
3822        return fiji_upload_dpmlevel_enable_mask(hwmgr);
3823}
3824
3825static uint32_t fiji_get_lowest_enabled_level(
3826                struct pp_hwmgr *hwmgr, uint32_t mask)
3827{
3828        uint32_t level = 0;
3829
3830        while(0 == (mask & (1 << level)))
3831                level++;
3832
3833        return level;
3834}
3835
3836static int fiji_force_dpm_lowest(struct pp_hwmgr *hwmgr)
3837{
3838        struct fiji_hwmgr *data =
3839                        (struct fiji_hwmgr *)(hwmgr->backend);
3840        uint32_t level;
3841
3842        if (!data->sclk_dpm_key_disabled)
3843                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
3844                        level = fiji_get_lowest_enabled_level(hwmgr,
3845                                                              data->dpm_level_enable_mask.sclk_dpm_enable_mask);
3846                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3847                                                            PPSMC_MSG_SCLKDPM_SetEnabledMask,
3848                                                            (1 << level));
3849
3850        }
3851
3852        if (!data->mclk_dpm_key_disabled) {
3853                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
3854                        level = fiji_get_lowest_enabled_level(hwmgr,
3855                                                              data->dpm_level_enable_mask.mclk_dpm_enable_mask);
3856                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3857                                                            PPSMC_MSG_MCLKDPM_SetEnabledMask,
3858                                                            (1 << level));
3859                }
3860        }
3861
3862        if (!data->pcie_dpm_key_disabled) {
3863                if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
3864                        level = fiji_get_lowest_enabled_level(hwmgr,
3865                                                              data->dpm_level_enable_mask.pcie_dpm_enable_mask);
3866                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3867                                                            PPSMC_MSG_PCIeDPM_ForceLevel,
3868                                                            (1 << level));
3869                }
3870        }
3871
3872        return 0;
3873
3874}
3875static int fiji_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
3876                                enum amd_dpm_forced_level level)
3877{
3878        int ret = 0;
3879
3880        switch (level) {
3881        case AMD_DPM_FORCED_LEVEL_HIGH:
3882                ret = fiji_force_dpm_highest(hwmgr);
3883                if (ret)
3884                        return ret;
3885                break;
3886        case AMD_DPM_FORCED_LEVEL_LOW:
3887                ret = fiji_force_dpm_lowest(hwmgr);
3888                if (ret)
3889                        return ret;
3890                break;
3891        case AMD_DPM_FORCED_LEVEL_AUTO:
3892                ret = fiji_unforce_dpm_levels(hwmgr);
3893                if (ret)
3894                        return ret;
3895                break;
3896        default:
3897                break;
3898        }
3899
3900        hwmgr->dpm_level = level;
3901
3902        return ret;
3903}
3904
3905static int fiji_get_power_state_size(struct pp_hwmgr *hwmgr)
3906{
3907        return sizeof(struct fiji_power_state);
3908}
3909
3910static int fiji_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
3911                void *state, struct pp_power_state *power_state,
3912                void *pp_table, uint32_t classification_flag)
3913{
3914        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3915        struct fiji_power_state  *fiji_power_state =
3916                        (struct fiji_power_state *)(&(power_state->hardware));
3917        struct fiji_performance_level *performance_level;
3918        ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
3919        ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
3920                        (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
3921        ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
3922                        (ATOM_Tonga_SCLK_Dependency_Table *)
3923                        (((unsigned long)powerplay_table) +
3924                                le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
3925        ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
3926                        (ATOM_Tonga_MCLK_Dependency_Table *)
3927                        (((unsigned long)powerplay_table) +
3928                                le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
3929
3930        /* The following fields are not initialized here: id orderedList allStatesList */
3931        power_state->classification.ui_label =
3932                        (le16_to_cpu(state_entry->usClassification) &
3933                        ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
3934                        ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
3935        power_state->classification.flags = classification_flag;
3936        /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
3937
3938        power_state->classification.temporary_state = false;
3939        power_state->classification.to_be_deleted = false;
3940
3941        power_state->validation.disallowOnDC =
3942                        (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
3943                                        ATOM_Tonga_DISALLOW_ON_DC));
3944
3945        power_state->pcie.lanes = 0;
3946
3947        power_state->display.disableFrameModulation = false;
3948        power_state->display.limitRefreshrate = false;
3949        power_state->display.enableVariBright =
3950                        (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
3951                                        ATOM_Tonga_ENABLE_VARIBRIGHT));
3952
3953        power_state->validation.supportedPowerLevels = 0;
3954        power_state->uvd_clocks.VCLK = 0;
3955        power_state->uvd_clocks.DCLK = 0;
3956        power_state->temperatures.min = 0;
3957        power_state->temperatures.max = 0;
3958
3959        performance_level = &(fiji_power_state->performance_levels
3960                        [fiji_power_state->performance_level_count++]);
3961
3962        PP_ASSERT_WITH_CODE(
3963                        (fiji_power_state->performance_level_count < SMU73_MAX_LEVELS_GRAPHICS),
3964                        "Performance levels exceeds SMC limit!",
3965                        return -1);
3966
3967        PP_ASSERT_WITH_CODE(
3968                        (fiji_power_state->performance_level_count <=
3969                                        hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
3970                        "Performance levels exceeds Driver limit!",
3971                        return -1);
3972
3973        /* Performance levels are arranged from low to high. */
3974        performance_level->memory_clock = mclk_dep_table->entries
3975                        [state_entry->ucMemoryClockIndexLow].ulMclk;
3976        performance_level->engine_clock = sclk_dep_table->entries
3977                        [state_entry->ucEngineClockIndexLow].ulSclk;
3978        performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
3979                        state_entry->ucPCIEGenLow);
3980        performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
3981                        state_entry->ucPCIELaneHigh);
3982
3983        performance_level = &(fiji_power_state->performance_levels
3984                        [fiji_power_state->performance_level_count++]);
3985        performance_level->memory_clock = mclk_dep_table->entries
3986                        [state_entry->ucMemoryClockIndexHigh].ulMclk;
3987        performance_level->engine_clock = sclk_dep_table->entries
3988                        [state_entry->ucEngineClockIndexHigh].ulSclk;
3989        performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
3990                        state_entry->ucPCIEGenHigh);
3991        performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
3992                        state_entry->ucPCIELaneHigh);
3993
3994        return 0;
3995}
3996
3997static int fiji_get_pp_table_entry(struct pp_hwmgr *hwmgr,
3998                unsigned long entry_index, struct pp_power_state *state)
3999{
4000        int result;
4001        struct fiji_power_state *ps;
4002        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4003        struct phm_ppt_v1_information *table_info =
4004                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
4005        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
4006                        table_info->vdd_dep_on_mclk;
4007
4008        state->hardware.magic = PHM_VIslands_Magic;
4009
4010        ps = (struct fiji_power_state *)(&state->hardware);
4011
4012        result = tonga_get_powerplay_table_entry(hwmgr, entry_index, state,
4013                        fiji_get_pp_table_entry_callback_func);
4014
4015        /* This is the earliest time we have all the dependency table and the VBIOS boot state
4016         * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
4017         * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
4018         */
4019        if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
4020                if (dep_mclk_table->entries[0].clk !=
4021                                data->vbios_boot_state.mclk_bootup_value)
4022                        printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
4023                                        "does not match VBIOS boot MCLK level");
4024                if (dep_mclk_table->entries[0].vddci !=
4025                                data->vbios_boot_state.vddci_bootup_value)
4026                        printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
4027                                        "does not match VBIOS boot VDDCI level");
4028        }
4029
4030        /* set DC compatible flag if this state supports DC */
4031        if (!state->validation.disallowOnDC)
4032                ps->dc_compatible = true;
4033
4034        if (state->classification.flags & PP_StateClassificationFlag_ACPI)
4035                data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
4036
4037        ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
4038        ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
4039
4040        if (!result) {
4041                uint32_t i;
4042
4043                switch (state->classification.ui_label) {
4044                case PP_StateUILabel_Performance:
4045                        data->use_pcie_performance_levels = true;
4046
4047                        for (i = 0; i < ps->performance_level_count; i++) {
4048                                if (data->pcie_gen_performance.max <
4049                                                ps->performance_levels[i].pcie_gen)
4050                                        data->pcie_gen_performance.max =
4051                                                        ps->performance_levels[i].pcie_gen;
4052
4053                                if (data->pcie_gen_performance.min >
4054                                                ps->performance_levels[i].pcie_gen)
4055                                        data->pcie_gen_performance.min =
4056                                                        ps->performance_levels[i].pcie_gen;
4057
4058                                if (data->pcie_lane_performance.max <
4059                                                ps->performance_levels[i].pcie_lane)
4060                                        data->pcie_lane_performance.max =
4061                                                        ps->performance_levels[i].pcie_lane;
4062
4063                                if (data->pcie_lane_performance.min >
4064                                                ps->performance_levels[i].pcie_lane)
4065                                        data->pcie_lane_performance.min =
4066                                                        ps->performance_levels[i].pcie_lane;
4067                        }
4068                        break;
4069                case PP_StateUILabel_Battery:
4070                        data->use_pcie_power_saving_levels = true;
4071
4072                        for (i = 0; i < ps->performance_level_count; i++) {
4073                                if (data->pcie_gen_power_saving.max <
4074                                                ps->performance_levels[i].pcie_gen)
4075                                        data->pcie_gen_power_saving.max =
4076                                                        ps->performance_levels[i].pcie_gen;
4077
4078                                if (data->pcie_gen_power_saving.min >
4079                                                ps->performance_levels[i].pcie_gen)
4080                                        data->pcie_gen_power_saving.min =
4081                                                        ps->performance_levels[i].pcie_gen;
4082
4083                                if (data->pcie_lane_power_saving.max <
4084                                                ps->performance_levels[i].pcie_lane)
4085                                        data->pcie_lane_power_saving.max =
4086                                                        ps->performance_levels[i].pcie_lane;
4087
4088                                if (data->pcie_lane_power_saving.min >
4089                                                ps->performance_levels[i].pcie_lane)
4090                                        data->pcie_lane_power_saving.min =
4091                                                        ps->performance_levels[i].pcie_lane;
4092                        }
4093                        break;
4094                default:
4095                        break;
4096                }
4097        }
4098        return 0;
4099}
4100
4101static int fiji_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
4102                                struct pp_power_state  *request_ps,
4103                        const struct pp_power_state *current_ps)
4104{
4105        struct fiji_power_state *fiji_ps =
4106                                cast_phw_fiji_power_state(&request_ps->hardware);
4107        uint32_t sclk;
4108        uint32_t mclk;
4109        struct PP_Clocks minimum_clocks = {0};
4110        bool disable_mclk_switching;
4111        bool disable_mclk_switching_for_frame_lock;
4112        struct cgs_display_info info = {0};
4113        const struct phm_clock_and_voltage_limits *max_limits;
4114        uint32_t i;
4115        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4116        struct phm_ppt_v1_information *table_info =
4117                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
4118        int32_t count;
4119        int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
4120
4121        data->battery_state = (PP_StateUILabel_Battery ==
4122                        request_ps->classification.ui_label);
4123
4124        PP_ASSERT_WITH_CODE(fiji_ps->performance_level_count == 2,
4125                                 "VI should always have 2 performance levels",);
4126
4127        max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
4128                        &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
4129                        &(hwmgr->dyn_state.max_clock_voltage_on_dc);
4130
4131        /* Cap clock DPM tables at DC MAX if it is in DC. */
4132        if (PP_PowerSource_DC == hwmgr->power_source) {
4133                for (i = 0; i < fiji_ps->performance_level_count; i++) {
4134                        if (fiji_ps->performance_levels[i].memory_clock > max_limits->mclk)
4135                                fiji_ps->performance_levels[i].memory_clock = max_limits->mclk;
4136                        if (fiji_ps->performance_levels[i].engine_clock > max_limits->sclk)
4137                                fiji_ps->performance_levels[i].engine_clock = max_limits->sclk;
4138                }
4139        }
4140
4141        fiji_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
4142        fiji_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
4143
4144        fiji_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
4145
4146        cgs_get_active_displays_info(hwmgr->device, &info);
4147
4148        /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4149
4150        /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4151
4152        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4153                        PHM_PlatformCaps_StablePState)) {
4154                max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
4155                stable_pstate_sclk = (max_limits->sclk * 75) / 100;
4156
4157                for (count = table_info->vdd_dep_on_sclk->count - 1;
4158                                count >= 0; count--) {
4159                        if (stable_pstate_sclk >=
4160                                        table_info->vdd_dep_on_sclk->entries[count].clk) {
4161                                stable_pstate_sclk =
4162                                                table_info->vdd_dep_on_sclk->entries[count].clk;
4163                                break;
4164                        }
4165                }
4166
4167                if (count < 0)
4168                        stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
4169
4170                stable_pstate_mclk = max_limits->mclk;
4171
4172                minimum_clocks.engineClock = stable_pstate_sclk;
4173                minimum_clocks.memoryClock = stable_pstate_mclk;
4174        }
4175
4176        if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
4177                minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
4178
4179        if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
4180                minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
4181
4182        fiji_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
4183
4184        if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
4185                PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
4186                                hwmgr->platform_descriptor.overdriveLimit.engineClock),
4187                                "Overdrive sclk exceeds limit",
4188                                hwmgr->gfx_arbiter.sclk_over_drive =
4189                                                hwmgr->platform_descriptor.overdriveLimit.engineClock);
4190
4191                if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
4192                        fiji_ps->performance_levels[1].engine_clock =
4193                                        hwmgr->gfx_arbiter.sclk_over_drive;
4194        }
4195
4196        if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
4197                PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
4198                                hwmgr->platform_descriptor.overdriveLimit.memoryClock),
4199                                "Overdrive mclk exceeds limit",
4200                                hwmgr->gfx_arbiter.mclk_over_drive =
4201                                                hwmgr->platform_descriptor.overdriveLimit.memoryClock);
4202
4203                if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
4204                        fiji_ps->performance_levels[1].memory_clock =
4205                                        hwmgr->gfx_arbiter.mclk_over_drive;
4206        }
4207
4208        disable_mclk_switching_for_frame_lock = phm_cap_enabled(
4209                                    hwmgr->platform_descriptor.platformCaps,
4210                                    PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
4211
4212        disable_mclk_switching = (1 < info.display_count) ||
4213                                    disable_mclk_switching_for_frame_lock;
4214
4215        sclk = fiji_ps->performance_levels[0].engine_clock;
4216        mclk = fiji_ps->performance_levels[0].memory_clock;
4217
4218        if (disable_mclk_switching)
4219                mclk = fiji_ps->performance_levels
4220                [fiji_ps->performance_level_count - 1].memory_clock;
4221
4222        if (sclk < minimum_clocks.engineClock)
4223                sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
4224                                max_limits->sclk : minimum_clocks.engineClock;
4225
4226        if (mclk < minimum_clocks.memoryClock)
4227                mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
4228                                max_limits->mclk : minimum_clocks.memoryClock;
4229
4230        fiji_ps->performance_levels[0].engine_clock = sclk;
4231        fiji_ps->performance_levels[0].memory_clock = mclk;
4232
4233        fiji_ps->performance_levels[1].engine_clock =
4234                (fiji_ps->performance_levels[1].engine_clock >=
4235                                fiji_ps->performance_levels[0].engine_clock) ?
4236                                                fiji_ps->performance_levels[1].engine_clock :
4237                                                fiji_ps->performance_levels[0].engine_clock;
4238
4239        if (disable_mclk_switching) {
4240                if (mclk < fiji_ps->performance_levels[1].memory_clock)
4241                        mclk = fiji_ps->performance_levels[1].memory_clock;
4242
4243                fiji_ps->performance_levels[0].memory_clock = mclk;
4244                fiji_ps->performance_levels[1].memory_clock = mclk;
4245        } else {
4246                if (fiji_ps->performance_levels[1].memory_clock <
4247                                fiji_ps->performance_levels[0].memory_clock)
4248                        fiji_ps->performance_levels[1].memory_clock =
4249                                        fiji_ps->performance_levels[0].memory_clock;
4250        }
4251
4252        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4253                        PHM_PlatformCaps_StablePState)) {
4254                for (i = 0; i < fiji_ps->performance_level_count; i++) {
4255                        fiji_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
4256                        fiji_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
4257                        fiji_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
4258                        fiji_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
4259                }
4260        }
4261
4262        return 0;
4263}
4264
4265static int fiji_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
4266{
4267        const struct phm_set_power_state_input *states =
4268                        (const struct phm_set_power_state_input *)input;
4269        const struct fiji_power_state *fiji_ps =
4270                        cast_const_phw_fiji_power_state(states->pnew_state);
4271        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4272        struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
4273        uint32_t sclk = fiji_ps->performance_levels
4274                        [fiji_ps->performance_level_count - 1].engine_clock;
4275        struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
4276        uint32_t mclk = fiji_ps->performance_levels
4277                        [fiji_ps->performance_level_count - 1].memory_clock;
4278        uint32_t i;
4279        struct cgs_display_info info = {0};
4280
4281        data->need_update_smu7_dpm_table = 0;
4282
4283        for (i = 0; i < sclk_table->count; i++) {
4284                if (sclk == sclk_table->dpm_levels[i].value)
4285                        break;
4286        }
4287
4288        if (i >= sclk_table->count)
4289                data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
4290        else {
4291                if(data->display_timing.min_clock_in_sr !=
4292                        hwmgr->display_config.min_core_set_clock_in_sr)
4293                        data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
4294        }
4295
4296        for (i = 0; i < mclk_table->count; i++) {
4297                if (mclk == mclk_table->dpm_levels[i].value)
4298                        break;
4299        }
4300
4301        if (i >= mclk_table->count)
4302                data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
4303
4304        cgs_get_active_displays_info(hwmgr->device, &info);
4305
4306        if (data->display_timing.num_existing_displays != info.display_count)
4307                data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
4308
4309        return 0;
4310}
4311
4312static uint16_t fiji_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
4313                const struct fiji_power_state *fiji_ps)
4314{
4315        uint32_t i;
4316        uint32_t sclk, max_sclk = 0;
4317        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4318        struct fiji_dpm_table *dpm_table = &data->dpm_table;
4319
4320        for (i = 0; i < fiji_ps->performance_level_count; i++) {
4321                sclk = fiji_ps->performance_levels[i].engine_clock;
4322                if (max_sclk < sclk)
4323                        max_sclk = sclk;
4324        }
4325
4326        for (i = 0; i < dpm_table->sclk_table.count; i++) {
4327                if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
4328                        return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
4329                                        dpm_table->pcie_speed_table.dpm_levels
4330                                        [dpm_table->pcie_speed_table.count - 1].value :
4331                                        dpm_table->pcie_speed_table.dpm_levels[i].value);
4332        }
4333
4334        return 0;
4335}
4336
4337static int fiji_request_link_speed_change_before_state_change(
4338                struct pp_hwmgr *hwmgr, const void *input)
4339{
4340        const struct phm_set_power_state_input *states =
4341                        (const struct phm_set_power_state_input *)input;
4342        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4343        const struct fiji_power_state *fiji_nps =
4344                        cast_const_phw_fiji_power_state(states->pnew_state);
4345        const struct fiji_power_state *fiji_cps =
4346                        cast_const_phw_fiji_power_state(states->pcurrent_state);
4347
4348        uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_nps);
4349        uint16_t current_link_speed;
4350
4351        if (data->force_pcie_gen == PP_PCIEGenInvalid)
4352                current_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_cps);
4353        else
4354                current_link_speed = data->force_pcie_gen;
4355
4356        data->force_pcie_gen = PP_PCIEGenInvalid;
4357        data->pspp_notify_required = false;
4358        if (target_link_speed > current_link_speed) {
4359                switch(target_link_speed) {
4360                case PP_PCIEGen3:
4361                        if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
4362                                break;
4363                        data->force_pcie_gen = PP_PCIEGen2;
4364                        if (current_link_speed == PP_PCIEGen2)
4365                                break;
4366                case PP_PCIEGen2:
4367                        if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
4368                                break;
4369                default:
4370                        data->force_pcie_gen = fiji_get_current_pcie_speed(hwmgr);
4371                        break;
4372                }
4373        } else {
4374                if (target_link_speed < current_link_speed)
4375                        data->pspp_notify_required = true;
4376        }
4377
4378        return 0;
4379}
4380
4381static int fiji_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
4382{
4383        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4384
4385        if (0 == data->need_update_smu7_dpm_table)
4386                return 0;
4387
4388        if ((0 == data->sclk_dpm_key_disabled) &&
4389                (data->need_update_smu7_dpm_table &
4390                        (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
4391                PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4392                                    "Trying to freeze SCLK DPM when DPM is disabled",
4393                                    );
4394                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4395                                PPSMC_MSG_SCLKDPM_FreezeLevel),
4396                                "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
4397                                return -1);
4398        }
4399
4400        if ((0 == data->mclk_dpm_key_disabled) &&
4401                (data->need_update_smu7_dpm_table &
4402                 DPMTABLE_OD_UPDATE_MCLK)) {
4403                PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4404                                    "Trying to freeze MCLK DPM when DPM is disabled",
4405                                    );
4406                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4407                                PPSMC_MSG_MCLKDPM_FreezeLevel),
4408                                "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
4409                                return -1);
4410        }
4411
4412        return 0;
4413}
4414
4415static int fiji_populate_and_upload_sclk_mclk_dpm_levels(
4416                struct pp_hwmgr *hwmgr, const void *input)
4417{
4418        int result = 0;
4419        const struct phm_set_power_state_input *states =
4420                        (const struct phm_set_power_state_input *)input;
4421        const struct fiji_power_state *fiji_ps =
4422                        cast_const_phw_fiji_power_state(states->pnew_state);
4423        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4424        uint32_t sclk = fiji_ps->performance_levels
4425                        [fiji_ps->performance_level_count - 1].engine_clock;
4426        uint32_t mclk = fiji_ps->performance_levels
4427                        [fiji_ps->performance_level_count - 1].memory_clock;
4428        struct fiji_dpm_table *dpm_table = &data->dpm_table;
4429
4430        struct fiji_dpm_table *golden_dpm_table = &data->golden_dpm_table;
4431        uint32_t dpm_count, clock_percent;
4432        uint32_t i;
4433
4434        if (0 == data->need_update_smu7_dpm_table)
4435                return 0;
4436
4437        if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
4438                dpm_table->sclk_table.dpm_levels
4439                [dpm_table->sclk_table.count - 1].value = sclk;
4440
4441                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4442                                PHM_PlatformCaps_OD6PlusinACSupport) ||
4443                        phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4444                                        PHM_PlatformCaps_OD6PlusinDCSupport)) {
4445                /* Need to do calculation based on the golden DPM table
4446                 * as the Heatmap GPU Clock axis is also based on the default values
4447                 */
4448                        PP_ASSERT_WITH_CODE(
4449                                (golden_dpm_table->sclk_table.dpm_levels
4450                                                [golden_dpm_table->sclk_table.count - 1].value != 0),
4451                                "Divide by 0!",
4452                                return -1);
4453                        dpm_count = dpm_table->sclk_table.count < 2 ?
4454                                        0 : dpm_table->sclk_table.count - 2;
4455                        for (i = dpm_count; i > 1; i--) {
4456                                if (sclk > golden_dpm_table->sclk_table.dpm_levels
4457                                                [golden_dpm_table->sclk_table.count-1].value) {
4458                                        clock_percent =
4459                                                ((sclk - golden_dpm_table->sclk_table.dpm_levels
4460                                                        [golden_dpm_table->sclk_table.count-1].value) * 100) /
4461                                                golden_dpm_table->sclk_table.dpm_levels
4462                                                        [golden_dpm_table->sclk_table.count-1].value;
4463
4464                                        dpm_table->sclk_table.dpm_levels[i].value =
4465                                                        golden_dpm_table->sclk_table.dpm_levels[i].value +
4466                                                        (golden_dpm_table->sclk_table.dpm_levels[i].value *
4467                                                                clock_percent)/100;
4468
4469                                } else if (golden_dpm_table->sclk_table.dpm_levels
4470                                                [dpm_table->sclk_table.count-1].value > sclk) {
4471                                        clock_percent =
4472                                                ((golden_dpm_table->sclk_table.dpm_levels
4473                                                [golden_dpm_table->sclk_table.count - 1].value - sclk) *
4474                                                                100) /
4475                                                golden_dpm_table->sclk_table.dpm_levels
4476                                                        [golden_dpm_table->sclk_table.count-1].value;
4477
4478                                        dpm_table->sclk_table.dpm_levels[i].value =
4479                                                        golden_dpm_table->sclk_table.dpm_levels[i].value -
4480                                                        (golden_dpm_table->sclk_table.dpm_levels[i].value *
4481                                                                        clock_percent) / 100;
4482                                } else
4483                                        dpm_table->sclk_table.dpm_levels[i].value =
4484                                                        golden_dpm_table->sclk_table.dpm_levels[i].value;
4485                        }
4486                }
4487        }
4488
4489        if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
4490                dpm_table->mclk_table.dpm_levels
4491                        [dpm_table->mclk_table.count - 1].value = mclk;
4492                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4493                                PHM_PlatformCaps_OD6PlusinACSupport) ||
4494                        phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4495                                PHM_PlatformCaps_OD6PlusinDCSupport)) {
4496
4497                        PP_ASSERT_WITH_CODE(
4498                                        (golden_dpm_table->mclk_table.dpm_levels
4499                                                [golden_dpm_table->mclk_table.count-1].value != 0),
4500                                        "Divide by 0!",
4501                                        return -1);
4502                        dpm_count = dpm_table->mclk_table.count < 2 ?
4503                                        0 : dpm_table->mclk_table.count - 2;
4504                        for (i = dpm_count; i > 1; i--) {
4505                                if (mclk > golden_dpm_table->mclk_table.dpm_levels
4506                                                [golden_dpm_table->mclk_table.count-1].value) {
4507                                        clock_percent = ((mclk -
4508                                                        golden_dpm_table->mclk_table.dpm_levels
4509                                                        [golden_dpm_table->mclk_table.count-1].value) * 100) /
4510                                                        golden_dpm_table->mclk_table.dpm_levels
4511                                                        [golden_dpm_table->mclk_table.count-1].value;
4512
4513                                        dpm_table->mclk_table.dpm_levels[i].value =
4514                                                        golden_dpm_table->mclk_table.dpm_levels[i].value +
4515                                                        (golden_dpm_table->mclk_table.dpm_levels[i].value *
4516                                                                        clock_percent) / 100;
4517
4518                                } else if (golden_dpm_table->mclk_table.dpm_levels
4519                                                [dpm_table->mclk_table.count-1].value > mclk) {
4520                                        clock_percent = ((golden_dpm_table->mclk_table.dpm_levels
4521                                                        [golden_dpm_table->mclk_table.count-1].value - mclk) * 100) /
4522                                                                        golden_dpm_table->mclk_table.dpm_levels
4523                                                                        [golden_dpm_table->mclk_table.count-1].value;
4524
4525                                        dpm_table->mclk_table.dpm_levels[i].value =
4526                                                        golden_dpm_table->mclk_table.dpm_levels[i].value -
4527                                                        (golden_dpm_table->mclk_table.dpm_levels[i].value *
4528                                                                        clock_percent) / 100;
4529                                } else
4530                                        dpm_table->mclk_table.dpm_levels[i].value =
4531                                                        golden_dpm_table->mclk_table.dpm_levels[i].value;
4532                        }
4533                }
4534        }
4535
4536        if (data->need_update_smu7_dpm_table &
4537                        (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
4538                result = fiji_populate_all_graphic_levels(hwmgr);
4539                PP_ASSERT_WITH_CODE((0 == result),
4540                                "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
4541                                return result);
4542        }
4543
4544        if (data->need_update_smu7_dpm_table &
4545                        (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
4546                /*populate MCLK dpm table to SMU7 */
4547                result = fiji_populate_all_memory_levels(hwmgr);
4548                PP_ASSERT_WITH_CODE((0 == result),
4549                                "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
4550                                return result);
4551        }
4552
4553        return result;
4554}
4555
4556static int fiji_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
4557                          struct fiji_single_dpm_table * dpm_table,
4558                             uint32_t low_limit, uint32_t high_limit)
4559{
4560        uint32_t i;
4561
4562        for (i = 0; i < dpm_table->count; i++) {
4563                if ((dpm_table->dpm_levels[i].value < low_limit) ||
4564                    (dpm_table->dpm_levels[i].value > high_limit))
4565                        dpm_table->dpm_levels[i].enabled = false;
4566                else
4567                        dpm_table->dpm_levels[i].enabled = true;
4568        }
4569        return 0;
4570}
4571
4572static int fiji_trim_dpm_states(struct pp_hwmgr *hwmgr,
4573                const struct fiji_power_state *fiji_ps)
4574{
4575        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4576        uint32_t high_limit_count;
4577
4578        PP_ASSERT_WITH_CODE((fiji_ps->performance_level_count >= 1),
4579                        "power state did not have any performance level",
4580                        return -1);
4581
4582        high_limit_count = (1 == fiji_ps->performance_level_count) ? 0 : 1;
4583
4584        fiji_trim_single_dpm_states(hwmgr,
4585                        &(data->dpm_table.sclk_table),
4586                        fiji_ps->performance_levels[0].engine_clock,
4587                        fiji_ps->performance_levels[high_limit_count].engine_clock);
4588
4589        fiji_trim_single_dpm_states(hwmgr,
4590                        &(data->dpm_table.mclk_table),
4591                        fiji_ps->performance_levels[0].memory_clock,
4592                        fiji_ps->performance_levels[high_limit_count].memory_clock);
4593
4594        return 0;
4595}
4596
4597static int fiji_generate_dpm_level_enable_mask(
4598                struct pp_hwmgr *hwmgr, const void *input)
4599{
4600        int result;
4601        const struct phm_set_power_state_input *states =
4602                        (const struct phm_set_power_state_input *)input;
4603        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4604        const struct fiji_power_state *fiji_ps =
4605                        cast_const_phw_fiji_power_state(states->pnew_state);
4606
4607        result = fiji_trim_dpm_states(hwmgr, fiji_ps);
4608        if (result)
4609                return result;
4610
4611        data->dpm_level_enable_mask.sclk_dpm_enable_mask =
4612                        fiji_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
4613        data->dpm_level_enable_mask.mclk_dpm_enable_mask =
4614                        fiji_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
4615        data->last_mclk_dpm_enable_mask =
4616                        data->dpm_level_enable_mask.mclk_dpm_enable_mask;
4617
4618        if (data->uvd_enabled) {
4619                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
4620                        data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
4621        }
4622
4623        data->dpm_level_enable_mask.pcie_dpm_enable_mask =
4624                        fiji_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
4625
4626        return 0;
4627}
4628
4629int fiji_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
4630{
4631        return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
4632                                  (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
4633                                  (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
4634}
4635
4636int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
4637{
4638        return smum_send_msg_to_smc(hwmgr->smumgr, enable?
4639                        PPSMC_MSG_VCEDPM_Enable :
4640                        PPSMC_MSG_VCEDPM_Disable);
4641}
4642
4643int fiji_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
4644{
4645        return smum_send_msg_to_smc(hwmgr->smumgr, enable?
4646                        PPSMC_MSG_SAMUDPM_Enable :
4647                        PPSMC_MSG_SAMUDPM_Disable);
4648}
4649
4650int fiji_enable_disable_acp_dpm(struct pp_hwmgr *hwmgr, bool enable)
4651{
4652        return smum_send_msg_to_smc(hwmgr->smumgr, enable?
4653                        PPSMC_MSG_ACPDPM_Enable :
4654                        PPSMC_MSG_ACPDPM_Disable);
4655}
4656
4657int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
4658{
4659        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4660        uint32_t mm_boot_level_offset, mm_boot_level_value;
4661        struct phm_ppt_v1_information *table_info =
4662                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
4663
4664        if (!bgate) {
4665                data->smc_state_table.UvdBootLevel = 0;
4666                if (table_info->mm_dep_table->count > 0)
4667                        data->smc_state_table.UvdBootLevel =
4668                                        (uint8_t) (table_info->mm_dep_table->count - 1);
4669                mm_boot_level_offset = data->dpm_table_start +
4670                                offsetof(SMU73_Discrete_DpmTable, UvdBootLevel);
4671                mm_boot_level_offset /= 4;
4672                mm_boot_level_offset *= 4;
4673                mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4674                                CGS_IND_REG__SMC, mm_boot_level_offset);
4675                mm_boot_level_value &= 0x00FFFFFF;
4676                mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
4677                cgs_write_ind_register(hwmgr->device,
4678                                CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4679
4680                if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4681                                PHM_PlatformCaps_UVDDPM) ||
4682                        phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4683                                PHM_PlatformCaps_StablePState))
4684                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4685                                        PPSMC_MSG_UVDDPM_SetEnabledMask,
4686                                        (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
4687        }
4688
4689        return fiji_enable_disable_uvd_dpm(hwmgr, !bgate);
4690}
4691
4692int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
4693{
4694        const struct phm_set_power_state_input *states =
4695                        (const struct phm_set_power_state_input *)input;
4696        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4697        const struct fiji_power_state *fiji_nps =
4698                        cast_const_phw_fiji_power_state(states->pnew_state);
4699        const struct fiji_power_state *fiji_cps =
4700                        cast_const_phw_fiji_power_state(states->pcurrent_state);
4701
4702        uint32_t mm_boot_level_offset, mm_boot_level_value;
4703        struct phm_ppt_v1_information *table_info =
4704                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
4705
4706        if (fiji_nps->vce_clks.evclk >0 &&
4707        (fiji_cps == NULL || fiji_cps->vce_clks.evclk == 0)) {
4708                data->smc_state_table.VceBootLevel =
4709                                (uint8_t) (table_info->mm_dep_table->count - 1);
4710
4711                mm_boot_level_offset = data->dpm_table_start +
4712                                offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
4713                mm_boot_level_offset /= 4;
4714                mm_boot_level_offset *= 4;
4715                mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4716                                CGS_IND_REG__SMC, mm_boot_level_offset);
4717                mm_boot_level_value &= 0xFF00FFFF;
4718                mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
4719                cgs_write_ind_register(hwmgr->device,
4720                                CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4721
4722                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4723                                PHM_PlatformCaps_StablePState)) {
4724                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4725                                        PPSMC_MSG_VCEDPM_SetEnabledMask,
4726                                        (uint32_t)1 << data->smc_state_table.VceBootLevel);
4727
4728                        fiji_enable_disable_vce_dpm(hwmgr, true);
4729                } else if (fiji_nps->vce_clks.evclk == 0 &&
4730                                fiji_cps != NULL &&
4731                                fiji_cps->vce_clks.evclk > 0)
4732                        fiji_enable_disable_vce_dpm(hwmgr, false);
4733        }
4734
4735        return 0;
4736}
4737
4738int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
4739{
4740        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4741        uint32_t mm_boot_level_offset, mm_boot_level_value;
4742        struct phm_ppt_v1_information *table_info =
4743                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
4744
4745        if (!bgate) {
4746                data->smc_state_table.SamuBootLevel =
4747                                (uint8_t) (table_info->mm_dep_table->count - 1);
4748                mm_boot_level_offset = data->dpm_table_start +
4749                                offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
4750                mm_boot_level_offset /= 4;
4751                mm_boot_level_offset *= 4;
4752                mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4753                                CGS_IND_REG__SMC, mm_boot_level_offset);
4754                mm_boot_level_value &= 0xFFFFFF00;
4755                mm_boot_level_value |= data->smc_state_table.SamuBootLevel << 0;
4756                cgs_write_ind_register(hwmgr->device,
4757                                CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4758
4759                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4760                                PHM_PlatformCaps_StablePState))
4761                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4762                                        PPSMC_MSG_SAMUDPM_SetEnabledMask,
4763                                        (uint32_t)(1 << data->smc_state_table.SamuBootLevel));
4764        }
4765
4766        return fiji_enable_disable_samu_dpm(hwmgr, !bgate);
4767}
4768
4769int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate)
4770{
4771        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4772        uint32_t mm_boot_level_offset, mm_boot_level_value;
4773        struct phm_ppt_v1_information *table_info =
4774                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
4775
4776        if (!bgate) {
4777                data->smc_state_table.AcpBootLevel =
4778                                (uint8_t) (table_info->mm_dep_table->count - 1);
4779                mm_boot_level_offset = data->dpm_table_start +
4780                                offsetof(SMU73_Discrete_DpmTable, AcpBootLevel);
4781                mm_boot_level_offset /= 4;
4782                mm_boot_level_offset *= 4;
4783                mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4784                                CGS_IND_REG__SMC, mm_boot_level_offset);
4785                mm_boot_level_value &= 0xFFFF00FF;
4786                mm_boot_level_value |= data->smc_state_table.AcpBootLevel << 8;
4787                cgs_write_ind_register(hwmgr->device,
4788                                CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4789
4790                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4791                                PHM_PlatformCaps_StablePState))
4792                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4793                                                PPSMC_MSG_ACPDPM_SetEnabledMask,
4794                                                (uint32_t)(1 << data->smc_state_table.AcpBootLevel));
4795        }
4796
4797        return fiji_enable_disable_acp_dpm(hwmgr, !bgate);
4798}
4799
4800static int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr)
4801{
4802        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4803
4804        int result = 0;
4805        uint32_t low_sclk_interrupt_threshold = 0;
4806
4807        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4808                        PHM_PlatformCaps_SclkThrottleLowNotification)
4809                && (hwmgr->gfx_arbiter.sclk_threshold !=
4810                                data->low_sclk_interrupt_threshold)) {
4811                data->low_sclk_interrupt_threshold =
4812                                hwmgr->gfx_arbiter.sclk_threshold;
4813                low_sclk_interrupt_threshold =
4814                                data->low_sclk_interrupt_threshold;
4815
4816                CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
4817
4818                result = fiji_copy_bytes_to_smc(
4819                                hwmgr->smumgr,
4820                                data->dpm_table_start +
4821                                offsetof(SMU73_Discrete_DpmTable,
4822                                        LowSclkInterruptThreshold),
4823                                (uint8_t *)&low_sclk_interrupt_threshold,
4824                                sizeof(uint32_t),
4825                                data->sram_end);
4826        }
4827
4828        return result;
4829}
4830
4831static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
4832{
4833        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4834
4835        if (data->need_update_smu7_dpm_table &
4836                (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
4837                return fiji_program_memory_timing_parameters(hwmgr);
4838
4839        return 0;
4840}
4841
4842static int fiji_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
4843{
4844        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4845
4846        if (0 == data->need_update_smu7_dpm_table)
4847                return 0;
4848
4849        if ((0 == data->sclk_dpm_key_disabled) &&
4850                (data->need_update_smu7_dpm_table &
4851                (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
4852
4853                PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4854                                    "Trying to Unfreeze SCLK DPM when DPM is disabled",
4855                                    );
4856                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4857                                PPSMC_MSG_SCLKDPM_UnfreezeLevel),
4858                        "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
4859                        return -1);
4860        }
4861
4862        if ((0 == data->mclk_dpm_key_disabled) &&
4863                (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
4864
4865                PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4866                                    "Trying to Unfreeze MCLK DPM when DPM is disabled",
4867                                    );
4868                PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4869                                PPSMC_MSG_SCLKDPM_UnfreezeLevel),
4870                    "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
4871                    return -1);
4872        }
4873
4874        data->need_update_smu7_dpm_table = 0;
4875
4876        return 0;
4877}
4878
4879/* Look up the voltaged based on DAL's requested level.
4880 * and then send the requested VDDC voltage to SMC
4881 */
4882static void fiji_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
4883{
4884        return;
4885}
4886
4887int fiji_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
4888{
4889        int result;
4890        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4891
4892        /* Apply minimum voltage based on DAL's request level */
4893        fiji_apply_dal_minimum_voltage_request(hwmgr);
4894
4895        if (0 == data->sclk_dpm_key_disabled) {
4896                /* Checking if DPM is running.  If we discover hang because of this,
4897                 *  we should skip this message.
4898                 */
4899                if (!fiji_is_dpm_running(hwmgr))
4900                        printk(KERN_ERR "[ powerplay ] "
4901                                        "Trying to set Enable Mask when DPM is disabled \n");
4902
4903                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
4904                        result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4905                                        PPSMC_MSG_SCLKDPM_SetEnabledMask,
4906                                        data->dpm_level_enable_mask.sclk_dpm_enable_mask);
4907                        PP_ASSERT_WITH_CODE((0 == result),
4908                                "Set Sclk Dpm enable Mask failed", return -1);
4909                }
4910        }
4911
4912        if (0 == data->mclk_dpm_key_disabled) {
4913                /* Checking if DPM is running.  If we discover hang because of this,
4914                 *  we should skip this message.
4915                 */
4916                if (!fiji_is_dpm_running(hwmgr))
4917                        printk(KERN_ERR "[ powerplay ]"
4918                                        " Trying to set Enable Mask when DPM is disabled \n");
4919
4920                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
4921                        result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4922                                        PPSMC_MSG_MCLKDPM_SetEnabledMask,
4923                                        data->dpm_level_enable_mask.mclk_dpm_enable_mask);
4924                        PP_ASSERT_WITH_CODE((0 == result),
4925                                "Set Mclk Dpm enable Mask failed", return -1);
4926                }
4927        }
4928
4929        return 0;
4930}
4931
4932static int fiji_notify_link_speed_change_after_state_change(
4933                struct pp_hwmgr *hwmgr, const void *input)
4934{
4935        const struct phm_set_power_state_input *states =
4936                        (const struct phm_set_power_state_input *)input;
4937        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4938        const struct fiji_power_state *fiji_ps =
4939                        cast_const_phw_fiji_power_state(states->pnew_state);
4940        uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_ps);
4941        uint8_t  request;
4942
4943        if (data->pspp_notify_required) {
4944                if (target_link_speed == PP_PCIEGen3)
4945                        request = PCIE_PERF_REQ_GEN3;
4946                else if (target_link_speed == PP_PCIEGen2)
4947                        request = PCIE_PERF_REQ_GEN2;
4948                else
4949                        request = PCIE_PERF_REQ_GEN1;
4950
4951                if(request == PCIE_PERF_REQ_GEN1 &&
4952                                fiji_get_current_pcie_speed(hwmgr) > 0)
4953                        return 0;
4954
4955                if (acpi_pcie_perf_request(hwmgr->device, request, false)) {
4956                        if (PP_PCIEGen2 == target_link_speed)
4957                                printk("PSPP request to switch to Gen2 from Gen3 Failed!");
4958                        else
4959                                printk("PSPP request to switch to Gen1 from Gen2 Failed!");
4960                }
4961        }
4962
4963        return 0;
4964}
4965
4966static int fiji_set_power_state_tasks(struct pp_hwmgr *hwmgr,
4967                const void *input)
4968{
4969        int tmp_result, result = 0;
4970
4971        tmp_result = fiji_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
4972        PP_ASSERT_WITH_CODE((0 == tmp_result),
4973                        "Failed to find DPM states clocks in DPM table!",
4974                        result = tmp_result);
4975
4976        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4977                        PHM_PlatformCaps_PCIEPerformanceRequest)) {
4978                tmp_result =
4979                        fiji_request_link_speed_change_before_state_change(hwmgr, input);
4980                PP_ASSERT_WITH_CODE((0 == tmp_result),
4981                                "Failed to request link speed change before state change!",
4982                                result = tmp_result);
4983        }
4984
4985        tmp_result = fiji_freeze_sclk_mclk_dpm(hwmgr);
4986        PP_ASSERT_WITH_CODE((0 == tmp_result),
4987                        "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
4988
4989        tmp_result = fiji_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
4990        PP_ASSERT_WITH_CODE((0 == tmp_result),
4991                        "Failed to populate and upload SCLK MCLK DPM levels!",
4992                        result = tmp_result);
4993
4994        tmp_result = fiji_generate_dpm_level_enable_mask(hwmgr, input);
4995        PP_ASSERT_WITH_CODE((0 == tmp_result),
4996                        "Failed to generate DPM level enabled mask!",
4997                        result = tmp_result);
4998
4999        tmp_result = fiji_update_vce_dpm(hwmgr, input);
5000        PP_ASSERT_WITH_CODE((0 == tmp_result),
5001                        "Failed to update VCE DPM!",
5002                        result = tmp_result);
5003
5004        tmp_result = fiji_update_sclk_threshold(hwmgr);
5005        PP_ASSERT_WITH_CODE((0 == tmp_result),
5006                        "Failed to update SCLK threshold!",
5007                        result = tmp_result);
5008
5009        tmp_result = fiji_program_mem_timing_parameters(hwmgr);
5010        PP_ASSERT_WITH_CODE((0 == tmp_result),
5011                        "Failed to program memory timing parameters!",
5012                        result = tmp_result);
5013
5014        tmp_result = fiji_unfreeze_sclk_mclk_dpm(hwmgr);
5015        PP_ASSERT_WITH_CODE((0 == tmp_result),
5016                        "Failed to unfreeze SCLK MCLK DPM!",
5017                        result = tmp_result);
5018
5019        tmp_result = fiji_upload_dpm_level_enable_mask(hwmgr);
5020        PP_ASSERT_WITH_CODE((0 == tmp_result),
5021                        "Failed to upload DPM level enabled mask!",
5022                        result = tmp_result);
5023
5024        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
5025                        PHM_PlatformCaps_PCIEPerformanceRequest)) {
5026                tmp_result =
5027                        fiji_notify_link_speed_change_after_state_change(hwmgr, input);
5028                PP_ASSERT_WITH_CODE((0 == tmp_result),
5029                                "Failed to notify link speed change after state change!",
5030                                result = tmp_result);
5031        }
5032
5033        return result;
5034}
5035
5036static int fiji_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
5037{
5038        struct pp_power_state  *ps;
5039        struct fiji_power_state  *fiji_ps;
5040
5041        if (hwmgr == NULL)
5042                return -EINVAL;
5043
5044        ps = hwmgr->request_ps;
5045
5046        if (ps == NULL)
5047                return -EINVAL;
5048
5049        fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5050
5051        if (low)
5052                return fiji_ps->performance_levels[0].engine_clock;
5053        else
5054                return fiji_ps->performance_levels
5055                                [fiji_ps->performance_level_count-1].engine_clock;
5056}
5057
5058static int fiji_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
5059{
5060        struct pp_power_state  *ps;
5061        struct fiji_power_state  *fiji_ps;
5062
5063        if (hwmgr == NULL)
5064                return -EINVAL;
5065
5066        ps = hwmgr->request_ps;
5067
5068        if (ps == NULL)
5069                return -EINVAL;
5070
5071        fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5072
5073        if (low)
5074                return fiji_ps->performance_levels[0].memory_clock;
5075        else
5076                return fiji_ps->performance_levels
5077                                [fiji_ps->performance_level_count-1].memory_clock;
5078}
5079
5080static void fiji_print_current_perforce_level(
5081                struct pp_hwmgr *hwmgr, struct seq_file *m)
5082{
5083        uint32_t sclk, mclk, activity_percent = 0;
5084        uint32_t offset;
5085        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5086
5087        smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
5088
5089        sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5090
5091        smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
5092
5093        mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5094        seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n",
5095                        mclk / 100, sclk / 100);
5096
5097        offset = data->soft_regs_start + offsetof(SMU73_SoftRegisters, AverageGraphicsActivity);
5098        activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
5099        activity_percent += 0x80;
5100        activity_percent >>= 8;
5101
5102        seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
5103
5104        seq_printf(m, "uvd    %sabled\n", data->uvd_power_gated ? "dis" : "en");
5105
5106        seq_printf(m, "vce    %sabled\n", data->vce_power_gated ? "dis" : "en");
5107}
5108
5109static int fiji_program_display_gap(struct pp_hwmgr *hwmgr)
5110{
5111        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5112        uint32_t num_active_displays = 0;
5113        uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
5114                        CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
5115        uint32_t display_gap2;
5116        uint32_t pre_vbi_time_in_us;
5117        uint32_t frame_time_in_us;
5118        uint32_t ref_clock;
5119        uint32_t refresh_rate = 0;
5120        struct cgs_display_info info = {0};
5121        struct cgs_mode_info mode_info;
5122
5123        info.mode_info = &mode_info;
5124
5125        cgs_get_active_displays_info(hwmgr->device, &info);
5126        num_active_displays = info.display_count;
5127
5128        display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
5129                        DISP_GAP, (num_active_displays > 0)?
5130                        DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
5131        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5132                        ixCG_DISPLAY_GAP_CNTL, display_gap);
5133
5134        ref_clock = mode_info.ref_clock;
5135        refresh_rate = mode_info.refresh_rate;
5136
5137        if (refresh_rate == 0)
5138                refresh_rate = 60;
5139
5140        frame_time_in_us = 1000000 / refresh_rate;
5141
5142        pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
5143        display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
5144
5145        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5146                        ixCG_DISPLAY_GAP_CNTL2, display_gap2);
5147
5148        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5149                        data->soft_regs_start +
5150                        offsetof(SMU73_SoftRegisters, PreVBlankGap), 0x64);
5151
5152        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5153                        data->soft_regs_start +
5154                        offsetof(SMU73_SoftRegisters, VBlankTimeout),
5155                        (frame_time_in_us - pre_vbi_time_in_us));
5156
5157        if (num_active_displays == 1)
5158                tonga_notify_smc_display_change(hwmgr, true);
5159
5160        return 0;
5161}
5162
5163int fiji_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
5164{
5165        return fiji_program_display_gap(hwmgr);
5166}
5167
5168static int fiji_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr,
5169                uint16_t us_max_fan_pwm)
5170{
5171        hwmgr->thermal_controller.
5172        advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
5173
5174        if (phm_is_hw_access_blocked(hwmgr))
5175                return 0;
5176
5177        return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5178                        PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
5179}
5180
5181static int fiji_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr,
5182                uint16_t us_max_fan_rpm)
5183{
5184        hwmgr->thermal_controller.
5185        advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
5186
5187        if (phm_is_hw_access_blocked(hwmgr))
5188                return 0;
5189
5190        return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5191                        PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
5192}
5193
5194int fiji_dpm_set_interrupt_state(void *private_data,
5195                                         unsigned src_id, unsigned type,
5196                                         int enabled)
5197{
5198        uint32_t cg_thermal_int;
5199        struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
5200
5201        if (hwmgr == NULL)
5202                return -EINVAL;
5203
5204        switch (type) {
5205        case AMD_THERMAL_IRQ_LOW_TO_HIGH:
5206                if (enabled) {
5207                        cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5208                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5209                        cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
5210                        cgs_write_ind_register(hwmgr->device,
5211                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5212                } else {
5213                        cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5214                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5215                        cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
5216                        cgs_write_ind_register(hwmgr->device,
5217                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5218                }
5219                break;
5220
5221        case AMD_THERMAL_IRQ_HIGH_TO_LOW:
5222                if (enabled) {
5223                        cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5224                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5225                        cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
5226                        cgs_write_ind_register(hwmgr->device,
5227                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5228                } else {
5229                        cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5230                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5231                        cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
5232                        cgs_write_ind_register(hwmgr->device,
5233                                        CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5234                }
5235                break;
5236        default:
5237                break;
5238        }
5239        return 0;
5240}
5241
5242int fiji_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
5243                                        const void *thermal_interrupt_info)
5244{
5245        int result;
5246        const struct pp_interrupt_registration_info *info =
5247                        (const struct pp_interrupt_registration_info *)
5248                        thermal_interrupt_info;
5249
5250        if (info == NULL)
5251                return -EINVAL;
5252
5253        result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
5254                                fiji_dpm_set_interrupt_state,
5255                                info->call_back, info->context);
5256
5257        if (result)
5258                return -EINVAL;
5259
5260        result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
5261                                fiji_dpm_set_interrupt_state,
5262                                info->call_back, info->context);
5263
5264        if (result)
5265                return -EINVAL;
5266
5267        return 0;
5268}
5269
5270static int fiji_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
5271{
5272        if (mode) {
5273                /* stop auto-manage */
5274                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
5275                                PHM_PlatformCaps_MicrocodeFanControl))
5276                        fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
5277                fiji_fan_ctrl_set_static_mode(hwmgr, mode);
5278        } else
5279                /* restart auto-manage */
5280                fiji_fan_ctrl_reset_fan_speed_to_default(hwmgr);
5281
5282        return 0;
5283}
5284
5285static int fiji_get_fan_control_mode(struct pp_hwmgr *hwmgr)
5286{
5287        if (hwmgr->fan_ctrl_is_in_default_mode)
5288                return hwmgr->fan_ctrl_default_mode;
5289        else
5290                return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
5291                                CG_FDO_CTRL2, FDO_PWM_MODE);
5292}
5293
5294static int fiji_force_clock_level(struct pp_hwmgr *hwmgr,
5295                enum pp_clock_type type, uint32_t mask)
5296{
5297        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5298
5299        if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
5300                return -EINVAL;
5301
5302        switch (type) {
5303        case PP_SCLK:
5304                if (!data->sclk_dpm_key_disabled)
5305                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5306                                        PPSMC_MSG_SCLKDPM_SetEnabledMask,
5307                                        data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
5308                break;
5309
5310        case PP_MCLK:
5311                if (!data->mclk_dpm_key_disabled)
5312                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5313                                        PPSMC_MSG_MCLKDPM_SetEnabledMask,
5314                                        data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
5315                break;
5316
5317        case PP_PCIE:
5318        {
5319                uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
5320                uint32_t level = 0;
5321
5322                while (tmp >>= 1)
5323                        level++;
5324
5325                if (!data->pcie_dpm_key_disabled)
5326                        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5327                                        PPSMC_MSG_PCIeDPM_ForceLevel,
5328                                        level);
5329                break;
5330        }
5331        default:
5332                break;
5333        }
5334
5335        return 0;
5336}
5337
5338static int fiji_print_clock_levels(struct pp_hwmgr *hwmgr,
5339                enum pp_clock_type type, char *buf)
5340{
5341        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5342        struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
5343        struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
5344        struct fiji_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table);
5345        int i, now, size = 0;
5346        uint32_t clock, pcie_speed;
5347
5348        switch (type) {
5349        case PP_SCLK:
5350                smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
5351                clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5352
5353                for (i = 0; i < sclk_table->count; i++) {
5354                        if (clock > sclk_table->dpm_levels[i].value)
5355                                continue;
5356                        break;
5357                }
5358                now = i;
5359
5360                for (i = 0; i < sclk_table->count; i++)
5361                        size += sprintf(buf + size, "%d: %uMhz %s\n",
5362                                        i, sclk_table->dpm_levels[i].value / 100,
5363                                        (i == now) ? "*" : "");
5364                break;
5365        case PP_MCLK:
5366                smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
5367                clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5368
5369                for (i = 0; i < mclk_table->count; i++) {
5370                        if (clock > mclk_table->dpm_levels[i].value)
5371                                continue;
5372                        break;
5373                }
5374                now = i;
5375
5376                for (i = 0; i < mclk_table->count; i++)
5377                        size += sprintf(buf + size, "%d: %uMhz %s\n",
5378                                        i, mclk_table->dpm_levels[i].value / 100,
5379                                        (i == now) ? "*" : "");
5380                break;
5381        case PP_PCIE:
5382                pcie_speed = fiji_get_current_pcie_speed(hwmgr);
5383                for (i = 0; i < pcie_table->count; i++) {
5384                        if (pcie_speed != pcie_table->dpm_levels[i].value)
5385                                continue;
5386                        break;
5387                }
5388                now = i;
5389
5390                for (i = 0; i < pcie_table->count; i++)
5391                        size += sprintf(buf + size, "%d: %s %s\n", i,
5392                                        (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x1" :
5393                                        (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" :
5394                                        (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "",
5395                                        (i == now) ? "*" : "");
5396                break;
5397        default:
5398                break;
5399        }
5400        return size;
5401}
5402
5403static inline bool fiji_are_power_levels_equal(const struct fiji_performance_level *pl1,
5404                                                           const struct fiji_performance_level *pl2)
5405{
5406        return ((pl1->memory_clock == pl2->memory_clock) &&
5407                  (pl1->engine_clock == pl2->engine_clock) &&
5408                  (pl1->pcie_gen == pl2->pcie_gen) &&
5409                  (pl1->pcie_lane == pl2->pcie_lane));
5410}
5411
5412int fiji_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
5413{
5414        const struct fiji_power_state *psa = cast_const_phw_fiji_power_state(pstate1);
5415        const struct fiji_power_state *psb = cast_const_phw_fiji_power_state(pstate2);
5416        int i;
5417
5418        if (equal == NULL || psa == NULL || psb == NULL)
5419                return -EINVAL;
5420
5421        /* If the two states don't even have the same number of performance levels they cannot be the same state. */
5422        if (psa->performance_level_count != psb->performance_level_count) {
5423                *equal = false;
5424                return 0;
5425        }
5426
5427        for (i = 0; i < psa->performance_level_count; i++) {
5428                if (!fiji_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
5429                        /* If we have found even one performance level pair that is different the states are different. */
5430                        *equal = false;
5431                        return 0;
5432                }
5433        }
5434
5435        /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5436        *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk));
5437        *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk));
5438        *equal &= (psa->sclk_threshold == psb->sclk_threshold);
5439        *equal &= (psa->acp_clk == psb->acp_clk);
5440
5441        return 0;
5442}
5443
5444bool fiji_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
5445{
5446        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5447        bool is_update_required = false;
5448        struct cgs_display_info info = {0,0,NULL};
5449
5450        cgs_get_active_displays_info(hwmgr->device, &info);
5451
5452        if (data->display_timing.num_existing_displays != info.display_count)
5453                is_update_required = true;
5454
5455        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
5456                if(hwmgr->display_config.min_core_set_clock_in_sr != data->display_timing.min_clock_in_sr)
5457                        is_update_required = true;
5458        }
5459
5460        return is_update_required;
5461}
5462
5463static int fiji_get_sclk_od(struct pp_hwmgr *hwmgr)
5464{
5465        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5466        struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
5467        struct fiji_single_dpm_table *golden_sclk_table =
5468                        &(data->golden_dpm_table.sclk_table);
5469        int value;
5470
5471        value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
5472                        golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
5473                        100 /
5474                        golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
5475
5476        return value;
5477}
5478
5479static int fiji_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
5480{
5481        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5482        struct fiji_single_dpm_table *golden_sclk_table =
5483                        &(data->golden_dpm_table.sclk_table);
5484        struct pp_power_state  *ps;
5485        struct fiji_power_state  *fiji_ps;
5486
5487        if (value > 20)
5488                value = 20;
5489
5490        ps = hwmgr->request_ps;
5491
5492        if (ps == NULL)
5493                return -EINVAL;
5494
5495        fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5496
5497        fiji_ps->performance_levels[fiji_ps->performance_level_count - 1].engine_clock =
5498                        golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
5499                        value / 100 +
5500                        golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
5501
5502        return 0;
5503}
5504
5505static int fiji_get_mclk_od(struct pp_hwmgr *hwmgr)
5506{
5507        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5508        struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
5509        struct fiji_single_dpm_table *golden_mclk_table =
5510                        &(data->golden_dpm_table.mclk_table);
5511        int value;
5512
5513        value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
5514                        golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
5515                        100 /
5516                        golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
5517
5518        return value;
5519}
5520
5521static int fiji_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
5522{
5523        struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5524        struct fiji_single_dpm_table *golden_mclk_table =
5525                        &(data->golden_dpm_table.mclk_table);
5526        struct pp_power_state  *ps;
5527        struct fiji_power_state  *fiji_ps;
5528
5529        if (value > 20)
5530                value = 20;
5531
5532        ps = hwmgr->request_ps;
5533
5534        if (ps == NULL)
5535                return -EINVAL;
5536
5537        fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5538
5539        fiji_ps->performance_levels[fiji_ps->performance_level_count - 1].memory_clock =
5540                        golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
5541                        value / 100 +
5542                        golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
5543
5544        return 0;
5545}
5546
5547static const struct pp_hwmgr_func fiji_hwmgr_funcs = {
5548        .backend_init = &fiji_hwmgr_backend_init,
5549        .backend_fini = &fiji_hwmgr_backend_fini,
5550        .asic_setup = &fiji_setup_asic_task,
5551        .dynamic_state_management_enable = &fiji_enable_dpm_tasks,
5552        .dynamic_state_management_disable = &fiji_disable_dpm_tasks,
5553        .force_dpm_level = &fiji_dpm_force_dpm_level,
5554        .get_num_of_pp_table_entries = &tonga_get_number_of_powerplay_table_entries,
5555        .get_power_state_size = &fiji_get_power_state_size,
5556        .get_pp_table_entry = &fiji_get_pp_table_entry,
5557        .patch_boot_state = &fiji_patch_boot_state,
5558        .apply_state_adjust_rules = &fiji_apply_state_adjust_rules,
5559        .power_state_set = &fiji_set_power_state_tasks,
5560        .get_sclk = &fiji_dpm_get_sclk,
5561        .get_mclk = &fiji_dpm_get_mclk,
5562        .print_current_perforce_level = &fiji_print_current_perforce_level,
5563        .powergate_uvd = &fiji_phm_powergate_uvd,
5564        .powergate_vce = &fiji_phm_powergate_vce,
5565        .disable_clock_power_gating = &fiji_phm_disable_clock_power_gating,
5566        .notify_smc_display_config_after_ps_adjustment =
5567                        &tonga_notify_smc_display_config_after_ps_adjustment,
5568        .display_config_changed = &fiji_display_configuration_changed_task,
5569        .set_max_fan_pwm_output = fiji_set_max_fan_pwm_output,
5570        .set_max_fan_rpm_output = fiji_set_max_fan_rpm_output,
5571        .get_temperature = fiji_thermal_get_temperature,
5572        .stop_thermal_controller = fiji_thermal_stop_thermal_controller,
5573        .get_fan_speed_info = fiji_fan_ctrl_get_fan_speed_info,
5574        .get_fan_speed_percent = fiji_fan_ctrl_get_fan_speed_percent,
5575        .set_fan_speed_percent = fiji_fan_ctrl_set_fan_speed_percent,
5576        .reset_fan_speed_to_default = fiji_fan_ctrl_reset_fan_speed_to_default,
5577        .get_fan_speed_rpm = fiji_fan_ctrl_get_fan_speed_rpm,
5578        .set_fan_speed_rpm = fiji_fan_ctrl_set_fan_speed_rpm,
5579        .uninitialize_thermal_controller = fiji_thermal_ctrl_uninitialize_thermal_controller,
5580        .register_internal_thermal_interrupt = fiji_register_internal_thermal_interrupt,
5581        .set_fan_control_mode = fiji_set_fan_control_mode,
5582        .get_fan_control_mode = fiji_get_fan_control_mode,
5583        .check_states_equal = fiji_check_states_equal,
5584        .check_smc_update_required_for_display_configuration = fiji_check_smc_update_required_for_display_configuration,
5585        .force_clock_level = fiji_force_clock_level,
5586        .print_clock_levels = fiji_print_clock_levels,
5587        .get_sclk_od = fiji_get_sclk_od,
5588        .set_sclk_od = fiji_set_sclk_od,
5589        .get_mclk_od = fiji_get_mclk_od,
5590        .set_mclk_od = fiji_set_mclk_od,
5591};
5592
5593int fiji_hwmgr_init(struct pp_hwmgr *hwmgr)
5594{
5595        hwmgr->hwmgr_func = &fiji_hwmgr_funcs;
5596        hwmgr->pptable_func = &tonga_pptable_funcs;
5597        pp_fiji_thermal_initialize(hwmgr);
5598        return 0;
5599}
5600