aboutsummaryrefslogtreecommitdiff
path: root/product/n1sdp/module
diff options
context:
space:
mode:
Diffstat (limited to 'product/n1sdp/module')
-rw-r--r--product/n1sdp/module/n1sdp_smt/include/internal/smt.h60
-rw-r--r--product/n1sdp/module/n1sdp_smt/include/mod_smt.h300
-rw-r--r--product/n1sdp/module/n1sdp_smt/src/Makefile11
-rw-r--r--product/n1sdp/module/n1sdp_smt/src/mod_smt.c629
4 files changed, 1000 insertions, 0 deletions
diff --git a/product/n1sdp/module/n1sdp_smt/include/internal/smt.h b/product/n1sdp/module/n1sdp_smt/include/internal/smt.h
new file mode 100644
index 00000000..98bf73b6
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_smt/include/internal/smt.h
@@ -0,0 +1,60 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMT_H
+#define SMT_H
+
+struct __attribute((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 /* SMT_H */
diff --git a/product/n1sdp/module/n1sdp_smt/include/mod_smt.h b/product/n1sdp/module/n1sdp_smt/include/mod_smt.h
new file mode 100644
index 00000000..c43e0118
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_smt/include/mod_smt.h
@@ -0,0 +1,300 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MOD_SMT_H
+#define MOD_SMT_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <fwk_id.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 secure Pointer to storage for 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 size Pointer to storage for 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 message_header Pointer to storage for 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 payload Pointer to storage for the pointer to the payload.
+ * \param size Pointer to storage for 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 payload Pointer to storage for the pointer to the payload.
+ * \param size Pointer to storage for 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/n1sdp/module/n1sdp_smt/src/Makefile b/product/n1sdp/module/n1sdp_smt/src/Makefile
new file mode 100644
index 00000000..980bfc7a
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_smt/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Arm SCP/MCP Software
+# Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := N1SDP_SMT
+BS_LIB_SOURCES = mod_smt.c
+
+include $(BS_DIR)/lib.mk
diff --git a/product/n1sdp/module/n1sdp_smt/src/mod_smt.c b/product/n1sdp/module/n1sdp_smt/src/mod_smt.c
new file mode 100644
index 00000000..90c77407
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_smt/src/mod_smt.c
@@ -0,0 +1,629 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <fwk_assert.h>
+#include <fwk_errno.h>
+#include <fwk_interrupt.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <fwk_notification.h>
+#include <mod_log.h>
+#include <mod_power_domain.h>
+#include <mod_smt.h>
+#include <internal/smt.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 {
+ /* Log module API */
+ struct mod_log_api *log_api;
+
+ /* 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)
+{
+ int status;
+ struct smt_channel_ctx *channel_ctx;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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)
+{
+ int status;
+ struct smt_channel_ctx *channel_ctx;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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)
+{
+ int status;
+ struct smt_channel_ctx *channel_ctx;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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)
+{
+ int status;
+ struct smt_channel_ctx *channel_ctx;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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)
+{
+ int status;
+ struct smt_channel_ctx *channel_ctx;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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;
+ int status;
+ (void)status;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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;
+ int status;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return false;
+ }
+
+ 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;
+ int status;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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;
+ int status;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS) {
+ assert(false);
+ return status;
+ }
+
+ 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)
+{
+ int status;
+ struct smt_channel_ctx *channel_ctx;
+
+ status = fwk_module_check_call(channel_id);
+ if (status != FWK_SUCCESS)
+ return status;
+
+ 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_module_bind(fwk_module_id_log,
+ FWK_ID_API(FWK_MODULE_IDX_LOG, 0),
+ &smt_ctx.log_api);
+ }
+
+ 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)];
+
+#if 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
+}
+
+#if 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_n1sdp_smt = {
+ .name = "N1SDP 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,
+#if BUILD_HAS_MOD_POWER_DOMAIN
+ .process_notification = smt_process_notification,
+#endif
+};