18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2011 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Authors: Alex Deucher 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "amdgpu.h" 268c2ecf20Sopenharmony_ci#include "amdgpu_atombios.h" 278c2ecf20Sopenharmony_ci#include "amdgpu_i2c.h" 288c2ecf20Sopenharmony_ci#include "amdgpu_dpm.h" 298c2ecf20Sopenharmony_ci#include "atom.h" 308c2ecf20Sopenharmony_ci#include "amd_pcie.h" 318c2ecf20Sopenharmony_ci#include "amdgpu_display.h" 328c2ecf20Sopenharmony_ci#include "hwmgr.h" 338c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define WIDTH_4K 3840 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_civoid amdgpu_dpm_print_class_info(u32 class, u32 class2) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci const char *s; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { 428c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_NONE: 438c2ecf20Sopenharmony_ci default: 448c2ecf20Sopenharmony_ci s = "none"; 458c2ecf20Sopenharmony_ci break; 468c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: 478c2ecf20Sopenharmony_ci s = "battery"; 488c2ecf20Sopenharmony_ci break; 498c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: 508c2ecf20Sopenharmony_ci s = "balanced"; 518c2ecf20Sopenharmony_ci break; 528c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: 538c2ecf20Sopenharmony_ci s = "performance"; 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci printk("\tui class: %s\n", s); 578c2ecf20Sopenharmony_ci printk("\tinternal class:"); 588c2ecf20Sopenharmony_ci if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) && 598c2ecf20Sopenharmony_ci (class2 == 0)) 608c2ecf20Sopenharmony_ci pr_cont(" none"); 618c2ecf20Sopenharmony_ci else { 628c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_BOOT) 638c2ecf20Sopenharmony_ci pr_cont(" boot"); 648c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL) 658c2ecf20Sopenharmony_ci pr_cont(" thermal"); 668c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) 678c2ecf20Sopenharmony_ci pr_cont(" limited_pwr"); 688c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_REST) 698c2ecf20Sopenharmony_ci pr_cont(" rest"); 708c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_FORCED) 718c2ecf20Sopenharmony_ci pr_cont(" forced"); 728c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) 738c2ecf20Sopenharmony_ci pr_cont(" 3d_perf"); 748c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE) 758c2ecf20Sopenharmony_ci pr_cont(" ovrdrv"); 768c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 778c2ecf20Sopenharmony_ci pr_cont(" uvd"); 788c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW) 798c2ecf20Sopenharmony_ci pr_cont(" 3d_low"); 808c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_ACPI) 818c2ecf20Sopenharmony_ci pr_cont(" acpi"); 828c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) 838c2ecf20Sopenharmony_ci pr_cont(" uvd_hd2"); 848c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) 858c2ecf20Sopenharmony_ci pr_cont(" uvd_hd"); 868c2ecf20Sopenharmony_ci if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) 878c2ecf20Sopenharmony_ci pr_cont(" uvd_sd"); 888c2ecf20Sopenharmony_ci if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) 898c2ecf20Sopenharmony_ci pr_cont(" limited_pwr2"); 908c2ecf20Sopenharmony_ci if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) 918c2ecf20Sopenharmony_ci pr_cont(" ulv"); 928c2ecf20Sopenharmony_ci if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) 938c2ecf20Sopenharmony_ci pr_cont(" uvd_mvc"); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci pr_cont("\n"); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_civoid amdgpu_dpm_print_cap_info(u32 caps) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci printk("\tcaps:"); 1018c2ecf20Sopenharmony_ci if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) 1028c2ecf20Sopenharmony_ci pr_cont(" single_disp"); 1038c2ecf20Sopenharmony_ci if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK) 1048c2ecf20Sopenharmony_ci pr_cont(" video"); 1058c2ecf20Sopenharmony_ci if (caps & ATOM_PPLIB_DISALLOW_ON_DC) 1068c2ecf20Sopenharmony_ci pr_cont(" no_dc"); 1078c2ecf20Sopenharmony_ci pr_cont("\n"); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_civoid amdgpu_dpm_print_ps_status(struct amdgpu_device *adev, 1118c2ecf20Sopenharmony_ci struct amdgpu_ps *rps) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci printk("\tstatus:"); 1148c2ecf20Sopenharmony_ci if (rps == adev->pm.dpm.current_ps) 1158c2ecf20Sopenharmony_ci pr_cont(" c"); 1168c2ecf20Sopenharmony_ci if (rps == adev->pm.dpm.requested_ps) 1178c2ecf20Sopenharmony_ci pr_cont(" r"); 1188c2ecf20Sopenharmony_ci if (rps == adev->pm.dpm.boot_ps) 1198c2ecf20Sopenharmony_ci pr_cont(" b"); 1208c2ecf20Sopenharmony_ci pr_cont("\n"); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_civoid amdgpu_dpm_get_active_displays(struct amdgpu_device *adev) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct drm_device *ddev = adev_to_drm(adev); 1268c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 1278c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci adev->pm.dpm.new_active_crtcs = 0; 1308c2ecf20Sopenharmony_ci adev->pm.dpm.new_active_crtc_count = 0; 1318c2ecf20Sopenharmony_ci if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { 1328c2ecf20Sopenharmony_ci list_for_each_entry(crtc, 1338c2ecf20Sopenharmony_ci &ddev->mode_config.crtc_list, head) { 1348c2ecf20Sopenharmony_ci amdgpu_crtc = to_amdgpu_crtc(crtc); 1358c2ecf20Sopenharmony_ci if (amdgpu_crtc->enabled) { 1368c2ecf20Sopenharmony_ci adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id); 1378c2ecf20Sopenharmony_ci adev->pm.dpm.new_active_crtc_count++; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciu32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct drm_device *dev = adev_to_drm(adev); 1478c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 1488c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc; 1498c2ecf20Sopenharmony_ci u32 vblank_in_pixels; 1508c2ecf20Sopenharmony_ci u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { 1538c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 1548c2ecf20Sopenharmony_ci amdgpu_crtc = to_amdgpu_crtc(crtc); 1558c2ecf20Sopenharmony_ci if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) { 1568c2ecf20Sopenharmony_ci vblank_in_pixels = 1578c2ecf20Sopenharmony_ci amdgpu_crtc->hw_mode.crtc_htotal * 1588c2ecf20Sopenharmony_ci (amdgpu_crtc->hw_mode.crtc_vblank_end - 1598c2ecf20Sopenharmony_ci amdgpu_crtc->hw_mode.crtc_vdisplay + 1608c2ecf20Sopenharmony_ci (amdgpu_crtc->v_border * 2)); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return vblank_time_us; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciu32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct drm_device *dev = adev_to_drm(adev); 1748c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 1758c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc; 1768c2ecf20Sopenharmony_ci u32 vrefresh = 0; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { 1798c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 1808c2ecf20Sopenharmony_ci amdgpu_crtc = to_amdgpu_crtc(crtc); 1818c2ecf20Sopenharmony_ci if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) { 1828c2ecf20Sopenharmony_ci vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode); 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return vrefresh; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cibool amdgpu_is_internal_thermal_sensor(enum amdgpu_int_thermal_type sensor) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci switch (sensor) { 1948c2ecf20Sopenharmony_ci case THERMAL_TYPE_RV6XX: 1958c2ecf20Sopenharmony_ci case THERMAL_TYPE_RV770: 1968c2ecf20Sopenharmony_ci case THERMAL_TYPE_EVERGREEN: 1978c2ecf20Sopenharmony_ci case THERMAL_TYPE_SUMO: 1988c2ecf20Sopenharmony_ci case THERMAL_TYPE_NI: 1998c2ecf20Sopenharmony_ci case THERMAL_TYPE_SI: 2008c2ecf20Sopenharmony_ci case THERMAL_TYPE_CI: 2018c2ecf20Sopenharmony_ci case THERMAL_TYPE_KV: 2028c2ecf20Sopenharmony_ci return true; 2038c2ecf20Sopenharmony_ci case THERMAL_TYPE_ADT7473_WITH_INTERNAL: 2048c2ecf20Sopenharmony_ci case THERMAL_TYPE_EMC2103_WITH_INTERNAL: 2058c2ecf20Sopenharmony_ci return false; /* need special handling */ 2068c2ecf20Sopenharmony_ci case THERMAL_TYPE_NONE: 2078c2ecf20Sopenharmony_ci case THERMAL_TYPE_EXTERNAL: 2088c2ecf20Sopenharmony_ci case THERMAL_TYPE_EXTERNAL_GPIO: 2098c2ecf20Sopenharmony_ci default: 2108c2ecf20Sopenharmony_ci return false; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciunion power_info { 2158c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO info; 2168c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V2 info_2; 2178c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V3 info_3; 2188c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 2198c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 2208c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 2218c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4; 2228c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5; 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciunion fan_info { 2268c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_FANTABLE fan; 2278c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_FANTABLE2 fan2; 2288c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_FANTABLE3 fan3; 2298c2ecf20Sopenharmony_ci}; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int amdgpu_parse_clk_voltage_dep_table(struct amdgpu_clock_voltage_dependency_table *amdgpu_table, 2328c2ecf20Sopenharmony_ci ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci u32 size = atom_table->ucNumEntries * 2358c2ecf20Sopenharmony_ci sizeof(struct amdgpu_clock_voltage_dependency_entry); 2368c2ecf20Sopenharmony_ci int i; 2378c2ecf20Sopenharmony_ci ATOM_PPLIB_Clock_Voltage_Dependency_Record *entry; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci amdgpu_table->entries = kzalloc(size, GFP_KERNEL); 2408c2ecf20Sopenharmony_ci if (!amdgpu_table->entries) 2418c2ecf20Sopenharmony_ci return -ENOMEM; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci entry = &atom_table->entries[0]; 2448c2ecf20Sopenharmony_ci for (i = 0; i < atom_table->ucNumEntries; i++) { 2458c2ecf20Sopenharmony_ci amdgpu_table->entries[i].clk = le16_to_cpu(entry->usClockLow) | 2468c2ecf20Sopenharmony_ci (entry->ucClockHigh << 16); 2478c2ecf20Sopenharmony_ci amdgpu_table->entries[i].v = le16_to_cpu(entry->usVoltage); 2488c2ecf20Sopenharmony_ci entry = (ATOM_PPLIB_Clock_Voltage_Dependency_Record *) 2498c2ecf20Sopenharmony_ci ((u8 *)entry + sizeof(ATOM_PPLIB_Clock_Voltage_Dependency_Record)); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci amdgpu_table->count = atom_table->ucNumEntries; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciint amdgpu_get_platform_caps(struct amdgpu_device *adev) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct amdgpu_mode_info *mode_info = &adev->mode_info; 2598c2ecf20Sopenharmony_ci union power_info *power_info; 2608c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 2618c2ecf20Sopenharmony_ci u16 data_offset; 2628c2ecf20Sopenharmony_ci u8 frev, crev; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, 2658c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 2668c2ecf20Sopenharmony_ci return -EINVAL; 2678c2ecf20Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci adev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); 2708c2ecf20Sopenharmony_ci adev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); 2718c2ecf20Sopenharmony_ci adev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */ 2778c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12 2788c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14 2798c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16 2808c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18 2818c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20 2828c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22 2838c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24 2848c2ecf20Sopenharmony_ci#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ciint amdgpu_parse_extended_power_table(struct amdgpu_device *adev) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct amdgpu_mode_info *mode_info = &adev->mode_info; 2898c2ecf20Sopenharmony_ci union power_info *power_info; 2908c2ecf20Sopenharmony_ci union fan_info *fan_info; 2918c2ecf20Sopenharmony_ci ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table; 2928c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 2938c2ecf20Sopenharmony_ci u16 data_offset; 2948c2ecf20Sopenharmony_ci u8 frev, crev; 2958c2ecf20Sopenharmony_ci int ret, i; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, 2988c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 2998c2ecf20Sopenharmony_ci return -EINVAL; 3008c2ecf20Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* fan table */ 3038c2ecf20Sopenharmony_ci if (le16_to_cpu(power_info->pplib.usTableSize) >= 3048c2ecf20Sopenharmony_ci sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) { 3058c2ecf20Sopenharmony_ci if (power_info->pplib3.usFanTableOffset) { 3068c2ecf20Sopenharmony_ci fan_info = (union fan_info *)(mode_info->atom_context->bios + data_offset + 3078c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib3.usFanTableOffset)); 3088c2ecf20Sopenharmony_ci adev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst; 3098c2ecf20Sopenharmony_ci adev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin); 3108c2ecf20Sopenharmony_ci adev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed); 3118c2ecf20Sopenharmony_ci adev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh); 3128c2ecf20Sopenharmony_ci adev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin); 3138c2ecf20Sopenharmony_ci adev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed); 3148c2ecf20Sopenharmony_ci adev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh); 3158c2ecf20Sopenharmony_ci if (fan_info->fan.ucFanTableFormat >= 2) 3168c2ecf20Sopenharmony_ci adev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax); 3178c2ecf20Sopenharmony_ci else 3188c2ecf20Sopenharmony_ci adev->pm.dpm.fan.t_max = 10900; 3198c2ecf20Sopenharmony_ci adev->pm.dpm.fan.cycle_delay = 100000; 3208c2ecf20Sopenharmony_ci if (fan_info->fan.ucFanTableFormat >= 3) { 3218c2ecf20Sopenharmony_ci adev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode; 3228c2ecf20Sopenharmony_ci adev->pm.dpm.fan.default_max_fan_pwm = 3238c2ecf20Sopenharmony_ci le16_to_cpu(fan_info->fan3.usFanPWMMax); 3248c2ecf20Sopenharmony_ci adev->pm.dpm.fan.default_fan_output_sensitivity = 4836; 3258c2ecf20Sopenharmony_ci adev->pm.dpm.fan.fan_output_sensitivity = 3268c2ecf20Sopenharmony_ci le16_to_cpu(fan_info->fan3.usFanOutputSensitivity); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci adev->pm.dpm.fan.ucode_fan_control = true; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* clock dependancy tables, shedding tables */ 3338c2ecf20Sopenharmony_ci if (le16_to_cpu(power_info->pplib.usTableSize) >= 3348c2ecf20Sopenharmony_ci sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE4)) { 3358c2ecf20Sopenharmony_ci if (power_info->pplib4.usVddcDependencyOnSCLKOffset) { 3368c2ecf20Sopenharmony_ci dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 3378c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 3388c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset)); 3398c2ecf20Sopenharmony_ci ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk, 3408c2ecf20Sopenharmony_ci dep_table); 3418c2ecf20Sopenharmony_ci if (ret) { 3428c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci if (power_info->pplib4.usVddciDependencyOnMCLKOffset) { 3478c2ecf20Sopenharmony_ci dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 3488c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 3498c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset)); 3508c2ecf20Sopenharmony_ci ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk, 3518c2ecf20Sopenharmony_ci dep_table); 3528c2ecf20Sopenharmony_ci if (ret) { 3538c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 3548c2ecf20Sopenharmony_ci return ret; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci if (power_info->pplib4.usVddcDependencyOnMCLKOffset) { 3588c2ecf20Sopenharmony_ci dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 3598c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 3608c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset)); 3618c2ecf20Sopenharmony_ci ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk, 3628c2ecf20Sopenharmony_ci dep_table); 3638c2ecf20Sopenharmony_ci if (ret) { 3648c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci if (power_info->pplib4.usMvddDependencyOnMCLKOffset) { 3698c2ecf20Sopenharmony_ci dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 3708c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 3718c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset)); 3728c2ecf20Sopenharmony_ci ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk, 3738c2ecf20Sopenharmony_ci dep_table); 3748c2ecf20Sopenharmony_ci if (ret) { 3758c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 3768c2ecf20Sopenharmony_ci return ret; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci if (power_info->pplib4.usMaxClockVoltageOnDCOffset) { 3808c2ecf20Sopenharmony_ci ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v = 3818c2ecf20Sopenharmony_ci (ATOM_PPLIB_Clock_Voltage_Limit_Table *) 3828c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 3838c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset)); 3848c2ecf20Sopenharmony_ci if (clk_v->ucNumEntries) { 3858c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk = 3868c2ecf20Sopenharmony_ci le16_to_cpu(clk_v->entries[0].usSclkLow) | 3878c2ecf20Sopenharmony_ci (clk_v->entries[0].ucSclkHigh << 16); 3888c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk = 3898c2ecf20Sopenharmony_ci le16_to_cpu(clk_v->entries[0].usMclkLow) | 3908c2ecf20Sopenharmony_ci (clk_v->entries[0].ucMclkHigh << 16); 3918c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc = 3928c2ecf20Sopenharmony_ci le16_to_cpu(clk_v->entries[0].usVddc); 3938c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci = 3948c2ecf20Sopenharmony_ci le16_to_cpu(clk_v->entries[0].usVddci); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci if (power_info->pplib4.usVddcPhaseShedLimitsTableOffset) { 3988c2ecf20Sopenharmony_ci ATOM_PPLIB_PhaseSheddingLimits_Table *psl = 3998c2ecf20Sopenharmony_ci (ATOM_PPLIB_PhaseSheddingLimits_Table *) 4008c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 4018c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib4.usVddcPhaseShedLimitsTableOffset)); 4028c2ecf20Sopenharmony_ci ATOM_PPLIB_PhaseSheddingLimits_Record *entry; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries = 4058c2ecf20Sopenharmony_ci kcalloc(psl->ucNumEntries, 4068c2ecf20Sopenharmony_ci sizeof(struct amdgpu_phase_shedding_limits_entry), 4078c2ecf20Sopenharmony_ci GFP_KERNEL); 4088c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) { 4098c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 4108c2ecf20Sopenharmony_ci return -ENOMEM; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci entry = &psl->entries[0]; 4148c2ecf20Sopenharmony_ci for (i = 0; i < psl->ucNumEntries; i++) { 4158c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].sclk = 4168c2ecf20Sopenharmony_ci le16_to_cpu(entry->usSclkLow) | (entry->ucSclkHigh << 16); 4178c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].mclk = 4188c2ecf20Sopenharmony_ci le16_to_cpu(entry->usMclkLow) | (entry->ucMclkHigh << 16); 4198c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].voltage = 4208c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVoltage); 4218c2ecf20Sopenharmony_ci entry = (ATOM_PPLIB_PhaseSheddingLimits_Record *) 4228c2ecf20Sopenharmony_ci ((u8 *)entry + sizeof(ATOM_PPLIB_PhaseSheddingLimits_Record)); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.phase_shedding_limits_table.count = 4258c2ecf20Sopenharmony_ci psl->ucNumEntries; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* cac data */ 4308c2ecf20Sopenharmony_ci if (le16_to_cpu(power_info->pplib.usTableSize) >= 4318c2ecf20Sopenharmony_ci sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE5)) { 4328c2ecf20Sopenharmony_ci adev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit); 4338c2ecf20Sopenharmony_ci adev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit); 4348c2ecf20Sopenharmony_ci adev->pm.dpm.near_tdp_limit_adjusted = adev->pm.dpm.near_tdp_limit; 4358c2ecf20Sopenharmony_ci adev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit); 4368c2ecf20Sopenharmony_ci if (adev->pm.dpm.tdp_od_limit) 4378c2ecf20Sopenharmony_ci adev->pm.dpm.power_control = true; 4388c2ecf20Sopenharmony_ci else 4398c2ecf20Sopenharmony_ci adev->pm.dpm.power_control = false; 4408c2ecf20Sopenharmony_ci adev->pm.dpm.tdp_adjustment = 0; 4418c2ecf20Sopenharmony_ci adev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold); 4428c2ecf20Sopenharmony_ci adev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage); 4438c2ecf20Sopenharmony_ci adev->pm.dpm.load_line_slope = le16_to_cpu(power_info->pplib5.usLoadLineSlope); 4448c2ecf20Sopenharmony_ci if (power_info->pplib5.usCACLeakageTableOffset) { 4458c2ecf20Sopenharmony_ci ATOM_PPLIB_CAC_Leakage_Table *cac_table = 4468c2ecf20Sopenharmony_ci (ATOM_PPLIB_CAC_Leakage_Table *) 4478c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 4488c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset)); 4498c2ecf20Sopenharmony_ci ATOM_PPLIB_CAC_Leakage_Record *entry; 4508c2ecf20Sopenharmony_ci u32 size = cac_table->ucNumEntries * sizeof(struct amdgpu_cac_leakage_table); 4518c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL); 4528c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries) { 4538c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 4548c2ecf20Sopenharmony_ci return -ENOMEM; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci entry = &cac_table->entries[0]; 4578c2ecf20Sopenharmony_ci for (i = 0; i < cac_table->ucNumEntries; i++) { 4588c2ecf20Sopenharmony_ci if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) { 4598c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1 = 4608c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVddc1); 4618c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2 = 4628c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVddc2); 4638c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3 = 4648c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVddc3); 4658c2ecf20Sopenharmony_ci } else { 4668c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc = 4678c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVddc); 4688c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage = 4698c2ecf20Sopenharmony_ci le32_to_cpu(entry->ulLeakageValue); 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci entry = (ATOM_PPLIB_CAC_Leakage_Record *) 4728c2ecf20Sopenharmony_ci ((u8 *)entry + sizeof(ATOM_PPLIB_CAC_Leakage_Record)); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* ext tables */ 4798c2ecf20Sopenharmony_ci if (le16_to_cpu(power_info->pplib.usTableSize) >= 4808c2ecf20Sopenharmony_ci sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) { 4818c2ecf20Sopenharmony_ci ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = (ATOM_PPLIB_EXTENDEDHEADER *) 4828c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 4838c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset)); 4848c2ecf20Sopenharmony_ci if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) && 4858c2ecf20Sopenharmony_ci ext_hdr->usVCETableOffset) { 4868c2ecf20Sopenharmony_ci VCEClockInfoArray *array = (VCEClockInfoArray *) 4878c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 4888c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usVCETableOffset) + 1); 4898c2ecf20Sopenharmony_ci ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *limits = 4908c2ecf20Sopenharmony_ci (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *) 4918c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 4928c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usVCETableOffset) + 1 + 4938c2ecf20Sopenharmony_ci 1 + array->ucNumEntries * sizeof(VCEClockInfo)); 4948c2ecf20Sopenharmony_ci ATOM_PPLIB_VCE_State_Table *states = 4958c2ecf20Sopenharmony_ci (ATOM_PPLIB_VCE_State_Table *) 4968c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 4978c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usVCETableOffset) + 1 + 4988c2ecf20Sopenharmony_ci 1 + (array->ucNumEntries * sizeof (VCEClockInfo)) + 4998c2ecf20Sopenharmony_ci 1 + (limits->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record))); 5008c2ecf20Sopenharmony_ci ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *entry; 5018c2ecf20Sopenharmony_ci ATOM_PPLIB_VCE_State_Record *state_entry; 5028c2ecf20Sopenharmony_ci VCEClockInfo *vce_clk; 5038c2ecf20Sopenharmony_ci u32 size = limits->numEntries * 5048c2ecf20Sopenharmony_ci sizeof(struct amdgpu_vce_clock_voltage_dependency_entry); 5058c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries = 5068c2ecf20Sopenharmony_ci kzalloc(size, GFP_KERNEL); 5078c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries) { 5088c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 5098c2ecf20Sopenharmony_ci return -ENOMEM; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count = 5128c2ecf20Sopenharmony_ci limits->numEntries; 5138c2ecf20Sopenharmony_ci entry = &limits->entries[0]; 5148c2ecf20Sopenharmony_ci state_entry = &states->entries[0]; 5158c2ecf20Sopenharmony_ci for (i = 0; i < limits->numEntries; i++) { 5168c2ecf20Sopenharmony_ci vce_clk = (VCEClockInfo *) 5178c2ecf20Sopenharmony_ci ((u8 *)&array->entries[0] + 5188c2ecf20Sopenharmony_ci (entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo))); 5198c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk = 5208c2ecf20Sopenharmony_ci le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16); 5218c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].ecclk = 5228c2ecf20Sopenharmony_ci le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16); 5238c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v = 5248c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVoltage); 5258c2ecf20Sopenharmony_ci entry = (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *) 5268c2ecf20Sopenharmony_ci ((u8 *)entry + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci adev->pm.dpm.num_of_vce_states = 5298c2ecf20Sopenharmony_ci states->numEntries > AMD_MAX_VCE_LEVELS ? 5308c2ecf20Sopenharmony_ci AMD_MAX_VCE_LEVELS : states->numEntries; 5318c2ecf20Sopenharmony_ci for (i = 0; i < adev->pm.dpm.num_of_vce_states; i++) { 5328c2ecf20Sopenharmony_ci vce_clk = (VCEClockInfo *) 5338c2ecf20Sopenharmony_ci ((u8 *)&array->entries[0] + 5348c2ecf20Sopenharmony_ci (state_entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo))); 5358c2ecf20Sopenharmony_ci adev->pm.dpm.vce_states[i].evclk = 5368c2ecf20Sopenharmony_ci le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16); 5378c2ecf20Sopenharmony_ci adev->pm.dpm.vce_states[i].ecclk = 5388c2ecf20Sopenharmony_ci le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16); 5398c2ecf20Sopenharmony_ci adev->pm.dpm.vce_states[i].clk_idx = 5408c2ecf20Sopenharmony_ci state_entry->ucClockInfoIndex & 0x3f; 5418c2ecf20Sopenharmony_ci adev->pm.dpm.vce_states[i].pstate = 5428c2ecf20Sopenharmony_ci (state_entry->ucClockInfoIndex & 0xc0) >> 6; 5438c2ecf20Sopenharmony_ci state_entry = (ATOM_PPLIB_VCE_State_Record *) 5448c2ecf20Sopenharmony_ci ((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record)); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) && 5488c2ecf20Sopenharmony_ci ext_hdr->usUVDTableOffset) { 5498c2ecf20Sopenharmony_ci UVDClockInfoArray *array = (UVDClockInfoArray *) 5508c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 5518c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usUVDTableOffset) + 1); 5528c2ecf20Sopenharmony_ci ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *limits = 5538c2ecf20Sopenharmony_ci (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *) 5548c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 5558c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usUVDTableOffset) + 1 + 5568c2ecf20Sopenharmony_ci 1 + (array->ucNumEntries * sizeof (UVDClockInfo))); 5578c2ecf20Sopenharmony_ci ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *entry; 5588c2ecf20Sopenharmony_ci u32 size = limits->numEntries * 5598c2ecf20Sopenharmony_ci sizeof(struct amdgpu_uvd_clock_voltage_dependency_entry); 5608c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries = 5618c2ecf20Sopenharmony_ci kzalloc(size, GFP_KERNEL); 5628c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries) { 5638c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 5648c2ecf20Sopenharmony_ci return -ENOMEM; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count = 5678c2ecf20Sopenharmony_ci limits->numEntries; 5688c2ecf20Sopenharmony_ci entry = &limits->entries[0]; 5698c2ecf20Sopenharmony_ci for (i = 0; i < limits->numEntries; i++) { 5708c2ecf20Sopenharmony_ci UVDClockInfo *uvd_clk = (UVDClockInfo *) 5718c2ecf20Sopenharmony_ci ((u8 *)&array->entries[0] + 5728c2ecf20Sopenharmony_ci (entry->ucUVDClockInfoIndex * sizeof(UVDClockInfo))); 5738c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].vclk = 5748c2ecf20Sopenharmony_ci le16_to_cpu(uvd_clk->usVClkLow) | (uvd_clk->ucVClkHigh << 16); 5758c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].dclk = 5768c2ecf20Sopenharmony_ci le16_to_cpu(uvd_clk->usDClkLow) | (uvd_clk->ucDClkHigh << 16); 5778c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v = 5788c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVoltage); 5798c2ecf20Sopenharmony_ci entry = (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *) 5808c2ecf20Sopenharmony_ci ((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record)); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) && 5848c2ecf20Sopenharmony_ci ext_hdr->usSAMUTableOffset) { 5858c2ecf20Sopenharmony_ci ATOM_PPLIB_SAMClk_Voltage_Limit_Table *limits = 5868c2ecf20Sopenharmony_ci (ATOM_PPLIB_SAMClk_Voltage_Limit_Table *) 5878c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 5888c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usSAMUTableOffset) + 1); 5898c2ecf20Sopenharmony_ci ATOM_PPLIB_SAMClk_Voltage_Limit_Record *entry; 5908c2ecf20Sopenharmony_ci u32 size = limits->numEntries * 5918c2ecf20Sopenharmony_ci sizeof(struct amdgpu_clock_voltage_dependency_entry); 5928c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries = 5938c2ecf20Sopenharmony_ci kzalloc(size, GFP_KERNEL); 5948c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries) { 5958c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 5968c2ecf20Sopenharmony_ci return -ENOMEM; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count = 5998c2ecf20Sopenharmony_ci limits->numEntries; 6008c2ecf20Sopenharmony_ci entry = &limits->entries[0]; 6018c2ecf20Sopenharmony_ci for (i = 0; i < limits->numEntries; i++) { 6028c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].clk = 6038c2ecf20Sopenharmony_ci le16_to_cpu(entry->usSAMClockLow) | (entry->ucSAMClockHigh << 16); 6048c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v = 6058c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVoltage); 6068c2ecf20Sopenharmony_ci entry = (ATOM_PPLIB_SAMClk_Voltage_Limit_Record *) 6078c2ecf20Sopenharmony_ci ((u8 *)entry + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record)); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) && 6118c2ecf20Sopenharmony_ci ext_hdr->usPPMTableOffset) { 6128c2ecf20Sopenharmony_ci ATOM_PPLIB_PPM_Table *ppm = (ATOM_PPLIB_PPM_Table *) 6138c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 6148c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usPPMTableOffset)); 6158c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table = 6168c2ecf20Sopenharmony_ci kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL); 6178c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.ppm_table) { 6188c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 6198c2ecf20Sopenharmony_ci return -ENOMEM; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign; 6228c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->cpu_core_number = 6238c2ecf20Sopenharmony_ci le16_to_cpu(ppm->usCpuCoreNumber); 6248c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->platform_tdp = 6258c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulPlatformTDP); 6268c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdp = 6278c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulSmallACPlatformTDP); 6288c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->platform_tdc = 6298c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulPlatformTDC); 6308c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdc = 6318c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulSmallACPlatformTDC); 6328c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->apu_tdp = 6338c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulApuTDP); 6348c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->dgpu_tdp = 6358c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulDGpuTDP); 6368c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->dgpu_ulv_power = 6378c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulDGpuUlvPower); 6388c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.ppm_table->tj_max = 6398c2ecf20Sopenharmony_ci le32_to_cpu(ppm->ulTjmax); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) && 6428c2ecf20Sopenharmony_ci ext_hdr->usACPTableOffset) { 6438c2ecf20Sopenharmony_ci ATOM_PPLIB_ACPClk_Voltage_Limit_Table *limits = 6448c2ecf20Sopenharmony_ci (ATOM_PPLIB_ACPClk_Voltage_Limit_Table *) 6458c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 6468c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usACPTableOffset) + 1); 6478c2ecf20Sopenharmony_ci ATOM_PPLIB_ACPClk_Voltage_Limit_Record *entry; 6488c2ecf20Sopenharmony_ci u32 size = limits->numEntries * 6498c2ecf20Sopenharmony_ci sizeof(struct amdgpu_clock_voltage_dependency_entry); 6508c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries = 6518c2ecf20Sopenharmony_ci kzalloc(size, GFP_KERNEL); 6528c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries) { 6538c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 6548c2ecf20Sopenharmony_ci return -ENOMEM; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count = 6578c2ecf20Sopenharmony_ci limits->numEntries; 6588c2ecf20Sopenharmony_ci entry = &limits->entries[0]; 6598c2ecf20Sopenharmony_ci for (i = 0; i < limits->numEntries; i++) { 6608c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].clk = 6618c2ecf20Sopenharmony_ci le16_to_cpu(entry->usACPClockLow) | (entry->ucACPClockHigh << 16); 6628c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v = 6638c2ecf20Sopenharmony_ci le16_to_cpu(entry->usVoltage); 6648c2ecf20Sopenharmony_ci entry = (ATOM_PPLIB_ACPClk_Voltage_Limit_Record *) 6658c2ecf20Sopenharmony_ci ((u8 *)entry + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record)); 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) && 6698c2ecf20Sopenharmony_ci ext_hdr->usPowerTuneTableOffset) { 6708c2ecf20Sopenharmony_ci u8 rev = *(u8 *)(mode_info->atom_context->bios + data_offset + 6718c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); 6728c2ecf20Sopenharmony_ci ATOM_PowerTune_Table *pt; 6738c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table = 6748c2ecf20Sopenharmony_ci kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL); 6758c2ecf20Sopenharmony_ci if (!adev->pm.dpm.dyn_state.cac_tdp_table) { 6768c2ecf20Sopenharmony_ci amdgpu_free_extended_power_table(adev); 6778c2ecf20Sopenharmony_ci return -ENOMEM; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci if (rev > 0) { 6808c2ecf20Sopenharmony_ci ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *) 6818c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 6828c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); 6838c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = 6848c2ecf20Sopenharmony_ci ppt->usMaximumPowerDeliveryLimit; 6858c2ecf20Sopenharmony_ci pt = &ppt->power_tune_table; 6868c2ecf20Sopenharmony_ci } else { 6878c2ecf20Sopenharmony_ci ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *) 6888c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 6898c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); 6908c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = 255; 6918c2ecf20Sopenharmony_ci pt = &ppt->power_tune_table; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->tdp = le16_to_cpu(pt->usTDP); 6948c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->configurable_tdp = 6958c2ecf20Sopenharmony_ci le16_to_cpu(pt->usConfigurableTDP); 6968c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->tdc = le16_to_cpu(pt->usTDC); 6978c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->battery_power_limit = 6988c2ecf20Sopenharmony_ci le16_to_cpu(pt->usBatteryPowerLimit); 6998c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->small_power_limit = 7008c2ecf20Sopenharmony_ci le16_to_cpu(pt->usSmallPowerLimit); 7018c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->low_cac_leakage = 7028c2ecf20Sopenharmony_ci le16_to_cpu(pt->usLowCACLeakage); 7038c2ecf20Sopenharmony_ci adev->pm.dpm.dyn_state.cac_tdp_table->high_cac_leakage = 7048c2ecf20Sopenharmony_ci le16_to_cpu(pt->usHighCACLeakage); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8) && 7078c2ecf20Sopenharmony_ci ext_hdr->usSclkVddgfxTableOffset) { 7088c2ecf20Sopenharmony_ci dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 7098c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 7108c2ecf20Sopenharmony_ci le16_to_cpu(ext_hdr->usSclkVddgfxTableOffset)); 7118c2ecf20Sopenharmony_ci ret = amdgpu_parse_clk_voltage_dep_table( 7128c2ecf20Sopenharmony_ci &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk, 7138c2ecf20Sopenharmony_ci dep_table); 7148c2ecf20Sopenharmony_ci if (ret) { 7158c2ecf20Sopenharmony_ci kfree(adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk.entries); 7168c2ecf20Sopenharmony_ci return ret; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return 0; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_civoid amdgpu_free_extended_power_table(struct amdgpu_device *adev) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct amdgpu_dpm_dynamic_state *dyn_state = &adev->pm.dpm.dyn_state; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci kfree(dyn_state->vddc_dependency_on_sclk.entries); 7298c2ecf20Sopenharmony_ci kfree(dyn_state->vddci_dependency_on_mclk.entries); 7308c2ecf20Sopenharmony_ci kfree(dyn_state->vddc_dependency_on_mclk.entries); 7318c2ecf20Sopenharmony_ci kfree(dyn_state->mvdd_dependency_on_mclk.entries); 7328c2ecf20Sopenharmony_ci kfree(dyn_state->cac_leakage_table.entries); 7338c2ecf20Sopenharmony_ci kfree(dyn_state->phase_shedding_limits_table.entries); 7348c2ecf20Sopenharmony_ci kfree(dyn_state->ppm_table); 7358c2ecf20Sopenharmony_ci kfree(dyn_state->cac_tdp_table); 7368c2ecf20Sopenharmony_ci kfree(dyn_state->vce_clock_voltage_dependency_table.entries); 7378c2ecf20Sopenharmony_ci kfree(dyn_state->uvd_clock_voltage_dependency_table.entries); 7388c2ecf20Sopenharmony_ci kfree(dyn_state->samu_clock_voltage_dependency_table.entries); 7398c2ecf20Sopenharmony_ci kfree(dyn_state->acp_clock_voltage_dependency_table.entries); 7408c2ecf20Sopenharmony_ci kfree(dyn_state->vddgfx_dependency_on_sclk.entries); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic const char *pp_lib_thermal_controller_names[] = { 7448c2ecf20Sopenharmony_ci "NONE", 7458c2ecf20Sopenharmony_ci "lm63", 7468c2ecf20Sopenharmony_ci "adm1032", 7478c2ecf20Sopenharmony_ci "adm1030", 7488c2ecf20Sopenharmony_ci "max6649", 7498c2ecf20Sopenharmony_ci "lm64", 7508c2ecf20Sopenharmony_ci "f75375", 7518c2ecf20Sopenharmony_ci "RV6xx", 7528c2ecf20Sopenharmony_ci "RV770", 7538c2ecf20Sopenharmony_ci "adt7473", 7548c2ecf20Sopenharmony_ci "NONE", 7558c2ecf20Sopenharmony_ci "External GPIO", 7568c2ecf20Sopenharmony_ci "Evergreen", 7578c2ecf20Sopenharmony_ci "emc2103", 7588c2ecf20Sopenharmony_ci "Sumo", 7598c2ecf20Sopenharmony_ci "Northern Islands", 7608c2ecf20Sopenharmony_ci "Southern Islands", 7618c2ecf20Sopenharmony_ci "lm96163", 7628c2ecf20Sopenharmony_ci "Sea Islands", 7638c2ecf20Sopenharmony_ci "Kaveri/Kabini", 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_civoid amdgpu_add_thermal_controller(struct amdgpu_device *adev) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct amdgpu_mode_info *mode_info = &adev->mode_info; 7698c2ecf20Sopenharmony_ci ATOM_PPLIB_POWERPLAYTABLE *power_table; 7708c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 7718c2ecf20Sopenharmony_ci ATOM_PPLIB_THERMALCONTROLLER *controller; 7728c2ecf20Sopenharmony_ci struct amdgpu_i2c_bus_rec i2c_bus; 7738c2ecf20Sopenharmony_ci u16 data_offset; 7748c2ecf20Sopenharmony_ci u8 frev, crev; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, 7778c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 7788c2ecf20Sopenharmony_ci return; 7798c2ecf20Sopenharmony_ci power_table = (ATOM_PPLIB_POWERPLAYTABLE *) 7808c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset); 7818c2ecf20Sopenharmony_ci controller = &power_table->sThermalController; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* add the i2c bus for thermal/fan chip */ 7848c2ecf20Sopenharmony_ci if (controller->ucType > 0) { 7858c2ecf20Sopenharmony_ci if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) 7868c2ecf20Sopenharmony_ci adev->pm.no_fan = true; 7878c2ecf20Sopenharmony_ci adev->pm.fan_pulses_per_revolution = 7888c2ecf20Sopenharmony_ci controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; 7898c2ecf20Sopenharmony_ci if (adev->pm.fan_pulses_per_revolution) { 7908c2ecf20Sopenharmony_ci adev->pm.fan_min_rpm = controller->ucFanMinRPM; 7918c2ecf20Sopenharmony_ci adev->pm.fan_max_rpm = controller->ucFanMaxRPM; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { 7948c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 7958c2ecf20Sopenharmony_ci (controller->ucFanParameters & 7968c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 7978c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; 7988c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { 7998c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 8008c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8018c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8028c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_RV770; 8038c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { 8048c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 8058c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8068c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8078c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; 8088c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) { 8098c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 8108c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8118c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8128c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_SUMO; 8138c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) { 8148c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 8158c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8168c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8178c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_NI; 8188c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) { 8198c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 8208c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8218c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8228c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_SI; 8238c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) { 8248c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 8258c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8268c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8278c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_CI; 8288c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) { 8298c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 8308c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8318c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8328c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_KV; 8338c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) { 8348c2ecf20Sopenharmony_ci DRM_INFO("External GPIO thermal controller %s fan control\n", 8358c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8368c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8378c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO; 8388c2ecf20Sopenharmony_ci } else if (controller->ucType == 8398c2ecf20Sopenharmony_ci ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) { 8408c2ecf20Sopenharmony_ci DRM_INFO("ADT7473 with internal thermal controller %s fan control\n", 8418c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8428c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8438c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL; 8448c2ecf20Sopenharmony_ci } else if (controller->ucType == 8458c2ecf20Sopenharmony_ci ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) { 8468c2ecf20Sopenharmony_ci DRM_INFO("EMC2103 with internal thermal controller %s fan control\n", 8478c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8488c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8498c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL; 8508c2ecf20Sopenharmony_ci } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) { 8518c2ecf20Sopenharmony_ci DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", 8528c2ecf20Sopenharmony_ci pp_lib_thermal_controller_names[controller->ucType], 8538c2ecf20Sopenharmony_ci controller->ucI2cAddress >> 1, 8548c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8558c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8568c2ecf20Sopenharmony_ci adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL; 8578c2ecf20Sopenharmony_ci i2c_bus = amdgpu_atombios_lookup_i2c_gpio(adev, controller->ucI2cLine); 8588c2ecf20Sopenharmony_ci adev->pm.i2c_bus = amdgpu_i2c_lookup(adev, &i2c_bus); 8598c2ecf20Sopenharmony_ci if (adev->pm.i2c_bus) { 8608c2ecf20Sopenharmony_ci struct i2c_board_info info = { }; 8618c2ecf20Sopenharmony_ci const char *name = pp_lib_thermal_controller_names[controller->ucType]; 8628c2ecf20Sopenharmony_ci info.addr = controller->ucI2cAddress >> 1; 8638c2ecf20Sopenharmony_ci strlcpy(info.type, name, sizeof(info.type)); 8648c2ecf20Sopenharmony_ci i2c_new_client_device(&adev->pm.i2c_bus->adapter, &info); 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci } else { 8678c2ecf20Sopenharmony_ci DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n", 8688c2ecf20Sopenharmony_ci controller->ucType, 8698c2ecf20Sopenharmony_ci controller->ucI2cAddress >> 1, 8708c2ecf20Sopenharmony_ci (controller->ucFanParameters & 8718c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cienum amdgpu_pcie_gen amdgpu_get_pcie_gen_support(struct amdgpu_device *adev, 8778c2ecf20Sopenharmony_ci u32 sys_mask, 8788c2ecf20Sopenharmony_ci enum amdgpu_pcie_gen asic_gen, 8798c2ecf20Sopenharmony_ci enum amdgpu_pcie_gen default_gen) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci switch (asic_gen) { 8828c2ecf20Sopenharmony_ci case AMDGPU_PCIE_GEN1: 8838c2ecf20Sopenharmony_ci return AMDGPU_PCIE_GEN1; 8848c2ecf20Sopenharmony_ci case AMDGPU_PCIE_GEN2: 8858c2ecf20Sopenharmony_ci return AMDGPU_PCIE_GEN2; 8868c2ecf20Sopenharmony_ci case AMDGPU_PCIE_GEN3: 8878c2ecf20Sopenharmony_ci return AMDGPU_PCIE_GEN3; 8888c2ecf20Sopenharmony_ci default: 8898c2ecf20Sopenharmony_ci if ((sys_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) && 8908c2ecf20Sopenharmony_ci (default_gen == AMDGPU_PCIE_GEN3)) 8918c2ecf20Sopenharmony_ci return AMDGPU_PCIE_GEN3; 8928c2ecf20Sopenharmony_ci else if ((sys_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) && 8938c2ecf20Sopenharmony_ci (default_gen == AMDGPU_PCIE_GEN2)) 8948c2ecf20Sopenharmony_ci return AMDGPU_PCIE_GEN2; 8958c2ecf20Sopenharmony_ci else 8968c2ecf20Sopenharmony_ci return AMDGPU_PCIE_GEN1; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci return AMDGPU_PCIE_GEN1; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistruct amd_vce_state* 9028c2ecf20Sopenharmony_ciamdgpu_get_vce_clock_state(void *handle, u32 idx) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct amdgpu_device *adev = (struct amdgpu_device *)handle; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (idx < adev->pm.dpm.num_of_vce_states) 9078c2ecf20Sopenharmony_ci return &adev->pm.dpm.vce_states[idx]; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci return NULL; 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ciint amdgpu_dpm_get_sclk(struct amdgpu_device *adev, bool low) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci uint32_t clk_freq; 9158c2ecf20Sopenharmony_ci int ret = 0; 9168c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 9178c2ecf20Sopenharmony_ci ret = smu_get_dpm_freq_range(&adev->smu, SMU_GFXCLK, 9188c2ecf20Sopenharmony_ci low ? &clk_freq : NULL, 9198c2ecf20Sopenharmony_ci !low ? &clk_freq : NULL); 9208c2ecf20Sopenharmony_ci if (ret) 9218c2ecf20Sopenharmony_ci return 0; 9228c2ecf20Sopenharmony_ci return clk_freq * 100; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci } else { 9258c2ecf20Sopenharmony_ci return (adev)->powerplay.pp_funcs->get_sclk((adev)->powerplay.pp_handle, (low)); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ciint amdgpu_dpm_get_mclk(struct amdgpu_device *adev, bool low) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci uint32_t clk_freq; 9328c2ecf20Sopenharmony_ci int ret = 0; 9338c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 9348c2ecf20Sopenharmony_ci ret = smu_get_dpm_freq_range(&adev->smu, SMU_UCLK, 9358c2ecf20Sopenharmony_ci low ? &clk_freq : NULL, 9368c2ecf20Sopenharmony_ci !low ? &clk_freq : NULL); 9378c2ecf20Sopenharmony_ci if (ret) 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci return clk_freq * 100; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci } else { 9428c2ecf20Sopenharmony_ci return (adev)->powerplay.pp_funcs->get_mclk((adev)->powerplay.pp_handle, (low)); 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ciint amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block_type, bool gate) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci int ret = 0; 9498c2ecf20Sopenharmony_ci bool swsmu = is_support_sw_smu(adev); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci switch (block_type) { 9528c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_UVD: 9538c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_VCE: 9548c2ecf20Sopenharmony_ci if (swsmu) { 9558c2ecf20Sopenharmony_ci ret = smu_dpm_set_power_gate(&adev->smu, block_type, gate); 9568c2ecf20Sopenharmony_ci } else if (adev->powerplay.pp_funcs && 9578c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->set_powergating_by_smu) { 9588c2ecf20Sopenharmony_ci /* 9598c2ecf20Sopenharmony_ci * TODO: need a better lock mechanism 9608c2ecf20Sopenharmony_ci * 9618c2ecf20Sopenharmony_ci * Here adev->pm.mutex lock protection is enforced on 9628c2ecf20Sopenharmony_ci * UVD and VCE cases only. Since for other cases, there 9638c2ecf20Sopenharmony_ci * may be already lock protection in amdgpu_pm.c. 9648c2ecf20Sopenharmony_ci * This is a quick fix for the deadlock issue below. 9658c2ecf20Sopenharmony_ci * NFO: task ocltst:2028 blocked for more than 120 seconds. 9668c2ecf20Sopenharmony_ci * Tainted: G OE 5.0.0-37-generic #40~18.04.1-Ubuntu 9678c2ecf20Sopenharmony_ci * echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. 9688c2ecf20Sopenharmony_ci * cltst D 0 2028 2026 0x00000000 9698c2ecf20Sopenharmony_ci * all Trace: 9708c2ecf20Sopenharmony_ci * __schedule+0x2c0/0x870 9718c2ecf20Sopenharmony_ci * schedule+0x2c/0x70 9728c2ecf20Sopenharmony_ci * schedule_preempt_disabled+0xe/0x10 9738c2ecf20Sopenharmony_ci * __mutex_lock.isra.9+0x26d/0x4e0 9748c2ecf20Sopenharmony_ci * __mutex_lock_slowpath+0x13/0x20 9758c2ecf20Sopenharmony_ci * ? __mutex_lock_slowpath+0x13/0x20 9768c2ecf20Sopenharmony_ci * mutex_lock+0x2f/0x40 9778c2ecf20Sopenharmony_ci * amdgpu_dpm_set_powergating_by_smu+0x64/0xe0 [amdgpu] 9788c2ecf20Sopenharmony_ci * gfx_v8_0_enable_gfx_static_mg_power_gating+0x3c/0x70 [amdgpu] 9798c2ecf20Sopenharmony_ci * gfx_v8_0_set_powergating_state+0x66/0x260 [amdgpu] 9808c2ecf20Sopenharmony_ci * amdgpu_device_ip_set_powergating_state+0x62/0xb0 [amdgpu] 9818c2ecf20Sopenharmony_ci * pp_dpm_force_performance_level+0xe7/0x100 [amdgpu] 9828c2ecf20Sopenharmony_ci * amdgpu_set_dpm_forced_performance_level+0x129/0x330 [amdgpu] 9838c2ecf20Sopenharmony_ci */ 9848c2ecf20Sopenharmony_ci mutex_lock(&adev->pm.mutex); 9858c2ecf20Sopenharmony_ci ret = ((adev)->powerplay.pp_funcs->set_powergating_by_smu( 9868c2ecf20Sopenharmony_ci (adev)->powerplay.pp_handle, block_type, gate)); 9878c2ecf20Sopenharmony_ci mutex_unlock(&adev->pm.mutex); 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci break; 9908c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_GFX: 9918c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_VCN: 9928c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_SDMA: 9938c2ecf20Sopenharmony_ci if (swsmu) 9948c2ecf20Sopenharmony_ci ret = smu_dpm_set_power_gate(&adev->smu, block_type, gate); 9958c2ecf20Sopenharmony_ci else if (adev->powerplay.pp_funcs && 9968c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->set_powergating_by_smu) 9978c2ecf20Sopenharmony_ci ret = ((adev)->powerplay.pp_funcs->set_powergating_by_smu( 9988c2ecf20Sopenharmony_ci (adev)->powerplay.pp_handle, block_type, gate)); 9998c2ecf20Sopenharmony_ci break; 10008c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_JPEG: 10018c2ecf20Sopenharmony_ci if (swsmu) 10028c2ecf20Sopenharmony_ci ret = smu_dpm_set_power_gate(&adev->smu, block_type, gate); 10038c2ecf20Sopenharmony_ci break; 10048c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_GMC: 10058c2ecf20Sopenharmony_ci case AMD_IP_BLOCK_TYPE_ACP: 10068c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs && 10078c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->set_powergating_by_smu) 10088c2ecf20Sopenharmony_ci ret = ((adev)->powerplay.pp_funcs->set_powergating_by_smu( 10098c2ecf20Sopenharmony_ci (adev)->powerplay.pp_handle, block_type, gate)); 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci default: 10128c2ecf20Sopenharmony_ci break; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci return ret; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ciint amdgpu_dpm_baco_enter(struct amdgpu_device *adev) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 10218c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 10228c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 10238c2ecf20Sopenharmony_ci int ret = 0; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 10268c2ecf20Sopenharmony_ci ret = smu_baco_enter(smu); 10278c2ecf20Sopenharmony_ci } else { 10288c2ecf20Sopenharmony_ci if (!pp_funcs || !pp_funcs->set_asic_baco_state) 10298c2ecf20Sopenharmony_ci return -ENOENT; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* enter BACO state */ 10328c2ecf20Sopenharmony_ci ret = pp_funcs->set_asic_baco_state(pp_handle, 1); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return ret; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ciint amdgpu_dpm_baco_exit(struct amdgpu_device *adev) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 10418c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 10428c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 10438c2ecf20Sopenharmony_ci int ret = 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 10468c2ecf20Sopenharmony_ci ret = smu_baco_exit(smu); 10478c2ecf20Sopenharmony_ci } else { 10488c2ecf20Sopenharmony_ci if (!pp_funcs || !pp_funcs->set_asic_baco_state) 10498c2ecf20Sopenharmony_ci return -ENOENT; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* exit BACO state */ 10528c2ecf20Sopenharmony_ci ret = pp_funcs->set_asic_baco_state(pp_handle, 0); 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci return ret; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ciint amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev, 10598c2ecf20Sopenharmony_ci enum pp_mp1_state mp1_state) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci int ret = 0; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 10648c2ecf20Sopenharmony_ci ret = smu_set_mp1_state(&adev->smu, mp1_state); 10658c2ecf20Sopenharmony_ci } else if (adev->powerplay.pp_funcs && 10668c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->set_mp1_state) { 10678c2ecf20Sopenharmony_ci ret = adev->powerplay.pp_funcs->set_mp1_state( 10688c2ecf20Sopenharmony_ci adev->powerplay.pp_handle, 10698c2ecf20Sopenharmony_ci mp1_state); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci return ret; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cibool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 10788c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 10798c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 10808c2ecf20Sopenharmony_ci bool baco_cap; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 10838c2ecf20Sopenharmony_ci return smu_baco_is_support(smu); 10848c2ecf20Sopenharmony_ci } else { 10858c2ecf20Sopenharmony_ci if (!pp_funcs || !pp_funcs->get_asic_baco_capability) 10868c2ecf20Sopenharmony_ci return false; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (pp_funcs->get_asic_baco_capability(pp_handle, &baco_cap)) 10898c2ecf20Sopenharmony_ci return false; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return baco_cap ? true : false; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ciint amdgpu_dpm_mode2_reset(struct amdgpu_device *adev) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 10988c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 10998c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 11028c2ecf20Sopenharmony_ci return smu_mode2_reset(smu); 11038c2ecf20Sopenharmony_ci } else { 11048c2ecf20Sopenharmony_ci if (!pp_funcs || !pp_funcs->asic_reset_mode_2) 11058c2ecf20Sopenharmony_ci return -ENOENT; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci return pp_funcs->asic_reset_mode_2(pp_handle); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ciint amdgpu_dpm_baco_reset(struct amdgpu_device *adev) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 11148c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 11158c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 11168c2ecf20Sopenharmony_ci int ret = 0; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 11198c2ecf20Sopenharmony_ci ret = smu_baco_enter(smu); 11208c2ecf20Sopenharmony_ci if (ret) 11218c2ecf20Sopenharmony_ci return ret; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci ret = smu_baco_exit(smu); 11248c2ecf20Sopenharmony_ci if (ret) 11258c2ecf20Sopenharmony_ci return ret; 11268c2ecf20Sopenharmony_ci } else { 11278c2ecf20Sopenharmony_ci if (!pp_funcs 11288c2ecf20Sopenharmony_ci || !pp_funcs->set_asic_baco_state) 11298c2ecf20Sopenharmony_ci return -ENOENT; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* enter BACO state */ 11328c2ecf20Sopenharmony_ci ret = pp_funcs->set_asic_baco_state(pp_handle, 1); 11338c2ecf20Sopenharmony_ci if (ret) 11348c2ecf20Sopenharmony_ci return ret; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* exit BACO state */ 11378c2ecf20Sopenharmony_ci ret = pp_funcs->set_asic_baco_state(pp_handle, 0); 11388c2ecf20Sopenharmony_ci if (ret) 11398c2ecf20Sopenharmony_ci return ret; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cibool amdgpu_dpm_is_mode1_reset_supported(struct amdgpu_device *adev) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 11508c2ecf20Sopenharmony_ci return smu_mode1_reset_is_support(smu); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci return false; 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ciint amdgpu_dpm_mode1_reset(struct amdgpu_device *adev) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 11608c2ecf20Sopenharmony_ci return smu_mode1_reset(smu); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ciint amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev, 11668c2ecf20Sopenharmony_ci enum PP_SMC_POWER_PROFILE type, 11678c2ecf20Sopenharmony_ci bool en) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci int ret = 0; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 11728c2ecf20Sopenharmony_ci ret = smu_switch_power_profile(&adev->smu, type, en); 11738c2ecf20Sopenharmony_ci else if (adev->powerplay.pp_funcs && 11748c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->switch_power_profile) 11758c2ecf20Sopenharmony_ci ret = adev->powerplay.pp_funcs->switch_power_profile( 11768c2ecf20Sopenharmony_ci adev->powerplay.pp_handle, type, en); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci return ret; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ciint amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev, 11828c2ecf20Sopenharmony_ci uint32_t pstate) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci int ret = 0; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 11878c2ecf20Sopenharmony_ci ret = smu_set_xgmi_pstate(&adev->smu, pstate); 11888c2ecf20Sopenharmony_ci else if (adev->powerplay.pp_funcs && 11898c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->set_xgmi_pstate) 11908c2ecf20Sopenharmony_ci ret = adev->powerplay.pp_funcs->set_xgmi_pstate(adev->powerplay.pp_handle, 11918c2ecf20Sopenharmony_ci pstate); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci return ret; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ciint amdgpu_dpm_set_df_cstate(struct amdgpu_device *adev, 11978c2ecf20Sopenharmony_ci uint32_t cstate) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci int ret = 0; 12008c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 12018c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 12028c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 12058c2ecf20Sopenharmony_ci ret = smu_set_df_cstate(smu, cstate); 12068c2ecf20Sopenharmony_ci else if (pp_funcs && 12078c2ecf20Sopenharmony_ci pp_funcs->set_df_cstate) 12088c2ecf20Sopenharmony_ci ret = pp_funcs->set_df_cstate(pp_handle, cstate); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci return ret; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ciint amdgpu_dpm_allow_xgmi_power_down(struct amdgpu_device *adev, bool en) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 12188c2ecf20Sopenharmony_ci return smu_allow_xgmi_power_down(smu, en); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci return 0; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ciint amdgpu_dpm_enable_mgpu_fan_boost(struct amdgpu_device *adev) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 12268c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = 12278c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs; 12288c2ecf20Sopenharmony_ci struct smu_context *smu = &adev->smu; 12298c2ecf20Sopenharmony_ci int ret = 0; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 12328c2ecf20Sopenharmony_ci ret = smu_enable_mgpu_fan_boost(smu); 12338c2ecf20Sopenharmony_ci else if (pp_funcs && pp_funcs->enable_mgpu_fan_boost) 12348c2ecf20Sopenharmony_ci ret = pp_funcs->enable_mgpu_fan_boost(pp_handle); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci return ret; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ciint amdgpu_dpm_set_clockgating_by_smu(struct amdgpu_device *adev, 12408c2ecf20Sopenharmony_ci uint32_t msg_id) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 12438c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = 12448c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs; 12458c2ecf20Sopenharmony_ci int ret = 0; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if (pp_funcs && pp_funcs->set_clockgating_by_smu) 12488c2ecf20Sopenharmony_ci ret = pp_funcs->set_clockgating_by_smu(pp_handle, 12498c2ecf20Sopenharmony_ci msg_id); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci return ret; 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ciint amdgpu_dpm_smu_i2c_bus_access(struct amdgpu_device *adev, 12558c2ecf20Sopenharmony_ci bool acquire) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci void *pp_handle = adev->powerplay.pp_handle; 12588c2ecf20Sopenharmony_ci const struct amd_pm_funcs *pp_funcs = 12598c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs; 12608c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (pp_funcs && pp_funcs->smu_i2c_bus_access) 12638c2ecf20Sopenharmony_ci ret = pp_funcs->smu_i2c_bus_access(pp_handle, 12648c2ecf20Sopenharmony_ci acquire); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci return ret; 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_civoid amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci if (adev->pm.dpm_enabled) { 12728c2ecf20Sopenharmony_ci mutex_lock(&adev->pm.mutex); 12738c2ecf20Sopenharmony_ci if (power_supply_is_system_supplied() > 0) 12748c2ecf20Sopenharmony_ci adev->pm.ac_power = true; 12758c2ecf20Sopenharmony_ci else 12768c2ecf20Sopenharmony_ci adev->pm.ac_power = false; 12778c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs && 12788c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->enable_bapm) 12798c2ecf20Sopenharmony_ci amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power); 12808c2ecf20Sopenharmony_ci mutex_unlock(&adev->pm.mutex); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 12838c2ecf20Sopenharmony_ci smu_set_ac_dc(&adev->smu); 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ciint amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor, 12888c2ecf20Sopenharmony_ci void *data, uint32_t *size) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci int ret = 0; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (!data || !size) 12938c2ecf20Sopenharmony_ci return -EINVAL; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) 12968c2ecf20Sopenharmony_ci ret = smu_read_sensor(&adev->smu, sensor, data, size); 12978c2ecf20Sopenharmony_ci else { 12988c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->read_sensor) 12998c2ecf20Sopenharmony_ci ret = adev->powerplay.pp_funcs->read_sensor((adev)->powerplay.pp_handle, 13008c2ecf20Sopenharmony_ci sensor, data, size); 13018c2ecf20Sopenharmony_ci else 13028c2ecf20Sopenharmony_ci ret = -EINVAL; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci return ret; 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_civoid amdgpu_dpm_thermal_work_handler(struct work_struct *work) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci struct amdgpu_device *adev = 13118c2ecf20Sopenharmony_ci container_of(work, struct amdgpu_device, 13128c2ecf20Sopenharmony_ci pm.dpm.thermal.work); 13138c2ecf20Sopenharmony_ci /* switch to the thermal state */ 13148c2ecf20Sopenharmony_ci enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL; 13158c2ecf20Sopenharmony_ci int temp, size = sizeof(temp); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci if (!adev->pm.dpm_enabled) 13188c2ecf20Sopenharmony_ci return; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, 13218c2ecf20Sopenharmony_ci (void *)&temp, &size)) { 13228c2ecf20Sopenharmony_ci if (temp < adev->pm.dpm.thermal.min_temp) 13238c2ecf20Sopenharmony_ci /* switch back the user state */ 13248c2ecf20Sopenharmony_ci dpm_state = adev->pm.dpm.user_state; 13258c2ecf20Sopenharmony_ci } else { 13268c2ecf20Sopenharmony_ci if (adev->pm.dpm.thermal.high_to_low) 13278c2ecf20Sopenharmony_ci /* switch back the user state */ 13288c2ecf20Sopenharmony_ci dpm_state = adev->pm.dpm.user_state; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci mutex_lock(&adev->pm.mutex); 13318c2ecf20Sopenharmony_ci if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL) 13328c2ecf20Sopenharmony_ci adev->pm.dpm.thermal_active = true; 13338c2ecf20Sopenharmony_ci else 13348c2ecf20Sopenharmony_ci adev->pm.dpm.thermal_active = false; 13358c2ecf20Sopenharmony_ci adev->pm.dpm.state = dpm_state; 13368c2ecf20Sopenharmony_ci mutex_unlock(&adev->pm.mutex); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci amdgpu_pm_compute_clocks(adev); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev, 13428c2ecf20Sopenharmony_ci enum amd_pm_state_type dpm_state) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci int i; 13458c2ecf20Sopenharmony_ci struct amdgpu_ps *ps; 13468c2ecf20Sopenharmony_ci u32 ui_class; 13478c2ecf20Sopenharmony_ci bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ? 13488c2ecf20Sopenharmony_ci true : false; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* check if the vblank period is too short to adjust the mclk */ 13518c2ecf20Sopenharmony_ci if (single_display && adev->powerplay.pp_funcs->vblank_too_short) { 13528c2ecf20Sopenharmony_ci if (amdgpu_dpm_vblank_too_short(adev)) 13538c2ecf20Sopenharmony_ci single_display = false; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* certain older asics have a separare 3D performance state, 13578c2ecf20Sopenharmony_ci * so try that first if the user selected performance 13588c2ecf20Sopenharmony_ci */ 13598c2ecf20Sopenharmony_ci if (dpm_state == POWER_STATE_TYPE_PERFORMANCE) 13608c2ecf20Sopenharmony_ci dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; 13618c2ecf20Sopenharmony_ci /* balanced states don't exist at the moment */ 13628c2ecf20Sopenharmony_ci if (dpm_state == POWER_STATE_TYPE_BALANCED) 13638c2ecf20Sopenharmony_ci dpm_state = POWER_STATE_TYPE_PERFORMANCE; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_cirestart_search: 13668c2ecf20Sopenharmony_ci /* Pick the best power state based on current conditions */ 13678c2ecf20Sopenharmony_ci for (i = 0; i < adev->pm.dpm.num_ps; i++) { 13688c2ecf20Sopenharmony_ci ps = &adev->pm.dpm.ps[i]; 13698c2ecf20Sopenharmony_ci ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK; 13708c2ecf20Sopenharmony_ci switch (dpm_state) { 13718c2ecf20Sopenharmony_ci /* user states */ 13728c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_BATTERY: 13738c2ecf20Sopenharmony_ci if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) { 13748c2ecf20Sopenharmony_ci if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { 13758c2ecf20Sopenharmony_ci if (single_display) 13768c2ecf20Sopenharmony_ci return ps; 13778c2ecf20Sopenharmony_ci } else 13788c2ecf20Sopenharmony_ci return ps; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci break; 13818c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_BALANCED: 13828c2ecf20Sopenharmony_ci if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) { 13838c2ecf20Sopenharmony_ci if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { 13848c2ecf20Sopenharmony_ci if (single_display) 13858c2ecf20Sopenharmony_ci return ps; 13868c2ecf20Sopenharmony_ci } else 13878c2ecf20Sopenharmony_ci return ps; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_PERFORMANCE: 13918c2ecf20Sopenharmony_ci if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { 13928c2ecf20Sopenharmony_ci if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { 13938c2ecf20Sopenharmony_ci if (single_display) 13948c2ecf20Sopenharmony_ci return ps; 13958c2ecf20Sopenharmony_ci } else 13968c2ecf20Sopenharmony_ci return ps; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci break; 13998c2ecf20Sopenharmony_ci /* internal states */ 14008c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD: 14018c2ecf20Sopenharmony_ci if (adev->pm.dpm.uvd_ps) 14028c2ecf20Sopenharmony_ci return adev->pm.dpm.uvd_ps; 14038c2ecf20Sopenharmony_ci else 14048c2ecf20Sopenharmony_ci break; 14058c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_SD: 14068c2ecf20Sopenharmony_ci if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) 14078c2ecf20Sopenharmony_ci return ps; 14088c2ecf20Sopenharmony_ci break; 14098c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_HD: 14108c2ecf20Sopenharmony_ci if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) 14118c2ecf20Sopenharmony_ci return ps; 14128c2ecf20Sopenharmony_ci break; 14138c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_HD2: 14148c2ecf20Sopenharmony_ci if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) 14158c2ecf20Sopenharmony_ci return ps; 14168c2ecf20Sopenharmony_ci break; 14178c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_MVC: 14188c2ecf20Sopenharmony_ci if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) 14198c2ecf20Sopenharmony_ci return ps; 14208c2ecf20Sopenharmony_ci break; 14218c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_BOOT: 14228c2ecf20Sopenharmony_ci return adev->pm.dpm.boot_ps; 14238c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_THERMAL: 14248c2ecf20Sopenharmony_ci if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) 14258c2ecf20Sopenharmony_ci return ps; 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_ACPI: 14288c2ecf20Sopenharmony_ci if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) 14298c2ecf20Sopenharmony_ci return ps; 14308c2ecf20Sopenharmony_ci break; 14318c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_ULV: 14328c2ecf20Sopenharmony_ci if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) 14338c2ecf20Sopenharmony_ci return ps; 14348c2ecf20Sopenharmony_ci break; 14358c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_3DPERF: 14368c2ecf20Sopenharmony_ci if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) 14378c2ecf20Sopenharmony_ci return ps; 14388c2ecf20Sopenharmony_ci break; 14398c2ecf20Sopenharmony_ci default: 14408c2ecf20Sopenharmony_ci break; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci /* use a fallback state if we didn't match */ 14448c2ecf20Sopenharmony_ci switch (dpm_state) { 14458c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_SD: 14468c2ecf20Sopenharmony_ci dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; 14478c2ecf20Sopenharmony_ci goto restart_search; 14488c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_HD: 14498c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_HD2: 14508c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_UVD_MVC: 14518c2ecf20Sopenharmony_ci if (adev->pm.dpm.uvd_ps) { 14528c2ecf20Sopenharmony_ci return adev->pm.dpm.uvd_ps; 14538c2ecf20Sopenharmony_ci } else { 14548c2ecf20Sopenharmony_ci dpm_state = POWER_STATE_TYPE_PERFORMANCE; 14558c2ecf20Sopenharmony_ci goto restart_search; 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_THERMAL: 14588c2ecf20Sopenharmony_ci dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI; 14598c2ecf20Sopenharmony_ci goto restart_search; 14608c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_ACPI: 14618c2ecf20Sopenharmony_ci dpm_state = POWER_STATE_TYPE_BATTERY; 14628c2ecf20Sopenharmony_ci goto restart_search; 14638c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_BATTERY: 14648c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_BALANCED: 14658c2ecf20Sopenharmony_ci case POWER_STATE_TYPE_INTERNAL_3DPERF: 14668c2ecf20Sopenharmony_ci dpm_state = POWER_STATE_TYPE_PERFORMANCE; 14678c2ecf20Sopenharmony_ci goto restart_search; 14688c2ecf20Sopenharmony_ci default: 14698c2ecf20Sopenharmony_ci break; 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci return NULL; 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci struct amdgpu_ps *ps; 14788c2ecf20Sopenharmony_ci enum amd_pm_state_type dpm_state; 14798c2ecf20Sopenharmony_ci int ret; 14808c2ecf20Sopenharmony_ci bool equal = false; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* if dpm init failed */ 14838c2ecf20Sopenharmony_ci if (!adev->pm.dpm_enabled) 14848c2ecf20Sopenharmony_ci return; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (adev->pm.dpm.user_state != adev->pm.dpm.state) { 14878c2ecf20Sopenharmony_ci /* add other state override checks here */ 14888c2ecf20Sopenharmony_ci if ((!adev->pm.dpm.thermal_active) && 14898c2ecf20Sopenharmony_ci (!adev->pm.dpm.uvd_active)) 14908c2ecf20Sopenharmony_ci adev->pm.dpm.state = adev->pm.dpm.user_state; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci dpm_state = adev->pm.dpm.state; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci ps = amdgpu_dpm_pick_power_state(adev, dpm_state); 14958c2ecf20Sopenharmony_ci if (ps) 14968c2ecf20Sopenharmony_ci adev->pm.dpm.requested_ps = ps; 14978c2ecf20Sopenharmony_ci else 14988c2ecf20Sopenharmony_ci return; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci if (amdgpu_dpm == 1 && adev->powerplay.pp_funcs->print_power_state) { 15018c2ecf20Sopenharmony_ci printk("switching from power state:\n"); 15028c2ecf20Sopenharmony_ci amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps); 15038c2ecf20Sopenharmony_ci printk("switching to power state:\n"); 15048c2ecf20Sopenharmony_ci amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps); 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* update whether vce is active */ 15088c2ecf20Sopenharmony_ci ps->vce_active = adev->pm.dpm.vce_active; 15098c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs->display_configuration_changed) 15108c2ecf20Sopenharmony_ci amdgpu_dpm_display_configuration_changed(adev); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci ret = amdgpu_dpm_pre_set_power_state(adev); 15138c2ecf20Sopenharmony_ci if (ret) 15148c2ecf20Sopenharmony_ci return; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs->check_state_equal) { 15178c2ecf20Sopenharmony_ci if (0 != amdgpu_dpm_check_state_equal(adev, adev->pm.dpm.current_ps, adev->pm.dpm.requested_ps, &equal)) 15188c2ecf20Sopenharmony_ci equal = false; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (equal) 15228c2ecf20Sopenharmony_ci return; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci amdgpu_dpm_set_power_state(adev); 15258c2ecf20Sopenharmony_ci amdgpu_dpm_post_set_power_state(adev); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs; 15288c2ecf20Sopenharmony_ci adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs->force_performance_level) { 15318c2ecf20Sopenharmony_ci if (adev->pm.dpm.thermal_active) { 15328c2ecf20Sopenharmony_ci enum amd_dpm_forced_level level = adev->pm.dpm.forced_level; 15338c2ecf20Sopenharmony_ci /* force low perf level for thermal */ 15348c2ecf20Sopenharmony_ci amdgpu_dpm_force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW); 15358c2ecf20Sopenharmony_ci /* save the user's level */ 15368c2ecf20Sopenharmony_ci adev->pm.dpm.forced_level = level; 15378c2ecf20Sopenharmony_ci } else { 15388c2ecf20Sopenharmony_ci /* otherwise, user selected level */ 15398c2ecf20Sopenharmony_ci amdgpu_dpm_force_performance_level(adev, adev->pm.dpm.forced_level); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci} 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_civoid amdgpu_pm_compute_clocks(struct amdgpu_device *adev) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci int i = 0; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if (!adev->pm.dpm_enabled) 15498c2ecf20Sopenharmony_ci return; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (adev->mode_info.num_crtc) 15528c2ecf20Sopenharmony_ci amdgpu_display_bandwidth_update(adev); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 15558c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 15568c2ecf20Sopenharmony_ci if (ring && ring->sched.ready) 15578c2ecf20Sopenharmony_ci amdgpu_fence_wait_empty(ring); 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (is_support_sw_smu(adev)) { 15618c2ecf20Sopenharmony_ci struct smu_dpm_context *smu_dpm = &adev->smu.smu_dpm; 15628c2ecf20Sopenharmony_ci smu_handle_task(&adev->smu, 15638c2ecf20Sopenharmony_ci smu_dpm->dpm_level, 15648c2ecf20Sopenharmony_ci AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, 15658c2ecf20Sopenharmony_ci true); 15668c2ecf20Sopenharmony_ci } else { 15678c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs->dispatch_tasks) { 15688c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) { 15698c2ecf20Sopenharmony_ci mutex_lock(&adev->pm.mutex); 15708c2ecf20Sopenharmony_ci amdgpu_dpm_get_active_displays(adev); 15718c2ecf20Sopenharmony_ci adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; 15728c2ecf20Sopenharmony_ci adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); 15738c2ecf20Sopenharmony_ci adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); 15748c2ecf20Sopenharmony_ci /* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */ 15758c2ecf20Sopenharmony_ci if (adev->pm.pm_display_cfg.vrefresh > 120) 15768c2ecf20Sopenharmony_ci adev->pm.pm_display_cfg.min_vblank_time = 0; 15778c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs->display_configuration_change) 15788c2ecf20Sopenharmony_ci adev->powerplay.pp_funcs->display_configuration_change( 15798c2ecf20Sopenharmony_ci adev->powerplay.pp_handle, 15808c2ecf20Sopenharmony_ci &adev->pm.pm_display_cfg); 15818c2ecf20Sopenharmony_ci mutex_unlock(&adev->pm.mutex); 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL); 15848c2ecf20Sopenharmony_ci } else { 15858c2ecf20Sopenharmony_ci mutex_lock(&adev->pm.mutex); 15868c2ecf20Sopenharmony_ci amdgpu_dpm_get_active_displays(adev); 15878c2ecf20Sopenharmony_ci amdgpu_dpm_change_power_state_locked(adev); 15888c2ecf20Sopenharmony_ci mutex_unlock(&adev->pm.mutex); 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_civoid amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci int ret = 0; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (adev->family == AMDGPU_FAMILY_SI) { 15988c2ecf20Sopenharmony_ci mutex_lock(&adev->pm.mutex); 15998c2ecf20Sopenharmony_ci if (enable) { 16008c2ecf20Sopenharmony_ci adev->pm.dpm.uvd_active = true; 16018c2ecf20Sopenharmony_ci adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD; 16028c2ecf20Sopenharmony_ci } else { 16038c2ecf20Sopenharmony_ci adev->pm.dpm.uvd_active = false; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci mutex_unlock(&adev->pm.mutex); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci amdgpu_pm_compute_clocks(adev); 16088c2ecf20Sopenharmony_ci } else { 16098c2ecf20Sopenharmony_ci ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable); 16108c2ecf20Sopenharmony_ci if (ret) 16118c2ecf20Sopenharmony_ci DRM_ERROR("Dpm %s uvd failed, ret = %d. \n", 16128c2ecf20Sopenharmony_ci enable ? "enable" : "disable", ret); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* enable/disable Low Memory PState for UVD (4k videos) */ 16158c2ecf20Sopenharmony_ci if (adev->asic_type == CHIP_STONEY && 16168c2ecf20Sopenharmony_ci adev->uvd.decode_image_width >= WIDTH_4K) { 16178c2ecf20Sopenharmony_ci struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci if (hwmgr && hwmgr->hwmgr_func && 16208c2ecf20Sopenharmony_ci hwmgr->hwmgr_func->update_nbdpm_pstate) 16218c2ecf20Sopenharmony_ci hwmgr->hwmgr_func->update_nbdpm_pstate(hwmgr, 16228c2ecf20Sopenharmony_ci !enable, 16238c2ecf20Sopenharmony_ci true); 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci} 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_civoid amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci int ret = 0; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (adev->family == AMDGPU_FAMILY_SI) { 16338c2ecf20Sopenharmony_ci mutex_lock(&adev->pm.mutex); 16348c2ecf20Sopenharmony_ci if (enable) { 16358c2ecf20Sopenharmony_ci adev->pm.dpm.vce_active = true; 16368c2ecf20Sopenharmony_ci /* XXX select vce level based on ring/task */ 16378c2ecf20Sopenharmony_ci adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL; 16388c2ecf20Sopenharmony_ci } else { 16398c2ecf20Sopenharmony_ci adev->pm.dpm.vce_active = false; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci mutex_unlock(&adev->pm.mutex); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci amdgpu_pm_compute_clocks(adev); 16448c2ecf20Sopenharmony_ci } else { 16458c2ecf20Sopenharmony_ci ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable); 16468c2ecf20Sopenharmony_ci if (ret) 16478c2ecf20Sopenharmony_ci DRM_ERROR("Dpm %s vce failed, ret = %d. \n", 16488c2ecf20Sopenharmony_ci enable ? "enable" : "disable", ret); 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_civoid amdgpu_pm_print_power_states(struct amdgpu_device *adev) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci int i; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs->print_power_state == NULL) 16578c2ecf20Sopenharmony_ci return; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci for (i = 0; i < adev->pm.dpm.num_ps; i++) 16608c2ecf20Sopenharmony_ci amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_civoid amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci int ret = 0; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_JPEG, !enable); 16698c2ecf20Sopenharmony_ci if (ret) 16708c2ecf20Sopenharmony_ci DRM_ERROR("Dpm %s jpeg failed, ret = %d. \n", 16718c2ecf20Sopenharmony_ci enable ? "enable" : "disable", ret); 16728c2ecf20Sopenharmony_ci} 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ciint amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version) 16758c2ecf20Sopenharmony_ci{ 16768c2ecf20Sopenharmony_ci int r; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->load_firmware) { 16798c2ecf20Sopenharmony_ci r = adev->powerplay.pp_funcs->load_firmware(adev->powerplay.pp_handle); 16808c2ecf20Sopenharmony_ci if (r) { 16818c2ecf20Sopenharmony_ci pr_err("smu firmware loading failed\n"); 16828c2ecf20Sopenharmony_ci return r; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci *smu_version = adev->pm.fw_version; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci return 0; 16878c2ecf20Sopenharmony_ci} 1688