1 | /* |
2 | * Copyright 2011 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 | * Authors: Alex Deucher |
23 | */ |
24 | |
25 | #include "amdgpu.h" |
26 | #include "amdgpu_atombios.h" |
27 | #include "amdgpu_i2c.h" |
28 | #include "amdgpu_dpm.h" |
29 | #include "atom.h" |
30 | #include "amd_pcie.h" |
31 | #include "amdgpu_display.h" |
32 | #include "hwmgr.h" |
33 | #include <linux/power_supply.h> |
34 | #include "amdgpu_smu.h" |
35 | |
36 | #define amdgpu_dpm_enable_bapm(adev, e) \ |
37 | ((adev)->powerplay.pp_funcs->enable_bapm((adev)->powerplay.pp_handle, (e))) |
38 | |
39 | #define amdgpu_dpm_is_legacy_dpm(adev) ((adev)->powerplay.pp_handle == (adev)) |
40 | |
41 | int amdgpu_dpm_get_sclk(struct amdgpu_device *adev, bool low) |
42 | { |
43 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
44 | int ret = 0; |
45 | |
46 | if (!pp_funcs->get_sclk) |
47 | return 0; |
48 | |
49 | mutex_lock(&adev->pm.mutex); |
50 | ret = pp_funcs->get_sclk((adev)->powerplay.pp_handle, |
51 | low); |
52 | mutex_unlock(lock: &adev->pm.mutex); |
53 | |
54 | return ret; |
55 | } |
56 | |
57 | int amdgpu_dpm_get_mclk(struct amdgpu_device *adev, bool low) |
58 | { |
59 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
60 | int ret = 0; |
61 | |
62 | if (!pp_funcs->get_mclk) |
63 | return 0; |
64 | |
65 | mutex_lock(&adev->pm.mutex); |
66 | ret = pp_funcs->get_mclk((adev)->powerplay.pp_handle, |
67 | low); |
68 | mutex_unlock(lock: &adev->pm.mutex); |
69 | |
70 | return ret; |
71 | } |
72 | |
73 | int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block_type, bool gate) |
74 | { |
75 | int ret = 0; |
76 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
77 | enum ip_power_state pwr_state = gate ? POWER_STATE_OFF : POWER_STATE_ON; |
78 | |
79 | if (atomic_read(v: &adev->pm.pwr_state[block_type]) == pwr_state) { |
80 | dev_dbg(adev->dev, "IP block%d already in the target %s state!" , |
81 | block_type, gate ? "gate" : "ungate" ); |
82 | return 0; |
83 | } |
84 | |
85 | mutex_lock(&adev->pm.mutex); |
86 | |
87 | switch (block_type) { |
88 | case AMD_IP_BLOCK_TYPE_UVD: |
89 | case AMD_IP_BLOCK_TYPE_VCE: |
90 | case AMD_IP_BLOCK_TYPE_GFX: |
91 | case AMD_IP_BLOCK_TYPE_VCN: |
92 | case AMD_IP_BLOCK_TYPE_SDMA: |
93 | case AMD_IP_BLOCK_TYPE_JPEG: |
94 | case AMD_IP_BLOCK_TYPE_GMC: |
95 | case AMD_IP_BLOCK_TYPE_ACP: |
96 | case AMD_IP_BLOCK_TYPE_VPE: |
97 | if (pp_funcs && pp_funcs->set_powergating_by_smu) |
98 | ret = (pp_funcs->set_powergating_by_smu( |
99 | (adev)->powerplay.pp_handle, block_type, gate)); |
100 | break; |
101 | default: |
102 | break; |
103 | } |
104 | |
105 | if (!ret) |
106 | atomic_set(v: &adev->pm.pwr_state[block_type], i: pwr_state); |
107 | |
108 | mutex_unlock(lock: &adev->pm.mutex); |
109 | |
110 | return ret; |
111 | } |
112 | |
113 | int amdgpu_dpm_set_gfx_power_up_by_imu(struct amdgpu_device *adev) |
114 | { |
115 | struct smu_context *smu = adev->powerplay.pp_handle; |
116 | int ret = -EOPNOTSUPP; |
117 | |
118 | mutex_lock(&adev->pm.mutex); |
119 | ret = smu_set_gfx_power_up_by_imu(smu); |
120 | mutex_unlock(lock: &adev->pm.mutex); |
121 | |
122 | msleep(msecs: 10); |
123 | |
124 | return ret; |
125 | } |
126 | |
127 | int amdgpu_dpm_baco_enter(struct amdgpu_device *adev) |
128 | { |
129 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
130 | void *pp_handle = adev->powerplay.pp_handle; |
131 | int ret = 0; |
132 | |
133 | if (!pp_funcs || !pp_funcs->set_asic_baco_state) |
134 | return -ENOENT; |
135 | |
136 | mutex_lock(&adev->pm.mutex); |
137 | |
138 | /* enter BACO state */ |
139 | ret = pp_funcs->set_asic_baco_state(pp_handle, 1); |
140 | |
141 | mutex_unlock(lock: &adev->pm.mutex); |
142 | |
143 | return ret; |
144 | } |
145 | |
146 | int amdgpu_dpm_baco_exit(struct amdgpu_device *adev) |
147 | { |
148 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
149 | void *pp_handle = adev->powerplay.pp_handle; |
150 | int ret = 0; |
151 | |
152 | if (!pp_funcs || !pp_funcs->set_asic_baco_state) |
153 | return -ENOENT; |
154 | |
155 | mutex_lock(&adev->pm.mutex); |
156 | |
157 | /* exit BACO state */ |
158 | ret = pp_funcs->set_asic_baco_state(pp_handle, 0); |
159 | |
160 | mutex_unlock(lock: &adev->pm.mutex); |
161 | |
162 | return ret; |
163 | } |
164 | |
165 | int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev, |
166 | enum pp_mp1_state mp1_state) |
167 | { |
168 | int ret = 0; |
169 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
170 | |
171 | if (pp_funcs && pp_funcs->set_mp1_state) { |
172 | mutex_lock(&adev->pm.mutex); |
173 | |
174 | ret = pp_funcs->set_mp1_state( |
175 | adev->powerplay.pp_handle, |
176 | mp1_state); |
177 | |
178 | mutex_unlock(lock: &adev->pm.mutex); |
179 | } |
180 | |
181 | return ret; |
182 | } |
183 | |
184 | int amdgpu_dpm_notify_rlc_state(struct amdgpu_device *adev, bool en) |
185 | { |
186 | int ret = 0; |
187 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
188 | |
189 | if (pp_funcs && pp_funcs->notify_rlc_state) { |
190 | mutex_lock(&adev->pm.mutex); |
191 | |
192 | ret = pp_funcs->notify_rlc_state( |
193 | adev->powerplay.pp_handle, |
194 | en); |
195 | |
196 | mutex_unlock(lock: &adev->pm.mutex); |
197 | } |
198 | |
199 | return ret; |
200 | } |
201 | |
202 | bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) |
203 | { |
204 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
205 | void *pp_handle = adev->powerplay.pp_handle; |
206 | bool ret; |
207 | |
208 | if (!pp_funcs || !pp_funcs->get_asic_baco_capability) |
209 | return false; |
210 | /* Don't use baco for reset in S3. |
211 | * This is a workaround for some platforms |
212 | * where entering BACO during suspend |
213 | * seems to cause reboots or hangs. |
214 | * This might be related to the fact that BACO controls |
215 | * power to the whole GPU including devices like audio and USB. |
216 | * Powering down/up everything may adversely affect these other |
217 | * devices. Needs more investigation. |
218 | */ |
219 | if (adev->in_s3) |
220 | return false; |
221 | |
222 | mutex_lock(&adev->pm.mutex); |
223 | |
224 | ret = pp_funcs->get_asic_baco_capability(pp_handle); |
225 | |
226 | mutex_unlock(lock: &adev->pm.mutex); |
227 | |
228 | return ret; |
229 | } |
230 | |
231 | int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev) |
232 | { |
233 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
234 | void *pp_handle = adev->powerplay.pp_handle; |
235 | int ret = 0; |
236 | |
237 | if (!pp_funcs || !pp_funcs->asic_reset_mode_2) |
238 | return -ENOENT; |
239 | |
240 | mutex_lock(&adev->pm.mutex); |
241 | |
242 | ret = pp_funcs->asic_reset_mode_2(pp_handle); |
243 | |
244 | mutex_unlock(lock: &adev->pm.mutex); |
245 | |
246 | return ret; |
247 | } |
248 | |
249 | int amdgpu_dpm_enable_gfx_features(struct amdgpu_device *adev) |
250 | { |
251 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
252 | void *pp_handle = adev->powerplay.pp_handle; |
253 | int ret = 0; |
254 | |
255 | if (!pp_funcs || !pp_funcs->asic_reset_enable_gfx_features) |
256 | return -ENOENT; |
257 | |
258 | mutex_lock(&adev->pm.mutex); |
259 | |
260 | ret = pp_funcs->asic_reset_enable_gfx_features(pp_handle); |
261 | |
262 | mutex_unlock(lock: &adev->pm.mutex); |
263 | |
264 | return ret; |
265 | } |
266 | |
267 | int amdgpu_dpm_baco_reset(struct amdgpu_device *adev) |
268 | { |
269 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
270 | void *pp_handle = adev->powerplay.pp_handle; |
271 | int ret = 0; |
272 | |
273 | if (!pp_funcs || !pp_funcs->set_asic_baco_state) |
274 | return -ENOENT; |
275 | |
276 | mutex_lock(&adev->pm.mutex); |
277 | |
278 | /* enter BACO state */ |
279 | ret = pp_funcs->set_asic_baco_state(pp_handle, 1); |
280 | if (ret) |
281 | goto out; |
282 | |
283 | /* exit BACO state */ |
284 | ret = pp_funcs->set_asic_baco_state(pp_handle, 0); |
285 | |
286 | out: |
287 | mutex_unlock(lock: &adev->pm.mutex); |
288 | return ret; |
289 | } |
290 | |
291 | bool amdgpu_dpm_is_mode1_reset_supported(struct amdgpu_device *adev) |
292 | { |
293 | struct smu_context *smu = adev->powerplay.pp_handle; |
294 | bool support_mode1_reset = false; |
295 | |
296 | if (is_support_sw_smu(adev)) { |
297 | mutex_lock(&adev->pm.mutex); |
298 | support_mode1_reset = smu_mode1_reset_is_support(smu); |
299 | mutex_unlock(lock: &adev->pm.mutex); |
300 | } |
301 | |
302 | return support_mode1_reset; |
303 | } |
304 | |
305 | int amdgpu_dpm_mode1_reset(struct amdgpu_device *adev) |
306 | { |
307 | struct smu_context *smu = adev->powerplay.pp_handle; |
308 | int ret = -EOPNOTSUPP; |
309 | |
310 | if (is_support_sw_smu(adev)) { |
311 | mutex_lock(&adev->pm.mutex); |
312 | ret = smu_mode1_reset(smu); |
313 | mutex_unlock(lock: &adev->pm.mutex); |
314 | } |
315 | |
316 | return ret; |
317 | } |
318 | |
319 | int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev, |
320 | enum PP_SMC_POWER_PROFILE type, |
321 | bool en) |
322 | { |
323 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
324 | int ret = 0; |
325 | |
326 | if (amdgpu_sriov_vf(adev)) |
327 | return 0; |
328 | |
329 | if (pp_funcs && pp_funcs->switch_power_profile) { |
330 | mutex_lock(&adev->pm.mutex); |
331 | ret = pp_funcs->switch_power_profile( |
332 | adev->powerplay.pp_handle, type, en); |
333 | mutex_unlock(lock: &adev->pm.mutex); |
334 | } |
335 | |
336 | return ret; |
337 | } |
338 | |
339 | int amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev, |
340 | uint32_t pstate) |
341 | { |
342 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
343 | int ret = 0; |
344 | |
345 | if (pp_funcs && pp_funcs->set_xgmi_pstate) { |
346 | mutex_lock(&adev->pm.mutex); |
347 | ret = pp_funcs->set_xgmi_pstate(adev->powerplay.pp_handle, |
348 | pstate); |
349 | mutex_unlock(lock: &adev->pm.mutex); |
350 | } |
351 | |
352 | return ret; |
353 | } |
354 | |
355 | int amdgpu_dpm_set_df_cstate(struct amdgpu_device *adev, |
356 | uint32_t cstate) |
357 | { |
358 | int ret = 0; |
359 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
360 | void *pp_handle = adev->powerplay.pp_handle; |
361 | |
362 | if (pp_funcs && pp_funcs->set_df_cstate) { |
363 | mutex_lock(&adev->pm.mutex); |
364 | ret = pp_funcs->set_df_cstate(pp_handle, cstate); |
365 | mutex_unlock(lock: &adev->pm.mutex); |
366 | } |
367 | |
368 | return ret; |
369 | } |
370 | |
371 | int amdgpu_dpm_get_xgmi_plpd_mode(struct amdgpu_device *adev, char **mode_desc) |
372 | { |
373 | struct smu_context *smu = adev->powerplay.pp_handle; |
374 | int mode = XGMI_PLPD_NONE; |
375 | |
376 | if (is_support_sw_smu(adev)) { |
377 | mode = smu->plpd_mode; |
378 | if (mode_desc == NULL) |
379 | return mode; |
380 | switch (smu->plpd_mode) { |
381 | case XGMI_PLPD_DISALLOW: |
382 | *mode_desc = "disallow" ; |
383 | break; |
384 | case XGMI_PLPD_DEFAULT: |
385 | *mode_desc = "default" ; |
386 | break; |
387 | case XGMI_PLPD_OPTIMIZED: |
388 | *mode_desc = "optimized" ; |
389 | break; |
390 | case XGMI_PLPD_NONE: |
391 | default: |
392 | *mode_desc = "none" ; |
393 | break; |
394 | } |
395 | } |
396 | |
397 | return mode; |
398 | } |
399 | |
400 | int amdgpu_dpm_set_xgmi_plpd_mode(struct amdgpu_device *adev, int mode) |
401 | { |
402 | struct smu_context *smu = adev->powerplay.pp_handle; |
403 | int ret = -EOPNOTSUPP; |
404 | |
405 | if (is_support_sw_smu(adev)) { |
406 | mutex_lock(&adev->pm.mutex); |
407 | ret = smu_set_xgmi_plpd_mode(smu, mode); |
408 | mutex_unlock(lock: &adev->pm.mutex); |
409 | } |
410 | |
411 | return ret; |
412 | } |
413 | |
414 | int amdgpu_dpm_enable_mgpu_fan_boost(struct amdgpu_device *adev) |
415 | { |
416 | void *pp_handle = adev->powerplay.pp_handle; |
417 | const struct amd_pm_funcs *pp_funcs = |
418 | adev->powerplay.pp_funcs; |
419 | int ret = 0; |
420 | |
421 | if (pp_funcs && pp_funcs->enable_mgpu_fan_boost) { |
422 | mutex_lock(&adev->pm.mutex); |
423 | ret = pp_funcs->enable_mgpu_fan_boost(pp_handle); |
424 | mutex_unlock(lock: &adev->pm.mutex); |
425 | } |
426 | |
427 | return ret; |
428 | } |
429 | |
430 | int amdgpu_dpm_set_clockgating_by_smu(struct amdgpu_device *adev, |
431 | uint32_t msg_id) |
432 | { |
433 | void *pp_handle = adev->powerplay.pp_handle; |
434 | const struct amd_pm_funcs *pp_funcs = |
435 | adev->powerplay.pp_funcs; |
436 | int ret = 0; |
437 | |
438 | if (pp_funcs && pp_funcs->set_clockgating_by_smu) { |
439 | mutex_lock(&adev->pm.mutex); |
440 | ret = pp_funcs->set_clockgating_by_smu(pp_handle, |
441 | msg_id); |
442 | mutex_unlock(lock: &adev->pm.mutex); |
443 | } |
444 | |
445 | return ret; |
446 | } |
447 | |
448 | int amdgpu_dpm_smu_i2c_bus_access(struct amdgpu_device *adev, |
449 | bool acquire) |
450 | { |
451 | void *pp_handle = adev->powerplay.pp_handle; |
452 | const struct amd_pm_funcs *pp_funcs = |
453 | adev->powerplay.pp_funcs; |
454 | int ret = -EOPNOTSUPP; |
455 | |
456 | if (pp_funcs && pp_funcs->smu_i2c_bus_access) { |
457 | mutex_lock(&adev->pm.mutex); |
458 | ret = pp_funcs->smu_i2c_bus_access(pp_handle, |
459 | acquire); |
460 | mutex_unlock(lock: &adev->pm.mutex); |
461 | } |
462 | |
463 | return ret; |
464 | } |
465 | |
466 | void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) |
467 | { |
468 | if (adev->pm.dpm_enabled) { |
469 | mutex_lock(&adev->pm.mutex); |
470 | if (power_supply_is_system_supplied() > 0) |
471 | adev->pm.ac_power = true; |
472 | else |
473 | adev->pm.ac_power = false; |
474 | |
475 | if (adev->powerplay.pp_funcs && |
476 | adev->powerplay.pp_funcs->enable_bapm) |
477 | amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power); |
478 | |
479 | if (is_support_sw_smu(adev)) |
480 | smu_set_ac_dc(smu: adev->powerplay.pp_handle); |
481 | |
482 | mutex_unlock(lock: &adev->pm.mutex); |
483 | } |
484 | } |
485 | |
486 | int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor, |
487 | void *data, uint32_t *size) |
488 | { |
489 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
490 | int ret = -EINVAL; |
491 | |
492 | if (!data || !size) |
493 | return -EINVAL; |
494 | |
495 | if (pp_funcs && pp_funcs->read_sensor) { |
496 | mutex_lock(&adev->pm.mutex); |
497 | ret = pp_funcs->read_sensor(adev->powerplay.pp_handle, |
498 | sensor, |
499 | data, |
500 | size); |
501 | mutex_unlock(lock: &adev->pm.mutex); |
502 | } |
503 | |
504 | return ret; |
505 | } |
506 | |
507 | int amdgpu_dpm_get_apu_thermal_limit(struct amdgpu_device *adev, uint32_t *limit) |
508 | { |
509 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
510 | int ret = -EOPNOTSUPP; |
511 | |
512 | if (pp_funcs && pp_funcs->get_apu_thermal_limit) { |
513 | mutex_lock(&adev->pm.mutex); |
514 | ret = pp_funcs->get_apu_thermal_limit(adev->powerplay.pp_handle, limit); |
515 | mutex_unlock(lock: &adev->pm.mutex); |
516 | } |
517 | |
518 | return ret; |
519 | } |
520 | |
521 | int amdgpu_dpm_set_apu_thermal_limit(struct amdgpu_device *adev, uint32_t limit) |
522 | { |
523 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
524 | int ret = -EOPNOTSUPP; |
525 | |
526 | if (pp_funcs && pp_funcs->set_apu_thermal_limit) { |
527 | mutex_lock(&adev->pm.mutex); |
528 | ret = pp_funcs->set_apu_thermal_limit(adev->powerplay.pp_handle, limit); |
529 | mutex_unlock(lock: &adev->pm.mutex); |
530 | } |
531 | |
532 | return ret; |
533 | } |
534 | |
535 | void amdgpu_dpm_compute_clocks(struct amdgpu_device *adev) |
536 | { |
537 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
538 | int i; |
539 | |
540 | if (!adev->pm.dpm_enabled) |
541 | return; |
542 | |
543 | if (!pp_funcs->pm_compute_clocks) |
544 | return; |
545 | |
546 | if (adev->mode_info.num_crtc) |
547 | amdgpu_display_bandwidth_update(adev); |
548 | |
549 | for (i = 0; i < AMDGPU_MAX_RINGS; i++) { |
550 | struct amdgpu_ring *ring = adev->rings[i]; |
551 | if (ring && ring->sched.ready) |
552 | amdgpu_fence_wait_empty(ring); |
553 | } |
554 | |
555 | mutex_lock(&adev->pm.mutex); |
556 | pp_funcs->pm_compute_clocks(adev->powerplay.pp_handle); |
557 | mutex_unlock(lock: &adev->pm.mutex); |
558 | } |
559 | |
560 | void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) |
561 | { |
562 | int ret = 0; |
563 | |
564 | if (adev->family == AMDGPU_FAMILY_SI) { |
565 | mutex_lock(&adev->pm.mutex); |
566 | if (enable) { |
567 | adev->pm.dpm.uvd_active = true; |
568 | adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD; |
569 | } else { |
570 | adev->pm.dpm.uvd_active = false; |
571 | } |
572 | mutex_unlock(lock: &adev->pm.mutex); |
573 | |
574 | amdgpu_dpm_compute_clocks(adev); |
575 | return; |
576 | } |
577 | |
578 | ret = amdgpu_dpm_set_powergating_by_smu(adev, block_type: AMD_IP_BLOCK_TYPE_UVD, gate: !enable); |
579 | if (ret) |
580 | DRM_ERROR("Dpm %s uvd failed, ret = %d. \n" , |
581 | enable ? "enable" : "disable" , ret); |
582 | } |
583 | |
584 | void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) |
585 | { |
586 | int ret = 0; |
587 | |
588 | if (adev->family == AMDGPU_FAMILY_SI) { |
589 | mutex_lock(&adev->pm.mutex); |
590 | if (enable) { |
591 | adev->pm.dpm.vce_active = true; |
592 | /* XXX select vce level based on ring/task */ |
593 | adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL; |
594 | } else { |
595 | adev->pm.dpm.vce_active = false; |
596 | } |
597 | mutex_unlock(lock: &adev->pm.mutex); |
598 | |
599 | amdgpu_dpm_compute_clocks(adev); |
600 | return; |
601 | } |
602 | |
603 | ret = amdgpu_dpm_set_powergating_by_smu(adev, block_type: AMD_IP_BLOCK_TYPE_VCE, gate: !enable); |
604 | if (ret) |
605 | DRM_ERROR("Dpm %s vce failed, ret = %d. \n" , |
606 | enable ? "enable" : "disable" , ret); |
607 | } |
608 | |
609 | void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) |
610 | { |
611 | int ret = 0; |
612 | |
613 | ret = amdgpu_dpm_set_powergating_by_smu(adev, block_type: AMD_IP_BLOCK_TYPE_JPEG, gate: !enable); |
614 | if (ret) |
615 | DRM_ERROR("Dpm %s jpeg failed, ret = %d. \n" , |
616 | enable ? "enable" : "disable" , ret); |
617 | } |
618 | |
619 | void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable) |
620 | { |
621 | int ret = 0; |
622 | |
623 | ret = amdgpu_dpm_set_powergating_by_smu(adev, block_type: AMD_IP_BLOCK_TYPE_VPE, gate: !enable); |
624 | if (ret) |
625 | DRM_ERROR("Dpm %s vpe failed, ret = %d.\n" , |
626 | enable ? "enable" : "disable" , ret); |
627 | } |
628 | |
629 | int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version) |
630 | { |
631 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
632 | int r = 0; |
633 | |
634 | if (!pp_funcs || !pp_funcs->load_firmware) |
635 | return 0; |
636 | |
637 | mutex_lock(&adev->pm.mutex); |
638 | r = pp_funcs->load_firmware(adev->powerplay.pp_handle); |
639 | if (r) { |
640 | pr_err("smu firmware loading failed\n" ); |
641 | goto out; |
642 | } |
643 | |
644 | if (smu_version) |
645 | *smu_version = adev->pm.fw_version; |
646 | |
647 | out: |
648 | mutex_unlock(lock: &adev->pm.mutex); |
649 | return r; |
650 | } |
651 | |
652 | int amdgpu_dpm_handle_passthrough_sbr(struct amdgpu_device *adev, bool enable) |
653 | { |
654 | int ret = 0; |
655 | |
656 | if (is_support_sw_smu(adev)) { |
657 | mutex_lock(&adev->pm.mutex); |
658 | ret = smu_handle_passthrough_sbr(smu: adev->powerplay.pp_handle, |
659 | enable); |
660 | mutex_unlock(lock: &adev->pm.mutex); |
661 | } |
662 | |
663 | return ret; |
664 | } |
665 | |
666 | int amdgpu_dpm_send_hbm_bad_pages_num(struct amdgpu_device *adev, uint32_t size) |
667 | { |
668 | struct smu_context *smu = adev->powerplay.pp_handle; |
669 | int ret = 0; |
670 | |
671 | if (!is_support_sw_smu(adev)) |
672 | return -EOPNOTSUPP; |
673 | |
674 | mutex_lock(&adev->pm.mutex); |
675 | ret = smu_send_hbm_bad_pages_num(smu, size); |
676 | mutex_unlock(lock: &adev->pm.mutex); |
677 | |
678 | return ret; |
679 | } |
680 | |
681 | int amdgpu_dpm_send_hbm_bad_channel_flag(struct amdgpu_device *adev, uint32_t size) |
682 | { |
683 | struct smu_context *smu = adev->powerplay.pp_handle; |
684 | int ret = 0; |
685 | |
686 | if (!is_support_sw_smu(adev)) |
687 | return -EOPNOTSUPP; |
688 | |
689 | mutex_lock(&adev->pm.mutex); |
690 | ret = smu_send_hbm_bad_channel_flag(smu, size); |
691 | mutex_unlock(lock: &adev->pm.mutex); |
692 | |
693 | return ret; |
694 | } |
695 | |
696 | int amdgpu_dpm_send_rma_reason(struct amdgpu_device *adev) |
697 | { |
698 | struct smu_context *smu = adev->powerplay.pp_handle; |
699 | int ret; |
700 | |
701 | if (!is_support_sw_smu(adev)) |
702 | return -EOPNOTSUPP; |
703 | |
704 | mutex_lock(&adev->pm.mutex); |
705 | ret = smu_send_rma_reason(smu); |
706 | mutex_unlock(lock: &adev->pm.mutex); |
707 | |
708 | return ret; |
709 | } |
710 | |
711 | int amdgpu_dpm_get_dpm_freq_range(struct amdgpu_device *adev, |
712 | enum pp_clock_type type, |
713 | uint32_t *min, |
714 | uint32_t *max) |
715 | { |
716 | int ret = 0; |
717 | |
718 | if (type != PP_SCLK) |
719 | return -EINVAL; |
720 | |
721 | if (!is_support_sw_smu(adev)) |
722 | return -EOPNOTSUPP; |
723 | |
724 | mutex_lock(&adev->pm.mutex); |
725 | ret = smu_get_dpm_freq_range(smu: adev->powerplay.pp_handle, |
726 | clk_type: SMU_SCLK, |
727 | min, |
728 | max); |
729 | mutex_unlock(lock: &adev->pm.mutex); |
730 | |
731 | return ret; |
732 | } |
733 | |
734 | int amdgpu_dpm_set_soft_freq_range(struct amdgpu_device *adev, |
735 | enum pp_clock_type type, |
736 | uint32_t min, |
737 | uint32_t max) |
738 | { |
739 | struct smu_context *smu = adev->powerplay.pp_handle; |
740 | int ret = 0; |
741 | |
742 | if (type != PP_SCLK) |
743 | return -EINVAL; |
744 | |
745 | if (!is_support_sw_smu(adev)) |
746 | return -EOPNOTSUPP; |
747 | |
748 | mutex_lock(&adev->pm.mutex); |
749 | ret = smu_set_soft_freq_range(smu, |
750 | clk_type: SMU_SCLK, |
751 | min, |
752 | max); |
753 | mutex_unlock(lock: &adev->pm.mutex); |
754 | |
755 | return ret; |
756 | } |
757 | |
758 | int amdgpu_dpm_write_watermarks_table(struct amdgpu_device *adev) |
759 | { |
760 | struct smu_context *smu = adev->powerplay.pp_handle; |
761 | int ret = 0; |
762 | |
763 | if (!is_support_sw_smu(adev)) |
764 | return 0; |
765 | |
766 | mutex_lock(&adev->pm.mutex); |
767 | ret = smu_write_watermarks_table(smu); |
768 | mutex_unlock(lock: &adev->pm.mutex); |
769 | |
770 | return ret; |
771 | } |
772 | |
773 | int amdgpu_dpm_wait_for_event(struct amdgpu_device *adev, |
774 | enum smu_event_type event, |
775 | uint64_t event_arg) |
776 | { |
777 | struct smu_context *smu = adev->powerplay.pp_handle; |
778 | int ret = 0; |
779 | |
780 | if (!is_support_sw_smu(adev)) |
781 | return -EOPNOTSUPP; |
782 | |
783 | mutex_lock(&adev->pm.mutex); |
784 | ret = smu_wait_for_event(smu, event, event_arg); |
785 | mutex_unlock(lock: &adev->pm.mutex); |
786 | |
787 | return ret; |
788 | } |
789 | |
790 | int amdgpu_dpm_set_residency_gfxoff(struct amdgpu_device *adev, bool value) |
791 | { |
792 | struct smu_context *smu = adev->powerplay.pp_handle; |
793 | int ret = 0; |
794 | |
795 | if (!is_support_sw_smu(adev)) |
796 | return -EOPNOTSUPP; |
797 | |
798 | mutex_lock(&adev->pm.mutex); |
799 | ret = smu_set_residency_gfxoff(smu, value); |
800 | mutex_unlock(lock: &adev->pm.mutex); |
801 | |
802 | return ret; |
803 | } |
804 | |
805 | int amdgpu_dpm_get_residency_gfxoff(struct amdgpu_device *adev, u32 *value) |
806 | { |
807 | struct smu_context *smu = adev->powerplay.pp_handle; |
808 | int ret = 0; |
809 | |
810 | if (!is_support_sw_smu(adev)) |
811 | return -EOPNOTSUPP; |
812 | |
813 | mutex_lock(&adev->pm.mutex); |
814 | ret = smu_get_residency_gfxoff(smu, value); |
815 | mutex_unlock(lock: &adev->pm.mutex); |
816 | |
817 | return ret; |
818 | } |
819 | |
820 | int amdgpu_dpm_get_entrycount_gfxoff(struct amdgpu_device *adev, u64 *value) |
821 | { |
822 | struct smu_context *smu = adev->powerplay.pp_handle; |
823 | int ret = 0; |
824 | |
825 | if (!is_support_sw_smu(adev)) |
826 | return -EOPNOTSUPP; |
827 | |
828 | mutex_lock(&adev->pm.mutex); |
829 | ret = smu_get_entrycount_gfxoff(smu, value); |
830 | mutex_unlock(lock: &adev->pm.mutex); |
831 | |
832 | return ret; |
833 | } |
834 | |
835 | int amdgpu_dpm_get_status_gfxoff(struct amdgpu_device *adev, uint32_t *value) |
836 | { |
837 | struct smu_context *smu = adev->powerplay.pp_handle; |
838 | int ret = 0; |
839 | |
840 | if (!is_support_sw_smu(adev)) |
841 | return -EOPNOTSUPP; |
842 | |
843 | mutex_lock(&adev->pm.mutex); |
844 | ret = smu_get_status_gfxoff(smu, value); |
845 | mutex_unlock(lock: &adev->pm.mutex); |
846 | |
847 | return ret; |
848 | } |
849 | |
850 | uint64_t amdgpu_dpm_get_thermal_throttling_counter(struct amdgpu_device *adev) |
851 | { |
852 | struct smu_context *smu = adev->powerplay.pp_handle; |
853 | |
854 | if (!is_support_sw_smu(adev)) |
855 | return 0; |
856 | |
857 | return atomic64_read(v: &smu->throttle_int_counter); |
858 | } |
859 | |
860 | /* amdgpu_dpm_gfx_state_change - Handle gfx power state change set |
861 | * @adev: amdgpu_device pointer |
862 | * @state: gfx power state(1 -sGpuChangeState_D0Entry and 2 -sGpuChangeState_D3Entry) |
863 | * |
864 | */ |
865 | void amdgpu_dpm_gfx_state_change(struct amdgpu_device *adev, |
866 | enum gfx_change_state state) |
867 | { |
868 | mutex_lock(&adev->pm.mutex); |
869 | if (adev->powerplay.pp_funcs && |
870 | adev->powerplay.pp_funcs->gfx_state_change_set) |
871 | ((adev)->powerplay.pp_funcs->gfx_state_change_set( |
872 | (adev)->powerplay.pp_handle, state)); |
873 | mutex_unlock(lock: &adev->pm.mutex); |
874 | } |
875 | |
876 | int amdgpu_dpm_get_ecc_info(struct amdgpu_device *adev, |
877 | void *umc_ecc) |
878 | { |
879 | struct smu_context *smu = adev->powerplay.pp_handle; |
880 | int ret = 0; |
881 | |
882 | if (!is_support_sw_smu(adev)) |
883 | return -EOPNOTSUPP; |
884 | |
885 | mutex_lock(&adev->pm.mutex); |
886 | ret = smu_get_ecc_info(smu, umc_ecc); |
887 | mutex_unlock(lock: &adev->pm.mutex); |
888 | |
889 | return ret; |
890 | } |
891 | |
892 | struct amd_vce_state *amdgpu_dpm_get_vce_clock_state(struct amdgpu_device *adev, |
893 | uint32_t idx) |
894 | { |
895 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
896 | struct amd_vce_state *vstate = NULL; |
897 | |
898 | if (!pp_funcs->get_vce_clock_state) |
899 | return NULL; |
900 | |
901 | mutex_lock(&adev->pm.mutex); |
902 | vstate = pp_funcs->get_vce_clock_state(adev->powerplay.pp_handle, |
903 | idx); |
904 | mutex_unlock(lock: &adev->pm.mutex); |
905 | |
906 | return vstate; |
907 | } |
908 | |
909 | void amdgpu_dpm_get_current_power_state(struct amdgpu_device *adev, |
910 | enum amd_pm_state_type *state) |
911 | { |
912 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
913 | |
914 | mutex_lock(&adev->pm.mutex); |
915 | |
916 | if (!pp_funcs->get_current_power_state) { |
917 | *state = adev->pm.dpm.user_state; |
918 | goto out; |
919 | } |
920 | |
921 | *state = pp_funcs->get_current_power_state(adev->powerplay.pp_handle); |
922 | if (*state < POWER_STATE_TYPE_DEFAULT || |
923 | *state > POWER_STATE_TYPE_INTERNAL_3DPERF) |
924 | *state = adev->pm.dpm.user_state; |
925 | |
926 | out: |
927 | mutex_unlock(lock: &adev->pm.mutex); |
928 | } |
929 | |
930 | void amdgpu_dpm_set_power_state(struct amdgpu_device *adev, |
931 | enum amd_pm_state_type state) |
932 | { |
933 | mutex_lock(&adev->pm.mutex); |
934 | adev->pm.dpm.user_state = state; |
935 | mutex_unlock(lock: &adev->pm.mutex); |
936 | |
937 | if (is_support_sw_smu(adev)) |
938 | return; |
939 | |
940 | if (amdgpu_dpm_dispatch_task(adev, |
941 | task_id: AMD_PP_TASK_ENABLE_USER_STATE, |
942 | user_state: &state) == -EOPNOTSUPP) |
943 | amdgpu_dpm_compute_clocks(adev); |
944 | } |
945 | |
946 | enum amd_dpm_forced_level amdgpu_dpm_get_performance_level(struct amdgpu_device *adev) |
947 | { |
948 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
949 | enum amd_dpm_forced_level level; |
950 | |
951 | if (!pp_funcs) |
952 | return AMD_DPM_FORCED_LEVEL_AUTO; |
953 | |
954 | mutex_lock(&adev->pm.mutex); |
955 | if (pp_funcs->get_performance_level) |
956 | level = pp_funcs->get_performance_level(adev->powerplay.pp_handle); |
957 | else |
958 | level = adev->pm.dpm.forced_level; |
959 | mutex_unlock(lock: &adev->pm.mutex); |
960 | |
961 | return level; |
962 | } |
963 | |
964 | int amdgpu_dpm_force_performance_level(struct amdgpu_device *adev, |
965 | enum amd_dpm_forced_level level) |
966 | { |
967 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
968 | enum amd_dpm_forced_level current_level; |
969 | uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD | |
970 | AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK | |
971 | AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK | |
972 | AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; |
973 | |
974 | if (!pp_funcs || !pp_funcs->force_performance_level) |
975 | return 0; |
976 | |
977 | if (adev->pm.dpm.thermal_active) |
978 | return -EINVAL; |
979 | |
980 | current_level = amdgpu_dpm_get_performance_level(adev); |
981 | if (current_level == level) |
982 | return 0; |
983 | |
984 | if (adev->asic_type == CHIP_RAVEN) { |
985 | if (!(adev->apu_flags & AMD_APU_IS_RAVEN2)) { |
986 | if (current_level != AMD_DPM_FORCED_LEVEL_MANUAL && |
987 | level == AMD_DPM_FORCED_LEVEL_MANUAL) |
988 | amdgpu_gfx_off_ctrl(adev, enable: false); |
989 | else if (current_level == AMD_DPM_FORCED_LEVEL_MANUAL && |
990 | level != AMD_DPM_FORCED_LEVEL_MANUAL) |
991 | amdgpu_gfx_off_ctrl(adev, enable: true); |
992 | } |
993 | } |
994 | |
995 | if (!(current_level & profile_mode_mask) && |
996 | (level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)) |
997 | return -EINVAL; |
998 | |
999 | if (!(current_level & profile_mode_mask) && |
1000 | (level & profile_mode_mask)) { |
1001 | /* enter UMD Pstate */ |
1002 | amdgpu_device_ip_set_powergating_state(dev: adev, |
1003 | block_type: AMD_IP_BLOCK_TYPE_GFX, |
1004 | state: AMD_PG_STATE_UNGATE); |
1005 | amdgpu_device_ip_set_clockgating_state(dev: adev, |
1006 | block_type: AMD_IP_BLOCK_TYPE_GFX, |
1007 | state: AMD_CG_STATE_UNGATE); |
1008 | } else if ((current_level & profile_mode_mask) && |
1009 | !(level & profile_mode_mask)) { |
1010 | /* exit UMD Pstate */ |
1011 | amdgpu_device_ip_set_clockgating_state(dev: adev, |
1012 | block_type: AMD_IP_BLOCK_TYPE_GFX, |
1013 | state: AMD_CG_STATE_GATE); |
1014 | amdgpu_device_ip_set_powergating_state(dev: adev, |
1015 | block_type: AMD_IP_BLOCK_TYPE_GFX, |
1016 | state: AMD_PG_STATE_GATE); |
1017 | } |
1018 | |
1019 | mutex_lock(&adev->pm.mutex); |
1020 | |
1021 | if (pp_funcs->force_performance_level(adev->powerplay.pp_handle, |
1022 | level)) { |
1023 | mutex_unlock(lock: &adev->pm.mutex); |
1024 | return -EINVAL; |
1025 | } |
1026 | |
1027 | adev->pm.dpm.forced_level = level; |
1028 | |
1029 | mutex_unlock(lock: &adev->pm.mutex); |
1030 | |
1031 | return 0; |
1032 | } |
1033 | |
1034 | int amdgpu_dpm_get_pp_num_states(struct amdgpu_device *adev, |
1035 | struct pp_states_info *states) |
1036 | { |
1037 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1038 | int ret = 0; |
1039 | |
1040 | if (!pp_funcs->get_pp_num_states) |
1041 | return -EOPNOTSUPP; |
1042 | |
1043 | mutex_lock(&adev->pm.mutex); |
1044 | ret = pp_funcs->get_pp_num_states(adev->powerplay.pp_handle, |
1045 | states); |
1046 | mutex_unlock(lock: &adev->pm.mutex); |
1047 | |
1048 | return ret; |
1049 | } |
1050 | |
1051 | int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev, |
1052 | enum amd_pp_task task_id, |
1053 | enum amd_pm_state_type *user_state) |
1054 | { |
1055 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1056 | int ret = 0; |
1057 | |
1058 | if (!pp_funcs->dispatch_tasks) |
1059 | return -EOPNOTSUPP; |
1060 | |
1061 | mutex_lock(&adev->pm.mutex); |
1062 | ret = pp_funcs->dispatch_tasks(adev->powerplay.pp_handle, |
1063 | task_id, |
1064 | user_state); |
1065 | mutex_unlock(lock: &adev->pm.mutex); |
1066 | |
1067 | return ret; |
1068 | } |
1069 | |
1070 | int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table) |
1071 | { |
1072 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1073 | int ret = 0; |
1074 | |
1075 | if (!pp_funcs->get_pp_table) |
1076 | return 0; |
1077 | |
1078 | mutex_lock(&adev->pm.mutex); |
1079 | ret = pp_funcs->get_pp_table(adev->powerplay.pp_handle, |
1080 | table); |
1081 | mutex_unlock(lock: &adev->pm.mutex); |
1082 | |
1083 | return ret; |
1084 | } |
1085 | |
1086 | int amdgpu_dpm_set_fine_grain_clk_vol(struct amdgpu_device *adev, |
1087 | uint32_t type, |
1088 | long *input, |
1089 | uint32_t size) |
1090 | { |
1091 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1092 | int ret = 0; |
1093 | |
1094 | if (!pp_funcs->set_fine_grain_clk_vol) |
1095 | return 0; |
1096 | |
1097 | mutex_lock(&adev->pm.mutex); |
1098 | ret = pp_funcs->set_fine_grain_clk_vol(adev->powerplay.pp_handle, |
1099 | type, |
1100 | input, |
1101 | size); |
1102 | mutex_unlock(lock: &adev->pm.mutex); |
1103 | |
1104 | return ret; |
1105 | } |
1106 | |
1107 | int amdgpu_dpm_odn_edit_dpm_table(struct amdgpu_device *adev, |
1108 | uint32_t type, |
1109 | long *input, |
1110 | uint32_t size) |
1111 | { |
1112 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1113 | int ret = 0; |
1114 | |
1115 | if (!pp_funcs->odn_edit_dpm_table) |
1116 | return 0; |
1117 | |
1118 | mutex_lock(&adev->pm.mutex); |
1119 | ret = pp_funcs->odn_edit_dpm_table(adev->powerplay.pp_handle, |
1120 | type, |
1121 | input, |
1122 | size); |
1123 | mutex_unlock(lock: &adev->pm.mutex); |
1124 | |
1125 | return ret; |
1126 | } |
1127 | |
1128 | int amdgpu_dpm_print_clock_levels(struct amdgpu_device *adev, |
1129 | enum pp_clock_type type, |
1130 | char *buf) |
1131 | { |
1132 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1133 | int ret = 0; |
1134 | |
1135 | if (!pp_funcs->print_clock_levels) |
1136 | return 0; |
1137 | |
1138 | mutex_lock(&adev->pm.mutex); |
1139 | ret = pp_funcs->print_clock_levels(adev->powerplay.pp_handle, |
1140 | type, |
1141 | buf); |
1142 | mutex_unlock(lock: &adev->pm.mutex); |
1143 | |
1144 | return ret; |
1145 | } |
1146 | |
1147 | int amdgpu_dpm_emit_clock_levels(struct amdgpu_device *adev, |
1148 | enum pp_clock_type type, |
1149 | char *buf, |
1150 | int *offset) |
1151 | { |
1152 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1153 | int ret = 0; |
1154 | |
1155 | if (!pp_funcs->emit_clock_levels) |
1156 | return -ENOENT; |
1157 | |
1158 | mutex_lock(&adev->pm.mutex); |
1159 | ret = pp_funcs->emit_clock_levels(adev->powerplay.pp_handle, |
1160 | type, |
1161 | buf, |
1162 | offset); |
1163 | mutex_unlock(lock: &adev->pm.mutex); |
1164 | |
1165 | return ret; |
1166 | } |
1167 | |
1168 | int amdgpu_dpm_set_ppfeature_status(struct amdgpu_device *adev, |
1169 | uint64_t ppfeature_masks) |
1170 | { |
1171 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1172 | int ret = 0; |
1173 | |
1174 | if (!pp_funcs->set_ppfeature_status) |
1175 | return 0; |
1176 | |
1177 | mutex_lock(&adev->pm.mutex); |
1178 | ret = pp_funcs->set_ppfeature_status(adev->powerplay.pp_handle, |
1179 | ppfeature_masks); |
1180 | mutex_unlock(lock: &adev->pm.mutex); |
1181 | |
1182 | return ret; |
1183 | } |
1184 | |
1185 | int amdgpu_dpm_get_ppfeature_status(struct amdgpu_device *adev, char *buf) |
1186 | { |
1187 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1188 | int ret = 0; |
1189 | |
1190 | if (!pp_funcs->get_ppfeature_status) |
1191 | return 0; |
1192 | |
1193 | mutex_lock(&adev->pm.mutex); |
1194 | ret = pp_funcs->get_ppfeature_status(adev->powerplay.pp_handle, |
1195 | buf); |
1196 | mutex_unlock(lock: &adev->pm.mutex); |
1197 | |
1198 | return ret; |
1199 | } |
1200 | |
1201 | int amdgpu_dpm_force_clock_level(struct amdgpu_device *adev, |
1202 | enum pp_clock_type type, |
1203 | uint32_t mask) |
1204 | { |
1205 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1206 | int ret = 0; |
1207 | |
1208 | if (!pp_funcs->force_clock_level) |
1209 | return 0; |
1210 | |
1211 | mutex_lock(&adev->pm.mutex); |
1212 | ret = pp_funcs->force_clock_level(adev->powerplay.pp_handle, |
1213 | type, |
1214 | mask); |
1215 | mutex_unlock(lock: &adev->pm.mutex); |
1216 | |
1217 | return ret; |
1218 | } |
1219 | |
1220 | int amdgpu_dpm_get_sclk_od(struct amdgpu_device *adev) |
1221 | { |
1222 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1223 | int ret = 0; |
1224 | |
1225 | if (!pp_funcs->get_sclk_od) |
1226 | return -EOPNOTSUPP; |
1227 | |
1228 | mutex_lock(&adev->pm.mutex); |
1229 | ret = pp_funcs->get_sclk_od(adev->powerplay.pp_handle); |
1230 | mutex_unlock(lock: &adev->pm.mutex); |
1231 | |
1232 | return ret; |
1233 | } |
1234 | |
1235 | int amdgpu_dpm_set_sclk_od(struct amdgpu_device *adev, uint32_t value) |
1236 | { |
1237 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1238 | |
1239 | if (is_support_sw_smu(adev)) |
1240 | return -EOPNOTSUPP; |
1241 | |
1242 | mutex_lock(&adev->pm.mutex); |
1243 | if (pp_funcs->set_sclk_od) |
1244 | pp_funcs->set_sclk_od(adev->powerplay.pp_handle, value); |
1245 | mutex_unlock(lock: &adev->pm.mutex); |
1246 | |
1247 | if (amdgpu_dpm_dispatch_task(adev, |
1248 | task_id: AMD_PP_TASK_READJUST_POWER_STATE, |
1249 | NULL) == -EOPNOTSUPP) { |
1250 | adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps; |
1251 | amdgpu_dpm_compute_clocks(adev); |
1252 | } |
1253 | |
1254 | return 0; |
1255 | } |
1256 | |
1257 | int amdgpu_dpm_get_mclk_od(struct amdgpu_device *adev) |
1258 | { |
1259 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1260 | int ret = 0; |
1261 | |
1262 | if (!pp_funcs->get_mclk_od) |
1263 | return -EOPNOTSUPP; |
1264 | |
1265 | mutex_lock(&adev->pm.mutex); |
1266 | ret = pp_funcs->get_mclk_od(adev->powerplay.pp_handle); |
1267 | mutex_unlock(lock: &adev->pm.mutex); |
1268 | |
1269 | return ret; |
1270 | } |
1271 | |
1272 | int amdgpu_dpm_set_mclk_od(struct amdgpu_device *adev, uint32_t value) |
1273 | { |
1274 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1275 | |
1276 | if (is_support_sw_smu(adev)) |
1277 | return -EOPNOTSUPP; |
1278 | |
1279 | mutex_lock(&adev->pm.mutex); |
1280 | if (pp_funcs->set_mclk_od) |
1281 | pp_funcs->set_mclk_od(adev->powerplay.pp_handle, value); |
1282 | mutex_unlock(lock: &adev->pm.mutex); |
1283 | |
1284 | if (amdgpu_dpm_dispatch_task(adev, |
1285 | task_id: AMD_PP_TASK_READJUST_POWER_STATE, |
1286 | NULL) == -EOPNOTSUPP) { |
1287 | adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps; |
1288 | amdgpu_dpm_compute_clocks(adev); |
1289 | } |
1290 | |
1291 | return 0; |
1292 | } |
1293 | |
1294 | int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev, |
1295 | char *buf) |
1296 | { |
1297 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1298 | int ret = 0; |
1299 | |
1300 | if (!pp_funcs->get_power_profile_mode) |
1301 | return -EOPNOTSUPP; |
1302 | |
1303 | mutex_lock(&adev->pm.mutex); |
1304 | ret = pp_funcs->get_power_profile_mode(adev->powerplay.pp_handle, |
1305 | buf); |
1306 | mutex_unlock(lock: &adev->pm.mutex); |
1307 | |
1308 | return ret; |
1309 | } |
1310 | |
1311 | int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev, |
1312 | long *input, uint32_t size) |
1313 | { |
1314 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1315 | int ret = 0; |
1316 | |
1317 | if (!pp_funcs->set_power_profile_mode) |
1318 | return 0; |
1319 | |
1320 | mutex_lock(&adev->pm.mutex); |
1321 | ret = pp_funcs->set_power_profile_mode(adev->powerplay.pp_handle, |
1322 | input, |
1323 | size); |
1324 | mutex_unlock(lock: &adev->pm.mutex); |
1325 | |
1326 | return ret; |
1327 | } |
1328 | |
1329 | int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table) |
1330 | { |
1331 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1332 | int ret = 0; |
1333 | |
1334 | if (!pp_funcs->get_gpu_metrics) |
1335 | return 0; |
1336 | |
1337 | mutex_lock(&adev->pm.mutex); |
1338 | ret = pp_funcs->get_gpu_metrics(adev->powerplay.pp_handle, |
1339 | table); |
1340 | mutex_unlock(lock: &adev->pm.mutex); |
1341 | |
1342 | return ret; |
1343 | } |
1344 | |
1345 | ssize_t amdgpu_dpm_get_pm_metrics(struct amdgpu_device *adev, void *pm_metrics, |
1346 | size_t size) |
1347 | { |
1348 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1349 | int ret = 0; |
1350 | |
1351 | if (!pp_funcs->get_pm_metrics) |
1352 | return -EOPNOTSUPP; |
1353 | |
1354 | mutex_lock(&adev->pm.mutex); |
1355 | ret = pp_funcs->get_pm_metrics(adev->powerplay.pp_handle, pm_metrics, |
1356 | size); |
1357 | mutex_unlock(lock: &adev->pm.mutex); |
1358 | |
1359 | return ret; |
1360 | } |
1361 | |
1362 | int amdgpu_dpm_get_fan_control_mode(struct amdgpu_device *adev, |
1363 | uint32_t *fan_mode) |
1364 | { |
1365 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1366 | int ret = 0; |
1367 | |
1368 | if (!pp_funcs->get_fan_control_mode) |
1369 | return -EOPNOTSUPP; |
1370 | |
1371 | mutex_lock(&adev->pm.mutex); |
1372 | ret = pp_funcs->get_fan_control_mode(adev->powerplay.pp_handle, |
1373 | fan_mode); |
1374 | mutex_unlock(lock: &adev->pm.mutex); |
1375 | |
1376 | return ret; |
1377 | } |
1378 | |
1379 | int amdgpu_dpm_set_fan_speed_pwm(struct amdgpu_device *adev, |
1380 | uint32_t speed) |
1381 | { |
1382 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1383 | int ret = 0; |
1384 | |
1385 | if (!pp_funcs->set_fan_speed_pwm) |
1386 | return -EOPNOTSUPP; |
1387 | |
1388 | mutex_lock(&adev->pm.mutex); |
1389 | ret = pp_funcs->set_fan_speed_pwm(adev->powerplay.pp_handle, |
1390 | speed); |
1391 | mutex_unlock(lock: &adev->pm.mutex); |
1392 | |
1393 | return ret; |
1394 | } |
1395 | |
1396 | int amdgpu_dpm_get_fan_speed_pwm(struct amdgpu_device *adev, |
1397 | uint32_t *speed) |
1398 | { |
1399 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1400 | int ret = 0; |
1401 | |
1402 | if (!pp_funcs->get_fan_speed_pwm) |
1403 | return -EOPNOTSUPP; |
1404 | |
1405 | mutex_lock(&adev->pm.mutex); |
1406 | ret = pp_funcs->get_fan_speed_pwm(adev->powerplay.pp_handle, |
1407 | speed); |
1408 | mutex_unlock(lock: &adev->pm.mutex); |
1409 | |
1410 | return ret; |
1411 | } |
1412 | |
1413 | int amdgpu_dpm_get_fan_speed_rpm(struct amdgpu_device *adev, |
1414 | uint32_t *speed) |
1415 | { |
1416 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1417 | int ret = 0; |
1418 | |
1419 | if (!pp_funcs->get_fan_speed_rpm) |
1420 | return -EOPNOTSUPP; |
1421 | |
1422 | mutex_lock(&adev->pm.mutex); |
1423 | ret = pp_funcs->get_fan_speed_rpm(adev->powerplay.pp_handle, |
1424 | speed); |
1425 | mutex_unlock(lock: &adev->pm.mutex); |
1426 | |
1427 | return ret; |
1428 | } |
1429 | |
1430 | int amdgpu_dpm_set_fan_speed_rpm(struct amdgpu_device *adev, |
1431 | uint32_t speed) |
1432 | { |
1433 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1434 | int ret = 0; |
1435 | |
1436 | if (!pp_funcs->set_fan_speed_rpm) |
1437 | return -EOPNOTSUPP; |
1438 | |
1439 | mutex_lock(&adev->pm.mutex); |
1440 | ret = pp_funcs->set_fan_speed_rpm(adev->powerplay.pp_handle, |
1441 | speed); |
1442 | mutex_unlock(lock: &adev->pm.mutex); |
1443 | |
1444 | return ret; |
1445 | } |
1446 | |
1447 | int amdgpu_dpm_set_fan_control_mode(struct amdgpu_device *adev, |
1448 | uint32_t mode) |
1449 | { |
1450 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1451 | int ret = 0; |
1452 | |
1453 | if (!pp_funcs->set_fan_control_mode) |
1454 | return -EOPNOTSUPP; |
1455 | |
1456 | mutex_lock(&adev->pm.mutex); |
1457 | ret = pp_funcs->set_fan_control_mode(adev->powerplay.pp_handle, |
1458 | mode); |
1459 | mutex_unlock(lock: &adev->pm.mutex); |
1460 | |
1461 | return ret; |
1462 | } |
1463 | |
1464 | int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev, |
1465 | uint32_t *limit, |
1466 | enum pp_power_limit_level pp_limit_level, |
1467 | enum pp_power_type power_type) |
1468 | { |
1469 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1470 | int ret = 0; |
1471 | |
1472 | if (!pp_funcs->get_power_limit) |
1473 | return -ENODATA; |
1474 | |
1475 | mutex_lock(&adev->pm.mutex); |
1476 | ret = pp_funcs->get_power_limit(adev->powerplay.pp_handle, |
1477 | limit, |
1478 | pp_limit_level, |
1479 | power_type); |
1480 | mutex_unlock(lock: &adev->pm.mutex); |
1481 | |
1482 | return ret; |
1483 | } |
1484 | |
1485 | int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev, |
1486 | uint32_t limit) |
1487 | { |
1488 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1489 | int ret = 0; |
1490 | |
1491 | if (!pp_funcs->set_power_limit) |
1492 | return -EINVAL; |
1493 | |
1494 | mutex_lock(&adev->pm.mutex); |
1495 | ret = pp_funcs->set_power_limit(adev->powerplay.pp_handle, |
1496 | limit); |
1497 | mutex_unlock(lock: &adev->pm.mutex); |
1498 | |
1499 | return ret; |
1500 | } |
1501 | |
1502 | int amdgpu_dpm_is_cclk_dpm_supported(struct amdgpu_device *adev) |
1503 | { |
1504 | bool cclk_dpm_supported = false; |
1505 | |
1506 | if (!is_support_sw_smu(adev)) |
1507 | return false; |
1508 | |
1509 | mutex_lock(&adev->pm.mutex); |
1510 | cclk_dpm_supported = is_support_cclk_dpm(adev); |
1511 | mutex_unlock(lock: &adev->pm.mutex); |
1512 | |
1513 | return (int)cclk_dpm_supported; |
1514 | } |
1515 | |
1516 | int amdgpu_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev, |
1517 | struct seq_file *m) |
1518 | { |
1519 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1520 | |
1521 | if (!pp_funcs->debugfs_print_current_performance_level) |
1522 | return -EOPNOTSUPP; |
1523 | |
1524 | mutex_lock(&adev->pm.mutex); |
1525 | pp_funcs->debugfs_print_current_performance_level(adev->powerplay.pp_handle, |
1526 | m); |
1527 | mutex_unlock(lock: &adev->pm.mutex); |
1528 | |
1529 | return 0; |
1530 | } |
1531 | |
1532 | int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev, |
1533 | void **addr, |
1534 | size_t *size) |
1535 | { |
1536 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1537 | int ret = 0; |
1538 | |
1539 | if (!pp_funcs->get_smu_prv_buf_details) |
1540 | return -ENOSYS; |
1541 | |
1542 | mutex_lock(&adev->pm.mutex); |
1543 | ret = pp_funcs->get_smu_prv_buf_details(adev->powerplay.pp_handle, |
1544 | addr, |
1545 | size); |
1546 | mutex_unlock(lock: &adev->pm.mutex); |
1547 | |
1548 | return ret; |
1549 | } |
1550 | |
1551 | int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev) |
1552 | { |
1553 | if (is_support_sw_smu(adev)) { |
1554 | struct smu_context *smu = adev->powerplay.pp_handle; |
1555 | |
1556 | return (smu->od_enabled || smu->is_apu); |
1557 | } else { |
1558 | struct pp_hwmgr *hwmgr; |
1559 | |
1560 | /* |
1561 | * dpm on some legacy asics don't carry od_enabled member |
1562 | * as its pp_handle is casted directly from adev. |
1563 | */ |
1564 | if (amdgpu_dpm_is_legacy_dpm(adev)) |
1565 | return false; |
1566 | |
1567 | hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle; |
1568 | |
1569 | return hwmgr->od_enabled; |
1570 | } |
1571 | } |
1572 | |
1573 | int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, |
1574 | const char *buf, |
1575 | size_t size) |
1576 | { |
1577 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1578 | int ret = 0; |
1579 | |
1580 | if (!pp_funcs->set_pp_table) |
1581 | return -EOPNOTSUPP; |
1582 | |
1583 | mutex_lock(&adev->pm.mutex); |
1584 | ret = pp_funcs->set_pp_table(adev->powerplay.pp_handle, |
1585 | buf, |
1586 | size); |
1587 | mutex_unlock(lock: &adev->pm.mutex); |
1588 | |
1589 | return ret; |
1590 | } |
1591 | |
1592 | int amdgpu_dpm_get_num_cpu_cores(struct amdgpu_device *adev) |
1593 | { |
1594 | struct smu_context *smu = adev->powerplay.pp_handle; |
1595 | |
1596 | if (!is_support_sw_smu(adev)) |
1597 | return INT_MAX; |
1598 | |
1599 | return smu->cpu_core_num; |
1600 | } |
1601 | |
1602 | void amdgpu_dpm_stb_debug_fs_init(struct amdgpu_device *adev) |
1603 | { |
1604 | if (!is_support_sw_smu(adev)) |
1605 | return; |
1606 | |
1607 | amdgpu_smu_stb_debug_fs_init(adev); |
1608 | } |
1609 | |
1610 | int amdgpu_dpm_display_configuration_change(struct amdgpu_device *adev, |
1611 | const struct amd_pp_display_configuration *input) |
1612 | { |
1613 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1614 | int ret = 0; |
1615 | |
1616 | if (!pp_funcs->display_configuration_change) |
1617 | return 0; |
1618 | |
1619 | mutex_lock(&adev->pm.mutex); |
1620 | ret = pp_funcs->display_configuration_change(adev->powerplay.pp_handle, |
1621 | input); |
1622 | mutex_unlock(lock: &adev->pm.mutex); |
1623 | |
1624 | return ret; |
1625 | } |
1626 | |
1627 | int amdgpu_dpm_get_clock_by_type(struct amdgpu_device *adev, |
1628 | enum amd_pp_clock_type type, |
1629 | struct amd_pp_clocks *clocks) |
1630 | { |
1631 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1632 | int ret = 0; |
1633 | |
1634 | if (!pp_funcs->get_clock_by_type) |
1635 | return 0; |
1636 | |
1637 | mutex_lock(&adev->pm.mutex); |
1638 | ret = pp_funcs->get_clock_by_type(adev->powerplay.pp_handle, |
1639 | type, |
1640 | clocks); |
1641 | mutex_unlock(lock: &adev->pm.mutex); |
1642 | |
1643 | return ret; |
1644 | } |
1645 | |
1646 | int amdgpu_dpm_get_display_mode_validation_clks(struct amdgpu_device *adev, |
1647 | struct amd_pp_simple_clock_info *clocks) |
1648 | { |
1649 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1650 | int ret = 0; |
1651 | |
1652 | if (!pp_funcs->get_display_mode_validation_clocks) |
1653 | return 0; |
1654 | |
1655 | mutex_lock(&adev->pm.mutex); |
1656 | ret = pp_funcs->get_display_mode_validation_clocks(adev->powerplay.pp_handle, |
1657 | clocks); |
1658 | mutex_unlock(lock: &adev->pm.mutex); |
1659 | |
1660 | return ret; |
1661 | } |
1662 | |
1663 | int amdgpu_dpm_get_clock_by_type_with_latency(struct amdgpu_device *adev, |
1664 | enum amd_pp_clock_type type, |
1665 | struct pp_clock_levels_with_latency *clocks) |
1666 | { |
1667 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1668 | int ret = 0; |
1669 | |
1670 | if (!pp_funcs->get_clock_by_type_with_latency) |
1671 | return 0; |
1672 | |
1673 | mutex_lock(&adev->pm.mutex); |
1674 | ret = pp_funcs->get_clock_by_type_with_latency(adev->powerplay.pp_handle, |
1675 | type, |
1676 | clocks); |
1677 | mutex_unlock(lock: &adev->pm.mutex); |
1678 | |
1679 | return ret; |
1680 | } |
1681 | |
1682 | int amdgpu_dpm_get_clock_by_type_with_voltage(struct amdgpu_device *adev, |
1683 | enum amd_pp_clock_type type, |
1684 | struct pp_clock_levels_with_voltage *clocks) |
1685 | { |
1686 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1687 | int ret = 0; |
1688 | |
1689 | if (!pp_funcs->get_clock_by_type_with_voltage) |
1690 | return 0; |
1691 | |
1692 | mutex_lock(&adev->pm.mutex); |
1693 | ret = pp_funcs->get_clock_by_type_with_voltage(adev->powerplay.pp_handle, |
1694 | type, |
1695 | clocks); |
1696 | mutex_unlock(lock: &adev->pm.mutex); |
1697 | |
1698 | return ret; |
1699 | } |
1700 | |
1701 | int amdgpu_dpm_set_watermarks_for_clocks_ranges(struct amdgpu_device *adev, |
1702 | void *clock_ranges) |
1703 | { |
1704 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1705 | int ret = 0; |
1706 | |
1707 | if (!pp_funcs->set_watermarks_for_clocks_ranges) |
1708 | return -EOPNOTSUPP; |
1709 | |
1710 | mutex_lock(&adev->pm.mutex); |
1711 | ret = pp_funcs->set_watermarks_for_clocks_ranges(adev->powerplay.pp_handle, |
1712 | clock_ranges); |
1713 | mutex_unlock(lock: &adev->pm.mutex); |
1714 | |
1715 | return ret; |
1716 | } |
1717 | |
1718 | int amdgpu_dpm_display_clock_voltage_request(struct amdgpu_device *adev, |
1719 | struct pp_display_clock_request *clock) |
1720 | { |
1721 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1722 | int ret = 0; |
1723 | |
1724 | if (!pp_funcs->display_clock_voltage_request) |
1725 | return -EOPNOTSUPP; |
1726 | |
1727 | mutex_lock(&adev->pm.mutex); |
1728 | ret = pp_funcs->display_clock_voltage_request(adev->powerplay.pp_handle, |
1729 | clock); |
1730 | mutex_unlock(lock: &adev->pm.mutex); |
1731 | |
1732 | return ret; |
1733 | } |
1734 | |
1735 | int amdgpu_dpm_get_current_clocks(struct amdgpu_device *adev, |
1736 | struct amd_pp_clock_info *clocks) |
1737 | { |
1738 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1739 | int ret = 0; |
1740 | |
1741 | if (!pp_funcs->get_current_clocks) |
1742 | return -EOPNOTSUPP; |
1743 | |
1744 | mutex_lock(&adev->pm.mutex); |
1745 | ret = pp_funcs->get_current_clocks(adev->powerplay.pp_handle, |
1746 | clocks); |
1747 | mutex_unlock(lock: &adev->pm.mutex); |
1748 | |
1749 | return ret; |
1750 | } |
1751 | |
1752 | void amdgpu_dpm_notify_smu_enable_pwe(struct amdgpu_device *adev) |
1753 | { |
1754 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1755 | |
1756 | if (!pp_funcs->notify_smu_enable_pwe) |
1757 | return; |
1758 | |
1759 | mutex_lock(&adev->pm.mutex); |
1760 | pp_funcs->notify_smu_enable_pwe(adev->powerplay.pp_handle); |
1761 | mutex_unlock(lock: &adev->pm.mutex); |
1762 | } |
1763 | |
1764 | int amdgpu_dpm_set_active_display_count(struct amdgpu_device *adev, |
1765 | uint32_t count) |
1766 | { |
1767 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1768 | int ret = 0; |
1769 | |
1770 | if (!pp_funcs->set_active_display_count) |
1771 | return -EOPNOTSUPP; |
1772 | |
1773 | mutex_lock(&adev->pm.mutex); |
1774 | ret = pp_funcs->set_active_display_count(adev->powerplay.pp_handle, |
1775 | count); |
1776 | mutex_unlock(lock: &adev->pm.mutex); |
1777 | |
1778 | return ret; |
1779 | } |
1780 | |
1781 | int amdgpu_dpm_set_min_deep_sleep_dcefclk(struct amdgpu_device *adev, |
1782 | uint32_t clock) |
1783 | { |
1784 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1785 | int ret = 0; |
1786 | |
1787 | if (!pp_funcs->set_min_deep_sleep_dcefclk) |
1788 | return -EOPNOTSUPP; |
1789 | |
1790 | mutex_lock(&adev->pm.mutex); |
1791 | ret = pp_funcs->set_min_deep_sleep_dcefclk(adev->powerplay.pp_handle, |
1792 | clock); |
1793 | mutex_unlock(lock: &adev->pm.mutex); |
1794 | |
1795 | return ret; |
1796 | } |
1797 | |
1798 | void amdgpu_dpm_set_hard_min_dcefclk_by_freq(struct amdgpu_device *adev, |
1799 | uint32_t clock) |
1800 | { |
1801 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1802 | |
1803 | if (!pp_funcs->set_hard_min_dcefclk_by_freq) |
1804 | return; |
1805 | |
1806 | mutex_lock(&adev->pm.mutex); |
1807 | pp_funcs->set_hard_min_dcefclk_by_freq(adev->powerplay.pp_handle, |
1808 | clock); |
1809 | mutex_unlock(lock: &adev->pm.mutex); |
1810 | } |
1811 | |
1812 | void amdgpu_dpm_set_hard_min_fclk_by_freq(struct amdgpu_device *adev, |
1813 | uint32_t clock) |
1814 | { |
1815 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1816 | |
1817 | if (!pp_funcs->set_hard_min_fclk_by_freq) |
1818 | return; |
1819 | |
1820 | mutex_lock(&adev->pm.mutex); |
1821 | pp_funcs->set_hard_min_fclk_by_freq(adev->powerplay.pp_handle, |
1822 | clock); |
1823 | mutex_unlock(lock: &adev->pm.mutex); |
1824 | } |
1825 | |
1826 | int amdgpu_dpm_display_disable_memory_clock_switch(struct amdgpu_device *adev, |
1827 | bool disable_memory_clock_switch) |
1828 | { |
1829 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1830 | int ret = 0; |
1831 | |
1832 | if (!pp_funcs->display_disable_memory_clock_switch) |
1833 | return 0; |
1834 | |
1835 | mutex_lock(&adev->pm.mutex); |
1836 | ret = pp_funcs->display_disable_memory_clock_switch(adev->powerplay.pp_handle, |
1837 | disable_memory_clock_switch); |
1838 | mutex_unlock(lock: &adev->pm.mutex); |
1839 | |
1840 | return ret; |
1841 | } |
1842 | |
1843 | int amdgpu_dpm_get_max_sustainable_clocks_by_dc(struct amdgpu_device *adev, |
1844 | struct pp_smu_nv_clock_table *max_clocks) |
1845 | { |
1846 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1847 | int ret = 0; |
1848 | |
1849 | if (!pp_funcs->get_max_sustainable_clocks_by_dc) |
1850 | return -EOPNOTSUPP; |
1851 | |
1852 | mutex_lock(&adev->pm.mutex); |
1853 | ret = pp_funcs->get_max_sustainable_clocks_by_dc(adev->powerplay.pp_handle, |
1854 | max_clocks); |
1855 | mutex_unlock(lock: &adev->pm.mutex); |
1856 | |
1857 | return ret; |
1858 | } |
1859 | |
1860 | enum pp_smu_status amdgpu_dpm_get_uclk_dpm_states(struct amdgpu_device *adev, |
1861 | unsigned int *clock_values_in_khz, |
1862 | unsigned int *num_states) |
1863 | { |
1864 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1865 | int ret = 0; |
1866 | |
1867 | if (!pp_funcs->get_uclk_dpm_states) |
1868 | return -EOPNOTSUPP; |
1869 | |
1870 | mutex_lock(&adev->pm.mutex); |
1871 | ret = pp_funcs->get_uclk_dpm_states(adev->powerplay.pp_handle, |
1872 | clock_values_in_khz, |
1873 | num_states); |
1874 | mutex_unlock(lock: &adev->pm.mutex); |
1875 | |
1876 | return ret; |
1877 | } |
1878 | |
1879 | int amdgpu_dpm_get_dpm_clock_table(struct amdgpu_device *adev, |
1880 | struct dpm_clocks *clock_table) |
1881 | { |
1882 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
1883 | int ret = 0; |
1884 | |
1885 | if (!pp_funcs->get_dpm_clock_table) |
1886 | return -EOPNOTSUPP; |
1887 | |
1888 | mutex_lock(&adev->pm.mutex); |
1889 | ret = pp_funcs->get_dpm_clock_table(adev->powerplay.pp_handle, |
1890 | clock_table); |
1891 | mutex_unlock(lock: &adev->pm.mutex); |
1892 | |
1893 | return ret; |
1894 | } |
1895 | |