1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a
3926deccbSFrançois Tigeot * copy of this software and associated documentation files (the "Software"),
4926deccbSFrançois Tigeot * to deal in the Software without restriction, including without limitation
5926deccbSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense,
6926deccbSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the
7926deccbSFrançois Tigeot * Software is furnished to do so, subject to the following conditions:
8926deccbSFrançois Tigeot *
9926deccbSFrançois Tigeot * The above copyright notice and this permission notice shall be included in
10926deccbSFrançois Tigeot * all copies or substantial portions of the Software.
11926deccbSFrançois Tigeot *
12926deccbSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13926deccbSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14926deccbSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15926deccbSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
16926deccbSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
17926deccbSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
18926deccbSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE.
19926deccbSFrançois Tigeot *
20926deccbSFrançois Tigeot * Authors: Rafał Miłecki <zajec5@gmail.com>
21926deccbSFrançois Tigeot * Alex Deucher <alexdeucher@gmail.com>
22926deccbSFrançois Tigeot */
23926deccbSFrançois Tigeot #include <drm/drmP.h>
24926deccbSFrançois Tigeot #include "radeon.h"
25926deccbSFrançois Tigeot #include "avivod.h"
26926deccbSFrançois Tigeot #include "atom.h"
27c59a5c48SFrançois Tigeot #include "r600_dpm.h"
281cfef1a5SFrançois Tigeot #include <linux/power_supply.h>
291cfef1a5SFrançois Tigeot #include <linux/hwmon.h>
301cfef1a5SFrançois Tigeot
311cfef1a5SFrançois Tigeot #include <sys/power.h>
321cfef1a5SFrançois Tigeot #include <sys/sensors.h>
33926deccbSFrançois Tigeot
34926deccbSFrançois Tigeot #define RADEON_IDLE_LOOP_MS 100
35926deccbSFrançois Tigeot #define RADEON_RECLOCK_DELAY_MS 200
36926deccbSFrançois Tigeot #define RADEON_WAIT_VBLANK_TIMEOUT 200
37926deccbSFrançois Tigeot
38926deccbSFrançois Tigeot static const char *radeon_pm_state_type_name[5] = {
39926deccbSFrançois Tigeot "",
40926deccbSFrançois Tigeot "Powersave",
41926deccbSFrançois Tigeot "Battery",
42926deccbSFrançois Tigeot "Balanced",
43926deccbSFrançois Tigeot "Performance",
44926deccbSFrançois Tigeot };
45926deccbSFrançois Tigeot
46926deccbSFrançois Tigeot static void radeon_dynpm_idle_work_handler(struct work_struct *work);
47926deccbSFrançois Tigeot static int radeon_debugfs_pm_init(struct radeon_device *rdev);
48926deccbSFrançois Tigeot static bool radeon_pm_in_vbl(struct radeon_device *rdev);
49926deccbSFrançois Tigeot static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish);
50926deccbSFrançois Tigeot static void radeon_pm_update_profile(struct radeon_device *rdev);
51926deccbSFrançois Tigeot static void radeon_pm_set_clocks(struct radeon_device *rdev);
52926deccbSFrançois Tigeot
radeon_pm_get_type_index(struct radeon_device * rdev,enum radeon_pm_state_type ps_type,int instance)53926deccbSFrançois Tigeot int radeon_pm_get_type_index(struct radeon_device *rdev,
54926deccbSFrançois Tigeot enum radeon_pm_state_type ps_type,
55926deccbSFrançois Tigeot int instance)
56926deccbSFrançois Tigeot {
57926deccbSFrançois Tigeot int i;
58926deccbSFrançois Tigeot int found_instance = -1;
59926deccbSFrançois Tigeot
60926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; i++) {
61926deccbSFrançois Tigeot if (rdev->pm.power_state[i].type == ps_type) {
62926deccbSFrançois Tigeot found_instance++;
63926deccbSFrançois Tigeot if (found_instance == instance)
64926deccbSFrançois Tigeot return i;
65926deccbSFrançois Tigeot }
66926deccbSFrançois Tigeot }
67926deccbSFrançois Tigeot /* return default if no match */
68926deccbSFrançois Tigeot return rdev->pm.default_power_state_index;
69926deccbSFrançois Tigeot }
70926deccbSFrançois Tigeot
radeon_pm_acpi_event_handler(struct radeon_device * rdev)71926deccbSFrançois Tigeot void radeon_pm_acpi_event_handler(struct radeon_device *rdev)
72926deccbSFrançois Tigeot {
734cd92098Szrj if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
741cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
75c6f73aabSFrançois Tigeot if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE)
764cd92098Szrj rdev->pm.dpm.ac_power = true;
774cd92098Szrj else
784cd92098Szrj rdev->pm.dpm.ac_power = false;
79c6f73aabSFrançois Tigeot if (rdev->family == CHIP_ARUBA) {
804cd92098Szrj if (rdev->asic->dpm.enable_bapm)
814cd92098Szrj radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power);
82c6f73aabSFrançois Tigeot }
831cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
844cd92098Szrj } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
85926deccbSFrançois Tigeot if (rdev->pm.profile == PM_PROFILE_AUTO) {
861cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
87926deccbSFrançois Tigeot radeon_pm_update_profile(rdev);
88926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
891cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
90926deccbSFrançois Tigeot }
91926deccbSFrançois Tigeot }
92926deccbSFrançois Tigeot }
93926deccbSFrançois Tigeot
radeon_pm_update_profile(struct radeon_device * rdev)94926deccbSFrançois Tigeot static void radeon_pm_update_profile(struct radeon_device *rdev)
95926deccbSFrançois Tigeot {
96926deccbSFrançois Tigeot switch (rdev->pm.profile) {
97926deccbSFrançois Tigeot case PM_PROFILE_DEFAULT:
98926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_DEFAULT_IDX;
99926deccbSFrançois Tigeot break;
100926deccbSFrançois Tigeot case PM_PROFILE_AUTO:
10157e252bfSMichael Neumann if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) {
102926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1)
103926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX;
104926deccbSFrançois Tigeot else
105926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX;
106926deccbSFrançois Tigeot } else {
107926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1)
108926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_MH_IDX;
109926deccbSFrançois Tigeot else
110926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_SH_IDX;
111926deccbSFrançois Tigeot }
112926deccbSFrançois Tigeot break;
113926deccbSFrançois Tigeot case PM_PROFILE_LOW:
114926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1)
115926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX;
116926deccbSFrançois Tigeot else
117926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX;
118926deccbSFrançois Tigeot break;
119926deccbSFrançois Tigeot case PM_PROFILE_MID:
120926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1)
121926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_MH_IDX;
122926deccbSFrançois Tigeot else
123926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_SH_IDX;
124926deccbSFrançois Tigeot break;
125926deccbSFrançois Tigeot case PM_PROFILE_HIGH:
126926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1)
127926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX;
128926deccbSFrançois Tigeot else
129926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX;
130926deccbSFrançois Tigeot break;
131926deccbSFrançois Tigeot }
132926deccbSFrançois Tigeot
133926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count == 0) {
134926deccbSFrançois Tigeot rdev->pm.requested_power_state_index =
135926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_off_ps_idx;
136926deccbSFrançois Tigeot rdev->pm.requested_clock_mode_index =
137926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_off_cm_idx;
138926deccbSFrançois Tigeot } else {
139926deccbSFrançois Tigeot rdev->pm.requested_power_state_index =
140926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_on_ps_idx;
141926deccbSFrançois Tigeot rdev->pm.requested_clock_mode_index =
142926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_on_cm_idx;
143926deccbSFrançois Tigeot }
144926deccbSFrançois Tigeot }
145926deccbSFrançois Tigeot
radeon_unmap_vram_bos(struct radeon_device * rdev)146926deccbSFrançois Tigeot static void radeon_unmap_vram_bos(struct radeon_device *rdev)
147926deccbSFrançois Tigeot {
148926deccbSFrançois Tigeot struct radeon_bo *bo, *n;
149926deccbSFrançois Tigeot
150926deccbSFrançois Tigeot if (list_empty(&rdev->gem.objects))
151926deccbSFrançois Tigeot return;
152926deccbSFrançois Tigeot
153926deccbSFrançois Tigeot list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) {
154926deccbSFrançois Tigeot if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
155926deccbSFrançois Tigeot ttm_bo_unmap_virtual(&bo->tbo);
156926deccbSFrançois Tigeot }
157926deccbSFrançois Tigeot }
158926deccbSFrançois Tigeot
radeon_sync_with_vblank(struct radeon_device * rdev)159926deccbSFrançois Tigeot static void radeon_sync_with_vblank(struct radeon_device *rdev)
160926deccbSFrançois Tigeot {
161926deccbSFrançois Tigeot if (rdev->pm.active_crtcs) {
162926deccbSFrançois Tigeot rdev->pm.vblank_sync = false;
163ee479021SImre Vadász #ifdef DUMBBELL_WIP
164926deccbSFrançois Tigeot wait_event_timeout(
165926deccbSFrançois Tigeot rdev->irq.vblank_queue, rdev->pm.vblank_sync,
166926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
167ee479021SImre Vadász #endif /* DUMBBELL_WIP */
168926deccbSFrançois Tigeot }
169926deccbSFrançois Tigeot }
170926deccbSFrançois Tigeot
radeon_set_power_state(struct radeon_device * rdev)171926deccbSFrançois Tigeot static void radeon_set_power_state(struct radeon_device *rdev)
172926deccbSFrançois Tigeot {
173926deccbSFrançois Tigeot u32 sclk, mclk;
174926deccbSFrançois Tigeot bool misc_after = false;
175926deccbSFrançois Tigeot
176926deccbSFrançois Tigeot if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
177926deccbSFrançois Tigeot (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index))
178926deccbSFrançois Tigeot return;
179926deccbSFrançois Tigeot
180926deccbSFrançois Tigeot if (radeon_gui_idle(rdev)) {
181926deccbSFrançois Tigeot sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
182926deccbSFrançois Tigeot clock_info[rdev->pm.requested_clock_mode_index].sclk;
183926deccbSFrançois Tigeot if (sclk > rdev->pm.default_sclk)
184926deccbSFrançois Tigeot sclk = rdev->pm.default_sclk;
185926deccbSFrançois Tigeot
186926deccbSFrançois Tigeot /* starting with BTC, there is one state that is used for both
187926deccbSFrançois Tigeot * MH and SH. Difference is that we always use the high clock index for
188b403bed8SMichael Neumann * mclk and vddci.
189926deccbSFrançois Tigeot */
190926deccbSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_PROFILE) &&
191926deccbSFrançois Tigeot (rdev->family >= CHIP_BARTS) &&
192926deccbSFrançois Tigeot rdev->pm.active_crtc_count &&
193926deccbSFrançois Tigeot ((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) ||
194926deccbSFrançois Tigeot (rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX)))
195926deccbSFrançois Tigeot mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
196926deccbSFrançois Tigeot clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].mclk;
197926deccbSFrançois Tigeot else
198926deccbSFrançois Tigeot mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
199926deccbSFrançois Tigeot clock_info[rdev->pm.requested_clock_mode_index].mclk;
200926deccbSFrançois Tigeot
201926deccbSFrançois Tigeot if (mclk > rdev->pm.default_mclk)
202926deccbSFrançois Tigeot mclk = rdev->pm.default_mclk;
203926deccbSFrançois Tigeot
204926deccbSFrançois Tigeot /* upvolt before raising clocks, downvolt after lowering clocks */
205926deccbSFrançois Tigeot if (sclk < rdev->pm.current_sclk)
206926deccbSFrançois Tigeot misc_after = true;
207926deccbSFrançois Tigeot
208926deccbSFrançois Tigeot radeon_sync_with_vblank(rdev);
209926deccbSFrançois Tigeot
210926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
211926deccbSFrançois Tigeot if (!radeon_pm_in_vbl(rdev))
212926deccbSFrançois Tigeot return;
213926deccbSFrançois Tigeot }
214926deccbSFrançois Tigeot
215926deccbSFrançois Tigeot radeon_pm_prepare(rdev);
216926deccbSFrançois Tigeot
217926deccbSFrançois Tigeot if (!misc_after)
218926deccbSFrançois Tigeot /* voltage, pcie lanes, etc.*/
219926deccbSFrançois Tigeot radeon_pm_misc(rdev);
220926deccbSFrançois Tigeot
221926deccbSFrançois Tigeot /* set engine clock */
222926deccbSFrançois Tigeot if (sclk != rdev->pm.current_sclk) {
223926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, false);
224926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, sclk);
225926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, true);
226926deccbSFrançois Tigeot rdev->pm.current_sclk = sclk;
227926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("Setting: e: %d\n", sclk);
228926deccbSFrançois Tigeot }
229926deccbSFrançois Tigeot
230926deccbSFrançois Tigeot /* set memory clock */
231926deccbSFrançois Tigeot if (rdev->asic->pm.set_memory_clock && (mclk != rdev->pm.current_mclk)) {
232926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, false);
233926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, mclk);
234926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, true);
235926deccbSFrançois Tigeot rdev->pm.current_mclk = mclk;
236926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("Setting: m: %d\n", mclk);
237926deccbSFrançois Tigeot }
238926deccbSFrançois Tigeot
239926deccbSFrançois Tigeot if (misc_after)
240926deccbSFrançois Tigeot /* voltage, pcie lanes, etc.*/
241926deccbSFrançois Tigeot radeon_pm_misc(rdev);
242926deccbSFrançois Tigeot
243926deccbSFrançois Tigeot radeon_pm_finish(rdev);
244926deccbSFrançois Tigeot
245926deccbSFrançois Tigeot rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
246926deccbSFrançois Tigeot rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
247926deccbSFrançois Tigeot } else
248926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("pm: GUI not idle!!!\n");
249926deccbSFrançois Tigeot }
250926deccbSFrançois Tigeot
radeon_pm_set_clocks(struct radeon_device * rdev)251926deccbSFrançois Tigeot static void radeon_pm_set_clocks(struct radeon_device *rdev)
252926deccbSFrançois Tigeot {
2531dedbd3bSFrançois Tigeot struct drm_crtc *crtc;
254926deccbSFrançois Tigeot int i, r;
255926deccbSFrançois Tigeot
256926deccbSFrançois Tigeot /* no need to take locks, etc. if nothing's going to change */
257926deccbSFrançois Tigeot if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
258926deccbSFrançois Tigeot (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index))
259926deccbSFrançois Tigeot return;
260926deccbSFrançois Tigeot
2611cfef1a5SFrançois Tigeot down_write(&rdev->pm.mclk_lock);
2621cfef1a5SFrançois Tigeot mutex_lock(&rdev->ring_lock);
263926deccbSFrançois Tigeot
264926deccbSFrançois Tigeot /* wait for the rings to drain */
265926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) {
266926deccbSFrançois Tigeot struct radeon_ring *ring = &rdev->ring[i];
267926deccbSFrançois Tigeot if (!ring->ready) {
268926deccbSFrançois Tigeot continue;
269926deccbSFrançois Tigeot }
270c6f73aabSFrançois Tigeot r = radeon_fence_wait_empty(rdev, i);
271926deccbSFrançois Tigeot if (r) {
272926deccbSFrançois Tigeot /* needs a GPU reset dont reset here */
2731cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock);
2741cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock);
275926deccbSFrançois Tigeot return;
276926deccbSFrançois Tigeot }
277926deccbSFrançois Tigeot }
278926deccbSFrançois Tigeot
279926deccbSFrançois Tigeot radeon_unmap_vram_bos(rdev);
280926deccbSFrançois Tigeot
281926deccbSFrançois Tigeot if (rdev->irq.installed) {
2821dedbd3bSFrançois Tigeot i = 0;
2831dedbd3bSFrançois Tigeot drm_for_each_crtc(crtc, rdev->ddev) {
284926deccbSFrançois Tigeot if (rdev->pm.active_crtcs & (1 << i)) {
285d78d3a22SFrançois Tigeot /* This can fail if a modeset is in progress */
2861dedbd3bSFrançois Tigeot if (drm_crtc_vblank_get(crtc) == 0)
287926deccbSFrançois Tigeot rdev->pm.req_vblank |= (1 << i);
288d78d3a22SFrançois Tigeot else
289d78d3a22SFrançois Tigeot DRM_DEBUG_DRIVER("crtc %d no vblank, can glitch\n",
290d78d3a22SFrançois Tigeot i);
291926deccbSFrançois Tigeot }
2921dedbd3bSFrançois Tigeot i++;
293926deccbSFrançois Tigeot }
294926deccbSFrançois Tigeot }
295926deccbSFrançois Tigeot
296926deccbSFrançois Tigeot radeon_set_power_state(rdev);
297926deccbSFrançois Tigeot
298926deccbSFrançois Tigeot if (rdev->irq.installed) {
2991dedbd3bSFrançois Tigeot i = 0;
3001dedbd3bSFrançois Tigeot drm_for_each_crtc(crtc, rdev->ddev) {
301926deccbSFrançois Tigeot if (rdev->pm.req_vblank & (1 << i)) {
302926deccbSFrançois Tigeot rdev->pm.req_vblank &= ~(1 << i);
3031dedbd3bSFrançois Tigeot drm_crtc_vblank_put(crtc);
304926deccbSFrançois Tigeot }
3051dedbd3bSFrançois Tigeot i++;
306926deccbSFrançois Tigeot }
307926deccbSFrançois Tigeot }
308926deccbSFrançois Tigeot
309926deccbSFrançois Tigeot /* update display watermarks based on new power state */
310926deccbSFrançois Tigeot radeon_update_bandwidth_info(rdev);
311926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count)
312926deccbSFrançois Tigeot radeon_bandwidth_update(rdev);
313926deccbSFrançois Tigeot
314926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
315926deccbSFrançois Tigeot
3161cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock);
3171cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock);
318926deccbSFrançois Tigeot }
319926deccbSFrançois Tigeot
radeon_pm_print_states(struct radeon_device * rdev)320926deccbSFrançois Tigeot static void radeon_pm_print_states(struct radeon_device *rdev)
321926deccbSFrançois Tigeot {
322926deccbSFrançois Tigeot int i, j;
323926deccbSFrançois Tigeot struct radeon_power_state *power_state;
324926deccbSFrançois Tigeot struct radeon_pm_clock_info *clock_info;
325926deccbSFrançois Tigeot
326926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("%d Power State(s)\n", rdev->pm.num_power_states);
327926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; i++) {
328926deccbSFrançois Tigeot power_state = &rdev->pm.power_state[i];
329926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("State %d: %s\n", i,
330926deccbSFrançois Tigeot radeon_pm_state_type_name[power_state->type]);
331926deccbSFrançois Tigeot if (i == rdev->pm.default_power_state_index)
332926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\tDefault");
333926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP))
334926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t%d PCIE Lanes\n", power_state->pcie_lanes);
335926deccbSFrançois Tigeot if (power_state->flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
336926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\tSingle display only\n");
337926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t%d Clock Mode(s)\n", power_state->num_clock_modes);
338926deccbSFrançois Tigeot for (j = 0; j < power_state->num_clock_modes; j++) {
339926deccbSFrançois Tigeot clock_info = &(power_state->clock_info[j]);
340926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_IGP)
341926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t\t%d e: %d\n",
342926deccbSFrançois Tigeot j,
343926deccbSFrançois Tigeot clock_info->sclk * 10);
344926deccbSFrançois Tigeot else
345926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d\n",
346926deccbSFrançois Tigeot j,
347926deccbSFrançois Tigeot clock_info->sclk * 10,
348926deccbSFrançois Tigeot clock_info->mclk * 10,
349926deccbSFrançois Tigeot clock_info->voltage.voltage);
350926deccbSFrançois Tigeot }
351926deccbSFrançois Tigeot }
352926deccbSFrançois Tigeot }
353926deccbSFrançois Tigeot
354926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
radeon_get_pm_profile(struct device * dev,struct device_attribute * attr,char * buf)355926deccbSFrançois Tigeot static ssize_t radeon_get_pm_profile(struct device *dev,
356926deccbSFrançois Tigeot struct device_attribute *attr,
357926deccbSFrançois Tigeot char *buf)
358926deccbSFrançois Tigeot {
359c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
360926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private;
361926deccbSFrançois Tigeot int cp = rdev->pm.profile;
362926deccbSFrançois Tigeot
363926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%s\n",
364926deccbSFrançois Tigeot (cp == PM_PROFILE_AUTO) ? "auto" :
365926deccbSFrançois Tigeot (cp == PM_PROFILE_LOW) ? "low" :
366926deccbSFrançois Tigeot (cp == PM_PROFILE_MID) ? "mid" :
367926deccbSFrançois Tigeot (cp == PM_PROFILE_HIGH) ? "high" : "default");
368926deccbSFrançois Tigeot }
369926deccbSFrançois Tigeot
radeon_set_pm_profile(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)370926deccbSFrançois Tigeot static ssize_t radeon_set_pm_profile(struct device *dev,
371926deccbSFrançois Tigeot struct device_attribute *attr,
372926deccbSFrançois Tigeot const char *buf,
373926deccbSFrançois Tigeot size_t count)
374926deccbSFrançois Tigeot {
375c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
376926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private;
377926deccbSFrançois Tigeot
378c6f73aabSFrançois Tigeot /* Can't set profile when the card is off */
379c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) &&
380c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
381c6f73aabSFrançois Tigeot return -EINVAL;
382c6f73aabSFrançois Tigeot
3831cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
384926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
385926deccbSFrançois Tigeot if (strncmp("default", buf, strlen("default")) == 0)
386926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT;
387926deccbSFrançois Tigeot else if (strncmp("auto", buf, strlen("auto")) == 0)
388926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_AUTO;
389926deccbSFrançois Tigeot else if (strncmp("low", buf, strlen("low")) == 0)
390926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_LOW;
391926deccbSFrançois Tigeot else if (strncmp("mid", buf, strlen("mid")) == 0)
392926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_MID;
393926deccbSFrançois Tigeot else if (strncmp("high", buf, strlen("high")) == 0)
394926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_HIGH;
395926deccbSFrançois Tigeot else {
396926deccbSFrançois Tigeot count = -EINVAL;
397926deccbSFrançois Tigeot goto fail;
398926deccbSFrançois Tigeot }
399926deccbSFrançois Tigeot radeon_pm_update_profile(rdev);
400926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
401926deccbSFrançois Tigeot } else
402926deccbSFrançois Tigeot count = -EINVAL;
403926deccbSFrançois Tigeot
404926deccbSFrançois Tigeot fail:
4051cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
406926deccbSFrançois Tigeot
407926deccbSFrançois Tigeot return count;
408926deccbSFrançois Tigeot }
409926deccbSFrançois Tigeot
radeon_get_pm_method(struct device * dev,struct device_attribute * attr,char * buf)410926deccbSFrançois Tigeot static ssize_t radeon_get_pm_method(struct device *dev,
411926deccbSFrançois Tigeot struct device_attribute *attr,
412926deccbSFrançois Tigeot char *buf)
413926deccbSFrançois Tigeot {
414c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
415926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private;
416926deccbSFrançois Tigeot int pm = rdev->pm.pm_method;
417926deccbSFrançois Tigeot
418926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%s\n",
41957e252bfSMichael Neumann (pm == PM_METHOD_DYNPM) ? "dynpm" :
42057e252bfSMichael Neumann (pm == PM_METHOD_PROFILE) ? "profile" : "dpm");
421926deccbSFrançois Tigeot }
422926deccbSFrançois Tigeot
radeon_set_pm_method(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)423926deccbSFrançois Tigeot static ssize_t radeon_set_pm_method(struct device *dev,
424926deccbSFrançois Tigeot struct device_attribute *attr,
425926deccbSFrançois Tigeot const char *buf,
426926deccbSFrançois Tigeot size_t count)
427926deccbSFrançois Tigeot {
428c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
429926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private;
430926deccbSFrançois Tigeot
431c6f73aabSFrançois Tigeot /* Can't set method when the card is off */
432c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) &&
433c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
434c6f73aabSFrançois Tigeot count = -EINVAL;
435c6f73aabSFrançois Tigeot goto fail;
436c6f73aabSFrançois Tigeot }
437c6f73aabSFrançois Tigeot
43857e252bfSMichael Neumann /* we don't support the legacy modes with dpm */
43957e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) {
44057e252bfSMichael Neumann count = -EINVAL;
44157e252bfSMichael Neumann goto fail;
44257e252bfSMichael Neumann }
443926deccbSFrançois Tigeot
444926deccbSFrançois Tigeot if (strncmp("dynpm", buf, strlen("dynpm")) == 0) {
4451cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
446926deccbSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DYNPM;
447926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_PAUSED;
448926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
4491cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
450926deccbSFrançois Tigeot } else if (strncmp("profile", buf, strlen("profile")) == 0) {
4511cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
452926deccbSFrançois Tigeot /* disable dynpm */
453926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
454926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
455926deccbSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE;
4561cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
457ee479021SImre Vadász #ifdef DUMBBELL_WIP
458926deccbSFrançois Tigeot cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
459ee479021SImre Vadász #endif /* DUMBBELL_WIP */
460926deccbSFrançois Tigeot } else {
461926deccbSFrançois Tigeot count = -EINVAL;
462926deccbSFrançois Tigeot goto fail;
463926deccbSFrançois Tigeot }
464926deccbSFrançois Tigeot radeon_pm_compute_clocks(rdev);
465926deccbSFrançois Tigeot fail:
466926deccbSFrançois Tigeot return count;
467926deccbSFrançois Tigeot }
468926deccbSFrançois Tigeot
radeon_get_dpm_state(struct device * dev,struct device_attribute * attr,char * buf)46957e252bfSMichael Neumann static ssize_t radeon_get_dpm_state(struct device *dev,
47057e252bfSMichael Neumann struct device_attribute *attr,
47157e252bfSMichael Neumann char *buf)
47257e252bfSMichael Neumann {
473c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
47457e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private;
47557e252bfSMichael Neumann enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
47657e252bfSMichael Neumann
47757e252bfSMichael Neumann return snprintf(buf, PAGE_SIZE, "%s\n",
47857e252bfSMichael Neumann (pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
47957e252bfSMichael Neumann (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
48057e252bfSMichael Neumann }
48157e252bfSMichael Neumann
radeon_set_dpm_state(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)48257e252bfSMichael Neumann static ssize_t radeon_set_dpm_state(struct device *dev,
48357e252bfSMichael Neumann struct device_attribute *attr,
48457e252bfSMichael Neumann const char *buf,
48557e252bfSMichael Neumann size_t count)
48657e252bfSMichael Neumann {
487c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
48857e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private;
48957e252bfSMichael Neumann
4901cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
49157e252bfSMichael Neumann if (strncmp("battery", buf, strlen("battery")) == 0)
49257e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
49357e252bfSMichael Neumann else if (strncmp("balanced", buf, strlen("balanced")) == 0)
49457e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
49557e252bfSMichael Neumann else if (strncmp("performance", buf, strlen("performance")) == 0)
49657e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
49757e252bfSMichael Neumann else {
4981cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
49957e252bfSMichael Neumann count = -EINVAL;
50057e252bfSMichael Neumann goto fail;
50157e252bfSMichael Neumann }
5021cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
503c6f73aabSFrançois Tigeot
504c6f73aabSFrançois Tigeot /* Can't set dpm state when the card is off */
505c6f73aabSFrançois Tigeot if (!(rdev->flags & RADEON_IS_PX) ||
506c6f73aabSFrançois Tigeot (ddev->switch_power_state == DRM_SWITCH_POWER_ON))
50757e252bfSMichael Neumann radeon_pm_compute_clocks(rdev);
508c6f73aabSFrançois Tigeot
50957e252bfSMichael Neumann fail:
51057e252bfSMichael Neumann return count;
51157e252bfSMichael Neumann }
51257e252bfSMichael Neumann
radeon_get_dpm_forced_performance_level(struct device * dev,struct device_attribute * attr,char * buf)51357e252bfSMichael Neumann static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
51457e252bfSMichael Neumann struct device_attribute *attr,
51557e252bfSMichael Neumann char *buf)
51657e252bfSMichael Neumann {
517c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
51857e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private;
51957e252bfSMichael Neumann enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
52057e252bfSMichael Neumann
521c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) &&
522c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
5231cfef1a5SFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "off\n");
524c6f73aabSFrançois Tigeot
52557e252bfSMichael Neumann return snprintf(buf, PAGE_SIZE, "%s\n",
52657e252bfSMichael Neumann (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
52757e252bfSMichael Neumann (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
52857e252bfSMichael Neumann }
52957e252bfSMichael Neumann
radeon_set_dpm_forced_performance_level(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)53057e252bfSMichael Neumann static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
53157e252bfSMichael Neumann struct device_attribute *attr,
53257e252bfSMichael Neumann const char *buf,
53357e252bfSMichael Neumann size_t count)
53457e252bfSMichael Neumann {
535c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev);
53657e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private;
53757e252bfSMichael Neumann enum radeon_dpm_forced_level level;
53857e252bfSMichael Neumann int ret = 0;
53957e252bfSMichael Neumann
540c6f73aabSFrançois Tigeot /* Can't force performance level when the card is off */
541c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) &&
542c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
543c6f73aabSFrançois Tigeot return -EINVAL;
544c6f73aabSFrançois Tigeot
5451cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
54657e252bfSMichael Neumann if (strncmp("low", buf, strlen("low")) == 0) {
54757e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_LOW;
54857e252bfSMichael Neumann } else if (strncmp("high", buf, strlen("high")) == 0) {
54957e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_HIGH;
55057e252bfSMichael Neumann } else if (strncmp("auto", buf, strlen("auto")) == 0) {
55157e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_AUTO;
55257e252bfSMichael Neumann } else {
55357e252bfSMichael Neumann count = -EINVAL;
55457e252bfSMichael Neumann goto fail;
55557e252bfSMichael Neumann }
55657e252bfSMichael Neumann if (rdev->asic->dpm.force_performance_level) {
557c6f73aabSFrançois Tigeot if (rdev->pm.dpm.thermal_active) {
558c6f73aabSFrançois Tigeot count = -EINVAL;
559c6f73aabSFrançois Tigeot goto fail;
560c6f73aabSFrançois Tigeot }
56157e252bfSMichael Neumann ret = radeon_dpm_force_performance_level(rdev, level);
56257e252bfSMichael Neumann if (ret)
56357e252bfSMichael Neumann count = -EINVAL;
56457e252bfSMichael Neumann }
56557e252bfSMichael Neumann fail:
5661cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
567c6f73aabSFrançois Tigeot
56857e252bfSMichael Neumann return count;
56957e252bfSMichael Neumann }
57057e252bfSMichael Neumann
radeon_hwmon_get_pwm1_enable(struct device * dev,struct device_attribute * attr,char * buf)571c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev,
572c59a5c48SFrançois Tigeot struct device_attribute *attr,
573c59a5c48SFrançois Tigeot char *buf)
574c59a5c48SFrançois Tigeot {
575c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev);
576c59a5c48SFrançois Tigeot u32 pwm_mode = 0;
577c59a5c48SFrançois Tigeot
578c59a5c48SFrançois Tigeot if (rdev->asic->dpm.fan_ctrl_get_mode)
579c59a5c48SFrançois Tigeot pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev);
580c59a5c48SFrançois Tigeot
581c59a5c48SFrançois Tigeot /* never 0 (full-speed), fuse or smc-controlled always */
582c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
583c59a5c48SFrançois Tigeot }
584c59a5c48SFrançois Tigeot
radeon_hwmon_set_pwm1_enable(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)585c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev,
586c59a5c48SFrançois Tigeot struct device_attribute *attr,
587c59a5c48SFrançois Tigeot const char *buf,
588c59a5c48SFrançois Tigeot size_t count)
589c59a5c48SFrançois Tigeot {
590c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev);
591c59a5c48SFrançois Tigeot int err;
592c59a5c48SFrançois Tigeot int value;
593c59a5c48SFrançois Tigeot
594c59a5c48SFrançois Tigeot if(!rdev->asic->dpm.fan_ctrl_set_mode)
595c59a5c48SFrançois Tigeot return -EINVAL;
596c59a5c48SFrançois Tigeot
597c59a5c48SFrançois Tigeot err = kstrtoint(buf, 10, &value);
598c59a5c48SFrançois Tigeot if (err)
599c59a5c48SFrançois Tigeot return err;
600c59a5c48SFrançois Tigeot
601c59a5c48SFrançois Tigeot switch (value) {
602c59a5c48SFrançois Tigeot case 1: /* manual, percent-based */
603c59a5c48SFrançois Tigeot rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC);
604c59a5c48SFrançois Tigeot break;
605c59a5c48SFrançois Tigeot default: /* disable */
606c59a5c48SFrançois Tigeot rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0);
607c59a5c48SFrançois Tigeot break;
608c59a5c48SFrançois Tigeot }
609c59a5c48SFrançois Tigeot
610c59a5c48SFrançois Tigeot return count;
611c59a5c48SFrançois Tigeot }
612c59a5c48SFrançois Tigeot
radeon_hwmon_get_pwm1_min(struct device * dev,struct device_attribute * attr,char * buf)613c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev,
614c59a5c48SFrançois Tigeot struct device_attribute *attr,
615c59a5c48SFrançois Tigeot char *buf)
616c59a5c48SFrançois Tigeot {
617c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", 0);
618c59a5c48SFrançois Tigeot }
619c59a5c48SFrançois Tigeot
radeon_hwmon_get_pwm1_max(struct device * dev,struct device_attribute * attr,char * buf)620c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev,
621c59a5c48SFrançois Tigeot struct device_attribute *attr,
622c59a5c48SFrançois Tigeot char *buf)
623c59a5c48SFrançois Tigeot {
624c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", 255);
625c59a5c48SFrançois Tigeot }
626c59a5c48SFrançois Tigeot
radeon_hwmon_set_pwm1(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)627c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_set_pwm1(struct device *dev,
628c59a5c48SFrançois Tigeot struct device_attribute *attr,
629c59a5c48SFrançois Tigeot const char *buf, size_t count)
630c59a5c48SFrançois Tigeot {
631c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev);
632c59a5c48SFrançois Tigeot int err;
633c59a5c48SFrançois Tigeot u32 value;
634c59a5c48SFrançois Tigeot
635c59a5c48SFrançois Tigeot err = kstrtou32(buf, 10, &value);
636c59a5c48SFrançois Tigeot if (err)
637c59a5c48SFrançois Tigeot return err;
638c59a5c48SFrançois Tigeot
639c59a5c48SFrançois Tigeot value = (value * 100) / 255;
640c59a5c48SFrançois Tigeot
641c59a5c48SFrançois Tigeot err = rdev->asic->dpm.set_fan_speed_percent(rdev, value);
642c59a5c48SFrançois Tigeot if (err)
643c59a5c48SFrançois Tigeot return err;
644c59a5c48SFrançois Tigeot
645c59a5c48SFrançois Tigeot return count;
646c59a5c48SFrançois Tigeot }
647c59a5c48SFrançois Tigeot
radeon_hwmon_get_pwm1(struct device * dev,struct device_attribute * attr,char * buf)648c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1(struct device *dev,
649c59a5c48SFrançois Tigeot struct device_attribute *attr,
650c59a5c48SFrançois Tigeot char *buf)
651c59a5c48SFrançois Tigeot {
652c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev);
653c59a5c48SFrançois Tigeot int err;
654c59a5c48SFrançois Tigeot u32 speed;
655c59a5c48SFrançois Tigeot
656c59a5c48SFrançois Tigeot err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed);
657c59a5c48SFrançois Tigeot if (err)
658c59a5c48SFrançois Tigeot return err;
659c59a5c48SFrançois Tigeot
660c59a5c48SFrançois Tigeot speed = (speed * 255) / 100;
661c59a5c48SFrançois Tigeot
662c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", speed);
663c59a5c48SFrançois Tigeot }
664c59a5c48SFrançois Tigeot
665926deccbSFrançois Tigeot static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
666926deccbSFrançois Tigeot static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
66757e252bfSMichael Neumann static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
66857e252bfSMichael Neumann static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
66957e252bfSMichael Neumann radeon_get_dpm_forced_performance_level,
67057e252bfSMichael Neumann radeon_set_dpm_forced_performance_level);
671926deccbSFrançois Tigeot
radeon_hwmon_show_temp(struct device * dev,struct device_attribute * attr,char * buf)672926deccbSFrançois Tigeot static ssize_t radeon_hwmon_show_temp(struct device *dev,
673926deccbSFrançois Tigeot struct device_attribute *attr,
674926deccbSFrançois Tigeot char *buf)
675926deccbSFrançois Tigeot {
676c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev);
677c6f73aabSFrançois Tigeot struct drm_device *ddev = rdev->ddev;
678926deccbSFrançois Tigeot int temp;
679926deccbSFrançois Tigeot
680c6f73aabSFrançois Tigeot /* Can't get temperature when the card is off */
681c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) &&
682c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
683c6f73aabSFrançois Tigeot return -EINVAL;
684c6f73aabSFrançois Tigeot
68557e252bfSMichael Neumann if (rdev->asic->pm.get_temperature)
68657e252bfSMichael Neumann temp = radeon_get_temperature(rdev);
68757e252bfSMichael Neumann else
688926deccbSFrançois Tigeot temp = 0;
689926deccbSFrançois Tigeot
690926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%d\n", temp);
691926deccbSFrançois Tigeot }
692926deccbSFrançois Tigeot
radeon_hwmon_show_temp_thresh(struct device * dev,struct device_attribute * attr,char * buf)693c6f73aabSFrançois Tigeot static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
694926deccbSFrançois Tigeot struct device_attribute *attr,
695926deccbSFrançois Tigeot char *buf)
696926deccbSFrançois Tigeot {
697c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev);
698c6f73aabSFrançois Tigeot int hyst = to_sensor_dev_attr(attr)->index;
699c6f73aabSFrançois Tigeot int temp;
700c6f73aabSFrançois Tigeot
701c6f73aabSFrançois Tigeot if (hyst)
702c6f73aabSFrançois Tigeot temp = rdev->pm.dpm.thermal.min_temp;
703c6f73aabSFrançois Tigeot else
704c6f73aabSFrançois Tigeot temp = rdev->pm.dpm.thermal.max_temp;
705c6f73aabSFrançois Tigeot
706c6f73aabSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%d\n", temp);
707926deccbSFrançois Tigeot }
708926deccbSFrançois Tigeot
709926deccbSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
710c6f73aabSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0);
711c6f73aabSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1);
712c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0);
713c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0);
714c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0);
715c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0);
716c59a5c48SFrançois Tigeot
717926deccbSFrançois Tigeot
718926deccbSFrançois Tigeot static struct attribute *hwmon_attributes[] = {
719926deccbSFrançois Tigeot &sensor_dev_attr_temp1_input.dev_attr.attr,
720c6f73aabSFrançois Tigeot &sensor_dev_attr_temp1_crit.dev_attr.attr,
721c6f73aabSFrançois Tigeot &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
722c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1.dev_attr.attr,
723c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1_enable.dev_attr.attr,
724c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1_min.dev_attr.attr,
725c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1_max.dev_attr.attr,
726926deccbSFrançois Tigeot NULL
727926deccbSFrançois Tigeot };
728926deccbSFrançois Tigeot
hwmon_attributes_visible(struct kobject * kobj,struct attribute * attr,int index)729c6f73aabSFrançois Tigeot static umode_t hwmon_attributes_visible(struct kobject *kobj,
730c6f73aabSFrançois Tigeot struct attribute *attr, int index)
731c6f73aabSFrançois Tigeot {
732d78d3a22SFrançois Tigeot struct device *dev = kobj_to_dev(kobj);
733c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev);
734c59a5c48SFrançois Tigeot umode_t effective_mode = attr->mode;
735c6f73aabSFrançois Tigeot
736c59a5c48SFrançois Tigeot /* Skip attributes if DPM is not enabled */
737c6f73aabSFrançois Tigeot if (rdev->pm.pm_method != PM_METHOD_DPM &&
738c6f73aabSFrançois Tigeot (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
739c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr ||
740c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
741c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
742c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
743c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
744c6f73aabSFrançois Tigeot return 0;
745c6f73aabSFrançois Tigeot
746c59a5c48SFrançois Tigeot /* Skip fan attributes if fan is not present */
747c59a5c48SFrançois Tigeot if (rdev->pm.no_fan &&
748c59a5c48SFrançois Tigeot (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
749c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
750c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
751c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
752c59a5c48SFrançois Tigeot return 0;
753c59a5c48SFrançois Tigeot
754c59a5c48SFrançois Tigeot /* mask fan attributes if we have no bindings for this asic to expose */
755c59a5c48SFrançois Tigeot if ((!rdev->asic->dpm.get_fan_speed_percent &&
756c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */
757c59a5c48SFrançois Tigeot (!rdev->asic->dpm.fan_ctrl_get_mode &&
758c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */
759c59a5c48SFrançois Tigeot effective_mode &= ~S_IRUGO;
760c59a5c48SFrançois Tigeot
761c59a5c48SFrançois Tigeot if ((!rdev->asic->dpm.set_fan_speed_percent &&
762c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */
763c59a5c48SFrançois Tigeot (!rdev->asic->dpm.fan_ctrl_set_mode &&
764c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */
765c59a5c48SFrançois Tigeot effective_mode &= ~S_IWUSR;
766c59a5c48SFrançois Tigeot
767c59a5c48SFrançois Tigeot /* hide max/min values if we can't both query and manage the fan */
768c59a5c48SFrançois Tigeot if ((!rdev->asic->dpm.set_fan_speed_percent &&
769c59a5c48SFrançois Tigeot !rdev->asic->dpm.get_fan_speed_percent) &&
770c59a5c48SFrançois Tigeot (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
771c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
772c59a5c48SFrançois Tigeot return 0;
773c59a5c48SFrançois Tigeot
774c59a5c48SFrançois Tigeot return effective_mode;
775c6f73aabSFrançois Tigeot }
776c6f73aabSFrançois Tigeot
777926deccbSFrançois Tigeot static const struct attribute_group hwmon_attrgroup = {
778926deccbSFrançois Tigeot .attrs = hwmon_attributes,
779c6f73aabSFrançois Tigeot .is_visible = hwmon_attributes_visible,
780c6f73aabSFrançois Tigeot };
781c6f73aabSFrançois Tigeot
782c6f73aabSFrançois Tigeot static const struct attribute_group *hwmon_groups[] = {
783c6f73aabSFrançois Tigeot &hwmon_attrgroup,
784c6f73aabSFrançois Tigeot NULL
785926deccbSFrançois Tigeot };
786926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
787926deccbSFrançois Tigeot
7882c86cb5bSImre Vadász static void
radeon_hwmon_refresh(void * arg)7892c86cb5bSImre Vadász radeon_hwmon_refresh(void *arg)
7902c86cb5bSImre Vadász {
7912c86cb5bSImre Vadász struct radeon_device *rdev = (struct radeon_device *)arg;
79226b5dbf2SImre Vadász struct drm_device *ddev = rdev->ddev;
7932c86cb5bSImre Vadász struct ksensor *s = rdev->pm.int_sensor;
7942c86cb5bSImre Vadász int temp;
79526b5dbf2SImre Vadász enum sensor_status stat;
7962c86cb5bSImre Vadász
79726b5dbf2SImre Vadász /* Can't get temperature when the card is off */
79826b5dbf2SImre Vadász if ((rdev->flags & RADEON_IS_PX) &&
79926b5dbf2SImre Vadász (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
80026b5dbf2SImre Vadász sensor_set_unknown(s);
80126b5dbf2SImre Vadász s->status = SENSOR_S_OK;
80226b5dbf2SImre Vadász return;
80326b5dbf2SImre Vadász }
80426b5dbf2SImre Vadász
80526b5dbf2SImre Vadász if (rdev->asic->pm.get_temperature == NULL) {
80626b5dbf2SImre Vadász sensor_set_invalid(s);
80726b5dbf2SImre Vadász return;
80826b5dbf2SImre Vadász }
80926b5dbf2SImre Vadász
8102c86cb5bSImre Vadász temp = radeon_get_temperature(rdev);
81126b5dbf2SImre Vadász if (temp >= rdev->pm.dpm.thermal.max_temp)
81226b5dbf2SImre Vadász stat = SENSOR_S_CRIT;
81326b5dbf2SImre Vadász else if (temp >= rdev->pm.dpm.thermal.min_temp)
81426b5dbf2SImre Vadász stat = SENSOR_S_WARN;
8152c86cb5bSImre Vadász else
81626b5dbf2SImre Vadász stat = SENSOR_S_OK;
8172c86cb5bSImre Vadász
81826b5dbf2SImre Vadász sensor_set(s, temp * 1000 + 273150000, stat);
8192c86cb5bSImre Vadász }
8202c86cb5bSImre Vadász
radeon_hwmon_init(struct radeon_device * rdev)821926deccbSFrançois Tigeot static int radeon_hwmon_init(struct radeon_device *rdev)
822926deccbSFrançois Tigeot {
823926deccbSFrançois Tigeot int err = 0;
824926deccbSFrançois Tigeot
8252c86cb5bSImre Vadász rdev->pm.int_sensor = NULL;
8262c86cb5bSImre Vadász rdev->pm.int_sensordev = NULL;
827926deccbSFrançois Tigeot
828926deccbSFrançois Tigeot switch (rdev->pm.int_thermal_type) {
829926deccbSFrançois Tigeot case THERMAL_TYPE_RV6XX:
830926deccbSFrançois Tigeot case THERMAL_TYPE_RV770:
831926deccbSFrançois Tigeot case THERMAL_TYPE_EVERGREEN:
832926deccbSFrançois Tigeot case THERMAL_TYPE_NI:
833926deccbSFrançois Tigeot case THERMAL_TYPE_SUMO:
834926deccbSFrançois Tigeot case THERMAL_TYPE_SI:
8354cd92098Szrj case THERMAL_TYPE_CI:
8364cd92098Szrj case THERMAL_TYPE_KV:
83757e252bfSMichael Neumann if (rdev->asic->pm.get_temperature == NULL)
838926deccbSFrançois Tigeot return err;
8392c86cb5bSImre Vadász
8402c86cb5bSImre Vadász rdev->pm.int_sensor = kmalloc(sizeof(*rdev->pm.int_sensor),
8412c86cb5bSImre Vadász M_DRM, M_ZERO | M_WAITOK);
8422c86cb5bSImre Vadász rdev->pm.int_sensordev = kmalloc(
8432c86cb5bSImre Vadász sizeof(*rdev->pm.int_sensordev), M_DRM,
8442c86cb5bSImre Vadász M_ZERO | M_WAITOK);
8452c86cb5bSImre Vadász strlcpy(rdev->pm.int_sensordev->xname,
846fb572d17SFrançois Tigeot device_get_nameunit(rdev->dev->bsddev),
8472c86cb5bSImre Vadász sizeof(rdev->pm.int_sensordev->xname));
8482c86cb5bSImre Vadász rdev->pm.int_sensor->type = SENSOR_TEMP;
84926b5dbf2SImre Vadász rdev->pm.int_sensor->flags |= SENSOR_FINVALID;
8502c86cb5bSImre Vadász sensor_attach(rdev->pm.int_sensordev, rdev->pm.int_sensor);
8512c86cb5bSImre Vadász sensor_task_register(rdev, radeon_hwmon_refresh, 5);
8522c86cb5bSImre Vadász sensordev_install(rdev->pm.int_sensordev);
853926deccbSFrançois Tigeot break;
854926deccbSFrançois Tigeot default:
855926deccbSFrançois Tigeot break;
856926deccbSFrançois Tigeot }
857926deccbSFrançois Tigeot
858926deccbSFrançois Tigeot return err;
859926deccbSFrançois Tigeot }
860926deccbSFrançois Tigeot
radeon_hwmon_fini(struct radeon_device * rdev)861926deccbSFrançois Tigeot static void radeon_hwmon_fini(struct radeon_device *rdev)
862926deccbSFrançois Tigeot {
8632c86cb5bSImre Vadász if (rdev->pm.int_sensor != NULL && rdev->pm.int_sensordev != NULL) {
8642c86cb5bSImre Vadász sensordev_deinstall(rdev->pm.int_sensordev);
8652c86cb5bSImre Vadász sensor_task_unregister(rdev);
8662c86cb5bSImre Vadász kfree(rdev->pm.int_sensor);
8672c86cb5bSImre Vadász kfree(rdev->pm.int_sensordev);
8682c86cb5bSImre Vadász rdev->pm.int_sensor = NULL;
8692c86cb5bSImre Vadász rdev->pm.int_sensordev = NULL;
870926deccbSFrançois Tigeot }
871926deccbSFrançois Tigeot }
872926deccbSFrançois Tigeot
radeon_dpm_thermal_work_handler(struct work_struct * work)8732c5cc6b9SFrançois Tigeot static void radeon_dpm_thermal_work_handler(struct work_struct *work)
87457e252bfSMichael Neumann {
8752c5cc6b9SFrançois Tigeot struct radeon_device *rdev =
8762c5cc6b9SFrançois Tigeot container_of(work, struct radeon_device,
8772c5cc6b9SFrançois Tigeot pm.dpm.thermal.work);
87857e252bfSMichael Neumann /* switch to the thermal state */
87957e252bfSMichael Neumann enum radeon_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
88057e252bfSMichael Neumann
88157e252bfSMichael Neumann if (!rdev->pm.dpm_enabled)
88257e252bfSMichael Neumann return;
88357e252bfSMichael Neumann
88457e252bfSMichael Neumann if (rdev->asic->pm.get_temperature) {
88557e252bfSMichael Neumann int temp = radeon_get_temperature(rdev);
88657e252bfSMichael Neumann
88757e252bfSMichael Neumann if (temp < rdev->pm.dpm.thermal.min_temp)
88857e252bfSMichael Neumann /* switch back the user state */
88957e252bfSMichael Neumann dpm_state = rdev->pm.dpm.user_state;
89057e252bfSMichael Neumann } else {
89157e252bfSMichael Neumann if (rdev->pm.dpm.thermal.high_to_low)
89257e252bfSMichael Neumann /* switch back the user state */
89357e252bfSMichael Neumann dpm_state = rdev->pm.dpm.user_state;
89457e252bfSMichael Neumann }
8954cd92098Szrj mutex_lock(&rdev->pm.mutex);
8964cd92098Szrj if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL)
8974cd92098Szrj rdev->pm.dpm.thermal_active = true;
8984cd92098Szrj else
8994cd92098Szrj rdev->pm.dpm.thermal_active = false;
9004cd92098Szrj rdev->pm.dpm.state = dpm_state;
9014cd92098Szrj mutex_unlock(&rdev->pm.mutex);
9024cd92098Szrj
9034cd92098Szrj radeon_pm_compute_clocks(rdev);
90457e252bfSMichael Neumann }
90557e252bfSMichael Neumann
radeon_dpm_single_display(struct radeon_device * rdev)9067dcf36dcSFrançois Tigeot static bool radeon_dpm_single_display(struct radeon_device *rdev)
90757e252bfSMichael Neumann {
90857e252bfSMichael Neumann bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ?
90957e252bfSMichael Neumann true : false;
91057e252bfSMichael Neumann
91157e252bfSMichael Neumann /* check if the vblank period is too short to adjust the mclk */
91257e252bfSMichael Neumann if (single_display && rdev->asic->dpm.vblank_too_short) {
91357e252bfSMichael Neumann if (radeon_dpm_vblank_too_short(rdev))
91457e252bfSMichael Neumann single_display = false;
91557e252bfSMichael Neumann }
91657e252bfSMichael Neumann
9177dcf36dcSFrançois Tigeot return single_display;
9187dcf36dcSFrançois Tigeot }
9197dcf36dcSFrançois Tigeot
radeon_dpm_pick_power_state(struct radeon_device * rdev,enum radeon_pm_state_type dpm_state)9207dcf36dcSFrançois Tigeot static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
9217dcf36dcSFrançois Tigeot enum radeon_pm_state_type dpm_state)
9227dcf36dcSFrançois Tigeot {
9237dcf36dcSFrançois Tigeot int i;
9247dcf36dcSFrançois Tigeot struct radeon_ps *ps;
9257dcf36dcSFrançois Tigeot u32 ui_class;
9267dcf36dcSFrançois Tigeot bool single_display = radeon_dpm_single_display(rdev);
9277dcf36dcSFrançois Tigeot
928c59a5c48SFrançois Tigeot /* 120hz tends to be problematic even if they are under the
929c59a5c48SFrançois Tigeot * vblank limit.
930c59a5c48SFrançois Tigeot */
931c59a5c48SFrançois Tigeot if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120))
932c59a5c48SFrançois Tigeot single_display = false;
933c59a5c48SFrançois Tigeot
93457e252bfSMichael Neumann /* certain older asics have a separare 3D performance state,
93557e252bfSMichael Neumann * so try that first if the user selected performance
93657e252bfSMichael Neumann */
93757e252bfSMichael Neumann if (dpm_state == POWER_STATE_TYPE_PERFORMANCE)
93857e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
93957e252bfSMichael Neumann /* balanced states don't exist at the moment */
94057e252bfSMichael Neumann if (dpm_state == POWER_STATE_TYPE_BALANCED)
941*3f2dd94aSFrançois Tigeot dpm_state = POWER_STATE_TYPE_PERFORMANCE;
94257e252bfSMichael Neumann
94357e252bfSMichael Neumann restart_search:
94457e252bfSMichael Neumann /* Pick the best power state based on current conditions */
94557e252bfSMichael Neumann for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
94657e252bfSMichael Neumann ps = &rdev->pm.dpm.ps[i];
94757e252bfSMichael Neumann ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
94857e252bfSMichael Neumann switch (dpm_state) {
94957e252bfSMichael Neumann /* user states */
95057e252bfSMichael Neumann case POWER_STATE_TYPE_BATTERY:
95157e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
95257e252bfSMichael Neumann if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
95357e252bfSMichael Neumann if (single_display)
95457e252bfSMichael Neumann return ps;
95557e252bfSMichael Neumann } else
95657e252bfSMichael Neumann return ps;
95757e252bfSMichael Neumann }
95857e252bfSMichael Neumann break;
95957e252bfSMichael Neumann case POWER_STATE_TYPE_BALANCED:
96057e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) {
96157e252bfSMichael Neumann if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
96257e252bfSMichael Neumann if (single_display)
96357e252bfSMichael Neumann return ps;
96457e252bfSMichael Neumann } else
96557e252bfSMichael Neumann return ps;
96657e252bfSMichael Neumann }
96757e252bfSMichael Neumann break;
96857e252bfSMichael Neumann case POWER_STATE_TYPE_PERFORMANCE:
96957e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
97057e252bfSMichael Neumann if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
97157e252bfSMichael Neumann if (single_display)
97257e252bfSMichael Neumann return ps;
97357e252bfSMichael Neumann } else
97457e252bfSMichael Neumann return ps;
97557e252bfSMichael Neumann }
97657e252bfSMichael Neumann break;
97757e252bfSMichael Neumann /* internal states */
97857e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD:
9794cd92098Szrj if (rdev->pm.dpm.uvd_ps)
98057e252bfSMichael Neumann return rdev->pm.dpm.uvd_ps;
9814cd92098Szrj else
9824cd92098Szrj break;
98357e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_SD:
98457e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
98557e252bfSMichael Neumann return ps;
98657e252bfSMichael Neumann break;
98757e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD:
98857e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
98957e252bfSMichael Neumann return ps;
99057e252bfSMichael Neumann break;
99157e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
99257e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
99357e252bfSMichael Neumann return ps;
99457e252bfSMichael Neumann break;
99557e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
99657e252bfSMichael Neumann if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
99757e252bfSMichael Neumann return ps;
99857e252bfSMichael Neumann break;
99957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_BOOT:
100057e252bfSMichael Neumann return rdev->pm.dpm.boot_ps;
100157e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_THERMAL:
100257e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
100357e252bfSMichael Neumann return ps;
100457e252bfSMichael Neumann break;
100557e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ACPI:
100657e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
100757e252bfSMichael Neumann return ps;
100857e252bfSMichael Neumann break;
100957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ULV:
101057e252bfSMichael Neumann if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
101157e252bfSMichael Neumann return ps;
101257e252bfSMichael Neumann break;
101357e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_3DPERF:
101457e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
101557e252bfSMichael Neumann return ps;
101657e252bfSMichael Neumann break;
101757e252bfSMichael Neumann default:
101857e252bfSMichael Neumann break;
101957e252bfSMichael Neumann }
102057e252bfSMichael Neumann }
102157e252bfSMichael Neumann /* use a fallback state if we didn't match */
102257e252bfSMichael Neumann switch (dpm_state) {
102357e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_SD:
10244cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
10254cd92098Szrj goto restart_search;
102657e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD:
102757e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
102857e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
10294cd92098Szrj if (rdev->pm.dpm.uvd_ps) {
103057e252bfSMichael Neumann return rdev->pm.dpm.uvd_ps;
10314cd92098Szrj } else {
10324cd92098Szrj dpm_state = POWER_STATE_TYPE_PERFORMANCE;
10334cd92098Szrj goto restart_search;
10344cd92098Szrj }
103557e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_THERMAL:
103657e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
103757e252bfSMichael Neumann goto restart_search;
103857e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ACPI:
103957e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_BATTERY;
104057e252bfSMichael Neumann goto restart_search;
104157e252bfSMichael Neumann case POWER_STATE_TYPE_BATTERY:
104257e252bfSMichael Neumann case POWER_STATE_TYPE_BALANCED:
104357e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_3DPERF:
104457e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_PERFORMANCE;
104557e252bfSMichael Neumann goto restart_search;
104657e252bfSMichael Neumann default:
104757e252bfSMichael Neumann break;
104857e252bfSMichael Neumann }
104957e252bfSMichael Neumann
105057e252bfSMichael Neumann return NULL;
105157e252bfSMichael Neumann }
105257e252bfSMichael Neumann
radeon_dpm_change_power_state_locked(struct radeon_device * rdev)105357e252bfSMichael Neumann static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
105457e252bfSMichael Neumann {
105557e252bfSMichael Neumann int i;
105657e252bfSMichael Neumann struct radeon_ps *ps;
105757e252bfSMichael Neumann enum radeon_pm_state_type dpm_state;
105857e252bfSMichael Neumann int ret;
10597dcf36dcSFrançois Tigeot bool single_display = radeon_dpm_single_display(rdev);
106057e252bfSMichael Neumann
106157e252bfSMichael Neumann /* if dpm init failed */
106257e252bfSMichael Neumann if (!rdev->pm.dpm_enabled)
106357e252bfSMichael Neumann return;
106457e252bfSMichael Neumann
106557e252bfSMichael Neumann if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) {
106657e252bfSMichael Neumann /* add other state override checks here */
106757e252bfSMichael Neumann if ((!rdev->pm.dpm.thermal_active) &&
106857e252bfSMichael Neumann (!rdev->pm.dpm.uvd_active))
106957e252bfSMichael Neumann rdev->pm.dpm.state = rdev->pm.dpm.user_state;
107057e252bfSMichael Neumann }
107157e252bfSMichael Neumann dpm_state = rdev->pm.dpm.state;
107257e252bfSMichael Neumann
107357e252bfSMichael Neumann ps = radeon_dpm_pick_power_state(rdev, dpm_state);
107457e252bfSMichael Neumann if (ps)
107557e252bfSMichael Neumann rdev->pm.dpm.requested_ps = ps;
107657e252bfSMichael Neumann else
107757e252bfSMichael Neumann return;
107857e252bfSMichael Neumann
107957e252bfSMichael Neumann /* no need to reprogram if nothing changed unless we are on BTC+ */
108057e252bfSMichael Neumann if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) {
1081c6f73aabSFrançois Tigeot /* vce just modifies an existing state so force a change */
1082c6f73aabSFrançois Tigeot if (ps->vce_active != rdev->pm.dpm.vce_active)
1083c6f73aabSFrançois Tigeot goto force;
10847dcf36dcSFrançois Tigeot /* user has made a display change (such as timing) */
10857dcf36dcSFrançois Tigeot if (rdev->pm.dpm.single_display != single_display)
10867dcf36dcSFrançois Tigeot goto force;
108757e252bfSMichael Neumann if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {
108857e252bfSMichael Neumann /* for pre-BTC and APUs if the num crtcs changed but state is the same,
108957e252bfSMichael Neumann * all we need to do is update the display configuration.
109057e252bfSMichael Neumann */
109157e252bfSMichael Neumann if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) {
109257e252bfSMichael Neumann /* update display watermarks based on new power state */
109357e252bfSMichael Neumann radeon_bandwidth_update(rdev);
109457e252bfSMichael Neumann /* update displays */
109557e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev);
109657e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
109757e252bfSMichael Neumann rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
109857e252bfSMichael Neumann }
109957e252bfSMichael Neumann return;
110057e252bfSMichael Neumann } else {
110157e252bfSMichael Neumann /* for BTC+ if the num crtcs hasn't changed and state is the same,
110257e252bfSMichael Neumann * nothing to do, if the num crtcs is > 1 and state is the same,
110357e252bfSMichael Neumann * update display configuration.
110457e252bfSMichael Neumann */
110557e252bfSMichael Neumann if (rdev->pm.dpm.new_active_crtcs ==
110657e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs) {
110757e252bfSMichael Neumann return;
110857e252bfSMichael Neumann } else {
110957e252bfSMichael Neumann if ((rdev->pm.dpm.current_active_crtc_count > 1) &&
111057e252bfSMichael Neumann (rdev->pm.dpm.new_active_crtc_count > 1)) {
111157e252bfSMichael Neumann /* update display watermarks based on new power state */
111257e252bfSMichael Neumann radeon_bandwidth_update(rdev);
111357e252bfSMichael Neumann /* update displays */
111457e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev);
111557e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
111657e252bfSMichael Neumann rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
111757e252bfSMichael Neumann return;
111857e252bfSMichael Neumann }
111957e252bfSMichael Neumann }
112057e252bfSMichael Neumann }
112157e252bfSMichael Neumann }
112257e252bfSMichael Neumann
1123c6f73aabSFrançois Tigeot force:
1124c6f73aabSFrançois Tigeot if (radeon_dpm == 1) {
112557e252bfSMichael Neumann printk("switching from power state:\n");
112657e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps);
112757e252bfSMichael Neumann printk("switching to power state:\n");
112857e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps);
1129c6f73aabSFrançois Tigeot }
113057e252bfSMichael Neumann
11311cfef1a5SFrançois Tigeot down_write(&rdev->pm.mclk_lock);
11321cfef1a5SFrançois Tigeot mutex_lock(&rdev->ring_lock);
113357e252bfSMichael Neumann
1134c6f73aabSFrançois Tigeot /* update whether vce is active */
1135c6f73aabSFrançois Tigeot ps->vce_active = rdev->pm.dpm.vce_active;
1136c6f73aabSFrançois Tigeot
113757e252bfSMichael Neumann ret = radeon_dpm_pre_set_power_state(rdev);
113857e252bfSMichael Neumann if (ret)
113957e252bfSMichael Neumann goto done;
114057e252bfSMichael Neumann
114157e252bfSMichael Neumann /* update display watermarks based on new power state */
114257e252bfSMichael Neumann radeon_bandwidth_update(rdev);
114357e252bfSMichael Neumann
114457e252bfSMichael Neumann /* wait for the rings to drain */
114557e252bfSMichael Neumann for (i = 0; i < RADEON_NUM_RINGS; i++) {
114657e252bfSMichael Neumann struct radeon_ring *ring = &rdev->ring[i];
114757e252bfSMichael Neumann if (ring->ready)
1148c6f73aabSFrançois Tigeot radeon_fence_wait_empty(rdev, i);
114957e252bfSMichael Neumann }
115057e252bfSMichael Neumann
115157e252bfSMichael Neumann /* program the new power state */
115257e252bfSMichael Neumann radeon_dpm_set_power_state(rdev);
115357e252bfSMichael Neumann
115457e252bfSMichael Neumann /* update current power state */
115557e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps;
115657e252bfSMichael Neumann
115757e252bfSMichael Neumann radeon_dpm_post_set_power_state(rdev);
115857e252bfSMichael Neumann
1159c59a5c48SFrançois Tigeot rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
1160c59a5c48SFrançois Tigeot rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
1161c59a5c48SFrançois Tigeot rdev->pm.dpm.single_display = single_display;
1162c59a5c48SFrançois Tigeot
1163d78d3a22SFrançois Tigeot /* update displays */
1164d78d3a22SFrançois Tigeot radeon_dpm_display_configuration_changed(rdev);
1165d78d3a22SFrançois Tigeot
11664cd92098Szrj if (rdev->asic->dpm.force_performance_level) {
1167c6f73aabSFrançois Tigeot if (rdev->pm.dpm.thermal_active) {
1168c6f73aabSFrançois Tigeot enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
11694cd92098Szrj /* force low perf level for thermal */
11704cd92098Szrj radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_LOW);
1171c6f73aabSFrançois Tigeot /* save the user's level */
1172c6f73aabSFrançois Tigeot rdev->pm.dpm.forced_level = level;
1173c6f73aabSFrançois Tigeot } else {
1174c6f73aabSFrançois Tigeot /* otherwise, user selected level */
1175c6f73aabSFrançois Tigeot radeon_dpm_force_performance_level(rdev, rdev->pm.dpm.forced_level);
1176c6f73aabSFrançois Tigeot }
11774cd92098Szrj }
11784cd92098Szrj
117957e252bfSMichael Neumann done:
11801cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock);
11811cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock);
118257e252bfSMichael Neumann }
118357e252bfSMichael Neumann
radeon_dpm_enable_uvd(struct radeon_device * rdev,bool enable)11844cd92098Szrj void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
118557e252bfSMichael Neumann {
11864cd92098Szrj enum radeon_pm_state_type dpm_state;
118757e252bfSMichael Neumann
11884cd92098Szrj if (rdev->asic->dpm.powergate_uvd) {
11894cd92098Szrj mutex_lock(&rdev->pm.mutex);
1190c6f73aabSFrançois Tigeot /* don't powergate anything if we
1191c6f73aabSFrançois Tigeot have active but pause streams */
1192c6f73aabSFrançois Tigeot enable |= rdev->pm.dpm.sd > 0;
1193c6f73aabSFrançois Tigeot enable |= rdev->pm.dpm.hd > 0;
11944cd92098Szrj /* enable/disable UVD */
11954cd92098Szrj radeon_dpm_powergate_uvd(rdev, !enable);
11964cd92098Szrj mutex_unlock(&rdev->pm.mutex);
11974cd92098Szrj } else {
11984cd92098Szrj if (enable) {
11994cd92098Szrj mutex_lock(&rdev->pm.mutex);
120057e252bfSMichael Neumann rdev->pm.dpm.uvd_active = true;
12014cd92098Szrj /* disable this for now */
12024cd92098Szrj #if 0
12034cd92098Szrj if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0))
12044cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD;
12054cd92098Szrj else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0))
12064cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
12074cd92098Szrj else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 1))
12084cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
12094cd92098Szrj else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2))
12104cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2;
12114cd92098Szrj else
12124cd92098Szrj #endif
12134cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD;
121457e252bfSMichael Neumann rdev->pm.dpm.state = dpm_state;
12154cd92098Szrj mutex_unlock(&rdev->pm.mutex);
12164cd92098Szrj } else {
12174cd92098Szrj mutex_lock(&rdev->pm.mutex);
12184cd92098Szrj rdev->pm.dpm.uvd_active = false;
12194cd92098Szrj mutex_unlock(&rdev->pm.mutex);
12204cd92098Szrj }
12214cd92098Szrj
122257e252bfSMichael Neumann radeon_pm_compute_clocks(rdev);
122357e252bfSMichael Neumann }
12244cd92098Szrj }
122557e252bfSMichael Neumann
radeon_dpm_enable_vce(struct radeon_device * rdev,bool enable)1226c6f73aabSFrançois Tigeot void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable)
1227c6f73aabSFrançois Tigeot {
1228c6f73aabSFrançois Tigeot if (enable) {
1229c6f73aabSFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1230c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_active = true;
1231c6f73aabSFrançois Tigeot /* XXX select vce level based on ring/task */
1232c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_level = RADEON_VCE_LEVEL_AC_ALL;
1233c6f73aabSFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1234c6f73aabSFrançois Tigeot } else {
1235c6f73aabSFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1236c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_active = false;
1237c6f73aabSFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1238c6f73aabSFrançois Tigeot }
1239c6f73aabSFrançois Tigeot
1240c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev);
1241c6f73aabSFrançois Tigeot }
1242c6f73aabSFrançois Tigeot
radeon_pm_suspend_old(struct radeon_device * rdev)124357e252bfSMichael Neumann static void radeon_pm_suspend_old(struct radeon_device *rdev)
1244926deccbSFrançois Tigeot {
12451cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1246926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
1247926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE)
1248926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED;
1249926deccbSFrançois Tigeot }
12501cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1251926deccbSFrançois Tigeot
1252ee479021SImre Vadász #ifdef DUMBBELL_WIP
1253926deccbSFrançois Tigeot cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
1254ee479021SImre Vadász #endif /* DUMBBELL_WIP */
1255926deccbSFrançois Tigeot }
1256926deccbSFrançois Tigeot
radeon_pm_suspend_dpm(struct radeon_device * rdev)125757e252bfSMichael Neumann static void radeon_pm_suspend_dpm(struct radeon_device *rdev)
125857e252bfSMichael Neumann {
12591cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
126057e252bfSMichael Neumann /* disable dpm */
126157e252bfSMichael Neumann radeon_dpm_disable(rdev);
126257e252bfSMichael Neumann /* reset the power state */
126357e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
126457e252bfSMichael Neumann rdev->pm.dpm_enabled = false;
12651cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
126657e252bfSMichael Neumann }
126757e252bfSMichael Neumann
radeon_pm_suspend(struct radeon_device * rdev)126857e252bfSMichael Neumann void radeon_pm_suspend(struct radeon_device *rdev)
126957e252bfSMichael Neumann {
127057e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM)
127157e252bfSMichael Neumann radeon_pm_suspend_dpm(rdev);
127257e252bfSMichael Neumann else
127357e252bfSMichael Neumann radeon_pm_suspend_old(rdev);
127457e252bfSMichael Neumann }
127557e252bfSMichael Neumann
radeon_pm_resume_old(struct radeon_device * rdev)127657e252bfSMichael Neumann static void radeon_pm_resume_old(struct radeon_device *rdev)
1277926deccbSFrançois Tigeot {
1278926deccbSFrançois Tigeot /* set up the default clocks if the MC ucode is loaded */
1279926deccbSFrançois Tigeot if ((rdev->family >= CHIP_BARTS) &&
12804cd92098Szrj (rdev->family <= CHIP_CAYMAN) &&
1281926deccbSFrançois Tigeot rdev->mc_fw) {
1282926deccbSFrançois Tigeot if (rdev->pm.default_vddc)
1283926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
1284926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDC);
1285926deccbSFrançois Tigeot if (rdev->pm.default_vddci)
1286926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
1287926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDCI);
1288926deccbSFrançois Tigeot if (rdev->pm.default_sclk)
1289926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
1290926deccbSFrançois Tigeot if (rdev->pm.default_mclk)
1291926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
1292926deccbSFrançois Tigeot }
1293926deccbSFrançois Tigeot /* asic init will reset the default power state */
12941cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1295926deccbSFrançois Tigeot rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
1296926deccbSFrançois Tigeot rdev->pm.current_clock_mode_index = 0;
1297926deccbSFrançois Tigeot rdev->pm.current_sclk = rdev->pm.default_sclk;
1298926deccbSFrançois Tigeot rdev->pm.current_mclk = rdev->pm.default_mclk;
1299c6f73aabSFrançois Tigeot if (rdev->pm.power_state) {
1300926deccbSFrançois Tigeot rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
1301926deccbSFrançois Tigeot rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci;
1302c6f73aabSFrançois Tigeot }
1303926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM
1304926deccbSFrançois Tigeot && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) {
1305926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
1306ee479021SImre Vadász #ifdef DUMBBELL_WIP
1307926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work,
1308926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
1309ee479021SImre Vadász #endif /* DUMBBELL_WIP */
1310926deccbSFrançois Tigeot }
13111cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1312926deccbSFrançois Tigeot radeon_pm_compute_clocks(rdev);
1313926deccbSFrançois Tigeot }
1314926deccbSFrançois Tigeot
radeon_pm_resume_dpm(struct radeon_device * rdev)131557e252bfSMichael Neumann static void radeon_pm_resume_dpm(struct radeon_device *rdev)
1316926deccbSFrançois Tigeot {
1317926deccbSFrançois Tigeot int ret;
1318926deccbSFrançois Tigeot
131957e252bfSMichael Neumann /* asic init will reset to the boot state */
13201cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
132157e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
132257e252bfSMichael Neumann radeon_dpm_setup_asic(rdev);
132357e252bfSMichael Neumann ret = radeon_dpm_enable(rdev);
13241cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1325c6f73aabSFrançois Tigeot if (ret)
1326c6f73aabSFrançois Tigeot goto dpm_resume_fail;
1327c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = true;
1328c6f73aabSFrançois Tigeot return;
1329c6f73aabSFrançois Tigeot
1330c6f73aabSFrançois Tigeot dpm_resume_fail:
133157e252bfSMichael Neumann DRM_ERROR("radeon: dpm resume failed\n");
133257e252bfSMichael Neumann if ((rdev->family >= CHIP_BARTS) &&
13334cd92098Szrj (rdev->family <= CHIP_CAYMAN) &&
133457e252bfSMichael Neumann rdev->mc_fw) {
133557e252bfSMichael Neumann if (rdev->pm.default_vddc)
133657e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
133757e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC);
133857e252bfSMichael Neumann if (rdev->pm.default_vddci)
133957e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
134057e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDCI);
134157e252bfSMichael Neumann if (rdev->pm.default_sclk)
134257e252bfSMichael Neumann radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
134357e252bfSMichael Neumann if (rdev->pm.default_mclk)
134457e252bfSMichael Neumann radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
134557e252bfSMichael Neumann }
134657e252bfSMichael Neumann }
134757e252bfSMichael Neumann
radeon_pm_resume(struct radeon_device * rdev)134857e252bfSMichael Neumann void radeon_pm_resume(struct radeon_device *rdev)
134957e252bfSMichael Neumann {
135057e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM)
135157e252bfSMichael Neumann radeon_pm_resume_dpm(rdev);
135257e252bfSMichael Neumann else
135357e252bfSMichael Neumann radeon_pm_resume_old(rdev);
135457e252bfSMichael Neumann }
135557e252bfSMichael Neumann
radeon_pm_init_old(struct radeon_device * rdev)135657e252bfSMichael Neumann static int radeon_pm_init_old(struct radeon_device *rdev)
135757e252bfSMichael Neumann {
135857e252bfSMichael Neumann int ret;
135957e252bfSMichael Neumann
1360926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT;
1361926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
1362926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
1363926deccbSFrançois Tigeot rdev->pm.dynpm_can_upclock = true;
1364926deccbSFrançois Tigeot rdev->pm.dynpm_can_downclock = true;
1365926deccbSFrançois Tigeot rdev->pm.default_sclk = rdev->clock.default_sclk;
1366926deccbSFrançois Tigeot rdev->pm.default_mclk = rdev->clock.default_mclk;
1367926deccbSFrançois Tigeot rdev->pm.current_sclk = rdev->clock.default_sclk;
1368926deccbSFrançois Tigeot rdev->pm.current_mclk = rdev->clock.default_mclk;
1369926deccbSFrançois Tigeot rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
1370926deccbSFrançois Tigeot
1371926deccbSFrançois Tigeot if (rdev->bios) {
1372926deccbSFrançois Tigeot if (rdev->is_atom_bios)
1373926deccbSFrançois Tigeot radeon_atombios_get_power_modes(rdev);
1374926deccbSFrançois Tigeot else
1375926deccbSFrançois Tigeot radeon_combios_get_power_modes(rdev);
1376926deccbSFrançois Tigeot radeon_pm_print_states(rdev);
1377926deccbSFrançois Tigeot radeon_pm_init_profile(rdev);
1378926deccbSFrançois Tigeot /* set up the default clocks if the MC ucode is loaded */
1379926deccbSFrançois Tigeot if ((rdev->family >= CHIP_BARTS) &&
13804cd92098Szrj (rdev->family <= CHIP_CAYMAN) &&
1381926deccbSFrançois Tigeot rdev->mc_fw) {
1382926deccbSFrançois Tigeot if (rdev->pm.default_vddc)
1383926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
1384926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDC);
1385926deccbSFrançois Tigeot if (rdev->pm.default_vddci)
1386926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
1387926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDCI);
1388926deccbSFrançois Tigeot if (rdev->pm.default_sclk)
1389926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
1390926deccbSFrançois Tigeot if (rdev->pm.default_mclk)
1391926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
1392926deccbSFrançois Tigeot }
1393926deccbSFrançois Tigeot }
1394926deccbSFrançois Tigeot
1395926deccbSFrançois Tigeot /* set up the internal thermal sensor if applicable */
1396926deccbSFrançois Tigeot ret = radeon_hwmon_init(rdev);
1397926deccbSFrançois Tigeot if (ret)
1398926deccbSFrançois Tigeot return ret;
1399926deccbSFrançois Tigeot
1400926deccbSFrançois Tigeot INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler);
1401926deccbSFrançois Tigeot
1402926deccbSFrançois Tigeot if (rdev->pm.num_power_states > 1) {
1403926deccbSFrançois Tigeot if (radeon_debugfs_pm_init(rdev)) {
1404926deccbSFrançois Tigeot DRM_ERROR("Failed to register debugfs file for PM!\n");
1405926deccbSFrançois Tigeot }
1406926deccbSFrançois Tigeot
1407926deccbSFrançois Tigeot DRM_INFO("radeon: power management initialized\n");
1408926deccbSFrançois Tigeot }
1409926deccbSFrançois Tigeot
1410926deccbSFrançois Tigeot return 0;
1411926deccbSFrançois Tigeot }
1412926deccbSFrançois Tigeot
radeon_dpm_print_power_states(struct radeon_device * rdev)141357e252bfSMichael Neumann static void radeon_dpm_print_power_states(struct radeon_device *rdev)
141457e252bfSMichael Neumann {
141557e252bfSMichael Neumann int i;
141657e252bfSMichael Neumann
141757e252bfSMichael Neumann for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
141857e252bfSMichael Neumann printk("== power state %d ==\n", i);
141957e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, &rdev->pm.dpm.ps[i]);
142057e252bfSMichael Neumann }
142157e252bfSMichael Neumann }
142257e252bfSMichael Neumann
radeon_pm_init_dpm(struct radeon_device * rdev)142357e252bfSMichael Neumann static int radeon_pm_init_dpm(struct radeon_device *rdev)
142457e252bfSMichael Neumann {
142557e252bfSMichael Neumann int ret;
142657e252bfSMichael Neumann
14274cd92098Szrj /* default to balanced state */
142857e252bfSMichael Neumann rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
142957e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
14304cd92098Szrj rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
143157e252bfSMichael Neumann rdev->pm.default_sclk = rdev->clock.default_sclk;
143257e252bfSMichael Neumann rdev->pm.default_mclk = rdev->clock.default_mclk;
143357e252bfSMichael Neumann rdev->pm.current_sclk = rdev->clock.default_sclk;
143457e252bfSMichael Neumann rdev->pm.current_mclk = rdev->clock.default_mclk;
143557e252bfSMichael Neumann rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
143657e252bfSMichael Neumann
143757e252bfSMichael Neumann if (rdev->bios && rdev->is_atom_bios)
143857e252bfSMichael Neumann radeon_atombios_get_power_modes(rdev);
143957e252bfSMichael Neumann else
144057e252bfSMichael Neumann return -EINVAL;
144157e252bfSMichael Neumann
144257e252bfSMichael Neumann /* set up the internal thermal sensor if applicable */
144357e252bfSMichael Neumann ret = radeon_hwmon_init(rdev);
144457e252bfSMichael Neumann if (ret)
144557e252bfSMichael Neumann return ret;
144657e252bfSMichael Neumann
14472c5cc6b9SFrançois Tigeot INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler);
14482c5cc6b9SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
144957e252bfSMichael Neumann radeon_dpm_init(rdev);
145057e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
1451c6f73aabSFrançois Tigeot if (radeon_dpm == 1)
145257e252bfSMichael Neumann radeon_dpm_print_power_states(rdev);
145357e252bfSMichael Neumann radeon_dpm_setup_asic(rdev);
145457e252bfSMichael Neumann ret = radeon_dpm_enable(rdev);
14552c5cc6b9SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1456c6f73aabSFrançois Tigeot if (ret)
1457c6f73aabSFrançois Tigeot goto dpm_failed;
1458c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = true;
1459c6f73aabSFrançois Tigeot
1460c6f73aabSFrançois Tigeot #ifdef TODO_DEVICE_FILE
1461c6f73aabSFrançois Tigeot if (radeon_debugfs_pm_init(rdev)) {
1462c6f73aabSFrançois Tigeot DRM_ERROR("Failed to register debugfs file for dpm!\n");
1463c6f73aabSFrançois Tigeot }
1464c6f73aabSFrançois Tigeot #endif
1465c6f73aabSFrançois Tigeot
1466c6f73aabSFrançois Tigeot DRM_INFO("radeon: dpm initialized\n");
1467c6f73aabSFrançois Tigeot
1468c6f73aabSFrançois Tigeot return 0;
1469c6f73aabSFrançois Tigeot
1470c6f73aabSFrançois Tigeot dpm_failed:
147157e252bfSMichael Neumann rdev->pm.dpm_enabled = false;
147257e252bfSMichael Neumann if ((rdev->family >= CHIP_BARTS) &&
14734cd92098Szrj (rdev->family <= CHIP_CAYMAN) &&
147457e252bfSMichael Neumann rdev->mc_fw) {
147557e252bfSMichael Neumann if (rdev->pm.default_vddc)
147657e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
147757e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC);
147857e252bfSMichael Neumann if (rdev->pm.default_vddci)
147957e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
148057e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDCI);
148157e252bfSMichael Neumann if (rdev->pm.default_sclk)
148257e252bfSMichael Neumann radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
148357e252bfSMichael Neumann if (rdev->pm.default_mclk)
148457e252bfSMichael Neumann radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
148557e252bfSMichael Neumann }
148657e252bfSMichael Neumann DRM_ERROR("radeon: dpm initialization failed\n");
148757e252bfSMichael Neumann return ret;
148857e252bfSMichael Neumann }
148957e252bfSMichael Neumann
14907dcf36dcSFrançois Tigeot struct radeon_dpm_quirk {
14917dcf36dcSFrançois Tigeot u32 chip_vendor;
14927dcf36dcSFrançois Tigeot u32 chip_device;
14937dcf36dcSFrançois Tigeot u32 subsys_vendor;
14947dcf36dcSFrançois Tigeot u32 subsys_device;
14957dcf36dcSFrançois Tigeot };
14967dcf36dcSFrançois Tigeot
14977dcf36dcSFrançois Tigeot /* cards with dpm stability problems */
14987dcf36dcSFrançois Tigeot static struct radeon_dpm_quirk radeon_dpm_quirk_list[] = {
14997dcf36dcSFrançois Tigeot /* TURKS - https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386534 */
15007dcf36dcSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6759, 0x1682, 0x3195 },
15017dcf36dcSFrançois Tigeot /* TURKS - https://bugzilla.kernel.org/show_bug.cgi?id=83731 */
15027dcf36dcSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6840, 0x1179, 0xfb81 },
15037dcf36dcSFrançois Tigeot { 0, 0, 0, 0 },
15047dcf36dcSFrançois Tigeot };
15057dcf36dcSFrançois Tigeot
radeon_pm_init(struct radeon_device * rdev)150657e252bfSMichael Neumann int radeon_pm_init(struct radeon_device *rdev)
150757e252bfSMichael Neumann {
15087dcf36dcSFrançois Tigeot struct radeon_dpm_quirk *p = radeon_dpm_quirk_list;
15097dcf36dcSFrançois Tigeot bool disable_dpm = false;
15107dcf36dcSFrançois Tigeot
15117dcf36dcSFrançois Tigeot /* Apply dpm quirks */
15127dcf36dcSFrançois Tigeot while (p && p->chip_device != 0) {
15137dcf36dcSFrançois Tigeot if (rdev->pdev->vendor == p->chip_vendor &&
15147dcf36dcSFrançois Tigeot rdev->pdev->device == p->chip_device &&
15157dcf36dcSFrançois Tigeot rdev->pdev->subsystem_vendor == p->subsys_vendor &&
15167dcf36dcSFrançois Tigeot rdev->pdev->subsystem_device == p->subsys_device) {
15177dcf36dcSFrançois Tigeot disable_dpm = true;
15187dcf36dcSFrançois Tigeot break;
15197dcf36dcSFrançois Tigeot }
15207dcf36dcSFrançois Tigeot ++p;
15217dcf36dcSFrançois Tigeot }
15227dcf36dcSFrançois Tigeot
152357e252bfSMichael Neumann /* enable dpm on rv6xx+ */
152457e252bfSMichael Neumann switch (rdev->family) {
152557e252bfSMichael Neumann case CHIP_RV610:
152657e252bfSMichael Neumann case CHIP_RV630:
152757e252bfSMichael Neumann case CHIP_RV620:
152857e252bfSMichael Neumann case CHIP_RV635:
152957e252bfSMichael Neumann case CHIP_RV670:
153057e252bfSMichael Neumann case CHIP_RS780:
153157e252bfSMichael Neumann case CHIP_RS880:
153257e252bfSMichael Neumann case CHIP_RV770:
1533c6f73aabSFrançois Tigeot /* DPM requires the RLC, RV770+ dGPU requires SMC */
1534c6f73aabSFrançois Tigeot if (!rdev->rlc_fw)
1535c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE;
1536c6f73aabSFrançois Tigeot else if ((rdev->family >= CHIP_RV770) &&
1537c6f73aabSFrançois Tigeot (!(rdev->flags & RADEON_IS_IGP)) &&
1538c6f73aabSFrançois Tigeot (!rdev->smc_fw))
1539c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE;
1540c6f73aabSFrançois Tigeot else if (radeon_dpm == 1)
1541c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DPM;
1542c6f73aabSFrançois Tigeot else
1543c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE;
1544c6f73aabSFrançois Tigeot break;
154557e252bfSMichael Neumann case CHIP_RV730:
154657e252bfSMichael Neumann case CHIP_RV710:
154757e252bfSMichael Neumann case CHIP_RV740:
154857e252bfSMichael Neumann case CHIP_CEDAR:
154957e252bfSMichael Neumann case CHIP_REDWOOD:
155057e252bfSMichael Neumann case CHIP_JUNIPER:
155157e252bfSMichael Neumann case CHIP_CYPRESS:
155257e252bfSMichael Neumann case CHIP_HEMLOCK:
155357e252bfSMichael Neumann case CHIP_PALM:
155457e252bfSMichael Neumann case CHIP_SUMO:
155557e252bfSMichael Neumann case CHIP_SUMO2:
155657e252bfSMichael Neumann case CHIP_BARTS:
155757e252bfSMichael Neumann case CHIP_TURKS:
155857e252bfSMichael Neumann case CHIP_CAICOS:
155957e252bfSMichael Neumann case CHIP_CAYMAN:
156057e252bfSMichael Neumann case CHIP_ARUBA:
156157e252bfSMichael Neumann case CHIP_TAHITI:
156257e252bfSMichael Neumann case CHIP_PITCAIRN:
156357e252bfSMichael Neumann case CHIP_VERDE:
156457e252bfSMichael Neumann case CHIP_OLAND:
156557e252bfSMichael Neumann case CHIP_HAINAN:
15664cd92098Szrj case CHIP_BONAIRE:
15674cd92098Szrj case CHIP_KABINI:
15684cd92098Szrj case CHIP_KAVERI:
1569c6f73aabSFrançois Tigeot case CHIP_HAWAII:
1570c6f73aabSFrançois Tigeot case CHIP_MULLINS:
157157e252bfSMichael Neumann /* DPM requires the RLC, RV770+ dGPU requires SMC */
157257e252bfSMichael Neumann if (!rdev->rlc_fw)
157357e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE;
157457e252bfSMichael Neumann else if ((rdev->family >= CHIP_RV770) &&
157557e252bfSMichael Neumann (!(rdev->flags & RADEON_IS_IGP)) &&
157657e252bfSMichael Neumann (!rdev->smc_fw))
157757e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE;
15787dcf36dcSFrançois Tigeot else if (disable_dpm && (radeon_dpm == -1))
15797dcf36dcSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE;
1580c6f73aabSFrançois Tigeot else if (radeon_dpm == 0)
158157e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE;
1582c6f73aabSFrançois Tigeot else
1583c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DPM;
158457e252bfSMichael Neumann break;
158557e252bfSMichael Neumann default:
158657e252bfSMichael Neumann /* default to profile method */
158757e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE;
158857e252bfSMichael Neumann break;
158957e252bfSMichael Neumann }
159057e252bfSMichael Neumann
159157e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM)
159257e252bfSMichael Neumann return radeon_pm_init_dpm(rdev);
159357e252bfSMichael Neumann else
159457e252bfSMichael Neumann return radeon_pm_init_old(rdev);
159557e252bfSMichael Neumann }
159657e252bfSMichael Neumann
radeon_pm_late_init(struct radeon_device * rdev)1597c6f73aabSFrançois Tigeot int radeon_pm_late_init(struct radeon_device *rdev)
1598c6f73aabSFrançois Tigeot {
1599c6f73aabSFrançois Tigeot int ret = 0;
1600c6f73aabSFrançois Tigeot
1601c6f73aabSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DPM) {
1602c59a5c48SFrançois Tigeot if (rdev->pm.dpm_enabled) {
1603c59a5c48SFrançois Tigeot if (!rdev->pm.sysfs_initialized) {
1604c59a5c48SFrançois Tigeot #if 0
1605c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
1606c59a5c48SFrançois Tigeot if (ret)
1607c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for dpm state\n");
1608c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
1609c59a5c48SFrançois Tigeot if (ret)
1610c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for dpm state\n");
1611c59a5c48SFrançois Tigeot /* XXX: these are noops for dpm but are here for backwards compat */
1612c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_profile);
1613c59a5c48SFrançois Tigeot if (ret)
1614c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power profile\n");
1615c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_method);
1616c59a5c48SFrançois Tigeot if (ret)
1617c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power method\n");
1618c59a5c48SFrançois Tigeot #endif
1619c59a5c48SFrançois Tigeot rdev->pm.sysfs_initialized = true;
1620c59a5c48SFrançois Tigeot }
1621c59a5c48SFrançois Tigeot
16221cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1623c6f73aabSFrançois Tigeot ret = radeon_dpm_late_enable(rdev);
16241cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1625c59a5c48SFrançois Tigeot if (ret) {
1626c59a5c48SFrançois Tigeot rdev->pm.dpm_enabled = false;
1627c59a5c48SFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
1628c59a5c48SFrançois Tigeot } else {
1629c59a5c48SFrançois Tigeot /* set the dpm state for PX since there won't be
1630c59a5c48SFrançois Tigeot * a modeset to call this.
1631c59a5c48SFrançois Tigeot */
1632c59a5c48SFrançois Tigeot radeon_pm_compute_clocks(rdev);
1633c59a5c48SFrançois Tigeot }
1634c59a5c48SFrançois Tigeot }
1635c59a5c48SFrançois Tigeot } else {
1636c59a5c48SFrançois Tigeot if ((rdev->pm.num_power_states > 1) &&
1637c59a5c48SFrançois Tigeot (!rdev->pm.sysfs_initialized)) {
1638c59a5c48SFrançois Tigeot /* where's the best place to put these? */
1639c59a5c48SFrançois Tigeot #if 0
1640c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_profile);
1641c59a5c48SFrançois Tigeot if (ret)
1642c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power profile\n");
1643c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_method);
1644c59a5c48SFrançois Tigeot if (ret)
1645c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power method\n");
1646c59a5c48SFrançois Tigeot if (!ret)
1647c59a5c48SFrançois Tigeot rdev->pm.sysfs_initialized = true;
1648c59a5c48SFrançois Tigeot #endif
1649c59a5c48SFrançois Tigeot }
1650c6f73aabSFrançois Tigeot }
1651c6f73aabSFrançois Tigeot return ret;
1652c6f73aabSFrançois Tigeot }
1653c6f73aabSFrançois Tigeot
radeon_pm_fini_old(struct radeon_device * rdev)165457e252bfSMichael Neumann static void radeon_pm_fini_old(struct radeon_device *rdev)
1655926deccbSFrançois Tigeot {
1656926deccbSFrançois Tigeot if (rdev->pm.num_power_states > 1) {
16571cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1658926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
1659926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT;
1660926deccbSFrançois Tigeot radeon_pm_update_profile(rdev);
1661926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
1662926deccbSFrançois Tigeot } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
1663926deccbSFrançois Tigeot /* reset default clocks */
1664926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
1665926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
1666926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
1667926deccbSFrançois Tigeot }
16681cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1669926deccbSFrançois Tigeot
1670926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1671ee479021SImre Vadász cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
1672ee479021SImre Vadász
1673926deccbSFrançois Tigeot device_remove_file(rdev->dev, &dev_attr_power_profile);
1674926deccbSFrançois Tigeot device_remove_file(rdev->dev, &dev_attr_power_method);
1675926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1676926deccbSFrançois Tigeot }
1677926deccbSFrançois Tigeot
1678926deccbSFrançois Tigeot if (rdev->pm.power_state) {
1679926deccbSFrançois Tigeot int i;
1680926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; ++i) {
1681c4ef309bSzrj kfree(rdev->pm.power_state[i].clock_info);
1682926deccbSFrançois Tigeot }
1683c4ef309bSzrj kfree(rdev->pm.power_state);
1684926deccbSFrançois Tigeot rdev->pm.power_state = NULL;
1685926deccbSFrançois Tigeot rdev->pm.num_power_states = 0;
1686926deccbSFrançois Tigeot }
1687926deccbSFrançois Tigeot
1688926deccbSFrançois Tigeot radeon_hwmon_fini(rdev);
1689926deccbSFrançois Tigeot }
1690926deccbSFrançois Tigeot
radeon_pm_fini_dpm(struct radeon_device * rdev)169157e252bfSMichael Neumann static void radeon_pm_fini_dpm(struct radeon_device *rdev)
169257e252bfSMichael Neumann {
169357e252bfSMichael Neumann if (rdev->pm.num_power_states > 1) {
16941cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
169557e252bfSMichael Neumann radeon_dpm_disable(rdev);
16961cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
169757e252bfSMichael Neumann
169857e252bfSMichael Neumann #ifdef TODO_DEVICE_FILE
169957e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_dpm_state);
170057e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
170157e252bfSMichael Neumann /* XXX backwards compat */
170257e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_profile);
170357e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_method);
170457e252bfSMichael Neumann #endif
170557e252bfSMichael Neumann }
170657e252bfSMichael Neumann radeon_dpm_fini(rdev);
170757e252bfSMichael Neumann
17085d6a9071Szrj /* prevents leaking 440 bytes on OLAND */
17095d6a9071Szrj if (rdev->pm.power_state) {
17105d6a9071Szrj int i;
17115d6a9071Szrj for (i = 0; i < rdev->pm.num_power_states; ++i) {
17125d6a9071Szrj kfree(rdev->pm.power_state[i].clock_info);
17135d6a9071Szrj }
171457e252bfSMichael Neumann kfree(rdev->pm.power_state);
17155d6a9071Szrj rdev->pm.power_state = NULL;
17165d6a9071Szrj rdev->pm.num_power_states = 0;
17175d6a9071Szrj }
171857e252bfSMichael Neumann
171957e252bfSMichael Neumann radeon_hwmon_fini(rdev);
172057e252bfSMichael Neumann }
172157e252bfSMichael Neumann
radeon_pm_fini(struct radeon_device * rdev)172257e252bfSMichael Neumann void radeon_pm_fini(struct radeon_device *rdev)
172357e252bfSMichael Neumann {
172457e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM)
172557e252bfSMichael Neumann radeon_pm_fini_dpm(rdev);
172657e252bfSMichael Neumann else
172757e252bfSMichael Neumann radeon_pm_fini_old(rdev);
172857e252bfSMichael Neumann }
172957e252bfSMichael Neumann
radeon_pm_compute_clocks_old(struct radeon_device * rdev)173057e252bfSMichael Neumann static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
1731926deccbSFrançois Tigeot {
1732926deccbSFrançois Tigeot struct drm_device *ddev = rdev->ddev;
1733926deccbSFrançois Tigeot struct drm_crtc *crtc;
1734926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc;
1735926deccbSFrançois Tigeot
1736926deccbSFrançois Tigeot if (rdev->pm.num_power_states < 2)
1737926deccbSFrançois Tigeot return;
1738926deccbSFrançois Tigeot
17391cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1740926deccbSFrançois Tigeot
1741926deccbSFrançois Tigeot rdev->pm.active_crtcs = 0;
1742926deccbSFrançois Tigeot rdev->pm.active_crtc_count = 0;
1743c6f73aabSFrançois Tigeot if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
1744926deccbSFrançois Tigeot list_for_each_entry(crtc,
1745926deccbSFrançois Tigeot &ddev->mode_config.crtc_list, head) {
1746926deccbSFrançois Tigeot radeon_crtc = to_radeon_crtc(crtc);
1747926deccbSFrançois Tigeot if (radeon_crtc->enabled) {
1748926deccbSFrançois Tigeot rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id);
1749926deccbSFrançois Tigeot rdev->pm.active_crtc_count++;
1750926deccbSFrançois Tigeot }
1751926deccbSFrançois Tigeot }
1752c6f73aabSFrançois Tigeot }
1753926deccbSFrançois Tigeot
1754926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
1755926deccbSFrançois Tigeot radeon_pm_update_profile(rdev);
1756926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
1757926deccbSFrançois Tigeot } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
1758926deccbSFrançois Tigeot if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) {
1759926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) {
1760926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) {
1761ee479021SImre Vadász #ifdef DUMBBELL_WIP
1762926deccbSFrançois Tigeot cancel_delayed_work(&rdev->pm.dynpm_idle_work);
1763ee479021SImre Vadász #endif /* DUMBBELL_WIP */
1764926deccbSFrançois Tigeot
1765926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_PAUSED;
1766926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
1767926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev);
1768926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
1769926deccbSFrançois Tigeot
1770926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("radeon: dynamic power management deactivated\n");
1771926deccbSFrançois Tigeot }
1772926deccbSFrançois Tigeot } else if (rdev->pm.active_crtc_count == 1) {
1773926deccbSFrançois Tigeot /* TODO: Increase clocks if needed for current mode */
1774926deccbSFrançois Tigeot
1775926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_MINIMUM) {
1776926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
1777926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_UPCLOCK;
1778926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev);
1779926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
1780926deccbSFrançois Tigeot
1781ee479021SImre Vadász #ifdef DUMBBELL_WIP
1782926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work,
1783926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
1784ee479021SImre Vadász #endif /* DUMBBELL_WIP */
1785926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) {
1786926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
1787ee479021SImre Vadász #ifdef DUMBBELL_WIP
1788926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work,
1789926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
1790ee479021SImre Vadász #endif /* DUMBBELL_WIP */
1791926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n");
1792926deccbSFrançois Tigeot }
1793926deccbSFrançois Tigeot } else { /* count == 0 */
1794926deccbSFrançois Tigeot if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) {
1795ee479021SImre Vadász #ifdef DUMBBELL_WIP
1796926deccbSFrançois Tigeot cancel_delayed_work(&rdev->pm.dynpm_idle_work);
1797ee479021SImre Vadász #endif /* DUMBBELL_WIP */
1798926deccbSFrançois Tigeot
1799926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM;
1800926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM;
1801926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev);
1802926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
1803926deccbSFrançois Tigeot }
1804926deccbSFrançois Tigeot }
1805926deccbSFrançois Tigeot }
1806926deccbSFrançois Tigeot }
1807926deccbSFrançois Tigeot
18081cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1809926deccbSFrançois Tigeot }
1810926deccbSFrançois Tigeot
radeon_pm_compute_clocks_dpm(struct radeon_device * rdev)181157e252bfSMichael Neumann static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
181257e252bfSMichael Neumann {
181357e252bfSMichael Neumann struct drm_device *ddev = rdev->ddev;
181457e252bfSMichael Neumann struct drm_crtc *crtc;
181557e252bfSMichael Neumann struct radeon_crtc *radeon_crtc;
181657e252bfSMichael Neumann
1817c6f73aabSFrançois Tigeot if (!rdev->pm.dpm_enabled)
1818c6f73aabSFrançois Tigeot return;
1819c6f73aabSFrançois Tigeot
18201cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
182157e252bfSMichael Neumann
182257e252bfSMichael Neumann /* update active crtc counts */
182357e252bfSMichael Neumann rdev->pm.dpm.new_active_crtcs = 0;
182457e252bfSMichael Neumann rdev->pm.dpm.new_active_crtc_count = 0;
1825c6f73aabSFrançois Tigeot if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
182657e252bfSMichael Neumann list_for_each_entry(crtc,
182757e252bfSMichael Neumann &ddev->mode_config.crtc_list, head) {
182857e252bfSMichael Neumann radeon_crtc = to_radeon_crtc(crtc);
182957e252bfSMichael Neumann if (crtc->enabled) {
183057e252bfSMichael Neumann rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
183157e252bfSMichael Neumann rdev->pm.dpm.new_active_crtc_count++;
183257e252bfSMichael Neumann }
183357e252bfSMichael Neumann }
1834c6f73aabSFrançois Tigeot }
183557e252bfSMichael Neumann
183657e252bfSMichael Neumann /* update battery/ac status */
183757e252bfSMichael Neumann if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE)
183857e252bfSMichael Neumann rdev->pm.dpm.ac_power = true;
183957e252bfSMichael Neumann else
184057e252bfSMichael Neumann rdev->pm.dpm.ac_power = false;
184157e252bfSMichael Neumann
184257e252bfSMichael Neumann radeon_dpm_change_power_state_locked(rdev);
184357e252bfSMichael Neumann
18441cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1845c6f73aabSFrançois Tigeot
184657e252bfSMichael Neumann }
184757e252bfSMichael Neumann
radeon_pm_compute_clocks(struct radeon_device * rdev)184857e252bfSMichael Neumann void radeon_pm_compute_clocks(struct radeon_device *rdev)
184957e252bfSMichael Neumann {
185057e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM)
185157e252bfSMichael Neumann radeon_pm_compute_clocks_dpm(rdev);
185257e252bfSMichael Neumann else
185357e252bfSMichael Neumann radeon_pm_compute_clocks_old(rdev);
185457e252bfSMichael Neumann }
185557e252bfSMichael Neumann
radeon_pm_in_vbl(struct radeon_device * rdev)1856926deccbSFrançois Tigeot static bool radeon_pm_in_vbl(struct radeon_device *rdev)
1857926deccbSFrançois Tigeot {
1858926deccbSFrançois Tigeot int crtc, vpos, hpos, vbl_status;
1859926deccbSFrançois Tigeot bool in_vbl = true;
1860926deccbSFrançois Tigeot
1861926deccbSFrançois Tigeot /* Iterate over all active crtc's. All crtc's must be in vblank,
1862926deccbSFrançois Tigeot * otherwise return in_vbl == false.
1863926deccbSFrançois Tigeot */
1864926deccbSFrançois Tigeot for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
1865926deccbSFrançois Tigeot if (rdev->pm.active_crtcs & (1 << crtc)) {
1866c59a5c48SFrançois Tigeot vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev,
1867c59a5c48SFrançois Tigeot crtc,
1868c59a5c48SFrançois Tigeot USE_REAL_VBLANKSTART,
1869352ff8bdSFrançois Tigeot &vpos, &hpos, NULL, NULL,
1870352ff8bdSFrançois Tigeot &rdev->mode_info.crtcs[crtc]->base.hwmode);
1871926deccbSFrançois Tigeot if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
18721b13d190SFrançois Tigeot !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK))
1873926deccbSFrançois Tigeot in_vbl = false;
1874926deccbSFrançois Tigeot }
1875926deccbSFrançois Tigeot }
1876926deccbSFrançois Tigeot
1877926deccbSFrançois Tigeot return in_vbl;
1878926deccbSFrançois Tigeot }
1879926deccbSFrançois Tigeot
radeon_pm_debug_check_in_vbl(struct radeon_device * rdev,bool finish)1880926deccbSFrançois Tigeot static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish)
1881926deccbSFrançois Tigeot {
1882926deccbSFrançois Tigeot u32 stat_crtc = 0;
1883926deccbSFrançois Tigeot bool in_vbl = radeon_pm_in_vbl(rdev);
1884926deccbSFrançois Tigeot
1885926deccbSFrançois Tigeot if (in_vbl == false)
1886926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("not in vbl for pm change %08x at %s\n", stat_crtc,
1887926deccbSFrançois Tigeot finish ? "exit" : "entry");
1888926deccbSFrançois Tigeot return in_vbl;
1889926deccbSFrançois Tigeot }
1890926deccbSFrançois Tigeot
radeon_dynpm_idle_work_handler(struct work_struct * work)1891926deccbSFrançois Tigeot static void radeon_dynpm_idle_work_handler(struct work_struct *work)
1892926deccbSFrançois Tigeot {
1893926deccbSFrançois Tigeot struct radeon_device *rdev;
1894926deccbSFrançois Tigeot int resched;
1895926deccbSFrançois Tigeot rdev = container_of(work, struct radeon_device,
1896926deccbSFrançois Tigeot pm.dynpm_idle_work.work);
1897926deccbSFrançois Tigeot
1898926deccbSFrançois Tigeot resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
18991cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1900926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) {
1901926deccbSFrançois Tigeot int not_processed = 0;
1902926deccbSFrançois Tigeot int i;
1903926deccbSFrançois Tigeot
1904926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1905926deccbSFrançois Tigeot struct radeon_ring *ring = &rdev->ring[i];
1906926deccbSFrançois Tigeot
1907926deccbSFrançois Tigeot if (ring->ready) {
1908926deccbSFrançois Tigeot not_processed += radeon_fence_count_emitted(rdev, i);
1909926deccbSFrançois Tigeot if (not_processed >= 3)
1910926deccbSFrançois Tigeot break;
1911926deccbSFrançois Tigeot }
1912926deccbSFrançois Tigeot }
1913926deccbSFrançois Tigeot
1914926deccbSFrançois Tigeot if (not_processed >= 3) { /* should upclock */
1915926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_DOWNCLOCK) {
1916926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
1917926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE &&
1918926deccbSFrançois Tigeot rdev->pm.dynpm_can_upclock) {
1919926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action =
1920926deccbSFrançois Tigeot DYNPM_ACTION_UPCLOCK;
1921926deccbSFrançois Tigeot rdev->pm.dynpm_action_timeout = jiffies +
1922926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS);
1923926deccbSFrançois Tigeot }
1924926deccbSFrançois Tigeot } else if (not_processed == 0) { /* should downclock */
1925926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_UPCLOCK) {
1926926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
1927926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE &&
1928926deccbSFrançois Tigeot rdev->pm.dynpm_can_downclock) {
1929926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action =
1930926deccbSFrançois Tigeot DYNPM_ACTION_DOWNCLOCK;
1931926deccbSFrançois Tigeot rdev->pm.dynpm_action_timeout = jiffies +
1932926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS);
1933926deccbSFrançois Tigeot }
1934926deccbSFrançois Tigeot }
1935926deccbSFrançois Tigeot
1936926deccbSFrançois Tigeot /* Note, radeon_pm_set_clocks is called with static_switch set
1937926deccbSFrançois Tigeot * to false since we want to wait for vbl to avoid flicker.
1938926deccbSFrançois Tigeot */
1939926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action != DYNPM_ACTION_NONE &&
1940926deccbSFrançois Tigeot jiffies > rdev->pm.dynpm_action_timeout) {
1941926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev);
1942926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev);
1943926deccbSFrançois Tigeot }
1944926deccbSFrançois Tigeot
1945926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work,
1946926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
1947926deccbSFrançois Tigeot }
19481cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1949926deccbSFrançois Tigeot ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
1950926deccbSFrançois Tigeot }
1951926deccbSFrançois Tigeot
1952926deccbSFrançois Tigeot /*
1953926deccbSFrançois Tigeot * Debugfs info
1954926deccbSFrançois Tigeot */
1955926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
1956926deccbSFrançois Tigeot
radeon_debugfs_pm_info(struct seq_file * m,void * data)1957926deccbSFrançois Tigeot static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
1958926deccbSFrançois Tigeot {
1959926deccbSFrançois Tigeot struct drm_info_node *node = (struct drm_info_node *) m->private;
1960926deccbSFrançois Tigeot struct drm_device *dev = node->minor->dev;
1961926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private;
1962c6f73aabSFrançois Tigeot struct drm_device *ddev = rdev->ddev;
1963926deccbSFrançois Tigeot
1964c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) &&
1965c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
1966c6f73aabSFrançois Tigeot seq_printf(m, "PX asic powered off\n");
1967c6f73aabSFrançois Tigeot } else if (rdev->pm.dpm_enabled) {
19681cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
196957e252bfSMichael Neumann if (rdev->asic->dpm.debugfs_print_current_performance_level)
197057e252bfSMichael Neumann radeon_dpm_debugfs_print_current_performance_level(rdev, m);
197157e252bfSMichael Neumann else
197257e252bfSMichael Neumann seq_printf(m, "Debugfs support not implemented for this asic\n");
19731cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
197457e252bfSMichael Neumann } else {
1975926deccbSFrançois Tigeot seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
1976f43cf1b1SMichael Neumann /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */
1977f43cf1b1SMichael Neumann if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP))
1978f43cf1b1SMichael Neumann seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk);
1979f43cf1b1SMichael Neumann else
1980926deccbSFrançois Tigeot seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
1981926deccbSFrançois Tigeot seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
1982926deccbSFrançois Tigeot if (rdev->asic->pm.get_memory_clock)
1983926deccbSFrançois Tigeot seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
1984926deccbSFrançois Tigeot if (rdev->pm.current_vddc)
1985926deccbSFrançois Tigeot seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
1986926deccbSFrançois Tigeot if (rdev->asic->pm.get_pcie_lanes)
1987926deccbSFrançois Tigeot seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
198857e252bfSMichael Neumann }
1989926deccbSFrançois Tigeot
1990926deccbSFrançois Tigeot return 0;
1991926deccbSFrançois Tigeot }
1992926deccbSFrançois Tigeot
1993926deccbSFrançois Tigeot static struct drm_info_list radeon_pm_info_list[] = {
1994926deccbSFrançois Tigeot {"radeon_pm_info", radeon_debugfs_pm_info, 0, NULL},
1995926deccbSFrançois Tigeot };
1996926deccbSFrançois Tigeot #endif
1997926deccbSFrançois Tigeot
radeon_debugfs_pm_init(struct radeon_device * rdev)1998926deccbSFrançois Tigeot static int radeon_debugfs_pm_init(struct radeon_device *rdev)
1999926deccbSFrançois Tigeot {
2000926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
2001926deccbSFrançois Tigeot return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list));
2002926deccbSFrançois Tigeot #else
2003926deccbSFrançois Tigeot return 0;
2004926deccbSFrançois Tigeot #endif
2005926deccbSFrançois Tigeot }
2006