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