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 36 uint8_t convert_to_vid(uint16_t vddc) 37 { 38 return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25); 39 } 40 41 uint16_t convert_to_vddc(uint8_t vid) 42 { 43 return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); 44 } 45 46 int 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 68 int 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 90 uint32_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 */ 110 int 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 */ 140 int 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 155 int 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 179 int 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 193 bool 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 198 bool 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 204 int 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 248 int 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 276 int 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 304 int 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 328 void 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 346 int 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 361 void 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 372 int32_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 389 uint8_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 409 uint8_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 430 uint16_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 443 int 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 460 int 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 */ 493 int 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 535 uint32_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 545 void 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 582 int 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 602 int 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 651 static const struct amdgpu_irq_src_funcs smu9_irq_funcs = { 652 .process = phm_irq_process, 653 }; 654 655 int 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 683 void *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 698 int 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 724 int 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