1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2021 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/pm/state.h>
9 #include <zephyr/toolchain.h>
10
11 BUILD_ASSERT(DT_NODE_EXISTS(DT_PATH(cpus)),
12 "cpus node not defined in Devicetree");
13
14 #define DEFINE_CPU_STATES(n) \
15 static const struct pm_state_info pmstates_##n[] \
16 = PM_STATE_INFO_LIST_FROM_DT_CPU(n);
17 #define CPU_STATE_REF(n) pmstates_##n
18
19 DT_FOREACH_CHILD(DT_PATH(cpus), DEFINE_CPU_STATES);
20
21 /** CPU power states information for each CPU */
22 static const struct pm_state_info *cpus_states[] = {
23 DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), CPU_STATE_REF, (,))
24 };
25
26 /** Number of states for each CPU */
27 static const uint8_t states_per_cpu[] = {
28 DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), DT_NUM_CPU_POWER_STATES, (,))
29 };
30
31 #define DEFINE_DISABLED_PM_STATE(node) \
32 IF_ENABLED(DT_NODE_HAS_STATUS(node, disabled), (PM_STATE_INFO_DT_INIT(node),))
33
34 /** Check if power states exists in the Devicetree. */
35 #define POWER_STATES_EXISTS() \
36 UTIL_OR(DT_NODE_EXISTS(DT_PATH(cpus, power_states)), \
37 DT_NODE_EXISTS(DT_PATH(power_states)))
38
39 /** Get node with power states. Macro assumes that power states exists. */
40 #define POWER_STATES_NODE() \
41 COND_CODE_1(DT_NODE_EXISTS(DT_PATH(cpus, power_states)), \
42 (DT_PATH(cpus, power_states)), (DT_PATH(power_states)))
43
44 /* Array with all states which are disabled but can be forced. */
45 static const struct pm_state_info disabled_states[] = {
46 IF_ENABLED(POWER_STATES_EXISTS(),
47 (DT_FOREACH_CHILD(POWER_STATES_NODE(), DEFINE_DISABLED_PM_STATE)))
48 };
49
pm_state_cpu_get_all(uint8_t cpu,const struct pm_state_info ** states)50 uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states)
51 {
52 if (cpu >= ARRAY_SIZE(cpus_states)) {
53 return 0;
54 }
55
56 *states = cpus_states[cpu];
57
58 return states_per_cpu[cpu];
59 }
60
pm_state_get(uint8_t cpu,enum pm_state state,uint8_t substate_id)61 const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id)
62 {
63 __ASSERT_NO_MSG(cpu < ARRAY_SIZE(cpus_states));
64 const struct pm_state_info *states = cpus_states[cpu];
65 uint8_t cnt = states_per_cpu[cpu];
66
67 for (uint8_t i = 0; i < cnt; i++) {
68 if ((states[i].state == state) && (states[i].substate_id == substate_id)) {
69 return &states[i];
70 }
71 }
72
73 for (uint8_t i = 0; i < ARRAY_SIZE(disabled_states); i++) {
74 if ((disabled_states[i].state == state) &&
75 (disabled_states[i].substate_id == substate_id)) {
76 return &disabled_states[i];
77 }
78 }
79
80 return NULL;
81 }
82
pm_state_to_str(enum pm_state state)83 const char *pm_state_to_str(enum pm_state state)
84 {
85 switch (state) {
86 case PM_STATE_ACTIVE:
87 return "active";
88 case PM_STATE_RUNTIME_IDLE:
89 return "runtime-idle";
90 case PM_STATE_SUSPEND_TO_IDLE:
91 return "suspend-to-idle";
92 case PM_STATE_STANDBY:
93 return "standby";
94 case PM_STATE_SUSPEND_TO_RAM:
95 return "suspend-to-ram";
96 case PM_STATE_SUSPEND_TO_DISK:
97 return "suspend-to-disk";
98 case PM_STATE_SOFT_OFF:
99 return "soft-off";
100 default:
101 return "UNKNOWN";
102 }
103 }
104
pm_state_from_str(const char * name,enum pm_state * out)105 int pm_state_from_str(const char *name, enum pm_state *out)
106 {
107 if (strcmp(name, "active") == 0) {
108 *out = PM_STATE_ACTIVE;
109 } else if (strcmp(name, "runtime-idle") == 0) {
110 *out = PM_STATE_RUNTIME_IDLE;
111 } else if (strcmp(name, "suspend-to-idle") == 0) {
112 *out = PM_STATE_SUSPEND_TO_IDLE;
113 } else if (strcmp(name, "standby") == 0) {
114 *out = PM_STATE_STANDBY;
115 } else if (strcmp(name, "suspend-to-ram") == 0) {
116 *out = PM_STATE_SUSPEND_TO_RAM;
117 } else if (strcmp(name, "suspend-to-disk") == 0) {
118 *out = PM_STATE_SUSPEND_TO_DISK;
119 } else if (strcmp(name, "soft-off") == 0) {
120 *out = PM_STATE_SOFT_OFF;
121 } else {
122 return -EINVAL;
123 }
124
125 return 0;
126 }
127
pm_state_in_constraints(const struct pm_state_constraints * constraints,const struct pm_state_constraint match)128 bool pm_state_in_constraints(const struct pm_state_constraints *constraints,
129 const struct pm_state_constraint match)
130 {
131 struct pm_state_constraint *constraints_list = constraints->list;
132 size_t num_constraints = constraints->count;
133 bool match_found = false;
134
135 for (int i = 0; i < num_constraints; i++) {
136 enum pm_state state = constraints_list[i].state;
137 uint8_t substate = constraints_list[i].substate_id;
138
139 match_found |= ((state == match.state) && (substate == match.substate_id));
140 }
141
142 return match_found;
143 }
144