Commit | Line | Data |
---|---|---|
9eb75d62 AL |
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 | ||
9eb75d62 AL |
26 | #include "amdgpu.h" |
27 | #include "amdgpu_smu.h" | |
9eb75d62 | 28 | #include "smu_v12_0_ppsmc.h" |
0a3c8424 | 29 | #include "smu12_driver_if.h" |
b5604512 | 30 | #include "smu_v12_0.h" |
9eb75d62 | 31 | #include "renoir_ppt.h" |
6c339f37 | 32 | #include "smu_cmn.h" |
9eb75d62 | 33 | |
55084d7f EQ |
34 | /* |
35 | * DO NOT use these for err/warn/info/debug messages. | |
36 | * Use dev_err, dev_warn, dev_info and dev_dbg instead. | |
37 | * They are more MGPU friendly. | |
38 | */ | |
39 | #undef pr_err | |
40 | #undef pr_warn | |
41 | #undef pr_info | |
42 | #undef pr_debug | |
9eb75d62 | 43 | |
6c339f37 EQ |
44 | static struct cmn2asic_msg_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = { |
45 | MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), | |
46 | MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), | |
47 | MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), | |
48 | MSG_MAP(PowerUpGfx, PPSMC_MSG_PowerUpGfx, 1), | |
49 | MSG_MAP(AllowGfxOff, PPSMC_MSG_EnableGfxOff, 1), | |
50 | MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisableGfxOff, 1), | |
51 | MSG_MAP(PowerDownIspByTile, PPSMC_MSG_PowerDownIspByTile, 1), | |
52 | MSG_MAP(PowerUpIspByTile, PPSMC_MSG_PowerUpIspByTile, 1), | |
53 | MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 1), | |
54 | MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 1), | |
55 | MSG_MAP(PowerDownSdma, PPSMC_MSG_PowerDownSdma, 1), | |
56 | MSG_MAP(PowerUpSdma, PPSMC_MSG_PowerUpSdma, 1), | |
57 | MSG_MAP(SetHardMinIspclkByFreq, PPSMC_MSG_SetHardMinIspclkByFreq, 1), | |
58 | MSG_MAP(SetHardMinVcn, PPSMC_MSG_SetHardMinVcn, 1), | |
59 | MSG_MAP(Spare1, PPSMC_MSG_spare1, 1), | |
60 | MSG_MAP(Spare2, PPSMC_MSG_spare2, 1), | |
61 | MSG_MAP(SetAllowFclkSwitch, PPSMC_MSG_SetAllowFclkSwitch, 1), | |
62 | MSG_MAP(SetMinVideoGfxclkFreq, PPSMC_MSG_SetMinVideoGfxclkFreq, 1), | |
63 | MSG_MAP(ActiveProcessNotify, PPSMC_MSG_ActiveProcessNotify, 1), | |
64 | MSG_MAP(SetCustomPolicy, PPSMC_MSG_SetCustomPolicy, 1), | |
65 | MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps, 1), | |
66 | MSG_MAP(NumOfDisplays, PPSMC_MSG_SetDisplayCount, 1), | |
67 | MSG_MAP(QueryPowerLimit, PPSMC_MSG_QueryPowerLimit, 1), | |
68 | MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), | |
69 | MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), | |
70 | MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), | |
71 | MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 1), | |
72 | MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDeviceDriverReset, 1), | |
73 | MSG_MAP(SetGfxclkOverdriveByFreqVid, PPSMC_MSG_SetGfxclkOverdriveByFreqVid, 1), | |
74 | MSG_MAP(SetHardMinDcfclkByFreq, PPSMC_MSG_SetHardMinDcfclkByFreq, 1), | |
75 | MSG_MAP(SetHardMinSocclkByFreq, PPSMC_MSG_SetHardMinSocclkByFreq, 1), | |
76 | MSG_MAP(ControlIgpuATS, PPSMC_MSG_ControlIgpuATS, 1), | |
77 | MSG_MAP(SetMinVideoFclkFreq, PPSMC_MSG_SetMinVideoFclkFreq, 1), | |
78 | MSG_MAP(SetMinDeepSleepDcfclk, PPSMC_MSG_SetMinDeepSleepDcfclk, 1), | |
79 | MSG_MAP(ForcePowerDownGfx, PPSMC_MSG_ForcePowerDownGfx, 1), | |
80 | MSG_MAP(SetPhyclkVoltageByFreq, PPSMC_MSG_SetPhyclkVoltageByFreq, 1), | |
81 | MSG_MAP(SetDppclkVoltageByFreq, PPSMC_MSG_SetDppclkVoltageByFreq, 1), | |
82 | MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn, 1), | |
83 | MSG_MAP(EnablePostCode, PPSMC_MSG_EnablePostCode, 1), | |
84 | MSG_MAP(GetGfxclkFrequency, PPSMC_MSG_GetGfxclkFrequency, 1), | |
85 | MSG_MAP(GetFclkFrequency, PPSMC_MSG_GetFclkFrequency, 1), | |
86 | MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxclkFrequency, 1), | |
87 | MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxclkFrequency, 1), | |
88 | MSG_MAP(SoftReset, PPSMC_MSG_SoftReset, 1), | |
89 | MSG_MAP(SetGfxCGPG, PPSMC_MSG_SetGfxCGPG, 1), | |
90 | MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), | |
91 | MSG_MAP(SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk, 1), | |
92 | MSG_MAP(SetSoftMaxSocclkByFreq, PPSMC_MSG_SetSoftMaxSocclkByFreq, 1), | |
93 | MSG_MAP(SetSoftMaxFclkByFreq, PPSMC_MSG_SetSoftMaxFclkByFreq, 1), | |
94 | MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn, 1), | |
95 | MSG_MAP(PowerGateMmHub, PPSMC_MSG_PowerGateMmHub, 1), | |
96 | MSG_MAP(UpdatePmeRestore, PPSMC_MSG_UpdatePmeRestore, 1), | |
97 | MSG_MAP(GpuChangeState, PPSMC_MSG_GpuChangeState, 1), | |
98 | MSG_MAP(SetPowerLimitPercentage, PPSMC_MSG_SetPowerLimitPercentage, 1), | |
99 | MSG_MAP(ForceGfxContentSave, PPSMC_MSG_ForceGfxContentSave, 1), | |
100 | MSG_MAP(EnableTmdp48MHzRefclkPwrDown, PPSMC_MSG_EnableTmdp48MHzRefclkPwrDown, 1), | |
101 | MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 1), | |
102 | MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 1), | |
103 | MSG_MAP(PowerGateAtHub, PPSMC_MSG_PowerGateAtHub, 1), | |
104 | MSG_MAP(SetSoftMinJpeg, PPSMC_MSG_SetSoftMinJpeg, 1), | |
105 | MSG_MAP(SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq, 1), | |
9eb75d62 AL |
106 | }; |
107 | ||
6c339f37 | 108 | static struct cmn2asic_mapping renoir_clk_map[SMU_CLK_COUNT] = { |
0b97bd6c XH |
109 | CLK_MAP(GFXCLK, CLOCK_GFXCLK), |
110 | CLK_MAP(SCLK, CLOCK_GFXCLK), | |
111 | CLK_MAP(SOCCLK, CLOCK_SOCCLK), | |
781345f9 PL |
112 | CLK_MAP(UCLK, CLOCK_FCLK), |
113 | CLK_MAP(MCLK, CLOCK_FCLK), | |
0b97bd6c XH |
114 | }; |
115 | ||
6c339f37 | 116 | static struct cmn2asic_mapping renoir_table_map[SMU_TABLE_COUNT] = { |
1405ac8f AL |
117 | TAB_MAP_VALID(WATERMARKS), |
118 | TAB_MAP_INVALID(CUSTOM_DPM), | |
119 | TAB_MAP_VALID(DPMCLOCKS), | |
120 | TAB_MAP_VALID(SMU_METRICS), | |
121 | }; | |
122 | ||
6c339f37 EQ |
123 | static struct cmn2asic_mapping renoir_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { |
124 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), | |
125 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, WORKLOAD_PPLIB_VIDEO_BIT), | |
126 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, WORKLOAD_PPLIB_VR_BIT), | |
127 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_COMPUTE_BIT), | |
128 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), | |
129 | }; | |
130 | ||
c1b353b7 | 131 | static int renoir_init_smc_tables(struct smu_context *smu) |
049284bd | 132 | { |
723d4735 | 133 | struct smu_table_context *smu_table = &smu->smu_table; |
c1b353b7 | 134 | struct smu_table *tables = smu_table->tables; |
723d4735 | 135 | |
049284bd AL |
136 | SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), |
137 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
138 | SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t), | |
139 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
140 | SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), | |
141 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
142 | ||
723d4735 AL |
143 | smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); |
144 | if (!smu_table->clocks_table) | |
95868b85 | 145 | goto err0_out; |
723d4735 | 146 | |
30b2c0ca | 147 | smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); |
148 | if (!smu_table->metrics_table) | |
95868b85 | 149 | goto err1_out; |
30b2c0ca | 150 | smu_table->metrics_time = 0; |
151 | ||
9fa1ed5b EQ |
152 | smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); |
153 | if (!smu_table->watermarks_table) | |
95868b85 EQ |
154 | goto err2_out; |
155 | ||
156 | smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_0); | |
157 | smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); | |
158 | if (!smu_table->gpu_metrics_table) | |
159 | goto err3_out; | |
9fa1ed5b | 160 | |
049284bd | 161 | return 0; |
95868b85 EQ |
162 | |
163 | err3_out: | |
164 | kfree(smu_table->watermarks_table); | |
165 | err2_out: | |
166 | kfree(smu_table->metrics_table); | |
167 | err1_out: | |
168 | kfree(smu_table->clocks_table); | |
169 | err0_out: | |
170 | return -ENOMEM; | |
049284bd AL |
171 | } |
172 | ||
eee3258e PL |
173 | /** |
174 | * This interface just for getting uclk ultimate freq and should't introduce | |
175 | * other likewise function result in overmuch callback. | |
176 | */ | |
ef5af37a PL |
177 | static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type, |
178 | uint32_t dpm_level, uint32_t *freq) | |
eee3258e | 179 | { |
ef5af37a | 180 | DpmClocks_t *clk_table = smu->smu_table.clocks_table; |
eee3258e | 181 | |
ef5af37a | 182 | if (!clk_table || clk_type >= SMU_CLK_COUNT) |
eee3258e PL |
183 | return -EINVAL; |
184 | ||
982d68b0 EQ |
185 | switch (clk_type) { |
186 | case SMU_SOCCLK: | |
187 | if (dpm_level >= NUM_SOCCLK_DPM_LEVELS) | |
188 | return -EINVAL; | |
189 | *freq = clk_table->SocClocks[dpm_level].Freq; | |
190 | break; | |
191 | case SMU_MCLK: | |
192 | if (dpm_level >= NUM_FCLK_DPM_LEVELS) | |
193 | return -EINVAL; | |
194 | *freq = clk_table->FClocks[dpm_level].Freq; | |
195 | break; | |
196 | case SMU_DCEFCLK: | |
197 | if (dpm_level >= NUM_DCFCLK_DPM_LEVELS) | |
198 | return -EINVAL; | |
199 | *freq = clk_table->DcfClocks[dpm_level].Freq; | |
200 | break; | |
201 | case SMU_FCLK: | |
202 | if (dpm_level >= NUM_FCLK_DPM_LEVELS) | |
203 | return -EINVAL; | |
204 | *freq = clk_table->FClocks[dpm_level].Freq; | |
205 | break; | |
206 | default: | |
207 | return -EINVAL; | |
208 | } | |
209 | ||
210 | return 0; | |
211 | } | |
212 | ||
213 | static int renoir_get_profiling_clk_mask(struct smu_context *smu, | |
214 | enum amd_dpm_forced_level level, | |
215 | uint32_t *sclk_mask, | |
216 | uint32_t *mclk_mask, | |
217 | uint32_t *soc_mask) | |
218 | { | |
219 | ||
220 | if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { | |
221 | if (sclk_mask) | |
222 | *sclk_mask = 0; | |
223 | } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { | |
224 | if (mclk_mask) | |
225 | *mclk_mask = 0; | |
226 | } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { | |
227 | if(sclk_mask) | |
228 | /* The sclk as gfxclk and has three level about max/min/current */ | |
229 | *sclk_mask = 3 - 1; | |
230 | ||
231 | if(mclk_mask) | |
232 | *mclk_mask = NUM_MEMCLK_DPM_LEVELS - 1; | |
233 | ||
234 | if(soc_mask) | |
235 | *soc_mask = NUM_SOCCLK_DPM_LEVELS - 1; | |
236 | } | |
eee3258e PL |
237 | |
238 | return 0; | |
eee3258e PL |
239 | } |
240 | ||
982d68b0 EQ |
241 | static int renoir_get_dpm_ultimate_freq(struct smu_context *smu, |
242 | enum smu_clk_type clk_type, | |
243 | uint32_t *min, | |
244 | uint32_t *max) | |
245 | { | |
246 | int ret = 0; | |
247 | uint32_t mclk_mask, soc_mask; | |
248 | uint32_t clock_limit; | |
249 | ||
a7bae061 | 250 | if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) { |
982d68b0 EQ |
251 | switch (clk_type) { |
252 | case SMU_MCLK: | |
253 | case SMU_UCLK: | |
254 | clock_limit = smu->smu_table.boot_values.uclk; | |
255 | break; | |
256 | case SMU_GFXCLK: | |
257 | case SMU_SCLK: | |
258 | clock_limit = smu->smu_table.boot_values.gfxclk; | |
259 | break; | |
260 | case SMU_SOCCLK: | |
261 | clock_limit = smu->smu_table.boot_values.socclk; | |
262 | break; | |
263 | default: | |
264 | clock_limit = 0; | |
265 | break; | |
266 | } | |
267 | ||
268 | /* clock in Mhz unit */ | |
269 | if (min) | |
270 | *min = clock_limit / 100; | |
271 | if (max) | |
272 | *max = clock_limit / 100; | |
273 | ||
274 | return 0; | |
275 | } | |
276 | ||
277 | if (max) { | |
278 | ret = renoir_get_profiling_clk_mask(smu, | |
279 | AMD_DPM_FORCED_LEVEL_PROFILE_PEAK, | |
280 | NULL, | |
281 | &mclk_mask, | |
282 | &soc_mask); | |
283 | if (ret) | |
284 | goto failed; | |
285 | ||
286 | switch (clk_type) { | |
287 | case SMU_GFXCLK: | |
288 | case SMU_SCLK: | |
66c86828 | 289 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMaxGfxclkFrequency, max); |
982d68b0 EQ |
290 | if (ret) { |
291 | dev_err(smu->adev->dev, "Attempt to get max GX frequency from SMC Failed !\n"); | |
292 | goto failed; | |
293 | } | |
294 | break; | |
295 | case SMU_UCLK: | |
296 | case SMU_FCLK: | |
297 | case SMU_MCLK: | |
298 | ret = renoir_get_dpm_clk_limited(smu, clk_type, mclk_mask, max); | |
299 | if (ret) | |
300 | goto failed; | |
301 | break; | |
302 | case SMU_SOCCLK: | |
303 | ret = renoir_get_dpm_clk_limited(smu, clk_type, soc_mask, max); | |
304 | if (ret) | |
305 | goto failed; | |
306 | break; | |
307 | default: | |
308 | ret = -EINVAL; | |
309 | goto failed; | |
310 | } | |
311 | } | |
312 | ||
313 | if (min) { | |
314 | switch (clk_type) { | |
315 | case SMU_GFXCLK: | |
316 | case SMU_SCLK: | |
66c86828 | 317 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMinGfxclkFrequency, min); |
982d68b0 EQ |
318 | if (ret) { |
319 | dev_err(smu->adev->dev, "Attempt to get min GX frequency from SMC Failed !\n"); | |
320 | goto failed; | |
321 | } | |
322 | break; | |
323 | case SMU_UCLK: | |
324 | case SMU_FCLK: | |
325 | case SMU_MCLK: | |
326 | ret = renoir_get_dpm_clk_limited(smu, clk_type, 0, min); | |
327 | if (ret) | |
328 | goto failed; | |
329 | break; | |
330 | case SMU_SOCCLK: | |
331 | ret = renoir_get_dpm_clk_limited(smu, clk_type, 0, min); | |
332 | if (ret) | |
333 | goto failed; | |
334 | break; | |
335 | default: | |
336 | ret = -EINVAL; | |
337 | goto failed; | |
338 | } | |
339 | } | |
340 | failed: | |
341 | return ret; | |
342 | } | |
343 | ||
6ab3b9e3 PL |
344 | static int renoir_print_clk_levels(struct smu_context *smu, |
345 | enum smu_clk_type clk_type, char *buf) | |
346 | { | |
347 | int i, size = 0, ret = 0; | |
348 | uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0; | |
d9420705 | 349 | SmuMetrics_t metrics; |
575b0a6e | 350 | bool cur_value_match_level = false; |
6ab3b9e3 | 351 | |
d9420705 RR |
352 | memset(&metrics, 0, sizeof(metrics)); |
353 | ||
fceafc9b | 354 | ret = smu_cmn_get_metrics_table(smu, &metrics, false); |
6ab3b9e3 PL |
355 | if (ret) |
356 | return ret; | |
357 | ||
358 | switch (clk_type) { | |
359 | case SMU_GFXCLK: | |
360 | case SMU_SCLK: | |
361 | /* retirve table returned paramters unit is MHz */ | |
362 | cur_value = metrics.ClockFrequency[CLOCK_GFXCLK]; | |
982d68b0 | 363 | ret = renoir_get_dpm_ultimate_freq(smu, SMU_GFXCLK, &min, &max); |
6ab3b9e3 PL |
364 | if (!ret) { |
365 | /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */ | |
366 | if (cur_value == max) | |
367 | i = 2; | |
368 | else if (cur_value == min) | |
369 | i = 0; | |
370 | else | |
371 | i = 1; | |
372 | ||
373 | size += sprintf(buf + size, "0: %uMhz %s\n", min, | |
374 | i == 0 ? "*" : ""); | |
375 | size += sprintf(buf + size, "1: %uMhz %s\n", | |
376 | i == 1 ? cur_value : RENOIR_UMD_PSTATE_GFXCLK, | |
377 | i == 1 ? "*" : ""); | |
378 | size += sprintf(buf + size, "2: %uMhz %s\n", max, | |
379 | i == 2 ? "*" : ""); | |
380 | } | |
381 | return size; | |
382 | case SMU_SOCCLK: | |
383 | count = NUM_SOCCLK_DPM_LEVELS; | |
384 | cur_value = metrics.ClockFrequency[CLOCK_SOCCLK]; | |
385 | break; | |
386 | case SMU_MCLK: | |
387 | count = NUM_MEMCLK_DPM_LEVELS; | |
781345f9 | 388 | cur_value = metrics.ClockFrequency[CLOCK_FCLK]; |
6ab3b9e3 PL |
389 | break; |
390 | case SMU_DCEFCLK: | |
391 | count = NUM_DCFCLK_DPM_LEVELS; | |
392 | cur_value = metrics.ClockFrequency[CLOCK_DCFCLK]; | |
393 | break; | |
394 | case SMU_FCLK: | |
395 | count = NUM_FCLK_DPM_LEVELS; | |
396 | cur_value = metrics.ClockFrequency[CLOCK_FCLK]; | |
397 | break; | |
398 | default: | |
399 | return -EINVAL; | |
400 | } | |
401 | ||
402 | for (i = 0; i < count; i++) { | |
982d68b0 EQ |
403 | ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value); |
404 | if (ret) | |
405 | return ret; | |
5f6a92e4 YD |
406 | if (!value) |
407 | continue; | |
6ab3b9e3 PL |
408 | size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, |
409 | cur_value == value ? "*" : ""); | |
575b0a6e YD |
410 | if (cur_value == value) |
411 | cur_value_match_level = true; | |
6ab3b9e3 PL |
412 | } |
413 | ||
575b0a6e YD |
414 | if (!cur_value_match_level) |
415 | size += sprintf(buf + size, " %uMhz *\n", cur_value); | |
416 | ||
6ab3b9e3 PL |
417 | return size; |
418 | } | |
419 | ||
75a8957f PL |
420 | static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context *smu) |
421 | { | |
422 | enum amd_pm_state_type pm_type; | |
423 | struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); | |
424 | ||
425 | if (!smu_dpm_ctx->dpm_context || | |
426 | !smu_dpm_ctx->dpm_current_power_state) | |
427 | return -EINVAL; | |
428 | ||
75a8957f PL |
429 | switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) { |
430 | case SMU_STATE_UI_LABEL_BATTERY: | |
431 | pm_type = POWER_STATE_TYPE_BATTERY; | |
432 | break; | |
433 | case SMU_STATE_UI_LABEL_BALLANCED: | |
434 | pm_type = POWER_STATE_TYPE_BALANCED; | |
435 | break; | |
436 | case SMU_STATE_UI_LABEL_PERFORMANCE: | |
437 | pm_type = POWER_STATE_TYPE_PERFORMANCE; | |
438 | break; | |
439 | default: | |
440 | if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT) | |
441 | pm_type = POWER_STATE_TYPE_INTERNAL_BOOT; | |
442 | else | |
443 | pm_type = POWER_STATE_TYPE_DEFAULT; | |
444 | break; | |
445 | } | |
75a8957f PL |
446 | |
447 | return pm_type; | |
448 | } | |
449 | ||
f6b4b4a1 | 450 | static int renoir_dpm_set_vcn_enable(struct smu_context *smu, bool enable) |
08dac62f | 451 | { |
08dac62f PL |
452 | int ret = 0; |
453 | ||
454 | if (enable) { | |
455 | /* vcn dpm on is a prerequisite for vcn power gate messages */ | |
b4bb3aaf | 456 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { |
66c86828 | 457 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL); |
08dac62f PL |
458 | if (ret) |
459 | return ret; | |
460 | } | |
08dac62f | 461 | } else { |
b4bb3aaf | 462 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { |
66c86828 | 463 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL); |
08dac62f PL |
464 | if (ret) |
465 | return ret; | |
466 | } | |
08dac62f PL |
467 | } |
468 | ||
469 | return ret; | |
470 | } | |
471 | ||
a986e151 LL |
472 | static int renoir_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) |
473 | { | |
a986e151 LL |
474 | int ret = 0; |
475 | ||
476 | if (enable) { | |
b4bb3aaf | 477 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { |
66c86828 | 478 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL); |
a986e151 LL |
479 | if (ret) |
480 | return ret; | |
481 | } | |
a986e151 | 482 | } else { |
b4bb3aaf | 483 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { |
66c86828 | 484 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0, NULL); |
a986e151 LL |
485 | if (ret) |
486 | return ret; | |
487 | } | |
a986e151 LL |
488 | } |
489 | ||
490 | return ret; | |
491 | } | |
492 | ||
0b97bd6c XH |
493 | static int renoir_get_current_clk_freq_by_table(struct smu_context *smu, |
494 | enum smu_clk_type clk_type, | |
495 | uint32_t *value) | |
496 | { | |
497 | int ret = 0, clk_id = 0; | |
498 | SmuMetrics_t metrics; | |
499 | ||
fceafc9b | 500 | ret = smu_cmn_get_metrics_table(smu, &metrics, false); |
0b97bd6c XH |
501 | if (ret) |
502 | return ret; | |
503 | ||
6c339f37 EQ |
504 | clk_id = smu_cmn_to_asic_specific_index(smu, |
505 | CMN2ASIC_MAPPING_CLK, | |
506 | clk_type); | |
0b97bd6c XH |
507 | if (clk_id < 0) |
508 | return clk_id; | |
509 | ||
510 | *value = metrics.ClockFrequency[clk_id]; | |
511 | ||
512 | return ret; | |
513 | } | |
514 | ||
47e56b53 PL |
515 | static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest) |
516 | { | |
517 | int ret = 0, i = 0; | |
518 | uint32_t min_freq, max_freq, force_freq; | |
519 | enum smu_clk_type clk_type; | |
520 | ||
521 | enum smu_clk_type clks[] = { | |
522 | SMU_GFXCLK, | |
523 | SMU_MCLK, | |
524 | SMU_SOCCLK, | |
525 | }; | |
526 | ||
527 | for (i = 0; i < ARRAY_SIZE(clks); i++) { | |
528 | clk_type = clks[i]; | |
982d68b0 | 529 | ret = renoir_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq); |
47e56b53 PL |
530 | if (ret) |
531 | return ret; | |
532 | ||
533 | force_freq = highest ? max_freq : min_freq; | |
c98f31d1 | 534 | ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq); |
47e56b53 PL |
535 | if (ret) |
536 | return ret; | |
537 | } | |
538 | ||
539 | return ret; | |
540 | } | |
541 | ||
542 | static int renoir_unforce_dpm_levels(struct smu_context *smu) { | |
543 | ||
544 | int ret = 0, i = 0; | |
545 | uint32_t min_freq, max_freq; | |
546 | enum smu_clk_type clk_type; | |
547 | ||
548 | struct clk_feature_map { | |
549 | enum smu_clk_type clk_type; | |
550 | uint32_t feature; | |
551 | } clk_feature_map[] = { | |
552 | {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT}, | |
553 | {SMU_MCLK, SMU_FEATURE_DPM_UCLK_BIT}, | |
554 | {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT}, | |
555 | }; | |
556 | ||
557 | for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) { | |
b4bb3aaf | 558 | if (!smu_cmn_feature_is_enabled(smu, clk_feature_map[i].feature)) |
47e56b53 PL |
559 | continue; |
560 | ||
561 | clk_type = clk_feature_map[i].clk_type; | |
562 | ||
982d68b0 | 563 | ret = renoir_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq); |
47e56b53 PL |
564 | if (ret) |
565 | return ret; | |
566 | ||
c98f31d1 | 567 | ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); |
47e56b53 PL |
568 | if (ret) |
569 | return ret; | |
570 | } | |
571 | ||
572 | return ret; | |
573 | } | |
574 | ||
8fa6a7b0 XH |
575 | static int renoir_get_gpu_temperature(struct smu_context *smu, uint32_t *value) |
576 | { | |
577 | int ret = 0; | |
578 | SmuMetrics_t metrics; | |
579 | ||
580 | if (!value) | |
581 | return -EINVAL; | |
582 | ||
fceafc9b | 583 | ret = smu_cmn_get_metrics_table(smu, &metrics, false); |
8fa6a7b0 XH |
584 | if (ret) |
585 | return ret; | |
586 | ||
587 | *value = (metrics.GfxTemperature / 100) * | |
588 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
589 | ||
590 | return 0; | |
591 | } | |
592 | ||
30b2c0ca | 593 | static int renoir_get_current_activity_percent(struct smu_context *smu, |
594 | enum amd_pp_sensors sensor, | |
595 | uint32_t *value) | |
596 | { | |
597 | int ret = 0; | |
598 | SmuMetrics_t metrics; | |
599 | ||
600 | if (!value) | |
601 | return -EINVAL; | |
602 | ||
fceafc9b | 603 | ret = smu_cmn_get_metrics_table(smu, &metrics, false); |
30b2c0ca | 604 | if (ret) |
605 | return ret; | |
606 | ||
607 | switch (sensor) { | |
608 | case AMDGPU_PP_SENSOR_GPU_LOAD: | |
a0250689 | 609 | *value = metrics.AverageGfxActivity / 100; |
30b2c0ca | 610 | break; |
611 | default: | |
d9811cfc | 612 | dev_err(smu->adev->dev, "Invalid sensor for retrieving clock activity\n"); |
30b2c0ca | 613 | return -EINVAL; |
614 | } | |
615 | ||
616 | return 0; | |
617 | } | |
618 | ||
7bbdbe40 HW |
619 | /** |
620 | * This interface get dpm clock table for dc | |
621 | */ | |
622 | static int renoir_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table) | |
623 | { | |
624 | DpmClocks_t *table = smu->smu_table.clocks_table; | |
625 | int i; | |
626 | ||
627 | if (!clock_table || !table) | |
628 | return -EINVAL; | |
629 | ||
0e04ad7d | 630 | for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) { |
7bbdbe40 HW |
631 | clock_table->DcfClocks[i].Freq = table->DcfClocks[i].Freq; |
632 | clock_table->DcfClocks[i].Vol = table->DcfClocks[i].Vol; | |
633 | } | |
634 | ||
0e04ad7d | 635 | for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) { |
7bbdbe40 HW |
636 | clock_table->SocClocks[i].Freq = table->SocClocks[i].Freq; |
637 | clock_table->SocClocks[i].Vol = table->SocClocks[i].Vol; | |
638 | } | |
639 | ||
0e04ad7d | 640 | for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) { |
7bbdbe40 HW |
641 | clock_table->FClocks[i].Freq = table->FClocks[i].Freq; |
642 | clock_table->FClocks[i].Vol = table->FClocks[i].Vol; | |
643 | } | |
644 | ||
0e04ad7d | 645 | for (i = 0; i< NUM_MEMCLK_DPM_LEVELS; i++) { |
7bbdbe40 HW |
646 | clock_table->MemClocks[i].Freq = table->MemClocks[i].Freq; |
647 | clock_table->MemClocks[i].Vol = table->MemClocks[i].Vol; | |
648 | } | |
649 | ||
650 | return 0; | |
651 | } | |
652 | ||
2e5294fe PL |
653 | static int renoir_force_clk_levels(struct smu_context *smu, |
654 | enum smu_clk_type clk_type, uint32_t mask) | |
655 | { | |
656 | ||
657 | int ret = 0 ; | |
658 | uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0; | |
2e5294fe PL |
659 | |
660 | soft_min_level = mask ? (ffs(mask) - 1) : 0; | |
661 | soft_max_level = mask ? (fls(mask) - 1) : 0; | |
662 | ||
663 | switch (clk_type) { | |
664 | case SMU_GFXCLK: | |
665 | case SMU_SCLK: | |
666 | if (soft_min_level > 2 || soft_max_level > 2) { | |
d9811cfc | 667 | dev_info(smu->adev->dev, "Currently sclk only support 3 levels on APU\n"); |
2e5294fe PL |
668 | return -EINVAL; |
669 | } | |
670 | ||
982d68b0 | 671 | ret = renoir_get_dpm_ultimate_freq(smu, SMU_GFXCLK, &min_freq, &max_freq); |
2e5294fe PL |
672 | if (ret) |
673 | return ret; | |
66c86828 | 674 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, |
2e5294fe | 675 | soft_max_level == 0 ? min_freq : |
1c58267c MC |
676 | soft_max_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : max_freq, |
677 | NULL); | |
2e5294fe PL |
678 | if (ret) |
679 | return ret; | |
66c86828 | 680 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, |
2e5294fe | 681 | soft_min_level == 2 ? max_freq : |
1c58267c MC |
682 | soft_min_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : min_freq, |
683 | NULL); | |
2e5294fe PL |
684 | if (ret) |
685 | return ret; | |
686 | break; | |
687 | case SMU_SOCCLK: | |
982d68b0 EQ |
688 | ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_min_level, &min_freq); |
689 | if (ret) | |
690 | return ret; | |
691 | ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_max_level, &max_freq); | |
692 | if (ret) | |
693 | return ret; | |
66c86828 | 694 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max_freq, NULL); |
2e5294fe PL |
695 | if (ret) |
696 | return ret; | |
66c86828 | 697 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min_freq, NULL); |
2e5294fe PL |
698 | if (ret) |
699 | return ret; | |
700 | break; | |
701 | case SMU_MCLK: | |
702 | case SMU_FCLK: | |
982d68b0 EQ |
703 | ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_min_level, &min_freq); |
704 | if (ret) | |
705 | return ret; | |
706 | ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_max_level, &max_freq); | |
707 | if (ret) | |
708 | return ret; | |
66c86828 | 709 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max_freq, NULL); |
2e5294fe PL |
710 | if (ret) |
711 | return ret; | |
66c86828 | 712 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min_freq, NULL); |
2e5294fe PL |
713 | if (ret) |
714 | return ret; | |
715 | break; | |
716 | default: | |
717 | break; | |
718 | } | |
719 | ||
720 | return ret; | |
721 | } | |
722 | ||
ea286ed7 PL |
723 | static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) |
724 | { | |
725 | int workload_type, ret; | |
726 | uint32_t profile_mode = input[size]; | |
727 | ||
728 | if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { | |
4c8f126e | 729 | dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); |
ea286ed7 PL |
730 | return -EINVAL; |
731 | } | |
732 | ||
733 | /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ | |
6c339f37 EQ |
734 | workload_type = smu_cmn_to_asic_specific_index(smu, |
735 | CMN2ASIC_MAPPING_WORKLOAD, | |
736 | profile_mode); | |
ea286ed7 | 737 | if (workload_type < 0) { |
6a52d464 PL |
738 | /* |
739 | * TODO: If some case need switch to powersave/default power mode | |
740 | * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving. | |
741 | */ | |
4c8f126e | 742 | dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode); |
ea286ed7 PL |
743 | return -EINVAL; |
744 | } | |
745 | ||
66c86828 | 746 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify, |
1c58267c MC |
747 | 1 << workload_type, |
748 | NULL); | |
ea286ed7 | 749 | if (ret) { |
d9811cfc | 750 | dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type); |
ea286ed7 PL |
751 | return ret; |
752 | } | |
753 | ||
754 | smu->power_profile_mode = profile_mode; | |
755 | ||
756 | return 0; | |
757 | } | |
758 | ||
2cf8d416 PL |
759 | static int renoir_set_peak_clock_by_device(struct smu_context *smu) |
760 | { | |
761 | int ret = 0; | |
762 | uint32_t sclk_freq = 0, uclk_freq = 0; | |
763 | ||
982d68b0 | 764 | ret = renoir_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_freq); |
2cf8d416 PL |
765 | if (ret) |
766 | return ret; | |
767 | ||
c98f31d1 | 768 | ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_SCLK, sclk_freq, sclk_freq); |
2cf8d416 PL |
769 | if (ret) |
770 | return ret; | |
771 | ||
982d68b0 | 772 | ret = renoir_get_dpm_ultimate_freq(smu, SMU_UCLK, NULL, &uclk_freq); |
2cf8d416 PL |
773 | if (ret) |
774 | return ret; | |
775 | ||
c98f31d1 | 776 | ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_UCLK, uclk_freq, uclk_freq); |
2cf8d416 PL |
777 | if (ret) |
778 | return ret; | |
779 | ||
780 | return ret; | |
781 | } | |
782 | ||
337443d0 AD |
783 | static int renoir_set_performance_level(struct smu_context *smu, |
784 | enum amd_dpm_forced_level level) | |
2cf8d416 PL |
785 | { |
786 | int ret = 0; | |
337443d0 | 787 | uint32_t sclk_mask, mclk_mask, soc_mask; |
2cf8d416 PL |
788 | |
789 | switch (level) { | |
337443d0 | 790 | case AMD_DPM_FORCED_LEVEL_HIGH: |
d56ff011 | 791 | ret = renoir_force_dpm_limit_value(smu, true); |
337443d0 AD |
792 | break; |
793 | case AMD_DPM_FORCED_LEVEL_LOW: | |
d56ff011 | 794 | ret = renoir_force_dpm_limit_value(smu, false); |
337443d0 AD |
795 | break; |
796 | case AMD_DPM_FORCED_LEVEL_AUTO: | |
797 | case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: | |
d56ff011 | 798 | ret = renoir_unforce_dpm_levels(smu); |
337443d0 AD |
799 | break; |
800 | case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: | |
801 | case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: | |
d56ff011 EQ |
802 | ret = renoir_get_profiling_clk_mask(smu, level, |
803 | &sclk_mask, | |
804 | &mclk_mask, | |
805 | &soc_mask); | |
337443d0 AD |
806 | if (ret) |
807 | return ret; | |
d56ff011 EQ |
808 | renoir_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask); |
809 | renoir_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask); | |
810 | renoir_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask); | |
337443d0 | 811 | break; |
2cf8d416 PL |
812 | case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: |
813 | ret = renoir_set_peak_clock_by_device(smu); | |
814 | break; | |
337443d0 AD |
815 | case AMD_DPM_FORCED_LEVEL_MANUAL: |
816 | case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: | |
2cf8d416 | 817 | default: |
2cf8d416 PL |
818 | break; |
819 | } | |
2cf8d416 PL |
820 | return ret; |
821 | } | |
ea286ed7 | 822 | |
7bbdbe40 HW |
823 | /* save watermark settings into pplib smu structure, |
824 | * also pass data to smu controller | |
825 | */ | |
826 | static int renoir_set_watermarks_table( | |
827 | struct smu_context *smu, | |
7bbdbe40 HW |
828 | struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges) |
829 | { | |
e7a95eea | 830 | Watermarks_t *table = smu->smu_table.watermarks_table; |
7bbdbe40 | 831 | int ret = 0; |
e7a95eea | 832 | int i; |
7bbdbe40 | 833 | |
e7a95eea EQ |
834 | if (clock_ranges) { |
835 | if (clock_ranges->num_wm_dmif_sets > 4 || | |
836 | clock_ranges->num_wm_mcif_sets > 4) | |
837 | return -EINVAL; | |
7bbdbe40 | 838 | |
e7a95eea EQ |
839 | /* save into smu->smu_table.tables[SMU_TABLE_WATERMARKS]->cpu_addr*/ |
840 | for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { | |
841 | table->WatermarkRow[WM_DCFCLK][i].MinClock = | |
842 | cpu_to_le16((uint16_t) | |
843 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz)); | |
844 | table->WatermarkRow[WM_DCFCLK][i].MaxClock = | |
845 | cpu_to_le16((uint16_t) | |
846 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz)); | |
847 | table->WatermarkRow[WM_DCFCLK][i].MinMclk = | |
848 | cpu_to_le16((uint16_t) | |
849 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz)); | |
850 | table->WatermarkRow[WM_DCFCLK][i].MaxMclk = | |
851 | cpu_to_le16((uint16_t) | |
852 | (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz)); | |
853 | table->WatermarkRow[WM_DCFCLK][i].WmSetting = (uint8_t) | |
854 | clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id; | |
855 | } | |
7bbdbe40 | 856 | |
e7a95eea EQ |
857 | for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { |
858 | table->WatermarkRow[WM_SOCCLK][i].MinClock = | |
859 | cpu_to_le16((uint16_t) | |
860 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz)); | |
861 | table->WatermarkRow[WM_SOCCLK][i].MaxClock = | |
862 | cpu_to_le16((uint16_t) | |
863 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz)); | |
864 | table->WatermarkRow[WM_SOCCLK][i].MinMclk = | |
865 | cpu_to_le16((uint16_t) | |
866 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz)); | |
867 | table->WatermarkRow[WM_SOCCLK][i].MaxMclk = | |
868 | cpu_to_le16((uint16_t) | |
869 | (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz)); | |
870 | table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t) | |
871 | clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; | |
872 | } | |
7bbdbe40 | 873 | |
e7a95eea | 874 | smu->watermarks_bitmap |= WATERMARKS_EXIST; |
7bbdbe40 HW |
875 | } |
876 | ||
877 | /* pass data to smu controller */ | |
e7a95eea EQ |
878 | if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && |
879 | !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { | |
caad2613 | 880 | ret = smu_cmn_write_watermarks_table(smu); |
f1e1483b | 881 | if (ret) { |
d9811cfc | 882 | dev_err(smu->adev->dev, "Failed to update WMTABLE!"); |
f1e1483b ZL |
883 | return ret; |
884 | } | |
885 | smu->watermarks_bitmap |= WATERMARKS_LOADED; | |
886 | } | |
7bbdbe40 | 887 | |
f1e1483b | 888 | return 0; |
7bbdbe40 HW |
889 | } |
890 | ||
ad7ce43c PL |
891 | static int renoir_get_power_profile_mode(struct smu_context *smu, |
892 | char *buf) | |
893 | { | |
894 | static const char *profile_name[] = { | |
895 | "BOOTUP_DEFAULT", | |
896 | "3D_FULL_SCREEN", | |
897 | "POWER_SAVING", | |
898 | "VIDEO", | |
899 | "VR", | |
900 | "COMPUTE", | |
901 | "CUSTOM"}; | |
902 | uint32_t i, size = 0; | |
903 | int16_t workload_type = 0; | |
904 | ||
774e335b | 905 | if (!buf) |
ad7ce43c PL |
906 | return -EINVAL; |
907 | ||
908 | for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { | |
909 | /* | |
910 | * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT | |
911 | * Not all profile modes are supported on arcturus. | |
912 | */ | |
6c339f37 EQ |
913 | workload_type = smu_cmn_to_asic_specific_index(smu, |
914 | CMN2ASIC_MAPPING_WORKLOAD, | |
915 | i); | |
ad7ce43c PL |
916 | if (workload_type < 0) |
917 | continue; | |
918 | ||
919 | size += sprintf(buf + size, "%2d %14s%s\n", | |
920 | i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " "); | |
921 | } | |
922 | ||
923 | return size; | |
924 | } | |
925 | ||
30b2c0ca | 926 | static int renoir_read_sensor(struct smu_context *smu, |
927 | enum amd_pp_sensors sensor, | |
928 | void *data, uint32_t *size) | |
929 | { | |
930 | int ret = 0; | |
931 | ||
932 | if (!data || !size) | |
933 | return -EINVAL; | |
934 | ||
935 | mutex_lock(&smu->sensor_lock); | |
936 | switch (sensor) { | |
937 | case AMDGPU_PP_SENSOR_GPU_LOAD: | |
938 | ret = renoir_get_current_activity_percent(smu, sensor, (uint32_t *)data); | |
939 | *size = 4; | |
940 | break; | |
8fa6a7b0 XH |
941 | case AMDGPU_PP_SENSOR_GPU_TEMP: |
942 | ret = renoir_get_gpu_temperature(smu, (uint32_t *)data); | |
943 | *size = 4; | |
944 | break; | |
e0f9e936 EQ |
945 | case AMDGPU_PP_SENSOR_GFX_MCLK: |
946 | ret = renoir_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data); | |
947 | *(uint32_t *)data *= 100; | |
948 | *size = 4; | |
949 | break; | |
950 | case AMDGPU_PP_SENSOR_GFX_SCLK: | |
951 | ret = renoir_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data); | |
952 | *(uint32_t *)data *= 100; | |
953 | *size = 4; | |
954 | break; | |
30b2c0ca | 955 | default: |
b2febc99 EQ |
956 | ret = -EOPNOTSUPP; |
957 | break; | |
30b2c0ca | 958 | } |
959 | mutex_unlock(&smu->sensor_lock); | |
960 | ||
961 | return ret; | |
962 | } | |
963 | ||
567c8fc4 PL |
964 | static bool renoir_is_dpm_running(struct smu_context *smu) |
965 | { | |
4e2fec33 PL |
966 | struct amdgpu_device *adev = smu->adev; |
967 | ||
567c8fc4 | 968 | /* |
db3e0a28 | 969 | * Until now, the pmfw hasn't exported the interface of SMU |
567c8fc4 PL |
970 | * feature mask to APU SKU so just force on all the feature |
971 | * at early initial stage. | |
972 | */ | |
4e2fec33 PL |
973 | if (adev->in_suspend) |
974 | return false; | |
975 | else | |
976 | return true; | |
567c8fc4 PL |
977 | |
978 | } | |
979 | ||
95868b85 EQ |
980 | static ssize_t renoir_get_gpu_metrics(struct smu_context *smu, |
981 | void **table) | |
982 | { | |
983 | struct smu_table_context *smu_table = &smu->smu_table; | |
984 | struct gpu_metrics_v2_0 *gpu_metrics = | |
985 | (struct gpu_metrics_v2_0 *)smu_table->gpu_metrics_table; | |
986 | SmuMetrics_t metrics; | |
987 | int ret = 0; | |
988 | ||
fceafc9b | 989 | ret = smu_cmn_get_metrics_table(smu, &metrics, true); |
95868b85 EQ |
990 | if (ret) |
991 | return ret; | |
992 | ||
993 | smu_v12_0_init_gpu_metrics_v2_0(gpu_metrics); | |
994 | ||
995 | gpu_metrics->temperature_gfx = metrics.GfxTemperature; | |
996 | gpu_metrics->temperature_soc = metrics.SocTemperature; | |
997 | memcpy(&gpu_metrics->temperature_core[0], | |
998 | &metrics.CoreTemperature[0], | |
999 | sizeof(uint16_t) * 8); | |
1000 | gpu_metrics->temperature_l3[0] = metrics.L3Temperature[0]; | |
1001 | gpu_metrics->temperature_l3[1] = metrics.L3Temperature[1]; | |
1002 | ||
1003 | gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; | |
1004 | gpu_metrics->average_mm_activity = metrics.AverageUvdActivity; | |
1005 | ||
1006 | gpu_metrics->average_socket_power = metrics.CurrentSocketPower; | |
1007 | gpu_metrics->average_cpu_power = metrics.Power[0]; | |
1008 | gpu_metrics->average_soc_power = metrics.Power[1]; | |
1009 | memcpy(&gpu_metrics->average_core_power[0], | |
1010 | &metrics.CorePower[0], | |
1011 | sizeof(uint16_t) * 8); | |
1012 | ||
1013 | gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; | |
1014 | gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; | |
1015 | gpu_metrics->average_fclk_frequency = metrics.AverageFclkFrequency; | |
1016 | gpu_metrics->average_vclk_frequency = metrics.AverageVclkFrequency; | |
1017 | ||
1018 | gpu_metrics->current_gfxclk = metrics.ClockFrequency[CLOCK_GFXCLK]; | |
1019 | gpu_metrics->current_socclk = metrics.ClockFrequency[CLOCK_SOCCLK]; | |
1020 | gpu_metrics->current_uclk = metrics.ClockFrequency[CLOCK_UMCCLK]; | |
1021 | gpu_metrics->current_fclk = metrics.ClockFrequency[CLOCK_FCLK]; | |
1022 | gpu_metrics->current_vclk = metrics.ClockFrequency[CLOCK_VCLK]; | |
1023 | gpu_metrics->current_dclk = metrics.ClockFrequency[CLOCK_DCLK]; | |
1024 | memcpy(&gpu_metrics->current_coreclk[0], | |
1025 | &metrics.CoreFrequency[0], | |
1026 | sizeof(uint16_t) * 8); | |
1027 | gpu_metrics->current_l3clk[0] = metrics.L3Frequency[0]; | |
1028 | gpu_metrics->current_l3clk[1] = metrics.L3Frequency[1]; | |
1029 | ||
1030 | gpu_metrics->throttle_status = metrics.ThrottlerStatus; | |
1031 | ||
1032 | gpu_metrics->fan_pwm = metrics.FanPwm; | |
1033 | ||
1034 | *table = (void *)gpu_metrics; | |
1035 | ||
1036 | return sizeof(struct gpu_metrics_v2_0); | |
1037 | } | |
1038 | ||
9eb75d62 | 1039 | static const struct pptable_funcs renoir_ppt_funcs = { |
9eb75d62 | 1040 | .set_power_state = NULL, |
6ab3b9e3 | 1041 | .print_clk_levels = renoir_print_clk_levels, |
75a8957f | 1042 | .get_current_power_state = renoir_get_current_power_state, |
f6b4b4a1 | 1043 | .dpm_set_vcn_enable = renoir_dpm_set_vcn_enable, |
a986e151 | 1044 | .dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable, |
2e5294fe | 1045 | .force_clk_levels = renoir_force_clk_levels, |
ea286ed7 | 1046 | .set_power_profile_mode = renoir_set_power_profile_mode, |
2cf8d416 | 1047 | .set_performance_level = renoir_set_performance_level, |
7bbdbe40 HW |
1048 | .get_dpm_clock_table = renoir_get_dpm_clock_table, |
1049 | .set_watermarks_table = renoir_set_watermarks_table, | |
ad7ce43c | 1050 | .get_power_profile_mode = renoir_get_power_profile_mode, |
30b2c0ca | 1051 | .read_sensor = renoir_read_sensor, |
6c45e480 EQ |
1052 | .check_fw_status = smu_v12_0_check_fw_status, |
1053 | .check_fw_version = smu_v12_0_check_fw_version, | |
1054 | .powergate_sdma = smu_v12_0_powergate_sdma, | |
66c86828 EQ |
1055 | .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, |
1056 | .send_smc_msg = smu_cmn_send_smc_msg, | |
6c45e480 EQ |
1057 | .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, |
1058 | .gfx_off_control = smu_v12_0_gfx_off_control, | |
443c7f3c | 1059 | .get_gfx_off_status = smu_v12_0_get_gfxoff_status, |
c1b353b7 | 1060 | .init_smc_tables = renoir_init_smc_tables, |
6c45e480 | 1061 | .fini_smc_tables = smu_v12_0_fini_smc_tables, |
947119a3 | 1062 | .set_default_dpm_table = smu_v12_0_set_default_dpm_tables, |
28251d72 | 1063 | .get_enabled_mask = smu_cmn_get_enabled_mask, |
b4bb3aaf | 1064 | .feature_is_enabled = smu_cmn_feature_is_enabled, |
af5ba6d2 | 1065 | .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, |
982d68b0 | 1066 | .get_dpm_ultimate_freq = renoir_get_dpm_ultimate_freq, |
6c45e480 EQ |
1067 | .mode2_reset = smu_v12_0_mode2_reset, |
1068 | .set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range, | |
ce0d0ec3 | 1069 | .set_driver_table_location = smu_v12_0_set_driver_table_location, |
567c8fc4 | 1070 | .is_dpm_running = renoir_is_dpm_running, |
7dbf7805 EQ |
1071 | .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, |
1072 | .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, | |
95868b85 | 1073 | .get_gpu_metrics = renoir_get_gpu_metrics, |
9eb75d62 AL |
1074 | }; |
1075 | ||
1076 | void renoir_set_ppt_funcs(struct smu_context *smu) | |
1077 | { | |
1078 | smu->ppt_funcs = &renoir_ppt_funcs; | |
6c339f37 EQ |
1079 | smu->message_map = renoir_message_map; |
1080 | smu->clock_map = renoir_clk_map; | |
1081 | smu->table_map = renoir_table_map; | |
1082 | smu->workload_map = renoir_workload_map; | |
e57761c6 | 1083 | smu->smc_driver_if_version = SMU12_DRIVER_IF_VERSION; |
af1ec44f | 1084 | smu->is_apu = true; |
9eb75d62 | 1085 | } |