18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: MIT */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright © 2019 Intel Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#ifndef __INTEL_RUNTIME_PM_H__ 78c2ecf20Sopenharmony_ci#define __INTEL_RUNTIME_PM_H__ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "display/intel_display.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "intel_wakeref.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "i915_utils.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct device; 188c2ecf20Sopenharmony_cistruct drm_i915_private; 198c2ecf20Sopenharmony_cistruct drm_printer; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cienum i915_drm_suspend_mode { 228c2ecf20Sopenharmony_ci I915_DRM_SUSPEND_IDLE, 238c2ecf20Sopenharmony_ci I915_DRM_SUSPEND_MEM, 248c2ecf20Sopenharmony_ci I915_DRM_SUSPEND_HIBERNATE, 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * This struct helps tracking the state needed for runtime PM, which puts the 298c2ecf20Sopenharmony_ci * device in PCI D3 state. Notice that when this happens, nothing on the 308c2ecf20Sopenharmony_ci * graphics device works, even register access, so we don't get interrupts nor 318c2ecf20Sopenharmony_ci * anything else. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Every piece of our code that needs to actually touch the hardware needs to 348c2ecf20Sopenharmony_ci * either call intel_runtime_pm_get or call intel_display_power_get with the 358c2ecf20Sopenharmony_ci * appropriate power domain. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Our driver uses the autosuspend delay feature, which means we'll only really 388c2ecf20Sopenharmony_ci * suspend if we stay with zero refcount for a certain amount of time. The 398c2ecf20Sopenharmony_ci * default value is currently very conservative (see intel_runtime_pm_enable), but 408c2ecf20Sopenharmony_ci * it can be changed with the standard runtime PM files from sysfs. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * The irqs_disabled variable becomes true exactly after we disable the IRQs and 438c2ecf20Sopenharmony_ci * goes back to false exactly before we reenable the IRQs. We use this variable 448c2ecf20Sopenharmony_ci * to check if someone is trying to enable/disable IRQs while they're supposed 458c2ecf20Sopenharmony_ci * to be disabled. This shouldn't happen and we'll print some error messages in 468c2ecf20Sopenharmony_ci * case it happens. 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * For more, read the Documentation/power/runtime_pm.rst. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_cistruct intel_runtime_pm { 518c2ecf20Sopenharmony_ci atomic_t wakeref_count; 528c2ecf20Sopenharmony_ci struct device *kdev; /* points to i915->drm.pdev->dev */ 538c2ecf20Sopenharmony_ci bool available; 548c2ecf20Sopenharmony_ci bool suspended; 558c2ecf20Sopenharmony_ci bool irqs_enabled; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * To aide detection of wakeref leaks and general misuse, we 608c2ecf20Sopenharmony_ci * track all wakeref holders. With manual markup (i.e. returning 618c2ecf20Sopenharmony_ci * a cookie to each rpm_get caller which they then supply to their 628c2ecf20Sopenharmony_ci * paired rpm_put) we can remove corresponding pairs of and keep 638c2ecf20Sopenharmony_ci * the array trimmed to active wakerefs. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci struct intel_runtime_pm_debug { 668c2ecf20Sopenharmony_ci spinlock_t lock; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci depot_stack_handle_t last_acquire; 698c2ecf20Sopenharmony_ci depot_stack_handle_t last_release; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci depot_stack_handle_t *owners; 728c2ecf20Sopenharmony_ci unsigned long count; 738c2ecf20Sopenharmony_ci } debug; 748c2ecf20Sopenharmony_ci#endif 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define BITS_PER_WAKEREF \ 788c2ecf20Sopenharmony_ci BITS_PER_TYPE(struct_member(struct intel_runtime_pm, wakeref_count)) 798c2ecf20Sopenharmony_ci#define INTEL_RPM_WAKELOCK_SHIFT (BITS_PER_WAKEREF / 2) 808c2ecf20Sopenharmony_ci#define INTEL_RPM_WAKELOCK_BIAS (1 << INTEL_RPM_WAKELOCK_SHIFT) 818c2ecf20Sopenharmony_ci#define INTEL_RPM_RAW_WAKEREF_MASK (INTEL_RPM_WAKELOCK_BIAS - 1) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic inline int 848c2ecf20Sopenharmony_ciintel_rpm_raw_wakeref_count(int wakeref_count) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci return wakeref_count & INTEL_RPM_RAW_WAKEREF_MASK; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic inline int 908c2ecf20Sopenharmony_ciintel_rpm_wakelock_count(int wakeref_count) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return wakeref_count >> INTEL_RPM_WAKELOCK_SHIFT; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic inline void 968c2ecf20Sopenharmony_ciassert_rpm_device_not_suspended(struct intel_runtime_pm *rpm) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci WARN_ONCE(rpm->suspended, 998c2ecf20Sopenharmony_ci "Device suspended during HW access\n"); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline void 1038c2ecf20Sopenharmony_ci__assert_rpm_raw_wakeref_held(struct intel_runtime_pm *rpm, int wakeref_count) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci assert_rpm_device_not_suspended(rpm); 1068c2ecf20Sopenharmony_ci WARN_ONCE(!intel_rpm_raw_wakeref_count(wakeref_count), 1078c2ecf20Sopenharmony_ci "RPM raw-wakeref not held\n"); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic inline void 1118c2ecf20Sopenharmony_ci__assert_rpm_wakelock_held(struct intel_runtime_pm *rpm, int wakeref_count) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci __assert_rpm_raw_wakeref_held(rpm, wakeref_count); 1148c2ecf20Sopenharmony_ci WARN_ONCE(!intel_rpm_wakelock_count(wakeref_count), 1158c2ecf20Sopenharmony_ci "RPM wakelock ref not held during HW access\n"); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic inline void 1198c2ecf20Sopenharmony_ciassert_rpm_raw_wakeref_held(struct intel_runtime_pm *rpm) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci __assert_rpm_raw_wakeref_held(rpm, atomic_read(&rpm->wakeref_count)); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic inline void 1258c2ecf20Sopenharmony_ciassert_rpm_wakelock_held(struct intel_runtime_pm *rpm) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci __assert_rpm_wakelock_held(rpm, atomic_read(&rpm->wakeref_count)); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/** 1318c2ecf20Sopenharmony_ci * disable_rpm_wakeref_asserts - disable the RPM assert checks 1328c2ecf20Sopenharmony_ci * @rpm: the intel_runtime_pm structure 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * This function disable asserts that check if we hold an RPM wakelock 1358c2ecf20Sopenharmony_ci * reference, while keeping the device-not-suspended checks still enabled. 1368c2ecf20Sopenharmony_ci * It's meant to be used only in special circumstances where our rule about 1378c2ecf20Sopenharmony_ci * the wakelock refcount wrt. the device power state doesn't hold. According 1388c2ecf20Sopenharmony_ci * to this rule at any point where we access the HW or want to keep the HW in 1398c2ecf20Sopenharmony_ci * an active state we must hold an RPM wakelock reference acquired via one of 1408c2ecf20Sopenharmony_ci * the intel_runtime_pm_get() helpers. Currently there are a few special spots 1418c2ecf20Sopenharmony_ci * where this rule doesn't hold: the IRQ and suspend/resume handlers, the 1428c2ecf20Sopenharmony_ci * forcewake release timer, and the GPU RPS and hangcheck works. All other 1438c2ecf20Sopenharmony_ci * users should avoid using this function. 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Any calls to this function must have a symmetric call to 1468c2ecf20Sopenharmony_ci * enable_rpm_wakeref_asserts(). 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistatic inline void 1498c2ecf20Sopenharmony_cidisable_rpm_wakeref_asserts(struct intel_runtime_pm *rpm) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci atomic_add(INTEL_RPM_WAKELOCK_BIAS + 1, 1528c2ecf20Sopenharmony_ci &rpm->wakeref_count); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/** 1568c2ecf20Sopenharmony_ci * enable_rpm_wakeref_asserts - re-enable the RPM assert checks 1578c2ecf20Sopenharmony_ci * @rpm: the intel_runtime_pm structure 1588c2ecf20Sopenharmony_ci * 1598c2ecf20Sopenharmony_ci * This function re-enables the RPM assert checks after disabling them with 1608c2ecf20Sopenharmony_ci * disable_rpm_wakeref_asserts. It's meant to be used only in special 1618c2ecf20Sopenharmony_ci * circumstances otherwise its use should be avoided. 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * Any calls to this function must have a symmetric call to 1648c2ecf20Sopenharmony_ci * disable_rpm_wakeref_asserts(). 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cistatic inline void 1678c2ecf20Sopenharmony_cienable_rpm_wakeref_asserts(struct intel_runtime_pm *rpm) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci atomic_sub(INTEL_RPM_WAKELOCK_BIAS + 1, 1708c2ecf20Sopenharmony_ci &rpm->wakeref_count); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_civoid intel_runtime_pm_init_early(struct intel_runtime_pm *rpm); 1748c2ecf20Sopenharmony_civoid intel_runtime_pm_enable(struct intel_runtime_pm *rpm); 1758c2ecf20Sopenharmony_civoid intel_runtime_pm_disable(struct intel_runtime_pm *rpm); 1768c2ecf20Sopenharmony_civoid intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm); 1798c2ecf20Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_if_in_use(struct intel_runtime_pm *rpm); 1808c2ecf20Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_if_active(struct intel_runtime_pm *rpm); 1818c2ecf20Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_noresume(struct intel_runtime_pm *rpm); 1828c2ecf20Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_raw(struct intel_runtime_pm *rpm); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define with_intel_runtime_pm(rpm, wf) \ 1858c2ecf20Sopenharmony_ci for ((wf) = intel_runtime_pm_get(rpm); (wf); \ 1868c2ecf20Sopenharmony_ci intel_runtime_pm_put((rpm), (wf)), (wf) = 0) 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define with_intel_runtime_pm_if_in_use(rpm, wf) \ 1898c2ecf20Sopenharmony_ci for ((wf) = intel_runtime_pm_get_if_in_use(rpm); (wf); \ 1908c2ecf20Sopenharmony_ci intel_runtime_pm_put((rpm), (wf)), (wf) = 0) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#define with_intel_runtime_pm_if_active(rpm, wf) \ 1938c2ecf20Sopenharmony_ci for ((wf) = intel_runtime_pm_get_if_active(rpm); (wf); \ 1948c2ecf20Sopenharmony_ci intel_runtime_pm_put((rpm), (wf)), (wf) = 0) 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_civoid intel_runtime_pm_put_unchecked(struct intel_runtime_pm *rpm); 1978c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) 1988c2ecf20Sopenharmony_civoid intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref); 1998c2ecf20Sopenharmony_ci#else 2008c2ecf20Sopenharmony_cistatic inline void 2018c2ecf20Sopenharmony_ciintel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci intel_runtime_pm_put_unchecked(rpm); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci#endif 2068c2ecf20Sopenharmony_civoid intel_runtime_pm_put_raw(struct intel_runtime_pm *rpm, intel_wakeref_t wref); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) 2098c2ecf20Sopenharmony_civoid print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, 2108c2ecf20Sopenharmony_ci struct drm_printer *p); 2118c2ecf20Sopenharmony_ci#else 2128c2ecf20Sopenharmony_cistatic inline void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, 2138c2ecf20Sopenharmony_ci struct drm_printer *p) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci#endif 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#endif /* __INTEL_RUNTIME_PM_H__ */ 219