Commit | Line | Data |
---|---|---|
1f7371b2 AD |
1 | /* |
2 | * Copyright 2015 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 | */ | |
7bd55429 | 23 | #include "pp_debug.h" |
1f7371b2 AD |
24 | #include <linux/types.h> |
25 | #include <linux/kernel.h> | |
26 | #include <linux/gfp.h> | |
ac885b3a | 27 | #include <linux/slab.h> |
64f6db77 | 28 | #include <linux/firmware.h> |
1f7371b2 AD |
29 | #include "amd_shared.h" |
30 | #include "amd_powerplay.h" | |
577bbe01 | 31 | #include "power_state.h" |
a2c120ce | 32 | #include "amdgpu.h" |
65ad7cac | 33 | #include "hwmgr.h" |
6ddbd37f EQ |
34 | #include "amdgpu_dpm_internal.h" |
35 | #include "amdgpu_display.h" | |
6d07fe7b | 36 | |
b905090d | 37 | static const struct amd_pm_funcs pp_dpm_funcs; |
3bace359 | 38 | |
a2c120ce | 39 | static int amd_powerplay_create(struct amdgpu_device *adev) |
139a285f | 40 | { |
b905090d | 41 | struct pp_hwmgr *hwmgr; |
139a285f | 42 | |
a2c120ce | 43 | if (adev == NULL) |
139a285f RZ |
44 | return -EINVAL; |
45 | ||
b905090d RZ |
46 | hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL); |
47 | if (hwmgr == NULL) | |
139a285f RZ |
48 | return -ENOMEM; |
49 | ||
b905090d | 50 | hwmgr->adev = adev; |
8bb575a2 | 51 | hwmgr->not_vf = !amdgpu_sriov_vf(adev); |
b905090d | 52 | hwmgr->device = amdgpu_cgs_create_device(adev); |
6b6706cd | 53 | mutex_init(&hwmgr->msg_lock); |
b905090d RZ |
54 | hwmgr->chip_family = adev->family; |
55 | hwmgr->chip_id = adev->asic_type; | |
3b94fb10 | 56 | hwmgr->feature_mask = adev->pm.pp_feature; |
555fd70c | 57 | hwmgr->display_config = &adev->pm.pm_display_cfg; |
b905090d RZ |
58 | adev->powerplay.pp_handle = hwmgr; |
59 | adev->powerplay.pp_funcs = &pp_dpm_funcs; | |
139a285f RZ |
60 | return 0; |
61 | } | |
62 | ||
a2c120ce | 63 | |
ba8ab90e | 64 | static void amd_powerplay_destroy(struct amdgpu_device *adev) |
139a285f | 65 | { |
b905090d | 66 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; |
139a285f | 67 | |
6b6706cd EQ |
68 | mutex_destroy(&hwmgr->msg_lock); |
69 | ||
b905090d RZ |
70 | kfree(hwmgr->hardcode_pp_table); |
71 | hwmgr->hardcode_pp_table = NULL; | |
7b38a49d | 72 | |
b905090d RZ |
73 | kfree(hwmgr); |
74 | hwmgr = NULL; | |
139a285f RZ |
75 | } |
76 | ||
1c863802 RZ |
77 | static int pp_early_init(void *handle) |
78 | { | |
79 | int ret; | |
b905090d | 80 | struct amdgpu_device *adev = handle; |
139a285f | 81 | |
a2c120ce | 82 | ret = amd_powerplay_create(adev); |
139a285f | 83 | |
a2c120ce RZ |
84 | if (ret != 0) |
85 | return ret; | |
86 | ||
b905090d | 87 | ret = hwmgr_early_init(adev->powerplay.pp_handle); |
9441f964 | 88 | if (ret) |
b3b03052 | 89 | return -EINVAL; |
1c863802 | 90 | |
b4eeed59 | 91 | return 0; |
1f7371b2 AD |
92 | } |
93 | ||
1c863802 | 94 | static int pp_sw_init(void *handle) |
1f7371b2 | 95 | { |
b905090d RZ |
96 | struct amdgpu_device *adev = handle; |
97 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
3bace359 JZ |
98 | int ret = 0; |
99 | ||
ba8ab90e | 100 | ret = hwmgr_sw_init(hwmgr); |
7383bcb9 | 101 | |
ba8ab90e | 102 | pr_debug("powerplay sw init %s\n", ret ? "failed" : "successfully"); |
b905090d | 103 | |
1c863802 RZ |
104 | return ret; |
105 | } | |
3bace359 | 106 | |
1c863802 RZ |
107 | static int pp_sw_fini(void *handle) |
108 | { | |
b905090d RZ |
109 | struct amdgpu_device *adev = handle; |
110 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
1c863802 | 111 | |
ba8ab90e | 112 | hwmgr_sw_fini(hwmgr); |
2dac5936 | 113 | |
3023015f RZ |
114 | release_firmware(adev->pm.fw); |
115 | adev->pm.fw = NULL; | |
2dac5936 | 116 | |
b905090d | 117 | return 0; |
1f7371b2 AD |
118 | } |
119 | ||
120 | static int pp_hw_init(void *handle) | |
121 | { | |
ac885b3a | 122 | int ret = 0; |
b905090d RZ |
123 | struct amdgpu_device *adev = handle; |
124 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
ac885b3a | 125 | |
ba8ab90e | 126 | ret = hwmgr_hw_init(hwmgr); |
ac885b3a | 127 | |
ba8ab90e RZ |
128 | if (ret) |
129 | pr_err("powerplay hw init failed\n"); | |
ac885b3a | 130 | |
e5f23736 | 131 | return ret; |
1f7371b2 AD |
132 | } |
133 | ||
134 | static int pp_hw_fini(void *handle) | |
135 | { | |
b905090d RZ |
136 | struct amdgpu_device *adev = handle; |
137 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
ac885b3a | 138 | |
ba8ab90e | 139 | hwmgr_hw_fini(hwmgr); |
df1e6394 | 140 | |
1f7371b2 AD |
141 | return 0; |
142 | } | |
143 | ||
7951e376 RZ |
144 | static void pp_reserve_vram_for_smu(struct amdgpu_device *adev) |
145 | { | |
146 | int r = -EINVAL; | |
147 | void *cpu_ptr = NULL; | |
148 | uint64_t gpu_addr; | |
149 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
150 | ||
151 | if (amdgpu_bo_create_kernel(adev, adev->pm.smu_prv_buffer_size, | |
152 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, | |
153 | &adev->pm.smu_prv_buffer, | |
154 | &gpu_addr, | |
155 | &cpu_ptr)) { | |
156 | DRM_ERROR("amdgpu: failed to create smu prv buffer\n"); | |
157 | return; | |
158 | } | |
159 | ||
160 | if (hwmgr->hwmgr_func->notify_cac_buffer_info) | |
161 | r = hwmgr->hwmgr_func->notify_cac_buffer_info(hwmgr, | |
162 | lower_32_bits((unsigned long)cpu_ptr), | |
163 | upper_32_bits((unsigned long)cpu_ptr), | |
164 | lower_32_bits(gpu_addr), | |
165 | upper_32_bits(gpu_addr), | |
166 | adev->pm.smu_prv_buffer_size); | |
167 | ||
168 | if (r) { | |
169 | amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL); | |
170 | adev->pm.smu_prv_buffer = NULL; | |
171 | DRM_ERROR("amdgpu: failed to notify SMU buffer address\n"); | |
172 | } | |
173 | } | |
174 | ||
6d07fe7b RZ |
175 | static int pp_late_init(void *handle) |
176 | { | |
b905090d RZ |
177 | struct amdgpu_device *adev = handle; |
178 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
b905090d | 179 | |
a746c77e | 180 | if (hwmgr && hwmgr->pm_en) |
b61e54cb | 181 | hwmgr_handle_task(hwmgr, |
39199b80 | 182 | AMD_PP_TASK_COMPLETE_INIT, NULL); |
7951e376 RZ |
183 | if (adev->pm.smu_prv_buffer_size != 0) |
184 | pp_reserve_vram_for_smu(adev); | |
9667849b | 185 | |
6d07fe7b RZ |
186 | return 0; |
187 | } | |
188 | ||
139a285f RZ |
189 | static void pp_late_fini(void *handle) |
190 | { | |
2dac5936 RZ |
191 | struct amdgpu_device *adev = handle; |
192 | ||
7951e376 RZ |
193 | if (adev->pm.smu_prv_buffer) |
194 | amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL); | |
2dac5936 | 195 | amd_powerplay_destroy(adev); |
139a285f RZ |
196 | } |
197 | ||
198 | ||
1f7371b2 AD |
199 | static bool pp_is_idle(void *handle) |
200 | { | |
ed5121a3 | 201 | return false; |
1f7371b2 AD |
202 | } |
203 | ||
204 | static int pp_wait_for_idle(void *handle) | |
205 | { | |
206 | return 0; | |
207 | } | |
208 | ||
209 | static int pp_sw_reset(void *handle) | |
210 | { | |
211 | return 0; | |
212 | } | |
213 | ||
1f7371b2 AD |
214 | static int pp_set_powergating_state(void *handle, |
215 | enum amd_powergating_state state) | |
216 | { | |
85f80cb3 | 217 | return 0; |
1f7371b2 AD |
218 | } |
219 | ||
220 | static int pp_suspend(void *handle) | |
221 | { | |
b905090d RZ |
222 | struct amdgpu_device *adev = handle; |
223 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
577bbe01 | 224 | |
ba8ab90e | 225 | return hwmgr_suspend(hwmgr); |
1f7371b2 AD |
226 | } |
227 | ||
228 | static int pp_resume(void *handle) | |
229 | { | |
b905090d RZ |
230 | struct amdgpu_device *adev = handle; |
231 | struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; | |
1c863802 | 232 | |
ba8ab90e | 233 | return hwmgr_resume(hwmgr); |
1f7371b2 AD |
234 | } |
235 | ||
f004938f AG |
236 | static int pp_set_clockgating_state(void *handle, |
237 | enum amd_clockgating_state state) | |
238 | { | |
239 | return 0; | |
240 | } | |
241 | ||
b905090d | 242 | static const struct amd_ip_funcs pp_ip_funcs = { |
88a907d6 | 243 | .name = "powerplay", |
1f7371b2 | 244 | .early_init = pp_early_init, |
6d07fe7b | 245 | .late_init = pp_late_init, |
1f7371b2 AD |
246 | .sw_init = pp_sw_init, |
247 | .sw_fini = pp_sw_fini, | |
248 | .hw_init = pp_hw_init, | |
249 | .hw_fini = pp_hw_fini, | |
139a285f | 250 | .late_fini = pp_late_fini, |
1f7371b2 AD |
251 | .suspend = pp_suspend, |
252 | .resume = pp_resume, | |
253 | .is_idle = pp_is_idle, | |
254 | .wait_for_idle = pp_wait_for_idle, | |
255 | .soft_reset = pp_sw_reset, | |
f004938f | 256 | .set_clockgating_state = pp_set_clockgating_state, |
1f7371b2 AD |
257 | .set_powergating_state = pp_set_powergating_state, |
258 | }; | |
259 | ||
b905090d RZ |
260 | const struct amdgpu_ip_block_version pp_smu_ip_block = |
261 | { | |
262 | .type = AMD_IP_BLOCK_TYPE_SMC, | |
263 | .major = 1, | |
264 | .minor = 0, | |
265 | .rev = 0, | |
266 | .funcs = &pp_ip_funcs, | |
267 | }; | |
268 | ||
9c8bc8d3 RZ |
269 | /* This interface only be supported On Vi, |
270 | * because only smu7/8 can help to load gfx/sdma fw, | |
271 | * smu need to be enabled before load other ip's fw. | |
272 | * so call start smu to load smu7 fw and other ip's fw | |
273 | */ | |
1f7371b2 AD |
274 | static int pp_dpm_load_fw(void *handle) |
275 | { | |
9c8bc8d3 RZ |
276 | struct pp_hwmgr *hwmgr = handle; |
277 | ||
278 | if (!hwmgr || !hwmgr->smumgr_funcs || !hwmgr->smumgr_funcs->start_smu) | |
279 | return -EINVAL; | |
280 | ||
281 | if (hwmgr->smumgr_funcs->start_smu(hwmgr)) { | |
282 | pr_err("fw load failed\n"); | |
283 | return -EINVAL; | |
284 | } | |
285 | ||
1f7371b2 AD |
286 | return 0; |
287 | } | |
288 | ||
289 | static int pp_dpm_fw_loading_complete(void *handle) | |
290 | { | |
291 | return 0; | |
292 | } | |
293 | ||
3811f8f0 RZ |
294 | static int pp_set_clockgating_by_smu(void *handle, uint32_t msg_id) |
295 | { | |
b905090d | 296 | struct pp_hwmgr *hwmgr = handle; |
3811f8f0 | 297 | |
ba8ab90e RZ |
298 | if (!hwmgr || !hwmgr->pm_en) |
299 | return -EINVAL; | |
3811f8f0 | 300 | |
3811f8f0 | 301 | if (hwmgr->hwmgr_func->update_clock_gatings == NULL) { |
527aa2a0 | 302 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
3811f8f0 RZ |
303 | return 0; |
304 | } | |
305 | ||
306 | return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); | |
307 | } | |
308 | ||
9947f704 RZ |
309 | static void pp_dpm_en_umd_pstate(struct pp_hwmgr *hwmgr, |
310 | enum amd_dpm_forced_level *level) | |
311 | { | |
312 | uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD | | |
313 | AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK | | |
314 | AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK | | |
315 | AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; | |
316 | ||
317 | if (!(hwmgr->dpm_level & profile_mode_mask)) { | |
318 | /* enter umd pstate, save current level, disable gfx cg*/ | |
319 | if (*level & profile_mode_mask) { | |
320 | hwmgr->saved_dpm_level = hwmgr->dpm_level; | |
321 | hwmgr->en_umd_pstate = true; | |
9947f704 RZ |
322 | } |
323 | } else { | |
324 | /* exit umd pstate, restore level, enable gfx cg*/ | |
325 | if (!(*level & profile_mode_mask)) { | |
326 | if (*level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT) | |
327 | *level = hwmgr->saved_dpm_level; | |
328 | hwmgr->en_umd_pstate = false; | |
9947f704 RZ |
329 | } |
330 | } | |
331 | } | |
332 | ||
1f7371b2 AD |
333 | static int pp_dpm_force_performance_level(void *handle, |
334 | enum amd_dpm_forced_level level) | |
335 | { | |
b905090d | 336 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 337 | |
ba8ab90e RZ |
338 | if (!hwmgr || !hwmgr->pm_en) |
339 | return -EINVAL; | |
577bbe01 | 340 | |
9947f704 RZ |
341 | if (level == hwmgr->dpm_level) |
342 | return 0; | |
343 | ||
9947f704 RZ |
344 | pp_dpm_en_umd_pstate(hwmgr, &level); |
345 | hwmgr->request_dpm_level = level; | |
b905090d | 346 | hwmgr_handle_task(hwmgr, AMD_PP_TASK_READJUST_POWER_STATE, NULL); |
8621bbbb | 347 | |
1f7371b2 AD |
348 | return 0; |
349 | } | |
577bbe01 | 350 | |
1f7371b2 AD |
351 | static enum amd_dpm_forced_level pp_dpm_get_performance_level( |
352 | void *handle) | |
353 | { | |
b905090d | 354 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 355 | |
ba8ab90e RZ |
356 | if (!hwmgr || !hwmgr->pm_en) |
357 | return -EINVAL; | |
577bbe01 | 358 | |
a746c77e | 359 | return hwmgr->dpm_level; |
1f7371b2 | 360 | } |
577bbe01 | 361 | |
f93f0c3a | 362 | static uint32_t pp_dpm_get_sclk(void *handle, bool low) |
1f7371b2 | 363 | { |
b905090d | 364 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 365 | |
ba8ab90e RZ |
366 | if (!hwmgr || !hwmgr->pm_en) |
367 | return 0; | |
577bbe01 | 368 | |
7383bcb9 | 369 | if (hwmgr->hwmgr_func->get_sclk == NULL) { |
527aa2a0 | 370 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
7383bcb9 RZ |
371 | return 0; |
372 | } | |
a746c77e | 373 | return hwmgr->hwmgr_func->get_sclk(hwmgr, low); |
1f7371b2 | 374 | } |
577bbe01 | 375 | |
f93f0c3a | 376 | static uint32_t pp_dpm_get_mclk(void *handle, bool low) |
1f7371b2 | 377 | { |
b905090d | 378 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 379 | |
ba8ab90e RZ |
380 | if (!hwmgr || !hwmgr->pm_en) |
381 | return 0; | |
577bbe01 | 382 | |
7383bcb9 | 383 | if (hwmgr->hwmgr_func->get_mclk == NULL) { |
527aa2a0 | 384 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
7383bcb9 RZ |
385 | return 0; |
386 | } | |
a746c77e | 387 | return hwmgr->hwmgr_func->get_mclk(hwmgr, low); |
1f7371b2 | 388 | } |
577bbe01 | 389 | |
f93f0c3a | 390 | static void pp_dpm_powergate_vce(void *handle, bool gate) |
1f7371b2 | 391 | { |
b905090d | 392 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 393 | |
ba8ab90e | 394 | if (!hwmgr || !hwmgr->pm_en) |
f93f0c3a | 395 | return; |
577bbe01 | 396 | |
7383bcb9 | 397 | if (hwmgr->hwmgr_func->powergate_vce == NULL) { |
527aa2a0 | 398 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
f93f0c3a | 399 | return; |
7383bcb9 | 400 | } |
f93f0c3a | 401 | hwmgr->hwmgr_func->powergate_vce(hwmgr, gate); |
1f7371b2 | 402 | } |
577bbe01 | 403 | |
f93f0c3a | 404 | static void pp_dpm_powergate_uvd(void *handle, bool gate) |
1f7371b2 | 405 | { |
b905090d | 406 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 407 | |
ba8ab90e | 408 | if (!hwmgr || !hwmgr->pm_en) |
f93f0c3a | 409 | return; |
577bbe01 | 410 | |
7383bcb9 | 411 | if (hwmgr->hwmgr_func->powergate_uvd == NULL) { |
527aa2a0 | 412 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
f93f0c3a | 413 | return; |
7383bcb9 | 414 | } |
f93f0c3a | 415 | hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate); |
577bbe01 RZ |
416 | } |
417 | ||
df1e6394 | 418 | static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id, |
39199b80 | 419 | enum amd_pm_state_type *user_state) |
1f7371b2 | 420 | { |
b905090d | 421 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 422 | |
ba8ab90e RZ |
423 | if (!hwmgr || !hwmgr->pm_en) |
424 | return -EINVAL; | |
577bbe01 | 425 | |
a746c77e | 426 | return hwmgr_handle_task(hwmgr, task_id, user_state); |
1f7371b2 | 427 | } |
577bbe01 | 428 | |
f8a4c11b | 429 | static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle) |
1f7371b2 | 430 | { |
b905090d | 431 | struct pp_hwmgr *hwmgr = handle; |
577bbe01 | 432 | struct pp_power_state *state; |
2a507105 | 433 | enum amd_pm_state_type pm_type; |
577bbe01 | 434 | |
ba8ab90e | 435 | if (!hwmgr || !hwmgr->pm_en || !hwmgr->current_ps) |
577bbe01 RZ |
436 | return -EINVAL; |
437 | ||
438 | state = hwmgr->current_ps; | |
439 | ||
440 | switch (state->classification.ui_label) { | |
441 | case PP_StateUILabel_Battery: | |
2a507105 | 442 | pm_type = POWER_STATE_TYPE_BATTERY; |
0f987cd0 | 443 | break; |
577bbe01 | 444 | case PP_StateUILabel_Balanced: |
2a507105 | 445 | pm_type = POWER_STATE_TYPE_BALANCED; |
0f987cd0 | 446 | break; |
577bbe01 | 447 | case PP_StateUILabel_Performance: |
2a507105 | 448 | pm_type = POWER_STATE_TYPE_PERFORMANCE; |
0f987cd0 | 449 | break; |
577bbe01 | 450 | default: |
f3898ea1 | 451 | if (state->classification.flags & PP_StateClassificationFlag_Boot) |
2a507105 | 452 | pm_type = POWER_STATE_TYPE_INTERNAL_BOOT; |
f3898ea1 | 453 | else |
2a507105 | 454 | pm_type = POWER_STATE_TYPE_DEFAULT; |
0f987cd0 | 455 | break; |
577bbe01 | 456 | } |
2a507105 RZ |
457 | |
458 | return pm_type; | |
1f7371b2 | 459 | } |
577bbe01 | 460 | |
685fae24 | 461 | static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode) |
cac9a199 | 462 | { |
b905090d | 463 | struct pp_hwmgr *hwmgr = handle; |
cac9a199 | 464 | |
ba8ab90e | 465 | if (!hwmgr || !hwmgr->pm_en) |
685fae24 EQ |
466 | return -EOPNOTSUPP; |
467 | ||
468 | if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) | |
469 | return -EOPNOTSUPP; | |
470 | ||
471 | if (mode == U32_MAX) | |
472 | return -EINVAL; | |
cac9a199 | 473 | |
f93f0c3a | 474 | hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode); |
685fae24 EQ |
475 | |
476 | return 0; | |
cac9a199 RZ |
477 | } |
478 | ||
685fae24 | 479 | static int pp_dpm_get_fan_control_mode(void *handle, uint32_t *fan_mode) |
cac9a199 | 480 | { |
b905090d | 481 | struct pp_hwmgr *hwmgr = handle; |
cac9a199 | 482 | |
ba8ab90e | 483 | if (!hwmgr || !hwmgr->pm_en) |
685fae24 EQ |
484 | return -EOPNOTSUPP; |
485 | ||
486 | if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) | |
487 | return -EOPNOTSUPP; | |
488 | ||
489 | if (!fan_mode) | |
490 | return -EINVAL; | |
cac9a199 | 491 | |
685fae24 | 492 | *fan_mode = hwmgr->hwmgr_func->get_fan_control_mode(hwmgr); |
685fae24 | 493 | return 0; |
cac9a199 RZ |
494 | } |
495 | ||
0d8318e1 | 496 | static int pp_dpm_set_fan_speed_pwm(void *handle, uint32_t speed) |
cac9a199 | 497 | { |
b905090d | 498 | struct pp_hwmgr *hwmgr = handle; |
cac9a199 | 499 | |
ba8ab90e | 500 | if (!hwmgr || !hwmgr->pm_en) |
685fae24 EQ |
501 | return -EOPNOTSUPP; |
502 | ||
503 | if (hwmgr->hwmgr_func->set_fan_speed_pwm == NULL) | |
504 | return -EOPNOTSUPP; | |
505 | ||
506 | if (speed == U32_MAX) | |
ba8ab90e | 507 | return -EINVAL; |
cac9a199 | 508 | |
a746c77e | 509 | return hwmgr->hwmgr_func->set_fan_speed_pwm(hwmgr, speed); |
cac9a199 RZ |
510 | } |
511 | ||
0d8318e1 | 512 | static int pp_dpm_get_fan_speed_pwm(void *handle, uint32_t *speed) |
cac9a199 | 513 | { |
b905090d | 514 | struct pp_hwmgr *hwmgr = handle; |
cac9a199 | 515 | |
ba8ab90e | 516 | if (!hwmgr || !hwmgr->pm_en) |
685fae24 | 517 | return -EOPNOTSUPP; |
cac9a199 | 518 | |
685fae24 EQ |
519 | if (hwmgr->hwmgr_func->get_fan_speed_pwm == NULL) |
520 | return -EOPNOTSUPP; | |
521 | ||
522 | if (!speed) | |
523 | return -EINVAL; | |
cac9a199 | 524 | |
a746c77e | 525 | return hwmgr->hwmgr_func->get_fan_speed_pwm(hwmgr, speed); |
cac9a199 RZ |
526 | } |
527 | ||
72a16a9d GI |
528 | static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm) |
529 | { | |
b905090d | 530 | struct pp_hwmgr *hwmgr = handle; |
72a16a9d | 531 | |
ba8ab90e | 532 | if (!hwmgr || !hwmgr->pm_en) |
685fae24 | 533 | return -EOPNOTSUPP; |
72a16a9d | 534 | |
72a16a9d | 535 | if (hwmgr->hwmgr_func->get_fan_speed_rpm == NULL) |
685fae24 EQ |
536 | return -EOPNOTSUPP; |
537 | ||
538 | if (!rpm) | |
72a16a9d GI |
539 | return -EINVAL; |
540 | ||
a746c77e | 541 | return hwmgr->hwmgr_func->get_fan_speed_rpm(hwmgr, rpm); |
72a16a9d GI |
542 | } |
543 | ||
c2870527 RZ |
544 | static int pp_dpm_set_fan_speed_rpm(void *handle, uint32_t rpm) |
545 | { | |
546 | struct pp_hwmgr *hwmgr = handle; | |
c2870527 RZ |
547 | |
548 | if (!hwmgr || !hwmgr->pm_en) | |
685fae24 EQ |
549 | return -EOPNOTSUPP; |
550 | ||
551 | if (hwmgr->hwmgr_func->set_fan_speed_rpm == NULL) | |
552 | return -EOPNOTSUPP; | |
553 | ||
554 | if (rpm == U32_MAX) | |
c2870527 RZ |
555 | return -EINVAL; |
556 | ||
a746c77e | 557 | return hwmgr->hwmgr_func->set_fan_speed_rpm(hwmgr, rpm); |
c2870527 RZ |
558 | } |
559 | ||
f3898ea1 EH |
560 | static int pp_dpm_get_pp_num_states(void *handle, |
561 | struct pp_states_info *data) | |
562 | { | |
b905090d | 563 | struct pp_hwmgr *hwmgr = handle; |
f3898ea1 EH |
564 | int i; |
565 | ||
4dbda35f EQ |
566 | memset(data, 0, sizeof(*data)); |
567 | ||
ba8ab90e | 568 | if (!hwmgr || !hwmgr->pm_en ||!hwmgr->ps) |
f3898ea1 EH |
569 | return -EINVAL; |
570 | ||
571 | data->nums = hwmgr->num_ps; | |
572 | ||
573 | for (i = 0; i < hwmgr->num_ps; i++) { | |
574 | struct pp_power_state *state = (struct pp_power_state *) | |
575 | ((unsigned long)hwmgr->ps + i * hwmgr->ps_size); | |
576 | switch (state->classification.ui_label) { | |
577 | case PP_StateUILabel_Battery: | |
578 | data->states[i] = POWER_STATE_TYPE_BATTERY; | |
579 | break; | |
580 | case PP_StateUILabel_Balanced: | |
581 | data->states[i] = POWER_STATE_TYPE_BALANCED; | |
582 | break; | |
583 | case PP_StateUILabel_Performance: | |
584 | data->states[i] = POWER_STATE_TYPE_PERFORMANCE; | |
585 | break; | |
586 | default: | |
587 | if (state->classification.flags & PP_StateClassificationFlag_Boot) | |
588 | data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT; | |
589 | else | |
590 | data->states[i] = POWER_STATE_TYPE_DEFAULT; | |
591 | } | |
592 | } | |
f3898ea1 EH |
593 | return 0; |
594 | } | |
595 | ||
596 | static int pp_dpm_get_pp_table(void *handle, char **table) | |
597 | { | |
b905090d | 598 | struct pp_hwmgr *hwmgr = handle; |
f3898ea1 | 599 | |
ba8ab90e | 600 | if (!hwmgr || !hwmgr->pm_en ||!hwmgr->soft_pp_table) |
4dcf9e6f EH |
601 | return -EINVAL; |
602 | ||
603 | *table = (char *)hwmgr->soft_pp_table; | |
a746c77e | 604 | return hwmgr->soft_pp_table_size; |
f3898ea1 EH |
605 | } |
606 | ||
f685d714 RZ |
607 | static int amd_powerplay_reset(void *handle) |
608 | { | |
b905090d | 609 | struct pp_hwmgr *hwmgr = handle; |
f685d714 RZ |
610 | int ret; |
611 | ||
46b27ee9 | 612 | ret = hwmgr_hw_fini(hwmgr); |
f685d714 RZ |
613 | if (ret) |
614 | return ret; | |
615 | ||
b905090d | 616 | ret = hwmgr_hw_init(hwmgr); |
f685d714 RZ |
617 | if (ret) |
618 | return ret; | |
619 | ||
b905090d | 620 | return hwmgr_handle_task(hwmgr, AMD_PP_TASK_COMPLETE_INIT, NULL); |
f685d714 RZ |
621 | } |
622 | ||
f3898ea1 EH |
623 | static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) |
624 | { | |
b905090d | 625 | struct pp_hwmgr *hwmgr = handle; |
b61e54cb | 626 | int ret = -ENOMEM; |
f3898ea1 | 627 | |
ba8ab90e RZ |
628 | if (!hwmgr || !hwmgr->pm_en) |
629 | return -EINVAL; | |
f3898ea1 | 630 | |
4dcf9e6f | 631 | if (!hwmgr->hardcode_pp_table) { |
efdf7a93 EC |
632 | hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table, |
633 | hwmgr->soft_pp_table_size, | |
634 | GFP_KERNEL); | |
b61e54cb | 635 | if (!hwmgr->hardcode_pp_table) |
a746c77e | 636 | return ret; |
7383bcb9 | 637 | } |
f3898ea1 | 638 | |
4dcf9e6f EH |
639 | memcpy(hwmgr->hardcode_pp_table, buf, size); |
640 | ||
641 | hwmgr->soft_pp_table = hwmgr->hardcode_pp_table; | |
642 | ||
dd4bdf3b EH |
643 | ret = amd_powerplay_reset(handle); |
644 | if (ret) | |
a746c77e | 645 | return ret; |
dd4bdf3b | 646 | |
a746c77e | 647 | if (hwmgr->hwmgr_func->avfs_control) |
dd4bdf3b | 648 | ret = hwmgr->hwmgr_func->avfs_control(hwmgr, false); |
a746c77e | 649 | |
b61e54cb | 650 | return ret; |
f3898ea1 EH |
651 | } |
652 | ||
653 | static int pp_dpm_force_clock_level(void *handle, | |
5632708f | 654 | enum pp_clock_type type, uint32_t mask) |
f3898ea1 | 655 | { |
b905090d | 656 | struct pp_hwmgr *hwmgr = handle; |
f3898ea1 | 657 | |
ba8ab90e RZ |
658 | if (!hwmgr || !hwmgr->pm_en) |
659 | return -EINVAL; | |
f3898ea1 | 660 | |
7383bcb9 | 661 | if (hwmgr->hwmgr_func->force_clock_level == NULL) { |
527aa2a0 | 662 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
7383bcb9 RZ |
663 | return 0; |
664 | } | |
241dbbb1 EQ |
665 | |
666 | if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { | |
9ed9203c | 667 | pr_debug("force clock level is for dpm manual mode only.\n"); |
241dbbb1 EQ |
668 | return -EINVAL; |
669 | } | |
670 | ||
a746c77e | 671 | return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask); |
f3898ea1 EH |
672 | } |
673 | ||
5d8539d2 DP |
674 | static int pp_dpm_emit_clock_levels(void *handle, |
675 | enum pp_clock_type type, | |
676 | char *buf, | |
677 | int *offset) | |
678 | { | |
679 | struct pp_hwmgr *hwmgr = handle; | |
680 | ||
681 | if (!hwmgr || !hwmgr->pm_en) | |
682 | return -EOPNOTSUPP; | |
683 | ||
684 | if (!hwmgr->hwmgr_func->emit_clock_levels) | |
685 | return -ENOENT; | |
686 | ||
687 | return hwmgr->hwmgr_func->emit_clock_levels(hwmgr, type, buf, offset); | |
688 | } | |
689 | ||
f3898ea1 EH |
690 | static int pp_dpm_print_clock_levels(void *handle, |
691 | enum pp_clock_type type, char *buf) | |
692 | { | |
b905090d | 693 | struct pp_hwmgr *hwmgr = handle; |
f3898ea1 | 694 | |
ba8ab90e RZ |
695 | if (!hwmgr || !hwmgr->pm_en) |
696 | return -EINVAL; | |
f3898ea1 | 697 | |
7383bcb9 | 698 | if (hwmgr->hwmgr_func->print_clock_levels == NULL) { |
527aa2a0 | 699 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
7383bcb9 RZ |
700 | return 0; |
701 | } | |
a746c77e | 702 | return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf); |
f3898ea1 EH |
703 | } |
704 | ||
428bafa8 EH |
705 | static int pp_dpm_get_sclk_od(void *handle) |
706 | { | |
b905090d | 707 | struct pp_hwmgr *hwmgr = handle; |
428bafa8 | 708 | |
ba8ab90e RZ |
709 | if (!hwmgr || !hwmgr->pm_en) |
710 | return -EINVAL; | |
428bafa8 | 711 | |
428bafa8 | 712 | if (hwmgr->hwmgr_func->get_sclk_od == NULL) { |
527aa2a0 | 713 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
428bafa8 EH |
714 | return 0; |
715 | } | |
a746c77e | 716 | return hwmgr->hwmgr_func->get_sclk_od(hwmgr); |
428bafa8 EH |
717 | } |
718 | ||
719 | static int pp_dpm_set_sclk_od(void *handle, uint32_t value) | |
720 | { | |
b905090d | 721 | struct pp_hwmgr *hwmgr = handle; |
428bafa8 | 722 | |
ba8ab90e RZ |
723 | if (!hwmgr || !hwmgr->pm_en) |
724 | return -EINVAL; | |
428bafa8 | 725 | |
428bafa8 | 726 | if (hwmgr->hwmgr_func->set_sclk_od == NULL) { |
527aa2a0 | 727 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
428bafa8 EH |
728 | return 0; |
729 | } | |
730 | ||
a746c77e | 731 | return hwmgr->hwmgr_func->set_sclk_od(hwmgr, value); |
428bafa8 EH |
732 | } |
733 | ||
f2bdc05f EH |
734 | static int pp_dpm_get_mclk_od(void *handle) |
735 | { | |
b905090d | 736 | struct pp_hwmgr *hwmgr = handle; |
f2bdc05f | 737 | |
ba8ab90e RZ |
738 | if (!hwmgr || !hwmgr->pm_en) |
739 | return -EINVAL; | |
f2bdc05f | 740 | |
f2bdc05f | 741 | if (hwmgr->hwmgr_func->get_mclk_od == NULL) { |
527aa2a0 | 742 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
f2bdc05f EH |
743 | return 0; |
744 | } | |
a746c77e | 745 | return hwmgr->hwmgr_func->get_mclk_od(hwmgr); |
f2bdc05f EH |
746 | } |
747 | ||
748 | static int pp_dpm_set_mclk_od(void *handle, uint32_t value) | |
749 | { | |
b905090d | 750 | struct pp_hwmgr *hwmgr = handle; |
f2bdc05f | 751 | |
ba8ab90e RZ |
752 | if (!hwmgr || !hwmgr->pm_en) |
753 | return -EINVAL; | |
f2bdc05f | 754 | |
f2bdc05f | 755 | if (hwmgr->hwmgr_func->set_mclk_od == NULL) { |
527aa2a0 | 756 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
f2bdc05f EH |
757 | return 0; |
758 | } | |
a746c77e | 759 | return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value); |
f2bdc05f EH |
760 | } |
761 | ||
9f8df7d7 TSD |
762 | static int pp_dpm_read_sensor(void *handle, int idx, |
763 | void *value, int *size) | |
a6e36952 | 764 | { |
b905090d | 765 | struct pp_hwmgr *hwmgr = handle; |
a6e36952 | 766 | |
ba8ab90e | 767 | if (!hwmgr || !hwmgr->pm_en || !value) |
5ed8d656 RZ |
768 | return -EINVAL; |
769 | ||
5ed8d656 RZ |
770 | switch (idx) { |
771 | case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK: | |
772 | *((uint32_t *)value) = hwmgr->pstate_sclk; | |
773 | return 0; | |
774 | case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK: | |
775 | *((uint32_t *)value) = hwmgr->pstate_mclk; | |
a6e36952 | 776 | return 0; |
d5f48037 RZ |
777 | case AMDGPU_PP_SENSOR_MIN_FAN_RPM: |
778 | *((uint32_t *)value) = hwmgr->thermal_controller.fanInfo.ulMinRPM; | |
779 | return 0; | |
780 | case AMDGPU_PP_SENSOR_MAX_FAN_RPM: | |
781 | *((uint32_t *)value) = hwmgr->thermal_controller.fanInfo.ulMaxRPM; | |
782 | return 0; | |
5ed8d656 | 783 | default: |
a746c77e | 784 | return hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size); |
a6e36952 | 785 | } |
a6e36952 TSD |
786 | } |
787 | ||
597be302 AD |
788 | static struct amd_vce_state* |
789 | pp_dpm_get_vce_clock_state(void *handle, unsigned idx) | |
790 | { | |
b905090d | 791 | struct pp_hwmgr *hwmgr = handle; |
597be302 | 792 | |
ba8ab90e | 793 | if (!hwmgr || !hwmgr->pm_en) |
1c863802 RZ |
794 | return NULL; |
795 | ||
ba8ab90e | 796 | if (idx < hwmgr->num_vce_state_tables) |
1c863802 | 797 | return &hwmgr->vce_states[idx]; |
597be302 AD |
798 | return NULL; |
799 | } | |
800 | ||
6390258a RZ |
801 | static int pp_get_power_profile_mode(void *handle, char *buf) |
802 | { | |
b905090d | 803 | struct pp_hwmgr *hwmgr = handle; |
6390258a | 804 | |
a7505591 | 805 | if (!hwmgr || !hwmgr->pm_en || !hwmgr->hwmgr_func->get_power_profile_mode) |
a035be8a ML |
806 | return -EOPNOTSUPP; |
807 | if (!buf) | |
6390258a RZ |
808 | return -EINVAL; |
809 | ||
a746c77e | 810 | return hwmgr->hwmgr_func->get_power_profile_mode(hwmgr, buf); |
6390258a RZ |
811 | } |
812 | ||
813 | static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size) | |
814 | { | |
b905090d | 815 | struct pp_hwmgr *hwmgr = handle; |
6390258a | 816 | |
a7505591 | 817 | if (!hwmgr || !hwmgr->pm_en || !hwmgr->hwmgr_func->set_power_profile_mode) |
a746c77e | 818 | return -EOPNOTSUPP; |
6390258a | 819 | |
7a862028 | 820 | if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { |
9ed9203c | 821 | pr_debug("power profile setting is for manual dpm mode only.\n"); |
a035be8a | 822 | return -EINVAL; |
7a862028 EQ |
823 | } |
824 | ||
a746c77e | 825 | return hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, input, size); |
6390258a RZ |
826 | } |
827 | ||
12a6727d XD |
828 | static int pp_set_fine_grain_clk_vol(void *handle, uint32_t type, long *input, uint32_t size) |
829 | { | |
830 | struct pp_hwmgr *hwmgr = handle; | |
831 | ||
832 | if (!hwmgr || !hwmgr->pm_en) | |
833 | return -EINVAL; | |
834 | ||
835 | if (hwmgr->hwmgr_func->set_fine_grain_clk_vol == NULL) | |
836 | return 0; | |
837 | ||
838 | return hwmgr->hwmgr_func->set_fine_grain_clk_vol(hwmgr, type, input, size); | |
839 | } | |
840 | ||
e3933f26 RZ |
841 | static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size) |
842 | { | |
b905090d | 843 | struct pp_hwmgr *hwmgr = handle; |
e3933f26 | 844 | |
ba8ab90e | 845 | if (!hwmgr || !hwmgr->pm_en) |
e3933f26 RZ |
846 | return -EINVAL; |
847 | ||
e3933f26 | 848 | if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) { |
527aa2a0 | 849 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
12a6727d | 850 | return 0; |
e3933f26 RZ |
851 | } |
852 | ||
853 | return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size); | |
854 | } | |
855 | ||
a2c28e34 AD |
856 | static int pp_dpm_set_mp1_state(void *handle, enum pp_mp1_state mp1_state) |
857 | { | |
858 | struct pp_hwmgr *hwmgr = handle; | |
859 | ||
29a45960 | 860 | if (!hwmgr) |
a2c28e34 AD |
861 | return -EINVAL; |
862 | ||
29a45960 EQ |
863 | if (!hwmgr->pm_en) |
864 | return 0; | |
865 | ||
479baeac AD |
866 | if (hwmgr->hwmgr_func->set_mp1_state) |
867 | return hwmgr->hwmgr_func->set_mp1_state(hwmgr, mp1_state); | |
a2c28e34 | 868 | |
479baeac | 869 | return 0; |
a2c28e34 AD |
870 | } |
871 | ||
34bb2734 | 872 | static int pp_dpm_switch_power_profile(void *handle, |
052fe96d | 873 | enum PP_SMC_POWER_PROFILE type, bool en) |
34bb2734 | 874 | { |
b905090d | 875 | struct pp_hwmgr *hwmgr = handle; |
052fe96d RZ |
876 | long workload; |
877 | uint32_t index; | |
34bb2734 | 878 | |
ba8ab90e | 879 | if (!hwmgr || !hwmgr->pm_en) |
34bb2734 EH |
880 | return -EINVAL; |
881 | ||
052fe96d | 882 | if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) { |
527aa2a0 | 883 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
052fe96d RZ |
884 | return -EINVAL; |
885 | } | |
886 | ||
887 | if (!(type < PP_SMC_POWER_PROFILE_CUSTOM)) | |
888 | return -EINVAL; | |
889 | ||
052fe96d RZ |
890 | if (!en) { |
891 | hwmgr->workload_mask &= ~(1 << hwmgr->workload_prority[type]); | |
892 | index = fls(hwmgr->workload_mask); | |
893 | index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0; | |
894 | workload = hwmgr->workload_setting[index]; | |
895 | } else { | |
896 | hwmgr->workload_mask |= (1 << hwmgr->workload_prority[type]); | |
897 | index = fls(hwmgr->workload_mask); | |
898 | index = index <= Workload_Policy_Max ? index - 1 : 0; | |
899 | workload = hwmgr->workload_setting[index]; | |
34bb2734 EH |
900 | } |
901 | ||
558491dd KF |
902 | if (type == PP_SMC_POWER_PROFILE_COMPUTE && |
903 | hwmgr->hwmgr_func->disable_power_features_for_compute_performance) { | |
a746c77e | 904 | if (hwmgr->hwmgr_func->disable_power_features_for_compute_performance(hwmgr, en)) |
558491dd | 905 | return -EINVAL; |
558491dd KF |
906 | } |
907 | ||
052fe96d RZ |
908 | if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) |
909 | hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0); | |
052fe96d | 910 | |
34bb2734 EH |
911 | return 0; |
912 | } | |
913 | ||
6ab8555e RZ |
914 | static int pp_set_power_limit(void *handle, uint32_t limit) |
915 | { | |
b905090d | 916 | struct pp_hwmgr *hwmgr = handle; |
f7becf9a | 917 | uint32_t max_power_limit; |
6ab8555e | 918 | |
ba8ab90e RZ |
919 | if (!hwmgr || !hwmgr->pm_en) |
920 | return -EINVAL; | |
6ab8555e | 921 | |
6ab8555e | 922 | if (hwmgr->hwmgr_func->set_power_limit == NULL) { |
527aa2a0 | 923 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
6ab8555e RZ |
924 | return -EINVAL; |
925 | } | |
926 | ||
927 | if (limit == 0) | |
928 | limit = hwmgr->default_power_limit; | |
929 | ||
f7becf9a JG |
930 | max_power_limit = hwmgr->default_power_limit; |
931 | if (hwmgr->od_enabled) { | |
932 | max_power_limit *= (100 + hwmgr->platform_descriptor.TDPODLimit); | |
933 | max_power_limit /= 100; | |
934 | } | |
935 | ||
936 | if (limit > max_power_limit) | |
6ab8555e RZ |
937 | return -EINVAL; |
938 | ||
6ab8555e RZ |
939 | hwmgr->hwmgr_func->set_power_limit(hwmgr, limit); |
940 | hwmgr->power_limit = limit; | |
ba8ab90e | 941 | return 0; |
6ab8555e RZ |
942 | } |
943 | ||
6e58941c | 944 | static int pp_get_power_limit(void *handle, uint32_t *limit, |
04bec521 DP |
945 | enum pp_power_limit_level pp_limit_level, |
946 | enum pp_power_type power_type) | |
6ab8555e | 947 | { |
b905090d | 948 | struct pp_hwmgr *hwmgr = handle; |
04bec521 | 949 | int ret = 0; |
6ab8555e | 950 | |
ba8ab90e | 951 | if (!hwmgr || !hwmgr->pm_en ||!limit) |
6ab8555e RZ |
952 | return -EINVAL; |
953 | ||
04bec521 DP |
954 | if (power_type != PP_PWR_TYPE_SUSTAINED) |
955 | return -EOPNOTSUPP; | |
956 | ||
04bec521 DP |
957 | switch (pp_limit_level) { |
958 | case PP_PWR_LIMIT_CURRENT: | |
959 | *limit = hwmgr->power_limit; | |
960 | break; | |
961 | case PP_PWR_LIMIT_DEFAULT: | |
962 | *limit = hwmgr->default_power_limit; | |
963 | break; | |
964 | case PP_PWR_LIMIT_MAX: | |
965 | *limit = hwmgr->default_power_limit; | |
6e58941c | 966 | if (hwmgr->od_enabled) { |
04bec521 DP |
967 | *limit *= (100 + hwmgr->platform_descriptor.TDPODLimit); |
968 | *limit /= 100; | |
6e58941c | 969 | } |
04bec521 DP |
970 | break; |
971 | default: | |
972 | ret = -EOPNOTSUPP; | |
973 | break; | |
f7becf9a | 974 | } |
6ab8555e | 975 | |
04bec521 | 976 | return ret; |
6ab8555e RZ |
977 | } |
978 | ||
f685d714 | 979 | static int pp_display_configuration_change(void *handle, |
155f1127 | 980 | const struct amd_pp_display_configuration *display_config) |
7fb72a1f | 981 | { |
b905090d | 982 | struct pp_hwmgr *hwmgr = handle; |
7fb72a1f | 983 | |
ba8ab90e RZ |
984 | if (!hwmgr || !hwmgr->pm_en) |
985 | return -EINVAL; | |
7fb72a1f RZ |
986 | |
987 | phm_store_dal_configuration_data(hwmgr, display_config); | |
988 | return 0; | |
989 | } | |
c4dd206b | 990 | |
f685d714 | 991 | static int pp_get_display_power_level(void *handle, |
47329134 | 992 | struct amd_pp_simple_clock_info *output) |
c4dd206b | 993 | { |
b905090d | 994 | struct pp_hwmgr *hwmgr = handle; |
c4dd206b | 995 | |
ba8ab90e | 996 | if (!hwmgr || !hwmgr->pm_en ||!output) |
1c863802 | 997 | return -EINVAL; |
ba5f884c | 998 | |
a746c77e | 999 | return phm_get_dal_power_level(hwmgr, output); |
c4dd206b | 1000 | } |
e273b041 | 1001 | |
f685d714 | 1002 | static int pp_get_current_clocks(void *handle, |
155f1127 | 1003 | struct amd_pp_clock_info *clocks) |
e273b041 | 1004 | { |
97e8f102 | 1005 | struct amd_pp_simple_clock_info simple_clocks = { 0 }; |
e273b041 | 1006 | struct pp_clock_info hw_clocks; |
b905090d | 1007 | struct pp_hwmgr *hwmgr = handle; |
1c863802 | 1008 | int ret = 0; |
e273b041 | 1009 | |
ba8ab90e RZ |
1010 | if (!hwmgr || !hwmgr->pm_en) |
1011 | return -EINVAL; | |
e273b041 RZ |
1012 | |
1013 | phm_get_dal_power_level(hwmgr, &simple_clocks); | |
1014 | ||
2a507105 RZ |
1015 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, |
1016 | PHM_PlatformCaps_PowerContainment)) | |
1017 | ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, | |
1018 | &hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment); | |
1019 | else | |
1020 | ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, | |
1021 | &hw_clocks, PHM_PerformanceLevelDesignation_Activity); | |
1022 | ||
ae97988f | 1023 | if (ret) { |
9ed9203c | 1024 | pr_debug("Error in phm_get_clock_info \n"); |
2a507105 | 1025 | return -EINVAL; |
e273b041 RZ |
1026 | } |
1027 | ||
1028 | clocks->min_engine_clock = hw_clocks.min_eng_clk; | |
1029 | clocks->max_engine_clock = hw_clocks.max_eng_clk; | |
1030 | clocks->min_memory_clock = hw_clocks.min_mem_clk; | |
1031 | clocks->max_memory_clock = hw_clocks.max_mem_clk; | |
1032 | clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth; | |
1033 | clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth; | |
1034 | ||
1035 | clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; | |
1036 | clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; | |
1037 | ||
97e8f102 RZ |
1038 | if (simple_clocks.level == 0) |
1039 | clocks->max_clocks_state = PP_DAL_POWERLEVEL_7; | |
1040 | else | |
1041 | clocks->max_clocks_state = simple_clocks.level; | |
e273b041 RZ |
1042 | |
1043 | if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) { | |
1044 | clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; | |
1045 | clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; | |
1046 | } | |
e273b041 | 1047 | return 0; |
e273b041 RZ |
1048 | } |
1049 | ||
f685d714 | 1050 | static int pp_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks) |
e273b041 | 1051 | { |
b905090d | 1052 | struct pp_hwmgr *hwmgr = handle; |
e273b041 | 1053 | |
ba8ab90e RZ |
1054 | if (!hwmgr || !hwmgr->pm_en) |
1055 | return -EINVAL; | |
1c863802 | 1056 | |
fa9e6991 | 1057 | if (clocks == NULL) |
e273b041 RZ |
1058 | return -EINVAL; |
1059 | ||
a746c77e | 1060 | return phm_get_clock_by_type(hwmgr, type, clocks); |
e273b041 RZ |
1061 | } |
1062 | ||
f685d714 | 1063 | static int pp_get_clock_by_type_with_latency(void *handle, |
d0187727 EH |
1064 | enum amd_pp_clock_type type, |
1065 | struct pp_clock_levels_with_latency *clocks) | |
1066 | { | |
b905090d | 1067 | struct pp_hwmgr *hwmgr = handle; |
d0187727 | 1068 | |
ba8ab90e | 1069 | if (!hwmgr || !hwmgr->pm_en ||!clocks) |
d0187727 EH |
1070 | return -EINVAL; |
1071 | ||
a746c77e | 1072 | return phm_get_clock_by_type_with_latency(hwmgr, type, clocks); |
d0187727 EH |
1073 | } |
1074 | ||
f685d714 | 1075 | static int pp_get_clock_by_type_with_voltage(void *handle, |
d0187727 EH |
1076 | enum amd_pp_clock_type type, |
1077 | struct pp_clock_levels_with_voltage *clocks) | |
1078 | { | |
b905090d | 1079 | struct pp_hwmgr *hwmgr = handle; |
d0187727 | 1080 | |
ba8ab90e | 1081 | if (!hwmgr || !hwmgr->pm_en ||!clocks) |
d0187727 EH |
1082 | return -EINVAL; |
1083 | ||
a746c77e | 1084 | return phm_get_clock_by_type_with_voltage(hwmgr, type, clocks); |
d0187727 EH |
1085 | } |
1086 | ||
f685d714 | 1087 | static int pp_set_watermarks_for_clocks_ranges(void *handle, |
99c5e27d | 1088 | void *clock_ranges) |
d0187727 | 1089 | { |
b905090d | 1090 | struct pp_hwmgr *hwmgr = handle; |
d0187727 | 1091 | |
99c5e27d | 1092 | if (!hwmgr || !hwmgr->pm_en || !clock_ranges) |
d0187727 EH |
1093 | return -EINVAL; |
1094 | ||
a746c77e EQ |
1095 | return phm_set_watermarks_for_clocks_ranges(hwmgr, |
1096 | clock_ranges); | |
d0187727 EH |
1097 | } |
1098 | ||
f685d714 | 1099 | static int pp_display_clock_voltage_request(void *handle, |
d0187727 EH |
1100 | struct pp_display_clock_request *clock) |
1101 | { | |
b905090d | 1102 | struct pp_hwmgr *hwmgr = handle; |
d0187727 | 1103 | |
ba8ab90e | 1104 | if (!hwmgr || !hwmgr->pm_en ||!clock) |
d0187727 EH |
1105 | return -EINVAL; |
1106 | ||
a746c77e | 1107 | return phm_display_clock_voltage_request(hwmgr, clock); |
d0187727 EH |
1108 | } |
1109 | ||
f685d714 | 1110 | static int pp_get_display_mode_validation_clocks(void *handle, |
155f1127 | 1111 | struct amd_pp_simple_clock_info *clocks) |
e273b041 | 1112 | { |
b905090d | 1113 | struct pp_hwmgr *hwmgr = handle; |
1c863802 | 1114 | int ret = 0; |
e273b041 | 1115 | |
ba8ab90e | 1116 | if (!hwmgr || !hwmgr->pm_en ||!clocks) |
1c863802 | 1117 | return -EINVAL; |
ba5f884c | 1118 | |
97e8f102 RZ |
1119 | clocks->level = PP_DAL_POWERLEVEL_7; |
1120 | ||
e273b041 | 1121 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState)) |
1c863802 | 1122 | ret = phm_get_max_high_clocks(hwmgr, clocks); |
e273b041 | 1123 | |
1c863802 | 1124 | return ret; |
e273b041 RZ |
1125 | } |
1126 | ||
a8da8ff3 | 1127 | static int pp_dpm_powergate_mmhub(void *handle) |
72d76191 | 1128 | { |
b905090d | 1129 | struct pp_hwmgr *hwmgr = handle; |
72d76191 | 1130 | |
ba8ab90e RZ |
1131 | if (!hwmgr || !hwmgr->pm_en) |
1132 | return -EINVAL; | |
72d76191 | 1133 | |
a8da8ff3 | 1134 | if (hwmgr->hwmgr_func->powergate_mmhub == NULL) { |
527aa2a0 | 1135 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
72d76191 EH |
1136 | return 0; |
1137 | } | |
1138 | ||
a8da8ff3 | 1139 | return hwmgr->hwmgr_func->powergate_mmhub(hwmgr); |
72d76191 EH |
1140 | } |
1141 | ||
85f80cb3 RZ |
1142 | static int pp_dpm_powergate_gfx(void *handle, bool gate) |
1143 | { | |
1144 | struct pp_hwmgr *hwmgr = handle; | |
1145 | ||
1146 | if (!hwmgr || !hwmgr->pm_en) | |
1147 | return 0; | |
1148 | ||
1149 | if (hwmgr->hwmgr_func->powergate_gfx == NULL) { | |
527aa2a0 | 1150 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
85f80cb3 RZ |
1151 | return 0; |
1152 | } | |
1153 | ||
1154 | return hwmgr->hwmgr_func->powergate_gfx(hwmgr, gate); | |
1155 | } | |
1156 | ||
982976d9 RZ |
1157 | static void pp_dpm_powergate_acp(void *handle, bool gate) |
1158 | { | |
1159 | struct pp_hwmgr *hwmgr = handle; | |
1160 | ||
1161 | if (!hwmgr || !hwmgr->pm_en) | |
1162 | return; | |
1163 | ||
1164 | if (hwmgr->hwmgr_func->powergate_acp == NULL) { | |
527aa2a0 | 1165 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
982976d9 RZ |
1166 | return; |
1167 | } | |
1168 | ||
1169 | hwmgr->hwmgr_func->powergate_acp(hwmgr, gate); | |
1170 | } | |
1171 | ||
40bea02f RZ |
1172 | static void pp_dpm_powergate_sdma(void *handle, bool gate) |
1173 | { | |
1174 | struct pp_hwmgr *hwmgr = handle; | |
1175 | ||
1176 | if (!hwmgr) | |
1177 | return; | |
1178 | ||
1179 | if (hwmgr->hwmgr_func->powergate_sdma == NULL) { | |
527aa2a0 | 1180 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
40bea02f RZ |
1181 | return; |
1182 | } | |
1183 | ||
1184 | hwmgr->hwmgr_func->powergate_sdma(hwmgr, gate); | |
1185 | } | |
1186 | ||
b92c6287 RZ |
1187 | static int pp_set_powergating_by_smu(void *handle, |
1188 | uint32_t block_type, bool gate) | |
1189 | { | |
1190 | int ret = 0; | |
1191 | ||
1192 | switch (block_type) { | |
1193 | case AMD_IP_BLOCK_TYPE_UVD: | |
1194 | case AMD_IP_BLOCK_TYPE_VCN: | |
1195 | pp_dpm_powergate_uvd(handle, gate); | |
1196 | break; | |
1197 | case AMD_IP_BLOCK_TYPE_VCE: | |
1198 | pp_dpm_powergate_vce(handle, gate); | |
1199 | break; | |
1200 | case AMD_IP_BLOCK_TYPE_GMC: | |
17252701 EQ |
1201 | /* |
1202 | * For now, this is only used on PICASSO. | |
1203 | * And only "gate" operation is supported. | |
1204 | */ | |
1205 | if (gate) | |
1206 | pp_dpm_powergate_mmhub(handle); | |
b92c6287 RZ |
1207 | break; |
1208 | case AMD_IP_BLOCK_TYPE_GFX: | |
85f80cb3 | 1209 | ret = pp_dpm_powergate_gfx(handle, gate); |
b92c6287 | 1210 | break; |
982976d9 RZ |
1211 | case AMD_IP_BLOCK_TYPE_ACP: |
1212 | pp_dpm_powergate_acp(handle, gate); | |
1213 | break; | |
40bea02f RZ |
1214 | case AMD_IP_BLOCK_TYPE_SDMA: |
1215 | pp_dpm_powergate_sdma(handle, gate); | |
1216 | break; | |
b92c6287 RZ |
1217 | default: |
1218 | break; | |
1219 | } | |
1220 | return ret; | |
1221 | } | |
1222 | ||
ea870e44 RZ |
1223 | static int pp_notify_smu_enable_pwe(void *handle) |
1224 | { | |
1225 | struct pp_hwmgr *hwmgr = handle; | |
1226 | ||
1227 | if (!hwmgr || !hwmgr->pm_en) | |
0d7f824b | 1228 | return -EINVAL; |
ea870e44 RZ |
1229 | |
1230 | if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) { | |
527aa2a0 | 1231 | pr_info_ratelimited("%s was not implemented.\n", __func__); |
2a782140 | 1232 | return -EINVAL; |
ea870e44 RZ |
1233 | } |
1234 | ||
ea870e44 | 1235 | hwmgr->hwmgr_func->smus_notify_pwe(hwmgr); |
ea870e44 RZ |
1236 | |
1237 | return 0; | |
1238 | } | |
1239 | ||
b55c9e7a EQ |
1240 | static int pp_enable_mgpu_fan_boost(void *handle) |
1241 | { | |
1242 | struct pp_hwmgr *hwmgr = handle; | |
1243 | ||
5be3bb6e | 1244 | if (!hwmgr) |
b55c9e7a EQ |
1245 | return -EINVAL; |
1246 | ||
5be3bb6e EQ |
1247 | if (!hwmgr->pm_en || |
1248 | hwmgr->hwmgr_func->enable_mgpu_fan_boost == NULL) | |
b55c9e7a | 1249 | return 0; |
b55c9e7a | 1250 | |
b55c9e7a | 1251 | hwmgr->hwmgr_func->enable_mgpu_fan_boost(hwmgr); |
b55c9e7a EQ |
1252 | |
1253 | return 0; | |
1254 | } | |
1255 | ||
9ed9203c | 1256 | static int pp_set_min_deep_sleep_dcefclk(void *handle, uint32_t clock) |
1257 | { | |
1258 | struct pp_hwmgr *hwmgr = handle; | |
1259 | ||
1260 | if (!hwmgr || !hwmgr->pm_en) | |
1261 | return -EINVAL; | |
1262 | ||
1263 | if (hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk == NULL) { | |
1264 | pr_debug("%s was not implemented.\n", __func__); | |
2a782140 | 1265 | return -EINVAL; |
9ed9203c | 1266 | } |
1267 | ||
9ed9203c | 1268 | hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk(hwmgr, clock); |
9ed9203c | 1269 | |
1270 | return 0; | |
1271 | } | |
1272 | ||
1273 | static int pp_set_hard_min_dcefclk_by_freq(void *handle, uint32_t clock) | |
1274 | { | |
1275 | struct pp_hwmgr *hwmgr = handle; | |
1276 | ||
1277 | if (!hwmgr || !hwmgr->pm_en) | |
1278 | return -EINVAL; | |
1279 | ||
1280 | if (hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq == NULL) { | |
1281 | pr_debug("%s was not implemented.\n", __func__); | |
2a782140 | 1282 | return -EINVAL; |
9ed9203c | 1283 | } |
1284 | ||
9ed9203c | 1285 | hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq(hwmgr, clock); |
9ed9203c | 1286 | |
1287 | return 0; | |
1288 | } | |
1289 | ||
1290 | static int pp_set_hard_min_fclk_by_freq(void *handle, uint32_t clock) | |
1291 | { | |
1292 | struct pp_hwmgr *hwmgr = handle; | |
1293 | ||
1294 | if (!hwmgr || !hwmgr->pm_en) | |
1295 | return -EINVAL; | |
1296 | ||
1297 | if (hwmgr->hwmgr_func->set_hard_min_fclk_by_freq == NULL) { | |
1298 | pr_debug("%s was not implemented.\n", __func__); | |
2a782140 | 1299 | return -EINVAL; |
9ed9203c | 1300 | } |
1301 | ||
9ed9203c | 1302 | hwmgr->hwmgr_func->set_hard_min_fclk_by_freq(hwmgr, clock); |
9ed9203c | 1303 | |
1304 | return 0; | |
1305 | } | |
1306 | ||
1307 | static int pp_set_active_display_count(void *handle, uint32_t count) | |
1308 | { | |
1309 | struct pp_hwmgr *hwmgr = handle; | |
9ed9203c | 1310 | |
1311 | if (!hwmgr || !hwmgr->pm_en) | |
1312 | return -EINVAL; | |
1313 | ||
a746c77e | 1314 | return phm_set_active_display_count(hwmgr, count); |
9ed9203c | 1315 | } |
1316 | ||
425db255 JQ |
1317 | static int pp_get_asic_baco_capability(void *handle, bool *cap) |
1318 | { | |
1319 | struct pp_hwmgr *hwmgr = handle; | |
1320 | ||
4ff17a1d | 1321 | *cap = false; |
425db255 JQ |
1322 | if (!hwmgr) |
1323 | return -EINVAL; | |
1324 | ||
c7833d33 TZ |
1325 | if (!(hwmgr->not_vf && amdgpu_dpm) || |
1326 | !hwmgr->hwmgr_func->get_asic_baco_capability) | |
425db255 JQ |
1327 | return 0; |
1328 | ||
425db255 | 1329 | hwmgr->hwmgr_func->get_asic_baco_capability(hwmgr, cap); |
425db255 JQ |
1330 | |
1331 | return 0; | |
1332 | } | |
1333 | ||
1334 | static int pp_get_asic_baco_state(void *handle, int *state) | |
1335 | { | |
1336 | struct pp_hwmgr *hwmgr = handle; | |
1337 | ||
1338 | if (!hwmgr) | |
1339 | return -EINVAL; | |
1340 | ||
a1cd1289 | 1341 | if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_asic_baco_state) |
425db255 JQ |
1342 | return 0; |
1343 | ||
425db255 | 1344 | hwmgr->hwmgr_func->get_asic_baco_state(hwmgr, (enum BACO_STATE *)state); |
425db255 JQ |
1345 | |
1346 | return 0; | |
1347 | } | |
1348 | ||
1349 | static int pp_set_asic_baco_state(void *handle, int state) | |
1350 | { | |
1351 | struct pp_hwmgr *hwmgr = handle; | |
1352 | ||
1353 | if (!hwmgr) | |
1354 | return -EINVAL; | |
1355 | ||
c7833d33 TZ |
1356 | if (!(hwmgr->not_vf && amdgpu_dpm) || |
1357 | !hwmgr->hwmgr_func->set_asic_baco_state) | |
425db255 JQ |
1358 | return 0; |
1359 | ||
425db255 | 1360 | hwmgr->hwmgr_func->set_asic_baco_state(hwmgr, (enum BACO_STATE)state); |
425db255 JQ |
1361 | |
1362 | return 0; | |
1363 | } | |
1364 | ||
7ca881a8 EQ |
1365 | static int pp_get_ppfeature_status(void *handle, char *buf) |
1366 | { | |
1367 | struct pp_hwmgr *hwmgr = handle; | |
7ca881a8 EQ |
1368 | |
1369 | if (!hwmgr || !hwmgr->pm_en || !buf) | |
1370 | return -EINVAL; | |
1371 | ||
1372 | if (hwmgr->hwmgr_func->get_ppfeature_status == NULL) { | |
1373 | pr_info_ratelimited("%s was not implemented.\n", __func__); | |
1374 | return -EINVAL; | |
1375 | } | |
1376 | ||
a746c77e | 1377 | return hwmgr->hwmgr_func->get_ppfeature_status(hwmgr, buf); |
7ca881a8 EQ |
1378 | } |
1379 | ||
1380 | static int pp_set_ppfeature_status(void *handle, uint64_t ppfeature_masks) | |
1381 | { | |
1382 | struct pp_hwmgr *hwmgr = handle; | |
7ca881a8 EQ |
1383 | |
1384 | if (!hwmgr || !hwmgr->pm_en) | |
1385 | return -EINVAL; | |
1386 | ||
1387 | if (hwmgr->hwmgr_func->set_ppfeature_status == NULL) { | |
1388 | pr_info_ratelimited("%s was not implemented.\n", __func__); | |
1389 | return -EINVAL; | |
1390 | } | |
1391 | ||
a746c77e | 1392 | return hwmgr->hwmgr_func->set_ppfeature_status(hwmgr, ppfeature_masks); |
7ca881a8 EQ |
1393 | } |
1394 | ||
e97204ea AG |
1395 | static int pp_asic_reset_mode_2(void *handle) |
1396 | { | |
1397 | struct pp_hwmgr *hwmgr = handle; | |
e97204ea AG |
1398 | |
1399 | if (!hwmgr || !hwmgr->pm_en) | |
1400 | return -EINVAL; | |
1401 | ||
1402 | if (hwmgr->hwmgr_func->asic_reset == NULL) { | |
1403 | pr_info_ratelimited("%s was not implemented.\n", __func__); | |
1404 | return -EINVAL; | |
1405 | } | |
1406 | ||
a746c77e | 1407 | return hwmgr->hwmgr_func->asic_reset(hwmgr, SMU_ASIC_RESET_MODE_2); |
e97204ea AG |
1408 | } |
1409 | ||
6acaa6af AG |
1410 | static int pp_smu_i2c_bus_access(void *handle, bool acquire) |
1411 | { | |
1412 | struct pp_hwmgr *hwmgr = handle; | |
1413 | ||
1414 | if (!hwmgr || !hwmgr->pm_en) | |
1415 | return -EINVAL; | |
1416 | ||
1417 | if (hwmgr->hwmgr_func->smu_i2c_bus_access == NULL) { | |
1418 | pr_info_ratelimited("%s was not implemented.\n", __func__); | |
1419 | return -EINVAL; | |
1420 | } | |
1421 | ||
a746c77e | 1422 | return hwmgr->hwmgr_func->smu_i2c_bus_access(hwmgr, acquire); |
6acaa6af AG |
1423 | } |
1424 | ||
06615f9a EQ |
1425 | static int pp_set_df_cstate(void *handle, enum pp_df_cstate state) |
1426 | { | |
1427 | struct pp_hwmgr *hwmgr = handle; | |
1428 | ||
1429 | if (!hwmgr) | |
1430 | return -EINVAL; | |
1431 | ||
1432 | if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_df_cstate) | |
1433 | return 0; | |
1434 | ||
06615f9a | 1435 | hwmgr->hwmgr_func->set_df_cstate(hwmgr, state); |
06615f9a EQ |
1436 | |
1437 | return 0; | |
1438 | } | |
1439 | ||
3e454860 EQ |
1440 | static int pp_set_xgmi_pstate(void *handle, uint32_t pstate) |
1441 | { | |
1442 | struct pp_hwmgr *hwmgr = handle; | |
1443 | ||
1444 | if (!hwmgr) | |
1445 | return -EINVAL; | |
1446 | ||
1447 | if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_xgmi_pstate) | |
1448 | return 0; | |
1449 | ||
3e454860 | 1450 | hwmgr->hwmgr_func->set_xgmi_pstate(hwmgr, pstate); |
3e454860 EQ |
1451 | |
1452 | return 0; | |
1453 | } | |
1454 | ||
0b01b830 EQ |
1455 | static ssize_t pp_get_gpu_metrics(void *handle, void **table) |
1456 | { | |
1457 | struct pp_hwmgr *hwmgr = handle; | |
0b01b830 EQ |
1458 | |
1459 | if (!hwmgr) | |
1460 | return -EINVAL; | |
1461 | ||
1462 | if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_gpu_metrics) | |
1463 | return -EOPNOTSUPP; | |
1464 | ||
a746c77e | 1465 | return hwmgr->hwmgr_func->get_gpu_metrics(hwmgr, table); |
0b01b830 EQ |
1466 | } |
1467 | ||
d90a53d6 PL |
1468 | static int pp_gfx_state_change_set(void *handle, uint32_t state) |
1469 | { | |
1470 | struct pp_hwmgr *hwmgr = handle; | |
1471 | ||
1472 | if (!hwmgr || !hwmgr->pm_en) | |
1473 | return -EINVAL; | |
1474 | ||
1475 | if (hwmgr->hwmgr_func->gfx_state_change == NULL) { | |
1476 | pr_info_ratelimited("%s was not implemented.\n", __func__); | |
1477 | return -EINVAL; | |
1478 | } | |
1479 | ||
d90a53d6 | 1480 | hwmgr->hwmgr_func->gfx_state_change(hwmgr, state); |
d90a53d6 PL |
1481 | return 0; |
1482 | } | |
1483 | ||
b8c78bdb LL |
1484 | static int pp_get_prv_buffer_details(void *handle, void **addr, size_t *size) |
1485 | { | |
1486 | struct pp_hwmgr *hwmgr = handle; | |
1487 | struct amdgpu_device *adev = hwmgr->adev; | |
1488 | ||
1489 | if (!addr || !size) | |
1490 | return -EINVAL; | |
1491 | ||
1492 | *addr = NULL; | |
1493 | *size = 0; | |
b8c78bdb LL |
1494 | if (adev->pm.smu_prv_buffer) { |
1495 | amdgpu_bo_kmap(adev->pm.smu_prv_buffer, addr); | |
1496 | *size = adev->pm.smu_prv_buffer_size; | |
1497 | } | |
b8c78bdb LL |
1498 | |
1499 | return 0; | |
1500 | } | |
1501 | ||
6ddbd37f EQ |
1502 | static void pp_pm_compute_clocks(void *handle) |
1503 | { | |
1504 | struct pp_hwmgr *hwmgr = handle; | |
1505 | struct amdgpu_device *adev = hwmgr->adev; | |
1506 | int i = 0; | |
1507 | ||
1508 | if (adev->mode_info.num_crtc) | |
1509 | amdgpu_display_bandwidth_update(adev); | |
1510 | ||
1511 | for (i = 0; i < AMDGPU_MAX_RINGS; i++) { | |
1512 | struct amdgpu_ring *ring = adev->rings[i]; | |
1513 | if (ring && ring->sched.ready) | |
1514 | amdgpu_fence_wait_empty(ring); | |
1515 | } | |
1516 | ||
1517 | if (!amdgpu_device_has_dc_support(adev)) { | |
1518 | amdgpu_dpm_get_active_displays(adev); | |
1519 | adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; | |
1520 | adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); | |
1521 | adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); | |
1522 | /* we have issues with mclk switching with | |
1523 | * refresh rates over 120 hz on the non-DC code. | |
1524 | */ | |
1525 | if (adev->pm.pm_display_cfg.vrefresh > 120) | |
1526 | adev->pm.pm_display_cfg.min_vblank_time = 0; | |
1527 | ||
1528 | pp_display_configuration_change(handle, | |
1529 | &adev->pm.pm_display_cfg); | |
1530 | } | |
1531 | ||
1532 | pp_dpm_dispatch_tasks(handle, | |
1533 | AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, | |
1534 | NULL); | |
1535 | } | |
1536 | ||
b905090d | 1537 | static const struct amd_pm_funcs pp_dpm_funcs = { |
f685d714 RZ |
1538 | .load_firmware = pp_dpm_load_fw, |
1539 | .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, | |
1540 | .force_performance_level = pp_dpm_force_performance_level, | |
1541 | .get_performance_level = pp_dpm_get_performance_level, | |
1542 | .get_current_power_state = pp_dpm_get_current_power_state, | |
f685d714 RZ |
1543 | .dispatch_tasks = pp_dpm_dispatch_tasks, |
1544 | .set_fan_control_mode = pp_dpm_set_fan_control_mode, | |
1545 | .get_fan_control_mode = pp_dpm_get_fan_control_mode, | |
0d8318e1 EQ |
1546 | .set_fan_speed_pwm = pp_dpm_set_fan_speed_pwm, |
1547 | .get_fan_speed_pwm = pp_dpm_get_fan_speed_pwm, | |
f685d714 | 1548 | .get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm, |
c2870527 | 1549 | .set_fan_speed_rpm = pp_dpm_set_fan_speed_rpm, |
f685d714 RZ |
1550 | .get_pp_num_states = pp_dpm_get_pp_num_states, |
1551 | .get_pp_table = pp_dpm_get_pp_table, | |
1552 | .set_pp_table = pp_dpm_set_pp_table, | |
1553 | .force_clock_level = pp_dpm_force_clock_level, | |
5d8539d2 | 1554 | .emit_clock_levels = pp_dpm_emit_clock_levels, |
f685d714 RZ |
1555 | .print_clock_levels = pp_dpm_print_clock_levels, |
1556 | .get_sclk_od = pp_dpm_get_sclk_od, | |
1557 | .set_sclk_od = pp_dpm_set_sclk_od, | |
1558 | .get_mclk_od = pp_dpm_get_mclk_od, | |
1559 | .set_mclk_od = pp_dpm_set_mclk_od, | |
1560 | .read_sensor = pp_dpm_read_sensor, | |
1561 | .get_vce_clock_state = pp_dpm_get_vce_clock_state, | |
f685d714 RZ |
1562 | .switch_power_profile = pp_dpm_switch_power_profile, |
1563 | .set_clockgating_by_smu = pp_set_clockgating_by_smu, | |
b92c6287 | 1564 | .set_powergating_by_smu = pp_set_powergating_by_smu, |
6390258a RZ |
1565 | .get_power_profile_mode = pp_get_power_profile_mode, |
1566 | .set_power_profile_mode = pp_set_power_profile_mode, | |
12a6727d | 1567 | .set_fine_grain_clk_vol = pp_set_fine_grain_clk_vol, |
e3933f26 | 1568 | .odn_edit_dpm_table = pp_odn_edit_dpm_table, |
a2c28e34 | 1569 | .set_mp1_state = pp_dpm_set_mp1_state, |
6ab8555e RZ |
1570 | .set_power_limit = pp_set_power_limit, |
1571 | .get_power_limit = pp_get_power_limit, | |
f685d714 RZ |
1572 | /* export to DC */ |
1573 | .get_sclk = pp_dpm_get_sclk, | |
1574 | .get_mclk = pp_dpm_get_mclk, | |
1575 | .display_configuration_change = pp_display_configuration_change, | |
1576 | .get_display_power_level = pp_get_display_power_level, | |
1577 | .get_current_clocks = pp_get_current_clocks, | |
1578 | .get_clock_by_type = pp_get_clock_by_type, | |
1579 | .get_clock_by_type_with_latency = pp_get_clock_by_type_with_latency, | |
1580 | .get_clock_by_type_with_voltage = pp_get_clock_by_type_with_voltage, | |
1581 | .set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges, | |
1582 | .display_clock_voltage_request = pp_display_clock_voltage_request, | |
1583 | .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks, | |
ea870e44 | 1584 | .notify_smu_enable_pwe = pp_notify_smu_enable_pwe, |
b55c9e7a | 1585 | .enable_mgpu_fan_boost = pp_enable_mgpu_fan_boost, |
9ed9203c | 1586 | .set_active_display_count = pp_set_active_display_count, |
1587 | .set_min_deep_sleep_dcefclk = pp_set_min_deep_sleep_dcefclk, | |
1588 | .set_hard_min_dcefclk_by_freq = pp_set_hard_min_dcefclk_by_freq, | |
1589 | .set_hard_min_fclk_by_freq = pp_set_hard_min_fclk_by_freq, | |
425db255 JQ |
1590 | .get_asic_baco_capability = pp_get_asic_baco_capability, |
1591 | .get_asic_baco_state = pp_get_asic_baco_state, | |
1592 | .set_asic_baco_state = pp_set_asic_baco_state, | |
7ca881a8 EQ |
1593 | .get_ppfeature_status = pp_get_ppfeature_status, |
1594 | .set_ppfeature_status = pp_set_ppfeature_status, | |
e97204ea | 1595 | .asic_reset_mode_2 = pp_asic_reset_mode_2, |
6acaa6af | 1596 | .smu_i2c_bus_access = pp_smu_i2c_bus_access, |
06615f9a | 1597 | .set_df_cstate = pp_set_df_cstate, |
3e454860 | 1598 | .set_xgmi_pstate = pp_set_xgmi_pstate, |
0b01b830 | 1599 | .get_gpu_metrics = pp_get_gpu_metrics, |
d90a53d6 | 1600 | .gfx_state_change_set = pp_gfx_state_change_set, |
b8c78bdb | 1601 | .get_smu_prv_buf_details = pp_get_prv_buffer_details, |
6ddbd37f | 1602 | .pm_compute_clocks = pp_pm_compute_clocks, |
f685d714 | 1603 | }; |