linux/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   8 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   9 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  10 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  11 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  12 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  13 * OTHER DEALINGS IN THE SOFTWARE.
  14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15 * and/or sell copies of the Software, and to permit persons to whom the
  16 * Software is furnished to do so, subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in
  19 * all copies or substantial portions of the Software.
  20 *
  21 *
  22 */
  23
  24#include "iceland_smc.h"
  25#include "smu7_dyn_defaults.h"
  26
  27#include "smu7_hwmgr.h"
  28#include "hardwaremanager.h"
  29#include "ppatomctrl.h"
  30#include "pp_debug.h"
  31#include "cgs_common.h"
  32#include "atombios.h"
  33#include "pppcielanes.h"
  34#include "pp_endian.h"
  35#include "smu7_ppsmc.h"
  36
  37#include "smu71_discrete.h"
  38
  39#include "smu/smu_7_1_1_d.h"
  40#include "smu/smu_7_1_1_sh_mask.h"
  41
  42#include "gmc/gmc_8_1_d.h"
  43#include "gmc/gmc_8_1_sh_mask.h"
  44
  45#include "bif/bif_5_0_d.h"
  46#include "bif/bif_5_0_sh_mask.h"
  47
  48#include "dce/dce_10_0_d.h"
  49#include "dce/dce_10_0_sh_mask.h"
  50#include "processpptables.h"
  51
  52#include "iceland_smumgr.h"
  53
  54#define VOLTAGE_SCALE 4
  55#define POWERTUNE_DEFAULT_SET_MAX    1
  56#define VOLTAGE_VID_OFFSET_SCALE1   625
  57#define VOLTAGE_VID_OFFSET_SCALE2   100
  58#define MC_CG_ARB_FREQ_F1           0x0b
  59#define VDDC_VDDCI_DELTA            200
  60
  61#define DEVICE_ID_VI_ICELAND_M_6900     0x6900
  62#define DEVICE_ID_VI_ICELAND_M_6901     0x6901
  63#define DEVICE_ID_VI_ICELAND_M_6902     0x6902
  64#define DEVICE_ID_VI_ICELAND_M_6903     0x6903
  65
  66static const struct iceland_pt_defaults defaults_iceland = {
  67        /*
  68         * sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc,
  69         * TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT
  70         */
  71        1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
  72        { 0x79,  0x253, 0x25D, 0xAE,  0x72,  0x80,  0x83,  0x86,  0x6F,  0xC8,  0xC9,  0xC9,  0x2F,  0x4D,  0x61  },
  73        { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
  74};
  75
  76/* 35W - XT, XTL */
  77static const struct iceland_pt_defaults defaults_icelandxt = {
  78        /*
  79         * sviLoadLIneEn, SviLoadLineVddC,
  80         * TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
  81         * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
  82         * BAPM_TEMP_GRADIENT
  83         */
  84        1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
  85        { 0xA7,  0x0, 0x0, 0xB5,  0x0, 0x0, 0x9F,  0x0, 0x0, 0xD6,  0x0, 0x0, 0xD7,  0x0, 0x0},
  86        { 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
  87};
  88
  89/* 25W - PRO, LE */
  90static const struct iceland_pt_defaults defaults_icelandpro = {
  91        /*
  92         * sviLoadLIneEn, SviLoadLineVddC,
  93         * TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
  94         * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
  95         * BAPM_TEMP_GRADIENT
  96         */
  97        1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
  98        { 0xB7,  0x0, 0x0, 0xC3,  0x0, 0x0, 0xB5,  0x0, 0x0, 0xEA,  0x0, 0x0, 0xE6,  0x0, 0x0},
  99        { 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
 100};
 101
 102static void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
 103{
 104        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 105        struct cgs_system_info sys_info = {0};
 106        uint32_t dev_id;
 107
 108        sys_info.size = sizeof(struct cgs_system_info);
 109        sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV;
 110        cgs_query_system_info(hwmgr->device, &sys_info);
 111        dev_id = (uint32_t)sys_info.value;
 112
 113        switch (dev_id) {
 114        case DEVICE_ID_VI_ICELAND_M_6900:
 115        case DEVICE_ID_VI_ICELAND_M_6903:
 116                smu_data->power_tune_defaults = &defaults_icelandxt;
 117                break;
 118
 119        case DEVICE_ID_VI_ICELAND_M_6901:
 120        case DEVICE_ID_VI_ICELAND_M_6902:
 121                smu_data->power_tune_defaults = &defaults_icelandpro;
 122                break;
 123        default:
 124                smu_data->power_tune_defaults = &defaults_iceland;
 125                pr_warning("Unknown V.I. Device ID.\n");
 126                break;
 127        }
 128        return;
 129}
 130
 131static int iceland_populate_svi_load_line(struct pp_hwmgr *hwmgr)
 132{
 133        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 134        const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
 135
 136        smu_data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
 137        smu_data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddc;
 138        smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
 139        smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
 140
 141        return 0;
 142}
 143
 144static int iceland_populate_tdc_limit(struct pp_hwmgr *hwmgr)
 145{
 146        uint16_t tdc_limit;
 147        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 148        const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
 149
 150        tdc_limit = (uint16_t)(hwmgr->dyn_state.cac_dtp_table->usTDC * 256);
 151        smu_data->power_tune_table.TDC_VDDC_PkgLimit =
 152                        CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
 153        smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
 154                        defaults->tdc_vddc_throttle_release_limit_perc;
 155        smu_data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
 156
 157        return 0;
 158}
 159
 160static int iceland_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
 161{
 162        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 163        const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
 164        uint32_t temp;
 165
 166        if (smu7_read_smc_sram_dword(hwmgr->smumgr,
 167                        fuse_table_offset +
 168                        offsetof(SMU71_Discrete_PmFuses, TdcWaterfallCtl),
 169                        (uint32_t *)&temp, SMC_RAM_END))
 170                PP_ASSERT_WITH_CODE(false,
 171                                "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
 172                                return -EINVAL);
 173        else
 174                smu_data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
 175
 176        return 0;
 177}
 178
 179static int iceland_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
 180{
 181        return 0;
 182}
 183
 184static int iceland_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
 185{
 186        int i;
 187        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 188
 189        /* Currently not used. Set all to zero. */
 190        for (i = 0; i < 8; i++)
 191                smu_data->power_tune_table.GnbLPML[i] = 0;
 192
 193        return 0;
 194}
 195
 196static int iceland_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
 197{
 198        return 0;
 199}
 200
 201static int iceland_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
 202{
 203        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 204        uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
 205        uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
 206        struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
 207
 208        HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
 209        LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
 210
 211        smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
 212                        CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
 213        smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
 214                        CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
 215
 216        return 0;
 217}
 218
 219static int iceland_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr)
 220{
 221        int i;
 222        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 223        uint8_t *hi_vid = smu_data->power_tune_table.BapmVddCVidHiSidd;
 224        uint8_t *lo_vid = smu_data->power_tune_table.BapmVddCVidLoSidd;
 225
 226        PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.cac_leakage_table,
 227                            "The CAC Leakage table does not exist!", return -EINVAL);
 228        PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count <= 8,
 229                            "There should never be more than 8 entries for BapmVddcVid!!!", return -EINVAL);
 230        PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count == hwmgr->dyn_state.vddc_dependency_on_sclk->count,
 231                            "CACLeakageTable->count and VddcDependencyOnSCLk->count not equal", return -EINVAL);
 232
 233        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EVV)) {
 234                for (i = 0; (uint32_t) i < hwmgr->dyn_state.cac_leakage_table->count; i++) {
 235                        lo_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc1);
 236                        hi_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc2);
 237                }
 238        } else {
 239                PP_ASSERT_WITH_CODE(false, "Iceland should always support EVV", return -EINVAL);
 240        }
 241
 242        return 0;
 243}
 244
 245static int iceland_populate_vddc_vid(struct pp_hwmgr *hwmgr)
 246{
 247        int i;
 248        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 249        uint8_t *vid = smu_data->power_tune_table.VddCVid;
 250        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 251
 252        PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 8,
 253                "There should never be more than 8 entries for VddcVid!!!",
 254                return -EINVAL);
 255
 256        for (i = 0; i < (int)data->vddc_voltage_table.count; i++) {
 257                vid[i] = convert_to_vid(data->vddc_voltage_table.entries[i].value);
 258        }
 259
 260        return 0;
 261}
 262
 263
 264
 265static int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr)
 266{
 267        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 268        uint32_t pm_fuse_table_offset;
 269
 270        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 271                        PHM_PlatformCaps_PowerContainment)) {
 272                if (smu7_read_smc_sram_dword(hwmgr->smumgr,
 273                                SMU71_FIRMWARE_HEADER_LOCATION +
 274                                offsetof(SMU71_Firmware_Header, PmFuseTable),
 275                                &pm_fuse_table_offset, SMC_RAM_END))
 276                        PP_ASSERT_WITH_CODE(false,
 277                                        "Attempt to get pm_fuse_table_offset Failed!",
 278                                        return -EINVAL);
 279
 280                /* DW0 - DW3 */
 281                if (iceland_populate_bapm_vddc_vid_sidd(hwmgr))
 282                        PP_ASSERT_WITH_CODE(false,
 283                                        "Attempt to populate bapm vddc vid Failed!",
 284                                        return -EINVAL);
 285
 286                /* DW4 - DW5 */
 287                if (iceland_populate_vddc_vid(hwmgr))
 288                        PP_ASSERT_WITH_CODE(false,
 289                                        "Attempt to populate vddc vid Failed!",
 290                                        return -EINVAL);
 291
 292                /* DW6 */
 293                if (iceland_populate_svi_load_line(hwmgr))
 294                        PP_ASSERT_WITH_CODE(false,
 295                                        "Attempt to populate SviLoadLine Failed!",
 296                                        return -EINVAL);
 297                /* DW7 */
 298                if (iceland_populate_tdc_limit(hwmgr))
 299                        PP_ASSERT_WITH_CODE(false,
 300                                        "Attempt to populate TDCLimit Failed!", return -EINVAL);
 301                /* DW8 */
 302                if (iceland_populate_dw8(hwmgr, pm_fuse_table_offset))
 303                        PP_ASSERT_WITH_CODE(false,
 304                                        "Attempt to populate TdcWaterfallCtl, "
 305                                        "LPMLTemperature Min and Max Failed!",
 306                                        return -EINVAL);
 307
 308                /* DW9-DW12 */
 309                if (0 != iceland_populate_temperature_scaler(hwmgr))
 310                        PP_ASSERT_WITH_CODE(false,
 311                                        "Attempt to populate LPMLTemperatureScaler Failed!",
 312                                        return -EINVAL);
 313
 314                /* DW13-DW16 */
 315                if (iceland_populate_gnb_lpml(hwmgr))
 316                        PP_ASSERT_WITH_CODE(false,
 317                                        "Attempt to populate GnbLPML Failed!",
 318                                        return -EINVAL);
 319
 320                /* DW17 */
 321                if (iceland_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
 322                        PP_ASSERT_WITH_CODE(false,
 323                                        "Attempt to populate GnbLPML Min and Max Vid Failed!",
 324                                        return -EINVAL);
 325
 326                /* DW18 */
 327                if (iceland_populate_bapm_vddc_base_leakage_sidd(hwmgr))
 328                        PP_ASSERT_WITH_CODE(false,
 329                                        "Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!",
 330                                        return -EINVAL);
 331
 332                if (smu7_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
 333                                (uint8_t *)&smu_data->power_tune_table,
 334                                sizeof(struct SMU71_Discrete_PmFuses), SMC_RAM_END))
 335                        PP_ASSERT_WITH_CODE(false,
 336                                        "Attempt to download PmFuseTable Failed!",
 337                                        return -EINVAL);
 338        }
 339        return 0;
 340}
 341
 342static int iceland_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr,
 343        struct phm_clock_voltage_dependency_table *allowed_clock_voltage_table,
 344        uint32_t clock, uint32_t *vol)
 345{
 346        uint32_t i = 0;
 347
 348        /* clock - voltage dependency table is empty table */
 349        if (allowed_clock_voltage_table->count == 0)
 350                return -EINVAL;
 351
 352        for (i = 0; i < allowed_clock_voltage_table->count; i++) {
 353                /* find first sclk bigger than request */
 354                if (allowed_clock_voltage_table->entries[i].clk >= clock) {
 355                        *vol = allowed_clock_voltage_table->entries[i].v;
 356                        return 0;
 357                }
 358        }
 359
 360        /* sclk is bigger than max sclk in the dependence table */
 361        *vol = allowed_clock_voltage_table->entries[i - 1].v;
 362
 363        return 0;
 364}
 365
 366static int iceland_get_std_voltage_value_sidd(struct pp_hwmgr *hwmgr,
 367                pp_atomctrl_voltage_table_entry *tab, uint16_t *hi,
 368                uint16_t *lo)
 369{
 370        uint16_t v_index;
 371        bool vol_found = false;
 372        *hi = tab->value * VOLTAGE_SCALE;
 373        *lo = tab->value * VOLTAGE_SCALE;
 374
 375        /* SCLK/VDDC Dependency Table has to exist. */
 376        PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.vddc_dependency_on_sclk,
 377                        "The SCLK/VDDC Dependency Table does not exist.\n",
 378                        return -EINVAL);
 379
 380        if (NULL == hwmgr->dyn_state.cac_leakage_table) {
 381                pr_warning("CAC Leakage Table does not exist, using vddc.\n");
 382                return 0;
 383        }
 384
 385        /*
 386         * Since voltage in the sclk/vddc dependency table is not
 387         * necessarily in ascending order because of ELB voltage
 388         * patching, loop through entire list to find exact voltage.
 389         */
 390        for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
 391                if (tab->value == hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
 392                        vol_found = true;
 393                        if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
 394                                *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
 395                                *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage * VOLTAGE_SCALE);
 396                        } else {
 397                                pr_warning("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index, using maximum index from CAC table.\n");
 398                                *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
 399                                *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
 400                        }
 401                        break;
 402                }
 403        }
 404
 405        /*
 406         * If voltage is not found in the first pass, loop again to
 407         * find the best match, equal or higher value.
 408         */
 409        if (!vol_found) {
 410                for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
 411                        if (tab->value <= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
 412                                vol_found = true;
 413                                if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
 414                                        *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
 415                                        *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage) * VOLTAGE_SCALE;
 416                                } else {
 417                                        pr_warning("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index in second look up, using maximum index from CAC table.");
 418                                        *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
 419                                        *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
 420                                }
 421                                break;
 422                        }
 423                }
 424
 425                if (!vol_found)
 426                        pr_warning("Unable to get std_vddc from SCLK/VDDC Dependency Table, using vddc.\n");
 427        }
 428
 429        return 0;
 430}
 431
 432static int iceland_populate_smc_voltage_table(struct pp_hwmgr *hwmgr,
 433                pp_atomctrl_voltage_table_entry *tab,
 434                SMU71_Discrete_VoltageLevel *smc_voltage_tab)
 435{
 436        int result;
 437
 438        result = iceland_get_std_voltage_value_sidd(hwmgr, tab,
 439                        &smc_voltage_tab->StdVoltageHiSidd,
 440                        &smc_voltage_tab->StdVoltageLoSidd);
 441        if (0 != result) {
 442                smc_voltage_tab->StdVoltageHiSidd = tab->value * VOLTAGE_SCALE;
 443                smc_voltage_tab->StdVoltageLoSidd = tab->value * VOLTAGE_SCALE;
 444        }
 445
 446        smc_voltage_tab->Voltage = PP_HOST_TO_SMC_US(tab->value * VOLTAGE_SCALE);
 447        CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd);
 448        CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd);
 449
 450        return 0;
 451}
 452
 453static int iceland_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
 454                        SMU71_Discrete_DpmTable *table)
 455{
 456        unsigned int count;
 457        int result;
 458        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 459
 460        table->VddcLevelCount = data->vddc_voltage_table.count;
 461        for (count = 0; count < table->VddcLevelCount; count++) {
 462                result = iceland_populate_smc_voltage_table(hwmgr,
 463                                &(data->vddc_voltage_table.entries[count]),
 464                                &(table->VddcLevel[count]));
 465                PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDC voltage table", return -EINVAL);
 466
 467                /* GPIO voltage control */
 468                if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control)
 469                        table->VddcLevel[count].Smio |= data->vddc_voltage_table.entries[count].smio_low;
 470                else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control)
 471                        table->VddcLevel[count].Smio = 0;
 472        }
 473
 474        CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
 475
 476        return 0;
 477}
 478
 479static int iceland_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
 480                        SMU71_Discrete_DpmTable *table)
 481{
 482        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 483        uint32_t count;
 484        int result;
 485
 486        table->VddciLevelCount = data->vddci_voltage_table.count;
 487
 488        for (count = 0; count < table->VddciLevelCount; count++) {
 489                result = iceland_populate_smc_voltage_table(hwmgr,
 490                                &(data->vddci_voltage_table.entries[count]),
 491                                &(table->VddciLevel[count]));
 492                PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC VDDCI voltage table", return -EINVAL);
 493                if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
 494                        table->VddciLevel[count].Smio |= data->vddci_voltage_table.entries[count].smio_low;
 495                else
 496                        table->VddciLevel[count].Smio |= 0;
 497        }
 498
 499        CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
 500
 501        return 0;
 502}
 503
 504static int iceland_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
 505                        SMU71_Discrete_DpmTable *table)
 506{
 507        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 508        uint32_t count;
 509        int result;
 510
 511        table->MvddLevelCount = data->mvdd_voltage_table.count;
 512
 513        for (count = 0; count < table->VddciLevelCount; count++) {
 514                result = iceland_populate_smc_voltage_table(hwmgr,
 515                                &(data->mvdd_voltage_table.entries[count]),
 516                                &table->MvddLevel[count]);
 517                PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC mvdd voltage table", return -EINVAL);
 518                if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control)
 519                        table->MvddLevel[count].Smio |= data->mvdd_voltage_table.entries[count].smio_low;
 520                else
 521                        table->MvddLevel[count].Smio |= 0;
 522        }
 523
 524        CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
 525
 526        return 0;
 527}
 528
 529
 530static int iceland_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
 531        SMU71_Discrete_DpmTable *table)
 532{
 533        int result;
 534
 535        result = iceland_populate_smc_vddc_table(hwmgr, table);
 536        PP_ASSERT_WITH_CODE(0 == result,
 537                        "can not populate VDDC voltage table to SMC", return -EINVAL);
 538
 539        result = iceland_populate_smc_vdd_ci_table(hwmgr, table);
 540        PP_ASSERT_WITH_CODE(0 == result,
 541                        "can not populate VDDCI voltage table to SMC", return -EINVAL);
 542
 543        result = iceland_populate_smc_mvdd_table(hwmgr, table);
 544        PP_ASSERT_WITH_CODE(0 == result,
 545                        "can not populate MVDD voltage table to SMC", return -EINVAL);
 546
 547        return 0;
 548}
 549
 550static int iceland_populate_ulv_level(struct pp_hwmgr *hwmgr,
 551                struct SMU71_Discrete_Ulv *state)
 552{
 553        uint32_t voltage_response_time, ulv_voltage;
 554        int result;
 555        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 556
 557        state->CcPwrDynRm = 0;
 558        state->CcPwrDynRm1 = 0;
 559
 560        result = pp_tables_get_response_times(hwmgr, &voltage_response_time, &ulv_voltage);
 561        PP_ASSERT_WITH_CODE((0 == result), "can not get ULV voltage value", return result;);
 562
 563        if (ulv_voltage == 0) {
 564                data->ulv_supported = false;
 565                return 0;
 566        }
 567
 568        if (data->voltage_control != SMU7_VOLTAGE_CONTROL_BY_SVID2) {
 569                /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
 570                if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
 571                        state->VddcOffset = 0;
 572                else
 573                        /* used in SMIO Mode. not implemented for now. this is backup only for CI. */
 574                        state->VddcOffset = (uint16_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage);
 575        } else {
 576                /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
 577                if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
 578                        state->VddcOffsetVid = 0;
 579                else  /* used in SVI2 Mode */
 580                        state->VddcOffsetVid = (uint8_t)(
 581                                        (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage)
 582                                                * VOLTAGE_VID_OFFSET_SCALE2
 583                                                / VOLTAGE_VID_OFFSET_SCALE1);
 584        }
 585        state->VddcPhase = 1;
 586
 587        CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
 588        CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
 589        CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
 590
 591        return 0;
 592}
 593
 594static int iceland_populate_ulv_state(struct pp_hwmgr *hwmgr,
 595                 SMU71_Discrete_Ulv *ulv_level)
 596{
 597        return iceland_populate_ulv_level(hwmgr, ulv_level);
 598}
 599
 600static int iceland_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU71_Discrete_DpmTable *table)
 601{
 602        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 603        struct smu7_dpm_table *dpm_table = &data->dpm_table;
 604        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 605        uint32_t i;
 606
 607        /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
 608        for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
 609                table->LinkLevel[i].PcieGenSpeed  =
 610                        (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
 611                table->LinkLevel[i].PcieLaneCount =
 612                        (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
 613                table->LinkLevel[i].EnabledForActivity =
 614                        1;
 615                table->LinkLevel[i].SPC =
 616                        (uint8_t)(data->pcie_spc_cap & 0xff);
 617                table->LinkLevel[i].DownThreshold =
 618                        PP_HOST_TO_SMC_UL(5);
 619                table->LinkLevel[i].UpThreshold =
 620                        PP_HOST_TO_SMC_UL(30);
 621        }
 622
 623        smu_data->smc_state_table.LinkLevelCount =
 624                (uint8_t)dpm_table->pcie_speed_table.count;
 625        data->dpm_level_enable_mask.pcie_dpm_enable_mask =
 626                phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
 627
 628        return 0;
 629}
 630
 631/**
 632 * Calculates the SCLK dividers using the provided engine clock
 633 *
 634 * @param    hwmgr      the address of the hardware manager
 635 * @param    engine_clock the engine clock to use to populate the structure
 636 * @param    sclk        the SMC SCLK structure to be populated
 637 */
 638static int iceland_calculate_sclk_params(struct pp_hwmgr *hwmgr,
 639                uint32_t engine_clock, SMU71_Discrete_GraphicsLevel *sclk)
 640{
 641        const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 642        pp_atomctrl_clock_dividers_vi dividers;
 643        uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
 644        uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
 645        uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
 646        uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
 647        uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
 648        uint32_t    reference_clock;
 649        uint32_t reference_divider;
 650        uint32_t fbdiv;
 651        int result;
 652
 653        /* get the engine clock dividers for this clock value*/
 654        result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
 655
 656        PP_ASSERT_WITH_CODE(result == 0,
 657                "Error retrieving Engine Clock dividers from VBIOS.", return result);
 658
 659        /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
 660        reference_clock = atomctrl_get_reference_clock(hwmgr);
 661
 662        reference_divider = 1 + dividers.uc_pll_ref_div;
 663
 664        /* low 14 bits is fraction and high 12 bits is divider*/
 665        fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
 666
 667        /* SPLL_FUNC_CNTL setup*/
 668        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
 669                CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
 670        spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
 671                CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
 672
 673        /* SPLL_FUNC_CNTL_3 setup*/
 674        spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
 675                CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
 676
 677        /* set to use fractional accumulation*/
 678        spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
 679                CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
 680
 681        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 682                        PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
 683                pp_atomctrl_internal_ss_info ss_info;
 684
 685                uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
 686                if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
 687                        /*
 688                        * ss_info.speed_spectrum_percentage -- in unit of 0.01%
 689                        * ss_info.speed_spectrum_rate -- in unit of khz
 690                        */
 691                        /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
 692                        uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
 693
 694                        /* clkv = 2 * D * fbdiv / NS */
 695                        uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
 696
 697                        cg_spll_spread_spectrum =
 698                                PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
 699                        cg_spll_spread_spectrum =
 700                                PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
 701                        cg_spll_spread_spectrum_2 =
 702                                PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
 703                }
 704        }
 705
 706        sclk->SclkFrequency        = engine_clock;
 707        sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
 708        sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
 709        sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
 710        sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
 711        sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
 712
 713        return 0;
 714}
 715
 716static int iceland_populate_phase_value_based_on_sclk(struct pp_hwmgr *hwmgr,
 717                                const struct phm_phase_shedding_limits_table *pl,
 718                                        uint32_t sclk, uint32_t *p_shed)
 719{
 720        unsigned int i;
 721
 722        /* use the minimum phase shedding */
 723        *p_shed = 1;
 724
 725        for (i = 0; i < pl->count; i++) {
 726                if (sclk < pl->entries[i].Sclk) {
 727                        *p_shed = i;
 728                        break;
 729                }
 730        }
 731        return 0;
 732}
 733
 734/**
 735 * Populates single SMC SCLK structure using the provided engine clock
 736 *
 737 * @param    hwmgr      the address of the hardware manager
 738 * @param    engine_clock the engine clock to use to populate the structure
 739 * @param    sclk        the SMC SCLK structure to be populated
 740 */
 741static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
 742                                                uint32_t engine_clock,
 743                                uint16_t sclk_activity_level_threshold,
 744                                SMU71_Discrete_GraphicsLevel *graphic_level)
 745{
 746        int result;
 747        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 748
 749        result = iceland_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
 750
 751        /* populate graphics levels*/
 752        result = iceland_get_dependecy_volt_by_clk(hwmgr,
 753                hwmgr->dyn_state.vddc_dependency_on_sclk, engine_clock,
 754                &graphic_level->MinVddc);
 755        PP_ASSERT_WITH_CODE((0 == result),
 756                "can not find VDDC voltage value for VDDC       \
 757                engine clock dependency table", return result);
 758
 759        /* SCLK frequency in units of 10KHz*/
 760        graphic_level->SclkFrequency = engine_clock;
 761        graphic_level->MinVddcPhases = 1;
 762
 763        if (data->vddc_phase_shed_control)
 764                iceland_populate_phase_value_based_on_sclk(hwmgr,
 765                                hwmgr->dyn_state.vddc_phase_shed_limits_table,
 766                                engine_clock,
 767                                &graphic_level->MinVddcPhases);
 768
 769        /* Indicates maximum activity level for this performance level. 50% for now*/
 770        graphic_level->ActivityLevel = sclk_activity_level_threshold;
 771
 772        graphic_level->CcPwrDynRm = 0;
 773        graphic_level->CcPwrDynRm1 = 0;
 774        /* this level can be used if activity is high enough.*/
 775        graphic_level->EnabledForActivity = 0;
 776        /* this level can be used for throttling.*/
 777        graphic_level->EnabledForThrottle = 1;
 778        graphic_level->UpHyst = 0;
 779        graphic_level->DownHyst = 100;
 780        graphic_level->VoltageDownHyst = 0;
 781        graphic_level->PowerThrottle = 0;
 782
 783        data->display_timing.min_clock_in_sr =
 784                        hwmgr->display_config.min_core_set_clock_in_sr;
 785
 786        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 787                        PHM_PlatformCaps_SclkDeepSleep))
 788                graphic_level->DeepSleepDivId =
 789                                smu7_get_sleep_divider_id_from_clock(engine_clock,
 790                                                data->display_timing.min_clock_in_sr);
 791
 792        /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
 793        graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
 794
 795        if (0 == result) {
 796                graphic_level->MinVddc = PP_HOST_TO_SMC_UL(graphic_level->MinVddc * VOLTAGE_SCALE);
 797                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);
 798                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
 799                CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
 800                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
 801                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
 802                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
 803                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
 804                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
 805                CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
 806        }
 807
 808        return result;
 809}
 810
 811/**
 812 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
 813 *
 814 * @param    hwmgr      the address of the hardware manager
 815 */
 816int iceland_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
 817{
 818        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 819        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
 820        struct smu7_dpm_table *dpm_table = &data->dpm_table;
 821        uint32_t level_array_adress = smu_data->smu7_data.dpm_table_start +
 822                                offsetof(SMU71_Discrete_DpmTable, GraphicsLevel);
 823
 824        uint32_t level_array_size = sizeof(SMU71_Discrete_GraphicsLevel) *
 825                                                SMU71_MAX_LEVELS_GRAPHICS;
 826
 827        SMU71_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel;
 828
 829        uint32_t i;
 830        uint8_t highest_pcie_level_enabled = 0;
 831        uint8_t lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0;
 832        uint8_t count = 0;
 833        int result = 0;
 834
 835        memset(levels, 0x00, level_array_size);
 836
 837        for (i = 0; i < dpm_table->sclk_table.count; i++) {
 838                result = iceland_populate_single_graphic_level(hwmgr,
 839                                        dpm_table->sclk_table.dpm_levels[i].value,
 840                                        (uint16_t)smu_data->activity_target[i],
 841                                        &(smu_data->smc_state_table.GraphicsLevel[i]));
 842                if (result != 0)
 843                        return result;
 844
 845                /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
 846                if (i > 1)
 847                        smu_data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
 848        }
 849
 850        /* Only enable level 0 for now. */
 851        smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
 852
 853        /* set highest level watermark to high */
 854        if (dpm_table->sclk_table.count > 1)
 855                smu_data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
 856                        PPSMC_DISPLAY_WATERMARK_HIGH;
 857
 858        smu_data->smc_state_table.GraphicsDpmLevelCount =
 859                (uint8_t)dpm_table->sclk_table.count;
 860        data->dpm_level_enable_mask.sclk_dpm_enable_mask =
 861                phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
 862
 863        while ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
 864                                (1 << (highest_pcie_level_enabled + 1))) != 0) {
 865                highest_pcie_level_enabled++;
 866        }
 867
 868        while ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
 869                (1 << lowest_pcie_level_enabled)) == 0) {
 870                lowest_pcie_level_enabled++;
 871        }
 872
 873        while ((count < highest_pcie_level_enabled) &&
 874                        ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
 875                                (1 << (lowest_pcie_level_enabled + 1 + count))) == 0)) {
 876                count++;
 877        }
 878
 879        mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
 880                (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
 881
 882
 883        /* set pcieDpmLevel to highest_pcie_level_enabled*/
 884        for (i = 2; i < dpm_table->sclk_table.count; i++) {
 885                smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
 886        }
 887
 888        /* set pcieDpmLevel to lowest_pcie_level_enabled*/
 889        smu_data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
 890
 891        /* set pcieDpmLevel to mid_pcie_level_enabled*/
 892        smu_data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
 893
 894        /* level count will send to smc once at init smc table and never change*/
 895        result = smu7_copy_bytes_to_smc(hwmgr->smumgr, level_array_adress,
 896                                (uint8_t *)levels, (uint32_t)level_array_size,
 897                                                                SMC_RAM_END);
 898
 899        return result;
 900}
 901
 902/**
 903 * Populates the SMC MCLK structure using the provided memory clock
 904 *
 905 * @param    hwmgr      the address of the hardware manager
 906 * @param    memory_clock the memory clock to use to populate the structure
 907 * @param    sclk        the SMC SCLK structure to be populated
 908 */
 909static int iceland_calculate_mclk_params(
 910                struct pp_hwmgr *hwmgr,
 911                uint32_t memory_clock,
 912                SMU71_Discrete_MemoryLevel *mclk,
 913                bool strobe_mode,
 914                bool dllStateOn
 915                )
 916{
 917        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 918
 919        uint32_t  dll_cntl = data->clock_registers.vDLL_CNTL;
 920        uint32_t  mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
 921        uint32_t  mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
 922        uint32_t  mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
 923        uint32_t  mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
 924        uint32_t  mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
 925        uint32_t  mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
 926        uint32_t  mpll_ss1 = data->clock_registers.vMPLL_SS1;
 927        uint32_t  mpll_ss2 = data->clock_registers.vMPLL_SS2;
 928
 929        pp_atomctrl_memory_clock_param mpll_param;
 930        int result;
 931
 932        result = atomctrl_get_memory_pll_dividers_si(hwmgr,
 933                                memory_clock, &mpll_param, strobe_mode);
 934        PP_ASSERT_WITH_CODE(0 == result,
 935                "Error retrieving Memory Clock Parameters from VBIOS.", return result);
 936
 937        /* MPLL_FUNC_CNTL setup*/
 938        mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
 939
 940        /* MPLL_FUNC_CNTL_1 setup*/
 941        mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
 942                                                        MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
 943        mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
 944                                                        MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
 945        mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
 946                                                        MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
 947
 948        /* MPLL_AD_FUNC_CNTL setup*/
 949        mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
 950                                                        MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
 951
 952        if (data->is_memory_gddr5) {
 953                /* MPLL_DQ_FUNC_CNTL setup*/
 954                mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
 955                                                                MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
 956                mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
 957                                                                MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
 958        }
 959
 960        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 961                        PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
 962                /*
 963                 ************************************
 964                 Fref = Reference Frequency
 965                 NF = Feedback divider ratio
 966                 NR = Reference divider ratio
 967                 Fnom = Nominal VCO output frequency = Fref * NF / NR
 968                 Fs = Spreading Rate
 969                 D = Percentage down-spread / 2
 970                 Fint = Reference input frequency to PFD = Fref / NR
 971                 NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
 972                 CLKS = NS - 1 = ISS_STEP_NUM[11:0]
 973                 NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
 974                 CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
 975                 *************************************
 976                 */
 977                pp_atomctrl_internal_ss_info ss_info;
 978                uint32_t freq_nom;
 979                uint32_t tmp;
 980                uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
 981
 982                /* for GDDR5 for all modes and DDR3 */
 983                if (1 == mpll_param.qdr)
 984                        freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
 985                else
 986                        freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
 987
 988                /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
 989                tmp = (freq_nom / reference_clock);
 990                tmp = tmp * tmp;
 991
 992                if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
 993                        /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
 994                        /* ss.Info.speed_spectrum_rate -- in unit of khz */
 995                        /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
 996                        /*     = reference_clock * 5 / speed_spectrum_rate */
 997                        uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
 998
 999                        /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
1000                        /*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
1001                        uint32_t clkv =
1002                                (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
1003                                                        ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
1004
1005                        mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
1006                        mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
1007                }
1008        }
1009
1010        /* MCLK_PWRMGT_CNTL setup */
1011        mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1012                MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
1013        mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1014                MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
1015        mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1016                MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
1017
1018
1019        /* Save the result data to outpupt memory level structure */
1020        mclk->MclkFrequency   = memory_clock;
1021        mclk->MpllFuncCntl    = mpll_func_cntl;
1022        mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
1023        mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
1024        mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
1025        mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
1026        mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
1027        mclk->DllCntl         = dll_cntl;
1028        mclk->MpllSs1         = mpll_ss1;
1029        mclk->MpllSs2         = mpll_ss2;
1030
1031        return 0;
1032}
1033
1034static uint8_t iceland_get_mclk_frequency_ratio(uint32_t memory_clock,
1035                bool strobe_mode)
1036{
1037        uint8_t mc_para_index;
1038
1039        if (strobe_mode) {
1040                if (memory_clock < 12500) {
1041                        mc_para_index = 0x00;
1042                } else if (memory_clock > 47500) {
1043                        mc_para_index = 0x0f;
1044                } else {
1045                        mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
1046                }
1047        } else {
1048                if (memory_clock < 65000) {
1049                        mc_para_index = 0x00;
1050                } else if (memory_clock > 135000) {
1051                        mc_para_index = 0x0f;
1052                } else {
1053                        mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
1054                }
1055        }
1056
1057        return mc_para_index;
1058}
1059
1060static uint8_t iceland_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
1061{
1062        uint8_t mc_para_index;
1063
1064        if (memory_clock < 10000) {
1065                mc_para_index = 0;
1066        } else if (memory_clock >= 80000) {
1067                mc_para_index = 0x0f;
1068        } else {
1069                mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
1070        }
1071
1072        return mc_para_index;
1073}
1074
1075static int iceland_populate_phase_value_based_on_mclk(struct pp_hwmgr *hwmgr, const struct phm_phase_shedding_limits_table *pl,
1076                                        uint32_t memory_clock, uint32_t *p_shed)
1077{
1078        unsigned int i;
1079
1080        *p_shed = 1;
1081
1082        for (i = 0; i < pl->count; i++) {
1083                if (memory_clock < pl->entries[i].Mclk) {
1084                        *p_shed = i;
1085                        break;
1086                }
1087        }
1088
1089        return 0;
1090}
1091
1092static int iceland_populate_single_memory_level(
1093                struct pp_hwmgr *hwmgr,
1094                uint32_t memory_clock,
1095                SMU71_Discrete_MemoryLevel *memory_level
1096                )
1097{
1098        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1099        int result = 0;
1100        bool dll_state_on;
1101        struct cgs_display_info info = {0};
1102        uint32_t mclk_edc_wr_enable_threshold = 40000;
1103        uint32_t mclk_edc_enable_threshold = 40000;
1104        uint32_t mclk_strobe_mode_threshold = 40000;
1105
1106        if (hwmgr->dyn_state.vddc_dependency_on_mclk != NULL) {
1107                result = iceland_get_dependecy_volt_by_clk(hwmgr,
1108                        hwmgr->dyn_state.vddc_dependency_on_mclk, memory_clock, &memory_level->MinVddc);
1109                PP_ASSERT_WITH_CODE((0 == result),
1110                        "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
1111        }
1112
1113        if (data->vddci_control == SMU7_VOLTAGE_CONTROL_NONE) {
1114                memory_level->MinVddci = memory_level->MinVddc;
1115        } else if (NULL != hwmgr->dyn_state.vddci_dependency_on_mclk) {
1116                result = iceland_get_dependecy_volt_by_clk(hwmgr,
1117                                hwmgr->dyn_state.vddci_dependency_on_mclk,
1118                                memory_clock,
1119                                &memory_level->MinVddci);
1120                PP_ASSERT_WITH_CODE((0 == result),
1121                        "can not find MinVddci voltage value from memory VDDCI voltage dependency table", return result);
1122        }
1123
1124        memory_level->MinVddcPhases = 1;
1125
1126        if (data->vddc_phase_shed_control) {
1127                iceland_populate_phase_value_based_on_mclk(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table,
1128                                memory_clock, &memory_level->MinVddcPhases);
1129        }
1130
1131        memory_level->EnabledForThrottle = 1;
1132        memory_level->EnabledForActivity = 0;
1133        memory_level->UpHyst = 0;
1134        memory_level->DownHyst = 100;
1135        memory_level->VoltageDownHyst = 0;
1136
1137        /* Indicates maximum activity level for this performance level.*/
1138        memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
1139        memory_level->StutterEnable = 0;
1140        memory_level->StrobeEnable = 0;
1141        memory_level->EdcReadEnable = 0;
1142        memory_level->EdcWriteEnable = 0;
1143        memory_level->RttEnable = 0;
1144
1145        /* default set to low watermark. Highest level will be set to high later.*/
1146        memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1147
1148        cgs_get_active_displays_info(hwmgr->device, &info);
1149        data->display_timing.num_existing_displays = info.display_count;
1150
1151        /* stutter mode not support on iceland */
1152
1153        /* decide strobe mode*/
1154        memory_level->StrobeEnable = (mclk_strobe_mode_threshold != 0) &&
1155                (memory_clock <= mclk_strobe_mode_threshold);
1156
1157        /* decide EDC mode and memory clock ratio*/
1158        if (data->is_memory_gddr5) {
1159                memory_level->StrobeRatio = iceland_get_mclk_frequency_ratio(memory_clock,
1160                                        memory_level->StrobeEnable);
1161
1162                if ((mclk_edc_enable_threshold != 0) &&
1163                                (memory_clock > mclk_edc_enable_threshold)) {
1164                        memory_level->EdcReadEnable = 1;
1165                }
1166
1167                if ((mclk_edc_wr_enable_threshold != 0) &&
1168                                (memory_clock > mclk_edc_wr_enable_threshold)) {
1169                        memory_level->EdcWriteEnable = 1;
1170                }
1171
1172                if (memory_level->StrobeEnable) {
1173                        if (iceland_get_mclk_frequency_ratio(memory_clock, 1) >=
1174                                        ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf))
1175                                dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
1176                        else
1177                                dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
1178                } else
1179                        dll_state_on = data->dll_default_on;
1180        } else {
1181                memory_level->StrobeRatio =
1182                        iceland_get_ddr3_mclk_frequency_ratio(memory_clock);
1183                dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
1184        }
1185
1186        result = iceland_calculate_mclk_params(hwmgr,
1187                memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
1188
1189        if (0 == result) {
1190                memory_level->MinVddc = PP_HOST_TO_SMC_UL(memory_level->MinVddc * VOLTAGE_SCALE);
1191                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinVddcPhases);
1192                memory_level->MinVddci = PP_HOST_TO_SMC_UL(memory_level->MinVddci * VOLTAGE_SCALE);
1193                memory_level->MinMvdd = PP_HOST_TO_SMC_UL(memory_level->MinMvdd * VOLTAGE_SCALE);
1194                /* MCLK frequency in units of 10KHz*/
1195                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
1196                /* Indicates maximum activity level for this performance level.*/
1197                CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
1198                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
1199                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
1200                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
1201                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
1202                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
1203                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
1204                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
1205                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
1206                CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
1207        }
1208
1209        return result;
1210}
1211
1212/**
1213 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
1214 *
1215 * @param    hwmgr      the address of the hardware manager
1216 */
1217
1218int iceland_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
1219{
1220        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1221        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
1222        struct smu7_dpm_table *dpm_table = &data->dpm_table;
1223        int result;
1224
1225        /* populate MCLK dpm table to SMU7 */
1226        uint32_t level_array_adress = smu_data->smu7_data.dpm_table_start + offsetof(SMU71_Discrete_DpmTable, MemoryLevel);
1227        uint32_t level_array_size = sizeof(SMU71_Discrete_MemoryLevel) * SMU71_MAX_LEVELS_MEMORY;
1228        SMU71_Discrete_MemoryLevel *levels = smu_data->smc_state_table.MemoryLevel;
1229        uint32_t i;
1230
1231        memset(levels, 0x00, level_array_size);
1232
1233        for (i = 0; i < dpm_table->mclk_table.count; i++) {
1234                PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
1235                        "can not populate memory level as memory clock is zero", return -EINVAL);
1236                result = iceland_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
1237                        &(smu_data->smc_state_table.MemoryLevel[i]));
1238                if (0 != result) {
1239                        return result;
1240                }
1241        }
1242
1243        /* Only enable level 0 for now.*/
1244        smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
1245
1246        /*
1247        * in order to prevent MC activity from stutter mode to push DPM up.
1248        * the UVD change complements this by putting the MCLK in a higher state
1249        * by default such that we are not effected by up threshold or and MCLK DPM latency.
1250        */
1251        smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
1252        CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
1253
1254        smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
1255        data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
1256        /* set highest level watermark to high*/
1257        smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
1258
1259        /* level count will send to smc once at init smc table and never change*/
1260        result = smu7_copy_bytes_to_smc(hwmgr->smumgr,
1261                level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size,
1262                SMC_RAM_END);
1263
1264        return result;
1265}
1266
1267static int iceland_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk,
1268                                        SMU71_Discrete_VoltageLevel *voltage)
1269{
1270        const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1271
1272        uint32_t i = 0;
1273
1274        if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
1275                /* find mvdd value which clock is more than request */
1276                for (i = 0; i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count; i++) {
1277                        if (mclk <= hwmgr->dyn_state.mvdd_dependency_on_mclk->entries[i].clk) {
1278                                /* Always round to higher voltage. */
1279                                voltage->Voltage = data->mvdd_voltage_table.entries[i].value;
1280                                break;
1281                        }
1282                }
1283
1284                PP_ASSERT_WITH_CODE(i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count,
1285                        "MVDD Voltage is outside the supported range.", return -EINVAL);
1286
1287        } else {
1288                return -EINVAL;
1289        }
1290
1291        return 0;
1292}
1293
1294static int iceland_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
1295        SMU71_Discrete_DpmTable *table)
1296{
1297        int result = 0;
1298        const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1299        struct pp_atomctrl_clock_dividers_vi dividers;
1300        uint32_t vddc_phase_shed_control = 0;
1301
1302        SMU71_Discrete_VoltageLevel voltage_level;
1303        uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
1304        uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
1305        uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
1306        uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
1307
1308
1309        /* The ACPI state should not do DPM on DC (or ever).*/
1310        table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
1311
1312        if (data->acpi_vddc)
1313                table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->acpi_vddc * VOLTAGE_SCALE);
1314        else
1315                table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->min_vddc_in_pptable * VOLTAGE_SCALE);
1316
1317        table->ACPILevel.MinVddcPhases = vddc_phase_shed_control ? 0 : 1;
1318        /* assign zero for now*/
1319        table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
1320
1321        /* get the engine clock dividers for this clock value*/
1322        result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
1323                table->ACPILevel.SclkFrequency,  &dividers);
1324
1325        PP_ASSERT_WITH_CODE(result == 0,
1326                "Error retrieving Engine Clock dividers from VBIOS.", return result);
1327
1328        /* divider ID for required SCLK*/
1329        table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
1330        table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1331        table->ACPILevel.DeepSleepDivId = 0;
1332
1333        spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
1334                                                        CG_SPLL_FUNC_CNTL,   SPLL_PWRON,     0);
1335        spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
1336                                                        CG_SPLL_FUNC_CNTL,   SPLL_RESET,     1);
1337        spll_func_cntl_2    = PHM_SET_FIELD(spll_func_cntl_2,
1338                                                        CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL,   4);
1339
1340        table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
1341        table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
1342        table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
1343        table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
1344        table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
1345        table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
1346        table->ACPILevel.CcPwrDynRm = 0;
1347        table->ACPILevel.CcPwrDynRm1 = 0;
1348
1349
1350        /* For various features to be enabled/disabled while this level is active.*/
1351        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
1352        /* SCLK frequency in units of 10KHz*/
1353        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
1354        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
1355        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
1356        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
1357        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
1358        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
1359        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
1360        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
1361        CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
1362
1363        /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
1364        table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
1365        table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
1366
1367        if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
1368                table->MemoryACPILevel.MinVddci = table->MemoryACPILevel.MinVddc;
1369        else {
1370                if (data->acpi_vddci != 0)
1371                        table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->acpi_vddci * VOLTAGE_SCALE);
1372                else
1373                        table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->min_vddci_in_pptable * VOLTAGE_SCALE);
1374        }
1375
1376        if (0 == iceland_populate_mvdd_value(hwmgr, 0, &voltage_level))
1377                table->MemoryACPILevel.MinMvdd =
1378                        PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
1379        else
1380                table->MemoryACPILevel.MinMvdd = 0;
1381
1382        /* Force reset on DLL*/
1383        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1384                MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
1385        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1386                MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
1387
1388        /* Disable DLL in ACPIState*/
1389        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1390                MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
1391        mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1392                MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
1393
1394        /* Enable DLL bypass signal*/
1395        dll_cntl            = PHM_SET_FIELD(dll_cntl,
1396                DLL_CNTL, MRDCK0_BYPASS, 0);
1397        dll_cntl            = PHM_SET_FIELD(dll_cntl,
1398                DLL_CNTL, MRDCK1_BYPASS, 0);
1399
1400        table->MemoryACPILevel.DllCntl            =
1401                PP_HOST_TO_SMC_UL(dll_cntl);
1402        table->MemoryACPILevel.MclkPwrmgtCntl     =
1403                PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
1404        table->MemoryACPILevel.MpllAdFuncCntl     =
1405                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
1406        table->MemoryACPILevel.MpllDqFuncCntl     =
1407                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
1408        table->MemoryACPILevel.MpllFuncCntl       =
1409                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
1410        table->MemoryACPILevel.MpllFuncCntl_1     =
1411                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
1412        table->MemoryACPILevel.MpllFuncCntl_2     =
1413                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
1414        table->MemoryACPILevel.MpllSs1            =
1415                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
1416        table->MemoryACPILevel.MpllSs2            =
1417                PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
1418
1419        table->MemoryACPILevel.EnabledForThrottle = 0;
1420        table->MemoryACPILevel.EnabledForActivity = 0;
1421        table->MemoryACPILevel.UpHyst = 0;
1422        table->MemoryACPILevel.DownHyst = 100;
1423        table->MemoryACPILevel.VoltageDownHyst = 0;
1424        /* Indicates maximum activity level for this performance level.*/
1425        table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
1426
1427        table->MemoryACPILevel.StutterEnable = 0;
1428        table->MemoryACPILevel.StrobeEnable = 0;
1429        table->MemoryACPILevel.EdcReadEnable = 0;
1430        table->MemoryACPILevel.EdcWriteEnable = 0;
1431        table->MemoryACPILevel.RttEnable = 0;
1432
1433        return result;
1434}
1435
1436static int iceland_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
1437                                        SMU71_Discrete_DpmTable *table)
1438{
1439        return 0;
1440}
1441
1442static int iceland_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
1443                SMU71_Discrete_DpmTable *table)
1444{
1445        return 0;
1446}
1447
1448static int iceland_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
1449                SMU71_Discrete_DpmTable *table)
1450{
1451        return 0;
1452}
1453
1454static int iceland_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
1455        SMU71_Discrete_DpmTable *table)
1456{
1457        return 0;
1458}
1459
1460static int iceland_populate_memory_timing_parameters(
1461                struct pp_hwmgr *hwmgr,
1462                uint32_t engine_clock,
1463                uint32_t memory_clock,
1464                struct SMU71_Discrete_MCArbDramTimingTableEntry *arb_regs
1465                )
1466{
1467        uint32_t dramTiming;
1468        uint32_t dramTiming2;
1469        uint32_t burstTime;
1470        int result;
1471
1472        result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
1473                                engine_clock, memory_clock);
1474
1475        PP_ASSERT_WITH_CODE(result == 0,
1476                "Error calling VBIOS to set DRAM_TIMING.", return result);
1477
1478        dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
1479        dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
1480        burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
1481
1482        arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
1483        arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
1484        arb_regs->McArbBurstTime = (uint8_t)burstTime;
1485
1486        return 0;
1487}
1488
1489/**
1490 * Setup parameters for the MC ARB.
1491 *
1492 * @param    hwmgr  the address of the powerplay hardware manager.
1493 * @return   always 0
1494 * This function is to be called from the SetPowerState table.
1495 */
1496static int iceland_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
1497{
1498        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1499        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
1500        int result = 0;
1501        SMU71_Discrete_MCArbDramTimingTable  arb_regs;
1502        uint32_t i, j;
1503
1504        memset(&arb_regs, 0x00, sizeof(SMU71_Discrete_MCArbDramTimingTable));
1505
1506        for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
1507                for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
1508                        result = iceland_populate_memory_timing_parameters
1509                                (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
1510                                 data->dpm_table.mclk_table.dpm_levels[j].value,
1511                                 &arb_regs.entries[i][j]);
1512
1513                        if (0 != result) {
1514                                break;
1515                        }
1516                }
1517        }
1518
1519        if (0 == result) {
1520                result = smu7_copy_bytes_to_smc(
1521                                hwmgr->smumgr,
1522                                smu_data->smu7_data.arb_table_start,
1523                                (uint8_t *)&arb_regs,
1524                                sizeof(SMU71_Discrete_MCArbDramTimingTable),
1525                                SMC_RAM_END
1526                                );
1527        }
1528
1529        return result;
1530}
1531
1532static int iceland_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
1533                        SMU71_Discrete_DpmTable *table)
1534{
1535        int result = 0;
1536        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1537        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
1538        table->GraphicsBootLevel = 0;
1539        table->MemoryBootLevel = 0;
1540
1541        /* find boot level from dpm table*/
1542        result = phm_find_boot_level(&(data->dpm_table.sclk_table),
1543                        data->vbios_boot_state.sclk_bootup_value,
1544                        (uint32_t *)&(smu_data->smc_state_table.GraphicsBootLevel));
1545
1546        if (0 != result) {
1547                smu_data->smc_state_table.GraphicsBootLevel = 0;
1548                printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
1549                        in dependency table. Using Graphics DPM level 0!");
1550                result = 0;
1551        }
1552
1553        result = phm_find_boot_level(&(data->dpm_table.mclk_table),
1554                data->vbios_boot_state.mclk_bootup_value,
1555                (uint32_t *)&(smu_data->smc_state_table.MemoryBootLevel));
1556
1557        if (0 != result) {
1558                smu_data->smc_state_table.MemoryBootLevel = 0;
1559                printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
1560                        in dependency table. Using Memory DPM level 0!");
1561                result = 0;
1562        }
1563
1564        table->BootVddc = data->vbios_boot_state.vddc_bootup_value;
1565        if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
1566                table->BootVddci = table->BootVddc;
1567        else
1568                table->BootVddci = data->vbios_boot_state.vddci_bootup_value;
1569
1570        table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
1571
1572        return result;
1573}
1574
1575static int iceland_populate_mc_reg_address(struct pp_smumgr *smumgr,
1576                                 SMU71_Discrete_MCRegisters *mc_reg_table)
1577{
1578        const struct iceland_smumgr *smu_data = (struct iceland_smumgr *)smumgr->backend;
1579
1580        uint32_t i, j;
1581
1582        for (i = 0, j = 0; j < smu_data->mc_reg_table.last; j++) {
1583                if (smu_data->mc_reg_table.validflag & 1<<j) {
1584                        PP_ASSERT_WITH_CODE(i < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE,
1585                                "Index of mc_reg_table->address[] array out of boundary", return -EINVAL);
1586                        mc_reg_table->address[i].s0 =
1587                                PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s0);
1588                        mc_reg_table->address[i].s1 =
1589                                PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s1);
1590                        i++;
1591                }
1592        }
1593
1594        mc_reg_table->last = (uint8_t)i;
1595
1596        return 0;
1597}
1598
1599/*convert register values from driver to SMC format */
1600static void iceland_convert_mc_registers(
1601        const struct iceland_mc_reg_entry *entry,
1602        SMU71_Discrete_MCRegisterSet *data,
1603        uint32_t num_entries, uint32_t valid_flag)
1604{
1605        uint32_t i, j;
1606
1607        for (i = 0, j = 0; j < num_entries; j++) {
1608                if (valid_flag & 1<<j) {
1609                        data->value[i] = PP_HOST_TO_SMC_UL(entry->mc_data[j]);
1610                        i++;
1611                }
1612        }
1613}
1614
1615static int iceland_convert_mc_reg_table_entry_to_smc(
1616                struct pp_smumgr *smumgr,
1617                const uint32_t memory_clock,
1618                SMU71_Discrete_MCRegisterSet *mc_reg_table_data
1619                )
1620{
1621        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
1622        uint32_t i = 0;
1623
1624        for (i = 0; i < smu_data->mc_reg_table.num_entries; i++) {
1625                if (memory_clock <=
1626                        smu_data->mc_reg_table.mc_reg_table_entry[i].mclk_max) {
1627                        break;
1628                }
1629        }
1630
1631        if ((i == smu_data->mc_reg_table.num_entries) && (i > 0))
1632                --i;
1633
1634        iceland_convert_mc_registers(&smu_data->mc_reg_table.mc_reg_table_entry[i],
1635                                mc_reg_table_data, smu_data->mc_reg_table.last,
1636                                smu_data->mc_reg_table.validflag);
1637
1638        return 0;
1639}
1640
1641static int iceland_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
1642                SMU71_Discrete_MCRegisters *mc_regs)
1643{
1644        int result = 0;
1645        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1646        int res;
1647        uint32_t i;
1648
1649        for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
1650                res = iceland_convert_mc_reg_table_entry_to_smc(
1651                                hwmgr->smumgr,
1652                                data->dpm_table.mclk_table.dpm_levels[i].value,
1653                                &mc_regs->data[i]
1654                                );
1655
1656                if (0 != res)
1657                        result = res;
1658        }
1659
1660        return result;
1661}
1662
1663static int iceland_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
1664{
1665        struct pp_smumgr *smumgr = hwmgr->smumgr;
1666        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
1667        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1668        uint32_t address;
1669        int32_t result;
1670
1671        if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
1672                return 0;
1673
1674
1675        memset(&smu_data->mc_regs, 0, sizeof(SMU71_Discrete_MCRegisters));
1676
1677        result = iceland_convert_mc_reg_table_to_smc(hwmgr, &(smu_data->mc_regs));
1678
1679        if (result != 0)
1680                return result;
1681
1682
1683        address = smu_data->smu7_data.mc_reg_table_start + (uint32_t)offsetof(SMU71_Discrete_MCRegisters, data[0]);
1684
1685        return  smu7_copy_bytes_to_smc(hwmgr->smumgr, address,
1686                                 (uint8_t *)&smu_data->mc_regs.data[0],
1687                                sizeof(SMU71_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
1688                                SMC_RAM_END);
1689}
1690
1691static int iceland_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
1692{
1693        int result;
1694        struct pp_smumgr *smumgr = hwmgr->smumgr;
1695        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
1696
1697        memset(&smu_data->mc_regs, 0x00, sizeof(SMU71_Discrete_MCRegisters));
1698        result = iceland_populate_mc_reg_address(smumgr, &(smu_data->mc_regs));
1699        PP_ASSERT_WITH_CODE(0 == result,
1700                "Failed to initialize MCRegTable for the MC register addresses!", return result;);
1701
1702        result = iceland_convert_mc_reg_table_to_smc(hwmgr, &smu_data->mc_regs);
1703        PP_ASSERT_WITH_CODE(0 == result,
1704                "Failed to initialize MCRegTable for driver state!", return result;);
1705
1706        return smu7_copy_bytes_to_smc(smumgr, smu_data->smu7_data.mc_reg_table_start,
1707                        (uint8_t *)&smu_data->mc_regs, sizeof(SMU71_Discrete_MCRegisters), SMC_RAM_END);
1708}
1709
1710static int iceland_populate_smc_initial_state(struct pp_hwmgr *hwmgr)
1711{
1712        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1713        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
1714        uint8_t count, level;
1715
1716        count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->count);
1717
1718        for (level = 0; level < count; level++) {
1719                if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[level].clk
1720                         >= data->vbios_boot_state.sclk_bootup_value) {
1721                        smu_data->smc_state_table.GraphicsBootLevel = level;
1722                        break;
1723                }
1724        }
1725
1726        count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_mclk->count);
1727
1728        for (level = 0; level < count; level++) {
1729                if (hwmgr->dyn_state.vddc_dependency_on_mclk->entries[level].clk
1730                        >= data->vbios_boot_state.mclk_bootup_value) {
1731                        smu_data->smc_state_table.MemoryBootLevel = level;
1732                        break;
1733                }
1734        }
1735
1736        return 0;
1737}
1738
1739static int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
1740{
1741        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1742        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
1743        const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
1744        SMU71_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
1745        struct phm_cac_tdp_table *cac_dtp_table = hwmgr->dyn_state.cac_dtp_table;
1746        struct phm_ppm_table *ppm = hwmgr->dyn_state.ppm_parameter_table;
1747        const uint16_t *def1, *def2;
1748        int i, j, k;
1749
1750
1751        /*
1752         * TDP number of fraction bits are changed from 8 to 7 for Iceland
1753         * as requested by SMC team
1754         */
1755
1756        dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 256));
1757        dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
1758
1759
1760        dpm_table->DTETjOffset = 0;
1761
1762        dpm_table->GpuTjMax = (uint8_t)(data->thermal_temp_setting.temperature_high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES);
1763        dpm_table->GpuTjHyst = 8;
1764
1765        dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
1766
1767        /* The following are for new Iceland Multi-input fan/thermal control */
1768        if (NULL != ppm) {
1769                dpm_table->PPM_PkgPwrLimit = (uint16_t)ppm->dgpu_tdp * 256 / 1000;
1770                dpm_table->PPM_TemperatureLimit = (uint16_t)ppm->tj_max * 256;
1771        } else {
1772                dpm_table->PPM_PkgPwrLimit = 0;
1773                dpm_table->PPM_TemperatureLimit = 0;
1774        }
1775
1776        CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_PkgPwrLimit);
1777        CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_TemperatureLimit);
1778
1779        dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient);
1780        def1 = defaults->bapmti_r;
1781        def2 = defaults->bapmti_rc;
1782
1783        for (i = 0; i < SMU71_DTE_ITERATIONS; i++) {
1784                for (j = 0; j < SMU71_DTE_SOURCES; j++) {
1785                        for (k = 0; k < SMU71_DTE_SINKS; k++) {
1786                                dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*def1);
1787                                dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*def2);
1788                                def1++;
1789                                def2++;
1790                        }
1791                }
1792        }
1793
1794        return 0;
1795}
1796
1797static int iceland_populate_smc_svi2_config(struct pp_hwmgr *hwmgr,
1798                                            SMU71_Discrete_DpmTable *tab)
1799{
1800        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1801
1802        if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control)
1803                tab->SVI2Enable |= VDDC_ON_SVI2;
1804
1805        if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
1806                tab->SVI2Enable |= VDDCI_ON_SVI2;
1807        else
1808                tab->MergedVddci = 1;
1809
1810        if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control)
1811                tab->SVI2Enable |= MVDD_ON_SVI2;
1812
1813        PP_ASSERT_WITH_CODE(tab->SVI2Enable != (VDDC_ON_SVI2 | VDDCI_ON_SVI2 | MVDD_ON_SVI2) &&
1814                (tab->SVI2Enable & VDDC_ON_SVI2), "SVI2 domain configuration is incorrect!", return -EINVAL);
1815
1816        return 0;
1817}
1818
1819/**
1820 * Initializes the SMC table and uploads it
1821 *
1822 * @param    hwmgr  the address of the powerplay hardware manager.
1823 * @param    pInput  the pointer to input data (PowerState)
1824 * @return   always 0
1825 */
1826int iceland_init_smc_table(struct pp_hwmgr *hwmgr)
1827{
1828        int result;
1829        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1830        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
1831        SMU71_Discrete_DpmTable  *table = &(smu_data->smc_state_table);
1832
1833
1834        iceland_initialize_power_tune_defaults(hwmgr);
1835        memset(&(smu_data->smc_state_table), 0x00, sizeof(smu_data->smc_state_table));
1836
1837        if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control) {
1838                iceland_populate_smc_voltage_tables(hwmgr, table);
1839        }
1840
1841        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1842                        PHM_PlatformCaps_AutomaticDCTransition))
1843                table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
1844
1845
1846        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1847                        PHM_PlatformCaps_StepVddc))
1848                table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
1849
1850        if (data->is_memory_gddr5)
1851                table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
1852
1853
1854        if (data->ulv_supported) {
1855                result = iceland_populate_ulv_state(hwmgr, &(smu_data->ulv_setting));
1856                PP_ASSERT_WITH_CODE(0 == result,
1857                        "Failed to initialize ULV state!", return result;);
1858
1859                cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1860                        ixCG_ULV_PARAMETER, 0x40035);
1861        }
1862
1863        result = iceland_populate_smc_link_level(hwmgr, table);
1864        PP_ASSERT_WITH_CODE(0 == result,
1865                "Failed to initialize Link Level!", return result;);
1866
1867        result = iceland_populate_all_graphic_levels(hwmgr);
1868        PP_ASSERT_WITH_CODE(0 == result,
1869                "Failed to initialize Graphics Level!", return result;);
1870
1871        result = iceland_populate_all_memory_levels(hwmgr);
1872        PP_ASSERT_WITH_CODE(0 == result,
1873                "Failed to initialize Memory Level!", return result;);
1874
1875        result = iceland_populate_smc_acpi_level(hwmgr, table);
1876        PP_ASSERT_WITH_CODE(0 == result,
1877                "Failed to initialize ACPI Level!", return result;);
1878
1879        result = iceland_populate_smc_vce_level(hwmgr, table);
1880        PP_ASSERT_WITH_CODE(0 == result,
1881                "Failed to initialize VCE Level!", return result;);
1882
1883        result = iceland_populate_smc_acp_level(hwmgr, table);
1884        PP_ASSERT_WITH_CODE(0 == result,
1885                "Failed to initialize ACP Level!", return result;);
1886
1887        result = iceland_populate_smc_samu_level(hwmgr, table);
1888        PP_ASSERT_WITH_CODE(0 == result,
1889                "Failed to initialize SAMU Level!", return result;);
1890
1891        /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
1892        /* need to populate the  ARB settings for the initial state. */
1893        result = iceland_program_memory_timing_parameters(hwmgr);
1894        PP_ASSERT_WITH_CODE(0 == result,
1895                "Failed to Write ARB settings for the initial state.", return result;);
1896
1897        result = iceland_populate_smc_uvd_level(hwmgr, table);
1898        PP_ASSERT_WITH_CODE(0 == result,
1899                "Failed to initialize UVD Level!", return result;);
1900
1901        table->GraphicsBootLevel = 0;
1902        table->MemoryBootLevel = 0;
1903
1904        result = iceland_populate_smc_boot_level(hwmgr, table);
1905        PP_ASSERT_WITH_CODE(0 == result,
1906                "Failed to initialize Boot Level!", return result;);
1907
1908        result = iceland_populate_smc_initial_state(hwmgr);
1909        PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize Boot State!", return result);
1910
1911        result = iceland_populate_bapm_parameters_in_dpm_table(hwmgr);
1912        PP_ASSERT_WITH_CODE(0 == result, "Failed to populate BAPM Parameters!", return result);
1913
1914        table->GraphicsVoltageChangeEnable  = 1;
1915        table->GraphicsThermThrottleEnable  = 1;
1916        table->GraphicsInterval = 1;
1917        table->VoltageInterval  = 1;
1918        table->ThermalInterval  = 1;
1919
1920        table->TemperatureLimitHigh =
1921                (data->thermal_temp_setting.temperature_high *
1922                 SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1923        table->TemperatureLimitLow =
1924                (data->thermal_temp_setting.temperature_low *
1925                SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1926
1927        table->MemoryVoltageChangeEnable  = 1;
1928        table->MemoryInterval  = 1;
1929        table->VoltageResponseTime  = 0;
1930        table->PhaseResponseTime  = 0;
1931        table->MemoryThermThrottleEnable  = 1;
1932        table->PCIeBootLinkLevel = 0;
1933        table->PCIeGenInterval = 1;
1934
1935        result = iceland_populate_smc_svi2_config(hwmgr, table);
1936        PP_ASSERT_WITH_CODE(0 == result,
1937                "Failed to populate SVI2 setting!", return result);
1938
1939        table->ThermGpio  = 17;
1940        table->SclkStepSize = 0x4000;
1941
1942        CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
1943        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcVid);
1944        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcPhase);
1945        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddciVid);
1946        CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskMvddVid);
1947        CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
1948        CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
1949        CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
1950        CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
1951        CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
1952
1953        table->BootVddc = PP_HOST_TO_SMC_US(table->BootVddc * VOLTAGE_SCALE);
1954        table->BootVddci = PP_HOST_TO_SMC_US(table->BootVddci * VOLTAGE_SCALE);
1955        table->BootMVdd = PP_HOST_TO_SMC_US(table->BootMVdd * VOLTAGE_SCALE);
1956
1957        /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
1958        result = smu7_copy_bytes_to_smc(hwmgr->smumgr, smu_data->smu7_data.dpm_table_start +
1959                                                                                offsetof(SMU71_Discrete_DpmTable, SystemFlags),
1960                                                                                (uint8_t *)&(table->SystemFlags),
1961                                                                                sizeof(SMU71_Discrete_DpmTable)-3 * sizeof(SMU71_PIDController),
1962                                                                                SMC_RAM_END);
1963
1964        PP_ASSERT_WITH_CODE(0 == result,
1965                "Failed to upload dpm data to SMC memory!", return result;);
1966
1967        /* Upload all ulv setting to SMC memory.(dpm level, dpm level count etc) */
1968        result = smu7_copy_bytes_to_smc(hwmgr->smumgr,
1969                        smu_data->smu7_data.ulv_setting_starts,
1970                        (uint8_t *)&(smu_data->ulv_setting),
1971                        sizeof(SMU71_Discrete_Ulv),
1972                        SMC_RAM_END);
1973
1974
1975        result = iceland_populate_initial_mc_reg_table(hwmgr);
1976        PP_ASSERT_WITH_CODE((0 == result),
1977                "Failed to populate initialize MC Reg table!", return result);
1978
1979        result = iceland_populate_pm_fuses(hwmgr);
1980        PP_ASSERT_WITH_CODE(0 == result,
1981                        "Failed to  populate PM fuses to SMC memory!", return result);
1982
1983        return 0;
1984}
1985
1986/**
1987* Set up the fan table to control the fan using the SMC.
1988* @param    hwmgr  the address of the powerplay hardware manager.
1989* @param    pInput the pointer to input data
1990* @param    pOutput the pointer to output data
1991* @param    pStorage the pointer to temporary storage
1992* @param    Result the last failure code
1993* @return   result from set temperature range routine
1994*/
1995int iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
1996{
1997        struct smu7_smumgr *smu7_data = (struct smu7_smumgr *)(hwmgr->smumgr->backend);
1998        SMU71_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
1999        uint32_t duty100;
2000        uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
2001        uint16_t fdo_min, slope1, slope2;
2002        uint32_t reference_clock;
2003        int res;
2004        uint64_t tmp64;
2005
2006        if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
2007                return 0;
2008
2009        if (0 == smu7_data->fan_table_start) {
2010                phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
2011                return 0;
2012        }
2013
2014        duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
2015
2016        if (0 == duty100) {
2017                phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
2018                return 0;
2019        }
2020
2021        tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
2022        do_div(tmp64, 10000);
2023        fdo_min = (uint16_t)tmp64;
2024
2025        t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
2026        t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
2027
2028        pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
2029        pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
2030
2031        slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
2032        slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
2033
2034        fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
2035        fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
2036        fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
2037
2038        fan_table.Slope1 = cpu_to_be16(slope1);
2039        fan_table.Slope2 = cpu_to_be16(slope2);
2040
2041        fan_table.FdoMin = cpu_to_be16(fdo_min);
2042
2043        fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
2044
2045        fan_table.HystUp = cpu_to_be16(1);
2046
2047        fan_table.HystSlope = cpu_to_be16(1);
2048
2049        fan_table.TempRespLim = cpu_to_be16(5);
2050
2051        reference_clock = smu7_get_xclk(hwmgr);
2052
2053        fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
2054
2055        fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
2056
2057        fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
2058
2059        /* fan_table.FanControl_GL_Flag = 1; */
2060
2061        res = smu7_copy_bytes_to_smc(hwmgr->smumgr, smu7_data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), SMC_RAM_END);
2062
2063        return 0;
2064}
2065
2066
2067static int iceland_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
2068{
2069        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2070
2071        if (data->need_update_smu7_dpm_table &
2072                (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
2073                return iceland_program_memory_timing_parameters(hwmgr);
2074
2075        return 0;
2076}
2077
2078int iceland_update_sclk_threshold(struct pp_hwmgr *hwmgr)
2079{
2080        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2081        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
2082
2083        int result = 0;
2084        uint32_t low_sclk_interrupt_threshold = 0;
2085
2086        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2087                        PHM_PlatformCaps_SclkThrottleLowNotification)
2088                && (hwmgr->gfx_arbiter.sclk_threshold !=
2089                                data->low_sclk_interrupt_threshold)) {
2090                data->low_sclk_interrupt_threshold =
2091                                hwmgr->gfx_arbiter.sclk_threshold;
2092                low_sclk_interrupt_threshold =
2093                                data->low_sclk_interrupt_threshold;
2094
2095                CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
2096
2097                result = smu7_copy_bytes_to_smc(
2098                                hwmgr->smumgr,
2099                                smu_data->smu7_data.dpm_table_start +
2100                                offsetof(SMU71_Discrete_DpmTable,
2101                                        LowSclkInterruptThreshold),
2102                                (uint8_t *)&low_sclk_interrupt_threshold,
2103                                sizeof(uint32_t),
2104                                SMC_RAM_END);
2105        }
2106
2107        result = iceland_update_and_upload_mc_reg_table(hwmgr);
2108
2109        PP_ASSERT_WITH_CODE((0 == result), "Failed to upload MC reg table!", return result);
2110
2111        result = iceland_program_mem_timing_parameters(hwmgr);
2112        PP_ASSERT_WITH_CODE((result == 0),
2113                        "Failed to program memory timing parameters!",
2114                        );
2115
2116        return result;
2117}
2118
2119uint32_t iceland_get_offsetof(uint32_t type, uint32_t member)
2120{
2121        switch (type) {
2122        case SMU_SoftRegisters:
2123                switch (member) {
2124                case HandshakeDisables:
2125                        return offsetof(SMU71_SoftRegisters, HandshakeDisables);
2126                case VoltageChangeTimeout:
2127                        return offsetof(SMU71_SoftRegisters, VoltageChangeTimeout);
2128                case AverageGraphicsActivity:
2129                        return offsetof(SMU71_SoftRegisters, AverageGraphicsActivity);
2130                case PreVBlankGap:
2131                        return offsetof(SMU71_SoftRegisters, PreVBlankGap);
2132                case VBlankTimeout:
2133                        return offsetof(SMU71_SoftRegisters, VBlankTimeout);
2134                case UcodeLoadStatus:
2135                        return offsetof(SMU71_SoftRegisters, UcodeLoadStatus);
2136                }
2137        case SMU_Discrete_DpmTable:
2138                switch (member) {
2139                case LowSclkInterruptThreshold:
2140                        return offsetof(SMU71_Discrete_DpmTable, LowSclkInterruptThreshold);
2141                }
2142        }
2143        printk("cant't get the offset of type %x member %x \n", type, member);
2144        return 0;
2145}
2146
2147uint32_t iceland_get_mac_definition(uint32_t value)
2148{
2149        switch (value) {
2150        case SMU_MAX_LEVELS_GRAPHICS:
2151                return SMU71_MAX_LEVELS_GRAPHICS;
2152        case SMU_MAX_LEVELS_MEMORY:
2153                return SMU71_MAX_LEVELS_MEMORY;
2154        case SMU_MAX_LEVELS_LINK:
2155                return SMU71_MAX_LEVELS_LINK;
2156        case SMU_MAX_ENTRIES_SMIO:
2157                return SMU71_MAX_ENTRIES_SMIO;
2158        case SMU_MAX_LEVELS_VDDC:
2159                return SMU71_MAX_LEVELS_VDDC;
2160        case SMU_MAX_LEVELS_VDDCI:
2161                return SMU71_MAX_LEVELS_VDDCI;
2162        case SMU_MAX_LEVELS_MVDD:
2163                return SMU71_MAX_LEVELS_MVDD;
2164        }
2165
2166        printk("cant't get the mac of %x \n", value);
2167        return 0;
2168}
2169
2170/**
2171 * Get the location of various tables inside the FW image.
2172 *
2173 * @param    hwmgr  the address of the powerplay hardware manager.
2174 * @return   always 0
2175 */
2176int iceland_process_firmware_header(struct pp_hwmgr *hwmgr)
2177{
2178        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2179        struct smu7_smumgr *smu7_data = (struct smu7_smumgr *)(hwmgr->smumgr->backend);
2180
2181        uint32_t tmp;
2182        int result;
2183        bool error = false;
2184
2185        result = smu7_read_smc_sram_dword(hwmgr->smumgr,
2186                                SMU71_FIRMWARE_HEADER_LOCATION +
2187                                offsetof(SMU71_Firmware_Header, DpmTable),
2188                                &tmp, SMC_RAM_END);
2189
2190        if (0 == result) {
2191                smu7_data->dpm_table_start = tmp;
2192        }
2193
2194        error |= (0 != result);
2195
2196        result = smu7_read_smc_sram_dword(hwmgr->smumgr,
2197                                SMU71_FIRMWARE_HEADER_LOCATION +
2198                                offsetof(SMU71_Firmware_Header, SoftRegisters),
2199                                &tmp, SMC_RAM_END);
2200
2201        if (0 == result) {
2202                data->soft_regs_start = tmp;
2203                smu7_data->soft_regs_start = tmp;
2204        }
2205
2206        error |= (0 != result);
2207
2208
2209        result = smu7_read_smc_sram_dword(hwmgr->smumgr,
2210                                SMU71_FIRMWARE_HEADER_LOCATION +
2211                                offsetof(SMU71_Firmware_Header, mcRegisterTable),
2212                                &tmp, SMC_RAM_END);
2213
2214        if (0 == result) {
2215                smu7_data->mc_reg_table_start = tmp;
2216        }
2217
2218        result = smu7_read_smc_sram_dword(hwmgr->smumgr,
2219                                SMU71_FIRMWARE_HEADER_LOCATION +
2220                                offsetof(SMU71_Firmware_Header, FanTable),
2221                                &tmp, SMC_RAM_END);
2222
2223        if (0 == result) {
2224                smu7_data->fan_table_start = tmp;
2225        }
2226
2227        error |= (0 != result);
2228
2229        result = smu7_read_smc_sram_dword(hwmgr->smumgr,
2230                                SMU71_FIRMWARE_HEADER_LOCATION +
2231                                offsetof(SMU71_Firmware_Header, mcArbDramTimingTable),
2232                                &tmp, SMC_RAM_END);
2233
2234        if (0 == result) {
2235                smu7_data->arb_table_start = tmp;
2236        }
2237
2238        error |= (0 != result);
2239
2240
2241        result = smu7_read_smc_sram_dword(hwmgr->smumgr,
2242                                SMU71_FIRMWARE_HEADER_LOCATION +
2243                                offsetof(SMU71_Firmware_Header, Version),
2244                                &tmp, SMC_RAM_END);
2245
2246        if (0 == result) {
2247                hwmgr->microcode_version_info.SMC = tmp;
2248        }
2249
2250        error |= (0 != result);
2251
2252        result = smu7_read_smc_sram_dword(hwmgr->smumgr,
2253                                SMU71_FIRMWARE_HEADER_LOCATION +
2254                                offsetof(SMU71_Firmware_Header, UlvSettings),
2255                                &tmp, SMC_RAM_END);
2256
2257        if (0 == result) {
2258                smu7_data->ulv_setting_starts = tmp;
2259        }
2260
2261        error |= (0 != result);
2262
2263        return error ? 1 : 0;
2264}
2265
2266/*---------------------------MC----------------------------*/
2267
2268static uint8_t iceland_get_memory_modile_index(struct pp_hwmgr *hwmgr)
2269{
2270        return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
2271}
2272
2273static bool iceland_check_s0_mc_reg_index(uint16_t in_reg, uint16_t *out_reg)
2274{
2275        bool result = true;
2276
2277        switch (in_reg) {
2278        case  mmMC_SEQ_RAS_TIMING:
2279                *out_reg = mmMC_SEQ_RAS_TIMING_LP;
2280                break;
2281
2282        case  mmMC_SEQ_DLL_STBY:
2283                *out_reg = mmMC_SEQ_DLL_STBY_LP;
2284                break;
2285
2286        case  mmMC_SEQ_G5PDX_CMD0:
2287                *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
2288                break;
2289
2290        case  mmMC_SEQ_G5PDX_CMD1:
2291                *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
2292                break;
2293
2294        case  mmMC_SEQ_G5PDX_CTRL:
2295                *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
2296                break;
2297
2298        case mmMC_SEQ_CAS_TIMING:
2299                *out_reg = mmMC_SEQ_CAS_TIMING_LP;
2300                break;
2301
2302        case mmMC_SEQ_MISC_TIMING:
2303                *out_reg = mmMC_SEQ_MISC_TIMING_LP;
2304                break;
2305
2306        case mmMC_SEQ_MISC_TIMING2:
2307                *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
2308                break;
2309
2310        case mmMC_SEQ_PMG_DVS_CMD:
2311                *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
2312                break;
2313
2314        case mmMC_SEQ_PMG_DVS_CTL:
2315                *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
2316                break;
2317
2318        case mmMC_SEQ_RD_CTL_D0:
2319                *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
2320                break;
2321
2322        case mmMC_SEQ_RD_CTL_D1:
2323                *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
2324                break;
2325
2326        case mmMC_SEQ_WR_CTL_D0:
2327                *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
2328                break;
2329
2330        case mmMC_SEQ_WR_CTL_D1:
2331                *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
2332                break;
2333
2334        case mmMC_PMG_CMD_EMRS:
2335                *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
2336                break;
2337
2338        case mmMC_PMG_CMD_MRS:
2339                *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
2340                break;
2341
2342        case mmMC_PMG_CMD_MRS1:
2343                *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
2344                break;
2345
2346        case mmMC_SEQ_PMG_TIMING:
2347                *out_reg = mmMC_SEQ_PMG_TIMING_LP;
2348                break;
2349
2350        case mmMC_PMG_CMD_MRS2:
2351                *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
2352                break;
2353
2354        case mmMC_SEQ_WR_CTL_2:
2355                *out_reg = mmMC_SEQ_WR_CTL_2_LP;
2356                break;
2357
2358        default:
2359                result = false;
2360                break;
2361        }
2362
2363        return result;
2364}
2365
2366static int iceland_set_s0_mc_reg_index(struct iceland_mc_reg_table *table)
2367{
2368        uint32_t i;
2369        uint16_t address;
2370
2371        for (i = 0; i < table->last; i++) {
2372                table->mc_reg_address[i].s0 =
2373                        iceland_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
2374                        ? address : table->mc_reg_address[i].s1;
2375        }
2376        return 0;
2377}
2378
2379static int iceland_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table,
2380                                        struct iceland_mc_reg_table *ni_table)
2381{
2382        uint8_t i, j;
2383
2384        PP_ASSERT_WITH_CODE((table->last <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2385                "Invalid VramInfo table.", return -EINVAL);
2386        PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
2387                "Invalid VramInfo table.", return -EINVAL);
2388
2389        for (i = 0; i < table->last; i++) {
2390                ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
2391        }
2392        ni_table->last = table->last;
2393
2394        for (i = 0; i < table->num_entries; i++) {
2395                ni_table->mc_reg_table_entry[i].mclk_max =
2396                        table->mc_reg_table_entry[i].mclk_max;
2397                for (j = 0; j < table->last; j++) {
2398                        ni_table->mc_reg_table_entry[i].mc_data[j] =
2399                                table->mc_reg_table_entry[i].mc_data[j];
2400                }
2401        }
2402
2403        ni_table->num_entries = table->num_entries;
2404
2405        return 0;
2406}
2407
2408/**
2409 * VBIOS omits some information to reduce size, we need to recover them here.
2410 * 1.   when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
2411 *      Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
2412 * 2.   when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
2413 * 3.   need to set these data for each clock range
2414 *
2415 * @param    hwmgr the address of the powerplay hardware manager.
2416 * @param    table the address of MCRegTable
2417 * @return   always 0
2418 */
2419static int iceland_set_mc_special_registers(struct pp_hwmgr *hwmgr,
2420                                        struct iceland_mc_reg_table *table)
2421{
2422        uint8_t i, j, k;
2423        uint32_t temp_reg;
2424        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2425
2426        for (i = 0, j = table->last; i < table->last; i++) {
2427                PP_ASSERT_WITH_CODE((j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2428                        "Invalid VramInfo table.", return -EINVAL);
2429
2430                switch (table->mc_reg_address[i].s1) {
2431
2432                case mmMC_SEQ_MISC1:
2433                        temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
2434                        table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
2435                        table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
2436                        for (k = 0; k < table->num_entries; k++) {
2437                                table->mc_reg_table_entry[k].mc_data[j] =
2438                                        ((temp_reg & 0xffff0000)) |
2439                                        ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
2440                        }
2441                        j++;
2442                        PP_ASSERT_WITH_CODE((j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2443                                "Invalid VramInfo table.", return -EINVAL);
2444
2445                        temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
2446                        table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
2447                        table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
2448                        for (k = 0; k < table->num_entries; k++) {
2449                                table->mc_reg_table_entry[k].mc_data[j] =
2450                                        (temp_reg & 0xffff0000) |
2451                                        (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
2452
2453                                if (!data->is_memory_gddr5) {
2454                                        table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
2455                                }
2456                        }
2457                        j++;
2458                        PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2459                                "Invalid VramInfo table.", return -EINVAL);
2460
2461                        if (!data->is_memory_gddr5 && j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE) {
2462                                table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
2463                                table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
2464                                for (k = 0; k < table->num_entries; k++) {
2465                                        table->mc_reg_table_entry[k].mc_data[j] =
2466                                                (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
2467                                }
2468                                j++;
2469                                PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2470                                        "Invalid VramInfo table.", return -EINVAL);
2471                        }
2472
2473                        break;
2474
2475                case mmMC_SEQ_RESERVE_M:
2476                        temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
2477                        table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
2478                        table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
2479                        for (k = 0; k < table->num_entries; k++) {
2480                                table->mc_reg_table_entry[k].mc_data[j] =
2481                                        (temp_reg & 0xffff0000) |
2482                                        (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
2483                        }
2484                        j++;
2485                        PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
2486                                "Invalid VramInfo table.", return -EINVAL);
2487                        break;
2488
2489                default:
2490                        break;
2491                }
2492
2493        }
2494
2495        table->last = j;
2496
2497        return 0;
2498}
2499
2500static int iceland_set_valid_flag(struct iceland_mc_reg_table *table)
2501{
2502        uint8_t i, j;
2503        for (i = 0; i < table->last; i++) {
2504                for (j = 1; j < table->num_entries; j++) {
2505                        if (table->mc_reg_table_entry[j-1].mc_data[i] !=
2506                                table->mc_reg_table_entry[j].mc_data[i]) {
2507                                table->validflag |= (1<<i);
2508                                break;
2509                        }
2510                }
2511        }
2512
2513        return 0;
2514}
2515
2516int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
2517{
2518        int result;
2519        struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
2520        pp_atomctrl_mc_reg_table *table;
2521        struct iceland_mc_reg_table *ni_table = &smu_data->mc_reg_table;
2522        uint8_t module_index = iceland_get_memory_modile_index(hwmgr);
2523
2524        table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
2525
2526        if (NULL == table)
2527                return -ENOMEM;
2528
2529        /* Program additional LP registers that are no longer programmed by VBIOS */
2530        cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
2531        cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
2532        cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
2533        cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
2534        cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
2535        cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
2536        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
2537        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
2538        cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
2539        cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
2540        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
2541        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
2542        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
2543        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
2544        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
2545        cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
2546        cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
2547        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
2548        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
2549        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
2550
2551        memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
2552
2553        result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
2554
2555        if (0 == result)
2556                result = iceland_copy_vbios_smc_reg_table(table, ni_table);
2557
2558        if (0 == result) {
2559                iceland_set_s0_mc_reg_index(ni_table);
2560                result = iceland_set_mc_special_registers(hwmgr, ni_table);
2561        }
2562
2563        if (0 == result)
2564                iceland_set_valid_flag(ni_table);
2565
2566        kfree(table);
2567
2568        return result;
2569}
2570
2571bool iceland_is_dpm_running(struct pp_hwmgr *hwmgr)
2572{
2573        return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
2574                        CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
2575                        ? true : false;
2576}
2577