1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev  * Copyright 2015 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev  *
4b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10b843c749SSergey Zigachev  *
11b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13b843c749SSergey Zigachev  *
14b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21b843c749SSergey Zigachev  *
22b843c749SSergey Zigachev  */
23b843c749SSergey Zigachev #include "pp_debug.h"
24b843c749SSergey Zigachev #include <linux/types.h>
25b843c749SSergey Zigachev #include <linux/kernel.h>
26b843c749SSergey Zigachev #include <linux/gfp.h>
27b843c749SSergey Zigachev #include <linux/slab.h>
28b843c749SSergey Zigachev #include <linux/firmware.h>
29b843c749SSergey Zigachev #include "amd_shared.h"
30b843c749SSergey Zigachev #include "amd_powerplay.h"
31b843c749SSergey Zigachev #include "power_state.h"
32b843c749SSergey Zigachev #include "amdgpu.h"
33b843c749SSergey Zigachev #include "hwmgr.h"
34b843c749SSergey Zigachev 
35b843c749SSergey Zigachev 
36b843c749SSergey Zigachev static const struct amd_pm_funcs pp_dpm_funcs;
37b843c749SSergey Zigachev 
amd_powerplay_create(struct amdgpu_device * adev)38b843c749SSergey Zigachev static int amd_powerplay_create(struct amdgpu_device *adev)
39b843c749SSergey Zigachev {
40b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr;
41b843c749SSergey Zigachev 
42b843c749SSergey Zigachev 	if (adev == NULL)
43b843c749SSergey Zigachev 		return -EINVAL;
44b843c749SSergey Zigachev 
45b843c749SSergey Zigachev 	hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
46b843c749SSergey Zigachev 	if (hwmgr == NULL)
47b843c749SSergey Zigachev 		return -ENOMEM;
48b843c749SSergey Zigachev 
49b843c749SSergey Zigachev 	hwmgr->adev = adev;
50b843c749SSergey Zigachev 	hwmgr->not_vf = !amdgpu_sriov_vf(adev);
51b843c749SSergey Zigachev 	hwmgr->pm_en = (amdgpu_dpm && hwmgr->not_vf) ? true : false;
52b843c749SSergey Zigachev 	hwmgr->device = amdgpu_cgs_create_device(adev);
53*78973132SSergey Zigachev 	lockinit(&hwmgr->smu_lock, "adhwmgrsmul", 0, LK_CANRECURSE);
54b843c749SSergey Zigachev 	hwmgr->chip_family = adev->family;
55b843c749SSergey Zigachev 	hwmgr->chip_id = adev->asic_type;
56b843c749SSergey Zigachev 	hwmgr->feature_mask = adev->powerplay.pp_feature;
57b843c749SSergey Zigachev 	hwmgr->display_config = &adev->pm.pm_display_cfg;
58b843c749SSergey Zigachev 	adev->powerplay.pp_handle = hwmgr;
59b843c749SSergey Zigachev 	adev->powerplay.pp_funcs = &pp_dpm_funcs;
60b843c749SSergey Zigachev 	return 0;
61b843c749SSergey Zigachev }
62b843c749SSergey Zigachev 
63b843c749SSergey Zigachev 
amd_powerplay_destroy(struct amdgpu_device * adev)64b843c749SSergey Zigachev static void amd_powerplay_destroy(struct amdgpu_device *adev)
65b843c749SSergey Zigachev {
66b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
67b843c749SSergey Zigachev 
68b843c749SSergey Zigachev 	kfree(hwmgr->hardcode_pp_table);
69b843c749SSergey Zigachev 	hwmgr->hardcode_pp_table = NULL;
70b843c749SSergey Zigachev 
71b843c749SSergey Zigachev 	kfree(hwmgr);
72b843c749SSergey Zigachev 	hwmgr = NULL;
73b843c749SSergey Zigachev }
74b843c749SSergey Zigachev 
pp_early_init(void * handle)75b843c749SSergey Zigachev static int pp_early_init(void *handle)
76b843c749SSergey Zigachev {
77b843c749SSergey Zigachev 	int ret;
78b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
79b843c749SSergey Zigachev 
80b843c749SSergey Zigachev 	ret = amd_powerplay_create(adev);
81b843c749SSergey Zigachev 
82b843c749SSergey Zigachev 	if (ret != 0)
83b843c749SSergey Zigachev 		return ret;
84b843c749SSergey Zigachev 
85b843c749SSergey Zigachev 	ret = hwmgr_early_init(adev->powerplay.pp_handle);
86b843c749SSergey Zigachev 	if (ret)
87b843c749SSergey Zigachev 		return -EINVAL;
88b843c749SSergey Zigachev 
89b843c749SSergey Zigachev 	return 0;
90b843c749SSergey Zigachev }
91b843c749SSergey Zigachev 
pp_sw_init(void * handle)92b843c749SSergey Zigachev static int pp_sw_init(void *handle)
93b843c749SSergey Zigachev {
94b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
95b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
96b843c749SSergey Zigachev 	int ret = 0;
97b843c749SSergey Zigachev 
98b843c749SSergey Zigachev 	ret = hwmgr_sw_init(hwmgr);
99b843c749SSergey Zigachev 
100b843c749SSergey Zigachev 	pr_debug("powerplay sw init %s\n", ret ? "failed" : "successfully");
101b843c749SSergey Zigachev 
102b843c749SSergey Zigachev 	return ret;
103b843c749SSergey Zigachev }
104b843c749SSergey Zigachev 
pp_sw_fini(void * handle)105b843c749SSergey Zigachev static int pp_sw_fini(void *handle)
106b843c749SSergey Zigachev {
107b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
108b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
109b843c749SSergey Zigachev 
110b843c749SSergey Zigachev 	hwmgr_sw_fini(hwmgr);
111b843c749SSergey Zigachev 
112b843c749SSergey Zigachev 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) {
113b843c749SSergey Zigachev 		release_firmware(adev->pm.fw);
114b843c749SSergey Zigachev 		adev->pm.fw = NULL;
115b843c749SSergey Zigachev 		amdgpu_ucode_fini_bo(adev);
116b843c749SSergey Zigachev 	}
117b843c749SSergey Zigachev 
118b843c749SSergey Zigachev 	return 0;
119b843c749SSergey Zigachev }
120b843c749SSergey Zigachev 
pp_hw_init(void * handle)121b843c749SSergey Zigachev static int pp_hw_init(void *handle)
122b843c749SSergey Zigachev {
123b843c749SSergey Zigachev 	int ret = 0;
124b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
125b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
126b843c749SSergey Zigachev 
127b843c749SSergey Zigachev 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU)
128b843c749SSergey Zigachev 		amdgpu_ucode_init_bo(adev);
129b843c749SSergey Zigachev 
130b843c749SSergey Zigachev 	ret = hwmgr_hw_init(hwmgr);
131b843c749SSergey Zigachev 
132b843c749SSergey Zigachev 	if (ret)
133b843c749SSergey Zigachev 		pr_err("powerplay hw init failed\n");
134b843c749SSergey Zigachev 
135b843c749SSergey Zigachev 	return ret;
136b843c749SSergey Zigachev }
137b843c749SSergey Zigachev 
pp_hw_fini(void * handle)138b843c749SSergey Zigachev static int pp_hw_fini(void *handle)
139b843c749SSergey Zigachev {
140b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
141b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
142b843c749SSergey Zigachev 
143b843c749SSergey Zigachev 	hwmgr_hw_fini(hwmgr);
144b843c749SSergey Zigachev 
145b843c749SSergey Zigachev 	return 0;
146b843c749SSergey Zigachev }
147b843c749SSergey Zigachev 
pp_reserve_vram_for_smu(struct amdgpu_device * adev)148b843c749SSergey Zigachev static void pp_reserve_vram_for_smu(struct amdgpu_device *adev)
149b843c749SSergey Zigachev {
150b843c749SSergey Zigachev 	int r = -EINVAL;
151b843c749SSergey Zigachev 	void *cpu_ptr = NULL;
152b843c749SSergey Zigachev 	uint64_t gpu_addr;
153b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
154b843c749SSergey Zigachev 
155b843c749SSergey Zigachev 	if (amdgpu_bo_create_kernel(adev, adev->pm.smu_prv_buffer_size,
156b843c749SSergey Zigachev 						PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
157b843c749SSergey Zigachev 						&adev->pm.smu_prv_buffer,
158*78973132SSergey Zigachev 						(u64 *)&gpu_addr,
159b843c749SSergey Zigachev 						&cpu_ptr)) {
160b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: failed to create smu prv buffer\n");
161b843c749SSergey Zigachev 		return;
162b843c749SSergey Zigachev 	}
163b843c749SSergey Zigachev 
164b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->notify_cac_buffer_info)
165b843c749SSergey Zigachev 		r = hwmgr->hwmgr_func->notify_cac_buffer_info(hwmgr,
166b843c749SSergey Zigachev 					lower_32_bits((unsigned long)cpu_ptr),
167b843c749SSergey Zigachev 					upper_32_bits((unsigned long)cpu_ptr),
168b843c749SSergey Zigachev 					lower_32_bits(gpu_addr),
169b843c749SSergey Zigachev 					upper_32_bits(gpu_addr),
170b843c749SSergey Zigachev 					adev->pm.smu_prv_buffer_size);
171b843c749SSergey Zigachev 
172b843c749SSergey Zigachev 	if (r) {
173b843c749SSergey Zigachev 		amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL);
174b843c749SSergey Zigachev 		adev->pm.smu_prv_buffer = NULL;
175b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: failed to notify SMU buffer address\n");
176b843c749SSergey Zigachev 	}
177b843c749SSergey Zigachev }
178b843c749SSergey Zigachev 
pp_late_init(void * handle)179b843c749SSergey Zigachev static int pp_late_init(void *handle)
180b843c749SSergey Zigachev {
181b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
182b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
183b843c749SSergey Zigachev 
184b843c749SSergey Zigachev 	if (hwmgr && hwmgr->pm_en) {
185b843c749SSergey Zigachev 		mutex_lock(&hwmgr->smu_lock);
186b843c749SSergey Zigachev 		hwmgr_handle_task(hwmgr,
187b843c749SSergey Zigachev 					AMD_PP_TASK_COMPLETE_INIT, NULL);
188b843c749SSergey Zigachev 		mutex_unlock(&hwmgr->smu_lock);
189b843c749SSergey Zigachev 	}
190b843c749SSergey Zigachev 	if (adev->pm.smu_prv_buffer_size != 0)
191b843c749SSergey Zigachev 		pp_reserve_vram_for_smu(adev);
192b843c749SSergey Zigachev 
193b843c749SSergey Zigachev 	return 0;
194b843c749SSergey Zigachev }
195b843c749SSergey Zigachev 
pp_late_fini(void * handle)196b843c749SSergey Zigachev static void pp_late_fini(void *handle)
197b843c749SSergey Zigachev {
198b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
199b843c749SSergey Zigachev 
200b843c749SSergey Zigachev 	if (adev->pm.smu_prv_buffer)
201b843c749SSergey Zigachev 		amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL);
202b843c749SSergey Zigachev 	amd_powerplay_destroy(adev);
203b843c749SSergey Zigachev }
204b843c749SSergey Zigachev 
205b843c749SSergey Zigachev 
pp_is_idle(void * handle)206b843c749SSergey Zigachev static bool pp_is_idle(void *handle)
207b843c749SSergey Zigachev {
208b843c749SSergey Zigachev 	return false;
209b843c749SSergey Zigachev }
210b843c749SSergey Zigachev 
pp_wait_for_idle(void * handle)211b843c749SSergey Zigachev static int pp_wait_for_idle(void *handle)
212b843c749SSergey Zigachev {
213b843c749SSergey Zigachev 	return 0;
214b843c749SSergey Zigachev }
215b843c749SSergey Zigachev 
pp_sw_reset(void * handle)216b843c749SSergey Zigachev static int pp_sw_reset(void *handle)
217b843c749SSergey Zigachev {
218b843c749SSergey Zigachev 	return 0;
219b843c749SSergey Zigachev }
220b843c749SSergey Zigachev 
pp_set_powergating_state(void * handle,enum amd_powergating_state state)221b843c749SSergey Zigachev static int pp_set_powergating_state(void *handle,
222b843c749SSergey Zigachev 				    enum amd_powergating_state state)
223b843c749SSergey Zigachev {
224b843c749SSergey Zigachev 	return 0;
225b843c749SSergey Zigachev }
226b843c749SSergey Zigachev 
pp_suspend(void * handle)227b843c749SSergey Zigachev static int pp_suspend(void *handle)
228b843c749SSergey Zigachev {
229b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
230b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
231b843c749SSergey Zigachev 
232b843c749SSergey Zigachev 	return hwmgr_suspend(hwmgr);
233b843c749SSergey Zigachev }
234b843c749SSergey Zigachev 
pp_resume(void * handle)235b843c749SSergey Zigachev static int pp_resume(void *handle)
236b843c749SSergey Zigachev {
237b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
238b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
239b843c749SSergey Zigachev 
240b843c749SSergey Zigachev 	return hwmgr_resume(hwmgr);
241b843c749SSergey Zigachev }
242b843c749SSergey Zigachev 
pp_set_clockgating_state(void * handle,enum amd_clockgating_state state)243b843c749SSergey Zigachev static int pp_set_clockgating_state(void *handle,
244b843c749SSergey Zigachev 					  enum amd_clockgating_state state)
245b843c749SSergey Zigachev {
246b843c749SSergey Zigachev 	return 0;
247b843c749SSergey Zigachev }
248b843c749SSergey Zigachev 
249b843c749SSergey Zigachev static const struct amd_ip_funcs pp_ip_funcs = {
250b843c749SSergey Zigachev 	.name = "powerplay",
251b843c749SSergey Zigachev 	.early_init = pp_early_init,
252b843c749SSergey Zigachev 	.late_init = pp_late_init,
253b843c749SSergey Zigachev 	.sw_init = pp_sw_init,
254b843c749SSergey Zigachev 	.sw_fini = pp_sw_fini,
255b843c749SSergey Zigachev 	.hw_init = pp_hw_init,
256b843c749SSergey Zigachev 	.hw_fini = pp_hw_fini,
257b843c749SSergey Zigachev 	.late_fini = pp_late_fini,
258b843c749SSergey Zigachev 	.suspend = pp_suspend,
259b843c749SSergey Zigachev 	.resume = pp_resume,
260b843c749SSergey Zigachev 	.is_idle = pp_is_idle,
261b843c749SSergey Zigachev 	.wait_for_idle = pp_wait_for_idle,
262b843c749SSergey Zigachev 	.soft_reset = pp_sw_reset,
263b843c749SSergey Zigachev 	.set_clockgating_state = pp_set_clockgating_state,
264b843c749SSergey Zigachev 	.set_powergating_state = pp_set_powergating_state,
265b843c749SSergey Zigachev };
266b843c749SSergey Zigachev 
267b843c749SSergey Zigachev const struct amdgpu_ip_block_version pp_smu_ip_block =
268b843c749SSergey Zigachev {
269b843c749SSergey Zigachev 	.type = AMD_IP_BLOCK_TYPE_SMC,
270b843c749SSergey Zigachev 	.major = 1,
271b843c749SSergey Zigachev 	.minor = 0,
272b843c749SSergey Zigachev 	.rev = 0,
273b843c749SSergey Zigachev 	.funcs = &pp_ip_funcs,
274b843c749SSergey Zigachev };
275b843c749SSergey Zigachev 
pp_dpm_load_fw(void * handle)276b843c749SSergey Zigachev static int pp_dpm_load_fw(void *handle)
277b843c749SSergey Zigachev {
278b843c749SSergey Zigachev 	return 0;
279b843c749SSergey Zigachev }
280b843c749SSergey Zigachev 
pp_dpm_fw_loading_complete(void * handle)281b843c749SSergey Zigachev static int pp_dpm_fw_loading_complete(void *handle)
282b843c749SSergey Zigachev {
283b843c749SSergey Zigachev 	return 0;
284b843c749SSergey Zigachev }
285b843c749SSergey Zigachev 
pp_set_clockgating_by_smu(void * handle,uint32_t msg_id)286b843c749SSergey Zigachev static int pp_set_clockgating_by_smu(void *handle, uint32_t msg_id)
287b843c749SSergey Zigachev {
288b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
289b843c749SSergey Zigachev 
290b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
291b843c749SSergey Zigachev 		return -EINVAL;
292b843c749SSergey Zigachev 
293b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
294b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
295b843c749SSergey Zigachev 		return 0;
296b843c749SSergey Zigachev 	}
297b843c749SSergey Zigachev 
298b843c749SSergey Zigachev 	return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
299b843c749SSergey Zigachev }
300b843c749SSergey Zigachev 
pp_dpm_en_umd_pstate(struct pp_hwmgr * hwmgr,enum amd_dpm_forced_level * level)301b843c749SSergey Zigachev static void pp_dpm_en_umd_pstate(struct pp_hwmgr  *hwmgr,
302b843c749SSergey Zigachev 						enum amd_dpm_forced_level *level)
303b843c749SSergey Zigachev {
304b843c749SSergey Zigachev 	uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
305b843c749SSergey Zigachev 					AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
306b843c749SSergey Zigachev 					AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
307b843c749SSergey Zigachev 					AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
308b843c749SSergey Zigachev 
309b843c749SSergey Zigachev 	if (!(hwmgr->dpm_level & profile_mode_mask)) {
310b843c749SSergey Zigachev 		/* enter umd pstate, save current level, disable gfx cg*/
311b843c749SSergey Zigachev 		if (*level & profile_mode_mask) {
312b843c749SSergey Zigachev 			hwmgr->saved_dpm_level = hwmgr->dpm_level;
313b843c749SSergey Zigachev 			hwmgr->en_umd_pstate = true;
314b843c749SSergey Zigachev 			amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
315b843c749SSergey Zigachev 						AMD_IP_BLOCK_TYPE_GFX,
316b843c749SSergey Zigachev 						AMD_CG_STATE_UNGATE);
317b843c749SSergey Zigachev 			amdgpu_device_ip_set_powergating_state(hwmgr->adev,
318b843c749SSergey Zigachev 					AMD_IP_BLOCK_TYPE_GFX,
319b843c749SSergey Zigachev 					AMD_PG_STATE_UNGATE);
320b843c749SSergey Zigachev 		}
321b843c749SSergey Zigachev 	} else {
322b843c749SSergey Zigachev 		/* exit umd pstate, restore level, enable gfx cg*/
323b843c749SSergey Zigachev 		if (!(*level & profile_mode_mask)) {
324b843c749SSergey Zigachev 			if (*level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)
325b843c749SSergey Zigachev 				*level = hwmgr->saved_dpm_level;
326b843c749SSergey Zigachev 			hwmgr->en_umd_pstate = false;
327b843c749SSergey Zigachev 			amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
328b843c749SSergey Zigachev 					AMD_IP_BLOCK_TYPE_GFX,
329b843c749SSergey Zigachev 					AMD_CG_STATE_GATE);
330b843c749SSergey Zigachev 			amdgpu_device_ip_set_powergating_state(hwmgr->adev,
331b843c749SSergey Zigachev 					AMD_IP_BLOCK_TYPE_GFX,
332b843c749SSergey Zigachev 					AMD_PG_STATE_GATE);
333b843c749SSergey Zigachev 		}
334b843c749SSergey Zigachev 	}
335b843c749SSergey Zigachev }
336b843c749SSergey Zigachev 
pp_dpm_force_performance_level(void * handle,enum amd_dpm_forced_level level)337b843c749SSergey Zigachev static int pp_dpm_force_performance_level(void *handle,
338b843c749SSergey Zigachev 					enum amd_dpm_forced_level level)
339b843c749SSergey Zigachev {
340b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
341b843c749SSergey Zigachev 
342b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
343b843c749SSergey Zigachev 		return -EINVAL;
344b843c749SSergey Zigachev 
345b843c749SSergey Zigachev 	if (level == hwmgr->dpm_level)
346b843c749SSergey Zigachev 		return 0;
347b843c749SSergey Zigachev 
348b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
349b843c749SSergey Zigachev 	pp_dpm_en_umd_pstate(hwmgr, &level);
350b843c749SSergey Zigachev 	hwmgr->request_dpm_level = level;
351b843c749SSergey Zigachev 	hwmgr_handle_task(hwmgr, AMD_PP_TASK_READJUST_POWER_STATE, NULL);
352b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
353b843c749SSergey Zigachev 
354b843c749SSergey Zigachev 	return 0;
355b843c749SSergey Zigachev }
356b843c749SSergey Zigachev 
pp_dpm_get_performance_level(void * handle)357b843c749SSergey Zigachev static enum amd_dpm_forced_level pp_dpm_get_performance_level(
358b843c749SSergey Zigachev 								void *handle)
359b843c749SSergey Zigachev {
360b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
361b843c749SSergey Zigachev 	enum amd_dpm_forced_level level;
362b843c749SSergey Zigachev 
363b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
364b843c749SSergey Zigachev 		return -EINVAL;
365b843c749SSergey Zigachev 
366b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
367b843c749SSergey Zigachev 	level = hwmgr->dpm_level;
368b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
369b843c749SSergey Zigachev 	return level;
370b843c749SSergey Zigachev }
371b843c749SSergey Zigachev 
pp_dpm_get_sclk(void * handle,bool low)372b843c749SSergey Zigachev static uint32_t pp_dpm_get_sclk(void *handle, bool low)
373b843c749SSergey Zigachev {
374b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
375b843c749SSergey Zigachev 	uint32_t clk = 0;
376b843c749SSergey Zigachev 
377b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
378b843c749SSergey Zigachev 		return 0;
379b843c749SSergey Zigachev 
380b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_sclk == NULL) {
381b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
382b843c749SSergey Zigachev 		return 0;
383b843c749SSergey Zigachev 	}
384b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
385b843c749SSergey Zigachev 	clk = hwmgr->hwmgr_func->get_sclk(hwmgr, low);
386b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
387b843c749SSergey Zigachev 	return clk;
388b843c749SSergey Zigachev }
389b843c749SSergey Zigachev 
pp_dpm_get_mclk(void * handle,bool low)390b843c749SSergey Zigachev static uint32_t pp_dpm_get_mclk(void *handle, bool low)
391b843c749SSergey Zigachev {
392b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
393b843c749SSergey Zigachev 	uint32_t clk = 0;
394b843c749SSergey Zigachev 
395b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
396b843c749SSergey Zigachev 		return 0;
397b843c749SSergey Zigachev 
398b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_mclk == NULL) {
399b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
400b843c749SSergey Zigachev 		return 0;
401b843c749SSergey Zigachev 	}
402b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
403b843c749SSergey Zigachev 	clk = hwmgr->hwmgr_func->get_mclk(hwmgr, low);
404b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
405b843c749SSergey Zigachev 	return clk;
406b843c749SSergey Zigachev }
407b843c749SSergey Zigachev 
pp_dpm_powergate_vce(void * handle,bool gate)408b843c749SSergey Zigachev static void pp_dpm_powergate_vce(void *handle, bool gate)
409b843c749SSergey Zigachev {
410b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
411b843c749SSergey Zigachev 
412b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
413b843c749SSergey Zigachev 		return;
414b843c749SSergey Zigachev 
415b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->powergate_vce == NULL) {
416b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
417b843c749SSergey Zigachev 		return;
418b843c749SSergey Zigachev 	}
419b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
420b843c749SSergey Zigachev 	hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
421b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
422b843c749SSergey Zigachev }
423b843c749SSergey Zigachev 
pp_dpm_powergate_uvd(void * handle,bool gate)424b843c749SSergey Zigachev static void pp_dpm_powergate_uvd(void *handle, bool gate)
425b843c749SSergey Zigachev {
426b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
427b843c749SSergey Zigachev 
428b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
429b843c749SSergey Zigachev 		return;
430b843c749SSergey Zigachev 
431b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
432b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
433b843c749SSergey Zigachev 		return;
434b843c749SSergey Zigachev 	}
435b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
436b843c749SSergey Zigachev 	hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
437b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
438b843c749SSergey Zigachev }
439b843c749SSergey Zigachev 
pp_dpm_dispatch_tasks(void * handle,enum amd_pp_task task_id,enum amd_pm_state_type * user_state)440b843c749SSergey Zigachev static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id,
441b843c749SSergey Zigachev 		enum amd_pm_state_type *user_state)
442b843c749SSergey Zigachev {
443b843c749SSergey Zigachev 	int ret = 0;
444b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
445b843c749SSergey Zigachev 
446b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
447b843c749SSergey Zigachev 		return -EINVAL;
448b843c749SSergey Zigachev 
449b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
450b843c749SSergey Zigachev 	ret = hwmgr_handle_task(hwmgr, task_id, user_state);
451b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
452b843c749SSergey Zigachev 
453b843c749SSergey Zigachev 	return ret;
454b843c749SSergey Zigachev }
455b843c749SSergey Zigachev 
pp_dpm_get_current_power_state(void * handle)456b843c749SSergey Zigachev static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
457b843c749SSergey Zigachev {
458b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
459b843c749SSergey Zigachev 	struct pp_power_state *state;
460b843c749SSergey Zigachev 	enum amd_pm_state_type pm_type;
461b843c749SSergey Zigachev 
462b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en || !hwmgr->current_ps)
463b843c749SSergey Zigachev 		return -EINVAL;
464b843c749SSergey Zigachev 
465b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
466b843c749SSergey Zigachev 
467b843c749SSergey Zigachev 	state = hwmgr->current_ps;
468b843c749SSergey Zigachev 
469b843c749SSergey Zigachev 	switch (state->classification.ui_label) {
470b843c749SSergey Zigachev 	case PP_StateUILabel_Battery:
471b843c749SSergey Zigachev 		pm_type = POWER_STATE_TYPE_BATTERY;
472b843c749SSergey Zigachev 		break;
473b843c749SSergey Zigachev 	case PP_StateUILabel_Balanced:
474b843c749SSergey Zigachev 		pm_type = POWER_STATE_TYPE_BALANCED;
475b843c749SSergey Zigachev 		break;
476b843c749SSergey Zigachev 	case PP_StateUILabel_Performance:
477b843c749SSergey Zigachev 		pm_type = POWER_STATE_TYPE_PERFORMANCE;
478b843c749SSergey Zigachev 		break;
479b843c749SSergey Zigachev 	default:
480b843c749SSergey Zigachev 		if (state->classification.flags & PP_StateClassificationFlag_Boot)
481b843c749SSergey Zigachev 			pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
482b843c749SSergey Zigachev 		else
483b843c749SSergey Zigachev 			pm_type = POWER_STATE_TYPE_DEFAULT;
484b843c749SSergey Zigachev 		break;
485b843c749SSergey Zigachev 	}
486b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
487b843c749SSergey Zigachev 
488b843c749SSergey Zigachev 	return pm_type;
489b843c749SSergey Zigachev }
490b843c749SSergey Zigachev 
pp_dpm_set_fan_control_mode(void * handle,uint32_t mode)491b843c749SSergey Zigachev static void pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
492b843c749SSergey Zigachev {
493b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
494b843c749SSergey Zigachev 
495b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
496b843c749SSergey Zigachev 		return;
497b843c749SSergey Zigachev 
498b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
499b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
500b843c749SSergey Zigachev 		return;
501b843c749SSergey Zigachev 	}
502b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
503b843c749SSergey Zigachev 	hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
504b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
505b843c749SSergey Zigachev }
506b843c749SSergey Zigachev 
pp_dpm_get_fan_control_mode(void * handle)507b843c749SSergey Zigachev static uint32_t pp_dpm_get_fan_control_mode(void *handle)
508b843c749SSergey Zigachev {
509b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
510b843c749SSergey Zigachev 	uint32_t mode = 0;
511b843c749SSergey Zigachev 
512b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
513b843c749SSergey Zigachev 		return 0;
514b843c749SSergey Zigachev 
515b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) {
516b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
517b843c749SSergey Zigachev 		return 0;
518b843c749SSergey Zigachev 	}
519b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
520b843c749SSergey Zigachev 	mode = hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
521b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
522b843c749SSergey Zigachev 	return mode;
523b843c749SSergey Zigachev }
524b843c749SSergey Zigachev 
pp_dpm_set_fan_speed_percent(void * handle,uint32_t percent)525b843c749SSergey Zigachev static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
526b843c749SSergey Zigachev {
527b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
528b843c749SSergey Zigachev 	int ret = 0;
529b843c749SSergey Zigachev 
530b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
531b843c749SSergey Zigachev 		return -EINVAL;
532b843c749SSergey Zigachev 
533b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) {
534b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
535b843c749SSergey Zigachev 		return 0;
536b843c749SSergey Zigachev 	}
537b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
538b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
539b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
540b843c749SSergey Zigachev 	return ret;
541b843c749SSergey Zigachev }
542b843c749SSergey Zigachev 
pp_dpm_get_fan_speed_percent(void * handle,uint32_t * speed)543b843c749SSergey Zigachev static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
544b843c749SSergey Zigachev {
545b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
546b843c749SSergey Zigachev 	int ret = 0;
547b843c749SSergey Zigachev 
548b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
549b843c749SSergey Zigachev 		return -EINVAL;
550b843c749SSergey Zigachev 
551b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
552b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
553b843c749SSergey Zigachev 		return 0;
554b843c749SSergey Zigachev 	}
555b843c749SSergey Zigachev 
556b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
557b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
558b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
559b843c749SSergey Zigachev 	return ret;
560b843c749SSergey Zigachev }
561b843c749SSergey Zigachev 
pp_dpm_get_fan_speed_rpm(void * handle,uint32_t * rpm)562b843c749SSergey Zigachev static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
563b843c749SSergey Zigachev {
564b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
565b843c749SSergey Zigachev 	int ret = 0;
566b843c749SSergey Zigachev 
567b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
568b843c749SSergey Zigachev 		return -EINVAL;
569b843c749SSergey Zigachev 
570b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_fan_speed_rpm == NULL)
571b843c749SSergey Zigachev 		return -EINVAL;
572b843c749SSergey Zigachev 
573b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
574b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->get_fan_speed_rpm(hwmgr, rpm);
575b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
576b843c749SSergey Zigachev 	return ret;
577b843c749SSergey Zigachev }
578b843c749SSergey Zigachev 
pp_dpm_get_pp_num_states(void * handle,struct pp_states_info * data)579b843c749SSergey Zigachev static int pp_dpm_get_pp_num_states(void *handle,
580b843c749SSergey Zigachev 		struct pp_states_info *data)
581b843c749SSergey Zigachev {
582b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
583b843c749SSergey Zigachev 	int i;
584b843c749SSergey Zigachev 
585b843c749SSergey Zigachev 	memset(data, 0, sizeof(*data));
586b843c749SSergey Zigachev 
587b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!hwmgr->ps)
588b843c749SSergey Zigachev 		return -EINVAL;
589b843c749SSergey Zigachev 
590b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
591b843c749SSergey Zigachev 
592b843c749SSergey Zigachev 	data->nums = hwmgr->num_ps;
593b843c749SSergey Zigachev 
594b843c749SSergey Zigachev 	for (i = 0; i < hwmgr->num_ps; i++) {
595b843c749SSergey Zigachev 		struct pp_power_state *state = (struct pp_power_state *)
596b843c749SSergey Zigachev 				((unsigned long)hwmgr->ps + i * hwmgr->ps_size);
597b843c749SSergey Zigachev 		switch (state->classification.ui_label) {
598b843c749SSergey Zigachev 		case PP_StateUILabel_Battery:
599b843c749SSergey Zigachev 			data->states[i] = POWER_STATE_TYPE_BATTERY;
600b843c749SSergey Zigachev 			break;
601b843c749SSergey Zigachev 		case PP_StateUILabel_Balanced:
602b843c749SSergey Zigachev 			data->states[i] = POWER_STATE_TYPE_BALANCED;
603b843c749SSergey Zigachev 			break;
604b843c749SSergey Zigachev 		case PP_StateUILabel_Performance:
605b843c749SSergey Zigachev 			data->states[i] = POWER_STATE_TYPE_PERFORMANCE;
606b843c749SSergey Zigachev 			break;
607b843c749SSergey Zigachev 		default:
608b843c749SSergey Zigachev 			if (state->classification.flags & PP_StateClassificationFlag_Boot)
609b843c749SSergey Zigachev 				data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT;
610b843c749SSergey Zigachev 			else
611b843c749SSergey Zigachev 				data->states[i] = POWER_STATE_TYPE_DEFAULT;
612b843c749SSergey Zigachev 		}
613b843c749SSergey Zigachev 	}
614b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
615b843c749SSergey Zigachev 	return 0;
616b843c749SSergey Zigachev }
617b843c749SSergey Zigachev 
pp_dpm_get_pp_table(void * handle,char ** table)618b843c749SSergey Zigachev static int pp_dpm_get_pp_table(void *handle, char **table)
619b843c749SSergey Zigachev {
620b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
621b843c749SSergey Zigachev 	int size = 0;
622b843c749SSergey Zigachev 
623b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!hwmgr->soft_pp_table)
624b843c749SSergey Zigachev 		return -EINVAL;
625b843c749SSergey Zigachev 
626b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
627b843c749SSergey Zigachev 	*table = (char *)hwmgr->soft_pp_table;
628b843c749SSergey Zigachev 	size = hwmgr->soft_pp_table_size;
629b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
630b843c749SSergey Zigachev 	return size;
631b843c749SSergey Zigachev }
632b843c749SSergey Zigachev 
amd_powerplay_reset(void * handle)633b843c749SSergey Zigachev static int amd_powerplay_reset(void *handle)
634b843c749SSergey Zigachev {
635b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
636b843c749SSergey Zigachev 	int ret;
637b843c749SSergey Zigachev 
638b843c749SSergey Zigachev 	ret = hwmgr_hw_fini(hwmgr);
639b843c749SSergey Zigachev 	if (ret)
640b843c749SSergey Zigachev 		return ret;
641b843c749SSergey Zigachev 
642b843c749SSergey Zigachev 	ret = hwmgr_hw_init(hwmgr);
643b843c749SSergey Zigachev 	if (ret)
644b843c749SSergey Zigachev 		return ret;
645b843c749SSergey Zigachev 
646b843c749SSergey Zigachev 	return hwmgr_handle_task(hwmgr, AMD_PP_TASK_COMPLETE_INIT, NULL);
647b843c749SSergey Zigachev }
648b843c749SSergey Zigachev 
pp_dpm_set_pp_table(void * handle,const char * buf,size_t size)649b843c749SSergey Zigachev static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
650b843c749SSergey Zigachev {
651b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
652b843c749SSergey Zigachev 	int ret = -ENOMEM;
653b843c749SSergey Zigachev 
654b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
655b843c749SSergey Zigachev 		return -EINVAL;
656b843c749SSergey Zigachev 
657b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
658b843c749SSergey Zigachev 	if (!hwmgr->hardcode_pp_table) {
659b843c749SSergey Zigachev 		hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
660b843c749SSergey Zigachev 						   hwmgr->soft_pp_table_size,
661b843c749SSergey Zigachev 						   GFP_KERNEL);
662b843c749SSergey Zigachev 		if (!hwmgr->hardcode_pp_table)
663b843c749SSergey Zigachev 			goto err;
664b843c749SSergey Zigachev 	}
665b843c749SSergey Zigachev 
666b843c749SSergey Zigachev 	memcpy(hwmgr->hardcode_pp_table, buf, size);
667b843c749SSergey Zigachev 
668b843c749SSergey Zigachev 	hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;
669b843c749SSergey Zigachev 
670b843c749SSergey Zigachev 	ret = amd_powerplay_reset(handle);
671b843c749SSergey Zigachev 	if (ret)
672b843c749SSergey Zigachev 		goto err;
673b843c749SSergey Zigachev 
674b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->avfs_control) {
675b843c749SSergey Zigachev 		ret = hwmgr->hwmgr_func->avfs_control(hwmgr, false);
676b843c749SSergey Zigachev 		if (ret)
677b843c749SSergey Zigachev 			goto err;
678b843c749SSergey Zigachev 	}
679b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
680b843c749SSergey Zigachev 	return 0;
681b843c749SSergey Zigachev err:
682b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
683b843c749SSergey Zigachev 	return ret;
684b843c749SSergey Zigachev }
685b843c749SSergey Zigachev 
pp_dpm_force_clock_level(void * handle,enum pp_clock_type type,uint32_t mask)686b843c749SSergey Zigachev static int pp_dpm_force_clock_level(void *handle,
687b843c749SSergey Zigachev 		enum pp_clock_type type, uint32_t mask)
688b843c749SSergey Zigachev {
689b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
690b843c749SSergey Zigachev 	int ret = 0;
691b843c749SSergey Zigachev 
692b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
693b843c749SSergey Zigachev 		return -EINVAL;
694b843c749SSergey Zigachev 
695b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->force_clock_level == NULL) {
696b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
697b843c749SSergey Zigachev 		return 0;
698b843c749SSergey Zigachev 	}
699b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
700b843c749SSergey Zigachev 	if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)
701b843c749SSergey Zigachev 		ret = hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
702b843c749SSergey Zigachev 	else
703b843c749SSergey Zigachev 		ret = -EINVAL;
704b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
705b843c749SSergey Zigachev 	return ret;
706b843c749SSergey Zigachev }
707b843c749SSergey Zigachev 
pp_dpm_print_clock_levels(void * handle,enum pp_clock_type type,char * buf)708b843c749SSergey Zigachev static int pp_dpm_print_clock_levels(void *handle,
709b843c749SSergey Zigachev 		enum pp_clock_type type, char *buf)
710b843c749SSergey Zigachev {
711b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
712b843c749SSergey Zigachev 	int ret = 0;
713b843c749SSergey Zigachev 
714b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
715b843c749SSergey Zigachev 		return -EINVAL;
716b843c749SSergey Zigachev 
717b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
718b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
719b843c749SSergey Zigachev 		return 0;
720b843c749SSergey Zigachev 	}
721b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
722b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
723b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
724b843c749SSergey Zigachev 	return ret;
725b843c749SSergey Zigachev }
726b843c749SSergey Zigachev 
pp_dpm_get_sclk_od(void * handle)727b843c749SSergey Zigachev static int pp_dpm_get_sclk_od(void *handle)
728b843c749SSergey Zigachev {
729b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
730b843c749SSergey Zigachev 	int ret = 0;
731b843c749SSergey Zigachev 
732b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
733b843c749SSergey Zigachev 		return -EINVAL;
734b843c749SSergey Zigachev 
735b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
736b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
737b843c749SSergey Zigachev 		return 0;
738b843c749SSergey Zigachev 	}
739b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
740b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->get_sclk_od(hwmgr);
741b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
742b843c749SSergey Zigachev 	return ret;
743b843c749SSergey Zigachev }
744b843c749SSergey Zigachev 
pp_dpm_set_sclk_od(void * handle,uint32_t value)745b843c749SSergey Zigachev static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
746b843c749SSergey Zigachev {
747b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
748b843c749SSergey Zigachev 	int ret = 0;
749b843c749SSergey Zigachev 
750b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
751b843c749SSergey Zigachev 		return -EINVAL;
752b843c749SSergey Zigachev 
753b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
754b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
755b843c749SSergey Zigachev 		return 0;
756b843c749SSergey Zigachev 	}
757b843c749SSergey Zigachev 
758b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
759b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->set_sclk_od(hwmgr, value);
760b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
761b843c749SSergey Zigachev 	return ret;
762b843c749SSergey Zigachev }
763b843c749SSergey Zigachev 
pp_dpm_get_mclk_od(void * handle)764b843c749SSergey Zigachev static int pp_dpm_get_mclk_od(void *handle)
765b843c749SSergey Zigachev {
766b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
767b843c749SSergey Zigachev 	int ret = 0;
768b843c749SSergey Zigachev 
769b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
770b843c749SSergey Zigachev 		return -EINVAL;
771b843c749SSergey Zigachev 
772b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
773b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
774b843c749SSergey Zigachev 		return 0;
775b843c749SSergey Zigachev 	}
776b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
777b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->get_mclk_od(hwmgr);
778b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
779b843c749SSergey Zigachev 	return ret;
780b843c749SSergey Zigachev }
781b843c749SSergey Zigachev 
pp_dpm_set_mclk_od(void * handle,uint32_t value)782b843c749SSergey Zigachev static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
783b843c749SSergey Zigachev {
784b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
785b843c749SSergey Zigachev 	int ret = 0;
786b843c749SSergey Zigachev 
787b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
788b843c749SSergey Zigachev 		return -EINVAL;
789b843c749SSergey Zigachev 
790b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
791b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
792b843c749SSergey Zigachev 		return 0;
793b843c749SSergey Zigachev 	}
794b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
795b843c749SSergey Zigachev 	ret = hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
796b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
797b843c749SSergey Zigachev 	return ret;
798b843c749SSergey Zigachev }
799b843c749SSergey Zigachev 
pp_dpm_read_sensor(void * handle,int idx,void * value,int * size)800b843c749SSergey Zigachev static int pp_dpm_read_sensor(void *handle, int idx,
801b843c749SSergey Zigachev 			      void *value, int *size)
802b843c749SSergey Zigachev {
803b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
804b843c749SSergey Zigachev 	int ret = 0;
805b843c749SSergey Zigachev 
806b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en || !value)
807b843c749SSergey Zigachev 		return -EINVAL;
808b843c749SSergey Zigachev 
809b843c749SSergey Zigachev 	switch (idx) {
810b843c749SSergey Zigachev 	case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK:
811b843c749SSergey Zigachev 		*((uint32_t *)value) = hwmgr->pstate_sclk;
812b843c749SSergey Zigachev 		return 0;
813b843c749SSergey Zigachev 	case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK:
814b843c749SSergey Zigachev 		*((uint32_t *)value) = hwmgr->pstate_mclk;
815b843c749SSergey Zigachev 		return 0;
816b843c749SSergey Zigachev 	default:
817b843c749SSergey Zigachev 		mutex_lock(&hwmgr->smu_lock);
818b843c749SSergey Zigachev 		ret = hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size);
819b843c749SSergey Zigachev 		mutex_unlock(&hwmgr->smu_lock);
820b843c749SSergey Zigachev 		return ret;
821b843c749SSergey Zigachev 	}
822b843c749SSergey Zigachev }
823b843c749SSergey Zigachev 
824b843c749SSergey Zigachev static struct amd_vce_state*
pp_dpm_get_vce_clock_state(void * handle,unsigned idx)825b843c749SSergey Zigachev pp_dpm_get_vce_clock_state(void *handle, unsigned idx)
826b843c749SSergey Zigachev {
827b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
828b843c749SSergey Zigachev 
829b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
830b843c749SSergey Zigachev 		return NULL;
831b843c749SSergey Zigachev 
832b843c749SSergey Zigachev 	if (idx < hwmgr->num_vce_state_tables)
833b843c749SSergey Zigachev 		return &hwmgr->vce_states[idx];
834b843c749SSergey Zigachev 	return NULL;
835b843c749SSergey Zigachev }
836b843c749SSergey Zigachev 
pp_get_power_profile_mode(void * handle,char * buf)837b843c749SSergey Zigachev static int pp_get_power_profile_mode(void *handle, char *buf)
838b843c749SSergey Zigachev {
839b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
840b843c749SSergey Zigachev 
841b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en || !buf)
842b843c749SSergey Zigachev 		return -EINVAL;
843b843c749SSergey Zigachev 
844b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->get_power_profile_mode == NULL) {
845b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
846b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
847b843c749SSergey Zigachev 	}
848b843c749SSergey Zigachev 
849b843c749SSergey Zigachev 	return hwmgr->hwmgr_func->get_power_profile_mode(hwmgr, buf);
850b843c749SSergey Zigachev }
851b843c749SSergey Zigachev 
pp_set_power_profile_mode(void * handle,long * input,uint32_t size)852b843c749SSergey Zigachev static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size)
853b843c749SSergey Zigachev {
854b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
855b843c749SSergey Zigachev 	int ret = -EINVAL;
856b843c749SSergey Zigachev 
857b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
858b843c749SSergey Zigachev 		return ret;
859b843c749SSergey Zigachev 
860b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) {
861b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
862b843c749SSergey Zigachev 		return ret;
863b843c749SSergey Zigachev 	}
864b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
865b843c749SSergey Zigachev 	if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)
866b843c749SSergey Zigachev 		ret = hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, input, size);
867b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
868b843c749SSergey Zigachev 	return ret;
869b843c749SSergey Zigachev }
870b843c749SSergey Zigachev 
pp_odn_edit_dpm_table(void * handle,uint32_t type,long * input,uint32_t size)871b843c749SSergey Zigachev static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size)
872b843c749SSergey Zigachev {
873b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
874b843c749SSergey Zigachev 
875b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
876b843c749SSergey Zigachev 		return -EINVAL;
877b843c749SSergey Zigachev 
878b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) {
879b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
880b843c749SSergey Zigachev 		return -EINVAL;
881b843c749SSergey Zigachev 	}
882b843c749SSergey Zigachev 
883b843c749SSergey Zigachev 	return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size);
884b843c749SSergey Zigachev }
885b843c749SSergey Zigachev 
pp_dpm_switch_power_profile(void * handle,enum PP_SMC_POWER_PROFILE type,bool en)886b843c749SSergey Zigachev static int pp_dpm_switch_power_profile(void *handle,
887b843c749SSergey Zigachev 		enum PP_SMC_POWER_PROFILE type, bool en)
888b843c749SSergey Zigachev {
889b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
890b843c749SSergey Zigachev 	long workload;
891b843c749SSergey Zigachev 	uint32_t index;
892b843c749SSergey Zigachev 
893b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
894b843c749SSergey Zigachev 		return -EINVAL;
895b843c749SSergey Zigachev 
896b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) {
897b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
898b843c749SSergey Zigachev 		return -EINVAL;
899b843c749SSergey Zigachev 	}
900b843c749SSergey Zigachev 
901b843c749SSergey Zigachev 	if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
902b843c749SSergey Zigachev 		return -EINVAL;
903b843c749SSergey Zigachev 
904b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
905b843c749SSergey Zigachev 
906b843c749SSergey Zigachev 	if (!en) {
907b843c749SSergey Zigachev 		hwmgr->workload_mask &= ~(1 << hwmgr->workload_prority[type]);
908b843c749SSergey Zigachev 		index = fls(hwmgr->workload_mask);
909b843c749SSergey Zigachev 		index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0;
910b843c749SSergey Zigachev 		workload = hwmgr->workload_setting[index];
911b843c749SSergey Zigachev 	} else {
912b843c749SSergey Zigachev 		hwmgr->workload_mask |= (1 << hwmgr->workload_prority[type]);
913b843c749SSergey Zigachev 		index = fls(hwmgr->workload_mask);
914b843c749SSergey Zigachev 		index = index <= Workload_Policy_Max ? index - 1 : 0;
915b843c749SSergey Zigachev 		workload = hwmgr->workload_setting[index];
916b843c749SSergey Zigachev 	}
917b843c749SSergey Zigachev 
918b843c749SSergey Zigachev 	if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
919b843c749SSergey Zigachev 		hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0);
920b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
921b843c749SSergey Zigachev 
922b843c749SSergey Zigachev 	return 0;
923b843c749SSergey Zigachev }
924b843c749SSergey Zigachev 
pp_set_power_limit(void * handle,uint32_t limit)925b843c749SSergey Zigachev static int pp_set_power_limit(void *handle, uint32_t limit)
926b843c749SSergey Zigachev {
927b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
928b843c749SSergey Zigachev 
929b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
930b843c749SSergey Zigachev 		return -EINVAL;
931b843c749SSergey Zigachev 
932b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->set_power_limit == NULL) {
933b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
934b843c749SSergey Zigachev 		return -EINVAL;
935b843c749SSergey Zigachev 	}
936b843c749SSergey Zigachev 
937b843c749SSergey Zigachev 	if (limit == 0)
938b843c749SSergey Zigachev 		limit = hwmgr->default_power_limit;
939b843c749SSergey Zigachev 
940b843c749SSergey Zigachev 	if (limit > hwmgr->default_power_limit)
941b843c749SSergey Zigachev 		return -EINVAL;
942b843c749SSergey Zigachev 
943b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
944b843c749SSergey Zigachev 	hwmgr->hwmgr_func->set_power_limit(hwmgr, limit);
945b843c749SSergey Zigachev 	hwmgr->power_limit = limit;
946b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
947b843c749SSergey Zigachev 	return 0;
948b843c749SSergey Zigachev }
949b843c749SSergey Zigachev 
pp_get_power_limit(void * handle,uint32_t * limit,bool default_limit)950b843c749SSergey Zigachev static int pp_get_power_limit(void *handle, uint32_t *limit, bool default_limit)
951b843c749SSergey Zigachev {
952b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
953b843c749SSergey Zigachev 
954b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!limit)
955b843c749SSergey Zigachev 		return -EINVAL;
956b843c749SSergey Zigachev 
957b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
958b843c749SSergey Zigachev 
959b843c749SSergey Zigachev 	if (default_limit)
960b843c749SSergey Zigachev 		*limit = hwmgr->default_power_limit;
961b843c749SSergey Zigachev 	else
962b843c749SSergey Zigachev 		*limit = hwmgr->power_limit;
963b843c749SSergey Zigachev 
964b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
965b843c749SSergey Zigachev 
966b843c749SSergey Zigachev 	return 0;
967b843c749SSergey Zigachev }
968b843c749SSergey Zigachev 
pp_display_configuration_change(void * handle,const struct amd_pp_display_configuration * display_config)969b843c749SSergey Zigachev static int pp_display_configuration_change(void *handle,
970b843c749SSergey Zigachev 	const struct amd_pp_display_configuration *display_config)
971b843c749SSergey Zigachev {
972b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
973b843c749SSergey Zigachev 
974b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
975b843c749SSergey Zigachev 		return -EINVAL;
976b843c749SSergey Zigachev 
977b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
978b843c749SSergey Zigachev 	phm_store_dal_configuration_data(hwmgr, display_config);
979b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
980b843c749SSergey Zigachev 	return 0;
981b843c749SSergey Zigachev }
982b843c749SSergey Zigachev 
pp_get_display_power_level(void * handle,struct amd_pp_simple_clock_info * output)983b843c749SSergey Zigachev static int pp_get_display_power_level(void *handle,
984b843c749SSergey Zigachev 		struct amd_pp_simple_clock_info *output)
985b843c749SSergey Zigachev {
986b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
987b843c749SSergey Zigachev 	int ret = 0;
988b843c749SSergey Zigachev 
989b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!output)
990b843c749SSergey Zigachev 		return -EINVAL;
991b843c749SSergey Zigachev 
992b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
993b843c749SSergey Zigachev 	ret = phm_get_dal_power_level(hwmgr, output);
994b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
995b843c749SSergey Zigachev 	return ret;
996b843c749SSergey Zigachev }
997b843c749SSergey Zigachev 
pp_get_current_clocks(void * handle,struct amd_pp_clock_info * clocks)998b843c749SSergey Zigachev static int pp_get_current_clocks(void *handle,
999b843c749SSergey Zigachev 		struct amd_pp_clock_info *clocks)
1000b843c749SSergey Zigachev {
1001b843c749SSergey Zigachev 	struct amd_pp_simple_clock_info simple_clocks = { 0 };
1002b843c749SSergey Zigachev 	struct pp_clock_info hw_clocks;
1003b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1004b843c749SSergey Zigachev 	int ret = 0;
1005b843c749SSergey Zigachev 
1006b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
1007b843c749SSergey Zigachev 		return -EINVAL;
1008b843c749SSergey Zigachev 
1009b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1010b843c749SSergey Zigachev 
1011b843c749SSergey Zigachev 	phm_get_dal_power_level(hwmgr, &simple_clocks);
1012b843c749SSergey Zigachev 
1013b843c749SSergey Zigachev 	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1014b843c749SSergey Zigachev 					PHM_PlatformCaps_PowerContainment))
1015b843c749SSergey Zigachev 		ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
1016b843c749SSergey Zigachev 					&hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment);
1017b843c749SSergey Zigachev 	else
1018b843c749SSergey Zigachev 		ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
1019b843c749SSergey Zigachev 					&hw_clocks, PHM_PerformanceLevelDesignation_Activity);
1020b843c749SSergey Zigachev 
1021b843c749SSergey Zigachev 	if (ret) {
1022b843c749SSergey Zigachev 		pr_info("Error in phm_get_clock_info \n");
1023b843c749SSergey Zigachev 		mutex_unlock(&hwmgr->smu_lock);
1024b843c749SSergey Zigachev 		return -EINVAL;
1025b843c749SSergey Zigachev 	}
1026b843c749SSergey Zigachev 
1027b843c749SSergey Zigachev 	clocks->min_engine_clock = hw_clocks.min_eng_clk;
1028b843c749SSergey Zigachev 	clocks->max_engine_clock = hw_clocks.max_eng_clk;
1029b843c749SSergey Zigachev 	clocks->min_memory_clock = hw_clocks.min_mem_clk;
1030b843c749SSergey Zigachev 	clocks->max_memory_clock = hw_clocks.max_mem_clk;
1031b843c749SSergey Zigachev 	clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth;
1032b843c749SSergey Zigachev 	clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth;
1033b843c749SSergey Zigachev 
1034b843c749SSergey Zigachev 	clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
1035b843c749SSergey Zigachev 	clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
1036b843c749SSergey Zigachev 
1037b843c749SSergey Zigachev 	if (simple_clocks.level == 0)
1038b843c749SSergey Zigachev 		clocks->max_clocks_state = PP_DAL_POWERLEVEL_7;
1039b843c749SSergey Zigachev 	else
1040b843c749SSergey Zigachev 		clocks->max_clocks_state = simple_clocks.level;
1041b843c749SSergey Zigachev 
1042b843c749SSergey Zigachev 	if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
1043b843c749SSergey Zigachev 		clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
1044b843c749SSergey Zigachev 		clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
1045b843c749SSergey Zigachev 	}
1046b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1047b843c749SSergey Zigachev 	return 0;
1048b843c749SSergey Zigachev }
1049b843c749SSergey Zigachev 
pp_get_clock_by_type(void * handle,enum amd_pp_clock_type type,struct amd_pp_clocks * clocks)1050b843c749SSergey Zigachev static int pp_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
1051b843c749SSergey Zigachev {
1052b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1053b843c749SSergey Zigachev 	int ret = 0;
1054b843c749SSergey Zigachev 
1055b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
1056b843c749SSergey Zigachev 		return -EINVAL;
1057b843c749SSergey Zigachev 
1058b843c749SSergey Zigachev 	if (clocks == NULL)
1059b843c749SSergey Zigachev 		return -EINVAL;
1060b843c749SSergey Zigachev 
1061b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1062b843c749SSergey Zigachev 	ret = phm_get_clock_by_type(hwmgr, type, clocks);
1063b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1064b843c749SSergey Zigachev 	return ret;
1065b843c749SSergey Zigachev }
1066b843c749SSergey Zigachev 
pp_get_clock_by_type_with_latency(void * handle,enum amd_pp_clock_type type,struct pp_clock_levels_with_latency * clocks)1067b843c749SSergey Zigachev static int pp_get_clock_by_type_with_latency(void *handle,
1068b843c749SSergey Zigachev 		enum amd_pp_clock_type type,
1069b843c749SSergey Zigachev 		struct pp_clock_levels_with_latency *clocks)
1070b843c749SSergey Zigachev {
1071b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1072b843c749SSergey Zigachev 	int ret = 0;
1073b843c749SSergey Zigachev 
1074b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!clocks)
1075b843c749SSergey Zigachev 		return -EINVAL;
1076b843c749SSergey Zigachev 
1077b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1078b843c749SSergey Zigachev 	ret = phm_get_clock_by_type_with_latency(hwmgr, type, clocks);
1079b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1080b843c749SSergey Zigachev 	return ret;
1081b843c749SSergey Zigachev }
1082b843c749SSergey Zigachev 
pp_get_clock_by_type_with_voltage(void * handle,enum amd_pp_clock_type type,struct pp_clock_levels_with_voltage * clocks)1083b843c749SSergey Zigachev static int pp_get_clock_by_type_with_voltage(void *handle,
1084b843c749SSergey Zigachev 		enum amd_pp_clock_type type,
1085b843c749SSergey Zigachev 		struct pp_clock_levels_with_voltage *clocks)
1086b843c749SSergey Zigachev {
1087b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1088b843c749SSergey Zigachev 	int ret = 0;
1089b843c749SSergey Zigachev 
1090b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!clocks)
1091b843c749SSergey Zigachev 		return -EINVAL;
1092b843c749SSergey Zigachev 
1093b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1094b843c749SSergey Zigachev 
1095b843c749SSergey Zigachev 	ret = phm_get_clock_by_type_with_voltage(hwmgr, type, clocks);
1096b843c749SSergey Zigachev 
1097b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1098b843c749SSergey Zigachev 	return ret;
1099b843c749SSergey Zigachev }
1100b843c749SSergey Zigachev 
pp_set_watermarks_for_clocks_ranges(void * handle,void * clock_ranges)1101b843c749SSergey Zigachev static int pp_set_watermarks_for_clocks_ranges(void *handle,
1102b843c749SSergey Zigachev 		void *clock_ranges)
1103b843c749SSergey Zigachev {
1104b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1105b843c749SSergey Zigachev 	int ret = 0;
1106b843c749SSergey Zigachev 
1107b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en || !clock_ranges)
1108b843c749SSergey Zigachev 		return -EINVAL;
1109b843c749SSergey Zigachev 
1110b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1111b843c749SSergey Zigachev 	ret = phm_set_watermarks_for_clocks_ranges(hwmgr,
1112b843c749SSergey Zigachev 			clock_ranges);
1113b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1114b843c749SSergey Zigachev 
1115b843c749SSergey Zigachev 	return ret;
1116b843c749SSergey Zigachev }
1117b843c749SSergey Zigachev 
pp_display_clock_voltage_request(void * handle,struct pp_display_clock_request * clock)1118b843c749SSergey Zigachev static int pp_display_clock_voltage_request(void *handle,
1119b843c749SSergey Zigachev 		struct pp_display_clock_request *clock)
1120b843c749SSergey Zigachev {
1121b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1122b843c749SSergey Zigachev 	int ret = 0;
1123b843c749SSergey Zigachev 
1124b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!clock)
1125b843c749SSergey Zigachev 		return -EINVAL;
1126b843c749SSergey Zigachev 
1127b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1128b843c749SSergey Zigachev 	ret = phm_display_clock_voltage_request(hwmgr, clock);
1129b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1130b843c749SSergey Zigachev 
1131b843c749SSergey Zigachev 	return ret;
1132b843c749SSergey Zigachev }
1133b843c749SSergey Zigachev 
pp_get_display_mode_validation_clocks(void * handle,struct amd_pp_simple_clock_info * clocks)1134b843c749SSergey Zigachev static int pp_get_display_mode_validation_clocks(void *handle,
1135b843c749SSergey Zigachev 		struct amd_pp_simple_clock_info *clocks)
1136b843c749SSergey Zigachev {
1137b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1138b843c749SSergey Zigachev 	int ret = 0;
1139b843c749SSergey Zigachev 
1140b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en ||!clocks)
1141b843c749SSergey Zigachev 		return -EINVAL;
1142b843c749SSergey Zigachev 
1143b843c749SSergey Zigachev 	clocks->level = PP_DAL_POWERLEVEL_7;
1144b843c749SSergey Zigachev 
1145b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1146b843c749SSergey Zigachev 
1147b843c749SSergey Zigachev 	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
1148b843c749SSergey Zigachev 		ret = phm_get_max_high_clocks(hwmgr, clocks);
1149b843c749SSergey Zigachev 
1150b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1151b843c749SSergey Zigachev 	return ret;
1152b843c749SSergey Zigachev }
1153b843c749SSergey Zigachev 
pp_dpm_powergate_mmhub(void * handle)1154b843c749SSergey Zigachev static int pp_dpm_powergate_mmhub(void *handle)
1155b843c749SSergey Zigachev {
1156b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1157b843c749SSergey Zigachev 
1158b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
1159b843c749SSergey Zigachev 		return -EINVAL;
1160b843c749SSergey Zigachev 
1161b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->powergate_mmhub == NULL) {
1162b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
1163b843c749SSergey Zigachev 		return 0;
1164b843c749SSergey Zigachev 	}
1165b843c749SSergey Zigachev 
1166b843c749SSergey Zigachev 	return hwmgr->hwmgr_func->powergate_mmhub(hwmgr);
1167b843c749SSergey Zigachev }
1168b843c749SSergey Zigachev 
pp_dpm_powergate_gfx(void * handle,bool gate)1169b843c749SSergey Zigachev static int pp_dpm_powergate_gfx(void *handle, bool gate)
1170b843c749SSergey Zigachev {
1171b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1172b843c749SSergey Zigachev 
1173b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
1174b843c749SSergey Zigachev 		return 0;
1175b843c749SSergey Zigachev 
1176b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->powergate_gfx == NULL) {
1177b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
1178b843c749SSergey Zigachev 		return 0;
1179b843c749SSergey Zigachev 	}
1180b843c749SSergey Zigachev 
1181b843c749SSergey Zigachev 	return hwmgr->hwmgr_func->powergate_gfx(hwmgr, gate);
1182b843c749SSergey Zigachev }
1183b843c749SSergey Zigachev 
pp_set_powergating_by_smu(void * handle,uint32_t block_type,bool gate)1184b843c749SSergey Zigachev static int pp_set_powergating_by_smu(void *handle,
1185b843c749SSergey Zigachev 				uint32_t block_type, bool gate)
1186b843c749SSergey Zigachev {
1187b843c749SSergey Zigachev 	int ret = 0;
1188b843c749SSergey Zigachev 
1189b843c749SSergey Zigachev 	switch (block_type) {
1190b843c749SSergey Zigachev 	case AMD_IP_BLOCK_TYPE_UVD:
1191b843c749SSergey Zigachev 	case AMD_IP_BLOCK_TYPE_VCN:
1192b843c749SSergey Zigachev 		pp_dpm_powergate_uvd(handle, gate);
1193b843c749SSergey Zigachev 		break;
1194b843c749SSergey Zigachev 	case AMD_IP_BLOCK_TYPE_VCE:
1195b843c749SSergey Zigachev 		pp_dpm_powergate_vce(handle, gate);
1196b843c749SSergey Zigachev 		break;
1197b843c749SSergey Zigachev 	case AMD_IP_BLOCK_TYPE_GMC:
1198b843c749SSergey Zigachev 		pp_dpm_powergate_mmhub(handle);
1199b843c749SSergey Zigachev 		break;
1200b843c749SSergey Zigachev 	case AMD_IP_BLOCK_TYPE_GFX:
1201b843c749SSergey Zigachev 		ret = pp_dpm_powergate_gfx(handle, gate);
1202b843c749SSergey Zigachev 		break;
1203b843c749SSergey Zigachev 	default:
1204b843c749SSergey Zigachev 		break;
1205b843c749SSergey Zigachev 	}
1206b843c749SSergey Zigachev 	return ret;
1207b843c749SSergey Zigachev }
1208b843c749SSergey Zigachev 
pp_notify_smu_enable_pwe(void * handle)1209b843c749SSergey Zigachev static int pp_notify_smu_enable_pwe(void *handle)
1210b843c749SSergey Zigachev {
1211b843c749SSergey Zigachev 	struct pp_hwmgr *hwmgr = handle;
1212b843c749SSergey Zigachev 
1213b843c749SSergey Zigachev 	if (!hwmgr || !hwmgr->pm_en)
1214b843c749SSergey Zigachev 		return -EINVAL;
1215b843c749SSergey Zigachev 
1216b843c749SSergey Zigachev 	if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) {
1217b843c749SSergey Zigachev 		pr_info("%s was not implemented.\n", __func__);
1218b843c749SSergey Zigachev 		return -EINVAL;;
1219b843c749SSergey Zigachev 	}
1220b843c749SSergey Zigachev 
1221b843c749SSergey Zigachev 	mutex_lock(&hwmgr->smu_lock);
1222b843c749SSergey Zigachev 	hwmgr->hwmgr_func->smus_notify_pwe(hwmgr);
1223b843c749SSergey Zigachev 	mutex_unlock(&hwmgr->smu_lock);
1224b843c749SSergey Zigachev 
1225b843c749SSergey Zigachev 	return 0;
1226b843c749SSergey Zigachev }
1227b843c749SSergey Zigachev 
1228b843c749SSergey Zigachev static const struct amd_pm_funcs pp_dpm_funcs = {
1229b843c749SSergey Zigachev 	.load_firmware = pp_dpm_load_fw,
1230b843c749SSergey Zigachev 	.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
1231b843c749SSergey Zigachev 	.force_performance_level = pp_dpm_force_performance_level,
1232b843c749SSergey Zigachev 	.get_performance_level = pp_dpm_get_performance_level,
1233b843c749SSergey Zigachev 	.get_current_power_state = pp_dpm_get_current_power_state,
1234b843c749SSergey Zigachev 	.dispatch_tasks = pp_dpm_dispatch_tasks,
1235b843c749SSergey Zigachev 	.set_fan_control_mode = pp_dpm_set_fan_control_mode,
1236b843c749SSergey Zigachev 	.get_fan_control_mode = pp_dpm_get_fan_control_mode,
1237b843c749SSergey Zigachev 	.set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
1238b843c749SSergey Zigachev 	.get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
1239b843c749SSergey Zigachev 	.get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm,
1240b843c749SSergey Zigachev 	.get_pp_num_states = pp_dpm_get_pp_num_states,
1241b843c749SSergey Zigachev 	.get_pp_table = pp_dpm_get_pp_table,
1242b843c749SSergey Zigachev 	.set_pp_table = pp_dpm_set_pp_table,
1243b843c749SSergey Zigachev 	.force_clock_level = pp_dpm_force_clock_level,
1244b843c749SSergey Zigachev 	.print_clock_levels = pp_dpm_print_clock_levels,
1245b843c749SSergey Zigachev 	.get_sclk_od = pp_dpm_get_sclk_od,
1246b843c749SSergey Zigachev 	.set_sclk_od = pp_dpm_set_sclk_od,
1247b843c749SSergey Zigachev 	.get_mclk_od = pp_dpm_get_mclk_od,
1248b843c749SSergey Zigachev 	.set_mclk_od = pp_dpm_set_mclk_od,
1249b843c749SSergey Zigachev 	.read_sensor = pp_dpm_read_sensor,
1250b843c749SSergey Zigachev 	.get_vce_clock_state = pp_dpm_get_vce_clock_state,
1251b843c749SSergey Zigachev 	.switch_power_profile = pp_dpm_switch_power_profile,
1252b843c749SSergey Zigachev 	.set_clockgating_by_smu = pp_set_clockgating_by_smu,
1253b843c749SSergey Zigachev 	.set_powergating_by_smu = pp_set_powergating_by_smu,
1254b843c749SSergey Zigachev 	.get_power_profile_mode = pp_get_power_profile_mode,
1255b843c749SSergey Zigachev 	.set_power_profile_mode = pp_set_power_profile_mode,
1256b843c749SSergey Zigachev 	.odn_edit_dpm_table = pp_odn_edit_dpm_table,
1257b843c749SSergey Zigachev 	.set_power_limit = pp_set_power_limit,
1258b843c749SSergey Zigachev 	.get_power_limit = pp_get_power_limit,
1259b843c749SSergey Zigachev /* export to DC */
1260b843c749SSergey Zigachev 	.get_sclk = pp_dpm_get_sclk,
1261b843c749SSergey Zigachev 	.get_mclk = pp_dpm_get_mclk,
1262b843c749SSergey Zigachev 	.display_configuration_change = pp_display_configuration_change,
1263b843c749SSergey Zigachev 	.get_display_power_level = pp_get_display_power_level,
1264b843c749SSergey Zigachev 	.get_current_clocks = pp_get_current_clocks,
1265b843c749SSergey Zigachev 	.get_clock_by_type = pp_get_clock_by_type,
1266b843c749SSergey Zigachev 	.get_clock_by_type_with_latency = pp_get_clock_by_type_with_latency,
1267b843c749SSergey Zigachev 	.get_clock_by_type_with_voltage = pp_get_clock_by_type_with_voltage,
1268b843c749SSergey Zigachev 	.set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges,
1269b843c749SSergey Zigachev 	.display_clock_voltage_request = pp_display_clock_voltage_request,
1270b843c749SSergey Zigachev 	.get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks,
1271b843c749SSergey Zigachev 	.notify_smu_enable_pwe = pp_notify_smu_enable_pwe,
1272b843c749SSergey Zigachev };
1273