aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManoj Kumar <manoj.kumar3@arm.com>2018-11-26 19:20:09 +0530
committerronald-cron-arm <39518861+ronald-cron-arm@users.noreply.github.com>2018-11-28 18:02:20 +0100
commit23c5bc022c2d2bd54766d523d67a6897b9cdeae8 (patch)
tree362518e41c2102decb376ebe8d7c26a6d830e7f9
parent03932702a2e309e41474664cb8088f74718f178d (diff)
n1sdp/n1sdp_smt: add module n1sdp_smt
This patch adds n1sdp_smt module taken from core smt module but modified to support smt master interface APIs. This modification resides under product folder until SCMI agent support is added in core module. Change-Id: I42dc986b6cb8a430081ec69eb698ac61618d4791 Signed-off-by: Manoj Kumar <manoj.kumar3@arm.com>
-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
+};