Add openamp messenger

Create an openamp messenger that will handle the setup and
communication to an outside PE using openamp and using mhu as a doorbell
mechanism.

Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Change-Id: Iac4119faac3f98dc04e7edbc1f401db8c8c93537
diff --git a/components/messaging/openamp/sp/openamp_messenger.c b/components/messaging/openamp/sp/openamp_messenger.c
new file mode 100644
index 0000000..2b77ea4
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <trace.h>
+#include "openamp_messenger.h"
+#include "openamp_messenger_api.h"
+#include "openamp_mhu.h"
+#include "openamp_virtio.h"
+#include <protocols/rpc/common/packed-c/status.h>
+
+#define OPENAMP_TRANSACTION_IDLE	0x0
+#define OPENAMP_TRANSACTION_INPROGRESS	0x1
+#define OPENAMP_TRANSACTION_INVOKED	0x2
+
+int openamp_messenger_call_begin(struct openamp_messenger *openamp,
+				 uint8_t **req_buf, size_t req_len)
+{
+	const struct openamp_platform_ops *ops = openamp->platform_ops;
+	int ret;
+
+	if (!openamp)
+		return -EINVAL;
+
+	ops = openamp->platform_ops;
+	if (!req_buf) {
+		EMSG("openamp: call_begin: not req_buf");
+		return -EINVAL;
+	}
+
+	if (req_len > UINT32_MAX || req_len == 0) {
+		EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
+		return -EINVAL;
+	}
+
+	if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
+		EMSG("openamp: call_begin: transaction not idle");
+		return -EINVAL;
+	}
+
+	ret = ops->platform_call_begin(openamp, req_buf, req_len);
+	if (ret < 0) {
+		EMSG("openamp: call_begin: platform begin failed: %d", ret);
+		return -EINVAL;
+	}
+
+	openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
+
+	return 0;
+}
+
+int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
+				  uint8_t **resp_buf, size_t *resp_len)
+{
+	const struct openamp_platform_ops *ops;
+	int ret;
+
+	if (!openamp || !resp_buf || !resp_len) {
+		EMSG("openamp: call_invoke: invalid arguments");
+		return -EINVAL;
+	}
+
+	if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
+		EMSG("openamp: call_invoke: transaction needed to be started");
+		return -ENOTCONN;
+	}
+
+	ops = openamp->platform_ops;
+
+	ret = ops->platform_call_invoke(openamp, resp_buf, resp_len);
+	if (ret < 0)
+		return ret;
+
+	openamp->status = OPENAMP_TRANSACTION_INVOKED;
+
+	return 0;
+}
+
+void openamp_messenger_call_end(struct openamp_messenger *openamp)
+{
+	const struct openamp_platform_ops *ops;
+
+	if (!openamp)
+		return;
+
+	if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
+		EMSG("openamp: call_end: transaction idle");
+		return;
+	}
+
+	ops = openamp->platform_ops;
+
+	ops->platform_call_end(openamp);
+
+	openamp->status = OPENAMP_TRANSACTION_IDLE;
+}
+
+void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
+				     void *pa)
+{
+	const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+	return ops->platform_phys_to_virt(openamp, pa);
+}
+
+void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
+				     void *va)
+{
+	const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+	return ops->platform_virt_to_phys(openamp, va);
+}
+
+static const struct openamp_platform_ops openamp_virtio_ops = {
+	.transport_init = openamp_mhu_init,
+	.transport_deinit = openamp_mhu_deinit,
+	.transport_notify = openamp_mhu_notify_peer,
+	.transport_receive = openamp_mhu_receive,
+	.platform_init = openamp_virtio_init,
+	.platform_call_begin = openamp_virtio_call_begin,
+	.platform_call_invoke = openamp_virtio_call_invoke,
+	.platform_call_end = openamp_virtio_call_end,
+	.platform_virt_to_phys = openamp_virtio_virt_to_phys,
+	.platform_phys_to_virt = openamp_virtio_phys_to_virt,
+};
+
+int openamp_messenger_init(struct openamp_messenger *openamp)
+{
+	const struct openamp_platform_ops *ops;
+	int ret;
+
+	if (openamp->ref_count)
+		return 0;
+
+	openamp->platform_ops = &openamp_virtio_ops;
+
+	ops = openamp->platform_ops;
+
+	ret = ops->transport_init(openamp);
+	if (ret < 0)
+		return ret;
+
+	ret = ops->platform_init(openamp);
+	if (ret < 0)
+		goto denit_transport;
+
+	openamp->ref_count++;
+
+	return 0;
+
+denit_transport:
+	ops->transport_deinit(openamp);
+
+	return ret;
+}
+
+void openamp_messenger_deinit(struct openamp_messenger *openamp)
+{
+	if (--openamp->ref_count)
+		return;
+}