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