diff options
author | Anurag Koul <anurag.koul@arm.com> | 2020-09-10 18:48:56 +0100 |
---|---|---|
committer | jimqui01 <54316584+jimqui01@users.noreply.github.com> | 2020-09-15 17:03:53 +0100 |
commit | 4097f3510f8d5d9b91c64f3e4c967a1ec7031f15 (patch) | |
tree | 012771a3ea6833d503216dc0cbf8a01ff18235ed /product/morello | |
parent | 6692e56d78e38aad58af382a3faa5f2d142d7e31 (diff) |
morello/module: add morello_smt module
This patch adds a module, morello_smt, based on core smt module
but modified to support smt master interface APIs until SCMI agent
support is added in the core module.
Signed-off-by: Anurag Koul <anurag.koul@arm.com>
Change-Id: I861ae553b994d4cd2cdd7e0cc81f65a2fcf47dc4
Diffstat (limited to 'product/morello')
-rw-r--r-- | product/morello/module/morello_smt/include/internal/smt.h | 64 | ||||
-rw-r--r-- | product/morello/module/morello_smt/include/mod_smt.h | 302 | ||||
-rw-r--r-- | product/morello/module/morello_smt/src/Makefile | 11 | ||||
-rw-r--r-- | product/morello/module/morello_smt/src/mod_smt.c | 560 |
4 files changed, 937 insertions, 0 deletions
diff --git a/product/morello/module/morello_smt/include/internal/smt.h b/product/morello/module/morello_smt/include/internal/smt.h new file mode 100644 index 00000000..6b6510b6 --- /dev/null +++ b/product/morello/module/morello_smt/include/internal/smt.h @@ -0,0 +1,64 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef INTERNAL_SMT_H +#define INTERNAL_SMT_H + +#include <fwk_attributes.h> + +#include <stdint.h> + +struct FWK_PACKED mod_smt_memory { + uint32_t reserved0; + uint32_t status; + uint64_t reserved1; + uint32_t flags; + uint32_t length; /* message_header + payload */ + uint32_t message_header; + uint32_t payload[]; +}; + +#define MOD_SMT_MAX_CHANNELS 8 + +#define MOD_SMT_MAILBOX_STATUS_FREE_POS 0 +#define MOD_SMT_MAILBOX_STATUS_FREE_MASK \ + (UINT32_C(0x1) << MOD_SMT_MAILBOX_STATUS_FREE_POS) + +#define MOD_SMT_MAILBOX_STATUS_ERROR_POS 1 +#define MOD_SMT_MAILBOX_STATUS_ERROR_MASK \ + (UINT32_C(0x1) << MOD_SMT_MAILBOX_STATUS_ERROR_POS) + +#define MOD_SMT_MAILBOX_FLAGS_IENABLED_POS 0 +#define MOD_SMT_MAILBOX_FLAGS_IENABLED_MASK \ + (UINT32_C(0x1) << MOD_SMT_MAILBOX_FLAGS_IENABLED_POS) + +#define MOD_SMT_MIN_PAYLOAD_SIZE \ + sizeof(((struct mod_smt_memory *)NULL)->payload[0]) + +#define MOD_SMT_MIN_MAILBOX_SIZE \ + (sizeof(struct mod_smt_memory) + MOD_SMT_MIN_PAYLOAD_SIZE) + +#define SCMI_MESSAGE_HEADER_MESSAGE_ID_POS 0 +#define SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS 10 +#define SCMI_MESSAGE_HEADER_TOKEN_POS 18 + +#define SCMI_MESSAGE_HEADER_MESSAGE_ID_MASK \ + (UINT32_C(0x3FF) << SCMI_MESSAGE_HEADER_MESSAGE_ID_POS) +#define SCMI_MESSAGE_HEADER_PROTOCOL_ID_MASK \ + (UINT32_C(0xFF) << SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS) +#define SCMI_MESSAGE_HEADER_TOKEN_MASK \ + (UINT32_C(0x3FF) << SCMI_MESSAGE_HEADER_TOKEN_POS) + +#define SCMI_MESSAGE_HEADER(MESSAGE_ID, PROTOCOL_ID, TOKEN) \ + ((((MESSAGE_ID) << SCMI_MESSAGE_HEADER_MESSAGE_ID_POS) & \ + SCMI_MESSAGE_HEADER_MESSAGE_ID_MASK) | \ + (((PROTOCOL_ID) << SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS) & \ + SCMI_MESSAGE_HEADER_PROTOCOL_ID_MASK) | \ + (((TOKEN) << SCMI_MESSAGE_HEADER_TOKEN_POS) & \ + SCMI_MESSAGE_HEADER_TOKEN_POS)) + +#endif /* INTERNAL_SMT_H */ diff --git a/product/morello/module/morello_smt/include/mod_smt.h b/product/morello/module/morello_smt/include/mod_smt.h new file mode 100644 index 00000000..dd4e2dc1 --- /dev/null +++ b/product/morello/module/morello_smt/include/mod_smt.h @@ -0,0 +1,302 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MOD_SMT_H +#define MOD_SMT_H + +#include <fwk_id.h> + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +/*! + * \name Channel policies + * + * \details These policies define attributes that affect how the channel is + * treated by the SMT component. + * + * @{ + */ + +/*! No policies */ +#define MOD_SMT_POLICY_NONE ((uint32_t)0) + +/*! This channel is secure */ +#define MOD_SMT_POLICY_SECURE ((uint32_t)(1 << 0)) + +/*! The mailbox for this channel requires initialization */ +#define MOD_SMT_POLICY_INIT_MAILBOX ((uint32_t)(1 << 1)) + +/*! + * @} + */ + +/*! + * \brief Channel type + * + * \details Defines the role of an entity in a channel + */ +enum mod_smt_channel_type { + /*! Master channel */ + MOD_SMT_CHANNEL_TYPE_MASTER, + + /*! Slave channel */ + MOD_SMT_CHANNEL_TYPE_SLAVE, + + /*! Channel type count */ + MOD_SMT_CHANNEL_TYPE_COUNT, +}; + +/*! + * \brief Channel config. + */ +struct mod_smt_channel_config { + /*! Channel role (slave or master) */ + enum mod_smt_channel_type type; + + /*! Channel policies */ + uint32_t policies; + + /*! Shared mailbox address */ + uintptr_t mailbox_address; + + /*! Shared mailbox size in bytes */ + size_t mailbox_size; + + /*! Identifier of the driver */ + fwk_id_t driver_id; + + /*! Identifier of the driver API to bind to */ + fwk_id_t driver_api_id; + + /*! Identifier of the power domain that this channel depends on */ + fwk_id_t pd_source_id; +}; + +/*! + * \brief SMT command configuration (used by SCMI agent). + */ +struct mod_smt_command_config { + /*! SCMI protocol ID of the command */ + unsigned int protocol_id; + + /*! SCMI message ID of the command */ + unsigned int message_id; + + /*! Pointer to SCMI payload data */ + void *payload; + + /*! SCMI payload size in bytes */ + size_t size; +}; + +/*! + * \brief Driver API + */ +struct mod_smt_driver_api { + /*! + * \brief Raise an interrupt on the receiver + * + * \param device_id Device identifier + * + * \retval FWK_SUCCESS The operation succeeded + * \retval FWK_E_PARAM The device_id parameter is invalid + * \return One of the standard error codes for implementation-defined + * errors + */ + int (*raise_interrupt)(fwk_id_t device_id); +}; + +/*! + * \brief Driver input API (Implemented by SMT) + * + * \details Interface used for driver -> SMT communication. + */ +struct mod_smt_driver_input_api { + /*! + * \brief Signal an incoming message in the mailbox + * + * \param device_id Channel identifier + * + * \retval FWK_SUCCESS The operation succeeded. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*signal_message)(fwk_id_t channel_id); +}; + +/*! + * \brief SCMI module to transport entity API. + */ +struct mod_scmi_to_transport_api { + /*! + * \brief Check whether a channel is secure or non-secure. + * + * \param channel_id Channel identifier. + * \param[out] secure The channel security state. True + * if the channel is secure, or false if it is non-secure. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The secure parameter is NULL. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_secure)(fwk_id_t channel_id, bool *secure); + + /*! + * \brief Get the maximum permitted payload size of a channel. + * + * \param channel_id Channel identifier. + * \param[out] size The maximum payload size in bytes. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The size parameter is NULL. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_max_payload_size)(fwk_id_t channel_id, size_t *size); + + /*! + * \brief Get the SCMI message header from a channel. + * + * \param channel_id Channel identifier. + * \param[out] message_header The SCMI message header. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The message_header parameter is NULL. + * \retval FWK_E_ACCESS No message is available to read. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_message_header)(fwk_id_t channel_id, uint32_t *message_header); + + /*! + * \brief Get the SCMI payload from a channel. + * + * \param channel_id Channel identifier. + * \param[out] payload The pointer to the payload. + * \param[out] size The payload size. May be NULL, in which case the + * parameter should be ignored. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The payload parameter is NULL. + * \retval FWK_E_ACCESS No message is available to read. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_payload)(fwk_id_t channel_id, const void **payload, size_t *size); + + /*! + * \brief Write part of a payload to a channel. + * + * \param channel_id Channel identifier. + * \param offset Offset to begin writing at. + * \param payload Payload data to write. + * \param size Size of the payload data. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The payload parameter is NULL. + * \retval FWK_E_PARAM The offset and size provided are not within the + * bounds of the payload area. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*write_payload)( + fwk_id_t channel_id, + size_t offset, + const void *payload, + size_t size); + + /*! + * \brief Respond to an SCMI message on a channel. + * + * \param channel_id Channel identifier. + * \param payload Payload data to write, or NULL if a payload has already + * been written. + * \param size Size of the payload source. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The size parameter is less than the size of one + * payload entry. + * \retval FWK_E_ACCESS No message is available to respond to. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*respond)(fwk_id_t channel_id, const void *payload, size_t size); +}; + +/*! + * \brief SCMI Agent to Transport API + * + * \details Interface used for SCMI Agent -> SMT communication. + */ +struct mod_scmi_agent_to_transport_api { + /*! + * \brief Check if a channel is free to use or not. + * + * \param channel_id Channel identifier + * + * \retval true The channel is free and the mailbox can be written to. + * \return false The channel is busy and the mailbox cannot be written. + */ + bool (*is_channel_free)(fwk_id_t channel_id); + + /*! + * \brief Send an SCMI message to platform + * + * \param channel_id Channel identifier + * \param cmd Pointer to SMT command configuration + * + * \retval FWK_SUCCESS The operation succeeded. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*send)(fwk_id_t channel_id, struct mod_smt_command_config *cmd); + + /*! + * \brief Get the SCMI payload from a channel. + * + * \param channel_id Channel identifier. + * \param[out] payload The pointer to the payload. + * \param[out] size The payload size. May be NULL, in which case the + * parameter should be ignored. + * + * \retval FWK_SUCCESS The operation succeeded. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_payload)(fwk_id_t channel_id, const void **payload, size_t *size); + + /*! + * \brief Release the SMT channel + * + * \param channel_id Channel identifier + * + * \retval FWK_SUCCESS The operation succeeded. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*put_channel)(fwk_id_t channel_id); +}; + +/*! + * \brief Type of the interfaces exposed by the power domain module. + */ +enum mod_smt_api_idx { + MOD_SMT_API_IDX_DRIVER_INPUT, + MOD_SMT_API_IDX_SCMI_PLATFORM_TRANSPORT, + MOD_SMT_API_IDX_SCMI_AGENT_TRANSPORT, + MOD_SMT_API_IDX_COUNT, +}; + +#endif /* MOD_SMT_H */ diff --git a/product/morello/module/morello_smt/src/Makefile b/product/morello/module/morello_smt/src/Makefile new file mode 100644 index 00000000..1e27356b --- /dev/null +++ b/product/morello/module/morello_smt/src/Makefile @@ -0,0 +1,11 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BS_LIB_NAME := MORELLO_SMT +BS_LIB_SOURCES = mod_smt.c + +include $(BS_DIR)/lib.mk diff --git a/product/morello/module/morello_smt/src/mod_smt.c b/product/morello/module/morello_smt/src/mod_smt.c new file mode 100644 index 00000000..63ac6380 --- /dev/null +++ b/product/morello/module/morello_smt/src/mod_smt.c @@ -0,0 +1,560 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <internal/smt.h> + +#include <mod_smt.h> + +#include <fwk_assert.h> +#include <fwk_id.h> +#include <fwk_interrupt.h> +#include <fwk_mm.h> +#include <fwk_module.h> +#include <fwk_module_idx.h> +#include <fwk_status.h> + +#include <stdbool.h> +#include <string.h> + +struct smt_channel_ctx { + /* Channel identifier */ + fwk_id_t id; + + /* Channel configuration data */ + struct mod_smt_channel_config *config; + + /* Channel read and write cache memory areas */ + struct mod_smt_memory *in, *out; + + /* Message processing in progrees flag */ + volatile bool locked; + + /* Maximum payload size of the channel */ + size_t max_payload_size; + + /* Driver entity identifier */ + fwk_id_t driver_id; + + /* SCMI module service bound to the channel */ + fwk_id_t scmi_service_id; + + /* Driver API */ + struct mod_smt_driver_api *driver_api; +}; + +struct smt_ctx { + /* Table of channel contexts */ + struct smt_channel_ctx *channel_ctx_table; + + /* Number of channels */ + unsigned int channel_count; +}; + +static struct smt_ctx smt_ctx; + +/* + * SCMI Transport API + */ +static int smt_get_secure(fwk_id_t channel_id, bool *secure) +{ + struct smt_channel_ctx *channel_ctx; + + if (secure == NULL) { + assert(false); + return FWK_E_PARAM; + } + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + + *secure = channel_ctx->config->policies & MOD_SMT_POLICY_SECURE; + + return FWK_SUCCESS; +} + +static int smt_get_max_payload_size(fwk_id_t channel_id, size_t *size) +{ + struct smt_channel_ctx *channel_ctx; + + if (size == NULL) { + assert(false); + return FWK_E_PARAM; + } + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + + *size = channel_ctx->max_payload_size; + + return FWK_SUCCESS; +} + +static int smt_get_message_header(fwk_id_t channel_id, uint32_t *header) +{ + struct smt_channel_ctx *channel_ctx; + + if (header == NULL) { + assert(false); + return FWK_E_PARAM; + } + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + + if (!channel_ctx->locked) + return FWK_E_ACCESS; + + *header = channel_ctx->in->message_header; + + return FWK_SUCCESS; +} + +static int smt_get_payload( + fwk_id_t channel_id, + const void **payload, + size_t *size) +{ + struct smt_channel_ctx *channel_ctx; + + if (payload == NULL) { + assert(false); + return FWK_E_PARAM; + } + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + + if (!channel_ctx->locked) + return FWK_E_ACCESS; + + *payload = channel_ctx->in->payload; + + if (size != NULL) { + *size = + channel_ctx->in->length - sizeof(channel_ctx->in->message_header); + } + + return FWK_SUCCESS; +} + +static int smt_write_payload( + fwk_id_t channel_id, + size_t offset, + const void *payload, + size_t size) +{ + struct smt_channel_ctx *channel_ctx; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + + if ((payload == NULL) || (offset > channel_ctx->max_payload_size) || + (size > channel_ctx->max_payload_size) || + ((offset + size) > channel_ctx->max_payload_size)) { + assert(false); + return FWK_E_PARAM; + } + + if (!channel_ctx->locked) + return FWK_E_ACCESS; + + memcpy(((uint8_t *)channel_ctx->out->payload) + offset, payload, size); + + return FWK_SUCCESS; +} + +static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size) +{ + struct smt_channel_ctx *channel_ctx; + struct mod_smt_memory *memory; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + memory = ((struct mod_smt_memory *)channel_ctx->config->mailbox_address); + + /* Copy the header from the write buffer */ + *memory = *channel_ctx->out; + + /* Copy the payload from either the write buffer or the payload parameter */ + memcpy( + memory->payload, + (payload == NULL ? channel_ctx->out->payload : payload), + size); + + /* + * NOTE: Disable interrupts for a brief period to ensure interrupts are not + * erroneously accepted in between unlocking the context, and setting + * the mailbox free bit. The agent should not interrupt during this + * period anyway, but this guard is included to protect against a + * misbehaving agent. + */ + fwk_interrupt_global_disable(); + + channel_ctx->locked = false; + + memory->length = sizeof(memory->message_header) + size; + memory->status |= MOD_SMT_MAILBOX_STATUS_FREE_MASK; + + fwk_interrupt_global_enable(); + + if (memory->flags & MOD_SMT_MAILBOX_FLAGS_IENABLED_MASK) + channel_ctx->driver_api->raise_interrupt(channel_ctx->driver_id); + + return FWK_SUCCESS; +} + +static const struct mod_scmi_to_transport_api smt_mod_scmi_to_transport_api = { + .get_secure = smt_get_secure, + .get_max_payload_size = smt_get_max_payload_size, + .get_message_header = smt_get_message_header, + .get_payload = smt_get_payload, + .write_payload = smt_write_payload, + .respond = smt_respond, +}; + +static bool smt_is_channel_free(fwk_id_t channel_id) +{ + struct smt_channel_ctx *channel_ctx; + struct mod_smt_memory *memory; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + memory = (struct mod_smt_memory *)channel_ctx->config->mailbox_address; + + return ((memory->status & MOD_SMT_MAILBOX_STATUS_FREE_MASK) != 0); +} + +static int smt_send(fwk_id_t channel_id, struct mod_smt_command_config *cmd) +{ + struct smt_channel_ctx *channel_ctx; + struct mod_smt_memory *memory; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + + if (((cmd->size != 0) && (cmd->payload == NULL)) || + (cmd->size > channel_ctx->max_payload_size)) { + assert(false); + return FWK_E_PARAM; + } + + memory = ((struct mod_smt_memory *)channel_ctx->config->mailbox_address); + + if (!smt_is_channel_free(channel_id)) + return FWK_E_ACCESS; + + memory->status &= ~MOD_SMT_MAILBOX_STATUS_FREE_MASK; + channel_ctx->locked = true; + + /* Copy the payload from the payload parameter */ + if (cmd->payload != NULL) + memcpy(memory->payload, cmd->payload, cmd->size); + memory->message_header = + SCMI_MESSAGE_HEADER(cmd->message_id, cmd->protocol_id, 0); + memory->length = sizeof(memory->message_header) + cmd->size; + memory->flags = MOD_SMT_MAILBOX_FLAGS_IENABLED_MASK; + + channel_ctx->driver_api->raise_interrupt(channel_ctx->driver_id); + + return FWK_SUCCESS; +} + +static int smt_put_channel(fwk_id_t channel_id) +{ + struct smt_channel_ctx *channel_ctx; + struct mod_smt_memory *memory; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + memory = (struct mod_smt_memory *)channel_ctx->config->mailbox_address; + + memory->status |= MOD_SMT_MAILBOX_STATUS_FREE_MASK; + channel_ctx->locked = false; + + return FWK_SUCCESS; +} + +static const struct mod_scmi_agent_to_transport_api + smt_mod_scmi_agent_to_transport_api = { + .is_channel_free = smt_is_channel_free, + .send = smt_send, + .get_payload = smt_get_payload, + .put_channel = smt_put_channel, + }; + +/* + * Driver handler API + */ +static int smt_master_handler(struct smt_channel_ctx *channel_ctx) +{ + struct mod_smt_memory *memory, *in; + size_t payload_size; + + /* Check if we are the holding the channel */ + if (!channel_ctx->locked) + return FWK_E_STATE; + + memory = ((struct mod_smt_memory *)channel_ctx->config->mailbox_address); + in = channel_ctx->in; + + /* Check if slave has released the channel */ + if (!(memory->status & MOD_SMT_MAILBOX_STATUS_FREE_MASK)) + return FWK_E_STATE; + + /* Mirror mailbox contents in read buffer (Payload not copied) */ + *in = *memory; + + /* Copy payload from shared memory to read buffer */ + payload_size = in->length - sizeof(in->message_header); + memcpy(in->payload, memory->payload, payload_size); + + return FWK_SUCCESS; +} + +static int smt_signal_message(fwk_id_t channel_id) +{ + struct smt_channel_ctx *channel_ctx; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + + switch (channel_ctx->config->type) { + case MOD_SMT_CHANNEL_TYPE_MASTER: + return smt_master_handler(channel_ctx); + break; + case MOD_SMT_CHANNEL_TYPE_SLAVE: + assert(false); + break; + default: + /* Invalid config */ + assert(false); + break; + } + + return FWK_SUCCESS; +} + +static const struct mod_smt_driver_input_api driver_input_api = { + .signal_message = smt_signal_message, +}; + +/* + * Framework API + */ +static int smt_init( + fwk_id_t module_id, + unsigned int element_count, + const void *data) +{ + smt_ctx.channel_ctx_table = + fwk_mm_calloc(element_count, sizeof(smt_ctx.channel_ctx_table[0])); + if (smt_ctx.channel_ctx_table == NULL) { + assert(false); + return FWK_E_NOMEM; + } + smt_ctx.channel_count = element_count; + + return FWK_SUCCESS; +} + +static int smt_channel_init( + fwk_id_t channel_id, + unsigned int unused, + const void *data) +{ + struct smt_channel_ctx *channel_ctx; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + channel_ctx->config = (struct mod_smt_channel_config *)data; + + /* Validate channel config */ + if ((channel_ctx->config->type >= MOD_SMT_CHANNEL_TYPE_COUNT) || + (channel_ctx->config->mailbox_address == 0) || + (channel_ctx->config->mailbox_size == 0)) { + assert(false); + return FWK_E_DATA; + } + + channel_ctx->id = channel_id; + channel_ctx->in = fwk_mm_alloc(1, channel_ctx->config->mailbox_size); + channel_ctx->out = fwk_mm_alloc(1, channel_ctx->config->mailbox_size); + + if ((channel_ctx->in == NULL) || (channel_ctx->out == NULL)) + return FWK_E_NOMEM; + + channel_ctx->max_payload_size = + channel_ctx->config->mailbox_size - sizeof(struct mod_smt_memory); + + /* Check memory allocations */ + if ((channel_ctx->in == NULL) || (channel_ctx->out == NULL)) { + assert(false); + return FWK_E_NOMEM; + } + + return FWK_SUCCESS; +} + +static int smt_bind(fwk_id_t id, unsigned int round) +{ + int status; + struct smt_channel_ctx *channel_ctx; + + if (round == 0) { + if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) + return FWK_SUCCESS; + + channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(id)]; + status = fwk_module_bind( + channel_ctx->config->driver_id, + channel_ctx->config->driver_api_id, + &channel_ctx->driver_api); + if (status != FWK_SUCCESS) + return status; + channel_ctx->driver_id = channel_ctx->config->driver_id; + } + + return FWK_SUCCESS; +} + +static int smt_process_bind_request( + fwk_id_t source_id, + fwk_id_t target_id, + fwk_id_t api_id, + const void **api) +{ + struct smt_channel_ctx *channel_ctx; + + /* Only bind to a channel (not the whole module) */ + if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) { + /* Tried to bind to something other than a specific channel */ + assert(false); + return FWK_E_PARAM; + } + + channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(target_id)]; + + switch (fwk_id_get_api_idx(api_id)) { + case MOD_SMT_API_IDX_DRIVER_INPUT: + /* Driver input API */ + + /* + * Make sure that the element that is trying to bind to us is the + * same element that we previously bound to. + * + * NOTE: We bound to an element but a sub-element should be binding + * back to us. This means we cannot use fwk_id_is_equal() because + * the ids have different types. For now we compare the indicies + * manually. + */ + if (fwk_id_get_module_idx(channel_ctx->driver_id) == + fwk_id_get_module_idx(source_id) && + fwk_id_get_element_idx(channel_ctx->driver_id) == + fwk_id_get_element_idx(source_id)) { + /* Ids are equal */ + *api = &driver_input_api; + } else { + /* A module that we did not bind to is trying to bind to us */ + assert(false); + return FWK_E_ACCESS; + } + break; + + case MOD_SMT_API_IDX_SCMI_PLATFORM_TRANSPORT: + /* SCMI transport API */ + *api = &smt_mod_scmi_to_transport_api; + channel_ctx->scmi_service_id = source_id; + break; + + case MOD_SMT_API_IDX_SCMI_AGENT_TRANSPORT: + /* SCMI agent transport API */ + *api = &smt_mod_scmi_agent_to_transport_api; + channel_ctx->scmi_service_id = source_id; + break; + + default: + /* Invalid API */ + assert(false); + return FWK_E_PARAM; + } + + return FWK_SUCCESS; +} + +static int smt_start(fwk_id_t id) +{ + struct smt_channel_ctx *ctx; + + if (!fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) + return FWK_SUCCESS; + + ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(id)]; + +#ifdef BUILD_HAS_MOD_POWER_DOMAIN + /* Register for power domain state transition notifications */ + return fwk_notification_subscribe( + mod_pd_notification_id_power_state_transition, + ctx->config->pd_source_id, + id); +#else + if (ctx->config->policies & MOD_SMT_POLICY_INIT_MAILBOX) { + /* Initialize mailbox */ + *((struct mod_smt_memory *)ctx->config->mailbox_address) = + (struct mod_smt_memory){ + .status = (1 << MOD_SMT_MAILBOX_STATUS_FREE_POS) + }; + } + return FWK_SUCCESS; +#endif +} + +#ifdef BUILD_HAS_MOD_POWER_DOMAIN +static int smt_process_notification( + const struct fwk_event *event, + struct fwk_event *resp_event) +{ + struct mod_pd_power_state_transition_notification_params *params; + struct smt_channel_ctx *channel_ctx; + + assert(fwk_id_is_equal( + event->id, mod_pd_notification_id_power_state_transition)); + assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT)); + + params = (struct mod_pd_power_state_transition_notification_params *) + event->params; + + if (params->state != MOD_PD_STATE_ON) + return FWK_SUCCESS; + + channel_ctx = + &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(event->target_id)]; + + if (channel_ctx->config->policies & MOD_SMT_POLICY_INIT_MAILBOX) { + /* Initialize mailbox */ + *((struct mod_smt_memory *)channel_ctx->config->mailbox_address) = + (struct mod_smt_memory){ + .status = (1 << MOD_SMT_MAILBOX_STATUS_FREE_POS) + }; + } + + return FWK_SUCCESS; +} +#endif + +const struct fwk_module module_morello_smt = { + .name = "MORELLO SMT", + .type = FWK_MODULE_TYPE_SERVICE, + .api_count = MOD_SMT_API_IDX_COUNT, + .init = smt_init, + .element_init = smt_channel_init, + .bind = smt_bind, + .start = smt_start, + .process_bind_request = smt_process_bind_request, +#ifdef BUILD_HAS_MOD_POWER_DOMAIN + .process_notification = smt_process_notification, +#endif +}; |