xref: /dragonfly/sys/dev/drm/amd/amdgpu/amdgpu_pm.c (revision 78973132)
1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev  * Copyright 2017 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  * Authors: Rafał Miłecki <zajec5@gmail.com>
23b843c749SSergey Zigachev  *          Alex Deucher <alexdeucher@gmail.com>
24b843c749SSergey Zigachev  */
25b843c749SSergey Zigachev #include <drm/drmP.h>
26b843c749SSergey Zigachev #include "amdgpu.h"
27b843c749SSergey Zigachev #include "amdgpu_drv.h"
28b843c749SSergey Zigachev #include "amdgpu_pm.h"
29b843c749SSergey Zigachev #include "amdgpu_dpm.h"
30b843c749SSergey Zigachev #include "atom.h"
31b843c749SSergey Zigachev #include <linux/power_supply.h>
32b843c749SSergey Zigachev #include <linux/hwmon.h>
33*78973132SSergey Zigachev #if 0
34b843c749SSergey Zigachev #include <linux/hwmon-sysfs.h>
35b843c749SSergey Zigachev #include <linux/nospec.h>
36*78973132SSergey Zigachev #endif
37b843c749SSergey Zigachev 
38b843c749SSergey Zigachev static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
39b843c749SSergey Zigachev 
40*78973132SSergey Zigachev #if 0
41b843c749SSergey Zigachev static const struct cg_flag_name clocks[] = {
42b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_MGCG, "Graphics Medium Grain Clock Gating"},
43b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_MGLS, "Graphics Medium Grain memory Light Sleep"},
44b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_CGCG, "Graphics Coarse Grain Clock Gating"},
45b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_CGLS, "Graphics Coarse Grain memory Light Sleep"},
46b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_CGTS, "Graphics Coarse Grain Tree Shader Clock Gating"},
47b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_CGTS_LS, "Graphics Coarse Grain Tree Shader Light Sleep"},
48b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_CP_LS, "Graphics Command Processor Light Sleep"},
49b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_RLC_LS, "Graphics Run List Controller Light Sleep"},
50b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_3D_CGCG, "Graphics 3D Coarse Grain Clock Gating"},
51b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_GFX_3D_CGLS, "Graphics 3D Coarse Grain memory Light Sleep"},
52b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_MC_LS, "Memory Controller Light Sleep"},
53b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_MC_MGCG, "Memory Controller Medium Grain Clock Gating"},
54b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_SDMA_LS, "System Direct Memory Access Light Sleep"},
55b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_SDMA_MGCG, "System Direct Memory Access Medium Grain Clock Gating"},
56b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_BIF_MGCG, "Bus Interface Medium Grain Clock Gating"},
57b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_BIF_LS, "Bus Interface Light Sleep"},
58b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_UVD_MGCG, "Unified Video Decoder Medium Grain Clock Gating"},
59b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_VCE_MGCG, "Video Compression Engine Medium Grain Clock Gating"},
60b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_HDP_LS, "Host Data Path Light Sleep"},
61b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_HDP_MGCG, "Host Data Path Medium Grain Clock Gating"},
62b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_DRM_MGCG, "Digital Right Management Medium Grain Clock Gating"},
63b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_DRM_LS, "Digital Right Management Light Sleep"},
64b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_ROM_MGCG, "Rom Medium Grain Clock Gating"},
65b843c749SSergey Zigachev 	{AMD_CG_SUPPORT_DF_MGCG, "Data Fabric Medium Grain Clock Gating"},
66b843c749SSergey Zigachev 	{0, NULL},
67b843c749SSergey Zigachev };
68*78973132SSergey Zigachev #endif
69b843c749SSergey Zigachev 
amdgpu_pm_acpi_event_handler(struct amdgpu_device * adev)70b843c749SSergey Zigachev void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
71b843c749SSergey Zigachev {
72b843c749SSergey Zigachev 	if (adev->pm.dpm_enabled) {
73b843c749SSergey Zigachev 		mutex_lock(&adev->pm.mutex);
74b843c749SSergey Zigachev 		if (power_supply_is_system_supplied() > 0)
75b843c749SSergey Zigachev 			adev->pm.ac_power = true;
76b843c749SSergey Zigachev 		else
77b843c749SSergey Zigachev 			adev->pm.ac_power = false;
78b843c749SSergey Zigachev 		if (adev->powerplay.pp_funcs &&
79b843c749SSergey Zigachev 		    adev->powerplay.pp_funcs->enable_bapm)
80b843c749SSergey Zigachev 			amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
81b843c749SSergey Zigachev 		mutex_unlock(&adev->pm.mutex);
82b843c749SSergey Zigachev 	}
83b843c749SSergey Zigachev }
84b843c749SSergey Zigachev 
85b843c749SSergey Zigachev /**
86b843c749SSergey Zigachev  * DOC: power_dpm_state
87b843c749SSergey Zigachev  *
88b843c749SSergey Zigachev  * The power_dpm_state file is a legacy interface and is only provided for
89b843c749SSergey Zigachev  * backwards compatibility. The amdgpu driver provides a sysfs API for adjusting
90b843c749SSergey Zigachev  * certain power related parameters.  The file power_dpm_state is used for this.
91b843c749SSergey Zigachev  * It accepts the following arguments:
92b843c749SSergey Zigachev  *
93b843c749SSergey Zigachev  * - battery
94b843c749SSergey Zigachev  *
95b843c749SSergey Zigachev  * - balanced
96b843c749SSergey Zigachev  *
97b843c749SSergey Zigachev  * - performance
98b843c749SSergey Zigachev  *
99b843c749SSergey Zigachev  * battery
100b843c749SSergey Zigachev  *
101b843c749SSergey Zigachev  * On older GPUs, the vbios provided a special power state for battery
102b843c749SSergey Zigachev  * operation.  Selecting battery switched to this state.  This is no
103b843c749SSergey Zigachev  * longer provided on newer GPUs so the option does nothing in that case.
104b843c749SSergey Zigachev  *
105b843c749SSergey Zigachev  * balanced
106b843c749SSergey Zigachev  *
107b843c749SSergey Zigachev  * On older GPUs, the vbios provided a special power state for balanced
108b843c749SSergey Zigachev  * operation.  Selecting balanced switched to this state.  This is no
109b843c749SSergey Zigachev  * longer provided on newer GPUs so the option does nothing in that case.
110b843c749SSergey Zigachev  *
111b843c749SSergey Zigachev  * performance
112b843c749SSergey Zigachev  *
113b843c749SSergey Zigachev  * On older GPUs, the vbios provided a special power state for performance
114b843c749SSergey Zigachev  * operation.  Selecting performance switched to this state.  This is no
115b843c749SSergey Zigachev  * longer provided on newer GPUs so the option does nothing in that case.
116b843c749SSergey Zigachev  *
117b843c749SSergey Zigachev  */
118*78973132SSergey Zigachev #if 0
119b843c749SSergey Zigachev static ssize_t amdgpu_get_dpm_state(struct device *dev,
120b843c749SSergey Zigachev 				    struct device_attribute *attr,
121b843c749SSergey Zigachev 				    char *buf)
122b843c749SSergey Zigachev {
123b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
124b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
125b843c749SSergey Zigachev 	enum amd_pm_state_type pm;
126b843c749SSergey Zigachev 
127b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_current_power_state)
128b843c749SSergey Zigachev 		pm = amdgpu_dpm_get_current_power_state(adev);
129b843c749SSergey Zigachev 	else
130b843c749SSergey Zigachev 		pm = adev->pm.dpm.user_state;
131b843c749SSergey Zigachev 
132b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%s\n",
133b843c749SSergey Zigachev 			(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
134b843c749SSergey Zigachev 			(pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
135b843c749SSergey Zigachev }
136b843c749SSergey Zigachev 
137b843c749SSergey Zigachev static ssize_t amdgpu_set_dpm_state(struct device *dev,
138b843c749SSergey Zigachev 				    struct device_attribute *attr,
139b843c749SSergey Zigachev 				    const char *buf,
140b843c749SSergey Zigachev 				    size_t count)
141b843c749SSergey Zigachev {
142b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
143b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
144b843c749SSergey Zigachev 	enum amd_pm_state_type  state;
145b843c749SSergey Zigachev 
146b843c749SSergey Zigachev 	if (strncmp("battery", buf, strlen("battery")) == 0)
147b843c749SSergey Zigachev 		state = POWER_STATE_TYPE_BATTERY;
148b843c749SSergey Zigachev 	else if (strncmp("balanced", buf, strlen("balanced")) == 0)
149b843c749SSergey Zigachev 		state = POWER_STATE_TYPE_BALANCED;
150b843c749SSergey Zigachev 	else if (strncmp("performance", buf, strlen("performance")) == 0)
151b843c749SSergey Zigachev 		state = POWER_STATE_TYPE_PERFORMANCE;
152b843c749SSergey Zigachev 	else {
153b843c749SSergey Zigachev 		count = -EINVAL;
154b843c749SSergey Zigachev 		goto fail;
155b843c749SSergey Zigachev 	}
156b843c749SSergey Zigachev 
157b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->dispatch_tasks) {
158b843c749SSergey Zigachev 		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_ENABLE_USER_STATE, &state);
159b843c749SSergey Zigachev 	} else {
160b843c749SSergey Zigachev 		mutex_lock(&adev->pm.mutex);
161b843c749SSergey Zigachev 		adev->pm.dpm.user_state = state;
162b843c749SSergey Zigachev 		mutex_unlock(&adev->pm.mutex);
163b843c749SSergey Zigachev 
164b843c749SSergey Zigachev 		/* Can't set dpm state when the card is off */
165b843c749SSergey Zigachev 		if (!(adev->flags & AMD_IS_PX) ||
166b843c749SSergey Zigachev 		    (ddev->switch_power_state == DRM_SWITCH_POWER_ON))
167b843c749SSergey Zigachev 			amdgpu_pm_compute_clocks(adev);
168b843c749SSergey Zigachev 	}
169b843c749SSergey Zigachev fail:
170b843c749SSergey Zigachev 	return count;
171b843c749SSergey Zigachev }
172b843c749SSergey Zigachev 
173b843c749SSergey Zigachev 
174b843c749SSergey Zigachev /**
175b843c749SSergey Zigachev  * DOC: power_dpm_force_performance_level
176b843c749SSergey Zigachev  *
177b843c749SSergey Zigachev  * The amdgpu driver provides a sysfs API for adjusting certain power
178b843c749SSergey Zigachev  * related parameters.  The file power_dpm_force_performance_level is
179b843c749SSergey Zigachev  * used for this.  It accepts the following arguments:
180b843c749SSergey Zigachev  *
181b843c749SSergey Zigachev  * - auto
182b843c749SSergey Zigachev  *
183b843c749SSergey Zigachev  * - low
184b843c749SSergey Zigachev  *
185b843c749SSergey Zigachev  * - high
186b843c749SSergey Zigachev  *
187b843c749SSergey Zigachev  * - manual
188b843c749SSergey Zigachev  *
189b843c749SSergey Zigachev  * - profile_standard
190b843c749SSergey Zigachev  *
191b843c749SSergey Zigachev  * - profile_min_sclk
192b843c749SSergey Zigachev  *
193b843c749SSergey Zigachev  * - profile_min_mclk
194b843c749SSergey Zigachev  *
195b843c749SSergey Zigachev  * - profile_peak
196b843c749SSergey Zigachev  *
197b843c749SSergey Zigachev  * auto
198b843c749SSergey Zigachev  *
199b843c749SSergey Zigachev  * When auto is selected, the driver will attempt to dynamically select
200b843c749SSergey Zigachev  * the optimal power profile for current conditions in the driver.
201b843c749SSergey Zigachev  *
202b843c749SSergey Zigachev  * low
203b843c749SSergey Zigachev  *
204b843c749SSergey Zigachev  * When low is selected, the clocks are forced to the lowest power state.
205b843c749SSergey Zigachev  *
206b843c749SSergey Zigachev  * high
207b843c749SSergey Zigachev  *
208b843c749SSergey Zigachev  * When high is selected, the clocks are forced to the highest power state.
209b843c749SSergey Zigachev  *
210b843c749SSergey Zigachev  * manual
211b843c749SSergey Zigachev  *
212b843c749SSergey Zigachev  * When manual is selected, the user can manually adjust which power states
213b843c749SSergey Zigachev  * are enabled for each clock domain via the sysfs pp_dpm_mclk, pp_dpm_sclk,
214b843c749SSergey Zigachev  * and pp_dpm_pcie files and adjust the power state transition heuristics
215b843c749SSergey Zigachev  * via the pp_power_profile_mode sysfs file.
216b843c749SSergey Zigachev  *
217b843c749SSergey Zigachev  * profile_standard
218b843c749SSergey Zigachev  * profile_min_sclk
219b843c749SSergey Zigachev  * profile_min_mclk
220b843c749SSergey Zigachev  * profile_peak
221b843c749SSergey Zigachev  *
222b843c749SSergey Zigachev  * When the profiling modes are selected, clock and power gating are
223b843c749SSergey Zigachev  * disabled and the clocks are set for different profiling cases. This
224b843c749SSergey Zigachev  * mode is recommended for profiling specific work loads where you do
225b843c749SSergey Zigachev  * not want clock or power gating for clock fluctuation to interfere
226b843c749SSergey Zigachev  * with your results. profile_standard sets the clocks to a fixed clock
227b843c749SSergey Zigachev  * level which varies from asic to asic.  profile_min_sclk forces the sclk
228b843c749SSergey Zigachev  * to the lowest level.  profile_min_mclk forces the mclk to the lowest level.
229b843c749SSergey Zigachev  * profile_peak sets all clocks (mclk, sclk, pcie) to the highest levels.
230b843c749SSergey Zigachev  *
231b843c749SSergey Zigachev  */
232b843c749SSergey Zigachev 
233b843c749SSergey Zigachev static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
234b843c749SSergey Zigachev 						struct device_attribute *attr,
235b843c749SSergey Zigachev 								char *buf)
236b843c749SSergey Zigachev {
237b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
238b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
239b843c749SSergey Zigachev 	enum amd_dpm_forced_level level = 0xff;
240b843c749SSergey Zigachev 
241b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
242b843c749SSergey Zigachev 	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
243b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "off\n");
244b843c749SSergey Zigachev 
245b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_performance_level)
246b843c749SSergey Zigachev 		level = amdgpu_dpm_get_performance_level(adev);
247b843c749SSergey Zigachev 	else
248b843c749SSergey Zigachev 		level = adev->pm.dpm.forced_level;
249b843c749SSergey Zigachev 
250b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%s\n",
251b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
252b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" :
253b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_HIGH) ? "high" :
254b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_MANUAL) ? "manual" :
255b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD) ? "profile_standard" :
256b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) ? "profile_min_sclk" :
257b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) ? "profile_min_mclk" :
258b843c749SSergey Zigachev 			(level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) ? "profile_peak" :
259b843c749SSergey Zigachev 			"unknown");
260b843c749SSergey Zigachev }
261b843c749SSergey Zigachev 
262b843c749SSergey Zigachev static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
263b843c749SSergey Zigachev 						       struct device_attribute *attr,
264b843c749SSergey Zigachev 						       const char *buf,
265b843c749SSergey Zigachev 						       size_t count)
266b843c749SSergey Zigachev {
267b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
268b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
269b843c749SSergey Zigachev 	enum amd_dpm_forced_level level;
270b843c749SSergey Zigachev 	enum amd_dpm_forced_level current_level = 0xff;
271b843c749SSergey Zigachev 	int ret = 0;
272b843c749SSergey Zigachev 
273b843c749SSergey Zigachev 	/* Can't force performance level when the card is off */
274b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
275b843c749SSergey Zigachev 	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
276b843c749SSergey Zigachev 		return -EINVAL;
277b843c749SSergey Zigachev 
278b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_performance_level)
279b843c749SSergey Zigachev 		current_level = amdgpu_dpm_get_performance_level(adev);
280b843c749SSergey Zigachev 
281b843c749SSergey Zigachev 	if (strncmp("low", buf, strlen("low")) == 0) {
282b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_LOW;
283b843c749SSergey Zigachev 	} else if (strncmp("high", buf, strlen("high")) == 0) {
284b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_HIGH;
285b843c749SSergey Zigachev 	} else if (strncmp("auto", buf, strlen("auto")) == 0) {
286b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_AUTO;
287b843c749SSergey Zigachev 	} else if (strncmp("manual", buf, strlen("manual")) == 0) {
288b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_MANUAL;
289b843c749SSergey Zigachev 	} else if (strncmp("profile_exit", buf, strlen("profile_exit")) == 0) {
290b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_PROFILE_EXIT;
291b843c749SSergey Zigachev 	} else if (strncmp("profile_standard", buf, strlen("profile_standard")) == 0) {
292b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD;
293b843c749SSergey Zigachev 	} else if (strncmp("profile_min_sclk", buf, strlen("profile_min_sclk")) == 0) {
294b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK;
295b843c749SSergey Zigachev 	} else if (strncmp("profile_min_mclk", buf, strlen("profile_min_mclk")) == 0) {
296b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK;
297b843c749SSergey Zigachev 	} else if (strncmp("profile_peak", buf, strlen("profile_peak")) == 0) {
298b843c749SSergey Zigachev 		level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
299b843c749SSergey Zigachev 	}  else {
300b843c749SSergey Zigachev 		count = -EINVAL;
301b843c749SSergey Zigachev 		goto fail;
302b843c749SSergey Zigachev 	}
303b843c749SSergey Zigachev 
304b843c749SSergey Zigachev 	if (current_level == level)
305b843c749SSergey Zigachev 		return count;
306b843c749SSergey Zigachev 
307b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->force_performance_level) {
308b843c749SSergey Zigachev 		mutex_lock(&adev->pm.mutex);
309b843c749SSergey Zigachev 		if (adev->pm.dpm.thermal_active) {
310b843c749SSergey Zigachev 			count = -EINVAL;
311b843c749SSergey Zigachev 			mutex_unlock(&adev->pm.mutex);
312b843c749SSergey Zigachev 			goto fail;
313b843c749SSergey Zigachev 		}
314b843c749SSergey Zigachev 		ret = amdgpu_dpm_force_performance_level(adev, level);
315b843c749SSergey Zigachev 		if (ret)
316b843c749SSergey Zigachev 			count = -EINVAL;
317b843c749SSergey Zigachev 		else
318b843c749SSergey Zigachev 			adev->pm.dpm.forced_level = level;
319b843c749SSergey Zigachev 		mutex_unlock(&adev->pm.mutex);
320b843c749SSergey Zigachev 	}
321b843c749SSergey Zigachev 
322b843c749SSergey Zigachev fail:
323b843c749SSergey Zigachev 	return count;
324b843c749SSergey Zigachev }
325b843c749SSergey Zigachev 
326b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_num_states(struct device *dev,
327b843c749SSergey Zigachev 		struct device_attribute *attr,
328b843c749SSergey Zigachev 		char *buf)
329b843c749SSergey Zigachev {
330b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
331b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
332b843c749SSergey Zigachev 	struct pp_states_info data;
333b843c749SSergey Zigachev 	int i, buf_len;
334b843c749SSergey Zigachev 
335b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_pp_num_states)
336b843c749SSergey Zigachev 		amdgpu_dpm_get_pp_num_states(adev, &data);
337b843c749SSergey Zigachev 
338b843c749SSergey Zigachev 	buf_len = snprintf(buf, PAGE_SIZE, "states: %d\n", data.nums);
339b843c749SSergey Zigachev 	for (i = 0; i < data.nums; i++)
340b843c749SSergey Zigachev 		buf_len += snprintf(buf + buf_len, PAGE_SIZE, "%d %s\n", i,
341b843c749SSergey Zigachev 				(data.states[i] == POWER_STATE_TYPE_INTERNAL_BOOT) ? "boot" :
342b843c749SSergey Zigachev 				(data.states[i] == POWER_STATE_TYPE_BATTERY) ? "battery" :
343b843c749SSergey Zigachev 				(data.states[i] == POWER_STATE_TYPE_BALANCED) ? "balanced" :
344b843c749SSergey Zigachev 				(data.states[i] == POWER_STATE_TYPE_PERFORMANCE) ? "performance" : "default");
345b843c749SSergey Zigachev 
346b843c749SSergey Zigachev 	return buf_len;
347b843c749SSergey Zigachev }
348b843c749SSergey Zigachev 
349b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_cur_state(struct device *dev,
350b843c749SSergey Zigachev 		struct device_attribute *attr,
351b843c749SSergey Zigachev 		char *buf)
352b843c749SSergey Zigachev {
353b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
354b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
355b843c749SSergey Zigachev 	struct pp_states_info data;
356b843c749SSergey Zigachev 	enum amd_pm_state_type pm = 0;
357b843c749SSergey Zigachev 	int i = 0;
358b843c749SSergey Zigachev 
359b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_current_power_state
360b843c749SSergey Zigachev 		 && adev->powerplay.pp_funcs->get_pp_num_states) {
361b843c749SSergey Zigachev 		pm = amdgpu_dpm_get_current_power_state(adev);
362b843c749SSergey Zigachev 		amdgpu_dpm_get_pp_num_states(adev, &data);
363b843c749SSergey Zigachev 
364b843c749SSergey Zigachev 		for (i = 0; i < data.nums; i++) {
365b843c749SSergey Zigachev 			if (pm == data.states[i])
366b843c749SSergey Zigachev 				break;
367b843c749SSergey Zigachev 		}
368b843c749SSergey Zigachev 
369b843c749SSergey Zigachev 		if (i == data.nums)
370b843c749SSergey Zigachev 			i = -EINVAL;
371b843c749SSergey Zigachev 	}
372b843c749SSergey Zigachev 
373b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", i);
374b843c749SSergey Zigachev }
375b843c749SSergey Zigachev 
376b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_force_state(struct device *dev,
377b843c749SSergey Zigachev 		struct device_attribute *attr,
378b843c749SSergey Zigachev 		char *buf)
379b843c749SSergey Zigachev {
380b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
381b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
382b843c749SSergey Zigachev 
383b843c749SSergey Zigachev 	if (adev->pp_force_state_enabled)
384b843c749SSergey Zigachev 		return amdgpu_get_pp_cur_state(dev, attr, buf);
385b843c749SSergey Zigachev 	else
386b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
387b843c749SSergey Zigachev }
388b843c749SSergey Zigachev 
389b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_force_state(struct device *dev,
390b843c749SSergey Zigachev 		struct device_attribute *attr,
391b843c749SSergey Zigachev 		const char *buf,
392b843c749SSergey Zigachev 		size_t count)
393b843c749SSergey Zigachev {
394*78973132SSergey Zigachev #if 0
395b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
396b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
397b843c749SSergey Zigachev 	enum amd_pm_state_type state = 0;
398b843c749SSergey Zigachev 	unsigned long idx;
399b843c749SSergey Zigachev 	int ret;
400b843c749SSergey Zigachev 
401b843c749SSergey Zigachev 	if (strlen(buf) == 1)
402b843c749SSergey Zigachev 		adev->pp_force_state_enabled = false;
403b843c749SSergey Zigachev 	else if (adev->powerplay.pp_funcs->dispatch_tasks &&
404b843c749SSergey Zigachev 			adev->powerplay.pp_funcs->get_pp_num_states) {
405b843c749SSergey Zigachev 		struct pp_states_info data;
406b843c749SSergey Zigachev 
407b843c749SSergey Zigachev 		ret = kstrtoul(buf, 0, &idx);
408b843c749SSergey Zigachev 		if (ret || idx >= ARRAY_SIZE(data.states)) {
409b843c749SSergey Zigachev 			count = -EINVAL;
410b843c749SSergey Zigachev 			goto fail;
411b843c749SSergey Zigachev 		}
412b843c749SSergey Zigachev 		idx = array_index_nospec(idx, ARRAY_SIZE(data.states));
413b843c749SSergey Zigachev 
414b843c749SSergey Zigachev 		amdgpu_dpm_get_pp_num_states(adev, &data);
415b843c749SSergey Zigachev 		state = data.states[idx];
416b843c749SSergey Zigachev 		/* only set user selected power states */
417b843c749SSergey Zigachev 		if (state != POWER_STATE_TYPE_INTERNAL_BOOT &&
418b843c749SSergey Zigachev 		    state != POWER_STATE_TYPE_DEFAULT) {
419b843c749SSergey Zigachev 			amdgpu_dpm_dispatch_task(adev,
420b843c749SSergey Zigachev 					AMD_PP_TASK_ENABLE_USER_STATE, &state);
421b843c749SSergey Zigachev 			adev->pp_force_state_enabled = true;
422b843c749SSergey Zigachev 		}
423b843c749SSergey Zigachev 	}
424b843c749SSergey Zigachev fail:
425b843c749SSergey Zigachev 	return count;
426*78973132SSergey Zigachev #endif
427*78973132SSergey Zigachev 	return -EINVAL;
428b843c749SSergey Zigachev }
429b843c749SSergey Zigachev 
430b843c749SSergey Zigachev /**
431b843c749SSergey Zigachev  * DOC: pp_table
432b843c749SSergey Zigachev  *
433b843c749SSergey Zigachev  * The amdgpu driver provides a sysfs API for uploading new powerplay
434b843c749SSergey Zigachev  * tables.  The file pp_table is used for this.  Reading the file
435b843c749SSergey Zigachev  * will dump the current power play table.  Writing to the file
436b843c749SSergey Zigachev  * will attempt to upload a new powerplay table and re-initialize
437b843c749SSergey Zigachev  * powerplay using that new table.
438b843c749SSergey Zigachev  *
439b843c749SSergey Zigachev  */
440b843c749SSergey Zigachev 
441b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_table(struct device *dev,
442b843c749SSergey Zigachev 		struct device_attribute *attr,
443b843c749SSergey Zigachev 		char *buf)
444b843c749SSergey Zigachev {
445b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
446b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
447b843c749SSergey Zigachev 	char *table = NULL;
448b843c749SSergey Zigachev 	int size;
449b843c749SSergey Zigachev 
450b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_pp_table)
451b843c749SSergey Zigachev 		size = amdgpu_dpm_get_pp_table(adev, &table);
452b843c749SSergey Zigachev 	else
453b843c749SSergey Zigachev 		return 0;
454b843c749SSergey Zigachev 
455b843c749SSergey Zigachev 	if (size >= PAGE_SIZE)
456b843c749SSergey Zigachev 		size = PAGE_SIZE - 1;
457b843c749SSergey Zigachev 
458b843c749SSergey Zigachev 	memcpy(buf, table, size);
459b843c749SSergey Zigachev 
460b843c749SSergey Zigachev 	return size;
461b843c749SSergey Zigachev }
462b843c749SSergey Zigachev 
463b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_table(struct device *dev,
464b843c749SSergey Zigachev 		struct device_attribute *attr,
465b843c749SSergey Zigachev 		const char *buf,
466b843c749SSergey Zigachev 		size_t count)
467b843c749SSergey Zigachev {
468b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
469b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
470b843c749SSergey Zigachev 
471b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->set_pp_table)
472b843c749SSergey Zigachev 		amdgpu_dpm_set_pp_table(adev, buf, count);
473b843c749SSergey Zigachev 
474b843c749SSergey Zigachev 	return count;
475b843c749SSergey Zigachev }
476b843c749SSergey Zigachev 
477b843c749SSergey Zigachev /**
478b843c749SSergey Zigachev  * DOC: pp_od_clk_voltage
479b843c749SSergey Zigachev  *
480b843c749SSergey Zigachev  * The amdgpu driver provides a sysfs API for adjusting the clocks and voltages
481b843c749SSergey Zigachev  * in each power level within a power state.  The pp_od_clk_voltage is used for
482b843c749SSergey Zigachev  * this.
483b843c749SSergey Zigachev  *
484b843c749SSergey Zigachev  * Reading the file will display:
485b843c749SSergey Zigachev  *
486b843c749SSergey Zigachev  * - a list of engine clock levels and voltages labeled OD_SCLK
487b843c749SSergey Zigachev  *
488b843c749SSergey Zigachev  * - a list of memory clock levels and voltages labeled OD_MCLK
489b843c749SSergey Zigachev  *
490b843c749SSergey Zigachev  * - a list of valid ranges for sclk, mclk, and voltage labeled OD_RANGE
491b843c749SSergey Zigachev  *
492b843c749SSergey Zigachev  * To manually adjust these settings, first select manual using
493b843c749SSergey Zigachev  * power_dpm_force_performance_level. Enter a new value for each
494b843c749SSergey Zigachev  * level by writing a string that contains "s/m level clock voltage" to
495b843c749SSergey Zigachev  * the file.  E.g., "s 1 500 820" will update sclk level 1 to be 500 MHz
496b843c749SSergey Zigachev  * at 820 mV; "m 0 350 810" will update mclk level 0 to be 350 MHz at
497b843c749SSergey Zigachev  * 810 mV.  When you have edited all of the states as needed, write
498b843c749SSergey Zigachev  * "c" (commit) to the file to commit your changes.  If you want to reset to the
499b843c749SSergey Zigachev  * default power levels, write "r" (reset) to the file to reset them.
500b843c749SSergey Zigachev  *
501b843c749SSergey Zigachev  */
502b843c749SSergey Zigachev 
503b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
504b843c749SSergey Zigachev 		struct device_attribute *attr,
505b843c749SSergey Zigachev 		const char *buf,
506b843c749SSergey Zigachev 		size_t count)
507b843c749SSergey Zigachev {
508b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
509b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
510b843c749SSergey Zigachev 	int ret;
511b843c749SSergey Zigachev 	uint32_t parameter_size = 0;
512b843c749SSergey Zigachev 	long parameter[64];
513b843c749SSergey Zigachev 	char buf_cpy[128];
514b843c749SSergey Zigachev 	char *tmp_str;
515b843c749SSergey Zigachev 	char *sub_str;
516b843c749SSergey Zigachev 	const char delimiter[3] = {' ', '\n', '\0'};
517b843c749SSergey Zigachev 	uint32_t type;
518b843c749SSergey Zigachev 
519b843c749SSergey Zigachev 	if (count > 127)
520b843c749SSergey Zigachev 		return -EINVAL;
521b843c749SSergey Zigachev 
522b843c749SSergey Zigachev 	if (*buf == 's')
523b843c749SSergey Zigachev 		type = PP_OD_EDIT_SCLK_VDDC_TABLE;
524b843c749SSergey Zigachev 	else if (*buf == 'm')
525b843c749SSergey Zigachev 		type = PP_OD_EDIT_MCLK_VDDC_TABLE;
526b843c749SSergey Zigachev 	else if(*buf == 'r')
527b843c749SSergey Zigachev 		type = PP_OD_RESTORE_DEFAULT_TABLE;
528b843c749SSergey Zigachev 	else if (*buf == 'c')
529b843c749SSergey Zigachev 		type = PP_OD_COMMIT_DPM_TABLE;
530b843c749SSergey Zigachev 	else
531b843c749SSergey Zigachev 		return -EINVAL;
532b843c749SSergey Zigachev 
533b843c749SSergey Zigachev 	memcpy(buf_cpy, buf, count+1);
534b843c749SSergey Zigachev 
535b843c749SSergey Zigachev 	tmp_str = buf_cpy;
536b843c749SSergey Zigachev 
537b843c749SSergey Zigachev 	while (isspace(*++tmp_str));
538b843c749SSergey Zigachev 
539b843c749SSergey Zigachev 	while (tmp_str[0]) {
540b843c749SSergey Zigachev 		sub_str = strsep(&tmp_str, delimiter);
541b843c749SSergey Zigachev 		ret = kstrtol(sub_str, 0, &parameter[parameter_size]);
542b843c749SSergey Zigachev 		if (ret)
543b843c749SSergey Zigachev 			return -EINVAL;
544b843c749SSergey Zigachev 		parameter_size++;
545b843c749SSergey Zigachev 
546b843c749SSergey Zigachev 		while (isspace(*tmp_str))
547b843c749SSergey Zigachev 			tmp_str++;
548b843c749SSergey Zigachev 	}
549b843c749SSergey Zigachev 
550b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->odn_edit_dpm_table)
551b843c749SSergey Zigachev 		ret = amdgpu_dpm_odn_edit_dpm_table(adev, type,
552b843c749SSergey Zigachev 						parameter, parameter_size);
553b843c749SSergey Zigachev 
554b843c749SSergey Zigachev 	if (ret)
555b843c749SSergey Zigachev 		return -EINVAL;
556b843c749SSergey Zigachev 
557b843c749SSergey Zigachev 	if (type == PP_OD_COMMIT_DPM_TABLE) {
558b843c749SSergey Zigachev 		if (adev->powerplay.pp_funcs->dispatch_tasks) {
559b843c749SSergey Zigachev 			amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL);
560b843c749SSergey Zigachev 			return count;
561b843c749SSergey Zigachev 		} else {
562b843c749SSergey Zigachev 			return -EINVAL;
563b843c749SSergey Zigachev 		}
564b843c749SSergey Zigachev 	}
565b843c749SSergey Zigachev 
566b843c749SSergey Zigachev 	return count;
567b843c749SSergey Zigachev }
568b843c749SSergey Zigachev 
569b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
570b843c749SSergey Zigachev 		struct device_attribute *attr,
571b843c749SSergey Zigachev 		char *buf)
572b843c749SSergey Zigachev {
573b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
574b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
575b843c749SSergey Zigachev 	uint32_t size = 0;
576b843c749SSergey Zigachev 
577b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->print_clock_levels) {
578b843c749SSergey Zigachev 		size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf);
579b843c749SSergey Zigachev 		size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf+size);
580b843c749SSergey Zigachev 		size += amdgpu_dpm_print_clock_levels(adev, OD_RANGE, buf+size);
581b843c749SSergey Zigachev 		return size;
582b843c749SSergey Zigachev 	} else {
583b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
584b843c749SSergey Zigachev 	}
585b843c749SSergey Zigachev 
586b843c749SSergey Zigachev }
587b843c749SSergey Zigachev 
588b843c749SSergey Zigachev /**
589b843c749SSergey Zigachev  * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
590b843c749SSergey Zigachev  *
591b843c749SSergey Zigachev  * The amdgpu driver provides a sysfs API for adjusting what power levels
592b843c749SSergey Zigachev  * are enabled for a given power state.  The files pp_dpm_sclk, pp_dpm_mclk,
593b843c749SSergey Zigachev  * and pp_dpm_pcie are used for this.
594b843c749SSergey Zigachev  *
595b843c749SSergey Zigachev  * Reading back the files will show you the available power levels within
596b843c749SSergey Zigachev  * the power state and the clock information for those levels.
597b843c749SSergey Zigachev  *
598b843c749SSergey Zigachev  * To manually adjust these states, first select manual using
599b843c749SSergey Zigachev  * power_dpm_force_performance_level.
600b843c749SSergey Zigachev  * Secondly,Enter a new value for each level by inputing a string that
601b843c749SSergey Zigachev  * contains " echo xx xx xx > pp_dpm_sclk/mclk/pcie"
602b843c749SSergey Zigachev  * E.g., echo 4 5 6 to > pp_dpm_sclk will enable sclk levels 4, 5, and 6.
603b843c749SSergey Zigachev  */
604b843c749SSergey Zigachev 
605b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev,
606b843c749SSergey Zigachev 		struct device_attribute *attr,
607b843c749SSergey Zigachev 		char *buf)
608b843c749SSergey Zigachev {
609b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
610b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
611b843c749SSergey Zigachev 
612b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->print_clock_levels)
613b843c749SSergey Zigachev 		return amdgpu_dpm_print_clock_levels(adev, PP_SCLK, buf);
614b843c749SSergey Zigachev 	else
615b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
616b843c749SSergey Zigachev }
617b843c749SSergey Zigachev 
618b843c749SSergey Zigachev /*
619b843c749SSergey Zigachev  * Worst case: 32 bits individually specified, in octal at 12 characters
620b843c749SSergey Zigachev  * per line (+1 for \n).
621b843c749SSergey Zigachev  */
622b843c749SSergey Zigachev #define AMDGPU_MASK_BUF_MAX	(32 * 13)
623b843c749SSergey Zigachev 
624b843c749SSergey Zigachev static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask)
625b843c749SSergey Zigachev {
626b843c749SSergey Zigachev 	int ret;
627b843c749SSergey Zigachev 	unsigned long level;
628b843c749SSergey Zigachev 	char *sub_str = NULL;
629b843c749SSergey Zigachev 	char *tmp;
630b843c749SSergey Zigachev 	char buf_cpy[AMDGPU_MASK_BUF_MAX + 1];
631b843c749SSergey Zigachev 	const char delimiter[3] = {' ', '\n', '\0'};
632b843c749SSergey Zigachev 	size_t bytes;
633b843c749SSergey Zigachev 
634b843c749SSergey Zigachev 	*mask = 0;
635b843c749SSergey Zigachev 
636b843c749SSergey Zigachev 	bytes = min(count, sizeof(buf_cpy) - 1);
637b843c749SSergey Zigachev 	memcpy(buf_cpy, buf, bytes);
638b843c749SSergey Zigachev 	buf_cpy[bytes] = '\0';
639b843c749SSergey Zigachev 	tmp = buf_cpy;
640b843c749SSergey Zigachev 	while (tmp[0]) {
641b843c749SSergey Zigachev 		sub_str = strsep(&tmp, delimiter);
642b843c749SSergey Zigachev 		if (strlen(sub_str)) {
643b843c749SSergey Zigachev 			ret = kstrtoul(sub_str, 0, &level);
644b843c749SSergey Zigachev 			if (ret || level > 31)
645b843c749SSergey Zigachev 				return -EINVAL;
646b843c749SSergey Zigachev 			*mask |= 1 << level;
647b843c749SSergey Zigachev 		} else
648b843c749SSergey Zigachev 			break;
649b843c749SSergey Zigachev 	}
650b843c749SSergey Zigachev 
651b843c749SSergey Zigachev 	return 0;
652b843c749SSergey Zigachev }
653b843c749SSergey Zigachev 
654b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev,
655b843c749SSergey Zigachev 		struct device_attribute *attr,
656b843c749SSergey Zigachev 		const char *buf,
657b843c749SSergey Zigachev 		size_t count)
658b843c749SSergey Zigachev {
659b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
660b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
661b843c749SSergey Zigachev 	int ret;
662b843c749SSergey Zigachev 	uint32_t mask = 0;
663b843c749SSergey Zigachev 
664b843c749SSergey Zigachev 	ret = amdgpu_read_mask(buf, count, &mask);
665b843c749SSergey Zigachev 	if (ret)
666b843c749SSergey Zigachev 		return ret;
667b843c749SSergey Zigachev 
668b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->force_clock_level)
669b843c749SSergey Zigachev 		amdgpu_dpm_force_clock_level(adev, PP_SCLK, mask);
670b843c749SSergey Zigachev 
671b843c749SSergey Zigachev 	return count;
672b843c749SSergey Zigachev }
673b843c749SSergey Zigachev 
674b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_dpm_mclk(struct device *dev,
675b843c749SSergey Zigachev 		struct device_attribute *attr,
676b843c749SSergey Zigachev 		char *buf)
677b843c749SSergey Zigachev {
678b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
679b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
680b843c749SSergey Zigachev 
681b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->print_clock_levels)
682b843c749SSergey Zigachev 		return amdgpu_dpm_print_clock_levels(adev, PP_MCLK, buf);
683b843c749SSergey Zigachev 	else
684b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
685b843c749SSergey Zigachev }
686b843c749SSergey Zigachev 
687b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev,
688b843c749SSergey Zigachev 		struct device_attribute *attr,
689b843c749SSergey Zigachev 		const char *buf,
690b843c749SSergey Zigachev 		size_t count)
691b843c749SSergey Zigachev {
692b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
693b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
694b843c749SSergey Zigachev 	int ret;
695b843c749SSergey Zigachev 	uint32_t mask = 0;
696b843c749SSergey Zigachev 
697b843c749SSergey Zigachev 	ret = amdgpu_read_mask(buf, count, &mask);
698b843c749SSergey Zigachev 	if (ret)
699b843c749SSergey Zigachev 		return ret;
700b843c749SSergey Zigachev 
701b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->force_clock_level)
702b843c749SSergey Zigachev 		amdgpu_dpm_force_clock_level(adev, PP_MCLK, mask);
703b843c749SSergey Zigachev 
704b843c749SSergey Zigachev 	return count;
705b843c749SSergey Zigachev }
706b843c749SSergey Zigachev 
707b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev,
708b843c749SSergey Zigachev 		struct device_attribute *attr,
709b843c749SSergey Zigachev 		char *buf)
710b843c749SSergey Zigachev {
711b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
712b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
713b843c749SSergey Zigachev 
714b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->print_clock_levels)
715b843c749SSergey Zigachev 		return amdgpu_dpm_print_clock_levels(adev, PP_PCIE, buf);
716b843c749SSergey Zigachev 	else
717b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
718b843c749SSergey Zigachev }
719b843c749SSergey Zigachev 
720b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_dpm_pcie(struct device *dev,
721b843c749SSergey Zigachev 		struct device_attribute *attr,
722b843c749SSergey Zigachev 		const char *buf,
723b843c749SSergey Zigachev 		size_t count)
724b843c749SSergey Zigachev {
725b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
726b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
727b843c749SSergey Zigachev 	int ret;
728b843c749SSergey Zigachev 	uint32_t mask = 0;
729b843c749SSergey Zigachev 
730b843c749SSergey Zigachev 	ret = amdgpu_read_mask(buf, count, &mask);
731b843c749SSergey Zigachev 	if (ret)
732b843c749SSergey Zigachev 		return ret;
733b843c749SSergey Zigachev 
734b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->force_clock_level)
735b843c749SSergey Zigachev 		amdgpu_dpm_force_clock_level(adev, PP_PCIE, mask);
736b843c749SSergey Zigachev 
737b843c749SSergey Zigachev 	return count;
738b843c749SSergey Zigachev }
739b843c749SSergey Zigachev 
740b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_sclk_od(struct device *dev,
741b843c749SSergey Zigachev 		struct device_attribute *attr,
742b843c749SSergey Zigachev 		char *buf)
743b843c749SSergey Zigachev {
744b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
745b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
746b843c749SSergey Zigachev 	uint32_t value = 0;
747b843c749SSergey Zigachev 
748b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_sclk_od)
749b843c749SSergey Zigachev 		value = amdgpu_dpm_get_sclk_od(adev);
750b843c749SSergey Zigachev 
751b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", value);
752b843c749SSergey Zigachev }
753b843c749SSergey Zigachev 
754b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_sclk_od(struct device *dev,
755b843c749SSergey Zigachev 		struct device_attribute *attr,
756b843c749SSergey Zigachev 		const char *buf,
757b843c749SSergey Zigachev 		size_t count)
758b843c749SSergey Zigachev {
759b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
760b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
761b843c749SSergey Zigachev 	int ret;
762b843c749SSergey Zigachev 	long int value;
763b843c749SSergey Zigachev 
764b843c749SSergey Zigachev 	ret = kstrtol(buf, 0, &value);
765b843c749SSergey Zigachev 
766b843c749SSergey Zigachev 	if (ret) {
767b843c749SSergey Zigachev 		count = -EINVAL;
768b843c749SSergey Zigachev 		goto fail;
769b843c749SSergey Zigachev 	}
770b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->set_sclk_od)
771b843c749SSergey Zigachev 		amdgpu_dpm_set_sclk_od(adev, (uint32_t)value);
772b843c749SSergey Zigachev 
773b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->dispatch_tasks) {
774b843c749SSergey Zigachev 		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL);
775b843c749SSergey Zigachev 	} else {
776b843c749SSergey Zigachev 		adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps;
777b843c749SSergey Zigachev 		amdgpu_pm_compute_clocks(adev);
778b843c749SSergey Zigachev 	}
779b843c749SSergey Zigachev 
780b843c749SSergey Zigachev fail:
781b843c749SSergey Zigachev 	return count;
782b843c749SSergey Zigachev }
783b843c749SSergey Zigachev 
784*78973132SSergey Zigachev static ssize_t amdgpu_get_pp_sclk_od(struct device *dev,
785*78973132SSergey Zigachev 		struct device_attribute *attr,
786*78973132SSergey Zigachev 		char *buf)
787*78973132SSergey Zigachev {
788*78973132SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
789*78973132SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
790*78973132SSergey Zigachev 	uint32_t value = 0;
791*78973132SSergey Zigachev 
792*78973132SSergey Zigachev 	if (adev->pp_enabled)
793*78973132SSergey Zigachev 		value = amdgpu_dpm_get_sclk_od(adev);
794*78973132SSergey Zigachev 
795*78973132SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", value);
796*78973132SSergey Zigachev }
797*78973132SSergey Zigachev 
798*78973132SSergey Zigachev static ssize_t amdgpu_set_pp_sclk_od(struct device *dev,
799*78973132SSergey Zigachev 		struct device_attribute *attr,
800*78973132SSergey Zigachev 		const char *buf,
801*78973132SSergey Zigachev 		size_t count)
802*78973132SSergey Zigachev {
803*78973132SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
804*78973132SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
805*78973132SSergey Zigachev 	int ret;
806*78973132SSergey Zigachev 	long int value;
807*78973132SSergey Zigachev 
808*78973132SSergey Zigachev 	ret = kstrtol(buf, 0, &value);
809*78973132SSergey Zigachev 
810*78973132SSergey Zigachev 	if (ret) {
811*78973132SSergey Zigachev 		count = -EINVAL;
812*78973132SSergey Zigachev 		goto fail;
813*78973132SSergey Zigachev 	}
814*78973132SSergey Zigachev 
815*78973132SSergey Zigachev 	if (adev->pp_enabled)
816*78973132SSergey Zigachev 		amdgpu_dpm_set_sclk_od(adev, (uint32_t)value);
817*78973132SSergey Zigachev 
818*78973132SSergey Zigachev 	amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_READJUST_POWER_STATE, NULL, NULL);
819*78973132SSergey Zigachev 
820*78973132SSergey Zigachev fail:
821*78973132SSergey Zigachev 	return count;
822*78973132SSergey Zigachev }
823*78973132SSergey Zigachev 
824b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_mclk_od(struct device *dev,
825b843c749SSergey Zigachev 		struct device_attribute *attr,
826b843c749SSergey Zigachev 		char *buf)
827b843c749SSergey Zigachev {
828b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
829b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
830b843c749SSergey Zigachev 	uint32_t value = 0;
831b843c749SSergey Zigachev 
832b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_mclk_od)
833b843c749SSergey Zigachev 		value = amdgpu_dpm_get_mclk_od(adev);
834b843c749SSergey Zigachev 
835b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", value);
836b843c749SSergey Zigachev }
837b843c749SSergey Zigachev 
838b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_mclk_od(struct device *dev,
839b843c749SSergey Zigachev 		struct device_attribute *attr,
840b843c749SSergey Zigachev 		const char *buf,
841b843c749SSergey Zigachev 		size_t count)
842b843c749SSergey Zigachev {
843b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
844b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
845b843c749SSergey Zigachev 	int ret;
846b843c749SSergey Zigachev 	long int value;
847b843c749SSergey Zigachev 
848b843c749SSergey Zigachev 	ret = kstrtol(buf, 0, &value);
849b843c749SSergey Zigachev 
850b843c749SSergey Zigachev 	if (ret) {
851b843c749SSergey Zigachev 		count = -EINVAL;
852b843c749SSergey Zigachev 		goto fail;
853b843c749SSergey Zigachev 	}
854b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->set_mclk_od)
855b843c749SSergey Zigachev 		amdgpu_dpm_set_mclk_od(adev, (uint32_t)value);
856b843c749SSergey Zigachev 
857b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->dispatch_tasks) {
858b843c749SSergey Zigachev 		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL);
859b843c749SSergey Zigachev 	} else {
860b843c749SSergey Zigachev 		adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps;
861b843c749SSergey Zigachev 		amdgpu_pm_compute_clocks(adev);
862b843c749SSergey Zigachev 	}
863b843c749SSergey Zigachev 
864b843c749SSergey Zigachev fail:
865b843c749SSergey Zigachev 	return count;
866b843c749SSergey Zigachev }
867b843c749SSergey Zigachev 
868b843c749SSergey Zigachev /**
869b843c749SSergey Zigachev  * DOC: pp_power_profile_mode
870b843c749SSergey Zigachev  *
871b843c749SSergey Zigachev  * The amdgpu driver provides a sysfs API for adjusting the heuristics
872b843c749SSergey Zigachev  * related to switching between power levels in a power state.  The file
873b843c749SSergey Zigachev  * pp_power_profile_mode is used for this.
874b843c749SSergey Zigachev  *
875b843c749SSergey Zigachev  * Reading this file outputs a list of all of the predefined power profiles
876b843c749SSergey Zigachev  * and the relevant heuristics settings for that profile.
877b843c749SSergey Zigachev  *
878b843c749SSergey Zigachev  * To select a profile or create a custom profile, first select manual using
879b843c749SSergey Zigachev  * power_dpm_force_performance_level.  Writing the number of a predefined
880b843c749SSergey Zigachev  * profile to pp_power_profile_mode will enable those heuristics.  To
881b843c749SSergey Zigachev  * create a custom set of heuristics, write a string of numbers to the file
882b843c749SSergey Zigachev  * starting with the number of the custom profile along with a setting
883b843c749SSergey Zigachev  * for each heuristic parameter.  Due to differences across asic families
884b843c749SSergey Zigachev  * the heuristic parameters vary from family to family.
885b843c749SSergey Zigachev  *
886b843c749SSergey Zigachev  */
887b843c749SSergey Zigachev 
888b843c749SSergey Zigachev static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev,
889b843c749SSergey Zigachev 		struct device_attribute *attr,
890b843c749SSergey Zigachev 		char *buf)
891b843c749SSergey Zigachev {
892b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
893b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
894b843c749SSergey Zigachev 
895b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_power_profile_mode)
896b843c749SSergey Zigachev 		return amdgpu_dpm_get_power_profile_mode(adev, buf);
897b843c749SSergey Zigachev 
898b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "\n");
899b843c749SSergey Zigachev }
900b843c749SSergey Zigachev 
901b843c749SSergey Zigachev 
902b843c749SSergey Zigachev static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
903b843c749SSergey Zigachev 		struct device_attribute *attr,
904b843c749SSergey Zigachev 		const char *buf,
905b843c749SSergey Zigachev 		size_t count)
906b843c749SSergey Zigachev {
907b843c749SSergey Zigachev 	int ret = 0xff;
908b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
909b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
910b843c749SSergey Zigachev 	uint32_t parameter_size = 0;
911b843c749SSergey Zigachev 	long parameter[64];
912b843c749SSergey Zigachev 	char *sub_str, buf_cpy[128];
913b843c749SSergey Zigachev 	char *tmp_str;
914b843c749SSergey Zigachev 	uint32_t i = 0;
915b843c749SSergey Zigachev 	char tmp[2];
916b843c749SSergey Zigachev 	long int profile_mode = 0;
917b843c749SSergey Zigachev 	const char delimiter[3] = {' ', '\n', '\0'};
918b843c749SSergey Zigachev 
919b843c749SSergey Zigachev 	tmp[0] = *(buf);
920b843c749SSergey Zigachev 	tmp[1] = '\0';
921b843c749SSergey Zigachev 	ret = kstrtol(tmp, 0, &profile_mode);
922b843c749SSergey Zigachev 	if (ret)
923b843c749SSergey Zigachev 		goto fail;
924b843c749SSergey Zigachev 
925b843c749SSergey Zigachev 	if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
926b843c749SSergey Zigachev 		if (count < 2 || count > 127)
927b843c749SSergey Zigachev 			return -EINVAL;
928b843c749SSergey Zigachev 		while (isspace(*++buf))
929b843c749SSergey Zigachev 			i++;
930b843c749SSergey Zigachev 		memcpy(buf_cpy, buf, count-i);
931b843c749SSergey Zigachev 		tmp_str = buf_cpy;
932b843c749SSergey Zigachev 		while (tmp_str[0]) {
933b843c749SSergey Zigachev 			sub_str = strsep(&tmp_str, delimiter);
934b843c749SSergey Zigachev 			ret = kstrtol(sub_str, 0, &parameter[parameter_size]);
935b843c749SSergey Zigachev 			if (ret) {
936b843c749SSergey Zigachev 				count = -EINVAL;
937b843c749SSergey Zigachev 				goto fail;
938b843c749SSergey Zigachev 			}
939b843c749SSergey Zigachev 			parameter_size++;
940b843c749SSergey Zigachev 			while (isspace(*tmp_str))
941b843c749SSergey Zigachev 				tmp_str++;
942b843c749SSergey Zigachev 		}
943b843c749SSergey Zigachev 	}
944b843c749SSergey Zigachev 	parameter[parameter_size] = profile_mode;
945b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->set_power_profile_mode)
946b843c749SSergey Zigachev 		ret = amdgpu_dpm_set_power_profile_mode(adev, parameter, parameter_size);
947b843c749SSergey Zigachev 
948b843c749SSergey Zigachev 	if (!ret)
949b843c749SSergey Zigachev 		return count;
950b843c749SSergey Zigachev fail:
951b843c749SSergey Zigachev 	return -EINVAL;
952b843c749SSergey Zigachev }
953b843c749SSergey Zigachev 
954b843c749SSergey Zigachev /**
955b843c749SSergey Zigachev  * DOC: busy_percent
956b843c749SSergey Zigachev  *
957b843c749SSergey Zigachev  * The amdgpu driver provides a sysfs API for reading how busy the GPU
958b843c749SSergey Zigachev  * is as a percentage.  The file gpu_busy_percent is used for this.
959b843c749SSergey Zigachev  * The SMU firmware computes a percentage of load based on the
960b843c749SSergey Zigachev  * aggregate activity level in the IP cores.
961b843c749SSergey Zigachev  */
962b843c749SSergey Zigachev static ssize_t amdgpu_get_busy_percent(struct device *dev,
963b843c749SSergey Zigachev 		struct device_attribute *attr,
964b843c749SSergey Zigachev 		char *buf)
965b843c749SSergey Zigachev {
966b843c749SSergey Zigachev 	struct drm_device *ddev = dev_get_drvdata(dev);
967b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddev->dev_private;
968b843c749SSergey Zigachev 	int r, value, size = sizeof(value);
969b843c749SSergey Zigachev 
970b843c749SSergey Zigachev 	/* sanity check PP is enabled */
971b843c749SSergey Zigachev 	if (!(adev->powerplay.pp_funcs &&
972b843c749SSergey Zigachev 	      adev->powerplay.pp_funcs->read_sensor))
973b843c749SSergey Zigachev 		return -EINVAL;
974b843c749SSergey Zigachev 
975b843c749SSergey Zigachev 	/* read the IP busy sensor */
976b843c749SSergey Zigachev 	r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD,
977b843c749SSergey Zigachev 				   (void *)&value, &size);
978b843c749SSergey Zigachev 	if (r)
979b843c749SSergey Zigachev 		return r;
980b843c749SSergey Zigachev 
981b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", value);
982b843c749SSergey Zigachev }
983b843c749SSergey Zigachev 
984b843c749SSergey Zigachev static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state);
985b843c749SSergey Zigachev static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
986b843c749SSergey Zigachev 		   amdgpu_get_dpm_forced_performance_level,
987b843c749SSergey Zigachev 		   amdgpu_set_dpm_forced_performance_level);
988b843c749SSergey Zigachev static DEVICE_ATTR(pp_num_states, S_IRUGO, amdgpu_get_pp_num_states, NULL);
989b843c749SSergey Zigachev static DEVICE_ATTR(pp_cur_state, S_IRUGO, amdgpu_get_pp_cur_state, NULL);
990b843c749SSergey Zigachev static DEVICE_ATTR(pp_force_state, S_IRUGO | S_IWUSR,
991b843c749SSergey Zigachev 		amdgpu_get_pp_force_state,
992b843c749SSergey Zigachev 		amdgpu_set_pp_force_state);
993b843c749SSergey Zigachev static DEVICE_ATTR(pp_table, S_IRUGO | S_IWUSR,
994b843c749SSergey Zigachev 		amdgpu_get_pp_table,
995b843c749SSergey Zigachev 		amdgpu_set_pp_table);
996b843c749SSergey Zigachev static DEVICE_ATTR(pp_dpm_sclk, S_IRUGO | S_IWUSR,
997b843c749SSergey Zigachev 		amdgpu_get_pp_dpm_sclk,
998b843c749SSergey Zigachev 		amdgpu_set_pp_dpm_sclk);
999b843c749SSergey Zigachev static DEVICE_ATTR(pp_dpm_mclk, S_IRUGO | S_IWUSR,
1000b843c749SSergey Zigachev 		amdgpu_get_pp_dpm_mclk,
1001b843c749SSergey Zigachev 		amdgpu_set_pp_dpm_mclk);
1002b843c749SSergey Zigachev static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR,
1003b843c749SSergey Zigachev 		amdgpu_get_pp_dpm_pcie,
1004b843c749SSergey Zigachev 		amdgpu_set_pp_dpm_pcie);
1005b843c749SSergey Zigachev static DEVICE_ATTR(pp_sclk_od, S_IRUGO | S_IWUSR,
1006b843c749SSergey Zigachev 		amdgpu_get_pp_sclk_od,
1007b843c749SSergey Zigachev 		amdgpu_set_pp_sclk_od);
1008b843c749SSergey Zigachev static DEVICE_ATTR(pp_mclk_od, S_IRUGO | S_IWUSR,
1009b843c749SSergey Zigachev 		amdgpu_get_pp_mclk_od,
1010b843c749SSergey Zigachev 		amdgpu_set_pp_mclk_od);
1011b843c749SSergey Zigachev static DEVICE_ATTR(pp_power_profile_mode, S_IRUGO | S_IWUSR,
1012b843c749SSergey Zigachev 		amdgpu_get_pp_power_profile_mode,
1013b843c749SSergey Zigachev 		amdgpu_set_pp_power_profile_mode);
1014b843c749SSergey Zigachev static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR,
1015b843c749SSergey Zigachev 		amdgpu_get_pp_od_clk_voltage,
1016b843c749SSergey Zigachev 		amdgpu_set_pp_od_clk_voltage);
1017b843c749SSergey Zigachev static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
1018b843c749SSergey Zigachev 		amdgpu_get_busy_percent, NULL);
1019b843c749SSergey Zigachev 
1020b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
1021b843c749SSergey Zigachev 				      struct device_attribute *attr,
1022b843c749SSergey Zigachev 				      char *buf)
1023b843c749SSergey Zigachev {
1024b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1025b843c749SSergey Zigachev 	struct drm_device *ddev = adev->ddev;
1026b843c749SSergey Zigachev 	int r, temp, size = sizeof(temp);
1027b843c749SSergey Zigachev 
1028b843c749SSergey Zigachev 	/* Can't get temperature when the card is off */
1029b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1030b843c749SSergey Zigachev 	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1031b843c749SSergey Zigachev 		return -EINVAL;
1032b843c749SSergey Zigachev 
1033b843c749SSergey Zigachev 	/* sanity check PP is enabled */
1034b843c749SSergey Zigachev 	if (!(adev->powerplay.pp_funcs &&
1035b843c749SSergey Zigachev 	      adev->powerplay.pp_funcs->read_sensor))
1036b843c749SSergey Zigachev 		return -EINVAL;
1037b843c749SSergey Zigachev 
1038b843c749SSergey Zigachev 	/* get the temperature */
1039b843c749SSergey Zigachev 	r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP,
1040b843c749SSergey Zigachev 				   (void *)&temp, &size);
1041b843c749SSergey Zigachev 	if (r)
1042b843c749SSergey Zigachev 		return r;
1043b843c749SSergey Zigachev 
1044b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", temp);
1045b843c749SSergey Zigachev }
1046b843c749SSergey Zigachev 
1047b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_temp_thresh(struct device *dev,
1048b843c749SSergey Zigachev 					     struct device_attribute *attr,
1049b843c749SSergey Zigachev 					     char *buf)
1050b843c749SSergey Zigachev {
1051b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1052b843c749SSergey Zigachev 	int hyst = to_sensor_dev_attr(attr)->index;
1053b843c749SSergey Zigachev 	int temp;
1054b843c749SSergey Zigachev 
1055b843c749SSergey Zigachev 	if (hyst)
1056b843c749SSergey Zigachev 		temp = adev->pm.dpm.thermal.min_temp;
1057b843c749SSergey Zigachev 	else
1058b843c749SSergey Zigachev 		temp = adev->pm.dpm.thermal.max_temp;
1059b843c749SSergey Zigachev 
1060b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", temp);
1061b843c749SSergey Zigachev }
1062b843c749SSergey Zigachev 
1063b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev,
1064b843c749SSergey Zigachev 					    struct device_attribute *attr,
1065b843c749SSergey Zigachev 					    char *buf)
1066b843c749SSergey Zigachev {
1067b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1068b843c749SSergey Zigachev 	u32 pwm_mode = 0;
1069b843c749SSergey Zigachev 
1070b843c749SSergey Zigachev 	if (!adev->powerplay.pp_funcs->get_fan_control_mode)
1071b843c749SSergey Zigachev 		return -EINVAL;
1072b843c749SSergey Zigachev 
1073b843c749SSergey Zigachev 	pwm_mode = amdgpu_dpm_get_fan_control_mode(adev);
1074b843c749SSergey Zigachev 
1075b843c749SSergey Zigachev 	return sprintf(buf, "%i\n", pwm_mode);
1076b843c749SSergey Zigachev }
1077b843c749SSergey Zigachev 
1078b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
1079b843c749SSergey Zigachev 					    struct device_attribute *attr,
1080b843c749SSergey Zigachev 					    const char *buf,
1081b843c749SSergey Zigachev 					    size_t count)
1082b843c749SSergey Zigachev {
1083b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1084b843c749SSergey Zigachev 	int err;
1085b843c749SSergey Zigachev 	int value;
1086b843c749SSergey Zigachev 
1087b843c749SSergey Zigachev 	/* Can't adjust fan when the card is off */
1088b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1089b843c749SSergey Zigachev 	     (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1090b843c749SSergey Zigachev 		return -EINVAL;
1091b843c749SSergey Zigachev 
1092b843c749SSergey Zigachev 	if (!adev->powerplay.pp_funcs->set_fan_control_mode)
1093b843c749SSergey Zigachev 		return -EINVAL;
1094b843c749SSergey Zigachev 
1095b843c749SSergey Zigachev 	err = kstrtoint(buf, 10, &value);
1096b843c749SSergey Zigachev 	if (err)
1097b843c749SSergey Zigachev 		return err;
1098b843c749SSergey Zigachev 
1099b843c749SSergey Zigachev 	amdgpu_dpm_set_fan_control_mode(adev, value);
1100b843c749SSergey Zigachev 
1101b843c749SSergey Zigachev 	return count;
1102b843c749SSergey Zigachev }
1103b843c749SSergey Zigachev 
1104b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_get_pwm1_min(struct device *dev,
1105b843c749SSergey Zigachev 					 struct device_attribute *attr,
1106b843c749SSergey Zigachev 					 char *buf)
1107b843c749SSergey Zigachev {
1108b843c749SSergey Zigachev 	return sprintf(buf, "%i\n", 0);
1109b843c749SSergey Zigachev }
1110b843c749SSergey Zigachev 
1111b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_get_pwm1_max(struct device *dev,
1112b843c749SSergey Zigachev 					 struct device_attribute *attr,
1113b843c749SSergey Zigachev 					 char *buf)
1114b843c749SSergey Zigachev {
1115b843c749SSergey Zigachev 	return sprintf(buf, "%i\n", 255);
1116b843c749SSergey Zigachev }
1117b843c749SSergey Zigachev 
1118b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev,
1119b843c749SSergey Zigachev 				     struct device_attribute *attr,
1120b843c749SSergey Zigachev 				     const char *buf, size_t count)
1121b843c749SSergey Zigachev {
1122b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1123b843c749SSergey Zigachev 	int err;
1124b843c749SSergey Zigachev 	u32 value;
1125b843c749SSergey Zigachev 
1126b843c749SSergey Zigachev 	/* Can't adjust fan when the card is off */
1127b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1128b843c749SSergey Zigachev 	     (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1129b843c749SSergey Zigachev 		return -EINVAL;
1130b843c749SSergey Zigachev 
1131b843c749SSergey Zigachev 	err = kstrtou32(buf, 10, &value);
1132b843c749SSergey Zigachev 	if (err)
1133b843c749SSergey Zigachev 		return err;
1134b843c749SSergey Zigachev 
1135b843c749SSergey Zigachev 	value = (value * 100) / 255;
1136b843c749SSergey Zigachev 
1137b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->set_fan_speed_percent) {
1138b843c749SSergey Zigachev 		err = amdgpu_dpm_set_fan_speed_percent(adev, value);
1139b843c749SSergey Zigachev 		if (err)
1140b843c749SSergey Zigachev 			return err;
1141b843c749SSergey Zigachev 	}
1142b843c749SSergey Zigachev 
1143b843c749SSergey Zigachev 	return count;
1144b843c749SSergey Zigachev }
1145b843c749SSergey Zigachev 
1146b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev,
1147b843c749SSergey Zigachev 				     struct device_attribute *attr,
1148b843c749SSergey Zigachev 				     char *buf)
1149b843c749SSergey Zigachev {
1150b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1151b843c749SSergey Zigachev 	int err;
1152b843c749SSergey Zigachev 	u32 speed = 0;
1153b843c749SSergey Zigachev 
1154b843c749SSergey Zigachev 	/* Can't adjust fan when the card is off */
1155b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1156b843c749SSergey Zigachev 	     (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1157b843c749SSergey Zigachev 		return -EINVAL;
1158b843c749SSergey Zigachev 
1159b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_fan_speed_percent) {
1160b843c749SSergey Zigachev 		err = amdgpu_dpm_get_fan_speed_percent(adev, &speed);
1161b843c749SSergey Zigachev 		if (err)
1162b843c749SSergey Zigachev 			return err;
1163b843c749SSergey Zigachev 	}
1164b843c749SSergey Zigachev 
1165b843c749SSergey Zigachev 	speed = (speed * 255) / 100;
1166b843c749SSergey Zigachev 
1167b843c749SSergey Zigachev 	return sprintf(buf, "%i\n", speed);
1168b843c749SSergey Zigachev }
1169b843c749SSergey Zigachev 
1170b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev,
1171b843c749SSergey Zigachev 					   struct device_attribute *attr,
1172b843c749SSergey Zigachev 					   char *buf)
1173b843c749SSergey Zigachev {
1174b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1175b843c749SSergey Zigachev 	int err;
1176b843c749SSergey Zigachev 	u32 speed = 0;
1177b843c749SSergey Zigachev 
1178b843c749SSergey Zigachev 	/* Can't adjust fan when the card is off */
1179b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1180b843c749SSergey Zigachev 	     (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1181b843c749SSergey Zigachev 		return -EINVAL;
1182b843c749SSergey Zigachev 
1183b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->get_fan_speed_rpm) {
1184b843c749SSergey Zigachev 		err = amdgpu_dpm_get_fan_speed_rpm(adev, &speed);
1185b843c749SSergey Zigachev 		if (err)
1186b843c749SSergey Zigachev 			return err;
1187b843c749SSergey Zigachev 	}
1188b843c749SSergey Zigachev 
1189b843c749SSergey Zigachev 	return sprintf(buf, "%i\n", speed);
1190b843c749SSergey Zigachev }
1191b843c749SSergey Zigachev 
1192b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_vddgfx(struct device *dev,
1193b843c749SSergey Zigachev 					struct device_attribute *attr,
1194b843c749SSergey Zigachev 					char *buf)
1195b843c749SSergey Zigachev {
1196b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1197b843c749SSergey Zigachev 	struct drm_device *ddev = adev->ddev;
1198b843c749SSergey Zigachev 	u32 vddgfx;
1199b843c749SSergey Zigachev 	int r, size = sizeof(vddgfx);
1200b843c749SSergey Zigachev 
1201b843c749SSergey Zigachev 	/* Can't get voltage when the card is off */
1202b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1203b843c749SSergey Zigachev 	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1204b843c749SSergey Zigachev 		return -EINVAL;
1205b843c749SSergey Zigachev 
1206b843c749SSergey Zigachev 	/* sanity check PP is enabled */
1207b843c749SSergey Zigachev 	if (!(adev->powerplay.pp_funcs &&
1208b843c749SSergey Zigachev 	      adev->powerplay.pp_funcs->read_sensor))
1209b843c749SSergey Zigachev 	      return -EINVAL;
1210b843c749SSergey Zigachev 
1211b843c749SSergey Zigachev 	/* get the voltage */
1212b843c749SSergey Zigachev 	r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX,
1213b843c749SSergey Zigachev 				   (void *)&vddgfx, &size);
1214b843c749SSergey Zigachev 	if (r)
1215b843c749SSergey Zigachev 		return r;
1216b843c749SSergey Zigachev 
1217b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", vddgfx);
1218b843c749SSergey Zigachev }
1219b843c749SSergey Zigachev 
1220b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_vddgfx_label(struct device *dev,
1221b843c749SSergey Zigachev 					      struct device_attribute *attr,
1222b843c749SSergey Zigachev 					      char *buf)
1223b843c749SSergey Zigachev {
1224b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "vddgfx\n");
1225b843c749SSergey Zigachev }
1226b843c749SSergey Zigachev 
1227b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev,
1228b843c749SSergey Zigachev 				       struct device_attribute *attr,
1229b843c749SSergey Zigachev 				       char *buf)
1230b843c749SSergey Zigachev {
1231b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1232b843c749SSergey Zigachev 	struct drm_device *ddev = adev->ddev;
1233b843c749SSergey Zigachev 	u32 vddnb;
1234b843c749SSergey Zigachev 	int r, size = sizeof(vddnb);
1235b843c749SSergey Zigachev 
1236b843c749SSergey Zigachev 	/* only APUs have vddnb */
1237b843c749SSergey Zigachev 	if  (!(adev->flags & AMD_IS_APU))
1238b843c749SSergey Zigachev 		return -EINVAL;
1239b843c749SSergey Zigachev 
1240b843c749SSergey Zigachev 	/* Can't get voltage when the card is off */
1241b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1242b843c749SSergey Zigachev 	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1243b843c749SSergey Zigachev 		return -EINVAL;
1244b843c749SSergey Zigachev 
1245b843c749SSergey Zigachev 	/* sanity check PP is enabled */
1246b843c749SSergey Zigachev 	if (!(adev->powerplay.pp_funcs &&
1247b843c749SSergey Zigachev 	      adev->powerplay.pp_funcs->read_sensor))
1248b843c749SSergey Zigachev 	      return -EINVAL;
1249b843c749SSergey Zigachev 
1250b843c749SSergey Zigachev 	/* get the voltage */
1251b843c749SSergey Zigachev 	r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB,
1252b843c749SSergey Zigachev 				   (void *)&vddnb, &size);
1253b843c749SSergey Zigachev 	if (r)
1254b843c749SSergey Zigachev 		return r;
1255b843c749SSergey Zigachev 
1256b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%d\n", vddnb);
1257b843c749SSergey Zigachev }
1258b843c749SSergey Zigachev 
1259b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_vddnb_label(struct device *dev,
1260b843c749SSergey Zigachev 					      struct device_attribute *attr,
1261b843c749SSergey Zigachev 					      char *buf)
1262b843c749SSergey Zigachev {
1263b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "vddnb\n");
1264b843c749SSergey Zigachev }
1265b843c749SSergey Zigachev 
1266b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
1267b843c749SSergey Zigachev 					   struct device_attribute *attr,
1268b843c749SSergey Zigachev 					   char *buf)
1269b843c749SSergey Zigachev {
1270b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1271b843c749SSergey Zigachev 	struct drm_device *ddev = adev->ddev;
1272b843c749SSergey Zigachev 	u32 query = 0;
1273b843c749SSergey Zigachev 	int r, size = sizeof(u32);
1274b843c749SSergey Zigachev 	unsigned uw;
1275b843c749SSergey Zigachev 
1276b843c749SSergey Zigachev 	/* Can't get power when the card is off */
1277b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
1278b843c749SSergey Zigachev 	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
1279b843c749SSergey Zigachev 		return -EINVAL;
1280b843c749SSergey Zigachev 
1281b843c749SSergey Zigachev 	/* sanity check PP is enabled */
1282b843c749SSergey Zigachev 	if (!(adev->powerplay.pp_funcs &&
1283b843c749SSergey Zigachev 	      adev->powerplay.pp_funcs->read_sensor))
1284b843c749SSergey Zigachev 	      return -EINVAL;
1285b843c749SSergey Zigachev 
1286b843c749SSergey Zigachev 	/* get the voltage */
1287b843c749SSergey Zigachev 	r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER,
1288b843c749SSergey Zigachev 				   (void *)&query, &size);
1289b843c749SSergey Zigachev 	if (r)
1290b843c749SSergey Zigachev 		return r;
1291b843c749SSergey Zigachev 
1292b843c749SSergey Zigachev 	/* convert to microwatts */
1293b843c749SSergey Zigachev 	uw = (query >> 8) * 1000000 + (query & 0xff) * 1000;
1294b843c749SSergey Zigachev 
1295b843c749SSergey Zigachev 	return snprintf(buf, PAGE_SIZE, "%u\n", uw);
1296b843c749SSergey Zigachev }
1297b843c749SSergey Zigachev 
1298b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_power_cap_min(struct device *dev,
1299b843c749SSergey Zigachev 					 struct device_attribute *attr,
1300b843c749SSergey Zigachev 					 char *buf)
1301b843c749SSergey Zigachev {
1302b843c749SSergey Zigachev 	return sprintf(buf, "%i\n", 0);
1303b843c749SSergey Zigachev }
1304b843c749SSergey Zigachev 
1305b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev,
1306b843c749SSergey Zigachev 					 struct device_attribute *attr,
1307b843c749SSergey Zigachev 					 char *buf)
1308b843c749SSergey Zigachev {
1309b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1310b843c749SSergey Zigachev 	uint32_t limit = 0;
1311b843c749SSergey Zigachev 
1312b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_power_limit) {
1313b843c749SSergey Zigachev 		adev->powerplay.pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, true);
1314b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "%u\n", limit * 1000000);
1315b843c749SSergey Zigachev 	} else {
1316b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
1317b843c749SSergey Zigachev 	}
1318b843c749SSergey Zigachev }
1319b843c749SSergey Zigachev 
1320b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_show_power_cap(struct device *dev,
1321b843c749SSergey Zigachev 					 struct device_attribute *attr,
1322b843c749SSergey Zigachev 					 char *buf)
1323b843c749SSergey Zigachev {
1324b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1325b843c749SSergey Zigachev 	uint32_t limit = 0;
1326b843c749SSergey Zigachev 
1327b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_power_limit) {
1328b843c749SSergey Zigachev 		adev->powerplay.pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, false);
1329b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "%u\n", limit * 1000000);
1330b843c749SSergey Zigachev 	} else {
1331b843c749SSergey Zigachev 		return snprintf(buf, PAGE_SIZE, "\n");
1332b843c749SSergey Zigachev 	}
1333b843c749SSergey Zigachev }
1334b843c749SSergey Zigachev 
1335b843c749SSergey Zigachev 
1336b843c749SSergey Zigachev static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
1337b843c749SSergey Zigachev 		struct device_attribute *attr,
1338b843c749SSergey Zigachev 		const char *buf,
1339b843c749SSergey Zigachev 		size_t count)
1340b843c749SSergey Zigachev {
1341b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1342b843c749SSergey Zigachev 	int err;
1343b843c749SSergey Zigachev 	u32 value;
1344b843c749SSergey Zigachev 
1345b843c749SSergey Zigachev 	err = kstrtou32(buf, 10, &value);
1346b843c749SSergey Zigachev 	if (err)
1347b843c749SSergey Zigachev 		return err;
1348b843c749SSergey Zigachev 
1349b843c749SSergey Zigachev 	value = value / 1000000; /* convert to Watt */
1350b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->set_power_limit) {
1351b843c749SSergey Zigachev 		err = adev->powerplay.pp_funcs->set_power_limit(adev->powerplay.pp_handle, value);
1352b843c749SSergey Zigachev 		if (err)
1353b843c749SSergey Zigachev 			return err;
1354b843c749SSergey Zigachev 	} else {
1355b843c749SSergey Zigachev 		return -EINVAL;
1356b843c749SSergey Zigachev 	}
1357b843c749SSergey Zigachev 
1358b843c749SSergey Zigachev 	return count;
1359b843c749SSergey Zigachev }
1360b843c749SSergey Zigachev 
1361b843c749SSergey Zigachev 
1362b843c749SSergey Zigachev /**
1363b843c749SSergey Zigachev  * DOC: hwmon
1364b843c749SSergey Zigachev  *
1365b843c749SSergey Zigachev  * The amdgpu driver exposes the following sensor interfaces:
1366b843c749SSergey Zigachev  *
1367b843c749SSergey Zigachev  * - GPU temperature (via the on-die sensor)
1368b843c749SSergey Zigachev  *
1369b843c749SSergey Zigachev  * - GPU voltage
1370b843c749SSergey Zigachev  *
1371b843c749SSergey Zigachev  * - Northbridge voltage (APUs only)
1372b843c749SSergey Zigachev  *
1373b843c749SSergey Zigachev  * - GPU power
1374b843c749SSergey Zigachev  *
1375b843c749SSergey Zigachev  * - GPU fan
1376b843c749SSergey Zigachev  *
1377b843c749SSergey Zigachev  * hwmon interfaces for GPU temperature:
1378b843c749SSergey Zigachev  *
1379b843c749SSergey Zigachev  * - temp1_input: the on die GPU temperature in millidegrees Celsius
1380b843c749SSergey Zigachev  *
1381b843c749SSergey Zigachev  * - temp1_crit: temperature critical max value in millidegrees Celsius
1382b843c749SSergey Zigachev  *
1383b843c749SSergey Zigachev  * - temp1_crit_hyst: temperature hysteresis for critical limit in millidegrees Celsius
1384b843c749SSergey Zigachev  *
1385b843c749SSergey Zigachev  * hwmon interfaces for GPU voltage:
1386b843c749SSergey Zigachev  *
1387b843c749SSergey Zigachev  * - in0_input: the voltage on the GPU in millivolts
1388b843c749SSergey Zigachev  *
1389b843c749SSergey Zigachev  * - in1_input: the voltage on the Northbridge in millivolts
1390b843c749SSergey Zigachev  *
1391b843c749SSergey Zigachev  * hwmon interfaces for GPU power:
1392b843c749SSergey Zigachev  *
1393b843c749SSergey Zigachev  * - power1_average: average power used by the GPU in microWatts
1394b843c749SSergey Zigachev  *
1395b843c749SSergey Zigachev  * - power1_cap_min: minimum cap supported in microWatts
1396b843c749SSergey Zigachev  *
1397b843c749SSergey Zigachev  * - power1_cap_max: maximum cap supported in microWatts
1398b843c749SSergey Zigachev  *
1399b843c749SSergey Zigachev  * - power1_cap: selected power cap in microWatts
1400b843c749SSergey Zigachev  *
1401b843c749SSergey Zigachev  * hwmon interfaces for GPU fan:
1402b843c749SSergey Zigachev  *
1403b843c749SSergey Zigachev  * - pwm1: pulse width modulation fan level (0-255)
1404b843c749SSergey Zigachev  *
1405b843c749SSergey Zigachev  * - pwm1_enable: pulse width modulation fan control method (0: no fan speed control, 1: manual fan speed control using pwm interface, 2: automatic fan speed control)
1406b843c749SSergey Zigachev  *
1407b843c749SSergey Zigachev  * - pwm1_min: pulse width modulation fan control minimum level (0)
1408b843c749SSergey Zigachev  *
1409b843c749SSergey Zigachev  * - pwm1_max: pulse width modulation fan control maximum level (255)
1410b843c749SSergey Zigachev  *
1411b843c749SSergey Zigachev  * - fan1_input: fan speed in RPM
1412b843c749SSergey Zigachev  *
1413b843c749SSergey Zigachev  * You can use hwmon tools like sensors to view this information on your system.
1414b843c749SSergey Zigachev  *
1415b843c749SSergey Zigachev  */
1416b843c749SSergey Zigachev 
1417b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, amdgpu_hwmon_show_temp, NULL, 0);
1418b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NULL, 0);
1419b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NULL, 1);
1420b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1, amdgpu_hwmon_set_pwm1, 0);
1421b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1_enable, amdgpu_hwmon_set_pwm1_enable, 0);
1422b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, amdgpu_hwmon_get_pwm1_min, NULL, 0);
1423b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, amdgpu_hwmon_get_pwm1_max, NULL, 0);
1424b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, amdgpu_hwmon_get_fan1_input, NULL, 0);
1425b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, amdgpu_hwmon_show_vddgfx, NULL, 0);
1426b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, amdgpu_hwmon_show_vddgfx_label, NULL, 0);
1427b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, amdgpu_hwmon_show_vddnb, NULL, 0);
1428b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, amdgpu_hwmon_show_vddnb_label, NULL, 0);
1429b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 0);
1430b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0);
1431b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0);
1432b843c749SSergey Zigachev static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0);
1433b843c749SSergey Zigachev 
1434b843c749SSergey Zigachev static struct attribute *hwmon_attributes[] = {
1435b843c749SSergey Zigachev 	&sensor_dev_attr_temp1_input.dev_attr.attr,
1436b843c749SSergey Zigachev 	&sensor_dev_attr_temp1_crit.dev_attr.attr,
1437b843c749SSergey Zigachev 	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
1438b843c749SSergey Zigachev 	&sensor_dev_attr_pwm1.dev_attr.attr,
1439b843c749SSergey Zigachev 	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
1440b843c749SSergey Zigachev 	&sensor_dev_attr_pwm1_min.dev_attr.attr,
1441b843c749SSergey Zigachev 	&sensor_dev_attr_pwm1_max.dev_attr.attr,
1442b843c749SSergey Zigachev 	&sensor_dev_attr_fan1_input.dev_attr.attr,
1443b843c749SSergey Zigachev 	&sensor_dev_attr_in0_input.dev_attr.attr,
1444b843c749SSergey Zigachev 	&sensor_dev_attr_in0_label.dev_attr.attr,
1445b843c749SSergey Zigachev 	&sensor_dev_attr_in1_input.dev_attr.attr,
1446b843c749SSergey Zigachev 	&sensor_dev_attr_in1_label.dev_attr.attr,
1447b843c749SSergey Zigachev 	&sensor_dev_attr_power1_average.dev_attr.attr,
1448b843c749SSergey Zigachev 	&sensor_dev_attr_power1_cap_max.dev_attr.attr,
1449b843c749SSergey Zigachev 	&sensor_dev_attr_power1_cap_min.dev_attr.attr,
1450b843c749SSergey Zigachev 	&sensor_dev_attr_power1_cap.dev_attr.attr,
1451b843c749SSergey Zigachev 	NULL
1452b843c749SSergey Zigachev };
1453b843c749SSergey Zigachev 
1454b843c749SSergey Zigachev static umode_t hwmon_attributes_visible(struct kobject *kobj,
1455b843c749SSergey Zigachev 					struct attribute *attr, int index)
1456b843c749SSergey Zigachev {
1457b843c749SSergey Zigachev 	struct device *dev = kobj_to_dev(kobj);
1458b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev_get_drvdata(dev);
1459b843c749SSergey Zigachev 	umode_t effective_mode = attr->mode;
1460b843c749SSergey Zigachev 
1461b843c749SSergey Zigachev 
1462b843c749SSergey Zigachev 	/* Skip fan attributes if fan is not present */
1463b843c749SSergey Zigachev 	if (adev->pm.no_fan && (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
1464b843c749SSergey Zigachev 	    attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
1465b843c749SSergey Zigachev 	    attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
1466b843c749SSergey Zigachev 	    attr == &sensor_dev_attr_pwm1_min.dev_attr.attr ||
1467b843c749SSergey Zigachev 	    attr == &sensor_dev_attr_fan1_input.dev_attr.attr))
1468b843c749SSergey Zigachev 		return 0;
1469b843c749SSergey Zigachev 
1470b843c749SSergey Zigachev 	/* Skip limit attributes if DPM is not enabled */
1471b843c749SSergey Zigachev 	if (!adev->pm.dpm_enabled &&
1472b843c749SSergey Zigachev 	    (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
1473b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr ||
1474b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
1475b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
1476b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
1477b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
1478b843c749SSergey Zigachev 		return 0;
1479b843c749SSergey Zigachev 
1480b843c749SSergey Zigachev 	/* mask fan attributes if we have no bindings for this asic to expose */
1481b843c749SSergey Zigachev 	if ((!adev->powerplay.pp_funcs->get_fan_speed_percent &&
1482b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */
1483b843c749SSergey Zigachev 	    (!adev->powerplay.pp_funcs->get_fan_control_mode &&
1484b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */
1485b843c749SSergey Zigachev 		effective_mode &= ~S_IRUGO;
1486b843c749SSergey Zigachev 
1487b843c749SSergey Zigachev 	if ((!adev->powerplay.pp_funcs->set_fan_speed_percent &&
1488b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */
1489b843c749SSergey Zigachev 	    (!adev->powerplay.pp_funcs->set_fan_control_mode &&
1490b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */
1491b843c749SSergey Zigachev 		effective_mode &= ~S_IWUSR;
1492b843c749SSergey Zigachev 
1493b843c749SSergey Zigachev 	if ((adev->flags & AMD_IS_APU) &&
1494b843c749SSergey Zigachev 	    (attr == &sensor_dev_attr_power1_average.dev_attr.attr ||
1495b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr ||
1496b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr||
1497b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_power1_cap.dev_attr.attr))
1498b843c749SSergey Zigachev 		return 0;
1499b843c749SSergey Zigachev 
1500b843c749SSergey Zigachev 	/* hide max/min values if we can't both query and manage the fan */
1501b843c749SSergey Zigachev 	if ((!adev->powerplay.pp_funcs->set_fan_speed_percent &&
1502b843c749SSergey Zigachev 	     !adev->powerplay.pp_funcs->get_fan_speed_percent) &&
1503b843c749SSergey Zigachev 	    (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
1504b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
1505b843c749SSergey Zigachev 		return 0;
1506b843c749SSergey Zigachev 
1507b843c749SSergey Zigachev 	/* only APUs have vddnb */
1508b843c749SSergey Zigachev 	if (!(adev->flags & AMD_IS_APU) &&
1509b843c749SSergey Zigachev 	    (attr == &sensor_dev_attr_in1_input.dev_attr.attr ||
1510b843c749SSergey Zigachev 	     attr == &sensor_dev_attr_in1_label.dev_attr.attr))
1511b843c749SSergey Zigachev 		return 0;
1512b843c749SSergey Zigachev 
1513b843c749SSergey Zigachev 	return effective_mode;
1514b843c749SSergey Zigachev }
1515b843c749SSergey Zigachev 
1516b843c749SSergey Zigachev static const struct attribute_group hwmon_attrgroup = {
1517b843c749SSergey Zigachev 	.attrs = hwmon_attributes,
1518b843c749SSergey Zigachev 	.is_visible = hwmon_attributes_visible,
1519b843c749SSergey Zigachev };
1520b843c749SSergey Zigachev 
1521b843c749SSergey Zigachev static const struct attribute_group *hwmon_groups[] = {
1522b843c749SSergey Zigachev 	&hwmon_attrgroup,
1523b843c749SSergey Zigachev 	NULL
1524b843c749SSergey Zigachev };
1525*78973132SSergey Zigachev #endif
1526b843c749SSergey Zigachev 
amdgpu_dpm_thermal_work_handler(struct work_struct * work)1527b843c749SSergey Zigachev void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
1528b843c749SSergey Zigachev {
1529b843c749SSergey Zigachev 	struct amdgpu_device *adev =
1530b843c749SSergey Zigachev 		container_of(work, struct amdgpu_device,
1531b843c749SSergey Zigachev 			     pm.dpm.thermal.work);
1532b843c749SSergey Zigachev 	/* switch to the thermal state */
1533b843c749SSergey Zigachev 	enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
1534b843c749SSergey Zigachev 	int temp, size = sizeof(temp);
1535b843c749SSergey Zigachev 
1536b843c749SSergey Zigachev 	if (!adev->pm.dpm_enabled)
1537b843c749SSergey Zigachev 		return;
1538b843c749SSergey Zigachev 
1539b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs &&
1540b843c749SSergey Zigachev 	    adev->powerplay.pp_funcs->read_sensor &&
1541b843c749SSergey Zigachev 	    !amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP,
1542b843c749SSergey Zigachev 				    (void *)&temp, &size)) {
1543b843c749SSergey Zigachev 		if (temp < adev->pm.dpm.thermal.min_temp)
1544b843c749SSergey Zigachev 			/* switch back the user state */
1545b843c749SSergey Zigachev 			dpm_state = adev->pm.dpm.user_state;
1546b843c749SSergey Zigachev 	} else {
1547b843c749SSergey Zigachev 		if (adev->pm.dpm.thermal.high_to_low)
1548b843c749SSergey Zigachev 			/* switch back the user state */
1549b843c749SSergey Zigachev 			dpm_state = adev->pm.dpm.user_state;
1550b843c749SSergey Zigachev 	}
1551b843c749SSergey Zigachev 	mutex_lock(&adev->pm.mutex);
1552b843c749SSergey Zigachev 	if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL)
1553b843c749SSergey Zigachev 		adev->pm.dpm.thermal_active = true;
1554b843c749SSergey Zigachev 	else
1555b843c749SSergey Zigachev 		adev->pm.dpm.thermal_active = false;
1556b843c749SSergey Zigachev 	adev->pm.dpm.state = dpm_state;
1557b843c749SSergey Zigachev 	mutex_unlock(&adev->pm.mutex);
1558b843c749SSergey Zigachev 
1559b843c749SSergey Zigachev 	amdgpu_pm_compute_clocks(adev);
1560b843c749SSergey Zigachev }
1561b843c749SSergey Zigachev 
amdgpu_dpm_pick_power_state(struct amdgpu_device * adev,enum amd_pm_state_type dpm_state)1562b843c749SSergey Zigachev static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
1563b843c749SSergey Zigachev 						     enum amd_pm_state_type dpm_state)
1564b843c749SSergey Zigachev {
1565b843c749SSergey Zigachev 	int i;
1566b843c749SSergey Zigachev 	struct amdgpu_ps *ps;
1567b843c749SSergey Zigachev 	u32 ui_class;
1568b843c749SSergey Zigachev 	bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ?
1569b843c749SSergey Zigachev 		true : false;
1570b843c749SSergey Zigachev 
1571b843c749SSergey Zigachev 	/* check if the vblank period is too short to adjust the mclk */
1572b843c749SSergey Zigachev 	if (single_display && adev->powerplay.pp_funcs->vblank_too_short) {
1573b843c749SSergey Zigachev 		if (amdgpu_dpm_vblank_too_short(adev))
1574b843c749SSergey Zigachev 			single_display = false;
1575b843c749SSergey Zigachev 	}
1576b843c749SSergey Zigachev 
1577b843c749SSergey Zigachev 	/* certain older asics have a separare 3D performance state,
1578b843c749SSergey Zigachev 	 * so try that first if the user selected performance
1579b843c749SSergey Zigachev 	 */
1580b843c749SSergey Zigachev 	if (dpm_state == POWER_STATE_TYPE_PERFORMANCE)
1581b843c749SSergey Zigachev 		dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
1582b843c749SSergey Zigachev 	/* balanced states don't exist at the moment */
1583b843c749SSergey Zigachev 	if (dpm_state == POWER_STATE_TYPE_BALANCED)
1584b843c749SSergey Zigachev 		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
1585b843c749SSergey Zigachev 
1586b843c749SSergey Zigachev restart_search:
1587b843c749SSergey Zigachev 	/* Pick the best power state based on current conditions */
1588b843c749SSergey Zigachev 	for (i = 0; i < adev->pm.dpm.num_ps; i++) {
1589b843c749SSergey Zigachev 		ps = &adev->pm.dpm.ps[i];
1590b843c749SSergey Zigachev 		ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
1591b843c749SSergey Zigachev 		switch (dpm_state) {
1592b843c749SSergey Zigachev 		/* user states */
1593b843c749SSergey Zigachev 		case POWER_STATE_TYPE_BATTERY:
1594b843c749SSergey Zigachev 			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
1595b843c749SSergey Zigachev 				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
1596b843c749SSergey Zigachev 					if (single_display)
1597b843c749SSergey Zigachev 						return ps;
1598b843c749SSergey Zigachev 				} else
1599b843c749SSergey Zigachev 					return ps;
1600b843c749SSergey Zigachev 			}
1601b843c749SSergey Zigachev 			break;
1602b843c749SSergey Zigachev 		case POWER_STATE_TYPE_BALANCED:
1603b843c749SSergey Zigachev 			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) {
1604b843c749SSergey Zigachev 				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
1605b843c749SSergey Zigachev 					if (single_display)
1606b843c749SSergey Zigachev 						return ps;
1607b843c749SSergey Zigachev 				} else
1608b843c749SSergey Zigachev 					return ps;
1609b843c749SSergey Zigachev 			}
1610b843c749SSergey Zigachev 			break;
1611b843c749SSergey Zigachev 		case POWER_STATE_TYPE_PERFORMANCE:
1612b843c749SSergey Zigachev 			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
1613b843c749SSergey Zigachev 				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
1614b843c749SSergey Zigachev 					if (single_display)
1615b843c749SSergey Zigachev 						return ps;
1616b843c749SSergey Zigachev 				} else
1617b843c749SSergey Zigachev 					return ps;
1618b843c749SSergey Zigachev 			}
1619b843c749SSergey Zigachev 			break;
1620b843c749SSergey Zigachev 		/* internal states */
1621b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_UVD:
1622b843c749SSergey Zigachev 			if (adev->pm.dpm.uvd_ps)
1623b843c749SSergey Zigachev 				return adev->pm.dpm.uvd_ps;
1624b843c749SSergey Zigachev 			else
1625b843c749SSergey Zigachev 				break;
1626b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_UVD_SD:
1627b843c749SSergey Zigachev 			if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
1628b843c749SSergey Zigachev 				return ps;
1629b843c749SSergey Zigachev 			break;
1630b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_UVD_HD:
1631b843c749SSergey Zigachev 			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
1632b843c749SSergey Zigachev 				return ps;
1633b843c749SSergey Zigachev 			break;
1634b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
1635b843c749SSergey Zigachev 			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
1636b843c749SSergey Zigachev 				return ps;
1637b843c749SSergey Zigachev 			break;
1638b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
1639b843c749SSergey Zigachev 			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
1640b843c749SSergey Zigachev 				return ps;
1641b843c749SSergey Zigachev 			break;
1642b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_BOOT:
1643b843c749SSergey Zigachev 			return adev->pm.dpm.boot_ps;
1644b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_THERMAL:
1645b843c749SSergey Zigachev 			if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1646b843c749SSergey Zigachev 				return ps;
1647b843c749SSergey Zigachev 			break;
1648b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_ACPI:
1649b843c749SSergey Zigachev 			if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
1650b843c749SSergey Zigachev 				return ps;
1651b843c749SSergey Zigachev 			break;
1652b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_ULV:
1653b843c749SSergey Zigachev 			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
1654b843c749SSergey Zigachev 				return ps;
1655b843c749SSergey Zigachev 			break;
1656b843c749SSergey Zigachev 		case POWER_STATE_TYPE_INTERNAL_3DPERF:
1657b843c749SSergey Zigachev 			if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
1658b843c749SSergey Zigachev 				return ps;
1659b843c749SSergey Zigachev 			break;
1660b843c749SSergey Zigachev 		default:
1661b843c749SSergey Zigachev 			break;
1662b843c749SSergey Zigachev 		}
1663b843c749SSergey Zigachev 	}
1664b843c749SSergey Zigachev 	/* use a fallback state if we didn't match */
1665b843c749SSergey Zigachev 	switch (dpm_state) {
1666b843c749SSergey Zigachev 	case POWER_STATE_TYPE_INTERNAL_UVD_SD:
1667b843c749SSergey Zigachev 		dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
1668b843c749SSergey Zigachev 		goto restart_search;
1669b843c749SSergey Zigachev 	case POWER_STATE_TYPE_INTERNAL_UVD_HD:
1670b843c749SSergey Zigachev 	case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
1671b843c749SSergey Zigachev 	case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
1672b843c749SSergey Zigachev 		if (adev->pm.dpm.uvd_ps) {
1673b843c749SSergey Zigachev 			return adev->pm.dpm.uvd_ps;
1674b843c749SSergey Zigachev 		} else {
1675b843c749SSergey Zigachev 			dpm_state = POWER_STATE_TYPE_PERFORMANCE;
1676b843c749SSergey Zigachev 			goto restart_search;
1677b843c749SSergey Zigachev 		}
1678b843c749SSergey Zigachev 	case POWER_STATE_TYPE_INTERNAL_THERMAL:
1679b843c749SSergey Zigachev 		dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
1680b843c749SSergey Zigachev 		goto restart_search;
1681b843c749SSergey Zigachev 	case POWER_STATE_TYPE_INTERNAL_ACPI:
1682b843c749SSergey Zigachev 		dpm_state = POWER_STATE_TYPE_BATTERY;
1683b843c749SSergey Zigachev 		goto restart_search;
1684b843c749SSergey Zigachev 	case POWER_STATE_TYPE_BATTERY:
1685b843c749SSergey Zigachev 	case POWER_STATE_TYPE_BALANCED:
1686b843c749SSergey Zigachev 	case POWER_STATE_TYPE_INTERNAL_3DPERF:
1687b843c749SSergey Zigachev 		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
1688b843c749SSergey Zigachev 		goto restart_search;
1689b843c749SSergey Zigachev 	default:
1690b843c749SSergey Zigachev 		break;
1691b843c749SSergey Zigachev 	}
1692b843c749SSergey Zigachev 
1693b843c749SSergey Zigachev 	return NULL;
1694b843c749SSergey Zigachev }
1695b843c749SSergey Zigachev 
amdgpu_dpm_change_power_state_locked(struct amdgpu_device * adev)1696b843c749SSergey Zigachev static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
1697b843c749SSergey Zigachev {
1698b843c749SSergey Zigachev 	struct amdgpu_ps *ps;
1699b843c749SSergey Zigachev 	enum amd_pm_state_type dpm_state;
1700b843c749SSergey Zigachev 	int ret;
1701b843c749SSergey Zigachev 	bool equal = false;
1702b843c749SSergey Zigachev 
1703b843c749SSergey Zigachev 	/* if dpm init failed */
1704b843c749SSergey Zigachev 	if (!adev->pm.dpm_enabled)
1705b843c749SSergey Zigachev 		return;
1706b843c749SSergey Zigachev 
1707b843c749SSergey Zigachev 	if (adev->pm.dpm.user_state != adev->pm.dpm.state) {
1708b843c749SSergey Zigachev 		/* add other state override checks here */
1709b843c749SSergey Zigachev 		if ((!adev->pm.dpm.thermal_active) &&
1710b843c749SSergey Zigachev 		    (!adev->pm.dpm.uvd_active))
1711b843c749SSergey Zigachev 			adev->pm.dpm.state = adev->pm.dpm.user_state;
1712b843c749SSergey Zigachev 	}
1713b843c749SSergey Zigachev 	dpm_state = adev->pm.dpm.state;
1714b843c749SSergey Zigachev 
1715b843c749SSergey Zigachev 	ps = amdgpu_dpm_pick_power_state(adev, dpm_state);
1716b843c749SSergey Zigachev 	if (ps)
1717b843c749SSergey Zigachev 		adev->pm.dpm.requested_ps = ps;
1718b843c749SSergey Zigachev 	else
1719b843c749SSergey Zigachev 		return;
1720b843c749SSergey Zigachev 
1721b843c749SSergey Zigachev 	if (amdgpu_dpm == 1 && adev->powerplay.pp_funcs->print_power_state) {
1722b843c749SSergey Zigachev 		printk("switching from power state:\n");
1723b843c749SSergey Zigachev 		amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps);
1724b843c749SSergey Zigachev 		printk("switching to power state:\n");
1725b843c749SSergey Zigachev 		amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps);
1726b843c749SSergey Zigachev 	}
1727b843c749SSergey Zigachev 
1728b843c749SSergey Zigachev 	/* update whether vce is active */
1729b843c749SSergey Zigachev 	ps->vce_active = adev->pm.dpm.vce_active;
1730b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->display_configuration_changed)
1731b843c749SSergey Zigachev 		amdgpu_dpm_display_configuration_changed(adev);
1732b843c749SSergey Zigachev 
1733b843c749SSergey Zigachev 	ret = amdgpu_dpm_pre_set_power_state(adev);
1734b843c749SSergey Zigachev 	if (ret)
1735b843c749SSergey Zigachev 		return;
1736b843c749SSergey Zigachev 
1737b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->check_state_equal) {
1738b843c749SSergey Zigachev 		if (0 != amdgpu_dpm_check_state_equal(adev, adev->pm.dpm.current_ps, adev->pm.dpm.requested_ps, &equal))
1739b843c749SSergey Zigachev 			equal = false;
1740b843c749SSergey Zigachev 	}
1741b843c749SSergey Zigachev 
1742b843c749SSergey Zigachev 	if (equal)
1743b843c749SSergey Zigachev 		return;
1744b843c749SSergey Zigachev 
1745b843c749SSergey Zigachev 	amdgpu_dpm_set_power_state(adev);
1746b843c749SSergey Zigachev 	amdgpu_dpm_post_set_power_state(adev);
1747b843c749SSergey Zigachev 
1748b843c749SSergey Zigachev 	adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
1749b843c749SSergey Zigachev 	adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
1750b843c749SSergey Zigachev 
1751b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->force_performance_level) {
1752b843c749SSergey Zigachev 		if (adev->pm.dpm.thermal_active) {
1753b843c749SSergey Zigachev 			enum amd_dpm_forced_level level = adev->pm.dpm.forced_level;
1754b843c749SSergey Zigachev 			/* force low perf level for thermal */
1755b843c749SSergey Zigachev 			amdgpu_dpm_force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW);
1756b843c749SSergey Zigachev 			/* save the user's level */
1757b843c749SSergey Zigachev 			adev->pm.dpm.forced_level = level;
1758b843c749SSergey Zigachev 		} else {
1759b843c749SSergey Zigachev 			/* otherwise, user selected level */
1760b843c749SSergey Zigachev 			amdgpu_dpm_force_performance_level(adev, adev->pm.dpm.forced_level);
1761b843c749SSergey Zigachev 		}
1762b843c749SSergey Zigachev 	}
1763b843c749SSergey Zigachev }
1764b843c749SSergey Zigachev 
amdgpu_dpm_enable_uvd(struct amdgpu_device * adev,bool enable)1765b843c749SSergey Zigachev void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
1766b843c749SSergey Zigachev {
1767b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->set_powergating_by_smu) {
1768b843c749SSergey Zigachev 		/* enable/disable UVD */
1769b843c749SSergey Zigachev 		mutex_lock(&adev->pm.mutex);
1770b843c749SSergey Zigachev 		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable);
1771b843c749SSergey Zigachev 		mutex_unlock(&adev->pm.mutex);
1772b843c749SSergey Zigachev 	} else {
1773b843c749SSergey Zigachev 		if (enable) {
1774b843c749SSergey Zigachev 			mutex_lock(&adev->pm.mutex);
1775b843c749SSergey Zigachev 			adev->pm.dpm.uvd_active = true;
1776b843c749SSergey Zigachev 			adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
1777b843c749SSergey Zigachev 			mutex_unlock(&adev->pm.mutex);
1778b843c749SSergey Zigachev 		} else {
1779b843c749SSergey Zigachev 			mutex_lock(&adev->pm.mutex);
1780b843c749SSergey Zigachev 			adev->pm.dpm.uvd_active = false;
1781b843c749SSergey Zigachev 			mutex_unlock(&adev->pm.mutex);
1782b843c749SSergey Zigachev 		}
1783b843c749SSergey Zigachev 		amdgpu_pm_compute_clocks(adev);
1784b843c749SSergey Zigachev 	}
1785b843c749SSergey Zigachev }
1786b843c749SSergey Zigachev 
amdgpu_dpm_enable_vce(struct amdgpu_device * adev,bool enable)1787b843c749SSergey Zigachev void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
1788b843c749SSergey Zigachev {
1789b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->set_powergating_by_smu) {
1790b843c749SSergey Zigachev 		/* enable/disable VCE */
1791b843c749SSergey Zigachev 		mutex_lock(&adev->pm.mutex);
1792b843c749SSergey Zigachev 		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable);
1793b843c749SSergey Zigachev 		mutex_unlock(&adev->pm.mutex);
1794b843c749SSergey Zigachev 	} else {
1795b843c749SSergey Zigachev 		if (enable) {
1796b843c749SSergey Zigachev 			mutex_lock(&adev->pm.mutex);
1797b843c749SSergey Zigachev 			adev->pm.dpm.vce_active = true;
1798b843c749SSergey Zigachev 			/* XXX select vce level based on ring/task */
1799b843c749SSergey Zigachev 			adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL;
1800b843c749SSergey Zigachev 			mutex_unlock(&adev->pm.mutex);
1801b843c749SSergey Zigachev 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
1802b843c749SSergey Zigachev 							       AMD_CG_STATE_UNGATE);
1803b843c749SSergey Zigachev 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
1804b843c749SSergey Zigachev 							       AMD_PG_STATE_UNGATE);
1805b843c749SSergey Zigachev 			amdgpu_pm_compute_clocks(adev);
1806b843c749SSergey Zigachev 		} else {
1807b843c749SSergey Zigachev 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
1808b843c749SSergey Zigachev 							       AMD_PG_STATE_GATE);
1809b843c749SSergey Zigachev 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
1810b843c749SSergey Zigachev 							       AMD_CG_STATE_GATE);
1811b843c749SSergey Zigachev 			mutex_lock(&adev->pm.mutex);
1812b843c749SSergey Zigachev 			adev->pm.dpm.vce_active = false;
1813b843c749SSergey Zigachev 			mutex_unlock(&adev->pm.mutex);
1814b843c749SSergey Zigachev 			amdgpu_pm_compute_clocks(adev);
1815b843c749SSergey Zigachev 		}
1816b843c749SSergey Zigachev 
1817b843c749SSergey Zigachev 	}
1818b843c749SSergey Zigachev }
1819b843c749SSergey Zigachev 
amdgpu_pm_print_power_states(struct amdgpu_device * adev)1820b843c749SSergey Zigachev void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
1821b843c749SSergey Zigachev {
1822b843c749SSergey Zigachev 	int i;
1823b843c749SSergey Zigachev 
1824b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->print_power_state == NULL)
1825b843c749SSergey Zigachev 		return;
1826b843c749SSergey Zigachev 
1827b843c749SSergey Zigachev 	for (i = 0; i < adev->pm.dpm.num_ps; i++)
1828b843c749SSergey Zigachev 		amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
1829b843c749SSergey Zigachev 
1830b843c749SSergey Zigachev }
1831b843c749SSergey Zigachev 
amdgpu_pm_sysfs_init(struct amdgpu_device * adev)1832b843c749SSergey Zigachev int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
1833b843c749SSergey Zigachev {
1834b843c749SSergey Zigachev 	int ret;
1835b843c749SSergey Zigachev 
1836b843c749SSergey Zigachev 	if (adev->pm.sysfs_initialized)
1837b843c749SSergey Zigachev 		return 0;
1838b843c749SSergey Zigachev 
1839b843c749SSergey Zigachev 	if (adev->pm.dpm_enabled == 0)
1840b843c749SSergey Zigachev 		return 0;
1841b843c749SSergey Zigachev 
1842*78973132SSergey Zigachev #if 0
1843b843c749SSergey Zigachev 	adev->pm.int_hwmon_dev = hwmon_device_register_with_groups(adev->dev,
1844b843c749SSergey Zigachev 								   DRIVER_NAME, adev,
1845b843c749SSergey Zigachev 								   hwmon_groups);
1846b843c749SSergey Zigachev 	if (IS_ERR(adev->pm.int_hwmon_dev)) {
1847b843c749SSergey Zigachev 		ret = PTR_ERR(adev->pm.int_hwmon_dev);
1848b843c749SSergey Zigachev 		dev_err(adev->dev,
1849b843c749SSergey Zigachev 			"Unable to register hwmon device: %d\n", ret);
1850b843c749SSergey Zigachev 		return ret;
1851b843c749SSergey Zigachev 	}
1852b843c749SSergey Zigachev 
1853b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_power_dpm_state);
1854b843c749SSergey Zigachev 	if (ret) {
1855b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file for dpm state\n");
1856b843c749SSergey Zigachev 		return ret;
1857b843c749SSergey Zigachev 	}
1858b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_power_dpm_force_performance_level);
1859b843c749SSergey Zigachev 	if (ret) {
1860b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file for dpm state\n");
1861b843c749SSergey Zigachev 		return ret;
1862b843c749SSergey Zigachev 	}
1863*78973132SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_mclk_od);
1864*78973132SSergey Zigachev 	if (ret) {
1865*78973132SSergey Zigachev 		DRM_ERROR("failed to create device file pp_mclk_od\n");
1866*78973132SSergey Zigachev 		return ret;
1867*78973132SSergey Zigachev 	}
1868b843c749SSergey Zigachev 
1869b843c749SSergey Zigachev 
1870b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_num_states);
1871b843c749SSergey Zigachev 	if (ret) {
1872b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_num_states\n");
1873b843c749SSergey Zigachev 		return ret;
1874b843c749SSergey Zigachev 	}
1875b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_cur_state);
1876b843c749SSergey Zigachev 	if (ret) {
1877b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_cur_state\n");
1878b843c749SSergey Zigachev 		return ret;
1879b843c749SSergey Zigachev 	}
1880b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_force_state);
1881b843c749SSergey Zigachev 	if (ret) {
1882b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_force_state\n");
1883b843c749SSergey Zigachev 		return ret;
1884b843c749SSergey Zigachev 	}
1885b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_table);
1886b843c749SSergey Zigachev 	if (ret) {
1887b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_table\n");
1888b843c749SSergey Zigachev 		return ret;
1889b843c749SSergey Zigachev 	}
1890b843c749SSergey Zigachev 
1891b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_dpm_sclk);
1892b843c749SSergey Zigachev 	if (ret) {
1893b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_dpm_sclk\n");
1894b843c749SSergey Zigachev 		return ret;
1895b843c749SSergey Zigachev 	}
1896b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_dpm_mclk);
1897b843c749SSergey Zigachev 	if (ret) {
1898b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_dpm_mclk\n");
1899b843c749SSergey Zigachev 		return ret;
1900b843c749SSergey Zigachev 	}
1901b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_dpm_pcie);
1902b843c749SSergey Zigachev 	if (ret) {
1903b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_dpm_pcie\n");
1904b843c749SSergey Zigachev 		return ret;
1905b843c749SSergey Zigachev 	}
1906b843c749SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_sclk_od);
1907b843c749SSergey Zigachev 	if (ret) {
1908b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file pp_sclk_od\n");
1909b843c749SSergey Zigachev 		return ret;
1910b843c749SSergey Zigachev 	}
1911b843c749SSergey Zigachev 	ret = device_create_file(adev->dev,
1912b843c749SSergey Zigachev 			&dev_attr_pp_power_profile_mode);
1913b843c749SSergey Zigachev 	if (ret) {
1914b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file	"
1915b843c749SSergey Zigachev 				"pp_power_profile_mode\n");
1916b843c749SSergey Zigachev 		return ret;
1917b843c749SSergey Zigachev 	}
1918b843c749SSergey Zigachev 	ret = device_create_file(adev->dev,
1919b843c749SSergey Zigachev 			&dev_attr_pp_od_clk_voltage);
1920b843c749SSergey Zigachev 	if (ret) {
1921b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file	"
1922b843c749SSergey Zigachev 				"pp_od_clk_voltage\n");
1923b843c749SSergey Zigachev 		return ret;
1924b843c749SSergey Zigachev 	}
1925b843c749SSergey Zigachev 	ret = device_create_file(adev->dev,
1926b843c749SSergey Zigachev 			&dev_attr_gpu_busy_percent);
1927b843c749SSergey Zigachev 	if (ret) {
1928b843c749SSergey Zigachev 		DRM_ERROR("failed to create device file	"
1929b843c749SSergey Zigachev 				"gpu_busy_level\n");
1930b843c749SSergey Zigachev 		return ret;
1931b843c749SSergey Zigachev 	}
1932*78973132SSergey Zigachev #endif
1933*78973132SSergey Zigachev 
1934b843c749SSergey Zigachev 	ret = amdgpu_debugfs_pm_init(adev);
1935b843c749SSergey Zigachev 	if (ret) {
1936b843c749SSergey Zigachev 		DRM_ERROR("Failed to register debugfs file for dpm!\n");
1937b843c749SSergey Zigachev 		return ret;
1938b843c749SSergey Zigachev 	}
1939*78973132SSergey Zigachev #if 0
1940*78973132SSergey Zigachev 	ret = device_create_file(adev->dev, &dev_attr_pp_sclk_od);
1941*78973132SSergey Zigachev 	if (ret) {
1942*78973132SSergey Zigachev 		DRM_ERROR("failed to create device file pp_sclk_od\n");
1943*78973132SSergey Zigachev 		return ret;
1944*78973132SSergey Zigachev 	}
1945*78973132SSergey Zigachev #endif
1946b843c749SSergey Zigachev 	adev->pm.sysfs_initialized = true;
1947b843c749SSergey Zigachev 
1948b843c749SSergey Zigachev 	return 0;
1949b843c749SSergey Zigachev }
1950b843c749SSergey Zigachev 
amdgpu_pm_sysfs_fini(struct amdgpu_device * adev)1951b843c749SSergey Zigachev void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
1952b843c749SSergey Zigachev {
1953*78973132SSergey Zigachev #if 0
1954b843c749SSergey Zigachev 	if (adev->pm.dpm_enabled == 0)
1955b843c749SSergey Zigachev 		return;
1956b843c749SSergey Zigachev 
1957b843c749SSergey Zigachev 	if (adev->pm.int_hwmon_dev)
1958b843c749SSergey Zigachev 		hwmon_device_unregister(adev->pm.int_hwmon_dev);
1959b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_power_dpm_state);
1960b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_power_dpm_force_performance_level);
1961b843c749SSergey Zigachev 
1962b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_num_states);
1963b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_cur_state);
1964b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_force_state);
1965b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_table);
1966b843c749SSergey Zigachev 
1967b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_dpm_sclk);
1968b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_dpm_mclk);
1969b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie);
1970b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_sclk_od);
1971b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_pp_mclk_od);
1972b843c749SSergey Zigachev 	device_remove_file(adev->dev,
1973b843c749SSergey Zigachev 			&dev_attr_pp_power_profile_mode);
1974b843c749SSergey Zigachev 	device_remove_file(adev->dev,
1975b843c749SSergey Zigachev 			&dev_attr_pp_od_clk_voltage);
1976b843c749SSergey Zigachev 	device_remove_file(adev->dev, &dev_attr_gpu_busy_percent);
1977*78973132SSergey Zigachev #endif
1978b843c749SSergey Zigachev }
1979b843c749SSergey Zigachev 
amdgpu_pm_compute_clocks(struct amdgpu_device * adev)1980b843c749SSergey Zigachev void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
1981b843c749SSergey Zigachev {
1982b843c749SSergey Zigachev 	int i = 0;
1983b843c749SSergey Zigachev 
1984b843c749SSergey Zigachev 	if (!adev->pm.dpm_enabled)
1985b843c749SSergey Zigachev 		return;
1986b843c749SSergey Zigachev 
1987b843c749SSergey Zigachev 	if (adev->mode_info.num_crtc)
1988b843c749SSergey Zigachev 		amdgpu_display_bandwidth_update(adev);
1989b843c749SSergey Zigachev 
1990b843c749SSergey Zigachev 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
1991b843c749SSergey Zigachev 		struct amdgpu_ring *ring = adev->rings[i];
1992b843c749SSergey Zigachev 		if (ring && ring->ready)
1993b843c749SSergey Zigachev 			amdgpu_fence_wait_empty(ring);
1994b843c749SSergey Zigachev 	}
1995b843c749SSergey Zigachev 
1996b843c749SSergey Zigachev 	if (adev->powerplay.pp_funcs->dispatch_tasks) {
1997b843c749SSergey Zigachev 		if (!amdgpu_device_has_dc_support(adev)) {
1998b843c749SSergey Zigachev 			mutex_lock(&adev->pm.mutex);
1999b843c749SSergey Zigachev 			amdgpu_dpm_get_active_displays(adev);
2000b843c749SSergey Zigachev 			adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count;
2001b843c749SSergey Zigachev 			adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev);
2002b843c749SSergey Zigachev 			adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev);
2003b843c749SSergey Zigachev 			/* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */
2004b843c749SSergey Zigachev 			if (adev->pm.pm_display_cfg.vrefresh > 120)
2005b843c749SSergey Zigachev 				adev->pm.pm_display_cfg.min_vblank_time = 0;
2006b843c749SSergey Zigachev 			if (adev->powerplay.pp_funcs->display_configuration_change)
2007b843c749SSergey Zigachev 				adev->powerplay.pp_funcs->display_configuration_change(
2008b843c749SSergey Zigachev 								adev->powerplay.pp_handle,
2009b843c749SSergey Zigachev 								&adev->pm.pm_display_cfg);
2010b843c749SSergey Zigachev 			mutex_unlock(&adev->pm.mutex);
2011b843c749SSergey Zigachev 		}
2012b843c749SSergey Zigachev 		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL);
2013b843c749SSergey Zigachev 	} else {
2014b843c749SSergey Zigachev 		mutex_lock(&adev->pm.mutex);
2015b843c749SSergey Zigachev 		amdgpu_dpm_get_active_displays(adev);
2016b843c749SSergey Zigachev 		amdgpu_dpm_change_power_state_locked(adev);
2017b843c749SSergey Zigachev 		mutex_unlock(&adev->pm.mutex);
2018b843c749SSergey Zigachev 	}
2019b843c749SSergey Zigachev }
2020b843c749SSergey Zigachev 
2021b843c749SSergey Zigachev /*
2022b843c749SSergey Zigachev  * Debugfs info
2023b843c749SSergey Zigachev  */
2024b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_FS)
2025b843c749SSergey Zigachev 
amdgpu_debugfs_pm_info_pp(struct seq_file * m,struct amdgpu_device * adev)2026b843c749SSergey Zigachev static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *adev)
2027b843c749SSergey Zigachev {
2028b843c749SSergey Zigachev 	uint32_t value;
2029b843c749SSergey Zigachev 	uint32_t query = 0;
2030b843c749SSergey Zigachev 	int size;
2031b843c749SSergey Zigachev 
2032b843c749SSergey Zigachev 	/* sanity check PP is enabled */
2033b843c749SSergey Zigachev 	if (!(adev->powerplay.pp_funcs &&
2034b843c749SSergey Zigachev 	      adev->powerplay.pp_funcs->read_sensor))
2035b843c749SSergey Zigachev 	      return -EINVAL;
2036b843c749SSergey Zigachev 
2037b843c749SSergey Zigachev 	/* GPU Clocks */
2038b843c749SSergey Zigachev 	size = sizeof(value);
2039b843c749SSergey Zigachev 	seq_printf(m, "GFX Clocks and Power:\n");
2040b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK, (void *)&value, &size))
2041b843c749SSergey Zigachev 		seq_printf(m, "\t%u MHz (MCLK)\n", value/100);
2042b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, (void *)&value, &size))
2043b843c749SSergey Zigachev 		seq_printf(m, "\t%u MHz (SCLK)\n", value/100);
2044b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK, (void *)&value, &size))
2045b843c749SSergey Zigachev 		seq_printf(m, "\t%u MHz (PSTATE_SCLK)\n", value/100);
2046b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK, (void *)&value, &size))
2047b843c749SSergey Zigachev 		seq_printf(m, "\t%u MHz (PSTATE_MCLK)\n", value/100);
2048b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, (void *)&value, &size))
2049b843c749SSergey Zigachev 		seq_printf(m, "\t%u mV (VDDGFX)\n", value);
2050b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&value, &size))
2051b843c749SSergey Zigachev 		seq_printf(m, "\t%u mV (VDDNB)\n", value);
2052b843c749SSergey Zigachev 	size = sizeof(uint32_t);
2053b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER, (void *)&query, &size))
2054b843c749SSergey Zigachev 		seq_printf(m, "\t%u.%u W (average GPU)\n", query >> 8, query & 0xff);
2055b843c749SSergey Zigachev 	size = sizeof(value);
2056b843c749SSergey Zigachev 	seq_printf(m, "\n");
2057b843c749SSergey Zigachev 
2058b843c749SSergey Zigachev 	/* GPU Temp */
2059b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, (void *)&value, &size))
2060b843c749SSergey Zigachev 		seq_printf(m, "GPU Temperature: %u C\n", value/1000);
2061b843c749SSergey Zigachev 
2062b843c749SSergey Zigachev 	/* GPU Load */
2063b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, (void *)&value, &size))
2064b843c749SSergey Zigachev 		seq_printf(m, "GPU Load: %u %%\n", value);
2065b843c749SSergey Zigachev 	seq_printf(m, "\n");
2066b843c749SSergey Zigachev 
2067b843c749SSergey Zigachev 	/* UVD clocks */
2068b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_POWER, (void *)&value, &size)) {
2069b843c749SSergey Zigachev 		if (!value) {
2070b843c749SSergey Zigachev 			seq_printf(m, "UVD: Disabled\n");
2071b843c749SSergey Zigachev 		} else {
2072b843c749SSergey Zigachev 			seq_printf(m, "UVD: Enabled\n");
2073b843c749SSergey Zigachev 			if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_DCLK, (void *)&value, &size))
2074b843c749SSergey Zigachev 				seq_printf(m, "\t%u MHz (DCLK)\n", value/100);
2075b843c749SSergey Zigachev 			if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_VCLK, (void *)&value, &size))
2076b843c749SSergey Zigachev 				seq_printf(m, "\t%u MHz (VCLK)\n", value/100);
2077b843c749SSergey Zigachev 		}
2078b843c749SSergey Zigachev 	}
2079b843c749SSergey Zigachev 	seq_printf(m, "\n");
2080b843c749SSergey Zigachev 
2081b843c749SSergey Zigachev 	/* VCE clocks */
2082b843c749SSergey Zigachev 	if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_POWER, (void *)&value, &size)) {
2083b843c749SSergey Zigachev 		if (!value) {
2084b843c749SSergey Zigachev 			seq_printf(m, "VCE: Disabled\n");
2085b843c749SSergey Zigachev 		} else {
2086b843c749SSergey Zigachev 			seq_printf(m, "VCE: Enabled\n");
2087b843c749SSergey Zigachev 			if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_ECCLK, (void *)&value, &size))
2088b843c749SSergey Zigachev 				seq_printf(m, "\t%u MHz (ECCLK)\n", value/100);
2089b843c749SSergey Zigachev 		}
2090b843c749SSergey Zigachev 	}
2091b843c749SSergey Zigachev 
2092b843c749SSergey Zigachev 	return 0;
2093b843c749SSergey Zigachev }
2094b843c749SSergey Zigachev 
amdgpu_parse_cg_state(struct seq_file * m,u32 flags)2095b843c749SSergey Zigachev static void amdgpu_parse_cg_state(struct seq_file *m, u32 flags)
2096b843c749SSergey Zigachev {
2097b843c749SSergey Zigachev 	int i;
2098b843c749SSergey Zigachev 
2099b843c749SSergey Zigachev 	for (i = 0; clocks[i].flag; i++)
2100b843c749SSergey Zigachev 		seq_printf(m, "\t%s: %s\n", clocks[i].name,
2101b843c749SSergey Zigachev 			   (flags & clocks[i].flag) ? "On" : "Off");
2102b843c749SSergey Zigachev }
2103b843c749SSergey Zigachev 
amdgpu_debugfs_pm_info(struct seq_file * m,void * data)2104b843c749SSergey Zigachev static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
2105b843c749SSergey Zigachev {
2106b843c749SSergey Zigachev 	struct drm_info_node *node = (struct drm_info_node *) m->private;
2107b843c749SSergey Zigachev 	struct drm_device *dev = node->minor->dev;
2108b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
2109b843c749SSergey Zigachev 	struct drm_device *ddev = adev->ddev;
2110b843c749SSergey Zigachev 	u32 flags = 0;
2111b843c749SSergey Zigachev 
2112b843c749SSergey Zigachev 	amdgpu_device_ip_get_clockgating_state(adev, &flags);
2113b843c749SSergey Zigachev 	seq_printf(m, "Clock Gating Flags Mask: 0x%x\n", flags);
2114b843c749SSergey Zigachev 	amdgpu_parse_cg_state(m, flags);
2115b843c749SSergey Zigachev 	seq_printf(m, "\n");
2116b843c749SSergey Zigachev 
2117b843c749SSergey Zigachev 	if (!adev->pm.dpm_enabled) {
2118b843c749SSergey Zigachev 		seq_printf(m, "dpm not enabled\n");
2119b843c749SSergey Zigachev 		return 0;
2120b843c749SSergey Zigachev 	}
2121b843c749SSergey Zigachev 	if  ((adev->flags & AMD_IS_PX) &&
2122b843c749SSergey Zigachev 	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
2123b843c749SSergey Zigachev 		seq_printf(m, "PX asic powered off\n");
2124b843c749SSergey Zigachev 	} else if (adev->powerplay.pp_funcs->debugfs_print_current_performance_level) {
2125b843c749SSergey Zigachev 		mutex_lock(&adev->pm.mutex);
2126b843c749SSergey Zigachev 		if (adev->powerplay.pp_funcs->debugfs_print_current_performance_level)
2127b843c749SSergey Zigachev 			adev->powerplay.pp_funcs->debugfs_print_current_performance_level(adev, m);
2128b843c749SSergey Zigachev 		else
2129b843c749SSergey Zigachev 			seq_printf(m, "Debugfs support not implemented for this asic\n");
2130b843c749SSergey Zigachev 		mutex_unlock(&adev->pm.mutex);
2131b843c749SSergey Zigachev 	} else {
2132b843c749SSergey Zigachev 		return amdgpu_debugfs_pm_info_pp(m, adev);
2133b843c749SSergey Zigachev 	}
2134b843c749SSergey Zigachev 
2135b843c749SSergey Zigachev 	return 0;
2136b843c749SSergey Zigachev }
2137b843c749SSergey Zigachev 
2138b843c749SSergey Zigachev static const struct drm_info_list amdgpu_pm_info_list[] = {
2139b843c749SSergey Zigachev 	{"amdgpu_pm_info", amdgpu_debugfs_pm_info, 0, NULL},
2140b843c749SSergey Zigachev };
2141b843c749SSergey Zigachev #endif
2142b843c749SSergey Zigachev 
amdgpu_debugfs_pm_init(struct amdgpu_device * adev)2143b843c749SSergey Zigachev static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev)
2144b843c749SSergey Zigachev {
2145b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_FS)
2146b843c749SSergey Zigachev 	return amdgpu_debugfs_add_files(adev, amdgpu_pm_info_list, ARRAY_SIZE(amdgpu_pm_info_list));
2147b843c749SSergey Zigachev #else
2148b843c749SSergey Zigachev 	return 0;
2149b843c749SSergey Zigachev #endif
2150b843c749SSergey Zigachev }
2151