Merge rss_comm support.

RSS Comm is a new protocol used to between the SPs and security
subsystems like the Secure Enclave on Corstone-1000 or RSS on Kronos.

This change deprecates the OpenAMP based original solution. This will
be removed in a future release.

Change-Id: Ic9038bd5e185a41ae41c4d95316e7a28eb45adf4
Signed-Off-By: Gyorgy Szing <gyorgy.szing@arm.com>
diff --git a/components/messaging/openamp/sp/component.cmake b/components/messaging/openamp/sp/component.cmake
index cee76a0..f5b3d84 100644
--- a/components/messaging/openamp/sp/component.cmake
+++ b/components/messaging/openamp/sp/component.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -22,3 +22,7 @@
 	 PUBLIC
 		"${CMAKE_CURRENT_LIST_DIR}"
 	)
+
+set_property(TARGET ${TGT} APPEND PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+	"mhu"
+)
diff --git a/components/messaging/openamp/sp/openamp_mhu.c b/components/messaging/openamp/sp/openamp_mhu.c
index bafba3e..20f071f 100644
--- a/components/messaging/openamp/sp/openamp_mhu.c
+++ b/components/messaging/openamp/sp/openamp_mhu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -8,7 +8,7 @@
 #include <config/interface/config_store.h>
 #include <config/interface/config_blob.h>
 #include <platform/interface/device_region.h>
-#include <platform/drivers/arm/mhu_driver/mhu_v2.h>
+#include <platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h>
 #include <trace.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -70,6 +70,8 @@
 	} while(!irq_status);
 
 	ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
