diff --git a/module/reset_domain/include/mod_reset_domain.h b/module/reset_domain/include/mod_reset_domain.h new file mode 100644 index 0000000000000000000000000000000000000000..6314543306670a4c27ec92261f6c0d967a4c8d7e --- /dev/null +++ b/module/reset_domain/include/mod_reset_domain.h @@ -0,0 +1,115 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Reset domain HAL. + */ + +#ifndef MOD_RESET_DOMAIN_H +#define MOD_RESET_DOMAIN_H + +#include + +/*! + * \addtogroup GroupModules Modules + * @{ + */ + +/*! + * \defgroup GroupResetDomain Reset Domains HAL + * + * \details Support for setting the state of reset domains. + * + * @{ + */ + +/*! + * \brief APIs that the module makes available to entities requesting binding. + */ +enum mod_reset_domain_api_type { + /*! Reset Domain HAL */ + MOD_RESET_DOMAIN_API_TYPE_HAL, + MOD_RESET_DOMAIN_API_COUNT, +}; + + +#ifdef BUILD_HAS_NOTIFICATION +/*! + * \brief Reset domain module configuration data. + * + * TODO: Needed for notification, not yet implemented in reset_domain module + */ +struct mod_reset_domain_config { + /*! + * \brief Identifier of a notification to subscribe reset domain devices to + * in order to receive notifications of reset domains that have already + * occurred. + * + * \note May be \ref FWK_ID_NONE to disable this functionality for all + * elements. + */ + const fwk_id_t notification_id; +}; +#endif + +/*! + * \brief Reset domain element configuration data. + */ +struct mod_reset_domain_dev_config { + /*! Driver identifier */ + const fwk_id_t driver_id; + /*! Driver API identifier */ + const fwk_id_t api_id; +}; + +/*! + * \brief Reset domain driver interface. + * + * \details The interface the reset domain module relies on to perform + * actions on a reset domain. + */ + +struct mod_reset_domain_drv_api { + /*! Name of the driver */ + const char *name; + + /*! + * \brief Target reset domain \p dev_id performs an autonomous reset. + * + * \param dev_id Driver identifier of the reset domain. + * + * \retval FWK_SUCCESS or one of FWK_E_* error codes. + */ + int (*auto_domain)(fwk_id_t dev_id, unsigned int state); + + /*! + * \brief Target reset domain identified by \p dev_id enters reset state. + * + * \param dev_id Driver identifier of the reset domain. + * + * \retval FWK_SUCCESS or one of FWK_E_* error codes. + */ + int (*assert_domain)(fwk_id_t dev_id); + + /*! + * \brief Target reset domain identified by \p dev_id exits reset state. + * + * \param dev_id Driver identifier of the reset domain. + * + * \retval FWK_SUCCESS or one of FWK_E_* error codes. + */ + int (*deassert_domain)(fwk_id_t dev_id); +}; + +/*! + * @} + */ + +/*! + * @} + */ + +#endif /* MOD_RESET_DOMAIN_H */ diff --git a/module/reset_domain/src/Makefile b/module/reset_domain/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..de48f45c66fc8576fc6fd9d30ba2a8dd5f02a545 --- /dev/null +++ b/module/reset_domain/src/Makefile @@ -0,0 +1,11 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BS_LIB_NAME := Reset Domain +BS_LIB_SOURCES := mod_reset_domain.c + +include $(BS_DIR)/lib.mk diff --git a/module/reset_domain/src/mod_reset_domain.c b/module/reset_domain/src/mod_reset_domain.c new file mode 100644 index 0000000000000000000000000000000000000000..2618c623ad061559cd769055d062cb35f3655c01 --- /dev/null +++ b/module/reset_domain/src/mod_reset_domain.c @@ -0,0 +1,168 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Reset domain HAL + */ + +#include +#include +#include +#include +#include + +/* + * Module and devices contexts for Reset Domain + * TODO: notification + */ + +/* Device context */ +struct rd_dev_ctx { + const struct mod_reset_domain_dev_config *config; + struct mod_reset_domain_drv_api *driver_api; +}; + +/* Module context */ +struct rd_mod_ctx { + const struct mod_reset_domain_config *config; + struct rd_dev_ctx *dev_ctx_table; + unsigned int dev_count; + const struct mod_log_api *log_api; +}; + +/* + * Internal variables + */ +static struct rd_mod_ctx module_ctx; + +/* + * API functions + */ +static int rd_autonomous(fwk_id_t reset_id, unsigned int state) +{ + int status = 0; + struct rd_dev_ctx *reset_ctx = NULL; + + status = fwk_module_check_call(reset_id); + if (status != FWK_SUCCESS) + return status; + + reset_ctx = &module_ctx.dev_ctx_table[fwk_id_get_element_idx(reset_id)]; + + return reset_ctx->driver_api->auto_domain(reset_ctx->config->driver_id, + state); +} + +static int rd_assert(fwk_id_t reset_id) +{ + int status = 0; + struct rd_dev_ctx *reset_ctx = NULL; + + status = fwk_module_check_call(reset_id); + if (status != FWK_SUCCESS) + return status; + + reset_ctx = &module_ctx.dev_ctx_table[fwk_id_get_element_idx(reset_id)]; + + return reset_ctx->driver_api->assert_domain(reset_ctx->config->driver_id); +} + +static int rd_deassert(fwk_id_t reset_id) +{ + int status = 0; + struct rd_dev_ctx *reset_ctx = NULL; + + status = fwk_module_check_call(reset_id); + if (status != FWK_SUCCESS) + return status; + + reset_ctx = &module_ctx.dev_ctx_table[fwk_id_get_element_idx(reset_id)]; + + return reset_ctx->driver_api->deassert_domain(reset_ctx->config->driver_id); +} + +static const struct mod_reset_domain_drv_api reset_api = { + .auto_domain = rd_autonomous, + .assert_domain = rd_assert, + .deassert_domain = rd_deassert, +}; + +/* + * Framework handlers + */ +static int rd_init(fwk_id_t module_id, + unsigned int dev_count, const void *data) +{ + module_ctx.dev_count = dev_count; + + module_ctx.config = (struct mod_reset_domain_config *)data; + module_ctx.dev_ctx_table = fwk_mm_calloc(dev_count, + sizeof(struct rd_dev_ctx)); + if (module_ctx.dev_ctx_table == NULL) + return FWK_E_NOMEM; + + return FWK_SUCCESS; +} + +static int rd_elt_init(fwk_id_t elt_id, + unsigned int dev_count, const void *data) +{ + struct rd_dev_ctx *reset_ctx = NULL; + + reset_ctx = &module_ctx.dev_ctx_table[fwk_id_get_element_idx(elt_id)]; + reset_ctx->config = (const struct mod_reset_domain_dev_config *)data; + + return FWK_SUCCESS; +} + + +static int rd_bind(fwk_id_t id, unsigned int round) +{ + struct rd_dev_ctx *reset_ctx = NULL; + + /* Nothing to do but during the first round of calls */ + if (round != 0) { + return FWK_SUCCESS; + } + + if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) { + return fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG), + FWK_ID_API(FWK_MODULE_IDX_LOG, 0), + &module_ctx.log_api); + } + + if (!fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) { + return FWK_SUCCESS; + } + + reset_ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(id); + + return fwk_module_bind(reset_ctx->config->driver_id, + reset_ctx->config->api_id, + &reset_ctx->driver_api); +} + +static int rd_process_bind_request(fwk_id_t source_id, fwk_id_t target_id, + fwk_id_t api_id, const void **api) +{ + if (fwk_id_get_api_idx(api_id) != MOD_RESET_DOMAIN_API_TYPE_HAL) { + return FWK_E_ACCESS; + } + + *api = &reset_api; + + return FWK_SUCCESS; +} + +const struct fwk_module module_reset_domain = { + .name = "Reset domain", + .type = FWK_MODULE_TYPE_HAL, + .api_count = MOD_RESET_DOMAIN_API_COUNT, + .init = rd_init, + .element_init = rd_elt_init, + .bind = rd_bind, + .process_bind_request = rd_process_bind_request, +}; diff --git a/module/scmi_reset_domain/include/internal/scmi_reset_domain.h b/module/scmi_reset_domain/include/internal/scmi_reset_domain.h new file mode 100644 index 0000000000000000000000000000000000000000..8f8c377ec84a3bffd8279f15a66f1955f30c2ed4 --- /dev/null +++ b/module/scmi_reset_domain/include/internal/scmi_reset_domain.h @@ -0,0 +1,141 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * System Control and Management Interface (SCMI) support. + */ + +#ifndef INTERNAL_SCMI_RESET_DOMAIN_H +#define INTERNAL_SCMI_RESET_DOMAIN_H + +/*! + * \addtogroup GroupModules Modules + * @{ + */ + +/*! + * \defgroup GroupSCMI_RESET SCMI Reset Domain Management Protocol + * @{ + */ + +#define SCMI_PROTOCOL_ID_RESET_DOMAIN UINT32_C(0x16) +#define SCMI_PROTOCOL_VERSION_RESET_DOMAIN UINT32_C(0x10000) + +#define SCMI_RESET_STATE_ARCH (1 << 31) +#define SCMI_RESET_STATE_IMPL (0 << 31) + +/* + * Identifiers of the SCMI Reset Domain Management Protocol commands + */ +enum scmi_reset_domain_command_id { + SCMI_RESET_DOMAIN_ATTRIBUTES = 0x03, + SCMI_RESET_REQUEST = 0x04, + SCMI_RESET_NOTIFY = 0x05, +}; + +/* + * Identifiers of the SCMI Reset Domain Management Protocol responses + */ +enum scmi_reset_domain_response_id { + SCMI_RESET_ISSUED = 0x00, + SCMI_RESET_COMPLETE = 0x04, +}; + +/* + * PROTOCOL_ATTRIBUTES + */ + +#define SCMI_RESET_DOMAIN_COUNT_MASK 0x0000ffff + +struct __attribute((packed)) scmi_reset_domain_protocol_attributes_p2a { + int32_t status; + uint32_t attributes; +}; + +/* Value for scmi_reset_domain_attributes_p2a:flags */ +#define SCMI_RESET_DOMAIN_ATTR_ASYNC (1 << 31) +#define SCMI_RESET_DOMAIN_ATTR_NOTIF (1 << 30) + +/* Value for scmi_reset_domain_attributes_p2a:latency */ +#define SCMI_RESET_DOMAIN_ATTR_UNK_LAT 0x7fffffff +#define SCMI_RESET_DOMAIN_ATTR_MAX_LAT 0x7ffffffe + +/* Macro for scmi_reset_domain_attributes_p2a:name */ +#define SCMI_RESET_DOMAIN_ATTR_NAME_SZ 16 + +struct __attribute((packed)) scmi_reset_domain_attributes_a2p { + uint32_t domain_id; +}; + +struct __attribute((packed)) scmi_reset_domain_attributes_p2a { + int32_t status; + uint32_t flags; + uint32_t latency; + uint8_t name[SCMI_RESET_DOMAIN_ATTR_NAME_SZ]; +}; + +/* + * RESET + */ + +/* Values for scmi_reset_domain_request_p2a:flags */ +#define SCMI_RESET_DOMAIN_ASYNC (1 << 2) +#define SCMI_RESET_DOMAIN_EXPLICIT (1 << 1) +#define SCMI_RESET_DOMAIN_AUTO (1 << 0) + +struct __attribute((packed)) scmi_reset_domain_request_a2p { + uint32_t domain_id; + uint32_t flags; + uint32_t reset_state; +}; + +struct __attribute((packed)) scmi_reset_domain_request_p2a { + int32_t status; +}; + +/* + * RESET_NOTIFY + */ + +/* Values for scmi_reset_notify_p2a:flags */ +#define SCMI_RESET_DOMAIN_DO_NOTIFY (1 << 0) + +struct __attribute((packed)) scmi_reset_domain_notify_a2p { + uint32_t domain_id; + uint32_t notify_enable; +}; + +struct __attribute((packed)) scmi_reset_domain_notify_p2a { + int32_t status; +}; + +/* + * RESET_COMPLETE + */ + +struct __attribute((packed)) scmi_reset_domain_complete_p2a { + int32_t status; + uint32_t domain_id; +}; + +/* + * RESET_ISSUED + */ + +struct __attribute((packed)) scmi_reset_domain_issued_p2a { + uint32_t domain_id; + uint32_t reset_state; +}; + +/*! + * @} + */ + +/*! + * @} + */ + +#endif /* INTERNAL_SCMI_RESET_DOMAIN_H */ diff --git a/module/scmi_reset_domain/include/mod_scmi_reset_domain.h b/module/scmi_reset_domain/include/mod_scmi_reset_domain.h new file mode 100644 index 0000000000000000000000000000000000000000..c206c3517917622c93498cb2fdad2301c4b6f29e --- /dev/null +++ b/module/scmi_reset_domain/include/mod_scmi_reset_domain.h @@ -0,0 +1,75 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * SCMI Reset Domain Protocol Support. + */ + +#ifndef MOD_SCMI_RESET_DOMAIN_H +#define MOD_SCMI_RESET_DOMAIN_H + +#include + +/*! + * \ingroup GroupModules Modules + * \defgroup GroupSCMI_RESET SCMI Reset Domain Management Protocol + * \{ + */ + +/*! + * \brief Reset domain device. + * + * \details Reset domain device structures are used in per-agent reset device + * tables. Each contains an identifier of an element that will be bound + * to in order to use the reset device. + */ +struct mod_scmi_reset_domain_device { + /*! + * \brief Reset element identifier. + * + * \details The module that owns the element must implement the Reset API + * that is defined by the \c reset module. + */ + fwk_id_t element_id; +}; + +/*! + * \brief Agent descriptor. + * + * \details Describes an agent that uses the SCMI Reset Domain protocol. + * Provides a pointer to the agent's reset device table and the number of + * devices within the table. + */ +struct mod_scmi_reset_domain_agent { + /*! Pointer to a table of clock devices that are visible to the agent */ + const struct mod_scmi_reset_domain_device *device_table; + + /*! + * \brief The number of \c mod_scmi_reset_domain_device structures in the + * table pointed to by \c device_table. + */ + uint8_t device_count; +}; + +/*! + * \brief Module configuration. + */ +struct mod_scmi_reset_domain_config { + /*! + * \brief Pointer to the table of agent descriptors, used to provide + * per-agent views of reset in the system. + */ + const struct mod_scmi_reset_domain_agent *agent_table; + + /*! Number of agents in \ref agent_table */ + size_t agent_count; +}; + +/*! + * \} + */ + +#endif /* MOD_SCMI_RESET_DOMAIN_H */ diff --git a/module/scmi_reset_domain/src/Makefile b/module/scmi_reset_domain/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5c1573810b13a58bae8b92680e6af30efdc962ca --- /dev/null +++ b/module/scmi_reset_domain/src/Makefile @@ -0,0 +1,11 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BS_LIB_NAME := SCMI Reset Domain Protocol +BS_LIB_SOURCES := mod_scmi_reset_domain.c + +include $(BS_DIR)/lib.mk diff --git a/module/scmi_reset_domain/src/mod_scmi_reset_domain.c b/module/scmi_reset_domain/src/mod_scmi_reset_domain.c new file mode 100644 index 0000000000000000000000000000000000000000..f411432bd12288f1d70e16cdefb7df7f517457d0 --- /dev/null +++ b/module/scmi_reset_domain/src/mod_scmi_reset_domain.c @@ -0,0 +1,414 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * SCMI Reset Domain management protocol support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct scmi_rd_ctx { + /*! SCMI Reset Module Configuration */ + const struct mod_scmi_reset_domain_config *config; + /* Table of agent descriptors,for per-agent views of reset domains */ + const struct mod_scmi_reset_domain_agent *agent_table; + /* Binded module APIs */ + const struct mod_log_api *log_api; + const struct mod_scmi_from_protocol_api *scmi_api; + const struct mod_reset_domain_drv_api *reset_api; +}; + +static int protocol_version_handler(fwk_id_t service_id, + const uint32_t *payload); + +static int protocol_attributes_handler(fwk_id_t service_id, + const uint32_t *payload); + +static int protocol_message_attributes_handler(fwk_id_t service_id, + const uint32_t *payload); + +static int reset_attributes_handler(fwk_id_t service_id, + const uint32_t *payload); + +static int reset_request_handler(fwk_id_t service_id, + const uint32_t *payload); + +static int reset_notify_handler(fwk_id_t service_id, + const uint32_t *payload); + +/* + * Internal variables + */ + +static struct scmi_rd_ctx scmi_rd_ctx; + +static int (*msg_handler_table[])(fwk_id_t, const uint32_t *) = { + [SCMI_PROTOCOL_VERSION] = protocol_version_handler, + [SCMI_PROTOCOL_ATTRIBUTES] = protocol_attributes_handler, + [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = protocol_message_attributes_handler, + [SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_attributes_handler, + [SCMI_RESET_REQUEST] = reset_request_handler, + [SCMI_RESET_NOTIFY] = reset_notify_handler, +}; + +static unsigned int payload_size_table[] = { + [SCMI_PROTOCOL_VERSION] = 0, + [SCMI_PROTOCOL_ATTRIBUTES] = 0, + [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = + sizeof(struct scmi_protocol_message_attributes_a2p), + [SCMI_RESET_DOMAIN_ATTRIBUTES] = + sizeof(struct scmi_reset_domain_attributes_a2p), + [SCMI_RESET_REQUEST] = sizeof(struct scmi_reset_domain_request_a2p), + [SCMI_RESET_NOTIFY] = sizeof(struct scmi_reset_domain_notify_a2p), +}; + +/* + * Reset domain management protocol implementation + */ + +static int protocol_version_handler(fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_protocol_version_p2a outmsg = { + .status = SCMI_SUCCESS, + .version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN, + }; + + scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, sizeof(outmsg)); + + return FWK_SUCCESS; +} + +static int protocol_attributes_handler(fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_reset_domain_protocol_attributes_p2a outmsg = { + .status = SCMI_SUCCESS, + }; + int status = 0; + unsigned int agent_id = 0; + + status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id); + if (status != FWK_SUCCESS) + return status; + + if (agent_id >= scmi_rd_ctx.config->agent_count) + return FWK_E_PARAM; + + outmsg.attributes = + scmi_rd_ctx.config->agent_table[agent_id].device_count; + + scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, sizeof(outmsg)); + + return FWK_SUCCESS; +} + +static int protocol_message_attributes_handler(fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_protocol_message_attributes_p2a outmsg = { + .status = SCMI_NOT_FOUND, + }; + size_t outmsg_size = sizeof(outmsg.status); + struct scmi_protocol_message_attributes_a2p params = { 0 }; + + params = *(const struct scmi_protocol_message_attributes_a2p *)payload; + + if ((params.message_id < FWK_ARRAY_SIZE(msg_handler_table)) && + msg_handler_table[params.message_id]) { + outmsg.status = SCMI_SUCCESS; + outmsg_size = sizeof(outmsg); + } + + scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size); + + return FWK_SUCCESS; +} + +/* + * Given a service identifier, retrieve a pointer to its agent's + * \c mod_scmi_reset_domain_agent structure within the agent table. + */ +static int get_agent_entry(fwk_id_t service_id, + const struct mod_scmi_reset_domain_agent **agent) +{ + int status = 0; + unsigned int agent_id = 0; + + status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id); + if (status != FWK_SUCCESS) + return status; + + if (agent_id >= scmi_rd_ctx.config->agent_count) + return FWK_E_PARAM; + + *agent = &scmi_rd_ctx.agent_table[agent_id]; + + return FWK_SUCCESS; +} + +static int get_reset_device(fwk_id_t service_id, unsigned int domain_id, + const struct mod_scmi_reset_domain_device **device) +{ + int status = 0; + const struct mod_scmi_reset_domain_agent *agent_entry = NULL; + + status = get_agent_entry(service_id, &agent_entry); + if (status != FWK_SUCCESS) + return status; + + if (domain_id >= agent_entry->device_count) + return FWK_E_RANGE; + + *device = &agent_entry->device_table[domain_id]; + + assert(fwk_module_is_valid_element_id((*device)->element_id)); + if (!fwk_module_is_valid_element_id((*device)->element_id)) + return FWK_E_PANIC; + + return FWK_SUCCESS; +} + +static int reset_attributes_handler(fwk_id_t service_id, + const uint32_t *payload) +{ + const struct mod_scmi_reset_domain_device *reset_device = NULL; + struct scmi_reset_domain_attributes_a2p params = { 0 }; + struct scmi_reset_domain_attributes_p2a outmsg = { + .status = SCMI_GENERIC_ERROR, + }; + size_t outmsg_size = sizeof(outmsg.status); + int status = FWK_SUCCESS; + + params = *(const struct scmi_reset_domain_attributes_a2p *)payload; + + status = get_reset_device(service_id, params.domain_id, &reset_device); + if (status != FWK_SUCCESS) { + outmsg.status = SCMI_NOT_FOUND; + goto exit; + } + + /* + * TODO: get Async/Sync support info from module reset + * Currently: no support for async reset, no support for notification + */ + outmsg.flags &= ~SCMI_RESET_DOMAIN_ATTR_ASYNC; + outmsg.flags &= ~SCMI_RESET_DOMAIN_ATTR_NOTIF; + + /* TODO: Get reset latency from reset driver */ + outmsg.latency = SCMI_RESET_DOMAIN_ATTR_UNK_LAT; + + strncpy((char *)outmsg.name, fwk_module_get_name(reset_device->element_id), + sizeof(outmsg.name) - 1); + + outmsg.status = SCMI_SUCCESS; + outmsg_size = sizeof(outmsg); + +exit: + scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size); + + return status; +} + +static int reset_request_handler(fwk_id_t service_id, + const uint32_t *payload) +{ + int status = FWK_SUCCESS; + struct scmi_reset_domain_request_a2p params = { 0 }; + struct scmi_reset_domain_request_p2a outmsg = { + .status = SCMI_NOT_FOUND + }; + size_t outmsg_size = sizeof(outmsg.status); + bool async_reset = false; + const struct mod_reset_domain_drv_api *reset_api = scmi_rd_ctx.reset_api; + const struct mod_scmi_reset_domain_device *reset_device = NULL; + + params = *(const struct scmi_reset_domain_request_a2p *)payload; + + if (params.domain_id >= SCMI_RESET_DOMAIN_COUNT_MASK) + goto exit; + + status = get_reset_device(service_id, params.domain_id, &reset_device); + if (status != FWK_SUCCESS) { + goto exit; + } + + if (async_reset) { + outmsg.status = SCMI_NOT_SUPPORTED; + goto exit; + } + + if (params.flags & SCMI_RESET_DOMAIN_AUTO) + status = reset_api->auto_domain(reset_device->element_id, + params.reset_state); + else if (params.flags & SCMI_RESET_DOMAIN_EXPLICIT) + status = reset_api->assert_domain(reset_device->element_id); + else + status = reset_api->deassert_domain(reset_device->element_id); + + if (status != FWK_SUCCESS) { + outmsg.status = SCMI_NOT_SUPPORTED; + goto exit; + } + + outmsg.status = SCMI_SUCCESS; + outmsg_size = sizeof(outmsg); + +exit: + scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size); + + return status; +} + +static int reset_notify_handler(fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_reset_domain_notify_p2a outmsg = { + .status = SCMI_NOT_SUPPORTED + }; + size_t outmsg_size = sizeof(outmsg.status); + + scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size); + + return FWK_SUCCESS; +} + +/* + * SCMI module -> SCMI power module interface + */ +static int scmi_reset_get_scmi_protocol_id(fwk_id_t protocol_id, + uint8_t *scmi_protocol_id) +{ + int status = 0; + + status = fwk_module_check_call(protocol_id); + if (status != FWK_SUCCESS) + return status; + + *scmi_protocol_id = SCMI_PROTOCOL_ID_RESET_DOMAIN; + + return FWK_SUCCESS; +} + +static int scmi_reset_message_handler(fwk_id_t protocol_id, + fwk_id_t service_id, + const uint32_t *payload, + size_t payload_size, + unsigned int message_id) +{ + int status = 0; + int32_t return_value; + + status = fwk_module_check_call(protocol_id); + if (status != FWK_SUCCESS) + return status; + + static_assert(FWK_ARRAY_SIZE(msg_handler_table) == + FWK_ARRAY_SIZE(payload_size_table), + "[SCMI] Power domain management protocol table sizes not consistent"); + + assert(payload != NULL); + + if (message_id >= FWK_ARRAY_SIZE(msg_handler_table)) { + return_value = SCMI_NOT_SUPPORTED; + goto error; + } + + if (payload_size != payload_size_table[message_id]) { + return_value = SCMI_PROTOCOL_ERROR; + goto error; + } + + return msg_handler_table[message_id](service_id, payload); + +error: + scmi_rd_ctx.scmi_api->respond(service_id, + &return_value, sizeof(return_value)); + return FWK_SUCCESS; +} + +static struct mod_scmi_to_protocol_api scmi_reset_mod_scmi_to_protocol_api = { + .get_scmi_protocol_id = scmi_reset_get_scmi_protocol_id, + .message_handler = scmi_reset_message_handler +}; + +/* + * Framework handlers + */ + +static int scmi_reset_init(fwk_id_t module_id, unsigned int element_count, + const void *data) +{ + const struct mod_scmi_reset_domain_config *config = NULL; + + config = (const struct mod_scmi_reset_domain_config *)data; + + if ((config == NULL) || (config->agent_table == NULL)) + return FWK_E_PARAM; + + scmi_rd_ctx.config = config; + scmi_rd_ctx.agent_table = config->agent_table; + + return FWK_SUCCESS; +} + +static int scmi_reset_bind(fwk_id_t id, unsigned int round) +{ + int status = 0; + + if (round == 1) + return FWK_SUCCESS; + + status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG), + FWK_ID_API(FWK_MODULE_IDX_LOG, 0), + &scmi_rd_ctx.log_api); + if (status != FWK_SUCCESS) + return status; + + status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_SCMI), + FWK_ID_API(FWK_MODULE_IDX_SCMI, + MOD_SCMI_API_IDX_PROTOCOL), + &scmi_rd_ctx.scmi_api); + if (status != FWK_SUCCESS) + return status; + + return fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN), + FWK_ID_API(FWK_MODULE_IDX_RESET_DOMAIN, 0), + &scmi_rd_ctx.reset_api); +} + +static int scmi_reset_process_bind_request(fwk_id_t source_id, fwk_id_t target_id, + fwk_id_t api_id, const void **api) +{ + assert(fwk_id_is_equal(source_id, FWK_ID_MODULE(FWK_MODULE_IDX_SCMI))); + + *api = &scmi_reset_mod_scmi_to_protocol_api; + + return FWK_SUCCESS; +} + +/* SCMI Reset Domain Management Protocol Definition */ +const struct fwk_module module_scmi_reset_domain = { + .name = "SCMI Reset Domain Management Protocol", + .api_count = 1, + .type = FWK_MODULE_TYPE_PROTOCOL, + .init = scmi_reset_init, + .bind = scmi_reset_bind, + .process_bind_request = scmi_reset_process_bind_request, +};