]>
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 | ||
24 | #include "pp_debug.h" | |
25 | #include <linux/firmware.h> | |
26 | #include "amdgpu.h" | |
27 | #include "amdgpu_smu.h" | |
28 | #include "atomfirmware.h" | |
29 | #include "amdgpu_atomfirmware.h" | |
30 | #include "smu_v11_0.h" | |
013fd3a6 | 31 | #include "smu11_driver_if_navi10.h" |
b3490673 HR |
32 | #include "soc15_common.h" |
33 | #include "atom.h" | |
34 | #include "navi10_ppt.h" | |
35 | #include "smu_v11_0_pptable.h" | |
36 | #include "smu_v11_0_ppsmc.h" | |
37 | ||
fc419158 TZ |
38 | #include "asic_reg/mp/mp_11_0_sh_mask.h" |
39 | ||
44ff0ae6 | 40 | #define FEATURE_MASK(feature) (1ULL << feature) |
4228b601 KW |
41 | #define SMC_DPM_FEATURE ( \ |
42 | FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ | |
43 | FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ | |
44 | FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT) | \ | |
45 | FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ | |
46 | FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ | |
47 | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) | \ | |
48 | FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ | |
49 | FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) | |
50 | ||
b3490673 | 51 | #define MSG_MAP(msg, index) \ |
7e01a2ec | 52 | [SMU_MSG_##msg] = {1, (index)} |
b3490673 | 53 | |
7e01a2ec | 54 | static struct smu_11_0_cmn2aisc_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = { |
b3490673 HR |
55 | MSG_MAP(TestMessage, PPSMC_MSG_TestMessage), |
56 | MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion), | |
57 | MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion), | |
58 | MSG_MAP(SetAllowedFeaturesMaskLow, PPSMC_MSG_SetAllowedFeaturesMaskLow), | |
59 | MSG_MAP(SetAllowedFeaturesMaskHigh, PPSMC_MSG_SetAllowedFeaturesMaskHigh), | |
60 | MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures), | |
61 | MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures), | |
62 | MSG_MAP(EnableSmuFeaturesLow, PPSMC_MSG_EnableSmuFeaturesLow), | |
63 | MSG_MAP(EnableSmuFeaturesHigh, PPSMC_MSG_EnableSmuFeaturesHigh), | |
64 | MSG_MAP(DisableSmuFeaturesLow, PPSMC_MSG_DisableSmuFeaturesLow), | |
65 | MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh), | |
66 | MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow), | |
67 | MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh), | |
68 | MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask), | |
69 | MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit), | |
70 | MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh), | |
71 | MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow), | |
72 | MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh), | |
73 | MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow), | |
74 | MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram), | |
75 | MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu), | |
76 | MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable), | |
77 | MSG_MAP(UseBackupPPTable, PPSMC_MSG_UseBackupPPTable), | |
78 | MSG_MAP(RunBtc, PPSMC_MSG_RunBtc), | |
79 | MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco), | |
80 | MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq), | |
81 | MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq), | |
82 | MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq), | |
83 | MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq), | |
84 | MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq), | |
85 | MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq), | |
86 | MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex), | |
87 | MSG_MAP(SetMemoryChannelConfig, PPSMC_MSG_SetMemoryChannelConfig), | |
88 | MSG_MAP(SetGeminiMode, PPSMC_MSG_SetGeminiMode), | |
89 | MSG_MAP(SetGeminiApertureHigh, PPSMC_MSG_SetGeminiApertureHigh), | |
90 | MSG_MAP(SetGeminiApertureLow, PPSMC_MSG_SetGeminiApertureLow), | |
91 | MSG_MAP(OverridePcieParameters, PPSMC_MSG_OverridePcieParameters), | |
92 | MSG_MAP(SetMinDeepSleepDcefclk, PPSMC_MSG_SetMinDeepSleepDcefclk), | |
93 | MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt), | |
94 | MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource), | |
95 | MSG_MAP(SetUclkFastSwitch, PPSMC_MSG_SetUclkFastSwitch), | |
96 | MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps), | |
97 | MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload), | |
98 | MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh), | |
99 | MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow), | |
100 | MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize), | |
101 | MSG_MAP(ConfigureGfxDidt, PPSMC_MSG_ConfigureGfxDidt), | |
102 | MSG_MAP(NumOfDisplays, PPSMC_MSG_NumOfDisplays), | |
103 | MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh), | |
104 | MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow), | |
105 | MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff), | |
106 | MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff), | |
107 | MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit), | |
108 | MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq), | |
109 | MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData), | |
110 | MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco), | |
111 | MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset), | |
112 | MSG_MAP(PrepareMp1ForShutdown, PPSMC_MSG_PrepareMp1ForShutdown), | |
a8179d62 KF |
113 | MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn), |
114 | MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn), | |
115 | MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg), | |
116 | MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg), | |
26e2b581 | 117 | MSG_MAP(BacoAudioD3PME, PPSMC_MSG_BacoAudioD3PME), |
767acabd | 118 | MSG_MAP(ArmD3, PPSMC_MSG_ArmD3), |
b3490673 HR |
119 | }; |
120 | ||
7e01a2ec | 121 | static struct smu_11_0_cmn2aisc_mapping navi10_clk_map[SMU_CLK_COUNT] = { |
0de94acf | 122 | CLK_MAP(GFXCLK, PPCLK_GFXCLK), |
b1e7e224 | 123 | CLK_MAP(SCLK, PPCLK_GFXCLK), |
0de94acf | 124 | CLK_MAP(SOCCLK, PPCLK_SOCCLK), |
b1e7e224 | 125 | CLK_MAP(FCLK, PPCLK_SOCCLK), |
0de94acf | 126 | CLK_MAP(UCLK, PPCLK_UCLK), |
b1e7e224 | 127 | CLK_MAP(MCLK, PPCLK_UCLK), |
0de94acf HR |
128 | CLK_MAP(DCLK, PPCLK_DCLK), |
129 | CLK_MAP(VCLK, PPCLK_VCLK), | |
130 | CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), | |
131 | CLK_MAP(DISPCLK, PPCLK_DISPCLK), | |
132 | CLK_MAP(PIXCLK, PPCLK_PIXCLK), | |
133 | CLK_MAP(PHYCLK, PPCLK_PHYCLK), | |
134 | }; | |
135 | ||
7e01a2ec | 136 | static struct smu_11_0_cmn2aisc_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = { |
ffcb08df HR |
137 | FEA_MAP(DPM_PREFETCHER), |
138 | FEA_MAP(DPM_GFXCLK), | |
139 | FEA_MAP(DPM_GFX_PACE), | |
140 | FEA_MAP(DPM_UCLK), | |
141 | FEA_MAP(DPM_SOCCLK), | |
142 | FEA_MAP(DPM_MP0CLK), | |
143 | FEA_MAP(DPM_LINK), | |
144 | FEA_MAP(DPM_DCEFCLK), | |
145 | FEA_MAP(MEM_VDDCI_SCALING), | |
146 | FEA_MAP(MEM_MVDD_SCALING), | |
147 | FEA_MAP(DS_GFXCLK), | |
148 | FEA_MAP(DS_SOCCLK), | |
149 | FEA_MAP(DS_LCLK), | |
150 | FEA_MAP(DS_DCEFCLK), | |
151 | FEA_MAP(DS_UCLK), | |
152 | FEA_MAP(GFX_ULV), | |
153 | FEA_MAP(FW_DSTATE), | |
154 | FEA_MAP(GFXOFF), | |
155 | FEA_MAP(BACO), | |
156 | FEA_MAP(VCN_PG), | |
157 | FEA_MAP(JPEG_PG), | |
158 | FEA_MAP(USB_PG), | |
159 | FEA_MAP(RSMU_SMN_CG), | |
160 | FEA_MAP(PPT), | |
161 | FEA_MAP(TDC), | |
162 | FEA_MAP(GFX_EDC), | |
163 | FEA_MAP(APCC_PLUS), | |
164 | FEA_MAP(GTHR), | |
165 | FEA_MAP(ACDC), | |
166 | FEA_MAP(VR0HOT), | |
167 | FEA_MAP(VR1HOT), | |
168 | FEA_MAP(FW_CTF), | |
169 | FEA_MAP(FAN_CONTROL), | |
170 | FEA_MAP(THERMAL), | |
171 | FEA_MAP(GFX_DCS), | |
172 | FEA_MAP(RM), | |
173 | FEA_MAP(LED_DISPLAY), | |
174 | FEA_MAP(GFX_SS), | |
175 | FEA_MAP(OUT_OF_BAND_MONITOR), | |
176 | FEA_MAP(TEMP_DEPENDENT_VMIN), | |
177 | FEA_MAP(MMHUB_PG), | |
178 | FEA_MAP(ATHUB_PG), | |
179 | }; | |
180 | ||
7e01a2ec | 181 | static struct smu_11_0_cmn2aisc_mapping navi10_table_map[SMU_TABLE_COUNT] = { |
2436911b HR |
182 | TAB_MAP(PPTABLE), |
183 | TAB_MAP(WATERMARKS), | |
184 | TAB_MAP(AVFS), | |
185 | TAB_MAP(AVFS_PSM_DEBUG), | |
186 | TAB_MAP(AVFS_FUSE_OVERRIDE), | |
187 | TAB_MAP(PMSTATUSLOG), | |
188 | TAB_MAP(SMU_METRICS), | |
189 | TAB_MAP(DRIVER_SMU_CONFIG), | |
190 | TAB_MAP(ACTIVITY_MONITOR_COEFF), | |
191 | TAB_MAP(OVERDRIVE), | |
192 | TAB_MAP(I2C_COMMANDS), | |
193 | TAB_MAP(PACE), | |
194 | }; | |
195 | ||
7e01a2ec | 196 | static struct smu_11_0_cmn2aisc_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { |
8890fe5f HR |
197 | PWR_MAP(AC), |
198 | PWR_MAP(DC), | |
199 | }; | |
200 | ||
7e01a2ec | 201 | static struct smu_11_0_cmn2aisc_mapping navi10_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { |
6c6187ec KW |
202 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, WORKLOAD_PPLIB_DEFAULT_BIT), |
203 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), | |
204 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, WORKLOAD_PPLIB_POWER_SAVING_BIT), | |
205 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, WORKLOAD_PPLIB_VIDEO_BIT), | |
206 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, WORKLOAD_PPLIB_VR_BIT), | |
207 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_CUSTOM_BIT), | |
208 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), | |
209 | }; | |
210 | ||
b3490673 HR |
211 | static int navi10_get_smu_msg_index(struct smu_context *smc, uint32_t index) |
212 | { | |
7e01a2ec EQ |
213 | struct smu_11_0_cmn2aisc_mapping mapping; |
214 | ||
c16d001b | 215 | if (index > SMU_MSG_MAX_COUNT) |
b3490673 | 216 | return -EINVAL; |
b3490673 | 217 | |
7e01a2ec | 218 | mapping = navi10_message_map[index]; |
c0640304 | 219 | if (!(mapping.valid_mapping)) { |
c16d001b | 220 | return -EINVAL; |
c0640304 | 221 | } |
c16d001b | 222 | |
7e01a2ec | 223 | return mapping.map_to; |
b3490673 HR |
224 | } |
225 | ||
0de94acf HR |
226 | static int navi10_get_smu_clk_index(struct smu_context *smc, uint32_t index) |
227 | { | |
7e01a2ec EQ |
228 | struct smu_11_0_cmn2aisc_mapping mapping; |
229 | ||
0de94acf HR |
230 | if (index >= SMU_CLK_COUNT) |
231 | return -EINVAL; | |
232 | ||
7e01a2ec | 233 | mapping = navi10_clk_map[index]; |
c0640304 | 234 | if (!(mapping.valid_mapping)) { |
0de94acf | 235 | return -EINVAL; |
c0640304 | 236 | } |
0de94acf | 237 | |
7e01a2ec | 238 | return mapping.map_to; |
0de94acf HR |
239 | } |
240 | ||
ffcb08df HR |
241 | static int navi10_get_smu_feature_index(struct smu_context *smc, uint32_t index) |
242 | { | |
7e01a2ec EQ |
243 | struct smu_11_0_cmn2aisc_mapping mapping; |
244 | ||
ffcb08df HR |
245 | if (index >= SMU_FEATURE_COUNT) |
246 | return -EINVAL; | |
247 | ||
7e01a2ec | 248 | mapping = navi10_feature_mask_map[index]; |
c0640304 | 249 | if (!(mapping.valid_mapping)) { |
ffcb08df | 250 | return -EINVAL; |
c0640304 | 251 | } |
ffcb08df | 252 | |
7e01a2ec | 253 | return mapping.map_to; |
ffcb08df HR |
254 | } |
255 | ||
2436911b HR |
256 | static int navi10_get_smu_table_index(struct smu_context *smc, uint32_t index) |
257 | { | |
7e01a2ec EQ |
258 | struct smu_11_0_cmn2aisc_mapping mapping; |
259 | ||
2436911b HR |
260 | if (index >= SMU_TABLE_COUNT) |
261 | return -EINVAL; | |
262 | ||
7e01a2ec | 263 | mapping = navi10_table_map[index]; |
c0640304 | 264 | if (!(mapping.valid_mapping)) { |
2436911b | 265 | return -EINVAL; |
c0640304 | 266 | } |
2436911b | 267 | |
7e01a2ec | 268 | return mapping.map_to; |
2436911b HR |
269 | } |
270 | ||
8890fe5f HR |
271 | static int navi10_get_pwr_src_index(struct smu_context *smc, uint32_t index) |
272 | { | |
7e01a2ec EQ |
273 | struct smu_11_0_cmn2aisc_mapping mapping; |
274 | ||
8890fe5f HR |
275 | if (index >= SMU_POWER_SOURCE_COUNT) |
276 | return -EINVAL; | |
277 | ||
7e01a2ec | 278 | mapping = navi10_pwr_src_map[index]; |
c0640304 | 279 | if (!(mapping.valid_mapping)) { |
8890fe5f | 280 | return -EINVAL; |
c0640304 | 281 | } |
8890fe5f | 282 | |
7e01a2ec | 283 | return mapping.map_to; |
8890fe5f HR |
284 | } |
285 | ||
6c6187ec KW |
286 | |
287 | static int navi10_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile) | |
288 | { | |
7e01a2ec EQ |
289 | struct smu_11_0_cmn2aisc_mapping mapping; |
290 | ||
6c6187ec KW |
291 | if (profile > PP_SMC_POWER_PROFILE_CUSTOM) |
292 | return -EINVAL; | |
293 | ||
7e01a2ec | 294 | mapping = navi10_workload_map[profile]; |
c0640304 | 295 | if (!(mapping.valid_mapping)) { |
7e01a2ec | 296 | return -EINVAL; |
c0640304 | 297 | } |
6c6187ec | 298 | |
7e01a2ec | 299 | return mapping.map_to; |
6c6187ec KW |
300 | } |
301 | ||
fc419158 TZ |
302 | static bool is_asic_secure(struct smu_context *smu) |
303 | { | |
304 | struct amdgpu_device *adev = smu->adev; | |
305 | bool is_secure = true; | |
306 | uint32_t mp0_fw_intf; | |
307 | ||
308 | mp0_fw_intf = RREG32_PCIE(MP0_Public | | |
309 | (smnMP0_FW_INTF & 0xffffffff)); | |
310 | ||
311 | if (!(mp0_fw_intf & (1 << 19))) | |
312 | is_secure = false; | |
313 | ||
314 | return is_secure; | |
315 | } | |
316 | ||
b3490673 | 317 | static int |
74c958a3 | 318 | navi10_get_allowed_feature_mask(struct smu_context *smu, |
b3490673 HR |
319 | uint32_t *feature_mask, uint32_t num) |
320 | { | |
9e040216 KF |
321 | struct amdgpu_device *adev = smu->adev; |
322 | ||
b3490673 HR |
323 | if (num > 2) |
324 | return -EINVAL; | |
325 | ||
74c958a3 KW |
326 | memset(feature_mask, 0, sizeof(uint32_t) * num); |
327 | ||
77ee9caf KW |
328 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) |
329 | | FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | |
330 | | FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | |
74c958a3 KW |
331 | | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) |
332 | | FEATURE_MASK(FEATURE_DPM_LINK_BIT) | |
333 | | FEATURE_MASK(FEATURE_GFX_ULV_BIT) | |
334 | | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) | |
d7a8efa5 | 335 | | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) |
74c958a3 KW |
336 | | FEATURE_MASK(FEATURE_PPT_BIT) |
337 | | FEATURE_MASK(FEATURE_TDC_BIT) | |
338 | | FEATURE_MASK(FEATURE_GFX_EDC_BIT) | |
339 | | FEATURE_MASK(FEATURE_VR0HOT_BIT) | |
340 | | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) | |
341 | | FEATURE_MASK(FEATURE_THERMAL_BIT) | |
342 | | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) | |
3a3c51dd KF |
343 | | FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) |
344 | | FEATURE_MASK(FEATURE_DS_GFXCLK_BIT) | |
345 | | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) | |
d8ceb192 | 346 | | FEATURE_MASK(FEATURE_FW_DSTATE_BIT) |
7c6fe84c | 347 | | FEATURE_MASK(FEATURE_BACO_BIT) |
597292eb KF |
348 | | FEATURE_MASK(FEATURE_ACDC_BIT) |
349 | | FEATURE_MASK(FEATURE_GFX_SS_BIT) | |
350 | | FEATURE_MASK(FEATURE_APCC_DFLL_BIT) | |
351 | | FEATURE_MASK(FEATURE_FW_CTF_BIT); | |
8c3b2d1b | 352 | |
a39bf398 KW |
353 | if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) |
354 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | |
355 | | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) | |
356 | | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); | |
357 | ||
1768908e | 358 | if (adev->pm.pp_feature & PP_GFXOFF_MASK) { |
597292eb | 359 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); |
1768908e JX |
360 | /* TODO: remove it once fw fix the bug */ |
361 | *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_FW_DSTATE_BIT); | |
362 | } | |
9e040216 | 363 | |
c12d410f HR |
364 | if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) |
365 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT); | |
366 | ||
a201b6ac HR |
367 | if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB) |
368 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT); | |
369 | ||
c4b76d23 KF |
370 | if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN) |
371 | *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT); | |
372 | ||
c877dff7 TZ |
373 | /* disable DPM UCLK and DS SOCCLK on navi10 A0 secure board */ |
374 | if (is_asic_secure(smu)) { | |
375 | /* only for navi10 A0 */ | |
376 | if ((adev->asic_type == CHIP_NAVI10) && | |
377 | (adev->rev_id == 0)) { | |
378 | *(uint64_t *)feature_mask &= | |
eefa5e2b KW |
379 | ~(FEATURE_MASK(FEATURE_DPM_UCLK_BIT) |
380 | | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) | |
381 | | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT)); | |
c877dff7 TZ |
382 | *(uint64_t *)feature_mask &= |
383 | ~FEATURE_MASK(FEATURE_DS_SOCCLK_BIT); | |
384 | } | |
385 | } | |
386 | ||
b3490673 HR |
387 | return 0; |
388 | } | |
389 | ||
390 | static int navi10_check_powerplay_table(struct smu_context *smu) | |
391 | { | |
392 | return 0; | |
393 | } | |
394 | ||
395 | static int navi10_append_powerplay_table(struct smu_context *smu) | |
396 | { | |
9e040216 | 397 | struct amdgpu_device *adev = smu->adev; |
b3490673 HR |
398 | struct smu_table_context *table_context = &smu->smu_table; |
399 | PPTable_t *smc_pptable = table_context->driver_pptable; | |
400 | struct atom_smc_dpm_info_v4_5 *smc_dpm_table; | |
401 | int index, ret; | |
402 | ||
403 | index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | |
404 | smc_dpm_info); | |
405 | ||
406 | ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, | |
407 | (uint8_t **)&smc_dpm_table); | |
408 | if (ret) | |
409 | return ret; | |
410 | ||
411 | memcpy(smc_pptable->I2cControllers, smc_dpm_table->I2cControllers, | |
412 | sizeof(I2cControllerConfig_t) * NUM_I2C_CONTROLLERS); | |
413 | ||
414 | /* SVI2 Board Parameters */ | |
415 | smc_pptable->MaxVoltageStepGfx = smc_dpm_table->MaxVoltageStepGfx; | |
416 | smc_pptable->MaxVoltageStepSoc = smc_dpm_table->MaxVoltageStepSoc; | |
417 | smc_pptable->VddGfxVrMapping = smc_dpm_table->VddGfxVrMapping; | |
418 | smc_pptable->VddSocVrMapping = smc_dpm_table->VddSocVrMapping; | |
419 | smc_pptable->VddMem0VrMapping = smc_dpm_table->VddMem0VrMapping; | |
420 | smc_pptable->VddMem1VrMapping = smc_dpm_table->VddMem1VrMapping; | |
421 | smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table->GfxUlvPhaseSheddingMask; | |
422 | smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table->SocUlvPhaseSheddingMask; | |
423 | smc_pptable->ExternalSensorPresent = smc_dpm_table->ExternalSensorPresent; | |
424 | smc_pptable->Padding8_V = smc_dpm_table->Padding8_V; | |
425 | ||
426 | /* Telemetry Settings */ | |
427 | smc_pptable->GfxMaxCurrent = smc_dpm_table->GfxMaxCurrent; | |
428 | smc_pptable->GfxOffset = smc_dpm_table->GfxOffset; | |
429 | smc_pptable->Padding_TelemetryGfx = smc_dpm_table->Padding_TelemetryGfx; | |
430 | smc_pptable->SocMaxCurrent = smc_dpm_table->SocMaxCurrent; | |
431 | smc_pptable->SocOffset = smc_dpm_table->SocOffset; | |
432 | smc_pptable->Padding_TelemetrySoc = smc_dpm_table->Padding_TelemetrySoc; | |
433 | smc_pptable->Mem0MaxCurrent = smc_dpm_table->Mem0MaxCurrent; | |
434 | smc_pptable->Mem0Offset = smc_dpm_table->Mem0Offset; | |
435 | smc_pptable->Padding_TelemetryMem0 = smc_dpm_table->Padding_TelemetryMem0; | |
436 | smc_pptable->Mem1MaxCurrent = smc_dpm_table->Mem1MaxCurrent; | |
437 | smc_pptable->Mem1Offset = smc_dpm_table->Mem1Offset; | |
438 | smc_pptable->Padding_TelemetryMem1 = smc_dpm_table->Padding_TelemetryMem1; | |
439 | ||
440 | /* GPIO Settings */ | |
441 | smc_pptable->AcDcGpio = smc_dpm_table->AcDcGpio; | |
442 | smc_pptable->AcDcPolarity = smc_dpm_table->AcDcPolarity; | |
443 | smc_pptable->VR0HotGpio = smc_dpm_table->VR0HotGpio; | |
444 | smc_pptable->VR0HotPolarity = smc_dpm_table->VR0HotPolarity; | |
445 | smc_pptable->VR1HotGpio = smc_dpm_table->VR1HotGpio; | |
446 | smc_pptable->VR1HotPolarity = smc_dpm_table->VR1HotPolarity; | |
447 | smc_pptable->GthrGpio = smc_dpm_table->GthrGpio; | |
448 | smc_pptable->GthrPolarity = smc_dpm_table->GthrPolarity; | |
449 | ||
450 | /* LED Display Settings */ | |
451 | smc_pptable->LedPin0 = smc_dpm_table->LedPin0; | |
452 | smc_pptable->LedPin1 = smc_dpm_table->LedPin1; | |
453 | smc_pptable->LedPin2 = smc_dpm_table->LedPin2; | |
454 | smc_pptable->padding8_4 = smc_dpm_table->padding8_4; | |
455 | ||
456 | /* GFXCLK PLL Spread Spectrum */ | |
457 | smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table->PllGfxclkSpreadEnabled; | |
458 | smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table->PllGfxclkSpreadPercent; | |
459 | smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table->PllGfxclkSpreadFreq; | |
460 | ||
461 | /* GFXCLK DFLL Spread Spectrum */ | |
462 | smc_pptable->DfllGfxclkSpreadEnabled = smc_dpm_table->DfllGfxclkSpreadEnabled; | |
463 | smc_pptable->DfllGfxclkSpreadPercent = smc_dpm_table->DfllGfxclkSpreadPercent; | |
464 | smc_pptable->DfllGfxclkSpreadFreq = smc_dpm_table->DfllGfxclkSpreadFreq; | |
465 | ||
466 | /* UCLK Spread Spectrum */ | |
467 | smc_pptable->UclkSpreadEnabled = smc_dpm_table->UclkSpreadEnabled; | |
468 | smc_pptable->UclkSpreadPercent = smc_dpm_table->UclkSpreadPercent; | |
469 | smc_pptable->UclkSpreadFreq = smc_dpm_table->UclkSpreadFreq; | |
470 | ||
471 | /* SOCCLK Spread Spectrum */ | |
472 | smc_pptable->SoclkSpreadEnabled = smc_dpm_table->SoclkSpreadEnabled; | |
473 | smc_pptable->SocclkSpreadPercent = smc_dpm_table->SocclkSpreadPercent; | |
474 | smc_pptable->SocclkSpreadFreq = smc_dpm_table->SocclkSpreadFreq; | |
475 | ||
476 | /* Total board power */ | |
477 | smc_pptable->TotalBoardPower = smc_dpm_table->TotalBoardPower; | |
478 | smc_pptable->BoardPadding = smc_dpm_table->BoardPadding; | |
479 | ||
480 | /* Mvdd Svi2 Div Ratio Setting */ | |
481 | smc_pptable->MvddRatio = smc_dpm_table->MvddRatio; | |
482 | ||
2a8bfa13 | 483 | if (adev->pm.pp_feature & PP_GFXOFF_MASK) { |
2a8bfa13 JX |
484 | /* TODO: remove it once SMU fw fix it */ |
485 | smc_pptable->DebugOverrides |= DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN; | |
486 | } | |
487 | ||
b3490673 HR |
488 | return 0; |
489 | } | |
490 | ||
491 | static int navi10_store_powerplay_table(struct smu_context *smu) | |
492 | { | |
493 | struct smu_11_0_powerplay_table *powerplay_table = NULL; | |
494 | struct smu_table_context *table_context = &smu->smu_table; | |
767acabd | 495 | struct smu_baco_context *smu_baco = &smu->smu_baco; |
b3490673 HR |
496 | |
497 | if (!table_context->power_play_table) | |
498 | return -EINVAL; | |
499 | ||
500 | powerplay_table = table_context->power_play_table; | |
501 | ||
502 | memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable, | |
503 | sizeof(PPTable_t)); | |
504 | ||
5e6d2665 KW |
505 | table_context->thermal_controller_type = powerplay_table->thermal_controller_type; |
506 | ||
767acabd KW |
507 | mutex_lock(&smu_baco->mutex); |
508 | if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_BACO || | |
509 | powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_MACO) | |
510 | smu_baco->platform_support = true; | |
511 | mutex_unlock(&smu_baco->mutex); | |
512 | ||
b3490673 HR |
513 | return 0; |
514 | } | |
515 | ||
62b9a88c | 516 | static int navi10_tables_init(struct smu_context *smu, struct smu_table *tables) |
22c9c6ca HR |
517 | { |
518 | SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), | |
519 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
520 | SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), | |
521 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
522 | SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), | |
523 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
524 | SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t), | |
525 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
526 | SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE, | |
527 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
528 | SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, | |
529 | sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, | |
530 | AMDGPU_GEM_DOMAIN_VRAM); | |
9634de27 HZ |
531 | |
532 | return 0; | |
22c9c6ca HR |
533 | } |
534 | ||
b3490673 HR |
535 | static int navi10_allocate_dpm_context(struct smu_context *smu) |
536 | { | |
537 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
538 | ||
539 | if (smu_dpm->dpm_context) | |
540 | return -EINVAL; | |
541 | ||
542 | smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), | |
543 | GFP_KERNEL); | |
544 | if (!smu_dpm->dpm_context) | |
545 | return -ENOMEM; | |
546 | ||
547 | smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context); | |
548 | ||
549 | return 0; | |
550 | } | |
551 | ||
552 | static int navi10_set_default_dpm_table(struct smu_context *smu) | |
553 | { | |
554 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
555 | struct smu_table_context *table_context = &smu->smu_table; | |
556 | struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; | |
557 | PPTable_t *driver_ppt = NULL; | |
558 | ||
559 | driver_ppt = table_context->driver_pptable; | |
560 | ||
561 | dpm_context->dpm_tables.soc_table.min = driver_ppt->FreqTableSocclk[0]; | |
562 | dpm_context->dpm_tables.soc_table.max = driver_ppt->FreqTableSocclk[NUM_SOCCLK_DPM_LEVELS - 1]; | |
563 | ||
564 | dpm_context->dpm_tables.gfx_table.min = driver_ppt->FreqTableGfx[0]; | |
565 | dpm_context->dpm_tables.gfx_table.max = driver_ppt->FreqTableGfx[NUM_GFXCLK_DPM_LEVELS - 1]; | |
566 | ||
567 | dpm_context->dpm_tables.uclk_table.min = driver_ppt->FreqTableUclk[0]; | |
568 | dpm_context->dpm_tables.uclk_table.max = driver_ppt->FreqTableUclk[NUM_UCLK_DPM_LEVELS - 1]; | |
569 | ||
570 | dpm_context->dpm_tables.vclk_table.min = driver_ppt->FreqTableVclk[0]; | |
571 | dpm_context->dpm_tables.vclk_table.max = driver_ppt->FreqTableVclk[NUM_VCLK_DPM_LEVELS - 1]; | |
572 | ||
573 | dpm_context->dpm_tables.dclk_table.min = driver_ppt->FreqTableDclk[0]; | |
574 | dpm_context->dpm_tables.dclk_table.max = driver_ppt->FreqTableDclk[NUM_DCLK_DPM_LEVELS - 1]; | |
575 | ||
576 | dpm_context->dpm_tables.dcef_table.min = driver_ppt->FreqTableDcefclk[0]; | |
577 | dpm_context->dpm_tables.dcef_table.max = driver_ppt->FreqTableDcefclk[NUM_DCEFCLK_DPM_LEVELS - 1]; | |
578 | ||
579 | dpm_context->dpm_tables.pixel_table.min = driver_ppt->FreqTablePixclk[0]; | |
580 | dpm_context->dpm_tables.pixel_table.max = driver_ppt->FreqTablePixclk[NUM_PIXCLK_DPM_LEVELS - 1]; | |
581 | ||
582 | dpm_context->dpm_tables.display_table.min = driver_ppt->FreqTableDispclk[0]; | |
583 | dpm_context->dpm_tables.display_table.max = driver_ppt->FreqTableDispclk[NUM_DISPCLK_DPM_LEVELS - 1]; | |
584 | ||
585 | dpm_context->dpm_tables.phy_table.min = driver_ppt->FreqTablePhyclk[0]; | |
586 | dpm_context->dpm_tables.phy_table.max = driver_ppt->FreqTablePhyclk[NUM_PHYCLK_DPM_LEVELS - 1]; | |
587 | ||
588 | return 0; | |
589 | } | |
590 | ||
a8179d62 KF |
591 | static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool enable) |
592 | { | |
593 | int ret = 0; | |
162aa5c3 KF |
594 | struct smu_power_context *smu_power = &smu->smu_power; |
595 | struct smu_power_gate *power_gate = &smu_power->power_gate; | |
a8179d62 | 596 | |
162aa5c3 | 597 | if (enable && power_gate->uvd_gated) { |
b2136465 EQ |
598 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { |
599 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 1); | |
600 | if (ret) | |
601 | return ret; | |
602 | } | |
162aa5c3 | 603 | power_gate->uvd_gated = false; |
a8179d62 | 604 | } else { |
162aa5c3 | 605 | if (!enable && !power_gate->uvd_gated) { |
b2136465 EQ |
606 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { |
607 | ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn); | |
608 | if (ret) | |
609 | return ret; | |
610 | } | |
162aa5c3 KF |
611 | power_gate->uvd_gated = true; |
612 | } | |
a8179d62 KF |
613 | } |
614 | ||
615 | return 0; | |
616 | } | |
617 | ||
98e1a543 KW |
618 | static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, |
619 | enum smu_clk_type clk_type, | |
620 | uint32_t *value) | |
621 | { | |
d693e8e3 | 622 | static SmuMetrics_t metrics; |
98e1a543 KW |
623 | int ret = 0, clk_id = 0; |
624 | ||
625 | if (!value) | |
626 | return -EINVAL; | |
627 | ||
d693e8e3 NC |
628 | memset(&metrics, 0, sizeof(metrics)); |
629 | ||
0d9d78b5 | 630 | ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false); |
98e1a543 KW |
631 | if (ret) |
632 | return ret; | |
633 | ||
634 | clk_id = smu_clk_get_index(smu, clk_type); | |
635 | if (clk_id < 0) | |
636 | return clk_id; | |
637 | ||
638 | *value = metrics.CurrClock[clk_id]; | |
639 | ||
640 | return ret; | |
641 | } | |
642 | ||
c49b1b59 KW |
643 | static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type) |
644 | { | |
645 | PPTable_t *pptable = smu->smu_table.driver_pptable; | |
646 | DpmDescriptor_t *dpm_desc = NULL; | |
647 | uint32_t clk_index = 0; | |
648 | ||
649 | clk_index = smu_clk_get_index(smu, clk_type); | |
650 | dpm_desc = &pptable->DpmDescriptor[clk_index]; | |
651 | ||
652 | /* 0 - Fine grained DPM, 1 - Discrete DPM */ | |
653 | return dpm_desc->SnapToDiscrete == 0 ? true : false; | |
654 | } | |
655 | ||
b1e7e224 KW |
656 | static int navi10_print_clk_levels(struct smu_context *smu, |
657 | enum smu_clk_type clk_type, char *buf) | |
658 | { | |
659 | int i, size = 0, ret = 0; | |
660 | uint32_t cur_value = 0, value = 0, count = 0; | |
c49b1b59 KW |
661 | uint32_t freq_values[3] = {0}; |
662 | uint32_t mark_index = 0; | |
b1e7e224 KW |
663 | |
664 | switch (clk_type) { | |
665 | case SMU_GFXCLK: | |
666 | case SMU_SCLK: | |
667 | case SMU_SOCCLK: | |
668 | case SMU_MCLK: | |
669 | case SMU_UCLK: | |
670 | case SMU_FCLK: | |
671 | case SMU_DCEFCLK: | |
672 | ret = smu_get_current_clk_freq(smu, clk_type, &cur_value); | |
673 | if (ret) | |
674 | return size; | |
c49b1b59 | 675 | |
e3618249 KW |
676 | /* 10KHz -> MHz */ |
677 | cur_value = cur_value / 100; | |
b1e7e224 | 678 | |
b1e7e224 KW |
679 | ret = smu_get_dpm_level_count(smu, clk_type, &count); |
680 | if (ret) | |
681 | return size; | |
682 | ||
c49b1b59 KW |
683 | if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) { |
684 | for (i = 0; i < count; i++) { | |
685 | ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &value); | |
686 | if (ret) | |
687 | return size; | |
688 | ||
689 | size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, | |
690 | cur_value == value ? "*" : ""); | |
691 | } | |
692 | } else { | |
693 | ret = smu_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); | |
694 | if (ret) | |
695 | return size; | |
696 | ret = smu_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); | |
b1e7e224 KW |
697 | if (ret) |
698 | return size; | |
699 | ||
c49b1b59 KW |
700 | freq_values[1] = cur_value; |
701 | mark_index = cur_value == freq_values[0] ? 0 : | |
702 | cur_value == freq_values[2] ? 2 : 1; | |
703 | if (mark_index != 1) | |
704 | freq_values[1] = (freq_values[0] + freq_values[2]) / 2; | |
705 | ||
706 | for (i = 0; i < 3; i++) { | |
707 | size += sprintf(buf + size, "%d: %uMhz %s\n", i, freq_values[i], | |
708 | i == mark_index ? "*" : ""); | |
709 | } | |
710 | ||
b1e7e224 KW |
711 | } |
712 | break; | |
713 | default: | |
714 | break; | |
715 | } | |
716 | ||
717 | return size; | |
718 | } | |
719 | ||
db439ca2 KW |
720 | static int navi10_force_clk_levels(struct smu_context *smu, |
721 | enum smu_clk_type clk_type, uint32_t mask) | |
722 | { | |
723 | ||
724 | int ret = 0, size = 0; | |
725 | uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0; | |
726 | ||
727 | soft_min_level = mask ? (ffs(mask) - 1) : 0; | |
728 | soft_max_level = mask ? (fls(mask) - 1) : 0; | |
729 | ||
730 | switch (clk_type) { | |
731 | case SMU_GFXCLK: | |
c0b9d6d2 | 732 | case SMU_SCLK: |
db439ca2 KW |
733 | case SMU_SOCCLK: |
734 | case SMU_MCLK: | |
735 | case SMU_UCLK: | |
736 | case SMU_DCEFCLK: | |
737 | case SMU_FCLK: | |
738 | ret = smu_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); | |
739 | if (ret) | |
740 | return size; | |
741 | ||
742 | ret = smu_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); | |
743 | if (ret) | |
744 | return size; | |
745 | ||
746 | ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq); | |
747 | if (ret) | |
748 | return size; | |
749 | break; | |
750 | default: | |
751 | break; | |
752 | } | |
753 | ||
754 | return size; | |
755 | } | |
756 | ||
fa51bfc2 KW |
757 | static int navi10_populate_umd_state_clk(struct smu_context *smu) |
758 | { | |
759 | int ret = 0; | |
64974ab2 | 760 | uint32_t min_sclk_freq = 0, min_mclk_freq = 0; |
fa51bfc2 KW |
761 | |
762 | ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, NULL); | |
763 | if (ret) | |
764 | return ret; | |
765 | ||
766 | smu->pstate_sclk = min_sclk_freq * 100; | |
767 | ||
64974ab2 KW |
768 | ret = smu_get_dpm_freq_range(smu, SMU_MCLK, &min_mclk_freq, NULL); |
769 | if (ret) | |
770 | return ret; | |
771 | ||
772 | smu->pstate_mclk = min_mclk_freq * 100; | |
773 | ||
fa51bfc2 KW |
774 | return ret; |
775 | } | |
776 | ||
a43913ea KW |
777 | static int navi10_get_clock_by_type_with_latency(struct smu_context *smu, |
778 | enum smu_clk_type clk_type, | |
779 | struct pp_clock_levels_with_latency *clocks) | |
780 | { | |
781 | int ret = 0, i = 0; | |
782 | uint32_t level_count = 0, freq = 0; | |
783 | ||
784 | switch (clk_type) { | |
785 | case SMU_GFXCLK: | |
786 | case SMU_DCEFCLK: | |
787 | case SMU_SOCCLK: | |
788 | ret = smu_get_dpm_level_count(smu, clk_type, &level_count); | |
789 | if (ret) | |
790 | return ret; | |
791 | ||
792 | level_count = min(level_count, (uint32_t)MAX_NUM_CLOCKS); | |
793 | clocks->num_levels = level_count; | |
794 | ||
795 | for (i = 0; i < level_count; i++) { | |
796 | ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &freq); | |
797 | if (ret) | |
798 | return ret; | |
799 | ||
800 | clocks->data[i].clocks_in_khz = freq * 1000; | |
801 | clocks->data[i].latency_in_us = 0; | |
802 | } | |
803 | break; | |
804 | default: | |
805 | break; | |
806 | } | |
807 | ||
808 | return ret; | |
809 | } | |
810 | ||
28430544 KW |
811 | static int navi10_pre_display_config_changed(struct smu_context *smu) |
812 | { | |
813 | int ret = 0; | |
814 | uint32_t max_freq = 0; | |
815 | ||
816 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0); | |
817 | if (ret) | |
818 | return ret; | |
819 | ||
820 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { | |
821 | ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &max_freq); | |
822 | if (ret) | |
823 | return ret; | |
824 | ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, max_freq); | |
825 | if (ret) | |
826 | return ret; | |
827 | } | |
828 | ||
829 | return ret; | |
830 | } | |
831 | ||
0a6430da KW |
832 | static int navi10_display_config_changed(struct smu_context *smu) |
833 | { | |
834 | int ret = 0; | |
835 | ||
836 | if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && | |
837 | !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { | |
838 | ret = smu_write_watermarks_table(smu); | |
839 | if (ret) | |
840 | return ret; | |
841 | ||
842 | smu->watermarks_bitmap |= WATERMARKS_LOADED; | |
843 | } | |
844 | ||
845 | if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && | |
846 | smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && | |
847 | smu_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { | |
848 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, | |
849 | smu->display_config->num_display); | |
850 | if (ret) | |
851 | return ret; | |
852 | } | |
853 | ||
854 | return ret; | |
855 | } | |
50add63b KW |
856 | |
857 | static int navi10_force_dpm_limit_value(struct smu_context *smu, bool highest) | |
858 | { | |
859 | int ret = 0, i = 0; | |
860 | uint32_t min_freq, max_freq, force_freq; | |
861 | enum smu_clk_type clk_type; | |
862 | ||
863 | enum smu_clk_type clks[] = { | |
864 | SMU_GFXCLK, | |
865 | SMU_MCLK, | |
866 | SMU_SOCCLK, | |
867 | }; | |
868 | ||
869 | for (i = 0; i < ARRAY_SIZE(clks); i++) { | |
870 | clk_type = clks[i]; | |
871 | ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq); | |
872 | if (ret) | |
873 | return ret; | |
874 | ||
875 | force_freq = highest ? max_freq : min_freq; | |
876 | ret = smu_set_soft_freq_range(smu, clk_type, force_freq, force_freq); | |
877 | if (ret) | |
878 | return ret; | |
879 | } | |
880 | ||
881 | return ret; | |
882 | } | |
883 | ||
42b3aa9a KW |
884 | static int navi10_unforce_dpm_levels(struct smu_context *smu) |
885 | { | |
2f72726b KW |
886 | int ret = 0, i = 0; |
887 | uint32_t min_freq, max_freq; | |
888 | enum smu_clk_type clk_type; | |
889 | ||
42b3aa9a KW |
890 | enum smu_clk_type clks[] = { |
891 | SMU_GFXCLK, | |
892 | SMU_MCLK, | |
893 | SMU_SOCCLK, | |
2f72726b KW |
894 | }; |
895 | ||
42b3aa9a KW |
896 | for (i = 0; i < ARRAY_SIZE(clks); i++) { |
897 | clk_type = clks[i]; | |
2f72726b KW |
898 | ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq); |
899 | if (ret) | |
900 | return ret; | |
901 | ||
902 | ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq); | |
903 | if (ret) | |
904 | return ret; | |
905 | } | |
906 | ||
907 | return ret; | |
908 | } | |
909 | ||
077ca74e KW |
910 | static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value) |
911 | { | |
912 | int ret = 0; | |
913 | SmuMetrics_t metrics; | |
914 | ||
915 | if (!value) | |
916 | return -EINVAL; | |
917 | ||
0d9d78b5 | 918 | ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, |
077ca74e KW |
919 | false); |
920 | if (ret) | |
921 | return ret; | |
922 | ||
39b27ffe | 923 | *value = metrics.AverageSocketPower << 8; |
077ca74e KW |
924 | |
925 | return 0; | |
926 | } | |
927 | ||
7447a23b | 928 | static int navi10_get_current_activity_percent(struct smu_context *smu, |
7f963d9f | 929 | enum amd_pp_sensors sensor, |
7447a23b KW |
930 | uint32_t *value) |
931 | { | |
932 | int ret = 0; | |
933 | SmuMetrics_t metrics; | |
934 | ||
935 | if (!value) | |
936 | return -EINVAL; | |
937 | ||
d5c31693 KW |
938 | msleep(1); |
939 | ||
0d9d78b5 | 940 | ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, |
7447a23b KW |
941 | (void *)&metrics, false); |
942 | if (ret) | |
943 | return ret; | |
944 | ||
7f963d9f AD |
945 | switch (sensor) { |
946 | case AMDGPU_PP_SENSOR_GPU_LOAD: | |
947 | *value = metrics.AverageGfxActivity; | |
948 | break; | |
949 | case AMDGPU_PP_SENSOR_MEM_LOAD: | |
950 | *value = metrics.AverageUclkActivity; | |
951 | break; | |
952 | default: | |
953 | pr_err("Invalid sensor for retrieving clock activity\n"); | |
954 | return -EINVAL; | |
955 | } | |
7447a23b KW |
956 | |
957 | return 0; | |
958 | } | |
959 | ||
4228b601 KW |
960 | static bool navi10_is_dpm_running(struct smu_context *smu) |
961 | { | |
962 | int ret = 0; | |
963 | uint32_t feature_mask[2]; | |
964 | unsigned long feature_enabled; | |
965 | ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); | |
966 | feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | | |
967 | ((uint64_t)feature_mask[1] << 32)); | |
968 | return !!(feature_enabled & SMC_DPM_FEATURE); | |
969 | } | |
970 | ||
95ccc155 AD |
971 | static int navi10_get_fan_speed_rpm(struct smu_context *smu, |
972 | uint32_t *speed) | |
ab43c4bf | 973 | { |
d693e8e3 | 974 | SmuMetrics_t metrics; |
ab43c4bf KW |
975 | int ret = 0; |
976 | ||
95ccc155 | 977 | if (!speed) |
ab43c4bf KW |
978 | return -EINVAL; |
979 | ||
d693e8e3 NC |
980 | memset(&metrics, 0, sizeof(metrics)); |
981 | ||
0d9d78b5 | 982 | ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, |
ab43c4bf KW |
983 | (void *)&metrics, false); |
984 | if (ret) | |
985 | return ret; | |
986 | ||
95ccc155 | 987 | *speed = metrics.CurrFanSpeed; |
ab43c4bf KW |
988 | |
989 | return ret; | |
990 | } | |
991 | ||
2d589a5b KW |
992 | static int navi10_get_fan_speed_percent(struct smu_context *smu, |
993 | uint32_t *speed) | |
994 | { | |
995 | int ret = 0; | |
996 | uint32_t percent = 0; | |
95ccc155 | 997 | uint32_t current_rpm; |
2d589a5b KW |
998 | PPTable_t *pptable = smu->smu_table.driver_pptable; |
999 | ||
95ccc155 | 1000 | ret = navi10_get_fan_speed_rpm(smu, ¤t_rpm); |
2d589a5b KW |
1001 | if (ret) |
1002 | return ret; | |
1003 | ||
1004 | percent = current_rpm * 100 / pptable->FanMaximumRpm; | |
1005 | *speed = percent > 100 ? 100 : percent; | |
1006 | ||
1007 | return ret; | |
1008 | } | |
1009 | ||
b45dc20b KW |
1010 | static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf) |
1011 | { | |
1012 | DpmActivityMonitorCoeffInt_t activity_monitor; | |
1013 | uint32_t i, size = 0; | |
c0640304 | 1014 | int16_t workload_type = 0; |
b45dc20b KW |
1015 | static const char *profile_name[] = { |
1016 | "BOOTUP_DEFAULT", | |
1017 | "3D_FULL_SCREEN", | |
1018 | "POWER_SAVING", | |
1019 | "VIDEO", | |
1020 | "VR", | |
1021 | "COMPUTE", | |
1022 | "CUSTOM"}; | |
1023 | static const char *title[] = { | |
1024 | "PROFILE_INDEX(NAME)", | |
1025 | "CLOCK_TYPE(NAME)", | |
1026 | "FPS", | |
1027 | "MinFreqType", | |
1028 | "MinActiveFreqType", | |
1029 | "MinActiveFreq", | |
1030 | "BoosterFreqType", | |
1031 | "BoosterFreq", | |
1032 | "PD_Data_limit_c", | |
1033 | "PD_Data_error_coeff", | |
1034 | "PD_Data_error_rate_coeff"}; | |
1035 | int result = 0; | |
1036 | ||
1037 | if (!buf) | |
1038 | return -EINVAL; | |
1039 | ||
1040 | size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n", | |
1041 | title[0], title[1], title[2], title[3], title[4], title[5], | |
1042 | title[6], title[7], title[8], title[9], title[10]); | |
1043 | ||
1044 | for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { | |
1045 | /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ | |
1046 | workload_type = smu_workload_get_type(smu, i); | |
c0640304 EQ |
1047 | if (workload_type < 0) |
1048 | return -EINVAL; | |
1049 | ||
b45dc20b | 1050 | result = smu_update_table(smu, |
0d9d78b5 | 1051 | SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type, |
b45dc20b KW |
1052 | (void *)(&activity_monitor), false); |
1053 | if (result) { | |
1054 | pr_err("[%s] Failed to get activity monitor!", __func__); | |
1055 | return result; | |
1056 | } | |
1057 | ||
1058 | size += sprintf(buf + size, "%2d %14s%s:\n", | |
1059 | i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " "); | |
1060 | ||
1061 | size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", | |
1062 | " ", | |
1063 | 0, | |
1064 | "GFXCLK", | |
1065 | activity_monitor.Gfx_FPS, | |
1066 | activity_monitor.Gfx_MinFreqStep, | |
1067 | activity_monitor.Gfx_MinActiveFreqType, | |
1068 | activity_monitor.Gfx_MinActiveFreq, | |
1069 | activity_monitor.Gfx_BoosterFreqType, | |
1070 | activity_monitor.Gfx_BoosterFreq, | |
1071 | activity_monitor.Gfx_PD_Data_limit_c, | |
1072 | activity_monitor.Gfx_PD_Data_error_coeff, | |
1073 | activity_monitor.Gfx_PD_Data_error_rate_coeff); | |
1074 | ||
1075 | size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", | |
1076 | " ", | |
1077 | 1, | |
1078 | "SOCCLK", | |
1079 | activity_monitor.Soc_FPS, | |
1080 | activity_monitor.Soc_MinFreqStep, | |
1081 | activity_monitor.Soc_MinActiveFreqType, | |
1082 | activity_monitor.Soc_MinActiveFreq, | |
1083 | activity_monitor.Soc_BoosterFreqType, | |
1084 | activity_monitor.Soc_BoosterFreq, | |
1085 | activity_monitor.Soc_PD_Data_limit_c, | |
1086 | activity_monitor.Soc_PD_Data_error_coeff, | |
1087 | activity_monitor.Soc_PD_Data_error_rate_coeff); | |
1088 | ||
1089 | size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", | |
1090 | " ", | |
1091 | 2, | |
1092 | "MEMLK", | |
1093 | activity_monitor.Mem_FPS, | |
1094 | activity_monitor.Mem_MinFreqStep, | |
1095 | activity_monitor.Mem_MinActiveFreqType, | |
1096 | activity_monitor.Mem_MinActiveFreq, | |
1097 | activity_monitor.Mem_BoosterFreqType, | |
1098 | activity_monitor.Mem_BoosterFreq, | |
1099 | activity_monitor.Mem_PD_Data_limit_c, | |
1100 | activity_monitor.Mem_PD_Data_error_coeff, | |
1101 | activity_monitor.Mem_PD_Data_error_rate_coeff); | |
1102 | } | |
1103 | ||
1104 | return size; | |
1105 | } | |
1106 | ||
1107 | static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) | |
1108 | { | |
1109 | DpmActivityMonitorCoeffInt_t activity_monitor; | |
1110 | int workload_type, ret = 0; | |
1111 | ||
1112 | smu->power_profile_mode = input[size]; | |
1113 | ||
1114 | if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { | |
1115 | pr_err("Invalid power profile mode %d\n", smu->power_profile_mode); | |
1116 | return -EINVAL; | |
1117 | } | |
1118 | ||
1119 | if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { | |
1120 | if (size < 0) | |
1121 | return -EINVAL; | |
1122 | ||
1123 | ret = smu_update_table(smu, | |
0d9d78b5 | 1124 | SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, |
b45dc20b KW |
1125 | (void *)(&activity_monitor), false); |
1126 | if (ret) { | |
1127 | pr_err("[%s] Failed to get activity monitor!", __func__); | |
1128 | return ret; | |
1129 | } | |
1130 | ||
1131 | switch (input[0]) { | |
1132 | case 0: /* Gfxclk */ | |
1133 | activity_monitor.Gfx_FPS = input[1]; | |
1134 | activity_monitor.Gfx_MinFreqStep = input[2]; | |
1135 | activity_monitor.Gfx_MinActiveFreqType = input[3]; | |
1136 | activity_monitor.Gfx_MinActiveFreq = input[4]; | |
1137 | activity_monitor.Gfx_BoosterFreqType = input[5]; | |
1138 | activity_monitor.Gfx_BoosterFreq = input[6]; | |
1139 | activity_monitor.Gfx_PD_Data_limit_c = input[7]; | |
1140 | activity_monitor.Gfx_PD_Data_error_coeff = input[8]; | |
1141 | activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9]; | |
1142 | break; | |
1143 | case 1: /* Socclk */ | |
1144 | activity_monitor.Soc_FPS = input[1]; | |
1145 | activity_monitor.Soc_MinFreqStep = input[2]; | |
1146 | activity_monitor.Soc_MinActiveFreqType = input[3]; | |
1147 | activity_monitor.Soc_MinActiveFreq = input[4]; | |
1148 | activity_monitor.Soc_BoosterFreqType = input[5]; | |
1149 | activity_monitor.Soc_BoosterFreq = input[6]; | |
1150 | activity_monitor.Soc_PD_Data_limit_c = input[7]; | |
1151 | activity_monitor.Soc_PD_Data_error_coeff = input[8]; | |
1152 | activity_monitor.Soc_PD_Data_error_rate_coeff = input[9]; | |
1153 | break; | |
1154 | case 2: /* Memlk */ | |
1155 | activity_monitor.Mem_FPS = input[1]; | |
1156 | activity_monitor.Mem_MinFreqStep = input[2]; | |
1157 | activity_monitor.Mem_MinActiveFreqType = input[3]; | |
1158 | activity_monitor.Mem_MinActiveFreq = input[4]; | |
1159 | activity_monitor.Mem_BoosterFreqType = input[5]; | |
1160 | activity_monitor.Mem_BoosterFreq = input[6]; | |
1161 | activity_monitor.Mem_PD_Data_limit_c = input[7]; | |
1162 | activity_monitor.Mem_PD_Data_error_coeff = input[8]; | |
1163 | activity_monitor.Mem_PD_Data_error_rate_coeff = input[9]; | |
1164 | break; | |
1165 | } | |
1166 | ||
1167 | ret = smu_update_table(smu, | |
0d9d78b5 | 1168 | SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, |
b45dc20b KW |
1169 | (void *)(&activity_monitor), true); |
1170 | if (ret) { | |
1171 | pr_err("[%s] Failed to set activity monitor!", __func__); | |
1172 | return ret; | |
1173 | } | |
1174 | } | |
1175 | ||
1176 | /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ | |
1177 | workload_type = smu_workload_get_type(smu, smu->power_profile_mode); | |
c0640304 EQ |
1178 | if (workload_type < 0) |
1179 | return -EINVAL; | |
b45dc20b KW |
1180 | smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, |
1181 | 1 << workload_type); | |
1182 | ||
1183 | return ret; | |
1184 | } | |
1185 | ||
2d9fb9b0 KW |
1186 | static int navi10_get_profiling_clk_mask(struct smu_context *smu, |
1187 | enum amd_dpm_forced_level level, | |
1188 | uint32_t *sclk_mask, | |
1189 | uint32_t *mclk_mask, | |
1190 | uint32_t *soc_mask) | |
1191 | { | |
1192 | int ret = 0; | |
1193 | uint32_t level_count = 0; | |
1194 | ||
1195 | if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { | |
1196 | if (sclk_mask) | |
1197 | *sclk_mask = 0; | |
1198 | } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { | |
1199 | if (mclk_mask) | |
1200 | *mclk_mask = 0; | |
1201 | } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { | |
1202 | if(sclk_mask) { | |
1203 | ret = smu_get_dpm_level_count(smu, SMU_SCLK, &level_count); | |
1204 | if (ret) | |
1205 | return ret; | |
1206 | *sclk_mask = level_count - 1; | |
1207 | } | |
1208 | ||
1209 | if(mclk_mask) { | |
1210 | ret = smu_get_dpm_level_count(smu, SMU_MCLK, &level_count); | |
1211 | if (ret) | |
1212 | return ret; | |
a54166d7 | 1213 | *mclk_mask = level_count - 1; |
2d9fb9b0 KW |
1214 | } |
1215 | ||
1216 | if(soc_mask) { | |
1217 | ret = smu_get_dpm_level_count(smu, SMU_SOCCLK, &level_count); | |
1218 | if (ret) | |
1219 | return ret; | |
a54166d7 | 1220 | *soc_mask = level_count - 1; |
2d9fb9b0 KW |
1221 | } |
1222 | } | |
1223 | ||
1224 | return ret; | |
1225 | } | |
1226 | ||
4f963b01 KW |
1227 | static int navi10_notify_smc_dispaly_config(struct smu_context *smu) |
1228 | { | |
1229 | struct smu_clocks min_clocks = {0}; | |
1230 | struct pp_display_clock_request clock_req; | |
1231 | int ret = 0; | |
1232 | ||
1233 | min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; | |
1234 | min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk; | |
1235 | min_clocks.memory_clock = smu->display_config->min_mem_set_clock; | |
1236 | ||
1237 | if (smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { | |
1238 | clock_req.clock_type = amd_pp_dcef_clock; | |
1239 | clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; | |
1240 | if (!smu_display_clock_voltage_request(smu, &clock_req)) { | |
1241 | if (smu_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) { | |
1242 | ret = smu_send_smc_msg_with_param(smu, | |
1243 | SMU_MSG_SetMinDeepSleepDcefclk, | |
1244 | min_clocks.dcef_clock_in_sr/100); | |
1245 | if (ret) { | |
1246 | pr_err("Attempt to set divider for DCEFCLK Failed!"); | |
1247 | return ret; | |
1248 | } | |
1249 | } | |
1250 | } else { | |
1251 | pr_info("Attempt to set Hard Min for DCEFCLK Failed!"); | |
1252 | } | |
1253 | } | |
1254 | ||
1255 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { | |
1256 | ret = smu_set_hard_freq_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0); | |
1257 | if (ret) { | |
1258 | pr_err("[%s] Set hard min uclk failed!", __func__); | |
1259 | return ret; | |
1260 | } | |
1261 | } | |
1262 | ||
1263 | return 0; | |
1264 | } | |
1265 | ||
5bbb0994 KW |
1266 | static int navi10_set_watermarks_table(struct smu_context *smu, |
1267 | void *watermarks, struct | |
1268 | dm_pp_wm_sets_with_clock_ranges_soc15 | |
1269 | *clock_ranges) | |
1270 | { | |
1271 | int i; | |
1272 | Watermarks_t *table = watermarks; | |
1273 | ||
1274 | if (!table || !clock_ranges) | |
1275 | return -EINVAL; | |
1276 | ||
1277 | if (clock_ranges->num_wm_dmif_sets > 4 || | |
1278 | clock_ranges->num_wm_mcif_sets > 4) | |
1279 | return -EINVAL; | |
1280 | ||
1281 | for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { | |
1282 | table->WatermarkRow[1][i].MinClock = | |
1283 | cpu_to_le16((uint16_t) | |
1284 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / | |
1285 | 1000)); | |
1286 | table->WatermarkRow[1][i].MaxClock = | |
1287 | cpu_to_le16((uint16_t) | |
1288 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / | |
1289 | 1000)); | |
1290 | table->WatermarkRow[1][i].MinUclk = | |
1291 | cpu_to_le16((uint16_t) | |
1292 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / | |
1293 | 1000)); | |
1294 | table->WatermarkRow[1][i].MaxUclk = | |
1295 | cpu_to_le16((uint16_t) | |
1296 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / | |
1297 | 1000)); | |
1298 | table->WatermarkRow[1][i].WmSetting = (uint8_t) | |
1299 | clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id; | |
1300 | } | |
1301 | ||
1302 | for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { | |
1303 | table->WatermarkRow[0][i].MinClock = | |
1304 | cpu_to_le16((uint16_t) | |
1305 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / | |
1306 | 1000)); | |
1307 | table->WatermarkRow[0][i].MaxClock = | |
1308 | cpu_to_le16((uint16_t) | |
1309 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / | |
1310 | 1000)); | |
1311 | table->WatermarkRow[0][i].MinUclk = | |
1312 | cpu_to_le16((uint16_t) | |
1313 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / | |
1314 | 1000)); | |
1315 | table->WatermarkRow[0][i].MaxUclk = | |
1316 | cpu_to_le16((uint16_t) | |
1317 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / | |
1318 | 1000)); | |
1319 | table->WatermarkRow[0][i].WmSetting = (uint8_t) | |
1320 | clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; | |
1321 | } | |
1322 | ||
1323 | return 0; | |
1324 | } | |
1325 | ||
e5aa29ce KW |
1326 | static int navi10_thermal_get_temperature(struct smu_context *smu, |
1327 | enum amd_pp_sensors sensor, | |
1328 | uint32_t *value) | |
1329 | { | |
1330 | SmuMetrics_t metrics; | |
1331 | int ret = 0; | |
1332 | ||
1333 | if (!value) | |
1334 | return -EINVAL; | |
1335 | ||
0d9d78b5 | 1336 | ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false); |
e5aa29ce KW |
1337 | if (ret) |
1338 | return ret; | |
1339 | ||
1340 | switch (sensor) { | |
1341 | case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: | |
1342 | *value = metrics.TemperatureHotspot * | |
1343 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
1344 | break; | |
1345 | case AMDGPU_PP_SENSOR_EDGE_TEMP: | |
1346 | *value = metrics.TemperatureEdge * | |
1347 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
1348 | break; | |
1349 | case AMDGPU_PP_SENSOR_MEM_TEMP: | |
1350 | *value = metrics.TemperatureMem * | |
1351 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
1352 | break; | |
1353 | default: | |
1354 | pr_err("Invalid sensor for retrieving temp\n"); | |
1355 | return -EINVAL; | |
1356 | } | |
1357 | ||
1358 | return 0; | |
1359 | } | |
1360 | ||
9c62f993 KW |
1361 | static int navi10_read_sensor(struct smu_context *smu, |
1362 | enum amd_pp_sensors sensor, | |
1363 | void *data, uint32_t *size) | |
1364 | { | |
1365 | int ret = 0; | |
1366 | struct smu_table_context *table_context = &smu->smu_table; | |
1367 | PPTable_t *pptable = table_context->driver_pptable; | |
1368 | ||
1369 | switch (sensor) { | |
1370 | case AMDGPU_PP_SENSOR_MAX_FAN_RPM: | |
1371 | *(uint32_t *)data = pptable->FanMaximumRpm; | |
1372 | *size = 4; | |
1373 | break; | |
7f963d9f | 1374 | case AMDGPU_PP_SENSOR_MEM_LOAD: |
d573bb21 | 1375 | case AMDGPU_PP_SENSOR_GPU_LOAD: |
7f963d9f | 1376 | ret = navi10_get_current_activity_percent(smu, sensor, (uint32_t *)data); |
d573bb21 KW |
1377 | *size = 4; |
1378 | break; | |
564c4c7f KW |
1379 | case AMDGPU_PP_SENSOR_GPU_POWER: |
1380 | ret = navi10_get_gpu_power(smu, (uint32_t *)data); | |
1381 | *size = 4; | |
1382 | break; | |
e5aa29ce KW |
1383 | case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: |
1384 | case AMDGPU_PP_SENSOR_EDGE_TEMP: | |
1385 | case AMDGPU_PP_SENSOR_MEM_TEMP: | |
1386 | ret = navi10_thermal_get_temperature(smu, sensor, (uint32_t *)data); | |
1387 | *size = 4; | |
1388 | break; | |
9c62f993 KW |
1389 | default: |
1390 | return -EINVAL; | |
1391 | } | |
1392 | ||
1393 | return ret; | |
1394 | } | |
1395 | ||
f4b3295f | 1396 | static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t *clocks_in_khz, uint32_t *num_states) |
1397 | { | |
1398 | uint32_t num_discrete_levels = 0; | |
1399 | uint16_t *dpm_levels = NULL; | |
1400 | uint16_t i = 0; | |
1401 | struct smu_table_context *table_context = &smu->smu_table; | |
1402 | PPTable_t *driver_ppt = NULL; | |
1403 | ||
1404 | if (!clocks_in_khz || !num_states || !table_context->driver_pptable) | |
1405 | return -EINVAL; | |
1406 | ||
1407 | driver_ppt = table_context->driver_pptable; | |
1408 | num_discrete_levels = driver_ppt->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels; | |
1409 | dpm_levels = driver_ppt->FreqTableUclk; | |
1410 | ||
1411 | if (num_discrete_levels == 0 || dpm_levels == NULL) | |
1412 | return -EINVAL; | |
1413 | ||
1414 | *num_states = num_discrete_levels; | |
1415 | for (i = 0; i < num_discrete_levels; i++) { | |
1416 | /* convert to khz */ | |
1417 | *clocks_in_khz = (*dpm_levels) * 1000; | |
1418 | clocks_in_khz++; | |
1419 | dpm_levels++; | |
1420 | } | |
1421 | ||
1422 | return 0; | |
1423 | } | |
1424 | ||
505ac303 EQ |
1425 | static int navi10_get_ppfeature_status(struct smu_context *smu, |
1426 | char *buf) | |
1427 | { | |
1428 | static const char *ppfeature_name[] = { | |
1429 | "DPM_PREFETCHER", | |
1430 | "DPM_GFXCLK", | |
1431 | "DPM_GFX_PACE", | |
1432 | "DPM_UCLK", | |
1433 | "DPM_SOCCLK", | |
1434 | "DPM_MP0CLK", | |
1435 | "DPM_LINK", | |
1436 | "DPM_DCEFCLK", | |
1437 | "MEM_VDDCI_SCALING", | |
1438 | "MEM_MVDD_SCALING", | |
1439 | "DS_GFXCLK", | |
1440 | "DS_SOCCLK", | |
1441 | "DS_LCLK", | |
1442 | "DS_DCEFCLK", | |
1443 | "DS_UCLK", | |
1444 | "GFX_ULV", | |
1445 | "FW_DSTATE", | |
1446 | "GFXOFF", | |
1447 | "BACO", | |
1448 | "VCN_PG", | |
1449 | "JPEG_PG", | |
1450 | "USB_PG", | |
1451 | "RSMU_SMN_CG", | |
1452 | "PPT", | |
1453 | "TDC", | |
1454 | "GFX_EDC", | |
1455 | "APCC_PLUS", | |
1456 | "GTHR", | |
1457 | "ACDC", | |
1458 | "VR0HOT", | |
1459 | "VR1HOT", | |
1460 | "FW_CTF", | |
1461 | "FAN_CONTROL", | |
1462 | "THERMAL", | |
1463 | "GFX_DCS", | |
1464 | "RM", | |
1465 | "LED_DISPLAY", | |
1466 | "GFX_SS", | |
1467 | "OUT_OF_BAND_MONITOR", | |
1468 | "TEMP_DEPENDENT_VMIN", | |
1469 | "MMHUB_PG", | |
1470 | "ATHUB_PG"}; | |
1471 | static const char *output_title[] = { | |
1472 | "FEATURES", | |
1473 | "BITMASK", | |
1474 | "ENABLEMENT"}; | |
1475 | uint64_t features_enabled; | |
1476 | uint32_t feature_mask[2]; | |
1477 | int i; | |
1478 | int ret = 0; | |
1479 | int size = 0; | |
1480 | ||
1481 | ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); | |
1482 | PP_ASSERT_WITH_CODE(!ret, | |
1483 | "[GetPPfeatureStatus] Failed to get enabled smc features!", | |
1484 | return ret); | |
1485 | features_enabled = (uint64_t)feature_mask[0] | | |
1486 | (uint64_t)feature_mask[1] << 32; | |
1487 | ||
1488 | size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled); | |
1489 | size += sprintf(buf + size, "%-19s %-22s %s\n", | |
1490 | output_title[0], | |
1491 | output_title[1], | |
1492 | output_title[2]); | |
1493 | for (i = 0; i < (sizeof(ppfeature_name) / sizeof(ppfeature_name[0])); i++) { | |
1494 | size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", | |
1495 | ppfeature_name[i], | |
1496 | 1ULL << i, | |
1497 | (features_enabled & (1ULL << i)) ? "Y" : "N"); | |
1498 | } | |
1499 | ||
1500 | return size; | |
1501 | } | |
1502 | ||
1503 | static int navi10_enable_smc_features(struct smu_context *smu, | |
1504 | bool enabled, | |
1505 | uint64_t feature_masks) | |
1506 | { | |
1507 | struct smu_feature *feature = &smu->smu_feature; | |
1508 | uint32_t feature_low, feature_high; | |
1509 | uint32_t feature_mask[2]; | |
1510 | int ret = 0; | |
1511 | ||
1512 | feature_low = (uint32_t)(feature_masks & 0xFFFFFFFF); | |
1513 | feature_high = (uint32_t)((feature_masks & 0xFFFFFFFF00000000ULL) >> 32); | |
1514 | ||
1515 | if (enabled) { | |
1516 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow, | |
1517 | feature_low); | |
1518 | if (ret) | |
1519 | return ret; | |
1520 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh, | |
1521 | feature_high); | |
1522 | if (ret) | |
1523 | return ret; | |
1524 | } else { | |
1525 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow, | |
1526 | feature_low); | |
1527 | if (ret) | |
1528 | return ret; | |
1529 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh, | |
1530 | feature_high); | |
1531 | if (ret) | |
1532 | return ret; | |
1533 | } | |
1534 | ||
1535 | ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); | |
1536 | if (ret) | |
1537 | return ret; | |
1538 | ||
1539 | mutex_lock(&feature->mutex); | |
1540 | bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, | |
1541 | feature->feature_num); | |
1542 | mutex_unlock(&feature->mutex); | |
1543 | ||
1544 | return 0; | |
1545 | } | |
1546 | ||
1547 | static int navi10_set_ppfeature_status(struct smu_context *smu, | |
1548 | uint64_t new_ppfeature_masks) | |
1549 | { | |
1550 | uint64_t features_enabled; | |
1551 | uint32_t feature_mask[2]; | |
1552 | uint64_t features_to_enable; | |
1553 | uint64_t features_to_disable; | |
1554 | int ret = 0; | |
1555 | ||
1556 | ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); | |
1557 | PP_ASSERT_WITH_CODE(!ret, | |
1558 | "[SetPPfeatureStatus] Failed to get enabled smc features!", | |
1559 | return ret); | |
1560 | features_enabled = (uint64_t)feature_mask[0] | | |
1561 | (uint64_t)feature_mask[1] << 32; | |
1562 | ||
1563 | features_to_disable = | |
1564 | features_enabled & ~new_ppfeature_masks; | |
1565 | features_to_enable = | |
1566 | ~features_enabled & new_ppfeature_masks; | |
1567 | ||
1568 | pr_debug("features_to_disable 0x%llx\n", features_to_disable); | |
1569 | pr_debug("features_to_enable 0x%llx\n", features_to_enable); | |
1570 | ||
1571 | if (features_to_disable) { | |
1572 | ret = navi10_enable_smc_features(smu, false, features_to_disable); | |
1573 | PP_ASSERT_WITH_CODE(!ret, | |
1574 | "[SetPPfeatureStatus] Failed to disable smc features!", | |
1575 | return ret); | |
1576 | } | |
1577 | ||
1578 | if (features_to_enable) { | |
1579 | ret = navi10_enable_smc_features(smu, true, features_to_enable); | |
1580 | PP_ASSERT_WITH_CODE(!ret, | |
1581 | "[SetPPfeatureStatus] Failed to enable smc features!", | |
1582 | return ret); | |
1583 | } | |
1584 | ||
1585 | return 0; | |
1586 | } | |
1587 | ||
ebf8fc31 KW |
1588 | static int navi10_set_peak_clock_by_device(struct smu_context *smu) |
1589 | { | |
1590 | struct amdgpu_device *adev = smu->adev; | |
1591 | int ret = 0; | |
1592 | uint32_t sclk_freq = 0, uclk_freq = 0; | |
1593 | uint32_t uclk_level = 0; | |
1594 | ||
1595 | switch (adev->rev_id) { | |
1596 | case 0xf0: /* XTX */ | |
1597 | case 0xc0: | |
1598 | sclk_freq = NAVI10_PEAK_SCLK_XTX; | |
1599 | break; | |
1600 | case 0xf1: /* XT */ | |
1601 | case 0xc1: | |
1602 | sclk_freq = NAVI10_PEAK_SCLK_XT; | |
1603 | break; | |
1604 | default: /* XL */ | |
1605 | sclk_freq = NAVI10_PEAK_SCLK_XL; | |
1606 | break; | |
1607 | } | |
1608 | ||
1609 | ret = smu_get_dpm_level_count(smu, SMU_UCLK, &uclk_level); | |
1610 | if (ret) | |
1611 | return ret; | |
1612 | ret = smu_get_dpm_freq_by_index(smu, SMU_UCLK, uclk_level - 1, &uclk_freq); | |
1613 | if (ret) | |
1614 | return ret; | |
1615 | ||
1616 | ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq); | |
1617 | if (ret) | |
1618 | return ret; | |
1619 | ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq); | |
1620 | if (ret) | |
1621 | return ret; | |
1622 | ||
1623 | return ret; | |
1624 | } | |
1625 | ||
1626 | static int navi10_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) | |
1627 | { | |
1628 | int ret = 0; | |
1629 | ||
1630 | switch (level) { | |
1631 | case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: | |
1632 | ret = navi10_set_peak_clock_by_device(smu); | |
1633 | break; | |
1634 | default: | |
1635 | ret = -EINVAL; | |
1636 | break; | |
1637 | } | |
1638 | ||
1639 | return ret; | |
1640 | } | |
1641 | ||
b3490673 | 1642 | static const struct pptable_funcs navi10_ppt_funcs = { |
22c9c6ca | 1643 | .tables_init = navi10_tables_init, |
b3490673 HR |
1644 | .alloc_dpm_context = navi10_allocate_dpm_context, |
1645 | .store_powerplay_table = navi10_store_powerplay_table, | |
1646 | .check_powerplay_table = navi10_check_powerplay_table, | |
1647 | .append_powerplay_table = navi10_append_powerplay_table, | |
1648 | .get_smu_msg_index = navi10_get_smu_msg_index, | |
0de94acf | 1649 | .get_smu_clk_index = navi10_get_smu_clk_index, |
ffcb08df | 1650 | .get_smu_feature_index = navi10_get_smu_feature_index, |
2436911b | 1651 | .get_smu_table_index = navi10_get_smu_table_index, |
8890fe5f | 1652 | .get_smu_power_index = navi10_get_pwr_src_index, |
6c6187ec | 1653 | .get_workload_type = navi10_get_workload_type, |
74c958a3 | 1654 | .get_allowed_feature_mask = navi10_get_allowed_feature_mask, |
b3490673 | 1655 | .set_default_dpm_table = navi10_set_default_dpm_table, |
a8179d62 | 1656 | .dpm_set_uvd_enable = navi10_dpm_set_uvd_enable, |
98e1a543 | 1657 | .get_current_clk_freq_by_table = navi10_get_current_clk_freq_by_table, |
b1e7e224 | 1658 | .print_clk_levels = navi10_print_clk_levels, |
db439ca2 | 1659 | .force_clk_levels = navi10_force_clk_levels, |
fa51bfc2 | 1660 | .populate_umd_state_clk = navi10_populate_umd_state_clk, |
a43913ea | 1661 | .get_clock_by_type_with_latency = navi10_get_clock_by_type_with_latency, |
28430544 | 1662 | .pre_display_config_changed = navi10_pre_display_config_changed, |
0a6430da | 1663 | .display_config_changed = navi10_display_config_changed, |
4f963b01 | 1664 | .notify_smc_dispaly_config = navi10_notify_smc_dispaly_config, |
50add63b | 1665 | .force_dpm_limit_value = navi10_force_dpm_limit_value, |
2f72726b | 1666 | .unforce_dpm_levels = navi10_unforce_dpm_levels, |
4228b601 | 1667 | .is_dpm_running = navi10_is_dpm_running, |
2d589a5b | 1668 | .get_fan_speed_percent = navi10_get_fan_speed_percent, |
95ccc155 | 1669 | .get_fan_speed_rpm = navi10_get_fan_speed_rpm, |
b45dc20b KW |
1670 | .get_power_profile_mode = navi10_get_power_profile_mode, |
1671 | .set_power_profile_mode = navi10_set_power_profile_mode, | |
2d9fb9b0 | 1672 | .get_profiling_clk_mask = navi10_get_profiling_clk_mask, |
5bbb0994 | 1673 | .set_watermarks_table = navi10_set_watermarks_table, |
9c62f993 | 1674 | .read_sensor = navi10_read_sensor, |
f4b3295f | 1675 | .get_uclk_dpm_states = navi10_get_uclk_dpm_states, |
505ac303 EQ |
1676 | .get_ppfeature_status = navi10_get_ppfeature_status, |
1677 | .set_ppfeature_status = navi10_set_ppfeature_status, | |
ebf8fc31 | 1678 | .set_performance_level = navi10_set_performance_level, |
b3490673 HR |
1679 | }; |
1680 | ||
1681 | void navi10_set_ppt_funcs(struct smu_context *smu) | |
1682 | { | |
cdb0c632 HR |
1683 | struct smu_table_context *smu_table = &smu->smu_table; |
1684 | ||
b3490673 | 1685 | smu->ppt_funcs = &navi10_ppt_funcs; |
19d894b9 | 1686 | smu->smc_if_version = SMU11_DRIVER_IF_VERSION; |
cdb0c632 | 1687 | smu_table->table_count = TABLE_COUNT; |
b3490673 | 1688 | } |