+	if (ret < 0)
+		return -1;
 
 	ret = mhu_v2_x_channel_clear(rx_dev, channel);
 	if (ret != MHU_V_2_X_ERR_NONE) {
diff --git a/components/messaging/rss_comms/sp/component.cmake b/components/messaging/rss_comms/sp/component.cmake
new file mode 100644
index 0000000..b9b7c4f
--- /dev/null
+++ b/components/messaging/rss_comms/sp/component.cmake
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+	"${CMAKE_CURRENT_LIST_DIR}/rss_comms_messenger_api.h"
+	)
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/rss_comms_messenger.c"
+	"${CMAKE_CURRENT_LIST_DIR}/rss_comms_platform.c"
+	)
+
+target_include_directories(${TGT}
+	 PUBLIC
+		"${CMAKE_CURRENT_LIST_DIR}"
+	)
+
+set_property(TARGET ${TGT} APPEND PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+	"mhu"
+)
diff --git a/components/messaging/rss_comms/sp/rss_comms_messenger.c b/components/messaging/rss_comms/sp/rss_comms_messenger.c
new file mode 100644
index 0000000..644181e
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_messenger.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <trace.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "rss_comms_messenger_api.h"
+#include "rss_comms_platform_api.h"
+
+struct rss_comms_msg {
+	uint8_t *req_buf;
+	size_t req_len;
+	uint8_t *resp_buf;
+};
+
+int rss_comms_messenger_init(struct rss_comms_messenger *rss_comms)
+{
+	int ret = 0;
+
+	if (!rss_comms || rss_comms->msg || rss_comms->platform)
+		return -1;
+
+	rss_comms->msg = calloc(1, sizeof(struct rss_comms_msg));
+	if (!rss_comms->msg)
+		return -1;
+
+	rss_comms->platform = rss_comms_platform_init();
+	if (!rss_comms->platform) {
+		EMSG("Platform init failed");
+		free(rss_comms->msg);
+		rss_comms->msg = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+void rss_comms_messenger_deinit(struct rss_comms_messenger *rss_comms)
+{
+	struct rss_comms_msg *msg = NULL;
+
+	if (!rss_comms)
+		return;
+
+	if (rss_comms->msg) {
+		msg = (struct rss_comms_msg *)rss_comms->msg;
+
+		if (msg->req_buf)
+			free(msg->req_buf);
+		if (msg->resp_buf)
+			free(msg->resp_buf);
+
+		free(msg);
+		rss_comms->msg = NULL;
+	}
+
+	rss_comms_platform_deinit(rss_comms->platform);
+	rss_comms->platform = NULL;
+}
+
+int rss_comms_messenger_call_invoke(struct rss_comms_messenger *rss_comms, uint8_t **resp_buf,
+				    size_t *resp_len)
+{
+	struct rss_comms_msg *msg = NULL;
+	int ret = 0;
+
+	if (!rss_comms || !resp_buf || !resp_len) {
+		EMSG("Invalid arguments");
+		return -1;
+	}
+
+	if (!rss_comms->msg) {
+		EMSG("msg is null");
+		return -1;
+	}
+
+	msg = (struct rss_comms_msg *)rss_comms->msg;
+	*resp_buf = calloc(1, *resp_len);
+
+	if (!(*resp_buf))
+		return -1;
+
+	ret = rss_comms_platform_invoke(rss_comms->platform, *resp_buf, msg->req_buf, resp_len,
+					msg->req_len);
+
+	if (ret < 0) {
+		free(*resp_buf);
+		*resp_buf = NULL;
+		return ret;
+	}
+
+	msg->resp_buf = *resp_buf;
+
+	return 0;
+}
+
+int rss_comms_messenger_call_begin(struct rss_comms_messenger *rss_comms, uint8_t **req_buf,
+				   size_t req_len)
+{
+	int ret = 0;
+	struct rss_comms_msg *msg = NULL;
+
+	if (!rss_comms || !req_buf || !rss_comms->msg)
+		return -1;
+
+	if (req_len > UINT32_MAX || req_len == 0) {
+		EMSG("req_len invalid: %lu", req_len);
+		return -1;
+	}
+
+	msg = (struct rss_comms_msg *)rss_comms->msg;
+
+	if (msg->req_buf)
+		return -1;
+
+	msg->req_buf = calloc(1, req_len);
+
+	if (!msg->req_buf)
+		return -1;
+
+	*req_buf = msg->req_buf;
+	msg->req_len = req_len;
+
+	ret = rss_comms_platform_begin(rss_comms->platform, *req_buf, req_len);
+
+	return ret;
+}
+
+void rss_comms_messenger_call_end(struct rss_comms_messenger *rss_comms)
+{
+	int ret = 0;
+	struct rss_comms_msg *msg = NULL;
+
+	if (!rss_comms || !rss_comms->msg)
+		return;
+
+	msg = (struct rss_comms_msg *)rss_comms->msg;
+
+	if (msg->req_buf)
+		free(msg->req_buf);
+
+	if (msg->resp_buf)
+		free(msg->resp_buf);
+
+	msg->req_len = 0;
+	msg->req_buf = NULL;
+	msg->resp_buf = NULL;
+
+	ret = rss_comms_platform_end(rss_comms->platform);
+
+	if (ret < 0) {
+		EMSG("Platform end failed: %d", ret);
+		return;
+	}
+}
diff --git a/components/messaging/rss_comms/sp/rss_comms_messenger_api.h b/components/messaging/rss_comms/sp/rss_comms_messenger_api.h
new file mode 100644
index 0000000..02bb6b5
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_messenger_api.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RSS_COMMS_MESSENGER_API_H__
+#define __RSS_COMMS_MESSENGER_API_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct rss_comms_messenger {
+	void *msg;
+	void *platform;
+};
+
+int rss_comms_messenger_init(struct rss_comms_messenger *rss_comms);
+void rss_comms_messenger_deinit(struct rss_comms_messenger *rss_comms);
+int rss_comms_messenger_call_invoke(struct rss_comms_messenger *rss_comms, uint8_t **resp_buf,
+				    size_t *resp_len);
+int rss_comms_messenger_call_begin(struct rss_comms_messenger *rss_comms, uint8_t **req_buf,
+				   size_t req_len);
+void rss_comms_messenger_call_end(struct rss_comms_messenger *rss_comms);
+
+#endif /* __RSS_COMMS_MESSENGER_API_H__ */
diff --git a/components/messaging/rss_comms/sp/rss_comms_platform.c b/components/messaging/rss_comms/sp/rss_comms_platform.c
new file mode 100644
index 0000000..5e09db2
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_platform.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#include "platform/interface/mhu_interface.h"
+#include "rss_comms_messenger_api.h"
+#include "rss_comms_platform_api.h"
+
+struct rss_comms_platform {
+	struct platform_mhu_driver rx_dev;
+	struct platform_mhu_driver tx_dev;
+};
+
+struct rss_comms_platform *rss_comms_platform_init(void)
+{
+	struct rss_comms_platform *rss_comms_plat = NULL;
+	int ret = 0;
+
+	rss_comms_plat = calloc(1, sizeof(*rss_comms_plat));
+	if (!rss_comms_plat) {
+		EMSG("rss_comms calloc dev failed");
+		return NULL;
+	}
+
+	ret = platform_mhu_create(&rss_comms_plat->rx_dev, "mhu-receiver", true);
+	if (ret < 0)
+		goto free_plat;
+
+	ret = platform_mhu_create(&rss_comms_plat->tx_dev, "mhu-sender", false);
+	if (ret < 0)
+		goto free_rx_dev;
+
+	return rss_comms_plat;
+
+free_rx_dev:
+	platform_mhu_destroy(&rss_comms_plat->rx_dev);
+free_plat:
+	free(rss_comms_plat);
+
+	return NULL;
+}
+
+int rss_comms_platform_deinit(struct rss_comms_platform *rss_comms_plat)
+{
+	if (!rss_comms_plat)
+		return -1;
+
+	platform_mhu_destroy(&rss_comms_plat->rx_dev);
+	platform_mhu_destroy(&rss_comms_plat->tx_dev);
+
+	free(rss_comms_plat);
+
+	return 0;
+}
+
+int rss_comms_platform_invoke(struct rss_comms_platform *rss_comms_plat, uint8_t *resp_buf,
+			      uint8_t *req_buf, size_t *resp_len, size_t req_len)
+{
+	struct platform_mhu_driver *rx_dev = NULL;
+	struct platform_mhu_driver *tx_dev = NULL;
+	int err = 0;
+
+	if (!rss_comms_plat || !resp_buf || !req_buf)
+		return -1;
+
+	rx_dev = &rss_comms_plat->rx_dev;
+	tx_dev = &rss_comms_plat->tx_dev;
+
+	if (!tx_dev->iface || !tx_dev->iface->send)
+		return -1;
+
+	err = tx_dev->iface->send(tx_dev->context, req_buf, req_len);
+	if (err != 0) {
+		EMSG("mhu send data failed!");
+		return -1;
+	}
+
+	if (!rx_dev->iface || !rx_dev->iface->wait_data || !rx_dev->iface->receive)
+		return -1;
+
+	err = rx_dev->iface->wait_data(rx_dev->context);
+	if (err != 0) {
+		EMSG("mhu wait for signal failed!");
+		return -1;
+	}
+
+	err = rx_dev->iface->receive(rx_dev->context, resp_buf, resp_len);
+	if (err != 0) {
+		EMSG("mhu receive data failed!");
+		return -1;
+	}
+
+	return 0;
+}
+
+int rss_comms_platform_begin(struct rss_comms_platform *rss_comms_plat, uint8_t *req_buf,
+			     size_t req_len)
+{
+	return 0;
+}
+
+int rss_comms_platform_end(struct rss_comms_platform *rss_comms_plat)
+{
+	return 0;
+}
diff --git a/components/messaging/rss_comms/sp/rss_comms_platform_api.h b/components/messaging/rss_comms/sp/rss_comms_platform_api.h
new file mode 100644
index 0000000..ed55506
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_platform_api.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RSS_COMMS_PLATFORM_API_H__
+#define __RSS_COMMS_PLATFORM_API_H__
+
+#include <stdint.h>
+
+struct rss_comms_platform;
+
+struct rss_comms_platform *rss_comms_platform_init(void);
+int rss_comms_platform_deinit(struct rss_comms_platform *rss_comms_plat);
+int rss_comms_platform_invoke(struct rss_comms_platform *rss_comms_plat, uint8_t *resp_buf,
+			      uint8_t *req_buf, size_t *resp_len, size_t req_len);
+int rss_comms_platform_begin(struct rss_comms_platform *rss_comms_plat, uint8_t *req_buf,
+			     size_t req_len);
+int rss_comms_platform_end(struct rss_comms_platform *rss_comms_plat);
+
+#endif /* __RSS_COMMS_PLATFORM_API_H__ */
diff --git a/components/rpc/psa_ipc/service_psa_ipc.c b/components/rpc/psa_ipc/service_psa_ipc.c
index 36c8e36..66ef67c 100644
--- a/components/rpc/psa_ipc/service_psa_ipc.c
+++ b/components/rpc/psa_ipc/service_psa_ipc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -176,13 +176,13 @@
 	if (!resp_msg || !out_len || resp_msg->reply != PSA_SUCCESS)
 		goto caller_end;
 
-	out_vec_param = (struct psa_outvec *)psa_ipc_phys_to_virt(caller,
+	out_vec_param = (struct psa_outvec *)psa_ipc_phys_to_virt(caller->context,
 				psa_u32_to_ptr(resp_msg->params.out_vec));
 
 	for (i = 0; i < resp_msg->params.out_len; i++) {
 		out_vec[i].len = out_vec_param[i].len;
 		unaligned_memcpy(psa_u32_to_ptr(out_vec[i].base),
-				 psa_ipc_phys_to_virt(caller,
+				 psa_ipc_phys_to_virt(caller->context,
 				      psa_u32_to_ptr(out_vec_param[i].base)),
 				 out_vec[i].len);
 	}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_caller.c b/components/rpc/rss_comms/caller/sp/rss_comms_caller.c
new file mode 100644
index 0000000..d857a2e
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_caller.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rss_comms_caller.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "rpc_caller.h"
+#include "rpc_status.h"
+
+struct rss_comms_caller_context {
+	struct rss_comms_messenger rss_comms;
+};
+
+rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid, uint16_t endpoint_id)
+{
+	return RPC_SUCCESS;
+}
+
+rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
+{
+	return RPC_SUCCESS;
+}
+
+rpc_status_t close_session(void *context)
+{
+	return RPC_SUCCESS;
+}
+
+rpc_status_t create_shared_memory(void *context, size_t size,
+				  struct rpc_caller_shared_memory *shared_memory)
+{
+	return RPC_ERROR_INVALID_VALUE;
+}
+
+rpc_status_t release_shared_memory(void *context, struct rpc_caller_shared_memory *shared_memory)
+{
+	return RPC_ERROR_INVALID_VALUE;
+}
+
+rpc_status_t call(void *context, uint16_t opcode, struct rpc_caller_shared_memory *shared_memory,
+		  size_t request_length, size_t *response_length, service_status_t *service_status)
+{
+	return RPC_ERROR_INTERNAL;
+}
+
+rpc_status_t rss_comms_caller_invoke(rss_comms_call_handle handle, uint32_t opcode,
+				     uint8_t **response_buffer, size_t *response_length)
+{
+	struct rpc_caller_interface *caller = (struct rpc_caller_interface *)handle;
+	struct rss_comms_caller_context *context = NULL;
+	int ret = 0;
+
+	if (!handle || !caller->context)
+		return RPC_ERROR_INVALID_VALUE;
+
+	context = (struct rss_comms_caller_context *)caller->context;
+
+	ret = rss_comms_messenger_call_invoke(&context->rss_comms, response_buffer,
+					      response_length);
+	if (ret < 0)
+		return RPC_ERROR_TRANSPORT_LAYER;
+
+	return RPC_SUCCESS;
+}
+
+rpc_status_t rss_comms_caller_init(struct rpc_caller_interface *rpc_caller)
+{
+	struct rss_comms_caller_context *context = NULL;
+	int ret = 0;
+
+	if (!rpc_caller || rpc_caller->context)
+		return RPC_ERROR_INVALID_VALUE;
+
+	context = (struct rss_comms_caller_context *)calloc(1,
+				sizeof(struct rss_comms_caller_context));
+	if (!context)
+		return RPC_ERROR_INTERNAL;
+
+	ret = rss_comms_messenger_init(&context->rss_comms);
+
+	if (ret < 0) {
+		free(context);
+		return RPC_ERROR_TRANSPORT_LAYER;
+	}
+
+	rpc_caller->context = context;
+	rpc_caller->open_session = open_session;
+	rpc_caller->find_and_open_session = find_and_open_session;
+	rpc_caller->close_session = close_session;
+	rpc_caller->create_shared_memory = create_shared_memory;
+	rpc_caller->release_shared_memory = release_shared_memory;
+	rpc_caller->call = call;
+
+	return RPC_SUCCESS;
+}
+
+rss_comms_call_handle rss_comms_caller_begin(struct rpc_caller_interface *caller,
+					     uint8_t **request_buffer, size_t request_length)
+{
+	struct rss_comms_caller_context *context = NULL;
+	int ret = 0;
+
+	if (!caller || !caller->context)
+		return NULL;
+
+	context = (struct rss_comms_caller_context *)caller->context;
+
+	ret = rss_comms_messenger_call_begin(&context->rss_comms, request_buffer, request_length);
+
+	if (ret < 0)
+		return NULL;
+
+	return caller;
+}
+
+rpc_status_t rss_comms_caller_end(rss_comms_call_handle handle)
+{
+	struct rpc_caller_interface *caller = (struct rpc_caller_interface *)handle;
+	struct rss_comms_caller_context *context = NULL;
+
+	if (!handle || !caller->context)
+		return RPC_ERROR_INVALID_VALUE;
+
+	context = (struct rss_comms_caller_context *)caller->context;
+
+	rss_comms_messenger_call_end(&context->rss_comms);
+
+	return RPC_SUCCESS;
+}
+
+rpc_status_t rss_comms_caller_deinit(struct rpc_caller_interface *rpc_caller)
+{
+	struct rss_comms_caller_context *context = NULL;
+
+	if (!rpc_caller)
+		return RPC_ERROR_INVALID_VALUE;
+
+	context = (struct rss_comms_caller_context *)rpc_caller->context;
+
+	rss_comms_messenger_deinit(&context->rss_comms);
+
+	free(context);
+	rpc_caller->context = NULL;
+
+	return RPC_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_caller.h b/components/rpc/rss_comms/caller/sp/rss_comms_caller.h
new file mode 100644
index 0000000..a62edb5
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_caller.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RSS_COMMS_CALLER_H__
+#define __RSS_COMMS_CALLER_H__
+
+#include "rpc_caller.h"
+#include "rss_comms_messenger_api.h"
+
+typedef void *rss_comms_call_handle;
+
+rpc_status_t rss_comms_caller_init(struct rpc_caller_interface *rpc_caller);
+rpc_status_t rss_comms_caller_deinit(struct rpc_caller_interface *rpc_caller);
+
+rss_comms_call_handle rss_comms_caller_begin(struct rpc_caller_interface *caller,
+					     uint8_t **request_buffer, size_t request_length);
+
+rpc_status_t rss_comms_caller_invoke(rss_comms_call_handle handle, uint32_t opcode,
+				     uint8_t **response_buffer, size_t *response_length);
+
+rpc_status_t rss_comms_caller_end(rss_comms_call_handle handle);
+
+#endif /* __RSS_COMMS_CALLER_H__ */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol.c b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.c
new file mode 100644
index 0000000..7969536
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include "rss_comms_protocol.h"
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+					int16_t type,
+					const struct psa_invec *in_vec,
+					uint8_t in_len,
+					const struct psa_outvec *out_vec,
+					uint8_t out_len,
+					struct serialized_rss_comms_msg_t *msg,
+					size_t *msg_len)
+{
+	psa_status_t status = PSA_SUCCESS;
+
+	assert(msg != NULL);
+	assert(msg_len != NULL);
+	assert(in_vec != NULL);
+
+	switch (msg->header.protocol_ver) {
+	case RSS_COMMS_PROTOCOL_EMBED:
+		status = rss_protocol_embed_serialize_msg(handle, type, in_vec, in_len, out_vec,
+							  out_len, &msg->msg.embed, msg_len);
+		if (status != PSA_SUCCESS) {
+			return status;
+		}
+		break;
+	case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+		status = rss_protocol_pointer_access_serialize_msg(handle, type, in_vec, in_len,
+								   out_vec, out_len,
+								   &msg->msg.pointer_access,
+								   msg_len);
+		if (status != PSA_SUCCESS) {
+			return status;
+		}
+		break;
+	default:
+		return PSA_ERROR_NOT_SUPPORTED;
+	}
+
+	*msg_len += sizeof(struct serialized_rss_comms_header_t);
+
+	return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_deserialize_reply(struct psa_outvec *out_vec,
+					    uint8_t out_len,
+					    psa_status_t *return_val,
+					    const struct serialized_rss_comms_reply_t *reply,
+					    size_t reply_size)
+{
+	assert(reply != NULL);
+	assert(return_val != NULL);
+
+	switch (reply->header.protocol_ver) {
+	case RSS_COMMS_PROTOCOL_EMBED:
+		return rss_protocol_embed_deserialize_reply(out_vec, out_len, return_val,
+							    &reply->reply.embed, reply_size);
+	case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+		return rss_protocol_pointer_access_deserialize_reply(out_vec, out_len, return_val,
+								     &reply->reply.pointer_access,
+								     reply_size);
+	default:
+		return PSA_ERROR_NOT_SUPPORTED;
+	}
+
+	return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_calculate_msg_len(psa_handle_t handle,
+					    uint8_t protocol_ver,
+					    const struct psa_invec *in_vec,
+					    uint8_t in_len,
+					    size_t *msg_len)
+{
+	psa_status_t status = PSA_SUCCESS;
+
+	assert(msg_len != NULL);
+	assert(in_vec != NULL);
+
+	switch (protocol_ver) {
+	case RSS_COMMS_PROTOCOL_EMBED:
+		status = rss_protocol_embed_calculate_msg_len(handle, in_vec, in_len, msg_len);
+		if (status != PSA_SUCCESS)
+			return status;
+
+		break;
+	case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+	default:
+		return PSA_ERROR_NOT_SUPPORTED;
+	}
+
+	*msg_len += sizeof(struct serialized_rss_comms_header_t);
+
+	return PSA_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.h
new file mode 100644
index 0000000..2d597b4
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_H__
+#define __RSS_COMMS_PROTOCOL_H__
+
+#include <stdint.h>
+
+#include <psa/client.h>
+#include "rss_comms_protocol_embed.h"
+#include "rss_comms_protocol_pointer_access.h"
+#include "service/common/include/psa/client.h"
+
+enum rss_comms_protocol_version_t {
+	RSS_COMMS_PROTOCOL_EMBED = 0,
+	RSS_COMMS_PROTOCOL_POINTER_ACCESS = 1,
+};
+
+struct __packed serialized_rss_comms_header_t {
+	uint8_t protocol_ver;
+	uint8_t seq_num;
+	uint16_t client_id;
+};
+
+/* MHU message passed from Host to RSS to deliver a PSA client call */
+struct __packed serialized_rss_comms_msg_t {
+	struct serialized_rss_comms_header_t header;
+	union __packed {
+		struct rss_embed_msg_t embed;
+		struct rss_pointer_access_msg_t pointer_access;
+	} msg;
+};
+
+/* MHU reply message to hold the PSA client reply result returned by RSS */
+struct __packed serialized_rss_comms_reply_t {
+	struct serialized_rss_comms_header_t header;
+	union __packed {
+		struct rss_embed_reply_t embed;
+		struct rss_pointer_access_reply_t pointer_access;
+	} reply;
+};
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+					int16_t type,
+					const struct psa_invec *in_vec,
+					uint8_t in_len,
+					const struct psa_outvec *out_vec,
+					uint8_t out_len,
+					struct serialized_rss_comms_msg_t *msg,
+					size_t *msg_len);
+
+psa_status_t rss_protocol_deserialize_reply(struct psa_outvec *out_vec,
+					    uint8_t out_len,
+					    psa_status_t *return_val,
+					    const struct serialized_rss_comms_reply_t *reply,
+					    size_t reply_size);
+
+psa_status_t rss_protocol_calculate_msg_len(psa_handle_t handle,
+					    uint8_t protocol_ver,
+					    const struct psa_invec *in_vec,
+					    uint8_t in_len,
+					    size_t *msg_len);
+
+#endif /* __RSS_COMMS_PROTOCOL_H__ */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_common.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_common.h
new file mode 100644
index 0000000..177d636
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_common.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * Packing scheme of the control parameter
+ *
+ *  31           30-28   27    26-24  23-20   19     18-16   15-0
+ * +------------+-----+------+-------+-----+-------+-------+------+
+ * |            |     |      | invec |     |       | outvec| type |
+ * | Res        | Res | Res  | number| Res | Res   | number|      |
+ * +------------+-----+------+-------+-----+-------+-------+------+
+ *
+ * Res: Reserved.
+ */
+
+#ifndef RSS_COMMS_PROTOCOL_COMMON
+#define RSS_COMMS_PROTOCOL_COMMON
+
+#define TYPE_OFFSET	(0U)
+#define TYPE_MASK	(0xFFFFUL << TYPE_OFFSET)
+#define IN_LEN_OFFSET	(24U)
+#define IN_LEN_MASK	(0x7UL << IN_LEN_OFFSET)
+#define OUT_LEN_OFFSET	(16U)
+#define OUT_LEN_MASK	(0x7UL << OUT_LEN_OFFSET)
+
+#define PARAM_PACK(type, in_len, out_len)			   \
+	(((((uint32_t)(type)) << TYPE_OFFSET) & TYPE_MASK)	 | \
+	 ((((uint32_t)(in_len)) << IN_LEN_OFFSET) & IN_LEN_MASK) | \
+	 ((((uint32_t)(out_len)) << OUT_LEN_OFFSET) & OUT_LEN_MASK))
+
+#endif /* RSS_COMMS_PROTOCOL_COMMON */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.c b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.c
new file mode 100644
index 0000000..6d96ff2
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "rss_comms_protocol_common.h"
+#include "rss_comms_protocol_embed.h"
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+					      int16_t type,
+					      const struct psa_invec *in_vec,
+					      uint8_t in_len,
+					      const struct psa_outvec *out_vec,
+					      uint8_t out_len,
+					      struct rss_embed_msg_t *msg,
+					      size_t *msg_len)
+{
+	uint32_t payload_size = 0;
+	uint32_t i;
+
+	assert(msg != NULL);
+	assert(msg_len != NULL);
+	assert(in_vec != NULL);
+
+	msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+	msg->handle = handle;
+
+	/* Fill msg iovec lengths */
+	for (i = 0U; i < in_len; ++i) {
+		msg->io_size[i] = in_vec[i].len;
+	}
+	for (i = 0U; i < out_len; ++i) {
+		msg->io_size[in_len + i] = out_vec[i].len;
+	}
+
+	for (i = 0U; i < in_len; ++i) {
+		if (in_vec[i].len > sizeof(msg->trailer) - payload_size) {
+			return PSA_ERROR_INVALID_ARGUMENT;
+		}
+		memcpy(msg->trailer + payload_size,
+		       psa_u32_to_ptr(in_vec[i].base),
+		       in_vec[i].len);
+		payload_size += in_vec[i].len;
+	}
+
+	/* Output the actual size of the message, to optimize sending */
+	*msg_len = sizeof(*msg) - sizeof(msg->trailer) + payload_size;
+
+	return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_embed_deserialize_reply(struct psa_outvec *out_vec,
+						  uint8_t out_len,
+						  psa_status_t *return_val,
+						  const struct rss_embed_reply_t *reply,
+						  size_t reply_size)
+{
+	uint32_t payload_offset = 0;
+	uint32_t i;
+
+	assert(reply != NULL);
+	assert(return_val != NULL);
+
+	for (i = 0U; i < out_len; ++i) {
+		if ((sizeof(*reply) - sizeof(reply->trailer) + payload_offset)
+		    > reply_size) {
+			return PSA_ERROR_INVALID_ARGUMENT;
+		}
+
+		memcpy(psa_u32_to_ptr(out_vec[i].base),
+		       reply->trailer + payload_offset,
+		       reply->out_size[i]);
+		out_vec[i].len = reply->out_size[i];
+		payload_offset += reply->out_size[i];
+	}
+
+	*return_val = reply->return_val;
+
+	return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_embed_calculate_msg_len(psa_handle_t handle,
+						  const struct psa_invec *in_vec,
+						  uint8_t in_len,
+						  size_t *msg_len)
+{
+	uint32_t payload_size = 0;
+	uint32_t i = 0;
+
+	assert(in_vec != NULL);
+	assert(msg_len != NULL);
+
+	for (i = 0U; i < in_len; ++i)
+		payload_size += in_vec[i].len;
+
+	/* Output the actual size of the message, to optimize sending */
+	*msg_len = offsetof(struct rss_embed_msg_t, trailer) + payload_size;
+
+	return PSA_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.h
new file mode 100644
index 0000000..29e2250
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_EMBED_H__
+#define __RSS_COMMS_PROTOCOL_EMBED_H__
+
+#include <psa/client.h>
+#include <sys/cdefs.h>
+
+struct __packed rss_embed_msg_t {
+	psa_handle_t handle;
+	uint32_t ctrl_param; /* type, in_len, out_len */
+	uint16_t io_size[PSA_MAX_IOVEC];
+	uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+struct __packed rss_embed_reply_t {
+	int32_t return_val;
+	uint16_t out_size[PSA_MAX_IOVEC];
+	uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+					      int16_t type,
+					      const struct psa_invec *in_vec,
+					      uint8_t in_len,
+					      const struct psa_outvec *out_vec,
+					      uint8_t out_len,
+					      struct rss_embed_msg_t *msg,
+					      size_t *msg_len);
+
+psa_status_t rss_protocol_embed_deserialize_reply(struct psa_outvec *out_vec,
+						  uint8_t out_len,
+						  psa_status_t *return_val,
+						  const struct rss_embed_reply_t *reply,
+						  size_t reply_size);
+
+psa_status_t rss_protocol_embed_calculate_msg_len(psa_handle_t handle,
+						  const struct psa_invec *in_vec,
+						  uint8_t in_len,
+						  size_t *msg_len);
+
+#endif /* __RSS_COMMS_PROTOCOL_EMBED_H__ */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.c b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.c
new file mode 100644
index 0000000..6d7d771
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include "rss_comms_protocol_common.h"
+#include "rss_comms_protocol_pointer_access.h"
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+						       int16_t type,
+						       const struct psa_invec *in_vec,
+						       uint8_t in_len,
+						       const struct psa_outvec *out_vec,
+						       uint8_t out_len,
+						       struct rss_pointer_access_msg_t *msg,
+						       size_t *msg_len)
+{
+	unsigned int i;
+
+	assert(msg != NULL);
+	assert(msg_len != NULL);
+	assert(in_vec != NULL);
+
+	msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+	msg->handle = handle;
+
+	/* Fill msg iovec lengths */
+	for (i = 0U; i < in_len; ++i) {
+		msg->io_sizes[i] = in_vec[i].len;
+		msg->host_ptrs[i] = (uint64_t)in_vec[i].base;
+	}
+	for (i = 0U; i < out_len; ++i) {
+		msg->io_sizes[in_len + i] = out_vec[i].len;
+		msg->host_ptrs[in_len + i] = (uint64_t)out_vec[i].base;
+	}
+
+	*msg_len = sizeof(*msg);
+
+	return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(struct psa_outvec *out_vec,
+							   uint8_t out_len,
+							   psa_status_t *return_val,
+							   const struct rss_pointer_access_reply_t *reply,
+							   size_t reply_size)
+{
+	unsigned int i;
+
+	assert(reply != NULL);
+	assert(return_val != NULL);
+
+	for (i = 0U; i < out_len; ++i) {
+		out_vec[i].len = reply->out_sizes[i];
+	}
+
+	*return_val = reply->return_val;
+
+	return PSA_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.h
new file mode 100644
index 0000000..a1b278c
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+#define __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+
+
+#include <psa/client.h>
+#include <sys/cdefs.h>
+
+struct __packed rss_pointer_access_msg_t {
+	psa_handle_t handle;
+	uint32_t ctrl_param;
+	uint32_t io_sizes[PSA_MAX_IOVEC];
+	uint64_t host_ptrs[PSA_MAX_IOVEC];
+};
+
+struct __packed rss_pointer_access_reply_t {
+	int32_t return_val;
+	uint32_t out_sizes[PSA_MAX_IOVEC];
+};
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+						       int16_t type,
+						       const struct psa_invec *in_vec,
+						       uint8_t in_len,
+						       const struct psa_outvec *out_vec,
+						       uint8_t out_len,
+						       struct rss_pointer_access_msg_t *msg,
+						       size_t *msg_len);
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(struct psa_outvec *out_vec,
+							   uint8_t out_len,
+							   psa_status_t *return_val,
+							   const struct rss_pointer_access_reply_t *reply,
+							   size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__ */
diff --git a/components/rpc/rss_comms/component.cmake b/components/rpc/rss_comms/component.cmake
new file mode 100644
index 0000000..1cafb5c
--- /dev/null
+++ b/components/rpc/rss_comms/component.cmake
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+	${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_caller.h
+	)
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/rss_comms.c"
+	"${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_caller.c"
+	"${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_protocol.c"
+	"${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_protocol_embed.c"
+	"${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_protocol_pointer_access.c"
+	)
+
+target_include_directories(${TGT}
+	 PUBLIC
+		"${CMAKE_CURRENT_LIST_DIR}/caller/sp/"
+	)
+
diff --git a/components/rpc/rss_comms/rss_comms.c b/components/rpc/rss_comms/rss_comms.c
new file mode 100644
index 0000000..267d134
--- /dev/null
+++ b/components/rpc/rss_comms/rss_comms.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "psa/client.h"
+#include "rss_comms_caller.h"
+#include "rss_comms_protocol.h"
+#include "trace.h"
+
+/* This value should be set according to the implemented channels
+ * in the MHU. As only the Embed protocol is supported at the moment,
+ * it is set big enough to fit even the largest messages.
+ */
+#ifndef COMMS_MHU_MSG_SIZE
+#define COMMS_MHU_MSG_SIZE 0x2200
+#endif
+
+static uint8_t select_protocol_version(const struct psa_invec *in_vec, size_t in_len,
+				       const struct psa_outvec *out_vec, size_t out_len)
+{
+	size_t comms_embed_msg_min_size;
+	size_t comms_embed_reply_min_size;
+	size_t in_size_total = 0;
+	size_t out_size_total = 0;
+	size_t i;
+
+	for (i = 0U; i < in_len; ++i) {
+		in_size_total += in_vec[i].len;
+	}
+	for (i = 0U; i < out_len; ++i) {
+		out_size_total += out_vec[i].len;
+	}
+
+	comms_embed_msg_min_size = sizeof(struct serialized_rss_comms_header_t) +
+				   sizeof(struct rss_embed_msg_t) - PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+	comms_embed_reply_min_size = sizeof(struct serialized_rss_comms_header_t) +
+				     sizeof(struct rss_embed_reply_t) -
+				     PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+	/* Use embed if we can pack into one message and reply, else use
+	 * pointer_access. The underlying MHU transport protocol uses a
+	 * single uint32_t to track the length, so the amount of data that
+	 * can be in a message is 4 bytes less than mhu_get_max_message_size
+	 * reports.
+	 *
+	 * TODO tune this with real performance numbers, it's possible a
+	 * pointer_access message is less performant than multiple embed
+	 * messages due to ATU configuration costs to allow access to the
+	 * pointers.
+	 */
+	if ((comms_embed_msg_min_size + in_size_total >
+	     COMMS_MHU_MSG_SIZE - sizeof(uint32_t)) ||
+	    (comms_embed_reply_min_size + out_size_total >
+	     COMMS_MHU_MSG_SIZE - sizeof(uint32_t))) {
+		return RSS_COMMS_PROTOCOL_POINTER_ACCESS;
+	} else {
+		return RSS_COMMS_PROTOCOL_EMBED;
+	}
+}
+
+psa_status_t __psa_call(struct rpc_caller_interface *caller, psa_handle_t handle, int32_t client_id,
+			int32_t type, const struct psa_invec *in_vec, size_t in_len,
+			struct psa_outvec *out_vec, size_t out_len)
+{
+	static uint8_t seq_num = 1U;
+	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+	psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
+	psa_status_t return_val = PSA_ERROR_INVALID_ARGUMENT;
+	rss_comms_call_handle rpc_handle = (rss_comms_call_handle)caller;
+	size_t req_len = 0;
+	size_t resp_len = 0;
+	struct serialized_rss_comms_msg_t *req = NULL;
+	struct serialized_rss_comms_reply_t *reply = NULL;
+	uint8_t protocol_ver = 0;
+
+	protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
+
+	psa_status = rss_protocol_calculate_msg_len(handle, protocol_ver, in_vec, in_len, &req_len);
+	if (psa_status != PSA_SUCCESS) {
+		EMSG("Message size calculation failed: %d", psa_status);
+		return psa_status;
+	}
+
+	rpc_handle = rss_comms_caller_begin(caller, (uint8_t **)&req, req_len);
+	if (!rpc_handle) {
+		EMSG("Could not get handle");
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	req->header.seq_num = seq_num;
+	/* No need to distinguish callers (currently concurrent calls are not supported). */
+	req->header.client_id = client_id;
+	req->header.protocol_ver = protocol_ver;
+
+	psa_status = rss_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec, out_len, req,
+						&req_len);
+	if (psa_status != PSA_SUCCESS) {
+		EMSG("Serialize msg failed: %d", psa_status);
+		return psa_status;
+	}
+
+	DMSG("Sending rss_comms message");
+	DMSG("protocol_ver=%u", req->header.protocol_ver);
+	DMSG("seq_num=%u", req->header.seq_num);
+	DMSG("client_id=%u", req->header.client_id);
+
+	resp_len = sizeof(*reply);
+
+	rpc_status = rss_comms_caller_invoke(rpc_handle, 0, (uint8_t **)&reply, &resp_len);
+	if (rpc_status != RPC_SUCCESS) {
+		EMSG("Invoke failed: %d", rpc_status);
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	DMSG("Received rss_comms reply");
+	DMSG("protocol_ver=%u", reply->header.protocol_ver);
+	DMSG("seq_num=%u", reply->header.seq_num);
+	DMSG("client_id=%u", reply->header.client_id);
+	DMSG("resp_len=%lu", resp_len);
+
+	psa_status = rss_protocol_deserialize_reply(out_vec, out_len, &return_val, reply, resp_len);
+	if (psa_status != PSA_SUCCESS) {
+		EMSG("Protocol deserialize reply failed: %d", psa_status);
+		return psa_status;
+	}
+
+	DMSG("Return_val=%d", return_val);
+
+	rss_comms_caller_end(rpc_handle);
+
+	seq_num++;
+
+	return return_val;
+}
+
+psa_status_t psa_call_client_id(struct rpc_caller_interface *caller, psa_handle_t psa_handle,
+				int32_t client_id, int32_t type, const struct psa_invec *in_vec,
+				size_t in_len, struct psa_outvec *out_vec, size_t out_len)
+{
+	return __psa_call(caller, psa_handle, client_id, type, in_vec, in_len, out_vec, out_len);
+}
+
+psa_status_t psa_call(struct rpc_caller_interface *caller, psa_handle_t psa_handle, int32_t type,
+		      const struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec,
+		      size_t out_len)
+{
+	return __psa_call(caller, psa_handle, 0, type, in_vec, in_len, out_vec, out_len);
+}
diff --git a/components/service/locator/sp/ffa/spffa_service_context.c b/components/service/locator/sp/ffa/spffa_service_context.c
index 0c1616f..f7730d0 100644
--- a/components/service/locator/sp/ffa/spffa_service_context.c
+++ b/components/service/locator/sp/ffa/spffa_service_context.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -52,7 +52,8 @@
 		return NULL;
 
 	rpc_status = rpc_caller_session_find_and_open(session, &this_context->caller,
-						      &this_context->service_uuid, 4096);
+						      &this_context->service_uuid,
+						      RPC_CALLER_SESSION_SHARED_MEMORY_SIZE);
 	if (rpc_status != RPC_SUCCESS) {
 		free(session);
 		return NULL;
diff --git a/components/service/locator/sp/ffa/spffa_service_context.h b/components/service/locator/sp/ffa/spffa_service_context.h
index ff9b2f2..e9ed9c6 100644
--- a/components/service/locator/sp/ffa/spffa_service_context.h
+++ b/components/service/locator/sp/ffa/spffa_service_context.h
@@ -13,6 +13,10 @@
 extern "C" {
 #endif
 
+#ifndef RPC_CALLER_SESSION_SHARED_MEMORY_SIZE
+#define RPC_CALLER_SESSION_SHARED_MEMORY_SIZE	(4096)
+#endif /* RPC_CALLER_SESSION_SHARED_MEMORY_SIZE */
+
 /*
  * A service_context that represents a service instance located in
  * a partition, accessed via FFA.  This service_context is suitable
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
index 986628c..83247d7 100644
--- a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -155,12 +155,18 @@
 	struct rpc_caller_interface *caller = ipc->client.session->caller;
 	psa_status_t psa_status;
 	uint32_t support_flags;
+	uint32_t dummy_vec = 0;
+	/* Use dummy in vector to guarantee parameter checking */
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&dummy_vec), .len = sizeof(dummy_vec) },
+	};
+
 	struct psa_outvec out_vec[] = {
 		{ .base = psa_ptr_to_u32(&support_flags), .len =  sizeof(support_flags) },
 	};
 
 	psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
-					TFM_PS_ITS_GET_SUPPORT, NULL, 0,
+					TFM_PS_ITS_GET_SUPPORT, in_vec, IOVEC_LEN(in_vec),
 					out_vec, IOVEC_LEN(out_vec));
 	if (psa_status != PSA_SUCCESS)
 		EMSG("ipc_get_support: failed to psa_call: %d", psa_status);
diff --git a/components/service/uefi/smm_variable/backend/uefi_variable_store.h b/components/service/uefi/smm_variable/backend/uefi_variable_store.h
index dc3d3ca..8be5f36 100644
--- a/components/service/uefi/smm_variable/backend/uefi_variable_store.h
+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.h
@@ -22,6 +22,11 @@
 #endif
 
 /**
+ * \brief Size of the variable store index for a given entry count
+ */
+#define UEFI_VARIABLE_STORE_INDEX_SIZE(count) (sizeof(struct variable_metadata) * (count))
+
+/**
  * \brief delegate_variable_store structure definition
  *
  * A delegate_variable_store combines an association with a concrete
diff --git a/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in b/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
index d3added..32e2ae3 100644
--- a/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
+++ b/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -34,11 +34,5 @@
 			pages-count = <16>;
 			attributes = <0x3>; /* read-write */
 		};
-		openamp-virtio {
-			/* Armv8 A Foundation Platform values */
-			base-address = <0x00000000 0x88000000>;
-			pages-count = <256>;
-			attributes = <0x3>; /* read-write */
-		};
 	};
 };
diff --git a/deployments/se-proxy/infra/corstone1000/infra.cmake b/deployments/se-proxy/infra/corstone1000/infra.cmake
index 4e7e2bd..a52a1b7 100644
--- a/deployments/se-proxy/infra/corstone1000/infra.cmake
+++ b/deployments/se-proxy/infra/corstone1000/infra.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -15,8 +15,8 @@
 	BASE_DIR ${TS_ROOT}
 	COMPONENTS
 		"components/rpc/common/caller"
-		"components/rpc/psa_ipc"
-		"components/messaging/openamp/sp"
+		"components/rpc/rss_comms"
+		"components/messaging/rss_comms/sp"
 		"components/service/attestation/client/psa_ipc"
 		"components/service/attestation/key_mngr/local"
 		"components/service/attestation/reporter/psa_ipc"
@@ -24,10 +24,6 @@
 		"components/service/secure_storage/backend/secure_storage_ipc"
 )
 
-# OpenAMP
-include(${TS_ROOT}/external/openamp/openamp.cmake)
-target_link_libraries(se-proxy PRIVATE openamp)
-
 target_sources(se-proxy PRIVATE
 
 	${CMAKE_CURRENT_LIST_DIR}/service_proxy_factory.c
diff --git a/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
index 6885f92..b3b93cf 100644
--- a/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
+++ b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -8,7 +8,7 @@
 #include <stddef.h>
 #include <psa/sid.h>
 #include "rpc/common/endpoint/rpc_service_interface.h"
-#include <rpc/psa_ipc/caller/sp/psa_ipc_caller.h>
+#include <rpc/rss_comms/caller/sp/rss_comms_caller.h>
 #include <service/attestation/provider/attest_provider.h>
 #include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h>
 #include <service/crypto/factory/crypto_provider_factory.h>
@@ -29,15 +29,15 @@
 	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
 
 	/* Static objects for proxy instance */
-	static struct rpc_caller_interface psa_ipc = { 0 };
+	static struct rpc_caller_interface rss_comms = { 0 };
 	static struct rpc_caller_session rpc_session = { 0 };
 	static struct attest_provider attest_provider = { 0 };
 
-	rpc_status = psa_ipc_caller_init(&psa_ipc);
+	rpc_status = rss_comms_caller_init(&rss_comms);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
-	rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+	rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
@@ -58,14 +58,14 @@
 	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
 
 	/* Static objects for proxy instance */
-	static struct rpc_caller_interface psa_ipc = { 0 };
+	static struct rpc_caller_interface rss_comms = { 0 };
 	static struct rpc_caller_session rpc_session = { 0 };
 
-	rpc_status = psa_ipc_caller_init(&psa_ipc);
+	rpc_status = rss_comms_caller_init(&rss_comms);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
-	rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+	rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
@@ -87,14 +87,14 @@
 	const struct rpc_uuid ps_uuid = { .uuid = TS_PSA_PROTECTED_STORAGE_UUID };
 
 	/* Static objects for proxy instance */
-	static struct rpc_caller_interface psa_ipc = { 0 };
+	static struct rpc_caller_interface rss_comms = { 0 };
 	static struct rpc_caller_session rpc_session = { 0 };
 
-	rpc_status = psa_ipc_caller_init(&psa_ipc);
+	rpc_status = rss_comms_caller_init(&rss_comms);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
-	rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+	rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
@@ -113,14 +113,14 @@
 	const struct rpc_uuid its_uuid = { .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID };
 
 	/* Static objects for proxy instance */
-	static struct rpc_caller_interface psa_ipc = { 0 };
+	static struct rpc_caller_interface rss_comms = { 0 };
 	static struct rpc_caller_session rpc_session = { 0 };
 
-	rpc_status = psa_ipc_caller_init(&psa_ipc);
+	rpc_status = rss_comms_caller_init(&rss_comms);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
-	rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+	rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
 	if (rpc_status != RPC_SUCCESS)
 		return NULL;
 
diff --git a/deployments/smm-gateway/common/smm_gateway.c b/deployments/smm-gateway/common/smm_gateway.c
index f7279fa..eaa8613 100644
--- a/deployments/smm-gateway/common/smm_gateway.c
+++ b/deployments/smm-gateway/common/smm_gateway.c
@@ -11,6 +11,7 @@
 #include "psa/crypto.h"
 #include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
 #include <service/secure_storage/backend/mock_store/mock_store.h>
+#include <service/locator/sp/ffa/spffa_service_context.h>
 #include <service_locator.h>
 
 /* Build-time default configuration */
@@ -32,6 +33,26 @@
 #define SMM_GATEWAY_MAX_UEFI_VARIABLES		(40)
 #endif
 
+/**
+ * The UEFI variable store index must fit into the RPC shared memory, otherwise
+ * load_variable_index/sync_variable_index will fail.
+ */
+#define SMM_UEFI_VARIABLE_STORE_INDEX_SIZE \
+	UEFI_VARIABLE_STORE_INDEX_SIZE(SMM_GATEWAY_MAX_UEFI_VARIABLES)
+
+_Static_assert(SMM_UEFI_VARIABLE_STORE_INDEX_SIZE < RPC_CALLER_SESSION_SHARED_MEMORY_SIZE,
+	       "The UEFI variable index does not fit into the RPC shared memory, please increase " \
+	       "RPC_CALLER_SESSION_SHARED_MEMORY_SIZE");
+
+/**
+ * The SP heap must be large enough for storing the UEFI variable index, the RPC shared memory and
+ * ~16kB of miscellaneous data.
+ */
+#define SMM_MIN_HEAP_SIZE \
+	SMM_UEFI_VARIABLE_STORE_INDEX_SIZE + RPC_CALLER_SESSION_SHARED_MEMORY_SIZE + 16 * 1024
+
+_Static_assert(SP_HEAP_SIZE > SMM_MIN_HEAP_SIZE, "Please increase SP_HEAP_SIZE");
+
 /* The smm_gateway instance - it's a singleton */
 static struct smm_gateway
 {
diff --git a/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
index b8e4704..39d4f60 100644
--- a/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
+++ b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -35,11 +35,26 @@
 set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
 set(SP_BOOT_ORDER "8" CACHE STRING "Boot order of the SP")
 
+#-------------------------------------------------------------------------------
+#  Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "smm-gateway")
+
+# SMM variable and RPC caller settings
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 40 CACHE STRING "Maximum UEFI variable count")
+set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 2*4096 CACHE STRING "RPC caller buffer size in SMMGW")
 if (UEFI_AUTH_VAR)
-set(SP_HEAP_SIZE "64 * 1024" CACHE STRING "SP heap size in bytes")
+set(SMM_SP_HEAP_SIZE 64*1024 CACHE STRING "SMM gateway SP heap size")
 else()
-set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(SMM_SP_HEAP_SIZE 32*1024 CACHE STRING "SMM gateway SP heap size")
 endif()
+set(SP_HEAP_SIZE "${SMM_SP_HEAP_SIZE}" CACHE STRING "SP heap size in bytes")
+
+target_compile_definitions("smm-gateway" PRIVATE
+	RPC_CALLER_SESSION_SHARED_MEMORY_SIZE=${SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE}
+	SMM_GATEWAY_MAX_UEFI_VARIABLES=${SMM_GATEWAY_MAX_UEFI_VARIABLES}
+)
 
 set(TRACE_PREFIX "SMMGW" CACHE STRING "Trace prefix")
 
@@ -66,11 +81,6 @@
 include(../../infra/psa-varstore.cmake REQUIRED)
 include(../../smm-gateway.cmake REQUIRED)
 
-#-------------------------------------------------------------------------------
-#  Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "smm-gateway")
 
 #-------------------------------------------------------------------------------
 #  Deployment specific build options
diff --git a/deployments/smm-gateway/config/default-sp/CMakeLists.txt b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
index 3dd182e..102c3ee 100644
--- a/deployments/smm-gateway/config/default-sp/CMakeLists.txt
+++ b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
@@ -40,11 +40,26 @@
 set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
 set(SP_BOOT_ORDER "8" CACHE STRING "Boot order of the SP")
 
+#-------------------------------------------------------------------------------
+#  Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "smm-gateway")
+
+# SMM variable and RPC caller settings
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 40 CACHE STRING "Maximum UEFI variable count")
+set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 2*4096 CACHE STRING "RPC caller buffer size in SMMGW")
 if (UEFI_AUTH_VAR)
