From eca0040ff0724e9b263011104d74e58812ffaf58 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 5 Sep 2025 13:27:08 -0500 Subject: [PATCH 1/5] [nrf fromtree] pm: Extend pm notifier to be able to report substate I am surprised this notifier didn't already report the substate id, it seems important since different substate obviously are defined for a reason, they can be having a different effect on the system. Signed-off-by: Declan Snyder (cherry picked from commit ae1f13149fcd4c5d5c75784292c738e2e39e2645) --- include/zephyr/pm/pm.h | 37 +++++++++++++++++++++++++++---------- subsys/pm/pm.c | 22 ++++++++++++++++------ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/include/zephyr/pm/pm.h b/include/zephyr/pm/pm.h index 443f5e37d8bd..096ca6942e6f 100644 --- a/include/zephyr/pm/pm.h +++ b/include/zephyr/pm/pm.h @@ -55,16 +55,33 @@ extern "C" { */ struct pm_notifier { sys_snode_t _node; - /** - * Application defined function for doing any target specific operations - * for power state entry. - */ - void (*state_entry)(enum pm_state state); - /** - * Application defined function for doing any target specific operations - * for power state exit. - */ - void (*state_exit)(enum pm_state state); + union { + struct { + /** + * Application defined function for doing any target specific operations + * for power state entry. + */ + void (*state_entry)(enum pm_state state); + /** + * Application defined function for doing any target specific operations + * for power state exit. + */ + void (*state_exit)(enum pm_state state); + }; + struct { + /** + * Application defined function for doing any target specific operations + * for power state entry. Reports the substate id additionally. + */ + void (*substate_entry)(enum pm_state state, uint8_t substate_id); + /** + * Application defined function for doing any target specific operations + * for power state exit. Reports the substate id additionally. + */ + void (*substate_exit)(enum pm_state state, uint8_t substate_id); + }; + }; + bool report_substate; /* 0 is for backwards compatibility that didn't report substates */ }; #if defined(CONFIG_PM) || defined(__DOXYGEN__) diff --git a/subsys/pm/pm.c b/subsys/pm/pm.c index 58448e1eba01..062c7bd623a0 100644 --- a/subsys/pm/pm.c +++ b/subsys/pm/pm.c @@ -47,19 +47,29 @@ static inline void pm_state_notify(bool entering_state) { struct pm_notifier *notifier; k_spinlock_key_t pm_notifier_key; - void (*callback)(enum pm_state state); + union { + void (*without_substate)(enum pm_state state); + void (*with_substate)(enum pm_state state, uint8_t substate_id); + } callback; pm_notifier_key = k_spin_lock(&pm_notifier_lock); SYS_SLIST_FOR_EACH_CONTAINER(&pm_notifiers, notifier, _node) { if (entering_state) { - callback = notifier->state_entry; + /* should be equivalent to also setting the "with substate" */ + callback.without_substate = notifier->state_entry; } else { - callback = notifier->state_exit; + /* should be equivalent to also setting the "with substate" */ + callback.without_substate = notifier->state_exit; } - if (callback) { - callback(z_cpus_pm_state[CPU_ID]->state); - } + if (callback.with_substate && notifier->report_substate) { + callback.with_substate(z_cpus_pm_state[CPU_ID]->state, + z_cpus_pm_state[CPU_ID]->substate_id); + } else if (callback.without_substate) { + callback.without_substate(z_cpus_pm_state[CPU_ID]->state); + } else { + /* intentionally empty */ + }; } k_spin_unlock(&pm_notifier_lock, pm_notifier_key); } From b4f39bc417233e7ed6a6091e67f2f880e2cbdfde Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Thu, 4 Sep 2025 16:43:13 +0800 Subject: [PATCH 2/5] [nrf fromtree] pm: states: add enum-string conversion helpers Add two helper functions to convert power management states between enum and string: - pm_state_to_string() - pm_state_from_string() Signed-off-by: Yongxu Wang (cherry picked from commit 8767cec875f8d12fc6b85ec5b8ea8a7408de7d5b) --- include/zephyr/pm/state.h | 21 ++++++++++++++++++ subsys/pm/state.c | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/include/zephyr/pm/state.h b/include/zephyr/pm/state.h index ef191d87c143..91119efbb69e 100644 --- a/include/zephyr/pm/state.h +++ b/include/zephyr/pm/state.h @@ -9,6 +9,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -382,6 +383,26 @@ uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states); * @return Pointer to the power state structure or NULL if state is not found. */ const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id); + +/** + * @brief Convert a pm_state enum value to its string representation. + * + * @param state Power state. + * + * @return A constant string representing the state. + */ +const char *pm_state_to_str(enum pm_state state); + + +/** + * @brief Parse a string and convert it to a pm_state enum value. + * + * @param name Input string (e.g., "suspend-to-ram"). + * @param out Pointer to store the parsed pm_state value. + * + * @return 0 on success, -EINVAL if the string is invalid or NULL. + */ +int pm_state_from_str(const char *name, enum pm_state *out); /** * @} */ diff --git a/subsys/pm/state.c b/subsys/pm/state.c index 477c462408d3..0ff8c4a4bc5f 100644 --- a/subsys/pm/state.c +++ b/subsys/pm/state.c @@ -107,3 +107,48 @@ const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8 return NULL; } + +const char *pm_state_to_str(enum pm_state state) +{ + switch (state) { + case PM_STATE_ACTIVE: + return "active"; + case PM_STATE_RUNTIME_IDLE: + return "runtime-idle"; + case PM_STATE_SUSPEND_TO_IDLE: + return "suspend-to-idle"; + case PM_STATE_STANDBY: + return "standby"; + case PM_STATE_SUSPEND_TO_RAM: + return "suspend-to-ram"; + case PM_STATE_SUSPEND_TO_DISK: + return "suspend-to-disk"; + case PM_STATE_SOFT_OFF: + return "soft-off"; + default: + return "UNKNOWN"; + } +} + +int pm_state_from_str(const char *name, enum pm_state *out) +{ + if (strcmp(name, "active") == 0) { + *out = PM_STATE_ACTIVE; + } else if (strcmp(name, "runtime-idle") == 0) { + *out = PM_STATE_RUNTIME_IDLE; + } else if (strcmp(name, "suspend-to-idle") == 0) { + *out = PM_STATE_SUSPEND_TO_IDLE; + } else if (strcmp(name, "standby") == 0) { + *out = PM_STATE_STANDBY; + } else if (strcmp(name, "suspend-to-ram") == 0) { + *out = PM_STATE_SUSPEND_TO_RAM; + } else if (strcmp(name, "suspend-to-disk") == 0) { + *out = PM_STATE_SUSPEND_TO_DISK; + } else if (strcmp(name, "soft-off") == 0) { + *out = PM_STATE_SOFT_OFF; + } else { + return -EINVAL; + } + + return 0; +} From 34106e6498c09653198a166624ed86f9c47d06bf Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 5 Sep 2025 13:28:37 -0500 Subject: [PATCH 3/5] [nrf fromtree] pm: Add constraint lists and APIs Some pieces of the system may have custom types of constraints that they define based on different effects and reasons than just the standard "zephyr,disabling-states". To avoid every single one of these component reinventing the wheel, make some common APIs to handle these type of custom constraint lists. Signed-off-by: Declan Snyder (cherry picked from commit a4225b1ee8b26bcb18067e272c55811a5af01465) --- include/zephyr/pm/policy.h | 30 ++++++++++ include/zephyr/pm/state.h | 81 ++++++++++++++++++++++++++- subsys/pm/policy/policy_device_lock.c | 10 ---- subsys/pm/policy/policy_state_lock.c | 16 ++++++ subsys/pm/state.c | 17 ++++++ 5 files changed, 143 insertions(+), 11 deletions(-) diff --git a/include/zephyr/pm/policy.h b/include/zephyr/pm/policy.h index eab33582b920..b38fa37f254b 100644 --- a/include/zephyr/pm/policy.h +++ b/include/zephyr/pm/policy.h @@ -125,6 +125,36 @@ void pm_policy_state_lock_get(enum pm_state state, uint8_t substate_id); */ void pm_policy_state_lock_put(enum pm_state state, uint8_t substate_id); +/** + * @brief Apply power state constraints by locking the specified states. + * + * This function locks all power states specified in the union of all constraints + * in the provided constraint list. Each constraint in the set contributes to + * determining which power states should be locked (not allowed), by increasing + * a reference count just as if pm_policy_state_lock_get was called on each constraints' + * states individually. + * + * @param constraints Pointer to the power state constraints set to apply. + * + * @see pm_policy_state_constraints_put() + */ +void pm_policy_state_constraints_get(struct pm_state_constraints *constraints); + +/** + * @brief Remove power state constraints by unlocking the specified states. + * + * This function unlocks all power states that were previously locked by a + * corresponding call to pm_policy_state_constraints_get() with the same + * constraint set. The function decreases the lock counter for each affected + * power state specified in the union of all constraints in the list, just as + * if pm_policy_state_put was called on all the constraints' states individually. + * + * @param constraints Pointer to the power state constraints set to remove. + * + * @see pm_policy_state_constraints_get() + */ +void pm_policy_state_constraints_put(struct pm_state_constraints *constraints); + /** * @brief Check if a power state lock is active (not allowed). * diff --git a/include/zephyr/pm/state.h b/include/zephyr/pm/state.h index 91119efbb69e..69d0cae8863a 100644 --- a/include/zephyr/pm/state.h +++ b/include/zephyr/pm/state.h @@ -168,7 +168,8 @@ struct pm_state_info { }; /** - * Power state information needed to lock a power state. + * Information needed to be able to reference a power state as a constraint + * on some device or system functions. */ struct pm_state_constraint { /** @@ -185,6 +186,16 @@ struct pm_state_constraint { uint8_t substate_id; }; +/** + * Collection of multiple power state constraints. + */ +struct pm_state_constraints { + /** Array of power state constraints */ + struct pm_state_constraint *list; + /** Number of constraints in the list */ + size_t count; +}; + /** @cond INTERNAL_HIDDEN */ /** @@ -359,6 +370,54 @@ struct pm_state_constraint { Z_PM_STATE_FROM_DT_CPU, (), node_id) \ } +/** + * @brief initialize a device pm constraint with information from devicetree. + * + * @param node_id Node identifier. + */ +#define PM_STATE_CONSTRAINT_INIT(node_id) \ + { \ + .state = PM_STATE_DT_INIT(node_id), \ + .substate_id = DT_PROP_OR(node_id, substate_id, 0), \ + } + +#define Z_PM_STATE_CONSTRAINT_REF(node_id, phandle, idx) \ + PM_STATE_CONSTRAINT_INIT(DT_PHANDLE_BY_IDX(node_id, phandle, idx)) + +#define Z_PM_STATE_CONSTRAINTS_LIST_NAME(node_id, phandles) \ + _CONCAT_4(node_id, _, phandles, _constraints) + +/** + * @brief Define a list of power state constraints from devicetree. + * + * This macro creates an array of pm_state_constraint structures initialized + * with power state information from the specified devicetree property. + * + * @param node_id Devicetree node identifier. + * @param prop Property name containing the list of power state phandles. + */ +#define PM_STATE_CONSTRAINTS_LIST_DEFINE(node_id, prop) \ + struct pm_state_constraint Z_PM_STATE_CONSTRAINTS_LIST_NAME(node_id, prop)[] = \ + { \ + DT_FOREACH_PROP_ELEM_SEP(node_id, prop, Z_PM_STATE_CONSTRAINT_REF, (,)) \ + } + +/** + * @brief Get power state constraints structure from devicetree. + * + * This macro creates a structure containing a pointer to the constraints list + * and the count of constraints, suitable for initializing a pm_state_constraints + * structure. Must be used after the PM_STATE_CONSTRAINTS_LIST_DEFINE call for the same + * @param prop to refer to the array of constraints. + * + * @param node_id Devicetree node identifier. + * @param prop Property name containing the list of power state phandles. + */ +#define PM_STATE_CONSTRAINTS_GET(node_id, prop) \ + { \ + .list = Z_PM_STATE_CONSTRAINTS_LIST_NAME(node_id, prop), \ + .count = DT_PROP_LEN(node_id, prop), \ + } #if defined(CONFIG_PM) || defined(__DOXYGEN__) /** @@ -403,6 +462,18 @@ const char *pm_state_to_str(enum pm_state state); * @return 0 on success, -EINVAL if the string is invalid or NULL. */ int pm_state_from_str(const char *name, enum pm_state *out); + +/** + * @brief Check if a power management constraint matches any in a set of constraints. + * + * @param constraints Pointer to the power state constraints structure. + * @param match The constraint to match against. + * + * @return true if the constraint matches, false otherwise. + */ +bool pm_state_in_constraints(const struct pm_state_constraints *constraints, + const struct pm_state_constraint match); + /** * @} */ @@ -428,6 +499,14 @@ static inline const struct pm_state_info *pm_state_get(uint8_t cpu, return NULL; } +static inline bool pm_state_in_constraints(struct pm_state_constraints *constraints, + struct pm_state_constraint match) +{ + ARG_UNUSED(constraints); + ARG_UNUSED(match); + + return false; +} #endif /* CONFIG_PM */ #ifdef __cplusplus diff --git a/subsys/pm/policy/policy_device_lock.c b/subsys/pm/policy/policy_device_lock.c index 290a1ff51597..0c70dd17a189 100644 --- a/subsys/pm/policy/policy_device_lock.c +++ b/subsys/pm/policy/policy_device_lock.c @@ -24,16 +24,6 @@ struct pm_state_device_constraint { */ #define PM_CONSTRAINTS_NAME(node_id) _CONCAT(__devicepmconstraints_, node_id) -/** - * @brief initialize a device pm constraint with information from devicetree. - * - * @param node_id Node identifier. - */ -#define PM_STATE_CONSTRAINT_INIT(node_id) \ - { \ - .state = PM_STATE_DT_INIT(node_id), \ - .substate_id = DT_PROP_OR(node_id, substate_id, 0), \ - } /** * @brief Helper macro to define a device pm constraints. diff --git a/subsys/pm/policy/policy_state_lock.c b/subsys/pm/policy/policy_state_lock.c index f69133dfe893..b4cc319339ba 100644 --- a/subsys/pm/policy/policy_state_lock.c +++ b/subsys/pm/policy/policy_state_lock.c @@ -65,6 +65,14 @@ void pm_policy_state_lock_get(enum pm_state state, uint8_t substate_id) #endif } +void pm_policy_state_constraints_get(struct pm_state_constraints *constraints) +{ + for (int i = 0; i < constraints->count; i++) { + pm_policy_state_lock_get(constraints->list[i].state, + constraints->list[i].substate_id); + } +} + void pm_policy_state_lock_put(enum pm_state state, uint8_t substate_id) { #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) @@ -84,6 +92,14 @@ void pm_policy_state_lock_put(enum pm_state state, uint8_t substate_id) #endif } +void pm_policy_state_constraints_put(struct pm_state_constraints *constraints) +{ + for (int i = 0; i < constraints->count; i++) { + pm_policy_state_lock_put(constraints->list[i].state, + constraints->list[i].substate_id); + } +} + bool pm_policy_state_lock_is_active(enum pm_state state, uint8_t substate_id) { #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) diff --git a/subsys/pm/state.c b/subsys/pm/state.c index 0ff8c4a4bc5f..3427d6684288 100644 --- a/subsys/pm/state.c +++ b/subsys/pm/state.c @@ -152,3 +152,20 @@ int pm_state_from_str(const char *name, enum pm_state *out) return 0; } + +bool pm_state_in_constraints(const struct pm_state_constraints *constraints, + const struct pm_state_constraint match) +{ + struct pm_state_constraint *constraints_list = constraints->list; + size_t num_constraints = constraints->count; + bool match_found = false; + + for (int i = 0; i < num_constraints; i++) { + enum pm_state state = constraints_list[i].state; + uint8_t substate = constraints_list[i].substate_id; + + match_found |= ((state == match.state) && (substate == match.substate_id)); + } + + return match_found; +} From 10b467744ea2f8fb3ed3312399e1a33580e42aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 2 Oct 2025 11:56:56 +0200 Subject: [PATCH 4/5] [nrf fromtree] pm: policy: Add option to lock all power states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add function for getting and putting a lock for all power states. It is much faster version of requesting 0 us latency with actual intention to disable all power states. Signed-off-by: Krzysztof Chruściński (cherry picked from commit 336e89efd665f424d7385d3d0044cb8a54c26292) --- include/zephyr/pm/policy.h | 22 ++++++++++++++++++++++ subsys/pm/policy/policy_state_lock.c | 23 +++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/zephyr/pm/policy.h b/include/zephyr/pm/policy.h index b38fa37f254b..0be63d38f8ce 100644 --- a/include/zephyr/pm/policy.h +++ b/include/zephyr/pm/policy.h @@ -112,6 +112,7 @@ const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks); * * @see pm_policy_state_lock_put() */ + void pm_policy_state_lock_get(enum pm_state state, uint8_t substate_id); /** @@ -125,6 +126,18 @@ void pm_policy_state_lock_get(enum pm_state state, uint8_t substate_id); */ void pm_policy_state_lock_put(enum pm_state state, uint8_t substate_id); +/** + * @brief Request to lock all power states. + * + * Requests use a reference counter. + */ +void pm_policy_state_all_lock_get(void); + +/** + * @brief Release locking of all power states. + */ +void pm_policy_state_all_lock_put(void); + /** * @brief Apply power state constraints by locking the specified states. * @@ -274,6 +287,14 @@ static inline void pm_policy_state_lock_put(enum pm_state state, uint8_t substat ARG_UNUSED(substate_id); } +static inline void pm_policy_state_all_lock_get(void) +{ +} + +static inline void pm_policy_state_all_lock_put(void) +{ +} + static inline bool pm_policy_state_lock_is_active(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); @@ -344,6 +365,7 @@ static inline void pm_policy_device_power_lock_put(const struct device *dev) { ARG_UNUSED(dev); } + #endif /* CONFIG_PM_POLICY_DEVICE_CONSTRAINTS */ #if defined(CONFIG_PM) || defined(CONFIG_PM_POLICY_LATENCY_STANDALONE) || defined(__DOXYGEN__) diff --git a/subsys/pm/policy/policy_state_lock.c b/subsys/pm/policy/policy_state_lock.c index b4cc319339ba..7ed8def652b0 100644 --- a/subsys/pm/policy/policy_state_lock.c +++ b/subsys/pm/policy/policy_state_lock.c @@ -43,10 +43,23 @@ static const struct { static atomic_t lock_cnt[ARRAY_SIZE(substates)]; static atomic_t latency_mask = BIT_MASK(ARRAY_SIZE(substates)); static atomic_t unlock_mask = BIT_MASK(ARRAY_SIZE(substates)); +static atomic_t global_lock_cnt; static struct k_spinlock lock; #endif +void pm_policy_state_all_lock_get(void) +{ + (void)atomic_inc(&global_lock_cnt); +} + +void pm_policy_state_all_lock_put(void) +{ + __ASSERT(global_lock_cnt > 0, "Unbalanced state lock get/put"); + (void)atomic_dec(&global_lock_cnt); +} + + void pm_policy_state_lock_get(enum pm_state state, uint8_t substate_id) { #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) @@ -106,7 +119,8 @@ bool pm_policy_state_lock_is_active(enum pm_state state, uint8_t substate_id) for (size_t i = 0; i < ARRAY_SIZE(substates); i++) { if (substates[i].state == state && (substates[i].substate_id == substate_id || substate_id == PM_ALL_SUBSTATES)) { - return atomic_get(&lock_cnt[i]) != 0; + return (atomic_get(&global_lock_cnt) != 0) || + (atomic_get(&lock_cnt[i]) != 0); } } #endif @@ -117,6 +131,10 @@ bool pm_policy_state_lock_is_active(enum pm_state state, uint8_t substate_id) bool pm_policy_state_is_available(enum pm_state state, uint8_t substate_id) { #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) + if (atomic_get(&global_lock_cnt) != 0) { + return false; + } + for (size_t i = 0; i < ARRAY_SIZE(substates); i++) { if (substates[i].state == state && (substates[i].substate_id == substate_id || substate_id == PM_ALL_SUBSTATES)) { @@ -135,7 +153,8 @@ bool pm_policy_state_any_active(void) /* Check if there is any power state that is not locked and not disabled due * to latency requirements. */ - return atomic_get(&unlock_mask) & atomic_get(&latency_mask); + return (atomic_get(&global_lock_cnt) == 0) && + (atomic_get(&unlock_mask) & atomic_get(&latency_mask)); #endif return true; } From 589ded085fc88a7ca4f93d093491719a70a6bb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 2 Oct 2025 12:49:21 +0200 Subject: [PATCH 5/5] [nrf fromtree] tests: pm: policy_api: Add test for locking all PM states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test case that validates behavior of pm_policy_state_all_lock_get and pm_policy_state_all_lock_put. Signed-off-by: Krzysztof Chruściński (cherry picked from commit 3595c9d0d46480e4aa76857073e07e5b29181fdc) --- include/zephyr/pm/policy.h | 2 -- subsys/pm/policy/policy_state_lock.c | 4 ++++ tests/subsys/pm/policy_api/src/main.c | 31 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/zephyr/pm/policy.h b/include/zephyr/pm/policy.h index 0be63d38f8ce..8175214e8774 100644 --- a/include/zephyr/pm/policy.h +++ b/include/zephyr/pm/policy.h @@ -112,7 +112,6 @@ const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks); * * @see pm_policy_state_lock_put() */ - void pm_policy_state_lock_get(enum pm_state state, uint8_t substate_id); /** @@ -365,7 +364,6 @@ static inline void pm_policy_device_power_lock_put(const struct device *dev) { ARG_UNUSED(dev); } - #endif /* CONFIG_PM_POLICY_DEVICE_CONSTRAINTS */ #if defined(CONFIG_PM) || defined(CONFIG_PM_POLICY_LATENCY_STANDALONE) || defined(__DOXYGEN__) diff --git a/subsys/pm/policy/policy_state_lock.c b/subsys/pm/policy/policy_state_lock.c index 7ed8def652b0..f8f5a7c41de6 100644 --- a/subsys/pm/policy/policy_state_lock.c +++ b/subsys/pm/policy/policy_state_lock.c @@ -50,13 +50,17 @@ static struct k_spinlock lock; void pm_policy_state_all_lock_get(void) { +#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) (void)atomic_inc(&global_lock_cnt); +#endif } void pm_policy_state_all_lock_put(void) { +#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) __ASSERT(global_lock_cnt > 0, "Unbalanced state lock get/put"); (void)atomic_dec(&global_lock_cnt); +#endif } diff --git a/tests/subsys/pm/policy_api/src/main.c b/tests/subsys/pm/policy_api/src/main.c index e336b756294d..9bd2e9fccc85 100644 --- a/tests/subsys/pm/policy_api/src/main.c +++ b/tests/subsys/pm/policy_api/src/main.c @@ -71,6 +71,37 @@ ZTEST(policy_api, test_pm_policy_next_state_default) zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM); } +ZTEST(policy_api, test_pm_policy_state_all_lock) +{ + /* initial state: PM_STATE_RUNTIME_IDLE allowed */ + zassert_false(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_true(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_true(pm_policy_state_any_active()); + + /* Locking all states. */ + pm_policy_state_all_lock_get(); + pm_policy_state_all_lock_get(); + + /* States are locked. */ + zassert_true(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_false(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_false(pm_policy_state_any_active()); + + pm_policy_state_all_lock_put(); + + /* States are still locked due to reference counter. */ + zassert_true(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_false(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_false(pm_policy_state_any_active()); + + pm_policy_state_all_lock_put(); + + /* States are available again. */ + zassert_false(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_true(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES)); + zassert_true(pm_policy_state_any_active()); +} + /** * @brief Test the behavior of pm_policy_next_state() when * states are allowed/disallowed and CONFIG_PM_POLICY_DEFAULT=y.