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