root/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. convert_to_vid
  2. convert_to_vddc
  3. phm_copy_clock_limits_array
  4. phm_copy_overdrive_settings_limits_array
  5. phm_set_field_to_u32
  6. phm_wait_on_register
  7. phm_wait_on_indirect_register
  8. phm_wait_for_register_unequal
  9. phm_wait_for_indirect_register_unequal
  10. phm_cf_want_uvd_power_gating
  11. phm_cf_want_vce_power_gating
  12. phm_trim_voltage_table
  13. phm_get_svi2_mvdd_voltage_table
  14. phm_get_svi2_vddci_voltage_table
  15. phm_get_svi2_vdd_voltage_table
  16. phm_trim_voltage_table_to_fit_state_table
  17. phm_reset_single_dpm_table
  18. phm_setup_pcie_table_entry
  19. phm_get_dpm_level_enable_mask_value
  20. phm_get_voltage_index
  21. phm_get_voltage_id
  22. phm_find_closest_vddci
  23. phm_find_boot_level
  24. phm_get_sclk_for_voltage_evv
  25. phm_initializa_dynamic_state_adjustment_rule_settings
  26. phm_get_lowest_enabled_level
  27. phm_apply_dal_min_voltage_request
  28. phm_get_voltage_evv_on_sclk
  29. phm_irq_process
  30. smu9_register_irq_handlers
  31. smu_atom_get_data_table
  32. smu_get_voltage_dependency_table_ppt_v1
  33. smu_set_watermarks_for_clocks_ranges

   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 
  35 uint8_t convert_to_vid(uint16_t vddc)
  36 {
  37         return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
  38 }
  39 
  40 uint16_t convert_to_vddc(uint8_t vid)
  41 {
  42         return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE);
  43 }
  44 
  45 int 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 
  67 int 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 
  89 uint32_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  */
 109 int 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  */
 139 int 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 
 154 int 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 
 178 int 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 
 192 bool 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 
 197 bool 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 
 203 int 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 
 247 int 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 
 275 int 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 
 303 int 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 
 327 void 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 
 345 int 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 
 360 void 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 
 371 int32_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 
 388 uint8_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 
 408 uint8_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 
 429 uint16_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 
 442 int 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 
 459 int 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  */
 492 int 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 
 523 uint32_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 
 533 void 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 
 568 int 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 
 588 int 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 
 631 static const struct amdgpu_irq_src_funcs smu9_irq_funcs = {
 632         .process = phm_irq_process,
 633 };
 634 
 635 int 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 
 663 void *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 
 678 int 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 
 704 int 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 }

/* [<][>][^][v][top][bottom][index][help] */