Commit | Line | Data |
---|---|---|
f50740be AL |
1 | /* |
2 | * Copyright 2020 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | */ | |
23 | ||
24 | #define SWSMU_CODE_LAYER_L2 | |
25 | ||
26 | #include "amdgpu.h" | |
27 | #include "amdgpu_smu.h" | |
21cf0293 | 28 | #include "smu_v13_0.h" |
f50740be AL |
29 | #include "smu13_driver_if_yellow_carp.h" |
30 | #include "yellow_carp_ppt.h" | |
31 | #include "smu_v13_0_1_ppsmc.h" | |
32 | #include "smu_v13_0_1_pmfw.h" | |
33 | #include "smu_cmn.h" | |
34 | ||
35 | /* | |
36 | * DO NOT use these for err/warn/info/debug messages. | |
37 | * Use dev_err, dev_warn, dev_info and dev_dbg instead. | |
38 | * They are more MGPU friendly. | |
39 | */ | |
40 | #undef pr_err | |
41 | #undef pr_warn | |
42 | #undef pr_info | |
43 | #undef pr_debug | |
44 | ||
2f6888af XH |
45 | #define FEATURE_MASK(feature) (1ULL << feature) |
46 | #define SMC_DPM_FEATURE ( \ | |
47 | FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ | |
48 | FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ | |
49 | FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ | |
50 | FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ | |
51 | FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ | |
52 | FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ | |
53 | FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ | |
54 | FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ | |
55 | FEATURE_MASK(FEATURE_GFX_DPM_BIT)) | |
56 | ||
f50740be AL |
57 | static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = { |
58 | MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), | |
59 | MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), | |
60 | MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), | |
61 | MSG_MAP(EnableGfxOff, PPSMC_MSG_EnableGfxOff, 1), | |
62 | MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 1), | |
63 | MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 1), | |
64 | MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 1), | |
65 | MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 1), | |
66 | MSG_MAP(SetHardMinVcn, PPSMC_MSG_SetHardMinVcn, 1), | |
907b3436 | 67 | MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1), |
f50740be AL |
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(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1), | |
74 | MSG_MAP(SetHardMinSocclkByFreq, PPSMC_MSG_SetHardMinSocclkByFreq, 1), | |
75 | MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn, 1), | |
76 | MSG_MAP(GetGfxclkFrequency, PPSMC_MSG_GetGfxclkFrequency, 1), | |
77 | MSG_MAP(GetFclkFrequency, PPSMC_MSG_GetFclkFrequency, 1), | |
78 | MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), | |
79 | MSG_MAP(SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk, 1), | |
80 | MSG_MAP(SetSoftMaxSocclkByFreq, PPSMC_MSG_SetSoftMaxSocclkByFreq, 1), | |
81 | MSG_MAP(SetSoftMaxFclkByFreq, PPSMC_MSG_SetSoftMaxFclkByFreq, 1), | |
82 | MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn, 1), | |
83 | MSG_MAP(SetPowerLimitPercentage, PPSMC_MSG_SetPowerLimitPercentage, 1), | |
84 | MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 1), | |
85 | MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 1), | |
86 | MSG_MAP(SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq, 1), | |
87 | MSG_MAP(SetSoftMinSocclkByFreq, PPSMC_MSG_SetSoftMinSocclkByFreq, 1), | |
88 | }; | |
89 | ||
d70b6842 XH |
90 | static struct cmn2asic_mapping yellow_carp_feature_mask_map[SMU_FEATURE_COUNT] = { |
91 | FEA_MAP(CCLK_DPM), | |
92 | FEA_MAP(FAN_CONTROLLER), | |
93 | FEA_MAP(PPT), | |
94 | FEA_MAP(TDC), | |
95 | FEA_MAP(THERMAL), | |
96 | FEA_MAP(ULV), | |
97 | FEA_MAP(VCN_DPM), | |
98 | FEA_MAP_REVERSE(FCLK), | |
99 | FEA_MAP_REVERSE(SOCCLK), | |
100 | FEA_MAP(LCLK_DPM), | |
101 | FEA_MAP(SHUBCLK_DPM), | |
102 | FEA_MAP(DCFCLK_DPM), | |
103 | FEA_MAP_HALF_REVERSE(GFX), | |
104 | FEA_MAP(DS_GFXCLK), | |
105 | FEA_MAP(DS_SOCCLK), | |
106 | FEA_MAP(DS_LCLK), | |
107 | FEA_MAP(DS_DCFCLK), | |
108 | FEA_MAP(DS_FCLK), | |
109 | FEA_MAP(DS_MP1CLK), | |
110 | FEA_MAP(DS_MP0CLK), | |
111 | FEA_MAP(GFX_DEM), | |
112 | FEA_MAP(PSI), | |
113 | FEA_MAP(PROCHOT), | |
114 | FEA_MAP(CPUOFF), | |
115 | FEA_MAP(STAPM), | |
116 | FEA_MAP(S0I3), | |
117 | FEA_MAP(PERF_LIMIT), | |
118 | FEA_MAP(CORE_DLDO), | |
119 | FEA_MAP(RSMU_LOW_POWER), | |
120 | FEA_MAP(SMN_LOW_POWER), | |
121 | FEA_MAP(THM_LOW_POWER), | |
122 | FEA_MAP(SMUIO_LOW_POWER), | |
123 | FEA_MAP(MP1_LOW_POWER), | |
124 | FEA_MAP(DS_VCN), | |
125 | FEA_MAP(CPPC), | |
126 | FEA_MAP(DF_CSTATES), | |
127 | FEA_MAP(MSMU_LOW_POWER), | |
128 | FEA_MAP(ATHUB_PG), | |
129 | }; | |
130 | ||
f50740be AL |
131 | static struct cmn2asic_mapping yellow_carp_table_map[SMU_TABLE_COUNT] = { |
132 | TAB_MAP_VALID(WATERMARKS), | |
133 | TAB_MAP_VALID(SMU_METRICS), | |
134 | TAB_MAP_VALID(CUSTOM_DPM), | |
135 | TAB_MAP_VALID(DPMCLOCKS), | |
136 | }; | |
137 | ||
138 | static int yellow_carp_init_smc_tables(struct smu_context *smu) | |
139 | { | |
140 | struct smu_table_context *smu_table = &smu->smu_table; | |
141 | struct smu_table *tables = smu_table->tables; | |
142 | ||
143 | SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), | |
144 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
145 | SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t), | |
146 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
147 | SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), | |
148 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
149 | ||
150 | smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); | |
151 | if (!smu_table->clocks_table) | |
152 | goto err0_out; | |
153 | ||
154 | smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); | |
155 | if (!smu_table->metrics_table) | |
156 | goto err1_out; | |
157 | smu_table->metrics_time = 0; | |
158 | ||
159 | smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); | |
160 | if (!smu_table->watermarks_table) | |
161 | goto err2_out; | |
162 | ||
9df5b9bd | 163 | smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1); |
f50740be AL |
164 | smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); |
165 | if (!smu_table->gpu_metrics_table) | |
166 | goto err3_out; | |
167 | ||
168 | return 0; | |
169 | ||
170 | err3_out: | |
171 | kfree(smu_table->watermarks_table); | |
172 | err2_out: | |
173 | kfree(smu_table->metrics_table); | |
174 | err1_out: | |
175 | kfree(smu_table->clocks_table); | |
176 | err0_out: | |
177 | return -ENOMEM; | |
178 | } | |
179 | ||
21cf0293 XH |
180 | static int yellow_carp_fini_smc_tables(struct smu_context *smu) |
181 | { | |
182 | struct smu_table_context *smu_table = &smu->smu_table; | |
183 | ||
184 | kfree(smu_table->clocks_table); | |
185 | smu_table->clocks_table = NULL; | |
186 | ||
187 | kfree(smu_table->metrics_table); | |
188 | smu_table->metrics_table = NULL; | |
189 | ||
190 | kfree(smu_table->watermarks_table); | |
191 | smu_table->watermarks_table = NULL; | |
192 | ||
193 | return 0; | |
194 | } | |
195 | ||
0b8b1c4d XH |
196 | static int yellow_carp_system_features_control(struct smu_context *smu, bool en) |
197 | { | |
198 | struct smu_feature *feature = &smu->smu_feature; | |
0e212522 | 199 | struct amdgpu_device *adev = smu->adev; |
2d282665 | 200 | uint64_t feature_mask; |
0b8b1c4d XH |
201 | int ret = 0; |
202 | ||
0e212522 | 203 | if (!en && !adev->in_s0ix) |
907b3436 AL |
204 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); |
205 | ||
0b8b1c4d | 206 | bitmap_zero(feature->enabled, feature->feature_num); |
0b8b1c4d XH |
207 | |
208 | if (!en) | |
209 | return ret; | |
210 | ||
2d282665 | 211 | ret = smu_cmn_get_enabled_mask(smu, &feature_mask); |
0b8b1c4d XH |
212 | if (ret) |
213 | return ret; | |
214 | ||
215 | bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, | |
216 | feature->feature_num); | |
0b8b1c4d XH |
217 | |
218 | return 0; | |
219 | } | |
220 | ||
3975cd8f HR |
221 | static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu, bool enable) |
222 | { | |
223 | int ret = 0; | |
224 | ||
225 | /* vcn dpm on is a prerequisite for vcn power gate messages */ | |
226 | if (enable) | |
227 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, | |
228 | 0, NULL); | |
229 | else | |
230 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, | |
231 | 0, NULL); | |
232 | ||
233 | return ret; | |
234 | } | |
235 | ||
236 | static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) | |
237 | { | |
238 | int ret = 0; | |
239 | ||
240 | if (enable) | |
241 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, | |
242 | 0, NULL); | |
243 | else | |
244 | ret = smu_cmn_send_smc_msg_with_param(smu, | |
245 | SMU_MSG_PowerDownJpeg, 0, | |
246 | NULL); | |
247 | ||
248 | return ret; | |
249 | } | |
250 | ||
251 | ||
f50740be AL |
252 | static bool yellow_carp_is_dpm_running(struct smu_context *smu) |
253 | { | |
2f6888af | 254 | int ret = 0; |
2f6888af XH |
255 | uint64_t feature_enabled; |
256 | ||
2d282665 | 257 | ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); |
f50740be | 258 | |
2f6888af | 259 | if (ret) |
f50740be | 260 | return false; |
f50740be | 261 | |
2f6888af | 262 | return !!(feature_enabled & SMC_DPM_FEATURE); |
f50740be AL |
263 | } |
264 | ||
a885bea7 AL |
265 | static int yellow_carp_post_smu_init(struct smu_context *smu) |
266 | { | |
267 | struct amdgpu_device *adev = smu->adev; | |
268 | int ret = 0; | |
269 | ||
270 | /* allow message will be sent after enable message on Yellow Carp*/ | |
271 | ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL); | |
272 | if (ret) | |
273 | dev_err(adev->dev, "Failed to Enable GfxOff!\n"); | |
274 | return ret; | |
275 | } | |
276 | ||
7d38d9dc AL |
277 | static int yellow_carp_mode_reset(struct smu_context *smu, int type) |
278 | { | |
279 | int ret = 0, index = 0; | |
280 | ||
281 | index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, | |
282 | SMU_MSG_GfxDeviceDriverReset); | |
283 | if (index < 0) | |
284 | return index == -EACCES ? 0 : index; | |
285 | ||
adefab4e AL |
286 | ret = smu_cmn_send_smc_msg_with_param(smu, (uint16_t)index, type, NULL); |
287 | if (ret) | |
288 | dev_err(smu->adev->dev, "Failed to mode reset!\n"); | |
7d38d9dc AL |
289 | |
290 | return ret; | |
291 | } | |
292 | ||
293 | static int yellow_carp_mode2_reset(struct smu_context *smu) | |
294 | { | |
295 | return yellow_carp_mode_reset(smu, SMU_RESET_MODE_2); | |
296 | } | |
297 | ||
77755dd3 XH |
298 | static int yellow_carp_get_smu_metrics_data(struct smu_context *smu, |
299 | MetricsMember_t member, | |
300 | uint32_t *value) | |
301 | { | |
302 | struct smu_table_context *smu_table = &smu->smu_table; | |
303 | ||
304 | SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; | |
305 | int ret = 0; | |
306 | ||
da11407f EQ |
307 | ret = smu_cmn_get_metrics_table(smu, NULL, false); |
308 | if (ret) | |
77755dd3 | 309 | return ret; |
77755dd3 XH |
310 | |
311 | switch (member) { | |
312 | case METRICS_AVERAGE_GFXCLK: | |
313 | *value = metrics->GfxclkFrequency; | |
314 | break; | |
315 | case METRICS_AVERAGE_SOCCLK: | |
316 | *value = metrics->SocclkFrequency; | |
317 | break; | |
318 | case METRICS_AVERAGE_VCLK: | |
319 | *value = metrics->VclkFrequency; | |
320 | break; | |
321 | case METRICS_AVERAGE_DCLK: | |
322 | *value = metrics->DclkFrequency; | |
323 | break; | |
324 | case METRICS_AVERAGE_UCLK: | |
325 | *value = metrics->MemclkFrequency; | |
326 | break; | |
327 | case METRICS_AVERAGE_GFXACTIVITY: | |
328 | *value = metrics->GfxActivity / 100; | |
329 | break; | |
330 | case METRICS_AVERAGE_VCNACTIVITY: | |
331 | *value = metrics->UvdActivity; | |
332 | break; | |
333 | case METRICS_AVERAGE_SOCKETPOWER: | |
334 | *value = (metrics->CurrentSocketPower << 8) / 1000; | |
335 | break; | |
336 | case METRICS_TEMPERATURE_EDGE: | |
337 | *value = metrics->GfxTemperature / 100 * | |
338 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
339 | break; | |
340 | case METRICS_TEMPERATURE_HOTSPOT: | |
341 | *value = metrics->SocTemperature / 100 * | |
342 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
343 | break; | |
344 | case METRICS_THROTTLER_STATUS: | |
345 | *value = metrics->ThrottlerStatus; | |
346 | break; | |
347 | case METRICS_VOLTAGE_VDDGFX: | |
348 | *value = metrics->Voltage[0]; | |
349 | break; | |
350 | case METRICS_VOLTAGE_VDDSOC: | |
351 | *value = metrics->Voltage[1]; | |
352 | break; | |
ac3fbe3b S |
353 | case METRICS_SS_APU_SHARE: |
354 | /* return the percentage of APU power with respect to APU's power limit. | |
355 | * percentage is reported, this isn't boost value. Smartshift power | |
356 | * boost/shift is only when the percentage is more than 100. | |
357 | */ | |
358 | if (metrics->StapmOpnLimit > 0) | |
359 | *value = (metrics->ApuPower * 100) / metrics->StapmOpnLimit; | |
360 | else | |
361 | *value = 0; | |
362 | break; | |
363 | case METRICS_SS_DGPU_SHARE: | |
364 | /* return the percentage of dGPU power with respect to dGPU's power limit. | |
365 | * percentage is reported, this isn't boost value. Smartshift power | |
366 | * boost/shift is only when the percentage is more than 100. | |
367 | */ | |
368 | if ((metrics->dGpuPower > 0) && | |
369 | (metrics->StapmCurrentLimit > metrics->StapmOpnLimit)) | |
370 | *value = (metrics->dGpuPower * 100) / | |
371 | (metrics->StapmCurrentLimit - metrics->StapmOpnLimit); | |
372 | else | |
373 | *value = 0; | |
374 | break; | |
77755dd3 XH |
375 | default: |
376 | *value = UINT_MAX; | |
377 | break; | |
378 | } | |
379 | ||
77755dd3 XH |
380 | return ret; |
381 | } | |
382 | ||
383 | static int yellow_carp_read_sensor(struct smu_context *smu, | |
384 | enum amd_pp_sensors sensor, | |
385 | void *data, uint32_t *size) | |
386 | { | |
387 | int ret = 0; | |
388 | ||
389 | if (!data || !size) | |
390 | return -EINVAL; | |
391 | ||
77755dd3 XH |
392 | switch (sensor) { |
393 | case AMDGPU_PP_SENSOR_GPU_LOAD: | |
394 | ret = yellow_carp_get_smu_metrics_data(smu, | |
395 | METRICS_AVERAGE_GFXACTIVITY, | |
396 | (uint32_t *)data); | |
397 | *size = 4; | |
398 | break; | |
399 | case AMDGPU_PP_SENSOR_GPU_POWER: | |
400 | ret = yellow_carp_get_smu_metrics_data(smu, | |
401 | METRICS_AVERAGE_SOCKETPOWER, | |
402 | (uint32_t *)data); | |
403 | *size = 4; | |
404 | break; | |
405 | case AMDGPU_PP_SENSOR_EDGE_TEMP: | |
406 | ret = yellow_carp_get_smu_metrics_data(smu, | |
407 | METRICS_TEMPERATURE_EDGE, | |
408 | (uint32_t *)data); | |
409 | *size = 4; | |
410 | break; | |
411 | case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: | |
412 | ret = yellow_carp_get_smu_metrics_data(smu, | |
413 | METRICS_TEMPERATURE_HOTSPOT, | |
414 | (uint32_t *)data); | |
415 | *size = 4; | |
416 | break; | |
417 | case AMDGPU_PP_SENSOR_GFX_MCLK: | |
418 | ret = yellow_carp_get_smu_metrics_data(smu, | |
419 | METRICS_AVERAGE_UCLK, | |
420 | (uint32_t *)data); | |
421 | *(uint32_t *)data *= 100; | |
422 | *size = 4; | |
423 | break; | |
424 | case AMDGPU_PP_SENSOR_GFX_SCLK: | |
425 | ret = yellow_carp_get_smu_metrics_data(smu, | |
426 | METRICS_AVERAGE_GFXCLK, | |
427 | (uint32_t *)data); | |
428 | *(uint32_t *)data *= 100; | |
429 | *size = 4; | |
430 | break; | |
431 | case AMDGPU_PP_SENSOR_VDDGFX: | |
432 | ret = yellow_carp_get_smu_metrics_data(smu, | |
433 | METRICS_VOLTAGE_VDDGFX, | |
434 | (uint32_t *)data); | |
435 | *size = 4; | |
436 | break; | |
437 | case AMDGPU_PP_SENSOR_VDDNB: | |
438 | ret = yellow_carp_get_smu_metrics_data(smu, | |
439 | METRICS_VOLTAGE_VDDSOC, | |
440 | (uint32_t *)data); | |
441 | *size = 4; | |
442 | break; | |
ac3fbe3b S |
443 | case AMDGPU_PP_SENSOR_SS_APU_SHARE: |
444 | ret = yellow_carp_get_smu_metrics_data(smu, | |
445 | METRICS_SS_APU_SHARE, | |
446 | (uint32_t *)data); | |
447 | *size = 4; | |
448 | break; | |
449 | case AMDGPU_PP_SENSOR_SS_DGPU_SHARE: | |
450 | ret = yellow_carp_get_smu_metrics_data(smu, | |
451 | METRICS_SS_DGPU_SHARE, | |
452 | (uint32_t *)data); | |
453 | *size = 4; | |
454 | break; | |
77755dd3 XH |
455 | default: |
456 | ret = -EOPNOTSUPP; | |
457 | break; | |
458 | } | |
77755dd3 XH |
459 | |
460 | return ret; | |
461 | } | |
462 | ||
4cea0fc9 XH |
463 | static int yellow_carp_set_watermarks_table(struct smu_context *smu, |
464 | struct pp_smu_wm_range_sets *clock_ranges) | |
465 | { | |
466 | int i; | |
467 | int ret = 0; | |
468 | Watermarks_t *table = smu->smu_table.watermarks_table; | |
469 | ||
470 | if (!table || !clock_ranges) | |
471 | return -EINVAL; | |
472 | ||
473 | if (clock_ranges) { | |
474 | if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES || | |
475 | clock_ranges->num_writer_wm_sets > NUM_WM_RANGES) | |
476 | return -EINVAL; | |
477 | ||
478 | for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) { | |
479 | table->WatermarkRow[WM_DCFCLK][i].MinClock = | |
480 | clock_ranges->reader_wm_sets[i].min_drain_clk_mhz; | |
481 | table->WatermarkRow[WM_DCFCLK][i].MaxClock = | |
482 | clock_ranges->reader_wm_sets[i].max_drain_clk_mhz; | |
483 | table->WatermarkRow[WM_DCFCLK][i].MinMclk = | |
484 | clock_ranges->reader_wm_sets[i].min_fill_clk_mhz; | |
485 | table->WatermarkRow[WM_DCFCLK][i].MaxMclk = | |
486 | clock_ranges->reader_wm_sets[i].max_fill_clk_mhz; | |
487 | ||
488 | table->WatermarkRow[WM_DCFCLK][i].WmSetting = | |
489 | clock_ranges->reader_wm_sets[i].wm_inst; | |
490 | } | |
491 | ||
492 | for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) { | |
493 | table->WatermarkRow[WM_SOCCLK][i].MinClock = | |
494 | clock_ranges->writer_wm_sets[i].min_fill_clk_mhz; | |
495 | table->WatermarkRow[WM_SOCCLK][i].MaxClock = | |
496 | clock_ranges->writer_wm_sets[i].max_fill_clk_mhz; | |
497 | table->WatermarkRow[WM_SOCCLK][i].MinMclk = | |
498 | clock_ranges->writer_wm_sets[i].min_drain_clk_mhz; | |
499 | table->WatermarkRow[WM_SOCCLK][i].MaxMclk = | |
500 | clock_ranges->writer_wm_sets[i].max_drain_clk_mhz; | |
501 | ||
502 | table->WatermarkRow[WM_SOCCLK][i].WmSetting = | |
503 | clock_ranges->writer_wm_sets[i].wm_inst; | |
504 | } | |
505 | ||
506 | smu->watermarks_bitmap |= WATERMARKS_EXIST; | |
507 | } | |
508 | ||
509 | /* pass data to smu controller */ | |
510 | if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && | |
511 | !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { | |
512 | ret = smu_cmn_write_watermarks_table(smu); | |
513 | if (ret) { | |
514 | dev_err(smu->adev->dev, "Failed to update WMTABLE!"); | |
515 | return ret; | |
516 | } | |
517 | smu->watermarks_bitmap |= WATERMARKS_LOADED; | |
518 | } | |
519 | ||
520 | return 0; | |
521 | } | |
522 | ||
9df5b9bd XH |
523 | static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu, |
524 | void **table) | |
525 | { | |
526 | struct smu_table_context *smu_table = &smu->smu_table; | |
527 | struct gpu_metrics_v2_1 *gpu_metrics = | |
528 | (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; | |
529 | SmuMetrics_t metrics; | |
530 | int ret = 0; | |
531 | ||
532 | ret = smu_cmn_get_metrics_table(smu, &metrics, true); | |
533 | if (ret) | |
534 | return ret; | |
535 | ||
536 | smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1); | |
537 | ||
538 | gpu_metrics->temperature_gfx = metrics.GfxTemperature; | |
539 | gpu_metrics->temperature_soc = metrics.SocTemperature; | |
540 | memcpy(&gpu_metrics->temperature_core[0], | |
541 | &metrics.CoreTemperature[0], | |
542 | sizeof(uint16_t) * 8); | |
543 | gpu_metrics->temperature_l3[0] = metrics.L3Temperature; | |
544 | ||
545 | gpu_metrics->average_gfx_activity = metrics.GfxActivity; | |
546 | gpu_metrics->average_mm_activity = metrics.UvdActivity; | |
547 | ||
548 | gpu_metrics->average_socket_power = metrics.CurrentSocketPower; | |
549 | gpu_metrics->average_gfx_power = metrics.Power[0]; | |
550 | gpu_metrics->average_soc_power = metrics.Power[1]; | |
551 | memcpy(&gpu_metrics->average_core_power[0], | |
552 | &metrics.CorePower[0], | |
553 | sizeof(uint16_t) * 8); | |
554 | ||
555 | gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency; | |
556 | gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency; | |
557 | gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency; | |
558 | gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency; | |
559 | gpu_metrics->average_vclk_frequency = metrics.VclkFrequency; | |
560 | gpu_metrics->average_dclk_frequency = metrics.DclkFrequency; | |
561 | ||
562 | memcpy(&gpu_metrics->current_coreclk[0], | |
563 | &metrics.CoreFrequency[0], | |
564 | sizeof(uint16_t) * 8); | |
565 | gpu_metrics->current_l3clk[0] = metrics.L3Frequency; | |
566 | ||
567 | gpu_metrics->throttle_status = metrics.ThrottlerStatus; | |
568 | ||
569 | gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); | |
570 | ||
571 | *table = (void *)gpu_metrics; | |
572 | ||
573 | return sizeof(struct gpu_metrics_v2_1); | |
574 | } | |
575 | ||
21cf0293 XH |
576 | static int yellow_carp_set_default_dpm_tables(struct smu_context *smu) |
577 | { | |
578 | struct smu_table_context *smu_table = &smu->smu_table; | |
579 | ||
580 | return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false); | |
581 | } | |
582 | ||
d54e9e70 XH |
583 | static int yellow_carp_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, |
584 | long input[], uint32_t size) | |
585 | { | |
6c83a015 | 586 | struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); |
d54e9e70 XH |
587 | int ret = 0; |
588 | ||
6c83a015 XH |
589 | /* Only allowed in manual mode */ |
590 | if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) | |
591 | return -EINVAL; | |
592 | ||
d54e9e70 XH |
593 | switch (type) { |
594 | case PP_OD_EDIT_SCLK_VDDC_TABLE: | |
595 | if (size != 2) { | |
596 | dev_err(smu->adev->dev, "Input parameter number not correct\n"); | |
597 | return -EINVAL; | |
598 | } | |
599 | ||
600 | if (input[0] == 0) { | |
601 | if (input[1] < smu->gfx_default_hard_min_freq) { | |
602 | dev_warn(smu->adev->dev, | |
603 | "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n", | |
604 | input[1], smu->gfx_default_hard_min_freq); | |
605 | return -EINVAL; | |
606 | } | |
607 | smu->gfx_actual_hard_min_freq = input[1]; | |
608 | } else if (input[0] == 1) { | |
609 | if (input[1] > smu->gfx_default_soft_max_freq) { | |
610 | dev_warn(smu->adev->dev, | |
611 | "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n", | |
612 | input[1], smu->gfx_default_soft_max_freq); | |
613 | return -EINVAL; | |
614 | } | |
615 | smu->gfx_actual_soft_max_freq = input[1]; | |
616 | } else { | |
617 | return -EINVAL; | |
618 | } | |
619 | break; | |
620 | case PP_OD_RESTORE_DEFAULT_TABLE: | |
621 | if (size != 0) { | |
622 | dev_err(smu->adev->dev, "Input parameter number not correct\n"); | |
623 | return -EINVAL; | |
624 | } else { | |
625 | smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; | |
626 | smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; | |
627 | } | |
628 | break; | |
629 | case PP_OD_COMMIT_DPM_TABLE: | |
630 | if (size != 0) { | |
631 | dev_err(smu->adev->dev, "Input parameter number not correct\n"); | |
632 | return -EINVAL; | |
633 | } else { | |
634 | if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) { | |
635 | dev_err(smu->adev->dev, | |
f5d8e164 | 636 | "The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n", |
d54e9e70 XH |
637 | smu->gfx_actual_hard_min_freq, |
638 | smu->gfx_actual_soft_max_freq); | |
639 | return -EINVAL; | |
640 | } | |
641 | ||
642 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, | |
643 | smu->gfx_actual_hard_min_freq, NULL); | |
644 | if (ret) { | |
645 | dev_err(smu->adev->dev, "Set hard min sclk failed!"); | |
646 | return ret; | |
647 | } | |
648 | ||
649 | ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, | |
650 | smu->gfx_actual_soft_max_freq, NULL); | |
651 | if (ret) { | |
652 | dev_err(smu->adev->dev, "Set soft max sclk failed!"); | |
653 | return ret; | |
654 | } | |
655 | } | |
656 | break; | |
657 | default: | |
658 | return -ENOSYS; | |
659 | } | |
660 | ||
661 | return ret; | |
662 | } | |
663 | ||
a831bafa XH |
664 | static int yellow_carp_get_current_clk_freq(struct smu_context *smu, |
665 | enum smu_clk_type clk_type, | |
666 | uint32_t *value) | |
667 | { | |
668 | MetricsMember_t member_type; | |
669 | ||
670 | switch (clk_type) { | |
671 | case SMU_SOCCLK: | |
672 | member_type = METRICS_AVERAGE_SOCCLK; | |
673 | break; | |
674 | case SMU_VCLK: | |
675 | member_type = METRICS_AVERAGE_VCLK; | |
676 | break; | |
677 | case SMU_DCLK: | |
678 | member_type = METRICS_AVERAGE_DCLK; | |
679 | break; | |
680 | case SMU_MCLK: | |
681 | member_type = METRICS_AVERAGE_UCLK; | |
682 | break; | |
683 | case SMU_FCLK: | |
684 | return smu_cmn_send_smc_msg_with_param(smu, | |
685 | SMU_MSG_GetFclkFrequency, 0, value); | |
3dac776e PY |
686 | case SMU_GFXCLK: |
687 | case SMU_SCLK: | |
688 | return smu_cmn_send_smc_msg_with_param(smu, | |
689 | SMU_MSG_GetGfxclkFrequency, 0, value); | |
690 | break; | |
a831bafa | 691 | default: |
2b517bd1 | 692 | return -EINVAL; |
a831bafa XH |
693 | } |
694 | ||
695 | return yellow_carp_get_smu_metrics_data(smu, member_type, value); | |
696 | } | |
697 | ||
698 | static int yellow_carp_get_dpm_level_count(struct smu_context *smu, | |
699 | enum smu_clk_type clk_type, | |
700 | uint32_t *count) | |
701 | { | |
702 | DpmClocks_t *clk_table = smu->smu_table.clocks_table; | |
703 | ||
704 | switch (clk_type) { | |
705 | case SMU_SOCCLK: | |
706 | *count = clk_table->NumSocClkLevelsEnabled; | |
707 | break; | |
708 | case SMU_VCLK: | |
709 | *count = clk_table->VcnClkLevelsEnabled; | |
710 | break; | |
711 | case SMU_DCLK: | |
712 | *count = clk_table->VcnClkLevelsEnabled; | |
713 | break; | |
714 | case SMU_MCLK: | |
715 | *count = clk_table->NumDfPstatesEnabled; | |
716 | break; | |
717 | case SMU_FCLK: | |
718 | *count = clk_table->NumDfPstatesEnabled; | |
719 | break; | |
720 | default: | |
721 | break; | |
722 | } | |
723 | ||
724 | return 0; | |
725 | } | |
726 | ||
727 | static int yellow_carp_get_dpm_freq_by_index(struct smu_context *smu, | |
728 | enum smu_clk_type clk_type, | |
729 | uint32_t dpm_level, | |
730 | uint32_t *freq) | |
731 | { | |
732 | DpmClocks_t *clk_table = smu->smu_table.clocks_table; | |
733 | ||
734 | if (!clk_table || clk_type >= SMU_CLK_COUNT) | |
735 | return -EINVAL; | |
736 | ||
737 | switch (clk_type) { | |
738 | case SMU_SOCCLK: | |
739 | if (dpm_level >= clk_table->NumSocClkLevelsEnabled) | |
740 | return -EINVAL; | |
741 | *freq = clk_table->SocClocks[dpm_level]; | |
742 | break; | |
743 | case SMU_VCLK: | |
744 | if (dpm_level >= clk_table->VcnClkLevelsEnabled) | |
745 | return -EINVAL; | |
746 | *freq = clk_table->VClocks[dpm_level]; | |
747 | break; | |
748 | case SMU_DCLK: | |
749 | if (dpm_level >= clk_table->VcnClkLevelsEnabled) | |
750 | return -EINVAL; | |
751 | *freq = clk_table->DClocks[dpm_level]; | |
752 | break; | |
753 | case SMU_UCLK: | |
754 | case SMU_MCLK: | |
755 | if (dpm_level >= clk_table->NumDfPstatesEnabled) | |
756 | return -EINVAL; | |
757 | *freq = clk_table->DfPstateTable[dpm_level].MemClk; | |
758 | break; | |
759 | case SMU_FCLK: | |
760 | if (dpm_level >= clk_table->NumDfPstatesEnabled) | |
761 | return -EINVAL; | |
762 | *freq = clk_table->DfPstateTable[dpm_level].FClk; | |
763 | break; | |
764 | default: | |
765 | return -EINVAL; | |
766 | } | |
767 | ||
768 | return 0; | |
769 | } | |
770 | ||
a06370ed XH |
771 | static bool yellow_carp_clk_dpm_is_enabled(struct smu_context *smu, |
772 | enum smu_clk_type clk_type) | |
773 | { | |
774 | enum smu_feature_mask feature_id = 0; | |
775 | ||
776 | switch (clk_type) { | |
777 | case SMU_MCLK: | |
778 | case SMU_UCLK: | |
779 | case SMU_FCLK: | |
780 | feature_id = SMU_FEATURE_DPM_FCLK_BIT; | |
781 | break; | |
782 | case SMU_GFXCLK: | |
783 | case SMU_SCLK: | |
784 | feature_id = SMU_FEATURE_DPM_GFXCLK_BIT; | |
785 | break; | |
786 | case SMU_SOCCLK: | |
787 | feature_id = SMU_FEATURE_DPM_SOCCLK_BIT; | |
788 | break; | |
789 | case SMU_VCLK: | |
790 | case SMU_DCLK: | |
791 | feature_id = SMU_FEATURE_VCN_DPM_BIT; | |
792 | break; | |
793 | default: | |
794 | return true; | |
795 | } | |
796 | ||
797 | return smu_cmn_feature_is_enabled(smu, feature_id); | |
798 | } | |
799 | ||
40954754 XH |
800 | static int yellow_carp_get_dpm_ultimate_freq(struct smu_context *smu, |
801 | enum smu_clk_type clk_type, | |
802 | uint32_t *min, | |
803 | uint32_t *max) | |
804 | { | |
805 | DpmClocks_t *clk_table = smu->smu_table.clocks_table; | |
806 | uint32_t clock_limit; | |
807 | uint32_t max_dpm_level, min_dpm_level; | |
808 | int ret = 0; | |
809 | ||
810 | if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type)) { | |
811 | switch (clk_type) { | |
812 | case SMU_MCLK: | |
813 | case SMU_UCLK: | |
814 | clock_limit = smu->smu_table.boot_values.uclk; | |
815 | break; | |
816 | case SMU_FCLK: | |
817 | clock_limit = smu->smu_table.boot_values.fclk; | |
818 | break; | |
819 | case SMU_GFXCLK: | |
820 | case SMU_SCLK: | |
821 | clock_limit = smu->smu_table.boot_values.gfxclk; | |
822 | break; | |
823 | case SMU_SOCCLK: | |
824 | clock_limit = smu->smu_table.boot_values.socclk; | |
825 | break; | |
826 | case SMU_VCLK: | |
827 | clock_limit = smu->smu_table.boot_values.vclk; | |
828 | break; | |
829 | case SMU_DCLK: | |
830 | clock_limit = smu->smu_table.boot_values.dclk; | |
831 | break; | |
832 | default: | |
833 | clock_limit = 0; | |
834 | break; | |
835 | } | |
836 | ||
837 | /* clock in Mhz unit */ | |
838 | if (min) | |
839 | *min = clock_limit / 100; | |
840 | if (max) | |
841 | *max = clock_limit / 100; | |
842 | ||
843 | return 0; | |
844 | } | |
845 | ||
846 | if (max) { | |
847 | switch (clk_type) { | |
848 | case SMU_GFXCLK: | |
849 | case SMU_SCLK: | |
850 | *max = clk_table->MaxGfxClk; | |
851 | break; | |
852 | case SMU_MCLK: | |
853 | case SMU_UCLK: | |
854 | case SMU_FCLK: | |
855 | max_dpm_level = 0; | |
856 | break; | |
857 | case SMU_SOCCLK: | |
858 | max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1; | |
859 | break; | |
860 | case SMU_VCLK: | |
861 | case SMU_DCLK: | |
862 | max_dpm_level = clk_table->VcnClkLevelsEnabled - 1; | |
863 | break; | |
864 | default: | |
865 | ret = -EINVAL; | |
866 | goto failed; | |
867 | } | |
868 | ||
869 | if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { | |
870 | ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max); | |
871 | if (ret) | |
872 | goto failed; | |
873 | } | |
874 | } | |
875 | ||
876 | if (min) { | |
877 | switch (clk_type) { | |
878 | case SMU_GFXCLK: | |
879 | case SMU_SCLK: | |
880 | *min = clk_table->MinGfxClk; | |
881 | break; | |
882 | case SMU_MCLK: | |
883 | case SMU_UCLK: | |
884 | case SMU_FCLK: | |
885 | min_dpm_level = clk_table->NumDfPstatesEnabled - 1; | |
886 | break; | |
887 | case SMU_SOCCLK: | |
888 | min_dpm_level = 0; | |
889 | break; | |
890 | case SMU_VCLK: | |
891 | case SMU_DCLK: | |
892 | min_dpm_level = 0; | |
893 | break; | |
894 | default: | |
895 | ret = -EINVAL; | |
896 | goto failed; | |
897 | } | |
898 | ||
899 | if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { | |
900 | ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min); | |
901 | if (ret) | |
902 | goto failed; | |
903 | } | |
904 | } | |
905 | ||
906 | failed: | |
907 | return ret; | |
908 | } | |
909 | ||
a06370ed XH |
910 | static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu, |
911 | enum smu_clk_type clk_type, | |
912 | uint32_t min, | |
913 | uint32_t max) | |
914 | { | |
915 | enum smu_message_type msg_set_min, msg_set_max; | |
916 | int ret = 0; | |
917 | ||
918 | if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type)) | |
919 | return -EINVAL; | |
920 | ||
921 | switch (clk_type) { | |
922 | case SMU_GFXCLK: | |
923 | case SMU_SCLK: | |
924 | msg_set_min = SMU_MSG_SetHardMinGfxClk; | |
925 | msg_set_max = SMU_MSG_SetSoftMaxGfxClk; | |
926 | break; | |
927 | case SMU_FCLK: | |
a06370ed XH |
928 | msg_set_min = SMU_MSG_SetHardMinFclkByFreq; |
929 | msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq; | |
930 | break; | |
931 | case SMU_SOCCLK: | |
932 | msg_set_min = SMU_MSG_SetHardMinSocclkByFreq; | |
933 | msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq; | |
934 | break; | |
935 | case SMU_VCLK: | |
936 | case SMU_DCLK: | |
937 | msg_set_min = SMU_MSG_SetHardMinVcn; | |
938 | msg_set_max = SMU_MSG_SetSoftMaxVcn; | |
939 | break; | |
940 | default: | |
941 | return -EINVAL; | |
942 | } | |
943 | ||
944 | ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); | |
945 | if (ret) | |
946 | goto out; | |
947 | ||
948 | ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL); | |
949 | if (ret) | |
950 | goto out; | |
951 | ||
952 | out: | |
953 | return ret; | |
954 | } | |
955 | ||
d54e9e70 XH |
956 | static int yellow_carp_print_clk_levels(struct smu_context *smu, |
957 | enum smu_clk_type clk_type, char *buf) | |
958 | { | |
a831bafa XH |
959 | int i, size = 0, ret = 0; |
960 | uint32_t cur_value = 0, value = 0, count = 0; | |
3dac776e | 961 | uint32_t min, max; |
d54e9e70 | 962 | |
8f48ba30 LY |
963 | smu_cmn_get_sysfs_buf(&buf, &size); |
964 | ||
d54e9e70 XH |
965 | switch (clk_type) { |
966 | case SMU_OD_SCLK: | |
8f48ba30 | 967 | size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); |
e738c2f0 | 968 | size += sysfs_emit_at(buf, size, "0: %10uMhz\n", |
d54e9e70 | 969 | (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq); |
e738c2f0 | 970 | size += sysfs_emit_at(buf, size, "1: %10uMhz\n", |
d54e9e70 XH |
971 | (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq); |
972 | break; | |
973 | case SMU_OD_RANGE: | |
8f48ba30 | 974 | size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); |
e738c2f0 | 975 | size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", |
d54e9e70 XH |
976 | smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq); |
977 | break; | |
a831bafa XH |
978 | case SMU_SOCCLK: |
979 | case SMU_VCLK: | |
980 | case SMU_DCLK: | |
981 | case SMU_MCLK: | |
982 | case SMU_FCLK: | |
983 | ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value); | |
984 | if (ret) | |
985 | goto print_clk_out; | |
986 | ||
987 | ret = yellow_carp_get_dpm_level_count(smu, clk_type, &count); | |
988 | if (ret) | |
989 | goto print_clk_out; | |
990 | ||
991 | for (i = 0; i < count; i++) { | |
992 | ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, i, &value); | |
993 | if (ret) | |
994 | goto print_clk_out; | |
995 | ||
e738c2f0 | 996 | size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, |
a831bafa XH |
997 | cur_value == value ? "*" : ""); |
998 | } | |
999 | break; | |
3dac776e PY |
1000 | case SMU_GFXCLK: |
1001 | case SMU_SCLK: | |
1002 | ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value); | |
1003 | if (ret) | |
1004 | goto print_clk_out; | |
1005 | min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; | |
1006 | max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; | |
1007 | if (cur_value == max) | |
1008 | i = 2; | |
1009 | else if (cur_value == min) | |
1010 | i = 0; | |
1011 | else | |
1012 | i = 1; | |
1013 | size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, | |
1014 | i == 0 ? "*" : ""); | |
1015 | size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", | |
1016 | i == 1 ? cur_value : YELLOW_CARP_UMD_PSTATE_GFXCLK, | |
1017 | i == 1 ? "*" : ""); | |
1018 | size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, | |
1019 | i == 2 ? "*" : ""); | |
1020 | break; | |
d54e9e70 XH |
1021 | default: |
1022 | break; | |
1023 | } | |
1024 | ||
a831bafa | 1025 | print_clk_out: |
d54e9e70 XH |
1026 | return size; |
1027 | } | |
1028 | ||
a06370ed XH |
1029 | static int yellow_carp_force_clk_levels(struct smu_context *smu, |
1030 | enum smu_clk_type clk_type, uint32_t mask) | |
1031 | { | |
1032 | uint32_t soft_min_level = 0, soft_max_level = 0; | |
1033 | uint32_t min_freq = 0, max_freq = 0; | |
1034 | int ret = 0; | |
1035 | ||
1036 | soft_min_level = mask ? (ffs(mask) - 1) : 0; | |
1037 | soft_max_level = mask ? (fls(mask) - 1) : 0; | |
1038 | ||
1039 | switch (clk_type) { | |
1040 | case SMU_SOCCLK: | |
a06370ed XH |
1041 | case SMU_FCLK: |
1042 | case SMU_VCLK: | |
1043 | case SMU_DCLK: | |
1044 | ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); | |
1045 | if (ret) | |
1046 | goto force_level_out; | |
1047 | ||
1048 | ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); | |
1049 | if (ret) | |
1050 | goto force_level_out; | |
1051 | ||
1052 | ret = yellow_carp_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); | |
1053 | if (ret) | |
1054 | goto force_level_out; | |
1055 | break; | |
1056 | default: | |
1057 | ret = -EINVAL; | |
1058 | break; | |
1059 | } | |
1060 | ||
1061 | force_level_out: | |
1062 | return ret; | |
1063 | } | |
1064 | ||
6c83a015 XH |
1065 | static int yellow_carp_set_performance_level(struct smu_context *smu, |
1066 | enum amd_dpm_forced_level level) | |
1067 | { | |
1068 | struct amdgpu_device *adev = smu->adev; | |
1069 | uint32_t sclk_min = 0, sclk_max = 0; | |
203ed53f | 1070 | uint32_t fclk_min = 0, fclk_max = 0; |
6c83a015 XH |
1071 | uint32_t socclk_min = 0, socclk_max = 0; |
1072 | int ret = 0; | |
1073 | ||
1074 | switch (level) { | |
1075 | case AMD_DPM_FORCED_LEVEL_HIGH: | |
1076 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max); | |
203ed53f | 1077 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max); |
6c83a015 XH |
1078 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max); |
1079 | sclk_min = sclk_max; | |
203ed53f | 1080 | fclk_min = fclk_max; |
6c83a015 XH |
1081 | socclk_min = socclk_max; |
1082 | break; | |
1083 | case AMD_DPM_FORCED_LEVEL_LOW: | |
1084 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL); | |
203ed53f | 1085 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL); |
6c83a015 XH |
1086 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL); |
1087 | sclk_max = sclk_min; | |
203ed53f | 1088 | fclk_max = fclk_min; |
6c83a015 XH |
1089 | socclk_max = socclk_min; |
1090 | break; | |
1091 | case AMD_DPM_FORCED_LEVEL_AUTO: | |
1092 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max); | |
203ed53f | 1093 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max); |
6c83a015 XH |
1094 | yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max); |
1095 | break; | |
1096 | case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: | |
1097 | case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: | |
1098 | case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: | |
1099 | case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: | |
1100 | /* Temporarily do nothing since the optimal clocks haven't been provided yet */ | |
1101 | break; | |
1102 | case AMD_DPM_FORCED_LEVEL_MANUAL: | |
1103 | case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: | |
1104 | return 0; | |
1105 | default: | |
1106 | dev_err(adev->dev, "Invalid performance level %d\n", level); | |
1107 | return -EINVAL; | |
1108 | } | |
1109 | ||
1110 | if (sclk_min && sclk_max) { | |
1111 | ret = yellow_carp_set_soft_freq_limited_range(smu, | |
1112 | SMU_SCLK, | |
1113 | sclk_min, | |
1114 | sclk_max); | |
1115 | if (ret) | |
1116 | return ret; | |
1117 | ||
1118 | smu->gfx_actual_hard_min_freq = sclk_min; | |
1119 | smu->gfx_actual_soft_max_freq = sclk_max; | |
1120 | } | |
1121 | ||
203ed53f | 1122 | if (fclk_min && fclk_max) { |
6c83a015 | 1123 | ret = yellow_carp_set_soft_freq_limited_range(smu, |
203ed53f XH |
1124 | SMU_FCLK, |
1125 | fclk_min, | |
1126 | fclk_max); | |
6c83a015 XH |
1127 | if (ret) |
1128 | return ret; | |
1129 | } | |
1130 | ||
1131 | if (socclk_min && socclk_max) { | |
1132 | ret = yellow_carp_set_soft_freq_limited_range(smu, | |
1133 | SMU_SOCCLK, | |
1134 | socclk_min, | |
1135 | socclk_max); | |
1136 | if (ret) | |
1137 | return ret; | |
1138 | } | |
1139 | ||
1140 | return ret; | |
1141 | } | |
1142 | ||
d54e9e70 XH |
1143 | static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) |
1144 | { | |
1145 | DpmClocks_t *clk_table = smu->smu_table.clocks_table; | |
1146 | ||
1147 | smu->gfx_default_hard_min_freq = clk_table->MinGfxClk; | |
1148 | smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk; | |
1149 | smu->gfx_actual_hard_min_freq = 0; | |
1150 | smu->gfx_actual_soft_max_freq = 0; | |
1151 | ||
1152 | return 0; | |
1153 | } | |
1154 | ||
f50740be | 1155 | static const struct pptable_funcs yellow_carp_ppt_funcs = { |
21cf0293 XH |
1156 | .check_fw_status = smu_v13_0_check_fw_status, |
1157 | .check_fw_version = smu_v13_0_check_fw_version, | |
f50740be | 1158 | .init_smc_tables = yellow_carp_init_smc_tables, |
21cf0293 XH |
1159 | .fini_smc_tables = yellow_carp_fini_smc_tables, |
1160 | .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, | |
0b8b1c4d | 1161 | .system_features_control = yellow_carp_system_features_control, |
f50740be AL |
1162 | .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, |
1163 | .send_smc_msg = smu_cmn_send_smc_msg, | |
3975cd8f HR |
1164 | .dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable, |
1165 | .dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable, | |
21cf0293 | 1166 | .set_default_dpm_table = yellow_carp_set_default_dpm_tables, |
77755dd3 | 1167 | .read_sensor = yellow_carp_read_sensor, |
f50740be | 1168 | .is_dpm_running = yellow_carp_is_dpm_running, |
4cea0fc9 | 1169 | .set_watermarks_table = yellow_carp_set_watermarks_table, |
9df5b9bd | 1170 | .get_gpu_metrics = yellow_carp_get_gpu_metrics, |
5af779ad | 1171 | .get_enabled_mask = smu_cmn_get_enabled_mask, |
f50740be | 1172 | .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, |
21cf0293 XH |
1173 | .set_driver_table_location = smu_v13_0_set_driver_table_location, |
1174 | .gfx_off_control = smu_v13_0_gfx_off_control, | |
a885bea7 | 1175 | .post_init = yellow_carp_post_smu_init, |
7d38d9dc | 1176 | .mode2_reset = yellow_carp_mode2_reset, |
40954754 | 1177 | .get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq, |
d54e9e70 XH |
1178 | .od_edit_dpm_table = yellow_carp_od_edit_dpm_table, |
1179 | .print_clk_levels = yellow_carp_print_clk_levels, | |
a06370ed | 1180 | .force_clk_levels = yellow_carp_force_clk_levels, |
6c83a015 | 1181 | .set_performance_level = yellow_carp_set_performance_level, |
d54e9e70 | 1182 | .set_fine_grain_gfx_freq_parameters = yellow_carp_set_fine_grain_gfx_freq_parameters, |
f50740be AL |
1183 | }; |
1184 | ||
1185 | void yellow_carp_set_ppt_funcs(struct smu_context *smu) | |
1186 | { | |
1187 | smu->ppt_funcs = &yellow_carp_ppt_funcs; | |
1188 | smu->message_map = yellow_carp_message_map; | |
d70b6842 | 1189 | smu->feature_map = yellow_carp_feature_mask_map; |
f50740be AL |
1190 | smu->table_map = yellow_carp_table_map; |
1191 | smu->is_apu = true; | |
1192 | } |