-set(SP_HEAP_SIZE "64 * 1024" CACHE STRING "Heap size")
+set(SMM_SP_HEAP_SIZE 64*1024 CACHE STRING "SMM gateway SP heap size")
 else()
-set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+set(SMM_SP_HEAP_SIZE 32*1024 CACHE STRING "SMM gateway SP heap size")
 endif()
+set(SP_HEAP_SIZE "${SMM_SP_HEAP_SIZE}" CACHE STRING "SP heap size in bytes")
+
+target_compile_definitions("smm-gateway" PRIVATE
+	RPC_CALLER_SESSION_SHARED_MEMORY_SIZE=${SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE}
+	SMM_GATEWAY_MAX_UEFI_VARIABLES=${SMM_GATEWAY_MAX_UEFI_VARIABLES}
+)
 
 # Setting the MM communication buffer parameters
 set(MM_COMM_BUFFER_ADDRESS "0x00000008 0x81000000" CACHE STRING "Address of MM communicte buffer in 64 bit DTS format")
@@ -65,12 +80,6 @@
 include(../../smm-gateway.cmake REQUIRED)
 
 #-------------------------------------------------------------------------------
-#  Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "smm-gateway")
-
-#-------------------------------------------------------------------------------
 #  Deployment specific build options
 #-------------------------------------------------------------------------------
 target_compile_definitions(smm-gateway PRIVATE
diff --git a/platform/drivers/arm/mhu_driver/component.cmake b/platform/drivers/arm/mhu_driver/component.cmake
deleted file mode 100644
index 77a5a50..0000000
--- a/platform/drivers/arm/mhu_driver/component.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-# Add source files for using mhu driver
-target_sources(${TGT}
-	PRIVATE
-	"${CMAKE_CURRENT_LIST_DIR}/mhu_v2_x.c"
-)
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake b/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake
new file mode 100644
index 0000000..e80c549
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Add source files for using mhu driver
+target_sources(${TGT}
+	PRIVATE
+		"${CMAKE_CURRENT_LIST_DIR}/mhu_v2_x.c"
+		"${CMAKE_CURRENT_LIST_DIR}/mhu_wrapper_v2_x.c"
+		"${CMAKE_CURRENT_LIST_DIR}/mhu_adapter_v2_x.c"
+)
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu.h b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu.h
new file mode 100644
index 0000000..a02fdd8
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2022-2023 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MHU_H__
+#define __MHU_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Generic MHU error enumeration types.
+ */
+enum mhu_error_t {
+    MHU_ERR_NONE                =  0,
+    MHU_ERR_NOT_INIT            = -1,
+    MHU_ERR_ALREADY_INIT        = -2,
+    MHU_ERR_UNSUPPORTED_VERSION = -3,
+    MHU_ERR_UNSUPPORTED         = -4,
+    MHU_ERR_INVALID_ARG         = -5,
+    MHU_ERR_BUFFER_TOO_SMALL    = -6,
+    MHU_ERR_GENERAL             = -7,
+};
+
+/**
+ * \brief Initializes sender MHU.
+ *
+ * \param[in] mhu_sender_dev        Pointer to the sender MHU.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note This function must be called before mhu_send_data().
+ */
+enum mhu_error_t mhu_init_sender(void *mhu_sender_dev);
+
+/**
+ * \brief Initializes receiver MHU.
+ *
+ * \param[in] mhu_receiver_dev      Pointer to the receiver MHU.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note This function must be called before mhu_receive_data().
+ */
+enum mhu_error_t mhu_init_receiver(void *mhu_receiver_dev);
+
+/**
+ * \brief Sends data over MHU.
+ *
+ * \param[in] mhu_sender_dev  Pointer to the sender MHU.
+ * \param[in] send_buffer     Pointer to buffer containing the data to be
+ *                            transmitted.
+ * \param[in] size            Size of the data to be transmitted in bytes.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note The send_buffer must be 4-byte aligned and its length must be at least
+ *       (4 - (size % 4)) bytes bigger than the data size to prevent buffer
+ *       over-reading.
+ */
+enum mhu_error_t mhu_send_data(void *mhu_sender_dev,
+                               const uint8_t *send_buffer,
+                               size_t size);
+
+/**
+ * \brief Wait for data from MHU.
+ *
+ * \param[in]     mhu_receiver_dev  Pointer to the receiver MHU.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note This function must be called before mhu_receive_data() if the MHU
+ *       receiver interrupt is not used.
+ */
+enum mhu_error_t mhu_wait_data(void *mhu_receiver_dev);
+
+/**
+ * \brief Receives data from MHU.
+ *
+ * \param[in]     mhu_receiver_dev  Pointer to the receiver MHU.
+ * \param[out]    receive_buffer    Pointer the buffer where to store the
+ *                                  received data.
+ * \param[in,out] size              As input the size of the receive_buffer,
+ *                                  as output the number of bytes received.
+ *                                  As a limitation, the size of the buffer
+ *                                  must be a multiple of 4.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note The receive_buffer must be 4-byte aligned and its length must be a
+ *       multiple of 4.
+ */
+enum mhu_error_t mhu_receive_data(void *mhu_receiver_dev,
+                                  uint8_t *receive_buffer,
+                                  size_t *size);
+
+/**
+ * \brief Signals an interrupt over the last available channel and wait for the
+ *        values to be cleared by the receiver.
+ *
+ * \param[in]     mhu_sender_dev   Pointer to the sender MHU.
+ * \param[in]     value            Value that will be used while signaling.
+ *
+ * \return Returns mhu_error_t error code.
+ */
+enum mhu_error_t signal_and_wait_for_clear(void *mhu_sender_dev,
+                                           uint32_t value);
+
+/**
+ * \brief Wait for signal on the last available channel in a loop and
+ *        acknowledge the transfer by clearing the status on that channel.
+ *
+ * \param[in]     mhu_receiver_dev Pointer to the receiver MHU.
+ * \param[in]     value            Value that will be used while waiting.
+ *
+ * \return Returns mhu_error_t error code.
+ */
+enum mhu_error_t wait_for_signal_and_clear(void *mhu_receiver_dev,
+                                           uint32_t value);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MHU_H__ */
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_adapter_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_adapter_v2_x.c
new file mode 100644
index 0000000..f781a35
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_adapter_v2_x.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <config/interface/config_store.h>
+#include <platform/interface/device_region.h>
+#include <platform/interface/mhu_interface.h>
+#include <stdlib.h>
+
+#include "mhu.h"
+#include "mhu_v2_x.h"
+
+static int mhu_adapter_send(void *context, unsigned char *send_buffer, size_t size)
+{
+	struct mhu_v2_x_dev_t *dev = NULL;
+
+	if (!context || !send_buffer || size == 0)
+		return -1;
+
+	dev = (struct mhu_v2_x_dev_t *)context;
+
+	if (mhu_send_data(dev, (uint8_t *)send_buffer, size) != MHU_ERR_NONE)
+		return -1;
+
+	return 0;
+}
+
+static int mhu_adapter_receive(void *context, unsigned char *receive_buffer, size_t *size)
+{
+	struct mhu_v2_x_dev_t *dev = NULL;
+
+	if (!context || !receive_buffer || !size)
+		return -1;
+
+	dev = (struct mhu_v2_x_dev_t *)context;
+
+	if (mhu_receive_data(dev, (uint8_t *)receive_buffer, size) != MHU_ERR_NONE)
+		return -1;
+
+	return 0;
+}
+
+static int mhu_adapter_wait_data(void *context)
+{
+	struct mhu_v2_x_dev_t *dev = NULL;
+
+	if (!context)
+		return -1;
+
+	dev = (struct mhu_v2_x_dev_t *)context;
+
+	if (mhu_wait_data(dev) != MHU_ERR_NONE)
+		return -1;
+
+	return 0;
+}
+
+static int mhu_adapter_signal_and_wait_for_clear(void *context, uint32_t value)
+{
+	struct mhu_v2_x_dev_t *dev = NULL;
+
+	if (!context)
+		return -1;
+
+	dev = (struct mhu_v2_x_dev_t *)context;
+
+	if (signal_and_wait_for_clear(dev, value) != MHU_ERR_NONE)
+		return -1;
+
+	return 0;
+}
+
+static int mhu_adapter_wait_for_signal_and_clear(void *context, uint32_t value)
+{
+	struct mhu_v2_x_dev_t *dev = NULL;
+
+	if (!context)
+		return -1;
+
+	dev = (struct mhu_v2_x_dev_t *)context;
+
+	if (wait_for_signal_and_clear(dev, value) == MHU_ERR_NONE)
+		return -1;
+
+	return 0;
+}
+
+int platform_mhu_create(struct platform_mhu_driver *driver, const char *object_name,
+			bool is_receiver)
+{
+	struct mhu_v2_x_dev_t *new_instance = NULL;
+	enum mhu_error_t status = MHU_ERR_NONE;
+	struct device_region device_region = { 0 };
+	static const struct platform_mhu_iface iface = {
+		.send = mhu_adapter_send,
+		.receive = mhu_adapter_receive,
+		.wait_data = mhu_adapter_wait_data,
+		.signal_and_wait_for_clear = mhu_adapter_signal_and_wait_for_clear,
+		.wait_for_signal_and_clear = mhu_adapter_wait_for_signal_and_clear,
+	};
+
+	/* Default to leaving the driver in a safe but inoperable state. */
+	driver->iface = &iface;
+	driver->context = NULL;
+
+	if (!config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, object_name, 0, &device_region,
+				sizeof(device_region)))
+		return -1;
+
+	new_instance = calloc(1, sizeof(struct mhu_v2_x_dev_t));
+	if (!new_instance)
+		return -1;
+
+	new_instance->base = device_region.base_addr;
+
+	if (is_receiver) {
+		new_instance->frame = MHU_V2_X_RECEIVER_FRAME;
+		status = mhu_init_receiver(new_instance);
+	} else {
+		new_instance->frame = MHU_V2_X_SENDER_FRAME;
+		status = mhu_init_sender(new_instance);
+	}
+
+	if (status != MHU_ERR_NONE) {
+		free(new_instance);
+		return -1;
+	}
+
+	driver->context = new_instance;
+
+	return 0;
+}
+
+void platform_mhu_destroy(struct platform_mhu_driver *driver)
+{
+	if (!driver->context)
+		return;
+
+	free(driver->context);
+	driver->context = NULL;
+}
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.c
similarity index 95%
rename from platform/drivers/arm/mhu_driver/mhu_v2_x.c
rename to platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.c
index d7e70ef..7d04b0a 100644
--- a/platform/drivers/arm/mhu_driver/mhu_v2_x.c
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Arm Limited
+ * Copyright (c) 2020-2024 Arm Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,7 +15,8 @@
  */
 #include <stdint.h>
 #include <stdbool.h>
