1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2022 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/pm/policy.h>
9 #include <zephyr/pm/state.h>
10 #include <zephyr/sys/__assert.h>
11 #include <zephyr/sys/atomic.h>
12 #include <zephyr/toolchain.h>
13
14 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
15
16 #define DT_SUB_LOCK_INIT(node_id) \
17 { .state = PM_STATE_DT_INIT(node_id), \
18 .substate_id = DT_PROP_OR(node_id, substate_id, 0), \
19 .lock = ATOMIC_INIT(0), \
20 },
21
22 /**
23 * State and substate lock structure.
24 *
25 * This struct is associating a reference counting to each <state,substate>
26 * couple to be used with the pm_policy_substate_lock_* functions.
27 *
28 * Operations on this array are in the order of O(n) with the number of power
29 * states and this is mostly due to the random nature of the substate value
30 * (that can be anything from a small integer value to a bitmask). We can
31 * probably do better with an hashmap.
32 */
33 static struct {
34 enum pm_state state;
35 uint8_t substate_id;
36 atomic_t lock;
37 } substate_lock_t[] = {
38 DT_FOREACH_STATUS_OKAY(zephyr_power_state, DT_SUB_LOCK_INIT)
39 };
40
41 #endif
42
pm_policy_state_lock_get(enum pm_state state,uint8_t substate_id)43 void pm_policy_state_lock_get(enum pm_state state, uint8_t substate_id)
44 {
45 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
46 for (size_t i = 0; i < ARRAY_SIZE(substate_lock_t); i++) {
47 if (substate_lock_t[i].state == state &&
48 (substate_lock_t[i].substate_id == substate_id ||
49 substate_id == PM_ALL_SUBSTATES)) {
50 atomic_inc(&substate_lock_t[i].lock);
51 }
52 }
53 #endif
54 }
55
pm_policy_state_lock_put(enum pm_state state,uint8_t substate_id)56 void pm_policy_state_lock_put(enum pm_state state, uint8_t substate_id)
57 {
58 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
59 for (size_t i = 0; i < ARRAY_SIZE(substate_lock_t); i++) {
60 if (substate_lock_t[i].state == state &&
61 (substate_lock_t[i].substate_id == substate_id ||
62 substate_id == PM_ALL_SUBSTATES)) {
63 atomic_t cnt = atomic_dec(&substate_lock_t[i].lock);
64
65 ARG_UNUSED(cnt);
66
67 __ASSERT(cnt >= 1, "Unbalanced state lock get/put");
68 }
69 }
70 #endif
71 }
72
pm_policy_state_lock_is_active(enum pm_state state,uint8_t substate_id)73 bool pm_policy_state_lock_is_active(enum pm_state state, uint8_t substate_id)
74 {
75 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
76 for (size_t i = 0; i < ARRAY_SIZE(substate_lock_t); i++) {
77 if (substate_lock_t[i].state == state &&
78 (substate_lock_t[i].substate_id == substate_id ||
79 substate_id == PM_ALL_SUBSTATES)) {
80 return (atomic_get(&substate_lock_t[i].lock) != 0);
81 }
82 }
83 #endif
84
85 return false;
86 }
87