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