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" 27*c59a5c48SFranç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 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 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 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 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 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 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 251926deccbSFrançois Tigeot static void radeon_pm_set_clocks(struct radeon_device *rdev) 252926deccbSFrançois Tigeot { 253926deccbSFrançois Tigeot int i, r; 254926deccbSFrançois Tigeot 255926deccbSFrançois Tigeot /* no need to take locks, etc. if nothing's going to change */ 256926deccbSFrançois Tigeot if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && 257926deccbSFrançois Tigeot (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) 258926deccbSFrançois Tigeot return; 259926deccbSFrançois Tigeot 2601cfef1a5SFrançois Tigeot down_write(&rdev->pm.mclk_lock); 2611cfef1a5SFrançois Tigeot mutex_lock(&rdev->ring_lock); 262926deccbSFrançois Tigeot 263926deccbSFrançois Tigeot /* wait for the rings to drain */ 264926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) { 265926deccbSFrançois Tigeot struct radeon_ring *ring = &rdev->ring[i]; 266926deccbSFrançois Tigeot if (!ring->ready) { 267926deccbSFrançois Tigeot continue; 268926deccbSFrançois Tigeot } 269c6f73aabSFrançois Tigeot r = radeon_fence_wait_empty(rdev, i); 270926deccbSFrançois Tigeot if (r) { 271926deccbSFrançois Tigeot /* needs a GPU reset dont reset here */ 2721cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock); 2731cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock); 274926deccbSFrançois Tigeot return; 275926deccbSFrançois Tigeot } 276926deccbSFrançois Tigeot } 277926deccbSFrançois Tigeot 278926deccbSFrançois Tigeot radeon_unmap_vram_bos(rdev); 279926deccbSFrançois Tigeot 280926deccbSFrançois Tigeot if (rdev->irq.installed) { 281926deccbSFrançois Tigeot for (i = 0; i < rdev->num_crtc; i++) { 282926deccbSFrançois Tigeot if (rdev->pm.active_crtcs & (1 << i)) { 283926deccbSFrançois Tigeot rdev->pm.req_vblank |= (1 << i); 284ee479021SImre Vadász drm_vblank_get(rdev->ddev, i); 285926deccbSFrançois Tigeot } 286926deccbSFrançois Tigeot } 287926deccbSFrançois Tigeot } 288926deccbSFrançois Tigeot 289926deccbSFrançois Tigeot radeon_set_power_state(rdev); 290926deccbSFrançois Tigeot 291926deccbSFrançois Tigeot if (rdev->irq.installed) { 292926deccbSFrançois Tigeot for (i = 0; i < rdev->num_crtc; i++) { 293926deccbSFrançois Tigeot if (rdev->pm.req_vblank & (1 << i)) { 294926deccbSFrançois Tigeot rdev->pm.req_vblank &= ~(1 << i); 295926deccbSFrançois Tigeot drm_vblank_put(rdev->ddev, i); 296926deccbSFrançois Tigeot } 297926deccbSFrançois Tigeot } 298926deccbSFrançois Tigeot } 299926deccbSFrançois Tigeot 300926deccbSFrançois Tigeot /* update display watermarks based on new power state */ 301926deccbSFrançois Tigeot radeon_update_bandwidth_info(rdev); 302926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count) 303926deccbSFrançois Tigeot radeon_bandwidth_update(rdev); 304926deccbSFrançois Tigeot 305926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 306926deccbSFrançois Tigeot 3071cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock); 3081cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock); 309926deccbSFrançois Tigeot } 310926deccbSFrançois Tigeot 311926deccbSFrançois Tigeot static void radeon_pm_print_states(struct radeon_device *rdev) 312926deccbSFrançois Tigeot { 313926deccbSFrançois Tigeot int i, j; 314926deccbSFrançois Tigeot struct radeon_power_state *power_state; 315926deccbSFrançois Tigeot struct radeon_pm_clock_info *clock_info; 316926deccbSFrançois Tigeot 317926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("%d Power State(s)\n", rdev->pm.num_power_states); 318926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; i++) { 319926deccbSFrançois Tigeot power_state = &rdev->pm.power_state[i]; 320926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("State %d: %s\n", i, 321926deccbSFrançois Tigeot radeon_pm_state_type_name[power_state->type]); 322926deccbSFrançois Tigeot if (i == rdev->pm.default_power_state_index) 323926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\tDefault"); 324926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) 325926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t%d PCIE Lanes\n", power_state->pcie_lanes); 326926deccbSFrançois Tigeot if (power_state->flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) 327926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\tSingle display only\n"); 328926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t%d Clock Mode(s)\n", power_state->num_clock_modes); 329926deccbSFrançois Tigeot for (j = 0; j < power_state->num_clock_modes; j++) { 330926deccbSFrançois Tigeot clock_info = &(power_state->clock_info[j]); 331926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_IGP) 332926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t\t%d e: %d\n", 333926deccbSFrançois Tigeot j, 334926deccbSFrançois Tigeot clock_info->sclk * 10); 335926deccbSFrançois Tigeot else 336926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d\n", 337926deccbSFrançois Tigeot j, 338926deccbSFrançois Tigeot clock_info->sclk * 10, 339926deccbSFrançois Tigeot clock_info->mclk * 10, 340926deccbSFrançois Tigeot clock_info->voltage.voltage); 341926deccbSFrançois Tigeot } 342926deccbSFrançois Tigeot } 343926deccbSFrançois Tigeot } 344926deccbSFrançois Tigeot 345926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 346926deccbSFrançois Tigeot static ssize_t radeon_get_pm_profile(struct device *dev, 347926deccbSFrançois Tigeot struct device_attribute *attr, 348926deccbSFrançois Tigeot char *buf) 349926deccbSFrançois Tigeot { 350c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 351926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 352926deccbSFrançois Tigeot int cp = rdev->pm.profile; 353926deccbSFrançois Tigeot 354926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%s\n", 355926deccbSFrançois Tigeot (cp == PM_PROFILE_AUTO) ? "auto" : 356926deccbSFrançois Tigeot (cp == PM_PROFILE_LOW) ? "low" : 357926deccbSFrançois Tigeot (cp == PM_PROFILE_MID) ? "mid" : 358926deccbSFrançois Tigeot (cp == PM_PROFILE_HIGH) ? "high" : "default"); 359926deccbSFrançois Tigeot } 360926deccbSFrançois Tigeot 361926deccbSFrançois Tigeot static ssize_t radeon_set_pm_profile(struct device *dev, 362926deccbSFrançois Tigeot struct device_attribute *attr, 363926deccbSFrançois Tigeot const char *buf, 364926deccbSFrançois Tigeot size_t count) 365926deccbSFrançois Tigeot { 366c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 367926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 368926deccbSFrançois Tigeot 369c6f73aabSFrançois Tigeot /* Can't set profile when the card is off */ 370c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 371c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 372c6f73aabSFrançois Tigeot return -EINVAL; 373c6f73aabSFrançois Tigeot 3741cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 375926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) { 376926deccbSFrançois Tigeot if (strncmp("default", buf, strlen("default")) == 0) 377926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT; 378926deccbSFrançois Tigeot else if (strncmp("auto", buf, strlen("auto")) == 0) 379926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_AUTO; 380926deccbSFrançois Tigeot else if (strncmp("low", buf, strlen("low")) == 0) 381926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_LOW; 382926deccbSFrançois Tigeot else if (strncmp("mid", buf, strlen("mid")) == 0) 383926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_MID; 384926deccbSFrançois Tigeot else if (strncmp("high", buf, strlen("high")) == 0) 385926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_HIGH; 386926deccbSFrançois Tigeot else { 387926deccbSFrançois Tigeot count = -EINVAL; 388926deccbSFrançois Tigeot goto fail; 389926deccbSFrançois Tigeot } 390926deccbSFrançois Tigeot radeon_pm_update_profile(rdev); 391926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 392926deccbSFrançois Tigeot } else 393926deccbSFrançois Tigeot count = -EINVAL; 394926deccbSFrançois Tigeot 395926deccbSFrançois Tigeot fail: 3961cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 397926deccbSFrançois Tigeot 398926deccbSFrançois Tigeot return count; 399926deccbSFrançois Tigeot } 400926deccbSFrançois Tigeot 401926deccbSFrançois Tigeot static ssize_t radeon_get_pm_method(struct device *dev, 402926deccbSFrançois Tigeot struct device_attribute *attr, 403926deccbSFrançois Tigeot char *buf) 404926deccbSFrançois Tigeot { 405c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 406926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 407926deccbSFrançois Tigeot int pm = rdev->pm.pm_method; 408926deccbSFrançois Tigeot 409926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%s\n", 41057e252bfSMichael Neumann (pm == PM_METHOD_DYNPM) ? "dynpm" : 41157e252bfSMichael Neumann (pm == PM_METHOD_PROFILE) ? "profile" : "dpm"); 412926deccbSFrançois Tigeot } 413926deccbSFrançois Tigeot 414926deccbSFrançois Tigeot static ssize_t radeon_set_pm_method(struct device *dev, 415926deccbSFrançois Tigeot struct device_attribute *attr, 416926deccbSFrançois Tigeot const char *buf, 417926deccbSFrançois Tigeot size_t count) 418926deccbSFrançois Tigeot { 419c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 420926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 421926deccbSFrançois Tigeot 422c6f73aabSFrançois Tigeot /* Can't set method when the card is off */ 423c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 424c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { 425c6f73aabSFrançois Tigeot count = -EINVAL; 426c6f73aabSFrançois Tigeot goto fail; 427c6f73aabSFrançois Tigeot } 428c6f73aabSFrançois Tigeot 42957e252bfSMichael Neumann /* we don't support the legacy modes with dpm */ 43057e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) { 43157e252bfSMichael Neumann count = -EINVAL; 43257e252bfSMichael Neumann goto fail; 43357e252bfSMichael Neumann } 434926deccbSFrançois Tigeot 435926deccbSFrançois Tigeot if (strncmp("dynpm", buf, strlen("dynpm")) == 0) { 4361cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 437926deccbSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DYNPM; 438926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; 439926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; 4401cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 441926deccbSFrançois Tigeot } else if (strncmp("profile", buf, strlen("profile")) == 0) { 4421cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 443926deccbSFrançois Tigeot /* disable dynpm */ 444926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; 445926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 446926deccbSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 4471cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 448ee479021SImre Vadász #ifdef DUMBBELL_WIP 449926deccbSFrançois Tigeot cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); 450ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 451926deccbSFrançois Tigeot } else { 452926deccbSFrançois Tigeot count = -EINVAL; 453926deccbSFrançois Tigeot goto fail; 454926deccbSFrançois Tigeot } 455926deccbSFrançois Tigeot radeon_pm_compute_clocks(rdev); 456926deccbSFrançois Tigeot fail: 457926deccbSFrançois Tigeot return count; 458926deccbSFrançois Tigeot } 459926deccbSFrançois Tigeot 46057e252bfSMichael Neumann static ssize_t radeon_get_dpm_state(struct device *dev, 46157e252bfSMichael Neumann struct device_attribute *attr, 46257e252bfSMichael Neumann char *buf) 46357e252bfSMichael Neumann { 464c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 46557e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 46657e252bfSMichael Neumann enum radeon_pm_state_type pm = rdev->pm.dpm.user_state; 46757e252bfSMichael Neumann 46857e252bfSMichael Neumann return snprintf(buf, PAGE_SIZE, "%s\n", 46957e252bfSMichael Neumann (pm == POWER_STATE_TYPE_BATTERY) ? "battery" : 47057e252bfSMichael Neumann (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance"); 47157e252bfSMichael Neumann } 47257e252bfSMichael Neumann 47357e252bfSMichael Neumann static ssize_t radeon_set_dpm_state(struct device *dev, 47457e252bfSMichael Neumann struct device_attribute *attr, 47557e252bfSMichael Neumann const char *buf, 47657e252bfSMichael Neumann size_t count) 47757e252bfSMichael Neumann { 478c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 47957e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 48057e252bfSMichael Neumann 4811cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 48257e252bfSMichael Neumann if (strncmp("battery", buf, strlen("battery")) == 0) 48357e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY; 48457e252bfSMichael Neumann else if (strncmp("balanced", buf, strlen("balanced")) == 0) 48557e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED; 48657e252bfSMichael Neumann else if (strncmp("performance", buf, strlen("performance")) == 0) 48757e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE; 48857e252bfSMichael Neumann else { 4891cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 49057e252bfSMichael Neumann count = -EINVAL; 49157e252bfSMichael Neumann goto fail; 49257e252bfSMichael Neumann } 4931cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 494c6f73aabSFrançois Tigeot 495c6f73aabSFrançois Tigeot /* Can't set dpm state when the card is off */ 496c6f73aabSFrançois Tigeot if (!(rdev->flags & RADEON_IS_PX) || 497c6f73aabSFrançois Tigeot (ddev->switch_power_state == DRM_SWITCH_POWER_ON)) 49857e252bfSMichael Neumann radeon_pm_compute_clocks(rdev); 499c6f73aabSFrançois Tigeot 50057e252bfSMichael Neumann fail: 50157e252bfSMichael Neumann return count; 50257e252bfSMichael Neumann } 50357e252bfSMichael Neumann 50457e252bfSMichael Neumann static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev, 50557e252bfSMichael Neumann struct device_attribute *attr, 50657e252bfSMichael Neumann char *buf) 50757e252bfSMichael Neumann { 508c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 50957e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 51057e252bfSMichael Neumann enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; 51157e252bfSMichael Neumann 512c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 513c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 5141cfef1a5SFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "off\n"); 515c6f73aabSFrançois Tigeot 51657e252bfSMichael Neumann return snprintf(buf, PAGE_SIZE, "%s\n", 51757e252bfSMichael Neumann (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" : 51857e252bfSMichael Neumann (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high"); 51957e252bfSMichael Neumann } 52057e252bfSMichael Neumann 52157e252bfSMichael Neumann static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev, 52257e252bfSMichael Neumann struct device_attribute *attr, 52357e252bfSMichael Neumann const char *buf, 52457e252bfSMichael Neumann size_t count) 52557e252bfSMichael Neumann { 526c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 52757e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 52857e252bfSMichael Neumann enum radeon_dpm_forced_level level; 52957e252bfSMichael Neumann int ret = 0; 53057e252bfSMichael Neumann 531c6f73aabSFrançois Tigeot /* Can't force performance level when the card is off */ 532c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 533c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 534c6f73aabSFrançois Tigeot return -EINVAL; 535c6f73aabSFrançois Tigeot 5361cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 53757e252bfSMichael Neumann if (strncmp("low", buf, strlen("low")) == 0) { 53857e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_LOW; 53957e252bfSMichael Neumann } else if (strncmp("high", buf, strlen("high")) == 0) { 54057e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_HIGH; 54157e252bfSMichael Neumann } else if (strncmp("auto", buf, strlen("auto")) == 0) { 54257e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_AUTO; 54357e252bfSMichael Neumann } else { 54457e252bfSMichael Neumann count = -EINVAL; 54557e252bfSMichael Neumann goto fail; 54657e252bfSMichael Neumann } 54757e252bfSMichael Neumann if (rdev->asic->dpm.force_performance_level) { 548c6f73aabSFrançois Tigeot if (rdev->pm.dpm.thermal_active) { 549c6f73aabSFrançois Tigeot count = -EINVAL; 550c6f73aabSFrançois Tigeot goto fail; 551c6f73aabSFrançois Tigeot } 55257e252bfSMichael Neumann ret = radeon_dpm_force_performance_level(rdev, level); 55357e252bfSMichael Neumann if (ret) 55457e252bfSMichael Neumann count = -EINVAL; 55557e252bfSMichael Neumann } 55657e252bfSMichael Neumann fail: 5571cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 558c6f73aabSFrançois Tigeot 55957e252bfSMichael Neumann return count; 56057e252bfSMichael Neumann } 56157e252bfSMichael Neumann 562*c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev, 563*c59a5c48SFrançois Tigeot struct device_attribute *attr, 564*c59a5c48SFrançois Tigeot char *buf) 565*c59a5c48SFrançois Tigeot { 566*c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 567*c59a5c48SFrançois Tigeot u32 pwm_mode = 0; 568*c59a5c48SFrançois Tigeot 569*c59a5c48SFrançois Tigeot if (rdev->asic->dpm.fan_ctrl_get_mode) 570*c59a5c48SFrançois Tigeot pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev); 571*c59a5c48SFrançois Tigeot 572*c59a5c48SFrançois Tigeot /* never 0 (full-speed), fuse or smc-controlled always */ 573*c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2); 574*c59a5c48SFrançois Tigeot } 575*c59a5c48SFrançois Tigeot 576*c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev, 577*c59a5c48SFrançois Tigeot struct device_attribute *attr, 578*c59a5c48SFrançois Tigeot const char *buf, 579*c59a5c48SFrançois Tigeot size_t count) 580*c59a5c48SFrançois Tigeot { 581*c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 582*c59a5c48SFrançois Tigeot int err; 583*c59a5c48SFrançois Tigeot int value; 584*c59a5c48SFrançois Tigeot 585*c59a5c48SFrançois Tigeot if(!rdev->asic->dpm.fan_ctrl_set_mode) 586*c59a5c48SFrançois Tigeot return -EINVAL; 587*c59a5c48SFrançois Tigeot 588*c59a5c48SFrançois Tigeot err = kstrtoint(buf, 10, &value); 589*c59a5c48SFrançois Tigeot if (err) 590*c59a5c48SFrançois Tigeot return err; 591*c59a5c48SFrançois Tigeot 592*c59a5c48SFrançois Tigeot switch (value) { 593*c59a5c48SFrançois Tigeot case 1: /* manual, percent-based */ 594*c59a5c48SFrançois Tigeot rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC); 595*c59a5c48SFrançois Tigeot break; 596*c59a5c48SFrançois Tigeot default: /* disable */ 597*c59a5c48SFrançois Tigeot rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0); 598*c59a5c48SFrançois Tigeot break; 599*c59a5c48SFrançois Tigeot } 600*c59a5c48SFrançois Tigeot 601*c59a5c48SFrançois Tigeot return count; 602*c59a5c48SFrançois Tigeot } 603*c59a5c48SFrançois Tigeot 604*c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev, 605*c59a5c48SFrançois Tigeot struct device_attribute *attr, 606*c59a5c48SFrançois Tigeot char *buf) 607*c59a5c48SFrançois Tigeot { 608*c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", 0); 609*c59a5c48SFrançois Tigeot } 610*c59a5c48SFrançois Tigeot 611*c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev, 612*c59a5c48SFrançois Tigeot struct device_attribute *attr, 613*c59a5c48SFrançois Tigeot char *buf) 614*c59a5c48SFrançois Tigeot { 615*c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", 255); 616*c59a5c48SFrançois Tigeot } 617*c59a5c48SFrançois Tigeot 618*c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_set_pwm1(struct device *dev, 619*c59a5c48SFrançois Tigeot struct device_attribute *attr, 620*c59a5c48SFrançois Tigeot const char *buf, size_t count) 621*c59a5c48SFrançois Tigeot { 622*c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 623*c59a5c48SFrançois Tigeot int err; 624*c59a5c48SFrançois Tigeot u32 value; 625*c59a5c48SFrançois Tigeot 626*c59a5c48SFrançois Tigeot err = kstrtou32(buf, 10, &value); 627*c59a5c48SFrançois Tigeot if (err) 628*c59a5c48SFrançois Tigeot return err; 629*c59a5c48SFrançois Tigeot 630*c59a5c48SFrançois Tigeot value = (value * 100) / 255; 631*c59a5c48SFrançois Tigeot 632*c59a5c48SFrançois Tigeot err = rdev->asic->dpm.set_fan_speed_percent(rdev, value); 633*c59a5c48SFrançois Tigeot if (err) 634*c59a5c48SFrançois Tigeot return err; 635*c59a5c48SFrançois Tigeot 636*c59a5c48SFrançois Tigeot return count; 637*c59a5c48SFrançois Tigeot } 638*c59a5c48SFrançois Tigeot 639*c59a5c48SFrançois Tigeot static ssize_t radeon_hwmon_get_pwm1(struct device *dev, 640*c59a5c48SFrançois Tigeot struct device_attribute *attr, 641*c59a5c48SFrançois Tigeot char *buf) 642*c59a5c48SFrançois Tigeot { 643*c59a5c48SFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 644*c59a5c48SFrançois Tigeot int err; 645*c59a5c48SFrançois Tigeot u32 speed; 646*c59a5c48SFrançois Tigeot 647*c59a5c48SFrançois Tigeot err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed); 648*c59a5c48SFrançois Tigeot if (err) 649*c59a5c48SFrançois Tigeot return err; 650*c59a5c48SFrançois Tigeot 651*c59a5c48SFrançois Tigeot speed = (speed * 255) / 100; 652*c59a5c48SFrançois Tigeot 653*c59a5c48SFrançois Tigeot return sprintf(buf, "%i\n", speed); 654*c59a5c48SFrançois Tigeot } 655*c59a5c48SFrançois Tigeot 656926deccbSFrançois Tigeot static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); 657926deccbSFrançois Tigeot static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); 65857e252bfSMichael Neumann static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); 65957e252bfSMichael Neumann static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, 66057e252bfSMichael Neumann radeon_get_dpm_forced_performance_level, 66157e252bfSMichael Neumann radeon_set_dpm_forced_performance_level); 662926deccbSFrançois Tigeot 663926deccbSFrançois Tigeot static ssize_t radeon_hwmon_show_temp(struct device *dev, 664926deccbSFrançois Tigeot struct device_attribute *attr, 665926deccbSFrançois Tigeot char *buf) 666926deccbSFrançois Tigeot { 667c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 668c6f73aabSFrançois Tigeot struct drm_device *ddev = rdev->ddev; 669926deccbSFrançois Tigeot int temp; 670926deccbSFrançois Tigeot 671c6f73aabSFrançois Tigeot /* Can't get temperature when the card is off */ 672c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 673c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 674c6f73aabSFrançois Tigeot return -EINVAL; 675c6f73aabSFrançois Tigeot 67657e252bfSMichael Neumann if (rdev->asic->pm.get_temperature) 67757e252bfSMichael Neumann temp = radeon_get_temperature(rdev); 67857e252bfSMichael Neumann else 679926deccbSFrançois Tigeot temp = 0; 680926deccbSFrançois Tigeot 681926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%d\n", temp); 682926deccbSFrançois Tigeot } 683926deccbSFrançois Tigeot 684c6f73aabSFrançois Tigeot static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev, 685926deccbSFrançois Tigeot struct device_attribute *attr, 686926deccbSFrançois Tigeot char *buf) 687926deccbSFrançois Tigeot { 688c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 689c6f73aabSFrançois Tigeot int hyst = to_sensor_dev_attr(attr)->index; 690c6f73aabSFrançois Tigeot int temp; 691c6f73aabSFrançois Tigeot 692c6f73aabSFrançois Tigeot if (hyst) 693c6f73aabSFrançois Tigeot temp = rdev->pm.dpm.thermal.min_temp; 694c6f73aabSFrançois Tigeot else 695c6f73aabSFrançois Tigeot temp = rdev->pm.dpm.thermal.max_temp; 696c6f73aabSFrançois Tigeot 697c6f73aabSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%d\n", temp); 698926deccbSFrançois Tigeot } 699926deccbSFrançois Tigeot 700926deccbSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0); 701c6f73aabSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0); 702c6f73aabSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1); 703*c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0); 704*c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0); 705*c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0); 706*c59a5c48SFrançois Tigeot static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0); 707*c59a5c48SFrançois Tigeot 708926deccbSFrançois Tigeot 709926deccbSFrançois Tigeot static struct attribute *hwmon_attributes[] = { 710926deccbSFrançois Tigeot &sensor_dev_attr_temp1_input.dev_attr.attr, 711c6f73aabSFrançois Tigeot &sensor_dev_attr_temp1_crit.dev_attr.attr, 712c6f73aabSFrançois Tigeot &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, 713*c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1.dev_attr.attr, 714*c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1_enable.dev_attr.attr, 715*c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1_min.dev_attr.attr, 716*c59a5c48SFrançois Tigeot &sensor_dev_attr_pwm1_max.dev_attr.attr, 717926deccbSFrançois Tigeot NULL 718926deccbSFrançois Tigeot }; 719926deccbSFrançois Tigeot 720c6f73aabSFrançois Tigeot static umode_t hwmon_attributes_visible(struct kobject *kobj, 721c6f73aabSFrançois Tigeot struct attribute *attr, int index) 722c6f73aabSFrançois Tigeot { 723c6f73aabSFrançois Tigeot struct device *dev = container_of(kobj, struct device, kobj); 724c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 725*c59a5c48SFrançois Tigeot umode_t effective_mode = attr->mode; 726c6f73aabSFrançois Tigeot 727*c59a5c48SFrançois Tigeot /* Skip attributes if DPM is not enabled */ 728c6f73aabSFrançois Tigeot if (rdev->pm.pm_method != PM_METHOD_DPM && 729c6f73aabSFrançois Tigeot (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr || 730*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr || 731*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1.dev_attr.attr || 732*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || 733*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || 734*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) 735c6f73aabSFrançois Tigeot return 0; 736c6f73aabSFrançois Tigeot 737*c59a5c48SFrançois Tigeot /* Skip fan attributes if fan is not present */ 738*c59a5c48SFrançois Tigeot if (rdev->pm.no_fan && 739*c59a5c48SFrançois Tigeot (attr == &sensor_dev_attr_pwm1.dev_attr.attr || 740*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || 741*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || 742*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) 743*c59a5c48SFrançois Tigeot return 0; 744*c59a5c48SFrançois Tigeot 745*c59a5c48SFrançois Tigeot /* mask fan attributes if we have no bindings for this asic to expose */ 746*c59a5c48SFrançois Tigeot if ((!rdev->asic->dpm.get_fan_speed_percent && 747*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */ 748*c59a5c48SFrançois Tigeot (!rdev->asic->dpm.fan_ctrl_get_mode && 749*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */ 750*c59a5c48SFrançois Tigeot effective_mode &= ~S_IRUGO; 751*c59a5c48SFrançois Tigeot 752*c59a5c48SFrançois Tigeot if ((!rdev->asic->dpm.set_fan_speed_percent && 753*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */ 754*c59a5c48SFrançois Tigeot (!rdev->asic->dpm.fan_ctrl_set_mode && 755*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */ 756*c59a5c48SFrançois Tigeot effective_mode &= ~S_IWUSR; 757*c59a5c48SFrançois Tigeot 758*c59a5c48SFrançois Tigeot /* hide max/min values if we can't both query and manage the fan */ 759*c59a5c48SFrançois Tigeot if ((!rdev->asic->dpm.set_fan_speed_percent && 760*c59a5c48SFrançois Tigeot !rdev->asic->dpm.get_fan_speed_percent) && 761*c59a5c48SFrançois Tigeot (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || 762*c59a5c48SFrançois Tigeot attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) 763*c59a5c48SFrançois Tigeot return 0; 764*c59a5c48SFrançois Tigeot 765*c59a5c48SFrançois Tigeot return effective_mode; 766c6f73aabSFrançois Tigeot } 767c6f73aabSFrançois Tigeot 768926deccbSFrançois Tigeot static const struct attribute_group hwmon_attrgroup = { 769926deccbSFrançois Tigeot .attrs = hwmon_attributes, 770c6f73aabSFrançois Tigeot .is_visible = hwmon_attributes_visible, 771c6f73aabSFrançois Tigeot }; 772c6f73aabSFrançois Tigeot 773c6f73aabSFrançois Tigeot static const struct attribute_group *hwmon_groups[] = { 774c6f73aabSFrançois Tigeot &hwmon_attrgroup, 775c6f73aabSFrançois Tigeot NULL 776926deccbSFrançois Tigeot }; 777926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 778926deccbSFrançois Tigeot 7792c86cb5bSImre Vadász static void 7802c86cb5bSImre Vadász radeon_hwmon_refresh(void *arg) 7812c86cb5bSImre Vadász { 7822c86cb5bSImre Vadász struct radeon_device *rdev = (struct radeon_device *)arg; 78326b5dbf2SImre Vadász struct drm_device *ddev = rdev->ddev; 7842c86cb5bSImre Vadász struct ksensor *s = rdev->pm.int_sensor; 7852c86cb5bSImre Vadász int temp; 78626b5dbf2SImre Vadász enum sensor_status stat; 7872c86cb5bSImre Vadász 78826b5dbf2SImre Vadász /* Can't get temperature when the card is off */ 78926b5dbf2SImre Vadász if ((rdev->flags & RADEON_IS_PX) && 79026b5dbf2SImre Vadász (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { 79126b5dbf2SImre Vadász sensor_set_unknown(s); 79226b5dbf2SImre Vadász s->status = SENSOR_S_OK; 79326b5dbf2SImre Vadász return; 79426b5dbf2SImre Vadász } 79526b5dbf2SImre Vadász 79626b5dbf2SImre Vadász if (rdev->asic->pm.get_temperature == NULL) { 79726b5dbf2SImre Vadász sensor_set_invalid(s); 79826b5dbf2SImre Vadász return; 79926b5dbf2SImre Vadász } 80026b5dbf2SImre Vadász 8012c86cb5bSImre Vadász temp = radeon_get_temperature(rdev); 80226b5dbf2SImre Vadász if (temp >= rdev->pm.dpm.thermal.max_temp) 80326b5dbf2SImre Vadász stat = SENSOR_S_CRIT; 80426b5dbf2SImre Vadász else if (temp >= rdev->pm.dpm.thermal.min_temp) 80526b5dbf2SImre Vadász stat = SENSOR_S_WARN; 8062c86cb5bSImre Vadász else 80726b5dbf2SImre Vadász stat = SENSOR_S_OK; 8082c86cb5bSImre Vadász 80926b5dbf2SImre Vadász sensor_set(s, temp * 1000 + 273150000, stat); 8102c86cb5bSImre Vadász } 8112c86cb5bSImre Vadász 812926deccbSFrançois Tigeot static int radeon_hwmon_init(struct radeon_device *rdev) 813926deccbSFrançois Tigeot { 814926deccbSFrançois Tigeot int err = 0; 815926deccbSFrançois Tigeot 8162c86cb5bSImre Vadász rdev->pm.int_sensor = NULL; 8172c86cb5bSImre Vadász rdev->pm.int_sensordev = NULL; 818926deccbSFrançois Tigeot 819926deccbSFrançois Tigeot switch (rdev->pm.int_thermal_type) { 820926deccbSFrançois Tigeot case THERMAL_TYPE_RV6XX: 821926deccbSFrançois Tigeot case THERMAL_TYPE_RV770: 822926deccbSFrançois Tigeot case THERMAL_TYPE_EVERGREEN: 823926deccbSFrançois Tigeot case THERMAL_TYPE_NI: 824926deccbSFrançois Tigeot case THERMAL_TYPE_SUMO: 825926deccbSFrançois Tigeot case THERMAL_TYPE_SI: 8264cd92098Szrj case THERMAL_TYPE_CI: 8274cd92098Szrj case THERMAL_TYPE_KV: 82857e252bfSMichael Neumann if (rdev->asic->pm.get_temperature == NULL) 829926deccbSFrançois Tigeot return err; 8302c86cb5bSImre Vadász 8312c86cb5bSImre Vadász rdev->pm.int_sensor = kmalloc(sizeof(*rdev->pm.int_sensor), 8322c86cb5bSImre Vadász M_DRM, M_ZERO | M_WAITOK); 8332c86cb5bSImre Vadász rdev->pm.int_sensordev = kmalloc( 8342c86cb5bSImre Vadász sizeof(*rdev->pm.int_sensordev), M_DRM, 8352c86cb5bSImre Vadász M_ZERO | M_WAITOK); 8362c86cb5bSImre Vadász strlcpy(rdev->pm.int_sensordev->xname, 837fb572d17SFrançois Tigeot device_get_nameunit(rdev->dev->bsddev), 8382c86cb5bSImre Vadász sizeof(rdev->pm.int_sensordev->xname)); 8392c86cb5bSImre Vadász rdev->pm.int_sensor->type = SENSOR_TEMP; 84026b5dbf2SImre Vadász rdev->pm.int_sensor->flags |= SENSOR_FINVALID; 8412c86cb5bSImre Vadász sensor_attach(rdev->pm.int_sensordev, rdev->pm.int_sensor); 8422c86cb5bSImre Vadász sensor_task_register(rdev, radeon_hwmon_refresh, 5); 8432c86cb5bSImre Vadász sensordev_install(rdev->pm.int_sensordev); 844926deccbSFrançois Tigeot break; 845926deccbSFrançois Tigeot default: 846926deccbSFrançois Tigeot break; 847926deccbSFrançois Tigeot } 848926deccbSFrançois Tigeot 849926deccbSFrançois Tigeot return err; 850926deccbSFrançois Tigeot } 851926deccbSFrançois Tigeot 852926deccbSFrançois Tigeot static void radeon_hwmon_fini(struct radeon_device *rdev) 853926deccbSFrançois Tigeot { 8542c86cb5bSImre Vadász if (rdev->pm.int_sensor != NULL && rdev->pm.int_sensordev != NULL) { 8552c86cb5bSImre Vadász sensordev_deinstall(rdev->pm.int_sensordev); 8562c86cb5bSImre Vadász sensor_task_unregister(rdev); 8572c86cb5bSImre Vadász kfree(rdev->pm.int_sensor); 8582c86cb5bSImre Vadász kfree(rdev->pm.int_sensordev); 8592c86cb5bSImre Vadász rdev->pm.int_sensor = NULL; 8602c86cb5bSImre Vadász rdev->pm.int_sensordev = NULL; 861926deccbSFrançois Tigeot } 862926deccbSFrançois Tigeot } 863926deccbSFrançois Tigeot 8642c5cc6b9SFrançois Tigeot static void radeon_dpm_thermal_work_handler(struct work_struct *work) 86557e252bfSMichael Neumann { 8662c5cc6b9SFrançois Tigeot struct radeon_device *rdev = 8672c5cc6b9SFrançois Tigeot container_of(work, struct radeon_device, 8682c5cc6b9SFrançois Tigeot pm.dpm.thermal.work); 86957e252bfSMichael Neumann /* switch to the thermal state */ 87057e252bfSMichael Neumann enum radeon_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL; 87157e252bfSMichael Neumann 87257e252bfSMichael Neumann if (!rdev->pm.dpm_enabled) 87357e252bfSMichael Neumann return; 87457e252bfSMichael Neumann 87557e252bfSMichael Neumann if (rdev->asic->pm.get_temperature) { 87657e252bfSMichael Neumann int temp = radeon_get_temperature(rdev); 87757e252bfSMichael Neumann 87857e252bfSMichael Neumann if (temp < rdev->pm.dpm.thermal.min_temp) 87957e252bfSMichael Neumann /* switch back the user state */ 88057e252bfSMichael Neumann dpm_state = rdev->pm.dpm.user_state; 88157e252bfSMichael Neumann } else { 88257e252bfSMichael Neumann if (rdev->pm.dpm.thermal.high_to_low) 88357e252bfSMichael Neumann /* switch back the user state */ 88457e252bfSMichael Neumann dpm_state = rdev->pm.dpm.user_state; 88557e252bfSMichael Neumann } 8864cd92098Szrj mutex_lock(&rdev->pm.mutex); 8874cd92098Szrj if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL) 8884cd92098Szrj rdev->pm.dpm.thermal_active = true; 8894cd92098Szrj else 8904cd92098Szrj rdev->pm.dpm.thermal_active = false; 8914cd92098Szrj rdev->pm.dpm.state = dpm_state; 8924cd92098Szrj mutex_unlock(&rdev->pm.mutex); 8934cd92098Szrj 8944cd92098Szrj radeon_pm_compute_clocks(rdev); 89557e252bfSMichael Neumann } 89657e252bfSMichael Neumann 8977dcf36dcSFrançois Tigeot static bool radeon_dpm_single_display(struct radeon_device *rdev) 89857e252bfSMichael Neumann { 89957e252bfSMichael Neumann bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ? 90057e252bfSMichael Neumann true : false; 90157e252bfSMichael Neumann 90257e252bfSMichael Neumann /* check if the vblank period is too short to adjust the mclk */ 90357e252bfSMichael Neumann if (single_display && rdev->asic->dpm.vblank_too_short) { 90457e252bfSMichael Neumann if (radeon_dpm_vblank_too_short(rdev)) 90557e252bfSMichael Neumann single_display = false; 90657e252bfSMichael Neumann } 90757e252bfSMichael Neumann 9087dcf36dcSFrançois Tigeot return single_display; 9097dcf36dcSFrançois Tigeot } 9107dcf36dcSFrançois Tigeot 9117dcf36dcSFrançois Tigeot static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, 9127dcf36dcSFrançois Tigeot enum radeon_pm_state_type dpm_state) 9137dcf36dcSFrançois Tigeot { 9147dcf36dcSFrançois Tigeot int i; 9157dcf36dcSFrançois Tigeot struct radeon_ps *ps; 9167dcf36dcSFrançois Tigeot u32 ui_class; 9177dcf36dcSFrançois Tigeot bool single_display = radeon_dpm_single_display(rdev); 9187dcf36dcSFrançois Tigeot 919*c59a5c48SFrançois Tigeot /* 120hz tends to be problematic even if they are under the 920*c59a5c48SFrançois Tigeot * vblank limit. 921*c59a5c48SFrançois Tigeot */ 922*c59a5c48SFrançois Tigeot if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120)) 923*c59a5c48SFrançois Tigeot single_display = false; 924*c59a5c48SFrançois Tigeot 92557e252bfSMichael Neumann /* certain older asics have a separare 3D performance state, 92657e252bfSMichael Neumann * so try that first if the user selected performance 92757e252bfSMichael Neumann */ 92857e252bfSMichael Neumann if (dpm_state == POWER_STATE_TYPE_PERFORMANCE) 92957e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; 93057e252bfSMichael Neumann /* balanced states don't exist at the moment */ 93157e252bfSMichael Neumann if (dpm_state == POWER_STATE_TYPE_BALANCED) 93257e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_PERFORMANCE; 93357e252bfSMichael Neumann 93457e252bfSMichael Neumann restart_search: 93557e252bfSMichael Neumann /* Pick the best power state based on current conditions */ 93657e252bfSMichael Neumann for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 93757e252bfSMichael Neumann ps = &rdev->pm.dpm.ps[i]; 93857e252bfSMichael Neumann ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK; 93957e252bfSMichael Neumann switch (dpm_state) { 94057e252bfSMichael Neumann /* user states */ 94157e252bfSMichael Neumann case POWER_STATE_TYPE_BATTERY: 94257e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) { 94357e252bfSMichael Neumann if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { 94457e252bfSMichael Neumann if (single_display) 94557e252bfSMichael Neumann return ps; 94657e252bfSMichael Neumann } else 94757e252bfSMichael Neumann return ps; 94857e252bfSMichael Neumann } 94957e252bfSMichael Neumann break; 95057e252bfSMichael Neumann case POWER_STATE_TYPE_BALANCED: 95157e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) { 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_PERFORMANCE: 96057e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { 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 /* internal states */ 96957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD: 9704cd92098Szrj if (rdev->pm.dpm.uvd_ps) 97157e252bfSMichael Neumann return rdev->pm.dpm.uvd_ps; 9724cd92098Szrj else 9734cd92098Szrj break; 97457e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_SD: 97557e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) 97657e252bfSMichael Neumann return ps; 97757e252bfSMichael Neumann break; 97857e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD: 97957e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) 98057e252bfSMichael Neumann return ps; 98157e252bfSMichael Neumann break; 98257e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD2: 98357e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) 98457e252bfSMichael Neumann return ps; 98557e252bfSMichael Neumann break; 98657e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_MVC: 98757e252bfSMichael Neumann if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) 98857e252bfSMichael Neumann return ps; 98957e252bfSMichael Neumann break; 99057e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_BOOT: 99157e252bfSMichael Neumann return rdev->pm.dpm.boot_ps; 99257e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_THERMAL: 99357e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) 99457e252bfSMichael Neumann return ps; 99557e252bfSMichael Neumann break; 99657e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ACPI: 99757e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) 99857e252bfSMichael Neumann return ps; 99957e252bfSMichael Neumann break; 100057e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ULV: 100157e252bfSMichael Neumann if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) 100257e252bfSMichael Neumann return ps; 100357e252bfSMichael Neumann break; 100457e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_3DPERF: 100557e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) 100657e252bfSMichael Neumann return ps; 100757e252bfSMichael Neumann break; 100857e252bfSMichael Neumann default: 100957e252bfSMichael Neumann break; 101057e252bfSMichael Neumann } 101157e252bfSMichael Neumann } 101257e252bfSMichael Neumann /* use a fallback state if we didn't match */ 101357e252bfSMichael Neumann switch (dpm_state) { 101457e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_SD: 10154cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; 10164cd92098Szrj goto restart_search; 101757e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD: 101857e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD2: 101957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_MVC: 10204cd92098Szrj if (rdev->pm.dpm.uvd_ps) { 102157e252bfSMichael Neumann return rdev->pm.dpm.uvd_ps; 10224cd92098Szrj } else { 10234cd92098Szrj dpm_state = POWER_STATE_TYPE_PERFORMANCE; 10244cd92098Szrj goto restart_search; 10254cd92098Szrj } 102657e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_THERMAL: 102757e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI; 102857e252bfSMichael Neumann goto restart_search; 102957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ACPI: 103057e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_BATTERY; 103157e252bfSMichael Neumann goto restart_search; 103257e252bfSMichael Neumann case POWER_STATE_TYPE_BATTERY: 103357e252bfSMichael Neumann case POWER_STATE_TYPE_BALANCED: 103457e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_3DPERF: 103557e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_PERFORMANCE; 103657e252bfSMichael Neumann goto restart_search; 103757e252bfSMichael Neumann default: 103857e252bfSMichael Neumann break; 103957e252bfSMichael Neumann } 104057e252bfSMichael Neumann 104157e252bfSMichael Neumann return NULL; 104257e252bfSMichael Neumann } 104357e252bfSMichael Neumann 104457e252bfSMichael Neumann static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev) 104557e252bfSMichael Neumann { 104657e252bfSMichael Neumann int i; 104757e252bfSMichael Neumann struct radeon_ps *ps; 104857e252bfSMichael Neumann enum radeon_pm_state_type dpm_state; 104957e252bfSMichael Neumann int ret; 10507dcf36dcSFrançois Tigeot bool single_display = radeon_dpm_single_display(rdev); 105157e252bfSMichael Neumann 105257e252bfSMichael Neumann /* if dpm init failed */ 105357e252bfSMichael Neumann if (!rdev->pm.dpm_enabled) 105457e252bfSMichael Neumann return; 105557e252bfSMichael Neumann 105657e252bfSMichael Neumann if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) { 105757e252bfSMichael Neumann /* add other state override checks here */ 105857e252bfSMichael Neumann if ((!rdev->pm.dpm.thermal_active) && 105957e252bfSMichael Neumann (!rdev->pm.dpm.uvd_active)) 106057e252bfSMichael Neumann rdev->pm.dpm.state = rdev->pm.dpm.user_state; 106157e252bfSMichael Neumann } 106257e252bfSMichael Neumann dpm_state = rdev->pm.dpm.state; 106357e252bfSMichael Neumann 106457e252bfSMichael Neumann ps = radeon_dpm_pick_power_state(rdev, dpm_state); 106557e252bfSMichael Neumann if (ps) 106657e252bfSMichael Neumann rdev->pm.dpm.requested_ps = ps; 106757e252bfSMichael Neumann else 106857e252bfSMichael Neumann return; 106957e252bfSMichael Neumann 107057e252bfSMichael Neumann /* no need to reprogram if nothing changed unless we are on BTC+ */ 107157e252bfSMichael Neumann if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) { 1072c6f73aabSFrançois Tigeot /* vce just modifies an existing state so force a change */ 1073c6f73aabSFrançois Tigeot if (ps->vce_active != rdev->pm.dpm.vce_active) 1074c6f73aabSFrançois Tigeot goto force; 10757dcf36dcSFrançois Tigeot /* user has made a display change (such as timing) */ 10767dcf36dcSFrançois Tigeot if (rdev->pm.dpm.single_display != single_display) 10777dcf36dcSFrançois Tigeot goto force; 107857e252bfSMichael Neumann if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) { 107957e252bfSMichael Neumann /* for pre-BTC and APUs if the num crtcs changed but state is the same, 108057e252bfSMichael Neumann * all we need to do is update the display configuration. 108157e252bfSMichael Neumann */ 108257e252bfSMichael Neumann if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) { 108357e252bfSMichael Neumann /* update display watermarks based on new power state */ 108457e252bfSMichael Neumann radeon_bandwidth_update(rdev); 108557e252bfSMichael Neumann /* update displays */ 108657e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev); 108757e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; 108857e252bfSMichael Neumann rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; 108957e252bfSMichael Neumann } 109057e252bfSMichael Neumann return; 109157e252bfSMichael Neumann } else { 109257e252bfSMichael Neumann /* for BTC+ if the num crtcs hasn't changed and state is the same, 109357e252bfSMichael Neumann * nothing to do, if the num crtcs is > 1 and state is the same, 109457e252bfSMichael Neumann * update display configuration. 109557e252bfSMichael Neumann */ 109657e252bfSMichael Neumann if (rdev->pm.dpm.new_active_crtcs == 109757e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs) { 109857e252bfSMichael Neumann return; 109957e252bfSMichael Neumann } else { 110057e252bfSMichael Neumann if ((rdev->pm.dpm.current_active_crtc_count > 1) && 110157e252bfSMichael Neumann (rdev->pm.dpm.new_active_crtc_count > 1)) { 110257e252bfSMichael Neumann /* update display watermarks based on new power state */ 110357e252bfSMichael Neumann radeon_bandwidth_update(rdev); 110457e252bfSMichael Neumann /* update displays */ 110557e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev); 110657e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; 110757e252bfSMichael Neumann rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; 110857e252bfSMichael Neumann return; 110957e252bfSMichael Neumann } 111057e252bfSMichael Neumann } 111157e252bfSMichael Neumann } 111257e252bfSMichael Neumann } 111357e252bfSMichael Neumann 1114c6f73aabSFrançois Tigeot force: 1115c6f73aabSFrançois Tigeot if (radeon_dpm == 1) { 111657e252bfSMichael Neumann printk("switching from power state:\n"); 111757e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps); 111857e252bfSMichael Neumann printk("switching to power state:\n"); 111957e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps); 1120c6f73aabSFrançois Tigeot } 112157e252bfSMichael Neumann 11221cfef1a5SFrançois Tigeot down_write(&rdev->pm.mclk_lock); 11231cfef1a5SFrançois Tigeot mutex_lock(&rdev->ring_lock); 112457e252bfSMichael Neumann 1125c6f73aabSFrançois Tigeot /* update whether vce is active */ 1126c6f73aabSFrançois Tigeot ps->vce_active = rdev->pm.dpm.vce_active; 1127c6f73aabSFrançois Tigeot 112857e252bfSMichael Neumann ret = radeon_dpm_pre_set_power_state(rdev); 112957e252bfSMichael Neumann if (ret) 113057e252bfSMichael Neumann goto done; 113157e252bfSMichael Neumann 113257e252bfSMichael Neumann /* update display watermarks based on new power state */ 113357e252bfSMichael Neumann radeon_bandwidth_update(rdev); 113457e252bfSMichael Neumann /* update displays */ 113557e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev); 113657e252bfSMichael Neumann 113757e252bfSMichael Neumann /* wait for the rings to drain */ 113857e252bfSMichael Neumann for (i = 0; i < RADEON_NUM_RINGS; i++) { 113957e252bfSMichael Neumann struct radeon_ring *ring = &rdev->ring[i]; 114057e252bfSMichael Neumann if (ring->ready) 1141c6f73aabSFrançois Tigeot radeon_fence_wait_empty(rdev, i); 114257e252bfSMichael Neumann } 114357e252bfSMichael Neumann 114457e252bfSMichael Neumann /* program the new power state */ 114557e252bfSMichael Neumann radeon_dpm_set_power_state(rdev); 114657e252bfSMichael Neumann 114757e252bfSMichael Neumann /* update current power state */ 114857e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps; 114957e252bfSMichael Neumann 115057e252bfSMichael Neumann radeon_dpm_post_set_power_state(rdev); 115157e252bfSMichael Neumann 1152*c59a5c48SFrançois Tigeot rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; 1153*c59a5c48SFrançois Tigeot rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; 1154*c59a5c48SFrançois Tigeot rdev->pm.dpm.single_display = single_display; 1155*c59a5c48SFrançois Tigeot 11564cd92098Szrj if (rdev->asic->dpm.force_performance_level) { 1157c6f73aabSFrançois Tigeot if (rdev->pm.dpm.thermal_active) { 1158c6f73aabSFrançois Tigeot enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; 11594cd92098Szrj /* force low perf level for thermal */ 11604cd92098Szrj radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_LOW); 1161c6f73aabSFrançois Tigeot /* save the user's level */ 1162c6f73aabSFrançois Tigeot rdev->pm.dpm.forced_level = level; 1163c6f73aabSFrançois Tigeot } else { 1164c6f73aabSFrançois Tigeot /* otherwise, user selected level */ 1165c6f73aabSFrançois Tigeot radeon_dpm_force_performance_level(rdev, rdev->pm.dpm.forced_level); 1166c6f73aabSFrançois Tigeot } 11674cd92098Szrj } 11684cd92098Szrj 116957e252bfSMichael Neumann done: 11701cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock); 11711cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock); 117257e252bfSMichael Neumann } 117357e252bfSMichael Neumann 11744cd92098Szrj void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable) 117557e252bfSMichael Neumann { 11764cd92098Szrj enum radeon_pm_state_type dpm_state; 117757e252bfSMichael Neumann 11784cd92098Szrj if (rdev->asic->dpm.powergate_uvd) { 11794cd92098Szrj mutex_lock(&rdev->pm.mutex); 1180c6f73aabSFrançois Tigeot /* don't powergate anything if we 1181c6f73aabSFrançois Tigeot have active but pause streams */ 1182c6f73aabSFrançois Tigeot enable |= rdev->pm.dpm.sd > 0; 1183c6f73aabSFrançois Tigeot enable |= rdev->pm.dpm.hd > 0; 11844cd92098Szrj /* enable/disable UVD */ 11854cd92098Szrj radeon_dpm_powergate_uvd(rdev, !enable); 11864cd92098Szrj mutex_unlock(&rdev->pm.mutex); 11874cd92098Szrj } else { 11884cd92098Szrj if (enable) { 11894cd92098Szrj mutex_lock(&rdev->pm.mutex); 119057e252bfSMichael Neumann rdev->pm.dpm.uvd_active = true; 11914cd92098Szrj /* disable this for now */ 11924cd92098Szrj #if 0 11934cd92098Szrj if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0)) 11944cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD; 11954cd92098Szrj else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0)) 11964cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; 11974cd92098Szrj else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 1)) 11984cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; 11994cd92098Szrj else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2)) 12004cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2; 12014cd92098Szrj else 12024cd92098Szrj #endif 12034cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD; 120457e252bfSMichael Neumann rdev->pm.dpm.state = dpm_state; 12054cd92098Szrj mutex_unlock(&rdev->pm.mutex); 12064cd92098Szrj } else { 12074cd92098Szrj mutex_lock(&rdev->pm.mutex); 12084cd92098Szrj rdev->pm.dpm.uvd_active = false; 12094cd92098Szrj mutex_unlock(&rdev->pm.mutex); 12104cd92098Szrj } 12114cd92098Szrj 121257e252bfSMichael Neumann radeon_pm_compute_clocks(rdev); 121357e252bfSMichael Neumann } 12144cd92098Szrj } 121557e252bfSMichael Neumann 1216c6f73aabSFrançois Tigeot void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable) 1217c6f73aabSFrançois Tigeot { 1218c6f73aabSFrançois Tigeot if (enable) { 1219c6f73aabSFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1220c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_active = true; 1221c6f73aabSFrançois Tigeot /* XXX select vce level based on ring/task */ 1222c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_level = RADEON_VCE_LEVEL_AC_ALL; 1223c6f73aabSFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1224c6f73aabSFrançois Tigeot } else { 1225c6f73aabSFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1226c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_active = false; 1227c6f73aabSFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1228c6f73aabSFrançois Tigeot } 1229c6f73aabSFrançois Tigeot 1230c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1231c6f73aabSFrançois Tigeot } 1232c6f73aabSFrançois Tigeot 123357e252bfSMichael Neumann static void radeon_pm_suspend_old(struct radeon_device *rdev) 1234926deccbSFrançois Tigeot { 12351cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1236926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM) { 1237926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) 1238926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED; 1239926deccbSFrançois Tigeot } 12401cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1241926deccbSFrançois Tigeot 1242ee479021SImre Vadász #ifdef DUMBBELL_WIP 1243926deccbSFrançois Tigeot cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); 1244ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1245926deccbSFrançois Tigeot } 1246926deccbSFrançois Tigeot 124757e252bfSMichael Neumann static void radeon_pm_suspend_dpm(struct radeon_device *rdev) 124857e252bfSMichael Neumann { 12491cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 125057e252bfSMichael Neumann /* disable dpm */ 125157e252bfSMichael Neumann radeon_dpm_disable(rdev); 125257e252bfSMichael Neumann /* reset the power state */ 125357e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; 125457e252bfSMichael Neumann rdev->pm.dpm_enabled = false; 12551cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 125657e252bfSMichael Neumann } 125757e252bfSMichael Neumann 125857e252bfSMichael Neumann void radeon_pm_suspend(struct radeon_device *rdev) 125957e252bfSMichael Neumann { 126057e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 126157e252bfSMichael Neumann radeon_pm_suspend_dpm(rdev); 126257e252bfSMichael Neumann else 126357e252bfSMichael Neumann radeon_pm_suspend_old(rdev); 126457e252bfSMichael Neumann } 126557e252bfSMichael Neumann 126657e252bfSMichael Neumann static void radeon_pm_resume_old(struct radeon_device *rdev) 1267926deccbSFrançois Tigeot { 1268926deccbSFrançois Tigeot /* set up the default clocks if the MC ucode is loaded */ 1269926deccbSFrançois Tigeot if ((rdev->family >= CHIP_BARTS) && 12704cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 1271926deccbSFrançois Tigeot rdev->mc_fw) { 1272926deccbSFrançois Tigeot if (rdev->pm.default_vddc) 1273926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 1274926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDC); 1275926deccbSFrançois Tigeot if (rdev->pm.default_vddci) 1276926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 1277926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDCI); 1278926deccbSFrançois Tigeot if (rdev->pm.default_sclk) 1279926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 1280926deccbSFrançois Tigeot if (rdev->pm.default_mclk) 1281926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 1282926deccbSFrançois Tigeot } 1283926deccbSFrançois Tigeot /* asic init will reset the default power state */ 12841cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1285926deccbSFrançois Tigeot rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; 1286926deccbSFrançois Tigeot rdev->pm.current_clock_mode_index = 0; 1287926deccbSFrançois Tigeot rdev->pm.current_sclk = rdev->pm.default_sclk; 1288926deccbSFrançois Tigeot rdev->pm.current_mclk = rdev->pm.default_mclk; 1289c6f73aabSFrançois Tigeot if (rdev->pm.power_state) { 1290926deccbSFrançois Tigeot rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; 1291926deccbSFrançois Tigeot rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; 1292c6f73aabSFrançois Tigeot } 1293926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM 1294926deccbSFrançois Tigeot && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { 1295926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; 1296ee479021SImre Vadász #ifdef DUMBBELL_WIP 1297926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1298926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1299ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1300926deccbSFrançois Tigeot } 13011cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1302926deccbSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1303926deccbSFrançois Tigeot } 1304926deccbSFrançois Tigeot 130557e252bfSMichael Neumann static void radeon_pm_resume_dpm(struct radeon_device *rdev) 1306926deccbSFrançois Tigeot { 1307926deccbSFrançois Tigeot int ret; 1308926deccbSFrançois Tigeot 130957e252bfSMichael Neumann /* asic init will reset to the boot state */ 13101cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 131157e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; 131257e252bfSMichael Neumann radeon_dpm_setup_asic(rdev); 131357e252bfSMichael Neumann ret = radeon_dpm_enable(rdev); 13141cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1315c6f73aabSFrançois Tigeot if (ret) 1316c6f73aabSFrançois Tigeot goto dpm_resume_fail; 1317c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = true; 1318c6f73aabSFrançois Tigeot return; 1319c6f73aabSFrançois Tigeot 1320c6f73aabSFrançois Tigeot dpm_resume_fail: 132157e252bfSMichael Neumann DRM_ERROR("radeon: dpm resume failed\n"); 132257e252bfSMichael Neumann if ((rdev->family >= CHIP_BARTS) && 13234cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 132457e252bfSMichael Neumann rdev->mc_fw) { 132557e252bfSMichael Neumann if (rdev->pm.default_vddc) 132657e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 132757e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC); 132857e252bfSMichael Neumann if (rdev->pm.default_vddci) 132957e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 133057e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDCI); 133157e252bfSMichael Neumann if (rdev->pm.default_sclk) 133257e252bfSMichael Neumann radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 133357e252bfSMichael Neumann if (rdev->pm.default_mclk) 133457e252bfSMichael Neumann radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 133557e252bfSMichael Neumann } 133657e252bfSMichael Neumann } 133757e252bfSMichael Neumann 133857e252bfSMichael Neumann void radeon_pm_resume(struct radeon_device *rdev) 133957e252bfSMichael Neumann { 134057e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 134157e252bfSMichael Neumann radeon_pm_resume_dpm(rdev); 134257e252bfSMichael Neumann else 134357e252bfSMichael Neumann radeon_pm_resume_old(rdev); 134457e252bfSMichael Neumann } 134557e252bfSMichael Neumann 134657e252bfSMichael Neumann static int radeon_pm_init_old(struct radeon_device *rdev) 134757e252bfSMichael Neumann { 134857e252bfSMichael Neumann int ret; 134957e252bfSMichael Neumann 1350926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT; 1351926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; 1352926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 1353926deccbSFrançois Tigeot rdev->pm.dynpm_can_upclock = true; 1354926deccbSFrançois Tigeot rdev->pm.dynpm_can_downclock = true; 1355926deccbSFrançois Tigeot rdev->pm.default_sclk = rdev->clock.default_sclk; 1356926deccbSFrançois Tigeot rdev->pm.default_mclk = rdev->clock.default_mclk; 1357926deccbSFrançois Tigeot rdev->pm.current_sclk = rdev->clock.default_sclk; 1358926deccbSFrançois Tigeot rdev->pm.current_mclk = rdev->clock.default_mclk; 1359926deccbSFrançois Tigeot rdev->pm.int_thermal_type = THERMAL_TYPE_NONE; 1360926deccbSFrançois Tigeot 1361926deccbSFrançois Tigeot if (rdev->bios) { 1362926deccbSFrançois Tigeot if (rdev->is_atom_bios) 1363926deccbSFrançois Tigeot radeon_atombios_get_power_modes(rdev); 1364926deccbSFrançois Tigeot else 1365926deccbSFrançois Tigeot radeon_combios_get_power_modes(rdev); 1366926deccbSFrançois Tigeot radeon_pm_print_states(rdev); 1367926deccbSFrançois Tigeot radeon_pm_init_profile(rdev); 1368926deccbSFrançois Tigeot /* set up the default clocks if the MC ucode is loaded */ 1369926deccbSFrançois Tigeot if ((rdev->family >= CHIP_BARTS) && 13704cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 1371926deccbSFrançois Tigeot rdev->mc_fw) { 1372926deccbSFrançois Tigeot if (rdev->pm.default_vddc) 1373926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 1374926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDC); 1375926deccbSFrançois Tigeot if (rdev->pm.default_vddci) 1376926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 1377926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDCI); 1378926deccbSFrançois Tigeot if (rdev->pm.default_sclk) 1379926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 1380926deccbSFrançois Tigeot if (rdev->pm.default_mclk) 1381926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 1382926deccbSFrançois Tigeot } 1383926deccbSFrançois Tigeot } 1384926deccbSFrançois Tigeot 1385926deccbSFrançois Tigeot /* set up the internal thermal sensor if applicable */ 1386926deccbSFrançois Tigeot ret = radeon_hwmon_init(rdev); 1387926deccbSFrançois Tigeot if (ret) 1388926deccbSFrançois Tigeot return ret; 1389926deccbSFrançois Tigeot 1390926deccbSFrançois Tigeot INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); 1391926deccbSFrançois Tigeot 1392926deccbSFrançois Tigeot if (rdev->pm.num_power_states > 1) { 1393926deccbSFrançois Tigeot if (radeon_debugfs_pm_init(rdev)) { 1394926deccbSFrançois Tigeot DRM_ERROR("Failed to register debugfs file for PM!\n"); 1395926deccbSFrançois Tigeot } 1396926deccbSFrançois Tigeot 1397926deccbSFrançois Tigeot DRM_INFO("radeon: power management initialized\n"); 1398926deccbSFrançois Tigeot } 1399926deccbSFrançois Tigeot 1400926deccbSFrançois Tigeot return 0; 1401926deccbSFrançois Tigeot } 1402926deccbSFrançois Tigeot 140357e252bfSMichael Neumann static void radeon_dpm_print_power_states(struct radeon_device *rdev) 140457e252bfSMichael Neumann { 140557e252bfSMichael Neumann int i; 140657e252bfSMichael Neumann 140757e252bfSMichael Neumann for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 140857e252bfSMichael Neumann printk("== power state %d ==\n", i); 140957e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, &rdev->pm.dpm.ps[i]); 141057e252bfSMichael Neumann } 141157e252bfSMichael Neumann } 141257e252bfSMichael Neumann 141357e252bfSMichael Neumann static int radeon_pm_init_dpm(struct radeon_device *rdev) 141457e252bfSMichael Neumann { 141557e252bfSMichael Neumann int ret; 141657e252bfSMichael Neumann 14174cd92098Szrj /* default to balanced state */ 141857e252bfSMichael Neumann rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED; 141957e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED; 14204cd92098Szrj rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; 142157e252bfSMichael Neumann rdev->pm.default_sclk = rdev->clock.default_sclk; 142257e252bfSMichael Neumann rdev->pm.default_mclk = rdev->clock.default_mclk; 142357e252bfSMichael Neumann rdev->pm.current_sclk = rdev->clock.default_sclk; 142457e252bfSMichael Neumann rdev->pm.current_mclk = rdev->clock.default_mclk; 142557e252bfSMichael Neumann rdev->pm.int_thermal_type = THERMAL_TYPE_NONE; 142657e252bfSMichael Neumann 142757e252bfSMichael Neumann if (rdev->bios && rdev->is_atom_bios) 142857e252bfSMichael Neumann radeon_atombios_get_power_modes(rdev); 142957e252bfSMichael Neumann else 143057e252bfSMichael Neumann return -EINVAL; 143157e252bfSMichael Neumann 143257e252bfSMichael Neumann /* set up the internal thermal sensor if applicable */ 143357e252bfSMichael Neumann ret = radeon_hwmon_init(rdev); 143457e252bfSMichael Neumann if (ret) 143557e252bfSMichael Neumann return ret; 143657e252bfSMichael Neumann 14372c5cc6b9SFrançois Tigeot INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler); 14382c5cc6b9SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 143957e252bfSMichael Neumann radeon_dpm_init(rdev); 144057e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; 1441c6f73aabSFrançois Tigeot if (radeon_dpm == 1) 144257e252bfSMichael Neumann radeon_dpm_print_power_states(rdev); 144357e252bfSMichael Neumann radeon_dpm_setup_asic(rdev); 144457e252bfSMichael Neumann ret = radeon_dpm_enable(rdev); 14452c5cc6b9SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1446c6f73aabSFrançois Tigeot if (ret) 1447c6f73aabSFrançois Tigeot goto dpm_failed; 1448c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = true; 1449c6f73aabSFrançois Tigeot 1450c6f73aabSFrançois Tigeot #ifdef TODO_DEVICE_FILE 1451c6f73aabSFrançois Tigeot if (radeon_debugfs_pm_init(rdev)) { 1452c6f73aabSFrançois Tigeot DRM_ERROR("Failed to register debugfs file for dpm!\n"); 1453c6f73aabSFrançois Tigeot } 1454c6f73aabSFrançois Tigeot #endif 1455c6f73aabSFrançois Tigeot 1456c6f73aabSFrançois Tigeot DRM_INFO("radeon: dpm initialized\n"); 1457c6f73aabSFrançois Tigeot 1458c6f73aabSFrançois Tigeot return 0; 1459c6f73aabSFrançois Tigeot 1460c6f73aabSFrançois Tigeot dpm_failed: 146157e252bfSMichael Neumann rdev->pm.dpm_enabled = false; 146257e252bfSMichael Neumann if ((rdev->family >= CHIP_BARTS) && 14634cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 146457e252bfSMichael Neumann rdev->mc_fw) { 146557e252bfSMichael Neumann if (rdev->pm.default_vddc) 146657e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 146757e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC); 146857e252bfSMichael Neumann if (rdev->pm.default_vddci) 146957e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 147057e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDCI); 147157e252bfSMichael Neumann if (rdev->pm.default_sclk) 147257e252bfSMichael Neumann radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 147357e252bfSMichael Neumann if (rdev->pm.default_mclk) 147457e252bfSMichael Neumann radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 147557e252bfSMichael Neumann } 147657e252bfSMichael Neumann DRM_ERROR("radeon: dpm initialization failed\n"); 147757e252bfSMichael Neumann return ret; 147857e252bfSMichael Neumann } 147957e252bfSMichael Neumann 14807dcf36dcSFrançois Tigeot struct radeon_dpm_quirk { 14817dcf36dcSFrançois Tigeot u32 chip_vendor; 14827dcf36dcSFrançois Tigeot u32 chip_device; 14837dcf36dcSFrançois Tigeot u32 subsys_vendor; 14847dcf36dcSFrançois Tigeot u32 subsys_device; 14857dcf36dcSFrançois Tigeot }; 14867dcf36dcSFrançois Tigeot 14877dcf36dcSFrançois Tigeot /* cards with dpm stability problems */ 14887dcf36dcSFrançois Tigeot static struct radeon_dpm_quirk radeon_dpm_quirk_list[] = { 14897dcf36dcSFrançois Tigeot /* TURKS - https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386534 */ 14907dcf36dcSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6759, 0x1682, 0x3195 }, 14917dcf36dcSFrançois Tigeot /* TURKS - https://bugzilla.kernel.org/show_bug.cgi?id=83731 */ 14927dcf36dcSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6840, 0x1179, 0xfb81 }, 14937dcf36dcSFrançois Tigeot { 0, 0, 0, 0 }, 14947dcf36dcSFrançois Tigeot }; 14957dcf36dcSFrançois Tigeot 149657e252bfSMichael Neumann int radeon_pm_init(struct radeon_device *rdev) 149757e252bfSMichael Neumann { 14987dcf36dcSFrançois Tigeot struct radeon_dpm_quirk *p = radeon_dpm_quirk_list; 14997dcf36dcSFrançois Tigeot bool disable_dpm = false; 15007dcf36dcSFrançois Tigeot 15017dcf36dcSFrançois Tigeot /* Apply dpm quirks */ 15027dcf36dcSFrançois Tigeot while (p && p->chip_device != 0) { 15037dcf36dcSFrançois Tigeot if (rdev->pdev->vendor == p->chip_vendor && 15047dcf36dcSFrançois Tigeot rdev->pdev->device == p->chip_device && 15057dcf36dcSFrançois Tigeot rdev->pdev->subsystem_vendor == p->subsys_vendor && 15067dcf36dcSFrançois Tigeot rdev->pdev->subsystem_device == p->subsys_device) { 15077dcf36dcSFrançois Tigeot disable_dpm = true; 15087dcf36dcSFrançois Tigeot break; 15097dcf36dcSFrançois Tigeot } 15107dcf36dcSFrançois Tigeot ++p; 15117dcf36dcSFrançois Tigeot } 15127dcf36dcSFrançois Tigeot 151357e252bfSMichael Neumann /* enable dpm on rv6xx+ */ 151457e252bfSMichael Neumann switch (rdev->family) { 151557e252bfSMichael Neumann case CHIP_RV610: 151657e252bfSMichael Neumann case CHIP_RV630: 151757e252bfSMichael Neumann case CHIP_RV620: 151857e252bfSMichael Neumann case CHIP_RV635: 151957e252bfSMichael Neumann case CHIP_RV670: 152057e252bfSMichael Neumann case CHIP_RS780: 152157e252bfSMichael Neumann case CHIP_RS880: 152257e252bfSMichael Neumann case CHIP_RV770: 1523c6f73aabSFrançois Tigeot /* DPM requires the RLC, RV770+ dGPU requires SMC */ 1524c6f73aabSFrançois Tigeot if (!rdev->rlc_fw) 1525c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 1526c6f73aabSFrançois Tigeot else if ((rdev->family >= CHIP_RV770) && 1527c6f73aabSFrançois Tigeot (!(rdev->flags & RADEON_IS_IGP)) && 1528c6f73aabSFrançois Tigeot (!rdev->smc_fw)) 1529c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 1530c6f73aabSFrançois Tigeot else if (radeon_dpm == 1) 1531c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DPM; 1532c6f73aabSFrançois Tigeot else 1533c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 1534c6f73aabSFrançois Tigeot break; 153557e252bfSMichael Neumann case CHIP_RV730: 153657e252bfSMichael Neumann case CHIP_RV710: 153757e252bfSMichael Neumann case CHIP_RV740: 153857e252bfSMichael Neumann case CHIP_CEDAR: 153957e252bfSMichael Neumann case CHIP_REDWOOD: 154057e252bfSMichael Neumann case CHIP_JUNIPER: 154157e252bfSMichael Neumann case CHIP_CYPRESS: 154257e252bfSMichael Neumann case CHIP_HEMLOCK: 154357e252bfSMichael Neumann case CHIP_PALM: 154457e252bfSMichael Neumann case CHIP_SUMO: 154557e252bfSMichael Neumann case CHIP_SUMO2: 154657e252bfSMichael Neumann case CHIP_BARTS: 154757e252bfSMichael Neumann case CHIP_TURKS: 154857e252bfSMichael Neumann case CHIP_CAICOS: 154957e252bfSMichael Neumann case CHIP_CAYMAN: 155057e252bfSMichael Neumann case CHIP_ARUBA: 155157e252bfSMichael Neumann case CHIP_TAHITI: 155257e252bfSMichael Neumann case CHIP_PITCAIRN: 155357e252bfSMichael Neumann case CHIP_VERDE: 155457e252bfSMichael Neumann case CHIP_OLAND: 155557e252bfSMichael Neumann case CHIP_HAINAN: 15564cd92098Szrj case CHIP_BONAIRE: 15574cd92098Szrj case CHIP_KABINI: 15584cd92098Szrj case CHIP_KAVERI: 1559c6f73aabSFrançois Tigeot case CHIP_HAWAII: 1560c6f73aabSFrançois Tigeot case CHIP_MULLINS: 156157e252bfSMichael Neumann /* DPM requires the RLC, RV770+ dGPU requires SMC */ 156257e252bfSMichael Neumann if (!rdev->rlc_fw) 156357e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 156457e252bfSMichael Neumann else if ((rdev->family >= CHIP_RV770) && 156557e252bfSMichael Neumann (!(rdev->flags & RADEON_IS_IGP)) && 156657e252bfSMichael Neumann (!rdev->smc_fw)) 156757e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 15687dcf36dcSFrançois Tigeot else if (disable_dpm && (radeon_dpm == -1)) 15697dcf36dcSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 1570c6f73aabSFrançois Tigeot else if (radeon_dpm == 0) 157157e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 1572c6f73aabSFrançois Tigeot else 1573c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DPM; 157457e252bfSMichael Neumann break; 157557e252bfSMichael Neumann default: 157657e252bfSMichael Neumann /* default to profile method */ 157757e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 157857e252bfSMichael Neumann break; 157957e252bfSMichael Neumann } 158057e252bfSMichael Neumann 158157e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 158257e252bfSMichael Neumann return radeon_pm_init_dpm(rdev); 158357e252bfSMichael Neumann else 158457e252bfSMichael Neumann return radeon_pm_init_old(rdev); 158557e252bfSMichael Neumann } 158657e252bfSMichael Neumann 1587c6f73aabSFrançois Tigeot int radeon_pm_late_init(struct radeon_device *rdev) 1588c6f73aabSFrançois Tigeot { 1589c6f73aabSFrançois Tigeot int ret = 0; 1590c6f73aabSFrançois Tigeot 1591c6f73aabSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DPM) { 1592*c59a5c48SFrançois Tigeot if (rdev->pm.dpm_enabled) { 1593*c59a5c48SFrançois Tigeot if (!rdev->pm.sysfs_initialized) { 1594*c59a5c48SFrançois Tigeot #if 0 1595*c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); 1596*c59a5c48SFrançois Tigeot if (ret) 1597*c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for dpm state\n"); 1598*c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); 1599*c59a5c48SFrançois Tigeot if (ret) 1600*c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for dpm state\n"); 1601*c59a5c48SFrançois Tigeot /* XXX: these are noops for dpm but are here for backwards compat */ 1602*c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_profile); 1603*c59a5c48SFrançois Tigeot if (ret) 1604*c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power profile\n"); 1605*c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_method); 1606*c59a5c48SFrançois Tigeot if (ret) 1607*c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power method\n"); 1608*c59a5c48SFrançois Tigeot #endif 1609*c59a5c48SFrançois Tigeot rdev->pm.sysfs_initialized = true; 1610*c59a5c48SFrançois Tigeot } 1611*c59a5c48SFrançois Tigeot 16121cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1613c6f73aabSFrançois Tigeot ret = radeon_dpm_late_enable(rdev); 16141cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1615*c59a5c48SFrançois Tigeot if (ret) { 1616*c59a5c48SFrançois Tigeot rdev->pm.dpm_enabled = false; 1617*c59a5c48SFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 1618*c59a5c48SFrançois Tigeot } else { 1619*c59a5c48SFrançois Tigeot /* set the dpm state for PX since there won't be 1620*c59a5c48SFrançois Tigeot * a modeset to call this. 1621*c59a5c48SFrançois Tigeot */ 1622*c59a5c48SFrançois Tigeot radeon_pm_compute_clocks(rdev); 1623*c59a5c48SFrançois Tigeot } 1624*c59a5c48SFrançois Tigeot } 1625*c59a5c48SFrançois Tigeot } else { 1626*c59a5c48SFrançois Tigeot if ((rdev->pm.num_power_states > 1) && 1627*c59a5c48SFrançois Tigeot (!rdev->pm.sysfs_initialized)) { 1628*c59a5c48SFrançois Tigeot /* where's the best place to put these? */ 1629*c59a5c48SFrançois Tigeot #if 0 1630*c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_profile); 1631*c59a5c48SFrançois Tigeot if (ret) 1632*c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power profile\n"); 1633*c59a5c48SFrançois Tigeot ret = device_create_file(rdev->dev, &dev_attr_power_method); 1634*c59a5c48SFrançois Tigeot if (ret) 1635*c59a5c48SFrançois Tigeot DRM_ERROR("failed to create device file for power method\n"); 1636*c59a5c48SFrançois Tigeot if (!ret) 1637*c59a5c48SFrançois Tigeot rdev->pm.sysfs_initialized = true; 1638*c59a5c48SFrançois Tigeot #endif 1639*c59a5c48SFrançois Tigeot } 1640c6f73aabSFrançois Tigeot } 1641c6f73aabSFrançois Tigeot return ret; 1642c6f73aabSFrançois Tigeot } 1643c6f73aabSFrançois Tigeot 164457e252bfSMichael Neumann static void radeon_pm_fini_old(struct radeon_device *rdev) 1645926deccbSFrançois Tigeot { 1646926deccbSFrançois Tigeot if (rdev->pm.num_power_states > 1) { 16471cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1648926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) { 1649926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT; 1650926deccbSFrançois Tigeot radeon_pm_update_profile(rdev); 1651926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1652926deccbSFrançois Tigeot } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { 1653926deccbSFrançois Tigeot /* reset default clocks */ 1654926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; 1655926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; 1656926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1657926deccbSFrançois Tigeot } 16581cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1659926deccbSFrançois Tigeot 1660926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1661ee479021SImre Vadász cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); 1662ee479021SImre Vadász 1663926deccbSFrançois Tigeot device_remove_file(rdev->dev, &dev_attr_power_profile); 1664926deccbSFrançois Tigeot device_remove_file(rdev->dev, &dev_attr_power_method); 1665926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1666926deccbSFrançois Tigeot } 1667926deccbSFrançois Tigeot 1668926deccbSFrançois Tigeot if (rdev->pm.power_state) { 1669926deccbSFrançois Tigeot int i; 1670926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; ++i) { 1671c4ef309bSzrj kfree(rdev->pm.power_state[i].clock_info); 1672926deccbSFrançois Tigeot } 1673c4ef309bSzrj kfree(rdev->pm.power_state); 1674926deccbSFrançois Tigeot rdev->pm.power_state = NULL; 1675926deccbSFrançois Tigeot rdev->pm.num_power_states = 0; 1676926deccbSFrançois Tigeot } 1677926deccbSFrançois Tigeot 1678926deccbSFrançois Tigeot radeon_hwmon_fini(rdev); 1679926deccbSFrançois Tigeot } 1680926deccbSFrançois Tigeot 168157e252bfSMichael Neumann static void radeon_pm_fini_dpm(struct radeon_device *rdev) 168257e252bfSMichael Neumann { 168357e252bfSMichael Neumann if (rdev->pm.num_power_states > 1) { 16841cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 168557e252bfSMichael Neumann radeon_dpm_disable(rdev); 16861cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 168757e252bfSMichael Neumann 168857e252bfSMichael Neumann #ifdef TODO_DEVICE_FILE 168957e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_dpm_state); 169057e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); 169157e252bfSMichael Neumann /* XXX backwards compat */ 169257e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_profile); 169357e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_method); 169457e252bfSMichael Neumann #endif 169557e252bfSMichael Neumann } 169657e252bfSMichael Neumann radeon_dpm_fini(rdev); 169757e252bfSMichael Neumann 16985d6a9071Szrj /* prevents leaking 440 bytes on OLAND */ 16995d6a9071Szrj if (rdev->pm.power_state) { 17005d6a9071Szrj int i; 17015d6a9071Szrj for (i = 0; i < rdev->pm.num_power_states; ++i) { 17025d6a9071Szrj kfree(rdev->pm.power_state[i].clock_info); 17035d6a9071Szrj } 170457e252bfSMichael Neumann kfree(rdev->pm.power_state); 17055d6a9071Szrj rdev->pm.power_state = NULL; 17065d6a9071Szrj rdev->pm.num_power_states = 0; 17075d6a9071Szrj } 170857e252bfSMichael Neumann 170957e252bfSMichael Neumann radeon_hwmon_fini(rdev); 171057e252bfSMichael Neumann } 171157e252bfSMichael Neumann 171257e252bfSMichael Neumann void radeon_pm_fini(struct radeon_device *rdev) 171357e252bfSMichael Neumann { 171457e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 171557e252bfSMichael Neumann radeon_pm_fini_dpm(rdev); 171657e252bfSMichael Neumann else 171757e252bfSMichael Neumann radeon_pm_fini_old(rdev); 171857e252bfSMichael Neumann } 171957e252bfSMichael Neumann 172057e252bfSMichael Neumann static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) 1721926deccbSFrançois Tigeot { 1722926deccbSFrançois Tigeot struct drm_device *ddev = rdev->ddev; 1723926deccbSFrançois Tigeot struct drm_crtc *crtc; 1724926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc; 1725926deccbSFrançois Tigeot 1726926deccbSFrançois Tigeot if (rdev->pm.num_power_states < 2) 1727926deccbSFrançois Tigeot return; 1728926deccbSFrançois Tigeot 17291cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1730926deccbSFrançois Tigeot 1731926deccbSFrançois Tigeot rdev->pm.active_crtcs = 0; 1732926deccbSFrançois Tigeot rdev->pm.active_crtc_count = 0; 1733c6f73aabSFrançois Tigeot if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { 1734926deccbSFrançois Tigeot list_for_each_entry(crtc, 1735926deccbSFrançois Tigeot &ddev->mode_config.crtc_list, head) { 1736926deccbSFrançois Tigeot radeon_crtc = to_radeon_crtc(crtc); 1737926deccbSFrançois Tigeot if (radeon_crtc->enabled) { 1738926deccbSFrançois Tigeot rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); 1739926deccbSFrançois Tigeot rdev->pm.active_crtc_count++; 1740926deccbSFrançois Tigeot } 1741926deccbSFrançois Tigeot } 1742c6f73aabSFrançois Tigeot } 1743926deccbSFrançois Tigeot 1744926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) { 1745926deccbSFrançois Tigeot radeon_pm_update_profile(rdev); 1746926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1747926deccbSFrançois Tigeot } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { 1748926deccbSFrançois Tigeot if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) { 1749926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) { 1750926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { 1751ee479021SImre Vadász #ifdef DUMBBELL_WIP 1752926deccbSFrançois Tigeot cancel_delayed_work(&rdev->pm.dynpm_idle_work); 1753ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1754926deccbSFrançois Tigeot 1755926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; 1756926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; 1757926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1758926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1759926deccbSFrançois Tigeot 1760926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("radeon: dynamic power management deactivated\n"); 1761926deccbSFrançois Tigeot } 1762926deccbSFrançois Tigeot } else if (rdev->pm.active_crtc_count == 1) { 1763926deccbSFrançois Tigeot /* TODO: Increase clocks if needed for current mode */ 1764926deccbSFrançois Tigeot 1765926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_MINIMUM) { 1766926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; 1767926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_UPCLOCK; 1768926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1769926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1770926deccbSFrançois Tigeot 1771ee479021SImre Vadász #ifdef DUMBBELL_WIP 1772926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1773926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1774ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1775926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) { 1776926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; 1777ee479021SImre Vadász #ifdef DUMBBELL_WIP 1778926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1779926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1780ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1781926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n"); 1782926deccbSFrançois Tigeot } 1783926deccbSFrançois Tigeot } else { /* count == 0 */ 1784926deccbSFrançois Tigeot if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) { 1785ee479021SImre Vadász #ifdef DUMBBELL_WIP 1786926deccbSFrançois Tigeot cancel_delayed_work(&rdev->pm.dynpm_idle_work); 1787ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1788926deccbSFrançois Tigeot 1789926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM; 1790926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM; 1791926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1792926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1793926deccbSFrançois Tigeot } 1794926deccbSFrançois Tigeot } 1795926deccbSFrançois Tigeot } 1796926deccbSFrançois Tigeot } 1797926deccbSFrançois Tigeot 17981cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1799926deccbSFrançois Tigeot } 1800926deccbSFrançois Tigeot 180157e252bfSMichael Neumann static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) 180257e252bfSMichael Neumann { 180357e252bfSMichael Neumann struct drm_device *ddev = rdev->ddev; 180457e252bfSMichael Neumann struct drm_crtc *crtc; 180557e252bfSMichael Neumann struct radeon_crtc *radeon_crtc; 180657e252bfSMichael Neumann 1807c6f73aabSFrançois Tigeot if (!rdev->pm.dpm_enabled) 1808c6f73aabSFrançois Tigeot return; 1809c6f73aabSFrançois Tigeot 18101cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 181157e252bfSMichael Neumann 181257e252bfSMichael Neumann /* update active crtc counts */ 181357e252bfSMichael Neumann rdev->pm.dpm.new_active_crtcs = 0; 181457e252bfSMichael Neumann rdev->pm.dpm.new_active_crtc_count = 0; 1815c6f73aabSFrançois Tigeot if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { 181657e252bfSMichael Neumann list_for_each_entry(crtc, 181757e252bfSMichael Neumann &ddev->mode_config.crtc_list, head) { 181857e252bfSMichael Neumann radeon_crtc = to_radeon_crtc(crtc); 181957e252bfSMichael Neumann if (crtc->enabled) { 182057e252bfSMichael Neumann rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); 182157e252bfSMichael Neumann rdev->pm.dpm.new_active_crtc_count++; 182257e252bfSMichael Neumann } 182357e252bfSMichael Neumann } 1824c6f73aabSFrançois Tigeot } 182557e252bfSMichael Neumann 182657e252bfSMichael Neumann /* update battery/ac status */ 182757e252bfSMichael Neumann if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) 182857e252bfSMichael Neumann rdev->pm.dpm.ac_power = true; 182957e252bfSMichael Neumann else 183057e252bfSMichael Neumann rdev->pm.dpm.ac_power = false; 183157e252bfSMichael Neumann 183257e252bfSMichael Neumann radeon_dpm_change_power_state_locked(rdev); 183357e252bfSMichael Neumann 18341cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1835c6f73aabSFrançois Tigeot 183657e252bfSMichael Neumann } 183757e252bfSMichael Neumann 183857e252bfSMichael Neumann void radeon_pm_compute_clocks(struct radeon_device *rdev) 183957e252bfSMichael Neumann { 184057e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 184157e252bfSMichael Neumann radeon_pm_compute_clocks_dpm(rdev); 184257e252bfSMichael Neumann else 184357e252bfSMichael Neumann radeon_pm_compute_clocks_old(rdev); 184457e252bfSMichael Neumann } 184557e252bfSMichael Neumann 1846926deccbSFrançois Tigeot static bool radeon_pm_in_vbl(struct radeon_device *rdev) 1847926deccbSFrançois Tigeot { 1848926deccbSFrançois Tigeot int crtc, vpos, hpos, vbl_status; 1849926deccbSFrançois Tigeot bool in_vbl = true; 1850926deccbSFrançois Tigeot 1851926deccbSFrançois Tigeot /* Iterate over all active crtc's. All crtc's must be in vblank, 1852926deccbSFrançois Tigeot * otherwise return in_vbl == false. 1853926deccbSFrançois Tigeot */ 1854926deccbSFrançois Tigeot for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { 1855926deccbSFrançois Tigeot if (rdev->pm.active_crtcs & (1 << crtc)) { 1856*c59a5c48SFrançois Tigeot vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, 1857*c59a5c48SFrançois Tigeot crtc, 1858*c59a5c48SFrançois Tigeot USE_REAL_VBLANKSTART, 1859352ff8bdSFrançois Tigeot &vpos, &hpos, NULL, NULL, 1860352ff8bdSFrançois Tigeot &rdev->mode_info.crtcs[crtc]->base.hwmode); 1861926deccbSFrançois Tigeot if ((vbl_status & DRM_SCANOUTPOS_VALID) && 18621b13d190SFrançois Tigeot !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK)) 1863926deccbSFrançois Tigeot in_vbl = false; 1864926deccbSFrançois Tigeot } 1865926deccbSFrançois Tigeot } 1866926deccbSFrançois Tigeot 1867926deccbSFrançois Tigeot return in_vbl; 1868926deccbSFrançois Tigeot } 1869926deccbSFrançois Tigeot 1870926deccbSFrançois Tigeot static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) 1871926deccbSFrançois Tigeot { 1872926deccbSFrançois Tigeot u32 stat_crtc = 0; 1873926deccbSFrançois Tigeot bool in_vbl = radeon_pm_in_vbl(rdev); 1874926deccbSFrançois Tigeot 1875926deccbSFrançois Tigeot if (in_vbl == false) 1876926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("not in vbl for pm change %08x at %s\n", stat_crtc, 1877926deccbSFrançois Tigeot finish ? "exit" : "entry"); 1878926deccbSFrançois Tigeot return in_vbl; 1879926deccbSFrançois Tigeot } 1880926deccbSFrançois Tigeot 1881926deccbSFrançois Tigeot static void radeon_dynpm_idle_work_handler(struct work_struct *work) 1882926deccbSFrançois Tigeot { 1883926deccbSFrançois Tigeot struct radeon_device *rdev; 1884926deccbSFrançois Tigeot int resched; 1885926deccbSFrançois Tigeot rdev = container_of(work, struct radeon_device, 1886926deccbSFrançois Tigeot pm.dynpm_idle_work.work); 1887926deccbSFrançois Tigeot 1888926deccbSFrançois Tigeot resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); 18891cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1890926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { 1891926deccbSFrançois Tigeot int not_processed = 0; 1892926deccbSFrançois Tigeot int i; 1893926deccbSFrançois Tigeot 1894926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1895926deccbSFrançois Tigeot struct radeon_ring *ring = &rdev->ring[i]; 1896926deccbSFrançois Tigeot 1897926deccbSFrançois Tigeot if (ring->ready) { 1898926deccbSFrançois Tigeot not_processed += radeon_fence_count_emitted(rdev, i); 1899926deccbSFrançois Tigeot if (not_processed >= 3) 1900926deccbSFrançois Tigeot break; 1901926deccbSFrançois Tigeot } 1902926deccbSFrançois Tigeot } 1903926deccbSFrançois Tigeot 1904926deccbSFrançois Tigeot if (not_processed >= 3) { /* should upclock */ 1905926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_DOWNCLOCK) { 1906926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 1907926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE && 1908926deccbSFrançois Tigeot rdev->pm.dynpm_can_upclock) { 1909926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = 1910926deccbSFrançois Tigeot DYNPM_ACTION_UPCLOCK; 1911926deccbSFrançois Tigeot rdev->pm.dynpm_action_timeout = jiffies + 1912926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); 1913926deccbSFrançois Tigeot } 1914926deccbSFrançois Tigeot } else if (not_processed == 0) { /* should downclock */ 1915926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_UPCLOCK) { 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_downclock) { 1919926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = 1920926deccbSFrançois Tigeot DYNPM_ACTION_DOWNCLOCK; 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 } 1925926deccbSFrançois Tigeot 1926926deccbSFrançois Tigeot /* Note, radeon_pm_set_clocks is called with static_switch set 1927926deccbSFrançois Tigeot * to false since we want to wait for vbl to avoid flicker. 1928926deccbSFrançois Tigeot */ 1929926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action != DYNPM_ACTION_NONE && 1930926deccbSFrançois Tigeot jiffies > rdev->pm.dynpm_action_timeout) { 1931926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1932926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1933926deccbSFrançois Tigeot } 1934926deccbSFrançois Tigeot 1935926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1936926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1937926deccbSFrançois Tigeot } 19381cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1939926deccbSFrançois Tigeot ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); 1940926deccbSFrançois Tigeot } 1941926deccbSFrançois Tigeot 1942926deccbSFrançois Tigeot /* 1943926deccbSFrançois Tigeot * Debugfs info 1944926deccbSFrançois Tigeot */ 1945926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1946926deccbSFrançois Tigeot 1947926deccbSFrançois Tigeot static int radeon_debugfs_pm_info(struct seq_file *m, void *data) 1948926deccbSFrançois Tigeot { 1949926deccbSFrançois Tigeot struct drm_info_node *node = (struct drm_info_node *) m->private; 1950926deccbSFrançois Tigeot struct drm_device *dev = node->minor->dev; 1951926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1952c6f73aabSFrançois Tigeot struct drm_device *ddev = rdev->ddev; 1953926deccbSFrançois Tigeot 1954c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 1955c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { 1956c6f73aabSFrançois Tigeot seq_printf(m, "PX asic powered off\n"); 1957c6f73aabSFrançois Tigeot } else if (rdev->pm.dpm_enabled) { 19581cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 195957e252bfSMichael Neumann if (rdev->asic->dpm.debugfs_print_current_performance_level) 196057e252bfSMichael Neumann radeon_dpm_debugfs_print_current_performance_level(rdev, m); 196157e252bfSMichael Neumann else 196257e252bfSMichael Neumann seq_printf(m, "Debugfs support not implemented for this asic\n"); 19631cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 196457e252bfSMichael Neumann } else { 1965926deccbSFrançois Tigeot seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk); 1966f43cf1b1SMichael Neumann /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */ 1967f43cf1b1SMichael Neumann if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP)) 1968f43cf1b1SMichael Neumann seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk); 1969f43cf1b1SMichael Neumann else 1970926deccbSFrançois Tigeot seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); 1971926deccbSFrançois Tigeot seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk); 1972926deccbSFrançois Tigeot if (rdev->asic->pm.get_memory_clock) 1973926deccbSFrançois Tigeot seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); 1974926deccbSFrançois Tigeot if (rdev->pm.current_vddc) 1975926deccbSFrançois Tigeot seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc); 1976926deccbSFrançois Tigeot if (rdev->asic->pm.get_pcie_lanes) 1977926deccbSFrançois Tigeot seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev)); 197857e252bfSMichael Neumann } 1979926deccbSFrançois Tigeot 1980926deccbSFrançois Tigeot return 0; 1981926deccbSFrançois Tigeot } 1982926deccbSFrançois Tigeot 1983926deccbSFrançois Tigeot static struct drm_info_list radeon_pm_info_list[] = { 1984926deccbSFrançois Tigeot {"radeon_pm_info", radeon_debugfs_pm_info, 0, NULL}, 1985926deccbSFrançois Tigeot }; 1986926deccbSFrançois Tigeot #endif 1987926deccbSFrançois Tigeot 1988926deccbSFrançois Tigeot static int radeon_debugfs_pm_init(struct radeon_device *rdev) 1989926deccbSFrançois Tigeot { 1990926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1991926deccbSFrançois Tigeot return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list)); 1992926deccbSFrançois Tigeot #else 1993926deccbSFrançois Tigeot return 0; 1994926deccbSFrançois Tigeot #endif 1995926deccbSFrançois Tigeot } 1996