17433874eSRafał Miłecki /* 27433874eSRafał Miłecki * Permission is hereby granted, free of charge, to any person obtaining a 37433874eSRafał Miłecki * copy of this software and associated documentation files (the "Software"), 47433874eSRafał Miłecki * to deal in the Software without restriction, including without limitation 57433874eSRafał Miłecki * the rights to use, copy, modify, merge, publish, distribute, sublicense, 67433874eSRafał Miłecki * and/or sell copies of the Software, and to permit persons to whom the 77433874eSRafał Miłecki * Software is furnished to do so, subject to the following conditions: 87433874eSRafał Miłecki * 97433874eSRafał Miłecki * The above copyright notice and this permission notice shall be included in 107433874eSRafał Miłecki * all copies or substantial portions of the Software. 117433874eSRafał Miłecki * 127433874eSRafał Miłecki * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 137433874eSRafał Miłecki * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 147433874eSRafał Miłecki * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 157433874eSRafał Miłecki * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 167433874eSRafał Miłecki * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 177433874eSRafał Miłecki * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 187433874eSRafał Miłecki * OTHER DEALINGS IN THE SOFTWARE. 197433874eSRafał Miłecki * 207433874eSRafał Miłecki * Authors: Rafał Miłecki <zajec5@gmail.com> 2156278a8eSAlex Deucher * Alex Deucher <alexdeucher@gmail.com> 227433874eSRafał Miłecki */ 237433874eSRafał Miłecki #include "drmP.h" 247433874eSRafał Miłecki #include "radeon.h" 25f735261bSDave Airlie #include "avivod.h" 267433874eSRafał Miłecki 27c913e23aSRafał Miłecki #define RADEON_IDLE_LOOP_MS 100 28c913e23aSRafał Miłecki #define RADEON_RECLOCK_DELAY_MS 200 2973a6d3fcSRafał Miłecki #define RADEON_WAIT_VBLANK_TIMEOUT 200 302031f77cSAlex Deucher #define RADEON_WAIT_IDLE_TIMEOUT 200 31c913e23aSRafał Miłecki 32c913e23aSRafał Miłecki static void radeon_pm_idle_work_handler(struct work_struct *work); 33c913e23aSRafał Miłecki static int radeon_debugfs_pm_init(struct radeon_device *rdev); 34c913e23aSRafał Miłecki 35*2aba631cSMatthew Garrett static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) 36a424816fSAlex Deucher { 37*2aba631cSMatthew Garrett int i; 38*2aba631cSMatthew Garrett 39a424816fSAlex Deucher mutex_lock(&rdev->cp.mutex); 40a424816fSAlex Deucher 41a424816fSAlex Deucher /* wait for GPU idle */ 42a424816fSAlex Deucher rdev->pm.gui_idle = false; 43a424816fSAlex Deucher rdev->irq.gui_idle = true; 44a424816fSAlex Deucher radeon_irq_set(rdev); 45a424816fSAlex Deucher wait_event_interruptible_timeout( 46a424816fSAlex Deucher rdev->irq.idle_queue, rdev->pm.gui_idle, 47a424816fSAlex Deucher msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); 48a424816fSAlex Deucher rdev->irq.gui_idle = false; 49a424816fSAlex Deucher radeon_irq_set(rdev); 50a424816fSAlex Deucher 51*2aba631cSMatthew Garrett if (!static_switch) { 52*2aba631cSMatthew Garrett for (i = 0; i < rdev->num_crtc; i++) { 53*2aba631cSMatthew Garrett if (rdev->pm.active_crtcs & (1 << i)) { 54*2aba631cSMatthew Garrett rdev->pm.req_vblank |= (1 << i); 55*2aba631cSMatthew Garrett drm_vblank_get(rdev->ddev, i); 56*2aba631cSMatthew Garrett } 57*2aba631cSMatthew Garrett } 58*2aba631cSMatthew Garrett } 59*2aba631cSMatthew Garrett 60*2aba631cSMatthew Garrett radeon_set_power_state(rdev, static_switch); 61*2aba631cSMatthew Garrett 62*2aba631cSMatthew Garrett if (!static_switch) { 63*2aba631cSMatthew Garrett for (i = 0; i < rdev->num_crtc; i++) { 64*2aba631cSMatthew Garrett if (rdev->pm.req_vblank & (1 << i)) { 65*2aba631cSMatthew Garrett rdev->pm.req_vblank &= ~(1 << i); 66*2aba631cSMatthew Garrett drm_vblank_put(rdev->ddev, i); 67*2aba631cSMatthew Garrett } 68*2aba631cSMatthew Garrett } 69*2aba631cSMatthew Garrett } 70a424816fSAlex Deucher 71a424816fSAlex Deucher /* update display watermarks based on new power state */ 72a424816fSAlex Deucher radeon_update_bandwidth_info(rdev); 73a424816fSAlex Deucher if (rdev->pm.active_crtc_count) 74a424816fSAlex Deucher radeon_bandwidth_update(rdev); 75a424816fSAlex Deucher 76*2aba631cSMatthew Garrett rdev->pm.planned_action = PM_ACTION_NONE; 77*2aba631cSMatthew Garrett 78a424816fSAlex Deucher mutex_unlock(&rdev->cp.mutex); 79a424816fSAlex Deucher } 80a424816fSAlex Deucher 81a424816fSAlex Deucher static ssize_t radeon_get_power_state_static(struct device *dev, 82a424816fSAlex Deucher struct device_attribute *attr, 83a424816fSAlex Deucher char *buf) 84a424816fSAlex Deucher { 85a424816fSAlex Deucher struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); 86a424816fSAlex Deucher struct radeon_device *rdev = ddev->dev_private; 87a424816fSAlex Deucher 88a424816fSAlex Deucher return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index, 89a424816fSAlex Deucher rdev->pm.current_clock_mode_index); 90a424816fSAlex Deucher } 91a424816fSAlex Deucher 92a424816fSAlex Deucher static ssize_t radeon_set_power_state_static(struct device *dev, 93a424816fSAlex Deucher struct device_attribute *attr, 94a424816fSAlex Deucher const char *buf, 95a424816fSAlex Deucher size_t count) 96a424816fSAlex Deucher { 97a424816fSAlex Deucher struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); 98a424816fSAlex Deucher struct radeon_device *rdev = ddev->dev_private; 99a424816fSAlex Deucher int ps, cm; 100a424816fSAlex Deucher 101a424816fSAlex Deucher if (sscanf(buf, "%u.%u", &ps, &cm) != 2) { 102a424816fSAlex Deucher DRM_ERROR("Invalid power state!\n"); 103a424816fSAlex Deucher return count; 104a424816fSAlex Deucher } 105a424816fSAlex Deucher 106a424816fSAlex Deucher mutex_lock(&rdev->pm.mutex); 107a424816fSAlex Deucher if ((ps >= 0) && (ps < rdev->pm.num_power_states) && 108a424816fSAlex Deucher (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { 109a424816fSAlex Deucher if ((rdev->pm.active_crtc_count > 1) && 110a424816fSAlex Deucher (rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) { 111a424816fSAlex Deucher DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm); 112a424816fSAlex Deucher } else { 113a424816fSAlex Deucher /* disable dynpm */ 114a424816fSAlex Deucher rdev->pm.state = PM_STATE_DISABLED; 115a424816fSAlex Deucher rdev->pm.planned_action = PM_ACTION_NONE; 116a424816fSAlex Deucher rdev->pm.requested_power_state_index = ps; 117a424816fSAlex Deucher rdev->pm.requested_clock_mode_index = cm; 118*2aba631cSMatthew Garrett radeon_pm_set_clocks(rdev, true); 119a424816fSAlex Deucher } 120a424816fSAlex Deucher } else 121a424816fSAlex Deucher DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); 122a424816fSAlex Deucher mutex_unlock(&rdev->pm.mutex); 123a424816fSAlex Deucher 124a424816fSAlex Deucher return count; 125a424816fSAlex Deucher } 126a424816fSAlex Deucher 127a424816fSAlex Deucher static ssize_t radeon_get_dynpm(struct device *dev, 128a424816fSAlex Deucher struct device_attribute *attr, 129a424816fSAlex Deucher char *buf) 130a424816fSAlex Deucher { 131a424816fSAlex Deucher struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); 132a424816fSAlex Deucher struct radeon_device *rdev = ddev->dev_private; 133a424816fSAlex Deucher 134a424816fSAlex Deucher return snprintf(buf, PAGE_SIZE, "%s\n", 135a424816fSAlex Deucher (rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled"); 136a424816fSAlex Deucher } 137a424816fSAlex Deucher 138a424816fSAlex Deucher static ssize_t radeon_set_dynpm(struct device *dev, 139a424816fSAlex Deucher struct device_attribute *attr, 140a424816fSAlex Deucher const char *buf, 141a424816fSAlex Deucher size_t count) 142a424816fSAlex Deucher { 143a424816fSAlex Deucher struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); 144a424816fSAlex Deucher struct radeon_device *rdev = ddev->dev_private; 145a424816fSAlex Deucher int tmp = simple_strtoul(buf, NULL, 10); 146a424816fSAlex Deucher 147a424816fSAlex Deucher if (tmp == 0) { 148a424816fSAlex Deucher /* update power mode info */ 149a424816fSAlex Deucher radeon_pm_compute_clocks(rdev); 150a424816fSAlex Deucher /* disable dynpm */ 151a424816fSAlex Deucher mutex_lock(&rdev->pm.mutex); 152a424816fSAlex Deucher rdev->pm.state = PM_STATE_DISABLED; 153a424816fSAlex Deucher rdev->pm.planned_action = PM_ACTION_NONE; 154a424816fSAlex Deucher mutex_unlock(&rdev->pm.mutex); 155a424816fSAlex Deucher DRM_INFO("radeon: dynamic power management disabled\n"); 156a424816fSAlex Deucher } else if (tmp == 1) { 157a424816fSAlex Deucher if (rdev->pm.num_power_states > 1) { 158a424816fSAlex Deucher /* enable dynpm */ 159a424816fSAlex Deucher mutex_lock(&rdev->pm.mutex); 160a424816fSAlex Deucher rdev->pm.state = PM_STATE_PAUSED; 161a424816fSAlex Deucher rdev->pm.planned_action = PM_ACTION_DEFAULT; 162a424816fSAlex Deucher radeon_get_power_state(rdev, rdev->pm.planned_action); 163a424816fSAlex Deucher mutex_unlock(&rdev->pm.mutex); 164a424816fSAlex Deucher /* update power mode info */ 165a424816fSAlex Deucher radeon_pm_compute_clocks(rdev); 166a424816fSAlex Deucher DRM_INFO("radeon: dynamic power management enabled\n"); 167a424816fSAlex Deucher } else 168a424816fSAlex Deucher DRM_ERROR("dynpm not valid on this system\n"); 169a424816fSAlex Deucher } else 170a424816fSAlex Deucher DRM_ERROR("Invalid setting: %d\n", tmp); 171a424816fSAlex Deucher 172a424816fSAlex Deucher return count; 173a424816fSAlex Deucher } 174a424816fSAlex Deucher 175a424816fSAlex Deucher static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static); 176a424816fSAlex Deucher static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm); 177a424816fSAlex Deucher 178a424816fSAlex Deucher 179c913e23aSRafał Miłecki static const char *pm_state_names[4] = { 180c913e23aSRafał Miłecki "PM_STATE_DISABLED", 181c913e23aSRafał Miłecki "PM_STATE_MINIMUM", 182c913e23aSRafał Miłecki "PM_STATE_PAUSED", 183c913e23aSRafał Miłecki "PM_STATE_ACTIVE" 184c913e23aSRafał Miłecki }; 1857433874eSRafał Miłecki 1860ec0e74fSAlex Deucher static const char *pm_state_types[5] = { 187d91eeb78SAlex Deucher "", 1880ec0e74fSAlex Deucher "Powersave", 1890ec0e74fSAlex Deucher "Battery", 1900ec0e74fSAlex Deucher "Balanced", 1910ec0e74fSAlex Deucher "Performance", 1920ec0e74fSAlex Deucher }; 1930ec0e74fSAlex Deucher 19456278a8eSAlex Deucher static void radeon_print_power_mode_info(struct radeon_device *rdev) 19556278a8eSAlex Deucher { 19656278a8eSAlex Deucher int i, j; 19756278a8eSAlex Deucher bool is_default; 19856278a8eSAlex Deucher 19956278a8eSAlex Deucher DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); 20056278a8eSAlex Deucher for (i = 0; i < rdev->pm.num_power_states; i++) { 201a48b9b4eSAlex Deucher if (rdev->pm.default_power_state_index == i) 20256278a8eSAlex Deucher is_default = true; 20356278a8eSAlex Deucher else 20456278a8eSAlex Deucher is_default = false; 2050ec0e74fSAlex Deucher DRM_INFO("State %d %s %s\n", i, 2060ec0e74fSAlex Deucher pm_state_types[rdev->pm.power_state[i].type], 2070ec0e74fSAlex Deucher is_default ? "(default)" : ""); 20856278a8eSAlex Deucher if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) 20979daedc9SAlex Deucher DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes); 210a48b9b4eSAlex Deucher if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) 211a48b9b4eSAlex Deucher DRM_INFO("\tSingle display only\n"); 21256278a8eSAlex Deucher DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); 21356278a8eSAlex Deucher for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { 21456278a8eSAlex Deucher if (rdev->flags & RADEON_IS_IGP) 21556278a8eSAlex Deucher DRM_INFO("\t\t%d engine: %d\n", 21656278a8eSAlex Deucher j, 21756278a8eSAlex Deucher rdev->pm.power_state[i].clock_info[j].sclk * 10); 21856278a8eSAlex Deucher else 21956278a8eSAlex Deucher DRM_INFO("\t\t%d engine/memory: %d/%d\n", 22056278a8eSAlex Deucher j, 22156278a8eSAlex Deucher rdev->pm.power_state[i].clock_info[j].sclk * 10, 22256278a8eSAlex Deucher rdev->pm.power_state[i].clock_info[j].mclk * 10); 22356278a8eSAlex Deucher } 22456278a8eSAlex Deucher } 22556278a8eSAlex Deucher } 22656278a8eSAlex Deucher 227bae6b562SAlex Deucher void radeon_sync_with_vblank(struct radeon_device *rdev) 228d0d6cb81SRafał Miłecki { 229d0d6cb81SRafał Miłecki if (rdev->pm.active_crtcs) { 230d0d6cb81SRafał Miłecki rdev->pm.vblank_sync = false; 231d0d6cb81SRafał Miłecki wait_event_timeout( 232d0d6cb81SRafał Miłecki rdev->irq.vblank_queue, rdev->pm.vblank_sync, 233d0d6cb81SRafał Miłecki msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); 234d0d6cb81SRafał Miłecki } 235d0d6cb81SRafał Miłecki } 236d0d6cb81SRafał Miłecki 2377433874eSRafał Miłecki int radeon_pm_init(struct radeon_device *rdev) 2387433874eSRafał Miłecki { 239c913e23aSRafał Miłecki rdev->pm.state = PM_STATE_DISABLED; 240c913e23aSRafał Miłecki rdev->pm.planned_action = PM_ACTION_NONE; 241a48b9b4eSAlex Deucher rdev->pm.can_upclock = true; 242a48b9b4eSAlex Deucher rdev->pm.can_downclock = true; 243c913e23aSRafał Miłecki 24456278a8eSAlex Deucher if (rdev->bios) { 24556278a8eSAlex Deucher if (rdev->is_atom_bios) 24656278a8eSAlex Deucher radeon_atombios_get_power_modes(rdev); 24756278a8eSAlex Deucher else 24856278a8eSAlex Deucher radeon_combios_get_power_modes(rdev); 24956278a8eSAlex Deucher radeon_print_power_mode_info(rdev); 25056278a8eSAlex Deucher } 25156278a8eSAlex Deucher 2527433874eSRafał Miłecki if (radeon_debugfs_pm_init(rdev)) { 253c142c3e5SRafał Miłecki DRM_ERROR("Failed to register debugfs file for PM!\n"); 2547433874eSRafał Miłecki } 2557433874eSRafał Miłecki 256a424816fSAlex Deucher /* where's the best place to put this? */ 257a424816fSAlex Deucher device_create_file(rdev->dev, &dev_attr_power_state); 258a424816fSAlex Deucher device_create_file(rdev->dev, &dev_attr_dynpm); 259a424816fSAlex Deucher 260c913e23aSRafał Miłecki INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); 261c913e23aSRafał Miłecki 26290c39059SAlex Deucher if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) { 263c913e23aSRafał Miłecki rdev->pm.state = PM_STATE_PAUSED; 264c913e23aSRafał Miłecki DRM_INFO("radeon: dynamic power management enabled\n"); 265c913e23aSRafał Miłecki } 266c913e23aSRafał Miłecki 267c913e23aSRafał Miłecki DRM_INFO("radeon: power management initialized\n"); 268c913e23aSRafał Miłecki 2697433874eSRafał Miłecki return 0; 2707433874eSRafał Miłecki } 2717433874eSRafał Miłecki 27229fb52caSAlex Deucher void radeon_pm_fini(struct radeon_device *rdev) 27329fb52caSAlex Deucher { 27458e21dffSAlex Deucher if (rdev->pm.state != PM_STATE_DISABLED) { 27558e21dffSAlex Deucher /* cancel work */ 27658e21dffSAlex Deucher cancel_delayed_work_sync(&rdev->pm.idle_work); 27758e21dffSAlex Deucher /* reset default clocks */ 27858e21dffSAlex Deucher rdev->pm.state = PM_STATE_DISABLED; 27958e21dffSAlex Deucher rdev->pm.planned_action = PM_ACTION_DEFAULT; 280*2aba631cSMatthew Garrett radeon_pm_set_clocks(rdev, false); 281a424816fSAlex Deucher } else if ((rdev->pm.current_power_state_index != 282a424816fSAlex Deucher rdev->pm.default_power_state_index) || 283a424816fSAlex Deucher (rdev->pm.current_clock_mode_index != 0)) { 284a424816fSAlex Deucher rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; 285a424816fSAlex Deucher rdev->pm.requested_clock_mode_index = 0; 286a424816fSAlex Deucher mutex_lock(&rdev->pm.mutex); 287*2aba631cSMatthew Garrett radeon_pm_set_clocks(rdev, true); 288a424816fSAlex Deucher mutex_unlock(&rdev->pm.mutex); 28958e21dffSAlex Deucher } 29058e21dffSAlex Deucher 291a424816fSAlex Deucher device_remove_file(rdev->dev, &dev_attr_power_state); 292a424816fSAlex Deucher device_remove_file(rdev->dev, &dev_attr_dynpm); 293a424816fSAlex Deucher 29429fb52caSAlex Deucher if (rdev->pm.i2c_bus) 29529fb52caSAlex Deucher radeon_i2c_destroy(rdev->pm.i2c_bus); 29629fb52caSAlex Deucher } 29729fb52caSAlex Deucher 298c913e23aSRafał Miłecki void radeon_pm_compute_clocks(struct radeon_device *rdev) 299c913e23aSRafał Miłecki { 300c913e23aSRafał Miłecki struct drm_device *ddev = rdev->ddev; 301a48b9b4eSAlex Deucher struct drm_crtc *crtc; 302c913e23aSRafał Miłecki struct radeon_crtc *radeon_crtc; 303c913e23aSRafał Miłecki 304c913e23aSRafał Miłecki if (rdev->pm.state == PM_STATE_DISABLED) 305c913e23aSRafał Miłecki return; 306c913e23aSRafał Miłecki 307c913e23aSRafał Miłecki mutex_lock(&rdev->pm.mutex); 308c913e23aSRafał Miłecki 309c913e23aSRafał Miłecki rdev->pm.active_crtcs = 0; 310a48b9b4eSAlex Deucher rdev->pm.active_crtc_count = 0; 311a48b9b4eSAlex Deucher list_for_each_entry(crtc, 312a48b9b4eSAlex Deucher &ddev->mode_config.crtc_list, head) { 313a48b9b4eSAlex Deucher radeon_crtc = to_radeon_crtc(crtc); 314a48b9b4eSAlex Deucher if (radeon_crtc->enabled) { 315c913e23aSRafał Miłecki rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); 316a48b9b4eSAlex Deucher rdev->pm.active_crtc_count++; 317c913e23aSRafał Miłecki } 318c913e23aSRafał Miłecki } 319c913e23aSRafał Miłecki 320a48b9b4eSAlex Deucher if (rdev->pm.active_crtc_count > 1) { 321c913e23aSRafał Miłecki if (rdev->pm.state == PM_STATE_ACTIVE) { 322c913e23aSRafał Miłecki cancel_delayed_work(&rdev->pm.idle_work); 323c913e23aSRafał Miłecki 324c913e23aSRafał Miłecki rdev->pm.state = PM_STATE_PAUSED; 325c913e23aSRafał Miłecki rdev->pm.planned_action = PM_ACTION_UPCLOCK; 326*2aba631cSMatthew Garrett radeon_pm_set_clocks(rdev, false); 327c913e23aSRafał Miłecki 328c913e23aSRafał Miłecki DRM_DEBUG("radeon: dynamic power management deactivated\n"); 329c913e23aSRafał Miłecki } 330a48b9b4eSAlex Deucher } else if (rdev->pm.active_crtc_count == 1) { 331c913e23aSRafał Miłecki /* TODO: Increase clocks if needed for current mode */ 332c913e23aSRafał Miłecki 333c913e23aSRafał Miłecki if (rdev->pm.state == PM_STATE_MINIMUM) { 334c913e23aSRafał Miłecki rdev->pm.state = PM_STATE_ACTIVE; 335c913e23aSRafał Miłecki rdev->pm.planned_action = PM_ACTION_UPCLOCK; 336*2aba631cSMatthew Garrett radeon_pm_set_clocks(rdev, false); 337c913e23aSRafał Miłecki 338c913e23aSRafał Miłecki queue_delayed_work(rdev->wq, &rdev->pm.idle_work, 339c913e23aSRafał Miłecki msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 340a48b9b4eSAlex Deucher } else if (rdev->pm.state == PM_STATE_PAUSED) { 341c913e23aSRafał Miłecki rdev->pm.state = PM_STATE_ACTIVE; 342c913e23aSRafał Miłecki queue_delayed_work(rdev->wq, &rdev->pm.idle_work, 343c913e23aSRafał Miłecki msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 344c913e23aSRafał Miłecki DRM_DEBUG("radeon: dynamic power management activated\n"); 345c913e23aSRafał Miłecki } 346a48b9b4eSAlex Deucher } else { /* count == 0 */ 347c913e23aSRafał Miłecki if (rdev->pm.state != PM_STATE_MINIMUM) { 348c913e23aSRafał Miłecki cancel_delayed_work(&rdev->pm.idle_work); 349c913e23aSRafał Miłecki 350c913e23aSRafał Miłecki rdev->pm.state = PM_STATE_MINIMUM; 351c913e23aSRafał Miłecki rdev->pm.planned_action = PM_ACTION_MINIMUM; 352*2aba631cSMatthew Garrett radeon_pm_set_clocks(rdev, false); 35373a6d3fcSRafał Miłecki } 354c913e23aSRafał Miłecki } 355c913e23aSRafał Miłecki 356c913e23aSRafał Miłecki mutex_unlock(&rdev->pm.mutex); 357c913e23aSRafał Miłecki } 358c913e23aSRafał Miłecki 359bae6b562SAlex Deucher bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) 360f735261bSDave Airlie { 361bae6b562SAlex Deucher u32 stat_crtc = 0; 362f735261bSDave Airlie bool in_vbl = true; 363f735261bSDave Airlie 364bae6b562SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 365f735261bSDave Airlie if (rdev->pm.active_crtcs & (1 << 0)) { 366bae6b562SAlex Deucher stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); 367bae6b562SAlex Deucher if (!(stat_crtc & 1)) 368f735261bSDave Airlie in_vbl = false; 369f735261bSDave Airlie } 370f735261bSDave Airlie if (rdev->pm.active_crtcs & (1 << 1)) { 371bae6b562SAlex Deucher stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); 372bae6b562SAlex Deucher if (!(stat_crtc & 1)) 373bae6b562SAlex Deucher in_vbl = false; 374bae6b562SAlex Deucher } 375bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 2)) { 376bae6b562SAlex Deucher stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); 377bae6b562SAlex Deucher if (!(stat_crtc & 1)) 378bae6b562SAlex Deucher in_vbl = false; 379bae6b562SAlex Deucher } 380bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 3)) { 381bae6b562SAlex Deucher stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); 382bae6b562SAlex Deucher if (!(stat_crtc & 1)) 383bae6b562SAlex Deucher in_vbl = false; 384bae6b562SAlex Deucher } 385bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 4)) { 386bae6b562SAlex Deucher stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); 387bae6b562SAlex Deucher if (!(stat_crtc & 1)) 388bae6b562SAlex Deucher in_vbl = false; 389bae6b562SAlex Deucher } 390bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 5)) { 391bae6b562SAlex Deucher stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); 392bae6b562SAlex Deucher if (!(stat_crtc & 1)) 393bae6b562SAlex Deucher in_vbl = false; 394bae6b562SAlex Deucher } 395bae6b562SAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 396bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 0)) { 397bae6b562SAlex Deucher stat_crtc = RREG32(D1CRTC_STATUS); 398bae6b562SAlex Deucher if (!(stat_crtc & 1)) 399bae6b562SAlex Deucher in_vbl = false; 400bae6b562SAlex Deucher } 401bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 1)) { 402bae6b562SAlex Deucher stat_crtc = RREG32(D2CRTC_STATUS); 403bae6b562SAlex Deucher if (!(stat_crtc & 1)) 404bae6b562SAlex Deucher in_vbl = false; 405bae6b562SAlex Deucher } 406bae6b562SAlex Deucher } else { 407bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 0)) { 408bae6b562SAlex Deucher stat_crtc = RREG32(RADEON_CRTC_STATUS); 409bae6b562SAlex Deucher if (!(stat_crtc & 1)) 410bae6b562SAlex Deucher in_vbl = false; 411bae6b562SAlex Deucher } 412bae6b562SAlex Deucher if (rdev->pm.active_crtcs & (1 << 1)) { 413bae6b562SAlex Deucher stat_crtc = RREG32(RADEON_CRTC2_STATUS); 414bae6b562SAlex Deucher if (!(stat_crtc & 1)) 415f735261bSDave Airlie in_vbl = false; 416f735261bSDave Airlie } 417f735261bSDave Airlie } 418f735261bSDave Airlie if (in_vbl == false) 419bae6b562SAlex Deucher DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, 420bae6b562SAlex Deucher finish ? "exit" : "entry"); 421f735261bSDave Airlie return in_vbl; 422f735261bSDave Airlie } 423c913e23aSRafał Miłecki 424c913e23aSRafał Miłecki static void radeon_pm_idle_work_handler(struct work_struct *work) 425c913e23aSRafał Miłecki { 426c913e23aSRafał Miłecki struct radeon_device *rdev; 427c913e23aSRafał Miłecki rdev = container_of(work, struct radeon_device, 428c913e23aSRafał Miłecki pm.idle_work.work); 429c913e23aSRafał Miłecki 430c913e23aSRafał Miłecki mutex_lock(&rdev->pm.mutex); 43173a6d3fcSRafał Miłecki if (rdev->pm.state == PM_STATE_ACTIVE) { 432c913e23aSRafał Miłecki unsigned long irq_flags; 433c913e23aSRafał Miłecki int not_processed = 0; 434c913e23aSRafał Miłecki 435c913e23aSRafał Miłecki read_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 436c913e23aSRafał Miłecki if (!list_empty(&rdev->fence_drv.emited)) { 437c913e23aSRafał Miłecki struct list_head *ptr; 438c913e23aSRafał Miłecki list_for_each(ptr, &rdev->fence_drv.emited) { 439c913e23aSRafał Miłecki /* count up to 3, that's enought info */ 440c913e23aSRafał Miłecki if (++not_processed >= 3) 441c913e23aSRafał Miłecki break; 442c913e23aSRafał Miłecki } 443c913e23aSRafał Miłecki } 444c913e23aSRafał Miłecki read_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 445c913e23aSRafał Miłecki 446c913e23aSRafał Miłecki if (not_processed >= 3) { /* should upclock */ 447c913e23aSRafał Miłecki if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) { 448c913e23aSRafał Miłecki rdev->pm.planned_action = PM_ACTION_NONE; 449c913e23aSRafał Miłecki } else if (rdev->pm.planned_action == PM_ACTION_NONE && 450a48b9b4eSAlex Deucher rdev->pm.can_upclock) { 451c913e23aSRafał Miłecki rdev->pm.planned_action = 452c913e23aSRafał Miłecki PM_ACTION_UPCLOCK; 453c913e23aSRafał Miłecki rdev->pm.action_timeout = jiffies + 454c913e23aSRafał Miłecki msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); 455c913e23aSRafał Miłecki } 456c913e23aSRafał Miłecki } else if (not_processed == 0) { /* should downclock */ 457c913e23aSRafał Miłecki if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) { 458c913e23aSRafał Miłecki rdev->pm.planned_action = PM_ACTION_NONE; 459c913e23aSRafał Miłecki } else if (rdev->pm.planned_action == PM_ACTION_NONE && 460a48b9b4eSAlex Deucher rdev->pm.can_downclock) { 461c913e23aSRafał Miłecki rdev->pm.planned_action = 462c913e23aSRafał Miłecki PM_ACTION_DOWNCLOCK; 463c913e23aSRafał Miłecki rdev->pm.action_timeout = jiffies + 464c913e23aSRafał Miłecki msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); 465c913e23aSRafał Miłecki } 466c913e23aSRafał Miłecki } 467c913e23aSRafał Miłecki 468c913e23aSRafał Miłecki if (rdev->pm.planned_action != PM_ACTION_NONE && 469c913e23aSRafał Miłecki jiffies > rdev->pm.action_timeout) { 470*2aba631cSMatthew Garrett radeon_pm_set_clocks(rdev, false); 471c913e23aSRafał Miłecki } 472c913e23aSRafał Miłecki } 473c913e23aSRafał Miłecki mutex_unlock(&rdev->pm.mutex); 474c913e23aSRafał Miłecki 475c913e23aSRafał Miłecki queue_delayed_work(rdev->wq, &rdev->pm.idle_work, 476c913e23aSRafał Miłecki msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); 477c913e23aSRafał Miłecki } 478c913e23aSRafał Miłecki 4797433874eSRafał Miłecki /* 4807433874eSRafał Miłecki * Debugfs info 4817433874eSRafał Miłecki */ 4827433874eSRafał Miłecki #if defined(CONFIG_DEBUG_FS) 4837433874eSRafał Miłecki 4847433874eSRafał Miłecki static int radeon_debugfs_pm_info(struct seq_file *m, void *data) 4857433874eSRafał Miłecki { 4867433874eSRafał Miłecki struct drm_info_node *node = (struct drm_info_node *) m->private; 4877433874eSRafał Miłecki struct drm_device *dev = node->minor->dev; 4887433874eSRafał Miłecki struct radeon_device *rdev = dev->dev_private; 4897433874eSRafał Miłecki 490c913e23aSRafał Miłecki seq_printf(m, "state: %s\n", pm_state_names[rdev->pm.state]); 4916234077dSRafał Miłecki seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk); 4926234077dSRafał Miłecki seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); 4936234077dSRafał Miłecki seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); 4946234077dSRafał Miłecki if (rdev->asic->get_memory_clock) 4956234077dSRafał Miłecki seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); 496aa5120d2SRafał Miłecki if (rdev->asic->get_pcie_lanes) 497aa5120d2SRafał Miłecki seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev)); 4987433874eSRafał Miłecki 4997433874eSRafał Miłecki return 0; 5007433874eSRafał Miłecki } 5017433874eSRafał Miłecki 5027433874eSRafał Miłecki static struct drm_info_list radeon_pm_info_list[] = { 5037433874eSRafał Miłecki {"radeon_pm_info", radeon_debugfs_pm_info, 0, NULL}, 5047433874eSRafał Miłecki }; 5057433874eSRafał Miłecki #endif 5067433874eSRafał Miłecki 507c913e23aSRafał Miłecki static int radeon_debugfs_pm_init(struct radeon_device *rdev) 5087433874eSRafał Miłecki { 5097433874eSRafał Miłecki #if defined(CONFIG_DEBUG_FS) 5107433874eSRafał Miłecki return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list)); 5117433874eSRafał Miłecki #else 5127433874eSRafał Miłecki return 0; 5137433874eSRafał Miłecki #endif 5147433874eSRafał Miłecki } 515