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*1cfef1a5SFrançois Tigeot #include <linux/power_supply.h> 28*1cfef1a5SFrançois Tigeot #include <linux/hwmon.h> 29*1cfef1a5SFrançois Tigeot 30*1cfef1a5SFrançois Tigeot #include <sys/power.h> 31*1cfef1a5SFrançois Tigeot #include <sys/sensors.h> 32926deccbSFrançois Tigeot 33926deccbSFrançois Tigeot #define RADEON_IDLE_LOOP_MS 100 34926deccbSFrançois Tigeot #define RADEON_RECLOCK_DELAY_MS 200 35926deccbSFrançois Tigeot #define RADEON_WAIT_VBLANK_TIMEOUT 200 36926deccbSFrançois Tigeot 37926deccbSFrançois Tigeot static const char *radeon_pm_state_type_name[5] = { 38926deccbSFrançois Tigeot "", 39926deccbSFrançois Tigeot "Powersave", 40926deccbSFrançois Tigeot "Battery", 41926deccbSFrançois Tigeot "Balanced", 42926deccbSFrançois Tigeot "Performance", 43926deccbSFrançois Tigeot }; 44926deccbSFrançois Tigeot 45ee479021SImre Vadász #ifdef DUMBBELL_WIP 46926deccbSFrançois Tigeot static void radeon_dynpm_idle_work_handler(struct work_struct *work); 47ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 48926deccbSFrançois Tigeot static int radeon_debugfs_pm_init(struct radeon_device *rdev); 49926deccbSFrançois Tigeot static bool radeon_pm_in_vbl(struct radeon_device *rdev); 50926deccbSFrançois Tigeot static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); 51926deccbSFrançois Tigeot static void radeon_pm_update_profile(struct radeon_device *rdev); 52926deccbSFrançois Tigeot static void radeon_pm_set_clocks(struct radeon_device *rdev); 53926deccbSFrançois Tigeot 54926deccbSFrançois Tigeot int radeon_pm_get_type_index(struct radeon_device *rdev, 55926deccbSFrançois Tigeot enum radeon_pm_state_type ps_type, 56926deccbSFrançois Tigeot int instance) 57926deccbSFrançois Tigeot { 58926deccbSFrançois Tigeot int i; 59926deccbSFrançois Tigeot int found_instance = -1; 60926deccbSFrançois Tigeot 61926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; i++) { 62926deccbSFrançois Tigeot if (rdev->pm.power_state[i].type == ps_type) { 63926deccbSFrançois Tigeot found_instance++; 64926deccbSFrançois Tigeot if (found_instance == instance) 65926deccbSFrançois Tigeot return i; 66926deccbSFrançois Tigeot } 67926deccbSFrançois Tigeot } 68926deccbSFrançois Tigeot /* return default if no match */ 69926deccbSFrançois Tigeot return rdev->pm.default_power_state_index; 70926deccbSFrançois Tigeot } 71926deccbSFrançois Tigeot 72926deccbSFrançois Tigeot void radeon_pm_acpi_event_handler(struct radeon_device *rdev) 73926deccbSFrançois Tigeot { 744cd92098Szrj if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 75*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 76c6f73aabSFrançois Tigeot if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) 774cd92098Szrj rdev->pm.dpm.ac_power = true; 784cd92098Szrj else 794cd92098Szrj rdev->pm.dpm.ac_power = false; 80c6f73aabSFrançois Tigeot if (rdev->family == CHIP_ARUBA) { 814cd92098Szrj if (rdev->asic->dpm.enable_bapm) 824cd92098Szrj radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power); 83c6f73aabSFrançois Tigeot } 84*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 854cd92098Szrj } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) { 86926deccbSFrançois Tigeot if (rdev->pm.profile == PM_PROFILE_AUTO) { 87*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 88926deccbSFrançois Tigeot radeon_pm_update_profile(rdev); 89926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 90*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 91926deccbSFrançois Tigeot } 92926deccbSFrançois Tigeot } 93926deccbSFrançois Tigeot } 94926deccbSFrançois Tigeot 95926deccbSFrançois Tigeot static void radeon_pm_update_profile(struct radeon_device *rdev) 96926deccbSFrançois Tigeot { 97926deccbSFrançois Tigeot switch (rdev->pm.profile) { 98926deccbSFrançois Tigeot case PM_PROFILE_DEFAULT: 99926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_DEFAULT_IDX; 100926deccbSFrançois Tigeot break; 101926deccbSFrançois Tigeot case PM_PROFILE_AUTO: 10257e252bfSMichael Neumann if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) { 103926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) 104926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; 105926deccbSFrançois Tigeot else 106926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX; 107926deccbSFrançois Tigeot } else { 108926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) 109926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_MH_IDX; 110926deccbSFrançois Tigeot else 111926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_SH_IDX; 112926deccbSFrançois Tigeot } 113926deccbSFrançois Tigeot break; 114926deccbSFrançois Tigeot case PM_PROFILE_LOW: 115926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) 116926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX; 117926deccbSFrançois Tigeot else 118926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX; 119926deccbSFrançois Tigeot break; 120926deccbSFrançois Tigeot case PM_PROFILE_MID: 121926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) 122926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_MH_IDX; 123926deccbSFrançois Tigeot else 124926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_MID_SH_IDX; 125926deccbSFrançois Tigeot break; 126926deccbSFrançois Tigeot case PM_PROFILE_HIGH: 127926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) 128926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; 129926deccbSFrançois Tigeot else 130926deccbSFrançois Tigeot rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX; 131926deccbSFrançois Tigeot break; 132926deccbSFrançois Tigeot } 133926deccbSFrançois Tigeot 134926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count == 0) { 135926deccbSFrançois Tigeot rdev->pm.requested_power_state_index = 136926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_off_ps_idx; 137926deccbSFrançois Tigeot rdev->pm.requested_clock_mode_index = 138926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_off_cm_idx; 139926deccbSFrançois Tigeot } else { 140926deccbSFrançois Tigeot rdev->pm.requested_power_state_index = 141926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_on_ps_idx; 142926deccbSFrançois Tigeot rdev->pm.requested_clock_mode_index = 143926deccbSFrançois Tigeot rdev->pm.profiles[rdev->pm.profile_index].dpms_on_cm_idx; 144926deccbSFrançois Tigeot } 145926deccbSFrançois Tigeot } 146926deccbSFrançois Tigeot 147926deccbSFrançois Tigeot static void radeon_unmap_vram_bos(struct radeon_device *rdev) 148926deccbSFrançois Tigeot { 149926deccbSFrançois Tigeot struct radeon_bo *bo, *n; 150926deccbSFrançois Tigeot 151926deccbSFrançois Tigeot if (list_empty(&rdev->gem.objects)) 152926deccbSFrançois Tigeot return; 153926deccbSFrançois Tigeot 154926deccbSFrançois Tigeot list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) { 155926deccbSFrançois Tigeot if (bo->tbo.mem.mem_type == TTM_PL_VRAM) 156926deccbSFrançois Tigeot ttm_bo_unmap_virtual(&bo->tbo); 157926deccbSFrançois Tigeot } 158926deccbSFrançois Tigeot } 159926deccbSFrançois Tigeot 160926deccbSFrançois Tigeot static void radeon_sync_with_vblank(struct radeon_device *rdev) 161926deccbSFrançois Tigeot { 162926deccbSFrançois Tigeot if (rdev->pm.active_crtcs) { 163926deccbSFrançois Tigeot rdev->pm.vblank_sync = false; 164ee479021SImre Vadász #ifdef DUMBBELL_WIP 165926deccbSFrançois Tigeot wait_event_timeout( 166926deccbSFrançois Tigeot rdev->irq.vblank_queue, rdev->pm.vblank_sync, 167926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); 168ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 169926deccbSFrançois Tigeot } 170926deccbSFrançois Tigeot } 171926deccbSFrançois Tigeot 172926deccbSFrançois Tigeot static void radeon_set_power_state(struct radeon_device *rdev) 173926deccbSFrançois Tigeot { 174926deccbSFrançois Tigeot u32 sclk, mclk; 175926deccbSFrançois Tigeot bool misc_after = false; 176926deccbSFrançois Tigeot 177926deccbSFrançois Tigeot if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && 178926deccbSFrançois Tigeot (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) 179926deccbSFrançois Tigeot return; 180926deccbSFrançois Tigeot 181926deccbSFrançois Tigeot if (radeon_gui_idle(rdev)) { 182926deccbSFrançois Tigeot sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. 183926deccbSFrançois Tigeot clock_info[rdev->pm.requested_clock_mode_index].sclk; 184926deccbSFrançois Tigeot if (sclk > rdev->pm.default_sclk) 185926deccbSFrançois Tigeot sclk = rdev->pm.default_sclk; 186926deccbSFrançois Tigeot 187926deccbSFrançois Tigeot /* starting with BTC, there is one state that is used for both 188926deccbSFrançois Tigeot * MH and SH. Difference is that we always use the high clock index for 189b403bed8SMichael Neumann * mclk and vddci. 190926deccbSFrançois Tigeot */ 191926deccbSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_PROFILE) && 192926deccbSFrançois Tigeot (rdev->family >= CHIP_BARTS) && 193926deccbSFrançois Tigeot rdev->pm.active_crtc_count && 194926deccbSFrançois Tigeot ((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) || 195926deccbSFrançois Tigeot (rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX))) 196926deccbSFrançois Tigeot mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. 197926deccbSFrançois Tigeot clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].mclk; 198926deccbSFrançois Tigeot else 199926deccbSFrançois Tigeot mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. 200926deccbSFrançois Tigeot clock_info[rdev->pm.requested_clock_mode_index].mclk; 201926deccbSFrançois Tigeot 202926deccbSFrançois Tigeot if (mclk > rdev->pm.default_mclk) 203926deccbSFrançois Tigeot mclk = rdev->pm.default_mclk; 204926deccbSFrançois Tigeot 205926deccbSFrançois Tigeot /* upvolt before raising clocks, downvolt after lowering clocks */ 206926deccbSFrançois Tigeot if (sclk < rdev->pm.current_sclk) 207926deccbSFrançois Tigeot misc_after = true; 208926deccbSFrançois Tigeot 209926deccbSFrançois Tigeot radeon_sync_with_vblank(rdev); 210926deccbSFrançois Tigeot 211926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM) { 212926deccbSFrançois Tigeot if (!radeon_pm_in_vbl(rdev)) 213926deccbSFrançois Tigeot return; 214926deccbSFrançois Tigeot } 215926deccbSFrançois Tigeot 216926deccbSFrançois Tigeot radeon_pm_prepare(rdev); 217926deccbSFrançois Tigeot 218926deccbSFrançois Tigeot if (!misc_after) 219926deccbSFrançois Tigeot /* voltage, pcie lanes, etc.*/ 220926deccbSFrançois Tigeot radeon_pm_misc(rdev); 221926deccbSFrançois Tigeot 222926deccbSFrançois Tigeot /* set engine clock */ 223926deccbSFrançois Tigeot if (sclk != rdev->pm.current_sclk) { 224926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, false); 225926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, sclk); 226926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, true); 227926deccbSFrançois Tigeot rdev->pm.current_sclk = sclk; 228926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("Setting: e: %d\n", sclk); 229926deccbSFrançois Tigeot } 230926deccbSFrançois Tigeot 231926deccbSFrançois Tigeot /* set memory clock */ 232926deccbSFrançois Tigeot if (rdev->asic->pm.set_memory_clock && (mclk != rdev->pm.current_mclk)) { 233926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, false); 234926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, mclk); 235926deccbSFrançois Tigeot radeon_pm_debug_check_in_vbl(rdev, true); 236926deccbSFrançois Tigeot rdev->pm.current_mclk = mclk; 237926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("Setting: m: %d\n", mclk); 238926deccbSFrançois Tigeot } 239926deccbSFrançois Tigeot 240926deccbSFrançois Tigeot if (misc_after) 241926deccbSFrançois Tigeot /* voltage, pcie lanes, etc.*/ 242926deccbSFrançois Tigeot radeon_pm_misc(rdev); 243926deccbSFrançois Tigeot 244926deccbSFrançois Tigeot radeon_pm_finish(rdev); 245926deccbSFrançois Tigeot 246926deccbSFrançois Tigeot rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; 247926deccbSFrançois Tigeot rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; 248926deccbSFrançois Tigeot } else 249926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("pm: GUI not idle!!!\n"); 250926deccbSFrançois Tigeot } 251926deccbSFrançois Tigeot 252926deccbSFrançois Tigeot static void radeon_pm_set_clocks(struct radeon_device *rdev) 253926deccbSFrançois Tigeot { 254926deccbSFrançois Tigeot int i, r; 255926deccbSFrançois Tigeot 256926deccbSFrançois Tigeot /* no need to take locks, etc. if nothing's going to change */ 257926deccbSFrançois Tigeot if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && 258926deccbSFrançois Tigeot (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) 259926deccbSFrançois Tigeot return; 260926deccbSFrançois Tigeot 261*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->ddev->struct_mutex); 262*1cfef1a5SFrançois Tigeot down_write(&rdev->pm.mclk_lock); 263*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->ring_lock); 264926deccbSFrançois Tigeot 265926deccbSFrançois Tigeot /* wait for the rings to drain */ 266926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) { 267926deccbSFrançois Tigeot struct radeon_ring *ring = &rdev->ring[i]; 268926deccbSFrançois Tigeot if (!ring->ready) { 269926deccbSFrançois Tigeot continue; 270926deccbSFrançois Tigeot } 271c6f73aabSFrançois Tigeot r = radeon_fence_wait_empty(rdev, i); 272926deccbSFrançois Tigeot if (r) { 273926deccbSFrançois Tigeot /* needs a GPU reset dont reset here */ 274*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock); 275*1cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock); 276*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ddev->struct_mutex); 277926deccbSFrançois Tigeot return; 278926deccbSFrançois Tigeot } 279926deccbSFrançois Tigeot } 280926deccbSFrançois Tigeot 281926deccbSFrançois Tigeot radeon_unmap_vram_bos(rdev); 282926deccbSFrançois Tigeot 283926deccbSFrançois Tigeot if (rdev->irq.installed) { 284926deccbSFrançois Tigeot for (i = 0; i < rdev->num_crtc; i++) { 285926deccbSFrançois Tigeot if (rdev->pm.active_crtcs & (1 << i)) { 286926deccbSFrançois Tigeot rdev->pm.req_vblank |= (1 << i); 287ee479021SImre Vadász drm_vblank_get(rdev->ddev, i); 288926deccbSFrançois Tigeot } 289926deccbSFrançois Tigeot } 290926deccbSFrançois Tigeot } 291926deccbSFrançois Tigeot 292926deccbSFrançois Tigeot radeon_set_power_state(rdev); 293926deccbSFrançois Tigeot 294926deccbSFrançois Tigeot if (rdev->irq.installed) { 295926deccbSFrançois Tigeot for (i = 0; i < rdev->num_crtc; i++) { 296926deccbSFrançois Tigeot if (rdev->pm.req_vblank & (1 << i)) { 297926deccbSFrançois Tigeot rdev->pm.req_vblank &= ~(1 << i); 298926deccbSFrançois Tigeot drm_vblank_put(rdev->ddev, i); 299926deccbSFrançois Tigeot } 300926deccbSFrançois Tigeot } 301926deccbSFrançois Tigeot } 302926deccbSFrançois Tigeot 303926deccbSFrançois Tigeot /* update display watermarks based on new power state */ 304926deccbSFrançois Tigeot radeon_update_bandwidth_info(rdev); 305926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count) 306926deccbSFrançois Tigeot radeon_bandwidth_update(rdev); 307926deccbSFrançois Tigeot 308926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 309926deccbSFrançois Tigeot 310*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock); 311*1cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock); 312*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ddev->struct_mutex); 313926deccbSFrançois Tigeot } 314926deccbSFrançois Tigeot 315926deccbSFrançois Tigeot static void radeon_pm_print_states(struct radeon_device *rdev) 316926deccbSFrançois Tigeot { 317926deccbSFrançois Tigeot int i, j; 318926deccbSFrançois Tigeot struct radeon_power_state *power_state; 319926deccbSFrançois Tigeot struct radeon_pm_clock_info *clock_info; 320926deccbSFrançois Tigeot 321926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("%d Power State(s)\n", rdev->pm.num_power_states); 322926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; i++) { 323926deccbSFrançois Tigeot power_state = &rdev->pm.power_state[i]; 324926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("State %d: %s\n", i, 325926deccbSFrançois Tigeot radeon_pm_state_type_name[power_state->type]); 326926deccbSFrançois Tigeot if (i == rdev->pm.default_power_state_index) 327926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\tDefault"); 328926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) 329926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t%d PCIE Lanes\n", power_state->pcie_lanes); 330926deccbSFrançois Tigeot if (power_state->flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) 331926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\tSingle display only\n"); 332926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t%d Clock Mode(s)\n", power_state->num_clock_modes); 333926deccbSFrançois Tigeot for (j = 0; j < power_state->num_clock_modes; j++) { 334926deccbSFrançois Tigeot clock_info = &(power_state->clock_info[j]); 335926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_IGP) 336926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t\t%d e: %d\n", 337926deccbSFrançois Tigeot j, 338926deccbSFrançois Tigeot clock_info->sclk * 10); 339926deccbSFrançois Tigeot else 340926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d\n", 341926deccbSFrançois Tigeot j, 342926deccbSFrançois Tigeot clock_info->sclk * 10, 343926deccbSFrançois Tigeot clock_info->mclk * 10, 344926deccbSFrançois Tigeot clock_info->voltage.voltage); 345926deccbSFrançois Tigeot } 346926deccbSFrançois Tigeot } 347926deccbSFrançois Tigeot } 348926deccbSFrançois Tigeot 349926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 350926deccbSFrançois Tigeot static ssize_t radeon_get_pm_profile(struct device *dev, 351926deccbSFrançois Tigeot struct device_attribute *attr, 352926deccbSFrançois Tigeot char *buf) 353926deccbSFrançois Tigeot { 354c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 355926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 356926deccbSFrançois Tigeot int cp = rdev->pm.profile; 357926deccbSFrançois Tigeot 358926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%s\n", 359926deccbSFrançois Tigeot (cp == PM_PROFILE_AUTO) ? "auto" : 360926deccbSFrançois Tigeot (cp == PM_PROFILE_LOW) ? "low" : 361926deccbSFrançois Tigeot (cp == PM_PROFILE_MID) ? "mid" : 362926deccbSFrançois Tigeot (cp == PM_PROFILE_HIGH) ? "high" : "default"); 363926deccbSFrançois Tigeot } 364926deccbSFrançois Tigeot 365926deccbSFrançois Tigeot static ssize_t radeon_set_pm_profile(struct device *dev, 366926deccbSFrançois Tigeot struct device_attribute *attr, 367926deccbSFrançois Tigeot const char *buf, 368926deccbSFrançois Tigeot size_t count) 369926deccbSFrançois Tigeot { 370c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 371926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 372926deccbSFrançois Tigeot 373c6f73aabSFrançois Tigeot /* Can't set profile when the card is off */ 374c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 375c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 376c6f73aabSFrançois Tigeot return -EINVAL; 377c6f73aabSFrançois Tigeot 378*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 379926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) { 380926deccbSFrançois Tigeot if (strncmp("default", buf, strlen("default")) == 0) 381926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT; 382926deccbSFrançois Tigeot else if (strncmp("auto", buf, strlen("auto")) == 0) 383926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_AUTO; 384926deccbSFrançois Tigeot else if (strncmp("low", buf, strlen("low")) == 0) 385926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_LOW; 386926deccbSFrançois Tigeot else if (strncmp("mid", buf, strlen("mid")) == 0) 387926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_MID; 388926deccbSFrançois Tigeot else if (strncmp("high", buf, strlen("high")) == 0) 389926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_HIGH; 390926deccbSFrançois Tigeot else { 391926deccbSFrançois Tigeot count = -EINVAL; 392926deccbSFrançois Tigeot goto fail; 393926deccbSFrançois Tigeot } 394926deccbSFrançois Tigeot radeon_pm_update_profile(rdev); 395926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 396926deccbSFrançois Tigeot } else 397926deccbSFrançois Tigeot count = -EINVAL; 398926deccbSFrançois Tigeot 399926deccbSFrançois Tigeot fail: 400*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 401926deccbSFrançois Tigeot 402926deccbSFrançois Tigeot return count; 403926deccbSFrançois Tigeot } 404926deccbSFrançois Tigeot 405926deccbSFrançois Tigeot static ssize_t radeon_get_pm_method(struct device *dev, 406926deccbSFrançois Tigeot struct device_attribute *attr, 407926deccbSFrançois Tigeot char *buf) 408926deccbSFrançois Tigeot { 409c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 410926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 411926deccbSFrançois Tigeot int pm = rdev->pm.pm_method; 412926deccbSFrançois Tigeot 413926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%s\n", 41457e252bfSMichael Neumann (pm == PM_METHOD_DYNPM) ? "dynpm" : 41557e252bfSMichael Neumann (pm == PM_METHOD_PROFILE) ? "profile" : "dpm"); 416926deccbSFrançois Tigeot } 417926deccbSFrançois Tigeot 418926deccbSFrançois Tigeot static ssize_t radeon_set_pm_method(struct device *dev, 419926deccbSFrançois Tigeot struct device_attribute *attr, 420926deccbSFrançois Tigeot const char *buf, 421926deccbSFrançois Tigeot size_t count) 422926deccbSFrançois Tigeot { 423c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 424926deccbSFrançois Tigeot struct radeon_device *rdev = ddev->dev_private; 425926deccbSFrançois Tigeot 426c6f73aabSFrançois Tigeot /* Can't set method when the card is off */ 427c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 428c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { 429c6f73aabSFrançois Tigeot count = -EINVAL; 430c6f73aabSFrançois Tigeot goto fail; 431c6f73aabSFrançois Tigeot } 432c6f73aabSFrançois Tigeot 43357e252bfSMichael Neumann /* we don't support the legacy modes with dpm */ 43457e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) { 43557e252bfSMichael Neumann count = -EINVAL; 43657e252bfSMichael Neumann goto fail; 43757e252bfSMichael Neumann } 438926deccbSFrançois Tigeot 439926deccbSFrançois Tigeot if (strncmp("dynpm", buf, strlen("dynpm")) == 0) { 440*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 441926deccbSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DYNPM; 442926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; 443926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; 444*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 445926deccbSFrançois Tigeot } else if (strncmp("profile", buf, strlen("profile")) == 0) { 446*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 447926deccbSFrançois Tigeot /* disable dynpm */ 448926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; 449926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 450926deccbSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 451*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 452ee479021SImre Vadász #ifdef DUMBBELL_WIP 453926deccbSFrançois Tigeot cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); 454ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 455926deccbSFrançois Tigeot } else { 456926deccbSFrançois Tigeot count = -EINVAL; 457926deccbSFrançois Tigeot goto fail; 458926deccbSFrançois Tigeot } 459926deccbSFrançois Tigeot radeon_pm_compute_clocks(rdev); 460926deccbSFrançois Tigeot fail: 461926deccbSFrançois Tigeot return count; 462926deccbSFrançois Tigeot } 463926deccbSFrançois Tigeot 46457e252bfSMichael Neumann static ssize_t radeon_get_dpm_state(struct device *dev, 46557e252bfSMichael Neumann struct device_attribute *attr, 46657e252bfSMichael Neumann char *buf) 46757e252bfSMichael Neumann { 468c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 46957e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 47057e252bfSMichael Neumann enum radeon_pm_state_type pm = rdev->pm.dpm.user_state; 47157e252bfSMichael Neumann 47257e252bfSMichael Neumann return snprintf(buf, PAGE_SIZE, "%s\n", 47357e252bfSMichael Neumann (pm == POWER_STATE_TYPE_BATTERY) ? "battery" : 47457e252bfSMichael Neumann (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance"); 47557e252bfSMichael Neumann } 47657e252bfSMichael Neumann 47757e252bfSMichael Neumann static ssize_t radeon_set_dpm_state(struct device *dev, 47857e252bfSMichael Neumann struct device_attribute *attr, 47957e252bfSMichael Neumann const char *buf, 48057e252bfSMichael Neumann size_t count) 48157e252bfSMichael Neumann { 482c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 48357e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 48457e252bfSMichael Neumann 485*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 48657e252bfSMichael Neumann if (strncmp("battery", buf, strlen("battery")) == 0) 48757e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY; 48857e252bfSMichael Neumann else if (strncmp("balanced", buf, strlen("balanced")) == 0) 48957e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED; 49057e252bfSMichael Neumann else if (strncmp("performance", buf, strlen("performance")) == 0) 49157e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE; 49257e252bfSMichael Neumann else { 493*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 49457e252bfSMichael Neumann count = -EINVAL; 49557e252bfSMichael Neumann goto fail; 49657e252bfSMichael Neumann } 497*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 498c6f73aabSFrançois Tigeot 499c6f73aabSFrançois Tigeot /* Can't set dpm state when the card is off */ 500c6f73aabSFrançois Tigeot if (!(rdev->flags & RADEON_IS_PX) || 501c6f73aabSFrançois Tigeot (ddev->switch_power_state == DRM_SWITCH_POWER_ON)) 50257e252bfSMichael Neumann radeon_pm_compute_clocks(rdev); 503c6f73aabSFrançois Tigeot 50457e252bfSMichael Neumann fail: 50557e252bfSMichael Neumann return count; 50657e252bfSMichael Neumann } 50757e252bfSMichael Neumann 50857e252bfSMichael Neumann static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev, 50957e252bfSMichael Neumann struct device_attribute *attr, 51057e252bfSMichael Neumann char *buf) 51157e252bfSMichael Neumann { 512c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 51357e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 51457e252bfSMichael Neumann enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; 51557e252bfSMichael Neumann 516c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 517c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 518*1cfef1a5SFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "off\n"); 519c6f73aabSFrançois Tigeot 52057e252bfSMichael Neumann return snprintf(buf, PAGE_SIZE, "%s\n", 52157e252bfSMichael Neumann (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" : 52257e252bfSMichael Neumann (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high"); 52357e252bfSMichael Neumann } 52457e252bfSMichael Neumann 52557e252bfSMichael Neumann static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev, 52657e252bfSMichael Neumann struct device_attribute *attr, 52757e252bfSMichael Neumann const char *buf, 52857e252bfSMichael Neumann size_t count) 52957e252bfSMichael Neumann { 530c6f73aabSFrançois Tigeot struct drm_device *ddev = dev_get_drvdata(dev); 53157e252bfSMichael Neumann struct radeon_device *rdev = ddev->dev_private; 53257e252bfSMichael Neumann enum radeon_dpm_forced_level level; 53357e252bfSMichael Neumann int ret = 0; 53457e252bfSMichael Neumann 535c6f73aabSFrançois Tigeot /* Can't force performance level when the card is off */ 536c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 537c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 538c6f73aabSFrançois Tigeot return -EINVAL; 539c6f73aabSFrançois Tigeot 540*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 54157e252bfSMichael Neumann if (strncmp("low", buf, strlen("low")) == 0) { 54257e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_LOW; 54357e252bfSMichael Neumann } else if (strncmp("high", buf, strlen("high")) == 0) { 54457e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_HIGH; 54557e252bfSMichael Neumann } else if (strncmp("auto", buf, strlen("auto")) == 0) { 54657e252bfSMichael Neumann level = RADEON_DPM_FORCED_LEVEL_AUTO; 54757e252bfSMichael Neumann } else { 54857e252bfSMichael Neumann count = -EINVAL; 54957e252bfSMichael Neumann goto fail; 55057e252bfSMichael Neumann } 55157e252bfSMichael Neumann if (rdev->asic->dpm.force_performance_level) { 552c6f73aabSFrançois Tigeot if (rdev->pm.dpm.thermal_active) { 553c6f73aabSFrançois Tigeot count = -EINVAL; 554c6f73aabSFrançois Tigeot goto fail; 555c6f73aabSFrançois Tigeot } 55657e252bfSMichael Neumann ret = radeon_dpm_force_performance_level(rdev, level); 55757e252bfSMichael Neumann if (ret) 55857e252bfSMichael Neumann count = -EINVAL; 55957e252bfSMichael Neumann } 56057e252bfSMichael Neumann fail: 561*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 562c6f73aabSFrançois Tigeot 56357e252bfSMichael Neumann return count; 56457e252bfSMichael Neumann } 56557e252bfSMichael Neumann 566926deccbSFrançois Tigeot static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); 567926deccbSFrançois Tigeot static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); 56857e252bfSMichael Neumann static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); 56957e252bfSMichael Neumann static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, 57057e252bfSMichael Neumann radeon_get_dpm_forced_performance_level, 57157e252bfSMichael Neumann radeon_set_dpm_forced_performance_level); 572926deccbSFrançois Tigeot 573926deccbSFrançois Tigeot static ssize_t radeon_hwmon_show_temp(struct device *dev, 574926deccbSFrançois Tigeot struct device_attribute *attr, 575926deccbSFrançois Tigeot char *buf) 576926deccbSFrançois Tigeot { 577c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 578c6f73aabSFrançois Tigeot struct drm_device *ddev = rdev->ddev; 579926deccbSFrançois Tigeot int temp; 580926deccbSFrançois Tigeot 581c6f73aabSFrançois Tigeot /* Can't get temperature when the card is off */ 582c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 583c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) 584c6f73aabSFrançois Tigeot return -EINVAL; 585c6f73aabSFrançois Tigeot 58657e252bfSMichael Neumann if (rdev->asic->pm.get_temperature) 58757e252bfSMichael Neumann temp = radeon_get_temperature(rdev); 58857e252bfSMichael Neumann else 589926deccbSFrançois Tigeot temp = 0; 590926deccbSFrançois Tigeot 591926deccbSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%d\n", temp); 592926deccbSFrançois Tigeot } 593926deccbSFrançois Tigeot 594c6f73aabSFrançois Tigeot static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev, 595926deccbSFrançois Tigeot struct device_attribute *attr, 596926deccbSFrançois Tigeot char *buf) 597926deccbSFrançois Tigeot { 598c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 599c6f73aabSFrançois Tigeot int hyst = to_sensor_dev_attr(attr)->index; 600c6f73aabSFrançois Tigeot int temp; 601c6f73aabSFrançois Tigeot 602c6f73aabSFrançois Tigeot if (hyst) 603c6f73aabSFrançois Tigeot temp = rdev->pm.dpm.thermal.min_temp; 604c6f73aabSFrançois Tigeot else 605c6f73aabSFrançois Tigeot temp = rdev->pm.dpm.thermal.max_temp; 606c6f73aabSFrançois Tigeot 607c6f73aabSFrançois Tigeot return ksnprintf(buf, PAGE_SIZE, "%d\n", temp); 608926deccbSFrançois Tigeot } 609926deccbSFrançois Tigeot 610926deccbSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0); 611c6f73aabSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0); 612c6f73aabSFrançois Tigeot static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1); 613926deccbSFrançois Tigeot 614926deccbSFrançois Tigeot static struct attribute *hwmon_attributes[] = { 615926deccbSFrançois Tigeot &sensor_dev_attr_temp1_input.dev_attr.attr, 616c6f73aabSFrançois Tigeot &sensor_dev_attr_temp1_crit.dev_attr.attr, 617c6f73aabSFrançois Tigeot &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, 618926deccbSFrançois Tigeot NULL 619926deccbSFrançois Tigeot }; 620926deccbSFrançois Tigeot 621c6f73aabSFrançois Tigeot static umode_t hwmon_attributes_visible(struct kobject *kobj, 622c6f73aabSFrançois Tigeot struct attribute *attr, int index) 623c6f73aabSFrançois Tigeot { 624c6f73aabSFrançois Tigeot struct device *dev = container_of(kobj, struct device, kobj); 625c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev_get_drvdata(dev); 626c6f73aabSFrançois Tigeot 627ee479021SImre Vadász /* Skip limit attributes if DPM is not enabled */ 628c6f73aabSFrançois Tigeot if (rdev->pm.pm_method != PM_METHOD_DPM && 629c6f73aabSFrançois Tigeot (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr || 630ee479021SImre Vadász attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)) 631c6f73aabSFrançois Tigeot return 0; 632c6f73aabSFrançois Tigeot 633ee479021SImre Vadász return attr->mode; 634c6f73aabSFrançois Tigeot } 635c6f73aabSFrançois Tigeot 636926deccbSFrançois Tigeot static const struct attribute_group hwmon_attrgroup = { 637926deccbSFrançois Tigeot .attrs = hwmon_attributes, 638c6f73aabSFrançois Tigeot .is_visible = hwmon_attributes_visible, 639c6f73aabSFrançois Tigeot }; 640c6f73aabSFrançois Tigeot 641c6f73aabSFrançois Tigeot static const struct attribute_group *hwmon_groups[] = { 642c6f73aabSFrançois Tigeot &hwmon_attrgroup, 643c6f73aabSFrançois Tigeot NULL 644926deccbSFrançois Tigeot }; 645926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 646926deccbSFrançois Tigeot 6472c86cb5bSImre Vadász static void 6482c86cb5bSImre Vadász radeon_hwmon_refresh(void *arg) 6492c86cb5bSImre Vadász { 6502c86cb5bSImre Vadász struct radeon_device *rdev = (struct radeon_device *)arg; 65126b5dbf2SImre Vadász struct drm_device *ddev = rdev->ddev; 6522c86cb5bSImre Vadász struct ksensor *s = rdev->pm.int_sensor; 6532c86cb5bSImre Vadász int temp; 65426b5dbf2SImre Vadász enum sensor_status stat; 6552c86cb5bSImre Vadász 65626b5dbf2SImre Vadász /* Can't get temperature when the card is off */ 65726b5dbf2SImre Vadász if ((rdev->flags & RADEON_IS_PX) && 65826b5dbf2SImre Vadász (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { 65926b5dbf2SImre Vadász sensor_set_unknown(s); 66026b5dbf2SImre Vadász s->status = SENSOR_S_OK; 66126b5dbf2SImre Vadász return; 66226b5dbf2SImre Vadász } 66326b5dbf2SImre Vadász 66426b5dbf2SImre Vadász if (rdev->asic->pm.get_temperature == NULL) { 66526b5dbf2SImre Vadász sensor_set_invalid(s); 66626b5dbf2SImre Vadász return; 66726b5dbf2SImre Vadász } 66826b5dbf2SImre Vadász 6692c86cb5bSImre Vadász temp = radeon_get_temperature(rdev); 67026b5dbf2SImre Vadász if (temp >= rdev->pm.dpm.thermal.max_temp) 67126b5dbf2SImre Vadász stat = SENSOR_S_CRIT; 67226b5dbf2SImre Vadász else if (temp >= rdev->pm.dpm.thermal.min_temp) 67326b5dbf2SImre Vadász stat = SENSOR_S_WARN; 6742c86cb5bSImre Vadász else 67526b5dbf2SImre Vadász stat = SENSOR_S_OK; 6762c86cb5bSImre Vadász 67726b5dbf2SImre Vadász sensor_set(s, temp * 1000 + 273150000, stat); 6782c86cb5bSImre Vadász } 6792c86cb5bSImre Vadász 680926deccbSFrançois Tigeot static int radeon_hwmon_init(struct radeon_device *rdev) 681926deccbSFrançois Tigeot { 682926deccbSFrançois Tigeot int err = 0; 683926deccbSFrançois Tigeot 6842c86cb5bSImre Vadász rdev->pm.int_sensor = NULL; 6852c86cb5bSImre Vadász rdev->pm.int_sensordev = NULL; 686926deccbSFrançois Tigeot 687926deccbSFrançois Tigeot switch (rdev->pm.int_thermal_type) { 688926deccbSFrançois Tigeot case THERMAL_TYPE_RV6XX: 689926deccbSFrançois Tigeot case THERMAL_TYPE_RV770: 690926deccbSFrançois Tigeot case THERMAL_TYPE_EVERGREEN: 691926deccbSFrançois Tigeot case THERMAL_TYPE_NI: 692926deccbSFrançois Tigeot case THERMAL_TYPE_SUMO: 693926deccbSFrançois Tigeot case THERMAL_TYPE_SI: 6944cd92098Szrj case THERMAL_TYPE_CI: 6954cd92098Szrj case THERMAL_TYPE_KV: 69657e252bfSMichael Neumann if (rdev->asic->pm.get_temperature == NULL) 697926deccbSFrançois Tigeot return err; 6982c86cb5bSImre Vadász 6992c86cb5bSImre Vadász rdev->pm.int_sensor = kmalloc(sizeof(*rdev->pm.int_sensor), 7002c86cb5bSImre Vadász M_DRM, M_ZERO | M_WAITOK); 7012c86cb5bSImre Vadász rdev->pm.int_sensordev = kmalloc( 7022c86cb5bSImre Vadász sizeof(*rdev->pm.int_sensordev), M_DRM, 7032c86cb5bSImre Vadász M_ZERO | M_WAITOK); 7042c86cb5bSImre Vadász strlcpy(rdev->pm.int_sensordev->xname, 705fb572d17SFrançois Tigeot device_get_nameunit(rdev->dev->bsddev), 7062c86cb5bSImre Vadász sizeof(rdev->pm.int_sensordev->xname)); 7072c86cb5bSImre Vadász rdev->pm.int_sensor->type = SENSOR_TEMP; 70826b5dbf2SImre Vadász rdev->pm.int_sensor->flags |= SENSOR_FINVALID; 7092c86cb5bSImre Vadász sensor_attach(rdev->pm.int_sensordev, rdev->pm.int_sensor); 7102c86cb5bSImre Vadász sensor_task_register(rdev, radeon_hwmon_refresh, 5); 7112c86cb5bSImre Vadász sensordev_install(rdev->pm.int_sensordev); 712926deccbSFrançois Tigeot break; 713926deccbSFrançois Tigeot default: 714926deccbSFrançois Tigeot break; 715926deccbSFrançois Tigeot } 716926deccbSFrançois Tigeot 717926deccbSFrançois Tigeot return err; 718926deccbSFrançois Tigeot } 719926deccbSFrançois Tigeot 720926deccbSFrançois Tigeot static void radeon_hwmon_fini(struct radeon_device *rdev) 721926deccbSFrançois Tigeot { 7222c86cb5bSImre Vadász if (rdev->pm.int_sensor != NULL && rdev->pm.int_sensordev != NULL) { 7232c86cb5bSImre Vadász sensordev_deinstall(rdev->pm.int_sensordev); 7242c86cb5bSImre Vadász sensor_task_unregister(rdev); 7252c86cb5bSImre Vadász kfree(rdev->pm.int_sensor); 7262c86cb5bSImre Vadász kfree(rdev->pm.int_sensordev); 7272c86cb5bSImre Vadász rdev->pm.int_sensor = NULL; 7282c86cb5bSImre Vadász rdev->pm.int_sensordev = NULL; 729926deccbSFrançois Tigeot } 730926deccbSFrançois Tigeot } 731926deccbSFrançois Tigeot 7322c5cc6b9SFrançois Tigeot static void radeon_dpm_thermal_work_handler(struct work_struct *work) 73357e252bfSMichael Neumann { 7342c5cc6b9SFrançois Tigeot struct radeon_device *rdev = 7352c5cc6b9SFrançois Tigeot container_of(work, struct radeon_device, 7362c5cc6b9SFrançois Tigeot pm.dpm.thermal.work); 73757e252bfSMichael Neumann /* switch to the thermal state */ 73857e252bfSMichael Neumann enum radeon_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL; 73957e252bfSMichael Neumann 74057e252bfSMichael Neumann if (!rdev->pm.dpm_enabled) 74157e252bfSMichael Neumann return; 74257e252bfSMichael Neumann 74357e252bfSMichael Neumann if (rdev->asic->pm.get_temperature) { 74457e252bfSMichael Neumann int temp = radeon_get_temperature(rdev); 74557e252bfSMichael Neumann 74657e252bfSMichael Neumann if (temp < rdev->pm.dpm.thermal.min_temp) 74757e252bfSMichael Neumann /* switch back the user state */ 74857e252bfSMichael Neumann dpm_state = rdev->pm.dpm.user_state; 74957e252bfSMichael Neumann } else { 75057e252bfSMichael Neumann if (rdev->pm.dpm.thermal.high_to_low) 75157e252bfSMichael Neumann /* switch back the user state */ 75257e252bfSMichael Neumann dpm_state = rdev->pm.dpm.user_state; 75357e252bfSMichael Neumann } 7544cd92098Szrj mutex_lock(&rdev->pm.mutex); 7554cd92098Szrj if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL) 7564cd92098Szrj rdev->pm.dpm.thermal_active = true; 7574cd92098Szrj else 7584cd92098Szrj rdev->pm.dpm.thermal_active = false; 7594cd92098Szrj rdev->pm.dpm.state = dpm_state; 7604cd92098Szrj mutex_unlock(&rdev->pm.mutex); 7614cd92098Szrj 7624cd92098Szrj radeon_pm_compute_clocks(rdev); 76357e252bfSMichael Neumann } 76457e252bfSMichael Neumann 765ee479021SImre Vadász static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, 766ee479021SImre Vadász enum radeon_pm_state_type dpm_state) 76757e252bfSMichael Neumann { 768ee479021SImre Vadász int i; 769ee479021SImre Vadász struct radeon_ps *ps; 770ee479021SImre Vadász u32 ui_class; 77157e252bfSMichael Neumann bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ? 77257e252bfSMichael Neumann true : false; 77357e252bfSMichael Neumann 77457e252bfSMichael Neumann /* check if the vblank period is too short to adjust the mclk */ 77557e252bfSMichael Neumann if (single_display && rdev->asic->dpm.vblank_too_short) { 77657e252bfSMichael Neumann if (radeon_dpm_vblank_too_short(rdev)) 77757e252bfSMichael Neumann single_display = false; 77857e252bfSMichael Neumann } 77957e252bfSMichael Neumann 78057e252bfSMichael Neumann /* certain older asics have a separare 3D performance state, 78157e252bfSMichael Neumann * so try that first if the user selected performance 78257e252bfSMichael Neumann */ 78357e252bfSMichael Neumann if (dpm_state == POWER_STATE_TYPE_PERFORMANCE) 78457e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; 78557e252bfSMichael Neumann /* balanced states don't exist at the moment */ 78657e252bfSMichael Neumann if (dpm_state == POWER_STATE_TYPE_BALANCED) 78757e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_PERFORMANCE; 78857e252bfSMichael Neumann 78957e252bfSMichael Neumann restart_search: 79057e252bfSMichael Neumann /* Pick the best power state based on current conditions */ 79157e252bfSMichael Neumann for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 79257e252bfSMichael Neumann ps = &rdev->pm.dpm.ps[i]; 79357e252bfSMichael Neumann ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK; 79457e252bfSMichael Neumann switch (dpm_state) { 79557e252bfSMichael Neumann /* user states */ 79657e252bfSMichael Neumann case POWER_STATE_TYPE_BATTERY: 79757e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) { 79857e252bfSMichael Neumann if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { 79957e252bfSMichael Neumann if (single_display) 80057e252bfSMichael Neumann return ps; 80157e252bfSMichael Neumann } else 80257e252bfSMichael Neumann return ps; 80357e252bfSMichael Neumann } 80457e252bfSMichael Neumann break; 80557e252bfSMichael Neumann case POWER_STATE_TYPE_BALANCED: 80657e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) { 80757e252bfSMichael Neumann if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { 80857e252bfSMichael Neumann if (single_display) 80957e252bfSMichael Neumann return ps; 81057e252bfSMichael Neumann } else 81157e252bfSMichael Neumann return ps; 81257e252bfSMichael Neumann } 81357e252bfSMichael Neumann break; 81457e252bfSMichael Neumann case POWER_STATE_TYPE_PERFORMANCE: 81557e252bfSMichael Neumann if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { 81657e252bfSMichael Neumann if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { 81757e252bfSMichael Neumann if (single_display) 81857e252bfSMichael Neumann return ps; 81957e252bfSMichael Neumann } else 82057e252bfSMichael Neumann return ps; 82157e252bfSMichael Neumann } 82257e252bfSMichael Neumann break; 82357e252bfSMichael Neumann /* internal states */ 82457e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD: 8254cd92098Szrj if (rdev->pm.dpm.uvd_ps) 82657e252bfSMichael Neumann return rdev->pm.dpm.uvd_ps; 8274cd92098Szrj else 8284cd92098Szrj break; 82957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_SD: 83057e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) 83157e252bfSMichael Neumann return ps; 83257e252bfSMichael Neumann break; 83357e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD: 83457e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) 83557e252bfSMichael Neumann return ps; 83657e252bfSMichael Neumann break; 83757e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD2: 83857e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) 83957e252bfSMichael Neumann return ps; 84057e252bfSMichael Neumann break; 84157e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_MVC: 84257e252bfSMichael Neumann if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) 84357e252bfSMichael Neumann return ps; 84457e252bfSMichael Neumann break; 84557e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_BOOT: 84657e252bfSMichael Neumann return rdev->pm.dpm.boot_ps; 84757e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_THERMAL: 84857e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) 84957e252bfSMichael Neumann return ps; 85057e252bfSMichael Neumann break; 85157e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ACPI: 85257e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) 85357e252bfSMichael Neumann return ps; 85457e252bfSMichael Neumann break; 85557e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ULV: 85657e252bfSMichael Neumann if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) 85757e252bfSMichael Neumann return ps; 85857e252bfSMichael Neumann break; 85957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_3DPERF: 86057e252bfSMichael Neumann if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) 86157e252bfSMichael Neumann return ps; 86257e252bfSMichael Neumann break; 86357e252bfSMichael Neumann default: 86457e252bfSMichael Neumann break; 86557e252bfSMichael Neumann } 86657e252bfSMichael Neumann } 86757e252bfSMichael Neumann /* use a fallback state if we didn't match */ 86857e252bfSMichael Neumann switch (dpm_state) { 86957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_SD: 8704cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; 8714cd92098Szrj goto restart_search; 87257e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD: 87357e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_HD2: 87457e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_UVD_MVC: 8754cd92098Szrj if (rdev->pm.dpm.uvd_ps) { 87657e252bfSMichael Neumann return rdev->pm.dpm.uvd_ps; 8774cd92098Szrj } else { 8784cd92098Szrj dpm_state = POWER_STATE_TYPE_PERFORMANCE; 8794cd92098Szrj goto restart_search; 8804cd92098Szrj } 88157e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_THERMAL: 88257e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI; 88357e252bfSMichael Neumann goto restart_search; 88457e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_ACPI: 88557e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_BATTERY; 88657e252bfSMichael Neumann goto restart_search; 88757e252bfSMichael Neumann case POWER_STATE_TYPE_BATTERY: 88857e252bfSMichael Neumann case POWER_STATE_TYPE_BALANCED: 88957e252bfSMichael Neumann case POWER_STATE_TYPE_INTERNAL_3DPERF: 89057e252bfSMichael Neumann dpm_state = POWER_STATE_TYPE_PERFORMANCE; 89157e252bfSMichael Neumann goto restart_search; 89257e252bfSMichael Neumann default: 89357e252bfSMichael Neumann break; 89457e252bfSMichael Neumann } 89557e252bfSMichael Neumann 89657e252bfSMichael Neumann return NULL; 89757e252bfSMichael Neumann } 89857e252bfSMichael Neumann 89957e252bfSMichael Neumann static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev) 90057e252bfSMichael Neumann { 90157e252bfSMichael Neumann int i; 90257e252bfSMichael Neumann struct radeon_ps *ps; 90357e252bfSMichael Neumann enum radeon_pm_state_type dpm_state; 90457e252bfSMichael Neumann int ret; 90557e252bfSMichael Neumann 90657e252bfSMichael Neumann /* if dpm init failed */ 90757e252bfSMichael Neumann if (!rdev->pm.dpm_enabled) 90857e252bfSMichael Neumann return; 90957e252bfSMichael Neumann 91057e252bfSMichael Neumann if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) { 91157e252bfSMichael Neumann /* add other state override checks here */ 91257e252bfSMichael Neumann if ((!rdev->pm.dpm.thermal_active) && 91357e252bfSMichael Neumann (!rdev->pm.dpm.uvd_active)) 91457e252bfSMichael Neumann rdev->pm.dpm.state = rdev->pm.dpm.user_state; 91557e252bfSMichael Neumann } 91657e252bfSMichael Neumann dpm_state = rdev->pm.dpm.state; 91757e252bfSMichael Neumann 91857e252bfSMichael Neumann ps = radeon_dpm_pick_power_state(rdev, dpm_state); 91957e252bfSMichael Neumann if (ps) 92057e252bfSMichael Neumann rdev->pm.dpm.requested_ps = ps; 92157e252bfSMichael Neumann else 92257e252bfSMichael Neumann return; 92357e252bfSMichael Neumann 92457e252bfSMichael Neumann /* no need to reprogram if nothing changed unless we are on BTC+ */ 92557e252bfSMichael Neumann if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) { 926c6f73aabSFrançois Tigeot /* vce just modifies an existing state so force a change */ 927c6f73aabSFrançois Tigeot if (ps->vce_active != rdev->pm.dpm.vce_active) 928c6f73aabSFrançois Tigeot goto force; 92957e252bfSMichael Neumann if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) { 93057e252bfSMichael Neumann /* for pre-BTC and APUs if the num crtcs changed but state is the same, 93157e252bfSMichael Neumann * all we need to do is update the display configuration. 93257e252bfSMichael Neumann */ 93357e252bfSMichael Neumann if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) { 93457e252bfSMichael Neumann /* update display watermarks based on new power state */ 93557e252bfSMichael Neumann radeon_bandwidth_update(rdev); 93657e252bfSMichael Neumann /* update displays */ 93757e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev); 93857e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; 93957e252bfSMichael Neumann rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; 94057e252bfSMichael Neumann } 94157e252bfSMichael Neumann return; 94257e252bfSMichael Neumann } else { 94357e252bfSMichael Neumann /* for BTC+ if the num crtcs hasn't changed and state is the same, 94457e252bfSMichael Neumann * nothing to do, if the num crtcs is > 1 and state is the same, 94557e252bfSMichael Neumann * update display configuration. 94657e252bfSMichael Neumann */ 94757e252bfSMichael Neumann if (rdev->pm.dpm.new_active_crtcs == 94857e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs) { 94957e252bfSMichael Neumann return; 95057e252bfSMichael Neumann } else { 95157e252bfSMichael Neumann if ((rdev->pm.dpm.current_active_crtc_count > 1) && 95257e252bfSMichael Neumann (rdev->pm.dpm.new_active_crtc_count > 1)) { 95357e252bfSMichael Neumann /* update display watermarks based on new power state */ 95457e252bfSMichael Neumann radeon_bandwidth_update(rdev); 95557e252bfSMichael Neumann /* update displays */ 95657e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev); 95757e252bfSMichael Neumann rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; 95857e252bfSMichael Neumann rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; 95957e252bfSMichael Neumann return; 96057e252bfSMichael Neumann } 96157e252bfSMichael Neumann } 96257e252bfSMichael Neumann } 96357e252bfSMichael Neumann } 96457e252bfSMichael Neumann 965c6f73aabSFrançois Tigeot force: 966c6f73aabSFrançois Tigeot if (radeon_dpm == 1) { 96757e252bfSMichael Neumann printk("switching from power state:\n"); 96857e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps); 96957e252bfSMichael Neumann printk("switching to power state:\n"); 97057e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps); 971c6f73aabSFrançois Tigeot } 97257e252bfSMichael Neumann 973*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->ddev->struct_mutex); 974*1cfef1a5SFrançois Tigeot down_write(&rdev->pm.mclk_lock); 975*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->ring_lock); 97657e252bfSMichael Neumann 977c6f73aabSFrançois Tigeot /* update whether vce is active */ 978c6f73aabSFrançois Tigeot ps->vce_active = rdev->pm.dpm.vce_active; 979c6f73aabSFrançois Tigeot 98057e252bfSMichael Neumann ret = radeon_dpm_pre_set_power_state(rdev); 98157e252bfSMichael Neumann if (ret) 98257e252bfSMichael Neumann goto done; 98357e252bfSMichael Neumann 98457e252bfSMichael Neumann /* update display watermarks based on new power state */ 98557e252bfSMichael Neumann radeon_bandwidth_update(rdev); 98657e252bfSMichael Neumann /* update displays */ 98757e252bfSMichael Neumann radeon_dpm_display_configuration_changed(rdev); 98857e252bfSMichael Neumann 989ee479021SImre Vadász rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; 990ee479021SImre Vadász rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; 991ee479021SImre Vadász 99257e252bfSMichael Neumann /* wait for the rings to drain */ 99357e252bfSMichael Neumann for (i = 0; i < RADEON_NUM_RINGS; i++) { 99457e252bfSMichael Neumann struct radeon_ring *ring = &rdev->ring[i]; 99557e252bfSMichael Neumann if (ring->ready) 996c6f73aabSFrançois Tigeot radeon_fence_wait_empty(rdev, i); 99757e252bfSMichael Neumann } 99857e252bfSMichael Neumann 99957e252bfSMichael Neumann /* program the new power state */ 100057e252bfSMichael Neumann radeon_dpm_set_power_state(rdev); 100157e252bfSMichael Neumann 100257e252bfSMichael Neumann /* update current power state */ 100357e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps; 100457e252bfSMichael Neumann 100557e252bfSMichael Neumann radeon_dpm_post_set_power_state(rdev); 100657e252bfSMichael Neumann 10074cd92098Szrj if (rdev->asic->dpm.force_performance_level) { 1008c6f73aabSFrançois Tigeot if (rdev->pm.dpm.thermal_active) { 1009c6f73aabSFrançois Tigeot enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; 10104cd92098Szrj /* force low perf level for thermal */ 10114cd92098Szrj radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_LOW); 1012c6f73aabSFrançois Tigeot /* save the user's level */ 1013c6f73aabSFrançois Tigeot rdev->pm.dpm.forced_level = level; 1014c6f73aabSFrançois Tigeot } else { 1015c6f73aabSFrançois Tigeot /* otherwise, user selected level */ 1016c6f73aabSFrançois Tigeot radeon_dpm_force_performance_level(rdev, rdev->pm.dpm.forced_level); 1017c6f73aabSFrançois Tigeot } 10184cd92098Szrj } 10194cd92098Szrj 102057e252bfSMichael Neumann done: 1021*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ring_lock); 1022*1cfef1a5SFrançois Tigeot up_write(&rdev->pm.mclk_lock); 1023*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->ddev->struct_mutex); 102457e252bfSMichael Neumann } 102557e252bfSMichael Neumann 10264cd92098Szrj void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable) 102757e252bfSMichael Neumann { 10284cd92098Szrj enum radeon_pm_state_type dpm_state; 102957e252bfSMichael Neumann 10304cd92098Szrj if (rdev->asic->dpm.powergate_uvd) { 10314cd92098Szrj mutex_lock(&rdev->pm.mutex); 1032c6f73aabSFrançois Tigeot /* don't powergate anything if we 1033c6f73aabSFrançois Tigeot have active but pause streams */ 1034c6f73aabSFrançois Tigeot enable |= rdev->pm.dpm.sd > 0; 1035c6f73aabSFrançois Tigeot enable |= rdev->pm.dpm.hd > 0; 10364cd92098Szrj /* enable/disable UVD */ 10374cd92098Szrj radeon_dpm_powergate_uvd(rdev, !enable); 10384cd92098Szrj mutex_unlock(&rdev->pm.mutex); 10394cd92098Szrj } else { 10404cd92098Szrj if (enable) { 10414cd92098Szrj mutex_lock(&rdev->pm.mutex); 104257e252bfSMichael Neumann rdev->pm.dpm.uvd_active = true; 10434cd92098Szrj /* disable this for now */ 10444cd92098Szrj #if 0 10454cd92098Szrj if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0)) 10464cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD; 10474cd92098Szrj else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0)) 10484cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; 10494cd92098Szrj else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 1)) 10504cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; 10514cd92098Szrj else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2)) 10524cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2; 10534cd92098Szrj else 10544cd92098Szrj #endif 10554cd92098Szrj dpm_state = POWER_STATE_TYPE_INTERNAL_UVD; 105657e252bfSMichael Neumann rdev->pm.dpm.state = dpm_state; 10574cd92098Szrj mutex_unlock(&rdev->pm.mutex); 10584cd92098Szrj } else { 10594cd92098Szrj mutex_lock(&rdev->pm.mutex); 10604cd92098Szrj rdev->pm.dpm.uvd_active = false; 10614cd92098Szrj mutex_unlock(&rdev->pm.mutex); 10624cd92098Szrj } 10634cd92098Szrj 106457e252bfSMichael Neumann radeon_pm_compute_clocks(rdev); 106557e252bfSMichael Neumann } 10664cd92098Szrj } 106757e252bfSMichael Neumann 1068c6f73aabSFrançois Tigeot void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable) 1069c6f73aabSFrançois Tigeot { 1070c6f73aabSFrançois Tigeot if (enable) { 1071c6f73aabSFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1072c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_active = true; 1073c6f73aabSFrançois Tigeot /* XXX select vce level based on ring/task */ 1074c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_level = RADEON_VCE_LEVEL_AC_ALL; 1075c6f73aabSFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1076c6f73aabSFrançois Tigeot } else { 1077c6f73aabSFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1078c6f73aabSFrançois Tigeot rdev->pm.dpm.vce_active = false; 1079c6f73aabSFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1080c6f73aabSFrançois Tigeot } 1081c6f73aabSFrançois Tigeot 1082c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1083c6f73aabSFrançois Tigeot } 1084c6f73aabSFrançois Tigeot 108557e252bfSMichael Neumann static void radeon_pm_suspend_old(struct radeon_device *rdev) 1086926deccbSFrançois Tigeot { 1087*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1088926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM) { 1089926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) 1090926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED; 1091926deccbSFrançois Tigeot } 1092*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1093926deccbSFrançois Tigeot 1094ee479021SImre Vadász #ifdef DUMBBELL_WIP 1095926deccbSFrançois Tigeot cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); 1096ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1097926deccbSFrançois Tigeot } 1098926deccbSFrançois Tigeot 109957e252bfSMichael Neumann static void radeon_pm_suspend_dpm(struct radeon_device *rdev) 110057e252bfSMichael Neumann { 1101*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 110257e252bfSMichael Neumann /* disable dpm */ 110357e252bfSMichael Neumann radeon_dpm_disable(rdev); 110457e252bfSMichael Neumann /* reset the power state */ 110557e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; 110657e252bfSMichael Neumann rdev->pm.dpm_enabled = false; 1107*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 110857e252bfSMichael Neumann } 110957e252bfSMichael Neumann 111057e252bfSMichael Neumann void radeon_pm_suspend(struct radeon_device *rdev) 111157e252bfSMichael Neumann { 111257e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 111357e252bfSMichael Neumann radeon_pm_suspend_dpm(rdev); 111457e252bfSMichael Neumann else 111557e252bfSMichael Neumann radeon_pm_suspend_old(rdev); 111657e252bfSMichael Neumann } 111757e252bfSMichael Neumann 111857e252bfSMichael Neumann static void radeon_pm_resume_old(struct radeon_device *rdev) 1119926deccbSFrançois Tigeot { 1120926deccbSFrançois Tigeot /* set up the default clocks if the MC ucode is loaded */ 1121926deccbSFrançois Tigeot if ((rdev->family >= CHIP_BARTS) && 11224cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 1123926deccbSFrançois Tigeot rdev->mc_fw) { 1124926deccbSFrançois Tigeot if (rdev->pm.default_vddc) 1125926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 1126926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDC); 1127926deccbSFrançois Tigeot if (rdev->pm.default_vddci) 1128926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 1129926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDCI); 1130926deccbSFrançois Tigeot if (rdev->pm.default_sclk) 1131926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 1132926deccbSFrançois Tigeot if (rdev->pm.default_mclk) 1133926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 1134926deccbSFrançois Tigeot } 1135926deccbSFrançois Tigeot /* asic init will reset the default power state */ 1136*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1137926deccbSFrançois Tigeot rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; 1138926deccbSFrançois Tigeot rdev->pm.current_clock_mode_index = 0; 1139926deccbSFrançois Tigeot rdev->pm.current_sclk = rdev->pm.default_sclk; 1140926deccbSFrançois Tigeot rdev->pm.current_mclk = rdev->pm.default_mclk; 1141c6f73aabSFrançois Tigeot if (rdev->pm.power_state) { 1142926deccbSFrançois Tigeot rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; 1143926deccbSFrançois Tigeot rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; 1144c6f73aabSFrançois Tigeot } 1145926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DYNPM 1146926deccbSFrançois Tigeot && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { 1147926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; 1148ee479021SImre Vadász #ifdef DUMBBELL_WIP 1149926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1150926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1151ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1152926deccbSFrançois Tigeot } 1153*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1154926deccbSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1155926deccbSFrançois Tigeot } 1156926deccbSFrançois Tigeot 115757e252bfSMichael Neumann static void radeon_pm_resume_dpm(struct radeon_device *rdev) 1158926deccbSFrançois Tigeot { 1159926deccbSFrançois Tigeot int ret; 1160926deccbSFrançois Tigeot 116157e252bfSMichael Neumann /* asic init will reset to the boot state */ 1162*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 116357e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; 116457e252bfSMichael Neumann radeon_dpm_setup_asic(rdev); 116557e252bfSMichael Neumann ret = radeon_dpm_enable(rdev); 1166*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1167c6f73aabSFrançois Tigeot if (ret) 1168c6f73aabSFrançois Tigeot goto dpm_resume_fail; 1169c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = true; 1170c6f73aabSFrançois Tigeot return; 1171c6f73aabSFrançois Tigeot 1172c6f73aabSFrançois Tigeot dpm_resume_fail: 117357e252bfSMichael Neumann DRM_ERROR("radeon: dpm resume failed\n"); 117457e252bfSMichael Neumann if ((rdev->family >= CHIP_BARTS) && 11754cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 117657e252bfSMichael Neumann rdev->mc_fw) { 117757e252bfSMichael Neumann if (rdev->pm.default_vddc) 117857e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 117957e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC); 118057e252bfSMichael Neumann if (rdev->pm.default_vddci) 118157e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 118257e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDCI); 118357e252bfSMichael Neumann if (rdev->pm.default_sclk) 118457e252bfSMichael Neumann radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 118557e252bfSMichael Neumann if (rdev->pm.default_mclk) 118657e252bfSMichael Neumann radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 118757e252bfSMichael Neumann } 118857e252bfSMichael Neumann } 118957e252bfSMichael Neumann 119057e252bfSMichael Neumann void radeon_pm_resume(struct radeon_device *rdev) 119157e252bfSMichael Neumann { 119257e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 119357e252bfSMichael Neumann radeon_pm_resume_dpm(rdev); 119457e252bfSMichael Neumann else 119557e252bfSMichael Neumann radeon_pm_resume_old(rdev); 119657e252bfSMichael Neumann } 119757e252bfSMichael Neumann 119857e252bfSMichael Neumann static int radeon_pm_init_old(struct radeon_device *rdev) 119957e252bfSMichael Neumann { 120057e252bfSMichael Neumann int ret; 120157e252bfSMichael Neumann 1202926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT; 1203926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; 1204926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 1205926deccbSFrançois Tigeot rdev->pm.dynpm_can_upclock = true; 1206926deccbSFrançois Tigeot rdev->pm.dynpm_can_downclock = true; 1207926deccbSFrançois Tigeot rdev->pm.default_sclk = rdev->clock.default_sclk; 1208926deccbSFrançois Tigeot rdev->pm.default_mclk = rdev->clock.default_mclk; 1209926deccbSFrançois Tigeot rdev->pm.current_sclk = rdev->clock.default_sclk; 1210926deccbSFrançois Tigeot rdev->pm.current_mclk = rdev->clock.default_mclk; 1211926deccbSFrançois Tigeot rdev->pm.int_thermal_type = THERMAL_TYPE_NONE; 1212926deccbSFrançois Tigeot 1213926deccbSFrançois Tigeot if (rdev->bios) { 1214926deccbSFrançois Tigeot if (rdev->is_atom_bios) 1215926deccbSFrançois Tigeot radeon_atombios_get_power_modes(rdev); 1216926deccbSFrançois Tigeot else 1217926deccbSFrançois Tigeot radeon_combios_get_power_modes(rdev); 1218926deccbSFrançois Tigeot radeon_pm_print_states(rdev); 1219926deccbSFrançois Tigeot radeon_pm_init_profile(rdev); 1220926deccbSFrançois Tigeot /* set up the default clocks if the MC ucode is loaded */ 1221926deccbSFrançois Tigeot if ((rdev->family >= CHIP_BARTS) && 12224cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 1223926deccbSFrançois Tigeot rdev->mc_fw) { 1224926deccbSFrançois Tigeot if (rdev->pm.default_vddc) 1225926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 1226926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDC); 1227926deccbSFrançois Tigeot if (rdev->pm.default_vddci) 1228926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 1229926deccbSFrançois Tigeot SET_VOLTAGE_TYPE_ASIC_VDDCI); 1230926deccbSFrançois Tigeot if (rdev->pm.default_sclk) 1231926deccbSFrançois Tigeot radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 1232926deccbSFrançois Tigeot if (rdev->pm.default_mclk) 1233926deccbSFrançois Tigeot radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 1234926deccbSFrançois Tigeot } 1235926deccbSFrançois Tigeot } 1236926deccbSFrançois Tigeot 1237926deccbSFrançois Tigeot /* set up the internal thermal sensor if applicable */ 1238926deccbSFrançois Tigeot ret = radeon_hwmon_init(rdev); 1239926deccbSFrançois Tigeot if (ret) 1240926deccbSFrançois Tigeot return ret; 1241926deccbSFrançois Tigeot 1242ee479021SImre Vadász #ifdef DUMBBELL_WIP 1243926deccbSFrançois Tigeot INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); 1244ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1245926deccbSFrançois Tigeot 1246926deccbSFrançois Tigeot if (rdev->pm.num_power_states > 1) { 1247ee479021SImre Vadász /* where's the best place to put these? */ 1248ee479021SImre Vadász #ifdef DUMBBELL_WIP 1249ee479021SImre Vadász ret = device_create_file(rdev->dev, &dev_attr_power_profile); 1250ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1251ee479021SImre Vadász if (ret) 1252ee479021SImre Vadász DRM_ERROR("failed to create device file for power profile\n"); 1253ee479021SImre Vadász #ifdef DUMBBELL_WIP 1254ee479021SImre Vadász ret = device_create_file(rdev->dev, &dev_attr_power_method); 1255ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1256ee479021SImre Vadász if (ret) 1257ee479021SImre Vadász DRM_ERROR("failed to create device file for power method\n"); 1258ee479021SImre Vadász 1259926deccbSFrançois Tigeot if (radeon_debugfs_pm_init(rdev)) { 1260926deccbSFrançois Tigeot DRM_ERROR("Failed to register debugfs file for PM!\n"); 1261926deccbSFrançois Tigeot } 1262926deccbSFrançois Tigeot 1263926deccbSFrançois Tigeot DRM_INFO("radeon: power management initialized\n"); 1264926deccbSFrançois Tigeot } 1265926deccbSFrançois Tigeot 1266926deccbSFrançois Tigeot return 0; 1267926deccbSFrançois Tigeot } 1268926deccbSFrançois Tigeot 126957e252bfSMichael Neumann static void radeon_dpm_print_power_states(struct radeon_device *rdev) 127057e252bfSMichael Neumann { 127157e252bfSMichael Neumann int i; 127257e252bfSMichael Neumann 127357e252bfSMichael Neumann for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 127457e252bfSMichael Neumann printk("== power state %d ==\n", i); 127557e252bfSMichael Neumann radeon_dpm_print_power_state(rdev, &rdev->pm.dpm.ps[i]); 127657e252bfSMichael Neumann } 127757e252bfSMichael Neumann } 127857e252bfSMichael Neumann 127957e252bfSMichael Neumann static int radeon_pm_init_dpm(struct radeon_device *rdev) 128057e252bfSMichael Neumann { 128157e252bfSMichael Neumann int ret; 128257e252bfSMichael Neumann 12834cd92098Szrj /* default to balanced state */ 128457e252bfSMichael Neumann rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED; 128557e252bfSMichael Neumann rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED; 12864cd92098Szrj rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; 128757e252bfSMichael Neumann rdev->pm.default_sclk = rdev->clock.default_sclk; 128857e252bfSMichael Neumann rdev->pm.default_mclk = rdev->clock.default_mclk; 128957e252bfSMichael Neumann rdev->pm.current_sclk = rdev->clock.default_sclk; 129057e252bfSMichael Neumann rdev->pm.current_mclk = rdev->clock.default_mclk; 129157e252bfSMichael Neumann rdev->pm.int_thermal_type = THERMAL_TYPE_NONE; 129257e252bfSMichael Neumann 129357e252bfSMichael Neumann if (rdev->bios && rdev->is_atom_bios) 129457e252bfSMichael Neumann radeon_atombios_get_power_modes(rdev); 129557e252bfSMichael Neumann else 129657e252bfSMichael Neumann return -EINVAL; 129757e252bfSMichael Neumann 129857e252bfSMichael Neumann /* set up the internal thermal sensor if applicable */ 129957e252bfSMichael Neumann ret = radeon_hwmon_init(rdev); 130057e252bfSMichael Neumann if (ret) 130157e252bfSMichael Neumann return ret; 130257e252bfSMichael Neumann 13032c5cc6b9SFrançois Tigeot INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler); 13042c5cc6b9SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 130557e252bfSMichael Neumann radeon_dpm_init(rdev); 130657e252bfSMichael Neumann rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; 1307c6f73aabSFrançois Tigeot if (radeon_dpm == 1) 130857e252bfSMichael Neumann radeon_dpm_print_power_states(rdev); 130957e252bfSMichael Neumann radeon_dpm_setup_asic(rdev); 131057e252bfSMichael Neumann ret = radeon_dpm_enable(rdev); 13112c5cc6b9SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1312c6f73aabSFrançois Tigeot if (ret) 1313c6f73aabSFrançois Tigeot goto dpm_failed; 1314c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = true; 1315c6f73aabSFrançois Tigeot 1316c6f73aabSFrançois Tigeot #ifdef TODO_DEVICE_FILE 1317ee479021SImre Vadász ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); 1318ee479021SImre Vadász if (ret) 1319ee479021SImre Vadász DRM_ERROR("failed to create device file for dpm state\n"); 1320ee479021SImre Vadász ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); 1321ee479021SImre Vadász if (ret) 1322ee479021SImre Vadász DRM_ERROR("failed to create device file for dpm state\n"); 1323ee479021SImre Vadász /* XXX: these are noops for dpm but are here for backwards compat */ 1324ee479021SImre Vadász ret = device_create_file(rdev->dev, &dev_attr_power_profile); 1325ee479021SImre Vadász if (ret) 1326ee479021SImre Vadász DRM_ERROR("failed to create device file for power profile\n"); 1327ee479021SImre Vadász ret = device_create_file(rdev->dev, &dev_attr_power_method); 1328ee479021SImre Vadász if (ret) 1329ee479021SImre Vadász DRM_ERROR("failed to create device file for power method\n"); 1330ee479021SImre Vadász 1331c6f73aabSFrançois Tigeot if (radeon_debugfs_pm_init(rdev)) { 1332c6f73aabSFrançois Tigeot DRM_ERROR("Failed to register debugfs file for dpm!\n"); 1333c6f73aabSFrançois Tigeot } 1334c6f73aabSFrançois Tigeot #endif 1335c6f73aabSFrançois Tigeot 1336c6f73aabSFrançois Tigeot DRM_INFO("radeon: dpm initialized\n"); 1337c6f73aabSFrançois Tigeot 1338c6f73aabSFrançois Tigeot return 0; 1339c6f73aabSFrançois Tigeot 1340c6f73aabSFrançois Tigeot dpm_failed: 134157e252bfSMichael Neumann rdev->pm.dpm_enabled = false; 134257e252bfSMichael Neumann if ((rdev->family >= CHIP_BARTS) && 13434cd92098Szrj (rdev->family <= CHIP_CAYMAN) && 134457e252bfSMichael Neumann rdev->mc_fw) { 134557e252bfSMichael Neumann if (rdev->pm.default_vddc) 134657e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, 134757e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC); 134857e252bfSMichael Neumann if (rdev->pm.default_vddci) 134957e252bfSMichael Neumann radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, 135057e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDCI); 135157e252bfSMichael Neumann if (rdev->pm.default_sclk) 135257e252bfSMichael Neumann radeon_set_engine_clock(rdev, rdev->pm.default_sclk); 135357e252bfSMichael Neumann if (rdev->pm.default_mclk) 135457e252bfSMichael Neumann radeon_set_memory_clock(rdev, rdev->pm.default_mclk); 135557e252bfSMichael Neumann } 135657e252bfSMichael Neumann DRM_ERROR("radeon: dpm initialization failed\n"); 135757e252bfSMichael Neumann return ret; 135857e252bfSMichael Neumann } 135957e252bfSMichael Neumann 136057e252bfSMichael Neumann int radeon_pm_init(struct radeon_device *rdev) 136157e252bfSMichael Neumann { 136257e252bfSMichael Neumann /* enable dpm on rv6xx+ */ 136357e252bfSMichael Neumann switch (rdev->family) { 136457e252bfSMichael Neumann case CHIP_RV610: 136557e252bfSMichael Neumann case CHIP_RV630: 136657e252bfSMichael Neumann case CHIP_RV620: 136757e252bfSMichael Neumann case CHIP_RV635: 136857e252bfSMichael Neumann case CHIP_RV670: 136957e252bfSMichael Neumann case CHIP_RS780: 137057e252bfSMichael Neumann case CHIP_RS880: 137157e252bfSMichael Neumann case CHIP_RV770: 1372c6f73aabSFrançois Tigeot /* DPM requires the RLC, RV770+ dGPU requires SMC */ 1373c6f73aabSFrançois Tigeot if (!rdev->rlc_fw) 1374c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 1375c6f73aabSFrançois Tigeot else if ((rdev->family >= CHIP_RV770) && 1376c6f73aabSFrançois Tigeot (!(rdev->flags & RADEON_IS_IGP)) && 1377c6f73aabSFrançois Tigeot (!rdev->smc_fw)) 1378c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 1379c6f73aabSFrançois Tigeot else if (radeon_dpm == 1) 1380c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DPM; 1381c6f73aabSFrançois Tigeot else 1382c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_PROFILE; 1383c6f73aabSFrançois Tigeot break; 138457e252bfSMichael Neumann case CHIP_RV730: 138557e252bfSMichael Neumann case CHIP_RV710: 138657e252bfSMichael Neumann case CHIP_RV740: 138757e252bfSMichael Neumann case CHIP_CEDAR: 138857e252bfSMichael Neumann case CHIP_REDWOOD: 138957e252bfSMichael Neumann case CHIP_JUNIPER: 139057e252bfSMichael Neumann case CHIP_CYPRESS: 139157e252bfSMichael Neumann case CHIP_HEMLOCK: 139257e252bfSMichael Neumann case CHIP_PALM: 139357e252bfSMichael Neumann case CHIP_SUMO: 139457e252bfSMichael Neumann case CHIP_SUMO2: 139557e252bfSMichael Neumann case CHIP_BARTS: 139657e252bfSMichael Neumann case CHIP_TURKS: 139757e252bfSMichael Neumann case CHIP_CAICOS: 139857e252bfSMichael Neumann case CHIP_CAYMAN: 139957e252bfSMichael Neumann case CHIP_ARUBA: 140057e252bfSMichael Neumann case CHIP_TAHITI: 140157e252bfSMichael Neumann case CHIP_PITCAIRN: 140257e252bfSMichael Neumann case CHIP_VERDE: 140357e252bfSMichael Neumann case CHIP_OLAND: 140457e252bfSMichael Neumann case CHIP_HAINAN: 14054cd92098Szrj case CHIP_BONAIRE: 14064cd92098Szrj case CHIP_KABINI: 14074cd92098Szrj case CHIP_KAVERI: 1408c6f73aabSFrançois Tigeot case CHIP_HAWAII: 1409c6f73aabSFrançois Tigeot case CHIP_MULLINS: 141057e252bfSMichael Neumann /* DPM requires the RLC, RV770+ dGPU requires SMC */ 141157e252bfSMichael Neumann if (!rdev->rlc_fw) 141257e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 141357e252bfSMichael Neumann else if ((rdev->family >= CHIP_RV770) && 141457e252bfSMichael Neumann (!(rdev->flags & RADEON_IS_IGP)) && 141557e252bfSMichael Neumann (!rdev->smc_fw)) 141657e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 1417c6f73aabSFrançois Tigeot else if (radeon_dpm == 0) 141857e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 1419c6f73aabSFrançois Tigeot else 1420c6f73aabSFrançois Tigeot rdev->pm.pm_method = PM_METHOD_DPM; 142157e252bfSMichael Neumann break; 142257e252bfSMichael Neumann default: 142357e252bfSMichael Neumann /* default to profile method */ 142457e252bfSMichael Neumann rdev->pm.pm_method = PM_METHOD_PROFILE; 142557e252bfSMichael Neumann break; 142657e252bfSMichael Neumann } 142757e252bfSMichael Neumann 142857e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 142957e252bfSMichael Neumann return radeon_pm_init_dpm(rdev); 143057e252bfSMichael Neumann else 143157e252bfSMichael Neumann return radeon_pm_init_old(rdev); 143257e252bfSMichael Neumann } 143357e252bfSMichael Neumann 1434c6f73aabSFrançois Tigeot int radeon_pm_late_init(struct radeon_device *rdev) 1435c6f73aabSFrançois Tigeot { 1436c6f73aabSFrançois Tigeot int ret = 0; 1437c6f73aabSFrançois Tigeot 1438c6f73aabSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_DPM) { 1439*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1440c6f73aabSFrançois Tigeot ret = radeon_dpm_late_enable(rdev); 1441*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1442c6f73aabSFrançois Tigeot } 1443c6f73aabSFrançois Tigeot return ret; 1444c6f73aabSFrançois Tigeot } 1445c6f73aabSFrançois Tigeot 144657e252bfSMichael Neumann static void radeon_pm_fini_old(struct radeon_device *rdev) 1447926deccbSFrançois Tigeot { 1448926deccbSFrançois Tigeot if (rdev->pm.num_power_states > 1) { 1449*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1450926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) { 1451926deccbSFrançois Tigeot rdev->pm.profile = PM_PROFILE_DEFAULT; 1452926deccbSFrançois Tigeot radeon_pm_update_profile(rdev); 1453926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1454926deccbSFrançois Tigeot } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { 1455926deccbSFrançois Tigeot /* reset default clocks */ 1456926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; 1457926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; 1458926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1459926deccbSFrançois Tigeot } 1460*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1461926deccbSFrançois Tigeot 1462926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1463ee479021SImre Vadász cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); 1464ee479021SImre Vadász 1465926deccbSFrançois Tigeot device_remove_file(rdev->dev, &dev_attr_power_profile); 1466926deccbSFrançois Tigeot device_remove_file(rdev->dev, &dev_attr_power_method); 1467926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1468926deccbSFrançois Tigeot } 1469926deccbSFrançois Tigeot 1470926deccbSFrançois Tigeot if (rdev->pm.power_state) { 1471926deccbSFrançois Tigeot int i; 1472926deccbSFrançois Tigeot for (i = 0; i < rdev->pm.num_power_states; ++i) { 1473c4ef309bSzrj kfree(rdev->pm.power_state[i].clock_info); 1474926deccbSFrançois Tigeot } 1475c4ef309bSzrj kfree(rdev->pm.power_state); 1476926deccbSFrançois Tigeot rdev->pm.power_state = NULL; 1477926deccbSFrançois Tigeot rdev->pm.num_power_states = 0; 1478926deccbSFrançois Tigeot } 1479926deccbSFrançois Tigeot 1480926deccbSFrançois Tigeot radeon_hwmon_fini(rdev); 1481926deccbSFrançois Tigeot } 1482926deccbSFrançois Tigeot 148357e252bfSMichael Neumann static void radeon_pm_fini_dpm(struct radeon_device *rdev) 148457e252bfSMichael Neumann { 148557e252bfSMichael Neumann if (rdev->pm.num_power_states > 1) { 1486*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 148757e252bfSMichael Neumann radeon_dpm_disable(rdev); 1488*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 148957e252bfSMichael Neumann 149057e252bfSMichael Neumann #ifdef TODO_DEVICE_FILE 149157e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_dpm_state); 149257e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); 149357e252bfSMichael Neumann /* XXX backwards compat */ 149457e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_profile); 149557e252bfSMichael Neumann device_remove_file(rdev->dev, &dev_attr_power_method); 149657e252bfSMichael Neumann #endif 149757e252bfSMichael Neumann } 149857e252bfSMichael Neumann radeon_dpm_fini(rdev); 149957e252bfSMichael Neumann 15005d6a9071Szrj /* prevents leaking 440 bytes on OLAND */ 15015d6a9071Szrj if (rdev->pm.power_state) { 15025d6a9071Szrj int i; 15035d6a9071Szrj for (i = 0; i < rdev->pm.num_power_states; ++i) { 15045d6a9071Szrj kfree(rdev->pm.power_state[i].clock_info); 15055d6a9071Szrj } 150657e252bfSMichael Neumann kfree(rdev->pm.power_state); 15075d6a9071Szrj rdev->pm.power_state = NULL; 15085d6a9071Szrj rdev->pm.num_power_states = 0; 15095d6a9071Szrj } 151057e252bfSMichael Neumann 151157e252bfSMichael Neumann radeon_hwmon_fini(rdev); 151257e252bfSMichael Neumann } 151357e252bfSMichael Neumann 151457e252bfSMichael Neumann void radeon_pm_fini(struct radeon_device *rdev) 151557e252bfSMichael Neumann { 151657e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 151757e252bfSMichael Neumann radeon_pm_fini_dpm(rdev); 151857e252bfSMichael Neumann else 151957e252bfSMichael Neumann radeon_pm_fini_old(rdev); 152057e252bfSMichael Neumann } 152157e252bfSMichael Neumann 152257e252bfSMichael Neumann static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) 1523926deccbSFrançois Tigeot { 1524926deccbSFrançois Tigeot struct drm_device *ddev = rdev->ddev; 1525926deccbSFrançois Tigeot struct drm_crtc *crtc; 1526926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc; 1527926deccbSFrançois Tigeot 1528926deccbSFrançois Tigeot if (rdev->pm.num_power_states < 2) 1529926deccbSFrançois Tigeot return; 1530926deccbSFrançois Tigeot 1531*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1532926deccbSFrançois Tigeot 1533926deccbSFrançois Tigeot rdev->pm.active_crtcs = 0; 1534926deccbSFrançois Tigeot rdev->pm.active_crtc_count = 0; 1535c6f73aabSFrançois Tigeot if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { 1536926deccbSFrançois Tigeot list_for_each_entry(crtc, 1537926deccbSFrançois Tigeot &ddev->mode_config.crtc_list, head) { 1538926deccbSFrançois Tigeot radeon_crtc = to_radeon_crtc(crtc); 1539926deccbSFrançois Tigeot if (radeon_crtc->enabled) { 1540926deccbSFrançois Tigeot rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); 1541926deccbSFrançois Tigeot rdev->pm.active_crtc_count++; 1542926deccbSFrançois Tigeot } 1543926deccbSFrançois Tigeot } 1544c6f73aabSFrançois Tigeot } 1545926deccbSFrançois Tigeot 1546926deccbSFrançois Tigeot if (rdev->pm.pm_method == PM_METHOD_PROFILE) { 1547926deccbSFrançois Tigeot radeon_pm_update_profile(rdev); 1548926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1549926deccbSFrançois Tigeot } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { 1550926deccbSFrançois Tigeot if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) { 1551926deccbSFrançois Tigeot if (rdev->pm.active_crtc_count > 1) { 1552926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { 1553ee479021SImre Vadász #ifdef DUMBBELL_WIP 1554926deccbSFrançois Tigeot cancel_delayed_work(&rdev->pm.dynpm_idle_work); 1555ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1556926deccbSFrançois Tigeot 1557926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; 1558926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; 1559926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1560926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1561926deccbSFrançois Tigeot 1562926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("radeon: dynamic power management deactivated\n"); 1563926deccbSFrançois Tigeot } 1564926deccbSFrançois Tigeot } else if (rdev->pm.active_crtc_count == 1) { 1565926deccbSFrançois Tigeot /* TODO: Increase clocks if needed for current mode */ 1566926deccbSFrançois Tigeot 1567926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_MINIMUM) { 1568926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; 1569926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_UPCLOCK; 1570926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1571926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1572926deccbSFrançois Tigeot 1573ee479021SImre Vadász #ifdef DUMBBELL_WIP 1574926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1575926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1576ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1577926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) { 1578926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; 1579ee479021SImre Vadász #ifdef DUMBBELL_WIP 1580926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1581926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1582ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1583926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n"); 1584926deccbSFrançois Tigeot } 1585926deccbSFrançois Tigeot } else { /* count == 0 */ 1586926deccbSFrançois Tigeot if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) { 1587ee479021SImre Vadász #ifdef DUMBBELL_WIP 1588926deccbSFrançois Tigeot cancel_delayed_work(&rdev->pm.dynpm_idle_work); 1589ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1590926deccbSFrançois Tigeot 1591926deccbSFrançois Tigeot rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM; 1592926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM; 1593926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1594926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1595926deccbSFrançois Tigeot } 1596926deccbSFrançois Tigeot } 1597926deccbSFrançois Tigeot } 1598926deccbSFrançois Tigeot } 1599926deccbSFrançois Tigeot 1600*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1601926deccbSFrançois Tigeot } 1602926deccbSFrançois Tigeot 160357e252bfSMichael Neumann static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) 160457e252bfSMichael Neumann { 160557e252bfSMichael Neumann struct drm_device *ddev = rdev->ddev; 160657e252bfSMichael Neumann struct drm_crtc *crtc; 160757e252bfSMichael Neumann struct radeon_crtc *radeon_crtc; 160857e252bfSMichael Neumann 1609c6f73aabSFrançois Tigeot if (!rdev->pm.dpm_enabled) 1610c6f73aabSFrançois Tigeot return; 1611c6f73aabSFrançois Tigeot 1612*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 161357e252bfSMichael Neumann 161457e252bfSMichael Neumann /* update active crtc counts */ 161557e252bfSMichael Neumann rdev->pm.dpm.new_active_crtcs = 0; 161657e252bfSMichael Neumann rdev->pm.dpm.new_active_crtc_count = 0; 1617c6f73aabSFrançois Tigeot if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { 161857e252bfSMichael Neumann list_for_each_entry(crtc, 161957e252bfSMichael Neumann &ddev->mode_config.crtc_list, head) { 162057e252bfSMichael Neumann radeon_crtc = to_radeon_crtc(crtc); 162157e252bfSMichael Neumann if (crtc->enabled) { 162257e252bfSMichael Neumann rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); 162357e252bfSMichael Neumann rdev->pm.dpm.new_active_crtc_count++; 162457e252bfSMichael Neumann } 162557e252bfSMichael Neumann } 1626c6f73aabSFrançois Tigeot } 162757e252bfSMichael Neumann 162857e252bfSMichael Neumann /* update battery/ac status */ 162957e252bfSMichael Neumann if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) 163057e252bfSMichael Neumann rdev->pm.dpm.ac_power = true; 163157e252bfSMichael Neumann else 163257e252bfSMichael Neumann rdev->pm.dpm.ac_power = false; 163357e252bfSMichael Neumann 163457e252bfSMichael Neumann radeon_dpm_change_power_state_locked(rdev); 163557e252bfSMichael Neumann 1636*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1637c6f73aabSFrançois Tigeot 163857e252bfSMichael Neumann } 163957e252bfSMichael Neumann 164057e252bfSMichael Neumann void radeon_pm_compute_clocks(struct radeon_device *rdev) 164157e252bfSMichael Neumann { 164257e252bfSMichael Neumann if (rdev->pm.pm_method == PM_METHOD_DPM) 164357e252bfSMichael Neumann radeon_pm_compute_clocks_dpm(rdev); 164457e252bfSMichael Neumann else 164557e252bfSMichael Neumann radeon_pm_compute_clocks_old(rdev); 164657e252bfSMichael Neumann } 164757e252bfSMichael Neumann 1648926deccbSFrançois Tigeot static bool radeon_pm_in_vbl(struct radeon_device *rdev) 1649926deccbSFrançois Tigeot { 1650926deccbSFrançois Tigeot int crtc, vpos, hpos, vbl_status; 1651926deccbSFrançois Tigeot bool in_vbl = true; 1652926deccbSFrançois Tigeot 1653926deccbSFrançois Tigeot /* Iterate over all active crtc's. All crtc's must be in vblank, 1654926deccbSFrançois Tigeot * otherwise return in_vbl == false. 1655926deccbSFrançois Tigeot */ 1656926deccbSFrançois Tigeot for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { 1657926deccbSFrançois Tigeot if (rdev->pm.active_crtcs & (1 << crtc)) { 1658ee479021SImre Vadász vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, 1659352ff8bdSFrançois Tigeot &vpos, &hpos, NULL, NULL, 1660352ff8bdSFrançois Tigeot &rdev->mode_info.crtcs[crtc]->base.hwmode); 1661926deccbSFrançois Tigeot if ((vbl_status & DRM_SCANOUTPOS_VALID) && 16621b13d190SFrançois Tigeot !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK)) 1663926deccbSFrançois Tigeot in_vbl = false; 1664926deccbSFrançois Tigeot } 1665926deccbSFrançois Tigeot } 1666926deccbSFrançois Tigeot 1667926deccbSFrançois Tigeot return in_vbl; 1668926deccbSFrançois Tigeot } 1669926deccbSFrançois Tigeot 1670926deccbSFrançois Tigeot static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) 1671926deccbSFrançois Tigeot { 1672926deccbSFrançois Tigeot u32 stat_crtc = 0; 1673926deccbSFrançois Tigeot bool in_vbl = radeon_pm_in_vbl(rdev); 1674926deccbSFrançois Tigeot 1675926deccbSFrançois Tigeot if (in_vbl == false) 1676926deccbSFrançois Tigeot DRM_DEBUG_DRIVER("not in vbl for pm change %08x at %s\n", stat_crtc, 1677926deccbSFrançois Tigeot finish ? "exit" : "entry"); 1678926deccbSFrançois Tigeot return in_vbl; 1679926deccbSFrançois Tigeot } 1680926deccbSFrançois Tigeot 1681ee479021SImre Vadász #ifdef DUMBBELL_WIP 1682926deccbSFrançois Tigeot static void radeon_dynpm_idle_work_handler(struct work_struct *work) 1683926deccbSFrançois Tigeot { 1684926deccbSFrançois Tigeot struct radeon_device *rdev; 1685926deccbSFrançois Tigeot int resched; 1686926deccbSFrançois Tigeot rdev = container_of(work, struct radeon_device, 1687926deccbSFrançois Tigeot pm.dynpm_idle_work.work); 1688926deccbSFrançois Tigeot 1689926deccbSFrançois Tigeot resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); 1690*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 1691926deccbSFrançois Tigeot if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { 1692926deccbSFrançois Tigeot int not_processed = 0; 1693926deccbSFrançois Tigeot int i; 1694926deccbSFrançois Tigeot 1695926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1696926deccbSFrançois Tigeot struct radeon_ring *ring = &rdev->ring[i]; 1697926deccbSFrançois Tigeot 1698926deccbSFrançois Tigeot if (ring->ready) { 1699926deccbSFrançois Tigeot not_processed += radeon_fence_count_emitted(rdev, i); 1700926deccbSFrançois Tigeot if (not_processed >= 3) 1701926deccbSFrançois Tigeot break; 1702926deccbSFrançois Tigeot } 1703926deccbSFrançois Tigeot } 1704926deccbSFrançois Tigeot 1705926deccbSFrançois Tigeot if (not_processed >= 3) { /* should upclock */ 1706926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_DOWNCLOCK) { 1707926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 1708926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE && 1709926deccbSFrançois Tigeot rdev->pm.dynpm_can_upclock) { 1710926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = 1711926deccbSFrançois Tigeot DYNPM_ACTION_UPCLOCK; 1712926deccbSFrançois Tigeot rdev->pm.dynpm_action_timeout = jiffies + 1713926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); 1714926deccbSFrançois Tigeot } 1715926deccbSFrançois Tigeot } else if (not_processed == 0) { /* should downclock */ 1716926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_UPCLOCK) { 1717926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; 1718926deccbSFrançois Tigeot } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE && 1719926deccbSFrançois Tigeot rdev->pm.dynpm_can_downclock) { 1720926deccbSFrançois Tigeot rdev->pm.dynpm_planned_action = 1721926deccbSFrançois Tigeot DYNPM_ACTION_DOWNCLOCK; 1722926deccbSFrançois Tigeot rdev->pm.dynpm_action_timeout = jiffies + 1723926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); 1724926deccbSFrançois Tigeot } 1725926deccbSFrançois Tigeot } 1726926deccbSFrançois Tigeot 1727926deccbSFrançois Tigeot /* Note, radeon_pm_set_clocks is called with static_switch set 1728926deccbSFrançois Tigeot * to false since we want to wait for vbl to avoid flicker. 1729926deccbSFrançois Tigeot */ 1730926deccbSFrançois Tigeot if (rdev->pm.dynpm_planned_action != DYNPM_ACTION_NONE && 1731926deccbSFrançois Tigeot jiffies > rdev->pm.dynpm_action_timeout) { 1732926deccbSFrançois Tigeot radeon_pm_get_dynpm_state(rdev); 1733926deccbSFrançois Tigeot radeon_pm_set_clocks(rdev); 1734926deccbSFrançois Tigeot } 1735926deccbSFrançois Tigeot 1736926deccbSFrançois Tigeot schedule_delayed_work(&rdev->pm.dynpm_idle_work, 1737926deccbSFrançois Tigeot msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 1738926deccbSFrançois Tigeot } 1739*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 1740926deccbSFrançois Tigeot ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); 1741926deccbSFrançois Tigeot } 1742ee479021SImre Vadász #endif /* DUMBBELL_WIP */ 1743926deccbSFrançois Tigeot 1744926deccbSFrançois Tigeot /* 1745926deccbSFrançois Tigeot * Debugfs info 1746926deccbSFrançois Tigeot */ 1747926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1748926deccbSFrançois Tigeot 1749926deccbSFrançois Tigeot static int radeon_debugfs_pm_info(struct seq_file *m, void *data) 1750926deccbSFrançois Tigeot { 1751926deccbSFrançois Tigeot struct drm_info_node *node = (struct drm_info_node *) m->private; 1752926deccbSFrançois Tigeot struct drm_device *dev = node->minor->dev; 1753926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1754c6f73aabSFrançois Tigeot struct drm_device *ddev = rdev->ddev; 1755926deccbSFrançois Tigeot 1756c6f73aabSFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && 1757c6f73aabSFrançois Tigeot (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { 1758c6f73aabSFrançois Tigeot seq_printf(m, "PX asic powered off\n"); 1759c6f73aabSFrançois Tigeot } else if (rdev->pm.dpm_enabled) { 1760*1cfef1a5SFrançois Tigeot mutex_lock(&rdev->pm.mutex); 176157e252bfSMichael Neumann if (rdev->asic->dpm.debugfs_print_current_performance_level) 176257e252bfSMichael Neumann radeon_dpm_debugfs_print_current_performance_level(rdev, m); 176357e252bfSMichael Neumann else 176457e252bfSMichael Neumann seq_printf(m, "Debugfs support not implemented for this asic\n"); 1765*1cfef1a5SFrançois Tigeot mutex_unlock(&rdev->pm.mutex); 176657e252bfSMichael Neumann } else { 1767926deccbSFrançois Tigeot seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk); 1768f43cf1b1SMichael Neumann /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */ 1769f43cf1b1SMichael Neumann if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP)) 1770f43cf1b1SMichael Neumann seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk); 1771f43cf1b1SMichael Neumann else 1772926deccbSFrançois Tigeot seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); 1773926deccbSFrançois Tigeot seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk); 1774926deccbSFrançois Tigeot if (rdev->asic->pm.get_memory_clock) 1775926deccbSFrançois Tigeot seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); 1776926deccbSFrançois Tigeot if (rdev->pm.current_vddc) 1777926deccbSFrançois Tigeot seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc); 1778926deccbSFrançois Tigeot if (rdev->asic->pm.get_pcie_lanes) 1779926deccbSFrançois Tigeot seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev)); 178057e252bfSMichael Neumann } 1781926deccbSFrançois Tigeot 1782926deccbSFrançois Tigeot return 0; 1783926deccbSFrançois Tigeot } 1784926deccbSFrançois Tigeot 1785926deccbSFrançois Tigeot static struct drm_info_list radeon_pm_info_list[] = { 1786926deccbSFrançois Tigeot {"radeon_pm_info", radeon_debugfs_pm_info, 0, NULL}, 1787926deccbSFrançois Tigeot }; 1788926deccbSFrançois Tigeot #endif 1789926deccbSFrançois Tigeot 1790926deccbSFrançois Tigeot static int radeon_debugfs_pm_init(struct radeon_device *rdev) 1791926deccbSFrançois Tigeot { 1792926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1793926deccbSFrançois Tigeot return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list)); 1794926deccbSFrançois Tigeot #else 1795926deccbSFrançois Tigeot return 0; 1796926deccbSFrançois Tigeot #endif 1797926deccbSFrançois Tigeot } 1798