aboutsummaryrefslogtreecommitdiff
path: root/module/scmi_apcore
diff options
context:
space:
mode:
Diffstat (limited to 'module/scmi_apcore')
-rw-r--r--module/scmi_apcore/doc/scmi_apcore.md153
-rw-r--r--module/scmi_apcore/include/internal/scmi_apcore.h71
-rw-r--r--module/scmi_apcore/include/mod_scmi_apcore.h75
-rw-r--r--module/scmi_apcore/src/Makefile11
-rw-r--r--module/scmi_apcore/src/mod_scmi_apcore.c432
5 files changed, 742 insertions, 0 deletions
diff --git a/module/scmi_apcore/doc/scmi_apcore.md b/module/scmi_apcore/doc/scmi_apcore.md
new file mode 100644
index 00000000..9af53a93
--- /dev/null
+++ b/module/scmi_apcore/doc/scmi_apcore.md
@@ -0,0 +1,153 @@
+SCMI AP Core Configuration Protocol v1.0
+========================================
+
+Protocol Overview {#scmi_apcore_protocol_overview}
+=================
+
+This protocol is an extension of the [Arm System Control and Management
+Interface (SCMI)]
+(http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html).
+
+The goal of this protocol is for the SCP to provide an interface to the AP
+firmware that supports changing the configuration of one or more AP cores.
+For example, one of the supported commands allows programming of the AP core
+address and is used when AP firmware is unable to program the reset address
+directly.
+
+The protocol identifier used for this protocol (0x90) is within the range that
+the SCMI specification provides for platform-specific extensions (0x80 - 0xFF).
+For further information on protocol identifiers refer to section 4.1.2 of the
+SCMI specification.
+
+Protocol Commands {#scmi_apcore_protocol}
+=================
+
+Protocol Version {#scmi_apcore_protocol_version}
+----------------
+
+On success, this command returns the version of the protocol. For this version
+of the specification the return value must be 0x10000, which corresponds to 1.0.
+
+message_id: 0x0<br>
+protocol_id: 0x90
+
+This command is mandatory.
+
+Return values:
+* int32 status
+ * See section 4.1.4 of the SCMI specification for status code
+ definitions
+* uint32 version
+ * For this version of the specification the return value must be 0x10000
+
+Protocol Attributes {#scmi_apcore_protocol_attributes}
+-------------------
+
+This command returns the implementation details associated with this protocol.
+
+message_id: 0x1<br>
+protocol_id: 0x90
+
+This command is mandatory.
+
+Return values:
+* int32 status
+ * See section 4.1.4 of the SCMI specification for status code
+ definitions
+* uint32 attributes
+ * Bits [31:1] Reserved, must be zero.
+ * Bit [0] If set to 1, the platform supports 64-bit reset addresses. If set
+ to 0, the platform supports 32-bit reset addresses.
+
+Protocol Message Attributes {#scmi_apcore_protocol_message__attributes}
+---------------------------
+
+On success, this command returns the implementation details associated with a
+specific message in this protocol. In addition to the standard status codes
+described in section 4.1.4 of the SCMI specification, the command can return the
+error NOT_FOUND if the message identified by message_id is not provided by
+the implementation.
+
+message_id: 0x2<br>
+protocol_id: 0x90
+
+This command is mandatory.
+
+Parameters:
+* uint32 message_id
+ * message_id of the message.
+
+Return values:
+* int32 status
+ * See section 4.1.4 of the SCMI specification for status code
+ definitions.
+* uint32 attributes
+ * Flags associated with a specific command in the protocol. For all commands
+ in this protocol this parameter has a value of 0.
+
+Core Reset Address Set {#scmi_apcore_protocol_set_address}
+----------------------
+
+Set the application core reset address. The address applies to all cores.
+
+In some platforms only the SCP is capable of programming the application core
+reset address. This command allows the SCP to carry out the programming on
+behalf of AP firmware. Such a feature is supported in the [Arm Trusted Firmware]
+(https://github.com/ARM-software/arm-trusted-firmware/blob/master/docs/reset-design.rst)
+
+message_id: 0x3<br>
+protocol_id: 0x90
+
+This command is optional.
+
+Parameters:
+* uint32 Reset address (lower word)
+ * Bit[31:0] AP core reset address (low)
+* uint32 Reset address (higher word)
+ * Bit[31:0] AP core reset address (high)
+ * On platforms that support only 32-bit addresses, only the lower word is
+ used - this higher word must be zero and the address must be 4-byte
+ aligned. For platforms supporting 64-bit addresses both words may be used
+ and the address must be 8-byte aligned.
+* uint32 attributes
+ * Bit[31:1] Reserved, must be zero.
+ * Bit[0] Lock. When set to 1, the platform will deny any further attempts to
+ change the reset address.
+
+Return values:
+* int32 status
+ * SUCCESS if the reset address was set successfully.
+ * INVALID_PARAMETERS:
+ * Reset address alignment is invalid.
+ * Platform supports only 32-bit addresses and the reset address received
+ is larger than 32-bits.
+ * DENIED: The reset address is locked and changes are not permitted.
+ * DENIED: The calling agent is not permitted to modify the reset address.
+ * See section 4.1.4 of the SCMI specification for status code
+ definitions.
+
+Core Reset Address Get {#scmi_apcore_protocol_get_address}
+----------------------
+
+Get the application core reset address. The address applies to all cores.
+
+message_id: 0x4<br>
+protocol_id: 0x90
+
+This command is optional.
+
+Return values:
+* int32 status
+ * SUCCESS if the reset address was retrieved successfully.
+ * DENIED: The calling agent is not permitted to retrieve the reset address.
+ * See section 4.1.4 of the SCMI specification for status code
+ definitions.
+* uint32 Reset address (lower word)
+ * Bit[31:0] AP core reset address (low)
+* uint32 Reset address (higher word)
+ * Bit[31:0] AP core reset address (high)
+ * On platforms that support only 32-bit addresses, only the lower word is
+ used and this higher word must be zero.
+* uint32 attributes
+ * Bit[31:1] Reserved, must be zero.
+ * Bit[0] Lock. When set to 1, changing the reset address is not permitted.
diff --git a/module/scmi_apcore/include/internal/scmi_apcore.h b/module/scmi_apcore/include/internal/scmi_apcore.h
new file mode 100644
index 00000000..d55e676b
--- /dev/null
+++ b/module/scmi_apcore/include/internal/scmi_apcore.h
@@ -0,0 +1,71 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * SCMI Core Configuration Protocol Support
+ */
+
+#ifndef SCMI_APCORE_H
+#define SCMI_APCORE_H
+
+#include <stdint.h>
+
+#define SCMI_PROTOCOL_ID_APCORE UINT32_C(0x90)
+#define SCMI_PROTOCOL_VERSION_APCORE UINT32_C(0x10000)
+
+/*
+ * Identifiers of the SCMI Core Configuration Protocol commands
+ */
+enum scmi_apcore_command_id {
+ SCMI_APCORE_RESET_ADDRESS_SET = 0x3,
+ SCMI_APCORE_RESET_ADDRESS_GET = 0x4,
+};
+
+/*
+ * Protocol Attributes
+ */
+
+#define SCMI_APCORE_PROTOCOL_ATTRIBUTES_64BIT_POS 0
+
+#define SCMI_APCORE_PROTOCOL_ATTRIBUTES_64BIT_MASK \
+ (UINT32_C(0x1) << SCMI_APCORE_PROTOCOL_ATTRIBUTES_64BIT_POS)
+
+/*
+ * Reset Address Set
+ */
+
+#define SCMI_APCORE_RESET_ADDRESS_SET_LOCK_POS 0
+
+#define SCMI_APCORE_RESET_ADDRESS_SET_LOCK_MASK \
+ (UINT32_C(0x1) << SCMI_APCORE_RESET_ADDRESS_SET_LOCK_POS)
+
+struct __attribute((packed)) scmi_apcore_reset_address_set_a2p {
+ uint32_t reset_address_low;
+ uint32_t reset_address_high;
+ uint32_t attributes;
+};
+
+struct __attribute((packed)) scmi_apcore_reset_address_set_p2a {
+ int32_t status;
+};
+
+/*
+ * Reset Address Get
+ */
+
+#define SCMI_APCORE_RESET_ADDRESS_GET_LOCK_POS 0
+
+#define SCMI_APCORE_RESET_ADDRESS_GET_LOCK_MASK \
+ (UINT32_C(0x1) << SCMI_APCORE_RESET_ADDRESS_GET_LOCK_POS)
+
+struct __attribute((packed)) scmi_apcore_reset_address_get_p2a {
+ int32_t status;
+ uint32_t reset_address_low;
+ uint32_t reset_address_high;
+ uint32_t attributes;
+};
+
+#endif /* SCMI_APCORE_H */
diff --git a/module/scmi_apcore/include/mod_scmi_apcore.h b/module/scmi_apcore/include/mod_scmi_apcore.h
new file mode 100644
index 00000000..82fe61d6
--- /dev/null
+++ b/module/scmi_apcore/include/mod_scmi_apcore.h
@@ -0,0 +1,75 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * SCMI Core Configuration Protocol Support.
+ */
+
+#ifndef MOD_SCMI_APCORE_H
+#define MOD_SCMI_APCORE_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*!
+ * \ingroup GroupModules Modules
+ * \defgroup GroupSCMI_APCORE SCMI Core Configuration Protocol
+ * \{
+ */
+
+/*!
+ * \brief Platform reset register widths.
+ */
+enum mod_scmi_apcore_register_width {
+ /*! Single-word, 32-bit reset address registers supported */
+ MOD_SCMI_APCORE_REG_WIDTH_32,
+
+ /*! Double-word, 64-bit reset address registers supported */
+ MOD_SCMI_APCORE_REG_WIDTH_64,
+
+ /*! Number of valid register widths */
+ MOD_SCMI_APCORE_REG_WIDTH_COUNT,
+};
+
+/*!
+ * \brief Reset register group.
+ *
+ * \details Describes a set of reset registers that are contiguous in memory.
+ */
+struct mod_scmi_apcore_reset_register_group {
+ /*! Address of the first register in the group */
+ uintptr_t base_register;
+
+ /*! The number of registers in the group */
+ size_t register_count;
+};
+
+/*!
+ * \brief Module configuration.
+ */
+struct mod_scmi_apcore_config {
+ /*!
+ * \brief Pointer to the table of \ref mod_scmi_apcore_reset_register_group
+ * structures that define the reset registers within the platform.
+ */
+ const struct mod_scmi_apcore_reset_register_group
+ *reset_register_group_table;
+
+ /*!
+ * \brief Number of \ref mod_scmi_apcore_reset_register_group structures in
+ * \ref reset_register_group_table.
+ */
+ size_t reset_register_group_count;
+
+ /*! Width of the reset address supported by the platform */
+ enum mod_scmi_apcore_register_width reset_register_width;
+};
+
+/*!
+ * \}
+ */
+
+#endif /* MOD_SCMI_APCORE_H */
diff --git a/module/scmi_apcore/src/Makefile b/module/scmi_apcore/src/Makefile
new file mode 100644
index 00000000..c5cf7079
--- /dev/null
+++ b/module/scmi_apcore/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Arm SCP/MCP Software
+# Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := SCMI Core Configuration Protocol
+BS_LIB_SOURCES := mod_scmi_apcore.c
+
+include $(BS_DIR)/lib.mk
diff --git a/module/scmi_apcore/src/mod_scmi_apcore.c b/module/scmi_apcore/src/mod_scmi_apcore.c
new file mode 100644
index 00000000..afedf8fc
--- /dev/null
+++ b/module/scmi_apcore/src/mod_scmi_apcore.c
@@ -0,0 +1,432 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * SCMI Core Configuration Protocol Support.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <fwk_errno.h>
+#include <fwk_id.h>
+#include <fwk_macros.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <internal/scmi.h>
+#include <internal/scmi_apcore.h>
+#include <mod_scmi.h>
+#include <mod_scmi_apcore.h>
+
+struct scmi_apcore_ctx {
+ /* Module Configuration */
+ const struct mod_scmi_apcore_config *config;
+
+ /* SCMI module API */
+ const struct mod_scmi_from_protocol_api *scmi_api;
+
+ /*
+ * Tracks whether an agent has requested that the configuration be locked.
+ * \c true if the configuration is locked and the reset address of the CPUs
+ * can no longer be altered, \c false otherwise.
+ */
+ bool locked;
+};
+
+static int scmi_apcore_protocol_version_handler(fwk_id_t service_id,
+ const uint32_t *payload);
+static int scmi_apcore_protocol_attributes_handler(fwk_id_t service_id,
+ const uint32_t *payload);
+static int scmi_apcore_protocol_message_attributes_handler(
+ fwk_id_t service_id, const uint32_t *payload);
+static int scmi_apcore_reset_address_set_handler(fwk_id_t service_id,
+ const uint32_t *payload);
+static int scmi_apcore_reset_address_get_handler(fwk_id_t service_id,
+ const uint32_t *payload);
+
+/*
+ * Internal variables.
+ */
+static struct scmi_apcore_ctx scmi_apcore_ctx;
+
+static int (* const handler_table[])(fwk_id_t, const uint32_t *) = {
+ [SCMI_PROTOCOL_VERSION] = scmi_apcore_protocol_version_handler,
+ [SCMI_PROTOCOL_ATTRIBUTES] = scmi_apcore_protocol_attributes_handler,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] =
+ scmi_apcore_protocol_message_attributes_handler,
+ [SCMI_APCORE_RESET_ADDRESS_SET] = scmi_apcore_reset_address_set_handler,
+ [SCMI_APCORE_RESET_ADDRESS_GET] = scmi_apcore_reset_address_get_handler,
+};
+
+static const 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_APCORE_RESET_ADDRESS_SET] =
+ sizeof(struct scmi_apcore_reset_address_set_a2p),
+ [SCMI_APCORE_RESET_ADDRESS_GET] = 0,
+};
+
+/*
+ * Static, Helper Functions
+ */
+static int set_reset_address(uint32_t address_low, uint32_t address_high)
+{
+ uint64_t address_composite;
+ unsigned int grp_idx;
+ unsigned int reg_idx;
+ const struct mod_scmi_apcore_reset_register_group *reg_group;
+ uintptr_t reset_reg;
+
+ address_composite = ((uint64_t)address_high << 32) | address_low;
+
+ /* Iterate over the reset register group structures */
+ for (grp_idx = 0;
+ grp_idx < scmi_apcore_ctx.config->reset_register_group_count;
+ grp_idx++) {
+
+ reg_group =
+ &scmi_apcore_ctx.config->reset_register_group_table[grp_idx];
+ assert(reg_group->base_register != 0);
+
+ /* Begin with the first register in the group */
+ reset_reg = reg_group->base_register;
+
+ /* Program each reset vector register within the group */
+ for (reg_idx = 0; reg_idx < reg_group->register_count; reg_idx++) {
+ if (scmi_apcore_ctx.config->reset_register_width ==
+ MOD_SCMI_APCORE_REG_WIDTH_32) {
+ /* Treat the register as 32-bit */
+ *(uint32_t *)reset_reg = address_low;
+ reset_reg += sizeof(uint32_t);
+ } else {
+ /* Treat the register as 64-bit */
+ *(uint64_t *)reset_reg = address_composite;
+ reset_reg += sizeof(uint64_t);
+ }
+ }
+ }
+
+ return FWK_SUCCESS;
+}
+
+/*
+ * Protocol Version
+ */
+static int scmi_apcore_protocol_version_handler(fwk_id_t service_id,
+ const uint32_t *payload)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_APCORE,
+ };
+
+ scmi_apcore_ctx.scmi_api->respond(
+ service_id, &return_values, sizeof(return_values));
+ return FWK_SUCCESS;
+}
+
+/*
+ * Protocol Attributes
+ */
+static int scmi_apcore_protocol_attributes_handler(fwk_id_t service_id,
+ const uint32_t *payload)
+{
+ struct scmi_protocol_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .attributes = 0,
+ };
+
+ if (scmi_apcore_ctx.config->reset_register_width ==
+ MOD_SCMI_APCORE_REG_WIDTH_64)
+ return_values.attributes |= SCMI_APCORE_PROTOCOL_ATTRIBUTES_64BIT_MASK;
+
+ scmi_apcore_ctx.scmi_api->respond(
+ service_id,
+ &return_values,
+ sizeof(return_values));
+
+ return FWK_SUCCESS;
+}
+
+/*
+ * Protocol Message Attributes
+ */
+static int scmi_apcore_protocol_message_attributes_handler(fwk_id_t service_id,
+ const uint32_t *payload)
+{
+ size_t response_size;
+ const struct scmi_protocol_message_attributes_a2p *parameters;
+ unsigned int message_id;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .attributes = 0,
+ };
+
+ parameters = (const struct scmi_protocol_message_attributes_a2p *)
+ payload;
+ message_id = parameters->message_id;
+
+ if ((message_id >= FWK_ARRAY_SIZE(handler_table)) ||
+ (handler_table[message_id] == NULL))
+ return_values.status = SCMI_NOT_FOUND;
+
+ response_size = (return_values.status == SCMI_SUCCESS) ?
+ sizeof(return_values) : sizeof(return_values.status);
+
+ scmi_apcore_ctx.scmi_api->respond(
+ service_id, &return_values, response_size);
+
+ return FWK_SUCCESS;
+}
+
+/*
+ * Reset Address Set
+ */
+static int scmi_apcore_reset_address_set_handler(fwk_id_t service_id,
+ const uint32_t *payload)
+{
+ int status;
+ unsigned int agent_id;
+ enum scmi_agent_type agent_type;
+ const struct scmi_apcore_reset_address_set_a2p *parameters;
+ struct scmi_apcore_reset_address_set_p2a return_values = {
+ .status = SCMI_GENERIC_ERROR
+ };
+
+ parameters = (const struct scmi_apcore_reset_address_set_a2p *)payload;
+
+ status = scmi_apcore_ctx.scmi_api->get_agent_id(service_id, &agent_id);
+ if (status != FWK_SUCCESS)
+ goto exit;
+
+ status = scmi_apcore_ctx.scmi_api->get_agent_type(agent_id, &agent_type);
+ if (status != FWK_SUCCESS)
+ goto exit;
+
+ /* Only the PSCI agent may set the reset address */
+ if (agent_type != SCMI_AGENT_TYPE_PSCI) {
+ return_values.status = SCMI_DENIED;
+ goto exit;
+ }
+
+ /* An agent previously requested that the configuration be locked */
+ if (scmi_apcore_ctx.locked) {
+ return_values.status = SCMI_DENIED;
+ goto exit;
+ }
+
+ /*
+ * Ensure that the platform has 64-bit reset vector registers if a reset
+ * address utilizing more that 32 bits has been provided.
+ */
+ if ((parameters->reset_address_high != 0) &&
+ (scmi_apcore_ctx.config->reset_register_width ==
+ MOD_SCMI_APCORE_REG_WIDTH_32)) {
+ return_values.status = SCMI_INVALID_PARAMETERS;
+ goto exit;
+ }
+
+ /* Check for alignment */
+ if (scmi_apcore_ctx.config->reset_register_width ==
+ MOD_SCMI_APCORE_REG_WIDTH_32) {
+ if ((parameters->reset_address_low % 4) != 0) {
+ return_values.status = SCMI_INVALID_PARAMETERS;
+ goto exit;
+ }
+ } else if ((parameters->reset_address_low % 8) != 0) {
+ return_values.status = SCMI_INVALID_PARAMETERS;
+ goto exit;
+ }
+
+ status = set_reset_address(
+ parameters->reset_address_low, parameters->reset_address_high);
+ if (status != FWK_SUCCESS)
+ goto exit;
+
+ return_values.status = SCMI_SUCCESS;
+
+ /* Lock the configuration if requested */
+ if (parameters->attributes & SCMI_APCORE_RESET_ADDRESS_SET_LOCK_MASK)
+ scmi_apcore_ctx.locked = true;
+
+exit:
+ scmi_apcore_ctx.scmi_api->respond(
+ service_id, &return_values, sizeof(return_values));
+ return status;
+}
+
+/*
+ * Reset Address Get
+ */
+static int scmi_apcore_reset_address_get_handler(fwk_id_t service_id,
+ const uint32_t *payload)
+{
+ int status;
+ unsigned int agent_id;
+ const struct mod_scmi_apcore_reset_register_group *reg_group;
+ uint64_t reset_address;
+ enum scmi_agent_type agent_type;
+ struct scmi_apcore_reset_address_get_p2a return_values = {
+ .status = SCMI_GENERIC_ERROR
+ };
+
+ status = scmi_apcore_ctx.scmi_api->get_agent_id(service_id, &agent_id);
+ if (status != FWK_SUCCESS)
+ goto exit;
+
+ status = scmi_apcore_ctx.scmi_api->get_agent_type(agent_id, &agent_type);
+ if (status != FWK_SUCCESS)
+ goto exit;
+
+ /* Only the PSCI agent may get the current reset address */
+ if (agent_type != SCMI_AGENT_TYPE_PSCI) {
+ return_values.status = SCMI_DENIED;
+ goto exit;
+ }
+
+ /* The reset address is common across all reset address registers */
+ reg_group = &scmi_apcore_ctx.config->reset_register_group_table[0];
+
+ if (scmi_apcore_ctx.config->reset_register_width ==
+ MOD_SCMI_APCORE_REG_WIDTH_32) {
+ reset_address = *(uint32_t *)reg_group->base_register;
+ return_values.reset_address_high = 0;
+ } else {
+ reset_address = *(uint64_t *)reg_group->base_register;
+ return_values.reset_address_high = (reset_address >> 32) & UINT32_MAX;
+ }
+
+ return_values.reset_address_low = (uint32_t)reset_address;
+
+ return_values.attributes |=
+ (scmi_apcore_ctx.locked << SCMI_APCORE_RESET_ADDRESS_GET_LOCK_POS);
+ return_values.status = SCMI_SUCCESS;
+
+exit:
+ scmi_apcore_ctx.scmi_api->respond(
+ service_id, &return_values, sizeof(return_values));
+ return status;
+}
+
+/*
+ * SCMI module -> SCMI AP Core Configuration module interface
+ */
+static int scmi_apcore_get_scmi_protocol_id(fwk_id_t protocol_id,
+ uint8_t *scmi_protocol_id)
+{
+ int status;
+
+ status = fwk_module_check_call(protocol_id);
+ if (status != FWK_SUCCESS)
+ return status;
+
+ *scmi_protocol_id = SCMI_PROTOCOL_ID_APCORE;
+
+ return FWK_SUCCESS;
+}
+
+static int scmi_apcore_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;
+ int32_t return_value;
+
+ static_assert(FWK_ARRAY_SIZE(handler_table) ==
+ FWK_ARRAY_SIZE(payload_size_table),
+ "[SCMI] Core configuration protocol table sizes not consistent");
+ assert(payload != NULL);
+
+ status = fwk_module_check_call(protocol_id);
+ if (status != FWK_SUCCESS)
+ return status;
+
+ if (message_id >= FWK_ARRAY_SIZE(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 handler_table[message_id](service_id, payload);
+
+error:
+ scmi_apcore_ctx.scmi_api->respond(
+ service_id,
+ &return_value,
+ sizeof(return_value));
+
+ return FWK_SUCCESS;
+}
+
+static struct mod_scmi_to_protocol_api scmi_apcore_mod_scmi_to_protocol_api = {
+ .get_scmi_protocol_id = scmi_apcore_get_scmi_protocol_id,
+ .message_handler = scmi_apcore_message_handler
+};
+
+/*
+ * Framework handlers
+ */
+
+static int scmi_apcore_init(fwk_id_t module_id, unsigned int element_count,
+ const void *data)
+{
+ const struct mod_scmi_apcore_config *config =
+ (const struct mod_scmi_apcore_config *)data;
+
+ if (config == NULL)
+ return FWK_E_PARAM;
+ if (config->reset_register_group_table == NULL)
+ return FWK_E_PARAM;
+ if (config->reset_register_group_count == 0)
+ return FWK_E_PARAM;
+ if (config->reset_register_width >= MOD_SCMI_APCORE_REG_WIDTH_COUNT)
+ return FWK_E_PARAM;
+
+ scmi_apcore_ctx.config = config;
+
+ return FWK_SUCCESS;
+}
+
+static int scmi_apcore_bind(fwk_id_t id, unsigned int round)
+{
+ if (round == 1)
+ return FWK_SUCCESS;
+
+ /* Bind to the SCMI module, storing an API pointer for later use. */
+ return fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
+ FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_PROTOCOL),
+ &scmi_apcore_ctx.scmi_api);
+}
+
+static int scmi_apcore_process_bind_request(fwk_id_t source_id,
+ fwk_id_t target_id, fwk_id_t api_id, const void **api)
+{
+ /* Only accept binding requests from the SCMI module. */
+ if (!fwk_id_is_equal(source_id, FWK_ID_MODULE(FWK_MODULE_IDX_SCMI)))
+ return FWK_E_ACCESS;
+
+ *api = &scmi_apcore_mod_scmi_to_protocol_api;
+
+ return FWK_SUCCESS;
+}
+
+/* SCMI Clock Management Protocol Definition */
+const struct fwk_module module_scmi_apcore = {
+ .name = "SCMI Core Configuration Protocol",
+ .api_count = 1,
+ .type = FWK_MODULE_TYPE_PROTOCOL,
+ .init = scmi_apcore_init,
+ .bind = scmi_apcore_bind,
+ .process_bind_request = scmi_apcore_process_bind_request,
+};