xref: /openbmc/linux/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c (revision ac8f933664c3a0e2d42f6ee9a2a6d25f87cb23f6)
1e098bc96SEvan Quan /*
2e098bc96SEvan Quan  * Copyright 2015 Advanced Micro Devices, Inc.
3e098bc96SEvan Quan  *
4e098bc96SEvan Quan  * Permission is hereby granted, free of charge, to any person obtaining a
5e098bc96SEvan Quan  * copy of this software and associated documentation files (the "Software"),
6e098bc96SEvan Quan  * to deal in the Software without restriction, including without limitation
7e098bc96SEvan Quan  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e098bc96SEvan Quan  * and/or sell copies of the Software, and to permit persons to whom the
9e098bc96SEvan Quan  * Software is furnished to do so, subject to the following conditions:
10e098bc96SEvan Quan  *
11e098bc96SEvan Quan  * The above copyright notice and this permission notice shall be included in
12e098bc96SEvan Quan  * all copies or substantial portions of the Software.
13e098bc96SEvan Quan  *
14e098bc96SEvan Quan  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e098bc96SEvan Quan  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e098bc96SEvan Quan  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17e098bc96SEvan Quan  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18e098bc96SEvan Quan  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19e098bc96SEvan Quan  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20e098bc96SEvan Quan  * OTHER DEALINGS IN THE SOFTWARE.
21e098bc96SEvan Quan  *
22e098bc96SEvan Quan  */
23e098bc96SEvan Quan #include "pp_debug.h"
24e098bc96SEvan Quan #include <linux/types.h>
25e098bc96SEvan Quan #include <linux/kernel.h>
26e098bc96SEvan Quan #include <linux/gfp.h>
27e098bc96SEvan Quan #include <linux/slab.h>
28e098bc96SEvan Quan #include <linux/firmware.h>
29b75efe88SEvan Quan #include <linux/reboot.h>
30e098bc96SEvan Quan #include "amd_shared.h"
31e098bc96SEvan Quan #include "amd_powerplay.h"
32e098bc96SEvan Quan #include "power_state.h"
33e098bc96SEvan Quan #include "amdgpu.h"
34e098bc96SEvan Quan #include "hwmgr.h"
356ddbd37fSEvan Quan #include "amdgpu_dpm_internal.h"
366ddbd37fSEvan Quan #include "amdgpu_display.h"
37e098bc96SEvan Quan 
38e098bc96SEvan Quan static const struct amd_pm_funcs pp_dpm_funcs;
39e098bc96SEvan Quan 
amd_powerplay_create(struct amdgpu_device * adev)40e098bc96SEvan Quan static int amd_powerplay_create(struct amdgpu_device *adev)
41e098bc96SEvan Quan {
42e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr;
43e098bc96SEvan Quan 
44e098bc96SEvan Quan 	if (adev == NULL)
45e098bc96SEvan Quan 		return -EINVAL;
46e098bc96SEvan Quan 
47e098bc96SEvan Quan 	hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
48e098bc96SEvan Quan 	if (hwmgr == NULL)
49e098bc96SEvan Quan 		return -ENOMEM;
50e098bc96SEvan Quan 
51e098bc96SEvan Quan 	hwmgr->adev = adev;
52e098bc96SEvan Quan 	hwmgr->not_vf = !amdgpu_sriov_vf(adev);
53e098bc96SEvan Quan 	hwmgr->device = amdgpu_cgs_create_device(adev);
54e098bc96SEvan Quan 	mutex_init(&hwmgr->msg_lock);
55e098bc96SEvan Quan 	hwmgr->chip_family = adev->family;
56e098bc96SEvan Quan 	hwmgr->chip_id = adev->asic_type;
57e098bc96SEvan Quan 	hwmgr->feature_mask = adev->pm.pp_feature;
58e098bc96SEvan Quan 	hwmgr->display_config = &adev->pm.pm_display_cfg;
59e098bc96SEvan Quan 	adev->powerplay.pp_handle = hwmgr;
60e098bc96SEvan Quan 	adev->powerplay.pp_funcs = &pp_dpm_funcs;
61e098bc96SEvan Quan 	return 0;
62e098bc96SEvan Quan }
63e098bc96SEvan Quan 
64e098bc96SEvan Quan 
amd_powerplay_destroy(struct amdgpu_device * adev)65e098bc96SEvan Quan static void amd_powerplay_destroy(struct amdgpu_device *adev)
66e098bc96SEvan Quan {
67e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
68e098bc96SEvan Quan 
69e098bc96SEvan Quan 	mutex_destroy(&hwmgr->msg_lock);
70e098bc96SEvan Quan 
71e098bc96SEvan Quan 	kfree(hwmgr->hardcode_pp_table);
72e098bc96SEvan Quan 	hwmgr->hardcode_pp_table = NULL;
73e098bc96SEvan Quan 
74e098bc96SEvan Quan 	kfree(hwmgr);
75e098bc96SEvan Quan 	hwmgr = NULL;
76e098bc96SEvan Quan }
77e098bc96SEvan Quan 
pp_early_init(void * handle)78e098bc96SEvan Quan static int pp_early_init(void *handle)
79e098bc96SEvan Quan {
80e098bc96SEvan Quan 	int ret;
81e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
82e098bc96SEvan Quan 
83e098bc96SEvan Quan 	ret = amd_powerplay_create(adev);
84e098bc96SEvan Quan 
85e098bc96SEvan Quan 	if (ret != 0)
86e098bc96SEvan Quan 		return ret;
87e098bc96SEvan Quan 
88e098bc96SEvan Quan 	ret = hwmgr_early_init(adev->powerplay.pp_handle);
89e098bc96SEvan Quan 	if (ret)
90e098bc96SEvan Quan 		return -EINVAL;
91e098bc96SEvan Quan 
92e098bc96SEvan Quan 	return 0;
93e098bc96SEvan Quan }
94e098bc96SEvan Quan 
pp_swctf_delayed_work_handler(struct work_struct * work)95b75efe88SEvan Quan static void pp_swctf_delayed_work_handler(struct work_struct *work)
96b75efe88SEvan Quan {
97b75efe88SEvan Quan 	struct pp_hwmgr *hwmgr =
98b75efe88SEvan Quan 		container_of(work, struct pp_hwmgr, swctf_delayed_work.work);
99b75efe88SEvan Quan 	struct amdgpu_device *adev = hwmgr->adev;
100b75efe88SEvan Quan 	struct amdgpu_dpm_thermal *range =
101b75efe88SEvan Quan 				&adev->pm.dpm.thermal;
102*fc0cb02eSJesse Zhang 	uint32_t gpu_temperature, size = sizeof(gpu_temperature);
103b75efe88SEvan Quan 	int ret;
104b75efe88SEvan Quan 
105b75efe88SEvan Quan 	/*
106b75efe88SEvan Quan 	 * If the hotspot/edge temperature is confirmed as below SW CTF setting point
107b75efe88SEvan Quan 	 * after the delay enforced, nothing will be done.
108b75efe88SEvan Quan 	 * Otherwise, a graceful shutdown will be performed to prevent further damage.
109b75efe88SEvan Quan 	 */
110b75efe88SEvan Quan 	if (range->sw_ctf_threshold &&
111b75efe88SEvan Quan 	    hwmgr->hwmgr_func->read_sensor) {
112b75efe88SEvan Quan 		ret = hwmgr->hwmgr_func->read_sensor(hwmgr,
113b75efe88SEvan Quan 						     AMDGPU_PP_SENSOR_HOTSPOT_TEMP,
114b75efe88SEvan Quan 						     &gpu_temperature,
115b75efe88SEvan Quan 						     &size);
116b75efe88SEvan Quan 		/*
117b75efe88SEvan Quan 		 * For some legacy ASICs, hotspot temperature retrieving might be not
118b75efe88SEvan Quan 		 * supported. Check the edge temperature instead then.
119b75efe88SEvan Quan 		 */
120b75efe88SEvan Quan 		if (ret == -EOPNOTSUPP)
121b75efe88SEvan Quan 			ret = hwmgr->hwmgr_func->read_sensor(hwmgr,
122b75efe88SEvan Quan 							     AMDGPU_PP_SENSOR_EDGE_TEMP,
123b75efe88SEvan Quan 							     &gpu_temperature,
124b75efe88SEvan Quan 							     &size);
125b75efe88SEvan Quan 		if (!ret && gpu_temperature / 1000 < range->sw_ctf_threshold)
126b75efe88SEvan Quan 			return;
127b75efe88SEvan Quan 	}
128b75efe88SEvan Quan 
129b75efe88SEvan Quan 	dev_emerg(adev->dev, "ERROR: GPU over temperature range(SW CTF) detected!\n");
130b75efe88SEvan Quan 	dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU SW CTF!\n");
131b75efe88SEvan Quan 	orderly_poweroff(true);
132b75efe88SEvan Quan }
133b75efe88SEvan Quan 
pp_sw_init(void * handle)134e098bc96SEvan Quan static int pp_sw_init(void *handle)
135e098bc96SEvan Quan {
136e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
137e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
138e098bc96SEvan Quan 	int ret = 0;
139e098bc96SEvan Quan 
140e098bc96SEvan Quan 	ret = hwmgr_sw_init(hwmgr);
141e098bc96SEvan Quan 
142e098bc96SEvan Quan 	pr_debug("powerplay sw init %s\n", ret ? "failed" : "successfully");
143e098bc96SEvan Quan 
144b75efe88SEvan Quan 	if (!ret)
145b75efe88SEvan Quan 		INIT_DELAYED_WORK(&hwmgr->swctf_delayed_work,
146b75efe88SEvan Quan 				  pp_swctf_delayed_work_handler);
147b75efe88SEvan Quan 
148e098bc96SEvan Quan 	return ret;
149e098bc96SEvan Quan }
150e098bc96SEvan Quan 
pp_sw_fini(void * handle)151e098bc96SEvan Quan static int pp_sw_fini(void *handle)
152e098bc96SEvan Quan {
153e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
154e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
155e098bc96SEvan Quan 
156e098bc96SEvan Quan 	hwmgr_sw_fini(hwmgr);
157e098bc96SEvan Quan 
158778af666SMario Limonciello 	amdgpu_ucode_release(&adev->pm.fw);
159e098bc96SEvan Quan 
160e098bc96SEvan Quan 	return 0;
161e098bc96SEvan Quan }
162e098bc96SEvan Quan 
pp_hw_init(void * handle)163e098bc96SEvan Quan static int pp_hw_init(void *handle)
164e098bc96SEvan Quan {
165e098bc96SEvan Quan 	int ret = 0;
166e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
167e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
168e098bc96SEvan Quan 
169e098bc96SEvan Quan 	ret = hwmgr_hw_init(hwmgr);
170e098bc96SEvan Quan 
171e098bc96SEvan Quan 	if (ret)
172e098bc96SEvan Quan 		pr_err("powerplay hw init failed\n");
173e098bc96SEvan Quan 
174e098bc96SEvan Quan 	return ret;
175e098bc96SEvan Quan }
176e098bc96SEvan Quan 
pp_hw_fini(void * handle)177e098bc96SEvan Quan static int pp_hw_fini(void *handle)
178e098bc96SEvan Quan {
179e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
180e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
181e098bc96SEvan Quan 
182b75efe88SEvan Quan 	cancel_delayed_work_sync(&hwmgr->swctf_delayed_work);
183b75efe88SEvan Quan 
184e098bc96SEvan Quan 	hwmgr_hw_fini(hwmgr);
185e098bc96SEvan Quan 
186e098bc96SEvan Quan 	return 0;
187e098bc96SEvan Quan }
188e098bc96SEvan Quan 
pp_reserve_vram_for_smu(struct amdgpu_device * adev)189e098bc96SEvan Quan static void pp_reserve_vram_for_smu(struct amdgpu_device *adev)
190e098bc96SEvan Quan {
191e098bc96SEvan Quan 	int r = -EINVAL;
192e098bc96SEvan Quan 	void *cpu_ptr = NULL;
193e098bc96SEvan Quan 	uint64_t gpu_addr;
194e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
195e098bc96SEvan Quan 
196e098bc96SEvan Quan 	if (amdgpu_bo_create_kernel(adev, adev->pm.smu_prv_buffer_size,
197e098bc96SEvan Quan 						PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
198e098bc96SEvan Quan 						&adev->pm.smu_prv_buffer,
199e098bc96SEvan Quan 						&gpu_addr,
200e098bc96SEvan Quan 						&cpu_ptr)) {
201e098bc96SEvan Quan 		DRM_ERROR("amdgpu: failed to create smu prv buffer\n");
202e098bc96SEvan Quan 		return;
203e098bc96SEvan Quan 	}
204e098bc96SEvan Quan 
205e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->notify_cac_buffer_info)
206e098bc96SEvan Quan 		r = hwmgr->hwmgr_func->notify_cac_buffer_info(hwmgr,
207e098bc96SEvan Quan 					lower_32_bits((unsigned long)cpu_ptr),
208e098bc96SEvan Quan 					upper_32_bits((unsigned long)cpu_ptr),
209e098bc96SEvan Quan 					lower_32_bits(gpu_addr),
210e098bc96SEvan Quan 					upper_32_bits(gpu_addr),
211e098bc96SEvan Quan 					adev->pm.smu_prv_buffer_size);
212e098bc96SEvan Quan 
213e098bc96SEvan Quan 	if (r) {
214e098bc96SEvan Quan 		amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL);
215e098bc96SEvan Quan 		adev->pm.smu_prv_buffer = NULL;
216e098bc96SEvan Quan 		DRM_ERROR("amdgpu: failed to notify SMU buffer address\n");
217e098bc96SEvan Quan 	}
218e098bc96SEvan Quan }
219e098bc96SEvan Quan 
pp_late_init(void * handle)220e098bc96SEvan Quan static int pp_late_init(void *handle)
221e098bc96SEvan Quan {
222e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
223e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
224e098bc96SEvan Quan 
225a746c77eSEvan Quan 	if (hwmgr && hwmgr->pm_en)
226e098bc96SEvan Quan 		hwmgr_handle_task(hwmgr,
227e098bc96SEvan Quan 					AMD_PP_TASK_COMPLETE_INIT, NULL);
228e098bc96SEvan Quan 	if (adev->pm.smu_prv_buffer_size != 0)
229e098bc96SEvan Quan 		pp_reserve_vram_for_smu(adev);
230e098bc96SEvan Quan 
231e098bc96SEvan Quan 	return 0;
232e098bc96SEvan Quan }
233e098bc96SEvan Quan 
pp_late_fini(void * handle)234e098bc96SEvan Quan static void pp_late_fini(void *handle)
235e098bc96SEvan Quan {
236e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
237e098bc96SEvan Quan 
238e098bc96SEvan Quan 	if (adev->pm.smu_prv_buffer)
239e098bc96SEvan Quan 		amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL);
240e098bc96SEvan Quan 	amd_powerplay_destroy(adev);
241e098bc96SEvan Quan }
242e098bc96SEvan Quan 
243e098bc96SEvan Quan 
pp_is_idle(void * handle)244e098bc96SEvan Quan static bool pp_is_idle(void *handle)
245e098bc96SEvan Quan {
246e098bc96SEvan Quan 	return false;
247e098bc96SEvan Quan }
248e098bc96SEvan Quan 
pp_wait_for_idle(void * handle)249e098bc96SEvan Quan static int pp_wait_for_idle(void *handle)
250e098bc96SEvan Quan {
251e098bc96SEvan Quan 	return 0;
252e098bc96SEvan Quan }
253e098bc96SEvan Quan 
pp_sw_reset(void * handle)254e098bc96SEvan Quan static int pp_sw_reset(void *handle)
255e098bc96SEvan Quan {
256e098bc96SEvan Quan 	return 0;
257e098bc96SEvan Quan }
258e098bc96SEvan Quan 
pp_set_powergating_state(void * handle,enum amd_powergating_state state)259e098bc96SEvan Quan static int pp_set_powergating_state(void *handle,
260e098bc96SEvan Quan 				    enum amd_powergating_state state)
261e098bc96SEvan Quan {
262e098bc96SEvan Quan 	return 0;
263e098bc96SEvan Quan }
264e098bc96SEvan Quan 
pp_suspend(void * handle)265e098bc96SEvan Quan static int pp_suspend(void *handle)
266e098bc96SEvan Quan {
267e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
268e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
269e098bc96SEvan Quan 
270b75efe88SEvan Quan 	cancel_delayed_work_sync(&hwmgr->swctf_delayed_work);
271b75efe88SEvan Quan 
272e098bc96SEvan Quan 	return hwmgr_suspend(hwmgr);
273e098bc96SEvan Quan }
274e098bc96SEvan Quan 
pp_resume(void * handle)275e098bc96SEvan Quan static int pp_resume(void *handle)
276e098bc96SEvan Quan {
277e098bc96SEvan Quan 	struct amdgpu_device *adev = handle;
278e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
279e098bc96SEvan Quan 
280e098bc96SEvan Quan 	return hwmgr_resume(hwmgr);
281e098bc96SEvan Quan }
282e098bc96SEvan Quan 
pp_set_clockgating_state(void * handle,enum amd_clockgating_state state)283e098bc96SEvan Quan static int pp_set_clockgating_state(void *handle,
284e098bc96SEvan Quan 					  enum amd_clockgating_state state)
285e098bc96SEvan Quan {
286e098bc96SEvan Quan 	return 0;
287e098bc96SEvan Quan }
288e098bc96SEvan Quan 
289e098bc96SEvan Quan static const struct amd_ip_funcs pp_ip_funcs = {
290e098bc96SEvan Quan 	.name = "powerplay",
291e098bc96SEvan Quan 	.early_init = pp_early_init,
292e098bc96SEvan Quan 	.late_init = pp_late_init,
293e098bc96SEvan Quan 	.sw_init = pp_sw_init,
294e098bc96SEvan Quan 	.sw_fini = pp_sw_fini,
295e098bc96SEvan Quan 	.hw_init = pp_hw_init,
296e098bc96SEvan Quan 	.hw_fini = pp_hw_fini,
297e098bc96SEvan Quan 	.late_fini = pp_late_fini,
298e098bc96SEvan Quan 	.suspend = pp_suspend,
299e098bc96SEvan Quan 	.resume = pp_resume,
300e098bc96SEvan Quan 	.is_idle = pp_is_idle,
301e098bc96SEvan Quan 	.wait_for_idle = pp_wait_for_idle,
302e098bc96SEvan Quan 	.soft_reset = pp_sw_reset,
303e098bc96SEvan Quan 	.set_clockgating_state = pp_set_clockgating_state,
304e098bc96SEvan Quan 	.set_powergating_state = pp_set_powergating_state,
305e098bc96SEvan Quan };
306e098bc96SEvan Quan 
307e098bc96SEvan Quan const struct amdgpu_ip_block_version pp_smu_ip_block =
308e098bc96SEvan Quan {
309e098bc96SEvan Quan 	.type = AMD_IP_BLOCK_TYPE_SMC,
310e098bc96SEvan Quan 	.major = 1,
311e098bc96SEvan Quan 	.minor = 0,
312e098bc96SEvan Quan 	.rev = 0,
313e098bc96SEvan Quan 	.funcs = &pp_ip_funcs,
314e098bc96SEvan Quan };
315e098bc96SEvan Quan 
316e098bc96SEvan Quan /* This interface only be supported On Vi,
317e098bc96SEvan Quan  * because only smu7/8 can help to load gfx/sdma fw,
318e098bc96SEvan Quan  * smu need to be enabled before load other ip's fw.
319e098bc96SEvan Quan  * so call start smu to load smu7 fw and other ip's fw
320e098bc96SEvan Quan  */
pp_dpm_load_fw(void * handle)321e098bc96SEvan Quan static int pp_dpm_load_fw(void *handle)
322e098bc96SEvan Quan {
323e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
324e098bc96SEvan Quan 
325e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->smumgr_funcs || !hwmgr->smumgr_funcs->start_smu)
326e098bc96SEvan Quan 		return -EINVAL;
327e098bc96SEvan Quan 
328e098bc96SEvan Quan 	if (hwmgr->smumgr_funcs->start_smu(hwmgr)) {
329e098bc96SEvan Quan 		pr_err("fw load failed\n");
330e098bc96SEvan Quan 		return -EINVAL;
331e098bc96SEvan Quan 	}
332e098bc96SEvan Quan 
333e098bc96SEvan Quan 	return 0;
334e098bc96SEvan Quan }
335e098bc96SEvan Quan 
pp_dpm_fw_loading_complete(void * handle)336e098bc96SEvan Quan static int pp_dpm_fw_loading_complete(void *handle)
337e098bc96SEvan Quan {
338e098bc96SEvan Quan 	return 0;
339e098bc96SEvan Quan }
340e098bc96SEvan Quan 
pp_set_clockgating_by_smu(void * handle,uint32_t msg_id)341e098bc96SEvan Quan static int pp_set_clockgating_by_smu(void *handle, uint32_t msg_id)
342e098bc96SEvan Quan {
343e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
344e098bc96SEvan Quan 
345e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
346e098bc96SEvan Quan 		return -EINVAL;
347e098bc96SEvan Quan 
348e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
349e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
350e098bc96SEvan Quan 		return 0;
351e098bc96SEvan Quan 	}
352e098bc96SEvan Quan 
353e098bc96SEvan Quan 	return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
354e098bc96SEvan Quan }
355e098bc96SEvan Quan 
pp_dpm_en_umd_pstate(struct pp_hwmgr * hwmgr,enum amd_dpm_forced_level * level)356e098bc96SEvan Quan static void pp_dpm_en_umd_pstate(struct pp_hwmgr  *hwmgr,
357e098bc96SEvan Quan 						enum amd_dpm_forced_level *level)
358e098bc96SEvan Quan {
359e098bc96SEvan Quan 	uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
360e098bc96SEvan Quan 					AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
361e098bc96SEvan Quan 					AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
362e098bc96SEvan Quan 					AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
363e098bc96SEvan Quan 
364e098bc96SEvan Quan 	if (!(hwmgr->dpm_level & profile_mode_mask)) {
365e098bc96SEvan Quan 		/* enter umd pstate, save current level, disable gfx cg*/
366e098bc96SEvan Quan 		if (*level & profile_mode_mask) {
367e098bc96SEvan Quan 			hwmgr->saved_dpm_level = hwmgr->dpm_level;
368e098bc96SEvan Quan 			hwmgr->en_umd_pstate = true;
369e098bc96SEvan Quan 		}
370e098bc96SEvan Quan 	} else {
371e098bc96SEvan Quan 		/* exit umd pstate, restore level, enable gfx cg*/
372e098bc96SEvan Quan 		if (!(*level & profile_mode_mask)) {
373e098bc96SEvan Quan 			if (*level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)
374e098bc96SEvan Quan 				*level = hwmgr->saved_dpm_level;
375e098bc96SEvan Quan 			hwmgr->en_umd_pstate = false;
376e098bc96SEvan Quan 		}
377e098bc96SEvan Quan 	}
378e098bc96SEvan Quan }
379e098bc96SEvan Quan 
pp_dpm_force_performance_level(void * handle,enum amd_dpm_forced_level level)380e098bc96SEvan Quan static int pp_dpm_force_performance_level(void *handle,
381e098bc96SEvan Quan 					enum amd_dpm_forced_level level)
382e098bc96SEvan Quan {
383e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
384e098bc96SEvan Quan 
385e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
386e098bc96SEvan Quan 		return -EINVAL;
387e098bc96SEvan Quan 
388e098bc96SEvan Quan 	if (level == hwmgr->dpm_level)
389e098bc96SEvan Quan 		return 0;
390e098bc96SEvan Quan 
391e098bc96SEvan Quan 	pp_dpm_en_umd_pstate(hwmgr, &level);
392e098bc96SEvan Quan 	hwmgr->request_dpm_level = level;
393e098bc96SEvan Quan 	hwmgr_handle_task(hwmgr, AMD_PP_TASK_READJUST_POWER_STATE, NULL);
394e098bc96SEvan Quan 
395e098bc96SEvan Quan 	return 0;
396e098bc96SEvan Quan }
397e098bc96SEvan Quan 
pp_dpm_get_performance_level(void * handle)398e098bc96SEvan Quan static enum amd_dpm_forced_level pp_dpm_get_performance_level(
399e098bc96SEvan Quan 								void *handle)
400e098bc96SEvan Quan {
401e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
402e098bc96SEvan Quan 
403e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
404e098bc96SEvan Quan 		return -EINVAL;
405e098bc96SEvan Quan 
406a746c77eSEvan Quan 	return hwmgr->dpm_level;
407e098bc96SEvan Quan }
408e098bc96SEvan Quan 
pp_dpm_get_sclk(void * handle,bool low)409e098bc96SEvan Quan static uint32_t pp_dpm_get_sclk(void *handle, bool low)
410e098bc96SEvan Quan {
411e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
412e098bc96SEvan Quan 
413e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
414e098bc96SEvan Quan 		return 0;
415e098bc96SEvan Quan 
416e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->get_sclk == NULL) {
417e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
418e098bc96SEvan Quan 		return 0;
419e098bc96SEvan Quan 	}
420a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
421e098bc96SEvan Quan }
422e098bc96SEvan Quan 
pp_dpm_get_mclk(void * handle,bool low)423e098bc96SEvan Quan static uint32_t pp_dpm_get_mclk(void *handle, bool low)
424e098bc96SEvan Quan {
425e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
426e098bc96SEvan Quan 
427e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
428e098bc96SEvan Quan 		return 0;
429e098bc96SEvan Quan 
430e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->get_mclk == NULL) {
431e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
432e098bc96SEvan Quan 		return 0;
433e098bc96SEvan Quan 	}
434a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
435e098bc96SEvan Quan }
436e098bc96SEvan Quan 
pp_dpm_powergate_vce(void * handle,bool gate)437e098bc96SEvan Quan static void pp_dpm_powergate_vce(void *handle, bool gate)
438e098bc96SEvan Quan {
439e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
440e098bc96SEvan Quan 
441e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
442e098bc96SEvan Quan 		return;
443e098bc96SEvan Quan 
444e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->powergate_vce == NULL) {
445e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
446e098bc96SEvan Quan 		return;
447e098bc96SEvan Quan 	}
448e098bc96SEvan Quan 	hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
449e098bc96SEvan Quan }
450e098bc96SEvan Quan 
pp_dpm_powergate_uvd(void * handle,bool gate)451e098bc96SEvan Quan static void pp_dpm_powergate_uvd(void *handle, bool gate)
452e098bc96SEvan Quan {
453e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
454e098bc96SEvan Quan 
455e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
456e098bc96SEvan Quan 		return;
457e098bc96SEvan Quan 
458e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
459e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
460e098bc96SEvan Quan 		return;
461e098bc96SEvan Quan 	}
462e098bc96SEvan Quan 	hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
463e098bc96SEvan Quan }
464e098bc96SEvan Quan 
pp_dpm_dispatch_tasks(void * handle,enum amd_pp_task task_id,enum amd_pm_state_type * user_state)465e098bc96SEvan Quan static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id,
466e098bc96SEvan Quan 		enum amd_pm_state_type *user_state)
467e098bc96SEvan Quan {
468e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
469e098bc96SEvan Quan 
470e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
471e098bc96SEvan Quan 		return -EINVAL;
472e098bc96SEvan Quan 
473a746c77eSEvan Quan 	return hwmgr_handle_task(hwmgr, task_id, user_state);
474e098bc96SEvan Quan }
475e098bc96SEvan Quan 
pp_dpm_get_current_power_state(void * handle)476e098bc96SEvan Quan static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
477e098bc96SEvan Quan {
478e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
479e098bc96SEvan Quan 	struct pp_power_state *state;
480e098bc96SEvan Quan 	enum amd_pm_state_type pm_type;
481e098bc96SEvan Quan 
482e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !hwmgr->current_ps)
483e098bc96SEvan Quan 		return -EINVAL;
484e098bc96SEvan Quan 
485e098bc96SEvan Quan 	state = hwmgr->current_ps;
486e098bc96SEvan Quan 
487e098bc96SEvan Quan 	switch (state->classification.ui_label) {
488e098bc96SEvan Quan 	case PP_StateUILabel_Battery:
489e098bc96SEvan Quan 		pm_type = POWER_STATE_TYPE_BATTERY;
490e098bc96SEvan Quan 		break;
491e098bc96SEvan Quan 	case PP_StateUILabel_Balanced:
492e098bc96SEvan Quan 		pm_type = POWER_STATE_TYPE_BALANCED;
493e098bc96SEvan Quan 		break;
494e098bc96SEvan Quan 	case PP_StateUILabel_Performance:
495e098bc96SEvan Quan 		pm_type = POWER_STATE_TYPE_PERFORMANCE;
496e098bc96SEvan Quan 		break;
497e098bc96SEvan Quan 	default:
498e098bc96SEvan Quan 		if (state->classification.flags & PP_StateClassificationFlag_Boot)
499e098bc96SEvan Quan 			pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
500e098bc96SEvan Quan 		else
501e098bc96SEvan Quan 			pm_type = POWER_STATE_TYPE_DEFAULT;
502e098bc96SEvan Quan 		break;
503e098bc96SEvan Quan 	}
504e098bc96SEvan Quan 
505e098bc96SEvan Quan 	return pm_type;
506e098bc96SEvan Quan }
507e098bc96SEvan Quan 
pp_dpm_set_fan_control_mode(void * handle,uint32_t mode)508685fae24SEvan Quan static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
509e098bc96SEvan Quan {
510e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
511e098bc96SEvan Quan 
512e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
513685fae24SEvan Quan 		return -EOPNOTSUPP;
514e098bc96SEvan Quan 
515685fae24SEvan Quan 	if (hwmgr->hwmgr_func->set_fan_control_mode == NULL)
516685fae24SEvan Quan 		return -EOPNOTSUPP;
517685fae24SEvan Quan 
518685fae24SEvan Quan 	if (mode == U32_MAX)
519685fae24SEvan Quan 		return -EINVAL;
520685fae24SEvan Quan 
521e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
522685fae24SEvan Quan 
523685fae24SEvan Quan 	return 0;
524e098bc96SEvan Quan }
525e098bc96SEvan Quan 
pp_dpm_get_fan_control_mode(void * handle,uint32_t * fan_mode)526685fae24SEvan Quan static int pp_dpm_get_fan_control_mode(void *handle, uint32_t *fan_mode)
527e098bc96SEvan Quan {
528e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
529e098bc96SEvan Quan 
530e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
531685fae24SEvan Quan 		return -EOPNOTSUPP;
532e098bc96SEvan Quan 
533685fae24SEvan Quan 	if (hwmgr->hwmgr_func->get_fan_control_mode == NULL)
534685fae24SEvan Quan 		return -EOPNOTSUPP;
535685fae24SEvan Quan 
536685fae24SEvan Quan 	if (!fan_mode)
537685fae24SEvan Quan 		return -EINVAL;
538685fae24SEvan Quan 
539685fae24SEvan Quan 	*fan_mode = hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
540685fae24SEvan Quan 	return 0;
541e098bc96SEvan Quan }
542e098bc96SEvan Quan 
pp_dpm_set_fan_speed_pwm(void * handle,uint32_t speed)5430d8318e1SEvan Quan static int pp_dpm_set_fan_speed_pwm(void *handle, uint32_t speed)
544e098bc96SEvan Quan {
545e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
546e098bc96SEvan Quan 
547e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
548685fae24SEvan Quan 		return -EOPNOTSUPP;
549685fae24SEvan Quan 
550685fae24SEvan Quan 	if (hwmgr->hwmgr_func->set_fan_speed_pwm == NULL)
551685fae24SEvan Quan 		return -EOPNOTSUPP;
552685fae24SEvan Quan 
553685fae24SEvan Quan 	if (speed == U32_MAX)
554e098bc96SEvan Quan 		return -EINVAL;
555e098bc96SEvan Quan 
556a746c77eSEvan Quan 	return hwmgr->hwmgr_func->set_fan_speed_pwm(hwmgr, speed);
557e098bc96SEvan Quan }
558e098bc96SEvan Quan 
pp_dpm_get_fan_speed_pwm(void * handle,uint32_t * speed)5590d8318e1SEvan Quan static int pp_dpm_get_fan_speed_pwm(void *handle, uint32_t *speed)
560e098bc96SEvan Quan {
561e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
562e098bc96SEvan Quan 
563e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
564685fae24SEvan Quan 		return -EOPNOTSUPP;
565e098bc96SEvan Quan 
566685fae24SEvan Quan 	if (hwmgr->hwmgr_func->get_fan_speed_pwm == NULL)
567685fae24SEvan Quan 		return -EOPNOTSUPP;
568685fae24SEvan Quan 
569685fae24SEvan Quan 	if (!speed)
570685fae24SEvan Quan 		return -EINVAL;
571e098bc96SEvan Quan 
572a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_fan_speed_pwm(hwmgr, speed);
573e098bc96SEvan Quan }
574e098bc96SEvan Quan 
pp_dpm_get_fan_speed_rpm(void * handle,uint32_t * rpm)575e098bc96SEvan Quan static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
576e098bc96SEvan Quan {
577e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
578e098bc96SEvan Quan 
579e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
580685fae24SEvan Quan 		return -EOPNOTSUPP;
581e098bc96SEvan Quan 
582e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->get_fan_speed_rpm == NULL)
583685fae24SEvan Quan 		return -EOPNOTSUPP;
584685fae24SEvan Quan 
585685fae24SEvan Quan 	if (!rpm)
586e098bc96SEvan Quan 		return -EINVAL;
587e098bc96SEvan Quan 
588a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_fan_speed_rpm(hwmgr, rpm);
589e098bc96SEvan Quan }
590e098bc96SEvan Quan 
pp_dpm_set_fan_speed_rpm(void * handle,uint32_t rpm)591e098bc96SEvan Quan static int pp_dpm_set_fan_speed_rpm(void *handle, uint32_t rpm)
592e098bc96SEvan Quan {
593e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
594e098bc96SEvan Quan 
595e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
596685fae24SEvan Quan 		return -EOPNOTSUPP;
597685fae24SEvan Quan 
598685fae24SEvan Quan 	if (hwmgr->hwmgr_func->set_fan_speed_rpm == NULL)
599685fae24SEvan Quan 		return -EOPNOTSUPP;
600685fae24SEvan Quan 
601685fae24SEvan Quan 	if (rpm == U32_MAX)
602e098bc96SEvan Quan 		return -EINVAL;
603e098bc96SEvan Quan 
604a746c77eSEvan Quan 	return hwmgr->hwmgr_func->set_fan_speed_rpm(hwmgr, rpm);
605e098bc96SEvan Quan }
606e098bc96SEvan Quan 
pp_dpm_get_pp_num_states(void * handle,struct pp_states_info * data)607e098bc96SEvan Quan static int pp_dpm_get_pp_num_states(void *handle,
608e098bc96SEvan Quan 		struct pp_states_info *data)
609e098bc96SEvan Quan {
610e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
611e098bc96SEvan Quan 	int i;
612e098bc96SEvan Quan 
613e098bc96SEvan Quan 	memset(data, 0, sizeof(*data));
614e098bc96SEvan Quan 
615e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !hwmgr->ps)
616e098bc96SEvan Quan 		return -EINVAL;
617e098bc96SEvan Quan 
618e098bc96SEvan Quan 	data->nums = hwmgr->num_ps;
619e098bc96SEvan Quan 
620e098bc96SEvan Quan 	for (i = 0; i < hwmgr->num_ps; i++) {
621e098bc96SEvan Quan 		struct pp_power_state *state = (struct pp_power_state *)
622e098bc96SEvan Quan 				((unsigned long)hwmgr->ps + i * hwmgr->ps_size);
623e098bc96SEvan Quan 		switch (state->classification.ui_label) {
624e098bc96SEvan Quan 		case PP_StateUILabel_Battery:
625e098bc96SEvan Quan 			data->states[i] = POWER_STATE_TYPE_BATTERY;
626e098bc96SEvan Quan 			break;
627e098bc96SEvan Quan 		case PP_StateUILabel_Balanced:
628e098bc96SEvan Quan 			data->states[i] = POWER_STATE_TYPE_BALANCED;
629e098bc96SEvan Quan 			break;
630e098bc96SEvan Quan 		case PP_StateUILabel_Performance:
631e098bc96SEvan Quan 			data->states[i] = POWER_STATE_TYPE_PERFORMANCE;
632e098bc96SEvan Quan 			break;
633e098bc96SEvan Quan 		default:
634e098bc96SEvan Quan 			if (state->classification.flags & PP_StateClassificationFlag_Boot)
635e098bc96SEvan Quan 				data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT;
636e098bc96SEvan Quan 			else
637e098bc96SEvan Quan 				data->states[i] = POWER_STATE_TYPE_DEFAULT;
638e098bc96SEvan Quan 		}
639e098bc96SEvan Quan 	}
640e098bc96SEvan Quan 	return 0;
641e098bc96SEvan Quan }
642e098bc96SEvan Quan 
pp_dpm_get_pp_table(void * handle,char ** table)643e098bc96SEvan Quan static int pp_dpm_get_pp_table(void *handle, char **table)
644e098bc96SEvan Quan {
645e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
646e098bc96SEvan Quan 
647e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !hwmgr->soft_pp_table)
648e098bc96SEvan Quan 		return -EINVAL;
649e098bc96SEvan Quan 
650e098bc96SEvan Quan 	*table = (char *)hwmgr->soft_pp_table;
651a746c77eSEvan Quan 	return hwmgr->soft_pp_table_size;
652e098bc96SEvan Quan }
653e098bc96SEvan Quan 
amd_powerplay_reset(void * handle)654e098bc96SEvan Quan static int amd_powerplay_reset(void *handle)
655e098bc96SEvan Quan {
656e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
657e098bc96SEvan Quan 	int ret;
658e098bc96SEvan Quan 
659e098bc96SEvan Quan 	ret = hwmgr_hw_fini(hwmgr);
660e098bc96SEvan Quan 	if (ret)
661e098bc96SEvan Quan 		return ret;
662e098bc96SEvan Quan 
663e098bc96SEvan Quan 	ret = hwmgr_hw_init(hwmgr);
664e098bc96SEvan Quan 	if (ret)
665e098bc96SEvan Quan 		return ret;
666e098bc96SEvan Quan 
667e098bc96SEvan Quan 	return hwmgr_handle_task(hwmgr, AMD_PP_TASK_COMPLETE_INIT, NULL);
668e098bc96SEvan Quan }
669e098bc96SEvan Quan 
pp_dpm_set_pp_table(void * handle,const char * buf,size_t size)670e098bc96SEvan Quan static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
671e098bc96SEvan Quan {
672e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
673e098bc96SEvan Quan 	int ret = -ENOMEM;
674e098bc96SEvan Quan 
675e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
676e098bc96SEvan Quan 		return -EINVAL;
677e098bc96SEvan Quan 
678e098bc96SEvan Quan 	if (!hwmgr->hardcode_pp_table) {
679e098bc96SEvan Quan 		hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
680e098bc96SEvan Quan 						   hwmgr->soft_pp_table_size,
681e098bc96SEvan Quan 						   GFP_KERNEL);
682e098bc96SEvan Quan 		if (!hwmgr->hardcode_pp_table)
683a746c77eSEvan Quan 			return ret;
684e098bc96SEvan Quan 	}
685e098bc96SEvan Quan 
686e098bc96SEvan Quan 	memcpy(hwmgr->hardcode_pp_table, buf, size);
687e098bc96SEvan Quan 
688e098bc96SEvan Quan 	hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;
689e098bc96SEvan Quan 
690e098bc96SEvan Quan 	ret = amd_powerplay_reset(handle);
691e098bc96SEvan Quan 	if (ret)
692a746c77eSEvan Quan 		return ret;
693e098bc96SEvan Quan 
694a746c77eSEvan Quan 	if (hwmgr->hwmgr_func->avfs_control)
695e098bc96SEvan Quan 		ret = hwmgr->hwmgr_func->avfs_control(hwmgr, false);
696a746c77eSEvan Quan 
697e098bc96SEvan Quan 	return ret;
698e098bc96SEvan Quan }
699e098bc96SEvan Quan 
pp_dpm_force_clock_level(void * handle,enum pp_clock_type type,uint32_t mask)700e098bc96SEvan Quan static int pp_dpm_force_clock_level(void *handle,
701e098bc96SEvan Quan 		enum pp_clock_type type, uint32_t mask)
702e098bc96SEvan Quan {
703e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
704e098bc96SEvan Quan 
705e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
706e098bc96SEvan Quan 		return -EINVAL;
707e098bc96SEvan Quan 
708e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->force_clock_level == NULL) {
709e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
710e098bc96SEvan Quan 		return 0;
711e098bc96SEvan Quan 	}
712e098bc96SEvan Quan 
713e098bc96SEvan Quan 	if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
714e098bc96SEvan Quan 		pr_debug("force clock level is for dpm manual mode only.\n");
715e098bc96SEvan Quan 		return -EINVAL;
716e098bc96SEvan Quan 	}
717e098bc96SEvan Quan 
718a746c77eSEvan Quan 	return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
719e098bc96SEvan Quan }
720e098bc96SEvan Quan 
pp_dpm_emit_clock_levels(void * handle,enum pp_clock_type type,char * buf,int * offset)7215d8539d2SDarren Powell static int pp_dpm_emit_clock_levels(void *handle,
7225d8539d2SDarren Powell 				    enum pp_clock_type type,
7235d8539d2SDarren Powell 				    char *buf,
7245d8539d2SDarren Powell 				    int *offset)
7255d8539d2SDarren Powell {
7265d8539d2SDarren Powell 	struct pp_hwmgr *hwmgr = handle;
7275d8539d2SDarren Powell 
7285d8539d2SDarren Powell 	if (!hwmgr || !hwmgr->pm_en)
7295d8539d2SDarren Powell 		return -EOPNOTSUPP;
7305d8539d2SDarren Powell 
7315d8539d2SDarren Powell 	if (!hwmgr->hwmgr_func->emit_clock_levels)
7325d8539d2SDarren Powell 		return -ENOENT;
7335d8539d2SDarren Powell 
7345d8539d2SDarren Powell 	return hwmgr->hwmgr_func->emit_clock_levels(hwmgr, type, buf, offset);
7355d8539d2SDarren Powell }
7365d8539d2SDarren Powell 
pp_dpm_print_clock_levels(void * handle,enum pp_clock_type type,char * buf)737e098bc96SEvan Quan static int pp_dpm_print_clock_levels(void *handle,
738e098bc96SEvan Quan 		enum pp_clock_type type, char *buf)
739e098bc96SEvan Quan {
740e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
741e098bc96SEvan Quan 
742e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
743e098bc96SEvan Quan 		return -EINVAL;
744e098bc96SEvan Quan 
745e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
746e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
747e098bc96SEvan Quan 		return 0;
748e098bc96SEvan Quan 	}
749a746c77eSEvan Quan 	return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
750e098bc96SEvan Quan }
751e098bc96SEvan Quan 
pp_dpm_get_sclk_od(void * handle)752e098bc96SEvan Quan static int pp_dpm_get_sclk_od(void *handle)
753e098bc96SEvan Quan {
754e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
755e098bc96SEvan Quan 
756e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
757e098bc96SEvan Quan 		return -EINVAL;
758e098bc96SEvan Quan 
759e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
760e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
761e098bc96SEvan Quan 		return 0;
762e098bc96SEvan Quan 	}
763a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_sclk_od(hwmgr);
764e098bc96SEvan Quan }
765e098bc96SEvan Quan 
pp_dpm_set_sclk_od(void * handle,uint32_t value)766e098bc96SEvan Quan static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
767e098bc96SEvan Quan {
768e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
769e098bc96SEvan Quan 
770e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
771e098bc96SEvan Quan 		return -EINVAL;
772e098bc96SEvan Quan 
773e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
774e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
775e098bc96SEvan Quan 		return 0;
776e098bc96SEvan Quan 	}
777e098bc96SEvan Quan 
778a746c77eSEvan Quan 	return hwmgr->hwmgr_func->set_sclk_od(hwmgr, value);
779e098bc96SEvan Quan }
780e098bc96SEvan Quan 
pp_dpm_get_mclk_od(void * handle)781e098bc96SEvan Quan static int pp_dpm_get_mclk_od(void *handle)
782e098bc96SEvan Quan {
783e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
784e098bc96SEvan Quan 
785e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
786e098bc96SEvan Quan 		return -EINVAL;
787e098bc96SEvan Quan 
788e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
789e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
790e098bc96SEvan Quan 		return 0;
791e098bc96SEvan Quan 	}
792a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_mclk_od(hwmgr);
793e098bc96SEvan Quan }
794e098bc96SEvan Quan 
pp_dpm_set_mclk_od(void * handle,uint32_t value)795e098bc96SEvan Quan static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
796e098bc96SEvan Quan {
797e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
798e098bc96SEvan Quan 
799e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
800e098bc96SEvan Quan 		return -EINVAL;
801e098bc96SEvan Quan 
802e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
803e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
804e098bc96SEvan Quan 		return 0;
805e098bc96SEvan Quan 	}
806a746c77eSEvan Quan 	return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
807e098bc96SEvan Quan }
808e098bc96SEvan Quan 
pp_dpm_read_sensor(void * handle,int idx,void * value,int * size)809e098bc96SEvan Quan static int pp_dpm_read_sensor(void *handle, int idx,
810e098bc96SEvan Quan 			      void *value, int *size)
811e098bc96SEvan Quan {
812e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
813e098bc96SEvan Quan 
814e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !value)
815e098bc96SEvan Quan 		return -EINVAL;
816e098bc96SEvan Quan 
817e098bc96SEvan Quan 	switch (idx) {
818e098bc96SEvan Quan 	case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK:
819b1a9557aSEvan Quan 		*((uint32_t *)value) = hwmgr->pstate_sclk * 100;
820e098bc96SEvan Quan 		return 0;
821e098bc96SEvan Quan 	case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK:
822b1a9557aSEvan Quan 		*((uint32_t *)value) = hwmgr->pstate_mclk * 100;
823b1a9557aSEvan Quan 		return 0;
824b1a9557aSEvan Quan 	case AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK:
825b1a9557aSEvan Quan 		*((uint32_t *)value) = hwmgr->pstate_sclk_peak * 100;
826b1a9557aSEvan Quan 		return 0;
827b1a9557aSEvan Quan 	case AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK:
828b1a9557aSEvan Quan 		*((uint32_t *)value) = hwmgr->pstate_mclk_peak * 100;
829e098bc96SEvan Quan 		return 0;
830e098bc96SEvan Quan 	case AMDGPU_PP_SENSOR_MIN_FAN_RPM:
831e098bc96SEvan Quan 		*((uint32_t *)value) = hwmgr->thermal_controller.fanInfo.ulMinRPM;
832e098bc96SEvan Quan 		return 0;
833e098bc96SEvan Quan 	case AMDGPU_PP_SENSOR_MAX_FAN_RPM:
834e098bc96SEvan Quan 		*((uint32_t *)value) = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
835e098bc96SEvan Quan 		return 0;
836e098bc96SEvan Quan 	default:
837a746c77eSEvan Quan 		return hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size);
838e098bc96SEvan Quan 	}
839e098bc96SEvan Quan }
840e098bc96SEvan Quan 
841e098bc96SEvan Quan static struct amd_vce_state*
pp_dpm_get_vce_clock_state(void * handle,unsigned idx)842e098bc96SEvan Quan pp_dpm_get_vce_clock_state(void *handle, unsigned idx)
843e098bc96SEvan Quan {
844e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
845e098bc96SEvan Quan 
846e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
847e098bc96SEvan Quan 		return NULL;
848e098bc96SEvan Quan 
849e098bc96SEvan Quan 	if (idx < hwmgr->num_vce_state_tables)
850e098bc96SEvan Quan 		return &hwmgr->vce_states[idx];
851e098bc96SEvan Quan 	return NULL;
852e098bc96SEvan Quan }
853e098bc96SEvan Quan 
pp_get_power_profile_mode(void * handle,char * buf)854e098bc96SEvan Quan static int pp_get_power_profile_mode(void *handle, char *buf)
855e098bc96SEvan Quan {
856e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
857e098bc96SEvan Quan 
858a7505591SMario Limonciello 	if (!hwmgr || !hwmgr->pm_en || !hwmgr->hwmgr_func->get_power_profile_mode)
859a035be8aSMario Limonciello 		return -EOPNOTSUPP;
860a035be8aSMario Limonciello 	if (!buf)
861e098bc96SEvan Quan 		return -EINVAL;
862e098bc96SEvan Quan 
863a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_power_profile_mode(hwmgr, buf);
864e098bc96SEvan Quan }
865e098bc96SEvan Quan 
pp_set_power_profile_mode(void * handle,long * input,uint32_t size)866e098bc96SEvan Quan static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size)
867e098bc96SEvan Quan {
868e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
869e098bc96SEvan Quan 
870a7505591SMario Limonciello 	if (!hwmgr || !hwmgr->pm_en || !hwmgr->hwmgr_func->set_power_profile_mode)
871a746c77eSEvan Quan 		return -EOPNOTSUPP;
872e098bc96SEvan Quan 
873e098bc96SEvan Quan 	if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
874e098bc96SEvan Quan 		pr_debug("power profile setting is for manual dpm mode only.\n");
875a035be8aSMario Limonciello 		return -EINVAL;
876e098bc96SEvan Quan 	}
877e098bc96SEvan Quan 
878a746c77eSEvan Quan 	return hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, input, size);
879e098bc96SEvan Quan }
880e098bc96SEvan Quan 
pp_set_fine_grain_clk_vol(void * handle,uint32_t type,long * input,uint32_t size)88112a6727dSXiaojian Du static int pp_set_fine_grain_clk_vol(void *handle, uint32_t type, long *input, uint32_t size)
88212a6727dSXiaojian Du {
88312a6727dSXiaojian Du 	struct pp_hwmgr *hwmgr = handle;
88412a6727dSXiaojian Du 
88512a6727dSXiaojian Du 	if (!hwmgr || !hwmgr->pm_en)
88612a6727dSXiaojian Du 		return -EINVAL;
88712a6727dSXiaojian Du 
88812a6727dSXiaojian Du 	if (hwmgr->hwmgr_func->set_fine_grain_clk_vol == NULL)
88912a6727dSXiaojian Du 		return 0;
89012a6727dSXiaojian Du 
89112a6727dSXiaojian Du 	return hwmgr->hwmgr_func->set_fine_grain_clk_vol(hwmgr, type, input, size);
89212a6727dSXiaojian Du }
89312a6727dSXiaojian Du 
pp_odn_edit_dpm_table(void * handle,enum PP_OD_DPM_TABLE_COMMAND type,long * input,uint32_t size)894e4d0ef75SNathan Chancellor static int pp_odn_edit_dpm_table(void *handle, enum PP_OD_DPM_TABLE_COMMAND type,
895e4d0ef75SNathan Chancellor 				 long *input, uint32_t size)
896e098bc96SEvan Quan {
897e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
898e098bc96SEvan Quan 
899e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
900e098bc96SEvan Quan 		return -EINVAL;
901e098bc96SEvan Quan 
902e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) {
903e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
90412a6727dSXiaojian Du 		return 0;
905e098bc96SEvan Quan 	}
906e098bc96SEvan Quan 
907e098bc96SEvan Quan 	return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size);
908e098bc96SEvan Quan }
909e098bc96SEvan Quan 
pp_dpm_set_mp1_state(void * handle,enum pp_mp1_state mp1_state)910e098bc96SEvan Quan static int pp_dpm_set_mp1_state(void *handle, enum pp_mp1_state mp1_state)
911e098bc96SEvan Quan {
912e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
913e098bc96SEvan Quan 
914e098bc96SEvan Quan 	if (!hwmgr)
915e098bc96SEvan Quan 		return -EINVAL;
916e098bc96SEvan Quan 
917e098bc96SEvan Quan 	if (!hwmgr->pm_en)
918e098bc96SEvan Quan 		return 0;
919e098bc96SEvan Quan 
920e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_mp1_state)
921e098bc96SEvan Quan 		return hwmgr->hwmgr_func->set_mp1_state(hwmgr, mp1_state);
922e098bc96SEvan Quan 
923e098bc96SEvan Quan 	return 0;
924e098bc96SEvan Quan }
925e098bc96SEvan Quan 
pp_dpm_switch_power_profile(void * handle,enum PP_SMC_POWER_PROFILE type,bool en)926e098bc96SEvan Quan static int pp_dpm_switch_power_profile(void *handle,
927e098bc96SEvan Quan 		enum PP_SMC_POWER_PROFILE type, bool en)
928e098bc96SEvan Quan {
929e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
930837ab17cSMa Jun 	long workload[1];
931e098bc96SEvan Quan 	uint32_t index;
932e098bc96SEvan Quan 
933e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
934e098bc96SEvan Quan 		return -EINVAL;
935e098bc96SEvan Quan 
936e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) {
937e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
938e098bc96SEvan Quan 		return -EINVAL;
939e098bc96SEvan Quan 	}
940e098bc96SEvan Quan 
941e098bc96SEvan Quan 	if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
942e098bc96SEvan Quan 		return -EINVAL;
943e098bc96SEvan Quan 
944e098bc96SEvan Quan 	if (!en) {
945e098bc96SEvan Quan 		hwmgr->workload_mask &= ~(1 << hwmgr->workload_prority[type]);
946e098bc96SEvan Quan 		index = fls(hwmgr->workload_mask);
947e098bc96SEvan Quan 		index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0;
948837ab17cSMa Jun 		workload[0] = hwmgr->workload_setting[index];
949e098bc96SEvan Quan 	} else {
950e098bc96SEvan Quan 		hwmgr->workload_mask |= (1 << hwmgr->workload_prority[type]);
951e098bc96SEvan Quan 		index = fls(hwmgr->workload_mask);
952e098bc96SEvan Quan 		index = index <= Workload_Policy_Max ? index - 1 : 0;
953837ab17cSMa Jun 		workload[0] = hwmgr->workload_setting[index];
954e098bc96SEvan Quan 	}
955e098bc96SEvan Quan 
956e098bc96SEvan Quan 	if (type == PP_SMC_POWER_PROFILE_COMPUTE &&
957e098bc96SEvan Quan 		hwmgr->hwmgr_func->disable_power_features_for_compute_performance) {
958a746c77eSEvan Quan 			if (hwmgr->hwmgr_func->disable_power_features_for_compute_performance(hwmgr, en))
959e098bc96SEvan Quan 				return -EINVAL;
960e098bc96SEvan Quan 	}
961e098bc96SEvan Quan 
962e098bc96SEvan Quan 	if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
963837ab17cSMa Jun 		hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, workload, 0);
964e098bc96SEvan Quan 
965e098bc96SEvan Quan 	return 0;
966e098bc96SEvan Quan }
967e098bc96SEvan Quan 
pp_set_power_limit(void * handle,uint32_t limit)968e098bc96SEvan Quan static int pp_set_power_limit(void *handle, uint32_t limit)
969e098bc96SEvan Quan {
970e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
971e098bc96SEvan Quan 	uint32_t max_power_limit;
972e098bc96SEvan Quan 
973e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
974e098bc96SEvan Quan 		return -EINVAL;
975e098bc96SEvan Quan 
976e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_power_limit == NULL) {
977e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
978e098bc96SEvan Quan 		return -EINVAL;
979e098bc96SEvan Quan 	}
980e098bc96SEvan Quan 
981e098bc96SEvan Quan 	if (limit == 0)
982e098bc96SEvan Quan 		limit = hwmgr->default_power_limit;
983e098bc96SEvan Quan 
984e098bc96SEvan Quan 	max_power_limit = hwmgr->default_power_limit;
985e098bc96SEvan Quan 	if (hwmgr->od_enabled) {
986e098bc96SEvan Quan 		max_power_limit *= (100 + hwmgr->platform_descriptor.TDPODLimit);
987e098bc96SEvan Quan 		max_power_limit /= 100;
988e098bc96SEvan Quan 	}
989e098bc96SEvan Quan 
990e098bc96SEvan Quan 	if (limit > max_power_limit)
991e098bc96SEvan Quan 		return -EINVAL;
992e098bc96SEvan Quan 
993e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_power_limit(hwmgr, limit);
994e098bc96SEvan Quan 	hwmgr->power_limit = limit;
995e098bc96SEvan Quan 	return 0;
996e098bc96SEvan Quan }
997e098bc96SEvan Quan 
pp_get_power_limit(void * handle,uint32_t * limit,enum pp_power_limit_level pp_limit_level,enum pp_power_type power_type)9986e58941cSEric Huang static int pp_get_power_limit(void *handle, uint32_t *limit,
99904bec521SDarren Powell 			      enum pp_power_limit_level pp_limit_level,
100004bec521SDarren Powell 			      enum pp_power_type power_type)
1001e098bc96SEvan Quan {
1002e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
100304bec521SDarren Powell 	int ret = 0;
1004e098bc96SEvan Quan 
1005e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !limit)
1006e098bc96SEvan Quan 		return -EINVAL;
1007e098bc96SEvan Quan 
100804bec521SDarren Powell 	if (power_type != PP_PWR_TYPE_SUSTAINED)
100904bec521SDarren Powell 		return -EOPNOTSUPP;
101004bec521SDarren Powell 
101104bec521SDarren Powell 	switch (pp_limit_level) {
101204bec521SDarren Powell 		case PP_PWR_LIMIT_CURRENT:
1013e098bc96SEvan Quan 			*limit = hwmgr->power_limit;
101404bec521SDarren Powell 			break;
101504bec521SDarren Powell 		case PP_PWR_LIMIT_DEFAULT:
101604bec521SDarren Powell 			*limit = hwmgr->default_power_limit;
101704bec521SDarren Powell 			break;
101804bec521SDarren Powell 		case PP_PWR_LIMIT_MAX:
101904bec521SDarren Powell 			*limit = hwmgr->default_power_limit;
102004bec521SDarren Powell 			if (hwmgr->od_enabled) {
102104bec521SDarren Powell 				*limit *= (100 + hwmgr->platform_descriptor.TDPODLimit);
102204bec521SDarren Powell 				*limit /= 100;
102304bec521SDarren Powell 			}
102404bec521SDarren Powell 			break;
102504bec521SDarren Powell 		default:
102604bec521SDarren Powell 			ret = -EOPNOTSUPP;
102704bec521SDarren Powell 			break;
102804bec521SDarren Powell 	}
1029e098bc96SEvan Quan 
103004bec521SDarren Powell 	return ret;
1031e098bc96SEvan Quan }
1032e098bc96SEvan Quan 
pp_display_configuration_change(void * handle,const struct amd_pp_display_configuration * display_config)1033e098bc96SEvan Quan static int pp_display_configuration_change(void *handle,
1034e098bc96SEvan Quan 	const struct amd_pp_display_configuration *display_config)
1035e098bc96SEvan Quan {
1036e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1037e098bc96SEvan Quan 
1038e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1039e098bc96SEvan Quan 		return -EINVAL;
1040e098bc96SEvan Quan 
1041e098bc96SEvan Quan 	phm_store_dal_configuration_data(hwmgr, display_config);
1042e098bc96SEvan Quan 	return 0;
1043e098bc96SEvan Quan }
1044e098bc96SEvan Quan 
pp_get_display_power_level(void * handle,struct amd_pp_simple_clock_info * output)1045e098bc96SEvan Quan static int pp_get_display_power_level(void *handle,
1046e098bc96SEvan Quan 		struct amd_pp_simple_clock_info *output)
1047e098bc96SEvan Quan {
1048e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1049e098bc96SEvan Quan 
1050e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !output)
1051e098bc96SEvan Quan 		return -EINVAL;
1052e098bc96SEvan Quan 
1053a746c77eSEvan Quan 	return phm_get_dal_power_level(hwmgr, output);
1054e098bc96SEvan Quan }
1055e098bc96SEvan Quan 
pp_get_current_clocks(void * handle,struct amd_pp_clock_info * clocks)1056e098bc96SEvan Quan static int pp_get_current_clocks(void *handle,
1057e098bc96SEvan Quan 		struct amd_pp_clock_info *clocks)
1058e098bc96SEvan Quan {
1059e098bc96SEvan Quan 	struct amd_pp_simple_clock_info simple_clocks = { 0 };
1060e098bc96SEvan Quan 	struct pp_clock_info hw_clocks;
1061e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1062e098bc96SEvan Quan 	int ret = 0;
1063e098bc96SEvan Quan 
1064e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1065e098bc96SEvan Quan 		return -EINVAL;
1066e098bc96SEvan Quan 
1067e098bc96SEvan Quan 	phm_get_dal_power_level(hwmgr, &simple_clocks);
1068e098bc96SEvan Quan 
1069e098bc96SEvan Quan 	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1070e098bc96SEvan Quan 					PHM_PlatformCaps_PowerContainment))
1071e098bc96SEvan Quan 		ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
1072e098bc96SEvan Quan 					&hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment);
1073e098bc96SEvan Quan 	else
1074e098bc96SEvan Quan 		ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
1075e098bc96SEvan Quan 					&hw_clocks, PHM_PerformanceLevelDesignation_Activity);
1076e098bc96SEvan Quan 
1077e098bc96SEvan Quan 	if (ret) {
1078e098bc96SEvan Quan 		pr_debug("Error in phm_get_clock_info \n");
1079e098bc96SEvan Quan 		return -EINVAL;
1080e098bc96SEvan Quan 	}
1081e098bc96SEvan Quan 
1082e098bc96SEvan Quan 	clocks->min_engine_clock = hw_clocks.min_eng_clk;
1083e098bc96SEvan Quan 	clocks->max_engine_clock = hw_clocks.max_eng_clk;
1084e098bc96SEvan Quan 	clocks->min_memory_clock = hw_clocks.min_mem_clk;
1085e098bc96SEvan Quan 	clocks->max_memory_clock = hw_clocks.max_mem_clk;
1086e098bc96SEvan Quan 	clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth;
1087e098bc96SEvan Quan 	clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth;
1088e098bc96SEvan Quan 
1089e098bc96SEvan Quan 	clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
1090e098bc96SEvan Quan 	clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
1091e098bc96SEvan Quan 
1092e098bc96SEvan Quan 	if (simple_clocks.level == 0)
1093e098bc96SEvan Quan 		clocks->max_clocks_state = PP_DAL_POWERLEVEL_7;
1094e098bc96SEvan Quan 	else
1095e098bc96SEvan Quan 		clocks->max_clocks_state = simple_clocks.level;
1096e098bc96SEvan Quan 
1097e098bc96SEvan Quan 	if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
1098e098bc96SEvan Quan 		clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
1099e098bc96SEvan Quan 		clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
1100e098bc96SEvan Quan 	}
1101e098bc96SEvan Quan 	return 0;
1102e098bc96SEvan Quan }
1103e098bc96SEvan Quan 
pp_get_clock_by_type(void * handle,enum amd_pp_clock_type type,struct amd_pp_clocks * clocks)1104e098bc96SEvan Quan static int pp_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
1105e098bc96SEvan Quan {
1106e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1107e098bc96SEvan Quan 
1108e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1109e098bc96SEvan Quan 		return -EINVAL;
1110e098bc96SEvan Quan 
1111e098bc96SEvan Quan 	if (clocks == NULL)
1112e098bc96SEvan Quan 		return -EINVAL;
1113e098bc96SEvan Quan 
1114a746c77eSEvan Quan 	return phm_get_clock_by_type(hwmgr, type, clocks);
1115e098bc96SEvan Quan }
1116e098bc96SEvan Quan 
pp_get_clock_by_type_with_latency(void * handle,enum amd_pp_clock_type type,struct pp_clock_levels_with_latency * clocks)1117e098bc96SEvan Quan static int pp_get_clock_by_type_with_latency(void *handle,
1118e098bc96SEvan Quan 		enum amd_pp_clock_type type,
1119e098bc96SEvan Quan 		struct pp_clock_levels_with_latency *clocks)
1120e098bc96SEvan Quan {
1121e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1122e098bc96SEvan Quan 
1123e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !clocks)
1124e098bc96SEvan Quan 		return -EINVAL;
1125e098bc96SEvan Quan 
1126a746c77eSEvan Quan 	return phm_get_clock_by_type_with_latency(hwmgr, type, clocks);
1127e098bc96SEvan Quan }
1128e098bc96SEvan Quan 
pp_get_clock_by_type_with_voltage(void * handle,enum amd_pp_clock_type type,struct pp_clock_levels_with_voltage * clocks)1129e098bc96SEvan Quan static int pp_get_clock_by_type_with_voltage(void *handle,
1130e098bc96SEvan Quan 		enum amd_pp_clock_type type,
1131e098bc96SEvan Quan 		struct pp_clock_levels_with_voltage *clocks)
1132e098bc96SEvan Quan {
1133e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1134e098bc96SEvan Quan 
1135e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !clocks)
1136e098bc96SEvan Quan 		return -EINVAL;
1137e098bc96SEvan Quan 
1138a746c77eSEvan Quan 	return phm_get_clock_by_type_with_voltage(hwmgr, type, clocks);
1139e098bc96SEvan Quan }
1140e098bc96SEvan Quan 
pp_set_watermarks_for_clocks_ranges(void * handle,void * clock_ranges)1141e098bc96SEvan Quan static int pp_set_watermarks_for_clocks_ranges(void *handle,
1142e098bc96SEvan Quan 		void *clock_ranges)
1143e098bc96SEvan Quan {
1144e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1145e098bc96SEvan Quan 
1146e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !clock_ranges)
1147e098bc96SEvan Quan 		return -EINVAL;
1148e098bc96SEvan Quan 
1149a746c77eSEvan Quan 	return phm_set_watermarks_for_clocks_ranges(hwmgr,
1150e098bc96SEvan Quan 						    clock_ranges);
1151e098bc96SEvan Quan }
1152e098bc96SEvan Quan 
pp_display_clock_voltage_request(void * handle,struct pp_display_clock_request * clock)1153e098bc96SEvan Quan static int pp_display_clock_voltage_request(void *handle,
1154e098bc96SEvan Quan 		struct pp_display_clock_request *clock)
1155e098bc96SEvan Quan {
1156e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1157e098bc96SEvan Quan 
1158e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !clock)
1159e098bc96SEvan Quan 		return -EINVAL;
1160e098bc96SEvan Quan 
1161a746c77eSEvan Quan 	return phm_display_clock_voltage_request(hwmgr, clock);
1162e098bc96SEvan Quan }
1163e098bc96SEvan Quan 
pp_get_display_mode_validation_clocks(void * handle,struct amd_pp_simple_clock_info * clocks)1164e098bc96SEvan Quan static int pp_get_display_mode_validation_clocks(void *handle,
1165e098bc96SEvan Quan 		struct amd_pp_simple_clock_info *clocks)
1166e098bc96SEvan Quan {
1167e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1168e098bc96SEvan Quan 	int ret = 0;
1169e098bc96SEvan Quan 
1170e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !clocks)
1171e098bc96SEvan Quan 		return -EINVAL;
1172e098bc96SEvan Quan 
1173e098bc96SEvan Quan 	clocks->level = PP_DAL_POWERLEVEL_7;
1174e098bc96SEvan Quan 
1175e098bc96SEvan Quan 	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
1176e098bc96SEvan Quan 		ret = phm_get_max_high_clocks(hwmgr, clocks);
1177e098bc96SEvan Quan 
1178e098bc96SEvan Quan 	return ret;
1179e098bc96SEvan Quan }
1180e098bc96SEvan Quan 
pp_dpm_powergate_mmhub(void * handle)1181e098bc96SEvan Quan static int pp_dpm_powergate_mmhub(void *handle)
1182e098bc96SEvan Quan {
1183e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1184e098bc96SEvan Quan 
1185e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1186e098bc96SEvan Quan 		return -EINVAL;
1187e098bc96SEvan Quan 
1188e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->powergate_mmhub == NULL) {
1189e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1190e098bc96SEvan Quan 		return 0;
1191e098bc96SEvan Quan 	}
1192e098bc96SEvan Quan 
1193e098bc96SEvan Quan 	return hwmgr->hwmgr_func->powergate_mmhub(hwmgr);
1194e098bc96SEvan Quan }
1195e098bc96SEvan Quan 
pp_dpm_powergate_gfx(void * handle,bool gate)1196e098bc96SEvan Quan static int pp_dpm_powergate_gfx(void *handle, bool gate)
1197e098bc96SEvan Quan {
1198e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1199e098bc96SEvan Quan 
1200e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1201e098bc96SEvan Quan 		return 0;
1202e098bc96SEvan Quan 
1203e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->powergate_gfx == NULL) {
1204e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1205e098bc96SEvan Quan 		return 0;
1206e098bc96SEvan Quan 	}
1207e098bc96SEvan Quan 
1208e098bc96SEvan Quan 	return hwmgr->hwmgr_func->powergate_gfx(hwmgr, gate);
1209e098bc96SEvan Quan }
1210e098bc96SEvan Quan 
pp_dpm_powergate_acp(void * handle,bool gate)1211e098bc96SEvan Quan static void pp_dpm_powergate_acp(void *handle, bool gate)
1212e098bc96SEvan Quan {
1213e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1214e098bc96SEvan Quan 
1215e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1216e098bc96SEvan Quan 		return;
1217e098bc96SEvan Quan 
1218e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->powergate_acp == NULL) {
1219e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1220e098bc96SEvan Quan 		return;
1221e098bc96SEvan Quan 	}
1222e098bc96SEvan Quan 
1223e098bc96SEvan Quan 	hwmgr->hwmgr_func->powergate_acp(hwmgr, gate);
1224e098bc96SEvan Quan }
1225e098bc96SEvan Quan 
pp_dpm_powergate_sdma(void * handle,bool gate)1226e098bc96SEvan Quan static void pp_dpm_powergate_sdma(void *handle, bool gate)
1227e098bc96SEvan Quan {
1228e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1229e098bc96SEvan Quan 
1230e098bc96SEvan Quan 	if (!hwmgr)
1231e098bc96SEvan Quan 		return;
1232e098bc96SEvan Quan 
1233e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->powergate_sdma == NULL) {
1234e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1235e098bc96SEvan Quan 		return;
1236e098bc96SEvan Quan 	}
1237e098bc96SEvan Quan 
1238e098bc96SEvan Quan 	hwmgr->hwmgr_func->powergate_sdma(hwmgr, gate);
1239e098bc96SEvan Quan }
1240e098bc96SEvan Quan 
pp_set_powergating_by_smu(void * handle,uint32_t block_type,bool gate)1241e098bc96SEvan Quan static int pp_set_powergating_by_smu(void *handle,
1242e098bc96SEvan Quan 				uint32_t block_type, bool gate)
1243e098bc96SEvan Quan {
1244e098bc96SEvan Quan 	int ret = 0;
1245e098bc96SEvan Quan 
1246e098bc96SEvan Quan 	switch (block_type) {
1247e098bc96SEvan Quan 	case AMD_IP_BLOCK_TYPE_UVD:
1248e098bc96SEvan Quan 	case AMD_IP_BLOCK_TYPE_VCN:
1249e098bc96SEvan Quan 		pp_dpm_powergate_uvd(handle, gate);
1250e098bc96SEvan Quan 		break;
1251e098bc96SEvan Quan 	case AMD_IP_BLOCK_TYPE_VCE:
1252e098bc96SEvan Quan 		pp_dpm_powergate_vce(handle, gate);
1253e098bc96SEvan Quan 		break;
1254e098bc96SEvan Quan 	case AMD_IP_BLOCK_TYPE_GMC:
125517252701SEvan Quan 		/*
125617252701SEvan Quan 		 * For now, this is only used on PICASSO.
125717252701SEvan Quan 		 * And only "gate" operation is supported.
125817252701SEvan Quan 		 */
125917252701SEvan Quan 		if (gate)
1260e098bc96SEvan Quan 			pp_dpm_powergate_mmhub(handle);
1261e098bc96SEvan Quan 		break;
1262e098bc96SEvan Quan 	case AMD_IP_BLOCK_TYPE_GFX:
1263e098bc96SEvan Quan 		ret = pp_dpm_powergate_gfx(handle, gate);
1264e098bc96SEvan Quan 		break;
1265e098bc96SEvan Quan 	case AMD_IP_BLOCK_TYPE_ACP:
1266e098bc96SEvan Quan 		pp_dpm_powergate_acp(handle, gate);
1267e098bc96SEvan Quan 		break;
1268e098bc96SEvan Quan 	case AMD_IP_BLOCK_TYPE_SDMA:
1269e098bc96SEvan Quan 		pp_dpm_powergate_sdma(handle, gate);
1270e098bc96SEvan Quan 		break;
1271e098bc96SEvan Quan 	default:
1272e098bc96SEvan Quan 		break;
1273e098bc96SEvan Quan 	}
1274e098bc96SEvan Quan 	return ret;
1275e098bc96SEvan Quan }
1276e098bc96SEvan Quan 
pp_notify_smu_enable_pwe(void * handle)1277e098bc96SEvan Quan static int pp_notify_smu_enable_pwe(void *handle)
1278e098bc96SEvan Quan {
1279e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1280e098bc96SEvan Quan 
1281e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1282e098bc96SEvan Quan 		return -EINVAL;
1283e098bc96SEvan Quan 
1284e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) {
1285e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1286e098bc96SEvan Quan 		return -EINVAL;
1287e098bc96SEvan Quan 	}
1288e098bc96SEvan Quan 
1289e098bc96SEvan Quan 	hwmgr->hwmgr_func->smus_notify_pwe(hwmgr);
1290e098bc96SEvan Quan 
1291e098bc96SEvan Quan 	return 0;
1292e098bc96SEvan Quan }
1293e098bc96SEvan Quan 
pp_enable_mgpu_fan_boost(void * handle)1294e098bc96SEvan Quan static int pp_enable_mgpu_fan_boost(void *handle)
1295e098bc96SEvan Quan {
1296e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1297e098bc96SEvan Quan 
1298e098bc96SEvan Quan 	if (!hwmgr)
1299e098bc96SEvan Quan 		return -EINVAL;
1300e098bc96SEvan Quan 
1301e098bc96SEvan Quan 	if (!hwmgr->pm_en ||
1302e098bc96SEvan Quan 	     hwmgr->hwmgr_func->enable_mgpu_fan_boost == NULL)
1303e098bc96SEvan Quan 		return 0;
1304e098bc96SEvan Quan 
1305e098bc96SEvan Quan 	hwmgr->hwmgr_func->enable_mgpu_fan_boost(hwmgr);
1306e098bc96SEvan Quan 
1307e098bc96SEvan Quan 	return 0;
1308e098bc96SEvan Quan }
1309e098bc96SEvan Quan 
pp_set_min_deep_sleep_dcefclk(void * handle,uint32_t clock)1310e098bc96SEvan Quan static int pp_set_min_deep_sleep_dcefclk(void *handle, uint32_t clock)
1311e098bc96SEvan Quan {
1312e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1313e098bc96SEvan Quan 
1314e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1315e098bc96SEvan Quan 		return -EINVAL;
1316e098bc96SEvan Quan 
1317e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk == NULL) {
1318e098bc96SEvan Quan 		pr_debug("%s was not implemented.\n", __func__);
1319e098bc96SEvan Quan 		return -EINVAL;
1320e098bc96SEvan Quan 	}
1321e098bc96SEvan Quan 
1322e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk(hwmgr, clock);
1323e098bc96SEvan Quan 
1324e098bc96SEvan Quan 	return 0;
1325e098bc96SEvan Quan }
1326e098bc96SEvan Quan 
pp_set_hard_min_dcefclk_by_freq(void * handle,uint32_t clock)1327e098bc96SEvan Quan static int pp_set_hard_min_dcefclk_by_freq(void *handle, uint32_t clock)
1328e098bc96SEvan Quan {
1329e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1330e098bc96SEvan Quan 
1331e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1332e098bc96SEvan Quan 		return -EINVAL;
1333e098bc96SEvan Quan 
1334e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq == NULL) {
1335e098bc96SEvan Quan 		pr_debug("%s was not implemented.\n", __func__);
1336e098bc96SEvan Quan 		return -EINVAL;
1337e098bc96SEvan Quan 	}
1338e098bc96SEvan Quan 
1339e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq(hwmgr, clock);
1340e098bc96SEvan Quan 
1341e098bc96SEvan Quan 	return 0;
1342e098bc96SEvan Quan }
1343e098bc96SEvan Quan 
pp_set_hard_min_fclk_by_freq(void * handle,uint32_t clock)1344e098bc96SEvan Quan static int pp_set_hard_min_fclk_by_freq(void *handle, uint32_t clock)
1345e098bc96SEvan Quan {
1346e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1347e098bc96SEvan Quan 
1348e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1349e098bc96SEvan Quan 		return -EINVAL;
1350e098bc96SEvan Quan 
1351e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_hard_min_fclk_by_freq == NULL) {
1352e098bc96SEvan Quan 		pr_debug("%s was not implemented.\n", __func__);
1353e098bc96SEvan Quan 		return -EINVAL;
1354e098bc96SEvan Quan 	}
1355e098bc96SEvan Quan 
1356e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_hard_min_fclk_by_freq(hwmgr, clock);
1357e098bc96SEvan Quan 
1358e098bc96SEvan Quan 	return 0;
1359e098bc96SEvan Quan }
1360e098bc96SEvan Quan 
pp_set_active_display_count(void * handle,uint32_t count)1361e098bc96SEvan Quan static int pp_set_active_display_count(void *handle, uint32_t count)
1362e098bc96SEvan Quan {
1363e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1364e098bc96SEvan Quan 
1365e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1366e098bc96SEvan Quan 		return -EINVAL;
1367e098bc96SEvan Quan 
1368a746c77eSEvan Quan 	return phm_set_active_display_count(hwmgr, count);
1369e098bc96SEvan Quan }
1370e098bc96SEvan Quan 
pp_get_asic_baco_capability(void * handle,bool * cap)1371e098bc96SEvan Quan static int pp_get_asic_baco_capability(void *handle, bool *cap)
1372e098bc96SEvan Quan {
1373e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1374e098bc96SEvan Quan 
1375e098bc96SEvan Quan 	*cap = false;
1376e098bc96SEvan Quan 	if (!hwmgr)
1377e098bc96SEvan Quan 		return -EINVAL;
1378e098bc96SEvan Quan 
1379e098bc96SEvan Quan 	if (!(hwmgr->not_vf && amdgpu_dpm) ||
1380e098bc96SEvan Quan 		!hwmgr->hwmgr_func->get_asic_baco_capability)
1381e098bc96SEvan Quan 		return 0;
1382e098bc96SEvan Quan 
1383e098bc96SEvan Quan 	hwmgr->hwmgr_func->get_asic_baco_capability(hwmgr, cap);
1384e098bc96SEvan Quan 
1385e098bc96SEvan Quan 	return 0;
1386e098bc96SEvan Quan }
1387e098bc96SEvan Quan 
pp_get_asic_baco_state(void * handle,int * state)1388e098bc96SEvan Quan static int pp_get_asic_baco_state(void *handle, int *state)
1389e098bc96SEvan Quan {
1390e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1391e098bc96SEvan Quan 
1392e098bc96SEvan Quan 	if (!hwmgr)
1393e098bc96SEvan Quan 		return -EINVAL;
1394e098bc96SEvan Quan 
1395e098bc96SEvan Quan 	if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_asic_baco_state)
1396e098bc96SEvan Quan 		return 0;
1397e098bc96SEvan Quan 
1398e098bc96SEvan Quan 	hwmgr->hwmgr_func->get_asic_baco_state(hwmgr, (enum BACO_STATE *)state);
1399e098bc96SEvan Quan 
1400e098bc96SEvan Quan 	return 0;
1401e098bc96SEvan Quan }
1402e098bc96SEvan Quan 
pp_set_asic_baco_state(void * handle,int state)1403e098bc96SEvan Quan static int pp_set_asic_baco_state(void *handle, int state)
1404e098bc96SEvan Quan {
1405e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1406e098bc96SEvan Quan 
1407e098bc96SEvan Quan 	if (!hwmgr)
1408e098bc96SEvan Quan 		return -EINVAL;
1409e098bc96SEvan Quan 
1410e098bc96SEvan Quan 	if (!(hwmgr->not_vf && amdgpu_dpm) ||
1411e098bc96SEvan Quan 		!hwmgr->hwmgr_func->set_asic_baco_state)
1412e098bc96SEvan Quan 		return 0;
1413e098bc96SEvan Quan 
1414e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_asic_baco_state(hwmgr, (enum BACO_STATE)state);
1415e098bc96SEvan Quan 
1416e098bc96SEvan Quan 	return 0;
1417e098bc96SEvan Quan }
1418e098bc96SEvan Quan 
pp_get_ppfeature_status(void * handle,char * buf)1419e098bc96SEvan Quan static int pp_get_ppfeature_status(void *handle, char *buf)
1420e098bc96SEvan Quan {
1421e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1422e098bc96SEvan Quan 
1423e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en || !buf)
1424e098bc96SEvan Quan 		return -EINVAL;
1425e098bc96SEvan Quan 
1426e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->get_ppfeature_status == NULL) {
1427e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1428e098bc96SEvan Quan 		return -EINVAL;
1429e098bc96SEvan Quan 	}
1430e098bc96SEvan Quan 
1431a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_ppfeature_status(hwmgr, buf);
1432e098bc96SEvan Quan }
1433e098bc96SEvan Quan 
pp_set_ppfeature_status(void * handle,uint64_t ppfeature_masks)1434e098bc96SEvan Quan static int pp_set_ppfeature_status(void *handle, uint64_t ppfeature_masks)
1435e098bc96SEvan Quan {
1436e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1437e098bc96SEvan Quan 
1438e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1439e098bc96SEvan Quan 		return -EINVAL;
1440e098bc96SEvan Quan 
1441e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->set_ppfeature_status == NULL) {
1442e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1443e098bc96SEvan Quan 		return -EINVAL;
1444e098bc96SEvan Quan 	}
1445e098bc96SEvan Quan 
1446a746c77eSEvan Quan 	return hwmgr->hwmgr_func->set_ppfeature_status(hwmgr, ppfeature_masks);
1447e098bc96SEvan Quan }
1448e098bc96SEvan Quan 
pp_asic_reset_mode_2(void * handle)1449e098bc96SEvan Quan static int pp_asic_reset_mode_2(void *handle)
1450e098bc96SEvan Quan {
1451e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1452e098bc96SEvan Quan 
1453e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1454e098bc96SEvan Quan 		return -EINVAL;
1455e098bc96SEvan Quan 
1456e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->asic_reset == NULL) {
1457e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1458e098bc96SEvan Quan 		return -EINVAL;
1459e098bc96SEvan Quan 	}
1460e098bc96SEvan Quan 
1461a746c77eSEvan Quan 	return hwmgr->hwmgr_func->asic_reset(hwmgr, SMU_ASIC_RESET_MODE_2);
1462e098bc96SEvan Quan }
1463e098bc96SEvan Quan 
pp_smu_i2c_bus_access(void * handle,bool acquire)1464e098bc96SEvan Quan static int pp_smu_i2c_bus_access(void *handle, bool acquire)
1465e098bc96SEvan Quan {
1466e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1467e098bc96SEvan Quan 
1468e098bc96SEvan Quan 	if (!hwmgr || !hwmgr->pm_en)
1469e098bc96SEvan Quan 		return -EINVAL;
1470e098bc96SEvan Quan 
1471e098bc96SEvan Quan 	if (hwmgr->hwmgr_func->smu_i2c_bus_access == NULL) {
1472e098bc96SEvan Quan 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1473e098bc96SEvan Quan 		return -EINVAL;
1474e098bc96SEvan Quan 	}
1475e098bc96SEvan Quan 
1476a746c77eSEvan Quan 	return hwmgr->hwmgr_func->smu_i2c_bus_access(hwmgr, acquire);
1477e098bc96SEvan Quan }
1478e098bc96SEvan Quan 
pp_set_df_cstate(void * handle,enum pp_df_cstate state)1479e098bc96SEvan Quan static int pp_set_df_cstate(void *handle, enum pp_df_cstate state)
1480e098bc96SEvan Quan {
1481e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1482e098bc96SEvan Quan 
1483e098bc96SEvan Quan 	if (!hwmgr)
1484e098bc96SEvan Quan 		return -EINVAL;
1485e098bc96SEvan Quan 
1486e098bc96SEvan Quan 	if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_df_cstate)
1487e098bc96SEvan Quan 		return 0;
1488e098bc96SEvan Quan 
1489e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_df_cstate(hwmgr, state);
1490e098bc96SEvan Quan 
1491e098bc96SEvan Quan 	return 0;
1492e098bc96SEvan Quan }
1493e098bc96SEvan Quan 
pp_set_xgmi_pstate(void * handle,uint32_t pstate)1494e098bc96SEvan Quan static int pp_set_xgmi_pstate(void *handle, uint32_t pstate)
1495e098bc96SEvan Quan {
1496e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1497e098bc96SEvan Quan 
1498e098bc96SEvan Quan 	if (!hwmgr)
1499e098bc96SEvan Quan 		return -EINVAL;
1500e098bc96SEvan Quan 
1501e098bc96SEvan Quan 	if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_xgmi_pstate)
1502e098bc96SEvan Quan 		return 0;
1503e098bc96SEvan Quan 
1504e098bc96SEvan Quan 	hwmgr->hwmgr_func->set_xgmi_pstate(hwmgr, pstate);
1505e098bc96SEvan Quan 
1506e098bc96SEvan Quan 	return 0;
1507e098bc96SEvan Quan }
1508e098bc96SEvan Quan 
pp_get_gpu_metrics(void * handle,void ** table)1509e098bc96SEvan Quan static ssize_t pp_get_gpu_metrics(void *handle, void **table)
1510e098bc96SEvan Quan {
1511e098bc96SEvan Quan 	struct pp_hwmgr *hwmgr = handle;
1512e098bc96SEvan Quan 
1513e098bc96SEvan Quan 	if (!hwmgr)
1514e098bc96SEvan Quan 		return -EINVAL;
1515e098bc96SEvan Quan 
1516e098bc96SEvan Quan 	if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_gpu_metrics)
1517e098bc96SEvan Quan 		return -EOPNOTSUPP;
1518e098bc96SEvan Quan 
1519a746c77eSEvan Quan 	return hwmgr->hwmgr_func->get_gpu_metrics(hwmgr, table);
1520e098bc96SEvan Quan }
1521e098bc96SEvan Quan 
pp_gfx_state_change_set(void * handle,uint32_t state)1522d90a53d6SPrike Liang static int pp_gfx_state_change_set(void *handle, uint32_t state)
1523d90a53d6SPrike Liang {
1524d90a53d6SPrike Liang 	struct pp_hwmgr *hwmgr = handle;
1525d90a53d6SPrike Liang 
1526d90a53d6SPrike Liang 	if (!hwmgr || !hwmgr->pm_en)
1527d90a53d6SPrike Liang 		return -EINVAL;
1528d90a53d6SPrike Liang 
1529d90a53d6SPrike Liang 	if (hwmgr->hwmgr_func->gfx_state_change == NULL) {
1530d90a53d6SPrike Liang 		pr_info_ratelimited("%s was not implemented.\n", __func__);
1531d90a53d6SPrike Liang 		return -EINVAL;
1532d90a53d6SPrike Liang 	}
1533d90a53d6SPrike Liang 
1534d90a53d6SPrike Liang 	hwmgr->hwmgr_func->gfx_state_change(hwmgr, state);
1535d90a53d6SPrike Liang 	return 0;
1536d90a53d6SPrike Liang }
1537d90a53d6SPrike Liang 
pp_get_prv_buffer_details(void * handle,void ** addr,size_t * size)1538b8c78bdbSLijo Lazar static int pp_get_prv_buffer_details(void *handle, void **addr, size_t *size)
1539b8c78bdbSLijo Lazar {
1540b8c78bdbSLijo Lazar 	struct pp_hwmgr *hwmgr = handle;
1541b8c78bdbSLijo Lazar 	struct amdgpu_device *adev = hwmgr->adev;
1542629c30dbSLi Zhong 	int err;
1543b8c78bdbSLijo Lazar 
1544b8c78bdbSLijo Lazar 	if (!addr || !size)
1545b8c78bdbSLijo Lazar 		return -EINVAL;
1546b8c78bdbSLijo Lazar 
1547b8c78bdbSLijo Lazar 	*addr = NULL;
1548b8c78bdbSLijo Lazar 	*size = 0;
1549b8c78bdbSLijo Lazar 	if (adev->pm.smu_prv_buffer) {
1550629c30dbSLi Zhong 		err = amdgpu_bo_kmap(adev->pm.smu_prv_buffer, addr);
1551629c30dbSLi Zhong 		if (err)
1552629c30dbSLi Zhong 			return err;
1553b8c78bdbSLijo Lazar 		*size = adev->pm.smu_prv_buffer_size;
1554b8c78bdbSLijo Lazar 	}
1555b8c78bdbSLijo Lazar 
1556b8c78bdbSLijo Lazar 	return 0;
1557b8c78bdbSLijo Lazar }
1558b8c78bdbSLijo Lazar 
pp_pm_compute_clocks(void * handle)15596ddbd37fSEvan Quan static void pp_pm_compute_clocks(void *handle)
15606ddbd37fSEvan Quan {
15616ddbd37fSEvan Quan 	struct pp_hwmgr *hwmgr = handle;
15626ddbd37fSEvan Quan 	struct amdgpu_device *adev = hwmgr->adev;
15636ddbd37fSEvan Quan 
1564d09ef243SAlex Deucher 	if (!adev->dc_enabled) {
15656ddbd37fSEvan Quan 		amdgpu_dpm_get_active_displays(adev);
15666ddbd37fSEvan Quan 		adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count;
15676ddbd37fSEvan Quan 		adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev);
15686ddbd37fSEvan Quan 		adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev);
15696ddbd37fSEvan Quan 		/* we have issues with mclk switching with
15706ddbd37fSEvan Quan 		 * refresh rates over 120 hz on the non-DC code.
15716ddbd37fSEvan Quan 		 */
15726ddbd37fSEvan Quan 		if (adev->pm.pm_display_cfg.vrefresh > 120)
15736ddbd37fSEvan Quan 			adev->pm.pm_display_cfg.min_vblank_time = 0;
15746ddbd37fSEvan Quan 
15756ddbd37fSEvan Quan 		pp_display_configuration_change(handle,
15766ddbd37fSEvan Quan 						&adev->pm.pm_display_cfg);
15776ddbd37fSEvan Quan 	}
15786ddbd37fSEvan Quan 
15796ddbd37fSEvan Quan 	pp_dpm_dispatch_tasks(handle,
15806ddbd37fSEvan Quan 			      AMD_PP_TASK_DISPLAY_CONFIG_CHANGE,
15816ddbd37fSEvan Quan 			      NULL);
15826ddbd37fSEvan Quan }
15836ddbd37fSEvan Quan 
1584e098bc96SEvan Quan static const struct amd_pm_funcs pp_dpm_funcs = {
1585e098bc96SEvan Quan 	.load_firmware = pp_dpm_load_fw,
1586e098bc96SEvan Quan 	.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
1587e098bc96SEvan Quan 	.force_performance_level = pp_dpm_force_performance_level,
1588e098bc96SEvan Quan 	.get_performance_level = pp_dpm_get_performance_level,
1589e098bc96SEvan Quan 	.get_current_power_state = pp_dpm_get_current_power_state,
1590e098bc96SEvan Quan 	.dispatch_tasks = pp_dpm_dispatch_tasks,
1591e098bc96SEvan Quan 	.set_fan_control_mode = pp_dpm_set_fan_control_mode,
1592e098bc96SEvan Quan 	.get_fan_control_mode = pp_dpm_get_fan_control_mode,
15930d8318e1SEvan Quan 	.set_fan_speed_pwm = pp_dpm_set_fan_speed_pwm,
15940d8318e1SEvan Quan 	.get_fan_speed_pwm = pp_dpm_get_fan_speed_pwm,
1595e098bc96SEvan Quan 	.get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm,
1596e098bc96SEvan Quan 	.set_fan_speed_rpm = pp_dpm_set_fan_speed_rpm,
1597e098bc96SEvan Quan 	.get_pp_num_states = pp_dpm_get_pp_num_states,
1598e098bc96SEvan Quan 	.get_pp_table = pp_dpm_get_pp_table,
1599e098bc96SEvan Quan 	.set_pp_table = pp_dpm_set_pp_table,
1600e098bc96SEvan Quan 	.force_clock_level = pp_dpm_force_clock_level,
16015d8539d2SDarren Powell 	.emit_clock_levels = pp_dpm_emit_clock_levels,
1602e098bc96SEvan Quan 	.print_clock_levels = pp_dpm_print_clock_levels,
1603e098bc96SEvan Quan 	.get_sclk_od = pp_dpm_get_sclk_od,
1604e098bc96SEvan Quan 	.set_sclk_od = pp_dpm_set_sclk_od,
1605e098bc96SEvan Quan 	.get_mclk_od = pp_dpm_get_mclk_od,
1606e098bc96SEvan Quan 	.set_mclk_od = pp_dpm_set_mclk_od,
1607e098bc96SEvan Quan 	.read_sensor = pp_dpm_read_sensor,
1608e098bc96SEvan Quan 	.get_vce_clock_state = pp_dpm_get_vce_clock_state,
1609e098bc96SEvan Quan 	.switch_power_profile = pp_dpm_switch_power_profile,
1610e098bc96SEvan Quan 	.set_clockgating_by_smu = pp_set_clockgating_by_smu,
1611e098bc96SEvan Quan 	.set_powergating_by_smu = pp_set_powergating_by_smu,
1612e098bc96SEvan Quan 	.get_power_profile_mode = pp_get_power_profile_mode,
1613e098bc96SEvan Quan 	.set_power_profile_mode = pp_set_power_profile_mode,
161412a6727dSXiaojian Du 	.set_fine_grain_clk_vol = pp_set_fine_grain_clk_vol,
1615e098bc96SEvan Quan 	.odn_edit_dpm_table = pp_odn_edit_dpm_table,
1616e098bc96SEvan Quan 	.set_mp1_state = pp_dpm_set_mp1_state,
1617e098bc96SEvan Quan 	.set_power_limit = pp_set_power_limit,
1618e098bc96SEvan Quan 	.get_power_limit = pp_get_power_limit,
1619e098bc96SEvan Quan /* export to DC */
1620e098bc96SEvan Quan 	.get_sclk = pp_dpm_get_sclk,
1621e098bc96SEvan Quan 	.get_mclk = pp_dpm_get_mclk,
1622e098bc96SEvan Quan 	.display_configuration_change = pp_display_configuration_change,
1623e098bc96SEvan Quan 	.get_display_power_level = pp_get_display_power_level,
1624e098bc96SEvan Quan 	.get_current_clocks = pp_get_current_clocks,
1625e098bc96SEvan Quan 	.get_clock_by_type = pp_get_clock_by_type,
1626e098bc96SEvan Quan 	.get_clock_by_type_with_latency = pp_get_clock_by_type_with_latency,
1627e098bc96SEvan Quan 	.get_clock_by_type_with_voltage = pp_get_clock_by_type_with_voltage,
1628e098bc96SEvan Quan 	.set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges,
1629e098bc96SEvan Quan 	.display_clock_voltage_request = pp_display_clock_voltage_request,
1630e098bc96SEvan Quan 	.get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks,
1631e098bc96SEvan Quan 	.notify_smu_enable_pwe = pp_notify_smu_enable_pwe,
1632e098bc96SEvan Quan 	.enable_mgpu_fan_boost = pp_enable_mgpu_fan_boost,
1633e098bc96SEvan Quan 	.set_active_display_count = pp_set_active_display_count,
1634e098bc96SEvan Quan 	.set_min_deep_sleep_dcefclk = pp_set_min_deep_sleep_dcefclk,
1635e098bc96SEvan Quan 	.set_hard_min_dcefclk_by_freq = pp_set_hard_min_dcefclk_by_freq,
1636e098bc96SEvan Quan 	.set_hard_min_fclk_by_freq = pp_set_hard_min_fclk_by_freq,
1637e098bc96SEvan Quan 	.get_asic_baco_capability = pp_get_asic_baco_capability,
1638e098bc96SEvan Quan 	.get_asic_baco_state = pp_get_asic_baco_state,
1639e098bc96SEvan Quan 	.set_asic_baco_state = pp_set_asic_baco_state,
1640e098bc96SEvan Quan 	.get_ppfeature_status = pp_get_ppfeature_status,
1641e098bc96SEvan Quan 	.set_ppfeature_status = pp_set_ppfeature_status,
1642e098bc96SEvan Quan 	.asic_reset_mode_2 = pp_asic_reset_mode_2,
1643e098bc96SEvan Quan 	.smu_i2c_bus_access = pp_smu_i2c_bus_access,
1644e098bc96SEvan Quan 	.set_df_cstate = pp_set_df_cstate,
1645e098bc96SEvan Quan 	.set_xgmi_pstate = pp_set_xgmi_pstate,
1646e098bc96SEvan Quan 	.get_gpu_metrics = pp_get_gpu_metrics,
1647d90a53d6SPrike Liang 	.gfx_state_change_set = pp_gfx_state_change_set,
1648b8c78bdbSLijo Lazar 	.get_smu_prv_buf_details = pp_get_prv_buffer_details,
16496ddbd37fSEvan Quan 	.pm_compute_clocks = pp_pm_compute_clocks,
1650e098bc96SEvan Quan };
1651