2024-10-22 16:00:54 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Intel Corporation.
|
|
|
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
2025-05-09 16:17:41 -05:00
|
|
|
* Copyright 2025 NXP
|
2024-10-22 16:00:54 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zephyr/pm/policy.h>
|
|
|
|
#include <zephyr/pm/state.h>
|
|
|
|
#include <zephyr/sys/util_macro.h>
|
|
|
|
#include <zephyr/pm/device.h>
|
|
|
|
|
|
|
|
struct pm_state_device_constraint {
|
2025-02-05 23:10:29 +00:00
|
|
|
const char *const dev;
|
2024-10-22 16:00:54 +02:00
|
|
|
size_t pm_constraints_size;
|
|
|
|
struct pm_state_constraint *constraints;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Synthesize the name of the object that holds a device pm constraint.
|
|
|
|
*
|
|
|
|
* @param dev_id Device identifier.
|
|
|
|
*/
|
|
|
|
#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.
|
|
|
|
*/
|
|
|
|
#define PM_STATE_CONSTRAINT_DEFINE(i, node_id) \
|
|
|
|
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, \
|
|
|
|
zephyr_disabling_power_states, i)), \
|
|
|
|
(PM_STATE_CONSTRAINT_INIT(DT_PHANDLE_BY_IDX(node_id, \
|
|
|
|
zephyr_disabling_power_states, i)),), ())
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Helper macro to generate a list of device pm constraints.
|
|
|
|
*/
|
|
|
|
#define PM_STATE_CONSTRAINTS_DEFINE(node_id) \
|
|
|
|
{ \
|
|
|
|
LISTIFY(DT_PROP_LEN_OR(node_id, zephyr_disabling_power_states, 0), \
|
|
|
|
PM_STATE_CONSTRAINT_DEFINE, (), node_id) \
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Helper macro to define an array of device pm constraints.
|
|
|
|
*/
|
|
|
|
#define CONSTRAINTS_DEFINE(node_id) \
|
|
|
|
Z_DECL_ALIGN(struct pm_state_constraint) \
|
|
|
|
PM_CONSTRAINTS_NAME(node_id)[] = \
|
|
|
|
PM_STATE_CONSTRAINTS_DEFINE(node_id);
|
|
|
|
|
|
|
|
#define DEVICE_CONSTRAINTS_DEFINE(node_id) \
|
|
|
|
COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \
|
|
|
|
(CONSTRAINTS_DEFINE(node_id)))
|
|
|
|
|
|
|
|
DT_FOREACH_STATUS_OKAY_NODE(DEVICE_CONSTRAINTS_DEFINE)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Helper macro to initialize a pm state device constraint
|
|
|
|
*/
|
|
|
|
#define PM_STATE_DEVICE_CONSTRAINT_INIT(node_id) \
|
|
|
|
{ \
|
2025-02-05 23:10:29 +00:00
|
|
|
.dev = DEVICE_DT_NAME(node_id), \
|
2024-10-22 16:00:54 +02:00
|
|
|
.pm_constraints_size = DT_PROP_LEN(node_id, zephyr_disabling_power_states), \
|
|
|
|
.constraints = PM_CONSTRAINTS_NAME(node_id), \
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Helper macro to initialize a pm state device constraint
|
|
|
|
*/
|
|
|
|
#define PM_STATE_DEVICE_CONSTRAINT_DEFINE(node_id) \
|
|
|
|
COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \
|
|
|
|
(PM_STATE_DEVICE_CONSTRAINT_INIT(node_id)))
|
|
|
|
|
|
|
|
static struct pm_state_device_constraint _devices_constraints[] = {
|
|
|
|
DT_FOREACH_STATUS_OKAY_NODE(PM_STATE_DEVICE_CONSTRAINT_DEFINE)
|
|
|
|
};
|
|
|
|
|
2025-05-09 16:16:05 -05:00
|
|
|
/* returns device's constraints in _devices_constraints, NULL if not found */
|
|
|
|
static struct pm_state_device_constraint *
|
|
|
|
pm_policy_priv_device_find_device_constraints(const struct device *dev)
|
2024-10-22 16:00:54 +02:00
|
|
|
{
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
|
2025-05-09 16:16:05 -05:00
|
|
|
if (dev == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-10-22 16:00:54 +02:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(_devices_constraints); i++) {
|
2025-02-05 23:10:29 +00:00
|
|
|
const struct device *device = device_get_binding(_devices_constraints[i].dev);
|
|
|
|
|
2025-05-09 16:16:05 -05:00
|
|
|
if (device == dev) {
|
|
|
|
return &_devices_constraints[i];
|
2024-10-22 16:00:54 +02:00
|
|
|
}
|
|
|
|
}
|
2025-05-09 16:16:05 -05:00
|
|
|
#endif
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pm_policy_device_power_lock_get(const struct device *dev)
|
|
|
|
{
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
|
|
|
|
struct pm_state_device_constraint *constraints =
|
|
|
|
pm_policy_priv_device_find_device_constraints(dev);
|
|
|
|
if (constraints == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t j = 0; j < constraints->pm_constraints_size; j++) {
|
|
|
|
pm_policy_state_lock_get(constraints->constraints[j].state,
|
|
|
|
constraints->constraints[j].substate_id);
|
|
|
|
}
|
2024-10-22 16:00:54 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void pm_policy_device_power_lock_put(const struct device *dev)
|
|
|
|
{
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
|
2025-05-09 16:16:05 -05:00
|
|
|
struct pm_state_device_constraint *constraints =
|
|
|
|
pm_policy_priv_device_find_device_constraints(dev);
|
|
|
|
if (constraints == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2025-02-05 23:10:29 +00:00
|
|
|
|
2025-05-09 16:16:05 -05:00
|
|
|
for (size_t j = 0; j < constraints->pm_constraints_size; j++) {
|
|
|
|
pm_policy_state_lock_put(constraints->constraints[j].state,
|
|
|
|
constraints->constraints[j].substate_id);
|
2024-10-22 16:00:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2025-05-09 16:17:41 -05:00
|
|
|
|
|
|
|
bool pm_policy_device_is_disabling_state(const struct device *dev,
|
|
|
|
enum pm_state state, uint8_t substate_id)
|
|
|
|
{
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
|
|
|
|
struct pm_state_device_constraint *constraints =
|
|
|
|
pm_policy_priv_device_find_device_constraints(dev);
|
|
|
|
if (constraints == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t j = 0; j < constraints->pm_constraints_size; j++) {
|
|
|
|
if (constraints->constraints[j].state == state &&
|
|
|
|
constraints->constraints[j].substate_id == substate_id) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|