]>
Commit | Line | Data |
---|---|---|
b3490673 HR |
1 | /* |
2 | * Copyright 2019 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | */ | |
23 | ||
d8e0b16d EQ |
24 | #define SWSMU_CODE_LAYER_L2 |
25 | ||
b3490673 | 26 | #include <linux/firmware.h> |
354e6e14 | 27 | #include <linux/pci.h> |
1bc73475 | 28 | #include <linux/i2c.h> |
b3490673 | 29 | #include "amdgpu.h" |
2f60dd50 | 30 | #include "amdgpu_dpm.h" |
b3490673 HR |
31 | #include "amdgpu_smu.h" |
32 | #include "atomfirmware.h" | |
33 | #include "amdgpu_atomfirmware.h" | |
22f2447c | 34 | #include "amdgpu_atombios.h" |
49e78c82 | 35 | #include "soc15_common.h" |
b3490673 | 36 | #include "smu_v11_0.h" |
013fd3a6 | 37 | #include "smu11_driver_if_navi10.h" |
b3490673 HR |
38 | #include "atom.h" |
39 | #include "navi10_ppt.h" | |
40 | #include "smu_v11_0_pptable.h" | |
41 | #include "smu_v11_0_ppsmc.h" | |
49e78c82 EQ |
42 | #include "nbio/nbio_2_3_offset.h" |
43 | #include "nbio/nbio_2_3_sh_mask.h" | |
947c127b LG |
44 | #include "thm/thm_11_0_2_offset.h" |
45 | #include "thm/thm_11_0_2_sh_mask.h" | |
b3490673 | 46 | |
fc419158 | 47 | #include "asic_reg/mp/mp_11_0_sh_mask.h" |
6c339f37 | 48 | #include "smu_cmn.h" |
665945eb | 49 | #include "smu_11_0_cdr_table.h" |
fc419158 | 50 | |
55084d7f EQ |
51 | /* |
52 | * DO NOT use these for err/warn/info/debug messages. | |
53 | * Use dev_err, dev_warn, dev_info and dev_dbg instead. | |
54 | * They are more MGPU friendly. | |
55 | */ | |
56 | #undef pr_err | |
57 | #undef pr_warn | |
58 | #undef pr_info | |
59 | #undef pr_debug | |
60 | ||
44ff0ae6 | 61 | #define FEATURE_MASK(feature) (1ULL << feature) |
4228b601 KW |
62 | #define SMC_DPM_FEATURE ( \ |
63 | FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ | |
64 | FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ | |
65 | FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT) | \ | |
66 | FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ | |
67 | FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ | |
68 | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) | \ | |
69 | FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ | |
70 | FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) | |
71 | ||
7d6c13ef EQ |
72 | #define SMU_11_0_GFX_BUSY_THRESHOLD 15 |
73 | ||
6c339f37 | 74 | static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = { |
d4f3c0b3 WS |
75 | MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), |
76 | MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), | |
77 | MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), | |
78 | MSG_MAP(SetAllowedFeaturesMaskLow, PPSMC_MSG_SetAllowedFeaturesMaskLow, 0), | |
79 | MSG_MAP(SetAllowedFeaturesMaskHigh, PPSMC_MSG_SetAllowedFeaturesMaskHigh, 0), | |
80 | MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0), | |
81 | MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0), | |
f1802aa7 YZ |
82 | MSG_MAP(EnableSmuFeaturesLow, PPSMC_MSG_EnableSmuFeaturesLow, 0), |
83 | MSG_MAP(EnableSmuFeaturesHigh, PPSMC_MSG_EnableSmuFeaturesHigh, 0), | |
84 | MSG_MAP(DisableSmuFeaturesLow, PPSMC_MSG_DisableSmuFeaturesLow, 0), | |
85 | MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh, 0), | |
d4f3c0b3 WS |
86 | MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 1), |
87 | MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 1), | |
fd30b7d9 | 88 | MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 0), |
d4f3c0b3 | 89 | MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), |
fd30b7d9 YZ |
90 | MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), |
91 | MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), | |
d4f3c0b3 WS |
92 | MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh, 0), |
93 | MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow, 0), | |
fd30b7d9 | 94 | MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), |
d4f3c0b3 WS |
95 | MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0), |
96 | MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable, 0), | |
97 | MSG_MAP(UseBackupPPTable, PPSMC_MSG_UseBackupPPTable, 0), | |
98 | MSG_MAP(RunBtc, PPSMC_MSG_RunBtc, 0), | |
99 | MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco, 0), | |
fd30b7d9 YZ |
100 | MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 1), |
101 | MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1), | |
102 | MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 0), | |
d4f3c0b3 WS |
103 | MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0), |
104 | MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1), | |
105 | MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1), | |
106 | MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1), | |
107 | MSG_MAP(SetMemoryChannelConfig, PPSMC_MSG_SetMemoryChannelConfig, 0), | |
108 | MSG_MAP(SetGeminiMode, PPSMC_MSG_SetGeminiMode, 0), | |
109 | MSG_MAP(SetGeminiApertureHigh, PPSMC_MSG_SetGeminiApertureHigh, 0), | |
110 | MSG_MAP(SetGeminiApertureLow, PPSMC_MSG_SetGeminiApertureLow, 0), | |
111 | MSG_MAP(OverridePcieParameters, PPSMC_MSG_OverridePcieParameters, 0), | |
112 | MSG_MAP(SetMinDeepSleepDcefclk, PPSMC_MSG_SetMinDeepSleepDcefclk, 0), | |
113 | MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0), | |
114 | MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0), | |
115 | MSG_MAP(SetUclkFastSwitch, PPSMC_MSG_SetUclkFastSwitch, 0), | |
116 | MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps, 0), | |
117 | MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1), | |
118 | MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), | |
119 | MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), | |
120 | MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize, 0), | |
121 | MSG_MAP(ConfigureGfxDidt, PPSMC_MSG_ConfigureGfxDidt, 0), | |
122 | MSG_MAP(NumOfDisplays, PPSMC_MSG_NumOfDisplays, 0), | |
123 | MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh, 0), | |
124 | MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow, 0), | |
125 | MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 0), | |
126 | MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 0), | |
127 | MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0), | |
128 | MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq, 1), | |
129 | MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData, 0), | |
130 | MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco, 0), | |
131 | MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset, 0), | |
132 | MSG_MAP(PrepareMp1ForShutdown, PPSMC_MSG_PrepareMp1ForShutdown, 0), | |
133 | MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 0), | |
134 | MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 0), | |
135 | MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 0), | |
136 | MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 0), | |
137 | MSG_MAP(BacoAudioD3PME, PPSMC_MSG_BacoAudioD3PME, 0), | |
138 | MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0), | |
1e3a58df | 139 | MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALDisableDummyPstateChange, 0), |
d4f3c0b3 WS |
140 | MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALEnableDummyPstateChange, 0), |
141 | MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm, 0), | |
142 | MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive, 0), | |
94a670d5 | 143 | MSG_MAP(SetMGpuFanBoostLimitRpm, PPSMC_MSG_SetMGpuFanBoostLimitRpm, 0), |
665945eb EQ |
144 | MSG_MAP(SET_DRIVER_DUMMY_TABLE_DRAM_ADDR_HIGH, PPSMC_MSG_SetDriverDummyTableDramAddrHigh, 0), |
145 | MSG_MAP(SET_DRIVER_DUMMY_TABLE_DRAM_ADDR_LOW, PPSMC_MSG_SetDriverDummyTableDramAddrLow, 0), | |
bb7257b5 | 146 | MSG_MAP(GET_UMC_FW_WA, PPSMC_MSG_GetUMCFWWA, 0), |
b3490673 HR |
147 | }; |
148 | ||
6c339f37 | 149 | static struct cmn2asic_mapping navi10_clk_map[SMU_CLK_COUNT] = { |
0de94acf | 150 | CLK_MAP(GFXCLK, PPCLK_GFXCLK), |
b1e7e224 | 151 | CLK_MAP(SCLK, PPCLK_GFXCLK), |
0de94acf | 152 | CLK_MAP(SOCCLK, PPCLK_SOCCLK), |
b1e7e224 | 153 | CLK_MAP(FCLK, PPCLK_SOCCLK), |
0de94acf | 154 | CLK_MAP(UCLK, PPCLK_UCLK), |
b1e7e224 | 155 | CLK_MAP(MCLK, PPCLK_UCLK), |
0de94acf HR |
156 | CLK_MAP(DCLK, PPCLK_DCLK), |
157 | CLK_MAP(VCLK, PPCLK_VCLK), | |
158 | CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), | |
159 | CLK_MAP(DISPCLK, PPCLK_DISPCLK), | |
160 | CLK_MAP(PIXCLK, PPCLK_PIXCLK), | |
161 | CLK_MAP(PHYCLK, PPCLK_PHYCLK), | |
162 | }; | |
163 | ||
6c339f37 | 164 | static struct cmn2asic_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = { |
ffcb08df HR |
165 | FEA_MAP(DPM_PREFETCHER), |
166 | FEA_MAP(DPM_GFXCLK), | |
167 | FEA_MAP(DPM_GFX_PACE), | |
168 | FEA_MAP(DPM_UCLK), | |
169 | FEA_MAP(DPM_SOCCLK), | |
170 | FEA_MAP(DPM_MP0CLK), | |
171 | FEA_MAP(DPM_LINK), | |
172 | FEA_MAP(DPM_DCEFCLK), | |
173 | FEA_MAP(MEM_VDDCI_SCALING), | |
174 | FEA_MAP(MEM_MVDD_SCALING), | |
175 | FEA_MAP(DS_GFXCLK), | |
176 | FEA_MAP(DS_SOCCLK), | |
177 | FEA_MAP(DS_LCLK), | |
178 | FEA_MAP(DS_DCEFCLK), | |
179 | FEA_MAP(DS_UCLK), | |
180 | FEA_MAP(GFX_ULV), | |
181 | FEA_MAP(FW_DSTATE), | |
182 | FEA_MAP(GFXOFF), | |
183 | FEA_MAP(BACO), | |
184 | FEA_MAP(VCN_PG), | |
185 | FEA_MAP(JPEG_PG), | |
186 | FEA_MAP(USB_PG), | |
187 | FEA_MAP(RSMU_SMN_CG), | |
188 | FEA_MAP(PPT), | |
189 | FEA_MAP(TDC), | |
190 | FEA_MAP(GFX_EDC), | |
191 | FEA_MAP(APCC_PLUS), | |
192 | FEA_MAP(GTHR), | |
193 | FEA_MAP(ACDC), | |
194 | FEA_MAP(VR0HOT), | |
195 | FEA_MAP(VR1HOT), | |
196 | FEA_MAP(FW_CTF), | |
197 | FEA_MAP(FAN_CONTROL), | |
198 | FEA_MAP(THERMAL), | |
199 | FEA_MAP(GFX_DCS), | |
200 | FEA_MAP(RM), | |
201 | FEA_MAP(LED_DISPLAY), | |
202 | FEA_MAP(GFX_SS), | |
203 | FEA_MAP(OUT_OF_BAND_MONITOR), | |
204 | FEA_MAP(TEMP_DEPENDENT_VMIN), | |
205 | FEA_MAP(MMHUB_PG), | |
206 | FEA_MAP(ATHUB_PG), | |
f256ba47 | 207 | FEA_MAP(APCC_DFLL), |
ffcb08df HR |
208 | }; |
209 | ||
6c339f37 | 210 | static struct cmn2asic_mapping navi10_table_map[SMU_TABLE_COUNT] = { |
2436911b HR |
211 | TAB_MAP(PPTABLE), |
212 | TAB_MAP(WATERMARKS), | |
213 | TAB_MAP(AVFS), | |
214 | TAB_MAP(AVFS_PSM_DEBUG), | |
215 | TAB_MAP(AVFS_FUSE_OVERRIDE), | |
216 | TAB_MAP(PMSTATUSLOG), | |
217 | TAB_MAP(SMU_METRICS), | |
218 | TAB_MAP(DRIVER_SMU_CONFIG), | |
219 | TAB_MAP(ACTIVITY_MONITOR_COEFF), | |
220 | TAB_MAP(OVERDRIVE), | |
221 | TAB_MAP(I2C_COMMANDS), | |
222 | TAB_MAP(PACE), | |
223 | }; | |
224 | ||
6c339f37 | 225 | static struct cmn2asic_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { |
8890fe5f HR |
226 | PWR_MAP(AC), |
227 | PWR_MAP(DC), | |
228 | }; | |
229 | ||
6c339f37 | 230 | static struct cmn2asic_mapping navi10_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { |
6c6187ec KW |
231 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, WORKLOAD_PPLIB_DEFAULT_BIT), |
232 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), | |
233 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, WORKLOAD_PPLIB_POWER_SAVING_BIT), | |
234 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, WORKLOAD_PPLIB_VIDEO_BIT), | |
235 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, WORKLOAD_PPLIB_VR_BIT), | |
2c874ad9 | 236 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_COMPUTE_BIT), |
6c6187ec KW |
237 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), |
238 | }; | |
239 | ||
64cdee43 GS |
240 | static const uint8_t navi1x_throttler_map[] = { |
241 | [THROTTLER_TEMP_EDGE_BIT] = (SMU_THROTTLER_TEMP_EDGE_BIT), | |
242 | [THROTTLER_TEMP_HOTSPOT_BIT] = (SMU_THROTTLER_TEMP_HOTSPOT_BIT), | |
243 | [THROTTLER_TEMP_MEM_BIT] = (SMU_THROTTLER_TEMP_MEM_BIT), | |
244 | [THROTTLER_TEMP_VR_GFX_BIT] = (SMU_THROTTLER_TEMP_VR_GFX_BIT), | |
245 | [THROTTLER_TEMP_VR_MEM0_BIT] = (SMU_THROTTLER_TEMP_VR_MEM0_BIT), | |
246 | [THROTTLER_TEMP_VR_MEM1_BIT] = (SMU_THROTTLER_TEMP_VR_MEM1_BIT), | |
247 | [THROTTLER_TEMP_VR_SOC_BIT] = (SMU_THROTTLER_TEMP_VR_SOC_BIT), | |
248 | [THROTTLER_TEMP_LIQUID0_BIT] = (SMU_THROTTLER_TEMP_LIQUID0_BIT), | |
249 | [THROTTLER_TEMP_LIQUID1_BIT] = (SMU_THROTTLER_TEMP_LIQUID1_BIT), | |
250 | [THROTTLER_TDC_GFX_BIT] = (SMU_THROTTLER_TDC_GFX_BIT), | |
251 | [THROTTLER_TDC_SOC_BIT] = (SMU_THROTTLER_TDC_SOC_BIT), | |
252 | [THROTTLER_PPT0_BIT] = (SMU_THROTTLER_PPT0_BIT), | |
253 | [THROTTLER_PPT1_BIT] = (SMU_THROTTLER_PPT1_BIT), | |
254 | [THROTTLER_PPT2_BIT] = (SMU_THROTTLER_PPT2_BIT), | |
255 | [THROTTLER_PPT3_BIT] = (SMU_THROTTLER_PPT3_BIT), | |
256 | [THROTTLER_FIT_BIT] = (SMU_THROTTLER_FIT_BIT), | |
257 | [THROTTLER_PPM_BIT] = (SMU_THROTTLER_PPM_BIT), | |
258 | [THROTTLER_APCC_BIT] = (SMU_THROTTLER_APCC_BIT), | |
259 | }; | |
260 | ||
261 | ||
fc419158 TZ |
262 | static bool is_asic_secure(struct smu_context *smu) |
263 | { | |
264 | struct amdgpu_device *adev = smu->adev; | |
265 | bool is_secure = true; | |
266 | uint32_t mp0_fw_intf; | |
267 | ||
268 | mp0_fw_intf = RREG32_PCIE(MP0_Public | | |
269 | (smnMP0_FW_INTF & 0xffffffff)); | |
270 | ||
271 | if (!(mp0_fw_intf & (1 << 19))) | |
272 | is_secure = false; | |
273 | ||
274 | return is_secure; | |
275 | } | |
276 | ||
b3490673 | 277 | static int |
74c958a3 | 278 | navi10_get_allowed_feature_mask(struct smu_context *smu, |
b3490673 HR |
279 | uint32_t *feature_mask, uint32_t num) |
280 | { | |
9e040216 KF |
281 | struct amdgpu_device *adev = smu->adev; |
282 | ||
b3490673 HR |
283 | if (num > 2) |
284 | return -EINVAL; | |
285 | ||
74c958a3 KW |
286 | memset(feature_mask, 0, sizeof(uint32_t) * num); |
287 | ||
77ee9caf | 288 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) |
74c958a3 | 289 | | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) |
74c958a3 | 290 | | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) |
d7a8efa5 | 291 | | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) |
74c958a3 KW |
292 | | FEATURE_MASK(FEATURE_PPT_BIT) |
293 | | FEATURE_MASK(FEATURE_TDC_BIT) | |
294 | | FEATURE_MASK(FEATURE_GFX_EDC_BIT) | |
c1972a56 | 295 | | FEATURE_MASK(FEATURE_APCC_PLUS_BIT) |
74c958a3 KW |
296 | | FEATURE_MASK(FEATURE_VR0HOT_BIT) |
297 | | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) | |
298 | | FEATURE_MASK(FEATURE_THERMAL_BIT) | |
299 | | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) | |
c1972a56 | 300 | | FEATURE_MASK(FEATURE_DS_LCLK_BIT) |
3a3c51dd | 301 | | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) |
d8ceb192 | 302 | | FEATURE_MASK(FEATURE_FW_DSTATE_BIT) |
7c6fe84c | 303 | | FEATURE_MASK(FEATURE_BACO_BIT) |
597292eb KF |
304 | | FEATURE_MASK(FEATURE_GFX_SS_BIT) |
305 | | FEATURE_MASK(FEATURE_APCC_DFLL_BIT) | |
c1972a56 | 306 | | FEATURE_MASK(FEATURE_FW_CTF_BIT) |
3043d13f AD |
307 | | FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT) |
308 | | FEATURE_MASK(FEATURE_TEMP_DEPENDENT_VMIN_BIT); | |
8c3b2d1b | 309 | |
bc7ef865 AD |
310 | if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) |
311 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); | |
312 | ||
313 | if (adev->pm.pp_feature & PP_PCIE_DPM_MASK) | |
314 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT); | |
315 | ||
316 | if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK) | |
317 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT); | |
318 | ||
bc7ef865 AD |
319 | if (adev->pm.pp_feature & PP_ULV_MASK) |
320 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT); | |
321 | ||
322 | if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK) | |
323 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); | |
324 | ||
bb3d7d32 | 325 | if (adev->pm.pp_feature & PP_GFXOFF_MASK) |
597292eb | 326 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); |
9e040216 | 327 | |
c12d410f HR |
328 | if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) |
329 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT); | |
330 | ||
a201b6ac HR |
331 | if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB) |
332 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT); | |
333 | ||
c4b76d23 | 334 | if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN) |
43717ff6 LL |
335 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT); |
336 | ||
337 | if (smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG) | |
338 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_JPEG_PG_BIT); | |
c4b76d23 | 339 | |
f5cdd2bd AD |
340 | if (smu->dc_controlled_by_gpio) |
341 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT); | |
342 | ||
c220ba6f EQ |
343 | if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK) |
344 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); | |
345 | ||
346 | /* DPM UCLK enablement should be skipped for navi10 A0 secure board */ | |
347 | if (!(is_asic_secure(smu) && | |
4e8303cf LL |
348 | (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) && |
349 | (adev->rev_id == 0)) && | |
c220ba6f EQ |
350 | (adev->pm.pp_feature & PP_MCLK_DPM_MASK)) |
351 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | |
352 | | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) | |
353 | | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); | |
354 | ||
10144762 EQ |
355 | /* DS SOCCLK enablement should be skipped for navi10 A0 secure board */ |
356 | if (is_asic_secure(smu) && | |
4e8303cf | 357 | (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) && |
10144762 EQ |
358 | (adev->rev_id == 0)) |
359 | *(uint64_t *)feature_mask &= | |
360 | ~FEATURE_MASK(FEATURE_DS_SOCCLK_BIT); | |
c877dff7 | 361 | |
b3490673 HR |
362 | return 0; |
363 | } | |
364 | ||
458020dd | 365 | static void navi10_check_bxco_support(struct smu_context *smu) |
b3490673 | 366 | { |
4a13b4ce EQ |
367 | struct smu_table_context *table_context = &smu->smu_table; |
368 | struct smu_11_0_powerplay_table *powerplay_table = | |
369 | table_context->power_play_table; | |
370 | struct smu_baco_context *smu_baco = &smu->smu_baco; | |
458020dd LL |
371 | struct amdgpu_device *adev = smu->adev; |
372 | uint32_t val; | |
373 | ||
374 | if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_BACO || | |
375 | powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_MACO) { | |
376 | val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0); | |
377 | smu_baco->platform_support = | |
378 | (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : | |
379 | false; | |
380 | } | |
381 | } | |
382 | ||
383 | static int navi10_check_powerplay_table(struct smu_context *smu) | |
384 | { | |
385 | struct smu_table_context *table_context = &smu->smu_table; | |
386 | struct smu_11_0_powerplay_table *powerplay_table = | |
387 | table_context->power_play_table; | |
4a13b4ce EQ |
388 | |
389 | if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_HARDWAREDC) | |
390 | smu->dc_controlled_by_gpio = true; | |
391 | ||
458020dd | 392 | navi10_check_bxco_support(smu); |
4a13b4ce EQ |
393 | |
394 | table_context->thermal_controller_type = | |
395 | powerplay_table->thermal_controller_type; | |
396 | ||
397 | /* | |
398 | * Instead of having its own buffer space and get overdrive_table copied, | |
399 | * smu->od_settings just points to the actual overdrive_table | |
400 | */ | |
401 | smu->od_settings = &powerplay_table->overdrive_table; | |
402 | ||
b3490673 HR |
403 | return 0; |
404 | } | |
405 | ||
406 | static int navi10_append_powerplay_table(struct smu_context *smu) | |
407 | { | |
9e040216 | 408 | struct amdgpu_device *adev = smu->adev; |
b3490673 HR |
409 | struct smu_table_context *table_context = &smu->smu_table; |
410 | PPTable_t *smc_pptable = table_context->driver_pptable; | |
411 | struct atom_smc_dpm_info_v4_5 *smc_dpm_table; | |
02c0bb4e | 412 | struct atom_smc_dpm_info_v4_7 *smc_dpm_table_v4_7; |
b3490673 HR |
413 | int index, ret; |
414 | ||
415 | index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | |
416 | smc_dpm_info); | |
417 | ||
22f2447c | 418 | ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL, |
b3490673 HR |
419 | (uint8_t **)&smc_dpm_table); |
420 | if (ret) | |
421 | return ret; | |
422 | ||
d9811cfc | 423 | dev_info(adev->dev, "smc_dpm_info table revision(format.content): %d.%d\n", |
02c0bb4e EQ |
424 | smc_dpm_table->table_header.format_revision, |
425 | smc_dpm_table->table_header.content_revision); | |
426 | ||
427 | if (smc_dpm_table->table_header.format_revision != 4) { | |
d9811cfc | 428 | dev_err(adev->dev, "smc_dpm_info table format revision is not 4!\n"); |
02c0bb4e EQ |
429 | return -EINVAL; |
430 | } | |
431 | ||
432 | switch (smc_dpm_table->table_header.content_revision) { | |
433 | case 5: /* nv10 and nv14 */ | |
4a9bd6db KC |
434 | smu_memcpy_trailing(smc_pptable, I2cControllers, BoardReserved, |
435 | smc_dpm_table, I2cControllers); | |
02c0bb4e EQ |
436 | break; |
437 | case 7: /* nv12 */ | |
22f2447c | 438 | ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL, |
02c0bb4e EQ |
439 | (uint8_t **)&smc_dpm_table_v4_7); |
440 | if (ret) | |
441 | return ret; | |
4a9bd6db KC |
442 | smu_memcpy_trailing(smc_pptable, I2cControllers, BoardReserved, |
443 | smc_dpm_table_v4_7, I2cControllers); | |
02c0bb4e EQ |
444 | break; |
445 | default: | |
d9811cfc | 446 | dev_err(smu->adev->dev, "smc_dpm_info with unsupported content revision %d!\n", |
02c0bb4e EQ |
447 | smc_dpm_table->table_header.content_revision); |
448 | return -EINVAL; | |
449 | } | |
b3490673 | 450 | |
2a8bfa13 | 451 | if (adev->pm.pp_feature & PP_GFXOFF_MASK) { |
2a8bfa13 JX |
452 | /* TODO: remove it once SMU fw fix it */ |
453 | smc_pptable->DebugOverrides |= DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN; | |
454 | } | |
455 | ||
b3490673 HR |
456 | return 0; |
457 | } | |
458 | ||
459 | static int navi10_store_powerplay_table(struct smu_context *smu) | |
460 | { | |
b3490673 | 461 | struct smu_table_context *table_context = &smu->smu_table; |
4a13b4ce EQ |
462 | struct smu_11_0_powerplay_table *powerplay_table = |
463 | table_context->power_play_table; | |
b3490673 HR |
464 | |
465 | memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable, | |
466 | sizeof(PPTable_t)); | |
467 | ||
4a13b4ce EQ |
468 | return 0; |
469 | } | |
5e6d2665 | 470 | |
4a13b4ce EQ |
471 | static int navi10_setup_pptable(struct smu_context *smu) |
472 | { | |
473 | int ret = 0; | |
f5cdd2bd | 474 | |
4a13b4ce EQ |
475 | ret = smu_v11_0_setup_pptable(smu); |
476 | if (ret) | |
477 | return ret; | |
767acabd | 478 | |
4a13b4ce EQ |
479 | ret = navi10_store_powerplay_table(smu); |
480 | if (ret) | |
481 | return ret; | |
482 | ||
483 | ret = navi10_append_powerplay_table(smu); | |
484 | if (ret) | |
485 | return ret; | |
486 | ||
487 | ret = navi10_check_powerplay_table(smu); | |
488 | if (ret) | |
489 | return ret; | |
490 | ||
491 | return ret; | |
b3490673 HR |
492 | } |
493 | ||
c1b353b7 | 494 | static int navi10_tables_init(struct smu_context *smu) |
22c9c6ca | 495 | { |
b94afb61 | 496 | struct smu_table_context *smu_table = &smu->smu_table; |
c1b353b7 | 497 | struct smu_table *tables = smu_table->tables; |
18c4e319 LL |
498 | struct smu_table *dummy_read_1_table = |
499 | &smu_table->dummy_read_1_table; | |
b94afb61 | 500 | |
22c9c6ca HR |
501 | SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), |
502 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
503 | SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), | |
504 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
7d6c13ef EQ |
505 | SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_NV1X_t), |
506 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
1bc73475 AD |
507 | SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t), |
508 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
22c9c6ca HR |
509 | SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t), |
510 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
511 | SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE, | |
512 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
513 | SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, | |
514 | sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, | |
515 | AMDGPU_GEM_DOMAIN_VRAM); | |
816d61d5 EQ |
516 | SMU_TABLE_INIT(tables, SMU_TABLE_DRIVER_SMU_CONFIG, sizeof(DriverSmuConfig_t), |
517 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
9634de27 | 518 | |
18c4e319 LL |
519 | dummy_read_1_table->size = 0x40000; |
520 | dummy_read_1_table->align = PAGE_SIZE; | |
521 | dummy_read_1_table->domain = AMDGPU_GEM_DOMAIN_VRAM; | |
522 | ||
7d6c13ef EQ |
523 | smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_NV1X_t), |
524 | GFP_KERNEL); | |
b94afb61 | 525 | if (!smu_table->metrics_table) |
6d4ff50a | 526 | goto err0_out; |
b94afb61 KW |
527 | smu_table->metrics_time = 0; |
528 | ||
61e2d322 | 529 | smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); |
6d4ff50a EQ |
530 | smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); |
531 | if (!smu_table->gpu_metrics_table) | |
532 | goto err1_out; | |
533 | ||
9fa1ed5b EQ |
534 | smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); |
535 | if (!smu_table->watermarks_table) | |
6d4ff50a | 536 | goto err2_out; |
9fa1ed5b | 537 | |
816d61d5 EQ |
538 | smu_table->driver_smu_config_table = |
539 | kzalloc(tables[SMU_TABLE_DRIVER_SMU_CONFIG].size, GFP_KERNEL); | |
540 | if (!smu_table->driver_smu_config_table) | |
541 | goto err3_out; | |
542 | ||
9634de27 | 543 | return 0; |
6d4ff50a | 544 | |
816d61d5 EQ |
545 | err3_out: |
546 | kfree(smu_table->watermarks_table); | |
6d4ff50a EQ |
547 | err2_out: |
548 | kfree(smu_table->gpu_metrics_table); | |
549 | err1_out: | |
550 | kfree(smu_table->metrics_table); | |
551 | err0_out: | |
552 | return -ENOMEM; | |
22c9c6ca HR |
553 | } |
554 | ||
7d6c13ef EQ |
555 | static int navi10_get_legacy_smu_metrics_data(struct smu_context *smu, |
556 | MetricsMember_t member, | |
557 | uint32_t *value) | |
558 | { | |
1e3a58df | 559 | struct smu_table_context *smu_table = &smu->smu_table; |
7d6c13ef EQ |
560 | SmuMetrics_legacy_t *metrics = |
561 | (SmuMetrics_legacy_t *)smu_table->metrics_table; | |
562 | int ret = 0; | |
563 | ||
da11407f EQ |
564 | ret = smu_cmn_get_metrics_table(smu, |
565 | NULL, | |
566 | false); | |
567 | if (ret) | |
7d6c13ef | 568 | return ret; |
7d6c13ef EQ |
569 | |
570 | switch (member) { | |
571 | case METRICS_CURR_GFXCLK: | |
572 | *value = metrics->CurrClock[PPCLK_GFXCLK]; | |
573 | break; | |
574 | case METRICS_CURR_SOCCLK: | |
575 | *value = metrics->CurrClock[PPCLK_SOCCLK]; | |
576 | break; | |
577 | case METRICS_CURR_UCLK: | |
578 | *value = metrics->CurrClock[PPCLK_UCLK]; | |
579 | break; | |
580 | case METRICS_CURR_VCLK: | |
581 | *value = metrics->CurrClock[PPCLK_VCLK]; | |
582 | break; | |
583 | case METRICS_CURR_DCLK: | |
584 | *value = metrics->CurrClock[PPCLK_DCLK]; | |
585 | break; | |
586 | case METRICS_CURR_DCEFCLK: | |
587 | *value = metrics->CurrClock[PPCLK_DCEFCLK]; | |
588 | break; | |
589 | case METRICS_AVERAGE_GFXCLK: | |
590 | *value = metrics->AverageGfxclkFrequency; | |
591 | break; | |
592 | case METRICS_AVERAGE_SOCCLK: | |
593 | *value = metrics->AverageSocclkFrequency; | |
594 | break; | |
595 | case METRICS_AVERAGE_UCLK: | |
596 | *value = metrics->AverageUclkFrequency; | |
597 | break; | |
598 | case METRICS_AVERAGE_GFXACTIVITY: | |
599 | *value = metrics->AverageGfxActivity; | |
600 | break; | |
601 | case METRICS_AVERAGE_MEMACTIVITY: | |
602 | *value = metrics->AverageUclkActivity; | |
603 | break; | |
604 | case METRICS_AVERAGE_SOCKETPOWER: | |
605 | *value = metrics->AverageSocketPower << 8; | |
606 | break; | |
607 | case METRICS_TEMPERATURE_EDGE: | |
608 | *value = metrics->TemperatureEdge * | |
609 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
610 | break; | |
611 | case METRICS_TEMPERATURE_HOTSPOT: | |
612 | *value = metrics->TemperatureHotspot * | |
613 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
614 | break; | |
615 | case METRICS_TEMPERATURE_MEM: | |
616 | *value = metrics->TemperatureMem * | |
617 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
618 | break; | |
619 | case METRICS_TEMPERATURE_VRGFX: | |
620 | *value = metrics->TemperatureVrGfx * | |
621 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
622 | break; | |
623 | case METRICS_TEMPERATURE_VRSOC: | |
624 | *value = metrics->TemperatureVrSoc * | |
625 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
626 | break; | |
627 | case METRICS_THROTTLER_STATUS: | |
628 | *value = metrics->ThrottlerStatus; | |
629 | break; | |
630 | case METRICS_CURR_FANSPEED: | |
631 | *value = metrics->CurrFanSpeed; | |
632 | break; | |
633 | default: | |
634 | *value = UINT_MAX; | |
635 | break; | |
636 | } | |
637 | ||
7d6c13ef EQ |
638 | return ret; |
639 | } | |
640 | ||
62d35163 EQ |
641 | static int navi10_get_smu_metrics_data(struct smu_context *smu, |
642 | MetricsMember_t member, | |
643 | uint32_t *value) | |
644 | { | |
1e3a58df | 645 | struct smu_table_context *smu_table = &smu->smu_table; |
7d6c13ef EQ |
646 | SmuMetrics_t *metrics = |
647 | (SmuMetrics_t *)smu_table->metrics_table; | |
648 | int ret = 0; | |
649 | ||
da11407f EQ |
650 | ret = smu_cmn_get_metrics_table(smu, |
651 | NULL, | |
652 | false); | |
653 | if (ret) | |
7d6c13ef | 654 | return ret; |
7d6c13ef EQ |
655 | |
656 | switch (member) { | |
657 | case METRICS_CURR_GFXCLK: | |
658 | *value = metrics->CurrClock[PPCLK_GFXCLK]; | |
659 | break; | |
660 | case METRICS_CURR_SOCCLK: | |
661 | *value = metrics->CurrClock[PPCLK_SOCCLK]; | |
662 | break; | |
663 | case METRICS_CURR_UCLK: | |
664 | *value = metrics->CurrClock[PPCLK_UCLK]; | |
665 | break; | |
666 | case METRICS_CURR_VCLK: | |
667 | *value = metrics->CurrClock[PPCLK_VCLK]; | |
668 | break; | |
669 | case METRICS_CURR_DCLK: | |
670 | *value = metrics->CurrClock[PPCLK_DCLK]; | |
671 | break; | |
672 | case METRICS_CURR_DCEFCLK: | |
673 | *value = metrics->CurrClock[PPCLK_DCEFCLK]; | |
674 | break; | |
675 | case METRICS_AVERAGE_GFXCLK: | |
676 | if (metrics->AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) | |
677 | *value = metrics->AverageGfxclkFrequencyPreDs; | |
678 | else | |
679 | *value = metrics->AverageGfxclkFrequencyPostDs; | |
680 | break; | |
681 | case METRICS_AVERAGE_SOCCLK: | |
682 | *value = metrics->AverageSocclkFrequency; | |
683 | break; | |
684 | case METRICS_AVERAGE_UCLK: | |
685 | *value = metrics->AverageUclkFrequencyPostDs; | |
686 | break; | |
687 | case METRICS_AVERAGE_GFXACTIVITY: | |
688 | *value = metrics->AverageGfxActivity; | |
689 | break; | |
690 | case METRICS_AVERAGE_MEMACTIVITY: | |
691 | *value = metrics->AverageUclkActivity; | |
692 | break; | |
693 | case METRICS_AVERAGE_SOCKETPOWER: | |
694 | *value = metrics->AverageSocketPower << 8; | |
695 | break; | |
696 | case METRICS_TEMPERATURE_EDGE: | |
697 | *value = metrics->TemperatureEdge * | |
698 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
699 | break; | |
700 | case METRICS_TEMPERATURE_HOTSPOT: | |
701 | *value = metrics->TemperatureHotspot * | |
702 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
703 | break; | |
704 | case METRICS_TEMPERATURE_MEM: | |
705 | *value = metrics->TemperatureMem * | |
706 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
707 | break; | |
708 | case METRICS_TEMPERATURE_VRGFX: | |
709 | *value = metrics->TemperatureVrGfx * | |
710 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
711 | break; | |
712 | case METRICS_TEMPERATURE_VRSOC: | |
713 | *value = metrics->TemperatureVrSoc * | |
714 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
715 | break; | |
716 | case METRICS_THROTTLER_STATUS: | |
717 | *value = metrics->ThrottlerStatus; | |
718 | break; | |
719 | case METRICS_CURR_FANSPEED: | |
720 | *value = metrics->CurrFanSpeed; | |
721 | break; | |
722 | default: | |
723 | *value = UINT_MAX; | |
724 | break; | |
725 | } | |
726 | ||
7d6c13ef EQ |
727 | return ret; |
728 | } | |
729 | ||
730 | static int navi12_get_legacy_smu_metrics_data(struct smu_context *smu, | |
731 | MetricsMember_t member, | |
732 | uint32_t *value) | |
733 | { | |
1e3a58df | 734 | struct smu_table_context *smu_table = &smu->smu_table; |
7d6c13ef EQ |
735 | SmuMetrics_NV12_legacy_t *metrics = |
736 | (SmuMetrics_NV12_legacy_t *)smu_table->metrics_table; | |
62d35163 EQ |
737 | int ret = 0; |
738 | ||
da11407f EQ |
739 | ret = smu_cmn_get_metrics_table(smu, |
740 | NULL, | |
741 | false); | |
742 | if (ret) | |
62d35163 | 743 | return ret; |
62d35163 | 744 | |
cf24dd27 EQ |
745 | switch (member) { |
746 | case METRICS_CURR_GFXCLK: | |
747 | *value = metrics->CurrClock[PPCLK_GFXCLK]; | |
748 | break; | |
749 | case METRICS_CURR_SOCCLK: | |
750 | *value = metrics->CurrClock[PPCLK_SOCCLK]; | |
751 | break; | |
752 | case METRICS_CURR_UCLK: | |
753 | *value = metrics->CurrClock[PPCLK_UCLK]; | |
754 | break; | |
755 | case METRICS_CURR_VCLK: | |
756 | *value = metrics->CurrClock[PPCLK_VCLK]; | |
757 | break; | |
758 | case METRICS_CURR_DCLK: | |
759 | *value = metrics->CurrClock[PPCLK_DCLK]; | |
760 | break; | |
9d09fa6f ND |
761 | case METRICS_CURR_DCEFCLK: |
762 | *value = metrics->CurrClock[PPCLK_DCEFCLK]; | |
763 | break; | |
cf24dd27 EQ |
764 | case METRICS_AVERAGE_GFXCLK: |
765 | *value = metrics->AverageGfxclkFrequency; | |
766 | break; | |
767 | case METRICS_AVERAGE_SOCCLK: | |
768 | *value = metrics->AverageSocclkFrequency; | |
769 | break; | |
770 | case METRICS_AVERAGE_UCLK: | |
771 | *value = metrics->AverageUclkFrequency; | |
772 | break; | |
773 | case METRICS_AVERAGE_GFXACTIVITY: | |
774 | *value = metrics->AverageGfxActivity; | |
775 | break; | |
776 | case METRICS_AVERAGE_MEMACTIVITY: | |
777 | *value = metrics->AverageUclkActivity; | |
778 | break; | |
779 | case METRICS_AVERAGE_SOCKETPOWER: | |
780 | *value = metrics->AverageSocketPower << 8; | |
781 | break; | |
782 | case METRICS_TEMPERATURE_EDGE: | |
783 | *value = metrics->TemperatureEdge * | |
784 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
785 | break; | |
786 | case METRICS_TEMPERATURE_HOTSPOT: | |
787 | *value = metrics->TemperatureHotspot * | |
788 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
789 | break; | |
790 | case METRICS_TEMPERATURE_MEM: | |
791 | *value = metrics->TemperatureMem * | |
792 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
793 | break; | |
794 | case METRICS_TEMPERATURE_VRGFX: | |
795 | *value = metrics->TemperatureVrGfx * | |
796 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
797 | break; | |
798 | case METRICS_TEMPERATURE_VRSOC: | |
799 | *value = metrics->TemperatureVrSoc * | |
800 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
801 | break; | |
802 | case METRICS_THROTTLER_STATUS: | |
803 | *value = metrics->ThrottlerStatus; | |
804 | break; | |
805 | case METRICS_CURR_FANSPEED: | |
806 | *value = metrics->CurrFanSpeed; | |
807 | break; | |
808 | default: | |
809 | *value = UINT_MAX; | |
810 | break; | |
811 | } | |
812 | ||
b94afb61 KW |
813 | return ret; |
814 | } | |
815 | ||
7d6c13ef EQ |
816 | static int navi12_get_smu_metrics_data(struct smu_context *smu, |
817 | MetricsMember_t member, | |
818 | uint32_t *value) | |
819 | { | |
1e3a58df | 820 | struct smu_table_context *smu_table = &smu->smu_table; |
7d6c13ef EQ |
821 | SmuMetrics_NV12_t *metrics = |
822 | (SmuMetrics_NV12_t *)smu_table->metrics_table; | |
823 | int ret = 0; | |
824 | ||
da11407f EQ |
825 | ret = smu_cmn_get_metrics_table(smu, |
826 | NULL, | |
827 | false); | |
828 | if (ret) | |
7d6c13ef | 829 | return ret; |
7d6c13ef EQ |
830 | |
831 | switch (member) { | |
832 | case METRICS_CURR_GFXCLK: | |
833 | *value = metrics->CurrClock[PPCLK_GFXCLK]; | |
834 | break; | |
835 | case METRICS_CURR_SOCCLK: | |
836 | *value = metrics->CurrClock[PPCLK_SOCCLK]; | |
837 | break; | |
838 | case METRICS_CURR_UCLK: | |
839 | *value = metrics->CurrClock[PPCLK_UCLK]; | |
840 | break; | |
841 | case METRICS_CURR_VCLK: | |
842 | *value = metrics->CurrClock[PPCLK_VCLK]; | |
843 | break; | |
844 | case METRICS_CURR_DCLK: | |
845 | *value = metrics->CurrClock[PPCLK_DCLK]; | |
846 | break; | |
847 | case METRICS_CURR_DCEFCLK: | |
848 | *value = metrics->CurrClock[PPCLK_DCEFCLK]; | |
849 | break; | |
850 | case METRICS_AVERAGE_GFXCLK: | |
851 | if (metrics->AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) | |
852 | *value = metrics->AverageGfxclkFrequencyPreDs; | |
853 | else | |
854 | *value = metrics->AverageGfxclkFrequencyPostDs; | |
855 | break; | |
856 | case METRICS_AVERAGE_SOCCLK: | |
857 | *value = metrics->AverageSocclkFrequency; | |
858 | break; | |
859 | case METRICS_AVERAGE_UCLK: | |
860 | *value = metrics->AverageUclkFrequencyPostDs; | |
861 | break; | |
862 | case METRICS_AVERAGE_GFXACTIVITY: | |
863 | *value = metrics->AverageGfxActivity; | |
864 | break; | |
865 | case METRICS_AVERAGE_MEMACTIVITY: | |
866 | *value = metrics->AverageUclkActivity; | |
867 | break; | |
868 | case METRICS_AVERAGE_SOCKETPOWER: | |
869 | *value = metrics->AverageSocketPower << 8; | |
870 | break; | |
871 | case METRICS_TEMPERATURE_EDGE: | |
872 | *value = metrics->TemperatureEdge * | |
873 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
874 | break; | |
875 | case METRICS_TEMPERATURE_HOTSPOT: | |
876 | *value = metrics->TemperatureHotspot * | |
877 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
878 | break; | |
879 | case METRICS_TEMPERATURE_MEM: | |
880 | *value = metrics->TemperatureMem * | |
881 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
882 | break; | |
883 | case METRICS_TEMPERATURE_VRGFX: | |
884 | *value = metrics->TemperatureVrGfx * | |
885 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
886 | break; | |
887 | case METRICS_TEMPERATURE_VRSOC: | |
888 | *value = metrics->TemperatureVrSoc * | |
889 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
890 | break; | |
891 | case METRICS_THROTTLER_STATUS: | |
892 | *value = metrics->ThrottlerStatus; | |
893 | break; | |
894 | case METRICS_CURR_FANSPEED: | |
895 | *value = metrics->CurrFanSpeed; | |
896 | break; | |
897 | default: | |
898 | *value = UINT_MAX; | |
899 | break; | |
900 | } | |
901 | ||
7d6c13ef EQ |
902 | return ret; |
903 | } | |
904 | ||
905 | static int navi1x_get_smu_metrics_data(struct smu_context *smu, | |
906 | MetricsMember_t member, | |
907 | uint32_t *value) | |
908 | { | |
909 | struct amdgpu_device *adev = smu->adev; | |
7d6c13ef EQ |
910 | int ret = 0; |
911 | ||
4e8303cf | 912 | switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { |
ea0d730a | 913 | case IP_VERSION(11, 0, 9): |
710d9cae | 914 | if (smu->smc_fw_version > 0x00341C00) |
7d6c13ef EQ |
915 | ret = navi12_get_smu_metrics_data(smu, member, value); |
916 | else | |
917 | ret = navi12_get_legacy_smu_metrics_data(smu, member, value); | |
918 | break; | |
ea0d730a AD |
919 | case IP_VERSION(11, 0, 0): |
920 | case IP_VERSION(11, 0, 5): | |
7d6c13ef | 921 | default: |
4e8303cf LL |
922 | if (((amdgpu_ip_version(adev, MP1_HWIP, 0) == |
923 | IP_VERSION(11, 0, 5)) && | |
710d9cae | 924 | smu->smc_fw_version > 0x00351F00) || |
4e8303cf LL |
925 | ((amdgpu_ip_version(adev, MP1_HWIP, 0) == |
926 | IP_VERSION(11, 0, 0)) && | |
710d9cae | 927 | smu->smc_fw_version > 0x002A3B00)) |
7d6c13ef EQ |
928 | ret = navi10_get_smu_metrics_data(smu, member, value); |
929 | else | |
930 | ret = navi10_get_legacy_smu_metrics_data(smu, member, value); | |
931 | break; | |
932 | } | |
933 | ||
934 | return ret; | |
935 | } | |
936 | ||
b3490673 HR |
937 | static int navi10_allocate_dpm_context(struct smu_context *smu) |
938 | { | |
939 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
940 | ||
b3490673 HR |
941 | smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), |
942 | GFP_KERNEL); | |
943 | if (!smu_dpm->dpm_context) | |
944 | return -ENOMEM; | |
945 | ||
946 | smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context); | |
947 | ||
948 | return 0; | |
949 | } | |
950 | ||
c1b353b7 EQ |
951 | static int navi10_init_smc_tables(struct smu_context *smu) |
952 | { | |
953 | int ret = 0; | |
954 | ||
955 | ret = navi10_tables_init(smu); | |
956 | if (ret) | |
957 | return ret; | |
958 | ||
959 | ret = navi10_allocate_dpm_context(smu); | |
960 | if (ret) | |
961 | return ret; | |
962 | ||
963 | return smu_v11_0_init_smc_tables(smu); | |
964 | } | |
965 | ||
b3490673 HR |
966 | static int navi10_set_default_dpm_table(struct smu_context *smu) |
967 | { | |
3afb244b EQ |
968 | struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; |
969 | PPTable_t *driver_ppt = smu->smu_table.driver_pptable; | |
970 | struct smu_11_0_dpm_table *dpm_table; | |
971 | int ret = 0; | |
b3490673 | 972 | |
3afb244b EQ |
973 | /* socclk dpm table setup */ |
974 | dpm_table = &dpm_context->dpm_tables.soc_table; | |
b4bb3aaf | 975 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { |
3afb244b EQ |
976 | ret = smu_v11_0_set_single_dpm_table(smu, |
977 | SMU_SOCCLK, | |
978 | dpm_table); | |
979 | if (ret) | |
980 | return ret; | |
981 | dpm_table->is_fine_grained = | |
982 | !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete; | |
983 | } else { | |
984 | dpm_table->count = 1; | |
985 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; | |
986 | dpm_table->dpm_levels[0].enabled = true; | |
987 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
988 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
989 | } | |
b3490673 | 990 | |
3afb244b EQ |
991 | /* gfxclk dpm table setup */ |
992 | dpm_table = &dpm_context->dpm_tables.gfx_table; | |
b4bb3aaf | 993 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { |
3afb244b EQ |
994 | ret = smu_v11_0_set_single_dpm_table(smu, |
995 | SMU_GFXCLK, | |
996 | dpm_table); | |
997 | if (ret) | |
998 | return ret; | |
999 | dpm_table->is_fine_grained = | |
1000 | !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete; | |
1001 | } else { | |
1002 | dpm_table->count = 1; | |
1003 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; | |
1004 | dpm_table->dpm_levels[0].enabled = true; | |
1005 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1006 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1007 | } | |
b3490673 | 1008 | |
3afb244b EQ |
1009 | /* uclk dpm table setup */ |
1010 | dpm_table = &dpm_context->dpm_tables.uclk_table; | |
b4bb3aaf | 1011 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { |
3afb244b EQ |
1012 | ret = smu_v11_0_set_single_dpm_table(smu, |
1013 | SMU_UCLK, | |
1014 | dpm_table); | |
1015 | if (ret) | |
1016 | return ret; | |
1017 | dpm_table->is_fine_grained = | |
1018 | !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete; | |
1019 | } else { | |
1020 | dpm_table->count = 1; | |
1021 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; | |
1022 | dpm_table->dpm_levels[0].enabled = true; | |
1023 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1024 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1025 | } | |
b3490673 | 1026 | |
3afb244b EQ |
1027 | /* vclk dpm table setup */ |
1028 | dpm_table = &dpm_context->dpm_tables.vclk_table; | |
b4bb3aaf | 1029 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { |
3afb244b EQ |
1030 | ret = smu_v11_0_set_single_dpm_table(smu, |
1031 | SMU_VCLK, | |
1032 | dpm_table); | |
1033 | if (ret) | |
1034 | return ret; | |
1035 | dpm_table->is_fine_grained = | |
1036 | !driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete; | |
1037 | } else { | |
1038 | dpm_table->count = 1; | |
1039 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100; | |
1040 | dpm_table->dpm_levels[0].enabled = true; | |
1041 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1042 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1043 | } | |
b3490673 | 1044 | |
3afb244b EQ |
1045 | /* dclk dpm table setup */ |
1046 | dpm_table = &dpm_context->dpm_tables.dclk_table; | |
b4bb3aaf | 1047 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { |
3afb244b EQ |
1048 | ret = smu_v11_0_set_single_dpm_table(smu, |
1049 | SMU_DCLK, | |
1050 | dpm_table); | |
1051 | if (ret) | |
1052 | return ret; | |
1053 | dpm_table->is_fine_grained = | |
1054 | !driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete; | |
1055 | } else { | |
1056 | dpm_table->count = 1; | |
1057 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100; | |
1058 | dpm_table->dpm_levels[0].enabled = true; | |
1059 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1060 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1061 | } | |
b3490673 | 1062 | |
3afb244b EQ |
1063 | /* dcefclk dpm table setup */ |
1064 | dpm_table = &dpm_context->dpm_tables.dcef_table; | |
b4bb3aaf | 1065 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { |
3afb244b EQ |
1066 | ret = smu_v11_0_set_single_dpm_table(smu, |
1067 | SMU_DCEFCLK, | |
1068 | dpm_table); | |
1069 | if (ret) | |
1070 | return ret; | |
1071 | dpm_table->is_fine_grained = | |
1072 | !driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete; | |
1073 | } else { | |
1074 | dpm_table->count = 1; | |
1075 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; | |
1076 | dpm_table->dpm_levels[0].enabled = true; | |
1077 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1078 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1079 | } | |
b3490673 | 1080 | |
3afb244b EQ |
1081 | /* pixelclk dpm table setup */ |
1082 | dpm_table = &dpm_context->dpm_tables.pixel_table; | |
b4bb3aaf | 1083 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { |
3afb244b EQ |
1084 | ret = smu_v11_0_set_single_dpm_table(smu, |
1085 | SMU_PIXCLK, | |
1086 | dpm_table); | |
1087 | if (ret) | |
1088 | return ret; | |
1089 | dpm_table->is_fine_grained = | |
1090 | !driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete; | |
1091 | } else { | |
1092 | dpm_table->count = 1; | |
1093 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; | |
1094 | dpm_table->dpm_levels[0].enabled = true; | |
1095 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1096 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1097 | } | |
b3490673 | 1098 | |
3afb244b EQ |
1099 | /* displayclk dpm table setup */ |
1100 | dpm_table = &dpm_context->dpm_tables.display_table; | |
b4bb3aaf | 1101 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { |
3afb244b EQ |
1102 | ret = smu_v11_0_set_single_dpm_table(smu, |
1103 | SMU_DISPCLK, | |
1104 | dpm_table); | |
1105 | if (ret) | |
1106 | return ret; | |
1107 | dpm_table->is_fine_grained = | |
1108 | !driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete; | |
1109 | } else { | |
1110 | dpm_table->count = 1; | |
1111 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; | |
1112 | dpm_table->dpm_levels[0].enabled = true; | |
1113 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1114 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1115 | } | |
b3490673 | 1116 | |
3afb244b EQ |
1117 | /* phyclk dpm table setup */ |
1118 | dpm_table = &dpm_context->dpm_tables.phy_table; | |
b4bb3aaf | 1119 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { |
3afb244b EQ |
1120 | ret = smu_v11_0_set_single_dpm_table(smu, |
1121 | SMU_PHYCLK, | |
1122 | dpm_table); | |
1123 | if (ret) | |
1124 | return ret; | |
1125 | dpm_table->is_fine_grained = | |
1126 | !driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete; | |
1127 | } else { | |
1128 | dpm_table->count = 1; | |
1129 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; | |
1130 | dpm_table->dpm_levels[0].enabled = true; | |
1131 | dpm_table->min = dpm_table->dpm_levels[0].value; | |
1132 | dpm_table->max = dpm_table->dpm_levels[0].value; | |
1133 | } | |
b3490673 HR |
1134 | |
1135 | return 0; | |
1136 | } | |
1137 | ||
8b7f3529 BZ |
1138 | static int navi10_dpm_set_vcn_enable(struct smu_context *smu, |
1139 | bool enable, | |
1140 | int inst) | |
a8179d62 KF |
1141 | { |
1142 | int ret = 0; | |
5fa790f6 EQ |
1143 | |
1144 | if (enable) { | |
706e5082 | 1145 | /* vcn dpm on is a prerequisite for vcn power gate messages */ |
b4bb3aaf | 1146 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { |
66c86828 | 1147 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 1, NULL); |
706e5082 EQ |
1148 | if (ret) |
1149 | return ret; | |
1150 | } | |
a8179d62 | 1151 | } else { |
b4bb3aaf | 1152 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { |
66c86828 | 1153 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL); |
706e5082 EQ |
1154 | if (ret) |
1155 | return ret; | |
1156 | } | |
a8179d62 KF |
1157 | } |
1158 | ||
5fa790f6 | 1159 | return ret; |
a8179d62 KF |
1160 | } |
1161 | ||
43717ff6 LL |
1162 | static int navi10_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) |
1163 | { | |
43717ff6 LL |
1164 | int ret = 0; |
1165 | ||
1166 | if (enable) { | |
b4bb3aaf | 1167 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { |
66c86828 | 1168 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerUpJpeg, NULL); |
43717ff6 LL |
1169 | if (ret) |
1170 | return ret; | |
1171 | } | |
43717ff6 | 1172 | } else { |
b4bb3aaf | 1173 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { |
66c86828 | 1174 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownJpeg, NULL); |
43717ff6 LL |
1175 | if (ret) |
1176 | return ret; | |
1177 | } | |
43717ff6 LL |
1178 | } |
1179 | ||
1180 | return ret; | |
1181 | } | |
1182 | ||
98e1a543 KW |
1183 | static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, |
1184 | enum smu_clk_type clk_type, | |
1185 | uint32_t *value) | |
1186 | { | |
cf24dd27 EQ |
1187 | MetricsMember_t member_type; |
1188 | int clk_id = 0; | |
98e1a543 | 1189 | |
6c339f37 EQ |
1190 | clk_id = smu_cmn_to_asic_specific_index(smu, |
1191 | CMN2ASIC_MAPPING_CLK, | |
1192 | clk_type); | |
98e1a543 KW |
1193 | if (clk_id < 0) |
1194 | return clk_id; | |
1195 | ||
cf24dd27 EQ |
1196 | switch (clk_id) { |
1197 | case PPCLK_GFXCLK: | |
1198 | member_type = METRICS_CURR_GFXCLK; | |
1199 | break; | |
1200 | case PPCLK_UCLK: | |
1201 | member_type = METRICS_CURR_UCLK; | |
1202 | break; | |
1203 | case PPCLK_SOCCLK: | |
1204 | member_type = METRICS_CURR_SOCCLK; | |
1205 | break; | |
1206 | case PPCLK_VCLK: | |
1207 | member_type = METRICS_CURR_VCLK; | |
1208 | break; | |
1209 | case PPCLK_DCLK: | |
1210 | member_type = METRICS_CURR_DCLK; | |
1211 | break; | |
1212 | case PPCLK_DCEFCLK: | |
1213 | member_type = METRICS_CURR_DCEFCLK; | |
1214 | break; | |
1215 | default: | |
1216 | return -EINVAL; | |
1217 | } | |
98e1a543 | 1218 | |
7d6c13ef | 1219 | return navi1x_get_smu_metrics_data(smu, |
cf24dd27 EQ |
1220 | member_type, |
1221 | value); | |
98e1a543 KW |
1222 | } |
1223 | ||
c8c19ebf | 1224 | static int navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type) |
c49b1b59 KW |
1225 | { |
1226 | PPTable_t *pptable = smu->smu_table.driver_pptable; | |
1227 | DpmDescriptor_t *dpm_desc = NULL; | |
c8c19ebf | 1228 | int clk_index = 0; |
c49b1b59 | 1229 | |
6c339f37 EQ |
1230 | clk_index = smu_cmn_to_asic_specific_index(smu, |
1231 | CMN2ASIC_MAPPING_CLK, | |
1232 | clk_type); | |
c8c19ebf JZ |
1233 | if (clk_index < 0) |
1234 | return clk_index; | |
1235 | ||
c49b1b59 KW |
1236 | dpm_desc = &pptable->DpmDescriptor[clk_index]; |
1237 | ||
1238 | /* 0 - Fine grained DPM, 1 - Discrete DPM */ | |
c8c19ebf | 1239 | return dpm_desc->SnapToDiscrete == 0 ? 1 : 0; |
c49b1b59 KW |
1240 | } |
1241 | ||
e33a8cfd | 1242 | static inline bool navi10_od_feature_is_supported(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODFEATURE_CAP cap) |
7f3353f6 | 1243 | { |
e33a8cfd | 1244 | return od_table->cap[cap]; |
7f3353f6 MC |
1245 | } |
1246 | ||
ee23a518 AD |
1247 | static void navi10_od_setting_get_range(struct smu_11_0_overdrive_table *od_table, |
1248 | enum SMU_11_0_ODSETTING_ID setting, | |
1249 | uint32_t *min, uint32_t *max) | |
1250 | { | |
1251 | if (min) | |
1252 | *min = od_table->min[setting]; | |
1253 | if (max) | |
1254 | *max = od_table->max[setting]; | |
1255 | } | |
7f3353f6 | 1256 | |
b06b48d7 DP |
1257 | static int navi10_emit_clk_levels(struct smu_context *smu, |
1258 | enum smu_clk_type clk_type, | |
1259 | char *buf, | |
1260 | int *offset) | |
1261 | { | |
1262 | uint16_t *curve_settings; | |
1263 | int ret = 0; | |
1264 | uint32_t cur_value = 0, value = 0; | |
1265 | uint32_t freq_values[3] = {0}; | |
1266 | uint32_t i, levels, mark_index = 0, count = 0; | |
1267 | struct smu_table_context *table_context = &smu->smu_table; | |
1268 | uint32_t gen_speed, lane_width; | |
1269 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
1270 | struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; | |
1271 | PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; | |
1272 | OverDriveTable_t *od_table = | |
1273 | (OverDriveTable_t *)table_context->overdrive_table; | |
1274 | struct smu_11_0_overdrive_table *od_settings = smu->od_settings; | |
1275 | uint32_t min_value, max_value; | |
1276 | ||
1277 | switch (clk_type) { | |
1278 | case SMU_GFXCLK: | |
1279 | case SMU_SCLK: | |
1280 | case SMU_SOCCLK: | |
1281 | case SMU_MCLK: | |
1282 | case SMU_UCLK: | |
1283 | case SMU_FCLK: | |
1284 | case SMU_VCLK: | |
1285 | case SMU_DCLK: | |
1286 | case SMU_DCEFCLK: | |
1287 | ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value); | |
1288 | if (ret) | |
1289 | return ret; | |
1290 | ||
1291 | ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count); | |
1292 | if (ret) | |
1293 | return ret; | |
1294 | ||
c8c19ebf JZ |
1295 | ret = navi10_is_support_fine_grained_dpm(smu, clk_type); |
1296 | if (ret < 0) | |
1297 | return ret; | |
1298 | ||
1299 | if (!ret) { | |
b06b48d7 DP |
1300 | for (i = 0; i < count; i++) { |
1301 | ret = smu_v11_0_get_dpm_freq_by_index(smu, | |
1302 | clk_type, i, &value); | |
1303 | if (ret) | |
1304 | return ret; | |
1305 | ||
1306 | *offset += sysfs_emit_at(buf, *offset, | |
1307 | "%d: %uMhz %s\n", | |
1308 | i, value, | |
1309 | cur_value == value ? "*" : ""); | |
1310 | } | |
1311 | } else { | |
1312 | ret = smu_v11_0_get_dpm_freq_by_index(smu, | |
1313 | clk_type, 0, &freq_values[0]); | |
1314 | if (ret) | |
1315 | return ret; | |
1316 | ret = smu_v11_0_get_dpm_freq_by_index(smu, | |
1317 | clk_type, | |
1318 | count - 1, | |
1319 | &freq_values[2]); | |
1320 | if (ret) | |
1321 | return ret; | |
1322 | ||
1323 | freq_values[1] = cur_value; | |
1324 | mark_index = cur_value == freq_values[0] ? 0 : | |
1325 | cur_value == freq_values[2] ? 2 : 1; | |
1326 | ||
1327 | levels = 3; | |
1328 | if (mark_index != 1) { | |
1329 | levels = 2; | |
1330 | freq_values[1] = freq_values[2]; | |
1331 | } | |
1332 | ||
1333 | for (i = 0; i < levels; i++) { | |
1334 | *offset += sysfs_emit_at(buf, *offset, | |
1335 | "%d: %uMhz %s\n", | |
1336 | i, freq_values[i], | |
1337 | i == mark_index ? "*" : ""); | |
1338 | } | |
1339 | } | |
1340 | break; | |
1341 | case SMU_PCIE: | |
1342 | gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu); | |
1343 | lane_width = smu_v11_0_get_current_pcie_link_width_level(smu); | |
1344 | for (i = 0; i < NUM_LINK_LEVELS; i++) { | |
1345 | *offset += sysfs_emit_at(buf, *offset, "%d: %s %s %dMhz %s\n", i, | |
1346 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : | |
1347 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," : | |
1348 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," : | |
1349 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "", | |
1350 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" : | |
1351 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" : | |
1352 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" : | |
1353 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" : | |
1354 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" : | |
1355 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "", | |
1356 | pptable->LclkFreq[i], | |
1357 | (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) && | |
1358 | (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ? | |
1359 | "*" : ""); | |
1360 | } | |
1361 | break; | |
1362 | case SMU_OD_SCLK: | |
1363 | if (!smu->od_enabled || !od_table || !od_settings) | |
1364 | return -EOPNOTSUPP; | |
1365 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) | |
1366 | break; | |
1367 | *offset += sysfs_emit_at(buf, *offset, "OD_SCLK:\n0: %uMhz\n1: %uMhz\n", | |
1368 | od_table->GfxclkFmin, od_table->GfxclkFmax); | |
1369 | break; | |
1370 | case SMU_OD_MCLK: | |
1371 | if (!smu->od_enabled || !od_table || !od_settings) | |
1372 | return -EOPNOTSUPP; | |
1373 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) | |
1374 | break; | |
1375 | *offset += sysfs_emit_at(buf, *offset, "OD_MCLK:\n1: %uMHz\n", od_table->UclkFmax); | |
1376 | break; | |
1377 | case SMU_OD_VDDC_CURVE: | |
1378 | if (!smu->od_enabled || !od_table || !od_settings) | |
1379 | return -EOPNOTSUPP; | |
1380 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) | |
1381 | break; | |
1382 | *offset += sysfs_emit_at(buf, *offset, "OD_VDDC_CURVE:\n"); | |
1383 | for (i = 0; i < 3; i++) { | |
1384 | switch (i) { | |
1385 | case 0: | |
1386 | curve_settings = &od_table->GfxclkFreq1; | |
1387 | break; | |
1388 | case 1: | |
1389 | curve_settings = &od_table->GfxclkFreq2; | |
1390 | break; | |
1391 | case 2: | |
1392 | curve_settings = &od_table->GfxclkFreq3; | |
1393 | break; | |
b06b48d7 DP |
1394 | } |
1395 | *offset += sysfs_emit_at(buf, *offset, "%d: %uMHz %umV\n", | |
1396 | i, curve_settings[0], | |
1397 | curve_settings[1] / NAVI10_VOLTAGE_SCALE); | |
1398 | } | |
1399 | break; | |
1400 | case SMU_OD_RANGE: | |
1401 | if (!smu->od_enabled || !od_table || !od_settings) | |
1402 | return -EOPNOTSUPP; | |
1403 | *offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_RANGE"); | |
1404 | ||
1405 | if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) { | |
1406 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMIN, | |
1407 | &min_value, NULL); | |
1408 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMAX, | |
1409 | NULL, &max_value); | |
1410 | *offset += sysfs_emit_at(buf, *offset, "SCLK: %7uMhz %10uMhz\n", | |
1411 | min_value, max_value); | |
1412 | } | |
1413 | ||
1414 | if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) { | |
1415 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX, | |
1416 | &min_value, &max_value); | |
1417 | *offset += sysfs_emit_at(buf, *offset, "MCLK: %7uMhz %10uMhz\n", | |
1418 | min_value, max_value); | |
1419 | } | |
1420 | ||
1421 | if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) { | |
1422 | navi10_od_setting_get_range(od_settings, | |
1423 | SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1, | |
1424 | &min_value, &max_value); | |
1425 | *offset += sysfs_emit_at(buf, *offset, | |
1426 | "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", | |
1427 | min_value, max_value); | |
1428 | navi10_od_setting_get_range(od_settings, | |
1429 | SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1, | |
1430 | &min_value, &max_value); | |
1431 | *offset += sysfs_emit_at(buf, *offset, | |
1432 | "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", | |
1433 | min_value, max_value); | |
1434 | navi10_od_setting_get_range(od_settings, | |
1435 | SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2, | |
1436 | &min_value, &max_value); | |
1437 | *offset += sysfs_emit_at(buf, *offset, | |
1438 | "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", | |
1439 | min_value, max_value); | |
1440 | navi10_od_setting_get_range(od_settings, | |
1441 | SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2, | |
1442 | &min_value, &max_value); | |
1443 | *offset += sysfs_emit_at(buf, *offset, | |
1444 | "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", | |
1445 | min_value, max_value); | |
1446 | navi10_od_setting_get_range(od_settings, | |
1447 | SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3, | |
1448 | &min_value, &max_value); | |
1449 | *offset += sysfs_emit_at(buf, *offset, | |
1450 | "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", | |
1451 | min_value, max_value); | |
1452 | navi10_od_setting_get_range(od_settings, | |
1453 | SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3, | |
1454 | &min_value, &max_value); | |
1455 | *offset += sysfs_emit_at(buf, *offset, | |
1456 | "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", | |
1457 | min_value, max_value); | |
1458 | } | |
1459 | ||
1460 | break; | |
1461 | default: | |
1462 | break; | |
1463 | } | |
1464 | ||
1465 | return 0; | |
1466 | } | |
1467 | ||
b1e7e224 KW |
1468 | static int navi10_print_clk_levels(struct smu_context *smu, |
1469 | enum smu_clk_type clk_type, char *buf) | |
1470 | { | |
7f3353f6 | 1471 | uint16_t *curve_settings; |
33155ce6 | 1472 | int i, levels, size = 0, ret = 0; |
b1e7e224 | 1473 | uint32_t cur_value = 0, value = 0, count = 0; |
c49b1b59 KW |
1474 | uint32_t freq_values[3] = {0}; |
1475 | uint32_t mark_index = 0; | |
7f3353f6 | 1476 | struct smu_table_context *table_context = &smu->smu_table; |
fddbfb1c KF |
1477 | uint32_t gen_speed, lane_width; |
1478 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
1479 | struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; | |
fddbfb1c KF |
1480 | PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; |
1481 | OverDriveTable_t *od_table = | |
1482 | (OverDriveTable_t *)table_context->overdrive_table; | |
1483 | struct smu_11_0_overdrive_table *od_settings = smu->od_settings; | |
ee23a518 | 1484 | uint32_t min_value, max_value; |
b1e7e224 | 1485 | |
ee121f7e LY |
1486 | smu_cmn_get_sysfs_buf(&buf, &size); |
1487 | ||
b1e7e224 KW |
1488 | switch (clk_type) { |
1489 | case SMU_GFXCLK: | |
1490 | case SMU_SCLK: | |
1491 | case SMU_SOCCLK: | |
1492 | case SMU_MCLK: | |
1493 | case SMU_UCLK: | |
1494 | case SMU_FCLK: | |
78842457 DN |
1495 | case SMU_VCLK: |
1496 | case SMU_DCLK: | |
b1e7e224 | 1497 | case SMU_DCEFCLK: |
5e6dc8fe | 1498 | ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value); |
b1e7e224 KW |
1499 | if (ret) |
1500 | return size; | |
c49b1b59 | 1501 | |
d8d3493a | 1502 | ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count); |
b1e7e224 KW |
1503 | if (ret) |
1504 | return size; | |
1505 | ||
c8c19ebf JZ |
1506 | ret = navi10_is_support_fine_grained_dpm(smu, clk_type); |
1507 | if (ret < 0) | |
1508 | return ret; | |
1509 | ||
1510 | if (!ret) { | |
c49b1b59 | 1511 | for (i = 0; i < count; i++) { |
d8d3493a | 1512 | ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value); |
c49b1b59 KW |
1513 | if (ret) |
1514 | return size; | |
1515 | ||
828db598 | 1516 | size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, |
c49b1b59 KW |
1517 | cur_value == value ? "*" : ""); |
1518 | } | |
1519 | } else { | |
d8d3493a | 1520 | ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); |
c49b1b59 KW |
1521 | if (ret) |
1522 | return size; | |
d8d3493a | 1523 | ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); |
b1e7e224 KW |
1524 | if (ret) |
1525 | return size; | |
1526 | ||
c49b1b59 KW |
1527 | freq_values[1] = cur_value; |
1528 | mark_index = cur_value == freq_values[0] ? 0 : | |
1529 | cur_value == freq_values[2] ? 2 : 1; | |
c49b1b59 | 1530 | |
33155ce6 LL |
1531 | levels = 3; |
1532 | if (mark_index != 1) { | |
1533 | levels = 2; | |
1534 | freq_values[1] = freq_values[2]; | |
1535 | } | |
1536 | ||
1537 | for (i = 0; i < levels; i++) { | |
828db598 | 1538 | size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, freq_values[i], |
c49b1b59 KW |
1539 | i == mark_index ? "*" : ""); |
1540 | } | |
b1e7e224 KW |
1541 | } |
1542 | break; | |
fddbfb1c | 1543 | case SMU_PCIE: |
e4c9200d EQ |
1544 | gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu); |
1545 | lane_width = smu_v11_0_get_current_pcie_link_width_level(smu); | |
fddbfb1c | 1546 | for (i = 0; i < NUM_LINK_LEVELS; i++) |
828db598 | 1547 | size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i, |
fddbfb1c KF |
1548 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : |
1549 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," : | |
1550 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," : | |
1551 | (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "", | |
1552 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" : | |
1553 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" : | |
1554 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" : | |
1555 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" : | |
1556 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" : | |
1557 | (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "", | |
1558 | pptable->LclkFreq[i], | |
1559 | (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) && | |
1560 | (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ? | |
1561 | "*" : ""); | |
1562 | break; | |
7f3353f6 MC |
1563 | case SMU_OD_SCLK: |
1564 | if (!smu->od_enabled || !od_table || !od_settings) | |
1565 | break; | |
e33a8cfd | 1566 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) |
7f3353f6 | 1567 | break; |
828db598 DP |
1568 | size += sysfs_emit_at(buf, size, "OD_SCLK:\n"); |
1569 | size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", | |
1570 | od_table->GfxclkFmin, od_table->GfxclkFmax); | |
7f3353f6 MC |
1571 | break; |
1572 | case SMU_OD_MCLK: | |
1573 | if (!smu->od_enabled || !od_table || !od_settings) | |
1574 | break; | |
e33a8cfd | 1575 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) |
7f3353f6 | 1576 | break; |
828db598 DP |
1577 | size += sysfs_emit_at(buf, size, "OD_MCLK:\n"); |
1578 | size += sysfs_emit_at(buf, size, "1: %uMHz\n", od_table->UclkFmax); | |
7f3353f6 MC |
1579 | break; |
1580 | case SMU_OD_VDDC_CURVE: | |
1581 | if (!smu->od_enabled || !od_table || !od_settings) | |
1582 | break; | |
e33a8cfd | 1583 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) |
7f3353f6 | 1584 | break; |
828db598 | 1585 | size += sysfs_emit_at(buf, size, "OD_VDDC_CURVE:\n"); |
7f3353f6 MC |
1586 | for (i = 0; i < 3; i++) { |
1587 | switch (i) { | |
1588 | case 0: | |
1589 | curve_settings = &od_table->GfxclkFreq1; | |
1590 | break; | |
1591 | case 1: | |
1592 | curve_settings = &od_table->GfxclkFreq2; | |
1593 | break; | |
1594 | case 2: | |
1595 | curve_settings = &od_table->GfxclkFreq3; | |
1596 | break; | |
7f3353f6 | 1597 | } |
828db598 DP |
1598 | size += sysfs_emit_at(buf, size, "%d: %uMHz %umV\n", |
1599 | i, curve_settings[0], | |
1600 | curve_settings[1] / NAVI10_VOLTAGE_SCALE); | |
7f3353f6 | 1601 | } |
ee23a518 AD |
1602 | break; |
1603 | case SMU_OD_RANGE: | |
1604 | if (!smu->od_enabled || !od_table || !od_settings) | |
1605 | break; | |
ee121f7e | 1606 | size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); |
ee23a518 | 1607 | |
e33a8cfd | 1608 | if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) { |
ee23a518 AD |
1609 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMIN, |
1610 | &min_value, NULL); | |
1611 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMAX, | |
1612 | NULL, &max_value); | |
828db598 | 1613 | size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", |
ee23a518 AD |
1614 | min_value, max_value); |
1615 | } | |
1616 | ||
e33a8cfd | 1617 | if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) { |
ee23a518 AD |
1618 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX, |
1619 | &min_value, &max_value); | |
828db598 | 1620 | size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n", |
ee23a518 AD |
1621 | min_value, max_value); |
1622 | } | |
1623 | ||
e33a8cfd | 1624 | if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) { |
ee23a518 AD |
1625 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1, |
1626 | &min_value, &max_value); | |
828db598 DP |
1627 | size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", |
1628 | min_value, max_value); | |
ee23a518 AD |
1629 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1, |
1630 | &min_value, &max_value); | |
828db598 DP |
1631 | size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", |
1632 | min_value, max_value); | |
ee23a518 AD |
1633 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2, |
1634 | &min_value, &max_value); | |
828db598 DP |
1635 | size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", |
1636 | min_value, max_value); | |
ee23a518 AD |
1637 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2, |
1638 | &min_value, &max_value); | |
828db598 DP |
1639 | size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", |
1640 | min_value, max_value); | |
ee23a518 AD |
1641 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3, |
1642 | &min_value, &max_value); | |
828db598 DP |
1643 | size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", |
1644 | min_value, max_value); | |
ee23a518 AD |
1645 | navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3, |
1646 | &min_value, &max_value); | |
828db598 DP |
1647 | size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", |
1648 | min_value, max_value); | |
ee23a518 AD |
1649 | } |
1650 | ||
7f3353f6 | 1651 | break; |
b1e7e224 KW |
1652 | default: |
1653 | break; | |
1654 | } | |
1655 | ||
1656 | return size; | |
1657 | } | |
1658 | ||
db439ca2 KW |
1659 | static int navi10_force_clk_levels(struct smu_context *smu, |
1660 | enum smu_clk_type clk_type, uint32_t mask) | |
1661 | { | |
1662 | ||
3ec61983 | 1663 | int ret = 0; |
db439ca2 KW |
1664 | uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0; |
1665 | ||
1666 | soft_min_level = mask ? (ffs(mask) - 1) : 0; | |
1667 | soft_max_level = mask ? (fls(mask) - 1) : 0; | |
1668 | ||
1669 | switch (clk_type) { | |
1670 | case SMU_GFXCLK: | |
c0b9d6d2 | 1671 | case SMU_SCLK: |
db439ca2 KW |
1672 | case SMU_SOCCLK: |
1673 | case SMU_MCLK: | |
1674 | case SMU_UCLK: | |
db439ca2 | 1675 | case SMU_FCLK: |
09ba2e7d | 1676 | /* There is only 2 levels for fine grained DPM */ |
c8c19ebf JZ |
1677 | ret = navi10_is_support_fine_grained_dpm(smu, clk_type); |
1678 | if (ret < 0) | |
1679 | return ret; | |
1680 | ||
1681 | if (ret) { | |
09ba2e7d EQ |
1682 | soft_max_level = (soft_max_level >= 1 ? 1 : 0); |
1683 | soft_min_level = (soft_min_level >= 1 ? 1 : 0); | |
1684 | } | |
1685 | ||
d8d3493a | 1686 | ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); |
db439ca2 | 1687 | if (ret) |
3ec61983 | 1688 | return 0; |
db439ca2 | 1689 | |
d8d3493a | 1690 | ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); |
db439ca2 | 1691 | if (ret) |
3ec61983 | 1692 | return 0; |
db439ca2 | 1693 | |
3d73327b | 1694 | ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); |
db439ca2 | 1695 | if (ret) |
3ec61983 | 1696 | return 0; |
db439ca2 | 1697 | break; |
b117b396 | 1698 | case SMU_DCEFCLK: |
1e3a58df | 1699 | dev_info(smu->adev->dev, "Setting DCEFCLK min/max dpm level is not supported!\n"); |
b117b396 DP |
1700 | break; |
1701 | ||
db439ca2 KW |
1702 | default: |
1703 | break; | |
1704 | } | |
1705 | ||
3ec61983 | 1706 | return 0; |
db439ca2 KW |
1707 | } |
1708 | ||
fa51bfc2 KW |
1709 | static int navi10_populate_umd_state_clk(struct smu_context *smu) |
1710 | { | |
62cc9dd1 EQ |
1711 | struct smu_11_0_dpm_context *dpm_context = |
1712 | smu->smu_dpm.dpm_context; | |
1713 | struct smu_11_0_dpm_table *gfx_table = | |
1714 | &dpm_context->dpm_tables.gfx_table; | |
1715 | struct smu_11_0_dpm_table *mem_table = | |
1716 | &dpm_context->dpm_tables.uclk_table; | |
1717 | struct smu_11_0_dpm_table *soc_table = | |
1718 | &dpm_context->dpm_tables.soc_table; | |
1719 | struct smu_umd_pstate_table *pstate_table = | |
1720 | &smu->pstate_table; | |
1721 | struct amdgpu_device *adev = smu->adev; | |
1722 | uint32_t sclk_freq; | |
1723 | ||
1724 | pstate_table->gfxclk_pstate.min = gfx_table->min; | |
4e8303cf | 1725 | switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { |
ea0d730a | 1726 | case IP_VERSION(11, 0, 0): |
62cc9dd1 EQ |
1727 | switch (adev->pdev->revision) { |
1728 | case 0xf0: /* XTX */ | |
1729 | case 0xc0: | |
1730 | sclk_freq = NAVI10_PEAK_SCLK_XTX; | |
1731 | break; | |
1732 | case 0xf1: /* XT */ | |
1733 | case 0xc1: | |
1734 | sclk_freq = NAVI10_PEAK_SCLK_XT; | |
1735 | break; | |
1736 | default: /* XL */ | |
1737 | sclk_freq = NAVI10_PEAK_SCLK_XL; | |
1738 | break; | |
1739 | } | |
1740 | break; | |
ea0d730a | 1741 | case IP_VERSION(11, 0, 5): |
62cc9dd1 EQ |
1742 | switch (adev->pdev->revision) { |
1743 | case 0xc7: /* XT */ | |
1744 | case 0xf4: | |
1745 | sclk_freq = NAVI14_UMD_PSTATE_PEAK_XT_GFXCLK; | |
1746 | break; | |
1747 | case 0xc1: /* XTM */ | |
1748 | case 0xf2: | |
1749 | sclk_freq = NAVI14_UMD_PSTATE_PEAK_XTM_GFXCLK; | |
1750 | break; | |
1751 | case 0xc3: /* XLM */ | |
1752 | case 0xf3: | |
1753 | sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK; | |
1754 | break; | |
1755 | case 0xc5: /* XTX */ | |
1756 | case 0xf6: | |
1757 | sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK; | |
1758 | break; | |
1759 | default: /* XL */ | |
1760 | sclk_freq = NAVI14_UMD_PSTATE_PEAK_XL_GFXCLK; | |
1761 | break; | |
1762 | } | |
1763 | break; | |
ea0d730a | 1764 | case IP_VERSION(11, 0, 9): |
62cc9dd1 EQ |
1765 | sclk_freq = NAVI12_UMD_PSTATE_PEAK_GFXCLK; |
1766 | break; | |
1767 | default: | |
1768 | sclk_freq = gfx_table->dpm_levels[gfx_table->count - 1].value; | |
1769 | break; | |
1770 | } | |
1771 | pstate_table->gfxclk_pstate.peak = sclk_freq; | |
1772 | ||
1773 | pstate_table->uclk_pstate.min = mem_table->min; | |
1774 | pstate_table->uclk_pstate.peak = mem_table->max; | |
1775 | ||
1776 | pstate_table->socclk_pstate.min = soc_table->min; | |
1777 | pstate_table->socclk_pstate.peak = soc_table->max; | |
1778 | ||
1779 | if (gfx_table->max > NAVI10_UMD_PSTATE_PROFILING_GFXCLK && | |
1780 | mem_table->max > NAVI10_UMD_PSTATE_PROFILING_MEMCLK && | |
1781 | soc_table->max > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) { | |
1782 | pstate_table->gfxclk_pstate.standard = | |
1783 | NAVI10_UMD_PSTATE_PROFILING_GFXCLK; | |
1784 | pstate_table->uclk_pstate.standard = | |
1785 | NAVI10_UMD_PSTATE_PROFILING_MEMCLK; | |
1786 | pstate_table->socclk_pstate.standard = | |
1787 | NAVI10_UMD_PSTATE_PROFILING_SOCCLK; | |
1788 | } else { | |
1789 | pstate_table->gfxclk_pstate.standard = | |
1790 | pstate_table->gfxclk_pstate.min; | |
1791 | pstate_table->uclk_pstate.standard = | |
1792 | pstate_table->uclk_pstate.min; | |
1793 | pstate_table->socclk_pstate.standard = | |
1794 | pstate_table->socclk_pstate.min; | |
1795 | } | |
64974ab2 | 1796 | |
62cc9dd1 | 1797 | return 0; |
fa51bfc2 KW |
1798 | } |
1799 | ||
a43913ea KW |
1800 | static int navi10_get_clock_by_type_with_latency(struct smu_context *smu, |
1801 | enum smu_clk_type clk_type, | |
1802 | struct pp_clock_levels_with_latency *clocks) | |
1803 | { | |
1804 | int ret = 0, i = 0; | |
1805 | uint32_t level_count = 0, freq = 0; | |
1806 | ||
1807 | switch (clk_type) { | |
1808 | case SMU_GFXCLK: | |
1809 | case SMU_DCEFCLK: | |
1810 | case SMU_SOCCLK: | |
e0d5322c AD |
1811 | case SMU_MCLK: |
1812 | case SMU_UCLK: | |
d8d3493a | 1813 | ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &level_count); |
a43913ea KW |
1814 | if (ret) |
1815 | return ret; | |
1816 | ||
1817 | level_count = min(level_count, (uint32_t)MAX_NUM_CLOCKS); | |
1818 | clocks->num_levels = level_count; | |
1819 | ||
1820 | for (i = 0; i < level_count; i++) { | |
d8d3493a | 1821 | ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &freq); |
a43913ea KW |
1822 | if (ret) |
1823 | return ret; | |
1824 | ||
1825 | clocks->data[i].clocks_in_khz = freq * 1000; | |
1826 | clocks->data[i].latency_in_us = 0; | |
1827 | } | |
1828 | break; | |
1829 | default: | |
1830 | break; | |
1831 | } | |
1832 | ||
1833 | return ret; | |
1834 | } | |
1835 | ||
28430544 KW |
1836 | static int navi10_pre_display_config_changed(struct smu_context *smu) |
1837 | { | |
1838 | int ret = 0; | |
1839 | uint32_t max_freq = 0; | |
1840 | ||
66c86828 | 1841 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL); |
28430544 KW |
1842 | if (ret) |
1843 | return ret; | |
1844 | ||
b4bb3aaf | 1845 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { |
e5ef784b | 1846 | ret = smu_v11_0_get_dpm_ultimate_freq(smu, SMU_UCLK, NULL, &max_freq); |
28430544 KW |
1847 | if (ret) |
1848 | return ret; | |
661b94f5 | 1849 | ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, max_freq); |
28430544 KW |
1850 | if (ret) |
1851 | return ret; | |
1852 | } | |
1853 | ||
1854 | return ret; | |
1855 | } | |
1856 | ||
0a6430da KW |
1857 | static int navi10_display_config_changed(struct smu_context *smu) |
1858 | { | |
1859 | int ret = 0; | |
1860 | ||
0a6430da | 1861 | if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && |
7ade3ca9 EQ |
1862 | smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && |
1863 | smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { | |
66c86828 | 1864 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, |
1c58267c MC |
1865 | smu->display_config->num_display, |
1866 | NULL); | |
0a6430da KW |
1867 | if (ret) |
1868 | return ret; | |
1869 | } | |
1870 | ||
1871 | return ret; | |
1872 | } | |
50add63b | 1873 | |
4228b601 KW |
1874 | static bool navi10_is_dpm_running(struct smu_context *smu) |
1875 | { | |
1876 | int ret = 0; | |
3d14a79b KW |
1877 | uint64_t feature_enabled; |
1878 | ||
2d282665 | 1879 | ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); |
3d14a79b KW |
1880 | if (ret) |
1881 | return false; | |
1882 | ||
4228b601 KW |
1883 | return !!(feature_enabled & SMC_DPM_FEATURE); |
1884 | } | |
1885 | ||
d9ca7567 EQ |
1886 | static int navi10_get_fan_speed_rpm(struct smu_context *smu, |
1887 | uint32_t *speed) | |
1888 | { | |
1889 | int ret = 0; | |
1890 | ||
1891 | if (!speed) | |
1892 | return -EINVAL; | |
1893 | ||
1894 | switch (smu_v11_0_get_fan_control_mode(smu)) { | |
1895 | case AMD_FAN_CTRL_AUTO: | |
1896 | ret = navi10_get_smu_metrics_data(smu, | |
1897 | METRICS_CURR_FANSPEED, | |
1898 | speed); | |
1899 | break; | |
1900 | default: | |
1901 | ret = smu_v11_0_get_fan_speed_rpm(smu, | |
1902 | speed); | |
1903 | break; | |
1904 | } | |
1905 | ||
1906 | return ret; | |
1907 | } | |
1908 | ||
3204ff3e AD |
1909 | static int navi10_get_fan_parameters(struct smu_context *smu) |
1910 | { | |
1911 | PPTable_t *pptable = smu->smu_table.driver_pptable; | |
1912 | ||
1913 | smu->fan_max_rpm = pptable->FanMaximumRpm; | |
1914 | ||
1915 | return 0; | |
1916 | } | |
1917 | ||
b45dc20b KW |
1918 | static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf) |
1919 | { | |
1920 | DpmActivityMonitorCoeffInt_t activity_monitor; | |
1921 | uint32_t i, size = 0; | |
c0640304 | 1922 | int16_t workload_type = 0; |
b45dc20b KW |
1923 | static const char *title[] = { |
1924 | "PROFILE_INDEX(NAME)", | |
1925 | "CLOCK_TYPE(NAME)", | |
1926 | "FPS", | |
1927 | "MinFreqType", | |
1928 | "MinActiveFreqType", | |
1929 | "MinActiveFreq", | |
1930 | "BoosterFreqType", | |
1931 | "BoosterFreq", | |
1932 | "PD_Data_limit_c", | |
1933 | "PD_Data_error_coeff", | |
1934 | "PD_Data_error_rate_coeff"}; | |
1935 | int result = 0; | |
1936 | ||
1937 | if (!buf) | |
1938 | return -EINVAL; | |
1939 | ||
828db598 | 1940 | size += sysfs_emit_at(buf, size, "%16s %s %s %s %s %s %s %s %s %s %s\n", |
b45dc20b KW |
1941 | title[0], title[1], title[2], title[3], title[4], title[5], |
1942 | title[6], title[7], title[8], title[9], title[10]); | |
1943 | ||
1944 | for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { | |
1945 | /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ | |
6c339f37 EQ |
1946 | workload_type = smu_cmn_to_asic_specific_index(smu, |
1947 | CMN2ASIC_MAPPING_WORKLOAD, | |
1948 | i); | |
c0640304 EQ |
1949 | if (workload_type < 0) |
1950 | return -EINVAL; | |
1951 | ||
caad2613 | 1952 | result = smu_cmn_update_table(smu, |
0d9d78b5 | 1953 | SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type, |
b45dc20b KW |
1954 | (void *)(&activity_monitor), false); |
1955 | if (result) { | |
d9811cfc | 1956 | dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); |
b45dc20b KW |
1957 | return result; |
1958 | } | |
1959 | ||
828db598 | 1960 | size += sysfs_emit_at(buf, size, "%2d %14s%s:\n", |
3867e370 | 1961 | i, amdgpu_pp_profile_name[i], (i == smu->power_profile_mode) ? "*" : " "); |
b45dc20b | 1962 | |
828db598 | 1963 | size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", |
b45dc20b KW |
1964 | " ", |
1965 | 0, | |
1966 | "GFXCLK", | |
1967 | activity_monitor.Gfx_FPS, | |
1968 | activity_monitor.Gfx_MinFreqStep, | |
1969 | activity_monitor.Gfx_MinActiveFreqType, | |
1970 | activity_monitor.Gfx_MinActiveFreq, | |
1971 | activity_monitor.Gfx_BoosterFreqType, | |
1972 | activity_monitor.Gfx_BoosterFreq, | |
1973 | activity_monitor.Gfx_PD_Data_limit_c, | |
1974 | activity_monitor.Gfx_PD_Data_error_coeff, | |
1975 | activity_monitor.Gfx_PD_Data_error_rate_coeff); | |
1976 | ||
828db598 | 1977 | size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", |
b45dc20b KW |
1978 | " ", |
1979 | 1, | |
1980 | "SOCCLK", | |
1981 | activity_monitor.Soc_FPS, | |
1982 | activity_monitor.Soc_MinFreqStep, | |
1983 | activity_monitor.Soc_MinActiveFreqType, | |
1984 | activity_monitor.Soc_MinActiveFreq, | |
1985 | activity_monitor.Soc_BoosterFreqType, | |
1986 | activity_monitor.Soc_BoosterFreq, | |
1987 | activity_monitor.Soc_PD_Data_limit_c, | |
1988 | activity_monitor.Soc_PD_Data_error_coeff, | |
1989 | activity_monitor.Soc_PD_Data_error_rate_coeff); | |
1990 | ||
828db598 | 1991 | size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", |
b45dc20b KW |
1992 | " ", |
1993 | 2, | |
17d30ed3 | 1994 | "MEMCLK", |
b45dc20b KW |
1995 | activity_monitor.Mem_FPS, |
1996 | activity_monitor.Mem_MinFreqStep, | |
1997 | activity_monitor.Mem_MinActiveFreqType, | |
1998 | activity_monitor.Mem_MinActiveFreq, | |
1999 | activity_monitor.Mem_BoosterFreqType, | |
2000 | activity_monitor.Mem_BoosterFreq, | |
2001 | activity_monitor.Mem_PD_Data_limit_c, | |
2002 | activity_monitor.Mem_PD_Data_error_coeff, | |
2003 | activity_monitor.Mem_PD_Data_error_rate_coeff); | |
2004 | } | |
2005 | ||
2006 | return size; | |
2007 | } | |
2008 | ||
2009 | static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) | |
2010 | { | |
2011 | DpmActivityMonitorCoeffInt_t activity_monitor; | |
2012 | int workload_type, ret = 0; | |
2013 | ||
2014 | smu->power_profile_mode = input[size]; | |
2015 | ||
2016 | if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { | |
d9811cfc | 2017 | dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); |
b45dc20b KW |
2018 | return -EINVAL; |
2019 | } | |
2020 | ||
2021 | if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { | |
adb9de4d MJ |
2022 | if (size != 10) |
2023 | return -EINVAL; | |
b45dc20b | 2024 | |
caad2613 | 2025 | ret = smu_cmn_update_table(smu, |
0d9d78b5 | 2026 | SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, |
b45dc20b KW |
2027 | (void *)(&activity_monitor), false); |
2028 | if (ret) { | |
d9811cfc | 2029 | dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); |
b45dc20b KW |
2030 | return ret; |
2031 | } | |
2032 | ||
2033 | switch (input[0]) { | |
2034 | case 0: /* Gfxclk */ | |
2035 | activity_monitor.Gfx_FPS = input[1]; | |
2036 | activity_monitor.Gfx_MinFreqStep = input[2]; | |
2037 | activity_monitor.Gfx_MinActiveFreqType = input[3]; | |
2038 | activity_monitor.Gfx_MinActiveFreq = input[4]; | |
2039 | activity_monitor.Gfx_BoosterFreqType = input[5]; | |
2040 | activity_monitor.Gfx_BoosterFreq = input[6]; | |
2041 | activity_monitor.Gfx_PD_Data_limit_c = input[7]; | |
2042 | activity_monitor.Gfx_PD_Data_error_coeff = input[8]; | |
2043 | activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9]; | |
2044 | break; | |
2045 | case 1: /* Socclk */ | |
2046 | activity_monitor.Soc_FPS = input[1]; | |
2047 | activity_monitor.Soc_MinFreqStep = input[2]; | |
2048 | activity_monitor.Soc_MinActiveFreqType = input[3]; | |
2049 | activity_monitor.Soc_MinActiveFreq = input[4]; | |
2050 | activity_monitor.Soc_BoosterFreqType = input[5]; | |
2051 | activity_monitor.Soc_BoosterFreq = input[6]; | |
2052 | activity_monitor.Soc_PD_Data_limit_c = input[7]; | |
2053 | activity_monitor.Soc_PD_Data_error_coeff = input[8]; | |
2054 | activity_monitor.Soc_PD_Data_error_rate_coeff = input[9]; | |
2055 | break; | |
17d30ed3 | 2056 | case 2: /* Memclk */ |
b45dc20b KW |
2057 | activity_monitor.Mem_FPS = input[1]; |
2058 | activity_monitor.Mem_MinFreqStep = input[2]; | |
2059 | activity_monitor.Mem_MinActiveFreqType = input[3]; | |
2060 | activity_monitor.Mem_MinActiveFreq = input[4]; | |
2061 | activity_monitor.Mem_BoosterFreqType = input[5]; | |
2062 | activity_monitor.Mem_BoosterFreq = input[6]; | |
2063 | activity_monitor.Mem_PD_Data_limit_c = input[7]; | |
2064 | activity_monitor.Mem_PD_Data_error_coeff = input[8]; | |
2065 | activity_monitor.Mem_PD_Data_error_rate_coeff = input[9]; | |
2066 | break; | |
adb9de4d MJ |
2067 | default: |
2068 | return -EINVAL; | |
b45dc20b KW |
2069 | } |
2070 | ||
caad2613 | 2071 | ret = smu_cmn_update_table(smu, |
0d9d78b5 | 2072 | SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, |
b45dc20b KW |
2073 | (void *)(&activity_monitor), true); |
2074 | if (ret) { | |
d9811cfc | 2075 | dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); |
b45dc20b KW |
2076 | return ret; |
2077 | } | |
2078 | } | |
2079 | ||
2080 | /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ | |
6c339f37 EQ |
2081 | workload_type = smu_cmn_to_asic_specific_index(smu, |
2082 | CMN2ASIC_MAPPING_WORKLOAD, | |
2083 | smu->power_profile_mode); | |
c0640304 EQ |
2084 | if (workload_type < 0) |
2085 | return -EINVAL; | |
ff284eca | 2086 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, |
1c58267c | 2087 | 1 << workload_type, NULL); |
ff284eca JZ |
2088 | if (ret) |
2089 | dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__); | |
b45dc20b KW |
2090 | |
2091 | return ret; | |
2092 | } | |
2093 | ||
19796597 | 2094 | static int navi10_notify_smc_display_config(struct smu_context *smu) |
4f963b01 KW |
2095 | { |
2096 | struct smu_clocks min_clocks = {0}; | |
2097 | struct pp_display_clock_request clock_req; | |
2098 | int ret = 0; | |
2099 | ||
2100 | min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; | |
2101 | min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk; | |
2102 | min_clocks.memory_clock = smu->display_config->min_mem_set_clock; | |
2103 | ||
7ade3ca9 | 2104 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { |
4f963b01 KW |
2105 | clock_req.clock_type = amd_pp_dcef_clock; |
2106 | clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; | |
3697b339 | 2107 | |
6c45e480 | 2108 | ret = smu_v11_0_display_clock_voltage_request(smu, &clock_req); |
3697b339 | 2109 | if (!ret) { |
7ade3ca9 | 2110 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) { |
66c86828 | 2111 | ret = smu_cmn_send_smc_msg_with_param(smu, |
4f963b01 | 2112 | SMU_MSG_SetMinDeepSleepDcefclk, |
1c58267c MC |
2113 | min_clocks.dcef_clock_in_sr/100, |
2114 | NULL); | |
4f963b01 | 2115 | if (ret) { |
d9811cfc | 2116 | dev_err(smu->adev->dev, "Attempt to set divider for DCEFCLK Failed!"); |
4f963b01 KW |
2117 | return ret; |
2118 | } | |
2119 | } | |
2120 | } else { | |
d9811cfc | 2121 | dev_info(smu->adev->dev, "Attempt to set Hard Min for DCEFCLK Failed!"); |
4f963b01 KW |
2122 | } |
2123 | } | |
2124 | ||
b4bb3aaf | 2125 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { |
661b94f5 | 2126 | ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0); |
4f963b01 | 2127 | if (ret) { |
d9811cfc | 2128 | dev_err(smu->adev->dev, "[%s] Set hard min uclk failed!", __func__); |
4f963b01 KW |
2129 | return ret; |
2130 | } | |
2131 | } | |
2132 | ||
2133 | return 0; | |
2134 | } | |
2135 | ||
5bbb0994 | 2136 | static int navi10_set_watermarks_table(struct smu_context *smu, |
7b9c7e30 | 2137 | struct pp_smu_wm_range_sets *clock_ranges) |
5bbb0994 | 2138 | { |
e7a95eea | 2139 | Watermarks_t *table = smu->smu_table.watermarks_table; |
2622e2ae | 2140 | int ret = 0; |
e7a95eea | 2141 | int i; |
5bbb0994 | 2142 | |
e7a95eea | 2143 | if (clock_ranges) { |
7b9c7e30 EQ |
2144 | if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES || |
2145 | clock_ranges->num_writer_wm_sets > NUM_WM_RANGES) | |
e7a95eea | 2146 | return -EINVAL; |
5bbb0994 | 2147 | |
7b9c7e30 EQ |
2148 | for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) { |
2149 | table->WatermarkRow[WM_DCEFCLK][i].MinClock = | |
2150 | clock_ranges->reader_wm_sets[i].min_drain_clk_mhz; | |
2151 | table->WatermarkRow[WM_DCEFCLK][i].MaxClock = | |
2152 | clock_ranges->reader_wm_sets[i].max_drain_clk_mhz; | |
2153 | table->WatermarkRow[WM_DCEFCLK][i].MinUclk = | |
2154 | clock_ranges->reader_wm_sets[i].min_fill_clk_mhz; | |
2155 | table->WatermarkRow[WM_DCEFCLK][i].MaxUclk = | |
2156 | clock_ranges->reader_wm_sets[i].max_fill_clk_mhz; | |
2157 | ||
2158 | table->WatermarkRow[WM_DCEFCLK][i].WmSetting = | |
2159 | clock_ranges->reader_wm_sets[i].wm_inst; | |
e7a95eea | 2160 | } |
5bbb0994 | 2161 | |
7b9c7e30 EQ |
2162 | for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) { |
2163 | table->WatermarkRow[WM_SOCCLK][i].MinClock = | |
2164 | clock_ranges->writer_wm_sets[i].min_fill_clk_mhz; | |
2165 | table->WatermarkRow[WM_SOCCLK][i].MaxClock = | |
2166 | clock_ranges->writer_wm_sets[i].max_fill_clk_mhz; | |
2167 | table->WatermarkRow[WM_SOCCLK][i].MinUclk = | |
2168 | clock_ranges->writer_wm_sets[i].min_drain_clk_mhz; | |
2169 | table->WatermarkRow[WM_SOCCLK][i].MaxUclk = | |
2170 | clock_ranges->writer_wm_sets[i].max_drain_clk_mhz; | |
2171 | ||
2172 | table->WatermarkRow[WM_SOCCLK][i].WmSetting = | |
2173 | clock_ranges->writer_wm_sets[i].wm_inst; | |
e7a95eea | 2174 | } |
5bbb0994 | 2175 | |
e7a95eea | 2176 | smu->watermarks_bitmap |= WATERMARKS_EXIST; |
5bbb0994 KW |
2177 | } |
2178 | ||
2622e2ae | 2179 | /* pass data to smu controller */ |
e7a95eea EQ |
2180 | if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && |
2181 | !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { | |
caad2613 | 2182 | ret = smu_cmn_write_watermarks_table(smu); |
2622e2ae | 2183 | if (ret) { |
d9811cfc | 2184 | dev_err(smu->adev->dev, "Failed to update WMTABLE!"); |
2622e2ae HW |
2185 | return ret; |
2186 | } | |
2187 | smu->watermarks_bitmap |= WATERMARKS_LOADED; | |
2188 | } | |
2189 | ||
5bbb0994 KW |
2190 | return 0; |
2191 | } | |
2192 | ||
9c62f993 KW |
2193 | static int navi10_read_sensor(struct smu_context *smu, |
2194 | enum amd_pp_sensors sensor, | |
2195 | void *data, uint32_t *size) | |
2196 | { | |
2197 | int ret = 0; | |
2198 | struct smu_table_context *table_context = &smu->smu_table; | |
2199 | PPTable_t *pptable = table_context->driver_pptable; | |
2200 | ||
1e3a58df | 2201 | if (!data || !size) |
9b4e63f4 KF |
2202 | return -EINVAL; |
2203 | ||
9c62f993 KW |
2204 | switch (sensor) { |
2205 | case AMDGPU_PP_SENSOR_MAX_FAN_RPM: | |
2206 | *(uint32_t *)data = pptable->FanMaximumRpm; | |
2207 | *size = 4; | |
2208 | break; | |
7f963d9f | 2209 | case AMDGPU_PP_SENSOR_MEM_LOAD: |
7d6c13ef | 2210 | ret = navi1x_get_smu_metrics_data(smu, |
fae3a572 AD |
2211 | METRICS_AVERAGE_MEMACTIVITY, |
2212 | (uint32_t *)data); | |
2213 | *size = 4; | |
2214 | break; | |
d573bb21 | 2215 | case AMDGPU_PP_SENSOR_GPU_LOAD: |
7d6c13ef | 2216 | ret = navi1x_get_smu_metrics_data(smu, |
fae3a572 AD |
2217 | METRICS_AVERAGE_GFXACTIVITY, |
2218 | (uint32_t *)data); | |
d573bb21 KW |
2219 | *size = 4; |
2220 | break; | |
9366c2e8 | 2221 | case AMDGPU_PP_SENSOR_GPU_AVG_POWER: |
7d6c13ef | 2222 | ret = navi1x_get_smu_metrics_data(smu, |
fae3a572 AD |
2223 | METRICS_AVERAGE_SOCKETPOWER, |
2224 | (uint32_t *)data); | |
564c4c7f KW |
2225 | *size = 4; |
2226 | break; | |
e5aa29ce | 2227 | case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: |
7d6c13ef | 2228 | ret = navi1x_get_smu_metrics_data(smu, |
fae3a572 AD |
2229 | METRICS_TEMPERATURE_HOTSPOT, |
2230 | (uint32_t *)data); | |
2231 | *size = 4; | |
2232 | break; | |
e5aa29ce | 2233 | case AMDGPU_PP_SENSOR_EDGE_TEMP: |
7d6c13ef | 2234 | ret = navi1x_get_smu_metrics_data(smu, |
fae3a572 AD |
2235 | METRICS_TEMPERATURE_EDGE, |
2236 | (uint32_t *)data); | |
2237 | *size = 4; | |
2238 | break; | |
e5aa29ce | 2239 | case AMDGPU_PP_SENSOR_MEM_TEMP: |
7d6c13ef | 2240 | ret = navi1x_get_smu_metrics_data(smu, |
fae3a572 AD |
2241 | METRICS_TEMPERATURE_MEM, |
2242 | (uint32_t *)data); | |
e5aa29ce KW |
2243 | *size = 4; |
2244 | break; | |
e0f9e936 EQ |
2245 | case AMDGPU_PP_SENSOR_GFX_MCLK: |
2246 | ret = navi10_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data); | |
2247 | *(uint32_t *)data *= 100; | |
2248 | *size = 4; | |
2249 | break; | |
2250 | case AMDGPU_PP_SENSOR_GFX_SCLK: | |
7d6c13ef | 2251 | ret = navi1x_get_smu_metrics_data(smu, METRICS_AVERAGE_GFXCLK, (uint32_t *)data); |
e0f9e936 EQ |
2252 | *(uint32_t *)data *= 100; |
2253 | *size = 4; | |
2254 | break; | |
b2febc99 EQ |
2255 | case AMDGPU_PP_SENSOR_VDDGFX: |
2256 | ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data); | |
2257 | *size = 4; | |
2258 | break; | |
47f1724d | 2259 | case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: |
9c62f993 | 2260 | default: |
b2febc99 EQ |
2261 | ret = -EOPNOTSUPP; |
2262 | break; | |
9c62f993 KW |
2263 | } |
2264 | ||
2265 | return ret; | |
2266 | } | |
2267 | ||
f4b3295f | 2268 | static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t *clocks_in_khz, uint32_t *num_states) |
2269 | { | |
2270 | uint32_t num_discrete_levels = 0; | |
2271 | uint16_t *dpm_levels = NULL; | |
2272 | uint16_t i = 0; | |
2273 | struct smu_table_context *table_context = &smu->smu_table; | |
2274 | PPTable_t *driver_ppt = NULL; | |
2275 | ||
2276 | if (!clocks_in_khz || !num_states || !table_context->driver_pptable) | |
2277 | return -EINVAL; | |
2278 | ||
2279 | driver_ppt = table_context->driver_pptable; | |
2280 | num_discrete_levels = driver_ppt->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels; | |
2281 | dpm_levels = driver_ppt->FreqTableUclk; | |
2282 | ||
2283 | if (num_discrete_levels == 0 || dpm_levels == NULL) | |
2284 | return -EINVAL; | |
2285 | ||
2286 | *num_states = num_discrete_levels; | |
2287 | for (i = 0; i < num_discrete_levels; i++) { | |
2288 | /* convert to khz */ | |
2289 | *clocks_in_khz = (*dpm_levels) * 1000; | |
2290 | clocks_in_khz++; | |
2291 | dpm_levels++; | |
2292 | } | |
2293 | ||
2294 | return 0; | |
2295 | } | |
2296 | ||
7a816371 KW |
2297 | static int navi10_get_thermal_temperature_range(struct smu_context *smu, |
2298 | struct smu_temperature_range *range) | |
2299 | { | |
e02e4d51 EQ |
2300 | struct smu_table_context *table_context = &smu->smu_table; |
2301 | struct smu_11_0_powerplay_table *powerplay_table = | |
2302 | table_context->power_play_table; | |
cbf3f132 | 2303 | PPTable_t *pptable = smu->smu_table.driver_pptable; |
7a816371 | 2304 | |
cbf3f132 | 2305 | if (!range) |
7a816371 KW |
2306 | return -EINVAL; |
2307 | ||
0540eced EQ |
2308 | memcpy(range, &smu11_thermal_policy[0], sizeof(struct smu_temperature_range)); |
2309 | ||
cbf3f132 EQ |
2310 | range->max = pptable->TedgeLimit * |
2311 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
2312 | range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) * | |
2313 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
2314 | range->hotspot_crit_max = pptable->ThotspotLimit * | |
2315 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
2316 | range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) * | |
2317 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
2318 | range->mem_crit_max = pptable->TmemLimit * | |
2319 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
2320 | range->mem_emergency_max = (pptable->TmemLimit + CTF_OFFSET_MEM)* | |
a056ddce | 2321 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; |
e02e4d51 | 2322 | range->software_shutdown_temp = powerplay_table->software_shutdown_temp; |
7a816371 KW |
2323 | |
2324 | return 0; | |
2325 | } | |
2326 | ||
6e92e156 KF |
2327 | static int navi10_display_disable_memory_clock_switch(struct smu_context *smu, |
2328 | bool disable_memory_clock_switch) | |
2329 | { | |
2330 | int ret = 0; | |
2331 | struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks = | |
2332 | (struct smu_11_0_max_sustainable_clocks *) | |
2333 | smu->smu_table.max_sustainable_clocks; | |
2334 | uint32_t min_memory_clock = smu->hard_min_uclk_req_from_dal; | |
2335 | uint32_t max_memory_clock = max_sustainable_clocks->uclock; | |
2336 | ||
1e3a58df | 2337 | if (smu->disable_uclk_switch == disable_memory_clock_switch) |
6e92e156 KF |
2338 | return 0; |
2339 | ||
1e3a58df | 2340 | if (disable_memory_clock_switch) |
661b94f5 | 2341 | ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, max_memory_clock, 0); |
6e92e156 | 2342 | else |
661b94f5 | 2343 | ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_memory_clock, 0); |
6e92e156 | 2344 | |
1e3a58df | 2345 | if (!ret) |
6e92e156 KF |
2346 | smu->disable_uclk_switch = disable_memory_clock_switch; |
2347 | ||
2348 | return ret; | |
2349 | } | |
2350 | ||
488f211d | 2351 | static int navi10_get_power_limit(struct smu_context *smu, |
19589468 MJ |
2352 | uint32_t *current_power_limit, |
2353 | uint32_t *default_power_limit, | |
2354 | uint32_t *max_power_limit, | |
2355 | uint32_t *min_power_limit) | |
b4af964e | 2356 | { |
1e239fdd EQ |
2357 | struct smu_11_0_powerplay_table *powerplay_table = |
2358 | (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table; | |
549db526 | 2359 | struct smu_11_0_overdrive_table *od_settings = smu->od_settings; |
b4af964e | 2360 | PPTable_t *pptable = smu->smu_table.driver_pptable; |
08ae9ef8 | 2361 | uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; |
1e239fdd EQ |
2362 | |
2363 | if (smu_v11_0_get_current_power_limit(smu, &power_limit)) { | |
2364 | /* the last hope to figure out the ppt limit */ | |
2365 | if (!pptable) { | |
2366 | dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); | |
2367 | return -EINVAL; | |
b4af964e | 2368 | } |
1e239fdd EQ |
2369 | power_limit = |
2370 | pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; | |
2371 | } | |
b4af964e | 2372 | |
488f211d EQ |
2373 | if (current_power_limit) |
2374 | *current_power_limit = power_limit; | |
2375 | if (default_power_limit) | |
2376 | *default_power_limit = power_limit; | |
1e239fdd | 2377 | |
08ae9ef8 MJ |
2378 | if (powerplay_table) { |
2379 | if (smu->od_enabled && | |
e1771825 | 2380 | navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) { |
08ae9ef8 | 2381 | od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]); |
e1771825 MJ |
2382 | od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]); |
2383 | } else if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) { | |
08ae9ef8 | 2384 | od_percent_upper = 0; |
e1771825 MJ |
2385 | od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]); |
2386 | } | |
08ae9ef8 | 2387 | } |
1e239fdd | 2388 | |
19589468 MJ |
2389 | dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n", |
2390 | od_percent_upper, od_percent_lower, power_limit); | |
488f211d | 2391 | |
19589468 MJ |
2392 | if (max_power_limit) { |
2393 | *max_power_limit = power_limit * (100 + od_percent_upper); | |
2394 | *max_power_limit /= 100; | |
2395 | } | |
488f211d | 2396 | |
19589468 MJ |
2397 | if (min_power_limit) { |
2398 | *min_power_limit = power_limit * (100 - od_percent_lower); | |
2399 | *min_power_limit /= 100; | |
b4af964e EQ |
2400 | } |
2401 | ||
b4af964e EQ |
2402 | return 0; |
2403 | } | |
2404 | ||
372120f0 | 2405 | static int navi10_update_pcie_parameters(struct smu_context *smu, |
7752ccf8 ML |
2406 | uint8_t pcie_gen_cap, |
2407 | uint8_t pcie_width_cap) | |
372120f0 | 2408 | { |
0b590970 | 2409 | struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; |
372120f0 | 2410 | PPTable_t *pptable = smu->smu_table.driver_pptable; |
372120f0 | 2411 | uint32_t smu_pcie_arg; |
0b590970 | 2412 | int ret, i; |
372120f0 | 2413 | |
0b590970 EQ |
2414 | /* lclk dpm table setup */ |
2415 | for (i = 0; i < MAX_PCIE_CONF; i++) { | |
2416 | dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pptable->PcieGenSpeed[i]; | |
2417 | dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pptable->PcieLaneCount[i]; | |
2418 | } | |
fddbfb1c | 2419 | |
372120f0 KF |
2420 | for (i = 0; i < NUM_LINK_LEVELS; i++) { |
2421 | smu_pcie_arg = (i << 16) | | |
2422 | ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) : | |
2423 | (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ? | |
2424 | pptable->PcieLaneCount[i] : pcie_width_cap); | |
66c86828 | 2425 | ret = smu_cmn_send_smc_msg_with_param(smu, |
372120f0 | 2426 | SMU_MSG_OverridePcieParameters, |
1c58267c MC |
2427 | smu_pcie_arg, |
2428 | NULL); | |
fddbfb1c KF |
2429 | |
2430 | if (ret) | |
2431 | return ret; | |
2432 | ||
2433 | if (pptable->PcieGenSpeed[i] > pcie_gen_cap) | |
2434 | dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pcie_gen_cap; | |
2435 | if (pptable->PcieLaneCount[i] > pcie_width_cap) | |
2436 | dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pcie_width_cap; | |
372120f0 | 2437 | } |
fddbfb1c KF |
2438 | |
2439 | return 0; | |
21677d08 MC |
2440 | } |
2441 | ||
d9811cfc EQ |
2442 | static inline void navi10_dump_od_table(struct smu_context *smu, |
2443 | OverDriveTable_t *od_table) | |
2444 | { | |
2445 | dev_dbg(smu->adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->GfxclkFmin, od_table->GfxclkFmax); | |
2446 | dev_dbg(smu->adev->dev, "OD: Gfx1: (%d, %d)\n", od_table->GfxclkFreq1, od_table->GfxclkVolt1); | |
2447 | dev_dbg(smu->adev->dev, "OD: Gfx2: (%d, %d)\n", od_table->GfxclkFreq2, od_table->GfxclkVolt2); | |
2448 | dev_dbg(smu->adev->dev, "OD: Gfx3: (%d, %d)\n", od_table->GfxclkFreq3, od_table->GfxclkVolt3); | |
2449 | dev_dbg(smu->adev->dev, "OD: UclkFmax: %d\n", od_table->UclkFmax); | |
2450 | dev_dbg(smu->adev->dev, "OD: OverDrivePct: %d\n", od_table->OverDrivePct); | |
21677d08 MC |
2451 | } |
2452 | ||
d9811cfc EQ |
2453 | static int navi10_od_setting_check_range(struct smu_context *smu, |
2454 | struct smu_11_0_overdrive_table *od_table, | |
2455 | enum SMU_11_0_ODSETTING_ID setting, | |
2456 | uint32_t value) | |
21677d08 MC |
2457 | { |
2458 | if (value < od_table->min[setting]) { | |
d9811cfc | 2459 | dev_warn(smu->adev->dev, "OD setting (%d, %d) is less than the minimum allowed (%d)\n", setting, value, od_table->min[setting]); |
21677d08 MC |
2460 | return -EINVAL; |
2461 | } | |
2462 | if (value > od_table->max[setting]) { | |
d9811cfc | 2463 | dev_warn(smu->adev->dev, "OD setting (%d, %d) is greater than the maximum allowed (%d)\n", setting, value, od_table->max[setting]); |
21677d08 MC |
2464 | return -EINVAL; |
2465 | } | |
2466 | return 0; | |
2467 | } | |
2468 | ||
0531aa6e AD |
2469 | static int navi10_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu, |
2470 | uint16_t *voltage, | |
2471 | uint32_t freq) | |
2472 | { | |
2473 | uint32_t param = (freq & 0xFFFF) | (PPCLK_GFXCLK << 16); | |
2474 | uint32_t value = 0; | |
2475 | int ret; | |
2476 | ||
66c86828 | 2477 | ret = smu_cmn_send_smc_msg_with_param(smu, |
0531aa6e | 2478 | SMU_MSG_GetVoltageByDpm, |
1c58267c MC |
2479 | param, |
2480 | &value); | |
0531aa6e | 2481 | if (ret) { |
d9811cfc | 2482 | dev_err(smu->adev->dev, "[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!"); |
0531aa6e AD |
2483 | return ret; |
2484 | } | |
2485 | ||
0531aa6e AD |
2486 | *voltage = (uint16_t)value; |
2487 | ||
2488 | return 0; | |
2489 | } | |
2490 | ||
13d75ead EQ |
2491 | static int navi10_baco_enter(struct smu_context *smu) |
2492 | { | |
2493 | struct amdgpu_device *adev = smu->adev; | |
2494 | ||
be68d44b EQ |
2495 | /* |
2496 | * This aims the case below: | |
2497 | * amdgpu driver loaded -> runpm suspend kicked -> sound driver loaded | |
2498 | * | |
2499 | * For NAVI10 and later ASICs, we rely on PMFW to handle the runpm. To | |
2500 | * make that possible, PMFW needs to acknowledge the dstate transition | |
2501 | * process for both gfx(function 0) and audio(function 1) function of | |
2502 | * the ASIC. | |
2503 | * | |
2504 | * The PCI device's initial runpm status is RUNPM_SUSPENDED. So as the | |
2505 | * device representing the audio function of the ASIC. And that means | |
2506 | * even if the sound driver(snd_hda_intel) was not loaded yet, it's still | |
2507 | * possible runpm suspend kicked on the ASIC. However without the dstate | |
2508 | * transition notification from audio function, pmfw cannot handle the | |
2509 | * BACO in/exit correctly. And that will cause driver hang on runpm | |
2510 | * resuming. | |
2511 | * | |
2512 | * To address this, we revert to legacy message way(driver masters the | |
2513 | * timing for BACO in/exit) on sound driver missing. | |
2514 | */ | |
2515 | if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) | |
13d75ead EQ |
2516 | return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO); |
2517 | else | |
2518 | return smu_v11_0_baco_enter(smu); | |
2519 | } | |
2520 | ||
2521 | static int navi10_baco_exit(struct smu_context *smu) | |
2522 | { | |
2523 | struct amdgpu_device *adev = smu->adev; | |
2524 | ||
be68d44b | 2525 | if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { |
13d75ead EQ |
2526 | /* Wait for PMFW handling for the Dstate change */ |
2527 | msleep(10); | |
2528 | return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); | |
2529 | } else { | |
2530 | return smu_v11_0_baco_exit(smu); | |
2531 | } | |
2532 | } | |
2533 | ||
792f80d1 EQ |
2534 | static int navi10_set_default_od_settings(struct smu_context *smu) |
2535 | { | |
2536 | OverDriveTable_t *od_table = | |
2537 | (OverDriveTable_t *)smu->smu_table.overdrive_table; | |
2538 | OverDriveTable_t *boot_od_table = | |
2539 | (OverDriveTable_t *)smu->smu_table.boot_overdrive_table; | |
92cf0508 EQ |
2540 | OverDriveTable_t *user_od_table = |
2541 | (OverDriveTable_t *)smu->smu_table.user_overdrive_table; | |
21677d08 MC |
2542 | int ret = 0; |
2543 | ||
92cf0508 EQ |
2544 | /* |
2545 | * For S3/S4/Runpm resume, no need to setup those overdrive tables again as | |
2546 | * - either they already have the default OD settings got during cold bootup | |
2547 | * - or they have some user customized OD settings which cannot be overwritten | |
2548 | */ | |
2549 | if (smu->adev->in_suspend) | |
2550 | return 0; | |
2551 | ||
2552 | ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)boot_od_table, false); | |
792f80d1 | 2553 | if (ret) { |
d9811cfc | 2554 | dev_err(smu->adev->dev, "Failed to get overdrive table!\n"); |
21677d08 | 2555 | return ret; |
792f80d1 | 2556 | } |
21677d08 | 2557 | |
92cf0508 | 2558 | if (!boot_od_table->GfxclkVolt1) { |
792f80d1 | 2559 | ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, |
92cf0508 EQ |
2560 | &boot_od_table->GfxclkVolt1, |
2561 | boot_od_table->GfxclkFreq1); | |
792f80d1 EQ |
2562 | if (ret) |
2563 | return ret; | |
2564 | } | |
21677d08 | 2565 | |
92cf0508 | 2566 | if (!boot_od_table->GfxclkVolt2) { |
792f80d1 | 2567 | ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, |
92cf0508 EQ |
2568 | &boot_od_table->GfxclkVolt2, |
2569 | boot_od_table->GfxclkFreq2); | |
792f80d1 EQ |
2570 | if (ret) |
2571 | return ret; | |
21677d08 MC |
2572 | } |
2573 | ||
92cf0508 | 2574 | if (!boot_od_table->GfxclkVolt3) { |
792f80d1 | 2575 | ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, |
92cf0508 EQ |
2576 | &boot_od_table->GfxclkVolt3, |
2577 | boot_od_table->GfxclkFreq3); | |
792f80d1 EQ |
2578 | if (ret) |
2579 | return ret; | |
21677d08 | 2580 | } |
372120f0 | 2581 | |
92cf0508 | 2582 | navi10_dump_od_table(smu, boot_od_table); |
792f80d1 | 2583 | |
92cf0508 EQ |
2584 | memcpy(od_table, boot_od_table, sizeof(OverDriveTable_t)); |
2585 | memcpy(user_od_table, boot_od_table, sizeof(OverDriveTable_t)); | |
792f80d1 EQ |
2586 | |
2587 | return 0; | |
372120f0 KF |
2588 | } |
2589 | ||
1e3a58df RS |
2590 | static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size) |
2591 | { | |
21677d08 MC |
2592 | int i; |
2593 | int ret = 0; | |
2594 | struct smu_table_context *table_context = &smu->smu_table; | |
2595 | OverDriveTable_t *od_table; | |
2596 | struct smu_11_0_overdrive_table *od_settings; | |
66107132 MC |
2597 | enum SMU_11_0_ODSETTING_ID freq_setting, voltage_setting; |
2598 | uint16_t *freq_ptr, *voltage_ptr; | |
21677d08 MC |
2599 | od_table = (OverDriveTable_t *)table_context->overdrive_table; |
2600 | ||
2601 | if (!smu->od_enabled) { | |
d9811cfc | 2602 | dev_warn(smu->adev->dev, "OverDrive is not enabled!\n"); |
21677d08 MC |
2603 | return -EINVAL; |
2604 | } | |
2605 | ||
2606 | if (!smu->od_settings) { | |
d9811cfc | 2607 | dev_err(smu->adev->dev, "OD board limits are not set!\n"); |
21677d08 MC |
2608 | return -ENOENT; |
2609 | } | |
2610 | ||
2611 | od_settings = smu->od_settings; | |
2612 | ||
2613 | switch (type) { | |
2614 | case PP_OD_EDIT_SCLK_VDDC_TABLE: | |
e33a8cfd | 2615 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) { |
d9811cfc | 2616 | dev_warn(smu->adev->dev, "GFXCLK_LIMITS not supported!\n"); |
21677d08 MC |
2617 | return -ENOTSUPP; |
2618 | } | |
2619 | if (!table_context->overdrive_table) { | |
d9811cfc | 2620 | dev_err(smu->adev->dev, "Overdrive is not initialized\n"); |
21677d08 MC |
2621 | return -EINVAL; |
2622 | } | |
2623 | for (i = 0; i < size; i += 2) { | |
2624 | if (i + 2 > size) { | |
d9811cfc | 2625 | dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size); |
21677d08 MC |
2626 | return -EINVAL; |
2627 | } | |
2628 | switch (input[i]) { | |
2629 | case 0: | |
2630 | freq_setting = SMU_11_0_ODSETTING_GFXCLKFMIN; | |
2631 | freq_ptr = &od_table->GfxclkFmin; | |
2632 | if (input[i + 1] > od_table->GfxclkFmax) { | |
d9811cfc | 2633 | dev_info(smu->adev->dev, "GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n", |
21677d08 MC |
2634 | input[i + 1], |
2635 | od_table->GfxclkFmin); | |
2636 | return -EINVAL; | |
2637 | } | |
2638 | break; | |
2639 | case 1: | |
2640 | freq_setting = SMU_11_0_ODSETTING_GFXCLKFMAX; | |
2641 | freq_ptr = &od_table->GfxclkFmax; | |
2642 | if (input[i + 1] < od_table->GfxclkFmin) { | |
d9811cfc | 2643 | dev_info(smu->adev->dev, "GfxclkFmax (%ld) must be >= GfxclkFmin (%u)!\n", |
21677d08 MC |
2644 | input[i + 1], |
2645 | od_table->GfxclkFmax); | |
2646 | return -EINVAL; | |
2647 | } | |
2648 | break; | |
2649 | default: | |
d9811cfc EQ |
2650 | dev_info(smu->adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]); |
2651 | dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n"); | |
21677d08 MC |
2652 | return -EINVAL; |
2653 | } | |
d9811cfc | 2654 | ret = navi10_od_setting_check_range(smu, od_settings, freq_setting, input[i + 1]); |
21677d08 MC |
2655 | if (ret) |
2656 | return ret; | |
2657 | *freq_ptr = input[i + 1]; | |
2658 | } | |
2659 | break; | |
2660 | case PP_OD_EDIT_MCLK_VDDC_TABLE: | |
e33a8cfd | 2661 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) { |
d9811cfc | 2662 | dev_warn(smu->adev->dev, "UCLK_MAX not supported!\n"); |
21677d08 MC |
2663 | return -ENOTSUPP; |
2664 | } | |
2665 | if (size < 2) { | |
d9811cfc | 2666 | dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size); |
21677d08 MC |
2667 | return -EINVAL; |
2668 | } | |
2669 | if (input[0] != 1) { | |
d9811cfc EQ |
2670 | dev_info(smu->adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[0]); |
2671 | dev_info(smu->adev->dev, "Supported indices: [1:max]\n"); | |
21677d08 MC |
2672 | return -EINVAL; |
2673 | } | |
d9811cfc | 2674 | ret = navi10_od_setting_check_range(smu, od_settings, SMU_11_0_ODSETTING_UCLKFMAX, input[1]); |
21677d08 MC |
2675 | if (ret) |
2676 | return ret; | |
2677 | od_table->UclkFmax = input[1]; | |
2678 | break; | |
93c5f1f6 MC |
2679 | case PP_OD_RESTORE_DEFAULT_TABLE: |
2680 | if (!(table_context->overdrive_table && table_context->boot_overdrive_table)) { | |
d9811cfc | 2681 | dev_err(smu->adev->dev, "Overdrive table was not initialized!\n"); |
93c5f1f6 MC |
2682 | return -EINVAL; |
2683 | } | |
2684 | memcpy(table_context->overdrive_table, table_context->boot_overdrive_table, sizeof(OverDriveTable_t)); | |
2685 | break; | |
21677d08 | 2686 | case PP_OD_COMMIT_DPM_TABLE: |
92cf0508 EQ |
2687 | if (memcmp(od_table, table_context->user_overdrive_table, sizeof(OverDriveTable_t))) { |
2688 | navi10_dump_od_table(smu, od_table); | |
2689 | ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true); | |
2690 | if (ret) { | |
2691 | dev_err(smu->adev->dev, "Failed to import overdrive table!\n"); | |
2692 | return ret; | |
2693 | } | |
2694 | memcpy(table_context->user_overdrive_table, od_table, sizeof(OverDriveTable_t)); | |
2695 | smu->user_dpm_profile.user_od = true; | |
2696 | ||
2697 | if (!memcmp(table_context->user_overdrive_table, | |
2698 | table_context->boot_overdrive_table, | |
2699 | sizeof(OverDriveTable_t))) | |
2700 | smu->user_dpm_profile.user_od = false; | |
21677d08 | 2701 | } |
21677d08 MC |
2702 | break; |
2703 | case PP_OD_EDIT_VDDC_CURVE: | |
e33a8cfd | 2704 | if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) { |
d9811cfc | 2705 | dev_warn(smu->adev->dev, "GFXCLK_CURVE not supported!\n"); |
66107132 MC |
2706 | return -ENOTSUPP; |
2707 | } | |
2708 | if (size < 3) { | |
d9811cfc | 2709 | dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size); |
66107132 MC |
2710 | return -EINVAL; |
2711 | } | |
2712 | if (!od_table) { | |
d9811cfc | 2713 | dev_info(smu->adev->dev, "Overdrive is not initialized\n"); |
66107132 MC |
2714 | return -EINVAL; |
2715 | } | |
2716 | ||
2717 | switch (input[0]) { | |
2718 | case 0: | |
2719 | freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1; | |
2720 | voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1; | |
2721 | freq_ptr = &od_table->GfxclkFreq1; | |
2722 | voltage_ptr = &od_table->GfxclkVolt1; | |
2723 | break; | |
2724 | case 1: | |
2725 | freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2; | |
2726 | voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2; | |
2727 | freq_ptr = &od_table->GfxclkFreq2; | |
2728 | voltage_ptr = &od_table->GfxclkVolt2; | |
2729 | break; | |
2730 | case 2: | |
2731 | freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3; | |
2732 | voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3; | |
2733 | freq_ptr = &od_table->GfxclkFreq3; | |
2734 | voltage_ptr = &od_table->GfxclkVolt3; | |
2735 | break; | |
2736 | default: | |
d9811cfc EQ |
2737 | dev_info(smu->adev->dev, "Invalid VDDC_CURVE index: %ld\n", input[0]); |
2738 | dev_info(smu->adev->dev, "Supported indices: [0, 1, 2]\n"); | |
66107132 MC |
2739 | return -EINVAL; |
2740 | } | |
d9811cfc | 2741 | ret = navi10_od_setting_check_range(smu, od_settings, freq_setting, input[1]); |
66107132 MC |
2742 | if (ret) |
2743 | return ret; | |
2744 | // Allow setting zero to disable the OverDrive VDDC curve | |
2745 | if (input[2] != 0) { | |
d9811cfc | 2746 | ret = navi10_od_setting_check_range(smu, od_settings, voltage_setting, input[2]); |
66107132 MC |
2747 | if (ret) |
2748 | return ret; | |
2749 | *freq_ptr = input[1]; | |
2750 | *voltage_ptr = ((uint16_t)input[2]) * NAVI10_VOLTAGE_SCALE; | |
d9811cfc | 2751 | dev_dbg(smu->adev->dev, "OD: set curve %ld: (%d, %d)\n", input[0], *freq_ptr, *voltage_ptr); |
66107132 MC |
2752 | } else { |
2753 | // If setting 0, disable all voltage curve settings | |
2754 | od_table->GfxclkVolt1 = 0; | |
2755 | od_table->GfxclkVolt2 = 0; | |
2756 | od_table->GfxclkVolt3 = 0; | |
2757 | } | |
d9811cfc | 2758 | navi10_dump_od_table(smu, od_table); |
66107132 | 2759 | break; |
21677d08 MC |
2760 | default: |
2761 | return -ENOSYS; | |
2762 | } | |
2763 | return ret; | |
2764 | } | |
372120f0 | 2765 | |
0eeaa899 EQ |
2766 | static int navi10_run_btc(struct smu_context *smu) |
2767 | { | |
2768 | int ret = 0; | |
2769 | ||
66c86828 | 2770 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunBtc, NULL); |
0eeaa899 | 2771 | if (ret) |
d9811cfc | 2772 | dev_err(smu->adev->dev, "RunBtc failed!\n"); |
0eeaa899 EQ |
2773 | |
2774 | return ret; | |
2775 | } | |
2776 | ||
12f04120 | 2777 | static bool navi10_need_umc_cdr_workaround(struct smu_context *smu) |
31157341 | 2778 | { |
eb5f69e7 EQ |
2779 | struct amdgpu_device *adev = smu->adev; |
2780 | ||
2781 | if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) | |
31157341 EQ |
2782 | return false; |
2783 | ||
4e8303cf LL |
2784 | if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0) || |
2785 | amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 5)) | |
31157341 | 2786 | return true; |
eb5f69e7 EQ |
2787 | |
2788 | return false; | |
31157341 EQ |
2789 | } |
2790 | ||
3646c00e | 2791 | static int navi10_umc_hybrid_cdr_workaround(struct smu_context *smu) |
1cf8c930 EQ |
2792 | { |
2793 | uint32_t uclk_count, uclk_min, uclk_max; | |
1cf8c930 EQ |
2794 | int ret = 0; |
2795 | ||
3646c00e EQ |
2796 | /* This workaround can be applied only with uclk dpm enabled */ |
2797 | if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) | |
1cf8c930 EQ |
2798 | return 0; |
2799 | ||
d8d3493a | 2800 | ret = smu_v11_0_get_dpm_level_count(smu, SMU_UCLK, &uclk_count); |
1cf8c930 EQ |
2801 | if (ret) |
2802 | return ret; | |
2803 | ||
3646c00e | 2804 | ret = smu_v11_0_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)(uclk_count - 1), &uclk_max); |
1cf8c930 EQ |
2805 | if (ret) |
2806 | return ret; | |
2807 | ||
3646c00e EQ |
2808 | /* |
2809 | * The NAVI10_UMC_HYBRID_CDR_WORKAROUND_UCLK_THRESHOLD is 750Mhz. | |
2810 | * This workaround is needed only when the max uclk frequency | |
2811 | * not greater than that. | |
2812 | */ | |
2813 | if (uclk_max > 0x2EE) | |
2814 | return 0; | |
2815 | ||
2816 | ret = smu_v11_0_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)0, &uclk_min); | |
1cf8c930 EQ |
2817 | if (ret) |
2818 | return ret; | |
2819 | ||
2820 | /* Force UCLK out of the highest DPM */ | |
661b94f5 | 2821 | ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, uclk_min); |
1cf8c930 EQ |
2822 | if (ret) |
2823 | return ret; | |
2824 | ||
2825 | /* Revert the UCLK Hardmax */ | |
661b94f5 | 2826 | ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, uclk_max); |
1cf8c930 EQ |
2827 | if (ret) |
2828 | return ret; | |
2829 | ||
2830 | /* | |
2831 | * In this case, SMU already disabled dummy pstate during enablement | |
2832 | * of UCLK DPM, we have to re-enabled it. | |
3646c00e EQ |
2833 | */ |
2834 | return smu_cmn_send_smc_msg(smu, SMU_MSG_DAL_ENABLE_DUMMY_PSTATE_CHANGE, NULL); | |
2835 | } | |
2836 | ||
665945eb EQ |
2837 | static int navi10_set_dummy_pstates_table_location(struct smu_context *smu) |
2838 | { | |
2839 | struct smu_table_context *smu_table = &smu->smu_table; | |
2840 | struct smu_table *dummy_read_table = | |
2841 | &smu_table->dummy_read_1_table; | |
2842 | char *dummy_table = dummy_read_table->cpu_addr; | |
2843 | int ret = 0; | |
2844 | uint32_t i; | |
2845 | ||
2846 | for (i = 0; i < 0x40000; i += 0x1000 * 2) { | |
2847 | memcpy(dummy_table, &NoDbiPrbs7[0], 0x1000); | |
2848 | dummy_table += 0x1000; | |
2849 | memcpy(dummy_table, &DbiPrbs7[0], 0x1000); | |
2850 | dummy_table += 0x1000; | |
2851 | } | |
2852 | ||
2853 | amdgpu_asic_flush_hdp(smu->adev, NULL); | |
2854 | ||
2855 | ret = smu_cmn_send_smc_msg_with_param(smu, | |
2856 | SMU_MSG_SET_DRIVER_DUMMY_TABLE_DRAM_ADDR_HIGH, | |
2857 | upper_32_bits(dummy_read_table->mc_address), | |
2858 | NULL); | |
2859 | if (ret) | |
2860 | return ret; | |
2861 | ||
2862 | return smu_cmn_send_smc_msg_with_param(smu, | |
2863 | SMU_MSG_SET_DRIVER_DUMMY_TABLE_DRAM_ADDR_LOW, | |
2864 | lower_32_bits(dummy_read_table->mc_address), | |
2865 | NULL); | |
2866 | } | |
2867 | ||
12f04120 | 2868 | static int navi10_run_umc_cdr_workaround(struct smu_context *smu) |
3646c00e | 2869 | { |
bb7257b5 EQ |
2870 | struct amdgpu_device *adev = smu->adev; |
2871 | uint8_t umc_fw_greater_than_v136 = false; | |
2872 | uint8_t umc_fw_disable_cdr = false; | |
bb7257b5 | 2873 | uint32_t param; |
3646c00e EQ |
2874 | int ret = 0; |
2875 | ||
12f04120 | 2876 | if (!navi10_need_umc_cdr_workaround(smu)) |
3646c00e EQ |
2877 | return 0; |
2878 | ||
bb7257b5 | 2879 | /* |
b226ef95 EQ |
2880 | * The messages below are only supported by Navi10 42.53.0 and later |
2881 | * PMFWs and Navi14 53.29.0 and later PMFWs. | |
bb7257b5 EQ |
2882 | * - PPSMC_MSG_SetDriverDummyTableDramAddrHigh |
2883 | * - PPSMC_MSG_SetDriverDummyTableDramAddrLow | |
2884 | * - PPSMC_MSG_GetUMCFWWA | |
2885 | */ | |
4e8303cf | 2886 | if (((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) && |
710d9cae | 2887 | (smu->smc_fw_version >= 0x2a3500)) || |
4e8303cf | 2888 | ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 5)) && |
710d9cae | 2889 | (smu->smc_fw_version >= 0x351D00))) { |
bb7257b5 EQ |
2890 | ret = smu_cmn_send_smc_msg_with_param(smu, |
2891 | SMU_MSG_GET_UMC_FW_WA, | |
2892 | 0, | |
2893 | ¶m); | |
2894 | if (ret) | |
2895 | return ret; | |
2896 | ||
2897 | /* First bit indicates if the UMC f/w is above v137 */ | |
2898 | umc_fw_greater_than_v136 = param & 0x1; | |
2899 | ||
2900 | /* Second bit indicates if hybrid-cdr is disabled */ | |
2901 | umc_fw_disable_cdr = param & 0x2; | |
3646c00e | 2902 | |
bb7257b5 EQ |
2903 | /* w/a only allowed if UMC f/w is <= 136 */ |
2904 | if (umc_fw_greater_than_v136) | |
2905 | return 0; | |
2906 | ||
e4912146 | 2907 | if (umc_fw_disable_cdr) { |
4e8303cf LL |
2908 | if (amdgpu_ip_version(adev, MP1_HWIP, 0) == |
2909 | IP_VERSION(11, 0, 0)) | |
e4912146 EQ |
2910 | return navi10_umc_hybrid_cdr_workaround(smu); |
2911 | } else { | |
bb7257b5 | 2912 | return navi10_set_dummy_pstates_table_location(smu); |
e4912146 | 2913 | } |
bb7257b5 | 2914 | } else { |
4e8303cf LL |
2915 | if (amdgpu_ip_version(adev, MP1_HWIP, 0) == |
2916 | IP_VERSION(11, 0, 0)) | |
bb7257b5 EQ |
2917 | return navi10_umc_hybrid_cdr_workaround(smu); |
2918 | } | |
2919 | ||
2920 | return 0; | |
1cf8c930 EQ |
2921 | } |
2922 | ||
7d6c13ef EQ |
2923 | static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, |
2924 | void **table) | |
2925 | { | |
2926 | struct smu_table_context *smu_table = &smu->smu_table; | |
61e2d322 DN |
2927 | struct gpu_metrics_v1_3 *gpu_metrics = |
2928 | (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; | |
7d6c13ef EQ |
2929 | SmuMetrics_legacy_t metrics; |
2930 | int ret = 0; | |
2931 | ||
da11407f EQ |
2932 | ret = smu_cmn_get_metrics_table(smu, |
2933 | NULL, | |
2934 | true); | |
2935 | if (ret) | |
7d6c13ef | 2936 | return ret; |
7d6c13ef EQ |
2937 | |
2938 | memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_legacy_t)); | |
2939 | ||
61e2d322 | 2940 | smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3); |
7d6c13ef EQ |
2941 | |
2942 | gpu_metrics->temperature_edge = metrics.TemperatureEdge; | |
2943 | gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; | |
2944 | gpu_metrics->temperature_mem = metrics.TemperatureMem; | |
2945 | gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; | |
2946 | gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; | |
2947 | gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; | |
2948 | ||
2949 | gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; | |
2950 | gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; | |
2951 | ||
2952 | gpu_metrics->average_socket_power = metrics.AverageSocketPower; | |
2953 | ||
2954 | gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; | |
2955 | gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; | |
2956 | gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; | |
2957 | ||
2958 | gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; | |
2959 | gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; | |
2960 | gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; | |
2961 | gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; | |
2962 | gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; | |
2963 | ||
2964 | gpu_metrics->throttle_status = metrics.ThrottlerStatus; | |
64cdee43 GS |
2965 | gpu_metrics->indep_throttle_status = |
2966 | smu_cmn_get_indep_throttler_status(metrics.ThrottlerStatus, | |
2967 | navi1x_throttler_map); | |
7d6c13ef EQ |
2968 | |
2969 | gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; | |
2970 | ||
2971 | gpu_metrics->pcie_link_width = | |
2972 | smu_v11_0_get_current_pcie_link_width(smu); | |
2973 | gpu_metrics->pcie_link_speed = | |
2974 | smu_v11_0_get_current_pcie_link_speed(smu); | |
2975 | ||
2976 | gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); | |
2977 | ||
61e2d322 DN |
2978 | if (metrics.CurrGfxVoltageOffset) |
2979 | gpu_metrics->voltage_gfx = | |
2980 | (155000 - 625 * metrics.CurrGfxVoltageOffset) / 100; | |
2981 | if (metrics.CurrMemVidOffset) | |
2982 | gpu_metrics->voltage_mem = | |
2983 | (155000 - 625 * metrics.CurrMemVidOffset) / 100; | |
2984 | if (metrics.CurrSocVoltageOffset) | |
2985 | gpu_metrics->voltage_soc = | |
2986 | (155000 - 625 * metrics.CurrSocVoltageOffset) / 100; | |
2987 | ||
7d6c13ef EQ |
2988 | *table = (void *)gpu_metrics; |
2989 | ||
61e2d322 | 2990 | return sizeof(struct gpu_metrics_v1_3); |
7d6c13ef EQ |
2991 | } |
2992 | ||
af01340b | 2993 | static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, |
ebe57d0c | 2994 | struct i2c_msg *msg, int num_msgs) |
af01340b | 2995 | { |
2f60dd50 LT |
2996 | struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(i2c_adap); |
2997 | struct amdgpu_device *adev = smu_i2c->adev; | |
ebfc2533 EQ |
2998 | struct smu_context *smu = adev->powerplay.pp_handle; |
2999 | struct smu_table_context *smu_table = &smu->smu_table; | |
af01340b AD |
3000 | struct smu_table *table = &smu_table->driver_table; |
3001 | SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; | |
ebe57d0c LT |
3002 | int i, j, r, c; |
3003 | u16 dir; | |
af01340b | 3004 | |
e281d594 AD |
3005 | if (!adev->pm.dpm_enabled) |
3006 | return -EBUSY; | |
3007 | ||
af01340b AD |
3008 | req = kzalloc(sizeof(*req), GFP_KERNEL); |
3009 | if (!req) | |
3010 | return -ENOMEM; | |
3011 | ||
2f60dd50 | 3012 | req->I2CcontrollerPort = smu_i2c->port; |
af01340b | 3013 | req->I2CSpeed = I2C_SPEED_FAST_400K; |
ebe57d0c LT |
3014 | req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */ |
3015 | dir = msg[0].flags & I2C_M_RD; | |
af01340b | 3016 | |
ebe57d0c LT |
3017 | for (c = i = 0; i < num_msgs; i++) { |
3018 | for (j = 0; j < msg[i].len; j++, c++) { | |
3019 | SwI2cCmd_t *cmd = &req->SwI2cCmds[c]; | |
af01340b | 3020 | |
af01340b AD |
3021 | if (!(msg[i].flags & I2C_M_RD)) { |
3022 | /* write */ | |
ebe57d0c LT |
3023 | cmd->Cmd = I2C_CMD_WRITE; |
3024 | cmd->RegisterAddr = msg[i].buf[j]; | |
3025 | } | |
3026 | ||
3027 | if ((dir ^ msg[i].flags) & I2C_M_RD) { | |
3028 | /* The direction changes. | |
3029 | */ | |
3030 | dir = msg[i].flags & I2C_M_RD; | |
3031 | cmd->CmdConfig |= CMDCONFIG_RESTART_MASK; | |
af01340b | 3032 | } |
14df5650 | 3033 | |
ebe57d0c LT |
3034 | req->NumCmds++; |
3035 | ||
14df5650 AG |
3036 | /* |
3037 | * Insert STOP if we are at the last byte of either last | |
3038 | * message for the transaction or the client explicitly | |
3039 | * requires a STOP at this particular message. | |
3040 | */ | |
ebe57d0c LT |
3041 | if ((j == msg[i].len - 1) && |
3042 | ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) { | |
3043 | cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK; | |
af01340b | 3044 | cmd->CmdConfig |= CMDCONFIG_STOP_MASK; |
ebe57d0c | 3045 | } |
af01340b AD |
3046 | } |
3047 | } | |
e0638c7a | 3048 | mutex_lock(&adev->pm.mutex); |
ebfc2533 | 3049 | r = smu_cmn_update_table(smu, SMU_TABLE_I2C_COMMANDS, 0, req, true); |
af01340b AD |
3050 | if (r) |
3051 | goto fail; | |
3052 | ||
ebe57d0c LT |
3053 | for (c = i = 0; i < num_msgs; i++) { |
3054 | if (!(msg[i].flags & I2C_M_RD)) { | |
3055 | c += msg[i].len; | |
3056 | continue; | |
3057 | } | |
3058 | for (j = 0; j < msg[i].len; j++, c++) { | |
3059 | SwI2cCmd_t *cmd = &res->SwI2cCmds[c]; | |
af01340b | 3060 | |
ebe57d0c | 3061 | msg[i].buf[j] = cmd->Data; |
af01340b AD |
3062 | } |
3063 | } | |
ebe57d0c | 3064 | r = num_msgs; |
af01340b | 3065 | fail: |
62b73bd5 | 3066 | mutex_unlock(&adev->pm.mutex); |
af01340b | 3067 | kfree(req); |
af01340b AD |
3068 | return r; |
3069 | } | |
3070 | ||
3071 | static u32 navi10_i2c_func(struct i2c_adapter *adap) | |
3072 | { | |
3073 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | |
3074 | } | |
3075 | ||
3076 | ||
3077 | static const struct i2c_algorithm navi10_i2c_algo = { | |
3078 | .master_xfer = navi10_i2c_xfer, | |
3079 | .functionality = navi10_i2c_func, | |
3080 | }; | |
3081 | ||
35ed2703 | 3082 | static const struct i2c_adapter_quirks navi10_i2c_control_quirks = { |
c0838d3a | 3083 | .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR | I2C_AQ_NO_ZERO_LEN, |
16736627 | 3084 | .max_read_len = MAX_SW_I2C_COMMANDS, |
35ed2703 | 3085 | .max_write_len = MAX_SW_I2C_COMMANDS, |
16736627 LT |
3086 | .max_comb_1st_msg_len = 2, |
3087 | .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2, | |
35ed2703 AG |
3088 | }; |
3089 | ||
2f60dd50 | 3090 | static int navi10_i2c_control_init(struct smu_context *smu) |
af01340b | 3091 | { |
2f60dd50 LT |
3092 | struct amdgpu_device *adev = smu->adev; |
3093 | int res, i; | |
3094 | ||
3095 | for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { | |
3096 | struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; | |
3097 | struct i2c_adapter *control = &smu_i2c->adapter; | |
3098 | ||
3099 | smu_i2c->adev = adev; | |
3100 | smu_i2c->port = i; | |
3101 | mutex_init(&smu_i2c->mutex); | |
3102 | control->owner = THIS_MODULE; | |
3103 | control->class = I2C_CLASS_HWMON; | |
3104 | control->dev.parent = &adev->pdev->dev; | |
3105 | control->algo = &navi10_i2c_algo; | |
3106 | snprintf(control->name, sizeof(control->name), "AMDGPU SMU %d", i); | |
3107 | control->quirks = &navi10_i2c_control_quirks; | |
3108 | i2c_set_adapdata(control, smu_i2c); | |
3109 | ||
3110 | res = i2c_add_adapter(control); | |
3111 | if (res) { | |
3112 | DRM_ERROR("Failed to register hw i2c, err: %d\n", res); | |
3113 | goto Out_err; | |
3114 | } | |
3115 | } | |
af01340b | 3116 | |
2f60dd50 LT |
3117 | adev->pm.ras_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter; |
3118 | adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[1].adapter; | |
af01340b | 3119 | |
2f60dd50 LT |
3120 | return 0; |
3121 | Out_err: | |
3122 | for ( ; i >= 0; i--) { | |
3123 | struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; | |
3124 | struct i2c_adapter *control = &smu_i2c->adapter; | |
af01340b | 3125 | |
2f60dd50 LT |
3126 | i2c_del_adapter(control); |
3127 | } | |
af01340b AD |
3128 | return res; |
3129 | } | |
3130 | ||
2f60dd50 | 3131 | static void navi10_i2c_control_fini(struct smu_context *smu) |
af01340b | 3132 | { |
2f60dd50 LT |
3133 | struct amdgpu_device *adev = smu->adev; |
3134 | int i; | |
3135 | ||
3136 | for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { | |
3137 | struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; | |
3138 | struct i2c_adapter *control = &smu_i2c->adapter; | |
3139 | ||
3140 | i2c_del_adapter(control); | |
3141 | } | |
3142 | adev->pm.ras_eeprom_i2c_bus = NULL; | |
3143 | adev->pm.fru_eeprom_i2c_bus = NULL; | |
af01340b AD |
3144 | } |
3145 | ||
6d4ff50a EQ |
3146 | static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, |
3147 | void **table) | |
3148 | { | |
3149 | struct smu_table_context *smu_table = &smu->smu_table; | |
61e2d322 DN |
3150 | struct gpu_metrics_v1_3 *gpu_metrics = |
3151 | (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; | |
6d4ff50a EQ |
3152 | SmuMetrics_t metrics; |
3153 | int ret = 0; | |
3154 | ||
da11407f EQ |
3155 | ret = smu_cmn_get_metrics_table(smu, |
3156 | NULL, | |
3157 | true); | |
3158 | if (ret) | |
6d4ff50a | 3159 | return ret; |
6d4ff50a | 3160 | |
fceafc9b | 3161 | memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_t)); |
7d6c13ef | 3162 | |
61e2d322 | 3163 | smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3); |
7d6c13ef EQ |
3164 | |
3165 | gpu_metrics->temperature_edge = metrics.TemperatureEdge; | |
3166 | gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; | |
3167 | gpu_metrics->temperature_mem = metrics.TemperatureMem; | |
3168 | gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; | |
3169 | gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; | |
3170 | gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; | |
3171 | ||
3172 | gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; | |
3173 | gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; | |
3174 | ||
3175 | gpu_metrics->average_socket_power = metrics.AverageSocketPower; | |
3176 | ||
3177 | if (metrics.AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) | |
3178 | gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPreDs; | |
3179 | else | |
3180 | gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPostDs; | |
3181 | ||
3182 | gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; | |
3183 | gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequencyPostDs; | |
3184 | ||
3185 | gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; | |
3186 | gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; | |
3187 | gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; | |
3188 | gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; | |
3189 | gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; | |
3190 | ||
3191 | gpu_metrics->throttle_status = metrics.ThrottlerStatus; | |
64cdee43 GS |
3192 | gpu_metrics->indep_throttle_status = |
3193 | smu_cmn_get_indep_throttler_status(metrics.ThrottlerStatus, | |
3194 | navi1x_throttler_map); | |
7d6c13ef EQ |
3195 | |
3196 | gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; | |
3197 | ||
c524c1c9 EQ |
3198 | gpu_metrics->pcie_link_width = metrics.PcieWidth; |
3199 | gpu_metrics->pcie_link_speed = link_speed[metrics.PcieRate]; | |
7d6c13ef EQ |
3200 | |
3201 | gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); | |
3202 | ||
61e2d322 DN |
3203 | if (metrics.CurrGfxVoltageOffset) |
3204 | gpu_metrics->voltage_gfx = | |
3205 | (155000 - 625 * metrics.CurrGfxVoltageOffset) / 100; | |
3206 | if (metrics.CurrMemVidOffset) | |
3207 | gpu_metrics->voltage_mem = | |
3208 | (155000 - 625 * metrics.CurrMemVidOffset) / 100; | |
3209 | if (metrics.CurrSocVoltageOffset) | |
3210 | gpu_metrics->voltage_soc = | |
3211 | (155000 - 625 * metrics.CurrSocVoltageOffset) / 100; | |
3212 | ||
7d6c13ef EQ |
3213 | *table = (void *)gpu_metrics; |
3214 | ||
61e2d322 | 3215 | return sizeof(struct gpu_metrics_v1_3); |
7d6c13ef EQ |
3216 | } |
3217 | ||
3218 | static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu, | |
3219 | void **table) | |
3220 | { | |
3221 | struct smu_table_context *smu_table = &smu->smu_table; | |
61e2d322 DN |
3222 | struct gpu_metrics_v1_3 *gpu_metrics = |
3223 | (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; | |
7d6c13ef EQ |
3224 | SmuMetrics_NV12_legacy_t metrics; |
3225 | int ret = 0; | |
3226 | ||
da11407f EQ |
3227 | ret = smu_cmn_get_metrics_table(smu, |
3228 | NULL, | |
3229 | true); | |
3230 | if (ret) | |
7d6c13ef | 3231 | return ret; |
7d6c13ef EQ |
3232 | |
3233 | memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_legacy_t)); | |
6d4ff50a | 3234 | |
61e2d322 | 3235 | smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3); |
6d4ff50a EQ |
3236 | |
3237 | gpu_metrics->temperature_edge = metrics.TemperatureEdge; | |
3238 | gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; | |
3239 | gpu_metrics->temperature_mem = metrics.TemperatureMem; | |
3240 | gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; | |
3241 | gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; | |
3242 | gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; | |
3243 | ||
3244 | gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; | |
3245 | gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; | |
3246 | ||
3247 | gpu_metrics->average_socket_power = metrics.AverageSocketPower; | |
3248 | ||
3249 | gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; | |
3250 | gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; | |
3251 | gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; | |
3252 | ||
7d6c13ef EQ |
3253 | gpu_metrics->energy_accumulator = metrics.EnergyAccumulator; |
3254 | gpu_metrics->average_vclk0_frequency = metrics.AverageVclkFrequency; | |
3255 | gpu_metrics->average_dclk0_frequency = metrics.AverageDclkFrequency; | |
3256 | gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage; | |
3257 | ||
3258 | gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; | |
3259 | gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; | |
3260 | gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; | |
3261 | gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; | |
3262 | gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; | |
3263 | ||
3264 | gpu_metrics->throttle_status = metrics.ThrottlerStatus; | |
64cdee43 GS |
3265 | gpu_metrics->indep_throttle_status = |
3266 | smu_cmn_get_indep_throttler_status(metrics.ThrottlerStatus, | |
3267 | navi1x_throttler_map); | |
7d6c13ef EQ |
3268 | |
3269 | gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; | |
3270 | ||
3271 | gpu_metrics->pcie_link_width = | |
3272 | smu_v11_0_get_current_pcie_link_width(smu); | |
3273 | gpu_metrics->pcie_link_speed = | |
3274 | smu_v11_0_get_current_pcie_link_speed(smu); | |
3275 | ||
3276 | gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); | |
3277 | ||
61e2d322 DN |
3278 | if (metrics.CurrGfxVoltageOffset) |
3279 | gpu_metrics->voltage_gfx = | |
3280 | (155000 - 625 * metrics.CurrGfxVoltageOffset) / 100; | |
3281 | if (metrics.CurrMemVidOffset) | |
3282 | gpu_metrics->voltage_mem = | |
3283 | (155000 - 625 * metrics.CurrMemVidOffset) / 100; | |
3284 | if (metrics.CurrSocVoltageOffset) | |
3285 | gpu_metrics->voltage_soc = | |
3286 | (155000 - 625 * metrics.CurrSocVoltageOffset) / 100; | |
3287 | ||
7d6c13ef EQ |
3288 | *table = (void *)gpu_metrics; |
3289 | ||
61e2d322 | 3290 | return sizeof(struct gpu_metrics_v1_3); |
7d6c13ef EQ |
3291 | } |
3292 | ||
3293 | static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, | |
3294 | void **table) | |
3295 | { | |
3296 | struct smu_table_context *smu_table = &smu->smu_table; | |
61e2d322 DN |
3297 | struct gpu_metrics_v1_3 *gpu_metrics = |
3298 | (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; | |
7d6c13ef EQ |
3299 | SmuMetrics_NV12_t metrics; |
3300 | int ret = 0; | |
3301 | ||
da11407f EQ |
3302 | ret = smu_cmn_get_metrics_table(smu, |
3303 | NULL, | |
3304 | true); | |
3305 | if (ret) | |
7d6c13ef | 3306 | return ret; |
6d4ff50a | 3307 | |
7d6c13ef EQ |
3308 | memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t)); |
3309 | ||
61e2d322 | 3310 | smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3); |
7d6c13ef EQ |
3311 | |
3312 | gpu_metrics->temperature_edge = metrics.TemperatureEdge; | |
3313 | gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; | |
3314 | gpu_metrics->temperature_mem = metrics.TemperatureMem; | |
3315 | gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; | |
3316 | gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; | |
3317 | gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; | |
3318 | ||
3319 | gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; | |
3320 | gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; | |
3321 | ||
3322 | gpu_metrics->average_socket_power = metrics.AverageSocketPower; | |
3323 | ||
3324 | if (metrics.AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) | |
3325 | gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPreDs; | |
3326 | else | |
3327 | gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPostDs; | |
3328 | ||
3329 | gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; | |
3330 | gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequencyPostDs; | |
3331 | ||
3332 | gpu_metrics->energy_accumulator = metrics.EnergyAccumulator; | |
3333 | gpu_metrics->average_vclk0_frequency = metrics.AverageVclkFrequency; | |
3334 | gpu_metrics->average_dclk0_frequency = metrics.AverageDclkFrequency; | |
3335 | gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage; | |
3336 | ||
6d4ff50a EQ |
3337 | gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; |
3338 | gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; | |
3339 | gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; | |
3340 | gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; | |
3341 | gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; | |
3342 | ||
3343 | gpu_metrics->throttle_status = metrics.ThrottlerStatus; | |
64cdee43 GS |
3344 | gpu_metrics->indep_throttle_status = |
3345 | smu_cmn_get_indep_throttler_status(metrics.ThrottlerStatus, | |
3346 | navi1x_throttler_map); | |
6d4ff50a EQ |
3347 | |
3348 | gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; | |
3349 | ||
c524c1c9 EQ |
3350 | gpu_metrics->pcie_link_width = metrics.PcieWidth; |
3351 | gpu_metrics->pcie_link_speed = link_speed[metrics.PcieRate]; | |
6d4ff50a | 3352 | |
de4b7cd8 KW |
3353 | gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); |
3354 | ||
61e2d322 DN |
3355 | if (metrics.CurrGfxVoltageOffset) |
3356 | gpu_metrics->voltage_gfx = | |
3357 | (155000 - 625 * metrics.CurrGfxVoltageOffset) / 100; | |
3358 | if (metrics.CurrMemVidOffset) | |
3359 | gpu_metrics->voltage_mem = | |
3360 | (155000 - 625 * metrics.CurrMemVidOffset) / 100; | |
3361 | if (metrics.CurrSocVoltageOffset) | |
3362 | gpu_metrics->voltage_soc = | |
3363 | (155000 - 625 * metrics.CurrSocVoltageOffset) / 100; | |
3364 | ||
6d4ff50a EQ |
3365 | *table = (void *)gpu_metrics; |
3366 | ||
61e2d322 | 3367 | return sizeof(struct gpu_metrics_v1_3); |
6d4ff50a | 3368 | } |
1bc73475 | 3369 | |
7d6c13ef EQ |
3370 | static ssize_t navi1x_get_gpu_metrics(struct smu_context *smu, |
3371 | void **table) | |
3372 | { | |
3373 | struct amdgpu_device *adev = smu->adev; | |
7d6c13ef EQ |
3374 | int ret = 0; |
3375 | ||
4e8303cf | 3376 | switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { |
ea0d730a | 3377 | case IP_VERSION(11, 0, 9): |
710d9cae | 3378 | if (smu->smc_fw_version > 0x00341C00) |
7d6c13ef EQ |
3379 | ret = navi12_get_gpu_metrics(smu, table); |
3380 | else | |
3381 | ret = navi12_get_legacy_gpu_metrics(smu, table); | |
3382 | break; | |
ea0d730a AD |
3383 | case IP_VERSION(11, 0, 0): |
3384 | case IP_VERSION(11, 0, 5): | |
7d6c13ef | 3385 | default: |
4e8303cf LL |
3386 | if (((amdgpu_ip_version(adev, MP1_HWIP, 0) == |
3387 | IP_VERSION(11, 0, 5)) && | |
710d9cae | 3388 | smu->smc_fw_version > 0x00351F00) || |
4e8303cf LL |
3389 | ((amdgpu_ip_version(adev, MP1_HWIP, 0) == |
3390 | IP_VERSION(11, 0, 0)) && | |
710d9cae | 3391 | smu->smc_fw_version > 0x002A3B00)) |
7d6c13ef EQ |
3392 | ret = navi10_get_gpu_metrics(smu, table); |
3393 | else | |
1e3a58df | 3394 | ret = navi10_get_legacy_gpu_metrics(smu, table); |
7d6c13ef EQ |
3395 | break; |
3396 | } | |
3397 | ||
3398 | return ret; | |
3399 | } | |
3400 | ||
94a670d5 EQ |
3401 | static int navi10_enable_mgpu_fan_boost(struct smu_context *smu) |
3402 | { | |
b804a75d EQ |
3403 | struct smu_table_context *table_context = &smu->smu_table; |
3404 | PPTable_t *smc_pptable = table_context->driver_pptable; | |
94a670d5 EQ |
3405 | struct amdgpu_device *adev = smu->adev; |
3406 | uint32_t param = 0; | |
3407 | ||
3408 | /* Navi12 does not support this */ | |
4e8303cf | 3409 | if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 9)) |
94a670d5 EQ |
3410 | return 0; |
3411 | ||
b804a75d EQ |
3412 | /* |
3413 | * Skip the MGpuFanBoost setting for those ASICs | |
3414 | * which do not support it | |
3415 | */ | |
3416 | if (!smc_pptable->MGpuFanBoostLimitRpm) | |
3417 | return 0; | |
3418 | ||
94a670d5 EQ |
3419 | /* Workaround for WS SKU */ |
3420 | if (adev->pdev->device == 0x7312 && | |
3421 | adev->pdev->revision == 0) | |
3422 | param = 0xD188; | |
3423 | ||
3424 | return smu_cmn_send_smc_msg_with_param(smu, | |
3425 | SMU_MSG_SetMGpuFanBoostLimitRpm, | |
3426 | param, | |
3427 | NULL); | |
3428 | } | |
3429 | ||
10144762 EQ |
3430 | static int navi10_post_smu_init(struct smu_context *smu) |
3431 | { | |
10144762 | 3432 | struct amdgpu_device *adev = smu->adev; |
82cac71c | 3433 | int ret = 0; |
10144762 | 3434 | |
911d5bd5 JC |
3435 | if (amdgpu_sriov_vf(adev)) |
3436 | return 0; | |
3437 | ||
12f04120 | 3438 | ret = navi10_run_umc_cdr_workaround(smu); |
57277399 | 3439 | if (ret) |
82cac71c EQ |
3440 | dev_err(adev->dev, "Failed to apply umc cdr workaround!\n"); |
3441 | ||
3442 | return ret; | |
10144762 EQ |
3443 | } |
3444 | ||
7e2a4cfc EQ |
3445 | static int navi10_get_default_config_table_settings(struct smu_context *smu, |
3446 | struct config_table_setting *table) | |
3447 | { | |
3448 | if (!table) | |
3449 | return -EINVAL; | |
3450 | ||
3451 | table->gfxclk_average_tau = 10; | |
3452 | table->socclk_average_tau = 10; | |
3453 | table->uclk_average_tau = 10; | |
3454 | table->gfx_activity_average_tau = 10; | |
3455 | table->mem_activity_average_tau = 10; | |
3456 | table->socket_power_average_tau = 10; | |
3457 | ||
3458 | return 0; | |
3459 | } | |
3460 | ||
3461 | static int navi10_set_config_table(struct smu_context *smu, | |
3462 | struct config_table_setting *table) | |
3463 | { | |
3464 | DriverSmuConfig_t driver_smu_config_table; | |
3465 | ||
3466 | if (!table) | |
3467 | return -EINVAL; | |
3468 | ||
3469 | memset(&driver_smu_config_table, | |
3470 | 0, | |
3471 | sizeof(driver_smu_config_table)); | |
3472 | ||
3473 | driver_smu_config_table.GfxclkAverageLpfTau = | |
3474 | table->gfxclk_average_tau; | |
3475 | driver_smu_config_table.SocclkAverageLpfTau = | |
3476 | table->socclk_average_tau; | |
3477 | driver_smu_config_table.UclkAverageLpfTau = | |
3478 | table->uclk_average_tau; | |
3479 | driver_smu_config_table.GfxActivityLpfTau = | |
3480 | table->gfx_activity_average_tau; | |
3481 | driver_smu_config_table.UclkActivityLpfTau = | |
3482 | table->mem_activity_average_tau; | |
3483 | driver_smu_config_table.SocketPowerLpfTau = | |
3484 | table->socket_power_average_tau; | |
3485 | ||
3486 | return smu_cmn_update_table(smu, | |
3487 | SMU_TABLE_DRIVER_SMU_CONFIG, | |
3488 | 0, | |
3489 | (void *)&driver_smu_config_table, | |
3490 | true); | |
3491 | } | |
3492 | ||
b3490673 | 3493 | static const struct pptable_funcs navi10_ppt_funcs = { |
74c958a3 | 3494 | .get_allowed_feature_mask = navi10_get_allowed_feature_mask, |
b3490673 | 3495 | .set_default_dpm_table = navi10_set_default_dpm_table, |
f6b4b4a1 | 3496 | .dpm_set_vcn_enable = navi10_dpm_set_vcn_enable, |
43717ff6 | 3497 | .dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable, |
af01340b AD |
3498 | .i2c_init = navi10_i2c_control_init, |
3499 | .i2c_fini = navi10_i2c_control_fini, | |
b1e7e224 | 3500 | .print_clk_levels = navi10_print_clk_levels, |
b06b48d7 | 3501 | .emit_clk_levels = navi10_emit_clk_levels, |
db439ca2 | 3502 | .force_clk_levels = navi10_force_clk_levels, |
fa51bfc2 | 3503 | .populate_umd_state_clk = navi10_populate_umd_state_clk, |
a43913ea | 3504 | .get_clock_by_type_with_latency = navi10_get_clock_by_type_with_latency, |
28430544 | 3505 | .pre_display_config_changed = navi10_pre_display_config_changed, |
0a6430da | 3506 | .display_config_changed = navi10_display_config_changed, |
19796597 | 3507 | .notify_smc_display_config = navi10_notify_smc_display_config, |
4228b601 | 3508 | .is_dpm_running = navi10_is_dpm_running, |
0d8318e1 | 3509 | .get_fan_speed_pwm = smu_v11_0_get_fan_speed_pwm, |
d9ca7567 | 3510 | .get_fan_speed_rpm = navi10_get_fan_speed_rpm, |
b45dc20b KW |
3511 | .get_power_profile_mode = navi10_get_power_profile_mode, |
3512 | .set_power_profile_mode = navi10_set_power_profile_mode, | |
5bbb0994 | 3513 | .set_watermarks_table = navi10_set_watermarks_table, |
9c62f993 | 3514 | .read_sensor = navi10_read_sensor, |
f4b3295f | 3515 | .get_uclk_dpm_states = navi10_get_uclk_dpm_states, |
46a301e1 | 3516 | .set_performance_level = smu_v11_0_set_performance_level, |
7a816371 | 3517 | .get_thermal_temperature_range = navi10_get_thermal_temperature_range, |
6e92e156 | 3518 | .display_disable_memory_clock_switch = navi10_display_disable_memory_clock_switch, |
b4af964e | 3519 | .get_power_limit = navi10_get_power_limit, |
372120f0 | 3520 | .update_pcie_parameters = navi10_update_pcie_parameters, |
6c45e480 EQ |
3521 | .init_microcode = smu_v11_0_init_microcode, |
3522 | .load_microcode = smu_v11_0_load_microcode, | |
6f47116e | 3523 | .fini_microcode = smu_v11_0_fini_microcode, |
c1b353b7 | 3524 | .init_smc_tables = navi10_init_smc_tables, |
6c45e480 EQ |
3525 | .fini_smc_tables = smu_v11_0_fini_smc_tables, |
3526 | .init_power = smu_v11_0_init_power, | |
3527 | .fini_power = smu_v11_0_fini_power, | |
3528 | .check_fw_status = smu_v11_0_check_fw_status, | |
4a13b4ce | 3529 | .setup_pptable = navi10_setup_pptable, |
6c45e480 | 3530 | .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, |
6c45e480 | 3531 | .check_fw_version = smu_v11_0_check_fw_version, |
caad2613 | 3532 | .write_pptable = smu_cmn_write_pptable, |
ce0d0ec3 | 3533 | .set_driver_table_location = smu_v11_0_set_driver_table_location, |
6c45e480 EQ |
3534 | .set_tool_table_location = smu_v11_0_set_tool_table_location, |
3535 | .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, | |
3536 | .system_features_control = smu_v11_0_system_features_control, | |
66c86828 EQ |
3537 | .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, |
3538 | .send_smc_msg = smu_cmn_send_smc_msg, | |
6c45e480 EQ |
3539 | .init_display_count = smu_v11_0_init_display_count, |
3540 | .set_allowed_mask = smu_v11_0_set_allowed_mask, | |
28251d72 | 3541 | .get_enabled_mask = smu_cmn_get_enabled_mask, |
b4bb3aaf | 3542 | .feature_is_enabled = smu_cmn_feature_is_enabled, |
af5ba6d2 | 3543 | .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, |
6c45e480 EQ |
3544 | .notify_display_change = smu_v11_0_notify_display_change, |
3545 | .set_power_limit = smu_v11_0_set_power_limit, | |
6c45e480 | 3546 | .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks, |
22f1e0e8 EQ |
3547 | .enable_thermal_alert = smu_v11_0_enable_thermal_alert, |
3548 | .disable_thermal_alert = smu_v11_0_disable_thermal_alert, | |
ce63d8f8 | 3549 | .set_min_dcef_deep_sleep = smu_v11_0_set_min_deep_sleep_dcefclk, |
6c45e480 EQ |
3550 | .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, |
3551 | .get_fan_control_mode = smu_v11_0_get_fan_control_mode, | |
3552 | .set_fan_control_mode = smu_v11_0_set_fan_control_mode, | |
0d8318e1 | 3553 | .set_fan_speed_pwm = smu_v11_0_set_fan_speed_pwm, |
f3289d04 | 3554 | .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, |
6c45e480 EQ |
3555 | .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, |
3556 | .gfx_off_control = smu_v11_0_gfx_off_control, | |
3557 | .register_irq_handler = smu_v11_0_register_irq_handler, | |
3558 | .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, | |
3559 | .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, | |
1b199594 | 3560 | .get_bamaco_support = smu_v11_0_get_bamaco_support, |
13d75ead EQ |
3561 | .baco_enter = navi10_baco_enter, |
3562 | .baco_exit = navi10_baco_exit, | |
6c45e480 EQ |
3563 | .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, |
3564 | .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, | |
21677d08 MC |
3565 | .set_default_od_settings = navi10_set_default_od_settings, |
3566 | .od_edit_dpm_table = navi10_od_edit_dpm_table, | |
92cf0508 | 3567 | .restore_user_od_settings = smu_v11_0_restore_user_od_settings, |
0eeaa899 | 3568 | .run_btc = navi10_run_btc, |
fa34520c | 3569 | .set_power_source = smu_v11_0_set_power_source, |
7dbf7805 EQ |
3570 | .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, |
3571 | .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, | |
7d6c13ef | 3572 | .get_gpu_metrics = navi1x_get_gpu_metrics, |
94a670d5 | 3573 | .enable_mgpu_fan_boost = navi10_enable_mgpu_fan_boost, |
e988026f | 3574 | .gfx_ulv_control = smu_v11_0_gfx_ulv_control, |
5ce99853 | 3575 | .deep_sleep_control = smu_v11_0_deep_sleep_control, |
3204ff3e | 3576 | .get_fan_parameters = navi10_get_fan_parameters, |
10144762 | 3577 | .post_init = navi10_post_smu_init, |
234676d6 | 3578 | .interrupt_work = smu_v11_0_interrupt_work, |
5f0f1727 | 3579 | .set_mp1_state = smu_cmn_set_mp1_state, |
7e2a4cfc EQ |
3580 | .get_default_config_table_settings = navi10_get_default_config_table_settings, |
3581 | .set_config_table = navi10_set_config_table, | |
b3490673 HR |
3582 | }; |
3583 | ||
3584 | void navi10_set_ppt_funcs(struct smu_context *smu) | |
3585 | { | |
3586 | smu->ppt_funcs = &navi10_ppt_funcs; | |
6c339f37 EQ |
3587 | smu->message_map = navi10_message_map; |
3588 | smu->clock_map = navi10_clk_map; | |
3589 | smu->feature_map = navi10_feature_mask_map; | |
3590 | smu->table_map = navi10_table_map; | |
3591 | smu->pwr_src_map = navi10_pwr_src_map; | |
3592 | smu->workload_map = navi10_workload_map; | |
da1db031 | 3593 | smu_v11_0_set_smu_mailbox_registers(smu); |
b3490673 | 3594 | } |