From 7c57fec0d0df5b3b16ab651d528b707cc190a291 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 9 Jul 2024 11:42:31 +0900 Subject: [PATCH] drivers: firmware: scmi: add power domain protocol Added helpers for ARM SCMI power dmomain protocol. Signed-off-by: Yangbo Lu --- doc/hardware/arch/arm-scmi.rst | 12 +++ drivers/firmware/scmi/CMakeLists.txt | 1 + drivers/firmware/scmi/Kconfig | 7 ++ drivers/firmware/scmi/power.c | 95 ++++++++++++++++++++ dts/bindings/firmware/arm,scmi-power.yaml | 21 +++++ include/zephyr/drivers/firmware/scmi/power.h | 68 ++++++++++++++ 6 files changed, 204 insertions(+) create mode 100644 drivers/firmware/scmi/power.c create mode 100644 dts/bindings/firmware/arm,scmi-power.yaml create mode 100644 include/zephyr/drivers/firmware/scmi/power.h diff --git a/doc/hardware/arch/arm-scmi.rst b/doc/hardware/arch/arm-scmi.rst index 65dad1bffce6..c4ffcf8229f1 100644 --- a/doc/hardware/arch/arm-scmi.rst +++ b/doc/hardware/arch/arm-scmi.rst @@ -135,10 +135,22 @@ Protocols Currently, Zephyr has support for the following standard protocols: + #. **Power domain management** #. **Clock management** #. **Pin Control** +Power domain management +*********************** + +This protocol is intended for management of power states of power domains. +This is done via a set of functions implementing various commands, for +example, ``POWER_STATE_GET`` and ``POWER_STATE_SET``. + +.. note:: + This driver is vendor-agnostic. As such, it may be used on any + system that uses SCMI for power domain management operations. + Clock management protocol ************************* diff --git a/drivers/firmware/scmi/CMakeLists.txt b/drivers/firmware/scmi/CMakeLists.txt index 68e4c7a787cb..fbd52e6ed2d1 100644 --- a/drivers/firmware/scmi/CMakeLists.txt +++ b/drivers/firmware/scmi/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_ARM_SCMI_SHMEM shmem.c) # SCMI protocol helper files zephyr_library_sources_ifdef(CONFIG_ARM_SCMI_CLK_HELPERS clk.c) zephyr_library_sources_ifdef(CONFIG_ARM_SCMI_PINCTRL_HELPERS pinctrl.c) +zephyr_library_sources_ifdef(CONFIG_ARM_SCMI_POWER_DOMAIN_HELPERS power.c) diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig index 1b4415452e67..93c1b1189636 100644 --- a/drivers/firmware/scmi/Kconfig +++ b/drivers/firmware/scmi/Kconfig @@ -28,6 +28,13 @@ config ARM_SCMI_PINCTRL_HELPERS help Enable support for SCMI pinctrl protocol helper functions. +config ARM_SCMI_POWER_DOMAIN_HELPERS + bool "Helper functions for SCMI power domain protocol" + default y + depends on DT_HAS_ARM_SCMI_POWER_ENABLED + help + Enable support for SCMI power domain protocol helper functions. + config ARM_SCMI_SHMEM bool "SCMI shared memory (SHMEM) driver" default y diff --git a/drivers/firmware/scmi/power.c b/drivers/firmware/scmi/power.c new file mode 100644 index 000000000000..e2c639a03fc3 --- /dev/null +++ b/drivers/firmware/scmi/power.c @@ -0,0 +1,95 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +DT_SCMI_PROTOCOL_DEFINE_NODEV(DT_INST(0, arm_scmi_power), NULL); + +struct scmi_power_state_get_reply { + int32_t status; + uint32_t power_state; +}; + +int scmi_power_state_get(uint32_t domain_id, uint32_t *power_state) +{ + struct scmi_protocol *proto = &SCMI_PROTOCOL_NAME(SCMI_PROTOCOL_POWER_DOMAIN); + struct scmi_power_state_get_reply reply_buffer; + struct scmi_message msg, reply; + int ret; + + /* sanity checks */ + if (!proto || !power_state) { + return -EINVAL; + } + + if (proto->id != SCMI_PROTOCOL_POWER_DOMAIN) { + return -EINVAL; + } + + msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_POWER_DOMAIN_MSG_POWER_STATE_GET, SCMI_COMMAND, + proto->id, 0x0); + msg.len = sizeof(domain_id); + msg.content = &domain_id; + + reply.hdr = msg.hdr; + reply.len = sizeof(reply_buffer); + reply.content = &reply_buffer; + + ret = scmi_send_message(proto, &msg, &reply); + if (ret < 0) { + return ret; + } + + if (reply_buffer.status != SCMI_SUCCESS) { + return scmi_status_to_errno(reply_buffer.status); + } + + *power_state = reply_buffer.power_state; + + return 0; +} + +int scmi_power_state_set(struct scmi_power_state_config *cfg) +{ + struct scmi_protocol *proto = &SCMI_PROTOCOL_NAME(SCMI_PROTOCOL_POWER_DOMAIN); + struct scmi_message msg, reply; + int status, ret; + + /* sanity checks */ + if (!proto || !cfg) { + return -EINVAL; + } + + if (proto->id != SCMI_PROTOCOL_POWER_DOMAIN) { + return -EINVAL; + } + + /* Currently ASYNC flag is not supported. */ + if (cfg->flags & SCMI_POWER_STATE_SET_FLAGS_ASYNC) { + return -ENOTSUP; + } + + msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_POWER_DOMAIN_MSG_POWER_STATE_SET, SCMI_COMMAND, + proto->id, 0x0); + msg.len = sizeof(*cfg); + msg.content = cfg; + + reply.hdr = msg.hdr; + reply.len = sizeof(status); + reply.content = &status; + + ret = scmi_send_message(proto, &msg, &reply); + if (ret < 0) { + return ret; + } + + if (status != SCMI_SUCCESS) { + return scmi_status_to_errno(status); + } + + return 0; +} diff --git a/dts/bindings/firmware/arm,scmi-power.yaml b/dts/bindings/firmware/arm,scmi-power.yaml new file mode 100644 index 000000000000..41ad234681d0 --- /dev/null +++ b/dts/bindings/firmware/arm,scmi-power.yaml @@ -0,0 +1,21 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: System Control and Management Interface (SCMI) power domain protocol + +compatible: "arm,scmi-power" + +include: [base.yaml] + +properties: + reg: + required: true + const: [0x11] + + "#power-domain-cells": + type: int + required: true + const: 1 + +power-domain-cells: + - name diff --git a/include/zephyr/drivers/firmware/scmi/power.h b/include/zephyr/drivers/firmware/scmi/power.h new file mode 100644 index 000000000000..649209c74690 --- /dev/null +++ b/include/zephyr/drivers/firmware/scmi/power.h @@ -0,0 +1,68 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief SCMI power domain protocol helpers + */ + +#ifndef _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_POWER_H_ +#define _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_POWER_H_ + +#include + +#define SCMI_POWER_STATE_SET_FLAGS_ASYNC BIT(0) + +/** + * @struct scmi_power_state_config + * + * @brief Describes the parameters for the POWER_STATE_SET + * command + */ +struct scmi_power_state_config { + uint32_t flags; + uint32_t domain_id; + uint32_t power_state; +}; + +/** + * @brief Power domain protocol command message IDs + */ +enum scmi_power_domain_message { + SCMI_POWER_DOMAIN_MSG_PROTOCOL_VERSION = 0x0, + SCMI_POWER_DOMAIN_MSG_PROTOCOL_ATTRIBUTES = 0x1, + SCMI_POWER_DOMAIN_MSG_PROTOCOL_MESSAGE_ATTRIBUTES = 0x2, + SCMI_POWER_DOMAIN_MSG_POWER_DOMAIN_ATTRIBUTES = 0x3, + SCMI_POWER_DOMAIN_MSG_POWER_STATE_SET = 0x4, + SCMI_POWER_DOMAIN_MSG_POWER_STATE_GET = 0x5, + SCMI_POWER_DOMAIN_MSG_POWER_STATE_NOTIFY = 0x6, + SCMI_POWER_DOMAIN_MSG_POWER_STATE_CHANGE_REQEUSTED_NOTIFY = 0x7, + SCMI_POWER_DOMAIN_MSG_POWER_DOMAIN_NAME_GET = 0x8, + SCMI_POWER_DOMAIN_MSG_NEGOTIATE_PROTOCOL_VERSION = 0x10, +}; + +/** + * @brief Send the POWER_STATE_SET command and get its reply + * + * @param cfg pointer to structure containing configuration + * to be set + * + * @retval 0 if successful + * @retval negative errno if failure + */ +int scmi_power_state_set(struct scmi_power_state_config *cfg); +/** + * @brief Query the power domain state + * + * @param domain_id ID of the power domain for which the query is done + * @param power_state pointer to be set via this command + * + * @retval 0 if successful + * @retval negative errno if failure + */ +int scmi_power_state_get(uint32_t domain_id, uint32_t *power_state); + +#endif /* _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_POWER_H_ */