blob: 57020a695124e33221efb85cb372880ad34bf56e [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation.
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/pm/state.h>
#include <zephyr/toolchain.h>
BUILD_ASSERT(DT_NODE_EXISTS(DT_PATH(cpus)),
"cpus node not defined in Devicetree");
#define DEFINE_CPU_STATES(n) \
static const struct pm_state_info pmstates_##n[] \
= PM_STATE_INFO_LIST_FROM_DT_CPU(n);
#define CPU_STATE_REF(n) pmstates_##n
DT_FOREACH_CHILD(DT_PATH(cpus), DEFINE_CPU_STATES);
/** CPU power states information for each CPU */
static const struct pm_state_info *cpus_states[] = {
DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), CPU_STATE_REF, (,))
};
/** Number of states for each CPU */
static const uint8_t states_per_cpu[] = {
DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), DT_NUM_CPU_POWER_STATES, (,))
};
#define DEFINE_DISABLED_PM_STATE(node) \
IF_ENABLED(DT_NODE_HAS_STATUS(node, disabled), (PM_STATE_INFO_DT_INIT(node),))
/** Check if power states exists in the Devicetree. */
#define POWER_STATES_EXISTS() \
UTIL_OR(DT_NODE_EXISTS(DT_PATH(cpus, power_states)), \
DT_NODE_EXISTS(DT_PATH(power_states)))
/** Get node with power states. Macro assumes that power states exists. */
#define POWER_STATES_NODE() \
COND_CODE_1(DT_NODE_EXISTS(DT_PATH(cpus, power_states)), \
(DT_PATH(cpus, power_states)), (DT_PATH(power_states)))
/* Array with all states which are disabled but can be forced. */
static const struct pm_state_info disabled_states[] = {
IF_ENABLED(POWER_STATES_EXISTS(),
(DT_FOREACH_CHILD(POWER_STATES_NODE(), DEFINE_DISABLED_PM_STATE)))
};
uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states)
{
if (cpu >= ARRAY_SIZE(cpus_states)) {
return 0;
}
*states = cpus_states[cpu];
return states_per_cpu[cpu];
}
const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id)
{
__ASSERT_NO_MSG(cpu < ARRAY_SIZE(cpus_states));
const struct pm_state_info *states = cpus_states[cpu];
uint8_t cnt = states_per_cpu[cpu];
for (uint8_t i = 0; i < cnt; i++) {
if ((states[i].state == state) && (states[i].substate_id == substate_id)) {
return &states[i];
}
}
for (uint8_t i = 0; i < ARRAY_SIZE(disabled_states); i++) {
if ((disabled_states[i].state == state) &&
(disabled_states[i].substate_id == substate_id)) {
return &disabled_states[i];
}
}
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;
}
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;
}