linux/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c
<<
>>
Prefs
   1/*
   2 * Copyright 2018 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 */
  23
  24#include <linux/pci.h>
  25#include <linux/reboot.h>
  26
  27#include "hwmgr.h"
  28#include "pp_debug.h"
  29#include "ppatomctrl.h"
  30#include "ppsmc.h"
  31#include "atom.h"
  32#include "ivsrcid/thm/irqsrcs_thm_9_0.h"
  33#include "ivsrcid/smuio/irqsrcs_smuio_9_0.h"
  34#include "ivsrcid/ivsrcid_vislands30.h"
  35
  36uint8_t convert_to_vid(uint16_t vddc)
  37{
  38        return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
  39}
  40
  41uint16_t convert_to_vddc(uint8_t vid)
  42{
  43        return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE);
  44}
  45
  46int phm_copy_clock_limits_array(
  47        struct pp_hwmgr *hwmgr,
  48        uint32_t **pptable_info_array,
  49        const uint32_t *pptable_array,
  50        uint32_t power_saving_clock_count)
  51{
  52        uint32_t array_size, i;
  53        uint32_t *table;
  54
  55        array_size = sizeof(uint32_t) * power_saving_clock_count;
  56        table = kzalloc(array_size, GFP_KERNEL);
  57        if (NULL == table)
  58                return -ENOMEM;
  59
  60        for (i = 0; i < power_saving_clock_count; i++)
  61                table[i] = le32_to_cpu(pptable_array[i]);
  62
  63        *pptable_info_array = table;
  64
  65        return 0;
  66}
  67
  68int phm_copy_overdrive_settings_limits_array(
  69        struct pp_hwmgr *hwmgr,
  70        uint32_t **pptable_info_array,
  71        const uint32_t *pptable_array,
  72        uint32_t od_setting_count)
  73{
  74        uint32_t array_size, i;
  75        uint32_t *table;
  76
  77        array_size = sizeof(uint32_t) * od_setting_count;
  78        table = kzalloc(array_size, GFP_KERNEL);
  79        if (NULL == table)
  80                return -ENOMEM;
  81
  82        for (i = 0; i < od_setting_count; i++)
  83                table[i] = le32_to_cpu(pptable_array[i]);
  84
  85        *pptable_info_array = table;
  86
  87        return 0;
  88}
  89
  90uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size)
  91{
  92        u32 mask = 0;
  93        u32 shift = 0;
  94
  95        shift = (offset % 4) << 3;
  96        if (size == sizeof(uint8_t))
  97                mask = 0xFF << shift;
  98        else if (size == sizeof(uint16_t))
  99                mask = 0xFFFF << shift;
 100
 101        original_data &= ~mask;
 102        original_data |= (field << shift);
 103        return original_data;
 104}
 105
 106/*
 107 * Returns once the part of the register indicated by the mask has
 108 * reached the given value.
 109 */
 110int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
 111                         uint32_t value, uint32_t mask)
 112{
 113        uint32_t i;
 114        uint32_t cur_value;
 115
 116        if (hwmgr == NULL || hwmgr->device == NULL) {
 117                pr_err("Invalid Hardware Manager!");
 118                return -EINVAL;
 119        }
 120
 121        for (i = 0; i < hwmgr->usec_timeout; i++) {
 122                cur_value = cgs_read_register(hwmgr->device, index);
 123                if ((cur_value & mask) == (value & mask))
 124                        break;
 125                udelay(1);
 126        }
 127
 128        /* timeout means wrong logic*/
 129        if (i == hwmgr->usec_timeout)
 130                return -1;
 131        return 0;
 132}
 133
 134
 135/*
 136 * Returns once the part of the register indicated by the mask has
 137 * reached the given value.The indirect space is described by giving
 138 * the memory-mapped index of the indirect index register.
 139 */
 140int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
 141                                uint32_t indirect_port,
 142                                uint32_t index,
 143                                uint32_t value,
 144                                uint32_t mask)
 145{
 146        if (hwmgr == NULL || hwmgr->device == NULL) {
 147                pr_err("Invalid Hardware Manager!");
 148                return -EINVAL;
 149        }
 150
 151        cgs_write_register(hwmgr->device, indirect_port, index);
 152        return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
 153}
 154
 155int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
 156                                        uint32_t index,
 157                                        uint32_t value, uint32_t mask)
 158{
 159        uint32_t i;
 160        uint32_t cur_value;
 161
 162        if (hwmgr == NULL || hwmgr->device == NULL)
 163                return -EINVAL;
 164
 165        for (i = 0; i < hwmgr->usec_timeout; i++) {
 166                cur_value = cgs_read_register(hwmgr->device,
 167                                                                        index);
 168                if ((cur_value & mask) != (value & mask))
 169                        break;
 170                udelay(1);
 171        }
 172
 173        /* timeout means wrong logic */
 174        if (i == hwmgr->usec_timeout)
 175                return -ETIME;
 176        return 0;
 177}
 178
 179int phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
 180                                                uint32_t indirect_port,
 181                                                uint32_t index,
 182                                                uint32_t value,
 183                                                uint32_t mask)
 184{
 185        if (hwmgr == NULL || hwmgr->device == NULL)
 186                return -EINVAL;
 187
 188        cgs_write_register(hwmgr->device, indirect_port, index);
 189        return phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
 190                                                value, mask);
 191}
 192
 193bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
 194{
 195        return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating);
 196}
 197
 198bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr)
 199{
 200        return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating);
 201}
 202
 203
 204int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
 205{
 206        uint32_t i, j;
 207        uint16_t vvalue;
 208        bool found = false;
 209        struct pp_atomctrl_voltage_table *table;
 210
 211        PP_ASSERT_WITH_CODE((NULL != vol_table),
 212                        "Voltage Table empty.", return -EINVAL);
 213
 214        table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
 215                        GFP_KERNEL);
 216
 217        if (NULL == table)
 218                return -EINVAL;
 219
 220        table->mask_low = vol_table->mask_low;
 221        table->phase_delay = vol_table->phase_delay;
 222
 223        for (i = 0; i < vol_table->count; i++) {
 224                vvalue = vol_table->entries[i].value;
 225                found = false;
 226
 227                for (j = 0; j < table->count; j++) {
 228                        if (vvalue == table->entries[j].value) {
 229                                found = true;
 230                                break;
 231                        }
 232                }
 233
 234                if (!found) {
 235                        table->entries[table->count].value = vvalue;
 236                        table->entries[table->count].smio_low =
 237                                        vol_table->entries[i].smio_low;
 238                        table->count++;
 239                }
 240        }
 241
 242        memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
 243        kfree(table);
 244        table = NULL;
 245        return 0;
 246}
 247
 248int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
 249                phm_ppt_v1_clock_voltage_dependency_table *dep_table)
 250{
 251        uint32_t i;
 252        int result;
 253
 254        PP_ASSERT_WITH_CODE((0 != dep_table->count),
 255                        "Voltage Dependency Table empty.", return -EINVAL);
 256
 257        PP_ASSERT_WITH_CODE((NULL != vol_table),
 258                        "vol_table empty.", return -EINVAL);
 259
 260        vol_table->mask_low = 0;
 261        vol_table->phase_delay = 0;
 262        vol_table->count = dep_table->count;
 263
 264        for (i = 0; i < dep_table->count; i++) {
 265                vol_table->entries[i].value = dep_table->entries[i].mvdd;
 266                vol_table->entries[i].smio_low = 0;
 267        }
 268
 269        result = phm_trim_voltage_table(vol_table);
 270        PP_ASSERT_WITH_CODE((0 == result),
 271                        "Failed to trim MVDD table.", return result);
 272
 273        return 0;
 274}
 275
 276int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
 277                phm_ppt_v1_clock_voltage_dependency_table *dep_table)
 278{
 279        uint32_t i;
 280        int result;
 281
 282        PP_ASSERT_WITH_CODE((0 != dep_table->count),
 283                        "Voltage Dependency Table empty.", return -EINVAL);
 284
 285        PP_ASSERT_WITH_CODE((NULL != vol_table),
 286                        "vol_table empty.", return -EINVAL);
 287
 288        vol_table->mask_low = 0;
 289        vol_table->phase_delay = 0;
 290        vol_table->count = dep_table->count;
 291
 292        for (i = 0; i < dep_table->count; i++) {
 293                vol_table->entries[i].value = dep_table->entries[i].vddci;
 294                vol_table->entries[i].smio_low = 0;
 295        }
 296
 297        result = phm_trim_voltage_table(vol_table);
 298        PP_ASSERT_WITH_CODE((0 == result),
 299                        "Failed to trim VDDCI table.", return result);
 300
 301        return 0;
 302}
 303
 304int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
 305                phm_ppt_v1_voltage_lookup_table *lookup_table)
 306{
 307        int i = 0;
 308
 309        PP_ASSERT_WITH_CODE((0 != lookup_table->count),
 310                        "Voltage Lookup Table empty.", return -EINVAL);
 311
 312        PP_ASSERT_WITH_CODE((NULL != vol_table),
 313                        "vol_table empty.", return -EINVAL);
 314
 315        vol_table->mask_low = 0;
 316        vol_table->phase_delay = 0;
 317
 318        vol_table->count = lookup_table->count;
 319
 320        for (i = 0; i < vol_table->count; i++) {
 321                vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
 322                vol_table->entries[i].smio_low = 0;
 323        }
 324
 325        return 0;
 326}
 327
 328void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps,
 329                                struct pp_atomctrl_voltage_table *vol_table)
 330{
 331        unsigned int i, diff;
 332
 333        if (vol_table->count <= max_vol_steps)
 334                return;
 335
 336        diff = vol_table->count - max_vol_steps;
 337
 338        for (i = 0; i < max_vol_steps; i++)
 339                vol_table->entries[i] = vol_table->entries[i + diff];
 340
 341        vol_table->count = max_vol_steps;
 342
 343        return;
 344}
 345
 346int phm_reset_single_dpm_table(void *table,
 347                                uint32_t count, int max)
 348{
 349        int i;
 350
 351        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 352
 353        dpm_table->count = count > max ? max : count;
 354
 355        for (i = 0; i < dpm_table->count; i++)
 356                dpm_table->dpm_level[i].enabled = false;
 357
 358        return 0;
 359}
 360
 361void phm_setup_pcie_table_entry(
 362        void *table,
 363        uint32_t index, uint32_t pcie_gen,
 364        uint32_t pcie_lanes)
 365{
 366        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 367        dpm_table->dpm_level[index].value = pcie_gen;
 368        dpm_table->dpm_level[index].param1 = pcie_lanes;
 369        dpm_table->dpm_level[index].enabled = 1;
 370}
 371
 372int32_t phm_get_dpm_level_enable_mask_value(void *table)
 373{
 374        int32_t i;
 375        int32_t mask = 0;
 376        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 377
 378        for (i = dpm_table->count; i > 0; i--) {
 379                mask = mask << 1;
 380                if (dpm_table->dpm_level[i - 1].enabled)
 381                        mask |= 0x1;
 382                else
 383                        mask &= 0xFFFFFFFE;
 384        }
 385
 386        return mask;
 387}
 388
 389uint8_t phm_get_voltage_index(
 390                struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
 391{
 392        uint8_t count = (uint8_t) (lookup_table->count);
 393        uint8_t i;
 394
 395        PP_ASSERT_WITH_CODE((NULL != lookup_table),
 396                        "Lookup Table empty.", return 0);
 397        PP_ASSERT_WITH_CODE((0 != count),
 398                        "Lookup Table empty.", return 0);
 399
 400        for (i = 0; i < lookup_table->count; i++) {
 401                /* find first voltage equal or bigger than requested */
 402                if (lookup_table->entries[i].us_vdd >= voltage)
 403                        return i;
 404        }
 405        /* voltage is bigger than max voltage in the table */
 406        return i - 1;
 407}
 408
 409uint8_t phm_get_voltage_id(pp_atomctrl_voltage_table *voltage_table,
 410                uint32_t voltage)
 411{
 412        uint8_t count = (uint8_t) (voltage_table->count);
 413        uint8_t i = 0;
 414
 415        PP_ASSERT_WITH_CODE((NULL != voltage_table),
 416                "Voltage Table empty.", return 0;);
 417        PP_ASSERT_WITH_CODE((0 != count),
 418                "Voltage Table empty.", return 0;);
 419
 420        for (i = 0; i < count; i++) {
 421                /* find first voltage bigger than requested */
 422                if (voltage_table->entries[i].value >= voltage)
 423                        return i;
 424        }
 425
 426        /* voltage is bigger than max voltage in the table */
 427        return i - 1;
 428}
 429
 430uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci)
 431{
 432        uint32_t  i;
 433
 434        for (i = 0; i < vddci_table->count; i++) {
 435                if (vddci_table->entries[i].value >= vddci)
 436                        return vddci_table->entries[i].value;
 437        }
 438
 439        pr_debug("vddci is larger than max value in vddci_table\n");
 440        return vddci_table->entries[i-1].value;
 441}
 442
 443int phm_find_boot_level(void *table,
 444                uint32_t value, uint32_t *boot_level)
 445{
 446        int result = -EINVAL;
 447        uint32_t i;
 448        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 449
 450        for (i = 0; i < dpm_table->count; i++) {
 451                if (value == dpm_table->dpm_level[i].value) {
 452                        *boot_level = i;
 453                        result = 0;
 454                }
 455        }
 456
 457        return result;
 458}
 459
 460int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
 461        phm_ppt_v1_voltage_lookup_table *lookup_table,
 462        uint16_t virtual_voltage_id, int32_t *sclk)
 463{
 464        uint8_t entry_id;
 465        uint8_t voltage_id;
 466        struct phm_ppt_v1_information *table_info =
 467                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 468
 469        PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
 470
 471        /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
 472        for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) {
 473                voltage_id = table_info->vdd_dep_on_sclk->entries[entry_id].vddInd;
 474                if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id)
 475                        break;
 476        }
 477
 478        if (entry_id >= table_info->vdd_dep_on_sclk->count) {
 479                pr_debug("Can't find requested voltage id in vdd_dep_on_sclk table\n");
 480                return -EINVAL;
 481        }
 482
 483        *sclk = table_info->vdd_dep_on_sclk->entries[entry_id].clk;
 484
 485        return 0;
 486}
 487
 488/**
 489 * phm_initializa_dynamic_state_adjustment_rule_settings - Initialize Dynamic State Adjustment Rule Settings
 490 *
 491 * @hwmgr:  the address of the powerplay hardware manager.
 492 */
 493int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
 494{
 495        struct phm_clock_voltage_dependency_table *table_clk_vlt;
 496        struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
 497
 498        /* initialize vddc_dep_on_dal_pwrl table */
 499        table_clk_vlt = kzalloc(struct_size(table_clk_vlt, entries, 4),
 500                                GFP_KERNEL);
 501
 502        if (NULL == table_clk_vlt) {
 503                pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n");
 504                return -ENOMEM;
 505        } else {
 506                table_clk_vlt->count = 4;
 507                table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
 508                if (hwmgr->chip_id >= CHIP_POLARIS10 &&
 509                    hwmgr->chip_id <= CHIP_VEGAM)
 510                        table_clk_vlt->entries[0].v = 700;
 511                else
 512                        table_clk_vlt->entries[0].v = 0;
 513                table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
 514                if (hwmgr->chip_id >= CHIP_POLARIS10 &&
 515                    hwmgr->chip_id <= CHIP_VEGAM)
 516                        table_clk_vlt->entries[1].v = 740;
 517                else
 518                        table_clk_vlt->entries[1].v = 720;
 519                table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
 520                if (hwmgr->chip_id >= CHIP_POLARIS10 &&
 521                    hwmgr->chip_id <= CHIP_VEGAM)
 522                        table_clk_vlt->entries[2].v = 800;
 523                else
 524                        table_clk_vlt->entries[2].v = 810;
 525                table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
 526                table_clk_vlt->entries[3].v = 900;
 527                if (pptable_info != NULL)
 528                        pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
 529                hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
 530        }
 531
 532        return 0;
 533}
 534
 535uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
 536{
 537        uint32_t level = 0;
 538
 539        while (0 == (mask & (1 << level)))
 540                level++;
 541
 542        return level;
 543}
 544
 545void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr)
 546{
 547        struct phm_ppt_v1_information *table_info =
 548                        (struct phm_ppt_v1_information *)hwmgr->pptable;
 549        struct phm_clock_voltage_dependency_table *table =
 550                                table_info->vddc_dep_on_dal_pwrl;
 551        struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table;
 552        enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level;
 553        uint32_t req_vddc = 0, req_volt, i;
 554
 555        if (!table || table->count <= 0
 556                || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW
 557                || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE)
 558                return;
 559
 560        for (i = 0; i < table->count; i++) {
 561                if (dal_power_level == table->entries[i].clk) {
 562                        req_vddc = table->entries[i].v;
 563                        break;
 564                }
 565        }
 566
 567        vddc_table = table_info->vdd_dep_on_sclk;
 568        for (i = 0; i < vddc_table->count; i++) {
 569                if (req_vddc <= vddc_table->entries[i].vddc) {
 570                        req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE);
 571                        smum_send_msg_to_smc_with_parameter(hwmgr,
 572                                        PPSMC_MSG_VddC_Request,
 573                                        req_volt,
 574                                        NULL);
 575                        return;
 576                }
 577        }
 578        pr_err("DAL requested level can not"
 579                        " found a available voltage in VDDC DPM Table \n");
 580}
 581
 582int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
 583                                uint32_t sclk, uint16_t id, uint16_t *voltage)
 584{
 585        uint32_t vol;
 586        int ret = 0;
 587
 588        if (hwmgr->chip_id < CHIP_TONGA) {
 589                ret = atomctrl_get_voltage_evv(hwmgr, id, voltage);
 590        } else if (hwmgr->chip_id < CHIP_POLARIS10) {
 591                ret = atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage);
 592                if (*voltage >= 2000 || *voltage == 0)
 593                        *voltage = 1150;
 594        } else {
 595                ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol);
 596                *voltage = (uint16_t)(vol/100);
 597        }
 598        return ret;
 599}
 600
 601
 602int phm_irq_process(struct amdgpu_device *adev,
 603                           struct amdgpu_irq_src *source,
 604                           struct amdgpu_iv_entry *entry)
 605{
 606        uint32_t client_id = entry->client_id;
 607        uint32_t src_id = entry->src_id;
 608
 609        if (client_id == AMDGPU_IRQ_CLIENTID_LEGACY) {
 610                if (src_id == VISLANDS30_IV_SRCID_CG_TSS_THERMAL_LOW_TO_HIGH) {
 611                        dev_emerg(adev->dev, "ERROR: GPU over temperature range(SW CTF) detected!\n");
 612                        /*
 613                         * SW CTF just occurred.
 614                         * Try to do a graceful shutdown to prevent further damage.
 615                         */
 616                        dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU SW CTF!\n");
 617                        orderly_poweroff(true);
 618                } else if (src_id == VISLANDS30_IV_SRCID_CG_TSS_THERMAL_HIGH_TO_LOW)
 619                        dev_emerg(adev->dev, "ERROR: GPU under temperature range detected!\n");
 620                else if (src_id == VISLANDS30_IV_SRCID_GPIO_19) {
 621                        dev_emerg(adev->dev, "ERROR: GPU HW Critical Temperature Fault(aka CTF) detected!\n");
 622                        /*
 623                         * HW CTF just occurred. Shutdown to prevent further damage.
 624                         */
 625                        dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU HW CTF!\n");
 626                        orderly_poweroff(true);
 627                }
 628        } else if (client_id == SOC15_IH_CLIENTID_THM) {
 629                if (src_id == 0) {
 630                        dev_emerg(adev->dev, "ERROR: GPU over temperature range(SW CTF) detected!\n");
 631                        /*
 632                         * SW CTF just occurred.
 633                         * Try to do a graceful shutdown to prevent further damage.
 634                         */
 635                        dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU SW CTF!\n");
 636                        orderly_poweroff(true);
 637                } else
 638                        dev_emerg(adev->dev, "ERROR: GPU under temperature range detected!\n");
 639        } else if (client_id == SOC15_IH_CLIENTID_ROM_SMUIO) {
 640                dev_emerg(adev->dev, "ERROR: GPU HW Critical Temperature Fault(aka CTF) detected!\n");
 641                /*
 642                 * HW CTF just occurred. Shutdown to prevent further damage.
 643                 */
 644                dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU HW CTF!\n");
 645                orderly_poweroff(true);
 646        }
 647
 648        return 0;
 649}
 650
 651static const struct amdgpu_irq_src_funcs smu9_irq_funcs = {
 652        .process = phm_irq_process,
 653};
 654
 655int smu9_register_irq_handlers(struct pp_hwmgr *hwmgr)
 656{
 657        struct amdgpu_irq_src *source =
 658                kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL);
 659
 660        if (!source)
 661                return -ENOMEM;
 662
 663        source->funcs = &smu9_irq_funcs;
 664
 665        amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
 666                        SOC15_IH_CLIENTID_THM,
 667                        THM_9_0__SRCID__THM_DIG_THERM_L2H,
 668                        source);
 669        amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
 670                        SOC15_IH_CLIENTID_THM,
 671                        THM_9_0__SRCID__THM_DIG_THERM_H2L,
 672                        source);
 673
 674        /* Register CTF(GPIO_19) interrupt */
 675        amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
 676                        SOC15_IH_CLIENTID_ROM_SMUIO,
 677                        SMUIO_9_0__SRCID__SMUIO_GPIO19,
 678                        source);
 679
 680        return 0;
 681}
 682
 683void *smu_atom_get_data_table(void *dev, uint32_t table, uint16_t *size,
 684                                                uint8_t *frev, uint8_t *crev)
 685{
 686        struct amdgpu_device *adev = dev;
 687        uint16_t data_start;
 688
 689        if (amdgpu_atom_parse_data_header(
 690                    adev->mode_info.atom_context, table, size,
 691                    frev, crev, &data_start))
 692                return (uint8_t *)adev->mode_info.atom_context->bios +
 693                        data_start;
 694
 695        return NULL;
 696}
 697
 698int smu_get_voltage_dependency_table_ppt_v1(
 699                        const struct phm_ppt_v1_clock_voltage_dependency_table *allowed_dep_table,
 700                        struct phm_ppt_v1_clock_voltage_dependency_table *dep_table)
 701{
 702        uint8_t i = 0;
 703        PP_ASSERT_WITH_CODE((0 != allowed_dep_table->count),
 704                                "Voltage Lookup Table empty",
 705                                return -EINVAL);
 706
 707        dep_table->count = allowed_dep_table->count;
 708        for (i=0; i<dep_table->count; i++) {
 709                dep_table->entries[i].clk = allowed_dep_table->entries[i].clk;
 710                dep_table->entries[i].vddInd = allowed_dep_table->entries[i].vddInd;
 711                dep_table->entries[i].vdd_offset = allowed_dep_table->entries[i].vdd_offset;
 712                dep_table->entries[i].vddc = allowed_dep_table->entries[i].vddc;
 713                dep_table->entries[i].vddgfx = allowed_dep_table->entries[i].vddgfx;
 714                dep_table->entries[i].vddci = allowed_dep_table->entries[i].vddci;
 715                dep_table->entries[i].mvdd = allowed_dep_table->entries[i].mvdd;
 716                dep_table->entries[i].phases = allowed_dep_table->entries[i].phases;
 717                dep_table->entries[i].cks_enable = allowed_dep_table->entries[i].cks_enable;
 718                dep_table->entries[i].cks_voffset = allowed_dep_table->entries[i].cks_voffset;
 719        }
 720
 721        return 0;
 722}
 723
 724int smu_set_watermarks_for_clocks_ranges(void *wt_table,
 725                struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges)
 726{
 727        uint32_t i;
 728        struct watermarks *table = wt_table;
 729
 730        if (!table || !wm_with_clock_ranges)
 731                return -EINVAL;
 732
 733        if (wm_with_clock_ranges->num_wm_dmif_sets > 4 || wm_with_clock_ranges->num_wm_mcif_sets > 4)
 734                return -EINVAL;
 735
 736        for (i = 0; i < wm_with_clock_ranges->num_wm_dmif_sets; i++) {
 737                table->WatermarkRow[1][i].MinClock =
 738                        cpu_to_le16((uint16_t)
 739                        (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
 740                        1000));
 741                table->WatermarkRow[1][i].MaxClock =
 742                        cpu_to_le16((uint16_t)
 743                        (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
 744                        1000));
 745                table->WatermarkRow[1][i].MinUclk =
 746                        cpu_to_le16((uint16_t)
 747                        (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
 748                        1000));
 749                table->WatermarkRow[1][i].MaxUclk =
 750                        cpu_to_le16((uint16_t)
 751                        (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
 752                        1000));
 753                table->WatermarkRow[1][i].WmSetting = (uint8_t)
 754                                wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
 755        }
 756
 757        for (i = 0; i < wm_with_clock_ranges->num_wm_mcif_sets; i++) {
 758                table->WatermarkRow[0][i].MinClock =
 759                        cpu_to_le16((uint16_t)
 760                        (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
 761                        1000));
 762                table->WatermarkRow[0][i].MaxClock =
 763                        cpu_to_le16((uint16_t)
 764                        (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
 765                        1000));
 766                table->WatermarkRow[0][i].MinUclk =
 767                        cpu_to_le16((uint16_t)
 768                        (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
 769                        1000));
 770                table->WatermarkRow[0][i].MaxUclk =
 771                        cpu_to_le16((uint16_t)
 772                        (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
 773                        1000));
 774                table->WatermarkRow[0][i].WmSetting = (uint8_t)
 775                                wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
 776        }
 777        return 0;
 778}
 779