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