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