-#include "mhu_v2.h"
+#include <stddef.h>
+#include "mhu_v2_x.h"
 
 #define _MHU_V2_X_MAX_CHANNELS    124
 #define _MHU_V2_1_MAX_CHCOMB_INT  4
@@ -70,7 +71,7 @@
     volatile uint32_t reserved_0;
     /* Offset: 0xFA0 (R/W) Channel Combined Interrupt Stat (Reserved in 2.0) */
     volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
-    /* Offset: ‭0xFC4‬ (R/ ) Reserved */
+    /* Offset: 0xFC4 (R/ ) Reserved */
     volatile uint32_t reserved_1[6];
     /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
     volatile uint32_t iidr;
@@ -142,7 +143,6 @@
 enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
      enum mhu_v2_x_supported_revisions rev)
 {
-    uint32_t AIDR = 0;
     union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
 
     if (dev->is_initialized) {
@@ -150,6 +150,7 @@
     }
 
     if (rev == MHU_REV_READ_FROM_HW) {
+        uint32_t AIDR = 0;
         /* Read revision from HW */
         if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
             AIDR = p_mhu->recv_frame.aidr;
@@ -190,7 +191,12 @@
 
 uint32_t mhu_v2_x_get_num_channel_implemented(const struct mhu_v2_x_dev_t *dev)
 {
-    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+    union _mhu_v2_x_frame_t *p_mhu = NULL;
+
+    if (!dev)
+        return MHU_V_2_X_ERR_GENERAL;
+
+    p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
 
     if ( !(dev->is_initialized) ) {
         return MHU_V_2_X_ERR_NOT_INIT;
@@ -220,6 +226,23 @@
     }
 }
 
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+     uint32_t channel, uint32_t *value)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+        *value = (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_st;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
 enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
      uint32_t channel)
 {
@@ -591,10 +614,11 @@
         }
 
         for(j = 0; j < CH_PER_CH_COMB; j++) {
-            if ((status >> (CH_PER_CH_COMB - j - 1)) & (ENABLE)) {
-                *channel = (CH_PER_CH_COMB - j -1) + (i * CH_PER_CH_COMB);
+            if (status & ENABLE) {
+                *channel = (j + (i * CH_PER_CH_COMB));
                 return MHU_V_2_X_ERR_NONE;
             }
+            status >>= 1;
         }
     }
 
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2.h b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h
similarity index 93%
rename from platform/drivers/arm/mhu_driver/mhu_v2.h
rename to platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h
index 26b3a5d..75f3f91 100644
--- a/platform/drivers/arm/mhu_driver/mhu_v2.h
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Arm Limited
+ * Copyright (c) 2020-2024 Arm Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -92,8 +92,6 @@
  *
  * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
  *
- * Returns the number of channels implemented.
- *
  * \return Returns the number of channels implemented.
  *
  * \note This function doesn't check if dev is NULL.
@@ -119,6 +117,23 @@
      uint32_t channel, uint32_t val);
 
 /**
+ * \brief Polls sender channel status.
+ *
+ * \param[in]  dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in]  channel     Channel to poll the status of.
+ * \param[out] value       Pointer to variable that will store the value.
+ *
+ * Polls sender channel status.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+     uint32_t channel, uint32_t *value);
+
+/**
  * \brief Clears the channel after the value is send over it.
  *
  * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
@@ -218,12 +233,12 @@
      const struct mhu_v2_x_dev_t *dev, uint32_t channel);
 
 /**
- * \brief Cleares the Channel interrupt.
+ * \brief Clears the Channel interrupt.
  *
  * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
  * \param[in] channel     Which channel's interrupt to clear.
  *
- * Cleares the Channel interrupt.
+ * Clears the Channel interrupt.
  *
  * \return Returns mhu_v2_x_error_t error code
  *
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_wrapper_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_wrapper_v2_x.c
new file mode 100644
index 0000000..68a30ab
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_wrapper_v2_x.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2022-2024 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mhu.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "mhu_v2_x.h"
+
+#define MHU_NOTIFY_VALUE    (1234u)
+
+static enum mhu_error_t
+error_mapping_to_mhu_error_t(enum mhu_v2_x_error_t err)
+{
+    switch (err) {
+    case MHU_V_2_X_ERR_NONE:
+        return MHU_ERR_NONE;
+    case MHU_V_2_X_ERR_NOT_INIT:
+        return MHU_ERR_NOT_INIT;
+    case MHU_V_2_X_ERR_ALREADY_INIT:
+        return MHU_ERR_ALREADY_INIT;
+    case MHU_V_2_X_ERR_UNSUPPORTED_VERSION:
+        return MHU_ERR_UNSUPPORTED_VERSION;
+    case MHU_V_2_X_ERR_INVALID_ARG:
+        return MHU_ERR_INVALID_ARG;
+    case MHU_V_2_X_ERR_GENERAL:
+        return MHU_ERR_GENERAL;
+    default:
+        return MHU_ERR_GENERAL;
+    }
+}
+
+enum mhu_error_t
+signal_and_wait_for_clear(void *mhu_sender_dev, uint32_t value)
+{
+    enum mhu_v2_x_error_t err;
+    struct mhu_v2_x_dev_t *dev;
+    uint32_t channel_notify;
+    uint32_t wait_val;
+
+    if (mhu_sender_dev == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    dev = (struct mhu_v2_x_dev_t *)mhu_sender_dev;
+
+    /* Use the last channel for notifications */
+    channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+    /* FIXME: Avoid wasting a whole channel for notifying */
+    err = mhu_v2_x_channel_send(dev, channel_notify, value);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+
+    do {
+        err = mhu_v2_x_channel_poll(dev, channel_notify, &wait_val);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            break;
+        }
+    } while (wait_val != 0);
+
+    return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t
+wait_for_signal_and_clear(void *mhu_receiver_dev, uint32_t value)
+{
+    enum mhu_v2_x_error_t err;
+    struct mhu_v2_x_dev_t *dev;
+    uint32_t channel_notify;
+    uint32_t wait_val;
+
+    if (mhu_receiver_dev == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    dev = (struct mhu_v2_x_dev_t *)mhu_receiver_dev;
+
+    /* Use the last channel for notifications */
+    channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+    do {
+        /* Using the last channel for notifications */
+        err = mhu_v2_x_channel_receive(dev, channel_notify, &wait_val);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            return error_mapping_to_mhu_error_t(err);
+        }
+    } while (wait_val != value);
+
+    /* Clear the last channel */
+    err = mhu_v2_x_channel_clear(dev, channel_notify);
+
+    return error_mapping_to_mhu_error_t(err);
+}
+
+static enum mhu_v2_x_error_t
+clear_and_wait_for_signal(struct mhu_v2_x_dev_t *dev)
+{
+    enum mhu_v2_x_error_t err;
+    uint32_t num_channels = 0;
+    uint32_t val, i;
+
+    if (dev == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+    /* At least 1 channal needed for signalling. */
+    if (num_channels < 1) {
+        return MHU_ERR_GENERAL;
+    }
+    /* Clear all channels */
+    for (i = 0; i < num_channels; ++i) {
+        err = mhu_v2_x_channel_clear(dev, i);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            return err;
+        }
+    }
+
+    do {
+        /* Using the last channel for notifications */
+        err = mhu_v2_x_channel_receive(dev, num_channels - 1, &val);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            break;
+        }
+    } while (val != MHU_NOTIFY_VALUE);
+
+    return err;
+}
+
+enum mhu_error_t mhu_init_sender(void *mhu_sender_dev)
+{
+    enum mhu_v2_x_error_t err;
+    struct mhu_v2_x_dev_t *dev = mhu_sender_dev;
+
+    if (dev == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    err = mhu_v2_x_driver_init(dev, MHU_REV_READ_FROM_HW);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+
+    /* This wrapper requires at least two channels to be implemented */
+    if (mhu_v2_x_get_num_channel_implemented(dev) < 2) {
+        return MHU_ERR_UNSUPPORTED;
+    }
+
+    return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_init_receiver(void *mhu_receiver_dev)
+{
+    enum mhu_v2_x_error_t err;
+    struct mhu_v2_x_dev_t *dev = mhu_receiver_dev;
+    uint32_t num_channels, i;
+
+    if (dev == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    err = mhu_v2_x_driver_init(dev, MHU_REV_READ_FROM_HW);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+
+    num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+
+    /* This wrapper requires at least two channels to be implemented */
+    if (num_channels < 2) {
+        return MHU_ERR_UNSUPPORTED;
+    }
+
+    /* Mask all channels except the notifying channel */
+    for (i = 0; i < (num_channels - 1); ++i) {
+        err = mhu_v2_x_channel_mask_set(dev, i, UINT32_MAX);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            return error_mapping_to_mhu_error_t(err);
+        }
+    }
+
+    /* The last channel is used for notifications */
+    err = mhu_v2_x_channel_mask_clear(dev, (num_channels - 1), UINT32_MAX);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+
+    err = mhu_v2_x_interrupt_enable(dev, MHU_2_1_INTR_CHCOMB_MASK);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+
+    return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_send_data(void *mhu_sender_dev,
+                               const uint8_t *send_buffer,
+                               size_t size)
+{
+    enum mhu_v2_x_error_t err;
+    enum mhu_error_t mhu_err;
+    struct mhu_v2_x_dev_t *dev = mhu_sender_dev;
+    uint32_t num_channels = 0;
+    uint32_t chan = 0;
+    uint32_t i;
+    uint32_t *p;
+
+    if (dev == NULL || send_buffer == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    } else if (size == 0) {
+        return MHU_ERR_NONE;
+    }
+
+    /* For simplicity, require the send_buffer to be 4-byte aligned. */
+    if ((uintptr_t)send_buffer & 0x3u) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+    /* At least 2 channals needed for sending a message. */
+    if (num_channels < 2) {
+        return MHU_ERR_GENERAL;
+    }
+    err = mhu_v2_x_initiate_transfer(dev);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+
+    /* First send over the size of the actual message. */
+    err = mhu_v2_x_channel_send(dev, chan, (uint32_t)size);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+    chan++;
+
+    p = (uint32_t *)send_buffer;
+    for (i = 0; i < size; i += 4) {
+        err = mhu_v2_x_channel_send(dev, chan, *p++);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            return error_mapping_to_mhu_error_t(err);
+        }
+        if (++chan == (num_channels - 1)) {
+            mhu_err = signal_and_wait_for_clear(dev, MHU_NOTIFY_VALUE);
+            if (mhu_err != MHU_ERR_NONE) {
+                return mhu_err;
+            }
+            chan = 0;
+        }
+    }
+
+    /* Signal the end of transfer.
+     *   It's not required to send a signal when the message was
+     *   perfectly-aligned ((num_channels - 1) channels were used in the last
+     *   round) preventing it from signaling twice at the end of transfer.
+     */
+    if (chan != 0) {
+        mhu_err = signal_and_wait_for_clear(dev, MHU_NOTIFY_VALUE);
+        if (mhu_err != MHU_ERR_NONE) {
+            return mhu_err;
+        }
+    }
+
+    err = mhu_v2_x_close_transfer(dev);
+    return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t mhu_wait_data(void *mhu_receiver_dev)
+{
+    enum mhu_v2_x_error_t err;
+    struct mhu_v2_x_dev_t *dev = mhu_receiver_dev;
+    uint32_t num_channels = 0;
+    uint32_t val;
+
+    if (dev == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+    /* At least 1 channal needed for signalling. */
+    if (num_channels < 1) {
+        return MHU_ERR_GENERAL;
+    }
+
+    do {
+        /* Using the last channel for notifications */
+        err = mhu_v2_x_channel_receive(dev, num_channels - 1, &val);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            break;
+        }
+    } while (val != MHU_NOTIFY_VALUE);
+
+    return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t mhu_receive_data(void *mhu_receiver_dev,
+                                  uint8_t *receive_buffer,
+                                  size_t *size)
+{
+    enum mhu_v2_x_error_t err;
+    struct mhu_v2_x_dev_t *dev = mhu_receiver_dev;
+    uint32_t num_channels = 0;
+    uint32_t chan = 0;
+    uint32_t message_len;
+    uint32_t i;
+    uint32_t *p;
+
+    if (dev == NULL || receive_buffer == NULL) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    /* For simplicity, require:
+     * - the receive_buffer to be 4-byte aligned,
+     * - the buffer size to be a multiple of 4.
+     */
+    if (((uintptr_t)receive_buffer & 0x3u) || (*size & 0x3u)) {
+        return MHU_ERR_INVALID_ARG;
+    }
+
+    num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+    /* At least 1 channal needed for signalling. */
+    if (num_channels < 1) {
+        return MHU_ERR_GENERAL;
+    }
+    /* The first word is the length of the actual message. */
+    err = mhu_v2_x_channel_receive(dev, chan, &message_len);
+    if (err != MHU_V_2_X_ERR_NONE) {
+        return error_mapping_to_mhu_error_t(err);
+    }
+    chan++;
+
+    if (message_len > *size) {
+        /* Message buffer too small */
+        *size = message_len;
+        return MHU_ERR_BUFFER_TOO_SMALL;
+    }
+
+    p = (uint32_t *)receive_buffer;
+    for (i = 0; i < message_len; i += 4) {
+        err = mhu_v2_x_channel_receive(dev, chan, p++);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            return error_mapping_to_mhu_error_t(err);
+        }
+
+        /* Only wait for next transfer if there is still missing data. */
+        if (++chan == (num_channels - 1) && (message_len - i) > 4) {
+            /* Busy wait for next transfer */
+            err = clear_and_wait_for_signal(dev);
+            if (err != MHU_V_2_X_ERR_NONE) {
+                return error_mapping_to_mhu_error_t(err);
+            }
+            chan = 0;
+        }
+    }
+
+    /* Clear all channels */
+    for (i = 0; i < num_channels; ++i) {
+        err = mhu_v2_x_channel_clear(dev, i);
+        if (err != MHU_V_2_X_ERR_NONE) {
+            return error_mapping_to_mhu_error_t(err);
+        }
+    }
+
+    *size = message_len;
+
+    return MHU_ERR_NONE;
+}
diff --git a/platform/interface/mhu_interface.h b/platform/interface/mhu_interface.h
new file mode 100644
index 0000000..723ef07
--- /dev/null
+++ b/platform/interface/mhu_interface.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_PLATFORM_INTERFACE_MHU_H
+#define TS_PLATFORM_INTERFACE_MHU_H
+
+/*
+ * Interface definition for a platform MHU driver.  A platform provider will
+ * provide concrete implementations of this interface for each alternative
+ * implementation supported.
+ */
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Virtual interface for a platform MHU driver.  A platform will provide
+ * one or more concrete implementations of this interface.
+ */
+struct platform_mhu_iface {
+    /*
+     * \brief Sends data over MHU.
+     *
+     * \param[in] context         Platform driver context.
+     * \param[in] send_buffer     Pointer to buffer containing the data to be
+     *                            transmitted.
+     * \param[in] size            Size of the data to be transmitted in bytes.
+     *
+     * \return 0 if successful.
+     *
+     * \note The send_buffer must be 4-byte aligned and its length must be at least
+     *       (4 - (size % 4)) bytes bigger than the data size to prevent buffer
+     *       over-reading.
+     */
+	int (*send)(void *context, unsigned char *send_buffer, size_t size);
+
+    /*
+     * \brief Receives data from MHU.
+     *
+     * \param[in]     context           Platform driver context.
+     * \param[out]    receive_buffer    Pointer the buffer where to store the
+     *                                  received data.
+     * \param[in,out] size              As input the size of the receive_buffer,
+     *                                  as output the number of bytes received.
+     *                                  As a limitation, the size of the buffer
+     *                                  must be a multiple of 4.
+     *
+     * \return 0 if successful.
+     *
+     * \note The receive_buffer must be 4-byte aligned and its length must be a
+     *       multiple of 4.
+     */
+	int (*receive)(void *context, unsigned char *receive_buffer, size_t *size);
+
+    /*
+     * \brief Wait for data from MHU.
+     *
+     * \param[in] context           Platform driver context.
+     *
+     * \return 0 if successful.
+     *
+     * \note This function must be called before mhu_receive_data() if the MHU
+     *       receiver interrupt is not used.
+     */
+	int (*wait_data)(void *context);
+
+    /*
+     * \brief Signals an interrupt over the last available channel and wait for the
+     *        values to be cleared by the receiver.
+     *
+     * \param[in]   context           Platform driver context.
+     * \param[in]   value             Value that will be used while signaling.
+     *
+     * \return 0 if successful.
+     */
+	int (*signal_and_wait_for_clear)(void *context, uint32_t value);
+
+    /*
+     * \brief Wait for signal on the last available channel in a loop and
+     *        acknowledge the transfer by clearing the status on that channel.
+     *
+     * \param[in]     context          Platform driver context.
+     * \param[in]     value            Value that will be used while waiting.
+     *
+     * \return 0 if successful.
+     */
+	int (*wait_for_signal_and_clear)(void *context, uint32_t value);
+};
+
+/*
+ * A platform MHU driver instance.
+ */
+struct platform_mhu_driver {
+	void *context; /**< Opaque driver context */
+	const struct platform_mhu_iface *iface; /**< Interface methods */
+};
+
+/*
+ * \brief Factory method to construct a platform specific MHU driver
+ *
+ * \param[out] driver         Pointer to driver structure to initialize on construction.
+ * \param[in]  object_name    Deployment specific name of the instance in the config store.
+ * \param[in]  is_receiver    True if the MHU will be used for receiving data, false if sending.
+ *
+ * \return          0 if successful.
+ */
+int platform_mhu_create(struct platform_mhu_driver *driver, const char *object_name,
+			bool is_receiver);
+
+/*
+ * \brief Destroy a driver constructed using the factory method
+ *
+ * \param[in] driver    Pointer to driver structure for constructed driver.
+ */
+void platform_mhu_destroy(struct platform_mhu_driver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TS_PLATFORM_INTERFACE_MHU_H */
diff --git a/platform/providers/arm/corstone1000/platform.cmake b/platform/providers/arm/corstone1000/platform.cmake
index a3c4209..d944acf 100644
--- a/platform/providers/arm/corstone1000/platform.cmake
+++ b/platform/providers/arm/corstone1000/platform.cmake
@@ -1,15 +1,29 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
-# Platform definition for the 'fvp_base_revc-2xaem8a' virtual platform.
+# Platform definition for the Corstone-1000 platform.
 #-------------------------------------------------------------------------------
 
-# include MHU driver
-include(${TS_ROOT}/platform/drivers/arm/mhu_driver/component.cmake)
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 80 CACHE STRING "Maximum UEFI variable count")
+set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 4*4096 CACHE STRING "RPC caller buffer size in SMMGW")
+set(SMM_SP_HEAP_SIZE 80*1024 CACHE STRING "SMM gateway SP heap size")
 
 target_compile_definitions(${TGT} PRIVATE
 	SMM_VARIABLE_INDEX_STORAGE_UID=0x787
-	SMM_GATEWAY_MAX_UEFI_VARIABLES=100
+	PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE=0x2080
+	COMMS_MHU_MSG_SIZE=0x3500
 )
+
+get_property(_platform_driver_dependencies TARGET ${TGT}
+	PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+)
+
+#-------------------------------------------------------------------------------
+#  Map platform dependencies to suitable drivers for this platform
+#
+#-------------------------------------------------------------------------------
+if ("mhu" IN_LIST _platform_driver_dependencies)
+	include(${TS_ROOT}/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake)
+endif()